Skip to content

Commit 5567d11

Browse files
Peter ZijlstraKAGA-KOKO
authored andcommitted
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) <[email protected]> Signed-off-by: Thomas Gleixner <[email protected]> Reviewed-by: Frederic Weisbecker <[email protected]> Reviewed-by: Alexandre Chartre <[email protected]> Link: https://lkml.kernel.org/r/[email protected]
1 parent b052df3 commit 5567d11

File tree

2 files changed

+37
-25
lines changed

2 files changed

+37
-25
lines changed

arch/x86/kernel/cpu/mce/core.c

Lines changed: 31 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,7 @@
4242
#include <linux/export.h>
4343
#include <linux/jump_label.h>
4444
#include <linux/set_memory.h>
45+
#include <linux/task_work.h>
4546

4647
#include <asm/intel-family.h>
4748
#include <asm/processor.h>
@@ -1086,23 +1087,6 @@ static void mce_clear_state(unsigned long *toclear)
10861087
}
10871088
}
10881089

1089-
static int do_memory_failure(struct mce *m)
1090-
{
1091-
int flags = MF_ACTION_REQUIRED;
1092-
int ret;
1093-
1094-
pr_err("Uncorrected hardware memory error in user-access at %llx", m->addr);
1095-
if (!(m->mcgstatus & MCG_STATUS_RIPV))
1096-
flags |= MF_MUST_KILL;
1097-
ret = memory_failure(m->addr >> PAGE_SHIFT, flags);
1098-
if (ret)
1099-
pr_err("Memory error not recovered");
1100-
else
1101-
set_mce_nospec(m->addr >> PAGE_SHIFT);
1102-
return ret;
1103-
}
1104-
1105-
11061090
/*
11071091
* Cases where we avoid rendezvous handler timeout:
11081092
* 1) If this CPU is offline.
@@ -1204,6 +1188,29 @@ static void __mc_scan_banks(struct mce *m, struct mce *final,
12041188
*m = *final;
12051189
}
12061190

1191+
static void kill_me_now(struct callback_head *ch)
1192+
{
1193+
force_sig(SIGBUS);
1194+
}
1195+
1196+
static void kill_me_maybe(struct callback_head *cb)
1197+
{
1198+
struct task_struct *p = container_of(cb, struct task_struct, mce_kill_me);
1199+
int flags = MF_ACTION_REQUIRED;
1200+
1201+
pr_err("Uncorrected hardware memory error in user-access at %llx", p->mce_addr);
1202+
if (!(p->mce_status & MCG_STATUS_RIPV))
1203+
flags |= MF_MUST_KILL;
1204+
1205+
if (!memory_failure(p->mce_addr >> PAGE_SHIFT, flags)) {
1206+
set_mce_nospec(p->mce_addr >> PAGE_SHIFT);
1207+
return;
1208+
}
1209+
1210+
pr_err("Memory error not recovered");
1211+
kill_me_now(cb);
1212+
}
1213+
12071214
/*
12081215
* The actual machine check handler. This only handles real
12091216
* 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,
12221229
* backing the user stack, tracing that reads the user stack will cause
12231230
* potentially infinite recursion.
12241231
*/
1225-
void notrace do_machine_check(struct pt_regs *regs, long error_code)
1232+
void noinstr do_machine_check(struct pt_regs *regs, long error_code)
12261233
{
12271234
DECLARE_BITMAP(valid_banks, MAX_NR_BANKS);
12281235
DECLARE_BITMAP(toclear, MAX_NR_BANKS);
@@ -1354,13 +1361,13 @@ void notrace do_machine_check(struct pt_regs *regs, long error_code)
13541361
if ((m.cs & 3) == 3) {
13551362
/* If this triggers there is no way to recover. Die hard. */
13561363
BUG_ON(!on_thread_stack() || !user_mode(regs));
1357-
local_irq_enable();
1358-
preempt_enable();
13591364

1360-
if (kill_it || do_memory_failure(&m))
1361-
force_sig(SIGBUS);
1362-
preempt_disable();
1363-
local_irq_disable();
1365+
current->mce_addr = m.addr;
1366+
current->mce_status = m.mcgstatus;
1367+
current->mce_kill_me.func = kill_me_maybe;
1368+
if (kill_it)
1369+
current->mce_kill_me.func = kill_me_now;
1370+
task_work_add(current, &current->mce_kill_me, true);
13641371
} else {
13651372
if (!fixup_exception(regs, X86_TRAP_MC, error_code, 0))
13661373
mce_panic("Failed kernel mode recovery", &m, msg);
@@ -1370,7 +1377,6 @@ void notrace do_machine_check(struct pt_regs *regs, long error_code)
13701377
ist_exit(regs);
13711378
}
13721379
EXPORT_SYMBOL_GPL(do_machine_check);
1373-
NOKPROBE_SYMBOL(do_machine_check);
13741380

13751381
#ifndef CONFIG_MEMORY_FAILURE
13761382
int memory_failure(unsigned long pfn, int flags)

include/linux/sched.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,6 +1297,12 @@ struct task_struct {
12971297
unsigned long prev_lowest_stack;
12981298
#endif
12991299

1300+
#ifdef CONFIG_X86_MCE
1301+
u64 mce_addr;
1302+
u64 mce_status;
1303+
struct callback_head mce_kill_me;
1304+
#endif
1305+
13001306
/*
13011307
* New fields for task_struct should be added above here, so that
13021308
* they are included in the randomized portion of task_struct.

0 commit comments

Comments
 (0)