aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorLai Jiangshan <laijs@cn.fujitsu.com>2009-03-06 11:21:48 -0500
committerIngo Molnar <mingo@elte.hu>2009-03-06 11:59:11 -0500
commit1ba28e02a18cbdbea123836f6c98efb09cbf59ec (patch)
tree41df06a06c702152902ffd7250f284a6efe9b0da
parent1427cdf0592368bdec57276edaf714040ee8744f (diff)
tracing: add trace_bprintk()
Impact: add a generic printk() for tracing, like trace_printk() trace_bprintk() uses the infrastructure to record events on ring_buffer. [ fweisbec@gmail.com: ported to latest -tip, made it work if !CONFIG_MODULES, never free the format strings from modules because we can't keep track of them and conditionnaly create the ftrace format strings section (reported by Steven Rostedt) ] Signed-off-by: Lai Jiangshan <laijs@cn.fujitsu.com> Signed-off-by: Frederic Weisbecker <fweisbec@gmail.com> Acked-by: Steven Rostedt <rostedt@goodmis.org> LKML-Reference: <1236356510-8381-4-git-send-email-fweisbec@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r--include/asm-generic/vmlinux.lds.h9
-rw-r--r--include/linux/ftrace.h21
-rw-r--r--include/linux/module.h5
-rw-r--r--kernel/module.c6
-rw-r--r--kernel/trace/trace.c15
-rw-r--r--kernel/trace/trace_bprintk.c87
6 files changed, 133 insertions, 10 deletions
diff --git a/include/asm-generic/vmlinux.lds.h b/include/asm-generic/vmlinux.lds.h
index 0add6b28c366..48ade3168b13 100644
--- a/include/asm-generic/vmlinux.lds.h
+++ b/include/asm-generic/vmlinux.lds.h
@@ -69,6 +69,14 @@
69#define FTRACE_EVENTS() 69#define FTRACE_EVENTS()
70#endif 70#endif
71 71
72#ifdef CONFIG_TRACING
73#define TRACE_PRINTKS() VMLINUX_SYMBOL(__start___trace_bprintk_fmt) = .; \
74 *(__trace_printk_fmt) /* Trace_printk fmt' pointer */ \
75 VMLINUX_SYMBOL(__stop___trace_bprintk_fmt) = .;
76#else
77#define TRACE_PRINTKS()
78#endif
79
72/* .data section */ 80/* .data section */
73#define DATA_DATA \ 81#define DATA_DATA \
74 *(.data) \ 82 *(.data) \
@@ -100,6 +108,7 @@
100 *(__vermagic) /* Kernel version magic */ \ 108 *(__vermagic) /* Kernel version magic */ \
101 *(__markers_strings) /* Markers: strings */ \ 109 *(__markers_strings) /* Markers: strings */ \
102 *(__tracepoints_strings)/* Tracepoints: strings */ \ 110 *(__tracepoints_strings)/* Tracepoints: strings */ \
111 TRACE_PRINTKS() \
103 } \ 112 } \
104 \ 113 \
105 .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \ 114 .rodata1 : AT(ADDR(.rodata1) - LOAD_OFFSET) { \
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 1c9cdca02580..1cc8ca453a9b 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -225,6 +225,27 @@ extern int ftrace_make_call(struct dyn_ftrace *rec, unsigned long addr);
225 225
226#ifdef CONFIG_TRACE_BPRINTK 226#ifdef CONFIG_TRACE_BPRINTK
227extern int trace_vbprintk(unsigned long ip, const char *fmt, va_list args); 227extern int trace_vbprintk(unsigned long ip, const char *fmt, va_list args);
228extern int __trace_bprintk(unsigned long ip, const char *fmt, ...)
229 __attribute__ ((format (printf, 2, 3)));
230
231static inline void ____trace_bprintk_check_format(const char *fmt, ...)
232 __attribute__ ((format (printf, 1, 2)));
233static inline void ____trace_bprintk_check_format(const char *fmt, ...) {}
234#define __trace_bprintk_check_format(fmt, args...) \
235do { \
236 if (0) \
237 ____trace_bprintk_check_format(fmt, ##args); \
238} while (0)
239
240#define trace_bprintk(fmt, args...) \
241do { \
242 static char *__attribute__((section("__trace_bprintk_fmt"))) \
243 trace_bprintk_fmt = fmt; \
244 __trace_bprintk_check_format(fmt, ##args); \
245 __trace_bprintk(_THIS_IP_, trace_bprintk_fmt, ##args); \
246} while (0)
247#else
248#define trace_bprintk trace_printk
228#endif 249#endif
229 250
230/* May be defined in arch */ 251/* May be defined in arch */
diff --git a/include/linux/module.h b/include/linux/module.h
index 145a75528cc1..8cbec972d8e7 100644
--- a/include/linux/module.h
+++ b/include/linux/module.h
@@ -329,6 +329,11 @@ struct module
329 unsigned int num_tracepoints; 329 unsigned int num_tracepoints;
330#endif 330#endif
331 331
332#ifdef CONFIG_TRACE_BPRINTK
333 const char **trace_bprintk_fmt_start;
334 unsigned int num_trace_bprintk_fmt;
335#endif
336
332#ifdef CONFIG_MODULE_UNLOAD 337#ifdef CONFIG_MODULE_UNLOAD
333 /* What modules depend on me? */ 338 /* What modules depend on me? */
334 struct list_head modules_which_use_me; 339 struct list_head modules_which_use_me;
diff --git a/kernel/module.c b/kernel/module.c
index 22d7379709da..2dece104f9a1 100644
--- a/kernel/module.c
+++ b/kernel/module.c
@@ -2158,6 +2158,12 @@ static noinline struct module *load_module(void __user *umod,
2158 &mod->num_tracepoints); 2158 &mod->num_tracepoints);
2159#endif 2159#endif
2160 2160
2161#ifdef CONFIG_TRACE_BPRINTK
2162 mod->trace_bprintk_fmt_start = section_objs(hdr, sechdrs, secstrings,
2163 "__trace_bprintk_fmt", sizeof(char *),
2164 &mod->num_trace_bprintk_fmt);
2165#endif
2166
2161#ifdef CONFIG_MODVERSIONS 2167#ifdef CONFIG_MODVERSIONS
2162 if ((mod->num_syms && !mod->crcs) 2168 if ((mod->num_syms && !mod->crcs)
2163 || (mod->num_gpl_syms && !mod->gpl_crcs) 2169 || (mod->num_gpl_syms && !mod->gpl_crcs)
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index ff53509e19f8..46b3cd7a5752 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -3848,6 +3848,21 @@ out:
3848} 3848}
3849EXPORT_SYMBOL_GPL(trace_vbprintk); 3849EXPORT_SYMBOL_GPL(trace_vbprintk);
3850 3850
3851int __trace_bprintk(unsigned long ip, const char *fmt, ...)
3852{
3853 int ret;
3854 va_list ap;
3855
3856 if (!fmt)
3857 return 0;
3858
3859 va_start(ap, fmt);
3860 ret = trace_vbprintk(ip, fmt, ap);
3861 va_end(ap);
3862 return ret;
3863}
3864EXPORT_SYMBOL_GPL(__trace_bprintk);
3865
3851static int trace_panic_handler(struct notifier_block *this, 3866static int trace_panic_handler(struct notifier_block *this,
3852 unsigned long event, void *unused) 3867 unsigned long event, void *unused)
3853{ 3868{
diff --git a/kernel/trace/trace_bprintk.c b/kernel/trace/trace_bprintk.c
index 1f8e532c3fb9..f4c245a5cd33 100644
--- a/kernel/trace/trace_bprintk.c
+++ b/kernel/trace/trace_bprintk.c
@@ -19,9 +19,21 @@
19 19
20#include "trace.h" 20#include "trace.h"
21 21
22#ifdef CONFIG_MODULES
23
22/* binary printk basic */ 24/* binary printk basic */
23static DEFINE_MUTEX(btrace_mutex); 25static DEFINE_MUTEX(btrace_mutex);
24static int btrace_metadata_count; 26/*
27 * modules trace_bprintk()'s formats are autosaved in struct trace_bprintk_fmt
28 * which are queued on trace_bprintk_fmt_list.
29 */
30static LIST_HEAD(trace_bprintk_fmt_list);
31
32struct trace_bprintk_fmt {
33 struct list_head list;
34 char fmt[0];
35};
36
25 37
26static inline void lock_btrace(void) 38static inline void lock_btrace(void)
27{ 39{
@@ -33,26 +45,75 @@ static inline void unlock_btrace(void)
33 mutex_unlock(&btrace_mutex); 45 mutex_unlock(&btrace_mutex);
34} 46}
35 47
36static void get_btrace_metadata(void) 48
49static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
37{ 50{
38 lock_btrace(); 51 struct trace_bprintk_fmt *pos;
39 btrace_metadata_count++; 52 list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
40 unlock_btrace(); 53 if (!strcmp(pos->fmt, fmt))
54 return pos;
55 }
56 return NULL;
41} 57}
42 58
43static void put_btrace_metadata(void) 59static
60void hold_module_trace_bprintk_format(const char **start, const char **end)
44{ 61{
62 const char **iter;
45 lock_btrace(); 63 lock_btrace();
46 btrace_metadata_count--; 64 for (iter = start; iter < end; iter++) {
65 struct trace_bprintk_fmt *tb_fmt = lookup_format(*iter);
66 if (tb_fmt) {
67 *iter = tb_fmt->fmt;
68 continue;
69 }
70
71 tb_fmt = kmalloc(offsetof(struct trace_bprintk_fmt, fmt)
72 + strlen(*iter) + 1, GFP_KERNEL);
73 if (tb_fmt) {
74 list_add_tail(&tb_fmt->list, &trace_bprintk_fmt_list);
75 strcpy(tb_fmt->fmt, *iter);
76 *iter = tb_fmt->fmt;
77 } else
78 *iter = NULL;
79 }
47 unlock_btrace(); 80 unlock_btrace();
48} 81}
49 82
83static int module_trace_bprintk_format_notify(struct notifier_block *self,
84 unsigned long val, void *data)
85{
86 struct module *mod = data;
87 if (mod->num_trace_bprintk_fmt) {
88 const char **start = mod->trace_bprintk_fmt_start;
89 const char **end = start + mod->num_trace_bprintk_fmt;
90
91 if (val == MODULE_STATE_COMING)
92 hold_module_trace_bprintk_format(start, end);
93 }
94 return 0;
95}
96
97#else /* !CONFIG_MODULES */
98__init static int
99module_trace_bprintk_format_notify(struct notifier_block *self,
100 unsigned long val, void *data)
101{
102 return 0;
103}
104#endif /* CONFIG_MODULES */
105
106
107__initdata_or_module static
108struct notifier_block module_trace_bprintk_format_nb = {
109 .notifier_call = module_trace_bprintk_format_notify,
110};
111
50/* events tracer */ 112/* events tracer */
51int trace_bprintk_enable; 113int trace_bprintk_enable;
52 114
53static void start_bprintk_trace(struct trace_array *tr) 115static void start_bprintk_trace(struct trace_array *tr)
54{ 116{
55 get_btrace_metadata();
56 tracing_reset_online_cpus(tr); 117 tracing_reset_online_cpus(tr);
57 trace_bprintk_enable = 1; 118 trace_bprintk_enable = 1;
58} 119}
@@ -61,7 +122,6 @@ static void stop_bprintk_trace(struct trace_array *tr)
61{ 122{
62 trace_bprintk_enable = 0; 123 trace_bprintk_enable = 0;
63 tracing_reset_online_cpus(tr); 124 tracing_reset_online_cpus(tr);
64 put_btrace_metadata();
65} 125}
66 126
67static int init_bprintk_trace(struct trace_array *tr) 127static int init_bprintk_trace(struct trace_array *tr)
@@ -81,7 +141,14 @@ static struct tracer bprintk_trace __read_mostly =
81 141
82static __init int init_bprintk(void) 142static __init int init_bprintk(void)
83{ 143{
84 return register_tracer(&bprintk_trace); 144 int ret = register_module_notifier(&module_trace_bprintk_format_nb);
145 if (ret)
146 return ret;
147
148 ret = register_tracer(&bprintk_trace);
149 if (ret)
150 unregister_module_notifier(&module_trace_bprintk_format_nb);
151 return ret;
85} 152}
86 153
87device_initcall(init_bprintk); 154device_initcall(init_bprintk);