aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJosh Stone <jistone@redhat.com>2009-08-24 17:43:13 -0400
committerFrederic Weisbecker <fweisbec@gmail.com>2009-08-25 18:36:41 -0400
commit97419875865859fd2403e66266c02ce028e2f5ab (patch)
tree7df6e6df767e9c8ff538a50bcae17638a1c8da99
parent3d27d8cb34fc156beb86de2338ca4029873a5cc6 (diff)
tracing: Move tracepoint callbacks from declaration to definition
It's not strictly correct for the tracepoint reg/unreg callbacks to occur when a client is hooking up, because the actual tracepoint may not be present yet. This happens to be fine for syscall, since that's in the core kernel, but it would cause problems for tracepoints defined in a module that hasn't been loaded yet. It also means the reg/unreg has to be EXPORTed for any modules to use the tracepoint (as in SystemTap). This patch removes DECLARE_TRACE_WITH_CALLBACK, and instead introduces DEFINE_TRACE_FN which stores the callbacks in struct tracepoint. The callbacks are used now when the active state of the tracepoint changes in set_tracepoint & disable_tracepoint. This also introduces TRACE_EVENT_FN, so ftrace events can also provide registration callbacks if needed. Signed-off-by: Josh Stone <jistone@redhat.com> Cc: Jason Baron <jbaron@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> Cc: Ingo Molnar <mingo@elte.hu> Cc: Li Zefan <lizf@cn.fujitsu.com> Cc: Steven Rostedt <rostedt@goodmis.org> Cc: Peter Zijlstra <peterz@infradead.org> Cc: Mathieu Desnoyers <mathieu.desnoyers@polymtl.ca> Cc: Jiaying Zhang <jiayingz@google.com> Cc: Martin Bligh <mbligh@google.com> Cc: Lai Jiangshan <laijs@cn.fujitsu.com> Cc: Paul Mundt <lethal@linux-sh.org> Cc: Martin Schwidefsky <schwidefsky@de.ibm.com> Cc: Heiko Carstens <heiko.carstens@de.ibm.com> LKML-Reference: <1251150194-1713-4-git-send-email-jistone@redhat.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com>
-rw-r--r--arch/s390/kernel/ptrace.c4
-rw-r--r--arch/x86/kernel/ptrace.c4
-rw-r--r--include/linux/tracepoint.h46
-rw-r--r--include/trace/define_trace.h5
-rw-r--r--include/trace/ftrace.h9
-rw-r--r--include/trace/syscall.h12
-rw-r--r--kernel/tracepoint.c14
7 files changed, 49 insertions, 45 deletions
diff --git a/arch/s390/kernel/ptrace.c b/arch/s390/kernel/ptrace.c
index 9d3dcfa79ea2..c05b44b80c23 100644
--- a/arch/s390/kernel/ptrace.c
+++ b/arch/s390/kernel/ptrace.c
@@ -51,8 +51,8 @@
51#include "compat_ptrace.h" 51#include "compat_ptrace.h"
52#endif 52#endif
53 53
54DEFINE_TRACE(syscall_enter); 54DEFINE_TRACE_FN(syscall_enter, syscall_regfunc, syscall_unregfunc);
55DEFINE_TRACE(syscall_exit); 55DEFINE_TRACE_FN(syscall_exit, syscall_regfunc, syscall_unregfunc);
56 56
57enum s390_regset { 57enum s390_regset {
58 REGSET_GENERAL, 58 REGSET_GENERAL,
diff --git a/arch/x86/kernel/ptrace.c b/arch/x86/kernel/ptrace.c
index a909afef44f4..31e9b97ec4d6 100644
--- a/arch/x86/kernel/ptrace.c
+++ b/arch/x86/kernel/ptrace.c
@@ -37,8 +37,8 @@
37 37
38#include <trace/syscall.h> 38#include <trace/syscall.h>
39 39
40DEFINE_TRACE(syscall_enter); 40DEFINE_TRACE_FN(syscall_enter, syscall_regfunc, syscall_unregfunc);
41DEFINE_TRACE(syscall_exit); 41DEFINE_TRACE_FN(syscall_exit, syscall_regfunc, syscall_unregfunc);
42 42
43#include "tls.h" 43#include "tls.h"
44 44
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h
index 5984ed04c03b..846a4ae501eb 100644
--- a/include/linux/tracepoint.h
+++ b/include/linux/tracepoint.h
@@ -23,6 +23,8 @@ struct tracepoint;
23struct tracepoint { 23struct tracepoint {
24 const char *name; /* Tracepoint name */ 24 const char *name; /* Tracepoint name */
25 int state; /* State. */ 25 int state; /* State. */
26 void (*regfunc)(void);
27 void (*unregfunc)(void);
26 void **funcs; 28 void **funcs;
27} __attribute__((aligned(32))); /* 29} __attribute__((aligned(32))); /*
28 * Aligned on 32 bytes because it is 30 * Aligned on 32 bytes because it is
@@ -60,10 +62,8 @@ struct tracepoint {
60 * Make sure the alignment of the structure in the __tracepoints section will 62 * Make sure the alignment of the structure in the __tracepoints section will
61 * not add unwanted padding between the beginning of the section and the 63 * not add unwanted padding between the beginning of the section and the
62 * structure. Force alignment to the same alignment as the section start. 64 * structure. Force alignment to the same alignment as the section start.
63 * An optional set of (un)registration functions can be passed to perform any
64 * additional (un)registration work.
65 */ 65 */
66#define DECLARE_TRACE_WITH_CALLBACK(name, proto, args, reg, unreg) \ 66#define DECLARE_TRACE(name, proto, args) \
67 extern struct tracepoint __tracepoint_##name; \ 67 extern struct tracepoint __tracepoint_##name; \
68 static inline void trace_##name(proto) \ 68 static inline void trace_##name(proto) \
69 { \ 69 { \
@@ -73,36 +73,23 @@ struct tracepoint {
73 } \ 73 } \
74 static inline int register_trace_##name(void (*probe)(proto)) \ 74 static inline int register_trace_##name(void (*probe)(proto)) \
75 { \ 75 { \
76 int ret; \ 76 return tracepoint_probe_register(#name, (void *)probe); \
77 void (*func)(void) = reg; \
78 \
79 ret = tracepoint_probe_register(#name, (void *)probe); \
80 if (func && !ret) \
81 func(); \
82 return ret; \
83 } \ 77 } \
84 static inline int unregister_trace_##name(void (*probe)(proto)) \ 78 static inline int unregister_trace_##name(void (*probe)(proto)) \
85 { \ 79 { \
86 int ret; \ 80 return tracepoint_probe_unregister(#name, (void *)probe);\
87 void (*func)(void) = unreg; \
88 \
89 ret = tracepoint_probe_unregister(#name, (void *)probe);\
90 if (func && !ret) \
91 func(); \
92 return ret; \
93 } 81 }
94 82
95 83
96#define DECLARE_TRACE(name, proto, args) \ 84#define DEFINE_TRACE_FN(name, reg, unreg) \
97 DECLARE_TRACE_WITH_CALLBACK(name, TP_PROTO(proto), TP_ARGS(args),\
98 NULL, NULL);
99
100#define DEFINE_TRACE(name) \
101 static const char __tpstrtab_##name[] \ 85 static const char __tpstrtab_##name[] \
102 __attribute__((section("__tracepoints_strings"))) = #name; \ 86 __attribute__((section("__tracepoints_strings"))) = #name; \
103 struct tracepoint __tracepoint_##name \ 87 struct tracepoint __tracepoint_##name \
104 __attribute__((section("__tracepoints"), aligned(32))) = \ 88 __attribute__((section("__tracepoints"), aligned(32))) = \
105 { __tpstrtab_##name, 0, NULL } 89 { __tpstrtab_##name, 0, reg, unreg, NULL }
90
91#define DEFINE_TRACE(name) \
92 DEFINE_TRACE_FN(name, NULL, NULL);
106 93
107#define EXPORT_TRACEPOINT_SYMBOL_GPL(name) \ 94#define EXPORT_TRACEPOINT_SYMBOL_GPL(name) \
108 EXPORT_SYMBOL_GPL(__tracepoint_##name) 95 EXPORT_SYMBOL_GPL(__tracepoint_##name)
@@ -113,7 +100,7 @@ extern void tracepoint_update_probe_range(struct tracepoint *begin,
113 struct tracepoint *end); 100 struct tracepoint *end);
114 101
115#else /* !CONFIG_TRACEPOINTS */ 102#else /* !CONFIG_TRACEPOINTS */
116#define DECLARE_TRACE_WITH_CALLBACK(name, proto, args, reg, unreg) \ 103#define DECLARE_TRACE(name, proto, args) \
117 static inline void _do_trace_##name(struct tracepoint *tp, proto) \ 104 static inline void _do_trace_##name(struct tracepoint *tp, proto) \
118 { } \ 105 { } \
119 static inline void trace_##name(proto) \ 106 static inline void trace_##name(proto) \
@@ -127,10 +114,7 @@ extern void tracepoint_update_probe_range(struct tracepoint *begin,
127 return -ENOSYS; \ 114 return -ENOSYS; \
128 } 115 }
129 116
130#define DECLARE_TRACE(name, proto, args) \ 117#define DEFINE_TRACE_FN(name, reg, unreg)
131 DECLARE_TRACE_WITH_CALLBACK(name, TP_PROTO(proto), TP_ARGS(args),\
132 NULL, NULL);
133
134#define DEFINE_TRACE(name) 118#define DEFINE_TRACE(name)
135#define EXPORT_TRACEPOINT_SYMBOL_GPL(name) 119#define EXPORT_TRACEPOINT_SYMBOL_GPL(name)
136#define EXPORT_TRACEPOINT_SYMBOL(name) 120#define EXPORT_TRACEPOINT_SYMBOL(name)
@@ -282,10 +266,16 @@ static inline void tracepoint_synchronize_unregister(void)
282 * can also by used by generic instrumentation like SystemTap), and 266 * can also by used by generic instrumentation like SystemTap), and
283 * it is also used to expose a structured trace record in 267 * it is also used to expose a structured trace record in
284 * /sys/kernel/debug/tracing/events/. 268 * /sys/kernel/debug/tracing/events/.
269 *
270 * A set of (un)registration functions can be passed to the variant
271 * TRACE_EVENT_FN to perform any (un)registration work.
285 */ 272 */
286 273
287#define TRACE_EVENT(name, proto, args, struct, assign, print) \ 274#define TRACE_EVENT(name, proto, args, struct, assign, print) \
288 DECLARE_TRACE(name, PARAMS(proto), PARAMS(args)) 275 DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
276#define TRACE_EVENT_FN(name, proto, args, struct, \
277 assign, print, reg, unreg) \
278 DECLARE_TRACE(name, PARAMS(proto), PARAMS(args))
289#endif 279#endif
290 280
291#endif 281#endif
diff --git a/include/trace/define_trace.h b/include/trace/define_trace.h
index f7a7ae1e8f90..2a969850736d 100644
--- a/include/trace/define_trace.h
+++ b/include/trace/define_trace.h
@@ -26,6 +26,11 @@
26#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \ 26#define TRACE_EVENT(name, proto, args, tstruct, assign, print) \
27 DEFINE_TRACE(name) 27 DEFINE_TRACE(name)
28 28
29#undef TRACE_EVENT_FN
30#define TRACE_EVENT_FN(name, proto, args, tstruct, \
31 assign, print, reg, unreg) \
32 DEFINE_TRACE_FN(name, reg, unreg)
33
29#undef DECLARE_TRACE 34#undef DECLARE_TRACE
30#define DECLARE_TRACE(name, proto, args) \ 35#define DECLARE_TRACE(name, proto, args) \
31 DEFINE_TRACE(name) 36 DEFINE_TRACE(name)
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index 127400255e4c..3a0b44bdabf7 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -42,6 +42,15 @@
42 }; \ 42 }; \
43 static struct ftrace_event_call event_##name 43 static struct ftrace_event_call event_##name
44 44
45/* Callbacks are meaningless to ftrace. */
46#undef TRACE_EVENT_FN
47#define TRACE_EVENT_FN(name, proto, args, tstruct, \
48 assign, print, reg, unreg) \
49 TRACE_EVENT(name, TP_PROTO(proto), TP_ARGS(args), \
50 TP_STRUCT__entry(tstruct), \
51 TP_fast_assign(assign), \
52 TP_printk(print))
53
45#include TRACE_INCLUDE(TRACE_INCLUDE_FILE) 54#include TRACE_INCLUDE(TRACE_INCLUDE_FILE)
46 55
47 56
diff --git a/include/trace/syscall.h b/include/trace/syscall.h
index 5dcb7e3a544c..4e1943001854 100644
--- a/include/trace/syscall.h
+++ b/include/trace/syscall.h
@@ -13,18 +13,14 @@
13extern void syscall_regfunc(void); 13extern void syscall_regfunc(void);
14extern void syscall_unregfunc(void); 14extern void syscall_unregfunc(void);
15 15
16DECLARE_TRACE_WITH_CALLBACK(syscall_enter, 16DECLARE_TRACE(syscall_enter,
17 TP_PROTO(struct pt_regs *regs, long id), 17 TP_PROTO(struct pt_regs *regs, long id),
18 TP_ARGS(regs, id), 18 TP_ARGS(regs, id)
19 syscall_regfunc,
20 syscall_unregfunc
21); 19);
22 20
23DECLARE_TRACE_WITH_CALLBACK(syscall_exit, 21DECLARE_TRACE(syscall_exit,
24 TP_PROTO(struct pt_regs *regs, long ret), 22 TP_PROTO(struct pt_regs *regs, long ret),
25 TP_ARGS(regs, ret), 23 TP_ARGS(regs, ret)
26 syscall_regfunc,
27 syscall_unregfunc
28); 24);
29 25
30#endif 26#endif
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c
index 9e0a36f0e2a9..1a6a453b7efb 100644
--- a/kernel/tracepoint.c
+++ b/kernel/tracepoint.c
@@ -243,6 +243,11 @@ static void set_tracepoint(struct tracepoint_entry **entry,
243{ 243{
244 WARN_ON(strcmp((*entry)->name, elem->name) != 0); 244 WARN_ON(strcmp((*entry)->name, elem->name) != 0);
245 245
246 if (elem->regfunc && !elem->state && active)
247 elem->regfunc();
248 else if (elem->unregfunc && elem->state && !active)
249 elem->unregfunc();
250
246 /* 251 /*
247 * rcu_assign_pointer has a smp_wmb() which makes sure that the new 252 * rcu_assign_pointer has a smp_wmb() which makes sure that the new
248 * probe callbacks array is consistent before setting a pointer to it. 253 * probe callbacks array is consistent before setting a pointer to it.
@@ -262,6 +267,9 @@ static void set_tracepoint(struct tracepoint_entry **entry,
262 */ 267 */
263static void disable_tracepoint(struct tracepoint *elem) 268static void disable_tracepoint(struct tracepoint *elem)
264{ 269{
270 if (elem->unregfunc && elem->state)
271 elem->unregfunc();
272
265 elem->state = 0; 273 elem->state = 0;
266 rcu_assign_pointer(elem->funcs, NULL); 274 rcu_assign_pointer(elem->funcs, NULL);
267} 275}
@@ -578,7 +586,7 @@ __initcall(init_tracepoints);
578 586
579#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS 587#ifdef CONFIG_HAVE_SYSCALL_TRACEPOINTS
580 588
581static DEFINE_MUTEX(regfunc_mutex); 589/* NB: reg/unreg are called while guarded with the tracepoints_mutex */
582static int sys_tracepoint_refcount; 590static int sys_tracepoint_refcount;
583 591
584void syscall_regfunc(void) 592void syscall_regfunc(void)
@@ -586,7 +594,6 @@ void syscall_regfunc(void)
586 unsigned long flags; 594 unsigned long flags;
587 struct task_struct *g, *t; 595 struct task_struct *g, *t;
588 596
589 mutex_lock(&regfunc_mutex);
590 if (!sys_tracepoint_refcount) { 597 if (!sys_tracepoint_refcount) {
591 read_lock_irqsave(&tasklist_lock, flags); 598 read_lock_irqsave(&tasklist_lock, flags);
592 do_each_thread(g, t) { 599 do_each_thread(g, t) {
@@ -595,7 +602,6 @@ void syscall_regfunc(void)
595 read_unlock_irqrestore(&tasklist_lock, flags); 602 read_unlock_irqrestore(&tasklist_lock, flags);
596 } 603 }
597 sys_tracepoint_refcount++; 604 sys_tracepoint_refcount++;
598 mutex_unlock(&regfunc_mutex);
599} 605}
600 606
601void syscall_unregfunc(void) 607void syscall_unregfunc(void)
@@ -603,7 +609,6 @@ void syscall_unregfunc(void)
603 unsigned long flags; 609 unsigned long flags;
604 struct task_struct *g, *t; 610 struct task_struct *g, *t;
605 611
606 mutex_lock(&regfunc_mutex);
607 sys_tracepoint_refcount--; 612 sys_tracepoint_refcount--;
608 if (!sys_tracepoint_refcount) { 613 if (!sys_tracepoint_refcount) {
609 read_lock_irqsave(&tasklist_lock, flags); 614 read_lock_irqsave(&tasklist_lock, flags);
@@ -612,6 +617,5 @@ void syscall_unregfunc(void)
612 } while_each_thread(g, t); 617 } while_each_thread(g, t);
613 read_unlock_irqrestore(&tasklist_lock, flags); 618 read_unlock_irqrestore(&tasklist_lock, flags);
614 } 619 }
615 mutex_unlock(&regfunc_mutex);
616} 620}
617#endif 621#endif