[RFC PATCH v2 08/13] lockdep: Prepare IRQ-on state from a hardirq return tail
flat view
WARM1d
From: Karl Mehltretter <hidden>
Date: 2026-10-28 03:32:05
Also in:
linux-doc, linux-rt-devel, linux-trace-kernel, lkml, llvm
Subsystem:
locking primitives, the rest · Maintainers:
Peter Zijlstra, Ingo Molnar, Will Deacon, Boqun Feng, Linus Torvalds
lockdep_hardirqs_on_prepare() rejects any live hardirq context. An ordinary hardirq return tail needs to retain synthetic hardirq nesting through traceable IRQ-on preparation. This keeps callbacks classified as hardirq work. Factor the common preparation and add a return-tail variant which requires the synthetic hardirq context to be present. An interrupted outer hardirq can contribute additional nesting. Keep the ordinary helper restricted to zero. Neither helper changes IRQ or hardirq state. The caller must remove the tail context before lockdep_hardirqs_on(). Assisted-by: LLM --- include/linux/irqflags.h | 2 ++ kernel/locking/lockdep.c | 43 +++++++++++++++++++++++++++++----------- 2 files changed, 33 insertions(+), 12 deletions(-)
diff --git a/include/linux/irqflags.h b/include/linux/irqflags.h
index e98313a8ad307..c7601a173e55b 100644
--- a/include/linux/irqflags.h
+++ b/include/linux/irqflags.h@@ -25,6 +25,7 @@ struct task_struct; extern void lockdep_softirqs_on(unsigned long ip); extern void lockdep_softirqs_off(unsigned long ip); extern void lockdep_hardirqs_on_prepare(void); +void lockdep_hardirqs_on_prepare_irqtail(void); extern void lockdep_hardirqs_on(unsigned long ip); extern void lockdep_hardirqs_off(unsigned long ip); extern void lockdep_cleanup_dead_cpu(unsigned int cpu,
@@ -33,6 +34,7 @@ struct task_struct; static inline void lockdep_softirqs_on(unsigned long ip) { } static inline void lockdep_softirqs_off(unsigned long ip) { } static inline void lockdep_hardirqs_on_prepare(void) { } +static inline void lockdep_hardirqs_on_prepare_irqtail(void) { } static inline void lockdep_hardirqs_on(unsigned long ip) { } static inline void lockdep_hardirqs_off(unsigned long ip) { } static inline void lockdep_cleanup_dead_cpu(unsigned int cpu,
diff --git a/kernel/locking/lockdep.c b/kernel/locking/lockdep.c
index 01dba8fb32a90..2ecd506715fa7 100644
--- a/kernel/locking/lockdep.c
+++ b/kernel/locking/lockdep.c@@ -4395,15 +4395,7 @@ static void __trace_hardirqs_on_caller(void) mark_held_locks(curr, LOCK_ENABLED_SOFTIRQ); } -/** - * lockdep_hardirqs_on_prepare - Prepare for enabling interrupts - * - * Invoked before a possible transition to RCU idle from exit to user or - * guest mode. This ensures that all RCU operations are done before RCU - * stops watching. After the RCU transition lockdep_hardirqs_on() has to be - * invoked to set the final state. - */ -void lockdep_hardirqs_on_prepare(void) +static void __lockdep_hardirqs_on_prepare(bool expect_hardirq) { if (unlikely(!debug_locks)) return;
@@ -4442,10 +4434,11 @@ void lockdep_hardirqs_on_prepare(void) return; /* - * Can't allow enabling interrupts while in an interrupt handler, - * that's general bad form and such. Recursion, limited stack etc.. + * Ordinary IRQ enable requires no hardirq context. The interrupt return + * tail variant requires its synthetic context, possibly nested inside + * an interrupted outer hardirq. */ - if (DEBUG_LOCKS_WARN_ON(lockdep_hardirq_context())) + if (DEBUG_LOCKS_WARN_ON(!!lockdep_hardirq_context() != expect_hardirq)) return; current->hardirq_chain_key = current->curr_chain_key;
@@ -4454,8 +4447,34 @@ void lockdep_hardirqs_on_prepare(void) __trace_hardirqs_on_caller(); lockdep_recursion_finish(); } + +/** + * lockdep_hardirqs_on_prepare - Prepare for enabling interrupts + * + * Invoked before a possible transition to RCU idle from exit to user or + * guest mode. This ensures that all RCU operations are done before RCU + * stops watching. After the RCU transition lockdep_hardirqs_on() has to be + * invoked to set the final state. + */ +void lockdep_hardirqs_on_prepare(void) +{ + __lockdep_hardirqs_on_prepare(false); +} EXPORT_SYMBOL_GPL(lockdep_hardirqs_on_prepare); +/** + * lockdep_hardirqs_on_prepare_irqtail - Prepare an interrupt return tail + * + * Like lockdep_hardirqs_on_prepare(), but invoked while the synthetic lockdep + * hardirq context covering an interrupt return tail is still active. An + * interrupted outer hardirq can contribute additional nesting. The caller + * must remove the tail context before lockdep_hardirqs_on(). + */ +void lockdep_hardirqs_on_prepare_irqtail(void) +{ + __lockdep_hardirqs_on_prepare(true); +} + void noinstr lockdep_hardirqs_on(unsigned long ip) { struct irqtrace_events *trace = ¤t->irqtrace;
--
2.39.5 (Apple Git-154)