@@ -1134,11 +1134,11 @@ advance_key:
if (key->offset < (u64)-1 && key->offset < sk->max_offset)
key->offset++;
else if (key->type < (u8)-1 && key->type < sk->max_type) {
- key->offset = 0;
+ key->offset = sk->min_offset;
key->type++;
} else if (key->objectid < (u64)-1 && key->objectid < sk-
>max_objectid) {
- key->offset = 0;
- key->type = 0;
+ key->offset = sk->min_offset;
+ key->type = sk->min_type;
key->objectid++;
} else
ret = 1;
@@ -1180,9 +1180,9 @@ static noinline int search_ioctl(struct inode *inode,
}
}
- key.objectid = sk->min_objectid;
- key.type = sk->min_type;
- key.offset = sk->min_offset;
+ key.objectid = max(sk->start_objectid, sk->min_objectid);
+ key.type = max(sk->start_type,sk->min_type);
+ key.offset = max(sk->start_offset, sk->min_offset);
max_key.objectid = sk->max_objectid;
max_key.type = sk->max_type;
@@ -1207,6 +1207,11 @@ static noinline int search_ioctl(struct inode *inode,
}
ret = 0;
err:
+ /* save the key for an hypothetic next iteration */
+ sk->start_objectid = key.objectid;
+ sk->start_type = key.type;
+ sk->start_offset = key.offset;
+
sk->nr_items = num_found;
btrfs_free_path(path);
return ret;
@@ -1234,6 +1239,39 @@ static noinline int btrfs_ioctl_tree_search(struct file
*file,
return ret;
}
+static noinline int btrfs_ioctl_tree_search_old(struct file *file,
+ void __user *argp)
+{
+ struct btrfs_ioctl_search_args *args;
+ struct inode *inode;
+ int ret;
+
+ printk(KERN_WARNING "BTRFS: Pid=%d(%s) is using the buggy "
+ "BTRFS_IOC_TREE_SEARCH_V0 ioctl\n",
+ current->pid, current->comm);
+
+ if (!capable(CAP_SYS_ADMIN))
+ return -EPERM;
+
+ args = memdup_user(argp, sizeof(*args));
+ if (IS_ERR(args))
+ return PTR_ERR(args);
+
+ inode = fdentry(file)->d_inode;
+
+ /* for compatibility */
+ args->key.start_objectid = 0;
+ args->key.start_type = 0;
+ args->key.start_offset = 0;
+
+ ret = search_ioctl(inode, args);
+ if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
+ ret = -EFAULT;
+ kfree(args);
+ return ret;
+}
+
+
/*
* Search INODE_REFs to identify path name of 'dirid' directory
* in a 'tree_id' tree. and sets path name to 'name'.
@@ -2286,6 +2324,8 @@ long btrfs_ioctl(struct file *file, unsigned int
return btrfs_ioctl_trans_start(file);
case BTRFS_IOC_TRANS_END:
return btrfs_ioctl_trans_end(file);
+ case BTRFS_IOC_TREE_SEARCH_V0:
+ return btrfs_ioctl_tree_search_old(file, argp);
case BTRFS_IOC_TREE_SEARCH:
return btrfs_ioctl_tree_search(file, argp);
case BTRFS_IOC_INO_LOOKUP:
@@ -74,12 +74,12 @@ struct btrfs_ioctl_search_key {
*/
__u32 nr_items;
- /* align to 64 bits */
- __u32 unused;
+ /* starting search key fields */
+ __u32 start_type;
+ __u64 start_objectid;
+ __u64 start_offset;
/* some extra for later */
- __u64 unused1;
- __u64 unused2;
__u64 unused3;
__u64 unused4;
};
@@ -182,7 +182,12 @@ struct btrfs_ioctl_space_args {
struct btrfs_ioctl_vol_args)
#define BTRFS_IOC_DEFRAG_RANGE _IOW(BTRFS_IOCTL_MAGIC, 16, \
struct btrfs_ioctl_defrag_range_args)
-#define BTRFS_IOC_TREE_SEARCH _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+
+/* buggy, don't use */
+
+#define BTRFS_IOC_TREE_SEARCH_V0 _IOWR(BTRFS_IOCTL_MAGIC, 17, \
+ struct btrfs_ioctl_search_args)
+#define BTRFS_IOC_TREE_SEARCH_V1 _IOWR(BTRFS_IOCTL_MAGIC, 25, \
struct btrfs_ioctl_search_args)
#define BTRFS_IOC_INO_LOOKUP _IOWR(BTRFS_IOCTL_MAGIC, 18, \
struct btrfs_ioctl_ino_lookup_args)