[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


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.