ia64/xen-unstable

view tools/xenstore/xenstored_domain.c @ 6946:e703abaf6e3d

Add behaviour to the remove methods to remove the transaction's path itself. This allows us to write Remove(path) to remove the specified path rather than having to slice the path ourselves.
author emellor@ewan
date Sun Sep 18 14:42:13 2005 +0100 (2005-09-18)
parents 3233e7ecfa9f
children 06d84bf87159
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 };
68 static LIST_HEAD(domains);
70 struct ringbuf_head
71 {
72 u32 write; /* Next place to write to */
73 u32 read; /* Next place to read from */
74 u8 flags;
75 char buf[0];
76 } __attribute__((packed));
78 #define EVENTCHN_BIND _IO('E', 2)
79 #define EVENTCHN_UNBIND _IO('E', 3)
81 /* FIXME: Mark connection as broken (close it?) when this happens. */
82 static bool check_buffer(const struct ringbuf_head *h)
83 {
84 return (h->write < ringbuf_datasize && h->read < ringbuf_datasize);
85 }
87 /* We can't fill last byte: would look like empty buffer. */
88 static void *get_output_chunk(const struct ringbuf_head *h,
89 void *buf, u32 *len)
90 {
91 u32 read_mark;
93 if (h->read == 0)
94 read_mark = ringbuf_datasize - 1;
95 else
96 read_mark = h->read - 1;
98 /* Here to the end of buffer, unless they haven't read some out. */
99 *len = ringbuf_datasize - h->write;
100 if (read_mark >= h->write)
101 *len = read_mark - h->write;
102 return buf + h->write;
103 }
105 static const void *get_input_chunk(const struct ringbuf_head *h,
106 const void *buf, u32 *len)
107 {
108 /* Here to the end of buffer, unless they haven't written some. */
109 *len = ringbuf_datasize - h->read;
110 if (h->write >= h->read)
111 *len = h->write - h->read;
112 return buf + h->read;
113 }
115 static void update_output_chunk(struct ringbuf_head *h, u32 len)
116 {
117 h->write += len;
118 if (h->write == ringbuf_datasize)
119 h->write = 0;
120 }
122 static void update_input_chunk(struct ringbuf_head *h, u32 len)
123 {
124 h->read += len;
125 if (h->read == ringbuf_datasize)
126 h->read = 0;
127 }
129 static bool buffer_has_input(const struct ringbuf_head *h)
130 {
131 u32 len;
133 get_input_chunk(h, NULL, &len);
134 return (len != 0);
135 }
137 static bool buffer_has_output_room(const struct ringbuf_head *h)
138 {
139 u32 len;
141 get_output_chunk(h, NULL, &len);
142 return (len != 0);
143 }
145 static int writechn(struct connection *conn, const void *data, unsigned int len)
146 {
147 u32 avail;
148 void *dest;
149 struct ringbuf_head h;
151 /* Must read head once, and before anything else, and verified. */
152 h = *conn->domain->output;
153 mb();
154 if (!check_buffer(&h)) {
155 errno = EIO;
156 return -1;
157 }
159 dest = get_output_chunk(&h, conn->domain->output->buf, &avail);
160 if (avail < len)
161 len = avail;
163 memcpy(dest, data, len);
164 mb();
165 update_output_chunk(conn->domain->output, len);
166 /* FIXME: Probably not neccessary. */
167 mb();
168 xc_evtchn_send(*xc_handle, conn->domain->port);
169 return len;
170 }
172 static int readchn(struct connection *conn, void *data, unsigned int len)
173 {
174 u32 avail;
175 const void *src;
176 struct ringbuf_head h;
177 bool was_full;
179 /* Must read head once, and before anything else, and verified. */
180 h = *conn->domain->input;
181 mb();
183 if (!check_buffer(&h)) {
184 errno = EIO;
185 return -1;
186 }
188 src = get_input_chunk(&h, conn->domain->input->buf, &avail);
189 if (avail < len)
190 len = avail;
192 was_full = !buffer_has_output_room(&h);
193 memcpy(data, src, len);
194 mb();
195 update_input_chunk(conn->domain->input, len);
196 /* FIXME: Probably not neccessary. */
197 mb();
199 /* If it was full, tell them we've taken some. */
200 if (was_full)
201 xc_evtchn_send(*xc_handle, conn->domain->port);
202 return len;
203 }
205 static int destroy_domain(void *_domain)
206 {
207 struct domain *domain = _domain;
209 list_del(&domain->list);
211 if (domain->port &&
212 (ioctl(eventchn_fd, EVENTCHN_UNBIND, domain->port) != 0))
213 eprintf("> Unbinding port %i failed!\n", domain->port);
215 if(domain->page)
216 munmap(domain->page, getpagesize());
218 return 0;
219 }
221 static void domain_cleanup(void)
222 {
223 xc_dominfo_t dominfo;
224 struct domain *domain, *tmp;
225 int released = 0;
227 list_for_each_entry_safe(domain, tmp, &domains, list) {
228 if (xc_domain_getinfo(*xc_handle, domain->domid, 1,
229 &dominfo) == 1 &&
230 dominfo.domid == domain->domid &&
231 !dominfo.dying && !dominfo.crashed && !dominfo.shutdown)
232 continue;
233 talloc_free(domain->conn);
234 released++;
235 }
237 if (released)
238 fire_watches(NULL, "@releaseDomain", false);
239 }
241 /* We scan all domains rather than use the information given here. */
242 void handle_event(int event_fd)
243 {
244 u16 port;
246 if (read(event_fd, &port, sizeof(port)) != sizeof(port))
247 barf_perror("Failed to read from event fd");
249 if (port == virq_port)
250 domain_cleanup();
252 #ifndef TESTING
253 if (write(event_fd, &port, sizeof(port)) != sizeof(port))
254 barf_perror("Failed to write to event fd");
255 #endif
256 }
258 bool domain_can_read(struct connection *conn)
259 {
260 return conn->state == OK && buffer_has_input(conn->domain->input);
261 }
263 bool domain_can_write(struct connection *conn)
264 {
265 return conn->out && buffer_has_output_room(conn->domain->output);
266 }
268 static struct domain *new_domain(void *context, domid_t domid,
269 unsigned long mfn, int port,
270 const char *path)
271 {
272 struct domain *domain;
273 domain = talloc(context, struct domain);
274 domain->port = 0;
275 domain->domid = domid;
276 domain->path = talloc_strdup(domain, path);
277 domain->page = xc_map_foreign_range(*xc_handle, domain->domid,
278 getpagesize(),
279 PROT_READ|PROT_WRITE,
280 mfn);
281 if (!domain->page)
282 return NULL;
284 list_add(&domain->list, &domains);
285 talloc_set_destructor(domain, destroy_domain);
287 /* One in each half of page. */
288 domain->input = domain->page;
289 domain->output = domain->page + getpagesize()/2;
291 /* Tell kernel we're interested in this event. */
292 if (ioctl(eventchn_fd, EVENTCHN_BIND, port) != 0)
293 return NULL;
295 domain->port = port;
296 domain->conn = new_connection(writechn, readchn);
297 domain->conn->domain = domain;
298 return domain;
299 }
301 /* domid, mfn, evtchn, path */
302 void do_introduce(struct connection *conn, struct buffered_data *in)
303 {
304 struct domain *domain;
305 char *vec[4];
307 if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
308 send_error(conn, EINVAL);
309 return;
310 }
312 if (conn->id != 0) {
313 send_error(conn, EACCES);
314 return;
315 }
317 if (!conn->can_write) {
318 send_error(conn, EROFS);
319 return;
320 }
322 /* Sanity check args. */
323 if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
324 send_error(conn, EINVAL);
325 return;
326 }
327 /* Hang domain off "in" until we're finished. */
328 domain = new_domain(in, atoi(vec[0]), atol(vec[1]), atol(vec[2]),
329 vec[3]);
330 if (!domain) {
331 send_error(conn, errno);
332 return;
333 }
335 /* Now domain belongs to its connection. */
336 talloc_steal(domain->conn, domain);
338 fire_watches(conn, "@introduceDomain", false);
340 send_ack(conn, XS_INTRODUCE);
341 }
343 static struct domain *find_domain_by_domid(domid_t domid)
344 {
345 struct domain *i;
347 list_for_each_entry(i, &domains, list) {
348 if (i->domid == domid)
349 return i;
350 }
351 return NULL;
352 }
354 /* domid */
355 void do_release(struct connection *conn, const char *domid_str)
356 {
357 struct domain *domain;
358 domid_t domid;
360 if (!domid_str) {
361 send_error(conn, EINVAL);
362 return;
363 }
365 domid = atoi(domid_str);
366 if (!domid) {
367 send_error(conn, EINVAL);
368 return;
369 }
371 if (conn->id != 0) {
372 send_error(conn, EACCES);
373 return;
374 }
376 domain = find_domain_by_domid(domid);
377 if (!domain) {
378 send_error(conn, ENOENT);
379 return;
380 }
382 if (!domain->conn) {
383 send_error(conn, EINVAL);
384 return;
385 }
387 talloc_free(domain->conn);
389 fire_watches(NULL, "@releaseDomain", false);
391 send_ack(conn, XS_RELEASE);
392 }
394 void do_get_domain_path(struct connection *conn, const char *domid_str)
395 {
396 struct domain *domain;
397 domid_t domid;
399 if (!domid_str) {
400 send_error(conn, EINVAL);
401 return;
402 }
404 domid = atoi(domid_str);
405 if (domid == DOMID_SELF)
406 domain = conn->domain;
407 else
408 domain = find_domain_by_domid(domid);
410 if (!domain)
411 send_error(conn, ENOENT);
412 else
413 send_reply(conn, XS_GET_DOMAIN_PATH, domain->path,
414 strlen(domain->path) + 1);
415 }
417 static int close_xc_handle(void *_handle)
418 {
419 xc_interface_close(*(int *)_handle);
420 return 0;
421 }
423 /* Returns the implicit path of a connection (only domains have this) */
424 const char *get_implicit_path(const struct connection *conn)
425 {
426 if (!conn->domain)
427 return NULL;
428 return conn->domain->path;
429 }
431 /* Restore existing connections. */
432 void restore_existing_connections(void)
433 {
434 }
436 #define EVTCHN_DEV_NAME "/dev/xen/evtchn"
437 #define EVTCHN_DEV_MAJOR 10
438 #define EVTCHN_DEV_MINOR 201
440 /* Returns the event channel handle. */
441 int domain_init(void)
442 {
443 struct stat st;
445 /* The size of the ringbuffer: half a page minus head structure. */
446 ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head);
448 xc_handle = talloc(talloc_autofree_context(), int);
449 if (!xc_handle)
450 barf_perror("Failed to allocate domain handle");
452 *xc_handle = xc_interface_open();
453 if (*xc_handle < 0)
454 barf_perror("Failed to open connection to hypervisor");
456 talloc_set_destructor(xc_handle, close_xc_handle);
458 #ifdef TESTING
459 eventchn_fd = fake_open_eventchn();
460 (void)&st;
461 #else
462 /* Make sure any existing device file links to correct device. */
463 if ((lstat(EVTCHN_DEV_NAME, &st) != 0) || !S_ISCHR(st.st_mode) ||
464 (st.st_rdev != makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)))
465 (void)unlink(EVTCHN_DEV_NAME);
467 reopen:
468 eventchn_fd = open(EVTCHN_DEV_NAME, O_NONBLOCK|O_RDWR);
469 if (eventchn_fd == -1) {
470 if ((errno == ENOENT) &&
471 ((mkdir("/dev/xen", 0755) == 0) || (errno == EEXIST)) &&
472 (mknod(EVTCHN_DEV_NAME, S_IFCHR|0600,
473 makedev(EVTCHN_DEV_MAJOR, EVTCHN_DEV_MINOR)) == 0))
474 goto reopen;
475 return -errno;
476 }
477 #endif
478 if (eventchn_fd < 0)
479 barf_perror("Failed to open evtchn device");
481 if (xc_evtchn_bind_virq(*xc_handle, VIRQ_DOM_EXC, &virq_port))
482 barf_perror("Failed to bind to domain exception virq");
484 if (ioctl(eventchn_fd, EVENTCHN_BIND, virq_port) != 0)
485 barf_perror("Failed to bind to domain exception virq port");
487 return eventchn_fd;
488 }