Re: [PATCH v2] btrfs: skip hole detection during full fsync for files without holes
Qu Wenruo <[email protected]> Fri, 31 Jul 2026 18:57:06 +0930
| Newsgroups | org.kernel.vger.linux-btrfs |
|---|---|
| Message-ID | <[email protected]> |
在 2026/7/31 18:49, [email protected] 写道: > 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]> Reviewed-by: Qu Wenruo <[email protected]> Thanks, Qu > --- > > 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;