• Qu Wenruo's avatar
    btrfs: defrag: bring back the old file extent search behavior · d5633b0d
    Qu Wenruo authored
    For defrag, we don't really want to use btrfs_get_extent() to iterate
    all extent maps of an inode.
    
    The reasons are:
    
    - btrfs_get_extent() can merge extent maps
      And the result em has the higher generation of the two, causing defrag
      to mark unnecessary part of such merged large extent map.
    
      This in fact can result extra IO for autodefrag in v5.16+ kernels.
    
      However this patch is not going to completely solve the problem, as
      one can still using read() to trigger extent map reading, and got
      them merged.
    
      The completely solution for the extent map merging generation problem
      will come as an standalone fix.
    
    - btrfs_get_extent() caches the extent map result
      Normally it's fine, but for defrag the target range may not get
      another read/write for a long long time.
      Such cache would only increase the memory usage.
    
    - btrfs_get_extent() doesn't skip older extent map
      Unlike the old find_new_extent() which uses btrfs_search_forward() to
      skip the older subtree, thus it will pick up unnecessary extent maps.
    
    This patch will fix the regression by introducing defrag_get_extent() to
    replace the btrfs_get_extent() call.
    
    This helper will:
    
    - Not cache the file extent we found
      It will search the file extent and manually convert it to em.
    
    - Use btrfs_search_forward() to skip entire ranges which is modified in
      the past
    
    This should reduce the IO for autodefrag.
    Reported-by: default avatarFilipe Manana <fdmanana@suse.com>
    Fixes: 7b508037 ("btrfs: defrag: use defrag_one_cluster() to implement btrfs_defrag_file()")
    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>
    d5633b0d
ioctl.c 133 KB