diff options
author | Kirill Korotaev <dev@sw.ru> | 2005-11-13 19:07:30 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-11-13 21:14:16 -0500 |
commit | 4557398f8cbaf9f254cff747534b4724c7f75c4f (patch) | |
tree | 052b59279b1312a4fde83a76feb4a7a0c5cf7df1 /kernel/stop_machine.c | |
parent | c5b609797b8e212dbfaf23944da8bf8c53233d5c (diff) |
[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>
Diffstat (limited to 'kernel/stop_machine.c')
-rw-r--r-- | kernel/stop_machine.c | 6 |
1 files changed, 3 insertions, 3 deletions
diff --git a/kernel/stop_machine.c b/kernel/stop_machine.c index 84a9d18aa8da..b3d4dc858e35 100644 --- a/kernel/stop_machine.c +++ b/kernel/stop_machine.c | |||
@@ -119,13 +119,12 @@ static int stop_machine(void) | |||
119 | return ret; | 119 | return ret; |
120 | } | 120 | } |
121 | 121 | ||
122 | /* Don't schedule us away at this point, please. */ | ||
123 | local_irq_disable(); | ||
124 | |||
125 | /* Now they are all started, make them hold the CPUs, ready. */ | 122 | /* Now they are all started, make them hold the CPUs, ready. */ |
123 | preempt_disable(); | ||
126 | stopmachine_set_state(STOPMACHINE_PREPARE); | 124 | stopmachine_set_state(STOPMACHINE_PREPARE); |
127 | 125 | ||
128 | /* Make them disable irqs. */ | 126 | /* Make them disable irqs. */ |
127 | local_irq_disable(); | ||
129 | stopmachine_set_state(STOPMACHINE_DISABLE_IRQ); | 128 | stopmachine_set_state(STOPMACHINE_DISABLE_IRQ); |
130 | 129 | ||
131 | return 0; | 130 | return 0; |
@@ -135,6 +134,7 @@ static void restart_machine(void) | |||
135 | { | 134 | { |
136 | stopmachine_set_state(STOPMACHINE_EXIT); | 135 | stopmachine_set_state(STOPMACHINE_EXIT); |
137 | local_irq_enable(); | 136 | local_irq_enable(); |
137 | preempt_enable_no_resched(); | ||
138 | } | 138 | } |
139 | 139 | ||
140 | struct stop_machine_data | 140 | struct stop_machine_data |