diff options
Diffstat (limited to 'lib/klist.c')
| -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.   *  |