| From 62d3301d1f68a084ff40f564f34ae7411214b352 Mon Sep 17 00:00:00 2001 |
| From: Thomas Gleixner <tglx@linutronix.de> |
| 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 <tglx@linutronix.de> |
| Signed-off-by: Paul Gortmaker <paul.gortmaker@windriver.com> |
| |
| 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.1.1 |
| |