From: Borislav Petkov bp@alien8.de
stable inclusion from stable-5.10.65 commit c0aec70a256ce63fc53345851988c142c826db62 bugzilla: 182361 https://gitee.com/openeuler/kernel/issues/I4EH3U
Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=...
--------------------------------
[ Upstream commit 3bff147b187d5dfccfca1ee231b0761a89f1eff5 ]
When a fatal machine check results in a system reset, Linux does not clear the error(s) from machine check bank(s) - hardware preserves the machine check banks across a warm reset.
During initialization of the kernel after the reboot, Linux reads, logs, and clears all machine check banks.
But there is a problem. In:
5de97c9f6d85 ("x86/mce: Factor out and deprecate the /dev/mcelog driver")
the call to mce_register_decode_chain() moved later in the boot sequence. This means that /dev/mcelog doesn't see those early error logs.
This was partially fixed by:
cd9c57cad3fe ("x86/MCE: Dump MCE to dmesg if no consumers")
which made sure that the logs were not lost completely by printing to the console. But parsing console logs is error prone. Users of /dev/mcelog should expect to find any early errors logged to standard places.
Add a new flag MCP_QUEUE_LOG to machine_check_poll() to be used in early machine check initialization to indicate that any errors found should just be queued to genpool. When mcheck_late_init() is called it will call mce_schedule_work() to actually log and flush any errors queued in the genpool.
[ Based on an original patch, commit message by and completely productized by Tony Luck. ]
Fixes: 5de97c9f6d85 ("x86/mce: Factor out and deprecate the /dev/mcelog driver") Reported-by: Sumanth Kamatala skamatala@juniper.net Signed-off-by: Borislav Petkov bp@suse.de Signed-off-by: Tony Luck tony.luck@intel.com Signed-off-by: Borislav Petkov bp@suse.de Link: https://lkml.kernel.org/r/20210824003129.GA1642753@agluck-desk2.amr.corp.int... Signed-off-by: Sasha Levin sashal@kernel.org Signed-off-by: Chen Jun chenjun102@huawei.com Acked-by: Weilong Chen chenweilong@huawei.com
Signed-off-by: Chen Jun chenjun102@huawei.com --- arch/x86/include/asm/mce.h | 1 + arch/x86/kernel/cpu/mce/core.c | 11 ++++++++--- 2 files changed, 9 insertions(+), 3 deletions(-)
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h index fc25c88c7ff2..9b5ff423e939 100644 --- a/arch/x86/include/asm/mce.h +++ b/arch/x86/include/asm/mce.h @@ -259,6 +259,7 @@ enum mcp_flags { MCP_TIMESTAMP = BIT(0), /* log time stamp */ MCP_UC = BIT(1), /* log uncorrected errors */ MCP_DONTLOG = BIT(2), /* only clear, don't log */ + MCP_QUEUE_LOG = BIT(3), /* only queue to genpool */ }; bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b);
diff --git a/arch/x86/kernel/cpu/mce/core.c b/arch/x86/kernel/cpu/mce/core.c index aca6ab19726f..f4d6b15944a0 100644 --- a/arch/x86/kernel/cpu/mce/core.c +++ b/arch/x86/kernel/cpu/mce/core.c @@ -819,7 +819,10 @@ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b) if (mca_cfg.dont_log_ce && !mce_usable_address(&m)) goto clear_it;
- mce_log(&m); + if (flags & MCP_QUEUE_LOG) + mce_gen_pool_add(&m); + else + mce_log(&m);
clear_it: /* @@ -1632,10 +1635,12 @@ static void __mcheck_cpu_init_generic(void) m_fl = MCP_DONTLOG;
/* - * Log the machine checks left over from the previous reset. + * Log the machine checks left over from the previous reset. Log them + * only, do not start processing them. That will happen in mcheck_late_init() + * when all consumers have been registered on the notifier chain. */ bitmap_fill(all_banks, MAX_NR_BANKS); - machine_check_poll(MCP_UC | m_fl, &all_banks); + machine_check_poll(MCP_UC | MCP_QUEUE_LOG | m_fl, &all_banks);
cr4_set_bits(X86_CR4_MCE);