]> git.karo-electronics.de Git - linux-beck.git/commitdiff
s390/ftrace: hotpatch support for function tracing
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Fri, 9 Jan 2015 12:08:28 +0000 (13:08 +0100)
committerMartin Schwidefsky <schwidefsky@de.ibm.com>
Thu, 29 Jan 2015 08:19:25 +0000 (09:19 +0100)
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>
arch/s390/Kconfig
arch/s390/Makefile
arch/s390/include/asm/ftrace.h
arch/s390/kernel/Makefile
arch/s390/kernel/ftrace.c
arch/s390/kernel/kprobes.c
arch/s390/kernel/mcount.S
scripts/recordmcount.pl

index 7eba5b5723e98614745f43c1258c7f76033eb5fd..8d11babf9aa505ff0a051d6017e4425a1c150636 100644 (file)
@@ -117,7 +117,6 @@ config S390
        select HAVE_BPF_JIT if 64BIT && PACK_STACK
        select HAVE_CMPXCHG_DOUBLE
        select HAVE_CMPXCHG_LOCAL
-       select HAVE_C_RECORDMCOUNT
        select HAVE_DEBUG_KMEMLEAK
        select HAVE_DYNAMIC_FTRACE if 64BIT
        select HAVE_DYNAMIC_FTRACE_WITH_REGS if 64BIT
index e742ec5de9a7e5217756151e6898e68179823edc..acb6859c6a95f4ea9e787f39e8131c093d8700f9 100644 (file)
@@ -87,6 +87,16 @@ ifeq ($(call cc-option-yn,-mwarn-dynamicstack),y)
 cflags-$(CONFIG_WARN_DYNAMIC_STACK) += -mwarn-dynamicstack
 endif
 
+ifdef CONFIG_FUNCTION_TRACER
+# make use of hotpatch feature if the compiler supports it
+cc_hotpatch    := -mhotpatch=0,3
+ifeq ($(call cc-option-yn,$(cc_hotpatch)),y)
+CC_FLAGS_FTRACE := $(cc_hotpatch)
+KBUILD_AFLAGS  += -DCC_USING_HOTPATCH
+KBUILD_CFLAGS  += -DCC_USING_HOTPATCH
+endif
+endif
+
 KBUILD_CFLAGS  += -mbackchain -msoft-float $(cflags-y)
 KBUILD_CFLAGS  += -pipe -fno-strength-reduce -Wno-sign-compare
 KBUILD_AFLAGS  += $(aflags-y)
index abb618f1ead25fcad51b90bc1cffd61ef8dde67b..836c56290499b84c0dad7785e9aa5979d68ed0bf 100644 (file)
@@ -3,8 +3,12 @@
 
 #define ARCH_SUPPORTS_FTRACE_OPS 1
 
+#ifdef CC_USING_HOTPATCH
+#define MCOUNT_INSN_SIZE       6
+#else
 #define MCOUNT_INSN_SIZE       24
 #define MCOUNT_RETURN_FIXUP    18
+#endif
 
 #ifndef __ASSEMBLY__
 
