|
@@ -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);
|
|
@@ -129,18 +138,31 @@ 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) \
|
|
|
- rcu_irq_enter_irqson(); \
|
|
|
- rcu_read_lock_sched_notrace(); \
|
|
|
- it_func_ptr = rcu_dereference_sched((tp)->funcs); \
|
|
|
+ \
|
|
|
+ /* 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); \
|
|
|
+ \
|
|
|
+ it_func_ptr = rcu_dereference_raw((tp)->funcs); \
|
|
|
+ \
|
|
|
if (it_func_ptr) { \
|
|
|
do { \
|
|
|
it_func = (it_func_ptr)->func; \
|
|
@@ -148,9 +170,11 @@ extern void syscall_unregfunc(void);
|
|
|
((void(*)(proto))(it_func))(args); \
|
|
|
} while ((++it_func_ptr)->func); \
|
|
|
} \
|
|
|
- rcu_read_unlock_sched_notrace(); \
|
|
|
- if (rcucheck) \
|
|
|
- rcu_irq_exit_irqson(); \
|
|
|
+ \
|
|
|
+ if (rcuidle) \
|
|
|
+ srcu_read_unlock_notrace(&tracepoint_srcu, idx);\
|
|
|
+ \
|
|
|
+ preempt_enable_notrace(); \
|
|
|
} while (0)
|
|
|
|
|
|
#ifndef MODULE
|