xarray: Add xas_create_range
[linux-2.6-block.git] / lib / test_xarray.c
CommitLineData
ad3d6c72
MW
1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * test_xarray.c: Test the XArray API
4 * Copyright (c) 2017-2018 Microsoft Corporation
5 * Author: Matthew Wilcox <willy@infradead.org>
6 */
7
8#include <linux/xarray.h>
9#include <linux/module.h>
10
11static unsigned int tests_run;
12static unsigned int tests_passed;
13
14#ifndef XA_DEBUG
15# ifdef __KERNEL__
16void xa_dump(const struct xarray *xa) { }
17# endif
18#undef XA_BUG_ON
19#define XA_BUG_ON(xa, x) do { \
20 tests_run++; \
21 if (x) { \
22 printk("BUG at %s:%d\n", __func__, __LINE__); \
23 xa_dump(xa); \
24 dump_stack(); \
25 } else { \
26 tests_passed++; \
27 } \
28} while (0)
29#endif
30
31static void *xa_store_index(struct xarray *xa, unsigned long index, gfp_t gfp)
32{
58d6ea30 33 return xa_store(xa, index, xa_mk_value(index & LONG_MAX), gfp);
ad3d6c72
MW
34}
35
36static void xa_erase_index(struct xarray *xa, unsigned long index)
37{
58d6ea30
MW
38 XA_BUG_ON(xa, xa_erase(xa, index) != xa_mk_value(index & LONG_MAX));
39 XA_BUG_ON(xa, xa_load(xa, index) != NULL);
40}
41
42/*
43 * If anyone needs this, please move it to xarray.c. We have no current
44 * users outside the test suite because all current multislot users want
45 * to use the advanced API.
46 */
47static void *xa_store_order(struct xarray *xa, unsigned long index,
48 unsigned order, void *entry, gfp_t gfp)
49{
50 XA_STATE_ORDER(xas, xa, index, order);
51 void *curr;
52
53 do {
54 xas_lock(&xas);
55 curr = xas_store(&xas, entry);
56 xas_unlock(&xas);
57 } while (xas_nomem(&xas, gfp));
58
59 return curr;
60}
61
62static noinline void check_xa_err(struct xarray *xa)
63{
64 XA_BUG_ON(xa, xa_err(xa_store_index(xa, 0, GFP_NOWAIT)) != 0);
65 XA_BUG_ON(xa, xa_err(xa_erase(xa, 0)) != 0);
66#ifndef __KERNEL__
67 /* The kernel does not fail GFP_NOWAIT allocations */
68 XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_NOWAIT)) != -ENOMEM);
69 XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_NOWAIT)) != -ENOMEM);
70#endif
71 XA_BUG_ON(xa, xa_err(xa_store_index(xa, 1, GFP_KERNEL)) != 0);
72 XA_BUG_ON(xa, xa_err(xa_store(xa, 1, xa_mk_value(0), GFP_KERNEL)) != 0);
73 XA_BUG_ON(xa, xa_err(xa_erase(xa, 1)) != 0);
74// kills the test-suite :-(
75// XA_BUG_ON(xa, xa_err(xa_store(xa, 0, xa_mk_internal(0), 0)) != -EINVAL);
ad3d6c72
MW
76}
77
b803b428
MW
78static noinline void check_xas_retry(struct xarray *xa)
79{
80 XA_STATE(xas, xa, 0);
81 void *entry;
82
83 xa_store_index(xa, 0, GFP_KERNEL);
84 xa_store_index(xa, 1, GFP_KERNEL);
85
86 rcu_read_lock();
87 XA_BUG_ON(xa, xas_find(&xas, ULONG_MAX) != xa_mk_value(0));
88 xa_erase_index(xa, 1);
89 XA_BUG_ON(xa, !xa_is_retry(xas_reload(&xas)));
90 XA_BUG_ON(xa, xas_retry(&xas, NULL));
91 XA_BUG_ON(xa, xas_retry(&xas, xa_mk_value(0)));
92 xas_reset(&xas);
93 XA_BUG_ON(xa, xas.xa_node != XAS_RESTART);
94 XA_BUG_ON(xa, xas_next_entry(&xas, ULONG_MAX) != xa_mk_value(0));
95 XA_BUG_ON(xa, xas.xa_node != NULL);
96
97 XA_BUG_ON(xa, xa_store_index(xa, 1, GFP_KERNEL) != NULL);
98 XA_BUG_ON(xa, !xa_is_internal(xas_reload(&xas)));
99 xas.xa_node = XAS_RESTART;
100 XA_BUG_ON(xa, xas_next_entry(&xas, ULONG_MAX) != xa_mk_value(0));
101 rcu_read_unlock();
102
103 /* Make sure we can iterate through retry entries */
104 xas_lock(&xas);
105 xas_set(&xas, 0);
106 xas_store(&xas, XA_RETRY_ENTRY);
107 xas_set(&xas, 1);
108 xas_store(&xas, XA_RETRY_ENTRY);
109
110 xas_set(&xas, 0);
111 xas_for_each(&xas, entry, ULONG_MAX) {
112 xas_store(&xas, xa_mk_value(xas.xa_index));
113 }
114 xas_unlock(&xas);
115
116 xa_erase_index(xa, 0);
117 xa_erase_index(xa, 1);
118}
119
ad3d6c72
MW
120static noinline void check_xa_load(struct xarray *xa)
121{
122 unsigned long i, j;
123
124 for (i = 0; i < 1024; i++) {
125 for (j = 0; j < 1024; j++) {
126 void *entry = xa_load(xa, j);
127 if (j < i)
128 XA_BUG_ON(xa, xa_to_value(entry) != j);
129 else
130 XA_BUG_ON(xa, entry);
131 }
132 XA_BUG_ON(xa, xa_store_index(xa, i, GFP_KERNEL) != NULL);
133 }
134
135 for (i = 0; i < 1024; i++) {
136 for (j = 0; j < 1024; j++) {
137 void *entry = xa_load(xa, j);
138 if (j >= i)
139 XA_BUG_ON(xa, xa_to_value(entry) != j);
140 else
141 XA_BUG_ON(xa, entry);
142 }
143 xa_erase_index(xa, i);
144 }
145 XA_BUG_ON(xa, !xa_empty(xa));
146}
147
9b89a035
MW
148static noinline void check_xa_mark_1(struct xarray *xa, unsigned long index)
149{
58d6ea30
MW
150 unsigned int order;
151 unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 8 : 1;
152
9b89a035
MW
153 /* NULL elements have no marks set */
154 XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
155 xa_set_mark(xa, index, XA_MARK_0);
156 XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
157
158 /* Storing a pointer will not make a mark appear */
159 XA_BUG_ON(xa, xa_store_index(xa, index, GFP_KERNEL) != NULL);
160 XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
161 xa_set_mark(xa, index, XA_MARK_0);
162 XA_BUG_ON(xa, !xa_get_mark(xa, index, XA_MARK_0));
163
164 /* Setting one mark will not set another mark */
165 XA_BUG_ON(xa, xa_get_mark(xa, index + 1, XA_MARK_0));
166 XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_1));
167
168 /* Storing NULL clears marks, and they can't be set again */
169 xa_erase_index(xa, index);
170 XA_BUG_ON(xa, !xa_empty(xa));
171 XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
172 xa_set_mark(xa, index, XA_MARK_0);
173 XA_BUG_ON(xa, xa_get_mark(xa, index, XA_MARK_0));
58d6ea30
MW
174
175 /*
176 * Storing a multi-index entry over entries with marks gives the
177 * entire entry the union of the marks
178 */
179 BUG_ON((index % 4) != 0);
180 for (order = 2; order < max_order; order++) {
181 unsigned long base = round_down(index, 1UL << order);
182 unsigned long next = base + (1UL << order);
183 unsigned long i;
184
185 XA_BUG_ON(xa, xa_store_index(xa, index + 1, GFP_KERNEL));
186 xa_set_mark(xa, index + 1, XA_MARK_0);
187 XA_BUG_ON(xa, xa_store_index(xa, index + 2, GFP_KERNEL));
188 xa_set_mark(xa, index + 2, XA_MARK_1);
189 XA_BUG_ON(xa, xa_store_index(xa, next, GFP_KERNEL));
190 xa_store_order(xa, index, order, xa_mk_value(index),
191 GFP_KERNEL);
192 for (i = base; i < next; i++) {
193 XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_0));
194 XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_1));
195 XA_BUG_ON(xa, xa_get_mark(xa, i, XA_MARK_2));
196 }
197 XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_0));
198 XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_1));
199 XA_BUG_ON(xa, xa_get_mark(xa, next, XA_MARK_2));
200 xa_erase_index(xa, index);
201 xa_erase_index(xa, next);
202 XA_BUG_ON(xa, !xa_empty(xa));
203 }
204 XA_BUG_ON(xa, !xa_empty(xa));
9b89a035
MW
205}
206
207static noinline void check_xa_mark(struct xarray *xa)
208{
209 unsigned long index;
210
211 for (index = 0; index < 16384; index += 4)
212 check_xa_mark_1(xa, index);
213}
214
58d6ea30
MW
215static noinline void check_xa_shrink(struct xarray *xa)
216{
217 XA_STATE(xas, xa, 1);
218 struct xa_node *node;
219
220 XA_BUG_ON(xa, !xa_empty(xa));
221 XA_BUG_ON(xa, xa_store_index(xa, 0, GFP_KERNEL) != NULL);
222 XA_BUG_ON(xa, xa_store_index(xa, 1, GFP_KERNEL) != NULL);
223
224 /*
225 * Check that erasing the entry at 1 shrinks the tree and properly
226 * marks the node as being deleted.
227 */
228 xas_lock(&xas);
229 XA_BUG_ON(xa, xas_load(&xas) != xa_mk_value(1));
230 node = xas.xa_node;
231 XA_BUG_ON(xa, xa_entry_locked(xa, node, 0) != xa_mk_value(0));
232 XA_BUG_ON(xa, xas_store(&xas, NULL) != xa_mk_value(1));
233 XA_BUG_ON(xa, xa_load(xa, 1) != NULL);
234 XA_BUG_ON(xa, xas.xa_node != XAS_BOUNDS);
235 XA_BUG_ON(xa, xa_entry_locked(xa, node, 0) != XA_RETRY_ENTRY);
236 XA_BUG_ON(xa, xas_load(&xas) != NULL);
237 xas_unlock(&xas);
238 XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0));
239 xa_erase_index(xa, 0);
240 XA_BUG_ON(xa, !xa_empty(xa));
241}
242
41aec91f
MW
243static noinline void check_cmpxchg(struct xarray *xa)
244{
245 void *FIVE = xa_mk_value(5);
246 void *SIX = xa_mk_value(6);
247 void *LOTS = xa_mk_value(12345678);
248
249 XA_BUG_ON(xa, !xa_empty(xa));
250 XA_BUG_ON(xa, xa_store_index(xa, 12345678, GFP_KERNEL) != NULL);
251 XA_BUG_ON(xa, xa_insert(xa, 12345678, xa, GFP_KERNEL) != -EEXIST);
252 XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, SIX, FIVE, GFP_KERNEL) != LOTS);
253 XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, LOTS, FIVE, GFP_KERNEL) != LOTS);
254 XA_BUG_ON(xa, xa_cmpxchg(xa, 12345678, FIVE, LOTS, GFP_KERNEL) != FIVE);
255 XA_BUG_ON(xa, xa_cmpxchg(xa, 5, FIVE, NULL, GFP_KERNEL) != NULL);
256 XA_BUG_ON(xa, xa_cmpxchg(xa, 5, NULL, FIVE, GFP_KERNEL) != NULL);
257 xa_erase_index(xa, 12345678);
258 xa_erase_index(xa, 5);
259 XA_BUG_ON(xa, !xa_empty(xa));
260}
261
b803b428
MW
262static noinline void check_xas_erase(struct xarray *xa)
263{
264 XA_STATE(xas, xa, 0);
265 void *entry;
266 unsigned long i, j;
267
268 for (i = 0; i < 200; i++) {
269 for (j = i; j < 2 * i + 17; j++) {
270 xas_set(&xas, j);
271 do {
272 xas_lock(&xas);
273 xas_store(&xas, xa_mk_value(j));
274 xas_unlock(&xas);
275 } while (xas_nomem(&xas, GFP_KERNEL));
276 }
277
278 xas_set(&xas, ULONG_MAX);
279 do {
280 xas_lock(&xas);
281 xas_store(&xas, xa_mk_value(0));
282 xas_unlock(&xas);
283 } while (xas_nomem(&xas, GFP_KERNEL));
284
285 xas_lock(&xas);
286 xas_store(&xas, NULL);
287
288 xas_set(&xas, 0);
289 j = i;
290 xas_for_each(&xas, entry, ULONG_MAX) {
291 XA_BUG_ON(xa, entry != xa_mk_value(j));
292 xas_store(&xas, NULL);
293 j++;
294 }
295 xas_unlock(&xas);
296 XA_BUG_ON(xa, !xa_empty(xa));
297 }
298}
299
58d6ea30
MW
300static noinline void check_multi_store(struct xarray *xa)
301{
302#ifdef CONFIG_XARRAY_MULTI
303 unsigned long i, j, k;
304 unsigned int max_order = (sizeof(long) == 4) ? 30 : 60;
305
306 /* Loading from any position returns the same value */
307 xa_store_order(xa, 0, 1, xa_mk_value(0), GFP_KERNEL);
308 XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0));
309 XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(0));
310 XA_BUG_ON(xa, xa_load(xa, 2) != NULL);
311 rcu_read_lock();
312 XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 2);
313 XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 2);
314 rcu_read_unlock();
315
316 /* Storing adjacent to the value does not alter the value */
317 xa_store(xa, 3, xa, GFP_KERNEL);
318 XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(0));
319 XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(0));
320 XA_BUG_ON(xa, xa_load(xa, 2) != NULL);
321 rcu_read_lock();
322 XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 3);
323 XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 2);
324 rcu_read_unlock();
325
326 /* Overwriting multiple indexes works */
327 xa_store_order(xa, 0, 2, xa_mk_value(1), GFP_KERNEL);
328 XA_BUG_ON(xa, xa_load(xa, 0) != xa_mk_value(1));
329 XA_BUG_ON(xa, xa_load(xa, 1) != xa_mk_value(1));
330 XA_BUG_ON(xa, xa_load(xa, 2) != xa_mk_value(1));
331 XA_BUG_ON(xa, xa_load(xa, 3) != xa_mk_value(1));
332 XA_BUG_ON(xa, xa_load(xa, 4) != NULL);
333 rcu_read_lock();
334 XA_BUG_ON(xa, xa_to_node(xa_head(xa))->count != 4);
335 XA_BUG_ON(xa, xa_to_node(xa_head(xa))->nr_values != 4);
336 rcu_read_unlock();
337
338 /* We can erase multiple values with a single store */
339 xa_store_order(xa, 0, 63, NULL, GFP_KERNEL);
340 XA_BUG_ON(xa, !xa_empty(xa));
341
342 /* Even when the first slot is empty but the others aren't */
343 xa_store_index(xa, 1, GFP_KERNEL);
344 xa_store_index(xa, 2, GFP_KERNEL);
345 xa_store_order(xa, 0, 2, NULL, GFP_KERNEL);
346 XA_BUG_ON(xa, !xa_empty(xa));
347
348 for (i = 0; i < max_order; i++) {
349 for (j = 0; j < max_order; j++) {
350 xa_store_order(xa, 0, i, xa_mk_value(i), GFP_KERNEL);
351 xa_store_order(xa, 0, j, xa_mk_value(j), GFP_KERNEL);
352
353 for (k = 0; k < max_order; k++) {
354 void *entry = xa_load(xa, (1UL << k) - 1);
355 if ((i < k) && (j < k))
356 XA_BUG_ON(xa, entry != NULL);
357 else
358 XA_BUG_ON(xa, entry != xa_mk_value(j));
359 }
360
361 xa_erase(xa, 0);
362 XA_BUG_ON(xa, !xa_empty(xa));
363 }
364 }
365#endif
366}
367
4e99d4e9
MW
368static noinline void __check_store_iter(struct xarray *xa, unsigned long start,
369 unsigned int order, unsigned int present)
370{
371 XA_STATE_ORDER(xas, xa, start, order);
372 void *entry;
373 unsigned int count = 0;
374
375retry:
376 xas_lock(&xas);
377 xas_for_each_conflict(&xas, entry) {
378 XA_BUG_ON(xa, !xa_is_value(entry));
379 XA_BUG_ON(xa, entry < xa_mk_value(start));
380 XA_BUG_ON(xa, entry > xa_mk_value(start + (1UL << order) - 1));
381 count++;
382 }
383 xas_store(&xas, xa_mk_value(start));
384 xas_unlock(&xas);
385 if (xas_nomem(&xas, GFP_KERNEL)) {
386 count = 0;
387 goto retry;
388 }
389 XA_BUG_ON(xa, xas_error(&xas));
390 XA_BUG_ON(xa, count != present);
391 XA_BUG_ON(xa, xa_load(xa, start) != xa_mk_value(start));
392 XA_BUG_ON(xa, xa_load(xa, start + (1UL << order) - 1) !=
393 xa_mk_value(start));
394 xa_erase_index(xa, start);
395}
396
397static noinline void check_store_iter(struct xarray *xa)
398{
399 unsigned int i, j;
400 unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 20 : 1;
401
402 for (i = 0; i < max_order; i++) {
403 unsigned int min = 1 << i;
404 unsigned int max = (2 << i) - 1;
405 __check_store_iter(xa, 0, i, 0);
406 XA_BUG_ON(xa, !xa_empty(xa));
407 __check_store_iter(xa, min, i, 0);
408 XA_BUG_ON(xa, !xa_empty(xa));
409
410 xa_store_index(xa, min, GFP_KERNEL);
411 __check_store_iter(xa, min, i, 1);
412 XA_BUG_ON(xa, !xa_empty(xa));
413 xa_store_index(xa, max, GFP_KERNEL);
414 __check_store_iter(xa, min, i, 1);
415 XA_BUG_ON(xa, !xa_empty(xa));
416
417 for (j = 0; j < min; j++)
418 xa_store_index(xa, j, GFP_KERNEL);
419 __check_store_iter(xa, 0, i, min);
420 XA_BUG_ON(xa, !xa_empty(xa));
421 for (j = 0; j < min; j++)
422 xa_store_index(xa, min + j, GFP_KERNEL);
423 __check_store_iter(xa, min, i, min);
424 XA_BUG_ON(xa, !xa_empty(xa));
425 }
426#ifdef CONFIG_XARRAY_MULTI
427 xa_store_index(xa, 63, GFP_KERNEL);
428 xa_store_index(xa, 65, GFP_KERNEL);
429 __check_store_iter(xa, 64, 2, 1);
430 xa_erase_index(xa, 63);
431#endif
432 XA_BUG_ON(xa, !xa_empty(xa));
433}
434
b803b428
MW
435static noinline void check_multi_find(struct xarray *xa)
436{
437#ifdef CONFIG_XARRAY_MULTI
438 unsigned long index;
439
440 xa_store_order(xa, 12, 2, xa_mk_value(12), GFP_KERNEL);
441 XA_BUG_ON(xa, xa_store_index(xa, 16, GFP_KERNEL) != NULL);
442
443 index = 0;
444 XA_BUG_ON(xa, xa_find(xa, &index, ULONG_MAX, XA_PRESENT) !=
445 xa_mk_value(12));
446 XA_BUG_ON(xa, index != 12);
447 index = 13;
448 XA_BUG_ON(xa, xa_find(xa, &index, ULONG_MAX, XA_PRESENT) !=
449 xa_mk_value(12));
450 XA_BUG_ON(xa, (index < 12) || (index >= 16));
451 XA_BUG_ON(xa, xa_find_after(xa, &index, ULONG_MAX, XA_PRESENT) !=
452 xa_mk_value(16));
453 XA_BUG_ON(xa, index != 16);
454
455 xa_erase_index(xa, 12);
456 xa_erase_index(xa, 16);
457 XA_BUG_ON(xa, !xa_empty(xa));
458#endif
459}
460
461static noinline void check_multi_find_2(struct xarray *xa)
462{
463 unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 10 : 1;
464 unsigned int i, j;
465 void *entry;
466
467 for (i = 0; i < max_order; i++) {
468 unsigned long index = 1UL << i;
469 for (j = 0; j < index; j++) {
470 XA_STATE(xas, xa, j + index);
471 xa_store_index(xa, index - 1, GFP_KERNEL);
472 xa_store_order(xa, index, i, xa_mk_value(index),
473 GFP_KERNEL);
474 rcu_read_lock();
475 xas_for_each(&xas, entry, ULONG_MAX) {
476 xa_erase_index(xa, index);
477 }
478 rcu_read_unlock();
479 xa_erase_index(xa, index - 1);
480 XA_BUG_ON(xa, !xa_empty(xa));
481 }
482 }
483}
484
485static noinline void check_find(struct xarray *xa)
486{
487 unsigned long i, j, k;
488
489 XA_BUG_ON(xa, !xa_empty(xa));
490
491 /*
492 * Check xa_find with all pairs between 0 and 99 inclusive,
493 * starting at every index between 0 and 99
494 */
495 for (i = 0; i < 100; i++) {
496 XA_BUG_ON(xa, xa_store_index(xa, i, GFP_KERNEL) != NULL);
497 xa_set_mark(xa, i, XA_MARK_0);
498 for (j = 0; j < i; j++) {
499 XA_BUG_ON(xa, xa_store_index(xa, j, GFP_KERNEL) !=
500 NULL);
501 xa_set_mark(xa, j, XA_MARK_0);
502 for (k = 0; k < 100; k++) {
503 unsigned long index = k;
504 void *entry = xa_find(xa, &index, ULONG_MAX,
505 XA_PRESENT);
506 if (k <= j)
507 XA_BUG_ON(xa, index != j);
508 else if (k <= i)
509 XA_BUG_ON(xa, index != i);
510 else
511 XA_BUG_ON(xa, entry != NULL);
512
513 index = k;
514 entry = xa_find(xa, &index, ULONG_MAX,
515 XA_MARK_0);
516 if (k <= j)
517 XA_BUG_ON(xa, index != j);
518 else if (k <= i)
519 XA_BUG_ON(xa, index != i);
520 else
521 XA_BUG_ON(xa, entry != NULL);
522 }
523 xa_erase_index(xa, j);
524 XA_BUG_ON(xa, xa_get_mark(xa, j, XA_MARK_0));
525 XA_BUG_ON(xa, !xa_get_mark(xa, i, XA_MARK_0));
526 }
527 xa_erase_index(xa, i);
528 XA_BUG_ON(xa, xa_get_mark(xa, i, XA_MARK_0));
529 }
530 XA_BUG_ON(xa, !xa_empty(xa));
531 check_multi_find(xa);
532 check_multi_find_2(xa);
533}
534
64d3e9a9
MW
535static noinline void check_move_small(struct xarray *xa, unsigned long idx)
536{
537 XA_STATE(xas, xa, 0);
538 unsigned long i;
539
540 xa_store_index(xa, 0, GFP_KERNEL);
541 xa_store_index(xa, idx, GFP_KERNEL);
542
543 rcu_read_lock();
544 for (i = 0; i < idx * 4; i++) {
545 void *entry = xas_next(&xas);
546 if (i <= idx)
547 XA_BUG_ON(xa, xas.xa_node == XAS_RESTART);
548 XA_BUG_ON(xa, xas.xa_index != i);
549 if (i == 0 || i == idx)
550 XA_BUG_ON(xa, entry != xa_mk_value(i));
551 else
552 XA_BUG_ON(xa, entry != NULL);
553 }
554 xas_next(&xas);
555 XA_BUG_ON(xa, xas.xa_index != i);
556
557 do {
558 void *entry = xas_prev(&xas);
559 i--;
560 if (i <= idx)
561 XA_BUG_ON(xa, xas.xa_node == XAS_RESTART);
562 XA_BUG_ON(xa, xas.xa_index != i);
563 if (i == 0 || i == idx)
564 XA_BUG_ON(xa, entry != xa_mk_value(i));
565 else
566 XA_BUG_ON(xa, entry != NULL);
567 } while (i > 0);
568
569 xas_set(&xas, ULONG_MAX);
570 XA_BUG_ON(xa, xas_next(&xas) != NULL);
571 XA_BUG_ON(xa, xas.xa_index != ULONG_MAX);
572 XA_BUG_ON(xa, xas_next(&xas) != xa_mk_value(0));
573 XA_BUG_ON(xa, xas.xa_index != 0);
574 XA_BUG_ON(xa, xas_prev(&xas) != NULL);
575 XA_BUG_ON(xa, xas.xa_index != ULONG_MAX);
576 rcu_read_unlock();
577
578 xa_erase_index(xa, 0);
579 xa_erase_index(xa, idx);
580 XA_BUG_ON(xa, !xa_empty(xa));
581}
582
583static noinline void check_move(struct xarray *xa)
584{
585 XA_STATE(xas, xa, (1 << 16) - 1);
586 unsigned long i;
587
588 for (i = 0; i < (1 << 16); i++)
589 XA_BUG_ON(xa, xa_store_index(xa, i, GFP_KERNEL) != NULL);
590
591 rcu_read_lock();
592 do {
593 void *entry = xas_prev(&xas);
594 i--;
595 XA_BUG_ON(xa, entry != xa_mk_value(i));
596 XA_BUG_ON(xa, i != xas.xa_index);
597 } while (i != 0);
598
599 XA_BUG_ON(xa, xas_prev(&xas) != NULL);
600 XA_BUG_ON(xa, xas.xa_index != ULONG_MAX);
601
602 do {
603 void *entry = xas_next(&xas);
604 XA_BUG_ON(xa, entry != xa_mk_value(i));
605 XA_BUG_ON(xa, i != xas.xa_index);
606 i++;
607 } while (i < (1 << 16));
608 rcu_read_unlock();
609
610 for (i = (1 << 8); i < (1 << 15); i++)
611 xa_erase_index(xa, i);
612
613 i = xas.xa_index;
614
615 rcu_read_lock();
616 do {
617 void *entry = xas_prev(&xas);
618 i--;
619 if ((i < (1 << 8)) || (i >= (1 << 15)))
620 XA_BUG_ON(xa, entry != xa_mk_value(i));
621 else
622 XA_BUG_ON(xa, entry != NULL);
623 XA_BUG_ON(xa, i != xas.xa_index);
624 } while (i != 0);
625
626 XA_BUG_ON(xa, xas_prev(&xas) != NULL);
627 XA_BUG_ON(xa, xas.xa_index != ULONG_MAX);
628
629 do {
630 void *entry = xas_next(&xas);
631 if ((i < (1 << 8)) || (i >= (1 << 15)))
632 XA_BUG_ON(xa, entry != xa_mk_value(i));
633 else
634 XA_BUG_ON(xa, entry != NULL);
635 XA_BUG_ON(xa, i != xas.xa_index);
636 i++;
637 } while (i < (1 << 16));
638 rcu_read_unlock();
639
640 xa_destroy(xa);
641
642 for (i = 0; i < 16; i++)
643 check_move_small(xa, 1UL << i);
644
645 for (i = 2; i < 16; i++)
646 check_move_small(xa, (1UL << i) - 1);
647}
648
2264f513
MW
649static noinline void xa_store_many_order(struct xarray *xa,
650 unsigned long index, unsigned order)
651{
652 XA_STATE_ORDER(xas, xa, index, order);
653 unsigned int i = 0;
654
655 do {
656 xas_lock(&xas);
657 XA_BUG_ON(xa, xas_find_conflict(&xas));
658 xas_create_range(&xas);
659 if (xas_error(&xas))
660 goto unlock;
661 for (i = 0; i < (1U << order); i++) {
662 XA_BUG_ON(xa, xas_store(&xas, xa_mk_value(index + i)));
663 xas_next(&xas);
664 }
665unlock:
666 xas_unlock(&xas);
667 } while (xas_nomem(&xas, GFP_KERNEL));
668
669 XA_BUG_ON(xa, xas_error(&xas));
670}
671
672static noinline void check_create_range_1(struct xarray *xa,
673 unsigned long index, unsigned order)
674{
675 unsigned long i;
676
677 xa_store_many_order(xa, index, order);
678 for (i = index; i < index + (1UL << order); i++)
679 xa_erase_index(xa, i);
680 XA_BUG_ON(xa, !xa_empty(xa));
681}
682
683static noinline void check_create_range_2(struct xarray *xa, unsigned order)
684{
685 unsigned long i;
686 unsigned long nr = 1UL << order;
687
688 for (i = 0; i < nr * nr; i += nr)
689 xa_store_many_order(xa, i, order);
690 for (i = 0; i < nr * nr; i++)
691 xa_erase_index(xa, i);
692 XA_BUG_ON(xa, !xa_empty(xa));
693}
694
695static noinline void check_create_range_3(void)
696{
697 XA_STATE(xas, NULL, 0);
698 xas_set_err(&xas, -EEXIST);
699 xas_create_range(&xas);
700 XA_BUG_ON(NULL, xas_error(&xas) != -EEXIST);
701}
702
703static noinline void check_create_range_4(struct xarray *xa,
704 unsigned long index, unsigned order)
705{
706 XA_STATE_ORDER(xas, xa, index, order);
707 unsigned long base = xas.xa_index;
708 unsigned long i = 0;
709
710 xa_store_index(xa, index, GFP_KERNEL);
711 do {
712 xas_lock(&xas);
713 xas_create_range(&xas);
714 if (xas_error(&xas))
715 goto unlock;
716 for (i = 0; i < (1UL << order); i++) {
717 void *old = xas_store(&xas, xa_mk_value(base + i));
718 if (xas.xa_index == index)
719 XA_BUG_ON(xa, old != xa_mk_value(base + i));
720 else
721 XA_BUG_ON(xa, old != NULL);
722 xas_next(&xas);
723 }
724unlock:
725 xas_unlock(&xas);
726 } while (xas_nomem(&xas, GFP_KERNEL));
727
728 XA_BUG_ON(xa, xas_error(&xas));
729
730 for (i = base; i < base + (1UL << order); i++)
731 xa_erase_index(xa, i);
732 XA_BUG_ON(xa, !xa_empty(xa));
733}
734
735static noinline void check_create_range(struct xarray *xa)
736{
737 unsigned int order;
738 unsigned int max_order = IS_ENABLED(CONFIG_XARRAY_MULTI) ? 12 : 1;
739
740 for (order = 0; order < max_order; order++) {
741 check_create_range_1(xa, 0, order);
742 check_create_range_1(xa, 1U << order, order);
743 check_create_range_1(xa, 2U << order, order);
744 check_create_range_1(xa, 3U << order, order);
745 check_create_range_1(xa, 1U << 24, order);
746 if (order < 10)
747 check_create_range_2(xa, order);
748
749 check_create_range_4(xa, 0, order);
750 check_create_range_4(xa, 1U << order, order);
751 check_create_range_4(xa, 2U << order, order);
752 check_create_range_4(xa, 3U << order, order);
753 check_create_range_4(xa, 1U << 24, order);
754
755 check_create_range_4(xa, 1, order);
756 check_create_range_4(xa, (1U << order) + 1, order);
757 check_create_range_4(xa, (2U << order) + 1, order);
758 check_create_range_4(xa, (2U << order) - 1, order);
759 check_create_range_4(xa, (3U << order) + 1, order);
760 check_create_range_4(xa, (3U << order) - 1, order);
761 check_create_range_4(xa, (1U << 24) + 1, order);
762 }
763
764 check_create_range_3();
765}
766
687149fc
MW
767static noinline void check_destroy(struct xarray *xa)
768{
769 unsigned long index;
770
771 XA_BUG_ON(xa, !xa_empty(xa));
772
773 /* Destroying an empty array is a no-op */
774 xa_destroy(xa);
775 XA_BUG_ON(xa, !xa_empty(xa));
776
777 /* Destroying an array with a single entry */
778 for (index = 0; index < 1000; index++) {
779 xa_store_index(xa, index, GFP_KERNEL);
780 XA_BUG_ON(xa, xa_empty(xa));
781 xa_destroy(xa);
782 XA_BUG_ON(xa, !xa_empty(xa));
783 }
784
785 /* Destroying an array with a single entry at ULONG_MAX */
786 xa_store(xa, ULONG_MAX, xa, GFP_KERNEL);
787 XA_BUG_ON(xa, xa_empty(xa));
788 xa_destroy(xa);
789 XA_BUG_ON(xa, !xa_empty(xa));
790
791#ifdef CONFIG_XARRAY_MULTI
792 /* Destroying an array with a multi-index entry */
793 xa_store_order(xa, 1 << 11, 11, xa, GFP_KERNEL);
794 XA_BUG_ON(xa, xa_empty(xa));
795 xa_destroy(xa);
796 XA_BUG_ON(xa, !xa_empty(xa));
797#endif
798}
799
58d6ea30 800static DEFINE_XARRAY(array);
ad3d6c72
MW
801
802static int xarray_checks(void)
803{
58d6ea30 804 check_xa_err(&array);
b803b428 805 check_xas_retry(&array);
ad3d6c72 806 check_xa_load(&array);
9b89a035 807 check_xa_mark(&array);
58d6ea30 808 check_xa_shrink(&array);
b803b428 809 check_xas_erase(&array);
41aec91f 810 check_cmpxchg(&array);
58d6ea30 811 check_multi_store(&array);
b803b428 812 check_find(&array);
687149fc 813 check_destroy(&array);
64d3e9a9 814 check_move(&array);
2264f513 815 check_create_range(&array);
4e99d4e9 816 check_store_iter(&array);
ad3d6c72
MW
817
818 printk("XArray: %u of %u tests passed\n", tests_passed, tests_run);
819 return (tests_run == tests_passed) ? 0 : -EINVAL;
820}
821
822static void xarray_exit(void)
823{
824}
825
826module_init(xarray_checks);
827module_exit(xarray_exit);
828MODULE_AUTHOR("Matthew Wilcox <willy@infradead.org>");
829MODULE_LICENSE("GPL");