All of lore.kernel.org
 help / color / mirror / Atom feed
From: Matthew Wilcox <mawilcox@linuxonhyperv.com>
To: linux-kernel@vger.kernel.org,
	Andrew Morton <akpm@linux-foundation.org>,
	Konstantin Khlebnikov <koct9i@gmail.com>,
	Ross Zwisler <ross.zwisler@linux.intel.com>
Cc: linux-fsdevel@vger.kernel.org,
	Matthew Wilcox <mawilcox@microsoft.com>,
	linux-mm@kvack.org,
	"Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>,
	Matthew Wilcox <willy@infradead.org>
Subject: [PATCH 22/29] radix-tree: Delete radix_tree_range_tag_if_tagged()
Date: Wed, 16 Nov 2016 16:16:49 -0800	[thread overview]
Message-ID: <1479341856-30320-25-git-send-email-mawilcox@linuxonhyperv.com> (raw)
In-Reply-To: <1479341856-30320-1-git-send-email-mawilcox@linuxonhyperv.com>

From: Matthew Wilcox <mawilcox@microsoft.com>

This is an exceptionally complicated function with just one caller
(tag_pages_for_writeback).  We devote a large portion of the runtime
of the test suite to testing this one function which has one caller.
By introducing the new function radix_tree_iter_tag_set(), we
can eliminate all of the complexity while keeping the performance.
The caller can now use a fairly standard radix_tree_for_each() loop,
and it doesn't need to worry about tricksy things like 'start' wrapping.

The test suite continues to spend a large amount of time investigating
this function, but now it's testing the underlying primitives such as
radix_tree_iter_next() and the radix_tree_for_each_tagged() iterator
which are also used by other parts of the kernel.

Signed-off-by: Matthew Wilcox <willy@infradead.org>
---
 include/linux/radix-tree.h             |  74 ++++++++++-----------
 lib/radix-tree.c                       | 114 +++++----------------------------
 mm/page-writeback.c                    |  28 +++++---
 tools/testing/radix-tree/main.c        |  12 ++--
 tools/testing/radix-tree/multiorder.c  |  13 ++--
 tools/testing/radix-tree/regression2.c |   3 +-
 tools/testing/radix-tree/tag_check.c   |   4 +-
 tools/testing/radix-tree/test.c        |  25 ++++++++
 tools/testing/radix-tree/test.h        |   3 +
 9 files changed, 113 insertions(+), 163 deletions(-)

diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 57bf635..ca4eea1 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -124,6 +124,41 @@ static inline bool radix_tree_empty(struct radix_tree_root *root)
 }
 
 /**
+ * struct radix_tree_iter - radix tree iterator state
+ *
+ * @index:	index of current slot
+ * @next_index:	one beyond the last index for this chunk
+ * @tags:	bit-mask for tag-iterating
+ * @node:	node that contains current slot
+ * @shift:	shift for the node that holds our slots
+ *
+ * This radix tree iterator works in terms of "chunks" of slots.  A chunk is a
+ * subinterval of slots contained within one radix tree leaf node.  It is
+ * described by a pointer to its first slot and a struct radix_tree_iter
+ * which holds the chunk's position in the tree and its size.  For tagged
+ * iteration radix_tree_iter also holds the slots' bit-mask for one chosen
+ * radix tree tag.
+ */
+struct radix_tree_iter {
+	unsigned long	index;
+	unsigned long	next_index;
+	unsigned long	tags;
+	struct radix_tree_node *node;
+#ifdef CONFIG_RADIX_TREE_MULTIORDER
+	unsigned int	shift;
+#endif
+};
+
+static inline unsigned int iter_shift(struct radix_tree_iter *iter)
+{
+#ifdef CONFIG_RADIX_TREE_MULTIORDER
+	return iter->shift;
+#else
+	return 0;
+#endif
+}
+
+/**
  * Radix-tree synchronization
  *
  * The radix-tree API requires that users provide all synchronisation (with
@@ -293,6 +328,8 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
 			unsigned long index, unsigned int tag);
 int radix_tree_tag_get(struct radix_tree_root *root,
 			unsigned long index, unsigned int tag);
+void radix_tree_iter_tag_set(struct radix_tree_root *root,
+		const struct radix_tree_iter *iter, unsigned int tag);
 unsigned int
 radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
 		unsigned long first_index, unsigned int max_items,
@@ -301,10 +338,6 @@ unsigned int
 radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
 		unsigned long first_index, unsigned int max_items,
 		unsigned int tag);
-unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
-		unsigned long *first_indexp, unsigned long last_index,
-		unsigned long nr_to_tag,
-		unsigned int fromtag, unsigned int totag);
 int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);
 
 static inline void radix_tree_preload_end(void)
@@ -318,39 +351,6 @@ int radix_tree_split(struct radix_tree_root *, unsigned long index,
 int radix_tree_join(struct radix_tree_root *, unsigned long index,
 			unsigned new_order, void *);
 
-/**
- * struct radix_tree_iter - radix tree iterator state
- *
- * @index:	index of current slot
- * @next_index:	one beyond the last index for this chunk
- * @tags:	bit-mask for tag-iterating
- * @shift:	shift for the node that holds our slots
- *
- * This radix tree iterator works in terms of "chunks" of slots.  A chunk is a
- * subinterval of slots contained within one radix tree leaf node.  It is
- * described by a pointer to its first slot and a struct radix_tree_iter
- * which holds the chunk's position in the tree and its size.  For tagged
- * iteration radix_tree_iter also holds the slots' bit-mask for one chosen
- * radix tree tag.
- */
-struct radix_tree_iter {
-	unsigned long	index;
-	unsigned long	next_index;
-	unsigned long	tags;
-#ifdef CONFIG_RADIX_TREE_MULTIORDER
-	unsigned int	shift;
-#endif
-};
-
-static inline unsigned int iter_shift(struct radix_tree_iter *iter)
-{
-#ifdef CONFIG_RADIX_TREE_MULTIORDER
-	return iter->shift;
-#else
-	return 0;
-#endif
-}
-
 #define RADIX_TREE_ITER_TAG_MASK	0x00FF	/* tag index in lower byte */
 #define RADIX_TREE_ITER_TAGGED		0x0100	/* lookup tagged slots */
 #define RADIX_TREE_ITER_CONTIG		0x0200	/* stop at first hole */
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 7e70ac9..c8ef657 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1049,6 +1049,20 @@ static void node_tag_set(struct radix_tree_root *root,
 }
 
 /**
+ * radix_tree_iter_tag_set - set a tag on the current iterator entry
+ *
+ * @root:	radix tree root
+ * @iter:	iterator state
+ * @tag:	tag to set
+ */
+void radix_tree_iter_tag_set(struct radix_tree_root *root,
+			const struct radix_tree_iter *iter, unsigned int tag)
+{
+	unsigned offset = (iter->index >> iter->shift) & RADIX_TREE_MAP_MASK;
+	node_tag_set(root, iter->node, tag, offset);
+}
+
+/**
  *	radix_tree_tag_clear - clear a tag on a radix tree node
  *	@root:		radix tree root
  *	@index:		index key
@@ -1176,6 +1190,7 @@ void ** __radix_tree_next_slot(void **slot, struct radix_tree_iter *iter,
 		if (node == RADIX_TREE_RETRY)
 			return slot;
 		node = entry_to_node(node);
+		iter->node = node;
 
 		if (flags & RADIX_TREE_ITER_TAGGED) {
 			unsigned tag_long, tag_bit;
@@ -1275,6 +1290,7 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
 		iter->index = index;
 		iter->next_index = maxindex + 1;
 		iter->tags = 1;
+		iter->node = NULL;
 		__set_iter_shift(iter, 0);
 		return (void **)&root->rnode;
 	}
@@ -1319,6 +1335,7 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
 	/* Update the iterator state */
 	iter->index = (index &~ node_maxindex(node)) | (offset << node->shift);
 	iter->next_index = (index | node_maxindex(node)) + 1;
