Skip to content

Commit 5314d25

Browse files
Ming Leiaxboe
authored andcommitted
selftests: ublk: improve I/O ordering test with bpftrace
Remove test_generic_01.sh since block layer may reorder I/O, making the test prone to false positives. Apply the improvements to test_generic_02.sh instead, which supposes for covering ublk dispatch io order. Rework test_generic_02 to verify that ublk dispatch doesn't reorder I/O by comparing request start order with completion order using bpftrace. The bpftrace script now: - Tracks each request's start sequence number in a map keyed by sector - On completion, verifies the request's start order matches expected completion order - Reports any out-of-order completions detected The test script: - Wait bpftrace BEGIN code block is run - Pins fio to CPU 0 for deterministic behavior - Uses block_io_start and block_rq_complete tracepoints - Checks bpftrace output for reordering errors Reported-and-tested-by: Alexander Atanasov <alex@zazolabs.com> Signed-off-by: Ming Lei <ming.lei@redhat.com> Signed-off-by: Jens Axboe <axboe@kernel.dk>
1 parent d9a36ab commit 5314d25

4 files changed

Lines changed: 54 additions & 65 deletions

File tree

tools/testing/selftests/ublk/Makefile

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,7 @@ endif
77

88
LDLIBS += -lpthread -lm -luring
99

10-
TEST_PROGS := test_generic_01.sh
11-
TEST_PROGS += test_generic_02.sh
10+
TEST_PROGS := test_generic_02.sh
1211
TEST_PROGS += test_generic_03.sh
1312
TEST_PROGS += test_generic_06.sh
1413
TEST_PROGS += test_generic_07.sh

tools/testing/selftests/ublk/test_generic_01.sh

Lines changed: 0 additions & 47 deletions
This file was deleted.

tools/testing/selftests/ublk/test_generic_02.sh

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,23 +13,28 @@ if ! _have_program fio; then
1313
exit "$UBLK_SKIP_CODE"
1414
fi
1515

16-
_prep_test "null" "sequential io order for MQ"
16+
_prep_test "null" "ublk dispatch won't reorder IO for MQ"
1717

1818
dev_id=$(_add_ublk_dev -t null -q 2)
1919
_check_add_dev $TID $?
2020

2121
dev_t=$(_get_disk_dev_t "$dev_id")
2222
bpftrace trace/seq_io.bt "$dev_t" "W" 1 > "$UBLK_TMP" 2>&1 &
2323
btrace_pid=$!
24-
sleep 2
2524

26-
if ! kill -0 "$btrace_pid" > /dev/null 2>&1; then
25+
# Wait for bpftrace probes to be attached (BEGIN block prints BPFTRACE_READY)
26+
for _ in $(seq 100); do
27+
grep -q "BPFTRACE_READY" "$UBLK_TMP" 2>/dev/null && break
28+
sleep 0.1
29+
done
30+
31+
if ! kill -0 "$btrace_pid" 2>/dev/null; then
2732
_cleanup_test "null"
2833
exit "$UBLK_SKIP_CODE"
2934
fi
3035

31-
# run fio over this ublk disk
32-
fio --name=write_seq \
36+
# run fio over this ublk disk (pinned to CPU 0)
37+
taskset -c 0 fio --name=write_seq \
3338
--filename=/dev/ublkb"${dev_id}" \
3439
--ioengine=libaio --iodepth=16 \
3540
--rw=write \
@@ -39,8 +44,11 @@ fio --name=write_seq \
3944
ERR_CODE=$?
4045
kill "$btrace_pid"
4146
wait
42-
if grep -q "io_out_of_order" "$UBLK_TMP"; then
43-
cat "$UBLK_TMP"
47+
48+
# Check for out-of-order completions detected by bpftrace
49+
if grep -q "^out_of_order:" "$UBLK_TMP"; then
50+
echo "I/O reordering detected:"
51+
grep "^out_of_order:" "$UBLK_TMP"
4452
ERR_CODE=255
4553
fi
4654
_cleanup_test "null"

tools/testing/selftests/ublk/trace/seq_io.bt

Lines changed: 38 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,52 @@
22
$1: dev_t
33
$2: RWBS
44
$3: strlen($2)
5+
6+
Track request order between block_io_start and block_rq_complete.
7+
Sequence starts at 1 so 0 means "never seen". On first valid
8+
completion, sync complete_seq to handle probe attachment races.
9+
block_rq_complete listed first to reduce missed completion window.
510
*/
11+
612
BEGIN {
7-
@last_rw[$1, str($2)] = (uint64)0;
13+
@start_seq = (uint64)1;
14+
@complete_seq = (uint64)0;
15+
@out_of_order = (uint64)0;
16+
@start_order[0] = (uint64)0;
17+
delete(@start_order[0]);
18+
printf("BPFTRACE_READY\n");
819
}
20+
921
tracepoint:block:block_rq_complete
22+
/(int64)args.dev == $1 && !strncmp(args.rwbs, str($2), $3)/
1023
{
11-
$dev = $1;
12-
if ((int64)args.dev == $1 && !strncmp(args.rwbs, str($2), $3)) {
13-
$last = @last_rw[$dev, str($2)];
14-
if ((uint64)args.sector != $last) {
15-
printf("io_out_of_order: exp %llu actual %llu\n",
16-
args.sector, $last);
24+
$expected = @start_order[args.sector];
25+
if ($expected > 0) {
26+
if (@complete_seq == 0) {
27+
@complete_seq = $expected;
28+
}
29+
if ($expected != @complete_seq) {
30+
printf("out_of_order: sector %llu started at seq %llu but completed at seq %llu\n",
31+
args.sector, $expected, @complete_seq);
32+
@out_of_order = @out_of_order + 1;
1733
}
18-
@last_rw[$dev, str($2)] = (args.sector + args.nr_sector);
34+
delete(@start_order[args.sector]);
35+
@complete_seq = @complete_seq + 1;
1936
}
2037
}
2138

39+
tracepoint:block:block_io_start
40+
/(int64)args.dev == $1 && !strncmp(args.rwbs, str($2), $3)/
41+
{
42+
@start_order[args.sector] = @start_seq;
43+
@start_seq = @start_seq + 1;
44+
}
45+
2246
END {
23-
clear(@last_rw);
47+
printf("total_start: %llu total_complete: %llu out_of_order: %llu\n",
48+
@start_seq - 1, @complete_seq, @out_of_order);
49+
clear(@start_order);
50+
clear(@start_seq);
51+
clear(@complete_seq);
52+
clear(@out_of_order);
2453
}

0 commit comments

Comments
 (0)