ia64/xen-unstable

view tools/xenstore/xenstored_domain.c @ 8740:3d7ea7972b39

Update patches for linux 2.6.15.

Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Thu Feb 02 17:16:00 2006 +0000 (2006-02-02)
parents 1f87f39aa0e1
children c9edeb3bd652
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 evtchn_port_t 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 evtchn_port_t port;
58 /* The remote end of the event channel, used only to validate
59 repeated domain introductions. */
60 evtchn_port_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 evtchn_port_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;
290 domain->conn->id = domid;
292 domain->remote_port = port;
293 domain->mfn = mfn;
295 return domain;
296 }
299 static struct domain *find_domain_by_domid(unsigned int domid)
300 {
301 struct domain *i;
303 list_for_each_entry(i, &domains, list) {
304 if (i->domid == domid)
305 return i;
306 }
307 return NULL;
308 }
311 /* domid, mfn, evtchn, path */
312 void do_introduce(struct connection *conn, struct buffered_data *in)
313 {
314 struct domain *domain;
315 char *vec[3];
316 unsigned int domid;
317 unsigned long mfn;
318 evtchn_port_t port;
320 if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
321 send_error(conn, EINVAL);
322 return;
323 }
325 if (conn->id != 0 || !conn->can_write) {
326 send_error(conn, EACCES);
327 return;
328 }
330 domid = atoi(vec[0]);
331 mfn = atol(vec[1]);
332 port = atoi(vec[2]);
334 /* Sanity check args. */
335 if (port <= 0) {
336 send_error(conn, EINVAL);
337 return;
338 }
340 domain = find_domain_by_domid(domid);
342 if (domain == NULL) {
343 /* Hang domain off "in" until we're finished. */
344 domain = new_domain(in, domid, mfn, port);
345 if (!domain) {
346 send_error(conn, errno);
347 return;
348 }
350 /* Now domain belongs to its connection. */
351 talloc_steal(domain->conn, domain);
353 fire_watches(conn, "@introduceDomain", false);
354 }
355 else {
356 /* Check that the given details match the ones we have
357 previously recorded. */
358 if (port != domain->remote_port ||
359 mfn != domain->mfn) {
360 send_error(conn, EINVAL);
361 return;
362 }
363 }
365 send_ack(conn, XS_INTRODUCE);
366 }
368 /* domid */
369 void do_release(struct connection *conn, const char *domid_str)
370 {
371 struct domain *domain;
372 unsigned int domid;
374 if (!domid_str) {
375 send_error(conn, EINVAL);
376 return;
377 }
379 domid = atoi(domid_str);
380 if (!domid) {
381 send_error(conn, EINVAL);
382 return;
383 }
385 if (conn->id != 0) {
386 send_error(conn, EACCES);
387 return;
388 }
390 domain = find_domain_by_domid(domid);
391 if (!domain) {
392 send_error(conn, ENOENT);
393 return;
394 }
396 if (!domain->conn) {
397 send_error(conn, EINVAL);
398 return;
399 }
401 talloc_free(domain->conn);
403 fire_watches(conn, "@releaseDomain", false);
405 send_ack(conn, XS_RELEASE);
406 }
408 void do_get_domain_path(struct connection *conn, const char *domid_str)
409 {
410 char *path;
412 if (!domid_str) {
413 send_error(conn, EINVAL);
414 return;
415 }
417 path = talloc_domain_path(conn, atoi(domid_str));
419 send_reply(conn, XS_GET_DOMAIN_PATH, path, strlen(path) + 1);
421 talloc_free(path);
422 }
424 void do_is_domain_introduced(struct connection *conn, const char *domid_str)
425 {
426 int result;
427 unsigned int domid;
429 if (!domid_str) {
430 send_error(conn, EINVAL);
431 return;
432 }
434 domid = atoi(domid_str);
435 if (domid == DOMID_SELF)
436 result = 1;
437 else
438 result = (find_domain_by_domid(domid) != NULL);
440 send_reply(conn, XS_IS_DOMAIN_INTRODUCED, result ? "T" : "F", 2);
441 }
443 static int close_xc_handle(void *_handle)
444 {
445 xc_interface_close(*(int *)_handle);
446 return 0;
447 }
449 /* Returns the implicit path of a connection (only domains have this) */
450 const char *get_implicit_path(const struct connection *conn)
451 {
452 if (!conn->domain)
453 return NULL;
454 return conn->domain->path;
455 }
457 /* Restore existing connections. */
458 void restore_existing_connections(void)
459 {
460 }
462 static int dom0_init(void)
463 {
464 int rc, fd;
465 evtchn_port_t port;
466 unsigned long mfn;
467 char str[20];
468 struct domain *dom0;
470 fd = open(XENSTORED_PROC_MFN, O_RDONLY);
471 if (fd == -1)
472 return -1;
474 rc = read(fd, str, sizeof(str));
475 if (rc == -1)
476 goto outfd;
477 str[rc] = '\0';
478 mfn = strtoul(str, NULL, 0);
480 close(fd);
482 fd = open(XENSTORED_PROC_PORT, O_RDONLY);
483 if (fd == -1)
484 return -1;
486 rc = read(fd, str, sizeof(str));
487 if (rc == -1)
488 goto outfd;
489 str[rc] = '\0';
490 port = strtoul(str, NULL, 0);
492 close(fd);
494 dom0 = new_domain(NULL, 0, mfn, port);
495 talloc_steal(dom0->conn, dom0);
497 evtchn_notify(dom0->port);
499 return 0;
500 outfd:
501 close(fd);
502 return -1;
503 }
507 #define EVTCHN_DEV_NAME "/dev/xen/evtchn"
508 #define EVTCHN_DEV_MAJOR 10
509 #define EVTCHN_DEV_MINOR 201
512 /* Returns the event channel handle. */
513 int domain_init(void)
514 {
515 struct stat st;
516 struct ioctl_evtchn_bind_virq bind;
517 int rc;
519 xc_handle = talloc(talloc_autofree_context(), int);
520 if (!xc_handle)
521 barf_perror("Failed to allocate domain handle");
523 *xc_handle = xc_interface_open();
524 if (*xc_handle < 0)
525 barf_perror("Failed to open connection to hypervisor");
527 talloc_set_destructor(xc_handle, close_xc_handle);
529 #ifdef TESTING
530 eventchn_fd = fake_open_eventchn();
531 (void)&st;
532 #else
533 /* Make sure any existing device file links to correct device. */
534 if ((lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
535 (st.st_rdev != makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)))
536 (void)unlink(EVTCHN_DEV_NAME);
538 reopen:
539 eventchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
540 if (eventchn_fd == -1) {
541 if ((errno == ENOENT) &&
542 ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
543 (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
544 makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)) == 0))
545 goto reopen;
546 return -errno;
547 }
548 #endif
549 if (eventchn_fd < 0)
550 barf_perror("Failed to open evtchn device");
552 if (dom0_init() != 0)
553 barf_perror("Failed to initialize dom0 state");
555 bind.virq = VIRQ_DOM_EXC;
556 rc = ioctl(eventchn_fd, IOCTL_EVTCHN_BIND_VIRQ, &bind);
557 if (rc == -1)
558 barf_perror("Failed to bind to domain exception virq port");
559 virq_port = rc;
561 return eventchn_fd;
562 }
564 /*
565 * Local variables:
566 * c-file-style: "linux"
567 * indent-tabs-mode: t
568 * c-indent-level: 8
569 * c-basic-offset: 8
570 * tab-width: 8
571 * End:
572 */