linux/fs/btrfs
Filipe Manana 031dd12c37 btrfs: optimize clearing all bits from first extent record in an io tree
When we are clearing all the bits from the first record that contains the
target range and that record ends at or before our target range but starts
before our target range, we are doing a lot of unnecessary work:

1) Allocating a prealloc state if we don't have one already;

2) Adjust that record's start offset to the start of our range and
   make the prealloc state have a range going from the original start
   offset of that first record to the start offset of our target range,
   and with the same bits as that first record. Then we insert the
   prealloc extent in the rbtree - this is done in split_state();

3) Remove our adjusted first state from the rbtree since all the bits
   were cleared - this is done in clear_state_bit().

This is only wasting time when we can simply trim that first record, so
that it represents the range from its start offset to the start offset of
our target range. So optimize for that case and avoid the prealloc state
allocation, insertion and deletion from the rbtree.

This patch is the last patch of a patchset comprised of the following
patches (in descending order):

  btrfs: optimize clearing all bits from first extent record in an io tree
  btrfs: panic instead of warn when splitting extent state not in the tree
  btrfs: free cached state outside critical section in wait_extent_bit()
  btrfs: avoid unnecessary wake ups on io trees when there are no waiters
  btrfs: remove wake parameter from clear_state_bit()
  btrfs: change last argument of add_extent_changeset() to boolean
  btrfs: use extent_io_tree_panic() instead of BUG_ON()
  btrfs: make add_extent_changeset() only return errors or success
  btrfs: tag as unlikely branches that call extent_io_tree_panic()
  btrfs: turn extent_io_tree_panic() into a macro for better error reporting
  btrfs: optimize clearing all bits from the last extent record in an io tree

