new file mode 100755
@@ -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`
+seqres=$RESULT_DIR/$seq
+echo "QA output created by $seq"
+tmp=/tmp/$$
+status=1 # failure is the default!
+trap "_cleanup; exit \$status" 0 1 2 3 15
+
+_cleanup()
+{
+ _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_scratch
+_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
+
+run_test()
+{
+ # 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
+_init_flakey
+_mount_flakey
+
+echo "Testing without NO_HOLES feature"
+run_test
+
+_unmount_flakey
+_cleanup_flakey
+
+_scratch_mkfs -O no-holes >>$seqres.full 2>&1
+_require_metadata_journaling $SCRATCH_DEV
+_init_flakey
+_mount_flakey
+
+echo
+echo "Testing with the NO_HOLES feature"
+run_test
+
+_unmount_flakey
+status=0
+exit
new file mode 100644
@@ -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
@@ -213,3 +213,4 @@
208 auto quick subvol
209 auto quick log
210 auto quick qgroup snapshot
+211 auto quick log prealloc