#! /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
