]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests: ublk: add generic_01 for verifying sequential IO order
authorMing Lei <ming.lei@redhat.com>
Sat, 22 Mar 2025 09:32:09 +0000 (17:32 +0800)
committerJens Axboe <axboe@kernel.dk>
Sat, 22 Mar 2025 14:35:08 +0000 (08:35 -0600)
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>
tools/testing/selftests/ublk/Makefile
tools/testing/selftests/ublk/test_common.sh
tools/testing/selftests/ublk/test_generic_01.sh [new file with mode: 0755]
tools/testing/selftests/ublk/trace/seq_io.bt [new file with mode: 0644]

index 5d8d5939f051e472657ce01067f00db595d56992..652ab40adb7336316dcfa6d082d95f9b621eab96 100644 (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
index 48fca609e741a6b8ca1ba0a9d6286633ffa22d90..75f54ac6b1c4d57879d6ba07d76ab91ff1be9645 100755 (executable)
@@ -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
diff --git a/tools/testing/selftests/ublk/test_generic_01.sh b/tools/testing/selftests/ublk/test_generic_01.sh
new file mode 100755 (executable)
index 0000000..9227a20
--- /dev/null
@@ -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
diff --git a/tools/testing/selftests/ublk/trace/seq_io.bt b/tools/testing/selftests/ublk/trace/seq_io.bt
new file mode 100644 (file)
index 0000000..272ac54
--- /dev/null
@@ -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);
+}