diff options
author | Chris Mason <chris.mason@oracle.com> | 2010-03-18 12:10:08 -0400 |
---|---|---|
committer | Chris Mason <chris.mason@oracle.com> | 2010-03-18 12:10:08 -0400 |
commit | abc6e1341bda974e2d0eddb75f57a20ac18e9b33 (patch) | |
tree | 399e587e8e94dd4ec2894f52f377a189a21ece2a /fs/btrfs/ioctl.c | |
parent | 7fde62bffb576d384ea49a3aed3403d5609ee5bc (diff) |
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: Chris Mason <chris.mason@oracle.com>
Diffstat (limited to 'fs/btrfs/ioctl.c')
-rw-r--r-- | fs/btrfs/ioctl.c | 39 |
1 files changed, 25 insertions, 14 deletions
diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c index 4329610b141b..291aa51ff420 100644 --- a/fs/btrfs/ioctl.c +++ b/fs/btrfs/ioctl.c | |||
@@ -914,17 +914,23 @@ out: | |||
914 | static noinline int key_in_sk(struct btrfs_key *key, | 914 | static noinline int key_in_sk(struct btrfs_key *key, |
915 | struct btrfs_ioctl_search_key *sk) | 915 | struct btrfs_ioctl_search_key *sk) |
916 | { | 916 | { |
917 | if (key->objectid < sk->min_objectid) | 917 | struct btrfs_key test; |
918 | return 0; | 918 | int ret; |
919 | if (key->offset < sk->min_offset) | 919 | |
920 | return 0; | 920 | test.objectid = sk->min_objectid; |
921 | if (key->type < sk->min_type) | 921 | test.type = sk->min_type; |
922 | return 0; | 922 | test.offset = sk->min_offset; |
923 | if (key->objectid > sk->max_objectid) | 923 | |
924 | return 0; | 924 | ret = btrfs_comp_cpu_keys(key, &test); |
925 | if (key->type > sk->max_type) | 925 | if (ret < 0) |
926 | return 0; | 926 | return 0; |
927 | if (key->offset > sk->max_offset) | 927 | |
928 | test.objectid = sk->max_objectid; | ||
929 | test.type = sk->max_type; | ||
930 | test.offset = sk->max_offset; | ||
931 | |||
932 | ret = btrfs_comp_cpu_keys(key, &test); | ||
933 | if (ret > 0) | ||
928 | return 0; | 934 | return 0; |
929 | return 1; | 935 | return 1; |
930 | } | 936 | } |
@@ -998,13 +1004,18 @@ static noinline int copy_to_sk(struct btrfs_root *root, | |||
998 | break; | 1004 | break; |
999 | } | 1005 | } |
1000 | advance_key: | 1006 | advance_key: |
1001 | if (key->offset < (u64)-1) | 1007 | ret = 0; |
1008 | if (key->offset < (u64)-1 && key->offset < sk->max_offset) | ||
1002 | key->offset++; | 1009 | key->offset++; |
1003 | else if (key->type < (u8)-1) | 1010 | else if (key->type < (u8)-1 && key->type < sk->max_type) { |
1011 | key->offset = 0; | ||
1004 | key->type++; | 1012 | key->type++; |
1005 | else if (key->objectid < (u64)-1) | 1013 | } else if (key->objectid < (u64)-1 && key->objectid < sk->max_objectid) { |
1014 | key->offset = 0; | ||
1015 | key->type = 0; | ||
1006 | key->objectid++; | 1016 | key->objectid++; |
1007 | ret = 0; | 1017 | } else |
1018 | ret = 1; | ||
1008 | overflow: | 1019 | overflow: |
1009 | *num_found += found; | 1020 | *num_found += found; |
1010 | return ret; | 1021 | return ret; |