The btt-check unit test exposed data mismatches during BTT I/O in a CI environment, indicating a race in lane acquisition that can lead to silent data corruption. The failure was not reliably reproduced under typical test conditions.
Add a targeted stress test that repeatedly writes, reads, and verifies data on a BTT namespace while background readers contend for BTT lanes and CPU loops increase preemption pressure. The test reproduces the race on an unfixed kernel and passes with the lane ownership fix applied. Assisted-By: Claude Sonnet 4.5 Signed-off-by: Alison Schofield <[email protected]> --- test/btt-stress.sh | 111 +++++++++++++++++++++++++++++++++++++++++++++ test/meson.build | 2 + 2 files changed, 113 insertions(+) create mode 100755 test/btt-stress.sh diff --git a/test/btt-stress.sh b/test/btt-stress.sh new file mode 100755 index 000000000000..c1892f536d75 --- /dev/null +++ b/test/btt-stress.sh @@ -0,0 +1,111 @@ +#!/bin/bash -E +# SPDX-License-Identifier: GPL-2.0 + +dev="" +mode="" +size="" +sector_size="" +blockdev="" +rc=77 + +. $(dirname $0)/common + +trap 'err $LINENO' ERR + +check_min_kver "7.1" || do_skip "known BTT lane race before fix" + +# Stress BTT I/O under contention to exercise lane acquisition races. +# Background readers contend for lanes while CPU loops increase +# preemption pressure. + +create() { + json=$($NDCTL create-namespace -b "$NFIT_TEST_BUS0" -t pmem -m sector) + rc=2 + eval "$(echo "$json" | json2var)" + [ -n "$dev" ] || err "$LINENO" + [ "$mode" = "sector" ] || err "$LINENO" + [ -n "$size" ] || err "$LINENO" + [ -n "$sector_size" ] || err "$LINENO" + [ -n "$blockdev" ] || err "$LINENO" + [ "$size" -gt 0 ] || err "$LINENO" +} + +# Start background workers: +# - readers contend for lanes +# - CPU loops increase preemption +start_bg_workers() { + local ncpus + ncpus=$(nproc) + local nworkers=$((ncpus / 2)) + + # Ensure at least one worker, cap to limit runtime noise + [ $nworkers -lt 1 ] && nworkers=1 + [ $nworkers -gt 8 ] && nworkers=8 + + BG_PIDS=() + local i + for i in $(seq 1 $nworkers); do + # Reader: contends for lanes (use O_DIRECT to avoid page cache) + (while :; do + dd if=/dev/"$blockdev" of=/dev/null \ + bs="$sector_size" count=256 \ + iflag=direct >/dev/null 2>&1 || true + done) & + BG_PIDS+=($!) + + # CPU hog: increase preemption + (while :; do :; done) & + BG_PIDS+=($!) + done + echo "started $nworkers readers + $nworkers CPU hogs" +} + +stop_bg_workers() { + local pid + for pid in "${BG_PIDS[@]}"; do + kill "$pid" 2>/dev/null || true + done + wait "${BG_PIDS[@]}" 2>/dev/null || true + BG_PIDS=() +} + +# Write, read, and verify data +do_io_verify() { + dd if=/dev/urandom of=test-bin \ + bs="$sector_size" count=$((size / sector_size)) >/dev/null 2>&1 + dd if=test-bin of=/dev/"$blockdev" \ + bs="$sector_size" count=$((size / sector_size)) >/dev/null 2>&1 + dd if=/dev/"$blockdev" of=test-bin-read \ + bs="$sector_size" count=$((size / sector_size)) >/dev/null 2>&1 + diff test-bin test-bin-read + rm -f test-bin* +} + +# Run verification under contention +test_io_stress() { + local iterations=${1:-20} + echo "=== ${FUNCNAME[0]} ($iterations iterations) ===" + + start_bg_workers + trap 'stop_bg_workers; err $LINENO' ERR + + local i + for i in $(seq 1 "$iterations"); do + echo "--- iteration $i/$iterations ---" + do_io_verify + done + + stop_bg_workers + trap 'err $LINENO' ERR +} + +modprobe nfit_test +rc=1 +reset && create + +# 30 iterations balances runtime and reproduction probability +test_io_stress 30 + +reset +_cleanup +exit 0 diff --git a/test/meson.build b/test/meson.build index e0e2193bfd51..ee6a18762a17 100644 --- a/test/meson.build +++ b/test/meson.build @@ -150,6 +150,7 @@ sector_mode = find_program('sector-mode.sh') inject_error = find_program('inject-error.sh') btt_errors = find_program('btt-errors.sh') btt_pad_compat = find_program('btt-pad-compat.sh') +btt_stress = find_program('btt-stress.sh') firmware_update = find_program('firmware-update.sh') rescan_partitions = find_program('rescan-partitions.sh') inject_smart = find_program('inject-smart.sh') @@ -185,6 +186,7 @@ tests = [ [ 'sector-mode.sh', sector_mode, 'ndctl' ], [ 'inject-error.sh', inject_error, 'ndctl' ], [ 'btt-errors.sh', btt_errors, 'ndctl' ], + [ 'btt-stress.sh', btt_stress, 'ndctl' ], [ 'hugetlb', hugetlb, 'ndctl' ], [ 'btt-pad-compat.sh', btt_pad_compat, 'ndctl' ], [ 'ack-shutdown-count-set', ack_shutdown_count, 'ndctl' ], -- 2.37.3
