History

genirq: prevent wakeup of freed irq thread

free_irq() can remove an irqaction while the corresponding interrupt is in progress, but free_irq() sets action->thread to NULL unconditionally, which might lead to a NULL pointer dereference in handle_IRQ_event() when the hard interrupt context tries to wake up the handler thread. Prevent this by moving the thread stop after synchronize_irq(). No need to set action->thread to NULL either as action is going to be freed anyway. This fixes a boot crash reported against preempt-rt which uses the mainline irq threads code to implement full irq threading. [ tglx: removed local irqthread variable ]

Linus Torvalds committed 17 years ago

Commit 2d860ad1 parent 3493e841 file · +7 −10Browse files

Showing the changes to kernel (1 of 1 file). Show all

Unified · Split

kernel/irq/manage.c+7−10
@@ -761,7 +761,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) · 760 unmodified lines
761761 {
762762 struct irq_desc *desc = irq_to_desc(irq);
763763 struct irqaction *action, **action_ptr;
764− struct task_struct *irqthread;
765764 unsigned long flags;
766765
767766 WARN(in_interrupt(), "Trying to free IRQ %d from IRQ context!\n", irq);
@@ -809,9 +808,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) · 41 unmodified lines
809808 desc->chip->disable(irq);
810809 }
811810
812− irqthread = action->thread;
813− action->thread = NULL;
814−
815811 spin_unlock_irqrestore(&desc->lock, flags);
816812
817813 unregister_handler_proc(irq, action);
@@ -819,12 +815,6 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) · 1 unmodified line
819815 /* Make sure it's not being used on another CPU: */
820816 synchronize_irq(irq);
821817
822− if (irqthread) {
823− if (!test_bit(IRQTF_DIED, &action->thread_flags))
824− kthread_stop(irqthread);
825− put_task_struct(irqthread);
826− }
827−
828818 #ifdef CONFIG_DEBUG_SHIRQ
829819 /*
830820 * It's a shared IRQ -- the driver ought to be prepared for an IRQ
@@ -840,6 +830,13 @@ static struct irqaction *__free_irq(unsigned int irq, void *dev_id) · 9 unmodified lines
840830 local_irq_restore(flags);
841831 }
842832 #endif
833+
834+ if (action->thread) {
835+ if (!test_bit(IRQTF_DIED, &action->thread_flags))
836+ kthread_stop(action->thread);
837+ put_task_struct(action->thread);
838+ }
839+
843840 return action;
844841 }
845842