aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorSteven Rostedt <srostedt@redhat.com>2008-05-12 15:20:45 -0400
committerThomas Gleixner <tglx@linutronix.de>2008-05-23 14:41:06 -0400
commit77a2b37d227483fe52aead242652aee406c25bf0 (patch)
treececb6a3a02a567530e2ce3502de18f371c9db7c1
parent7bd2f24c2f769e3f8f1d4fc8b9fddf689825f6a7 (diff)
ftrace: startup tester on dynamic tracing.
This patch adds a startup self test on dynamic code modification and filters. The test filters on a specific function, makes sure that no other function is traced, exectutes the function, then makes sure that the function is traced. This patch also fixes a slight bug with the ftrace selftest, where tracer_enabled was not being set. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
-rw-r--r--include/linux/ftrace.h2
-rw-r--r--kernel/trace/ftrace.c19
-rw-r--r--kernel/trace/trace_selftest.c113
3 files changed, 130 insertions, 4 deletions
diff --git a/include/linux/ftrace.h b/include/linux/ftrace.h
index 953a36d6a199..a842d96c6343 100644
--- a/include/linux/ftrace.h
+++ b/include/linux/ftrace.h
@@ -55,6 +55,7 @@ struct dyn_ftrace {
55}; 55};
56 56
57int ftrace_force_update(void); 57int ftrace_force_update(void);
58void ftrace_set_filter(unsigned char *buf, int len, int reset);
58 59
59/* defined in arch */ 60/* defined in arch */
60extern int ftrace_ip_converted(unsigned long ip); 61extern int ftrace_ip_converted(unsigned long ip);
@@ -70,6 +71,7 @@ extern void ftrace_call(void);
70extern void mcount_call(void); 71extern void mcount_call(void);
71#else 72#else
72# define ftrace_force_update() ({ 0; }) 73# define ftrace_force_update() ({ 0; })
74# define ftrace_set_filter(buf, len, reset) do { } while (0)
73#endif 75#endif
74 76
75static inline void tracer_disable(void) 77static inline void tracer_disable(void)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 6d4d2e86debc..5e9389faaf75 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -1010,6 +1010,25 @@ ftrace_filter_write(struct file *file, const char __user *ubuf,
1010 return ret; 1010 return ret;
1011} 1011}
1012 1012
1013/**
1014 * ftrace_set_filter - set a function to filter on in ftrace
1015 * @buf - the string that holds the function filter text.
1016 * @len - the length of the string.
1017 * @reset - non zero to reset all filters before applying this filter.
1018 *
1019 * Filters denote which functions should be enabled when tracing is enabled.
1020 * If @buf is NULL and reset is set, all functions will be enabled for tracing.
1021 */
1022notrace void ftrace_set_filter(unsigned char *buf, int len, int reset)
1023{
1024 mutex_lock(&ftrace_filter_lock);
1025 if (reset)
1026 ftrace_filter_reset();
1027 if (buf)
1028 ftrace_match(buf, len);
1029 mutex_unlock(&ftrace_filter_lock);
1030}
1031
1013static int notrace 1032static int notrace
1014ftrace_filter_release(struct inode *inode, struct file *file) 1033ftrace_filter_release(struct inode *inode, struct file *file)
1015{ 1034{
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c
index c01874c3b1f9..4c8a1b2d8231 100644
--- a/kernel/trace/trace_selftest.c
+++ b/kernel/trace/trace_selftest.c
@@ -99,6 +99,100 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
99} 99}
100 100
101#ifdef CONFIG_FTRACE 101#ifdef CONFIG_FTRACE
102
103#ifdef CONFIG_DYNAMIC_FTRACE
104
105#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
106#define __STR(x) #x
107#define STR(x) __STR(x)
108static int DYN_FTRACE_TEST_NAME(void)
109{
110 /* used to call mcount */
111 return 0;
112}
113
114/* Test dynamic code modification and ftrace filters */
115int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
116 struct trace_array *tr,
117 int (*func)(void))
118{
119 unsigned long count;
120 int ret;
121 int save_ftrace_enabled = ftrace_enabled;
122 int save_tracer_enabled = tracer_enabled;
123
124 /* The ftrace test PASSED */
125 printk(KERN_CONT "PASSED\n");
126 pr_info("Testing dynamic ftrace: ");
127
128 /* enable tracing, and record the filter function */
129 ftrace_enabled = 1;
130 tracer_enabled = 1;
131
132 /* passed in by parameter to fool gcc from optimizing */
133 func();
134
135 /* update the records */
136 ret = ftrace_force_update();
137 if (ret) {
138 printk(KERN_CONT ".. ftraced failed .. ");
139 return ret;
140 }
141
142 /* filter only on our function */
143 ftrace_set_filter(STR(DYN_FTRACE_TEST_NAME),
144 sizeof(STR(DYN_FTRACE_TEST_NAME)), 1);
145
146 /* enable tracing */
147 tr->ctrl = 1;
148 trace->init(tr);
149 /* Sleep for a 1/10 of a second */
150 msleep(100);
151
152 /* we should have nothing in the buffer */
153 ret = trace_test_buffer(tr, &count);
154 if (ret)
155 goto out;
156
157 if (count) {
158 ret = -1;
159 printk(KERN_CONT ".. filter did not filter .. ");
160 goto out;
161 }
162
163 /* call our function again */
164 func();
165
166 /* sleep again */
167 msleep(100);
168
169 /* stop the tracing. */
170 tr->ctrl = 0;
171 trace->ctrl_update(tr);
172 ftrace_enabled = 0;
173
174 /* check the trace buffer */
175 ret = trace_test_buffer(tr, &count);
176 trace->reset(tr);
177
178 /* we should only have one item */
179 if (!ret && count != 1) {
180 printk(KERN_CONT ".. filter failed ..");
181 ret = -1;
182 goto out;
183 }
184 out:
185 ftrace_enabled = save_ftrace_enabled;
186 tracer_enabled = save_tracer_enabled;
187
188 /* Enable tracing on all functions again */
189 ftrace_set_filter(NULL, 0, 1);
190
191 return ret;
192}
193#else
194# define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })
195#endif /* CONFIG_DYNAMIC_FTRACE */
102/* 196/*
103 * Simple verification test of ftrace function tracer. 197 * Simple verification test of ftrace function tracer.
104 * Enable ftrace, sleep 1/10 second, and then read the trace 198 * Enable ftrace, sleep 1/10 second, and then read the trace
@@ -109,8 +203,13 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
109{ 203{
110 unsigned long count; 204 unsigned long count;
111 int ret; 205 int ret;
206 int save_ftrace_enabled = ftrace_enabled;
207 int save_tracer_enabled = tracer_enabled;
112 208
113 /* make sure functions have been recorded */ 209 /* make sure msleep has been recorded */
210 msleep(1);
211
212 /* force the recorded functions to be traced */
114 ret = ftrace_force_update(); 213 ret = ftrace_force_update();
115 if (ret) { 214 if (ret) {
116 printk(KERN_CONT ".. ftraced failed .. "); 215 printk(KERN_CONT ".. ftraced failed .. ");
@@ -119,6 +218,7 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
119 218
120 /* start the tracing */ 219 /* start the tracing */
121 ftrace_enabled = 1; 220 ftrace_enabled = 1;
221 tracer_enabled = 1;
122 222
123 tr->ctrl = 1; 223 tr->ctrl = 1;
124 trace->init(tr); 224 trace->init(tr);
@@ -136,8 +236,16 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
136 if (!ret && !count) { 236 if (!ret && !count) {
137 printk(KERN_CONT ".. no entries found .."); 237 printk(KERN_CONT ".. no entries found ..");
138 ret = -1; 238 ret = -1;
239 goto out;
139 } 240 }
140 241
242 ret = trace_selftest_startup_dynamic_tracing(trace, tr,
243 DYN_FTRACE_TEST_NAME);
244
245 out:
246 ftrace_enabled = save_ftrace_enabled;
247 tracer_enabled = save_tracer_enabled;
248
141 return ret; 249 return ret;
142} 250}
143#endif /* CONFIG_FTRACE */ 251#endif /* CONFIG_FTRACE */
@@ -415,6 +523,3 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr
415 return ret; 523 return ret;
416} 524}
417#endif /* CONFIG_CONTEXT_SWITCH_TRACER */ 525#endif /* CONFIG_CONTEXT_SWITCH_TRACER */
418
419#ifdef CONFIG_DYNAMIC_FTRACE
420#endif /* CONFIG_DYNAMIC_FTRACE */