• Qu Wenruo's avatar
    btrfs: avoid defragging extents whose next extents are not targets · 75a36a7d
    Qu Wenruo authored
    [BUG]
    There is a report that autodefrag is defragging single sector, which
    is completely waste of IO, and no help for defragging:
    
       btrfs-cleaner-808 defrag_one_locked_range: root=256 ino=651122 start=0 len=4096
    
    [CAUSE]
    In defrag_collect_targets(), we check if the current range (A) can be merged
    with next one (B).
    
    If mergeable, we will add range A into target for defrag.
    
    However there is a catch for autodefrag, when checking mergeability
    against range B, we intentionally pass 0 as @newer_than, hoping to get a
    higher chance to merge with the next extent.
    
    But in the next iteration, range B will looked up by defrag_lookup_extent(),
    with non-zero @newer_than.
    
    And if range B is not really newer, it will rejected directly, causing
    only range A being defragged, while we expect to defrag both range A and
    B.
    
    [FIX]
    Since the root cause is the difference in check condition of
    defrag_check_next_extent() and defrag_collect_targets(), we fix it by:
    
    1. Pass @newer_than to defrag_check_next_extent()
    2. Pass @extent_thresh to defrag_check_next_extent()
    
    This makes the check between defrag_collect_targets() and
    defrag_check_next_extent() more consistent.
    
    While there is still some minor difference, the remaining checks are
    focus on runtime flags like writeback/delalloc, which are mostly
    transient and safe to be checked only in defrag_collect_targets().
    
    Link: https://github.com/btrfs/linux/issues/423#issuecomment-1066981856
    CC: stable@vger.kernel.org # 5.16+
    Reviewed-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarQu Wenruo <wqu@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    75a36a7d
ioctl.c 139 KB