genirq: Prevent resend to interrupts marked IRQ_NESTED_THREAD

The resend mechanism happily calls the interrupt handler of interrupts
which are marked IRQ_NESTED_THREAD from softirq context. This can
result in crashes because the interrupt handler is not the proper way
to invoke the device handlers. They must be invoked via
handle_nested_irq.

Prevent the resend even if the interrupt has no valid parent irq
set. Its better to have a lost interrupt than a crashing machine.

Reported-by: Uwe Kleine-König <u.kleine-koenig@pengutronix.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Cc: stable@vger.kernel.org
This commit is contained in:
Thomas Gleixner 2015-07-16 14:10:17 +02:00
parent ce0d3c0a6f
commit 75a06189fc

View file

@ -75,13 +75,21 @@ void check_irq_resend(struct irq_desc *desc, unsigned int irq)
!desc->irq_data.chip->irq_retrigger(&desc->irq_data)) { !desc->irq_data.chip->irq_retrigger(&desc->irq_data)) {
#ifdef CONFIG_HARDIRQS_SW_RESEND #ifdef CONFIG_HARDIRQS_SW_RESEND
/* /*
* If the interrupt has a parent irq and runs * If the interrupt is running in the thread
* in the thread context of the parent irq, * context of the parent irq we need to be
* retrigger the parent. * careful, because we cannot trigger it
* directly.
*/ */
if (desc->parent_irq && if (irq_settings_is_nested_thread(desc)) {
irq_settings_is_nested_thread(desc)) /*
* If the parent_irq is valid, we
* retrigger the parent, otherwise we
* do nothing.
*/
if (!desc->parent_irq)
return;
irq = desc->parent_irq; irq = desc->parent_irq;
}
/* Set it pending and activate the softirq: */ /* Set it pending and activate the softirq: */
set_bit(irq, irqs_resend); set_bit(irq, irqs_resend);
tasklet_schedule(&resend_tasklet); tasklet_schedule(&resend_tasklet);