|
@@ -2172,6 +2172,45 @@ static noinline int btrfs_ioctl_tree_search(struct file *file,
|
|
|
return ret;
|
|
|
}
|
|
|
|
|
|
+static noinline int btrfs_ioctl_tree_search_v2(struct file *file,
|
|
|
+ void __user *argp)
|
|
|
+{
|
|
|
+ struct btrfs_ioctl_search_args_v2 __user *uarg;
|
|
|
+ struct btrfs_ioctl_search_args_v2 args;
|
|
|
+ struct inode *inode;
|
|
|
+ int ret;
|
|
|
+ size_t buf_size;
|
|
|
+ const size_t buf_limit = 16 * 1024 * 1024;
|
|
|
+
|
|
|
+ if (!capable(CAP_SYS_ADMIN))
|
|
|
+ return -EPERM;
|
|
|
+
|
|
|
+ /* copy search header and buffer size */
|
|
|
+ uarg = (struct btrfs_ioctl_search_args_v2 __user *)argp;
|
|
|
+ if (copy_from_user(&args, uarg, sizeof(args)))
|
|
|
+ return -EFAULT;
|
|
|
+
|
|
|
+ buf_size = args.buf_size;
|
|
|
+
|
|
|
+ if (buf_size < sizeof(struct btrfs_ioctl_search_header))
|
|
|
+ return -EOVERFLOW;
|
|
|
+
|
|
|
+ /* limit result size to 16MB */
|
|
|
+ if (buf_size > buf_limit)
|
|
|
+ buf_size = buf_limit;
|
|
|
+
|
|
|
+ inode = file_inode(file);
|
|
|
+ ret = search_ioctl(inode, &args.key, &buf_size,
|
|
|
+ (char *)(&uarg->buf[0]));
|
|
|
+ if (ret == 0 && copy_to_user(&uarg->key, &args.key, sizeof(args.key)))
|
|
|
+ ret = -EFAULT;
|
|
|
+ else if (ret == -EOVERFLOW &&
|
|
|
+ copy_to_user(&uarg->buf_size, &buf_size, sizeof(buf_size)))
|
|
|
+ ret = -EFAULT;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/*
|
|
|
* Search INODE_REFs to identify path name of 'dirid' directory
|
|
|
* in a 'tree_id' tree. and sets path name to 'name'.
|
|
@@ -5252,6 +5291,8 @@ long btrfs_ioctl(struct file *file, unsigned int
|
|
|
return btrfs_ioctl_trans_end(file);
|
|
|
case BTRFS_IOC_TREE_SEARCH:
|
|
|
return btrfs_ioctl_tree_search(file, argp);
|
|
|
+ case BTRFS_IOC_TREE_SEARCH_V2:
|
|
|
+ return btrfs_ioctl_tree_search_v2(file, argp);
|
|
|
case BTRFS_IOC_INO_LOOKUP:
|
|
|
return btrfs_ioctl_ino_lookup(file, argp);
|
|
|
case BTRFS_IOC_INO_PATHS:
|