dm persistent data: add btree_walk
Add dm_btree_walk to iterate through the contents of a btree. This will be used by the dm cache target. Signed-off-by: Joe Thornber <ejt@redhat.com> Signed-off-by: Alasdair G Kergon <agk@redhat.com>
This commit is contained in:
parent
b0d8ed4d96
commit
4e7f1f9089
@ -64,6 +64,7 @@ struct ro_spine {
|
|||||||
void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info);
|
void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info);
|
||||||
int exit_ro_spine(struct ro_spine *s);
|
int exit_ro_spine(struct ro_spine *s);
|
||||||
int ro_step(struct ro_spine *s, dm_block_t new_child);
|
int ro_step(struct ro_spine *s, dm_block_t new_child);
|
||||||
|
void ro_pop(struct ro_spine *s);
|
||||||
struct btree_node *ro_node(struct ro_spine *s);
|
struct btree_node *ro_node(struct ro_spine *s);
|
||||||
|
|
||||||
struct shadow_spine {
|
struct shadow_spine {
|
||||||
|
@ -164,6 +164,13 @@ int ro_step(struct ro_spine *s, dm_block_t new_child)
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ro_pop(struct ro_spine *s)
|
||||||
|
{
|
||||||
|
BUG_ON(!s->count);
|
||||||
|
--s->count;
|
||||||
|
unlock_block(s->info, s->nodes[s->count]);
|
||||||
|
}
|
||||||
|
|
||||||
struct btree_node *ro_node(struct ro_spine *s)
|
struct btree_node *ro_node(struct ro_spine *s)
|
||||||
{
|
{
|
||||||
struct dm_block *block;
|
struct dm_block *block;
|
||||||
|
@ -807,3 +807,55 @@ int dm_btree_find_highest_key(struct dm_btree_info *info, dm_block_t root,
|
|||||||
return r ? r : count;
|
return r ? r : count;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(dm_btree_find_highest_key);
|
EXPORT_SYMBOL_GPL(dm_btree_find_highest_key);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* FIXME: We shouldn't use a recursive algorithm when we have limited stack
|
||||||
|
* space. Also this only works for single level trees.
|
||||||
|
*/
|
||||||
|
static int walk_node(struct ro_spine *s, dm_block_t block,
|
||||||
|
int (*fn)(void *context, uint64_t *keys, void *leaf),
|
||||||
|
void *context)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
unsigned i, nr;
|
||||||
|
struct btree_node *n;
|
||||||
|
uint64_t keys;
|
||||||
|
|
||||||
|
r = ro_step(s, block);
|
||||||
|
n = ro_node(s);
|
||||||
|
|
||||||
|
nr = le32_to_cpu(n->header.nr_entries);
|
||||||
|
for (i = 0; i < nr; i++) {
|
||||||
|
if (le32_to_cpu(n->header.flags) & INTERNAL_NODE) {
|
||||||
|
r = walk_node(s, value64(n, i), fn, context);
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
} else {
|
||||||
|
keys = le64_to_cpu(*key_ptr(n, i));
|
||||||
|
r = fn(context, &keys, value_ptr(n, i));
|
||||||
|
if (r)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
ro_pop(s);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
int dm_btree_walk(struct dm_btree_info *info, dm_block_t root,
|
||||||
|
int (*fn)(void *context, uint64_t *keys, void *leaf),
|
||||||
|
void *context)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
struct ro_spine spine;
|
||||||
|
|
||||||
|
BUG_ON(info->levels > 1);
|
||||||
|
|
||||||
|
init_ro_spine(&spine, info);
|
||||||
|
r = walk_node(&spine, root, fn, context);
|
||||||
|
exit_ro_spine(&spine);
|
||||||
|
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
EXPORT_SYMBOL_GPL(dm_btree_walk);
|
||||||
|
@ -142,4 +142,13 @@ int dm_btree_remove(struct dm_btree_info *info, dm_block_t root,
|
|||||||
int dm_btree_find_highest_key(struct dm_btree_info *info, dm_block_t root,
|
int dm_btree_find_highest_key(struct dm_btree_info *info, dm_block_t root,
|
||||||
uint64_t *result_keys);
|
uint64_t *result_keys);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Iterate through the a btree, calling fn() on each entry.
|
||||||
|
* It only works for single level trees and is internally recursive, so
|
||||||
|
* monitor stack usage carefully.
|
||||||
|
*/
|
||||||
|
int dm_btree_walk(struct dm_btree_info *info, dm_block_t root,
|
||||||
|
int (*fn)(void *context, uint64_t *keys, void *leaf),
|
||||||
|
void *context);
|
||||||
|
|
||||||
#endif /* _LINUX_DM_BTREE_H */
|
#endif /* _LINUX_DM_BTREE_H */
|
||||||
|
Loading…
Reference in New Issue
Block a user