| .. | .. | 
|---|
| 18 | 18 |  #include <linux/clocksource.h> | 
|---|
| 19 | 19 |  #include <linux/sched/task.h> | 
|---|
| 20 | 20 |  #include <linux/kallsyms.h> | 
|---|
 | 21 | +#include <linux/security.h>  | 
|---|
| 21 | 22 |  #include <linux/seq_file.h> | 
|---|
| 22 |  | -#include <linux/suspend.h>  | 
|---|
| 23 | 23 |  #include <linux/tracefs.h> | 
|---|
| 24 | 24 |  #include <linux/hardirq.h> | 
|---|
| 25 | 25 |  #include <linux/kthread.h> | 
|---|
| .. | .. | 
|---|
| 41 | 41 |  #include <asm/sections.h> | 
|---|
| 42 | 42 |  #include <asm/setup.h> | 
|---|
| 43 | 43 |   | 
|---|
 | 44 | +#include "ftrace_internal.h"  | 
|---|
| 44 | 45 |  #include "trace_output.h" | 
|---|
| 45 | 46 |  #include "trace_stat.h" | 
|---|
| 46 | 47 |   | 
|---|
| .. | .. | 
|---|
| 61 | 62 |  	}) | 
|---|
| 62 | 63 |   | 
|---|
| 63 | 64 |  /* hash bits for specific function selection */ | 
|---|
| 64 |  | -#define FTRACE_HASH_BITS 7  | 
|---|
| 65 |  | -#define FTRACE_FUNC_HASHSIZE (1 << FTRACE_HASH_BITS)  | 
|---|
| 66 | 65 |  #define FTRACE_HASH_DEFAULT_BITS 10 | 
|---|
| 67 | 66 |  #define FTRACE_HASH_MAX_BITS 12 | 
|---|
| 68 | 67 |   | 
|---|
| .. | .. | 
|---|
| 70 | 69 |  #define INIT_OPS_HASH(opsname)	\ | 
|---|
| 71 | 70 |  	.func_hash		= &opsname.local_hash,			\ | 
|---|
| 72 | 71 |  	.local_hash.regex_lock	= __MUTEX_INITIALIZER(opsname.local_hash.regex_lock), | 
|---|
| 73 |  | -#define ASSIGN_OPS_HASH(opsname, val) \  | 
|---|
| 74 |  | -	.func_hash		= val, \  | 
|---|
| 75 |  | -	.local_hash.regex_lock	= __MUTEX_INITIALIZER(opsname.local_hash.regex_lock),  | 
|---|
| 76 | 72 |  #else | 
|---|
| 77 | 73 |  #define INIT_OPS_HASH(opsname) | 
|---|
| 78 |  | -#define ASSIGN_OPS_HASH(opsname, val)  | 
|---|
| 79 | 74 |  #endif | 
|---|
| 80 | 75 |   | 
|---|
| 81 |  | -static struct ftrace_ops ftrace_list_end __read_mostly = {  | 
|---|
 | 76 | +enum {  | 
|---|
 | 77 | +	FTRACE_MODIFY_ENABLE_FL		= (1 << 0),  | 
|---|
 | 78 | +	FTRACE_MODIFY_MAY_SLEEP_FL	= (1 << 1),  | 
|---|
 | 79 | +};  | 
|---|
 | 80 | +  | 
|---|
 | 81 | +struct ftrace_ops ftrace_list_end __read_mostly = {  | 
|---|
| 82 | 82 |  	.func		= ftrace_stub, | 
|---|
| 83 | 83 |  	.flags		= FTRACE_OPS_FL_RECURSION_SAFE | FTRACE_OPS_FL_STUB, | 
|---|
| 84 | 84 |  	INIT_OPS_HASH(ftrace_list_end) | 
|---|
| .. | .. | 
|---|
| 102 | 102 |   | 
|---|
| 103 | 103 |  	tr = ops->private; | 
|---|
| 104 | 104 |   | 
|---|
| 105 |  | -	return tr->function_pids != NULL;  | 
|---|
 | 105 | +	return tr->function_pids != NULL || tr->function_no_pids != NULL;  | 
|---|
| 106 | 106 |  } | 
|---|
| 107 | 107 |   | 
|---|
| 108 | 108 |  static void ftrace_update_trampoline(struct ftrace_ops *ops); | 
|---|
| .. | .. | 
|---|
| 113 | 113 |   */ | 
|---|
| 114 | 114 |  static int ftrace_disabled __read_mostly; | 
|---|
| 115 | 115 |   | 
|---|
| 116 |  | -static DEFINE_MUTEX(ftrace_lock);  | 
|---|
 | 116 | +DEFINE_MUTEX(ftrace_lock);  | 
|---|
| 117 | 117 |   | 
|---|
| 118 |  | -static struct ftrace_ops __rcu *ftrace_ops_list __read_mostly = &ftrace_list_end;  | 
|---|
 | 118 | +struct ftrace_ops __rcu *ftrace_ops_list __read_mostly = &ftrace_list_end;  | 
|---|
| 119 | 119 |  ftrace_func_t ftrace_trace_function __read_mostly = ftrace_stub; | 
|---|
| 120 |  | -static struct ftrace_ops global_ops;  | 
|---|
 | 120 | +struct ftrace_ops global_ops;  | 
|---|
| 121 | 121 |   | 
|---|
| 122 | 122 |  #if ARCH_SUPPORTS_FTRACE_OPS | 
|---|
| 123 | 123 |  static void ftrace_ops_list_func(unsigned long ip, unsigned long parent_ip, | 
|---|
| 124 | 124 |  				 struct ftrace_ops *op, struct pt_regs *regs); | 
|---|
| 125 | 125 |  #else | 
|---|
| 126 | 126 |  /* See comment below, where ftrace_ops_list_func is defined */ | 
|---|
| 127 |  | -static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip,  | 
|---|
| 128 |  | -			      struct ftrace_ops *op, struct pt_regs *regs);  | 
|---|
| 129 |  | -#define ftrace_ops_list_func ftrace_ops_no_ops  | 
|---|
 | 127 | +static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip);  | 
|---|
 | 128 | +#define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops)  | 
|---|
| 130 | 129 |  #endif | 
|---|
| 131 |  | -  | 
|---|
| 132 |  | -/*  | 
|---|
| 133 |  | - * Traverse the ftrace_global_list, invoking all entries.  The reason that we  | 
|---|
| 134 |  | - * can use rcu_dereference_raw_notrace() is that elements removed from this list  | 
|---|
| 135 |  | - * are simply leaked, so there is no need to interact with a grace-period  | 
|---|
| 136 |  | - * mechanism.  The rcu_dereference_raw_notrace() calls are needed to handle  | 
|---|
| 137 |  | - * concurrent insertions into the ftrace_global_list.  | 
|---|
| 138 |  | - *  | 
|---|
| 139 |  | - * Silly Alpha and silly pointer-speculation compiler optimizations!  | 
|---|
| 140 |  | - */  | 
|---|
| 141 |  | -#define do_for_each_ftrace_op(op, list)			\  | 
|---|
| 142 |  | -	op = rcu_dereference_raw_notrace(list);			\  | 
|---|
| 143 |  | -	do  | 
|---|
| 144 |  | -  | 
|---|
| 145 |  | -/*  | 
|---|
| 146 |  | - * Optimized for just a single item in the list (as that is the normal case).  | 
|---|
| 147 |  | - */  | 
|---|
| 148 |  | -#define while_for_each_ftrace_op(op)				\  | 
|---|
| 149 |  | -	while (likely(op = rcu_dereference_raw_notrace((op)->next)) &&	\  | 
|---|
| 150 |  | -	       unlikely((op) != &ftrace_list_end))  | 
|---|
| 151 | 130 |   | 
|---|
| 152 | 131 |  static inline void ftrace_ops_init(struct ftrace_ops *ops) | 
|---|
| 153 | 132 |  { | 
|---|
| .. | .. | 
|---|
| 164 | 143 |  			    struct ftrace_ops *op, struct pt_regs *regs) | 
|---|
| 165 | 144 |  { | 
|---|
| 166 | 145 |  	struct trace_array *tr = op->private; | 
|---|
 | 146 | +	int pid;  | 
|---|
| 167 | 147 |   | 
|---|
| 168 |  | -	if (tr && this_cpu_read(tr->trace_buffer.data->ftrace_ignore_pid))  | 
|---|
| 169 |  | -		return;  | 
|---|
 | 148 | +	if (tr) {  | 
|---|
 | 149 | +		pid = this_cpu_read(tr->array_buffer.data->ftrace_ignore_pid);  | 
|---|
 | 150 | +		if (pid == FTRACE_PID_IGNORE)  | 
|---|
 | 151 | +			return;  | 
|---|
 | 152 | +		if (pid != FTRACE_PID_TRACE &&  | 
|---|
 | 153 | +		    pid != current->pid)  | 
|---|
 | 154 | +			return;  | 
|---|
 | 155 | +	}  | 
|---|
| 170 | 156 |   | 
|---|
| 171 | 157 |  	op->saved_func(ip, parent_ip, op, regs); | 
|---|
| 172 |  | -}  | 
|---|
| 173 |  | -  | 
|---|
| 174 |  | -static void ftrace_sync(struct work_struct *work)  | 
|---|
| 175 |  | -{  | 
|---|
| 176 |  | -	/*  | 
|---|
| 177 |  | -	 * This function is just a stub to implement a hard force  | 
|---|
| 178 |  | -	 * of synchronize_sched(). This requires synchronizing  | 
|---|
| 179 |  | -	 * tasks even in userspace and idle.  | 
|---|
| 180 |  | -	 *  | 
|---|
| 181 |  | -	 * Yes, function tracing is rude.  | 
|---|
| 182 |  | -	 */  | 
|---|
| 183 | 158 |  } | 
|---|
| 184 | 159 |   | 
|---|
| 185 | 160 |  static void ftrace_sync_ipi(void *data) | 
|---|
| .. | .. | 
|---|
| 187 | 162 |  	/* Probably not needed, but do it anyway */ | 
|---|
| 188 | 163 |  	smp_rmb(); | 
|---|
| 189 | 164 |  } | 
|---|
| 190 |  | -  | 
|---|
| 191 |  | -#ifdef CONFIG_FUNCTION_GRAPH_TRACER  | 
|---|
| 192 |  | -static void update_function_graph_func(void);  | 
|---|
| 193 |  | -  | 
|---|
| 194 |  | -/* Both enabled by default (can be cleared by function_graph tracer flags */  | 
|---|
| 195 |  | -static bool fgraph_sleep_time = true;  | 
|---|
| 196 |  | -static bool fgraph_graph_time = true;  | 
|---|
| 197 |  | -  | 
|---|
| 198 |  | -#else  | 
|---|
| 199 |  | -static inline void update_function_graph_func(void) { }  | 
|---|
| 200 |  | -#endif  | 
|---|
| 201 |  | -  | 
|---|
| 202 | 165 |   | 
|---|
| 203 | 166 |  static ftrace_func_t ftrace_ops_get_list_func(struct ftrace_ops *ops) | 
|---|
| 204 | 167 |  { | 
|---|
| .. | .. | 
|---|
| 267 | 230 |  	/* | 
|---|
| 268 | 231 |  	 * For static tracing, we need to be a bit more careful. | 
|---|
| 269 | 232 |  	 * The function change takes affect immediately. Thus, | 
|---|
| 270 |  | -	 * we need to coorditate the setting of the function_trace_ops  | 
|---|
 | 233 | +	 * we need to coordinate the setting of the function_trace_ops  | 
|---|
| 271 | 234 |  	 * with the setting of the ftrace_trace_function. | 
|---|
| 272 | 235 |  	 * | 
|---|
| 273 | 236 |  	 * Set the function to the list ops, which will call the | 
|---|
| .. | .. | 
|---|
| 279 | 242 |  	 * Make sure all CPUs see this. Yes this is slow, but static | 
|---|
| 280 | 243 |  	 * tracing is slow and nasty to have enabled. | 
|---|
| 281 | 244 |  	 */ | 
|---|
| 282 |  | -	schedule_on_each_cpu(ftrace_sync);  | 
|---|
 | 245 | +	synchronize_rcu_tasks_rude();  | 
|---|
| 283 | 246 |  	/* Now all cpus are using the list ops. */ | 
|---|
| 284 | 247 |  	function_trace_op = set_function_trace_op; | 
|---|
| 285 | 248 |  	/* Make sure the function_trace_op is visible on all CPUs */ | 
|---|
| .. | .. | 
|---|
| 336 | 299 |   | 
|---|
| 337 | 300 |  static void ftrace_update_trampoline(struct ftrace_ops *ops); | 
|---|
| 338 | 301 |   | 
|---|
| 339 |  | -static int __register_ftrace_function(struct ftrace_ops *ops)  | 
|---|
 | 302 | +int __register_ftrace_function(struct ftrace_ops *ops)  | 
|---|
| 340 | 303 |  { | 
|---|
| 341 | 304 |  	if (ops->flags & FTRACE_OPS_FL_DELETED) | 
|---|
| 342 | 305 |  		return -EINVAL; | 
|---|
| .. | .. | 
|---|
| 357 | 320 |  	if (ops->flags & FTRACE_OPS_FL_SAVE_REGS_IF_SUPPORTED) | 
|---|
| 358 | 321 |  		ops->flags |= FTRACE_OPS_FL_SAVE_REGS; | 
|---|
| 359 | 322 |  #endif | 
|---|
 | 323 | +	if (!ftrace_enabled && (ops->flags & FTRACE_OPS_FL_PERMANENT))  | 
|---|
 | 324 | +		return -EBUSY;  | 
|---|
| 360 | 325 |   | 
|---|
| 361 | 326 |  	if (!core_kernel_data((unsigned long)ops)) | 
|---|
| 362 | 327 |  		ops->flags |= FTRACE_OPS_FL_DYNAMIC; | 
|---|
| .. | .. | 
|---|
| 377 | 342 |  	return 0; | 
|---|
| 378 | 343 |  } | 
|---|
| 379 | 344 |   | 
|---|
| 380 |  | -static int __unregister_ftrace_function(struct ftrace_ops *ops)  | 
|---|
 | 345 | +int __unregister_ftrace_function(struct ftrace_ops *ops)  | 
|---|
| 381 | 346 |  { | 
|---|
| 382 | 347 |  	int ret; | 
|---|
| 383 | 348 |   | 
|---|
| .. | .. | 
|---|
| 494 | 459 |   | 
|---|
| 495 | 460 |  #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 
|---|
| 496 | 461 |  /* function graph compares on total time */ | 
|---|
| 497 |  | -static int function_stat_cmp(void *p1, void *p2)  | 
|---|
 | 462 | +static int function_stat_cmp(const void *p1, const void *p2)  | 
|---|
| 498 | 463 |  { | 
|---|
| 499 |  | -	struct ftrace_profile *a = p1;  | 
|---|
| 500 |  | -	struct ftrace_profile *b = p2;  | 
|---|
 | 464 | +	const struct ftrace_profile *a = p1;  | 
|---|
 | 465 | +	const struct ftrace_profile *b = p2;  | 
|---|
| 501 | 466 |   | 
|---|
| 502 | 467 |  	if (a->time < b->time) | 
|---|
| 503 | 468 |  		return -1; | 
|---|
| .. | .. | 
|---|
| 508 | 473 |  } | 
|---|
| 509 | 474 |  #else | 
|---|
| 510 | 475 |  /* not function graph compares against hits */ | 
|---|
| 511 |  | -static int function_stat_cmp(void *p1, void *p2)  | 
|---|
 | 476 | +static int function_stat_cmp(const void *p1, const void *p2)  | 
|---|
| 512 | 477 |  { | 
|---|
| 513 |  | -	struct ftrace_profile *a = p1;  | 
|---|
| 514 |  | -	struct ftrace_profile *b = p2;  | 
|---|
 | 478 | +	const struct ftrace_profile *a = p1;  | 
|---|
 | 479 | +	const struct ftrace_profile *b = p2;  | 
|---|
| 515 | 480 |   | 
|---|
| 516 | 481 |  	if (a->counter < b->counter) | 
|---|
| 517 | 482 |  		return -1; | 
|---|
| .. | .. | 
|---|
| 817 | 782 |  } | 
|---|
| 818 | 783 |   | 
|---|
| 819 | 784 |  #ifdef CONFIG_FUNCTION_GRAPH_TRACER | 
|---|
 | 785 | +static bool fgraph_graph_time = true;  | 
|---|
 | 786 | +  | 
|---|
 | 787 | +void ftrace_graph_graph_time_control(bool enable)  | 
|---|
 | 788 | +{  | 
|---|
 | 789 | +	fgraph_graph_time = enable;  | 
|---|
 | 790 | +}  | 
|---|
 | 791 | +  | 
|---|
| 820 | 792 |  static int profile_graph_entry(struct ftrace_graph_ent *trace) | 
|---|
| 821 | 793 |  { | 
|---|
| 822 |  | -	int index = current->curr_ret_stack;  | 
|---|
 | 794 | +	struct ftrace_ret_stack *ret_stack;  | 
|---|
| 823 | 795 |   | 
|---|
| 824 | 796 |  	function_profile_call(trace->func, 0, NULL, NULL); | 
|---|
| 825 | 797 |   | 
|---|
| .. | .. | 
|---|
| 827 | 799 |  	if (!current->ret_stack) | 
|---|
| 828 | 800 |  		return 0; | 
|---|
| 829 | 801 |   | 
|---|
| 830 |  | -	if (index >= 0 && index < FTRACE_RETFUNC_DEPTH)  | 
|---|
| 831 |  | -		current->ret_stack[index].subtime = 0;  | 
|---|
 | 802 | +	ret_stack = ftrace_graph_get_ret_stack(current, 0);  | 
|---|
 | 803 | +	if (ret_stack)  | 
|---|
 | 804 | +		ret_stack->subtime = 0;  | 
|---|
| 832 | 805 |   | 
|---|
| 833 | 806 |  	return 1; | 
|---|
| 834 | 807 |  } | 
|---|
| 835 | 808 |   | 
|---|
| 836 | 809 |  static void profile_graph_return(struct ftrace_graph_ret *trace) | 
|---|
| 837 | 810 |  { | 
|---|
 | 811 | +	struct ftrace_ret_stack *ret_stack;  | 
|---|
| 838 | 812 |  	struct ftrace_profile_stat *stat; | 
|---|
| 839 | 813 |  	unsigned long long calltime; | 
|---|
| 840 | 814 |  	struct ftrace_profile *rec; | 
|---|
| .. | .. | 
|---|
| 852 | 826 |  	calltime = trace->rettime - trace->calltime; | 
|---|
| 853 | 827 |   | 
|---|
| 854 | 828 |  	if (!fgraph_graph_time) { | 
|---|
| 855 |  | -		int index;  | 
|---|
| 856 |  | -  | 
|---|
| 857 |  | -		index = current->curr_ret_stack;  | 
|---|
| 858 | 829 |   | 
|---|
| 859 | 830 |  		/* Append this call time to the parent time to subtract */ | 
|---|
| 860 |  | -		if (index)  | 
|---|
| 861 |  | -			current->ret_stack[index - 1].subtime += calltime;  | 
|---|
 | 831 | +		ret_stack = ftrace_graph_get_ret_stack(current, 1);  | 
|---|
 | 832 | +		if (ret_stack)  | 
|---|
 | 833 | +			ret_stack->subtime += calltime;  | 
|---|
| 862 | 834 |   | 
|---|
| 863 |  | -		if (current->ret_stack[index].subtime < calltime)  | 
|---|
| 864 |  | -			calltime -= current->ret_stack[index].subtime;  | 
|---|
 | 835 | +		ret_stack = ftrace_graph_get_ret_stack(current, 0);  | 
|---|
 | 836 | +		if (ret_stack && ret_stack->subtime < calltime)  | 
|---|
 | 837 | +			calltime -= ret_stack->subtime;  | 
|---|
| 865 | 838 |  		else | 
|---|
| 866 | 839 |  			calltime = 0; | 
|---|
| 867 | 840 |  	} | 
|---|
| .. | .. | 
|---|
| 876 | 849 |  	local_irq_restore(flags); | 
|---|
| 877 | 850 |  } | 
|---|
| 878 | 851 |   | 
|---|
 | 852 | +static struct fgraph_ops fprofiler_ops = {  | 
|---|
 | 853 | +	.entryfunc = &profile_graph_entry,  | 
|---|
 | 854 | +	.retfunc = &profile_graph_return,  | 
|---|
 | 855 | +};  | 
|---|
 | 856 | +  | 
|---|
| 879 | 857 |  static int register_ftrace_profiler(void) | 
|---|
| 880 | 858 |  { | 
|---|
| 881 |  | -	return register_ftrace_graph(&profile_graph_return,  | 
|---|
| 882 |  | -				     &profile_graph_entry);  | 
|---|
 | 859 | +	return register_ftrace_graph(&fprofiler_ops);  | 
|---|
| 883 | 860 |  } | 
|---|
| 884 | 861 |   | 
|---|
| 885 | 862 |  static void unregister_ftrace_profiler(void) | 
|---|
| 886 | 863 |  { | 
|---|
| 887 |  | -	unregister_ftrace_graph();  | 
|---|
 | 864 | +	unregister_ftrace_graph(&fprofiler_ops);  | 
|---|
| 888 | 865 |  } | 
|---|
| 889 | 866 |  #else | 
|---|
| 890 | 867 |  static struct ftrace_ops ftrace_profile_ops __read_mostly = { | 
|---|
| .. | .. | 
|---|
| 936 | 913 |  			ftrace_profile_enabled = 0; | 
|---|
| 937 | 914 |  			/* | 
|---|
| 938 | 915 |  			 * unregister_ftrace_profiler calls stop_machine | 
|---|
| 939 |  | -			 * so this acts like an synchronize_sched.  | 
|---|
 | 916 | +			 * so this acts like an synchronize_rcu.  | 
|---|
| 940 | 917 |  			 */ | 
|---|
| 941 | 918 |  			unregister_ftrace_profiler(); | 
|---|
| 942 | 919 |  		} | 
|---|
| .. | .. | 
|---|
| 1023 | 1000 |  } | 
|---|
| 1024 | 1001 |  #endif /* CONFIG_FUNCTION_PROFILER */ | 
|---|
| 1025 | 1002 |   | 
|---|
| 1026 |  | -#ifdef CONFIG_FUNCTION_GRAPH_TRACER  | 
|---|
| 1027 |  | -static int ftrace_graph_active;  | 
|---|
| 1028 |  | -#else  | 
|---|
| 1029 |  | -# define ftrace_graph_active 0  | 
|---|
| 1030 |  | -#endif  | 
|---|
| 1031 |  | -  | 
|---|
| 1032 | 1003 |  #ifdef CONFIG_DYNAMIC_FTRACE | 
|---|
| 1033 | 1004 |   | 
|---|
| 1034 | 1005 |  static struct ftrace_ops *removed_ops; | 
|---|
| .. | .. | 
|---|
| 1042 | 1013 |  #ifndef CONFIG_FTRACE_MCOUNT_RECORD | 
|---|
| 1043 | 1014 |  # error Dynamic ftrace depends on MCOUNT_RECORD | 
|---|
| 1044 | 1015 |  #endif | 
|---|
| 1045 |  | -  | 
|---|
| 1046 |  | -struct ftrace_func_entry {  | 
|---|
| 1047 |  | -	struct hlist_node hlist;  | 
|---|
| 1048 |  | -	unsigned long ip;  | 
|---|
| 1049 |  | -};  | 
|---|
| 1050 | 1016 |   | 
|---|
| 1051 | 1017 |  struct ftrace_func_probe { | 
|---|
| 1052 | 1018 |  	struct ftrace_probe_ops	*probe_ops; | 
|---|
| .. | .. | 
|---|
| 1069 | 1035 |  }; | 
|---|
| 1070 | 1036 |  #define EMPTY_HASH	((struct ftrace_hash *)&empty_hash) | 
|---|
| 1071 | 1037 |   | 
|---|
| 1072 |  | -static struct ftrace_ops global_ops = {  | 
|---|
 | 1038 | +struct ftrace_ops global_ops = {  | 
|---|
| 1073 | 1039 |  	.func				= ftrace_stub, | 
|---|
| 1074 | 1040 |  	.local_hash.notrace_hash	= EMPTY_HASH, | 
|---|
| 1075 | 1041 |  	.local_hash.filter_hash		= EMPTY_HASH, | 
|---|
| .. | .. | 
|---|
| 1088 | 1054 |   | 
|---|
| 1089 | 1055 |  	/* | 
|---|
| 1090 | 1056 |  	 * Some of the ops may be dynamically allocated, | 
|---|
| 1091 |  | -	 * they are freed after a synchronize_sched().  | 
|---|
 | 1057 | +	 * they are freed after a synchronize_rcu().  | 
|---|
| 1092 | 1058 |  	 */ | 
|---|
| 1093 | 1059 |  	preempt_disable_notrace(); | 
|---|
| 1094 | 1060 |   | 
|---|
| .. | .. | 
|---|
| 1130 | 1096 |   | 
|---|
| 1131 | 1097 |  #define ENTRY_SIZE sizeof(struct dyn_ftrace) | 
|---|
| 1132 | 1098 |  #define ENTRIES_PER_PAGE (PAGE_SIZE / ENTRY_SIZE) | 
|---|
| 1133 |  | -  | 
|---|
| 1134 |  | -/* estimate from running different kernels */  | 
|---|
| 1135 |  | -#define NR_TO_INIT		10000  | 
|---|
| 1136 | 1099 |   | 
|---|
| 1137 | 1100 |  static struct ftrace_page	*ftrace_pages_start; | 
|---|
| 1138 | 1101 |  static struct ftrace_page	*ftrace_pages; | 
|---|
| .. | .. | 
|---|
| 1288 | 1251 |  { | 
|---|
| 1289 | 1252 |  	if (!hash || hash == EMPTY_HASH) | 
|---|
| 1290 | 1253 |  		return; | 
|---|
| 1291 |  | -	call_rcu_sched(&hash->rcu, __free_ftrace_hash_rcu);  | 
|---|
 | 1254 | +	call_rcu(&hash->rcu, __free_ftrace_hash_rcu);  | 
|---|
| 1292 | 1255 |  } | 
|---|
| 1293 | 1256 |   | 
|---|
| 1294 | 1257 |  void ftrace_free_filter(struct ftrace_ops *ops) | 
|---|
| .. | .. | 
|---|
| 1332 | 1295 |  	if (!ftrace_mod) | 
|---|
| 1333 | 1296 |  		return -ENOMEM; | 
|---|
| 1334 | 1297 |   | 
|---|
 | 1298 | +	INIT_LIST_HEAD(&ftrace_mod->list);  | 
|---|
| 1335 | 1299 |  	ftrace_mod->func = kstrdup(func, GFP_KERNEL); | 
|---|
| 1336 | 1300 |  	ftrace_mod->module = kstrdup(module, GFP_KERNEL); | 
|---|
| 1337 | 1301 |  	ftrace_mod->enable = enable; | 
|---|
| .. | .. | 
|---|
| 1395 | 1359 |  static int ftrace_hash_ipmodify_update(struct ftrace_ops *ops, | 
|---|
| 1396 | 1360 |  				       struct ftrace_hash *new_hash); | 
|---|
| 1397 | 1361 |   | 
|---|
| 1398 |  | -static struct ftrace_hash *  | 
|---|
| 1399 |  | -__ftrace_hash_move(struct ftrace_hash *src)  | 
|---|
 | 1362 | +static struct ftrace_hash *dup_hash(struct ftrace_hash *src, int size)  | 
|---|
| 1400 | 1363 |  { | 
|---|
| 1401 | 1364 |  	struct ftrace_func_entry *entry; | 
|---|
| 1402 |  | -	struct hlist_node *tn;  | 
|---|
| 1403 |  | -	struct hlist_head *hhd;  | 
|---|
| 1404 | 1365 |  	struct ftrace_hash *new_hash; | 
|---|
| 1405 |  | -	int size = src->count;  | 
|---|
 | 1366 | +	struct hlist_head *hhd;  | 
|---|
 | 1367 | +	struct hlist_node *tn;  | 
|---|
| 1406 | 1368 |  	int bits = 0; | 
|---|
| 1407 | 1369 |  	int i; | 
|---|
| 1408 | 1370 |   | 
|---|
| 1409 | 1371 |  	/* | 
|---|
| 1410 |  | -	 * If the new source is empty, just return the empty_hash.  | 
|---|
 | 1372 | +	 * Use around half the size (max bit of it), but  | 
|---|
 | 1373 | +	 * a minimum of 2 is fine (as size of 0 or 1 both give 1 for bits).  | 
|---|
| 1411 | 1374 |  	 */ | 
|---|
| 1412 |  | -	if (ftrace_hash_empty(src))  | 
|---|
| 1413 |  | -		return EMPTY_HASH;  | 
|---|
| 1414 |  | -  | 
|---|
| 1415 |  | -	/*  | 
|---|
| 1416 |  | -	 * Make the hash size about 1/2 the # found  | 
|---|
| 1417 |  | -	 */  | 
|---|
| 1418 |  | -	for (size /= 2; size; size >>= 1)  | 
|---|
| 1419 |  | -		bits++;  | 
|---|
 | 1375 | +	bits = fls(size / 2);  | 
|---|
| 1420 | 1376 |   | 
|---|
| 1421 | 1377 |  	/* Don't allocate too much */ | 
|---|
| 1422 | 1378 |  	if (bits > FTRACE_HASH_MAX_BITS) | 
|---|
| .. | .. | 
|---|
| 1436 | 1392 |  			__add_hash_entry(new_hash, entry); | 
|---|
| 1437 | 1393 |  		} | 
|---|
| 1438 | 1394 |  	} | 
|---|
| 1439 |  | -  | 
|---|
| 1440 | 1395 |  	return new_hash; | 
|---|
 | 1396 | +}  | 
|---|
 | 1397 | +  | 
|---|
 | 1398 | +static struct ftrace_hash *  | 
|---|
 | 1399 | +__ftrace_hash_move(struct ftrace_hash *src)  | 
|---|
 | 1400 | +{  | 
|---|
 | 1401 | +	int size = src->count;  | 
|---|
 | 1402 | +  | 
|---|
 | 1403 | +	/*  | 
|---|
 | 1404 | +	 * If the new source is empty, just return the empty_hash.  | 
|---|
 | 1405 | +	 */  | 
|---|
 | 1406 | +	if (ftrace_hash_empty(src))  | 
|---|
 | 1407 | +		return EMPTY_HASH;  | 
|---|
 | 1408 | +  | 
|---|
 | 1409 | +	return dup_hash(src, size);  | 
|---|
| 1441 | 1410 |  } | 
|---|
| 1442 | 1411 |   | 
|---|
| 1443 | 1412 |  static int | 
|---|
| .. | .. | 
|---|
| 1483 | 1452 |  { | 
|---|
| 1484 | 1453 |  	/* | 
|---|
| 1485 | 1454 |  	 * The function record is a match if it exists in the filter | 
|---|
| 1486 |  | -	 * hash and not in the notrace hash. Note, an emty hash is  | 
|---|
 | 1455 | +	 * hash and not in the notrace hash. Note, an empty hash is  | 
|---|
| 1487 | 1456 |  	 * considered a match for the filter hash, but an empty | 
|---|
| 1488 | 1457 |  	 * notrace hash is considered not in the notrace hash. | 
|---|
| 1489 | 1458 |  	 */ | 
|---|
| .. | .. | 
|---|
| 1503 | 1472 |   * the ip is not in the ops->notrace_hash. | 
|---|
| 1504 | 1473 |   * | 
|---|
| 1505 | 1474 |   * This needs to be called with preemption disabled as | 
|---|
| 1506 |  | - * the hashes are freed with call_rcu_sched().  | 
|---|
 | 1475 | + * the hashes are freed with call_rcu().  | 
|---|
| 1507 | 1476 |   */ | 
|---|
| 1508 |  | -static int  | 
|---|
 | 1477 | +int  | 
|---|
| 1509 | 1478 |  ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs) | 
|---|
| 1510 | 1479 |  { | 
|---|
| 1511 | 1480 |  	struct ftrace_ops_hash hash; | 
|---|
| .. | .. | 
|---|
| 1559 | 1528 |  	return 0; | 
|---|
| 1560 | 1529 |  } | 
|---|
| 1561 | 1530 |   | 
|---|
 | 1531 | +static struct dyn_ftrace *lookup_rec(unsigned long start, unsigned long end)  | 
|---|
 | 1532 | +{  | 
|---|
 | 1533 | +	struct ftrace_page *pg;  | 
|---|
 | 1534 | +	struct dyn_ftrace *rec = NULL;  | 
|---|
 | 1535 | +	struct dyn_ftrace key;  | 
|---|
 | 1536 | +  | 
|---|
 | 1537 | +	key.ip = start;  | 
|---|
 | 1538 | +	key.flags = end;	/* overload flags, as it is unsigned long */  | 
|---|
 | 1539 | +  | 
|---|
 | 1540 | +	for (pg = ftrace_pages_start; pg; pg = pg->next) {  | 
|---|
 | 1541 | +		if (end < pg->records[0].ip ||  | 
|---|
 | 1542 | +		    start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))  | 
|---|
 | 1543 | +			continue;  | 
|---|
 | 1544 | +		rec = bsearch(&key, pg->records, pg->index,  | 
|---|
 | 1545 | +			      sizeof(struct dyn_ftrace),  | 
|---|
 | 1546 | +			      ftrace_cmp_recs);  | 
|---|
 | 1547 | +		if (rec)  | 
|---|
 | 1548 | +			break;  | 
|---|
 | 1549 | +	}  | 
|---|
 | 1550 | +	return rec;  | 
|---|
 | 1551 | +}  | 
