Driver core: fix error by cleanup up symlinks properly
authorJames Simmons <jsimmons@infradead.org>
Wed, 21 Feb 2007 17:44:51 +0000 (17:44 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 23 Feb 2007 22:52:09 +0000 (14:52 -0800)
When a device fails to register the class symlinks where not cleaned up.
This left a symlink in the /sys/class/"device"/ directory that pointed
to no where. This caused the sysfs_follow_link Oops I reported earlier.
This patch cleanups up the symlink. Please apply. Thank you.

Signed-Off: James Simmons <jsimmons@infradead.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/base/core.c

index d04fd33dcd91526775606ce37ae1806b3d7be380..cf2a398aaaa1f6c0113bb1b58793e8d14b940129 100644 (file)
@@ -637,12 +637,41 @@ int device_add(struct device *dev)
                                             BUS_NOTIFY_DEL_DEVICE, dev);
        device_remove_groups(dev);
  GroupError:
-       device_remove_attrs(dev);
+       device_remove_attrs(dev);
  AttrsError:
        if (dev->devt_attr) {
                device_remove_file(dev, dev->devt_attr);
                kfree(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.kset.kobj)
+                       sysfs_remove_link(&dev->class->subsys.kset.kobj,
+                                         dev->bus_id);
+#ifdef CONFIG_SYSFS_DEPRECATED
+               if (parent) {
+                       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);
+                       sysfs_remove_link(&dev->kobj, "device");
+               }
+#endif
+
+               down(&dev->class->sem);
+               /* notify any interfaces that the device is now gone */
+               list_for_each_entry(class_intf, &dev->class->interfaces, node)
+                       if (class_intf->remove_dev)
+                               class_intf->remove_dev(dev, class_intf);
+               /* remove the device from the class list */
+               list_del_init(&dev->node);
+               up(&dev->class->sem);
+       }
  ueventattrError:
        device_remove_file(dev, &dev->uevent_attr);
  attrError: