aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2016-12-14 20:25:18 -0500
committerLinus Torvalds <torvalds@linux-foundation.org>2016-12-14 20:25:18 -0500
commita57cb1c1d7974c62a5c80f7869e35b492ace12cd (patch)
tree5a42ee9a668f171143464bc86013954c1bbe94ad /tools
parentcf1b3341afab9d3ad02a76b3a619ea027dcf4e28 (diff)
parente1e14ab8411df344a17687821f8f78f0a1e73cbb (diff)
Merge branch 'akpm' (patches from Andrew)
Merge more updates from Andrew Morton: - a few misc things - kexec updates - DMA-mapping updates to better support networking DMA operations - IPC updates - various MM changes to improve DAX fault handling - lots of radix-tree changes, mainly to the test suite. All leading up to reimplementing the IDA/IDR code to be a wrapper layer over the radix-tree. However the final trigger-pulling patch is held off for 4.11. * emailed patches from Andrew Morton <akpm@linux-foundation.org>: (114 commits) radix tree test suite: delete unused rcupdate.c radix tree test suite: add new tag check radix-tree: ensure counts are initialised radix tree test suite: cache recently freed objects radix tree test suite: add some more functionality idr: reduce the number of bits per level from 8 to 6 rxrpc: abstract away knowledge of IDR internals tpm: use idr_find(), not idr_find_slowpath() idr: add ida_is_empty radix tree test suite: check multiorder iteration radix-tree: fix replacement for multiorder entries radix-tree: add radix_tree_split_preload() radix-tree: add radix_tree_split radix-tree: add radix_tree_join radix-tree: delete radix_tree_range_tag_if_tagged() radix-tree: delete radix_tree_locate_item() radix-tree: improve multiorder iterators btrfs: fix race in btrfs_free_dummy_fs_info() radix-tree: improve dump output radix-tree: make radix_tree_find_next_bit more useful ...
Diffstat (limited to 'tools')
-rw-r--r--tools/include/asm/bug.h11
-rw-r--r--tools/include/linux/bitmap.h26
-rwxr-xr-xtools/testing/ktest/ktest.pl8
-rw-r--r--tools/testing/radix-tree/Makefile15
-rw-r--r--tools/testing/radix-tree/benchmark.c98
-rw-r--r--tools/testing/radix-tree/find_next_bit.c57
-rw-r--r--tools/testing/radix-tree/iteration_check.c123
-rw-r--r--tools/testing/radix-tree/linux.c67
-rw-r--r--tools/testing/radix-tree/linux/bitops.h40
-rw-r--r--tools/testing/radix-tree/linux/bitops/non-atomic.h13
-rw-r--r--tools/testing/radix-tree/linux/bug.h2
-rw-r--r--tools/testing/radix-tree/linux/gfp.h22
-rw-r--r--tools/testing/radix-tree/linux/kernel.h18
-rw-r--r--tools/testing/radix-tree/linux/preempt.h6
-rw-r--r--tools/testing/radix-tree/linux/slab.h11
-rw-r--r--tools/testing/radix-tree/linux/types.h2
-rw-r--r--tools/testing/radix-tree/main.c77
-rw-r--r--tools/testing/radix-tree/multiorder.c326
-rw-r--r--tools/testing/radix-tree/rcupdate.c86
-rw-r--r--tools/testing/radix-tree/regression2.c3
-rw-r--r--tools/testing/radix-tree/regression3.c8
-rw-r--r--tools/testing/radix-tree/tag_check.c12
-rw-r--r--tools/testing/radix-tree/test.c92
-rw-r--r--tools/testing/radix-tree/test.h21
24 files changed, 842 insertions, 302 deletions
diff --git a/tools/include/asm/bug.h b/tools/include/asm/bug.h
index 9e5f4846967f..beda1a884b50 100644
--- a/tools/include/asm/bug.h
+++ b/tools/include/asm/bug.h
@@ -12,6 +12,17 @@
12 unlikely(__ret_warn_on); \ 12 unlikely(__ret_warn_on); \
13}) 13})
14 14
15#define WARN_ON_ONCE(condition) ({ \
16 static int __warned; \
17 int __ret_warn_once = !!(condition); \
18 \
19 if (unlikely(__ret_warn_once && !__warned)) { \
20 __warned = true; \
21 WARN_ON(1); \
22 } \
23 unlikely(__ret_warn_once); \
24})
25
15#define WARN_ONCE(condition, format...) ({ \ 26#define WARN_ONCE(condition, format...) ({ \
16 static int __warned; \ 27 static int __warned; \
17 int __ret_warn_once = !!(condition); \ 28 int __ret_warn_once = !!(condition); \
diff --git a/tools/include/linux/bitmap.h b/tools/include/linux/bitmap.h
index 43c1c5021e4b..eef41d500e9e 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)
35 } 35 }
36} 36}
37 37
38static inline void bitmap_fill(unsigned long *dst, unsigned int nbits)
39{
40 unsigned int nlongs = BITS_TO_LONGS(nbits);
41 if (!small_const_nbits(nbits)) {
42 unsigned int len = (nlongs - 1) * sizeof(unsigned long);
43 memset(dst, 0xff, len);
44 }
45 dst[nlongs - 1] = BITMAP_LAST_WORD_MASK(nbits);
46}
47
48static inline int bitmap_empty(const unsigned long *src, unsigned nbits)
49{
50 if (small_const_nbits(nbits))
51 return ! (*src & BITMAP_LAST_WORD_MASK(nbits));
52
53 return find_first_bit(src, nbits) == nbits;
54}
55
56static inline int bitmap_full(const unsigned long *src, unsigned int nbits)
57{
58 if (small_const_nbits(nbits))
59 return ! (~(*src) & BITMAP_LAST_WORD_MASK(nbits));
60
61 return find_first_zero_bit(src, nbits) == nbits;
62}
63
38static inline int bitmap_weight(const unsigned long *src, int nbits) 64static inline int bitmap_weight(const unsigned long *src, int nbits)
39{ 65{
40 if (small_const_nbits(nbits)) 66 if (small_const_nbits(nbits))
diff --git a/tools/testing/ktest/ktest.pl b/tools/testing/ktest/ktest.pl
index d08e214ec6e7..be93ab02b490 100755
--- a/tools/testing/ktest/ktest.pl
+++ b/tools/testing/ktest/ktest.pl
@@ -719,14 +719,14 @@ sub set_value {
719 719
720 if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") { 720 if ($buildonly && $lvalue =~ /^TEST_TYPE(\[.*\])?$/ && $prvalue ne "build") {
721 # Note if a test is something other than build, then we 721 # Note if a test is something other than build, then we
722 # will need other manditory options. 722 # will need other mandatory options.
723 if ($prvalue ne "install") { 723 if ($prvalue ne "install") {
724 # for bisect, we need to check BISECT_TYPE 724 # for bisect, we need to check BISECT_TYPE
725 if ($prvalue ne "bisect") { 725 if ($prvalue ne "bisect") {
726 $buildonly = 0; 726 $buildonly = 0;
727 } 727 }
728 } else { 728 } else {
729 # install still limits some manditory options. 729 # install still limits some mandatory options.
730 $buildonly = 2; 730 $buildonly = 2;
731 } 731 }
732 } 732 }
@@ -735,7 +735,7 @@ sub set_value {
735 if ($prvalue ne "install") { 735 if ($prvalue ne "install") {
736 $buildonly = 0; 736 $buildonly = 0;
737 } else { 737 } else {
738 # install still limits some manditory options. 738 # install still limits some mandatory options.
739 $buildonly = 2; 739 $buildonly = 2;
740 } 740 }
741 } 741 }
@@ -3989,7 +3989,7 @@ sub make_min_config {
3989 } 3989 }
3990 } 3990 }
3991 3991
3992 # Save off all the current mandidory configs 3992 # Save off all the current mandatory configs
3993 open (OUT, ">$temp_config") 3993 open (OUT, ">$temp_config")
3994 or die "Can't write to $temp_config"; 3994 or die "Can't write to $temp_config";
3995 foreach my $config (keys %keep_configs) { 3995 foreach my $config (keys %keep_configs) {
diff --git a/tools/testing/radix-tree/Makefile b/tools/testing/radix-tree/Makefile
index f2e07f2fd4b4..3635e4d3eca7 100644
--- a/tools/testing/radix-tree/Makefile
+++ b/tools/testing/radix-tree/Makefile
@@ -1,10 +1,14 @@
1 1
2CFLAGS += -I. -g -O2 -Wall -D_LGPL_SOURCE 2CFLAGS += -I. -I../../include -g -O2 -Wall -D_LGPL_SOURCE
3LDFLAGS += -lpthread -lurcu 3LDFLAGS += -lpthread -lurcu
4TARGETS = main 4TARGETS = main
5OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \ 5OFILES = main.o radix-tree.o linux.o test.o tag_check.o find_next_bit.o \
6 regression1.o regression2.o regression3.o multiorder.o \ 6 regression1.o regression2.o regression3.o multiorder.o \
7 iteration_check.o 7 iteration_check.o benchmark.o
8
9ifdef BENCHMARK
10 CFLAGS += -DBENCHMARK=1
11endif
8 12
9targets: $(TARGETS) 13targets: $(TARGETS)
10 14
@@ -14,7 +18,12 @@ main: $(OFILES)
14clean: 18clean:
15 $(RM) -f $(TARGETS) *.o radix-tree.c 19 $(RM) -f $(TARGETS) *.o radix-tree.c
16 20
17$(OFILES): *.h */*.h ../../../include/linux/radix-tree.h ../../include/linux/*.h 21find_next_bit.o: ../../lib/find_bit.c
22 $(CC) $(CFLAGS) -c -o $@ $<
23
24$(OFILES): *.h */*.h \
25 ../../include/linux/*.h \
26 ../../../include/linux/radix-tree.h
18 27
19radix-tree.c: ../../../lib/radix-tree.c 28radix-tree.c: ../../../lib/radix-tree.c
20 sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@ 29 sed -e 's/^static //' -e 's/__always_inline //' -e 's/inline //' < $< > $@
diff --git a/tools/testing/radix-tree/benchmark.c b/tools/testing/radix-tree/benchmark.c
new file mode 100644
index 000000000000..215ca86c7605
--- /dev/null
+++ b/tools/testing/radix-tree/benchmark.c
@@ -0,0 +1,98 @@
1/*
2 * benchmark.c:
3 * Author: Konstantin Khlebnikov <koct9i@gmail.com>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14#include <linux/radix-tree.h>
15#include <linux/slab.h>
16#include <linux/errno.h>
17#include <time.h>
18#include "test.h"
19
20#define NSEC_PER_SEC 1000000000L
21
22static long long benchmark_iter(struct radix_tree_root *root, bool tagged)
23{
24 volatile unsigned long sink = 0;
25 struct radix_tree_iter iter;
26 struct timespec start, finish;
27 long long nsec;
28 int l, loops = 1;
29 void **slot;
30
31#ifdef BENCHMARK
32again:
33#endif
34 clock_gettime(CLOCK_MONOTONIC, &start);
35 for (l = 0; l < loops; l++) {
36 if (tagged) {
37 radix_tree_for_each_tagged(slot, root, &iter, 0, 0)
38 sink ^= (unsigned long)slot;
39 } else {
40 radix_tree_for_each_slot(slot, root, &iter, 0)
41 sink ^= (unsigned long)slot;
42 }
43 }
44 clock_gettime(CLOCK_MONOTONIC, &finish);
45
46 nsec = (finish.tv_sec - start.tv_sec) * NSEC_PER_SEC +
47 (finish.tv_nsec - start.tv_nsec);
48
49#ifdef BENCHMARK
50 if (loops == 1 && nsec * 5 < NSEC_PER_SEC) {
51 loops = NSEC_PER_SEC / nsec / 4 + 1;
52 goto again;
53 }
54#endif
55
56 nsec /= loops;
57 return nsec;
58}
59
60static void benchmark_size(unsigned long size, unsigned long step, int order)
61{
62 RADIX_TREE(tree, GFP_KERNEL);
63 long long normal, tagged;
64 unsigned long index;
65
66 for (index = 0 ; index < size ; index += step) {
67 item_insert_order(&tree, index, order);
68 radix_tree_tag_set(&tree, index, 0);
69 }
70
71 tagged = benchmark_iter(&tree, true);
72 normal = benchmark_iter(&tree, false);
73
74 printf("Size %ld, step %6ld, order %d tagged %10lld ns, normal %10lld ns\n",
75 size, step, order, tagged, normal);
76
77 item_kill_tree(&tree);
78 rcu_barrier();
79}
80
81void benchmark(void)
82{
83 unsigned long size[] = {1 << 10, 1 << 20, 0};
84 unsigned long step[] = {1, 2, 7, 15, 63, 64, 65,
85 128, 256, 512, 12345, 0};
86 int c, s;
87
88 printf("starting benchmarks\n");
89 printf("RADIX_TREE_MAP_SHIFT = %d\n", RADIX_TREE_MAP_SHIFT);
90
91 for (c = 0; size[c]; c++)
92 for (s = 0; step[s]; s++)
93 benchmark_size(size[c], step[s], 0);
94
95 for (c = 0; size[c]; c++)
96 for (s = 0; step[s]; s++)
97 benchmark_size(size[c], step[s] << 9, 9);
98}
diff --git a/tools/testing/radix-tree/find_next_bit.c b/tools/testing/radix-tree/find_next_bit.c
deleted file mode 100644
index d1c2178bb2d4..000000000000
--- a/tools/testing/radix-tree/find_next_bit.c
+++ /dev/null
@@ -1,57 +0,0 @@
1/* find_next_bit.c: fallback find next bit implementation
2 *
3 * Copyright (C) 2004 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License
8 * as published by the Free Software Foundation; either version
9 * 2 of the License, or (at your option) any later version.
10 */
11
12#include <linux/types.h>
13#include <linux/bitops.h>
14
15#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
16
17/*
18 * Find the next set bit in a memory region.
19 */
20unsigned long find_next_bit(const unsigned long *addr, unsigned long size,
21 unsigned long offset)
22{
23 const unsigned long *p = addr + BITOP_WORD(offset);
24 unsigned long result = offset & ~(BITS_PER_LONG-1);
25 unsigned long tmp;
26
27 if (offset >= size)
28 return size;
29 size -= result;
30 offset %= BITS_PER_LONG;
31 if (offset) {
32 tmp = *(p++);
33 tmp &= (~0UL << offset);
34 if (size < BITS_PER_LONG)
35 goto found_first;
36 if (tmp)
37 goto found_middle;
38 size -= BITS_PER_LONG;
39 result += BITS_PER_LONG;
40 }
41 while (size & ~(BITS_PER_LONG-1)) {
42 if ((tmp = *(p++)))
43 goto found_middle;
44 result += BITS_PER_LONG;
45 size -= BITS_PER_LONG;
46 }
47 if (!size)
48 return result;
49 tmp = *p;
50
51found_first:
52 tmp &= (~0UL >> (BITS_PER_LONG - size));
53 if (tmp == 0UL) /* Are any bits set? */
54 return result + size; /* Nope. */
55found_middle:
56 return result + __ffs(tmp);
57}
diff --git a/tools/testing/radix-tree/iteration_check.c b/tools/testing/radix-tree/iteration_check.c
index 9adb8e7415a6..7572b7ed930e 100644
--- a/tools/testing/radix-tree/iteration_check.c
+++ b/tools/testing/radix-tree/iteration_check.c
@@ -16,35 +16,50 @@
16#include <pthread.h> 16#include <pthread.h>
17#include "test.h" 17#include "test.h"
18 18
19#define NUM_THREADS 4 19#define NUM_THREADS 5
20#define TAG 0 20#define MAX_IDX 100
21#define TAG 0
22#define NEW_TAG 1
23
21static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER; 24static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER;
22static pthread_t threads[NUM_THREADS]; 25static pthread_t threads[NUM_THREADS];
23RADIX_TREE(tree, GFP_KERNEL); 26static unsigned int seeds[3];
24bool test_complete; 27static RADIX_TREE(tree, GFP_KERNEL);
28static bool test_complete;
29static int max_order;
25 30
26/* relentlessly fill the tree with tagged entries */ 31/* relentlessly fill the tree with tagged entries */
27static void *add_entries_fn(void *arg) 32static void *add_entries_fn(void *arg)
28{ 33{
29 int pgoff; 34 rcu_register_thread();
30 35
31 while (!test_complete) { 36 while (!test_complete) {
32 for (pgoff = 0; pgoff < 100; pgoff++) { 37 unsigned long pgoff;
38 int order;
39
40 for (pgoff = 0; pgoff < MAX_IDX; pgoff++) {
33 pthread_mutex_lock(&tree_lock); 41 pthread_mutex_lock(&tree_lock);
34 if (item_insert(&tree, pgoff) == 0) 42 for (order = max_order; order >= 0; order--) {
35 item_tag_set(&tree, pgoff, TAG); 43 if (item_insert_order(&tree, pgoff, order)
44 == 0) {
45 item_tag_set(&tree, pgoff, TAG);
46 break;
47 }
48 }
36 pthread_mutex_unlock(&tree_lock); 49 pthread_mutex_unlock(&tree_lock);
37 } 50 }
38 } 51 }
39 52
53 rcu_unregister_thread();
54
40 return NULL; 55 return NULL;
41} 56}
42 57
43/* 58/*
44 * Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find 59 * Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find
45 * things that have been removed and randomly resetting our iteration to the 60 * things that have been removed and randomly resetting our iteration to the
46 * next chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and 61 * next chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and
47 * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a 62 * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a
48 * NULL 'slot' variable. 63 * NULL 'slot' variable.
49 */ 64 */
50static void *tagged_iteration_fn(void *arg) 65static void *tagged_iteration_fn(void *arg)
@@ -52,17 +67,12 @@ static void *tagged_iteration_fn(void *arg)
52 struct radix_tree_iter iter; 67 struct radix_tree_iter iter;
53 void **slot; 68 void **slot;
54 69
70 rcu_register_thread();
71
55 while (!test_complete) { 72 while (!test_complete) {
56 rcu_read_lock(); 73 rcu_read_lock();
57 radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) { 74 radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) {
58 void *entry; 75 void *entry = radix_tree_deref_slot(slot);
59 int i;
60
61 /* busy wait to let removals happen */
62 for (i = 0; i < 1000000; i++)
63 ;
64
65 entry = radix_tree_deref_slot(slot);
66 if (unlikely(!entry)) 76 if (unlikely(!entry))
67 continue; 77 continue;
68 78
@@ -71,20 +81,26 @@ static void *tagged_iteration_fn(void *arg)
71 continue; 81 continue;
72 } 82 }
73 83
74 if (rand() % 50 == 0) 84 if (rand_r(&seeds[0]) % 50 == 0) {
75 slot = radix_tree_iter_next(&iter); 85 slot = radix_tree_iter_resume(slot, &iter);
86 rcu_read_unlock();
87 rcu_barrier();
88 rcu_read_lock();
89 }
76 } 90 }
77 rcu_read_unlock(); 91 rcu_read_unlock();
78 } 92 }
79 93
94 rcu_unregister_thread();
95
80 return NULL; 96 return NULL;
81} 97}
82 98
83/* 99/*
84 * Iterate over the entries, doing a radix_tree_iter_retry() as we find things 100 * Iterate over the entries, doing a radix_tree_iter_retry() as we find things
85 * that have been removed and randomly resetting our iteration to the next 101 * that have been removed and randomly resetting our iteration to the next
86 * chunk with radix_tree_iter_next(). Both radix_tree_iter_retry() and 102 * chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and
87 * radix_tree_iter_next() cause radix_tree_next_slot() to be called with a 103 * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a
88 * NULL 'slot' variable. 104 * NULL 'slot' variable.
89 */ 105 */
90static void *untagged_iteration_fn(void *arg) 106static void *untagged_iteration_fn(void *arg)
@@ -92,17 +108,12 @@ static void *untagged_iteration_fn(void *arg)
92 struct radix_tree_iter iter; 108 struct radix_tree_iter iter;
93 void **slot; 109 void **slot;
94 110
111 rcu_register_thread();
112
95 while (!test_complete) { 113 while (!test_complete) {
96 rcu_read_lock(); 114 rcu_read_lock();
97 radix_tree_for_each_slot(slot, &tree, &iter, 0) { 115 radix_tree_for_each_slot(slot, &tree, &iter, 0) {
98 void *entry; 116 void *entry = radix_tree_deref_slot(slot);
99 int i;
100
101 /* busy wait to let removals happen */
102 for (i = 0; i < 1000000; i++)
103 ;
104
105 entry = radix_tree_deref_slot(slot);
106 if (unlikely(!entry)) 117 if (unlikely(!entry))
107 continue; 118 continue;
108 119
@@ -111,12 +122,18 @@ static void *untagged_iteration_fn(void *arg)
111 continue; 122 continue;
112 } 123 }
113 124
114 if (rand() % 50 == 0) 125 if (rand_r(&seeds[1]) % 50 == 0) {
115 slot = radix_tree_iter_next(&iter); 126 slot = radix_tree_iter_resume(slot, &iter);
127 rcu_read_unlock();
128 rcu_barrier();
129 rcu_read_lock();
130 }
116 } 131 }
117 rcu_read_unlock(); 132 rcu_read_unlock();
118 } 133 }
119 134
135 rcu_unregister_thread();
136
120 return NULL; 137 return NULL;
121} 138}
122 139
@@ -126,47 +143,71 @@ static void *untagged_iteration_fn(void *arg)
126 */ 143 */
127static void *remove_entries_fn(void *arg) 144static void *remove_entries_fn(void *arg)
128{ 145{
146 rcu_register_thread();
147
129 while (!test_complete) { 148 while (!test_complete) {
130 int pgoff; 149 int pgoff;
131 150
132 pgoff = rand() % 100; 151 pgoff = rand_r(&seeds[2]) % MAX_IDX;
133 152
134 pthread_mutex_lock(&tree_lock); 153 pthread_mutex_lock(&tree_lock);
135 item_delete(&tree, pgoff); 154 item_delete(&tree, pgoff);
136 pthread_mutex_unlock(&tree_lock); 155 pthread_mutex_unlock(&tree_lock);
137 } 156 }
138 157
158 rcu_unregister_thread();
159
160 return NULL;
161}
162
163static void *tag_entries_fn(void *arg)
164{
165 rcu_register_thread();
166
167 while (!test_complete) {
168 tag_tagged_items(&tree, &tree_lock, 0, MAX_IDX, 10, TAG,
169 NEW_TAG);
170 }
171 rcu_unregister_thread();
139 return NULL; 172 return NULL;
140} 173}
141 174
142/* This is a unit test for a bug found by the syzkaller tester */ 175/* This is a unit test for a bug found by the syzkaller tester */
143void iteration_test(void) 176void iteration_test(unsigned order, unsigned test_duration)
144{ 177{
145 int i; 178 int i;
146 179
147 printf("Running iteration tests for 10 seconds\n"); 180 printf("Running %siteration tests for %d seconds\n",
181 order > 0 ? "multiorder " : "", test_duration);
148 182
149 srand(time(0)); 183 max_order = order;
150 test_complete = false; 184 test_complete = false;
151 185
186 for (i = 0; i < 3; i++)
187 seeds[i] = rand();
188
152 if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) { 189 if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) {
153 perror("pthread_create"); 190 perror("create tagged iteration thread");
154 exit(1); 191 exit(1);
155 } 192 }
156 if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) { 193 if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) {
157 perror("pthread_create"); 194 perror("create untagged iteration thread");
158 exit(1); 195 exit(1);
159 } 196 }
160 if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) { 197 if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) {
161 perror("pthread_create"); 198 perror("create add entry thread");
162 exit(1); 199 exit(1);
163 } 200 }
164 if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) { 201 if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) {
165 perror("pthread_create"); 202 perror("create remove entry thread");
203 exit(1);
204 }
205 if (pthread_create(&threads[4], NULL, tag_entries_fn, NULL)) {
206 perror("create tag entry thread");
166 exit(1); 207 exit(1);
167 } 208 }
168 209
169 sleep(10); 210 sleep(test_duration);
170 test_complete = true; 211 test_complete = true;
171 212
172 for (i = 0; i < NUM_THREADS; i++) { 213 for (i = 0; i < NUM_THREADS; i++) {
diff --git a/tools/testing/radix-tree/linux.c b/tools/testing/radix-tree/linux.c
index 154823737b20..d31ea7c9abec 100644
--- a/tools/testing/radix-tree/linux.c
+++ b/tools/testing/radix-tree/linux.c
@@ -1,14 +1,26 @@
1#include <stdlib.h> 1#include <stdlib.h>
2#include <string.h> 2#include <string.h>
3#include <malloc.h> 3#include <malloc.h>
4#include <pthread.h>
4#include <unistd.h> 5#include <unistd.h>
5#include <assert.h> 6#include <assert.h>
6 7
7#include <linux/mempool.h> 8#include <linux/mempool.h>
9#include <linux/poison.h>
8#include <linux/slab.h> 10#include <linux/slab.h>
11#include <linux/radix-tree.h>
9#include <urcu/uatomic.h> 12#include <urcu/uatomic.h>
10 13
11int nr_allocated; 14int nr_allocated;
15int preempt_count;
16
17struct kmem_cache {
18 pthread_mutex_t lock;
19 int size;
20 int nr_objs;
21 void *objs;
22 void (*ctor)(void *);
23};
12 24
13void *mempool_alloc(mempool_t *pool, int gfp_mask) 25void *mempool_alloc(mempool_t *pool, int gfp_mask)
14{ 26{
@@ -33,19 +45,59 @@ mempool_t *mempool_create(int min_nr, mempool_alloc_t *alloc_fn,
33 45
34void *kmem_cache_alloc(struct kmem_cache *cachep, int flags) 46void *kmem_cache_alloc(struct kmem_cache *cachep, int flags)
35{ 47{
36 void *ret = malloc(cachep->size); 48 struct radix_tree_node *node;
37 if (cachep->ctor) 49
38 cachep->ctor(ret); 50 if (flags & __GFP_NOWARN)
51 return NULL;
52
53 pthread_mutex_lock(&cachep->lock);
54 if (cachep->nr_objs) {
55 cachep->nr_objs--;
56 node = cachep->objs;
57 cachep->objs = node->private_data;
58 pthread_mutex_unlock(&cachep->lock);
59 node->private_data = NULL;
60 } else {
61 pthread_mutex_unlock(&cachep->lock);
62 node = malloc(cachep->size);
63 if (cachep->ctor)
64 cachep->ctor(node);
65 }
66
39 uatomic_inc(&nr_allocated); 67 uatomic_inc(&nr_allocated);
40 return ret; 68 return node;
41} 69}
42 70
43void kmem_cache_free(struct kmem_cache *cachep, void *objp) 71void kmem_cache_free(struct kmem_cache *cachep, void *objp)
44{ 72{
45 assert(objp); 73 assert(objp);
46 uatomic_dec(&nr_allocated); 74 uatomic_dec(&nr_allocated);
47 memset(objp, 0, cachep->size); 75 pthread_mutex_lock(&cachep->lock);
48 free(objp); 76 if (cachep->nr_objs > 10) {
77 memset(objp, POISON_FREE, cachep->size);
78 free(objp);
79 } else {
80 struct radix_tree_node *node = objp;
81 cachep->nr_objs++;
82 node->private_data = cachep->objs;
83 cachep->objs = node;
84 }
85 pthread_mutex_unlock(&cachep->lock);
86}
87
88void *kmalloc(size_t size, gfp_t gfp)
89{
90 void *ret = malloc(size);
91 uatomic_inc(&nr_allocated);
92 return ret;
93}
94
95void kfree(void *p)
96{
97 if (!p)
98 return;
99 uatomic_dec(&nr_allocated);
100 free(p);
49} 101}
50 102
51struct kmem_cache * 103struct kmem_cache *
@@ -54,7 +106,10 @@ kmem_cache_create(const char *name, size_t size, size_t offset,
54{ 106{
55 struct kmem_cache *ret = malloc(sizeof(*ret)); 107 struct kmem_cache *ret = malloc(sizeof(*ret));
56 108
109 pthread_mutex_init(&ret->lock, NULL);
57 ret->size = size; 110 ret->size = size;
111 ret->nr_objs = 0;
112 ret->objs = NULL;
58 ret->ctor = ctor; 113 ret->ctor = ctor;
59 return ret; 114 return ret;
60} 115}
diff --git a/tools/testing/radix-tree/linux/bitops.h b/tools/testing/radix-tree/linux/bitops.h
index 71d58427ab60..a13e9bc76eec 100644
--- a/tools/testing/radix-tree/linux/bitops.h
+++ b/tools/testing/radix-tree/linux/bitops.h
@@ -2,9 +2,14 @@
2#define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ 2#define _ASM_GENERIC_BITOPS_NON_ATOMIC_H_
3 3
4#include <linux/types.h> 4#include <linux/types.h>
5#include <linux/bitops/find.h>
6#include <linux/bitops/hweight.h>
7#include <linux/kernel.h>
5 8
6#define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG)) 9#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
7#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) 10#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
11#define BITS_PER_BYTE 8
12#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_BYTE * sizeof(long))
8 13
9/** 14/**
10 * __set_bit - Set a bit in memory 15 * __set_bit - Set a bit in memory
@@ -17,16 +22,16 @@
17 */ 22 */
18static inline void __set_bit(int nr, volatile unsigned long *addr) 23static inline void __set_bit(int nr, volatile unsigned long *addr)
19{ 24{
20 unsigned long mask = BITOP_MASK(nr); 25 unsigned long mask = BIT_MASK(nr);
21 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 26 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
22 27
23 *p |= mask; 28 *p |= mask;
24} 29}
25 30
26static inline void __clear_bit(int nr, volatile unsigned long *addr) 31static inline void __clear_bit(int nr, volatile unsigned long *addr)
27{ 32{
28 unsigned long mask = BITOP_MASK(nr); 33 unsigned long mask = BIT_MASK(nr);
29 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 34 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
30 35
31 *p &= ~mask; 36 *p &= ~mask;
32} 37}
@@ -42,8 +47,8 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr)
42 */ 47 */
43static inline void __change_bit(int nr, volatile unsigned long *addr) 48static inline void __change_bit(int nr, volatile unsigned long *addr)
44{ 49{
45 unsigned long mask = BITOP_MASK(nr); 50 unsigned long mask = BIT_MASK(nr);
46 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 51 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
47 52
48 *p ^= mask; 53 *p ^= mask;
49} 54}
@@ -59,8 +64,8 @@ static inline void __change_bit(int nr, volatile unsigned long *addr)
59 */ 64 */
60static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) 65static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
61{ 66{
62 unsigned long mask = BITOP_MASK(nr); 67 unsigned long mask = BIT_MASK(nr);
63 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 68 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
64 unsigned long old = *p; 69 unsigned long old = *p;
65 70
66 *p = old | mask; 71 *p = old | mask;
@@ -78,8 +83,8 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
78 */ 83 */
79static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) 84static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
80{ 85{
81 unsigned long mask = BITOP_MASK(nr); 86 unsigned long mask = BIT_MASK(nr);
82 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 87 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
83 unsigned long old = *p; 88 unsigned long old = *p;
84 89
85 *p = old & ~mask; 90 *p = old & ~mask;
@@ -90,8 +95,8 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
90static inline int __test_and_change_bit(int nr, 95static inline int __test_and_change_bit(int nr,
91 volatile unsigned long *addr) 96 volatile unsigned long *addr)
92{ 97{
93 unsigned long mask = BITOP_MASK(nr); 98 unsigned long mask = BIT_MASK(nr);
94 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 99 unsigned long *p = ((unsigned long *)addr) + BIT_WORD(nr);
95 unsigned long old = *p; 100 unsigned long old = *p;
96 101
97 *p = old ^ mask; 102 *p = old ^ mask;
@@ -105,7 +110,7 @@ static inline int __test_and_change_bit(int nr,
105 */ 110 */
106static inline int test_bit(int nr, const volatile unsigned long *addr) 111static inline int test_bit(int nr, const volatile unsigned long *addr)
107{ 112{
108 return 1UL & (addr[BITOP_WORD(nr)] >> (nr & (BITS_PER_LONG-1))); 113 return 1UL & (addr[BIT_WORD(nr)] >> (nr & (BITS_PER_LONG-1)));
109} 114}
110 115
111/** 116/**
@@ -147,4 +152,9 @@ unsigned long find_next_bit(const unsigned long *addr,
147 unsigned long size, 152 unsigned long size,
148 unsigned long offset); 153 unsigned long offset);
149 154
155static inline unsigned long hweight_long(unsigned long w)
156{
157 return sizeof(w) == 4 ? hweight32(w) : hweight64(w);
158}
159
150#endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */ 160#endif /* _ASM_GENERIC_BITOPS_NON_ATOMIC_H_ */
diff --git a/tools/testing/radix-tree/linux/bitops/non-atomic.h b/tools/testing/radix-tree/linux/bitops/non-atomic.h
index 46a825cf2ae1..6a1bcb9d2c4a 100644
--- a/tools/testing/radix-tree/linux/bitops/non-atomic.h
+++ b/tools/testing/radix-tree/linux/bitops/non-atomic.h
@@ -3,7 +3,6 @@
3 3
4#include <asm/types.h> 4#include <asm/types.h>
5 5
6#define BITOP_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
7#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG) 6#define BITOP_WORD(nr) ((nr) / BITS_PER_LONG)
8 7
9/** 8/**
@@ -17,7 +16,7 @@
17 */ 16 */
18static inline void __set_bit(int nr, volatile unsigned long *addr) 17static inline void __set_bit(int nr, volatile unsigned long *addr)
19{ 18{
20 unsigned long mask = BITOP_MASK(nr); 19 unsigned long mask = BIT_MASK(nr);
21 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 20 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
22 21
23 *p |= mask; 22 *p |= mask;
@@ -25,7 +24,7 @@ static inline void __set_bit(int nr, volatile unsigned long *addr)
25 24
26static inline void __clear_bit(int nr, volatile unsigned long *addr) 25static inline void __clear_bit(int nr, volatile unsigned long *addr)
27{ 26{
28 unsigned long mask = BITOP_MASK(nr); 27 unsigned long mask = BIT_MASK(nr);
29 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 28 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
30 29
31 *p &= ~mask; 30 *p &= ~mask;
@@ -42,7 +41,7 @@ static inline void __clear_bit(int nr, volatile unsigned long *addr)
42 */ 41 */
43static inline void __change_bit(int nr, volatile unsigned long *addr) 42static inline void __change_bit(int nr, volatile unsigned long *addr)
44{ 43{
45 unsigned long mask = BITOP_MASK(nr); 44 unsigned long mask = BIT_MASK(nr);
46 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 45 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
47 46
48 *p ^= mask; 47 *p ^= mask;
@@ -59,7 +58,7 @@ static inline void __change_bit(int nr, volatile unsigned long *addr)
59 */ 58 */
60static inline int __test_and_set_bit(int nr, volatile unsigned long *addr) 59static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
61{ 60{
62 unsigned long mask = BITOP_MASK(nr); 61 unsigned long mask = BIT_MASK(nr);
63 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 62 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
64 unsigned long old = *p; 63 unsigned long old = *p;
65 64
@@ -78,7 +77,7 @@ static inline int __test_and_set_bit(int nr, volatile unsigned long *addr)
78 */ 77 */
79static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr) 78static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
80{ 79{
81 unsigned long mask = BITOP_MASK(nr); 80 unsigned long mask = BIT_MASK(nr);
82 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 81 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
83 unsigned long old = *p; 82 unsigned long old = *p;
84 83
@@ -90,7 +89,7 @@ static inline int __test_and_clear_bit(int nr, volatile unsigned long *addr)
90static inline int __test_and_change_bit(int nr, 89static inline int __test_and_change_bit(int nr,
91 volatile unsigned long *addr) 90 volatile unsigned long *addr)
92{ 91{
93 unsigned long mask = BITOP_MASK(nr); 92 unsigned long mask = BIT_MASK(nr);
94 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr); 93 unsigned long *p = ((unsigned long *)addr) + BITOP_WORD(nr);
95 unsigned long old = *p; 94 unsigned long old = *p;
96 95
diff --git a/tools/testing/radix-tree/linux/bug.h b/tools/testing/radix-tree/linux/bug.h
index ccbe444977df..23b8ed52f8c8 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/gfp.h b/tools/testing/radix-tree/linux/gfp.h
index 5201b915f631..5b09b2ce6c33 100644
--- a/tools/testing/radix-tree/linux/gfp.h
+++ b/tools/testing/radix-tree/linux/gfp.h
@@ -3,8 +3,24 @@
3 3
4#define __GFP_BITS_SHIFT 26 4#define __GFP_BITS_SHIFT 26
5#define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1)) 5#define __GFP_BITS_MASK ((gfp_t)((1 << __GFP_BITS_SHIFT) - 1))
6#define __GFP_WAIT 1 6
7#define __GFP_ACCOUNT 0 7#define __GFP_HIGH 0x20u
8#define __GFP_NOWARN 0 8#define __GFP_IO 0x40u
9#define __GFP_FS 0x80u
10#define __GFP_NOWARN 0x200u
11#define __GFP_ATOMIC 0x80000u
12#define __GFP_ACCOUNT 0x100000u
13#define __GFP_DIRECT_RECLAIM 0x400000u
14#define __GFP_KSWAPD_RECLAIM 0x2000000u
15
16#define __GFP_RECLAIM (__GFP_DIRECT_RECLAIM|__GFP_KSWAPD_RECLAIM)
17
18#define GFP_ATOMIC (__GFP_HIGH|__GFP_ATOMIC|__GFP_KSWAPD_RECLAIM)
19#define GFP_KERNEL (__GFP_RECLAIM | __GFP_IO | __GFP_FS)
20
21static inline bool gfpflags_allow_blocking(const gfp_t gfp_flags)
22{
23 return !!(gfp_flags & __GFP_DIRECT_RECLAIM);
24}
9 25
10#endif 26#endif
diff --git a/tools/testing/radix-tree/linux/kernel.h b/tools/testing/radix-tree/linux/kernel.h
index be98a47b4e1b..9b43b4975d83 100644
--- a/tools/testing/radix-tree/linux/kernel.h
+++ b/tools/testing/radix-tree/linux/kernel.h
@@ -8,9 +8,14 @@
8#include <limits.h> 8#include <limits.h>
9 9
10#include "../../include/linux/compiler.h" 10#include "../../include/linux/compiler.h"
11#include "../../include/linux/err.h"
11#include "../../../include/linux/kconfig.h" 12#include "../../../include/linux/kconfig.h"
12 13
14#ifdef BENCHMARK
15#define RADIX_TREE_MAP_SHIFT 6
16#else
13#define RADIX_TREE_MAP_SHIFT 3 17#define RADIX_TREE_MAP_SHIFT 3
18#endif
14 19
15#ifndef NULL 20#ifndef NULL
16#define NULL 0 21#define NULL 0
@@ -43,4 +48,17 @@ static inline int in_interrupt(void)
43{ 48{
44 return 0; 49 return 0;
45} 50}
51
52/*
53 * This looks more complex than it should be. But we need to
54 * get the type for the ~ right in round_down (it needs to be
55 * as wide as the result!), and we want to evaluate the macro
56 * arguments just once each.
57 */
58#define __round_mask(x, y) ((__typeof__(x))((y)-1))
59#define round_up(x, y) ((((x)-1) | __round_mask(x, y))+1)
60#define round_down(x, y) ((x) & ~__round_mask(x, y))
61
62#define xchg(ptr, x) uatomic_xchg(ptr, x)
63
46#endif /* _KERNEL_H */ 64#endif /* _KERNEL_H */
diff --git a/tools/testing/radix-tree/linux/preempt.h b/tools/testing/radix-tree/linux/preempt.h
index 6210672e3baa..65c04c226965 100644
--- a/tools/testing/radix-tree/linux/preempt.h
+++ b/tools/testing/radix-tree/linux/preempt.h
@@ -1,4 +1,4 @@
1/* */ 1extern int preempt_count;
2 2
3#define preempt_disable() do { } while (0) 3#define preempt_disable() uatomic_inc(&preempt_count)
4#define preempt_enable() do { } while (0) 4#define preempt_enable() uatomic_dec(&preempt_count)
diff --git a/tools/testing/radix-tree/linux/slab.h b/tools/testing/radix-tree/linux/slab.h
index 6d5a34770fd4..e40337f41a38 100644
--- a/tools/testing/radix-tree/linux/slab.h
+++ b/tools/testing/radix-tree/linux/slab.h
@@ -7,15 +7,8 @@
7#define SLAB_PANIC 2 7#define SLAB_PANIC 2
8#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */ 8#define SLAB_RECLAIM_ACCOUNT 0x00020000UL /* Objects are reclaimable */
9 9
10static inline int gfpflags_allow_blocking(gfp_t mask) 10void *kmalloc(size_t size, gfp_t);
11{ 11void kfree(void *);
12 return 1;
13}
14
15struct kmem_cache {
16 int size;
17 void (*ctor)(void *);
18};
19 12
20void *kmem_cache_alloc(struct kmem_cache *cachep, int flags); 13void *kmem_cache_alloc(struct kmem_cache *cachep, int flags);
21void kmem_cache_free(struct kmem_cache *cachep, void *objp); 14void kmem_cache_free(struct kmem_cache *cachep, void *objp);
diff --git a/tools/testing/radix-tree/linux/types.h b/tools/testing/radix-tree/linux/types.h
index faa0b6ff9ca8..8491d89873bb 100644
--- a/tools/testing/radix-tree/linux/types.h
+++ b/tools/testing/radix-tree/linux/types.h
@@ -6,8 +6,6 @@
6#define __rcu 6#define __rcu
7#define __read_mostly 7#define __read_mostly
8 8
9#define BITS_PER_LONG (sizeof(long) * 8)
10
11static inline void INIT_LIST_HEAD(struct list_head *list) 9static inline void INIT_LIST_HEAD(struct list_head *list)
12{ 10{
13 list->next = list; 11 list->next = list;
diff --git a/tools/testing/radix-tree/main.c b/tools/testing/radix-tree/main.c
index daa9010693e8..f7e9801a6754 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)
67 67
68 for (i = 0; i < (long_run ? 1000 : 3); i++) { 68 for (i = 0; i < (long_run ? 1000 : 3); i++) {
69 __big_gang_check(); 69 __big_gang_check();
70 srand(time(0));
71 printf("%d ", i); 70 printf("%d ", i);
72 fflush(stdout); 71 fflush(stdout);
73 } 72 }
@@ -206,8 +205,7 @@ void copy_tag_check(void)
206 } 205 }
207 206
208// printf("\ncopying tags...\n"); 207// printf("\ncopying tags...\n");
209 cur = start; 208 tagged = tag_tagged_items(&tree, NULL, start, end, ITEMS, 0, 1);
210 tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, ITEMS, 0, 1);
211 209
212// printf("checking copied tags\n"); 210// printf("checking copied tags\n");
213 assert(tagged == count); 211 assert(tagged == count);
@@ -215,16 +213,13 @@ void copy_tag_check(void)
215 213
216 /* Copy tags in several rounds */ 214 /* Copy tags in several rounds */
217// printf("\ncopying tags...\n"); 215// printf("\ncopying tags...\n");
218 cur = start; 216 tmp = rand() % (count / 10 + 2);
219 do { 217 tagged = tag_tagged_items(&tree, NULL, start, end, tmp, 0, 2);
220 tmp = rand() % (count/10+2); 218 assert(tagged == count);
221 tagged = radix_tree_range_tag_if_tagged(&tree, &cur, end, tmp, 0, 2);
222 } while (tmp == tagged);
223 219
224// printf("%lu %lu %lu\n", tagged, tmp, count); 220// printf("%lu %lu %lu\n", tagged, tmp, count);
225// printf("checking copied tags\n"); 221// printf("checking copied tags\n");
226 check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2); 222 check_copied_tags(&tree, start, end, idx, ITEMS, 0, 2);
227 assert(tagged < tmp);
228 verify_tag_consistency(&tree, 0); 223 verify_tag_consistency(&tree, 0);
229 verify_tag_consistency(&tree, 1); 224 verify_tag_consistency(&tree, 1);
230 verify_tag_consistency(&tree, 2); 225 verify_tag_consistency(&tree, 2);
@@ -240,7 +235,7 @@ static void __locate_check(struct radix_tree_root *tree, unsigned long index,
240 235
241 item_insert_order(tree, index, order); 236 item_insert_order(tree, index, order);
242 item = item_lookup(tree, index); 237 item = item_lookup(tree, index);
243 index2 = radix_tree_locate_item(tree, item); 238 index2 = find_item(tree, item);
244 if (index != index2) { 239 if (index != index2) {
245 printf("index %ld order %d inserted; found %ld\n", 240 printf("index %ld order %d inserted; found %ld\n",
246 index, order, index2); 241 index, order, index2);
@@ -274,17 +269,17 @@ static void locate_check(void)
274 index += (1UL << order)) { 269 index += (1UL << order)) {
275 __locate_check(&tree, index + offset, order); 270 __locate_check(&tree, index + offset, order);
276 } 271 }
277 if (radix_tree_locate_item(&tree, &tree) != -1) 272 if (find_item(&tree, &tree) != -1)
278 abort(); 273 abort();
279 274
280 item_kill_tree(&tree); 275 item_kill_tree(&tree);
281 } 276 }
282 } 277 }
283 278
284 if (radix_tree_locate_item(&tree, &tree) != -1) 279 if (find_item(&tree, &tree) != -1)
285 abort(); 280 abort();
286 __locate_check(&tree, -1, 0); 281 __locate_check(&tree, -1, 0);
287 if (radix_tree_locate_item(&tree, &tree) != -1) 282 if (find_item(&tree, &tree) != -1)
288 abort(); 283 abort();
289 item_kill_tree(&tree); 284 item_kill_tree(&tree);
290} 285}
@@ -293,50 +288,80 @@ static void single_thread_tests(bool long_run)
293{ 288{
294 int i; 289 int i;
295 290
296 printf("starting single_thread_tests: %d allocated\n", nr_allocated); 291 printf("starting single_thread_tests: %d allocated, preempt %d\n",
292 nr_allocated, preempt_count);
297 multiorder_checks(); 293 multiorder_checks();
298 printf("after multiorder_check: %d allocated\n", nr_allocated); 294 rcu_barrier();
295 printf("after multiorder_check: %d allocated, preempt %d\n",
296 nr_allocated, preempt_count);
299 locate_check(); 297 locate_check();
300 printf("after locate_check: %d allocated\n", nr_allocated); 298 rcu_barrier();
299 printf("after locate_check: %d allocated, preempt %d\n",
300 nr_allocated, preempt_count);
301 tag_check(); 301 tag_check();
302 printf("after tag_check: %d allocated\n", nr_allocated); 302 rcu_barrier();
303 printf("after tag_check: %d allocated, preempt %d\n",
304 nr_allocated, preempt_count);
303 gang_check(); 305 gang_check();
304 printf("after gang_check: %d allocated\n", nr_allocated); 306 rcu_barrier();
307 printf("after gang_check: %d allocated, preempt %d\n",
308 nr_allocated, preempt_count);
305 add_and_check(); 309 add_and_check();
306 printf("after add_and_check: %d allocated\n", nr_allocated); 310 rcu_barrier();
311 printf("after add_and_check: %d allocated, preempt %d\n",
312 nr_allocated, preempt_count);
307 dynamic_height_check(); 313 dynamic_height_check();
308 printf("after dynamic_height_check: %d allocated\n", nr_allocated); 314 rcu_barrier();
315 printf("after dynamic_height_check: %d allocated, preempt %d\n",
316 nr_allocated, preempt_count);
309 big_gang_check(long_run); 317 big_gang_check(long_run);
310 printf("after big_gang_check: %d allocated\n", nr_allocated); 318 rcu_barrier();
319 printf("after big_gang_check: %d allocated, preempt %d\n",
320 nr_allocated, preempt_count);
311 for (i = 0; i < (long_run ? 2000 : 3); i++) { 321 for (i = 0; i < (long_run ? 2000 : 3); i++) {
312 copy_tag_check(); 322 copy_tag_check();
313 printf("%d ", i); 323 printf("%d ", i);
314 fflush(stdout); 324 fflush(stdout);
315 } 325 }
316 printf("after copy_tag_check: %d allocated\n", nr_allocated); 326 rcu_barrier();
327 printf("after copy_tag_check: %d allocated, preempt %d\n",
328 nr_allocated, preempt_count);
317} 329}
318 330
319int main(int argc, char **argv) 331int main(int argc, char **argv)
320{ 332{
321 bool long_run = false; 333 bool long_run = false;
322 int opt; 334 int opt;
335 unsigned int seed = time(NULL);
323 336
324 while ((opt = getopt(argc, argv, "l")) != -1) { 337 while ((opt = getopt(argc, argv, "ls:")) != -1) {
325 if (opt == 'l') 338 if (opt == 'l')
326 long_run = true; 339 long_run = true;
340 else if (opt == 's')
341 seed = strtoul(optarg, NULL, 0);
327 } 342 }
328 343
344 printf("random seed %u\n", seed);
345 srand(seed);
346
329 rcu_register_thread(); 347 rcu_register_thread();
330 radix_tree_init(); 348 radix_tree_init();
331 349
332 regression1_test(); 350 regression1_test();
333 regression2_test(); 351 regression2_test();
334 regression3_test(); 352 regression3_test();
335 iteration_test(); 353 iteration_test(0, 10);
354 iteration_test(7, 20);
336 single_thread_tests(long_run); 355 single_thread_tests(long_run);
337 356
338 sleep(1); 357 /* Free any remaining preallocated nodes */
339 printf("after sleep(1): %d allocated\n", nr_allocated); 358 radix_tree_cpu_dead(0);
359
360 benchmark();
361
362 rcu_barrier();
363 printf("after rcu_barrier: %d allocated, preempt %d\n",
364 nr_allocated, preempt_count);
340 rcu_unregister_thread(); 365 rcu_unregister_thread();
341 366
342 exit(0); 367 exit(0);
diff --git a/tools/testing/radix-tree/multiorder.c b/tools/testing/radix-tree/multiorder.c
index d1be94667a30..f79812a5e070 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)
26{ 26{
27 RADIX_TREE(tree, GFP_KERNEL); 27 RADIX_TREE(tree, GFP_KERNEL);
28 int base, err, i; 28 int base, err, i;
29 unsigned long first = 0;
30 29
31 /* our canonical entry */ 30 /* our canonical entry */
32 base = index & ~((1 << order) - 1); 31 base = index & ~((1 << order) - 1);
@@ -60,7 +59,7 @@ static void __multiorder_tag_test(int index, int order)
60 assert(!radix_tree_tag_get(&tree, i, 1)); 59 assert(!radix_tree_tag_get(&tree, i, 1));
61 } 60 }
62 61
63 assert(radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, 10, 0, 1) == 1); 62 assert(tag_tagged_items(&tree, NULL, 0, ~0UL, 10, 0, 1) == 1);
64 assert(radix_tree_tag_clear(&tree, index, 0)); 63 assert(radix_tree_tag_clear(&tree, index, 0));
65 64
66 for_each_index(i, base, order) { 65 for_each_index(i, base, order) {
@@ -76,8 +75,27 @@ static void __multiorder_tag_test(int index, int order)
76 item_kill_tree(&tree); 75 item_kill_tree(&tree);
77} 76}
78 77
78static void __multiorder_tag_test2(unsigned order, unsigned long index2)
79{
80 RADIX_TREE(tree, GFP_KERNEL);
81 unsigned long index = (1 << order);
82 index2 += index;
83
84 assert(item_insert_order(&tree, 0, order) == 0);
85 assert(item_insert(&tree, index2) == 0);
86
87 assert(radix_tree_tag_set(&tree, 0, 0));
88 assert(radix_tree_tag_set(&tree, index2, 0));
89
90 assert(tag_tagged_items(&tree, NULL, 0, ~0UL, 10, 0, 1) == 2);
91
92 item_kill_tree(&tree);
93}
94
79static void multiorder_tag_tests(void) 95static void multiorder_tag_tests(void)
80{ 96{
97 int i, j;
98
81 /* test multi-order entry for indices 0-7 with no sibling pointers */ 99 /* test multi-order entry for indices 0-7 with no sibling pointers */
82 __multiorder_tag_test(0, 3); 100 __multiorder_tag_test(0, 3);
83 __multiorder_tag_test(5, 3); 101 __multiorder_tag_test(5, 3);
@@ -117,6 +135,10 @@ static void multiorder_tag_tests(void)
117 __multiorder_tag_test(300, 8); 135 __multiorder_tag_test(300, 8);
118 136
119 __multiorder_tag_test(0x12345678UL, 8); 137 __multiorder_tag_test(0x12345678UL, 8);
138
139 for (i = 1; i < 10; i++)
140 for (j = 0; j < (10 << i); j++)
141 __multiorder_tag_test2(i, j);
120} 142}
121 143
122static void multiorder_check(unsigned long index, int order) 144static void multiorder_check(unsigned long index, int order)
@@ -125,7 +147,7 @@ static void multiorder_check(unsigned long index, int order)
125 unsigned long min = index & ~((1UL << order) - 1); 147 unsigned long min = index & ~((1UL << order) - 1);
126 unsigned long max = min + (1UL << order); 148 unsigned long max = min + (1UL << order);
127 void **slot; 149 void **slot;
128 struct item *item2 = item_create(min); 150 struct item *item2 = item_create(min, order);
129 RADIX_TREE(tree, GFP_KERNEL); 151 RADIX_TREE(tree, GFP_KERNEL);
130 152
131 printf("Multiorder index %ld, order %d\n", index, order); 153 printf("Multiorder index %ld, order %d\n", index, order);
@@ -231,11 +253,14 @@ void multiorder_iteration(void)
231 radix_tree_for_each_slot(slot, &tree, &iter, j) { 253 radix_tree_for_each_slot(slot, &tree, &iter, j) {
232 int height = order[i] / RADIX_TREE_MAP_SHIFT; 254 int height = order[i] / RADIX_TREE_MAP_SHIFT;
233 int shift = height * RADIX_TREE_MAP_SHIFT; 255 int shift = height * RADIX_TREE_MAP_SHIFT;
234 int mask = (1 << order[i]) - 1; 256 unsigned long mask = (1UL << order[i]) - 1;
257 struct item *item = *slot;
235 258
236 assert(iter.index >= (index[i] &~ mask)); 259 assert((iter.index | mask) == (index[i] | mask));
237 assert(iter.index <= (index[i] | mask));
238 assert(iter.shift == shift); 260 assert(iter.shift == shift);
261 assert(!radix_tree_is_internal_node(item));
262 assert((item->index | mask) == (index[i] | mask));
263 assert(item->order == order[i]);
239 i++; 264 i++;
240 } 265 }
241 } 266 }
@@ -248,7 +273,6 @@ void multiorder_tagged_iteration(void)
248 RADIX_TREE(tree, GFP_KERNEL); 273 RADIX_TREE(tree, GFP_KERNEL);
249 struct radix_tree_iter iter; 274 struct radix_tree_iter iter;
250 void **slot; 275 void **slot;
251 unsigned long first = 0;
252 int i, j; 276 int i, j;
253 277
254 printf("Multiorder tagged iteration test\n"); 278 printf("Multiorder tagged iteration test\n");
@@ -269,7 +293,7 @@ void multiorder_tagged_iteration(void)
269 assert(radix_tree_tag_set(&tree, tag_index[i], 1)); 293 assert(radix_tree_tag_set(&tree, tag_index[i], 1));
270 294
271 for (j = 0; j < 256; j++) { 295 for (j = 0; j < 256; j++) {
272 int mask, k; 296 int k;
273 297
274 for (i = 0; i < TAG_ENTRIES; i++) { 298 for (i = 0; i < TAG_ENTRIES; i++) {
275 for (k = i; index[k] < tag_index[i]; k++) 299 for (k = i; index[k] < tag_index[i]; k++)
@@ -279,18 +303,22 @@ void multiorder_tagged_iteration(void)
279 } 303 }
280 304
281 radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) { 305 radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) {
306 unsigned long mask;
307 struct item *item = *slot;
282 for (k = i; index[k] < tag_index[i]; k++) 308 for (k = i; index[k] < tag_index[i]; k++)
283 ; 309 ;
284 mask = (1 << order[k]) - 1; 310 mask = (1UL << order[k]) - 1;
285 311
286 assert(iter.index >= (tag_index[i] &~ mask)); 312 assert((iter.index | mask) == (tag_index[i] | mask));
287 assert(iter.index <= (tag_index[i] | mask)); 313 assert(!radix_tree_is_internal_node(item));
314 assert((item->index | mask) == (tag_index[i] | mask));
315 assert(item->order == order[k]);
288 i++; 316 i++;
289 } 317 }
290 } 318 }
291 319
292 radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, 320 assert(tag_tagged_items(&tree, NULL, 0, ~0UL, TAG_ENTRIES, 1, 2) ==
293 MT_NUM_ENTRIES, 1, 2); 321 TAG_ENTRIES);
294 322
295 for (j = 0; j < 256; j++) { 323 for (j = 0; j < 256; j++) {
296 int mask, k; 324 int mask, k;
@@ -303,19 +331,21 @@ void multiorder_tagged_iteration(void)
303 } 331 }
304 332
305 radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) { 333 radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) {
334 struct item *item = *slot;
306 for (k = i; index[k] < tag_index[i]; k++) 335 for (k = i; index[k] < tag_index[i]; k++)
307 ; 336 ;
308 mask = (1 << order[k]) - 1; 337 mask = (1 << order[k]) - 1;
309 338
310 assert(iter.index >= (tag_index[i] &~ mask)); 339 assert((iter.index | mask) == (tag_index[i] | mask));
311 assert(iter.index <= (tag_index[i] | mask)); 340 assert(!radix_tree_is_internal_node(item));
341 assert((item->index | mask) == (tag_index[i] | mask));
342 assert(item->order == order[k]);
312 i++; 343 i++;
313 } 344 }
314 } 345 }
315 346
316 first = 1; 347 assert(tag_tagged_items(&tree, NULL, 1, ~0UL, MT_NUM_ENTRIES * 2, 1, 0)
317 radix_tree_range_tag_if_tagged(&tree, &first, ~0UL, 348 == TAG_ENTRIES);
318 MT_NUM_ENTRIES, 1, 0);
319 i = 0; 349 i = 0;
320 radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) { 350 radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) {
321 assert(iter.index == tag_index[i]); 351 assert(iter.index == tag_index[i]);
@@ -325,6 +355,261 @@ void multiorder_tagged_iteration(void)
325 item_kill_tree(&tree); 355 item_kill_tree(&tree);
326} 356}
327 357
358static void multiorder_join1(unsigned long index,
359 unsigned order1, unsigned order2)
360{
361 unsigned long loc;
362 void *item, *item2 = item_create(index + 1, order1);
363 RADIX_TREE(tree, GFP_KERNEL);
364
365 item_insert_order(&tree, index, order2);
366 item = radix_tree_lookup(&tree, index);
367 radix_tree_join(&tree, index + 1, order1, item2);
368 loc = find_item(&tree, item);
369 if (loc == -1)
370 free(item);
371 item = radix_tree_lookup(&tree, index + 1);
372 assert(item == item2);
373 item_kill_tree(&tree);
374}
375
376static void multiorder_join2(unsigned order1, unsigned order2)
377{
378 RADIX_TREE(tree, GFP_KERNEL);
379 struct radix_tree_node *node;
380 void *item1 = item_create(0, order1);
381 void *item2;
382
383 item_insert_order(&tree, 0, order2);
384 radix_tree_insert(&tree, 1 << order2, (void *)0x12UL);
385 item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL);
386 assert(item2 == (void *)0x12UL);
387 assert(node->exceptional == 1);
388
389 radix_tree_join(&tree, 0, order1, item1);
390 item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL);
391 assert(item2 == item1);
392 assert(node->exceptional == 0);
393 item_kill_tree(&tree);
394}
395
396/*
397 * This test revealed an accounting bug for exceptional entries at one point.
398 * Nodes were being freed back into the pool with an elevated exception count
399 * by radix_tree_join() and then radix_tree_split() was failing to zero the
400 * count of exceptional entries.
401 */
402static void multiorder_join3(unsigned int order)
403{
404 RADIX_TREE(tree, GFP_KERNEL);
405 struct radix_tree_node *node;
406 void **slot;
407 struct radix_tree_iter iter;
408 unsigned long i;
409
410 for (i = 0; i < (1 << order); i++) {
411 radix_tree_insert(&tree, i, (void *)0x12UL);
412 }
413
414 radix_tree_join(&tree, 0, order, (void *)0x16UL);
415 rcu_barrier();
416
417 radix_tree_split(&tree, 0, 0);
418
419 radix_tree_for_each_slot(slot, &tree, &iter, 0) {
420 radix_tree_iter_replace(&tree, &iter, slot, (void *)0x12UL);
421 }
422
423 __radix_tree_lookup(&tree, 0, &node, NULL);
424 assert(node->exceptional == node->count);
425
426 item_kill_tree(&tree);
427}
428
429static void multiorder_join(void)
430{
431 int i, j, idx;
432
433 for (idx = 0; idx < 1024; idx = idx * 2 + 3) {
434 for (i = 1; i < 15; i++) {
435 for (j = 0; j < i; j++) {
436 multiorder_join1(idx, i, j);
437 }
438 }
439 }
440
441 for (i = 1; i < 15; i++) {
442 for (j = 0; j < i; j++) {
443 multiorder_join2(i, j);
444 }
445 }
446
447 for (i = 3; i < 10; i++) {
448 multiorder_join3(i);
449 }
450}
451
452static void check_mem(unsigned old_order, unsigned new_order, unsigned alloc)
453{
454 struct radix_tree_preload *rtp = &radix_tree_preloads;
455 if (rtp->nr != 0)
456 printf("split(%u %u) remaining %u\n", old_order, new_order,
457 rtp->nr);
458 /*
459 * Can't check for equality here as some nodes may have been
460 * RCU-freed while we ran. But we should never finish with more
461 * nodes allocated since they should have all been preloaded.
462 */
463 if (nr_allocated > alloc)
464 printf("split(%u %u) allocated %u %u\n", old_order, new_order,
465 alloc, nr_allocated);
466}
467
468static void __multiorder_split(int old_order, int new_order)
469{
470 RADIX_TREE(tree, GFP_ATOMIC);
471 void **slot;
472 struct radix_tree_iter iter;
473 unsigned alloc;
474
475 radix_tree_preload(GFP_KERNEL);
476 assert(item_insert_order(&tree, 0, old_order) == 0);
477 radix_tree_preload_end();
478
479 /* Wipe out the preloaded cache or it'll confuse check_mem() */
480 radix_tree_cpu_dead(0);
481
482 radix_tree_tag_set(&tree, 0, 2);
483
484 radix_tree_split_preload(old_order, new_order, GFP_KERNEL);
485 alloc = nr_allocated;
486 radix_tree_split(&tree, 0, new_order);
487 check_mem(old_order, new_order, alloc);
488 radix_tree_for_each_slot(slot, &tree, &iter, 0) {
489 radix_tree_iter_replace(&tree, &iter, slot,
490 item_create(iter.index, new_order));
491 }
492 radix_tree_preload_end();
493
494 item_kill_tree(&tree);
495}
496
497static void __multiorder_split2(int old_order, int new_order)
498{
499 RADIX_TREE(tree, GFP_KERNEL);
500 void **slot;
501 struct radix_tree_iter iter;
502 struct radix_tree_node *node;
503 void *item;
504
505 __radix_tree_insert(&tree, 0, old_order, (void *)0x12);
506
507 item = __radix_tree_lookup(&tree, 0, &node, NULL);
508 assert(item == (void *)0x12);
509 assert(node->exceptional > 0);
510
511 radix_tree_split(&tree, 0, new_order);
512 radix_tree_for_each_slot(slot, &tree, &iter, 0) {
513 radix_tree_iter_replace(&tree, &iter, slot,
514 item_create(iter.index, new_order));
515 }
516
517 item = __radix_tree_lookup(&tree, 0, &node, NULL);
518 assert(item != (void *)0x12);
519 assert(node->exceptional == 0);
520
521 item_kill_tree(&tree);
522}
523
524static void __multiorder_split3(int old_order, int new_order)
525{
526 RADIX_TREE(tree, GFP_KERNEL);
527 void **slot;
528 struct radix_tree_iter iter;
529 struct radix_tree_node *node;
530 void *item;
531
532 __radix_tree_insert(&tree, 0, old_order, (void *)0x12);
533
534 item = __radix_tree_lookup(&tree, 0, &node, NULL);
535 assert(item == (void *)0x12);
536 assert(node->exceptional > 0);
537
538 radix_tree_split(&tree, 0, new_order);
539 radix_tree_for_each_slot(slot, &tree, &iter, 0) {
540 radix_tree_iter_replace(&tree, &iter, slot, (void *)0x16);
541 }
542
543 item = __radix_tree_lookup(&tree, 0, &node, NULL);
544 assert(item == (void *)0x16);
545 assert(node->exceptional > 0);
546
547 item_kill_tree(&tree);
548
549 __radix_tree_insert(&tree, 0, old_order, (void *)0x12);
550
551 item = __radix_tree_lookup(&tree, 0, &node, NULL);
552 assert(item == (void *)0x12);
553 assert(node->exceptional > 0);
554
555 radix_tree_split(&tree, 0, new_order);
556 radix_tree_for_each_slot(slot, &tree, &iter, 0) {
557 if (iter.index == (1 << new_order))
558 radix_tree_iter_replace(&tree, &iter, slot,
559 (void *)0x16);
560 else
561 radix_tree_iter_replace(&tree, &iter, slot, NULL);
562 }
563
564 item = __radix_tree_lookup(&tree, 1 << new_order, &node, NULL);
565 assert(item == (void *)0x16);
566 assert(node->count == node->exceptional);
567 do {
568 node = node->parent;
569 if (!node)
570 break;
571 assert(node->count == 1);
572 assert(node->exceptional == 0);
573 } while (1);
574
575 item_kill_tree(&tree);
576}
577
578static void multiorder_split(void)
579{
580 int i, j;
581
582 for (i = 3; i < 11; i++)
583 for (j = 0; j < i; j++) {
584 __multiorder_split(i, j);
585 __multiorder_split2(i, j);
586 __multiorder_split3(i, j);
587 }
588}
589
590static void multiorder_account(void)
591{
592 RADIX_TREE(tree, GFP_KERNEL);
593 struct radix_tree_node *node;
594 void **slot;
595
596 item_insert_order(&tree, 0, 5);
597
598 __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12);
599 __radix_tree_lookup(&tree, 0, &node, NULL);
600 assert(node->count == node->exceptional * 2);
601 radix_tree_delete(&tree, 1 << 5);
602 assert(node->exceptional == 0);
603
604 __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12);
605 __radix_tree_lookup(&tree, 1 << 5, &node, &slot);
606 assert(node->count == node->exceptional * 2);
607 __radix_tree_replace(&tree, node, slot, NULL, NULL, NULL);
608 assert(node->exceptional == 0);
609
610 item_kill_tree(&tree);
611}
612
328void multiorder_checks(void) 613void multiorder_checks(void)
329{ 614{
330 int i; 615 int i;
@@ -342,4 +627,9 @@ void multiorder_checks(void)
342 multiorder_tag_tests(); 627 multiorder_tag_tests();
343 multiorder_iteration(); 628 multiorder_iteration();
344 multiorder_tagged_iteration(); 629 multiorder_tagged_iteration();
630 multiorder_join();
631 multiorder_split();
632 multiorder_account();
633
634 radix_tree_cpu_dead(0);
345} 635}
diff --git a/tools/testing/radix-tree/rcupdate.c b/tools/testing/radix-tree/rcupdate.c
deleted file mode 100644
index 31a2d14225d6..000000000000
--- a/tools/testing/radix-tree/rcupdate.c
+++ /dev/null
@@ -1,86 +0,0 @@
1#include <linux/rcupdate.h>
2#include <pthread.h>
3#include <stdio.h>
4#include <assert.h>
5
6static pthread_mutex_t rculock = PTHREAD_MUTEX_INITIALIZER;
7static struct rcu_head *rcuhead_global = NULL;
8static __thread int nr_rcuhead = 0;
9static __thread struct rcu_head *rcuhead = NULL;
10static __thread struct rcu_head *rcutail = NULL;
11
12static pthread_cond_t rcu_worker_cond = PTHREAD_COND_INITIALIZER;
13
14/* switch to urcu implementation when it is merged. */
15void call_rcu(struct rcu_head *head, void (*func)(struct rcu_head *head))
16{
17 head->func = func;
18 head->next = rcuhead;
19 rcuhead = head;
20 if (!rcutail)
21 rcutail = head;
22 nr_rcuhead++;
23 if (nr_rcuhead >= 1000) {
24 int signal = 0;
25
26 pthread_mutex_lock(&rculock);
27 if (!rcuhead_global)
28 signal = 1;
29 rcutail->next = rcuhead_global;
30 rcuhead_global = head;
31 pthread_mutex_unlock(&rculock);
32
33 nr_rcuhead = 0;
34 rcuhead = NULL;
35 rcutail = NULL;
36
37 if (signal) {
38 pthread_cond_signal(&rcu_worker_cond);
39 }
40 }
41}
42
43static void *rcu_worker(void *arg)
44{
45 struct rcu_head *r;
46
47 rcupdate_thread_init();
48
49 while (1) {
50 pthread_mutex_lock(&rculock);
51 while (!rcuhead_global) {
52 pthread_cond_wait(&rcu_worker_cond, &rculock);
53 }
54 r = rcuhead_global;
55 rcuhead_global = NULL;
56
57 pthread_mutex_unlock(&rculock);
58
59 synchronize_rcu();
60
61 while (r) {
62 struct rcu_head *tmp = r->next;
63 r->func(r);
64 r = tmp;
65 }
66 }
67
68 rcupdate_thread_exit();
69
70 return NULL;
71}
72
73static pthread_t worker_thread;
74void rcupdate_init(void)
75{
76 pthread_create(&worker_thread, NULL, rcu_worker, NULL);
77}
78
79void rcupdate_thread_init(void)
80{
81 rcu_register_thread();
82}
83void rcupdate_thread_exit(void)
84{
85 rcu_unregister_thread();
86}
diff --git a/tools/testing/radix-tree/regression2.c b/tools/testing/radix-tree/regression2.c
index 63bf347aaf33..a41325d7a170 100644
--- a/tools/testing/radix-tree/regression2.c
+++ b/tools/testing/radix-tree/regression2.c
@@ -50,6 +50,7 @@
50#include <stdio.h> 50#include <stdio.h>
51 51
52#include "regression.h" 52#include "regression.h"
53#include "test.h"
53 54
54#define PAGECACHE_TAG_DIRTY 0 55#define PAGECACHE_TAG_DIRTY 0
55#define PAGECACHE_TAG_WRITEBACK 1 56#define PAGECACHE_TAG_WRITEBACK 1
@@ -90,7 +91,7 @@ void regression2_test(void)
90 /* 1. */ 91 /* 1. */
91 start = 0; 92 start = 0;
92 end = max_slots - 2; 93 end = max_slots - 2;
93 radix_tree_range_tag_if_tagged(&mt_tree, &start, end, 1, 94 tag_tagged_items(&mt_tree, NULL, start, end, 1,
94 PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE); 95 PAGECACHE_TAG_DIRTY, PAGECACHE_TAG_TOWRITE);
95 96
96 /* 2. */ 97 /* 2. */
diff --git a/tools/testing/radix-tree/regression3.c b/tools/testing/radix-tree/regression3.c
index 1f06ed73d0a8..b594841fae85 100644
--- a/tools/testing/radix-tree/regression3.c
+++ b/tools/testing/radix-tree/regression3.c
@@ -5,7 +5,7 @@
5 * In following radix_tree_next_slot current chunk size becomes zero. 5 * In following radix_tree_next_slot current chunk size becomes zero.
6 * This isn't checked and it tries to dereference null pointer in slot. 6 * This isn't checked and it tries to dereference null pointer in slot.
7 * 7 *
8 * Helper radix_tree_iter_next reset slot to NULL and next_index to index + 1, 8 * Helper radix_tree_iter_resume reset slot to NULL and next_index to index + 1,
9 * for tagger iteraction it also must reset cached tags in iterator to abort 9 * for tagger iteraction it also must reset cached tags in iterator to abort
10 * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk. 10 * next radix_tree_next_slot and go to slow-path into radix_tree_next_chunk.
11 * 11 *
@@ -88,7 +88,7 @@ void regression3_test(void)
88 printf("slot %ld %p\n", iter.index, *slot); 88 printf("slot %ld %p\n", iter.index, *slot);
89 if (!iter.index) { 89 if (!iter.index) {
90 printf("next at %ld\n", iter.index); 90 printf("next at %ld\n", iter.index);
91 slot = radix_tree_iter_next(&iter); 91 slot = radix_tree_iter_resume(slot, &iter);
92 } 92 }
93 } 93 }
94 94
@@ -96,7 +96,7 @@ void regression3_test(void)
96 printf("contig %ld %p\n", iter.index, *slot); 96 printf("contig %ld %p\n", iter.index, *slot);
97 if (!iter.index) { 97 if (!iter.index) {
98 printf("next at %ld\n", iter.index); 98 printf("next at %ld\n", iter.index);
99 slot = radix_tree_iter_next(&iter); 99 slot = radix_tree_iter_resume(slot, &iter);
100 } 100 }
101 } 101 }
102 102
@@ -106,7 +106,7 @@ void regression3_test(void)
106 printf("tagged %ld %p\n", iter.index, *slot); 106 printf("tagged %ld %p\n", iter.index, *slot);
107 if (!iter.index) { 107 if (!iter.index) {
108 printf("next at %ld\n", iter.index); 108 printf("next at %ld\n", iter.index);
109 slot = radix_tree_iter_next(&iter); 109 slot = radix_tree_iter_resume(slot, &iter);
110 } 110 }
111 } 111 }
112 112
diff --git a/tools/testing/radix-tree/tag_check.c b/tools/testing/radix-tree/tag_check.c
index b0ac05741750..fd98c132207a 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)
23 item_tag_set(tree, index, tag); 23 item_tag_set(tree, index, tag);
24 ret = item_tag_get(tree, index, tag); 24 ret = item_tag_get(tree, index, tag);
25 assert(ret != 0); 25 assert(ret != 0);
26 ret = radix_tree_range_tag_if_tagged(tree, &first, ~0UL, 10, tag, !tag); 26 ret = tag_tagged_items(tree, NULL, first, ~0UL, 10, tag, !tag);
27 assert(ret == 1); 27 assert(ret == 1);
28 ret = item_tag_get(tree, index, !tag); 28 ret = item_tag_get(tree, index, !tag);
29 assert(ret != 0); 29 assert(ret != 0);
@@ -51,6 +51,7 @@ void simple_checks(void)
51 verify_tag_consistency(&tree, 1); 51 verify_tag_consistency(&tree, 1);
52 printf("before item_kill_tree: %d allocated\n", nr_allocated); 52 printf("before item_kill_tree: %d allocated\n", nr_allocated);
53 item_kill_tree(&tree); 53 item_kill_tree(&tree);
54 rcu_barrier();
54 printf("after item_kill_tree: %d allocated\n", nr_allocated); 55 printf("after item_kill_tree: %d allocated\n", nr_allocated);
55} 56}
56 57
@@ -319,10 +320,13 @@ static void single_check(void)
319 assert(ret == 0); 320 assert(ret == 0);
320 verify_tag_consistency(&tree, 0); 321 verify_tag_consistency(&tree, 0);
321 verify_tag_consistency(&tree, 1); 322 verify_tag_consistency(&tree, 1);
322 ret = radix_tree_range_tag_if_tagged(&tree, &first, 10, 10, 0, 1); 323 ret = tag_tagged_items(&tree, NULL, first, 10, 10, 0, 1);
323 assert(ret == 1); 324 assert(ret == 1);
324 ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1); 325 ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 1);
325 assert(ret == 1); 326 assert(ret == 1);
327 item_tag_clear(&tree, 0, 0);
328 ret = radix_tree_gang_lookup_tag(&tree, (void **)items, 0, BATCH, 0);
329 assert(ret == 0);
326 item_kill_tree(&tree); 330 item_kill_tree(&tree);
327} 331}
328 332
@@ -331,12 +335,16 @@ void tag_check(void)
331 single_check(); 335 single_check();
332 extend_checks(); 336 extend_checks();
333 contract_checks(); 337 contract_checks();
338 rcu_barrier();
334 printf("after extend_checks: %d allocated\n", nr_allocated); 339 printf("after extend_checks: %d allocated\n", nr_allocated);
335 __leak_check(); 340 __leak_check();
336 leak_check(); 341 leak_check();
342 rcu_barrier();
337 printf("after leak_check: %d allocated\n", nr_allocated); 343 printf("after leak_check: %d allocated\n", nr_allocated);
338 simple_checks(); 344 simple_checks();
345 rcu_barrier();
339 printf("after simple_checks: %d allocated\n", nr_allocated); 346 printf("after simple_checks: %d allocated\n", nr_allocated);
340 thrash_tags(); 347 thrash_tags();
348 rcu_barrier();
341 printf("after thrash_tags: %d allocated\n", nr_allocated); 349 printf("after thrash_tags: %d allocated\n", nr_allocated);
342} 350}
diff --git a/tools/testing/radix-tree/test.c b/tools/testing/radix-tree/test.c
index a6e8099eaf4f..e5726e373646 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)
24 return radix_tree_tag_get(root, index, tag); 24 return radix_tree_tag_get(root, index, tag);
25} 25}
26 26
27int __item_insert(struct radix_tree_root *root, struct item *item, 27int __item_insert(struct radix_tree_root *root, struct item *item)
28 unsigned order)
29{ 28{
30 return __radix_tree_insert(root, item->index, order, item); 29 return __radix_tree_insert(root, item->index, item->order, item);
31} 30}
32 31
33int item_insert(struct radix_tree_root *root, unsigned long index) 32int item_insert(struct radix_tree_root *root, unsigned long index)
34{ 33{
35 return __item_insert(root, item_create(index), 0); 34 return __item_insert(root, item_create(index, 0));
36} 35}
37 36
38int item_insert_order(struct radix_tree_root *root, unsigned long index, 37int item_insert_order(struct radix_tree_root *root, unsigned long index,
39 unsigned order) 38 unsigned order)
40{ 39{
41 return __item_insert(root, item_create(index), order); 40 return __item_insert(root, item_create(index, order));
41}
42
43void item_sanity(struct item *item, unsigned long index)
44{
45 unsigned long mask;
46 assert(!radix_tree_is_internal_node(item));
47 assert(item->order < BITS_PER_LONG);
48 mask = (1UL << item->order) - 1;
49 assert((item->index | mask) == (index | mask));
42} 50}
43 51
44int item_delete(struct radix_tree_root *root, unsigned long index) 52int 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)
46 struct item *item = radix_tree_delete(root, index); 54 struct item *item = radix_tree_delete(root, index);
47 55
48 if (item) { 56 if (item) {
49 assert(item->index == index); 57 item_sanity(item, index);
50 free(item); 58 free(item);
51 return 1; 59 return 1;
52 } 60 }
53 return 0; 61 return 0;
54} 62}
55 63
56struct item *item_create(unsigned long index) 64struct item *item_create(unsigned long index, unsigned int order)
57{ 65{
58 struct item *ret = malloc(sizeof(*ret)); 66 struct item *ret = malloc(sizeof(*ret));
59 67
60 ret->index = index; 68 ret->index = index;
69 ret->order = order;
61 return ret; 70 return ret;
62} 71}
63 72
@@ -66,8 +75,8 @@ void item_check_present(struct radix_tree_root *root, unsigned long index)
66 struct item *item; 75 struct item *item;
67 76
68 item = radix_tree_lookup(root, index); 77 item = radix_tree_lookup(root, index);
69 assert(item != 0); 78 assert(item != NULL);
70 assert(item->index == index); 79 item_sanity(item, index);
71} 80}
72 81
73struct item *item_lookup(struct radix_tree_root *root, unsigned long index) 82struct 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)
80 struct item *item; 89 struct item *item;
81 90
82 item = radix_tree_lookup(root, index); 91 item = radix_tree_lookup(root, index);
83 assert(item == 0); 92 assert(item == NULL);
84} 93}
85 94
86/* 95/*
@@ -142,6 +151,62 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start,
142 assert(nfound == 0); 151 assert(nfound == 0);
143} 152}
144 153
154/* Use the same pattern as tag_pages_for_writeback() in mm/page-writeback.c */
155int tag_tagged_items(struct radix_tree_root *root, pthread_mutex_t *lock,
156 unsigned long start, unsigned long end, unsigned batch,
157 unsigned iftag, unsigned thentag)
158{
159 unsigned long tagged = 0;
160 struct radix_tree_iter iter;
161 void **slot;
162
163 if (batch == 0)
164 batch = 1;
165
166 if (lock)
167 pthread_mutex_lock(lock);
168 radix_tree_for_each_tagged(slot, root, &iter, start, iftag) {
169 if (iter.index > end)
170 break;
171 radix_tree_iter_tag_set(root, &iter, thentag);
172 tagged++;
173 if ((tagged % batch) != 0)
174 continue;
175 slot = radix_tree_iter_resume(slot, &iter);
176 if (lock) {
177 pthread_mutex_unlock(lock);
178 rcu_barrier();
179 pthread_mutex_lock(lock);
180 }
181 }
182 if (lock)
183 pthread_mutex_unlock(lock);
184
185 return tagged;
186}
187
188/* Use the same pattern as find_swap_entry() in mm/shmem.c */
189unsigned long find_item(struct radix_tree_root *root, void *item)
190{
191 struct radix_tree_iter iter;
192 void **slot;
193 unsigned long found = -1;
194 unsigned long checked = 0;
195
196 radix_tree_for_each_slot(slot, root, &iter, 0) {
197 if (*slot == item) {
198 found = iter.index;
199 break;
200 }
201 checked++;
202 if ((checked % 4) != 0)
203 continue;
204 slot = radix_tree_iter_resume(slot, &iter);
205 }
206
207 return found;
208}
209
145static int verify_node(struct radix_tree_node *slot, unsigned int tag, 210static int verify_node(struct radix_tree_node *slot, unsigned int tag,
146 int tagged) 211 int tagged)
147{ 212{
@@ -200,9 +265,16 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag)
200 265
201void item_kill_tree(struct radix_tree_root *root) 266void item_kill_tree(struct radix_tree_root *root)
202{ 267{
268 struct radix_tree_iter iter;
269 void **slot;
203 struct item *items[32]; 270 struct item *items[32];
204 int nfound; 271 int nfound;
205 272
273 radix_tree_for_each_slot(slot, root, &iter, 0) {
274 if (radix_tree_exceptional_entry(*slot))
275 radix_tree_delete(root, iter.index);
276 }
277
206 while ((nfound = radix_tree_gang_lookup(root, (void **)items, 0, 32))) { 278 while ((nfound = radix_tree_gang_lookup(root, (void **)items, 0, 32))) {
207 int i; 279 int i;
208 280
diff --git a/tools/testing/radix-tree/test.h b/tools/testing/radix-tree/test.h
index 217fb2403f09..056a23b56467 100644
--- a/tools/testing/radix-tree/test.h
+++ b/tools/testing/radix-tree/test.h
@@ -5,11 +5,11 @@
5 5
6struct item { 6struct item {
7 unsigned long index; 7 unsigned long index;
8 unsigned int order;
8}; 9};
9 10
10struct item *item_create(unsigned long index); 11struct item *item_create(unsigned long index, unsigned int order);
11int __item_insert(struct radix_tree_root *root, struct item *item, 12int __item_insert(struct radix_tree_root *root, struct item *item);
12 unsigned order);
13int item_insert(struct radix_tree_root *root, unsigned long index); 13int item_insert(struct radix_tree_root *root, unsigned long index);
14int item_insert_order(struct radix_tree_root *root, unsigned long index, 14int item_insert_order(struct radix_tree_root *root, unsigned long index,
15 unsigned order); 15 unsigned order);
@@ -25,9 +25,15 @@ void item_full_scan(struct radix_tree_root *root, unsigned long start,
25 unsigned long nr, int chunk); 25 unsigned long nr, int chunk);
26void item_kill_tree(struct radix_tree_root *root); 26void item_kill_tree(struct radix_tree_root *root);
27 27
28int tag_tagged_items(struct radix_tree_root *, pthread_mutex_t *,
29 unsigned long start, unsigned long end, unsigned batch,
30 unsigned iftag, unsigned thentag);
31unsigned long find_item(struct radix_tree_root *, void *item);
32
28void tag_check(void); 33void tag_check(void);
29void multiorder_checks(void); 34void multiorder_checks(void);
30void iteration_test(void); 35void iteration_test(unsigned order, unsigned duration);
36void benchmark(void);
31 37
32struct item * 38struct item *
33item_tag_set(struct radix_tree_root *root, unsigned long index, int tag); 39item_tag_set(struct radix_tree_root *root, unsigned long index, int tag);
@@ -40,7 +46,14 @@ void verify_tag_consistency(struct radix_tree_root *root, unsigned int tag);
40extern int nr_allocated; 46extern int nr_allocated;
41 47
42/* Normally private parts of lib/radix-tree.c */ 48/* Normally private parts of lib/radix-tree.c */
49struct radix_tree_node *entry_to_node(void *ptr);
43void radix_tree_dump(struct radix_tree_root *root); 50void radix_tree_dump(struct radix_tree_root *root);
44int root_tag_get(struct radix_tree_root *root, unsigned int tag); 51int root_tag_get(struct radix_tree_root *root, unsigned int tag);
45unsigned long node_maxindex(struct radix_tree_node *); 52unsigned long node_maxindex(struct radix_tree_node *);
46unsigned long shift_maxindex(unsigned int shift); 53unsigned long shift_maxindex(unsigned int shift);
54int radix_tree_cpu_dead(unsigned int cpu);
55struct radix_tree_preload {
56 unsigned nr;
57 struct radix_tree_node *nodes;
58};
59extern struct radix_tree_preload radix_tree_preloads;