diff options
| author | Steven Rostedt (Red Hat) <rostedt@goodmis.org> | 2014-12-12 22:27:10 -0500 |
|---|---|---|
| committer | Steven Rostedt <rostedt@goodmis.org> | 2014-12-15 10:17:38 -0500 |
| commit | 0daa2302968c13b657118d6ac92471f8fd2f3f28 (patch) | |
| tree | 8bea68f7bbeab6521c11c01f55b5660082eeedf6 /kernel | |
| parent | 5f893b2639b21ffe6834b1aebba392c37d2b83f9 (diff) | |
tracing: Add tp_printk cmdline to have tracepoints go to printk()
Add the kernel command line tp_printk option that will have tracepoints
that are active sent to printk() as well as to the trace buffer.
Passing "tp_printk" will activate this. To turn it off, the sysctl
/proc/sys/kernel/tracepoint_printk can have '0' echoed into it. Note,
this only works if the cmdline option is used. Echoing 1 into the sysctl
file without the cmdline option will have no affect.
Note, this is a dangerous option. Having high frequency tracepoints send
their data to printk() can possibly cause a live lock. This is another
reason why this is only active if the command line option is used.
Link: http://lkml.kernel.org/r/alpine.DEB.2.11.1412121539300.16494@nanos
Suggested-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Thomas Gleixner <tglx@linutronix.de>
Acked-by: Thomas Gleixner <tglx@linutronix.de>
Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
Diffstat (limited to 'kernel')
| -rw-r--r-- | kernel/sysctl.c | 7 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 17 | ||||
| -rw-r--r-- | kernel/trace/trace.h | 1 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 32 |
4 files changed, 57 insertions, 0 deletions
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 4aada6d9fe74..bb50c2187194 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
| @@ -622,6 +622,13 @@ static struct ctl_table kern_table[] = { | |||
| 622 | .mode = 0644, | 622 | .mode = 0644, |
| 623 | .proc_handler = proc_dointvec, | 623 | .proc_handler = proc_dointvec, |
| 624 | }, | 624 | }, |
| 625 | { | ||
| 626 | .procname = "tracepoint_printk", | ||
| 627 | .data = &tracepoint_printk, | ||
| 628 | .maxlen = sizeof(tracepoint_printk), | ||
| 629 | .mode = 0644, | ||
| 630 | .proc_handler = proc_dointvec, | ||
| 631 | }, | ||
| 625 | #endif | 632 | #endif |
| 626 | #ifdef CONFIG_KEXEC | 633 | #ifdef CONFIG_KEXEC |
| 627 | { | 634 | { |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index ec3ca694665f..e890d2d4ec89 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
| @@ -63,6 +63,10 @@ static bool __read_mostly tracing_selftest_running; | |||
| 63 | */ | 63 | */ |
| 64 | bool __read_mostly tracing_selftest_disabled; | 64 | bool __read_mostly tracing_selftest_disabled; |
| 65 | 65 | ||
| 66 | /* Pipe tracepoints to printk */ | ||
| 67 | struct trace_iterator *tracepoint_print_iter; | ||
| 68 | int tracepoint_printk; | ||
| 69 | |||
| 66 | /* For tracers that don't implement custom flags */ | 70 | /* For tracers that don't implement custom flags */ |
| 67 | static struct tracer_opt dummy_tracer_opt[] = { | 71 | static struct tracer_opt dummy_tracer_opt[] = { |
| 68 | { } | 72 | { } |
| @@ -193,6 +197,13 @@ static int __init set_trace_boot_clock(char *str) | |||
| 193 | } | 197 | } |
| 194 | __setup("trace_clock=", set_trace_boot_clock); | 198 | __setup("trace_clock=", set_trace_boot_clock); |
| 195 | 199 | ||
| 200 | static int __init set_tracepoint_printk(char *str) | ||
| 201 | { | ||
| 202 | if ((strcmp(str, "=0") != 0 && strcmp(str, "=off") != 0)) | ||
| 203 | tracepoint_printk = 1; | ||
| 204 | return 1; | ||
| 205 | } | ||
| 206 | __setup("tp_printk", set_tracepoint_printk); | ||
| 196 | 207 | ||
| 197 | unsigned long long ns2usecs(cycle_t nsec) | 208 | unsigned long long ns2usecs(cycle_t nsec) |
| 198 | { | 209 | { |
| @@ -6878,6 +6889,12 @@ out: | |||
| 6878 | 6889 | ||
| 6879 | void __init trace_init(void) | 6890 | void __init trace_init(void) |
| 6880 | { | 6891 | { |
| 6892 | if (tracepoint_printk) { | ||
| 6893 | tracepoint_print_iter = | ||
| 6894 | kmalloc(sizeof(*tracepoint_print_iter), GFP_KERNEL); | ||
| 6895 | if (WARN_ON(!tracepoint_print_iter)) | ||
| 6896 | tracepoint_printk = 0; | ||
| 6897 | } | ||
| 6881 | tracer_alloc_buffers(); | 6898 | tracer_alloc_buffers(); |
| 6882 | init_ftrace_syscalls(); | 6899 | init_ftrace_syscalls(); |
| 6883 | trace_event_init(); | 6900 | trace_event_init(); |
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index c138c149d6ef..8de48bac1ce2 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h | |||
| @@ -1313,5 +1313,6 @@ void trace_event_init(void); | |||
| 1313 | static inline void __init trace_event_init(void) { } | 1313 | static inline void __init trace_event_init(void) { } |
| 1314 | #endif | 1314 | #endif |
| 1315 | 1315 | ||
| 1316 | extern struct trace_iterator *tracepoint_print_iter; | ||
| 1316 | 1317 | ||
| 1317 | #endif /* _LINUX_KERNEL_TRACE_H */ | 1318 | #endif /* _LINUX_KERNEL_TRACE_H */ |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index fd9deb0e03f0..9f7175a3df71 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
| @@ -212,8 +212,40 @@ void *ftrace_event_buffer_reserve(struct ftrace_event_buffer *fbuffer, | |||
| 212 | } | 212 | } |
| 213 | EXPORT_SYMBOL_GPL(ftrace_event_buffer_reserve); | 213 | EXPORT_SYMBOL_GPL(ftrace_event_buffer_reserve); |
| 214 | 214 | ||
| 215 | static DEFINE_SPINLOCK(tracepoint_iter_lock); | ||
| 216 | |||
| 217 | static void output_printk(struct ftrace_event_buffer *fbuffer) | ||
| 218 | { | ||
| 219 | struct ftrace_event_call *event_call; | ||
| 220 | struct trace_event *event; | ||
| 221 | unsigned long flags; | ||
| 222 | struct trace_iterator *iter = tracepoint_print_iter; | ||
| 223 | |||
| 224 | if (!iter) | ||
| 225 | return; | ||
| 226 | |||
| 227 | event_call = fbuffer->ftrace_file->event_call; | ||
| 228 | if (!event_call || !event_call->event.funcs || | ||
| 229 | !event_call->event.funcs->trace) | ||
| 230 | return; | ||
| 231 | |||
| 232 | event = &fbuffer->ftrace_file->event_call->event; | ||
| 233 | |||
| 234 | spin_lock_irqsave(&tracepoint_iter_lock, flags); | ||
| 235 | trace_seq_init(&iter->seq); | ||
| 236 | iter->ent = fbuffer->entry; | ||
| 237 | event_call->event.funcs->trace(iter, 0, event); | ||
| 238 | trace_seq_putc(&iter->seq, 0); | ||
| 239 | printk("%s", iter->seq.buffer); | ||
| 240 | |||
| 241 | spin_unlock_irqrestore(&tracepoint_iter_lock, flags); | ||
| 242 | } | ||
| 243 | |||
| 215 | void ftrace_event_buffer_commit(struct ftrace_event_buffer *fbuffer) | 244 | void ftrace_event_buffer_commit(struct ftrace_event_buffer *fbuffer) |
| 216 | { | 245 | { |
| 246 | if (tracepoint_printk) | ||
| 247 | output_printk(fbuffer); | ||
| 248 | |||
| 217 | event_trigger_unlock_commit(fbuffer->ftrace_file, fbuffer->buffer, | 249 | event_trigger_unlock_commit(fbuffer->ftrace_file, fbuffer->buffer, |
| 218 | fbuffer->event, fbuffer->entry, | 250 | fbuffer->event, fbuffer->entry, |
| 219 | fbuffer->flags, fbuffer->pc); | 251 | fbuffer->flags, fbuffer->pc); |
