aboutsummaryrefslogtreecommitdiffstats
path: root/lib/radix-tree.c
diff options
context:
space:
mode:
Diffstat (limited to 'lib/radix-tree.c')
-rw-r--r--lib/radix-tree.c134
1 files changed, 132 insertions, 2 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c
index 05da38bcc298..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
@@ -609,6 +611,134 @@ int radix_tree_tag_get(struct radix_tree_root *root,
609EXPORT_SYMBOL(radix_tree_tag_get); 611EXPORT_SYMBOL(radix_tree_tag_get);
610 612
611/** 613/**
614 * radix_tree_range_tag_if_tagged - for each item in given range set given
615 * tag if item has another tag set
616 * @root: radix tree root
617 * @first_indexp: pointer to a starting index of a range to scan
618 * @last_index: last index of a range to scan
619 * @nr_to_tag: maximum number items to tag
620 * @iftag: tag index to test
621 * @settag: tag index to set if tested tag is set
622 *
623 * This function scans range of radix tree from first_index to last_index
624 * (inclusive). For each item in the range if iftag is set, the function sets
625 * also settag. The function stops either after tagging nr_to_tag items or
626 * after reaching last_index.
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 *
635 * The function returns number of leaves where the tag was set and sets
636 * *first_indexp to the first unscanned index.
637 * WARNING! *first_indexp can wrap if last_index is ULONG_MAX. Caller must
638 * be prepared to handle that.
639 */
640unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root,
641 unsigned long *first_indexp, unsigned long last_index,
642 unsigned long nr_to_tag,
643 unsigned int iftag, unsigned int settag)
644{
645 unsigned int height = root->height;
646 struct radix_tree_path path[height];
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;
652
653 last_index = min(last_index, radix_tree_maxindex(height));
654 if (index > last_index)
655 return 0;
656 if (!nr_to_tag)
657 return 0;
658 if (!root_tag_get(root, iftag)) {
659 *first_indexp = last_index + 1;
660 return 0;
661 }
662 if (height == 0) {
663 *first_indexp = last_index + 1;
664 root_tag_set(root, settag);
665 return 1;
666 }
667
668 shift = (height - 1) * RADIX_TREE_MAP_SHIFT;
669 slot = radix_tree_indirect_to_ptr(root->rnode);
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
678 for (;;) {
679 int offset;
680
681 offset = (index >> shift) & RADIX_TREE_MAP_MASK;
682 if (!slot->slots[offset])
683 goto next;
684 if (!tag_get(slot, iftag, offset))
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++;
698 tag_set(slot, settag, offset);
699
700 /* walk back up the path tagging interior nodes */
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++;
708 }
709
710next:
711 /* Go to next item at level determined by 'shift' */
712 index = ((index >> shift) + 1) << shift;
713 /* Overflow can happen when last_index is ~0UL... */
714 if (index > last_index || !index)
715 break;
716 if (tagged >= nr_to_tag)
717 break;
718 while (((index >> shift) & RADIX_TREE_MAP_MASK) == 0) {
719 /*
720 * We've fully scanned this node. Go up. Because
721 * last_index is guaranteed to be in the tree, what
722 * we do below cannot wander astray.
723 */
724 slot = path[height - 1].node;
725 height++;
726 shift += RADIX_TREE_MAP_SHIFT;
727 }
728 }
729 /*
730 * The iftag must have been set somewhere because otherwise
731 * we would return immediated at the beginning of the function
732 */
733 root_tag_set(root, settag);
734 *first_indexp = index;
735
736 return tagged;
737}
738EXPORT_SYMBOL(radix_tree_range_tag_if_tagged);
739
740
741/**
612 * radix_tree_next_hole - find the next hole (not-present entry) 742 * radix_tree_next_hole - find the next hole (not-present entry)
613 * @root: tree root 743 * @root: tree root
614 * @index: index key 744 * @index: index key