diff --git a/kmod/src/btree.c b/kmod/src/btree.c index b9b02696..f9e6795f 100644 --- a/kmod/src/btree.c +++ b/kmod/src/btree.c @@ -83,6 +83,7 @@ enum btree_walk_flags { BTW_ALLOC = (1 << 3), /* allocate a new block for 0 ref, requires dirty */ BTW_INSERT = (1 << 4), /* walking to insert, try splitting */ BTW_DELETE = (1 << 5), /* walking to delete, try joining */ + BTW_PAR_RNG = (1 << 6), /* return range through final parent */ }; /* total length of the value payload */ @@ -1098,7 +1099,8 @@ static int btree_walk(struct super_block *sb, unsigned int nr; int ret; - if (WARN_ON_ONCE((flags & BTW_DIRTY) && (!alloc || !wri))) + if (WARN_ON_ONCE((flags & BTW_DIRTY) && (!alloc || !wri)) || + WARN_ON_ONCE((flags & BTW_PAR_RNG) && !kr)) return -EINVAL; /* all ops come through walk and walk calls all reads */ @@ -1144,6 +1146,12 @@ restart: trace_scoutfs_btree_walk(sb, root, key, flags, level, ref); + /* par range set by ref to last parent block */ + if (level < 2 && (flags & BTW_PAR_RNG)) { + ret = 0; + break; + } + ret = get_ref_block(sb, alloc, wri, flags, ref, &bl); if (ret) break; @@ -1742,3 +1750,29 @@ int scoutfs_btree_insert_list(struct super_block *sb, out: return ret; } + +/* + * Descend towards the leaf that would contain the key. As we arrive at + * the last parent block, set start and end to the range of keys that + * could be found through traversal of that last parent. + * + * If the tree is too short for parent blocks then the max key range + * is returned. + */ +int scoutfs_btree_parent_range(struct super_block *sb, + struct scoutfs_btree_root *root, + struct scoutfs_key *key, + struct scoutfs_key *start, + struct scoutfs_key *end) +{ + struct btree_walk_key_range kr; + int ret; + + ret = btree_walk(sb, NULL, NULL, root, BTW_PAR_RNG, key, 0, NULL, &kr); + if (ret == -ENOENT) + ret = 0; + + *start = kr.start; + *end = kr.end; + return ret; +} diff --git a/kmod/src/btree.h b/kmod/src/btree.h index 79d4de58..697f34c3 100644 --- a/kmod/src/btree.h +++ b/kmod/src/btree.h @@ -82,6 +82,12 @@ int scoutfs_btree_insert_list(struct super_block *sb, struct scoutfs_btree_root *root, struct scoutfs_btree_item_list *lst); +int scoutfs_btree_parent_range(struct super_block *sb, + struct scoutfs_btree_root *root, + struct scoutfs_key *key, + struct scoutfs_key *start, + struct scoutfs_key *end); + void scoutfs_btree_put_iref(struct scoutfs_btree_item_ref *iref); #endif