aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
authorMaxim Patlasov <mpatlasov@parallels.com>2012-12-14 10:21:26 -0500
committerMiklos Szeredi <mszeredi@suse.cz>2013-04-17 15:50:59 -0400
commit439ee5f0c5080d4fd15fda0c5bbee1fb3a57894e (patch)
tree457b85c7011dae6de9f64edd673b841a5a3a0596 /fs/fuse/file.c
parentbcba24ccdc82f7415154cf87226c2577cea13a5c (diff)
fuse: optimize short direct reads
If user requested direct read beyond EOF, we can skip sending fuse requests for positions beyond EOF because userspace would ACK them with zero bytes read anyway. We can trust to i_size in fuse_direct_IO for such cases because it's called from fuse_file_aio_read() and the latter updates fuse attributes including i_size. Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r--fs/fuse/file.c19
1 files changed, 13 insertions, 6 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index ba1d50369c24..8f39f7b8cef2 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -1331,7 +1331,8 @@ EXPORT_SYMBOL_GPL(fuse_direct_io);
1331 1331
1332static ssize_t __fuse_direct_read(struct fuse_io_priv *io, 1332static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
1333 const struct iovec *iov, 1333 const struct iovec *iov,
1334 unsigned long nr_segs, loff_t *ppos) 1334 unsigned long nr_segs, loff_t *ppos,
1335 size_t count)
1335{ 1336{
1336 ssize_t res; 1337 ssize_t res;
1337 struct file *file = io->file; 1338 struct file *file = io->file;
@@ -1340,8 +1341,7 @@ static ssize_t __fuse_direct_read(struct fuse_io_priv *io,
1340 if (is_bad_inode(inode)) 1341 if (is_bad_inode(inode))
1341 return -EIO; 1342 return -EIO;
1342 1343
1343 res = fuse_direct_io(io, iov, nr_segs, iov_length(iov, nr_segs), 1344 res = fuse_direct_io(io, iov, nr_segs, count, ppos, 0);
1344 ppos, 0);
1345 1345
1346 fuse_invalidate_attr(inode); 1346 fuse_invalidate_attr(inode);
1347 1347
@@ -1353,7 +1353,7 @@ static ssize_t fuse_direct_read(struct file *file, char __user *buf,
1353{ 1353{
1354 struct fuse_io_priv io = { .async = 0, .file = file }; 1354 struct fuse_io_priv io = { .async = 0, .file = file };
1355 struct iovec iov = { .iov_base = buf, .iov_len = count }; 1355 struct iovec iov = { .iov_base = buf, .iov_len = count };
1356 return __fuse_direct_read(&io, &iov, 1, ppos); 1356 return __fuse_direct_read(&io, &iov, 1, ppos, count);
1357} 1357}
1358 1358
1359static ssize_t __fuse_direct_write(struct fuse_io_priv *io, 1359static ssize_t __fuse_direct_write(struct fuse_io_priv *io,
@@ -2369,6 +2369,13 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
2369 inode = file->f_mapping->host; 2369 inode = file->f_mapping->host;
2370 i_size = i_size_read(inode); 2370 i_size = i_size_read(inode);
2371 2371
2372 /* optimization for short read */
2373 if (rw != WRITE && offset + count > i_size) {
2374 if (offset >= i_size)
2375 return 0;
2376 count = i_size - offset;
2377 }
2378
2372 io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); 2379 io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
2373 if (!io) 2380 if (!io)
2374 return -ENOMEM; 2381 return -ENOMEM;
@@ -2392,13 +2399,13 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
2392 * to wait on real async I/O requests, so we must submit this request 2399 * to wait on real async I/O requests, so we must submit this request
2393 * synchronously. 2400 * synchronously.
2394 */ 2401 */
2395 if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE) 2402 if (!is_sync_kiocb(iocb) && (offset + count > i_size))
2396 io->async = false; 2403 io->async = false;
2397 2404
2398 if (rw == WRITE) 2405 if (rw == WRITE)
2399 ret = __fuse_direct_write(io, iov, nr_segs, &pos); 2406 ret = __fuse_direct_write(io, iov, nr_segs, &pos);
2400 else 2407 else
2401 ret = __fuse_direct_read(io, iov, nr_segs, &pos); 2408 ret = __fuse_direct_read(io, iov, nr_segs, &pos, count);
2402 2409
2403 if (io->async) { 2410 if (io->async) {
2404 fuse_aio_complete(io, ret < 0 ? ret : 0, -1); 2411 fuse_aio_complete(io, ret < 0 ? ret : 0, -1);