• Filipe Manana's avatar
    btrfs: stop doing excessive space reservation for csum deletion · adb86dbe
    Filipe Manana authored
    Currently when reserving space for deleting the csum items for a data
    extent, when adding or updating a delayed ref head, we determine how
    many leaves of csum items we can have and then pass that number to the
    helper btrfs_calc_delayed_ref_bytes(). This helper is used for calculating
    space for all tree modifications we need when running delayed references,
    however the amount of space it computes is excessive for deleting csum
    items because:
    
    1) It uses btrfs_calc_insert_metadata_size() which is excessive because
       we only need to delete csum items from the csum tree, we don't need
       to insert any items, so btrfs_calc_metadata_size() is all we need (as
       it computes space needed to delete an item);
    
    2) If the free space tree is enabled, it doubles the amount of space,
       which is pointless for csum deletion since we don't need to touch the
       free space tree or any other tree other than the csum tree.
    
    So improve on this by tracking how many csum deletions we have and using
    a new helper to calculate space for csum deletions (just a wrapper around
    btrfs_calc_metadata_size() with a comment). This reduces the amount of
    space we need to reserve for csum deletions by a factor of 4, and it helps
    reduce the number of times we have to block space reservations and have
    the reclaim task enter the space flushing algorithm (flush delayed items,
    flush delayed refs, etc) in order to satisfy tickets.
    
    For example this results in a total time decrease when unlinking (or
    truncating) files with many extents, as we end up having to block on space
    metadata reservations less often. Example test:
    
      $ cat test.sh
      #!/bin/bash
    
      DEV=/dev/nullb0
      MNT=/mnt/test
    
      umount $DEV &> /dev/null
      mkfs.btrfs -f $DEV
      # Use compression to quickly create files with a lot of extents
      # (each with a size of 128K).
      mount -o compress=lzo $DEV $MNT
    
      # 100G gives at least 983040 extents with a size of 128K.
      xfs_io -f -c "pwrite -S 0xab -b 1M 0 120G" $MNT/foobar
    
      # Flush all delalloc and clear all metadata from memory.
      umount $MNT
      mount -o compress=lzo $DEV $MNT
    
      start=$(date +%s%N)
      rm -f $MNT/foobar
      end=$(date +%s%N)
      dur=$(( (end - start) / 1000000 ))
      echo "rm took $dur milliseconds"
    
      umount $MNT
    
    Before this change rm took: 7504 milliseconds
    After this change rm took:  6574 milliseconds  (-12.4%)
    Reviewed-by: default avatarJosef Bacik <josef@toxicpanda.com>
    Signed-off-by: default avatarFilipe Manana <fdmanana@suse.com>
    Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
    adb86dbe
delayed-ref.h 12.1 KB