aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2015-09-22 17:13:19 -0400
committerSteven Rostedt <rostedt@goodmis.org>2015-10-25 21:33:54 -0400
commit7904b5c4988e18b50056b5e71a3ffca752a8a451 (patch)
tree4319a3e6fe143e6404420f885275cb1f7c87a1a4
parent883a1e867e0fe7c2dc2e5844ef692f80177631d5 (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.h13
-rw-r--r--kernel/tracepoint.c61
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;
26struct tracepoint_func { 26struct tracepoint_func {
27 void *func; 27 void *func;
28 void *data; 28 void *data;
29 int prio;
29}; 30};
30 31
31struct tracepoint { 32struct 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
45extern int 48extern int
46tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data); 49tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data);
47extern int 50extern int
51tracepoint_probe_register_prio(struct tracepoint *tp, void *probe, void *data,
52 int prio);
53extern int
48tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data); 54tracepoint_probe_unregister(struct tracepoint *tp, void *probe, void *data);
49extern void 55extern void
50for_each_kernel_tracepoint(void (*fct)(struct tracepoint *tp, void *priv), 56for_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
94static struct tracepoint_func *func_add(struct tracepoint_func **funcs, 94static struct tracepoint_func *
95 struct tracepoint_func *tp_func) 95func_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 */
176static int tracepoint_add_func(struct tracepoint *tp, 193static 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 */
250int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data) 268int 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}
282EXPORT_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 */
297int tracepoint_probe_register(struct tracepoint *tp, void *probe, void *data)
298{
299 return tracepoint_probe_register_prio(tp, probe, data, TRACEPOINT_DEFAULT_PRIO);
300}
262EXPORT_SYMBOL_GPL(tracepoint_probe_register); 301EXPORT_SYMBOL_GPL(tracepoint_probe_register);
263 302
264/** 303/**