diff options
Diffstat (limited to 'kernel/trace/trace_functions.c')
| -rw-r--r-- | kernel/trace/trace_functions.c | 207 | 
1 files changed, 150 insertions, 57 deletions
| diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c index 60115252332..c4d6d719198 100644 --- a/kernel/trace/trace_functions.c +++ b/kernel/trace/trace_functions.c @@ -28,7 +28,7 @@ static void tracing_stop_function_trace(void);  static int function_trace_init(struct trace_array *tr)  {  	func_trace = tr; -	tr->cpu = get_cpu(); +	tr->trace_buffer.cpu = get_cpu();  	put_cpu();  	tracing_start_cmdline_record(); @@ -44,7 +44,7 @@ static void function_trace_reset(struct trace_array *tr)  static void function_trace_start(struct trace_array *tr)  { -	tracing_reset_online_cpus(tr); +	tracing_reset_online_cpus(&tr->trace_buffer);  }  /* Our option */ @@ -76,7 +76,7 @@ function_trace_call(unsigned long ip, unsigned long parent_ip,  		goto out;  	cpu = smp_processor_id(); -	data = tr->data[cpu]; +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);  	if (!atomic_read(&data->disabled)) {  		local_save_flags(flags);  		trace_function(tr, ip, parent_ip, flags, pc); @@ -107,7 +107,7 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip,  	 */  	local_irq_save(flags);  	cpu = raw_smp_processor_id(); -	data = tr->data[cpu]; +	data = per_cpu_ptr(tr->trace_buffer.data, cpu);  	disabled = atomic_inc_return(&data->disabled);  	if (likely(disabled == 1)) { @@ -214,66 +214,89 @@ static struct tracer function_trace __read_mostly =  };  #ifdef CONFIG_DYNAMIC_FTRACE -static void -ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data) +static int update_count(void **data)  { -	long *count = (long *)data; - -	if (tracing_is_on()) -		return; +	unsigned long *count = (long *)data;  	if (!*count) -		return; +		return 0;  	if (*count != -1)  		(*count)--; -	tracing_on(); +	return 1;  }  static void -ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data) +ftrace_traceon_count(unsigned long ip, unsigned long parent_ip, void **data)  { -	long *count = (long *)data; +	if (tracing_is_on()) +		return; + +	if (update_count(data)) +		tracing_on(); +} +static void +ftrace_traceoff_count(unsigned long ip, unsigned long parent_ip, void **data) +{  	if (!tracing_is_on())  		return; -	if (!*count) +	if (update_count(data)) +		tracing_off(); +} + +static void +ftrace_traceon(unsigned long ip, unsigned long parent_ip, void **data) +{ +	if (tracing_is_on())  		return; -	if (*count != -1) -		(*count)--; +	tracing_on(); +} + +static void +ftrace_traceoff(unsigned long ip, unsigned long parent_ip, void **data) +{ +	if (!tracing_is_on()) +		return;  	tracing_off();  } -static int -ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip, -			 struct ftrace_probe_ops *ops, void *data); +/* + * Skip 4: + *   ftrace_stacktrace() + *   function_trace_probe_call() + *   ftrace_ops_list_func() + *   ftrace_call() + */ +#define STACK_SKIP 4 -static struct ftrace_probe_ops traceon_probe_ops = { -	.func			= ftrace_traceon, -	.print			= ftrace_trace_onoff_print, -}; +static void +ftrace_stacktrace(unsigned long ip, unsigned long parent_ip, void **data) +{ +	trace_dump_stack(STACK_SKIP); +} -static struct ftrace_probe_ops traceoff_probe_ops = { -	.func			= ftrace_traceoff, -	.print			= ftrace_trace_onoff_print, -}; +static void +ftrace_stacktrace_count(unsigned long ip, unsigned long parent_ip, void **data) +{ +	if (!tracing_is_on()) +		return; + +	if (update_count(data)) +		trace_dump_stack(STACK_SKIP); +}  static int -ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip, -			 struct ftrace_probe_ops *ops, void *data) +ftrace_probe_print(const char *name, struct seq_file *m, +		   unsigned long ip, void *data)  {  	long count = (long)data; -	seq_printf(m, "%ps:", (void *)ip); - -	if (ops == &traceon_probe_ops) -		seq_printf(m, "traceon"); -	else -		seq_printf(m, "traceoff"); +	seq_printf(m, "%ps:%s", (void *)ip, name);  	if (count == -1)  		seq_printf(m, ":unlimited\n"); @@ -284,26 +307,61 @@ ftrace_trace_onoff_print(struct seq_file *m, unsigned long ip,  }  static int -ftrace_trace_onoff_unreg(char *glob, char *cmd, char *param) +ftrace_traceon_print(struct seq_file *m, unsigned long ip, +			 struct ftrace_probe_ops *ops, void *data)  { -	struct ftrace_probe_ops *ops; - -	/* we register both traceon and traceoff to this callback */ -	if (strcmp(cmd, "traceon") == 0) -		ops = &traceon_probe_ops; -	else -		ops = &traceoff_probe_ops; +	return ftrace_probe_print("traceon", m, ip, data); +} -	unregister_ftrace_function_probe_func(glob, ops); +static int +ftrace_traceoff_print(struct seq_file *m, unsigned long ip, +			 struct ftrace_probe_ops *ops, void *data) +{ +	return ftrace_probe_print("traceoff", m, ip, data); +} -	return 0; +static int +ftrace_stacktrace_print(struct seq_file *m, unsigned long ip, +			struct ftrace_probe_ops *ops, void *data) +{ +	return ftrace_probe_print("stacktrace", m, ip, data);  } +static struct ftrace_probe_ops traceon_count_probe_ops = { +	.func			= ftrace_traceon_count, +	.print			= ftrace_traceon_print, +}; + +static struct ftrace_probe_ops traceoff_count_probe_ops = { +	.func			= ftrace_traceoff_count, +	.print			= ftrace_traceoff_print, +}; + +static struct ftrace_probe_ops stacktrace_count_probe_ops = { +	.func			= ftrace_stacktrace_count, +	.print			= ftrace_stacktrace_print, +}; + +static struct ftrace_probe_ops traceon_probe_ops = { +	.func			= ftrace_traceon, +	.print			= ftrace_traceon_print, +}; + +static struct ftrace_probe_ops traceoff_probe_ops = { +	.func			= ftrace_traceoff, +	.print			= ftrace_traceoff_print, +}; + +static struct ftrace_probe_ops stacktrace_probe_ops = { +	.func			= ftrace_stacktrace, +	.print			= ftrace_stacktrace_print, +}; +  static int -ftrace_trace_onoff_callback(struct ftrace_hash *hash, -			    char *glob, char *cmd, char *param, int enable) +ftrace_trace_probe_callback(struct ftrace_probe_ops *ops, +			    struct ftrace_hash *hash, char *glob, +			    char *cmd, char *param, int enable)  { -	struct ftrace_probe_ops *ops;  	void *count = (void *)-1;  	char *number;  	int ret; @@ -312,14 +370,10 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,  	if (!enable)  		return -EINVAL; -	if (glob[0] == '!') -		return ftrace_trace_onoff_unreg(glob+1, cmd, param); - -	/* we register both traceon and traceoff to this callback */ -	if (strcmp(cmd, "traceon") == 0) -		ops = &traceon_probe_ops; -	else -		ops = &traceoff_probe_ops; +	if (glob[0] == '!') { +		unregister_ftrace_function_probe_func(glob+1, ops); +		return 0; +	}  	if (!param)  		goto out_reg; @@ -343,6 +397,34 @@ ftrace_trace_onoff_callback(struct ftrace_hash *hash,  	return ret < 0 ? ret : 0;  } +static int +ftrace_trace_onoff_callback(struct ftrace_hash *hash, +			    char *glob, char *cmd, char *param, int enable) +{ +	struct ftrace_probe_ops *ops; + +	/* we register both traceon and traceoff to this callback */ +	if (strcmp(cmd, "traceon") == 0) +		ops = param ? &traceon_count_probe_ops : &traceon_probe_ops; +	else +		ops = param ? &traceoff_count_probe_ops : &traceoff_probe_ops; + +	return ftrace_trace_probe_callback(ops, hash, glob, cmd, +					   param, enable); +} + +static int +ftrace_stacktrace_callback(struct ftrace_hash *hash, +			   char *glob, char *cmd, char *param, int enable) +{ +	struct ftrace_probe_ops *ops; + +	ops = param ? &stacktrace_count_probe_ops : &stacktrace_probe_ops; + +	return ftrace_trace_probe_callback(ops, hash, glob, cmd, +					   param, enable); +} +  static struct ftrace_func_command ftrace_traceon_cmd = {  	.name			= "traceon",  	.func			= ftrace_trace_onoff_callback, @@ -353,6 +435,11 @@ static struct ftrace_func_command ftrace_traceoff_cmd = {  	.func			= ftrace_trace_onoff_callback,  }; +static struct ftrace_func_command ftrace_stacktrace_cmd = { +	.name			= "stacktrace", +	.func			= ftrace_stacktrace_callback, +}; +  static int __init init_func_cmd_traceon(void)  {  	int ret; @@ -364,6 +451,12 @@ static int __init init_func_cmd_traceon(void)  	ret = register_ftrace_command(&ftrace_traceon_cmd);  	if (ret)  		unregister_ftrace_command(&ftrace_traceoff_cmd); + +	ret = register_ftrace_command(&ftrace_stacktrace_cmd); +	if (ret) { +		unregister_ftrace_command(&ftrace_traceoff_cmd); +		unregister_ftrace_command(&ftrace_traceon_cmd); +	}  	return ret;  }  #else | 
