diff options
author | James Bottomley <James.Bottomley@steeleye.com> | 2005-08-28 10:13:17 -0400 |
---|---|---|
committer | James Bottomley <jejb@titanic.(none)> | 2005-08-30 23:44:32 -0400 |
commit | 2b7d6a8cb9718fc1d9e826201b64909c44a915f4 (patch) | |
tree | ad08bea9651332c41192cd7e019692a1e1e103bf /drivers/base/attribute_container.c | |
parent | 53c165e0a6c8a4ff7df316557528fa7a52d20711 (diff) |
[SCSI] attribute container final klist fixes
Since the attribute container deletes from a klist while it's walking
it, it is vulnerable to the problem (and fix) here:
http://marc.theaimsgroup.com/?l=linux-scsi&m=112485448830217
The attached fixes this (but won't compile without the above).
It also fixes the logical reversal in the traversal loop which meant
that we were never actually traversing the loop to hit this bug in the
first place.
Signed-off-by: James Bottomley <James.Bottomley@SteelEye.com>
Diffstat (limited to 'drivers/base/attribute_container.c')
-rw-r--r-- | drivers/base/attribute_container.c | 24 |
1 files changed, 20 insertions, 4 deletions
diff --git a/drivers/base/attribute_container.c b/drivers/base/attribute_container.c index 6c0f49340eb2..373e7b728fa7 100644 --- a/drivers/base/attribute_container.c +++ b/drivers/base/attribute_container.c | |||
@@ -27,6 +27,21 @@ struct internal_container { | |||
27 | struct class_device classdev; | 27 | struct class_device classdev; |
28 | }; | 28 | }; |
29 | 29 | ||
30 | static void internal_container_klist_get(struct klist_node *n) | ||
31 | { | ||
32 | struct internal_container *ic = | ||
33 | container_of(n, struct internal_container, node); | ||
34 | class_device_get(&ic->classdev); | ||
35 | } | ||
36 | |||
37 | static void internal_container_klist_put(struct klist_node *n) | ||
38 | { | ||
39 | struct internal_container *ic = | ||
40 | container_of(n, struct internal_container, node); | ||
41 | class_device_put(&ic->classdev); | ||
42 | } | ||
43 | |||
44 | |||
30 | /** | 45 | /** |
31 | * attribute_container_classdev_to_container - given a classdev, return the container | 46 | * attribute_container_classdev_to_container - given a classdev, return the container |
32 | * | 47 | * |
@@ -57,7 +72,8 @@ int | |||
57 | attribute_container_register(struct attribute_container *cont) | 72 | attribute_container_register(struct attribute_container *cont) |
58 | { | 73 | { |
59 | INIT_LIST_HEAD(&cont->node); | 74 | INIT_LIST_HEAD(&cont->node); |
60 | klist_init(&cont->containers); | 75 | klist_init(&cont->containers,internal_container_klist_get, |
76 | internal_container_klist_put); | ||
61 | 77 | ||
62 | down(&attribute_container_mutex); | 78 | down(&attribute_container_mutex); |
63 | list_add_tail(&cont->node, &attribute_container_list); | 79 | list_add_tail(&cont->node, &attribute_container_list); |
@@ -163,8 +179,8 @@ attribute_container_add_device(struct device *dev, | |||
163 | #define klist_for_each_entry(pos, head, member, iter) \ | 179 | #define klist_for_each_entry(pos, head, member, iter) \ |
164 | for (klist_iter_init(head, iter); (pos = ({ \ | 180 | for (klist_iter_init(head, iter); (pos = ({ \ |
165 | struct klist_node *n = klist_next(iter); \ | 181 | struct klist_node *n = klist_next(iter); \ |
166 | n ? ({ klist_iter_exit(iter) ; NULL; }) : \ | 182 | n ? container_of(n, typeof(*pos), member) : \ |
167 | container_of(n, typeof(*pos), member);\ | 183 | ({ klist_iter_exit(iter) ; NULL; }); \ |
168 | }) ) != NULL; ) | 184 | }) ) != NULL; ) |
169 | 185 | ||
170 | 186 | ||
@@ -206,7 +222,7 @@ attribute_container_remove_device(struct device *dev, | |||
206 | klist_for_each_entry(ic, &cont->containers, node, &iter) { | 222 | klist_for_each_entry(ic, &cont->containers, node, &iter) { |
207 | if (dev != ic->classdev.dev) | 223 | if (dev != ic->classdev.dev) |
208 | continue; | 224 | continue; |
209 | klist_remove(&ic->node); | 225 | klist_del(&ic->node); |
210 | if (fn) | 226 | if (fn) |
211 | fn(cont, dev, &ic->classdev); | 227 | fn(cont, dev, &ic->classdev); |
212 | else { | 228 | else { |