Commit 4557398f8cbaf9f254cff747534b4724c7f75c4f
Committed by
Linus Torvalds
1 parent
c5b609797b
Exists in
master
and in
7 other branches
[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 |