]> git.apps.os.sepia.ceph.com Git - xfstests-dev.git/commitdiff
generic: Add atomic write multi-fsblock O_[D]SYNC tests
authorOjaswin Mujoo <ojaswin@linux.ibm.com>
Fri, 19 Sep 2025 06:48:00 +0000 (12:18 +0530)
committerZorro Lang <zlang@kernel.org>
Sat, 18 Oct 2025 15:01:32 +0000 (23:01 +0800)
This adds various atomic write multi-fsblock stress tests
with mixed mappings and O_SYNC, to ensure the data and metadata
is atomically persisted even if there is a shutdown.

Suggested-by: Ritesh Harjani (IBM) <ritesh.list@gmail.com>
Reviewed-by: Darrick J. Wong <djwong@kernel.org>
Reviewed-by: John Garry <john.g.garry@oracle.com>
Signed-off-by: Ojaswin Mujoo <ojaswin@linux.ibm.com>
Signed-off-by: Zorro Lang <zlang@kernel.org>
tests/generic/775 [new file with mode: 0755]
tests/generic/775.out [new file with mode: 0644]

diff --git a/tests/generic/775 b/tests/generic/775
new file mode 100755 (executable)
index 0000000..2a4287b
--- /dev/null
@@ -0,0 +1,138 @@
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 IBM Corporation. All Rights Reserved.
+#
+# FS QA Test No. 775
+#
+# Atomic write multi-fsblock data integrity tests with mixed mappings
+# and O_SYNC
+#
+. ./common/preamble
+. ./common/atomicwrites
+_begin_fstest auto quick rw atomicwrites
+
+_require_scratch_write_atomic_multi_fsblock
+_require_atomic_write_test_commands
+_require_scratch_shutdown
+_require_xfs_io_command "truncate"
+
+_scratch_mkfs >> $seqres.full
+_scratch_mount >> $seqres.full
+
+check_data_integrity() {
+       actual=$(_hexdump $testfile)
+       if [[ "$expected" != "$actual" ]]
+       then
+               echo "Integrity check failed"
+               echo "Integrity check failed" >> $seqres.full
+               echo "# Expected file contents:" >> $seqres.full
+               echo "$expected" >> $seqres.full
+               echo "# Actual file contents:" >> $seqres.full
+               echo "$actual" >> $seqres.full
+
+               _fail "Data integrity check failed. The atomic write was torn."
+       fi
+}
+
+prep_mixed_mapping() {
+       $XFS_IO_PROG -c "truncate 0" $testfile >> $seqres.full
+       local off=0
+       local mapping=""
+
+       local operations=("W" "H" "U")
+       local num_blocks=$((awu_max / blksz))
+       for ((i=0; i<num_blocks; i++)); do
+               local index=$((RANDOM % ${#operations[@]}))
+               local map="${operations[$index]}"
+               local mapping="${mapping}${map}"
+
+               case "$map" in
+                       "W")
+                               $XFS_IO_PROG -dc "pwrite -S 0x61 -b $blksz $off $blksz" $testfile > /dev/null
+                               ;;
+                       "H")
+                               # No operation needed for hole
+                               ;;
+                       "U")
+                               $XFS_IO_PROG -c "falloc $off $blksz" $testfile >> /dev/null
+                               ;;
+               esac
+               off=$((off + blksz))
+       done
+
+       echo "+ + Mixed mapping prep done. Full mapping pattern: $mapping" >> $seqres.full
+
+       sync $testfile
+}
+
+verify_atomic_write() {
+       test $bytes_written -eq $awu_max || _fail "atomic write len=$awu_max assertion failed"
+       check_data_integrity
+}
+
+mixed_mapping_test() {
+       prep_mixed_mapping
+
+       echo -"+ + Performing O_DSYNC atomic write from 0 to $awu_max" >> $seqres.full
+       if [[ "$1" == "shutdown" ]]
+       then
+               bytes_written=$($XFS_IO_PROG -x -dc \
+                               "pwrite -DA -V1 -b $awu_max 0 $awu_max" \
+                               -c "shutdown" $testfile | grep wrote | \
+                               awk -F'[/ ]' '{print $2}')
+               _scratch_cycle_mount >>$seqres.full 2>&1 || _fail "remount failed"
+       else
+               bytes_written=$($XFS_IO_PROG -dc \
+                               "pwrite -DA -V1 -b $awu_max 0 $awu_max" $testfile | \
+                               grep wrote | awk -F'[/ ]' '{print $2}')
+       fi
+
+       verify_atomic_write
+}
+
+testfile=$SCRATCH_MNT/testfile
+touch $testfile
+
+awu_max=$(_get_atomic_write_unit_max $testfile)
+blksz=$(_get_block_size $SCRATCH_MNT)
+
+# Create an expected pattern to compare with
+$XFS_IO_PROG -tc "pwrite -b $awu_max 0 $awu_max" $testfile >> $seqres.full
+expected=$(_hexdump $testfile)
+echo "# Expected file contents:" >> $seqres.full
+echo "$expected" >> $seqres.full
+echo >> $seqres.full
+
+echo "# Test 1: Do O_DSYNC atomic write on random mixed mapping:" >> $seqres.full
+echo >> $seqres.full
+
+iterations=10
+for ((i=1; i<=$iterations; i++)); do
+       echo "=== Mixed Mapping Test Iteration $i ===" >> $seqres.full
+
+       echo "+ Testing without shutdown..." >> $seqres.full
+       mixed_mapping_test
+       echo "Passed!" >> $seqres.full
+
+       echo "+ Testing with sudden shutdown..." >> $seqres.full
+       mixed_mapping_test "shutdown"
+       echo "Passed!" >> $seqres.full
+
+       echo "Iteration $i completed: OK" >> $seqres.full
+       echo >> $seqres.full
+done
+echo "# Test 1: Do O_SYNC atomic write on random mixed mapping ($iterations iterations): OK" >> $seqres.full
+
+
+echo >> $seqres.full
+echo "# Test 2: Do extending O_SYNC atomic writes: " >> $seqres.full
+bytes_written=$($XFS_IO_PROG -x -dstc "pwrite -A -V1 -b $awu_max 0 $awu_max" \
+               -c "shutdown" $testfile | grep wrote | awk -F'[/ ]' '{print $2}')
+_scratch_cycle_mount >>$seqres.full 2>&1 || _fail "remount failed"
+verify_atomic_write
+echo "# Test 2: Do extending O_SYNC atomic writes: OK" >> $seqres.full
+
+# success, all done
+echo "Silence is golden"
+status=0
+exit
diff --git a/tests/generic/775.out b/tests/generic/775.out
new file mode 100644 (file)
index 0000000..e9f0011
--- /dev/null
@@ -0,0 +1,2 @@
+QA output created by 775
+Silence is golden