1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20#include <linux/errno.h>
21#include <linux/init.h>
22#include <linux/kernel.h>
23#include <linux/module.h>
24#include <linux/radix-tree.h>
25#include <linux/percpu.h>
26#include <linux/slab.h>
27#include <linux/gfp.h>
28#include <linux/string.h>
29
30
31
32
33#define RADIX_TREE_MAP_SHIFT 6
34#define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT)
35#define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1)
36
37struct radix_tree_node {
38 unsigned int count;
39 void *slots[RADIX_TREE_MAP_SIZE];
40};
41
42struct radix_tree_path {
43 struct radix_tree_node *node, **slot;
44};
45
46#define RADIX_TREE_INDEX_BITS (8 * sizeof(unsigned long))
47#define RADIX_TREE_MAX_PATH (RADIX_TREE_INDEX_BITS/RADIX_TREE_MAP_SHIFT + 2)
48
49static unsigned long height_to_maxindex[RADIX_TREE_MAX_PATH];
50
51
52
53
54static kmem_cache_t *radix_tree_node_cachep;
55
56
57
58
59struct radix_tree_preload {
60 int nr;
61 struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH];
62};
63DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, };
64
65
66
67
68
69static struct radix_tree_node *
70radix_tree_node_alloc(struct radix_tree_root *root)
71{
72 struct radix_tree_node *ret;
73
74 ret = kmem_cache_alloc(radix_tree_node_cachep, root->gfp_mask);
75 if (ret == NULL && !(root->gfp_mask & __GFP_WAIT)) {
76 struct radix_tree_preload *rtp;
77
78 rtp = &__get_cpu_var(radix_tree_preloads);
79 if (rtp->nr) {
80 ret = rtp->nodes[rtp->nr - 1];
81 rtp->nodes[rtp->nr - 1] = NULL;
82 rtp->nr--;
83 }
84 }
85 return ret;
86}
87
88static inline void
89radix_tree_node_free(struct radix_tree_node *node)
90{
91 kmem_cache_free(radix_tree_node_cachep, node);
92}
93
94
95
96
97
98
99
100int radix_tree_preload(int gfp_mask)
101{
102 struct radix_tree_preload *rtp;
103 struct radix_tree_node *node;
104 int ret = -ENOMEM;
105
106 preempt_disable();
107 rtp = &__get_cpu_var(radix_tree_preloads);
108 while (rtp->nr < ARRAY_SIZE(rtp->nodes)) {
109 preempt_enable();
110 node = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask);
111 if (node == NULL)
112 goto out;
113 preempt_disable();
114 rtp = &__get_cpu_var(radix_tree_preloads);
115 if (rtp->nr < ARRAY_SIZE(rtp->nodes))
116 rtp->nodes[rtp->nr++] = node;
117 else
118 kmem_cache_free(radix_tree_node_cachep, node);
119 }
120 ret = 0;
121out:
122 return ret;
123}
124
125
126
127
128
129static inline unsigned long radix_tree_maxindex(unsigned int height)
130{
131 return height_to_maxindex[height];
132}
133
134
135
136
137static int radix_tree_extend(struct radix_tree_root *root, unsigned long index)
138{
139 struct radix_tree_node *node;
140 unsigned int height;
141
142
143 height = root->height + 1;
144 while (index > radix_tree_maxindex(height))
145 height++;
146
147 if (root->rnode) {
148 do {
149 if (!(node = radix_tree_node_alloc(root)))
150 return -ENOMEM;
151
152
153 node->slots[0] = root->rnode;
154 node->count = 1;
155 root->rnode = node;
156 root->height++;
157 } while (height > root->height);
158 } else
159 root->height = height;
160
161 return 0;
162}
163
164
165
166
167
168
169
170
171
172int radix_tree_insert(struct radix_tree_root *root, unsigned long index, void *item)
173{
174 struct radix_tree_node *node = NULL, *tmp, **slot;
175 unsigned int height, shift;
176 int error;
177
178
179 if (index > radix_tree_maxindex(root->height)) {
180 error = radix_tree_extend(root, index);
181 if (error)
182 return error;
183 }
184
185 slot = &root->rnode;
186 height = root->height;
187 shift = (height-1) * RADIX_TREE_MAP_SHIFT;
188
189 while (height > 0) {
190 if (*slot == NULL) {
191
192 if (!(tmp = radix_tree_node_alloc(root)))
193 return -ENOMEM;
194 *slot = tmp;
195 if (node)
196 node->count++;
197 }
198
199
200 node = *slot;
201 slot = (struct radix_tree_node **)
202 (node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
203 shift -= RADIX_TREE_MAP_SHIFT;
204 height--;
205 }
206
207 if (*slot != NULL)
208 return -EEXIST;
209 if (node)
210 node->count++;
211
212 *slot = item;
213 return 0;
214}
215EXPORT_SYMBOL(radix_tree_insert);
216
217
218
219
220
221
222
223
224void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
225{
226 unsigned int height, shift;
227 struct radix_tree_node **slot;
228
229 height = root->height;
230 if (index > radix_tree_maxindex(height))
231 return NULL;
232
233 shift = (height-1) * RADIX_TREE_MAP_SHIFT;
234 slot = &root->rnode;
235
236 while (height > 0) {
237 if (*slot == NULL)
238 return NULL;
239
240 slot = (struct radix_tree_node **)
241 ((*slot)->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
242 shift -= RADIX_TREE_MAP_SHIFT;
243 height--;
244 }
245
246 return (void *) *slot;
247}
248EXPORT_SYMBOL(radix_tree_lookup);
249
250static unsigned int
251__lookup(struct radix_tree_root *root, void **results, unsigned long index,
252 unsigned int max_items, unsigned long *next_index)
253{
254 unsigned int nr_found = 0;
255 unsigned int shift;
256 unsigned int height = root->height;
257 struct radix_tree_node *slot;
258
259 shift = (height-1) * RADIX_TREE_MAP_SHIFT;
260 slot = root->rnode;
261
262 while (height > 0) {
263 unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
264
265 for ( ; i < RADIX_TREE_MAP_SIZE; i++) {
266 if (slot->slots[i] != NULL)
267 break;
268 index &= ~((1 << shift) - 1);
269 index += 1 << shift;
270 if (index == 0)
271 goto out;
272 }
273 if (i == RADIX_TREE_MAP_SIZE)
274 goto out;
275 height--;
276 if (height == 0) {
277 unsigned long j = index & RADIX_TREE_MAP_MASK;
278
279 for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
280 index++;
281 if (slot->slots[j]) {
282 results[nr_found++] = slot->slots[j];
283 if (nr_found == max_items)
284 goto out;
285 }
286 }
287 }
288 shift -= RADIX_TREE_MAP_SHIFT;
289 slot = slot->slots[i];
290 }
291out:
292 *next_index = index;
293 return nr_found;
294}
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309unsigned int
310radix_tree_gang_lookup(struct radix_tree_root *root, void **results,
311 unsigned long first_index, unsigned int max_items)
312{
313 const unsigned long max_index = radix_tree_maxindex(root->height);
314 unsigned long cur_index = first_index;
315 unsigned int ret = 0;
316
317 if (root->rnode == NULL)
318 goto out;
319 if (max_index == 0) {
320 if (first_index == 0) {
321 if (max_items > 0) {
322 *results = root->rnode;
323 ret = 1;
324 }
325 }
326 goto out;
327 }
328 while (ret < max_items) {
329 unsigned int nr_found;
330 unsigned long next_index;
331
332 if (cur_index > max_index)
333 break;
334 nr_found = __lookup(root, results + ret, cur_index,
335 max_items - ret, &next_index);
336 ret += nr_found;
337 if (next_index == 0)
338 break;
339 cur_index = next_index;
340 }
341out:
342 return ret;
343}
344EXPORT_SYMBOL(radix_tree_gang_lookup);
345
346
347
348
349
350
351
352
353
354
355void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
356{
357 struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
358 unsigned int height, shift;
359 void *ret = NULL;
360
361 height = root->height;
362 if (index > radix_tree_maxindex(height))
363 goto out;
364
365 shift = (height-1) * RADIX_TREE_MAP_SHIFT;
366 pathp->node = NULL;
367 pathp->slot = &root->rnode;
368
369 while (height > 0) {
370 if (*pathp->slot == NULL)
371 goto out;
372
373 pathp[1].node = *pathp[0].slot;
374 pathp[1].slot = (struct radix_tree_node **)
375 (pathp[1].node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK));
376 pathp++;
377 shift -= RADIX_TREE_MAP_SHIFT;
378 height--;
379 }
380
381 ret = *pathp[0].slot;
382 if (ret == NULL)
383 goto out;
384
385 *pathp[0].slot = NULL;
386 while (pathp[0].node && --pathp[0].node->count == 0) {
387 pathp--;
388 *pathp[0].slot = NULL;
389 radix_tree_node_free(pathp[1].node);
390 }
391
392 if (root->rnode == NULL)
393 root->height = 0;
394out:
395 return ret;
396}
397EXPORT_SYMBOL(radix_tree_delete);
398
399static void
400radix_tree_node_ctor(void *node, kmem_cache_t *cachep, unsigned long flags)
401{
402 memset(node, 0, sizeof(struct radix_tree_node));
403}
404
405static __init unsigned long __maxindex(unsigned int height)
406{
407 unsigned int tmp = height * RADIX_TREE_MAP_SHIFT;
408 unsigned long index = (~0UL >> (RADIX_TREE_INDEX_BITS - tmp - 1)) >> 1;
409
410 if (tmp >= RADIX_TREE_INDEX_BITS)
411 index = ~0UL;
412 return index;
413}
414
415static __init void radix_tree_init_maxindex(void)
416{
417 unsigned int i;
418
419 for (i = 0; i < ARRAY_SIZE(height_to_maxindex); i++)
420 height_to_maxindex[i] = __maxindex(i);
421}
422
423void __init radix_tree_init(void)
424{
425 radix_tree_node_cachep = kmem_cache_create("radix_tree_node",
426 sizeof(struct radix_tree_node), 0,
427 0, radix_tree_node_ctor, NULL);
428 if (!radix_tree_node_cachep)
429 panic ("Failed to create radix_tree_node cache\n");
430 radix_tree_init_maxindex();
431}
432