scoutfs: fix depth-first radix next bit search

The radix block next bit search could return a spurious -ENOENT if it
ran out of references in a parent block further down the tree.  It needs
to bubble up to try the next ref in its parent so that it keeps
performing a depth-first search of the entire tree.

This lead to an assertion being tripped in _radix_merge.  Getting an
early -ENOENT caused it to start searching from 0 again.  When it's
iterating over a read-only input it could find the same leaf and try to
clear source bits that were already cleared.

Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
Zach Brown
2020-04-15 16:24:51 -07:00
committed by Zach Brown
parent 2c5e3aa551
commit d2a15ea506

View File

@@ -901,9 +901,29 @@ static int get_path(struct super_block *sb, struct scoutfs_radix_root *root,
ind++;
}
/*
* Didn't find a ref in the rest of the block at
* this level. If we're the root block there's no
* more next bits to return. If we're further down
* we bubble up a level and continue on a depth-first
* search. We check the next ref from our parent and reset
* all the child inds to the left spine of the new
* subtree.
*/
if (ind >= SCOUTFS_RADIX_REFS) {
ret = -ENOENT;
goto out;
if (level == root->height - 1) {
ret = -ENOENT;
goto out;
}
path->inds[level + 1]++;
for (i = level; i >= 0; i--)
path->inds[i] = 0;
for (i = level; i <= level + 1; i++) {
scoutfs_block_put(sb, path->bls[i]);
path->bls[i] = NULL;
}
level += 2;
continue;
}
/* reset all lower indices if we searched */