Linux Trace Kernel
 help / color / mirror / Atom feed
* [PATCH] rtla/tests: cover a CPU hotplug cycle in user-space timerlat mode
@ 2026-11-12 10:20 Chaosheng Qu
  2026-11-12 10:39 ` sashiko-bot
  0 siblings, 1 reply; 2+ messages in thread
From: Chaosheng Qu @ 2026-11-12 10:20 UTC (permalink / raw)
  To: Steven Rostedt, Tomas Glozar; +Cc: linux-trace-kernel, linux-kernel

From 1cd99268c2352aff3196d01773c0c2f93c521e33 Mon Sep 17 00:00:00 2001
From: Chaosheng Qu <chaosheng.qu.linux@gmail.com>
Date: Thu, 12 Nov 2026 18:12:35 +0800
Subject: [PATCH] rtla/tests: cover a CPU hotplug cycle in user-space timerlat
 mode

timerlat samples either from a "timerlat/<cpu>" kernel thread, when
OSN_WORKLOAD is set, or from the user thread reading timerlat_fd.  Only
one may exist for a CPU.

Onlining a CPU during a user-space run installs the kernel thread anyway,
because osnoise_hotplug_workfn() calls start_kthread() without the check
that start_per_cpu_kthreads() makes.  When the trace stops, stop_kthread()
picks the teardown path from the current OSN_WORKLOAD, takes the
user-thread branch for that kthread and releases it with put_task_struct()
although kthread_stop() owns it.

Add a test that offlines and onlines a CPU while timerlat runs, and checks
that no timerlat workload kthread appeared.  The helper drives rtla
itself: the kthread is only torn down after rtla exits, so there is no
"rtla arguments" string to hand to check().

Signed-off-by: Chaosheng Qu <chaosheng.qu.linux@gmail.com>
Assisted-by: LLM
---
 .../rtla/tests/scripts/check-hotplug.sh       | 97 +++++++++++++++++++
 tools/tracing/rtla/tests/timerlat.t           | 42 ++++++++
 2 files changed, 139 insertions(+)
 create mode 100755 tools/tracing/rtla/tests/scripts/check-hotplug.sh

diff --git a/tools/tracing/rtla/tests/scripts/check-hotplug.sh b/tools/tracing/rtla/tests/scripts/check-hotplug.sh
new file mode 100755
index 000000000..5287034cd
--- /dev/null
+++ b/tools/tracing/rtla/tests/scripts/check-hotplug.sh
@@ -0,0 +1,97 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+#
+# Offline and online a CPU while rtla timerlat runs, and check that the
+# CPU coming back did not install a workload kthread.
+#
+# timerlat can sample in two ways.  With OSN_WORKLOAD set the sampling is
+# done by a "timerlat/<cpu>" kernel thread; with it clear (what rtla's
+# user-space mode uses) the sampling is done by the user thread itself,
+# named "timerlatu/<cpu>".  Only one of the two may exist for a CPU.
+#
+# Onlining a CPU used to install the kernel thread even in user-space mode,
+# because the hotplug worker called start_kthread() without the check that
+# start_per_cpu_kthreads() does.  stop_kthread() then picked the teardown
+# path from the current OSN_WORKLOAD, treated that kthread as a user thread
+# and freed it with put_task_struct() although kthread_stop() owns it, which
+# ends in warnings from stop_kthread, __put_task_struct and free_task, and
+# then in NULL pointer faults.
+#
+# The stray kthread shows up within a fraction of a second of the CPU coming
+# back, well before the teardown that crashes, so asserting on it gives a
+# clean failure instead of taking the kernel down.
+#
+# Usage: check-hotplug.sh <rtla> <cpu>
+#
+# Prints "HOTPLUG_FAIL: ..." on failure, "HOTPLUG_SKIP: ..." when the system
+# cannot run the test, and "HOTPLUG_OK" otherwise.
+
+RTLA=${1:?usage: check-hotplug.sh <rtla> <cpu>}
+CPU=${2:?usage: check-hotplug.sh <rtla> <cpu>}
+ONLINE=/sys/devices/system/cpu/cpu$CPU/online
+
+[ -x "$RTLA" ] || { echo "HOTPLUG_SKIP: $RTLA is not executable"; exit 0; }
+[ -w "$ONLINE" ] || { echo "HOTPLUG_SKIP: $ONLINE is not writable"; exit 0; }
+
+# Names of the timerlat workload threads that currently exist, one per line.
+timerlat_threads() {
+	for c in /proc/[0-9]*/comm; do
+		read -r name <"$c" 2>/dev/null || continue
+		case "$name" in
+		timerlat/*) echo "$name" ;;
+		esac
+	done
+}
+
+"$RTLA" timerlat top -q -d 20s -c 0,"$CPU" -P F:1 >/dev/null 2>&1 &
+pid=$!
+
+# Let rtla create its instance and settle into user-space sampling.
+sleep 3
+
+if ! echo 0 >"$ONLINE"; then
+	echo "HOTPLUG_SKIP: could not offline cpu$CPU"
+	kill -INT $pid 2>/dev/null; wait $pid 2>/dev/null; exit 0
+fi
+if ! echo 1 >"$ONLINE"; then
+	echo "HOTPLUG_SKIP: could not online cpu$CPU"
+	kill -INT $pid 2>/dev/null; wait $pid 2>/dev/null; exit 0
+fi
+
+# The hotplug work is queued on the CPU that just came up, and the damage is
+# done as part of bringing it up: stop_kthread() runs before this point and
+# the log is already tainted.  Check both, so that a build where the stray
+# kthread is gone but the teardown still misbehaves does not slip through.
+stray=''
+i=0
+while [ $i -lt 20 ]; do
+	stray=$(timerlat_threads)
+	[ -n "$stray" ] && break
+	sleep 0.2
+	i=$((i + 1))
+done
+
+# Give the run time to reach its own stop path, which is where the kthread
+# gets torn down, and then let it finish.
+sleep 2
+kill -INT $pid 2>/dev/null
+wait $pid 2>/dev/null
+sleep 1
+
+warn=$(dmesg 2>/dev/null | grep -c 'WARNING: at')
+fault=$(dmesg 2>/dev/null | grep -c 'BUG: kernel NULL pointer')
+
+if [ -n "$stray" ]; then
+	echo "stray workload kthread(s): $(echo $stray)"
+	echo "HOTPLUG_FAIL: cpu$CPU came back online and a timerlat" \
+		"workload kthread was started in user-space mode"
+	exit 1
+fi
+
+if [ "$fault" -gt 0 ] || [ "$warn" -gt 0 ]; then
+	dmesg | grep -A12 'WARNING: at' | tail -30
+	echo "HOTPLUG_FAIL: the kernel warned ($warn) or faulted ($fault) during the hotplug run"
+	exit 1
+fi
+
+echo "HOTPLUG_OK"
diff --git a/tools/tracing/rtla/tests/timerlat.t b/tools/tracing/rtla/tests/timerlat.t
index 5116857d7..a1af962ad 100644
--- a/tools/tracing/rtla/tests/timerlat.t
+++ b/tools/tracing/rtla/tests/timerlat.t
@@ -6,6 +6,18 @@ test_begin
 set_timeout 2m
 timerlat_sample_event='/sys/kernel/tracing/events/osnoise/timerlat_sample'
 
+# Pick a CPU that can be offlined without taking cpu0 down.  A hotplug test
+# needs one whose "online" file is writable, plus at least one other CPU so
+# the tool can still run; otherwise skip the case.
+hotplug_cpu=''
+for c in /sys/devices/system/cpu/cpu[1-9]*/online; do
+	[ -w "$c" ] || continue
+	hotplug_cpu=${c#/sys/devices/system/cpu/cpu}
+	hotplug_cpu=${hotplug_cpu%/online}
+	[ "$(cat /sys/devices/system/cpu/online)" != "$hotplug_cpu" ] || continue
+	break
+done
+
 if ldd $RTLA | grep libbpf >/dev/null && [ -d "$timerlat_sample_event" ]
 then
 	# rtla build with BPF and system supports BPF mode
@@ -153,4 +165,34 @@ else
 fi
 done
 
+# Hotplug test: timerlat in user-space mode samples from the user thread and
+# has no workload kthread.  Onlining a CPU mid-run must not install one; if
+# it does, stopping the trace tears that kthread down through the
+# user-thread path, which warns and then faults.
+#
+# The helper drives rtla itself, because the kthread is only torn down after
+# rtla exits, so there is no "rtla arguments" string to hand to check().
+if [ -n "$hotplug_cpu" ]; then
+	ctr=$((ctr + 1))
+	if [ -n "$TEST_COUNT" ]; then
+		[ "$NO_RESET_OSNOISE" == 1 ] || reset_osnoise
+		tmpdir=$(mktemp -d)
+		pushd "$tmpdir" >/dev/null
+
+		result=$("$testdir"/scripts/check-hotplug.sh "$RTLA" "$hotplug_cpu" 2>&1)
+		exitcode=$?
+
+		if [ "$exitcode" -eq 0 ] && grep -q '^HOTPLUG_OK' <<< "$result"; then
+			echo "ok $ctr - top survives a CPU hotplug cycle"
+		else
+			echo "not ok $ctr - top survives a CPU hotplug cycle"
+			echo "$result" | while read -r line; do echo "# $line"; done
+			printf "#\n# exit code %s\n" "$exitcode"
+		fi
+
+		popd >/dev/null
+		rm -r "$tmpdir"
+	fi
+fi
+
 test_end
-- 
2.43.0



^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-11-12 10:39 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-11-12 10:20 [PATCH] rtla/tests: cover a CPU hotplug cycle in user-space timerlat mode Chaosheng Qu
2026-11-12 10:39 ` sashiko-bot

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox