xen-vtx-unstable

annotate linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 219d96d545fc 1f460d0fd6c6
children e7c7196fa329 8ca0f98ba8e2
rev   line source
cl349@5598 1 /******************************************************************************
cl349@5598 2 * Talks to Xen Store to figure out what devices we have.
cl349@5598 3 *
cl349@5598 4 * Copyright (C) 2005 Rusty Russell, IBM Corporation
cl349@5598 5 * Copyright (C) 2005 Mike Wray, Hewlett-Packard
cl349@5598 6 *
cl349@5598 7 * This file may be distributed separately from the Linux kernel, or
cl349@5598 8 * incorporated into other software packages, subject to the following license:
cl349@5598 9 *
cl349@5598 10 * Permission is hereby granted, free of charge, to any person obtaining a copy
cl349@5598 11 * of this source file (the "Software"), to deal in the Software without
cl349@5598 12 * restriction, including without limitation the rights to use, copy, modify,
cl349@5598 13 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
cl349@5598 14 * and to permit persons to whom the Software is furnished to do so, subject to
cl349@5598 15 * the following conditions:
cl349@5598 16 *
cl349@5598 17 * The above copyright notice and this permission notice shall be included in
cl349@5598 18 * all copies or substantial portions of the Software.
cl349@5598 19 *
cl349@5598 20 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cl349@5598 21 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cl349@5598 22 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cl349@5598 23 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cl349@5598 24 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
cl349@5598 25 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
cl349@5598 26 * IN THE SOFTWARE.
cl349@5598 27 */
cl349@5863 28 #define DEBUG
cl349@5863 29
cl349@5598 30 #include <asm-xen/hypervisor.h>
cl349@5598 31 #include <asm-xen/xenbus.h>
cl349@5950 32 #include <asm-xen/balloon.h>
cl349@5598 33 #include <linux/kernel.h>
cl349@5598 34 #include <linux/err.h>
cl349@5598 35 #include <linux/string.h>
cl349@5598 36 #include <linux/ctype.h>
cl349@5598 37 #include <linux/fcntl.h>
cl349@5598 38 #include <stdarg.h>
kaf24@6019 39 #include <linux/notifier.h>
cl349@5598 40 #include "xenbus_comms.h"
cl349@5598 41
cl349@5598 42 #define streq(a, b) (strcmp((a), (b)) == 0)
cl349@5598 43
kaf24@6019 44 static struct notifier_block *xenstore_chain;
kaf24@6019 45
cl349@5598 46 /* If something in array of ids matches this device, return it. */
cl349@5598 47 static const struct xenbus_device_id *
cl349@5598 48 match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev)
cl349@5598 49 {
cl349@5635 50 for (; !streq(arr->devicetype, ""); arr++) {
cl349@6251 51 if (streq(arr->devicetype, dev->devicetype))
cl349@5872 52 return arr;
cl349@5598 53 }
cl349@5598 54 return NULL;
cl349@5598 55 }
cl349@5598 56
cl349@5598 57 static int xenbus_match(struct device *_dev, struct device_driver *_drv)
cl349@5598 58 {
cl349@5598 59 struct xenbus_driver *drv = to_xenbus_driver(_drv);
cl349@5598 60
cl349@5598 61 if (!drv->ids)
cl349@5598 62 return 0;
cl349@5598 63
cl349@5598 64 return match_device(drv->ids, to_xenbus_device(_dev)) != NULL;
cl349@5598 65 }
cl349@5598 66
cl349@6240 67 struct xen_bus_type
cl349@6240 68 {
cl349@6240 69 char *root;
cl349@6240 70 unsigned int levels;
cl349@6240 71 int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename);
cl349@6240 72 int (*probe)(const char *type, const char *dir);
cl349@6240 73 struct bus_type bus;
cl349@6244 74 struct device dev;
cl349@6240 75 };
cl349@6240 76
cl349@6240 77 /* device/<type>/<id> => <type>-<id> */
cl349@6240 78 static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
cl349@6240 79 {
cl349@6240 80 nodename = strchr(nodename, '/');
cl349@6240 81 if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) {
cl349@6240 82 printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename);
cl349@6240 83 return -EINVAL;
cl349@6240 84 }
cl349@6240 85
cl349@6240 86 strlcpy(bus_id, nodename + 1, BUS_ID_SIZE);
cl349@6240 87 if (!strchr(bus_id, '/')) {
cl349@6240 88 printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id);
cl349@6240 89 return -EINVAL;
cl349@6240 90 }
cl349@6240 91 *strchr(bus_id, '/') = '-';
cl349@6240 92 return 0;
cl349@6240 93 }
cl349@6240 94
cl349@5598 95 /* Bus type for frontend drivers. */
cl349@6240 96 static int xenbus_probe_frontend(const char *type, const char *name);
cl349@6240 97 static struct xen_bus_type xenbus_frontend = {
cl349@6240 98 .root = "device",
cl349@6240 99 .levels = 2, /* device/type/<id> */
cl349@6240 100 .get_bus_id = frontend_bus_id,
cl349@6240 101 .probe = xenbus_probe_frontend,
cl349@6240 102 .bus = {
cl349@6243 103 .name = "xen",
cl349@6240 104 .match = xenbus_match,
cl349@6240 105 },
cl349@6244 106 .dev = {
cl349@6244 107 .bus_id = "xen",
cl349@6244 108 },
cl349@6240 109 };
cl349@6240 110
cl349@6240 111 /* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */
cl349@6240 112 static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename)
cl349@6240 113 {
cl349@6249 114 int domid, err;
cl349@6249 115 const char *devid, *type, *frontend;
cl349@6249 116 unsigned int typelen;
cl349@6240 117
cl349@6249 118 type = strchr(nodename, '/');
cl349@6249 119 if (!type)
cl349@6249 120 return -EINVAL;
cl349@6249 121 type++;
cl349@6249 122 typelen = strcspn(type, "/");
cl349@6249 123 if (!typelen || type[typelen] != '/')
cl349@6240 124 return -EINVAL;
cl349@6249 125
cl349@6249 126 devid = strrchr(nodename, '/') + 1;
cl349@6249 127
cl349@6249 128 err = xenbus_gather(nodename, "frontend-id", "%i", &domid,
cl349@6249 129 "frontend", NULL, &frontend,
cl349@6249 130 NULL);
cl349@6249 131 if (err)
cl349@6249 132 return err;
cl349@6249 133 if (strlen(frontend) == 0)
cl349@6249 134 err = -ERANGE;
cl349@6249 135
cl349@6249 136 if (!err && !xenbus_exists(frontend, ""))
cl349@6249 137 err = -ENOENT;
cl349@6249 138
cl349@6249 139 if (err) {
cl349@6249 140 kfree(frontend);
cl349@6249 141 return err;
cl349@6249 142 }
cl349@6240 143
cl349@6240 144 if (snprintf(bus_id, BUS_ID_SIZE,
cl349@6249 145 "%.*s-%i-%s", typelen, type, domid, devid) >= BUS_ID_SIZE)
cl349@6240 146 return -ENOSPC;
cl349@6240 147 return 0;
cl349@6240 148 }
cl349@6240 149
cl349@6585 150 static int xenbus_hotplug_backend(struct device *dev, char **envp,
cl349@6585 151 int num_envp, char *buffer, int buffer_size)
cl349@6585 152 {
cl349@6585 153 struct xenbus_device *xdev;
cl349@6585 154 int i = 0;
cl349@6585 155 int length = 0;
cl349@6585 156
cl349@6585 157 if (dev == NULL)
cl349@6585 158 return -ENODEV;
cl349@6585 159
cl349@6585 160 xdev = to_xenbus_device(dev);
cl349@6585 161 if (xdev == NULL)
cl349@6585 162 return -ENODEV;
cl349@6585 163
cl349@6585 164 /* stuff we want to pass to /sbin/hotplug */
cl349@6585 165 add_hotplug_env_var(envp, num_envp, &i,
cl349@6585 166 buffer, buffer_size, &length,
cl349@6585 167 "XENBUS_TYPE=%s", xdev->devicetype);
cl349@6585 168
cl349@6740 169 add_hotplug_env_var(envp, num_envp, &i,
cl349@6740 170 buffer, buffer_size, &length,
cl349@6740 171 "XENBUS_PATH=%s", xdev->nodename);
cl349@6740 172
cl349@6585 173 /* terminate, set to next free slot, shrink available space */
cl349@6585 174 envp[i] = NULL;
cl349@6585 175 envp = &envp[i];
cl349@6585 176 num_envp -= i;
cl349@6585 177 buffer = &buffer[length];
cl349@6585 178 buffer_size -= length;
cl349@6585 179
cl349@6585 180 if (dev->driver && to_xenbus_driver(dev->driver)->hotplug)
cl349@6585 181 return to_xenbus_driver(dev->driver)->hotplug
cl349@6585 182 (xdev, envp, num_envp, buffer, buffer_size);
cl349@6585 183
cl349@6585 184 return 0;
cl349@6585 185 }
cl349@6585 186
cl349@6240 187 static int xenbus_probe_backend(const char *type, const char *uuid);
cl349@6240 188 static struct xen_bus_type xenbus_backend = {
cl349@6240 189 .root = "backend",
cl349@6240 190 .levels = 3, /* backend/type/<frontend>/<id> */
cl349@6240 191 .get_bus_id = backend_bus_id,
cl349@6240 192 .probe = xenbus_probe_backend,
cl349@6240 193 .bus = {
cl349@6243 194 .name = "xen-backend",
cl349@6240 195 .match = xenbus_match,
cl349@6585 196 .hotplug = xenbus_hotplug_backend,
cl349@6240 197 },
cl349@6244 198 .dev = {
cl349@6244 199 .bus_id = "xen-backend",
cl349@6244 200 },
cl349@5598 201 };
cl349@5598 202
cl349@5598 203 static int xenbus_dev_probe(struct device *_dev)
cl349@5598 204 {
cl349@5598 205 struct xenbus_device *dev = to_xenbus_device(_dev);
cl349@5598 206 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
cl349@5598 207 const struct xenbus_device_id *id;
cl349@5598 208
cl349@5864 209 if (!drv->probe)
cl349@5598 210 return -ENODEV;
cl349@5598 211
cl349@5598 212 id = match_device(drv->ids, dev);
cl349@5864 213 if (!id)
cl349@5598 214 return -ENODEV;
cl349@5864 215
cl349@5598 216 return drv->probe(dev, id);
cl349@5598 217 }
cl349@5598 218
cl349@5598 219 static int xenbus_dev_remove(struct device *_dev)
cl349@5598 220 {
cl349@5598 221 struct xenbus_device *dev = to_xenbus_device(_dev);
cl349@5598 222 struct xenbus_driver *drv = to_xenbus_driver(_dev->driver);
cl349@5598 223
cl349@5635 224 if (!drv->remove)
cl349@5635 225 return 0;
cl349@5635 226 return drv->remove(dev);
cl349@5598 227 }
cl349@5598 228
cl349@6240 229 static int xenbus_register_driver(struct xenbus_driver *drv,
cl349@6240 230 struct xen_bus_type *bus)
cl349@5598 231 {
cl349@5872 232 int err;
cl349@5598 233
cl349@5598 234 drv->driver.name = drv->name;
cl349@6240 235 drv->driver.bus = &bus->bus;
cl349@5598 236 drv->driver.owner = drv->owner;
cl349@5598 237 drv->driver.probe = xenbus_dev_probe;
cl349@5598 238 drv->driver.remove = xenbus_dev_remove;
cl349@5598 239
cl349@5872 240 down(&xenbus_lock);
cl349@5598 241 err = driver_register(&drv->driver);
cl349@5872 242 up(&xenbus_lock);
cl349@5635 243 return err;
cl349@5598 244 }
cl349@5598 245
cl349@6240 246 int xenbus_register_device(struct xenbus_driver *drv)
cl349@6240 247 {
cl349@6240 248 return xenbus_register_driver(drv, &xenbus_frontend);
cl349@6240 249 }
kaf24@6467 250 EXPORT_SYMBOL(xenbus_register_device);
cl349@6240 251
cl349@6240 252 int xenbus_register_backend(struct xenbus_driver *drv)
cl349@6240 253 {
cl349@6240 254 return xenbus_register_driver(drv, &xenbus_backend);
cl349@6240 255 }
cl349@6240 256
cl349@5598 257 void xenbus_unregister_driver(struct xenbus_driver *drv)
cl349@5598 258 {
cl349@5872 259 down(&xenbus_lock);
cl349@5598 260 driver_unregister(&drv->driver);
cl349@5872 261 up(&xenbus_lock);
cl349@5598 262 }
cl349@5598 263
cl349@5868 264 struct xb_find_info
cl349@5868 265 {
cl349@5868 266 struct xenbus_device *dev;
cl349@6240 267 const char *nodename;
cl349@5868 268 };
cl349@5868 269
cl349@5868 270 static int cmp_dev(struct device *dev, void *data)
cl349@5868 271 {
cl349@6240 272 struct xenbus_device *xendev = to_xenbus_device(dev);
cl349@5868 273 struct xb_find_info *info = data;
cl349@5868 274
cl349@6240 275 if (streq(xendev->nodename, info->nodename)) {
cl349@6240 276 info->dev = xendev;
cl349@6245 277 get_device(dev);
cl349@5868 278 return 1;
cl349@5868 279 }
cl349@5868 280 return 0;
cl349@5598 281 }
cl349@5598 282
cl349@6240 283 struct xenbus_device *xenbus_device_find(const char *nodename,
cl349@6240 284 struct bus_type *bus)
cl349@5868 285 {
cl349@6240 286 struct xb_find_info info = { .dev = NULL, .nodename = nodename };
cl349@5868 287
cl349@6240 288 bus_for_each_dev(bus, NULL, &info, cmp_dev);
cl349@5868 289 return info.dev;
cl349@5868 290 }
cl349@5868 291
cl349@6248 292 static int cleanup_dev(struct device *dev, void *data)
cl349@6248 293 {
cl349@6248 294 struct xenbus_device *xendev = to_xenbus_device(dev);
cl349@6248 295 struct xb_find_info *info = data;
cl349@6248 296 int len = strlen(info->nodename);
cl349@6248 297
cl349@6248 298 if (!strncmp(xendev->nodename, info->nodename, len)) {
cl349@6248 299 info->dev = xendev;
cl349@6248 300 get_device(dev);
cl349@6248 301 return 1;
cl349@6248 302 }
cl349@6248 303 return 0;
cl349@6248 304 }
cl349@6248 305
cl349@6248 306 static void xenbus_cleanup_devices(const char *path, struct bus_type *bus)
cl349@6248 307 {
cl349@6248 308 struct xb_find_info info = { .nodename = path };
cl349@6248 309
cl349@6248 310 do {
cl349@6248 311 info.dev = NULL;
cl349@6248 312 bus_for_each_dev(bus, NULL, &info, cleanup_dev);
cl349@6248 313 if (info.dev) {
cl349@6248 314 device_unregister(&info.dev->dev);
cl349@6248 315 put_device(&info.dev->dev);
cl349@6248 316 }
cl349@6248 317 } while (info.dev);
cl349@6248 318 }
cl349@5873 319
cl349@5873 320 static void xenbus_release_device(struct device *dev)
cl349@5873 321 {
cl349@5873 322 if (dev) {
cl349@5873 323 struct xenbus_device *xendev = to_xenbus_device(dev);
cl349@5873 324
cl349@5873 325 kfree(xendev);
cl349@5873 326 }
cl349@5873 327 }
cl349@6240 328
cl349@6240 329 /* Simplified asprintf. */
cl349@6240 330 static char *kasprintf(const char *fmt, ...)
cl349@6240 331 {
cl349@6240 332 va_list ap;
cl349@6240 333 unsigned int len;
cl349@6240 334 char *p, dummy[1];
cl349@6240 335
cl349@6240 336 va_start(ap, fmt);
cl349@6240 337 /* FIXME: vsnprintf has a bug, NULL should work */
cl349@6240 338 len = vsnprintf(dummy, 0, fmt, ap);
cl349@6240 339 va_end(ap);
cl349@6240 340
cl349@6240 341 p = kmalloc(len + 1, GFP_KERNEL);
cl349@6240 342 if (!p)
cl349@6240 343 return NULL;
cl349@6240 344 va_start(ap, fmt);
cl349@6240 345 vsprintf(p, fmt, ap);
cl349@6240 346 va_end(ap);
cl349@6240 347 return p;
cl349@6240 348 }
cl349@6240 349
cl349@6240 350 static int xenbus_probe_node(struct xen_bus_type *bus,
cl349@6240 351 const char *type,
cl349@6240 352 const char *nodename)
cl349@5598 353 {
cl349@5598 354 int err;
cl349@5598 355 struct xenbus_device *xendev;
cl349@5863 356 unsigned int stringlen;
cl349@5598 357
cl349@6240 358 stringlen = strlen(nodename) + 1 + strlen(type) + 1;
cl349@5863 359 xendev = kmalloc(sizeof(*xendev) + stringlen, GFP_KERNEL);
cl349@5863 360 if (!xendev)
cl349@5863 361 return -ENOMEM;
cl349@5864 362 memset(xendev, 0, sizeof(*xendev));
cl349@5598 363
cl349@5598 364 /* Copy the strings into the extra space. */
cl349@5598 365 xendev->nodename = (char *)(xendev + 1);
cl349@6240 366 strcpy(xendev->nodename, nodename);
cl349@5598 367 xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1;
cl349@6240 368 strcpy(xendev->devicetype, type);
cl349@5598 369
cl349@6244 370 xendev->dev.parent = &bus->dev;
cl349@6244 371 xendev->dev.bus = &bus->bus;
cl349@5873 372 xendev->dev.release = xenbus_release_device;
cl349@5598 373
cl349@6240 374 err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename);
cl349@6240 375 if (err) {
cl349@6240 376 kfree(xendev);
cl349@6240 377 return err;
cl349@6240 378 }
cl349@6240 379
cl349@5598 380 /* Register with generic device framework. */
cl349@5598 381 err = device_register(&xendev->dev);
cl349@5635 382 if (err) {
cl349@6240 383 printk("XENBUS: Registering %s device %s: error %i\n",
cl349@6240 384 bus->bus.name, xendev->dev.bus_id, err);
cl349@5598 385 kfree(xendev);
cl349@5635 386 }
cl349@5598 387 return err;
cl349@5598 388 }
cl349@5598 389
cl349@6240 390 /* device/<typename>/<name> */
cl349@6240 391 static int xenbus_probe_frontend(const char *type, const char *name)
cl349@6240 392 {
cl349@6240 393 char *nodename;
cl349@6240 394 int err;
cl349@6240 395
cl349@6240 396 nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name);
cl349@6240 397 if (!nodename)
cl349@6240 398 return -ENOMEM;
cl349@6240 399
cl349@6240 400 err = xenbus_probe_node(&xenbus_frontend, type, nodename);
cl349@6240 401 kfree(nodename);
cl349@6240 402 return err;
cl349@6240 403 }
cl349@6240 404
cl349@6240 405 /* backend/<typename>/<frontend-uuid>/<name> */
cl349@6240 406 static int xenbus_probe_backend_unit(const char *dir,
cl349@6240 407 const char *type,
cl349@6240 408 const char *name)
cl349@6240 409 {
cl349@6240 410 char *nodename;
cl349@6240 411 int err;
cl349@6240 412
cl349@6240 413 nodename = kasprintf("%s/%s", dir, name);
cl349@6240 414 if (!nodename)
cl349@6240 415 return -ENOMEM;
cl349@6240 416
cl349@6240 417 err = xenbus_probe_node(&xenbus_backend, type, nodename);
cl349@6240 418 kfree(nodename);
cl349@6240 419 return err;
cl349@6240 420 }
cl349@6240 421
cl349@6240 422 /* backend/<typename>/<frontend-uuid> */
cl349@6240 423 static int xenbus_probe_backend(const char *type, const char *uuid)
cl349@6240 424 {
cl349@6240 425 char *nodename;
cl349@6240 426 int err = 0;
cl349@6240 427 char **dir;
cl349@6240 428 unsigned int i, dir_n = 0;
cl349@6240 429
cl349@6240 430 nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, uuid);
cl349@6240 431 if (!nodename)
cl349@6240 432 return -ENOMEM;
cl349@6240 433
cl349@6240 434 dir = xenbus_directory(nodename, "", &dir_n);
cl349@6240 435 if (IS_ERR(dir)) {
cl349@6240 436 kfree(nodename);
cl349@6240 437 return PTR_ERR(dir);
cl349@6240 438 }
cl349@6240 439
cl349@6240 440 for (i = 0; i < dir_n; i++) {
cl349@6240 441 err = xenbus_probe_backend_unit(nodename, type, dir[i]);
cl349@6240 442 if (err)
cl349@6240 443 break;
cl349@6240 444 }
cl349@6247 445 kfree(dir);
cl349@6240 446 kfree(nodename);
cl349@6240 447 return err;
cl349@6240 448 }
cl349@6240 449
cl349@6240 450 static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type)
cl349@5598 451 {
cl349@5598 452 int err = 0;
cl349@5598 453 char **dir;
cl349@5598 454 unsigned int dir_n = 0;
cl349@5598 455 int i;
cl349@5598 456
cl349@6240 457 dir = xenbus_directory(bus->root, type, &dir_n);
cl349@5864 458 if (IS_ERR(dir))
cl349@5863 459 return PTR_ERR(dir);
cl349@5598 460
cl349@5598 461 for (i = 0; i < dir_n; i++) {
cl349@6240 462 err = bus->probe(type, dir[i]);
cl349@5598 463 if (err)
cl349@5598 464 break;
cl349@5598 465 }
cl349@5598 466 kfree(dir);
cl349@5598 467 return err;
cl349@5598 468 }
cl349@5598 469
cl349@6240 470 static int xenbus_probe_devices(struct xen_bus_type *bus)
cl349@5598 471 {
cl349@5598 472 int err = 0;
cl349@5598 473 char **dir;
cl349@5598 474 unsigned int i, dir_n;
cl349@5598 475
cl349@6240 476 dir = xenbus_directory(bus->root, "", &dir_n);
cl349@5872 477 if (IS_ERR(dir))
cl349@5872 478 return PTR_ERR(dir);
cl349@5872 479
cl349@5598 480 for (i = 0; i < dir_n; i++) {
cl349@6240 481 err = xenbus_probe_device_type(bus, dir[i]);
cl349@5598 482 if (err)
cl349@5598 483 break;
cl349@5598 484 }
cl349@5598 485 kfree(dir);
cl349@5598 486 return err;
cl349@5598 487 }
cl349@5598 488
cl349@5869 489 static unsigned int char_count(const char *str, char c)
cl349@5598 490 {
cl349@5869 491 unsigned int i, ret = 0;
cl349@5598 492
cl349@5869 493 for (i = 0; str[i]; i++)
cl349@5869 494 if (str[i] == c)
cl349@5869 495 ret++;
cl349@5869 496 return ret;
cl349@5598 497 }
cl349@5598 498
cl349@6248 499 static int strsep_len(const char *str, char c, unsigned int len)
cl349@5598 500 {
cl349@6248 501 unsigned int i;
cl349@6248 502
cl349@6248 503 for (i = 0; str[i]; i++)
cl349@6248 504 if (str[i] == c) {
cl349@6248 505 if (len == 0)
cl349@6248 506 return i;
cl349@6248 507 len--;
cl349@6248 508 }
cl349@6248 509 return (len == 0) ? i : -ERANGE;
cl349@6248 510 }
cl349@5598 511
cl349@6240 512 static void dev_changed(const char *node, struct xen_bus_type *bus)
cl349@5598 513 {
cl349@6248 514 int exists, rootlen;
cl349@5868 515 struct xenbus_device *dev;
cl349@6240 516 char type[BUS_ID_SIZE];
cl349@6248 517 const char *p, *root;
cl349@5869 518
cl349@6248 519 if (char_count(node, '/') < 2)
cl349@6248 520 return;
cl349@5598 521
cl349@6248 522 exists = xenbus_exists(node, "");
cl349@6248 523 if (!exists) {
cl349@6248 524 xenbus_cleanup_devices(node, &bus->bus);
cl349@5865 525 return;
cl349@5635 526 }
cl349@5869 527
cl349@6240 528 /* backend/<type>/... or device/<type>/... */
cl349@6240 529 p = strchr(node, '/') + 1;
cl349@6240 530 snprintf(type, BUS_ID_SIZE, "%.*s", strcspn(p, "/"), p);
cl349@6240 531 type[BUS_ID_SIZE-1] = '\0';
cl349@6240 532
cl349@6248 533 rootlen = strsep_len(node, '/', bus->levels);
cl349@6248 534 if (rootlen < 0)
cl349@6248 535 return;
cl349@6248 536 root = kasprintf("%.*s", rootlen, node);
cl349@6248 537 if (!root)
cl349@6248 538 return;
cl349@5598 539
cl349@6248 540 dev = xenbus_device_find(root, &bus->bus);
cl349@6248 541 if (!dev)
cl349@6248 542 xenbus_probe_node(bus, type, root);
cl349@6248 543 else
cl349@5868 544 put_device(&dev->dev);
cl349@6248 545
cl349@6248 546 kfree(root);
cl349@5598 547 }
cl349@5598 548
cl349@6240 549 static void frontend_changed(struct xenbus_watch *watch, const char *node)
cl349@6240 550 {
cl349@6240 551 dev_changed(node, &xenbus_frontend);
cl349@6240 552 }
cl349@6240 553
cl349@6240 554 static void backend_changed(struct xenbus_watch *watch, const char *node)
cl349@6240 555 {
cl349@6240 556 dev_changed(node, &xenbus_backend);
cl349@5598 557 }
cl349@5598 558
cl349@5865 559 /* We watch for devices appearing and vanishing. */
cl349@6240 560 static struct xenbus_watch fe_watch = {
cl349@5865 561 .node = "device",
cl349@6240 562 .callback = frontend_changed,
cl349@6240 563 };
cl349@6240 564
cl349@6240 565 static struct xenbus_watch be_watch = {
cl349@6240 566 .node = "backend",
cl349@6240 567 .callback = backend_changed,
cl349@5865 568 };
cl349@5747 569
cl349@6240 570 static int suspend_dev(struct device *dev, void *data)
cl349@6240 571 {
cl349@6240 572 int err = 0;
cl349@6266 573 struct xenbus_driver *drv;
cl349@6266 574 struct xenbus_device *xdev;
cl349@6240 575
cl349@6266 576 if (dev->driver == NULL)
cl349@6266 577 return 0;
cl349@6266 578 drv = to_xenbus_driver(dev->driver);
cl349@6266 579 xdev = container_of(dev, struct xenbus_device, dev);
cl349@6240 580 if (drv->suspend)
cl349@6240 581 err = drv->suspend(xdev);
cl349@6240 582 if (err)
cl349@6240 583 printk("xenbus: suspend %s failed: %i\n", dev->bus_id, err);
cl349@6240 584 return 0;
cl349@6240 585 }
cl349@6240 586
cl349@6240 587 static int resume_dev(struct device *dev, void *data)
cl349@6240 588 {
cl349@6240 589 int err = 0;
cl349@6266 590 struct xenbus_driver *drv;
cl349@6266 591 struct xenbus_device *xdev;
cl349@6240 592
cl349@6266 593 if (dev->driver == NULL)
cl349@6266 594 return 0;
cl349@6266 595 drv = to_xenbus_driver(dev->driver);
cl349@6266 596 xdev = container_of(dev, struct xenbus_device, dev);
cl349@6240 597 if (drv->resume)
cl349@6240 598 err = drv->resume(xdev);
cl349@6240 599 if (err)
cl349@6240 600 printk("xenbus: resume %s failed: %i\n", dev->bus_id, err);
cl349@6240 601 return 0;
cl349@6240 602 }
cl349@6240 603
cl349@5944 604 void xenbus_suspend(void)
cl349@5944 605 {
cl349@5944 606 /* We keep lock, so no comms can happen as page moves. */
cl349@5944 607 down(&xenbus_lock);
cl349@6240 608 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev);
cl349@6240 609 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev);
cl349@5944 610 xb_suspend_comms();
cl349@5944 611 }
cl349@5944 612
cl349@5944 613 void xenbus_resume(void)
cl349@5944 614 {
cl349@5944 615 xb_init_comms();
cl349@6209 616 reregister_xenbus_watches();
cl349@6240 617 bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev);
cl349@6240 618 bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev);
cl349@5944 619 up(&xenbus_lock);
cl349@5944 620 }
cl349@5944 621
kaf24@6019 622 int register_xenstore_notifier(struct notifier_block *nb)
kaf24@6019 623 {
kaf24@6029 624 int ret = 0;
kaf24@6029 625
kaf24@6029 626 down(&xenbus_lock);
kaf24@6019 627
cl349@6618 628 if (xen_start_info->store_evtchn) {
kaf24@6029 629 ret = nb->notifier_call(nb, 0, NULL);
kaf24@6029 630 } else {
kaf24@6029 631 notifier_chain_register(&xenstore_chain, nb);
kaf24@6029 632 }
kaf24@6029 633
kaf24@6029 634 up(&xenbus_lock);
kaf24@6029 635
kaf24@6019 636 return ret;
kaf24@6019 637 }
kaf24@6019 638 EXPORT_SYMBOL(register_xenstore_notifier);
kaf24@6019 639
kaf24@6019 640 void unregister_xenstore_notifier(struct notifier_block *nb)
kaf24@6019 641 {
kaf24@6029 642 down(&xenbus_lock);
kaf24@6019 643 notifier_chain_unregister(&xenstore_chain, nb);
kaf24@6029 644 up(&xenbus_lock);
kaf24@6019 645 }
kaf24@6019 646 EXPORT_SYMBOL(unregister_xenstore_notifier);
kaf24@6019 647
cl349@5747 648 /* called from a thread in privcmd/privcmd.c */
cl349@5747 649 int do_xenbus_probe(void *unused)
cl349@5598 650 {
cl349@5598 651 int err = 0;
cl349@5598 652
cl349@5635 653 /* Initialize xenstore comms unless already done. */
cl349@6618 654 printk("store_evtchn = %i\n", xen_start_info->store_evtchn);
cl349@5635 655 err = xs_init();
cl349@5635 656 if (err) {
cl349@5635 657 printk("XENBUS: Error initializing xenstore comms:"
cl349@5635 658 " %i\n", err);
cl349@5864 659 return err;
cl349@5635 660 }
cl349@5598 661
kaf24@6029 662 down(&xenbus_lock);
cl349@5863 663 /* Enumerate devices in xenstore. */
cl349@6240 664 xenbus_probe_devices(&xenbus_frontend);
cl349@6240 665 xenbus_probe_devices(&xenbus_backend);
cl349@5872 666 /* Watch for changes. */
cl349@6240 667 register_xenbus_watch(&fe_watch);
cl349@6240 668 register_xenbus_watch(&be_watch);
cl349@6366 669 /* Notify others that xenstore is up */
cl349@6366 670 notifier_call_chain(&xenstore_chain, 0, 0);
cl349@5866 671 up(&xenbus_lock);
cl349@5864 672 return 0;
cl349@5598 673 }
cl349@5598 674
cl349@5598 675 static int __init xenbus_probe_init(void)
cl349@5598 676 {
cl349@6240 677 bus_register(&xenbus_frontend.bus);
cl349@6240 678 bus_register(&xenbus_backend.bus);
cl349@6244 679 device_register(&xenbus_frontend.dev);
cl349@6244 680 device_register(&xenbus_backend.dev);
kaf24@6376 681
cl349@6618 682 if (!xen_start_info->store_evtchn)
cl349@5598 683 return 0;
cl349@5598 684
cl349@5747 685 do_xenbus_probe(NULL);
cl349@5598 686 return 0;
cl349@5598 687 }
cl349@5598 688
cl349@5598 689 postcore_initcall(xenbus_probe_init);