blob: 4dffad9284e030aab1d75c54b2bb520acb6d3f3c [file] [log] [blame]
Matthew Wilcox0a835c42016-12-20 10:27:56 -05001/*
2 * idr-test.c: Test the IDR API
3 * Copyright (c) 2016 Matthew Wilcox <willy@infradead.org>
4 *
5 * This program is free software; you can redistribute it and/or modify it
6 * under the terms and conditions of the GNU General Public License,
7 * version 2, as published by the Free Software Foundation.
8 *
9 * This program is distributed in the hope it will be useful, but WITHOUT
10 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
12 * more details.
13 */
14#include <linux/idr.h>
15#include <linux/slab.h>
16#include <linux/kernel.h>
17#include <linux/errno.h>
18
19#include "test.h"
20
21#define DUMMY_PTR ((void *)0x12)
22
23int item_idr_free(int id, void *p, void *data)
24{
25 struct item *item = p;
26 assert(item->index == id);
27 free(p);
28
29 return 0;
30}
31
32void item_idr_remove(struct idr *idr, int id)
33{
34 struct item *item = idr_find(idr, id);
35 assert(item->index == id);
36 idr_remove(idr, id);
37 free(item);
38}
39
40void idr_alloc_test(void)
41{
42 unsigned long i;
43 DEFINE_IDR(idr);
44
45 assert(idr_alloc_cyclic(&idr, DUMMY_PTR, 0, 0x4000, GFP_KERNEL) == 0);
46 assert(idr_alloc_cyclic(&idr, DUMMY_PTR, 0x3ffd, 0x4000, GFP_KERNEL) == 0x3ffd);
47 idr_remove(&idr, 0x3ffd);
48 idr_remove(&idr, 0);
49
50 for (i = 0x3ffe; i < 0x4003; i++) {
51 int id;
52 struct item *item;
53
54 if (i < 0x4000)
55 item = item_create(i, 0);
56 else
57 item = item_create(i - 0x3fff, 0);
58
59 id = idr_alloc_cyclic(&idr, item, 1, 0x4000, GFP_KERNEL);
60 assert(id == item->index);
61 }
62
63 idr_for_each(&idr, item_idr_free, &idr);
64 idr_destroy(&idr);
65}
66
67void idr_replace_test(void)
68{
69 DEFINE_IDR(idr);
70
71 idr_alloc(&idr, (void *)-1, 10, 11, GFP_KERNEL);
72 idr_replace(&idr, &idr, 10);
73
74 idr_destroy(&idr);
75}
76
77/*
78 * Unlike the radix tree, you can put a NULL pointer -- with care -- into
79 * the IDR. Some interfaces, like idr_find() do not distinguish between
80 * "present, value is NULL" and "not present", but that's exactly what some
81 * users want.
82 */
83void idr_null_test(void)
84{
85 int i;
86 DEFINE_IDR(idr);
87
88 assert(idr_is_empty(&idr));
89
90 assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
91 assert(!idr_is_empty(&idr));
92 idr_remove(&idr, 0);
93 assert(idr_is_empty(&idr));
94
95 assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
96 assert(!idr_is_empty(&idr));
97 idr_destroy(&idr);
98 assert(idr_is_empty(&idr));
99
100 for (i = 0; i < 10; i++) {
101 assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == i);
102 }
103
104 assert(idr_replace(&idr, DUMMY_PTR, 3) == NULL);
105 assert(idr_replace(&idr, DUMMY_PTR, 4) == NULL);
106 assert(idr_replace(&idr, NULL, 4) == DUMMY_PTR);
107 assert(idr_replace(&idr, DUMMY_PTR, 11) == ERR_PTR(-ENOENT));
108 idr_remove(&idr, 5);
109 assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 5);
110 idr_remove(&idr, 5);
111
112 for (i = 0; i < 9; i++) {
113 idr_remove(&idr, i);
114 assert(!idr_is_empty(&idr));
115 }
116 idr_remove(&idr, 8);
117 assert(!idr_is_empty(&idr));
118 idr_remove(&idr, 9);
119 assert(idr_is_empty(&idr));
120
121 assert(idr_alloc(&idr, NULL, 0, 0, GFP_KERNEL) == 0);
122 assert(idr_replace(&idr, DUMMY_PTR, 3) == ERR_PTR(-ENOENT));
123 assert(idr_replace(&idr, DUMMY_PTR, 0) == NULL);
124 assert(idr_replace(&idr, NULL, 0) == DUMMY_PTR);
125
126 idr_destroy(&idr);
127 assert(idr_is_empty(&idr));
128
129 for (i = 1; i < 10; i++) {
130 assert(idr_alloc(&idr, NULL, 1, 0, GFP_KERNEL) == i);
131 }
132
133 idr_destroy(&idr);
134 assert(idr_is_empty(&idr));
135}
136
137void idr_nowait_test(void)
138{
139 unsigned int i;
140 DEFINE_IDR(idr);
141
142 idr_preload(GFP_KERNEL);
143
144 for (i = 0; i < 3; i++) {
145 struct item *item = item_create(i, 0);
146 assert(idr_alloc(&idr, item, i, i + 1, GFP_NOWAIT) == i);
147 }
148
149 idr_preload_end();
150
151 idr_for_each(&idr, item_idr_free, &idr);
152 idr_destroy(&idr);
153}
154
155void idr_checks(void)
156{
157 unsigned long i;
158 DEFINE_IDR(idr);
159
160 for (i = 0; i < 10000; i++) {
161 struct item *item = item_create(i, 0);
162 assert(idr_alloc(&idr, item, 0, 20000, GFP_KERNEL) == i);
163 }
164
165 assert(idr_alloc(&idr, DUMMY_PTR, 5, 30, GFP_KERNEL) < 0);
166
167 for (i = 0; i < 5000; i++)
168 item_idr_remove(&idr, i);
169
170 idr_remove(&idr, 3);
171
172 idr_for_each(&idr, item_idr_free, &idr);
173 idr_destroy(&idr);
174
175 assert(idr_is_empty(&idr));
176
177 idr_remove(&idr, 3);
178 idr_remove(&idr, 0);
179
180 for (i = INT_MAX - 3UL; i < INT_MAX + 1UL; i++) {
181 struct item *item = item_create(i, 0);
182 assert(idr_alloc(&idr, item, i, i + 10, GFP_KERNEL) == i);
183 }
184 assert(idr_alloc(&idr, DUMMY_PTR, i - 2, i, GFP_KERNEL) == -ENOSPC);
185
186 idr_for_each(&idr, item_idr_free, &idr);
187 idr_destroy(&idr);
188 idr_destroy(&idr);
189
190 assert(idr_is_empty(&idr));
191
192 for (i = 1; i < 10000; i++) {
193 struct item *item = item_create(i, 0);
194 assert(idr_alloc(&idr, item, 1, 20000, GFP_KERNEL) == i);
195 }
196
197 idr_for_each(&idr, item_idr_free, &idr);
198 idr_destroy(&idr);
199
200 idr_replace_test();
201 idr_alloc_test();
202 idr_null_test();
203 idr_nowait_test();
204}
205
206/*
207 * Check that we get the correct error when we run out of memory doing
208 * allocations. To ensure we run out of memory, just "forget" to preload.
209 * The first test is for not having a bitmap available, and the second test
210 * is for not being able to allocate a level of the radix tree.
211 */
212void ida_check_nomem(void)
213{
214 DEFINE_IDA(ida);
215 int id, err;
216
217 err = ida_get_new(&ida, &id);
218 assert(err == -EAGAIN);
219 err = ida_get_new_above(&ida, 1UL << 30, &id);
220 assert(err == -EAGAIN);
221}
222
223/*
224 * Check what happens when we fill a leaf and then delete it. This may
225 * discover mishandling of IDR_FREE.
226 */
227void ida_check_leaf(void)
228{
229 DEFINE_IDA(ida);
230 int id;
231 unsigned long i;
232
233 for (i = 0; i < IDA_BITMAP_BITS; i++) {
234 assert(ida_pre_get(&ida, GFP_KERNEL));
235 assert(!ida_get_new(&ida, &id));
236 assert(id == i);
237 }
238
239 ida_destroy(&ida);
240 assert(ida_is_empty(&ida));
241
242 assert(ida_pre_get(&ida, GFP_KERNEL));
243 assert(!ida_get_new(&ida, &id));
244 assert(id == 0);
245 ida_destroy(&ida);
246 assert(ida_is_empty(&ida));
247}
248
249/*
250 * Check allocations up to and slightly above the maximum allowed (2^31-1) ID.
251 * Allocating up to 2^31-1 should succeed, and then allocating the next one
252 * should fail.
253 */
254void ida_check_max(void)
255{
256 DEFINE_IDA(ida);
257 int id, err;
258 unsigned long i, j;
259
260 for (j = 1; j < 65537; j *= 2) {
261 unsigned long base = (1UL << 31) - j;
262 for (i = 0; i < j; i++) {
263 assert(ida_pre_get(&ida, GFP_KERNEL));
264 assert(!ida_get_new_above(&ida, base, &id));
265 assert(id == base + i);
266 }
267 assert(ida_pre_get(&ida, GFP_KERNEL));
268 err = ida_get_new_above(&ida, base, &id);
269 assert(err == -ENOSPC);
270 ida_destroy(&ida);
271 assert(ida_is_empty(&ida));
272 rcu_barrier();
273 }
274}
275
276void ida_checks(void)
277{
278 DEFINE_IDA(ida);
279 int id;
280 unsigned long i;
281
282 radix_tree_cpu_dead(1);
283 ida_check_nomem();
284
285 for (i = 0; i < 10000; i++) {
286 assert(ida_pre_get(&ida, GFP_KERNEL));
287 assert(!ida_get_new(&ida, &id));
288 assert(id == i);
289 }
290
291 ida_remove(&ida, 20);
292 ida_remove(&ida, 21);
293 for (i = 0; i < 3; i++) {
294 assert(ida_pre_get(&ida, GFP_KERNEL));
295 assert(!ida_get_new(&ida, &id));
296 if (i == 2)
297 assert(id == 10000);
298 }
299
300 for (i = 0; i < 5000; i++)
301 ida_remove(&ida, i);
302
303 assert(ida_pre_get(&ida, GFP_KERNEL));
304 assert(!ida_get_new_above(&ida, 5000, &id));
305 assert(id == 10001);
306
307 ida_destroy(&ida);
308
309 assert(ida_is_empty(&ida));
310
311 assert(ida_pre_get(&ida, GFP_KERNEL));
312 assert(!ida_get_new_above(&ida, 1, &id));
313 assert(id == 1);
314
315 ida_remove(&ida, id);
316 assert(ida_is_empty(&ida));
317 ida_destroy(&ida);
318 assert(ida_is_empty(&ida));
319
320 assert(ida_pre_get(&ida, GFP_KERNEL));
321 assert(!ida_get_new_above(&ida, 1, &id));
322 ida_destroy(&ida);
323 assert(ida_is_empty(&ida));
324
325 assert(ida_pre_get(&ida, GFP_KERNEL));
326 assert(!ida_get_new_above(&ida, 1, &id));
327 assert(id == 1);
328 assert(ida_pre_get(&ida, GFP_KERNEL));
329 assert(!ida_get_new_above(&ida, 1025, &id));
330 assert(id == 1025);
331 assert(ida_pre_get(&ida, GFP_KERNEL));
332 assert(!ida_get_new_above(&ida, 10000, &id));
333 assert(id == 10000);
334 ida_remove(&ida, 1025);
335 ida_destroy(&ida);
336 assert(ida_is_empty(&ida));
337
338 ida_check_leaf();
339 ida_check_max();
340
341 radix_tree_cpu_dead(1);
342}