From 0016728c7248109eabf7e73f03e20b12ca332c40 Mon Sep 17 00:00:00 2001 From: Thomas Gleixner Date: Fri, 3 Jul 2009 13:16:38 -0500 Subject: [PATCH] softirq: Sanitize softirq pending for NOHZ/RT commit 1b5c1881af922ba4a3c793ec9afb240885293370 in tip. Signed-off-by: Thomas Gleixner Signed-off-by: Paul Gortmaker --- include/linux/interrupt.h | 1 + kernel/softirq.c | 68 +++++++++++++++++++++++++++++++++++++++++++++ kernel/time/tick-sched.c | 8 +---- 3 files changed, 70 insertions(+), 7 deletions(-) diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 0fd5b27..9f6580a 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -390,6 +390,7 @@ extern void open_softirq(int nr, void (*action)(struct softirq_action *)); extern void softirq_init(void); extern void raise_softirq_irqoff(unsigned int nr); extern void raise_softirq(unsigned int nr); +extern void softirq_check_pending_idle(void); /* This is the worklist that queues up per-cpu softirq work. * diff --git a/kernel/softirq.c b/kernel/softirq.c index b4b1819..f0b863e 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -76,6 +76,74 @@ char *softirq_to_name[NR_SOFTIRQS] = { "TASKLET", "SCHED", "HRTIMER", "RCU" }; +#ifdef CONFIG_PREEMPT_RT +/* + * On preempt-rt a softirq might be blocked on a lock. There might be + * no other runnable task on this CPU because the lock owner runs on + * some other CPU. So we have to go into idle with the pending bit + * set. Therefor we need to check this otherwise we warn about false + * positives which confuses users and defeats the whole purpose of + * this test. + * + * This code is called with interrupts disabled. + */ +void softirq_check_pending_idle(void) +{ + static int rate_limit; + u32 warnpending = 0, pending = local_softirq_pending(); + int curr = 0; + + if (rate_limit >= 10) + return; + + while (pending) { + if (pending & 1) { + struct task_struct *tsk; + + tsk = __get_cpu_var(ksoftirqd)[curr].tsk; + /* + * The wakeup code in rtmutex.c wakes up the + * task _before_ it sets pi_blocked_on to NULL + * under tsk->pi_lock. So we need to check for + * both: state and pi_blocked_on. + */ + raw_spin_lock(&tsk->pi_lock); + + if (!tsk->pi_blocked_on && + !(tsk->state == TASK_RUNNING) && + !(tsk->state & TASK_RUNNING_MUTEX)) + warnpending |= 1 << curr; + + raw_spin_unlock(&tsk->pi_lock); + } + pending >>= 1; + curr++; + } + + if (warnpending) { + printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n", + warnpending); + rate_limit++; + } +} + +#else +/* + * On !PREEMPT_RT we just printk rate limited: + */ +void softirq_check_pending_idle(void) +{ + static int rate_limit; + + if (rate_limit < 10) { + printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n", + local_softirq_pending()); + rate_limit++; + } +} + +#endif + /* * we cannot loop indefinitely here to avoid userspace starvation, * but we also don't want to introduce a worst case 1/HZ latency diff --git a/kernel/time/tick-sched.c b/kernel/time/tick-sched.c index a85776e..a521150 100644 --- a/kernel/time/tick-sched.c +++ b/kernel/time/tick-sched.c @@ -252,13 +252,7 @@ void tick_nohz_stop_sched_tick(int inidle) goto end; if (unlikely(local_softirq_pending() && cpu_online(cpu))) { - static int ratelimit; - - if (ratelimit < 10) { - printk(KERN_ERR "NOHZ: local_softirq_pending %02x\n", - (unsigned int) local_softirq_pending()); - ratelimit++; - } + softirq_check_pending_idle(); goto end; } -- 1.7.0.4