idr-test.c 13 KB

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