Skip to content

Commit 95950c2

Browse files
Steven Rostedtrostedt
authored andcommitted
ftrace: Add self-tests for multiple function trace users
Add some basic sanity tests for multiple users of the function tracer at startup. Signed-off-by: Steven Rostedt <[email protected]>
1 parent 936e074 commit 95950c2

File tree

3 files changed

+217
-1
lines changed

3 files changed

+217
-1
lines changed

kernel/trace/trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -419,6 +419,8 @@ extern void trace_find_cmdline(int pid, char comm[]);
419419
extern unsigned long ftrace_update_tot_cnt;
420420
#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
421421
extern int DYN_FTRACE_TEST_NAME(void);
422+
#define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
423+
extern int DYN_FTRACE_TEST_NAME2(void);
422424
#endif
423425

424426
extern int ring_buffer_expanded;

kernel/trace/trace_selftest.c

Lines changed: 209 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,206 @@ static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret)
101101

102102
#ifdef CONFIG_DYNAMIC_FTRACE
103103

104+
static int trace_selftest_test_probe1_cnt;
105+
static void trace_selftest_test_probe1_func(unsigned long ip,
106+
unsigned long pip)
107+
{
108+
trace_selftest_test_probe1_cnt++;
109+
}
110+
111+
static int trace_selftest_test_probe2_cnt;
112+
static void trace_selftest_test_probe2_func(unsigned long ip,
113+
unsigned long pip)
114+
{
115+
trace_selftest_test_probe2_cnt++;
116+
}
117+
118+
static int trace_selftest_test_probe3_cnt;
119+
static void trace_selftest_test_probe3_func(unsigned long ip,
120+
unsigned long pip)
121+
{
122+
trace_selftest_test_probe3_cnt++;
123+
}
124+
125+
static int trace_selftest_test_global_cnt;
126+
static void trace_selftest_test_global_func(unsigned long ip,
127+
unsigned long pip)
128+
{
129+
trace_selftest_test_global_cnt++;
130+
}
131+
132+
static int trace_selftest_test_dyn_cnt;
133+
static void trace_selftest_test_dyn_func(unsigned long ip,
134+
unsigned long pip)
135+
{
136+
trace_selftest_test_dyn_cnt++;
137+
}
138+
139+
static struct ftrace_ops test_probe1 = {
140+
.func = trace_selftest_test_probe1_func,
141+
};
142+
143+
static struct ftrace_ops test_probe2 = {
144+
.func = trace_selftest_test_probe2_func,
145+
};
146+
147+
static struct ftrace_ops test_probe3 = {
148+
.func = trace_selftest_test_probe3_func,
149+
};
150+
151+
static struct ftrace_ops test_global = {
152+
.func = trace_selftest_test_global_func,
153+
.flags = FTRACE_OPS_FL_GLOBAL,
154+
};
155+
156+
static void print_counts(void)
157+
{
158+
printk("(%d %d %d %d %d) ",
159+
trace_selftest_test_probe1_cnt,
160+
trace_selftest_test_probe2_cnt,
161+
trace_selftest_test_probe3_cnt,
162+
trace_selftest_test_global_cnt,
163+
trace_selftest_test_dyn_cnt);
164+
}
165+
166+
static void reset_counts(void)
167+
{
168+
trace_selftest_test_probe1_cnt = 0;
169+
trace_selftest_test_probe2_cnt = 0;
170+
trace_selftest_test_probe3_cnt = 0;
171+
trace_selftest_test_global_cnt = 0;
172+
trace_selftest_test_dyn_cnt = 0;
173+
}
174+
175+
static int trace_selftest_ops(int cnt)
176+
{
177+
int save_ftrace_enabled = ftrace_enabled;
178+
struct ftrace_ops *dyn_ops;
179+
char *func1_name;
180+
char *func2_name;
181+
int len1;
182+
int len2;
183+
int ret = -1;
184+
185+
printk(KERN_CONT "PASSED\n");
186+
pr_info("Testing dynamic ftrace ops #%d: ", cnt);
187+
188+
ftrace_enabled = 1;
189+
reset_counts();
190+
191+
/* Handle PPC64 '.' name */
192+
func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
193+
func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2);
194+
len1 = strlen(func1_name);
195+
len2 = strlen(func2_name);
196+
197+
/*
198+
* Probe 1 will trace function 1.
199+
* Probe 2 will trace function 2.
200+
* Probe 3 will trace functions 1 and 2.
201+
*/
202+
ftrace_set_filter(&test_probe1, func1_name, len1, 1);
203+
ftrace_set_filter(&test_probe2, func2_name, len2, 1);
204+
ftrace_set_filter(&test_probe3, func1_name, len1, 1);
205+
ftrace_set_filter(&test_probe3, func2_name, len2, 0);
206+
207+
register_ftrace_function(&test_probe1);
208+
register_ftrace_function(&test_probe2);
209+
register_ftrace_function(&test_probe3);
210+
register_ftrace_function(&test_global);
211+
212+
DYN_FTRACE_TEST_NAME();
213+
214+
print_counts();
215+
216+
if (trace_selftest_test_probe1_cnt != 1)
217+
goto out;
218+
if (trace_selftest_test_probe2_cnt != 0)
219+
goto out;
220+
if (trace_selftest_test_probe3_cnt != 1)
221+
goto out;
222+
if (trace_selftest_test_global_cnt == 0)
223+
goto out;
224+
225+
DYN_FTRACE_TEST_NAME2();
226+
227+
print_counts();
228+
229+
if (trace_selftest_test_probe1_cnt != 1)
230+
goto out;
231+
if (trace_selftest_test_probe2_cnt != 1)
232+
goto out;
233+
if (trace_selftest_test_probe3_cnt != 2)
234+
goto out;
235+
236+
/* Add a dynamic probe */
237+
dyn_ops = kzalloc(sizeof(*dyn_ops), GFP_KERNEL);
238+
if (!dyn_ops) {
239+
printk("MEMORY ERROR ");
240+
goto out;
241+
}
242+
243+
dyn_ops->func = trace_selftest_test_dyn_func;
244+
245+
register_ftrace_function(dyn_ops);
246+
247+
trace_selftest_test_global_cnt = 0;
248+
249+
DYN_FTRACE_TEST_NAME();
250+
251+
print_counts();
252+
253+
if (trace_selftest_test_probe1_cnt != 2)
254+
goto out_free;
255+
if (trace_selftest_test_probe2_cnt != 1)
256+
goto out_free;
257+
if (trace_selftest_test_probe3_cnt != 3)
258+
goto out_free;
259+
if (trace_selftest_test_global_cnt == 0)
260+
goto out;
261+
if (trace_selftest_test_dyn_cnt == 0)
262+
goto out_free;
263+
264+
DYN_FTRACE_TEST_NAME2();
265+
266+
print_counts();
267+
268+
if (trace_selftest_test_probe1_cnt != 2)
269+
goto out_free;
270+
if (trace_selftest_test_probe2_cnt != 2)
271+
goto out_free;
272+
if (trace_selftest_test_probe3_cnt != 4)
273+
goto out_free;
274+
275+
ret = 0;
276+
out_free:
277+
unregister_ftrace_function(dyn_ops);
278+
kfree(dyn_ops);
279+
280+
out:
281+
/* Purposely unregister in the same order */
282+
unregister_ftrace_function(&test_probe1);
283+
unregister_ftrace_function(&test_probe2);
284+
unregister_ftrace_function(&test_probe3);
285+
unregister_ftrace_function(&test_global);
286+
287+
/* Make sure everything is off */
288+
reset_counts();
289+
DYN_FTRACE_TEST_NAME();
290+
DYN_FTRACE_TEST_NAME();
291+
292+
if (trace_selftest_test_probe1_cnt ||
293+
trace_selftest_test_probe2_cnt ||
294+
trace_selftest_test_probe3_cnt ||
295+
trace_selftest_test_global_cnt ||
296+
trace_selftest_test_dyn_cnt)
297+
ret = -1;
298+
299+
ftrace_enabled = save_ftrace_enabled;
300+
301+
return ret;
302+
}
303+
104304
/* Test dynamic code modification and ftrace filters */
105305
int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
106306
struct trace_array *tr,
@@ -166,23 +366,31 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
166366