+	iter->node = node;
 	__set_iter_shift(iter, node->shift);
 
 	/* Construct iter->tags bit-mask from node->tags[tag] array */
@@ -1344,103 +1361,6 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
 EXPORT_SYMBOL(radix_tree_next_chunk);
 
 /**
- * radix_tree_range_tag_if_tagged - for each item in given range set given
- *				   tag if item has another tag set
- * @root:		radix tree root
- * @first_indexp:	pointer to a starting index of a range to scan
- * @last_index:		last index of a range to scan
- * @nr_to_tag:		maximum number items to tag
- * @iftag:		tag index to test
- * @settag:		tag index to set if tested tag is set
- *
- * This function scans range of radix tree from first_index to last_index
- * (inclusive).  For each item in the range if iftag is set, the function sets
- * also settag. The function stops either after tagging nr_to_tag items or
- * after reaching last_index.
- *
- * The tags must be set from the leaf level only and propagated back up the
- * path to the root. We must do this so that we resolve the full path before
- * setting any tags on intermediate nodes. If we set tags as we descend, then
- * we can get to the leaf node and find that the index that has the iftag
- * set is outside the range we are scanning. This reults in dangling tags and
- * can lead to problems with later tag operations (e.g. livelocks on lookups).
- *
- * The function returns the number of leaves where the tag was set and sets
- * *first_indexp to the first unscanned index.
- * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must
- * be prepared to handle that.
- */
-unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
-		unsigned long *first_indexp, unsigned long last_index,
-		unsigned long nr_to_tag,
-		unsigned int iftag, unsigned int settag)
-{
-	struct radix_tree_node *node, *child;
-	unsigned long maxindex;
-	unsigned long tagged = 0;
-	unsigned long index = *first_indexp;
-
-	radix_tree_load_root(root, &child, &maxindex);
-	last_index = min(last_index, maxindex);
-	if (index > last_index)
-		return 0;
-	if (!nr_to_tag)
-		return 0;
-	if (!root_tag_get(root, iftag)) {
-		*first_indexp = last_index + 1;
-		return 0;
-	}
-	if (!radix_tree_is_internal_node(child)) {
-		*first_indexp = last_index + 1;
-		root_tag_set(root, settag);
-		return 1;
-	}
-
-	node = entry_to_node(child);
-
-	for (;;) {
-		unsigned offset = radix_tree_descend(node, &child, index);
-		if (!child)
-			goto next;
-		if (!tag_get(node, iftag, offset))
-			goto next;
-		/* Sibling slots never have tags set on them */
-		if (radix_tree_is_internal_node(child)) {
-			node = entry_to_node(child);
-			continue;
-		}
-
-		tagged++;
-		node_tag_set(root, node, settag, offset);
- next:
-		/* Go to next entry in node */
-		index = ((index >> node->shift) + 1) << node->shift;
-		/* Overflow can happen when last_index is ~0UL... */
-		if (index > last_index || !index)
-			break;
-		offset = (index >> node->shift) & RADIX_TREE_MAP_MASK;
-		while (offset == 0) {
-			/*
-			 * We've fully scanned this node. Go up. Because
-			 * last_index is guaranteed to be in the tree, what
-			 * we do below cannot wander astray.
-			 */
-			node = node->parent;
-			offset = (index >> node->shift) & RADIX_TREE_MAP_MASK;
-		}
-		if (is_sibling_entry(node, node->slots[offset]))
-			goto next;
-		if (tagged >= nr_to_tag)
-			break;
-	}
-
-	*first_indexp = index;
-
-	return tagged;
-}
-EXPORT_SYMBOL(radix_tree_range_tag_if_tagged);
-
-/**
  *	radix_tree_gang_lookup - perform multiple lookup on a radix tree
  *	@root:		radix tree root
  *	@results:	where the results of the lookup are placed
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 439cc63..c593715 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2105,18 +2105,26 @@ void tag_pages_for_writeback(struct address_space *mapping,
 			     pgoff_t start, pgoff_t end)
 {
 #define WRITEBACK_TAG_BATCH 4096
-	unsigned long tagged;
-
-	do {
-		spin_lock_irq(&mapping->tree_lock);
-		tagged = radix_tree_range_tag_if_tagged(&mapping->page_tree,
-				&start, end, WRITEBACK_TAG_BATCH,
-				PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE);
+	unsigned long tagged = 0;
+	struct radix_tree_iter iter;
+	void **slot;
+
+	spin_lock_irq(&mapping->tree_lock);
+	radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter, start,
+							PAGECACHE_TAG_DIRTY) {
+		if (iter.index > end)
+			break;
+		radix_tree_iter_tag_set(&mapping->page_tree, &iter,
+							PAGECACHE_TAG_TOWRITE);
+		tagged++;
+		if ((tagged % WRITEBACK_TAG_BATCH) != 0)
+			continue;
+		slot = radix_tree_iter_next(slot, &iter);
 		spin_unlock_irq(&mapping->tree_lock);
-		WARN_ON_ONCE(tagged > WRITEBACK_TAG_BATCH);
 		cond_resched();
-		/* We check 'start' to handle wrapping when end == ~0UL */
-	} while (tagged >= WRITEBACK_TAG_BATCH && start);
+		spin_lock_irq(&mapping->tree_lock);
+	}
+	spin_unlock_irq(&mapping->tree_lock);
 }
 EXPORT_SYMBOL(tag_pages_for_writeback);
 
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c
index 93a77f9..7d14812 100644
--- a/tools/testing/radix-tree/main.c
+++ b/tools/testing/radix-tree/main.c
@@ -205,8 +205,7 @@ void copy_tag_check(void)
 	}
 
 //	printf("\ncopying tags...\n");
