--- /dev/null
+#! /bin/bash
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2025 IBM Corporation. All Rights Reserved.
+#
+# FS QA Test 061
+#
+# This test does a lot of parallel RWF_ATOMIC IO on a preallocated file to
+# stress the write and end-io unwritten conversion code paths. We brute force
+# this for all possible blocksize and clustersizes and after each iteration we
+# ensure the data was not torn or corrupted using fio crc verification.
+#
+# Note that in this test we use overlapping atomic writes of same io size.
+# Although serializing racing writes is not guaranteed for RWF_ATOMIC, NVMe and
+# SCSI provide this guarantee as an inseparable feature to power-fail
+# atomicity. Keeping the iosize as same also ensures that ext4 doesn't tear the
+# write due to racing ioend unwritten conversion.
+#
+# The value of this test is that we make sure the RWF_ATOMIC is handled
+# correctly by ext4 as well as test that the block layer doesn't split or only
+# generate multiple bios for an atomic write.
+
+. ./common/preamble
+. ./common/atomicwrites
+
+_begin_fstest auto rw stress atomicwrites
+
+_require_scratch_write_atomic
+_require_fio_atomic_writes
+_require_aiodio
+
+FIO_LOAD=$(($(nproc) * 2 * LOAD_FACTOR))
+SIZE=$((100*1024*1024))
+
+# Calculate fsblocksize as per bdev atomic write units.
+bdev_awu_min=$(_get_atomic_write_unit_min $SCRATCH_DEV)
+bdev_awu_max=$(_get_atomic_write_unit_max $SCRATCH_DEV)
+bs=$(_max 4096 "$bdev_awu_min")
+
+function create_fio_configs()
+{
+       local bsize=$1
+       create_fio_aw_config $bsize
+       create_fio_verify_config $bsize
+}
+
+function create_fio_verify_config()
+{
+       local bsize=$1
+cat >$fio_verify_config <<EOF
+       [aio-dio-aw-verify]
+       direct=1
+       ioengine=libaio
+       rw=read
+       bs=$bsize
+       fallocate=native
+       filename=$SCRATCH_MNT/test-file
+       size=$SIZE
+       iodepth=$FIO_LOAD
+       numjobs=$FIO_LOAD
+       atomic=1
+       group_reporting=1
+
+       verify_only=1
+       verify_state_save=0
+       verify=crc32c
+       verify_fatal=1
+       verify_write_sequence=0
+EOF
+}
+
+function create_fio_aw_config()
+{
+       local bsize=$1
+cat >$fio_aw_config <<EOF
+       [aio-dio-aw]
+       direct=1
+       ioengine=libaio
+       rw=randwrite
+       bs=$bsize
+       fallocate=native
+       filename=$SCRATCH_MNT/test-file
+       size=$SIZE
+       iodepth=$FIO_LOAD
+       numjobs=$FIO_LOAD
+       group_reporting=1
+       atomic=1
+
+       verify_state_save=0
+       verify=crc32c
+       do_verify=0
+
+EOF
+}
+
+run_test_one() {
+       local bs=$1
+       local cs=$2
+       local iosize=$3
+
+       MKFS_OPTIONS="-O bigalloc -b $bs -C $cs"
+       _scratch_mkfs_ext4  >> $seqres.full 2>&1 || return
+       if _try_scratch_mount >> $seqres.full 2>&1; then
+               echo "== Testing: bs=$bs cs=$cs iosize=$iosize ==" >> $seqres.full
+
+               touch $SCRATCH_MNT/f1
+               create_fio_configs $iosize
+
+               cat $fio_aw_config >> $seqres.full
+               echo >> $seqres.full
+               cat $fio_verify_config >> $seqres.full
+
+               $FIO_PROG $fio_aw_config >> $seqres.full
+               ret1=$?
+
+               $FIO_PROG $fio_verify_config >> $seqres.full
+               ret2=$?
+
+               _scratch_unmount
+
+               [[ $ret1 -eq 0 && $ret2 -eq 0 ]] || _fail "fio with atomic write failed"
+       fi
+}
+
+run_test() {
+       local bs=$1
+
+       # cluster sizes above 16 x blocksize are experimental so avoid them
+       # Also, cap cluster size at 128kb to keep it reasonable for large
+       # blocks size
+       max_cs=$(_min $((16 * bs)) "$bdev_awu_max" $((128 * 1024)))
+
+       # Fuzz for combinations of blocksize, clustersize and
+       # iosize that cover most of the cases
+       run_test_one $bs $bs $bs
+       run_test_one $bs $max_cs $bs
+       run_test_one $bs $max_cs $max_cs
+       run_test_one $bs $max_cs $(_max "$((max_cs/2))" $bs)
+}
+
+# Let's create a sample fio config to check whether fio supports all options.
+fio_aw_config=$tmp.aw.fio
+fio_verify_config=$tmp.verify.fio
+fio_out=$tmp.fio.out
+
+create_fio_configs $bs
+_require_fio $fio_aw_config
+
+for ((bs=$bs; bs <= $(_get_page_size); bs = $bs << 1)); do
+       run_test $bs
+done
+
+# success, all done
+echo Silence is golden
+status=0
+exit