• Maxim Patlasov's avatar
    fuse: wait for writeback in fuse_file_fallocate() · bde52788
    Maxim Patlasov authored
    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: default avatarMaxim Patlasov <mpatlasov@parallels.com>
    Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
    Cc: stable@vger.kernel.org
    bde52788
file.c 62.5 KB