-	cur = start;
-	tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, ITEMS, 0, 1);
+	tagged = tag_tagged_items(&tree, start, end, ITEMS, 0, 1);
 
 //	printf("checking copied tags\n");
 	assert(tagged == count);
@@ -214,16 +213,13 @@ void copy_tag_check(void)
 
 	/* Copy tags in several rounds */
 //	printf("\ncopying tags...\n");
-	cur = start;
-	do {
-		tmp = rand() % (count/10+2);
-		tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, tmp, 0, 2);
-	} while (tmp == tagged);
+	tmp = rand() % (count / 10 + 2);
+	tagged = tag_tagged_items(&tree, start, end, tmp, 0, 2);
+	assert(tagged == count);
 
 //	printf("%lu %lu %lu\n", tagged, tmp, count);
 //	printf("checking copied tags\n");
 	check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2);
-	assert(tagged < tmp);
 	verify_tag_consistency(&tree, 0);
 	verify_tag_consistency(&tree, 1);
 	verify_tag_consistency(&tree, 2);
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c
index 400de5c..6a0287d 100644
--- a/tools/testing/radix-tree/multiorder.c
+++ b/tools/testing/radix-tree/multiorder.c
@@ -26,7 +26,6 @@ static void __multiorder_tag_test(int index, int order)
 {
 	RADIX_TREE(tree, GFP_KERNEL);
 	int base, err, i;
-	unsigned long first = 0;
 
 	/* our canonical entry */
 	base = index & ~((1 << order) - 1);
@@ -60,7 +59,7 @@ static void __multiorder_tag_test(int index, int order)
 		assert(!radix_tree_tag_get(&tree, i, 1));
 	}
 
-	assert(radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, 10, 0, 1) == 1);
+	assert(tag_tagged_items(&tree, 0, ~0UL, 10, 0, 1) == 1);
 	assert(radix_tree_tag_clear(&tree, index, 0));
 
 	for_each_index(i, base, order) {
@@ -252,7 +251,6 @@ void multiorder_tagged_iteration(void)
 	RADIX_TREE(tree, GFP_KERNEL);
 	struct radix_tree_iter iter;
 	void **slot;
-	unsigned long first = 0;
 	int i, j;
 
 	printf("Multiorder tagged iteration test\n");
@@ -297,8 +295,8 @@ void multiorder_tagged_iteration(void)
 		}
 	}
 
-	radix_tree_range_tag_if_tagged(&tree, &first, ~0UL,
-					MT_NUM_ENTRIES, 1, 2);
+	assert(tag_tagged_items(&tree, 0, ~0UL, TAG_ENTRIES, 1, 2) ==
+				TAG_ENTRIES);
 
 	for (j = 0; j < 256; j++) {
 		int mask, k;
@@ -325,9 +323,8 @@ void multiorder_tagged_iteration(void)
 		}
 	}
 
-	first = 1;
-	radix_tree_range_tag_if_tagged(&tree, &first, ~0UL,
-					MT_NUM_ENTRIES, 1, 0);
+	assert(tag_tagged_items(&tree, 1, ~0UL, MT_NUM_ENTRIES * 2, 1, 0)
+			== TAG_ENTRIES);
 	i = 0;
 	radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) {
 		assert(iter.index == tag_index[i]);
diff --git a/tools/testing/radix-tree/regression2.c b/tools/testing/radix-tree/regression2.c
index 63bf347..5cd2c0f 100644
--- a/tools/testing/radix-tree/regression2.c
+++ b/tools/testing/radix-tree/regression2.c
@@ -50,6 +50,7 @@
 #include <stdio.h>
 
 #include "regression.h"
+#include "test.h"
 
 #define PAGECACHE_TAG_DIRTY     0
 #define PAGECACHE_TAG_WRITEBACK 1
@@ -90,7 +91,7 @@ void regression2_test(void)
 	/* 1. */
 	start = 0;
 	end = max_slots - 2;
-	radix_tree_range_tag_if_tagged(&mt_tree, &start, end, 1,
+	tag_tagged_items(&mt_tree, start, end, 1,
 				PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE);
 
 	/* 2. */
diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c
index 186f6e4..b047b2d 100644
--- a/tools/testing/radix-tree/tag_check.c
+++ b/tools/testing/radix-tree/tag_check.c
@@ -23,7 +23,7 @@ __simple_checks(struct radix_tree_root *tree, unsigned long index, int tag)
 	item_tag_set(tree, index, tag);
 	ret = item_tag_get(tree, index, tag);
 	assert(ret != 0);
-	ret = radix_tree_range_tag_if_tagged(tree, &first, ~0UL, 10, tag, !tag);
+	ret = tag_tagged_items(tree, first, ~0UL, 10, tag, !tag);
 	assert(ret == 1);
 	ret = item_tag_get(tree, index, !tag);
 	assert(ret != 0);
@@ -320,7 +320,7 @@ static void single_check(void)
 	assert(ret == 0);
 	verify_tag_consistency(&tree, 0);
 	verify_tag_consistency(&tree, 1);
-	ret = radix_tree_range_tag_if_tagged(&tree, &first, 10, 10, 0, 1);
+	ret = tag_tagged_items(&tree, first, 10, 10, 0, 1);
 	assert(ret == 1);
 	ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1);
 	assert(ret == 1);
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c
index a68ed3b..322c34b 100644
--- a/tools/testing/radix-tree/test.c
+++ b/tools/testing/radix-tree/test.c
@@ -142,6 +142,31 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start,
 	assert(nfound == 0);
 }
 
