In copy_to_sk, if an item is too large for the given buffer, it now returns
-EOVERFLOW instead of copying a search_header with len = 0. For backward
compatibility for the first item it still copies such a header to the buffer,
but not any other following items, which could have fitted.

tree_search changes -EOVERFLOW back to 0 to behave similiar to the way it
behaved before this patch.

Signed-off-by: Gerhard Heift <gerh...@heift.name>
---
 fs/btrfs/ioctl.c | 28 ++++++++++++++++++++++++++--
 1 file changed, 26 insertions(+), 2 deletions(-)

diff --git a/fs/btrfs/ioctl.c b/fs/btrfs/ioctl.c
index 6aa79e0..04e1a98 100644
--- a/fs/btrfs/ioctl.c
+++ b/fs/btrfs/ioctl.c
@@ -1887,8 +1887,20 @@ 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 overflow;
+                       }
+
+                       /*
+                        * return one empty item back for v1, which does not
+                        * handle -EOVERFLOW
+                        */
+
                        item_len = 0;
+                       ret = -EOVERFLOW;
+               }
 
                if (sizeof(sh) + item_len + *sk_offset > buf_size) {
                        ret = 1;
@@ -1914,6 +1926,9 @@ static noinline int copy_to_sk(struct btrfs_root *root,
                }
                (*num_found)++;
 
+               if (ret) /* -EOVERFLOW from above */
+                       goto overflow;
+
                if (*num_found >= sk->nr_items)
                        break;
        }
@@ -1990,7 +2005,8 @@ static noinline int search_ioctl(struct inode *inode,
                        break;
 
        }
-       ret = 0;
+       if (ret > 0)
+               ret = 0;
 err:
        sk->nr_items = num_found;
        btrfs_free_path(path);
@@ -2013,6 +2029,14 @@ static noinline int btrfs_ioctl_tree_search(struct file 
*file,
 
        inode = file_inode(file);
        ret = search_ioctl(inode, &args->key, sizeof(args->buf), args->buf);
+
+       /*
+        * In the origin implementation an overflow is handled by returning a
+        * search header with a len of zero, so reset ret.
+        */
+       if (ret == -EOVERFLOW)
+               ret = 0;
+
        if (ret == 0 && copy_to_user(argp, args, sizeof(*args)))
                ret = -EFAULT;
        kfree(args);
-- 
1.8.5.3

--
To unsubscribe from this list: send the line "unsubscribe linux-btrfs" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to