diff options
Diffstat (limited to 'kernel/trace/trace.h')
| -rw-r--r-- | kernel/trace/trace.h | 211 | 
1 files changed, 146 insertions, 65 deletions
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h index f69f86788c2..f1f99572cde 100644 --- a/kernel/trace/trace.h +++ b/kernel/trace/trace.h @@ -5,7 +5,9 @@  #include <asm/atomic.h>  #include <linux/sched.h>  #include <linux/clocksource.h> +#include <linux/ring_buffer.h>  #include <linux/mmiotrace.h> +#include <linux/ftrace.h>  enum trace_type {  	__TRACE_FIRST_TYPE = 0, @@ -13,38 +15,60 @@ enum trace_type {  	TRACE_FN,  	TRACE_CTX,  	TRACE_WAKE, +	TRACE_CONT,  	TRACE_STACK, +	TRACE_PRINT,  	TRACE_SPECIAL,  	TRACE_MMIO_RW,  	TRACE_MMIO_MAP, +	TRACE_BOOT,  	__TRACE_LAST_TYPE  };  /* + * The trace entry - the most basic unit of tracing. This is what + * is printed in the end as a single line in the trace output, such as: + * + *     bash-15816 [01]   235.197585: idle_cpu <- irq_enter + */ +struct trace_entry { +	unsigned char		type; +	unsigned char		cpu; +	unsigned char		flags; +	unsigned char		preempt_count; +	int			pid; +}; + +/*   * Function trace entry - function address and parent function addres:   */  struct ftrace_entry { +	struct trace_entry	ent;  	unsigned long		ip;  	unsigned long		parent_ip;  }; +extern struct tracer boot_tracer;  /*   * Context switch trace entry - which task (and prio) we switched from/to:   */  struct ctx_switch_entry { +	struct trace_entry	ent;  	unsigned int		prev_pid;  	unsigned char		prev_prio;  	unsigned char		prev_state;  	unsigned int		next_pid;  	unsigned char		next_prio;  	unsigned char		next_state; +	unsigned int		next_cpu;  };  /*   * Special (free-form) trace entry:   */  struct special_entry { +	struct trace_entry	ent;  	unsigned long		arg1;  	unsigned long		arg2;  	unsigned long		arg3; @@ -57,33 +81,60 @@ struct special_entry {  #define FTRACE_STACK_ENTRIES	8  struct stack_entry { +	struct trace_entry	ent;  	unsigned long		caller[FTRACE_STACK_ENTRIES];  };  /* - * The trace entry - the most basic unit of tracing. This is what - * is printed in the end as a single line in the trace output, such as: - * - *     bash-15816 [01]   235.197585: idle_cpu <- irq_enter + * ftrace_printk entry:   */ -struct trace_entry { -	char			type; -	char			cpu; -	char			flags; -	char			preempt_count; -	int			pid; -	cycle_t			t; -	union { -		struct ftrace_entry		fn; -		struct ctx_switch_entry		ctx; -		struct special_entry		special; -		struct stack_entry		stack; -		struct mmiotrace_rw		mmiorw; -		struct mmiotrace_map		mmiomap; -	}; +struct print_entry { +	struct trace_entry	ent; +	unsigned long		ip; +	char			buf[]; +}; + +#define TRACE_OLD_SIZE		88 + +struct trace_field_cont { +	unsigned char		type; +	/* Temporary till we get rid of this completely */ +	char			buf[TRACE_OLD_SIZE - 1]; +}; + +struct trace_mmiotrace_rw { +	struct trace_entry	ent; +	struct mmiotrace_rw	rw; +}; + +struct trace_mmiotrace_map { +	struct trace_entry	ent; +	struct mmiotrace_map	map; +}; + +struct trace_boot { +	struct trace_entry	ent; +	struct boot_trace	initcall; +}; + +/* + * trace_flag_type is an enumeration that holds different + * states when a trace occurs. These are: + *  IRQS_OFF	- interrupts were disabled + *  NEED_RESCED - reschedule is requested + *  HARDIRQ	- inside an interrupt handler + *  SOFTIRQ	- inside a softirq handler + *  CONT	- multiple entries hold the trace item + */ +enum trace_flag_type { +	TRACE_FLAG_IRQS_OFF		= 0x01, +	TRACE_FLAG_NEED_RESCHED		= 0x02, +	TRACE_FLAG_HARDIRQ		= 0x04, +	TRACE_FLAG_SOFTIRQ		= 0x08, +	TRACE_FLAG_CONT			= 0x10,  }; -#define TRACE_ENTRY_SIZE	sizeof(struct trace_entry) +#define TRACE_BUF_SIZE		1024  /*   * The CPU trace array - it consists of thousands of trace entries @@ -91,16 +142,9 @@ struct trace_entry {   * the trace, etc.)   */  struct trace_array_cpu { -	struct list_head	trace_pages;  	atomic_t		disabled; -	raw_spinlock_t		lock; -	struct lock_class_key	lock_key;  	/* these fields get copied into max-trace: */ -	unsigned		trace_head_idx; -	unsigned		trace_tail_idx; -	void			*trace_head; /* producer */ -	void			*trace_tail; /* consumer */  	unsigned long		trace_idx;  	unsigned long		overrun;  	unsigned long		saved_latency; @@ -124,6 +168,7 @@ struct trace_iterator;   * They have on/off state as well:   */  struct trace_array { +	struct ring_buffer	*buffer;  	unsigned long		entries;  	long			ctrl;  	int			cpu; @@ -132,6 +177,56 @@ struct trace_array {  	struct trace_array_cpu	*data[NR_CPUS];  }; +#define FTRACE_CMP_TYPE(var, type) \ +	__builtin_types_compatible_p(typeof(var), type *) + +#undef IF_ASSIGN +#define IF_ASSIGN(var, entry, etype, id)		\ +	if (FTRACE_CMP_TYPE(var, etype)) {		\ +		var = (typeof(var))(entry);		\ +		WARN_ON(id && (entry)->type != id);	\ +		break;					\ +	} + +/* Will cause compile errors if type is not found. */ +extern void __ftrace_bad_type(void); + +/* + * The trace_assign_type is a verifier that the entry type is + * the same as the type being assigned. To add new types simply + * add a line with the following format: + * + * IF_ASSIGN(var, ent, type, id); + * + *  Where "type" is the trace type that includes the trace_entry + *  as the "ent" item. And "id" is the trace identifier that is + *  used in the trace_type enum. + * + *  If the type can have more than one id, then use zero. + */ +#define trace_assign_type(var, ent)					\ +	do {								\ +		IF_ASSIGN(var, ent, struct ftrace_entry, TRACE_FN);	\ +		IF_ASSIGN(var, ent, struct ctx_switch_entry, 0);	\ +		IF_ASSIGN(var, ent, struct trace_field_cont, TRACE_CONT); \ +		IF_ASSIGN(var, ent, struct stack_entry, TRACE_STACK);	\ +		IF_ASSIGN(var, ent, struct print_entry, TRACE_PRINT);	\ +		IF_ASSIGN(var, ent, struct special_entry, 0);		\ +		IF_ASSIGN(var, ent, struct trace_mmiotrace_rw,		\ +			  TRACE_MMIO_RW);				\ +		IF_ASSIGN(var, ent, struct trace_mmiotrace_map,		\ +			  TRACE_MMIO_MAP);				\ +		IF_ASSIGN(var, ent, struct trace_boot, TRACE_BOOT);	\ +		__ftrace_bad_type();					\ +	} while (0) + +/* Return values for print_line callback */ +enum print_line_t { +	TRACE_TYPE_PARTIAL_LINE	= 0,	/* Retry after flushing the seq */ +	TRACE_TYPE_HANDLED	= 1, +	TRACE_TYPE_UNHANDLED	= 2	/* Relay to other output functions */ +}; +  /*   * A specific tracer, represented by methods that operate on a trace array:   */ @@ -152,7 +247,7 @@ struct tracer {  	int			(*selftest)(struct tracer *trace,  					    struct trace_array *tr);  #endif -	int			(*print_line)(struct trace_iterator *iter); +	enum print_line_t	(*print_line)(struct trace_iterator *iter);  	struct tracer		*next;  	int			print_max;  }; @@ -171,57 +266,58 @@ struct trace_iterator {  	struct trace_array	*tr;  	struct tracer		*trace;  	void			*private; -	long			last_overrun[NR_CPUS]; -	long			overrun[NR_CPUS]; +	struct ring_buffer_iter	*buffer_iter[NR_CPUS];  	/* The below is zeroed out in pipe_read */  	struct trace_seq	seq;  	struct trace_entry	*ent;  	int			cpu; - -	struct trace_entry	*prev_ent; -	int			prev_cpu; +	u64			ts;  	unsigned long		iter_flags;  	loff_t			pos; -	unsigned long		next_idx[NR_CPUS]; -	struct list_head	*next_page[NR_CPUS]; -	unsigned		next_page_idx[NR_CPUS];  	long			idx;  }; -void tracing_reset(struct trace_array_cpu *data); +void trace_wake_up(void); +void tracing_reset(struct trace_array *tr, int cpu);  int tracing_open_generic(struct inode *inode, struct file *filp);  struct dentry *tracing_init_dentry(void);  void init_tracer_sysprof_debugfs(struct dentry *d_tracer); +struct trace_entry *tracing_get_trace_entry(struct trace_array *tr, +						struct trace_array_cpu *data); +void tracing_generic_entry_update(struct trace_entry *entry, +				  unsigned long flags, +				  int pc); +  void ftrace(struct trace_array *tr,  			    struct trace_array_cpu *data,  			    unsigned long ip,  			    unsigned long parent_ip, -			    unsigned long flags); +			    unsigned long flags, int pc);  void tracing_sched_switch_trace(struct trace_array *tr,  				struct trace_array_cpu *data,  				struct task_struct *prev,  				struct task_struct *next, -				unsigned long flags); +				unsigned long flags, int pc);  void tracing_record_cmdline(struct task_struct *tsk);  void tracing_sched_wakeup_trace(struct trace_array *tr,  				struct trace_array_cpu *data,  				struct task_struct *wakee,  				struct task_struct *cur, -				unsigned long flags); +				unsigned long flags, int pc);  void trace_special(struct trace_array *tr,  		   struct trace_array_cpu *data,  		   unsigned long arg1,  		   unsigned long arg2, -		   unsigned long arg3); +		   unsigned long arg3, int pc);  void trace_function(struct trace_array *tr,  		    struct trace_array_cpu *data,  		    unsigned long ip,  		    unsigned long parent_ip, -		    unsigned long flags); +		    unsigned long flags, int pc);  void tracing_start_cmdline_record(void);  void tracing_stop_cmdline_record(void); @@ -268,51 +364,33 @@ extern unsigned long ftrace_update_tot_cnt;  extern int DYN_FTRACE_TEST_NAME(void);  #endif -#ifdef CONFIG_MMIOTRACE -extern void __trace_mmiotrace_rw(struct trace_array *tr, -				struct trace_array_cpu *data, -				struct mmiotrace_rw *rw); -extern void __trace_mmiotrace_map(struct trace_array *tr, -				struct trace_array_cpu *data, -				struct mmiotrace_map *map); -#endif -  #ifdef CONFIG_FTRACE_STARTUP_TEST -#ifdef CONFIG_FTRACE  extern int trace_selftest_startup_function(struct tracer *trace,  					   struct trace_array *tr); -#endif -#ifdef CONFIG_IRQSOFF_TRACER  extern int trace_selftest_startup_irqsoff(struct tracer *trace,  					  struct trace_array *tr); -#endif -#ifdef CONFIG_PREEMPT_TRACER  extern int trace_selftest_startup_preemptoff(struct tracer *trace,  					     struct trace_array *tr); -#endif -#if defined(CONFIG_IRQSOFF_TRACER) && defined(CONFIG_PREEMPT_TRACER)  extern int trace_selftest_startup_preemptirqsoff(struct tracer *trace,  						 struct trace_array *tr); -#endif -#ifdef CONFIG_SCHED_TRACER  extern int trace_selftest_startup_wakeup(struct tracer *trace,  					 struct trace_array *tr); -#endif -#ifdef CONFIG_CONTEXT_SWITCH_TRACER +extern int trace_selftest_startup_nop(struct tracer *trace, +					 struct trace_array *tr);  extern int trace_selftest_startup_sched_switch(struct tracer *trace,  					       struct trace_array *tr); -#endif -#ifdef CONFIG_SYSPROF_TRACER  extern int trace_selftest_startup_sysprof(struct tracer *trace,  					       struct trace_array *tr); -#endif  #endif /* CONFIG_FTRACE_STARTUP_TEST */  extern void *head_page(struct trace_array_cpu *data);  extern int trace_seq_printf(struct trace_seq *s, const char *fmt, ...); +extern void trace_seq_print_cont(struct trace_seq *s, +				 struct trace_iterator *iter);  extern ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf,  				 size_t cnt);  extern long ns2usecs(cycle_t nsec); +extern int trace_vprintk(unsigned long ip, const char *fmt, va_list args);  extern unsigned long trace_flags; @@ -334,6 +412,9 @@ enum trace_iterator_flags {  	TRACE_ITER_BLOCK		= 0x80,  	TRACE_ITER_STACKTRACE		= 0x100,  	TRACE_ITER_SCHED_TREE		= 0x200, +	TRACE_ITER_PRINTK		= 0x400,  }; +extern struct tracer nop_trace; +  #endif /* _LINUX_KERNEL_TRACE_H */  |