The following fio script was used to measure performance before and after
applying all the patches:

  $ cat ./fio-io-uring-2.sh
  #!/bin/bash

  DEV=/dev/nullb0
  MNT=/mnt/nullb0
  MOUNT_OPTIONS="-o ssd"
  MKFS_OPTIONS=""

  if [ $# -ne 3 ]; then
      echo "Use $0 NUM_JOBS FILE_SIZE RUN_TIME"
      exit 1
  fi

  NUM_JOBS=$1
  FILE_SIZE=$2
  RUN_TIME=$3

  cat <<EOF > /tmp/fio-job.ini
  [io_uring_rw]
  rw=randwrite
  fsync=0
  fallocate=none
  group_reporting=1
  direct=1
  ioengine=io_uring
  fixedbufs=1
  iodepth=64
  bs=4K
  filesize=$FILE_SIZE
  runtime=$RUN_TIME
  time_based
  filename=foobar
  directory=$MNT
  numjobs=$NUM_JOBS
  thread
  EOF

  echo performance | \
      tee /sys/devices/system/cpu/cpu*/cpufreq/scaling_governor

  echo
  echo "Using config:"
  echo
  cat /tmp/fio-job.ini
  echo

  umount $MNT &> /dev/null
  mkfs.btrfs -f $MKFS_OPTIONS $DEV &> /dev/null
  mount $MOUNT_OPTIONS $DEV $MNT

  fio /tmp/fio-job.ini

  umount $MNT

When running this script on a 12 cores machine using a 16G null block
device the results were the following:

Before patchset:

  $ ./fio-io-uring-2.sh 12 8G 60
  (...)
  WRITE: bw=74.8MiB/s (78.5MB/s), 74.8MiB/s-74.8MiB/s (78.5MB/s-78.5MB/s), io=4504MiB (4723MB), run=60197-60197msec

After patchset:

  $ ./fio-io-uring-2.sh 12 8G 60
  (...)
  WRITE: bw=82.2MiB/s (86.2MB/s), 82.2MiB/s-82.2MiB/s (86.2MB/s-86.2MB/s), io=4937MiB (5176MB), run=60027-60027msec

Also, using bpftrace to collect the duration (in nanoseconds) of all the
btrfs_clear_extent_bit_changeset() calls done during that fio test and
then making an histogram from that data, held the following results:

Before patchset:

  Count: 6304804
  Range:  0.000 - 7587172.000; Mean: 2011.308; Median: 1219.000; Stddev: 17117.533
  Percentiles:  90th: 1888.000; 95th: 2189.000; 99th: 16104.000
        0.000 -    8.098:        7 |
        8.098 -   40.385:       20 |
       40.385 -  187.254:      146 |
      187.254 -  855.347:   742048 #######
      855.347 - 3894.426:  5462542 #####################################################
     3894.426 - 17718.848:   41489 |
    17718.848 - 80604.558:   46085 |
    80604.558 - 366664.449:  11285 |
   366664.449 - 1667918.122:   961 |
  1667918.122 - 7587172.000:   113 |

After patchset:

  Count: 6282879
  Range:  0.000 - 6029290.000; Mean: 1896.482; Median: 1126.000; Stddev: 15276.691
  Percentiles:  90th: 1741.000; 95th: 2026.000; 99th: 15713.000
        0.000 - 60.014:         12 |
       60.014 - 217.984:        63 |
      217.984 - 784.949:    517515 #####
      784.949 - 2819.823:  5632335 #####################################################
     2819.823 - 10123.127:   55716 #
    10123.127 - 36335.184:   46034 |
    36335.184 - 130412.049:  25708 |
   130412.049 - 468060.350:   4824 |
   468060.350 - 1679903.189:   549 |
  1679903.189 - 6029290.000:    84 |

Signed-off-by: Filipe Manana <fdmanana@suse.com>
Reviewed-by: David Sterba <dsterba@suse.com>
Signed-off-by: David Sterba <dsterba@suse.com>
History 2026-04-07 18:56:04 +02:00
..
tests btrfs: replace kcalloc() calls to kzalloc_objs() 2026-04-07 18:55:59 +02:00
accessors.c btrfs: fix typos in comments and strings 2025-09-23 08:49:16 +02:00
accessors.h btrfs: allow mounting filesystems with remap-tree incompat flag 2026-02-03 07:54:35 +01:00
acl.c posix_acl: make posix_acl_to_xattr() alloc the buffer 2026-01-16 10:51:12 +01:00
acl.h btrfs: update include and forward declarations in headers 2025-03-18 20:35:43 +01:00
async-thread.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
async-thread.h btrfs: add forward declarations and headers, part 1 2024-03-04 16:24:49 +01:00
backref.c btrfs: remove redundant extent_buffer_uptodate() checks after read_tree_block() 2026-04-07 18:55:55 +02:00
backref.h btrfs: declare free_ipath() via DEFINE_FREE() 2025-11-24 22:34:51 +01:00
bio.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
bio.h btrfs: move existing remaps before relocating block group 2026-02-03 07:54:35 +01:00
block-group.c btrfs: zoned: limit number of zones reclaimed in flush_space() 2026-04-07 18:56:01 +02:00
block-group.h btrfs: zoned: limit number of zones reclaimed in flush_space() 2026-04-07 18:56:01 +02:00
block-rsv.c btrfs: don't allow log trees to consume global reserve or overcommit metadata 2026-04-07 18:55:53 +02:00
block-rsv.h btrfs: add METADATA_REMAP chunk type 2026-02-03 07:54:27 +01:00
btrfs_inode.h fsverity: use a hashtable to find the fsverity_info 2026-02-04 11:31:54 -08:00
compression.c btrfs: reduce the size of compressed_bio 2026-04-07 18:55:59 +02:00
compression.h btrfs: extract the max compression chunk size into a macro 2026-04-07 18:56:00 +02:00
ctree.c btrfs: remove atomic parameter from btrfs_buffer_uptodate() 2026-04-07 18:56:02 +02:00
ctree.h btrfs: introduce BTRFS_PATH_AUTO_RELEASE() helper 2026-02-03 06:38:32 +01:00
defrag.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
defrag.h btrfs: pass struct btrfs_inode to btrfs_defrag_file() 2025-03-18 20:35:43 +01:00
delalloc-space.c btrfs: remove fs_info argument from btrfs_reserve_metadata_bytes() 2025-11-24 21:59:11 +01:00
delalloc-space.h btrfs: pass struct btrfs_inode to btrfs_free_reserved_data_space_noquota() 2025-05-15 14:30:52 +02:00
delayed-inode.c for-7.0-rc2-tag 2026-03-03 09:08:00 -08:00
delayed-inode.h btrfs: embed delayed root to struct btrfs_fs_info 2026-02-03 07:56:20 +01:00
delayed-ref.c btrfs: zoned: cap delayed refs metadata reservation to avoid overcommit 2026-04-07 18:55:55 +02:00
delayed-ref.h btrfs: move ref-verify under CONFIG_BTRFS_DEBUG 2025-09-22 10:54:32 +02:00
dev-replace.c btrfs: pass literal booleans to functions that take boolean arguments 2026-04-07 18:55:56 +02:00
dev-replace.h btrfs: trivial conversion to return bool instead of int 2025-05-15 14:30:49 +02:00
dir-item.c btrfs: remove pointless error check in btrfs_check_dir_item_collision() 2026-04-07 18:56:00 +02:00
dir-item.h btrfs: rename inode number parameter passed to btrfs_check_dir_item_collision() 2025-07-22 00:05:00 +02:00
direct-io.c btrfs: remove redundant nowait check in lock_extent_direct() 2026-04-07 18:55:58 +02:00
direct-io.h btrfs: update include and forward declarations in headers 2025-03-18 20:35:43 +01:00
discard.c btrfs: handle discarding fully-remapped block groups 2026-02-03 07:54:36 +01:00
discard.h btrfs: update include and forward declarations in headers 2025-03-18 20:35:43 +01:00
disk-io.c btrfs: remove atomic parameter from btrfs_buffer_uptodate() 2026-04-07 18:56:02 +02:00
disk-io.h btrfs: remove atomic parameter from btrfs_buffer_uptodate() 2026-04-07 18:56:02 +02:00
export.c btrfs: avoid potential out-of-bounds in btrfs_encode_fh() 2025-09-26 08:48:30 +02:00
export.h btrfs: add forward declarations and headers, part 1 2024-03-04 16:24:49 +01:00
extent-io-tree.c btrfs: optimize clearing all bits from first extent record in an io tree 2026-04-07 18:56:04 +02:00
extent-io-tree.h btrfs: convert several int parameters to bool 2025-09-22 10:54:32 +02:00
extent-tree.c btrfs: remove atomic parameter from btrfs_buffer_uptodate() 2026-04-07 18:56:02 +02:00
extent-tree.h btrfs: add do_remap parameter to btrfs_discard_extent() 2026-02-03 07:54:35 +01:00
extent_io.c btrfs: remove atomic parameter from btrfs_buffer_uptodate() 2026-04-07 18:56:02 +02:00
extent_io.h btrfs: inhibit extent buffer writeback to prevent COW amplification 2026-04-07 18:56:00 +02:00
extent_map.c btrfs: add strict extent map alignment checks 2026-02-03 07:56:19 +01:00
extent_map.h btrfs: headers cleanup to remove unnecessary local includes 2025-11-24 22:34:52 +01:00
fiemap.c Convert remaining multi-line kmalloc_obj/flex GFP_KERNEL uses 2026-02-22 08:26:33 -08:00
fiemap.h btrfs: move fiemap code into its own file 2024-07-11 15:33:20 +02:00
file-item.c btrfs: rename btrfs_csum_file_blocks() to btrfs_insert_data_csums() 2026-04-07 18:55:56 +02:00
file-item.h btrfs: rename btrfs_csum_file_blocks() to btrfs_insert_data_csums() 2026-04-07 18:55:56 +02:00
file.c btrfs: pass literal booleans to functions that take boolean arguments 2026-04-07 18:55:56 +02:00
file.h btrfs: update include and forward declarations in headers 2025-03-18 20:35:43 +01:00
free-space-cache.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
free-space-cache.h btrfs: handle discarding fully-remapped block groups 2026-02-03 07:54:36 +01:00
free-space-tree.c btrfs: check for NULL root after calls to btrfs_extent_root() 2026-03-17 11:22:49 +01:00
free-space-tree.h btrfs: handle setting up relocation of block group with remap-tree 2026-02-03 07:54:35 +01:00
fs.c btrfs: switch to library APIs for checksums 2026-02-03 06:38:32 +01:00
fs.h btrfs: report filesystem shutdown via fserror 2026-04-07 18:55:59 +02:00
inode-item.c btrfs: merge setting ret and return ret 2026-02-03 06:38:33 +01:00
inode-item.h btrfs: remove unused parameters from btrfs_lookup_inode_extref() 2025-07-21 23:58:03 +02:00
inode.c btrfs: prefer IS_ERR_OR_NULL() over manual NULL check 2026-04-07 18:56:02 +02:00
ioctl.c btrfs: stop checking for -EEXIST return value from btrfs_uuid_tree_add() 2026-04-07 18:55:59 +02:00
ioctl.h tree-wide: s/struct fileattr/struct file_kattr/g 2025-07-04 16:14:39 +02:00
Kconfig btrfs: allow mounting filesystems with remap-tree incompat flag 2026-02-03 07:54:35 +01:00
locking.c btrfs: add definitions and constants for remap-tree 2026-02-03 07:54:02 +01:00
locking.h btrfs: fix typos in comments and strings 2025-09-23 08:49:16 +02:00
lru_cache.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
lru_cache.h btrfs: cleanup recursive include of the same header 2024-07-11 15:33:22 +02:00
lzo.c btrfs: reduce the size of compressed_bio 2026-04-07 18:55:59 +02:00
Makefile btrfs: tests: zoned: add tests cases for zoned code 2026-04-07 18:55:52 +02:00
messages.c btrfs: pass level to _btrfs_printk() to avoid parsing level from string 2026-02-03 07:49:10 +01:00
messages.h btrfs: stop printing condition result in assertion failure messages 2026-04-07 18:55:58 +02:00
misc.h btrfs: introduce a common helper to calculate the size of a bio 2026-04-07 18:55:59 +02:00
ordered-data.c btrfs: output more info when duplicated ordered extent is found 2026-04-07 18:56:02 +02:00
ordered-data.h btrfs: check type flags in alloc_ordered_extent() 2026-04-07 18:56:02 +02:00
orphan.c btrfs: BTRFS_PATH_AUTO_FREE in orphan.c 2024-09-10 16:51:22 +02:00
orphan.h btrfs: add forward declarations and headers, part 1 2024-03-04 16:24:49 +01:00
print-tree.c btrfs: remove redundant extent_buffer_uptodate() checks after read_tree_block() 2026-04-07 18:55:55 +02:00
print-tree.h btrfs: update include and forward declarations in headers 2025-03-18 20:35:43 +01:00
props.c btrfs: props: switch prop_handler::extract to struct btrfs_inode 2025-03-18 20:35:44 +01:00
props.h btrfs: pass struct btrfs_inode to btrfs_inode_inherit_props() 2025-03-18 20:35:44 +01:00
qgroup.c btrfs: pass literal booleans to functions that take boolean arguments 2026-04-07 18:55:56 +02:00
qgroup.h btrfs: update include and forward declarations in headers 2025-03-18 20:35:43 +01:00
raid-stripe-tree.c btrfs: fix placement of unlikely() in btrfs_insert_one_raid_extent() 2026-04-07 18:55:58 +02:00
raid-stripe-tree.h btrfs: update include and forward declarations in headers 2025-03-18 20:35:43 +01:00
raid56.c btrfs: replace kcalloc() calls to kzalloc_objs() 2026-04-07 18:55:59 +02:00
raid56.h btrfs: raid56: introduce a new parameter to locate a sector 2025-11-25 01:46:58 +01:00
ref-verify.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
ref-verify.h btrfs: move ref-verify under CONFIG_BTRFS_DEBUG 2025-09-22 10:54:32 +02:00
reflink.c btrfs: pass literal booleans to functions that take boolean arguments 2026-04-07 18:55:56 +02:00
reflink.h btrfs: add forward declarations and headers, part 1 2024-03-04 16:24:49 +01:00
relocation.c btrfs: avoid starting new transaction and commit in relocate_block_group() 2026-04-07 18:55:55 +02:00
relocation.h btrfs: handle setting up relocation of block group with remap-tree 2026-02-03 07:54:35 +01:00
root-tree.c btrfs: fix lost error return in btrfs_find_orphan_roots() 2026-02-18 15:25:54 +01:00
root-tree.h btrfs: qgroup: fix qgroup prealloc rsv leak in subvolume operations 2024-04-02 19:18:23 +02:00
scrub.c btrfs: introduce a common helper to calculate the size of a bio 2026-04-07 18:55:59 +02:00
scrub.h btrfs: convert several int parameters to bool 2025-09-22 10:54:32 +02:00
send.c btrfs: pass literal booleans to functions that take boolean arguments 2026-04-07 18:55:56 +02:00
send.h btrfs: pass btrfs_root pointers to send ioctl parameters 2025-03-18 20:35:49 +01:00
space-info.c btrfs: zoned: limit number of zones reclaimed in flush_space() 2026-04-07 18:56:01 +02:00
space-info.h btrfs: constify arguments of some functions 2026-04-07 18:55:58 +02:00
subpage.c for-6.19-tag 2025-12-03 20:03:46 -08:00
subpage.h btrfs: headers cleanup to remove unnecessary local includes 2025-11-24 22:34:52 +01:00
super.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
super.h btrfs: constify arguments of some functions 2026-04-07 18:55:58 +02:00
sysfs.c Convert 'alloc_obj' family to use the new default GFP_KERNEL argument 2026-02-21 17:09:51 -08:00
sysfs.h btrfs: remove fs_info argument from btrfs_sysfs_add_space_info_type() 2025-11-24 22:02:30 +01:00
transaction.c btrfs: prefer IS_ERR_OR_NULL() over manual NULL check 2026-04-07 18:56:02 +02:00
transaction.h btrfs: inhibit extent buffer writeback to prevent COW amplification 2026-04-07 18:56:00 +02:00
tree-checker.c btrfs: tree-checker: introduce checks for FREE_SPACE_BITMAP 2026-04-07 18:56:02 +02:00
tree-checker.h btrfs: add definitions and constants for remap-tree 2026-02-03 07:54:02 +01:00
tree-log.c btrfs: remove atomic parameter from btrfs_buffer_uptodate() 2026-04-07 18:56:02 +02:00
tree-log.h btrfs: reduce arguments to btrfs_del_inode_ref_in_log() 2025-11-25 01:53:33 +01:00
tree-mod-log.c btrfs: remove redundant extent_buffer_uptodate() checks after read_tree_block() 2026-04-07 18:55:55 +02:00
tree-mod-log.h btrfs: drop unused parameter path from btrfs_tree_mod_log_rewind() 2024-11-11 14:34:15 +01:00
ulist.c treewide: Replace kmalloc with kmalloc_obj for non-scalar types 2026-02-21 01:02:28 -08:00
ulist.h btrfs: preallocate ulist memory for qgroup rsv 2024-07-11 15:33:26 +02:00
uuid-tree.c btrfs: prefer IS_ERR_OR_NULL() over manual NULL check 2026-04-07 18:56:02 +02:00
uuid-tree.h btrfs: fix transaction abort on set received ioctl due to item overflow 2026-03-03 17:03:59 +01:00
verity.c for-7.0-rc1-tag 2026-02-20 14:57:09 -08:00
verity.h btrfs: add forward declarations and headers, part 1 2024-03-04 16:24:49 +01:00
volumes.c btrfs: replace kcalloc() calls to kzalloc_objs() 2026-04-07 18:55:59 +02:00
volumes.h btrfs: introduce the device layout aware per-profile available space 2026-04-07 18:55:53 +02:00
xattr.c btrfs: remaining BTRFS_PATH_AUTO_FREE conversions 2025-11-25 01:53:33 +01:00
xattr.h btrfs: update include and forward declarations in headers 2025-03-18 20:35:43 +01:00
zlib.c btrfs: reduce the size of compressed_bio 2026-04-07 18:55:59 +02:00
zoned.c btrfs: replace kcalloc() calls to kzalloc_objs() 2026-04-07 18:55:59 +02:00
zoned.h btrfs: zoned: factor out the zone loading part into a testable function 2026-02-03 07:59:06 +01:00
zstd.c btrfs: reduce the size of compressed_bio 2026-04-07 18:55:59 +02:00