[PATCH v2] btrfs: skip hole detection during full fsync for files without holes
[email protected] Fri, 31 Jul 2026 10:19:42 +0100
| Newsgroups | org.kernel.vger.linux-btrfs |
|---|---|
| Message-ID | <8a62eeb9c24994929aa697d2125a197e82bb7c02.1785488972.git.fdmanana@suse.com> |
From: Filipe Manana <[email protected]> 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) is greater than or equals to 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 umount $MNT &> /dev/null mkfs.btrfs -f $DEV mount $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 $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 <[email protected]> --- V2: Support the case where i_size is not sector size aligned and so i_size <= nbytes. fs/btrfs/tree-log.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/fs/btrfs/tree-log.c b/fs/btrfs/tree-log.c index 47046dd14997..88b6258f2e3f 100644 --- a/fs/btrfs/tree-log.c +++ b/fs/btrfs/tree-log.c @@ -5591,6 +5591,15 @@ 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 is greater than or equals to 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