[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-changelog] Update probe code for backend layout.
# HG changeset patch # User cl349@xxxxxxxxxxxxxxxxxxxx # Node ID 9471090bb8ec4c01be2531c84510879e235bd4dc # Parent 18f04796ea89798c85e843912856994bfa2f9d65 Update probe code for backend layout. Backend directories are of form backend/<type>/<frontend-uuid>/<id>. This extra level makes an asymmetry with front ends (device/type/id) and are too long to make nice bus-ids under Linux, but the code isn't too horrible, and an OS which only wants to be a guest doesn't need to implement it. It allows backends to calculate the front-end path directly, which is a nice benefit. Also: subtype matching is tightened: they must match exactly. That way a future variant which requires a specific driver will not match current drivers. Signed-off-by: Rusty Russell <rusty@xxxxxxxxxxxxxxx> Signed-off-by: Christian Limpach <Christian.Limpach@xxxxxxxxxxxx> diff -r 18f04796ea89 -r 9471090bb8ec linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c --- a/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Wed Aug 17 12:30:04 2005 +++ b/linux-2.6-xen-sparse/drivers/xen/xenbus/xenbus_probe.c Thu Aug 18 18:54:38 2005 @@ -48,15 +48,8 @@ match_device(const struct xenbus_device_id *arr, struct xenbus_device *dev) { for (; !streq(arr->devicetype, ""); arr++) { - if (!streq(arr->devicetype, dev->devicetype)) - continue; - - /* If they don't care what subtype, it's a match. */ - if (streq(arr->subtype, "")) - return arr; - - /* If they care, device must have (same) subtype. */ - if (dev->subtype && streq(arr->subtype, dev->subtype)) + if (streq(arr->devicetype, dev->devicetype) && + streq(arr->subtype, dev->subtype ?: "")) return arr; } return NULL; @@ -72,10 +65,101 @@ return match_device(drv->ids, to_xenbus_device(_dev)) != NULL; } +struct xen_bus_type +{ + char *root; + unsigned int levels; + int (*get_bus_id)(char bus_id[BUS_ID_SIZE], const char *nodename); + int (*probe)(const char *type, const char *dir); + struct bus_type bus; +}; + +/* device/<type>/<id> => <type>-<id> */ +static int frontend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) +{ + nodename = strchr(nodename, '/'); + if (!nodename || strlen(nodename + 1) >= BUS_ID_SIZE) { + printk(KERN_WARNING "XENBUS: bad frontend %s\n", nodename); + return -EINVAL; + } + + strlcpy(bus_id, nodename + 1, BUS_ID_SIZE); + if (!strchr(bus_id, '/')) { + printk(KERN_WARNING "XENBUS: bus_id %s no slash\n", bus_id); + return -EINVAL; + } + *strchr(bus_id, '/') = '-'; + return 0; +} + /* Bus type for frontend drivers. */ -static struct bus_type xenbus_type = { - .name = "xenbus", - .match = xenbus_match, +static int xenbus_probe_frontend(const char *type, const char *name); +static struct xen_bus_type xenbus_frontend = { + .root = "device", + .levels = 2, /* device/type/<id> */ + .get_bus_id = frontend_bus_id, + .probe = xenbus_probe_frontend, + .bus = { + .name = "xenbus", + .match = xenbus_match, + }, +}; + +/* For backends, does lookup on uuid (up to /). Returns domid, or -errno. */ +int xenbus_uuid_to_domid(const char *uuid) +{ + int err, domid, len; + char path[strlen("/domain/") + 50]; + + len = strcspn(uuid, "/"); + if (snprintf(path, sizeof(path), "/domain/%.*s", len, uuid) + >= sizeof(path)) + return -ENOSPC; + err = xenbus_scanf(path, "id", "%i", &domid); + if (err != 1) + return err; + return domid; +} + +/* backend/<type>/<fe-uuid>/<id> => <type>-<fe-domid>-<id> */ +static int backend_bus_id(char bus_id[BUS_ID_SIZE], const char *nodename) +{ + unsigned int typelen, uuidlen; + int domid; + const char *p; + + nodename = strchr(nodename, '/'); + if (!nodename) + return -EINVAL; + nodename++; + typelen = strcspn(nodename, "/"); + if (!typelen || nodename[typelen] != '/') + return -EINVAL; + p = nodename + typelen + 1; + uuidlen = strcspn(p, "/"); + if (!uuidlen || p[uuidlen] != '/') + return -EINVAL; + domid = xenbus_uuid_to_domid(p); + if (domid < 0) + return domid; + p += uuidlen + 1; + + if (snprintf(bus_id, BUS_ID_SIZE, + "%.*s-%i-%s", typelen, nodename, domid, p) >= BUS_ID_SIZE) + return -ENOSPC; + return 0; +} + +static int xenbus_probe_backend(const char *type, const char *uuid); +static struct xen_bus_type xenbus_backend = { + .root = "backend", + .levels = 3, /* backend/type/<frontend>/<id> */ + .get_bus_id = backend_bus_id, + .probe = xenbus_probe_backend, + .bus = { + .name = "xenbus-backend", + .match = xenbus_match, + }, }; static int xenbus_dev_probe(struct device *_dev) @@ -104,12 +188,13 @@ return drv->remove(dev); } -int xenbus_register_driver(struct xenbus_driver *drv) +static int xenbus_register_driver(struct xenbus_driver *drv, + struct xen_bus_type *bus) { int err; drv->driver.name = drv->name; - drv->driver.bus = &xenbus_type; + drv->driver.bus = &bus->bus; drv->driver.owner = drv->owner; drv->driver.probe = xenbus_dev_probe; drv->driver.remove = xenbus_dev_remove; @@ -120,6 +205,16 @@ return err; } +int xenbus_register_device(struct xenbus_driver *drv) +{ + return xenbus_register_driver(drv, &xenbus_frontend); +} + +int xenbus_register_backend(struct xenbus_driver *drv) +{ + return xenbus_register_driver(drv, &xenbus_backend); +} + void xenbus_unregister_driver(struct xenbus_driver *drv) { down(&xenbus_lock); @@ -130,30 +225,29 @@ struct xb_find_info { struct xenbus_device *dev; - const char *busid; + const char *nodename; }; static int cmp_dev(struct device *dev, void *data) { + struct xenbus_device *xendev = to_xenbus_device(dev); struct xb_find_info *info = data; - if (streq(dev->bus_id, info->busid)) { - info->dev = container_of(get_device(dev), - struct xenbus_device, dev); + if (streq(xendev->nodename, info->nodename)) { + info->dev = xendev; return 1; } return 0; } -/* FIXME: device_find is fixed in 2.6.13-rc2 according to Greg KH --RR */ -struct xenbus_device *xenbus_device_find(const char *busid) -{ - struct xb_find_info info = { .dev = NULL, .busid = busid }; - - bus_for_each_dev(&xenbus_type, NULL, &info, cmp_dev); +struct xenbus_device *xenbus_device_find(const char *nodename, + struct bus_type *bus) +{ + struct xb_find_info info = { .dev = NULL, .nodename = nodename }; + + bus_for_each_dev(bus, NULL, &info, cmp_dev); return info.dev; } - static void xenbus_release_device(struct device *dev) { @@ -164,18 +258,37 @@ kfree(xendev); } } -/* devices/<typename>/<name> */ -static int xenbus_probe_device(const char *dirpath, const char *devicetype, - const char *name) + +/* Simplified asprintf. */ +static char *kasprintf(const char *fmt, ...) +{ + va_list ap; + unsigned int len; + char *p, dummy[1]; + + va_start(ap, fmt); + /* FIXME: vsnprintf has a bug, NULL should work */ + len = vsnprintf(dummy, 0, fmt, ap); + va_end(ap); + + p = kmalloc(len + 1, GFP_KERNEL); + if (!p) + return NULL; + va_start(ap, fmt); + vsprintf(p, fmt, ap); + va_end(ap); + return p; +} + +static int xenbus_probe_node(struct xen_bus_type *bus, + const char *type, + const char *nodename) { int err; struct xenbus_device *xendev; unsigned int stringlen; - /* Nodename: /device/<typename>/<name>/ */ - stringlen = strlen(dirpath) + strlen(devicetype) + strlen(name) + 3; - /* Typename */ - stringlen += strlen(devicetype) + 1; + stringlen = strlen(nodename) + 1 + strlen(type) + 1; xendev = kmalloc(sizeof(*xendev) + stringlen, GFP_KERNEL); if (!xendev) return -ENOMEM; @@ -183,38 +296,108 @@ /* Copy the strings into the extra space. */ xendev->nodename = (char *)(xendev + 1); - sprintf(xendev->nodename, "%s/%s/%s", dirpath, devicetype, name); + strcpy(xendev->nodename, nodename); xendev->devicetype = xendev->nodename + strlen(xendev->nodename) + 1; - strcpy(xendev->devicetype, devicetype); - - /* FIXME: look for "subtype" field. */ - snprintf(xendev->dev.bus_id, BUS_ID_SIZE, "%s-%s", devicetype, name); - xendev->dev.bus = &xenbus_type; + strcpy(xendev->devicetype, type); + + /* This might not exist, but that's OK. */ + xendev->subtype = xenbus_read(xendev->nodename, "subtype", NULL); + if (IS_ERR(xendev->subtype)) + xendev->subtype = NULL; + + err = bus->get_bus_id(xendev->dev.bus_id, xendev->nodename); + if (err) { + printk("XENBUS: Failed to get bus id for %s: error %i\n", + xendev->nodename, err); + kfree(xendev); + return err; + } + + xendev->dev.bus = &bus->bus; xendev->dev.release = xenbus_release_device; /* Register with generic device framework. */ err = device_register(&xendev->dev); if (err) { - printk("XENBUS: Registering device %s: error %i\n", - xendev->dev.bus_id, err); + printk("XENBUS: Registering %s device %s: error %i\n", + bus->bus.name, xendev->dev.bus_id, err); kfree(xendev); } return err; } -static int xenbus_probe_device_type(const char *dirpath, const char *typename) +/* device/<typename>/<name> */ +static int xenbus_probe_frontend(const char *type, const char *name) +{ + char *nodename; + int err; + + nodename = kasprintf("%s/%s/%s", xenbus_frontend.root, type, name); + if (!nodename) + return -ENOMEM; + + err = xenbus_probe_node(&xenbus_frontend, type, nodename); + kfree(nodename); + return err; +} + +/* backend/<typename>/<frontend-uuid>/<name> */ +static int xenbus_probe_backend_unit(const char *dir, + const char *type, + const char *name) +{ + char *nodename; + int err; + + nodename = kasprintf("%s/%s", dir, name); + if (!nodename) + return -ENOMEM; + + err = xenbus_probe_node(&xenbus_backend, type, nodename); + kfree(nodename); + return err; +} + +/* backend/<typename>/<frontend-uuid> */ +static int xenbus_probe_backend(const char *type, const char *uuid) +{ + char *nodename; + int err = 0; + char **dir; + unsigned int i, dir_n = 0; + + nodename = kasprintf("%s/%s/%s", xenbus_backend.root, type, uuid); + if (!nodename) + return -ENOMEM; + + dir = xenbus_directory(nodename, "", &dir_n); + if (IS_ERR(dir)) { + kfree(nodename); + return PTR_ERR(dir); + } + + for (i = 0; i < dir_n; i++) { + err = xenbus_probe_backend_unit(nodename, type, dir[i]); + if (err) + break; + } + kfree(nodename); + return err; +} + +static int xenbus_probe_device_type(struct xen_bus_type *bus, const char *type) { int err = 0; char **dir; unsigned int dir_n = 0; int i; - dir = xenbus_directory(dirpath, typename, &dir_n); + dir = xenbus_directory(bus->root, type, &dir_n); if (IS_ERR(dir)) return PTR_ERR(dir); for (i = 0; i < dir_n; i++) { - err = xenbus_probe_device(dirpath, typename, dir[i]); + err = bus->probe(type, dir[i]); if (err) break; } @@ -222,18 +405,18 @@ return err; } -static int xenbus_probe_devices(const char *path) +static int xenbus_probe_devices(struct xen_bus_type *bus) { int err = 0; char **dir; unsigned int i, dir_n; - dir = xenbus_directory(path, "", &dir_n); + dir = xenbus_directory(bus->root, "", &dir_n); if (IS_ERR(dir)) return PTR_ERR(dir); for (i = 0; i < dir_n; i++) { - err = xenbus_probe_device_type(path, dir[i]); + err = xenbus_probe_device_type(bus, dir[i]); if (err) break; } @@ -251,58 +434,96 @@ return ret; } -static void dev_changed(struct xenbus_watch *watch, const char *node) -{ - char busid[BUS_ID_SIZE]; +static void dev_changed(const char *node, struct xen_bus_type *bus) +{ int exists; struct xenbus_device *dev; - char *p; - - /* Node is of form device/<type>/<identifier>[/...] */ - if (char_count(node, '/') != 2) + char type[BUS_ID_SIZE]; + const char *p; + + /* FIXME: wouldn't need this if we could limit watch depth. */ + if (char_count(node, '/') != bus->levels) return; + + /* backend/<type>/... or device/<type>/... */ + p = strchr(node, '/') + 1; + snprintf(type, BUS_ID_SIZE, "%.*s", strcspn(p, "/"), p); + type[BUS_ID_SIZE-1] = '\0'; /* Created or deleted? */ exists = xenbus_exists(node, ""); - - p = strchr(node, '/') + 1; - if (strlen(p) + 1 > BUS_ID_SIZE) { - printk("Device for node %s is too big!\n", node); - return; - } - /* Bus ID is name with / changed to - */ - strcpy(busid, p); - *strchr(busid, '/') = '-'; - - dev = xenbus_device_find(busid); - printk("xenbus: device %s %s\n", busid, dev ? "exists" : "new"); + dev = xenbus_device_find(node, &bus->bus); + + printk("xenbus: device %s %s\n", node, dev ? "exists" : "new"); if (dev && !exists) { - printk("xenbus: Unregistering device %s\n", busid); - /* FIXME: free? */ + printk("xenbus: Unregistering device %s\n", node); device_unregister(&dev->dev); } else if (!dev && exists) { - printk("xenbus: Adding device %s\n", busid); - /* Hack bus id back into two strings. */ - *strrchr(busid, '-') = '\0'; - xenbus_probe_device("device", busid, busid+strlen(busid)+1); + printk("xenbus: Adding device %s\n", node); + xenbus_probe_node(bus, type, node); } else - printk("xenbus: strange, %s already %s\n", busid, + printk("xenbus: strange, %s already %s\n", node, exists ? "exists" : "gone"); if (dev) put_device(&dev->dev); } +static void frontend_changed(struct xenbus_watch *watch, const char *node) +{ + dev_changed(node, &xenbus_frontend); +} + +static void backend_changed(struct xenbus_watch *watch, const char *node) +{ + dev_changed(node, &xenbus_backend); +} + /* We watch for devices appearing and vanishing. */ -static struct xenbus_watch dev_watch = { +static struct xenbus_watch fe_watch = { /* FIXME: Ideally we'd only watch for changes 2 levels deep... */ .node = "device", - .callback = dev_changed, + .callback = frontend_changed, }; + +static struct xenbus_watch be_watch = { + .node = "backend", + .callback = backend_changed, +}; + +static int suspend_dev(struct device *dev, void *data) +{ + int err = 0; + struct xenbus_driver *drv = to_xenbus_driver(dev->driver); + struct xenbus_device *xdev + = container_of(dev, struct xenbus_device, dev); + + if (drv->suspend) + err = drv->suspend(xdev); + if (err) + printk("xenbus: suspend %s failed: %i\n", dev->bus_id, err); + return 0; +} + +static int resume_dev(struct device *dev, void *data) +{ + int err = 0; + struct xenbus_driver *drv = to_xenbus_driver(dev->driver); + struct xenbus_device *xdev + = container_of(dev, struct xenbus_device, dev); + + if (drv->resume) + err = drv->resume(xdev); + if (err) + printk("xenbus: resume %s failed: %i\n", dev->bus_id, err); + return 0; +} void xenbus_suspend(void) { /* We keep lock, so no comms can happen as page moves. */ down(&xenbus_lock); + bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, suspend_dev); + bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, suspend_dev); xb_suspend_comms(); } @@ -310,6 +531,8 @@ { xb_init_comms(); reregister_xenbus_watches(); + bus_for_each_dev(&xenbus_frontend.bus, NULL, NULL, resume_dev); + bus_for_each_dev(&xenbus_backend.bus, NULL, NULL, resume_dev); up(&xenbus_lock); } @@ -354,30 +577,21 @@ } down(&xenbus_lock); - err = notifier_call_chain(&xenstore_chain, 0, 0); - up(&xenbus_lock); - - if (err == NOTIFY_BAD) { - printk("%s: calling xenstore notify chain failed\n", - __FUNCTION__); - return -EINVAL; - } - - err = 0; - - down(&xenbus_lock); /* Enumerate devices in xenstore. */ - xenbus_probe_devices("device"); + xenbus_probe_devices(&xenbus_frontend); + xenbus_probe_devices(&xenbus_backend); /* Watch for changes. */ - register_xenbus_watch(&dev_watch); + register_xenbus_watch(&fe_watch); + register_xenbus_watch(&be_watch); up(&xenbus_lock); return 0; } static int __init xenbus_probe_init(void) { - bus_register(&xenbus_type); - + bus_register(&xenbus_frontend.bus); + bus_register(&xenbus_backend.bus); + if (!xen_start_info.store_evtchn) return 0; diff -r 18f04796ea89 -r 9471090bb8ec linux-2.6-xen-sparse/include/asm-xen/xenbus.h --- a/linux-2.6-xen-sparse/include/asm-xen/xenbus.h Wed Aug 17 12:30:04 2005 +++ b/linux-2.6-xen-sparse/include/asm-xen/xenbus.h Thu Aug 18 18:54:38 2005 @@ -61,9 +61,11 @@ char *name; struct module *owner; const struct xenbus_device_id *ids; - int (*probe) (struct xenbus_device * dev, - const struct xenbus_device_id * id); - int (*remove) (struct xenbus_device * dev); + int (*probe)(struct xenbus_device *dev, + const struct xenbus_device_id *id); + int (*remove)(struct xenbus_device *dev); + int (*suspend)(struct xenbus_device *dev); + int (*resume)(struct xenbus_device *dev); struct device_driver driver; }; @@ -72,7 +74,8 @@ return container_of(drv, struct xenbus_driver, driver); } -int xenbus_register_driver(struct xenbus_driver *drv); +int xenbus_register_device(struct xenbus_driver *drv); +int xenbus_register_backend(struct xenbus_driver *drv); void xenbus_unregister_driver(struct xenbus_driver *drv); /* Caller must hold this lock to call these functions: it's also held @@ -123,6 +126,9 @@ void unregister_xenbus_watch(struct xenbus_watch *watch); void reregister_xenbus_watches(void); +/* For backends, does lookup on uuid (up to /). Returns domid, or -errno. */ +int xenbus_uuid_to_domid(const char *uuid); + /* Called from xen core code. */ void xenbus_suspend(void); void xenbus_resume(void); _______________________________________________ Xen-changelog mailing list Xen-changelog@xxxxxxxxxxxxxxxxxxx http://lists.xensource.com/xen-changelog
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |