* [PATCH v3 blktests 0/2] Add atomic write tests for scsi and nvme
@ 2025-02-05 23:10 Alan Adamson
2025-02-05 23:10 ` [PATCH v3 blktests 1/2] scsi/009: add atomic write tests Alan Adamson
2025-02-05 23:11 ` [PATCH v3 blktests 2/2] nvme/059: " Alan Adamson
0 siblings, 2 replies; 7+ messages in thread
From: Alan Adamson @ 2025-02-05 23:10 UTC (permalink / raw)
To: linux-block; +Cc: linux-scsi, alan.adamson, linux-nvme, shinichiro.kawasaki
Changes in v3:
- Remove _have_xfs_io routine and use _have_program.
- Comment cleanup in 0001
- Add SKIP_REASONS when xfs_io -A option is absent.
- Keep lines <=80 characters.
- Move device_requires logic in 0001 and 0002 to common/rc.
Changes in v2:
- Add additional comments in common/xfs
- Remove xfs_io and kernel version checking
- Simplify paths for sysfs attributes
- Fix failed case output (missing echo) in scsi/009
- Add local variable that sets Test # and description (test_desc) for scsi/009 and nvme/059
- Only use scsi_debug device if no scsi test device is provided.
- nvme testing done with qemu-nvme.
- scsi testing done with scsi_debug and qemu-scsi (no atomic write support). No testing on
atomic write capable scsi devices was done.
-------------------------------------------------------------------------------------------
Add tests for atomic write support.
Tests will be delivered for scsi (using scsi_debug) and nvme. NVMe can use the qemu-nvme
emulated device that supports Controller-based Atomic Parameters (QEMU 9.2).
The xfs_io utility delivered with the xfsprogs-devel package (version 6.12) is required by
these tests.
The Linux Kernel 6.11 (and greater) supports Atomic Writes and is required by these tests.
Alan Adamson (2):
scsi/009: add atomic write tests
nvme/059: add atomic write tests
common/rc | 8 ++
common/xfs | 58 ++++++++++++
tests/nvme/059 | 147 +++++++++++++++++++++++++++++
tests/nvme/059.out | 10 ++
tests/scsi/009 | 229 +++++++++++++++++++++++++++++++++++++++++++++
tests/scsi/009.out | 18 ++++
6 files changed, 470 insertions(+)
create mode 100755 tests/nvme/059
create mode 100644 tests/nvme/059.out
create mode 100755 tests/scsi/009
create mode 100644 tests/scsi/009.out
--
2.43.5
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH v3 blktests 1/2] scsi/009: add atomic write tests
2025-02-05 23:10 [PATCH v3 blktests 0/2] Add atomic write tests for scsi and nvme Alan Adamson
@ 2025-02-05 23:10 ` Alan Adamson
2025-02-06 6:00 ` Chaitanya Kulkarni
2025-02-06 11:57 ` John Garry
2025-02-05 23:11 ` [PATCH v3 blktests 2/2] nvme/059: " Alan Adamson
1 sibling, 2 replies; 7+ messages in thread
From: Alan Adamson @ 2025-02-05 23:10 UTC (permalink / raw)
To: linux-block; +Cc: linux-scsi, alan.adamson, linux-nvme, shinichiro.kawasaki
Tests basic atomic write functionality. If no scsi test device is provided,
a scsi_debug device will be used. 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@oracle.com>
---
common/rc | 8 ++
common/xfs | 58 ++++++++++++
tests/scsi/009 | 229 +++++++++++++++++++++++++++++++++++++++++++++
tests/scsi/009.out | 18 ++++
4 files changed, 313 insertions(+)
create mode 100755 tests/scsi/009
create mode 100644 tests/scsi/009.out
diff --git a/common/rc b/common/rc
index bcb215d35114..06c0a416e3e1 100644
--- a/common/rc
+++ b/common/rc
@@ -292,6 +292,14 @@ _require_test_dev_can_discard() {
return 0
}
+_require_device_support_atomic_writes() {
+ _require_test_dev_sysfs queue/atomic_write_max_bytes
+ if (( $(< "${TEST_DEV_SYSFS}"/queue/atomic_write_max_bytes) == 0 )); then
+ SKIP_REASONS+=("${TEST_DEV} does not support atomic write")
+ return 1
+ fi
+}
+
_test_dev_queue_get() {
if [[ $1 = scheduler ]]; then
sed -e 's/.*\[//' -e 's/\].*//' "${TEST_DEV_SYSFS}/queue/scheduler"
diff --git a/common/xfs b/common/xfs
index 569770fecd53..0b1ca7c29049 100644
--- a/common/xfs
+++ b/common/xfs
@@ -6,6 +6,22 @@
. common/shellcheck
+_have_xfs_io_atomic_write() {
+ local s
+
+ _have_program xfs_io || return $?
+
+ # If the pwrite command supports the -A option then this version
+ # of xfs_io supports atomic writes.
+ s=$(xfs_io -c help | grep pwrite | awk '{ print $4}')
+ if [[ $s == *"A"* ]];
+ then
+ return 0
+ fi
+ SKIP_REASONS+=("xfs_io does not support the -A option")
+ return 1
+}
+
_have_xfs() {
_have_fs xfs && _have_program mkfs.xfs
}
@@ -52,3 +68,45 @@ _xfs_run_fio_verify_io() {
return "${rc}"
}
+
+# Use xfs_io to perform a non-atomic write using pwritev2().
+# Args: $1 - device to write to
+# $2 - number of bytes to write
+# Returns: Number of bytes written
+run_xfs_io_pwritev2() {
+ local dev=$1
+ local bytes_to_write=$2
+ local bytes_written
+
+ # Perform write and extract out bytes written from xfs_io output
+ 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"
+}
+
+# Use xfs_io to perform an atomic write using pwritev2().
+# Args: $1 - device to write to
+# $2 - number of bytes to write
+# Returns: Number of bytes written
+run_xfs_io_pwritev2_atomic() {
+ local dev=$1
+ local bytes_to_write=$2
+ local bytes_written
+
+ # Perform atomic write and extract out bytes written from xfs_io output
+ 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..b114d92dd3db
--- /dev/null
+++ b/tests/scsi/009
@@ -0,0 +1,229 @@
+#!/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_xfs_io_atomic_write
+}
+
+device_requires() {
+ _require_device_support_atomic_writes
+}
+
+fallback_device() {
+ local scsi_debug_params=(
+ delay=0
+ atomic_wr=1
+ )
+ if ! _configure_scsi_debug "${scsi_debug_params[@]}"; then
+ return 1
+ fi
+ echo "/dev/${SCSI_DEBUG_DEVICES[0]}"
+}
+
+cleanup_fallback_device() {
+ _exit_scsi_debug
+}
+
+test_device() {
+ 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
+ local test_desc
+
+ echo "Running ${TEST_NAME}"
+
+ sysfs_logical_block_size=$(< "${TEST_DEV_SYSFS}"/queue/logical_block_size)
+ sysfs_max_hw_sectors_kb=$(< "${TEST_DEV_SYSFS}"/queue/max_hw_sectors_kb)
+ max_hw_bytes=$(( "$sysfs_max_hw_sectors_kb" * 1024 ))
+ sysfs_atomic_max_bytes=$(< "${TEST_DEV_SYSFS}"/queue/atomic_write_max_bytes)
+ sysfs_atomic_unit_max_bytes=$(< "${TEST_DEV_SYSFS}"/queue/atomic_write_unit_max_bytes)
+ sysfs_atomic_unit_min_bytes=$(< "${TEST_DEV_SYSFS}"/queue/atomic_write_unit_min_bytes)
+ scsi_debug_atomic_wr_max_length=$(< /sys/module/scsi_debug/parameters/atomic_wr_max_length)
+ scsi_debug_atomic_wr_gran=$(< /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_desc="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_desc - pass"
+ else
+ echo "$test_desc - 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_desc="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_desc - pass"
+ else
+ echo "$test_desc - 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_desc - pass"
+ else
+ echo "$test_desc - fail $scsi_atomic_max_bytes - $max_hw_bytes -" \
+ "$sysfs_atomic_max_bytes"
+ fi
+ fi
+
+ test_desc="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_desc - pass"
+ else
+ echo "$test_desc - fail $sysfs_atomic_unit_max_bytes - $scsi_atomic_max_bytes"
+ fi
+
+ test_desc="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_desc - pass"
+ else
+ echo "$test_desc - fail $sysfs_atomic_unit_min_bytes - $scsi_atomic_min_bytes"
+ fi
+
+ test_desc="TEST 5 - check statx stx_atomic_write_unit_min"
+ statx_atomic_min=$(run_xfs_io_xstat "$TEST_DEV" "stat.atomic_write_unit_min")
+ if [ "$statx_atomic_min" = "$scsi_atomic_min_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $statx_atomic_min - $scsi_atomic_min_bytes"
+ fi
+
+ test_desc="TEST 6 - check statx stx_atomic_write_unit_max"
+ statx_atomic_max=$(run_xfs_io_xstat "$TEST_DEV" "stat.atomic_write_unit_max")
+ if [ "$statx_atomic_max" = "$sysfs_atomic_unit_max_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $statx_atomic_max - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ test_desc="TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes "
+ test_desc+="with no RWF_ATOMIC flag - pwritev2 should be succesful"
+ bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$sysfs_atomic_unit_max_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ test_desc="TEST 8 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with "
+ test_desc+="RWF_ATOMIC flag - pwritev2 should be succesful"
+ bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$sysfs_atomic_unit_max_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ test_desc="TEST 9 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 "
+ test_desc+="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 "$TEST_DEV" "$bytes_to_write")
+ if [ "$bytes_written" = "$bytes_to_write" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $bytes_to_write"
+ fi
+
+ test_desc="TEST 10 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 "
+ test_desc+="bytes with RWF_ATOMIC flag - pwritev2 should not be succesful"
+ bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$bytes_to_write")
+ if [ "$bytes_written" = "" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $bytes_to_write"
+ fi
+
+ test_desc="TEST 11 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes "
+ test_desc+="with no RWF_ATOMIC flag - pwritev2 should be succesful"
+ bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$sysfs_atomic_unit_min_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_min_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $scsi_atomic_min_bytes"
+ fi
+
+ test_desc="TEST 12 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes "
+ test_desc+="with RWF_ATOMIC flag - pwritev2 should be succesful"
+ bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$sysfs_atomic_unit_min_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_min_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $scsi_atomic_min_bytes"
+ fi
+
+ test_desc="TEST 13 - perform a pwritev2 with a size of sysfs_atomic_unit_min_bytes - 512 "
+ test_desc+="bytes with no RWF_ATOMIC flag - pwritev2 should be succesful"
+ bytes_to_write=$(( "${sysfs_atomic_unit_min_bytes}" - "${sysfs_logical_block_size}" ))
+ if [ "$bytes_to_write" = 0 ]
+ then
+ echo "$test_desc - pass"
+ echo "pwrite: Invalid argument"
+ else
+ bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$bytes_to_write")
+ if [ "$bytes_written" = "$bytes_to_write" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $bytes_to_write"
+ fi
+ fi
+ test_desc="TEST 14 - perform a pwritev2 with a size of sysfs_atomic_unit_min_bytes - 512 "
+ test_desc+="bytes with RWF_ATOMIC flag - pwritev2 should fail"
+ if [ "$bytes_to_write" = 0 ]
+ then
+ echo "$test_desc - pass"
+ else
+ bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$bytes_to_write")
+ if [ "$bytes_written" = "" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - 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..e31416b93515
--- /dev/null
+++ b/tests/scsi/009.out
@@ -0,0 +1,18 @@
+Running scsi/009
+TEST 1 - Verify sysfs atomic attributes - pass
+TEST 2 - check scsi_debug atomic_wr_max_length is the same as sysfs atomic_write_max_bytes - pass
+TEST 3 - check sysfs atomic_write_unit_max_bytes <= scsi_debug atomic_wr_max_length - pass
+TEST 4 - check sysfs atomic_write_unit_min_bytes = scsi_debug atomic_wr_gran - pass
+TEST 5 - check statx stx_atomic_write_unit_min - pass
+TEST 6 - check statx stx_atomic_write_unit_max - pass
+TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with no RWF_ATOMIC flag - pwritev2 should be succesful - pass
+TEST 8 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with RWF_ATOMIC flag - pwritev2 should be succesful - pass
+TEST 9 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 bytes with no RWF_ATOMIC flag - pwritev2 should be succesful - pass
+pwrite: Invalid argument
+TEST 10 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 bytes with RWF_ATOMIC flag - pwritev2 should not be succesful - pass
+TEST 11 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes with no RWF_ATOMIC flag - pwritev2 should be succesful - pass
+TEST 12 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes with RWF_ATOMIC flag - pwritev2 should be succesful - pass
+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 - pass
+pwrite: Invalid argument
+TEST 14 - perform a pwritev2 with a size of sysfs_atomic_unit_min_bytes - 512 bytes with RWF_ATOMIC flag - pwritev2 should fail - pass
+Test complete
--
2.43.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH v3 blktests 2/2] nvme/059: add atomic write tests
2025-02-05 23:10 [PATCH v3 blktests 0/2] Add atomic write tests for scsi and nvme Alan Adamson
2025-02-05 23:10 ` [PATCH v3 blktests 1/2] scsi/009: add atomic write tests Alan Adamson
@ 2025-02-05 23:11 ` Alan Adamson
2025-02-06 6:01 ` Chaitanya Kulkarni
2025-02-06 11:47 ` John Garry
1 sibling, 2 replies; 7+ messages in thread
From: Alan Adamson @ 2025-02-05 23:11 UTC (permalink / raw)
To: linux-block; +Cc: linux-scsi, alan.adamson, linux-nvme, shinichiro.kawasaki
Tests basic atomic write functionality using NVMe devices
that support the AWUN and AWUPF Controller Atomic Parameters
and NAWUN and NAWUPF Namespace Atomic Parameters.
Testing areas include:
- Verify sysfs atomic write attributes are consistent with
atomic write capablities advertised by the NVMe HW.
- 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)
- a write larger than atomic_write_unit_max_bytes
Signed-off-by: Alan Adamson <alan.adamson@oracle.com>
---
tests/nvme/059 | 147 +++++++++++++++++++++++++++++++++++++++++++++
tests/nvme/059.out | 10 +++
2 files changed, 157 insertions(+)
create mode 100755 tests/nvme/059
create mode 100644 tests/nvme/059.out
diff --git a/tests/nvme/059 b/tests/nvme/059
new file mode 100755
index 000000000000..24b2bec645a8
--- /dev/null
+++ b/tests/nvme/059
@@ -0,0 +1,147 @@
+#!/bin/bash
+# SPDX-License-Identifier: GPL-3.0+
+# Copyright (C) 2025 Oracle and/or its affiliates
+#
+# Test NVMe Atomic Writes
+
+. tests/nvme/rc
+. common/xfs
+
+DESCRIPTION="test atomic writes"
+QUICK=1
+
+requires() {
+ _nvme_requires
+ _have_program nvme
+ _have_xfs_io_atomic_write
+}
+
+device_requires() {
+ _require_device_support_atomic_writes
+}
+
+test_device() {
+ local ns_dev
+ local ctrl_dev
+ local queue_path
+ local nvme_awupf
+ local nvme_nsfeat
+ local nvme_nsabp
+ local atomic_max_bytes
+ local statx_atomic_max
+ local sysfs_atomic_max_bytes
+ local sysfs_atomic_unit_max_bytes
+ local sysfs_logical_block_size
+ local bytes_written
+ local bytes_to_write
+ local test_desc
+
+ echo "Running ${TEST_NAME}"
+ ns_dev=${TEST_DEV##*/}
+ ctrl_dev=${ns_dev%n*}
+ queue_path="${TEST_DEV_SYSFS}/queue/"
+
+ test_desc="TEST 1 - Verify sysfs attributes"
+
+ sysfs_logical_block_size=$(cat "$queue_path"/logical_block_size)
+ sysfs_max_hw_sectors_kb=$(cat "$queue_path"/max_hw_sectors_kb)
+ max_hw_bytes=$(( "$sysfs_max_hw_sectors_kb" * 1024 ))
+ sysfs_atomic_max_bytes=$(cat "$queue_path"/atomic_write_max_bytes)
+ sysfs_atomic_unit_max_bytes=$(cat "$queue_path"/atomic_write_unit_max_bytes)
+ sysfs_atomic_unit_min_bytes=$(cat "$queue_path"/atomic_write_unit_min_bytes)
+
+ 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_desc - pass"
+ else
+ echo "$test_desc - 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_desc="TEST 2 - Verify sysfs atomic_write_unit_max_bytes is consistent "
+ test_desc+="with NVMe AWUPF/NAWUPF"
+ nvme_nsfeat=$(nvme id-ns /dev/"${ns_dev}" | grep nsfeat | awk '{ print $3}')
+ nvme_nsabp=$((("$nvme_nsfeat" & 0x2) != 0))
+ if [ "$nvme_nsabp" = 1 ] # Check if NSABP is set
+ then
+ nvme_awupf=$(nvme id-ns /dev/"$ns_dev" | grep nawupf | awk '{ print $3}')
+ atomic_max_bytes=$(( ("$nvme_awupf" + 1) * "$sysfs_logical_block_size" ))
+ else
+ nvme_awupf=$(nvme id-ctrl /dev/"${ctrl_dev}" | grep awupf | awk '{ print $3}')
+ atomic_max_bytes=$(( ("$nvme_awupf" + 1) * "$sysfs_logical_block_size" ))
+ fi
+ if [ "$atomic_max_bytes" -le "$max_hw_bytes" ]
+ then
+ if [ "$atomic_max_bytes" = "$sysfs_atomic_max_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $nvme_nsabp - $atomic_max_bytes - $sysfs_atomic_max_bytes -" \
+ "$max_hw_bytes"
+ fi
+ else
+ if [ "$sysfs_atomic_max_bytes" = "$max_hw_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $nvme_nsabp - $atomic_max_bytes - $sysfs_atomic_max_bytes -" \
+ "$max_hw_bytes"
+ fi
+ fi
+
+ test_desc="TEST 3 - Verify statx is correctly reporting atomic_unit_max_bytes"
+ statx_atomic_max=$(run_xfs_io_xstat /dev/"$ns_dev" "stat.atomic_write_unit_max")
+ if [ "$sysfs_atomic_unit_max_bytes" = "$statx_atomic_max" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $statx_atomic_max - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ test_desc="TEST 4 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes "\
+ test_desc+="with no RWF_ATOMIC"
+ # flag - pwritev2 should be succesful.
+ bytes_written=$(run_xfs_io_pwritev2 /dev/"$ns_dev" "$sysfs_atomic_unit_max_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ test_desc="TEST 5 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with "
+ test_desc+="RWF_ATOMIC flag - pwritev2 should be succesful"
+ bytes_written=$(run_xfs_io_pwritev2_atomic /dev/"$ns_dev" "$sysfs_atomic_unit_max_bytes")
+ if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
+ fi
+
+ test_desc="TEST 6 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 1 logical "
+ test_desc+="block 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/"$ns_dev" "$bytes_to_write")
+ if [ "$bytes_written" = "$bytes_to_write" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $bytes_to_write"
+ fi
+
+ test_desc="TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + logical "
+ test_desc+="block with RWF_ATOMIC flag - pwritev2 should not be succesful"
+ bytes_written=$(run_xfs_io_pwritev2_atomic /dev/"$ns_dev" "$bytes_to_write")
+ if [ "$bytes_written" = "" ]
+ then
+ echo "$test_desc - pass"
+ else
+ echo "$test_desc - fail $bytes_written - $bytes_to_write"
+ fi
+
+ echo "Test complete"
+}
diff --git a/tests/nvme/059.out b/tests/nvme/059.out
new file mode 100644
index 000000000000..e803de35776f
--- /dev/null
+++ b/tests/nvme/059.out
@@ -0,0 +1,10 @@
+Running nvme/059
+TEST 1 - Verify sysfs attributes - pass
+TEST 2 - Verify sysfs atomic_write_unit_max_bytes is consistent with NVMe AWUPF/NAWUPF - pass
+TEST 3 - Verify statx is correctly reporting atomic_unit_max_bytes - pass
+TEST 4 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with no RWF_ATOMIC - pass
+TEST 5 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with RWF_ATOMIC flag - pwritev2 should be succesful - pass
+TEST 6 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 1 logical block with no RWF_ATOMIC flag - pwritev2 should be succesful - pass
+pwrite: Invalid argument
+TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + logical block with RWF_ATOMIC flag - pwritev2 should not be succesful - pass
+Test complete
--
2.43.5
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH v3 blktests 1/2] scsi/009: add atomic write tests
2025-02-05 23:10 ` [PATCH v3 blktests 1/2] scsi/009: add atomic write tests Alan Adamson
@ 2025-02-06 6:00 ` Chaitanya Kulkarni
2025-02-06 11:57 ` John Garry
1 sibling, 0 replies; 7+ messages in thread
From: Chaitanya Kulkarni @ 2025-02-06 6:00 UTC (permalink / raw)
To: Alan Adamson, linux-block@vger.kernel.org
Cc: linux-scsi@vger.kernel.org, linux-nvme@lists.infradead.org,
shinichiro.kawasaki@wdc.com
On 2/5/25 15:10, Alan Adamson wrote:
> Tests basic atomic write functionality. If no scsi test device is provided,
> a scsi_debug device will be used. 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@oracle.com>
Looks good.
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
-ck
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 blktests 2/2] nvme/059: add atomic write tests
2025-02-05 23:11 ` [PATCH v3 blktests 2/2] nvme/059: " Alan Adamson
@ 2025-02-06 6:01 ` Chaitanya Kulkarni
2025-02-06 11:47 ` John Garry
1 sibling, 0 replies; 7+ messages in thread
From: Chaitanya Kulkarni @ 2025-02-06 6:01 UTC (permalink / raw)
To: Alan Adamson, linux-block@vger.kernel.org
Cc: linux-scsi@vger.kernel.org, linux-nvme@lists.infradead.org,
shinichiro.kawasaki@wdc.com
On 2/5/25 15:11, Alan Adamson wrote:
> Tests basic atomic write functionality using NVMe devices
> that support the AWUN and AWUPF Controller Atomic Parameters
> and NAWUN and NAWUPF Namespace Atomic Parameters.
>
> Testing areas include:
>
> - Verify sysfs atomic write attributes are consistent with
> atomic write capablities advertised by the NVMe HW.
>
> - 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)
> - a write larger than atomic_write_unit_max_bytes
>
> Signed-off-by: Alan Adamson<alan.adamson@oracle.com>
Looks good.
Reviewed-by: Chaitanya Kulkarni <kch@nvidia.com>
-ck
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 blktests 2/2] nvme/059: add atomic write tests
2025-02-05 23:11 ` [PATCH v3 blktests 2/2] nvme/059: " Alan Adamson
2025-02-06 6:01 ` Chaitanya Kulkarni
@ 2025-02-06 11:47 ` John Garry
1 sibling, 0 replies; 7+ messages in thread
From: John Garry @ 2025-02-06 11:47 UTC (permalink / raw)
To: Alan Adamson, linux-block; +Cc: linux-scsi, linux-nvme, shinichiro.kawasaki
On 05/02/2025 23:11, Alan Adamson wrote:
> Tests basic atomic write functionality using NVMe devices
> that support the AWUN and AWUPF Controller Atomic Parameters
> and NAWUN and NAWUPF Namespace Atomic Parameters.
>
> Testing areas include:
>
> - Verify sysfs atomic write attributes are consistent with
> atomic write capablities advertised by the NVMe HW.
>
> - 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)
> - a write larger than atomic_write_unit_max_bytes
>
> Signed-off-by: Alan Adamson <alan.adamson@oracle.com>
Generally this looks ok, but some comments below.
> ---
> tests/nvme/059 | 147 +++++++++++++++++++++++++++++++++++++++++++++
> tests/nvme/059.out | 10 +++
> 2 files changed, 157 insertions(+)
> create mode 100755 tests/nvme/059
> create mode 100644 tests/nvme/059.out
>
> diff --git a/tests/nvme/059 b/tests/nvme/059
> new file mode 100755
> index 000000000000..24b2bec645a8
> --- /dev/null
> +++ b/tests/nvme/059
> @@ -0,0 +1,147 @@
> +#!/bin/bash
> +# SPDX-License-Identifier: GPL-3.0+
> +# Copyright (C) 2025 Oracle and/or its affiliates
> +#
> +# Test NVMe Atomic Writes
> +
> +. tests/nvme/rc
> +. common/xfs
> +
> +DESCRIPTION="test atomic writes"
> +QUICK=1
> +
> +requires() {
> + _nvme_requires
> + _have_program nvme
> + _have_xfs_io_atomic_write
> +}
> +
> +device_requires() {
> + _require_device_support_atomic_writes
> +}
> +
> +test_device() {
> + local ns_dev
> + local ctrl_dev
> + local queue_path
> + local nvme_awupf
> + local nvme_nsfeat
> + local nvme_nsabp
> + local atomic_max_bytes
> + local statx_atomic_max
> + local sysfs_atomic_max_bytes
> + local sysfs_atomic_unit_max_bytes
> + local sysfs_logical_block_size
> + local bytes_written
> + local bytes_to_write
> + local test_desc
> +
> + echo "Running ${TEST_NAME}"
> + ns_dev=${TEST_DEV##*/}
> + ctrl_dev=${ns_dev%n*}
> + queue_path="${TEST_DEV_SYSFS}/queue/"
> +
> + test_desc="TEST 1 - Verify sysfs attributes"
> +
> + sysfs_logical_block_size=$(cat "$queue_path"/logical_block_size)
> + sysfs_max_hw_sectors_kb=$(cat "$queue_path"/max_hw_sectors_kb)
> + max_hw_bytes=$(( "$sysfs_max_hw_sectors_kb" * 1024 ))
> + sysfs_atomic_max_bytes=$(cat "$queue_path"/atomic_write_max_bytes)
> + sysfs_atomic_unit_max_bytes=$(cat "$queue_path"/atomic_write_unit_max_bytes)
> + sysfs_atomic_unit_min_bytes=$(cat "$queue_path"/atomic_write_unit_min_bytes)
> +
> + 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_desc - pass"
> + else
> + echo "$test_desc - 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_desc="TEST 2 - Verify sysfs atomic_write_unit_max_bytes is consistent "
> + test_desc+="with NVMe AWUPF/NAWUPF"
> + nvme_nsfeat=$(nvme id-ns /dev/"${ns_dev}" | grep nsfeat | awk '{ print $3}')
> + nvme_nsabp=$((("$nvme_nsfeat" & 0x2) != 0))
> + if [ "$nvme_nsabp" = 1 ] # Check if NSABP is set
> + then
> + nvme_awupf=$(nvme id-ns /dev/"$ns_dev" | grep nawupf | awk '{ print $3}')
> + atomic_max_bytes=$(( ("$nvme_awupf" + 1) * "$sysfs_logical_block_size" ))
> + else
> + nvme_awupf=$(nvme id-ctrl /dev/"${ctrl_dev}" | grep awupf | awk '{ print $3}')
> + atomic_max_bytes=$(( ("$nvme_awupf" + 1) * "$sysfs_logical_block_size" ))
> + fi
> + if [ "$atomic_max_bytes" -le "$max_hw_bytes" ]
> + then
> + if [ "$atomic_max_bytes" = "$sysfs_atomic_max_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $nvme_nsabp - $atomic_max_bytes - $sysfs_atomic_max_bytes -" \
> + "$max_hw_bytes"
> + fi
> + else
> + if [ "$sysfs_atomic_max_bytes" = "$max_hw_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $nvme_nsabp - $atomic_max_bytes - $sysfs_atomic_max_bytes -" \
> + "$max_hw_bytes"
> + fi
> + fi
> +
> + test_desc="TEST 3 - Verify statx is correctly reporting atomic_unit_max_bytes"
I suppose that you can also check atomic_unit_min_bytes
And min can be checked in other tests (when applicable).
> + statx_atomic_max=$(run_xfs_io_xstat /dev/"$ns_dev" "stat.atomic_write_unit_max")
> + if [ "$sysfs_atomic_unit_max_bytes" = "$statx_atomic_max" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $statx_atomic_max - $sysfs_atomic_unit_max_bytes"
> + fi
> +
> + test_desc="TEST 4 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes "\
> + test_desc+="with no RWF_ATOMIC"
> + # flag - pwritev2 should be succesful.
> + bytes_written=$(run_xfs_io_pwritev2 /dev/"$ns_dev" "$sysfs_atomic_unit_max_bytes")
> + if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
> + fi
> +
> + test_desc="TEST 5 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with "
> + test_desc+="RWF_ATOMIC flag - pwritev2 should be succesful"
> + bytes_written=$(run_xfs_io_pwritev2_atomic /dev/"$ns_dev" "$sysfs_atomic_unit_max_bytes")
> + if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
> + fi
> +
> + test_desc="TEST 6 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 1 logical "
> + test_desc+="block with no RWF_ATOMIC flag - pwritev2 should be succesful"
I don't really see much value in this test. If this doesn't pass, then
something is really wrong.
> + bytes_to_write=$(( "$sysfs_atomic_unit_max_bytes" + "$sysfs_logical_block_size" ))
> + bytes_written=$(run_xfs_io_pwritev2 /dev/"$ns_dev" "$bytes_to_write")
> + if [ "$bytes_written" = "$bytes_to_write" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $bytes_to_write"
> + fi
> +
> + test_desc="TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + logical "
> + test_desc+="block with RWF_ATOMIC flag - pwritev2 should not be succesful"
nit: I really don't think that "succesful" is the proper spelling
> + bytes_written=$(run_xfs_io_pwritev2_atomic /dev/"$ns_dev" "$bytes_to_write")
> + if [ "$bytes_written" = "" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $bytes_to_write"
> + fi
> +
> + echo "Test complete"
> +}
> diff --git a/tests/nvme/059.out b/tests/nvme/059.out
> new file mode 100644
> index 000000000000..e803de35776f
> --- /dev/null
> +++ b/tests/nvme/059.out
> @@ -0,0 +1,10 @@
> +Running nvme/059
> +TEST 1 - Verify sysfs attributes - pass
> +TEST 2 - Verify sysfs atomic_write_unit_max_bytes is consistent with NVMe AWUPF/NAWUPF - pass
> +TEST 3 - Verify statx is correctly reporting atomic_unit_max_bytes - pass
> +TEST 4 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with no RWF_ATOMIC - pass
> +TEST 5 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with RWF_ATOMIC flag - pwritev2 should be succesful - pass
> +TEST 6 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 1 logical block with no RWF_ATOMIC flag - pwritev2 should be succesful - pass
> +pwrite: Invalid argument
> +TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + logical block with RWF_ATOMIC flag - pwritev2 should not be succesful - pass
> +Test complete
^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [PATCH v3 blktests 1/2] scsi/009: add atomic write tests
2025-02-05 23:10 ` [PATCH v3 blktests 1/2] scsi/009: add atomic write tests Alan Adamson
2025-02-06 6:00 ` Chaitanya Kulkarni
@ 2025-02-06 11:57 ` John Garry
1 sibling, 0 replies; 7+ messages in thread
From: John Garry @ 2025-02-06 11:57 UTC (permalink / raw)
To: Alan Adamson, linux-block; +Cc: linux-scsi, linux-nvme, shinichiro.kawasaki
On 05/02/2025 23:10, Alan Adamson wrote:
> Tests basic atomic write functionality. If no scsi test device is provided,
> a scsi_debug device will be used. 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@oracle.com>
generally looks ok, thanks, but a couple of comments
> ---
> common/rc | 8 ++
> common/xfs | 58 ++++++++++++
I suppose that this common stuff could go in a separate prep patch, but
it doesn't bother me too much
> tests/scsi/009 | 229 +++++++++++++++++++++++++++++++++++++++++++++
> tests/scsi/009.out | 18 ++++
> 4 files changed, 313 insertions(+)
> create mode 100755 tests/scsi/009
> create mode 100644 tests/scsi/009.out
>
> diff --git a/common/rc b/common/rc
> index bcb215d35114..06c0a416e3e1 100644
> --- a/common/rc
> +++ b/common/rc
> @@ -292,6 +292,14 @@ _require_test_dev_can_discard() {
> return 0
> }
>
> +_require_device_support_atomic_writes() {
> + _require_test_dev_sysfs queue/atomic_write_max_bytes
> + if (( $(< "${TEST_DEV_SYSFS}"/queue/atomic_write_max_bytes) == 0 )); then
> + SKIP_REASONS+=("${TEST_DEV} does not support atomic write")
> + return 1
> + fi
> +}
> +
> _test_dev_queue_get() {
> if [[ $1 = scheduler ]]; then
> sed -e 's/.*\[//' -e 's/\].*//' "${TEST_DEV_SYSFS}/queue/scheduler"
> diff --git a/common/xfs b/common/xfs
> index 569770fecd53..0b1ca7c29049 100644
> --- a/common/xfs
> +++ b/common/xfs
> @@ -6,6 +6,22 @@
>
> . common/shellcheck
>
> +_have_xfs_io_atomic_write() {
> + local s
> +
> + _have_program xfs_io || return $?
> +
> + # If the pwrite command supports the -A option then this version
> + # of xfs_io supports atomic writes.
> + s=$(xfs_io -c help | grep pwrite | awk '{ print $4}')
> + if [[ $s == *"A"* ]];
> + then
> + return 0
> + fi
> + SKIP_REASONS+=("xfs_io does not support the -A option")
> + return 1
> +}
> +
> _have_xfs() {
> _have_fs xfs && _have_program mkfs.xfs
> }
> @@ -52,3 +68,45 @@ _xfs_run_fio_verify_io() {
>
> return "${rc}"
> }
> +
> +# Use xfs_io to perform a non-atomic write using pwritev2().
> +# Args: $1 - device to write to
> +# $2 - number of bytes to write
> +# Returns: Number of bytes written
> +run_xfs_io_pwritev2() {
> + local dev=$1
> + local bytes_to_write=$2
> + local bytes_written
> +
> + # Perform write and extract out bytes written from xfs_io output
> + 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"
> +}
> +
> +# Use xfs_io to perform an atomic write using pwritev2().
> +# Args: $1 - device to write to
> +# $2 - number of bytes to write
> +# Returns: Number of bytes written
> +run_xfs_io_pwritev2_atomic() {
> + local dev=$1
> + local bytes_to_write=$2
> + local bytes_written
> +
> + # Perform atomic write and extract out bytes written from xfs_io output
> + 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..b114d92dd3db
> --- /dev/null
> +++ b/tests/scsi/009
> @@ -0,0 +1,229 @@
> +#!/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_xfs_io_atomic_write
> +}
> +
> +device_requires() {
> + _require_device_support_atomic_writes
> +}
> +
> +fallback_device() {
> + local scsi_debug_params=(
> + delay=0
> + atomic_wr=1
> + )
> + if ! _configure_scsi_debug "${scsi_debug_params[@]}"; then
> + return 1
> + fi
> + echo "/dev/${SCSI_DEBUG_DEVICES[0]}"
> +}
> +
> +cleanup_fallback_device() {
> + _exit_scsi_debug
> +}
> +
> +test_device() {
> + 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
> + local test_desc
> +
> + echo "Running ${TEST_NAME}"
> +
> + sysfs_logical_block_size=$(< "${TEST_DEV_SYSFS}"/queue/logical_block_size)
> + sysfs_max_hw_sectors_kb=$(< "${TEST_DEV_SYSFS}"/queue/max_hw_sectors_kb)
> + max_hw_bytes=$(( "$sysfs_max_hw_sectors_kb" * 1024 ))
> + sysfs_atomic_max_bytes=$(< "${TEST_DEV_SYSFS}"/queue/atomic_write_max_bytes)
> + sysfs_atomic_unit_max_bytes=$(< "${TEST_DEV_SYSFS}"/queue/atomic_write_unit_max_bytes)
> + sysfs_atomic_unit_min_bytes=$(< "${TEST_DEV_SYSFS}"/queue/atomic_write_unit_min_bytes)
> + scsi_debug_atomic_wr_max_length=$(< /sys/module/scsi_debug/parameters/atomic_wr_max_length)
> + scsi_debug_atomic_wr_gran=$(< /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_desc="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_desc - pass"
> + else
> + echo "$test_desc - 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_desc="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_desc - pass"
> + else
> + echo "$test_desc - 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_desc - pass"
> + else
> + echo "$test_desc - fail $scsi_atomic_max_bytes - $max_hw_bytes -" \
> + "$sysfs_atomic_max_bytes"
> + fi
> + fi
> +
> + test_desc="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_desc - pass"
> + else
> + echo "$test_desc - fail $sysfs_atomic_unit_max_bytes - $scsi_atomic_max_bytes"
> + fi
> +
> + test_desc="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_desc - pass"
> + else
> + echo "$test_desc - fail $sysfs_atomic_unit_min_bytes - $scsi_atomic_min_bytes"
> + fi
> +
> + test_desc="TEST 5 - check statx stx_atomic_write_unit_min"
> + statx_atomic_min=$(run_xfs_io_xstat "$TEST_DEV" "stat.atomic_write_unit_min")
> + if [ "$statx_atomic_min" = "$scsi_atomic_min_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $statx_atomic_min - $scsi_atomic_min_bytes"
> + fi
> +
> + test_desc="TEST 6 - check statx stx_atomic_write_unit_max"
> + statx_atomic_max=$(run_xfs_io_xstat "$TEST_DEV" "stat.atomic_write_unit_max")
> + if [ "$statx_atomic_max" = "$sysfs_atomic_unit_max_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $statx_atomic_max - $sysfs_atomic_unit_max_bytes"
> + fi
> +
> + test_desc="TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes "
> + test_desc+="with no RWF_ATOMIC flag - pwritev2 should be succesful"
> + bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$sysfs_atomic_unit_max_bytes")
> + if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
> + fi
> +
> + test_desc="TEST 8 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with "
> + test_desc+="RWF_ATOMIC flag - pwritev2 should be succesful"
> + bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$sysfs_atomic_unit_max_bytes")
> + if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $sysfs_atomic_unit_max_bytes"
> + fi
> +
> + test_desc="TEST 9 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 "
> + test_desc+="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 "$TEST_DEV" "$bytes_to_write")
> + if [ "$bytes_written" = "$bytes_to_write" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $bytes_to_write"
> + fi
> +
> + test_desc="TEST 10 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 "
> + test_desc+="bytes with RWF_ATOMIC flag - pwritev2 should not be succesful"
> + bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$bytes_to_write")
> + if [ "$bytes_written" = "" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $bytes_to_write"
> + fi
> +
> + test_desc="TEST 11 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes "
> + test_desc+="with no RWF_ATOMIC flag - pwritev2 should be succesful"
> + bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$sysfs_atomic_unit_min_bytes")
> + if [ "$bytes_written" = "$sysfs_atomic_unit_min_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $scsi_atomic_min_bytes"
> + fi
> +
> + test_desc="TEST 12 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes "
> + test_desc+="with RWF_ATOMIC flag - pwritev2 should be succesful"
> + bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$sysfs_atomic_unit_min_bytes")
> + if [ "$bytes_written" = "$sysfs_atomic_unit_min_bytes" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $scsi_atomic_min_bytes"
> + fi
> +
> + test_desc="TEST 13 - perform a pwritev2 with a size of sysfs_atomic_unit_min_bytes - 512 "
> + test_desc+="bytes with no RWF_ATOMIC flag - pwritev2 should be succesful"
Again, I am not really sure that testing with RWF_ATOMIC has any value here.
> + bytes_to_write=$(( "${sysfs_atomic_unit_min_bytes}" - "${sysfs_logical_block_size}" ))
> + if [ "$bytes_to_write" = 0 ]
> + then
> + echo "$test_desc - pass"
> + echo "pwrite: Invalid argument"
> + else
> + bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$bytes_to_write")
> + if [ "$bytes_written" = "$bytes_to_write" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - fail $bytes_written - $bytes_to_write"
> + fi
> + fi
> + test_desc="TEST 14 - perform a pwritev2 with a size of sysfs_atomic_unit_min_bytes - 512 "
> + test_desc+="bytes with RWF_ATOMIC flag - pwritev2 should fail"
> + if [ "$bytes_to_write" = 0 ]
> + then
> + echo "$test_desc - pass"
> + else
> + bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$bytes_to_write")
> + if [ "$bytes_written" = "" ]
> + then
> + echo "$test_desc - pass"
> + else
> + echo "$test_desc - 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..e31416b93515
> --- /dev/null
> +++ b/tests/scsi/009.out
> @@ -0,0 +1,18 @@
> +Running scsi/009
> +TEST 1 - Verify sysfs atomic attributes - pass
> +TEST 2 - check scsi_debug atomic_wr_max_length is the same as sysfs atomic_write_max_bytes - pass
> +TEST 3 - check sysfs atomic_write_unit_max_bytes <= scsi_debug atomic_wr_max_length - pass
> +TEST 4 - check sysfs atomic_write_unit_min_bytes = scsi_debug atomic_wr_gran - pass
> +TEST 5 - check statx stx_atomic_write_unit_min - pass
> +TEST 6 - check statx stx_atomic_write_unit_max - pass
> +TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with no RWF_ATOMIC flag - pwritev2 should be succesful - pass
> +TEST 8 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes with RWF_ATOMIC flag - pwritev2 should be succesful - pass
> +TEST 9 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 bytes with no RWF_ATOMIC flag - pwritev2 should be succesful - pass
> +pwrite: Invalid argument
> +TEST 10 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + 512 bytes with RWF_ATOMIC flag - pwritev2 should not be succesful - pass
> +TEST 11 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes with no RWF_ATOMIC flag - pwritev2 should be succesful - pass
> +TEST 12 - perform a pwritev2 with size of sysfs_atomic_unit_min_bytes with RWF_ATOMIC flag - pwritev2 should be succesful - pass
> +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 - pass
> +pwrite: Invalid argument
> +TEST 14 - perform a pwritev2 with a size of sysfs_atomic_unit_min_bytes - 512 bytes with RWF_ATOMIC flag - pwritev2 should fail - pass
> +Test complete
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2025-02-06 11:57 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-02-05 23:10 [PATCH v3 blktests 0/2] Add atomic write tests for scsi and nvme Alan Adamson
2025-02-05 23:10 ` [PATCH v3 blktests 1/2] scsi/009: add atomic write tests Alan Adamson
2025-02-06 6:00 ` Chaitanya Kulkarni
2025-02-06 11:57 ` John Garry
2025-02-05 23:11 ` [PATCH v3 blktests 2/2] nvme/059: " Alan Adamson
2025-02-06 6:01 ` Chaitanya Kulkarni
2025-02-06 11:47 ` John Garry
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox