diff options
| author | Greg Kroah-Hartman <gregkh@suse.de> | 2007-11-29 13:09:54 -0800 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@suse.de> | 2007-11-29 13:09:54 -0800 |
| commit | dc5d756ede811a83b7e321f88185a1717ebb7866 (patch) | |
| tree | a79424a4dab3b3ea20e389abb82ed36ed44cb8f1 /driver | |
| parent | 0ff942ac4f6bf2472868e19f7f18591def87cfa9 (diff) | |
| download | patches-dc5d756ede811a83b7e321f88185a1717ebb7866.tar.gz | |
added driver/driver-core-fix-class-glue-dir-cleanup-logic.patch
Diffstat (limited to 'driver')
| -rw-r--r-- | driver/driver-core-fix-class-glue-dir-cleanup-logic.patch | 343 | ||||
| -rw-r--r-- | driver/put_device-might_sleep.patch | 2 |
2 files changed, 344 insertions, 1 deletions
diff --git a/driver/driver-core-fix-class-glue-dir-cleanup-logic.patch b/driver/driver-core-fix-class-glue-dir-cleanup-logic.patch new file mode 100644 index 00000000000000..282176756c92e1 --- /dev/null +++ b/driver/driver-core-fix-class-glue-dir-cleanup-logic.patch @@ -0,0 +1,343 @@ +From kay.sievers@vrfy.org Thu Nov 29 13:05:50 2007 +From: Kay Sievers <kay.sievers@vrfy.org> +Date: Wed, 21 Nov 2007 17:29:15 +0100 +Subject: Driver core: fix class glue dir cleanup logic +Message-ID: <1195662555.2722.11.camel@lov.site> + + +We should remove the glue directory between the class and the bus +device _after_ we sent out the 'remove' event for the device, otherwise +the parent relationship is no longer valid, and composing the path +with deleted sysfs entries will not work. + +Cc: Alan Stern <stern@rowland.harvard.edu> +Signed-off-by: Kay Sievers <kay.sievers@vrfy.org> +Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> + +--- + drivers/base/core.c | 206 +++++++++++++++++++++++----------------------------- + 1 file changed, 94 insertions(+), 112 deletions(-) + +--- a/drivers/base/core.c ++++ b/drivers/base/core.c +@@ -18,7 +18,7 @@ + #include <linux/string.h> + #include <linux/kdev_t.h> + #include <linux/notifier.h> +- ++#include <linux/genhd.h> + #include <asm/semaphore.h> + + #include "base.h" +@@ -539,22 +539,20 @@ void device_initialize(struct device *de + } + + #ifdef CONFIG_SYSFS_DEPRECATED +-static struct kobject * get_device_parent(struct device *dev, +- struct device *parent) ++static struct kobject *get_device_parent(struct device *dev, ++ struct device *parent) + { +- /* +- * Set the parent to the class, not the parent device +- * for topmost devices in class hierarchy. +- * This keeps sysfs from having a symlink to make old +- * udevs happy +- */ ++ /* class devices without a parent live in /sys/class/<classname>/ */ + if (dev->class && (!parent || parent->class != dev->class)) + return &dev->class->subsys.kobj; ++ /* all other devices keep their parent */ + else if (parent) + return &parent->kobj; + + return NULL; + } ++ ++static inline void cleanup_device_parent(struct device *dev) {} + #else + static struct kobject *virtual_device_parent(struct device *dev) + { +@@ -567,8 +565,8 @@ static struct kobject *virtual_device_pa + return virtual_dir; + } + +-static struct kobject * get_device_parent(struct device *dev, +- struct device *parent) ++static struct kobject *get_device_parent(struct device *dev, ++ struct device *parent) + { + int retval; + +@@ -617,6 +615,34 @@ static struct kobject * get_device_paren + return &parent->kobj; + return NULL; + } ++ ++static void cleanup_device_parent(struct device *dev) ++{ ++ struct device *d; ++ int other = 0; ++ ++ if (!dev->class) ++ return; ++ ++ /* see if we live in a parent class directory */ ++ if (dev->kobj.parent->kset != &dev->class->class_dirs) ++ return; ++ ++ /* if we are the last child of our class, delete the directory */ ++ down(&dev->class->sem); ++ list_for_each_entry(d, &dev->class->devices, node) { ++ if (d == dev) ++ continue; ++ if (d->kobj.parent == dev->kobj.parent) { ++ other = 1; ++ break; ++ } ++ } ++ if (!other) ++ kobject_del(dev->kobj.parent); ++ kobject_put(dev->kobj.parent); ++ up(&dev->class->sem); ++} + #endif + + static int setup_parent(struct device *dev, struct device *parent) +@@ -636,65 +662,74 @@ static int device_add_class_symlinks(str + + if (!dev->class) + return 0; ++ + error = sysfs_create_link(&dev->kobj, &dev->class->subsys.kobj, + "subsystem"); + if (error) + goto out; +- /* +- * If this is not a "fake" compatible device, then create the +- * symlink from the class to the device. +- */ ++ ++#ifdef CONFIG_SYSFS_DEPRECATED ++ /* stacked class devices need a symlink in the class directory */ + if (dev->kobj.parent != &dev->class->subsys.kobj) { + error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, + dev->bus_id); + if (error) + goto out_subsys; + } ++ + if (dev->parent) { +-#ifdef CONFIG_SYSFS_DEPRECATED +- { +- struct device *parent = dev->parent; +- char *class_name; +- +- /* +- * In old sysfs stacked class devices had 'device' +- * link pointing to real device instead of parent +- */ +- while (parent->class && !parent->bus && parent->parent) +- parent = parent->parent; +- +- error = sysfs_create_link(&dev->kobj, +- &parent->kobj, +- "device"); +- if (error) +- goto out_busid; ++ struct device *parent = dev->parent; ++ char *class_name; + +- class_name = make_class_name(dev->class->name, +- &dev->kobj); +- if (class_name) +- error = sysfs_create_link(&dev->parent->kobj, +- &dev->kobj, class_name); +- kfree(class_name); +- if (error) +- goto out_device; +- } +-#else +- error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, ++ /* ++ * stacked class devices have the 'device' link ++ * pointing to the bus device instead of the parent ++ */ ++ while (parent->class && !parent->bus && parent->parent) ++ parent = parent->parent; ++ ++ error = sysfs_create_link(&dev->kobj, ++ &parent->kobj, + "device"); + if (error) + goto out_busid; +-#endif ++ ++ class_name = make_class_name(dev->class->name, ++ &dev->kobj); ++ if (class_name) ++ error = sysfs_create_link(&dev->parent->kobj, ++ &dev->kobj, class_name); ++ kfree(class_name); ++ if (error) ++ goto out_device; + } + return 0; + +-#ifdef CONFIG_SYSFS_DEPRECATED + out_device: + if (dev->parent) + sysfs_remove_link(&dev->kobj, "device"); +-#endif + out_busid: + if (dev->kobj.parent != &dev->class->subsys.kobj) + sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); ++#else ++ /* link in the class directory pointing to the device */ ++ error = sysfs_create_link(&dev->class->subsys.kobj, &dev->kobj, ++ dev->bus_id); ++ if (error) ++ goto out_subsys; ++ ++ if (dev->parent) { ++ error = sysfs_create_link(&dev->kobj, &dev->parent->kobj, ++ "device"); ++ if (error) ++ goto out_busid; ++ } ++ return 0; ++ ++out_busid: ++ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); ++#endif ++ + out_subsys: + sysfs_remove_link(&dev->kobj, "subsystem"); + out: +@@ -705,8 +740,9 @@ static void device_remove_class_symlinks + { + if (!dev->class) + return; +- if (dev->parent) { ++ + #ifdef CONFIG_SYSFS_DEPRECATED ++ if (dev->parent) { + char *class_name; + + class_name = make_class_name(dev->class->name, &dev->kobj); +@@ -714,11 +750,18 @@ static void device_remove_class_symlinks + sysfs_remove_link(&dev->parent->kobj, class_name); + kfree(class_name); + } +-#endif + sysfs_remove_link(&dev->kobj, "device"); + } ++ + if (dev->kobj.parent != &dev->class->subsys.kobj) + sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); ++#else ++ if (dev->parent) ++ sysfs_remove_link(&dev->kobj, "device"); ++ ++ sysfs_remove_link(&dev->class->subsys.kobj, dev->bus_id); ++#endif ++ + sysfs_remove_link(&dev->kobj, "subsystem"); + } + +@@ -827,26 +870,6 @@ int device_add(struct device *dev) + SymlinkError: + if (MAJOR(dev->devt)) + device_remove_file(dev, &devt_attr); +- +- if (dev->class) { +- sysfs_remove_link(&dev->kobj, "subsystem"); +- /* If this is not a "fake" compatible device, remove the +- * symlink from the class to the device. */ +- if (dev->kobj.parent != &dev->class->subsys.kobj) +- sysfs_remove_link(&dev->class->subsys.kobj, +- dev->bus_id); +- if (parent) { +-#ifdef CONFIG_SYSFS_DEPRECATED +- char *class_name = make_class_name(dev->class->name, +- &dev->kobj); +- if (class_name) +- sysfs_remove_link(&dev->parent->kobj, +- class_name); +- kfree(class_name); +-#endif +- sysfs_remove_link(&dev->kobj, "device"); +- } +- } + ueventattrError: + device_remove_file(dev, &uevent_attr); + attrError: +@@ -928,23 +951,7 @@ void device_del(struct device * dev) + if (MAJOR(dev->devt)) + device_remove_file(dev, &devt_attr); + if (dev->class) { +- sysfs_remove_link(&dev->kobj, "subsystem"); +- /* If this is not a "fake" compatible device, remove the +- * symlink from the class to the device. */ +- if (dev->kobj.parent != &dev->class->subsys.kobj) +- sysfs_remove_link(&dev->class->subsys.kobj, +- dev->bus_id); +- if (parent) { +-#ifdef CONFIG_SYSFS_DEPRECATED +- char *class_name = make_class_name(dev->class->name, +- &dev->kobj); +- if (class_name) +- sysfs_remove_link(&dev->parent->kobj, +- class_name); +- kfree(class_name); +-#endif +- sysfs_remove_link(&dev->kobj, "device"); +- } ++ device_remove_class_symlinks(dev); + + down(&dev->class->sem); + /* notify any interfaces that the device is now gone */ +@@ -954,31 +961,6 @@ void device_del(struct device * dev) + /* remove the device from the class list */ + list_del_init(&dev->node); + up(&dev->class->sem); +- +- /* If we live in a parent class-directory, unreference it */ +- if (dev->kobj.parent->kset == &dev->class->class_dirs) { +- struct device *d; +- int other = 0; +- +- /* +- * if we are the last child of our class, delete +- * our class-directory at this parent +- */ +- down(&dev->class->sem); +- list_for_each_entry(d, &dev->class->devices, node) { +- if (d == dev) +- continue; +- if (d->kobj.parent == dev->kobj.parent) { +- other = 1; +- break; +- } +- } +- if (!other) +- kobject_del(dev->kobj.parent); +- +- kobject_put(dev->kobj.parent); +- up(&dev->class->sem); +- } + } + device_remove_file(dev, &uevent_attr); + device_remove_attrs(dev); +@@ -1001,9 +983,9 @@ void device_del(struct device * dev) + BUS_NOTIFY_DEL_DEVICE, dev); + device_pm_remove(dev); + kobject_uevent(&dev->kobj, KOBJ_REMOVE); ++ cleanup_device_parent(dev); + kobject_del(&dev->kobj); +- if (parent) +- put_device(parent); ++ put_device(parent); + } + + /** diff --git a/driver/put_device-might_sleep.patch b/driver/put_device-might_sleep.patch index 01b5a9386e3d05..c88f131bcd7b8b 100644 --- a/driver/put_device-might_sleep.patch +++ b/driver/put_device-might_sleep.patch @@ -12,7 +12,7 @@ Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de> --- a/drivers/base/core.c +++ b/drivers/base/core.c -@@ -899,6 +899,7 @@ struct device * get_device(struct device +@@ -922,6 +922,7 @@ struct device * get_device(struct device */ void put_device(struct device * dev) { |
