1#include <linux/bitmap.h>
2#include <linux/export.h>
3#include <linux/idr.h>
4#include <linux/slab.h>
5#include <linux/spinlock.h>
6
7DEFINE_PER_CPU(struct ida_bitmap *, ida_bitmap);
8static DEFINE_SPINLOCK(simple_ida_lock);
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29int idr_alloc(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
30{
31 void __rcu **slot;
32 struct radix_tree_iter iter;
33
34 if (WARN_ON_ONCE(start < 0))
35 return -EINVAL;
36 if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr)))
37 return -EINVAL;
38
39 radix_tree_iter_init(&iter, start);
40 slot = idr_get_free(&idr->idr_rt, &iter, gfp, end);
41 if (IS_ERR(slot))
42 return PTR_ERR(slot);
43
44 radix_tree_iter_replace(&idr->idr_rt, &iter, slot, ptr);
45 radix_tree_iter_tag_clear(&idr->idr_rt, &iter, IDR_FREE);
46 return iter.index;
47}
48EXPORT_SYMBOL_GPL(idr_alloc);
49
50
51
52
53
54
55
56
57
58
59
60
61
62int idr_alloc_cyclic(struct idr *idr, void *ptr, int start, int end, gfp_t gfp)
63{
64 int id, curr = idr->idr_next;
65
66 if (curr < start)
67 curr = start;
68
69 id = idr_alloc(idr, ptr, curr, end, gfp);
70 if ((id == -ENOSPC) && (curr > start))
71 id = idr_alloc(idr, ptr, start, curr, gfp);
72
73 if (id >= 0)
74 idr->idr_next = id + 1U;
75
76 return id;
77}
78EXPORT_SYMBOL(idr_alloc_cyclic);
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97int idr_for_each(const struct idr *idr,
98 int (*fn)(int id, void *p, void *data), void *data)
99{
100 struct radix_tree_iter iter;
101 void __rcu **slot;
102
103 radix_tree_for_each_slot(slot, &idr->idr_rt, &iter, 0) {
104 int ret = fn(iter.index, rcu_dereference_raw(*slot), data);
105 if (ret)
106 return ret;
107 }
108
109 return 0;
110}
111EXPORT_SYMBOL(idr_for_each);
112
113
114
115
116
117
118
119
120
121
122
123void *idr_get_next(struct idr *idr, int *nextid)
124{
125 struct radix_tree_iter iter;
126 void __rcu **slot;
127
128 slot = radix_tree_iter_find(&idr->idr_rt, &iter, *nextid);
129 if (!slot)
130 return NULL;
131
132 *nextid = iter.index;
133 return rcu_dereference_raw(*slot);
134}
135EXPORT_SYMBOL(idr_get_next);
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151void *idr_replace(struct idr *idr, void *ptr, int id)
152{
153 struct radix_tree_node *node;
154 void __rcu **slot = NULL;
155 void *entry;
156
157 if (WARN_ON_ONCE(id < 0))
158 return ERR_PTR(-EINVAL);
159 if (WARN_ON_ONCE(radix_tree_is_internal_node(ptr)))
160 return ERR_PTR(-EINVAL);
161
162 entry = __radix_tree_lookup(&idr->idr_rt, id, &node, &slot);
163 if (!slot || radix_tree_tag_get(&idr->idr_rt, id, IDR_FREE))
164 return ERR_PTR(-ENOENT);
165
166 __radix_tree_replace(&idr->idr_rt, node, slot, ptr, NULL, NULL);
167
168 return entry;
169}
170EXPORT_SYMBOL(idr_replace);
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230#define IDA_MAX (0x80000000U / IDA_BITMAP_BITS)
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250int ida_get_new_above(struct ida *ida, int start, int *id)
251{
252 struct radix_tree_root *root = &ida->ida_rt;
253 void __rcu **slot;
254 struct radix_tree_iter iter;
255 struct ida_bitmap *bitmap;
256 unsigned long index;
257 unsigned bit, ebit;
258 int new;
259
260 index = start / IDA_BITMAP_BITS;
261 bit = start % IDA_BITMAP_BITS;
262 ebit = bit + RADIX_TREE_EXCEPTIONAL_SHIFT;
263
264 slot = radix_tree_iter_init(&iter, index);
265 for (;;) {
266 if (slot)
267 slot = radix_tree_next_slot(slot, &iter,
268 RADIX_TREE_ITER_TAGGED);
269 if (!slot) {
270 slot = idr_get_free(root, &iter, GFP_NOWAIT, IDA_MAX);
271 if (IS_ERR(slot)) {
272 if (slot == ERR_PTR(-ENOMEM))
273 return -EAGAIN;
274 return PTR_ERR(slot);
275 }
276 }
277 if (iter.index > index) {
278 bit = 0;
279 ebit = RADIX_TREE_EXCEPTIONAL_SHIFT;
280 }
281 new = iter.index * IDA_BITMAP_BITS;
282 bitmap = rcu_dereference_raw(*slot);
283 if (radix_tree_exception(bitmap)) {
284 unsigned long tmp = (unsigned long)bitmap;
285 ebit = find_next_zero_bit(&tmp, BITS_PER_LONG, ebit);
286 if (ebit < BITS_PER_LONG) {
287 tmp |= 1UL << ebit;
288 rcu_assign_pointer(*slot, (void *)tmp);
289 *id = new + ebit - RADIX_TREE_EXCEPTIONAL_SHIFT;
290 return 0;
291 }
292 bitmap = this_cpu_xchg(ida_bitmap, NULL);
293 if (!bitmap)
294 return -EAGAIN;
295 memset(bitmap, 0, sizeof(*bitmap));
296 bitmap->bitmap[0] = tmp >> RADIX_TREE_EXCEPTIONAL_SHIFT;
297 rcu_assign_pointer(*slot, bitmap);
298 }
299
300 if (bitmap) {
301 bit = find_next_zero_bit(bitmap->bitmap,
302 IDA_BITMAP_BITS, bit);
303 new += bit;
304 if (new < 0)
305 return -ENOSPC;
306 if (bit == IDA_BITMAP_BITS)
307 continue;
308
309 __set_bit(bit, bitmap->bitmap);
310 if (bitmap_full(bitmap->bitmap, IDA_BITMAP_BITS))
311 radix_tree_iter_tag_clear(root, &iter,
312 IDR_FREE);
313 } else {
314 new += bit;
315 if (new < 0)
316 return -ENOSPC;
317 if (ebit < BITS_PER_LONG) {
318 bitmap = (void *)((1UL << ebit) |
319 RADIX_TREE_EXCEPTIONAL_ENTRY);
320 radix_tree_iter_replace(root, &iter, slot,
321 bitmap);
322 *id = new;
323 return 0;
324 }
325 bitmap = this_cpu_xchg(ida_bitmap, NULL);
326 if (!bitmap)
327 return -EAGAIN;
328 memset(bitmap, 0, sizeof(*bitmap));
329 __set_bit(bit, bitmap->bitmap);
330 radix_tree_iter_replace(root, &iter, slot, bitmap);
331 }
332
333 *id = new;
334 return 0;
335 }
336}
337EXPORT_SYMBOL(ida_get_new_above);
338
339
340
341
342
343
344
345
346void ida_remove(struct ida *ida, int id)
347{
348 unsigned long index = id / IDA_BITMAP_BITS;
349 unsigned offset = id % IDA_BITMAP_BITS;
350 struct ida_bitmap *bitmap;
351 unsigned long *btmp;
352 struct radix_tree_iter iter;
353 void __rcu **slot;
354
355 slot = radix_tree_iter_lookup(&ida->ida_rt, &iter, index);
356 if (!slot)
357 goto err;
358
359 bitmap = rcu_dereference_raw(*slot);
360 if (radix_tree_exception(bitmap)) {
361 btmp = (unsigned long *)slot;
362 offset += RADIX_TREE_EXCEPTIONAL_SHIFT;
363 if (offset >= BITS_PER_LONG)
364 goto err;
365 } else {
366 btmp = bitmap->bitmap;
367 }
368 if (!test_bit(offset, btmp))
369 goto err;
370
371 __clear_bit(offset, btmp);
372 radix_tree_iter_tag_set(&ida->ida_rt, &iter, IDR_FREE);
373 if (radix_tree_exception(bitmap)) {
374 if (rcu_dereference_raw(*slot) ==
375 (void *)RADIX_TREE_EXCEPTIONAL_ENTRY)
376 radix_tree_iter_delete(&ida->ida_rt, &iter, slot);
377 } else if (bitmap_empty(btmp, IDA_BITMAP_BITS)) {
378 kfree(bitmap);
379 radix_tree_iter_delete(&ida->ida_rt, &iter, slot);
380 }
381 return;
382 err:
383 WARN(1, "ida_remove called for id=%d which is not allocated.\n", id);
384}
385EXPORT_SYMBOL(ida_remove);
386
387
388
389
390
391
392
393
394
395
396void ida_destroy(struct ida *ida)
397{
398 struct radix_tree_iter iter;
399 void __rcu **slot;
400
401 radix_tree_for_each_slot(slot, &ida->ida_rt, &iter, 0) {
402 struct ida_bitmap *bitmap = rcu_dereference_raw(*slot);
403 if (!radix_tree_exception(bitmap))
404 kfree(bitmap);
405 radix_tree_iter_delete(&ida->ida_rt, &iter, slot);
406 }
407}
408EXPORT_SYMBOL(ida_destroy);
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425int ida_simple_get(struct ida *ida, unsigned int start, unsigned int end,
426 gfp_t gfp_mask)
427{
428 int ret, id;
429 unsigned int max;
430 unsigned long flags;
431
432 BUG_ON((int)start < 0);
433 BUG_ON((int)end < 0);
434
435 if (end == 0)
436 max = 0x80000000;
437 else {
438 BUG_ON(end < start);
439 max = end - 1;
440 }
441
442again:
443 if (!ida_pre_get(ida, gfp_mask))
444 return -ENOMEM;
445
446 spin_lock_irqsave(&simple_ida_lock, flags);
447 ret = ida_get_new_above(ida, start, &id);
448 if (!ret) {
449 if (id > max) {
450 ida_remove(ida, id);
451 ret = -ENOSPC;
452 } else {
453 ret = id;
454 }
455 }
456 spin_unlock_irqrestore(&simple_ida_lock, flags);
457
458 if (unlikely(ret == -EAGAIN))
459 goto again;
460
461 return ret;
462}
463EXPORT_SYMBOL(ida_simple_get);
464
465
466
467
468
469
470
471
472
473
474
475void ida_simple_remove(struct ida *ida, unsigned int id)
476{
477 unsigned long flags;
478
479 BUG_ON((int)id < 0);
480 spin_lock_irqsave(&simple_ida_lock, flags);
481 ida_remove(ida, id);
482 spin_unlock_irqrestore(&simple_ida_lock, flags);
483}
484EXPORT_SYMBOL(ida_simple_remove);
485