diff options
author | Nadia Derbey <Nadia.Derbey@bull.net> | 2008-07-25 04:48:01 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2008-07-25 13:53:42 -0400 |
commit | f9c46d6ea5ce138a886c3a0f10a46130afab75f5 (patch) | |
tree | 1eedc2428866fb0b3f9f864e52ffb6eaf00911a4 | |
parent | 3219b3b7456d5cf15ba7b1fe7b1bcf15ce8840e2 (diff) |
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: Nadia Derbey <Nadia.Derbey@bull.net>
Reviewed-by: "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: Rik van Riel <riel@redhat.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | include/linux/idr.h | 16 | ||||
-rw-r--r-- | lib/idr.c | 11 |
2 files changed, 22 insertions, 5 deletions
diff --git a/include/linux/idr.h b/include/linux/idr.h index 762c3f2c631d..fa035f96f2a3 100644 --- a/include/linux/idr.h +++ b/include/linux/idr.h | |||
@@ -79,6 +79,22 @@ struct idr { | |||
79 | 79 | ||
80 | #define _idr_rc_to_errno(rc) ((rc) == -1 ? -EAGAIN : -ENOSPC) | 80 | #define _idr_rc_to_errno(rc) ((rc) == -1 ? -EAGAIN : -ENOSPC) |
81 | 81 | ||
82 | /** | ||
83 | * idr synchronization (stolen from radix-tree.h) | ||
84 | * | ||
85 | * idr_find() is able to be called locklessly, using RCU. The caller must | ||
86 | * ensure calls to this function are made within rcu_read_lock() regions. | ||
87 | * Other readers (lock-free or otherwise) and modifications may be running | ||
88 | * concurrently. | ||
89 | * | ||
90 | * It is still required that the caller manage the synchronization and | ||
91 | * lifetimes of the items. So if RCU lock-free lookups are used, typically | ||
92 | * this would mean that the items have their own locks, or are amenable to | ||
93 | * lock-free access; and that the items are freed by RCU (or only freed after | ||
94 | * having been deleted from the idr tree *and* a synchronize_rcu() grace | ||
95 | * period). | ||
96 | */ | ||
97 | |||
82 | /* | 98 | /* |
83 | * This is what we export. | 99 | * This is what we export. |
84 | */ | 100 | */ |
@@ -456,7 +456,8 @@ EXPORT_SYMBOL(idr_destroy); | |||
456 | * return indicates that @id is not valid or you passed %NULL in | 456 | * return indicates that @id is not valid or you passed %NULL in |
457 | * idr_get_new(). | 457 | * idr_get_new(). |
458 | * | 458 | * |
459 | * The caller must serialize idr_find() vs idr_get_new() and idr_remove(). | 459 | * This function can be called under rcu_read_lock(), given that the leaf |
460 | * pointers lifetimes are correctly managed. | ||
460 | */ | 461 | */ |
461 | void *idr_find(struct idr *idp, int id) | 462 | void *idr_find(struct idr *idp, int id) |
462 | { | 463 | { |
@@ -464,7 +465,7 @@ void *idr_find(struct idr *idp, int id) | |||
464 | struct idr_layer *p; | 465 | struct idr_layer *p; |
465 | 466 | ||
466 | n = idp->layers * IDR_BITS; | 467 | n = idp->layers * IDR_BITS; |
467 | p = idp->top; | 468 | p = rcu_dereference(idp->top); |
468 | 469 | ||
469 | /* Mask off upper bits we don't use for the search. */ | 470 | /* Mask off upper bits we don't use for the search. */ |
470 | id &= MAX_ID_MASK; | 471 | id &= MAX_ID_MASK; |
@@ -474,7 +475,7 @@ void *idr_find(struct idr *idp, int id) | |||
474 | 475 | ||
475 | while (n > 0 && p) { | 476 | while (n > 0 && p) { |
476 | n -= IDR_BITS; | 477 | n -= IDR_BITS; |
477 | p = p->ary[(id >> n) & IDR_MASK]; | 478 | p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); |
478 | } | 479 | } |
479 | return((void *)p); | 480 | return((void *)p); |
480 | } | 481 | } |
@@ -507,7 +508,7 @@ int idr_for_each(struct idr *idp, | |||
507 | struct idr_layer **paa = &pa[0]; | 508 | struct idr_layer **paa = &pa[0]; |
508 | 509 | ||
509 | n = idp->layers * IDR_BITS; | 510 | n = idp->layers * IDR_BITS; |
510 | p = idp->top; | 511 | p = rcu_dereference(idp->top); |
511 | max = 1 << n; | 512 | max = 1 << n; |
512 | 513 | ||
513 | id = 0; | 514 | id = 0; |
@@ -515,7 +516,7 @@ int idr_for_each(struct idr *idp, | |||
515 | while (n > 0 && p) { | 516 | while (n > 0 && p) { |
516 | n -= IDR_BITS; | 517 | n -= IDR_BITS; |
517 | *paa++ = p; | 518 | *paa++ = p; |
518 | p = p->ary[(id >> n) & IDR_MASK]; | 519 | p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); |
519 | } | 520 | } |
520 | 521 | ||
521 | if (p) { | 522 | if (p) { |