s390/unwind: stop gracefully at user mode pt_regs in irq stack
authorVasily Gorbik <gor@linux.ibm.com>
Wed, 11 Dec 2019 16:27:31 +0000 (17:27 +0100)
committerVasily Gorbik <gor@linux.ibm.com>
Wed, 18 Dec 2019 22:29:26 +0000 (23:29 +0100)
Consider reaching user mode pt_regs at the bottom of irq stack graceful
unwinder termination. This is the case when irq/mcck/ext interrupt arrives
while in user mode.

Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
arch/s390/kernel/unwind_bc.c

index da2d4d4c5b0e0252186df8d985cf3dafa7fb6994..707fd99f6734d86ca1f037887f6be085b7366a3c 100644 (file)
@@ -36,10 +36,17 @@ static bool update_stack_info(struct unwind_state *state, unsigned long sp)
        return true;
 }
 
-static inline bool is_task_pt_regs(struct unwind_state *state,
-                                  struct pt_regs *regs)
+static inline bool is_final_pt_regs(struct unwind_state *state,
+                                   struct pt_regs *regs)
 {
-       return task_pt_regs(state->task) == regs;
+       /* user mode or kernel thread pt_regs at the bottom of task stack */
+       if (task_pt_regs(state->task) == regs)
+               return true;
+
+       /* user mode pt_regs at the bottom of irq stack */
+       return state->stack_info.type == STACK_TYPE_IRQ &&
+              state->stack_info.end - sizeof(struct pt_regs) == (unsigned long)regs &&
+              READ_ONCE_NOCHECK(regs->psw.mask) & PSW_MASK_PSTATE;
 }
 
 bool unwind_next_frame(struct unwind_state *state)
@@ -80,7 +87,7 @@ bool unwind_next_frame(struct unwind_state *state)
                        if (!on_stack(info, sp, sizeof(struct pt_regs)))
                                goto out_err;
                        regs = (struct pt_regs *) sp;
-                       if (is_task_pt_regs(state, regs))
+                       if (is_final_pt_regs(state, regs))
                                goto out_stop;
                        ip = READ_ONCE_NOCHECK(regs->psw.addr);
                        sp = READ_ONCE_NOCHECK(regs->gprs[15]);