12025cf9eSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
20a835c4fSMatthew Wilcox /*
30a835c4fSMatthew Wilcox  * idr-test.c: Test the IDR API
40a835c4fSMatthew Wilcox  * Copyright (c) 2016 Matthew Wilcox <willy@infradead.org>
50a835c4fSMatthew Wilcox  */
6d37cacc5SMatthew Wilcox #include <linux/bitmap.h>
70a835c4fSMatthew Wilcox #include <linux/idr.h>
80a835c4fSMatthew Wilcox #include <linux/slab.h>
90a835c4fSMatthew Wilcox #include <linux/kernel.h>
100a835c4fSMatthew Wilcox #include <linux/errno.h>
110a835c4fSMatthew Wilcox 
120a835c4fSMatthew Wilcox #include "test.h"
130a835c4fSMatthew Wilcox 
143159f943SMatthew Wilcox #define DUMMY_PTR	((void *)0x10)
150a835c4fSMatthew Wilcox 
item_idr_free(int id,void * p,void * data)160a835c4fSMatthew Wilcox int item_idr_free(int id, void *p, void *data)
170a835c4fSMatthew Wilcox {
180a835c4fSMatthew Wilcox 	struct item *item = p;
190a835c4fSMatthew Wilcox 	assert(item->index == id);
200a835c4fSMatthew Wilcox 	free(p);
210a835c4fSMatthew Wilcox 
220a835c4fSMatthew Wilcox 	return 0;
230a835c4fSMatthew Wilcox }
240a835c4fSMatthew Wilcox 
item_idr_remove(struct idr * idr,int id)250a835c4fSMatthew Wilcox void item_idr_remove(struct idr *idr, int id)
260a835c4fSMatthew Wilcox {
270a835c4fSMatthew Wilcox 	struct item *item = idr_find(idr, id);
280a835c4fSMatthew Wilcox 	assert(item->index == id);
290a835c4fSMatthew Wilcox 	idr_remove(idr, id);
300a835c4fSMatthew Wilcox 	free(item);
310a835c4fSMatthew Wilcox }
320a835c4fSMatthew Wilcox 
idr_alloc_test(void)330a835c4fSMatthew Wilcox void idr_alloc_test(void)
340a835c4fSMatthew Wilcox {
350a835c4fSMatthew Wilcox 	unsigned long i;
360a835c4fSMatthew Wilcox 	DEFINE_IDR(idr);
370a835c4fSMatthew Wilcox 
380a835c4fSMatthew Wilcox 	assert(idr_alloc_cyclic(&idr, DUMMY_PTR, 0, 0x4000, GFP_KERNEL) == 0);
390a835c4fSMatthew Wilcox 	assert(idr_alloc_cyclic(&idr, DUMMY_PTR, 0x3ffd, 0x4000, GFP_KERNEL) == 0x3ffd);
400a835c4fSMatthew Wilcox 	idr_remove(&idr, 0x3ffd);
410a835c4fSMatthew Wilcox 	idr_remove(&idr, 0);
420a835c4fSMatthew Wilcox 
430a835c4fSMatthew Wilcox 	for (i = 0x3ffe; i < 0x4003; i++) {
440a835c4fSMatthew Wilcox 		int id;
450a835c4fSMatthew Wilcox 		struct item *item;
460a835c4fSMatthew Wilcox 
470a835c4fSMatthew Wilcox 		if (i < 0x4000)
480a835c4fSMatthew Wilcox 			item = item_create(i, 0);
490a835c4fSMatthew Wilcox 		else
500a835c4fSMatthew Wilcox 			item = item_create(i - 0x3fff, 0);
510a835c4fSMatthew Wilcox 
520a835c4fSMatthew Wilcox 		id = idr_alloc_cyclic(&idr, item, 1, 0x4000, GFP_KERNEL);
530a835c4fSMatthew Wilcox 		assert(id == item->index);
540a835c4fSMatthew Wilcox 	}
550a835c4fSMatthew Wilcox 
560a835c4fSMatthew Wilcox 	idr_for_each(&idr, item_idr_free, &idr);
570a835c4fSMatthew Wilcox 	idr_destroy(&idr);
580a835c4fSMatthew Wilcox }
590a835c4fSMatthew Wilcox 
idr_replace_test(void)600a835c4fSMatthew Wilcox void idr_replace_test(void)
610a835c4fSMatthew Wilcox {
620a835c4fSMatthew Wilcox 	DEFINE_IDR(idr);
630a835c4fSMatthew Wilcox 
640a835c4fSMatthew Wilcox 	idr_alloc(&idr, (void *)-1, 10, 11, GFP_KERNEL);
650a835c4fSMatthew Wilcox 	idr_replace(&idr, &idr, 10);
660a835c4fSMatthew Wilcox 
670a835c4fSMatthew Wilcox 	idr_destroy(&idr);
680a835c4fSMatthew Wilcox }
690a835c4fSMatthew Wilcox 
700a835c4fSMatthew Wilcox /*
710a835c4fSMatthew Wilcox  * Unlike the radix tree, you can put a NULL pointer -- with care -- into
720a835c4fSMatthew Wilcox  * the IDR.  Some interfaces, like idr_find() do not distinguish between
730a835c4fSMatthew Wilcox  * "present, value is NULL" and "not present", but that's exactly what some
740a835c4fSMatthew Wilcox  * users want.
750a835c4fSMatthew Wilcox  */
idr_null_test(void)760a835c4fSMatthew Wilcox void idr_null_test(void)
770a835c4fSMatthew Wilcox {
780a835c4fSMatthew Wilcox 	int i;
790a835c4fSMatthew Wilcox 	DEFINE_IDR(idr);
800a835c4fSMatthew Wilcox 
810a835c4fSMatthew Wilcox 	assert(idr_is_empty(&idr));
820a835c4fSMatthew Wilcox 
830a835c4fSMatthew Wilcox 	assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
840a835c4fSMatthew Wilcox 	assert(!idr_is_empty(&idr));
850a835c4fSMatthew Wilcox 	idr_remove(&idr, 0);
860a835c4fSMatthew Wilcox 	assert(idr_is_empty(&idr));
870a835c4fSMatthew Wilcox 
880a835c4fSMatthew Wilcox 	assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
890a835c4fSMatthew Wilcox 	assert(!idr_is_empty(&idr));
900a835c4fSMatthew Wilcox 	idr_destroy(&idr);
910a835c4fSMatthew Wilcox 	assert(idr_is_empty(&idr));
920a835c4fSMatthew Wilcox 
930a835c4fSMatthew Wilcox 	for (i = 0; i < 10; i++) {
940a835c4fSMatthew Wilcox 		assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == i);
950a835c4fSMatthew Wilcox 	}
960a835c4fSMatthew Wilcox 
970a835c4fSMatthew Wilcox 	assert(idr_replace(&idr, DUMMY_PTR, 3) == NULL);
980a835c4fSMatthew Wilcox 	assert(idr_replace(&idr, DUMMY_PTR, 4) == NULL);
990a835c4fSMatthew Wilcox 	assert(idr_replace(&idr, NULL, 4) == DUMMY_PTR);
1000a835c4fSMatthew Wilcox 	assert(idr_replace(&idr, DUMMY_PTR, 11) == ERR_PTR(-ENOENT));
1010a835c4fSMatthew Wilcox 	idr_remove(&idr, 5);
1020a835c4fSMatthew Wilcox 	assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 5);
1030a835c4fSMatthew Wilcox 	idr_remove(&idr, 5);
1040a835c4fSMatthew Wilcox 
1050a835c4fSMatthew Wilcox 	for (i = 0; i < 9; i++) {
1060a835c4fSMatthew Wilcox 		idr_remove(&idr, i);
1070a835c4fSMatthew Wilcox 		assert(!idr_is_empty(&idr));
1080a835c4fSMatthew Wilcox 	}
1090a835c4fSMatthew Wilcox 	idr_remove(&idr, 8);
1100a835c4fSMatthew Wilcox 	assert(!idr_is_empty(&idr));
1110a835c4fSMatthew Wilcox 	idr_remove(&idr, 9);
1120a835c4fSMatthew Wilcox 	assert(idr_is_empty(&idr));
1130a835c4fSMatthew Wilcox 
1140a835c4fSMatthew Wilcox 	assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
1150a835c4fSMatthew Wilcox 	assert(idr_replace(&idr, DUMMY_PTR, 3) == ERR_PTR(-ENOENT));
1160a835c4fSMatthew Wilcox 	assert(idr_replace(&idr, DUMMY_PTR, 0) == NULL);
1170a835c4fSMatthew Wilcox 	assert(idr_replace(&idr, NULL, 0) == DUMMY_PTR);
1180a835c4fSMatthew Wilcox 
1190a835c4fSMatthew Wilcox 	idr_destroy(&idr);
1200a835c4fSMatthew Wilcox 	assert(idr_is_empty(&idr));
1210a835c4fSMatthew Wilcox 
1220a835c4fSMatthew Wilcox 	for (i = 1; i < 10; i++) {
1230a835c4fSMatthew Wilcox 		assert(idr_alloc(&idr, NULL, 1, 0, GFP_KERNEL) == i);
1240a835c4fSMatthew Wilcox 	}
1250a835c4fSMatthew Wilcox 
1260a835c4fSMatthew Wilcox 	idr_destroy(&idr);
1270a835c4fSMatthew Wilcox 	assert(idr_is_empty(&idr));
1280a835c4fSMatthew Wilcox }
1290a835c4fSMatthew Wilcox 
idr_nowait_test(void)1300a835c4fSMatthew Wilcox void idr_nowait_test(void)
1310a835c4fSMatthew Wilcox {
1320a835c4fSMatthew Wilcox 	unsigned int i;
1330a835c4fSMatthew Wilcox 	DEFINE_IDR(idr);
1340a835c4fSMatthew Wilcox 
1350a835c4fSMatthew Wilcox 	idr_preload(GFP_KERNEL);
1360a835c4fSMatthew Wilcox 
1370a835c4fSMatthew Wilcox 	for (i = 0; i < 3; i++) {
1380a835c4fSMatthew Wilcox 		struct item *item = item_create(i, 0);
1390a835c4fSMatthew Wilcox 		assert(idr_alloc(&idr, item, i, i + 1, GFP_NOWAIT) == i);
1400a835c4fSMatthew Wilcox 	}
1410a835c4fSMatthew Wilcox 
1420a835c4fSMatthew Wilcox 	idr_preload_end();
1430a835c4fSMatthew Wilcox 
1440a835c4fSMatthew Wilcox 	idr_for_each(&idr, item_idr_free, &idr);
1450a835c4fSMatthew Wilcox 	idr_destroy(&idr);
1460a835c4fSMatthew Wilcox }
1470a835c4fSMatthew Wilcox 
idr_get_next_test(int base)1486ce711f2SMatthew Wilcox void idr_get_next_test(int base)
1492eacc79cSRehas Sachdeva {
1502eacc79cSRehas Sachdeva 	unsigned long i;
1512eacc79cSRehas Sachdeva 	int nextid;
1522eacc79cSRehas Sachdeva 	DEFINE_IDR(idr);
1536ce711f2SMatthew Wilcox 	idr_init_base(&idr, base);
1542eacc79cSRehas Sachdeva 
1552eacc79cSRehas Sachdeva 	int indices[] = {4, 7, 9, 15, 65, 128, 1000, 99999, 0};
1562eacc79cSRehas Sachdeva 
1572eacc79cSRehas Sachdeva 	for(i = 0; indices[i]; i++) {
1582eacc79cSRehas Sachdeva 		struct item *item = item_create(indices[i], 0);
1592eacc79cSRehas Sachdeva 		assert(idr_alloc(&idr, item, indices[i], indices[i+1],
1602eacc79cSRehas Sachdeva 				 GFP_KERNEL) == indices[i]);
1612eacc79cSRehas Sachdeva 	}
1622eacc79cSRehas Sachdeva 
1632eacc79cSRehas Sachdeva 	for(i = 0, nextid = 0; indices[i]; i++) {
1642eacc79cSRehas Sachdeva 		idr_get_next(&idr, &nextid);
1652eacc79cSRehas Sachdeva 		assert(nextid == indices[i]);
1662eacc79cSRehas Sachdeva 		nextid++;
1672eacc79cSRehas Sachdeva 	}
1682eacc79cSRehas Sachdeva 
1692eacc79cSRehas Sachdeva 	idr_for_each(&idr, item_idr_free, &idr);
1702eacc79cSRehas Sachdeva 	idr_destroy(&idr);
1712eacc79cSRehas Sachdeva }
1722eacc79cSRehas Sachdeva 
idr_u32_cb(int id,void * ptr,void * data)1734b0ad076SMatthew Wilcox int idr_u32_cb(int id, void *ptr, void *data)
1744b0ad076SMatthew Wilcox {
1754b0ad076SMatthew Wilcox 	BUG_ON(id < 0);
1764b0ad076SMatthew Wilcox 	BUG_ON(ptr != DUMMY_PTR);
1774b0ad076SMatthew Wilcox 	return 0;
1784b0ad076SMatthew Wilcox }
1794b0ad076SMatthew Wilcox 
idr_u32_test1(struct idr * idr,u32 handle)1804b0ad076SMatthew Wilcox void idr_u32_test1(struct idr *idr, u32 handle)
1814b0ad076SMatthew Wilcox {
1824b0ad076SMatthew Wilcox 	static bool warned = false;
1834b0ad076SMatthew Wilcox 	u32 id = handle;
1844b0ad076SMatthew Wilcox 	int sid = 0;
1854b0ad076SMatthew Wilcox 	void *ptr;
1864b0ad076SMatthew Wilcox 
1874b0ad076SMatthew Wilcox 	BUG_ON(idr_alloc_u32(idr, DUMMY_PTR, &id, id, GFP_KERNEL));
1884b0ad076SMatthew Wilcox 	BUG_ON(id != handle);
1894b0ad076SMatthew Wilcox 	BUG_ON(idr_alloc_u32(idr, DUMMY_PTR, &id, id, GFP_KERNEL) != -ENOSPC);
1904b0ad076SMatthew Wilcox 	BUG_ON(id != handle);
1914b0ad076SMatthew Wilcox 	if (!warned && id > INT_MAX)
1924b0ad076SMatthew Wilcox 		printk("vvv Ignore these warnings\n");
1934b0ad076SMatthew Wilcox 	ptr = idr_get_next(idr, &sid);
1944b0ad076SMatthew Wilcox 	if (id > INT_MAX) {
1954b0ad076SMatthew Wilcox 		BUG_ON(ptr != NULL);
1964b0ad076SMatthew Wilcox 		BUG_ON(sid != 0);
1974b0ad076SMatthew Wilcox 	} else {
1984b0ad076SMatthew Wilcox 		BUG_ON(ptr != DUMMY_PTR);
1994b0ad076SMatthew Wilcox 		BUG_ON(sid != id);
2004b0ad076SMatthew Wilcox 	}
2014b0ad076SMatthew Wilcox 	idr_for_each(idr, idr_u32_cb, NULL);
2024b0ad076SMatthew Wilcox 	if (!warned && id > INT_MAX) {
2034b0ad076SMatthew Wilcox 		printk("^^^ Warnings over\n");
2044b0ad076SMatthew Wilcox 		warned = true;
2054b0ad076SMatthew Wilcox 	}
2064b0ad076SMatthew Wilcox 	BUG_ON(idr_remove(idr, id) != DUMMY_PTR);
2074b0ad076SMatthew Wilcox 	BUG_ON(!idr_is_empty(idr));
2084b0ad076SMatthew Wilcox }
2094b0ad076SMatthew Wilcox 
idr_u32_test(int base)2104b0ad076SMatthew Wilcox void idr_u32_test(int base)
2114b0ad076SMatthew Wilcox {
2124b0ad076SMatthew Wilcox 	DEFINE_IDR(idr);
2134b0ad076SMatthew Wilcox 	idr_init_base(&idr, base);
2144b0ad076SMatthew Wilcox 	idr_u32_test1(&idr, 10);
2154b0ad076SMatthew Wilcox 	idr_u32_test1(&idr, 0x7fffffff);
2164b0ad076SMatthew Wilcox 	idr_u32_test1(&idr, 0x80000000);
2174b0ad076SMatthew Wilcox 	idr_u32_test1(&idr, 0x80000001);
2184b0ad076SMatthew Wilcox 	idr_u32_test1(&idr, 0xffe00000);
2194b0ad076SMatthew Wilcox 	idr_u32_test1(&idr, 0xffffffff);
2204b0ad076SMatthew Wilcox }
2214b0ad076SMatthew Wilcox 
idr_align_test(struct idr * idr)22266ee620fSMatthew Wilcox static void idr_align_test(struct idr *idr)
22366ee620fSMatthew Wilcox {
22466ee620fSMatthew Wilcox 	char name[] = "Motorola 68000";
22566ee620fSMatthew Wilcox 	int i, id;
22666ee620fSMatthew Wilcox 	void *entry;
22766ee620fSMatthew Wilcox 
22866ee620fSMatthew Wilcox 	for (i = 0; i < 9; i++) {
22966ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != i);
23066ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
23166ee620fSMatthew Wilcox 	}
23266ee620fSMatthew Wilcox 	idr_destroy(idr);
23366ee620fSMatthew Wilcox 
23466ee620fSMatthew Wilcox 	for (i = 1; i < 10; i++) {
23566ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != i - 1);
23666ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
23766ee620fSMatthew Wilcox 	}
23866ee620fSMatthew Wilcox 	idr_destroy(idr);
23966ee620fSMatthew Wilcox 
24066ee620fSMatthew Wilcox 	for (i = 2; i < 11; i++) {
24166ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != i - 2);
24266ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
24366ee620fSMatthew Wilcox 	}
24466ee620fSMatthew Wilcox 	idr_destroy(idr);
24566ee620fSMatthew Wilcox 
24666ee620fSMatthew Wilcox 	for (i = 3; i < 12; i++) {
24766ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != i - 3);
24866ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
24966ee620fSMatthew Wilcox 	}
25066ee620fSMatthew Wilcox 	idr_destroy(idr);
25166ee620fSMatthew Wilcox 
25266ee620fSMatthew Wilcox 	for (i = 0; i < 8; i++) {
25366ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != 0);
25466ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, &name[i + 1], 0, 0, GFP_KERNEL) != 1);
25566ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
25666ee620fSMatthew Wilcox 		idr_remove(idr, 1);
25766ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
25866ee620fSMatthew Wilcox 		idr_remove(idr, 0);
25966ee620fSMatthew Wilcox 		BUG_ON(!idr_is_empty(idr));
26066ee620fSMatthew Wilcox 	}
26166ee620fSMatthew Wilcox 
26266ee620fSMatthew Wilcox 	for (i = 0; i < 8; i++) {
26366ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, NULL, 0, 0, GFP_KERNEL) != 0);
26466ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
26566ee620fSMatthew Wilcox 		idr_replace(idr, &name[i], 0);
26666ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
26766ee620fSMatthew Wilcox 		BUG_ON(idr_find(idr, 0) != &name[i]);
26866ee620fSMatthew Wilcox 		idr_remove(idr, 0);
26966ee620fSMatthew Wilcox 	}
27066ee620fSMatthew Wilcox 
27166ee620fSMatthew Wilcox 	for (i = 0; i < 8; i++) {
27266ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, &name[i], 0, 0, GFP_KERNEL) != 0);
27366ee620fSMatthew Wilcox 		BUG_ON(idr_alloc(idr, NULL, 0, 0, GFP_KERNEL) != 1);
27466ee620fSMatthew Wilcox 		idr_remove(idr, 1);
27566ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
27666ee620fSMatthew Wilcox 		idr_replace(idr, &name[i + 1], 0);
27766ee620fSMatthew Wilcox 		idr_for_each_entry(idr, entry, id);
27866ee620fSMatthew Wilcox 		idr_remove(idr, 0);
27966ee620fSMatthew Wilcox 	}
28066ee620fSMatthew Wilcox }
28166ee620fSMatthew Wilcox 
2825c089fd0SMatthew Wilcox (Oracle) DEFINE_IDR(find_idr);
2835c089fd0SMatthew Wilcox (Oracle) 
idr_throbber(void * arg)2845c089fd0SMatthew Wilcox (Oracle) static void *idr_throbber(void *arg)
2855c089fd0SMatthew Wilcox (Oracle) {
2865c089fd0SMatthew Wilcox (Oracle) 	time_t start = time(NULL);
2875c089fd0SMatthew Wilcox (Oracle) 	int id = *(int *)arg;
2885c089fd0SMatthew Wilcox (Oracle) 
2895c089fd0SMatthew Wilcox (Oracle) 	rcu_register_thread();
2905c089fd0SMatthew Wilcox (Oracle) 	do {
2915c089fd0SMatthew Wilcox (Oracle) 		idr_alloc(&find_idr, xa_mk_value(id), id, id + 1, GFP_KERNEL);
2925c089fd0SMatthew Wilcox (Oracle) 		idr_remove(&find_idr, id);
2935c089fd0SMatthew Wilcox (Oracle) 	} while (time(NULL) < start + 10);
2945c089fd0SMatthew Wilcox (Oracle) 	rcu_unregister_thread();
2955c089fd0SMatthew Wilcox (Oracle) 
2965c089fd0SMatthew Wilcox (Oracle) 	return NULL;
2975c089fd0SMatthew Wilcox (Oracle) }
2985c089fd0SMatthew Wilcox (Oracle) 
299*2c7e57a0SMatthew Wilcox (Oracle) /*
300*2c7e57a0SMatthew Wilcox (Oracle)  * There are always either 1 or 2 objects in the IDR.  If we find nothing,
301*2c7e57a0SMatthew Wilcox (Oracle)  * or we find something at an ID we didn't expect, that's a bug.
302*2c7e57a0SMatthew Wilcox (Oracle)  */
idr_find_test_1(int anchor_id,int throbber_id)3035c089fd0SMatthew Wilcox (Oracle) void idr_find_test_1(int anchor_id, int throbber_id)
3045c089fd0SMatthew Wilcox (Oracle) {
3055c089fd0SMatthew Wilcox (Oracle) 	pthread_t throbber;
3065c089fd0SMatthew Wilcox (Oracle) 	time_t start = time(NULL);
3075c089fd0SMatthew Wilcox (Oracle) 
3085c089fd0SMatthew Wilcox (Oracle) 	BUG_ON(idr_alloc(&find_idr, xa_mk_value(anchor_id), anchor_id,
3095c089fd0SMatthew Wilcox (Oracle) 				anchor_id + 1, GFP_KERNEL) != anchor_id);
3105c089fd0SMatthew Wilcox (Oracle) 
311094ffbd1SMatthew Wilcox (Oracle) 	pthread_create(&throbber, NULL, idr_throbber, &throbber_id);
312094ffbd1SMatthew Wilcox (Oracle) 
31370358641SMatthew Wilcox (Oracle) 	rcu_read_lock();
3145c089fd0SMatthew Wilcox (Oracle) 	do {
3155c089fd0SMatthew Wilcox (Oracle) 		int id = 0;
3165c089fd0SMatthew Wilcox (Oracle) 		void *entry = idr_get_next(&find_idr, &id);
31770358641SMatthew Wilcox (Oracle) 		rcu_read_unlock();
318*2c7e57a0SMatthew Wilcox (Oracle) 		if ((id != anchor_id && id != throbber_id) ||
319*2c7e57a0SMatthew Wilcox (Oracle) 		    entry != xa_mk_value(id)) {
320*2c7e57a0SMatthew Wilcox (Oracle) 			printf("%s(%d, %d): %p at %d\n", __func__, anchor_id,
321*2c7e57a0SMatthew Wilcox (Oracle) 				throbber_id, entry, id);
322*2c7e57a0SMatthew Wilcox (Oracle) 			abort();
323*2c7e57a0SMatthew Wilcox (Oracle) 		}
32470358641SMatthew Wilcox (Oracle) 		rcu_read_lock();
3255c089fd0SMatthew Wilcox (Oracle) 	} while (time(NULL) < start + 11);
32670358641SMatthew Wilcox (Oracle) 	rcu_read_unlock();
3275c089fd0SMatthew Wilcox (Oracle) 
3285c089fd0SMatthew Wilcox (Oracle) 	pthread_join(throbber, NULL);
3295c089fd0SMatthew Wilcox (Oracle) 
3305c089fd0SMatthew Wilcox (Oracle) 	idr_remove(&find_idr, anchor_id);
3315c089fd0SMatthew Wilcox (Oracle) 	BUG_ON(!idr_is_empty(&find_idr));
3325c089fd0SMatthew Wilcox (Oracle) }
3335c089fd0SMatthew Wilcox (Oracle) 
idr_find_test(void)3345c089fd0SMatthew Wilcox (Oracle) void idr_find_test(void)
3355c089fd0SMatthew Wilcox (Oracle) {
3365c089fd0SMatthew Wilcox (Oracle) 	idr_find_test_1(100000, 0);
3375c089fd0SMatthew Wilcox (Oracle) 	idr_find_test_1(0, 100000);
3385c089fd0SMatthew Wilcox (Oracle) }
3395c089fd0SMatthew Wilcox (Oracle) 
idr_checks(void)3400a835c4fSMatthew Wilcox void idr_checks(void)
3410a835c4fSMatthew Wilcox {
3420a835c4fSMatthew Wilcox 	unsigned long i;
3430a835c4fSMatthew Wilcox 	DEFINE_IDR(idr);
3440a835c4fSMatthew Wilcox 
3450a835c4fSMatthew Wilcox 	for (i = 0; i < 10000; i++) {
3460a835c4fSMatthew Wilcox 		struct item *item = item_create(i, 0);
3470a835c4fSMatthew Wilcox 		assert(idr_alloc(&idr, item, 0, 20000, GFP_KERNEL) == i);
3480a835c4fSMatthew Wilcox 	}
3490a835c4fSMatthew Wilcox 
3500a835c4fSMatthew Wilcox 	assert(idr_alloc(&idr, DUMMY_PTR, 5, 30, GFP_KERNEL) < 0);
3510a835c4fSMatthew Wilcox 
3520a835c4fSMatthew Wilcox 	for (i = 0; i < 5000; i++)
3530a835c4fSMatthew Wilcox 		item_idr_remove(&idr, i);
3540a835c4fSMatthew Wilcox 
3550a835c4fSMatthew Wilcox 	idr_remove(&idr, 3);
3560a835c4fSMatthew Wilcox 
3570a835c4fSMatthew Wilcox 	idr_for_each(&idr, item_idr_free, &idr);
3580a835c4fSMatthew Wilcox 	idr_destroy(&idr);
3590a835c4fSMatthew Wilcox 
3600a835c4fSMatthew Wilcox 	assert(idr_is_empty(&idr));
3610a835c4fSMatthew Wilcox 
3620a835c4fSMatthew Wilcox 	idr_remove(&idr, 3);
3630a835c4fSMatthew Wilcox 	idr_remove(&idr, 0);
3640a835c4fSMatthew Wilcox 
3657a4deea1SMatthew Wilcox 	assert(idr_alloc(&idr, DUMMY_PTR, 0, 0, GFP_KERNEL) == 0);
3667a4deea1SMatthew Wilcox 	idr_remove(&idr, 1);
3677a4deea1SMatthew Wilcox 	for (i = 1; i < RADIX_TREE_MAP_SIZE; i++)
3687a4deea1SMatthew Wilcox 		assert(idr_alloc(&idr, DUMMY_PTR, 0, 0, GFP_KERNEL) == i);
3697a4deea1SMatthew Wilcox 	idr_remove(&idr, 1 << 30);
3707a4deea1SMatthew Wilcox 	idr_destroy(&idr);
3717a4deea1SMatthew Wilcox 
3720a835c4fSMatthew Wilcox 	for (i = INT_MAX - 3UL; i < INT_MAX + 1UL; i++) {
3730a835c4fSMatthew Wilcox 		struct item *item = item_create(i, 0);
3740a835c4fSMatthew Wilcox 		assert(idr_alloc(&idr, item, i, i + 10, GFP_KERNEL) == i);
3750a835c4fSMatthew Wilcox 	}
3760a835c4fSMatthew Wilcox 	assert(idr_alloc(&idr, DUMMY_PTR, i - 2, i, GFP_KERNEL) == -ENOSPC);
3776e6d3014SMatthew Wilcox 	assert(idr_alloc(&idr, DUMMY_PTR, i - 2, i + 10, GFP_KERNEL) == -ENOSPC);
3780a835c4fSMatthew Wilcox 
3790a835c4fSMatthew Wilcox 	idr_for_each(&idr, item_idr_free, &idr);
3800a835c4fSMatthew Wilcox 	idr_destroy(&idr);
3810a835c4fSMatthew Wilcox 	idr_destroy(&idr);
3820a835c4fSMatthew Wilcox 
3830a835c4fSMatthew Wilcox 	assert(idr_is_empty(&idr));
3840a835c4fSMatthew Wilcox 
385460488c5SMatthew Wilcox 	idr_set_cursor(&idr, INT_MAX - 3UL);
386460488c5SMatthew Wilcox 	for (i = INT_MAX - 3UL; i < INT_MAX + 3UL; i++) {
387460488c5SMatthew Wilcox 		struct item *item;
388460488c5SMatthew Wilcox 		unsigned int id;
389460488c5SMatthew Wilcox 		if (i <= INT_MAX)
390460488c5SMatthew Wilcox 			item = item_create(i, 0);
391460488c5SMatthew Wilcox 		else
392460488c5SMatthew Wilcox 			item = item_create(i - INT_MAX - 1, 0);
393460488c5SMatthew Wilcox 
394460488c5SMatthew Wilcox 		id = idr_alloc_cyclic(&idr, item, 0, 0, GFP_KERNEL);
395460488c5SMatthew Wilcox 		assert(id == item->index);
396460488c5SMatthew Wilcox 	}
397460488c5SMatthew Wilcox 
398460488c5SMatthew Wilcox 	idr_for_each(&idr, item_idr_free, &idr);
399460488c5SMatthew Wilcox 	idr_destroy(&idr);
400460488c5SMatthew Wilcox 	assert(idr_is_empty(&idr));
401460488c5SMatthew Wilcox 
4020a835c4fSMatthew Wilcox 	for (i = 1; i < 10000; i++) {
4030a835c4fSMatthew Wilcox 		struct item *item = item_create(i, 0);
4040a835c4fSMatthew Wilcox 		assert(idr_alloc(&idr, item, 1, 20000, GFP_KERNEL) == i);
4050a835c4fSMatthew Wilcox 	}
4060a835c4fSMatthew Wilcox 
4070a835c4fSMatthew Wilcox 	idr_for_each(&idr, item_idr_free, &idr);
4080a835c4fSMatthew Wilcox 	idr_destroy(&idr);
4090a835c4fSMatthew Wilcox 
4100a835c4fSMatthew Wilcox 	idr_replace_test();
4110a835c4fSMatthew Wilcox 	idr_alloc_test();
4120a835c4fSMatthew Wilcox 	idr_null_test();
4130a835c4fSMatthew Wilcox 	idr_nowait_test();
4146ce711f2SMatthew Wilcox 	idr_get_next_test(0);
4156ce711f2SMatthew Wilcox 	idr_get_next_test(1);
4166ce711f2SMatthew Wilcox 	idr_get_next_test(4);
4174b0ad076SMatthew Wilcox 	idr_u32_test(4);
4184b0ad076SMatthew Wilcox 	idr_u32_test(1);
4194b0ad076SMatthew Wilcox 	idr_u32_test(0);
42066ee620fSMatthew Wilcox 	idr_align_test(&idr);
4215c089fd0SMatthew Wilcox (Oracle) 	idr_find_test();
4220a835c4fSMatthew Wilcox }
4230a835c4fSMatthew Wilcox 
4248ab8ba38SMatthew Wilcox #define module_init(x)
4258ab8ba38SMatthew Wilcox #define module_exit(x)
4268ab8ba38SMatthew Wilcox #define MODULE_AUTHOR(x)
4278ab8ba38SMatthew Wilcox #define MODULE_LICENSE(x)
4288ab8ba38SMatthew Wilcox #define dump_stack()    assert(0)
4298ab8ba38SMatthew Wilcox void ida_dump(struct ida *);
4308ab8ba38SMatthew Wilcox 
4318ab8ba38SMatthew Wilcox #include "../../../lib/test_ida.c"
4328ab8ba38SMatthew Wilcox 
4330a835c4fSMatthew Wilcox /*
4340a835c4fSMatthew Wilcox  * Check that we get the correct error when we run out of memory doing
43506b01113SMatthew Wilcox  * allocations.  In userspace, GFP_NOWAIT will always fail an allocation.
4360a835c4fSMatthew Wilcox  * The first test is for not having a bitmap available, and the second test
4370a835c4fSMatthew Wilcox  * is for not being able to allocate a level of the radix tree.
4380a835c4fSMatthew Wilcox  */
ida_check_nomem(void)4390a835c4fSMatthew Wilcox void ida_check_nomem(void)
4400a835c4fSMatthew Wilcox {
4410a835c4fSMatthew Wilcox 	DEFINE_IDA(ida);
44206b01113SMatthew Wilcox 	int id;
4430a835c4fSMatthew Wilcox 
44406b01113SMatthew Wilcox 	id = ida_alloc_min(&ida, 256, GFP_NOWAIT);
44506b01113SMatthew Wilcox 	IDA_BUG_ON(&ida, id != -ENOMEM);
44606b01113SMatthew Wilcox 	id = ida_alloc_min(&ida, 1UL << 30, GFP_NOWAIT);
44706b01113SMatthew Wilcox 	IDA_BUG_ON(&ida, id != -ENOMEM);
44806b01113SMatthew Wilcox 	IDA_BUG_ON(&ida, !ida_is_empty(&ida));
4490a835c4fSMatthew Wilcox }
4500a835c4fSMatthew Wilcox 
4510a835c4fSMatthew Wilcox /*
452d37cacc5SMatthew Wilcox  * Check handling of conversions between exceptional entries and full bitmaps.
453d37cacc5SMatthew Wilcox  */
ida_check_conv_user(void)4545c78b0b1SMatthew Wilcox void ida_check_conv_user(void)
455d37cacc5SMatthew Wilcox {
456d37cacc5SMatthew Wilcox 	DEFINE_IDA(ida);
457d37cacc5SMatthew Wilcox 	unsigned long i;
458d37cacc5SMatthew Wilcox 
459d37cacc5SMatthew Wilcox 	for (i = 0; i < 1000000; i++) {
4605c78b0b1SMatthew Wilcox 		int id = ida_alloc(&ida, GFP_NOWAIT);
4615c78b0b1SMatthew Wilcox 		if (id == -ENOMEM) {
462f32f004cSMatthew Wilcox 			IDA_BUG_ON(&ida, ((i % IDA_BITMAP_BITS) !=
463f32f004cSMatthew Wilcox 					  BITS_PER_XA_VALUE) &&
464f32f004cSMatthew Wilcox 					 ((i % IDA_BITMAP_BITS) != 0));
4655c78b0b1SMatthew Wilcox 			id = ida_alloc(&ida, GFP_KERNEL);
466d37cacc5SMatthew Wilcox 		} else {
4675c78b0b1SMatthew Wilcox 			IDA_BUG_ON(&ida, (i % IDA_BITMAP_BITS) ==
4683159f943SMatthew Wilcox 					BITS_PER_XA_VALUE);
469d37cacc5SMatthew Wilcox 		}
4705c78b0b1SMatthew Wilcox 		IDA_BUG_ON(&ida, id != i);
471d37cacc5SMatthew Wilcox 	}
472d37cacc5SMatthew Wilcox 	ida_destroy(&ida);
473d37cacc5SMatthew Wilcox }
474d37cacc5SMatthew Wilcox 
ida_check_random(void)475d37cacc5SMatthew Wilcox void ida_check_random(void)
476d37cacc5SMatthew Wilcox {
477d37cacc5SMatthew Wilcox 	DEFINE_IDA(ida);
478d37cacc5SMatthew Wilcox 	DECLARE_BITMAP(bitmap, 2048);
479d37cacc5SMatthew Wilcox 	unsigned int i;
480d37cacc5SMatthew Wilcox 	time_t s = time(NULL);
481d37cacc5SMatthew Wilcox 
482d37cacc5SMatthew Wilcox  repeat:
483d37cacc5SMatthew Wilcox 	memset(bitmap, 0, sizeof(bitmap));
484d37cacc5SMatthew Wilcox 	for (i = 0; i < 100000; i++) {
485d37cacc5SMatthew Wilcox 		int i = rand();
486d37cacc5SMatthew Wilcox 		int bit = i & 2047;
487d37cacc5SMatthew Wilcox 		if (test_bit(bit, bitmap)) {
488d37cacc5SMatthew Wilcox 			__clear_bit(bit, bitmap);
489f272668dSMatthew Wilcox 			ida_free(&ida, bit);
490d37cacc5SMatthew Wilcox 		} else {
491d37cacc5SMatthew Wilcox 			__set_bit(bit, bitmap);
492f272668dSMatthew Wilcox 			IDA_BUG_ON(&ida, ida_alloc_min(&ida, bit, GFP_KERNEL)
493f272668dSMatthew Wilcox 					!= bit);
494d37cacc5SMatthew Wilcox 		}
495d37cacc5SMatthew Wilcox 	}
496d37cacc5SMatthew Wilcox 	ida_destroy(&ida);
497d37cacc5SMatthew Wilcox 	if (time(NULL) < s + 10)
498d37cacc5SMatthew Wilcox 		goto repeat;
499d37cacc5SMatthew Wilcox }
500d37cacc5SMatthew Wilcox 
ida_simple_get_remove_test(void)501166bb1f5SRehas Sachdeva void ida_simple_get_remove_test(void)
502166bb1f5SRehas Sachdeva {
503166bb1f5SRehas Sachdeva 	DEFINE_IDA(ida);
504166bb1f5SRehas Sachdeva 	unsigned long i;
505166bb1f5SRehas Sachdeva 
506166bb1f5SRehas Sachdeva 	for (i = 0; i < 10000; i++) {
507166bb1f5SRehas Sachdeva 		assert(ida_simple_get(&ida, 0, 20000, GFP_KERNEL) == i);
508166bb1f5SRehas Sachdeva 	}
509166bb1f5SRehas Sachdeva 	assert(ida_simple_get(&ida, 5, 30, GFP_KERNEL) < 0);
510166bb1f5SRehas Sachdeva 
511166bb1f5SRehas Sachdeva 	for (i = 0; i < 10000; i++) {
512166bb1f5SRehas Sachdeva 		ida_simple_remove(&ida, i);
513166bb1f5SRehas Sachdeva 	}
514166bb1f5SRehas Sachdeva 	assert(ida_is_empty(&ida));
515166bb1f5SRehas Sachdeva 
516166bb1f5SRehas Sachdeva 	ida_destroy(&ida);
517166bb1f5SRehas Sachdeva }
518166bb1f5SRehas Sachdeva 
user_ida_checks(void)5198ab8ba38SMatthew Wilcox void user_ida_checks(void)
5200a835c4fSMatthew Wilcox {
5210a835c4fSMatthew Wilcox 	radix_tree_cpu_dead(1);
522f272668dSMatthew Wilcox 
5230a835c4fSMatthew Wilcox 	ida_check_nomem();
5245c78b0b1SMatthew Wilcox 	ida_check_conv_user();
525d37cacc5SMatthew Wilcox 	ida_check_random();
526166bb1f5SRehas Sachdeva 	ida_simple_get_remove_test();
5270a835c4fSMatthew Wilcox 
5280a835c4fSMatthew Wilcox 	radix_tree_cpu_dead(1);
5290a835c4fSMatthew Wilcox }
5308ac04868SMatthew Wilcox 
ida_random_fn(void * arg)5314ecd9542SMatthew Wilcox static void *ida_random_fn(void *arg)
5324ecd9542SMatthew Wilcox {
5334ecd9542SMatthew Wilcox 	rcu_register_thread();
5344ecd9542SMatthew Wilcox 	ida_check_random();
5354ecd9542SMatthew Wilcox 	rcu_unregister_thread();
5364ecd9542SMatthew Wilcox 	return NULL;
5374ecd9542SMatthew Wilcox }
5384ecd9542SMatthew Wilcox 
ida_leak_fn(void * arg)539a219b856SMatthew Wilcox (Oracle) static void *ida_leak_fn(void *arg)
540a219b856SMatthew Wilcox (Oracle) {
541a219b856SMatthew Wilcox (Oracle) 	struct ida *ida = arg;
542a219b856SMatthew Wilcox (Oracle) 	time_t s = time(NULL);
543a219b856SMatthew Wilcox (Oracle) 	int i, ret;
544a219b856SMatthew Wilcox (Oracle) 
545a219b856SMatthew Wilcox (Oracle) 	rcu_register_thread();
546a219b856SMatthew Wilcox (Oracle) 
547a219b856SMatthew Wilcox (Oracle) 	do for (i = 0; i < 1000; i++) {
548a219b856SMatthew Wilcox (Oracle) 		ret = ida_alloc_range(ida, 128, 128, GFP_KERNEL);
549a219b856SMatthew Wilcox (Oracle) 		if (ret >= 0)
550a219b856SMatthew Wilcox (Oracle) 			ida_free(ida, 128);
551a219b856SMatthew Wilcox (Oracle) 	} while (time(NULL) < s + 2);
552a219b856SMatthew Wilcox (Oracle) 
553a219b856SMatthew Wilcox (Oracle) 	rcu_unregister_thread();
554a219b856SMatthew Wilcox (Oracle) 	return NULL;
555a219b856SMatthew Wilcox (Oracle) }
556a219b856SMatthew Wilcox (Oracle) 
ida_thread_tests(void)5574ecd9542SMatthew Wilcox void ida_thread_tests(void)
5584ecd9542SMatthew Wilcox {
559a219b856SMatthew Wilcox (Oracle) 	DEFINE_IDA(ida);
560490645d0SMatthew Wilcox 	pthread_t threads[20];
5614ecd9542SMatthew Wilcox 	int i;
5624ecd9542SMatthew Wilcox 
5634ecd9542SMatthew Wilcox 	for (i = 0; i < ARRAY_SIZE(threads); i++)
5644ecd9542SMatthew Wilcox 		if (pthread_create(&threads[i], NULL, ida_random_fn, NULL)) {
5654ecd9542SMatthew Wilcox 			perror("creating ida thread");
5664ecd9542SMatthew Wilcox 			exit(1);
5674ecd9542SMatthew Wilcox 		}
5684ecd9542SMatthew Wilcox 
5694ecd9542SMatthew Wilcox 	while (i--)
5704ecd9542SMatthew Wilcox 		pthread_join(threads[i], NULL);
571a219b856SMatthew Wilcox (Oracle) 
572a219b856SMatthew Wilcox (Oracle) 	for (i = 0; i < ARRAY_SIZE(threads); i++)
573a219b856SMatthew Wilcox (Oracle) 		if (pthread_create(&threads[i], NULL, ida_leak_fn, &ida)) {
574a219b856SMatthew Wilcox (Oracle) 			perror("creating ida thread");
575a219b856SMatthew Wilcox (Oracle) 			exit(1);
576a219b856SMatthew Wilcox (Oracle) 		}
577a219b856SMatthew Wilcox (Oracle) 
578a219b856SMatthew Wilcox (Oracle) 	while (i--)
579a219b856SMatthew Wilcox (Oracle) 		pthread_join(threads[i], NULL);
580a219b856SMatthew Wilcox (Oracle) 	assert(ida_is_empty(&ida));
5814ecd9542SMatthew Wilcox }
5824ecd9542SMatthew Wilcox 
ida_tests(void)5838ab8ba38SMatthew Wilcox void ida_tests(void)
5848ab8ba38SMatthew Wilcox {
5858ab8ba38SMatthew Wilcox 	user_ida_checks();
5868ab8ba38SMatthew Wilcox 	ida_checks();
5878ab8ba38SMatthew Wilcox 	ida_exit();
5888ab8ba38SMatthew Wilcox 	ida_thread_tests();
5898ab8ba38SMatthew Wilcox }
5908ab8ba38SMatthew Wilcox 
main(void)5918ac04868SMatthew Wilcox int __weak main(void)
5928ac04868SMatthew Wilcox {
5931bb4bd26SMatthew Wilcox (Oracle) 	rcu_register_thread();
5948ac04868SMatthew Wilcox 	radix_tree_init();
5958ac04868SMatthew Wilcox 	idr_checks();
5968ab8ba38SMatthew Wilcox 	ida_tests();
5974ecd9542SMatthew Wilcox 	radix_tree_cpu_dead(1);
5988ac04868SMatthew Wilcox 	rcu_barrier();
5998ac04868SMatthew Wilcox 	if (nr_allocated)
6008ac04868SMatthew Wilcox 		printf("nr_allocated = %d\n", nr_allocated);
6011bb4bd26SMatthew Wilcox (Oracle) 	rcu_unregister_thread();
6028ac04868SMatthew Wilcox 	return 0;
6038ac04868SMatthew Wilcox }
604