• Maxim Patlasov's avatar
    fuse: fix race in fuse_writepages() · 2d033eaa
    Maxim Patlasov authored
    
    
    The patch fixes a race between ftruncate(2), mmap-ed write and write(2):
    
    1) An user makes a page dirty via mmap-ed write.
    2) The user performs shrinking truncate(2) intended to purge the page.
    3) Before fuse_do_setattr calls truncate_pagecache, the page goes to
       writeback. fuse_writepages_fill attaches a new page to FUSE_WRITE request,
       then releases the original page by end_page_writeback and unlock it.
    4) fuse_do_setattr completes and successfully returns. Since now, i_mutex
       is free.
    5) Ordinary write(2) extends i_size back to cover the page. Note that
       fuse_send_write_pages do wait for fuse writeback, but for another
       page->index.
    6) fuse_writepages_fill attaches more pages to the request (if any), then
       fuse_writepages_send is eventually called. It is supposed to crop
       inarg->size of the request, but it doesn't because i_size has already been
       extended back.
    
    Moving end_page_writeback behind fuse_writepages_send guarantees that
    __fuse_release_nowrite (called from fuse_do_setattr) will crop inarg->size
    of the request before write(2) gets the chance to extend i_size.
    
    Signed-off-by: default avatarMaxim Patlasov <mpatlasov@parallels.com>
    Signed-off-by: default avatarMiklos Szeredi <mszeredi@suse.cz>
    2d033eaa