dm persistent data: add btree_walk
authorJoe Thornber <ejt@redhat.com>
Fri, 1 Mar 2013 22:45:50 +0000 (22:45 +0000)
committerAlasdair G Kergon <agk@redhat.com>
Fri, 1 Mar 2013 22:45:50 +0000 (22:45 +0000)
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>
drivers/md/persistent-data/dm-btree-internal.h
drivers/md/persistent-data/dm-btree-spine.c
drivers/md/persistent-data/dm-btree.c
drivers/md/persistent-data/dm-btree.h

index accbb05..37d367b 100644 (file)
@@ -64,6 +64,7 @@ struct ro_spine {
 void init_ro_spine(struct ro_spine *s, struct dm_btree_info *info);
 int exit_ro_spine(struct ro_spine *s);
 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 shadow_spine {
index f199a0c..cf9fd67 100644 (file)
@@ -164,6 +164,13 @@ int ro_step(struct ro_spine *s, dm_block_t new_child)
        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 dm_block *block;
index 4caf669..3586542 100644 (file)
@@ -807,3 +807,55 @@ int dm_btree_find_highest_key(struct dm_btree_info *info, dm_block_t root,
        return r ? r : count;
 }
 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);
index fced831..8672d15 100644 (file)
@@ -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,
                              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 */