btrfs: add a test for fsync of file with prealloc extents crossing eof
authorFilipe Manana <>
Tue, 21 Apr 2020 10:25:39 +0000 (11:25 +0100)
committerEryu Guan <>
Sun, 10 May 2020 12:54:18 +0000 (20:54 +0800)
Test that if we fsync a file with prealloc extents that start before and
after the file's size, we don't end up with missing parts of the extents
and implicit file holes after a power failure. Test both without and with
the NO_HOLES feature.

It is fixed commit f135cea30de5 ("btrfs: fix partial loss of
prealloc extent past i_size after fsync")

Signed-off-by: Filipe Manana <>
Reviewed-by: Eryu Guan <>
Signed-off-by: Eryu Guan <>
tests/btrfs/211 [new file with mode: 0755]
tests/btrfs/211.out [new file with mode: 0644]

diff --git a/tests/btrfs/211 b/tests/btrfs/211
new file mode 100755 (executable)
index 0000000..3495b30
--- /dev/null
@@ -0,0 +1,112 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2020 SUSE Linux Products GmbH. All Rights Reserved.
+# FSQA Test No. 211
+# Test that if we fsync a file with prealloc extents that start before and
+# after the file's size, we don't end up with missing parts of the extents
+# and implicit file holes after a power failure. Test both without and with
+# the NO_HOLES feature.
+seq=`basename $0`
+echo "QA output created by $seq"
+status=1       # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+       _cleanup_flakey
+       cd /
+       rm -f $tmp.*
+# get standard environment, filters and checks
+. ./common/rc
+. ./common/filter
+. ./common/dmflakey
+# real QA test starts here
+_supported_fs btrfs
+_supported_os Linux
+_require_xfs_io_command "falloc" "-k"
+# fiemap needed by _count_extents()
+_require_xfs_io_command "fiemap"
+_require_btrfs_fs_feature "no_holes"
+_require_btrfs_mkfs_feature "no-holes"
+_require_dm_target flakey
+rm -f $seqres.full
+    # Create our test file with 2 consecutive prealloc extents, each with a size
+    # of 128Kb, and covering the range from 0 to 256Kb, with a file size of 0.
+    # Then fsync the file to record both extents in a log tree.
+    $XFS_IO_PROG -f -c "falloc -k 0 128K" $SCRATCH_MNT/foo
+    $XFS_IO_PROG -c "falloc -k 128K 128K" $SCRATCH_MNT/foo
+    $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/foo
+    # Now do a redudant extent allocation for the range from 0 to 64Kb. This will
+    # merely increase the file size from 0 to 64Kb. Instead we could also do a
+    # truncate to set the file size to 64Kb.
+    $XFS_IO_PROG -c "falloc 0 64K" $SCRATCH_MNT/foo
+    # Fsync the file, so we update the log with the new file size. Here btrfs
+    # used to incorrectly set the number of bytes to 64Kb for the prealloc extent
+    # that covers the file range from 0 to 128Kb.
+    $XFS_IO_PROG -c "fsync" $SCRATCH_MNT/foo
+    # Now set the file size to 256K with a truncate and then fsync the file. We
+    # want to verify the log tree doesn't end up with an implicit hole for the
+    # file range from 64Kb to 128Kb. That would lead to an implicit hole after
+    # replaying the log and losing part of the prealloc extent, so a future write
+    # to anywhere in the file range from 64Kb to 128Kb would result in allocating
+    # a new extent and not use the extent previously allocated with fallocate().
+    $XFS_IO_PROG -c "truncate 256K" -c "fsync" $SCRATCH_MNT/foo
+    # Simulate a power failure and then mount again the filesystem to replay the
+    # log tree.
+    _flakey_drop_and_remount
+    # Unmount the filesystem and run 'btrfs check'/fsck to verify that we don't
+    # have a missing hole for the file range from 64K to 128K.
+    _unmount_flakey
+    _check_scratch_fs $FLAKEY_DEV
+    _mount_flakey
+    # Now write to the file range from 0 to 128K. After this we should still have
+    # rwo extents in our file, corresponding to the 2 extents we allocated before
+    # using fallocate(). In particular writing to the file range from 64Kb to
+    # 128Kb should not have allocated a new extent.
+    $XFS_IO_PROG -c "pwrite -S 0xab 0 128K" $SCRATCH_MNT/foo | _filter_xfs_io
+    echo "File extent count after write: $(_count_extents $SCRATCH_MNT/foo)"
+_scratch_mkfs -O ^no-holes >>$seqres.full 2>&1
+_require_metadata_journaling $SCRATCH_DEV
+echo "Testing without NO_HOLES feature"
+_scratch_mkfs -O no-holes >>$seqres.full 2>&1
+_require_metadata_journaling $SCRATCH_DEV
+echo "Testing with the NO_HOLES feature"
diff --git a/tests/btrfs/211.out b/tests/btrfs/211.out
new file mode 100644 (file)
index 0000000..838b1a7
--- /dev/null
@@ -0,0 +1,10 @@
+QA output created by 211
+Testing without NO_HOLES feature
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File extent count after write: 2
+Testing with the NO_HOLES feature
+wrote 131072/131072 bytes at offset 0
+XXX Bytes, X ops; XX:XX:XX.X (XXX YYY/sec and XXX ops/sec)
+File extent count after write: 2
index 9426fb171c88375a7d4bf095f793cc4009864e9c..66b1beacfd7e5ff5e9a119796c1ce45bba181b41 100644 (file)
 208 auto quick subvol
 209 auto quick log
 210 auto quick qgroup snapshot
+211 auto quick log prealloc