+/* Use the same pattern as tag_pages_for_writeback() in mm/page-writeback.c */
+int tag_tagged_items(struct radix_tree_root *root,
+			unsigned long start, unsigned long end, unsigned batch,
+			unsigned iftag, unsigned thentag)
+{
+	unsigned long tagged = 0;
+	struct radix_tree_iter iter;
+	void **slot;
+
+	if (batch == 0)
+		batch = 1;
+
+	radix_tree_for_each_tagged(slot, root, &iter, start, iftag) {
+		if (iter.index > end)
+			break;
+		radix_tree_iter_tag_set(root, &iter, thentag);
+		tagged++;
+		if ((tagged % batch) != 0)
+			continue;
+		slot = radix_tree_iter_next(slot, &iter);
+	}
+
+	return tagged;
+}
+
 /* Use the same pattern as find_swap_entry() in mm/shmem.c */
 unsigned long find_item(struct radix_tree_root *root, void *item)
 {
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h
index ccdd3c1..1faf0a3 100644
--- a/tools/testing/radix-tree/test.h
+++ b/tools/testing/radix-tree/test.h
@@ -27,6 +27,9 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start,
 			unsigned long nr, int chunk);
 void item_kill_tree(struct radix_tree_root *root);
 
+int tag_tagged_items(struct radix_tree_root *, unsigned long start,
+			unsigned long end, unsigned batch,
+			unsigned iftag, unsigned thentag);
 unsigned long find_item(struct radix_tree_root *, void *item);
 
 void tag_check(void);
-- 
2.10.2

WARNING: multiple messages have this Message-ID (diff)
From: Matthew Wilcox <mawilcox@linuxonhyperv.com>
To: linux-kernel@vger.kernel.org,
	Andrew Morton <akpm@linux-foundation.org>,
	Konstantin Khlebnikov <koct9i@gmail.com>,
	Ross Zwisler <ross.zwisler@linux.intel.com>
Cc: linux-fsdevel@vger.kernel.org,
	Matthew Wilcox <mawilcox@microsoft.com>,
	linux-mm@kvack.org,
	"Kirill A . Shutemov" <kirill.shutemov@linux.intel.com>,
	Matthew Wilcox <willy@infradead.org>
Subject: [PATCH 22/29] radix-tree: Delete radix_tree_range_tag_if_tagged()
Date: Wed, 16 Nov 2016 16:16:49 -0800	[thread overview]
Message-ID: <1479341856-30320-25-git-send-email-mawilcox@linuxonhyperv.com> (raw)
In-Reply-To: <1479341856-30320-1-git-send-email-mawilcox@linuxonhyperv.com>

From: Matthew Wilcox <mawilcox@microsoft.com>

This is an exceptionally complicated function with just one caller
(tag_pages_for_writeback).  We devote a large portion of the runtime
of the test suite to testing this one function which has one caller.
By introducing the new function radix_tree_iter_tag_set(), we
can eliminate all of the complexity while keeping the performance.
The caller can now use a fairly standard radix_tree_for_each() loop,
and it doesn't need to worry about tricksy things like 'start' wrapping.

The test suite continues to spend a large amount of time investigating
this function, but now it's testing the underlying primitives such as
radix_tree_iter_next() and the radix_tree_for_each_tagged() iterator
which are also used by other parts of the kernel.

Signed-off-by: Matthew Wilcox <willy@infradead.org>
---
 include/linux/radix-tree.h             |  74 ++++++++++-----------
 lib/radix-tree.c                       | 114 +++++----------------------------
 mm/page-writeback.c                    |  28 +++++---
 tools/testing/radix-tree/main.c        |  12 ++--
 tools/testing/radix-tree/multiorder.c  |  13 ++--
 tools/testing/radix-tree/regression2.c |   3 +-
 tools/testing/radix-tree/tag_check.c   |   4 +-
 tools/testing/radix-tree/test.c        |  25 ++++++++
 tools/testing/radix-tree/test.h        |   3 +
 9 files changed, 113 insertions(+), 163 deletions(-)

diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 57bf635..ca4eea1 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -124,6 +124,41 @@ static inline bool radix_tree_empty(struct radix_tree_root *root)
 }
 
 /**
+ * struct radix_tree_iter - radix tree iterator state
+ *
+ * @index:	index of current slot
+ * @next_index:	one beyond the last index for this chunk
+ * @tags:	bit-mask for tag-iterating
+ * @node:	node that contains current slot
+ * @shift:	shift for the node that holds our slots
+ *
+ * This radix tree iterator works in terms of "chunks" of slots.  A chunk is a
+ * subinterval of slots contained within one radix tree leaf node.  It is
+ * described by a pointer to its first slot and a struct radix_tree_iter
+ * which holds the chunk's position in the tree and its size.  For tagged
+ * iteration radix_tree_iter also holds the slots' bit-mask for one chosen
+ * radix tree tag.
+ */
+struct radix_tree_iter {
+	unsigned long	index;
+	unsigned long	next_index;
+	unsigned long	tags;
+	struct radix_tree_node *node;
+#ifdef CONFIG_RADIX_TREE_MULTIORDER
+	unsigned int	shift;
+#endif
+};
+
+static inline unsigned int iter_shift(struct radix_tree_iter *iter)
+{
+#ifdef CONFIG_RADIX_TREE_MULTIORDER
+	return iter->shift;
+#else
+	return 0;
+#endif
+}
+
+/**
  * Radix-tree synchronization
  *
  * The radix-tree API requires that users provide all synchronisation (with
@@ -293,6 +328,8 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
 			unsigned long index, unsigned int tag);
 int radix_tree_tag_get(struct radix_tree_root *root,
 			unsigned long index, unsigned int tag);
+void radix_tree_iter_tag_set(struct radix_tree_root *root,
+		const struct radix_tree_iter *iter, unsigned int tag);
 unsigned int
 radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results,
 		unsigned long first_index, unsigned int max_items,
@@ -301,10 +338,6 @@ unsigned int
 radix_tree_gang_lookup_tag_slot(struct radix_tree_root *root, void ***results,
 		unsigned long first_index, unsigned int max_items,
 		unsigned int tag);
-unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
-		unsigned long *first_indexp, unsigned long last_index,
-		unsigned long nr_to_tag,
-		unsigned int fromtag, unsigned int totag);
 int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag);
 
 static inline void radix_tree_preload_end(void)
@@ -318,39 +351,6 @@ int radix_tree_split(struct radix_tree_root *, unsigned long index,
 int radix_tree_join(struct radix_tree_root *, unsigned long index,
 			unsigned new_order, void *);
 
-/**
- * struct radix_tree_iter - radix tree iterator state
- *
- * @index:	index of current slot
- * @next_index:	one beyond the last index for this chunk
- * @tags:	bit-mask for tag-iterating
- * @shift:	shift for the node that holds our slots
- *
- * This radix tree iterator works in terms of "chunks" of slots.  A chunk is a
- * subinterval of slots contained within one radix tree leaf node.  It is
- * described by a pointer to its first slot and a struct radix_tree_iter
- * which holds the chunk's position in the tree and its size.  For tagged
- * iteration radix_tree_iter also holds the slots' bit-mask for one chosen
- * radix tree tag.
- */
-struct radix_tree_iter {
-	unsigned long	index;
-	unsigned long	next_index;
-	unsigned long	tags;
-#ifdef CONFIG_RADIX_TREE_MULTIORDER
-	unsigned int	shift;
-#endif
-};
-
-static inline unsigned int iter_shift(struct radix_tree_iter *iter)
-{
-#ifdef CONFIG_RADIX_TREE_MULTIORDER
-	return iter->shift;
-#else
-	return 0;
-#endif
-}
-
 #define RADIX_TREE_ITER_TAG_MASK	0x00FF	/* tag index in lower byte */
 #define RADIX_TREE_ITER_TAGGED		0x0100	/* lookup tagged slots */
 #define RADIX_TREE_ITER_CONTIG		0x0200	/* stop at first hole */
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 7e70ac9..c8ef657 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1049,6 +1049,20 @@ static void node_tag_set(struct radix_tree_root *root,
 }
 
 /**
+ * radix_tree_iter_tag_set - set a tag on the current iterator entry
+ *
+ * @root:	radix tree root
+ * @iter:	iterator state
+ * @tag:	tag to set
+ */
+void radix_tree_iter_tag_set(struct radix_tree_root *root,
+			const struct radix_tree_iter *iter, unsigned int tag)
+{
+	unsigned offset = (iter->index >> iter->shift) & RADIX_TREE_MAP_MASK;
+	node_tag_set(root, iter->node, tag, offset);
+}
+
+/**
  *	radix_tree_tag_clear - clear a tag on a radix tree node
  *	@root:		radix tree root
  *	@index:		index key
@@ -1176,6 +1190,7 @@ void ** __radix_tree_next_slot(void **slot, struct radix_tree_iter *iter,
 		if (node == RADIX_TREE_RETRY)
 			return slot;
 		node = entry_to_node(node);
+		iter->node = node;
 
 		if (flags & RADIX_TREE_ITER_TAGGED) {
 			unsigned tag_long, tag_bit;
@@ -1275,6 +1290,7 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
 		iter->index = index;
 		iter->next_index = maxindex + 1;
 		iter->tags = 1;
+		iter->node = NULL;
 		__set_iter_shift(iter, 0);
 		return (void **)&root->rnode;
 	}
@@ -1319,6 +1335,7 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
 	/* Update the iterator state */
 	iter->index = (index &~ node_maxindex(node)) | (offset << node->shift);
 	iter->next_index = (index | node_maxindex(node)) + 1;
+	iter->node = node;
 	__set_iter_shift(iter, node->shift);
 
 	/* Construct iter->tags bit-mask from node->tags[tag] array */