@@ -37,17 +41,28 @@ struct ftrace_insn {
 static inline void ftrace_generate_nop_insn(struct ftrace_insn *insn)
 {
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CC_USING_HOTPATCH
+       /* brcl 0,0 */
+       insn->opc = 0xc004;
+       insn->disp = 0;
+#else
        /* jg .+24 */
        insn->opc = 0xc0f4;
        insn->disp = MCOUNT_INSN_SIZE / 2;
 #endif
+#endif
 }
 
 static inline int is_ftrace_nop(struct ftrace_insn *insn)
 {
 #ifdef CONFIG_FUNCTION_TRACER
+#ifdef CC_USING_HOTPATCH
+       if (insn->disp == 0)
+               return 1;
+#else
        if (insn->disp == MCOUNT_INSN_SIZE / 2)
                return 1;
+#endif
 #endif
        return 0;
 }
index 204c43a4c245dd1835915adbbae39da494c2d947..31fab2676fe9216ab5e7338283b2c7004924e919 100644 (file)
@@ -4,8 +4,8 @@
 
 ifdef CONFIG_FUNCTION_TRACER
 # Don't trace early setup code and tracing code
-CFLAGS_REMOVE_early.o = -pg
-CFLAGS_REMOVE_ftrace.o = -pg
+CFLAGS_REMOVE_early.o = $(CC_FLAGS_FTRACE)
+CFLAGS_REMOVE_ftrace.o = $(CC_FLAGS_FTRACE)
 endif
 
 #
index 3dabcae40e0421457d4b6fee1aa05773920bec0c..82c19899574f83070158c09c5eed5b438bc092c1 100644 (file)
  *     lg      %r14,8(%r15)            # offset 18
  * The jg instruction branches to offset 24 to skip as many instructions
  * as possible.
+ * In case we use gcc's hotpatch feature the original and also the disabled
+ * function prologue contains only a single six byte instruction and looks
+ * like this:
+ * >   brcl    0,0                     # offset 0
+ * To enable ftrace the code gets patched like above and afterwards looks
+ * like this:
+ * >   brasl   %r0,ftrace_caller       # offset 0
  */
 
 unsigned long ftrace_plt;
@@ -64,9 +71,15 @@ int ftrace_make_nop(struct module *mod, struct dyn_ftrace *rec,
        if (probe_kernel_read(&old, (void *) rec->ip, sizeof(old)))
                return -EFAULT;
        if (addr == MCOUNT_ADDR) {
-               /* Initial code replacement; we expect to see stg r14,8(r15) */
+               /* Initial code replacement */
+#ifdef CC_USING_HOTPATCH
+               /* We expect to see brcl 0,0 */
+               ftrace_generate_nop_insn(&orig);
+#else
+               /* We expect to see stg r14,8(r15) */
                orig.opc = 0xe3e0;
                orig.disp = 0xf0080024;
+#endif
                ftrace_generate_nop_insn(&new);
        } else if (old.opc == BREAKPOINT_INSTRUCTION) {
                /*
index 1e4c710dfb9233dafa10a07fcb769b6028758a66..f516edc1fbe31a952839102db45ed9a1b71bdab7 100644 (file)
@@ -69,7 +69,8 @@ static void copy_instruction(struct kprobe *p)
                /*
                 * If kprobes patches the instruction that is morphed by
                 * ftrace make sure that kprobes always sees the branch
-                * "jg .+24" that skips the mcount block
+                * "jg .+24" that skips the mcount block or the "brcl 0,0"
+                * in case of hotpatch.
                 */
                ftrace_generate_nop_insn((struct ftrace_insn *)p->ainsn.insn);
                p->ainsn.is_ftrace_insn = 1;
index b6dfc5bfcb892227407302def2c35963f450cae0..e499370fbccb328561e6ef5ab0bfe35afb4a0b51 100644 (file)
@@ -27,7 +27,9 @@ ENTRY(ftrace_caller)
        .globl  ftrace_regs_caller
        .set    ftrace_regs_caller,ftrace_caller
        lgr     %r1,%r15
+#ifndef CC_USING_HOTPATCH
        aghi    %r0,MCOUNT_RETURN_FIXUP
+#endif
        aghi    %r15,-STACK_FRAME_SIZE
        stg     %r1,__SF_BACKCHAIN(%r15)
        stg     %r1,(STACK_PTREGS_GPRS+15*8)(%r15)
index 56ea99a12ab79c82e062b54cfd34d9a39ef6a867..be39be0abefca87defe8b562fa8f64860268a5f3 100755 (executable)
@@ -242,8 +242,13 @@ if ($arch eq "x86_64") {
     $cc .= " -m32";
 
 } elsif ($arch eq "s390" && $bits == 64) {
-    $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
-    $mcount_adjust = -14;
+    if ($cc =~ /-DCC_USING_HOTPATCH/) {
+       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*c0 04 00 00 00 00\\s*brcl\\s*0,[0-9a-f]+ <([^\+]*)>\$";
+       $mcount_adjust = 0;
+    } else {
+       $mcount_regex = "^\\s*([0-9a-fA-F]+):\\s*R_390_(PC|PLT)32DBL\\s+_mcount\\+0x2\$";
+       $mcount_adjust = -14;
+    }
     $alignment = 8;
     $type = ".quad";
     $ld .= " -m elf64_s390";