Commit a358324466b171e145df20bdb74fe81759906de6

Authored by Steven Rostedt
1 parent 4143c5cb36

ring-buffer: buffer record on/off switch

Impact: enable/disable ring buffer recording API added

Several kernel developers have requested that there be a way to stop
recording into the ring buffers with a simple switch that can also
be enabled from userspace. This patch addes a new kernel API to the
ring buffers called:

 tracing_on()
 tracing_off()

When tracing_off() is called, all ring buffers will not be able to record
into their buffers.

tracing_on() will enable the ring buffers again.

These two act like an on/off switch. That is, there is no counting of the
number of times tracing_off or tracing_on has been called.

A new file is added to the debugfs/tracing directory called

  tracing_on

This allows for userspace applications to also flip the switch.

  echo 0 > debugfs/tracing/tracing_on

disables the tracing.

  echo 1 > /debugfs/tracing/tracing_on

enables it.

Note, this does not disable or enable any tracers. It only sets or clears
a flag that needs to be set in order for the ring buffers to write to
their buffers. It is a global flag, and affects all ring buffers.

The buffers start out with tracing_on enabled.

There are now three flags that control recording into the buffers:

 tracing_on: which affects all ring buffer tracers.

 buffer->record_disabled: which affects an allocated buffer, which may be set
     if an anomaly is detected, and tracing is disabled.

 cpu_buffer->record_disabled: which is set by tracing_stop() or if an
     anomaly is detected. tracing_start can not reenable this if
     an anomaly occurred.

The userspace debugfs/tracing/tracing_enabled is implemented with
tracing_stop() but the user space code can not enable it if the kernel
called tracing_stop().

Userspace can enable the tracing_on even if the kernel disabled it.
It is just a switch used to stop tracing if a condition was hit.
tracing_on is not for protecting critical areas in the kernel nor is
it for stopping tracing if an anomaly occurred. This is because userspace
can reenable it at any time.

Side effect: With this patch, I discovered a dead variable in ftrace.c
  called tracing_on. This patch removes it.

Signed-off-by: Steven Rostedt <srostedt@redhat.com>

Showing 3 changed files with 106 additions and 6 deletions Side-by-side Diff

include/linux/ring_buffer.h
... ... @@ -120,6 +120,9 @@
120 120 u64 ring_buffer_time_stamp(int cpu);
121 121 void ring_buffer_normalize_time_stamp(int cpu, u64 *ts);
122 122  
  123 +void tracing_on(void);
  124 +void tracing_off(void);
  125 +
