mirror of
https://github.com/versity/scoutfs.git
synced 2026-09-05 23:56:58 +00:00
scoutfs: fix binary search for sorted srch block
The search_xattrs ioctl looks for srch entries in srch files that map the caller's hashed xattr name to inodes. As it searches it maintains a range of entries that it is looking for. When it searches sorted srch files for entries it first performs a binary search for the start of the range and then iterates over the blocks until it reaches the end of its range. The binary search for the start of the range was a bit wrong. If the start of the range was less than all the blocks then the binary search could wrap the left index, try to get a file block at a negative index, and return an error for the search. This is relatively hard to hit in practice. You have to search for the xattr name with the smallest hashed value and have a sorted srch file that's just the right size so that blk offset 0 is the last block compared in the binary search, which sets the right index to -1. If there are lots of xattrs, or sorted files of the wrong length, it'll work. This fixes the binary search so that it specifically records the first block offset that intersects with the range and tests that the left and right offsets haven't been inverted. Now that we're not breaking out of the binary search loop we can more obviously put each block reference that we get. Signed-off-by: Zach Brown <zab@versity.com>
This commit is contained in:
+26
-15
@@ -758,34 +758,45 @@ static int search_sorted_file(struct super_block *sb,
|
||||
struct scoutfs_block *bl = NULL;
|
||||
int ret = 0;
|
||||
int pos = 0;
|
||||
u64 left;
|
||||
u64 right;
|
||||
s64 left;
|
||||
s64 right;
|
||||
u64 first;
|
||||
u64 blk;
|
||||
|
||||
/* binary search for the block that contains the start */
|
||||
blk = 0;
|
||||
if (sfl->blocks == 0)
|
||||
return 0;
|
||||
|
||||
/* binary search for first block in the range */
|
||||
first = U64_MAX;
|
||||
left = 0;
|
||||
right = le64_to_cpu(sfl->blocks) - 1;
|
||||
while (left != right) {
|
||||
while (left <= right) {
|
||||
blk = (left + right) >> 1;
|
||||
|
||||
scoutfs_block_put(sb, bl);
|
||||
ret = get_file_block(sb, NULL, NULL, sfl, 0, blk, &bl);
|
||||
if (ret < 0)
|
||||
goto out;
|
||||
srb = bl->data;
|
||||
|
||||
if (sre_cmp(start, &srb->first) < 0)
|
||||
right = --blk;
|
||||
else if (sre_cmp(start, &srb->last) > 0)
|
||||
left = ++blk;
|
||||
else
|
||||
break;
|
||||
if (sre_cmp(end, &srb->first) < 0) {
|
||||
right = blk - 1;
|
||||
} else if (sre_cmp(start, &srb->last) > 0) {
|
||||
left = blk + 1;
|
||||
} else {
|
||||
first = min(blk, first);
|
||||
right = blk - 1;
|
||||
}
|
||||
|
||||
scoutfs_block_put(sb, bl);
|
||||
bl = NULL;
|
||||
}
|
||||
|
||||
/* blk is the result of the search */
|
||||
scoutfs_block_put(sb, bl);
|
||||
bl = NULL;
|
||||
/* no blocks in range */
|
||||
if (first == U64_MAX) {
|
||||
ret = 0;
|
||||
goto out;
|
||||
}
|
||||
blk = first;
|
||||
|
||||
/* stream entries until end or we're past the full tracking rb_root */
|
||||
for (;;) {
|
||||
|
||||
Reference in New Issue
Block a user