Linux Btrfs filesystem development
 help / color / mirror / Atom feed
* [PATCH] btrfs: skip hole detection during full fsync for files without holes
@ 2026-07-30 16:41 fdmanana
  2026-07-30 22:32 ` Qu Wenruo
  2026-07-31  9:19 ` [PATCH v2] " fdmanana
  0 siblings, 2 replies; 4+ messages in thread
From: fdmanana @ 2026-07-30 16:41 UTC (permalink / raw)
  To: linux-btrfs

From: Filipe Manana <fdmanana@suse.com>

If we the no-holes feature is enabled (a default since btrfs-progs 5.15),
when doing a full fsync we always iterate of all leaves in the subvolume
root that contain file extent items in order to detect holes between them.

This can take a lot of time for files with a large number of extents.
But if we know there are no prealloc extents and the amount of space
(uncompressed space) matches the i_size of the inode, then we cannot
have holes and therefore avoid searching for them. So skip the search
if those conditions are met.

The following test script was used:

  $ cat test.sh
  #!/bin/bash

  MNT=/mnt/nullb0
  DEV=/dev/nullb0

  MOUNT_OPTIONS="-o ssd"
  MKFS_OPTIONS=""

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

  # 256M gives 64K extents of 4K each.
  FILE_SIZE=$((256 * 1024 * 1024))
  touch $MNT/foobar

  for ((i = 0; i < $FILE_SIZE; i += 8192)); do
      xfs_io -c "pwrite -S 0xab $i 4K" $MNT/foobar > /dev/null
  done

  xfs_io -c "fsync" $MNT/foobar

  for ((i = 4096; i < $FILE_SIZE; i += 8192)); do
     xfs_io -c "pwrite -S 0xab $i 4K" $MNT/foobar > /dev/null
  done

  # unmount and mount, clear caches and ensure the next fsync is a
  # full sync.
  umount $MNT
  mount $MOUNT_OPTIONS $DEV $MNT

  # Do some change to the file in order to fsync.
  xfs_io -c "pwrite -S 0xcd 0 4K" $MNT/foobar > /dev/null

  T0=$(date +%s%N)
  xfs_io -c "fsync" $MNT/foobar
  T1=$(date +%s%N)

  echo
  echo "Took $(( (T1 - T0) / 1000 ))us"

  umount $MNT

Before this change:

  Took 28721us

After this change:

  Took 5453us

That's about 5.3x times faster.

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 fs/btrfs/tree-log.c | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c
index 47046dd14997..226dd3053564 100644
--- a/fs/btrfs/tree-log.c
+++ b/fs/btrfs/tree-log.c
@@ -5591,6 +5591,14 @@ static int btrfs_log_holes(struct btrfs_trans_handle *trans,
 	if (!btrfs_fs_incompat(fs_info, NO_HOLES) || i_size == 0)
 		return 0;
 
+	/*
+	 * If there are no prealloc extents (which can be located past i_size),
+	 * and disk space used matches the i_size, then there are no holes.
+	 */
+	if (!(inode->flags & BTRFS_INODE_PREALLOC) &&
+	    i_size == inode_get_bytes(&inode->vfs_inode))
+		return 0;
+
 	key.objectid = ino;
 	key.type = BTRFS_EXTENT_DATA_KEY;
 	key.offset = 0;
-- 
2.47.2


^ permalink raw reply related	[flat|nested] 4+ messages in thread

end of thread, other threads:[~2026-07-31  9:27 UTC | newest]

Thread overview: 4+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-07-30 16:41 [PATCH] btrfs: skip hole detection during full fsync for files without holes fdmanana
2026-07-30 22:32 ` Qu Wenruo
2026-07-31  9:19 ` [PATCH v2] " fdmanana
2026-07-31  9:27   ` Qu Wenruo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox