Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit d3fdaed9 authored by Hugh Dickins's avatar Hugh Dickins Committed by Paul Mackerras
Browse files

[POWERPC] Fix smp_call_function to be preempt-safe



smp_call_function_map() was not safe against preemption to another
cpu: its test for removing self from map was outside the spinlock.
Rearrange it a little to fix that.

smp_call_function_single() was also wrong: now get_cpu() before
excluding self, as other architectures do.

Signed-off-by: default avatarHugh Dickins <hugh@veritas.com>
Signed-off-by: default avatarPaul Mackerras <paulus@samba.org>
parent d2579053
Loading
Loading
Loading
Loading
+18 −16
Original line number Diff line number Diff line
@@ -201,13 +201,6 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic,
	/* Can deadlock when called with interrupts disabled */
	WARN_ON(irqs_disabled());

	/* remove 'self' from the map */
	if (cpu_isset(smp_processor_id(), map))
		cpu_clear(smp_processor_id(), map);

	/* sanity check the map, remove any non-online processors. */
	cpus_and(map, map, cpu_online_map);

	if (unlikely(smp_ops == NULL))
		return ret;

@@ -222,10 +215,17 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic,
	/* Must grab online cpu count with preempt disabled, otherwise
	 * it can change. */
	num_cpus = num_online_cpus() - 1;
	if (!num_cpus || cpus_empty(map)) {
		ret = 0;
		goto out;
	}
	if (!num_cpus)
		goto done;

	/* remove 'self' from the map */
	if (cpu_isset(smp_processor_id(), map))
		cpu_clear(smp_processor_id(), map);

	/* sanity check the map, remove any non-online processors. */
	cpus_and(map, map, cpu_online_map);
	if (cpus_empty(map))
		goto done;

	call_data = &data;
	smp_wmb();
@@ -263,6 +263,7 @@ int smp_call_function_map(void (*func) (void *info), void *info, int nonatomic,
		}
	}

 done:
	ret = 0;

 out:
@@ -283,15 +284,16 @@ int smp_call_function_single(int cpu, void (*func) (void *info), void *info, int
			int wait)
{
	cpumask_t map = CPU_MASK_NONE;
	int ret = -EBUSY;

	if (!cpu_online(cpu))
		return -EINVAL;

	if (cpu == smp_processor_id())
		return -EBUSY;

	cpu_set(cpu, map);
	return smp_call_function_map(func,info,nonatomic,wait,map);
	if (cpu != get_cpu())
		ret = smp_call_function_map(func,info,nonatomic,wait,map);
	put_cpu();
	return ret;
}
EXPORT_SYMBOL(smp_call_function_single);