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: 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>
This commit is contained in:
committed by
Greg Kroah-Hartman
parent
2b31594a95
commit
fde25a9b63
@@ -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);
|
|||||||
* 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)
|
|||||||
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
|
|||||||
} 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 *
|
|||||||
} 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)
|
|||||||
|
|
||||||
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)
|
|||||||
|
|
||||||
drv = driver_find("ivtv", &pci_bus_type);
|
drv = driver_find("ivtv", &pci_bus_type);
|
||||||
err = driver_for_each_device(drv, NULL, ®istered, ivtvfb_callback_init);
|
err = driver_for_each_device(drv, NULL, ®istered, 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)
|
|||||||
|
|
||||||
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)
|
|||||||
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(
|
|||||||
}
|
}
|
||||||
|
|
||||||
done:
|
done:
|
||||||
put_driver(drv);
|
|
||||||
return sd;
|
return sd;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -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)
|
|||||||
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)
|
|||||||
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);
|
||||||
|
Reference in New Issue
Block a user