xarray: Add xas_for_each_conflict
[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
687149fc
MW
649static noinline void check_destroy(struct xarray *xa)
650{
651 unsigned long index;
652
653 XA_BUG_ON(xa, !xa_empty(xa));
654
655 /* Destroying an empty array is a no-op */
656 xa_destroy(xa);
657 XA_BUG_ON(xa, !xa_empty(xa));
658
659 /* Destroying an array with a single entry */
660 for (index = 0; index < 1000; index++) {
661 xa_store_index(xa, index, GFP_KERNEL);
662 XA_BUG_ON(xa, xa_empty(xa));
663 xa_destroy(xa);
664 XA_BUG_ON(xa, !xa_empty(xa));
665 }
666
667 /* Destroying an array with a single entry at ULONG_MAX */
668 xa_store(xa, ULONG_MAX, xa, GFP_KERNEL);
669 XA_BUG_ON(xa, xa_empty(xa));
670 xa_destroy(xa);
671 XA_BUG_ON(xa, !xa_empty(xa));
672
673#ifdef CONFIG_XARRAY_MULTI
674 /* Destroying an array with a multi-index entry */
675 xa_store_order(xa, 1 << 11, 11, xa, GFP_KERNEL);
676 XA_BUG_ON(xa, xa_empty(xa));
677 xa_destroy(xa);
678 XA_BUG_ON(xa, !xa_empty(xa));
679#endif
680}
681
58d6ea30 682static DEFINE_XARRAY(array);
ad3d6c72
MW
683
684static int xarray_checks(void)
685{
58d6ea30 686 check_xa_err(&array);
b803b428 687 check_xas_retry(&array);
ad3d6c72 688 check_xa_load(&array);
9b89a035 689 check_xa_mark(&array);
58d6ea30 690 check_xa_shrink(&array);
b803b428 691 check_xas_erase(&array);
41aec91f 692 check_cmpxchg(&array);
58d6ea30 693 check_multi_store(&array);
b803b428 694 check_find(&array);
687149fc 695 check_destroy(&array);
64d3e9a9 696 check_move(&array);
4e99d4e9 697 check_store_iter(&array);
ad3d6c72
MW
698
699 printk("XArray: %u of %u tests passed\n", tests_passed, tests_run);
700 return (tests_run == tests_passed) ? 0 : -EINVAL;
701}
702
703static void xarray_exit(void)
704{
705}
706
707module_init(xarray_checks);
708module_exit(xarray_exit);
709MODULE_AUTHOR("Matthew Wilcox <willy@infradead.org>");
710MODULE_LICENSE("GPL");