• Qu Wenruo's avatar
    btrfs: defrag: properly update range->start for autodefrag · c080b414
    Qu Wenruo authored
    [BUG]
    After commit 7b508037 ("btrfs: defrag: use defrag_one_cluster() to
    implement btrfs_defrag_file()") autodefrag no longer properly re-defrag
    the file from previously finished location.
    
    [CAUSE]
    The recent refactoring of defrag only focuses on defrag ioctl subpage
    support, doesn't take autodefrag into consideration.
    
    There are two problems involved which prevents autodefrag to restart its
    scan:
    
    - No range.start update
      Previously when one defrag target is found, range->start will be
      updated to indicate where next search should start from.
    
      But now btrfs_defrag_file() doesn't update it anymore, making all
      autodefrag to rescan from file offset 0.
    
      This would also make autodefrag to mark the same range dirty again and
      again, causing extra IO.
    
    - No proper quick exit for defrag_one_cluster()
      Currently if we reached or exceed @max_sectors limit, we just exit
      defrag_one_cluster(), and let next defrag_one_cluster() call to do a
      quick exit.
      This makes @cur increase, thus no way to properly know which range is
      defragged and which range is skipped.
    
    [FIX]
    The fix involves two modifications:
    
    - Update range->start to next cluster start
      This is a little different from the old behavior.
      Previously range->start is updated to the next defrag target.
    
      But in the end, the behavior should still be pretty much the same,
      as now we skip to next defrag target inside btrfs_defrag_file().
    
      Thus if auto-defrag determines to re-scan, then we still do the skip,
      just at a different timing.
    
    - Make defrag_one_cluster() to return >0 to indicate a quick exit
      So that btrfs_defrag_file() can also do a quick exit, without
      increasing @cur to the range end, and re-use @cur to update
      @range->start.
    
    - Add comment for btrfs_defrag_file() to mention the range->start update
      Currently only autodefrag utilize this behavior, as defrag ioctl won't
      set @max_to_defrag parameter, thus unless interrupted it will always
      try to defrag the whole range.
    Reported-by: default avatarFilipe Manana <fdmanana@suse.com>
    Fixes: 7b508037 ("btrfs: defrag: use defrag_one_cluster() to implement btrfs_defrag_file()")
    Link: https://lore.kernel.org/linux-btrfs/0a269612-e43f-da22-c5bc-b34b1b56ebe8@mailbox.org/
    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>
    c080b414
ioctl.c 126 KB