aboutsummaryrefslogtreecommitdiffstats
path: root/lib/klist.c
diff options
context:
space:
mode:
authorJames Bottomley <James.Bottomley@HansenPartnership.com>2005-09-06 19:56:51 -0400
committerLinus Torvalds <torvalds@g5.osdl.org>2005-09-07 21:26:54 -0400
commit34bb61f9ddabd7a7f909cbfb05592eb775f6662a (patch)
tree06232f6fc975bd279236fd8005c7d5528220ec68 /lib/klist.c
parentdf4edad1787bbfa3c9c10824e4f11e9f4a7ec5c6 (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 'lib/klist.c')
-rw-r--r--lib/klist.c18
1 files changed, 17 insertions, 1 deletions
diff --git a/lib/klist.c b/lib/klist.c
index a70c836c5c4c..bb2f3551d50a 100644
--- a/lib/klist.c
+++ b/lib/klist.c
@@ -42,12 +42,23 @@
42/** 42/**
43 * klist_init - Initialize a klist structure. 43 * klist_init - Initialize a klist structure.
44 * @k: The klist we're initializing. 44 * @k: The klist we're initializing.
45 * @get: The get function for the embedding object (NULL if none)
46 * @put: The put function for the embedding object (NULL if none)
47 *
48 * Initialises the klist structure. If the klist_node structures are
49 * going to be embedded in refcounted objects (necessary for safe
50 * deletion) then the get/put arguments are used to initialise
51 * functions that take and release references on the embedding
52 * objects.
45 */ 53 */
46 54
47void klist_init(struct klist * k) 55void klist_init(struct klist * k, void (*get)(struct klist_node *),
56 void (*put)(struct klist_node *))
48{ 57{
49 INIT_LIST_HEAD(&k->k_list); 58 INIT_LIST_HEAD(&k->k_list);
50 spin_lock_init(&k->k_lock); 59 spin_lock_init(&k->k_lock);
60 k->get = get;
61 k->put = put;
51} 62}
52 63
53EXPORT_SYMBOL_GPL(klist_init); 64EXPORT_SYMBOL_GPL(klist_init);
@@ -74,6 +85,8 @@ static void klist_node_init(struct klist * k, struct klist_node * n)
74 init_completion(&n->n_removed); 85 init_completion(&n->n_removed);
75 kref_init(&n->n_ref); 86 kref_init(&n->n_ref);
76 n->n_klist = k; 87 n->n_klist = k;
88 if (k->get)
89 k->get(n);
77} 90}
78 91
79 92
@@ -110,9 +123,12 @@ EXPORT_SYMBOL_GPL(klist_add_tail);
110static void klist_release(struct kref * kref) 123static void klist_release(struct kref * kref)
111{ 124{
112 struct klist_node * n = container_of(kref, struct klist_node, n_ref); 125 struct klist_node * n = container_of(kref, struct klist_node, n_ref);
126 void (*put)(struct klist_node *) = n->n_klist->put;
113 list_del(&n->n_node); 127 list_del(&n->n_node);
114 complete(&n->n_removed); 128 complete(&n->n_removed);
115 n->n_klist = NULL; 129 n->n_klist = NULL;
130 if (put)
131 put(n);
116} 132}
117 133
118static int klist_dec_and_del(struct klist_node * n) 134static int klist_dec_and_del(struct klist_node * n)