aboutsummaryrefslogtreecommitdiffstats
path: root/lib
diff options
context:
space:
mode:
Diffstat (limited to 'lib')
-rw-r--r--lib/radix-tree.c57
1 files changed, 44 insertions, 13 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 1014171dd1c5..e0ee8cb37e41 100644
--- a/lib/radix-tree.c
+++ b/lib/radix-tree.c
@@ -625,6 +625,13 @@ EXPORT_SYMBOL(radix_tree_tag_get);
625 * 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
626 * after reaching last_index. 626 * after reaching last_index.
627 * 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 *
628 * 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
629 * *first_indexp to the first unscanned index. 636 * *first_indexp to the first unscanned index.
630 */ 637 */
@@ -633,9 +640,13 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
633 unsigned long nr_to_tag, 640 unsigned long nr_to_tag,
634 unsigned int iftag, unsigned int settag) 641 unsigned int iftag, unsigned int settag)
635{ 642{
636 unsigned int height = root->height, shift; 643 unsigned int height = root->height;
637 unsigned long tagged = 0, index = *first_indexp; 644 struct radix_tree_path path[height];
638 struct radix_tree_node *open_slots[height], *slot; 645 struct radix_tree_path *pathp = path;
646 struct radix_tree_node *slot;
647 unsigned int shift;
648 unsigned long tagged = 0;
649 unsigned long index = *first_indexp;
639 650
640 last_index = min(last_index, radix_tree_maxindex(height)); 651 last_index = min(last_index, radix_tree_maxindex(height));
641 if (index > last_index) 652 if (index > last_index)
@@ -655,6 +666,13 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
655 shift = (height - 1) * RADIX_TREE_MAP_SHIFT; 666 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
656 slot = radix_tree_indirect_to_ptr(root->rnode); 667 slot = radix_tree_indirect_to_ptr(root->rnode);
657 668
669 /*
670 * we fill the path from (root->height - 2) to 0, leaving the index at
671 * (root->height - 1) as a terminator. Zero the node in the terminator
672 * so that we can use this to end walk loops back up the path.
673 */
674 path[height - 1].node = NULL;
675
658 for (;;) { 676 for (;;) {
659 int offset; 677 int offset;
660 678
@@ -663,17 +681,30 @@ unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
663 goto next; 681 goto next;
664 if (!tag_get(slot, iftag, offset)) 682 if (!tag_get(slot, iftag, offset))
665 goto next; 683 goto next;
684 if (height > 1) {
685 /* Go down one level */
686 height--;
687 shift -= RADIX_TREE_MAP_SHIFT;
688 path[height - 1].node = slot;
689 path[height - 1].offset = offset;
690 slot = slot->slots[offset];
691 continue;
692 }
693
694 /* tag the leaf */
695 tagged++;
666 tag_set(slot, settag, offset); 696 tag_set(slot, settag, offset);
667 if (height == 1) { 697
668 tagged++; 698 /* walk back up the path tagging interior nodes */
669 goto next; 699 pathp = &path[0];
700 while (pathp->node) {
701 /* stop if we find a node with the tag already set */
702 if (tag_get(pathp->node, settag, pathp->offset))
703 break;
704 tag_set(pathp->node, settag, pathp->offset);
705 pathp++;
670 } 706 }
671 /* Go down one level */ 707
672 height--;
673 shift -= RADIX_TREE_MAP_SHIFT;
674 open_slots[height] = slot;
675 slot = slot->slots[offset];
676 continue;
677next: 708next:
678 /* Go to next item at level determined by 'shift' */ 709 /* Go to next item at level determined by 'shift' */
679 index = ((index >> shift) + 1) << shift; 710 index = ((index >> shift) + 1) << shift;
@@ -687,7 +718,7 @@ next:
687 * last_index is guaranteed to be in the tree, what 718 * last_index is guaranteed to be in the tree, what
688 * we do below cannot wander astray. 719 * we do below cannot wander astray.
689 */ 720 */
690 slot = open_slots[height]; 721 slot = path[height - 1].node;
691 height++; 722 height++;
692 shift += RADIX_TREE_MAP_SHIFT; 723 shift += RADIX_TREE_MAP_SHIFT;
693 } 724 }