Driver core: driver_find() drops reference before returning
authorAlan Stern <stern@rowland.harvard.edu>
Tue, 24 Jan 2012 18:34:24 +0000 (13:34 -0500)
committerGreg Kroah-Hartman <gregkh@suse.de>
Wed, 25 Jan 2012 00:00:34 +0000 (16:00 -0800)
As part of the removal of get_driver()/put_driver(), this patch
(as1510) changes driver_find(); it now drops the reference it acquires
before returning.  The patch also adjusts all the callers of
driver_find() to remove the now unnecessary calls to put_driver().

In addition, the patch adds a warning to driver_find(): Callers must
make sure the driver they are searching for does not get unloaded
while they are using it.  This has always been the case; driver_find()
has never prevented a driver from being unregistered or unloaded.
Hence the patch will not introduce any new bugs.  The existing callers
all seem to be okay in this respect, however I don't understand the
video drivers well enough to be certain about them.

Signed-off-by: Alan Stern <stern@rowland.harvard.edu>
CC: Dmitry Torokhov <dmitry.torokhov@gmail.com>
CC: Kyungmin Park <kyungmin.park@samsung.com>
CC: Andy Walls <awalls@md.metrocast.net>
CC: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/base/driver.c
drivers/input/gameport/gameport.c
drivers/input/serio/serio.c
drivers/media/video/cx18/cx18-alsa-main.c
drivers/media/video/ivtv/ivtvfb.c
drivers/media/video/s5p-fimc/fimc-mdevice.c
drivers/media/video/s5p-tv/mixer_video.c
drivers/s390/net/smsgiucv_app.c

index b631f7c59453c2a51f1ce4d65c6fec458cde51e3..e979cad75c6ed32754c59e2008d5f8f03df19fe9 100644 (file)
@@ -234,7 +234,6 @@ int driver_register(struct device_driver *drv)
 
        other = driver_find(drv->name, drv->bus);
        if (other) {
-               put_driver(other);
                printk(KERN_ERR "Error: Driver '%s' is already registered, "
                        "aborting...\n", drv->name);
                return -EBUSY;
@@ -275,7 +274,9 @@ EXPORT_SYMBOL_GPL(driver_unregister);
  * Call kset_find_obj() to iterate over list of drivers on
  * a bus to find driver by name. Return driver if found.
  *
- * Note that kset_find_obj increments driver's reference count.
+ * This routine provides no locking to prevent the driver it returns
+ * from being unregistered or unloaded while the caller is using it.
+ * The caller is responsible for preventing this.
  */
 struct device_driver *driver_find(const char *name, struct bus_type *bus)
 {
@@ -283,6 +284,8 @@ struct device_driver *driver_find(const char *name, struct bus_type *bus)
        struct driver_private *priv;
 
        if (k) {
+               /* Drop reference added by kset_find_obj() */
+               kobject_put(k);
                priv = to_driver(k);
                return priv->driver;
        }
index c351aa421f8f7b79c41ac8d6f581de6f8f3c6571..da739d9d19057c983318db9aa23ec858d7fe3177 100644 (file)
@@ -449,7 +449,6 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut
        } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
                gameport_disconnect_port(gameport);
                error = gameport_bind_driver(gameport, to_gameport_driver(drv));
-               put_driver(drv);
        } else {
                error = -EINVAL;
        }
index ba70058e2be3ae2bc6a3289c08d541f336a4aad8..d0f7533dbf88cbc0a632576f87fddc5e3f50ccfe 100644 (file)
@@ -441,7 +441,6 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute *
        } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
                serio_disconnect_port(serio);
                error = serio_bind_driver(serio, to_serio_driver(drv));
-               put_driver(drv);
                serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
        } else {
                error = -EINVAL;
index a1e6c2a32478225ef0860f61ea1688f723ab2443..e118361c2e7bc0fb5df1add2082c0e0205901de7 100644 (file)
@@ -285,7 +285,6 @@ static void __exit cx18_alsa_exit(void)
 
        drv = driver_find("cx18", &pci_bus_type);
        ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
-       put_driver(drv);
 
        cx18_ext_init = NULL;
        printk(KERN_INFO "cx18-alsa: module unload complete\n");
index d0fbfcf7133da88cfabf2caf52c26e685aae35b1..e5e7fa9e737bf961313b274ea5a834786247372c 100644 (file)
@@ -1293,7 +1293,6 @@ static int __init ivtvfb_init(void)
 
        drv = driver_find("ivtv", &pci_bus_type);
        err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
-       put_driver(drv);
        if (!registered) {
                printk(KERN_ERR "ivtvfb:  no cards found\n");
                return -ENODEV;
@@ -1310,7 +1309,6 @@ static void ivtvfb_cleanup(void)
 
        drv = driver_find("ivtv", &pci_bus_type);
        err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
-       put_driver(drv);
 }
 
 module_init(ivtvfb_init);
index 8ea4ee116e46900224a528fa415d300d2c43196b..63eccb55728f38cf88c496afcb5ba2cdcdfffc70 100644 (file)
@@ -344,16 +344,13 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd)
                return -ENODEV;
        ret = driver_for_each_device(driver, NULL, fmd,
                                     fimc_register_callback);
-       put_driver(driver);
        if (ret)
                return ret;
 
        driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
-       if (driver) {
+       if (driver)
                ret = driver_for_each_device(driver, NULL, fmd,
                                             csis_register_callback);
-               put_driver(driver);
-       }
        return ret;
 }
 
index 7884baeff76a8748133abda13659aedc48a6dff2..f7ca5cc143c64d103194b625452bd79e72bd884b 100644 (file)
@@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_register_subdev(
        }
 
 done:
-       put_driver(drv);
        return sd;
 }
 
index 4d2ea4000422d7544c594cdc474f6d1c86d5557e..32515a201bbc65c4a0c6e9d48282a188ff16cdda 100644 (file)
@@ -168,7 +168,7 @@ static int __init smsgiucv_app_init(void)
        rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
        if (rc) {
                kfree(smsg_app_dev);
-               goto fail_put_driver;
+               goto fail;
        }
        smsg_app_dev->bus = &iucv_bus;
        smsg_app_dev->parent = iucv_root;
@@ -177,7 +177,7 @@ static int __init smsgiucv_app_init(void)
        rc = device_register(smsg_app_dev);
        if (rc) {
                put_device(smsg_app_dev);
-               goto fail_put_driver;
+               goto fail;
        }
 
        /* convert sender to uppercase characters */
@@ -191,12 +191,11 @@ static int __init smsgiucv_app_init(void)
        rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
        if (rc) {
                device_unregister(smsg_app_dev);
-               goto fail_put_driver;
+               goto fail;
        }
 
        rc = 0;
-fail_put_driver:
-       put_driver(smsgiucv_drv);
+fail:
        return rc;
 }
 module_init(smsgiucv_app_init);