diff options
| author | Nick Piggin <npiggin@suse.de> | 2006-06-23 05:03:22 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@g5.osdl.org> | 2006-06-23 10:42:49 -0400 |
| commit | 612d6c19db2fd0dc97b0fa370613ecd4a305ffc3 (patch) | |
| tree | 3ab670895b5c3e389ff922192a572cbfd8159d03 /lib | |
| parent | 929f97276bcf7f4a95272ed08a85339b98ba210d (diff) | |
[PATCH] radix-tree: direct data
The ability to have height 0 radix trees (a direct pointer to the data item
rather than going through a full node->slot) quietly disappeared with
old-2.6-bkcvs commit ffee171812d51652f9ba284302d9e5c5cc14bdfd. On 64-bit
machines this causes nearly 600 bytes to be used for every <= 4K file in
pagecache.
Re-introduce this feature, root tags stored in spare ->gfp_mask bits.
Simplify radix_tree_delete's complex tag clearing arrangement (which would
become even more complex) by just falling back to tag clearing functions
(the pagecache radix-tree never uses this path anyway, so the icache
savings will mean it's actually a speedup).
On my 4GB G5, this saves 8MB RAM per kernel kernel source+object tree in
pagecache.
Pagecache lookup, insertion, and removal speed for small files will also be
improved.
This makes RCU radix tree harder, but it's worth it.
Signed-off-by: Nick Piggin <npiggin@suse.de>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'lib')
| -rw-r--r-- | lib/radix-tree.c | 192 |
1 files changed, 111 insertions, 81 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 7097bb239e40..35a2d93b3528 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
| @@ -74,6 +74,11 @@ struct radix_tree_preload { | |||
| 74 | }; | 74 | }; |
| 75 | DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; | 75 | DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; |
| 76 | 76 | ||
| 77 | static inline gfp_t root_gfp_mask(struct radix_tree_root *root) | ||
| 78 | { | ||
| 79 | return root->gfp_mask & __GFP_BITS_MASK; | ||
| 80 | } | ||
| 81 | |||
| 77 | /* | 82 | /* |
| 78 | * This assumes that the caller has performed appropriate preallocation, and | 83 | * This assumes that the caller has performed appropriate preallocation, and |
| 79 | * that the caller has pinned this thread of control to the current CPU. | 84 | * that the caller has pinned this thread of control to the current CPU. |
| @@ -82,9 +87,10 @@ static struct radix_tree_node * | |||
| 82 | radix_tree_node_alloc(struct radix_tree_root *root) | 87 | radix_tree_node_alloc(struct radix_tree_root *root) |
| 83 | { | 88 | { |
| 84 | struct radix_tree_node *ret; | 89 | struct radix_tree_node *ret; |
| 90 | gfp_t gfp_mask = root_gfp_mask(root); | ||
| 85 | 91 | ||
| 86 | ret = kmem_cache_alloc(radix_tree_node_cachep, root->gfp_mask); | 92 | ret = kmem_cache_alloc(radix_tree_node_cachep, gfp_mask); |
| 87 | if (ret == NULL && !(root->gfp_mask & __GFP_WAIT)) { | 93 | if (ret == NULL && !(gfp_mask & __GFP_WAIT)) { |
| 88 | struct radix_tree_preload *rtp; | 94 | struct radix_tree_preload *rtp; |
| 89 | 95 | ||
| 90 | rtp = &__get_cpu_var(radix_tree_preloads); | 96 | rtp = &__get_cpu_var(radix_tree_preloads); |
| @@ -152,6 +158,27 @@ static inline int tag_get(struct radix_tree_node *node, unsigned int tag, | |||
| 152 | return test_bit(offset, node->tags[tag]); | 158 | return test_bit(offset, node->tags[tag]); |
| 153 | } | 159 | } |
| 154 | 160 | ||
| 161 | static inline void root_tag_set(struct radix_tree_root *root, unsigned int tag) | ||
| 162 | { | ||
| 163 | root->gfp_mask |= (1 << (tag + __GFP_BITS_SHIFT)); | ||
| 164 | } | ||
| 165 | |||
| 166 | |||
| 167 | static inline void root_tag_clear(struct radix_tree_root *root, unsigned int tag) | ||
| 168 | { | ||
| 169 | root->gfp_mask &= ~(1 << (tag + __GFP_BITS_SHIFT)); | ||
| 170 | } | ||
| 171 | |||
| 172 | static inline void root_tag_clear_all(struct radix_tree_root *root) | ||
| 173 | { | ||
| 174 | root->gfp_mask &= __GFP_BITS_MASK; | ||
| 175 | } | ||
| 176 | |||
| 177 | static inline int root_tag_get(struct radix_tree_root *root, unsigned int tag) | ||
| 178 | { | ||
| 179 | return root->gfp_mask & (1 << (tag + __GFP_BITS_SHIFT)); | ||
| 180 | } | ||
| 181 | |||
| 155 | /* | 182 | /* |
| 156 | * Returns 1 if any slot in the node has this tag set. | 183 | * Returns 1 if any slot in the node has this tag set. |
| 157 | * Otherwise returns 0. | 184 | * Otherwise returns 0. |
| @@ -182,7 +209,6 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) | |||
| 182 | { | 209 | { |
| 183 | struct radix_tree_node *node; | 210 | struct radix_tree_node *node; |
| 184 | unsigned int height; | 211 | unsigned int height; |
| 185 | char tags[RADIX_TREE_MAX_TAGS]; | ||
| 186 | int tag; | 212 | int tag; |
| 187 | 213 | ||
| 188 | /* Figure out what the height should be. */ | 214 | /* Figure out what the height should be. */ |
| @@ -195,16 +221,6 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) | |||
| 195 | goto out; | 221 | goto out; |
| 196 | } | 222 | } |
| 197 | 223 | ||
| 198 | /* | ||
| 199 | * Prepare the tag status of the top-level node for propagation | ||
| 200 | * into the newly-pushed top-level node(s) | ||
| 201 | */ | ||
| 202 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { | ||
| 203 | tags[tag] = 0; | ||
| 204 | if (any_tag_set(root->rnode, tag)) | ||
| 205 | tags[tag] = 1; | ||
| 206 | } | ||
| 207 | |||
| 208 | do { | 224 | do { |
| 209 | if (!(node = radix_tree_node_alloc(root))) | 225 | if (!(node = radix_tree_node_alloc(root))) |
| 210 | return -ENOMEM; | 226 | return -ENOMEM; |
| @@ -214,7 +230,7 @@ static int radix_tree_extend(struct radix_tree_root *root, unsigned long index) | |||
| 214 | 230 | ||
| 215 | /* Propagate the aggregated tag info into the new root */ | 231 | /* Propagate the aggregated tag info into the new root */ |
| 216 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { | 232 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { |
| 217 | if (tags[tag]) | 233 | if (root_tag_get(root, tag)) |
| 218 | tag_set(node, tag, 0); | 234 | tag_set(node, tag, 0); |
| 219 | } | 235 | } |
| 220 | 236 | ||
| @@ -243,8 +259,7 @@ int radix_tree_insert(struct radix_tree_root *root, | |||
| 243 | int error; | 259 | int error; |
| 244 | 260 | ||
| 245 | /* Make sure the tree is high enough. */ | 261 | /* Make sure the tree is high enough. */ |
| 246 | if ((!index && !root->rnode) || | 262 | if (index > radix_tree_maxindex(root->height)) { |
| 247 | index > radix_tree_maxindex(root->height)) { | ||
| 248 | error = radix_tree_extend(root, index); | 263 | error = radix_tree_extend(root, index); |
| 249 | if (error) | 264 | if (error) |
| 250 | return error; | 265 | return error; |
| @@ -255,7 +270,7 @@ int radix_tree_insert(struct radix_tree_root *root, | |||
| 255 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | 270 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; |
| 256 | 271 | ||
| 257 | offset = 0; /* uninitialised var warning */ | 272 | offset = 0; /* uninitialised var warning */ |
| 258 | do { | 273 | while (height > 0) { |
| 259 | if (slot == NULL) { | 274 | if (slot == NULL) { |
| 260 | /* Have to add a child node. */ | 275 | /* Have to add a child node. */ |
| 261 | if (!(slot = radix_tree_node_alloc(root))) | 276 | if (!(slot = radix_tree_node_alloc(root))) |
| @@ -273,16 +288,21 @@ int radix_tree_insert(struct radix_tree_root *root, | |||
| 273 | slot = node->slots[offset]; | 288 | slot = node->slots[offset]; |
| 274 | shift -= RADIX_TREE_MAP_SHIFT; | 289 | shift -= RADIX_TREE_MAP_SHIFT; |
| 275 | height--; | 290 | height--; |
| 276 | } while (height > 0); | 291 | } |
| 277 | 292 | ||
| 278 | if (slot != NULL) | 293 | if (slot != NULL) |
| 279 | return -EEXIST; | 294 | return -EEXIST; |
| 280 | 295 | ||
| 281 | BUG_ON(!node); | 296 | if (node) { |
| 282 | node->count++; | 297 | node->count++; |
| 283 | node->slots[offset] = item; | 298 | node->slots[offset] = item; |
| 284 | BUG_ON(tag_get(node, 0, offset)); | 299 | BUG_ON(tag_get(node, 0, offset)); |
| 285 | BUG_ON(tag_get(node, 1, offset)); | 300 | BUG_ON(tag_get(node, 1, offset)); |
| 301 | } else { | ||
| 302 | root->rnode = item; | ||
| 303 | BUG_ON(root_tag_get(root, 0)); | ||
| 304 | BUG_ON(root_tag_get(root, 1)); | ||
| 305 | } | ||
| 286 | 306 | ||
| 287 | return 0; | 307 | return 0; |
| 288 | } | 308 | } |
| @@ -295,9 +315,13 @@ static inline void **__lookup_slot(struct radix_tree_root *root, | |||
| 295 | struct radix_tree_node **slot; | 315 | struct radix_tree_node **slot; |
| 296 | 316 | ||
| 297 | height = root->height; | 317 | height = root->height; |
| 318 | |||
| 298 | if (index > radix_tree_maxindex(height)) | 319 | if (index > radix_tree_maxindex(height)) |
| 299 | return NULL; | 320 | return NULL; |
| 300 | 321 | ||
| 322 | if (height == 0 && root->rnode) | ||
| 323 | return (void **)&root->rnode; | ||
| 324 | |||
| 301 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | 325 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; |
| 302 | slot = &root->rnode; | 326 | slot = &root->rnode; |
| 303 | 327 | ||
| @@ -368,8 +392,8 @@ void *radix_tree_tag_set(struct radix_tree_root *root, | |||
| 368 | if (index > radix_tree_maxindex(height)) | 392 | if (index > radix_tree_maxindex(height)) |
| 369 | return NULL; | 393 | return NULL; |
| 370 | 394 | ||
| 371 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
| 372 | slot = root->rnode; | 395 | slot = root->rnode; |
| 396 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
| 373 | 397 | ||
| 374 | while (height > 0) { | 398 | while (height > 0) { |
| 375 | int offset; | 399 | int offset; |
| @@ -383,6 +407,10 @@ void *radix_tree_tag_set(struct radix_tree_root *root, | |||
| 383 | height--; | 407 | height--; |
| 384 | } | 408 | } |
| 385 | 409 | ||
| 410 | /* set the root's tag bit */ | ||
| 411 | if (slot && !root_tag_get(root, tag)) | ||
| 412 | root_tag_set(root, tag); | ||
| 413 | |||
| 386 | return slot; | 414 | return slot; |
| 387 | } | 415 | } |
| 388 | EXPORT_SYMBOL(radix_tree_tag_set); | 416 | EXPORT_SYMBOL(radix_tree_tag_set); |
| @@ -405,9 +433,8 @@ void *radix_tree_tag_clear(struct radix_tree_root *root, | |||
| 405 | unsigned long index, unsigned int tag) | 433 | unsigned long index, unsigned int tag) |
| 406 | { | 434 | { |
| 407 | struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; | 435 | struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; |
| 408 | struct radix_tree_node *slot; | 436 | struct radix_tree_node *slot = NULL; |
| 409 | unsigned int height, shift; | 437 | unsigned int height, shift; |
| 410 | void *ret = NULL; | ||
| 411 | 438 | ||
| 412 | height = root->height; | 439 | height = root->height; |
| 413 | if (index > radix_tree_maxindex(height)) | 440 | if (index > radix_tree_maxindex(height)) |
| @@ -432,20 +459,24 @@ void *radix_tree_tag_clear(struct radix_tree_root *root, | |||
| 432 | height--; | 459 | height--; |
| 433 | } | 460 | } |
| 434 | 461 | ||
| 435 | ret = slot; | 462 | if (slot == NULL) |
| 436 | if (ret == NULL) | ||
| 437 | goto out; | 463 | goto out; |
| 438 | 464 | ||
| 439 | do { | 465 | while (pathp->node) { |
| 440 | if (!tag_get(pathp->node, tag, pathp->offset)) | 466 | if (!tag_get(pathp->node, tag, pathp->offset)) |
| 441 | goto out; | 467 | goto out; |
| 442 | tag_clear(pathp->node, tag, pathp->offset); | 468 | tag_clear(pathp->node, tag, pathp->offset); |
| 443 | if (any_tag_set(pathp->node, tag)) | 469 | if (any_tag_set(pathp->node, tag)) |
| 444 | goto out; | 470 | goto out; |
| 445 | pathp--; | 471 | pathp--; |
| 446 | } while (pathp->node); | 472 | } |
| 473 | |||
| 474 | /* clear the root's tag bit */ | ||
| 475 | if (root_tag_get(root, tag)) | ||
| 476 | root_tag_clear(root, tag); | ||
| 477 | |||
| 447 | out: | 478 | out: |
| 448 | return ret; | 479 | return slot; |
| 449 | } | 480 | } |
| 450 | EXPORT_SYMBOL(radix_tree_tag_clear); | 481 | EXPORT_SYMBOL(radix_tree_tag_clear); |
| 451 | 482 | ||
| @@ -458,9 +489,8 @@ EXPORT_SYMBOL(radix_tree_tag_clear); | |||
| 458 | * | 489 | * |
| 459 | * Return values: | 490 | * Return values: |
| 460 | * | 491 | * |
| 461 | * 0: tag not present | 492 | * 0: tag not present or not set |
| 462 | * 1: tag present, set | 493 | * 1: tag set |
| 463 | * -1: tag present, unset | ||
| 464 | */ | 494 | */ |
| 465 | int radix_tree_tag_get(struct radix_tree_root *root, | 495 | int radix_tree_tag_get(struct radix_tree_root *root, |
| 466 | unsigned long index, unsigned int tag) | 496 | unsigned long index, unsigned int tag) |
| @@ -473,6 +503,13 @@ int radix_tree_tag_get(struct radix_tree_root *root, | |||
| 473 | if (index > radix_tree_maxindex(height)) | 503 | if (index > radix_tree_maxindex(height)) |
| 474 | return 0; | 504 | return 0; |
| 475 | 505 | ||
| 506 | /* check the root's tag bit */ | ||
| 507 | if (!root_tag_get(root, tag)) | ||
| 508 | return 0; | ||
| 509 | |||
| 510 | if (height == 0) | ||
| 511 | return 1; | ||
| 512 | |||
| 476 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | 513 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; |
| 477 | slot = root->rnode; | 514 | slot = root->rnode; |
| 478 | 515 | ||
| @@ -494,7 +531,7 @@ int radix_tree_tag_get(struct radix_tree_root *root, | |||
| 494 | int ret = tag_get(slot, tag, offset); | 531 | int ret = tag_get(slot, tag, offset); |
| 495 | 532 | ||
| 496 | BUG_ON(ret && saw_unset_tag); | 533 | BUG_ON(ret && saw_unset_tag); |
| 497 | return ret ? 1 : -1; | 534 | return ret; |
| 498 | } | 535 | } |
| 499 | slot = slot->slots[offset]; | 536 | slot = slot->slots[offset]; |
| 500 | shift -= RADIX_TREE_MAP_SHIFT; | 537 | shift -= RADIX_TREE_MAP_SHIFT; |
| @@ -514,8 +551,11 @@ __lookup(struct radix_tree_root *root, void **results, unsigned long index, | |||
| 514 | unsigned long i; | 551 | unsigned long i; |
| 515 | 552 | ||
| 516 | height = root->height; | 553 | height = root->height; |
| 517 | if (height == 0) | 554 | if (height == 0) { |
| 555 | if (root->rnode && index == 0) | ||
| 556 | results[nr_found++] = root->rnode; | ||
| 518 | goto out; | 557 | goto out; |
| 558 | } | ||
| 519 | 559 | ||
| 520 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; | 560 | shift = (height-1) * RADIX_TREE_MAP_SHIFT; |
| 521 | slot = root->rnode; | 561 | slot = root->rnode; |
| @@ -603,10 +643,16 @@ __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, | |||
| 603 | unsigned int height = root->height; | 643 | unsigned int height = root->height; |
| 604 | struct radix_tree_node *slot; | 644 | struct radix_tree_node *slot; |
| 605 | 645 | ||
| 646 | if (height == 0) { | ||
| 647 | if (root->rnode && index == 0) | ||
| 648 | results[nr_found++] = root->rnode; | ||
| 649 | goto out; | ||
| 650 | } | ||
| 651 | |||
| 606 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | 652 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; |
| 607 | slot = root->rnode; | 653 | slot = root->rnode; |
| 608 | 654 | ||
| 609 | while (height > 0) { | 655 | do { |
| 610 | unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; | 656 | unsigned long i = (index >> shift) & RADIX_TREE_MAP_MASK; |
| 611 | 657 | ||
| 612 | for ( ; i < RADIX_TREE_MAP_SIZE; i++) { | 658 | for ( ; i < RADIX_TREE_MAP_SIZE; i++) { |
| @@ -637,7 +683,7 @@ __lookup_tag(struct radix_tree_root *root, void **results, unsigned long index, | |||
| 637 | } | 683 | } |
| 638 | shift -= RADIX_TREE_MAP_SHIFT; | 684 | shift -= RADIX_TREE_MAP_SHIFT; |
| 639 | slot = slot->slots[i]; | 685 | slot = slot->slots[i]; |
| 640 | } | 686 | } while (height > 0); |
| 641 | out: | 687 | out: |
| 642 | *next_index = index; | 688 | *next_index = index; |
| 643 | return nr_found; | 689 | return nr_found; |
| @@ -665,6 +711,10 @@ radix_tree_gang_lookup_tag(struct radix_tree_root *root, void **results, | |||
| 665 | unsigned long cur_index = first_index; | 711 | unsigned long cur_index = first_index; |
| 666 | unsigned int ret = 0; | 712 | unsigned int ret = 0; |
| 667 | 713 | ||
| 714 | /* check the root's tag bit */ | ||
| 715 | if (!root_tag_get(root, tag)) | ||
| 716 | return 0; | ||
| 717 | |||
| 668 | while (ret < max_items) { | 718 | while (ret < max_items) { |
| 669 | unsigned int nr_found; | 719 | unsigned int nr_found; |
| 670 | unsigned long next_index; /* Index of next search */ | 720 | unsigned long next_index; /* Index of next search */ |
| @@ -689,7 +739,7 @@ EXPORT_SYMBOL(radix_tree_gang_lookup_tag); | |||
| 689 | static inline void radix_tree_shrink(struct radix_tree_root *root) | 739 | static inline void radix_tree_shrink(struct radix_tree_root *root) |
| 690 | { | 740 | { |
| 691 | /* try to shrink tree height */ | 741 | /* try to shrink tree height */ |
| 692 | while (root->height > 1 && | 742 | while (root->height > 0 && |
| 693 | root->rnode->count == 1 && | 743 | root->rnode->count == 1 && |
| 694 | root->rnode->slots[0]) { | 744 | root->rnode->slots[0]) { |
| 695 | struct radix_tree_node *to_free = root->rnode; | 745 | struct radix_tree_node *to_free = root->rnode; |
| @@ -717,12 +767,8 @@ static inline void radix_tree_shrink(struct radix_tree_root *root) | |||
| 717 | void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | 767 | void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) |
| 718 | { | 768 | { |
| 719 | struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; | 769 | struct radix_tree_path path[RADIX_TREE_MAX_PATH], *pathp = path; |
| 720 | struct radix_tree_path *orig_pathp; | 770 | struct radix_tree_node *slot = NULL; |
| 721 | struct radix_tree_node *slot; | ||
| 722 | unsigned int height, shift; | 771 | unsigned int height, shift; |
| 723 | void *ret = NULL; | ||
| 724 | char tags[RADIX_TREE_MAX_TAGS]; | ||
| 725 | int nr_cleared_tags; | ||
| 726 | int tag; | 772 | int tag; |
| 727 | int offset; | 773 | int offset; |
| 728 | 774 | ||
| @@ -730,11 +776,17 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | |||
| 730 | if (index > radix_tree_maxindex(height)) | 776 | if (index > radix_tree_maxindex(height)) |
| 731 | goto out; | 777 | goto out; |
| 732 | 778 | ||
| 779 | slot = root->rnode; | ||
| 780 | if (height == 0 && root->rnode) { | ||
| 781 | root_tag_clear_all(root); | ||
| 782 | root->rnode = NULL; | ||
| 783 | goto out; | ||
| 784 | } | ||
| 785 | |||
| 733 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | 786 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; |
| 734 | pathp->node = NULL; | 787 | pathp->node = NULL; |
| 735 | slot = root->rnode; | ||
| 736 | 788 | ||
| 737 | for ( ; height > 0; height--) { | 789 | do { |
| 738 | if (slot == NULL) | 790 | if (slot == NULL) |
| 739 | goto out; | 791 | goto out; |
| 740 | 792 | ||
| @@ -744,44 +796,22 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | |||
| 744 | pathp->node = slot; | 796 | pathp->node = slot; |
| 745 | slot = slot->slots[offset]; | 797 | slot = slot->slots[offset]; |
| 746 | shift -= RADIX_TREE_MAP_SHIFT; | 798 | shift -= RADIX_TREE_MAP_SHIFT; |
| 747 | } | 799 | height--; |
| 800 | } while (height > 0); | ||
| 748 | 801 | ||
| 749 | ret = slot; | 802 | if (slot == NULL) |
| 750 | if (ret == NULL) | ||
| 751 | goto out; | 803 | goto out; |
| 752 | 804 | ||
| 753 | orig_pathp = pathp; | ||
| 754 | |||
| 755 | /* | 805 | /* |
| 756 | * Clear all tags associated with the just-deleted item | 806 | * Clear all tags associated with the just-deleted item |
| 757 | */ | 807 | */ |
| 758 | nr_cleared_tags = 0; | ||
| 759 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { | 808 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { |
| 760 | tags[tag] = 1; | 809 | if (tag_get(pathp->node, tag, pathp->offset)) |
| 761 | if (tag_get(pathp->node, tag, pathp->offset)) { | 810 | radix_tree_tag_clear(root, index, tag); |
| 762 | tag_clear(pathp->node, tag, pathp->offset); | ||
| 763 | if (!any_tag_set(pathp->node, tag)) { | ||
| 764 | tags[tag] = 0; | ||
| 765 | nr_cleared_tags++; | ||
| 766 | } | ||
| 767 | } | ||
| 768 | } | ||
| 769 | |||
| 770 | for (pathp--; nr_cleared_tags && pathp->node; pathp--) { | ||
| 771 | for (tag = 0; tag < RADIX_TREE_MAX_TAGS; tag++) { | ||
| 772 | if (tags[tag]) | ||
| 773 | continue; | ||
| 774 | |||
| 775 | tag_clear(pathp->node, tag, pathp->offset); | ||
| 776 | if (any_tag_set(pathp->node, tag)) { | ||
| 777 | tags[tag] = 1; | ||
| 778 | nr_cleared_tags--; | ||
| 779 | } | ||
| 780 | } | ||
| 781 | } | 811 | } |
| 782 | 812 | ||
| 783 | /* Now free the nodes we do not need anymore */ | 813 | /* Now free the nodes we do not need anymore */ |
| 784 | for (pathp = orig_pathp; pathp->node; pathp--) { | 814 | while (pathp->node) { |
| 785 | pathp->node->slots[pathp->offset] = NULL; | 815 | pathp->node->slots[pathp->offset] = NULL; |
| 786 | pathp->node->count--; | 816 | pathp->node->count--; |
| 787 | 817 | ||
| @@ -793,11 +823,15 @@ void *radix_tree_delete(struct radix_tree_root *root, unsigned long index) | |||
| 793 | 823 | ||
| 794 | /* Node with zero slots in use so free it */ | 824 | /* Node with zero slots in use so free it */ |
| 795 | radix_tree_node_free(pathp->node); | 825 | radix_tree_node_free(pathp->node); |
| 826 | |||
| 827 | pathp--; | ||
| 796 | } | 828 | } |
| 797 | root->rnode = NULL; | 829 | root_tag_clear_all(root); |
| 798 | root->height = 0; | 830 | root->height = 0; |
| 831 | root->rnode = NULL; | ||
| 832 | |||
| 799 | out: | 833 | out: |
| 800 | return ret; | 834 | return slot; |
| 801 | } | 835 | } |
| 802 | EXPORT_SYMBOL(radix_tree_delete); | 836 | EXPORT_SYMBOL(radix_tree_delete); |
| 803 | 837 | ||
| @@ -808,11 +842,7 @@ EXPORT_SYMBOL(radix_tree_delete); | |||
| 808 | */ | 842 | */ |
| 809 | int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) | 843 | int radix_tree_tagged(struct radix_tree_root *root, unsigned int tag) |
| 810 | { | 844 | { |
| 811 | struct radix_tree_node *rnode; | 845 | return root_tag_get(root, tag); |
| 812 | rnode = root->rnode; | ||
| 813 | if (!rnode) | ||
| 814 | return 0; | ||
| 815 | return any_tag_set(rnode, tag); | ||
| 816 | } | 846 | } |
| 817 | EXPORT_SYMBOL(radix_tree_tagged); | 847 | EXPORT_SYMBOL(radix_tree_tagged); |
| 818 | 848 | ||
