The patch titled generic-ipi: fix the race between generic_smp_call_function_*() and hotplug_cfd() has been added to the -mm tree. Its filename is generic-ipi-fix-the-race-between-generic_smp_call_function_-and-hotplug_cfd.patch Before you just go and hit "reply", please: a) Consider who else should be cc'ed b) Prefer to cc a suitable mailing list as well c) Ideally: find the original patch on the mailing list and do a reply-to-all to that, adding suitable additional cc's *** Remember to use Documentation/SubmitChecklist when testing your code *** See http://userweb.kernel.org/~akpm/stuff/added-to-mm.txt to find out what to do about this The current -mm tree may be found at http://userweb.kernel.org/~akpm/mmotm/ ------------------------------------------------------ Subject: generic-ipi: fix the race between generic_smp_call_function_*() and hotplug_cfd() From: Xiao Guangrong <xiaoguangrong@xxxxxxxxxxxxxx> There is a race between generic_smp_call_function_*() and hotplug_cfd() in many cases, see below examples: 1: hotplug_cfd() can free cfd->cpumask, the system will crash if the cpu's cfd still in the call_function list: CPU A: CPU B smp_call_function_many() ...... cpu_down() ...... hotplug_cfd() -> ...... free_cpumask_var(cfd->cpumask) (receive function IPI interrupte) /* read cfd->cpumask */ generic_smp_call_function_interrupt() -> cpumask_test_and_clear_cpu(cpu, data->cpumask) CRASH!!! 2: It's not handle call_function list when cpu down, It's will lead to dead-wait if other path is waiting this cpu to execute function CPU A: CPU B smp_call_function_many(wait=0) ...... CPU B down smp_call_function_many() --> (cpu down before recevie function csd_lock(&data->csd); IPI interrupte) DEAD-WAIT!!!! So, CPU A will dead-wait in csd_lock(), the same as smp_call_function_single() Signed-off-by: Xiao Guangrong <xiaoguangrong@xxxxxxxxxxxxxx> Cc: Ingo Molnar <mingo@xxxxxxx> Cc: Jens Axboe <jens.axboe@xxxxxxxxxx> Cc: Nick Piggin <nickpiggin@xxxxxxxxxxxx> Cc: Peter Zijlstra <peterz@xxxxxxxxxxxxx> Cc: Rusty Russell <rusty@xxxxxxxxxxxxxxx> Signed-off-by: Andrew Morton <akpm@xxxxxxxxxxxxxxxxxxxx> --- kernel/smp.c | 38 ++++++++++++++++++++++++++++---------- 1 file changed, 28 insertions(+), 10 deletions(-) diff -puN kernel/smp.c~generic-ipi-fix-the-race-between-generic_smp_call_function_-and-hotplug_cfd kernel/smp.c --- a/kernel/smp.c~generic-ipi-fix-the-race-between-generic_smp_call_function_-and-hotplug_cfd +++ a/kernel/smp.c @@ -113,14 +113,10 @@ void generic_exec_single(int cpu, struct csd_lock_wait(data); } -/* - * Invoked by arch to handle an IPI for call function. Must be called with - * interrupts disabled. - */ -void generic_smp_call_function_interrupt(void) +static void +__generic_smp_call_function_interrupt(int cpu, int run_callbacks) { struct call_function_data *data; - int cpu = smp_processor_id(); /* * Ensure entry is visible on call_function_queue after we have @@ -159,12 +155,18 @@ void generic_smp_call_function_interrupt } /* - * Invoked by arch to handle an IPI for call function single. Must be - * called from the arch with interrupts disabled. + * Invoked by arch to handle an IPI for call function. Must be called with + * interrupts disabled. */ -void generic_smp_call_function_single_interrupt(void) +void generic_smp_call_function_interrupt(void) +{ + __generic_smp_call_function_interrupt(smp_processor_id(), 1); +} + +static void +__generic_smp_call_function_single_interrupt(int cpu, int run_callbacks) { - struct call_single_queue *q = &__get_cpu_var(call_single_queue); + struct call_single_queue *q = &per_cpu(call_single_queue, cpu); unsigned int data_flags; LIST_HEAD(list); @@ -195,6 +197,15 @@ void generic_smp_call_function_single_in } } +/* + * Invoked by arch to handle an IPI for call function single. Must be + * called from the arch with interrupts disabled. + */ +void generic_smp_call_function_single_interrupt(void) +{ + __generic_smp_call_function_single_interrupt(smp_processor_id(), 1); +} + static DEFINE_PER_CPU(struct call_single_data, csd_data); /* @@ -443,6 +454,7 @@ static int hotplug_cfd(struct notifier_block *nfb, unsigned long action, void *hcpu) { long cpu = (long)hcpu; + unsigned long flags; struct call_function_data *cfd = &per_cpu(cfd_data, cpu); switch (action) { @@ -459,6 +471,12 @@ hotplug_cfd(struct notifier_block *nfb, case CPU_DEAD: case CPU_DEAD_FROZEN: + local_irq_save(flags); + __generic_smp_call_function_interrupt(cpu, 0); + __generic_smp_call_function_single_interrupt(cpu, 0); + local_irq_restore(flags); + + csd_lock_wait(&cfd->csd); free_cpumask_var(cfd->cpumask); break; #endif _ Patches currently in -mm which might be from xiaoguangrong@xxxxxxxxxxxxxx are generic-ipi-fix-hotplug_cfd.patch generic-ipi-make-struct-call_function_data-lockless.patch generic-ipi-make-struct-call_function_data-lockless-cleanup.patch generic-ipi-cleanup-for-generic_smp_call_function_interrupt.patch kernel-smpc-relocate-some-code.patch generic-ipi-fix-the-race-between-generic_smp_call_function_-and-hotplug_cfd.patch generic-ipi-fix-the-race-between-generic_smp_call_function_-and-hotplug_cfd-fix.patch -- To unsubscribe from this list: send the line "unsubscribe mm-commits" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html