From: Andrew Morton Cc: Nick Piggin Signed-off-by: Andrew Morton --- lib/radix-tree.c | 28 ++++++++++++++++++++-------- 1 file changed, 20 insertions(+), 8 deletions(-) diff -puN lib/radix-tree.c~adix-tree-rcu-lockless-readside-update-tidy lib/radix-tree.c --- a/lib/radix-tree.c~adix-tree-rcu-lockless-readside-update-tidy +++ a/lib/radix-tree.c @@ -609,7 +609,7 @@ __lookup(struct radix_tree_node *slot, v shift = (height-1) * RADIX_TREE_MAP_SHIFT; for ( ; height > 1; height--) { - i = (index >> shift) & RADIX_TREE_MAP_MASK ; + i = (index >> shift) & RADIX_TREE_MAP_MASK; for (;;) { if (slot->slots[i] != NULL) break; @@ -738,14 +738,26 @@ __lookup_tag(struct radix_tree_node *slo unsigned long j = index & RADIX_TREE_MAP_MASK; for ( ; j < RADIX_TREE_MAP_SIZE; j++) { + struct radix_tree_node *node; index++; - if (tag_get(slot, tag, j)) { - struct radix_tree_node *node = slot->slots[j]; - if (node) { - results[nr_found++] = rcu_dereference(node); - if (nr_found == max_items) - goto out; - } + if (!tag_get(slot, tag, j)) + continue; + node = slot->slots[j]; + /* + * Even though the tag was found set, we need to + * recheck that we have a non-NULL node, because + * if this lookup is lockless, it may have been + * subsequently deleted. + * + * Similar care must be taken in any place that + * lookup ->slots[x] without a lock (ie. can't + * rely on its value remaining the same). + */ + if (node) { + node = rcu_dereference(node); + results[nr_found++] = node; + if (nr_found == max_items) + goto out; } } } _