Re: [PATCH] btrfs: skip hole detection during full fsync for files without holes
Qu Wenruo <[email protected]> Fri, 31 Jul 2026 08:02:07 +0930
| Newsgroups | org.kernel.vger.linux-btrfs |
|---|---|
| Message-ID | <[email protected]> |
=E5=9C=A8 2026/7/31 02:11, [email protected] =E5=86=99=E9=81=93: > From: Filipe Manana <[email protected]> >=20 > 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 the= m. >=20 > 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. >=20 > The following test script was used: >=20 > $ cat test.sh > #!/bin/bash >=20 > MNT=3D/mnt/nullb0 > DEV=3D/dev/nullb0 >=20 > MOUNT_OPTIONS=3D"-o ssd" > MKFS_OPTIONS=3D"" >=20 > umount $MNT &> /dev/null > mkfs.btrfs -f $MKFS_OPTIONS $DEV > mount $MOUNT_OPTIONS $DEV $MNT >=20 > # 256M gives 64K extents of 4K each. > FILE_SIZE=3D$((256 * 1024 * 1024)) > touch $MNT/foobar >=20 > for ((i =3D 0; i < $FILE_SIZE; i +=3D 8192)); do > xfs_io -c "pwrite -S 0xab $i 4K" $MNT/foobar > /dev/null > done >=20 > xfs_io -c "fsync" $MNT/foobar >=20 > for ((i =3D 4096; i < $FILE_SIZE; i +=3D 8192)); do > xfs_io -c "pwrite -S 0xab $i 4K" $MNT/foobar > /dev/null > done >=20 > # unmount and mount, clear caches and ensure the next fsync is a > # full sync. > umount $MNT > mount $MOUNT_OPTIONS $DEV $MNT >=20 > # Do some change to the file in order to fsync. > xfs_io -c "pwrite -S 0xcd 0 4K" $MNT/foobar > /dev/null >=20 > T0=3D$(date +%s%N) > xfs_io -c "fsync" $MNT/foobar > T1=3D$(date +%s%N) >=20 > echo > echo "Took $(( (T1 - T0) / 1000 ))us" >=20 > umount $MNT >=20 > Before this change: >=20 > Took 28721us >=20 > After this change: >=20 > Took 5453us >=20 > That's about 5.3x times faster. >=20 > Signed-off-by: Filipe Manana <[email protected]> > --- > fs/btrfs/tree-log.c | 8 ++++++++ > 1 file changed, 8 insertions(+) >=20 > 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_han= dle *trans, > if (!btrfs_fs_incompat(fs_info, NO_HOLES) || i_size =3D=3D 0) > return 0; > =20 > + /* > + * 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. > + */ I'm wondering if i_size < nbytes, can we still skip the hole scan? Thanks, Qu > + if (!(inode->flags & BTRFS_INODE_PREALLOC) && > + i_size =3D=3D inode_get_bytes(&inode->vfs_inode)) > + return 0; > + > key.objectid =3D ino; > key.type =3D BTRFS_EXTENT_DATA_KEY; > key.offset =3D 0;