ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @ 6766:219d96d545fc

merge?
author cl349@firebug.cl.cam.ac.uk
date Mon Sep 12 20:00:41 2005 +0000 (2005-09-12)
parents f5adc1aa61d8 1f460d0fd6c6
children 4d899a738d59 8ca0f98ba8e2
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 add_hotplug_env_var(envp, num_envp, &i,
170 buffer, buffer_size, &length,
171 "XENBUS_PATH=%s", xdev->nodename);
173 /* terminate, set to next free slot, shrink available space */
174 envp[i] = NULL;
175 envp = &envp[i];
176 num_envp -= i;
177 buffer = &buffer[length];
178 buffer_size -= length;
180 if (dev->driver && to_xenbus_driver(dev->driver)->hotplug)
181 return to_xenbus_driver(dev->driver)->hotplug
182 (xdev, envp, num_envp, buffer, buffer_size);
184 return 0;
185 }
187 static int xenbus_probe_backend(const char *type, const char *uuid);
188 static struct xen_bus_type xenbus_backend = {
189 .root = "backend",
190 .levels = 3, /* backend/type/<frontend>/<id> */
191 .get_bus_id = backend_bus_id,
192 .probe = xenbus_probe_backend,
193 .bus = {
194 .name = "xen-backend",
195 .match = xenbus_match,
196 .hotplug = xenbus_hotplug_backend,
197 },
198 .dev = {
199 .bus_id = "xen-backend",
200 },
201 };
203 static int xenbus_dev_probe(struct device *_dev)
204 {
205 struct xenbus_device *dev = to_xenbus_device(_dev);
206 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
207 const struct xenbus_device_id *id;
209 if (!drv->probe)
210 return -ENODEV;
212 id = match_device(drv->ids, dev);
213 if (!id)
214 return -ENODEV;
216 return drv->probe(dev, id);
217 }
219 static int xenbus_dev_remove(struct device *_dev)
220 {
221 struct xenbus_device *dev = to_xenbus_device(_dev);
222 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
224 if (!drv->remove)
225 return 0;
226 return drv->remove(dev);
227 }
229 static int xenbus_register_driver(struct xenbus_driver *drv,
230 struct xen_bus_type *bus)
231 {
232 int err;
234 drv->driver.name = drv->name;
235 drv->driver.bus = &bus->bus;
236 drv->driver.owner = drv->owner;
237 drv->driver.probe = xenbus_dev_probe;
238 drv->driver.remove = xenbus_dev_remove;
240 down(&xenbus_lock);
241 err = driver_register(&drv->driver);
242 up(&xenbus_lock);
243 return err;
244 }
246 int xenbus_register_device(struct xenbus_driver *drv)
247 {
248 return xenbus_register_driver(drv, &xenbus_frontend);
249 }
250 EXPORT_SYMBOL(xenbus_register_device);
252 int xenbus_register_backend(struct xenbus_driver *drv)
253 {
254 return xenbus_register_driver(drv, &xenbus_backend);
255 }
257 void xenbus_unregister_driver(struct xenbus_driver *drv)
258 {
259 down(&xenbus_lock);
260 driver_unregister(&drv->driver);
261 up(&xenbus_lock);
262 }
264 struct xb_find_info
265 {
266 struct xenbus_device *dev;
267 const char *nodename;
268 };
270 static int cmp_dev(struct device *dev, void *data)
271 {
272 struct xenbus_device *xendev = to_xenbus_device(dev);
273 struct xb_find_info *info = data;
275 if (streq(xendev->nodename, info->nodename)) {
276 info->dev = xendev;
277 get_device(dev);
278 return 1;
279 }
280 return 0;
281 }
283 struct xenbus_device *xenbus_device_find(const char *nodename,
284 struct bus_type *bus)
285 {
286 struct xb_find_info info = { .dev = NULL, .nodename = nodename };
288 bus_for_each_dev(bus, NULL, &info, cmp_dev);
289 return info.dev;
290 }
292 static int cleanup_dev(struct device *dev, void *data)
293 {
294 struct xenbus_device *xendev = to_xenbus_device(dev);
295 struct xb_find_info *info = data;
296 int len = strlen(info->nodename);
298 if (!strncmp(xendev->nodename, info->nodename, len)) {
299 info->dev = xendev;
300 get_device(dev);
301 return 1;
302 }
303 return 0;
304 }
306 static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
307 {
308 struct xb_find_info info = { .nodename = path };
310 do {
311 info.dev = NULL;
312 bus_for_each_dev(bus, NULL, &info, cleanup_dev);
313 if (info.dev) {
314 device_unregister(&info.dev->dev);
315 put_device(&info.dev->dev);
316 }
317 } while (info.dev);
318 }
320 static void xenbus_release_device(struct device *dev)
321 {
322 if (dev) {
323 struct xenbus_device *xendev = to_xenbus_device(dev);
325 kfree(xendev);
326 }
327 }
329 /* Simplified asprintf. */
330 static char *kasprintf(const char *fmt, ...)
331 {
332 va_list ap;
333 unsigned int len;
334 char *p, dummy[1];
336 va_start(ap, fmt);
337 /* FIXME: vsnprintf has a bug, NULL should work */
338 len = vsnprintf(dummy, 0, fmt, ap);
339 va_end(ap);
341 p = kmalloc(len + 1, GFP_KERNEL);
342 if (!p)
343 return NULL;
344 va_start(ap, fmt);
345 vsprintf(p, fmt, ap);
346 va_end(ap);
347 return p;
348 }
350 static int xenbus_probe_node(struct xen_bus_type *bus,
351 const char *type,
352 const char *nodename)
353 {
354 int err;
355 struct xenbus_device *xendev;
356 unsigned int stringlen;
358 stringlen = strlen(nodename) + 1 + strlen(type) + 1;
359 xendev = kmalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
360 if (!xendev)
361 return -ENOMEM;
362 memset(xendev, 0, sizeof(*xendev));
364 /* Copy the strings into the extra space. */
365 xendev->nodename = (char *)(xendev + 1);
366 strcpy(xendev->nodename, nodename);
367 xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1;
368 strcpy(xendev->devicetype, type);
370 xendev->dev.parent = &bus->dev;
371 xendev->dev.bus = &bus->bus;
372 xendev->dev.release = xenbus_release_device;
374 err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
375 if (err) {
376 kfree(xendev);
377 return err;
378 }
380 /* Register with generic device framework. */
381 err = device_register(&xendev->dev);
382 if (err) {
383 printk("XENBUS: Registering %s device %s: error %i\n",
384 bus->bus.name, xendev->dev.bus_id, err);
385 kfree(xendev);
386 }
387 return err;
388 }
390 /* device/<typename>/<name> */
391 static int xenbus_probe_frontend(const char *type, const char *name)
392 {
393 char *nodename;
394 int err;
396 nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name);
397 if (!nodename)
398 return -ENOMEM;
400 err = xenbus_probe_node(&xenbus_frontend, type, nodename);
401 kfree(nodename);
402 return err;
403 }
405 /* backend/<typename>/<frontend-uuid>/<name> */
406 static int xenbus_probe_backend_unit(const char *dir,
407 const char *type,
408 const char *name)
409 {
410 char *nodename;
411 int err;
413 nodename = kasprintf("%s/%s", dir, name);
414 if (!nodename)
415 return -ENOMEM;
417 err = xenbus_probe_node(&xenbus_backend, type, nodename);
418 kfree(nodename);
419 return err;
420 }
422 /* backend/<typename>/<frontend-uuid> */
423 static int xenbus_probe_backend(const char *type, const char *uuid)
424 {
425 char *nodename;
426 int err = 0;
427 char **dir;
428 unsigned int i, dir_n = 0;
430 nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, uuid);
431 if (!nodename)
432 return -ENOMEM;
434 dir = xenbus_directory(nodename, "", &dir_n);
435 if (IS_ERR(dir)) {
436 kfree(nodename);
437 return PTR_ERR(dir);
438 }
440 for (i = 0; i < dir_n; i++) {
441 err = xenbus_probe_backend_unit(nodename, type, dir[i]);
442 if (err)
443 break;
444 }
445 kfree(dir);
446 kfree(nodename);
447 return err;
448 }
450 static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
451 {
452 int err = 0;
453 char **dir;
454 unsigned int dir_n = 0;
455 int i;
457 dir = xenbus_directory(bus->root, type, &dir_n);
458 if (IS_ERR(dir))
459 return PTR_ERR(dir);
461 for (i = 0; i < dir_n; i++) {
462 err = bus->probe(type, dir[i]);
463 if (err)
464 break;
465 }
466 kfree(dir);
467 return err;
468 }
470 static int xenbus_probe_devices(struct xen_bus_type *bus)
471 {
472 int err = 0;
473 char **dir;
474 unsigned int i, dir_n;
476 dir = xenbus_directory(bus->root, "", &dir_n);
477 if (IS_ERR(dir))
478 return PTR_ERR(dir);
480 for (i = 0; i < dir_n; i++) {
481 err = xenbus_probe_device_type(bus, dir[i]);
482 if (err)
483 break;
484 }
485 kfree(dir);
486 return err;
487 }
489 static unsigned int char_count(const char *str, char c)
490 {
491 unsigned int i, ret = 0;
493 for (i = 0; str[i]; i++)
494 if (str[i] == c)
495 ret++;
496 return ret;
497 }
499 static int strsep_len(const char *str, char c, unsigned int len)
500 {
501 unsigned int i;
503 for (i = 0; str[i]; i++)
504 if (str[i] == c) {
505 if (len == 0)
506 return i;
507 len--;
508 }
509 return (len == 0) ? i : -ERANGE;
510 }
512 static void dev_changed(const char *node, struct xen_bus_type *bus)
513 {
514 int exists, rootlen;
515 struct xenbus_device *dev;
516 char type[BUS_ID_SIZE];
517 const char *p, *root;
519 if (char_count(node, '/') < 2)
520 return;
522 exists = xenbus_exists(node, "");
523 if (!exists) {
524 xenbus_cleanup_devices(node, &bus->bus);
525 return;
526 }
528 /* backend/<type>/... or device/<type>/... */
529 p = strchr(node, '/') + 1;
530 snprintf(type, BUS_ID_SIZE, "%.*s", strcspn(p, "/"), p);
531 type[BUS_ID_SIZE-1] = '\0';
533 rootlen = strsep_len(node, '/', bus->levels);
534 if (rootlen < 0)
535 return;
536 root = kasprintf("%.*s", rootlen, node);
537 if (!root)
538 return;
540 dev = xenbus_device_find(root, &bus->bus);
541 if (!dev)
542 xenbus_probe_node(bus, type, root);
543 else
544 put_device(&dev->dev);
546 kfree(root);
547 }
549 static void frontend_changed(struct xenbus_watch *watch, const char *node)
550 {
551 dev_changed(node, &xenbus_frontend);
552 }
554 static void backend_changed(struct xenbus_watch *watch, const char *node)
555 {
556 dev_changed(node, &xenbus_backend);
557 }
559 /* We watch for devices appearing and vanishing. */
560 static struct xenbus_watch fe_watch = {
561 .node = "device",
562 .callback = frontend_changed,
563 };
565 static struct xenbus_watch be_watch = {
566 .node = "backend",
567 .callback = backend_changed,
568 };
570 static int suspend_dev(struct device *dev, void *data)
571 {
572 int err = 0;
573 struct xenbus_driver *drv;
574 struct xenbus_device *xdev;
576 if (dev->driver == NULL)
577 return 0;
578 drv = to_xenbus_driver(dev->driver);
579 xdev = container_of(dev, struct xenbus_device, dev);
580 if (drv->suspend)
581 err = drv->suspend(xdev);
582 if (err)
583 printk("xenbus: suspend %s failed: %i\n", dev->bus_id, err);
584 return 0;
585 }
587 static int resume_dev(struct device *dev, void *data)
588 {
589 int err = 0;
590 struct xenbus_driver *drv;
591 struct xenbus_device *xdev;
593 if (dev->driver == NULL)
594 return 0;
595 drv = to_xenbus_driver(dev->driver);
596 xdev = container_of(dev, struct xenbus_device, dev);
597 if (drv->resume)
598 err = drv->resume(xdev);
599 if (err)
600 printk("xenbus: resume %s failed: %i\n", dev->bus_id, err);
601 return 0;
602 }
604 void xenbus_suspend(void)
605 {
606 /* We keep lock, so no comms can happen as page moves. */
607 down(&xenbus_lock);
608 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
609 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
610 xb_suspend_comms();
611 }
613 void xenbus_resume(void)
614 {
615 xb_init_comms();
616 reregister_xenbus_watches();
617 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
618 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
619 up(&xenbus_lock);
620 }
622 int register_xenstore_notifier(struct notifier_block *nb)
623 {
624 int ret = 0;
626 down(&xenbus_lock);
628 if (xen_start_info->store_evtchn) {
629 ret = nb->notifier_call(nb, 0, NULL);
630 } else {
631 notifier_chain_register(&xenstore_chain, nb);
632 }
634 up(&xenbus_lock);
636 return ret;
637 }
638 EXPORT_SYMBOL(register_xenstore_notifier);
640 void unregister_xenstore_notifier(struct notifier_block *nb)
641 {
642 down(&xenbus_lock);
643 notifier_chain_unregister(&xenstore_chain, nb);
644 up(&xenbus_lock);
645 }
646 EXPORT_SYMBOL(unregister_xenstore_notifier);
648 /* called from a thread in privcmd/privcmd.c */
649 int do_xenbus_probe(void *unused)
650 {
651 int err = 0;
653 /* Initialize xenstore comms unless already done. */
654 printk("store_evtchn = %i\n", xen_start_info->store_evtchn);
655 err = xs_init();
656 if (err) {
657 printk("XENBUS: Error initializing xenstore comms:"
658 " %i\n", err);
659 return err;
660 }
662 down(&xenbus_lock);
663 /* Enumerate devices in xenstore. */
664 xenbus_probe_devices(&xenbus_frontend);
665 xenbus_probe_devices(&xenbus_backend);
666 /* Watch for changes. */
667 register_xenbus_watch(&fe_watch);
668 register_xenbus_watch(&be_watch);
669 /* Notify others that xenstore is up */
670 notifier_call_chain(&xenstore_chain, 0, 0);
671 up(&xenbus_lock);
672 return 0;
673 }
675 static int __init xenbus_probe_init(void)
676 {
677 bus_register(&xenbus_frontend.bus);
678 bus_register(&xenbus_backend.bus);
679 device_register(&xenbus_frontend.dev);
680 device_register(&xenbus_backend.dev);
682 if (!xen_start_info->store_evtchn)
683 return 0;
685 do_xenbus_probe(NULL);
686 return 0;
687 }
689 postcore_initcall(xenbus_probe_init);