kernel: tracepoints: add support for relative references
authorArd Biesheuvel <ard.biesheuvel@linaro.org>
Wed, 22 Aug 2018 04:56:22 +0000 (21:56 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Wed, 22 Aug 2018 17:52:47 +0000 (10:52 -0700)
To avoid the need for relocating absolute references to tracepoint
structures at boot time when running relocatable kernels (which may
take a disproportionate amount of space), add the option to emit
these tables as relative references instead.

Link: http://lkml.kernel.org/r/20180704083651.24360-7-ard.biesheuvel@linaro.org
Acked-by: Michael Ellerman <mpe@ellerman.id.au>
Acked-by: Ingo Molnar <mingo@kernel.org>
Acked-by: Steven Rostedt (VMware) <rostedt@goodmis.org>
Signed-off-by: Ard Biesheuvel <ard.biesheuvel@linaro.org>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Cc: Bjorn Helgaas <bhelgaas@google.com>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: James Morris <james.morris@microsoft.com>
Cc: James Morris <jmorris@namei.org>
Cc: Jessica Yu <jeyu@kernel.org>
Cc: Josh Poimboeuf <jpoimboe@redhat.com>
Cc: Kees Cook <keescook@chromium.org>
Cc: Nicolas Pitre <nico@linaro.org>
Cc: Paul Mackerras <paulus@samba.org>
Cc: Petr Mladek <pmladek@suse.com>
Cc: Russell King <linux@armlinux.org.uk>
Cc: "Serge E. Hallyn" <serge@hallyn.com>
Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com>
Cc: Thomas Garnier <thgarnie@google.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Will Deacon <will.deacon@arm.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
include/linux/tracepoint.h
kernel/tracepoint.c

index d9a084c..7f2e16e 100644 (file)
@@ -249,6 +249,19 @@ extern void syscall_unregfunc(void);
                return static_key_false(&__tracepoint_##name.key);      \
        }
 
+#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS
+#define __TRACEPOINT_ENTRY(name)                                       \
+       asm("   .section \"__tracepoints_ptrs\", \"a\"          \n"     \
+           "   .balign 4                                       \n"     \
+           "   .long   __tracepoint_" #name " - .              \n"     \
+           "   .previous                                       \n")
+#else
+#define __TRACEPOINT_ENTRY(name)                                        \
+       static struct tracepoint * const __tracepoint_ptr_##name __used  \
+       __attribute__((section("__tracepoints_ptrs"))) =                 \
+               &__tracepoint_##name
+#endif
+
 /*
  * We have no guarantee that gcc and the linker won't up-align the tracepoint
  * structures, so we create an array of pointers that will be used for iteration
@@ -258,11 +271,9 @@ extern void syscall_unregfunc(void);
        static const char __tpstrtab_##name[]                            \
        __attribute__((section("__tracepoints_strings"))) = #name;       \
        struct tracepoint __tracepoint_##name                            \
-       __attribute__((section("__tracepoints"))) =                      \
+       __attribute__((section("__tracepoints"), used)) =                \
                { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\
-       static struct tracepoint * const __tracepoint_ptr_##name __used  \
-       __attribute__((section("__tracepoints_ptrs"))) =                 \
-               &__tracepoint_##name;
+       __TRACEPOINT_ENTRY(name);
 
 #define DEFINE_TRACE(name)                                             \
        DEFINE_TRACE_FN(name, NULL, NULL);
index 96db841..bf2c06e 100644 (file)
@@ -371,6 +371,27 @@ int tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data)
 }
 EXPORT_SYMBOL_GPL(tracepoint_probe_unregister);
 
+static void for_each_tracepoint_range(struct tracepoint * const *begin,
+               struct tracepoint * const *end,
+               void (*fct)(struct tracepoint *tp, void *priv),
+               void *priv)
+{
+       if (!begin)
+               return;
+
+       if (IS_ENABLED(CONFIG_HAVE_ARCH_PREL32_RELOCATIONS)) {
+               const int *iter;
+
+               for (iter = (const int *)begin; iter < (const int *)end; iter++)
+                       fct(offset_to_ptr(iter), priv);
+       } else {
+               struct tracepoint * const *iter;
+
+               for (iter = begin; iter < end; iter++)
+                       fct(*iter, priv);
+       }
+}
+
 #ifdef CONFIG_MODULES
 bool trace_module_has_bad_taint(struct module *mod)
 {
@@ -435,15 +456,9 @@ EXPORT_SYMBOL_GPL(unregister_tracepoint_module_notifier);
  * Ensure the tracer unregistered the module's probes before the module
  * teardown is performed. Prevents leaks of probe and data pointers.
  */
-static void tp_module_going_check_quiescent(struct tracepoint * const *begin,
-               struct tracepoint * const *end)
+static void tp_module_going_check_quiescent(struct tracepoint *tp, void *priv)
 {
-       struct tracepoint * const *iter;
-
-       if (!begin)
-               return;
-       for (iter = begin; iter < end; iter++)
-               WARN_ON_ONCE((*iter)->funcs);
+       WARN_ON_ONCE(tp->funcs);
 }
 
 static int tracepoint_module_coming(struct module *mod)
@@ -494,8 +509,9 @@ static void tracepoint_module_going(struct module *mod)
                         * Called the going notifier before checking for
                         * quiescence.
                         */
-                       tp_module_going_check_quiescent(mod->tracepoints_ptrs,
-                               mod->tracepoints_ptrs + mod->num_tracepoints);
+                       for_each_tracepoint_range(mod->tracepoints_ptrs,
+                               mod->tracepoints_ptrs + mod->num_tracepoints,
+                               tp_module_going_check_quiescent, NULL);
                        break;
                }
        }
@@ -547,19 +563,6 @@ static __init int init_tracepoints(void)
 __initcall(init_tracepoints);
 #endif /* CONFIG_MODULES */
 
-static void for_each_tracepoint_range(struct tracepoint * const *begin,
-               struct tracepoint * const *end,
-               void (*fct)(struct tracepoint *tp, void *priv),
-               void *priv)
-{
-       struct tracepoint * const *iter;
-
-       if (!begin)
-               return;
-       for (iter = begin; iter < end; iter++)
-               fct(*iter, priv);
-}
-
 /**
  * for_each_kernel_tracepoint - iteration on all kernel tracepoints
  * @fct: callback