]> asedeno.scripts.mit.edu Git - linux.git/blob - tools/testing/radix-tree/multiorder.c
72d80f7059d3155da93b0d81940013c97b50c4a3
[linux.git] / tools / testing / radix-tree / multiorder.c
1 /*
2  * multiorder.c: Multi-order radix tree entry testing
3  * Copyright (c) 2016 Intel Corporation
4  * Author: Ross Zwisler <ross.zwisler@linux.intel.com>
5  * Author: Matthew Wilcox <matthew.r.wilcox@intel.com>
6  *
7  * This program is free software; you can redistribute it and/or modify it
8  * under the terms and conditions of the GNU General Public License,
9  * version 2, as published by the Free Software Foundation.
10  *
11  * This program is distributed in the hope it will be useful, but WITHOUT
12  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13  * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
14  * more details.
15  */
16 #include <linux/radix-tree.h>
17 #include <linux/slab.h>
18 #include <linux/errno.h>
19
20 #include "test.h"
21
22 #define for_each_index(i, base, order) \
23         for (i = base; i < base + (1 << order); i++)
24
25 static void __multiorder_tag_test(int index, int order)
26 {
27         RADIX_TREE(tree, GFP_KERNEL);
28         int base, err, i;
29
30         /* our canonical entry */
31         base = index & ~((1 << order) - 1);
32
33         printv(2, "Multiorder tag test with index %d, canonical entry %d\n",
34                         index, base);
35
36         err = item_insert_order(&tree, index, order);
37         assert(!err);
38
39         /*
40          * Verify we get collisions for covered indices.  We try and fail to
41          * insert an exceptional entry so we don't leak memory via
42          * item_insert_order().
43          */
44         for_each_index(i, base, order) {
45                 err = __radix_tree_insert(&tree, i, order,
46                                 (void *)(0xA0 | RADIX_TREE_EXCEPTIONAL_ENTRY));
47                 assert(err == -EEXIST);
48         }
49
50         for_each_index(i, base, order) {
51                 assert(!radix_tree_tag_get(&tree, i, 0));
52                 assert(!radix_tree_tag_get(&tree, i, 1));
53         }
54
55         assert(radix_tree_tag_set(&tree, index, 0));
56
57         for_each_index(i, base, order) {
58                 assert(radix_tree_tag_get(&tree, i, 0));
59                 assert(!radix_tree_tag_get(&tree, i, 1));
60         }
61
62         assert(tag_tagged_items(&tree, NULL, 0, ~0UL, 10, 0, 1) == 1);
63         assert(radix_tree_tag_clear(&tree, index, 0));
64
65         for_each_index(i, base, order) {
66                 assert(!radix_tree_tag_get(&tree, i, 0));
67                 assert(radix_tree_tag_get(&tree, i, 1));
68         }
69
70         assert(radix_tree_tag_clear(&tree, index, 1));
71
72         assert(!radix_tree_tagged(&tree, 0));
73         assert(!radix_tree_tagged(&tree, 1));
74
75         item_kill_tree(&tree);
76 }
77
78 static void __multiorder_tag_test2(unsigned order, unsigned long index2)
79 {
80         RADIX_TREE(tree, GFP_KERNEL);
81         unsigned long index = (1 << order);
82         index2 += index;
83
84         assert(item_insert_order(&tree, 0, order) == 0);
85         assert(item_insert(&tree, index2) == 0);
86
87         assert(radix_tree_tag_set(&tree, 0, 0));
88         assert(radix_tree_tag_set(&tree, index2, 0));
89
90         assert(tag_tagged_items(&tree, NULL, 0, ~0UL, 10, 0, 1) == 2);
91
92         item_kill_tree(&tree);
93 }
94
95 static void multiorder_tag_tests(void)
96 {
97         int i, j;
98
99         /* test multi-order entry for indices 0-7 with no sibling pointers */
100         __multiorder_tag_test(0, 3);
101         __multiorder_tag_test(5, 3);
102
103         /* test multi-order entry for indices 8-15 with no sibling pointers */
104         __multiorder_tag_test(8, 3);
105         __multiorder_tag_test(15, 3);
106
107         /*
108          * Our order 5 entry covers indices 0-31 in a tree with height=2.
109          * This is broken up as follows:
110          * 0-7:         canonical entry
111          * 8-15:        sibling 1
112          * 16-23:       sibling 2
113          * 24-31:       sibling 3
114          */
115         __multiorder_tag_test(0, 5);
116         __multiorder_tag_test(29, 5);
117
118         /* same test, but with indices 32-63 */
119         __multiorder_tag_test(32, 5);
120         __multiorder_tag_test(44, 5);
121
122         /*
123          * Our order 8 entry covers indices 0-255 in a tree with height=3.
124          * This is broken up as follows:
125          * 0-63:        canonical entry
126          * 64-127:      sibling 1
127          * 128-191:     sibling 2
128          * 192-255:     sibling 3
129          */
130         __multiorder_tag_test(0, 8);
131         __multiorder_tag_test(190, 8);
132
133         /* same test, but with indices 256-511 */
134         __multiorder_tag_test(256, 8);
135         __multiorder_tag_test(300, 8);
136
137         __multiorder_tag_test(0x12345678UL, 8);
138
139         for (i = 1; i < 10; i++)
140                 for (j = 0; j < (10 << i); j++)
141                         __multiorder_tag_test2(i, j);
142 }
143
144 static void multiorder_check(unsigned long index, int order)
145 {
146         unsigned long i;
147         unsigned long min = index & ~((1UL << order) - 1);
148         unsigned long max = min + (1UL << order);
149         void **slot;
150         struct item *item2 = item_create(min, order);
151         RADIX_TREE(tree, GFP_KERNEL);
152
153         printv(2, "Multiorder index %ld, order %d\n", index, order);
154
155         assert(item_insert_order(&tree, index, order) == 0);
156
157         for (i = min; i < max; i++) {
158                 struct item *item = item_lookup(&tree, i);
159                 assert(item != 0);
160                 assert(item->index == index);
161         }
162         for (i = 0; i < min; i++)
163                 item_check_absent(&tree, i);
164         for (i = max; i < 2*max; i++)
165                 item_check_absent(&tree, i);
166         for (i = min; i < max; i++)
167                 assert(radix_tree_insert(&tree, i, item2) == -EEXIST);
168
169         slot = radix_tree_lookup_slot(&tree, index);
170         free(*slot);
171         radix_tree_replace_slot(&tree, slot, item2);
172         for (i = min; i < max; i++) {
173                 struct item *item = item_lookup(&tree, i);
174                 assert(item != 0);
175                 assert(item->index == min);
176         }
177
178         assert(item_delete(&tree, min) != 0);
179
180         for (i = 0; i < 2*max; i++)
181                 item_check_absent(&tree, i);
182 }
183
184 static void multiorder_shrink(unsigned long index, int order)
185 {
186         unsigned long i;
187         unsigned long max = 1 << order;
188         RADIX_TREE(tree, GFP_KERNEL);
189         struct radix_tree_node *node;
190
191         printv(2, "Multiorder shrink index %ld, order %d\n", index, order);
192
193         assert(item_insert_order(&tree, 0, order) == 0);
194
195         node = tree.rnode;
196
197         assert(item_insert(&tree, index) == 0);
198         assert(node != tree.rnode);
199
200         assert(item_delete(&tree, index) != 0);
201         assert(node == tree.rnode);
202
203         for (i = 0; i < max; i++) {
204                 struct item *item = item_lookup(&tree, i);
205                 assert(item != 0);
206                 assert(item->index == 0);
207         }
208         for (i = max; i < 2*max; i++)
209                 item_check_absent(&tree, i);
210
211         if (!item_delete(&tree, 0)) {
212                 printv(2, "failed to delete index %ld (order %d)\n", index, order);
213                 abort();
214         }
215
216         for (i = 0; i < 2*max; i++)
217                 item_check_absent(&tree, i);
218 }
219
220 static void multiorder_insert_bug(void)
221 {
222         RADIX_TREE(tree, GFP_KERNEL);
223
224         item_insert(&tree, 0);
225         radix_tree_tag_set(&tree, 0, 0);
226         item_insert_order(&tree, 3 << 6, 6);
227
228         item_kill_tree(&tree);
229 }
230
231 void multiorder_iteration(void)
232 {
233         RADIX_TREE(tree, GFP_KERNEL);
234         struct radix_tree_iter iter;
235         void **slot;
236         int i, j, err;
237
238         printv(1, "Multiorder iteration test\n");
239
240 #define NUM_ENTRIES 11
241         int index[NUM_ENTRIES] = {0, 2, 4, 8, 16, 32, 34, 36, 64, 72, 128};
242         int order[NUM_ENTRIES] = {1, 1, 2, 3,  4,  1,  0,  1,  3,  0, 7};
243
244         for (i = 0; i < NUM_ENTRIES; i++) {
245                 err = item_insert_order(&tree, index[i], order[i]);
246                 assert(!err);
247         }
248
249         for (j = 0; j < 256; j++) {
250                 for (i = 0; i < NUM_ENTRIES; i++)
251                         if (j <= (index[i] | ((1 << order[i]) - 1)))
252                                 break;
253
254                 radix_tree_for_each_slot(slot, &tree, &iter, j) {
255                         int height = order[i] / RADIX_TREE_MAP_SHIFT;
256                         int shift = height * RADIX_TREE_MAP_SHIFT;
257                         unsigned long mask = (1UL << order[i]) - 1;
258                         struct item *item = *slot;
259
260                         assert((iter.index | mask) == (index[i] | mask));
261                         assert(iter.shift == shift);
262                         assert(!radix_tree_is_internal_node(item));
263                         assert((item->index | mask) == (index[i] | mask));
264                         assert(item->order == order[i]);
265                         i++;
266                 }
267         }
268
269         item_kill_tree(&tree);
270 }
271
272 void multiorder_tagged_iteration(void)
273 {
274         RADIX_TREE(tree, GFP_KERNEL);
275         struct radix_tree_iter iter;
276         void **slot;
277         int i, j;
278
279         printv(1, "Multiorder tagged iteration test\n");
280
281 #define MT_NUM_ENTRIES 9
282         int index[MT_NUM_ENTRIES] = {0, 2, 4, 16, 32, 40, 64, 72, 128};
283         int order[MT_NUM_ENTRIES] = {1, 0, 2, 4,  3,  1,  3,  0,   7};
284
285 #define TAG_ENTRIES 7
286         int tag_index[TAG_ENTRIES] = {0, 4, 16, 40, 64, 72, 128};
287
288         for (i = 0; i < MT_NUM_ENTRIES; i++)
289                 assert(!item_insert_order(&tree, index[i], order[i]));
290
291         assert(!radix_tree_tagged(&tree, 1));
292
293         for (i = 0; i < TAG_ENTRIES; i++)
294                 assert(radix_tree_tag_set(&tree, tag_index[i], 1));
295
296         for (j = 0; j < 256; j++) {
297                 int k;
298
299                 for (i = 0; i < TAG_ENTRIES; i++) {
300                         for (k = i; index[k] < tag_index[i]; k++)
301                                 ;
302                         if (j <= (index[k] | ((1 << order[k]) - 1)))
303                                 break;
304                 }
305
306                 radix_tree_for_each_tagged(slot, &tree, &iter, j, 1) {
307                         unsigned long mask;
308                         struct item *item = *slot;
309                         for (k = i; index[k] < tag_index[i]; k++)
310                                 ;
311                         mask = (1UL << order[k]) - 1;
312
313                         assert((iter.index | mask) == (tag_index[i] | mask));
314                         assert(!radix_tree_is_internal_node(item));
315                         assert((item->index | mask) == (tag_index[i] | mask));
316                         assert(item->order == order[k]);
317                         i++;
318                 }
319         }
320
321         assert(tag_tagged_items(&tree, NULL, 0, ~0UL, TAG_ENTRIES, 1, 2) ==
322                                 TAG_ENTRIES);
323
324         for (j = 0; j < 256; j++) {
325                 int mask, k;
326
327                 for (i = 0; i < TAG_ENTRIES; i++) {
328                         for (k = i; index[k] < tag_index[i]; k++)
329                                 ;
330                         if (j <= (index[k] | ((1 << order[k]) - 1)))
331                                 break;
332                 }
333
334                 radix_tree_for_each_tagged(slot, &tree, &iter, j, 2) {
335                         struct item *item = *slot;
336                         for (k = i; index[k] < tag_index[i]; k++)
337                                 ;
338                         mask = (1 << order[k]) - 1;
339
340                         assert((iter.index | mask) == (tag_index[i] | mask));
341                         assert(!radix_tree_is_internal_node(item));
342                         assert((item->index | mask) == (tag_index[i] | mask));
343                         assert(item->order == order[k]);
344                         i++;
345                 }
346         }
347
348         assert(tag_tagged_items(&tree, NULL, 1, ~0UL, MT_NUM_ENTRIES * 2, 1, 0)
349                         == TAG_ENTRIES);
350         i = 0;
351         radix_tree_for_each_tagged(slot, &tree, &iter, 0, 0) {
352                 assert(iter.index == tag_index[i]);
353                 i++;
354         }
355
356         item_kill_tree(&tree);
357 }
358
359 static void multiorder_join1(unsigned long index,
360                                 unsigned order1, unsigned order2)
361 {
362         unsigned long loc;
363         void *item, *item2 = item_create(index + 1, order1);
364         RADIX_TREE(tree, GFP_KERNEL);
365
366         item_insert_order(&tree, index, order2);
367         item = radix_tree_lookup(&tree, index);
368         radix_tree_join(&tree, index + 1, order1, item2);
369         loc = find_item(&tree, item);
370         if (loc == -1)
371                 free(item);
372         item = radix_tree_lookup(&tree, index + 1);
373         assert(item == item2);
374         item_kill_tree(&tree);
375 }
376
377 static void multiorder_join2(unsigned order1, unsigned order2)
378 {
379         RADIX_TREE(tree, GFP_KERNEL);
380         struct radix_tree_node *node;
381         void *item1 = item_create(0, order1);
382         void *item2;
383
384         item_insert_order(&tree, 0, order2);
385         radix_tree_insert(&tree, 1 << order2, (void *)0x12UL);
386         item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL);
387         assert(item2 == (void *)0x12UL);
388         assert(node->exceptional == 1);
389
390         radix_tree_join(&tree, 0, order1, item1);
391         item2 = __radix_tree_lookup(&tree, 1 << order2, &node, NULL);
392         assert(item2 == item1);
393         assert(node->exceptional == 0);
394         item_kill_tree(&tree);
395 }
396
397 /*
398  * This test revealed an accounting bug for exceptional entries at one point.
399  * Nodes were being freed back into the pool with an elevated exception count
400  * by radix_tree_join() and then radix_tree_split() was failing to zero the
401  * count of exceptional entries.
402  */
403 static void multiorder_join3(unsigned int order)
404 {
405         RADIX_TREE(tree, GFP_KERNEL);
406         struct radix_tree_node *node;
407         void **slot;
408         struct radix_tree_iter iter;
409         unsigned long i;
410
411         for (i = 0; i < (1 << order); i++) {
412                 radix_tree_insert(&tree, i, (void *)0x12UL);
413         }
414
415         radix_tree_join(&tree, 0, order, (void *)0x16UL);
416         rcu_barrier();
417
418         radix_tree_split(&tree, 0, 0);
419
420         radix_tree_for_each_slot(slot, &tree, &iter, 0) {
421                 radix_tree_iter_replace(&tree, &iter, slot, (void *)0x12UL);
422         }
423
424         __radix_tree_lookup(&tree, 0, &node, NULL);
425         assert(node->exceptional == node->count);
426
427         item_kill_tree(&tree);
428 }
429
430 static void multiorder_join(void)
431 {
432         int i, j, idx;
433
434         for (idx = 0; idx < 1024; idx = idx * 2 + 3) {
435                 for (i = 1; i < 15; i++) {
436                         for (j = 0; j < i; j++) {
437                                 multiorder_join1(idx, i, j);
438                         }
439                 }
440         }
441
442         for (i = 1; i < 15; i++) {
443                 for (j = 0; j < i; j++) {
444                         multiorder_join2(i, j);
445                 }
446         }
447
448         for (i = 3; i < 10; i++) {
449                 multiorder_join3(i);
450         }
451 }
452
453 static void check_mem(unsigned old_order, unsigned new_order, unsigned alloc)
454 {
455         struct radix_tree_preload *rtp = &radix_tree_preloads;
456         if (rtp->nr != 0)
457                 printv(2, "split(%u %u) remaining %u\n", old_order, new_order,
458                                                         rtp->nr);
459         /*
460          * Can't check for equality here as some nodes may have been
461          * RCU-freed while we ran.  But we should never finish with more
462          * nodes allocated since they should have all been preloaded.
463          */
464         if (nr_allocated > alloc)
465                 printv(2, "split(%u %u) allocated %u %u\n", old_order, new_order,
466                                                         alloc, nr_allocated);
467 }
468
469 static void __multiorder_split(int old_order, int new_order)
470 {
471         RADIX_TREE(tree, GFP_ATOMIC);
472         void **slot;
473         struct radix_tree_iter iter;
474         unsigned alloc;
475
476         radix_tree_preload(GFP_KERNEL);
477         assert(item_insert_order(&tree, 0, old_order) == 0);
478         radix_tree_preload_end();
479
480         /* Wipe out the preloaded cache or it'll confuse check_mem() */
481         radix_tree_cpu_dead(0);
482
483         radix_tree_tag_set(&tree, 0, 2);
484
485         radix_tree_split_preload(old_order, new_order, GFP_KERNEL);
486         alloc = nr_allocated;
487         radix_tree_split(&tree, 0, new_order);
488         check_mem(old_order, new_order, alloc);
489         radix_tree_for_each_slot(slot, &tree, &iter, 0) {
490                 radix_tree_iter_replace(&tree, &iter, slot,
491                                         item_create(iter.index, new_order));
492         }
493         radix_tree_preload_end();
494
495         item_kill_tree(&tree);
496 }
497
498 static void __multiorder_split2(int old_order, int new_order)
499 {
500         RADIX_TREE(tree, GFP_KERNEL);
501         void **slot;
502         struct radix_tree_iter iter;
503         struct radix_tree_node *node;
504         void *item;
505
506         __radix_tree_insert(&tree, 0, old_order, (void *)0x12);
507
508         item = __radix_tree_lookup(&tree, 0, &node, NULL);
509         assert(item == (void *)0x12);
510         assert(node->exceptional > 0);
511
512         radix_tree_split(&tree, 0, new_order);
513         radix_tree_for_each_slot(slot, &tree, &iter, 0) {
514                 radix_tree_iter_replace(&tree, &iter, slot,
515                                         item_create(iter.index, new_order));
516         }
517
518         item = __radix_tree_lookup(&tree, 0, &node, NULL);
519         assert(item != (void *)0x12);
520         assert(node->exceptional == 0);
521
522         item_kill_tree(&tree);
523 }
524
525 static void __multiorder_split3(int old_order, int new_order)
526 {
527         RADIX_TREE(tree, GFP_KERNEL);
528         void **slot;
529         struct radix_tree_iter iter;
530         struct radix_tree_node *node;
531         void *item;
532
533         __radix_tree_insert(&tree, 0, old_order, (void *)0x12);
534
535         item = __radix_tree_lookup(&tree, 0, &node, NULL);
536         assert(item == (void *)0x12);
537         assert(node->exceptional > 0);
538
539         radix_tree_split(&tree, 0, new_order);
540         radix_tree_for_each_slot(slot, &tree, &iter, 0) {
541                 radix_tree_iter_replace(&tree, &iter, slot, (void *)0x16);
542         }
543
544         item = __radix_tree_lookup(&tree, 0, &node, NULL);
545         assert(item == (void *)0x16);
546         assert(node->exceptional > 0);
547
548         item_kill_tree(&tree);
549
550         __radix_tree_insert(&tree, 0, old_order, (void *)0x12);
551
552         item = __radix_tree_lookup(&tree, 0, &node, NULL);
553         assert(item == (void *)0x12);
554         assert(node->exceptional > 0);
555
556         radix_tree_split(&tree, 0, new_order);
557         radix_tree_for_each_slot(slot, &tree, &iter, 0) {
558                 if (iter.index == (1 << new_order))
559                         radix_tree_iter_replace(&tree, &iter, slot,
560                                                 (void *)0x16);
561                 else
562                         radix_tree_iter_replace(&tree, &iter, slot, NULL);
563         }
564
565         item = __radix_tree_lookup(&tree, 1 << new_order, &node, NULL);
566         assert(item == (void *)0x16);
567         assert(node->count == node->exceptional);
568         do {
569                 node = node->parent;
570                 if (!node)
571                         break;
572                 assert(node->count == 1);
573                 assert(node->exceptional == 0);
574         } while (1);
575
576         item_kill_tree(&tree);
577 }
578
579 static void multiorder_split(void)
580 {
581         int i, j;
582
583         for (i = 3; i < 11; i++)
584                 for (j = 0; j < i; j++) {
585                         __multiorder_split(i, j);
586                         __multiorder_split2(i, j);
587                         __multiorder_split3(i, j);
588                 }
589 }
590
591 static void multiorder_account(void)
592 {
593         RADIX_TREE(tree, GFP_KERNEL);
594         struct radix_tree_node *node;
595         void **slot;
596
597         item_insert_order(&tree, 0, 5);
598
599         __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12);
600         __radix_tree_lookup(&tree, 0, &node, NULL);
601         assert(node->count == node->exceptional * 2);
602         radix_tree_delete(&tree, 1 << 5);
603         assert(node->exceptional == 0);
604
605         __radix_tree_insert(&tree, 1 << 5, 5, (void *)0x12);
606         __radix_tree_lookup(&tree, 1 << 5, &node, &slot);
607         assert(node->count == node->exceptional * 2);
608         __radix_tree_replace(&tree, node, slot, NULL, NULL, NULL);
609         assert(node->exceptional == 0);
610
611         item_kill_tree(&tree);
612 }
613
614 void multiorder_checks(void)
615 {
616         int i;
617
618         for (i = 0; i < 20; i++) {
619                 multiorder_check(200, i);
620                 multiorder_check(0, i);
621                 multiorder_check((1UL << i) + 1, i);
622         }
623
624         for (i = 0; i < 15; i++)
625                 multiorder_shrink((1UL << (i + RADIX_TREE_MAP_SHIFT)), i);
626
627         multiorder_insert_bug();
628         multiorder_tag_tests();
629         multiorder_iteration();
630         multiorder_tagged_iteration();
631         multiorder_join();
632         multiorder_split();
633         multiorder_account();
634
635         radix_tree_cpu_dead(0);
636 }
637
638 int __weak main(void)
639 {
640         radix_tree_init();
641         multiorder_checks();
642         return 0;
643 }