167367
/* check the trace buffer */
168368
ret = trace_test_buffer(tr, &count);
169-
trace->reset(tr);
170369
tracing_start();
171370

172371
/* we should only have one item */
173372
if (!ret && count != 1) {
373+
trace->reset(tr);
174374
printk(KERN_CONT ".. filter failed count=%ld ..", count);
175375
ret = -1;
176376
goto out;
177377
}
178378

379+
/* Test the ops with global tracing running */
380+
ret = trace_selftest_ops(1);
381+
trace->reset(tr);
382+
179383
out:
180384
ftrace_enabled = save_ftrace_enabled;
181385
tracer_enabled = save_tracer_enabled;
182386

183387
/* Enable tracing on all functions again */
184388
ftrace_set_global_filter(NULL, 0, 1);
185389

390+
/* Test the ops with global tracing off */
391+
if (!ret)
392+
ret = trace_selftest_ops(2);
393+
186394
return ret;
187395
}
188396
#else

kernel/trace/trace_selftest_dynamic.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,3 +5,9 @@ int DYN_FTRACE_TEST_NAME(void)
55
/* used to call mcount */
66
return 0;
77
}
8+
9+
int DYN_FTRACE_TEST_NAME2(void)
10+
{
11+
/* used to call mcount */
12+
return 0;
13+
}

0 commit comments

Comments
 (0)