@@ -1344,103 +1361,6 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
 EXPORT_SYMBOL(radix_tree_next_chunk);
 
 /**
- * radix_tree_range_tag_if_tagged - for each item in given range set given
- *				   tag if item has another tag set
- * @root:		radix tree root
- * @first_indexp:	pointer to a starting index of a range to scan
- * @last_index:		last index of a range to scan
- * @nr_to_tag:		maximum number items to tag
- * @iftag:		tag index to test
- * @settag:		tag index to set if tested tag is set
- *
- * This function scans range of radix tree from first_index to last_index
- * (inclusive).  For each item in the range if iftag is set, the function sets
- * also settag. The function stops either after tagging nr_to_tag items or
- * after reaching last_index.
- *
- * The tags must be set from the leaf level only and propagated back up the
- * path to the root. We must do this so that we resolve the full path before
- * setting any tags on intermediate nodes. If we set tags as we descend, then
- * we can get to the leaf node and find that the index that has the iftag
- * set is outside the range we are scanning. This reults in dangling tags and
- * can lead to problems with later tag operations (e.g. livelocks on lookups).
- *
- * The function returns the number of leaves where the tag was set and sets
- * *first_indexp to the first unscanned index.
- * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must
- * be prepared to handle that.
- */
-unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
-		unsigned long *first_indexp, unsigned long last_index,
-		unsigned long nr_to_tag,
-		unsigned int iftag, unsigned int settag)
-{
-	struct radix_tree_node *node, *child;
-	unsigned long maxindex;
-	unsigned long tagged = 0;
-	unsigned long index = *first_indexp;
-
-	radix_tree_load_root(root, &child, &maxindex);
-	last_index = min(last_index, maxindex);
-	if (index > last_index)
-		return 0;
-	if (!nr_to_tag)
-		return 0;
-	if (!root_tag_get(root, iftag)) {
-		*first_indexp = last_index + 1;
-		return 0;
-	}
-	if (!radix_tree_is_internal_node(child)) {
-		*first_indexp = last_index + 1;
-		root_tag_set(root, settag);
-		return 1;
-	}
-
-	node = entry_to_node(child);
-
-	for (;;) {
-		unsigned offset = radix_tree_descend(node, &child, index);
-		if (!child)
-			goto next;
-		if (!tag_get(node, iftag, offset))
-			goto next;
-		/* Sibling slots never have tags set on them */
-		if (radix_tree_is_internal_node(child)) {
-			node = entry_to_node(child);
-			continue;
-		}
-
-		tagged++;
-		node_tag_set(root, node, settag, offset);
- next:
-		/* Go to next entry in node */
-		index = ((index >> node->shift) + 1) << node->shift;
-		/* Overflow can happen when last_index is ~0UL... */
-		if (index > last_index || !index)
-			break;
-		offset = (index >> node->shift) & RADIX_TREE_MAP_MASK;
-		while (offset == 0) {
-			/*
-			 * We've fully scanned this node. Go up. Because
-			 * last_index is guaranteed to be in the tree, what
-			 * we do below cannot wander astray.
-			 */
-			node = node->parent;
-			offset = (index >> node->shift) & RADIX_TREE_MAP_MASK;
-		}
-		if (is_sibling_entry(node, node->slots[offset]))
-			goto next;
-		if (tagged >= nr_to_tag)
-			break;
-	}
-
-	*first_indexp = index;
-
-	return tagged;
-}
-EXPORT_SYMBOL(radix_tree_range_tag_if_tagged);
-
-/**
  *	radix_tree_gang_lookup - perform multiple lookup on a radix tree
  *	@root:		radix tree root
  *	@results:	where the results of the lookup are placed
diff --git a/mm/page-writeback.c b/mm/page-writeback.c
index 439cc63..c593715 100644
--- a/mm/page-writeback.c
+++ b/mm/page-writeback.c
@@ -2105,18 +2105,26 @@ void tag_pages_for_writeback(struct address_space *mapping,
 			     pgoff_t start, pgoff_t end)
 {
 #define WRITEBACK_TAG_BATCH 4096
-	unsigned long tagged;
-
-	do {
-		spin_lock_irq(&mapping->tree_lock);
-		tagged = radix_tree_range_tag_if_tagged(&mapping->page_tree,
-				&start, end, WRITEBACK_TAG_BATCH,
-				PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE);
+	unsigned long tagged = 0;
+	struct radix_tree_iter iter;
+	void **slot;
+
+	spin_lock_irq(&mapping->tree_lock);
+	radix_tree_for_each_tagged(slot, &mapping->page_tree, &iter, start,
+							PAGECACHE_TAG_DIRTY) {
+		if (iter.index > end)
+			break;
+		radix_tree_iter_tag_set(&mapping->page_tree, &iter,
+							PAGECACHE_TAG_TOWRITE);
+		tagged++;
+		if ((tagged % WRITEBACK_TAG_BATCH) != 0)
+			continue;
+		slot = radix_tree_iter_next(slot, &iter);
 		spin_unlock_irq(&mapping->tree_lock);
-		WARN_ON_ONCE(tagged > WRITEBACK_TAG_BATCH);
 		cond_resched();
-		/* We check 'start' to handle wrapping when end == ~0UL */
-	} while (tagged >= WRITEBACK_TAG_BATCH && start);
+		spin_lock_irq(&mapping->tree_lock);
+	}
+	spin_unlock_irq(&mapping->tree_lock);
 }
 EXPORT_SYMBOL(tag_pages_for_writeback);
 
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c
index 93a77f9..7d14812 100644
--- a/tools/testing/radix-tree/main.c
+++ b/tools/testing/radix-tree/main.c
@@ -205,8 +205,7 @@ void copy_tag_check(void)
 	}
 
 //	printf("\ncopying tags...\n");
-	cur = start;
-	tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, ITEMS, 0, 1);
+	tagged = tag_tagged_items(&tree, start, end, ITEMS, 0, 1);
 
 //	printf("checking copied tags\n");
 	assert(tagged == count);
@@ -214,16 +213,13 @@ void copy_tag_check(void)
 
 	/* Copy tags in several rounds */
 //	printf("\ncopying tags...\n");
-	cur = start;
-	do {
-		tmp = rand() % (count/10+2);
-		tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, tmp, 0, 2);
-	} while (tmp == tagged);
+	tmp = rand() % (count / 10 + 2);
+	tagged = tag_tagged_items(&tree, start, end, tmp, 0, 2);
+	assert(tagged == count);
 
 //	printf("%lu %lu %lu\n", tagged, tmp, count);
 //	printf("checking copied tags\n");
 	check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2);
-	assert(tagged < tmp);
 	verify_tag_consistency(&tree, 0);
 	verify_tag_consistency(&tree, 1);
 	verify_tag_consistency(&tree, 2);
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c
index 400de5c..6a0287d 100644
--- a/tools/testing/radix-tree/multiorder.c
+++ b/tools/testing/radix-tree/multiorder.c
@@ -26,7 +26,6 @@ static void __multiorder_tag_test(int index, int order)
 {
 	RADIX_TREE(tree, GFP_KERNEL);
 	int base, err, i;
-	unsigned long first = 0;
 
 	/* our canonical entry */
 	base = index & ~((1 << order) - 1);
@@ -60,7 +59,7 @@ static void __multiorder_tag_test(int index, int order)
 		assert(!radix_tree_tag_get(&tree, i, 1));
 	}
 
