diff options
author | Liu, Jinsong <jinsong.liu@intel.com> | 2011-03-02 10:31:06 +0000 |
---|---|---|
committer | Liu, Jinsong <jinsong.liu@intel.com> | 2011-03-02 10:31:06 +0000 |
commit | 67a93c8da5b99374ec02dbbc14a70e01ffdab20c (patch) | |
tree | 2d3d9fc9eb3ba83a2dc91c4df9eae7ba51189c7b | |
parent | 4947f9bdc80526a936a9a90e97c535f8b5b0431a (diff) | |
download | xen-67a93c8da5b99374ec02dbbc14a70e01ffdab20c.tar.gz xen-67a93c8da5b99374ec02dbbc14a70e01ffdab20c.tar.bz2 xen-67a93c8da5b99374ec02dbbc14a70e01ffdab20c.zip |
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@intel.com>
Signed-off-by: Keir Fraser <keir@xen.org>
-rw-r--r-- | xen/arch/x86/cpu/mcheck/mce_intel.c | 92 |
1 files changed, 57 insertions, 35 deletions
diff --git a/xen/arch/x86/cpu/mcheck/mce_intel.c b/xen/arch/x86/cpu/mcheck/mce_intel.c index b306b23ecc..2da2ffb881 100644 --- a/xen/arch/x86/cpu/mcheck/mce_intel.c +++ b/xen/arch/x86/cpu/mcheck/mce_intel.c @@ -1227,9 +1227,24 @@ static void intel_init_mce(void) 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 @@ static int intel_init_mca_banks(void) 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 @@ out: 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 @@ int intel_mce_rdmsr(uint32_t msr, uint64_t *val) 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); |