diff options
author | Steven Rostedt (Red Hat) <rostedt@goodmis.org> | 2013-07-01 15:58:24 -0400 |
---|---|---|
committer | Steven Rostedt <rostedt@goodmis.org> | 2013-07-01 20:34:28 -0400 |
commit | 10246fa35d4ffdfe472185d4cbf9c2dfd9a9f023 (patch) | |
tree | 277cb4041486bfe87730fd767b2a8072330211b9 /kernel/trace/trace.c | |
parent | b04d52e368e2cf526abb2bab61f304eaea126af2 (diff) |
tracing: Use flag buffer_disabled for irqsoff tracer
If the ring buffer is disabled and the irqsoff tracer records a trace it
will clear out its buffer and lose the data it had previously recorded.
Currently there's a callback when writing to the tracing_of file, but if
tracing is disabled via the function tracer trigger, it will not inform
the irqsoff tracer to stop recording.
By using the "mirror" flag (buffer_disabled) in the trace_array, that keeps
track of the status of the trace_array's buffer, it gives the irqsoff
tracer a fast way to know if it should record a new trace or not.
The flag may be a little behind the real state of the buffer, but it
should not affect the trace too much. It's more important for the irqsoff
tracer to be fast.
Reported-by: Dave Jones <davej@redhat.com>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace/trace.c')
-rw-r--r-- | kernel/trace/trace.c | 101 |
1 files changed, 70 insertions, 31 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index c4c9296b1916..0dc50711d656 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -226,9 +226,24 @@ cycle_t ftrace_now(int cpu) | |||
226 | return ts; | 226 | return ts; |
227 | } | 227 | } |
228 | 228 | ||
229 | /** | ||
230 | * tracing_is_enabled - Show if global_trace has been disabled | ||
231 | * | ||
232 | * Shows if the global trace has been enabled or not. It uses the | ||
233 | * mirror flag "buffer_disabled" to be used in fast paths such as for | ||
234 | * the irqsoff tracer. But it may be inaccurate due to races. If you | ||
235 | * need to know the accurate state, use tracing_is_on() which is a little | ||
236 | * slower, but accurate. | ||
237 | */ | ||
229 | int tracing_is_enabled(void) | 238 | int tracing_is_enabled(void) |
230 | { | 239 | { |
231 | return tracing_is_on(); | 240 | /* |
241 | * For quick access (irqsoff uses this in fast path), just | ||
242 | * return the mirror variable of the state of the ring buffer. | ||
243 | * It's a little racy, but we don't really care. | ||
244 | */ | ||
245 | smp_rmb(); | ||
246 | return !global_trace.buffer_disabled; | ||
232 | } | 247 | } |
233 | 248 | ||
234 | /* | 249 | /* |
@@ -341,6 +356,23 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | | |||
341 | TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE | | 356 | TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE | |
342 | TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION; | 357 | TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS | TRACE_ITER_FUNCTION; |
343 | 358 | ||
359 | void tracer_tracing_on(struct trace_array *tr) | ||
360 | { | ||
361 | if (tr->trace_buffer.buffer) | ||
362 | ring_buffer_record_on(tr->trace_buffer.buffer); | ||
363 | /* | ||
364 | * This flag is looked at when buffers haven't been allocated | ||
365 | * yet, or by some tracers (like irqsoff), that just want to | ||
366 | * know if the ring buffer has been disabled, but it can handle | ||
367 | * races of where it gets disabled but we still do a record. | ||
368 | * As the check is in the fast path of the tracers, it is more | ||
369 | * important to be fast than accurate. | ||
370 | */ | ||
371 | tr->buffer_disabled = 0; | ||
372 | /* Make the flag seen by readers */ | ||
373 | smp_wmb(); | ||
374 | } | ||
375 | |||
344 | /** | 376 | /** |
345 | * tracing_on - enable tracing buffers | 377 | * tracing_on - enable tracing buffers |
346 | * | 378 | * |
@@ -349,15 +381,7 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK | | |||
349 | */ | 381 | */ |
350 | void tracing_on(void) | 382 | void tracing_on(void) |
351 | { | 383 | { |
352 | if (global_trace.trace_buffer.buffer) | 384 | tracer_tracing_on(&global_trace); |
353 | ring_buffer_record_on(global_trace.trace_buffer.buffer); | ||
354 | /* | ||
355 | * This flag is only looked at when buffers haven't been | ||
356 | * allocated yet. We don't really care about the race | ||
357 | * between setting this flag and actually turning | ||
358 | * on the buffer. | ||
359 | */ | ||
360 | global_trace.buffer_disabled = 0; | ||
361 | } | 385 | } |
362 | EXPORT_SYMBOL_GPL(tracing_on); | 386 | EXPORT_SYMBOL_GPL(tracing_on); |
363 | 387 | ||
@@ -551,6 +575,23 @@ void tracing_snapshot_alloc(void) | |||
551 | EXPORT_SYMBOL_GPL(tracing_snapshot_alloc); | 575 | EXPORT_SYMBOL_GPL(tracing_snapshot_alloc); |
552 | #endif /* CONFIG_TRACER_SNAPSHOT */ | 576 | #endif /* CONFIG_TRACER_SNAPSHOT */ |
553 | 577 | ||
578 | void tracer_tracing_off(struct trace_array *tr) | ||
579 | { | ||
580 | if (tr->trace_buffer.buffer) | ||
581 | ring_buffer_record_off(tr->trace_buffer.buffer); | ||
582 | /* | ||
583 | * This flag is looked at when buffers haven't been allocated | ||
584 | * yet, or by some tracers (like irqsoff), that just want to | ||
585 | * know if the ring buffer has been disabled, but it can handle | ||
586 | * races of where it gets disabled but we still do a record. | ||
587 | * As the check is in the fast path of the tracers, it is more | ||
588 | * important to be fast than accurate. | ||
589 | */ | ||
590 | tr->buffer_disabled = 1; | ||
591 | /* Make the flag seen by readers */ | ||
592 | smp_wmb(); | ||
593 | } | ||
594 | |||
554 | /** | 595 | /** |
555 | * tracing_off - turn off tracing buffers | 596 | * tracing_off - turn off tracing buffers |
556 | * | 597 | * |
@@ -561,15 +602,7 @@ EXPORT_SYMBOL_GPL(tracing_snapshot_alloc); | |||
561 | */ | 602 | */ |
562 | void tracing_off(void) | 603 | void tracing_off(void) |
563 | { | 604 | { |
564 | if (global_trace.trace_buffer.buffer) | 605 | tracer_tracing_off(&global_trace); |
565 | ring_buffer_record_off(global_trace.trace_buffer.buffer); | ||
566 | /* | ||
567 | * This flag is only looked at when buffers haven't been | ||
568 | * allocated yet. We don't really care about the race | ||
569 | * between setting this flag and actually turning | ||
570 | * on the buffer. | ||
571 | */ | ||
572 | global_trace.buffer_disabled = 1; | ||
573 | } | 606 | } |
574 | EXPORT_SYMBOL_GPL(tracing_off); | 607 | EXPORT_SYMBOL_GPL(tracing_off); |
575 | 608 | ||
@@ -580,13 +613,24 @@ void disable_trace_on_warning(void) | |||
580 | } | 613 | } |
581 | 614 | ||
582 | /** | 615 | /** |
616 | * tracer_tracing_is_on - show real state of ring buffer enabled | ||
617 | * @tr : the trace array to know if ring buffer is enabled | ||
618 | * | ||
619 | * Shows real state of the ring buffer if it is enabled or not. | ||
620 | */ | ||
621 | int tracer_tracing_is_on(struct trace_array *tr) | ||
622 | { | ||
623 | if (tr->trace_buffer.buffer) | ||
624 | return ring_buffer_record_is_on(tr->trace_buffer.buffer); | ||
625 | return !tr->buffer_disabled; | ||
626 | } | ||
627 | |||
628 | /** | ||
583 | * tracing_is_on - show state of ring buffers enabled | 629 | * tracing_is_on - show state of ring buffers enabled |
584 | */ | 630 | */ |
585 | int tracing_is_on(void) | 631 | int tracing_is_on(void) |
586 | { | 632 | { |
587 | if (global_trace.trace_buffer.buffer) | 633 | return tracer_tracing_is_on(&global_trace); |
588 | return ring_buffer_record_is_on(global_trace.trace_buffer.buffer); | ||
589 | return !global_trace.buffer_disabled; | ||
590 | } | 634 | } |
591 | EXPORT_SYMBOL_GPL(tracing_is_on); | 635 | EXPORT_SYMBOL_GPL(tracing_is_on); |
592 | 636 | ||
@@ -3958,7 +4002,7 @@ static int tracing_wait_pipe(struct file *filp) | |||
3958 | * | 4002 | * |
3959 | * iter->pos will be 0 if we haven't read anything. | 4003 | * iter->pos will be 0 if we haven't read anything. |
3960 | */ | 4004 | */ |
3961 | if (!tracing_is_enabled() && iter->pos) | 4005 | if (!tracing_is_on() && iter->pos) |
3962 | break; | 4006 | break; |
3963 | } | 4007 | } |
3964 | 4008 | ||
@@ -5631,15 +5675,10 @@ rb_simple_read(struct file *filp, char __user *ubuf, | |||
5631 | size_t cnt, loff_t *ppos) | 5675 | size_t cnt, loff_t *ppos) |
5632 | { | 5676 | { |
5633 | struct trace_array *tr = filp->private_data; | 5677 | struct trace_array *tr = filp->private_data; |
5634 | struct ring_buffer *buffer = tr->trace_buffer.buffer; | ||
5635 | char buf[64]; | 5678 | char buf[64]; |
5636 | int r; | 5679 | int r; |
5637 | 5680 | ||
5638 | if (buffer) | 5681 | r = tracer_tracing_is_on(tr); |
5639 | r = ring_buffer_record_is_on(buffer); | ||
5640 | else | ||
5641 | r = 0; | ||
5642 | |||
5643 | r = sprintf(buf, "%d\n", r); | 5682 | r = sprintf(buf, "%d\n", r); |
5644 | 5683 | ||
5645 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); | 5684 | return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); |
@@ -5661,11 +5700,11 @@ rb_simple_write(struct file *filp, const char __user *ubuf, | |||
5661 | if (buffer) { | 5700 | if (buffer) { |
5662 | mutex_lock(&trace_types_lock); | 5701 | mutex_lock(&trace_types_lock); |
5663 | if (val) { | 5702 | if (val) { |
5664 | ring_buffer_record_on(buffer); | 5703 | tracer_tracing_on(tr); |
5665 | if (tr->current_trace->start) | 5704 | if (tr->current_trace->start) |
5666 | tr->current_trace->start(tr); | 5705 | tr->current_trace->start(tr); |
5667 | } else { | 5706 | } else { |
5668 | ring_buffer_record_off(buffer); | 5707 | tracer_tracing_off(tr); |
5669 | if (tr->current_trace->stop) | 5708 | if (tr->current_trace->stop) |
5670 | tr->current_trace->stop(tr); | 5709 | tr->current_trace->stop(tr); |
5671 | } | 5710 | } |