-	assert(radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, 10, 0, 1) == 1);
+	assert(tag_tagged_items(&tree, 0, ~0UL, 10, 0, 1) == 1);
 	assert(radix_tree_tag_clear(&tree, index, 0));
 
 	for_each_index(i, base, order) {
@@ -252,7 +251,6 @@ void multiorder_tagged_iteration(void)
 	RADIX_TREE(tree, GFP_KERNEL);
 	struct radix_tree_iter iter;
 	void **slot;
-	unsigned long first = 0;
 	int i, j;
 
 	printf("Multiorder tagged iteration test\n");
@@ -297,8 +295,8 @@ void multiorder_tagged_iteration(void)
 		}
 	}
 
-	radix_tree_range_tag_if_tagged(&tree, &first, ~0UL,
-					MT_NUM_ENTRIES, 1, 2);
+	assert(tag_tagged_items(&tree, 0, ~0UL, TAG_ENTRIES, 1, 2) ==
+				TAG_ENTRIES);
 
 	for (j = 0; j < 256; j++) {
 		int mask, k;
@@ -325,9 +323,8 @@ void multiorder_tagged_iteration(void)
 		}
 	}
 
-	first = 1;
-	radix_tree_range_tag_if_tagged(&tree, &first, ~0UL,
-					MT_NUM_ENTRIES, 1, 0);
+	assert(tag_tagged_items(&tree, 1, ~0UL, MT_NUM_ENTRIES * 2, 1, 0)
+			== TAG_ENTRIES);
 	i = 0;
 	radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) {
 		assert(iter.index == tag_index[i]);
diff --git a/tools/testing/radix-tree/regression2.c b/tools/testing/radix-tree/regression2.c
index 63bf347..5cd2c0f 100644
--- a/tools/testing/radix-tree/regression2.c
+++ b/tools/testing/radix-tree/regression2.c
@@ -50,6 +50,7 @@
 #include <stdio.h>
 
 #include "regression.h"
+#include "test.h"
 
 #define PAGECACHE_TAG_DIRTY     0
 #define PAGECACHE_TAG_WRITEBACK 1
@@ -90,7 +91,7 @@ void regression2_test(void)
 	/* 1. */
 	start = 0;
 	end = max_slots - 2;
-	radix_tree_range_tag_if_tagged(&mt_tree, &start, end, 1,
+	tag_tagged_items(&mt_tree, start, end, 1,
 				PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE);
 
 	/* 2. */
diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c
index 186f6e4..b047b2d 100644
--- a/tools/testing/radix-tree/tag_check.c
+++ b/tools/testing/radix-tree/tag_check.c
@@ -23,7 +23,7 @@ __simple_checks(struct radix_tree_root *tree, unsigned long index, int tag)
 	item_tag_set(tree, index, tag);
 	ret = item_tag_get(tree, index, tag);
 	assert(ret != 0);
-	ret = radix_tree_range_tag_if_tagged(tree, &first, ~0UL, 10, tag, !tag);
+	ret = tag_tagged_items(tree, first, ~0UL, 10, tag, !tag);
 	assert(ret == 1);
 	ret = item_tag_get(tree, index, !tag);
 	assert(ret != 0);
@@ -320,7 +320,7 @@ static void single_check(void)
 	assert(ret == 0);
 	verify_tag_consistency(&tree, 0);
 	verify_tag_consistency(&tree, 1);
-	ret = radix_tree_range_tag_if_tagged(&tree, &first, 10, 10, 0, 1);
+	ret = tag_tagged_items(&tree, first, 10, 10, 0, 1);
 	assert(ret == 1);
 	ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1);
 	assert(ret == 1);
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c
index a68ed3b..322c34b 100644
--- a/tools/testing/radix-tree/test.c
+++ b/tools/testing/radix-tree/test.c
@@ -142,6 +142,31 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start,
 	assert(nfound == 0);
 }
 
+/* Use the same pattern as tag_pages_for_writeback() in mm/page-writeback.c */
+int tag_tagged_items(struct radix_tree_root *root,
+			unsigned long start, unsigned long end, unsigned batch,
+			unsigned iftag, unsigned thentag)
+{
+	unsigned long tagged = 0;
+	struct radix_tree_iter iter;
+	void **slot;
+
+	if (batch == 0)
+		batch = 1;
+
+	radix_tree_for_each_tagged(slot, root, &iter, start, iftag) {
+		if (iter.index > end)
+			break;
+		radix_tree_iter_tag_set(root, &iter, thentag);
+		tagged++;
+		if ((tagged % batch) != 0)
+			continue;
+		slot = radix_tree_iter_next(slot, &iter);
+	}
+
+	return tagged;
+}
+
 /* Use the same pattern as find_swap_entry() in mm/shmem.c */
 unsigned long find_item(struct radix_tree_root *root, void *item)
 {
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h
index ccdd3c1..1faf0a3 100644
--- a/tools/testing/radix-tree/test.h
+++ b/tools/testing/radix-tree/test.h
@@ -27,6 +27,9 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start,
 			unsigned long nr, int chunk);
 void item_kill_tree(struct radix_tree_root *root);
 
+int tag_tagged_items(struct radix_tree_root *, unsigned long start,
+			unsigned long end, unsigned batch,
+			unsigned iftag, unsigned thentag);
 unsigned long find_item(struct radix_tree_root *, void *item);
 
 void tag_check(void);
-- 
2.10.2

--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org.  For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>

  parent reply	other threads:[~2016-11-16 22:35 UTC|newest]

