| From 21324ca6ada667f9a2392aa504b5040526296cb2 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Mon, 23 Aug 2021 17:31:29 -0700 |
| Subject: x86/mce: Defer processing of early errors |
| |
| From: Borislav Petkov <bp@alien8.de> |
| |
| [ 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.intel.com |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| 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 b7a27589dfa0..056d0367864e 100644 |
| --- a/arch/x86/kernel/cpu/mce/core.c |
| +++ b/arch/x86/kernel/cpu/mce/core.c |
| @@ -817,7 +817,10 @@ log_it: |
| 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: |
| /* |
| @@ -1628,10 +1631,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); |
| |
| -- |
| 2.30.2 |
| |