• Chris Mason's avatar
    Btrfs: fix regressions in copy_from_user handling · b1bf862e
    Chris Mason authored
    Commit 914ee295 fixed deadlocks in
    btrfs_file_write where we would catch page faults on pages we had
    locked.
    
    But, there were a few problems:
    
    1) The x86-32 iov_iter_copy_from_user_atomic code always fails to copy
    data when the amount to copy is more than 4K and the offset to start
    copying from is not page aligned.  The result was btrfs_file_write
    looping forever retrying the iov_iter_copy_from_user_atomic
    
    We deal with this by changing btrfs_file_write to drop down to single
    page copies when iov_iter_copy_from_user_atomic starts returning failure.
    
    2) The btrfs_file_write code was leaking delalloc reservations when
    iov_iter_copy_from_user_atomic returned zero.  The looping above would
    result in the entire filesystem running out of delalloc reservations and
    constantly trying to flush things to disk.
    
    3) btrfs_file_write will lock down page cache pages, make sure
    any writeback is finished, do the copy_from_user and then release them.
    Before the loop runs we check the first and last pages in the write to
    see if they are only being partially modified.  If the start or end of
    the write isn't aligned, we make sure the corresponding pages are
    up to date so that we don't introduce garbage into the file.
    
    With the copy_from_user changes, we're allowing the VM to reclaim the
    pages after a partial update from copy_from_user, but we're not
    making sure the page cache page is up to date when we loop around to
    resume the write.
    
    We deal with this by pushing the up to date checks down into the page
    prep code.  This fits better with how the rest of file_write works.
    Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
    Reported-by: default avatarMitch Harder <mitch.harder@sabayonlinux.org>
    cc: stable@kernel.org
    b1bf862e
file.c 33.5 KB