diff --git a/fs/fuse/file.c b/fs/fuse/file.c index 416108b42412..9dde38f12c07 100644 --- a/fs/fuse/file.c +++ b/fs/fuse/file.c @@ -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) { @@ -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; @@ -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) @@ -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)); @@ -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); @@ -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; @@ -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);