diff mbox series

btrfs: add a test for fsync of file with prealloc extents crossing eof

Message ID 20200421102539.14786-1-fdmanana@kernel.org (mailing list archive)
State New, archived
Headers show
Series btrfs: add a test for fsync of file with prealloc extents crossing eof | expand

Commit Message

Filipe Manana April 21, 2020, 10:25 a.m. UTC
From: Filipe Manana <fdmanana@suse.com>

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.

This currently fails and it is fixed by a patch that has the following
subject:

  "Btrfs: fix partial loss of prealloc extent past i_size after fsync"

Signed-off-by: Filipe Manana <fdmanana@suse.com>
---
 tests/btrfs/211     | 112 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 tests/btrfs/211.out |  10 +++++
 tests/btrfs/group   |   1 +
 3 files changed, 123 insertions(+)
 create mode 100755 tests/btrfs/211
 create mode 100644 tests/btrfs/211.out
diff mbox series

Patch

diff --git a/tests/btrfs/211 b/tests/btrfs/211
new file mode 100755
index 00000000..3495b309
--- /dev/null
+++ b/tests/btrfs/211
@@ -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
diff --git a/tests/btrfs/211.out b/tests/btrfs/211.out
new file mode 100644
index 00000000..838b1a76
--- /dev/null
+++ b/tests/btrfs/211.out
@@ -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
diff --git a/tests/btrfs/group b/tests/btrfs/group
index 9426fb17..66b1beac 100644
--- a/tests/btrfs/group
+++ b/tests/btrfs/group
@@ -213,3 +213,4 @@ 
 208 auto quick subvol
 209 auto quick log
 210 auto quick qgroup snapshot
+211 auto quick log prealloc