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@xxxxxxxxxx> --- tests/nvme/059 | 138 +++++++++++++++++++++++++++++++++++++++++++++ tests/nvme/059.out | 10 ++++ 2 files changed, 148 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..af4a4263329d --- /dev/null +++ b/tests/nvme/059 @@ -0,0 +1,138 @@ +#!/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_kver 6 11 + _have_xfs_io_ver 6 12 0 +} + +test_device() { + local ns_dev + local ctrl_dev + 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 + + echo "Running ${TEST_NAME}" + ns_dev=${TEST_DEV##*/} + ctrl_dev=${ns_dev%n*} + + # TEST 1 - Verify sysfs attributes + sysfs_logical_block_size=$(cat "${TEST_DEV_SYSFS}"/queue/logical_block_size) + sysfs_max_hw_sectors_kb=$(cat "${TEST_DEV_SYSFS}"/queue/max_hw_sectors_kb) + max_hw_bytes=$(( "$sysfs_max_hw_sectors_kb" * 1024 )) + sysfs_atomic_max_bytes=$(cat "${TEST_DEV_SYSFS}"/queue/atomic_write_max_bytes) + sysfs_atomic_unit_max_bytes=$(cat "${TEST_DEV_SYSFS}"/queue/atomic_write_unit_max_bytes) + sysfs_atomic_unit_min_bytes=$(cat "${TEST_DEV_SYSFS}"/queue/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 1 - pass" + else + echo "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 - Verify sysfs atomic_write_unit_max_bytes is consistent 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 2 - pass" + else + echo "TEST 2 - 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 2 - pass" + else + echo "TEST 2 - fail $nvme_nsabp - $atomic_max_bytes - $sysfs_atomic_max_bytes -" \ + "$max_hw_bytes" + fi + fi + + # 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 3 - pass" + else + echo "TEST 3 - fail $statx_atomic_max - $sysfs_atomic_unit_max_bytes" + fi + + # TEST 4 - 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/"$ns_dev" "$sysfs_atomic_unit_max_bytes") + if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ] + then + echo "TEST 4 - pass" + else + echo "TEST 4 - fail $bytes_written - $sysfs_atomic_unit_max_bytes" + fi + + # TEST 5 - 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/"$ns_dev" "$sysfs_atomic_unit_max_bytes") + if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ] + then + echo "TEST 5 - pass" + else + echo "TEST 5 - fail $bytes_written - $sysfs_atomic_unit_max_bytes" + fi + + # 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. + 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 6 - pass" + else + echo "TEST 6 - fail $bytes_written - $bytes_to_write" + fi + + # TEST 7 - perform a pwritev2 with size of sysfs_atomic_unit_max_bytes + logical 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 7 - pass" + else + echo "TEST 7 - 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..45bc5d3566b4 --- /dev/null +++ b/tests/nvme/059.out @@ -0,0 +1,10 @@ +Running nvme/059 +TEST 1 - pass +TEST 2 - pass +TEST 3 - pass +TEST 4 - pass +TEST 5 - pass +TEST 6 - pass +pwrite: Invalid argument +TEST 7 - pass +Test complete -- 2.43.5