1 From: Gerald Schaefer <geraldsc@de.ibm.com>
2 Subject: kernel: smp_call_function races.
6 Problem: The s390 specific implementation of smp_call_function()
7 waits until all signalled cpus have started to execute
8 the function. This can cause deadlocks.
9 Solution: Replace the s390 speficic implementation with the generic
12 Acked-by: John Jolly <jjolly@suse.de>
15 arch/s390/include/asm/sigp.h | 1
16 arch/s390/include/asm/smp.h | 5 -
17 arch/s390/kernel/smp.c | 175 ++++---------------------------------------
18 4 files changed, 24 insertions(+), 158 deletions(-)
20 --- a/arch/s390/include/asm/sigp.h
21 +++ b/arch/s390/include/asm/sigp.h
22 @@ -61,6 +61,7 @@ typedef enum
26 + ec_call_function_single,
30 --- a/arch/s390/include/asm/smp.h
31 +++ b/arch/s390/include/asm/smp.h
32 @@ -91,8 +91,9 @@ extern int __cpu_up (unsigned int cpu);
33 extern struct mutex smp_cpu_state_mutex;
34 extern int smp_cpu_polarization[];
36 -extern int smp_call_function_mask(cpumask_t mask, void (*func)(void *),
37 - void *info, int wait);
38 +extern void arch_send_call_function_single_ipi(int cpu);
39 +extern void arch_send_call_function_ipi(cpumask_t mask);
44 --- a/arch/s390/Kconfig
45 +++ b/arch/s390/Kconfig
46 @@ -70,6 +70,7 @@ mainmenu "Linux Kernel Configuration"
50 + select USE_GENERIC_SMP_HELPERS if SMP
51 select HAVE_SYSCALL_WRAPPERS
54 --- a/arch/s390/kernel/smp.c
55 +++ b/arch/s390/kernel/smp.c
56 @@ -79,159 +79,6 @@ static DEFINE_PER_CPU(struct cpu, cpu_de
58 static void smp_ext_bitcall(int, ec_bit_sig);
61 - * Structure and data for __smp_call_function_map(). This is designed to
62 - * minimise static memory requirements. It also looks cleaner.
64 -static DEFINE_SPINLOCK(call_lock);
66 -struct call_data_struct {
67 - void (*func) (void *info);
74 -static struct call_data_struct *call_data;
77 - * 'Call function' interrupt callback
79 -static void do_call_function(void)
81 - void (*func) (void *info) = call_data->func;
82 - void *info = call_data->info;
83 - int wait = call_data->wait;
85 - cpu_set(smp_processor_id(), call_data->started);
88 - cpu_set(smp_processor_id(), call_data->finished);;
91 -static void __smp_call_function_map(void (*func) (void *info), void *info,
92 - int wait, cpumask_t map)
94 - struct call_data_struct data;
98 - * Can deadlock when interrupts are disabled or if in wrong context.
100 - WARN_ON(irqs_disabled() || in_irq());
103 - * Check for local function call. We have to have the same call order
104 - * as in on_each_cpu() because of machine_restart_smp().
106 - if (cpu_isset(smp_processor_id(), map)) {
108 - cpu_clear(smp_processor_id(), map);
111 - cpus_and(map, map, cpu_online_map);
112 - if (cpus_empty(map))
117 - data.started = CPU_MASK_NONE;
120 - data.finished = CPU_MASK_NONE;
124 - for_each_cpu_mask(cpu, map)
125 - smp_ext_bitcall(cpu, ec_call_function);
127 - /* Wait for response */
128 - while (!cpus_equal(map, data.started))
131 - while (!cpus_equal(map, data.finished))
135 - local_irq_disable();
137 - local_irq_enable();
142 - * smp_call_function:
143 - * @func: the function to run; this must be fast and non-blocking
144 - * @info: an arbitrary pointer to pass to the function
145 - * @wait: if true, wait (atomically) until function has completed on other CPUs
147 - * Run a function on all other CPUs.
149 - * You must not call this function with disabled interrupts, from a
150 - * hardware interrupt handler or from a bottom half.
152 -int smp_call_function(void (*func) (void *info), void *info, int wait)
156 - spin_lock(&call_lock);
157 - map = cpu_online_map;
158 - cpu_clear(smp_processor_id(), map);
159 - __smp_call_function_map(func, info, wait, map);
160 - spin_unlock(&call_lock);
163 -EXPORT_SYMBOL(smp_call_function);
166 - * smp_call_function_single:
167 - * @cpu: the CPU where func should run
168 - * @func: the function to run; this must be fast and non-blocking
169 - * @info: an arbitrary pointer to pass to the function
170 - * @wait: if true, wait (atomically) until function has completed on other CPUs
172 - * Run a function on one processor.
174 - * You must not call this function with disabled interrupts, from a
175 - * hardware interrupt handler or from a bottom half.
177 -int smp_call_function_single(int cpu, void (*func) (void *info), void *info,
180 - spin_lock(&call_lock);
181 - __smp_call_function_map(func, info, wait, cpumask_of_cpu(cpu));
182 - spin_unlock(&call_lock);
185 -EXPORT_SYMBOL(smp_call_function_single);
188 - * smp_call_function_mask(): Run a function on a set of other CPUs.
189 - * @mask: The set of cpus to run on. Must not include the current cpu.
190 - * @func: The function to run. This must be fast and non-blocking.
191 - * @info: An arbitrary pointer to pass to the function.
192 - * @wait: If true, wait (atomically) until function has completed on other CPUs.
194 - * Returns 0 on success, else a negative status code.
196 - * If @wait is true, then returns once @func has returned; otherwise
197 - * it returns just before the target cpu calls @func.
199 - * You must not call this function with disabled interrupts or from a
200 - * hardware interrupt handler or from a bottom half handler.
202 -int smp_call_function_mask(cpumask_t mask, void (*func)(void *), void *info,
205 - spin_lock(&call_lock);
206 - cpu_clear(smp_processor_id(), mask);
207 - __smp_call_function_map(func, info, wait, mask);
208 - spin_unlock(&call_lock);
211 -EXPORT_SYMBOL(smp_call_function_mask);
213 void smp_send_stop(void)
216 @@ -273,7 +120,10 @@ static void do_ext_call_interrupt(__u16
217 bits = xchg(&S390_lowcore.ext_call_fast, 0);
219 if (test_bit(ec_call_function, &bits))
220 - do_call_function();
221 + generic_smp_call_function_interrupt();
223 + if (test_bit(ec_call_function_single, &bits))
224 + generic_smp_call_function_single_interrupt();
228 @@ -290,6 +140,19 @@ static void smp_ext_bitcall(int cpu, ec_
232 +void arch_send_call_function_ipi(cpumask_t mask)
236 + for_each_cpu_mask(cpu, mask)
237 + smp_ext_bitcall(cpu, ec_call_function);
240 +void arch_send_call_function_single_ipi(int cpu)
242 + smp_ext_bitcall(cpu, ec_call_function_single);
247 * this function sends a 'purge tlb' signal to another CPU.
248 @@ -588,9 +451,9 @@ int __cpuinit start_secondary(void *cpuv
251 /* Mark this cpu as online */
252 - spin_lock(&call_lock);
254 cpu_set(smp_processor_id(), cpu_online_map);
255 - spin_unlock(&call_lock);
257 /* Switch on interrupts */
259 /* Print info about this processor */