xen-vtx-unstable

view linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @ 6622:1f460d0fd6c6

merge?
author cl349@firebug.cl.cam.ac.uk
date Mon Sep 05 14:54:05 2005 +0000 (2005-09-05)
parents 79658ef58925 291e816acbf4
children f5adc1aa61d8 219d96d545fc 4d899a738d59 e7c7196fa329
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-xen/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 /* If something in array of ids matches this device, return it. */
47 static const struct xenbus_device_id *
48 match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
49 {
50 for (; !streq(arr->devicetype, ""); arr++) {
51 if (streq(arr->devicetype, dev->devicetype))
52 return arr;
53 }
54 return NULL;
55 }
57 static int xenbus_match(struct device *_dev, struct device_driver *_drv)
58 {
59 struct xenbus_driver *drv = to_xenbus_driver(_drv);
61 if (!drv->ids)
62 return 0;
64 return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
65 }
67 struct xen_bus_type
68 {
69 char *root;
70 unsigned int levels;
71 int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
72 int (*probe)(const char *type, const char *dir);
73 struct bus_type bus;
74 struct device dev;
75 };
77 /* device/<type>/<id> => <type>-<id> */
78 static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
79 {
80 nodename = strchr(nodename, '/');
81 if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
82 printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
83 return -EINVAL;
84 }
86 strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
87 if (!strchr(bus_id, '/')) {
88 printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
89 return -EINVAL;
90 }
91 *strchr(bus_id, '/') = '-';
92 return 0;
93 }
95 /* Bus type for frontend drivers. */
96 static int xenbus_probe_frontend(const char *type, const char *name);
97 static struct xen_bus_type xenbus_frontend = {
98 .root = "device",
99 .levels = 2, /* device/type/<id> */
100 .get_bus_id = frontend_bus_id,
101 .probe = xenbus_probe_frontend,
102 .bus = {
103 .name = "xen",
104 .match = xenbus_match,
105 },
106 .dev = {
107 .bus_id = "xen",
108 },
109 };
111 /* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
112 static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
113 {
114 int domid, err;
115 const char *devid, *type, *frontend;
116 unsigned int typelen;
118 type = strchr(nodename, '/');
119 if (!type)
120 return -EINVAL;
121 type++;
122 typelen = strcspn(type, "/");
123 if (!typelen || type[typelen] != '/')
124 return -EINVAL;
126 devid = strrchr(nodename, '/') + 1;
128 err = xenbus_gather(nodename, "frontend-id", "%i", &domid,
129 "frontend", NULL, &frontend,
130 NULL);
131 if (err)
132 return err;
133 if (strlen(frontend) == 0)
134 err = -ERANGE;
136 if (!err && !xenbus_exists(frontend, ""))
137 err = -ENOENT;
139 if (err) {
140 kfree(frontend);
141 return err;
142 }
144 if (snprintf(bus_id, BUS_ID_SIZE,
145 "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
146 return -ENOSPC;
147 return 0;
148 }
150 static int xenbus_hotplug_backend(struct device *dev, char **envp,
151 int num_envp, char *buffer, int buffer_size)
152 {
153 struct xenbus_device *xdev;
154 int i = 0;
155 int length = 0;
157 if (dev == NULL)
158 return -ENODEV;
160 xdev = to_xenbus_device(dev);
161 if (xdev == NULL)
162 return -ENODEV;
164 /* stuff we want to pass to /sbin/hotplug */
165 add_hotplug_env_var(envp, num_envp, &i,
166 buffer, buffer_size, &length,
167 "XENBUS_TYPE=%s", xdev->devicetype);
169 /* terminate, set to next free slot, shrink available space */
170 envp[i] = NULL;
171 envp = &envp[i];
172 num_envp -= i;
173 buffer = &buffer[length];
174 buffer_size -= length;
176 if (dev->driver && to_xenbus_driver(dev->driver)->hotplug)
177 return to_xenbus_driver(dev->driver)->hotplug
178 (xdev, envp, num_envp, buffer, buffer_size);
180 return 0;
181 }
183 static int xenbus_probe_backend(const char *type, const char *uuid);
184 static struct xen_bus_type xenbus_backend = {
185 .root = "backend",
186 .levels = 3, /* backend/type/<frontend>/<id> */
187 .get_bus_id = backend_bus_id,
188 .probe = xenbus_probe_backend,
189 .bus = {
190 .name = "xen-backend",
191 .match = xenbus_match,
192 .hotplug = xenbus_hotplug_backend,
193 },
194 .dev = {
195 .bus_id = "xen-backend",
196 },
197 };
199 static int xenbus_dev_probe(struct device *_dev)
200 {
201 struct xenbus_device *dev = to_xenbus_device(_dev);
202 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
203 const struct xenbus_device_id *id;
205 if (!drv->probe)
206 return -ENODEV;
208 id = match_device(drv->ids, dev);
209 if (!id)
210 return -ENODEV;
212 return drv->probe(dev, id);
213 }
215 static int xenbus_dev_remove(struct device *_dev)
216 {
217 struct xenbus_device *dev = to_xenbus_device(_dev);
218 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
220 if (!drv->remove)
221 return 0;
222 return drv->remove(dev);
223 }
225 static int xenbus_register_driver(struct xenbus_driver *drv,
226 struct xen_bus_type *bus)
227 {
228 int err;
230 drv->driver.name = drv->name;
231 drv->driver.bus = &bus->bus;
232 drv->driver.owner = drv->owner;
233 drv->driver.probe = xenbus_dev_probe;
234 drv->driver.remove = xenbus_dev_remove;
236 down(&xenbus_lock);
237 err = driver_register(&drv->driver);
238 up(&xenbus_lock);
239 return err;
240 }
242 int xenbus_register_device(struct xenbus_driver *drv)
243 {
244 return xenbus_register_driver(drv, &xenbus_frontend);
245 }
246 EXPORT_SYMBOL(xenbus_register_device);
248 int xenbus_register_backend(struct xenbus_driver *drv)
249 {
250 return xenbus_register_driver(drv, &xenbus_backend);
251 }
253 void xenbus_unregister_driver(struct xenbus_driver *drv)
254 {
255 down(&xenbus_lock);
256 driver_unregister(&drv->driver);
257 up(&xenbus_lock);
258 }
260 struct xb_find_info
261 {
262 struct xenbus_device *dev;
263 const char *nodename;
264 };
266 static int cmp_dev(struct device *dev, void *data)
267 {
268 struct xenbus_device *xendev = to_xenbus_device(dev);
269 struct xb_find_info *info = data;
271 if (streq(xendev->nodename, info->nodename)) {
272 info->dev = xendev;
273 get_device(dev);
274 return 1;
275 }
276 return 0;
277 }
279 struct xenbus_device *xenbus_device_find(const char *nodename,
280 struct bus_type *bus)
281 {
282 struct xb_find_info info = { .dev = NULL, .nodename = nodename };
284 bus_for_each_dev(bus, NULL, &info, cmp_dev);
285 return info.dev;
286 }
288 static int cleanup_dev(struct device *dev, void *data)
289 {
290 struct xenbus_device *xendev = to_xenbus_device(dev);
291 struct xb_find_info *info = data;
292 int len = strlen(info->nodename);
294 if (!strncmp(xendev->nodename, info->nodename, len)) {
295 info->dev = xendev;
296 get_device(dev);
297 return 1;
298 }
299 return 0;
300 }
302 static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
303 {
304 struct xb_find_info info = { .nodename = path };
306 do {
307 info.dev = NULL;
308 bus_for_each_dev(bus, NULL, &info, cleanup_dev);
309 if (info.dev) {
310 device_unregister(&info.dev->dev);
311 put_device(&info.dev->dev);
312 }
313 } while (info.dev);
314 }
316 static void xenbus_release_device(struct device *dev)
317 {
318 if (dev) {
319 struct xenbus_device *xendev = to_xenbus_device(dev);
321 kfree(xendev);
322 }
323 }
325 /* Simplified asprintf. */
326 static char *kasprintf(const char *fmt, ...)
327 {
328 va_list ap;
329 unsigned int len;
330 char *p, dummy[1];
332 va_start(ap, fmt);
333 /* FIXME: vsnprintf has a bug, NULL should work */
334 len = vsnprintf(dummy, 0, fmt, ap);
335 va_end(ap);
337 p = kmalloc(len + 1, GFP_KERNEL);
338 if (!p)
339 return NULL;
340 va_start(ap, fmt);
341 vsprintf(p, fmt, ap);
342 va_end(ap);
343 return p;
344 }
346 static int xenbus_probe_node(struct xen_bus_type *bus,
347 const char *type,
348 const char *nodename)
349 {
350 int err;
351 struct xenbus_device *xendev;
352 unsigned int stringlen;
354 stringlen = strlen(nodename) + 1 + strlen(type) + 1;
355 xendev = kmalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
356 if (!xendev)
357 return -ENOMEM;
358 memset(xendev, 0, sizeof(*xendev));
360 /* Copy the strings into the extra space. */
361 xendev->nodename = (char *)(xendev + 1);
362 strcpy(xendev->nodename, nodename);
363 xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1;
364 strcpy(xendev->devicetype, type);
366 xendev->dev.parent = &bus->dev;
367 xendev->dev.bus = &bus->bus;
368 xendev->dev.release = xenbus_release_device;
370 err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
371 if (err) {
372 kfree(xendev);
373 return err;
374 }
376 /* Register with generic device framework. */
377 err = device_register(&xendev->dev);
378 if (err) {
379 printk("XENBUS: Registering %s device %s: error %i\n",
380 bus->bus.name, xendev->dev.bus_id, err);
381 kfree(xendev);
382 }
383 return err;
384 }
386 /* device/<typename>/<name> */
387 static int xenbus_probe_frontend(const char *type, const char *name)
388 {
389 char *nodename;
390 int err;
392 nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name);
393 if (!nodename)
394 return -ENOMEM;
396 err = xenbus_probe_node(&xenbus_frontend, type, nodename);
397 kfree(nodename);
398 return err;
399 }
401 /* backend/<typename>/<frontend-uuid>/<name> */
402 static int xenbus_probe_backend_unit(const char *dir,
403 const char *type,
404 const char *name)
405 {
406 char *nodename;
407 int err;
409 nodename = kasprintf("%s/%s", dir, name);
410 if (!nodename)
411 return -ENOMEM;
413 err = xenbus_probe_node(&xenbus_backend, type, nodename);
414 kfree(nodename);
415 return err;
416 }
418 /* backend/<typename>/<frontend-uuid> */
419 static int xenbus_probe_backend(const char *type, const char *uuid)
420 {
421 char *nodename;
422 int err = 0;
423 char **dir;
424 unsigned int i, dir_n = 0;
426 nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, uuid);
427 if (!nodename)
428 return -ENOMEM;
430 dir = xenbus_directory(nodename, "", &dir_n);
431 if (IS_ERR(dir)) {
432 kfree(nodename);
433 return PTR_ERR(dir);
434 }
436 for (i = 0; i < dir_n; i++) {
437 err = xenbus_probe_backend_unit(nodename, type, dir[i]);
438 if (err)
439 break;
440 }
441 kfree(dir);
442 kfree(nodename);
443 return err;
444 }
446 static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
447 {
448 int err = 0;
449 char **dir;
450 unsigned int dir_n = 0;
451 int i;
453 dir = xenbus_directory(bus->root, type, &dir_n);
454 if (IS_ERR(dir))
455 return PTR_ERR(dir);
457 for (i = 0; i < dir_n; i++) {
458 err = bus->probe(type, dir[i]);
459 if (err)
460 break;
461 }
462 kfree(dir);
463 return err;
464 }
466 static int xenbus_probe_devices(struct xen_bus_type *bus)
467 {
468 int err = 0;
469 char **dir;
470 unsigned int i, dir_n;
472 dir = xenbus_directory(bus->root, "", &dir_n);
473 if (IS_ERR(dir))
474 return PTR_ERR(dir);
476 for (i = 0; i < dir_n; i++) {
477 err = xenbus_probe_device_type(bus, dir[i]);
478 if (err)
479 break;
480 }
481 kfree(dir);
482 return err;
483 }
485 static unsigned int char_count(const char *str, char c)
486 {
487 unsigned int i, ret = 0;
489 for (i = 0; str[i]; i++)
490 if (str[i] == c)
491 ret++;
492 return ret;
493 }
495 static int strsep_len(const char *str, char c, unsigned int len)
496 {
497 unsigned int i;
499 for (i = 0; str[i]; i++)
500 if (str[i] == c) {
501 if (len == 0)
502 return i;
503 len--;
504 }
505 return (len == 0) ? i : -ERANGE;
506 }
508 static void dev_changed(const char *node, struct xen_bus_type *bus)
509 {
510 int exists, rootlen;
511 struct xenbus_device *dev;
512 char type[BUS_ID_SIZE];
513 const char *p, *root;
515 if (char_count(node, '/') < 2)
516 return;
518 exists = xenbus_exists(node, "");
519 if (!exists) {
520 xenbus_cleanup_devices(node, &bus->bus);
521 return;
522 }
524 /* backend/<type>/... or device/<type>/... */
525 p = strchr(node, '/') + 1;
526 snprintf(type, BUS_ID_SIZE, "%.*s", strcspn(p, "/"), p);
527 type[BUS_ID_SIZE-1] = '\0';
529 rootlen = strsep_len(node, '/', bus->levels);
530 if (rootlen < 0)
531 return;
532 root = kasprintf("%.*s", rootlen, node);
533 if (!root)
534 return;
536 dev = xenbus_device_find(root, &bus->bus);
537 if (!dev)
538 xenbus_probe_node(bus, type, root);
539 else
540 put_device(&dev->dev);
542 kfree(root);
543 }
545 static void frontend_changed(struct xenbus_watch *watch, const char *node)
546 {
547 dev_changed(node, &xenbus_frontend);
548 }
550 static void backend_changed(struct xenbus_watch *watch, const char *node)
551 {
552 dev_changed(node, &xenbus_backend);
553 }
555 /* We watch for devices appearing and vanishing. */
556 static struct xenbus_watch fe_watch = {
557 .node = "device",
558 .callback = frontend_changed,
559 };
561 static struct xenbus_watch be_watch = {
562 .node = "backend",
563 .callback = backend_changed,
564 };
566 static int suspend_dev(struct device *dev, void *data)
567 {
568 int err = 0;
569 struct xenbus_driver *drv;
570 struct xenbus_device *xdev;
572 if (dev->driver == NULL)
573 return 0;
574 drv = to_xenbus_driver(dev->driver);
575 xdev = container_of(dev, struct xenbus_device, dev);
576 if (drv->suspend)
577 err = drv->suspend(xdev);
578 if (err)
579 printk("xenbus: suspend %s failed: %i\n", dev->bus_id, err);
580 return 0;
581 }
583 static int resume_dev(struct device *dev, void *data)
584 {
585 int err = 0;
586 struct xenbus_driver *drv;
587 struct xenbus_device *xdev;
589 if (dev->driver == NULL)
590 return 0;
591 drv = to_xenbus_driver(dev->driver);
592 xdev = container_of(dev, struct xenbus_device, dev);
593 if (drv->resume)
594 err = drv->resume(xdev);
595 if (err)
596 printk("xenbus: resume %s failed: %i\n", dev->bus_id, err);
597 return 0;
598 }
600 void xenbus_suspend(void)
601 {
602 /* We keep lock, so no comms can happen as page moves. */
603 down(&xenbus_lock);
604 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
605 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
606 xb_suspend_comms();
607 }
609 void xenbus_resume(void)
610 {
611 xb_init_comms();
612 reregister_xenbus_watches();
613 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
614 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
615 up(&xenbus_lock);
616 }
618 int register_xenstore_notifier(struct notifier_block *nb)
619 {
620 int ret = 0;
622 down(&xenbus_lock);
624 if (xen_start_info->store_evtchn) {
625 ret = nb->notifier_call(nb, 0, NULL);
626 } else {
627 notifier_chain_register(&xenstore_chain, nb);
628 }
630 up(&xenbus_lock);
632 return ret;
633 }
634 EXPORT_SYMBOL(register_xenstore_notifier);
636 void unregister_xenstore_notifier(struct notifier_block *nb)
637 {
638 down(&xenbus_lock);
639 notifier_chain_unregister(&xenstore_chain, nb);
640 up(&xenbus_lock);
641 }
642 EXPORT_SYMBOL(unregister_xenstore_notifier);
644 /* called from a thread in privcmd/privcmd.c */
645 int do_xenbus_probe(void *unused)
646 {
647 int err = 0;
649 /* Initialize xenstore comms unless already done. */
650 printk("store_evtchn = %i\n", xen_start_info->store_evtchn);
651 err = xs_init();
652 if (err) {
653 printk("XENBUS: Error initializing xenstore comms:"
654 " %i\n", err);
655 return err;
656 }
658 down(&xenbus_lock);
659 /* Enumerate devices in xenstore. */
660 xenbus_probe_devices(&xenbus_frontend);
661 xenbus_probe_devices(&xenbus_backend);
662 /* Watch for changes. */
663 register_xenbus_watch(&fe_watch);
664 register_xenbus_watch(&be_watch);
665 /* Notify others that xenstore is up */
666 notifier_call_chain(&xenstore_chain, 0, 0);
667 up(&xenbus_lock);
668 return 0;
669 }
671 static int __init xenbus_probe_init(void)
672 {
673 bus_register(&xenbus_frontend.bus);
674 bus_register(&xenbus_backend.bus);
675 device_register(&xenbus_frontend.dev);
676 device_register(&xenbus_backend.dev);
678 if (!xen_start_info->store_evtchn)
679 return 0;
681 do_xenbus_probe(NULL);
682 return 0;
683 }
685 postcore_initcall(xenbus_probe_init);