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 | |
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')
-rw-r--r-- | drivers/base/core.c | 2 | ||||
-rw-r--r-- | drivers/base/dd.c | 34 | ||||
-rw-r--r-- | drivers/base/driver.c | 27 |
3 files changed, 35 insertions, 28 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index 93440824b800..bc5bec61a01a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -209,8 +209,8 @@ void device_initialize(struct device *dev) | |||
209 | kobject_init(&dev->kobj); | 209 | kobject_init(&dev->kobj); |
210 | INIT_LIST_HEAD(&dev->node); | 210 | INIT_LIST_HEAD(&dev->node); |
211 | INIT_LIST_HEAD(&dev->children); | 211 | INIT_LIST_HEAD(&dev->children); |
212 | INIT_LIST_HEAD(&dev->driver_list); | ||
213 | INIT_LIST_HEAD(&dev->bus_list); | 212 | INIT_LIST_HEAD(&dev->bus_list); |
213 | INIT_LIST_HEAD(&dev->driver_list); | ||
214 | INIT_LIST_HEAD(&dev->dma_pools); | 214 | INIT_LIST_HEAD(&dev->dma_pools); |
215 | init_MUTEX(&dev->sem); | 215 | init_MUTEX(&dev->sem); |
216 | } | 216 | } |
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 | ||
diff --git a/drivers/base/driver.c b/drivers/base/driver.c index 484fed1985aa..34bd38aa7eb8 100644 --- a/drivers/base/driver.c +++ b/drivers/base/driver.c | |||
@@ -19,6 +19,12 @@ | |||
19 | #define to_drv(obj) container_of(obj, struct device_driver, kobj) | 19 | #define to_drv(obj) container_of(obj, struct device_driver, kobj) |
20 | 20 | ||
21 | 21 | ||
22 | static struct device * next_device(struct klist_iter * i) | ||
23 | { | ||
24 | struct klist_node * n = klist_next(i); | ||
25 | return n ? container_of(n, struct device, knode_driver) : NULL; | ||
26 | } | ||
27 | |||
22 | /** | 28 | /** |
23 | * driver_for_each_device - Iterator for devices bound to a driver. | 29 | * driver_for_each_device - Iterator for devices bound to a driver. |
24 | * @drv: Driver we're iterating. | 30 | * @drv: Driver we're iterating. |
@@ -32,21 +38,18 @@ | |||
32 | int driver_for_each_device(struct device_driver * drv, struct device * start, | 38 | int driver_for_each_device(struct device_driver * drv, struct device * start, |
33 | void * data, int (*fn)(struct device *, void *)) | 39 | void * data, int (*fn)(struct device *, void *)) |
34 | { | 40 | { |
35 | struct list_head * head; | 41 | struct klist_iter i; |
36 | struct device * dev; | 42 | struct device * dev; |
37 | int error = 0; | 43 | int error = 0; |
38 | 44 | ||
39 | down_read(&drv->bus->subsys.rwsem); | 45 | if (!drv) |
40 | head = &drv->devices; | 46 | return -EINVAL; |
41 | dev = list_prepare_entry(start, head, driver_list); | 47 | |
42 | list_for_each_entry_continue(dev, head, driver_list) { | 48 | klist_iter_init_node(&drv->klist_devices, &i, |
43 | get_device(dev); | 49 | start ? &start->knode_driver : NULL); |
50 | while ((dev = next_device(&i)) && !error) | ||
44 | error = fn(dev, data); | 51 | error = fn(dev, data); |
45 | put_device(dev); | 52 | klist_iter_exit(&i); |
46 | if (error) | ||
47 | break; | ||
48 | } | ||
49 | up_read(&drv->bus->subsys.rwsem); | ||
50 | return error; | 53 | return error; |
51 | } | 54 | } |
52 | 55 | ||
@@ -120,7 +123,7 @@ void put_driver(struct device_driver * drv) | |||
120 | */ | 123 | */ |
121 | int driver_register(struct device_driver * drv) | 124 | int driver_register(struct device_driver * drv) |
122 | { | 125 | { |
123 | INIT_LIST_HEAD(&drv->devices); | 126 | klist_init(&drv->klist_devices); |
124 | init_completion(&drv->unloaded); | 127 | init_completion(&drv->unloaded); |
125 | return bus_add_driver(drv); | 128 | return bus_add_driver(drv); |
126 | } | 129 | } |