diff options
Diffstat (limited to 'kernel/smp.c')
| -rw-r--r-- | kernel/smp.c | 13 | 
1 files changed, 12 insertions, 1 deletions
| diff --git a/kernel/smp.c b/kernel/smp.c index 29dd40a9f2f4..69f38bd98b42 100644 --- a/kernel/smp.c +++ b/kernel/smp.c @@ -33,6 +33,7 @@ struct call_function_data {  	struct call_single_data	csd;  	atomic_t		refs;  	cpumask_var_t		cpumask; +	cpumask_var_t		cpumask_ipi;  };  static DEFINE_PER_CPU_SHARED_ALIGNED(struct call_function_data, cfd_data); @@ -56,6 +57,9 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)  		if (!zalloc_cpumask_var_node(&cfd->cpumask, GFP_KERNEL,  				cpu_to_node(cpu)))  			return notifier_from_errno(-ENOMEM); +		if (!zalloc_cpumask_var_node(&cfd->cpumask_ipi, GFP_KERNEL, +				cpu_to_node(cpu))) +			return notifier_from_errno(-ENOMEM);  		break;  #ifdef CONFIG_HOTPLUG_CPU @@ -65,6 +69,7 @@ hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu)  	case CPU_DEAD:  	case CPU_DEAD_FROZEN:  		free_cpumask_var(cfd->cpumask); +		free_cpumask_var(cfd->cpumask_ipi);  		break;  #endif  	}; @@ -526,6 +531,12 @@ void smp_call_function_many(const struct cpumask *mask,  		return;  	} +	/* +	 * After we put an entry into the list, data->cpumask +	 * may be cleared again when another CPU sends another IPI for +	 * a SMP function call, so data->cpumask will be zero. +	 */ +	cpumask_copy(data->cpumask_ipi, data->cpumask);  	raw_spin_lock_irqsave(&call_function.lock, flags);  	/*  	 * Place entry at the _HEAD_ of the list, so that any cpu still @@ -549,7 +560,7 @@ void smp_call_function_many(const struct cpumask *mask,  	smp_mb();  	/* Send a message to all CPUs in the map */ -	arch_send_call_function_ipi_mask(data->cpumask); +	arch_send_call_function_ipi_mask(data->cpumask_ipi);  	/* Optionally wait for the CPUs to complete */  	if (wait) | 
