Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Nadia Derbey and committed by
Linus Torvalds
f9c46d6e 3219b3b7

+22 -5
+16
include/linux/idr.h
··· 79 79 80 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 99 * This is what we export. 84 100 */
+6 -5
lib/idr.c
··· 456 456 * return indicates that @id is not valid or you passed %NULL in 457 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 462 void *idr_find(struct idr *idp, int id) 462 463 { ··· 465 464 struct idr_layer *p; 466 465 467 466 n = idp->layers * IDR_BITS; 468 - p = idp->top; 467 + p = rcu_dereference(idp->top); 469 468 470 469 /* Mask off upper bits we don't use for the search. */ 471 470 id &= MAX_ID_MASK; ··· 475 474 476 475 while (n > 0 && p) { 477 476 n -= IDR_BITS; 478 - p = p->ary[(id >> n) & IDR_MASK]; 477 + p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); 479 478 } 480 479 return((void *)p); 481 480 } ··· 508 507 struct idr_layer **paa = &pa[0]; 509 508 510 509 n = idp->layers * IDR_BITS; 511 - p = idp->top; 510 + p = rcu_dereference(idp->top); 512 511 max = 1 << n; 513 512 514 513 id = 0; ··· 516 515 while (n > 0 && p) { 517 516 n -= IDR_BITS; 518 517 *paa++ = p; 519 - p = p->ary[(id >> n) & IDR_MASK]; 518 + p = rcu_dereference(p->ary[(id >> n) & IDR_MASK]); 520 519 } 521 520 522 521 if (p) {