diff options
author | James Bottomley <James.Bottomley@HansenPartnership.com> | 2005-09-06 19:56:51 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 21:26:54 -0400 |
commit | 34bb61f9ddabd7a7f909cbfb05592eb775f6662a (patch) | |
tree | 06232f6fc975bd279236fd8005c7d5528220ec68 /drivers/base/core.c | |
parent | df4edad1787bbfa3c9c10824e4f11e9f4a7ec5c6 (diff) |
[PATCH] fix klist semantics for lists which have elements removed on traversal
The problem is that klists claim to provide semantics for safe traversal of
lists which are being modified. The failure case is when traversal of a
list causes element removal (a fairly common case). The issue is that
although the list node is refcounted, if it is embedded in an object (which
is universally the case), then the object will be freed regardless of the
klist refcount leading to slab corruption because the klist iterator refers
to the prior element to get the next.
The solution is to make the klist take and release references to the
embedding object meaning that the embedding object won't be released until
the list relinquishes the reference to it.
(akpm: fast-track this because it's needed for the 2.6.13 scsi merge)
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'drivers/base/core.c')
-rw-r--r-- | drivers/base/core.c | 17 |
1 files changed, 16 insertions, 1 deletions
diff --git a/drivers/base/core.c b/drivers/base/core.c index c8a33df00761..6ab73f5c799a 100644 --- a/drivers/base/core.c +++ b/drivers/base/core.c | |||
@@ -191,6 +191,20 @@ void device_remove_file(struct device * dev, struct device_attribute * attr) | |||
191 | } | 191 | } |
192 | } | 192 | } |
193 | 193 | ||
194 | static void klist_children_get(struct klist_node *n) | ||
195 | { | ||
196 | struct device *dev = container_of(n, struct device, knode_parent); | ||
197 | |||
198 | get_device(dev); | ||
199 | } | ||
200 | |||
201 | static void klist_children_put(struct klist_node *n) | ||
202 | { | ||
203 | struct device *dev = container_of(n, struct device, knode_parent); | ||
204 | |||
205 | put_device(dev); | ||
206 | } | ||
207 | |||
194 | 208 | ||
195 | /** | 209 | /** |
196 | * device_initialize - init device structure. | 210 | * device_initialize - init device structure. |
@@ -207,7 +221,8 @@ void device_initialize(struct device *dev) | |||
207 | { | 221 | { |
208 | kobj_set_kset_s(dev, devices_subsys); | 222 | kobj_set_kset_s(dev, devices_subsys); |
209 | kobject_init(&dev->kobj); | 223 | kobject_init(&dev->kobj); |
210 | klist_init(&dev->klist_children); | 224 | klist_init(&dev->klist_children, klist_children_get, |
225 | klist_children_put); | ||
211 | INIT_LIST_HEAD(&dev->dma_pools); | 226 | INIT_LIST_HEAD(&dev->dma_pools); |
212 | init_MUTEX(&dev->sem); | 227 | init_MUTEX(&dev->sem); |
213 | } | 228 | } |