Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b6e817d authored by Gerhard Heift's avatar Gerhard Heift Committed by Chris Mason
Browse files

btrfs: tree_search, copy_to_sk: return needed size on EOVERFLOW



If an item in tree_search is too large to be stored in the given buffer, return
the needed size (including the header).

Signed-off-by: default avatarGerhard Heift <Gerhard@Heift.Name>
Signed-off-by: default avatarChris Mason <clm@fb.com>
Acked-by: default avatarDavid Sterba <dsterba@suse.cz>
parent 8f5f6178
Loading
Loading
Loading
Loading
+15 −9
Original line number Diff line number Diff line
@@ -1957,7 +1957,7 @@ static noinline int copy_to_sk(struct btrfs_root *root,
			       struct btrfs_path *path,
			       struct btrfs_key *key,
			       struct btrfs_ioctl_search_key *sk,
			       size_t buf_size,
			       size_t *buf_size,
			       char *buf,
			       unsigned long *sk_offset,
			       int *num_found)
@@ -1990,7 +1990,7 @@ static noinline int copy_to_sk(struct btrfs_root *root,
		if (!key_in_sk(key, sk))
			continue;

		if (sizeof(sh) + item_len > buf_size) {
		if (sizeof(sh) + item_len > *buf_size) {
			if (*num_found) {
				ret = 1;
				goto out;
@@ -2001,11 +2001,12 @@ static noinline int copy_to_sk(struct btrfs_root *root,
			 * handle -EOVERFLOW
			 */

			*buf_size = sizeof(sh) + item_len;
			item_len = 0;
			ret = -EOVERFLOW;
		}

		if (sizeof(sh) + item_len + *sk_offset > buf_size) {
		if (sizeof(sh) + item_len + *sk_offset > *buf_size) {
			ret = 1;
			goto out;
		}
@@ -2056,7 +2057,7 @@ static noinline int copy_to_sk(struct btrfs_root *root,

static noinline int search_ioctl(struct inode *inode,
				 struct btrfs_ioctl_search_key *sk,
				 size_t buf_size,
				 size_t *buf_size,
				 char *buf)
{
	struct btrfs_root *root;
@@ -2067,8 +2068,10 @@ static noinline int search_ioctl(struct inode *inode,
	int num_found = 0;
	unsigned long sk_offset = 0;

	if (buf_size < sizeof(struct btrfs_ioctl_search_header))
	if (*buf_size < sizeof(struct btrfs_ioctl_search_header)) {
		*buf_size = sizeof(struct btrfs_ioctl_search_header);
		return -EOVERFLOW;
	}

	path = btrfs_alloc_path();
	if (!path)
@@ -2124,6 +2127,7 @@ static noinline int btrfs_ioctl_tree_search(struct file *file,
	struct btrfs_ioctl_search_args *args;
	struct inode *inode;
	int ret;
	size_t buf_size;

	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
@@ -2132,8 +2136,10 @@ static noinline int btrfs_ioctl_tree_search(struct file *file,
	if (IS_ERR(args))
		return PTR_ERR(args);

	buf_size = sizeof(args->buf);

	inode = file_inode(file);
	ret = search_ioctl(inode, &args->key, sizeof(args->buf), args->buf);
	ret = search_ioctl(inode, &args->key, &buf_size, args->buf);

	/*
	 * In the origin implementation an overflow is handled by returning a