diff options
Diffstat (limited to 'tools/testing/radix-tree/iteration_check.c')
-rw-r--r-- | tools/testing/radix-tree/iteration_check.c | 80 |
1 files changed, 47 insertions, 33 deletions
diff --git a/tools/testing/radix-tree/iteration_check.c b/tools/testing/radix-tree/iteration_check.c index f328a66899b4..7572b7ed930e 100644 --- a/tools/testing/radix-tree/iteration_check.c +++ b/tools/testing/radix-tree/iteration_check.c | |||
@@ -16,26 +16,36 @@ | |||
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 | |||
21 | static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER; | 24 | static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER; |
22 | static pthread_t threads[NUM_THREADS]; | 25 | static pthread_t threads[NUM_THREADS]; |
23 | static unsigned int seeds[3]; | 26 | static unsigned int seeds[3]; |
24 | RADIX_TREE(tree, GFP_KERNEL); | 27 | static RADIX_TREE(tree, GFP_KERNEL); |
25 | bool test_complete; | 28 | static bool test_complete; |
29 | static int max_order; | ||
26 | 30 | ||
27 | /* relentlessly fill the tree with tagged entries */ | 31 | /* relentlessly fill the tree with tagged entries */ |
28 | static void *add_entries_fn(void *arg) | 32 | static void *add_entries_fn(void *arg) |
29 | { | 33 | { |
30 | int pgoff; | ||
31 | |||
32 | rcu_register_thread(); | 34 | rcu_register_thread(); |
33 | 35 | ||
34 | while (!test_complete) { | 36 | while (!test_complete) { |
35 | for (pgoff = 0; pgoff < 100; pgoff++) { | 37 | unsigned long pgoff; |
38 | int order; | ||
39 | |||
40 | for (pgoff = 0; pgoff < MAX_IDX; pgoff++) { | ||
36 | pthread_mutex_lock(&tree_lock); | 41 | pthread_mutex_lock(&tree_lock); |
37 | if (item_insert(&tree, pgoff) == 0) | 42 | for (order = max_order; order >= 0; order--) { |
38 | 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 | } | ||
39 | pthread_mutex_unlock(&tree_lock); | 49 | pthread_mutex_unlock(&tree_lock); |
40 | } | 50 | } |
41 | } | 51 | } |
@@ -62,14 +72,7 @@ static void *tagged_iteration_fn(void *arg) | |||
62 | while (!test_complete) { | 72 | while (!test_complete) { |
63 | rcu_read_lock(); | 73 | rcu_read_lock(); |
64 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) { | 74 | radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) { |
65 | void *entry; | 75 | void *entry = radix_tree_deref_slot(slot); |
66 | int i; | ||
67 | |||
68 | /* busy wait to let removals happen */ | ||
69 | for (i = 0; i < 1000000; i++) | ||
70 | ; | ||
71 | |||
72 | entry = radix_tree_deref_slot(slot); | ||
73 | if (unlikely(!entry)) | 76 | if (unlikely(!entry)) |
74 | continue; | 77 | continue; |
75 | 78 | ||
@@ -110,14 +113,7 @@ static void *untagged_iteration_fn(void *arg) | |||
110 | while (!test_complete) { | 113 | while (!test_complete) { |
111 | rcu_read_lock(); | 114 | rcu_read_lock(); |
112 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { | 115 | radix_tree_for_each_slot(slot, &tree, &iter, 0) { |
113 | void *entry; | 116 | void *entry = radix_tree_deref_slot(slot); |
114 | int i; | ||
115 | |||
116 | /* busy wait to let removals happen */ | ||
117 | for (i = 0; i < 1000000; i++) | ||
118 | ; | ||
119 | |||
120 | entry = radix_tree_deref_slot(slot); | ||
121 | if (unlikely(!entry)) | 117 | if (unlikely(!entry)) |
122 | continue; | 118 | continue; |
123 | 119 | ||
@@ -152,7 +148,7 @@ static void *remove_entries_fn(void *arg) | |||
152 | while (!test_complete) { | 148 | while (!test_complete) { |
153 | int pgoff; | 149 | int pgoff; |
154 | 150 | ||
155 | pgoff = rand_r(&seeds[2]) % 100; | 151 | pgoff = rand_r(&seeds[2]) % MAX_IDX; |
156 | 152 | ||
157 | pthread_mutex_lock(&tree_lock); | 153 | pthread_mutex_lock(&tree_lock); |
158 | item_delete(&tree, pgoff); | 154 | item_delete(&tree, pgoff); |
@@ -164,36 +160,54 @@ static void *remove_entries_fn(void *arg) | |||
164 | return NULL; | 160 | return NULL; |
165 | } | 161 | } |
166 | 162 | ||
163 | static 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(); | ||
172 | return NULL; | ||
173 | } | ||
174 | |||
167 | /* 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 */ |
168 | void iteration_test(void) | 176 | void iteration_test(unsigned order, unsigned test_duration) |
169 | { | 177 | { |
170 | int i; | 178 | int i; |
171 | 179 | ||
172 | printf("Running iteration tests for 10 seconds\n"); | 180 | printf("Running %siteration tests for %d seconds\n", |
181 | order > 0 ? "multiorder " : "", test_duration); | ||
173 | 182 | ||
183 | max_order = order; | ||
174 | test_complete = false; | 184 | test_complete = false; |
175 | 185 | ||
176 | for (i = 0; i < 3; i++) | 186 | for (i = 0; i < 3; i++) |
177 | seeds[i] = rand(); | 187 | seeds[i] = rand(); |
178 | 188 | ||
179 | if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) { | 189 | if (pthread_create(&threads[0], NULL, tagged_iteration_fn, NULL)) { |
180 | perror("pthread_create"); | 190 | perror("create tagged iteration thread"); |
181 | exit(1); | 191 | exit(1); |
182 | } | 192 | } |
183 | if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) { | 193 | if (pthread_create(&threads[1], NULL, untagged_iteration_fn, NULL)) { |
184 | perror("pthread_create"); | 194 | perror("create untagged iteration thread"); |
185 | exit(1); | 195 | exit(1); |
186 | } | 196 | } |
187 | if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) { | 197 | if (pthread_create(&threads[2], NULL, add_entries_fn, NULL)) { |
188 | perror("pthread_create"); | 198 | perror("create add entry thread"); |
189 | exit(1); | 199 | exit(1); |
190 | } | 200 | } |
191 | if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) { | 201 | if (pthread_create(&threads[3], NULL, remove_entries_fn, NULL)) { |
192 | 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"); | ||
193 | exit(1); | 207 | exit(1); |
194 | } | 208 | } |
195 | 209 | ||
196 | sleep(10); | 210 | sleep(test_duration); |
197 | test_complete = true; | 211 | test_complete = true; |
198 | 212 | ||
199 | for (i = 0; i < NUM_THREADS; i++) { | 213 | for (i = 0; i < NUM_THREADS; i++) { |