提交 a8c321fb 编写于 作者: T Tony Luck

x86/mce: Handle "action required" errors

All non-urgent actions (reporting low severity errors and handling
"action-optional" errors) are now handled by a work queue. This
means that TIF_MCE_NOTIFY can be used to block execution for a
thread experiencing an "action-required" fault until we get all
cpus out of the machine check handler (and the thread that hit
the fault into mce_notify_process().

We use the new mce_{save,find,clear}_info() API to get information
from do_machine_check() to mce_notify_process(), and then use the
newly improved memory_failure(..., MF_ACTION_REQUIRED) to handle
the error (possibly signalling the process).

Update some comments to make the new code flows clearer.
Signed-off-by: NTony Luck <tony.luck@intel.com>
上级 af104e39
...@@ -982,7 +982,9 @@ void do_machine_check(struct pt_regs *regs, long error_code) ...@@ -982,7 +982,9 @@ void do_machine_check(struct pt_regs *regs, long error_code)
barrier(); barrier();
/* /*
* When no restart IP must always kill or panic. * When no restart IP might need to kill or panic.
* Assume the worst for now, but if we find the
* severity is MCE_AR_SEVERITY we have other options.
*/ */
if (!(m.mcgstatus & MCG_STATUS_RIPV)) if (!(m.mcgstatus & MCG_STATUS_RIPV))
kill_it = 1; kill_it = 1;
...@@ -1036,12 +1038,6 @@ void do_machine_check(struct pt_regs *regs, long error_code) ...@@ -1036,12 +1038,6 @@ void do_machine_check(struct pt_regs *regs, long error_code)
continue; continue;
} }
/*
* Kill on action required.
*/
if (severity == MCE_AR_SEVERITY)
kill_it = 1;
mce_read_aux(&m, i); mce_read_aux(&m, i);
/* /*
...@@ -1062,6 +1058,9 @@ void do_machine_check(struct pt_regs *regs, long error_code) ...@@ -1062,6 +1058,9 @@ void do_machine_check(struct pt_regs *regs, long error_code)
} }
} }
/* mce_clear_state will clear *final, save locally for use later */
m = *final;
if (!no_way_out) if (!no_way_out)
mce_clear_state(toclear); mce_clear_state(toclear);
...@@ -1073,27 +1072,22 @@ void do_machine_check(struct pt_regs *regs, long error_code) ...@@ -1073,27 +1072,22 @@ void do_machine_check(struct pt_regs *regs, long error_code)
no_way_out = worst >= MCE_PANIC_SEVERITY; no_way_out = worst >= MCE_PANIC_SEVERITY;
/* /*
* If we have decided that we just CAN'T continue, and the user * At insane "tolerant" levels we take no action. Otherwise
* has not set tolerant to an insane level, give up and die. * we only die if we have no other choice. For less serious
* * issues we try to recover, or limit damage to the current
* This is mainly used in the case when the system doesn't * process.
* support MCE broadcasting or it has been disabled.
*/ */
if (no_way_out && tolerant < 3) if (tolerant < 3) {
mce_panic("Fatal machine check on current CPU", final, msg); if (no_way_out)
mce_panic("Fatal machine check on current CPU", &m, msg);
/* if (worst == MCE_AR_SEVERITY) {
* If the error seems to be unrecoverable, something should be /* schedule action before return to userland */
* done. Try to kill as little as possible. If we can kill just mce_save_info(m.addr);
* one task, do that. If the user has set the tolerance very set_thread_flag(TIF_MCE_NOTIFY);
* high, don't try to do anything at all. } else if (kill_it) {
*/ force_sig(SIGBUS, current);
}
if (kill_it && tolerant < 3) }
force_sig(SIGBUS, current);
/* notify userspace ASAP */
set_thread_flag(TIF_MCE_NOTIFY);
if (worst > 0) if (worst > 0)
mce_report_event(regs); mce_report_event(regs);
...@@ -1107,6 +1101,8 @@ EXPORT_SYMBOL_GPL(do_machine_check); ...@@ -1107,6 +1101,8 @@ EXPORT_SYMBOL_GPL(do_machine_check);
#ifndef CONFIG_MEMORY_FAILURE #ifndef CONFIG_MEMORY_FAILURE
int memory_failure(unsigned long pfn, int vector, int flags) int memory_failure(unsigned long pfn, int vector, int flags)
{ {
/* mce_severity() should not hand us an ACTION_REQUIRED error */
BUG_ON(flags & MF_ACTION_REQUIRED);
printk(KERN_ERR "Uncorrected memory error in page 0x%lx ignored\n" printk(KERN_ERR "Uncorrected memory error in page 0x%lx ignored\n"
"Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n", pfn); "Rebuild kernel with CONFIG_MEMORY_FAILURE=y for smarter handling\n", pfn);
...@@ -1115,27 +1111,44 @@ int memory_failure(unsigned long pfn, int vector, int flags) ...@@ -1115,27 +1111,44 @@ int memory_failure(unsigned long pfn, int vector, int flags)
#endif #endif
/* /*
* Called after mce notification in process context. This code * Called in process context that interrupted by MCE and marked with
* is allowed to sleep. Call the high level VM handler to process * TIF_MCE_NOTIFY, just before returning to erroneous userland.
* any corrupted pages. * This code is allowed to sleep.
* Assume that the work queue code only calls this one at a time * Attempt possible recovery such as calling the high level VM handler to
* per CPU. * process any corrupted pages, and kill/signal current process if required.
* Note we don't disable preemption, so this code might run on the wrong * Action required errors are handled here.
* CPU. In this case the event is picked up by the scheduled work queue.
* This is merely a fast path to expedite processing in some common
* cases.
*/ */
void mce_notify_process(void) void mce_notify_process(void)
{ {
unsigned long pfn; unsigned long pfn;
mce_notify_irq(); struct mce_info *mi = mce_find_info();
while (mce_ring_get(&pfn))
memory_failure(pfn, MCE_VECTOR, 0); if (!mi)
mce_panic("Lost physical address for unconsumed uncorrectable error", NULL, NULL);
pfn = mi->paddr >> PAGE_SHIFT;
clear_thread_flag(TIF_MCE_NOTIFY);
pr_err("Uncorrected hardware memory error in user-access at %llx",
mi->paddr);
if (memory_failure(pfn, MCE_VECTOR, MF_ACTION_REQUIRED) < 0) {
pr_err("Memory error not recovered");
force_sig(SIGBUS, current);
}
mce_clear_info(mi);
} }
/*
* Action optional processing happens here (picking up
* from the list of faulting pages that do_machine_check()
* placed into the "ring").
*/
static void mce_process_work(struct work_struct *dummy) static void mce_process_work(struct work_struct *dummy)
{ {
mce_notify_process(); unsigned long pfn;
while (mce_ring_get(&pfn))
memory_failure(pfn, MCE_VECTOR, 0);
} }
#ifdef CONFIG_X86_MCE_INTEL #ifdef CONFIG_X86_MCE_INTEL
...@@ -1225,8 +1238,6 @@ int mce_notify_irq(void) ...@@ -1225,8 +1238,6 @@ int mce_notify_irq(void)
/* Not more than two messages every minute */ /* Not more than two messages every minute */
static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2); static DEFINE_RATELIMIT_STATE(ratelimit, 60*HZ, 2);
clear_thread_flag(TIF_MCE_NOTIFY);
if (test_and_clear_bit(0, &mce_need_notify)) { if (test_and_clear_bit(0, &mce_need_notify)) {
/* wake processes polling /dev/mcelog */ /* wake processes polling /dev/mcelog */
wake_up_interruptible(&mce_chrdev_wait); wake_up_interruptible(&mce_chrdev_wait);
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册