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

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
...@@ -79,6 +79,22 @@ struct idr { ...@@ -79,6 +79,22 @@ struct idr {
#define _idr_rc_to_errno(rc) ((rc) == -1 ? -EAGAIN : -ENOSPC) #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. * This is what we export.
*/ */
......
...@@ -456,7 +456,8 @@ EXPORT_SYMBOL(idr_destroy); ...@@ -456,7 +456,8 @@ EXPORT_SYMBOL(idr_destroy);
* return indicates that @id is not valid or you passed %NULL in * return indicates that @id is not valid or you passed %NULL in
* idr_get_new(). * 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) void *idr_find(struct idr *idp, int id)
{ {
...@@ -464,7 +465,7 @@ void *idr_find(struct idr *idp, int id) ...@@ -464,7 +465,7 @@ void *idr_find(struct idr *idp, int id)
struct idr_layer *p; struct idr_layer *p;
n = idp->layers * IDR_BITS; n = idp->layers * IDR_BITS;
p = idp->top; p = rcu_dereference(idp->top);
/* Mask off upper bits we don't use for the search. */ /* Mask off upper bits we don't use for the search. */
id &= MAX_ID_MASK; id &= MAX_ID_MASK;
...@@ -474,7 +475,7 @@ void *idr_find(struct idr *idp, int id) ...@@ -474,7 +475,7 @@ void *idr_find(struct idr *idp, int id)
while (n > 0 && p) { while (n > 0 && p) {
n -= IDR_BITS; n -= IDR_BITS;
p = p->ary[(id >> n) & IDR_MASK]; p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]);
} }
return((void *)p); return((void *)p);
} }
...@@ -507,7 +508,7 @@ int idr_for_each(struct idr *idp, ...@@ -507,7 +508,7 @@ int idr_for_each(struct idr *idp,
struct idr_layer **paa = &pa[0]; struct idr_layer **paa = &pa[0];
n = idp->layers * IDR_BITS; n = idp->layers * IDR_BITS;
p = idp->top; p = rcu_dereference(idp->top);
max = 1 << n; max = 1 << n;
id = 0; id = 0;
...@@ -515,7 +516,7 @@ int idr_for_each(struct idr *idp, ...@@ -515,7 +516,7 @@ int idr_for_each(struct idr *idp,
while (n > 0 && p) { while (n > 0 && p) {
n -= IDR_BITS; n -= IDR_BITS;
*paa++ = p; *paa++ = p;
p = p->ary[(id >> n) & IDR_MASK]; p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]);
} }
if (p) { if (p) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment