root/tools/testing/radix-tree/idr-test.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. item_idr_free
  2. item_idr_remove
  3. idr_alloc_test
  4. idr_replace_test
  5. idr_null_test
  6. idr_nowait_test
  7. idr_get_next_test
  8. idr_u32_cb
  9. idr_u32_test1
  10. idr_u32_test
  11. idr_align_test
  12. idr_throbber
  13. idr_find_test_1
  14. idr_find_test
  15. idr_checks
  16. ida_check_nomem
  17. ida_check_conv_user
  18. ida_check_random
  19. ida_simple_get_remove_test
  20. user_ida_checks
  21. ida_random_fn
  22. ida_thread_tests
  23. ida_tests
  24. main

   1 // SPDX-License-Identifier: GPL-2.0-only
   2 /*
   3  * idr-test.c: Test the IDR API
   4  * Copyright (c) 2016 Matthew Wilcox <willy@infradead.org>
   5  */
   6 #include <linux/bitmap.h>
   7 #include <linux/idr.h>
   8 #include <linux/slab.h>
   9 #include <linux/kernel.h>
  10 #include <linux/errno.h>
  11 
  12 #include "test.h"
  13 
  14 #define DUMMY_PTR       ((void *)0x10)
  15 
  16 int item_idr_free(int id, void *p, void *data)
  17 {
  18         struct item *item = p;
  19         assert(item->index == id);
  20         free(p);
  21 
  22         return 0;
  23 }
  24 
  25 void item_idr_remove(struct idr *idr, int id)
  26 {
  27         struct item *item = idr_find(idr, id);
  28         assert(item->index == id);
  29         idr_remove(idr, id);
  30         free(item);
  31 }
  32 
  33 void idr_alloc_test(void)
  34 {
  35         unsigned long i;
  36         DEFINE_IDR(idr);
  37 
  38         assert(idr_alloc_cyclic(&idr, DUMMY_PTR, 0, 0x4000, GFP_KERNEL) == 0);
  39         assert(idr_alloc_cyclic(&idr, DUMMY_PTR, 0x3ffd, 0x4000, GFP_KERNEL) == 0x3ffd);
  40         idr_remove(&idr, 0x3ffd);
  41         idr_remove(&idr, 0);
  42 
  43         for (i = 0x3ffe; i < 0x4003; i++) {
  44                 int id;
  45                 struct item *item;
  46 
  47                 if (i < 0x4000)
  48                         item = item_create(i, 0);
  49                 else
  50                         item = item_create(i - 0x3fff, 0);
  51 
  52                 id = idr_alloc_cyclic(&idr, item, 1, 0x4000, GFP_KERNEL);
  53                 assert(id == item->index);
  54         }
  55 
  56         idr_for_each(&idr, item_idr_free, &idr);
  57         idr_destroy(&idr);
  58 }
  59 
  60 void idr_replace_test(void)
  61 {
  62         DEFINE_IDR(idr);
  63 
  64         idr_alloc(&idr, (void *)-1, 10, 11, GFP_KERNEL);
  65         idr_replace(&idr, &idr, 10);
  66 
  67         idr_destroy(&idr);
  68 }
  69 
  70 /*
  71  * Unlike the radix tree, you can put a NULL pointer -- with care -- into
  72  * the IDR.  Some interfaces, like idr_find() do not distinguish between
  73  * "present, value is NULL" and "not present", but that's exactly what some
  74  * users want.
  75  */
  76 void idr_null_test(void)
  77 {
  78         int i;
  79         DEFINE_IDR(idr);
  80 
  81         assert(idr_is_empty(&idr));
  82 
  83         assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
  84         assert(!idr_is_empty(&idr));
  85         idr_remove(&idr, 0);
  86         assert(idr_is_empty(&idr));
  87 
  88         assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
  89         assert(!idr_is_empty(&idr));
  90         idr_destroy(&idr);
  91         assert(idr_is_empty(&idr));
  92 
  93         for (i = 0; i < 10; i++) {
  94                 assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == i);
  95         }
  96 
  97         assert(idr_replace(&idr, DUMMY_PTR, 3) == NULL);
  98         assert(idr_replace(&idr, DUMMY_PTR, 4) == NULL);
  99         assert(idr_replace(&idr, NULL, 4) == DUMMY_PTR);
 100         assert(idr_replace(&idr, DUMMY_PTR, 11) == ERR_PTR(-ENOENT));
 101         idr_remove(&idr, 5);
 102         assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 5);
 103         idr_remove(&idr, 5);
 104 
 105         for (i = 0; i < 9; i++) {
 106                 idr_remove(&idr, i);
 107                 assert(!idr_is_empty(&idr));
 108         }
 109         idr_remove(&idr, 8);
 110         assert(!idr_is_empty(&idr));
 111         idr_remove(&idr, 9);
 112         assert(idr_is_empty(&idr));
 113 
 114         assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
 115         assert(idr_replace(&idr, DUMMY_PTR, 3) == ERR_PTR(-ENOENT));
 116         assert(idr_replace(&idr, DUMMY_PTR, 0) == NULL);
 117         assert(idr_replace(&idr, NULL, 0) == DUMMY_PTR);
 118 
 119         idr_destroy(&idr);
 120         assert(idr_is_empty(&idr));
 121 
 122         for (i = 1; i < 10; i++) {
 123                 assert(idr_alloc(&idr, NULL, 1, 0, GFP_KERNEL) == i);
 124         }
 125 
 126         idr_destroy(&idr);
 127         assert(idr_is_empty(&idr));
 128 }
 129 
 130 void idr_nowait_test(void)
 131 {
 132         unsigned int i;
 133         DEFINE_IDR(idr);
 134 
 135         idr_preload(GFP_KERNEL);
 136 
 137         for (i = 0; i < 3; i++) {
 138                 struct item *item = item_create(i, 0);
 139                 assert(idr_alloc(&idr, item, i, i + 1, GFP_NOWAIT) == i);
 140         }
 141 
 142         idr_preload_end();
 143 
 144         idr_for_each(&idr, item_idr_free, &idr);
 145         idr_destroy(&idr);
 146 }
 147 
 148 void idr_get_next_test(int base)
 149 {
 150         unsigned long i;
 151         int nextid;
 152         DEFINE_IDR(idr);
 153         idr_init_base(&idr, base);
 154 
 155         int indices[] = {4, 7, 9, 15, 65, 128, 1000, 99999, 0};
 156 
 157         for(i = 0; indices[i]; i++) {
 158                 struct item *item = item_create(indices[i], 0);
 159                 assert(idr_alloc(&idr, item, indices[i], indices[i+1],
 160                                  GFP_KERNEL) == indices[i]);
 161         }
 162 
 163         for(i = 0, nextid = 0; indices[i]; i++) {
 164                 idr_get_next(&idr, &nextid);
 165                 assert(nextid == indices[i]);
 166                 nextid++;
 167         }
 168 
 169         idr_for_each(&idr, item_idr_free, &idr);
 170         idr_destroy(&idr);
 171 }
 172 
 173 int idr_u32_cb(int id, void *ptr, void *data)
 174 {
 175         BUG_ON(id < 0);
 176         BUG_ON(ptr != DUMMY_PTR);
 177         return 0;
 178 }
 179 
 180 void idr_u32_test1(struct idr *idr, u32 handle)
 181 {
 182         static bool warned = false;
 183         u32 id = handle;
 184         int sid = 0;
 185         void *ptr;
 186 
 187         BUG_ON(idr_alloc_u32(idr, DUMMY_PTR, &id, id, GFP_KERNEL));
 188         BUG_ON(id != handle);
 189         BUG_ON(idr_alloc_u32(idr, DUMMY_PTR, &id, id, GFP_KERNEL) != -ENOSPC);
 190         BUG_ON(id != handle);
 191         if (!warned && id > INT_MAX)
 192                 printk("vvv Ignore these warnings\n");
 193         ptr = idr_get_next(idr, &sid);
 194         if (id > INT_MAX) {
 195                 BUG_ON(ptr != NULL);
 196                 BUG_ON(sid != 0);
 197         } else {
 198                 BUG_ON(ptr != DUMMY_PTR);
 199                 BUG_ON(sid != id);
 200         }
 201         idr_for_each(idr, idr_u32_cb, NULL);
 202         if (!warned && id > INT_MAX) {
 203                 printk("^^^ Warnings over\n");
 204                 warned = true;
 205         }
 206         BUG_ON(idr_remove(idr, id) != DUMMY_PTR);
 207         BUG_ON(!idr_is_empty(idr));
 208 }
 209 
 210 void idr_u32_test(int base)
 211 {
 212         DEFINE_IDR(idr);
 213         idr_init_base(&idr, base);
 214         idr_u32_test1(&idr, 10);
 215         idr_u32_test1(&idr, 0x7fffffff);
 216         idr_u32_test1(&idr, 0x80000000);
 217         idr_u32_test1(&idr, 0x80000001);
 218         idr_u32_test1(&idr, 0xffe00000);
 219         idr_u32_test1(&idr, 0xffffffff);
 220 }
 221 
 222 static void idr_align_test(struct idr *idr)
 223 {
 224         char name[] = "Motorola 68000";
 225         int i, id;
 226         void *entry;
 227 
 228         for (i = 0; i < 9; i++) {
 229                 BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != i);
 230                 idr_for_each_entry(idr, entry, id);
 231         }
 232         idr_destroy(idr);
 233 
 234         for (i = 1; i < 10; i++) {
 235                 BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != i - 1);
 236                 idr_for_each_entry(idr, entry, id);
 237         }
 238         idr_destroy(idr);
 239 
 240         for (i = 2; i < 11; i++) {
 241                 BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != i - 2);
 242                 idr_for_each_entry(idr, entry, id);
 243         }
 244         idr_destroy(idr);
 245 
 246         for (i = 3; i < 12; i++) {
 247                 BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != i - 3);
 248                 idr_for_each_entry(idr, entry, id);
 249         }
 250         idr_destroy(idr);
 251 
 252         for (i = 0; i < 8; i++) {
 253                 BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != 0);
 254                 BUG_ON(idr_alloc(idr, &name[i + 1], 0, 0, GFP_KERNEL) != 1);
 255                 idr_for_each_entry(idr, entry, id);
 256                 idr_remove(idr, 1);
 257                 idr_for_each_entry(idr, entry, id);
 258                 idr_remove(idr, 0);
 259                 BUG_ON(!idr_is_empty(idr));
 260         }
 261 
 262         for (i = 0; i < 8; i++) {
 263                 BUG_ON(idr_alloc(idr, NULL, 0, 0, GFP_KERNEL) != 0);
 264                 idr_for_each_entry(idr, entry, id);
 265                 idr_replace(idr, &name[i], 0);
 266                 idr_for_each_entry(idr, entry, id);
 267                 BUG_ON(idr_find(idr, 0) != &name[i]);
 268                 idr_remove(idr, 0);
 269         }
 270 
 271         for (i = 0; i < 8; i++) {
 272                 BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != 0);
 273                 BUG_ON(idr_alloc(idr, NULL, 0, 0, GFP_KERNEL) != 1);
 274                 idr_remove(idr, 1);
 275                 idr_for_each_entry(idr, entry, id);
 276                 idr_replace(idr, &name[i + 1], 0);
 277                 idr_for_each_entry(idr, entry, id);
 278                 idr_remove(idr, 0);
 279         }
 280 }
 281 
 282 DEFINE_IDR(find_idr);
 283 
 284 static void *idr_throbber(void *arg)
 285 {
 286         time_t start = time(NULL);
 287         int id = *(int *)arg;
 288 
 289         rcu_register_thread();
 290         do {
 291                 idr_alloc(&find_idr, xa_mk_value(id), id, id + 1, GFP_KERNEL);
 292                 idr_remove(&find_idr, id);
 293         } while (time(NULL) < start + 10);
 294         rcu_unregister_thread();
 295 
 296         return NULL;
 297 }
 298 
 299 void idr_find_test_1(int anchor_id, int throbber_id)
 300 {
 301         pthread_t throbber;
 302         time_t start = time(NULL);
 303 
 304         pthread_create(&throbber, NULL, idr_throbber, &throbber_id);
 305 
 306         BUG_ON(idr_alloc(&find_idr, xa_mk_value(anchor_id), anchor_id,
 307                                 anchor_id + 1, GFP_KERNEL) != anchor_id);
 308 
 309         do {
 310                 int id = 0;
 311                 void *entry = idr_get_next(&find_idr, &id);
 312                 BUG_ON(entry != xa_mk_value(id));
 313         } while (time(NULL) < start + 11);
 314 
 315         pthread_join(throbber, NULL);
 316 
 317         idr_remove(&find_idr, anchor_id);
 318         BUG_ON(!idr_is_empty(&find_idr));
 319 }
 320 
 321 void idr_find_test(void)
 322 {
 323         idr_find_test_1(100000, 0);
 324         idr_find_test_1(0, 100000);
 325 }
 326 
 327 void idr_checks(void)
 328 {
 329         unsigned long i;
 330         DEFINE_IDR(idr);
 331 
 332         for (i = 0; i < 10000; i++) {
 333                 struct item *item = item_create(i, 0);
 334                 assert(idr_alloc(&idr, item, 0, 20000, GFP_KERNEL) == i);
 335         }
 336 
 337         assert(idr_alloc(&idr, DUMMY_PTR, 5, 30, GFP_KERNEL) < 0);
 338 
 339         for (i = 0; i < 5000; i++)
 340                 item_idr_remove(&idr, i);
 341 
 342         idr_remove(&idr, 3);
 343 
 344         idr_for_each(&idr, item_idr_free, &idr);
 345         idr_destroy(&idr);
 346 
 347         assert(idr_is_empty(&idr));
 348 
 349         idr_remove(&idr, 3);
 350         idr_remove(&idr, 0);
 351 
 352         assert(idr_alloc(&idr, DUMMY_PTR, 0, 0, GFP_KERNEL) == 0);
 353         idr_remove(&idr, 1);
 354         for (i = 1; i < RADIX_TREE_MAP_SIZE; i++)
 355                 assert(idr_alloc(&idr, DUMMY_PTR, 0, 0, GFP_KERNEL) == i);
 356         idr_remove(&idr, 1 << 30);
 357         idr_destroy(&idr);
 358 
 359         for (i = INT_MAX - 3UL; i < INT_MAX + 1UL; i++) {
 360                 struct item *item = item_create(i, 0);
 361                 assert(idr_alloc(&idr, item, i, i + 10, GFP_KERNEL) == i);
 362         }
 363         assert(idr_alloc(&idr, DUMMY_PTR, i - 2, i, GFP_KERNEL) == -ENOSPC);
 364         assert(idr_alloc(&idr, DUMMY_PTR, i - 2, i + 10, GFP_KERNEL) == -ENOSPC);
 365 
 366         idr_for_each(&idr, item_idr_free, &idr);
 367         idr_destroy(&idr);
 368         idr_destroy(&idr);
 369 
 370         assert(idr_is_empty(&idr));
 371 
 372         idr_set_cursor(&idr, INT_MAX - 3UL);
 373         for (i = INT_MAX - 3UL; i < INT_MAX + 3UL; i++) {
 374                 struct item *item;
 375                 unsigned int id;
 376                 if (i <= INT_MAX)
 377                         item = item_create(i, 0);
 378                 else
 379                         item = item_create(i - INT_MAX - 1, 0);
 380 
 381                 id = idr_alloc_cyclic(&idr, item, 0, 0, GFP_KERNEL);
 382                 assert(id == item->index);
 383         }
 384 
 385         idr_for_each(&idr, item_idr_free, &idr);
 386         idr_destroy(&idr);
 387         assert(idr_is_empty(&idr));
 388 
 389         for (i = 1; i < 10000; i++) {
 390                 struct item *item = item_create(i, 0);
 391                 assert(idr_alloc(&idr, item, 1, 20000, GFP_KERNEL) == i);
 392         }
 393 
 394         idr_for_each(&idr, item_idr_free, &idr);
 395         idr_destroy(&idr);
 396 
 397         idr_replace_test();
 398         idr_alloc_test();
 399         idr_null_test();
 400         idr_nowait_test();
 401         idr_get_next_test(0);
 402         idr_get_next_test(1);
 403         idr_get_next_test(4);
 404         idr_u32_test(4);
 405         idr_u32_test(1);
 406         idr_u32_test(0);
 407         idr_align_test(&idr);
 408         idr_find_test();
 409 }
 410 
 411 #define module_init(x)
 412 #define module_exit(x)
 413 #define MODULE_AUTHOR(x)
 414 #define MODULE_LICENSE(x)
 415 #define dump_stack()    assert(0)
 416 void ida_dump(struct ida *);
 417 
 418 #include "../../../lib/test_ida.c"
 419 
 420 /*
 421  * Check that we get the correct error when we run out of memory doing
 422  * allocations.  In userspace, GFP_NOWAIT will always fail an allocation.
 423  * The first test is for not having a bitmap available, and the second test
 424  * is for not being able to allocate a level of the radix tree.
 425  */
 426 void ida_check_nomem(void)
 427 {
 428         DEFINE_IDA(ida);
 429         int id;
 430 
 431         id = ida_alloc_min(&ida, 256, GFP_NOWAIT);
 432         IDA_BUG_ON(&ida, id != -ENOMEM);
 433         id = ida_alloc_min(&ida, 1UL << 30, GFP_NOWAIT);
 434         IDA_BUG_ON(&ida, id != -ENOMEM);
 435         IDA_BUG_ON(&ida, !ida_is_empty(&ida));
 436 }
 437 
 438 /*
 439  * Check handling of conversions between exceptional entries and full bitmaps.
 440  */
 441 void ida_check_conv_user(void)
 442 {
 443         DEFINE_IDA(ida);
 444         unsigned long i;
 445 
 446         for (i = 0; i < 1000000; i++) {
 447                 int id = ida_alloc(&ida, GFP_NOWAIT);
 448                 if (id == -ENOMEM) {
 449                         IDA_BUG_ON(&ida, ((i % IDA_BITMAP_BITS) !=
 450                                           BITS_PER_XA_VALUE) &&
 451                                          ((i % IDA_BITMAP_BITS) != 0));
 452                         id = ida_alloc(&ida, GFP_KERNEL);
 453                 } else {
 454                         IDA_BUG_ON(&ida, (i % IDA_BITMAP_BITS) ==
 455                                         BITS_PER_XA_VALUE);
 456                 }
 457                 IDA_BUG_ON(&ida, id != i);
 458         }
 459         ida_destroy(&ida);
 460 }
 461 
 462 void ida_check_random(void)
 463 {
 464         DEFINE_IDA(ida);
 465         DECLARE_BITMAP(bitmap, 2048);
 466         unsigned int i;
 467         time_t s = time(NULL);
 468 
 469  repeat:
 470         memset(bitmap, 0, sizeof(bitmap));
 471         for (i = 0; i < 100000; i++) {
 472                 int i = rand();
 473                 int bit = i & 2047;
 474                 if (test_bit(bit, bitmap)) {
 475                         __clear_bit(bit, bitmap);
 476                         ida_free(&ida, bit);
 477                 } else {
 478                         __set_bit(bit, bitmap);
 479                         IDA_BUG_ON(&ida, ida_alloc_min(&ida, bit, GFP_KERNEL)
 480                                         != bit);
 481                 }
 482         }
 483         ida_destroy(&ida);
 484         if (time(NULL) < s + 10)
 485                 goto repeat;
 486 }
 487 
 488 void ida_simple_get_remove_test(void)
 489 {
 490         DEFINE_IDA(ida);
 491         unsigned long i;
 492 
 493         for (i = 0; i < 10000; i++) {
 494                 assert(ida_simple_get(&ida, 0, 20000, GFP_KERNEL) == i);
 495         }
 496         assert(ida_simple_get(&ida, 5, 30, GFP_KERNEL) < 0);
 497 
 498         for (i = 0; i < 10000; i++) {
 499                 ida_simple_remove(&ida, i);
 500         }
 501         assert(ida_is_empty(&ida));
 502 
 503         ida_destroy(&ida);
 504 }
 505 
 506 void user_ida_checks(void)
 507 {
 508         radix_tree_cpu_dead(1);
 509 
 510         ida_check_nomem();
 511         ida_check_conv_user();
 512         ida_check_random();
 513         ida_simple_get_remove_test();
 514 
 515         radix_tree_cpu_dead(1);
 516 }
 517 
 518 static void *ida_random_fn(void *arg)
 519 {
 520         rcu_register_thread();
 521         ida_check_random();
 522         rcu_unregister_thread();
 523         return NULL;
 524 }
 525 
 526 void ida_thread_tests(void)
 527 {
 528         pthread_t threads[20];
 529         int i;
 530 
 531         for (i = 0; i < ARRAY_SIZE(threads); i++)
 532                 if (pthread_create(&threads[i], NULL, ida_random_fn, NULL)) {
 533                         perror("creating ida thread");
 534                         exit(1);
 535                 }
 536 
 537         while (i--)
 538                 pthread_join(threads[i], NULL);
 539 }
 540 
 541 void ida_tests(void)
 542 {
 543         user_ida_checks();
 544         ida_checks();
 545         ida_exit();
 546         ida_thread_tests();
 547 }
 548 
 549 int __weak main(void)
 550 {
 551         radix_tree_init();
 552         idr_checks();
 553         ida_tests();
 554         radix_tree_cpu_dead(1);
 555         rcu_barrier();
 556         if (nr_allocated)
 557                 printf("nr_allocated = %d\n", nr_allocated);
 558         return 0;
 559 }

/* [<][>][^][v][top][bottom][index][help] */