aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAshish Samant <ashish.samant@oracle.com>2016-03-15 00:57:35 -0400
committerMiklos Szeredi <miklos@szeredi.hu>2016-03-16 09:38:31 -0400
commit742f992708dff0ada8b426228900ffb009c7167b (patch)
treedc353b2630af0a033d024f9c96e57027a1edd092
parent744742d692e37ad5c20630e57d526c8f2e2fe3c9 (diff)
fuse: return patrial success from fuse_direct_io()
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>
-rw-r--r--fs/fuse/file.c23
1 files changed, 11 insertions, 12 deletions
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,
1247 size_t *nbytesp, int write) 1247 size_t *nbytesp, int write)
1248{ 1248{
1249 size_t nbytes = 0; /* # bytes already packed in req */ 1249 size_t nbytes = 0; /* # bytes already packed in req */
1250 ssize_t ret = 0;
1250 1251
1251 /* Special case for kernel I/O: can copy directly into the buffer */ 1252 /* Special case for kernel I/O: can copy directly into the buffer */
1252 if (ii->type & ITER_KVEC) { 1253 if (ii->type & ITER_KVEC) {
@@ -1266,13 +1267,12 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
1266 while (nbytes < *nbytesp && req->num_pages < req->max_pages) { 1267 while (nbytes < *nbytesp && req->num_pages < req->max_pages) {
1267 unsigned npages; 1268 unsigned npages;
1268 size_t start; 1269 size_t start;
1269 ssize_t ret = iov_iter_get_pages(ii, 1270 ret = iov_iter_get_pages(ii, &req->pages[req->num_pages],
1270 &req->pages[req->num_pages],
1271 *nbytesp - nbytes, 1271 *nbytesp - nbytes,
1272 req->max_pages - req->num_pages, 1272 req->max_pages - req->num_pages,
1273 &start); 1273 &start);
1274 if (ret < 0) 1274 if (ret < 0)
1275 return ret; 1275 break;
1276 1276
1277 iov_iter_advance(ii, ret); 1277 iov_iter_advance(ii, ret);
1278 nbytes += ret; 1278 nbytes += ret;
@@ -1295,7 +1295,7 @@ static int fuse_get_user_pages(struct fuse_req *req, struct iov_iter *ii,
1295 1295
1296 *nbytesp = nbytes; 1296 *nbytesp = nbytes;
1297 1297
1298 return 0; 1298 return ret;
1299} 1299}
1300 1300
1301static inline int fuse_iter_npages(const struct iov_iter *ii_p) 1301static 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,
1319 pgoff_t idx_to = (pos + count - 1) >> PAGE_CACHE_SHIFT; 1319 pgoff_t idx_to = (pos + count - 1) >> PAGE_CACHE_SHIFT;
1320 ssize_t res = 0; 1320 ssize_t res = 0;
1321 struct fuse_req *req; 1321 struct fuse_req *req;
1322 int err = 0;
1322 1323
1323 if (io->async) 1324 if (io->async)
1324 req = fuse_get_req_for_background(fc, fuse_iter_npages(iter)); 1325 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,
1339 size_t nres; 1340 size_t nres;
1340 fl_owner_t owner = current->files; 1341 fl_owner_t owner = current->files;
1341 size_t nbytes = min(count, nmax); 1342 size_t nbytes = min(count, nmax);
1342 int err = fuse_get_user_pages(req, iter, &nbytes, write); 1343 err = fuse_get_user_pages(req, iter, &nbytes, write);
1343 if (err) { 1344 if (err && !nbytes)
1344 res = err;
1345 break; 1345 break;
1346 }
1347 1346
1348 if (write) 1347 if (write)
1349 nres = fuse_send_write(req, io, pos, nbytes, owner); 1348 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,
1353 if (!io->async) 1352 if (!io->async)
1354 fuse_release_user_pages(req, !write); 1353 fuse_release_user_pages(req, !write);
1355 if (req->out.h.error) { 1354 if (req->out.h.error) {
1356 if (!res) 1355 err = req->out.h.error;
1357 res = req->out.h.error;
1358 break; 1356 break;
1359 } else if (nres > nbytes) { 1357 } else if (nres > nbytes) {
1360 res = -EIO; 1358 res = 0;
1359 err = -EIO;
1361 break; 1360 break;
1362 } 1361 }
1363 count -= nres; 1362 count -= nres;
@@ -1381,7 +1380,7 @@ ssize_t fuse_direct_io(struct fuse_io_priv *io, struct iov_iter *iter,
1381 if (res > 0) 1380 if (res > 0)
1382 *ppos = pos; 1381 *ppos = pos;
1383 1382
1384 return res; 1383 return res > 0 ? res : err;
1385} 1384}
1386EXPORT_SYMBOL_GPL(fuse_direct_io); 1385EXPORT_SYMBOL_GPL(fuse_direct_io);
1387 1386