Thread overview: 152+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2016-11-17  0:16 [PATCH 00/29] Improve radix tree for 4.10 Matthew Wilcox
2016-11-17  0:16 ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 01/29] tools: Add WARN_ON_ONCE Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 02/29] radix tree test suite: Allow GFP_ATOMIC allocations to fail Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 03/29] radix tree test suite: Track preempt_count Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 04/29] radix tree test suite: Free preallocated nodes Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 05/29] radix tree test suite: Make runs more reproducible Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 06/28] Add benchmark Matthew Wilcox
2016-11-17  0:16 ` [PATCH 06/29] radix tree test suite: benchmark for iterator Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 07/29] radix tree test suite: Use rcu_barrier Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 07/28] test suite: Switch to rcu_barrier from sleep Matthew Wilcox
2016-11-17  0:16 ` [PATCH 08/29] tools: Add more bitmap functions Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 09/29] radix tree test suite: Use common find-bit code Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 10/29] radix-tree: Add radix_tree_join Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 11/29] radix-tree: Add radix_tree_split Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 12/29] radix-tree: Add radix_tree_split_preload() Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 13/29] radix-tree: Fix typo Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 14/29] radix-tree: Move rcu_head into a union with private_list Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 15/29] radix-tree: Create node_tag_set() Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 16/29] radix-tree: Make radix_tree_find_next_bit more useful Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 17/29] radix-tree: Improve dump output Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 18/29] btrfs: Fix race in btrfs_free_dummy_fs_info() Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 19/29] radix tree test suite: iteration test misuses RCU Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 20/29] radix tree: Improve multiorder iterators Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 21/29] radix-tree: Delete radix_tree_locate_item() Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` Matthew Wilcox [this message]
2016-11-17  0:16   ` [PATCH 22/29] radix-tree: Delete radix_tree_range_tag_if_tagged() Matthew Wilcox
2016-11-17  0:16 ` [PATCH 23/29] idr: Add ida_is_empty Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-18 11:56   ` Konstantin Khlebnikov
2016-11-18 11:56     ` Konstantin Khlebnikov
2016-11-17  0:16 ` [PATCH 24/29] tpm: Use idr_find(), not idr_find_slowpath() Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 25/28] idr: Reduce the number of bits per level from 8 to 6 Matthew Wilcox
2016-11-17  0:16 ` [PATCH 25/29] rxrpc: Abstract away knowledge of IDR internals Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 26/29] idr: Reduce the number of bits per level from 8 to 6 Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 26/28] radix tree test suite: Add some more functionality Matthew Wilcox
2016-11-17  0:16 ` [PATCH 27/28] radix-tree: Create all_tag_set Matthew Wilcox
2016-11-17  0:16 ` [PATCH 27/29] radix tree test suite: Add some more functionality Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:16 ` [PATCH 28/28] Reimplement IDR and IDA using the radix tree Matthew Wilcox
2016-11-17  0:16 ` [PATCH 28/29] radix-tree: Create all_tag_set Matthew Wilcox
2016-11-17  0:16   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 29/29] Reimplement IDR and IDA using the radix tree Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 00/29] Improve radix tree for 4.10 Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17 19:38   ` Matthew Wilcox
2016-11-17 19:38     ` Matthew Wilcox
2016-11-17 22:17   ` Ross Zwisler
2016-11-17 22:17     ` Ross Zwisler
2016-11-18  4:24     ` Matthew Wilcox
2016-11-18  4:24       ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 01/29] tools: Add WARN_ON_ONCE Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 02/29] radix tree test suite: Allow GFP_ATOMIC allocations to fail Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 03/29] radix tree test suite: Track preempt_count Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 04/29] radix tree test suite: Free preallocated nodes Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 05/29] radix tree test suite: Make runs more reproducible Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 06/28] Add benchmark Matthew Wilcox
2016-11-17  0:17 ` [PATCH 06/29] radix tree test suite: benchmark for iterator Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 07/29] radix tree test suite: Use rcu_barrier Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 07/28] test suite: Switch to rcu_barrier from sleep Matthew Wilcox
2016-11-17  0:17 ` [PATCH 08/29] tools: Add more bitmap functions Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 09/29] radix tree test suite: Use common find-bit code Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 10/29] radix-tree: Add radix_tree_join Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 11/29] radix-tree: Add radix_tree_split Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 12/29] radix-tree: Add radix_tree_split_preload() Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 13/29] radix-tree: Fix typo Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 14/29] radix-tree: Move rcu_head into a union with private_list Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 15/29] radix-tree: Create node_tag_set() Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 16/29] radix-tree: Make radix_tree_find_next_bit more useful Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 17/29] radix-tree: Improve dump output Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 18/29] btrfs: Fix race in btrfs_free_dummy_fs_info() Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 19/29] radix tree test suite: iteration test misuses RCU Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 20/29] radix tree: Improve multiorder iterators Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-18 11:47   ` Konstantin Khlebnikov
2016-11-18 11:47     ` Konstantin Khlebnikov
2016-11-18 16:31     ` Matthew Wilcox
2016-11-18 16:31       ` Matthew Wilcox
2016-11-18 17:56       ` Konstantin Khlebnikov
2016-11-18 17:56         ` Konstantin Khlebnikov
2016-11-18 20:23         ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 21/29] radix-tree: Delete radix_tree_locate_item() Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-18 11:50   ` Konstantin Khlebnikov
2016-11-18 11:50     ` Konstantin Khlebnikov
2016-11-18 16:34     ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 22/29] radix-tree: Delete radix_tree_range_tag_if_tagged() Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 23/29] idr: Add ida_is_empty Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 24/29] tpm: Use idr_find(), not idr_find_slowpath() Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 25/28] idr: Reduce the number of bits per level from 8 to 6 Matthew Wilcox
2016-11-17  0:17 ` [PATCH 25/29] rxrpc: Abstract away knowledge of IDR internals Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 26/29] idr: Reduce the number of bits per level from 8 to 6 Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 26/28] radix tree test suite: Add some more functionality Matthew Wilcox
2016-11-17  0:17 ` [PATCH 27/28] radix-tree: Create all_tag_set Matthew Wilcox
2016-11-17  0:17 ` [PATCH 27/29] radix tree test suite: Add some more functionality Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 28/28] Reimplement IDR and IDA using the radix tree Matthew Wilcox
2016-11-18 11:52   ` Konstantin Khlebnikov
2016-11-18 13:43     ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 28/29] radix-tree: Create all_tag_set Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox
2016-11-17  0:17 ` [PATCH 29/29] Reimplement IDR and IDA using the radix tree Matthew Wilcox
2016-11-17  0:17   ` Matthew Wilcox

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1479341856-30320-25-git-send-email-mawilcox@linuxonhyperv.com \
    --to=mawilcox@linuxonhyperv.com \
    --cc=akpm@linux-foundation.org \
    --cc=kirill.shutemov@linux.intel.com \
    --cc=koct9i@gmail.com \
    --cc=linux-fsdevel@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-mm@kvack.org \
    --cc=mawilcox@microsoft.com \
    --cc=ross.zwisler@linux.intel.com \
    --cc=willy@infradead.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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.