On Thu, Sep 17, 2020 at 01:42:44PM -0400, Qian Cai wrote:
> > 
> >     How much IO does it take to trigger that on your reproducer?
> 
> That is something I don't know for sure because it is always reproducible by
> running the trinity fuzzer for a few seconds (32 threads). I did another run
> below (still with your patch applied) and then tried to capture some logs 
> here:
> 
> http://people.redhat.com/qcai/iov_iter_revert/

FWIW, there were several bugs in that patch:
        * 'shortened' possibly left uninitialized
        * possible error returns with reexpand not done

Could you try this instead?

Signed-off-by: Al Viro <v...@zeniv.linux.org.uk>
---
diff --git a/fs/fuse/file.c b/fs/fuse/file.c
index 6611ef3269a8..43c165e796da 100644
--- a/fs/fuse/file.c
+++ b/fs/fuse/file.c
@@ -3091,11 +3091,10 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter 
*iter)
        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;
-       size_t count = iov_iter_count(iter);
+       size_t count = iov_iter_count(iter), shortened = 0;
        loff_t offset = iocb->ki_pos;
        struct fuse_io_priv *io;
 
@@ -3103,17 +3102,9 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        inode = file->f_mapping->host;
        i_size = i_size_read(inode);
 
-       if ((iov_iter_rw(iter) == READ) && (offset > i_size))
+       if ((iov_iter_rw(iter) == READ) && (offset >= i_size))
                return 0;
 
-       /* optimization for short read */
-       if (async_dio && iov_iter_rw(iter) != WRITE && offset + count > i_size) 
{
-               if (offset >= i_size)
-                       return 0;
-               iov_iter_truncate(iter, fuse_round_up(ff->fc, i_size - offset));
-               count = iov_iter_count(iter);
-       }
-
        io = kmalloc(sizeof(struct fuse_io_priv), GFP_KERNEL);
        if (!io)
                return -ENOMEM;
@@ -3129,15 +3120,22 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter 
*iter)
         * By default, we want to optimize all I/Os with async request
         * submission to the client filesystem if supported.
         */
-       io->async = async_dio;
+       io->async = ff->fc->async_dio;
        io->iocb = iocb;
        io->blocking = is_sync_kiocb(iocb);
 
+       /* optimization for short read */
+       if (io->async && !io->write && offset + count > i_size) {
+               iov_iter_truncate(iter, fuse_round_up(ff->fc, i_size - offset));
+               shortened = count - iov_iter_count(iter);
+               count -= shortened;
+       }
+
        /*
         * We cannot asynchronously extend the size of a file.
         * In such case the aio will behave exactly like sync io.
         */
-       if ((offset + count > i_size) && iov_iter_rw(iter) == WRITE)
+       if ((offset + count > i_size) && io->write)
                io->blocking = true;
 
        if (io->async && io->blocking) {
@@ -3155,6 +3153,7 @@ fuse_direct_IO(struct kiocb *iocb, struct iov_iter *iter)
        } else {
                ret = __fuse_direct_read(io, iter, &pos);
        }
+       iov_iter_reexpand(iter, iov_iter_count(iter) + shortened);
 
        if (io->async) {
                bool blocking = io->blocking;

Reply via email to