ia64/xen-unstable

view tools/xenstore/xenstored_domain.c @ 6812:26cf3cfd3bed

Switch vcpu hotplugging to use xstransact.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 17:31:13 2005 +0000 (2005-09-13)
parents 72e4e2aab342
children 9af349b055e5 3233e7ecfa9f
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 }