diff options
author | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-07-31 21:40:03 +0200 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2015-07-31 21:40:03 +0200 |
commit | 50ba22479c324c0d9dc8134d519dcba92d83a8a7 (patch) | |
tree | 0f939779c7ff97d1b4e923a4fbded2718e09e4d3 /lib | |
parent | 71b65445f0ed04c2afe3660f829779fddb2890c1 (diff) | |
parent | 3431e490b50356b56084305a2e93b3a980802b22 (diff) |
Merge back earlier ACPI PM material for v4.3.
Diffstat (limited to 'lib')
-rw-r--r-- | lib/klist.c | 41 |
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. * |