All of lore.kernel.org
 help / color / mirror / Atom feed
From: John Garry <john.g.garry@oracle.com>
To: Alan Adamson <alan.adamson@oracle.com>, linux-block@vger.kernel.org
Cc: linux-scsi@vger.kernel.org, linux-nvme@lists.infradead.org,
	shinichiro.kawasaki@wdc.com
Subject: Re: [PATCH v3 blktests 1/2] scsi/009: add atomic write tests
Date: Thu, 6 Feb 2025 11:57:04 +0000	[thread overview]
Message-ID: <cd61706d-cb16-471c-bcb7-93cf84c79097@oracle.com> (raw)
In-Reply-To: <20250205231100.391005-2-alan.adamson@oracle.com>

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


  parent reply	other threads:[~2025-02-06 11:57 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
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 [this message]
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

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=cd61706d-cb16-471c-bcb7-93cf84c79097@oracle.com \
    --to=john.g.garry@oracle.com \
    --cc=alan.adamson@oracle.com \
    --cc=linux-block@vger.kernel.org \
    --cc=linux-nvme@lists.infradead.org \
    --cc=linux-scsi@vger.kernel.org \
    --cc=shinichiro.kawasaki@wdc.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.