summaryrefslogtreecommitdiffstats
path: root/lib/klist.c
diff options
context:
space:
mode:
authorAndy Shevchenko <andriy.shevchenko@linux.intel.com>2015-07-27 18:03:59 +0300
committerLee Jones <lee.jones@linaro.org>2015-07-28 08:50:42 +0100
commit2e0fed7f7cdc41679e209c5636ad7537dc6210a9 (patch)
treeb6b445d658a1c4f2d2e95f8afcb9402f5807216c /lib/klist.c
parentddef08dd00f5548f943422c86e4ffe67dd040b6c (diff)
downloadlinux-stable-2e0fed7f7cdc41679e209c5636ad7537dc6210a9.tar.gz
linux-stable-2e0fed7f7cdc41679e209c5636ad7537dc6210a9.tar.bz2
linux-stable-2e0fed7f7cdc41679e209c5636ad7537dc6210a9.zip
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>
Diffstat (limited to 'lib/klist.c')
-rw-r--r--lib/klist.c41
1 files changed, 41 insertions, 0 deletions
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)
}
/**
+ * 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);
+
+/**
* klist_next - Ante up next node in list.
* @i: Iterator structure.
*