diff options
Diffstat (limited to 'kernel/trace/trace.c')
| -rw-r--r-- | kernel/trace/trace.c | 953 | 
1 files changed, 676 insertions, 277 deletions
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 7974ba20557..291397e6666 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -73,7 +73,8 @@ static struct tracer_flags dummy_tracer_flags = {  	.opts = dummy_tracer_opt  }; -static int dummy_set_flag(u32 old_flags, u32 bit, int set) +static int +dummy_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)  {  	return 0;  } @@ -118,7 +119,7 @@ enum ftrace_dump_mode ftrace_dump_on_oops;  /* When set, tracing will stop when a WARN*() is hit */  int __disable_trace_on_warning; -static int tracing_set_tracer(const char *buf); +static int tracing_set_tracer(struct trace_array *tr, const char *buf);  #define MAX_TRACER_SIZE		100  static char bootup_tracer_buf[MAX_TRACER_SIZE] __initdata; @@ -180,6 +181,17 @@ static int __init set_trace_boot_options(char *str)  }  __setup("trace_options=", set_trace_boot_options); +static char trace_boot_clock_buf[MAX_TRACER_SIZE] __initdata; +static char *trace_boot_clock __initdata; + +static int __init set_trace_boot_clock(char *str) +{ +	strlcpy(trace_boot_clock_buf, str, MAX_TRACER_SIZE); +	trace_boot_clock = trace_boot_clock_buf; +	return 0; +} +__setup("trace_clock=", set_trace_boot_clock); +  unsigned long long ns2usecs(cycle_t nsec)  { @@ -235,15 +247,35 @@ void trace_array_put(struct trace_array *this_tr)  	mutex_unlock(&trace_types_lock);  } -int filter_current_check_discard(struct ring_buffer *buffer, -				 struct ftrace_event_call *call, void *rec, -				 struct ring_buffer_event *event) +int filter_check_discard(struct ftrace_event_file *file, void *rec, +			 struct ring_buffer *buffer, +			 struct ring_buffer_event *event)  { -	return filter_check_discard(call, rec, buffer, event); +	if (unlikely(file->flags & FTRACE_EVENT_FL_FILTERED) && +	    !filter_match_preds(file->filter, rec)) { +		ring_buffer_discard_commit(buffer, event); +		return 1; +	} + +	return 0;  } -EXPORT_SYMBOL_GPL(filter_current_check_discard); +EXPORT_SYMBOL_GPL(filter_check_discard); -cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu) +int call_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; +} +EXPORT_SYMBOL_GPL(call_filter_check_discard); + +static cycle_t buffer_ftrace_now(struct trace_buffer *buf, int cpu)  {  	u64 ts; @@ -434,13 +466,22 @@ int __trace_puts(unsigned long ip, const char *str, int size)  	struct print_entry *entry;  	unsigned long irq_flags;  	int alloc; +	int pc; + +	if (!(trace_flags & TRACE_ITER_PRINTK)) +		return 0; + +	pc = preempt_count(); + +	if (unlikely(tracing_selftest_running || tracing_disabled)) +		return 0;  	alloc = sizeof(*entry) + size + 2; /* possible \n added */  	local_save_flags(irq_flags);  	buffer = global_trace.trace_buffer.buffer;  	event = trace_buffer_lock_reserve(buffer, TRACE_PRINT, alloc,  -					  irq_flags, preempt_count()); +					  irq_flags, pc);  	if (!event)  		return 0; @@ -457,6 +498,7 @@ int __trace_puts(unsigned long ip, const char *str, int size)  		entry->buf[size] = '\0';  	__buffer_unlock_commit(buffer, event); +	ftrace_trace_stack(buffer, irq_flags, 4, pc);  	return size;  } @@ -474,11 +516,20 @@ int __trace_bputs(unsigned long ip, const char *str)  	struct bputs_entry *entry;  	unsigned long irq_flags;  	int size = sizeof(struct bputs_entry); +	int pc; + +	if (!(trace_flags & TRACE_ITER_PRINTK)) +		return 0; + +	pc = preempt_count(); + +	if (unlikely(tracing_selftest_running || tracing_disabled)) +		return 0;  	local_save_flags(irq_flags);  	buffer = global_trace.trace_buffer.buffer;  	event = trace_buffer_lock_reserve(buffer, TRACE_BPUTS, size, -					  irq_flags, preempt_count()); +					  irq_flags, pc);  	if (!event)  		return 0; @@ -487,6 +538,7 @@ int __trace_bputs(unsigned long ip, const char *str)  	entry->str			= str;  	__buffer_unlock_commit(buffer, event); +	ftrace_trace_stack(buffer, irq_flags, 4, pc);  	return 1;  } @@ -561,7 +613,7 @@ static int alloc_snapshot(struct trace_array *tr)  	return 0;  } -void free_snapshot(struct trace_array *tr) +static void free_snapshot(struct trace_array *tr)  {  	/*  	 * We don't free the ring buffer. instead, resize it because @@ -575,6 +627,28 @@ void free_snapshot(struct trace_array *tr)  }  /** + * tracing_alloc_snapshot - allocate snapshot buffer. + * + * This only allocates the snapshot buffer if it isn't already + * allocated - it doesn't also take a snapshot. + * + * This is meant to be used in cases where the snapshot buffer needs + * to be set up for events that can't sleep but need to be able to + * trigger a snapshot. + */ +int tracing_alloc_snapshot(void) +{ +	struct trace_array *tr = &global_trace; +	int ret; + +	ret = alloc_snapshot(tr); +	WARN_ON(ret < 0); + +	return ret; +} +EXPORT_SYMBOL_GPL(tracing_alloc_snapshot); + +/**   * trace_snapshot_alloc - allocate and take a snapshot of the current buffer.   *   * This is similar to trace_snapshot(), but it will allocate the @@ -587,11 +661,10 @@ void free_snapshot(struct trace_array *tr)   */  void tracing_snapshot_alloc(void)  { -	struct trace_array *tr = &global_trace;  	int ret; -	ret = alloc_snapshot(tr); -	if (WARN_ON(ret < 0)) +	ret = tracing_alloc_snapshot(); +	if (ret < 0)  		return;  	tracing_snapshot(); @@ -603,6 +676,12 @@ void tracing_snapshot(void)  	WARN_ONCE(1, "Snapshot feature not enabled, but internal snapshot used");  }  EXPORT_SYMBOL_GPL(tracing_snapshot); +int tracing_alloc_snapshot(void) +{ +	WARN_ONCE(1, "Snapshot feature not enabled, but snapshot allocation used"); +	return -ENODEV; +} +EXPORT_SYMBOL_GPL(tracing_alloc_snapshot);  void tracing_snapshot_alloc(void)  {  	/* Give warning */ @@ -744,7 +823,7 @@ static struct {  	{ trace_clock_local,	"local",	1 },  	{ trace_clock_global,	"global",	1 },  	{ trace_clock_counter,	"counter",	0 }, -	{ trace_clock_jiffies,	"uptime",	1 }, +	{ trace_clock_jiffies,	"uptime",	0 },  	{ trace_clock,		"perf",		1 },  	ARCH_TRACE_CLOCKS  }; @@ -843,9 +922,12 @@ int trace_get_user(struct trace_parser *parser, const char __user *ubuf,  	if (isspace(ch)) {  		parser->buffer[parser->idx] = 0;  		parser->cont = false; -	} else { +	} else if (parser->idx < parser->size - 1) {  		parser->cont = true;  		parser->buffer[parser->idx++] = ch; +	} else { +		ret = -EINVAL; +		goto out;  	}  	*ppos += read; @@ -895,27 +977,9 @@ static ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)  	return cnt;  } -/* - * ftrace_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. - */ -static arch_spinlock_t ftrace_max_lock = -	(arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; -  unsigned long __read_mostly	tracing_thresh;  #ifdef CONFIG_TRACER_MAX_TRACE -unsigned long __read_mostly	tracing_max_latency; -  /*   * Copy the new maximum trace into the separate maximum-trace   * structure. (this way the maximum trace is permanently saved, @@ -932,7 +996,7 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)  	max_buf->cpu = cpu;  	max_buf->time_start = data->preempt_timestamp; -	max_data->saved_latency = tracing_max_latency; +	max_data->saved_latency = tr->max_latency;  	max_data->critical_start = data->critical_start;  	max_data->critical_end = data->critical_end; @@ -980,14 +1044,14 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)  		return;  	} -	arch_spin_lock(&ftrace_max_lock); +	arch_spin_lock(&tr->max_lock);  	buf = tr->trace_buffer.buffer;  	tr->trace_buffer.buffer = tr->max_buffer.buffer;  	tr->max_buffer.buffer = buf;  	__update_max_tr(tr, tsk, cpu); -	arch_spin_unlock(&ftrace_max_lock); +	arch_spin_unlock(&tr->max_lock);  }  /** @@ -1013,7 +1077,7 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)  		return;  	} -	arch_spin_lock(&ftrace_max_lock); +	arch_spin_lock(&tr->max_lock);  	ret = ring_buffer_swap_cpu(tr->max_buffer.buffer, tr->trace_buffer.buffer, cpu); @@ -1031,17 +1095,17 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)  	WARN_ON_ONCE(ret && ret != -EAGAIN && ret != -EBUSY);  	__update_max_tr(tr, tsk, cpu); -	arch_spin_unlock(&ftrace_max_lock); +	arch_spin_unlock(&tr->max_lock);  }  #endif /* CONFIG_TRACER_MAX_TRACE */ -static void default_wait_pipe(struct trace_iterator *iter) +static int wait_on_pipe(struct trace_iterator *iter)  {  	/* Iterators are static, they should be filled or empty */  	if (trace_buffer_iter(iter, iter->cpu_file)) -		return; +		return 0; -	ring_buffer_wait(iter->trace_buffer->buffer, iter->cpu_file); +	return ring_buffer_wait(iter->trace_buffer->buffer, iter->cpu_file);  }  #ifdef CONFIG_FTRACE_STARTUP_TEST @@ -1152,8 +1216,6 @@ int register_tracer(struct tracer *type)  	else  		if (!type->flags->opts)  			type->flags->opts = dummy_tracer_opt; -	if (!type->wait_pipe) -		type->wait_pipe = default_wait_pipe;  	ret = run_tracer_selftest(type);  	if (ret < 0) @@ -1174,7 +1236,7 @@ int register_tracer(struct tracer *type)  	printk(KERN_INFO "Starting tracer '%s'\n", type->name);  	/* Do we want this tracer to start on bootup? */ -	tracing_set_tracer(type->name); +	tracing_set_tracer(&global_trace, type->name);  	default_bootup_tracer = NULL;  	/* disable other selftests, since this will break it. */  	tracing_selftest_disabled = true; @@ -1237,42 +1299,76 @@ void tracing_reset_all_online_cpus(void)  	}  } -#define SAVED_CMDLINES 128 +#define SAVED_CMDLINES_DEFAULT 128  #define NO_CMDLINE_MAP UINT_MAX -static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; -static unsigned map_cmdline_to_pid[SAVED_CMDLINES]; -static char saved_cmdlines[SAVED_CMDLINES][TASK_COMM_LEN]; -static int cmdline_idx;  static arch_spinlock_t trace_cmdline_lock = __ARCH_SPIN_LOCK_UNLOCKED; +struct saved_cmdlines_buffer { +	unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1]; +	unsigned *map_cmdline_to_pid; +	unsigned cmdline_num; +	int cmdline_idx; +	char *saved_cmdlines; +}; +static struct saved_cmdlines_buffer *savedcmd;  /* temporary disable recording */  static atomic_t trace_record_cmdline_disabled __read_mostly; -static void trace_init_cmdlines(void) +static inline char *get_saved_cmdlines(int idx)  { -	memset(&map_pid_to_cmdline, NO_CMDLINE_MAP, sizeof(map_pid_to_cmdline)); -	memset(&map_cmdline_to_pid, NO_CMDLINE_MAP, sizeof(map_cmdline_to_pid)); -	cmdline_idx = 0; +	return &savedcmd->saved_cmdlines[idx * TASK_COMM_LEN];  } -int is_tracing_stopped(void) +static inline void set_cmdline(int idx, const char *cmdline)  { -	return global_trace.stop_count; +	memcpy(get_saved_cmdlines(idx), cmdline, TASK_COMM_LEN);  } -/** - * ftrace_off_permanent - disable all ftrace code permanently - * - * This should only be called when a serious anomally has - * been detected.  This will turn off the function tracing, - * ring buffers, and other tracing utilites. It takes no - * locks and can be called from any context. - */ -void ftrace_off_permanent(void) +static int allocate_cmdlines_buffer(unsigned int val, +				    struct saved_cmdlines_buffer *s)  { -	tracing_disabled = 1; -	ftrace_stop(); -	tracing_off_permanent(); +	s->map_cmdline_to_pid = kmalloc(val * sizeof(*s->map_cmdline_to_pid), +					GFP_KERNEL); +	if (!s->map_cmdline_to_pid) +		return -ENOMEM; + +	s->saved_cmdlines = kmalloc(val * TASK_COMM_LEN, GFP_KERNEL); +	if (!s->saved_cmdlines) { +		kfree(s->map_cmdline_to_pid); +		return -ENOMEM; +	} + +	s->cmdline_idx = 0; +	s->cmdline_num = val; +	memset(&s->map_pid_to_cmdline, NO_CMDLINE_MAP, +	       sizeof(s->map_pid_to_cmdline)); +	memset(s->map_cmdline_to_pid, NO_CMDLINE_MAP, +	       val * sizeof(*s->map_cmdline_to_pid)); + +	return 0; +} + +static int trace_create_savedcmd(void) +{ +	int ret; + +	savedcmd = kmalloc(sizeof(*savedcmd), GFP_KERNEL); +	if (!savedcmd) +		return -ENOMEM; + +	ret = allocate_cmdlines_buffer(SAVED_CMDLINES_DEFAULT, savedcmd); +	if (ret < 0) { +		kfree(savedcmd); +		savedcmd = NULL; +		return -ENOMEM; +	} + +	return 0; +} + +int is_tracing_stopped(void) +{ +	return global_trace.stop_count;  }  /** @@ -1300,7 +1396,7 @@ void tracing_start(void)  	}  	/* Prevent the buffers from switching */ -	arch_spin_lock(&ftrace_max_lock); +	arch_spin_lock(&global_trace.max_lock);  	buffer = global_trace.trace_buffer.buffer;  	if (buffer) @@ -1312,9 +1408,8 @@ void tracing_start(void)  		ring_buffer_record_enable(buffer);  #endif -	arch_spin_unlock(&ftrace_max_lock); +	arch_spin_unlock(&global_trace.max_lock); -	ftrace_start();   out:  	raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);  } @@ -1361,13 +1456,12 @@ void tracing_stop(void)  	struct ring_buffer *buffer;  	unsigned long flags; -	ftrace_stop();  	raw_spin_lock_irqsave(&global_trace.start_lock, flags);  	if (global_trace.stop_count++)  		goto out;  	/* Prevent the buffers from switching */ -	arch_spin_lock(&ftrace_max_lock); +	arch_spin_lock(&global_trace.max_lock);  	buffer = global_trace.trace_buffer.buffer;  	if (buffer) @@ -1379,7 +1473,7 @@ void tracing_stop(void)  		ring_buffer_record_disable(buffer);  #endif -	arch_spin_unlock(&ftrace_max_lock); +	arch_spin_unlock(&global_trace.max_lock);   out:  	raw_spin_unlock_irqrestore(&global_trace.start_lock, flags); @@ -1408,12 +1502,12 @@ static void tracing_stop_tr(struct trace_array *tr)  void trace_stop_cmdline_recording(void); -static void trace_save_cmdline(struct task_struct *tsk) +static int trace_save_cmdline(struct task_struct *tsk)  {  	unsigned pid, idx;  	if (!tsk->pid || unlikely(tsk->pid > PID_MAX_DEFAULT)) -		return; +		return 0;  	/*  	 * It's not the end of the world if we don't get @@ -1422,11 +1516,11 @@ static void trace_save_cmdline(struct task_struct *tsk)  	 * so if we miss here, then better luck next time.  	 */  	if (!arch_spin_trylock(&trace_cmdline_lock)) -		return; +		return 0; -	idx = map_pid_to_cmdline[tsk->pid]; +	idx = savedcmd->map_pid_to_cmdline[tsk->pid];  	if (idx == NO_CMDLINE_MAP) { -		idx = (cmdline_idx + 1) % SAVED_CMDLINES; +		idx = (savedcmd->cmdline_idx + 1) % savedcmd->cmdline_num;  		/*  		 * Check whether the cmdline buffer at idx has a pid @@ -1434,22 +1528,24 @@ static void trace_save_cmdline(struct task_struct *tsk)  		 * need to clear the map_pid_to_cmdline. Otherwise we  		 * would read the new comm for the old pid.  		 */ -		pid = map_cmdline_to_pid[idx]; +		pid = savedcmd->map_cmdline_to_pid[idx];  		if (pid != NO_CMDLINE_MAP) -			map_pid_to_cmdline[pid] = NO_CMDLINE_MAP; +			savedcmd->map_pid_to_cmdline[pid] = NO_CMDLINE_MAP; -		map_cmdline_to_pid[idx] = tsk->pid; -		map_pid_to_cmdline[tsk->pid] = idx; +		savedcmd->map_cmdline_to_pid[idx] = tsk->pid; +		savedcmd->map_pid_to_cmdline[tsk->pid] = idx; -		cmdline_idx = idx; +		savedcmd->cmdline_idx = idx;  	} -	memcpy(&saved_cmdlines[idx], tsk->comm, TASK_COMM_LEN); +	set_cmdline(idx, tsk->comm);  	arch_spin_unlock(&trace_cmdline_lock); + +	return 1;  } -void trace_find_cmdline(int pid, char comm[]) +static void __trace_find_cmdline(int pid, char comm[])  {  	unsigned map; @@ -1468,13 +1564,19 @@ void trace_find_cmdline(int pid, char comm[])  		return;  	} -	preempt_disable(); -	arch_spin_lock(&trace_cmdline_lock); -	map = map_pid_to_cmdline[pid]; +	map = savedcmd->map_pid_to_cmdline[pid];  	if (map != NO_CMDLINE_MAP) -		strcpy(comm, saved_cmdlines[map]); +		strcpy(comm, get_saved_cmdlines(map));  	else  		strcpy(comm, "<...>"); +} + +void trace_find_cmdline(int pid, char comm[]) +{ +	preempt_disable(); +	arch_spin_lock(&trace_cmdline_lock); + +	__trace_find_cmdline(pid, comm);  	arch_spin_unlock(&trace_cmdline_lock);  	preempt_enable(); @@ -1488,9 +1590,8 @@ void tracing_record_cmdline(struct task_struct *tsk)  	if (!__this_cpu_read(trace_cmdline_save))  		return; -	__this_cpu_write(trace_cmdline_save, false); - -	trace_save_cmdline(tsk); +	if (trace_save_cmdline(tsk)) +		__this_cpu_write(trace_cmdline_save, false);  }  void @@ -1509,7 +1610,8 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,  #endif  		((pc & HARDIRQ_MASK) ? TRACE_FLAG_HARDIRQ : 0) |  		((pc & SOFTIRQ_MASK) ? TRACE_FLAG_SOFTIRQ : 0) | -		(need_resched() ? TRACE_FLAG_NEED_RESCHED : 0); +		(tif_need_resched() ? TRACE_FLAG_NEED_RESCHED : 0) | +		(test_preempt_need_resched() ? TRACE_FLAG_PREEMPT_RESCHED : 0);  }  EXPORT_SYMBOL_GPL(tracing_generic_entry_update); @@ -1558,15 +1660,31 @@ void trace_buffer_unlock_commit(struct ring_buffer *buffer,  }  EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit); +static struct ring_buffer *temp_buffer; +  struct ring_buffer_event *  trace_event_buffer_lock_reserve(struct ring_buffer **current_rb,  			  struct ftrace_event_file *ftrace_file,  			  int type, unsigned long len,  			  unsigned long flags, int pc)  { +	struct ring_buffer_event *entry; +  	*current_rb = ftrace_file->tr->trace_buffer.buffer; -	return trace_buffer_lock_reserve(*current_rb, +	entry = trace_buffer_lock_reserve(*current_rb,  					 type, len, flags, pc); +	/* +	 * If tracing is off, but we have triggers enabled +	 * we still need to look at the event data. Use the temp_buffer +	 * to store the trace event for the tigger to use. It's recusive +	 * safe and will not be recorded anywhere. +	 */ +	if (!entry && ftrace_file->flags & FTRACE_EVENT_FL_TRIGGER_COND) { +		*current_rb = temp_buffer; +		entry = trace_buffer_lock_reserve(*current_rb, +						  type, len, flags, pc); +	} +	return entry;  }  EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve); @@ -1630,7 +1748,7 @@ trace_function(struct trace_array *tr,  	entry->ip			= ip;  	entry->parent_ip		= parent_ip; -	if (!filter_check_discard(call, entry, buffer, event)) +	if (!call_filter_check_discard(call, entry, buffer, event))  		__buffer_unlock_commit(buffer, event);  } @@ -1676,7 +1794,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,  	 */  	barrier();  	if (use_stack == 1) { -		trace.entries		= &__get_cpu_var(ftrace_stack).calls[0]; +		trace.entries		= this_cpu_ptr(ftrace_stack.calls);  		trace.max_entries	= FTRACE_STACK_MAX_ENTRIES;  		if (regs) @@ -1714,7 +1832,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,  	entry->size = trace.nr_entries; -	if (!filter_check_discard(call, entry, buffer, event)) +	if (!call_filter_check_discard(call, entry, buffer, event))  		__buffer_unlock_commit(buffer, event);   out: @@ -1816,7 +1934,7 @@ ftrace_trace_userstack(struct ring_buffer *buffer, unsigned long flags, int pc)  	trace.entries		= entry->caller;  	save_stack_trace_user(&trace); -	if (!filter_check_discard(call, entry, buffer, event)) +	if (!call_filter_check_discard(call, entry, buffer, event))  		__buffer_unlock_commit(buffer, event);   out_drop_count: @@ -1925,7 +2043,21 @@ void trace_printk_init_buffers(void)  	if (alloc_percpu_trace_buffer())  		return; -	pr_info("ftrace: Allocated trace_printk buffers\n"); +	/* trace_printk() is for debug use only. Don't use it in production. */ + +	pr_warning("\n**********************************************************\n"); +	pr_warning("**   NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE   **\n"); +	pr_warning("**                                                      **\n"); +	pr_warning("** trace_printk() being used. Allocating extra memory.  **\n"); +	pr_warning("**                                                      **\n"); +	pr_warning("** This means that this is a DEBUG kernel and it is     **\n"); +	pr_warning("** unsafe for produciton use.                           **\n"); +	pr_warning("**                                                      **\n"); +	pr_warning("** If you see this message and you are not debugging    **\n"); +	pr_warning("** the kernel, report this immediately to your vendor!  **\n"); +	pr_warning("**                                                      **\n"); +	pr_warning("**   NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE   **\n"); +	pr_warning("**********************************************************\n");  	/* Expand the buffers to set size */  	tracing_update_buffers(); @@ -2008,7 +2140,7 @@ int trace_vbprintk(unsigned long ip, const char *fmt, va_list args)  	entry->fmt			= fmt;  	memcpy(entry->buf, tbuffer, sizeof(u32) * len); -	if (!filter_check_discard(call, entry, buffer, event)) { +	if (!call_filter_check_discard(call, entry, buffer, event)) {  		__buffer_unlock_commit(buffer, event);  		ftrace_trace_stack(buffer, flags, 6, pc);  	} @@ -2063,7 +2195,7 @@ __trace_array_vprintk(struct ring_buffer *buffer,  	memcpy(&entry->buf, tbuffer, len);  	entry->buf[len] = '\0'; -	if (!filter_check_discard(call, entry, buffer, event)) { +	if (!call_filter_check_discard(call, entry, buffer, event)) {  		__buffer_unlock_commit(buffer, event);  		ftrace_trace_stack(buffer, flags, 6, pc);  	} @@ -2760,7 +2892,7 @@ static void show_snapshot_main_help(struct seq_file *m)  	seq_printf(m, "# echo 0 > snapshot : Clears and frees snapshot buffer\n");  	seq_printf(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n");  	seq_printf(m, "#                      Takes a snapshot of the main buffer.\n"); -	seq_printf(m, "# echo 2 > snapshot : Clears snapshot buffer (but does not allocate)\n"); +	seq_printf(m, "# echo 2 > snapshot : Clears snapshot buffer (but does not allocate or free)\n");  	seq_printf(m, "#                      (Doesn't have to be '2' works with any number that\n");  	seq_printf(m, "#                       is not a '0' or '1')\n");  } @@ -2964,6 +3096,11 @@ int tracing_open_generic(struct inode *inode, struct file *filp)  	return 0;  } +bool tracing_is_disabled(void) +{ +	return (tracing_disabled) ? true: false; +} +  /*   * Open and update trace_array ref count.   * Must have the current trace_array passed to it. @@ -3074,27 +3211,52 @@ static int tracing_open(struct inode *inode, struct file *file)  	return ret;  } +/* + * Some tracers are not suitable for instance buffers. + * A tracer is always available for the global array (toplevel) + * or if it explicitly states that it is. + */ +static bool +trace_ok_for_array(struct tracer *t, struct trace_array *tr) +{ +	return (tr->flags & TRACE_ARRAY_FL_GLOBAL) || t->allow_instances; +} + +/* Find the next tracer that this trace array may use */ +static struct tracer * +get_tracer_for_array(struct trace_array *tr, struct tracer *t) +{ +	while (t && !trace_ok_for_array(t, tr)) +		t = t->next; + +	return t; +} +  static void *  t_next(struct seq_file *m, void *v, loff_t *pos)  { +	struct trace_array *tr = m->private;  	struct tracer *t = v;  	(*pos)++;  	if (t) -		t = t->next; +		t = get_tracer_for_array(tr, t->next);  	return t;  }  static void *t_start(struct seq_file *m, loff_t *pos)  { +	struct trace_array *tr = m->private;  	struct tracer *t;  	loff_t l = 0;  	mutex_lock(&trace_types_lock); -	for (t = trace_types; t && l < *pos; t = t_next(m, t, &l)) -		; + +	t = get_tracer_for_array(tr, trace_types); +	for (; t && l < *pos; t = t_next(m, t, &l)) +			;  	return t;  } @@ -3129,10 +3291,21 @@ static const struct seq_operations show_traces_seq_ops = {  static int show_traces_open(struct inode *inode, struct file *file)  { +	struct trace_array *tr = inode->i_private; +	struct seq_file *m; +	int ret; +  	if (tracing_disabled)  		return -ENODEV; -	return seq_open(file, &show_traces_seq_ops); +	ret = seq_open(file, &show_traces_seq_ops); +	if (ret) +		return ret; + +	m = file->private_data; +	m->private = tr; + +	return 0;  }  static ssize_t @@ -3142,19 +3315,23 @@ tracing_write_stub(struct file *filp, const char __user *ubuf,  	return count;  } -static loff_t tracing_seek(struct file *file, loff_t offset, int origin) +loff_t tracing_lseek(struct file *file, loff_t offset, int whence)  { +	int ret; +  	if (file->f_mode & FMODE_READ) -		return seq_lseek(file, offset, origin); +		ret = seq_lseek(file, offset, whence);  	else -		return 0; +		file->f_pos = ret = 0; + +	return ret;  }  static const struct file_operations tracing_fops = {  	.open		= tracing_open,  	.read		= seq_read,  	.write		= tracing_write_stub, -	.llseek		= tracing_seek, +	.llseek		= tracing_lseek,  	.release	= tracing_release,  }; @@ -3218,7 +3395,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,  	mutex_lock(&tracing_cpumask_update_lock);  	local_irq_disable(); -	arch_spin_lock(&ftrace_max_lock); +	arch_spin_lock(&tr->max_lock);  	for_each_tracing_cpu(cpu) {  		/*  		 * Increase/decrease the disabled counter if we are @@ -3235,7 +3412,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,  			ring_buffer_record_enable_cpu(tr->trace_buffer.buffer, cpu);  		}  	} -	arch_spin_unlock(&ftrace_max_lock); +	arch_spin_unlock(&tr->max_lock);  	local_irq_enable();  	cpumask_copy(tr->tracing_cpumask, tracing_cpumask_new); @@ -3288,13 +3465,14 @@ static int tracing_trace_options_show(struct seq_file *m, void *v)  	return 0;  } -static int __set_tracer_option(struct tracer *trace, +static int __set_tracer_option(struct trace_array *tr,  			       struct tracer_flags *tracer_flags,  			       struct tracer_opt *opts, int neg)  { +	struct tracer *trace = tr->current_trace;  	int ret; -	ret = trace->set_flag(tracer_flags->val, opts->bit, !neg); +	ret = trace->set_flag(tr, tracer_flags->val, opts->bit, !neg);  	if (ret)  		return ret; @@ -3306,8 +3484,9 @@ static int __set_tracer_option(struct tracer *trace,  }  /* Try to assign a tracer specific option */ -static int set_tracer_option(struct tracer *trace, char *cmp, int neg) +static int set_tracer_option(struct trace_array *tr, char *cmp, int neg)  { +	struct tracer *trace = tr->current_trace;  	struct tracer_flags *tracer_flags = trace->flags;  	struct tracer_opt *opts = NULL;  	int i; @@ -3316,8 +3495,7 @@ static int set_tracer_option(struct tracer *trace, char *cmp, int neg)  		opts = &tracer_flags->opts[i];  		if (strcmp(cmp, opts->name) == 0) -			return __set_tracer_option(trace, trace->flags, -						   opts, neg); +			return __set_tracer_option(tr, trace->flags, opts, neg);  	}  	return -EINVAL; @@ -3340,7 +3518,7 @@ int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)  	/* Give the tracer a chance to approve the change */  	if (tr->current_trace->flag_changed) -		if (tr->current_trace->flag_changed(tr->current_trace, mask, !!enabled)) +		if (tr->current_trace->flag_changed(tr, mask, !!enabled))  			return -EINVAL;  	if (enabled) @@ -3389,7 +3567,7 @@ static int trace_set_options(struct trace_array *tr, char *option)  	/* If no option could be set, test the specific tracer options */  	if (!trace_options[i]) -		ret = set_tracer_option(tr->current_trace, cmp, neg); +		ret = set_tracer_option(tr, cmp, neg);  	mutex_unlock(&trace_types_lock); @@ -3474,60 +3652,106 @@ static const char readme_msg[] =  	"  instances\t\t- Make sub-buffers with: mkdir instances/foo\n"  	"\t\t\t  Remove sub-buffer with rmdir\n"  	"  trace_options\t\t- Set format or modify how tracing happens\n" -	"\t\t\t  Disable an option by adding a suffix 'no' to the option name\n" +	"\t\t\t  Disable an option by adding a suffix 'no' to the\n" +	"\t\t\t  option name\n" +	"  saved_cmdlines_size\t- echo command number in here to store comm-pid list\n"  #ifdef CONFIG_DYNAMIC_FTRACE  	"\n  available_filter_functions - list of functions that can be filtered on\n" -	"  set_ftrace_filter\t- echo function name in here to only trace these functions\n" -	"            accepts: func_full_name, *func_end, func_begin*, *func_middle*\n" -	"            modules: Can select a group via module\n" -	"             Format: :mod:<module-name>\n" -	"             example: echo :mod:ext3 > set_ftrace_filter\n" -	"            triggers: a command to perform when function is hit\n" -	"              Format: <function>:<trigger>[:count]\n" -	"             trigger: traceon, traceoff\n" -	"                      enable_event:<system>:<event>\n" -	"                      disable_event:<system>:<event>\n" +	"  set_ftrace_filter\t- echo function name in here to only trace these\n" +	"\t\t\t  functions\n" +	"\t     accepts: func_full_name, *func_end, func_begin*, *func_middle*\n" +	"\t     modules: Can select a group via module\n" +	"\t      Format: :mod:<module-name>\n" +	"\t     example: echo :mod:ext3 > set_ftrace_filter\n" +	"\t    triggers: a command to perform when function is hit\n" +	"\t      Format: <function>:<trigger>[:count]\n" +	"\t     trigger: traceon, traceoff\n" +	"\t\t      enable_event:<system>:<event>\n" +	"\t\t      disable_event:<system>:<event>\n"  #ifdef CONFIG_STACKTRACE -	"                      stacktrace\n" +	"\t\t      stacktrace\n"  #endif  #ifdef CONFIG_TRACER_SNAPSHOT -	"                      snapshot\n" +	"\t\t      snapshot\n"  #endif -	"             example: echo do_fault:traceoff > set_ftrace_filter\n" -	"                      echo do_trap:traceoff:3 > set_ftrace_filter\n" -	"             The first one will disable tracing every time do_fault is hit\n" -	"             The second will disable tracing at most 3 times when do_trap is hit\n" -	"               The first time do trap is hit and it disables tracing, the counter\n" -	"               will decrement to 2. If tracing is already disabled, the counter\n" -	"               will not decrement. It only decrements when the trigger did work\n" -	"             To remove trigger without count:\n" -	"               echo '!<function>:<trigger> > set_ftrace_filter\n" -	"             To remove trigger with a count:\n" -	"               echo '!<function>:<trigger>:0 > set_ftrace_filter\n" +	"\t\t      dump\n" +	"\t\t      cpudump\n" +	"\t     example: echo do_fault:traceoff > set_ftrace_filter\n" +	"\t              echo do_trap:traceoff:3 > set_ftrace_filter\n" +	"\t     The first one will disable tracing every time do_fault is hit\n" +	"\t     The second will disable tracing at most 3 times when do_trap is hit\n" +	"\t       The first time do trap is hit and it disables tracing, the\n" +	"\t       counter will decrement to 2. If tracing is already disabled,\n" +	"\t       the counter will not decrement. It only decrements when the\n" +	"\t       trigger did work\n" +	"\t     To remove trigger without count:\n" +	"\t       echo '!<function>:<trigger> > set_ftrace_filter\n" +	"\t     To remove trigger with a count:\n" +	"\t       echo '!<function>:<trigger>:0 > set_ftrace_filter\n"  	"  set_ftrace_notrace\t- echo function name in here to never trace.\n" -	"            accepts: func_full_name, *func_end, func_begin*, *func_middle*\n" -	"            modules: Can select a group via module command :mod:\n" -	"            Does not accept triggers\n" +	"\t    accepts: func_full_name, *func_end, func_begin*, *func_middle*\n" +	"\t    modules: Can select a group via module command :mod:\n" +	"\t    Does not accept triggers\n"  #endif /* CONFIG_DYNAMIC_FTRACE */  #ifdef CONFIG_FUNCTION_TRACER -	"  set_ftrace_pid\t- Write pid(s) to only function trace those pids (function)\n" +	"  set_ftrace_pid\t- Write pid(s) to only function trace those pids\n" +	"\t\t    (function)\n"  #endif  #ifdef CONFIG_FUNCTION_GRAPH_TRACER  	"  set_graph_function\t- Trace the nested calls of a function (function_graph)\n"  	"  max_graph_depth\t- Trace a limited depth of nested calls (0 is unlimited)\n"  #endif  #ifdef CONFIG_TRACER_SNAPSHOT -	"\n  snapshot\t\t- Like 'trace' but shows the content of the static snapshot buffer\n" -	"\t\t\t  Read the contents for more information\n" +	"\n  snapshot\t\t- Like 'trace' but shows the content of the static\n" +	"\t\t\t  snapshot buffer. Read the contents for more\n" +	"\t\t\t  information\n"  #endif  #ifdef CONFIG_STACK_TRACER  	"  stack_trace\t\t- Shows the max stack trace when active\n"  	"  stack_max_size\t- Shows current max stack size that was traced\n" -	"\t\t\t  Write into this file to reset the max size (trigger a new trace)\n" +	"\t\t\t  Write into this file to reset the max size (trigger a\n" +	"\t\t\t  new trace)\n"  #ifdef CONFIG_DYNAMIC_FTRACE -	"  stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace traces\n" +	"  stack_trace_filter\t- Like set_ftrace_filter but limits what stack_trace\n" +	"\t\t\t  traces\n"  #endif  #endif /* CONFIG_STACK_TRACER */ +	"  events/\t\t- Directory containing all trace event subsystems:\n" +	"      enable\t\t- Write 0/1 to enable/disable tracing of all events\n" +	"  events/<system>/\t- Directory containing all trace events for <system>:\n" +	"      enable\t\t- Write 0/1 to enable/disable tracing of all <system>\n" +	"\t\t\t  events\n" +	"      filter\t\t- If set, only events passing filter are traced\n" +	"  events/<system>/<event>/\t- Directory containing control files for\n" +	"\t\t\t  <event>:\n" +	"      enable\t\t- Write 0/1 to enable/disable tracing of <event>\n" +	"      filter\t\t- If set, only events passing filter are traced\n" +	"      trigger\t\t- If set, a command to perform when event is hit\n" +	"\t    Format: <trigger>[:count][if <filter>]\n" +	"\t   trigger: traceon, traceoff\n" +	"\t            enable_event:<system>:<event>\n" +	"\t            disable_event:<system>:<event>\n" +#ifdef CONFIG_STACKTRACE +	"\t\t    stacktrace\n" +#endif +#ifdef CONFIG_TRACER_SNAPSHOT +	"\t\t    snapshot\n" +#endif +	"\t   example: echo traceoff > events/block/block_unplug/trigger\n" +	"\t            echo traceoff:3 > events/block/block_unplug/trigger\n" +	"\t            echo 'enable_event:kmem:kmalloc:3 if nr_rq > 1' > \\\n" +	"\t                  events/block/block_unplug/trigger\n" +	"\t   The first disables tracing every time block_unplug is hit.\n" +	"\t   The second disables tracing the first 3 times block_unplug is hit.\n" +	"\t   The third enables the kmalloc event the first 3 times block_unplug\n" +	"\t     is hit and has value of greater than 1 for the 'nr_rq' event field.\n" +	"\t   Like function triggers, the counter is only decremented if it\n" +	"\t    enabled or disabled tracing.\n" +	"\t   To remove a trigger without a count:\n" +	"\t     echo '!<trigger> > <system>/<event>/trigger\n" +	"\t   To remove a trigger with a count:\n" +	"\t     echo '!<trigger>:0 > <system>/<event>/trigger\n" +	"\t   Filters can be ignored when removing a trigger.\n"  ;  static ssize_t @@ -3544,55 +3768,153 @@ static const struct file_operations tracing_readme_fops = {  	.llseek		= generic_file_llseek,  }; +static void *saved_cmdlines_next(struct seq_file *m, void *v, loff_t *pos) +{ +	unsigned int *ptr = v; + +	if (*pos || m->count) +		ptr++; + +	(*pos)++; + +	for (; ptr < &savedcmd->map_cmdline_to_pid[savedcmd->cmdline_num]; +	     ptr++) { +		if (*ptr == -1 || *ptr == NO_CMDLINE_MAP) +			continue; + +		return ptr; +	} + +	return NULL; +} + +static void *saved_cmdlines_start(struct seq_file *m, loff_t *pos) +{ +	void *v; +	loff_t l = 0; + +	preempt_disable(); +	arch_spin_lock(&trace_cmdline_lock); + +	v = &savedcmd->map_cmdline_to_pid[0]; +	while (l <= *pos) { +		v = saved_cmdlines_next(m, v, &l); +		if (!v) +			return NULL; +	} + +	return v; +} + +static void saved_cmdlines_stop(struct seq_file *m, void *v) +{ +	arch_spin_unlock(&trace_cmdline_lock); +	preempt_enable(); +} + +static int saved_cmdlines_show(struct seq_file *m, void *v) +{ +	char buf[TASK_COMM_LEN]; +	unsigned int *pid = v; + +	__trace_find_cmdline(*pid, buf); +	seq_printf(m, "%d %s\n", *pid, buf); +	return 0; +} + +static const struct seq_operations tracing_saved_cmdlines_seq_ops = { +	.start		= saved_cmdlines_start, +	.next		= saved_cmdlines_next, +	.stop		= saved_cmdlines_stop, +	.show		= saved_cmdlines_show, +}; + +static int tracing_saved_cmdlines_open(struct inode *inode, struct file *filp) +{ +	if (tracing_disabled) +		return -ENODEV; + +	return seq_open(filp, &tracing_saved_cmdlines_seq_ops); +} + +static const struct file_operations tracing_saved_cmdlines_fops = { +	.open		= tracing_saved_cmdlines_open, +	.read		= seq_read, +	.llseek		= seq_lseek, +	.release	= seq_release, +}; +  static ssize_t -tracing_saved_cmdlines_read(struct file *file, char __user *ubuf, -				size_t cnt, loff_t *ppos) +tracing_saved_cmdlines_size_read(struct file *filp, char __user *ubuf, +				 size_t cnt, loff_t *ppos)  { -	char *buf_comm; -	char *file_buf; -	char *buf; -	int len = 0; -	int pid; -	int i; +	char buf[64]; +	int r; + +	arch_spin_lock(&trace_cmdline_lock); +	r = scnprintf(buf, sizeof(buf), "%u\n", savedcmd->cmdline_num); +	arch_spin_unlock(&trace_cmdline_lock); -	file_buf = kmalloc(SAVED_CMDLINES*(16+TASK_COMM_LEN), GFP_KERNEL); -	if (!file_buf) +	return simple_read_from_buffer(ubuf, cnt, ppos, buf, r); +} + +static void free_saved_cmdlines_buffer(struct saved_cmdlines_buffer *s) +{ +	kfree(s->saved_cmdlines); +	kfree(s->map_cmdline_to_pid); +	kfree(s); +} + +static int tracing_resize_saved_cmdlines(unsigned int val) +{ +	struct saved_cmdlines_buffer *s, *savedcmd_temp; + +	s = kmalloc(sizeof(*s), GFP_KERNEL); +	if (!s)  		return -ENOMEM; -	buf_comm = kmalloc(TASK_COMM_LEN, GFP_KERNEL); -	if (!buf_comm) { -		kfree(file_buf); +	if (allocate_cmdlines_buffer(val, s) < 0) { +		kfree(s);  		return -ENOMEM;  	} -	buf = file_buf; +	arch_spin_lock(&trace_cmdline_lock); +	savedcmd_temp = savedcmd; +	savedcmd = s; +	arch_spin_unlock(&trace_cmdline_lock); +	free_saved_cmdlines_buffer(savedcmd_temp); + +	return 0; +} -	for (i = 0; i < SAVED_CMDLINES; i++) { -		int r; +static ssize_t +tracing_saved_cmdlines_size_write(struct file *filp, const char __user *ubuf, +				  size_t cnt, loff_t *ppos) +{ +	unsigned long val; +	int ret; -		pid = map_cmdline_to_pid[i]; -		if (pid == -1 || pid == NO_CMDLINE_MAP) -			continue; +	ret = kstrtoul_from_user(ubuf, cnt, 10, &val); +	if (ret) +		return ret; -		trace_find_cmdline(pid, buf_comm); -		r = sprintf(buf, "%d %s\n", pid, buf_comm); -		buf += r; -		len += r; -	} +	/* must have at least 1 entry or less than PID_MAX_DEFAULT */ +	if (!val || val > PID_MAX_DEFAULT) +		return -EINVAL; -	len = simple_read_from_buffer(ubuf, cnt, ppos, -				      file_buf, len); +	ret = tracing_resize_saved_cmdlines((unsigned int)val); +	if (ret < 0) +		return ret; -	kfree(file_buf); -	kfree(buf_comm); +	*ppos += cnt; -	return len; +	return cnt;  } -static const struct file_operations tracing_saved_cmdlines_fops = { -    .open       = tracing_open_generic, -    .read       = tracing_saved_cmdlines_read, -    .llseek	= generic_file_llseek, +static const struct file_operations tracing_saved_cmdlines_size_fops = { +	.open		= tracing_open_generic, +	.read		= tracing_saved_cmdlines_size_read, +	.write		= tracing_saved_cmdlines_size_write,  };  static ssize_t @@ -3775,10 +4097,26 @@ create_trace_option_files(struct trace_array *tr, struct tracer *tracer);  static void  destroy_trace_option_files(struct trace_option_dentry *topts); -static int tracing_set_tracer(const char *buf) +/* + * Used to clear out the tracer before deletion of an instance. + * Must have trace_types_lock held. + */ +static void tracing_set_nop(struct trace_array *tr) +{ +	if (tr->current_trace == &nop_trace) +		return; +	 +	tr->current_trace->enabled--; + +	if (tr->current_trace->reset) +		tr->current_trace->reset(tr); + +	tr->current_trace = &nop_trace; +} + +static int tracing_set_tracer(struct trace_array *tr, const char *buf)  {  	static struct trace_option_dentry *topts; -	struct trace_array *tr = &global_trace;  	struct tracer *t;  #ifdef CONFIG_TRACER_MAX_TRACE  	bool had_max_tr; @@ -3806,9 +4144,15 @@ static int tracing_set_tracer(const char *buf)  	if (t == tr->current_trace)  		goto out; +	/* Some tracers are only allowed for the top level buffer */ +	if (!trace_ok_for_array(t, tr)) { +		ret = -EINVAL; +		goto out; +	} +  	trace_branch_disable(); -	tr->current_trace->enabled = false; +	tr->current_trace->enabled--;  	if (tr->current_trace->reset)  		tr->current_trace->reset(tr); @@ -3831,9 +4175,11 @@ static int tracing_set_tracer(const char *buf)  		free_snapshot(tr);  	}  #endif -	destroy_trace_option_files(topts); - -	topts = create_trace_option_files(tr, t); +	/* Currently, only the top instance has options */ +	if (tr->flags & TRACE_ARRAY_FL_GLOBAL) { +		destroy_trace_option_files(topts); +		topts = create_trace_option_files(tr, t); +	}  #ifdef CONFIG_TRACER_MAX_TRACE  	if (t->use_max_tr && !had_max_tr) { @@ -3850,7 +4196,7 @@ static int tracing_set_tracer(const char *buf)  	}  	tr->current_trace = t; -	tr->current_trace->enabled = true; +	tr->current_trace->enabled++;  	trace_branch_enable(tr);   out:  	mutex_unlock(&trace_types_lock); @@ -3862,6 +4208,7 @@ static ssize_t  tracing_set_trace_write(struct file *filp, const char __user *ubuf,  			size_t cnt, loff_t *ppos)  { +	struct trace_array *tr = filp->private_data;  	char buf[MAX_TRACER_SIZE+1];  	int i;  	size_t ret; @@ -3881,7 +4228,7 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,  	for (i = cnt - 1; i > 0 && isspace(buf[i]); i--)  		buf[i] = 0; -	err = tracing_set_tracer(buf); +	err = tracing_set_tracer(tr, buf);  	if (err)  		return err; @@ -4039,29 +4386,11 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table)  	return trace_poll(iter, filp, poll_table);  } -/* - * This is a make-shift waitqueue. - * A tracer might use this callback on some rare cases: - * - *  1) the current tracer might hold the runqueue lock when it wakes up - *     a reader, hence a deadlock (sched, function, and function graph tracers) - *  2) the function tracers, trace all functions, we don't want - *     the overhead of calling wake_up and friends - *     (and tracing them too) - * - *     Anyway, this is really very primitive wakeup. - */ -void poll_wait_pipe(struct trace_iterator *iter) -{ -	set_current_state(TASK_INTERRUPTIBLE); -	/* sleep for 100 msecs, and try again. */ -	schedule_timeout(HZ / 10); -} -  /* Must be called with trace_types_lock mutex held. */  static int tracing_wait_pipe(struct file *filp)  {  	struct trace_iterator *iter = filp->private_data; +	int ret;  	while (trace_empty(iter)) { @@ -4069,15 +4398,6 @@ static int tracing_wait_pipe(struct file *filp)  			return -EAGAIN;  		} -		mutex_unlock(&iter->mutex); - -		iter->trace->wait_pipe(iter); - -		mutex_lock(&iter->mutex); - -		if (signal_pending(current)) -			return -EINTR; -  		/*  		 * We block until we read something and tracing is disabled.  		 * We still block if tracing is disabled, but we have never @@ -4089,6 +4409,18 @@ static int tracing_wait_pipe(struct file *filp)  		 */  		if (!tracing_is_on() && iter->pos)  			break; + +		mutex_unlock(&iter->mutex); + +		ret = wait_on_pipe(iter); + +		mutex_lock(&iter->mutex); + +		if (ret) +			return ret; + +		if (signal_pending(current)) +			return -EINTR;  	}  	return 1; @@ -4198,12 +4530,6 @@ out:  	return sret;  } -static void tracing_pipe_buf_release(struct pipe_inode_info *pipe, -				     struct pipe_buffer *buf) -{ -	__free_page(buf->page); -} -  static void tracing_spd_release_pipe(struct splice_pipe_desc *spd,  				     unsigned int idx)  { @@ -4212,10 +4538,8 @@ static void tracing_spd_release_pipe(struct splice_pipe_desc *spd,  static const struct pipe_buf_operations tracing_pipe_buf_ops = {  	.can_merge		= 0, -	.map			= generic_pipe_buf_map, -	.unmap			= generic_pipe_buf_unmap,  	.confirm		= generic_pipe_buf_confirm, -	.release		= tracing_pipe_buf_release, +	.release		= generic_pipe_buf_release,  	.steal			= generic_pipe_buf_steal,  	.get			= generic_pipe_buf_get,  }; @@ -4308,7 +4632,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,  	trace_access_lock(iter->cpu_file);  	/* Fill as many pages as possible. */ -	for (i = 0, rem = len; i < pipe->buffers && rem; i++) { +	for (i = 0, rem = len; i < spd.nr_pages_max && rem; i++) {  		spd.pages[i] = alloc_page(GFP_KERNEL);  		if (!spd.pages[i])  			break; @@ -4595,25 +4919,10 @@ static int tracing_clock_show(struct seq_file *m, void *v)  	return 0;  } -static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf, -				   size_t cnt, loff_t *fpos) +static int tracing_set_clock(struct trace_array *tr, const char *clockstr)  { -	struct seq_file *m = filp->private_data; -	struct trace_array *tr = m->private; -	char buf[64]; -	const char *clockstr;  	int i; -	if (cnt >= sizeof(buf)) -		return -EINVAL; - -	if (copy_from_user(&buf, ubuf, cnt)) -		return -EFAULT; - -	buf[cnt] = 0; - -	clockstr = strstrip(buf); -  	for (i = 0; i < ARRAY_SIZE(trace_clocks); i++) {  		if (strcmp(trace_clocks[i].name, clockstr) == 0)  			break; @@ -4641,6 +4950,32 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,  	mutex_unlock(&trace_types_lock); +	return 0; +} + +static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf, +				   size_t cnt, loff_t *fpos) +{ +	struct seq_file *m = filp->private_data; +	struct trace_array *tr = m->private; +	char buf[64]; +	const char *clockstr; +	int ret; + +	if (cnt >= sizeof(buf)) +		return -EINVAL; + +	if (copy_from_user(&buf, ubuf, cnt)) +		return -EFAULT; + +	buf[cnt] = 0; + +	clockstr = strstrip(buf); + +	ret = tracing_set_clock(tr, clockstr); +	if (ret) +		return ret; +  	*fpos += cnt;  	return cnt; @@ -4899,7 +5234,7 @@ static const struct file_operations snapshot_fops = {  	.open		= tracing_snapshot_open,  	.read		= seq_read,  	.write		= tracing_snapshot_write, -	.llseek		= tracing_seek, +	.llseek		= tracing_lseek,  	.release	= tracing_snapshot_release,  }; @@ -5008,8 +5343,12 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,  				goto out_unlock;  			}  			mutex_unlock(&trace_types_lock); -			iter->trace->wait_pipe(iter); +			ret = wait_on_pipe(iter);  			mutex_lock(&trace_types_lock); +			if (ret) { +				size = ret; +				goto out_unlock; +			}  			if (signal_pending(current)) {  				size = -EINTR;  				goto out_unlock; @@ -5090,8 +5429,6 @@ static void buffer_pipe_buf_get(struct pipe_inode_info *pipe,  /* Pipe buffer operations for a buffer. */  static const struct pipe_buf_operations buffer_pipe_buf_ops = {  	.can_merge		= 0, -	.map			= generic_pipe_buf_map, -	.unmap			= generic_pipe_buf_unmap,  	.confirm		= generic_pipe_buf_confirm,  	.release		= buffer_pipe_buf_release,  	.steal			= generic_pipe_buf_steal, @@ -5167,7 +5504,7 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,  	trace_access_lock(iter->cpu_file);  	entries = ring_buffer_entries_cpu(iter->trace_buffer->buffer, iter->cpu_file); -	for (i = 0; i < pipe->buffers && len && entries; i++, len -= PAGE_SIZE) { +	for (i = 0; i < spd.nr_pages_max && len && entries; i++, len -= PAGE_SIZE) {  		struct page *page;  		int r; @@ -5221,8 +5558,10 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,  			goto out;  		}  		mutex_unlock(&trace_types_lock); -		iter->trace->wait_pipe(iter); +		ret = wait_on_pipe(iter);  		mutex_lock(&trace_types_lock); +		if (ret) +			goto out;  		if (signal_pending(current)) {  			ret = -EINTR;  			goto out; @@ -5454,12 +5793,12 @@ static struct ftrace_func_command ftrace_snapshot_cmd = {  	.func			= ftrace_trace_snapshot_callback,  }; -static int register_snapshot_cmd(void) +static __init int register_snapshot_cmd(void)  {  	return register_ftrace_command(&ftrace_snapshot_cmd);  }  #else -static inline int register_snapshot_cmd(void) { return 0; } +static inline __init int register_snapshot_cmd(void) { return 0; }  #endif /* defined(CONFIG_TRACER_SNAPSHOT) && defined(CONFIG_DYNAMIC_FTRACE) */  struct dentry *tracing_init_dentry_tr(struct trace_array *tr) @@ -5601,7 +5940,7 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt,  	if (!!(topt->flags->val & topt->opt->bit) != val) {  		mutex_lock(&trace_types_lock); -		ret = __set_tracer_option(topt->tr->current_trace, topt->flags, +		ret = __set_tracer_option(topt->tr, topt->flags,  					  topt->opt, !val);  		mutex_unlock(&trace_types_lock);  		if (ret) @@ -5869,6 +6208,8 @@ allocate_trace_buffer(struct trace_array *tr, struct trace_buffer *buf, int size  	rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0; +	buf->tr = tr; +  	buf->buffer = ring_buffer_alloc(size, rb_flags);  	if (!buf->buffer)  		return -ENOMEM; @@ -5913,6 +6254,28 @@ static int allocate_trace_buffers(struct trace_array *tr, int size)  	return 0;  } +static void free_trace_buffer(struct trace_buffer *buf) +{ +	if (buf->buffer) { +		ring_buffer_free(buf->buffer); +		buf->buffer = NULL; +		free_percpu(buf->data); +		buf->data = NULL; +	} +} + +static void free_trace_buffers(struct trace_array *tr) +{ +	if (!tr) +		return; + +	free_trace_buffer(&tr->trace_buffer); + +#ifdef CONFIG_TRACER_MAX_TRACE +	free_trace_buffer(&tr->max_buffer); +#endif +} +  static int new_instance_create(const char *name)  {  	struct trace_array *tr; @@ -5942,6 +6305,8 @@ static int new_instance_create(const char *name)  	raw_spin_lock_init(&tr->start_lock); +	tr->max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; +  	tr->current_trace = &nop_trace;  	INIT_LIST_HEAD(&tr->systems); @@ -5969,8 +6334,7 @@ static int new_instance_create(const char *name)  	return 0;   out_free_tr: -	if (tr->trace_buffer.buffer) -		ring_buffer_free(tr->trace_buffer.buffer); +	free_trace_buffers(tr);  	free_cpumask_var(tr->tracing_cpumask);  	kfree(tr->name);  	kfree(tr); @@ -6006,10 +6370,11 @@ static int instance_delete(const char *name)  	list_del(&tr->list); +	tracing_set_nop(tr);  	event_trace_del_tracer(tr); +	ftrace_destroy_function_files(tr);  	debugfs_remove_recursive(tr->dir); -	free_percpu(tr->trace_buffer.data); -	ring_buffer_free(tr->trace_buffer.buffer); +	free_trace_buffers(tr);  	kfree(tr->name);  	kfree(tr); @@ -6101,6 +6466,12 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)  {  	int cpu; +	trace_create_file("available_tracers", 0444, d_tracer, +			tr, &show_traces_fops); + +	trace_create_file("current_tracer", 0644, d_tracer, +			tr, &set_tracer_fops); +  	trace_create_file("tracing_cpumask", 0644, d_tracer,  			  tr, &tracing_cpumask_fops); @@ -6131,6 +6502,14 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)  	trace_create_file("tracing_on", 0644, d_tracer,  			  tr, &rb_simple_fops); +#ifdef CONFIG_TRACER_MAX_TRACE +	trace_create_file("tracing_max_latency", 0644, d_tracer, +			&tr->max_latency, &tracing_max_lat_fops); +#endif + +	if (ftrace_create_function_files(tr, d_tracer)) +		WARN(1, "Could not allocate function filter files"); +  #ifdef CONFIG_TRACER_SNAPSHOT  	trace_create_file("snapshot", 0644, d_tracer,  			  tr, &snapshot_fops); @@ -6153,17 +6532,6 @@ static __init int tracer_init_debugfs(void)  	init_tracer_debugfs(&global_trace, d_tracer); -	trace_create_file("available_tracers", 0444, d_tracer, -			&global_trace, &show_traces_fops); - -	trace_create_file("current_tracer", 0644, d_tracer, -			&global_trace, &set_tracer_fops); - -#ifdef CONFIG_TRACER_MAX_TRACE -	trace_create_file("tracing_max_latency", 0644, d_tracer, -			&tracing_max_latency, &tracing_max_lat_fops); -#endif -  	trace_create_file("tracing_thresh", 0644, d_tracer,  			&tracing_thresh, &tracing_max_lat_fops); @@ -6173,6 +6541,9 @@ static __init int tracer_init_debugfs(void)  	trace_create_file("saved_cmdlines", 0444, d_tracer,  			NULL, &tracing_saved_cmdlines_fops); +	trace_create_file("saved_cmdlines_size", 0644, d_tracer, +			  NULL, &tracing_saved_cmdlines_size_fops); +  #ifdef CONFIG_DYNAMIC_FTRACE  	trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,  			&ftrace_update_tot_cnt, &tracing_dyn_info_fops); @@ -6253,6 +6624,17 @@ void trace_init_global_iter(struct trace_iterator *iter)  	iter->trace = iter->tr->current_trace;  	iter->cpu_file = RING_BUFFER_ALL_CPUS;  	iter->trace_buffer = &global_trace.trace_buffer; + +	if (iter->trace && iter->trace->open) +		iter->trace->open(iter); + +	/* Annotate start of buffers if we had overruns */ +	if (ring_buffer_overruns(iter->trace_buffer->buffer)) +		iter->iter_flags |= TRACE_FILE_ANNOTATE; + +	/* Output in nanoseconds only if we are using a clock in nanoseconds. */ +	if (trace_clocks[iter->tr->clock_id].in_ns) +		iter->iter_flags |= TRACE_FILE_TIME_IN_NS;  }  void ftrace_dump(enum ftrace_dump_mode oops_dump_mode) @@ -6393,17 +6775,30 @@ __init static int tracer_alloc_buffers(void)  	raw_spin_lock_init(&global_trace.start_lock); +	/* Used for event triggers */ +	temp_buffer = ring_buffer_alloc(PAGE_SIZE, RB_FL_OVERWRITE); +	if (!temp_buffer) +		goto out_free_cpumask; + +	if (trace_create_savedcmd() < 0) +		goto out_free_temp_buffer; +  	/* TODO: make the number of buffers hot pluggable with CPUS */  	if (allocate_trace_buffers(&global_trace, ring_buf_size) < 0) {  		printk(KERN_ERR "tracer: failed to allocate ring buffer!\n");  		WARN_ON(1); -		goto out_free_cpumask; +		goto out_free_savedcmd;  	}  	if (global_trace.buffer_disabled)  		tracing_off(); -	trace_init_cmdlines(); +	if (trace_boot_clock) { +		ret = tracing_set_clock(&global_trace, trace_boot_clock); +		if (ret < 0) +			pr_warning("Trace clock %s not defined, going back to default\n", +				   trace_boot_clock); +	}  	/*  	 * register_tracer() might reference current_trace, so it @@ -6412,6 +6807,10 @@ __init static int tracer_alloc_buffers(void)  	 */  	global_trace.current_trace = &nop_trace; +	global_trace.max_lock = (arch_spinlock_t)__ARCH_SPIN_LOCK_UNLOCKED; + +	ftrace_init_global_array_ops(&global_trace); +  	register_tracer(&nop_trace);  	/* All seems OK, enable tracing */ @@ -6439,11 +6838,11 @@ __init static int tracer_alloc_buffers(void)  	return 0; +out_free_savedcmd: +	free_saved_cmdlines_buffer(savedcmd); +out_free_temp_buffer: +	ring_buffer_free(temp_buffer);  out_free_cpumask: -	free_percpu(global_trace.trace_buffer.data); -#ifdef CONFIG_TRACER_MAX_TRACE -	free_percpu(global_trace.max_buffer.data); -#endif  	free_cpumask_var(global_trace.tracing_cpumask);  out_free_buffer_mask:  	free_cpumask_var(tracing_buffer_mask);  | 
