diff options
author | Jan Kara <jack@suse.cz> | 2010-08-09 20:19:11 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-08-09 23:44:59 -0400 |
commit | ebf8aa44beed48cd17893a83d92a4403e5f9d9e2 (patch) | |
tree | 03607aa1cdbbb7fda935edb28bb3ad06423852ac /lib | |
parent | 44ab57a06ded284db6ccdefc6b76eddb1c34d7ed (diff) |
radix-tree: omplement function radix_tree_range_tag_if_tagged
Implement function for setting one tag if another tag is set for each item
in given range.
Signed-off-by: Jan Kara <jack@suse.cz>
Cc: Dave Chinner <david@fromorbit.com>
Cc: Nick Piggin <nickpiggin@yahoo.com.au>
Cc: Chris Mason <chris.mason@oracle.com>
Cc: Theodore Ts'o <tytso@mit.edu>
Cc: Jens Axboe <axboe@kernel.dk>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'lib')
-rw-r--r-- | lib/radix-tree.c | 94 |
1 files changed, 94 insertions, 0 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 05da38bcc298..e907858498a6 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
@@ -609,6 +609,100 @@ int radix_tree_tag_get(struct radix_tree_root *root, | |||
609 | EXPORT_SYMBOL(radix_tree_tag_get); | 609 | EXPORT_SYMBOL(radix_tree_tag_get); |
610 | 610 | ||
611 | /** | 611 | /** |
612 | * radix_tree_range_tag_if_tagged - for each item in given range set given | ||
613 | * tag if item has another tag set | ||
614 | * @root: radix tree root | ||
615 | * @first_indexp: pointer to a starting index of a range to scan | ||
616 | * @last_index: last index of a range to scan | ||
617 | * @nr_to_tag: maximum number items to tag | ||
618 | * @iftag: tag index to test | ||
619 | * @settag: tag index to set if tested tag is set | ||
620 | * | ||
621 | * This function scans range of radix tree from first_index to last_index | ||
622 | * (inclusive). For each item in the range if iftag is set, the function sets | ||
623 | * also settag. The function stops either after tagging nr_to_tag items or | ||
624 | * after reaching last_index. | ||
625 | * | ||
626 | * The function returns number of leaves where the tag was set and sets | ||
627 | * *first_indexp to the first unscanned index. | ||
628 | */ | ||
629 | unsigned long radix_tree_range_tag_if_tagged(struct radix_tree_root *root, | ||
630 | unsigned long *first_indexp, unsigned long last_index, | ||
631 | unsigned long nr_to_tag, | ||
632 | unsigned int iftag, unsigned int settag) | ||
633 | { | ||
634 | unsigned int height = root->height, shift; | ||
635 | unsigned long tagged = 0, index = *first_indexp; | ||
636 | struct radix_tree_node *open_slots[height], *slot; | ||
637 | |||
638 | last_index = min(last_index, radix_tree_maxindex(height)); | ||
639 | if (index > last_index) | ||
640 | return 0; | ||
641 | if (!nr_to_tag) | ||
642 | return 0; | ||
643 | if (!root_tag_get(root, iftag)) { | ||
644 | *first_indexp = last_index + 1; | ||
645 | return 0; | ||
646 | } | ||
647 | if (height == 0) { | ||
648 | *first_indexp = last_index + 1; | ||
649 | root_tag_set(root, settag); | ||
650 | return 1; | ||
651 | } | ||
652 | |||
653 | shift = (height - 1) * RADIX_TREE_MAP_SHIFT; | ||
654 | slot = radix_tree_indirect_to_ptr(root->rnode); | ||
655 | |||
656 | for (;;) { | ||
657 | int offset; | ||
658 | |||
659 | offset = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
660 | if (!slot->slots[offset]) | ||
661 | goto next; | ||
662 | if (!tag_get(slot, iftag, offset)) | ||
663 | goto next; | ||
664 | tag_set(slot, settag, offset); | ||
665 | if (height == 1) { | ||
666 | tagged++; | ||
667 | goto next; | ||
668 | } | ||
669 | /* Go down one level */ | ||
670 | height--; | ||
671 | shift -= RADIX_TREE_MAP_SHIFT; | ||
672 | open_slots[height] = slot; | ||
673 | slot = slot->slots[offset]; | ||
674 | continue; | ||
675 | next: | ||
676 | /* Go to next item at level determined by 'shift' */ | ||
677 | index = ((index >> shift) + 1) << shift; | ||
678 | if (index > last_index) | ||
679 | break; | ||
680 | if (tagged >= nr_to_tag) | ||
681 | break; | ||
682 | while (((index >> shift) & RADIX_TREE_MAP_MASK) == 0) { | ||
683 | /* | ||
684 | * We've fully scanned this node. Go up. Because | ||
685 | * last_index is guaranteed to be in the tree, what | ||
686 | * we do below cannot wander astray. | ||
687 | */ | ||
688 | slot = open_slots[height]; | ||
689 | height++; | ||
690 | shift += RADIX_TREE_MAP_SHIFT; | ||
691 | } | ||
692 | } | ||
693 | /* | ||
694 | * The iftag must have been set somewhere because otherwise | ||
695 | * we would return immediated at the beginning of the function | ||
696 | */ | ||
697 | root_tag_set(root, settag); | ||
698 | *first_indexp = index; | ||
699 | |||
700 | return tagged; | ||
701 | } | ||
702 | EXPORT_SYMBOL(radix_tree_range_tag_if_tagged); | ||
703 | |||
704 | |||
705 | /** | ||
612 | * radix_tree_next_hole - find the next hole (not-present entry) | 706 | * radix_tree_next_hole - find the next hole (not-present entry) |
613 | * @root: tree root | 707 | * @root: tree root |
614 | * @index: index key | 708 | * @index: index key |