Commit 7df1e988 authored by Miklos Szeredi's avatar Miklos Szeredi

fuse: fix fuse_send_readpages() in the syncronous read case

Buffered read in fuse normally goes via:

 -> generic_file_buffered_read()
   -> fuse_readpages()
     -> fuse_send_readpages()
       ->fuse_simple_request() [called since v5.4]

In the case of a read request, fuse_simple_request() will return a
non-negative bytecount on success or a negative error value.  A positive
bytecount was taken to be an error and the PG_error flag set on the page.
This resulted in generic_file_buffered_read() falling back to ->readpage(),
which would repeat the read request and succeed.  Because of the repeated
read succeeding the bug was not detected with regression tests or other use
cases.

The FTP module in GVFS however fails the second read due to the
non-seekable nature of FTP downloads.

Fix by checking and ignoring positive return value from
fuse_simple_request().
Reported-by: default avatarOndrej Holy <oholy@redhat.com>
Link: https://gitlab.gnome.org/GNOME/gvfs/issues/441
Fixes: 134831e3 ("fuse: convert readpages to simple api")
Cc: <stable@vger.kernel.org> # v5.4
Signed-off-by: default avatarMiklos Szeredi <mszeredi@redhat.com>
parent e42617b8
...@@ -882,6 +882,7 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file) ...@@ -882,6 +882,7 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
struct fuse_args_pages *ap = &ia->ap; struct fuse_args_pages *ap = &ia->ap;
loff_t pos = page_offset(ap->pages[0]); loff_t pos = page_offset(ap->pages[0]);
size_t count = ap->num_pages << PAGE_SHIFT; size_t count = ap->num_pages << PAGE_SHIFT;
ssize_t res;
int err; int err;
ap->args.out_pages = true; ap->args.out_pages = true;
...@@ -896,7 +897,8 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file) ...@@ -896,7 +897,8 @@ static void fuse_send_readpages(struct fuse_io_args *ia, struct file *file)
if (!err) if (!err)
return; return;
} else { } else {
err = fuse_simple_request(fc, &ap->args); res = fuse_simple_request(fc, &ap->args);
err = res < 0 ? res : 0;
} }
fuse_readpages_end(fc, &ap->args, err); fuse_readpages_end(fc, &ap->args, err);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment