[RFC PATCH v7 10/10] selftests/ftrace: add a stackmap instance gating test
From: Li Pengfei
Date: Sat Sep 12 2026 - 04:53:28 EST
From: Pengfei Li <lipengfei28@xxxxxxxxxx>
Verify both enforcement points for the global-instance-only stackmap
option.
Require options/stackmap and stack_map on the top-level instance. Read a
shared-kernel random UUID from /proc/sys/kernel/random/uuid and combine
it with ftracetest's $PID to create collision-resistant owned and foreign
secondary-instance names, including across PID namespaces. Verify that
neither the option nor any stack_map node appears in the owned instance.
Also require writing stackmap through its aggregate trace_options file
to fail and leave the option unset.
Create the foreign instance as a sentinel. Remove the owned instance
explicitly and verify the sentinel remains, proving that cleanup does
not remove unrelated instances.
Defer signal exit across each mkdir and ownership assignment so cleanup
removes a directory only after this invocation has created it. Put mkdir
in an if condition so ftracetest's errexit mode cannot bypass return-code
handling, the explicit failure path, or ownership bookkeeping. Track both
directories separately and remove only those created by this test. Keep
the auxiliary stack_map_stat and stack_map_bin nodes optional on the
global side.
Signed-off-by: Pengfei Li <lipengfei28@xxxxxxxxxx>
---
.../test.d/ftrace/stackmap-instance-gate.tc | 114 ++++++++++++++++++
1 file changed, 114 insertions(+)
create mode 100644 tools/testing/selftests/ftrace/test.d/ftrace/stackmap-instance-gate.tc
diff --git a/tools/testing/selftests/ftrace/test.d/ftrace/stackmap-instance-gate.tc b/tools/testing/selftests/ftrace/test.d/ftrace/stackmap-instance-gate.tc
new file mode 100644
index 000000000000..818dbb7bfeb8
--- /dev/null
+++ b/tools/testing/selftests/ftrace/test.d/ftrace/stackmap-instance-gate.tc
@@ -0,0 +1,114 @@
+#!/bin/sh
+# SPDX-License-Identifier: GPL-2.0
+# description: ftrace - stackmap option is gated to the top-level trace instance
+# requires: stack_map options/stackmap instances
+
+# The 'stackmap' option is added to TOP_LEVEL_TRACE_FLAGS, matching the
+# convention used for global-only options like 'printk' and 'record-cmd'.
+# Verify that:
+# 1. The global instance exposes options/stackmap and the required
+# stack_map node. stack_map_stat and stack_map_bin are auxiliary and
+# may be absent if their tracefs creation failed.
+# 2. A newly created secondary instance under instances/ does NOT expose
+# options/stackmap or any stack_map* nodes.
+
+fail() {
+ echo "FAIL: $1"
+ exit_fail
+}
+
+instance_token=$(cat /proc/sys/kernel/random/uuid 2>/dev/null) || {
+ echo "could not obtain a collision-resistant instance token"
+ exit_unresolved
+}
+[ -n "$instance_token" ] || exit_unresolved
+owned_instance=stackmap_gate_owned_${PID}_${instance_token}
+owned_dir=instances/$owned_instance
+foreign_instance=stackmap_gate_foreign_${PID}_${instance_token}
+foreign_dir=instances/$foreign_instance
+owned_created=0
+foreign_created=0
+
+remove_owned() {
+ if [ "$owned_created" -eq 1 ]; then
+ rmdir "$owned_dir" || return 1
+ owned_created=0
+ fi
+}
+
+cleanup() {
+ if [ "$owned_created" -eq 1 ]; then
+ rmdir "$owned_dir" 2>/dev/null || :
+ fi
+ if [ "$foreign_created" -eq 1 ]; then
+ rmdir "$foreign_dir" 2>/dev/null || :
+ fi
+}
+trap cleanup EXIT
+trap 'exit 1' HUP INT TERM
+
+# 1. Global instance must expose the option and required map node
+test -e options/stackmap || fail "options/stackmap missing on global instance"
+test -e stack_map || fail "stack_map missing on global instance"
+
+# 2. Create a foreign sentinel and an owned secondary instance. Defer signal
+# exit across each mkdir and ownership assignment: cleanup must remove a path
+# only after this invocation has successfully created it.
+interrupted=0
+trap 'interrupted=1' HUP INT TERM
+create_rc=0
+if mkdir "$foreign_dir"; then
+ foreign_created=1
+else
+ create_rc=$?
+fi
+trap 'exit 1' HUP INT TERM
+[ "$interrupted" -eq 0 ] || exit 1
+[ "$create_rc" -eq 0 ] || fail "could not create foreign sentinel instance"
+
+interrupted=0
+trap 'interrupted=1' HUP INT TERM
+create_rc=0
+if mkdir "$owned_dir"; then
+ owned_created=1
+else
+ create_rc=$?
+fi
+trap 'exit 1' HUP INT TERM
+[ "$interrupted" -eq 0 ] || exit 1
+[ "$create_rc" -eq 0 ] || fail "could not create secondary instance"
+
+if [ -e "$owned_dir/options/stackmap" ]; then
+ fail "secondary instance unexpectedly exposes options/stackmap"
+fi
+
+for f in stack_map stack_map_stat stack_map_bin; do
+ if [ -e "$owned_dir/$f" ]; then
+ fail "secondary instance unexpectedly has $f"
+ fi
+done
+
+# 3. The aggregate trace_options file still reaches set_tracer_flag(),
+# so writing 'stackmap' there must be rejected on a secondary
+# instance. Otherwise the bit could appear set in trace_options
+# while the hot path silently falls back to a full stack trace
+# (tr->stackmap == NULL).
+if echo stackmap > "$owned_dir/trace_options" 2>/dev/null; then
+ fail "secondary instance accepted 'echo stackmap > trace_options'"
+fi
+if grep -qw stackmap "$owned_dir/trace_options"; then
+ fail "secondary instance trace_options reports stackmap as set"
+fi
+
+remove_owned || fail "could not remove owned secondary instance"
+if [ -e "$owned_dir" ]; then
+ fail "owned secondary instance still exists after removal"
+fi
+if [ ! -d "$foreign_dir" ]; then
+ fail "owned cleanup removed foreign sentinel instance"
+fi
+rmdir "$foreign_dir" || fail "could not remove foreign sentinel instance"
+foreign_created=0
+
+echo "stackmap option gating to top-level instance works"
+exit 0
--
2.34.1