debuggers.hg

view tools/xenstore/xenstored_domain.c @ 6676:d6d77aa96aa1

Make xenstored listen to domain exception virqs.
The virq triggers a scan for domains which have gone away, and then
removes those domains.
Signed-off-by: Christian Limpach <Christian.Limpach@cl.cam.ac.uk>
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 06 16:59:14 2005 +0000 (2005-09-06)
parents 22599cd6aae0
children d4d69c509371
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 unsigned int ringbuf_datasize;
43 struct domain
44 {
45 struct list_head list;
47 /* The id of this domain */
48 domid_t domid;
50 /* Event channel port */
51 u16 port;
53 /* Domain path in store. */
54 char *path;
56 /* Shared page. */
57 void *page;
59 /* Input and output ringbuffer heads. */
60 struct ringbuf_head *input, *output;
62 /* The connection associated with this. */
63 struct connection *conn;
65 };
67 static LIST_HEAD(domains);
69 struct ringbuf_head
70 {
71 u32 write; /* Next place to write to */
72 u32 read; /* Next place to read from */
73 u8 flags;
74 char buf[0];
75 } __attribute__((packed));
77 #define EVENTCHN_BIND _IO('E', 2)
78 #define EVENTCHN_UNBIND _IO('E', 3)
80 /* FIXME: Mark connection as broken (close it?) when this happens. */
81 static bool check_buffer(const struct ringbuf_head *h)
82 {
83 return (h->write < ringbuf_datasize && h->read < ringbuf_datasize);
84 }
86 /* We can't fill last byte: would look like empty buffer. */
87 static void *get_output_chunk(const struct ringbuf_head *h,
88 void *buf, u32 *len)
89 {
90 u32 read_mark;
92 if (h->read == 0)
93 read_mark = ringbuf_datasize - 1;
94 else
95 read_mark = h->read - 1;
97 /* Here to the end of buffer, unless they haven't read some out. */
98 *len = ringbuf_datasize - h->write;
99 if (read_mark >= h->write)
100 *len = read_mark - h->write;
101 return buf + h->write;
102 }
104 static const void *get_input_chunk(const struct ringbuf_head *h,
105 const void *buf, u32 *len)
106 {
107 /* Here to the end of buffer, unless they haven't written some. */
108 *len = ringbuf_datasize - h->read;
109 if (h->write >= h->read)
110 *len = h->write - h->read;
111 return buf + h->read;
112 }
114 static void update_output_chunk(struct ringbuf_head *h, u32 len)
115 {
116 h->write += len;
117 if (h->write == ringbuf_datasize)
118 h->write = 0;
119 }
121 static void update_input_chunk(struct ringbuf_head *h, u32 len)
122 {
123 h->read += len;
124 if (h->read == ringbuf_datasize)
125 h->read = 0;
126 }
128 static bool buffer_has_input(const struct ringbuf_head *h)
129 {
130 u32 len;
132 get_input_chunk(h, NULL, &len);
133 return (len != 0);
134 }
136 static bool buffer_has_output_room(const struct ringbuf_head *h)
137 {
138 u32 len;
140 get_output_chunk(h, NULL, &len);
141 return (len != 0);
142 }
144 static int writechn(struct connection *conn, const void *data, unsigned int len)
145 {
146 u32 avail;
147 void *dest;
148 struct ringbuf_head h;
150 /* Must read head once, and before anything else, and verified. */
151 h = *conn->domain->output;
152 mb();
153 if (!check_buffer(&h)) {
154 errno = EIO;
155 return -1;
156 }
158 dest = get_output_chunk(&h, conn->domain->output->buf, &avail);
159 if (avail < len)
160 len = avail;
162 memcpy(dest, data, len);
163 mb();
164 update_output_chunk(conn->domain->output, len);
165 /* FIXME: Probably not neccessary. */
166 mb();
167 xc_evtchn_send(*xc_handle, conn->domain->port);
168 return len;
169 }
171 static int readchn(struct connection *conn, void *data, unsigned int len)
172 {
173 u32 avail;
174 const void *src;
175 struct ringbuf_head h;
176 bool was_full;
178 /* Must read head once, and before anything else, and verified. */
179 h = *conn->domain->input;
180 mb();
182 if (!check_buffer(&h)) {
183 errno = EIO;
184 return -1;
185 }
187 src = get_input_chunk(&h, conn->domain->input->buf, &avail);
188 if (avail < len)
189 len = avail;
191 was_full = !buffer_has_output_room(&h);
192 memcpy(data, src, len);
193 mb();
194 update_input_chunk(conn->domain->input, len);
195 /* FIXME: Probably not neccessary. */
196 mb();
198 /* If it was full, tell them we've taken some. */
199 if (was_full)
200 xc_evtchn_send(*xc_handle, conn->domain->port);
201 return len;
202 }
204 static int destroy_domain(void *_domain)
205 {
206 struct domain *domain = _domain;
208 list_del(&domain->list);
210 if (domain->port &&
211 (ioctl(eventchn_fd, EVENTCHN_UNBIND, domain->port) != 0))
212 eprintf("> Unbinding port %i failed!\n", domain->port);
214 if(domain->page)
215 munmap(domain->page, getpagesize());
217 return 0;
218 }
220 /* We scan all domains rather than use the information given here. */
221 void handle_event(int event_fd)
222 {
223 u16 port;
225 if (read(event_fd, &port, sizeof(port)) != sizeof(port))
226 barf_perror("Failed to read from event fd");
227 #ifndef TESTING
228 if (write(event_fd, &port, sizeof(port)) != sizeof(port))
229 barf_perror("Failed to write to event fd");
230 #endif
231 }
233 bool domain_can_read(struct connection *conn)
234 {
235 return conn->state == OK && buffer_has_input(conn->domain->input);
236 }
238 bool domain_can_write(struct connection *conn)
239 {
240 return conn->out && buffer_has_output_room(conn->domain->output);
241 }
243 static struct domain *new_domain(void *context, domid_t domid,
244 unsigned long mfn, int port,
245 const char *path)
246 {
247 struct domain *domain;
248 domain = talloc(context, struct domain);
249 domain->port = 0;
250 domain->domid = domid;
251 domain->path = talloc_strdup(domain, path);
252 domain->page = xc_map_foreign_range(*xc_handle, domain->domid,
253 getpagesize(),
254 PROT_READ|PROT_WRITE,
255 mfn);
256 if (!domain->page)
257 return NULL;
259 list_add(&domain->list, &domains);
260 talloc_set_destructor(domain, destroy_domain);
262 /* One in each half of page. */
263 domain->input = domain->page;
264 domain->output = domain->page + getpagesize()/2;
266 /* Tell kernel we're interested in this event. */
267 if (ioctl(eventchn_fd, EVENTCHN_BIND, port) != 0)
268 return NULL;
270 domain->port = port;
271 domain->conn = new_connection(writechn, readchn);
272 domain->conn->domain = domain;
273 return domain;
274 }
276 /* domid, mfn, evtchn, path */
277 void do_introduce(struct connection *conn, struct buffered_data *in)
278 {
279 struct domain *domain;
280 char *vec[4];
282 if (get_strings(in, vec, ARRAY_SIZE(vec)) < ARRAY_SIZE(vec)) {
283 send_error(conn, EINVAL);
284 return;
285 }
287 if (conn->id != 0) {
288 send_error(conn, EACCES);
289 return;
290 }
292 if (!conn->can_write) {
293 send_error(conn, EROFS);
294 return;
295 }
297 /* Sanity check args. */
298 if ((atoi(vec[2]) <= 0) || !is_valid_nodename(vec[3])) {
299 send_error(conn, EINVAL);
300 return;
301 }
302 /* Hang domain off "in" until we're finished. */
303 domain = new_domain(in, atoi(vec[0]), atol(vec[1]), atol(vec[2]),
304 vec[3]);
305 if (!domain) {
306 send_error(conn, errno);
307 return;
308 }
310 /* Now domain belongs to its connection. */
311 talloc_steal(domain->conn, domain);
313 fire_watches(conn, "@introduceDomain", false);
315 send_ack(conn, XS_INTRODUCE);
316 }
318 static struct domain *find_domain_by_domid(domid_t domid)
319 {
320 struct domain *i;
322 list_for_each_entry(i, &domains, list) {
323 if (i->domid == domid)
324 return i;
325 }
326 return NULL;
327 }
329 /* domid */
330 void do_release(struct connection *conn, const char *domid_str)
331 {
332 struct domain *domain;
333 domid_t domid;
335 if (!domid_str) {
336 send_error(conn, EINVAL);
337 return;
338 }
340 domid = atoi(domid_str);
341 if (!domid) {
342 send_error(conn, EINVAL);
343 return;
344 }
346 if (conn->id != 0) {
347 send_error(conn, EACCES);
348 return;
349 }
351 domain = find_domain_by_domid(domid);
352 if (!domain) {
353 send_error(conn, ENOENT);
354 return;
355 }
357 if (!domain->conn) {
358 send_error(conn, EINVAL);
359 return;
360 }
362 talloc_free(domain->conn);
363 send_ack(conn, XS_RELEASE);
364 }
366 void domain_cleanup(void)
367 {
368 xc_dominfo_t dominfo;
369 struct domain *domain, *tmp;
371 list_for_each_entry_safe(domain, tmp, &domains, list) {
372 if (xc_domain_getinfo(*xc_handle, domain->domid, 1,
373 &dominfo) == 1 &&
374 dominfo.domid == domain->domid &&
375 !dominfo.dying && !dominfo.crashed && !dominfo.shutdown)
376 continue;
377 talloc_free(domain->conn);
378 }
379 }
381 void do_get_domain_path(struct connection *conn, const char *domid_str)
382 {
383 struct domain *domain;
384 domid_t domid;
386 if (!domid_str) {
387 send_error(conn, EINVAL);
388 return;
389 }
391 domid = atoi(domid_str);
392 if (domid == DOMID_SELF)
393 domain = conn->domain;
394 else
395 domain = find_domain_by_domid(domid);
397 if (!domain)
398 send_error(conn, ENOENT);
399 else
400 send_reply(conn, XS_GET_DOMAIN_PATH, domain->path,
401 strlen(domain->path) + 1);
402 }
404 static int close_xc_handle(void *_handle)
405 {
406 xc_interface_close(*(int *)_handle);
407 return 0;
408 }
410 /* Returns the implicit path of a connection (only domains have this) */
411 const char *get_implicit_path(const struct connection *conn)
412 {
413 if (!conn->domain)
414 return NULL;
415 return conn->domain->path;
416 }
418 /* Restore existing connections. */
419 void restore_existing_connections(void)
420 {
421 }
423 /* Returns the event channel handle. */
424 int domain_init(void)
425 {
426 /* The size of the ringbuffer: half a page minus head structure. */
427 ringbuf_datasize = getpagesize() / 2 - sizeof(struct ringbuf_head);
429 xc_handle = talloc(talloc_autofree_context(), int);
430 if (!xc_handle)
431 barf_perror("Failed to allocate domain handle");
432 *xc_handle = xc_interface_open();
433 if (*xc_handle < 0)
434 barf_perror("Failed to open connection to hypervisor");
435 talloc_set_destructor(xc_handle, close_xc_handle);
437 #ifdef TESTING
438 eventchn_fd = fake_open_eventchn();
439 #else
440 eventchn_fd = open("/dev/xen/evtchn", O_RDWR);
441 #endif
442 if (eventchn_fd < 0)
443 barf_perror("Failed to open connection to hypervisor");
444 return eventchn_fd;
445 }