diff options
Diffstat (limited to 'include/linux/tracepoint.h')
| -rw-r--r-- | include/linux/tracepoint.h | 69 | 
1 files changed, 59 insertions, 10 deletions
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index 19a690b559ca..538ba1a58f5b 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h @@ -15,6 +15,7 @@   */  #include <linux/smp.h> +#include <linux/srcu.h>  #include <linux/errno.h>  #include <linux/types.h>  #include <linux/cpumask.h> @@ -33,6 +34,8 @@ struct trace_eval_map {  #define TRACEPOINT_DEFAULT_PRIO	10 +extern struct srcu_struct tracepoint_srcu; +  extern int  tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);  extern int @@ -75,10 +78,16 @@ int unregister_tracepoint_module_notifier(struct notifier_block *nb)   * probe unregistration and the end of module exit to make sure there is no   * caller executing a probe when it is freed.   */ +#ifdef CONFIG_TRACEPOINTS  static inline void tracepoint_synchronize_unregister(void)  { +	synchronize_srcu(&tracepoint_srcu);  	synchronize_sched();  } +#else +static inline void tracepoint_synchronize_unregister(void) +{ } +#endif  #ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS  extern int syscall_regfunc(void); @@ -90,6 +99,29 @@ extern void syscall_unregfunc(void);  #define TRACE_DEFINE_ENUM(x)  #define TRACE_DEFINE_SIZEOF(x) +#ifdef CONFIG_HAVE_ARCH_PREL32_RELOCATIONS +static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) +{ +	return offset_to_ptr(p); +} + +#define __TRACEPOINT_ENTRY(name)					\ +	asm("	.section \"__tracepoints_ptrs\", \"a\"		\n"	\ +	    "	.balign 4					\n"	\ +	    "	.long 	__tracepoint_" #name " - .		\n"	\ +	    "	.previous					\n") +#else +static inline struct tracepoint *tracepoint_ptr_deref(tracepoint_ptr_t *p) +{ +	return *p; +} + +#define __TRACEPOINT_ENTRY(name)					 \ +	static tracepoint_ptr_t __tracepoint_ptr_##name __used		 \ +	__attribute__((section("__tracepoints_ptrs"))) =		 \ +		&__tracepoint_##name +#endif +  #endif /* _LINUX_TRACEPOINT_H */  /* @@ -129,18 +161,33 @@ extern void syscall_unregfunc(void);   * as "(void *, void)". The DECLARE_TRACE_NOARGS() will pass in just   * "void *data", where as the DECLARE_TRACE() will pass in "void *data, proto".   */ -#define __DO_TRACE(tp, proto, args, cond, rcucheck)			\ +#define __DO_TRACE(tp, proto, args, cond, rcuidle)			\  	do {								\  		struct tracepoint_func *it_func_ptr;			\  		void *it_func;						\  		void *__data;						\ +		int __maybe_unused idx = 0;				\  									\  		if (!(cond))						\  			return;						\ -		if (rcucheck)						\ +									\ +		/* srcu can't be used from NMI */			\ +		WARN_ON_ONCE(rcuidle && in_nmi());			\ +									\ +		/* keep srcu and sched-rcu usage consistent */		\ +		preempt_disable_notrace();				\ +									\ +		/*							\ +		 * For rcuidle callers, use srcu since sched-rcu	\ +		 * doesn't work from the idle path.			\ +		 */							\ +		if (rcuidle) {						\ +			idx = srcu_read_lock_notrace(&tracepoint_srcu);	\  			rcu_irq_enter_irqson();				\ -		rcu_read_lock_sched_notrace();				\ -		it_func_ptr = rcu_dereference_sched((tp)->funcs);	\ +		}							\ +									\ +		it_func_ptr = rcu_dereference_raw((tp)->funcs);		\ +									\  		if (it_func_ptr) {					\  			do {						\  				it_func = (it_func_ptr)->func;		\ @@ -148,9 +195,13 @@ extern void syscall_unregfunc(void);  				((void(*)(proto))(it_func))(args);	\  			} while ((++it_func_ptr)->func);		\  		}							\ -		rcu_read_unlock_sched_notrace();			\ -		if (rcucheck)						\ +									\ +		if (rcuidle) {						\  			rcu_irq_exit_irqson();				\ +			srcu_read_unlock_notrace(&tracepoint_srcu, idx);\ +		}							\ +									\ +		preempt_enable_notrace();				\  	} while (0)  #ifndef MODULE @@ -234,11 +285,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);  | 
