tracing: Get trace_array ref counts when accessing trace files
When a trace file is opened that may access a trace array, it must increment its ref count to prevent it from being deleted. Cc: stable@vger.kernel.org # 3.10 Reported-by: Alexander Lam <azl@google.com> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
committed by
Steven Rostedt
parent
ff451961a8
commit
7b85af6303
@@ -2965,6 +2965,43 @@ int tracing_open_generic(struct inode *inode, struct file *filp)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Open and update trace_array ref count.
|
||||||
|
* Must have the current trace_array passed to it.
|
||||||
|
*/
|
||||||
|
int tracing_open_generic_tr(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
struct trace_array *tr = inode->i_private;
|
||||||
|
|
||||||
|
if (tracing_disabled)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (trace_array_get(tr) < 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
filp->private_data = inode->i_private;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int tracing_open_generic_tc(struct inode *inode, struct file *filp)
|
||||||
|
{
|
||||||
|
struct trace_cpu *tc = inode->i_private;
|
||||||
|
struct trace_array *tr = tc->tr;
|
||||||
|
|
||||||
|
if (tracing_disabled)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (trace_array_get(tr) < 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
filp->private_data = inode->i_private;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
static int tracing_release(struct inode *inode, struct file *file)
|
static int tracing_release(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct seq_file *m = file->private_data;
|
struct seq_file *m = file->private_data;
|
||||||
@@ -3008,6 +3045,32 @@ static int tracing_release(struct inode *inode, struct file *file)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int tracing_release_generic_tr(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct trace_array *tr = inode->i_private;
|
||||||
|
|
||||||
|
trace_array_put(tr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tracing_release_generic_tc(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct trace_cpu *tc = inode->i_private;
|
||||||
|
struct trace_array *tr = tc->tr;
|
||||||
|
|
||||||
|
trace_array_put(tr);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int tracing_single_release_tr(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
struct trace_array *tr = inode->i_private;
|
||||||
|
|
||||||
|
trace_array_put(tr);
|
||||||
|
|
||||||
|
return single_release(inode, file);
|
||||||
|
}
|
||||||
|
|
||||||
static int tracing_open(struct inode *inode, struct file *file)
|
static int tracing_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct trace_cpu *tc = inode->i_private;
|
struct trace_cpu *tc = inode->i_private;
|
||||||
@@ -3394,9 +3457,14 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
|
|||||||
|
|
||||||
static int tracing_trace_options_open(struct inode *inode, struct file *file)
|
static int tracing_trace_options_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
|
struct trace_array *tr = inode->i_private;
|
||||||
|
|
||||||
if (tracing_disabled)
|
if (tracing_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (trace_array_get(tr) < 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
return single_open(file, tracing_trace_options_show, inode->i_private);
|
return single_open(file, tracing_trace_options_show, inode->i_private);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3404,7 +3472,7 @@ static const struct file_operations tracing_iter_fops = {
|
|||||||
.open = tracing_trace_options_open,
|
.open = tracing_trace_options_open,
|
||||||
.read = seq_read,
|
.read = seq_read,
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = single_release,
|
.release = tracing_single_release_tr,
|
||||||
.write = tracing_trace_options_write,
|
.write = tracing_trace_options_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -3892,6 +3960,9 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
|
|||||||
if (tracing_disabled)
|
if (tracing_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (trace_array_get(tr) < 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
mutex_lock(&trace_types_lock);
|
mutex_lock(&trace_types_lock);
|
||||||
|
|
||||||
/* create a buffer to store the information to pass to userspace */
|
/* create a buffer to store the information to pass to userspace */
|
||||||
@@ -3944,6 +4015,7 @@ out:
|
|||||||
fail:
|
fail:
|
||||||
kfree(iter->trace);
|
kfree(iter->trace);
|
||||||
kfree(iter);
|
kfree(iter);
|
||||||
|
__trace_array_put(tr);
|
||||||
mutex_unlock(&trace_types_lock);
|
mutex_unlock(&trace_types_lock);
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
@@ -3951,6 +4023,8 @@ fail:
|
|||||||
static int tracing_release_pipe(struct inode *inode, struct file *file)
|
static int tracing_release_pipe(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
struct trace_iterator *iter = file->private_data;
|
struct trace_iterator *iter = file->private_data;
|
||||||
|
struct trace_cpu *tc = inode->i_private;
|
||||||
|
struct trace_array *tr = tc->tr;
|
||||||
|
|
||||||
mutex_lock(&trace_types_lock);
|
mutex_lock(&trace_types_lock);
|
||||||
|
|
||||||
@@ -3964,6 +4038,8 @@ static int tracing_release_pipe(struct inode *inode, struct file *file)
|
|||||||
kfree(iter->trace);
|
kfree(iter->trace);
|
||||||
kfree(iter);
|
kfree(iter);
|
||||||
|
|
||||||
|
trace_array_put(tr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4421,6 +4497,8 @@ tracing_free_buffer_release(struct inode *inode, struct file *filp)
|
|||||||
/* resize the ring buffer to 0 */
|
/* resize the ring buffer to 0 */
|
||||||
tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
|
tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
|
||||||
|
|
||||||
|
trace_array_put(tr);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -4597,10 +4675,20 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
|
|||||||
|
|
||||||
static int tracing_clock_open(struct inode *inode, struct file *file)
|
static int tracing_clock_open(struct inode *inode, struct file *file)
|
||||||
{
|
{
|
||||||
|
struct trace_array *tr = inode->i_private;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (tracing_disabled)
|
if (tracing_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
return single_open(file, tracing_clock_show, inode->i_private);
|
if (trace_array_get(tr))
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
|
ret = single_open(file, tracing_clock_show, inode->i_private);
|
||||||
|
if (ret < 0)
|
||||||
|
trace_array_put(tr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ftrace_buffer_info {
|
struct ftrace_buffer_info {
|
||||||
@@ -4796,34 +4884,38 @@ static const struct file_operations tracing_pipe_fops = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations tracing_entries_fops = {
|
static const struct file_operations tracing_entries_fops = {
|
||||||
.open = tracing_open_generic,
|
.open = tracing_open_generic_tc,
|
||||||
.read = tracing_entries_read,
|
.read = tracing_entries_read,
|
||||||
.write = tracing_entries_write,
|
.write = tracing_entries_write,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
|
.release = tracing_release_generic_tc,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations tracing_total_entries_fops = {
|
static const struct file_operations tracing_total_entries_fops = {
|
||||||
.open = tracing_open_generic,
|
.open = tracing_open_generic_tr,
|
||||||
.read = tracing_total_entries_read,
|
.read = tracing_total_entries_read,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
|
.release = tracing_release_generic_tr,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations tracing_free_buffer_fops = {
|
static const struct file_operations tracing_free_buffer_fops = {
|
||||||
|
.open = tracing_open_generic_tr,
|
||||||
.write = tracing_free_buffer_write,
|
.write = tracing_free_buffer_write,
|
||||||
.release = tracing_free_buffer_release,
|
.release = tracing_free_buffer_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations tracing_mark_fops = {
|
static const struct file_operations tracing_mark_fops = {
|
||||||
.open = tracing_open_generic,
|
.open = tracing_open_generic_tr,
|
||||||
.write = tracing_mark_write,
|
.write = tracing_mark_write,
|
||||||
.llseek = generic_file_llseek,
|
.llseek = generic_file_llseek,
|
||||||
|
.release = tracing_release_generic_tr,
|
||||||
};
|
};
|
||||||
|
|
||||||
static const struct file_operations trace_clock_fops = {
|
static const struct file_operations trace_clock_fops = {
|
||||||
.open = tracing_clock_open,
|
.open = tracing_clock_open,
|
||||||
.read = seq_read,
|
.read = seq_read,
|
||||||
.llseek = seq_lseek,
|
.llseek = seq_lseek,
|
||||||
.release = single_release,
|
.release = tracing_single_release_tr,
|
||||||
.write = tracing_clock_write,
|
.write = tracing_clock_write,
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -4851,13 +4943,19 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
|
|||||||
struct trace_cpu *tc = inode->i_private;
|
struct trace_cpu *tc = inode->i_private;
|
||||||
struct trace_array *tr = tc->tr;
|
struct trace_array *tr = tc->tr;
|
||||||
struct ftrace_buffer_info *info;
|
struct ftrace_buffer_info *info;
|
||||||
|
int ret;
|
||||||
|
|
||||||
if (tracing_disabled)
|
if (tracing_disabled)
|
||||||
return -ENODEV;
|
return -ENODEV;
|
||||||
|
|
||||||
|
if (trace_array_get(tr) < 0)
|
||||||
|
return -ENODEV;
|
||||||
|
|
||||||
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
info = kzalloc(sizeof(*info), GFP_KERNEL);
|
||||||
if (!info)
|
if (!info) {
|
||||||
|
trace_array_put(tr);
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
mutex_lock(&trace_types_lock);
|
mutex_lock(&trace_types_lock);
|
||||||
|
|
||||||
@@ -4875,7 +4973,11 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
|
|||||||
|
|
||||||
mutex_unlock(&trace_types_lock);
|
mutex_unlock(&trace_types_lock);
|
||||||
|
|
||||||
return nonseekable_open(inode, filp);
|
ret = nonseekable_open(inode, filp);
|
||||||
|
if (ret < 0)
|
||||||
|
trace_array_put(tr);
|
||||||
|
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned int
|
static unsigned int
|
||||||
@@ -5765,9 +5867,10 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static const struct file_operations rb_simple_fops = {
|
static const struct file_operations rb_simple_fops = {
|
||||||
.open = tracing_open_generic,
|
.open = tracing_open_generic_tr,
|
||||||
.read = rb_simple_read,
|
.read = rb_simple_read,
|
||||||
.write = rb_simple_write,
|
.write = rb_simple_write,
|
||||||
|
.release = tracing_release_generic_tr,
|
||||||
.llseek = default_llseek,
|
.llseek = default_llseek,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user