diff options
author | Vasily Gorbik <gor@linux.ibm.com> | 2019-11-22 20:22:06 +0300 |
---|---|---|
committer | Vasily Gorbik <gor@linux.ibm.com> | 2019-11-30 12:52:47 +0300 |
commit | 7868249fbbc8125b82b83d99d33b23897ae7d9ab (patch) | |
tree | 1168e658e094e7ee81d017d0a477f38f4f5a72a4 /arch | |
parent | 4ac24c092b4eef69b2436ee4d478500dc886e8b5 (diff) | |
download | linux-7868249fbbc8125b82b83d99d33b23897ae7d9ab.tar.xz |
s390/test_unwind: add CALL_ON_STACK tests
Add CALL_ON_STACK helper testing. Tests make sure that we can unwind from
switched stack to original one up to task pt_regs (nodat -> task stack).
UWM_SWITCH_STACK could not be used together with UWM_THREAD because
get_stack_info explicitly restricts unwinding to task stack if
task != current.
Reviewed-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Vasily Gorbik <gor@linux.ibm.com>
Diffstat (limited to 'arch')
-rw-r--r-- | arch/s390/lib/test_unwind.c | 26 |
1 files changed, 19 insertions, 7 deletions
diff --git a/arch/s390/lib/test_unwind.c b/arch/s390/lib/test_unwind.c index 2839f8cb691d..687a6922beda 100644 --- a/arch/s390/lib/test_unwind.c +++ b/arch/s390/lib/test_unwind.c @@ -43,7 +43,7 @@ static noinline int test_unwind(struct task_struct *task, struct pt_regs *regs, int ret = 0; char *bt; - bt = kmalloc(BT_BUF_SIZE, GFP_KERNEL); + bt = kmalloc(BT_BUF_SIZE, GFP_ATOMIC); if (!bt) { pr_err("failed to allocate backtrace buffer\n"); return -ENOMEM; @@ -98,11 +98,12 @@ struct unwindme { }; /* Values of unwindme.flags. */ -#define UWM_DEFAULT 0x0 -#define UWM_THREAD 0x1 /* Unwind a separate task. */ -#define UWM_REGS 0x2 /* Pass regs to test_unwind(). */ -#define UWM_SP 0x4 /* Pass sp to test_unwind(). */ -#define UWM_CALLER 0x8 /* Unwind starting from caller. */ +#define UWM_DEFAULT 0x0 +#define UWM_THREAD 0x1 /* Unwind a separate task. */ +#define UWM_REGS 0x2 /* Pass regs to test_unwind(). */ +#define UWM_SP 0x4 /* Pass sp to test_unwind(). */ +#define UWM_CALLER 0x8 /* Unwind starting from caller. */ +#define UWM_SWITCH_STACK 0x10 /* Use CALL_ON_STACK. */ static __always_inline unsigned long get_psw_addr(void) { @@ -146,7 +147,16 @@ static noinline int unwindme_func3(struct unwindme *u) /* This function must appear in the backtrace. */ static noinline int unwindme_func2(struct unwindme *u) { - return unwindme_func3(u); + int rc; + + if (u->flags & UWM_SWITCH_STACK) { + preempt_disable(); + rc = CALL_ON_STACK(unwindme_func3, S390_lowcore.nodat_stack, 1, u); + preempt_enable(); + return rc; + } else { + return unwindme_func3(u); + } } /* This function must follow unwindme_func2 in the backtrace. */ @@ -215,9 +225,11 @@ do { \ TEST(UWM_DEFAULT); TEST(UWM_SP); TEST(UWM_REGS); + TEST(UWM_SWITCH_STACK); TEST(UWM_SP | UWM_REGS); TEST(UWM_CALLER | UWM_SP); TEST(UWM_CALLER | UWM_SP | UWM_REGS); + TEST(UWM_CALLER | UWM_SP | UWM_REGS | UWM_SWITCH_STACK); TEST(UWM_THREAD); TEST(UWM_THREAD | UWM_SP); TEST(UWM_THREAD | UWM_CALLER | UWM_SP); |