Commit abc6e134 authored by Chris Mason's avatar Chris Mason

Btrfs: fix key checks and advance in the search ioctl

The search ioctl was working well for finding tree roots, but using it for
generic searches requires a few changes to how the keys are advanced.
This treats the search control min fields for objectid, type and offset
more like a key, where we drop the offset to zero once we bump the type,
etc.

The downside of this is that we are changing the min_type and min_offset
fields during the search, and so the ioctl caller needs extra checks to make sure
the keys in the result are the ones it wanted.

This also changes key_in_sk to use btrfs_comp_cpu_keys, just to make
things more readable.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent 7fde62bf
...@@ -914,17 +914,23 @@ out: ...@@ -914,17 +914,23 @@ out:
static noinline int key_in_sk(struct btrfs_key *key, static noinline int key_in_sk(struct btrfs_key *key,
struct btrfs_ioctl_search_key *sk) struct btrfs_ioctl_search_key *sk)
{ {
if (key->objectid < sk->min_objectid) struct btrfs_key test;
return 0; int ret;
if (key->offset < sk->min_offset)
return 0; test.objectid = sk->min_objectid;
if (key->type < sk->min_type) test.type = sk->min_type;
return 0; test.offset = sk->min_offset;
if (key->objectid > sk->max_objectid)
return 0; ret = btrfs_comp_cpu_keys(key, &test);
if (key->type > sk->max_type) if (ret < 0)
return 0; return 0;
if (key->offset > sk->max_offset)
test.objectid = sk->max_objectid;
test.type = sk->max_type;
test.offset = sk->max_offset;
ret = btrfs_comp_cpu_keys(key, &test);
if (ret > 0)
return 0; return 0;
return 1; return 1;
} }
...@@ -998,13 +1004,18 @@ static noinline int copy_to_sk(struct btrfs_root *root, ...@@ -998,13 +1004,18 @@ static noinline int copy_to_sk(struct btrfs_root *root,
break; break;
} }
advance_key: advance_key:
if (key->offset < (u64)-1) ret = 0;
if (key->offset < (u64)-1 && key->offset < sk->max_offset)
key->offset++; key->offset++;
else if (key->type < (u8)-1) else if (key->type < (u8)-1 && key->type < sk->max_type) {
key->offset = 0;
key->type++; key->type++;
else if (key->objectid < (u64)-1) } else if (key->objectid < (u64)-1 && key->objectid < sk->max_objectid) {
key->offset = 0;
key->type = 0;
key->objectid++; key->objectid++;
ret = 0; } else
ret = 1;
overflow: overflow:
*num_found += found; *num_found += found;
return ret; return ret;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment