diff options
Diffstat (limited to 'lib/radix-tree.c')
-rw-r--r-- | lib/radix-tree.c | 385 |
1 files changed, 187 insertions, 198 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index bd4a8dfdf0b8..9599aa72d7a0 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
@@ -35,33 +35,6 @@ | |||
35 | #include <linux/hardirq.h> /* in_interrupt() */ | 35 | #include <linux/hardirq.h> /* in_interrupt() */ |
36 | 36 | ||
37 | 37 | ||
38 | #ifdef __KERNEL__ | ||
39 | #define RADIX_TREE_MAP_SHIFT (CONFIG_BASE_SMALL ? 4 : 6) | ||
40 | #else | ||
41 | #define RADIX_TREE_MAP_SHIFT 3 /* For more stressful testing */ | ||
42 | #endif | ||
43 | |||
44 | #define RADIX_TREE_MAP_SIZE (1UL << RADIX_TREE_MAP_SHIFT) | ||
45 | #define RADIX_TREE_MAP_MASK (RADIX_TREE_MAP_SIZE-1) | ||
46 | |||
47 | #define RADIX_TREE_TAG_LONGS \ | ||
48 | ((RADIX_TREE_MAP_SIZE + BITS_PER_LONG - 1) / BITS_PER_LONG) | ||
49 | |||
50 | struct radix_tree_node { | ||
51 | unsigned int height; /* Height from the bottom */ | ||
52 | unsigned int count; | ||
53 | union { | ||
54 | struct radix_tree_node *parent; /* Used when ascending tree */ | ||
55 | struct rcu_head rcu_head; /* Used when freeing node */ | ||
56 | }; | ||
57 | void __rcu *slots[RADIX_TREE_MAP_SIZE]; | ||
58 | unsigned long tags[RADIX_TREE_MAX_TAGS][RADIX_TREE_TAG_LONGS]; | ||
59 | }; | ||
60 | |||
61 | #define RADIX_TREE_INDEX_BITS (8 /* CHAR_BIT */ * sizeof(unsigned long)) | ||
62 | #define RADIX_TREE_MAX_PATH (DIV_ROUND_UP(RADIX_TREE_INDEX_BITS, \ | ||
63 | RADIX_TREE_MAP_SHIFT)) | ||
64 | |||
65 | /* | 38 | /* |
66 | * The height_to_maxindex array needs to be one deeper than the maximum | 39 | * The height_to_maxindex array needs to be one deeper than the maximum |
67 | * path as height 0 holds only 1 entry. | 40 | * path as height 0 holds only 1 entry. |
@@ -369,7 +342,8 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) | |||
369 | 342 | ||
370 | /* Increase the height. */ | 343 | /* Increase the height. */ |
371 | newheight = root->height+1; | 344 | newheight = root->height+1; |
372 | node->height = newheight; | 345 | BUG_ON(newheight & ~RADIX_TREE_HEIGHT_MASK); |
346 | node->path = newheight; | ||
373 | node->count = 1; | 347 | node->count = 1; |
374 | node->parent = NULL; | 348 | node->parent = NULL; |
375 | slot = root->rnode; | 349 | slot = root->rnode; |
@@ -387,23 +361,28 @@ out: | |||
387 | } | 361 | } |
388 | 362 | ||
389 | /** | 363 | /** |
390 | * radix_tree_insert - insert into a radix tree | 364 | * __radix_tree_create - create a slot in a radix tree |
391 | * @root: radix tree root | 365 | * @root: radix tree root |
392 | * @index: index key | 366 | * @index: index key |
393 | * @item: item to insert | 367 | * @nodep: returns node |
368 | * @slotp: returns slot | ||
394 | * | 369 | * |
395 | * Insert an item into the radix tree at position @index. | 370 | * Create, if necessary, and return the node and slot for an item |
371 | * at position @index in the radix tree @root. | ||
372 | * | ||
373 | * Until there is more than one item in the tree, no nodes are | ||
374 | * allocated and @root->rnode is used as a direct slot instead of | ||
375 | * pointing to a node, in which case *@nodep will be NULL. | ||
376 | * | ||
377 | * Returns -ENOMEM, or 0 for success. | ||
396 | */ | 378 | */ |
397 | int radix_tree_insert(struct radix_tree_root *root, | 379 | int __radix_tree_create(struct radix_tree_root *root, unsigned long index, |
398 | unsigned long index, void *item) | 380 | struct radix_tree_node **nodep, void ***slotp) |
399 | { | 381 | { |
400 | struct radix_tree_node *node = NULL, *slot; | 382 | struct radix_tree_node *node = NULL, *slot; |
401 | unsigned int height, shift; | 383 | unsigned int height, shift, offset; |
402 | int offset; | ||
403 | int error; | 384 | int error; |
404 | 385 | ||
405 | BUG_ON(radix_tree_is_indirect_ptr(item)); | ||
406 | |||
407 | /* Make sure the tree is high enough. */ | 386 | /* Make sure the tree is high enough. */ |
408 | if (index > radix_tree_maxindex(root->height)) { | 387 | if (index > radix_tree_maxindex(root->height)) { |
409 | error = radix_tree_extend(root, index); | 388 | error = radix_tree_extend(root, index); |
@@ -422,11 +401,12 @@ int radix_tree_insert(struct radix_tree_root *root, | |||
422 | /* Have to add a child node. */ | 401 | /* Have to add a child node. */ |
423 | if (!(slot = radix_tree_node_alloc(root))) | 402 | if (!(slot = radix_tree_node_alloc(root))) |
424 | return -ENOMEM; | 403 | return -ENOMEM; |
425 | slot->height = height; | 404 | slot->path = height; |
426 | slot->parent = node; | 405 | slot->parent = node; |
427 | if (node) { | 406 | if (node) { |
428 | rcu_assign_pointer(node->slots[offset], slot); | 407 | rcu_assign_pointer(node->slots[offset], slot); |
429 | node->count++; | 408 | node->count++; |
409 | slot->path |= offset << RADIX_TREE_HEIGHT_SHIFT; | ||
430 | } else | 410 | } else |
431 | rcu_assign_pointer(root->rnode, ptr_to_indirect(slot)); | 411 | rcu_assign_pointer(root->rnode, ptr_to_indirect(slot)); |
432 | } | 412 | } |
@@ -439,16 +419,42 @@ int radix_tree_insert(struct radix_tree_root *root, | |||
439 | height--; | 419 | height--; |
440 | } | 420 | } |
441 | 421 | ||
442 | if (slot != NULL) | 422 | if (nodep) |
423 | *nodep = node; | ||
424 | if (slotp) | ||
425 | *slotp = node ? node->slots + offset : (void **)&root->rnode; | ||
426 | return 0; | ||
427 | } | ||
428 | |||
429 | /** | ||
430 | * radix_tree_insert - insert into a radix tree | ||
431 | * @root: radix tree root | ||
432 | * @index: index key | ||
433 | * @item: item to insert | ||
434 | * | ||
435 | * Insert an item into the radix tree at position @index. | ||
436 | */ | ||
437 | int radix_tree_insert(struct radix_tree_root *root, | ||
438 | unsigned long index, void *item) | ||
439 | { | ||
440 | struct radix_tree_node *node; | ||
441 | void **slot; | ||
442 | int error; | ||
443 | |||
444 | BUG_ON(radix_tree_is_indirect_ptr(item)); | ||
445 | |||
446 | error = __radix_tree_create(root, index, &node, &slot); | ||
447 | if (error) | ||
448 | return error; | ||
449 | if (*slot != NULL) | ||
443 | return -EEXIST; | 450 | return -EEXIST; |
451 | rcu_assign_pointer(*slot, item); | ||
444 | 452 | ||
445 | if (node) { | 453 | if (node) { |
446 | node->count++; | 454 | node->count++; |
447 | rcu_assign_pointer(node->slots[offset], item); | 455 | BUG_ON(tag_get(node, 0, index & RADIX_TREE_MAP_MASK)); |
448 | BUG_ON(tag_get(node, 0, offset)); | 456 | BUG_ON(tag_get(node, 1, index & RADIX_TREE_MAP_MASK)); |
449 | BUG_ON(tag_get(node, 1, offset)); | ||
450 | } else { | 457 | } else { |
451 | rcu_assign_pointer(root->rnode, item); | ||
452 | BUG_ON(root_tag_get(root, 0)); | 458 | BUG_ON(root_tag_get(root, 0)); |
453 | BUG_ON(root_tag_get(root, 1)); | 459 | BUG_ON(root_tag_get(root, 1)); |
454 | } | 460 | } |
@@ -457,15 +463,26 @@ int radix_tree_insert(struct radix_tree_root *root, | |||
457 | } | 463 | } |
458 | EXPORT_SYMBOL(radix_tree_insert); | 464 | EXPORT_SYMBOL(radix_tree_insert); |
459 | 465 | ||
460 | /* | 466 | /** |
461 | * is_slot == 1 : search for the slot. | 467 | * __radix_tree_lookup - lookup an item in a radix tree |
462 | * is_slot == 0 : search for the node. | 468 | * @root: radix tree root |
469 | * @index: index key | ||
470 | * @nodep: returns node | ||
471 | * @slotp: returns slot | ||
472 | * | ||
473 | * Lookup and return the item at position @index in the radix | ||
474 | * tree @root. | ||
475 | * | ||
476 | * Until there is more than one item in the tree, no nodes are | ||
477 | * allocated and @root->rnode is used as a direct slot instead of | ||
478 | * pointing to a node, in which case *@nodep will be NULL. | ||
463 | */ | 479 | */ |
464 | static void *radix_tree_lookup_element(struct radix_tree_root *root, | 480 | void *__radix_tree_lookup(struct radix_tree_root *root, unsigned long index, |
465 | unsigned long index, int is_slot) | 481 | struct radix_tree_node **nodep, void ***slotp) |
466 | { | 482 | { |
483 | struct radix_tree_node *node, *parent; | ||
467 | unsigned int height, shift; | 484 | unsigned int height, shift; |
468 | struct radix_tree_node *node, **slot; | 485 | void **slot; |
469 | 486 | ||
470 | node = rcu_dereference_raw(root->rnode); | 487 | node = rcu_dereference_raw(root->rnode); |
471 | if (node == NULL) | 488 | if (node == NULL) |
@@ -474,19 +491,24 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root, | |||
474 | if (!radix_tree_is_indirect_ptr(node)) { | 491 | if (!radix_tree_is_indirect_ptr(node)) { |
475 | if (index > 0) | 492 | if (index > 0) |
476 | return NULL; | 493 | return NULL; |
477 | return is_slot ? (void *)&root->rnode : node; | 494 | |
495 | if (nodep) | ||
496 | *nodep = NULL; | ||
497 | if (slotp) | ||
498 | *slotp = (void **)&root->rnode; | ||
499 | return node; | ||
478 | } | 500 | } |
479 | node = indirect_to_ptr(node); | 501 | node = indirect_to_ptr(node); |
480 | 502 | ||
481 | height = node->height; | 503 | height = node->path & RADIX_TREE_HEIGHT_MASK; |
482 | if (index > radix_tree_maxindex(height)) | 504 | if (index > radix_tree_maxindex(height)) |
483 | return NULL; | 505 | return NULL; |
484 | 506 | ||
485 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | 507 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; |
486 | 508 | ||
487 | do { | 509 | do { |
488 | slot = (struct radix_tree_node **) | 510 | parent = node; |
489 | (node->slots + ((index>>shift) & RADIX_TREE_MAP_MASK)); | 511 | slot = node->slots + ((index >> shift) & RADIX_TREE_MAP_MASK); |
490 | node = rcu_dereference_raw(*slot); | 512 | node = rcu_dereference_raw(*slot); |
491 | if (node == NULL) | 513 | if (node == NULL) |
492 | return NULL; | 514 | return NULL; |
@@ -495,7 +517,11 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root, | |||
495 | height--; | 517 | height--; |
496 | } while (height > 0); | 518 | } while (height > 0); |
497 | 519 | ||
498 | return is_slot ? (void *)slot : indirect_to_ptr(node); | 520 | if (nodep) |
521 | *nodep = parent; | ||
522 | if (slotp) | ||
523 | *slotp = slot; | ||
524 | return node; | ||
499 | } | 525 | } |
500 | 526 | ||
501 | /** | 527 | /** |
@@ -513,7 +539,11 @@ static void *radix_tree_lookup_element(struct radix_tree_root *root, | |||
513 | */ | 539 | */ |
514 | void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) | 540 | void **radix_tree_lookup_slot(struct radix_tree_root *root, unsigned long index) |
515 | { | 541 | { |
516 | return (void **)radix_tree_lookup_element(root, index, 1); | 542 | void **slot; |
543 | |||
544 | if (!__radix_tree_lookup(root, index, NULL, &slot)) | ||
545 | return NULL; | ||
546 | return slot; | ||
517 | } | 547 | } |
518 | EXPORT_SYMBOL(radix_tree_lookup_slot); | 548 | EXPORT_SYMBOL(radix_tree_lookup_slot); |
519 | 549 | ||
@@ -531,7 +561,7 @@ EXPORT_SYMBOL(radix_tree_lookup_slot); | |||
531 | */ | 561 | */ |
532 | void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) | 562 | void *radix_tree_lookup(struct radix_tree_root *root, unsigned long index) |
533 | { | 563 | { |
534 | return radix_tree_lookup_element(root, index, 0); | 564 | return __radix_tree_lookup(root, index, NULL, NULL); |
535 | } | 565 | } |
536 | EXPORT_SYMBOL(radix_tree_lookup); | 566 | EXPORT_SYMBOL(radix_tree_lookup); |
537 | 567 | ||
@@ -676,7 +706,7 @@ int radix_tree_tag_get(struct radix_tree_root *root, | |||
676 | return (index == 0); | 706 | return (index == 0); |
677 | node = indirect_to_ptr(node); | 707 | node = indirect_to_ptr(node); |
678 | 708 | ||
679 | height = node->height; | 709 | height = node->path & RADIX_TREE_HEIGHT_MASK; |
680 | if (index > radix_tree_maxindex(height)) | 710 | if (index > radix_tree_maxindex(height)) |
681 | return 0; | 711 | return 0; |
682 | 712 | ||
@@ -713,7 +743,7 @@ void **radix_tree_next_chunk(struct radix_tree_root *root, | |||
713 | { | 743 | { |
714 | unsigned shift, tag = flags & RADIX_TREE_ITER_TAG_MASK; | 744 | unsigned shift, tag = flags & RADIX_TREE_ITER_TAG_MASK; |
715 | struct radix_tree_node *rnode, *node; | 745 | struct radix_tree_node *rnode, *node; |
716 | unsigned long index, offset; | 746 | unsigned long index, offset, height; |
717 | 747 | ||
718 | if ((flags & RADIX_TREE_ITER_TAGGED) && !root_tag_get(root, tag)) | 748 | if ((flags & RADIX_TREE_ITER_TAGGED) && !root_tag_get(root, tag)) |
719 | return NULL; | 749 | return NULL; |
@@ -744,7 +774,8 @@ void **radix_tree_next_chunk(struct radix_tree_root *root, | |||
744 | return NULL; | 774 | return NULL; |
745 | 775 | ||
746 | restart: | 776 | restart: |
747 | shift = (rnode->height - 1) * RADIX_TREE_MAP_SHIFT; | 777 | height = rnode->path & RADIX_TREE_HEIGHT_MASK; |
778 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
748 | offset = index >> shift; | 779 | offset = index >> shift; |
749 | 780 | ||
750 | /* Index outside of the tree */ | 781 | /* Index outside of the tree */ |
@@ -946,81 +977,6 @@ next: | |||
946 | } | 977 | } |
947 | EXPORT_SYMBOL(radix_tree_range_tag_if_tagged); | 978 | EXPORT_SYMBOL(radix_tree_range_tag_if_tagged); |
948 | 979 | ||
949 | |||
950 | /** | ||
951 | * radix_tree_next_hole - find the next hole (not-present entry) | ||
952 | * @root: tree root | ||
953 | * @index: index key | ||
954 | * @max_scan: maximum range to search | ||
955 | * | ||
956 | * Search the set [index, min(index+max_scan-1, MAX_INDEX)] for the lowest | ||
957 | * indexed hole. | ||
958 | * | ||
959 | * Returns: the index of the hole if found, otherwise returns an index | ||
960 | * outside of the set specified (in which case 'return - index >= max_scan' | ||
961 | * will be true). In rare cases of index wrap-around, 0 will be returned. | ||
962 | * | ||
963 | * radix_tree_next_hole may be called under rcu_read_lock. However, like | ||
964 | * radix_tree_gang_lookup, this will not atomically search a snapshot of | ||
965 | * the tree at a single point in time. For example, if a hole is created | ||
966 | * at index 5, then subsequently a hole is created at index 10, | ||
967 | * radix_tree_next_hole covering both indexes may return 10 if called | ||
968 | * under rcu_read_lock. | ||
969 | */ | ||
970 | unsigned long radix_tree_next_hole(struct radix_tree_root *root, | ||
971 | unsigned long index, unsigned long max_scan) | ||
972 | { | ||
973 | unsigned long i; | ||
974 | |||
975 | for (i = 0; i < max_scan; i++) { | ||
976 | if (!radix_tree_lookup(root, index)) | ||
977 | break; | ||
978 | index++; | ||
979 | if (index == 0) | ||
980 | break; | ||
981 | } | ||
982 | |||
983 | return index; | ||
984 | } | ||
985 | EXPORT_SYMBOL(radix_tree_next_hole); | ||
986 | |||
987 | /** | ||
988 | * radix_tree_prev_hole - find the prev hole (not-present entry) | ||
989 | * @root: tree root | ||
990 | * @index: index key | ||
991 | * @max_scan: maximum range to search | ||
992 | * | ||
993 | * Search backwards in the range [max(index-max_scan+1, 0), index] | ||
994 | * for the first hole. | ||
995 | * | ||
996 | * Returns: the index of the hole if found, otherwise returns an index | ||
997 | * outside of the set specified (in which case 'index - return >= max_scan' | ||
998 | * will be true). In rare cases of wrap-around, ULONG_MAX will be returned. | ||
999 | * | ||
1000 | * radix_tree_next_hole may be called under rcu_read_lock. However, like | ||
1001 | * radix_tree_gang_lookup, this will not atomically search a snapshot of | ||
1002 | * the tree at a single point in time. For example, if a hole is created | ||
1003 | * at index 10, then subsequently a hole is created at index 5, | ||
1004 | * radix_tree_prev_hole covering both indexes may return 5 if called under | ||
1005 | * rcu_read_lock. | ||
1006 | */ | ||
1007 | unsigned long radix_tree_prev_hole(struct radix_tree_root *root, | ||
1008 | unsigned long index, unsigned long max_scan) | ||
1009 | { | ||
1010 | unsigned long i; | ||
1011 | |||
1012 | for (i = 0; i < max_scan; i++) { | ||
1013 | if (!radix_tree_lookup(root, index)) | ||
1014 | break; | ||
1015 | index--; | ||
1016 | if (index == ULONG_MAX) | ||
1017 | break; | ||
1018 | } | ||
1019 | |||
1020 | return index; | ||
1021 | } | ||
1022 | EXPORT_SYMBOL(radix_tree_prev_hole); | ||
1023 | |||
1024 | /** | 980 | /** |
1025 | * radix_tree_gang_lookup - perform multiple lookup on a radix tree | 981 | * radix_tree_gang_lookup - perform multiple lookup on a radix tree |
1026 | * @root: radix tree root | 982 | * @root: radix tree root |
@@ -1189,7 +1145,7 @@ static unsigned long __locate(struct radix_tree_node *slot, void *item, | |||
1189 | unsigned int shift, height; | 1145 | unsigned int shift, height; |
1190 | unsigned long i; | 1146 | unsigned long i; |
1191 | 1147 | ||
1192 | height = slot->height; | 1148 | height = slot->path & RADIX_TREE_HEIGHT_MASK; |
1193 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | 1149 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; |
1194 | 1150 | ||
1195 | for ( ; height > 1; height--) { | 1151 | for ( ; height > 1; height--) { |
@@ -1252,7 +1208,8 @@ unsigned long radix_tree_locate_item(struct radix_tree_root *root, void *item) | |||
1252 | } | 1208 | } |
1253 | 1209 | ||
1254 | node = indirect_to_ptr(node); | 1210 | node = indirect_to_ptr(node); |
1255 | max_index = radix_tree_maxindex(node->height); | 1211 | max_index = radix_tree_maxindex(node->path & |
1212 | RADIX_TREE_HEIGHT_MASK); | ||
1256 | if (cur_index > max_index) { | 1213 | if (cur_index > max_index) { |
1257 | rcu_read_unlock(); | 1214 | rcu_read_unlock(); |
1258 | break; | 1215 | break; |
@@ -1337,48 +1294,90 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) | |||
1337 | } | 1294 | } |
1338 | 1295 | ||
1339 | /** | 1296 | /** |
1340 | * radix_tree_delete - delete an item from a radix tree | 1297 | * __radix_tree_delete_node - try to free node after clearing a slot |
1341 | * @root: radix tree root | 1298 | * @root: radix tree root |
1342 | * @index: index key | 1299 | * @index: index key |
1300 | * @node: node containing @index | ||
1343 | * | 1301 | * |
1344 | * Remove the item at @index from the radix tree rooted at @root. | 1302 | * After clearing the slot at @index in @node from radix tree |
1303 | * rooted at @root, call this function to attempt freeing the | ||
1304 | * node and shrinking the tree. | ||
1345 | * | 1305 | * |
1346 | * Returns the address of the deleted item, or NULL if it was not present. | 1306 | * Returns %true if @node was freed, %false otherwise. |
1347 | */ | 1307 | */ |
1348 | void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | 1308 | bool __radix_tree_delete_node(struct radix_tree_root *root, |
1309 | struct radix_tree_node *node) | ||
1349 | { | 1310 | { |
1350 | struct radix_tree_node *node = NULL; | 1311 | bool deleted = false; |
1351 | struct radix_tree_node *slot = NULL; | 1312 | |
1352 | struct radix_tree_node *to_free; | 1313 | do { |
1353 | unsigned int height, shift; | 1314 | struct radix_tree_node *parent; |
1315 | |||
1316 | if (node->count) { | ||
1317 | if (node == indirect_to_ptr(root->rnode)) { | ||
1318 | radix_tree_shrink(root); | ||
1319 | if (root->height == 0) | ||
1320 | deleted = true; | ||
1321 | } | ||
1322 | return deleted; | ||
1323 | } | ||
1324 | |||
1325 | parent = node->parent; | ||
1326 | if (parent) { | ||
1327 | unsigned int offset; | ||
1328 | |||
1329 | offset = node->path >> RADIX_TREE_HEIGHT_SHIFT; | ||
1330 | parent->slots[offset] = NULL; | ||
1331 | parent->count--; | ||
1332 | } else { | ||
1333 | root_tag_clear_all(root); | ||
1334 | root->height = 0; | ||
1335 | root->rnode = NULL; | ||
1336 | } | ||
1337 | |||
1338 | radix_tree_node_free(node); | ||
1339 | deleted = true; | ||
1340 | |||
1341 | node = parent; | ||
1342 | } while (node); | ||
1343 | |||
1344 | return deleted; | ||
1345 | } | ||
1346 | |||
1347 | /** | ||
1348 | * radix_tree_delete_item - delete an item from a radix tree | ||
1349 | * @root: radix tree root | ||
1350 | * @index: index key | ||
1351 | * @item: expected item | ||
1352 | * | ||
1353 | * Remove @item at @index from the radix tree rooted at @root. | ||
1354 | * | ||
1355 | * Returns the address of the deleted item, or NULL if it was not present | ||
1356 | * or the entry at the given @index was not @item. | ||
1357 | */ | ||
1358 | void *radix_tree_delete_item(struct radix_tree_root *root, | ||
1359 | unsigned long index, void *item) | ||
1360 | { | ||
1361 | struct radix_tree_node *node; | ||
1362 | unsigned int offset; | ||
1363 | void **slot; | ||
1364 | void *entry; | ||
1354 | int tag; | 1365 | int tag; |
1355 | int uninitialized_var(offset); | ||
1356 | 1366 | ||
1357 | height = root->height; | 1367 | entry = __radix_tree_lookup(root, index, &node, &slot); |
1358 | if (index > radix_tree_maxindex(height)) | 1368 | if (!entry) |
1359 | goto out; | 1369 | return NULL; |
1360 | 1370 | ||
1361 | slot = root->rnode; | 1371 | if (item && entry != item) |
1362 | if (height == 0) { | 1372 | return NULL; |
1373 | |||
1374 | if (!node) { | ||
1363 | root_tag_clear_all(root); | 1375 | root_tag_clear_all(root); |
1364 | root->rnode = NULL; | 1376 | root->rnode = NULL; |
1365 | goto out; | 1377 | return entry; |
1366 | } | 1378 | } |
1367 | slot = indirect_to_ptr(slot); | ||
1368 | shift = height * RADIX_TREE_MAP_SHIFT; | ||
1369 | 1379 | ||
1370 | do { | 1380 | offset = index & RADIX_TREE_MAP_MASK; |
1371 | if (slot == NULL) | ||
1372 | goto out; | ||
1373 | |||
1374 | shift -= RADIX_TREE_MAP_SHIFT; | ||
1375 | offset = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
1376 | node = slot; | ||
1377 | slot = slot->slots[offset]; | ||
1378 | } while (shift); | ||
1379 | |||
1380 | if (slot == NULL) | ||
1381 | goto out; | ||
1382 | 1381 | ||
1383 | /* | 1382 | /* |
1384 | * Clear all tags associated with the item to be deleted. | 1383 | * Clear all tags associated with the item to be deleted. |
@@ -1389,40 +1388,27 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | |||
1389 | radix_tree_tag_clear(root, index, tag); | 1388 | radix_tree_tag_clear(root, index, tag); |
1390 | } | 1389 | } |
1391 | 1390 | ||
1392 | to_free = NULL; | 1391 | node->slots[offset] = NULL; |
1393 | /* Now free the nodes we do not need anymore */ | 1392 | node->count--; |
1394 | while (node) { | ||
1395 | node->slots[offset] = NULL; | ||
1396 | node->count--; | ||
1397 | /* | ||
1398 | * Queue the node for deferred freeing after the | ||
1399 | * last reference to it disappears (set NULL, above). | ||
1400 | */ | ||
1401 | if (to_free) | ||
1402 | radix_tree_node_free(to_free); | ||
1403 | |||
1404 | if (node->count) { | ||
1405 | if (node == indirect_to_ptr(root->rnode)) | ||
1406 | radix_tree_shrink(root); | ||
1407 | goto out; | ||
1408 | } | ||
1409 | 1393 | ||
1410 | /* Node with zero slots in use so free it */ | 1394 | __radix_tree_delete_node(root, node); |
1411 | to_free = node; | ||
1412 | 1395 | ||
1413 | index >>= RADIX_TREE_MAP_SHIFT; | 1396 | return entry; |
1414 | offset = index & RADIX_TREE_MAP_MASK; | 1397 | } |
1415 | node = node->parent; | 1398 | EXPORT_SYMBOL(radix_tree_delete_item); |
1416 | } | ||
1417 | |||
1418 | root_tag_clear_all(root); | ||
1419 | root->height = 0; | ||
1420 | root->rnode = NULL; | ||
1421 | if (to_free) | ||
1422 | radix_tree_node_free(to_free); | ||
1423 | 1399 | ||
1424 | out: | 1400 | /** |
1425 | return slot; | 1401 | * radix_tree_delete - delete an item from a radix tree |
1402 | * @root: radix tree root | ||
1403 | * @index: index key | ||
1404 | * | ||
1405 | * Remove the item at @index from the radix tree rooted at @root. | ||
1406 | * | ||
1407 | * Returns the address of the deleted item, or NULL if it was not present. | ||
1408 | */ | ||
1409 | void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | ||
1410 | { | ||
1411 | return radix_tree_delete_item(root, index, NULL); | ||
1426 | } | 1412 | } |
1427 | EXPORT_SYMBOL(radix_tree_delete); | 1413 | EXPORT_SYMBOL(radix_tree_delete); |
1428 | 1414 | ||
@@ -1438,9 +1424,12 @@ int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) | |||
1438 | EXPORT_SYMBOL(radix_tree_tagged); | 1424 | EXPORT_SYMBOL(radix_tree_tagged); |
1439 | 1425 | ||
1440 | static void | 1426 | static void |
1441 | radix_tree_node_ctor(void *node) | 1427 | radix_tree_node_ctor(void *arg) |
1442 | { | 1428 | { |
1443 | memset(node, 0, sizeof(struct radix_tree_node)); | 1429 | struct radix_tree_node *node = arg; |
1430 | |||
1431 | memset(node, 0, sizeof(*node)); | ||
1432 | INIT_LIST_HEAD(&node->private_list); | ||
1444 | } | 1433 | } |
1445 | 1434 | ||
1446 | static __init unsigned long __maxindex(unsigned int height) | 1435 | static __init unsigned long __maxindex(unsigned int height) |