aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/spurious.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-02-07 03:05:05 -0500
committerThomas Gleixner <tglx@linutronix.de>2011-02-19 06:58:08 -0500
commit1082687e8d6292a61759eb83358e7db39fed1bf4 (patch)
tree2a6ba19073820f116050b1730f3e08f97187ddb2 /kernel/irq/spurious.c
parent2b879eaf095878430c38cbd95e5c0fc4ce65ad8e (diff)
genirq: Plug race in report_bad_irq()
We cannot walk the action chain unlocked. Even if IRQ_INPROGRESS is set an action can be removed and we follow a null pointer. It's safe to take the lock there, because the code which removes the action will call synchronize_irq() which waits unlocked for IRQ_INPROGRESS going away. Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq/spurious.c')
-rw-r--r--kernel/irq/spurious.c12
1 files changed, 9 insertions, 3 deletions
diff --git a/kernel/irq/spurious.c b/kernel/irq/spurious.c
index 3089d3b9d5f..2fbfda2716e 100644
--- a/kernel/irq/spurious.c
+++ b/kernel/irq/spurious.c
@@ -139,15 +139,13 @@ static void poll_spurious_irqs(unsigned long dummy)
139 * 139 *
140 * (The other 100-of-100,000 interrupts may have been a correctly 140 * (The other 100-of-100,000 interrupts may have been a correctly
141 * functioning device sharing an IRQ with the failing one) 141 * functioning device sharing an IRQ with the failing one)
142 *
143 * Called under desc->lock
144 */ 142 */
145
146static void 143static void
147__report_bad_irq(unsigned int irq, struct irq_desc *desc, 144__report_bad_irq(unsigned int irq, struct irq_desc *desc,
148 irqreturn_t action_ret) 145 irqreturn_t action_ret)
149{ 146{
150 struct irqaction *action; 147 struct irqaction *action;
148 unsigned long flags;
151 149
152 if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) { 150 if (action_ret != IRQ_HANDLED && action_ret != IRQ_NONE) {
153 printk(KERN_ERR "irq event %d: bogus return value %x\n", 151 printk(KERN_ERR "irq event %d: bogus return value %x\n",
@@ -159,6 +157,13 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,
159 dump_stack(); 157 dump_stack();
160 printk(KERN_ERR "handlers:\n"); 158 printk(KERN_ERR "handlers:\n");
161 159
160 /*
161 * We need to take desc->lock here. note_interrupt() is called
162 * w/o desc->lock held, but IRQ_PROGRESS set. We might race
163 * with something else removing an action. It's ok to take
164 * desc->lock here. See synchronize_irq().
165 */
166 raw_spin_lock_irqsave(&desc->lock, flags);
162 action = desc->action; 167 action = desc->action;
163 while (action) { 168 while (action) {
164 printk(KERN_ERR "[<%p>]", action->handler); 169 printk(KERN_ERR "[<%p>]", action->handler);
@@ -167,6 +172,7 @@ __report_bad_irq(unsigned int irq, struct irq_desc *desc,
167 printk("\n"); 172 printk("\n");
168 action = action->next; 173 action = action->next;
169 } 174 }
175 raw_spin_unlock_irqrestore(&desc->lock, flags);
170} 176}
171 177
172static void 178static void