diff options
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/softirq.c | 15 | ||||
-rw-r--r-- | kernel/time/tick-sched.c | 2 |
2 files changed, 16 insertions, 1 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c index 1ed1c55aa2a7..5a99696da86a 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -141,6 +141,21 @@ static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = { .lock = INIT_LOCAL_LOCK(softirq_ctrl.lock), }; +/** + * local_bh_blocked() - Check for idle whether BH processing is blocked + * + * Returns false if the per CPU softirq::cnt is 0 otherwise true. + * + * This is invoked from the idle task to guard against false positive + * softirq pending warnings, which would happen when the task which holds + * softirq_ctrl::lock was the only running task on the CPU and blocks on + * some other lock. + */ +bool local_bh_blocked(void) +{ + return __this_cpu_read(softirq_ctrl.cnt) != 0; +} + void __local_bh_disable_ip(unsigned long ip, unsigned int cnt) { unsigned long flags; diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index e10a4af88737..0cc55791b2b6 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -973,7 +973,7 @@ static bool can_stop_idle_tick(int cpu, struct tick_sched *ts) if (unlikely(local_softirq_pending())) { static int ratelimit; - if (ratelimit < 10 && + if (ratelimit < 10 && !local_bh_blocked() && (local_softirq_pending() & SOFTIRQ_STOP_IDLE_MASK)) { pr_warn("NOHZ tick-stop error: Non-RCU local softirq work is pending, handler #%02x!!!\n", (unsigned int) local_softirq_pending()); |