diff options
author | Zhang, Yanmin <yanmin_zhang@linux.intel.com> | 2008-06-24 04:06:23 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-06-30 07:15:43 -0400 |
commit | fcb43042ef55d2f46b0efa5d7746967cef38f056 (patch) | |
tree | 21aa270c236fe572c377eb16337d77be8e5d4362 | |
parent | 0b1faeef5f9243bb5fc5713a34bbf1ceab0de562 (diff) |
x86: fix cpu hotplug crash
Vegard Nossum reported crashes during cpu hotplug tests:
http://marc.info/?l=linux-kernel&m=121413950227884&w=4
In function _cpu_up, the panic happens when calling
__raw_notifier_call_chain at the second time. Kernel doesn't panic when
calling it at the first time. If just say because of nr_cpu_ids, that's
not right.
By checking the source code, I found that function do_boot_cpu is the culprit.
Consider below call chain:
_cpu_up=>__cpu_up=>smp_ops.cpu_up=>native_cpu_up=>do_boot_cpu.
So do_boot_cpu is called in the end. In do_boot_cpu, if
boot_error==true, cpu_clear(cpu, cpu_possible_map) is executed. So later
on, when _cpu_up calls __raw_notifier_call_chain at the second time to
report CPU_UP_CANCELED, because this cpu is already cleared from
cpu_possible_map, get_cpu_sysdev returns NULL.
Many resources are related to cpu_possible_map, so it's better not to
change it.
Below patch against 2.6.26-rc7 fixes it by removing the bit clearing in
cpu_possible_map.
Signed-off-by: Zhang Yanmin <yanmin_zhang@linux.intel.com>
Tested-by: Vegard Nossum <vegard.nossum@gmail.com>
Acked-by: Rusty Russell <rusty@rustcorp.com.au>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/smpboot.c | 1 |
1 files changed, 0 insertions, 1 deletions
diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c index 56078d61c793..3e1cecedde42 100644 --- a/arch/x86/kernel/smpboot.c +++ b/arch/x86/kernel/smpboot.c | |||
@@ -996,7 +996,6 @@ do_rest: | |||
996 | #endif | 996 | #endif |
997 | cpu_clear(cpu, cpu_callout_map); /* was set by do_boot_cpu() */ | 997 | cpu_clear(cpu, cpu_callout_map); /* was set by do_boot_cpu() */ |
998 | cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */ | 998 | cpu_clear(cpu, cpu_initialized); /* was set by cpu_init() */ |
999 | cpu_clear(cpu, cpu_possible_map); | ||
1000 | cpu_clear(cpu, cpu_present_map); | 999 | cpu_clear(cpu, cpu_present_map); |
1001 | per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID; | 1000 | per_cpu(x86_cpu_to_apicid, cpu) = BAD_APICID; |
1002 | } | 1001 | } |