From 57af2bd34b77b3eb7da9ea8259b767ced4034881 Mon Sep 17 00:00:00 2001 From: Zach Brown Date: Tue, 18 Aug 2020 10:17:44 -0700 Subject: [PATCH] scoutfs: give btree walk callers more keys The current btree walk recorded the start and end of child subtrees as it walked, and it could give the caller the next key to iterate towards after the block it returned. Future methods want to get at the key bounds of child subtrees, so we add a key range struct that all walk callers provide and fill it with all the interesting keys calculated during the walk. Signed-off-by: Zach Brown --- kmod/src/btree.c | 65 +++++++++++++++++++++++++++--------------------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/kmod/src/btree.c b/kmod/src/btree.c index 9d79335c..99dede60 100644 --- a/kmod/src/btree.c +++ b/kmod/src/btree.c @@ -1194,6 +1194,14 @@ out: BUG(); } +struct btree_walk_key_range { + struct scoutfs_key start; + struct scoutfs_key end; + /* zero if no remaining blocks outside our walk in that direction */ + struct scoutfs_key iter_prev; + struct scoutfs_key iter_next; +}; + /* * Return the leaf block that should contain the given key. The caller * is responsible for searching the leaf block and performing their @@ -1217,7 +1225,7 @@ static int btree_walk(struct super_block *sb, int flags, struct scoutfs_key *key, unsigned int val_len, struct scoutfs_block **bl_ret, - struct scoutfs_key *iter_key) + struct btree_walk_key_range *kr) { struct scoutfs_block *par_bl = NULL; struct scoutfs_block *bl = NULL; @@ -1229,14 +1237,11 @@ static int btree_walk(struct super_block *sb, struct scoutfs_avl_node *next_node; struct scoutfs_avl_node *node; struct scoutfs_btree_ref *ref; - struct scoutfs_key start; - struct scoutfs_key end; unsigned int level; unsigned int nr; int ret; - if (WARN_ON_ONCE((flags & (BTW_NEXT|BTW_PREV)) && iter_key == NULL) || - WARN_ON_ONCE((flags & BTW_DIRTY) && (!alloc || !wri))) + if (WARN_ON_ONCE((flags & BTW_DIRTY) && (!alloc || !wri))) return -EINVAL; scoutfs_inc_counter(sb, btree_walk); @@ -1249,8 +1254,12 @@ restart: scoutfs_block_put(sb, bl); bl = NULL; bt = NULL; - scoutfs_key_set_zeros(&start); - scoutfs_key_set_ones(&end); + if (kr) { + scoutfs_key_set_zeros(&kr->start); + scoutfs_key_set_ones(&kr->end); + scoutfs_key_set_zeros(&kr->iter_prev); + scoutfs_key_set_zeros(&kr->iter_next); + } level = root->height; ret = 0; @@ -1280,8 +1289,8 @@ restart: break; bt = bl->data; - if (0) - verify_btree_block(sb, bt, level, &start, &end); + if (0 && kr) + verify_btree_block(sb, bt, level, &kr->start, &kr->end); /* XXX more aggressive block verification, before ref updates? */ if (bt->level != level) { @@ -1342,23 +1351,20 @@ restart: break; } - /* give the caller the next key to iterate towards */ - if (iter_key && (flags & BTW_NEXT) && next_item(bt, item)) { - *iter_key = *item_key(item); - scoutfs_key_inc(iter_key); - - } else if (iter_key && (flags & BTW_PREV) && - (prev = prev_item(bt, item))) { - *iter_key = *item_key(prev); + if (kr) { + /* update keys for walk bounds and next iteration */ + if ((prev = prev_item(bt, item))) { + kr->start = *item_key(prev); + scoutfs_key_inc(&kr->start); + kr->iter_prev = *item_key(prev); + } + kr->end = *item_key(item); + if (next_item(bt, item)) { + kr->iter_next = *item_key(item); + scoutfs_key_inc(&kr->iter_next); + } } - /* possible range of keys in referenced child block */ - if ((prev = prev_item(bt, item))) { - start = *item_key(prev); - scoutfs_key_inc(&start); - } - end = *item_key(item); - scoutfs_block_put(sb, par_bl); par_bl = bl; parent = bt; @@ -1672,8 +1678,9 @@ static int btree_iter(struct super_block *sb,struct scoutfs_btree_root *root, struct scoutfs_avl_node *prev; struct scoutfs_btree_item *item; struct scoutfs_btree_block *bt; - struct scoutfs_key iter_key; + struct btree_walk_key_range kr; struct scoutfs_key walk_key; + struct scoutfs_key *iter_key; struct scoutfs_block *bl; int ret; @@ -1684,9 +1691,8 @@ static int btree_iter(struct super_block *sb,struct scoutfs_btree_root *root, walk_key = *key; for (;;) { - scoutfs_key_set_zeros(&iter_key); ret = btree_walk(sb, NULL, NULL, root, flags, &walk_key, - 0, &bl, &iter_key); + 0, &bl, &kr); if (ret < 0) break; bt = bl->data; @@ -1708,8 +1714,9 @@ static int btree_iter(struct super_block *sb,struct scoutfs_btree_root *root, scoutfs_block_put(sb, bl); /* nothing in this leaf, walk gave us a key */ - if (!scoutfs_key_is_zeros(&iter_key)) { - walk_key = iter_key; + iter_key = (flags & BTW_NEXT) ? &kr.iter_next : &kr.iter_prev; + if (!scoutfs_key_is_zeros(iter_key)) { + walk_key = *iter_key; continue; }