forked from mirrors/linux
		
	x86/mce: Send #MC singal from task work
Convert #MC over to using task_work_add(); it will run the same code slightly later, on the return to user path of the same exception. Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Reviewed-by: Frederic Weisbecker <frederic@kernel.org> Reviewed-by: Alexandre Chartre <alexandre.chartre@oracle.com> Link: https://lkml.kernel.org/r/20200505134100.957390899@linutronix.de
This commit is contained in:
		
							parent
							
								
									b052df3da8
								
							
						
					
					
						commit
						5567d11c21
					
				
					 2 changed files with 37 additions and 25 deletions
				
			
		| 
						 | 
				
			
			@ -42,6 +42,7 @@
 | 
			
		|||
#include <linux/export.h>
 | 
			
		||||
#include <linux/jump_label.h>
 | 
			
		||||
#include <linux/set_memory.h>
 | 
			
		||||
#include <linux/task_work.h>
 | 
			
		||||
 | 
			
		||||
#include <asm/intel-family.h>
 | 
			
		||||
#include <asm/processor.h>
 | 
			
		||||
| 
						 | 
				
			
			@ -1086,23 +1087,6 @@ static void mce_clear_state(unsigned long *toclear)
 | 
			
		|||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static int do_memory_failure(struct mce *m)
 | 
			
		||||
{
 | 
			
		||||
	int flags = MF_ACTION_REQUIRED;
 | 
			
		||||
	int ret;
 | 
			
		||||
 | 
			
		||||
	pr_err("Uncorrected hardware memory error in user-access at %llx", m->addr);
 | 
			
		||||
	if (!(m->mcgstatus & MCG_STATUS_RIPV))
 | 
			
		||||
		flags |= MF_MUST_KILL;
 | 
			
		||||
	ret = memory_failure(m->addr >> PAGE_SHIFT, flags);
 | 
			
		||||
	if (ret)
 | 
			
		||||
		pr_err("Memory error not recovered");
 | 
			
		||||
	else
 | 
			
		||||
		set_mce_nospec(m->addr >> PAGE_SHIFT);
 | 
			
		||||
	return ret;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * Cases where we avoid rendezvous handler timeout:
 | 
			
		||||
 * 1) If this CPU is offline.
 | 
			
		||||
| 
						 | 
				
			
			@ -1204,6 +1188,29 @@ static void __mc_scan_banks(struct mce *m, struct mce *final,
 | 
			
		|||
	*m = *final;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void kill_me_now(struct callback_head *ch)
 | 
			
		||||
{
 | 
			
		||||
	force_sig(SIGBUS);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
static void kill_me_maybe(struct callback_head *cb)
 | 
			
		||||
{
 | 
			
		||||
	struct task_struct *p = container_of(cb, struct task_struct, mce_kill_me);
 | 
			
		||||
	int flags = MF_ACTION_REQUIRED;
 | 
			
		||||
 | 
			
		||||
	pr_err("Uncorrected hardware memory error in user-access at %llx", p->mce_addr);
 | 
			
		||||
	if (!(p->mce_status & MCG_STATUS_RIPV))
 | 
			
		||||
		flags |= MF_MUST_KILL;
 | 
			
		||||
 | 
			
		||||
	if (!memory_failure(p->mce_addr >> PAGE_SHIFT, flags)) {
 | 
			
		||||
		set_mce_nospec(p->mce_addr >> PAGE_SHIFT);
 | 
			
		||||
		return;
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	pr_err("Memory error not recovered");
 | 
			
		||||
	kill_me_now(cb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/*
 | 
			
		||||
 * The actual machine check handler. This only handles real
 | 
			
		||||
 * exceptions when something got corrupted coming in through int 18.
 | 
			
		||||
| 
						 | 
				
			
			@ -1222,7 +1229,7 @@ static void __mc_scan_banks(struct mce *m, struct mce *final,
 | 
			
		|||
 * backing the user stack, tracing that reads the user stack will cause
 | 
			
		||||
 * potentially infinite recursion.
 | 
			
		||||
 */
 | 
			
		||||
void notrace do_machine_check(struct pt_regs *regs, long error_code)
 | 
			
		||||
void noinstr do_machine_check(struct pt_regs *regs, long error_code)
 | 
			
		||||
{
 | 
			
		||||
	DECLARE_BITMAP(valid_banks, MAX_NR_BANKS);
 | 
			
		||||
	DECLARE_BITMAP(toclear, MAX_NR_BANKS);
 | 
			
		||||
| 
						 | 
				
			
			@ -1354,13 +1361,13 @@ void notrace do_machine_check(struct pt_regs *regs, long error_code)
 | 
			
		|||
	if ((m.cs & 3) == 3) {
 | 
			
		||||
		/* If this triggers there is no way to recover. Die hard. */
 | 
			
		||||
		BUG_ON(!on_thread_stack() || !user_mode(regs));
 | 
			
		||||
		local_irq_enable();
 | 
			
		||||
		preempt_enable();
 | 
			
		||||
 | 
			
		||||
		if (kill_it || do_memory_failure(&m))
 | 
			
		||||
			force_sig(SIGBUS);
 | 
			
		||||
		preempt_disable();
 | 
			
		||||
		local_irq_disable();
 | 
			
		||||
		current->mce_addr = m.addr;
 | 
			
		||||
		current->mce_status = m.mcgstatus;
 | 
			
		||||
		current->mce_kill_me.func = kill_me_maybe;
 | 
			
		||||
		if (kill_it)
 | 
			
		||||
			current->mce_kill_me.func = kill_me_now;
 | 
			
		||||
		task_work_add(current, ¤t->mce_kill_me, true);
 | 
			
		||||
	} else {
 | 
			
		||||
		if (!fixup_exception(regs, X86_TRAP_MC, error_code, 0))
 | 
			
		||||
			mce_panic("Failed kernel mode recovery", &m, msg);
 | 
			
		||||
| 
						 | 
				
			
			@ -1370,7 +1377,6 @@ void notrace do_machine_check(struct pt_regs *regs, long error_code)
 | 
			
		|||
	ist_exit(regs);
 | 
			
		||||
}
 | 
			
		||||
EXPORT_SYMBOL_GPL(do_machine_check);
 | 
			
		||||
NOKPROBE_SYMBOL(do_machine_check);
 | 
			
		||||
 | 
			
		||||
#ifndef CONFIG_MEMORY_FAILURE
 | 
			
		||||
int memory_failure(unsigned long pfn, int flags)
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
| 
						 | 
				
			
			@ -1297,6 +1297,12 @@ struct task_struct {
 | 
			
		|||
	unsigned long			prev_lowest_stack;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
#ifdef CONFIG_X86_MCE
 | 
			
		||||
	u64				mce_addr;
 | 
			
		||||
	u64				mce_status;
 | 
			
		||||
	struct callback_head		mce_kill_me;
 | 
			
		||||
#endif
 | 
			
		||||
 | 
			
		||||
	/*
 | 
			
		||||
	 * New fields for task_struct should be added above here, so that
 | 
			
		||||
	 * they are included in the randomized portion of task_struct.
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in a new issue