Groups | Search | Server Info | Keyboard shortcuts | Login | Register [http] [https] [nntp] [nntps]
Groups > linux.kernel > #1531607 > unrolled thread
| Started by | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| First post | 2016-11-28 21:10 +0100 |
| Last post | 2016-12-06 23:00 +0100 |
| Articles | 20 on this page of 40 — 5 participants |
Back to article view | Back to linux.kernel
[PATCH v3 00/33] Radix tree patches for 4.10 Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 26/33] radix-tree: Fix replacement for multiorder entries Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 00/33] Radix tree patches for 4.10 Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 27/33] radix tree test suite: Check multiorder iteration Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 15/33] radix-tree: Move rcu_head into a union with private_list Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 23/33] radix-tree: Add radix_tree_join Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 09/33] radix tree test suite: Use rcu_barrier Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 16/33] radix-tree: Create node_tag_set() Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 25/33] radix-tree: Add radix_tree_split_preload() Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 09/33] radix tree test suite: Use rcu_barrier Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 12/33] tools: Add more bitmap functions Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 16/33] radix-tree: Create node_tag_set() Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 27/33] radix tree test suite: Check multiorder iteration Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 21/33] radix-tree: Delete radix_tree_locate_item() Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:10 +0100
[PATCH v3 08/33] radix tree test suite: benchmark for iterator Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 22/33] radix-tree: Delete radix_tree_range_tag_if_tagged() Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 17/33] radix-tree: Make radix_tree_find_next_bit more useful Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 23/33] radix-tree: Add radix_tree_join Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 18/33] radix-tree: Improve dump output Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 05/33] radix tree test suite: Free preallocated nodes Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 06/33] radix tree test suite: Make runs more reproducible Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 20/33] radix-tree: Improve multiorder iterators Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 02/33] tools: Add WARN_ON_ONCE Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 14/33] radix-tree: Fix typo Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 03/33] radix tree test suite: Allow GFP_ATOMIC allocations to fail Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 12/33] tools: Add more bitmap functions Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 10/33] radix tree test suite: Handle exceptional entries Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 24/33] radix-tree: Add radix_tree_split Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
Re: [PATCH v3 24/33] radix-tree: Add radix_tree_split Randy Dunlap <rdunlap@infradead.org> - 2016-11-29 01:10 +0100
RE: [PATCH v3 24/33] radix-tree: Add radix_tree_split Matthew Wilcox <mawilcox@microsoft.com> - 2016-11-29 16:00 +0100
[PATCH v3 15/33] radix-tree: Move rcu_head into a union with private_list Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 11/33] radix tree test suite: record order in each item Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 01/33] radix tree test suite: Fix compilation Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 08/33] radix tree test suite: benchmark for iterator Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 17/33] radix-tree: Make radix_tree_find_next_bit more useful Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
[PATCH v3 10/33] radix tree test suite: Handle exceptional entries Matthew Wilcox <mawilcox@linuxonhyperv.com> - 2016-11-28 21:20 +0100
Re: [PATCH v3 00/33] Radix tree patches for 4.10 "Kirill A. Shutemov" <kirill@shutemov.name> - 2016-11-29 12:30 +0100
Re: [PATCH v3 33/33] Reimplement IDR and IDA using the radix tree Andrew Morton <akpm@linux-foundation.org> - 2016-12-06 21:50 +0100
Re: [PATCH v3 33/33] Reimplement IDR and IDA using the radix tree Andrew Morton <akpm@linux-foundation.org> - 2016-12-06 22:30 +0100
RE: [PATCH v3 33/33] Reimplement IDR and IDA using the radix tree Matthew Wilcox <mawilcox@microsoft.com> - 2016-12-06 23:00 +0100
Page 2 of 2 — ← Prev page 1 [2]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 06/33] radix tree test suite: Make runs more reproducible |
| Message-ID | <sIAz8-6P8-19@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <willy@infradead.org>
Instead of reseeding the random number generator every time around the
loop in big_gang_check(), seed it at the beginning of execution. Use
rand_r() and an independent base seed for each thread in iteration_test()
so they don't stomp all over each others state. Since this particular
test depends on the kernel scheduler, the iteration test can't be
reproduced based purely on the random seed, but at least it won't pollute
the other tests.
Print the seed, and allow the seed to be specified so that a run which
hits a problem can be reproduced.
Signed-off-by: Matthew Wilcox <willy@infradead.org>
---
tools/testing/radix-tree/iteration_check.c | 11 +++++++----
tools/testing/radix-tree/main.c | 9 +++++++--
2 files changed, 14 insertions(+), 6 deletions(-)
diff --git a/tools/testing/radix-tree/iteration_check.c b/tools/testing/radix-tree/iteration_check.c
index 9adb8e7..11d570c 100644
--- a/tools/testing/radix-tree/iteration_check.c
+++ b/tools/testing/radix-tree/iteration_check.c
@@ -20,6 +20,7 @@
#define TAG 0
static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER;
static pthread_t threads[NUM_THREADS];
+static unsigned int seeds[3];
RADIX_TREE(tree, GFP_KERNEL);
bool test_complete;
@@ -71,7 +72,7 @@ static void *tagged_iteration_fn(void *arg)
continue;
}
- if (rand() % 50 == 0)
+ if (rand_r(&seeds[0]) % 50 == 0)
slot = radix_tree_iter_next(&iter);
}
rcu_read_unlock();
@@ -111,7 +112,7 @@ static void *untagged_iteration_fn(void *arg)
continue;
}
- if (rand() % 50 == 0)
+ if (rand_r(&seeds[1]) % 50 == 0)
slot = radix_tree_iter_next(&iter);
}
rcu_read_unlock();
@@ -129,7 +130,7 @@ static void *remove_entries_fn(void *arg)
while (!test_complete) {
int pgoff;
- pgoff = rand() % 100;
+ pgoff = rand_r(&seeds[2]) % 100;
pthread_mutex_lock(&tree_lock);
item_delete(&tree, pgoff);
@@ -146,9 +147,11 @@ void iteration_test(void)
printf("Running iteration tests for 10 seconds\n");
- srand(time(0));
test_complete = false;
+ for (i = 0; i < 3; i++)
+ seeds[i] = rand();
+
if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) {
perror("pthread_create");
exit(1);
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c
index 52ce1ea..2eb6949 100644
--- a/tools/testing/radix-tree/main.c
+++ b/tools/testing/radix-tree/main.c
@@ -67,7 +67,6 @@ void big_gang_check(bool long_run)
for (i = 0; i < (long_run ? 1000 : 3); i++) {
__big_gang_check();
- srand(time(0));
printf("%d ", i);
fflush(stdout);
}
@@ -329,12 +328,18 @@ int main(int argc, char **argv)
{
bool long_run = false;
int opt;
+ unsigned int seed = time(NULL);
- while ((opt = getopt(argc, argv, "l")) != -1) {
+ while ((opt = getopt(argc, argv, "ls:")) != -1) {
if (opt == 'l')
long_run = true;
+ else if (opt == 's')
+ seed = strtoul(optarg, NULL, 0);
}
+ printf("random seed %u\n", seed);
+ srand(seed);
+
rcu_register_thread();
radix_tree_init();
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 20/33] radix-tree: Improve multiorder iterators |
| Message-ID | <sIAz8-6P8-21@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <mawilcox@microsoft.com>
This fixes several interlinked problems with the iterators in the
presence of multiorder entries.
1. radix_tree_iter_next() would only advance by one slot, which would
result in the iterators returning the same entry more than once if there
were sibling entries.
2. radix_tree_next_slot() could return an internal pointer instead of
a user pointer if a tagged multiorder entry was immediately followed by
an entry of lower order.
3. radix_tree_next_slot() expanded to a lot more code than it used to
when multiorder support was compiled in. And I wasn't comfortable with
entry_to_node() being in a header file.
Fixing radix_tree_iter_next() for the presence of sibling entries
necessarily involves examining the contents of the radix tree, so we now
need to pass 'slot' to radix_tree_iter_next(), and we need to change the
calling convention so it is called *before* dropping the lock which
protects the tree. Also rename it to radix_tree_iter_resume(), as some
people thought it was necessary to call radix_tree_iter_next() each time
around the loop.
radix_tree_next_slot() becomes closer to how it looked before multiorder
support was introduced. It only checks to see if the next entry in the
chunk is a sibling entry or a pointer to a node; this should be rare
enough that handling this case out of line is not a performance impact
(and such impact is amortised by the fact that the entry we just
processed was a multiorder entry). Also, radix_tree_next_slot() used
to force a new chunk lookup for untagged entries, which is more
expensive than the out of line sibling entry skipping.
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
---
fs/btrfs/tests/btrfs-tests.c | 2 +-
include/linux/radix-tree.h | 71 +++++++--------
lib/radix-tree.c | 138 +++++++++++++++++++++++++----
mm/khugepaged.c | 7 +-
mm/shmem.c | 6 +-
tools/testing/radix-tree/iteration_check.c | 12 +--
tools/testing/radix-tree/multiorder.c | 28 ++++--
tools/testing/radix-tree/regression3.c | 8 +-
tools/testing/radix-tree/test.h | 1 +
9 files changed, 188 insertions(+), 85 deletions(-)
diff --git a/fs/btrfs/tests/btrfs-tests.c b/fs/btrfs/tests/btrfs-tests.c
index 73076a0..00ee006 100644
--- a/fs/btrfs/tests/btrfs-tests.c
+++ b/fs/btrfs/tests/btrfs-tests.c
@@ -162,7 +162,7 @@ void btrfs_free_dummy_fs_info(struct btrfs_fs_info *fs_info)
slot = radix_tree_iter_retry(&iter);
continue;
}
- slot = radix_tree_iter_next(&iter);
+ slot = radix_tree_iter_resume(slot, &iter);
spin_unlock(&fs_info->buffer_lock);
free_extent_buffer_stale(eb);
spin_lock(&fs_info->buffer_lock);
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index d04073a..289d007 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -403,20 +403,17 @@ __radix_tree_iter_add(struct radix_tree_iter *iter, unsigned long slots)
}
/**
- * radix_tree_iter_next - resume iterating when the chunk may be invalid
- * @iter: iterator state
+ * radix_tree_iter_resume - resume iterating when the chunk may be invalid
+ * @slot: pointer to current slot
+ * @iter: iterator state
+ * Returns: New slot pointer
*
* If the iterator needs to release then reacquire a lock, the chunk may
* have been invalidated by an insertion or deletion. Call this function
- * to continue the iteration from the next index.
+ * before releasing the lock to continue the iteration from the next index.
*/
-static inline __must_check
-void **radix_tree_iter_next(struct radix_tree_iter *iter)
-{
- iter->next_index = __radix_tree_iter_add(iter, 1);
- iter->tags = 0;
- return NULL;
-}
+void **__must_check radix_tree_iter_resume(void **slot,
+ struct radix_tree_iter *iter);
/**
* radix_tree_chunk_size - get current chunk size
@@ -430,10 +427,17 @@ radix_tree_chunk_size(struct radix_tree_iter *iter)
return (iter->next_index - iter->index) >> iter_shift(iter);
}
-static inline struct radix_tree_node *entry_to_node(void *ptr)
+#ifdef CONFIG_RADIX_TREE_MULTIORDER
+void ** __radix_tree_next_slot(void **slot, struct radix_tree_iter *iter,
+ unsigned flags);
+#else
+/* Can't happen without sibling entries, but the compiler can't tell that */
+static inline void ** __radix_tree_next_slot(void **slot,
+ struct radix_tree_iter *iter, unsigned flags)
{
- return (void *)((unsigned long)ptr & ~RADIX_TREE_INTERNAL_NODE);
+ return slot;
}
+#endif
/**
* radix_tree_next_slot - find next slot in chunk
@@ -447,7 +451,7 @@ static inline struct radix_tree_node *entry_to_node(void *ptr)
* For tagged lookup it also eats @iter->tags.
*
* There are several cases where 'slot' can be passed in as NULL to this
- * function. These cases result from the use of radix_tree_iter_next() or
+ * function. These cases result from the use of radix_tree_iter_resume() or
* radix_tree_iter_retry(). In these cases we don't end up dereferencing
* 'slot' because either:
* a) we are doing tagged iteration and iter->tags has been set to 0, or
@@ -458,51 +462,31 @@ static __always_inline void **
radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags)
{
if (flags & RADIX_TREE_ITER_TAGGED) {
- void *canon = slot;
-
iter->tags >>= 1;
if (unlikely(!iter->tags))
return NULL;
- while (IS_ENABLED(CONFIG_RADIX_TREE_MULTIORDER) &&
- radix_tree_is_internal_node(slot[1])) {
- if (entry_to_node(slot[1]) == canon) {
- iter->tags >>= 1;
- iter->index = __radix_tree_iter_add(iter, 1);
- slot++;
- continue;
- }
- iter->next_index = __radix_tree_iter_add(iter, 1);
- return NULL;
- }
if (likely(iter->tags & 1ul)) {
iter->index = __radix_tree_iter_add(iter, 1);
- return slot + 1;
+ slot++;
+ goto found;
}
if (!(flags & RADIX_TREE_ITER_CONTIG)) {
unsigned offset = __ffs(iter->tags);
- iter->tags >>= offset;
- iter->index = __radix_tree_iter_add(iter, offset + 1);
- return slot + offset + 1;
+ iter->tags >>= offset++;
+ iter->index = __radix_tree_iter_add(iter, offset);
+ slot += offset;
+ goto found;
}
} else {
long count = radix_tree_chunk_size(iter);
- void *canon = slot;
while (--count > 0) {
slot++;
iter->index = __radix_tree_iter_add(iter, 1);
- if (IS_ENABLED(CONFIG_RADIX_TREE_MULTIORDER) &&
- radix_tree_is_internal_node(*slot)) {
- if (entry_to_node(*slot) == canon)
- continue;
- iter->next_index = iter->index;
- break;
- }
-
if (likely(*slot))
- return slot;
+ goto found;
if (flags & RADIX_TREE_ITER_CONTIG) {
/* forbid switching to the next chunk */
iter->next_index = 0;
@@ -511,6 +495,11 @@ radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags)
}
}
return NULL;
+
+ found:
+ if (unlikely(radix_tree_is_internal_node(*slot)))
+ return __radix_tree_next_slot(slot, iter, flags);
+ return slot;
}
/**
@@ -561,6 +550,6 @@ radix_tree_next_slot(void **slot, struct radix_tree_iter *iter, unsigned flags)
slot || (slot = radix_tree_next_chunk(root, iter, \
RADIX_TREE_ITER_TAGGED | tag)) ; \
slot = radix_tree_next_slot(slot, iter, \
- RADIX_TREE_ITER_TAGGED))
+ RADIX_TREE_ITER_TAGGED | tag))
#endif /* _LINUX_RADIX_TREE_H */
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 49b320e..f8fab01 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -68,6 +68,11 @@ struct radix_tree_preload {
};
static DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
+static inline struct radix_tree_node *entry_to_node(void *ptr)
+{
+ return (void *)((unsigned long)ptr & ~RADIX_TREE_INTERNAL_NODE);
+}
+
static inline void *node_to_entry(void *ptr)
{
return (void *)((unsigned long)ptr | RADIX_TREE_INTERNAL_NODE);
@@ -1103,6 +1108,120 @@ static inline void __set_iter_shift(struct radix_tree_iter *iter,
#endif
}
+/* Construct iter->tags bit-mask from node->tags[tag] array */
+static void set_iter_tags(struct radix_tree_iter *iter,
+ struct radix_tree_node *node, unsigned offset,
+ unsigned tag)
+{
+ unsigned tag_long = offset / BITS_PER_LONG;
+ unsigned tag_bit = offset % BITS_PER_LONG;
+
+ iter->tags = node->tags[tag][tag_long] >> tag_bit;
+
+ /* This never happens if RADIX_TREE_TAG_LONGS == 1 */
+ if (tag_long < RADIX_TREE_TAG_LONGS - 1) {
+ /* Pick tags from next element */
+ if (tag_bit)
+ iter->tags |= node->tags[tag][tag_long + 1] <<
+ (BITS_PER_LONG - tag_bit);
+ /* Clip chunk size, here only BITS_PER_LONG tags */
+ iter->next_index = __radix_tree_iter_add(iter, BITS_PER_LONG);
+ }
+}
+
+#ifdef CONFIG_RADIX_TREE_MULTIORDER
+static void **skip_siblings(struct radix_tree_node **nodep,
+ void **slot, struct radix_tree_iter *iter)
+{
+ void *sib = node_to_entry(slot - 1);
+
+ while (iter->index < iter->next_index) {
+ *nodep = rcu_dereference_raw(*slot);
+ if (*nodep && *nodep != sib)
+ return slot;
+ slot++;
+ iter->index = __radix_tree_iter_add(iter, 1);
+ iter->tags >>= 1;
+ }
+
+ *nodep = NULL;
+ return NULL;
+}
+
+void ** __radix_tree_next_slot(void **slot, struct radix_tree_iter *iter,
+ unsigned flags)
+{
+ unsigned tag = flags & RADIX_TREE_ITER_TAG_MASK;
+ struct radix_tree_node *node = rcu_dereference_raw(*slot);
+
+ slot = skip_siblings(&node, slot, iter);
+
+ while (radix_tree_is_internal_node(node)) {
+ unsigned offset;
+ unsigned long next_index;
+
+ if (node == RADIX_TREE_RETRY)
+ return slot;
+ node = entry_to_node(node);
+ iter->shift = node->shift;
+
+ if (flags & RADIX_TREE_ITER_TAGGED) {
+ offset = radix_tree_find_next_bit(node, tag, 0);
+ if (offset == RADIX_TREE_MAP_SIZE)
+ return NULL;
+ slot = &node->slots[offset];
+ iter->index = __radix_tree_iter_add(iter, offset);
+ set_iter_tags(iter, node, offset, tag);
+ node = rcu_dereference_raw(*slot);
+ } else {
+ offset = 0;
+ slot = &node->slots[0];
+ for (;;) {
+ node = rcu_dereference_raw(*slot);
+ if (node)
+ break;
+ slot++;
+ offset++;
+ if (offset == RADIX_TREE_MAP_SIZE)
+ return NULL;
+ }
+ iter->index = __radix_tree_iter_add(iter, offset);
+ }
+ if ((flags & RADIX_TREE_ITER_CONTIG) && (offset > 0))
+ goto none;
+ next_index = (iter->index | shift_maxindex(iter->shift)) + 1;
+ if (next_index < iter->next_index)
+ iter->next_index = next_index;
+ }
+
+ return slot;
+ none:
+ iter->next_index = 0;
+ return NULL;
+}
+EXPORT_SYMBOL(__radix_tree_next_slot);
+#else
+static void **skip_siblings(struct radix_tree_node **nodep,
+ void **slot, struct radix_tree_iter *iter)
+{
+ return slot;
+}
+#endif
+
+void **radix_tree_iter_resume(void **slot, struct radix_tree_iter *iter)
+{
+ struct radix_tree_node *node;
+
+ slot++;
+ iter->index = __radix_tree_iter_add(iter, 1);
+ node = rcu_dereference_raw(*slot);
+ skip_siblings(&node, slot, iter);
+ iter->next_index = iter->index;
+ iter->tags = 0;
+ return NULL;
+}
+EXPORT_SYMBOL(radix_tree_iter_resume);
+
/**
* radix_tree_next_chunk - find next chunk of slots for iteration
*
@@ -1190,23 +1309,8 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
iter->next_index = (index | node_maxindex(node)) + 1;
__set_iter_shift(iter, node->shift);
- /* Construct iter->tags bit-mask from node->tags[tag] array */
- if (flags & RADIX_TREE_ITER_TAGGED) {
- unsigned tag_long, tag_bit;
-
- tag_long = offset / BITS_PER_LONG;
- tag_bit = offset % BITS_PER_LONG;
- iter->tags = node->tags[tag][tag_long] >> tag_bit;
- /* This never happens if RADIX_TREE_TAG_LONGS == 1 */
- if (tag_long < RADIX_TREE_TAG_LONGS - 1) {
- /* Pick tags from next element */
- if (tag_bit)
- iter->tags |= node->tags[tag][tag_long + 1] <<
- (BITS_PER_LONG - tag_bit);
- /* Clip chunk size, here only BITS_PER_LONG tags */
- iter->next_index = index + BITS_PER_LONG;
- }
- }
+ if (flags & RADIX_TREE_ITER_TAGGED)
+ set_iter_tags(iter, node, offset, tag);
return node->slots + offset;
}
diff --git a/mm/khugepaged.c b/mm/khugepaged.c
index 7434a63..e32389a 100644
--- a/mm/khugepaged.c
+++ b/mm/khugepaged.c
@@ -1446,7 +1446,7 @@ static void collapse_shmem(struct mm_struct *mm,
radix_tree_replace_slot(&mapping->page_tree, slot,
new_page + (index % HPAGE_PMD_NR));
- slot = radix_tree_iter_next(&iter);
+ slot = radix_tree_iter_resume(slot, &iter);
index++;
continue;
out_lru:
@@ -1546,7 +1546,6 @@ static void collapse_shmem(struct mm_struct *mm,
/* Put holes back where they were */
radix_tree_delete(&mapping->page_tree,
iter.index);
- slot = radix_tree_iter_next(&iter);
continue;
}
@@ -1557,11 +1556,11 @@ static void collapse_shmem(struct mm_struct *mm,
page_ref_unfreeze(page, 2);
radix_tree_replace_slot(&mapping->page_tree,
slot, page);
+ slot = radix_tree_iter_resume(slot, &iter);
spin_unlock_irq(&mapping->tree_lock);
putback_lru_page(page);
unlock_page(page);
spin_lock_irq(&mapping->tree_lock);
- slot = radix_tree_iter_next(&iter);
}
VM_BUG_ON(nr_none);
spin_unlock_irq(&mapping->tree_lock);
@@ -1641,8 +1640,8 @@ static void khugepaged_scan_shmem(struct mm_struct *mm,
present++;
if (need_resched()) {
+ slot = radix_tree_iter_resume(slot, &iter);
cond_resched_rcu();
- slot = radix_tree_iter_next(&iter);
}
}
rcu_read_unlock();
diff --git a/mm/shmem.c b/mm/shmem.c
index f917b49..b9a785e 100644
--- a/mm/shmem.c
+++ b/mm/shmem.c
@@ -661,8 +661,8 @@ unsigned long shmem_partial_swap_usage(struct address_space *mapping,
swapped++;
if (need_resched()) {
+ slot = radix_tree_iter_resume(slot, &iter);
cond_resched_rcu();
- slot = radix_tree_iter_next(&iter);
}
}
@@ -2435,8 +2435,8 @@ static void shmem_tag_pins(struct address_space *mapping)
}
if (need_resched()) {
+ slot = radix_tree_iter_resume(slot, &iter);
cond_resched_rcu();
- slot = radix_tree_iter_next(&iter);
}
}
rcu_read_unlock();
@@ -2505,8 +2505,8 @@ static int shmem_wait_for_pins(struct address_space *mapping)
spin_unlock_irq(&mapping->tree_lock);
continue_resched:
if (need_resched()) {
+ slot = radix_tree_iter_resume(slot, &iter);
cond_resched_rcu();
- slot = radix_tree_iter_next(&iter);
}
}
rcu_read_unlock();
diff --git a/tools/testing/radix-tree/iteration_check.c b/tools/testing/radix-tree/iteration_check.c
index df71cb8..f328a66 100644
--- a/tools/testing/radix-tree/iteration_check.c
+++ b/tools/testing/radix-tree/iteration_check.c
@@ -48,8 +48,8 @@ static void *add_entries_fn(void *arg)
/*
* Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find
* things that have been removed and randomly resetting our iteration to the
- * next chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and
- * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a
+ * next chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and
+ * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a
* NULL 'slot' variable.
*/
static void *tagged_iteration_fn(void *arg)
@@ -79,7 +79,7 @@ static void *tagged_iteration_fn(void *arg)
}
if (rand_r(&seeds[0]) % 50 == 0) {
- slot = radix_tree_iter_next(&iter);
+ slot = radix_tree_iter_resume(slot, &iter);
rcu_read_unlock();
rcu_barrier();
rcu_read_lock();
@@ -96,8 +96,8 @@ static void *tagged_iteration_fn(void *arg)
/*
* Iterate over the entries, doing a radix_tree_iter_retry() as we find things
* that have been removed and randomly resetting our iteration to the next
- * chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and
- * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a
+ * chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and
+ * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a
* NULL 'slot' variable.
*/
static void *untagged_iteration_fn(void *arg)
@@ -127,7 +127,7 @@ static void *untagged_iteration_fn(void *arg)
}
if (rand_r(&seeds[1]) % 50 == 0) {
- slot = radix_tree_iter_next(&iter);
+ slot = radix_tree_iter_resume(slot, &iter);
rcu_read_unlock();
rcu_barrier();
rcu_read_lock();
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c
index 8d5865c..b9be885 100644
--- a/tools/testing/radix-tree/multiorder.c
+++ b/tools/testing/radix-tree/multiorder.c
@@ -231,11 +231,14 @@ void multiorder_iteration(void)
radix_tree_for_each_slot(slot, &tree, &iter, j) {
int height = order[i] / RADIX_TREE_MAP_SHIFT;
int shift = height * RADIX_TREE_MAP_SHIFT;
- int mask = (1 << order[i]) - 1;
+ unsigned long mask = (1UL << order[i]) - 1;
+ struct item *item = *slot;
- assert(iter.index >= (index[i] &~ mask));
- assert(iter.index <= (index[i] | mask));
+ assert((iter.index | mask) == (index[i] | mask));
assert(iter.shift == shift);
+ assert(!radix_tree_is_internal_node(item));
+ assert((item->index | mask) == (index[i] | mask));
+ assert(item->order == order[i]);
i++;
}
}
@@ -269,7 +272,7 @@ void multiorder_tagged_iteration(void)
assert(radix_tree_tag_set(&tree, tag_index[i], 1));
for (j = 0; j < 256; j++) {
- int mask, k;
+ int k;
for (i = 0; i < TAG_ENTRIES; i++) {
for (k = i; index[k] < tag_index[i]; k++)
@@ -279,12 +282,16 @@ void multiorder_tagged_iteration(void)
}
radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) {
+ unsigned long mask;
+ struct item *item = *slot;
for (k = i; index[k] < tag_index[i]; k++)
;
- mask = (1 << order[k]) - 1;
+ mask = (1UL << order[k]) - 1;
- assert(iter.index >= (tag_index[i] &~ mask));
- assert(iter.index <= (tag_index[i] | mask));
+ assert((iter.index | mask) == (tag_index[i] | mask));
+ assert(!radix_tree_is_internal_node(item));
+ assert((item->index | mask) == (tag_index[i] | mask));
+ assert(item->order == order[k]);
i++;
}
}
@@ -303,12 +310,15 @@ void multiorder_tagged_iteration(void)
}
radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) {
+ struct item *item = *slot;
for (k = i; index[k] < tag_index[i]; k++)
;
mask = (1 << order[k]) - 1;
- assert(iter.index >= (tag_index[i] &~ mask));
- assert(iter.index <= (tag_index[i] | mask));
+ assert((iter.index | mask) == (tag_index[i] | mask));
+ assert(!radix_tree_is_internal_node(item));
+ assert((item->index | mask) == (tag_index[i] | mask));
+ assert(item->order == order[k]);
i++;
}
}
diff --git a/tools/testing/radix-tree/regression3.c b/tools/testing/radix-tree/regression3.c
index 1f06ed7..b594841 100644
--- a/tools/testing/radix-tree/regression3.c
+++ b/tools/testing/radix-tree/regression3.c
@@ -5,7 +5,7 @@
* In following radix_tree_next_slot current chunk size becomes zero.
* This isn't checked and it tries to dereference null pointer in slot.
*
- * Helper radix_tree_iter_next reset slot to NULL and next_index to index + 1,
+ * Helper radix_tree_iter_resume reset slot to NULL and next_index to index + 1,
* for tagger iteraction it also must reset cached tags in iterator to abort
* next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk.
*
@@ -88,7 +88,7 @@ void regression3_test(void)
printf("slot %ld %p\n", iter.index, *slot);
if (!iter.index) {
printf("next at %ld\n", iter.index);
- slot = radix_tree_iter_next(&iter);
+ slot = radix_tree_iter_resume(slot, &iter);
}
}
@@ -96,7 +96,7 @@ void regression3_test(void)
printf("contig %ld %p\n", iter.index, *slot);
if (!iter.index) {
printf("next at %ld\n", iter.index);
- slot = radix_tree_iter_next(&iter);
+ slot = radix_tree_iter_resume(slot, &iter);
}
}
@@ -106,7 +106,7 @@ void regression3_test(void)
printf("tagged %ld %p\n", iter.index, *slot);
if (!iter.index) {
printf("next at %ld\n", iter.index);
- slot = radix_tree_iter_next(&iter);
+ slot = radix_tree_iter_resume(slot, &iter);
}
}
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h
index 423c528..617416e 100644
--- a/tools/testing/radix-tree/test.h
+++ b/tools/testing/radix-tree/test.h
@@ -41,6 +41,7 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag);
extern int nr_allocated;
/* Normally private parts of lib/radix-tree.c */
+struct radix_tree_node *entry_to_node(void *ptr);
void radix_tree_dump(struct radix_tree_root *root);
int root_tag_get(struct radix_tree_root *root, unsigned int tag);
unsigned long node_maxindex(struct radix_tree_node *);
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 02/33] tools: Add WARN_ON_ONCE |
| Message-ID | <sIAz8-6P8-27@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <willy@linux.intel.com>
The radix tree uses its own buggy WARN_ON_ONCE. Replace it with the
definition from asm-generic/bug.h
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
---
tools/include/asm/bug.h | 11 +++++++++++
tools/testing/radix-tree/Makefile | 2 +-
tools/testing/radix-tree/linux/bug.h | 2 +-
tools/testing/radix-tree/linux/types.h | 2 --
4 files changed, 13 insertions(+), 4 deletions(-)
diff --git a/tools/include/asm/bug.h b/tools/include/asm/bug.h
index 9e5f484..beda1a8 100644
--- a/tools/include/asm/bug.h
+++ b/tools/include/asm/bug.h
@@ -12,6 +12,17 @@
unlikely(__ret_warn_on); \
})
+#define WARN_ON_ONCE(condition) ({ \
+ static int __warned; \
+ int __ret_warn_once = !!(condition); \
+ \
+ if (unlikely(__ret_warn_once && !__warned)) { \
+ __warned = true; \
+ WARN_ON(1); \
+ } \
+ unlikely(__ret_warn_once); \
+})
+
#define WARN_ONCE(condition, format...) ({ \
static int __warned; \
int __ret_warn_once = !!(condition); \
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile
index f2e07f2..3c338dc 100644
--- a/tools/testing/radix-tree/Makefile
+++ b/tools/testing/radix-tree/Makefile
@@ -1,5 +1,5 @@
-CFLAGS += -I. -g -O2 -Wall -D_LGPL_SOURCE
+CFLAGS += -I. -I../../include -g -O2 -Wall -D_LGPL_SOURCE
LDFLAGS += -lpthread -lurcu
TARGETS = main
OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \
diff --git a/tools/testing/radix-tree/linux/bug.h b/tools/testing/radix-tree/linux/bug.h
index ccbe444..23b8ed5 100644
--- a/tools/testing/radix-tree/linux/bug.h
+++ b/tools/testing/radix-tree/linux/bug.h
@@ -1 +1 @@
-#define WARN_ON_ONCE(x) assert(x)
+#include "asm/bug.h"
diff --git a/tools/testing/radix-tree/linux/types.h b/tools/testing/radix-tree/linux/types.h
index faa0b6f..8491d89 100644
--- a/tools/testing/radix-tree/linux/types.h
+++ b/tools/testing/radix-tree/linux/types.h
@@ -6,8 +6,6 @@
#define __rcu
#define __read_mostly
-#define BITS_PER_LONG (sizeof(long) * 8)
-
static inline void INIT_LIST_HEAD(struct list_head *list)
{
list->next = list;
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 14/33] radix-tree: Fix typo |
| Message-ID | <sIAz8-6P8-31@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <willy@linux.intel.com> --- lib/radix-tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/radix-tree.c b/lib/radix-tree.c index e0290d1..b329056 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -1109,7 +1109,7 @@ void **radix_tree_next_chunk(struct radix_tree_root *root, * because RADIX_TREE_MAP_SHIFT < BITS_PER_LONG. * * This condition also used by radix_tree_next_slot() to stop - * contiguous iterating, and forbid swithing to the next chunk. + * contiguous iterating, and forbid switching to the next chunk. */ index = iter->next_index; if (!index && iter->index) -- 2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 03/33] radix tree test suite: Allow GFP_ATOMIC allocations to fail |
| Message-ID | <sIAz9-6P8-55@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <willy@linux.intel.com>
In order to test the preload code, it is necessary to fail GFP_ATOMIC
allocations, which requires defining GFP_KERNEL and GFP_ATOMIC properly.
Remove the obsolete __GFP_WAIT and copy the definitions of the __GFP
flags which are used from the kernel include files. We also need the
real definition of gfpflags_allow_blocking() to persuade the radix tree
to actually use its preallocated nodes.
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
---
tools/testing/radix-tree/linux.c | 7 ++++++-
tools/testing/radix-tree/linux/gfp.h | 22 +++++++++++++++++++---
tools/testing/radix-tree/linux/slab.h | 5 -----
3 files changed, 25 insertions(+), 9 deletions(-)
diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c
index 1548237..3cfb04e 100644
--- a/tools/testing/radix-tree/linux.c
+++ b/tools/testing/radix-tree/linux.c
@@ -33,7 +33,12 @@ mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
void *kmem_cache_alloc(struct kmem_cache *cachep, int flags)
{
- void *ret = malloc(cachep->size);
+ void *ret;
+
+ if (flags & __GFP_NOWARN)
+ return NULL;
+
+ ret = malloc(cachep->size);
if (cachep->ctor)
cachep->ctor(ret);
uatomic_inc(&nr_allocated);
diff --git a/tools/testing/radix-tree/linux/gfp.h b/tools/testing/radix-tree/linux/gfp.h
index 5201b91..5b09b2c 100644
--- a/tools/testing/radix-tree/linux/gfp.h
+++ b/tools/testing/radix-tree/linux/gfp.h
@@ -3,8 +3,24 @@
#define __GFP_BITS_SHIFT 26
#define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
-#define __GFP_WAIT 1
-#define __GFP_ACCOUNT 0
-#define __GFP_NOWARN 0
+
+#define __GFP_HIGH 0x20u
+#define __GFP_IO 0x40u
+#define __GFP_FS 0x80u
+#define __GFP_NOWARN 0x200u
+#define __GFP_ATOMIC 0x80000u
+#define __GFP_ACCOUNT 0x100000u
+#define __GFP_DIRECT_RECLAIM 0x400000u
+#define __GFP_KSWAPD_RECLAIM 0x2000000u
+
+#define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM|__GFP_KSWAPD_RECLAIM)
+
+#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)
+#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)
+
+static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
+{
+ return !!(gfp_flags & __GFP_DIRECT_RECLAIM);
+}
#endif
diff --git a/tools/testing/radix-tree/linux/slab.h b/tools/testing/radix-tree/linux/slab.h
index 6d5a347..452e2bf 100644
--- a/tools/testing/radix-tree/linux/slab.h
+++ b/tools/testing/radix-tree/linux/slab.h
@@ -7,11 +7,6 @@
#define SLAB_PANIC 2
#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
-static inline int gfpflags_allow_blocking(gfp_t mask)
-{
- return 1;
-}
-
struct kmem_cache {
int size;
void (*ctor)(void *);
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 12/33] tools: Add more bitmap functions |
| Message-ID | <sIAz9-6P8-45@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <willy@linux.intel.com>
I need the following functions for the radix tree:
bitmap_fill
bitmap_empty
bitmap_full
Copy the implementations from include/linux/bitmap.h
---
tools/include/linux/bitmap.h | 26 ++++++++++++++++++++++++++
1 file changed, 26 insertions(+)
diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h
index 43c1c50..eef41d5 100644
--- a/tools/include/linux/bitmap.h
+++ b/tools/include/linux/bitmap.h
@@ -35,6 +35,32 @@ static inline void bitmap_zero(unsigned long *dst, int nbits)
}
}
+static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
+{
+ unsigned int nlongs = BITS_TO_LONGS(nbits);
+ if (!small_const_nbits(nbits)) {
+ unsigned int len = (nlongs - 1) * sizeof(unsigned long);
+ memset(dst, 0xff, len);
+ }
+ dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
+}
+
+static inline int bitmap_empty(const unsigned long *src, unsigned nbits)
+{
+ if (small_const_nbits(nbits))
+ return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
+
+ return find_first_bit(src, nbits) == nbits;
+}
+
+static inline int bitmap_full(const unsigned long *src, unsigned int nbits)
+{
+ if (small_const_nbits(nbits))
+ return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
+
+ return find_first_zero_bit(src, nbits) == nbits;
+}
+
static inline int bitmap_weight(const unsigned long *src, int nbits)
{
if (small_const_nbits(nbits))
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 10/33] radix tree test suite: Handle exceptional entries |
| Message-ID | <sIAz9-6P8-41@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <mawilcox@microsoft.com>
item_kill_tree() assumes that everything in the tree is a pointer to a
struct item, which is annoying when testing the behaviour of exceptional
entries. Fix it to delete exceptional entries on the assumption they
don't need to be freed.
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
---
tools/testing/radix-tree/test.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c
index a6e8099..6f8dafc 100644
--- a/tools/testing/radix-tree/test.c
+++ b/tools/testing/radix-tree/test.c
@@ -200,9 +200,16 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag)
void item_kill_tree(struct radix_tree_root *root)
{
+ struct radix_tree_iter iter;
+ void **slot;
struct item *items[32];
int nfound;
+ radix_tree_for_each_slot(slot, root, &iter, 0) {
+ if (radix_tree_exceptional_entry(*slot))
+ radix_tree_delete(root, iter.index);
+ }
+
while ((nfound = radix_tree_gang_lookup(root, (void **)items, 0, 32))) {
int i;
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 24/33] radix-tree: Add radix_tree_split |
| Message-ID | <sIAz9-6P8-57@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <willy@linux.intel.com>
This new function splits a larger multiorder entry into smaller entries
(potentially multi-order entries). These entries are initialised to
RADIX_TREE_RETRY to ensure that RCU walkers who see this state aren't
confused. The caller should then call radix_tree_for_each_slot() and
radix_tree_replace_slot() in order to turn these retry entries into the
intended new entries. Tags are replicated from the original multiorder
entry into each new entry.
Signed-off-by: Matthew Wilcox <willy@linux.intel.com>
---
include/linux/radix-tree.h | 12 +++
lib/radix-tree.c | 142 +++++++++++++++++++++++++++++++++-
tools/testing/radix-tree/multiorder.c | 64 +++++++++++++++
3 files changed, 214 insertions(+), 4 deletions(-)
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 935293a..1f4b561 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -80,6 +80,14 @@ static inline bool radix_tree_is_internal_node(void *ptr)
#define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \
RADIX_TREE_MAP_SHIFT))
+/*
+ * @count is the count of every non-NULL element in the ->slots array
+ * whether that is an exceptional entry, a retry entry, a user pointer,
+ * a sibling entry or a pointer to the next level of the tree.
+ * @exceptional is the count of every element in ->slots which is
+ * either radix_tree_exceptional_entry() or is a sibling entry for an
+ * exceptional entry.
+ */
struct radix_tree_node {
unsigned char shift; /* Bits remaining in each slot */
unsigned char offset; /* Slot offset in parent */
@@ -293,6 +301,8 @@ void __radix_tree_replace(struct radix_tree_root *root,
struct radix_tree_node *node,
void **slot, void *item,
radix_tree_update_node_t update_node, void *private);
+void radix_tree_iter_replace(struct radix_tree_root *,
+ const struct radix_tree_iter *, void **slot, void *item);
void radix_tree_replace_slot(struct radix_tree_root *root,
void **slot, void *item);
void __radix_tree_delete_node(struct radix_tree_root *root,
@@ -335,6 +345,8 @@ static inline void radix_tree_preload_end(void)
preempt_enable();
}
+int radix_tree_split(struct radix_tree_root *, unsigned long index,
+ unsigned new_order);
int radix_tree_join(struct radix_tree_root *, unsigned long index,
unsigned new_order, void *);
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 257ad9d..704201b 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -22,6 +22,7 @@
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
+#include <linux/cpu.h>
#include <linux/errno.h>
#include <linux/init.h>
#include <linux/kernel.h>
@@ -757,7 +758,10 @@ static inline int insert_entries(struct radix_tree_node *node, void **slot,
unsigned i, n, tag, offset, tags = 0;
if (node) {
- n = 1 << (order - node->shift);
+ if (order > node->shift)
+ n = 1 << (order - node->shift);
+ else
+ n = 1;
offset = get_slot_offset(node, slot);
} else {
n = 1;
@@ -796,7 +800,8 @@ static inline int insert_entries(struct radix_tree_node *node, void **slot,
tag_set(node, tag, offset);
}
if (radix_tree_is_internal_node(old) &&
- !is_sibling_entry(node, old))
+ !is_sibling_entry(node, old) &&
+ (old != RADIX_TREE_RETRY))
radix_tree_free_nodes(old);
if (radix_tree_exceptional_entry(old))
node->exceptional--;
@@ -1020,7 +1025,8 @@ void __radix_tree_replace(struct radix_tree_root *root,
* NOTE: This cannot be used to switch between non-entries (empty slots),
* regular entries, and exceptional entries, as that requires accounting
* inside the radix tree node. When switching from one type of entry or
- * deleting, use __radix_tree_lookup() and __radix_tree_replace().
+ * deleting, use __radix_tree_lookup() and __radix_tree_replace() or
+ * radix_tree_iter_replace().
*/
void radix_tree_replace_slot(struct radix_tree_root *root,
void **slot, void *item)
@@ -1028,6 +1034,21 @@ void radix_tree_replace_slot(struct radix_tree_root *root,
replace_slot(root, NULL, slot, item, true);
}
+/**
+ * radix_tree_iter_replace - replace item in a slot
+ * @root: radix tree root
+ * @slot: pointer to slot
+ * @item: new item to store in the slot.
+ *
+ * For use with radix_tree_split() and radix_tree_for_each_slot().
+ * Caller must hold tree write locked across split and replacement.
+ */
+void radix_tree_iter_replace(struct radix_tree_root *root,
+ const struct radix_tree_iter *iter, void **slot, void *item)
+{
+ __radix_tree_replace(root, iter->node, slot, item, NULL, NULL);
+}
+
#ifdef CONFIG_RADIX_TREE_MULTIORDER
/**
* radix_tree_join - replace multiple entries with one multiorder entry
@@ -1060,6 +1081,117 @@ int radix_tree_join(struct radix_tree_root *root, unsigned long index,
return error;
}
+
+/**
+ * radix_tree_split - Split an entry into smaller entries
+ * @root: radix tree root
+ * @index: An index within the large entry
+ * @order: Order of new entries
+ *
+ * Call this function as the first step in replacing a multiorder entry
+ * with several entries of lower order. After this function returns,
+ * loop over the relevant portion of the tree using radix_tree_for_each_slot()
+ * and call radix_tree_iter_replace() to set up each new entry.
+ *
+ * The tags from this entry are replicated to all the new entries.
+ *
+ * The radix tree should be locked against modification during the entire
+ * replacement operation. Lock-free lookups will see RADIX_TREE_RETRY which
+ * should prompt RCU walkers to restart the lookup from the root.
+ */
+int radix_tree_split(struct radix_tree_root *root, unsigned long index,
+ unsigned order)
+{
+ struct radix_tree_node *parent, *node, *child;
+ void **slot;
+ unsigned int offset, end;
+ unsigned n, tag, tags = 0;
+
+ if (!__radix_tree_lookup(root, index, &parent, &slot))
+ return -ENOENT;
+ if (!parent)
+ return -ENOENT;
+
+ offset = get_slot_offset(parent, slot);
+
+ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
+ if (tag_get(parent, tag, offset))
+ tags |= 1 << tag;
+
+ for (end = offset + 1; end < RADIX_TREE_MAP_SIZE; end++) {
+ if (!is_sibling_entry(parent, parent->slots[end]))
+ break;
+ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
+ if (tags & (1 << tag))
+ tag_set(parent, tag, end);
+ /* rcu_assign_pointer ensures tags are set before RETRY */
+ rcu_assign_pointer(parent->slots[end], RADIX_TREE_RETRY);
+ }
+ rcu_assign_pointer(parent->slots[offset], RADIX_TREE_RETRY);
+ parent->exceptional -= (end - offset);
+
+ if (order == parent->shift)
+ return 0;
+ if (order > parent->shift) {
+ while (offset < end)
+ offset += insert_entries(parent, &parent->slots[offset],
+ RADIX_TREE_RETRY, order, true);
+ return 0;
+ }
+
+ node = parent;
+
+ for (;;) {
+ if (node->shift > order) {
+ child = radix_tree_node_alloc(root);
+ if (!child)
+ goto nomem;
+ child->shift = node->shift - RADIX_TREE_MAP_SHIFT;
+ child->offset = offset;
+ child->count = 0;
+ child->parent = node;
+ if (node != parent) {
+ node->count++;
+ node->slots[offset] = node_to_entry(child);
+ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
+ if (tags & (1 << tag))
+ tag_set(node, tag, offset);
+ }
+
+ node = child;
+ offset = 0;
+ continue;
+ }
+
+ n = insert_entries(node, &node->slots[offset],
+ RADIX_TREE_RETRY, order, false);
+ BUG_ON(n > RADIX_TREE_MAP_SIZE);
+
+ for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++)
+ if (tags & (1 << tag))
+ tag_set(node, tag, offset);
+ offset += n;
+
+ while (offset == RADIX_TREE_MAP_SIZE) {
+ if (node == parent)
+ break;
+ offset = node->offset;
+ child = node;
+ node = node->parent;
+ rcu_assign_pointer(node->slots[offset],
+ node_to_entry(child));
+ offset++;
+ }
+ if ((node == parent) && (offset == end))
+ return 0;
+ }
+
+ nomem:
+ /* Shouldn't happen; did user forget to preload? */
+ /* TODO: free all the allocated nodes */
+ WARN_ON(1);
+ return -ENOMEM;
+}
#endif
/**
@@ -1440,8 +1572,10 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
child = rcu_dereference_raw(node->slots[offset]);
}
- if ((child == NULL) || (child == RADIX_TREE_RETRY))
+ if (!child)
goto restart;
+ if (child == RADIX_TREE_RETRY)
+ break;
} while (radix_tree_is_internal_node(child));
/* Update the iterator state */
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c
index c9f656c..fa6effe 100644
--- a/tools/testing/radix-tree/multiorder.c
+++ b/tools/testing/radix-tree/multiorder.c
@@ -389,6 +389,69 @@ static void multiorder_join(void)
}
}
+static void __multiorder_split(int old_order, int new_order)
+{
+ RADIX_TREE(tree, GFP_KERNEL);
+ void **slot;
+ struct radix_tree_iter iter;
+ struct radix_tree_node *node;
+ void *item;
+
+ item_insert_order(&tree, 0, old_order);
+ radix_tree_tag_set(&tree, 0, 2);
+ radix_tree_split(&tree, 0, new_order);
+ radix_tree_for_each_slot(slot, &tree, &iter, 0) {
+ radix_tree_iter_replace(&tree, &iter, slot,
+ item_create(iter.index, new_order));
+ }
+
+ item_kill_tree(&tree);
+
+ __radix_tree_insert(&tree, 0, old_order, (void *)0x12);
+
+ item = __radix_tree_lookup(&tree, 0, &node, NULL);
+ assert(item == (void *)0x12);
+ assert(node->exceptional > 0);
+
+ radix_tree_split(&tree, 0, new_order);
+ radix_tree_for_each_slot(slot, &tree, &iter, 0) {
+ radix_tree_iter_replace(&tree, &iter, slot,
+ item_create(iter.index, new_order));
+ }
+
+ item = __radix_tree_lookup(&tree, 0, &node, NULL);
+ assert(item != (void *)0x12);
+ assert(node->exceptional == 0);
+
+ item_kill_tree(&tree);
+
+ __radix_tree_insert(&tree, 0, old_order, (void *)0x12);
+
+ item = __radix_tree_lookup(&tree, 0, &node, NULL);
+ assert(item == (void *)0x12);
+ assert(node->exceptional > 0);
+
+ radix_tree_split(&tree, 0, new_order);
+ radix_tree_for_each_slot(slot, &tree, &iter, 0) {
+ radix_tree_iter_replace(&tree, &iter, slot, (void *)0x16);
+ }
+
+ item = __radix_tree_lookup(&tree, 0, &node, NULL);
+ assert(item == (void *)0x16);
+ assert(node->exceptional > 0);
+
+ item_kill_tree(&tree);
+}
+
+static void multiorder_split(void)
+{
+ int i, j;
+
+ for (i = 9; i < 19; i++)
+ for (j = 0; j < i; j++)
+ __multiorder_split(i, j);
+}
+
void multiorder_checks(void)
{
int i;
@@ -407,4 +470,5 @@ void multiorder_checks(void)
multiorder_iteration();
multiorder_tagged_iteration();
multiorder_join();
+ multiorder_split();
}
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Randy Dunlap <rdunlap@infradead.org> |
|---|---|
| Date | 2016-11-29 01:10 +0100 |
| Subject | Re: [PATCH v3 24/33] radix-tree: Add radix_tree_split |
| Message-ID | <sIE9H-FF-7@gated-at.bofh.it> |
| In reply to | #1531637 |
On 11/28/16 13:50, Matthew Wilcox wrote: > From: Matthew Wilcox <willy@linux.intel.com> > > This new function splits a larger multiorder entry into smaller entries > (potentially multi-order entries). These entries are initialised to > RADIX_TREE_RETRY to ensure that RCU walkers who see this state aren't > confused. The caller should then call radix_tree_for_each_slot() and > radix_tree_replace_slot() in order to turn these retry entries into the > intended new entries. Tags are replicated from the original multiorder > entry into each new entry. > > Signed-off-by: Matthew Wilcox <willy@linux.intel.com> > --- > include/linux/radix-tree.h | 12 +++ > lib/radix-tree.c | 142 +++++++++++++++++++++++++++++++++- > tools/testing/radix-tree/multiorder.c | 64 +++++++++++++++ > 3 files changed, 214 insertions(+), 4 deletions(-) > > diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h > index 935293a..1f4b561 100644 > --- a/include/linux/radix-tree.h > +++ b/include/linux/radix-tree.h > @@ -293,6 +301,8 @@ void __radix_tree_replace(struct radix_tree_root *root, > struct radix_tree_node *node, > void **slot, void *item, > radix_tree_update_node_t update_node, void *private); > +void radix_tree_iter_replace(struct radix_tree_root *, > + const struct radix_tree_iter *, void **slot, void *item); above > void radix_tree_replace_slot(struct radix_tree_root *root, > void **slot, void *item); > void __radix_tree_delete_node(struct radix_tree_root *root, > @@ -335,6 +345,8 @@ static inline void radix_tree_preload_end(void) > preempt_enable(); > } > > +int radix_tree_split(struct radix_tree_root *, unsigned long index, > + unsigned new_order); and above: and in patch 25/33: Add radix_tree_split_preload() As indicated in CodingStyle: In function prototypes, include parameter names with their data types. Although this is not required by the C language, it is preferred in Linux because it is a simple way to add valuable information for the reader. > int radix_tree_join(struct radix_tree_root *, unsigned long index, > unsigned new_order, void *); > Yes, the source file already omits some function prototype parameter names, so these patches just follow that tradition. It's weird (to me) though that the existing code even mixes this style in one function prototype (see immed. above). Thanks. -- ~Randy
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@microsoft.com> |
|---|---|
| Date | 2016-11-29 16:00 +0100 |
| Subject | RE: [PATCH v3 24/33] radix-tree: Add radix_tree_split |
| Message-ID | <sIS30-1lb-21@gated-at.bofh.it> |
| In reply to | #1531811 |
From: Randy Dunlap [mailto:rdunlap@infradead.org] > > +void radix_tree_iter_replace(struct radix_tree_root *, > > + const struct radix_tree_iter *, void **slot, void *item); > > > +int radix_tree_split(struct radix_tree_root *, unsigned long index, > > + unsigned new_order); > > and above: > > As indicated in CodingStyle: > In function prototypes, include parameter names with their data types. > Although this is not required by the C language, it is preferred in Linux > because it is a simple way to add valuable information for the reader. I think the rule here should be a bit more nuanced. I think it is positively criminal to have an unnamed 'unsigned long' or 'bool' in a function prototype. But what extra information is communicated by adding 'root' after 'struct radix_tree_root *'? I know it's a root, you told me that with the structure name! Obviously sometimes it would be useful, for example if we had a function to move an entry from one radix tree to another, you might want to have 'struct radix_tree_root *old, struct radix_tree_root *new' as two of your parameters. > > int radix_tree_join(struct radix_tree_root *, unsigned long index, > > unsigned new_order, void *); > > Yes, the source file already omits some function prototype parameter names, > so these patches just follow that tradition. It's weird (to me) though that > the existing code even mixes this style in one function prototype (see > immed. above). I agree that void * should probably be named (as new_entry). Naming index and new_order is correct. But again, there's no useful information given by naming root.
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 15/33] radix-tree: Move rcu_head into a union with private_list |
| Message-ID | <sIAz9-6P8-51@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <willy@infradead.org>
I want to be able to reference node->parent after freeing node.
Currently node->parent is in a union with rcu_head, so it is overwritten
when the node is put on the RCU list. We know that private_list is not
referenced after the node is freed, so it is safe for these two members
to share space.
Signed-off-by: Matthew Wilcox <willy@infradead.org>
---
include/linux/radix-tree.h | 14 ++++----------
lib/radix-tree.c | 1 +
2 files changed, 5 insertions(+), 10 deletions(-)
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h
index 7444860..d04073a 100644
--- a/include/linux/radix-tree.h
+++ b/include/linux/radix-tree.h
@@ -85,18 +85,12 @@ struct radix_tree_node {
unsigned char offset; /* Slot offset in parent */
unsigned char count; /* Total entry count */
unsigned char exceptional; /* Exceptional entry count */
+ struct radix_tree_node *parent; /* Used when ascending tree */
+ void *private_data; /* For tree user */
union {
- struct {
- /* Used when ascending tree */
- struct radix_tree_node *parent;
- /* For tree user */
- void *private_data;
- };
- /* Used when freeing node */
- struct rcu_head rcu_head;
+ struct list_head private_list; /* For tree user */
+ struct rcu_head rcu_head; /* Used when freeing node */
};
- /* For tree user */
- struct list_head private_list;
void __rcu *slots[RADIX_TREE_MAP_SIZE];
unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS];
};
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index b329056..3f49417 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -324,6 +324,7 @@ static void radix_tree_node_rcu_free(struct rcu_head *head)
tag_clear(node, i, 0);
node->slots[0] = NULL;
+ INIT_LIST_HEAD(&node->private_list);
kmem_cache_free(radix_tree_node_cachep, node);
}
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 11/33] radix tree test suite: record order in each item |
| Message-ID | <sIAz8-6P8-39@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <mawilcox@microsoft.com>
This probably doubles the size of each item allocated by the test suite
but it lets us check a few more things, and may be needed for upcoming
API changes that require the caller pass in the order of the entry.
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
---
tools/testing/radix-tree/multiorder.c | 2 +-
tools/testing/radix-tree/test.c | 29 +++++++++++++++++++----------
tools/testing/radix-tree/test.h | 6 +++---
3 files changed, 23 insertions(+), 14 deletions(-)
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c
index d1be946..8d5865c 100644
--- a/tools/testing/radix-tree/multiorder.c
+++ b/tools/testing/radix-tree/multiorder.c
@@ -125,7 +125,7 @@ static void multiorder_check(unsigned long index, int order)
unsigned long min = index & ~((1UL << order) - 1);
unsigned long max = min + (1UL << order);
void **slot;
- struct item *item2 = item_create(min);
+ struct item *item2 = item_create(min, order);
RADIX_TREE(tree, GFP_KERNEL);
printf("Multiorder index %ld, order %d\n", index, order);
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c
index 6f8dafc..0de5489 100644
--- a/tools/testing/radix-tree/test.c
+++ b/tools/testing/radix-tree/test.c
@@ -24,21 +24,29 @@ int item_tag_get(struct radix_tree_root *root, unsigned long index, int tag)
return radix_tree_tag_get(root, index, tag);
}
-int __item_insert(struct radix_tree_root *root, struct item *item,
- unsigned order)
+int __item_insert(struct radix_tree_root *root, struct item *item)
{
- return __radix_tree_insert(root, item->index, order, item);
+ return __radix_tree_insert(root, item->index, item->order, item);
}
int item_insert(struct radix_tree_root *root, unsigned long index)
{
- return __item_insert(root, item_create(index), 0);
+ return __item_insert(root, item_create(index, 0));
}
int item_insert_order(struct radix_tree_root *root, unsigned long index,
unsigned order)
{
- return __item_insert(root, item_create(index), order);
+ return __item_insert(root, item_create(index, order));
+}
+
+void item_sanity(struct item *item, unsigned long index)
+{
+ unsigned long mask;
+ assert(!radix_tree_is_internal_node(item));
+ assert(item->order < BITS_PER_LONG);
+ mask = (1UL << item->order) - 1;
+ assert((item->index | mask) == (index | mask));
}
int item_delete(struct radix_tree_root *root, unsigned long index)
@@ -46,18 +54,19 @@ int item_delete(struct radix_tree_root *root, unsigned long index)
struct item *item = radix_tree_delete(root, index);
if (item) {
- assert(item->index == index);
+ item_sanity(item, index);
free(item);
return 1;
}
return 0;
}
-struct item *item_create(unsigned long index)
+struct item *item_create(unsigned long index, unsigned int order)
{
struct item *ret = malloc(sizeof(*ret));
ret->index = index;
+ ret->order = order;
return ret;
}
@@ -66,8 +75,8 @@ void item_check_present(struct radix_tree_root *root, unsigned long index)
struct item *item;
item = radix_tree_lookup(root, index);
- assert(item != 0);
- assert(item->index == index);
+ assert(item != NULL);
+ item_sanity(item, index);
}
struct item *item_lookup(struct radix_tree_root *root, unsigned long index)
@@ -80,7 +89,7 @@ void item_check_absent(struct radix_tree_root *root, unsigned long index)
struct item *item;
item = radix_tree_lookup(root, index);
- assert(item == 0);
+ assert(item == NULL);
}
/*
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h
index 215ab77..423c528 100644
--- a/tools/testing/radix-tree/test.h
+++ b/tools/testing/radix-tree/test.h
@@ -5,11 +5,11 @@
struct item {
unsigned long index;
+ unsigned int order;
};
-struct item *item_create(unsigned long index);
-int __item_insert(struct radix_tree_root *root, struct item *item,
- unsigned order);
+struct item *item_create(unsigned long index, unsigned int order);
+int __item_insert(struct radix_tree_root *root, struct item *item);
int item_insert(struct radix_tree_root *root, unsigned long index);
int item_insert_order(struct radix_tree_root *root, unsigned long index,
unsigned order);
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 01/33] radix tree test suite: Fix compilation |
| Message-ID | <sIAz9-6P8-61@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <mawilcox@microsoft.com> Patch "lib/radix-tree: Convert to hotplug state machine" breaks the test suite as it adds a call to cpuhp_setup_state_nocalls() which is not currently emulated in the test suite. Add it, and delete the emulation of the old CPU hotplug mechanism. Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com> --- lib/radix-tree.c | 1 - tools/testing/radix-tree/linux/cpu.h | 22 +--------------------- tools/testing/radix-tree/linux/notifier.h | 8 -------- 3 files changed, 1 insertion(+), 30 deletions(-) delete mode 100644 tools/testing/radix-tree/linux/notifier.h diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 2e8c6f7..e0290d1 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c @@ -30,7 +30,6 @@ #include <linux/percpu.h> #include <linux/slab.h> #include <linux/kmemleak.h> -#include <linux/notifier.h> #include <linux/cpu.h> #include <linux/string.h> #include <linux/bitops.h> diff --git a/tools/testing/radix-tree/linux/cpu.h b/tools/testing/radix-tree/linux/cpu.h index 7cf4121..a45530d 100644 --- a/tools/testing/radix-tree/linux/cpu.h +++ b/tools/testing/radix-tree/linux/cpu.h @@ -1,21 +1 @@ - -#define hotcpu_notifier(a, b) - -#define CPU_ONLINE 0x0002 /* CPU (unsigned)v is up */ -#define CPU_UP_PREPARE 0x0003 /* CPU (unsigned)v coming up */ -#define CPU_UP_CANCELED 0x0004 /* CPU (unsigned)v NOT coming up */ -#define CPU_DOWN_PREPARE 0x0005 /* CPU (unsigned)v going down */ -#define CPU_DOWN_FAILED 0x0006 /* CPU (unsigned)v NOT going down */ -#define CPU_DEAD 0x0007 /* CPU (unsigned)v dead */ -#define CPU_POST_DEAD 0x0009 /* CPU (unsigned)v dead, cpu_hotplug - * lock is dropped */ -#define CPU_BROKEN 0x000C /* CPU (unsigned)v did not die properly, - * perhaps due to preemption. */ -#define CPU_TASKS_FROZEN 0x0010 - -#define CPU_ONLINE_FROZEN (CPU_ONLINE | CPU_TASKS_FROZEN) -#define CPU_UP_PREPARE_FROZEN (CPU_UP_PREPARE | CPU_TASKS_FROZEN) -#define CPU_UP_CANCELED_FROZEN (CPU_UP_CANCELED | CPU_TASKS_FROZEN) -#define CPU_DOWN_PREPARE_FROZEN (CPU_DOWN_PREPARE | CPU_TASKS_FROZEN) -#define CPU_DOWN_FAILED_FROZEN (CPU_DOWN_FAILED | CPU_TASKS_FROZEN) -#define CPU_DEAD_FROZEN (CPU_DEAD | CPU_TASKS_FROZEN) +#define cpuhp_setup_state_nocalls(a, b, c, d) (0) diff --git a/tools/testing/radix-tree/linux/notifier.h b/tools/testing/radix-tree/linux/notifier.h deleted file mode 100644 index 70e4797..0000000 --- a/tools/testing/radix-tree/linux/notifier.h +++ /dev/null @@ -1,8 +0,0 @@ -#ifndef _NOTIFIER_H -#define _NOTIFIER_H - -struct notifier_block; - -#define NOTIFY_OK 0x0001 /* Suits me */ - -#endif -- 2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 08/33] radix tree test suite: benchmark for iterator |
| Message-ID | <sIAz9-6P8-63@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Konstantin Khlebnikov <koct9i@gmail.com>
This adds simple benchmark for iterator similar to one I've used for
commit 78c1d78 ("radix-tree: introduce bit-optimized iterator")
Building with make BENCHMARK=1 set radix tree order to 6, this allows
to get performance comparable to in kernel performance.
Signed-off-by: Konstantin Khlebnikov <koct9i@gmail.com>
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
---
tools/testing/radix-tree/Makefile | 6 +-
tools/testing/radix-tree/benchmark.c | 98 +++++++++++++++++++++++++++++++++
tools/testing/radix-tree/linux/kernel.h | 4 ++
tools/testing/radix-tree/main.c | 2 +
tools/testing/radix-tree/test.h | 1 +
5 files changed, 110 insertions(+), 1 deletion(-)
create mode 100644 tools/testing/radix-tree/benchmark.c
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile
index 3c338dc..08283a8 100644
--- a/tools/testing/radix-tree/Makefile
+++ b/tools/testing/radix-tree/Makefile
@@ -4,7 +4,11 @@ LDFLAGS += -lpthread -lurcu
TARGETS = main
OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \
regression1.o regression2.o regression3.o multiorder.o \
- iteration_check.o
+ iteration_check.o benchmark.o
+
+ifdef BENCHMARK
+ CFLAGS += -DBENCHMARK=1
+endif
targets: $(TARGETS)
diff --git a/tools/testing/radix-tree/benchmark.c b/tools/testing/radix-tree/benchmark.c
new file mode 100644
index 0000000..215ca86
--- /dev/null
+++ b/tools/testing/radix-tree/benchmark.c
@@ -0,0 +1,98 @@
+/*
+ * benchmark.c:
+ * Author: Konstantin Khlebnikov <koct9i@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
+ * more details.
+ */
+#include <linux/radix-tree.h>
+#include <linux/slab.h>
+#include <linux/errno.h>
+#include <time.h>
+#include "test.h"
+
+#define NSEC_PER_SEC 1000000000L
+
+static long long benchmark_iter(struct radix_tree_root *root, bool tagged)
+{
+ volatile unsigned long sink = 0;
+ struct radix_tree_iter iter;
+ struct timespec start, finish;
+ long long nsec;
+ int l, loops = 1;
+ void **slot;
+
+#ifdef BENCHMARK
+again:
+#endif
+ clock_gettime(CLOCK_MONOTONIC, &start);
+ for (l = 0; l < loops; l++) {
+ if (tagged) {
+ radix_tree_for_each_tagged(slot, root, &iter, 0, 0)
+ sink ^= (unsigned long)slot;
+ } else {
+ radix_tree_for_each_slot(slot, root, &iter, 0)
+ sink ^= (unsigned long)slot;
+ }
+ }
+ clock_gettime(CLOCK_MONOTONIC, &finish);
+
+ nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC +
+ (finish.tv_nsec - start.tv_nsec);
+
+#ifdef BENCHMARK
+ if (loops == 1 && nsec * 5 < NSEC_PER_SEC) {
+ loops = NSEC_PER_SEC / nsec / 4 + 1;
+ goto again;
+ }
+#endif
+
+ nsec /= loops;
+ return nsec;
+}
+
+static void benchmark_size(unsigned long size, unsigned long step, int order)
+{
+ RADIX_TREE(tree, GFP_KERNEL);
+ long long normal, tagged;
+ unsigned long index;
+
+ for (index = 0 ; index < size ; index += step) {
+ item_insert_order(&tree, index, order);
+ radix_tree_tag_set(&tree, index, 0);
+ }
+
+ tagged = benchmark_iter(&tree, true);
+ normal = benchmark_iter(&tree, false);
+
+ printf("Size %ld, step %6ld, order %d tagged %10lld ns, normal %10lld ns\n",
+ size, step, order, tagged, normal);
+
+ item_kill_tree(&tree);
+ rcu_barrier();
+}
+
+void benchmark(void)
+{
+ unsigned long size[] = {1 << 10, 1 << 20, 0};
+ unsigned long step[] = {1, 2, 7, 15, 63, 64, 65,
+ 128, 256, 512, 12345, 0};
+ int c, s;
+
+ printf("starting benchmarks\n");
+ printf("RADIX_TREE_MAP_SHIFT = %d\n", RADIX_TREE_MAP_SHIFT);
+
+ for (c = 0; size[c]; c++)
+ for (s = 0; step[s]; s++)
+ benchmark_size(size[c], step[s], 0);
+
+ for (c = 0; size[c]; c++)
+ for (s = 0; step[s]; s++)
+ benchmark_size(size[c], step[s] << 9, 9);
+}
diff --git a/tools/testing/radix-tree/linux/kernel.h b/tools/testing/radix-tree/linux/kernel.h
index be98a47..dbe4b92 100644
--- a/tools/testing/radix-tree/linux/kernel.h
+++ b/tools/testing/radix-tree/linux/kernel.h
@@ -10,7 +10,11 @@
#include "../../include/linux/compiler.h"
#include "../../../include/linux/kconfig.h"
+#ifdef BENCHMARK
+#define RADIX_TREE_MAP_SHIFT 6
+#else
#define RADIX_TREE_MAP_SHIFT 3
+#endif
#ifndef NULL
#define NULL 0
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c
index 2eb6949..f1d1e3b 100644
--- a/tools/testing/radix-tree/main.c
+++ b/tools/testing/radix-tree/main.c
@@ -352,6 +352,8 @@ int main(int argc, char **argv)
/* Free any remaining preallocated nodes */
radix_tree_cpu_dead(0);
+ benchmark();
+
sleep(1);
printf("after sleep(1): %d allocated, preempt %d\n",
nr_allocated, preempt_count);
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h
index 5d2fad0..215ab77 100644
--- a/tools/testing/radix-tree/test.h
+++ b/tools/testing/radix-tree/test.h
@@ -28,6 +28,7 @@ void item_kill_tree(struct radix_tree_root *root);
void tag_check(void);
void multiorder_checks(void);
void iteration_test(void);
+void benchmark(void);
struct item *
item_tag_set(struct radix_tree_root *root, unsigned long index, int tag);
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 17/33] radix-tree: Make radix_tree_find_next_bit more useful |
| Message-ID | <sIAz9-6P8-53@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <willy@linux.intel.com>
Since this function is specialised to the radix tree, pass in the node
and tag to calculate the address of the bitmap in radix_tree_find_next_bit()
instead of the caller. Likewise, there is no need to pass in the size of
the bitmap.
Signed-off-by: Matthew Wilcox <willy@infradead.org>
---
lib/radix-tree.c | 17 +++++++----------
1 file changed, 7 insertions(+), 10 deletions(-)
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index c72da89..01ed70b 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -190,13 +190,12 @@ static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag)
* Returns next bit offset, or size if nothing found.
*/
static __always_inline unsigned long
-radix_tree_find_next_bit(const unsigned long *addr,
- unsigned long size, unsigned long offset)
+radix_tree_find_next_bit(struct radix_tree_node *node, unsigned int tag,
+ unsigned long offset)
{
- if (!__builtin_constant_p(size))
- return find_next_bit(addr, size, offset);
+ const unsigned long *addr = node->tags[tag];
- if (offset < size) {
+ if (offset < RADIX_TREE_MAP_SIZE) {
unsigned long tmp;
addr += offset / BITS_PER_LONG;
@@ -204,14 +203,14 @@ radix_tree_find_next_bit(const unsigned long *addr,
if (tmp)
return __ffs(tmp) + offset;
offset = (offset + BITS_PER_LONG) & ~(BITS_PER_LONG - 1);
- while (offset < size) {
+ while (offset < RADIX_TREE_MAP_SIZE) {
tmp = *++addr;
if (tmp)
return __ffs(tmp) + offset;
offset += BITS_PER_LONG;
}
}
- return size;
+ return RADIX_TREE_MAP_SIZE;
}
#ifndef __KERNEL__
@@ -1159,9 +1158,7 @@ void **radix_tree_next_chunk(struct radix_tree_root *root,
return NULL;
if (flags & RADIX_TREE_ITER_TAGGED)
- offset = radix_tree_find_next_bit(
- node->tags[tag],
- RADIX_TREE_MAP_SIZE,
+ offset = radix_tree_find_next_bit(node, tag,
offset + 1);
else
while (++offset < RADIX_TREE_MAP_SIZE) {
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@linuxonhyperv.com> |
|---|---|
| Date | 2016-11-28 21:20 +0100 |
| Subject | [PATCH v3 10/33] radix tree test suite: Handle exceptional entries |
| Message-ID | <sIAz9-6P8-59@gated-at.bofh.it> |
| In reply to | #1531607 |
From: Matthew Wilcox <mawilcox@microsoft.com>
item_kill_tree() assumes that everything in the tree is a pointer to a
struct item, which is annoying when testing the behaviour of exceptional
entries. Fix it to delete exceptional entries on the assumption they
don't need to be freed.
Signed-off-by: Matthew Wilcox <mawilcox@microsoft.com>
---
tools/testing/radix-tree/test.c | 7 +++++++
1 file changed, 7 insertions(+)
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c
index a6e8099..6f8dafc 100644
--- a/tools/testing/radix-tree/test.c
+++ b/tools/testing/radix-tree/test.c
@@ -200,9 +200,16 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag)
void item_kill_tree(struct radix_tree_root *root)
{
+ struct radix_tree_iter iter;
+ void **slot;
struct item *items[32];
int nfound;
+ radix_tree_for_each_slot(slot, root, &iter, 0) {
+ if (radix_tree_exceptional_entry(*slot))
+ radix_tree_delete(root, iter.index);
+ }
+
while ((nfound = radix_tree_gang_lookup(root, (void **)items, 0, 32))) {
int i;
--
2.10.2
[toc] | [prev] | [next] | [standalone]
| From | "Kirill A. Shutemov" <kirill@shutemov.name> |
|---|---|
| Date | 2016-11-29 12:30 +0100 |
| Message-ID | <sIOLM-7NC-19@gated-at.bofh.it> |
| In reply to | #1531607 |
On Mon, Nov 28, 2016 at 01:50:04PM -0800, Matthew Wilcox wrote: > From: Matthew Wilcox <mawilcox@microsoft.com> > > Hi Andrew, > > Please include these patches in the -mm tree for 4.10. Mostly these > are improvements; the only bug fixes in here relate to multiorder > entries (which are unused in the 4.9 tree). The IDR rewrite has the > highest potential for causing mayhem as the test suite is quite spartan. > We have an Outreachy intern scheduled to work on the test suite for the > 2016 winter season, so hopefully it will improve soon. > > I did not include Konstantin's suggested change to the API for > radix_tree_iter_resume(). Many of the callers do not currently care > about the size of the entry they are consuming, and determining that > information is not always trivial. Since this is not a performance > critical API (it's called when we've paused iterating through a tree > in order to schedule for a higher priority task), I think it's more > important to have a simpler interface. > > I'd like to thank Kiryl for all the testing he's been doing. He's found > at least two bugs which weren't related to the API extensions that he > really wanted from this patch set. Tested-by: Kirill A. Shutemov <kirill.shutemov@linux.intel.com> I would like to get in as my ext4 patchset depends on this. -- Kirill A. Shutemov
[toc] | [prev] | [next] | [standalone]
| From | Andrew Morton <akpm@linux-foundation.org> |
|---|---|
| Date | 2016-12-06 21:50 +0100 |
| Subject | Re: [PATCH v3 33/33] Reimplement IDR and IDA using the radix tree |
| Message-ID | <sLuQx-6Vs-19@gated-at.bofh.it> |
| In reply to | #1531607 |
On Mon, 28 Nov 2016 13:50:37 -0800 Matthew Wilcox <mawilcox@linuxonhyperv.com> wrote: > The IDR is very similar to the radix tree. It has some functionality > that the radix tree did not have (alloc next free, cyclic allocation, > a callback-based for_each, destroy tree), which is readily implementable > on top of the radix tree. A few small changes were needed in order to > use a tag to represent nodes with free space below them. > > The IDA is reimplemented as a client of the newly enhanced radix tree. > As in the current implementation, it uses a bitmap at the last level of > the tree. > > Signed-off-by: Matthew Wilcox <willy@infradead.org> > --- > include/linux/idr.h | 132 ++-- > include/linux/radix-tree.h | 5 +- > init/main.c | 3 +- > lib/idr.c | 1078 ------------------------------- > lib/radix-tree.c | 632 ++++++++++++++++-- hm. It's just a cosmetic issue, but perhaps the idr wrappers-around-radix-tree code should be in a different .c file. Before: akpm3:/usr/src/25> size lib/idr.o lib/radix-tree.o text data bss dec hex filename 6566 89 16 6671 1a0f lib/idr.o 11811 117 8 11936 2ea0 lib/radix-tree.o After: text data bss dec hex filename 14151 118 8 14277 37c5 lib/radix-tree.o So 4500 bytes saved. Decent.
[toc] | [prev] | [next] | [standalone]
| From | Andrew Morton <akpm@linux-foundation.org> |
|---|---|
| Date | 2016-12-06 22:30 +0100 |
| Subject | Re: [PATCH v3 33/33] Reimplement IDR and IDA using the radix tree |
| Message-ID | <sLvtf-7oy-5@gated-at.bofh.it> |
| In reply to | #1537269 |
On Tue, 6 Dec 2016 21:17:52 +0000 Matthew Wilcox <mawilcox@microsoft.com> wrote: > From: Andrew Morton [mailto:akpm@linux-foundation.org] > > On Mon, 28 Nov 2016 13:50:37 -0800 Matthew Wilcox > > <mawilcox@linuxonhyperv.com> wrote: > > > include/linux/idr.h | 132 ++-- > > > include/linux/radix-tree.h | 5 +- > > > init/main.c | 3 +- > > > lib/idr.c | 1078 ------------------------------- > > > lib/radix-tree.c | 632 ++++++++++++++++-- > > > > hm. It's just a cosmetic issue, but perhaps the idr > > wrappers-around-radix-tree code should be in a different .c file. > > I can put some of them back into idr.c -- there's a couple of routines left in there still, so adding some more won't hurt. OK. Sometime. Let's see how this lot pans out as-is for now?
[toc] | [prev] | [next] | [standalone]
| From | Matthew Wilcox <mawilcox@microsoft.com> |
|---|---|
| Date | 2016-12-06 23:00 +0100 |
| Subject | RE: [PATCH v3 33/33] Reimplement IDR and IDA using the radix tree |
| Message-ID | <sLvtf-7oy-7@gated-at.bofh.it> |
| In reply to | #1537269 |
From: Andrew Morton [mailto:akpm@linux-foundation.org] > On Mon, 28 Nov 2016 13:50:37 -0800 Matthew Wilcox > <mawilcox@linuxonhyperv.com> wrote: > > include/linux/idr.h | 132 ++-- > > include/linux/radix-tree.h | 5 +- > > init/main.c | 3 +- > > lib/idr.c | 1078 ------------------------------- > > lib/radix-tree.c | 632 ++++++++++++++++-- > > hm. It's just a cosmetic issue, but perhaps the idr > wrappers-around-radix-tree code should be in a different .c file. I can put some of them back into idr.c -- there's a couple of routines left in there still, so adding some more won't hurt. > Before: > > akpm3:/usr/src/25> size lib/idr.o lib/radix-tree.o > text data bss dec hex filename > 6566 89 16 6671 1a0f lib/idr.o > 11811 117 8 11936 2ea0 lib/radix-tree.o > > After: > > text data bss dec hex filename > 14151 118 8 14277 37c5 lib/radix-tree.o > > > So 4500 bytes saved. Decent. Not bad. 0day has been sending me email telling me that I saved something more like 1500 bytes, but that's on a minimal config. (also a couple of routines stayed in idr.c, so you're overstating how much I saved)
[toc] | [prev] | [standalone]
Page 2 of 2 — ← Prev page 1 [2]
Back to top | Article view | linux.kernel
csiph-web