aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2015-07-27 11:03:59 -0400
committerLee Jones <lee.jones@linaro.org>2015-07-28 03:50:42 -0400
commit2e0fed7f7cdc41679e209c5636ad7537dc6210a9 (patch)
treeb6b445d658a1c4f2d2e95f8afcb9402f5807216c
parentddef08dd00f5548f943422c86e4ffe67dd040b6c (diff)
klist: implement klist_prev()
klist_prev() gets the previous element in the list. It is useful to traverse through the list in reverse order, for example, to provide LIFO (last in first out) variant of access. Signed-off-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> Signed-off-by: Lee Jones <lee.jones@linaro.org>
-rw-r--r--include/linux/klist.h1
-rw-r--r--lib/klist.c41
2 files changed, 42 insertions, 0 deletions
diff --git a/include/linux/klist.h b/include/linux/klist.h
index 61e5b723ae73..953f283f8451 100644
--- a/include/linux/klist.h
+++ b/include/linux/klist.h
@@ -63,6 +63,7 @@ extern void klist_iter_init(struct klist *k, struct klist_iter *i);
63extern void klist_iter_init_node(struct klist *k, struct klist_iter *i, 63extern void klist_iter_init_node(struct klist *k, struct klist_iter *i,
64 struct klist_node *n); 64 struct klist_node *n);
65extern void klist_iter_exit(struct klist_iter *i); 65extern void klist_iter_exit(struct klist_iter *i);
66extern struct klist_node *klist_prev(struct klist_iter *i);
66extern struct klist_node *klist_next(struct klist_iter *i); 67extern struct klist_node *klist_next(struct klist_iter *i);
67 68
68#endif 69#endif
diff --git a/lib/klist.c b/lib/klist.c
index 89b485a2a58d..d74cf7a29afd 100644
--- a/lib/klist.c
+++ b/lib/klist.c
@@ -324,6 +324,47 @@ static struct klist_node *to_klist_node(struct list_head *n)
324} 324}
325 325
326/** 326/**
327 * klist_prev - Ante up prev node in list.
328 * @i: Iterator structure.
329 *
330 * First grab list lock. Decrement the reference count of the previous
331 * node, if there was one. Grab the prev node, increment its reference
332 * count, drop the lock, and return that prev node.
333 */
334struct klist_node *klist_prev(struct klist_iter *i)
335{
336 void (*put)(struct klist_node *) = i->i_klist->put;
337 struct klist_node *last = i->i_cur;
338 struct klist_node *prev;
339
340 spin_lock(&i->i_klist->k_lock);
341
342 if (last) {
343 prev = to_klist_node(last->n_node.prev);
344 if (!klist_dec_and_del(last))
345 put = NULL;
346 } else
347 prev = to_klist_node(i->i_klist->k_list.prev);
348
349 i->i_cur = NULL;
350 while (prev != to_klist_node(&i->i_klist->k_list)) {
351 if (likely(!knode_dead(prev))) {
352 kref_get(&prev->n_ref);
353 i->i_cur = prev;
354 break;
355 }
356 prev = to_klist_node(prev->n_node.prev);
357 }
358
359 spin_unlock(&i->i_klist->k_lock);
360
361 if (put && last)
362 put(last);
363 return i->i_cur;
364}
365EXPORT_SYMBOL_GPL(klist_prev);
366
367/**
327 * klist_next - Ante up next node in list. 368 * klist_next - Ante up next node in list.
328 * @i: Iterator structure. 369 * @i: Iterator structure.
329 * 370 *