Commit e5c5f05dca0cf90f0f3bb1aea85dcf658baff185
Committed by
Miklos Szeredi
1 parent
c9ecf989cc
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>
Showing 1 changed file with 10 additions and 4 deletions Side-by-side Diff
fs/fuse/file.c
... | ... | @@ -2373,6 +2373,11 @@ |
2373 | 2373 | fuse_do_setattr(inode, &attr, file); |
2374 | 2374 | } |
2375 | 2375 | |
2376 | +static inline loff_t fuse_round_up(loff_t off) | |
2377 | +{ | |
2378 | + return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT); | |
2379 | +} | |
2380 | + | |
2376 | 2381 | static ssize_t |
2377 | 2382 | fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov, |
2378 | 2383 | loff_t offset, unsigned long nr_segs) |
... | ... | @@ -2380,6 +2385,7 @@ |
2380 | 2385 | ssize_t ret = 0; |
2381 | 2386 | struct file *file = iocb->ki_filp; |
2382 | 2387 | struct fuse_file *ff = file->private_data; |
2388 | + bool async_dio = ff->fc->async_dio; | |
2383 | 2389 | loff_t pos = 0; |
2384 | 2390 | struct inode *inode; |
2385 | 2391 | loff_t i_size; |
2386 | 2392 | |
... | ... | @@ -2391,10 +2397,10 @@ |
2391 | 2397 | i_size = i_size_read(inode); |
2392 | 2398 | |
2393 | 2399 | /* optimization for short read */ |
2394 | - if (rw != WRITE && offset + count > i_size) { | |
2400 | + if (async_dio && rw != WRITE && offset + count > i_size) { | |
2395 | 2401 | if (offset >= i_size) |
2396 | 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 | 2406 | io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL); |
... | ... | @@ -2412,7 +2418,7 @@ |
2412 | 2418 | * By default, we want to optimize all I/Os with async request |
2413 | 2419 | * submission to the client filesystem if supported. |
2414 | 2420 | */ |
2415 | - io->async = ff->fc->async_dio; | |
2421 | + io->async = async_dio; | |
2416 | 2422 | io->iocb = iocb; |
2417 | 2423 | |
2418 | 2424 | /* |
... | ... | @@ -2420,7 +2426,7 @@ |
2420 | 2426 | * to wait on real async I/O requests, so we must submit this request |
2421 | 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 | 2430 | io->async = false; |
2425 | 2431 | |
2426 | 2432 | if (rw == WRITE) |