Fix some existing issues in the ublk selftest suite and add coverage for user copy, which is currently untested.
Caleb Sander Mateos (8): selftests: ublk: correct last_rw map type in seq_io.bt selftests: ublk: remove unused ios map in seq_io.bt selftests: ublk: fix fio arguments in run_io_and_recover() selftests: ublk: use auto_zc for PER_IO_DAEMON tests in stress_04 selftests: ublk: don't share backing files between ublk servers selftests: ublk: forbid multiple data copy modes selftests: ublk: add support for user copy to kublk selftests: ublk: add user copy test cases
tools/testing/selftests/ublk/Makefile | 8 ++ tools/testing/selftests/ublk/file_backed.c | 7 +- tools/testing/selftests/ublk/kublk.c | 74 +++++++++++++++---- tools/testing/selftests/ublk/kublk.h | 11 +++ tools/testing/selftests/ublk/stripe.c | 2 +- tools/testing/selftests/ublk/test_common.sh | 5 +- .../testing/selftests/ublk/test_generic_04.sh | 2 +- .../testing/selftests/ublk/test_generic_05.sh | 2 +- .../testing/selftests/ublk/test_generic_09.sh | 2 +- .../testing/selftests/ublk/test_generic_11.sh | 2 +- .../testing/selftests/ublk/test_generic_14.sh | 40 ++++++++++ tools/testing/selftests/ublk/test_loop_06.sh | 25 +++++++ tools/testing/selftests/ublk/test_loop_07.sh | 21 ++++++ tools/testing/selftests/ublk/test_null_03.sh | 24 ++++++ .../testing/selftests/ublk/test_stress_03.sh | 4 +- .../testing/selftests/ublk/test_stress_04.sh | 14 ++-- .../testing/selftests/ublk/test_stress_05.sh | 17 +++-- .../testing/selftests/ublk/test_stress_06.sh | 39 ++++++++++ .../testing/selftests/ublk/test_stress_07.sh | 39 ++++++++++ .../testing/selftests/ublk/test_stripe_05.sh | 26 +++++++ .../testing/selftests/ublk/test_stripe_06.sh | 21 ++++++ tools/testing/selftests/ublk/trace/seq_io.bt | 3 +- 22 files changed, 350 insertions(+), 38 deletions(-) create mode 100755 tools/testing/selftests/ublk/test_generic_14.sh create mode 100755 tools/testing/selftests/ublk/test_loop_06.sh create mode 100755 tools/testing/selftests/ublk/test_loop_07.sh create mode 100755 tools/testing/selftests/ublk/test_null_03.sh create mode 100755 tools/testing/selftests/ublk/test_stress_06.sh create mode 100755 tools/testing/selftests/ublk/test_stress_07.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_05.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_06.sh
The last_rw map is initialized with a value of 0 but later assigned the value args.sector + args.nr_sector, which has type sector_t = u64. bpftrace complains about the type mismatch between int64 and uint64: trace/seq_io.bt:18:3-59: ERROR: Type mismatch for @last_rw: trying to assign value of type 'uint64' when map already contains a value of type 'int64' @last_rw[$dev, str($2)] = (args.sector + args.nr_sector);
Cast the initial value to uint64 so bpftrace will load the program.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com --- tools/testing/selftests/ublk/trace/seq_io.bt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/ublk/trace/seq_io.bt b/tools/testing/selftests/ublk/trace/seq_io.bt index 272ac54c9d5f..507a3ca05abf 100644 --- a/tools/testing/selftests/ublk/trace/seq_io.bt +++ b/tools/testing/selftests/ublk/trace/seq_io.bt @@ -2,11 +2,11 @@ $1: dev_t $2: RWBS $3: strlen($2) */ BEGIN { - @last_rw[$1, str($2)] = 0; + @last_rw[$1, str($2)] = (uint64)0; } tracepoint:block:block_rq_complete { $dev = $1; if ((int64)args.dev == $1 && !strncmp(args.rwbs, str($2), $3)) {
On Wed, Dec 10, 2025 at 10:15:56PM -0700, Caleb Sander Mateos wrote:
The last_rw map is initialized with a value of 0 but later assigned the value args.sector + args.nr_sector, which has type sector_t = u64. bpftrace complains about the type mismatch between int64 and uint64: trace/seq_io.bt:18:3-59: ERROR: Type mismatch for @last_rw: trying to assign value of type 'uint64' when map already contains a value of type 'int64' @last_rw[$dev, str($2)] = (args.sector + args.nr_sector);
Cast the initial value to uint64 so bpftrace will load the program.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/trace/seq_io.bt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/tools/testing/selftests/ublk/trace/seq_io.bt b/tools/testing/selftests/ublk/trace/seq_io.bt index 272ac54c9d5f..507a3ca05abf 100644 --- a/tools/testing/selftests/ublk/trace/seq_io.bt +++ b/tools/testing/selftests/ublk/trace/seq_io.bt @@ -2,11 +2,11 @@ $1: dev_t $2: RWBS $3: strlen($2) */ BEGIN {
- @last_rw[$1, str($2)] = 0;
- @last_rw[$1, str($2)] = (uint64)0;
Reviewed-by: Ming Lei ming.lei@redhat.com
Thanks, Ming
The ios map populated by seq_io.bt is never read, so remove it.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com --- tools/testing/selftests/ublk/trace/seq_io.bt | 1 - 1 file changed, 1 deletion(-)
diff --git a/tools/testing/selftests/ublk/trace/seq_io.bt b/tools/testing/selftests/ublk/trace/seq_io.bt index 507a3ca05abf..b2f60a92b118 100644 --- a/tools/testing/selftests/ublk/trace/seq_io.bt +++ b/tools/testing/selftests/ublk/trace/seq_io.bt @@ -15,11 +15,10 @@ tracepoint:block:block_rq_complete printf("io_out_of_order: exp %llu actual %llu\n", args.sector, $last); } @last_rw[$dev, str($2)] = (args.sector + args.nr_sector); } - @ios = count(); }
END { clear(@last_rw); }
On Wed, Dec 10, 2025 at 10:15:57PM -0700, Caleb Sander Mateos wrote:
The ios map populated by seq_io.bt is never read, so remove it.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/trace/seq_io.bt | 1 - 1 file changed, 1 deletion(-)
diff --git a/tools/testing/selftests/ublk/trace/seq_io.bt b/tools/testing/selftests/ublk/trace/seq_io.bt index 507a3ca05abf..b2f60a92b118 100644 --- a/tools/testing/selftests/ublk/trace/seq_io.bt +++ b/tools/testing/selftests/ublk/trace/seq_io.bt @@ -15,11 +15,10 @@ tracepoint:block:block_rq_complete printf("io_out_of_order: exp %llu actual %llu\n", args.sector, $last); } @last_rw[$dev, str($2)] = (args.sector + args.nr_sector); }
- @ios = count();
BTW, it was for debug purpose, but now it isn't needed.
Reviewed-by: Ming Lei ming.lei@redhat.com
Thanks, Ming ~
run_io_and_recover() invokes fio with --size="${size}", but the variable size doesn't exist. Thus, the argument expands to --size=, which causes fio to exit immediately with an error without issuing any I/O. Pass the value for size as the first argument to the function.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com --- tools/testing/selftests/ublk/test_common.sh | 5 +++-- tools/testing/selftests/ublk/test_generic_04.sh | 2 +- tools/testing/selftests/ublk/test_generic_05.sh | 2 +- tools/testing/selftests/ublk/test_generic_11.sh | 2 +- 4 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/tools/testing/selftests/ublk/test_common.sh b/tools/testing/selftests/ublk/test_common.sh index 8a4dbd09feb0..6f1c042de40e 100755 --- a/tools/testing/selftests/ublk/test_common.sh +++ b/tools/testing/selftests/ublk/test_common.sh @@ -331,15 +331,16 @@ run_io_and_kill_daemon() fi }
run_io_and_recover() { - local action=$1 + local size=$1 + local action=$2 local state local dev_id
- shift 1 + shift 2 dev_id=$(_add_ublk_dev "$@") _check_add_dev "$TID" $?
fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio \ --rw=randread --iodepth=256 --size="${size}" --numjobs=4 \ diff --git a/tools/testing/selftests/ublk/test_generic_04.sh b/tools/testing/selftests/ublk/test_generic_04.sh index 8b533217d4a1..baf5b156193d 100755 --- a/tools/testing/selftests/ublk/test_generic_04.sh +++ b/tools/testing/selftests/ublk/test_generic_04.sh @@ -6,11 +6,11 @@ TID="generic_04" ERR_CODE=0
ublk_run_recover_test() { - run_io_and_recover "kill_daemon" "$@" + run_io_and_recover 256M "kill_daemon" "$@" ERR_CODE=$? if [ ${ERR_CODE} -ne 0 ]; then echo "$TID failure: $*" _show_result $TID $ERR_CODE fi diff --git a/tools/testing/selftests/ublk/test_generic_05.sh b/tools/testing/selftests/ublk/test_generic_05.sh index 398e9e2b58e1..7b5083afc02a 100755 --- a/tools/testing/selftests/ublk/test_generic_05.sh +++ b/tools/testing/selftests/ublk/test_generic_05.sh @@ -6,11 +6,11 @@ TID="generic_05" ERR_CODE=0
ublk_run_recover_test() { - run_io_and_recover "kill_daemon" "$@" + run_io_and_recover 256M "kill_daemon" "$@" ERR_CODE=$? if [ ${ERR_CODE} -ne 0 ]; then echo "$TID failure: $*" _show_result $TID $ERR_CODE fi diff --git a/tools/testing/selftests/ublk/test_generic_11.sh b/tools/testing/selftests/ublk/test_generic_11.sh index a00357a5ec6b..d1f973c8c645 100755 --- a/tools/testing/selftests/ublk/test_generic_11.sh +++ b/tools/testing/selftests/ublk/test_generic_11.sh @@ -6,11 +6,11 @@ TID="generic_11" ERR_CODE=0
ublk_run_quiesce_recover() { - run_io_and_recover "quiesce_dev" "$@" + run_io_and_recover 256M "quiesce_dev" "$@" ERR_CODE=$? if [ ${ERR_CODE} -ne 0 ]; then echo "$TID failure: $*" _show_result $TID $ERR_CODE fi
On Wed, Dec 10, 2025 at 10:15:58PM -0700, Caleb Sander Mateos wrote:
run_io_and_recover() invokes fio with --size="${size}", but the variable size doesn't exist. Thus, the argument expands to --size=, which causes fio to exit immediately with an error without issuing any I/O. Pass the value for size as the first argument to the function.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
Reviewed-by: Ming Lei ming.lei@redhat.com
Thanks, Ming
stress_04 is described as "run IO and kill ublk server(zero copy)" but the --per_io_tasks tests cases don't use zero copy. Plus, one of the test cases is duplicated. Add --auto_zc to these test cases and --auto_zc_fallback to one of the duplicated ones. This matches the test cases in stress_03.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com --- tools/testing/selftests/ublk/test_stress_04.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 3f901db4d09d..965befcee830 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -38,14 +38,14 @@ if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & fi
if _have_feature "PER_IO_DAEMON"; then - ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks & - ublk_io_and_kill_daemon 256M -t loop -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & - ublk_io_and_kill_daemon 256M -t stripe -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & - ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks & + ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & + ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & + ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & + ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & fi wait
_cleanup_test "stress" _show_result $TID $ERR_CODE
On Wed, Dec 10, 2025 at 10:15:59PM -0700, Caleb Sander Mateos wrote:
stress_04 is described as "run IO and kill ublk server(zero copy)" but the --per_io_tasks tests cases don't use zero copy. Plus, one of the test cases is duplicated. Add --auto_zc to these test cases and --auto_zc_fallback to one of the duplicated ones. This matches the test cases in stress_03.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/test_stress_04.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 3f901db4d09d..965befcee830 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -38,14 +38,14 @@ if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & fi if _have_feature "PER_IO_DAEMON"; then
- ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &
- ublk_io_and_kill_daemon 256M -t loop -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &
- ublk_io_and_kill_daemon 256M -t stripe -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
- ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &
- ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks &
- ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &
- ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
- ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &
I'd rather to fix the test description, the original motivation is to cover more data copy parameters(--z, --auto_zc, plain copy) in same stress test.
Thanks, Ming
On Thu, Dec 11, 2025 at 1:06 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:15:59PM -0700, Caleb Sander Mateos wrote:
stress_04 is described as "run IO and kill ublk server(zero copy)" but the --per_io_tasks tests cases don't use zero copy. Plus, one of the test cases is duplicated. Add --auto_zc to these test cases and --auto_zc_fallback to one of the duplicated ones. This matches the test cases in stress_03.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/test_stress_04.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 3f901db4d09d..965befcee830 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -38,14 +38,14 @@ if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & fi
if _have_feature "PER_IO_DAEMON"; then
ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &ublk_io_and_kill_daemon 256M -t loop -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &ublk_io_and_kill_daemon 256M -t stripe -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks &ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &I'd rather to fix the test description, the original motivation is to cover more data copy parameters(--z, --auto_zc, plain copy) in same stress test.
What about the duplicated "-t null -q 4 --nthreads 8 --per_io_tasks" test case? I can't imagine that's intentional...
Thanks, Caleb
On Thu, Dec 11, 2025 at 10:33:20AM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:06 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:15:59PM -0700, Caleb Sander Mateos wrote:
stress_04 is described as "run IO and kill ublk server(zero copy)" but the --per_io_tasks tests cases don't use zero copy. Plus, one of the test cases is duplicated. Add --auto_zc to these test cases and --auto_zc_fallback to one of the duplicated ones. This matches the test cases in stress_03.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/test_stress_04.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 3f901db4d09d..965befcee830 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -38,14 +38,14 @@ if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & fi
if _have_feature "PER_IO_DAEMON"; then
ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &ublk_io_and_kill_daemon 256M -t loop -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &ublk_io_and_kill_daemon 256M -t stripe -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks &ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &I'd rather to fix the test description, the original motivation is to cover more data copy parameters(--z, --auto_zc, plain copy) in same stress test.
What about the duplicated "-t null -q 4 --nthreads 8 --per_io_tasks" test case? I can't imagine that's intentional...
OK, the last one may need to pass '-z' so that --per_io_tasks & -z combination can be covered.
Thanks, Ming
stress_04 is missing a wait between blocks of tests, meaning multiple ublk servers will be running in parallel using the same backing files. Add a wait after each section to ensure each backing file is in use by a single ublk server at a time.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com --- tools/testing/selftests/ublk/test_stress_04.sh | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-)
diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 965befcee830..c7220723b537 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -29,23 +29,25 @@ _create_backfile 1 128M _create_backfile 2 128M
ublk_io_and_kill_daemon 8G -t null -q 4 -z --no_ublk_fixed_fd & ublk_io_and_kill_daemon 256M -t loop -q 4 -z --no_ublk_fixed_fd "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 -z "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & + wait fi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & + wait fi -wait
_cleanup_test "stress" _show_result $TID $ERR_CODE
On Wed, Dec 10, 2025 at 10:16:00PM -0700, Caleb Sander Mateos wrote:
stress_04 is missing a wait between blocks of tests, meaning multiple ublk servers will be running in parallel using the same backing files. Add a wait after each section to ensure each backing file is in use by a single ublk server at a time.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
Reviewed-by: Ming Lei ming.lei@redhat.com
Thanks, Ming
The kublk mock ublk server allows multiple data copy mode arguments to be passed on the command line (--zero_copy, --get_data, and --auto_zc). The ublk device will be created with all the requested feature flags, however kublk will only use one of the modes to interact with request data (arbitrarily preferring auto_zc over zero_copy over get_data). To clarify the intent of the test, don't allow multiple data copy modes to be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an independent feature. Don't require zero_copy for auto_zc_fallback, as only auto_zc is needed. Fix the test cases passing multiple data copy mode arguments.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com --- tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- .../testing/selftests/ublk/test_generic_09.sh | 2 +- .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- .../testing/selftests/ublk/test_stress_04.sh | 2 +- .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- 5 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index f8fa102a627f..1765c4806523 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) break; case 'd': ctx.queue_depth = strtol(optarg, NULL, 10); break; case 'z': - ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY; + ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; break; case 'r': value = strtol(optarg, NULL, 10); if (value) ctx.flags |= UBLK_F_USER_RECOVERY; @@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) optind += 1; break; } }
- /* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */ - if (ctx.auto_zc_fallback && - !((ctx.flags & UBLK_F_AUTO_BUF_REG) && - (ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) { - ublk_err("%s: auto_zc_fallback is set but neither " - "F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n", - __func__); + /* auto_zc_fallback depends on F_AUTO_BUF_REG */ + if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) { + ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n", + __func__); + return -EINVAL; + } + + if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) + + !!(ctx.flags & UBLK_F_NEED_GET_DATA) + + !!(ctx.flags & UBLK_F_USER_COPY) + + !!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) { + fprintf(stderr, "too many data copy modes specified\n"); return -EINVAL; }
i = optind; while (i < argc && ctx.nr_files < MAX_BACK_FILES) { diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh index bb6f77ca5522..145e17b3d2b0 100755 --- a/tools/testing/selftests/ublk/test_generic_09.sh +++ b/tools/testing/selftests/ublk/test_generic_09.sh @@ -14,11 +14,11 @@ if ! _have_program fio; then exit "$UBLK_SKIP_CODE" fi
_prep_test "null" "basic IO test"
-dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) _check_add_dev $TID $?
# run fio over the two disks fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 ERR_CODE=$? diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh index 3ed4c9b2d8c0..8e9f2786ef9c 100755 --- a/tools/testing/selftests/ublk/test_stress_03.sh +++ b/tools/testing/selftests/ublk/test_stress_03.sh @@ -36,19 +36,19 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc & ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & - ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & wait fi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & - ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & wait fi
_cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index c7220723b537..6e165a1f90b4 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -35,11 +35,11 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & - ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & + ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & wait fi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 274295061042..09b94c36f2ba 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do wait done
if _have_feature "ZERO_COPY"; then for reissue in $(seq 0 1); do - ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" & - ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & + ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" & + ublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & wait done fi
if _have_feature "AUTO_BUF_REG"; then for reissue in $(seq 0 1); do - ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" & - ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & - ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" & + ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" & + ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" & wait done fi
if _have_feature "PER_IO_DAEMON"; then
On Wed, Dec 10, 2025 at 10:16:01PM -0700, Caleb Sander Mateos wrote:
The kublk mock ublk server allows multiple data copy mode arguments to be passed on the command line (--zero_copy, --get_data, and --auto_zc). The ublk device will be created with all the requested feature flags, however kublk will only use one of the modes to interact with request data (arbitrarily preferring auto_zc over zero_copy over get_data). To clarify the intent of the test, don't allow multiple data copy modes to be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an independent feature. Don't require zero_copy for auto_zc_fallback, as only auto_zc is needed. Fix the test cases passing multiple data copy mode arguments.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- .../testing/selftests/ublk/test_generic_09.sh | 2 +- .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- .../testing/selftests/ublk/test_stress_04.sh | 2 +- .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- 5 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index f8fa102a627f..1765c4806523 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) break; case 'd': ctx.queue_depth = strtol(optarg, NULL, 10); break; case 'z':
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY;
case 'r': value = strtol(optarg, NULL, 10); if (value) ctx.flags |= UBLK_F_USER_RECOVERY;ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; break;@@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) optind += 1; break; } }
- /* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */
- if (ctx.auto_zc_fallback &&
!((ctx.flags & UBLK_F_AUTO_BUF_REG) &&(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) {ublk_err("%s: auto_zc_fallback is set but neither ""F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n",__func__);
- /* auto_zc_fallback depends on F_AUTO_BUF_REG */
- if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) {
ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n",__func__);return -EINVAL;- }
- if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) +
!!(ctx.flags & UBLK_F_NEED_GET_DATA) +!!(ctx.flags & UBLK_F_USER_COPY) +!!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) { return -EINVAL; }fprintf(stderr, "too many data copy modes specified\n");
Actually most of them are allowed to co-exist, such as -z/--auto_zc/-u.
i = optind; while (i < argc && ctx.nr_files < MAX_BACK_FILES) { diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh index bb6f77ca5522..145e17b3d2b0 100755 --- a/tools/testing/selftests/ublk/test_generic_09.sh +++ b/tools/testing/selftests/ublk/test_generic_09.sh @@ -14,11 +14,11 @@ if ! _have_program fio; then exit "$UBLK_SKIP_CODE" fi _prep_test "null" "basic IO test" -dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) _check_add_dev $TID $? # run fio over the two disks fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 ERR_CODE=$? diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh index 3ed4c9b2d8c0..8e9f2786ef9c 100755 --- a/tools/testing/selftests/ublk/test_stress_03.sh +++ b/tools/testing/selftests/ublk/test_stress_03.sh @@ -36,19 +36,19 @@ wait if _have_feature "AUTO_BUF_REG"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc & ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
- ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
- ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & wait
fi if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
- ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &
- ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & wait
fi _cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index c7220723b537..6e165a1f90b4 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -35,11 +35,11 @@ wait if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
- ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
- ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & wait
fi if _have_feature "PER_IO_DAEMON"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 274295061042..09b94c36f2ba 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do wait done if _have_feature "ZERO_COPY"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" & wait doneublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &fi if _have_feature "AUTO_BUF_REG"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &
ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &
--auto_zc_fallback requires both -z and --auto_zc.
Thanks, Ming
On Thu, Dec 11, 2025 at 1:09 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:16:01PM -0700, Caleb Sander Mateos wrote:
The kublk mock ublk server allows multiple data copy mode arguments to be passed on the command line (--zero_copy, --get_data, and --auto_zc). The ublk device will be created with all the requested feature flags, however kublk will only use one of the modes to interact with request data (arbitrarily preferring auto_zc over zero_copy over get_data). To clarify the intent of the test, don't allow multiple data copy modes to be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an independent feature. Don't require zero_copy for auto_zc_fallback, as only auto_zc is needed. Fix the test cases passing multiple data copy mode arguments.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- .../testing/selftests/ublk/test_generic_09.sh | 2 +- .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- .../testing/selftests/ublk/test_stress_04.sh | 2 +- .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- 5 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index f8fa102a627f..1765c4806523 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) break; case 'd': ctx.queue_depth = strtol(optarg, NULL, 10); break; case 'z':
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY;
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; break; case 'r': value = strtol(optarg, NULL, 10); if (value) ctx.flags |= UBLK_F_USER_RECOVERY;@@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) optind += 1; break; } }
/* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */if (ctx.auto_zc_fallback &&!((ctx.flags & UBLK_F_AUTO_BUF_REG) &&(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) {ublk_err("%s: auto_zc_fallback is set but neither ""F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n",__func__);
/* auto_zc_fallback depends on F_AUTO_BUF_REG */if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) {ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n",__func__);return -EINVAL;}if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) +!!(ctx.flags & UBLK_F_NEED_GET_DATA) +!!(ctx.flags & UBLK_F_USER_COPY) +!!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) {fprintf(stderr, "too many data copy modes specified\n"); return -EINVAL; }Actually most of them are allowed to co-exist, such as -z/--auto_zc/-u.
Yes, I know the ublk driver allows multiple copy mode flags to be set (though it will clear UBLK_F_NEED_GET_DATA if any of the others are set). However, kublk will only actually use one of the modes. For example, --get_data --zero_copy will use zero copy for the data transfer, not get data. And --zero_copy --auto_zc will only use auto buffer registration. So I think it's confusing to allow multiple of these parameters to be passed to kublk. Or do you think there is value in testing ublk device creation with multiple data copy mode flags set, but only one of the modes actually used?
i = optind; while (i < argc && ctx.nr_files < MAX_BACK_FILES) {diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh index bb6f77ca5522..145e17b3d2b0 100755 --- a/tools/testing/selftests/ublk/test_generic_09.sh +++ b/tools/testing/selftests/ublk/test_generic_09.sh @@ -14,11 +14,11 @@ if ! _have_program fio; then exit "$UBLK_SKIP_CODE" fi
_prep_test "null" "basic IO test"
-dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) _check_add_dev $TID $?
# run fio over the two disks fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 ERR_CODE=$? diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh index 3ed4c9b2d8c0..8e9f2786ef9c 100755 --- a/tools/testing/selftests/ublk/test_stress_03.sh +++ b/tools/testing/selftests/ublk/test_stress_03.sh @@ -36,19 +36,19 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc & ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & waitfi
_cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index c7220723b537..6e165a1f90b4 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -35,11 +35,11 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 274295061042..09b94c36f2ba 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do wait done
if _have_feature "ZERO_COPY"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & wait donefi
if _have_feature "AUTO_BUF_REG"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &
ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &--auto_zc_fallback requires both -z and --auto_zc.
Ah, right, I forgot that the fallback path relies on normal zero copy buffer registration. I guess we are missing coverage of that, then, since the tests still passed with --zero_copy disabled.
Thanks, Caleb
On Thu, Dec 11, 2025 at 10:45:36AM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:09 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:16:01PM -0700, Caleb Sander Mateos wrote:
The kublk mock ublk server allows multiple data copy mode arguments to be passed on the command line (--zero_copy, --get_data, and --auto_zc). The ublk device will be created with all the requested feature flags, however kublk will only use one of the modes to interact with request data (arbitrarily preferring auto_zc over zero_copy over get_data). To clarify the intent of the test, don't allow multiple data copy modes to be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an independent feature. Don't require zero_copy for auto_zc_fallback, as only auto_zc is needed. Fix the test cases passing multiple data copy mode arguments.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- .../testing/selftests/ublk/test_generic_09.sh | 2 +- .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- .../testing/selftests/ublk/test_stress_04.sh | 2 +- .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- 5 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index f8fa102a627f..1765c4806523 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) break; case 'd': ctx.queue_depth = strtol(optarg, NULL, 10); break; case 'z':
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY;
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; break; case 'r': value = strtol(optarg, NULL, 10); if (value) ctx.flags |= UBLK_F_USER_RECOVERY;@@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) optind += 1; break; } }
/* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */if (ctx.auto_zc_fallback &&!((ctx.flags & UBLK_F_AUTO_BUF_REG) &&(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) {ublk_err("%s: auto_zc_fallback is set but neither ""F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n",__func__);
/* auto_zc_fallback depends on F_AUTO_BUF_REG */if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) {ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n",__func__);return -EINVAL;}if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) +!!(ctx.flags & UBLK_F_NEED_GET_DATA) +!!(ctx.flags & UBLK_F_USER_COPY) +!!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) {fprintf(stderr, "too many data copy modes specified\n"); return -EINVAL; }Actually most of them are allowed to co-exist, such as -z/--auto_zc/-u.
Yes, I know the ublk driver allows multiple copy mode flags to be set (though it will clear UBLK_F_NEED_GET_DATA if any of the others are set). However, kublk will only actually use one of the modes. For example, --get_data --zero_copy will use zero copy for the data transfer, not get data. And --zero_copy --auto_zc will only use auto buffer registration. So I think it's confusing to allow multiple of these parameters to be passed to kublk. Or do you think there is value in testing ublk device creation with multiple data copy mode flags set, but only one of the modes actually used?
i = optind; while (i < argc && ctx.nr_files < MAX_BACK_FILES) {diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh index bb6f77ca5522..145e17b3d2b0 100755 --- a/tools/testing/selftests/ublk/test_generic_09.sh +++ b/tools/testing/selftests/ublk/test_generic_09.sh @@ -14,11 +14,11 @@ if ! _have_program fio; then exit "$UBLK_SKIP_CODE" fi
_prep_test "null" "basic IO test"
-dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) _check_add_dev $TID $?
# run fio over the two disks fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 ERR_CODE=$? diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh index 3ed4c9b2d8c0..8e9f2786ef9c 100755 --- a/tools/testing/selftests/ublk/test_stress_03.sh +++ b/tools/testing/selftests/ublk/test_stress_03.sh @@ -36,19 +36,19 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc & ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & waitfi
_cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index c7220723b537..6e165a1f90b4 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -35,11 +35,11 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 274295061042..09b94c36f2ba 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do wait done
if _have_feature "ZERO_COPY"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & wait donefi
if _have_feature "AUTO_BUF_REG"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &
ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &--auto_zc_fallback requires both -z and --auto_zc.
Ah, right, I forgot that the fallback path relies on normal zero copy buffer registration. I guess we are missing coverage of that, then, since the tests still passed with --zero_copy disabled.
Looks one regression from commit 0a9beafa7c63 ("ublk: refactor auto buffer register in ublk_dispatch_req()")
Thanks, Ming
The ublk selftests mock ublk server kublk supports every data copy mode except user copy. Add support for user copy to kublk, enabled via the --user_copy (-u) command line argument. On writes, issue pread() calls to copy the write data into the ublk_io's buffer before dispatching the write to the target implementation. On reads, issue pwrite() calls to copy read data from the ublk_io's buffer before committing the request. Copy in 2 KB chunks to provide some coverage of the offseting logic.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com --- tools/testing/selftests/ublk/file_backed.c | 7 +-- tools/testing/selftests/ublk/kublk.c | 53 ++++++++++++++++++++-- tools/testing/selftests/ublk/kublk.h | 11 +++++ tools/testing/selftests/ublk/stripe.c | 2 +- 4 files changed, 64 insertions(+), 9 deletions(-)
diff --git a/tools/testing/selftests/ublk/file_backed.c b/tools/testing/selftests/ublk/file_backed.c index cd9fe69ecce2..269d5f124e06 100644 --- a/tools/testing/selftests/ublk/file_backed.c +++ b/tools/testing/selftests/ublk/file_backed.c @@ -32,12 +32,13 @@ static int loop_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q, { unsigned ublk_op = ublksrv_get_op(iod); unsigned zc = ublk_queue_use_zc(q); unsigned auto_zc = ublk_queue_use_auto_zc(q); enum io_uring_op op = ublk_to_uring_op(iod, zc | auto_zc); + struct ublk_io *io = ublk_get_io(q, tag); struct io_uring_sqe *sqe[3]; - void *addr = (zc | auto_zc) ? NULL : (void *)iod->addr; + void *addr = io->buf_addr;
if (!zc || auto_zc) { ublk_io_alloc_sqes(t, sqe, 1); if (!sqe[0]) return -ENOMEM; @@ -54,11 +55,11 @@ static int loop_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q, return 1; }
ublk_io_alloc_sqes(t, sqe, 3);
- io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index); + io_uring_prep_buf_register(sqe[0], q, tag, q->q_id, io->buf_index); sqe[0]->flags |= IOSQE_CQE_SKIP_SUCCESS | IOSQE_IO_HARDLINK; sqe[0]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[0]->cmd_op), 0, q->q_id, 1);
io_uring_prep_rw(op, sqe[1], ublk_get_registered_fd(q, 1) /*fds[1]*/, 0, @@ -66,11 +67,11 @@ static int loop_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q, iod->start_sector << 9); sqe[1]->buf_index = tag; sqe[1]->flags |= IOSQE_FIXED_FILE | IOSQE_IO_HARDLINK; sqe[1]->user_data = build_user_data(tag, ublk_op, 0, q->q_id, 1);
- io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, ublk_get_io(q, tag)->buf_index); + io_uring_prep_buf_unregister(sqe[2], q, tag, q->q_id, io->buf_index); sqe[2]->user_data = build_user_data(tag, ublk_cmd_op_nr(sqe[2]->cmd_op), 0, q->q_id, 1);
return 2; }
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index 1765c4806523..86443365dcac 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -594,10 +594,42 @@ static void ublk_set_auto_buf_reg(const struct ublk_queue *q, buf.flags = UBLK_AUTO_BUF_REG_FALLBACK;
sqe->addr = ublk_auto_buf_reg_to_sqe_addr(&buf); }
+/* Copy in pieces to test the buffer offset logic */ +#define UBLK_USER_COPY_LEN 2048 + +static void ublk_user_copy(const struct ublk_io *io, __u8 match_ublk_op) +{ + const struct ublk_queue *q = ublk_io_to_queue(io); + const struct ublksrv_io_desc *iod = ublk_get_iod(q, io->tag); + __u64 off = ublk_user_copy_offset(q->q_id, io->tag); + __u8 ublk_op = ublksrv_get_op(iod); + __u32 len = iod->nr_sectors << 9; + void *addr = io->buf_addr; + + if (ublk_op != match_ublk_op) + return; + + while (len) { + __u32 copy_len = min(len, UBLK_USER_COPY_LEN); + ssize_t copied; + + if (ublk_op == UBLK_IO_OP_WRITE) + copied = pread(q->ublk_fd, addr, copy_len, off); + else if (ublk_op == UBLK_IO_OP_READ) + copied = pwrite(q->ublk_fd, addr, copy_len, off); + else + assert(0); + assert(copied == (ssize_t)copy_len); + addr += copy_len; + off += copy_len; + len -= copy_len; + } +} + int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io) { struct ublk_queue *q = ublk_io_to_queue(io); struct ublksrv_io_cmd *cmd; struct io_uring_sqe *sqe[1]; @@ -616,13 +648,16 @@ int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io) (UBLKS_IO_NEED_FETCH_RQ | UBLKS_IO_NEED_COMMIT_RQ_COMP | UBLKS_IO_NEED_GET_DATA))) return 0;
if (io->flags & UBLKS_IO_NEED_GET_DATA) cmd_op = UBLK_U_IO_NEED_GET_DATA; - else if (io->flags & UBLKS_IO_NEED_COMMIT_RQ_COMP) + else if (io->flags & UBLKS_IO_NEED_COMMIT_RQ_COMP) { + if (ublk_queue_use_user_copy(q)) + ublk_user_copy(io, UBLK_IO_OP_READ); + cmd_op = UBLK_U_IO_COMMIT_AND_FETCH_REQ; - else if (io->flags & UBLKS_IO_NEED_FETCH_RQ) + } else if (io->flags & UBLKS_IO_NEED_FETCH_RQ) cmd_op = UBLK_U_IO_FETCH_REQ;
if (io_uring_sq_space_left(&t->ring) < 1) io_uring_submit(&t->ring);
@@ -647,11 +682,11 @@ int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io) else sqe[0]->flags = IOSQE_FIXED_FILE; sqe[0]->rw_flags = 0; cmd->tag = io->tag; cmd->q_id = q->q_id; - if (!ublk_queue_no_buf(q)) + if (!ublk_queue_no_buf(q) && !ublk_queue_use_user_copy(q)) cmd->addr = (__u64) (uintptr_t) io->buf_addr; else cmd->addr = 0;
if (ublk_queue_use_auto_zc(q)) @@ -749,10 +784,14 @@ static void ublk_handle_uring_cmd(struct ublk_thread *t, io->flags &= ~UBLKS_IO_NEED_FETCH_RQ; }
if (cqe->res == UBLK_IO_RES_OK) { assert(tag < q->q_depth); + + if (ublk_queue_use_user_copy(q)) + ublk_user_copy(io, UBLK_IO_OP_WRITE); + if (q->tgt_ops->queue_io) q->tgt_ops->queue_io(t, q, tag); } else if (cqe->res == UBLK_IO_RES_NEED_GET_DATA) { io->flags |= UBLKS_IO_NEED_GET_DATA | UBLKS_IO_FREE; ublk_queue_io_cmd(t, io); @@ -1505,11 +1544,11 @@ static void __cmd_create_help(char *exe, bool recovery) { int i;
printf("%s %s -t [null|loop|stripe|fault_inject] [-q nr_queues] [-d depth] [-n dev_id]\n", exe, recovery ? "recover" : "add"); - printf("\t[--foreground] [--quiet] [-z] [--auto_zc] [--auto_zc_fallback] [--debug_mask mask] [-r 0|1 ] [-g]\n"); + printf("\t[--foreground] [--quiet] [-z] [--auto_zc] [--auto_zc_fallback] [--debug_mask mask] [-r 0|1] [-g] [-u]\n"); printf("\t[-e 0|1 ] [-i 0|1] [--no_ublk_fixed_fd]\n"); printf("\t[--nthreads threads] [--per_io_tasks]\n"); printf("\t[target options] [backfile1] [backfile2] ...\n"); printf("\tdefault: nr_queues=2(max 32), depth=128(max 1024), dev_id=-1(auto allocation)\n"); printf("\tdefault: nthreads=nr_queues"); @@ -1566,10 +1605,11 @@ int main(int argc, char *argv[]) { "recovery_fail_io", 1, NULL, 'e'}, { "recovery_reissue", 1, NULL, 'i'}, { "get_data", 1, NULL, 'g'}, { "auto_zc", 0, NULL, 0 }, { "auto_zc_fallback", 0, NULL, 0 }, + { "user_copy", 0, NULL, 'u'}, { "size", 1, NULL, 's'}, { "nthreads", 1, NULL, 0 }, { "per_io_tasks", 0, NULL, 0 }, { "no_ublk_fixed_fd", 0, NULL, 0 }, { 0, 0, 0, 0 } @@ -1591,11 +1631,11 @@ int main(int argc, char *argv[]) if (argc == 1) return ret;
opterr = 0; optind = 2; - while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:s:gaz", + while ((opt = getopt_long(argc, argv, "t:n:d:q:r:e:i:s:gazu", longopts, &option_idx)) != -1) { switch (opt) { case 'a': ctx.all = 1; break; @@ -1631,10 +1671,13 @@ int main(int argc, char *argv[]) ctx.flags |= UBLK_F_USER_RECOVERY | UBLK_F_USER_RECOVERY_REISSUE; break; case 'g': ctx.flags |= UBLK_F_NEED_GET_DATA; break; + case 'u': + ctx.flags |= UBLK_F_USER_COPY; + break; case 's': ctx.size = strtoull(optarg, NULL, 10); break; case 0: if (!strcmp(longopts[option_idx].name, "debug_mask")) diff --git a/tools/testing/selftests/ublk/kublk.h b/tools/testing/selftests/ublk/kublk.h index fe42705c6d42..fda72e19ef09 100644 --- a/tools/testing/selftests/ublk/kublk.h +++ b/tools/testing/selftests/ublk/kublk.h @@ -206,10 +206,16 @@ extern int ublk_queue_io_cmd(struct ublk_thread *t, struct ublk_io *io); static inline int ublk_io_auto_zc_fallback(const struct ublksrv_io_desc *iod) { return !!(iod->op_flags & UBLK_IO_F_NEED_REG_BUF); }
+static inline __u64 ublk_user_copy_offset(unsigned q_id, unsigned tag) +{ + return UBLKSRV_IO_BUF_OFFSET + + ((__u64)q_id << UBLK_QID_OFF | (__u64)tag << UBLK_TAG_OFF); +} + static inline int is_target_io(__u64 user_data) { return (user_data & (1ULL << 63)) != 0; }
@@ -403,10 +409,15 @@ static inline int ublk_queue_use_auto_zc(const struct ublk_queue *q) static inline int ublk_queue_auto_zc_fallback(const struct ublk_queue *q) { return q->flags & UBLKS_Q_AUTO_BUF_REG_FALLBACK; }
+static inline bool ublk_queue_use_user_copy(const struct ublk_queue *q) +{ + return !!(q->flags & UBLK_F_USER_COPY); +} + static inline int ublk_queue_no_buf(const struct ublk_queue *q) { return ublk_queue_use_zc(q) || ublk_queue_use_auto_zc(q); }
diff --git a/tools/testing/selftests/ublk/stripe.c b/tools/testing/selftests/ublk/stripe.c index 791fa8dc1651..fd412e1f01c0 100644 --- a/tools/testing/selftests/ublk/stripe.c +++ b/tools/testing/selftests/ublk/stripe.c @@ -132,11 +132,11 @@ static int stripe_queue_tgt_rw_io(struct ublk_thread *t, struct ublk_queue *q, enum io_uring_op op = stripe_to_uring_op(iod, zc | auto_zc); struct io_uring_sqe *sqe[NR_STRIPE]; struct stripe_array *s = alloc_stripe_array(conf, iod); struct ublk_io *io = ublk_get_io(q, tag); int i, extra = zc ? 2 : 0; - void *base = (zc | auto_zc) ? NULL : (void *)iod->addr; + void *base = io->buf_addr;
io->private_data = s; calculate_stripe_array(conf, iod, s, base);
ublk_io_alloc_sqes(t, sqe, s->nr + extra);
The ublk selftests cover every data copy mode except user copy. Add tests for user copy based on the existing test suite: - generic_14 ("basic recover function verification (user copy)") based on generic_04 and generic_05 - null_03 ("basic IO test with user copy") based on null_01 and null_02 - loop_06 ("write and verify over user copy") based on loop_01 and loop_03 - loop_07 ("mkfs & mount & umount with user copy") based on loop_02 and loop_04 - stripe_05 ("write and verify test on user copy") based on stripe_03 - stripe_06 ("mkfs & mount & umount on user copy") based on stripe_02 and stripe_04 - Added test cases to stress_05 ("run IO and remove device with recovery enabled") for user copy - stress_06 ("run IO and remove device (user copy)") based on stress_01 and stress_03 - stress_07 ("run IO and kill ublk server (user copy)") based on stress_02 and stress_04
Signed-off-by: Caleb Sander Mateos csander@purestorage.com --- tools/testing/selftests/ublk/Makefile | 8 ++++ .../testing/selftests/ublk/test_generic_14.sh | 40 +++++++++++++++++++ tools/testing/selftests/ublk/test_loop_06.sh | 25 ++++++++++++ tools/testing/selftests/ublk/test_loop_07.sh | 21 ++++++++++ tools/testing/selftests/ublk/test_null_03.sh | 24 +++++++++++ .../testing/selftests/ublk/test_stress_05.sh | 7 ++++ .../testing/selftests/ublk/test_stress_06.sh | 39 ++++++++++++++++++ .../testing/selftests/ublk/test_stress_07.sh | 39 ++++++++++++++++++ .../testing/selftests/ublk/test_stripe_05.sh | 26 ++++++++++++ .../testing/selftests/ublk/test_stripe_06.sh | 21 ++++++++++ 10 files changed, 250 insertions(+) create mode 100755 tools/testing/selftests/ublk/test_generic_14.sh create mode 100755 tools/testing/selftests/ublk/test_loop_06.sh create mode 100755 tools/testing/selftests/ublk/test_loop_07.sh create mode 100755 tools/testing/selftests/ublk/test_null_03.sh create mode 100755 tools/testing/selftests/ublk/test_stress_06.sh create mode 100755 tools/testing/selftests/ublk/test_stress_07.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_05.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_06.sh
diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile index 770269efe42a..837977b62417 100644 --- a/tools/testing/selftests/ublk/Makefile +++ b/tools/testing/selftests/ublk/Makefile @@ -19,28 +19,36 @@ TEST_PROGS += test_generic_08.sh TEST_PROGS += test_generic_09.sh TEST_PROGS += test_generic_10.sh TEST_PROGS += test_generic_11.sh TEST_PROGS += test_generic_12.sh TEST_PROGS += test_generic_13.sh +TEST_PROGS += test_generic_14.sh
TEST_PROGS += test_null_01.sh TEST_PROGS += test_null_02.sh +TEST_PROGS += test_null_03.sh TEST_PROGS += test_loop_01.sh TEST_PROGS += test_loop_02.sh TEST_PROGS += test_loop_03.sh TEST_PROGS += test_loop_04.sh TEST_PROGS += test_loop_05.sh +TEST_PROGS += test_loop_06.sh +TEST_PROGS += test_loop_07.sh TEST_PROGS += test_stripe_01.sh TEST_PROGS += test_stripe_02.sh TEST_PROGS += test_stripe_03.sh TEST_PROGS += test_stripe_04.sh +TEST_PROGS += test_stripe_05.sh +TEST_PROGS += test_stripe_06.sh
TEST_PROGS += test_stress_01.sh TEST_PROGS += test_stress_02.sh TEST_PROGS += test_stress_03.sh TEST_PROGS += test_stress_04.sh TEST_PROGS += test_stress_05.sh +TEST_PROGS += test_stress_06.sh +TEST_PROGS += test_stress_07.sh
TEST_GEN_PROGS_EXTENDED = kublk
include ../lib.mk
diff --git a/tools/testing/selftests/ublk/test_generic_14.sh b/tools/testing/selftests/ublk/test_generic_14.sh new file mode 100755 index 000000000000..cd9b44b97c24 --- /dev/null +++ b/tools/testing/selftests/ublk/test_generic_14.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh + +TID="generic_14" +ERR_CODE=0 + +ublk_run_recover_test() +{ + run_io_and_recover 256M "kill_daemon" "$@" + ERR_CODE=$? + if [ ${ERR_CODE} -ne 0 ]; then + echo "$TID failure: $*" + _show_result $TID $ERR_CODE + fi +} + +if ! _have_program fio; then + exit "$UBLK_SKIP_CODE" +fi + +_prep_test "recover" "basic recover function verification (user copy)" + +_create_backfile 0 256M +_create_backfile 1 128M +_create_backfile 2 128M + +ublk_run_recover_test -t null -q 2 -r 1 -u & +ublk_run_recover_test -t loop -q 2 -r 1 -u "${UBLK_BACKFILES[0]}" & +ublk_run_recover_test -t stripe -q 2 -r 1 -u "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait + +ublk_run_recover_test -t null -q 2 -r 1 -u -i 1 & +ublk_run_recover_test -t loop -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[0]}" & +ublk_run_recover_test -t stripe -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait + +_cleanup_test "recover" +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_loop_06.sh b/tools/testing/selftests/ublk/test_loop_06.sh new file mode 100755 index 000000000000..1d1a8a725502 --- /dev/null +++ b/tools/testing/selftests/ublk/test_loop_06.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh + +TID="loop_06" +ERR_CODE=0 + +if ! _have_program fio; then + exit "$UBLK_SKIP_CODE" +fi + +_prep_test "loop" "write and verify over user copy" + +_create_backfile 0 256M +dev_id=$(_add_ublk_dev -t loop -u "${UBLK_BACKFILES[0]}") +_check_add_dev $TID $? + +# run fio over the ublk disk +_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M +ERR_CODE=$? + +_cleanup_test "loop" + +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_loop_07.sh b/tools/testing/selftests/ublk/test_loop_07.sh new file mode 100755 index 000000000000..493f3fb611a5 --- /dev/null +++ b/tools/testing/selftests/ublk/test_loop_07.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh + +TID="loop_07" +ERR_CODE=0 + +_prep_test "loop" "mkfs & mount & umount with user copy" + +_create_backfile 0 256M + +dev_id=$(_add_ublk_dev -t loop -u "${UBLK_BACKFILES[0]}") +_check_add_dev $TID $? + +_mkfs_mount_test /dev/ublkb"${dev_id}" +ERR_CODE=$? + +_cleanup_test "loop" + +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_null_03.sh b/tools/testing/selftests/ublk/test_null_03.sh new file mode 100755 index 000000000000..0051067b4686 --- /dev/null +++ b/tools/testing/selftests/ublk/test_null_03.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh + +TID="null_03" +ERR_CODE=0 + +if ! _have_program fio; then + exit "$UBLK_SKIP_CODE" +fi + +_prep_test "null" "basic IO test with user copy" + +dev_id=$(_add_ublk_dev -t null -u) +_check_add_dev $TID $? + +# run fio over the two disks +fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 +ERR_CODE=$? + +_cleanup_test "null" + +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 09b94c36f2ba..cb8203957d1d 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -78,7 +78,14 @@ if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 256M -t loop -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 8G -t null -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" & fi wait
+for reissue in $(seq 0 1); do + ublk_io_and_remove 8G -t null -q 4 -u -r 1 -i "$reissue" & + ublk_io_and_remove 256M -t loop -q 4 -u -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & + ublk_io_and_remove 8G -t null -q 4 -u -r 1 -i "$reissue" & + wait +done + _cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_06.sh b/tools/testing/selftests/ublk/test_stress_06.sh new file mode 100755 index 000000000000..37188ec2e1f7 --- /dev/null +++ b/tools/testing/selftests/ublk/test_stress_06.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh +TID="stress_06" +ERR_CODE=0 + +ublk_io_and_remove() +{ + run_io_and_remove "$@" + ERR_CODE=$? + if [ ${ERR_CODE} -ne 0 ]; then + echo "$TID failure: $*" + _show_result $TID $ERR_CODE + fi +} + +if ! _have_program fio; then + exit "$UBLK_SKIP_CODE" +fi + +_prep_test "stress" "run IO and remove device (user copy)" + +_create_backfile 0 256M +_create_backfile 1 128M +_create_backfile 2 128M + +ublk_io_and_remove 8G -t null -q 4 -u & +ublk_io_and_remove 256M -t loop -q 4 -u "${UBLK_BACKFILES[0]}" & +ublk_io_and_remove 256M -t stripe -q 4 -u "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait + +ublk_io_and_remove 8G -t null -q 4 -u --nthreads 8 --per_io_tasks & +ublk_io_and_remove 256M -t loop -q 4 -u --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & +ublk_io_and_remove 256M -t stripe -q 4 -u --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait + +_cleanup_test "stress" +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_07.sh b/tools/testing/selftests/ublk/test_stress_07.sh new file mode 100755 index 000000000000..fb061fc26d36 --- /dev/null +++ b/tools/testing/selftests/ublk/test_stress_07.sh @@ -0,0 +1,39 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh +TID="stress_07" +ERR_CODE=0 + +ublk_io_and_kill_daemon() +{ + run_io_and_kill_daemon "$@" + ERR_CODE=$? + if [ ${ERR_CODE} -ne 0 ]; then + echo "$TID failure: $*" + _show_result $TID $ERR_CODE + fi +} + +if ! _have_program fio; then + exit "$UBLK_SKIP_CODE" +fi + +_prep_test "stress" "run IO and kill ublk server (user copy)" + +_create_backfile 0 256M +_create_backfile 1 128M +_create_backfile 2 128M + +ublk_io_and_kill_daemon 8G -t null -q 4 -u --no_ublk_fixed_fd & +ublk_io_and_kill_daemon 256M -t loop -q 4 -u --no_ublk_fixed_fd "${UBLK_BACKFILES[0]}" & +ublk_io_and_kill_daemon 256M -t stripe -q 4 -u "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait + +ublk_io_and_kill_daemon 8G -t null -q 4 -u --nthreads 8 --per_io_tasks & +ublk_io_and_kill_daemon 256M -t loop -q 4 -u --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & +ublk_io_and_kill_daemon 256M -t stripe -q 4 -u --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait + +_cleanup_test "stress" +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stripe_05.sh b/tools/testing/selftests/ublk/test_stripe_05.sh new file mode 100755 index 000000000000..05d71951d710 --- /dev/null +++ b/tools/testing/selftests/ublk/test_stripe_05.sh @@ -0,0 +1,26 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh + +TID="stripe_05" +ERR_CODE=0 + +if ! _have_program fio; then + exit "$UBLK_SKIP_CODE" +fi + +_prep_test "stripe" "write and verify test on user copy" + +_create_backfile 0 256M +_create_backfile 1 256M + +dev_id=$(_add_ublk_dev -t stripe -q 2 -u "${UBLK_BACKFILES[0]}" "${UBLK_BACKFILES[1]}") +_check_add_dev $TID $? + +# run fio over the ublk disk +_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=512M +ERR_CODE=$? + +_cleanup_test "stripe" +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stripe_06.sh b/tools/testing/selftests/ublk/test_stripe_06.sh new file mode 100755 index 000000000000..d06cac7626e2 --- /dev/null +++ b/tools/testing/selftests/ublk/test_stripe_06.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0 + +. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh + +TID="stripe_06" +ERR_CODE=0 + +_prep_test "stripe" "mkfs & mount & umount on user copy" + +_create_backfile 0 256M +_create_backfile 1 256M + +dev_id=$(_add_ublk_dev -t stripe -u -q 2 "${UBLK_BACKFILES[0]}" "${UBLK_BACKFILES[1]}") +_check_add_dev $TID $? + +_mkfs_mount_test /dev/ublkb"${dev_id}" +ERR_CODE=$? + +_cleanup_test "stripe" +_show_result $TID $ERR_CODE
On Wed, Dec 10, 2025 at 10:16:03PM -0700, Caleb Sander Mateos wrote:
The ublk selftests cover every data copy mode except user copy. Add tests for user copy based on the existing test suite:
- generic_14 ("basic recover function verification (user copy)") based on generic_04 and generic_05
- null_03 ("basic IO test with user copy") based on null_01 and null_02
- loop_06 ("write and verify over user copy") based on loop_01 and loop_03
- loop_07 ("mkfs & mount & umount with user copy") based on loop_02 and loop_04
- stripe_05 ("write and verify test on user copy") based on stripe_03
- stripe_06 ("mkfs & mount & umount on user copy") based on stripe_02 and stripe_04
- Added test cases to stress_05 ("run IO and remove device with recovery enabled") for user copy
- stress_06 ("run IO and remove device (user copy)") based on stress_01 and stress_03
- stress_07 ("run IO and kill ublk server (user copy)") based on stress_02 and stress_04
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/Makefile | 8 ++++ .../testing/selftests/ublk/test_generic_14.sh | 40 +++++++++++++++++++ tools/testing/selftests/ublk/test_loop_06.sh | 25 ++++++++++++ tools/testing/selftests/ublk/test_loop_07.sh | 21 ++++++++++ tools/testing/selftests/ublk/test_null_03.sh | 24 +++++++++++ .../testing/selftests/ublk/test_stress_05.sh | 7 ++++ .../testing/selftests/ublk/test_stress_06.sh | 39 ++++++++++++++++++ .../testing/selftests/ublk/test_stress_07.sh | 39 ++++++++++++++++++ .../testing/selftests/ublk/test_stripe_05.sh | 26 ++++++++++++ .../testing/selftests/ublk/test_stripe_06.sh | 21 ++++++++++ 10 files changed, 250 insertions(+) create mode 100755 tools/testing/selftests/ublk/test_generic_14.sh create mode 100755 tools/testing/selftests/ublk/test_loop_06.sh create mode 100755 tools/testing/selftests/ublk/test_loop_07.sh create mode 100755 tools/testing/selftests/ublk/test_null_03.sh create mode 100755 tools/testing/selftests/ublk/test_stress_06.sh create mode 100755 tools/testing/selftests/ublk/test_stress_07.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_05.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_06.sh
diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile index 770269efe42a..837977b62417 100644 --- a/tools/testing/selftests/ublk/Makefile +++ b/tools/testing/selftests/ublk/Makefile @@ -19,28 +19,36 @@ TEST_PROGS += test_generic_08.sh TEST_PROGS += test_generic_09.sh TEST_PROGS += test_generic_10.sh TEST_PROGS += test_generic_11.sh TEST_PROGS += test_generic_12.sh TEST_PROGS += test_generic_13.sh +TEST_PROGS += test_generic_14.sh TEST_PROGS += test_null_01.sh TEST_PROGS += test_null_02.sh +TEST_PROGS += test_null_03.sh TEST_PROGS += test_loop_01.sh TEST_PROGS += test_loop_02.sh TEST_PROGS += test_loop_03.sh TEST_PROGS += test_loop_04.sh TEST_PROGS += test_loop_05.sh +TEST_PROGS += test_loop_06.sh +TEST_PROGS += test_loop_07.sh TEST_PROGS += test_stripe_01.sh TEST_PROGS += test_stripe_02.sh TEST_PROGS += test_stripe_03.sh TEST_PROGS += test_stripe_04.sh +TEST_PROGS += test_stripe_05.sh +TEST_PROGS += test_stripe_06.sh TEST_PROGS += test_stress_01.sh TEST_PROGS += test_stress_02.sh TEST_PROGS += test_stress_03.sh TEST_PROGS += test_stress_04.sh TEST_PROGS += test_stress_05.sh +TEST_PROGS += test_stress_06.sh +TEST_PROGS += test_stress_07.sh TEST_GEN_PROGS_EXTENDED = kublk include ../lib.mk diff --git a/tools/testing/selftests/ublk/test_generic_14.sh b/tools/testing/selftests/ublk/test_generic_14.sh new file mode 100755 index 000000000000..cd9b44b97c24 --- /dev/null +++ b/tools/testing/selftests/ublk/test_generic_14.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="generic_14" +ERR_CODE=0
+ublk_run_recover_test() +{
- run_io_and_recover 256M "kill_daemon" "$@"
- ERR_CODE=$?
- if [ ${ERR_CODE} -ne 0 ]; then
echo "$TID failure: $*"_show_result $TID $ERR_CODE- fi
+}
+if ! _have_program fio; then
- exit "$UBLK_SKIP_CODE"
+fi
+_prep_test "recover" "basic recover function verification (user copy)"
+_create_backfile 0 256M +_create_backfile 1 128M +_create_backfile 2 128M
+ublk_run_recover_test -t null -q 2 -r 1 -u & +ublk_run_recover_test -t loop -q 2 -r 1 -u "${UBLK_BACKFILES[0]}" & +ublk_run_recover_test -t stripe -q 2 -r 1 -u "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait
+ublk_run_recover_test -t null -q 2 -r 1 -u -i 1 & +ublk_run_recover_test -t loop -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[0]}" & +ublk_run_recover_test -t stripe -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait
+_cleanup_test "recover" +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_loop_06.sh b/tools/testing/selftests/ublk/test_loop_06.sh new file mode 100755 index 000000000000..1d1a8a725502 --- /dev/null +++ b/tools/testing/selftests/ublk/test_loop_06.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="loop_06" +ERR_CODE=0
+if ! _have_program fio; then
- exit "$UBLK_SKIP_CODE"
+fi
+_prep_test "loop" "write and verify over user copy"
+_create_backfile 0 256M +dev_id=$(_add_ublk_dev -t loop -u "${UBLK_BACKFILES[0]}") +_check_add_dev $TID $?
+# run fio over the ublk disk +_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M +ERR_CODE=$?
+_cleanup_test "loop"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_loop_07.sh b/tools/testing/selftests/ublk/test_loop_07.sh new file mode 100755 index 000000000000..493f3fb611a5 --- /dev/null +++ b/tools/testing/selftests/ublk/test_loop_07.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="loop_07" +ERR_CODE=0
+_prep_test "loop" "mkfs & mount & umount with user copy"
+_create_backfile 0 256M
+dev_id=$(_add_ublk_dev -t loop -u "${UBLK_BACKFILES[0]}") +_check_add_dev $TID $?
+_mkfs_mount_test /dev/ublkb"${dev_id}" +ERR_CODE=$?
+_cleanup_test "loop"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_null_03.sh b/tools/testing/selftests/ublk/test_null_03.sh new file mode 100755 index 000000000000..0051067b4686 --- /dev/null +++ b/tools/testing/selftests/ublk/test_null_03.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="null_03" +ERR_CODE=0
+if ! _have_program fio; then
- exit "$UBLK_SKIP_CODE"
+fi
+_prep_test "null" "basic IO test with user copy"
+dev_id=$(_add_ublk_dev -t null -u) +_check_add_dev $TID $?
+# run fio over the two disks +fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 +ERR_CODE=$?
+_cleanup_test "null"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 09b94c36f2ba..cb8203957d1d 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -78,7 +78,14 @@ if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 256M -t loop -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 8G -t null -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" & fi wait +for reissue in $(seq 0 1); do
- ublk_io_and_remove 8G -t null -q 4 -u -r 1 -i "$reissue" &
- ublk_io_and_remove 256M -t loop -q 4 -u -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
- ublk_io_and_remove 8G -t null -q 4 -u -r 1 -i "$reissue" &
- wait
+done
I'd suggest to not add new test coverage in old stress tests until default timeout is overrided, now it is close to default 45 seconds timeout.
Thanks, Ming
On Thu, Dec 11, 2025 at 1:17 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:16:03PM -0700, Caleb Sander Mateos wrote:
The ublk selftests cover every data copy mode except user copy. Add tests for user copy based on the existing test suite:
- generic_14 ("basic recover function verification (user copy)") based on generic_04 and generic_05
- null_03 ("basic IO test with user copy") based on null_01 and null_02
- loop_06 ("write and verify over user copy") based on loop_01 and loop_03
- loop_07 ("mkfs & mount & umount with user copy") based on loop_02 and loop_04
- stripe_05 ("write and verify test on user copy") based on stripe_03
- stripe_06 ("mkfs & mount & umount on user copy") based on stripe_02 and stripe_04
- Added test cases to stress_05 ("run IO and remove device with recovery enabled") for user copy
- stress_06 ("run IO and remove device (user copy)") based on stress_01 and stress_03
- stress_07 ("run IO and kill ublk server (user copy)") based on stress_02 and stress_04
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/Makefile | 8 ++++ .../testing/selftests/ublk/test_generic_14.sh | 40 +++++++++++++++++++ tools/testing/selftests/ublk/test_loop_06.sh | 25 ++++++++++++ tools/testing/selftests/ublk/test_loop_07.sh | 21 ++++++++++ tools/testing/selftests/ublk/test_null_03.sh | 24 +++++++++++ .../testing/selftests/ublk/test_stress_05.sh | 7 ++++ .../testing/selftests/ublk/test_stress_06.sh | 39 ++++++++++++++++++ .../testing/selftests/ublk/test_stress_07.sh | 39 ++++++++++++++++++ .../testing/selftests/ublk/test_stripe_05.sh | 26 ++++++++++++ .../testing/selftests/ublk/test_stripe_06.sh | 21 ++++++++++ 10 files changed, 250 insertions(+) create mode 100755 tools/testing/selftests/ublk/test_generic_14.sh create mode 100755 tools/testing/selftests/ublk/test_loop_06.sh create mode 100755 tools/testing/selftests/ublk/test_loop_07.sh create mode 100755 tools/testing/selftests/ublk/test_null_03.sh create mode 100755 tools/testing/selftests/ublk/test_stress_06.sh create mode 100755 tools/testing/selftests/ublk/test_stress_07.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_05.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_06.sh
diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile index 770269efe42a..837977b62417 100644 --- a/tools/testing/selftests/ublk/Makefile +++ b/tools/testing/selftests/ublk/Makefile @@ -19,28 +19,36 @@ TEST_PROGS += test_generic_08.sh TEST_PROGS += test_generic_09.sh TEST_PROGS += test_generic_10.sh TEST_PROGS += test_generic_11.sh TEST_PROGS += test_generic_12.sh TEST_PROGS += test_generic_13.sh +TEST_PROGS += test_generic_14.sh
TEST_PROGS += test_null_01.sh TEST_PROGS += test_null_02.sh +TEST_PROGS += test_null_03.sh TEST_PROGS += test_loop_01.sh TEST_PROGS += test_loop_02.sh TEST_PROGS += test_loop_03.sh TEST_PROGS += test_loop_04.sh TEST_PROGS += test_loop_05.sh +TEST_PROGS += test_loop_06.sh +TEST_PROGS += test_loop_07.sh TEST_PROGS += test_stripe_01.sh TEST_PROGS += test_stripe_02.sh TEST_PROGS += test_stripe_03.sh TEST_PROGS += test_stripe_04.sh +TEST_PROGS += test_stripe_05.sh +TEST_PROGS += test_stripe_06.sh
TEST_PROGS += test_stress_01.sh TEST_PROGS += test_stress_02.sh TEST_PROGS += test_stress_03.sh TEST_PROGS += test_stress_04.sh TEST_PROGS += test_stress_05.sh +TEST_PROGS += test_stress_06.sh +TEST_PROGS += test_stress_07.sh
TEST_GEN_PROGS_EXTENDED = kublk
include ../lib.mk
diff --git a/tools/testing/selftests/ublk/test_generic_14.sh b/tools/testing/selftests/ublk/test_generic_14.sh new file mode 100755 index 000000000000..cd9b44b97c24 --- /dev/null +++ b/tools/testing/selftests/ublk/test_generic_14.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="generic_14" +ERR_CODE=0
+ublk_run_recover_test() +{
run_io_and_recover 256M "kill_daemon" "$@"ERR_CODE=$?if [ ${ERR_CODE} -ne 0 ]; thenecho "$TID failure: $*"_show_result $TID $ERR_CODEfi+}
+if ! _have_program fio; then
exit "$UBLK_SKIP_CODE"+fi
+_prep_test "recover" "basic recover function verification (user copy)"
+_create_backfile 0 256M +_create_backfile 1 128M +_create_backfile 2 128M
+ublk_run_recover_test -t null -q 2 -r 1 -u & +ublk_run_recover_test -t loop -q 2 -r 1 -u "${UBLK_BACKFILES[0]}" & +ublk_run_recover_test -t stripe -q 2 -r 1 -u "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait
+ublk_run_recover_test -t null -q 2 -r 1 -u -i 1 & +ublk_run_recover_test -t loop -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[0]}" & +ublk_run_recover_test -t stripe -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait
+_cleanup_test "recover" +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_loop_06.sh b/tools/testing/selftests/ublk/test_loop_06.sh new file mode 100755 index 000000000000..1d1a8a725502 --- /dev/null +++ b/tools/testing/selftests/ublk/test_loop_06.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="loop_06" +ERR_CODE=0
+if ! _have_program fio; then
exit "$UBLK_SKIP_CODE"+fi
+_prep_test "loop" "write and verify over user copy"
+_create_backfile 0 256M +dev_id=$(_add_ublk_dev -t loop -u "${UBLK_BACKFILES[0]}") +_check_add_dev $TID $?
+# run fio over the ublk disk +_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M +ERR_CODE=$?
+_cleanup_test "loop"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_loop_07.sh b/tools/testing/selftests/ublk/test_loop_07.sh new file mode 100755 index 000000000000..493f3fb611a5 --- /dev/null +++ b/tools/testing/selftests/ublk/test_loop_07.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="loop_07" +ERR_CODE=0
+_prep_test "loop" "mkfs & mount & umount with user copy"
+_create_backfile 0 256M
+dev_id=$(_add_ublk_dev -t loop -u "${UBLK_BACKFILES[0]}") +_check_add_dev $TID $?
+_mkfs_mount_test /dev/ublkb"${dev_id}" +ERR_CODE=$?
+_cleanup_test "loop"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_null_03.sh b/tools/testing/selftests/ublk/test_null_03.sh new file mode 100755 index 000000000000..0051067b4686 --- /dev/null +++ b/tools/testing/selftests/ublk/test_null_03.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="null_03" +ERR_CODE=0
+if ! _have_program fio; then
exit "$UBLK_SKIP_CODE"+fi
+_prep_test "null" "basic IO test with user copy"
+dev_id=$(_add_ublk_dev -t null -u) +_check_add_dev $TID $?
+# run fio over the two disks +fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 +ERR_CODE=$?
+_cleanup_test "null"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 09b94c36f2ba..cb8203957d1d 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -78,7 +78,14 @@ if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 256M -t loop -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 8G -t null -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" & fi wait
+for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -u -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -u -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 -u -r 1 -i "$reissue" &wait+done
I'd suggest to not add new test coverage in old stress tests until default timeout is overrided, now it is close to default 45 seconds timeout.
Okay, I can just drop the changes in test_stress_05.sh if that sounds good to you?
Thanks, Caleb
On Thu, Dec 11, 2025 at 10:46:41AM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:17 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:16:03PM -0700, Caleb Sander Mateos wrote:
The ublk selftests cover every data copy mode except user copy. Add tests for user copy based on the existing test suite:
- generic_14 ("basic recover function verification (user copy)") based on generic_04 and generic_05
- null_03 ("basic IO test with user copy") based on null_01 and null_02
- loop_06 ("write and verify over user copy") based on loop_01 and loop_03
- loop_07 ("mkfs & mount & umount with user copy") based on loop_02 and loop_04
- stripe_05 ("write and verify test on user copy") based on stripe_03
- stripe_06 ("mkfs & mount & umount on user copy") based on stripe_02 and stripe_04
- Added test cases to stress_05 ("run IO and remove device with recovery enabled") for user copy
- stress_06 ("run IO and remove device (user copy)") based on stress_01 and stress_03
- stress_07 ("run IO and kill ublk server (user copy)") based on stress_02 and stress_04
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/Makefile | 8 ++++ .../testing/selftests/ublk/test_generic_14.sh | 40 +++++++++++++++++++ tools/testing/selftests/ublk/test_loop_06.sh | 25 ++++++++++++ tools/testing/selftests/ublk/test_loop_07.sh | 21 ++++++++++ tools/testing/selftests/ublk/test_null_03.sh | 24 +++++++++++ .../testing/selftests/ublk/test_stress_05.sh | 7 ++++ .../testing/selftests/ublk/test_stress_06.sh | 39 ++++++++++++++++++ .../testing/selftests/ublk/test_stress_07.sh | 39 ++++++++++++++++++ .../testing/selftests/ublk/test_stripe_05.sh | 26 ++++++++++++ .../testing/selftests/ublk/test_stripe_06.sh | 21 ++++++++++ 10 files changed, 250 insertions(+) create mode 100755 tools/testing/selftests/ublk/test_generic_14.sh create mode 100755 tools/testing/selftests/ublk/test_loop_06.sh create mode 100755 tools/testing/selftests/ublk/test_loop_07.sh create mode 100755 tools/testing/selftests/ublk/test_null_03.sh create mode 100755 tools/testing/selftests/ublk/test_stress_06.sh create mode 100755 tools/testing/selftests/ublk/test_stress_07.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_05.sh create mode 100755 tools/testing/selftests/ublk/test_stripe_06.sh
diff --git a/tools/testing/selftests/ublk/Makefile b/tools/testing/selftests/ublk/Makefile index 770269efe42a..837977b62417 100644 --- a/tools/testing/selftests/ublk/Makefile +++ b/tools/testing/selftests/ublk/Makefile @@ -19,28 +19,36 @@ TEST_PROGS += test_generic_08.sh TEST_PROGS += test_generic_09.sh TEST_PROGS += test_generic_10.sh TEST_PROGS += test_generic_11.sh TEST_PROGS += test_generic_12.sh TEST_PROGS += test_generic_13.sh +TEST_PROGS += test_generic_14.sh
TEST_PROGS += test_null_01.sh TEST_PROGS += test_null_02.sh +TEST_PROGS += test_null_03.sh TEST_PROGS += test_loop_01.sh TEST_PROGS += test_loop_02.sh TEST_PROGS += test_loop_03.sh TEST_PROGS += test_loop_04.sh TEST_PROGS += test_loop_05.sh +TEST_PROGS += test_loop_06.sh +TEST_PROGS += test_loop_07.sh TEST_PROGS += test_stripe_01.sh TEST_PROGS += test_stripe_02.sh TEST_PROGS += test_stripe_03.sh TEST_PROGS += test_stripe_04.sh +TEST_PROGS += test_stripe_05.sh +TEST_PROGS += test_stripe_06.sh
TEST_PROGS += test_stress_01.sh TEST_PROGS += test_stress_02.sh TEST_PROGS += test_stress_03.sh TEST_PROGS += test_stress_04.sh TEST_PROGS += test_stress_05.sh +TEST_PROGS += test_stress_06.sh +TEST_PROGS += test_stress_07.sh
TEST_GEN_PROGS_EXTENDED = kublk
include ../lib.mk
diff --git a/tools/testing/selftests/ublk/test_generic_14.sh b/tools/testing/selftests/ublk/test_generic_14.sh new file mode 100755 index 000000000000..cd9b44b97c24 --- /dev/null +++ b/tools/testing/selftests/ublk/test_generic_14.sh @@ -0,0 +1,40 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="generic_14" +ERR_CODE=0
+ublk_run_recover_test() +{
run_io_and_recover 256M "kill_daemon" "$@"ERR_CODE=$?if [ ${ERR_CODE} -ne 0 ]; thenecho "$TID failure: $*"_show_result $TID $ERR_CODEfi+}
+if ! _have_program fio; then
exit "$UBLK_SKIP_CODE"+fi
+_prep_test "recover" "basic recover function verification (user copy)"
+_create_backfile 0 256M +_create_backfile 1 128M +_create_backfile 2 128M
+ublk_run_recover_test -t null -q 2 -r 1 -u & +ublk_run_recover_test -t loop -q 2 -r 1 -u "${UBLK_BACKFILES[0]}" & +ublk_run_recover_test -t stripe -q 2 -r 1 -u "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait
+ublk_run_recover_test -t null -q 2 -r 1 -u -i 1 & +ublk_run_recover_test -t loop -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[0]}" & +ublk_run_recover_test -t stripe -q 2 -r 1 -u -i 1 "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & +wait
+_cleanup_test "recover" +_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_loop_06.sh b/tools/testing/selftests/ublk/test_loop_06.sh new file mode 100755 index 000000000000..1d1a8a725502 --- /dev/null +++ b/tools/testing/selftests/ublk/test_loop_06.sh @@ -0,0 +1,25 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="loop_06" +ERR_CODE=0
+if ! _have_program fio; then
exit "$UBLK_SKIP_CODE"+fi
+_prep_test "loop" "write and verify over user copy"
+_create_backfile 0 256M +dev_id=$(_add_ublk_dev -t loop -u "${UBLK_BACKFILES[0]}") +_check_add_dev $TID $?
+# run fio over the ublk disk +_run_fio_verify_io --filename=/dev/ublkb"${dev_id}" --size=256M +ERR_CODE=$?
+_cleanup_test "loop"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_loop_07.sh b/tools/testing/selftests/ublk/test_loop_07.sh new file mode 100755 index 000000000000..493f3fb611a5 --- /dev/null +++ b/tools/testing/selftests/ublk/test_loop_07.sh @@ -0,0 +1,21 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="loop_07" +ERR_CODE=0
+_prep_test "loop" "mkfs & mount & umount with user copy"
+_create_backfile 0 256M
+dev_id=$(_add_ublk_dev -t loop -u "${UBLK_BACKFILES[0]}") +_check_add_dev $TID $?
+_mkfs_mount_test /dev/ublkb"${dev_id}" +ERR_CODE=$?
+_cleanup_test "loop"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_null_03.sh b/tools/testing/selftests/ublk/test_null_03.sh new file mode 100755 index 000000000000..0051067b4686 --- /dev/null +++ b/tools/testing/selftests/ublk/test_null_03.sh @@ -0,0 +1,24 @@ +#!/bin/bash +# SPDX-License-Identifier: GPL-2.0
+. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
+TID="null_03" +ERR_CODE=0
+if ! _have_program fio; then
exit "$UBLK_SKIP_CODE"+fi
+_prep_test "null" "basic IO test with user copy"
+dev_id=$(_add_ublk_dev -t null -u) +_check_add_dev $TID $?
+# run fio over the two disks +fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 +ERR_CODE=$?
+_cleanup_test "null"
+_show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 09b94c36f2ba..cb8203957d1d 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -78,7 +78,14 @@ if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 256M -t loop -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 8G -t null -q 4 --nthreads 8 --per_io_tasks -r 1 -i "$reissue" & fi wait
+for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -u -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -u -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 -u -r 1 -i "$reissue" &wait+done
I'd suggest to not add new test coverage in old stress tests until default timeout is overrided, now it is close to default 45 seconds timeout.
Okay, I can just drop the changes in test_stress_05.sh if that sounds good to you?
Yeah, it is fine to drop it in test_stress_05.sh.
Thanks, Ming
On Thu, Dec 11, 2025 at 9:14 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 08:59:00PM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 6:38 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 06:06:51PM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 3:05 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 10:45:36AM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:09 AM Ming Lei ming.lei@redhat.com wrote: > > On Wed, Dec 10, 2025 at 10:16:01PM -0700, Caleb Sander Mateos wrote: > > The kublk mock ublk server allows multiple data copy mode arguments to > > be passed on the command line (--zero_copy, --get_data, and --auto_zc). > > The ublk device will be created with all the requested feature flags, > > however kublk will only use one of the modes to interact with request > > data (arbitrarily preferring auto_zc over zero_copy over get_data). To > > clarify the intent of the test, don't allow multiple data copy modes to > > be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an > > independent feature. Don't require zero_copy for auto_zc_fallback, as > > only auto_zc is needed. Fix the test cases passing multiple data copy > > mode arguments. > > > > Signed-off-by: Caleb Sander Mateos csander@purestorage.com > > --- > > tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- > > .../testing/selftests/ublk/test_generic_09.sh | 2 +- > > .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- > > .../testing/selftests/ublk/test_stress_04.sh | 2 +- > > .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- > > 5 files changed, 22 insertions(+), 17 deletions(-) > > > > diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c > > index f8fa102a627f..1765c4806523 100644 > > --- a/tools/testing/selftests/ublk/kublk.c > > +++ b/tools/testing/selftests/ublk/kublk.c > > @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) > > break; > > case 'd': > > ctx.queue_depth = strtol(optarg, NULL, 10); > > break; > > case 'z': > > - ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY; > > + ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; > > break; > > case 'r': > > value = strtol(optarg, NULL, 10); > > if (value) > > ctx.flags |= UBLK_F_USER_RECOVERY; > > @@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) > > optind += 1; > > break; > > } > > } > > > > - /* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */ > > - if (ctx.auto_zc_fallback && > > - !((ctx.flags & UBLK_F_AUTO_BUF_REG) && > > - (ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) { > > - ublk_err("%s: auto_zc_fallback is set but neither " > > - "F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n", > > - __func__); > > + /* auto_zc_fallback depends on F_AUTO_BUF_REG */ > > + if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) { > > + ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n", > > + __func__); > > + return -EINVAL; > > + } > > + > > + if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) + > > + !!(ctx.flags & UBLK_F_NEED_GET_DATA) + > > + !!(ctx.flags & UBLK_F_USER_COPY) + > > + !!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) { > > + fprintf(stderr, "too many data copy modes specified\n"); > > return -EINVAL; > > } > > Actually most of them are allowed to co-exist, such as -z/--auto_zc/-u.
Yes, I know the ublk driver allows multiple copy mode flags to be set (though it will clear UBLK_F_NEED_GET_DATA if any of the others are set). However, kublk will only actually use one of the modes. For example, --get_data --zero_copy will use zero copy for the data transfer, not get data. And --zero_copy --auto_zc will only use auto buffer registration. So I think it's confusing to allow multiple of these parameters to be passed to kublk. Or do you think there is value in testing ublk device creation with multiple data copy mode flags set, but only one of the modes actually used?
> > > > > i = optind; > > while (i < argc && ctx.nr_files < MAX_BACK_FILES) { > > diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh > > index bb6f77ca5522..145e17b3d2b0 100755 > > --- a/tools/testing/selftests/ublk/test_generic_09.sh > > +++ b/tools/testing/selftests/ublk/test_generic_09.sh > > @@ -14,11 +14,11 @@ if ! _have_program fio; then > > exit "$UBLK_SKIP_CODE" > > fi > > > > _prep_test "null" "basic IO test" > > > > -dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) > > +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) > > _check_add_dev $TID $? > > > > # run fio over the two disks > > fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 > > ERR_CODE=$? > > diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh > > index 3ed4c9b2d8c0..8e9f2786ef9c 100755 > > --- a/tools/testing/selftests/ublk/test_stress_03.sh > > +++ b/tools/testing/selftests/ublk/test_stress_03.sh > > @@ -36,19 +36,19 @@ wait > > > > if _have_feature "AUTO_BUF_REG"; then > > ublk_io_and_remove 8G -t null -q 4 --auto_zc & > > ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & > > ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & > > - ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & > > + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & > > wait > > fi > > > > if _have_feature "PER_IO_DAEMON"; then > > ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & > > ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & > > ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & > > - ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & > > + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & > > wait > > fi > > > > _cleanup_test "stress" > > _show_result $TID $ERR_CODE > > diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh > > index c7220723b537..6e165a1f90b4 100755 > > --- a/tools/testing/selftests/ublk/test_stress_04.sh > > +++ b/tools/testing/selftests/ublk/test_stress_04.sh > > @@ -35,11 +35,11 @@ wait > > > > if _have_feature "AUTO_BUF_REG"; then > > ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & > > ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & > > ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & > > - ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & > > + ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & > > wait > > fi > > > > if _have_feature "PER_IO_DAEMON"; then > > ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & > > diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh > > index 274295061042..09b94c36f2ba 100755 > > --- a/tools/testing/selftests/ublk/test_stress_05.sh > > +++ b/tools/testing/selftests/ublk/test_stress_05.sh > > @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do > > wait > > done > > > > if _have_feature "ZERO_COPY"; then > > for reissue in $(seq 0 1); do > > - ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" & > > - ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & > > + ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" & > > + ublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & > > wait > > done > > fi > > > > if _have_feature "AUTO_BUF_REG"; then > > for reissue in $(seq 0 1); do > > - ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" & > > - ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & > > - ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" & > > + ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" & > > + ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & > > + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" & > > --auto_zc_fallback requires both -z and --auto_zc.
Ah, right, I forgot that the fallback path relies on normal zero copy buffer registration. I guess we are missing coverage of that, then, since the tests still passed with --zero_copy disabled.
Looks one regression from commit 0a9beafa7c63 ("ublk: refactor auto buffer register in ublk_dispatch_req()")
Is there a particular issue you see in that commit? I think the issue
Looks I overlooked.
is that if UBLK_IO_F_NEED_REG_BUF is set in the ublksrv_io_desc but zc isn't enabled, the null ublk server will just complete the I/O immediately. And --auto_zc_fallback isn't supported by any of the other ublk servers.
if (auto_zc && !ublk_io_auto_zc_fallback(iod)) queued = null_queue_auto_zc_io(t, q, tag); else if (zc) queued = null_queue_zc_io(t, q, tag); else { ublk_complete_io(t, q, tag, iod->nr_sectors << 9); return 0; }
So it looks to me to just be an issue with my kublk change.
But ublk_queue_auto_zc_fallback() is broken, so the auto_zc_fallback code path isn't examined actually.
How is it broken?
typeof(q->flags) is u64, but the return type is i32, so it is overflowed.
Ah, good catch. Yeah, these ublk_queue flag query functions should probably return bool. Are you going to send out a patch?
Thanks, Caleb
On Thu, Dec 11, 2025 at 3:05 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 10:45:36AM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:09 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:16:01PM -0700, Caleb Sander Mateos wrote:
The kublk mock ublk server allows multiple data copy mode arguments to be passed on the command line (--zero_copy, --get_data, and --auto_zc). The ublk device will be created with all the requested feature flags, however kublk will only use one of the modes to interact with request data (arbitrarily preferring auto_zc over zero_copy over get_data). To clarify the intent of the test, don't allow multiple data copy modes to be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an independent feature. Don't require zero_copy for auto_zc_fallback, as only auto_zc is needed. Fix the test cases passing multiple data copy mode arguments.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- .../testing/selftests/ublk/test_generic_09.sh | 2 +- .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- .../testing/selftests/ublk/test_stress_04.sh | 2 +- .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- 5 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index f8fa102a627f..1765c4806523 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) break; case 'd': ctx.queue_depth = strtol(optarg, NULL, 10); break; case 'z':
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY;
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; break; case 'r': value = strtol(optarg, NULL, 10); if (value) ctx.flags |= UBLK_F_USER_RECOVERY;@@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) optind += 1; break; } }
/* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */if (ctx.auto_zc_fallback &&!((ctx.flags & UBLK_F_AUTO_BUF_REG) &&(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) {ublk_err("%s: auto_zc_fallback is set but neither ""F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n",__func__);
/* auto_zc_fallback depends on F_AUTO_BUF_REG */if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) {ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n",__func__);return -EINVAL;}if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) +!!(ctx.flags & UBLK_F_NEED_GET_DATA) +!!(ctx.flags & UBLK_F_USER_COPY) +!!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) {fprintf(stderr, "too many data copy modes specified\n"); return -EINVAL; }Actually most of them are allowed to co-exist, such as -z/--auto_zc/-u.
Yes, I know the ublk driver allows multiple copy mode flags to be set (though it will clear UBLK_F_NEED_GET_DATA if any of the others are set). However, kublk will only actually use one of the modes. For example, --get_data --zero_copy will use zero copy for the data transfer, not get data. And --zero_copy --auto_zc will only use auto buffer registration. So I think it's confusing to allow multiple of these parameters to be passed to kublk. Or do you think there is value in testing ublk device creation with multiple data copy mode flags set, but only one of the modes actually used?
i = optind; while (i < argc && ctx.nr_files < MAX_BACK_FILES) {diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh index bb6f77ca5522..145e17b3d2b0 100755 --- a/tools/testing/selftests/ublk/test_generic_09.sh +++ b/tools/testing/selftests/ublk/test_generic_09.sh @@ -14,11 +14,11 @@ if ! _have_program fio; then exit "$UBLK_SKIP_CODE" fi
_prep_test "null" "basic IO test"
-dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) _check_add_dev $TID $?
# run fio over the two disks fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 ERR_CODE=$? diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh index 3ed4c9b2d8c0..8e9f2786ef9c 100755 --- a/tools/testing/selftests/ublk/test_stress_03.sh +++ b/tools/testing/selftests/ublk/test_stress_03.sh @@ -36,19 +36,19 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc & ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & waitfi
_cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index c7220723b537..6e165a1f90b4 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -35,11 +35,11 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 274295061042..09b94c36f2ba 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do wait done
if _have_feature "ZERO_COPY"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & wait donefi
if _have_feature "AUTO_BUF_REG"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &
ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &--auto_zc_fallback requires both -z and --auto_zc.
Ah, right, I forgot that the fallback path relies on normal zero copy buffer registration. I guess we are missing coverage of that, then, since the tests still passed with --zero_copy disabled.
Looks one regression from commit 0a9beafa7c63 ("ublk: refactor auto buffer register in ublk_dispatch_req()")
Is there a particular issue you see in that commit? I think the issue is that if UBLK_IO_F_NEED_REG_BUF is set in the ublksrv_io_desc but zc isn't enabled, the null ublk server will just complete the I/O immediately. And --auto_zc_fallback isn't supported by any of the other ublk servers.
if (auto_zc && !ublk_io_auto_zc_fallback(iod)) queued = null_queue_auto_zc_io(t, q, tag); else if (zc) queued = null_queue_zc_io(t, q, tag); else { ublk_complete_io(t, q, tag, iod->nr_sectors << 9); return 0; }
So it looks to me to just be an issue with my kublk change.
Thanks, Caleb
On Thu, Dec 11, 2025 at 06:06:51PM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 3:05 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 10:45:36AM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:09 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:16:01PM -0700, Caleb Sander Mateos wrote:
The kublk mock ublk server allows multiple data copy mode arguments to be passed on the command line (--zero_copy, --get_data, and --auto_zc). The ublk device will be created with all the requested feature flags, however kublk will only use one of the modes to interact with request data (arbitrarily preferring auto_zc over zero_copy over get_data). To clarify the intent of the test, don't allow multiple data copy modes to be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an independent feature. Don't require zero_copy for auto_zc_fallback, as only auto_zc is needed. Fix the test cases passing multiple data copy mode arguments.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- .../testing/selftests/ublk/test_generic_09.sh | 2 +- .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- .../testing/selftests/ublk/test_stress_04.sh | 2 +- .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- 5 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index f8fa102a627f..1765c4806523 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) break; case 'd': ctx.queue_depth = strtol(optarg, NULL, 10); break; case 'z':
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY;
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; break; case 'r': value = strtol(optarg, NULL, 10); if (value) ctx.flags |= UBLK_F_USER_RECOVERY;@@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) optind += 1; break; } }
/* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */if (ctx.auto_zc_fallback &&!((ctx.flags & UBLK_F_AUTO_BUF_REG) &&(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) {ublk_err("%s: auto_zc_fallback is set but neither ""F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n",__func__);
/* auto_zc_fallback depends on F_AUTO_BUF_REG */if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) {ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n",__func__);return -EINVAL;}if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) +!!(ctx.flags & UBLK_F_NEED_GET_DATA) +!!(ctx.flags & UBLK_F_USER_COPY) +!!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) {fprintf(stderr, "too many data copy modes specified\n"); return -EINVAL; }Actually most of them are allowed to co-exist, such as -z/--auto_zc/-u.
Yes, I know the ublk driver allows multiple copy mode flags to be set (though it will clear UBLK_F_NEED_GET_DATA if any of the others are set). However, kublk will only actually use one of the modes. For example, --get_data --zero_copy will use zero copy for the data transfer, not get data. And --zero_copy --auto_zc will only use auto buffer registration. So I think it's confusing to allow multiple of these parameters to be passed to kublk. Or do you think there is value in testing ublk device creation with multiple data copy mode flags set, but only one of the modes actually used?
i = optind; while (i < argc && ctx.nr_files < MAX_BACK_FILES) {diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh index bb6f77ca5522..145e17b3d2b0 100755 --- a/tools/testing/selftests/ublk/test_generic_09.sh +++ b/tools/testing/selftests/ublk/test_generic_09.sh @@ -14,11 +14,11 @@ if ! _have_program fio; then exit "$UBLK_SKIP_CODE" fi
_prep_test "null" "basic IO test"
-dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) _check_add_dev $TID $?
# run fio over the two disks fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 ERR_CODE=$? diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh index 3ed4c9b2d8c0..8e9f2786ef9c 100755 --- a/tools/testing/selftests/ublk/test_stress_03.sh +++ b/tools/testing/selftests/ublk/test_stress_03.sh @@ -36,19 +36,19 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc & ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & waitfi
_cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index c7220723b537..6e165a1f90b4 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -35,11 +35,11 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 274295061042..09b94c36f2ba 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do wait done
if _have_feature "ZERO_COPY"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & wait donefi
if _have_feature "AUTO_BUF_REG"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &
ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &--auto_zc_fallback requires both -z and --auto_zc.
Ah, right, I forgot that the fallback path relies on normal zero copy buffer registration. I guess we are missing coverage of that, then, since the tests still passed with --zero_copy disabled.
Looks one regression from commit 0a9beafa7c63 ("ublk: refactor auto buffer register in ublk_dispatch_req()")
Is there a particular issue you see in that commit? I think the issue
Looks I overlooked.
is that if UBLK_IO_F_NEED_REG_BUF is set in the ublksrv_io_desc but zc isn't enabled, the null ublk server will just complete the I/O immediately. And --auto_zc_fallback isn't supported by any of the other ublk servers.
if (auto_zc && !ublk_io_auto_zc_fallback(iod)) queued = null_queue_auto_zc_io(t, q, tag); else if (zc) queued = null_queue_zc_io(t, q, tag); else { ublk_complete_io(t, q, tag, iod->nr_sectors << 9); return 0; }
So it looks to me to just be an issue with my kublk change.
But ublk_queue_auto_zc_fallback() is broken, so the auto_zc_fallback code path isn't examined actually.
Thanks, Ming
On Thu, Dec 11, 2025 at 1:06 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:15:59PM -0700, Caleb Sander Mateos wrote:
stress_04 is described as "run IO and kill ublk server(zero copy)" but the --per_io_tasks tests cases don't use zero copy. Plus, one of the test cases is duplicated. Add --auto_zc to these test cases and --auto_zc_fallback to one of the duplicated ones. This matches the test cases in stress_03.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/test_stress_04.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 3f901db4d09d..965befcee830 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -38,14 +38,14 @@ if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & fi
if _have_feature "PER_IO_DAEMON"; then
ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &ublk_io_and_kill_daemon 256M -t loop -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &ublk_io_and_kill_daemon 256M -t stripe -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks &ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &I'd rather to fix the test description, the original motivation is to cover more data copy parameters(--z, --auto_zc, plain copy) in same stress test.
test_stress_02.sh ("run IO and kill ublk server") already covers plain copy. But sure, I can change the test_stress_04.sh description to "... (more features)" or something.
Thanks, Caleb
On Thu, Dec 11, 2025 at 06:57:51PM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:06 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:15:59PM -0700, Caleb Sander Mateos wrote:
stress_04 is described as "run IO and kill ublk server(zero copy)" but the --per_io_tasks tests cases don't use zero copy. Plus, one of the test cases is duplicated. Add --auto_zc to these test cases and --auto_zc_fallback to one of the duplicated ones. This matches the test cases in stress_03.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/test_stress_04.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index 3f901db4d09d..965befcee830 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -38,14 +38,14 @@ if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & fi
if _have_feature "PER_IO_DAEMON"; then
ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &ublk_io_and_kill_daemon 256M -t loop -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &ublk_io_and_kill_daemon 256M -t stripe -q 4 --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &ublk_io_and_kill_daemon 8G -t null -q 4 --nthreads 8 --per_io_tasks &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks &ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" &ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &I'd rather to fix the test description, the original motivation is to cover more data copy parameters(--z, --auto_zc, plain copy) in same stress test.
test_stress_02.sh ("run IO and kill ublk server") already covers plain copy. But sure, I can change the test_stress_04.sh description to "... (more features)" or something.
oops, stress_02 is same kind of test with stress_04.sh, I missed this point.
Your patch looks correct to make stress_04 for covering zero copy only.
Sorry for the noise.
Thanks, Ming
On Thu, Dec 11, 2025 at 6:38 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 06:06:51PM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 3:05 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 10:45:36AM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:09 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:16:01PM -0700, Caleb Sander Mateos wrote:
The kublk mock ublk server allows multiple data copy mode arguments to be passed on the command line (--zero_copy, --get_data, and --auto_zc). The ublk device will be created with all the requested feature flags, however kublk will only use one of the modes to interact with request data (arbitrarily preferring auto_zc over zero_copy over get_data). To clarify the intent of the test, don't allow multiple data copy modes to be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an independent feature. Don't require zero_copy for auto_zc_fallback, as only auto_zc is needed. Fix the test cases passing multiple data copy mode arguments.
Signed-off-by: Caleb Sander Mateos csander@purestorage.com
tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- .../testing/selftests/ublk/test_generic_09.sh | 2 +- .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- .../testing/selftests/ublk/test_stress_04.sh | 2 +- .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- 5 files changed, 22 insertions(+), 17 deletions(-)
diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c index f8fa102a627f..1765c4806523 100644 --- a/tools/testing/selftests/ublk/kublk.c +++ b/tools/testing/selftests/ublk/kublk.c @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) break; case 'd': ctx.queue_depth = strtol(optarg, NULL, 10); break; case 'z':
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY;
ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; break; case 'r': value = strtol(optarg, NULL, 10); if (value) ctx.flags |= UBLK_F_USER_RECOVERY;@@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) optind += 1; break; } }
/* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */if (ctx.auto_zc_fallback &&!((ctx.flags & UBLK_F_AUTO_BUF_REG) &&(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) {ublk_err("%s: auto_zc_fallback is set but neither ""F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n",__func__);
/* auto_zc_fallback depends on F_AUTO_BUF_REG */if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) {ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n",__func__);return -EINVAL;}if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) +!!(ctx.flags & UBLK_F_NEED_GET_DATA) +!!(ctx.flags & UBLK_F_USER_COPY) +!!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) {fprintf(stderr, "too many data copy modes specified\n"); return -EINVAL; }Actually most of them are allowed to co-exist, such as -z/--auto_zc/-u.
Yes, I know the ublk driver allows multiple copy mode flags to be set (though it will clear UBLK_F_NEED_GET_DATA if any of the others are set). However, kublk will only actually use one of the modes. For example, --get_data --zero_copy will use zero copy for the data transfer, not get data. And --zero_copy --auto_zc will only use auto buffer registration. So I think it's confusing to allow multiple of these parameters to be passed to kublk. Or do you think there is value in testing ublk device creation with multiple data copy mode flags set, but only one of the modes actually used?
i = optind; while (i < argc && ctx.nr_files < MAX_BACK_FILES) {diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh index bb6f77ca5522..145e17b3d2b0 100755 --- a/tools/testing/selftests/ublk/test_generic_09.sh +++ b/tools/testing/selftests/ublk/test_generic_09.sh @@ -14,11 +14,11 @@ if ! _have_program fio; then exit "$UBLK_SKIP_CODE" fi
_prep_test "null" "basic IO test"
-dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) _check_add_dev $TID $?
# run fio over the two disks fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 ERR_CODE=$? diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh index 3ed4c9b2d8c0..8e9f2786ef9c 100755 --- a/tools/testing/selftests/ublk/test_stress_03.sh +++ b/tools/testing/selftests/ublk/test_stress_03.sh @@ -36,19 +36,19 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc & ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks &
ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & waitfi
_cleanup_test "stress" _show_result $TID $ERR_CODE diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh index c7220723b537..6e165a1f90b4 100755 --- a/tools/testing/selftests/ublk/test_stress_04.sh +++ b/tools/testing/selftests/ublk/test_stress_04.sh @@ -35,11 +35,11 @@ wait
if _have_feature "AUTO_BUF_REG"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" &
ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback &
ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & waitfi
if _have_feature "PER_IO_DAEMON"; then ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh index 274295061042..09b94c36f2ba 100755 --- a/tools/testing/selftests/ublk/test_stress_05.sh +++ b/tools/testing/selftests/ublk/test_stress_05.sh @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do wait done
if _have_feature "ZERO_COPY"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &
ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & wait donefi
if _have_feature "AUTO_BUF_REG"; then for reissue in $(seq 0 1); do
ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &
ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" &ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" &ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &--auto_zc_fallback requires both -z and --auto_zc.
Ah, right, I forgot that the fallback path relies on normal zero copy buffer registration. I guess we are missing coverage of that, then, since the tests still passed with --zero_copy disabled.
Looks one regression from commit 0a9beafa7c63 ("ublk: refactor auto buffer register in ublk_dispatch_req()")
Is there a particular issue you see in that commit? I think the issue
Looks I overlooked.
is that if UBLK_IO_F_NEED_REG_BUF is set in the ublksrv_io_desc but zc isn't enabled, the null ublk server will just complete the I/O immediately. And --auto_zc_fallback isn't supported by any of the other ublk servers.
if (auto_zc && !ublk_io_auto_zc_fallback(iod)) queued = null_queue_auto_zc_io(t, q, tag); else if (zc) queued = null_queue_zc_io(t, q, tag); else { ublk_complete_io(t, q, tag, iod->nr_sectors << 9); return 0; }
So it looks to me to just be an issue with my kublk change.
But ublk_queue_auto_zc_fallback() is broken, so the auto_zc_fallback code path isn't examined actually.
How is it broken?
On Thu, Dec 11, 2025 at 08:59:00PM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 6:38 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 06:06:51PM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 3:05 PM Ming Lei ming.lei@redhat.com wrote:
On Thu, Dec 11, 2025 at 10:45:36AM -0800, Caleb Sander Mateos wrote:
On Thu, Dec 11, 2025 at 1:09 AM Ming Lei ming.lei@redhat.com wrote:
On Wed, Dec 10, 2025 at 10:16:01PM -0700, Caleb Sander Mateos wrote: > The kublk mock ublk server allows multiple data copy mode arguments to > be passed on the command line (--zero_copy, --get_data, and --auto_zc). > The ublk device will be created with all the requested feature flags, > however kublk will only use one of the modes to interact with request > data (arbitrarily preferring auto_zc over zero_copy over get_data). To > clarify the intent of the test, don't allow multiple data copy modes to > be specified. Don't set UBLK_F_USER_COPY for zero_copy, as it's an > independent feature. Don't require zero_copy for auto_zc_fallback, as > only auto_zc is needed. Fix the test cases passing multiple data copy > mode arguments. > > Signed-off-by: Caleb Sander Mateos csander@purestorage.com > --- > tools/testing/selftests/ublk/kublk.c | 21 ++++++++++++------- > .../testing/selftests/ublk/test_generic_09.sh | 2 +- > .../testing/selftests/ublk/test_stress_03.sh | 4 ++-- > .../testing/selftests/ublk/test_stress_04.sh | 2 +- > .../testing/selftests/ublk/test_stress_05.sh | 10 ++++----- > 5 files changed, 22 insertions(+), 17 deletions(-) > > diff --git a/tools/testing/selftests/ublk/kublk.c b/tools/testing/selftests/ublk/kublk.c > index f8fa102a627f..1765c4806523 100644 > --- a/tools/testing/selftests/ublk/kublk.c > +++ b/tools/testing/selftests/ublk/kublk.c > @@ -1611,11 +1611,11 @@ int main(int argc, char *argv[]) > break; > case 'd': > ctx.queue_depth = strtol(optarg, NULL, 10); > break; > case 'z': > - ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY | UBLK_F_USER_COPY; > + ctx.flags |= UBLK_F_SUPPORT_ZERO_COPY; > break; > case 'r': > value = strtol(optarg, NULL, 10); > if (value) > ctx.flags |= UBLK_F_USER_RECOVERY; > @@ -1674,17 +1674,22 @@ int main(int argc, char *argv[]) > optind += 1; > break; > } > } > > - /* auto_zc_fallback depends on F_AUTO_BUF_REG & F_SUPPORT_ZERO_COPY */ > - if (ctx.auto_zc_fallback && > - !((ctx.flags & UBLK_F_AUTO_BUF_REG) && > - (ctx.flags & UBLK_F_SUPPORT_ZERO_COPY))) { > - ublk_err("%s: auto_zc_fallback is set but neither " > - "F_AUTO_BUF_REG nor F_SUPPORT_ZERO_COPY is enabled\n", > - __func__); > + /* auto_zc_fallback depends on F_AUTO_BUF_REG */ > + if (ctx.auto_zc_fallback && !(ctx.flags & UBLK_F_AUTO_BUF_REG)) { > + ublk_err("%s: auto_zc_fallback is set but F_AUTO_BUF_REG is disabled\n", > + __func__); > + return -EINVAL; > + } > + > + if (!!(ctx.flags & UBLK_F_SUPPORT_ZERO_COPY) + > + !!(ctx.flags & UBLK_F_NEED_GET_DATA) + > + !!(ctx.flags & UBLK_F_USER_COPY) + > + !!(ctx.flags & UBLK_F_AUTO_BUF_REG) > 1) { > + fprintf(stderr, "too many data copy modes specified\n"); > return -EINVAL; > }
Actually most of them are allowed to co-exist, such as -z/--auto_zc/-u.
Yes, I know the ublk driver allows multiple copy mode flags to be set (though it will clear UBLK_F_NEED_GET_DATA if any of the others are set). However, kublk will only actually use one of the modes. For example, --get_data --zero_copy will use zero copy for the data transfer, not get data. And --zero_copy --auto_zc will only use auto buffer registration. So I think it's confusing to allow multiple of these parameters to be passed to kublk. Or do you think there is value in testing ublk device creation with multiple data copy mode flags set, but only one of the modes actually used?
> > i = optind; > while (i < argc && ctx.nr_files < MAX_BACK_FILES) { > diff --git a/tools/testing/selftests/ublk/test_generic_09.sh b/tools/testing/selftests/ublk/test_generic_09.sh > index bb6f77ca5522..145e17b3d2b0 100755 > --- a/tools/testing/selftests/ublk/test_generic_09.sh > +++ b/tools/testing/selftests/ublk/test_generic_09.sh > @@ -14,11 +14,11 @@ if ! _have_program fio; then > exit "$UBLK_SKIP_CODE" > fi > > _prep_test "null" "basic IO test" > > -dev_id=$(_add_ublk_dev -t null -z --auto_zc --auto_zc_fallback) > +dev_id=$(_add_ublk_dev -t null --auto_zc --auto_zc_fallback) > _check_add_dev $TID $? > > # run fio over the two disks > fio --name=job1 --filename=/dev/ublkb"${dev_id}" --ioengine=libaio --rw=readwrite --iodepth=32 --size=256M > /dev/null 2>&1 > ERR_CODE=$? > diff --git a/tools/testing/selftests/ublk/test_stress_03.sh b/tools/testing/selftests/ublk/test_stress_03.sh > index 3ed4c9b2d8c0..8e9f2786ef9c 100755 > --- a/tools/testing/selftests/ublk/test_stress_03.sh > +++ b/tools/testing/selftests/ublk/test_stress_03.sh > @@ -36,19 +36,19 @@ wait > > if _have_feature "AUTO_BUF_REG"; then > ublk_io_and_remove 8G -t null -q 4 --auto_zc & > ublk_io_and_remove 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & > ublk_io_and_remove 256M -t stripe -q 4 --auto_zc "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & > - ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & > + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback & > wait > fi > > if _have_feature "PER_IO_DAEMON"; then > ublk_io_and_remove 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & > ublk_io_and_remove 256M -t loop -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[0]}" & > ublk_io_and_remove 256M -t stripe -q 4 --auto_zc --nthreads 8 --per_io_tasks "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & > - ublk_io_and_remove 8G -t null -q 4 -z --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & > + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback --nthreads 8 --per_io_tasks & > wait > fi > > _cleanup_test "stress" > _show_result $TID $ERR_CODE > diff --git a/tools/testing/selftests/ublk/test_stress_04.sh b/tools/testing/selftests/ublk/test_stress_04.sh > index c7220723b537..6e165a1f90b4 100755 > --- a/tools/testing/selftests/ublk/test_stress_04.sh > +++ b/tools/testing/selftests/ublk/test_stress_04.sh > @@ -35,11 +35,11 @@ wait > > if _have_feature "AUTO_BUF_REG"; then > ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc & > ublk_io_and_kill_daemon 256M -t loop -q 4 --auto_zc "${UBLK_BACKFILES[0]}" & > ublk_io_and_kill_daemon 256M -t stripe -q 4 --auto_zc --no_ublk_fixed_fd "${UBLK_BACKFILES[1]}" "${UBLK_BACKFILES[2]}" & > - ublk_io_and_kill_daemon 8G -t null -q 4 -z --auto_zc --auto_zc_fallback & > + ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --auto_zc_fallback & > wait > fi > > if _have_feature "PER_IO_DAEMON"; then > ublk_io_and_kill_daemon 8G -t null -q 4 --auto_zc --nthreads 8 --per_io_tasks & > diff --git a/tools/testing/selftests/ublk/test_stress_05.sh b/tools/testing/selftests/ublk/test_stress_05.sh > index 274295061042..09b94c36f2ba 100755 > --- a/tools/testing/selftests/ublk/test_stress_05.sh > +++ b/tools/testing/selftests/ublk/test_stress_05.sh > @@ -56,21 +56,21 @@ for reissue in $(seq 0 1); do > wait > done > > if _have_feature "ZERO_COPY"; then > for reissue in $(seq 0 1); do > - ublk_io_and_remove 8G -t null -q 4 -g -z -r 1 -i "$reissue" & > - ublk_io_and_remove 256M -t loop -q 4 -g -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & > + ublk_io_and_remove 8G -t null -q 4 -z -r 1 -i "$reissue" & > + ublk_io_and_remove 256M -t loop -q 4 -z -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & > wait > done > fi > > if _have_feature "AUTO_BUF_REG"; then > for reissue in $(seq 0 1); do > - ublk_io_and_remove 8G -t null -q 4 -g --auto_zc -r 1 -i "$reissue" & > - ublk_io_and_remove 256M -t loop -q 4 -g --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & > - ublk_io_and_remove 8G -t null -q 4 -g -z --auto_zc --auto_zc_fallback -r 1 -i "$reissue" & > + ublk_io_and_remove 8G -t null -q 4 --auto_zc -r 1 -i "$reissue" & > + ublk_io_and_remove 256M -t loop -q 4 --auto_zc -r 1 -i "$reissue" "${UBLK_BACKFILES[1]}" & > + ublk_io_and_remove 8G -t null -q 4 --auto_zc --auto_zc_fallback -r 1 -i "$reissue" &
--auto_zc_fallback requires both -z and --auto_zc.
Ah, right, I forgot that the fallback path relies on normal zero copy buffer registration. I guess we are missing coverage of that, then, since the tests still passed with --zero_copy disabled.
Looks one regression from commit 0a9beafa7c63 ("ublk: refactor auto buffer register in ublk_dispatch_req()")
Is there a particular issue you see in that commit? I think the issue
Looks I overlooked.
is that if UBLK_IO_F_NEED_REG_BUF is set in the ublksrv_io_desc but zc isn't enabled, the null ublk server will just complete the I/O immediately. And --auto_zc_fallback isn't supported by any of the other ublk servers.
if (auto_zc && !ublk_io_auto_zc_fallback(iod)) queued = null_queue_auto_zc_io(t, q, tag); else if (zc) queued = null_queue_zc_io(t, q, tag); else { ublk_complete_io(t, q, tag, iod->nr_sectors << 9); return 0; }
So it looks to me to just be an issue with my kublk change.
But ublk_queue_auto_zc_fallback() is broken, so the auto_zc_fallback code path isn't examined actually.
How is it broken?
typeof(q->flags) is u64, but the return type is i32, so it is overflowed.
Thanks, Ming
linux-kselftest-mirror@lists.linaro.org