blob: f4c245a5cd3387a42b9b335255742662ba40927c [file] [log] [blame]
Lai Jiangshan1427cdf2009-03-06 17:21:47 +01001/*
2 * trace binary printk
3 *
4 * Copyright (C) 2008 Lai Jiangshan <laijs@cn.fujitsu.com>
5 *
6 */
7#include <linux/kernel.h>
8#include <linux/ftrace.h>
9#include <linux/string.h>
10#include <linux/ctype.h>
11#include <linux/list.h>
12#include <linux/mutex.h>
13#include <linux/slab.h>
14#include <linux/module.h>
15#include <linux/seq_file.h>
16#include <linux/fs.h>
17#include <linux/marker.h>
18#include <linux/uaccess.h>
19
20#include "trace.h"
21
Lai Jiangshan1ba28e02009-03-06 17:21:48 +010022#ifdef CONFIG_MODULES
23
Lai Jiangshan1427cdf2009-03-06 17:21:47 +010024/* binary printk basic */
25static DEFINE_MUTEX(btrace_mutex);
Lai Jiangshan1ba28e02009-03-06 17:21:48 +010026/*
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
Lai Jiangshan1427cdf2009-03-06 17:21:47 +010037
38static inline void lock_btrace(void)
39{
40 mutex_lock(&btrace_mutex);
41}
42
43static inline void unlock_btrace(void)
44{
45 mutex_unlock(&btrace_mutex);
46}
47
Lai Jiangshan1ba28e02009-03-06 17:21:48 +010048
49static inline struct trace_bprintk_fmt *lookup_format(const char *fmt)
Lai Jiangshan1427cdf2009-03-06 17:21:47 +010050{
Lai Jiangshan1ba28e02009-03-06 17:21:48 +010051 struct trace_bprintk_fmt *pos;
52 list_for_each_entry(pos, &trace_bprintk_fmt_list, list) {
53 if (!strcmp(pos->fmt, fmt))
54 return pos;
55 }
56 return NULL;
57}
58
59static
60void hold_module_trace_bprintk_format(const char **start, const char **end)
61{
62 const char **iter;
Lai Jiangshan1427cdf2009-03-06 17:21:47 +010063 lock_btrace();
Lai Jiangshan1ba28e02009-03-06 17:21:48 +010064 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 }
Lai Jiangshan1427cdf2009-03-06 17:21:47 +010080 unlock_btrace();
81}
82
Lai Jiangshan1ba28e02009-03-06 17:21:48 +010083static int module_trace_bprintk_format_notify(struct notifier_block *self,
84 unsigned long val, void *data)
Lai Jiangshan1427cdf2009-03-06 17:21:47 +010085{
Lai Jiangshan1ba28e02009-03-06 17:21:48 +010086 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;
Lai Jiangshan1427cdf2009-03-06 17:21:47 +010095}
96
Lai Jiangshan1ba28e02009-03-06 17:21:48 +010097#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
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100112/* events tracer */
113int trace_bprintk_enable;
114
115static void start_bprintk_trace(struct trace_array *tr)
116{
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100117 tracing_reset_online_cpus(tr);
118 trace_bprintk_enable = 1;
119}
120
121static void stop_bprintk_trace(struct trace_array *tr)
122{
123 trace_bprintk_enable = 0;
124 tracing_reset_online_cpus(tr);
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100125}
126
127static int init_bprintk_trace(struct trace_array *tr)
128{
129 start_bprintk_trace(tr);
130 return 0;
131}
132
133static struct tracer bprintk_trace __read_mostly =
134{
135 .name = "events",
136 .init = init_bprintk_trace,
137 .reset = stop_bprintk_trace,
138 .start = start_bprintk_trace,
139 .stop = stop_bprintk_trace,
140};
141
142static __init int init_bprintk(void)
143{
Lai Jiangshan1ba28e02009-03-06 17:21:48 +0100144 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;
Lai Jiangshan1427cdf2009-03-06 17:21:47 +0100152}
153
154device_initcall(init_bprintk);