Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt...
authorIngo Molnar <mingo@kernel.org>
Wed, 20 Feb 2013 10:26:21 +0000 (11:26 +0100)
committerIngo Molnar <mingo@kernel.org>
Wed, 20 Feb 2013 10:26:21 +0000 (11:26 +0100)
Pull two fixes from Steven Rostedt.

Signed-off-by: Ingo Molnar <mingo@kernel.org>
arch/x86/include/asm/ftrace.h
arch/x86/include/asm/thread_info.h
kernel/trace/ftrace.c
kernel/trace/trace_syscalls.c

index 86cb51e1ca96abc11dda6317293a775aebbdf51e..0525a8bdf65d6421cd602286283575d559f41fe1 100644 (file)
@@ -72,4 +72,28 @@ int ftrace_int3_handler(struct pt_regs *regs);
 #endif /* __ASSEMBLY__ */
 #endif /* CONFIG_FUNCTION_TRACER */
 
+
+#if !defined(__ASSEMBLY__) && !defined(COMPILE_OFFSETS)
+
+#if defined(CONFIG_FTRACE_SYSCALLS) && defined(CONFIG_IA32_EMULATION)
+#include <asm/compat.h>
+
+/*
+ * Because ia32 syscalls do not map to x86_64 syscall numbers
+ * this screws up the trace output when tracing a ia32 task.
+ * Instead of reporting bogus syscalls, just do not trace them.
+ *
+ * If the user realy wants these, then they should use the
+ * raw syscall tracepoints with filtering.
+ */
+#define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS 1
+static inline bool arch_trace_is_compat_syscall(struct pt_regs *regs)
+{
+       if (is_compat_task())
+               return true;
+       return false;
+}
+#endif /* CONFIG_FTRACE_SYSCALLS && CONFIG_IA32_EMULATION */
+#endif /* !__ASSEMBLY__  && !COMPILE_OFFSETS */
+
 #endif /* _ASM_X86_FTRACE_H */
index 2d946e63ee82bceca34043aff29958b5e0e34127..2cd056e3ada394aa05c30a9990da58027f535d96 100644 (file)
@@ -20,7 +20,6 @@
 struct task_struct;
 struct exec_domain;
 #include <asm/processor.h>
