# HG changeset patch
# User Liu, Jinsong <jinsong.liu@xxxxxxxxx>
# Date 1299061866 0
# Node ID f71212f712fd8dad7997785fd61edca28c0d9536
# Parent 666006a3a4ad3e4015fa0610aae6ebda3d271523
x86: Fix cpu online/offline bug: mce memory leak.
Current Xen mce logic didn't free mcabanks. This would be a memory
leak when cpu offline. When repeatly do cpu online/offline, this
memory leak would make xenpool shrink, and at a time point, will call
alloc_heap_pages --> flush_area_mask, which
ASSERT(local_irq_is_enabled()). However, cpu online is irq disable,
so it finally result in Xen crash.
This patch fix the memory leak bug, and tested OK over 50,000 round
cpu online/offline.
Signed-off-by: Liu, Jinsong <jinsong.liu@xxxxxxxxx>
Signed-off-by: Keir Fraser <keir@xxxxxxx>
---
diff -r 666006a3a4ad -r f71212f712fd xen/arch/x86/cpu/mcheck/mce_intel.c
--- a/xen/arch/x86/cpu/mcheck/mce_intel.c Wed Mar 02 10:23:23 2011 +0000
+++ b/xen/arch/x86/cpu/mcheck/mce_intel.c Wed Mar 02 10:31:06 2011 +0000
@@ -1227,9 +1227,24 @@
mce_uhandler_num = sizeof(intel_mce_uhandlers)/sizeof(struct
mca_error_handler);
}
-static int intel_init_mca_banks(void)
+static void cpu_mcabank_free(unsigned int cpu)
{
- struct mca_banks *mb1, *mb2, * mb3;
+ struct mca_banks *mb1, *mb2, *mb3, *mb4;
+
+ mb1 = per_cpu(mce_clear_banks, cpu);
+ mb2 = per_cpu(no_cmci_banks, cpu);
+ mb3 = per_cpu(mce_banks_owned, cpu);
+ mb4 = per_cpu(poll_bankmask, cpu);
+
+ mcabanks_free(mb1);
+ mcabanks_free(mb2);
+ mcabanks_free(mb3);
+ mcabanks_free(mb4);
+}
+
+static int cpu_mcabank_alloc(unsigned int cpu)
+{
+ struct mca_banks *mb1, *mb2, *mb3;
mb1 = mcabanks_alloc();
mb2 = mcabanks_alloc();
@@ -1237,9 +1252,9 @@
if (!mb1 || !mb2 || !mb3)
goto out;
- __get_cpu_var(mce_clear_banks) = mb1;
- __get_cpu_var(no_cmci_banks) = mb2;
- __get_cpu_var(mce_banks_owned) = mb3;
+ per_cpu(mce_clear_banks, cpu) = mb1;
+ per_cpu(no_cmci_banks, cpu) = mb2;
+ per_cpu(mce_banks_owned, cpu) = mb3;
return 0;
out:
@@ -1249,11 +1264,46 @@
return -ENOMEM;
}
+static int cpu_callback(
+ struct notifier_block *nfb, unsigned long action, void *hcpu)
+{
+ unsigned int cpu = (unsigned long)hcpu;
+ int rc = 0;
+
+ switch ( action )
+ {
+ case CPU_UP_PREPARE:
+ rc = cpu_mcabank_alloc(cpu);
+ break;
+ case CPU_DYING:
+ cpu_mcheck_disable();
+ break;
+ case CPU_UP_CANCELED:
+ case CPU_DEAD:
+ cpu_mcheck_distribute_cmci();
+ cpu_mcabank_free(cpu);
+ break;
+ default:
+ break;
+ }
+
+ return !rc ? NOTIFY_DONE : notifier_from_errno(rc);
+}
+
+static struct notifier_block cpu_nfb = {
+ .notifier_call = cpu_callback
+};
+
/* p4/p6 family have similar MCA initialization process */
enum mcheck_type intel_mcheck_init(struct cpuinfo_x86 *c)
{
- if (intel_init_mca_banks())
- return mcheck_none;
+ if ( smp_processor_id() == 0 )
+ {
+ /* Early MCE initialisation for BSP. */
+ if ( cpu_mcabank_alloc(0) )
+ BUG();
+ register_cpu_notifier(&cpu_nfb);
+ }
intel_init_mca(c);
@@ -1298,31 +1348,3 @@
return ret;
}
-static int cpu_callback(
- struct notifier_block *nfb, unsigned long action, void *hcpu)
-{
- switch ( action )
- {
- case CPU_DYING:
- cpu_mcheck_disable();
- break;
- case CPU_DEAD:
- cpu_mcheck_distribute_cmci();
- break;
- default:
- break;
- }
-
- return NOTIFY_DONE;
-}
-
-static struct notifier_block cpu_nfb = {
- .notifier_call = cpu_callback
-};
-
-static int __init intel_mce_initcall(void)
-{
- register_cpu_notifier(&cpu_nfb);
- return 0;
-}
-presmp_initcall(intel_mce_initcall);
_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog
|