diff options
Diffstat (limited to 'kernel/trace/trace.c')
| -rw-r--r-- | kernel/trace/trace.c | 194 | 
1 files changed, 82 insertions, 112 deletions
| diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c index 4a9079b9f082..62c6506d663f 100644 --- a/kernel/trace/trace.c +++ b/kernel/trace/trace.c @@ -2036,7 +2036,8 @@ void trace_printk_init_buffers(void)  	/* trace_printk() is for debug use only. Don't use it in production. */ -	pr_warning("\n**********************************************************\n"); +	pr_warning("\n"); +	pr_warning("**********************************************************\n");  	pr_warning("**   NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE NOTICE   **\n");  	pr_warning("**                                                      **\n");  	pr_warning("** trace_printk() being used. Allocating extra memory.  **\n"); @@ -3352,12 +3353,12 @@ tracing_cpumask_read(struct file *filp, char __user *ubuf,  	mutex_lock(&tracing_cpumask_update_lock); -	len = cpumask_scnprintf(mask_str, count, tr->tracing_cpumask); -	if (count - len < 2) { +	len = snprintf(mask_str, count, "%*pb\n", +		       cpumask_pr_args(tr->tracing_cpumask)); +	if (len >= count) {  		count = -EINVAL;  		goto out_err;  	} -	len += sprintf(mask_str + len, "\n");  	count = simple_read_from_buffer(ubuf, count, ppos, mask_str, NR_CPUS+1);  out_err: @@ -4140,6 +4141,12 @@ static int tracing_set_tracer(struct trace_array *tr, const char *buf)  		goto out;  	} +	/* If trace pipe files are being read, we can't change the tracer */ +	if (tr->current_trace->ref) { +		ret = -EBUSY; +		goto out; +	} +  	trace_branch_disable();  	tr->current_trace->enabled--; @@ -4326,17 +4333,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)  	}  	trace_seq_init(&iter->seq); - -	/* -	 * We make a copy of the current tracer to avoid concurrent -	 * changes on it while we are reading. -	 */ -	iter->trace = kmalloc(sizeof(*iter->trace), GFP_KERNEL); -	if (!iter->trace) { -		ret = -ENOMEM; -		goto fail; -	} -	*iter->trace = *tr->current_trace; +	iter->trace = tr->current_trace;  	if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {  		ret = -ENOMEM; @@ -4363,6 +4360,8 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)  		iter->trace->pipe_open(iter);  	nonseekable_open(inode, filp); + +	tr->current_trace->ref++;  out:  	mutex_unlock(&trace_types_lock);  	return ret; @@ -4382,6 +4381,8 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)  	mutex_lock(&trace_types_lock); +	tr->current_trace->ref--; +  	if (iter->trace->pipe_close)  		iter->trace->pipe_close(iter); @@ -4389,7 +4390,6 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)  	free_cpumask_var(iter->started);  	mutex_destroy(&iter->mutex); -	kfree(iter->trace);  	kfree(iter);  	trace_array_put(tr); @@ -4422,7 +4422,7 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table)  	return trace_poll(iter, filp, poll_table);  } -/* Must be called with trace_types_lock mutex held. */ +/* Must be called with iter->mutex held. */  static int tracing_wait_pipe(struct file *filp)  {  	struct trace_iterator *iter = filp->private_data; @@ -4467,7 +4467,6 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,  		  size_t cnt, loff_t *ppos)  {  	struct trace_iterator *iter = filp->private_data; -	struct trace_array *tr = iter->tr;  	ssize_t sret;  	/* return any leftover data */ @@ -4477,12 +4476,6 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,  	trace_seq_init(&iter->seq); -	/* copy the tracer to avoid using a global lock all around */ -	mutex_lock(&trace_types_lock); -	if (unlikely(iter->trace->name != tr->current_trace->name)) -		*iter->trace = *tr->current_trace; -	mutex_unlock(&trace_types_lock); -  	/*  	 * Avoid more than one consumer on a single file descriptor  	 * This is just a matter of traces coherency, the ring buffer itself @@ -4642,7 +4635,6 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,  		.ops		= &tracing_pipe_buf_ops,  		.spd_release	= tracing_spd_release_pipe,  	}; -	struct trace_array *tr = iter->tr;  	ssize_t ret;  	size_t rem;  	unsigned int i; @@ -4650,12 +4642,6 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,  	if (splice_grow_spd(pipe, &spd))  		return -ENOMEM; -	/* copy the tracer to avoid using a global lock all around */ -	mutex_lock(&trace_types_lock); -	if (unlikely(iter->trace->name != tr->current_trace->name)) -		*iter->trace = *tr->current_trace; -	mutex_unlock(&trace_types_lock); -  	mutex_lock(&iter->mutex);  	if (iter->trace->splice_read) { @@ -4942,7 +4928,7 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,  	*fpos += written;   out_unlock: -	for (i = 0; i < nr_pages; i++){ +	for (i = nr_pages - 1; i >= 0; i--) {  		kunmap_atomic(map_page[i]);  		put_page(pages[i]);  	} @@ -5331,6 +5317,8 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)  	filp->private_data = info; +	tr->current_trace->ref++; +  	mutex_unlock(&trace_types_lock);  	ret = nonseekable_open(inode, filp); @@ -5361,21 +5349,16 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,  	if (!count)  		return 0; -	mutex_lock(&trace_types_lock); -  #ifdef CONFIG_TRACER_MAX_TRACE -	if (iter->snapshot && iter->tr->current_trace->use_max_tr) { -		size = -EBUSY; -		goto out_unlock; -	} +	if (iter->snapshot && iter->tr->current_trace->use_max_tr) +		return -EBUSY;  #endif  	if (!info->spare)  		info->spare = ring_buffer_alloc_read_page(iter->trace_buffer->buffer,  							  iter->cpu_file); -	size = -ENOMEM;  	if (!info->spare) -		goto out_unlock; +		return -ENOMEM;  	/* Do we have previous read data to read? */  	if (info->read < PAGE_SIZE) @@ -5391,21 +5374,16 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,  	if (ret < 0) {  		if (trace_empty(iter)) { -			if ((filp->f_flags & O_NONBLOCK)) { -				size = -EAGAIN; -				goto out_unlock; -			} -			mutex_unlock(&trace_types_lock); +			if ((filp->f_flags & O_NONBLOCK)) +				return -EAGAIN; +  			ret = wait_on_pipe(iter, false); -			mutex_lock(&trace_types_lock); -			if (ret) { -				size = ret; -				goto out_unlock; -			} +			if (ret) +				return ret; +  			goto again;  		} -		size = 0; -		goto out_unlock; +		return 0;  	}  	info->read = 0; @@ -5415,18 +5393,14 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,  		size = count;  	ret = copy_to_user(ubuf, info->spare + info->read, size); -	if (ret == size) { -		size = -EFAULT; -		goto out_unlock; -	} +	if (ret == size) +		return -EFAULT; +  	size -= ret;  	*ppos += size;  	info->read += size; - out_unlock: -	mutex_unlock(&trace_types_lock); -  	return size;  } @@ -5437,6 +5411,8 @@ static int tracing_buffers_release(struct inode *inode, struct file *file)  	mutex_lock(&trace_types_lock); +	iter->tr->current_trace->ref--; +  	__trace_array_put(iter->tr);  	if (info->spare) @@ -5522,30 +5498,20 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,  	int entries, size, i;  	ssize_t ret = 0; -	mutex_lock(&trace_types_lock); -  #ifdef CONFIG_TRACER_MAX_TRACE -	if (iter->snapshot && iter->tr->current_trace->use_max_tr) { -		ret = -EBUSY; -		goto out; -	} +	if (iter->snapshot && iter->tr->current_trace->use_max_tr) +		return -EBUSY;  #endif -	if (splice_grow_spd(pipe, &spd)) { -		ret = -ENOMEM; -		goto out; -	} +	if (splice_grow_spd(pipe, &spd)) +		return -ENOMEM; -	if (*ppos & (PAGE_SIZE - 1)) { -		ret = -EINVAL; -		goto out; -	} +	if (*ppos & (PAGE_SIZE - 1)) +		return -EINVAL;  	if (len & (PAGE_SIZE - 1)) { -		if (len < PAGE_SIZE) { -			ret = -EINVAL; -			goto out; -		} +		if (len < PAGE_SIZE) +			return -EINVAL;  		len &= PAGE_MASK;  	} @@ -5606,25 +5572,20 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,  	/* did we read anything? */  	if (!spd.nr_pages) {  		if (ret) -			goto out; +			return ret; + +		if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK)) +			return -EAGAIN; -		if ((file->f_flags & O_NONBLOCK) || (flags & SPLICE_F_NONBLOCK)) { -			ret = -EAGAIN; -			goto out; -		} -		mutex_unlock(&trace_types_lock);  		ret = wait_on_pipe(iter, true); -		mutex_lock(&trace_types_lock);  		if (ret) -			goto out; +			return ret;  		goto again;  	}  	ret = splice_to_pipe(pipe, &spd);  	splice_shrink_spd(&spd); -out: -	mutex_unlock(&trace_types_lock);  	return ret;  } @@ -5854,28 +5815,11 @@ static __init int register_snapshot_cmd(void)  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) +static struct dentry *tracing_get_dentry(struct trace_array *tr)  { -	if (tr->dir) -		return tr->dir; - -	if (!debugfs_initialized()) -		return NULL; - -	if (tr->flags & TRACE_ARRAY_FL_GLOBAL) -		tr->dir = debugfs_create_dir("tracing", NULL); - -	if (!tr->dir) -		pr_warn_once("Could not create debugfs directory 'tracing'\n"); -  	return tr->dir;  } -struct dentry *tracing_init_dentry(void) -{ -	return tracing_init_dentry_tr(&global_trace); -} -  static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu)  {  	struct dentry *d_tracer; @@ -5883,8 +5827,8 @@ static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu)  	if (tr->percpu_dir)  		return tr->percpu_dir; -	d_tracer = tracing_init_dentry_tr(tr); -	if (!d_tracer) +	d_tracer = tracing_get_dentry(tr); +	if (IS_ERR(d_tracer))  		return NULL;  	tr->percpu_dir = debugfs_create_dir("per_cpu", d_tracer); @@ -6086,8 +6030,8 @@ static struct dentry *trace_options_init_dentry(struct trace_array *tr)  	if (tr->options)  		return tr->options; -	d_tracer = tracing_init_dentry_tr(tr); -	if (!d_tracer) +	d_tracer = tracing_get_dentry(tr); +	if (IS_ERR(d_tracer))  		return NULL;  	tr->options = debugfs_create_dir("options", d_tracer); @@ -6416,7 +6360,7 @@ static int instance_delete(const char *name)  		goto out_unlock;  	ret = -EBUSY; -	if (tr->ref) +	if (tr->ref || (tr->current_trace && tr->current_trace->ref))  		goto out_unlock;  	list_del(&tr->list); @@ -6571,6 +6515,33 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)  } +/** + * tracing_init_dentry - initialize top level trace array + * + * This is called when creating files or directories in the tracing + * directory. It is called via fs_initcall() by any of the boot up code + * and expects to return the dentry of the top level tracing directory. + */ +struct dentry *tracing_init_dentry(void) +{ +	struct trace_array *tr = &global_trace; + +	if (tr->dir) +		return tr->dir; + +	if (WARN_ON(!debugfs_initialized())) +		return ERR_PTR(-ENODEV); + +	tr->dir = debugfs_create_dir("tracing", NULL); + +	if (!tr->dir) { +		pr_warn_once("Could not create debugfs directory 'tracing'\n"); +		return ERR_PTR(-ENOMEM); +	} + +	return tr->dir; +} +  static __init int tracer_init_debugfs(void)  {  	struct dentry *d_tracer; @@ -6578,7 +6549,7 @@ static __init int tracer_init_debugfs(void)  	trace_access_lock_init();  	d_tracer = tracing_init_dentry(); -	if (!d_tracer) +	if (IS_ERR(d_tracer))  		return 0;  	init_tracer_debugfs(&global_trace, d_tracer); @@ -6811,7 +6782,6 @@ __init static int tracer_alloc_buffers(void)  	int ring_buf_size;  	int ret = -ENOMEM; -  	if (!alloc_cpumask_var(&tracing_buffer_mask, GFP_KERNEL))  		goto out; |