Blame view
lib/klist.c
10.3 KB
9a19fea43 [PATCH] Add initi... |
1 |
/* |
c3bb7fada klist: fix coding... |
2 |
* klist.c - Routines for manipulating klists. |
9a19fea43 [PATCH] Add initi... |
3 |
* |
c3bb7fada klist: fix coding... |
4 |
* Copyright (C) 2005 Patrick Mochel |
9a19fea43 [PATCH] Add initi... |
5 |
* |
c3bb7fada klist: fix coding... |
6 |
* This file is released under the GPL v2. |
9a19fea43 [PATCH] Add initi... |
7 |
* |
c3bb7fada klist: fix coding... |
8 9 10 11 12 13 14 |
* This klist interface provides a couple of structures that wrap around * struct list_head to provide explicit list "head" (struct klist) and list * "node" (struct klist_node) objects. For struct klist, a spinlock is * included that protects access to the actual list itself. struct * klist_node provides a pointer to the klist that owns it and a kref * reference count that indicates the number of current users of that node * in the list. |
9a19fea43 [PATCH] Add initi... |
15 |
* |
c3bb7fada klist: fix coding... |
16 17 18 19 |
* The entire point is to provide an interface for iterating over a list * that is safe and allows for modification of the list during the * iteration (e.g. insertion and removal), including modification of the * current node on the list. |
9a19fea43 [PATCH] Add initi... |
20 |
* |
c3bb7fada klist: fix coding... |
21 22 23 24 25 26 |
* It works using a 3rd object type - struct klist_iter - that is declared * and initialized before an iteration. klist_next() is used to acquire the * next element in the list. It returns NULL if there are no more items. * Internally, that routine takes the klist's lock, decrements the * reference count of the previous klist_node and increments the count of * the next klist_node. It then drops the lock and returns. |
9a19fea43 [PATCH] Add initi... |
27 |
* |
c3bb7fada klist: fix coding... |
28 29 30 31 32 33 34 |
* There are primitives for adding and removing nodes to/from a klist. * When deleting, klist_del() will simply decrement the reference count. * Only when the count goes to 0 is the node removed from the list. * klist_remove() will try to delete the node from the list and block until * it is actually removed. This is useful for objects (like devices) that * have been removed from the system and must be freed (but must wait until * all accessors have finished). |
9a19fea43 [PATCH] Add initi... |
35 36 37 |
*/ #include <linux/klist.h> |
8bc3bcc93 lib: reduce the u... |
38 |
#include <linux/export.h> |
210272a28 driver core: Remo... |
39 |
#include <linux/sched.h> |
9a19fea43 [PATCH] Add initi... |
40 |
|
a1ed5b0cf klist: don't iter... |
41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
/* * Use the lowest bit of n_klist to mark deleted nodes and exclude * dead ones from iteration. */ #define KNODE_DEAD 1LU #define KNODE_KLIST_MASK ~KNODE_DEAD static struct klist *knode_klist(struct klist_node *knode) { return (struct klist *) ((unsigned long)knode->n_klist & KNODE_KLIST_MASK); } static bool knode_dead(struct klist_node *knode) { return (unsigned long)knode->n_klist & KNODE_DEAD; } static void knode_set_klist(struct klist_node *knode, struct klist *klist) { knode->n_klist = klist; /* no knode deserves to start its life dead */ WARN_ON(knode_dead(knode)); } static void knode_kill(struct klist_node *knode) { /* and no knode should die twice ever either, see we're very humane */ WARN_ON(knode_dead(knode)); *(unsigned long *)&knode->n_klist |= KNODE_DEAD; } |
9a19fea43 [PATCH] Add initi... |
72 73 |
/** |
c3bb7fada klist: fix coding... |
74 75 76 77 |
* klist_init - Initialize a klist structure. * @k: The klist we're initializing. * @get: The get function for the embedding object (NULL if none) * @put: The put function for the embedding object (NULL if none) |
34bb61f9d [PATCH] fix klist... |
78 79 80 81 82 83 |
* * Initialises the klist structure. If the klist_node structures are * going to be embedded in refcounted objects (necessary for safe * deletion) then the get/put arguments are used to initialise * functions that take and release references on the embedding * objects. |
9a19fea43 [PATCH] Add initi... |
84 |
*/ |
c3bb7fada klist: fix coding... |
85 |
void klist_init(struct klist *k, void (*get)(struct klist_node *), |
34bb61f9d [PATCH] fix klist... |
86 |
void (*put)(struct klist_node *)) |
9a19fea43 [PATCH] Add initi... |
87 88 89 |
{ INIT_LIST_HEAD(&k->k_list); spin_lock_init(&k->k_lock); |
34bb61f9d [PATCH] fix klist... |
90 91 |
k->get = get; k->put = put; |
9a19fea43 [PATCH] Add initi... |
92 |
} |
9a19fea43 [PATCH] Add initi... |
93 |
EXPORT_SYMBOL_GPL(klist_init); |
c3bb7fada klist: fix coding... |
94 |
static void add_head(struct klist *k, struct klist_node *n) |
9a19fea43 [PATCH] Add initi... |
95 96 97 98 99 |
{ spin_lock(&k->k_lock); list_add(&n->n_node, &k->k_list); spin_unlock(&k->k_lock); } |
c3bb7fada klist: fix coding... |
100 |
static void add_tail(struct klist *k, struct klist_node *n) |
9a19fea43 [PATCH] Add initi... |
101 102 103 104 105 |
{ spin_lock(&k->k_lock); list_add_tail(&n->n_node, &k->k_list); spin_unlock(&k->k_lock); } |
c3bb7fada klist: fix coding... |
106 |
static void klist_node_init(struct klist *k, struct klist_node *n) |
9a19fea43 [PATCH] Add initi... |
107 108 |
{ INIT_LIST_HEAD(&n->n_node); |
9a19fea43 [PATCH] Add initi... |
109 |
kref_init(&n->n_ref); |
a1ed5b0cf klist: don't iter... |
110 |
knode_set_klist(n, k); |
34bb61f9d [PATCH] fix klist... |
111 112 |
if (k->get) k->get(n); |
9a19fea43 [PATCH] Add initi... |
113 |
} |
9a19fea43 [PATCH] Add initi... |
114 |
/** |
c3bb7fada klist: fix coding... |
115 116 117 |
* klist_add_head - Initialize a klist_node and add it to front. * @n: node we're adding. * @k: klist it's going on. |
9a19fea43 [PATCH] Add initi... |
118 |
*/ |
c3bb7fada klist: fix coding... |
119 |
void klist_add_head(struct klist_node *n, struct klist *k) |
9a19fea43 [PATCH] Add initi... |
120 121 122 123 |
{ klist_node_init(k, n); add_head(k, n); } |
9a19fea43 [PATCH] Add initi... |
124 |
EXPORT_SYMBOL_GPL(klist_add_head); |
9a19fea43 [PATCH] Add initi... |
125 |
/** |
c3bb7fada klist: fix coding... |
126 127 128 |
* klist_add_tail - Initialize a klist_node and add it to back. * @n: node we're adding. * @k: klist it's going on. |
9a19fea43 [PATCH] Add initi... |
129 |
*/ |
c3bb7fada klist: fix coding... |
130 |
void klist_add_tail(struct klist_node *n, struct klist *k) |
9a19fea43 [PATCH] Add initi... |
131 132 133 134 |
{ klist_node_init(k, n); add_tail(k, n); } |
9a19fea43 [PATCH] Add initi... |
135 |
EXPORT_SYMBOL_GPL(klist_add_tail); |
93dd40013 klist: implement ... |
136 |
/** |
0f9859ca9 klist: use same n... |
137 |
* klist_add_behind - Init a klist_node and add it after an existing node |
93dd40013 klist: implement ... |
138 139 140 |
* @n: node we're adding. * @pos: node to put @n after */ |
0f9859ca9 klist: use same n... |
141 |
void klist_add_behind(struct klist_node *n, struct klist_node *pos) |
93dd40013 klist: implement ... |
142 |
{ |
a1ed5b0cf klist: don't iter... |
143 |
struct klist *k = knode_klist(pos); |
93dd40013 klist: implement ... |
144 145 146 147 148 149 |
klist_node_init(k, n); spin_lock(&k->k_lock); list_add(&n->n_node, &pos->n_node); spin_unlock(&k->k_lock); } |
0f9859ca9 klist: use same n... |
150 |
EXPORT_SYMBOL_GPL(klist_add_behind); |
93dd40013 klist: implement ... |
151 152 153 154 155 156 157 158 |
/** * klist_add_before - Init a klist_node and add it before an existing node * @n: node we're adding. * @pos: node to put @n after */ void klist_add_before(struct klist_node *n, struct klist_node *pos) { |
a1ed5b0cf klist: don't iter... |
159 |
struct klist *k = knode_klist(pos); |
93dd40013 klist: implement ... |
160 161 162 163 164 165 166 |
klist_node_init(k, n); spin_lock(&k->k_lock); list_add_tail(&n->n_node, &pos->n_node); spin_unlock(&k->k_lock); } EXPORT_SYMBOL_GPL(klist_add_before); |
210272a28 driver core: Remo... |
167 168 169 170 171 172 173 174 175 |
struct klist_waiter { struct list_head list; struct klist_node *node; struct task_struct *process; int woken; }; static DEFINE_SPINLOCK(klist_remove_lock); static LIST_HEAD(klist_remove_waiters); |
c3bb7fada klist: fix coding... |
176 |
static void klist_release(struct kref *kref) |
9a19fea43 [PATCH] Add initi... |
177 |
{ |
210272a28 driver core: Remo... |
178 |
struct klist_waiter *waiter, *tmp; |
c3bb7fada klist: fix coding... |
179 |
struct klist_node *n = container_of(kref, struct klist_node, n_ref); |
7e9f4b2d3 Driver core: Don'... |
180 |
|
a1ed5b0cf klist: don't iter... |
181 |
WARN_ON(!knode_dead(n)); |
9a19fea43 [PATCH] Add initi... |
182 |
list_del(&n->n_node); |
210272a28 driver core: Remo... |
183 184 185 186 |
spin_lock(&klist_remove_lock); list_for_each_entry_safe(waiter, tmp, &klist_remove_waiters, list) { if (waiter->node != n) continue; |
ac5a2962b klist: del waiter... |
187 |
list_del(&waiter->list); |
210272a28 driver core: Remo... |
188 189 190 |
waiter->woken = 1; mb(); wake_up_process(waiter->process); |
210272a28 driver core: Remo... |
191 192 |
} spin_unlock(&klist_remove_lock); |
a1ed5b0cf klist: don't iter... |
193 |
knode_set_klist(n, NULL); |
9a19fea43 [PATCH] Add initi... |
194 |
} |
c3bb7fada klist: fix coding... |
195 |
static int klist_dec_and_del(struct klist_node *n) |
9a19fea43 [PATCH] Add initi... |
196 197 198 |
{ return kref_put(&n->n_ref, klist_release); } |
a1ed5b0cf klist: don't iter... |
199 |
static void klist_put(struct klist_node *n, bool kill) |
9a19fea43 [PATCH] Add initi... |
200 |
{ |
a1ed5b0cf klist: don't iter... |
201 |
struct klist *k = knode_klist(n); |
7e9f4b2d3 Driver core: Don'... |
202 |
void (*put)(struct klist_node *) = k->put; |
9a19fea43 [PATCH] Add initi... |
203 204 |
spin_lock(&k->k_lock); |
a1ed5b0cf klist: don't iter... |
205 206 |
if (kill) knode_kill(n); |
7e9f4b2d3 Driver core: Don'... |
207 208 |
if (!klist_dec_and_del(n)) put = NULL; |
9a19fea43 [PATCH] Add initi... |
209 |
spin_unlock(&k->k_lock); |
7e9f4b2d3 Driver core: Don'... |
210 211 |
if (put) put(n); |
9a19fea43 [PATCH] Add initi... |
212 |
} |
a1ed5b0cf klist: don't iter... |
213 214 215 216 217 218 219 220 221 |
/** * klist_del - Decrement the reference count of node and try to remove. * @n: node we're deleting. */ void klist_del(struct klist_node *n) { klist_put(n, true); } |
9a19fea43 [PATCH] Add initi... |
222 |
EXPORT_SYMBOL_GPL(klist_del); |
9a19fea43 [PATCH] Add initi... |
223 |
/** |
c3bb7fada klist: fix coding... |
224 225 |
* klist_remove - Decrement the refcount of node and wait for it to go away. * @n: node we're removing. |
9a19fea43 [PATCH] Add initi... |
226 |
*/ |
c3bb7fada klist: fix coding... |
227 |
void klist_remove(struct klist_node *n) |
9a19fea43 [PATCH] Add initi... |
228 |
{ |
210272a28 driver core: Remo... |
229 230 231 232 233 234 235 236 |
struct klist_waiter waiter; waiter.node = n; waiter.process = current; waiter.woken = 0; spin_lock(&klist_remove_lock); list_add(&waiter.list, &klist_remove_waiters); spin_unlock(&klist_remove_lock); |
7e9f4b2d3 Driver core: Don'... |
237 |
klist_del(n); |
210272a28 driver core: Remo... |
238 239 240 241 242 243 244 245 |
for (;;) { set_current_state(TASK_UNINTERRUPTIBLE); if (waiter.woken) break; schedule(); } __set_current_state(TASK_RUNNING); |
9a19fea43 [PATCH] Add initi... |
246 |
} |
9a19fea43 [PATCH] Add initi... |
247 |
EXPORT_SYMBOL_GPL(klist_remove); |
9a19fea43 [PATCH] Add initi... |
248 |
/** |
c3bb7fada klist: fix coding... |
249 250 |
* klist_node_attached - Say whether a node is bound to a list or not. * @n: Node that we're testing. |
8b0c250be [PATCH] add klist... |
251 |
*/ |
c3bb7fada klist: fix coding... |
252 |
int klist_node_attached(struct klist_node *n) |
8b0c250be [PATCH] add klist... |
253 254 255 |
{ return (n->n_klist != NULL); } |
8b0c250be [PATCH] add klist... |
256 |
EXPORT_SYMBOL_GPL(klist_node_attached); |
8b0c250be [PATCH] add klist... |
257 |
/** |
c3bb7fada klist: fix coding... |
258 259 260 261 |
* klist_iter_init_node - Initialize a klist_iter structure. * @k: klist we're iterating. * @i: klist_iter we're filling. * @n: node to start with. |
9a19fea43 [PATCH] Add initi... |
262 |
* |
c3bb7fada klist: fix coding... |
263 264 |
* Similar to klist_iter_init(), but starts the action off with @n, * instead of with the list head. |
9a19fea43 [PATCH] Add initi... |
265 |
*/ |
c3bb7fada klist: fix coding... |
266 267 |
void klist_iter_init_node(struct klist *k, struct klist_iter *i, struct klist_node *n) |
9a19fea43 [PATCH] Add initi... |
268 269 |
{ i->i_klist = k; |
00cd29b79 klist: fix starti... |
270 271 272 |
i->i_cur = NULL; if (n && kref_get_unless_zero(&n->n_ref)) i->i_cur = n; |
9a19fea43 [PATCH] Add initi... |
273 |
} |
9a19fea43 [PATCH] Add initi... |
274 |
EXPORT_SYMBOL_GPL(klist_iter_init_node); |
9a19fea43 [PATCH] Add initi... |
275 |
/** |
c3bb7fada klist: fix coding... |
276 277 278 |
* klist_iter_init - Iniitalize a klist_iter structure. * @k: klist we're iterating. * @i: klist_iter structure we're filling. |
9a19fea43 [PATCH] Add initi... |
279 |
* |
c3bb7fada klist: fix coding... |
280 |
* Similar to klist_iter_init_node(), but start with the list head. |
9a19fea43 [PATCH] Add initi... |
281 |
*/ |
c3bb7fada klist: fix coding... |
282 |
void klist_iter_init(struct klist *k, struct klist_iter *i) |
9a19fea43 [PATCH] Add initi... |
283 284 285 |
{ klist_iter_init_node(k, i, NULL); } |
9a19fea43 [PATCH] Add initi... |
286 |
EXPORT_SYMBOL_GPL(klist_iter_init); |
9a19fea43 [PATCH] Add initi... |
287 |
/** |
c3bb7fada klist: fix coding... |
288 289 |
* klist_iter_exit - Finish a list iteration. * @i: Iterator structure. |
9a19fea43 [PATCH] Add initi... |
290 |
* |
c3bb7fada klist: fix coding... |
291 292 293 |
* Must be called when done iterating over list, as it decrements the * refcount of the current node. Necessary in case iteration exited before * the end of the list was reached, and always good form. |
9a19fea43 [PATCH] Add initi... |
294 |
*/ |
c3bb7fada klist: fix coding... |
295 |
void klist_iter_exit(struct klist_iter *i) |
9a19fea43 [PATCH] Add initi... |
296 297 |
{ if (i->i_cur) { |
a1ed5b0cf klist: don't iter... |
298 |
klist_put(i->i_cur, false); |
9a19fea43 [PATCH] Add initi... |
299 300 301 |
i->i_cur = NULL; } } |
9a19fea43 [PATCH] Add initi... |
302 |
EXPORT_SYMBOL_GPL(klist_iter_exit); |
c3bb7fada klist: fix coding... |
303 |
static struct klist_node *to_klist_node(struct list_head *n) |
9a19fea43 [PATCH] Add initi... |
304 305 306 |
{ return container_of(n, struct klist_node, n_node); } |
9a19fea43 [PATCH] Add initi... |
307 |
/** |
2e0fed7f7 klist: implement ... |
308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
* klist_prev - Ante up prev node in list. * @i: Iterator structure. * * First grab list lock. Decrement the reference count of the previous * node, if there was one. Grab the prev node, increment its reference * count, drop the lock, and return that prev node. */ struct klist_node *klist_prev(struct klist_iter *i) { void (*put)(struct klist_node *) = i->i_klist->put; struct klist_node *last = i->i_cur; struct klist_node *prev; spin_lock(&i->i_klist->k_lock); if (last) { prev = to_klist_node(last->n_node.prev); if (!klist_dec_and_del(last)) put = NULL; } else prev = to_klist_node(i->i_klist->k_list.prev); i->i_cur = NULL; while (prev != to_klist_node(&i->i_klist->k_list)) { if (likely(!knode_dead(prev))) { kref_get(&prev->n_ref); i->i_cur = prev; break; } prev = to_klist_node(prev->n_node.prev); } spin_unlock(&i->i_klist->k_lock); if (put && last) put(last); return i->i_cur; } EXPORT_SYMBOL_GPL(klist_prev); /** |
c3bb7fada klist: fix coding... |
349 350 |
* klist_next - Ante up next node in list. * @i: Iterator structure. |
9a19fea43 [PATCH] Add initi... |
351 |
* |
c3bb7fada klist: fix coding... |
352 353 354 |
* First grab list lock. Decrement the reference count of the previous * node, if there was one. Grab the next node, increment its reference * count, drop the lock, and return that next node. |
9a19fea43 [PATCH] Add initi... |
355 |
*/ |
c3bb7fada klist: fix coding... |
356 |
struct klist_node *klist_next(struct klist_iter *i) |
9a19fea43 [PATCH] Add initi... |
357 |
{ |
7e9f4b2d3 Driver core: Don'... |
358 |
void (*put)(struct klist_node *) = i->i_klist->put; |
a1ed5b0cf klist: don't iter... |
359 360 |
struct klist_node *last = i->i_cur; struct klist_node *next; |
9a19fea43 [PATCH] Add initi... |
361 362 |
spin_lock(&i->i_klist->k_lock); |
a1ed5b0cf klist: don't iter... |
363 364 365 366 |
if (last) { next = to_klist_node(last->n_node.next); if (!klist_dec_and_del(last)) |
7e9f4b2d3 Driver core: Don'... |
367 |
put = NULL; |
9a19fea43 [PATCH] Add initi... |
368 |
} else |
a1ed5b0cf klist: don't iter... |
369 |
next = to_klist_node(i->i_klist->k_list.next); |
9a19fea43 [PATCH] Add initi... |
370 |
|
a1ed5b0cf klist: don't iter... |
371 372 373 374 375 376 377 378 |
i->i_cur = NULL; while (next != to_klist_node(&i->i_klist->k_list)) { if (likely(!knode_dead(next))) { kref_get(&next->n_ref); i->i_cur = next; break; } next = to_klist_node(next->n_node.next); |
9a19fea43 [PATCH] Add initi... |
379 |
} |
a1ed5b0cf klist: don't iter... |
380 |
|
9a19fea43 [PATCH] Add initi... |
381 |
spin_unlock(&i->i_klist->k_lock); |
a1ed5b0cf klist: don't iter... |
382 383 384 385 |
if (put && last) put(last); return i->i_cur; |
9a19fea43 [PATCH] Add initi... |
386 |
} |
9a19fea43 [PATCH] Add initi... |
387 |
EXPORT_SYMBOL_GPL(klist_next); |