[RFC PATCH 2/9] arm64/entry: Make debug_exception_enter/exit() noinstr
From: Hongyan Xia
Date: Mon Jul 27 2026 - 08:28:55 EST
From: Hongyan Xia <hongyan.xia@xxxxxxxxxxxxx>
Commit 879a6754d3d11e30af24b7dc486f561510d62641 ran into a crash because
debug_exception_enter/exit() triggered page faults caused by perf dwarf
call graph tracing. That patch was a band-aid on top. Instead of trying
to band-aid all possible paths that can happen during instrumentation or
perf tracing, simply make both functions noinstr.
Drop the RCU_LOCKDEP_WARN(): arm64_enter_el1_dbg() runs first and
enters NMI context via ct_nmi_enter(), so RCU is always watching by the
time debug_exception_enter() runs.
Signed-off-by: Hongyan Xia <hongyan.xia@xxxxxxxxxxxxx>
---
arch/arm64/kernel/entry-common.c | 24 +++++++++++++++---------
1 file changed, 15 insertions(+), 9 deletions(-)
diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
index 466529cce1c3..f06b5e2437cd 100644
--- a/arch/arm64/kernel/entry-common.c
+++ b/arch/arm64/kernel/entry-common.c
@@ -293,20 +293,26 @@ static __always_inline void fpsimd_syscall_exit(void)
* accidentally schedule in exception context and it will force a warning
* if we somehow manage to schedule by accident.
*/
-static void debug_exception_enter(struct pt_regs *regs)
+static void noinstr debug_exception_enter(struct pt_regs *regs)
{
- preempt_disable();
-
- /* This code is a bit fragile. Test it. */
- RCU_LOCKDEP_WARN(!rcu_is_watching(), "exception_enter didn't work");
+ /*
+ * debug_exception_enter/exit() can be quite delicate. The normal
+ * preempt_disable/enable() can be instrumented or traced by perf,
+ * which leads to a can of worms including triggering page faults.
+ *
+ * Instead of trying to make all of them work properly here, just
+ * open-code the simpler version of preempt_disable/enable() and make
+ * enter/exit() both noinstr to avoid the entire complexity.
+ */
+ __preempt_count_inc();
+ barrier();
}
-NOKPROBE_SYMBOL(debug_exception_enter);
-static void debug_exception_exit(struct pt_regs *regs)
+static void noinstr debug_exception_exit(struct pt_regs *regs)
{
- preempt_enable_no_resched();
+ barrier();
+ __preempt_count_dec();
}
-NOKPROBE_SYMBOL(debug_exception_exit);
UNHANDLED(el1t, 64, sync)
UNHANDLED(el1t, 64, irq)
--
2.47.3