|---|
 | 1552 | +  | 
|---|
| 1562 | 1553 |  /** | 
|---|
| 1563 | 1554 |   * ftrace_location_range - return the first address of a traced location | 
|---|
| 1564 | 1555 |   *	if it touches the given ip range | 
|---|
| .. | .. | 
|---|
| 1573 | 1564 |   */ | 
|---|
| 1574 | 1565 |  unsigned long ftrace_location_range(unsigned long start, unsigned long end) | 
|---|
| 1575 | 1566 |  { | 
|---|
| 1576 |  | -	struct ftrace_page *pg;  | 
|---|
| 1577 | 1567 |  	struct dyn_ftrace *rec; | 
|---|
| 1578 |  | -	struct dyn_ftrace key;  | 
|---|
| 1579 | 1568 |   | 
|---|
| 1580 |  | -	key.ip = start;  | 
|---|
| 1581 |  | -	key.flags = end;	/* overload flags, as it is unsigned long */  | 
|---|
| 1582 |  | -  | 
|---|
| 1583 |  | -	for (pg = ftrace_pages_start; pg; pg = pg->next) {  | 
|---|
| 1584 |  | -		if (end < pg->records[0].ip ||  | 
|---|
| 1585 |  | -		    start >= (pg->records[pg->index - 1].ip + MCOUNT_INSN_SIZE))  | 
|---|
| 1586 |  | -			continue;  | 
|---|
| 1587 |  | -		rec = bsearch(&key, pg->records, pg->index,  | 
|---|
| 1588 |  | -			      sizeof(struct dyn_ftrace),  | 
|---|
| 1589 |  | -			      ftrace_cmp_recs);  | 
|---|
| 1590 |  | -		if (rec)  | 
|---|
| 1591 |  | -			return rec->ip;  | 
|---|
| 1592 |  | -	}  | 
|---|
 | 1569 | +	rec = lookup_rec(start, end);  | 
|---|
 | 1570 | +	if (rec)  | 
|---|
 | 1571 | +		return rec->ip;  | 
|---|
| 1593 | 1572 |   | 
|---|
| 1594 | 1573 |  	return 0; | 
|---|
| 1595 | 1574 |  } | 
|---|
| .. | .. | 
|---|
| 1742 | 1721 |  			if (FTRACE_WARN_ON(ftrace_rec_count(rec) == FTRACE_REF_MAX)) | 
|---|
| 1743 | 1722 |  				return false; | 
|---|
| 1744 | 1723 |   | 
|---|
 | 1724 | +			if (ops->flags & FTRACE_OPS_FL_DIRECT)  | 
|---|
 | 1725 | +				rec->flags |= FTRACE_FL_DIRECT;  | 
|---|
 | 1726 | +  | 
|---|
| 1745 | 1727 |  			/* | 
|---|
| 1746 | 1728 |  			 * If there's only a single callback registered to a | 
|---|
| 1747 | 1729 |  			 * function, and the ops has a trampoline registered | 
|---|
| .. | .. | 
|---|
| 1768 | 1750 |  			if (FTRACE_WARN_ON(ftrace_rec_count(rec) == 0)) | 
|---|
| 1769 | 1751 |  				return false; | 
|---|
| 1770 | 1752 |  			rec->flags--; | 
|---|
 | 1753 | +  | 
|---|
 | 1754 | +			/*  | 
|---|
 | 1755 | +			 * Only the internal direct_ops should have the  | 
|---|
 | 1756 | +			 * DIRECT flag set. Thus, if it is removing a  | 
|---|
 | 1757 | +			 * function, then that function should no longer  | 
|---|
 | 1758 | +			 * be direct.  | 
|---|
 | 1759 | +			 */  | 
|---|
 | 1760 | +			if (ops->flags & FTRACE_OPS_FL_DIRECT)  | 
|---|
 | 1761 | +				rec->flags &= ~FTRACE_FL_DIRECT;  | 
|---|
| 1771 | 1762 |   | 
|---|
| 1772 | 1763 |  			/* | 
|---|
| 1773 | 1764 |  			 * If the rec had REGS enabled and the ops that is | 
|---|
| .. | .. | 
|---|
| 1803 | 1794 |  		count++; | 
|---|
| 1804 | 1795 |   | 
|---|
| 1805 | 1796 |  		/* Must match FTRACE_UPDATE_CALLS in ftrace_modify_all_code() */ | 
|---|
| 1806 |  | -		update |= ftrace_test_record(rec, 1) != FTRACE_UPDATE_IGNORE;  | 
|---|
 | 1797 | +		update |= ftrace_test_record(rec, true) != FTRACE_UPDATE_IGNORE;  | 
|---|
| 1807 | 1798 |   | 
|---|
| 1808 | 1799 |  		/* Shortcut, if we handled all records, we are done. */ | 
|---|
| 1809 | 1800 |  		if (!all && count == hash->count) | 
|---|
| .. | .. | 
|---|
| 1981 | 1972 |  	char ins[MCOUNT_INSN_SIZE]; | 
|---|
| 1982 | 1973 |  	int i; | 
|---|
| 1983 | 1974 |   | 
|---|
| 1984 |  | -	if (probe_kernel_read(ins, p, MCOUNT_INSN_SIZE)) {  | 
|---|
 | 1975 | +	if (copy_from_kernel_nofault(ins, p, MCOUNT_INSN_SIZE)) {  | 
|---|
| 1985 | 1976 |  		printk(KERN_CONT "%s[FAULT] %px\n", fmt, p); | 
|---|
| 1986 | 1977 |  		return; | 
|---|
| 1987 | 1978 |  	} | 
|---|
| .. | .. | 
|---|
| 2025 | 2016 |   * modifying the code. @failed should be one of either: | 
|---|
| 2026 | 2017 |   * EFAULT - if the problem happens on reading the @ip address | 
|---|
| 2027 | 2018 |   * EINVAL - if what is read at @ip is not what was expected | 
|---|
| 2028 |  | - * EPERM - if the problem happens on writting to the @ip address  | 
|---|
 | 2019 | + * EPERM - if the problem happens on writing to the @ip address  | 
|---|
| 2029 | 2020 |   */ | 
|---|
| 2030 | 2021 |  void ftrace_bug(int failed, struct dyn_ftrace *rec) | 
|---|
| 2031 | 2022 |  { | 
|---|
| 2032 | 2023 |  	unsigned long ip = rec ? rec->ip : 0; | 
|---|
| 2033 | 2024 |   | 
|---|
 | 2025 | +	pr_info("------------[ ftrace bug ]------------\n");  | 
|---|
 | 2026 | +  | 
|---|
| 2034 | 2027 |  	switch (failed) { | 
|---|
| 2035 | 2028 |  	case -EFAULT: | 
|---|
| 2036 |  | -		FTRACE_WARN_ON_ONCE(1);  | 
|---|
| 2037 | 2029 |  		pr_info("ftrace faulted on modifying "); | 
|---|
| 2038 |  | -		print_ip_sym(ip);  | 
|---|
 | 2030 | +		print_ip_sym(KERN_INFO, ip);  | 
|---|
| 2039 | 2031 |  		break; | 
|---|
| 2040 | 2032 |  	case -EINVAL: | 
|---|
| 2041 |  | -		FTRACE_WARN_ON_ONCE(1);  | 
|---|
| 2042 | 2033 |  		pr_info("ftrace failed to modify "); | 
|---|
| 2043 |  | -		print_ip_sym(ip);  | 
|---|
 | 2034 | +		print_ip_sym(KERN_INFO, ip);  | 
|---|
| 2044 | 2035 |  		print_ip_ins(" actual:   ", (unsigned char *)ip); | 
|---|
| 2045 | 2036 |  		pr_cont("\n"); | 
|---|
| 2046 | 2037 |  		if (ftrace_expected) { | 
|---|
| .. | .. | 
|---|
| 2049 | 2040 |  		} | 
|---|
| 2050 | 2041 |  		break; | 
|---|
| 2051 | 2042 |  	case -EPERM: | 
|---|
| 2052 |  | -		FTRACE_WARN_ON_ONCE(1);  | 
|---|
| 2053 | 2043 |  		pr_info("ftrace faulted on writing "); | 
|---|
| 2054 |  | -		print_ip_sym(ip);  | 
|---|
 | 2044 | +		print_ip_sym(KERN_INFO, ip);  | 
|---|
| 2055 | 2045 |  		break; | 
|---|
| 2056 | 2046 |  	default: | 
|---|
| 2057 |  | -		FTRACE_WARN_ON_ONCE(1);  | 
|---|
| 2058 | 2047 |  		pr_info("ftrace faulted on unknown error "); | 
|---|
| 2059 |  | -		print_ip_sym(ip);  | 
|---|
 | 2048 | +		print_ip_sym(KERN_INFO, ip);  | 
|---|
| 2060 | 2049 |  	} | 
|---|
| 2061 | 2050 |  	print_bug_type(); | 
|---|
| 2062 | 2051 |  	if (rec) { | 
|---|
| .. | .. | 
|---|
| 2081 | 2070 |  		ip = ftrace_get_addr_curr(rec); | 
|---|
| 2082 | 2071 |  		pr_cont("\n expected tramp: %lx\n", ip); | 
|---|
| 2083 | 2072 |  	} | 
|---|
 | 2073 | +  | 
|---|
 | 2074 | +	FTRACE_WARN_ON_ONCE(1);  | 
|---|
| 2084 | 2075 |  } | 
|---|
| 2085 | 2076 |   | 
|---|
| 2086 |  | -static int ftrace_check_record(struct dyn_ftrace *rec, int enable, int update)  | 
|---|
 | 2077 | +static int ftrace_check_record(struct dyn_ftrace *rec, bool enable, bool update)  | 
|---|
| 2087 | 2078 |  { | 
|---|
| 2088 | 2079 |  	unsigned long flag = 0UL; | 
|---|
| 2089 | 2080 |   | 
|---|
| .. | .. | 
|---|
| 2110 | 2101 |  	 * If enabling and the REGS flag does not match the REGS_EN, or | 
|---|
| 2111 | 2102 |  	 * the TRAMP flag doesn't match the TRAMP_EN, then do not ignore | 
|---|
| 2112 | 2103 |  	 * this record. Set flags to fail the compare against ENABLED. | 
|---|
 | 2104 | +	 * Same for direct calls.  | 
|---|
| 2113 | 2105 |  	 */ | 
|---|
| 2114 | 2106 |  	if (flag) { | 
|---|
| 2115 |  | -		if (!(rec->flags & FTRACE_FL_REGS) !=   | 
|---|
 | 2107 | +		if (!(rec->flags & FTRACE_FL_REGS) !=  | 
|---|
| 2116 | 2108 |  		    !(rec->flags & FTRACE_FL_REGS_EN)) | 
|---|
| 2117 | 2109 |  			flag |= FTRACE_FL_REGS; | 
|---|
| 2118 | 2110 |   | 
|---|
| 2119 |  | -		if (!(rec->flags & FTRACE_FL_TRAMP) !=   | 
|---|
 | 2111 | +		if (!(rec->flags & FTRACE_FL_TRAMP) !=  | 
|---|
| 2120 | 2112 |  		    !(rec->flags & FTRACE_FL_TRAMP_EN)) | 
|---|
| 2121 | 2113 |  			flag |= FTRACE_FL_TRAMP; | 
|---|
 | 2114 | +  | 
|---|
 | 2115 | +		/*  | 
|---|
 | 2116 | +		 * Direct calls are special, as count matters.  | 
|---|
 | 2117 | +		 * We must test the record for direct, if the  | 
|---|
 | 2118 | +		 * DIRECT and DIRECT_EN do not match, but only  | 
|---|
 | 2119 | +		 * if the count is 1. That's because, if the  | 
|---|
 | 2120 | +		 * count is something other than one, we do not  | 
|---|
 | 2121 | +		 * want the direct enabled (it will be done via the  | 
|---|
 | 2122 | +		 * direct helper). But if DIRECT_EN is set, and  | 
|---|
 | 2123 | +		 * the count is not one, we need to clear it.  | 
|---|
 | 2124 | +		 */  | 
|---|
 | 2125 | +		if (ftrace_rec_count(rec) == 1) {  | 
|---|
 | 2126 | +			if (!(rec->flags & FTRACE_FL_DIRECT) !=  | 
|---|
 | 2127 | +			    !(rec->flags & FTRACE_FL_DIRECT_EN))  | 
|---|
 | 2128 | +				flag |= FTRACE_FL_DIRECT;  | 
|---|
 | 2129 | +		} else if (rec->flags & FTRACE_FL_DIRECT_EN) {  | 
|---|
 | 2130 | +			flag |= FTRACE_FL_DIRECT;  | 
|---|
 | 2131 | +		}  | 
|---|
| 2122 | 2132 |  	} | 
|---|
| 2123 | 2133 |   | 
|---|
| 2124 | 2134 |  	/* If the state of this record hasn't changed, then do nothing */ | 
|---|
| .. | .. | 
|---|
| 2142 | 2152 |  					rec->flags |= FTRACE_FL_TRAMP_EN; | 
|---|
| 2143 | 2153 |  				else | 
|---|
| 2144 | 2154 |  					rec->flags &= ~FTRACE_FL_TRAMP_EN; | 
|---|
 | 2155 | +			}  | 
|---|
 | 2156 | +			if (flag & FTRACE_FL_DIRECT) {  | 
|---|
 | 2157 | +				/*  | 
|---|
 | 2158 | +				 * If there's only one user (direct_ops helper)  | 
|---|
 | 2159 | +				 * then we can call the direct function  | 
|---|
 | 2160 | +				 * directly (no ftrace trampoline).  | 
|---|
 | 2161 | +				 */  | 
|---|
 | 2162 | +				if (ftrace_rec_count(rec) == 1) {  | 
|---|
 | 2163 | +					if (rec->flags & FTRACE_FL_DIRECT)  | 
|---|
 | 2164 | +						rec->flags |= FTRACE_FL_DIRECT_EN;  | 
|---|
 | 2165 | +					else  | 
|---|
 | 2166 | +						rec->flags &= ~FTRACE_FL_DIRECT_EN;  | 
|---|
 | 2167 | +				} else {  | 
|---|
 | 2168 | +					/*  | 
|---|
 | 2169 | +					 * Can only call directly if there's  | 
|---|
 | 2170 | +					 * only one callback to the function.  | 
|---|
 | 2171 | +					 */  | 
|---|
 | 2172 | +					rec->flags &= ~FTRACE_FL_DIRECT_EN;  | 
|---|
 | 2173 | +				}  | 
|---|
| 2145 | 2174 |  			} | 
|---|
| 2146 | 2175 |  		} | 
|---|
| 2147 | 2176 |   | 
|---|
| .. | .. | 
|---|
| 2172 | 2201 |  			 * and REGS states. The _EN flags must be disabled though. | 
|---|
| 2173 | 2202 |  			 */ | 
|---|
| 2174 | 2203 |  			rec->flags &= ~(FTRACE_FL_ENABLED | FTRACE_FL_TRAMP_EN | | 
|---|
| 2175 |  | -					FTRACE_FL_REGS_EN);  | 
|---|
 | 2204 | +					FTRACE_FL_REGS_EN | FTRACE_FL_DIRECT_EN);  | 
|---|
| 2176 | 2205 |  	} | 
|---|
| 2177 | 2206 |   | 
|---|
| 2178 | 2207 |  	ftrace_bug_type = FTRACE_BUG_NOP; | 
|---|
| .. | .. | 
|---|
| 2182 | 2211 |  /** | 
|---|
| 2183 | 2212 |   * ftrace_update_record, set a record that now is tracing or not | 
|---|
| 2184 | 2213 |   * @rec: the record to update | 
|---|
| 2185 |  | - * @enable: set to 1 if the record is tracing, zero to force disable  | 
|---|
 | 2214 | + * @enable: set to true if the record is tracing, false to force disable  | 
|---|
| 2186 | 2215 |   * | 
|---|
| 2187 | 2216 |   * The records that represent all functions that can be traced need | 
|---|
| 2188 | 2217 |   * to be updated when tracing has been enabled. | 
|---|
| 2189 | 2218 |   */ | 
|---|
| 2190 |  | -int ftrace_update_record(struct dyn_ftrace *rec, int enable)  | 
|---|
 | 2219 | +int ftrace_update_record(struct dyn_ftrace *rec, bool enable)  | 
