diff options
Diffstat (limited to 'include/linux/tracepoint.h')
| -rw-r--r-- | include/linux/tracepoint.h | 59 |
1 files changed, 47 insertions, 12 deletions
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 19a690b559ca..7f2e16e76ac4 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | */ | 15 | */ |
| 16 | 16 | ||
| 17 | #include <linux/smp.h> | 17 | #include <linux/smp.h> |
| 18 | #include <linux/srcu.h> | ||
| 18 | #include <linux/errno.h> | 19 | #include <linux/errno.h> |
| 19 | #include <linux/types.h> | 20 | #include <linux/types.h> |
| 20 | #include <linux/cpumask.h> | 21 | #include <linux/cpumask.h> |
| @@ -33,6 +34,8 @@ struct trace_eval_map { | |||
| 33 | 34 | ||
| 34 | #define TRACEPOINT_DEFAULT_PRIO 10 | 35 | #define TRACEPOINT_DEFAULT_PRIO 10 |
| 35 | 36 | ||
| 37 | extern struct srcu_struct tracepoint_srcu; | ||
| 38 | |||
| 36 | extern int | 39 | extern int |
| 37 | tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); | 40 | tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); |
| 38 | extern int | 41 | extern int |
| @@ -75,10 +78,16 @@ int unregister_tracepoint_module_notifier(struct notifier_block *nb) | |||
| 75 | * probe unregistration and the end of module exit to make sure there is no | 78 | * probe unregistration and the end of module exit to make sure there is no |
| 76 | * caller executing a probe when it is freed. | 79 | * caller executing a probe when it is freed. |
| 77 | */ | 80 | */ |
| 81 | #ifdef CONFIG_TRACEPOINTS | ||
| 78 | static inline void tracepoint_synchronize_unregister(void) | 82 | static inline void tracepoint_synchronize_unregister(void) |
| 79 | { | 83 | { |
| 84 | synchronize_srcu(&tracepoint_srcu); | ||
| 80 | synchronize_sched(); | 85 | synchronize_sched(); |
| 81 | } | 86 | } |
| 87 | #else | ||
| 88 | static inline void tracepoint_synchronize_unregister(void) | ||
| 89 | { } | ||
| 90 | #endif | ||
| 82 | 91 | ||
| 83 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS | 92 | #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS |
| 84 | extern int syscall_regfunc(void); | 93 | extern int syscall_regfunc(void); |
| @@ -129,18 +138,31 @@ extern void syscall_unregfunc(void); | |||
| 129 | * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just | 138 | * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just |
| 130 | * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". | 139 | * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto". |
| 131 | */ | 140 | */ |
| 132 | #define __DO_TRACE(tp, proto, args, cond, rcucheck) \ | 141 | #define __DO_TRACE(tp, proto, args, cond, rcuidle) \ |
| 133 | do { \ | 142 | do { \ |
| 134 | struct tracepoint_func *it_func_ptr; \ | 143 | struct tracepoint_func *it_func_ptr; \ |
| 135 | void *it_func; \ | 144 | void *it_func; \ |
| 136 | void *__data; \ | 145 | void *__data; \ |
| 146 | int __maybe_unused idx = 0; \ | ||
| 137 | \ | 147 | \ |
| 138 | if (!(cond)) \ | 148 | if (!(cond)) \ |
| 139 | return; \ | 149 | return; \ |
| 140 | if (rcucheck) \ | 150 | \ |
| 141 | rcu_irq_enter_irqson(); \ | 151 | /* srcu can't be used from NMI */ \ |
| 142 | rcu_read_lock_sched_notrace(); \ | 152 | WARN_ON_ONCE(rcuidle && in_nmi()); \ |
| 143 | it_func_ptr = rcu_dereference_sched((tp)->funcs); \ | 153 | \ |
| 154 | /* keep srcu and sched-rcu usage consistent */ \ | ||
| 155 | preempt_disable_notrace(); \ | ||
| 156 | \ | ||
| 157 | /* \ | ||
| 158 | * For rcuidle callers, use srcu since sched-rcu \ | ||
| 159 | * doesn't work from the idle path. \ | ||
| 160 | */ \ | ||
| 161 | if (rcuidle) \ | ||
| 162 | idx = srcu_read_lock_notrace(&tracepoint_srcu); \ | ||
| 163 | \ | ||
| 164 | it_func_ptr = rcu_dereference_raw((tp)->funcs); \ | ||
| 165 | \ | ||
| 144 | if (it_func_ptr) { \ | 166 | if (it_func_ptr) { \ |
| 145 | do { \ | 167 | do { \ |
| 146 | it_func = (it_func_ptr)->func; \ | 168 | it_func = (it_func_ptr)->func; \ |
| @@ -148,9 +170,11 @@ extern void syscall_unregfunc(void); | |||
| 148 | ((void(*)(proto))(it_func))(args); \ | 170 | ((void(*)(proto))(it_func))(args); \ |
| 149 | } while ((++it_func_ptr)->func); \ | 171 | } while ((++it_func_ptr)->func); \ |
| 150 | } \ | 172 | } \ |
| 151 | rcu_read_unlock_sched_notrace(); \ | 173 | \ |
| 152 | if (rcucheck) \ | 174 | if (rcuidle) \ |
| 153 | rcu_irq_exit_irqson(); \ | 175 | srcu_read_unlock_notrace(&tracepoint_srcu, idx);\ |
| 176 | \ | ||
| 177 | preempt_enable_notrace(); \ | ||
| 154 | } while (0) | 178 | } while (0) |
| 155 | 179 | ||
| 156 | #ifndef MODULE | 180 | #ifndef MODULE |
| @@ -225,6 +249,19 @@ extern void syscall_unregfunc(void); | |||
| 225 | return static_key_false(&__tracepoint_##name.key); \ | 249 | return static_key_false(&__tracepoint_##name.key); \ |
| 226 | } | 250 | } |
| 227 | 251 | ||
| 252 | #ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS | ||
| 253 | #define __TRACEPOINT_ENTRY(name) \ | ||
| 254 | asm(" .section \"__tracepoints_ptrs\", \"a\" \n" \ | ||
| 255 | " .balign 4 \n" \ | ||
| 256 | " .long __tracepoint_" #name " - . \n" \ | ||
| 257 | " .previous \n") | ||
| 258 | #else | ||
| 259 | #define __TRACEPOINT_ENTRY(name) \ | ||
| 260 | static struct tracepoint * const __tracepoint_ptr_##name __used \ | ||
| 261 | __attribute__((section("__tracepoints_ptrs"))) = \ | ||
| 262 | &__tracepoint_##name | ||
| 263 | #endif | ||
| 264 | |||
| 228 | /* | 265 | /* |
| 229 | * We have no guarantee that gcc and the linker won't up-align the tracepoint | 266 | * We have no guarantee that gcc and the linker won't up-align the tracepoint |
| 230 | * structures, so we create an array of pointers that will be used for iteration | 267 | * structures, so we create an array of pointers that will be used for iteration |
| @@ -234,11 +271,9 @@ extern void syscall_unregfunc(void); | |||
| 234 | static const char __tpstrtab_##name[] \ | 271 | static const char __tpstrtab_##name[] \ |
| 235 | __attribute__((section("__tracepoints_strings"))) = #name; \ | 272 | __attribute__((section("__tracepoints_strings"))) = #name; \ |
| 236 | struct tracepoint __tracepoint_##name \ | 273 | struct tracepoint __tracepoint_##name \ |
| 237 | __attribute__((section("__tracepoints"))) = \ | 274 | __attribute__((section("__tracepoints"), used)) = \ |
| 238 | { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\ | 275 | { __tpstrtab_##name, STATIC_KEY_INIT_FALSE, reg, unreg, NULL };\ |
| 239 | static struct tracepoint * const __tracepoint_ptr_##name __used \ | 276 | __TRACEPOINT_ENTRY(name); |
| 240 | __attribute__((section("__tracepoints_ptrs"))) = \ | ||
| 241 | &__tracepoint_##name; | ||
| 242 | 277 | ||
| 243 | #define DEFINE_TRACE(name) \ | 278 | #define DEFINE_TRACE(name) \ |
| 244 | DEFINE_TRACE_FN(name, NULL, NULL); | 279 | DEFINE_TRACE_FN(name, NULL, NULL); |
