lkml.org 
[lkml]   [2020]   [Dec]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.9 005/175] ARC: stack unwinding: dont assume non-current task is sleeping
    Date
    From: Vineet Gupta <vgupta@synopsys.com>

    [ Upstream commit e42404fa10fd11fe72d0a0e149a321d10e577715 ]

    To start stack unwinding (SP, PC and BLINK) are needed. When the
    explicit execution context (pt_regs etc) is not available, unwinder
    assumes the task is sleeping (in __switch_to()) and fetches SP and BLINK
    from kernel mode stack.

    But this assumption is not true, specially in a SMP system, when top
    runs on 1 core, there may be active running processes on all cores.

    So when unwinding non courrent tasks, ensure they are NOT running.

    And while at it, handle the self unwinding case explicitly.

    This came out of investigation of a customer reported hang with
    rcutorture+top

    Link: https://github.com/foss-for-synopsys-dwc-arc-processors/linux/issues/31
    Signed-off-by: Vineet Gupta <vgupta@synopsys.com>
    Signed-off-by: Sasha Levin <sashal@kernel.org>
    ---
    arch/arc/kernel/stacktrace.c | 23 +++++++++++++++--------
    1 file changed, 15 insertions(+), 8 deletions(-)

    diff --git a/arch/arc/kernel/stacktrace.c b/arch/arc/kernel/stacktrace.c
    index 165158735aa6b..3ee19b1e79be5 100644
    --- a/arch/arc/kernel/stacktrace.c
    +++ b/arch/arc/kernel/stacktrace.c
    @@ -39,15 +39,15 @@

    #ifdef CONFIG_ARC_DW2_UNWIND

    -static void seed_unwind_frame_info(struct task_struct *tsk,
    - struct pt_regs *regs,
    - struct unwind_frame_info *frame_info)
    +static int
    +seed_unwind_frame_info(struct task_struct *tsk, struct pt_regs *regs,
    + struct unwind_frame_info *frame_info)
    {
    /*
    * synchronous unwinding (e.g. dump_stack)
    * - uses current values of SP and friends
    */
    - if (tsk == NULL && regs == NULL) {
    + if (regs == NULL && (tsk == NULL || tsk == current)) {
    unsigned long fp, sp, blink, ret;
    frame_info->task = current;

    @@ -66,11 +66,15 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
    frame_info->call_frame = 0;
    } else if (regs == NULL) {
    /*
    - * Asynchronous unwinding of sleeping task
    - * - Gets SP etc from task's pt_regs (saved bottom of kernel
    - * mode stack of task)
    + * Asynchronous unwinding of a likely sleeping task
    + * - first ensure it is actually sleeping
    + * - if so, it will be in __switch_to, kernel mode SP of task
    + * is safe-kept and BLINK at a well known location in there
    */

    + if (tsk->state == TASK_RUNNING)
    + return -1;
    +
    frame_info->task = tsk;

    frame_info->regs.r27 = TSK_K_FP(tsk);
    @@ -104,6 +108,8 @@ static void seed_unwind_frame_info(struct task_struct *tsk,
    frame_info->regs.r63 = regs->ret;
    frame_info->call_frame = 0;
    }
    +
    + return 0;
    }

    #endif
    @@ -117,7 +123,8 @@ arc_unwind_core(struct task_struct *tsk, struct pt_regs *regs,
    unsigned int address;
    struct unwind_frame_info frame_info;

    - seed_unwind_frame_info(tsk, regs, &frame_info);
    + if (seed_unwind_frame_info(tsk, regs, &frame_info))
    + return 0;

    while (1) {
    address = UNW_PC(&frame_info);
    --
    2.27.0


    \
     
     \ /
      Last update: 2020-12-28 17:41    [W:4.081 / U:0.036 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site