Skip to content

Commit ad3ca81

Browse files
Vasily Gorbikgregkh
authored andcommitted
s390/ftrace: Avoid calling unwinder in ftrace_return_address()
commit a84dd0d upstream. ftrace_return_address() is called extremely often from performance-critical code paths when debugging features like CONFIG_TRACE_IRQFLAGS are enabled. For example, with debug_defconfig, ftrace selftests on my LPAR currently execute ftrace_return_address() as follows: ftrace_return_address(0) - 0 times (common code uses __builtin_return_address(0) instead) ftrace_return_address(1) - 2,986,805,401 times (with this patch applied) ftrace_return_address(2) - 140 times ftrace_return_address(>2) - 0 times The use of __builtin_return_address(n) was replaced by return_address() with an unwinder call by commit cae74ba ("s390/ftrace: Use unwinder instead of __builtin_return_address()") because __builtin_return_address(n) simply walks the stack backchain and doesn't check for reaching the stack top. For shallow stacks with fewer than "n" frames, this results in reads at low addresses and random memory accesses. While calling the fully functional unwinder "works", it is very slow for this purpose. Moreover, potentially following stack switches and walking past IRQ context is simply wrong thing to do for ftrace_return_address(). Reimplement return_address() to essentially be __builtin_return_address(n) with checks for reaching the stack top. Since the ftrace_return_address(n) argument is always a constant, keep the implementation in the header, allowing both GCC and Clang to unroll the loop and optimize it to the bare minimum. Fixes: cae74ba ("s390/ftrace: Use unwinder instead of __builtin_return_address()") Cc: [email protected] Reported-by: Sumanth Korikkar <[email protected]> Reviewed-by: Heiko Carstens <[email protected]> Acked-by: Sumanth Korikkar <[email protected]> Signed-off-by: Vasily Gorbik <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent b5dc3ef commit ad3ca81

2 files changed

Lines changed: 16 additions & 20 deletions

File tree

arch/s390/include/asm/ftrace.h

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,23 @@
66
#define MCOUNT_INSN_SIZE 6
77

88
#ifndef __ASSEMBLY__
9+
#include <asm/stacktrace.h>
910

10-
unsigned long return_address(unsigned int n);
11+
static __always_inline unsigned long return_address(unsigned int n)
12+
{
13+
struct stack_frame *sf;
14+
15+
if (!n)
16+
return (unsigned long)__builtin_return_address(0);
17+
18+
sf = (struct stack_frame *)current_frame_address();
19+
do {
20+
sf = (struct stack_frame *)sf->back_chain;
21+
if (!sf)
22+
return 0;
23+
} while (--n);
24+
return sf->gprs[8];
25+
}
1126
#define ftrace_return_address(n) return_address(n)
1227

1328
void ftrace_caller(void);

arch/s390/kernel/stacktrace.c

Lines changed: 0 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -162,22 +162,3 @@ void arch_stack_walk_user(stack_trace_consume_fn consume_entry, void *cookie,
162162
{
163163
arch_stack_walk_user_common(consume_entry, cookie, NULL, regs, false);
164164
}
165-
166-
unsigned long return_address(unsigned int n)
167-
{
168-
struct unwind_state state;
169-
unsigned long addr;
170-
171-
/* Increment to skip current stack entry */
172-
n++;
173-
174-
unwind_for_each_frame(&state, NULL, NULL, 0) {
175-
addr = unwind_get_return_address(&state);
176-
if (!addr)
177-
break;
178-
if (!n--)
179-
return addr;
180-
}
181-
return 0;
182-
}
183-
EXPORT_SYMBOL_GPL(return_address);

0 commit comments

Comments
 (0)