diff options
-rw-r--r-- | kernel/smp.c | 13 |
1 files changed, 10 insertions, 3 deletions
diff --git a/kernel/smp.c b/kernel/smp.c index 7c6ded5effd9..954548906afb 100644 --- a/kernel/smp.c +++ b/kernel/smp.c | |||
@@ -450,7 +450,7 @@ void smp_call_function_many(const struct cpumask *mask, | |||
450 | { | 450 | { |
451 | struct call_function_data *data; | 451 | struct call_function_data *data; |
452 | unsigned long flags; | 452 | unsigned long flags; |
453 | int cpu, next_cpu, this_cpu = smp_processor_id(); | 453 | int refs, cpu, next_cpu, this_cpu = smp_processor_id(); |
454 | 454 | ||
455 | /* | 455 | /* |
456 | * Can deadlock when called with interrupts disabled. | 456 | * Can deadlock when called with interrupts disabled. |
@@ -461,7 +461,7 @@ void smp_call_function_many(const struct cpumask *mask, | |||
461 | WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() | 461 | WARN_ON_ONCE(cpu_online(this_cpu) && irqs_disabled() |
462 | && !oops_in_progress && !early_boot_irqs_disabled); | 462 | && !oops_in_progress && !early_boot_irqs_disabled); |
463 | 463 | ||
464 | /* So, what's a CPU they want? Ignoring this one. */ | 464 | /* Try to fastpath. So, what's a CPU they want? Ignoring this one. */ |
465 | cpu = cpumask_first_and(mask, cpu_online_mask); | 465 | cpu = cpumask_first_and(mask, cpu_online_mask); |
466 | if (cpu == this_cpu) | 466 | if (cpu == this_cpu) |
467 | cpu = cpumask_next_and(cpu, mask, cpu_online_mask); | 467 | cpu = cpumask_next_and(cpu, mask, cpu_online_mask); |
@@ -519,6 +519,13 @@ void smp_call_function_many(const struct cpumask *mask, | |||
519 | /* We rely on the "and" being processed before the store */ | 519 | /* We rely on the "and" being processed before the store */ |
520 | cpumask_and(data->cpumask, mask, cpu_online_mask); | 520 | cpumask_and(data->cpumask, mask, cpu_online_mask); |
521 | cpumask_clear_cpu(this_cpu, data->cpumask); | 521 | cpumask_clear_cpu(this_cpu, data->cpumask); |
522 | refs = cpumask_weight(data->cpumask); | ||
523 | |||
524 | /* Some callers race with other cpus changing the passed mask */ | ||
525 | if (unlikely(!refs)) { | ||
526 | csd_unlock(&data->csd); | ||
527 | return; | ||
528 | } | ||
522 | 529 | ||
523 | raw_spin_lock_irqsave(&call_function.lock, flags); | 530 | raw_spin_lock_irqsave(&call_function.lock, flags); |
524 | /* | 531 | /* |
@@ -532,7 +539,7 @@ void smp_call_function_many(const struct cpumask *mask, | |||
532 | * to the cpumask before this write to refs, which indicates | 539 | * to the cpumask before this write to refs, which indicates |
533 | * data is on the list and is ready to be processed. | 540 | * data is on the list and is ready to be processed. |
534 | */ | 541 | */ |
535 | atomic_set(&data->refs, cpumask_weight(data->cpumask)); | 542 | atomic_set(&data->refs, refs); |
536 | raw_spin_unlock_irqrestore(&call_function.lock, flags); | 543 | raw_spin_unlock_irqrestore(&call_function.lock, flags); |
537 | 544 | ||
538 | /* | 545 | /* |