aboutsummaryrefslogtreecommitdiffstats
path: root/driver
diff options
authorGreg Kroah-Hartman <gregkh@suse.de>2007-11-29 13:09:54 -0800
committerGreg Kroah-Hartman <gregkh@suse.de>2007-11-29 13:09:54 -0800
commitdc5d756ede811a83b7e321f88185a1717ebb7866 (patch)
treea79424a4dab3b3ea20e389abb82ed36ed44cb8f1 /driver
parent0ff942ac4f6bf2472868e19f7f18591def87cfa9 (diff)
downloadpatches-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.patch343
-rw-r--r--driver/put_device-might_sleep.patch2
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)
{