]> git.proxmox.com Git - mirror_ubuntu-jammy-kernel.git/commitdiff
x86/mce: Send #MC singal from task work
authorPeter Zijlstra <peterz@infradead.org>
Wed, 19 Feb 2020 09:22:06 +0000 (10:22 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Tue, 19 May 2020 13:51:19 +0000 (15:51 +0200)
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
arch/x86/kernel/cpu/mce/core.c
include/linux/sched.h

index 98bf91cd7d5d3111180589077b1b6332b9fd5e30..2f0ef95795f3a303291003c5cfbce2fbc60b38d5 100644 (file)
@@ -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, &current->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 @@ out_ist:
        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)
index 9437b53cc603dde340951e0c6c2b3245c631d2d7..57d0ed061ae40a952a0f5aa193ff76840f062c83 100644 (file)
@@ -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.