diff options
-rw-r--r-- | include/linux/ftrace_event.h | 20 | ||||
-rw-r--r-- | include/trace/ftrace.h | 8 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 75 |
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; | |||
251 | enum { | 251 | enum { |
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 | */ |
261 | enum { | 266 | enum { |
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 | ||
266 | struct ftrace_event_file { | 273 | struct 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 | ||
217 | static int ftrace_event_enable_disable(struct ftrace_event_file *file, | 217 | static 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 | ||
298 | static 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 | |||
258 | static void ftrace_clear_events(struct trace_array *tr) | 304 | static 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 | ||
558 | static ssize_t | 607 | static ssize_t |