diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/radix-tree.c | 151 |
1 files changed, 151 insertions, 0 deletions
diff --git a/lib/radix-tree.c b/lib/radix-tree.c index 3e69c2b66c9..fefa76e6ff9 100644 --- a/lib/radix-tree.c +++ b/lib/radix-tree.c | |||
@@ -3,6 +3,7 @@ | |||
3 | * Portions Copyright (C) 2001 Christoph Hellwig | 3 | * Portions Copyright (C) 2001 Christoph Hellwig |
4 | * Copyright (C) 2005 SGI, Christoph Lameter | 4 | * Copyright (C) 2005 SGI, Christoph Lameter |
5 | * Copyright (C) 2006 Nick Piggin | 5 | * Copyright (C) 2006 Nick Piggin |
6 | * Copyright (C) 2012 Konstantin Khlebnikov | ||
6 | * | 7 | * |
7 | * This program is free software; you can redistribute it and/or | 8 | * This program is free software; you can redistribute it and/or |
8 | * modify it under the terms of the GNU General Public License as | 9 | * modify it under the terms of the GNU General Public License as |
@@ -146,6 +147,43 @@ static inline int any_tag_set(struct radix_tree_node *node, unsigned int tag) | |||
146 | } | 147 | } |
147 | return 0; | 148 | return 0; |
148 | } | 149 | } |
150 | |||
151 | /** | ||
152 | * radix_tree_find_next_bit - find the next set bit in a memory region | ||
153 | * | ||
154 | * @addr: The address to base the search on | ||
155 | * @size: The bitmap size in bits | ||
156 | * @offset: The bitnumber to start searching at | ||
157 | * | ||
158 | * Unrollable variant of find_next_bit() for constant size arrays. | ||
159 | * Tail bits starting from size to roundup(size, BITS_PER_LONG) must be zero. | ||
160 | * Returns next bit offset, or size if nothing found. | ||
161 | */ | ||
162 | static __always_inline unsigned long | ||
163 | radix_tree_find_next_bit(const unsigned long *addr, | ||
164 | unsigned long size, unsigned long offset) | ||
165 | { | ||
166 | if (!__builtin_constant_p(size)) | ||
167 | return find_next_bit(addr, size, offset); | ||
168 | |||
169 | if (offset < size) { | ||
170 | unsigned long tmp; | ||
171 | |||
172 | addr += offset / BITS_PER_LONG; | ||
173 | tmp = *addr >> (offset % BITS_PER_LONG); | ||
174 | if (tmp) | ||
175 | return __ffs(tmp) + offset; | ||
176 | offset = (offset + BITS_PER_LONG) & ~(BITS_PER_LONG - 1); | ||
177 | while (offset < size) { | ||
178 | tmp = *++addr; | ||
179 | if (tmp) | ||
180 | return __ffs(tmp) + offset; | ||
181 | offset += BITS_PER_LONG; | ||
182 | } | ||
183 | } | ||
184 | return size; | ||
185 | } | ||
186 | |||
149 | /* | 187 | /* |
150 | * This assumes that the caller has performed appropriate preallocation, and | 188 | * This assumes that the caller has performed appropriate preallocation, and |
151 | * that the caller has pinned this thread of control to the current CPU. | 189 | * that the caller has pinned this thread of control to the current CPU. |
@@ -613,6 +651,119 @@ int radix_tree_tag_get(struct radix_tree_root *root, | |||
613 | EXPORT_SYMBOL(radix_tree_tag_get); | 651 | EXPORT_SYMBOL(radix_tree_tag_get); |
614 | 652 | ||
615 | /** | 653 | /** |
654 | * radix_tree_next_chunk - find next chunk of slots for iteration | ||
655 | * | ||
656 | * @root: radix tree root | ||
657 | * @iter: iterator state | ||
658 | * @flags: RADIX_TREE_ITER_* flags and tag index | ||
659 | * Returns: pointer to chunk first slot, or NULL if iteration is over | ||
660 | */ | ||
661 | void **radix_tree_next_chunk(struct radix_tree_root *root, | ||
662 | struct radix_tree_iter *iter, unsigned flags) | ||
663 | { | ||
664 | unsigned shift, tag = flags & RADIX_TREE_ITER_TAG_MASK; | ||
665 | struct radix_tree_node *rnode, *node; | ||
666 | unsigned long index, offset; | ||
667 | |||
668 | if ((flags & RADIX_TREE_ITER_TAGGED) && !root_tag_get(root, tag)) | ||
669 | return NULL; | ||
670 | |||
671 | /* | ||
672 | * Catch next_index overflow after ~0UL. iter->index never overflows | ||
673 | * during iterating; it can be zero only at the beginning. | ||
674 | * And we cannot overflow iter->next_index in a single step, | ||
675 | * because RADIX_TREE_MAP_SHIFT < BITS_PER_LONG. | ||
676 | */ | ||
677 | index = iter->next_index; | ||
678 | if (!index && iter->index) | ||
679 | return NULL; | ||
680 | |||
681 | rnode = rcu_dereference_raw(root->rnode); | ||
682 | if (radix_tree_is_indirect_ptr(rnode)) { | ||
683 | rnode = indirect_to_ptr(rnode); | ||
684 | } else if (rnode && !index) { | ||
685 | /* Single-slot tree */ | ||
686 | iter->index = 0; | ||
687 | iter->next_index = 1; | ||
688 | iter->tags = 1; | ||
689 | return (void **)&root->rnode; | ||
690 | } else | ||
691 | return NULL; | ||
692 | |||
693 | restart: | ||
694 | shift = (rnode->height - 1) * RADIX_TREE_MAP_SHIFT; | ||
695 | offset = index >> shift; | ||
696 | |||
697 | /* Index outside of the tree */ | ||
698 | if (offset >= RADIX_TREE_MAP_SIZE) | ||
699 | return NULL; | ||
700 | |||
701 | node = rnode; | ||
702 | while (1) { | ||
703 | if ((flags & RADIX_TREE_ITER_TAGGED) ? | ||
704 | !test_bit(offset, node->tags[tag]) : | ||
705 | !node->slots[offset]) { | ||
706 | /* Hole detected */ | ||
707 | if (flags & RADIX_TREE_ITER_CONTIG) | ||
708 | return NULL; | ||
709 | |||
710 | if (flags & RADIX_TREE_ITER_TAGGED) | ||
711 | offset = radix_tree_find_next_bit( | ||
712 | node->tags[tag], | ||
713 | RADIX_TREE_MAP_SIZE, | ||
714 | offset + 1); | ||
715 | else | ||
716 | while (++offset < RADIX_TREE_MAP_SIZE) { | ||
717 | if (node->slots[offset]) | ||
718 | break; | ||
719 | } | ||
720 | index &= ~((RADIX_TREE_MAP_SIZE << shift) - 1); | ||
721 | index += offset << shift; | ||
722 | /* Overflow after ~0UL */ | ||
723 | if (!index) | ||
724 | return NULL; | ||
725 | if (offset == RADIX_TREE_MAP_SIZE) | ||
726 | goto restart; | ||
727 | } | ||
728 | |||
729 | /* This is leaf-node */ | ||
730 | if (!shift) | ||
731 | break; | ||
732 | |||
733 | node = rcu_dereference_raw(node->slots[offset]); | ||
734 | if (node == NULL) | ||
735 | goto restart; | ||
736 | shift -= RADIX_TREE_MAP_SHIFT; | ||
737 | offset = (index >> shift) & RADIX_TREE_MAP_MASK; | ||
738 | } | ||
739 | |||
740 | /* Update the iterator state */ | ||
741 | iter->index = index; | ||
742 | iter->next_index = (index | RADIX_TREE_MAP_MASK) + 1; | ||
743 | |||
744 | /* Construct iter->tags bit-mask from node->tags[tag] array */ | ||
745 | if (flags & RADIX_TREE_ITER_TAGGED) { | ||
746 | unsigned tag_long, tag_bit; | ||
747 | |||
748 | tag_long = offset / BITS_PER_LONG; | ||
749 | tag_bit = offset % BITS_PER_LONG; | ||
750 | iter->tags = node->tags[tag][tag_long] >> tag_bit; | ||
751 | /* This never happens if RADIX_TREE_TAG_LONGS == 1 */ | ||
752 | if (tag_long < RADIX_TREE_TAG_LONGS - 1) { | ||
753 | /* Pick tags from next element */ | ||
754 | if (tag_bit) | ||
755 | iter->tags |= node->tags[tag][tag_long + 1] << | ||
756 | (BITS_PER_LONG - tag_bit); | ||
757 | /* Clip chunk size, here only BITS_PER_LONG tags */ | ||
758 | iter->next_index = index + BITS_PER_LONG; | ||
759 | } | ||
760 | } | ||
761 | |||
762 | return node->slots + offset; | ||
763 | } | ||
764 | EXPORT_SYMBOL(radix_tree_next_chunk); | ||
765 | |||
766 | /** | ||
616 | * radix_tree_range_tag_if_tagged - for each item in given range set given | 767 | * radix_tree_range_tag_if_tagged - for each item in given range set given |
617 | * tag if item has another tag set | 768 | * tag if item has another tag set |
618 | * @root: radix tree root | 769 | * @root: radix tree root |