mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	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 <rostedt@goodmis.org>
This commit is contained in:
		
							parent
							
								
									936e074b28
								
							
						
					
					
						commit
						95950c2ecb
					
				
					 3 changed files with 217 additions and 1 deletions
				
			
		| 
						 | 
					@ -419,6 +419,8 @@ extern void trace_find_cmdline(int pid, char comm[]);
 | 
				
			||||||
extern unsigned long ftrace_update_tot_cnt;
 | 
					extern unsigned long ftrace_update_tot_cnt;
 | 
				
			||||||
#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
 | 
					#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
 | 
				
			||||||
extern int DYN_FTRACE_TEST_NAME(void);
 | 
					extern int DYN_FTRACE_TEST_NAME(void);
 | 
				
			||||||
 | 
					#define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
 | 
				
			||||||
 | 
					extern int DYN_FTRACE_TEST_NAME2(void);
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
extern int ring_buffer_expanded;
 | 
					extern int ring_buffer_expanded;
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -101,6 +101,206 @@ static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_DYNAMIC_FTRACE
 | 
					#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 */
 | 
					/* Test dynamic code modification and ftrace filters */
 | 
				
			||||||
int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 | 
					int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 | 
				
			||||||
					   struct trace_array *tr,
 | 
										   struct trace_array *tr,
 | 
				
			||||||
| 
						 | 
					@ -166,16 +366,20 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* check the trace buffer */
 | 
						/* check the trace buffer */
 | 
				
			||||||
	ret = trace_test_buffer(tr, &count);
 | 
						ret = trace_test_buffer(tr, &count);
 | 
				
			||||||
	trace->reset(tr);
 | 
					 | 
				
			||||||
	tracing_start();
 | 
						tracing_start();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	/* we should only have one item */
 | 
						/* we should only have one item */
 | 
				
			||||||
	if (!ret && count != 1) {
 | 
						if (!ret && count != 1) {
 | 
				
			||||||
 | 
							trace->reset(tr);
 | 
				
			||||||
		printk(KERN_CONT ".. filter failed count=%ld ..", count);
 | 
							printk(KERN_CONT ".. filter failed count=%ld ..", count);
 | 
				
			||||||
		ret = -1;
 | 
							ret = -1;
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Test the ops with global tracing running */
 | 
				
			||||||
 | 
						ret = trace_selftest_ops(1);
 | 
				
			||||||
 | 
						trace->reset(tr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 out:
 | 
					 out:
 | 
				
			||||||
	ftrace_enabled = save_ftrace_enabled;
 | 
						ftrace_enabled = save_ftrace_enabled;
 | 
				
			||||||
	tracer_enabled = save_tracer_enabled;
 | 
						tracer_enabled = save_tracer_enabled;
 | 
				
			||||||
| 
						 | 
					@ -183,6 +387,10 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 | 
				
			||||||
	/* Enable tracing on all functions again */
 | 
						/* Enable tracing on all functions again */
 | 
				
			||||||
	ftrace_set_global_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;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
#else
 | 
					#else
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -5,3 +5,9 @@ int DYN_FTRACE_TEST_NAME(void)
 | 
				
			||||||
	/* used to call mcount */
 | 
						/* used to call mcount */
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int DYN_FTRACE_TEST_NAME2(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/* used to call mcount */
 | 
				
			||||||
 | 
						return 0;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue