| From foo@baz Wed Dec 6 18:04:41 CET 2017 |
| From: Jibin Xu <jibin.xu@windriver.com> |
| Date: Sun, 10 Sep 2017 20:11:42 -0700 |
| Subject: sysrq : fix Show Regs call trace on ARM |
| |
| From: Jibin Xu <jibin.xu@windriver.com> |
| |
| |
| [ Upstream commit b00bebbc301c8e1f74f230dc82282e56b7e7a6db ] |
| |
| When kernel configuration SMP,PREEMPT and DEBUG_PREEMPT are enabled, |
| echo 1 >/proc/sys/kernel/sysrq |
| echo p >/proc/sysrq-trigger |
| kernel will print call trace as below: |
| |
| sysrq: SysRq : Show Regs |
| BUG: using __this_cpu_read() in preemptible [00000000] code: sh/435 |
| caller is __this_cpu_preempt_check+0x18/0x20 |
| Call trace: |
| [<ffffff8008088e80>] dump_backtrace+0x0/0x1d0 |
| [<ffffff8008089074>] show_stack+0x24/0x30 |
| [<ffffff8008447970>] dump_stack+0x90/0xb0 |
| [<ffffff8008463950>] check_preemption_disabled+0x100/0x108 |
| [<ffffff8008463998>] __this_cpu_preempt_check+0x18/0x20 |
| [<ffffff80084c9194>] sysrq_handle_showregs+0x1c/0x40 |
| [<ffffff80084c9c7c>] __handle_sysrq+0x12c/0x1a0 |
| [<ffffff80084ca140>] write_sysrq_trigger+0x60/0x70 |
| [<ffffff8008251e00>] proc_reg_write+0x90/0xd0 |
| [<ffffff80081f1788>] __vfs_write+0x48/0x90 |
| [<ffffff80081f241c>] vfs_write+0xa4/0x190 |
| [<ffffff80081f3354>] SyS_write+0x54/0xb0 |
| [<ffffff80080833f0>] el0_svc_naked+0x24/0x28 |
| |
| This can be seen on a common board like an r-pi3. |
| This happens because when echo p >/proc/sysrq-trigger, |
| get_irq_regs() is called outside of IRQ context, |
| if preemption is enabled in this situation,kernel will |
| print the call trace. Since many prior discussions on |
| the mailing lists have made it clear that get_irq_regs |
| either just returns NULL or stale data when used outside |
| of IRQ context,we simply avoid calling it outside of |
| IRQ context. |
| |
| Signed-off-by: Jibin Xu <jibin.xu@windriver.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sasha Levin <alexander.levin@verizon.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/tty/sysrq.c | 9 +++++++-- |
| 1 file changed, 7 insertions(+), 2 deletions(-) |
| |
| --- a/drivers/tty/sysrq.c |
| +++ b/drivers/tty/sysrq.c |
| @@ -246,8 +246,10 @@ static void sysrq_handle_showallcpus(int |
| * architecture has no support for it: |
| */ |
| if (!trigger_all_cpu_backtrace()) { |
| - struct pt_regs *regs = get_irq_regs(); |
| + struct pt_regs *regs = NULL; |
| |
| + if (in_irq()) |
| + regs = get_irq_regs(); |
| if (regs) { |
| pr_info("CPU%d:\n", smp_processor_id()); |
| show_regs(regs); |
| @@ -266,7 +268,10 @@ static struct sysrq_key_op sysrq_showall |
| |
| static void sysrq_handle_showregs(int key) |
| { |
| - struct pt_regs *regs = get_irq_regs(); |
| + struct pt_regs *regs = NULL; |
| + |
| + if (in_irq()) |
| + regs = get_irq_regs(); |
| if (regs) |
| show_regs(regs); |
| perf_event_print_debug(); |