All of lore.kernel.org
 help / color / mirror / Atom feed
* [patch 16/18] radix-tree: fix race in gang lookup
@ 2016-02-03  0:57 akpm
  0 siblings, 0 replies; only message in thread
From: akpm @ 2016-02-03  0:57 UTC (permalink / raw)
  To: torvalds, akpm, willy, hughd, khlebnikov, ohad, stable

From: Matthew Wilcox <willy@linux.intel.com>
Subject: radix-tree: fix race in gang lookup

If the indirect_ptr bit is set on a slot, that indicates we need to redo
the lookup.  Introduce a new function radix_tree_iter_retry() which forces
the loop to retry the lookup by setting 'slot' to NULL and turning the
iterator back to point at the problematic entry.

This is a pretty rare problem to hit at the moment; the lookup has to race
with a grow of the radix tree from a height of 0.  The consequences of
hitting this race are that gang lookup could return a pointer to a
radix_tree_node instead of a pointer to whatever the user had inserted in
the tree.

Fixes: cebbd29e1c2f ("radix-tree: rewrite gang lookup using iterator")
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
Cc: Hugh Dickins <hughd@google.com>
Cc: Ohad Ben-Cohen <ohad@wizery.com>
Cc: Konstantin Khlebnikov <khlebnikov@openvz.org>
Cc: <stable@vger.kernel.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
---

 include/linux/radix-tree.h |   16 ++++++++++++++++
 lib/radix-tree.c           |   12 ++++++++++--
 2 files changed, 26 insertions(+), 2 deletions(-)

diff -puN include/linux/radix-tree.h~radix-tree-fix-race-in-gang-lookup include/linux/radix-tree.h
--- a/include/linux/radix-tree.h~radix-tree-fix-race-in-gang-lookup
+++ a/include/linux/radix-tree.h
@@ -379,6 +379,22 @@ void **radix_tree_next_chunk(struct radi
 			     struct radix_tree_iter *iter, unsigned flags);
 
 /**
+ * radix_tree_iter_retry - retry this chunk of the iteration
+ * @iter:	iterator state
+ *
+ * If we iterate over a tree protected only by the RCU lock, a race
+ * against deletion or creation may result in seeing a slot for which
+ * radix_tree_deref_retry() returns true.  If so, call this function
+ * and continue the iteration.
+ */
+static inline __must_check
+void **radix_tree_iter_retry(struct radix_tree_iter *iter)
+{
+	iter->next_index = iter->index;
+	return NULL;
+}
+
+/**
  * radix_tree_chunk_size - get current chunk size
  *
  * @iter:	pointer to radix tree iterator
diff -puN lib/radix-tree.c~radix-tree-fix-race-in-gang-lookup lib/radix-tree.c
--- a/lib/radix-tree.c~radix-tree-fix-race-in-gang-lookup
+++ a/lib/radix-tree.c
@@ -1019,9 +1019,13 @@ radix_tree_gang_lookup(struct radix_tree
 		return 0;
 
 	radix_tree_for_each_slot(slot, root, &iter, first_index) {
-		results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot));
+		results[ret] = rcu_dereference_raw(*slot);
 		if (!results[ret])
 			continue;
+		if (radix_tree_is_indirect_ptr(results[ret])) {
+			slot = radix_tree_iter_retry(&iter);
+			continue;
+		}
 		if (++ret == max_items)
 			break;
 	}
@@ -1098,9 +1102,13 @@ radix_tree_gang_lookup_tag(struct radix_
 		return 0;
 
 	radix_tree_for_each_tagged(slot, root, &iter, first_index, tag) {
-		results[ret] = indirect_to_ptr(rcu_dereference_raw(*slot));
+		results[ret] = rcu_dereference_raw(*slot);
 		if (!results[ret])
 			continue;
+		if (radix_tree_is_indirect_ptr(results[ret])) {
+			slot = radix_tree_iter_retry(&iter);
+			continue;
+		}
 		if (++ret == max_items)
 			break;
 	}
_

^ permalink raw reply	[flat|nested] only message in thread

only message in thread, other threads:[~2016-02-03  0:57 UTC | newest]

Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-02-03  0:57 [patch 16/18] radix-tree: fix race in gang lookup akpm

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.