|---|
| 2191 | 2220 |  { | 
|---|
| 2192 |  | -	return ftrace_check_record(rec, enable, 1);  | 
|---|
 | 2221 | +	return ftrace_check_record(rec, enable, true);  | 
|---|
| 2193 | 2222 |  } | 
|---|
| 2194 | 2223 |   | 
|---|
| 2195 | 2224 |  /** | 
|---|
| 2196 | 2225 |   * ftrace_test_record, check if the record has been enabled or not | 
|---|
| 2197 | 2226 |   * @rec: the record to test | 
|---|
| 2198 |  | - * @enable: set to 1 to check if enabled, 0 if it is disabled  | 
|---|
 | 2227 | + * @enable: set to true to check if enabled, false if it is disabled  | 
|---|
| 2199 | 2228 |   * | 
|---|
| 2200 | 2229 |   * The arch code may need to test if a record is already set to | 
|---|
| 2201 | 2230 |   * tracing to determine how to modify the function code that it | 
|---|
| 2202 | 2231 |   * represents. | 
|---|
| 2203 | 2232 |   */ | 
|---|
| 2204 |  | -int ftrace_test_record(struct dyn_ftrace *rec, int enable)  | 
|---|
 | 2233 | +int ftrace_test_record(struct dyn_ftrace *rec, bool enable)  | 
|---|
| 2205 | 2234 |  { | 
|---|
| 2206 |  | -	return ftrace_check_record(rec, enable, 0);  | 
|---|
 | 2235 | +	return ftrace_check_record(rec, enable, false);  | 
|---|
| 2207 | 2236 |  } | 
|---|
| 2208 | 2237 |   | 
|---|
| 2209 | 2238 |  static struct ftrace_ops * | 
|---|
| .. | .. | 
|---|
| 2255 | 2284 |   | 
|---|
| 2256 | 2285 |  		if (hash_contains_ip(ip, op->func_hash)) | 
|---|
| 2257 | 2286 |  			return op; | 
|---|
| 2258 |  | -	}   | 
|---|
 | 2287 | +	}  | 
|---|
| 2259 | 2288 |   | 
|---|
| 2260 | 2289 |  	return NULL; | 
|---|
| 2261 | 2290 |  } | 
|---|
| .. | .. | 
|---|
| 2345 | 2374 |  	return NULL; | 
|---|
| 2346 | 2375 |  } | 
|---|
| 2347 | 2376 |   | 
|---|
 | 2377 | +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS  | 
|---|
 | 2378 | +/* Protected by rcu_tasks for reading, and direct_mutex for writing */  | 
|---|
 | 2379 | +static struct ftrace_hash *direct_functions = EMPTY_HASH;  | 
|---|
 | 2380 | +static DEFINE_MUTEX(direct_mutex);  | 
|---|
 | 2381 | +int ftrace_direct_func_count;  | 
|---|
 | 2382 | +  | 
|---|
 | 2383 | +/*  | 
|---|
 | 2384 | + * Search the direct_functions hash to see if the given instruction pointer  | 
|---|
 | 2385 | + * has a direct caller attached to it.  | 
|---|
 | 2386 | + */  | 
|---|
 | 2387 | +unsigned long ftrace_find_rec_direct(unsigned long ip)  | 
|---|
 | 2388 | +{  | 
|---|
 | 2389 | +	struct ftrace_func_entry *entry;  | 
|---|
 | 2390 | +  | 
|---|
 | 2391 | +	entry = __ftrace_lookup_ip(direct_functions, ip);  | 
|---|
 | 2392 | +	if (!entry)  | 
|---|
 | 2393 | +		return 0;  | 
|---|
 | 2394 | +  | 
|---|
 | 2395 | +	return entry->direct;  | 
|---|
 | 2396 | +}  | 
|---|
 | 2397 | +  | 
|---|
 | 2398 | +static void call_direct_funcs(unsigned long ip, unsigned long pip,  | 
|---|
 | 2399 | +			      struct ftrace_ops *ops, struct pt_regs *regs)  | 
|---|
 | 2400 | +{  | 
|---|
 | 2401 | +	unsigned long addr;  | 
|---|
 | 2402 | +  | 
|---|
 | 2403 | +	addr = ftrace_find_rec_direct(ip);  | 
|---|
 | 2404 | +	if (!addr)  | 
|---|
 | 2405 | +		return;  | 
|---|
 | 2406 | +  | 
|---|
 | 2407 | +	arch_ftrace_set_direct_caller(regs, addr);  | 
|---|
 | 2408 | +}  | 
|---|
 | 2409 | +  | 
|---|
 | 2410 | +struct ftrace_ops direct_ops = {  | 
|---|
 | 2411 | +	.func		= call_direct_funcs,  | 
|---|
 | 2412 | +	.flags		= FTRACE_OPS_FL_IPMODIFY | FTRACE_OPS_FL_RECURSION_SAFE  | 
|---|
 | 2413 | +			  | FTRACE_OPS_FL_DIRECT | FTRACE_OPS_FL_SAVE_REGS  | 
|---|
 | 2414 | +			  | FTRACE_OPS_FL_PERMANENT,  | 
|---|
 | 2415 | +	/*  | 
|---|
 | 2416 | +	 * By declaring the main trampoline as this trampoline  | 
|---|
 | 2417 | +	 * it will never have one allocated for it. Allocated  | 
|---|
 | 2418 | +	 * trampolines should not call direct functions.  | 
|---|
 | 2419 | +	 * The direct_ops should only be called by the builtin  | 
|---|
 | 2420 | +	 * ftrace_regs_caller trampoline.  | 
|---|
 | 2421 | +	 */  | 
|---|
 | 2422 | +	.trampoline	= FTRACE_REGS_ADDR,  | 
|---|
 | 2423 | +};  | 
|---|
 | 2424 | +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */  | 
|---|
 | 2425 | +  | 
|---|
| 2348 | 2426 |  /** | 
|---|
| 2349 | 2427 |   * ftrace_get_addr_new - Get the call address to set to | 
|---|
| 2350 | 2428 |   * @rec:  The ftrace record descriptor | 
|---|
| 2351 | 2429 |   * | 
|---|
| 2352 | 2430 |   * If the record has the FTRACE_FL_REGS set, that means that it | 
|---|
| 2353 | 2431 |   * wants to convert to a callback that saves all regs. If FTRACE_FL_REGS | 
|---|
| 2354 |  | - * is not not set, then it wants to convert to the normal callback.  | 
|---|
 | 2432 | + * is not set, then it wants to convert to the normal callback.  | 
|---|
| 2355 | 2433 |   * | 
|---|
| 2356 | 2434 |   * Returns the address of the trampoline to set to | 
|---|
| 2357 | 2435 |   */ | 
|---|
| 2358 | 2436 |  unsigned long ftrace_get_addr_new(struct dyn_ftrace *rec) | 
|---|
| 2359 | 2437 |  { | 
|---|
| 2360 | 2438 |  	struct ftrace_ops *ops; | 
|---|
 | 2439 | +	unsigned long addr;  | 
|---|
 | 2440 | +  | 
|---|
 | 2441 | +	if ((rec->flags & FTRACE_FL_DIRECT) &&  | 
|---|
 | 2442 | +	    (ftrace_rec_count(rec) == 1)) {  | 
|---|
 | 2443 | +		addr = ftrace_find_rec_direct(rec->ip);  | 
|---|
 | 2444 | +		if (addr)  | 
|---|
 | 2445 | +			return addr;  | 
|---|
 | 2446 | +		WARN_ON_ONCE(1);  | 
|---|
 | 2447 | +	}  | 
|---|
| 2361 | 2448 |   | 
|---|
| 2362 | 2449 |  	/* Trampolines take precedence over regs */ | 
|---|
| 2363 | 2450 |  	if (rec->flags & FTRACE_FL_TRAMP) { | 
|---|
| .. | .. | 
|---|
| 2390 | 2477 |  unsigned long ftrace_get_addr_curr(struct dyn_ftrace *rec) | 
|---|
| 2391 | 2478 |  { | 
|---|
| 2392 | 2479 |  	struct ftrace_ops *ops; | 
|---|
 | 2480 | +	unsigned long addr;  | 
|---|
 | 2481 | +  | 
|---|
 | 2482 | +	/* Direct calls take precedence over trampolines */  | 
|---|
 | 2483 | +	if (rec->flags & FTRACE_FL_DIRECT_EN) {  | 
|---|
 | 2484 | +		addr = ftrace_find_rec_direct(rec->ip);  | 
|---|
 | 2485 | +		if (addr)  | 
|---|
 | 2486 | +			return addr;  | 
|---|
 | 2487 | +		WARN_ON_ONCE(1);  | 
|---|
 | 2488 | +	}  | 
|---|
| 2393 | 2489 |   | 
|---|
| 2394 | 2490 |  	/* Trampolines take precedence over regs */ | 
|---|
| 2395 | 2491 |  	if (rec->flags & FTRACE_FL_TRAMP_EN) { | 
|---|
| .. | .. | 
|---|
| 2410 | 2506 |  } | 
|---|
| 2411 | 2507 |   | 
|---|
| 2412 | 2508 |  static int | 
|---|
| 2413 |  | -__ftrace_replace_code(struct dyn_ftrace *rec, int enable)  | 
|---|
 | 2509 | +__ftrace_replace_code(struct dyn_ftrace *rec, bool enable)  | 
|---|
| 2414 | 2510 |  { | 
|---|
| 2415 | 2511 |  	unsigned long ftrace_old_addr; | 
|---|
| 2416 | 2512 |  	unsigned long ftrace_addr; | 
|---|
| .. | .. | 
|---|
| 2442 | 2538 |  		return ftrace_modify_call(rec, ftrace_old_addr, ftrace_addr); | 
|---|
| 2443 | 2539 |  	} | 
|---|
| 2444 | 2540 |   | 
|---|
| 2445 |  | -	return -1; /* unknow ftrace bug */  | 
|---|
 | 2541 | +	return -1; /* unknown ftrace bug */  | 
|---|
| 2446 | 2542 |  } | 
|---|
| 2447 | 2543 |   | 
|---|
| 2448 |  | -void __weak ftrace_replace_code(int enable)  | 
|---|
 | 2544 | +void __weak ftrace_replace_code(int mod_flags)  | 
|---|
| 2449 | 2545 |  { | 
|---|
| 2450 | 2546 |  	struct dyn_ftrace *rec; | 
|---|
| 2451 | 2547 |  	struct ftrace_page *pg; | 
|---|
 | 2548 | +	bool enable = mod_flags & FTRACE_MODIFY_ENABLE_FL;  | 
|---|
 | 2549 | +	int schedulable = mod_flags & FTRACE_MODIFY_MAY_SLEEP_FL;  | 
|---|
| 2452 | 2550 |  	int failed; | 
|---|
| 2453 | 2551 |   | 
|---|
| 2454 | 2552 |  	if (unlikely(ftrace_disabled)) | 
|---|
| .. | .. | 
|---|
| 2465 | 2563 |  			/* Stop processing */ | 
|---|
| 2466 | 2564 |  			return; | 
|---|
| 2467 | 2565 |  		} | 
|---|
 | 2566 | +		if (schedulable)  | 
|---|
 | 2567 | +			cond_resched();  | 
|---|
| 2468 | 2568 |  	} while_for_each_ftrace_rec(); | 
|---|
| 2469 | 2569 |  } | 
|---|
| 2470 | 2570 |   | 
|---|
| .. | .. | 
|---|
| 2541 | 2641 |  } | 
|---|
| 2542 | 2642 |   | 
|---|
| 2543 | 2643 |  static int | 
|---|
| 2544 |  | -ftrace_code_disable(struct module *mod, struct dyn_ftrace *rec)  | 
|---|
 | 2644 | +ftrace_nop_initialize(struct module *mod, struct dyn_ftrace *rec)  | 
