aboutsummaryrefslogtreecommitdiffstats
path: root/fs/fuse/file.c
diff options
context:
space:
mode:
authorMaxim Patlasov <mpatlasov@parallels.com>2013-05-30 08:41:34 -0400
committerMiklos Szeredi <mszeredi@suse.cz>2013-06-03 09:15:42 -0400
commite5c5f05dca0cf90f0f3bb1aea85dcf658baff185 (patch)
treed6290697847d61da2c4a183d9ea521989a814a43 /fs/fuse/file.c
parentc9ecf989cc7626e9edf8abef79f64b909542129b (diff)
fuse: fix alignment in short read optimization for async_dio
The bug was introduced with async_dio feature: trying to optimize short reads, we cut number-of-bytes-to-read to i_size boundary. Hence the following example: truncate --size=300 /mnt/file dd if=/mnt/file of=/dev/null iflag=direct led to FUSE_READ request of 300 bytes size. This turned out to be problem for userspace fuse implementations who rely on assumption that kernel fuse does not change alignment of request from client FS. The patch turns off the optimization if async_dio is disabled. And, if it's enabled, the patch fixes adjustment of number-of-bytes-to-read to preserve alignment. Note, that we cannot throw out short read optimization entirely because otherwise a direct read of a huge size issued on a tiny file would generate a huge amount of fuse requests and most of them would be ACKed by userspace with zero bytes read. Signed-off-by: Maxim Patlasov <MPatlasov@parallels.com> Reviewed-by: Brian Foster <bfoster@redhat.com> Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
Diffstat (limited to 'fs/fuse/file.c')
-rw-r--r--fs/fuse/file.c14
1 files changed, 10 insertions, 4 deletions
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index b3ad8d61a162..e570081f9f76 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2373,6 +2373,11 @@ static void fuse_do_truncate(struct file *file)
2373 fuse_do_setattr(inode, &attr, file); 2373 fuse_do_setattr(inode, &attr, file);
2374} 2374}
2375 2375
2376static inline loff_t fuse_round_up(loff_t off)
2377{
2378 return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
2379}
2380
2376static ssize_t 2381static ssize_t
2377fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, 2382fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
2378 loff_t offset, unsigned long nr_segs) 2383 loff_t offset, unsigned long nr_segs)
@@ -2380,6 +2385,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
2380 ssize_t ret = 0; 2385 ssize_t ret = 0;
2381 struct file *file = iocb->ki_filp; 2386 struct file *file = iocb->ki_filp;
2382 struct fuse_file *ff = file->private_data; 2387 struct fuse_file *ff = file->private_data;
2388 bool async_dio = ff->fc->async_dio;
2383 loff_t pos = 0; 2389 loff_t pos = 0;
2384 struct inode *inode; 2390 struct inode *inode;
2385 loff_t i_size; 2391 loff_t i_size;
@@ -2391,10 +2397,10 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
2391 i_size = i_size_read(inode); 2397 i_size = i_size_read(inode);
2392 2398
2393 /* optimization for short read */ 2399 /* optimization for short read */
2394 if (rw != WRITE && offset + count > i_size) { 2400 if (async_dio && rw != WRITE && offset + count > i_size) {
2395 if (offset >= i_size) 2401 if (offset >= i_size)
2396 return 0; 2402 return 0;
2397 count = i_size - offset; 2403 count = min_t(loff_t, count, fuse_round_up(i_size - offset));
2398 } 2404 }
2399 2405
2400 io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); 2406 io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
@@ -2412,7 +2418,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
2412 * By default, we want to optimize all I/Os with async request 2418 * By default, we want to optimize all I/Os with async request
2413 * submission to the client filesystem if supported. 2419 * submission to the client filesystem if supported.
2414 */ 2420 */
2415 io->async = ff->fc->async_dio; 2421 io->async = async_dio;
2416 io->iocb = iocb; 2422 io->iocb = iocb;
2417 2423
2418 /* 2424 /*
@@ -2420,7 +2426,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
2420 * to wait on real async I/O requests, so we must submit this request 2426 * to wait on real async I/O requests, so we must submit this request
2421 * synchronously. 2427 * synchronously.
2422 */ 2428 */
2423 if (!is_sync_kiocb(iocb) && (offset + count > i_size)) 2429 if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE)
2424 io->async = false; 2430 io->async = false;
2425 2431
2426 if (rw == WRITE) 2432 if (rw == WRITE)