• Filipe Manana's avatar
    btrfs: fix RWF_NOWAIT writes blocking on extent locks and waiting for IO · 5dbb75ed
    Filipe Manana authored
    A RWF_NOWAIT write is not supposed to wait on filesystem locks that can be
    held for a long time or for ongoing IO to complete.
    
    However when calling check_can_nocow(), if the inode has prealloc extents
    or has the NOCOW flag set, we can block on extent (file range) locks
    through the call to btrfs_lock_and_flush_ordered_range(). Such lock can
    take a significant amount of time to be available. For example, a fiemap
    task may be running, and iterating through the entire file range checking
    all extents and doing backref walking to determine if they are shared,
    or a readpage operation may be in progress.
    
    Also at btrfs_lock_and_flush_ordered_range(), called by check_can_nocow(),
    after locking the file range we wait for any existing ordered extent that
    is in progress to complete. Another operation that can take a significant
    amount of time and defeat the purpose of RWF_NOWAIT.
    
    So fix this by trying to lock the file range and if it's currently locked
    return -EAGAIN to user space. If we are able to lock the file range without
    waiting and there is an ordered extent in the range, return -EAGAIN as
    well, instead of waiting for it to complete. Finally, don't bother trying
    to lock the snapshot lock of the root when attempting a RWF_NOWAIT write,
    as that is only important for buffered writes.
    
    Fixes: edf064e7 ("btrfs: nowait aio support")
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    5dbb75ed
file.c 94 KB