lkml.org 
[lkml]   [2013]   [Oct]   [11]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[ 057/110] fuse: wait for writeback in fuse_file_fallocate()
    Date
    3.10-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Maxim Patlasov <MPatlasov@parallels.com>

    commit bde52788bdb755b9e4b75db6c434f30e32a0ca0b upstream.

    The patch fixes a race between mmap-ed write and fallocate(PUNCH_HOLE):

    1) An user makes a page dirty via mmap-ed write.
    2) The user performs fallocate(2) with mode == PUNCH_HOLE|KEEP_SIZE
    and <offset, size> covering the page.
    3) Before truncate_pagecache_range call from fuse_file_fallocate,
    the page goes to write-back. The page is fully processed by fuse_writepage
    (including end_page_writeback on the page), but fuse_flush_writepages did
    nothing because fi->writectr < 0.
    4) truncate_pagecache_range is called and fuse_file_fallocate is finishing
    by calling fuse_release_nowrite. The latter triggers processing queued
    write-back request which will write stale data to the hole soon.

    Changed in v2 (thanks to Brian for suggestion):
    - Do not truncate page cache until FUSE_FALLOCATE succeeded. Otherwise,
    we can end up in returning -ENOTSUPP while user data is already punched
    from page cache. Use filemap_write_and_wait_range() instead.
    Changed in v3 (thanks to Miklos for suggestion):
    - fuse_wait_on_writeback() is prone to livelocks; use fuse_set_nowrite()
    instead. So far as we need a dirty-page barrier only, fuse_sync_writes()
    should be enough.
    - rebased to for-linus branch of fuse.git

    Signed-off-by: Maxim Patlasov <mpatlasov@parallels.com>
    Signed-off-by: Miklos Szeredi <mszeredi@suse.cz>
    Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

    ---
    fs/fuse/file.c | 16 ++++++++++------
    1 file changed, 10 insertions(+), 6 deletions(-)

    --- a/fs/fuse/file.c
    +++ b/fs/fuse/file.c
    @@ -2485,8 +2485,15 @@ static long fuse_file_fallocate(struct f

    if (lock_inode) {
    mutex_lock(&inode->i_mutex);
    - if (mode & FALLOC_FL_PUNCH_HOLE)
    - fuse_set_nowrite(inode);
    + if (mode & FALLOC_FL_PUNCH_HOLE) {
    + loff_t endbyte = offset + length - 1;
    + err = filemap_write_and_wait_range(inode->i_mapping,
    + offset, endbyte);
    + if (err)
    + goto out;
    +
    + fuse_sync_writes(inode);
    + }
    }

    req = fuse_get_req_nopages(fc);
    @@ -2521,11 +2528,8 @@ static long fuse_file_fallocate(struct f
    fuse_invalidate_attr(inode);

    out:
    - if (lock_inode) {
    - if (mode & FALLOC_FL_PUNCH_HOLE)
    - fuse_release_nowrite(inode);
    + if (lock_inode)
    mutex_unlock(&inode->i_mutex);
    - }

    return err;
    }



    \
     
     \ /
      Last update: 2013-10-12 00:41    [W:4.059 / U:0.112 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site