diff options
-rw-r--r-- | kernel/trace/ftrace.c | 40 | ||||
-rw-r--r-- | kernel/trace/trace.h | 106 |
2 files changed, 110 insertions, 36 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 639b6ab1f04c..ce8c3d68292f 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c | |||
@@ -158,25 +158,15 @@ ftrace_global_list_func(unsigned long ip, unsigned long parent_ip, | |||
158 | { | 158 | { |
159 | int bit; | 159 | int bit; |
160 | 160 | ||
161 | if (in_interrupt()) { | 161 | bit = trace_test_and_set_recursion(TRACE_GLOBAL_START, TRACE_GLOBAL_MAX); |
162 | if (in_nmi()) | 162 | if (bit < 0) |
163 | bit = TRACE_GLOBAL_NMI_BIT; | ||
164 | |||
165 | else if (in_irq()) | ||
166 | bit = TRACE_GLOBAL_IRQ_BIT; | ||
167 | else | ||
168 | bit = TRACE_GLOBAL_SIRQ_BIT; | ||
169 | } else | ||
170 | bit = TRACE_GLOBAL_BIT; | ||
171 | |||
172 | if (unlikely(trace_recursion_test(bit))) | ||
173 | return; | 163 | return; |
174 | 164 | ||
175 | trace_recursion_set(bit); | ||
176 | do_for_each_ftrace_op(op, ftrace_global_list) { | 165 | do_for_each_ftrace_op(op, ftrace_global_list) { |
177 | op->func(ip, parent_ip, op, regs); | 166 | op->func(ip, parent_ip, op, regs); |
178 | } while_for_each_ftrace_op(op); | 167 | } while_for_each_ftrace_op(op); |
179 | trace_recursion_clear(bit); | 168 | |
169 | trace_clear_recursion(bit); | ||
180 | } | 170 | } |
181 | 171 | ||
182 | static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, | 172 | static void ftrace_pid_func(unsigned long ip, unsigned long parent_ip, |
@@ -4145,26 +4135,14 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, | |||
4145 | struct ftrace_ops *ignored, struct pt_regs *regs) | 4135 | struct ftrace_ops *ignored, struct pt_regs *regs) |
4146 | { | 4136 | { |
4147 | struct ftrace_ops *op; | 4137 | struct ftrace_ops *op; |
4148 | unsigned int bit; | 4138 | int bit; |
4149 | 4139 | ||
4150 | if (function_trace_stop) | 4140 | if (function_trace_stop) |
4151 | return; | 4141 | return; |
4152 | 4142 | ||
4153 | if (in_interrupt()) { | 4143 | bit = trace_test_and_set_recursion(TRACE_LIST_START, TRACE_LIST_MAX); |
4154 | if (in_nmi()) | 4144 | if (bit < 0) |
4155 | bit = TRACE_INTERNAL_NMI_BIT; | 4145 | return; |
4156 | |||
4157 | else if (in_irq()) | ||
4158 | bit = TRACE_INTERNAL_IRQ_BIT; | ||
4159 | else | ||
4160 | bit = TRACE_INTERNAL_SIRQ_BIT; | ||
4161 | } else | ||
4162 | bit = TRACE_INTERNAL_BIT; | ||
4163 | |||
4164 | if (unlikely(trace_recursion_test(bit))) | ||
4165 | return; | ||
4166 | |||
4167 | trace_recursion_set(bit); | ||
4168 | 4146 | ||
4169 | /* | 4147 | /* |
4170 | * Some of the ops may be dynamically allocated, | 4148 | * Some of the ops may be dynamically allocated, |
@@ -4176,7 +4154,7 @@ __ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, | |||
4176 | op->func(ip, parent_ip, op, regs); | 4154 | op->func(ip, parent_ip, op, regs); |
4177 | } while_for_each_ftrace_op(op); | 4155 | } while_for_each_ftrace_op(op); |
4178 | preempt_enable_notrace(); | 4156 | preempt_enable_notrace(); |
4179 | trace_recursion_clear(bit); | 4157 | trace_clear_recursion(bit); |
4180 | } | 4158 | } |
4181 | 4159 | ||
4182 | /* | 4160 | /* |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 5a095d6f088d..c203a51dd412 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
@@ -297,18 +297,49 @@ struct tracer { | |||
297 | /* Ring buffer has the 10 LSB bits to count */ | 297 | /* Ring buffer has the 10 LSB bits to count */ |
298 | #define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff) | 298 | #define trace_recursion_buffer() ((current)->trace_recursion & 0x3ff) |
299 | 299 | ||
300 | /* for function tracing recursion */ | 300 | /* |
301 | * For function tracing recursion: | ||
302 | * The order of these bits are important. | ||
303 | * | ||
304 | * When function tracing occurs, the following steps are made: | ||
305 | * If arch does not support a ftrace feature: | ||
306 | * call internal function (uses INTERNAL bits) which calls... | ||
307 | * If callback is registered to the "global" list, the list | ||
308 | * function is called and recursion checks the GLOBAL bits. | ||
309 | * then this function calls... | ||
310 | * The function callback, which can use the FTRACE bits to | ||
311 | * check for recursion. | ||
312 | * | ||
313 | * Now if the arch does not suppport a feature, and it calls | ||
314 | * the global list function which calls the ftrace callback | ||
315 | * all three of these steps will do a recursion protection. | ||
316 | * There's no reason to do one if the previous caller already | ||
317 | * did. The recursion that we are protecting against will | ||
318 | * go through the same steps again. | ||
319 | * | ||
320 | * To prevent the multiple recursion checks, if a recursion | ||
321 | * bit is set that is higher than the MAX bit of the current | ||
322 | * check, then we know that the check was made by the previous | ||
323 | * caller, and we can skip the current check. | ||
324 | */ | ||
301 | enum { | 325 | enum { |
302 | TRACE_INTERNAL_BIT = 11, | 326 | TRACE_FTRACE_BIT = 11, |
303 | TRACE_INTERNAL_NMI_BIT, | 327 | TRACE_FTRACE_NMI_BIT, |
304 | TRACE_INTERNAL_IRQ_BIT, | 328 | TRACE_FTRACE_IRQ_BIT, |
305 | TRACE_INTERNAL_SIRQ_BIT, | 329 | TRACE_FTRACE_SIRQ_BIT, |
306 | 330 | ||
331 | /* GLOBAL_BITs must be greater than FTRACE_BITs */ | ||
307 | TRACE_GLOBAL_BIT, | 332 | TRACE_GLOBAL_BIT, |
308 | TRACE_GLOBAL_NMI_BIT, | 333 | TRACE_GLOBAL_NMI_BIT, |
309 | TRACE_GLOBAL_IRQ_BIT, | 334 | TRACE_GLOBAL_IRQ_BIT, |
310 | TRACE_GLOBAL_SIRQ_BIT, | 335 | TRACE_GLOBAL_SIRQ_BIT, |
311 | 336 | ||
337 | /* INTERNAL_BITs must be greater than GLOBAL_BITs */ | ||
338 | TRACE_INTERNAL_BIT, | ||
339 | TRACE_INTERNAL_NMI_BIT, | ||
340 | TRACE_INTERNAL_IRQ_BIT, | ||
341 | TRACE_INTERNAL_SIRQ_BIT, | ||
342 | |||
312 | TRACE_CONTROL_BIT, | 343 | TRACE_CONTROL_BIT, |
313 | 344 | ||
314 | /* | 345 | /* |
@@ -325,6 +356,71 @@ enum { | |||
325 | #define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(1<<(bit)); } while (0) | 356 | #define trace_recursion_clear(bit) do { (current)->trace_recursion &= ~(1<<(bit)); } while (0) |
326 | #define trace_recursion_test(bit) ((current)->trace_recursion & (1<<(bit))) | 357 | #define trace_recursion_test(bit) ((current)->trace_recursion & (1<<(bit))) |
327 | 358 | ||
359 | #define TRACE_CONTEXT_BITS 4 | ||
360 | |||
361 | #define TRACE_FTRACE_START TRACE_FTRACE_BIT | ||
362 | #define TRACE_FTRACE_MAX ((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1) | ||
363 | |||
364 | #define TRACE_GLOBAL_START TRACE_GLOBAL_BIT | ||
365 | #define TRACE_GLOBAL_MAX ((1 << (TRACE_GLOBAL_START + TRACE_CONTEXT_BITS)) - 1) | ||
366 | |||
367 | #define TRACE_LIST_START TRACE_INTERNAL_BIT | ||
368 | #define TRACE_LIST_MAX ((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1) | ||
369 | |||
370 | #define TRACE_CONTEXT_MASK TRACE_LIST_MAX | ||
371 | |||
372 | static __always_inline int trace_get_context_bit(void) | ||
373 | { | ||
374 | int bit; | ||
375 | |||
376 | if (in_interrupt()) { | ||
377 | if (in_nmi()) | ||
378 | bit = 0; | ||
379 | |||
380 | else if (in_irq()) | ||
381 | bit = 1; | ||
382 | else | ||
383 | bit = 2; | ||
384 | } else | ||
385 | bit = 3; | ||
386 | |||
387 | return bit; | ||
388 | } | ||
389 | |||
390 | static __always_inline int trace_test_and_set_recursion(int start, int max) | ||
391 | { | ||
392 | unsigned int val = current->trace_recursion; | ||
393 | int bit; | ||
394 | |||
395 | /* A previous recursion check was made */ | ||
396 | if ((val & TRACE_CONTEXT_MASK) > max) | ||
397 | return 0; | ||
398 | |||
399 | bit = trace_get_context_bit() + start; | ||
400 | if (unlikely(val & (1 << bit))) | ||
401 | return -1; | ||
402 | |||
403 | val |= 1 << bit; | ||
404 | current->trace_recursion = val; | ||
405 | barrier(); | ||
406 | |||
407 | return bit; | ||
408 | } | ||
409 | |||
410 | static __always_inline void trace_clear_recursion(int bit) | ||
411 | { | ||
412 | unsigned int val = current->trace_recursion; | ||
413 | |||
414 | if (!bit) | ||
415 | return; | ||
416 | |||
417 | bit = 1 << bit; | ||
418 | val &= ~bit; | ||
419 | |||
420 | barrier(); | ||
421 | current->trace_recursion = val; | ||
422 | } | ||
423 | |||
328 | #define TRACE_PIPE_ALL_CPU -1 | 424 | #define TRACE_PIPE_ALL_CPU -1 |
329 | 425 | ||
330 | static inline struct ring_buffer_iter * | 426 | static inline struct ring_buffer_iter * |