[PATCH 3/3] docs: trace: Warn against using printk() in probe handlers

From: Masami Hiramatsu (Google)

Date: Mon Nov 02 2026 - 02:14:31 EST


From: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>

Probe handlers (kprobes, kretprobes, and fprobes) execute in atomic or
non-preemptible contexts. Because handlers do not run in NMI context
(especially when jump-optimized or ftrace-based), calling printk()
directly can attempt to synchronously acquire console driver locks or
scheduler locks (via console_unlock()), risking a deadlock if the probed
or interrupted context already holds those locks.

Document this restriction in both kprobes.rst and fprobe.rst, and
recommend using trace_printk() instead to safely log messages to the
ftrace buffer.

Signed-off-by: Masami Hiramatsu (Google) <mhiramat@xxxxxxxxxx>
---
Documentation/trace/fprobe.rst | 5 +++++
Documentation/trace/kprobes.rst | 11 +++++++++--
2 files changed, 14 insertions(+), 2 deletions(-)

diff --git a/Documentation/trace/fprobe.rst b/Documentation/trace/fprobe.rst
index 46dd46a97c1f..72e0fd9e1808 100644
--- a/Documentation/trace/fprobe.rst
+++ b/Documentation/trace/fprobe.rst
@@ -101,6 +101,11 @@ handler.
If the entry callback function returns !0, the corresponding exit callback
will be cancelled.

+Since the callbacks run with preemption disabled under ftrace recursion
+protection, calling printk() or pr_*() from these callbacks is not safe
+and can cause deadlocks on console driver or scheduler locks. Use
+trace_printk() instead to log debugging output.
+
@fp
This is the address of `fprobe` data structure related to this handler.
You can embed the `fprobe` to your data structure and get it by
diff --git a/Documentation/trace/kprobes.rst b/Documentation/trace/kprobes.rst
index 5e606730cec6..19c04a91a664 100644
--- a/Documentation/trace/kprobes.rst
+++ b/Documentation/trace/kprobes.rst
@@ -563,8 +563,8 @@ course, has no way to distinguish the deliberately injected faults
from the accidental ones. Don't drink and probe.

Kprobes makes no attempt to prevent probe handlers from stepping on
-each other -- e.g., probing printk() and then calling printk() from a
-probe handler. If a probe handler hits a probe, that second probe's
+each other -- e.g., probing trace_printk() and then calling trace_printk()
+from a probe handler. If a probe handler hits a probe, that second probe's
handlers won't be run in that instance, and the kprobe.nmissed member
of the second probe will be incremented.

@@ -579,6 +579,13 @@ which depends on the architecture and optimization state. (e.g.,
kretprobe handlers and optimized kprobe handlers run without interrupt
disabled on x86/x86-64). In any case, your handler should not yield
the CPU (e.g., by attempting to acquire a semaphore, or waiting I/O).
+Furthermore, probe handlers should avoid calling printk() or pr_*().
+Because probe handlers execute in atomic/non-preemptible contexts without
+being in NMI context (especially when jump-optimized or ftrace-based),
+calling printk() may attempt to synchronously acquire console driver locks
+or scheduler locks via console_unlock(), risking a deadlock if the probed
+or interrupted context already holds those locks. Use trace_printk()
+instead to safely output messages to the trace buffer.

Since a return probe is implemented by replacing the return
address with the trampoline's address, stack backtraces and calls