diff options
-rw-r--r-- | include/linux/ftrace.h | 4 | ||||
-rw-r--r-- | kernel/sysctl.c | 2 | ||||
-rw-r--r-- | kernel/trace/trace.c | 78 | ||||
-rw-r--r-- | kernel/trace/trace_events.c | 40 |
4 files changed, 83 insertions, 41 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h index b3d34d3e0e7e..8700049fd0e5 100644 --- a/include/linux/ftrace.h +++ b/include/linux/ftrace.h | |||
@@ -945,6 +945,10 @@ extern int __disable_trace_on_warning; | |||
945 | #define INIT_TRACE_RECURSION .trace_recursion = 0, | 945 | #define INIT_TRACE_RECURSION .trace_recursion = 0, |
946 | #endif | 946 | #endif |
947 | 947 | ||
948 | int tracepoint_printk_sysctl(struct ctl_table *table, int write, | ||
949 | void __user *buffer, size_t *lenp, | ||
950 | loff_t *ppos); | ||
951 | |||
948 | #else /* CONFIG_TRACING */ | 952 | #else /* CONFIG_TRACING */ |
949 | static inline void disable_trace_on_warning(void) { } | 953 | static inline void disable_trace_on_warning(void) { } |
950 | #endif /* CONFIG_TRACING */ | 954 | #endif /* CONFIG_TRACING */ |
diff --git a/kernel/sysctl.c b/kernel/sysctl.c index 706309f9ed84..6ccc60dfbc7a 100644 --- a/kernel/sysctl.c +++ b/kernel/sysctl.c | |||
@@ -634,7 +634,7 @@ static struct ctl_table kern_table[] = { | |||
634 | .data = &tracepoint_printk, | 634 | .data = &tracepoint_printk, |
635 | .maxlen = sizeof(tracepoint_printk), | 635 | .maxlen = sizeof(tracepoint_printk), |
636 | .mode = 0644, | 636 | .mode = 0644, |
637 | .proc_handler = proc_dointvec, | 637 | .proc_handler = tracepoint_printk_sysctl, |
638 | }, | 638 | }, |
639 | #endif | 639 | #endif |
640 | #ifdef CONFIG_KEXEC_CORE | 640 | #ifdef CONFIG_KEXEC_CORE |
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 490533726b54..725e8b2c453f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c | |||
@@ -69,6 +69,7 @@ bool __read_mostly tracing_selftest_disabled; | |||
69 | /* Pipe tracepoints to printk */ | 69 | /* Pipe tracepoints to printk */ |
70 | struct trace_iterator *tracepoint_print_iter; | 70 | struct trace_iterator *tracepoint_print_iter; |
71 | int tracepoint_printk; | 71 | int tracepoint_printk; |
72 | static DEFINE_STATIC_KEY_FALSE(tracepoint_printk_key); | ||
72 | 73 | ||
73 | /* For tracers that don't implement custom flags */ | 74 | /* For tracers that don't implement custom flags */ |
74 | static struct tracer_opt dummy_tracer_opt[] = { | 75 | static struct tracer_opt dummy_tracer_opt[] = { |
@@ -2116,6 +2117,81 @@ trace_event_buffer_lock_reserve(struct ring_buffer **current_rb, | |||
2116 | } | 2117 | } |
2117 | EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve); | 2118 | EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve); |
2118 | 2119 | ||
2120 | static DEFINE_SPINLOCK(tracepoint_iter_lock); | ||
2121 | static DEFINE_MUTEX(tracepoint_printk_mutex); | ||
2122 | |||
2123 | static void output_printk(struct trace_event_buffer *fbuffer) | ||
2124 | { | ||
2125 | struct trace_event_call *event_call; | ||
2126 | struct trace_event *event; | ||
2127 | unsigned long flags; | ||
2128 | struct trace_iterator *iter = tracepoint_print_iter; | ||
2129 | |||
2130 | /* We should never get here if iter is NULL */ | ||
2131 | if (WARN_ON_ONCE(!iter)) | ||
2132 | return; | ||
2133 | |||
2134 | event_call = fbuffer->trace_file->event_call; | ||
2135 | if (!event_call || !event_call->event.funcs || | ||
2136 | !event_call->event.funcs->trace) | ||
2137 | return; | ||
2138 | |||
2139 | event = &fbuffer->trace_file->event_call->event; | ||
2140 | |||
2141 | spin_lock_irqsave(&tracepoint_iter_lock, flags); | ||
2142 | trace_seq_init(&iter->seq); | ||
2143 | iter->ent = fbuffer->entry; | ||
2144 | event_call->event.funcs->trace(iter, 0, event); | ||
2145 | trace_seq_putc(&iter->seq, 0); | ||
2146 | printk("%s", iter->seq.buffer); | ||
2147 | |||
2148 | spin_unlock_irqrestore(&tracepoint_iter_lock, flags); | ||
2149 | } | ||
2150 | |||
2151 | int tracepoint_printk_sysctl(struct ctl_table *table, int write, | ||
2152 | void __user *buffer, size_t *lenp, | ||
2153 | loff_t *ppos) | ||
2154 | { | ||
2155 | int save_tracepoint_printk; | ||
2156 | int ret; | ||
2157 | |||
2158 | mutex_lock(&tracepoint_printk_mutex); | ||
2159 | save_tracepoint_printk = tracepoint_printk; | ||
2160 | |||
2161 | ret = proc_dointvec(table, write, buffer, lenp, ppos); | ||
2162 | |||
2163 | /* | ||
2164 | * This will force exiting early, as tracepoint_printk | ||
2165 | * is always zero when tracepoint_printk_iter is not allocated | ||
2166 | */ | ||
2167 | if (!tracepoint_print_iter) | ||
2168 | tracepoint_printk = 0; | ||
2169 | |||
2170 | if (save_tracepoint_printk == tracepoint_printk) | ||
2171 | goto out; | ||
2172 | |||
2173 | if (tracepoint_printk) | ||
2174 | static_key_enable(&tracepoint_printk_key.key); | ||
2175 | else | ||
2176 | static_key_disable(&tracepoint_printk_key.key); | ||
2177 | |||
2178 | out: | ||
2179 | mutex_unlock(&tracepoint_printk_mutex); | ||
2180 | |||
2181 | return ret; | ||
2182 | } | ||
2183 | |||
2184 | void trace_event_buffer_commit(struct trace_event_buffer *fbuffer) | ||
2185 | { | ||
2186 | if (static_key_false(&tracepoint_printk_key.key)) | ||
2187 | output_printk(fbuffer); | ||
2188 | |||
2189 | event_trigger_unlock_commit(fbuffer->trace_file, fbuffer->buffer, | ||
2190 | fbuffer->event, fbuffer->entry, | ||
2191 | fbuffer->flags, fbuffer->pc); | ||
2192 | } | ||
2193 | EXPORT_SYMBOL_GPL(trace_event_buffer_commit); | ||
2194 | |||
2119 | void trace_buffer_unlock_commit_regs(struct trace_array *tr, | 2195 | void trace_buffer_unlock_commit_regs(struct trace_array *tr, |
2120 | struct ring_buffer *buffer, | 2196 | struct ring_buffer *buffer, |
2121 | struct ring_buffer_event *event, | 2197 | struct ring_buffer_event *event, |
@@ -7977,6 +8053,8 @@ void __init trace_init(void) | |||
7977 | kmalloc(sizeof(*tracepoint_print_iter), GFP_KERNEL); | 8053 | kmalloc(sizeof(*tracepoint_print_iter), GFP_KERNEL); |
7978 | if (WARN_ON(!tracepoint_print_iter)) | 8054 | if (WARN_ON(!tracepoint_print_iter)) |
7979 | tracepoint_printk = 0; | 8055 | tracepoint_printk = 0; |
8056 | else | ||
8057 | static_key_enable(&tracepoint_printk_key.key); | ||
7980 | } | 8058 | } |
7981 | tracer_alloc_buffers(); | 8059 | tracer_alloc_buffers(); |
7982 | trace_event_init(); | 8060 | trace_event_init(); |
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index ba67ede48822..d35fc2b0d304 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c | |||
@@ -283,46 +283,6 @@ void *trace_event_buffer_reserve(struct trace_event_buffer *fbuffer, | |||
283 | } | 283 | } |
284 | EXPORT_SYMBOL_GPL(trace_event_buffer_reserve); | 284 | EXPORT_SYMBOL_GPL(trace_event_buffer_reserve); |
285 | 285 | ||
286 | static DEFINE_SPINLOCK(tracepoint_iter_lock); | ||
287 | |||
288 | static void output_printk(struct trace_event_buffer *fbuffer) | ||
289 | { | ||
290 | struct trace_event_call *event_call; | ||
291 | struct trace_event *event; | ||
292 | unsigned long flags; | ||
293 | struct trace_iterator *iter = tracepoint_print_iter; | ||
294 | |||
295 | if (!iter) | ||
296 | return; | ||
297 | |||
298 | event_call = fbuffer->trace_file->event_call; | ||
299 | if (!event_call || !event_call->event.funcs || | ||
300 | !event_call->event.funcs->trace) | ||
301 | return; | ||
302 | |||
303 | event = &fbuffer->trace_file->event_call->event; | ||
304 | |||
305 | spin_lock_irqsave(&tracepoint_iter_lock, flags); | ||
306 | trace_seq_init(&iter->seq); | ||
307 | iter->ent = fbuffer->entry; | ||
308 | event_call->event.funcs->trace(iter, 0, event); | ||
309 | trace_seq_putc(&iter->seq, 0); | ||
310 | printk("%s", iter->seq.buffer); | ||
311 | |||
312 | spin_unlock_irqrestore(&tracepoint_iter_lock, flags); | ||
313 | } | ||
314 | |||
315 | void trace_event_buffer_commit(struct trace_event_buffer *fbuffer) | ||
316 | { | ||
317 | if (tracepoint_printk) | ||
318 | output_printk(fbuffer); | ||
319 | |||
320 | event_trigger_unlock_commit(fbuffer->trace_file, fbuffer->buffer, | ||
321 | fbuffer->event, fbuffer->entry, | ||
322 | fbuffer->flags, fbuffer->pc); | ||
323 | } | ||
324 | EXPORT_SYMBOL_GPL(trace_event_buffer_commit); | ||
325 | |||
326 | int trace_event_reg(struct trace_event_call *call, | 286 | int trace_event_reg(struct trace_event_call *call, |
327 | enum trace_reg type, void *data) | 287 | enum trace_reg type, void *data) |
328 | { | 288 | { |