Commit fde25a9b authored by Alan Stern's avatar Alan Stern Committed by Greg Kroah-Hartman

Driver core: driver_find() drops reference before returning

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: default avatarAlan 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: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 2b31594a
...@@ -234,7 +234,6 @@ int driver_register(struct device_driver *drv) ...@@ -234,7 +234,6 @@ int driver_register(struct device_driver *drv)
other = driver_find(drv->name, drv->bus); other = driver_find(drv->name, drv->bus);
if (other) { if (other) {
put_driver(other);
printk(KERN_ERR "Error: Driver '%s' is already registered, " printk(KERN_ERR "Error: Driver '%s' is already registered, "
"aborting...\n", drv->name); "aborting...\n", drv->name);
return -EBUSY; return -EBUSY;
...@@ -275,7 +274,9 @@ EXPORT_SYMBOL_GPL(driver_unregister); ...@@ -275,7 +274,9 @@ EXPORT_SYMBOL_GPL(driver_unregister);
* Call kset_find_obj() to iterate over list of drivers on * Call kset_find_obj() to iterate over list of drivers on
* a bus to find driver by name. Return driver if found. * 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) 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) ...@@ -283,6 +284,8 @@ struct device_driver *driver_find(const char *name, struct bus_type *bus)
struct driver_private *priv; struct driver_private *priv;
if (k) { if (k) {
/* Drop reference added by kset_find_obj() */
kobject_put(k);
priv = to_driver(k); priv = to_driver(k);
return priv->driver; return priv->driver;
} }
......
...@@ -449,7 +449,6 @@ static ssize_t gameport_rebind_driver(struct device *dev, struct device_attribut ...@@ -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) { } else if ((drv = driver_find(buf, &gameport_bus)) != NULL) {
gameport_disconnect_port(gameport); gameport_disconnect_port(gameport);
error = gameport_bind_driver(gameport, to_gameport_driver(drv)); error = gameport_bind_driver(gameport, to_gameport_driver(drv));
put_driver(drv);
} else { } else {
error = -EINVAL; error = -EINVAL;
} }
......
...@@ -441,7 +441,6 @@ static ssize_t serio_rebind_driver(struct device *dev, struct device_attribute * ...@@ -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) { } else if ((drv = driver_find(buf, &serio_bus)) != NULL) {
serio_disconnect_port(serio); serio_disconnect_port(serio);
error = serio_bind_driver(serio, to_serio_driver(drv)); error = serio_bind_driver(serio, to_serio_driver(drv));
put_driver(drv);
serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT); serio_remove_duplicate_events(serio, SERIO_RESCAN_PORT);
} else { } else {
error = -EINVAL; error = -EINVAL;
......
...@@ -285,7 +285,6 @@ static void __exit cx18_alsa_exit(void) ...@@ -285,7 +285,6 @@ static void __exit cx18_alsa_exit(void)
drv = driver_find("cx18", &pci_bus_type); drv = driver_find("cx18", &pci_bus_type);
ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback); ret = driver_for_each_device(drv, NULL, NULL, cx18_alsa_exit_callback);
put_driver(drv);
cx18_ext_init = NULL; cx18_ext_init = NULL;
printk(KERN_INFO "cx18-alsa: module unload complete\n"); printk(KERN_INFO "cx18-alsa: module unload complete\n");
......
...@@ -1293,7 +1293,6 @@ static int __init ivtvfb_init(void) ...@@ -1293,7 +1293,6 @@ static int __init ivtvfb_init(void)
drv = driver_find("ivtv", &pci_bus_type); drv = driver_find("ivtv", &pci_bus_type);
err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init); err = driver_for_each_device(drv, NULL, &registered, ivtvfb_callback_init);
put_driver(drv);
if (!registered) { if (!registered) {
printk(KERN_ERR "ivtvfb: no cards found\n"); printk(KERN_ERR "ivtvfb: no cards found\n");
return -ENODEV; return -ENODEV;
...@@ -1310,7 +1309,6 @@ static void ivtvfb_cleanup(void) ...@@ -1310,7 +1309,6 @@ static void ivtvfb_cleanup(void)
drv = driver_find("ivtv", &pci_bus_type); drv = driver_find("ivtv", &pci_bus_type);
err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup); err = driver_for_each_device(drv, NULL, NULL, ivtvfb_callback_cleanup);
put_driver(drv);
} }
module_init(ivtvfb_init); module_init(ivtvfb_init);
......
...@@ -344,16 +344,13 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd) ...@@ -344,16 +344,13 @@ static int fimc_md_register_platform_entities(struct fimc_md *fmd)
return -ENODEV; return -ENODEV;
ret = driver_for_each_device(driver, NULL, fmd, ret = driver_for_each_device(driver, NULL, fmd,
fimc_register_callback); fimc_register_callback);
put_driver(driver);
if (ret) if (ret)
return ret; return ret;
driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type); driver = driver_find(CSIS_DRIVER_NAME, &platform_bus_type);
if (driver) { if (driver)
ret = driver_for_each_device(driver, NULL, fmd, ret = driver_for_each_device(driver, NULL, fmd,
csis_register_callback); csis_register_callback);
put_driver(driver);
}
return ret; return ret;
} }
......
...@@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_register_subdev( ...@@ -58,7 +58,6 @@ static struct v4l2_subdev *find_and_register_subdev(
} }
done: done:
put_driver(drv);
return sd; return sd;
} }
......
...@@ -168,7 +168,7 @@ static int __init smsgiucv_app_init(void) ...@@ -168,7 +168,7 @@ static int __init smsgiucv_app_init(void)
rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT); rc = dev_set_name(smsg_app_dev, KMSG_COMPONENT);
if (rc) { if (rc) {
kfree(smsg_app_dev); kfree(smsg_app_dev);
goto fail_put_driver; goto fail;
} }
smsg_app_dev->bus = &iucv_bus; smsg_app_dev->bus = &iucv_bus;
smsg_app_dev->parent = iucv_root; smsg_app_dev->parent = iucv_root;
...@@ -177,7 +177,7 @@ static int __init smsgiucv_app_init(void) ...@@ -177,7 +177,7 @@ static int __init smsgiucv_app_init(void)
rc = device_register(smsg_app_dev); rc = device_register(smsg_app_dev);
if (rc) { if (rc) {
put_device(smsg_app_dev); put_device(smsg_app_dev);
goto fail_put_driver; goto fail;
} }
/* convert sender to uppercase characters */ /* convert sender to uppercase characters */
...@@ -191,12 +191,11 @@ static int __init smsgiucv_app_init(void) ...@@ -191,12 +191,11 @@ static int __init smsgiucv_app_init(void)
rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback); rc = smsg_register_callback(SMSG_PREFIX, smsg_app_callback);
if (rc) { if (rc) {
device_unregister(smsg_app_dev); device_unregister(smsg_app_dev);
goto fail_put_driver; goto fail;
} }
rc = 0; rc = 0;
fail_put_driver: fail:
put_driver(smsgiucv_drv);
return rc; return rc;
} }
module_init(smsgiucv_app_init); module_init(smsgiucv_app_init);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment