| From: Mike Galbraith <efault@gmx.de> |
| Date: Fri, 20 Jan 2017 18:10:20 +0100 |
| Subject: [PATCH] softirq: wake the timer softirq if needed |
| |
| The irq-exit path only checks the "normal"-softirq thread if it is |
| running and ignores the state of the "timer"-softirq thread. It is possible |
| that the timer-softirq thread is and has work pending which leads to the |
| following warning: |
| |
| [ 84.087571] NOHZ: local_softirq_pending 02 |
| [ 84.087593] NOHZ: local_softirq_pending 02 |
| [ 84.087598] NOHZ: local_softirq_pending 02 |
| [ 84.087904] NOHZ: local_softirq_pending 02 |
| [ 84.088526] NOHZ: local_softirq_pending 02 |
| [ 84.088899] NOHZ: local_softirq_pending 02 |
| [ 84.089463] NOHZ: local_softirq_pending 02 |
| [ 115.013470] NOHZ: local_softirq_pending 02 |
| [ 115.013601] NOHZ: local_softirq_pending 02 |
| [ 115.013709] NOHZ: local_softirq_pending 02 |
| |
| This was introduced during the timer-softirq split. |
| |
| Cc: stable-rt@vger.kernel.org |
| Signed-off-by: Mike Galbraith <efault@gmx.de> |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| kernel/softirq.c | 11 +++++------ |
| 1 file changed, 5 insertions(+), 6 deletions(-) |
| |
| --- a/kernel/softirq.c |
| +++ b/kernel/softirq.c |
| @@ -28,6 +28,7 @@ |
| #include <linux/tick.h> |
| #include <linux/locallock.h> |
| #include <linux/irq.h> |
| +#include <linux/sched/types.h> |
| |
| #define CREATE_TRACE_POINTS |
| #include <trace/events/irq.h> |
| @@ -206,6 +207,7 @@ static void handle_softirq(unsigned int |
| } |
| } |
| |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| /* |
| * If ksoftirqd is scheduled, we do not want to process pending softirqs |
| * right now. Let ksoftirqd handle this at its own rate, to get fairness. |
| @@ -217,7 +219,6 @@ static bool ksoftirqd_running(void) |
| return tsk && (tsk->state == TASK_RUNNING); |
| } |
| |
| -#ifndef CONFIG_PREEMPT_RT_FULL |
| static inline int ksoftirqd_softirq_pending(void) |
| { |
| return local_softirq_pending(); |
| @@ -773,13 +774,10 @@ void irq_enter(void) |
| |
| static inline void invoke_softirq(void) |
| { |
| -#ifdef CONFIG_PREEMPT_RT_FULL |
| - unsigned long flags; |
| -#endif |
| - |
| +#ifndef CONFIG_PREEMPT_RT_FULL |
| if (ksoftirqd_running()) |
| return; |
| -#ifndef CONFIG_PREEMPT_RT_FULL |
| + |
| if (!force_irqthreads) { |
| #ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK |
| /* |
| @@ -800,6 +798,7 @@ static inline void invoke_softirq(void) |
| wakeup_softirqd(); |
| } |
| #else /* PREEMPT_RT_FULL */ |
| + unsigned long flags; |
| |
| local_irq_save(flags); |
| if (__this_cpu_read(ksoftirqd) && |