lkml.org 
[lkml]   [2020]   [Oct]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 5.8 36/85] fuse: fix the ->direct_IO() treatment of iov_iter
    Date
    From: Al Viro <viro@zeniv.linux.org.uk>

    [ Upstream commit 933a3752babcf6513117d5773d2b70782d6ad149 ]

    the callers rely upon having any iov_iter_truncate() done inside
    ->direct_IO() countered by iov_iter_reexpand().

    Reported-by: Qian Cai <cai@redhat.com>
    Tested-by: Qian Cai <cai@redhat.com>
    Signed-off-by: Al Viro <viro@zeniv.linux.org.uk>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    fs/fuse/file.c | 25 ++++++++++++-------------
    1 file changed, 12 insertions(+), 13 deletions(-)

    diff --git a/fs/fuse/file.c b/fs/fuse/file.c
    index 83d917f7e5425..98e170cc0b932 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;
    --
    2.25.1


    \
     
     \ /
      Last update: 2020-10-05 17:37    [W:4.185 / U:1.432 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site