diff options
Diffstat (limited to 'kernel/trace/trace_selftest.c')
| -rw-r--r-- | kernel/trace/trace_selftest.c | 214 | 
1 files changed, 211 insertions, 3 deletions
diff --git a/kernel/trace/trace_selftest.c b/kernel/trace/trace_selftest.c index 659732eba07..288541f977f 100644 --- a/kernel/trace/trace_selftest.c +++ b/kernel/trace/trace_selftest.c @@ -101,6 +101,206 @@ static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret)  #ifdef CONFIG_DYNAMIC_FTRACE +static int trace_selftest_test_probe1_cnt; +static void trace_selftest_test_probe1_func(unsigned long ip, +					    unsigned long pip) +{ +	trace_selftest_test_probe1_cnt++; +} + +static int trace_selftest_test_probe2_cnt; +static void trace_selftest_test_probe2_func(unsigned long ip, +					    unsigned long pip) +{ +	trace_selftest_test_probe2_cnt++; +} + +static int trace_selftest_test_probe3_cnt; +static void trace_selftest_test_probe3_func(unsigned long ip, +					    unsigned long pip) +{ +	trace_selftest_test_probe3_cnt++; +} + +static int trace_selftest_test_global_cnt; +static void trace_selftest_test_global_func(unsigned long ip, +					    unsigned long pip) +{ +	trace_selftest_test_global_cnt++; +} + +static int trace_selftest_test_dyn_cnt; +static void trace_selftest_test_dyn_func(unsigned long ip, +					 unsigned long pip) +{ +	trace_selftest_test_dyn_cnt++; +} + +static struct ftrace_ops test_probe1 = { +	.func			= trace_selftest_test_probe1_func, +}; + +static struct ftrace_ops test_probe2 = { +	.func			= trace_selftest_test_probe2_func, +}; + +static struct ftrace_ops test_probe3 = { +	.func			= trace_selftest_test_probe3_func, +}; + +static struct ftrace_ops test_global = { +	.func			= trace_selftest_test_global_func, +	.flags			= FTRACE_OPS_FL_GLOBAL, +}; + +static void print_counts(void) +{ +	printk("(%d %d %d %d %d) ", +	       trace_selftest_test_probe1_cnt, +	       trace_selftest_test_probe2_cnt, +	       trace_selftest_test_probe3_cnt, +	       trace_selftest_test_global_cnt, +	       trace_selftest_test_dyn_cnt); +} + +static void reset_counts(void) +{ +	trace_selftest_test_probe1_cnt = 0; +	trace_selftest_test_probe2_cnt = 0; +	trace_selftest_test_probe3_cnt = 0; +	trace_selftest_test_global_cnt = 0; +	trace_selftest_test_dyn_cnt = 0; +} + +static int trace_selftest_ops(int cnt) +{ +	int save_ftrace_enabled = ftrace_enabled; +	struct ftrace_ops *dyn_ops; +	char *func1_name; +	char *func2_name; +	int len1; +	int len2; +	int ret = -1; + +	printk(KERN_CONT "PASSED\n"); +	pr_info("Testing dynamic ftrace ops #%d: ", cnt); + +	ftrace_enabled = 1; +	reset_counts(); + +	/* Handle PPC64 '.' name */ +	func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME); +	func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2); +	len1 = strlen(func1_name); +	len2 = strlen(func2_name); + +	/* +	 * Probe 1 will trace function 1. +	 * Probe 2 will trace function 2. +	 * Probe 3 will trace functions 1 and 2. +	 */ +	ftrace_set_filter(&test_probe1, func1_name, len1, 1); +	ftrace_set_filter(&test_probe2, func2_name, len2, 1); +	ftrace_set_filter(&test_probe3, func1_name, len1, 1); +	ftrace_set_filter(&test_probe3, func2_name, len2, 0); + +	register_ftrace_function(&test_probe1); +	register_ftrace_function(&test_probe2); +	register_ftrace_function(&test_probe3); +	register_ftrace_function(&test_global); + +	DYN_FTRACE_TEST_NAME(); + +	print_counts(); + +	if (trace_selftest_test_probe1_cnt != 1) +		goto out; +	if (trace_selftest_test_probe2_cnt != 0) +		goto out; +	if (trace_selftest_test_probe3_cnt != 1) +		goto out; +	if (trace_selftest_test_global_cnt == 0) +		goto out; + +	DYN_FTRACE_TEST_NAME2(); + +	print_counts(); + +	if (trace_selftest_test_probe1_cnt != 1) +		goto out; +	if (trace_selftest_test_probe2_cnt != 1) +		goto out; +	if (trace_selftest_test_probe3_cnt != 2) +		goto out; + +	/* Add a dynamic probe */ +	dyn_ops = kzalloc(sizeof(*dyn_ops), GFP_KERNEL); +	if (!dyn_ops) { +		printk("MEMORY ERROR "); +		goto out; +	} + +	dyn_ops->func = trace_selftest_test_dyn_func; + +	register_ftrace_function(dyn_ops); + +	trace_selftest_test_global_cnt = 0; + +	DYN_FTRACE_TEST_NAME(); + +	print_counts(); + +	if (trace_selftest_test_probe1_cnt != 2) +		goto out_free; +	if (trace_selftest_test_probe2_cnt != 1) +		goto out_free; +	if (trace_selftest_test_probe3_cnt != 3) +		goto out_free; +	if (trace_selftest_test_global_cnt == 0) +		goto out; +	if (trace_selftest_test_dyn_cnt == 0) +		goto out_free; + +	DYN_FTRACE_TEST_NAME2(); + +	print_counts(); + +	if (trace_selftest_test_probe1_cnt != 2) +		goto out_free; +	if (trace_selftest_test_probe2_cnt != 2) +		goto out_free; +	if (trace_selftest_test_probe3_cnt != 4) +		goto out_free; + +	ret = 0; + out_free: +	unregister_ftrace_function(dyn_ops); +	kfree(dyn_ops); + + out: +	/* Purposely unregister in the same order */ +	unregister_ftrace_function(&test_probe1); +	unregister_ftrace_function(&test_probe2); +	unregister_ftrace_function(&test_probe3); +	unregister_ftrace_function(&test_global); + +	/* Make sure everything is off */ +	reset_counts(); +	DYN_FTRACE_TEST_NAME(); +	DYN_FTRACE_TEST_NAME(); + +	if (trace_selftest_test_probe1_cnt || +	    trace_selftest_test_probe2_cnt || +	    trace_selftest_test_probe3_cnt || +	    trace_selftest_test_global_cnt || +	    trace_selftest_test_dyn_cnt) +		ret = -1; + +	ftrace_enabled = save_ftrace_enabled; + +	return ret; +} +  /* Test dynamic code modification and ftrace filters */  int trace_selftest_startup_dynamic_tracing(struct tracer *trace,  					   struct trace_array *tr, @@ -131,7 +331,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,  	func_name = "*" __stringify(DYN_FTRACE_TEST_NAME);  	/* filter only on our function */ -	ftrace_set_filter(func_name, strlen(func_name), 1); +	ftrace_set_global_filter(func_name, strlen(func_name), 1);  	/* enable tracing */  	ret = tracer_init(trace, tr); @@ -166,22 +366,30 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,  	/* check the trace buffer */  	ret = trace_test_buffer(tr, &count); -	trace->reset(tr);  	tracing_start();  	/* we should only have one item */  	if (!ret && count != 1) { +		trace->reset(tr);  		printk(KERN_CONT ".. filter failed count=%ld ..", count);  		ret = -1;  		goto out;  	} +	/* Test the ops with global tracing running */ +	ret = trace_selftest_ops(1); +	trace->reset(tr); +   out:  	ftrace_enabled = save_ftrace_enabled;  	tracer_enabled = save_tracer_enabled;  	/* Enable tracing on all functions again */ -	ftrace_set_filter(NULL, 0, 1); +	ftrace_set_global_filter(NULL, 0, 1); + +	/* Test the ops with global tracing off */ +	if (!ret) +		ret = trace_selftest_ops(2);  	return ret;  }  |