hc
2023-12-11 d2ccde1c8e90d38cee87a1b0309ad2827f3fd30d
kernel/tools/testing/radix-tree/iteration_check.c
....@@ -1,52 +1,57 @@
1
+// SPDX-License-Identifier: GPL-2.0-only
12 /*
2
- * iteration_check.c: test races having to do with radix tree iteration
3
+ * iteration_check.c: test races having to do with xarray iteration
34 * Copyright (c) 2016 Intel Corporation
45 * Author: Ross Zwisler <ross.zwisler@linux.intel.com>
5
- *
6
- * This program is free software; you can redistribute it and/or modify it
7
- * under the terms and conditions of the GNU General Public License,
8
- * version 2, as published by the Free Software Foundation.
9
- *
10
- * This program is distributed in the hope it will be useful, but WITHOUT
11
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13
- * more details.
146 */
15
-#include <linux/radix-tree.h>
167 #include <pthread.h>
178 #include "test.h"
189
1910 #define NUM_THREADS 5
2011 #define MAX_IDX 100
21
-#define TAG 0
22
-#define NEW_TAG 1
12
+#define TAG XA_MARK_0
13
+#define NEW_TAG XA_MARK_1
2314
24
-static pthread_mutex_t tree_lock = PTHREAD_MUTEX_INITIALIZER;
2515 static pthread_t threads[NUM_THREADS];
2616 static unsigned int seeds[3];
27
-static RADIX_TREE(tree, GFP_KERNEL);
17
+static DEFINE_XARRAY(array);
2818 static bool test_complete;
2919 static int max_order;
3020
31
-/* relentlessly fill the tree with tagged entries */
21
+void my_item_insert(struct xarray *xa, unsigned long index)
22
+{
23
+ XA_STATE(xas, xa, index);
24
+ struct item *item = item_create(index, 0);
25
+ int order;
26
+
27
+retry:
28
+ xas_lock(&xas);
29
+ for (order = max_order; order >= 0; order--) {
30
+ xas_set_order(&xas, index, order);
31
+ item->order = order;
32
+ if (xas_find_conflict(&xas))
33
+ continue;
34
+ xas_store(&xas, item);
35
+ xas_set_mark(&xas, TAG);
36
+ break;
37
+ }
38
+ xas_unlock(&xas);
39
+ if (xas_nomem(&xas, GFP_KERNEL))
40
+ goto retry;
41
+ if (order < 0)
42
+ free(item);
43
+}
44
+
45
+/* relentlessly fill the array with tagged entries */
3246 static void *add_entries_fn(void *arg)
3347 {
3448 rcu_register_thread();
3549
3650 while (!test_complete) {
3751 unsigned long pgoff;
38
- int order;
3952
4053 for (pgoff = 0; pgoff < MAX_IDX; pgoff++) {
41
- pthread_mutex_lock(&tree_lock);
42
- for (order = max_order; order >= 0; order--) {
43
- if (item_insert_order(&tree, pgoff, order)
44
- == 0) {
45
- item_tag_set(&tree, pgoff, TAG);
46
- break;
47
- }
48
- }
49
- pthread_mutex_unlock(&tree_lock);
54
+ my_item_insert(&array, pgoff);
5055 }
5156 }
5257
....@@ -56,33 +61,25 @@
5661 }
5762
5863 /*
59
- * Iterate over the tagged entries, doing a radix_tree_iter_retry() as we find
60
- * things that have been removed and randomly resetting our iteration to the
61
- * next chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and
62
- * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a
63
- * NULL 'slot' variable.
64
+ * Iterate over tagged entries, retrying when we find ourselves in a deleted
65
+ * node and randomly pausing the iteration.
6466 */
6567 static void *tagged_iteration_fn(void *arg)
6668 {
67
- struct radix_tree_iter iter;
68
- void **slot;
69
+ XA_STATE(xas, &array, 0);
70
+ void *entry;
6971
7072 rcu_register_thread();
7173
7274 while (!test_complete) {
75
+ xas_set(&xas, 0);
7376 rcu_read_lock();
74
- radix_tree_for_each_tagged(slot, &tree, &iter, 0, TAG) {
75
- void *entry = radix_tree_deref_slot(slot);
76
- if (unlikely(!entry))
77
+ xas_for_each_marked(&xas, entry, ULONG_MAX, TAG) {
78
+ if (xas_retry(&xas, entry))
7779 continue;
78
-
79
- if (radix_tree_deref_retry(entry)) {
80
- slot = radix_tree_iter_retry(&iter);
81
- continue;
82
- }
8380
8481 if (rand_r(&seeds[0]) % 50 == 0) {
85
- slot = radix_tree_iter_resume(slot, &iter);
82
+ xas_pause(&xas);
8683 rcu_read_unlock();
8784 rcu_barrier();
8885 rcu_read_lock();
....@@ -97,33 +94,25 @@
9794 }
9895
9996 /*
100
- * Iterate over the entries, doing a radix_tree_iter_retry() as we find things
101
- * that have been removed and randomly resetting our iteration to the next
102
- * chunk with radix_tree_iter_resume(). Both radix_tree_iter_retry() and
103
- * radix_tree_iter_resume() cause radix_tree_next_slot() to be called with a
104
- * NULL 'slot' variable.
97
+ * Iterate over the entries, retrying when we find ourselves in a deleted
98
+ * node and randomly pausing the iteration.
10599 */
106100 static void *untagged_iteration_fn(void *arg)
107101 {
108
- struct radix_tree_iter iter;
109
- void **slot;
102
+ XA_STATE(xas, &array, 0);
103
+ void *entry;
110104
111105 rcu_register_thread();
112106
113107 while (!test_complete) {
108
+ xas_set(&xas, 0);
114109 rcu_read_lock();
115
- radix_tree_for_each_slot(slot, &tree, &iter, 0) {
116
- void *entry = radix_tree_deref_slot(slot);
117
- if (unlikely(!entry))
110
+ xas_for_each(&xas, entry, ULONG_MAX) {
111
+ if (xas_retry(&xas, entry))
118112 continue;
119
-
120
- if (radix_tree_deref_retry(entry)) {
121
- slot = radix_tree_iter_retry(&iter);
122
- continue;
123
- }
124113
125114 if (rand_r(&seeds[1]) % 50 == 0) {
126
- slot = radix_tree_iter_resume(slot, &iter);
115
+ xas_pause(&xas);
127116 rcu_read_unlock();
128117 rcu_barrier();
129118 rcu_read_lock();
....@@ -138,7 +127,7 @@
138127 }
139128
140129 /*
141
- * Randomly remove entries to help induce radix_tree_iter_retry() calls in the
130
+ * Randomly remove entries to help induce retries in the
142131 * two iteration functions.
143132 */
144133 static void *remove_entries_fn(void *arg)
....@@ -147,12 +136,13 @@
147136
148137 while (!test_complete) {
149138 int pgoff;
139
+ struct item *item;
150140
151141 pgoff = rand_r(&seeds[2]) % MAX_IDX;
152142
153
- pthread_mutex_lock(&tree_lock);
154
- item_delete(&tree, pgoff);
155
- pthread_mutex_unlock(&tree_lock);
143
+ item = xa_erase(&array, pgoff);
144
+ if (item)
145
+ item_free(item, pgoff);
156146 }
157147
158148 rcu_unregister_thread();
....@@ -165,8 +155,7 @@
165155 rcu_register_thread();
166156
167157 while (!test_complete) {
168
- tag_tagged_items(&tree, &tree_lock, 0, MAX_IDX, 10, TAG,
169
- NEW_TAG);
158
+ tag_tagged_items(&array, 0, MAX_IDX, 10, TAG, NEW_TAG);
170159 }
171160 rcu_unregister_thread();
172161 return NULL;
....@@ -217,5 +206,5 @@
217206 }
218207 }
219208
220
- item_kill_tree(&tree);
209
+ item_kill_tree(&array);
221210 }