Skip to content

Commit

Permalink
fuse: return patrial success from fuse_direct_io()
Browse files Browse the repository at this point in the history
If a user calls writev/readv in direct io mode with partially valid data
in the iovec array such that any vector other than the first one in the
array contains invalid data, we currently return the error for the invalid
iovec.

Instead, we should return the number of bytes already written/read and not
the error as we do in the non direct_io case.

Reported-by: Alexey Kodanev <alexey.kodanev@oracle.com>
Signed-off-by: Ashish Samant <ashish.samant@oracle.com>
Signed-off-by: Miklos Szeredi <mszeredi@redhat.com>
  • Loading branch information
Ashish Samant authored and Miklos Szeredi committed Mar 16, 2016
1 parent 744742d commit 742f992
Showing 1 changed file with 11 additions and 12 deletions.
23 changes: 11 additions & 12 deletions fs/fuse/file.c
Original file line number Diff line number Diff line change
Expand Up @@ -1247,6 +1247,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
size_t *nbytesp, int write)
{
size_t nbytes = 0; /* # bytes already packed in req */
ssize_t ret = 0;

/* Special case for kernel I/O: can copy directly into the buffer */
if (ii->type & ITER_KVEC) {
Expand All @@ -1266,13 +1267,12 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
while (nbytes < *nbytesp && req->num_pages < req->max_pages) {
unsigned npages;
size_t start;
ssize_t ret = iov_iter_get_pages(ii,
&req->pages[req->num_pages],
ret = iov_iter_get_pages(ii, &req->pages[req->num_pages],
*nbytesp - nbytes,
req->max_pages - req->num_pages,
&start);
if (ret < 0)
return ret;
break;

iov_iter_advance(ii, ret);
nbytes += ret;
Expand All @@ -1295,7 +1295,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,

*nbytesp = nbytes;

return 0;
return ret;
}

static inline int fuse_iter_npages(const struct iov_iter *ii_p)
Expand All @@ -1319,6 +1319,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
pgoff_t idx_to = (pos + count - 1) >> PAGE_CACHE_SHIFT;
ssize_t res = 0;
struct fuse_req *req;
int err = 0;

if (io->async)
req = fuse_get_req_for_background(fc, fuse_iter_npages(iter));
Expand All @@ -1339,11 +1340,9 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
size_t nres;
fl_owner_t owner = current->files;
size_t nbytes = min(count, nmax);
int err = fuse_get_user_pages(req, iter, &nbytes, write);
if (err) {
res = err;
err = fuse_get_user_pages(req, iter, &nbytes, write);
if (err && !nbytes)
break;
}

if (write)
nres = fuse_send_write(req, io, pos, nbytes, owner);
Expand All @@ -1353,11 +1352,11 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
if (!io->async)
fuse_release_user_pages(req, !write);
if (req->out.h.error) {
if (!res)
res = req->out.h.error;
err = req->out.h.error;
break;
} else if (nres > nbytes) {
res = -EIO;
res = 0;
err = -EIO;
break;
}
count -= nres;
Expand All @@ -1381,7 +1380,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
if (res > 0)
*ppos = pos;

return res;
return res > 0 ? res : err;
}
EXPORT_SYMBOL_GPL(fuse_direct_io);

Expand Down

0 comments on commit 742f992

Please sign in to comment.