diff options
author | mochel@digitalimplant.org <mochel@digitalimplant.org> | 2005-03-21 15:25:36 -0500 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@suse.de> | 2005-06-20 18:15:16 -0400 |
commit | 94e7b1c5ff2055571703e38b059afffe17658432 (patch) | |
tree | 469dbd920087ec62acd88b4985437a78c6786c0e /drivers/base/dd.c | |
parent | 38fdac3cdce276554b4484a41f8ec2daf81cb2ff (diff) |
[PATCH] Add a klist to struct device_driver for the devices bound to it.
- Use it in driver_for_each_device() instead of the regular list_head and stop using
the bus's rwsem for protection.
- Use driver_for_each_device() in driver_detach() so we don't deadlock on the
bus's rwsem.
- Remove ->devices.
- Move klist access and sysfs link access out from under device's semaphore, since
they're synchronized through other means.
Signed-off-by: Patrick Mochel <mochel@digitalimplant.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Diffstat (limited to 'drivers/base/dd.c')
-rw-r--r-- | drivers/base/dd.c | 34 |
1 files changed, 19 insertions, 15 deletions
diff --git a/drivers/base/dd.c b/drivers/base/dd.c index b709b1e0cb2a..47cbb5641235 100644 --- a/drivers/base/dd.c +++ b/drivers/base/dd.c | |||
@@ -40,7 +40,7 @@ void device_bind_driver(struct device * dev) | |||
40 | { | 40 | { |
41 | pr_debug("bound device '%s' to driver '%s'\n", | 41 | pr_debug("bound device '%s' to driver '%s'\n", |
42 | dev->bus_id, dev->driver->name); | 42 | dev->bus_id, dev->driver->name); |
43 | list_add_tail(&dev->driver_list, &dev->driver->devices); | 43 | klist_add_tail(&dev->driver->klist_devices, &dev->knode_driver); |
44 | sysfs_create_link(&dev->driver->kobj, &dev->kobj, | 44 | sysfs_create_link(&dev->driver->kobj, &dev->kobj, |
45 | kobject_name(&dev->kobj)); | 45 | kobject_name(&dev->kobj)); |
46 | sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); | 46 | sysfs_create_link(&dev->kobj, &dev->driver->kobj, "driver"); |
@@ -164,31 +164,35 @@ void driver_attach(struct device_driver * drv) | |||
164 | */ | 164 | */ |
165 | void device_release_driver(struct device * dev) | 165 | void device_release_driver(struct device * dev) |
166 | { | 166 | { |
167 | struct device_driver * drv; | 167 | struct device_driver * drv = dev->driver; |
168 | |||
169 | if (!drv) | ||
170 | return; | ||
171 | |||
172 | sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); | ||
173 | sysfs_remove_link(&dev->kobj, "driver"); | ||
174 | klist_remove(&dev->knode_driver); | ||
168 | 175 | ||
169 | down(&dev->sem); | 176 | down(&dev->sem); |
170 | drv = dev->driver; | 177 | if (drv->remove) |
171 | if (drv) { | 178 | drv->remove(dev); |
172 | sysfs_remove_link(&drv->kobj, kobject_name(&dev->kobj)); | 179 | dev->driver = NULL; |
173 | sysfs_remove_link(&dev->kobj, "driver"); | ||
174 | list_del_init(&dev->driver_list); | ||
175 | if (drv->remove) | ||
176 | drv->remove(dev); | ||
177 | dev->driver = NULL; | ||
178 | } | ||
179 | up(&dev->sem); | 180 | up(&dev->sem); |
180 | } | 181 | } |
181 | 182 | ||
183 | static int __remove_driver(struct device * dev, void * unused) | ||
184 | { | ||
185 | device_release_driver(dev); | ||
186 | return 0; | ||
187 | } | ||
188 | |||
182 | /** | 189 | /** |
183 | * driver_detach - detach driver from all devices it controls. | 190 | * driver_detach - detach driver from all devices it controls. |
184 | * @drv: driver. | 191 | * @drv: driver. |
185 | */ | 192 | */ |
186 | void driver_detach(struct device_driver * drv) | 193 | void driver_detach(struct device_driver * drv) |
187 | { | 194 | { |
188 | while (!list_empty(&drv->devices)) { | 195 | driver_for_each_device(drv, NULL, NULL, __remove_driver); |
189 | struct device * dev = container_of(drv->devices.next, struct device, driver_list); | ||
190 | device_release_driver(dev); | ||
191 | } | ||
192 | } | 196 | } |
193 | 197 | ||
194 | 198 | ||