123 126 enum ring_buffer_flags {
124 127 RB_FL_OVERWRITE = 1 << 0,
125 128 };
kernel/trace/ftrace.c
... ... @@ -185,7 +185,6 @@
185 185 };
186 186  
187 187 static int ftrace_filtered;
188   -static int tracing_on;
189 188  
190 189 static LIST_HEAD(ftrace_new_addrs);
191 190  
192 191  
193 192  
... ... @@ -506,13 +505,10 @@
506 505 {
507 506 int *command = data;
508 507  
509   - if (*command & FTRACE_ENABLE_CALLS) {
  508 + if (*command & FTRACE_ENABLE_CALLS)
510 509 ftrace_replace_code(1);
511   - tracing_on = 1;
512   - } else if (*command & FTRACE_DISABLE_CALLS) {
  510 + else if (*command & FTRACE_DISABLE_CALLS)
513 511 ftrace_replace_code(0);
514   - tracing_on = 0;
515   - }
516 512  
517 513 if (*command & FTRACE_UPDATE_TRACE_FUNC)
518 514 ftrace_update_ftrace_func(ftrace_trace_function);
kernel/trace/ring_buffer.c
... ... @@ -16,6 +16,35 @@
16 16 #include <linux/list.h>
17 17 #include <linux/fs.h>
18 18  
  19 +#include "trace.h"
  20 +
  21 +/* Global flag to disable all recording to ring buffers */
  22 +static int ring_buffers_off __read_mostly;
  23 +
  24 +/**
  25 + * tracing_on - enable all tracing buffers
  26 + *
  27 + * This function enables all tracing buffers that may have been
  28 + * disabled with tracing_off.
  29 + */
  30 +void tracing_on(void)
  31 +{
  32 + ring_buffers_off = 0;
  33 +}
  34 +
  35 +/**
  36 + * tracing_off - turn off all tracing buffers
  37 + *
  38 + * This function stops all tracing buffers from recording data.
  39 + * It does not disable any overhead the tracers themselves may
  40 + * be causing. This function simply causes all recording to
  41 + * the ring buffers to fail.
  42 + */
  43 +void tracing_off(void)
  44 +{
  45 + ring_buffers_off = 1;
  46 +}
  47 +
19 48 /* Up this if you want to test the TIME_EXTENTS and normalization */
20 49 #define DEBUG_SHIFT 0
21 50  
... ... @@ -1133,6 +1162,9 @@
1133 1162 struct ring_buffer_event *event;
1134 1163 int cpu, resched;
1135 1164  
  1165 + if (ring_buffers_off)
  1166 + return NULL;
  1167 +
1136 1168 if (atomic_read(&buffer->record_disabled))
1137 1169 return NULL;
1138 1170  
... ... @@ -1249,6 +1281,9 @@
1249 1281 int ret = -EBUSY;
1250 1282 int cpu, resched;
1251 1283  
  1284 + if (ring_buffers_off)
  1285 + return -EBUSY;
  1286 +
1252 1287 if (atomic_read(&buffer->record_disabled))
1253 1288 return -EBUSY;
1254 1289  
... ... @@ -2069,4 +2104,71 @@
2069 2104  
2070 2105 return 0;
2071 2106 }
  2107 +
  2108 +static ssize_t
  2109 +rb_simple_read(struct file *filp, char __user *ubuf,
  2110 + size_t cnt, loff_t *ppos)
  2111 +{
  2112 + int *p = filp->private_data;
  2113 + char buf[64];
  2114 + int r;
  2115 +
  2116 + /* !ring_buffers_off == tracing_on */
  2117 + r = sprintf(buf, "%d\n", !*p);
  2118 +
  2119 + return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
  2120 +}
  2121 +
  2122 +static ssize_t
  2123 +rb_simple_write(struct file *filp, const char __user *ubuf,
  2124 + size_t cnt, loff_t *ppos)
  2125 +{
  2126 + int *p = filp->private_data;
  2127 + char buf[64];
  2128 + long val;
  2129 + int ret;
  2130 +
  2131 + if (cnt >= sizeof(buf))
  2132 + return -EINVAL;
  2133 +
  2134 + if (copy_from_user(&buf, ubuf, cnt))
  2135 + return -EFAULT;
  2136 +
  2137 + buf[cnt] = 0;
  2138 +
  2139 + ret = strict_strtoul(buf, 10, &val);
  2140 + if (ret < 0)
  2141 + return ret;
  2142 +
  2143 + /* !ring_buffers_off == tracing_on */
  2144 + *p = !val;
  2145 +
  2146 + (*ppos)++;
  2147 +
  2148 + return cnt;
  2149 +}
  2150 +
  2151 +static struct file_operations rb_simple_fops = {
  2152 + .open = tracing_open_generic,
  2153 + .read = rb_simple_read,
  2154 + .write = rb_simple_write,
  2155 +};
  2156 +
  2157 +
  2158 +static __init int rb_init_debugfs(void)
  2159 +{
  2160 + struct dentry *d_tracer;
  2161 + struct dentry *entry;
  2162 +
  2163 + d_tracer = tracing_init_dentry();
  2164 +
  2165 + entry = debugfs_create_file("tracing_on", 0644, d_tracer,
  2166 + &ring_buffers_off, &rb_simple_fops);
  2167 + if (!entry)
  2168 + pr_warning("Could not create debugfs 'tracing_on' entry\n");
  2169 +
  2170 + return 0;
  2171 +}
  2172 +
  2173 +fs_initcall(rb_init_debugfs);