From: Chaosheng Qu <chaosheng.qu.linux@gmail.com>
To: Steven Rostedt <rostedt@goodmis.org>, Tomas Glozar <tglozar@redhat.com>
Cc: linux-trace-kernel@vger.kernel.org, linux-kernel@vger.kernel.org
Subject: [PATCH] rtla/tests: cover a CPU hotplug cycle in user-space timerlat mode
Date: Thu, 12 Nov 2026 18:20:20 +0800 [thread overview]
Message-ID: <179447882047.254241.11597980544275717800@gmail.com> (raw)
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
next reply other threads:[~2026-11-12 10:23 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-11-12 10:20 Chaosheng Qu [this message]
2026-11-12 10:39 ` [PATCH] rtla/tests: cover a CPU hotplug cycle in user-space timerlat mode sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=179447882047.254241.11597980544275717800@gmail.com \
--to=chaosheng.qu.linux@gmail.com \
--cc=linux-kernel@vger.kernel.org \
--cc=linux-trace-kernel@vger.kernel.org \
--cc=rostedt@goodmis.org \
--cc=tglozar@redhat.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox