• Filipe Manana's avatar
    btrfs: fix deadlock when reserving space during defrag · 0cb5950f
    Filipe Manana authored
    When defragging we can end up collecting a range for defrag that has
    already pages under delalloc (dirty), as long as the respective extent
    map for their range is not mapped to a hole, a prealloc extent or
    the extent map is from an old generation.
    
    Most of the time that is harmless from a functional perspective at
    least, however it can result in a deadlock:
    
    1) At defrag_collect_targets() we find an extent map that meets all
       requirements but there's delalloc for the range it covers, and we add
       its range to list of ranges to defrag;
    
    2) The defrag_collect_targets() function is called at defrag_one_range(),
       after it locked a range that overlaps the range of the extent map;
    
    3) At defrag_one_range(), while the range is still locked, we call
       defrag_one_locked_target() for the range associated to the extent
       map we collected at step 1);
    
    4) Then finally at defrag_one_locked_target() we do a call to
       btrfs_delalloc_reserve_space(), which will reserve data and metadata
       space. If the space reservations can not be satisfied right away, the
       flusher might be kicked in and start flushing delalloc and wait for
       the respective ordered extents to complete. If this happens we will
       deadlock, because both flushing delalloc and finishing an ordered
       extent, requires locking the range in the inode's io tree, which was
       already locked at defrag_collect_targets().
    
    So fix this by skipping extent maps for which there's already delalloc.
    
    Fixes: eb793cf8 ("btrfs: defrag: introduce helper to collect target file extents")
    CC: stable@vger.kernel.org # 5.16
    Reviewed-by: default avatarQu Wenruo <wqu@suse.com>
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    0cb5950f
ioctl.c 127 KB