diff options
-rw-r--r-- | arch/s390/kernel/ptrace.c | 4 | ||||
-rw-r--r-- | arch/x86/kernel/ptrace.c | 4 | ||||
-rw-r--r-- | include/linux/tracepoint.h | 46 | ||||
-rw-r--r-- | include/trace/define_trace.h | 5 | ||||
-rw-r--r-- | include/trace/ftrace.h | 9 | ||||
-rw-r--r-- | include/trace/syscall.h | 12 | ||||
-rw-r--r-- | kernel/tracepoint.c | 14 |
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 | ||
54 | DEFINE_TRACE(syscall_enter); | 54 | DEFINE_TRACE_FN(syscall_enter, syscall_regfunc, syscall_unregfunc); |
55 | DEFINE_TRACE(syscall_exit); | 55 | DEFINE_TRACE_FN(syscall_exit, syscall_regfunc, syscall_unregfunc); |
56 | 56 | ||
57 | enum s390_regset { | 57 | enum 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 | ||
40 | DEFINE_TRACE(syscall_enter); | 40 | DEFINE_TRACE_FN(syscall_enter, syscall_regfunc, syscall_unregfunc); |
41 | DEFINE_TRACE(syscall_exit); | 41 | DEFINE_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; | |||
23 | struct tracepoint { | 23 | struct 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 @@ | |||
13 | extern void syscall_regfunc(void); | 13 | extern void syscall_regfunc(void); |
14 | extern void syscall_unregfunc(void); | 14 | extern void syscall_unregfunc(void); |
15 | 15 | ||
16 | DECLARE_TRACE_WITH_CALLBACK(syscall_enter, | 16 | DECLARE_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 | ||
23 | DECLARE_TRACE_WITH_CALLBACK(syscall_exit, | 21 | DECLARE_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 | */ |
263 | static void disable_tracepoint(struct tracepoint *elem) | 268 | static 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 | ||
581 | static DEFINE_MUTEX(regfunc_mutex); | 589 | /* NB: reg/unreg are called while guarded with the tracepoints_mutex */ |
582 | static int sys_tracepoint_refcount; | 590 | static int sys_tracepoint_refcount; |
583 | 591 | ||
584 | void syscall_regfunc(void) | 592 | void 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(®func_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(®func_mutex); | ||
599 | } | 605 | } |
600 | 606 | ||
601 | void syscall_unregfunc(void) | 607 | void 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(®func_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(®func_mutex); | ||
616 | } | 620 | } |
617 | #endif | 621 | #endif |