diff options
author | Steven Rostedt (Red Hat) <rostedt@goodmis.org> | 2015-09-22 17:13:19 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2015-10-25 21:33:54 -0400 |
commit | 7904b5c4988e18b50056b5e71a3ffca752a8a451 (patch) | |
tree | 4319a3e6fe143e6404420f885275cb1f7c87a1a4 | |
parent | 883a1e867e0fe7c2dc2e5844ef692f80177631d5 (diff) |
tracepoint: Give priority to probes of tracepoints
In order to guarantee that a probe will be called before other probes that
are attached to a tracepoint, there needs to be a mechanism to provide
priority of one probe over the others.
Adding a prio field to the struct tracepoint_func, which lets the probes be
sorted by the priority set in the structure. If no priority is specified,
then a priority of 10 is given (this is a macro, and perhaps may be changed
in the future).
Now probes may be added to affect other probes that are attached to a
tracepoint with a guaranteed order.
One use case would be to allow tracing of tracepoints be able to filter by
pid. A special (higher priority probe) may be added to the sched_switch
tracepoint and set the necessary flags of the other tracepoints to notify
them if they should be traced or not. In case a tracepoint is enabled at the
sched_switch tracepoint too, the order of the two are not random.
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
-rw-r--r-- | include/linux/tracepoint.h | 13 | ||||
-rw-r--r-- | kernel/tracepoint.c | 61 |
2 files changed, 63 insertions, 11 deletions
diff --git a/include/linux/tracepoint.h b/include/linux/tracepoint.h index afada369c5b7..6b79537a42b1 100644 --- a/include/linux/tracepoint.h +++ b/include/linux/tracepoint.h | |||
@@ -26,6 +26,7 @@ struct notifier_block; | |||
26 | struct tracepoint_func { | 26 | struct tracepoint_func { |
27 | void *func; | 27 | void *func; |
28 | void *data; | 28 | void *data; |
29 | int prio; | ||
29 | }; | 30 | }; |
30 | 31 | ||
31 | struct tracepoint { | 32 | struct tracepoint { |
@@ -42,9 +43,14 @@ struct trace_enum_map { | |||
42 | unsigned long enum_value; | 43 | unsigned long enum_value; |
43 | }; | 44 | }; |
44 | 45 | ||
46 | #define TRACEPOINT_DEFAULT_PRIO 10 | ||
47 | |||
45 | extern int | 48 | extern int |
46 | tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); | 49 | tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); |
47 | extern int | 50 | extern int |
51 | tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data, | ||
52 | int prio); | ||
53 | extern int | ||
48 | tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data); | 54 | tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data); |
49 | extern void | 55 | extern void |
50 | for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), | 56 | for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), |
@@ -207,6 +213,13 @@ extern void syscall_unregfunc(void); | |||
207 | (void *)probe, data); \ | 213 | (void *)probe, data); \ |
208 | } \ | 214 | } \ |
209 | static inline int \ | 215 | static inline int \ |
216 | register_trace_prio_##name(void (*probe)(data_proto), void *data,\ | ||
217 | int prio) \ | ||
218 | { \ | ||
219 | return tracepoint_probe_register_prio(&__tracepoint_##name, \ | ||
220 | (void *)probe, data, prio); \ | ||
221 | } \ | ||
222 | static inline int \ | ||
210 | unregister_trace_##name(void (*probe)(data_proto), void *data) \ | 223 | unregister_trace_##name(void (*probe)(data_proto), void *data) \ |
211 | { \ | 224 | { \ |
212 | return tracepoint_probe_unregister(&__tracepoint_##name,\ | 225 | return tracepoint_probe_unregister(&__tracepoint_##name,\ |
diff --git a/kernel/tracepoint.c b/kernel/tracepoint.c index 3490407dc7b7..ecd536de603a 100644 --- a/kernel/tracepoint.c +++ b/kernel/tracepoint.c | |||
@@ -91,11 +91,13 @@ static void debug_print_probes(struct tracepoint_func *funcs) | |||
91 | printk(KERN_DEBUG "Probe %d : %p\n", i, funcs[i].func); | 91 | printk(KERN_DEBUG "Probe %d : %p\n", i, funcs[i].func); |
92 | } | 92 | } |
93 | 93 | ||
94 | static struct tracepoint_func *func_add(struct tracepoint_func **funcs, | 94 | static struct tracepoint_func * |
95 | struct tracepoint_func *tp_func) | 95 | func_add(struct tracepoint_func **funcs, struct tracepoint_func *tp_func, |
96 | int prio) | ||
96 | { | 97 | { |
97 | int nr_probes = 0; | ||
98 | struct tracepoint_func *old, *new; | 98 | struct tracepoint_func *old, *new; |
99 | int nr_probes = 0; | ||
100 | int pos = -1; | ||
99 | 101 | ||
100 | if (WARN_ON(!tp_func->func)) | 102 | if (WARN_ON(!tp_func->func)) |
101 | return ERR_PTR(-EINVAL); | 103 | return ERR_PTR(-EINVAL); |
@@ -104,18 +106,33 @@ static struct tracepoint_func *func_add(struct tracepoint_func **funcs, | |||
104 | old = *funcs; | 106 | old = *funcs; |
105 | if (old) { | 107 | if (old) { |
106 | /* (N -> N+1), (N != 0, 1) probes */ | 108 | /* (N -> N+1), (N != 0, 1) probes */ |
107 | for (nr_probes = 0; old[nr_probes].func; nr_probes++) | 109 | for (nr_probes = 0; old[nr_probes].func; nr_probes++) { |
110 | /* Insert before probes of lower priority */ | ||
111 | if (pos < 0 && old[nr_probes].prio < prio) | ||
112 | pos = nr_probes; | ||
108 | if (old[nr_probes].func == tp_func->func && | 113 | if (old[nr_probes].func == tp_func->func && |
109 | old[nr_probes].data == tp_func->data) | 114 | old[nr_probes].data == tp_func->data) |
110 | return ERR_PTR(-EEXIST); | 115 | return ERR_PTR(-EEXIST); |
116 | } | ||
111 | } | 117 | } |
112 | /* + 2 : one for new probe, one for NULL func */ | 118 | /* + 2 : one for new probe, one for NULL func */ |
113 | new = allocate_probes(nr_probes + 2); | 119 | new = allocate_probes(nr_probes + 2); |
114 | if (new == NULL) | 120 | if (new == NULL) |
115 | return ERR_PTR(-ENOMEM); | 121 | return ERR_PTR(-ENOMEM); |
116 | if (old) | 122 | if (old) { |
117 | memcpy(new, old, nr_probes * sizeof(struct tracepoint_func)); | 123 | if (pos < 0) { |
118 | new[nr_probes] = *tp_func; | 124 | pos = nr_probes; |
125 | memcpy(new, old, nr_probes * sizeof(struct tracepoint_func)); | ||
126 | } else { | ||
127 | /* Copy higher priority probes ahead of the new probe */ | ||
128 | memcpy(new, old, pos * sizeof(struct tracepoint_func)); | ||
129 | /* Copy the rest after it. */ | ||
130 | memcpy(new + pos + 1, old + pos, | ||
131 | (nr_probes - pos) * sizeof(struct tracepoint_func)); | ||
132 | } | ||
133 | } else | ||
134 | pos = 0; | ||
135 | new[pos] = *tp_func; | ||
119 | new[nr_probes + 1].func = NULL; | 136 | new[nr_probes + 1].func = NULL; |
120 | *funcs = new; | 137 | *funcs = new; |
121 | debug_print_probes(*funcs); | 138 | debug_print_probes(*funcs); |
@@ -174,7 +191,7 @@ static void *func_remove(struct tracepoint_func **funcs, | |||
174 | * Add the probe function to a tracepoint. | 191 | * Add the probe function to a tracepoint. |
175 | */ | 192 | */ |
176 | static int tracepoint_add_func(struct tracepoint *tp, | 193 | static int tracepoint_add_func(struct tracepoint *tp, |
177 | struct tracepoint_func *func) | 194 | struct tracepoint_func *func, int prio) |
178 | { | 195 | { |
179 | struct tracepoint_func *old, *tp_funcs; | 196 | struct tracepoint_func *old, *tp_funcs; |
180 | 197 | ||
@@ -183,7 +200,7 @@ static int tracepoint_add_func(struct tracepoint *tp, | |||
183 | 200 | ||
184 | tp_funcs = rcu_dereference_protected(tp->funcs, | 201 | tp_funcs = rcu_dereference_protected(tp->funcs, |
185 | lockdep_is_held(&tracepoints_mutex)); | 202 | lockdep_is_held(&tracepoints_mutex)); |
186 | old = func_add(&tp_funcs, func); | 203 | old = func_add(&tp_funcs, func, prio); |
187 | if (IS_ERR(old)) { | 204 | if (IS_ERR(old)) { |
188 | WARN_ON_ONCE(1); | 205 | WARN_ON_ONCE(1); |
189 | return PTR_ERR(old); | 206 | return PTR_ERR(old); |
@@ -240,6 +257,7 @@ static int tracepoint_remove_func(struct tracepoint *tp, | |||
240 | * @tp: tracepoint | 257 | * @tp: tracepoint |
241 | * @probe: probe handler | 258 | * @probe: probe handler |
242 | * @data: tracepoint data | 259 | * @data: tracepoint data |
260 | * @prio: priority of this function over other registered functions | ||
243 | * | 261 | * |
244 | * Returns 0 if ok, error value on error. | 262 | * Returns 0 if ok, error value on error. |
245 | * Note: if @tp is within a module, the caller is responsible for | 263 | * Note: if @tp is within a module, the caller is responsible for |
@@ -247,7 +265,8 @@ static int tracepoint_remove_func(struct tracepoint *tp, | |||
247 | * performed either with a tracepoint module going notifier, or from | 265 | * performed either with a tracepoint module going notifier, or from |
248 | * within module exit functions. | 266 | * within module exit functions. |
249 | */ | 267 | */ |
250 | int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) | 268 | int tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, |
269 | void *data, int prio) | ||
251 | { | 270 | { |
252 | struct tracepoint_func tp_func; | 271 | struct tracepoint_func tp_func; |
253 | int ret; | 272 | int ret; |
@@ -255,10 +274,30 @@ int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) | |||
255 | mutex_lock(&tracepoints_mutex); | 274 | mutex_lock(&tracepoints_mutex); |
256 | tp_func.func = probe; | 275 | tp_func.func = probe; |
257 | tp_func.data = data; | 276 | tp_func.data = data; |
258 | ret = tracepoint_add_func(tp, &tp_func); | 277 | tp_func.prio = prio; |
278 | ret = tracepoint_add_func(tp, &tp_func, prio); | ||
259 | mutex_unlock(&tracepoints_mutex); | 279 | mutex_unlock(&tracepoints_mutex); |
260 | return ret; | 280 | return ret; |
261 | } | 281 | } |
282 | EXPORT_SYMBOL_GPL(tracepoint_probe_register_prio); | ||
283 | |||
284 | /** | ||
285 | * tracepoint_probe_register - Connect a probe to a tracepoint | ||
286 | * @tp: tracepoint | ||
287 | * @probe: probe handler | ||
288 | * @data: tracepoint data | ||
289 | * @prio: priority of this function over other registered functions | ||
290 | * | ||
291 | * Returns 0 if ok, error value on error. | ||
292 | * Note: if @tp is within a module, the caller is responsible for | ||
293 | * unregistering the probe before the module is gone. This can be | ||
294 | * performed either with a tracepoint module going notifier, or from | ||
295 | * within module exit functions. | ||
296 | */ | ||
297 | int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) | ||
298 | { | ||
299 | return tracepoint_probe_register_prio(tp, probe, data, TRACEPOINT_DEFAULT_PRIO); | ||
300 | } | ||
262 | EXPORT_SYMBOL_GPL(tracepoint_probe_register); | 301 | EXPORT_SYMBOL_GPL(tracepoint_probe_register); |
263 | 302 | ||
264 | /** | 303 | /** |