Btrfs: fix key checks and advance in the search ioctl
authorChris Mason <chris.mason@oracle.com>
Thu, 18 Mar 2010 16:10:08 +0000 (12:10 -0400)
committerChris Mason <chris.mason@oracle.com>
Thu, 18 Mar 2010 16:10:08 +0000 (12:10 -0400)
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>
fs/btrfs/ioctl.c

index 4329610..291aa51 100644 (file)
@@ -914,17 +914,23 @@ out:
 static noinline int key_in_sk(struct btrfs_key *key,
                              struct btrfs_ioctl_search_key *sk)
 {
-       if (key->objectid < sk->min_objectid)
-               return 0;
-       if (key->offset < sk->min_offset)
-               return 0;
-       if (key->type < sk->min_type)
-               return 0;
-       if (key->objectid > sk->max_objectid)
-               return 0;
-       if (key->type > sk->max_type)
+       struct btrfs_key test;
+       int ret;
+
+       test.objectid = sk->min_objectid;
+       test.type = sk->min_type;
+       test.offset = sk->min_offset;
+
+       ret = btrfs_comp_cpu_keys(key, &test);
+       if (ret < 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 1;
 }
@@ -998,13 +1004,18 @@ static noinline int copy_to_sk(struct btrfs_root *root,
                        break;
        }
 advance_key:
-       if (key->offset < (u64)-1)
+       ret = 0;
+       if (key->offset < (u64)-1 && key->offset < sk->max_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++;
-       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++;
-       ret = 0;
+       } else
+               ret = 1;
 overflow:
        *num_found += found;
        return ret;