diff options
Diffstat (limited to 'kernel/trace/trace.c')
| -rw-r--r-- | kernel/trace/trace.c | 178 | 
1 files changed, 154 insertions, 24 deletions
| diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index a555a861b978..937e9676dfd4 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -49,6 +49,8 @@  #include <linux/irq_work.h>  #include <linux/workqueue.h> +#include <asm/setup.h> /* COMMAND_LINE_SIZE */ +  #include "trace.h"  #include "trace_output.h" @@ -186,6 +188,12 @@ static char *default_bootup_tracer;  static bool allocate_snapshot;  static bool snapshot_at_boot; +static char boot_instance_info[COMMAND_LINE_SIZE] __initdata; +static int boot_instance_index; + +static char boot_snapshot_info[COMMAND_LINE_SIZE] __initdata; +static int boot_snapshot_index; +  static int __init set_cmdline_ftrace(char *str)  {  	strlcpy(bootup_tracer_buf, str, MAX_TRACER_SIZE); @@ -222,9 +230,22 @@ __setup("traceoff_on_warning", stop_trace_on_warning);  static int __init boot_alloc_snapshot(char *str)  { -	allocate_snapshot = true; -	/* We also need the main ring buffer expanded */ -	ring_buffer_expanded = true; +	char *slot = boot_snapshot_info + boot_snapshot_index; +	int left = sizeof(boot_snapshot_info) - boot_snapshot_index; +	int ret; + +	if (str[0] == '=') { +		str++; +		if (strlen(str) >= left) +			return -1; + +		ret = snprintf(slot, left, "%s\t", str); +		boot_snapshot_index += ret; +	} else { +		allocate_snapshot = true; +		/* We also need the main ring buffer expanded */ +		ring_buffer_expanded = true; +	}  	return 1;  }  __setup("alloc_snapshot", boot_alloc_snapshot); @@ -239,6 +260,23 @@ static int __init boot_snapshot(char *str)  __setup("ftrace_boot_snapshot", boot_snapshot); +static int __init boot_instance(char *str) +{ +	char *slot = boot_instance_info + boot_instance_index; +	int left = sizeof(boot_instance_info) - boot_instance_index; +	int ret; + +	if (strlen(str) >= left) +		return -1; + +	ret = snprintf(slot, left, "%s\t", str); +	boot_instance_index += ret; + +	return 1; +} +__setup("trace_instance=", boot_instance); + +  static char trace_boot_options_buf[MAX_TRACER_SIZE] __initdata;  static int __init set_trace_boot_options(char *str) @@ -1001,13 +1039,8 @@ __buffer_unlock_commit(struct trace_buffer *buffer, struct ring_buffer_event *ev  		ring_buffer_unlock_commit(buffer);  } -/** - * __trace_puts - write a constant string into the trace buffer. - * @ip:	   The address of the caller - * @str:   The constant string to write - * @size:  The size of the string. - */ -int __trace_puts(unsigned long ip, const char *str, int size) +int __trace_array_puts(struct trace_array *tr, unsigned long ip, +		       const char *str, int size)  {  	struct ring_buffer_event *event;  	struct trace_buffer *buffer; @@ -1015,7 +1048,7 @@ int __trace_puts(unsigned long ip, const char *str, int size)  	unsigned int trace_ctx;  	int alloc; -	if (!(global_trace.trace_flags & TRACE_ITER_PRINTK)) +	if (!(tr->trace_flags & TRACE_ITER_PRINTK))  		return 0;  	if (unlikely(tracing_selftest_running || tracing_disabled)) @@ -1024,7 +1057,7 @@ int __trace_puts(unsigned long ip, const char *str, int size)  	alloc = sizeof(*entry) + size + 2; /* possible \n added */  	trace_ctx = tracing_gen_ctx(); -	buffer = global_trace.array_buffer.buffer; +	buffer = tr->array_buffer.buffer;  	ring_buffer_nest_start(buffer);  	event = __trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc,  					    trace_ctx); @@ -1046,11 +1079,23 @@ int __trace_puts(unsigned long ip, const char *str, int size)  		entry->buf[size] = '\0';  	__buffer_unlock_commit(buffer, event); -	ftrace_trace_stack(&global_trace, buffer, trace_ctx, 4, NULL); +	ftrace_trace_stack(tr, buffer, trace_ctx, 4, NULL);   out:  	ring_buffer_nest_end(buffer);  	return size;  } +EXPORT_SYMBOL_GPL(__trace_array_puts); + +/** + * __trace_puts - write a constant string into the trace buffer. + * @ip:	   The address of the caller + * @str:   The constant string to write + * @size:  The size of the string. + */ +int __trace_puts(unsigned long ip, const char *str, int size) +{ +	return __trace_array_puts(&global_trace, ip, str, size); +}  EXPORT_SYMBOL_GPL(__trace_puts);  /** @@ -1142,7 +1187,7 @@ void tracing_snapshot_instance(struct trace_array *tr)   *   * Note, make sure to allocate the snapshot with either   * a tracing_snapshot_alloc(), or by doing it manually - * with: echo 1 > /sys/kernel/debug/tracing/snapshot + * with: echo 1 > /sys/kernel/tracing/snapshot   *   * If the snapshot buffer is not allocated, it will stop tracing.   * Basically making a permanent snapshot. @@ -3128,6 +3173,9 @@ void __trace_stack(struct trace_array *tr, unsigned int trace_ctx,  		return;  	} +	if (WARN_ON_ONCE(IS_ENABLED(CONFIG_GENERIC_ENTRY))) +		return; +  	/*  	 * When an NMI triggers, RCU is enabled via ct_nmi_enter(),  	 * but if the above rcu_is_watching() failed, then the NMI @@ -5119,6 +5167,8 @@ loff_t tracing_lseek(struct file *file, loff_t offset, int whence)  static const struct file_operations tracing_fops = {  	.open		= tracing_open,  	.read		= seq_read, +	.read_iter	= seq_read_iter, +	.splice_read	= generic_file_splice_read,  	.write		= tracing_write_stub,  	.llseek		= tracing_lseek,  	.release	= tracing_release, @@ -5598,7 +5648,7 @@ static const char readme_msg[] =  #ifdef CONFIG_HIST_TRIGGERS  	"\t           s:[synthetic/]<event> <field> [<field>]\n"  #endif -	"\t           e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>]\n" +	"\t           e[:[<group>/][<event>]] <attached-group>.<attached-event> [<args>] [if <filter>]\n"  	"\t           -:[<group>/][<event>]\n"  #ifdef CONFIG_KPROBE_EVENTS  	"\t    place: [<module>:]<symbol>[+<offset>]|<memaddr>\n" @@ -5615,7 +5665,7 @@ static const char readme_msg[] =  	"\t           $stack<index>, $stack, $retval, $comm,\n"  #endif  	"\t           +|-[u]<offset>(<fetcharg>), \\imm-value, \\\"imm-string\"\n" -	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, string, symbol,\n" +	"\t     type: s8/16/32/64, u8/16/32/64, x8/16/32/64, char, string, symbol,\n"  	"\t           b<bit-width>@<bit-offset>/<container-size>, ustring,\n"  	"\t           symstr, <type>\\[<array-size>\\]\n"  #ifdef CONFIG_HIST_TRIGGERS @@ -5757,7 +5807,7 @@ static const char readme_msg[] =  #ifdef CONFIG_SYNTH_EVENTS  	"  events/synthetic_events\t- Create/append/remove/show synthetic events\n"  	"\t  Write into this file to define/undefine new synthetic events.\n" -	"\t     example: echo 'myevent u64 lat; char name[]' >> synthetic_events\n" +	"\t     example: echo 'myevent u64 lat; char name[]; long[] stack' >> synthetic_events\n"  #endif  #endif  ; @@ -9148,9 +9198,6 @@ buffer_percent_write(struct file *filp, const char __user *ubuf,  	if (val > 100)  		return -EINVAL; -	if (!val) -		val = 1; -  	tr->buffer_percent = val;  	(*ppos)++; @@ -9225,10 +9272,6 @@ static int allocate_trace_buffers(struct trace_array *tr, int size)  	}  	tr->allocated_snapshot = allocate_snapshot; -	/* -	 * Only the top level trace array gets its snapshot allocated -	 * from the kernel command line. -	 */  	allocate_snapshot = false;  #endif @@ -10144,6 +10187,79 @@ out:  	return ret;  } +#ifdef CONFIG_TRACER_MAX_TRACE +__init static bool tr_needs_alloc_snapshot(const char *name) +{ +	char *test; +	int len = strlen(name); +	bool ret; + +	if (!boot_snapshot_index) +		return false; + +	if (strncmp(name, boot_snapshot_info, len) == 0 && +	    boot_snapshot_info[len] == '\t') +		return true; + +	test = kmalloc(strlen(name) + 3, GFP_KERNEL); +	if (!test) +		return false; + +	sprintf(test, "\t%s\t", name); +	ret = strstr(boot_snapshot_info, test) == NULL; +	kfree(test); +	return ret; +} + +__init static void do_allocate_snapshot(const char *name) +{ +	if (!tr_needs_alloc_snapshot(name)) +		return; + +	/* +	 * When allocate_snapshot is set, the next call to +	 * allocate_trace_buffers() (called by trace_array_get_by_name()) +	 * will allocate the snapshot buffer. That will alse clear +	 * this flag. +	 */ +	allocate_snapshot = true; +} +#else +static inline void do_allocate_snapshot(const char *name) { } +#endif + +__init static void enable_instances(void) +{ +	struct trace_array *tr; +	char *curr_str; +	char *str; +	char *tok; + +	/* A tab is always appended */ +	boot_instance_info[boot_instance_index - 1] = '\0'; +	str = boot_instance_info; + +	while ((curr_str = strsep(&str, "\t"))) { + +		tok = strsep(&curr_str, ","); + +		if (IS_ENABLED(CONFIG_TRACER_MAX_TRACE)) +			do_allocate_snapshot(tok); + +		tr = trace_array_get_by_name(tok); +		if (!tr) { +			pr_warn("Failed to create instance buffer %s\n", curr_str); +			continue; +		} +		/* Allow user space to delete it */ +		trace_array_put(tr); + +		while ((tok = strsep(&curr_str, ","))) { +			early_enable_events(tr, tok, true); +		} +	} +} +  __init static int tracer_alloc_buffers(void)  {  	int ring_buf_size; @@ -10277,10 +10393,19 @@ out:  void __init ftrace_boot_snapshot(void)  { +	struct trace_array *tr; +  	if (snapshot_at_boot) {  		tracing_snapshot();  		internal_trace_puts("** Boot snapshot taken **\n");  	} + +	list_for_each_entry(tr, &ftrace_trace_arrays, list) { +		if (tr == &global_trace) +			continue; +		trace_array_puts(tr, "** Boot snapshot taken **\n"); +		tracing_snapshot_instance(tr); +	}  }  void __init early_trace_init(void) @@ -10295,11 +10420,16 @@ void __init early_trace_init(void)  			static_key_enable(&tracepoint_printk_key.key);  	}  	tracer_alloc_buffers(); + +	init_events();  }  void __init trace_init(void)  {  	trace_event_init(); + +	if (boot_instance_index) +		enable_instances();  }  __init static void clear_boot_tracer(void) |