mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 10:40:15 +02:00 
			
		
		
		
	tracing: Make tracer_flags use the right set_flag callback
When I was updating the ftrace_stress test of ltp. I encountered a strange phenomemon, excute following steps: echo nop > /sys/kernel/debug/tracing/current_tracer echo 0 > /sys/kernel/debug/tracing/options/funcgraph-cpu bash: echo: write error: Invalid argument check dmesg: [ 1024.903855] nop_test_refuse flag set to 0: we refuse.Now cat trace_options to see the result The reason is that the trace option test will randomly setup trace option under tracing/options no matter what the current_tracer is. but the set_tracer_option is always using the set_flag callback from the current_tracer. This patch adds a pointer to tracer_flags and make it point to the tracer it belongs to. When the option is setup, the set_flag of the right tracer will be used no matter what the the current_tracer is. And the old dummy_tracer_flags is used for all the tracers which doesn't have a tracer_flags, having issue to use it to save the pointer of a tracer. So remove it and use dynamic dummy tracer_flags for tracers needing a dummy tracer_flags, as a result, there are no tracers sharing tracer_flags, so remove the check code. And save the current tracer to trace_option_dentry seems not good as it may waste mem space when mount the debug/trace fs more than one time. Link: http://lkml.kernel.org/r/1457444222-8654-1-git-send-email-chuhu@redhat.com Signed-off-by: Chunyu Hu <chuhu@redhat.com> [ Fixed up function tracer options to work with the change ] Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
		
							parent
							
								
									f6cede5b49
								
							
						
					
					
						commit
						d39cdd2036
					
				
					 3 changed files with 21 additions and 14 deletions
				
			
		| 
						 | 
					@ -74,11 +74,6 @@ static struct tracer_opt dummy_tracer_opt[] = {
 | 
				
			||||||
	{ }
 | 
						{ }
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct tracer_flags dummy_tracer_flags = {
 | 
					 | 
				
			||||||
	.val = 0,
 | 
					 | 
				
			||||||
	.opts = dummy_tracer_opt
 | 
					 | 
				
			||||||
};
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
 | 
					dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -1258,12 +1253,20 @@ int __init register_tracer(struct tracer *type)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (!type->set_flag)
 | 
						if (!type->set_flag)
 | 
				
			||||||
		type->set_flag = &dummy_set_flag;
 | 
							type->set_flag = &dummy_set_flag;
 | 
				
			||||||
	if (!type->flags)
 | 
						if (!type->flags) {
 | 
				
			||||||
		type->flags = &dummy_tracer_flags;
 | 
							/*allocate a dummy tracer_flags*/
 | 
				
			||||||
	else
 | 
							type->flags = kmalloc(sizeof(*type->flags), GFP_KERNEL);
 | 
				
			||||||
 | 
							if (!type->flags)
 | 
				
			||||||
 | 
								return -ENOMEM;
 | 
				
			||||||
 | 
							type->flags->val = 0;
 | 
				
			||||||
 | 
							type->flags->opts = dummy_tracer_opt;
 | 
				
			||||||
 | 
						} else
 | 
				
			||||||
		if (!type->flags->opts)
 | 
							if (!type->flags->opts)
 | 
				
			||||||
			type->flags->opts = dummy_tracer_opt;
 | 
								type->flags->opts = dummy_tracer_opt;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* store the tracer for __set_tracer_option */
 | 
				
			||||||
 | 
						type->flags->trace = type;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = run_tracer_selftest(type);
 | 
						ret = run_tracer_selftest(type);
 | 
				
			||||||
	if (ret < 0)
 | 
						if (ret < 0)
 | 
				
			||||||
		goto out;
 | 
							goto out;
 | 
				
			||||||
| 
						 | 
					@ -3505,7 +3508,7 @@ static int __set_tracer_option(struct trace_array *tr,
 | 
				
			||||||
			       struct tracer_flags *tracer_flags,
 | 
								       struct tracer_flags *tracer_flags,
 | 
				
			||||||
			       struct tracer_opt *opts, int neg)
 | 
								       struct tracer_opt *opts, int neg)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct tracer *trace = tr->current_trace;
 | 
						struct tracer *trace = tracer_flags->trace;
 | 
				
			||||||
	int ret;
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = trace->set_flag(tr, tracer_flags->val, opts->bit, !neg);
 | 
						ret = trace->set_flag(tr, tracer_flags->val, opts->bit, !neg);
 | 
				
			||||||
| 
						 | 
					@ -6391,11 +6394,8 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer)
 | 
				
			||||||
		return;
 | 
							return;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	for (i = 0; i < tr->nr_topts; i++) {
 | 
						for (i = 0; i < tr->nr_topts; i++) {
 | 
				
			||||||
		/*
 | 
							/* Make sure there's no duplicate flags. */
 | 
				
			||||||
		 * Check if these flags have already been added.
 | 
							if (WARN_ON_ONCE(tr->topts[i].tracer->flags == tracer->flags))
 | 
				
			||||||
		 * Some tracers share flags.
 | 
					 | 
				
			||||||
		 */
 | 
					 | 
				
			||||||
		if (tr->topts[i].tracer->flags == tracer->flags)
 | 
					 | 
				
			||||||
			return;
 | 
								return;
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -345,6 +345,7 @@ struct tracer_opt {
 | 
				
			||||||
struct tracer_flags {
 | 
					struct tracer_flags {
 | 
				
			||||||
	u32			val;
 | 
						u32			val;
 | 
				
			||||||
	struct tracer_opt	*opts;
 | 
						struct tracer_opt	*opts;
 | 
				
			||||||
 | 
						struct tracer		*trace;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/* Makes more easy to define a tracer opt */
 | 
					/* Makes more easy to define a tracer opt */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -219,6 +219,8 @@ static void tracing_stop_function_trace(struct trace_array *tr)
 | 
				
			||||||
	unregister_ftrace_function(tr->ops);
 | 
						unregister_ftrace_function(tr->ops);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static struct tracer function_trace;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int
 | 
					static int
 | 
				
			||||||
func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
 | 
					func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
| 
						 | 
					@ -228,6 +230,10 @@ func_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
 | 
				
			||||||
		if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
 | 
							if (!!set == !!(func_flags.val & TRACE_FUNC_OPT_STACK))
 | 
				
			||||||
			break;
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* We can change this flag when not running. */
 | 
				
			||||||
 | 
							if (tr->current_trace != &function_trace)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		unregister_ftrace_function(tr->ops);
 | 
							unregister_ftrace_function(tr->ops);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		if (set) {
 | 
							if (set) {
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue