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