From 09125dde90085a19a09abffc3a20877446374d8c Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Tue, 1 Feb 2011 17:19:56 +0100 Subject: [PATCH] --- yaml --- r: 235461 b: refs/heads/master c: f4203e3032e5ae74c3e89df85a5a6d96022d0c49 h: refs/heads/master i: 235459: 4bf36c830f5b979cf90e665729ceac4b4a1c9b7c v: v3 --- [refs] | 2 +- trunk/drivers/base/sys.c | 61 +++++++++++++++++++++++++++++----------- 2 files changed, 45 insertions(+), 18 deletions(-) diff --git a/[refs] b/[refs] index b9d0fc87f223..68d4d12de56e 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: 1f7da214e26a8ee4fbb66af50e27147d5d115c5a +refs/heads/master: f4203e3032e5ae74c3e89df85a5a6d96022d0c49 diff --git a/trunk/drivers/base/sys.c b/trunk/drivers/base/sys.c index b094e0d6139f..f6fb54741602 100644 --- a/trunk/drivers/base/sys.c +++ b/trunk/drivers/base/sys.c @@ -166,6 +166,36 @@ EXPORT_SYMBOL_GPL(sysdev_class_unregister); static DEFINE_MUTEX(sysdev_drivers_lock); +/* + * @dev != NULL means that we're unwinding because some drv->add() + * failed for some reason. You need to grab sysdev_drivers_lock before + * calling this. + */ +static void __sysdev_driver_remove(struct sysdev_class *cls, + struct sysdev_driver *drv, + struct sys_device *from_dev) +{ + struct sys_device *dev = from_dev; + + list_del_init(&drv->entry); + if (!cls) + return; + + if (!drv->remove) + goto kset_put; + + if (dev) + list_for_each_entry_continue_reverse(dev, &cls->kset.list, + kobj.entry) + drv->remove(dev); + else + list_for_each_entry(dev, &cls->kset.list, kobj.entry) + drv->remove(dev); + +kset_put: + kset_put(&cls->kset); +} + /** * sysdev_driver_register - Register auxillary driver * @cls: Device class driver belongs to. @@ -175,9 +205,9 @@ static DEFINE_MUTEX(sysdev_drivers_lock); * called on each operation on devices of that class. The refcount * of @cls is incremented. */ - int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) { + struct sys_device *dev = NULL; int err = 0; if (!cls) { @@ -198,19 +228,27 @@ int sysdev_driver_register(struct sysdev_class *cls, struct sysdev_driver *drv) /* If devices of this class already exist, tell the driver */ if (drv->add) { - struct sys_device *dev; - list_for_each_entry(dev, &cls->kset.list, kobj.entry) - drv->add(dev); + list_for_each_entry(dev, &cls->kset.list, kobj.entry) { + err = drv->add(dev); + if (err) + goto unwind; + } } } else { err = -EINVAL; WARN(1, KERN_ERR "%s: invalid device class\n", __func__); } + + goto unlock; + +unwind: + __sysdev_driver_remove(cls, drv, dev); + +unlock: mutex_unlock(&sysdev_drivers_lock); return err; } - /** * sysdev_driver_unregister - Remove an auxillary driver. * @cls: Class driver belongs to. @@ -220,23 +258,12 @@ void sysdev_driver_unregister(struct sysdev_class *cls, struct sysdev_driver *drv) { mutex_lock(&sysdev_drivers_lock); - list_del_init(&drv->entry); - if (cls) { - if (drv->remove) { - struct sys_device *dev; - list_for_each_entry(dev, &cls->kset.list, kobj.entry) - drv->remove(dev); - } - kset_put(&cls->kset); - } + __sysdev_driver_remove(cls, drv, NULL); mutex_unlock(&sysdev_drivers_lock); } - EXPORT_SYMBOL_GPL(sysdev_driver_register); EXPORT_SYMBOL_GPL(sysdev_driver_unregister); - - /** * sysdev_register - add a system device to the tree * @sysdev: device in question