diff options
author | Thomas Gleixner <tglx@linutronix.de> | 2013-02-20 16:00:48 -0500 |
---|---|---|
committer | Thomas Gleixner <tglx@linutronix.de> | 2013-02-21 14:52:24 -0500 |
commit | 74eed0163d0def3fce27228d9ccf3d36e207b286 (patch) | |
tree | 28aa386f02468504846ebec731e9ba432e4a4010 /kernel | |
parent | e5ab012c3271990e8457055c25cafddc1ae8aa6b (diff) |
irq: Ensure irq_exit() code runs with interrupts disabled
We had already a few problems with code called from irq_exit() when
interrupted from a nesting interrupt. This can happen on architectures
which do not define __ARCH_IRQ_EXIT_IRQS_DISABLED.
__ARCH_IRQ_EXIT_IRQS_DISABLED should go away and we want to make it
mandatory to call irq_exit() with interrupts disabled.
As a temporary protection disable interrupts for those architectures
which do not define __ARCH_IRQ_EXIT_IRQS_DISABLED and add a WARN_ONCE
when an architecture which defines __ARCH_IRQ_EXIT_IRQS_DISABLED calls
irq_exit() with interrupts enabled.
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: Frederic Weisbecker <fweisbec@gmail.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Ingo Molnar <mingo@kernel.org>
Cc: Paul E. McKenney <paulmck@linux.vnet.ibm.com>
Cc: Linus Torvalds <torvalds@linuxfoundation.org>
Link: http://lkml.kernel.org/r/alpine.LFD.2.02.1302202155320.22263@ionos
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/softirq.c | 11 |
1 files changed, 11 insertions, 0 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c index f5cc25f147a6..f2a934673008 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c | |||
@@ -341,6 +341,14 @@ static inline void invoke_softirq(void) | |||
341 | */ | 341 | */ |
342 | void irq_exit(void) | 342 | void irq_exit(void) |
343 | { | 343 | { |
344 | #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED | ||
345 | unsigned long flags; | ||
346 | |||
347 | local_irq_save(flags); | ||
348 | #else | ||
349 | WARN_ON_ONCE(!irqs_disabled()); | ||
350 | #endif | ||
351 | |||
344 | account_irq_exit_time(current); | 352 | account_irq_exit_time(current); |
345 | trace_hardirq_exit(); | 353 | trace_hardirq_exit(); |
346 | sub_preempt_count(IRQ_EXIT_OFFSET); | 354 | sub_preempt_count(IRQ_EXIT_OFFSET); |
@@ -354,6 +362,9 @@ void irq_exit(void) | |||
354 | #endif | 362 | #endif |
355 | rcu_irq_exit(); | 363 | rcu_irq_exit(); |
356 | sched_preempt_enable_no_resched(); | 364 | sched_preempt_enable_no_resched(); |
365 | #ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED | ||
366 | local_irq_restore(flags); | ||
367 | #endif | ||
357 | } | 368 | } |
358 | 369 | ||
359 | /* | 370 | /* |