aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/trace/ring_buffer.c64
1 files changed, 17 insertions, 47 deletions
diff --git a/kernel/trace/ring_buffer.c b/kernel/trace/ring_buffer.c
index 81279c6602ff..f6ee9b1ef62a 100644
--- a/kernel/trace/ring_buffer.c
+++ b/kernel/trace/ring_buffer.c
@@ -2538,61 +2538,29 @@ rb_wakeups(struct ring_buffer *buffer, struct ring_buffer_per_cpu *cpu_buffer)
2538 * The lock and unlock are done within a preempt disable section. 2538 * The lock and unlock are done within a preempt disable section.
2539 * The current_context per_cpu variable can only be modified 2539 * The current_context per_cpu variable can only be modified
2540 * by the current task between lock and unlock. But it can 2540 * by the current task between lock and unlock. But it can
2541 * be modified more than once via an interrupt. To pass this 2541 * be modified more than once via an interrupt. There are four
2542 * information from the lock to the unlock without having to 2542 * different contexts that we need to consider.
2543 * access the 'in_interrupt()' functions again (which do show
2544 * a bit of overhead in something as critical as function tracing,
2545 * we use a bitmask trick.
2546 * 2543 *
2547 * bit 0 = NMI context 2544 * Normal context.
2548 * bit 1 = IRQ context 2545 * SoftIRQ context
2549 * bit 2 = SoftIRQ context 2546 * IRQ context
2550 * bit 3 = normal context. 2547 * NMI context
2551 * 2548 *
2552 * This works because this is the order of contexts that can 2549 * If for some reason the ring buffer starts to recurse, we
2553 * preempt other contexts. A SoftIRQ never preempts an IRQ 2550 * only allow that to happen at most 4 times (one for each
2554 * context. 2551 * context). If it happens 5 times, then we consider this a
2555 * 2552 * recusive loop and do not let it go further.
2556 * When the context is determined, the corresponding bit is
2557 * checked and set (if it was set, then a recursion of that context
2558 * happened).
2559 *
2560 * On unlock, we need to clear this bit. To do so, just subtract
2561 * 1 from the current_context and AND it to itself.
2562 *
2563 * (binary)
2564 * 101 - 1 = 100
2565 * 101 & 100 = 100 (clearing bit zero)
2566 *
2567 * 1010 - 1 = 1001
2568 * 1010 & 1001 = 1000 (clearing bit 1)
2569 *
2570 * The least significant bit can be cleared this way, and it
2571 * just so happens that it is the same bit corresponding to
2572 * the current context.
2573 */ 2553 */
2574 2554
2575static __always_inline int 2555static __always_inline int
2576trace_recursive_lock(struct ring_buffer_per_cpu *cpu_buffer) 2556trace_recursive_lock(struct ring_buffer_per_cpu *cpu_buffer)
2577{ 2557{
2578 unsigned int val = cpu_buffer->current_context; 2558 if (cpu_buffer->current_context >= 4)
2579 int bit;
2580
2581 if (in_interrupt()) {
2582 if (in_nmi())
2583 bit = RB_CTX_NMI;
2584 else if (in_irq())
2585 bit = RB_CTX_IRQ;
2586 else
2587 bit = RB_CTX_SOFTIRQ;
2588 } else
2589 bit = RB_CTX_NORMAL;
2590
2591 if (unlikely(val & (1 << bit)))
2592 return 1; 2559 return 1;
2593 2560
2594 val |= (1 << bit); 2561 cpu_buffer->current_context++;
2595 cpu_buffer->current_context = val; 2562 /* Interrupts must see this update */
2563 barrier();
2596 2564
2597 return 0; 2565 return 0;
2598} 2566}
@@ -2600,7 +2568,9 @@ trace_recursive_lock(struct ring_buffer_per_cpu *cpu_buffer)
2600static __always_inline void 2568static __always_inline void
2601trace_recursive_unlock(struct ring_buffer_per_cpu *cpu_buffer) 2569trace_recursive_unlock(struct ring_buffer_per_cpu *cpu_buffer)
2602{ 2570{
2603 cpu_buffer->current_context &= cpu_buffer->current_context - 1; 2571 /* Don't let the dec leak out */
2572 barrier();
2573 cpu_buffer->current_context--;
2604} 2574}
2605 2575
2606/** 2576/**