[PATCH blktests 1/2] scsi/009: add atomic write tests
Alan Adamson
alan.adamson at oracle.com
Tue Jan 21 14:25:29 PST 2025
Uses scsi_debug to test basic atomic write functionality. Testing
areas include:
- Verify sysfs atomic write attributes are consistent with
atomic write attributes advertised by scsi_debug.
- Verify the atomic write paramters of statx are correct using
xfs_io.
- Perform a pwritev2() (with and without RWF_ATOMIC flag) using
xfs_io:
- maximum byte size (atomic_write_unit_max_bytes)
- minimum byte size (atomic_write_unit_min_bytes)
- a write larger than atomic_write_unit_max_bytes
- a write smaller than atomic_write_unit_min_bytes
Signed-off-by: Alan Adamson <alan.adamson at oracle.com>
---
common/xfs | 49 +++++++++++
tests/scsi/009 | 213 +++++++++++++++++++++++++++++++++++++++++++++
tests/scsi/009.out | 18 ++++
3 files changed, 280 insertions(+)
create mode 100755 tests/scsi/009
create mode 100644 tests/scsi/009.out
diff --git a/common/xfs b/common/xfs
index 569770fecd53..284c6d7cdc40 100644
--- a/common/xfs
+++ b/common/xfs
@@ -6,6 +6,28 @@
. common/shellcheck
+_have_xfs_io() {
+ if ! _have_program xfs_io; then
+ return 1
+ fi
+ return 0
+}
+
+# Check whether the version of xfs_io is greater than or equal to $1.$2.$3
+_have_xfs_io_ver() {
+ local d=$1 e=$2 f=$3
+
+ _have_xfs_io || return $?
+
+ IFS='.' read -r a b c < <(xfs_io -V | sed 's/xfs_io version *//')
+ if [ $((a * 65536 + b * 256 + c)) -lt $((d * 65536 + e * 256 + f)) ];
+ then
+ SKIP_REASONS+=("xfs_io version too old")
+ return 1
+ fi
+ return 0
+}
+
_have_xfs() {
_have_fs xfs && _have_program mkfs.xfs
}
@@ -52,3 +74,30 @@ _xfs_run_fio_verify_io() {
return "${rc}"
}
+
+run_xfs_io_pwritev2() {
+ local dev=$1
+ local bytes_to_write=$2
+ local bytes_written
+
+ bytes_written=$(xfs_io -d -C "pwrite -b ${bytes_to_write} -V 1 -D 0 ${bytes_to_write}" "$dev" | grep "wrote" | sed 's/\// /g' | awk '{ print $2 }')
+ echo "$bytes_written"
+}
+
+run_xfs_io_pwritev2_atomic() {
+ local dev=$1
+ local bytes_to_write=$2
+ local bytes_written
+
+ bytes_written=$(xfs_io -d -C "pwrite -b ${bytes_to_write} -V 1 -A -D 0 ${bytes_to_write}" "$dev" | grep "wrote" | sed 's/\// /g' | awk '{ print $2 }')
+ echo "$bytes_written"
+}
+
+run_xfs_io_xstat() {
+ local dev=$1
+ local field=$2
+ local statx_output
+
+ statx_output=$(xfs_io -c "statx -r -m 0x00010000" "$dev" | grep "$field" | awk '{ print $3 }')
+ echo "$statx_output"
+}
diff --git a/tests/scsi/009 b/tests/scsi/009
new file mode 100755
index 000000000000..f3ab00f61369
--- /dev/null
+++ b/tests/scsi/009
@@ -0,0 +1,213 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-3.0+
+# Copyright (C) 2025 Oracle and/or its affiliates
+#
+# Test SCSI Atomic Writes with scsi_debug
+
+. tests/scsi/rc
+. common/scsi_debug
+. common/xfs
+
+DESCRIPTION="test scsi atomic writes"
+QUICK=1
+
+requires() {
+ _have_driver scsi_debug
+ _have_kver 6 11
+ _have_xfs_io_ver 6 12 0
+}
+
+test() {
+ local dev
+ local scsi_debug_atomic_wr_max_length
+ local scsi_debug_atomic_wr_gran
+ local scsi_atomic_max_bytes
+ local scsi_atomic_min_bytes
+ local sysfs_max_hw_sectors_kb
+ local max_hw_bytes
+ local sysfs_logical_block_size
+ local sysfs_atomic_max_bytes
+ local sysfs_atomic_unit_max_bytes
+ local sysfs_atomic_unit_min_bytes
+ local statx_atomic_min
+ local statx_atomic_max
+ local bytes_to_write
+ local bytes_written
+
+ echo "Running ${TEST_NAME}"
+
+ local scsi_debug_params=(
+ delay=0
+ atomic_wr=1
+ )
+ _configure_scsi_debug "${scsi_debug_params[@]}"
+ dev="/dev/${SCSI_DEBUG_DEVICES[0]}"
+ sysfs_logical_block_size=$(cat /sys/block/"${SCSI_DEBUG_DEVICES[0]}"/queue/logical_block_size)
+ sysfs_max_hw_sectors_kb=$(cat /sys/block/"${SCSI_DEBUG_DEVICES[0]}"/queue/max_hw_sectors_kb)
+ max_hw_bytes=$(( "$sysfs_max_hw_sectors_kb" * 1024 ))
+ sysfs_atomic_max_bytes=$(cat /sys/block/"${SCSI_DEBUG_DEVICES[0]}"/queue/atomic_write_max_bytes)
+ sysfs_atomic_unit_max_bytes=$(cat /sys/block/"${SCSI_DEBUG_DEVICES[0]}"/queue/atomic_write_unit_max_bytes)
+ sysfs_atomic_unit_min_bytes=$(cat /sys/block/"${SCSI_DEBUG_DEVICES[0]}"/queue/atomic_write_unit_min_bytes)
+ scsi_debug_atomic_wr_max_length=$(cat /sys/module/scsi_debug/parameters/atomic_wr_max_length)
+ scsi_debug_atomic_wr_gran=$(cat /sys/module/scsi_debug/parameters/atomic_wr_gran)
+ scsi_atomic_max_bytes=$(( "$scsi_debug_atomic_wr_max_length" * "$sysfs_logical_block_size" ))
+ scsi_atomic_min_bytes=$(( "$scsi_debug_atomic_wr_gran" * "$sysfs_logical_block_size" ))
+
+ # TEST 1 - Verify sysfs atomic attributes
+ if [ "$max_hw_bytes" -ge "$sysfs_atomic_max_bytes" ] &&
+ [ "$sysfs_atomic_max_bytes" -ge "$sysfs_atomic_unit_max_bytes" ] &&
+ [ "$sysfs_atomic_unit_max_bytes" -ge "$sysfs_atomic_unit_min_bytes" ]
+ then
+ echo "TEST 1 - pass"
+ else
+ "TEST 1 - fail $max_hw_bytes - $sysfs_max_hw_sectors_kb -" \
+ "$sysfs_atomic_max_bytes - $sysfs_atomic_unit_max_bytes -" \
+ "$sysfs_atomic_unit_min_bytes"
+ fi
+
+ # TEST 2 - check scsi_debug atomic_wr_max_length is the same as sysfs atomic_write_max_bytes
+ if [ "$scsi_atomic_max_bytes" -le "$max_hw_bytes" ]
+ then
+ if [ "$scsi_atomic_max_bytes" = "$sysfs_atomic_max_bytes" ]
+ then
+ echo "TEST 2 - pass"
+ else
+ echo "TEST 2 - fail $scsi_atomic_max_bytes - $max_hw_bytes -" \
+ "$sysfs_atomic_max_bytes"
+ fi
+ else
+ if [ "$sysfs_atomic_max_bytes" = "$max_hw_bytes" ]
+ then
+ echo "TEST 2 - pass"
+ else
+ echo "TEST 2 - fail $scsi_atomic_max_bytes - $max_hw_bytes -" \
+ "$sysfs_atomic_max_bytes"
+ fi
+ fi
+
+ # TEST 3 - check sysfs atomic_write_unit_max_bytes <= scsi_debug atomic_wr_max_length
+ if (("$sysfs_atomic_unit_max_bytes" <= "$scsi_atomic_max_bytes"))
+ then
+ echo "TEST 3 - pass"
+ else
+ echo "TEST 3 - fail $sysfs_atomic_unit_max_bytes - $scsi_atomic_max_bytes"
+ fi
+
+ # TEST 4 - check sysfs atomic_write_unit_min_bytes = scsi_debug atomic_wr_gran
+ if [ "$sysfs_atomic_unit_min_bytes" = "$scsi_atomic_min_bytes" ]
+ then
+ echo "TEST 4 - pass"
+ else
+ echo "TEST 4 - fail $sysfs_atomic_unit_min_bytes - $scsi_atomic_min_bytes"
+ fi
+
+ # TEST 5 - check statx stx_atomic_write_unit_min
+ statx_atomic_min=$(run_xfs_io_xstat "$dev" "stat.atomic_write_unit_min")
+ if [ "$statx_atomic_min" = "$scsi_atomic_min_bytes" ]
+ then
+ echo "TEST 5 - pass"
+ else
+ echo "TEST 5 - fail $statx_atomic_min - $scsi_atomic_min_bytes"
+ fi
+
+ # TEST 6 - check statx stx_atomic_write_unit_max
+ statx_atomic_max=$(run_xfs_io_xstat "$dev" "stat.atomic_write_unit_max")
+ if [ "$statx_atomic_max" = "$sysfs_atomic_unit_max_bytes" ]
+ then
+ echo "TEST 6 - pass"
+ else
+ echo "TEST 6 - fail $statx_atomic_max - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ # TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with no RWF_ATOMIC flag - pwritev2 should
+ # be succesful.
+ bytes_written=$(run_xfs_io_pwritev2 "$dev" "$sysfs_atomic_unit_max_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
+ then
+ echo "TEST 7 - pass"
+ else
+ echo "TEST 7 - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ # TEST 8 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with RWF_ATOMIC flag - pwritev2 should
+ # be succesful.
+ bytes_written=$(run_xfs_io_pwritev2_atomic "$dev" "$sysfs_atomic_unit_max_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
+ then
+ echo "TEST 8 - pass"
+ else
+ echo "TEST 8 - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ # TEST 9 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 bytes with no RWF_ATOMIC flag - pwritev2
+ # should be succesful.
+ bytes_to_write=$(( "${sysfs_atomic_unit_max_bytes}" + "$sysfs_logical_block_size" ))
+ bytes_written=$(run_xfs_io_pwritev2 "$dev" "$bytes_to_write")
+ if [ "$bytes_written" = "$bytes_to_write" ]
+ then
+ echo "TEST 9 - pass"
+ else
+ echo "TEST 9 - fail $bytes_written - $bytes_to_write"
+ fi
+
+ # TEST 10 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 bytes with RWF_ATOMIC flag - pwritev2
+ # should not be succesful.
+ bytes_written=$(run_xfs_io_pwritev2_atomic "$dev" "$bytes_to_write")
+ if [ "$bytes_written" = "" ]
+ then
+ echo "TEST 10 - pass"
+ else
+ echo "TEST 10 - fail $bytes_written - $bytes_to_write"
+ fi
+
+ # TEST 11 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes with no RWF_ATOMIC flag - pwritev2 should
+ # be succesful.
+ bytes_written=$(run_xfs_io_pwritev2 "$dev" "$sysfs_atomic_unit_min_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_min_bytes" ]
+ then
+ echo "TEST 11 - pass"
+ else
+ echo "TEST 11 - fail $bytes_written - $scsi_atomic_min_bytes"
+ fi
+
+ # TEST 12 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes with RWF_ATOMIC flag - pwritev2 should
+ # be succesful.
+ bytes_written=$(run_xfs_io_pwritev2_atomic "$dev" "$sysfs_atomic_unit_min_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_min_bytes" ]
+ then
+ echo "TEST 12 - pass"
+ else
+ echo "TEST 12 - fail $bytes_written - $scsi_atomic_min_bytes"
+ fi
+
+ # TEST 13 - perform a pwritev2 with a size of sysfs_atomic_unit_min_bytes - 512 bytes with no
+ # RWF_ATOMIC flag - pwritev2 should be succesful.
+ # TEST 14 - perform a pwritev2 with a size of sysfs_atomic_unit_min_bytes - 512 bytes with
+ # RWF_ATOMIC flag - pwritev2 should fail.
+ bytes_to_write=$(( "${sysfs_atomic_unit_min_bytes}" - "${sysfs_logical_block_size}" ))
+ if [ "$bytes_to_write" = 0 ]
+ then
+ # sysfs_atomic_unit_min_bytes is set to 1 logical block so these tests aren't needed.
+ echo "TEST 13 - pass"
+ echo "TEST 14 - pass"
+ else
+ bytes_written=$(run_xfs_io_pwritev2 "$dev" "$bytes_to_write")
+ if [ "$bytes_written" = "$bytes_to_write" ]
+ then
+ echo "TEST 13 - pass"
+ else
+ echo "TEST 13 - fail $bytes_written - $bytes_to_write"
+ fi
+ bytes_written=$(run_xfs_io_pwritev2_atomic "$dev" "$bytes_to_write")
+ if [ "$bytes_written" = "" ]
+ then
+ echo "TEST 14 - pass"
+ else
+ echo "TEST 14 - fail $bytes_written - $bytes_to_write"
+ fi
+ fi
+
+ _exit_scsi_debug
+
+ echo "Test complete"
+}
diff --git a/tests/scsi/009.out b/tests/scsi/009.out
new file mode 100644
index 000000000000..3a3382b1190c
--- /dev/null
+++ b/tests/scsi/009.out
@@ -0,0 +1,18 @@
+Running scsi/009
+TEST 1 - pass
+TEST 2 - pass
+TEST 3 - pass
+TEST 4 - pass
+TEST 5 - pass
+TEST 6 - pass
+TEST 7 - pass
+TEST 8 - pass
+TEST 9 - pass
+pwrite: Invalid argument
+TEST 10 - pass
+TEST 11 - pass
+TEST 12 - pass
+TEST 13 - pass
+pwrite: Invalid argument
+TEST 14 - pass
+Test complete
--
2.43.5
More information about the Linux-nvme
mailing list