diff options
Diffstat (limited to 'kernel/trace/trace.h')
| -rw-r--r-- | kernel/trace/trace.h | 331 | 
1 files changed, 290 insertions, 41 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index 10c86fb7a2b..9258f5a815d 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -1,3 +1,4 @@ +  #ifndef _LINUX_KERNEL_TRACE_H  #define _LINUX_KERNEL_TRACE_H @@ -12,6 +13,7 @@  #include <linux/hw_breakpoint.h>  #include <linux/trace_seq.h>  #include <linux/ftrace_event.h> +#include <linux/compiler.h>  #ifdef CONFIG_FTRACE_SYSCALLS  #include <asm/unistd.h>		/* For NR_SYSCALLS	     */ @@ -124,6 +126,7 @@ enum trace_flag_type {  	TRACE_FLAG_NEED_RESCHED		= 0x04,  	TRACE_FLAG_HARDIRQ		= 0x08,  	TRACE_FLAG_SOFTIRQ		= 0x10, +	TRACE_FLAG_PREEMPT_RESCHED	= 0x20,  };  #define TRACE_BUF_SIZE		1024 @@ -187,13 +190,28 @@ struct trace_array {  	 */  	struct trace_buffer	max_buffer;  	bool			allocated_snapshot; +	unsigned long		max_latency;  #endif +	/* +	 * max_lock is used to protect the swapping of buffers +	 * when taking a max snapshot. The buffers themselves are +	 * protected by per_cpu spinlocks. But the action of the swap +	 * needs its own lock. +	 * +	 * This is defined as a arch_spinlock_t in order to help +	 * with performance when lockdep debugging is enabled. +	 * +	 * It is also used in other places outside the update_max_tr +	 * so it needs to be defined outside of the +	 * CONFIG_TRACER_MAX_TRACE. +	 */ +	arch_spinlock_t		max_lock;  	int			buffer_disabled;  #ifdef CONFIG_FTRACE_SYSCALLS  	int			sys_refcount_enter;  	int			sys_refcount_exit; -	DECLARE_BITMAP(enabled_enter_syscalls, NR_syscalls); -	DECLARE_BITMAP(enabled_exit_syscalls, NR_syscalls); +	struct ftrace_event_file __rcu *enter_syscall_files[NR_syscalls]; +	struct ftrace_event_file __rcu *exit_syscall_files[NR_syscalls];  #endif  	int			stop_count;  	int			clock_id; @@ -208,6 +226,11 @@ struct trace_array {  	struct list_head	events;  	cpumask_var_t		tracing_cpumask; /* only trace on set CPUs */  	int			ref; +#ifdef CONFIG_FUNCTION_TRACER +	struct ftrace_ops	*ops; +	/* function tracing enabled */ +	int			function_enabled; +#endif  };  enum { @@ -229,6 +252,9 @@ static inline struct trace_array *top_trace_array(void)  {  	struct trace_array *tr; +	if (list_empty(&ftrace_trace_arrays)) +		return NULL; +  	tr = list_entry(ftrace_trace_arrays.prev,  			typeof(*tr), list);  	WARN_ON(!(tr->flags & TRACE_ARRAY_FL_GLOBAL)); @@ -315,7 +341,6 @@ struct tracer_flags {   * @stop: called when tracing is paused (echo 0 > tracing_enabled)   * @open: called when the trace file is opened   * @pipe_open: called when the trace_pipe file is opened - * @wait_pipe: override how the user waits for traces on trace_pipe   * @close: called when the trace file is released   * @pipe_close: called when the trace_pipe file is released   * @read: override the default read callback on trace_pipe @@ -334,7 +359,6 @@ struct tracer {  	void			(*stop)(struct trace_array *tr);  	void			(*open)(struct trace_iterator *iter);  	void			(*pipe_open)(struct trace_iterator *iter); -	void			(*wait_pipe)(struct trace_iterator *iter);  	void			(*close)(struct trace_iterator *iter);  	void			(*pipe_close)(struct trace_iterator *iter);  	ssize_t			(*read)(struct trace_iterator *iter, @@ -353,14 +377,16 @@ struct tracer {  	void			(*print_header)(struct seq_file *m);  	enum print_line_t	(*print_line)(struct trace_iterator *iter);  	/* If you handled the flag setting, return 0 */ -	int			(*set_flag)(u32 old_flags, u32 bit, int set); +	int			(*set_flag)(struct trace_array *tr, +					    u32 old_flags, u32 bit, int set);  	/* Return 0 if OK with change, else return non-zero */ -	int			(*flag_changed)(struct tracer *tracer, +	int			(*flag_changed)(struct trace_array *tr,  						u32 mask, int set);  	struct tracer		*next;  	struct tracer_flags	*flags; +	int			enabled;  	bool			print_max; -	bool			enabled; +	bool			allow_instances;  #ifdef CONFIG_TRACER_MAX_TRACE  	bool			use_max_tr;  #endif @@ -406,13 +432,7 @@ enum {  	TRACE_FTRACE_IRQ_BIT,  	TRACE_FTRACE_SIRQ_BIT, -	/* GLOBAL_BITs must be greater than FTRACE_BITs */ -	TRACE_GLOBAL_BIT, -	TRACE_GLOBAL_NMI_BIT, -	TRACE_GLOBAL_IRQ_BIT, -	TRACE_GLOBAL_SIRQ_BIT, - -	/* INTERNAL_BITs must be greater than GLOBAL_BITs */ +	/* INTERNAL_BITs must be greater than FTRACE_BITs */  	TRACE_INTERNAL_BIT,  	TRACE_INTERNAL_NMI_BIT,  	TRACE_INTERNAL_IRQ_BIT, @@ -439,9 +459,6 @@ enum {  #define TRACE_FTRACE_START	TRACE_FTRACE_BIT  #define TRACE_FTRACE_MAX	((1 << (TRACE_FTRACE_START + TRACE_CONTEXT_BITS)) - 1) -#define TRACE_GLOBAL_START	TRACE_GLOBAL_BIT -#define TRACE_GLOBAL_MAX	((1 << (TRACE_GLOBAL_START + TRACE_CONTEXT_BITS)) - 1) -  #define TRACE_LIST_START	TRACE_INTERNAL_BIT  #define TRACE_LIST_MAX		((1 << (TRACE_LIST_START + TRACE_CONTEXT_BITS)) - 1) @@ -514,6 +531,7 @@ void tracing_reset_online_cpus(struct trace_buffer *buf);  void tracing_reset_current(int cpu);  void tracing_reset_all_online_cpus(void);  int tracing_open_generic(struct inode *inode, struct file *filp); +bool tracing_is_disabled(void);  struct dentry *trace_create_file(const char *name,  				 umode_t mode,  				 struct dentry *parent, @@ -549,8 +567,6 @@ void trace_init_global_iter(struct trace_iterator *iter);  void tracing_iter_reset(struct trace_iterator *iter, int cpu); -void poll_wait_pipe(struct trace_iterator *iter); -  void tracing_sched_switch_trace(struct trace_array *tr,  				struct task_struct *prev,  				struct task_struct *next, @@ -585,6 +601,8 @@ void tracing_start_sched_switch_record(void);  int register_tracer(struct tracer *type);  int is_tracing_stopped(void); +loff_t tracing_lseek(struct file *file, loff_t offset, int whence); +  extern cpumask_var_t __read_mostly tracing_buffer_mask;  #define for_each_tracing_cpu(cpu)	\ @@ -595,8 +613,6 @@ extern unsigned long nsecs_to_usecs(unsigned long nsecs);  extern unsigned long tracing_thresh;  #ifdef CONFIG_TRACER_MAX_TRACE -extern unsigned long tracing_max_latency; -  void update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu);  void update_max_tr_single(struct trace_array *tr,  			  struct task_struct *tsk, int cpu); @@ -711,6 +727,10 @@ extern unsigned long trace_flags;  #define TRACE_GRAPH_PRINT_PROC          0x8  #define TRACE_GRAPH_PRINT_DURATION      0x10  #define TRACE_GRAPH_PRINT_ABS_TIME      0x20 +#define TRACE_GRAPH_PRINT_IRQS          0x40 +#define TRACE_GRAPH_PRINT_TAIL          0x80 +#define TRACE_GRAPH_PRINT_FILL_SHIFT	28 +#define TRACE_GRAPH_PRINT_FILL_MASK	(0x3 << TRACE_GRAPH_PRINT_FILL_SHIFT)  extern enum print_line_t  print_graph_function_flags(struct trace_iterator *iter, u32 flags); @@ -730,15 +750,16 @@ extern void __trace_graph_return(struct trace_array *tr,  #ifdef CONFIG_DYNAMIC_FTRACE  /* TODO: make this variable */  #define FTRACE_GRAPH_MAX_FUNCS		32 -extern int ftrace_graph_filter_enabled;  extern int ftrace_graph_count;  extern unsigned long ftrace_graph_funcs[FTRACE_GRAPH_MAX_FUNCS]; +extern int ftrace_graph_notrace_count; +extern unsigned long ftrace_graph_notrace_funcs[FTRACE_GRAPH_MAX_FUNCS];  static inline int ftrace_graph_addr(unsigned long addr)  {  	int i; -	if (!ftrace_graph_filter_enabled) +	if (!ftrace_graph_count)  		return 1;  	for (i = 0; i < ftrace_graph_count; i++) { @@ -758,11 +779,31 @@ static inline int ftrace_graph_addr(unsigned long addr)  	return 0;  } + +static inline int ftrace_graph_notrace_addr(unsigned long addr) +{ +	int i; + +	if (!ftrace_graph_notrace_count) +		return 0; + +	for (i = 0; i < ftrace_graph_notrace_count; i++) { +		if (addr == ftrace_graph_notrace_funcs[i]) +			return 1; +	} + +	return 0; +}  #else  static inline int ftrace_graph_addr(unsigned long addr)  {  	return 1;  } + +static inline int ftrace_graph_notrace_addr(unsigned long addr) +{ +	return 0; +}  #endif /* CONFIG_DYNAMIC_FTRACE */  #else /* CONFIG_FUNCTION_GRAPH_TRACER */  static inline enum print_line_t @@ -784,13 +825,45 @@ static inline int ftrace_trace_task(struct task_struct *task)  	return test_tsk_trace_trace(task);  }  extern int ftrace_is_dead(void); +int ftrace_create_function_files(struct trace_array *tr, +				 struct dentry *parent); +void ftrace_destroy_function_files(struct trace_array *tr); +void ftrace_init_global_array_ops(struct trace_array *tr); +void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func); +void ftrace_reset_array_ops(struct trace_array *tr); +int using_ftrace_ops_list_func(void);  #else  static inline int ftrace_trace_task(struct task_struct *task)  {  	return 1;  }  static inline int ftrace_is_dead(void) { return 0; } -#endif +static inline int +ftrace_create_function_files(struct trace_array *tr, +			     struct dentry *parent) +{ +	return 0; +} +static inline void ftrace_destroy_function_files(struct trace_array *tr) { } +static inline __init void +ftrace_init_global_array_ops(struct trace_array *tr) { } +static inline void ftrace_reset_array_ops(struct trace_array *tr) { } +/* ftace_func_t type is not defined, use macro instead of static inline */ +#define ftrace_init_array_ops(tr, func) do { } while (0) +#endif /* CONFIG_FUNCTION_TRACER */ + +#if defined(CONFIG_FUNCTION_TRACER) && defined(CONFIG_DYNAMIC_FTRACE) +void ftrace_create_filter_files(struct ftrace_ops *ops, +				struct dentry *parent); +void ftrace_destroy_filter_files(struct ftrace_ops *ops); +#else +/* + * The ops parameter passed in is usually undefined. + * This must be a macro. + */ +#define ftrace_create_filter_files(ops, parent) do { } while (0) +#define ftrace_destroy_filter_files(ops) do { } while (0) +#endif /* CONFIG_FUNCTION_TRACER && CONFIG_DYNAMIC_FTRACE */  int ftrace_event_is_function(struct ftrace_event_call *call); @@ -986,40 +1059,216 @@ struct filter_pred {  extern enum regex_type  filter_parse_regex(char *buff, int len, char **search, int *not); -extern void print_event_filter(struct ftrace_event_call *call, +extern void print_event_filter(struct ftrace_event_file *file,  			       struct trace_seq *s); -extern int apply_event_filter(struct ftrace_event_call *call, +extern int apply_event_filter(struct ftrace_event_file *file,  			      char *filter_string);  extern int apply_subsystem_event_filter(struct ftrace_subsystem_dir *dir,  					char *filter_string);  extern void print_subsystem_event_filter(struct event_subsystem *system,  					 struct trace_seq *s);  extern int filter_assign_type(const char *type); +extern int create_event_filter(struct ftrace_event_call *call, +			       char *filter_str, bool set_str, +			       struct event_filter **filterp); +extern void free_event_filter(struct event_filter *filter);  struct ftrace_event_field *  trace_find_event_field(struct ftrace_event_call *call, char *name); -static inline int -filter_check_discard(struct ftrace_event_call *call, void *rec, -		     struct ring_buffer *buffer, -		     struct ring_buffer_event *event) -{ -	if (unlikely(call->flags & TRACE_EVENT_FL_FILTERED) && -	    !filter_match_preds(call->filter, rec)) { -		ring_buffer_discard_commit(buffer, event); -		return 1; -	} - -	return 0; -} -  extern void trace_event_enable_cmd_record(bool enable);  extern int event_trace_add_tracer(struct dentry *parent, struct trace_array *tr);  extern int event_trace_del_tracer(struct trace_array *tr); +extern struct ftrace_event_file *find_event_file(struct trace_array *tr, +						 const char *system, +						 const char *event); + +static inline void *event_file_data(struct file *filp) +{ +	return ACCESS_ONCE(file_inode(filp)->i_private); +} +  extern struct mutex event_mutex;  extern struct list_head ftrace_events; +extern const struct file_operations event_trigger_fops; + +extern int register_trigger_cmds(void); +extern void clear_event_triggers(struct trace_array *tr); + +struct event_trigger_data { +	unsigned long			count; +	int				ref; +	struct event_trigger_ops	*ops; +	struct event_command		*cmd_ops; +	struct event_filter __rcu	*filter; +	char				*filter_str; +	void				*private_data; +	struct list_head		list; +}; + +/** + * struct event_trigger_ops - callbacks for trace event triggers + * + * The methods in this structure provide per-event trigger hooks for + * various trigger operations. + * + * All the methods below, except for @init() and @free(), must be + * implemented. + * + * @func: The trigger 'probe' function called when the triggering + *	event occurs.  The data passed into this callback is the data + *	that was supplied to the event_command @reg() function that + *	registered the trigger (see struct event_command). + * + * @init: An optional initialization function called for the trigger + *	when the trigger is registered (via the event_command reg() + *	function).  This can be used to perform per-trigger + *	initialization such as incrementing a per-trigger reference + *	count, for instance.  This is usually implemented by the + *	generic utility function @event_trigger_init() (see + *	trace_event_triggers.c). + * + * @free: An optional de-initialization function called for the + *	trigger when the trigger is unregistered (via the + *	event_command @reg() function).  This can be used to perform + *	per-trigger de-initialization such as decrementing a + *	per-trigger reference count and freeing corresponding trigger + *	data, for instance.  This is usually implemented by the + *	generic utility function @event_trigger_free() (see + *	trace_event_triggers.c). + * + * @print: The callback function invoked to have the trigger print + *	itself.  This is usually implemented by a wrapper function + *	that calls the generic utility function @event_trigger_print() + *	(see trace_event_triggers.c). + */ +struct event_trigger_ops { +	void			(*func)(struct event_trigger_data *data); +	int			(*init)(struct event_trigger_ops *ops, +					struct event_trigger_data *data); +	void			(*free)(struct event_trigger_ops *ops, +					struct event_trigger_data *data); +	int			(*print)(struct seq_file *m, +					 struct event_trigger_ops *ops, +					 struct event_trigger_data *data); +}; + +/** + * struct event_command - callbacks and data members for event commands + * + * Event commands are invoked by users by writing the command name + * into the 'trigger' file associated with a trace event.  The + * parameters associated with a specific invocation of an event + * command are used to create an event trigger instance, which is + * added to the list of trigger instances associated with that trace + * event.  When the event is hit, the set of triggers associated with + * that event is invoked. + * + * The data members in this structure provide per-event command data + * for various event commands. + * + * All the data members below, except for @post_trigger, must be set + * for each event command. + * + * @name: The unique name that identifies the event command.  This is + *	the name used when setting triggers via trigger files. + * + * @trigger_type: A unique id that identifies the event command + *	'type'.  This value has two purposes, the first to ensure that + *	only one trigger of the same type can be set at a given time + *	for a particular event e.g. it doesn't make sense to have both + *	a traceon and traceoff trigger attached to a single event at + *	the same time, so traceon and traceoff have the same type + *	though they have different names.  The @trigger_type value is + *	also used as a bit value for deferring the actual trigger + *	action until after the current event is finished.  Some + *	commands need to do this if they themselves log to the trace + *	buffer (see the @post_trigger() member below).  @trigger_type + *	values are defined by adding new values to the trigger_type + *	enum in include/linux/ftrace_event.h. + * + * @post_trigger: A flag that says whether or not this command needs + *	to have its action delayed until after the current event has + *	been closed.  Some triggers need to avoid being invoked while + *	an event is currently in the process of being logged, since + *	the trigger may itself log data into the trace buffer.  Thus + *	we make sure the current event is committed before invoking + *	those triggers.  To do that, the trigger invocation is split + *	in two - the first part checks the filter using the current + *	trace record; if a command has the @post_trigger flag set, it + *	sets a bit for itself in the return value, otherwise it + *	directly invokes the trigger.  Once all commands have been + *	either invoked or set their return flag, the current record is + *	either committed or discarded.  At that point, if any commands + *	have deferred their triggers, those commands are finally + *	invoked following the close of the current event.  In other + *	words, if the event_trigger_ops @func() probe implementation + *	itself logs to the trace buffer, this flag should be set, + *	otherwise it can be left unspecified. + * + * All the methods below, except for @set_filter(), must be + * implemented. + * + * @func: The callback function responsible for parsing and + *	registering the trigger written to the 'trigger' file by the + *	user.  It allocates the trigger instance and registers it with + *	the appropriate trace event.  It makes use of the other + *	event_command callback functions to orchestrate this, and is + *	usually implemented by the generic utility function + *	@event_trigger_callback() (see trace_event_triggers.c). + * + * @reg: Adds the trigger to the list of triggers associated with the + *	event, and enables the event trigger itself, after + *	initializing it (via the event_trigger_ops @init() function). + *	This is also where commands can use the @trigger_type value to + *	make the decision as to whether or not multiple instances of + *	the trigger should be allowed.  This is usually implemented by + *	the generic utility function @register_trigger() (see + *	trace_event_triggers.c). + * + * @unreg: Removes the trigger from the list of triggers associated + *	with the event, and disables the event trigger itself, after + *	initializing it (via the event_trigger_ops @free() function). + *	This is usually implemented by the generic utility function + *	@unregister_trigger() (see trace_event_triggers.c). + * + * @set_filter: An optional function called to parse and set a filter + *	for the trigger.  If no @set_filter() method is set for the + *	event command, filters set by the user for the command will be + *	ignored.  This is usually implemented by the generic utility + *	function @set_trigger_filter() (see trace_event_triggers.c). + * + * @get_trigger_ops: The callback function invoked to retrieve the + *	event_trigger_ops implementation associated with the command. + */ +struct event_command { +	struct list_head	list; +	char			*name; +	enum event_trigger_type	trigger_type; +	bool			post_trigger; +	int			(*func)(struct event_command *cmd_ops, +					struct ftrace_event_file *file, +					char *glob, char *cmd, char *params); +	int			(*reg)(char *glob, +				       struct event_trigger_ops *ops, +				       struct event_trigger_data *data, +				       struct ftrace_event_file *file); +	void			(*unreg)(char *glob, +					 struct event_trigger_ops *ops, +					 struct event_trigger_data *data, +					 struct ftrace_event_file *file); +	int			(*set_filter)(char *filter_str, +					      struct event_trigger_data *data, +					      struct ftrace_event_file *file); +	struct event_trigger_ops *(*get_trigger_ops)(char *cmd, char *param); +}; + +extern int trace_event_enable_disable(struct ftrace_event_file *file, +				      int enable, int soft_disable); +extern int tracing_alloc_snapshot(void); +  extern const char *__start___trace_bprintk_fmt[];  extern const char *__stop___trace_bprintk_fmt[]; @@ -1045,7 +1294,7 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled);  #undef FTRACE_ENTRY  #define FTRACE_ENTRY(call, struct_name, id, tstruct, print, filter)	\  	extern struct ftrace_event_call					\ -	__attribute__((__aligned__(4))) event_##call; +	__aligned(4) event_##call;  #undef FTRACE_ENTRY_DUP  #define FTRACE_ENTRY_DUP(call, struct_name, id, tstruct, print, filter)	\  	FTRACE_ENTRY(call, struct_name, id, PARAMS(tstruct), PARAMS(print), \  | 
