aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/trace
diff options
context:
space:
mode:
authorSteven Rostedt (Red Hat) <rostedt@goodmis.org>2013-03-12 13:26:18 -0400
committerSteven Rostedt <rostedt@goodmis.org>2013-03-15 00:36:03 -0400
commit417944c4c7a0f657158d0515f3b8e8c043fd788f (patch)
tree838e9bb09f8df63af3adf5b865d3781eeac8d6ba /kernel/trace
parent7818b3886545f89549185e4023743e2df91d1fa1 (diff)
tracing: Add a way to soft disable trace events
In order to let triggers enable or disable events, we need a 'soft' method for doing so. For example, if a function probe is added that lets a user enable or disable events when a function is called, that change must be done without taking locks or a mutex, and definitely it can't sleep. But the full enabling of a tracepoint is expensive. By adding a 'SOFT_DISABLE' flag, and converting the flags to be updated without the protection of a mutex (using set/clear_bit()), this soft disable flag can be used to allow critical sections to enable or disable events from being traced (after the event has been placed into "SOFT_MODE"). Some caveats though: The comm recorder (to map pids with a comm) can not be soft disabled (yet). If you disable an event with with a "soft" disable and wait a while before reading the trace, the comm cache may be replaced and you'll get a bunch of <...> for comms in the trace. Reading the "enable" file for an event that is disabled will now give you "0*" where the '*' denotes that the tracepoint is still active but the event itself is "disabled". [ fixed _BIT used in & operation : thanks to Dan Carpenter and smatch ] Cc: Dan Carpenter <dan.carpenter@oracle.com> Cc: Tom Zanussi <tom.zanussi@linux.intel.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel/trace')
-rw-r--r--kernel/trace/trace_events.c75
1 files changed, 62 insertions, 13 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 38b54c5edeb9..106640b0df4a 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -205,37 +205,77 @@ void trace_event_enable_cmd_record(bool enable)
205 205
206 if (enable) { 206 if (enable) {
207 tracing_start_cmdline_record(); 207 tracing_start_cmdline_record();
208 file->flags |= FTRACE_EVENT_FL_RECORDED_CMD; 208 set_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
209 } else { 209 } else {
210 tracing_stop_cmdline_record(); 210 tracing_stop_cmdline_record();
211 file->flags &= ~FTRACE_EVENT_FL_RECORDED_CMD; 211 clear_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
212 } 212 }
213 } while_for_each_event_file(); 213 } while_for_each_event_file();
214 mutex_unlock(&event_mutex); 214 mutex_unlock(&event_mutex);
215} 215}
216 216
217static int ftrace_event_enable_disable(struct ftrace_event_file *file, 217static int __ftrace_event_enable_disable(struct ftrace_event_file *file,
218 int enable) 218 int enable, int soft_disable)
219{ 219{
220 struct ftrace_event_call *call = file->event_call; 220 struct ftrace_event_call *call = file->event_call;
221 int ret = 0; 221 int ret = 0;
222 int disable;
222 223
223 switch (enable) { 224 switch (enable) {
224 case 0: 225 case 0:
225 if (file->flags & FTRACE_EVENT_FL_ENABLED) { 226 /*
226 file->flags &= ~FTRACE_EVENT_FL_ENABLED; 227 * When soft_disable is set and enable is cleared, we want
228 * to clear the SOFT_DISABLED flag but leave the event in the
229 * state that it was. That is, if the event was enabled and
230 * SOFT_DISABLED isn't set, then do nothing. But if SOFT_DISABLED
231 * is set we do not want the event to be enabled before we
232 * clear the bit.
233 *
234 * When soft_disable is not set but the SOFT_MODE flag is,
235 * we do nothing. Do not disable the tracepoint, otherwise
236 * "soft enable"s (clearing the SOFT_DISABLED bit) wont work.
237 */
238 if (soft_disable) {
239 disable = file->flags & FTRACE_EVENT_FL_SOFT_DISABLED;
240 clear_bit(FTRACE_EVENT_FL_SOFT_MODE_BIT, &file->flags);
241 } else
242 disable = !(file->flags & FTRACE_EVENT_FL_SOFT_MODE);
243
244 if (disable && (file->flags & FTRACE_EVENT_FL_ENABLED)) {
245 clear_bit(FTRACE_EVENT_FL_ENABLED_BIT, &file->flags);
227 if (file->flags & FTRACE_EVENT_FL_RECORDED_CMD) { 246 if (file->flags & FTRACE_EVENT_FL_RECORDED_CMD) {
228 tracing_stop_cmdline_record(); 247 tracing_stop_cmdline_record();
229 file->flags &= ~FTRACE_EVENT_FL_RECORDED_CMD; 248 clear_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
230 } 249 }
231 call->class->reg(call, TRACE_REG_UNREGISTER, file); 250 call->class->reg(call, TRACE_REG_UNREGISTER, file);
232 } 251 }
252 /* If in SOFT_MODE, just set the SOFT_DISABLE_BIT */
253 if (file->flags & FTRACE_EVENT_FL_SOFT_MODE)
254 set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
233 break; 255 break;
234 case 1: 256 case 1:
257 /*
258 * When soft_disable is set and enable is set, we want to
259 * register the tracepoint for the event, but leave the event
260 * as is. That means, if the event was already enabled, we do
261 * nothing (but set SOFT_MODE). If the event is disabled, we
262 * set SOFT_DISABLED before enabling the event tracepoint, so
263 * it still seems to be disabled.
264 */
265 if (!soft_disable)
266 clear_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
267 else
268 set_bit(FTRACE_EVENT_FL_SOFT_MODE_BIT, &file->flags);
269
235 if (!(file->flags & FTRACE_EVENT_FL_ENABLED)) { 270 if (!(file->flags & FTRACE_EVENT_FL_ENABLED)) {
271
272 /* Keep the event disabled, when going to SOFT_MODE. */
273 if (soft_disable)
274 set_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, &file->flags);
275
236 if (trace_flags & TRACE_ITER_RECORD_CMD) { 276 if (trace_flags & TRACE_ITER_RECORD_CMD) {
237 tracing_start_cmdline_record(); 277 tracing_start_cmdline_record();
238 file->flags |= FTRACE_EVENT_FL_RECORDED_CMD; 278 set_bit(FTRACE_EVENT_FL_RECORDED_CMD_BIT, &file->flags);
239 } 279 }
240 ret = call->class->reg(call, TRACE_REG_REGISTER, file); 280 ret = call->class->reg(call, TRACE_REG_REGISTER, file);
241 if (ret) { 281 if (ret) {
@@ -244,7 +284,7 @@ static int ftrace_event_enable_disable(struct ftrace_event_file *file,
244 "%s\n", call->name); 284 "%s\n", call->name);
245 break; 285 break;
246 } 286 }
247 file->flags |= FTRACE_EVENT_FL_ENABLED; 287 set_bit(FTRACE_EVENT_FL_ENABLED_BIT, &file->flags);
248 288
249 /* WAS_ENABLED gets set but never cleared. */ 289 /* WAS_ENABLED gets set but never cleared. */
250 call->flags |= TRACE_EVENT_FL_WAS_ENABLED; 290 call->flags |= TRACE_EVENT_FL_WAS_ENABLED;
@@ -255,6 +295,12 @@ static int ftrace_event_enable_disable(struct ftrace_event_file *file,
255 return ret; 295 return ret;
256} 296}
257 297
298static int ftrace_event_enable_disable(struct ftrace_event_file *file,
299 int enable)
300{
301 return __ftrace_event_enable_disable(file, enable, 0);
302}
303
258static void ftrace_clear_events(struct trace_array *tr) 304static void ftrace_clear_events(struct trace_array *tr)
259{ 305{
260 struct ftrace_event_file *file; 306 struct ftrace_event_file *file;
@@ -547,12 +593,15 @@ event_enable_read(struct file *filp, char __user *ubuf, size_t cnt,
547 struct ftrace_event_file *file = filp->private_data; 593 struct ftrace_event_file *file = filp->private_data;
548 char *buf; 594 char *buf;
549 595
550 if (file->flags & FTRACE_EVENT_FL_ENABLED) 596 if (file->flags & FTRACE_EVENT_FL_ENABLED) {
551 buf = "1\n"; 597 if (file->flags & FTRACE_EVENT_FL_SOFT_DISABLED)
552 else 598 buf = "0*\n";
599 else
600 buf = "1\n";
601 } else
553 buf = "0\n"; 602 buf = "0\n";
554 603
555 return simple_read_from_buffer(ubuf, cnt, ppos, buf, 2); 604 return simple_read_from_buffer(ubuf, cnt, ppos, buf, strlen(buf));
556} 605}
557 606
558static ssize_t 607static ssize_t