diff options
-rw-r--r-- | Documentation/kernel-parameters.txt | 18 | ||||
-rw-r--r-- | include/linux/ftrace.h | 1 | ||||
-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 |
6 files changed, 76 insertions, 0 deletions
diff --git a/Documentation/kernel-parameters.txt b/Documentation/kernel-parameters.txt index 1d09eb37c562..ae41f1181e9a 100644 --- a/Documentation/kernel-parameters.txt +++ b/Documentation/kernel-parameters.txt | |||
@@ -3500,6 +3500,24 @@ bytes respectively. Such letter suffixes can also be entirely omitted. | |||
3500 | See also Documentation/trace/ftrace.txt "trace options" | 3500 | See also Documentation/trace/ftrace.txt "trace options" |
3501 | section. | 3501 | section. |
3502 | 3502 | ||
3503 | tp_printk[FTRACE] | ||
3504 | Have the tracepoints sent to printk as well as the | ||
3505 | tracing ring buffer. This is useful for early boot up | ||
3506 | where the system hangs or reboots and does not give the | ||
3507 | option for reading the tracing buffer or performing a | ||
3508 | ftrace_dump_on_oops. | ||
3509 | |||
3510 | To turn off having tracepoints sent to printk, | ||
3511 | echo 0 > /proc/sys/kernel/tracepoint_printk | ||
3512 | Note, echoing 1 into this file without the | ||
3513 | tracepoint_printk kernel cmdline option has no effect. | ||
3514 | |||
3515 | ** CAUTION ** | ||
3516 | |||
3517 | Having tracepoints sent to printk() and activating high | ||
3518 | frequency tracepoints such as irq or sched, can cause | ||
3519 | the system to live lock. | ||
3520 | |||
3503 | traceoff_on_warning | 3521 | traceoff_on_warning |
3504 | [FTRACE] enable this option to disable tracing when a | 3522 | [FTRACE] enable this option to disable tracing when a |
3505 | warning is hit. This turns off "tracing_on". Tracing can | 3523 | warning is hit. This turns off "tracing_on". Tracing can |
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index f4bc14b7d444..1da602982cf9 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -879,6 +879,7 @@ static inline int test_tsk_trace_graph(struct task_struct *tsk) | |||
879 | enum ftrace_dump_mode; | 879 | enum ftrace_dump_mode; |
880 | 880 | ||
881 | extern enum ftrace_dump_mode ftrace_dump_on_oops; | 881 | extern enum ftrace_dump_mode ftrace_dump_on_oops; |
882 | extern int tracepoint_printk; | ||
882 | 883 | ||
883 | extern void disable_trace_on_warning(void); | 884 | extern void disable_trace_on_warning(void); |
884 | extern int __disable_trace_on_warning; | 885 | extern int __disable_trace_on_warning; |
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); |