aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--include/linux/ftrace_event.h20
-rw-r--r--include/trace/ftrace.h8
-rw-r--r--kernel/trace/trace_events.c75
3 files changed, 84 insertions, 19 deletions
diff --git a/include/linux/ftrace_event.h b/include/linux/ftrace_event.h
index 4cb6cd8338a4..4e28b011e63b 100644
--- a/include/linux/ftrace_event.h
+++ b/include/linux/ftrace_event.h
@@ -251,16 +251,23 @@ struct ftrace_subsystem_dir;
251enum { 251enum {
252 FTRACE_EVENT_FL_ENABLED_BIT, 252 FTRACE_EVENT_FL_ENABLED_BIT,
253 FTRACE_EVENT_FL_RECORDED_CMD_BIT, 253 FTRACE_EVENT_FL_RECORDED_CMD_BIT,
254 FTRACE_EVENT_FL_SOFT_MODE_BIT,
255 FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
254}; 256};
255 257
256/* 258/*
257 * Ftrace event file flags: 259 * Ftrace event file flags:
258 * ENABLED - The event is enabled 260 * ENABLED - The event is enabled
259 * RECORDED_CMD - The comms should be recorded at sched_switch 261 * RECORDED_CMD - The comms should be recorded at sched_switch
262 * SOFT_MODE - The event is enabled/disabled by SOFT_DISABLED
263 * SOFT_DISABLED - When set, do not trace the event (even though its
264 * tracepoint may be enabled)
260 */ 265 */
261enum { 266enum {
262 FTRACE_EVENT_FL_ENABLED = (1 << FTRACE_EVENT_FL_ENABLED_BIT), 267 FTRACE_EVENT_FL_ENABLED = (1 << FTRACE_EVENT_FL_ENABLED_BIT),
263 FTRACE_EVENT_FL_RECORDED_CMD = (1 << FTRACE_EVENT_FL_RECORDED_CMD_BIT), 268 FTRACE_EVENT_FL_RECORDED_CMD = (1 << FTRACE_EVENT_FL_RECORDED_CMD_BIT),
269 FTRACE_EVENT_FL_SOFT_MODE = (1 << FTRACE_EVENT_FL_SOFT_MODE_BIT),
270 FTRACE_EVENT_FL_SOFT_DISABLED = (1 << FTRACE_EVENT_FL_SOFT_DISABLED_BIT),
264}; 271};
265 272
266struct ftrace_event_file { 273struct ftrace_event_file {
@@ -274,17 +281,18 @@ struct ftrace_event_file {
274 * 32 bit flags: 281 * 32 bit flags:
275 * bit 0: enabled 282 * bit 0: enabled
276 * bit 1: enabled cmd record 283 * bit 1: enabled cmd record
284 * bit 2: enable/disable with the soft disable bit
285 * bit 3: soft disabled
277 * 286 *
278 * Changes to flags must hold the event_mutex. 287 * Note: The bits must be set atomically to prevent races
279 * 288 * from other writers. Reads of flags do not need to be in
280 * Note: Reads of flags do not hold the event_mutex since 289 * sync as they occur in critical sections. But the way flags
281 * they occur in critical sections. But the way flags
282 * is currently used, these changes do not affect the code 290 * is currently used, these changes do not affect the code
283 * except that when a change is made, it may have a slight 291 * except that when a change is made, it may have a slight
284 * delay in propagating the changes to other CPUs due to 292 * delay in propagating the changes to other CPUs due to
285 * caching and such. 293 * caching and such. Which is mostly OK ;-)
286 */ 294 */
287 unsigned int flags; 295 unsigned long flags;
288}; 296};
289 297
290#define __TRACE_EVENT_FLAGS(name, value) \ 298#define __TRACE_EVENT_FLAGS(name, value) \
diff --git a/include/trace/ftrace.h b/include/trace/ftrace.h
index bbf09c2021b9..4bda044e6c77 100644
--- a/include/trace/ftrace.h
+++ b/include/trace/ftrace.h
@@ -413,6 +413,10 @@ static inline notrace int ftrace_get_offsets_##call( \
413 * int __data_size; 413 * int __data_size;
414 * int pc; 414 * int pc;
415 * 415 *
416 * if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT,
417 * &ftrace_file->flags))
418 * return;
419 *
416 * local_save_flags(irq_flags); 420 * local_save_flags(irq_flags);
417 * pc = preempt_count(); 421 * pc = preempt_count();
418 * 422 *
@@ -518,6 +522,10 @@ ftrace_raw_event_##call(void *__data, proto) \
518 int __data_size; \ 522 int __data_size; \
519 int pc; \ 523 int pc; \
520 \ 524 \
525 if (test_bit(FTRACE_EVENT_FL_SOFT_DISABLED_BIT, \
526 &ftrace_file->flags)) \
527 return; \
528 \
521 local_save_flags(irq_flags); \ 529 local_save_flags(irq_flags); \
522 pc = preempt_count(); \ 530 pc = preempt_count(); \
523 \ 531 \
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