aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/idr.h16
-rw-r--r--lib/idr.c11
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 */
diff --git a/lib/idr.c b/lib/idr.c
index 44ab3b2a4eba..21e12af1f231 100644
--- a/lib/idr.c
+++ b/lib/idr.c
@@ -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 */
461void *idr_find(struct idr *idp, int id) 462void *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) {