ia64/xen-unstable

view tools/xenstore/xenstored_domain.c @ 7238:971e7c7411b3

Raise an exception if an error appears on the pipes to our children, and make
sure that the child's pipes are closed even under that exception. Move the
handling of POLLHUP to the end of the loop, so that we guarantee to read any
remaining data from the child if POLLHUP and POLLIN appear at the same time.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@ewan
date Thu Oct 06 10:13:11 2005 +0100 (2005-10-06)
parents 5e5ae8340956
children 61b3b357d827 4083eb31def0
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_watch.h"
37 #include "xenstored_test.h"
39 static int *xc_handle;
40 static int eventchn_fd;
41 static int virq_port;
42 static unsigned int ringbuf_datasize;
44 struct domain
45 {
46 struct list_head list;
48 /* The id of this domain */
49 domid_t domid;
51 /* Event channel port */
52 u16 port;
54 /* Domain path in store. */
55 char *path;
57 /* Shared page. */
58 void *page;
60 /* Input and output ringbuffer heads. */
61 struct ringbuf_head *input, *output;
63 /* The connection associated with this. */
64 struct connection *conn;
66 /* Have we noticed that this domain is shutdown? */
67 int shutdown;
68 };
70 static LIST_HEAD(domains);
72 struct ringbuf_head
73 {
74 u32 write; /* Next place to write to */
75 u32 read; /* Next place to read from */
76 u8 flags;
77 char buf[0];
78 } __attribute__((packed));
80 #define EVENTCHN_BIND _IO('E', 2)
81 #define EVENTCHN_UNBIND _IO('E', 3)
83 /* FIXME: Mark connection as broken (close it?) when this happens. */
84 static bool check_buffer(const struct ringbuf_head *h)
85 {
86 return (h->write < ringbuf_datasize && h->read < ringbuf_datasize);
87 }
89 /* We can't fill last byte: would look like empty buffer. */
90 static void *get_output_chunk(const struct ringbuf_head *h,
91 void *buf, u32 *len)
92 {
93 u32 read_mark;
95 if (h->read == 0)
96 read_mark = ringbuf_datasize - 1;
97 else
98 read_mark = h->read - 1;
100 /* Here to the end of buffer, unless they haven't read some out. */
101 *len = ringbuf_datasize - h->write;
102 if (read_mark >= h->write)
103 *len = read_mark - h->write;
104 return buf + h->write;
105 }
107 static const void *get_input_chunk(const struct ringbuf_head *h,
108 const void *buf, u32 *len)
109 {
110 /* Here to the end of buffer, unless they haven't written some. */
111 *len = ringbuf_datasize - h->read;
112 if (h->write >= h->read)
113 *len = h->write - h->read;
114 return buf + h->read;
115 }
117 static void update_output_chunk(struct ringbuf_head *h, u32 len)
118 {
119 h->write += len;
120 if (h->write == ringbuf_datasize)
121 h->write = 0;
122 }
124 static void update_input_chunk(struct ringbuf_head *h, u32 len)
125 {
126 h->read += len;
127 if (h->read == ringbuf_datasize)
128 h->read = 0;
129 }
131 static bool buffer_has_input(const struct ringbuf_head *h)
132 {
133 u32 len;
135 get_input_chunk(h, NULL, &len);
136 return (len != 0);
137 }
139 static bool buffer_has_output_room(const struct ringbuf_head *h)
140 {
141 u32 len;
143 get_output_chunk(h, NULL, &len);
144 return (len != 0);
145 }
147 static int writechn(struct connection *conn, const void *data, unsigned int len)
148 {
149 u32 avail;
150 void *dest;
151 struct ringbuf_head h;
153 /* Must read head once, and before anything else, and verified. */
154 h = *conn->domain->output;
155 mb();
156 if (!check_buffer(&h)) {
157 errno = EIO;
158 return -1;
159 }
161 dest = get_output_chunk(&h, conn->domain->output->buf, &avail);
162 if (avail < len)
163 len = avail;
165 memcpy(dest, data, len);
166 mb();
167 update_output_chunk(conn->domain->output, len);
168 /* FIXME: Probably not neccessary. */
169 mb();
170 xc_evtchn_send(*xc_handle, conn->domain->port);
171 return len;
172 }
174 static int readchn(struct connection *conn, void *data, unsigned int len)
175 {
176 u32 avail;
177 const void *src;
178 struct ringbuf_head h;
179 bool was_full;
181 /* Must read head once, and before anything else, and verified. */
182 h = *conn->domain->input;
183 mb();
185 if (!check_buffer(&h)) {
186 errno = EIO;
187 return -1;
188 }
190 src = get_input_chunk(&h, conn->domain->input->buf, &avail);
191 if (avail < len)
192 len = avail;
194 was_full = !buffer_has_output_room(&h);
195 memcpy(data, src, len);
196 mb();
197 update_input_chunk(conn->domain->input, len);
198 /* FIXME: Probably not neccessary. */
199 mb();
201 /* If it was full, tell them we've taken some. */
202 if (was_full)
203 xc_evtchn_send(*xc_handle, conn->domain->port);
204 return len;
205 }
207 static int destroy_domain(void *_domain)
208 {
209 struct domain *domain = _domain;
211 list_del(&domain->list);
213 if (domain->port &&
214 (ioctl(eventchn_fd, EVENTCHN_UNBIND, domain->port) != 0))
215 eprintf("> Unbinding port %i failed!\n", domain->port);
217 if(domain->page)
218 munmap(domain->page, getpagesize());
220 return 0;
221 }
223 static void domain_cleanup(void)
224 {
225 xc_dominfo_t dominfo;
226 struct domain *domain, *tmp;
227 int notify = 0;
229 list_for_each_entry_safe(domain, tmp, &domains, list) {
230 if (xc_domain_getinfo(*xc_handle, domain->domid, 1,
231 &dominfo) == 1 &&
232 dominfo.domid == domain->domid) {
233 if ((dominfo.crashed || dominfo.shutdown)
234 && !domain->shutdown) {
235 domain->shutdown = 1;
236 notify = 1;
237 }
238 if (!dominfo.dying)
239 continue;
240 }
241 talloc_free(domain->conn);
242 notify = 1;
243 }
245 if (notify)
246 fire_watches(NULL, "@releaseDomain", false);
247 }
249 /* We scan all domains rather than use the information given here. */
250 void handle_event(int event_fd)
251 {
252 u16 port;
254 if (read(event_fd, &port, sizeof(port)) != sizeof(port))
255 barf_perror("Failed to read from event fd");
257 if (port == virq_port)
258 domain_cleanup();
260 #ifndef TESTING
261 if (write(event_fd, &port, sizeof(port)) != sizeof(port))
262 barf_perror("Failed to write to event fd");
263 #endif
264 }
266 bool domain_can_read(struct connection *conn)
267 {
268 return conn->state == OK && buffer_has_input(conn->domain->input);
269 }
271 bool domain_can_write(struct connection *conn)
272 {
273 return conn->out && buffer_has_output_room(conn->domain->output);
274 }
276 static struct domain *new_domain(void *context, domid_t domid,
277 unsigned long mfn, int port,
278 const char *path)
279 {
280 struct domain *domain;
281 domain = talloc(context, struct domain);
282 domain->port = 0;
283 domain->shutdown = 0;
284 domain->domid = domid;
285 domain->path = talloc_strdup(domain, path);
286 domain->page = xc_map_foreign_range(*xc_handle, domain->domid,
287 getpagesize(),
288 PROT_READ|PROT_WRITE,
289 mfn);
290 if (!domain->page)
291 return NULL;
293 list_add(&domain->list, &domains);
294 talloc_set_destructor(domain, destroy_domain);
296 /* One in each half of page. */
297 domain->input = domain->page;
298 domain->output = domain->page + getpagesize()/2;
300 /* Tell kernel we're interested in this event. */
301 if (ioctl(eventchn_fd, EVENTCHN_BIND, port) != 0)
302 return NULL;
304 domain->port = port;
305 domain->conn = new_connection(writechn, readchn);
306 domain->conn->domain = domain;
307 return domain;
308 }
310 /* domid, mfn, evtchn, path */
311 void do_introduce(struct connection *conn, struct buffered_data *in)
312 {
313 struct domain *domain;
314 char *vec[4];
316 if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
317 send_error(conn, EINVAL);
318 return;
319 }
321 if (conn->id != 0 || !conn->can_write) {
322 send_error(conn, EACCES);
323 return;
324 }
326 /* Sanity check args. */
327 if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
328 send_error(conn, EINVAL);
329 return;
330 }
331 /* Hang domain off "in" until we're finished. */
332 domain = new_domain(in, atoi(vec[0]), atol(vec[1]), atol(vec[2]),
333 vec[3]);
334 if (!domain) {
335 send_error(conn, errno);
336 return;
337 }
339 /* Now domain belongs to its connection. */
340 talloc_steal(domain->conn, domain);
342 fire_watches(conn, "@introduceDomain", false);
344 send_ack(conn, XS_INTRODUCE);
345 }
347 static struct domain *find_domain_by_domid(domid_t domid)
348 {
349 struct domain *i;
351 list_for_each_entry(i, &domains, list) {
352 if (i->domid == domid)
353 return i;
354 }
355 return NULL;
356 }
358 /* domid */
359 void do_release(struct connection *conn, const char *domid_str)
360 {
361 struct domain *domain;
362 domid_t domid;
364 if (!domid_str) {
365 send_error(conn, EINVAL);
366 return;
367 }
369 domid = atoi(domid_str);
370 if (!domid) {
371 send_error(conn, EINVAL);
372 return;
373 }
375 if (conn->id != 0) {
376 send_error(conn, EACCES);
377 return;
378 }
380 domain = find_domain_by_domid(domid);
381 if (!domain) {
382 send_error(conn, ENOENT);
383 return;
384 }
386 if (!domain->conn) {
387 send_error(conn, EINVAL);
388 return;
389 }
391 talloc_free(domain->conn);
393 fire_watches(conn, "@releaseDomain", false);
395 send_ack(conn, XS_RELEASE);
396 }
398 void do_get_domain_path(struct connection *conn, const char *domid_str)
399 {
400 struct domain *domain;
401 domid_t domid;
403 if (!domid_str) {
404 send_error(conn, EINVAL);
405 return;
406 }
408 domid = atoi(domid_str);
409 if (domid == DOMID_SELF)
410 domain = conn->domain;
411 else
412 domain = find_domain_by_domid(domid);
414 if (!domain)
415 send_error(conn, ENOENT);
416 else
417 send_reply(conn, XS_GET_DOMAIN_PATH, domain->path,
418 strlen(domain->path) + 1);
419 }
421 static int close_xc_handle(void *_handle)
422 {
423 xc_interface_close(*(int *)_handle);
424 return 0;
425 }
427 /* Returns the implicit path of a connection (only domains have this) */
428 const char *get_implicit_path(const struct connection *conn)
429 {
430 if (!conn->domain)
431 return NULL;
432 return conn->domain->path;
433 }
435 /* Restore existing connections. */
436 void restore_existing_connections(void)
437 {
438 }
440 #define EVTCHN_DEV_NAME "/dev/xen/evtchn"
441 #define EVTCHN_DEV_MAJOR 10
442 #define EVTCHN_DEV_MINOR 201
444 /* Returns the event channel handle. */
445 int domain_init(void)
446 {
447 struct stat st;
449 /* The size of the ringbuffer: half a page minus head structure. */
450 ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head);
452 xc_handle = talloc(talloc_autofree_context(), int);
453 if (!xc_handle)
454 barf_perror("Failed to allocate domain handle");
456 *xc_handle = xc_interface_open();
457 if (*xc_handle < 0)
458 barf_perror("Failed to open connection to hypervisor");
460 talloc_set_destructor(xc_handle, close_xc_handle);
462 #ifdef TESTING
463 eventchn_fd = fake_open_eventchn();
464 (void)&st;
465 #else
466 /* Make sure any existing device file links to correct device. */
467 if ((lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
468 (st.st_rdev != makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)))
469 (void)unlink(EVTCHN_DEV_NAME);
471 reopen:
472 eventchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
473 if (eventchn_fd == -1) {
474 if ((errno == ENOENT) &&
475 ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
476 (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
477 makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)) == 0))
478 goto reopen;
479 return -errno;
480 }
481 #endif
482 if (eventchn_fd < 0)
483 barf_perror("Failed to open evtchn device");
485 if (xc_evtchn_bind_virq(*xc_handle, VIRQ_DOM_EXC, &virq_port))
486 barf_perror("Failed to bind to domain exception virq");
488 if (ioctl(eventchn_fd, EVENTCHN_BIND, virq_port) != 0)
489 barf_perror("Failed to bind to domain exception virq port");
491 return eventchn_fd;
492 }