Commit f9c46d6e authored by Nadia Derbey's avatar Nadia Derbey Committed by Linus Torvalds
Browse files

idr: make idr_find rcu-safe



Make idr_find rcu-safe: it can now be called inside an rcu_read critical
section.

Signed-off-by: default avatarNadia Derbey <Nadia.Derbey@bull.net>
Reviewed-by: default avatar"Paul E. McKenney" <paulmck@us.ibm.com>
Cc: Manfred Spraul <manfred@colorfullife.com>
Cc: Jim Houston <jim.houston@comcast.net>
Cc: Pierre Peiffer <peifferp@gmail.com>
Acked-by: default avatarRik van Riel <riel@redhat.com>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent 3219b3b7
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -79,6 +79,22 @@ struct idr {

#define _idr_rc_to_errno(rc) ((rc) == -1 ? -EAGAIN : -ENOSPC)

/**
 * idr synchronization (stolen from radix-tree.h)
 *
 * idr_find() is able to be called locklessly, using RCU. The caller must
 * ensure calls to this function are made within rcu_read_lock() regions.
 * Other readers (lock-free or otherwise) and modifications may be running
 * concurrently.
 *
 * It is still required that the caller manage the synchronization and
 * lifetimes of the items. So if RCU lock-free lookups are used, typically
 * this would mean that the items have their own locks, or are amenable to
 * lock-free access; and that the items are freed by RCU (or only freed after
 * having been deleted from the idr tree *and* a synchronize_rcu() grace
 * period).
 */

/*
 * This is what we export.
 */
+6 −5
Original line number Diff line number Diff line
@@ -456,7 +456,8 @@ EXPORT_SYMBOL(idr_destroy);
 * return indicates that @id is not valid or you passed %NULL in
 * idr_get_new().
 *
 * The caller must serialize idr_find() vs idr_get_new() and idr_remove().
 * This function can be called under rcu_read_lock(), given that the leaf
 * pointers lifetimes are correctly managed.
 */
void *idr_find(struct idr *idp, int id)
{
@@ -464,7 +465,7 @@ void *idr_find(struct idr *idp, int id)
	struct idr_layer *p;

	n = idp->layers * IDR_BITS;
	p = idp->top;
	p = rcu_dereference(idp->top);

	/* Mask off upper bits we don't use for the search. */
	id &= MAX_ID_MASK;
@@ -474,7 +475,7 @@ void *idr_find(struct idr *idp, int id)

	while (n > 0 && p) {
		n -= IDR_BITS;
		p = p->ary[(id >> n) & IDR_MASK];
		p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]);
	}
	return((void *)p);
}
@@ -507,7 +508,7 @@ int idr_for_each(struct idr *idp,
	struct idr_layer **paa = &pa[0];

	n = idp->layers * IDR_BITS;
	p = idp->top;
	p = rcu_dereference(idp->top);
	max = 1 << n;

	id = 0;
@@ -515,7 +516,7 @@ int idr_for_each(struct idr *idp,
		while (n > 0 && p) {
			n -= IDR_BITS;
			*paa++ = p;
			p = p->ary[(id >> n) & IDR_MASK];
			p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]);
		}

		if (p) {