ia64/xen-unstable

view tools/blktap/xenbus.c @ 9488:0a6f5527ca4b

[IA64] set itv handoff as masked and enable reading irr[0-3]

Set initial vcpu itv handoff state to mask the timer vector.
This seems to match hardware and makes logical sense from a
spurious interrupt perspective. Enable vcpu_get_irr[0-3]
functions as they seem to work and have the proper backing.
This enables the check_sal_cache_flush() in arch/ia64/kernel.sal.c
to work unmodified, allowing us to remove the Xen changes from
the file (and thus the file from the sparse tree).

Signed-off-by: Alex Williamson <alex.williamson@hp.com>
author awilliam@xenbuild.aw
date Tue Apr 04 09:39:45 2006 -0600 (2006-04-04)
parents fcb7e5616102
children
line source
1 /*
2 * xenbus.c
3 *
4 * xenbus interface to the blocktap.
5 *
6 * this handles the top-half of integration with block devices through the
7 * store -- the tap driver negotiates the device channel etc, while the
8 * userland tap clinet needs to sort out the disk parameters etc.
9 *
10 * A. Warfield 2005 Based primarily on the blkback and xenbus driver code.
11 * Comments there apply here...
12 */
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <err.h>
18 #include <stdarg.h>
19 #include <errno.h>
20 #include <xs.h>
21 #include <sys/types.h>
22 #include <sys/stat.h>
23 #include <fcntl.h>
24 #include <poll.h>
25 #include "blktaplib.h"
26 #include "list.h"
28 #if 0
29 #define DPRINTF(_f, _a...) printf ( _f , ## _a )
30 #else
31 #define DPRINTF(_f, _a...) ((void)0)
32 #endif
34 /* --- Xenstore / Xenbus helpers ---------------------------------------- */
35 /*
36 * These should all be pulled out into the xenstore API. I'm faulting commands
37 * in from the xenbus interface as i need them.
38 */
41 /* Takes tuples of names, scanf-style args, and void **, NULL terminated. */
42 int xs_gather(struct xs_handle *xs, const char *dir, ...)
43 {
44 va_list ap;
45 const char *name;
46 char *path;
47 int ret = 0;
49 va_start(ap, dir);
50 while (ret == 0 && (name = va_arg(ap, char *)) != NULL) {
51 const char *fmt = va_arg(ap, char *);
52 void *result = va_arg(ap, void *);
53 char *p;
55 if (asprintf(&path, "%s/%s", dir, name) == -1)
56 {
57 warn("allocation error in xs_gather!\n");
58 ret = ENOMEM;
59 break;
60 }
61 p = xs_read(xs, path, NULL);
62 free(path);
63 if (p == NULL) {
64 ret = ENOENT;
65 break;
66 }
67 if (fmt) {
68 if (sscanf(p, fmt, result) == 0)
69 ret = EINVAL;
70 free(p);
71 } else
72 *(char **)result = p;
73 }
74 va_end(ap);
75 return ret;
76 }
78 /* Single printf and write: returns -errno or 0. */
79 int xs_printf(struct xs_handle *h, const char *dir, const char *node,
80 const char *fmt, ...)
81 {
82 char *buf, *path;
83 va_list ap;
84 int ret;
86 va_start(ap, fmt);
87 ret = vasprintf(&buf, fmt, ap);
88 va_end(ap);
90 asprintf(&path, "%s/%s", dir, node);
92 if ((path == NULL) || (buf == NULL))
93 return 0;
95 ret = xs_write(h, path, buf, strlen(buf)+1);
97 free(buf);
98 free(path);
100 return ret;
101 }
104 int xs_exists(struct xs_handle *h, const char *path)
105 {
106 char **d;
107 int num;
109 d = xs_directory(h, path, &num);
110 if (d == NULL)
111 return 0;
112 free(d);
113 return 1;
114 }
118 /* This assumes that the domain name we are looking for is unique! */
119 char *get_dom_domid(struct xs_handle *h, const char *name)
120 {
121 char **e, *val, *domid = NULL;
122 int num, i, len;
123 char *path;
125 e = xs_directory(h, "/local/domain", &num);
127 i=0;
128 while (i < num) {
129 asprintf(&path, "/local/domain/%s/name", e[i]);
130 val = xs_read(h, path, &len);
131 free(path);
132 if (val == NULL)
133 continue;
134 if (strcmp(val, name) == 0) {
135 /* match! */
136 asprintf(&path, "/local/domain/%s/domid", e[i]);
137 domid = xs_read(h, path, &len);
138 free(val);
139 free(path);
140 break;
141 }
142 free(val);
143 i++;
144 }
146 free(e);
147 return domid;
148 }
150 static int strsep_len(const char *str, char c, unsigned int len)
151 {
152 unsigned int i;
154 for (i = 0; str[i]; i++)
155 if (str[i] == c) {
156 if (len == 0)
157 return i;
158 len--;
159 }
160 return (len == 0) ? i : -ERANGE;
161 }
164 /* xenbus watches: */
165 /* Register callback to watch this node. */
166 struct xenbus_watch
167 {
168 struct list_head list;
169 char *node;
170 void (*callback)(struct xs_handle *h,
171 struct xenbus_watch *,
172 const char *node);
173 };
175 static LIST_HEAD(watches);
177 /* A little paranoia: we don't just trust token. */
178 static struct xenbus_watch *find_watch(const char *token)
179 {
180 struct xenbus_watch *i, *cmp;
182 cmp = (void *)strtoul(token, NULL, 16);
184 list_for_each_entry(i, &watches, list)
185 if (i == cmp)
186 return i;
187 return NULL;
188 }
190 /* Register callback to watch this node. like xs_watch, return 0 on failure */
191 int register_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch)
192 {
193 /* Pointer in ascii is the token. */
194 char token[sizeof(watch) * 2 + 1];
195 int er;
197 sprintf(token, "%lX", (long)watch);
198 if (find_watch(token))
199 {
200 warn("watch collision!");
201 return -EINVAL;
202 }
204 er = xs_watch(h, watch->node, token);
205 if (er != 0) {
206 list_add(&watch->list, &watches);
207 }
209 return er;
210 }
212 int unregister_xenbus_watch(struct xs_handle *h, struct xenbus_watch *watch)
213 {
214 char token[sizeof(watch) * 2 + 1];
215 int er;
217 sprintf(token, "%lX", (long)watch);
218 if (!find_watch(token))
219 {
220 warn("no such watch!");
221 return -EINVAL;
222 }
225 er = xs_unwatch(h, watch->node, token);
226 list_del(&watch->list);
228 if (er == 0)
229 warn("XENBUS Failed to release watch %s: %i",
230 watch->node, er);
231 return 0;
232 }
234 /* Re-register callbacks to all watches. */
235 void reregister_xenbus_watches(struct xs_handle *h)
236 {
237 struct xenbus_watch *watch;
238 char token[sizeof(watch) * 2 + 1];
240 list_for_each_entry(watch, &watches, list) {
241 sprintf(token, "%lX", (long)watch);
242 xs_watch(h, watch->node, token);
243 }
244 }
246 /* based on watch_thread() */
247 int xs_fire_next_watch(struct xs_handle *h)
248 {
249 char **res;
250 char *token;
251 char *node = NULL;
252 struct xenbus_watch *w;
253 int er;
254 unsigned int num;
256 res = xs_read_watch(h, &num);
257 if (res == NULL)
258 return -EAGAIN; /* in O_NONBLOCK, read_watch returns 0... */
260 node = res[XS_WATCH_PATH];
261 token = res[XS_WATCH_TOKEN];
263 w = find_watch(token);
264 if (!w)
265 {
266 warn("unregistered watch fired");
267 goto done;
268 }
269 w->callback(h, w, node);
271 done:
272 free(res);
273 return 1;
274 }
279 /* ---------------------------------------------------------------------- */
281 struct backend_info
282 {
283 /* our communications channel */
284 blkif_t *blkif;
286 long int frontend_id;
287 long int pdev;
288 long int readonly;
290 /* watch back end for changes */
291 struct xenbus_watch backend_watch;
292 char *backpath;
294 /* watch front end for changes */
295 struct xenbus_watch watch;
296 char *frontpath;
298 struct list_head list;
299 };
301 static LIST_HEAD(belist);
303 static struct backend_info *be_lookup_be(const char *bepath)
304 {
305 struct backend_info *be;
307 list_for_each_entry(be, &belist, list)
308 if (strcmp(bepath, be->backpath) == 0)
309 return be;
310 return (struct backend_info *)NULL;
311 }
313 static int be_exists_be(const char *bepath)
314 {
315 return ( be_lookup_be(bepath) != NULL );
316 }
318 static struct backend_info *be_lookup_fe(const char *fepath)
319 {
320 struct backend_info *be;
322 list_for_each_entry(be, &belist, list)
323 if (strcmp(fepath, be->frontpath) == 0)
324 return be;
325 return (struct backend_info *)NULL;
326 }
328 static int backend_remove(struct xs_handle *h, struct backend_info *be)
329 {
330 /* Turn off watches. */
331 if (be->watch.node)
332 unregister_xenbus_watch(h, &be->watch);
333 if (be->backend_watch.node)
334 unregister_xenbus_watch(h, &be->backend_watch);
336 /* Unhook from be list. */
337 list_del(&be->list);
339 /* Free everything else. */
340 if (be->blkif)
341 free_blkif(be->blkif);
342 free(be->frontpath);
343 free(be->backpath);
344 free(be);
345 return 0;
346 }
348 static void frontend_changed(struct xs_handle *h, struct xenbus_watch *w,
349 const char *fepath_im)
350 {
351 struct backend_info *be;
352 char *fepath = NULL;
353 int er;
355 be = be_lookup_fe(w->node);
356 if (be == NULL)
357 {
358 warn("frontend changed called for nonexistent backend! (%s)", fepath);
359 goto fail;
360 }
362 /* If other end is gone, delete ourself. */
363 if (w->node && !xs_exists(h, be->frontpath)) {
364 DPRINTF("DELETING BE: %s\n", be->backpath);
365 backend_remove(h, be);
366 return;
367 }
369 if (be->blkif == NULL || (be->blkif->state == CONNECTED))
370 return;
372 /* Supply the information about the device the frontend needs */
373 er = xs_transaction_start(h, be->backpath);
374 if (er == 0) {
375 warn("starting transaction");
376 goto fail;
377 }
379 er = xs_printf(h, be->backpath, "sectors", "%lu",
380 be->blkif->ops->get_size(be->blkif));
381 if (er == 0) {
382 warn("writing sectors");
383 goto fail;
384 }
386 er = xs_printf(h, be->backpath, "info", "%u",
387 be->blkif->ops->get_info(be->blkif));
388 if (er == 0) {
389 warn("writing info");
390 goto fail;
391 }
393 er = xs_printf(h, be->backpath, "sector-size", "%lu",
394 be->blkif->ops->get_secsize(be->blkif));
395 if (er == 0) {
396 warn("writing sector-size");
397 goto fail;
398 }
400 be->blkif->state = CONNECTED;
402 xs_transaction_end(h, 0);
404 return;
406 fail:
407 free(fepath);
408 }
411 static void backend_changed(struct xs_handle *h, struct xenbus_watch *w,
412 const char *bepath_im)
413 {
414 struct backend_info *be;
415 char *path = NULL, *p;
416 int len, er;
417 long int pdev = 0, handle;
419 be = be_lookup_be(w->node);
420 if (be == NULL)
421 {
422 warn("backend changed called for nonexistent backend! (%s)", w->node);
423 goto fail;
424 }
426 er = xs_gather(h, be->backpath, "physical-device", "%li", &pdev, NULL);
427 if (er != 0)
428 goto fail;
430 if (be->pdev && be->pdev != pdev) {
431 warn("changing physical-device not supported");
432 goto fail;
433 }
434 be->pdev = pdev;
436 asprintf(&path, "%s/%s", w->node, "read-only");
437 if (xs_exists(h, path))
438 be->readonly = 1;
440 if (be->blkif == NULL) {
441 /* Front end dir is a number, which is used as the handle. */
442 p = strrchr(be->frontpath, '/') + 1;
443 handle = strtoul(p, NULL, 0);
445 be->blkif = alloc_blkif(be->frontend_id);
446 if (be->blkif == NULL)
447 goto fail;
449 er = blkif_init(be->blkif, handle, be->pdev, be->readonly);
450 if (er)
451 goto fail;
453 DPRINTF("[BECHG]: ADDED A NEW BLKIF (%s)\n", w->node);
455 /* Pass in NULL node to skip exist test. */
456 frontend_changed(h, &be->watch, NULL);
457 }
459 fail:
460 free(path);
461 }
463 static void blkback_probe(struct xs_handle *h, struct xenbus_watch *w,
464 const char *bepath_im)
465 {
466 struct backend_info *be = NULL;
467 char *frontend = NULL, *bepath = NULL;
468 int er, len;
470 bepath = strdup(bepath_im);
471 if (!bepath)
472 return;
473 len = strsep_len(bepath, '/', 6);
474 if (len < 0)
475 goto free_be;
477 bepath[len] = '\0'; /*truncate the passed-in string with predjudice. */
479 be = malloc(sizeof(*be));
480 if (!be) {
481 warn("allocating backend structure");
482 goto free_be;
483 }
484 memset(be, 0, sizeof(*be));
486 frontend = NULL;
487 er = xs_gather(h, bepath,
488 "frontend-id", "%li", &be->frontend_id,
489 "frontend", NULL, &frontend,
490 NULL);
491 if (er)
492 goto free_be;
494 if (strlen(frontend) == 0 || !xs_exists(h, frontend)) {
495 /* If we can't get a frontend path and a frontend-id,
496 * then our bus-id is no longer valid and we need to
497 * destroy the backend device.
498 */
499 DPRINTF("No frontend (%s)\n", frontend);
500 goto free_be;
501 }
503 /* Are we already tracking this device? */
504 if (be_exists_be(bepath))
505 goto free_be;
507 be->backpath = bepath;
508 be->backend_watch.node = be->backpath;
509 be->backend_watch.callback = backend_changed;
510 er = register_xenbus_watch(h, &be->backend_watch);
511 if (er == 0) {
512 be->backend_watch.node = NULL;
513 warn("error adding backend watch on %s", bepath);
514 goto free_be;
515 }
517 be->frontpath = frontend;
518 be->watch.node = be->frontpath;
519 be->watch.callback = frontend_changed;
520 er = register_xenbus_watch(h, &be->watch);
521 if (er == 0) {
522 be->watch.node = NULL;
523 warn("adding frontend watch on %s", be->frontpath);
524 goto free_be;
525 }
527 list_add(&be->list, &belist);
529 DPRINTF("[PROBE]: ADDED NEW DEVICE (%s)\n", bepath_im);
531 backend_changed(h, &be->backend_watch, bepath);
532 return;
534 free_be:
535 if (be && (be->backend_watch.node))
536 unregister_xenbus_watch(h, &be->backend_watch);
537 free(frontend);
538 free(bepath);
539 free(be);
540 return;
541 }
544 int add_blockdevice_probe_watch(struct xs_handle *h, const char *domname)
545 {
546 char *domid, *path;
547 struct xenbus_watch *vbd_watch;
548 int er;
550 domid = get_dom_domid(h, domname);
552 DPRINTF("%s: %s\n", domname, (domid != NULL) ? domid : "[ not found! ]");
554 asprintf(&path, "/local/domain/%s/backend/vbd", domid);
555 if (path == NULL)
556 return -ENOMEM;
558 vbd_watch = (struct xenbus_watch *)malloc(sizeof(struct xenbus_watch));
559 vbd_watch->node = path;
560 vbd_watch->callback = blkback_probe;
561 er = register_xenbus_watch(h, vbd_watch);
562 if (er == 0) {
563 warn("Error adding vbd probe watch %s", path);
564 return -EINVAL;
565 }
567 return 0;
568 }