aboutsummaryrefslogtreecommitdiffstats
path: root/lib/radix-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/radix-tree.c')
-rw-r--r--lib/radix-tree.c159
1 files changed, 82 insertions, 77 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 10bed1c8c3c3..2e9bd54beba4 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -1,6 +1,7 @@
1/* 1/*
2 * Copyright (C) 2001 Momchil Velikov 2 * Copyright (C) 2001 Momchil Velikov
3 * Portions Copyright (C) 2001 Christoph Hellwig 3 * Portions Copyright (C) 2001 Christoph Hellwig
4 * Copyright (C) 2005 SGI, Christoph Lameter <clameter@sgi.com>
4 * 5 *
5 * This program is free software; you can redistribute it and/or 6 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU General Public License as 7 * modify it under the terms of the GNU General Public License as
@@ -51,7 +52,7 @@ struct radix_tree_node {
51}; 52};
52 53
53struct radix_tree_path { 54struct radix_tree_path {
54 struct radix_tree_node *node, **slot; 55 struct radix_tree_node *node;
55 int offset; 56 int offset;
56}; 57};
57 58
@@ -227,7 +228,7 @@ out:
227int radix_tree_insert(struct radix_tree_root *root, 228int radix_tree_insert(struct radix_tree_root *root,
228 unsigned long index, void *item) 229 unsigned long index, void *item)
229{ 230{
230 struct radix_tree_node *node = NULL, *tmp, **slot; 231 struct radix_tree_node *node = NULL, *slot;
231 unsigned int height, shift; 232 unsigned int height, shift;
232 int offset; 233 int offset;
233 int error; 234 int error;
@@ -240,38 +241,42 @@ int radix_tree_insert(struct radix_tree_root *root,
240 return error; 241 return error;
241 } 242 }
242 243
243 slot = &root->rnode; 244 slot = root->rnode;
244 height = root->height; 245 height = root->height;
245 shift = (height-1) * RADIX_TREE_MAP_SHIFT; 246 shift = (height-1) * RADIX_TREE_MAP_SHIFT;
246 247
247 offset = 0; /* uninitialised var warning */ 248 offset = 0; /* uninitialised var warning */
248 while (height > 0) { 249 while (height > 0) {
249 if (*slot == NULL) { 250 if (slot == NULL) {
250 /* Have to add a child node. */ 251 /* Have to add a child node. */
251 if (!(tmp = radix_tree_node_alloc(root))) 252 if (!(slot = radix_tree_node_alloc(root)))
252 return -ENOMEM; 253 return -ENOMEM;
253 *slot = tmp; 254 if (node) {
254 if (node) 255 node->slots[offset] = slot;
255 node->count++; 256 node->count++;
257 } else
258 root->rnode = slot;
256 } 259 }
257 260
258 /* Go a level down */ 261 /* Go a level down */
259 offset = (index >> shift) & RADIX_TREE_MAP_MASK; 262 offset = (index >> shift) & RADIX_TREE_MAP_MASK;
260 node = *slot; 263 node = slot;
261 slot = (struct radix_tree_node **)(node->slots + offset); 264 slot = node->slots[offset];
262 shift -= RADIX_TREE_MAP_SHIFT; 265 shift -= RADIX_TREE_MAP_SHIFT;
263 height--; 266 height--;
264 } 267 }
265 268
266 if (*slot != NULL) 269 if (slot != NULL)
267 return -EEXIST; 270 return -EEXIST;
271
268 if (node) { 272 if (node) {
269 node->count++; 273 node->count++;
274 node->slots[offset] = item;
270 BUG_ON(tag_get(node, 0, offset)); 275 BUG_ON(tag_get(node, 0, offset));
271 BUG_ON(tag_get(node, 1, offset)); 276 BUG_ON(tag_get(node, 1, offset));
272 } 277 } else
278 root->rnode = item;
273 279
274 *slot = item;
275 return 0; 280 return 0;
276} 281}
277EXPORT_SYMBOL(radix_tree_insert); 282EXPORT_SYMBOL(radix_tree_insert);
@@ -286,27 +291,25 @@ EXPORT_SYMBOL(radix_tree_insert);
286void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) 291void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index)
287{ 292{
288 unsigned int height, shift; 293 unsigned int height, shift;
289 struct radix_tree_node **slot; 294 struct radix_tree_node *slot;
290 295
291 height = root->height; 296 height = root->height;
292 if (index > radix_tree_maxindex(height)) 297 if (index > radix_tree_maxindex(height))
293 return NULL; 298 return NULL;
294 299
295 shift = (height-1) * RADIX_TREE_MAP_SHIFT; 300 shift = (height-1) * RADIX_TREE_MAP_SHIFT;
296 slot = &root->rnode; 301 slot = root->rnode;
297 302
298 while (height > 0) { 303 while (height > 0) {
299 if (*slot == NULL) 304 if (slot == NULL)
300 return NULL; 305 return NULL;
301 306
302 slot = (struct radix_tree_node **) 307 slot = slot->slots[(index >> shift) & RADIX_TREE_MAP_MASK];
303 ((*slot)->slots +
304 ((index >> shift) & RADIX_TREE_MAP_MASK));
305 shift -= RADIX_TREE_MAP_SHIFT; 308 shift -= RADIX_TREE_MAP_SHIFT;
306 height--; 309 height--;
307 } 310 }
308 311
309 return *slot; 312 return slot;
310} 313}
311EXPORT_SYMBOL(radix_tree_lookup); 314EXPORT_SYMBOL(radix_tree_lookup);
312 315
@@ -326,27 +329,27 @@ void *radix_tree_tag_set(struct radix_tree_root *root,
326 unsigned long index, int tag) 329 unsigned long index, int tag)
327{ 330{
328 unsigned int height, shift; 331 unsigned int height, shift;
329 struct radix_tree_node **slot; 332 struct radix_tree_node *slot;
330 333
331 height = root->height; 334 height = root->height;
332 if (index > radix_tree_maxindex(height)) 335 if (index > radix_tree_maxindex(height))
333 return NULL; 336 return NULL;
334 337
335 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 338 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
336 slot = &root->rnode; 339 slot = root->rnode;
337 340
338 while (height > 0) { 341 while (height > 0) {
339 int offset; 342 int offset;
340 343
341 offset = (index >> shift) & RADIX_TREE_MAP_MASK; 344 offset = (index >> shift) & RADIX_TREE_MAP_MASK;
342 tag_set(*slot, tag, offset); 345 tag_set(slot, tag, offset);
343 slot = (struct radix_tree_node **)((*slot)->slots + offset); 346 slot = slot->slots[offset];
344 BUG_ON(*slot == NULL); 347 BUG_ON(slot == NULL);
345 shift -= RADIX_TREE_MAP_SHIFT; 348 shift -= RADIX_TREE_MAP_SHIFT;
346 height--; 349 height--;
347 } 350 }
348 351
349 return *slot; 352 return slot;
350} 353}
351EXPORT_SYMBOL(radix_tree_tag_set); 354EXPORT_SYMBOL(radix_tree_tag_set);
352 355
@@ -367,6 +370,7 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
367 unsigned long index, int tag) 370 unsigned long index, int tag)
368{ 371{
369 struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; 372 struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
373 struct radix_tree_node *slot;
370 unsigned int height, shift; 374 unsigned int height, shift;
371 void *ret = NULL; 375 void *ret = NULL;
372 376
@@ -376,38 +380,37 @@ void *radix_tree_tag_clear(struct radix_tree_root *root,
376 380
377 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 381 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
378 pathp->node = NULL; 382 pathp->node = NULL;
379 pathp->slot = &root->rnode; 383 slot = root->rnode;
380 384
381 while (height > 0) { 385 while (height > 0) {
382 int offset; 386 int offset;
383 387
384 if (*pathp->slot == NULL) 388 if (slot == NULL)
385 goto out; 389 goto out;
386 390
387 offset = (index >> shift) & RADIX_TREE_MAP_MASK; 391 offset = (index >> shift) & RADIX_TREE_MAP_MASK;
388 pathp[1].offset = offset; 392 pathp[1].offset = offset;
389 pathp[1].node = *pathp[0].slot; 393 pathp[1].node = slot;
390 pathp[1].slot = (struct radix_tree_node **) 394 slot = slot->slots[offset];
391 (pathp[1].node->slots + offset);
392 pathp++; 395 pathp++;
393 shift -= RADIX_TREE_MAP_SHIFT; 396 shift -= RADIX_TREE_MAP_SHIFT;
394 height--; 397 height--;
395 } 398 }
396 399
397 ret = *pathp[0].slot; 400 ret = slot;
398 if (ret == NULL) 401 if (ret == NULL)
399 goto out; 402 goto out;
400 403
401 do { 404 do {
402 int idx; 405 int idx;
403 406
404 tag_clear(pathp[0].node, tag, pathp[0].offset); 407 tag_clear(pathp->node, tag, pathp->offset);
405 for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { 408 for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
406 if (pathp[0].node->tags[tag][idx]) 409 if (pathp->node->tags[tag][idx])
407 goto out; 410 goto out;
408 } 411 }
409 pathp--; 412 pathp--;
410 } while (pathp[0].node); 413 } while (pathp->node);
411out: 414out:
412 return ret; 415 return ret;
413} 416}
@@ -429,7 +432,7 @@ int radix_tree_tag_get(struct radix_tree_root *root,
429 unsigned long index, int tag) 432 unsigned long index, int tag)
430{ 433{
431 unsigned int height, shift; 434 unsigned int height, shift;
432 struct radix_tree_node **slot; 435 struct radix_tree_node *slot;
433 int saw_unset_tag = 0; 436 int saw_unset_tag = 0;
434 437
435 height = root->height; 438 height = root->height;
@@ -437,12 +440,12 @@ int radix_tree_tag_get(struct radix_tree_root *root,
437 return 0; 440 return 0;
438 441
439 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 442 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
440 slot = &root->rnode; 443 slot = root->rnode;
441 444
442 for ( ; ; ) { 445 for ( ; ; ) {
443 int offset; 446 int offset;
444 447
445 if (*slot == NULL) 448 if (slot == NULL)
446 return 0; 449 return 0;
447 450
448 offset = (index >> shift) & RADIX_TREE_MAP_MASK; 451 offset = (index >> shift) & RADIX_TREE_MAP_MASK;
@@ -451,15 +454,15 @@ int radix_tree_tag_get(struct radix_tree_root *root,
451 * This is just a debug check. Later, we can bale as soon as 454 * This is just a debug check. Later, we can bale as soon as
452 * we see an unset tag. 455 * we see an unset tag.
453 */ 456 */
454 if (!tag_get(*slot, tag, offset)) 457 if (!tag_get(slot, tag, offset))
455 saw_unset_tag = 1; 458 saw_unset_tag = 1;
456 if (height == 1) { 459 if (height == 1) {
457 int ret = tag_get(*slot, tag, offset); 460 int ret = tag_get(slot, tag, offset);
458 461
459 BUG_ON(ret && saw_unset_tag); 462 BUG_ON(ret && saw_unset_tag);
460 return ret; 463 return ret;
461 } 464 }
462 slot = (struct radix_tree_node **)((*slot)->slots + offset); 465 slot = slot->slots[offset];
463 shift -= RADIX_TREE_MAP_SHIFT; 466 shift -= RADIX_TREE_MAP_SHIFT;
464 height--; 467 height--;
465 } 468 }
@@ -472,17 +475,21 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
472 unsigned int max_items, unsigned long *next_index) 475 unsigned int max_items, unsigned long *next_index)
473{ 476{
474 unsigned int nr_found = 0; 477 unsigned int nr_found = 0;
475 unsigned int shift; 478 unsigned int shift, height;
476 unsigned int height = root->height;
477 struct radix_tree_node *slot; 479 struct radix_tree_node *slot;
480 unsigned long i;
481
482 height = root->height;
483 if (height == 0)
484 goto out;
478 485
479 shift = (height-1) * RADIX_TREE_MAP_SHIFT; 486 shift = (height-1) * RADIX_TREE_MAP_SHIFT;
480 slot = root->rnode; 487 slot = root->rnode;
481 488
482 while (height > 0) { 489 for ( ; height > 1; height--) {
483 unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK;
484 490
485 for ( ; i < RADIX_TREE_MAP_SIZE; i++) { 491 for (i = (index >> shift) & RADIX_TREE_MAP_MASK ;
492 i < RADIX_TREE_MAP_SIZE; i++) {
486 if (slot->slots[i] != NULL) 493 if (slot->slots[i] != NULL)
487 break; 494 break;
488 index &= ~((1UL << shift) - 1); 495 index &= ~((1UL << shift) - 1);
@@ -492,22 +499,20 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index,
492 } 499 }
493 if (i == RADIX_TREE_MAP_SIZE) 500 if (i == RADIX_TREE_MAP_SIZE)
494 goto out; 501 goto out;
495 height--;
496 if (height == 0) { /* Bottom level: grab some items */
497 unsigned long j = index & RADIX_TREE_MAP_MASK;
498 502
499 for ( ; j < RADIX_TREE_MAP_SIZE; j++) {
500 index++;
501 if (slot->slots[j]) {
502 results[nr_found++] = slot->slots[j];
503 if (nr_found == max_items)
504 goto out;
505 }
506 }
507 }
508 shift -= RADIX_TREE_MAP_SHIFT; 503 shift -= RADIX_TREE_MAP_SHIFT;
509 slot = slot->slots[i]; 504 slot = slot->slots[i];
510 } 505 }
506
507 /* Bottom level: grab some items */
508 for (i = index & RADIX_TREE_MAP_MASK; i < RADIX_TREE_MAP_SIZE; i++) {
509 index++;
510 if (slot->slots[i]) {
511 results[nr_found++] = slot->slots[i];
512 if (nr_found == max_items)
513 goto out;
514 }
515 }
511out: 516out:
512 *next_index = index; 517 *next_index = index;
513 return nr_found; 518 return nr_found;
@@ -655,6 +660,7 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
655{ 660{
656 struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; 661 struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path;
657 struct radix_tree_path *orig_pathp; 662 struct radix_tree_path *orig_pathp;
663 struct radix_tree_node *slot;
658 unsigned int height, shift; 664 unsigned int height, shift;
659 void *ret = NULL; 665 void *ret = NULL;
660 char tags[RADIX_TREE_TAGS]; 666 char tags[RADIX_TREE_TAGS];
@@ -666,25 +672,23 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
666 672
667 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 673 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
668 pathp->node = NULL; 674 pathp->node = NULL;
669 pathp->slot = &root->rnode; 675 slot = root->rnode;
670 676
671 while (height > 0) { 677 for ( ; height > 0; height--) {
672 int offset; 678 int offset;
673 679
674 if (*pathp->slot == NULL) 680 if (slot == NULL)
675 goto out; 681 goto out;
676 682
677 offset = (index >> shift) & RADIX_TREE_MAP_MASK; 683 offset = (index >> shift) & RADIX_TREE_MAP_MASK;
678 pathp[1].offset = offset; 684 pathp[1].offset = offset;
679 pathp[1].node = *pathp[0].slot; 685 pathp[1].node = slot;
680 pathp[1].slot = (struct radix_tree_node **) 686 slot = slot->slots[offset];
681 (pathp[1].node->slots + offset);
682 pathp++; 687 pathp++;
683 shift -= RADIX_TREE_MAP_SHIFT; 688 shift -= RADIX_TREE_MAP_SHIFT;
684 height--;
685 } 689 }
686 690
687 ret = *pathp[0].slot; 691 ret = slot;
688 if (ret == NULL) 692 if (ret == NULL)
689 goto out; 693 goto out;
690 694
@@ -704,10 +708,10 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
704 if (tags[tag]) 708 if (tags[tag])
705 continue; 709 continue;
706 710
707 tag_clear(pathp[0].node, tag, pathp[0].offset); 711 tag_clear(pathp->node, tag, pathp->offset);
708 712
709 for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) { 713 for (idx = 0; idx < RADIX_TREE_TAG_LONGS; idx++) {
710 if (pathp[0].node->tags[tag][idx]) { 714 if (pathp->node->tags[tag][idx]) {
711 tags[tag] = 1; 715 tags[tag] = 1;
712 nr_cleared_tags--; 716 nr_cleared_tags--;
713 break; 717 break;
@@ -715,18 +719,19 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index)
715 } 719 }
716 } 720 }
717 pathp--; 721 pathp--;
718 } while (pathp[0].node && nr_cleared_tags); 722 } while (pathp->node && nr_cleared_tags);
719 723
720 pathp = orig_pathp; 724 /* Now free the nodes we do not need anymore */
721 *pathp[0].slot = NULL; 725 for (pathp = orig_pathp; pathp->node; pathp--) {
722 while (pathp[0].node && --pathp[0].node->count == 0) { 726 pathp->node->slots[pathp->offset] = NULL;
723 pathp--; 727 if (--pathp->node->count)
724 BUG_ON(*pathp[0].slot == NULL); 728 goto out;
725 *pathp[0].slot = NULL; 729
726 radix_tree_node_free(pathp[1].node); 730 /* Node with zero slots in use so free it */
731 radix_tree_node_free(pathp->node);
727 } 732 }
728 if (root->rnode == NULL) 733 root->rnode = NULL;
729 root->height = 0; 734 root->height = 0;
730out: 735out:
731 return ret; 736 return ret;
732} 737}