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 | |
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>
-rw-r--r-- | include/linux/radix-tree.h | 5 | ||||
-rw-r--r-- | lib/radix-tree.c | 192 |
2 files changed, 114 insertions, 83 deletions
diff --git a/include/linux/radix-tree.h b/include/linux/radix-tree.h index dd83cca28001..9158a68140c9 100644 --- a/include/linux/radix-tree.h +++ b/include/linux/radix-tree.h | |||
@@ -23,6 +23,9 @@ | |||
23 | #include <linux/preempt.h> | 23 | #include <linux/preempt.h> |
24 | #include <linux/types.h> | 24 | #include <linux/types.h> |
25 | 25 | ||
26 | #define RADIX_TREE_MAX_TAGS 2 | ||
27 | |||
28 | /* root tags are stored in gfp_mask, shifted by __GFP_BITS_SHIFT */ | ||
26 | struct radix_tree_root { | 29 | struct radix_tree_root { |
27 | unsigned int height; | 30 | unsigned int height; |
28 | gfp_t gfp_mask; | 31 | gfp_t gfp_mask; |
@@ -45,8 +48,6 @@ do { \ | |||
45 | (root)->rnode = NULL; \ | 48 | (root)->rnode = NULL; \ |
46 | } while (0) | 49 | } while (0) |
47 | 50 | ||
48 | #define RADIX_TREE_MAX_TAGS 2 | ||
49 | |||
50 | int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); | 51 | int radix_tree_insert(struct radix_tree_root *, unsigned long, void *); |
51 | void *radix_tree_lookup(struct radix_tree_root *, unsigned long); | 52 | void *radix_tree_lookup(struct radix_tree_root *, unsigned long); |
52 | void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); | 53 | void **radix_tree_lookup_slot(struct radix_tree_root *, unsigned long); |
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 | ||