diff options
Diffstat (limited to 'drivers/md/persistent-data')
-rw-r--r-- | drivers/md/persistent-data/dm-btree-internal.h | 1 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-btree-spine.c | 7 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-btree.c | 52 | ||||
-rw-r--r-- | drivers/md/persistent-data/dm-btree.h | 9 |
4 files changed, 69 insertions, 0 deletions
diff --git a/drivers/md/persistent-data/dm-btree-internal.h b/drivers/md/persistent-data/dm-btree-internal.h index accbb05f17b6..37d367bb9aa8 100644 --- a/drivers/md/persistent-data/dm-btree-internal.h +++ b/drivers/md/persistent-data/dm-btree-internal.h | |||
@@ -64,6 +64,7 @@ struct ro_spine { | |||
64 | void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info); | 64 | void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info); |
65 | int exit_ro_spine(struct ro_spine *s); | 65 | int exit_ro_spine(struct ro_spine *s); |
66 | int ro_step(struct ro_spine *s, dm_block_t new_child); | 66 | int ro_step(struct ro_spine *s, dm_block_t new_child); |
67 | void ro_pop(struct ro_spine *s); | ||
67 | struct btree_node *ro_node(struct ro_spine *s); | 68 | struct btree_node *ro_node(struct ro_spine *s); |
68 | 69 | ||
69 | struct shadow_spine { | 70 | struct shadow_spine { |
diff --git a/drivers/md/persistent-data/dm-btree-spine.c b/drivers/md/persistent-data/dm-btree-spine.c index f199a0c4ed04..cf9fd676ae44 100644 --- a/drivers/md/persistent-data/dm-btree-spine.c +++ b/drivers/md/persistent-data/dm-btree-spine.c | |||
@@ -164,6 +164,13 @@ int ro_step(struct ro_spine *s, dm_block_t new_child) | |||
164 | return r; | 164 | return r; |
165 | } | 165 | } |
166 | 166 | ||
167 | void ro_pop(struct ro_spine *s) | ||
168 | { | ||
169 | BUG_ON(!s->count); | ||
170 | --s->count; | ||
171 | unlock_block(s->info, s->nodes[s->count]); | ||
172 | } | ||
173 | |||
167 | struct btree_node *ro_node(struct ro_spine *s) | 174 | struct btree_node *ro_node(struct ro_spine *s) |
168 | { | 175 | { |
169 | struct dm_block *block; | 176 | struct dm_block *block; |
diff --git a/drivers/md/persistent-data/dm-btree.c b/drivers/md/persistent-data/dm-btree.c index 4caf66918cdb..35865425e4b4 100644 --- a/drivers/md/persistent-data/dm-btree.c +++ b/drivers/md/persistent-data/dm-btree.c | |||
@@ -807,3 +807,55 @@ int dm_btree_find_highest_key(struct dm_btree_info *info, dm_block_t root, | |||
807 | return r ? r : count; | 807 | return r ? r : count; |
808 | } | 808 | } |
809 | EXPORT_SYMBOL_GPL(dm_btree_find_highest_key); | 809 | EXPORT_SYMBOL_GPL(dm_btree_find_highest_key); |
810 | |||
811 | /* | ||
812 | * FIXME: We shouldn't use a recursive algorithm when we have limited stack | ||
813 | * space. Also this only works for single level trees. | ||
814 | */ | ||
815 | static int walk_node(struct ro_spine *s, dm_block_t block, | ||
816 | int (*fn)(void *context, uint64_t *keys, void *leaf), | ||
817 | void *context) | ||
818 | { | ||
819 | int r; | ||
820 | unsigned i, nr; | ||
821 | struct btree_node *n; | ||
822 | uint64_t keys; | ||
823 | |||
824 | r = ro_step(s, block); | ||
825 | n = ro_node(s); | ||
826 | |||
827 | nr = le32_to_cpu(n->header.nr_entries); | ||
828 | for (i = 0; i < nr; i++) { | ||
829 | if (le32_to_cpu(n->header.flags) & INTERNAL_NODE) { | ||
830 | r = walk_node(s, value64(n, i), fn, context); | ||
831 | if (r) | ||
832 | goto out; | ||
833 | } else { | ||
834 | keys = le64_to_cpu(*key_ptr(n, i)); | ||
835 | r = fn(context, &keys, value_ptr(n, i)); | ||
836 | if (r) | ||
837 | goto out; | ||
838 | } | ||
839 | } | ||
840 | |||
841 | out: | ||
842 | ro_pop(s); | ||
843 | return r; | ||
844 | } | ||
845 | |||
846 | int dm_btree_walk(struct dm_btree_info *info, dm_block_t root, | ||
847 | int (*fn)(void *context, uint64_t *keys, void *leaf), | ||
848 | void *context) | ||
849 | { | ||
850 | int r; | ||
851 | struct ro_spine spine; | ||
852 | |||
853 | BUG_ON(info->levels > 1); | ||
854 | |||
855 | init_ro_spine(&spine, info); | ||
856 | r = walk_node(&spine, root, fn, context); | ||
857 | exit_ro_spine(&spine); | ||
858 | |||
859 | return r; | ||
860 | } | ||
861 | EXPORT_SYMBOL_GPL(dm_btree_walk); | ||
diff --git a/drivers/md/persistent-data/dm-btree.h b/drivers/md/persistent-data/dm-btree.h index fced8316bca2..8672d159e0b5 100644 --- a/drivers/md/persistent-data/dm-btree.h +++ b/drivers/md/persistent-data/dm-btree.h | |||
@@ -142,4 +142,13 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root, | |||
142 | int dm_btree_find_highest_key(struct dm_btree_info *info, dm_block_t root, | 142 | int dm_btree_find_highest_key(struct dm_btree_info *info, dm_block_t root, |
143 | uint64_t *result_keys); | 143 | uint64_t *result_keys); |
144 | 144 | ||
145 | /* | ||
146 | * Iterate through the a btree, calling fn() on each entry. | ||
147 | * It only works for single level trees and is internally recursive, so | ||
148 | * monitor stack usage carefully. | ||
149 | */ | ||
150 | int dm_btree_walk(struct dm_btree_info *info, dm_block_t root, | ||
151 | int (*fn)(void *context, uint64_t *keys, void *leaf), | ||
152 | void *context); | ||
153 | |||
145 | #endif /* _LINUX_DM_BTREE_H */ | 154 | #endif /* _LINUX_DM_BTREE_H */ |