Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

s390/ftrace: hotpatch support for function tracing

Make use of gcc's hotpatch support to generate better code for ftrace
function tracing.
The generated code now contains only a six byte nop in each function
prologue instead of a 24 byte code block which will be runtime patched to
support function tracing.
With the new code generation the runtime overhead for supporting function
tracing is close to zero, while the original code did show a significant
performance impact.

Acked-by: Steven Rostedt <rostedt@goodmis.org>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>

authored by

Heiko Carstens and committed by
Martin Schwidefsky
e6d60b36 61f55214

+52 -7
-1
arch/s390/Kconfig
··· 117 117 select HAVE_BPF_JIT if 64BIT && PACK_STACK 118 118 select HAVE_CMPXCHG_DOUBLE 119 119 select HAVE_CMPXCHG_LOCAL 120 - select HAVE_C_RECORDMCOUNT 121 120 select HAVE_DEBUG_KMEMLEAK 122 121 select HAVE_DYNAMIC_FTRACE if 64BIT 123 122 select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT
+10
arch/s390/Makefile
··· 87 87 cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack 88 88 endif 89 89 90 + ifdef CONFIG_FUNCTION_TRACER 91 + # make use of hotpatch feature if the compiler supports it 92 + cc_hotpatch := -mhotpatch=0,3 93 + ifeq ($(call cc-option-yn,$(cc_hotpatch)),y) 94 + CC_FLAGS_FTRACE := $(cc_hotpatch) 95 + KBUILD_AFLAGS += -DCC_USING_HOTPATCH 96 + KBUILD_CFLAGS += -DCC_USING_HOTPATCH 97 + endif 98 + endif 99 + 90 100 KBUILD_CFLAGS += -mbackchain -msoft-float $(cflags-y) 91 101 KBUILD_CFLAGS += -pipe -fno-strength-reduce -Wno-sign-compare 92 102 KBUILD_AFLAGS += $(aflags-y)
+15
arch/s390/include/asm/ftrace.h
··· 3 3 4 4 #define ARCH_SUPPORTS_FTRACE_OPS 1 5 5 6 + #ifdef CC_USING_HOTPATCH 7 + #define MCOUNT_INSN_SIZE 6 8 + #else 6 9 #define MCOUNT_INSN_SIZE 24 7 10 #define MCOUNT_RETURN_FIXUP 18 11 + #endif 8 12 9 13 #ifndef __ASSEMBLY__ 10 14 ··· 41 37 static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn) 42 38 { 43 39 #ifdef CONFIG_FUNCTION_TRACER 40 + #ifdef CC_USING_HOTPATCH 41 + /* brcl 0,0 */ 42 + insn->opc = 0xc004; 43 + insn->disp = 0; 44 + #else 44 45 /* jg .+24 */ 45 46 insn->opc = 0xc0f4; 46 47 insn->disp = MCOUNT_INSN_SIZE / 2; 48 + #endif 47 49 #endif 48 50 } 49 51 50 52 static inline int is_ftrace_nop(struct ftrace_insn *insn) 51 53 { 52 54 #ifdef CONFIG_FUNCTION_TRACER 55 + #ifdef CC_USING_HOTPATCH 56 + if (insn->disp == 0) 57 + return 1; 58 + #else 53 59 if (insn->disp == MCOUNT_INSN_SIZE / 2) 54 60 return 1; 61 + #endif 55 62 #endif 56 63 return 0; 57 64 }
+2 -2
arch/s390/kernel/Makefile
··· 4 4 5 5 ifdef CONFIG_FUNCTION_TRACER 6 6 # Don't trace early setup code and tracing code 7 - CFLAGS_REMOVE_early.o = -pg 8 - CFLAGS_REMOVE_ftrace.o = -pg 7 + CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE) 8 + CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE) 9 9 endif 10 10 11 11 #
+14 -1
arch/s390/kernel/ftrace.c
··· 46 46 * lg %r14,8(%r15) # offset 18 47 47 * The jg instruction branches to offset 24 to skip as many instructions 48 48 * as possible. 49 + * In case we use gcc's hotpatch feature the original and also the disabled 50 + * function prologue contains only a single six byte instruction and looks 51 + * like this: 52 + * > brcl 0,0 # offset 0 53 + * To enable ftrace the code gets patched like above and afterwards looks 54 + * like this: 55 + * > brasl %r0,ftrace_caller # offset 0 49 56 */ 50 57 51 58 unsigned long ftrace_plt; ··· 71 64 if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old))) 72 65 return -EFAULT; 73 66 if (addr == MCOUNT_ADDR) { 74 - /* Initial code replacement; we expect to see stg r14,8(r15) */ 67 + /* Initial code replacement */ 68 + #ifdef CC_USING_HOTPATCH 69 + /* We expect to see brcl 0,0 */ 70 + ftrace_generate_nop_insn(&orig); 71 + #else 72 + /* We expect to see stg r14,8(r15) */ 75 73 orig.opc = 0xe3e0; 76 74 orig.disp = 0xf0080024; 75 + #endif 77 76 ftrace_generate_nop_insn(&new); 78 77 } else if (old.opc == BREAKPOINT_INSTRUCTION) { 79 78 /*
+2 -1
arch/s390/kernel/kprobes.c
··· 69 69 /* 70 70 * If kprobes patches the instruction that is morphed by 71 71 * ftrace make sure that kprobes always sees the branch 72 - * "jg .+24" that skips the mcount block 72 + * "jg .+24" that skips the mcount block or the "brcl 0,0" 73 + * in case of hotpatch. 73 74 */ 74 75 ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn); 75 76 p->ainsn.is_ftrace_insn = 1;
+2
arch/s390/kernel/mcount.S
··· 27 27 .globl ftrace_regs_caller 28 28 .set ftrace_regs_caller,ftrace_caller 29 29 lgr %r1,%r15 30 + #ifndef CC_USING_HOTPATCH 30 31 aghi %r0,MCOUNT_RETURN_FIXUP 32 + #endif 31 33 aghi %r15,-STACK_FRAME_SIZE 32 34 stg %r1,__SF_BACKCHAIN(%r15) 33 35 stg %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
+7 -2
scripts/recordmcount.pl
··· 242 242 $cc .= " -m32"; 243 243 244 244 } elsif ($arch eq "s390" && $bits == 64) { 245 - $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$"; 246 - $mcount_adjust = -14; 245 + if ($cc =~ /-DCC_USING_HOTPATCH/) { 246 + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*brcl\\s*0,[0-9a-f]+ <([^\+]*)>\$"; 247 + $mcount_adjust = 0; 248 + } else { 249 + $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$"; 250 + $mcount_adjust = -14; 251 + } 247 252 $alignment = 8; 248 253 $type = ".quad"; 249 254 $ld .= " -m elf64_s390";