Commit 1901fb26 authored by Kay Sievers's avatar Kay Sievers Committed by Greg Kroah-Hartman

Driver core: fix "driver" symlink timing

Create the "driver" link before the child device may be created by
the probing logic. This makes it possible for userspace (udev), to
determine the driver property of the parent device, at the time the
child device is created.
Signed-off-by: default avatarKay Sievers <kay.sievers@novell.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@suse.de>
parent 116af378
...@@ -26,28 +26,12 @@ ...@@ -26,28 +26,12 @@
#define to_drv(node) container_of(node, struct device_driver, kobj.entry) #define to_drv(node) container_of(node, struct device_driver, kobj.entry)
/** static void driver_bound(struct device *dev)
* device_bind_driver - bind a driver to one device.
* @dev: device.
*
* Allow manual attachment of a driver to a device.
* Caller must have already set @dev->driver.
*
* Note that this does not modify the bus reference count
* nor take the bus's rwsem. Please verify those are accounted
* for before calling this. (It is ok to call with no other effort
* from a driver's probe() method.)
*
* This function must be called with @dev->sem held.
*/
int device_bind_driver(struct device *dev)
{ {
int ret;
if (klist_node_attached(&dev->knode_driver)) { if (klist_node_attached(&dev->knode_driver)) {
printk(KERN_WARNING "%s: device %s already bound\n", printk(KERN_WARNING "%s: device %s already bound\n",
__FUNCTION__, kobject_name(&dev->kobj)); __FUNCTION__, kobject_name(&dev->kobj));
return 0; return;
} }
pr_debug("bound device '%s' to driver '%s'\n", pr_debug("bound device '%s' to driver '%s'\n",
...@@ -58,6 +42,12 @@ int device_bind_driver(struct device *dev) ...@@ -58,6 +42,12 @@ int device_bind_driver(struct device *dev)
BUS_NOTIFY_BOUND_DRIVER, dev); BUS_NOTIFY_BOUND_DRIVER, dev);
klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices); klist_add_tail(&dev->knode_driver, &dev->driver->klist_devices);
}
static int driver_sysfs_add(struct device *dev)
{
int ret;
ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj, ret = sysfs_create_link(&dev->driver->kobj, &dev->kobj,
kobject_name(&dev->kobj)); kobject_name(&dev->kobj));
if (ret == 0) { if (ret == 0) {
...@@ -70,6 +60,36 @@ int device_bind_driver(struct device *dev) ...@@ -70,6 +60,36 @@ int device_bind_driver(struct device *dev)
return ret; return ret;
} }
static void driver_sysfs_remove(struct device *dev)
{
struct device_driver *drv = dev->driver;
if (drv) {
sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj));
sysfs_remove_link(&dev->kobj, "driver");
}
}
/**
* device_bind_driver - bind a driver to one device.
* @dev: device.
*
* Allow manual attachment of a driver to a device.
* Caller must have already set @dev->driver.
*
* Note that this does not modify the bus reference count
* nor take the bus's rwsem. Please verify those are accounted
* for before calling this. (It is ok to call with no other effort
* from a driver's probe() method.)
*
* This function must be called with @dev->sem held.
*/
int device_bind_driver(struct device *dev)
{
driver_bound(dev);
return driver_sysfs_add(dev);
}
struct stupid_thread_structure { struct stupid_thread_structure {
struct device_driver *drv; struct device_driver *drv;
struct device *dev; struct device *dev;
...@@ -90,30 +110,32 @@ static int really_probe(void *void_data) ...@@ -90,30 +110,32 @@ static int really_probe(void *void_data)
drv->bus->name, drv->name, dev->bus_id); drv->bus->name, drv->name, dev->bus_id);
dev->driver = drv; dev->driver = drv;
if (driver_sysfs_add(dev)) {
printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",
__FUNCTION__, dev->bus_id);
goto probe_failed;
}
if (dev->bus->probe) { if (dev->bus->probe) {
ret = dev->bus->probe(dev); ret = dev->bus->probe(dev);
if (ret) { if (ret)
dev->driver = NULL;
goto probe_failed; goto probe_failed;
}
} else if (drv->probe) { } else if (drv->probe) {
ret = drv->probe(dev); ret = drv->probe(dev);
if (ret) { if (ret)
dev->driver = NULL;
goto probe_failed; goto probe_failed;
}
}
if (device_bind_driver(dev)) {
printk(KERN_ERR "%s: device_bind_driver(%s) failed\n",
__FUNCTION__, dev->bus_id);
/* How does undo a ->probe? We're screwed. */
} }
driver_bound(dev);
ret = 1; ret = 1;
pr_debug("%s: Bound Device %s to Driver %s\n", pr_debug("%s: Bound Device %s to Driver %s\n",
drv->bus->name, dev->bus_id, drv->name); drv->bus->name, dev->bus_id, drv->name);
goto done; goto done;
probe_failed: probe_failed:
driver_sysfs_remove(dev);
dev->driver = NULL;
if (ret == -ENODEV || ret == -ENXIO) { if (ret == -ENODEV || ret == -ENXIO) {
/* Driver matched, but didn't support device /* Driver matched, but didn't support device
* or device not found. * or device not found.
...@@ -289,7 +311,7 @@ static void __device_release_driver(struct device * dev) ...@@ -289,7 +311,7 @@ static void __device_release_driver(struct device * dev)
drv = dev->driver; drv = dev->driver;
if (drv) { if (drv) {
get_driver(drv); get_driver(drv);
sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); driver_sysfs_remove(dev);
sysfs_remove_link(&dev->kobj, "driver"); sysfs_remove_link(&dev->kobj, "driver");
klist_remove(&dev->knode_driver); klist_remove(&dev->knode_driver);
......
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