direct-io.hg

view tools/xenstore/xenstored_domain.c @ 7480:a90d670c98b9

Change the semantics of GetDomainPath so that it always succeeds, regardless of
whether a domain has been introduced to the store. Added a separate message
XS_IS_DOMAIN_INTRODUCED and API for that (xs_is_domain_introduced) to determine
whether the domain has really been introduced. This change means that the
tools can determine the correct domain path earlier in the domain creation
process, which is particularly a factor with live migration, as it allows us
to create the devices earlier in the process, and unpause the new domain before
performing the introduce. Until recently we already had these features, but
the simplification of the interface between xend and xenstored caused breakage.

No longer clear out the domain path when a domain is introduced -- this was a
hack to work around the recent problematic semantics of GetDomainPath.

Do not write the contents of the info block to the store. All the configuration
info is written to the /vm path, and anything else in the info block is either
dealt with explicitly or is ephemeral and has no place in the store.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Sun Oct 23 22:45:15 2005 +0100 (2005-10-23)
parents d8b35f72a587
children f5b119533cc8
line source
1 /*
2 Domain communications for Xen Store Daemon.
3 Copyright (C) 2005 Rusty Russell IBM Corporation
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 2 of the License, or
8 (at your option) any later version.
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
18 */
20 #include <stdio.h>
21 #include <linux/ioctl.h>
22 #include <sys/ioctl.h>
23 #include <sys/mman.h>
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdarg.h>
27 #include <sys/types.h>
28 #include <sys/stat.h>
29 #include <fcntl.h>
31 //#define DEBUG
32 #include "utils.h"
33 #include "talloc.h"
34 #include "xenstored_core.h"
35 #include "xenstored_domain.h"
36 #include "xenstored_proc.h"
37 #include "xenstored_watch.h"
38 #include "xenstored_test.h"
40 #include <xenctrl.h>
41 #include <xen/linux/evtchn.h>
43 static int *xc_handle;
44 static int virq_port;
46 int eventchn_fd = -1;
48 struct domain
49 {
50 struct list_head list;
52 /* The id of this domain */
53 unsigned int domid;
55 /* Event channel port */
56 uint16_t port;
58 /* The remote end of the event channel, used only to validate
59 repeated domain introductions. */
60 uint16_t remote_port;
62 /* The mfn associated with the event channel, used only to validate
63 repeated domain introductions. */
64 unsigned long mfn;
66 /* Domain path in store. */
67 char *path;
69 /* Shared page. */
70 struct xenstore_domain_interface *interface;
72 /* The connection associated with this. */
73 struct connection *conn;
75 /* Have we noticed that this domain is shutdown? */
76 int shutdown;
77 };
79 static LIST_HEAD(domains);
81 #ifndef TESTING
82 static void evtchn_notify(int port)
83 {
84 int rc;
86 struct ioctl_evtchn_notify notify;
87 notify.port = port;
88 rc = ioctl(eventchn_fd, IOCTL_EVTCHN_NOTIFY, &notify);
89 }
90 #else
91 extern void evtchn_notify(int port);
92 #endif
94 /* FIXME: Mark connection as broken (close it?) when this happens. */
95 static bool check_indexes(XENSTORE_RING_IDX cons, XENSTORE_RING_IDX prod)
96 {
97 return ((prod - cons) <= XENSTORE_RING_SIZE);
98 }
100 static void *get_output_chunk(XENSTORE_RING_IDX cons,
101 XENSTORE_RING_IDX prod,
102 char *buf, uint32_t *len)
103 {
104 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(prod);
105 if ((XENSTORE_RING_SIZE - (prod - cons)) < *len)
106 *len = XENSTORE_RING_SIZE - (prod - cons);
107 return buf + MASK_XENSTORE_IDX(prod);
108 }
110 static const void *get_input_chunk(XENSTORE_RING_IDX cons,
111 XENSTORE_RING_IDX prod,
112 const char *buf, uint32_t *len)
113 {
114 *len = XENSTORE_RING_SIZE - MASK_XENSTORE_IDX(cons);
115 if ((prod - cons) < *len)
116 *len = prod - cons;
117 return buf + MASK_XENSTORE_IDX(cons);
118 }
120 static int writechn(struct connection *conn, const void *data, unsigned int len)
121 {
122 uint32_t avail;
123 void *dest;
124 struct xenstore_domain_interface *intf = conn->domain->interface;
125 XENSTORE_RING_IDX cons, prod;
127 /* Must read indexes once, and before anything else, and verified. */
128 cons = intf->rsp_cons;
129 prod = intf->rsp_prod;
130 mb();
131 if (!check_indexes(cons, prod)) {
132 errno = EIO;
133 return -1;
134 }
136 dest = get_output_chunk(cons, prod, intf->rsp, &avail);
137 if (avail < len)
138 len = avail;
140 memcpy(dest, data, len);
141 mb();
142 intf->rsp_prod += len;
144 evtchn_notify(conn->domain->port);
146 return len;
147 }
149 static int readchn(struct connection *conn, void *data, unsigned int len)
150 {
151 uint32_t avail;
152 const void *src;
153 struct xenstore_domain_interface *intf = conn->domain->interface;
154 XENSTORE_RING_IDX cons, prod;
156 /* Must read indexes once, and before anything else, and verified. */
157 cons = intf->req_cons;
158 prod = intf->req_prod;
159 mb();
161 if (!check_indexes(cons, prod)) {
162 errno = EIO;
163 return -1;
164 }
166 src = get_input_chunk(cons, prod, intf->req, &avail);
167 if (avail < len)
168 len = avail;
170 memcpy(data, src, len);
171 mb();
172 intf->req_cons += len;
174 evtchn_notify(conn->domain->port);
176 return len;
177 }
179 static int destroy_domain(void *_domain)
180 {
181 struct domain *domain = _domain;
182 struct ioctl_evtchn_unbind unbind;
184 list_del(&domain->list);
186 if (domain->port) {
187 unbind.port = domain->port;
188 if (ioctl(eventchn_fd, IOCTL_EVTCHN_UNBIND, &unbind) == -1)
189 eprintf("> Unbinding port %i failed!\n", domain->port);
190 }
192 if (domain->interface)
193 munmap(domain->interface, getpagesize());
195 return 0;
196 }
198 static void domain_cleanup(void)
199 {
200 xc_dominfo_t dominfo;
201 struct domain *domain, *tmp;
202 int notify = 0;
204 list_for_each_entry_safe(domain, tmp, &domains, list) {
205 if (xc_domain_getinfo(*xc_handle, domain->domid, 1,
206 &dominfo) == 1 &&
207 dominfo.domid == domain->domid) {
208 if ((dominfo.crashed || dominfo.shutdown)
209 && !domain->shutdown) {
210 domain->shutdown = 1;
211 notify = 1;
212 }
213 if (!dominfo.dying)
214 continue;
215 }
216 talloc_free(domain->conn);
217 notify = 1;
218 }
220 if (notify)
221 fire_watches(NULL, "@releaseDomain", false);
222 }
224 /* We scan all domains rather than use the information given here. */
225 void handle_event(void)
226 {
227 uint16_t port;
229 if (read(eventchn_fd, &port, sizeof(port)) != sizeof(port))
230 barf_perror("Failed to read from event fd");
232 if (port == virq_port)
233 domain_cleanup();
235 #ifndef TESTING
236 if (write(eventchn_fd, &port, sizeof(port)) != sizeof(port))
237 barf_perror("Failed to write to event fd");
238 #endif
239 }
241 bool domain_can_read(struct connection *conn)
242 {
243 struct xenstore_domain_interface *intf = conn->domain->interface;
244 return (intf->req_cons != intf->req_prod);
245 }
247 bool domain_can_write(struct connection *conn)
248 {
249 struct xenstore_domain_interface *intf = conn->domain->interface;
250 return ((intf->rsp_prod - intf->rsp_cons) != XENSTORE_RING_SIZE);
251 }
253 static char *talloc_domain_path(void *context, unsigned int domid)
254 {
255 return talloc_asprintf(context, "/local/domain/%u", domid);
256 }
258 static struct domain *new_domain(void *context, unsigned int domid,
259 unsigned long mfn, int port)
260 {
261 struct domain *domain;
262 struct ioctl_evtchn_bind_interdomain bind;
263 int rc;
266 domain = talloc(context, struct domain);
267 domain->port = 0;
268 domain->shutdown = 0;
269 domain->domid = domid;
270 domain->path = talloc_domain_path(domain, domid);
271 domain->interface = xc_map_foreign_range(
272 *xc_handle, domain->domid,
273 getpagesize(), PROT_READ|PROT_WRITE, mfn);
274 if (!domain->interface)
275 return NULL;
277 list_add(&domain->list, &domains);
278 talloc_set_destructor(domain, destroy_domain);
280 /* Tell kernel we're interested in this event. */
281 bind.remote_domain = domid;
282 bind.remote_port = port;
283 rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_INTERDOMAIN, &bind);
284 if (rc == -1)
285 return NULL;
286 domain->port = rc;
288 domain->conn = new_connection(writechn, readchn);
289 domain->conn->domain = domain;
291 domain->remote_port = port;
292 domain->mfn = mfn;
294 return domain;
295 }
298 static struct domain *find_domain_by_domid(unsigned int domid)
299 {
300 struct domain *i;
302 list_for_each_entry(i, &domains, list) {
303 if (i->domid == domid)
304 return i;
305 }
306 return NULL;
307 }
310 /* domid, mfn, evtchn, path */
311 void do_introduce(struct connection *conn, struct buffered_data *in)
312 {
313 struct domain *domain;
314 char *vec[3];
315 unsigned int domid;
316 unsigned long mfn;
317 uint16_t port;
319 if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
320 send_error(conn, EINVAL);
321 return;
322 }
324 if (conn->id != 0 || !conn->can_write) {
325 send_error(conn, EACCES);
326 return;
327 }
329 domid = atoi(vec[0]);
330 mfn = atol(vec[1]);
331 port = atoi(vec[2]);
333 /* Sanity check args. */
334 if (port <= 0) {
335 send_error(conn, EINVAL);
336 return;
337 }
339 domain = find_domain_by_domid(domid);
341 if (domain == NULL) {
342 /* Hang domain off "in" until we're finished. */
343 domain = new_domain(in, domid, mfn, port);
344 if (!domain) {
345 send_error(conn, errno);
346 return;
347 }
349 /* Now domain belongs to its connection. */
350 talloc_steal(domain->conn, domain);
352 fire_watches(conn, "@introduceDomain", false);
353 }
354 else {
355 /* Check that the given details match the ones we have
356 previously recorded. */
357 if (port != domain->remote_port ||
358 mfn != domain->mfn) {
359 send_error(conn, EINVAL);
360 return;
361 }
362 }
364 send_ack(conn, XS_INTRODUCE);
365 }
367 /* domid */
368 void do_release(struct connection *conn, const char *domid_str)
369 {
370 struct domain *domain;
371 unsigned int domid;
373 if (!domid_str) {
374 send_error(conn, EINVAL);
375 return;
376 }
378 domid = atoi(domid_str);
379 if (!domid) {
380 send_error(conn, EINVAL);
381 return;
382 }
384 if (conn->id != 0) {
385 send_error(conn, EACCES);
386 return;
387 }
389 domain = find_domain_by_domid(domid);
390 if (!domain) {
391 send_error(conn, ENOENT);
392 return;
393 }
395 if (!domain->conn) {
396 send_error(conn, EINVAL);
397 return;
398 }
400 talloc_free(domain->conn);
402 fire_watches(conn, "@releaseDomain", false);
404 send_ack(conn, XS_RELEASE);
405 }
407 void do_get_domain_path(struct connection *conn, const char *domid_str)
408 {
409 char *path;
411 if (!domid_str) {
412 send_error(conn, EINVAL);
413 return;
414 }
416 path = talloc_domain_path(conn, atoi(domid_str));
418 send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
420 talloc_free(path);
421 }
423 void do_is_domain_introduced(struct connection *conn, const char *domid_str)
424 {
425 int result;
426 unsigned int domid;
428 if (!domid_str) {
429 send_error(conn, EINVAL);
430 return;
431 }
433 domid = atoi(domid_str);
434 if (domid == DOMID_SELF)
435 result = 1;
436 else
437 result = (find_domain_by_domid(domid) != NULL);
439 send_reply(conn, XS_IS_DOMAIN_INTRODUCED, result ? "T" : "F", 2);
440 }
442 static int close_xc_handle(void *_handle)
443 {
444 xc_interface_close(*(int *)_handle);
445 return 0;
446 }
448 /* Returns the implicit path of a connection (only domains have this) */
449 const char *get_implicit_path(const struct connection *conn)
450 {
451 if (!conn->domain)
452 return NULL;
453 return conn->domain->path;
454 }
456 /* Restore existing connections. */
457 void restore_existing_connections(void)
458 {
459 }
461 static int dom0_init(void)
462 {
463 int rc, fd, port;
464 unsigned long mfn;
465 char str[20];
466 struct domain *dom0;
468 fd = open(XENSTORED_PROC_MFN, O_RDONLY);
470 rc = read(fd, str, sizeof(str));
471 str[rc] = '\0';
472 mfn = strtoul(str, NULL, 0);
474 close(fd);
476 fd = open(XENSTORED_PROC_PORT, O_RDONLY);
478 rc = read(fd, str, sizeof(str));
479 str[rc] = '\0';
480 port = strtoul(str, NULL, 0);
482 close(fd);
485 dom0 = new_domain(NULL, 0, mfn, port);
486 talloc_steal(dom0->conn, dom0);
488 evtchn_notify(dom0->port);
490 return 0;
491 }
495 #define EVTCHN_DEV_NAME "/dev/xen/evtchn"
496 #define EVTCHN_DEV_MAJOR 10
497 #define EVTCHN_DEV_MINOR 201
500 /* Returns the event channel handle. */
501 int domain_init(void)
502 {
503 struct stat st;
504 struct ioctl_evtchn_bind_virq bind;
505 int rc;
507 xc_handle = talloc(talloc_autofree_context(), int);
508 if (!xc_handle)
509 barf_perror("Failed to allocate domain handle");
511 *xc_handle = xc_interface_open();
512 if (*xc_handle < 0)
513 barf_perror("Failed to open connection to hypervisor");
515 talloc_set_destructor(xc_handle, close_xc_handle);
517 #ifdef TESTING
518 eventchn_fd = fake_open_eventchn();
519 (void)&st;
520 #else
521 /* Make sure any existing device file links to correct device. */
522 if ((lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
523 (st.st_rdev != makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)))
524 (void)unlink(EVTCHN_DEV_NAME);
526 reopen:
527 eventchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
528 if (eventchn_fd == -1) {
529 if ((errno == ENOENT) &&
530 ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
531 (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
532 makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)) == 0))
533 goto reopen;
534 return -errno;
535 }
536 #endif
537 if (eventchn_fd < 0)
538 barf_perror("Failed to open evtchn device");
540 if (dom0_init() != 0)
541 barf_perror("Failed to initialize dom0 state");
543 bind.virq = VIRQ_DOM_EXC;
544 rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_VIRQ, &bind);
545 if (rc == -1)
546 barf_perror("Failed to bind to domain exception virq port");
547 virq_port = rc;
549 return eventchn_fd;
550 }
552 /*
553 * Local variables:
554 * c-file-style: "linux"
555 * indent-tabs-mode: t
556 * c-indent-level: 8
557 * c-basic-offset: 8
558 * tab-width: 8
559 * End:
560 */