-#include <asm/ftrace.h>
 #include <linux/atomic.h>
 
 struct thread_info {
index ce8c3d68292f701ac7813f4e20a19af79896fa4b..98ca94a4181967800df7a2b858c594347617866f 100644 (file)
@@ -3996,37 +3996,51 @@ static void ftrace_init_module(struct module *mod,
        ftrace_process_locs(mod, start, end);
 }
 
-static int ftrace_module_notify(struct notifier_block *self,
-                               unsigned long val, void *data)
+static int ftrace_module_notify_enter(struct notifier_block *self,
+                                     unsigned long val, void *data)
 {
        struct module *mod = data;
 
-       switch (val) {
-       case MODULE_STATE_COMING:
+       if (val == MODULE_STATE_COMING)
                ftrace_init_module(mod, mod->ftrace_callsites,
                                   mod->ftrace_callsites +
                                   mod->num_ftrace_callsites);
-               break;
-       case MODULE_STATE_GOING:
+       return 0;
+}
+
+static int ftrace_module_notify_exit(struct notifier_block *self,
+                                    unsigned long val, void *data)
+{
+       struct module *mod = data;
+
+       if (val == MODULE_STATE_GOING)
                ftrace_release_mod(mod);
-               break;
-       }
 
        return 0;
 }
 #else
-static int ftrace_module_notify(struct notifier_block *self,
-                               unsigned long val, void *data)
+static int ftrace_module_notify_enter(struct notifier_block *self,
+                                     unsigned long val, void *data)
+{
+       return 0;
+}
+static int ftrace_module_notify_exit(struct notifier_block *self,
+                                    unsigned long val, void *data)
 {
        return 0;
 }
 #endif /* CONFIG_MODULES */
 
-struct notifier_block ftrace_module_nb = {
-       .notifier_call = ftrace_module_notify,
+struct notifier_block ftrace_module_enter_nb = {
+       .notifier_call = ftrace_module_notify_enter,
        .priority = INT_MAX,    /* Run before anything that can use kprobes */
 };
 
+struct notifier_block ftrace_module_exit_nb = {
+       .notifier_call = ftrace_module_notify_exit,
+       .priority = INT_MIN,    /* Run after anything that can remove kprobes */
+};
+
 extern unsigned long __start_mcount_loc[];
 extern unsigned long __stop_mcount_loc[];
 
@@ -4058,9 +4072,13 @@ void __init ftrace_init(void)
                                  __start_mcount_loc,
                                  __stop_mcount_loc);
 
-       ret = register_module_notifier(&ftrace_module_nb);
+       ret = register_module_notifier(&ftrace_module_enter_nb);
+       if (ret)
+               pr_warning("Failed to register trace ftrace module enter notifier\n");
+
+       ret = register_module_notifier(&ftrace_module_exit_nb);
        if (ret)
-               pr_warning("Failed to register trace ftrace module notifier\n");
+               pr_warning("Failed to register trace ftrace module exit notifier\n");
 
        set_ftrace_early_filters();
 
index 5329e13e74a13816969771b421852916f8bc3a50..7a809e3210583a77f5eb8e8a64ce1cb6552e7f6f 100644 (file)
@@ -1,5 +1,6 @@
 #include <trace/syscall.h>
 #include <trace/events/syscalls.h>
+#include <linux/syscalls.h>
 #include <linux/slab.h>
 #include <linux/kernel.h>
 #include <linux/module.h>      /* for MODULE_NAME_LEN via KSYM_SYMBOL_LEN */
@@ -47,6 +48,38 @@ static inline bool arch_syscall_match_sym_name(const char *sym, const char *name
 }
 #endif
 
+#ifdef ARCH_TRACE_IGNORE_COMPAT_SYSCALLS
+/*
+ * Some architectures that allow for 32bit applications
+ * to run on a 64bit kernel, do not map the syscalls for
+ * the 32bit tasks the same as they do for 64bit tasks.
+ *
+ *     *cough*x86*cough*
+ *
+ * In such a case, instead of reporting the wrong syscalls,
+ * simply ignore them.
+ *
+ * For an arch to ignore the compat syscalls it needs to
+ * define ARCH_TRACE_IGNORE_COMPAT_SYSCALLS as well as
+ * define the function arch_trace_is_compat_syscall() to let
+ * the tracing system know that it should ignore it.
+ */
+static int
+trace_get_syscall_nr(struct task_struct *task, struct pt_regs *regs)
+{
+       if (unlikely(arch_trace_is_compat_syscall(regs)))
+               return -1;
+
+       return syscall_get_nr(task, regs);
+}
+#else
+static inline int
+trace_get_syscall_nr(struct task_struct *task, struct pt_regs *regs)
+{
+       return syscall_get_nr(task, regs);
+}
+#endif /* ARCH_TRACE_IGNORE_COMPAT_SYSCALLS */
+
 static __init struct syscall_metadata *
 find_syscall_meta(unsigned long syscall)
 {
@@ -276,10 +309,10 @@ static void ftrace_syscall_enter(void *ignore, struct pt_regs *regs, long id)
        struct syscall_metadata *sys_data;
        struct ring_buffer_event *event;
        struct ring_buffer *buffer;
-       int size;
        int syscall_nr;
+       int size;
 
-       syscall_nr = syscall_get_nr(current, regs);
+       syscall_nr = trace_get_syscall_nr(current, regs);
        if (syscall_nr < 0)
                return;
        if (!test_bit(syscall_nr, enabled_enter_syscalls))
@@ -313,7 +346,7 @@ static void ftrace_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
        struct ring_buffer *buffer;
        int syscall_nr;
 
-       syscall_nr = syscall_get_nr(current, regs);
+       syscall_nr = trace_get_syscall_nr(current, regs);
        if (syscall_nr < 0)
                return;
        if (!test_bit(syscall_nr, enabled_exit_syscalls))
@@ -502,7 +535,7 @@ static void perf_syscall_enter(void *ignore, struct pt_regs *regs, long id)
        int rctx;
        int size;
 
-       syscall_nr = syscall_get_nr(current, regs);
+       syscall_nr = trace_get_syscall_nr(current, regs);
        if (syscall_nr < 0)
                return;
        if (!test_bit(syscall_nr, enabled_perf_enter_syscalls))
@@ -578,7 +611,7 @@ static void perf_syscall_exit(void *ignore, struct pt_regs *regs, long ret)
        int rctx;
        int size;
 
-       syscall_nr = syscall_get_nr(current, regs);
+       syscall_nr = trace_get_syscall_nr(current, regs);
        if (syscall_nr < 0)
                return;
        if (!test_bit(syscall_nr, enabled_perf_exit_syscalls))