new file mode 100755
@@ -0,0 +1,116 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (C) 2022 SUSE Linux Products GmbH. All Rights Reserved.
+#
+# FS QA Test 001
+#
+# Test if a filesystem can detect unexpected changes at thaw time.
+#
+
+. ./common/preamble
+_begin_fstest auto freeze
+
+# For now, only btrfs explicitly checks the superblock at thaw time.
+_supported_fs btrfs
+_require_freeze
+_require_scratch
+
+if [ "x$FSTYP" == "xbtrfs" ]; then
+ _fixed_by_kernel_commit a05d3c915314 \
+ "btrfs: check superblock to ensure the fs was not modified at thaw time"
+fi
+
+# Make sure we can save the whole binary dump of the fs into $tmp, which
+# is normally backed up by tmpfs, thus may have very limited size.
+dd if=/dev/zero of=$tmp.binary_dump bs=1M count=512 >> $seqres.full 2>&1
+if [ $? -ne 0 ]; then
+ _notrun "Failed to save 512M sized image into $tmp.binary, maybe /tmp is too small?"
+fi
+rm -f $tmp.binary_dump
+
+prepare_and_freeze()
+{
+ _scratch_mount
+
+ $FSSTRESS_PROG -d $SCRATCH_MNT -n 100 -w >> $seqres.full
+ sync
+
+ $XFS_IO_PROG -x -c "freeze" $SCRATCH_MNT >> $seqres.full
+}
+
+thaw_and_verify()
+{
+ # We can not rely on the return value from thaw operation,
+ # as even some checks failed, we have to return 0 to allow
+ # the fs exit frezon status. Thus we do the check later.
+ $XFS_IO_PROG -x -c "thaw" $SCRATCH_MNT >> $seqres.full 2>&1
+
+ touch $SCRATCH_MNT/should_fail &> $seqres.full
+ if [ $? -eq 0 ]; then
+ echo "Failed to detect corrupted super block"
+ else
+ echo "Detected corrupted super block and fs fell RO"
+ fi
+ echo
+ _scratch_unmount
+}
+
+save_scratch_dev()
+{
+ dd if=$SCRATCH_DEV of=$tmp.binary_dump bs=1M count=512 >> $seqres.full 2>&1
+ if [ $? -ne 0 ]; then
+ _fail "Unable to save the full fs binary dump"
+ fi
+}
+
+restore_scratch_dev()
+{
+ dd if=$tmp.binary_dump of=$SCRATCH_DEV bs=1M >> $seqres.full 2>&1
+ if [ $? -ne 0 ]; then
+ _fail "Unable to restore the full fs binary dump"
+ fi
+ rm -f $tmp.binary_dump
+}
+
+test_corrupted_super()
+{
+ echo "Corrupted super block at thaw time:"
+ _scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+ prepare_and_freeze
+ # Corrupt the first 1M to cover the superblock.
+ dd if=/dev/zero of=$SCRATCH_DEV bs=1M count=1 >> $seqres.full 2>&1
+ thaw_and_verify
+}
+
+test_different_fs()
+{
+ echo "Different fs at thaw time:"
+ _scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+ save_scratch_dev
+
+ # Now go a new fs to start the test.
+ _scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+
+ prepare_and_freeze
+ restore_scratch_dev
+ thaw_and_verify
+}
+
+test_different_generation()
+{
+ echo "Same fs but different generation:"
+
+ _scratch_mkfs_sized $((512 * 1024 * 1024)) >> $seqres.full
+ save_scratch_dev
+ prepare_and_freeze
+ restore_scratch_dev
+ thaw_and_verify
+}
+
+test_corrupted_super
+test_different_fs
+test_different_generation
+
+# success, all done
+status=0
+exit
new file mode 100644
@@ -0,0 +1,10 @@
+QA output created by 001
+Corrupted super block at thaw time:
+Detected corrupted super block and fs fell RO
+
+Different fs at thaw time:
+Detected corrupted super block and fs fell RO
+
+Same fs but different generation:
+Detected corrupted super block and fs fell RO
+
[BACKGROUND] There is bug report from btrfs mailing list that, hibernation can allow one to modify the frozen filesystem unexpectedly (using another OS). (https://lore.kernel.org/linux-btrfs/83bf3b4b-7f4c-387a-b286-9251e3991e34@bluemole.com/) Later btrfs adds the check to make sure the fs is not changed unexpectedly, to prevent corruption from happening. [TESTCASE] The test case will test the following three cases: - Completely corrupted super block Fill the superblock range (the first 1M) with garbage. - Superblock is valid, but has different fsid We save a binary dump of a newly created fs, then create another fs on the scratch device. After the fs got frozen, write the saved binary dump back. - Superblock is valid, but has different generation. We save a binary dump of a newly created fs. Then modify the created fs, then freeze it. After the fs got frozen, write the saved binary dump back. And since we're using "$tmp.binary_dump" to save the whole 512M fs, systems with small memory and using tmpfs as /tmp may fail to save the image. Thus before the run, the test case will do a dry run to make sure we can save the image into "$tmp.binary_dump" first. Currently only btrfs does such explicit check at thaw time, thus it will mark the fs RO immediately. Other common fses like XFS/EXT4 can detect the problem at read or write time, but no explicit check at thaw time yet. Feel free to opt-in the new test case if the early check sounds valid. Signed-off-by: Qu Wenruo <wqu@suse.com> --- Changelog: v2: - Move the test case to shared group This allow each fs to opt-in. - Add two new types of super block modification Other than pure garbage, also introduce: * Valid superblock but different fsid * valid superblock and same fsid, but different generation - Remove cache drop To make the explicit thaw time check more obvious. --- tests/shared/001 | 116 +++++++++++++++++++++++++++++++++++++++++++ tests/shared/001.out | 10 ++++ 2 files changed, 126 insertions(+) create mode 100755 tests/shared/001 create mode 100644 tests/shared/001.out