|---|
| 2545 | 2645 |  { | 
|---|
| 2546 | 2646 |  	int ret; | 
|---|
| 2547 | 2647 |   | 
|---|
| 2548 | 2648 |  	if (unlikely(ftrace_disabled)) | 
|---|
| 2549 | 2649 |  		return 0; | 
|---|
| 2550 | 2650 |   | 
|---|
| 2551 |  | -	ret = ftrace_make_nop(mod, rec, MCOUNT_ADDR);  | 
|---|
 | 2651 | +	ret = ftrace_init_nop(mod, rec);  | 
|---|
| 2552 | 2652 |  	if (ret) { | 
|---|
| 2553 | 2653 |  		ftrace_bug_type = FTRACE_BUG_INIT; | 
|---|
| 2554 | 2654 |  		ftrace_bug(ret, rec); | 
|---|
| .. | .. | 
|---|
| 2578 | 2678 |  void ftrace_modify_all_code(int command) | 
|---|
| 2579 | 2679 |  { | 
|---|
| 2580 | 2680 |  	int update = command & FTRACE_UPDATE_TRACE_FUNC; | 
|---|
 | 2681 | +	int mod_flags = 0;  | 
|---|
| 2581 | 2682 |  	int err = 0; | 
|---|
 | 2683 | +  | 
|---|
 | 2684 | +	if (command & FTRACE_MAY_SLEEP)  | 
|---|
 | 2685 | +		mod_flags = FTRACE_MODIFY_MAY_SLEEP_FL;  | 
|---|
| 2582 | 2686 |   | 
|---|
| 2583 | 2687 |  	/* | 
|---|
| 2584 | 2688 |  	 * If the ftrace_caller calls a ftrace_ops func directly, | 
|---|
| .. | .. | 
|---|
| 2597 | 2701 |  	} | 
|---|
| 2598 | 2702 |   | 
|---|
| 2599 | 2703 |  	if (command & FTRACE_UPDATE_CALLS) | 
|---|
| 2600 |  | -		ftrace_replace_code(1);  | 
|---|
 | 2704 | +		ftrace_replace_code(mod_flags | FTRACE_MODIFY_ENABLE_FL);  | 
|---|
| 2601 | 2705 |  	else if (command & FTRACE_DISABLE_CALLS) | 
|---|
| 2602 |  | -		ftrace_replace_code(0);  | 
|---|
 | 2706 | +		ftrace_replace_code(mod_flags);  | 
|---|
| 2603 | 2707 |   | 
|---|
| 2604 | 2708 |  	if (update && ftrace_trace_function != ftrace_ops_list_func) { | 
|---|
| 2605 | 2709 |  		function_trace_op = set_function_trace_op; | 
|---|
| .. | .. | 
|---|
| 2692 | 2796 |  { | 
|---|
| 2693 | 2797 |  } | 
|---|
| 2694 | 2798 |   | 
|---|
 | 2799 | +/* List of trace_ops that have allocated trampolines */  | 
|---|
 | 2800 | +static LIST_HEAD(ftrace_ops_trampoline_list);  | 
|---|
 | 2801 | +  | 
|---|
 | 2802 | +static void ftrace_add_trampoline_to_kallsyms(struct ftrace_ops *ops)  | 
|---|
 | 2803 | +{  | 
|---|
 | 2804 | +	lockdep_assert_held(&ftrace_lock);  | 
|---|
 | 2805 | +	list_add_rcu(&ops->list, &ftrace_ops_trampoline_list);  | 
|---|
 | 2806 | +}  | 
|---|
 | 2807 | +  | 
|---|
 | 2808 | +static void ftrace_remove_trampoline_from_kallsyms(struct ftrace_ops *ops)  | 
|---|
 | 2809 | +{  | 
|---|
 | 2810 | +	lockdep_assert_held(&ftrace_lock);  | 
|---|
 | 2811 | +	list_del_rcu(&ops->list);  | 
|---|
 | 2812 | +	synchronize_rcu();  | 
|---|
 | 2813 | +}  | 
|---|
 | 2814 | +  | 
|---|
 | 2815 | +/*  | 
|---|
 | 2816 | + * "__builtin__ftrace" is used as a module name in /proc/kallsyms for symbols  | 
|---|
 | 2817 | + * for pages allocated for ftrace purposes, even though "__builtin__ftrace" is  | 
|---|
 | 2818 | + * not a module.  | 
|---|
 | 2819 | + */  | 
|---|
 | 2820 | +#define FTRACE_TRAMPOLINE_MOD "__builtin__ftrace"  | 
|---|
 | 2821 | +#define FTRACE_TRAMPOLINE_SYM "ftrace_trampoline"  | 
|---|
 | 2822 | +  | 
|---|
 | 2823 | +static void ftrace_trampoline_free(struct ftrace_ops *ops)  | 
|---|
 | 2824 | +{  | 
|---|
 | 2825 | +	if (ops && (ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP) &&  | 
|---|
 | 2826 | +	    ops->trampoline) {  | 
|---|
 | 2827 | +		/*  | 
|---|
 | 2828 | +		 * Record the text poke event before the ksymbol unregister  | 
|---|
 | 2829 | +		 * event.  | 
|---|
 | 2830 | +		 */  | 
|---|
 | 2831 | +		perf_event_text_poke((void *)ops->trampoline,  | 
|---|
 | 2832 | +				     (void *)ops->trampoline,  | 
|---|
 | 2833 | +				     ops->trampoline_size, NULL, 0);  | 
|---|
 | 2834 | +		perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_OOL,  | 
|---|
 | 2835 | +				   ops->trampoline, ops->trampoline_size,  | 
|---|
 | 2836 | +				   true, FTRACE_TRAMPOLINE_SYM);  | 
|---|
 | 2837 | +		/* Remove from kallsyms after the perf events */  | 
|---|
 | 2838 | +		ftrace_remove_trampoline_from_kallsyms(ops);  | 
|---|
 | 2839 | +	}  | 
|---|
 | 2840 | +  | 
|---|
 | 2841 | +	arch_ftrace_trampoline_free(ops);  | 
|---|
 | 2842 | +}  | 
|---|
 | 2843 | +  | 
|---|
| 2695 | 2844 |  static void ftrace_startup_enable(int command) | 
|---|
| 2696 | 2845 |  { | 
|---|
| 2697 | 2846 |  	if (saved_ftrace_func != ftrace_trace_function) { | 
|---|
| .. | .. | 
|---|
| 2712 | 2861 |  	update_all_ops = false; | 
|---|
| 2713 | 2862 |  } | 
|---|
| 2714 | 2863 |   | 
|---|
| 2715 |  | -static int ftrace_startup(struct ftrace_ops *ops, int command)  | 
|---|
 | 2864 | +int ftrace_startup(struct ftrace_ops *ops, int command)  | 
|---|
| 2716 | 2865 |  { | 
|---|
| 2717 | 2866 |  	int ret; | 
|---|
| 2718 | 2867 |   | 
|---|
| .. | .. | 
|---|
| 2741 | 2890 |  		__unregister_ftrace_function(ops); | 
|---|
| 2742 | 2891 |  		ftrace_start_up--; | 
|---|
| 2743 | 2892 |  		ops->flags &= ~FTRACE_OPS_FL_ENABLED; | 
|---|
 | 2893 | +		if (ops->flags & FTRACE_OPS_FL_DYNAMIC)  | 
|---|
 | 2894 | +			ftrace_trampoline_free(ops);  | 
|---|
| 2744 | 2895 |  		return ret; | 
|---|
| 2745 | 2896 |  	} | 
|---|
| 2746 | 2897 |   | 
|---|
| .. | .. | 
|---|
| 2749 | 2900 |   | 
|---|
| 2750 | 2901 |  	ftrace_startup_enable(command); | 
|---|
| 2751 | 2902 |   | 
|---|
 | 2903 | +	/*  | 
|---|
 | 2904 | +	 * If ftrace is in an undefined state, we just remove ops from list  | 
|---|
 | 2905 | +	 * to prevent the NULL pointer, instead of totally rolling it back and  | 
|---|
 | 2906 | +	 * free trampoline, because those actions could cause further damage.  | 
|---|
 | 2907 | +	 */  | 
|---|
 | 2908 | +	if (unlikely(ftrace_disabled)) {  | 
|---|
 | 2909 | +		__unregister_ftrace_function(ops);  | 
|---|
 | 2910 | +		return -ENODEV;  | 
|---|
 | 2911 | +	}  | 
|---|
 | 2912 | +  | 
|---|
| 2752 | 2913 |  	ops->flags &= ~FTRACE_OPS_FL_ADDING; | 
|---|
| 2753 | 2914 |   | 
|---|
| 2754 | 2915 |  	return 0; | 
|---|
| 2755 | 2916 |  } | 
|---|
| 2756 | 2917 |   | 
|---|
| 2757 |  | -static int ftrace_shutdown(struct ftrace_ops *ops, int command)  | 
|---|
 | 2918 | +int ftrace_shutdown(struct ftrace_ops *ops, int command)  | 
|---|
| 2758 | 2919 |  { | 
|---|
| 2759 | 2920 |  	int ret; | 
|---|
| 2760 | 2921 |   | 
|---|
| .. | .. | 
|---|
| 2786 | 2947 |  		command |= FTRACE_UPDATE_TRACE_FUNC; | 
|---|
| 2787 | 2948 |  	} | 
|---|
| 2788 | 2949 |   | 
|---|
| 2789 |  | -	if (!command || !ftrace_enabled) {  | 
|---|
| 2790 |  | -		/*  | 
|---|
| 2791 |  | -		 * If these are dynamic or per_cpu ops, they still  | 
|---|
| 2792 |  | -		 * need their data freed. Since, function tracing is  | 
|---|
| 2793 |  | -		 * not currently active, we can just free them  | 
|---|
| 2794 |  | -		 * without synchronizing all CPUs.  | 
|---|
| 2795 |  | -		 */  | 
|---|
| 2796 |  | -		if (ops->flags & FTRACE_OPS_FL_DYNAMIC)  | 
|---|
| 2797 |  | -			goto free_ops;  | 
|---|
| 2798 |  | -  | 
|---|
| 2799 |  | -		return 0;  | 
|---|
| 2800 |  | -	}  | 
|---|
 | 2950 | +	if (!command || !ftrace_enabled)  | 
|---|
 | 2951 | +		goto out;  | 
|---|
| 2801 | 2952 |   | 
|---|
| 2802 | 2953 |  	/* | 
|---|
| 2803 | 2954 |  	 * If the ops uses a trampoline, then it needs to be | 
|---|
| .. | .. | 
|---|
| 2834 | 2985 |  	removed_ops = NULL; | 
|---|
| 2835 | 2986 |  	ops->flags &= ~FTRACE_OPS_FL_REMOVING; | 
|---|
| 2836 | 2987 |   | 
|---|
 | 2988 | +out:  | 
|---|
| 2837 | 2989 |  	/* | 
|---|
| 2838 | 2990 |  	 * Dynamic ops may be freed, we must make sure that all | 
|---|
| 2839 | 2991 |  	 * callers are done before leaving this function. | 
|---|
| .. | .. | 
|---|
| 2849 | 3001 |  		 * infrastructure to do the synchronization, thus we must do it | 
|---|
| 2850 | 3002 |  		 * ourselves. | 
|---|
| 2851 | 3003 |  		 */ | 
|---|
| 2852 |  | -		schedule_on_each_cpu(ftrace_sync);  | 
|---|
 | 3004 | +		synchronize_rcu_tasks_rude();  | 
|---|
| 2853 | 3005 |   | 
|---|
| 2854 | 3006 |  		/* | 
|---|
| 2855 |  | -		 * When the kernel is preeptive, tasks can be preempted  | 
|---|
 | 3007 | +		 * When the kernel is preemptive, tasks can be preempted  | 
|---|
| 2856 | 3008 |  		 * while on a ftrace trampoline. Just scheduling a task on | 
|---|
| 2857 | 3009 |  		 * a CPU is not good enough to flush them. Calling | 
|---|
| 2858 | 3010 |  		 * synchornize_rcu_tasks() will wait for those tasks to | 
|---|
| 2859 | 3011 |  		 * execute and either schedule voluntarily or enter user space. | 
|---|
| 2860 | 3012 |  		 */ | 
|---|
| 2861 |  | -		if (IS_ENABLED(CONFIG_PREEMPT))  | 
|---|
 | 3013 | +		if (IS_ENABLED(CONFIG_PREEMPTION))  | 
|---|
| 2862 | 3014 |  			synchronize_rcu_tasks(); | 
|---|
| 2863 | 3015 |   | 
|---|
| 2864 |  | - free_ops:  | 
|---|
| 2865 |  | -		arch_ftrace_trampoline_free(ops);  | 
|---|
 | 3016 | +		ftrace_trampoline_free(ops);  | 
|---|
| 2866 | 3017 |  	} | 
|---|
| 2867 | 3018 |   | 
|---|
| 2868 | 3019 |  	return 0; | 
|---|
| .. | .. | 
|---|
| 2904 | 3055 |   | 
|---|
| 2905 | 3056 |  static u64		ftrace_update_time; | 
|---|
| 2906 | 3057 |  unsigned long		ftrace_update_tot_cnt; | 
|---|
 | 3058 | +unsigned long		ftrace_number_of_pages;  | 
|---|
 | 3059 | +unsigned long		ftrace_number_of_groups;  | 
|---|
| 2907 | 3060 |   | 
|---|
| 2908 | 3061 |  static inline int ops_traces_mod(struct ftrace_ops *ops) | 
|---|
| 2909 | 3062 |  { | 
|---|
| .. | .. | 
|---|
| 2986 | 3139 |  			 * to the NOP instructions. | 
|---|
| 2987 | 3140 |  			 */ | 
|---|
| 2988 | 3141 |  			if (!__is_defined(CC_USING_NOP_MCOUNT) && | 
|---|
| 2989 |  | -			    !ftrace_code_disable(mod, p))  | 
|---|
 | 3142 | +			    !ftrace_nop_initialize(mod, p))  | 
|---|
| 2990 | 3143 |  				break; | 
|---|
| 2991 | 3144 |   | 
|---|
| 2992 | 3145 |  			update_cnt++; | 
|---|
| .. | .. | 
|---|
| 3003 | 3156 |  static int ftrace_allocate_records(struct ftrace_page *pg, int count) | 
|---|
| 3004 | 3157 |  { | 
|---|
| 3005 | 3158 |  	int order; | 
|---|
 | 3159 | +	int pages;  | 
|---|
| 3006 | 3160 |  	int cnt; | 
|---|
| 3007 | 3161 |   | 
|---|
| 3008 | 3162 |  	if (WARN_ON(!count)) | 
|---|
| 3009 | 3163 |  		return -EINVAL; | 
|---|
| 3010 | 3164 |   | 
|---|
| 3011 |  | -	order = get_count_order(DIV_ROUND_UP(count, ENTRIES_PER_PAGE));  | 
|---|
 | 3165 | +	pages = DIV_ROUND_UP(count, ENTRIES_PER_PAGE);  | 
|---|
 | 3166 | +	order = get_count_order(pages);  | 
|---|
| 3012 | 3167 |   | 
|---|
| 3013 | 3168 |  	/* | 
|---|
| 3014 | 3169 |  	 * We want to fill as much as possible. No more than a page | 
|---|
| 3015 | 3170 |  	 * may be empty. | 
|---|
| 3016 | 3171 |  	 */ | 
|---|
| 3017 |  | -	while ((PAGE_SIZE << order) / ENTRY_SIZE >= count + ENTRIES_PER_PAGE)  | 
|---|
 | 3172 | +	if (!is_power_of_2(pages))  | 
|---|
| 3018 | 3173 |  		order--; | 
|---|
| 3019 | 3174 |   | 
|---|
| 3020 | 3175 |   again: | 
|---|
| .. | .. | 
|---|
| 3024 | 3179 |  		/* if we can't allocate this size, try something smaller */ | 
|---|
| 3025 | 3180 |  		if (!order) | 
|---|
| 3026 | 3181 |  			return -ENOMEM; | 
|---|
| 3027 |  | -		order >>= 1;  | 
|---|
 | 3182 | +		order--;  | 
|---|
| 3028 | 3183 |  		goto again; | 
|---|
| 3029 | 3184 |  	} | 
|---|
 | 3185 | +  | 
|---|
 | 3186 | +	ftrace_number_of_pages += 1 << order;  | 
|---|
 | 3187 | +	ftrace_number_of_groups++;  | 
|---|
| 3030 | 3188 |   | 
|---|
| 3031 | 3189 |  	cnt = (PAGE_SIZE << order) / ENTRY_SIZE; | 
|---|
| 3032 | 3190 |  	pg->size = cnt; | 
|---|
| .. | .. | 
|---|
| 3046 | 3204 |  	int cnt; | 
|---|
| 3047 | 3205 |   | 
|---|
| 3048 | 3206 |  	if (!num_to_init) | 
|---|
| 3049 |  | -		return 0;  | 
|---|
 | 3207 | +		return NULL;  | 
|---|
| 3050 | 3208 |   | 
|---|
| 3051 | 3209 |  	start_pg = pg = kzalloc(sizeof(*pg), GFP_KERNEL); | 
|---|
| 3052 | 3210 |  	if (!pg) | 
|---|
| .. | .. | 
|---|
| 3079 | 3237 |  	pg = start_pg; | 
|---|
| 3080 | 3238 |  	while (pg) { | 
|---|
| 3081 | 3239 |  		order = get_count_order(pg->size / ENTRIES_PER_PAGE); | 
|---|
| 3082 |  | -		free_pages((unsigned long)pg->records, order);  | 
|---|
 | 3240 | +		if (order >= 0)  | 
|---|
 | 3241 | +			free_pages((unsigned long)pg->records, order);  | 
|---|
| 3083 | 3242 |  		start_pg = pg->next; | 
|---|
| 3084 | 3243 |  		kfree(pg); | 
|---|
| 3085 | 3244 |  		pg = start_pg; | 
|---|
 | 3245 | +		ftrace_number_of_pages -= 1 << order;  | 
|---|
 | 3246 | +		ftrace_number_of_groups--;  | 
|---|
| 3086 | 3247 |  	} | 
|---|
| 3087 | 3248 |  	pr_info("ftrace: FAILED to allocate memory for functions\n"); | 
|---|
| 3088 | 3249 |  	return NULL; | 
|---|
| .. | .. | 
|---|
| 3493 | 3654 |  	if (iter->flags & FTRACE_ITER_ENABLED) { | 
|---|
| 3494 | 3655 |  		struct ftrace_ops *ops; | 
|---|
| 3495 | 3656 |   | 
|---|
| 3496 |  | -		seq_printf(m, " (%ld)%s%s",  | 
|---|
 | 3657 | +		seq_printf(m, " (%ld)%s%s%s",  | 
|---|
| 3497 | 3658 |  			   ftrace_rec_count(rec), | 
|---|
| 3498 | 3659 |  			   rec->flags & FTRACE_FL_REGS ? " R" : "  ", | 
|---|
| 3499 |  | -			   rec->flags & FTRACE_FL_IPMODIFY ? " I" : "  ");  | 
|---|
 | 3660 | +			   rec->flags & FTRACE_FL_IPMODIFY ? " I" : "  ",  | 
|---|
 | 3661 | +			   rec->flags & FTRACE_FL_DIRECT ? " D" : "  ");  | 
|---|
| 3500 | 3662 |  		if (rec->flags & FTRACE_FL_TRAMP_EN) { | 
|---|
| 3501 | 3663 |  			ops = ftrace_find_tramp_ops_any(rec); | 
|---|
| 3502 | 3664 |  			if (ops) { | 
|---|
| .. | .. | 
|---|
| 3512 | 3674 |  		} else { | 
|---|
| 3513 | 3675 |  			add_trampoline_func(m, NULL, rec); | 
|---|
| 3514 | 3676 |  		} | 
|---|
| 3515 |  | -	}	  | 
|---|
 | 3677 | +		if (rec->flags & FTRACE_FL_DIRECT) {  | 
|---|
 | 3678 | +			unsigned long direct;  | 
|---|
 | 3679 | +  | 
|---|
 | 3680 | +			direct = ftrace_find_rec_direct(rec->ip);  | 
|---|
 | 3681 | +			if (direct)  | 
|---|
 | 3682 | +				seq_printf(m, "\n\tdirect-->%pS", (void *)direct);  | 
|---|
 | 3683 | +		}  | 
|---|
 | 3684 | +	}  | 
|---|
| 3516 | 3685 |   | 
|---|
| 3517 | 3686 |  	seq_putc(m, '\n'); | 
|---|
| 3518 | 3687 |   | 
|---|
| .. | .. | 
|---|
| 3530 | 3699 |  ftrace_avail_open(struct inode *inode, struct file *file) | 
|---|
| 3531 | 3700 |  { | 
|---|
| 3532 | 3701 |  	struct ftrace_iterator *iter; | 
|---|
 | 3702 | +	int ret;  | 
|---|
 | 3703 | +  | 
|---|
 | 3704 | +	ret = security_locked_down(LOCKDOWN_TRACEFS);  | 
|---|
 | 3705 | +	if (ret)  | 
|---|
 | 3706 | +		return ret;  | 
|---|
| 3533 | 3707 |   | 
|---|
| 3534 | 3708 |  	if (unlikely(ftrace_disabled)) | 
|---|
| 3535 | 3709 |  		return -ENODEV; | 
|---|
| .. | .. | 
|---|
| 3548 | 3722 |  ftrace_enabled_open(struct inode *inode, struct file *file) | 
|---|
| 3549 | 3723 |  { | 
|---|
| 3550 | 3724 |  	struct ftrace_iterator *iter; | 
|---|
 | 3725 | +  | 
|---|
 | 3726 | +	/*  | 
|---|
 | 3727 | +	 * This shows us what functions are currently being  | 
|---|
 | 3728 | +	 * traced and by what. Not sure if we want lockdown  | 
|---|
 | 3729 | +	 * to hide such critical information for an admin.  | 
|---|
 | 3730 | +	 * Although, perhaps it can show information we don't  | 
|---|
 | 3731 | +	 * want people to see, but if something is tracing  | 
|---|
 | 3732 | +	 * something, we probably want to know about it.  | 
|---|
 | 3733 | +	 */  | 
|---|
| 3551 | 3734 |   | 
|---|
| 3552 | 3735 |  	iter = __seq_open_private(file, &show_ftrace_seq_ops, sizeof(*iter)); | 
|---|
| 3553 | 3736 |  	if (!iter) | 
|---|
| .. | .. | 
|---|
| 3591 | 3774 |  	if (unlikely(ftrace_disabled)) | 
|---|
| 3592 | 3775 |  		return -ENODEV; | 
|---|
| 3593 | 3776 |   | 
|---|
| 3594 |  | -	if (tr && trace_array_get(tr) < 0)  | 
|---|
 | 3777 | +	if (tracing_check_open_get_tr(tr))  | 
|---|
| 3595 | 3778 |  		return -ENODEV; | 
|---|
| 3596 | 3779 |   | 
|---|
| 3597 | 3780 |  	iter = kzalloc(sizeof(*iter), GFP_KERNEL); | 
|---|
| .. | .. | 
|---|
| 3669 | 3852 |  { | 
|---|
| 3670 | 3853 |  	struct ftrace_ops *ops = inode->i_private; | 
|---|
| 3671 | 3854 |   | 
|---|
 | 3855 | +	/* Checks for tracefs lockdown */  | 
|---|
| 3672 | 3856 |  	return ftrace_regex_open(ops, | 
|---|
| 3673 | 3857 |  			FTRACE_ITER_FILTER | FTRACE_ITER_DO_PROBES, | 
|---|
| 3674 | 3858 |  			inode, file); | 
|---|
| .. | .. | 
|---|
| 3679 | 3863 |  { | 
|---|
| 3680 | 3864 |  	struct ftrace_ops *ops = inode->i_private; | 
|---|
| 3681 | 3865 |   | 
|---|
 | 3866 | +	/* Checks for tracefs lockdown */  | 
|---|
| 3682 | 3867 |  	return ftrace_regex_open(ops, FTRACE_ITER_NOTRACE, | 
|---|
| 3683 | 3868 |  				 inode, file); | 
|---|
| 3684 | 3869 |  } | 
|---|
| .. | .. | 
|---|
| 3759 | 3944 |  } | 
|---|
| 3760 | 3945 |   | 
|---|
| 3761 | 3946 |  static int | 
|---|
 | 3947 | +add_rec_by_index(struct ftrace_hash *hash, struct ftrace_glob *func_g,  | 
|---|
 | 3948 | +		 int clear_filter)  | 
|---|
 | 3949 | +{  | 
|---|
 | 3950 | +	long index = simple_strtoul(func_g->search, NULL, 0);  | 
|---|
 | 3951 | +	struct ftrace_page *pg;  | 
|---|
 | 3952 | +	struct dyn_ftrace *rec;  | 
|---|
 | 3953 | +  | 
|---|
 | 3954 | +	/* The index starts at 1 */  | 
|---|
 | 3955 | +	if (--index < 0)  | 
|---|
 | 3956 | +		return 0;  | 
|---|
 | 3957 | +  | 
|---|
 | 3958 | +	do_for_each_ftrace_rec(pg, rec) {  | 
|---|
 | 3959 | +		if (pg->index <= index) {  | 
|---|
 | 3960 | +			index -= pg->index;  | 
|---|
 | 3961 | +			/* this is a double loop, break goes to the next page */  | 
|---|
 | 3962 | +			break;  | 
|---|
 | 3963 | +		}  | 
|---|
 | 3964 | +		rec = &pg->records[index];  | 
|---|
 | 3965 | +		enter_record(hash, rec, clear_filter);  | 
|---|
 | 3966 | +		return 1;  | 
|---|
 | 3967 | +	} while_for_each_ftrace_rec();  | 
|---|
 | 3968 | +	return 0;  | 
|---|
 | 3969 | +}  | 
|---|
 | 3970 | +  | 
|---|
 | 3971 | +static int  | 
|---|
| 3762 | 3972 |  ftrace_match_record(struct dyn_ftrace *rec, struct ftrace_glob *func_g, | 
|---|
| 3763 | 3973 |  		struct ftrace_glob *mod_g, int exclude_mod) | 
|---|
| 3764 | 3974 |  { | 
|---|
| .. | .. | 
|---|
| 3825 | 4035 |   | 
|---|
| 3826 | 4036 |  	if (unlikely(ftrace_disabled)) | 
|---|
| 3827 | 4037 |  		goto out_unlock; | 
|---|
 | 4038 | +  | 
|---|
 | 4039 | +	if (func_g.type == MATCH_INDEX) {  | 
|---|
 | 4040 | +		found = add_rec_by_index(hash, &func_g, clear_filter);  | 
|---|
 | 4041 | +		goto out_unlock;  | 
|---|
 | 4042 | +	}  | 
|---|
| 3828 | 4043 |   | 
|---|
| 3829 | 4044 |  	do_for_each_ftrace_rec(pg, rec) { | 
|---|
| 3830 | 4045 |   | 
|---|
| .. | .. | 
|---|
| 3906 | 4121 |  static bool module_exists(const char *module) | 
|---|
| 3907 | 4122 |  { | 
|---|
| 3908 | 4123 |  	/* All modules have the symbol __this_module */ | 
|---|
| 3909 |  | -	const char this_mod[] = "__this_module";  | 
|---|
 | 4124 | +	static const char this_mod[] = "__this_module";  | 
|---|
| 3910 | 4125 |  	char modname[MAX_PARAM_PREFIX_LEN + sizeof(this_mod) + 2]; | 
|---|
| 3911 | 4126 |  	unsigned long val; | 
|---|
| 3912 | 4127 |  	int n; | 
|---|
| .. | .. | 
|---|
| 4183 | 4398 |   * @ip: The instruction pointer address to map @data to | 
|---|
| 4184 | 4399 |   * @data: The data to map to @ip | 
|---|
| 4185 | 4400 |   * | 
|---|
| 4186 |  | - * Returns 0 on succes otherwise an error.  | 
|---|
 | 4401 | + * Returns 0 on success otherwise an error.  | 
|---|
| 4187 | 4402 |   */ | 
|---|
| 4188 | 4403 |  int ftrace_func_mapper_add_ip(struct ftrace_func_mapper *mapper, | 
|---|
| 4189 | 4404 |  			      unsigned long ip, void *data) | 
|---|
| .. | .. | 
|---|
| 4213 | 4428 |   * @ip: The instruction pointer address to remove the data from | 
|---|
| 4214 | 4429 |   * | 
|---|
| 4215 | 4430 |   * Returns the data if it is found, otherwise NULL. | 
|---|
| 4216 |  | - * Note, if the data pointer is used as the data itself, (see   | 
|---|
 | 4431 | + * Note, if the data pointer is used as the data itself, (see  | 
|---|
| 4217 | 4432 |   * ftrace_func_mapper_find_ip(), then the return value may be meaningless, | 
|---|
| 4218 | 4433 |   * if the data pointer was set to zero. | 
|---|
| 4219 | 4434 |   */ | 
|---|
| .. | .. | 
|---|
| 4351 | 4566 |   | 
|---|
| 4352 | 4567 |  	/* | 
|---|
| 4353 | 4568 |  	 * Note, there's a small window here that the func_hash->filter_hash | 
|---|
| 4354 |  | -	 * may be NULL or empty. Need to be carefule when reading the loop.  | 
|---|
 | 4569 | +	 * may be NULL or empty. Need to be careful when reading the loop.  | 
|---|
| 4355 | 4570 |  	 */ | 
|---|
| 4356 | 4571 |  	mutex_lock(&probe->ops.func_hash->regex_lock); | 
|---|
| 4357 | 4572 |   | 
|---|
| .. | .. | 
|---|
| 4552 | 4767 |  	if (ftrace_enabled && !ftrace_hash_empty(hash)) | 
|---|
| 4553 | 4768 |  		ftrace_run_modify_code(&probe->ops, FTRACE_UPDATE_CALLS, | 
|---|
| 4554 | 4769 |  				       &old_hash_ops); | 
|---|
| 4555 |  | -	synchronize_sched();  | 
|---|
 | 4770 | +	synchronize_rcu();  | 
|---|
| 4556 | 4771 |   | 
|---|
| 4557 | 4772 |  	hlist_for_each_entry_safe(entry, tmp, &hhd, hlist) { | 
|---|
| 4558 | 4773 |  		hlist_del(&entry->hlist); | 
|---|
| .. | .. | 
|---|
| 4794 | 5009 |  ftrace_set_addr(struct ftrace_ops *ops, unsigned long ip, int remove, | 
|---|
| 4795 | 5010 |  		int reset, int enable) | 
|---|
| 4796 | 5011 |  { | 
|---|
| 4797 |  | -	return ftrace_set_hash(ops, 0, 0, ip, remove, reset, enable);  | 
|---|
 | 5012 | +	return ftrace_set_hash(ops, NULL, 0, ip, remove, reset, enable);  | 
|---|
| 4798 | 5013 |  } | 
|---|
 | 5014 | +  | 
|---|
 | 5015 | +#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS  | 
|---|
 | 5016 | +  | 
|---|
 | 5017 | +struct ftrace_direct_func {  | 
|---|
 | 5018 | +	struct list_head	next;  | 
|---|
 | 5019 | +	unsigned long		addr;  | 
|---|
 | 5020 | +	int			count;  | 
|---|
 | 5021 | +};  | 
|---|
 | 5022 | +  | 
|---|
 | 5023 | +static LIST_HEAD(ftrace_direct_funcs);  | 
|---|
 | 5024 | +  | 
|---|
 | 5025 | +/**  | 
|---|
 | 5026 | + * ftrace_find_direct_func - test an address if it is a registered direct caller  | 
|---|
 | 5027 | + * @addr: The address of a registered direct caller  | 
|---|
 | 5028 | + *  | 
|---|
 | 5029 | + * This searches to see if a ftrace direct caller has been registered  | 
|---|
 | 5030 | + * at a specific address, and if so, it returns a descriptor for it.  | 
|---|
 | 5031 | + *  | 
|---|
 | 5032 | + * This can be used by architecture code to see if an address is  | 
|---|
 | 5033 | + * a direct caller (trampoline) attached to a fentry/mcount location.  | 
|---|
 | 5034 | + * This is useful for the function_graph tracer, as it may need to  | 
|---|
 | 5035 | + * do adjustments if it traced a location that also has a direct  | 
|---|
 | 5036 | + * trampoline attached to it.  | 
|---|
 | 5037 | + */  | 
|---|
 | 5038 | +struct ftrace_direct_func *ftrace_find_direct_func(unsigned long addr)  | 
|---|
 | 5039 | +{  | 
|---|
 | 5040 | +	struct ftrace_direct_func *entry;  | 
|---|
 | 5041 | +	bool found = false;  | 
|---|
 | 5042 | +  | 
|---|
 | 5043 | +	/* May be called by fgraph trampoline (protected by rcu tasks) */  | 
|---|
 | 5044 | +	list_for_each_entry_rcu(entry, &ftrace_direct_funcs, next) {  | 
|---|
 | 5045 | +		if (entry->addr == addr) {  | 
|---|
 | 5046 | +			found = true;  | 
|---|
 | 5047 | +			break;  | 
|---|
 | 5048 | +		}  | 
|---|
 | 5049 | +	}  | 
|---|
 | 5050 | +	if (found)  | 
|---|
 | 5051 | +		return entry;  | 
|---|
 | 5052 | +  | 
|---|
 | 5053 | +	return NULL;  | 
|---|
 | 5054 | +}  | 
|---|
 | 5055 | +  | 
|---|
 | 5056 | +static struct ftrace_direct_func *ftrace_alloc_direct_func(unsigned long addr)  | 
|---|
 | 5057 | +{  | 
|---|
 | 5058 | +	struct ftrace_direct_func *direct;  | 
|---|
 | 5059 | +  | 
|---|
 | 5060 | +	direct = kmalloc(sizeof(*direct), GFP_KERNEL);  | 
|---|
 | 5061 | +	if (!direct)  | 
|---|
 | 5062 | +		return NULL;  | 
|---|
 | 5063 | +	direct->addr = addr;  | 
|---|
 | 5064 | +	direct->count = 0;  | 
|---|
 | 5065 | +	list_add_rcu(&direct->next, &ftrace_direct_funcs);  | 
|---|
 | 5066 | +	ftrace_direct_func_count++;  | 
|---|
 | 5067 | +	return direct;  | 
|---|
 | 5068 | +}  | 
|---|
 | 5069 | +  | 
|---|
 | 5070 | +/**  | 
|---|
 | 5071 | + * register_ftrace_direct - Call a custom trampoline directly  | 
|---|
 | 5072 | + * @ip: The address of the nop at the beginning of a function  | 
|---|
 | 5073 | + * @addr: The address of the trampoline to call at @ip  | 
|---|
 | 5074 | + *  | 
|---|
 | 5075 | + * This is used to connect a direct call from the nop location (@ip)  | 
|---|
 | 5076 | + * at the start of ftrace traced functions. The location that it calls  | 
|---|
 | 5077 | + * (@addr) must be able to handle a direct call, and save the parameters  | 
|---|
 | 5078 | + * of the function being traced, and restore them (or inject new ones  | 
|---|
 | 5079 | + * if needed), before returning.  | 
|---|
 | 5080 | + *  | 
|---|
 | 5081 | + * Returns:  | 
|---|
 | 5082 | + *  0 on success  | 
|---|
 | 5083 | + *  -EBUSY - Another direct function is already attached (there can be only one)  | 
|---|
 | 5084 | + *  -ENODEV - @ip does not point to a ftrace nop location (or not supported)  | 
|---|
 | 5085 | + *  -ENOMEM - There was an allocation failure.  | 
|---|
 | 5086 | + */  | 
|---|
 | 5087 | +int register_ftrace_direct(unsigned long ip, unsigned long addr)  | 
|---|
 | 5088 | +{  | 
|---|
 | 5089 | +	struct ftrace_direct_func *direct;  | 
|---|
 | 5090 | +	struct ftrace_func_entry *entry;  | 
|---|
 | 5091 | +	struct ftrace_hash *free_hash = NULL;  | 
|---|
 | 5092 | +	struct dyn_ftrace *rec;  | 
|---|
 | 5093 | +	int ret = -EBUSY;  | 
|---|
 | 5094 | +  | 
|---|
 | 5095 | +	mutex_lock(&direct_mutex);  | 
|---|
 | 5096 | +  | 
|---|
 | 5097 | +	/* See if there's a direct function at @ip already */  | 
|---|
 | 5098 | +	if (ftrace_find_rec_direct(ip))  | 
|---|
 | 5099 | +		goto out_unlock;  | 
|---|
 | 5100 | +  | 
|---|
 | 5101 | +	ret = -ENODEV;  | 
|---|
 | 5102 | +	rec = lookup_rec(ip, ip);  | 
|---|
 | 5103 | +	if (!rec)  | 
|---|
 | 5104 | +		goto out_unlock;  | 
|---|
 | 5105 | +  | 
|---|
 | 5106 | +	/*  | 
|---|
 | 5107 | +	 * Check if the rec says it has a direct call but we didn't  | 
|---|
 | 5108 | +	 * find one earlier?  | 
|---|
 | 5109 | +	 */  | 
|---|
 | 5110 | +	if (WARN_ON(rec->flags & FTRACE_FL_DIRECT))  | 
|---|
 | 5111 | +		goto out_unlock;  | 
|---|
 | 5112 | +  | 
|---|
 | 5113 | +	/* Make sure the ip points to the exact record */  | 
|---|
 | 5114 | +	if (ip != rec->ip) {  | 
|---|
 | 5115 | +		ip = rec->ip;  | 
|---|
 | 5116 | +		/* Need to check this ip for a direct. */  | 
|---|
 | 5117 | +		if (ftrace_find_rec_direct(ip))  | 
|---|
 | 5118 | +			goto out_unlock;  | 
|---|
 | 5119 | +	}  | 
|---|
 | 5120 | +  | 
|---|
 | 5121 | +	ret = -ENOMEM;  | 
|---|
 | 5122 | +	if (ftrace_hash_empty(direct_functions) ||  | 
|---|
 | 5123 | +	    direct_functions->count > 2 * (1 << direct_functions->size_bits)) {  | 
|---|
 | 5124 | +		struct ftrace_hash *new_hash;  | 
|---|
 | 5125 | +		int size = ftrace_hash_empty(direct_functions) ? 0 :  | 
|---|
 | 5126 | +			direct_functions->count + 1;  | 
|---|
 | 5127 | +  | 
|---|
 | 5128 | +		if (size < 32)  | 
|---|
 | 5129 | +			size = 32;  | 
|---|
 | 5130 | +  | 
|---|
 | 5131 | +		new_hash = dup_hash(direct_functions, size);  | 
|---|
 | 5132 | +		if (!new_hash)  | 
|---|
 | 5133 | +			goto out_unlock;  | 
|---|
 | 5134 | +  | 
|---|
 | 5135 | +		free_hash = direct_functions;  | 
|---|
 | 5136 | +		direct_functions = new_hash;  | 
|---|
 | 5137 | +	}  | 
|---|
 | 5138 | +  | 
|---|
 | 5139 | +	entry = kmalloc(sizeof(*entry), GFP_KERNEL);  | 
|---|
 | 5140 | +	if (!entry)  | 
|---|
 | 5141 | +		goto out_unlock;  | 
|---|
 | 5142 | +  | 
|---|
 | 5143 | +	direct = ftrace_find_direct_func(addr);  | 
|---|
 | 5144 | +	if (!direct) {  | 
|---|
 | 5145 | +		direct = ftrace_alloc_direct_func(addr);  | 
|---|
 | 5146 | +		if (!direct) {  | 
|---|
 | 5147 | +			kfree(entry);  | 
|---|
 | 5148 | +			goto out_unlock;  | 
|---|
 | 5149 | +		}  | 
|---|
 | 5150 | +	}  | 
|---|
 | 5151 | +  | 
|---|
 | 5152 | +	entry->ip = ip;  | 
|---|
 | 5153 | +	entry->direct = addr;  | 
|---|
 | 5154 | +	__add_hash_entry(direct_functions, entry);  | 
|---|
 | 5155 | +  | 
|---|
 | 5156 | +	ret = ftrace_set_filter_ip(&direct_ops, ip, 0, 0);  | 
|---|
 | 5157 | +  | 
|---|
 | 5158 | +	if (!ret && !(direct_ops.flags & FTRACE_OPS_FL_ENABLED)) {  | 
|---|
 | 5159 | +		ret = register_ftrace_function(&direct_ops);  | 
|---|
 | 5160 | +		if (ret)  | 
|---|
 | 5161 | +			ftrace_set_filter_ip(&direct_ops, ip, 1, 0);  | 
|---|
 | 5162 | +	}  | 
|---|
 | 5163 | +  | 
|---|
 | 5164 | +	if (ret) {  | 
|---|
 | 5165 | +		remove_hash_entry(direct_functions, entry);  | 
|---|
 | 5166 | +		kfree(entry);  | 
|---|
 | 5167 | +		if (!direct->count) {  | 
|---|
 | 5168 | +			list_del_rcu(&direct->next);  | 
|---|
 | 5169 | +			synchronize_rcu_tasks();  | 
|---|
 | 5170 | +			kfree(direct);  | 
|---|
 | 5171 | +			if (free_hash)  | 
|---|
 | 5172 | +				free_ftrace_hash(free_hash);  | 
|---|
 | 5173 | +			free_hash = NULL;  | 
|---|
 | 5174 | +			ftrace_direct_func_count--;  | 
|---|
 | 5175 | +		}  | 
|---|
 | 5176 | +	} else {  | 
|---|
 | 5177 | +		direct->count++;  | 
|---|
 | 5178 | +	}  | 
|---|
 | 5179 | + out_unlock:  | 
|---|
 | 5180 | +	mutex_unlock(&direct_mutex);  | 
|---|
 | 5181 | +  | 
|---|
 | 5182 | +	if (free_hash) {  | 
|---|
 | 5183 | +		synchronize_rcu_tasks();  | 
|---|
 | 5184 | +		free_ftrace_hash(free_hash);  | 
|---|
 | 5185 | +	}  | 
|---|
 | 5186 | +  | 
|---|
 | 5187 | +	return ret;  | 
|---|
 | 5188 | +}  | 
|---|
 | 5189 | +EXPORT_SYMBOL_GPL(register_ftrace_direct);  | 
|---|
 | 5190 | +  | 
|---|
 | 5191 | +static struct ftrace_func_entry *find_direct_entry(unsigned long *ip,  | 
|---|
 | 5192 | +						   struct dyn_ftrace **recp)  | 
|---|
 | 5193 | +{  | 
|---|
 | 5194 | +	struct ftrace_func_entry *entry;  | 
|---|
 | 5195 | +	struct dyn_ftrace *rec;  | 
|---|
 | 5196 | +  | 
|---|
 | 5197 | +	rec = lookup_rec(*ip, *ip);  | 
|---|
 | 5198 | +	if (!rec)  | 
|---|
 | 5199 | +		return NULL;  | 
|---|
 | 5200 | +  | 
|---|
 | 5201 | +	entry = __ftrace_lookup_ip(direct_functions, rec->ip);  | 
|---|
 | 5202 | +	if (!entry) {  | 
|---|
 | 5203 | +		WARN_ON(rec->flags & FTRACE_FL_DIRECT);  | 
|---|
 | 5204 | +		return NULL;  | 
|---|
 | 5205 | +	}  | 
|---|
 | 5206 | +  | 
|---|
 | 5207 | +	WARN_ON(!(rec->flags & FTRACE_FL_DIRECT));  | 
|---|
 | 5208 | +  | 
|---|
 | 5209 | +	/* Passed in ip just needs to be on the call site */  | 
|---|
 | 5210 | +	*ip = rec->ip;  | 
|---|
 | 5211 | +  | 
|---|
 | 5212 | +	if (recp)  | 
|---|
 | 5213 | +		*recp = rec;  | 
|---|
 | 5214 | +  | 
|---|
 | 5215 | +	return entry;  | 
|---|
 | 5216 | +}  | 
|---|
 | 5217 | +  | 
|---|
 | 5218 | +int unregister_ftrace_direct(unsigned long ip, unsigned long addr)  | 
|---|
 | 5219 | +{  | 
|---|
 | 5220 | +	struct ftrace_direct_func *direct;  | 
|---|
 | 5221 | +	struct ftrace_func_entry *entry;  | 
|---|
 | 5222 | +	int ret = -ENODEV;  | 
|---|
 | 5223 | +  | 
|---|
 | 5224 | +	mutex_lock(&direct_mutex);  | 
|---|
 | 5225 | +  | 
|---|
 | 5226 | +	entry = find_direct_entry(&ip, NULL);  | 
|---|
 | 5227 | +	if (!entry)  | 
|---|
 | 5228 | +		goto out_unlock;  | 
|---|
 | 5229 | +  | 
|---|
 | 5230 | +	if (direct_functions->count == 1)  | 
|---|
 | 5231 | +		unregister_ftrace_function(&direct_ops);  | 
|---|
 | 5232 | +  | 
|---|
 | 5233 | +	ret = ftrace_set_filter_ip(&direct_ops, ip, 1, 0);  | 
|---|
 | 5234 | +  | 
|---|
 | 5235 | +	WARN_ON(ret);  | 
|---|
 | 5236 | +  | 
|---|
 | 5237 | +	remove_hash_entry(direct_functions, entry);  | 
|---|
 | 5238 | +  | 
|---|
 | 5239 | +	direct = ftrace_find_direct_func(addr);  | 
|---|
 | 5240 | +	if (!WARN_ON(!direct)) {  | 
|---|
 | 5241 | +		/* This is the good path (see the ! before WARN) */  | 
|---|
 | 5242 | +		direct->count--;  | 
|---|
 | 5243 | +		WARN_ON(direct->count < 0);  | 
|---|
 | 5244 | +		if (!direct->count) {  | 
|---|
 | 5245 | +			list_del_rcu(&direct->next);  | 
|---|
 | 5246 | +			synchronize_rcu_tasks();  | 
|---|
 | 5247 | +			kfree(direct);  | 
|---|
 | 5248 | +			kfree(entry);  | 
|---|
 | 5249 | +			ftrace_direct_func_count--;  | 
|---|
 | 5250 | +		}  | 
|---|
 | 5251 | +	}  | 
|---|
 | 5252 | + out_unlock:  | 
|---|
 | 5253 | +	mutex_unlock(&direct_mutex);  | 
|---|
 | 5254 | +  | 
|---|
 | 5255 | +	return ret;  | 
|---|
 | 5256 | +}  | 
|---|
 | 5257 | +EXPORT_SYMBOL_GPL(unregister_ftrace_direct);  | 
|---|
 | 5258 | +  | 
|---|
 | 5259 | +static struct ftrace_ops stub_ops = {  | 
|---|
 | 5260 | +	.func		= ftrace_stub,  | 
|---|
 | 5261 | +};  | 
|---|
 | 5262 | +  | 
|---|
 | 5263 | +/**  | 
|---|
 | 5264 | + * ftrace_modify_direct_caller - modify ftrace nop directly  | 
|---|
 | 5265 | + * @entry: The ftrace hash entry of the direct helper for @rec  | 
|---|
 | 5266 | + * @rec: The record representing the function site to patch  | 
|---|
 | 5267 | + * @old_addr: The location that the site at @rec->ip currently calls  | 
|---|
 | 5268 | + * @new_addr: The location that the site at @rec->ip should call  | 
|---|
 | 5269 | + *  | 
|---|
 | 5270 | + * An architecture may overwrite this function to optimize the  | 
|---|
 | 5271 | + * changing of the direct callback on an ftrace nop location.  | 
|---|
 | 5272 | + * This is called with the ftrace_lock mutex held, and no other  | 
|---|
 | 5273 | + * ftrace callbacks are on the associated record (@rec). Thus,  | 
|---|
 | 5274 | + * it is safe to modify the ftrace record, where it should be  | 
|---|
 | 5275 | + * currently calling @old_addr directly, to call @new_addr.  | 
|---|
 | 5276 | + *  | 
|---|
 | 5277 | + * Safety checks should be made to make sure that the code at  | 
|---|
 | 5278 | + * @rec->ip is currently calling @old_addr. And this must  | 
|---|
 | 5279 | + * also update entry->direct to @new_addr.  | 
|---|
 | 5280 | + */  | 
|---|
 | 5281 | +int __weak ftrace_modify_direct_caller(struct ftrace_func_entry *entry,  | 
|---|
 | 5282 | +				       struct dyn_ftrace *rec,  | 
|---|
 | 5283 | +				       unsigned long old_addr,  | 
|---|
 | 5284 | +				       unsigned long new_addr)  | 
|---|
 | 5285 | +{  | 
|---|
 | 5286 | +	unsigned long ip = rec->ip;  | 
|---|
 | 5287 | +	int ret;  | 
|---|
 | 5288 | +  | 
|---|
 | 5289 | +	/*  | 
|---|
 | 5290 | +	 * The ftrace_lock was used to determine if the record  | 
|---|
 | 5291 | +	 * had more than one registered user to it. If it did,  | 
|---|
 | 5292 | +	 * we needed to prevent that from changing to do the quick  | 
|---|
 | 5293 | +	 * switch. But if it did not (only a direct caller was attached)  | 
|---|
 | 5294 | +	 * then this function is called. But this function can deal  | 
|---|
 | 5295 | +	 * with attached callers to the rec that we care about, and  | 
|---|
 | 5296 | +	 * since this function uses standard ftrace calls that take  | 
|---|
 | 5297 | +	 * the ftrace_lock mutex, we need to release it.  | 
|---|
 | 5298 | +	 */  | 
|---|
 | 5299 | +	mutex_unlock(&ftrace_lock);  | 
|---|
 | 5300 | +  | 
|---|
 | 5301 | +	/*  | 
|---|
 | 5302 | +	 * By setting a stub function at the same address, we force  | 
|---|
 | 5303 | +	 * the code to call the iterator and the direct_ops helper.  | 
|---|
 | 5304 | +	 * This means that @ip does not call the direct call, and  | 
|---|
 | 5305 | +	 * we can simply modify it.  | 
|---|
 | 5306 | +	 */  | 
|---|
 | 5307 | +	ret = ftrace_set_filter_ip(&stub_ops, ip, 0, 0);  | 
|---|
 | 5308 | +	if (ret)  | 
|---|
 | 5309 | +		goto out_lock;  | 
|---|
 | 5310 | +  | 
|---|
 | 5311 | +	ret = register_ftrace_function(&stub_ops);  | 
|---|
 | 5312 | +	if (ret) {  | 
|---|
 | 5313 | +		ftrace_set_filter_ip(&stub_ops, ip, 1, 0);  | 
|---|
 | 5314 | +		goto out_lock;  | 
|---|
 | 5315 | +	}  | 
|---|
 | 5316 | +  | 
|---|
 | 5317 | +	entry->direct = new_addr;  | 
|---|
 | 5318 | +  | 
|---|
 | 5319 | +	/*  | 
|---|
 | 5320 | +	 * By removing the stub, we put back the direct call, calling  | 
|---|
 | 5321 | +	 * the @new_addr.  | 
|---|
 | 5322 | +	 */  | 
|---|
 | 5323 | +	unregister_ftrace_function(&stub_ops);  | 
|---|
 | 5324 | +	ftrace_set_filter_ip(&stub_ops, ip, 1, 0);  | 
|---|
 | 5325 | +  | 
|---|
 | 5326 | + out_lock:  | 
|---|
 | 5327 | +	mutex_lock(&ftrace_lock);  | 
|---|
 | 5328 | +  | 
|---|
 | 5329 | +	return ret;  | 
|---|
 | 5330 | +}  | 
|---|
 | 5331 | +  | 
|---|
 | 5332 | +/**  | 
|---|
 | 5333 | + * modify_ftrace_direct - Modify an existing direct call to call something else  | 
|---|
 | 5334 | + * @ip: The instruction pointer to modify  | 
|---|
 | 5335 | + * @old_addr: The address that the current @ip calls directly  | 
|---|
 | 5336 | + * @new_addr: The address that the @ip should call  | 
|---|
 | 5337 | + *  | 
|---|
 | 5338 | + * This modifies a ftrace direct caller at an instruction pointer without  | 
|---|
 | 5339 | + * having to disable it first. The direct call will switch over to the  | 
|---|
 | 5340 | + * @new_addr without missing anything.  | 
|---|
 | 5341 | + *  | 
|---|
 | 5342 | + * Returns: zero on success. Non zero on error, which includes:  | 
|---|
 | 5343 | + *  -ENODEV : the @ip given has no direct caller attached  | 
|---|
 | 5344 | + *  -EINVAL : the @old_addr does not match the current direct caller  | 
|---|
 | 5345 | + */  | 
|---|
 | 5346 | +int modify_ftrace_direct(unsigned long ip,  | 
|---|
 | 5347 | +			 unsigned long old_addr, unsigned long new_addr)  | 
|---|
 | 5348 | +{  | 
|---|
 | 5349 | +	struct ftrace_direct_func *direct, *new_direct = NULL;  | 
|---|
 | 5350 | +	struct ftrace_func_entry *entry;  | 
|---|
 | 5351 | +	struct dyn_ftrace *rec;  | 
|---|
 | 5352 | +	int ret = -ENODEV;  | 
|---|
 | 5353 | +  | 
|---|
 | 5354 | +	mutex_lock(&direct_mutex);  | 
|---|
 | 5355 | +  | 
|---|
 | 5356 | +	mutex_lock(&ftrace_lock);  | 
|---|
 | 5357 | +	entry = find_direct_entry(&ip, &rec);  | 
|---|
 | 5358 | +	if (!entry)  | 
|---|
 | 5359 | +		goto out_unlock;  | 
|---|
 | 5360 | +  | 
|---|
 | 5361 | +	ret = -EINVAL;  | 
|---|
 | 5362 | +	if (entry->direct != old_addr)  | 
|---|
 | 5363 | +		goto out_unlock;  | 
|---|
 | 5364 | +  | 
|---|
 | 5365 | +	direct = ftrace_find_direct_func(old_addr);  | 
|---|
 | 5366 | +	if (WARN_ON(!direct))  | 
|---|
 | 5367 | +		goto out_unlock;  | 
|---|
 | 5368 | +	if (direct->count > 1) {  | 
|---|
 | 5369 | +		ret = -ENOMEM;  | 
|---|
 | 5370 | +		new_direct = ftrace_alloc_direct_func(new_addr);  | 
|---|
 | 5371 | +		if (!new_direct)  | 
|---|
 | 5372 | +			goto out_unlock;  | 
|---|
 | 5373 | +		direct->count--;  | 
|---|
 | 5374 | +		new_direct->count++;  | 
|---|
 | 5375 | +	} else {  | 
|---|
 | 5376 | +		direct->addr = new_addr;  | 
|---|
 | 5377 | +	}  | 
|---|
 | 5378 | +  | 
|---|
 | 5379 | +	/*  | 
|---|
 | 5380 | +	 * If there's no other ftrace callback on the rec->ip location,  | 
|---|
 | 5381 | +	 * then it can be changed directly by the architecture.  | 
|---|
 | 5382 | +	 * If there is another caller, then we just need to change the  | 
|---|
 | 5383 | +	 * direct caller helper to point to @new_addr.  | 
|---|
 | 5384 | +	 */  | 
|---|
 | 5385 | +	if (ftrace_rec_count(rec) == 1) {  | 
|---|
 | 5386 | +		ret = ftrace_modify_direct_caller(entry, rec, old_addr, new_addr);  | 
|---|
 | 5387 | +	} else {  | 
|---|
 | 5388 | +		entry->direct = new_addr;  | 
|---|
 | 5389 | +		ret = 0;  | 
|---|
 | 5390 | +	}  | 
|---|
 | 5391 | +  | 
|---|
 | 5392 | +	if (unlikely(ret && new_direct)) {  | 
|---|
 | 5393 | +		direct->count++;  | 
|---|
 | 5394 | +		list_del_rcu(&new_direct->next);  | 
|---|
 | 5395 | +		synchronize_rcu_tasks();  | 
|---|
 | 5396 | +		kfree(new_direct);  | 
|---|
 | 5397 | +		ftrace_direct_func_count--;  | 
|---|
 | 5398 | +	}  | 
|---|
 | 5399 | +  | 
|---|
 | 5400 | + out_unlock:  | 
|---|
 | 5401 | +	mutex_unlock(&ftrace_lock);  | 
|---|
 | 5402 | +	mutex_unlock(&direct_mutex);  | 
|---|
 | 5403 | +	return ret;  | 
|---|
 | 5404 | +}  | 
|---|
 | 5405 | +EXPORT_SYMBOL_GPL(modify_ftrace_direct);  | 
|---|
 | 5406 | +#endif /* CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS */  | 
|---|
| 4799 | 5407 |   | 
|---|
| 4800 | 5408 |  /** | 
|---|
| 4801 | 5409 |   * ftrace_set_filter_ip - set a function to filter on in ftrace by address | 
|---|
| .. | .. | 
|---|
| 4967 | 5575 |  	struct ftrace_hash *hash; | 
|---|
| 4968 | 5576 |   | 
|---|
| 4969 | 5577 |  	hash = alloc_ftrace_hash(FTRACE_HASH_DEFAULT_BITS); | 
|---|
| 4970 |  | -	if (WARN_ON(!hash))  | 
|---|
 | 5578 | +	if (MEM_FAIL(!hash, "Failed to allocate hash\n"))  | 
|---|
| 4971 | 5579 |  		return; | 
|---|
| 4972 | 5580 |   | 
|---|
| 4973 | 5581 |  	while (buf) { | 
|---|
| .. | .. | 
|---|
| 5045 | 5653 |   | 
|---|
| 5046 | 5654 |  		if (filter_hash) { | 
|---|
| 5047 | 5655 |  			orig_hash = &iter->ops->func_hash->filter_hash; | 
|---|
| 5048 |  | -			if (iter->tr && !list_empty(&iter->tr->mod_trace))  | 
|---|
| 5049 |  | -				iter->hash->flags |= FTRACE_HASH_FL_MOD;  | 
|---|
 | 5656 | +			if (iter->tr) {  | 
|---|
 | 5657 | +				if (list_empty(&iter->tr->mod_trace))  | 
|---|
 | 5658 | +					iter->hash->flags &= ~FTRACE_HASH_FL_MOD;  | 
|---|
 | 5659 | +				else  | 
|---|
 | 5660 | +					iter->hash->flags |= FTRACE_HASH_FL_MOD;  | 
|---|
 | 5661 | +			}  | 
|---|
| 5050 | 5662 |  		} else | 
|---|
| 5051 | 5663 |  			orig_hash = &iter->ops->func_hash->notrace_hash; | 
|---|
| 5052 | 5664 |   | 
|---|
| .. | .. | 
|---|
| 5220 | 5832 |  __ftrace_graph_open(struct inode *inode, struct file *file, | 
|---|
| 5221 | 5833 |  		    struct ftrace_graph_data *fgd) | 
|---|
| 5222 | 5834 |  { | 
|---|
| 5223 |  | -	int ret = 0;  | 
|---|
 | 5835 | +	int ret;  | 
|---|
| 5224 | 5836 |  	struct ftrace_hash *new_hash = NULL; | 
|---|
 | 5837 | +  | 
|---|
 | 5838 | +	ret = security_locked_down(LOCKDOWN_TRACEFS);  | 
|---|
 | 5839 | +	if (ret)  | 
|---|
 | 5840 | +		return ret;  | 
|---|
| 5225 | 5841 |   | 
|---|
| 5226 | 5842 |  	if (file->f_mode & FMODE_WRITE) { | 
|---|
| 5227 | 5843 |  		const int size_bits = FTRACE_HASH_DEFAULT_BITS; | 
|---|
| .. | .. | 
|---|
| 5382 | 5998 |  		 * infrastructure to do the synchronization, thus we must do it | 
|---|
| 5383 | 5999 |  		 * ourselves. | 
|---|
| 5384 | 6000 |  		 */ | 
|---|
| 5385 |  | -		schedule_on_each_cpu(ftrace_sync);  | 
|---|
 | 6001 | +		synchronize_rcu_tasks_rude();  | 
|---|
| 5386 | 6002 |   | 
|---|
| 5387 | 6003 |  		free_ftrace_hash(old_hash); | 
|---|
| 5388 | 6004 |  	} | 
|---|
| .. | .. | 
|---|
| 5514 | 6130 |   | 
|---|
| 5515 | 6131 |  /* | 
|---|
| 5516 | 6132 |   * The name "destroy_filter_files" is really a misnomer. Although | 
|---|
| 5517 |  | - * in the future, it may actualy delete the files, but this is  | 
|---|
 | 6133 | + * in the future, it may actually delete the files, but this is  | 
|---|
| 5518 | 6134 |   * really intended to make sure the ops passed in are disabled | 
|---|
| 5519 | 6135 |   * and that when this function returns, the caller is free to | 
|---|
| 5520 | 6136 |   * free the ops. | 
|---|
| .. | .. | 
|---|
| 5567 | 6183 |  	return 0; | 
|---|
| 5568 | 6184 |  } | 
|---|
| 5569 | 6185 |   | 
|---|
| 5570 |  | -static int __norecordmcount ftrace_process_locs(struct module *mod,  | 
|---|
| 5571 |  | -						unsigned long *start,  | 
|---|
| 5572 |  | -						unsigned long *end)  | 
|---|
 | 6186 | +static int ftrace_process_locs(struct module *mod,  | 
|---|
 | 6187 | +			       unsigned long *start,  | 
|---|
 | 6188 | +			       unsigned long *end)  | 
|---|
| 5573 | 6189 |  { | 
|---|
| 5574 | 6190 |  	struct ftrace_page *start_pg; | 
|---|
| 5575 | 6191 |  	struct ftrace_page *pg; | 
|---|
| .. | .. | 
|---|
| 5683 | 6299 |  	unsigned int		num_funcs; | 
|---|
| 5684 | 6300 |  }; | 
|---|
| 5685 | 6301 |   | 
|---|
 | 6302 | +static int ftrace_get_trampoline_kallsym(unsigned int symnum,  | 
|---|
 | 6303 | +					 unsigned long *value, char *type,  | 
|---|
 | 6304 | +					 char *name, char *module_name,  | 
|---|
 | 6305 | +					 int *exported)  | 
|---|
 | 6306 | +{  | 
|---|
 | 6307 | +	struct ftrace_ops *op;  | 
|---|
 | 6308 | +  | 
|---|
 | 6309 | +	list_for_each_entry_rcu(op, &ftrace_ops_trampoline_list, list) {  | 
|---|
 | 6310 | +		if (!op->trampoline || symnum--)  | 
|---|
 | 6311 | +			continue;  | 
|---|
 | 6312 | +		*value = op->trampoline;  | 
|---|
 | 6313 | +		*type = 't';  | 
|---|
 | 6314 | +		strlcpy(name, FTRACE_TRAMPOLINE_SYM, KSYM_NAME_LEN);  | 
|---|
 | 6315 | +		strlcpy(module_name, FTRACE_TRAMPOLINE_MOD, MODULE_NAME_LEN);  | 
|---|
 | 6316 | +		*exported = 0;  | 
|---|
 | 6317 | +		return 0;  | 
|---|
 | 6318 | +	}  | 
|---|
 | 6319 | +  | 
|---|
 | 6320 | +	return -ERANGE;  | 
|---|
 | 6321 | +}  | 
|---|
 | 6322 | +  | 
|---|
| 5686 | 6323 |  #ifdef CONFIG_MODULES | 
|---|
| 5687 | 6324 |   | 
|---|
| 5688 | 6325 |  #define next_to_ftrace_page(p) container_of(p, struct ftrace_page, next) | 
|---|
| .. | .. | 
|---|
| 5696 | 6333 |   | 
|---|
| 5697 | 6334 |  	for (ops = ftrace_ops_list; ops != &ftrace_list_end; ops = ops->next) { | 
|---|
| 5698 | 6335 |  		if (ops_references_rec(ops, rec)) { | 
|---|
 | 6336 | +			if (WARN_ON_ONCE(ops->flags & FTRACE_OPS_FL_DIRECT))  | 
|---|
 | 6337 | +				continue;  | 
|---|
 | 6338 | +			if (WARN_ON_ONCE(ops->flags & FTRACE_OPS_FL_IPMODIFY))  | 
|---|
 | 6339 | +				continue;  | 
|---|
| 5699 | 6340 |  			cnt++; | 
|---|
| 5700 | 6341 |  			if (ops->flags & FTRACE_OPS_FL_SAVE_REGS) | 
|---|
| 5701 | 6342 |  				rec->flags |= FTRACE_FL_REGS; | 
|---|
 | 6343 | +			if (cnt == 1 && ops->trampoline)  | 
|---|
 | 6344 | +				rec->flags |= FTRACE_FL_TRAMP;  | 
|---|
 | 6345 | +			else  | 
|---|
 | 6346 | +				rec->flags &= ~FTRACE_FL_TRAMP;  | 
|---|
| 5702 | 6347 |  		} | 
|---|
| 5703 | 6348 |  	} | 
|---|
| 5704 | 6349 |   | 
|---|
| .. | .. | 
|---|
| 5779 | 6424 |  	list_for_each_entry_safe(mod_map, n, &ftrace_mod_maps, list) { | 
|---|
| 5780 | 6425 |  		if (mod_map->mod == mod) { | 
|---|
| 5781 | 6426 |  			list_del_rcu(&mod_map->list); | 
|---|
| 5782 |  | -			call_rcu_sched(&mod_map->rcu, ftrace_free_mod_map);  | 
|---|
 | 6427 | +			call_rcu(&mod_map->rcu, ftrace_free_mod_map);  | 
|---|
| 5783 | 6428 |  			break; | 
|---|
| 5784 | 6429 |  		} | 
|---|
| 5785 | 6430 |  	} | 
|---|
| .. | .. | 
|---|
| 5821 | 6466 |  		clear_mod_from_hashes(pg); | 
|---|
| 5822 | 6467 |   | 
|---|
| 5823 | 6468 |  		order = get_count_order(pg->size / ENTRIES_PER_PAGE); | 
|---|
| 5824 |  | -		free_pages((unsigned long)pg->records, order);  | 
|---|
 | 6469 | +		if (order >= 0)  | 
|---|
 | 6470 | +			free_pages((unsigned long)pg->records, order);  | 
|---|
| 5825 | 6471 |  		tmp_page = pg->next; | 
|---|
| 5826 | 6472 |  		kfree(pg); | 
|---|
 | 6473 | +		ftrace_number_of_pages -= 1 << order;  | 
|---|
 | 6474 | +		ftrace_number_of_groups--;  | 
|---|
| 5827 | 6475 |  	} | 
|---|
| 5828 | 6476 |  } | 
|---|
| 5829 | 6477 |   | 
|---|
| .. | .. | 
|---|
| 5840 | 6488 |  	/* | 
|---|
| 5841 | 6489 |  	 * If the tracing is enabled, go ahead and enable the record. | 
|---|
| 5842 | 6490 |  	 * | 
|---|
| 5843 |  | -	 * The reason not to enable the record immediatelly is the  | 
|---|
 | 6491 | +	 * The reason not to enable the record immediately is the  | 
|---|
| 5844 | 6492 |  	 * inherent check of ftrace_make_nop/ftrace_make_call for | 
|---|
| 5845 | 6493 |  	 * correct previous instructions.  Making first the NOP | 
|---|
| 5846 | 6494 |  	 * conversion puts the module to the correct state, thus | 
|---|
| .. | .. | 
|---|
| 5999 | 6647 |  	struct ftrace_mod_map *mod_map; | 
|---|
| 6000 | 6648 |  	const char *ret = NULL; | 
|---|
| 6001 | 6649 |   | 
|---|
| 6002 |  | -	/* mod_map is freed via call_rcu_sched() */  | 
|---|
 | 6650 | +	/* mod_map is freed via call_rcu() */  | 
|---|
| 6003 | 6651 |  	preempt_disable(); | 
|---|
| 6004 | 6652 |  	list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) { | 
|---|
| 6005 | 6653 |  		ret = ftrace_func_address_lookup(mod_map, addr, size, off, sym); | 
|---|
| .. | .. | 
|---|
| 6020 | 6668 |  { | 
|---|
| 6021 | 6669 |  	struct ftrace_mod_map *mod_map; | 
|---|
| 6022 | 6670 |  	struct ftrace_mod_func *mod_func; | 
|---|
 | 6671 | +	int ret;  | 
|---|
| 6023 | 6672 |   | 
|---|
| 6024 | 6673 |  	preempt_disable(); | 
|---|
| 6025 | 6674 |  	list_for_each_entry_rcu(mod_map, &ftrace_mod_maps, list) { | 
|---|
| .. | .. | 
|---|
| 6046 | 6695 |  		WARN_ON(1); | 
|---|
| 6047 | 6696 |  		break; | 
|---|
| 6048 | 6697 |  	} | 
|---|
 | 6698 | +	ret = ftrace_get_trampoline_kallsym(symnum, value, type, name,  | 
|---|
 | 6699 | +					    module_name, exported);  | 
|---|
| 6049 | 6700 |  	preempt_enable(); | 
|---|
| 6050 |  | -	return -ERANGE;  | 
|---|
 | 6701 | +	return ret;  | 
|---|
| 6051 | 6702 |  } | 
|---|
| 6052 | 6703 |   | 
|---|
| 6053 | 6704 |  #else | 
|---|
| .. | .. | 
|---|
| 6058 | 6709 |  			unsigned long start, unsigned long end) | 
|---|
| 6059 | 6710 |  { | 
|---|
| 6060 | 6711 |  	return NULL; | 
|---|
 | 6712 | +}  | 
|---|
 | 6713 | +int ftrace_mod_get_kallsym(unsigned int symnum, unsigned long *value,  | 
|---|
 | 6714 | +			   char *type, char *name, char *module_name,  | 
|---|
 | 6715 | +			   int *exported)  | 
|---|
 | 6716 | +{  | 
|---|
 | 6717 | +	int ret;  | 
|---|
 | 6718 | +  | 
|---|
 | 6719 | +	preempt_disable();  | 
|---|
 | 6720 | +	ret = ftrace_get_trampoline_kallsym(symnum, value, type, name,  | 
|---|
 | 6721 | +					    module_name, exported);  | 
|---|
 | 6722 | +	preempt_enable();  | 
|---|
 | 6723 | +	return ret;  | 
|---|
| 6061 | 6724 |  } | 
|---|
| 6062 | 6725 |  #endif /* CONFIG_MODULES */ | 
|---|
| 6063 | 6726 |   | 
|---|
| .. | .. | 
|---|
| 6072 | 6735 |  { | 
|---|
| 6073 | 6736 |  	struct ftrace_func_entry *entry; | 
|---|
| 6074 | 6737 |   | 
|---|
| 6075 |  | -	if (ftrace_hash_empty(hash))  | 
|---|
| 6076 |  | -		return;  | 
|---|
| 6077 |  | -  | 
|---|
| 6078 |  | -	entry = __ftrace_lookup_ip(hash, func->ip);  | 
|---|
| 6079 |  | -  | 
|---|
 | 6738 | +	entry = ftrace_lookup_ip(hash, func->ip);  | 
|---|
| 6080 | 6739 |  	/* | 
|---|
| 6081 | 6740 |  	 * Do not allow this rec to match again. | 
|---|
| 6082 | 6741 |  	 * Yeah, it may waste some memory, but will be removed | 
|---|
| .. | .. | 
|---|
| 6110 | 6769 |   | 
|---|
| 6111 | 6770 |  	func = kmalloc(sizeof(*func), GFP_KERNEL); | 
|---|
| 6112 | 6771 |  	if (!func) { | 
|---|
| 6113 |  | -		WARN_ONCE(1, "alloc failure, ftrace filter could be stale\n");  | 
|---|
 | 6772 | +		MEM_FAIL(1, "alloc failure, ftrace filter could be stale\n");  | 
|---|
| 6114 | 6773 |  		return; | 
|---|
| 6115 | 6774 |  	} | 
|---|
| 6116 | 6775 |   | 
|---|
| .. | .. | 
|---|
| 6168 | 6827 |  		if (!pg->index) { | 
|---|
| 6169 | 6828 |  			*last_pg = pg->next; | 
|---|
| 6170 | 6829 |  			order = get_count_order(pg->size / ENTRIES_PER_PAGE); | 
|---|
| 6171 |  | -			free_pages((unsigned long)pg->records, order);  | 
|---|
 | 6830 | +			if (order >= 0)  | 
|---|
 | 6831 | +				free_pages((unsigned long)pg->records, order);  | 
|---|
 | 6832 | +			ftrace_number_of_pages -= 1 << order;  | 
|---|
 | 6833 | +			ftrace_number_of_groups--;  | 
|---|
| 6172 | 6834 |  			kfree(pg); | 
|---|
| 6173 | 6835 |  			pg = container_of(last_pg, struct ftrace_page, next); | 
|---|
| 6174 | 6836 |  			if (!(*last_pg)) | 
|---|
| .. | .. | 
|---|
| 6216 | 6878 |  	} | 
|---|
| 6217 | 6879 |   | 
|---|
| 6218 | 6880 |  	pr_info("ftrace: allocating %ld entries in %ld pages\n", | 
|---|
| 6219 |  | -		count, count / ENTRIES_PER_PAGE + 1);  | 
|---|
 | 6881 | +		count, DIV_ROUND_UP(count, ENTRIES_PER_PAGE));  | 
|---|
| 6220 | 6882 |   | 
|---|
| 6221 | 6883 |  	last_ftrace_enabled = ftrace_enabled = 1; | 
|---|
| 6222 | 6884 |   | 
|---|
| 6223 | 6885 |  	ret = ftrace_process_locs(NULL, | 
|---|
| 6224 | 6886 |  				  __start_mcount_loc, | 
|---|
| 6225 | 6887 |  				  __stop_mcount_loc); | 
|---|
 | 6888 | +  | 
|---|
 | 6889 | +	pr_info("ftrace: allocated %ld pages with %ld groups\n",  | 
|---|
 | 6890 | +		ftrace_number_of_pages, ftrace_number_of_groups);  | 
|---|
| 6226 | 6891 |   | 
|---|
| 6227 | 6892 |  	set_ftrace_early_filters(); | 
|---|
| 6228 | 6893 |   | 
|---|
| .. | .. | 
|---|
| 6238 | 6903 |   | 
|---|
| 6239 | 6904 |  static void ftrace_update_trampoline(struct ftrace_ops *ops) | 
|---|
| 6240 | 6905 |  { | 
|---|
 | 6906 | +	unsigned long trampoline = ops->trampoline;  | 
|---|
 | 6907 | +  | 
|---|
| 6241 | 6908 |  	arch_ftrace_update_trampoline(ops); | 
|---|
 | 6909 | +	if (ops->trampoline && ops->trampoline != trampoline &&  | 
|---|
 | 6910 | +	    (ops->flags & FTRACE_OPS_FL_ALLOC_TRAMP)) {  | 
|---|
 | 6911 | +		/* Add to kallsyms before the perf events */  | 
|---|
 | 6912 | +		ftrace_add_trampoline_to_kallsyms(ops);  | 
|---|
 | 6913 | +		perf_event_ksymbol(PERF_RECORD_KSYMBOL_TYPE_OOL,  | 
|---|
 | 6914 | +				   ops->trampoline, ops->trampoline_size, false,  | 
|---|
 | 6915 | +				   FTRACE_TRAMPOLINE_SYM);  | 
|---|
 | 6916 | +		/*  | 
|---|
 | 6917 | +		 * Record the perf text poke event after the ksymbol register  | 
|---|
 | 6918 | +		 * event.  | 
|---|
 | 6919 | +		 */  | 
|---|
 | 6920 | +		perf_event_text_poke((void *)ops->trampoline, NULL, 0,  | 
|---|
 | 6921 | +				     (void *)ops->trampoline,  | 
|---|
 | 6922 | +				     ops->trampoline_size);  | 
|---|
 | 6923 | +	}  | 
|---|
| 6242 | 6924 |  } | 
|---|
| 6243 | 6925 |   | 
|---|
| 6244 | 6926 |  void ftrace_init_trace_array(struct trace_array *tr) | 
|---|
| .. | .. | 
|---|
| 6249 | 6931 |  } | 
|---|
| 6250 | 6932 |  #else | 
|---|
| 6251 | 6933 |   | 
|---|
| 6252 |  | -static struct ftrace_ops global_ops = {  | 
|---|
 | 6934 | +struct ftrace_ops global_ops = {  | 
|---|
| 6253 | 6935 |  	.func			= ftrace_stub, | 
|---|
| 6254 | 6936 |  	.flags			= FTRACE_OPS_FL_RECURSION_SAFE | | 
|---|
| 6255 | 6937 |  				  FTRACE_OPS_FL_INITIALIZED | | 
|---|
| .. | .. | 
|---|
| 6266 | 6948 |  static inline int ftrace_init_dyn_tracefs(struct dentry *d_tracer) { return 0; } | 
|---|
| 6267 | 6949 |  static inline void ftrace_startup_enable(int command) { } | 
|---|
| 6268 | 6950 |  static inline void ftrace_startup_all(int command) { } | 
|---|
| 6269 |  | -/* Keep as macros so we do not need to define the commands */  | 
|---|
| 6270 |  | -# define ftrace_startup(ops, command)					\  | 
|---|
| 6271 |  | -	({								\  | 
|---|
| 6272 |  | -		int ___ret = __register_ftrace_function(ops);		\  | 
|---|
| 6273 |  | -		if (!___ret)						\  | 
|---|
| 6274 |  | -			(ops)->flags |= FTRACE_OPS_FL_ENABLED;		\  | 
|---|
| 6275 |  | -		___ret;							\  | 
|---|
| 6276 |  | -	})  | 
|---|
| 6277 |  | -# define ftrace_shutdown(ops, command)					\  | 
|---|
| 6278 |  | -	({								\  | 
|---|
| 6279 |  | -		int ___ret = __unregister_ftrace_function(ops);		\  | 
|---|
| 6280 |  | -		if (!___ret)						\  | 
|---|
| 6281 |  | -			(ops)->flags &= ~FTRACE_OPS_FL_ENABLED;		\  | 
|---|
| 6282 |  | -		___ret;							\  | 
|---|
| 6283 |  | -	})  | 
|---|
| 6284 | 6951 |   | 
|---|
| 6285 | 6952 |  # define ftrace_startup_sysctl()	do { } while (0) | 
|---|
| 6286 | 6953 |  # define ftrace_shutdown_sysctl()	do { } while (0) | 
|---|
| 6287 |  | -  | 
|---|
| 6288 |  | -static inline int  | 
|---|
| 6289 |  | -ftrace_ops_test(struct ftrace_ops *ops, unsigned long ip, void *regs)  | 
|---|
| 6290 |  | -{  | 
|---|
| 6291 |  | -	return 1;  | 
|---|
| 6292 |  | -}  | 
|---|
| 6293 | 6954 |   | 
|---|
| 6294 | 6955 |  static void ftrace_update_trampoline(struct ftrace_ops *ops) | 
|---|
| 6295 | 6956 |  { | 
|---|
| .. | .. | 
|---|
| 6334 | 6995 |   | 
|---|
| 6335 | 6996 |  	/* | 
|---|
| 6336 | 6997 |  	 * Some of the ops may be dynamically allocated, | 
|---|
| 6337 |  | -	 * they must be freed after a synchronize_sched().  | 
|---|
 | 6998 | +	 * they must be freed after a synchronize_rcu().  | 
|---|
| 6338 | 6999 |  	 */ | 
|---|
| 6339 | 7000 |  	preempt_disable_notrace(); | 
|---|
| 6340 | 7001 |   | 
|---|
| 6341 | 7002 |  	do_for_each_ftrace_op(op, ftrace_ops_list) { | 
|---|
 | 7003 | +		/* Stub functions don't need to be called nor tested */  | 
|---|
 | 7004 | +		if (op->flags & FTRACE_OPS_FL_STUB)  | 
|---|
 | 7005 | +			continue;  | 
|---|
| 6342 | 7006 |  		/* | 
|---|
| 6343 | 7007 |  		 * Check the following for each ops before calling their func: | 
|---|
| 6344 | 7008 |  		 *  if RCU flag is set, then rcu_is_watching() must be true | 
|---|
| .. | .. | 
|---|
| 6383 | 7047 |  } | 
|---|
| 6384 | 7048 |  NOKPROBE_SYMBOL(ftrace_ops_list_func); | 
|---|
| 6385 | 7049 |  #else | 
|---|
| 6386 |  | -static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip,  | 
|---|
| 6387 |  | -			      struct ftrace_ops *op, struct pt_regs *regs)  | 
|---|
 | 7050 | +static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip)  | 
|---|
| 6388 | 7051 |  { | 
|---|
| 6389 | 7052 |  	__ftrace_ops_list_func(ip, parent_ip, NULL, NULL); | 
|---|
| 6390 | 7053 |  } | 
|---|
| .. | .. | 
|---|
| 6445 | 7108 |  { | 
|---|
| 6446 | 7109 |  	struct trace_array *tr = data; | 
|---|
| 6447 | 7110 |  	struct trace_pid_list *pid_list; | 
|---|
 | 7111 | +	struct trace_pid_list *no_pid_list;  | 
|---|
| 6448 | 7112 |   | 
|---|
| 6449 | 7113 |  	pid_list = rcu_dereference_sched(tr->function_pids); | 
|---|
 | 7114 | +	no_pid_list = rcu_dereference_sched(tr->function_no_pids);  | 
|---|
| 6450 | 7115 |   | 
|---|
| 6451 |  | -	this_cpu_write(tr->trace_buffer.data->ftrace_ignore_pid,  | 
|---|
| 6452 |  | -		       trace_ignore_this_task(pid_list, next));  | 
|---|
 | 7116 | +	if (trace_ignore_this_task(pid_list, no_pid_list, next))  | 
|---|
 | 7117 | +		this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid,  | 
|---|
 | 7118 | +			       FTRACE_PID_IGNORE);  | 
|---|
 | 7119 | +	else  | 
|---|
 | 7120 | +		this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid,  | 
|---|
 | 7121 | +			       next->pid);  | 
|---|
| 6453 | 7122 |  } | 
|---|
| 6454 | 7123 |   | 
|---|
| 6455 | 7124 |  static void | 
|---|
| .. | .. | 
|---|
| 6462 | 7131 |   | 
|---|
| 6463 | 7132 |  	pid_list = rcu_dereference_sched(tr->function_pids); | 
|---|
| 6464 | 7133 |  	trace_filter_add_remove_task(pid_list, self, task); | 
|---|
 | 7134 | +  | 
|---|
 | 7135 | +	pid_list = rcu_dereference_sched(tr->function_no_pids);  | 
|---|
 | 7136 | +	trace_filter_add_remove_task(pid_list, self, task);  | 
|---|
| 6465 | 7137 |  } | 
|---|
| 6466 | 7138 |   | 
|---|
| 6467 | 7139 |  static void | 
|---|
| .. | .. | 
|---|
| 6471 | 7143 |  	struct trace_array *tr = data; | 
|---|
| 6472 | 7144 |   | 
|---|
| 6473 | 7145 |  	pid_list = rcu_dereference_sched(tr->function_pids); | 
|---|
 | 7146 | +	trace_filter_add_remove_task(pid_list, NULL, task);  | 
|---|
 | 7147 | +  | 
|---|
 | 7148 | +	pid_list = rcu_dereference_sched(tr->function_no_pids);  | 
|---|
| 6474 | 7149 |  	trace_filter_add_remove_task(pid_list, NULL, task); | 
|---|
| 6475 | 7150 |  } | 
|---|
| 6476 | 7151 |   | 
|---|
| .. | .. | 
|---|
| 6489 | 7164 |  	} | 
|---|
| 6490 | 7165 |  } | 
|---|
| 6491 | 7166 |   | 
|---|
| 6492 |  | -static void clear_ftrace_pids(struct trace_array *tr)  | 
|---|
 | 7167 | +static void clear_ftrace_pids(struct trace_array *tr, int type)  | 
|---|
| 6493 | 7168 |  { | 
|---|
| 6494 | 7169 |  	struct trace_pid_list *pid_list; | 
|---|
 | 7170 | +	struct trace_pid_list *no_pid_list;  | 
|---|
| 6495 | 7171 |  	int cpu; | 
|---|
| 6496 | 7172 |   | 
|---|
| 6497 | 7173 |  	pid_list = rcu_dereference_protected(tr->function_pids, | 
|---|
| 6498 | 7174 |  					     lockdep_is_held(&ftrace_lock)); | 
|---|
| 6499 |  | -	if (!pid_list)  | 
|---|
 | 7175 | +	no_pid_list = rcu_dereference_protected(tr->function_no_pids,  | 
|---|
 | 7176 | +						lockdep_is_held(&ftrace_lock));  | 
|---|
 | 7177 | +  | 
|---|
 | 7178 | +	/* Make sure there's something to do */  | 
|---|
 | 7179 | +	if (!pid_type_enabled(type, pid_list, no_pid_list))  | 
|---|
| 6500 | 7180 |  		return; | 
|---|
| 6501 | 7181 |   | 
|---|
| 6502 |  | -	unregister_trace_sched_switch(ftrace_filter_pid_sched_switch_probe, tr);  | 
|---|
 | 7182 | +	/* See if the pids still need to be checked after this */  | 
|---|
 | 7183 | +	if (!still_need_pid_events(type, pid_list, no_pid_list)) {  | 
|---|
 | 7184 | +		unregister_trace_sched_switch(ftrace_filter_pid_sched_switch_probe, tr);  | 
|---|
 | 7185 | +		for_each_possible_cpu(cpu)  | 
|---|
 | 7186 | +			per_cpu_ptr(tr->array_buffer.data, cpu)->ftrace_ignore_pid = FTRACE_PID_TRACE;  | 
|---|
 | 7187 | +	}  | 
|---|
| 6503 | 7188 |   | 
|---|
| 6504 |  | -	for_each_possible_cpu(cpu)  | 
|---|
| 6505 |  | -		per_cpu_ptr(tr->trace_buffer.data, cpu)->ftrace_ignore_pid = false;  | 
|---|
 | 7189 | +	if (type & TRACE_PIDS)  | 
|---|
 | 7190 | +		rcu_assign_pointer(tr->function_pids, NULL);  | 
|---|
| 6506 | 7191 |   | 
|---|
| 6507 |  | -	rcu_assign_pointer(tr->function_pids, NULL);  | 
|---|
 | 7192 | +	if (type & TRACE_NO_PIDS)  | 
|---|
 | 7193 | +		rcu_assign_pointer(tr->function_no_pids, NULL);  | 
|---|
| 6508 | 7194 |   | 
|---|
| 6509 | 7195 |  	/* Wait till all users are no longer using pid filtering */ | 
|---|
| 6510 |  | -	synchronize_sched();  | 
|---|
 | 7196 | +	synchronize_rcu();  | 
|---|
| 6511 | 7197 |   | 
|---|
| 6512 |  | -	trace_free_pid_list(pid_list);  | 
|---|
 | 7198 | +	if ((type & TRACE_PIDS) && pid_list)  | 
|---|
 | 7199 | +		trace_free_pid_list(pid_list);  | 
|---|
 | 7200 | +  | 
|---|
 | 7201 | +	if ((type & TRACE_NO_PIDS) && no_pid_list)  | 
|---|
 | 7202 | +		trace_free_pid_list(no_pid_list);  | 
|---|
| 6513 | 7203 |  } | 
|---|
| 6514 | 7204 |   | 
|---|
| 6515 | 7205 |  void ftrace_clear_pids(struct trace_array *tr) | 
|---|
| 6516 | 7206 |  { | 
|---|
| 6517 | 7207 |  	mutex_lock(&ftrace_lock); | 
|---|
| 6518 | 7208 |   | 
|---|
| 6519 |  | -	clear_ftrace_pids(tr);  | 
|---|
 | 7209 | +	clear_ftrace_pids(tr, TRACE_PIDS | TRACE_NO_PIDS);  | 
|---|
| 6520 | 7210 |   | 
|---|
| 6521 | 7211 |  	mutex_unlock(&ftrace_lock); | 
|---|
| 6522 | 7212 |  } | 
|---|
| 6523 | 7213 |   | 
|---|
| 6524 |  | -static void ftrace_pid_reset(struct trace_array *tr)  | 
|---|
 | 7214 | +static void ftrace_pid_reset(struct trace_array *tr, int type)  | 
|---|
| 6525 | 7215 |  { | 
|---|
| 6526 | 7216 |  	mutex_lock(&ftrace_lock); | 
|---|
| 6527 |  | -	clear_ftrace_pids(tr);  | 
|---|
 | 7217 | +	clear_ftrace_pids(tr, type);  | 
|---|
| 6528 | 7218 |   | 
|---|
| 6529 | 7219 |  	ftrace_update_pid_func(); | 
|---|
| 6530 | 7220 |  	ftrace_startup_all(0); | 
|---|
| .. | .. | 
|---|
| 6588 | 7278 |  	.show = fpid_show, | 
|---|
| 6589 | 7279 |  }; | 
|---|
| 6590 | 7280 |   | 
|---|
| 6591 |  | -static int  | 
|---|
| 6592 |  | -ftrace_pid_open(struct inode *inode, struct file *file)  | 
|---|
 | 7281 | +static void *fnpid_start(struct seq_file *m, loff_t *pos)  | 
|---|
 | 7282 | +	__acquires(RCU)  | 
|---|
| 6593 | 7283 |  { | 
|---|
 | 7284 | +	struct trace_pid_list *pid_list;  | 
|---|
 | 7285 | +	struct trace_array *tr = m->private;  | 
|---|
 | 7286 | +  | 
|---|
 | 7287 | +	mutex_lock(&ftrace_lock);  | 
|---|
 | 7288 | +	rcu_read_lock_sched();  | 
|---|
 | 7289 | +  | 
|---|
 | 7290 | +	pid_list = rcu_dereference_sched(tr->function_no_pids);  | 
|---|
 | 7291 | +  | 
|---|
 | 7292 | +	if (!pid_list)  | 
|---|
 | 7293 | +		return !(*pos) ? FTRACE_NO_PIDS : NULL;  | 
|---|
 | 7294 | +  | 
|---|
 | 7295 | +	return trace_pid_start(pid_list, pos);  | 
|---|
 | 7296 | +}  | 
|---|
 | 7297 | +  | 
|---|
 | 7298 | +static void *fnpid_next(struct seq_file *m, void *v, loff_t *pos)  | 
|---|
 | 7299 | +{  | 
|---|
 | 7300 | +	struct trace_array *tr = m->private;  | 
|---|
 | 7301 | +	struct trace_pid_list *pid_list = rcu_dereference_sched(tr->function_no_pids);  | 
|---|
 | 7302 | +  | 
|---|
 | 7303 | +	if (v == FTRACE_NO_PIDS) {  | 
|---|
 | 7304 | +		(*pos)++;  | 
|---|
 | 7305 | +		return NULL;  | 
|---|
 | 7306 | +	}  | 
|---|
 | 7307 | +	return trace_pid_next(pid_list, v, pos);  | 
|---|
 | 7308 | +}  | 
|---|
 | 7309 | +  | 
|---|
 | 7310 | +static const struct seq_operations ftrace_no_pid_sops = {  | 
|---|
 | 7311 | +	.start = fnpid_start,  | 
|---|
 | 7312 | +	.next = fnpid_next,  | 
|---|
 | 7313 | +	.stop = fpid_stop,  | 
|---|
 | 7314 | +	.show = fpid_show,  | 
|---|
 | 7315 | +};  | 
|---|
 | 7316 | +  | 
|---|
 | 7317 | +static int pid_open(struct inode *inode, struct file *file, int type)  | 
|---|
 | 7318 | +{  | 
|---|
 | 7319 | +	const struct seq_operations *seq_ops;  | 
|---|
| 6594 | 7320 |  	struct trace_array *tr = inode->i_private; | 
|---|
| 6595 | 7321 |  	struct seq_file *m; | 
|---|
| 6596 | 7322 |  	int ret = 0; | 
|---|
| 6597 | 7323 |   | 
|---|
| 6598 |  | -	if (trace_array_get(tr) < 0)  | 
|---|
| 6599 |  | -		return -ENODEV;  | 
|---|
 | 7324 | +	ret = tracing_check_open_get_tr(tr);  | 
|---|
 | 7325 | +	if (ret)  | 
|---|
 | 7326 | +		return ret;  | 
|---|
| 6600 | 7327 |   | 
|---|
| 6601 | 7328 |  	if ((file->f_mode & FMODE_WRITE) && | 
|---|
| 6602 | 7329 |  	    (file->f_flags & O_TRUNC)) | 
|---|
| 6603 |  | -		ftrace_pid_reset(tr);  | 
|---|
 | 7330 | +		ftrace_pid_reset(tr, type);  | 
|---|
| 6604 | 7331 |   | 
|---|
| 6605 |  | -	ret = seq_open(file, &ftrace_pid_sops);  | 
|---|
 | 7332 | +	switch (type) {  | 
|---|
 | 7333 | +	case TRACE_PIDS:  | 
|---|
 | 7334 | +		seq_ops = &ftrace_pid_sops;  | 
|---|
 | 7335 | +		break;  | 
|---|
 | 7336 | +	case TRACE_NO_PIDS:  | 
|---|
 | 7337 | +		seq_ops = &ftrace_no_pid_sops;  | 
|---|
 | 7338 | +		break;  | 
|---|
 | 7339 | +	default:  | 
|---|
 | 7340 | +		trace_array_put(tr);  | 
|---|
 | 7341 | +		WARN_ON_ONCE(1);  | 
|---|
 | 7342 | +		return -EINVAL;  | 
|---|
 | 7343 | +	}  | 
|---|
 | 7344 | +  | 
|---|
 | 7345 | +	ret = seq_open(file, seq_ops);  | 
|---|
| 6606 | 7346 |  	if (ret < 0) { | 
|---|
| 6607 | 7347 |  		trace_array_put(tr); | 
|---|
| 6608 | 7348 |  	} else { | 
|---|
| .. | .. | 
|---|
| 6614 | 7354 |  	return ret; | 
|---|
| 6615 | 7355 |  } | 
|---|
| 6616 | 7356 |   | 
|---|
 | 7357 | +static int  | 
|---|
 | 7358 | +ftrace_pid_open(struct inode *inode, struct file *file)  | 
|---|
 | 7359 | +{  | 
|---|
 | 7360 | +	return pid_open(inode, file, TRACE_PIDS);  | 
|---|
 | 7361 | +}  | 
|---|
 | 7362 | +  | 
|---|
 | 7363 | +static int  | 
|---|
 | 7364 | +ftrace_no_pid_open(struct inode *inode, struct file *file)  | 
|---|
 | 7365 | +{  | 
|---|
 | 7366 | +	return pid_open(inode, file, TRACE_NO_PIDS);  | 
|---|
 | 7367 | +}  | 
|---|
 | 7368 | +  | 
|---|
| 6617 | 7369 |  static void ignore_task_cpu(void *data) | 
|---|
| 6618 | 7370 |  { | 
|---|
| 6619 | 7371 |  	struct trace_array *tr = data; | 
|---|
| 6620 | 7372 |  	struct trace_pid_list *pid_list; | 
|---|
 | 7373 | +	struct trace_pid_list *no_pid_list;  | 
|---|
| 6621 | 7374 |   | 
|---|
| 6622 | 7375 |  	/* | 
|---|
| 6623 | 7376 |  	 * This function is called by on_each_cpu() while the | 
|---|
| .. | .. | 
|---|
| 6625 | 7378 |  	 */ | 
|---|
| 6626 | 7379 |  	pid_list = rcu_dereference_protected(tr->function_pids, | 
|---|
| 6627 | 7380 |  					     mutex_is_locked(&ftrace_lock)); | 
|---|
 | 7381 | +	no_pid_list = rcu_dereference_protected(tr->function_no_pids,  | 
|---|
 | 7382 | +						mutex_is_locked(&ftrace_lock));  | 
|---|
| 6628 | 7383 |   | 
|---|
| 6629 |  | -	this_cpu_write(tr->trace_buffer.data->ftrace_ignore_pid,  | 
|---|
| 6630 |  | -		       trace_ignore_this_task(pid_list, current));  | 
|---|
 | 7384 | +	if (trace_ignore_this_task(pid_list, no_pid_list, current))  | 
|---|
 | 7385 | +		this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid,  | 
|---|
 | 7386 | +			       FTRACE_PID_IGNORE);  | 
|---|
 | 7387 | +	else  | 
|---|
 | 7388 | +		this_cpu_write(tr->array_buffer.data->ftrace_ignore_pid,  | 
|---|
 | 7389 | +			       current->pid);  | 
|---|
| 6631 | 7390 |  } | 
|---|
| 6632 | 7391 |   | 
|---|
| 6633 | 7392 |  static ssize_t | 
|---|
| 6634 |  | -ftrace_pid_write(struct file *filp, const char __user *ubuf,  | 
|---|
| 6635 |  | -		   size_t cnt, loff_t *ppos)  | 
|---|
 | 7393 | +pid_write(struct file *filp, const char __user *ubuf,  | 
|---|
 | 7394 | +	  size_t cnt, loff_t *ppos, int type)  | 
|---|
| 6636 | 7395 |  { | 
|---|
| 6637 | 7396 |  	struct seq_file *m = filp->private_data; | 
|---|
| 6638 | 7397 |  	struct trace_array *tr = m->private; | 
|---|
| 6639 |  | -	struct trace_pid_list *filtered_pids = NULL;  | 
|---|
 | 7398 | +	struct trace_pid_list *filtered_pids;  | 
|---|
 | 7399 | +	struct trace_pid_list *other_pids;  | 
|---|
| 6640 | 7400 |  	struct trace_pid_list *pid_list; | 
|---|
| 6641 | 7401 |  	ssize_t ret; | 
|---|
| 6642 | 7402 |   | 
|---|
| .. | .. | 
|---|
| 6645 | 7405 |   | 
|---|
| 6646 | 7406 |  	mutex_lock(&ftrace_lock); | 
|---|
| 6647 | 7407 |   | 
|---|
| 6648 |  | -	filtered_pids = rcu_dereference_protected(tr->function_pids,  | 
|---|
 | 7408 | +	switch (type) {  | 
|---|
 | 7409 | +	case TRACE_PIDS:  | 
|---|
 | 7410 | +		filtered_pids = rcu_dereference_protected(tr->function_pids,  | 
|---|
| 6649 | 7411 |  					     lockdep_is_held(&ftrace_lock)); | 
|---|
 | 7412 | +		other_pids = rcu_dereference_protected(tr->function_no_pids,  | 
|---|
 | 7413 | +					     lockdep_is_held(&ftrace_lock));  | 
|---|
 | 7414 | +		break;  | 
|---|
 | 7415 | +	case TRACE_NO_PIDS:  | 
|---|
 | 7416 | +		filtered_pids = rcu_dereference_protected(tr->function_no_pids,  | 
|---|
 | 7417 | +					     lockdep_is_held(&ftrace_lock));  | 
|---|
 | 7418 | +		other_pids = rcu_dereference_protected(tr->function_pids,  | 
|---|
 | 7419 | +					     lockdep_is_held(&ftrace_lock));  | 
|---|
 | 7420 | +		break;  | 
|---|
 | 7421 | +	default:  | 
|---|
 | 7422 | +		ret = -EINVAL;  | 
|---|
 | 7423 | +		WARN_ON_ONCE(1);  | 
|---|
 | 7424 | +		goto out;  | 
|---|
 | 7425 | +	}  | 
|---|
| 6650 | 7426 |   | 
|---|
| 6651 | 7427 |  	ret = trace_pid_write(filtered_pids, &pid_list, ubuf, cnt); | 
|---|
| 6652 | 7428 |  	if (ret < 0) | 
|---|
| 6653 | 7429 |  		goto out; | 
|---|
| 6654 | 7430 |   | 
|---|
| 6655 |  | -	rcu_assign_pointer(tr->function_pids, pid_list);  | 
|---|
 | 7431 | +	switch (type) {  | 
|---|
 | 7432 | +	case TRACE_PIDS:  | 
|---|
 | 7433 | +		rcu_assign_pointer(tr->function_pids, pid_list);  | 
|---|
 | 7434 | +		break;  | 
|---|
 | 7435 | +	case TRACE_NO_PIDS:  | 
|---|
 | 7436 | +		rcu_assign_pointer(tr->function_no_pids, pid_list);  | 
|---|
 | 7437 | +		break;  | 
|---|
 | 7438 | +	}  | 
|---|
 | 7439 | +  | 
|---|
| 6656 | 7440 |   | 
|---|
| 6657 | 7441 |  	if (filtered_pids) { | 
|---|
| 6658 |  | -		synchronize_sched();  | 
|---|
 | 7442 | +		synchronize_rcu();  | 
|---|
| 6659 | 7443 |  		trace_free_pid_list(filtered_pids); | 
|---|
| 6660 |  | -	} else if (pid_list) {  | 
|---|
 | 7444 | +	} else if (pid_list && !other_pids) {  | 
|---|
| 6661 | 7445 |  		/* Register a probe to set whether to ignore the tracing of a task */ | 
|---|
| 6662 | 7446 |  		register_trace_sched_switch(ftrace_filter_pid_sched_switch_probe, tr); | 
|---|
| 6663 | 7447 |  	} | 
|---|
| .. | .. | 
|---|
| 6680 | 7464 |  	return ret; | 
|---|
| 6681 | 7465 |  } | 
|---|
| 6682 | 7466 |   | 
|---|
 | 7467 | +static ssize_t  | 
|---|
 | 7468 | +ftrace_pid_write(struct file *filp, const char __user *ubuf,  | 
|---|
 | 7469 | +		 size_t cnt, loff_t *ppos)  | 
|---|
 | 7470 | +{  | 
|---|
 | 7471 | +	return pid_write(filp, ubuf, cnt, ppos, TRACE_PIDS);  | 
|---|
 | 7472 | +}  | 
|---|
 | 7473 | +  | 
|---|
 | 7474 | +static ssize_t  | 
|---|
 | 7475 | +ftrace_no_pid_write(struct file *filp, const char __user *ubuf,  | 
|---|
 | 7476 | +		    size_t cnt, loff_t *ppos)  | 
|---|
 | 7477 | +{  | 
|---|
 | 7478 | +	return pid_write(filp, ubuf, cnt, ppos, TRACE_NO_PIDS);  | 
|---|
 | 7479 | +}  | 
|---|
 | 7480 | +  | 
|---|
| 6683 | 7481 |  static int | 
|---|
| 6684 | 7482 |  ftrace_pid_release(struct inode *inode, struct file *file) | 
|---|
| 6685 | 7483 |  { | 
|---|
| .. | .. | 
|---|
| 6698 | 7496 |  	.release	= ftrace_pid_release, | 
|---|
| 6699 | 7497 |  }; | 
|---|
| 6700 | 7498 |   | 
|---|
 | 7499 | +static const struct file_operations ftrace_no_pid_fops = {  | 
|---|
 | 7500 | +	.open		= ftrace_no_pid_open,  | 
|---|
 | 7501 | +	.write		= ftrace_no_pid_write,  | 
|---|
 | 7502 | +	.read		= seq_read,  | 
|---|
 | 7503 | +	.llseek		= tracing_lseek,  | 
|---|
 | 7504 | +	.release	= ftrace_pid_release,  | 
|---|
 | 7505 | +};  | 
|---|
 | 7506 | +  | 
|---|
| 6701 | 7507 |  void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer) | 
|---|
| 6702 | 7508 |  { | 
|---|
| 6703 | 7509 |  	trace_create_file("set_ftrace_pid", 0644, d_tracer, | 
|---|
| 6704 | 7510 |  			    tr, &ftrace_pid_fops); | 
|---|
 | 7511 | +	trace_create_file("set_ftrace_notrace_pid", 0644, d_tracer,  | 
|---|
 | 7512 | +			    tr, &ftrace_no_pid_fops);  | 
|---|
| 6705 | 7513 |  } | 
|---|
| 6706 | 7514 |   | 
|---|
| 6707 | 7515 |  void __init ftrace_init_tracefs_toplevel(struct trace_array *tr, | 
|---|
| .. | .. | 
|---|
| 6781 | 7589 |  } | 
|---|
| 6782 | 7590 |  EXPORT_SYMBOL_GPL(unregister_ftrace_function); | 
|---|
| 6783 | 7591 |   | 
|---|
 | 7592 | +static bool is_permanent_ops_registered(void)  | 
|---|
 | 7593 | +{  | 
|---|
 | 7594 | +	struct ftrace_ops *op;  | 
|---|
 | 7595 | +  | 
|---|
 | 7596 | +	do_for_each_ftrace_op(op, ftrace_ops_list) {  | 
|---|
 | 7597 | +		if (op->flags & FTRACE_OPS_FL_PERMANENT)  | 
|---|
 | 7598 | +			return true;  | 
|---|
 | 7599 | +	} while_for_each_ftrace_op(op);  | 
|---|
 | 7600 | +  | 
|---|
 | 7601 | +	return false;  | 
|---|
 | 7602 | +}  | 
|---|
 | 7603 | +  | 
|---|
| 6784 | 7604 |  int | 
|---|
| 6785 | 7605 |  ftrace_enable_sysctl(struct ctl_table *table, int write, | 
|---|
| 6786 |  | -		     void __user *buffer, size_t *lenp,  | 
|---|
| 6787 |  | -		     loff_t *ppos)  | 
|---|
 | 7606 | +		     void *buffer, size_t *lenp, loff_t *ppos)  | 
|---|
| 6788 | 7607 |  { | 
|---|
| 6789 | 7608 |  	int ret = -ENODEV; | 
|---|
| 6790 | 7609 |   | 
|---|
| .. | .. | 
|---|
| 6798 | 7617 |  	if (ret || !write || (last_ftrace_enabled == !!ftrace_enabled)) | 
|---|
| 6799 | 7618 |  		goto out; | 
|---|
| 6800 | 7619 |   | 
|---|
| 6801 |  | -	last_ftrace_enabled = !!ftrace_enabled;  | 
|---|
| 6802 |  | -  | 
|---|
| 6803 | 7620 |  	if (ftrace_enabled) { | 
|---|
| 6804 | 7621 |   | 
|---|
| 6805 | 7622 |  		/* we are starting ftrace again */ | 
|---|
| .. | .. | 
|---|
| 6810 | 7627 |  		ftrace_startup_sysctl(); | 
|---|
| 6811 | 7628 |   | 
|---|
| 6812 | 7629 |  	} else { | 
|---|
 | 7630 | +		if (is_permanent_ops_registered()) {  | 
|---|
 | 7631 | +			ftrace_enabled = true;  | 
|---|
 | 7632 | +			ret = -EBUSY;  | 
|---|
 | 7633 | +			goto out;  | 
|---|
 | 7634 | +		}  | 
|---|
 | 7635 | +  | 
|---|
| 6813 | 7636 |  		/* stopping ftrace calls (just send to ftrace_stub) */ | 
|---|
| 6814 | 7637 |  		ftrace_trace_function = ftrace_stub; | 
|---|
| 6815 | 7638 |   | 
|---|
| 6816 | 7639 |  		ftrace_shutdown_sysctl(); | 
|---|
| 6817 | 7640 |  	} | 
|---|
| 6818 | 7641 |   | 
|---|
 | 7642 | +	last_ftrace_enabled = !!ftrace_enabled;  | 
|---|
| 6819 | 7643 |   out: | 
|---|
| 6820 | 7644 |  	mutex_unlock(&ftrace_lock); | 
|---|
| 6821 | 7645 |  	return ret; | 
|---|
| 6822 | 7646 |  } | 
|---|
| 6823 |  | -  | 
|---|
| 6824 |  | -#ifdef CONFIG_FUNCTION_GRAPH_TRACER  | 
|---|
| 6825 |  | -  | 
|---|
| 6826 |  | -static struct ftrace_ops graph_ops = {  | 
|---|
| 6827 |  | -	.func			= ftrace_stub,  | 
|---|
| 6828 |  | -	.flags			= FTRACE_OPS_FL_RECURSION_SAFE |  | 
|---|
| 6829 |  | -				   FTRACE_OPS_FL_INITIALIZED |  | 
|---|
| 6830 |  | -				   FTRACE_OPS_FL_PID |  | 
|---|
| 6831 |  | -				   FTRACE_OPS_FL_STUB,  | 
|---|
| 6832 |  | -#ifdef FTRACE_GRAPH_TRAMP_ADDR  | 
|---|
| 6833 |  | -	.trampoline		= FTRACE_GRAPH_TRAMP_ADDR,  | 
|---|
| 6834 |  | -	/* trampoline_size is only needed for dynamically allocated tramps */  | 
|---|
| 6835 |  | -#endif  | 
|---|
| 6836 |  | -	ASSIGN_OPS_HASH(graph_ops, &global_ops.local_hash)  | 
|---|
| 6837 |  | -};  | 
|---|
| 6838 |  | -  | 
|---|
| 6839 |  | -void ftrace_graph_sleep_time_control(bool enable)  | 
|---|
| 6840 |  | -{  | 
|---|
| 6841 |  | -	fgraph_sleep_time = enable;  | 
|---|
| 6842 |  | -}  | 
|---|
| 6843 |  | -  | 
|---|
| 6844 |  | -void ftrace_graph_graph_time_control(bool enable)  | 
|---|
| 6845 |  | -{  | 
|---|
| 6846 |  | -	fgraph_graph_time = enable;  | 
|---|
| 6847 |  | -}  | 
|---|
| 6848 |  | -  | 
|---|
| 6849 |  | -void ftrace_graph_return_stub(struct ftrace_graph_ret *trace)  | 
|---|
| 6850 |  | -{  | 
|---|
| 6851 |  | -}  | 
|---|
| 6852 |  | -  | 
|---|
| 6853 |  | -int ftrace_graph_entry_stub(struct ftrace_graph_ent *trace)  | 
|---|
| 6854 |  | -{  | 
|---|
| 6855 |  | -	return 0;  | 
|---|
| 6856 |  | -}  | 
|---|
| 6857 |  | -  | 
|---|
| 6858 |  | -/* The callbacks that hook a function */  | 
|---|
| 6859 |  | -trace_func_graph_ret_t ftrace_graph_return = ftrace_graph_return_stub;  | 
|---|
| 6860 |  | -trace_func_graph_ent_t ftrace_graph_entry = ftrace_graph_entry_stub;  | 
|---|
| 6861 |  | -static trace_func_graph_ent_t __ftrace_graph_entry = ftrace_graph_entry_stub;  | 
|---|
| 6862 |  | -  | 
|---|
| 6863 |  | -/* Try to assign a return stack array on FTRACE_RETSTACK_ALLOC_SIZE tasks. */  | 
|---|
| 6864 |  | -static int alloc_retstack_tasklist(struct ftrace_ret_stack **ret_stack_list)  | 
|---|
| 6865 |  | -{  | 
|---|
| 6866 |  | -	int i;  | 
|---|
| 6867 |  | -	int ret = 0;  | 
|---|
| 6868 |  | -	int start = 0, end = FTRACE_RETSTACK_ALLOC_SIZE;  | 
|---|
| 6869 |  | -	struct task_struct *g, *t;  | 
|---|
| 6870 |  | -  | 
|---|
| 6871 |  | -	for (i = 0; i < FTRACE_RETSTACK_ALLOC_SIZE; i++) {  | 
|---|
| 6872 |  | -		ret_stack_list[i] =  | 
|---|
| 6873 |  | -			kmalloc_array(FTRACE_RETFUNC_DEPTH,  | 
|---|
| 6874 |  | -				      sizeof(struct ftrace_ret_stack),  | 
|---|
| 6875 |  | -				      GFP_KERNEL);  | 
|---|
| 6876 |  | -		if (!ret_stack_list[i]) {  | 
|---|
| 6877 |  | -			start = 0;  | 
|---|
| 6878 |  | -			end = i;  | 
|---|
| 6879 |  | -			ret = -ENOMEM;  | 
|---|
| 6880 |  | -			goto free;  | 
|---|
| 6881 |  | -		}  | 
|---|
| 6882 |  | -	}  | 
|---|
| 6883 |  | -  | 
|---|
| 6884 |  | -	read_lock(&tasklist_lock);  | 
|---|
| 6885 |  | -	do_each_thread(g, t) {  | 
|---|
| 6886 |  | -		if (start == end) {  | 
|---|
| 6887 |  | -			ret = -EAGAIN;  | 
|---|
| 6888 |  | -			goto unlock;  | 
|---|
| 6889 |  | -		}  | 
|---|
| 6890 |  | -  | 
|---|
| 6891 |  | -		if (t->ret_stack == NULL) {  | 
|---|
| 6892 |  | -			atomic_set(&t->trace_overrun, 0);  | 
|---|
| 6893 |  | -			t->curr_ret_stack = -1;  | 
|---|
| 6894 |  | -			t->curr_ret_depth = -1;  | 
|---|
| 6895 |  | -			/* Make sure the tasks see the -1 first: */  | 
|---|
| 6896 |  | -			smp_wmb();  | 
|---|
| 6897 |  | -			t->ret_stack = ret_stack_list[start++];  | 
|---|
| 6898 |  | -		}  | 
|---|
| 6899 |  | -	} while_each_thread(g, t);  | 
|---|
| 6900 |  | -  | 
|---|
| 6901 |  | -unlock:  | 
|---|
| 6902 |  | -	read_unlock(&tasklist_lock);  | 
|---|
| 6903 |  | -free:  | 
|---|
| 6904 |  | -	for (i = start; i < end; i++)  | 
|---|
| 6905 |  | -		kfree(ret_stack_list[i]);  | 
|---|
| 6906 |  | -	return ret;  | 
|---|
| 6907 |  | -}  | 
|---|
| 6908 |  | -  | 
|---|
| 6909 |  | -static void  | 
|---|
| 6910 |  | -ftrace_graph_probe_sched_switch(void *ignore, bool preempt,  | 
|---|
| 6911 |  | -			struct task_struct *prev, struct task_struct *next)  | 
|---|
| 6912 |  | -{  | 
|---|
| 6913 |  | -	unsigned long long timestamp;  | 
|---|
| 6914 |  | -	int index;  | 
|---|
| 6915 |  | -  | 
|---|
| 6916 |  | -	/*  | 
|---|
| 6917 |  | -	 * Does the user want to count the time a function was asleep.  | 
|---|
| 6918 |  | -	 * If so, do not update the time stamps.  | 
|---|
| 6919 |  | -	 */  | 
|---|
| 6920 |  | -	if (fgraph_sleep_time)  | 
|---|
| 6921 |  | -		return;  | 
|---|
| 6922 |  | -  | 
|---|
| 6923 |  | -	timestamp = trace_clock_local();  | 
|---|
| 6924 |  | -  | 
|---|
| 6925 |  | -	prev->ftrace_timestamp = timestamp;  | 
|---|
| 6926 |  | -  | 
|---|
| 6927 |  | -	/* only process tasks that we timestamped */  | 
|---|
| 6928 |  | -	if (!next->ftrace_timestamp)  | 
|---|
| 6929 |  | -		return;  | 
|---|
| 6930 |  | -  | 
|---|
| 6931 |  | -	/*  | 
|---|
| 6932 |  | -	 * Update all the counters in next to make up for the  | 
|---|
| 6933 |  | -	 * time next was sleeping.  | 
|---|
| 6934 |  | -	 */  | 
|---|
| 6935 |  | -	timestamp -= next->ftrace_timestamp;  | 
|---|
| 6936 |  | -  | 
|---|
| 6937 |  | -	for (index = next->curr_ret_stack; index >= 0; index--)  | 
|---|
| 6938 |  | -		next->ret_stack[index].calltime += timestamp;  | 
|---|
| 6939 |  | -}  | 
|---|
| 6940 |  | -  | 
|---|
| 6941 |  | -/* Allocate a return stack for each task */  | 
|---|
| 6942 |  | -static int start_graph_tracing(void)  | 
|---|
| 6943 |  | -{  | 
|---|
| 6944 |  | -	struct ftrace_ret_stack **ret_stack_list;  | 
|---|
| 6945 |  | -	int ret, cpu;  | 
|---|
| 6946 |  | -  | 
|---|
| 6947 |  | -	ret_stack_list = kmalloc_array(FTRACE_RETSTACK_ALLOC_SIZE,  | 
|---|
| 6948 |  | -				       sizeof(struct ftrace_ret_stack *),  | 
|---|
| 6949 |  | -				       GFP_KERNEL);  | 
|---|
| 6950 |  | -  | 
|---|
| 6951 |  | -	if (!ret_stack_list)  | 
|---|
| 6952 |  | -		return -ENOMEM;  | 
|---|
| 6953 |  | -  | 
|---|
| 6954 |  | -	/* The cpu_boot init_task->ret_stack will never be freed */  | 
|---|
| 6955 |  | -	for_each_online_cpu(cpu) {  | 
|---|
| 6956 |  | -		if (!idle_task(cpu)->ret_stack)  | 
|---|
| 6957 |  | -			ftrace_graph_init_idle_task(idle_task(cpu), cpu);  | 
|---|
| 6958 |  | -	}  | 
|---|
| 6959 |  | -  | 
|---|
| 6960 |  | -	do {  | 
|---|
| 6961 |  | -		ret = alloc_retstack_tasklist(ret_stack_list);  | 
|---|
| 6962 |  | -	} while (ret == -EAGAIN);  | 
|---|
| 6963 |  | -  | 
|---|
| 6964 |  | -	if (!ret) {  | 
|---|
| 6965 |  | -		ret = register_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);  | 
|---|
| 6966 |  | -		if (ret)  | 
|---|
| 6967 |  | -			pr_info("ftrace_graph: Couldn't activate tracepoint"  | 
|---|
| 6968 |  | -				" probe to kernel_sched_switch\n");  | 
|---|
| 6969 |  | -	}  | 
|---|
| 6970 |  | -  | 
|---|
| 6971 |  | -	kfree(ret_stack_list);  | 
|---|
| 6972 |  | -	return ret;  | 
|---|
| 6973 |  | -}  | 
|---|
| 6974 |  | -  | 
|---|
| 6975 |  | -/*  | 
|---|
| 6976 |  | - * Hibernation protection.  | 
|---|
| 6977 |  | - * The state of the current task is too much unstable during  | 
|---|
| 6978 |  | - * suspend/restore to disk. We want to protect against that.  | 
|---|
| 6979 |  | - */  | 
|---|
| 6980 |  | -static int  | 
|---|
| 6981 |  | -ftrace_suspend_notifier_call(struct notifier_block *bl, unsigned long state,  | 
|---|
| 6982 |  | -							void *unused)  | 
|---|
| 6983 |  | -{  | 
|---|
| 6984 |  | -	switch (state) {  | 
|---|
| 6985 |  | -	case PM_HIBERNATION_PREPARE:  | 
|---|
| 6986 |  | -		pause_graph_tracing();  | 
|---|
| 6987 |  | -		break;  | 
|---|
| 6988 |  | -  | 
|---|
| 6989 |  | -	case PM_POST_HIBERNATION:  | 
|---|
| 6990 |  | -		unpause_graph_tracing();  | 
|---|
| 6991 |  | -		break;  | 
|---|
| 6992 |  | -	}  | 
|---|
| 6993 |  | -	return NOTIFY_DONE;  | 
|---|
| 6994 |  | -}  | 
|---|
| 6995 |  | -  | 
|---|
| 6996 |  | -static int ftrace_graph_entry_test(struct ftrace_graph_ent *trace)  | 
|---|
| 6997 |  | -{  | 
|---|
| 6998 |  | -	if (!ftrace_ops_test(&global_ops, trace->func, NULL))  | 
|---|
| 6999 |  | -		return 0;  | 
|---|
| 7000 |  | -	return __ftrace_graph_entry(trace);  | 
|---|
| 7001 |  | -}  | 
|---|
| 7002 |  | -  | 
|---|
| 7003 |  | -/*  | 
|---|
| 7004 |  | - * The function graph tracer should only trace the functions defined  | 
|---|
| 7005 |  | - * by set_ftrace_filter and set_ftrace_notrace. If another function  | 
|---|
| 7006 |  | - * tracer ops is registered, the graph tracer requires testing the  | 
|---|
| 7007 |  | - * function against the global ops, and not just trace any function  | 
|---|
| 7008 |  | - * that any ftrace_ops registered.  | 
|---|
| 7009 |  | - */  | 
|---|
| 7010 |  | -static void update_function_graph_func(void)  | 
|---|
| 7011 |  | -{  | 
|---|
| 7012 |  | -	struct ftrace_ops *op;  | 
|---|
| 7013 |  | -	bool do_test = false;  | 
|---|
| 7014 |  | -  | 
|---|
| 7015 |  | -	/*  | 
|---|
| 7016 |  | -	 * The graph and global ops share the same set of functions  | 
|---|
| 7017 |  | -	 * to test. If any other ops is on the list, then  | 
|---|
| 7018 |  | -	 * the graph tracing needs to test if its the function  | 
|---|
| 7019 |  | -	 * it should call.  | 
|---|
| 7020 |  | -	 */  | 
|---|
| 7021 |  | -	do_for_each_ftrace_op(op, ftrace_ops_list) {  | 
|---|
| 7022 |  | -		if (op != &global_ops && op != &graph_ops &&  | 
|---|
| 7023 |  | -		    op != &ftrace_list_end) {  | 
|---|
| 7024 |  | -			do_test = true;  | 
|---|
| 7025 |  | -			/* in double loop, break out with goto */  | 
|---|
| 7026 |  | -			goto out;  | 
|---|
| 7027 |  | -		}  | 
|---|
| 7028 |  | -	} while_for_each_ftrace_op(op);  | 
|---|
| 7029 |  | - out:  | 
|---|
| 7030 |  | -	if (do_test)  | 
|---|
| 7031 |  | -		ftrace_graph_entry = ftrace_graph_entry_test;  | 
|---|
| 7032 |  | -	else  | 
|---|
| 7033 |  | -		ftrace_graph_entry = __ftrace_graph_entry;  | 
|---|
| 7034 |  | -}  | 
|---|
| 7035 |  | -  | 
|---|
| 7036 |  | -static struct notifier_block ftrace_suspend_notifier = {  | 
|---|
| 7037 |  | -	.notifier_call = ftrace_suspend_notifier_call,  | 
|---|
| 7038 |  | -};  | 
|---|
| 7039 |  | -  | 
|---|
| 7040 |  | -int register_ftrace_graph(trace_func_graph_ret_t retfunc,  | 
|---|
| 7041 |  | -			trace_func_graph_ent_t entryfunc)  | 
|---|
| 7042 |  | -{  | 
|---|
| 7043 |  | -	int ret = 0;  | 
|---|
| 7044 |  | -  | 
|---|
| 7045 |  | -	mutex_lock(&ftrace_lock);  | 
|---|
| 7046 |  | -  | 
|---|
| 7047 |  | -	/* we currently allow only one tracer registered at a time */  | 
|---|
| 7048 |  | -	if (ftrace_graph_active) {  | 
|---|
| 7049 |  | -		ret = -EBUSY;  | 
|---|
| 7050 |  | -		goto out;  | 
|---|
| 7051 |  | -	}  | 
|---|
| 7052 |  | -  | 
|---|
| 7053 |  | -	register_pm_notifier(&ftrace_suspend_notifier);  | 
|---|
| 7054 |  | -  | 
|---|
| 7055 |  | -	ftrace_graph_active++;  | 
|---|
| 7056 |  | -	ret = start_graph_tracing();  | 
|---|
| 7057 |  | -	if (ret) {  | 
|---|
| 7058 |  | -		ftrace_graph_active--;  | 
|---|
| 7059 |  | -		goto out;  | 
|---|
| 7060 |  | -	}  | 
|---|
| 7061 |  | -  | 
|---|
| 7062 |  | -	ftrace_graph_return = retfunc;  | 
|---|
| 7063 |  | -  | 
|---|
| 7064 |  | -	/*  | 
|---|
| 7065 |  | -	 * Update the indirect function to the entryfunc, and the  | 
|---|
| 7066 |  | -	 * function that gets called to the entry_test first. Then  | 
|---|
| 7067 |  | -	 * call the update fgraph entry function to determine if  | 
|---|
| 7068 |  | -	 * the entryfunc should be called directly or not.  | 
|---|
| 7069 |  | -	 */  | 
|---|
| 7070 |  | -	__ftrace_graph_entry = entryfunc;  | 
|---|
| 7071 |  | -	ftrace_graph_entry = ftrace_graph_entry_test;  | 
|---|
| 7072 |  | -	update_function_graph_func();  | 
|---|
| 7073 |  | -  | 
|---|
| 7074 |  | -	ret = ftrace_startup(&graph_ops, FTRACE_START_FUNC_RET);  | 
|---|
| 7075 |  | -out:  | 
|---|
| 7076 |  | -	mutex_unlock(&ftrace_lock);  | 
|---|
| 7077 |  | -	return ret;  | 
|---|
| 7078 |  | -}  | 
|---|
| 7079 |  | -  | 
|---|
| 7080 |  | -void unregister_ftrace_graph(void)  | 
|---|
| 7081 |  | -{  | 
|---|
| 7082 |  | -	mutex_lock(&ftrace_lock);  | 
|---|
| 7083 |  | -  | 
|---|
| 7084 |  | -	if (unlikely(!ftrace_graph_active))  | 
|---|
| 7085 |  | -		goto out;  | 
|---|
| 7086 |  | -  | 
|---|
| 7087 |  | -	ftrace_graph_active--;  | 
|---|
| 7088 |  | -	ftrace_graph_return = ftrace_graph_return_stub;  | 
|---|
| 7089 |  | -	ftrace_graph_entry = ftrace_graph_entry_stub;  | 
|---|
| 7090 |  | -	__ftrace_graph_entry = ftrace_graph_entry_stub;  | 
|---|
| 7091 |  | -	ftrace_shutdown(&graph_ops, FTRACE_STOP_FUNC_RET);  | 
|---|
| 7092 |  | -	unregister_pm_notifier(&ftrace_suspend_notifier);  | 
|---|
| 7093 |  | -	unregister_trace_sched_switch(ftrace_graph_probe_sched_switch, NULL);  | 
|---|
| 7094 |  | -  | 
|---|
| 7095 |  | - out:  | 
|---|
| 7096 |  | -	mutex_unlock(&ftrace_lock);  | 
|---|
| 7097 |  | -}  | 
|---|
| 7098 |  | -  | 
|---|
| 7099 |  | -static DEFINE_PER_CPU(struct ftrace_ret_stack *, idle_ret_stack);  | 
|---|
| 7100 |  | -  | 
|---|
| 7101 |  | -static void  | 
|---|
| 7102 |  | -graph_init_task(struct task_struct *t, struct ftrace_ret_stack *ret_stack)  | 
|---|
| 7103 |  | -{  | 
|---|
| 7104 |  | -	atomic_set(&t->trace_overrun, 0);  | 
|---|
| 7105 |  | -	t->ftrace_timestamp = 0;  | 
|---|
| 7106 |  | -	/* make curr_ret_stack visible before we add the ret_stack */  | 
|---|
| 7107 |  | -	smp_wmb();  | 
|---|
| 7108 |  | -	t->ret_stack = ret_stack;  | 
|---|
| 7109 |  | -}  | 
|---|
| 7110 |  | -  | 
|---|
| 7111 |  | -/*  | 
|---|
| 7112 |  | - * Allocate a return stack for the idle task. May be the first  | 
|---|
| 7113 |  | - * time through, or it may be done by CPU hotplug online.  | 
|---|
| 7114 |  | - */  | 
|---|
| 7115 |  | -void ftrace_graph_init_idle_task(struct task_struct *t, int cpu)  | 
|---|
| 7116 |  | -{  | 
|---|
| 7117 |  | -	t->curr_ret_stack = -1;  | 
|---|
| 7118 |  | -	t->curr_ret_depth = -1;  | 
|---|
| 7119 |  | -	/*  | 
|---|
| 7120 |  | -	 * The idle task has no parent, it either has its own  | 
|---|
| 7121 |  | -	 * stack or no stack at all.  | 
|---|
| 7122 |  | -	 */  | 
|---|
| 7123 |  | -	if (t->ret_stack)  | 
|---|
| 7124 |  | -		WARN_ON(t->ret_stack != per_cpu(idle_ret_stack, cpu));  | 
|---|
| 7125 |  | -  | 
|---|
| 7126 |  | -	if (ftrace_graph_active) {  | 
|---|
| 7127 |  | -		struct ftrace_ret_stack *ret_stack;  | 
|---|
| 7128 |  | -  | 
|---|
| 7129 |  | -		ret_stack = per_cpu(idle_ret_stack, cpu);  | 
|---|
| 7130 |  | -		if (!ret_stack) {  | 
|---|
| 7131 |  | -			ret_stack =  | 
|---|
| 7132 |  | -				kmalloc_array(FTRACE_RETFUNC_DEPTH,  | 
|---|
| 7133 |  | -					      sizeof(struct ftrace_ret_stack),  | 
|---|
| 7134 |  | -					      GFP_KERNEL);  | 
|---|
| 7135 |  | -			if (!ret_stack)  | 
|---|
| 7136 |  | -				return;  | 
|---|
| 7137 |  | -			per_cpu(idle_ret_stack, cpu) = ret_stack;  | 
|---|
| 7138 |  | -		}  | 
|---|
| 7139 |  | -		graph_init_task(t, ret_stack);  | 
|---|
| 7140 |  | -	}  | 
|---|
| 7141 |  | -}  | 
|---|
| 7142 |  | -  | 
|---|
| 7143 |  | -/* Allocate a return stack for newly created task */  | 
|---|
| 7144 |  | -void ftrace_graph_init_task(struct task_struct *t)  | 
|---|
| 7145 |  | -{  | 
|---|
| 7146 |  | -	/* Make sure we do not use the parent ret_stack */  | 
|---|
| 7147 |  | -	t->ret_stack = NULL;  | 
|---|
| 7148 |  | -	t->curr_ret_stack = -1;  | 
|---|
| 7149 |  | -	t->curr_ret_depth = -1;  | 
|---|
| 7150 |  | -  | 
|---|
| 7151 |  | -	if (ftrace_graph_active) {  | 
|---|
| 7152 |  | -		struct ftrace_ret_stack *ret_stack;  | 
|---|
| 7153 |  | -  | 
|---|
| 7154 |  | -		ret_stack = kmalloc_array(FTRACE_RETFUNC_DEPTH,  | 
|---|
| 7155 |  | -					  sizeof(struct ftrace_ret_stack),  | 
|---|
| 7156 |  | -					  GFP_KERNEL);  | 
|---|
| 7157 |  | -		if (!ret_stack)  | 
|---|
| 7158 |  | -			return;  | 
|---|
| 7159 |  | -		graph_init_task(t, ret_stack);  | 
|---|
| 7160 |  | -	}  | 
|---|
| 7161 |  | -}  | 
|---|
| 7162 |  | -  | 
|---|
| 7163 |  | -void ftrace_graph_exit_task(struct task_struct *t)  | 
|---|
| 7164 |  | -{  | 
|---|
| 7165 |  | -	struct ftrace_ret_stack	*ret_stack = t->ret_stack;  | 
|---|
| 7166 |  | -  | 
|---|
| 7167 |  | -	t->ret_stack = NULL;  | 
|---|
| 7168 |  | -	/* NULL must become visible to IRQs before we free it: */  | 
|---|
| 7169 |  | -	barrier();  | 
|---|
| 7170 |  | -  | 
|---|
| 7171 |  | -	kfree(ret_stack);  | 
|---|
| 7172 |  | -}  | 
|---|
| 7173 |  | -#endif  | 
|---|