aboutsummaryrefslogtreecommitdiffstats
path: root/tools/testing/radix-tree/iteration_check.c
diff options
context:
space:
mode:
Diffstat (limited to 'tools/testing/radix-tree/iteration_check.c')
-rw-r--r--tools/testing/radix-tree/iteration_check.c123
1 files changed, 82 insertions, 41 deletions
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++) {