Commit 4557398f8cbaf9f254cff747534b4724c7f75c4f

Authored by Kirill Korotaev
Committed by Linus Torvalds
1 parent c5b609797b

[PATCH] stop_machine() vs. synchronous IPI send deadlock

This fixes deadlock of stop_machine() vs.  synchronous IPI send.  The
problem is that stop_machine() disables interrupts before disabling
preemption on other CPUs.  So if another CPU is preempted and then calls
something like flush_tlb_all() it will deadlock with CPU doing
stop_machine() and which can't process IPI due to disabled IRQs.

I changed stop_machine() to do the same things exactly as it does on other
CPUs, i.e.  it should disable preemption first on _all_ CPUs including
itself and only after that disable IRQs.

Signed-off-by: Kirill Korotaev <dev@sw.ru>
Cc: Rusty Russell <rusty@rustcorp.com.au>
Cc: "Andrey Savochkin" <saw@sawoct.com>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>

Showing 1 changed file with 3 additions and 3 deletions Side-by-side Diff

kernel/stop_machine.c
... ... @@ -119,13 +119,12 @@
119 119 return ret;
120 120 }
121 121  
122   - /* Don't schedule us away at this point, please. */
123   - local_irq_disable();
124   -
125 122 /* Now they are all started, make them hold the CPUs, ready. */
  123 + preempt_disable();
126 124 stopmachine_set_state(STOPMACHINE_PREPARE);
127 125  
128 126 /* Make them disable irqs. */
  127 + local_irq_disable();
129 128 stopmachine_set_state(STOPMACHINE_DISABLE_IRQ);
130 129  
131 130 return 0;
... ... @@ -135,6 +134,7 @@
135 134 {
136 135 stopmachine_set_state(STOPMACHINE_EXIT);
137 136 local_irq_enable();
  137 + preempt_enable_no_resched();
138 138 }
139 139  
140 140 struct stop_machine_data