lkml.org 
[lkml]   [2020]   [May]   [5]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[patch V4 part 1 29/36] x86/mce: Send #MC singal from task work
    From: Peter Zijlstra <peterz@infradead.org>

    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>
    ---
    arch/x86/kernel/cpu/mce/core.c | 56 ++++++++++++++++++++++-------------------
    include/linux/sched.h | 6 ++++
    2 files changed, 37 insertions(+), 25 deletions(-)

    --- a/arch/x86/kernel/cpu/mce/core.c
    +++ b/arch/x86/kernel/cpu/mce/core.c
    @@ -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 lon
    }
    }

    -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 = *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 *
    * 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_
    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 @@ void notrace do_machine_check(struct pt_
    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)
    --- a/include/linux/sched.h
    +++ b/include/linux/sched.h
    @@ -1290,6 +1290,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.
    \
     
     \ /
      Last update: 2020-05-05 16:14    [W:4.253 / U:0.932 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site