• Filipe Manana's avatar
    btrfs: fix deadlock when cloning inline extents and low on available space · 76a6d5cd
    Filipe Manana authored
    There are a few cases where cloning an inline extent requires copying data
    into a page of the destination inode. For these cases we are allocating
    the required data and metadata space while holding a leaf locked. This can
    result in a deadlock when we are low on available space because allocating
    the space may flush delalloc and two deadlock scenarios can happen:
    
    1) When starting writeback for an inode with a very small dirty range that
       fits in an inline extent, we deadlock during the writeback when trying
       to insert the inline extent, at cow_file_range_inline(), if the extent
       is going to be located in the leaf for which we are already holding a
       read lock;
    
    2) After successfully starting writeback, for non-inline extent cases,
       the async reclaim thread will hang waiting for an ordered extent to
       complete if the ordered extent completion needs to modify the leaf
       for which the clone task is holding a read lock (for adding or
       replacing file extent items). So the cloning task will wait forever
       on the async reclaim thread to make progress, which in turn is
       waiting for the ordered extent completion which in turn is waiting
       to acquire a write lock on the same leaf.
    
    So fix this by making sure we release the path (and therefore the leaf)
    every time we need to copy the inline extent's data into a page of the
    destination inode, as by that time we do not need to have the leaf locked.
    
    Fixes: 05a5a762 ("Btrfs: implement full reflink support for inline extents")
    CC: stable@vger.kernel.org # 5.10+
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    76a6d5cd
reflink.c 27.2 KB