* [PATCH] fuse: fix alignment in short read optimization for async_dio
@ 2013-05-30 12:41 Maxim Patlasov
2013-05-30 19:31 ` Brian Foster
0 siblings, 1 reply; 2+ messages in thread
From: Maxim Patlasov @ 2013-05-30 12:41 UTC (permalink / raw)
To: miklos; +Cc: fuse-devel, bfoster, linux-kernel, devel
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>
---
fs/fuse/file.c | 14 ++++++++++----
1 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index d1c9b85..9026572 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -2365,6 +2365,11 @@ static void fuse_do_truncate(struct file *file)
fuse_do_setattr(inode, &attr, file);
}
+static inline loff_t fuse_round_up(loff_t off)
+{
+ return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
+}
+
static ssize_t
fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
loff_t offset, unsigned long nr_segs)
@@ -2372,6 +2377,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
ssize_t ret = 0;
struct file *file = iocb->ki_filp;
struct fuse_file *ff = file->private_data;
+ bool async_dio = ff->fc->async_dio;
loff_t pos = 0;
struct inode *inode;
loff_t i_size;
@@ -2383,10 +2389,10 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
i_size = i_size_read(inode);
/* optimization for short read */
- if (rw != WRITE && offset + count > i_size) {
+ if (async_dio && rw != WRITE && offset + count > i_size) {
if (offset >= i_size)
return 0;
- count = i_size - offset;
+ count = min_t(loff_t, count, fuse_round_up(i_size - offset));
}
io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
@@ -2404,7 +2410,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
* By default, we want to optimize all I/Os with async request
* submission to the client filesystem if supported.
*/
- io->async = ff->fc->async_dio;
+ io->async = async_dio;
io->iocb = iocb;
/*
@@ -2412,7 +2418,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
* to wait on real async I/O requests, so we must submit this request
* synchronously.
*/
- if (!is_sync_kiocb(iocb) && (offset + count > i_size))
+ if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE)
io->async = false;
if (rw == WRITE)
^ permalink raw reply related [flat|nested] 2+ messages in thread
* Re: [PATCH] fuse: fix alignment in short read optimization for async_dio
2013-05-30 12:41 [PATCH] fuse: fix alignment in short read optimization for async_dio Maxim Patlasov
@ 2013-05-30 19:31 ` Brian Foster
0 siblings, 0 replies; 2+ messages in thread
From: Brian Foster @ 2013-05-30 19:31 UTC (permalink / raw)
To: Maxim Patlasov; +Cc: miklos, fuse-devel, linux-kernel, devel
On 05/30/2013 08:41 AM, Maxim Patlasov wrote:
> 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>
> ---
Looks good and passes my tests. Thanks for cooking this up Maxim!
Reviewed-by: Brian Foster <bfoster@redhat.com>
> fs/fuse/file.c | 14 ++++++++++----
> 1 files changed, 10 insertions(+), 4 deletions(-)
>
> diff --git a/fs/fuse/file.c b/fs/fuse/file.c
> index d1c9b85..9026572 100644
> --- a/fs/fuse/file.c
> +++ b/fs/fuse/file.c
> @@ -2365,6 +2365,11 @@ static void fuse_do_truncate(struct file *file)
> fuse_do_setattr(inode, &attr, file);
> }
>
> +static inline loff_t fuse_round_up(loff_t off)
> +{
> + return round_up(off, FUSE_MAX_PAGES_PER_REQ << PAGE_SHIFT);
> +}
> +
> static ssize_t
> fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
> loff_t offset, unsigned long nr_segs)
> @@ -2372,6 +2377,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
> ssize_t ret = 0;
> struct file *file = iocb->ki_filp;
> struct fuse_file *ff = file->private_data;
> + bool async_dio = ff->fc->async_dio;
> loff_t pos = 0;
> struct inode *inode;
> loff_t i_size;
> @@ -2383,10 +2389,10 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
> i_size = i_size_read(inode);
>
> /* optimization for short read */
> - if (rw != WRITE && offset + count > i_size) {
> + if (async_dio && rw != WRITE && offset + count > i_size) {
> if (offset >= i_size)
> return 0;
> - count = i_size - offset;
> + count = min_t(loff_t, count, fuse_round_up(i_size - offset));
> }
>
> io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
> @@ -2404,7 +2410,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
> * By default, we want to optimize all I/Os with async request
> * submission to the client filesystem if supported.
> */
> - io->async = ff->fc->async_dio;
> + io->async = async_dio;
> io->iocb = iocb;
>
> /*
> @@ -2412,7 +2418,7 @@ fuse_direct_IO(int rw, struct kiocb *iocb, const struct iovec *iov,
> * to wait on real async I/O requests, so we must submit this request
> * synchronously.
> */
> - if (!is_sync_kiocb(iocb) && (offset + count > i_size))
> + if (!is_sync_kiocb(iocb) && (offset + count > i_size) && rw == WRITE)
> io->async = false;
>
> if (rw == WRITE)
>
^ permalink raw reply [flat|nested] 2+ messages in thread
end of thread, other threads:[~2013-05-30 19:34 UTC | newest]
Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-05-30 12:41 [PATCH] fuse: fix alignment in short read optimization for async_dio Maxim Patlasov
2013-05-30 19:31 ` Brian Foster
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox