selftests: ublk: add generic_01 for verifying sequential IO order

block layer, ublk and io_uring might re-order IO in the past

- plug

- queue ublk io command via task work

Add one test for verifying if sequential WRITE IO is dispatched in order.

- null target is taken, so we can just observe io order from
`tracepoint:block:block_rq_complete` which represents the dispatch order

- WRITE IO is taken because READ may come from system-wide utility

Cc: Uday Shankar <ushankar@purestorage.com>
Signed-off-by: Ming Lei <ming.lei@redhat.com>
Link: https://lore.kernel.org/r/20250322093218.431419-2-ming.lei@redhat.com
Signed-off-by: Jens Axboe <axboe@kernel.dk>
This commit is contained in:
Ming Lei 2025-03-22 17:32:09 +08:00 committed by Jens Axboe
parent ffde32a49a
commit 723977cab4
4 changed files with 94 additions and 1 deletions

View file

@ -3,7 +3,9 @@
CFLAGS += -O3 -Wl,-no-as-needed -Wall -I $(top_srcdir)
LDLIBS += -lpthread -lm -luring
TEST_PROGS := test_null_01.sh
TEST_PROGS := test_generic_01.sh
TEST_PROGS += test_null_01.sh
TEST_PROGS += test_loop_01.sh
TEST_PROGS += test_loop_02.sh
TEST_PROGS += test_loop_03.sh

View file

@ -3,6 +3,26 @@
UBLK_SKIP_CODE=4
_have_program() {
if command -v "$1" >/dev/null 2>&1; then
return 0
fi
return 1
}
_get_disk_dev_t() {
local dev_id=$1
local dev
local major
local minor
dev=/dev/ublkb"${dev_id}"
major=$(stat -c '%Hr' "$dev")
minor=$(stat -c '%Lr' "$dev")
echo $(( (major & 0xfff) << 20 | (minor & 0xfffff) ))
}
_create_backfile() {
local my_size=$1
local my_file
@ -121,6 +141,7 @@ _check_add_dev()
_cleanup_test() {
"${UBLK_PROG}" del -a
rm -f "$UBLK_TMP"
}
_have_feature()
@ -216,6 +237,7 @@ _ublk_test_top_dir()
cd "$(dirname "$0")" && pwd
}
UBLK_TMP=$(mktemp ublk_test_XXXXX)
UBLK_PROG=$(_ublk_test_top_dir)/kublk
UBLK_TEST_QUIET=1
UBLK_TEST_SHOW_RESULT=1

View file

@ -0,0 +1,44 @@
#!/bin/bash
# SPDX-License-Identifier: GPL-2.0
. "$(cd "$(dirname "$0")" && pwd)"/test_common.sh
TID="generic_01"
ERR_CODE=0
if ! _have_program bpftrace; then
exit "$UBLK_SKIP_CODE"
fi
_prep_test "null" "sequential io order"
dev_id=$(_add_ublk_dev -t null)
_check_add_dev $TID $?
dev_t=$(_get_disk_dev_t "$dev_id")
bpftrace trace/seq_io.bt "$dev_t" "W" 1 > "$UBLK_TMP" 2>&1 &
btrace_pid=$!
sleep 2
if ! kill -0 "$btrace_pid" > /dev/null 2>&1; then
_cleanup_test "null"
exit "$UBLK_SKIP_CODE"
fi
# run fio over this ublk disk
fio --name=write_seq \
--filename=/dev/ublkb"${dev_id}" \
--ioengine=libaio --iodepth=16 \
--rw=write \
--size=512M \
--direct=1 \
--bs=4k > /dev/null 2>&1
ERR_CODE=$?
kill "$btrace_pid"
wait
if grep -q "io_out_of_order" "$UBLK_TMP"; then
cat "$UBLK_TMP"
ERR_CODE=255
fi
_cleanup_test "null"
_show_result $TID $ERR_CODE

View file

@ -0,0 +1,25 @@
/*
$1: dev_t
$2: RWBS
$3: strlen($2)
*/
BEGIN {
@last_rw[$1, str($2)] = 0;
}
tracepoint:block:block_rq_complete
{
$dev = $1;
if ((int64)args.dev == $1 && !strncmp(args.rwbs, str($2), $3)) {
$last = @last_rw[$dev, str($2)];
if ((uint64)args.sector != $last) {
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);
}