ia64/xen-unstable

view tools/xenstore/xenstored_domain.c @ 6690:b7c7cb88f0ba

Create /dev/xen/evtchn if it doesn't exist.

Signed-off-by: Steven Hand <steven@xensource.com>
author shand@ubuntu.eng.hq.xensource.com
date Wed Sep 07 12:30:00 2005 -0800 (2005-09-07)
parents acde14d25398
children 7bc32f4c67fb
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 /* We scan all domains rather than use the information given here. */
222 void handle_event(int event_fd)
223 {
224 u16 port;
226 if (read(event_fd, &port, sizeof(port)) != sizeof(port))
227 barf_perror("Failed to read from event fd");
229 if (port == virq_port)
230 domain_cleanup();
232 #ifndef TESTING
233 if (write(event_fd, &port, sizeof(port)) != sizeof(port))
234 barf_perror("Failed to write to event fd");
235 #endif
236 }
238 bool domain_can_read(struct connection *conn)
239 {
240 return conn->state == OK && buffer_has_input(conn->domain->input);
241 }
243 bool domain_can_write(struct connection *conn)
244 {
245 return conn->out && buffer_has_output_room(conn->domain->output);
246 }
248 static struct domain *new_domain(void *context, domid_t domid,
249 unsigned long mfn, int port,
250 const char *path)
251 {
252 struct domain *domain;
253 domain = talloc(context, struct domain);
254 domain->port = 0;
255 domain->domid = domid;
256 domain->path = talloc_strdup(domain, path);
257 domain->page = xc_map_foreign_range(*xc_handle, domain->domid,
258 getpagesize(),
259 PROT_READ|PROT_WRITE,
260 mfn);
261 if (!domain->page)
262 return NULL;
264 list_add(&domain->list, &domains);
265 talloc_set_destructor(domain, destroy_domain);
267 /* One in each half of page. */
268 domain->input = domain->page;
269 domain->output = domain->page + getpagesize()/2;
271 /* Tell kernel we're interested in this event. */
272 if (ioctl(eventchn_fd, EVENTCHN_BIND, port) != 0)
273 return NULL;
275 domain->port = port;
276 domain->conn = new_connection(writechn, readchn);
277 domain->conn->domain = domain;
278 return domain;
279 }
281 /* domid, mfn, evtchn, path */
282 void do_introduce(struct connection *conn, struct buffered_data *in)
283 {
284 struct domain *domain;
285 char *vec[4];
287 if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
288 send_error(conn, EINVAL);
289 return;
290 }
292 if (conn->id != 0) {
293 send_error(conn, EACCES);
294 return;
295 }
297 if (!conn->can_write) {
298 send_error(conn, EROFS);
299 return;
300 }
302 /* Sanity check args. */
303 if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
304 send_error(conn, EINVAL);
305 return;
306 }
307 /* Hang domain off "in" until we're finished. */
308 domain = new_domain(in, atoi(vec[0]), atol(vec[1]), atol(vec[2]),
309 vec[3]);
310 if (!domain) {
311 send_error(conn, errno);
312 return;
313 }
315 /* Now domain belongs to its connection. */
316 talloc_steal(domain->conn, domain);
318 fire_watches(conn, "@introduceDomain", false);
320 send_ack(conn, XS_INTRODUCE);
321 }
323 static struct domain *find_domain_by_domid(domid_t domid)
324 {
325 struct domain *i;
327 list_for_each_entry(i, &domains, list) {
328 if (i->domid == domid)
329 return i;
330 }
331 return NULL;
332 }
334 /* domid */
335 void do_release(struct connection *conn, const char *domid_str)
336 {
337 struct domain *domain;
338 domid_t domid;
340 if (!domid_str) {
341 send_error(conn, EINVAL);
342 return;
343 }
345 domid = atoi(domid_str);
346 if (!domid) {
347 send_error(conn, EINVAL);
348 return;
349 }
351 if (conn->id != 0) {
352 send_error(conn, EACCES);
353 return;
354 }
356 domain = find_domain_by_domid(domid);
357 if (!domain) {
358 send_error(conn, ENOENT);
359 return;
360 }
362 if (!domain->conn) {
363 send_error(conn, EINVAL);
364 return;
365 }
367 talloc_free(domain->conn);
369 fire_watches(NULL, "@releaseDomain", false);
371 send_ack(conn, XS_RELEASE);
372 }
374 void domain_cleanup(void)
375 {
376 xc_dominfo_t dominfo;
377 struct domain *domain, *tmp;
378 int released = 0;
380 list_for_each_entry_safe(domain, tmp, &domains, list) {
381 if (xc_domain_getinfo(*xc_handle, domain->domid, 1,
382 &dominfo) == 1 &&
383 dominfo.domid == domain->domid &&
384 !dominfo.dying && !dominfo.crashed && !dominfo.shutdown)
385 continue;
386 talloc_free(domain->conn);
387 released++;
388 }
390 if (released)
391 fire_watches(NULL, "@releaseDomain", false);
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 /* The size of the ringbuffer: half a page minus head structure. */
444 ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head);
446 xc_handle = talloc(talloc_autofree_context(), int);
447 if (!xc_handle)
448 barf_perror("Failed to allocate domain handle");
450 *xc_handle = xc_interface_open();
451 if (*xc_handle < 0)
452 barf_perror("Failed to open connection to hypervisor (privcmd)");
454 talloc_set_destructor(xc_handle, close_xc_handle);
456 #ifdef TESTING
457 eventchn_fd = fake_open_eventchn();
458 #else
459 {
460 struct stat st;
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 }
478 #endif
479 if (eventchn_fd < 0)
480 barf_perror("Failed to open connection to hypervisor (evtchn)");
482 if (xc_evtchn_bind_virq(*xc_handle, VIRQ_DOM_EXC, &virq_port))
483 barf_perror("Failed to bind to domain exception virq");
485 if (ioctl(eventchn_fd, EVENTCHN_BIND, virq_port) != 0)
486 barf_perror("Failed to bind to domain exception virq port");
488 return eventchn_fd;
489 }