Re: [PATCH blktests 1/2] scsi/009: add atomic write tests

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Jan 22, 2025 / 00:51, Chaitanya Kulkarni wrote:
> On 1/21/25 14:25, Alan Adamson wrote:
> > 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@xxxxxxxxxx>
> 
> Thanks a lot for the testcase, this is really useful based on
> amount of work has been done on the kernel side.

Agreed, I also think these test cases are valuable :)

> 
> > ---
> >   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)) ];
> 
> can we add some comments for above calculations ?

These are checking xfs_io command version, and I think the numbers and the logic
were copied form _have_kver().

Anyway, I wonder if we really need this helper function. In general, version
dependency is not the best approach and we should avoid them as much as we can.
Instead, I suggest to check output of "xfs_io -c help" command. The old version,
the output is as follows and the -A option is not printed.

$ xfs_io -c help | grep pwrite
pwrite [-i infile [-qdDwNOW] [-s skip]] [-b bs] [-S seed] [-FBR [-Z N]] [-V N] off len -- writes a number of bytes at a specified offset

With this approach, we can implement a helper function with name
_have_xfs_io_atomic_write() or something, and call it from requires() in
scsi/009 and nvme/059.

> 
> > +	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 }')
> 
> same here little comment would be really useful
> 
> > +	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 }')
> 
> same here
> 
> > +	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 }')
> 
> same here
> 
> > +	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

I suggest to remove this kernel version dependency also. Let me describe how to
do it below.

> > +	_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)
> 
> you can also use the local variable for following path to trim down the
> cat operations where :-
> 
> /sys/block/"${SCSI_DEBUG_DEVICES[0]}"/queue
> 
> makes the code easy to read ...
> 
> > +	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)

I agree that these lines are lengthy.

Taking this chance, let me suggest to use fallback_device() and
cleanup_fallback_device(). (They are not well documented, but are used in some
test cases like zbd/001 or block/007). When a test case with test_device()
implements these hooks, blktests runs the test case even when TEST_DEVS is
empty. It calls fallback_device() to set up the test target TEST_DEV then run
test_device(). After the test completion, it calls cleanup_fallback_device() to
clean up TEST_DEV. For this test case, fallback_device() can call
_configure_scsi_debug with atmoic_wr=1 option. With this approach, we can refer
to TEST_DEV and TEST_DEV_SYSFS in test_device().

This approach has following benefits:

- Using TEST_DEV_SYSFS, the sysfs attribute reference codes will simpler and
  similar as nvme/059 in the next patch.
- We can call "_require_test_dev_sysfs queue/atomic_write_max_bytes" in
  device_requires to check that the kernel supports amotic writes. This will
  avoid the kernel version dependency.
- If users have real scsi devices with atomic write support, the users can
  specify the devices in TEST_DEVS and run this test case with them.
  (We need to skip the test if the devices do not support atomic writes,
   by checking the queue/atomic_write_max_bytes value in device_requires())

For your reference, here I share the change needed for this approach. It is
untested. I hope it is enough to convey my idea.

diff --git a/tests/scsi/009 b/tests/scsi/009
index f3ab00f..686cc8a 100755
--- a/tests/scsi/009
+++ b/tests/scsi/009
@@ -13,12 +13,34 @@ QUICK=1
 
 requires() {
 	_have_driver scsi_debug
-	_have_kver 6 11
-	_have_xfs_io_ver 6 12 0
 }
 
-test() {
-	local dev
+device_requires() {
+	_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
+}
+
+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
@@ -36,20 +58,14 @@ test() {
 
 	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)
+	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=$(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)
+	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" ))
 
@@ -102,7 +118,7 @@ test() {
 	fi
 
 	# TEST 5 - check statx stx_atomic_write_unit_min
-	statx_atomic_min=$(run_xfs_io_xstat "$dev" "stat.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 5 - pass"
@@ -111,7 +127,7 @@ test() {
 	fi
 
 	# TEST  6 - check statx stx_atomic_write_unit_max
-	statx_atomic_max=$(run_xfs_io_xstat "$dev" "stat.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 6 - pass"
@@ -121,7 +137,7 @@ test() {
 
 	# 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")
+	bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$sysfs_atomic_unit_max_bytes")
 	if [ "$bytes_written" = "$sysfs_atomic_unit_max_bytes" ]
 	then
 		echo "TEST 7 - pass"
@@ -131,7 +147,7 @@ test() {
 
 	# 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")
+	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 8 - pass"
@@ -142,7 +158,7 @@ test() {
 	# 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")
+	bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$bytes_to_write")
 	if [ "$bytes_written" = "$bytes_to_write" ]
 	then
 		echo "TEST 9 - pass"
@@ -152,7 +168,7 @@ test() {
 
 	# 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")
+	bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$bytes_to_write")
 	if [ "$bytes_written" = "" ]
 	then
 		echo "TEST 10 - pass"
@@ -162,7 +178,7 @@ test() {
 
 	# 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")
+	bytes_written=$(run_xfs_io_pwritev2 "$TEST_DEV" "$sysfs_atomic_unit_min_bytes")
 	if [ "$bytes_written" = "$sysfs_atomic_unit_min_bytes" ]
 	then
 		echo "TEST 11 - pass"
@@ -172,7 +188,7 @@ test() {
 
 	# 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")
+	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 12 - pass"
@@ -191,14 +207,14 @@ test() {
 		echo "TEST 13 - pass"
 		echo "TEST 14 - pass"
 	else
-		bytes_written=$(run_xfs_io_pwritev2 "$dev" "$bytes_to_write")
+		bytes_written=$(run_xfs_io_pwritev2 "$TEST_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")
+		bytes_written=$(run_xfs_io_pwritev2_atomic "$TEST_DEV" "$bytes_to_write")
 		if [ "$bytes_written" = "" ]
 		then
 			echo "TEST 14 - pass"
@@ -207,7 +223,5 @@ test() {
 		fi
 	fi
 
-	_exit_scsi_debug
-
 	echo "Test complete"
 }




[Index of Archives]     [Linux RAID]     [Linux SCSI]     [Linux ATA RAID]     [IDE]     [Linux Wireless]     [Linux Kernel]     [ATH6KL]     [Linux Bluetooth]     [Linux Netdev]     [Kernel Newbies]     [Security]     [Git]     [Netfilter]     [Bugtraq]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Device Mapper]

  Powered by Linux