aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2010-08-22 22:55:14 -0400
committerLinus Torvalds <torvalds@linux-foundation.org>2010-08-22 22:55:14 -0400
commit9ee47476d6734c9deb9ae9ab05d963302f6b6150 (patch)
treed6d5a54831322628427eb54cb3edc2f78a6125f4 /lib
parent76be97c1fc945db08aae1f1b746012662d643e97 (diff)
parent144dcfc01221e1a79fa47ca897df7d5e3ab298e6 (diff)
Merge branch 'radix-tree' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/xfsdev
* 'radix-tree' of git://git.kernel.org/pub/scm/linux/kernel/git/dgc/xfsdev: radix-tree: radix_tree_range_tag_if_tagged() can set incorrect tags radix-tree: clear all tags in radix_tree_node_rcu_free
Diffstat (limited to 'lib')
-rw-r--r--lib/radix-tree.c63
1 files changed, 48 insertions, 15 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 5b7d4623f0b7..efd16fa80b1c 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -174,14 +174,16 @@ static void radix_tree_node_rcu_free(struct rcu_head *head)
174{ 174{
175 struct radix_tree_node *node = 175 struct radix_tree_node *node =
176 container_of(head, struct radix_tree_node, rcu_head); 176 container_of(head, struct radix_tree_node, rcu_head);
177 int i;
177 178
178 /* 179 /*
179 * must only free zeroed nodes into the slab. radix_tree_shrink 180 * must only free zeroed nodes into the slab. radix_tree_shrink
180 * can leave us with a non-NULL entry in the first slot, so clear 181 * can leave us with a non-NULL entry in the first slot, so clear
181 * that here to make sure. 182 * that here to make sure.
182 */ 183 */
183 tag_clear(node, 0, 0); 184 for (i = 0; i < RADIX_TREE_MAX_TAGS; i++)
184 tag_clear(node, 1, 0); 185 tag_clear(node, i, 0);
186
185 node->slots[0] = NULL; 187 node->slots[0] = NULL;
186 node->count = 0; 188 node->count = 0;
187 189
@@ -623,6 +625,13 @@ EXPORT_SYMBOL(radix_tree_tag_get);
623 * also settag. The function stops either after tagging nr_to_tag items or 625 * also settag. The function stops either after tagging nr_to_tag items or
624 * after reaching last_index. 626 * after reaching last_index.
625 * 627 *
628 * The tags must be set from the leaf level only and propagated back up the
629 * path to the root. We must do this so that we resolve the full path before
630 * setting any tags on intermediate nodes. If we set tags as we descend, then
631 * we can get to the leaf node and find that the index that has the iftag
632 * set is outside the range we are scanning. This reults in dangling tags and
633 * can lead to problems with later tag operations (e.g. livelocks on lookups).
634 *
626 * The function returns number of leaves where the tag was set and sets 635 * The function returns number of leaves where the tag was set and sets
627 * *first_indexp to the first unscanned index. 636 * *first_indexp to the first unscanned index.
628 * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must 637 * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must
@@ -633,9 +642,13 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
633 unsigned long nr_to_tag, 642 unsigned long nr_to_tag,
634 unsigned int iftag, unsigned int settag) 643 unsigned int iftag, unsigned int settag)
635{ 644{
636 unsigned int height = root->height, shift; 645 unsigned int height = root->height;
637 unsigned long tagged = 0, index = *first_indexp; 646 struct radix_tree_path path[height];
638 struct radix_tree_node *open_slots[height], *slot; 647 struct radix_tree_path *pathp = path;
648 struct radix_tree_node *slot;
649 unsigned int shift;
650 unsigned long tagged = 0;
651 unsigned long index = *first_indexp;
639 652
640 last_index = min(last_index, radix_tree_maxindex(height)); 653 last_index = min(last_index, radix_tree_maxindex(height));
641 if (index > last_index) 654 if (index > last_index)
@@ -655,6 +668,13 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
655 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 668 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
656 slot = radix_tree_indirect_to_ptr(root->rnode); 669 slot = radix_tree_indirect_to_ptr(root->rnode);
657 670
671 /*
672 * we fill the path from (root->height - 2) to 0, leaving the index at
673 * (root->height - 1) as a terminator. Zero the node in the terminator
674 * so that we can use this to end walk loops back up the path.
675 */
676 path[height - 1].node = NULL;
677
658 for (;;) { 678 for (;;) {
659 int offset; 679 int offset;
660 680
@@ -663,17 +683,30 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
663 goto next; 683 goto next;
664 if (!tag_get(slot, iftag, offset)) 684 if (!tag_get(slot, iftag, offset))
665 goto next; 685 goto next;
686 if (height > 1) {
687 /* Go down one level */
688 height--;
689 shift -= RADIX_TREE_MAP_SHIFT;
690 path[height - 1].node = slot;
691 path[height - 1].offset = offset;
692 slot = slot->slots[offset];
693 continue;
694 }
695
696 /* tag the leaf */
697 tagged++;
666 tag_set(slot, settag, offset); 698 tag_set(slot, settag, offset);
667 if (height == 1) { 699
668 tagged++; 700 /* walk back up the path tagging interior nodes */
669 goto next; 701 pathp = &path[0];
702 while (pathp->node) {
703 /* stop if we find a node with the tag already set */
704 if (tag_get(pathp->node, settag, pathp->offset))
705 break;
706 tag_set(pathp->node, settag, pathp->offset);
707 pathp++;
670 } 708 }
671 /* Go down one level */ 709
672 height--;
673 shift -= RADIX_TREE_MAP_SHIFT;
674 open_slots[height] = slot;
675 slot = slot->slots[offset];
676 continue;
677next: 710next:
678 /* Go to next item at level determined by 'shift' */ 711 /* Go to next item at level determined by 'shift' */
679 index = ((index >> shift) + 1) << shift; 712 index = ((index >> shift) + 1) << shift;
@@ -688,7 +721,7 @@ next:
688 * last_index is guaranteed to be in the tree, what 721 * last_index is guaranteed to be in the tree, what
689 * we do below cannot wander astray. 722 * we do below cannot wander astray.
690 */ 723 */
691 slot = open_slots[height]; 724 slot = path[height - 1].node;
692 height++; 725 height++;
693 shift += RADIX_TREE_MAP_SHIFT; 726 shift += RADIX_TREE_MAP_SHIFT;
694 } 727 }