| From: Masami Hiramatsu <mhiramat@kernel.org> |
| Date: Sat, 14 Jul 2018 01:28:15 +0900 |
| Subject: ring_buffer: tracing: Inherit the tracing setting to next ring buffer |
| |
| commit 73c8d8945505acdcbae137c2e00a1232e0be709f upstream. |
| |
| Maintain the tracing on/off setting of the ring_buffer when switching |
| to the trace buffer snapshot. |
| |
| Taking a snapshot is done by swapping the backup ring buffer |
| (max_tr_buffer). But since the tracing on/off setting is defined |
| by the ring buffer, when swapping it, the tracing on/off setting |
| can also be changed. This causes a strange result like below: |
| |
| /sys/kernel/debug/tracing # cat tracing_on |
| 1 |
| /sys/kernel/debug/tracing # echo 0 > tracing_on |
| /sys/kernel/debug/tracing # cat tracing_on |
| 0 |
| /sys/kernel/debug/tracing # echo 1 > snapshot |
| /sys/kernel/debug/tracing # cat tracing_on |
| 1 |
| /sys/kernel/debug/tracing # echo 1 > snapshot |
| /sys/kernel/debug/tracing # cat tracing_on |
| 0 |
| |
| We don't touch tracing_on, but snapshot changes tracing_on |
| setting each time. This is an anomaly, because user doesn't know |
| that each "ring_buffer" stores its own tracing-enable state and |
| the snapshot is done by swapping ring buffers. |
| |
| Link: http://lkml.kernel.org/r/153149929558.11274.11730609978254724394.stgit@devbox |
| |
| Cc: Ingo Molnar <mingo@redhat.com> |
| Cc: Shuah Khan <shuah@kernel.org> |
| Cc: Tom Zanussi <tom.zanussi@linux.intel.com> |
| Cc: Hiraku Toyooka <hiraku.toyooka@cybertrust.co.jp> |
| Fixes: debdd57f5145 ("tracing: Make a snapshot feature available from userspace") |
| Signed-off-by: Masami Hiramatsu <mhiramat@kernel.org> |
| [ Updated commit log and comment in the code ] |
| Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> |
| [bwh: Backported to 3.16: adjust context] |
| Signed-off-by: Ben Hutchings <ben@decadent.org.uk> |
| --- |
| include/linux/ring_buffer.h | 1 + |
| kernel/trace/ring_buffer.c | 16 ++++++++++++++++ |
| kernel/trace/trace.c | 6 ++++++ |
| 3 files changed, 23 insertions(+) |
| |
| --- a/include/linux/ring_buffer.h |
| +++ b/include/linux/ring_buffer.h |
| @@ -162,6 +162,7 @@ void ring_buffer_record_enable(struct ri |
| void ring_buffer_record_off(struct ring_buffer *buffer); |
| void ring_buffer_record_on(struct ring_buffer *buffer); |
| int ring_buffer_record_is_on(struct ring_buffer *buffer); |
| +int ring_buffer_record_is_set_on(struct ring_buffer *buffer); |
| void ring_buffer_record_disable_cpu(struct ring_buffer *buffer, int cpu); |
| void ring_buffer_record_enable_cpu(struct ring_buffer *buffer, int cpu); |
| |
| --- a/kernel/trace/ring_buffer.c |
| +++ b/kernel/trace/ring_buffer.c |
| @@ -3165,6 +3165,22 @@ int ring_buffer_record_is_on(struct ring |
| } |
| |
| /** |
| + * ring_buffer_record_is_set_on - return true if the ring buffer is set writable |
| + * @buffer: The ring buffer to see if write is set enabled |
| + * |
| + * Returns true if the ring buffer is set writable by ring_buffer_record_on(). |
| + * Note that this does NOT mean it is in a writable state. |
| + * |
| + * It may return true when the ring buffer has been disabled by |
| + * ring_buffer_record_disable(), as that is a temporary disabling of |
| + * the ring buffer. |
| + */ |
| +int ring_buffer_record_is_set_on(struct ring_buffer *buffer) |
| +{ |
| + return !(atomic_read(&buffer->record_disabled) & RB_BUFFER_OFF); |
| +} |
| + |
| +/** |
| * ring_buffer_record_disable_cpu - stop all writes into the cpu_buffer |
| * @buffer: The ring buffer to stop writes to. |
| * @cpu: The CPU buffer to stop |
| --- a/kernel/trace/trace.c |
| +++ b/kernel/trace/trace.c |
| @@ -1046,6 +1046,12 @@ update_max_tr(struct trace_array *tr, st |
| |
| arch_spin_lock(&tr->max_lock); |
| |
| + /* Inherit the recordable setting from trace_buffer */ |
| + if (ring_buffer_record_is_set_on(tr->trace_buffer.buffer)) |
| + ring_buffer_record_on(tr->max_buffer.buffer); |
| + else |
| + ring_buffer_record_off(tr->max_buffer.buffer); |
| + |
| buf = tr->trace_buffer.buffer; |
| tr->trace_buffer.buffer = tr->max_buffer.buffer; |
| tr->max_buffer.buffer = buf; |