diff options
Diffstat (limited to 'kernel/trace/ftrace.c')
| -rw-r--r-- | kernel/trace/ftrace.c | 73 | 
1 files changed, 37 insertions, 36 deletions
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c index da1710499698..65208d3b5ed9 100644 --- a/kernel/trace/ftrace.c +++ b/kernel/trace/ftrace.c @@ -1595,12 +1595,15 @@ static struct dyn_ftrace *lookup_rec(unsigned long start, unsigned long end)  unsigned long ftrace_location_range(unsigned long start, unsigned long end)  {  	struct dyn_ftrace *rec; +	unsigned long ip = 0; +	rcu_read_lock();  	rec = lookup_rec(start, end);  	if (rec) -		return rec->ip; +		ip = rec->ip; +	rcu_read_unlock(); -	return 0; +	return ip;  }  /** @@ -1614,25 +1617,22 @@ unsigned long ftrace_location_range(unsigned long start, unsigned long end)   */  unsigned long ftrace_location(unsigned long ip)  { -	struct dyn_ftrace *rec; +	unsigned long loc;  	unsigned long offset;  	unsigned long size; -	rec = lookup_rec(ip, ip); -	if (!rec) { +	loc = ftrace_location_range(ip, ip); +	if (!loc) {  		if (!kallsyms_lookup_size_offset(ip, &size, &offset))  			goto out;  		/* map sym+0 to __fentry__ */  		if (!offset) -			rec = lookup_rec(ip, ip + size - 1); +			loc = ftrace_location_range(ip, ip + size - 1);  	} -	if (rec) -		return rec->ip; -  out: -	return 0; +	return loc;  }  /** @@ -2538,7 +2538,6 @@ ftrace_find_unique_ops(struct dyn_ftrace *rec)  /* Protected by rcu_tasks for reading, and direct_mutex for writing */  static struct ftrace_hash __rcu *direct_functions = EMPTY_HASH;  static DEFINE_MUTEX(direct_mutex); -int ftrace_direct_func_count;  /*   * Search the direct_functions hash to see if the given instruction pointer @@ -3157,8 +3156,7 @@ out:  		 * synchronize_rcu_tasks() will wait for those tasks to  		 * execute and either schedule voluntarily or enter user space.  		 */ -		if (IS_ENABLED(CONFIG_PREEMPTION)) -			synchronize_rcu_tasks(); +		synchronize_rcu_tasks();  		ftrace_trampoline_free(ops);  	} @@ -4202,12 +4200,12 @@ static int  add_rec_by_index(struct ftrace_hash *hash, struct ftrace_glob *func_g,  		 int clear_filter)  { -	long index = simple_strtoul(func_g->search, NULL, 0); +	long index;  	struct ftrace_page *pg;  	struct dyn_ftrace *rec;  	/* The index starts at 1 */ -	if (--index < 0) +	if (kstrtoul(func_g->search, 0, &index) || --index < 0)  		return 0;  	do_for_each_ftrace_rec(pg, rec) { @@ -5318,14 +5316,6 @@ ftrace_set_addr(struct ftrace_ops *ops, unsigned long *ips, unsigned int cnt,  #ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS -struct ftrace_direct_func { -	struct list_head	next; -	unsigned long		addr; -	int			count; -}; - -static LIST_HEAD(ftrace_direct_funcs); -  static int register_ftrace_function_nolock(struct ftrace_ops *ops);  /* @@ -5366,6 +5356,13 @@ static void remove_direct_functions_hash(struct ftrace_hash *hash, unsigned long  	}  } +static void register_ftrace_direct_cb(struct rcu_head *rhp) +{ +	struct ftrace_hash *fhp = container_of(rhp, struct ftrace_hash, rcu); + +	free_ftrace_hash(fhp); +} +  /**   * register_ftrace_direct - Call a custom trampoline directly   * for multiple functions registered in @ops @@ -5464,10 +5461,8 @@ int register_ftrace_direct(struct ftrace_ops *ops, unsigned long addr)   out_unlock:  	mutex_unlock(&direct_mutex); -	if (free_hash && free_hash != EMPTY_HASH) { -		synchronize_rcu_tasks(); -		free_ftrace_hash(free_hash); -	} +	if (free_hash && free_hash != EMPTY_HASH) +		call_rcu_tasks(&free_hash->rcu, register_ftrace_direct_cb);  	if (new_hash)  		free_ftrace_hash(new_hash); @@ -5817,9 +5812,8 @@ __setup("ftrace_graph_notrace=", set_graph_notrace_function);  static int __init set_graph_max_depth_function(char *str)  { -	if (!str) +	if (!str || kstrtouint(str, 0, &fgraph_max_depth))  		return 0; -	fgraph_max_depth = simple_strtoul(str, NULL, 0);  	return 1;  }  __setup("ftrace_graph_max_depth=", set_graph_max_depth_function); @@ -6596,6 +6590,8 @@ static int ftrace_process_locs(struct module *mod,  	/* We should have used all pages unless we skipped some */  	if (pg_unuse) {  		WARN_ON(!skipped); +		/* Need to synchronize with ftrace_location_range() */ +		synchronize_rcu();  		ftrace_free_pages(pg_unuse);  	}  	return ret; @@ -6809,6 +6805,9 @@ void ftrace_release_mod(struct module *mod)   out_unlock:  	mutex_unlock(&ftrace_lock); +	/* Need to synchronize with ftrace_location_range() */ +	if (tmp_page) +		synchronize_rcu();  	for (pg = tmp_page; pg; pg = tmp_page) {  		/* Needs to be called outside of ftrace_lock */ @@ -7142,6 +7141,7 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)  	unsigned long start = (unsigned long)(start_ptr);  	unsigned long end = (unsigned long)(end_ptr);  	struct ftrace_page **last_pg = &ftrace_pages_start; +	struct ftrace_page *tmp_page = NULL;  	struct ftrace_page *pg;  	struct dyn_ftrace *rec;  	struct dyn_ftrace key; @@ -7183,12 +7183,8 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)  		ftrace_update_tot_cnt--;  		if (!pg->index) {  			*last_pg = pg->next; -			if (pg->records) { -				free_pages((unsigned long)pg->records, pg->order); -				ftrace_number_of_pages -= 1 << pg->order; -			} -			ftrace_number_of_groups--; -			kfree(pg); +			pg->next = tmp_page; +			tmp_page = pg;  			pg = container_of(last_pg, struct ftrace_page, next);  			if (!(*last_pg))  				ftrace_pages = pg; @@ -7205,6 +7201,11 @@ void ftrace_free_mem(struct module *mod, void *start_ptr, void *end_ptr)  		clear_func_from_hashes(func);  		kfree(func);  	} +	/* Need to synchronize with ftrace_location_range() */ +	if (tmp_page) { +		synchronize_rcu(); +		ftrace_free_pages(tmp_page); +	}  }  void __init ftrace_free_init_mem(void) @@ -7895,6 +7896,7 @@ void ftrace_kill(void)  	ftrace_disabled = 1;  	ftrace_enabled = 0;  	ftrace_trace_function = ftrace_stub; +	kprobe_ftrace_kill();  }  /** @@ -8270,7 +8272,6 @@ static struct ctl_table ftrace_sysctls[] = {  		.mode           = 0644,  		.proc_handler   = ftrace_enable_sysctl,  	}, -	{}  };  static int __init ftrace_sysctl_init(void)  |