ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @ 7294:5df423407700

Added some clarifying comments regarding xenbus/xenstore kernel startup.

Signed-off-by: Steven Hand <steven@xensource.com>
author smh22@firebug.cl.cam.ac.uk
date Sun Oct 09 20:55:53 2005 +0100 (2005-10-09)
parents 8016551fde98
children f1e8d5f64105
line source
1 /******************************************************************************
2 * Talks to Xen Store to figure out what devices we have.
3 *
4 * Copyright (C) 2005 Rusty Russell, IBM Corporation
5 * Copyright (C) 2005 Mike Wray, Hewlett-Packard
6 *
7 * This file may be distributed separately from the Linux kernel, or
8 * incorporated into other software packages, subject to the following license:
9 *
10 * Permission is hereby granted, free of charge, to any person obtaining a copy
11 * of this source file (the "Software"), to deal in the Software without
12 * restriction, including without limitation the rights to use, copy, modify,
13 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
14 * and to permit persons to whom the Software is furnished to do so, subject to
15 * the following conditions:
16 *
17 * The above copyright notice and this permission notice shall be included in
18 * all copies or substantial portions of the Software.
19 *
20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
26 * IN THE SOFTWARE.
27 */
28 #define DEBUG
30 #include <asm/hypervisor.h>
31 #include <asm-xen/xenbus.h>
32 #include <asm-xen/balloon.h>
33 #include <linux/kernel.h>
34 #include <linux/err.h>
35 #include <linux/string.h>
36 #include <linux/ctype.h>
37 #include <linux/fcntl.h>
38 #include <stdarg.h>
39 #include <linux/notifier.h>
40 #include "xenbus_comms.h"
42 #define streq(a, b) (strcmp((a), (b)) == 0)
44 static struct notifier_block *xenstore_chain;
46 /* Now used to protect xenbus probes against save/restore. */
47 static DECLARE_MUTEX(xenbus_lock);
49 /* If something in array of ids matches this device, return it. */
50 static const struct xenbus_device_id *
51 match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
52 {
53 for (; !streq(arr->devicetype, ""); arr++) {
54 if (streq(arr->devicetype, dev->devicetype))
55 return arr;
56 }
57 return NULL;
58 }
60 static int xenbus_match(struct device *_dev, struct device_driver *_drv)
61 {
62 struct xenbus_driver *drv = to_xenbus_driver(_drv);
64 if (!drv->ids)
65 return 0;
67 return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
68 }
70 struct xen_bus_type
71 {
72 char *root;
73 unsigned int levels;
74 int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
75 int (*probe)(const char *type, const char *dir);
76 struct bus_type bus;
77 struct device dev;
78 };
80 /* device/<type>/<id> => <type>-<id> */
81 static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
82 {
83 nodename = strchr(nodename, '/');
84 if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
85 printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
86 return -EINVAL;
87 }
89 strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
90 if (!strchr(bus_id, '/')) {
91 printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
92 return -EINVAL;
93 }
94 *strchr(bus_id, '/') = '-';
95 return 0;
96 }
98 /* Bus type for frontend drivers. */
99 static int xenbus_probe_frontend(const char *type, const char *name);
100 static struct xen_bus_type xenbus_frontend = {
101 .root = "device",
102 .levels = 2, /* device/type/<id> */
103 .get_bus_id = frontend_bus_id,
104 .probe = xenbus_probe_frontend,
105 .bus = {
106 .name = "xen",
107 .match = xenbus_match,
108 },
109 .dev = {
110 .bus_id = "xen",
111 },
112 };
114 /* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
115 static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
116 {
117 int domid, err;
118 const char *devid, *type, *frontend;
119 unsigned int typelen;
121 type = strchr(nodename, '/');
122 if (!type)
123 return -EINVAL;
124 type++;
125 typelen = strcspn(type, "/");
126 if (!typelen || type[typelen] != '/')
127 return -EINVAL;
129 devid = strrchr(nodename, '/') + 1;
131 err = xenbus_gather(nodename, "frontend-id", "%i", &domid,
132 "frontend", NULL, &frontend,
133 NULL);
134 if (err)
135 return err;
136 if (strlen(frontend) == 0)
137 err = -ERANGE;
139 if (!err && !xenbus_exists(frontend, ""))
140 err = -ENOENT;
142 if (err) {
143 kfree(frontend);
144 return err;
145 }
147 if (snprintf(bus_id, BUS_ID_SIZE,
148 "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
149 return -ENOSPC;
150 return 0;
151 }
153 static int xenbus_hotplug_backend(struct device *dev, char **envp,
154 int num_envp, char *buffer, int buffer_size)
155 {
156 struct xenbus_device *xdev;
157 int i = 0;
158 int length = 0;
160 if (dev == NULL)
161 return -ENODEV;
163 xdev = to_xenbus_device(dev);
164 if (xdev == NULL)
165 return -ENODEV;
167 /* stuff we want to pass to /sbin/hotplug */
168 add_hotplug_env_var(envp, num_envp, &i,
169 buffer, buffer_size, &length,
170 "XENBUS_TYPE=%s", xdev->devicetype);
172 add_hotplug_env_var(envp, num_envp, &i,
173 buffer, buffer_size, &length,
174 "XENBUS_PATH=%s", xdev->nodename);
176 /* terminate, set to next free slot, shrink available space */
177 envp[i] = NULL;
178 envp = &envp[i];
179 num_envp -= i;
180 buffer = &buffer[length];
181 buffer_size -= length;
183 if (dev->driver && to_xenbus_driver(dev->driver)->hotplug)
184 return to_xenbus_driver(dev->driver)->hotplug
185 (xdev, envp, num_envp, buffer, buffer_size);
187 return 0;
188 }
190 static int xenbus_probe_backend(const char *type, const char *domid);
191 static struct xen_bus_type xenbus_backend = {
192 .root = "backend",
193 .levels = 3, /* backend/type/<frontend>/<id> */
194 .get_bus_id = backend_bus_id,
195 .probe = xenbus_probe_backend,
196 .bus = {
197 .name = "xen-backend",
198 .match = xenbus_match,
199 .hotplug = xenbus_hotplug_backend,
200 },
201 .dev = {
202 .bus_id = "xen-backend",
203 },
204 };
206 static int xenbus_dev_probe(struct device *_dev)
207 {
208 struct xenbus_device *dev = to_xenbus_device(_dev);
209 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
210 const struct xenbus_device_id *id;
212 if (!drv->probe)
213 return -ENODEV;
215 id = match_device(drv->ids, dev);
216 if (!id)
217 return -ENODEV;
219 return drv->probe(dev, id);
220 }
222 static int xenbus_dev_remove(struct device *_dev)
223 {
224 struct xenbus_device *dev = to_xenbus_device(_dev);
225 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
227 if (!drv->remove)
228 return 0;
229 return drv->remove(dev);
230 }
232 static int xenbus_register_driver_common(struct xenbus_driver *drv,
233 struct xen_bus_type *bus)
234 {
235 int err;
237 drv->driver.name = drv->name;
238 drv->driver.bus = &bus->bus;
239 drv->driver.owner = drv->owner;
240 drv->driver.probe = xenbus_dev_probe;
241 drv->driver.remove = xenbus_dev_remove;
243 down(&xenbus_lock);
244 err = driver_register(&drv->driver);
245 up(&xenbus_lock);
246 return err;
247 }
249 int xenbus_register_driver(struct xenbus_driver *drv)
250 {
251 return xenbus_register_driver_common(drv, &xenbus_frontend);
252 }
253 EXPORT_SYMBOL(xenbus_register_driver);
255 int xenbus_register_backend(struct xenbus_driver *drv)
256 {
257 return xenbus_register_driver_common(drv, &xenbus_backend);
258 }
260 void xenbus_unregister_driver(struct xenbus_driver *drv)
261 {
262 down(&xenbus_lock);
263 driver_unregister(&drv->driver);
264 up(&xenbus_lock);
265 }
266 EXPORT_SYMBOL(xenbus_unregister_driver);
268 struct xb_find_info
269 {
270 struct xenbus_device *dev;
271 const char *nodename;
272 };
274 static int cmp_dev(struct device *dev, void *data)
275 {
276 struct xenbus_device *xendev = to_xenbus_device(dev);
277 struct xb_find_info *info = data;
279 if (streq(xendev->nodename, info->nodename)) {
280 info->dev = xendev;
281 get_device(dev);
282 return 1;
283 }
284 return 0;
285 }
287 struct xenbus_device *xenbus_device_find(const char *nodename,
288 struct bus_type *bus)
289 {
290 struct xb_find_info info = { .dev = NULL, .nodename = nodename };
292 bus_for_each_dev(bus, NULL, &info, cmp_dev);
293 return info.dev;
294 }
296 static int cleanup_dev(struct device *dev, void *data)
297 {
298 struct xenbus_device *xendev = to_xenbus_device(dev);
299 struct xb_find_info *info = data;
300 int len = strlen(info->nodename);
302 if (!strncmp(xendev->nodename, info->nodename, len)) {
303 info->dev = xendev;
304 get_device(dev);
305 return 1;
306 }
307 return 0;
308 }
310 static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
311 {
312 struct xb_find_info info = { .nodename = path };
314 do {
315 info.dev = NULL;
316 bus_for_each_dev(bus, NULL, &info, cleanup_dev);
317 if (info.dev) {
318 device_unregister(&info.dev->dev);
319 put_device(&info.dev->dev);
320 }
321 } while (info.dev);
322 }
324 static void xenbus_release_device(struct device *dev)
325 {
326 if (dev) {
327 struct xenbus_device *xendev = to_xenbus_device(dev);
329 kfree(xendev);
330 }
331 }
333 /* Simplified asprintf. */
334 static char *kasprintf(const char *fmt, ...)
335 {
336 va_list ap;
337 unsigned int len;
338 char *p, dummy[1];
340 va_start(ap, fmt);
341 /* FIXME: vsnprintf has a bug, NULL should work */
342 len = vsnprintf(dummy, 0, fmt, ap);
343 va_end(ap);
345 p = kmalloc(len + 1, GFP_KERNEL);
346 if (!p)
347 return NULL;
348 va_start(ap, fmt);
349 vsprintf(p, fmt, ap);
350 va_end(ap);
351 return p;
352 }
354 static ssize_t xendev_show_nodename(struct device *dev, char *buf)
355 {
356 return sprintf(buf, "%s\n", to_xenbus_device(dev)->nodename);
357 }
358 DEVICE_ATTR(nodename, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_nodename, NULL);
360 static ssize_t xendev_show_devtype(struct device *dev, char *buf)
361 {
362 return sprintf(buf, "%s\n", to_xenbus_device(dev)->devicetype);
363 }
364 DEVICE_ATTR(devtype, S_IRUSR | S_IRGRP | S_IROTH, xendev_show_devtype, NULL);
366 static int xenbus_probe_node(struct xen_bus_type *bus,
367 const char *type,
368 const char *nodename)
369 {
370 int err;
371 struct xenbus_device *xendev;
372 unsigned int stringlen;
374 stringlen = strlen(nodename) + 1 + strlen(type) + 1;
375 xendev = kmalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
376 if (!xendev)
377 return -ENOMEM;
378 memset(xendev, 0, sizeof(*xendev));
380 /* Copy the strings into the extra space. */
381 xendev->nodename = (char *)(xendev + 1);
382 strcpy(xendev->nodename, nodename);
383 xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1;
384 strcpy(xendev->devicetype, type);
386 xendev->dev.parent = &bus->dev;
387 xendev->dev.bus = &bus->bus;
388 xendev->dev.release = xenbus_release_device;
390 err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
391 if (err) {
392 kfree(xendev);
393 return err;
394 }
396 /* Register with generic device framework. */
397 err = device_register(&xendev->dev);
398 if (err) {
399 printk("XENBUS: Registering %s device %s: error %i\n",
400 bus->bus.name, xendev->dev.bus_id, err);
401 kfree(xendev);
402 } else {
403 device_create_file(&xendev->dev, &dev_attr_nodename);
404 device_create_file(&xendev->dev, &dev_attr_devtype);
405 }
406 return err;
407 }
409 /* device/<typename>/<name> */
410 static int xenbus_probe_frontend(const char *type, const char *name)
411 {
412 char *nodename;
413 int err;
415 nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name);
416 if (!nodename)
417 return -ENOMEM;
419 err = xenbus_probe_node(&xenbus_frontend, type, nodename);
420 kfree(nodename);
421 return err;
422 }
424 /* backend/<typename>/<frontend-uuid>/<name> */
425 static int xenbus_probe_backend_unit(const char *dir,
426 const char *type,
427 const char *name)
428 {
429 char *nodename;
430 int err;
432 nodename = kasprintf("%s/%s", dir, name);
433 if (!nodename)
434 return -ENOMEM;
436 err = xenbus_probe_node(&xenbus_backend, type, nodename);
437 kfree(nodename);
438 return err;
439 }
441 /* backend/<typename>/<frontend-domid> */
442 static int xenbus_probe_backend(const char *type, const char *domid)
443 {
444 char *nodename;
445 int err = 0;
446 char **dir;
447 unsigned int i, dir_n = 0;
449 nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, domid);
450 if (!nodename)
451 return -ENOMEM;
453 dir = xenbus_directory(nodename, "", &dir_n);
454 if (IS_ERR(dir)) {
455 kfree(nodename);
456 return PTR_ERR(dir);
457 }
459 for (i = 0; i < dir_n; i++) {
460 err = xenbus_probe_backend_unit(nodename, type, dir[i]);
461 if (err)
462 break;
463 }
464 kfree(dir);
465 kfree(nodename);
466 return err;
467 }
469 static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
470 {
471 int err = 0;
472 char **dir;
473 unsigned int dir_n = 0;
474 int i;
476 dir = xenbus_directory(bus->root, type, &dir_n);
477 if (IS_ERR(dir))
478 return PTR_ERR(dir);
480 for (i = 0; i < dir_n; i++) {
481 err = bus->probe(type, dir[i]);
482 if (err)
483 break;
484 }
485 kfree(dir);
486 return err;
487 }
489 static int xenbus_probe_devices(struct xen_bus_type *bus)
490 {
491 int err = 0;
492 char **dir;
493 unsigned int i, dir_n;
495 dir = xenbus_directory(bus->root, "", &dir_n);
496 if (IS_ERR(dir))
497 return PTR_ERR(dir);
499 for (i = 0; i < dir_n; i++) {
500 err = xenbus_probe_device_type(bus, dir[i]);
501 if (err)
502 break;
503 }
504 kfree(dir);
505 return err;
506 }
508 static unsigned int char_count(const char *str, char c)
509 {
510 unsigned int i, ret = 0;
512 for (i = 0; str[i]; i++)
513 if (str[i] == c)
514 ret++;
515 return ret;
516 }
518 static int strsep_len(const char *str, char c, unsigned int len)
519 {
520 unsigned int i;
522 for (i = 0; str[i]; i++)
523 if (str[i] == c) {
524 if (len == 0)
525 return i;
526 len--;
527 }
528 return (len == 0) ? i : -ERANGE;
529 }
531 static void dev_changed(const char *node, struct xen_bus_type *bus)
532 {
533 int exists, rootlen;
534 struct xenbus_device *dev;
535 char type[BUS_ID_SIZE];
536 const char *p, *root;
538 if (char_count(node, '/') < 2)
539 return;
541 exists = xenbus_exists(node, "");
542 if (!exists) {
543 xenbus_cleanup_devices(node, &bus->bus);
544 return;
545 }
547 /* backend/<type>/... or device/<type>/... */
548 p = strchr(node, '/') + 1;
549 snprintf(type, BUS_ID_SIZE, "%.*s", strcspn(p, "/"), p);
550 type[BUS_ID_SIZE-1] = '\0';
552 rootlen = strsep_len(node, '/', bus->levels);
553 if (rootlen < 0)
554 return;
555 root = kasprintf("%.*s", rootlen, node);
556 if (!root)
557 return;
559 dev = xenbus_device_find(root, &bus->bus);
560 if (!dev)
561 xenbus_probe_node(bus, type, root);
562 else
563 put_device(&dev->dev);
565 kfree(root);
566 }
568 static void frontend_changed(struct xenbus_watch *watch,
569 const char **vec, unsigned int len)
570 {
571 dev_changed(vec[XS_WATCH_PATH], &xenbus_frontend);
572 }
574 static void backend_changed(struct xenbus_watch *watch,
575 const char **vec, unsigned int len)
576 {
577 dev_changed(vec[XS_WATCH_PATH], &xenbus_backend);
578 }
580 /* We watch for devices appearing and vanishing. */
581 static struct xenbus_watch fe_watch = {
582 .node = "device",
583 .callback = frontend_changed,
584 };
586 static struct xenbus_watch be_watch = {
587 .node = "backend",
588 .callback = backend_changed,
589 };
591 static int suspend_dev(struct device *dev, void *data)
592 {
593 int err = 0;
594 struct xenbus_driver *drv;
595 struct xenbus_device *xdev;
597 if (dev->driver == NULL)
598 return 0;
599 drv = to_xenbus_driver(dev->driver);
600 xdev = container_of(dev, struct xenbus_device, dev);
601 if (drv->suspend)
602 err = drv->suspend(xdev);
603 if (err)
604 printk("xenbus: suspend %s failed: %i\n", dev->bus_id, err);
605 return 0;
606 }
608 static int resume_dev(struct device *dev, void *data)
609 {
610 int err = 0;
611 struct xenbus_driver *drv;
612 struct xenbus_device *xdev;
614 if (dev->driver == NULL)
615 return 0;
616 drv = to_xenbus_driver(dev->driver);
617 xdev = container_of(dev, struct xenbus_device, dev);
618 if (drv->resume)
619 err = drv->resume(xdev);
620 if (err)
621 printk("xenbus: resume %s failed: %i\n", dev->bus_id, err);
622 return 0;
623 }
625 void xenbus_suspend(void)
626 {
627 /* We keep lock, so no comms can happen as page moves. */
628 down(&xenbus_lock);
629 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
630 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
631 xs_suspend();
632 }
634 void xenbus_resume(void)
635 {
636 xb_init_comms();
637 xs_resume();
638 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
639 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
640 up(&xenbus_lock);
641 }
643 int register_xenstore_notifier(struct notifier_block *nb)
644 {
645 int ret = 0;
647 down(&xenbus_lock);
649 if (xen_start_info->store_evtchn) {
650 ret = nb->notifier_call(nb, 0, NULL);
651 } else {
652 notifier_chain_register(&xenstore_chain, nb);
653 }
655 up(&xenbus_lock);
657 return ret;
658 }
659 EXPORT_SYMBOL(register_xenstore_notifier);
661 void unregister_xenstore_notifier(struct notifier_block *nb)
662 {
663 down(&xenbus_lock);
664 notifier_chain_unregister(&xenstore_chain, nb);
665 up(&xenbus_lock);
666 }
667 EXPORT_SYMBOL(unregister_xenstore_notifier);
669 /*
670 ** Called either from below xenbus_probe_init() initcall (for domUs)
671 ** or, for dom0, from a thread created in privcmd/privcmd.c (after
672 ** the user-space tools have invoked initDomainStore())
673 */
674 int do_xenbus_probe(void *unused)
675 {
676 int err = 0;
678 /* Initialize the interface to xenstore. */
679 err = xs_init();
680 if (err) {
681 printk("XENBUS: Error initializing xenstore comms:"
682 " %i\n", err);
683 return err;
684 }
686 down(&xenbus_lock);
687 /* Enumerate devices in xenstore. */
688 xenbus_probe_devices(&xenbus_frontend);
689 xenbus_probe_devices(&xenbus_backend);
690 /* Watch for changes. */
691 register_xenbus_watch(&fe_watch);
692 register_xenbus_watch(&be_watch);
693 /* Notify others that xenstore is up */
694 notifier_call_chain(&xenstore_chain, 0, 0);
695 up(&xenbus_lock);
697 return 0;
698 }
700 static int __init xenbus_probe_init(void)
701 {
702 if (xen_init() < 0)
703 return -ENODEV;
705 bus_register(&xenbus_frontend.bus);
706 bus_register(&xenbus_backend.bus);
707 device_register(&xenbus_frontend.dev);
708 device_register(&xenbus_backend.dev);
710 /*
711 ** Domain0 doesn't have a store_evtchn yet - this will
712 ** be set up later by xend invoking initDomainStore()
713 */
714 if (!xen_start_info->store_evtchn)
715 return 0;
717 do_xenbus_probe(NULL);
718 return 0;
719 }
721 postcore_initcall(xenbus_probe_init);
723 /*
724 * Local variables:
725 * c-file-style: "linux"
726 * indent-tabs-mode: t
727 * c-indent-level: 8
728 * c-basic-offset: 8
729 * tab-width: 8
730 * End:
731 */