mbox series

[v3,blktests,0/2] Add atomic write tests for scsi and nvme

Message ID 20250205231100.391005-1-alan.adamson@oracle.com
Headers show
Series Add atomic write tests for scsi and nvme | expand

Message

Alan Adamson Feb. 5, 2025, 11:10 p.m. UTC
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

Comments

Chaitanya Kulkarni Feb. 6, 2025, 6:01 a.m. UTC | #1
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
John Garry Feb. 6, 2025, 11:47 a.m. UTC | #2
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