diff options
Diffstat (limited to 'kernel/trace')
| -rw-r--r-- | kernel/trace/ftrace.c | 53 | ||||
| -rw-r--r-- | kernel/trace/trace.c | 1 | ||||
| -rw-r--r-- | kernel/trace/trace_events.c | 69 | ||||
| -rw-r--r-- | kernel/trace/trace_kdb.c | 4 | 
4 files changed, 102 insertions, 25 deletions
| diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index 929a733d302e..224e768bdc73 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -2497,12 +2497,14 @@ static void ftrace_run_update_code(int command)  }  static void ftrace_run_modify_code(struct ftrace_ops *ops, int command, -				   struct ftrace_hash *old_hash) +				   struct ftrace_ops_hash *old_hash)  {  	ops->flags |= FTRACE_OPS_FL_MODIFYING; -	ops->old_hash.filter_hash = old_hash; +	ops->old_hash.filter_hash = old_hash->filter_hash; +	ops->old_hash.notrace_hash = old_hash->notrace_hash;  	ftrace_run_update_code(command);  	ops->old_hash.filter_hash = NULL; +	ops->old_hash.notrace_hash = NULL;  	ops->flags &= ~FTRACE_OPS_FL_MODIFYING;  } @@ -3579,7 +3581,7 @@ static struct ftrace_ops trace_probe_ops __read_mostly =  static int ftrace_probe_registered; -static void __enable_ftrace_function_probe(struct ftrace_hash *old_hash) +static void __enable_ftrace_function_probe(struct ftrace_ops_hash *old_hash)  {  	int ret;  	int i; @@ -3637,6 +3639,7 @@ int  register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,  			      void *data)  { +	struct ftrace_ops_hash old_hash_ops;  	struct ftrace_func_probe *entry;  	struct ftrace_hash **orig_hash = &trace_probe_ops.func_hash->filter_hash;  	struct ftrace_hash *old_hash = *orig_hash; @@ -3658,6 +3661,10 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,  	mutex_lock(&trace_probe_ops.func_hash->regex_lock); +	old_hash_ops.filter_hash = old_hash; +	/* Probes only have filters */ +	old_hash_ops.notrace_hash = NULL; +  	hash = alloc_and_copy_ftrace_hash(FTRACE_HASH_DEFAULT_BITS, old_hash);  	if (!hash) {  		count = -ENOMEM; @@ -3718,7 +3725,7 @@ register_ftrace_function_probe(char *glob, struct ftrace_probe_ops *ops,  	ret = ftrace_hash_move(&trace_probe_ops, 1, orig_hash, hash); -	__enable_ftrace_function_probe(old_hash); +	__enable_ftrace_function_probe(&old_hash_ops);  	if (!ret)  		free_ftrace_hash_rcu(old_hash); @@ -4006,10 +4013,34 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long ip, int remove)  }  static void ftrace_ops_update_code(struct ftrace_ops *ops, -				   struct ftrace_hash *old_hash) +				   struct ftrace_ops_hash *old_hash)  { -	if (ops->flags & FTRACE_OPS_FL_ENABLED && ftrace_enabled) +	struct ftrace_ops *op; + +	if (!ftrace_enabled) +		return; + +	if (ops->flags & FTRACE_OPS_FL_ENABLED) {  		ftrace_run_modify_code(ops, FTRACE_UPDATE_CALLS, old_hash); +		return; +	} + +	/* +	 * If this is the shared global_ops filter, then we need to +	 * check if there is another ops that shares it, is enabled. +	 * If so, we still need to run the modify code. +	 */ +	if (ops->func_hash != &global_ops.local_hash) +		return; + +	do_for_each_ftrace_op(op, ftrace_ops_list) { +		if (op->func_hash == &global_ops.local_hash && +		    op->flags & FTRACE_OPS_FL_ENABLED) { +			ftrace_run_modify_code(op, FTRACE_UPDATE_CALLS, old_hash); +			/* Only need to do this once */ +			return; +		} +	} while_for_each_ftrace_op(op);  }  static int @@ -4017,6 +4048,7 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,  		unsigned long ip, int remove, int reset, int enable)  {  	struct ftrace_hash **orig_hash; +	struct ftrace_ops_hash old_hash_ops;  	struct ftrace_hash *old_hash;  	struct ftrace_hash *hash;  	int ret; @@ -4053,9 +4085,11 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,  	mutex_lock(&ftrace_lock);  	old_hash = *orig_hash; +	old_hash_ops.filter_hash = ops->func_hash->filter_hash; +	old_hash_ops.notrace_hash = ops->func_hash->notrace_hash;  	ret = ftrace_hash_move(ops, enable, orig_hash, hash);  	if (!ret) { -		ftrace_ops_update_code(ops, old_hash); +		ftrace_ops_update_code(ops, &old_hash_ops);  		free_ftrace_hash_rcu(old_hash);  	}  	mutex_unlock(&ftrace_lock); @@ -4267,6 +4301,7 @@ static void __init set_ftrace_early_filters(void)  int ftrace_regex_release(struct inode *inode, struct file *file)  {  	struct seq_file *m = (struct seq_file *)file->private_data; +	struct ftrace_ops_hash old_hash_ops;  	struct ftrace_iterator *iter;  	struct ftrace_hash **orig_hash;  	struct ftrace_hash *old_hash; @@ -4300,10 +4335,12 @@ int ftrace_regex_release(struct inode *inode, struct file *file)  		mutex_lock(&ftrace_lock);  		old_hash = *orig_hash; +		old_hash_ops.filter_hash = iter->ops->func_hash->filter_hash; +		old_hash_ops.notrace_hash = iter->ops->func_hash->notrace_hash;  		ret = ftrace_hash_move(iter->ops, filter_hash,  				       orig_hash, iter->hash);  		if (!ret) { -			ftrace_ops_update_code(iter->ops, old_hash); +			ftrace_ops_update_code(iter->ops, &old_hash_ops);  			free_ftrace_hash_rcu(old_hash);  		}  		mutex_unlock(&ftrace_lock); diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 2e767972e99c..4a9079b9f082 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -6918,7 +6918,6 @@ void __init trace_init(void)  			tracepoint_printk = 0;  	}  	tracer_alloc_buffers(); -	init_ftrace_syscalls();  	trace_event_init();	  } diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c index 366a78a3e61e..b03a0ea77b99 100644 --- a/kernel/trace/trace_events.c +++ b/kernel/trace/trace_events.c @@ -2429,12 +2429,39 @@ static __init int event_trace_memsetup(void)  	return 0;  } +static __init void +early_enable_events(struct trace_array *tr, bool disable_first) +{ +	char *buf = bootup_event_buf; +	char *token; +	int ret; + +	while (true) { +		token = strsep(&buf, ","); + +		if (!token) +			break; +		if (!*token) +			continue; + +		/* Restarting syscalls requires that we stop them first */ +		if (disable_first) +			ftrace_set_clr_event(tr, token, 0); + +		ret = ftrace_set_clr_event(tr, token, 1); +		if (ret) +			pr_warn("Failed to enable trace event: %s\n", token); + +		/* Put back the comma to allow this to be called again */ +		if (buf) +			*(buf - 1) = ','; +	} +} +  static __init int event_trace_enable(void)  {  	struct trace_array *tr = top_trace_array();  	struct ftrace_event_call **iter, *call; -	char *buf = bootup_event_buf; -	char *token;  	int ret;  	if (!tr) @@ -2456,18 +2483,7 @@ static __init int event_trace_enable(void)  	 */  	__trace_early_add_events(tr); -	while (true) { -		token = strsep(&buf, ","); - -		if (!token) -			break; -		if (!*token) -			continue; - -		ret = ftrace_set_clr_event(tr, token, 1); -		if (ret) -			pr_warn("Failed to enable trace event: %s\n", token); -	} +	early_enable_events(tr, false);  	trace_printk_start_comm(); @@ -2478,6 +2494,31 @@ static __init int event_trace_enable(void)  	return 0;  } +/* + * event_trace_enable() is called from trace_event_init() first to + * initialize events and perhaps start any events that are on the + * command line. Unfortunately, there are some events that will not + * start this early, like the system call tracepoints that need + * to set the TIF_SYSCALL_TRACEPOINT flag of pid 1. But event_trace_enable() + * is called before pid 1 starts, and this flag is never set, making + * the syscall tracepoint never get reached, but the event is enabled + * regardless (and not doing anything). + */ +static __init int event_trace_enable_again(void) +{ +	struct trace_array *tr; + +	tr = top_trace_array(); +	if (!tr) +		return -ENODEV; + +	early_enable_events(tr, true); + +	return 0; +} + +early_initcall(event_trace_enable_again); +  static __init int event_trace_init(void)  {  	struct trace_array *tr; diff --git a/kernel/trace/trace_kdb.c b/kernel/trace/trace_kdb.c index b0b1c44e923a..3ccf5c2c1320 100644 --- a/kernel/trace/trace_kdb.c +++ b/kernel/trace/trace_kdb.c @@ -132,8 +132,8 @@ static int kdb_ftdump(int argc, const char **argv)  static __init int kdb_ftrace_register(void)  { -	kdb_register_repeat("ftdump", kdb_ftdump, "[skip_#lines] [cpu]", -			    "Dump ftrace log", 0, KDB_REPEAT_NONE); +	kdb_register_flags("ftdump", kdb_ftdump, "[skip_#lines] [cpu]", +			    "Dump ftrace log", 0, KDB_ENABLE_ALWAYS_SAFE);  	return 0;  } | 
