The following commit has been merged into the locking/core branch of tip: Commit-ID: 8a9d677a395703ef9075c91dd04066be8a553405 Gitweb: https://git.kernel.org/tip/8a9d677a395703ef9075c91dd04066be8a553405 Author: Ryo Takakura <ryotkkr98@xxxxxxxxx> AuthorDate: Sat, 18 Jan 2025 14:49:00 +09:00 Committer: Boqun Feng <boqun.feng@xxxxxxxxx> CommitterDate: Sun, 23 Feb 2025 18:24:46 -08:00 lockdep: Fix wait context check on softirq for PREEMPT_RT Since commit 0c1d7a2c2d32 ("lockdep: Remove softirq accounting on PREEMPT_RT."), the wait context test for mutex usage within "in softirq context" fails as it references @softirq_context. [ 0.184549] | wait context tests | [ 0.184549] -------------------------------------------------------------------------- [ 0.184549] | rcu | raw | spin |mutex | [ 0.184549] -------------------------------------------------------------------------- [ 0.184550] in hardirq context: ok | ok | ok | ok | [ 0.185083] in hardirq context (not threaded): ok | ok | ok | ok | [ 0.185606] in softirq context: ok | ok | ok |FAILED| As a fix, add lockdep map for BH disabled section. This fixes the issue by letting us catch cases when local_bh_disable() gets called with preemption disabled where local_lock doesn't get acquired. In the case of "in softirq context" selftest, local_bh_disable() was being called with preemption disable as it's early in the boot. Signed-off-by: Ryo Takakura <ryotkkr98@xxxxxxxxx> Signed-off-by: Boqun Feng <boqun.feng@xxxxxxxxx> Link: https://lore.kernel.org/r/20250118054900.18639-1-ryotkkr98@xxxxxxxxx --- include/linux/bottom_half.h | 8 ++++++++ kernel/softirq.c | 12 ++++++++++++ 2 files changed, 20 insertions(+) diff --git a/include/linux/bottom_half.h b/include/linux/bottom_half.h index fc53e0a..0640a14 100644 --- a/include/linux/bottom_half.h +++ b/include/linux/bottom_half.h @@ -4,6 +4,7 @@ #include <linux/instruction_pointer.h> #include <linux/preempt.h> +#include <linux/lockdep.h> #if defined(CONFIG_PREEMPT_RT) || defined(CONFIG_TRACE_IRQFLAGS) extern void __local_bh_disable_ip(unsigned long ip, unsigned int cnt); @@ -15,8 +16,13 @@ static __always_inline void __local_bh_disable_ip(unsigned long ip, unsigned int } #endif +#ifdef CONFIG_DEBUG_LOCK_ALLOC +extern struct lockdep_map bh_lock_map; +#endif + static inline void local_bh_disable(void) { + lock_map_acquire_read(&bh_lock_map); __local_bh_disable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET); } @@ -25,11 +31,13 @@ extern void __local_bh_enable_ip(unsigned long ip, unsigned int cnt); static inline void local_bh_enable_ip(unsigned long ip) { + lock_map_release(&bh_lock_map); __local_bh_enable_ip(ip, SOFTIRQ_DISABLE_OFFSET); } static inline void local_bh_enable(void) { + lock_map_release(&bh_lock_map); __local_bh_enable_ip(_THIS_IP_, SOFTIRQ_DISABLE_OFFSET); } diff --git a/kernel/softirq.c b/kernel/softirq.c index 4dae6ac..e864f9c 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -1073,3 +1073,15 @@ unsigned int __weak arch_dynirq_lower_bound(unsigned int from) { return from; } + +#ifdef CONFIG_DEBUG_LOCK_ALLOC +static struct lock_class_key bh_lock_key; +struct lockdep_map bh_lock_map = { + .name = "local_bh", + .key = &bh_lock_key, + .wait_type_outer = LD_WAIT_FREE, + .wait_type_inner = LD_WAIT_CONFIG, /* PREEMPT_RT makes BH preemptible. */ + .lock_type = LD_LOCK_PERCPU, +}; +EXPORT_SYMBOL_GPL(bh_lock_map); +#endif
![]() |