irqentry_nmi_enter() reads lockdep's hardirq state before __nmi_enter()
establishes NMI context. Arm64 does the same for its NMI-like EL1 debug
entry. Both paths run with interrupts disabled and cannot migrate.

lockdep_hardirqs_enabled() uses this_cpu_read(), whose preemption checks
are unnecessary for these callers. Add a raw accessor and use it in the
two entry paths and in lockdep_hardirqs_off(). Keep the existing accessor
for callers which are not already pinned.

Check the interrupt state before accessing per-CPU state in
lockdep_hardirqs_off(), independently of warning suppression.

On arm64, this change relies on __kern_my_cpu_offset() being forced inline
by the earlier prerequisite patch so the call chain remains noinstr-safe.

Assisted-by: LLM
---
 arch/arm64/kernel/entry-common.c | 6 +++---
 include/linux/irqflags.h         | 3 +++
 kernel/entry/common.c            | 2 +-
 kernel/locking/lockdep.c         | 6 ++++--
 4 files changed, 11 insertions(+), 6 deletions(-)

diff --git a/arch/arm64/kernel/entry-common.c b/arch/arm64/kernel/entry-common.c
index 11d3f888fcd87..003f84109a913 100644
--- a/arch/arm64/kernel/entry-common.c
+++ b/arch/arm64/kernel/entry-common.c
@@ -177,9 +177,9 @@ asmlinkage void noinstr asm_exit_to_user_mode(struct 
pt_regs *regs)
  */
 static noinstr irqentry_state_t arm64_enter_el1_dbg(struct pt_regs *regs)
 {
-       irqentry_state_t state;
-
-       state.lockdep = lockdep_hardirqs_enabled();
+       irqentry_state_t state = {
+               .lockdep = lockdep_hardirqs_enabled_raw(),
+       };
 
        lockdep_hardirqs_off(CALLER_ADDR0);
        ct_nmi_enter();
diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h
index 57b074e0cfbbb..5bc179a88e513 100644
--- a/include/linux/irqflags.h
+++ b/include/linux/irqflags.h
@@ -52,6 +52,8 @@ extern void trace_hardirqs_off(void);
 # define lockdep_hardirq_context()     (raw_cpu_read(hardirq_context))
 # define lockdep_softirq_context(p)    ((p)->softirq_context)
 # define lockdep_hardirqs_enabled()    (this_cpu_read(hardirqs_enabled))
+/* The caller must already be pinned to the current CPU. */
+# define lockdep_hardirqs_enabled_raw()        (raw_cpu_read(hardirqs_enabled))
 # define lockdep_softirqs_enabled(p)   ((p)->softirqs_enabled)
 # define lockdep_hardirq_enter()                       \
 do {                                                   \
@@ -113,6 +115,7 @@ do {                                                \
 # define lockdep_hardirq_context()             0
 # define lockdep_softirq_context(p)            0
 # define lockdep_hardirqs_enabled()            0
+# define lockdep_hardirqs_enabled_raw()                0
 # define lockdep_softirqs_enabled(p)           0
 # define lockdep_hardirq_enter()               do { } while (0)
 # define lockdep_hardirq_threaded()            do { } while (0)
diff --git a/kernel/entry/common.c b/kernel/entry/common.c
index e234b04373fea..2f5229132466c 100644
--- a/kernel/entry/common.c
+++ b/kernel/entry/common.c
@@ -158,7 +158,7 @@ irqentry_state_t noinstr irqentry_nmi_enter(struct pt_regs 
*regs)
 {
        irqentry_state_t irq_state;
 
-       irq_state.lockdep = lockdep_hardirqs_enabled();
+       irq_state.lockdep = lockdep_hardirqs_enabled_raw();
 
        __nmi_enter();
        lockdep_hardirqs_off(CALLER_ADDR0);
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index c3dc84a7cef26..01dba8fb32a90 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c
@@ -4543,10 +4543,12 @@ void noinstr lockdep_hardirqs_off(unsigned long ip)
         * So we're supposed to get called after you mask local IRQs, but for
         * some reason the hardware doesn't quite think you did a proper job.
         */
-       if (DEBUG_LOCKS_WARN_ON(!irqs_disabled()))
+       if (unlikely(!irqs_disabled())) {
+               DEBUG_LOCKS_WARN_ON(1);
                return;
+       }
 
-       if (lockdep_hardirqs_enabled()) {
+       if (lockdep_hardirqs_enabled_raw()) {
                struct irqtrace_events *trace = &current->irqtrace;
 
                /*
-- 
2.39.5 (Apple Git-154)


Reply via email to