Commit 6484c71c authored by Oleg Nesterov's avatar Oleg Nesterov Committed by Steven Rostedt

tracing: Change tracing_fops/snapshot_fops to rely on tracing_get_cpu()

tracing_open() and tracing_snapshot_open() are racy, the memory
inode->i_private points to can be already freed.

Convert these last users of "inode->i_private == trace_cpu" to
use "i_private = trace_array" and rely on tracing_get_cpu().

v2: incorporate the fix from Steven, tracing_release() must not
    blindly dereference file->private_data unless we know that
    the file was opened for reading.

Link: http://lkml.kernel.org/r/20130723152610.GA23737@redhat.comSigned-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent 0bc392ee
...@@ -2862,9 +2862,9 @@ static const struct seq_operations tracer_seq_ops = { ...@@ -2862,9 +2862,9 @@ static const struct seq_operations tracer_seq_ops = {
}; };
static struct trace_iterator * static struct trace_iterator *
__tracing_open(struct trace_array *tr, struct trace_cpu *tc, __tracing_open(struct inode *inode, struct file *file, bool snapshot)
struct inode *inode, struct file *file, bool snapshot)
{ {
struct trace_array *tr = inode->i_private;
struct trace_iterator *iter; struct trace_iterator *iter;
int cpu; int cpu;
...@@ -2905,8 +2905,8 @@ __tracing_open(struct trace_array *tr, struct trace_cpu *tc, ...@@ -2905,8 +2905,8 @@ __tracing_open(struct trace_array *tr, struct trace_cpu *tc,
iter->trace_buffer = &tr->trace_buffer; iter->trace_buffer = &tr->trace_buffer;
iter->snapshot = snapshot; iter->snapshot = snapshot;
iter->pos = -1; iter->pos = -1;
iter->cpu_file = tracing_get_cpu(inode);
mutex_init(&iter->mutex); mutex_init(&iter->mutex);
iter->cpu_file = tc->cpu;
/* Notify the tracer early; before we stop tracing. */ /* Notify the tracer early; before we stop tracing. */
if (iter->trace && iter->trace->open) if (iter->trace && iter->trace->open)
...@@ -2986,22 +2986,18 @@ static int tracing_open_generic_tr(struct inode *inode, struct file *filp) ...@@ -2986,22 +2986,18 @@ static int tracing_open_generic_tr(struct inode *inode, struct file *filp)
static int tracing_release(struct inode *inode, struct file *file) static int tracing_release(struct inode *inode, struct file *file)
{ {
struct trace_array *tr = inode->i_private;
struct seq_file *m = file->private_data; struct seq_file *m = file->private_data;
struct trace_iterator *iter; struct trace_iterator *iter;
struct trace_array *tr;
int cpu; int cpu;
/* Writes do not use seq_file, need to grab tr from inode */
if (!(file->f_mode & FMODE_READ)) { if (!(file->f_mode & FMODE_READ)) {
struct trace_cpu *tc = inode->i_private; trace_array_put(tr);
trace_array_put(tc->tr);
return 0; return 0;
} }
/* Writes do not use seq_file */
iter = m->private; iter = m->private;
tr = iter->tr;
mutex_lock(&trace_types_lock); mutex_lock(&trace_types_lock);
for_each_tracing_cpu(cpu) { for_each_tracing_cpu(cpu) {
...@@ -3048,8 +3044,7 @@ static int tracing_single_release_tr(struct inode *inode, struct file *file) ...@@ -3048,8 +3044,7 @@ static int tracing_single_release_tr(struct inode *inode, struct file *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_array *tr = inode->i_private;
struct trace_array *tr = tc->tr;
struct trace_iterator *iter; struct trace_iterator *iter;
int ret = 0; int ret = 0;
...@@ -3057,16 +3052,17 @@ static int tracing_open(struct inode *inode, struct file *file) ...@@ -3057,16 +3052,17 @@ static int tracing_open(struct inode *inode, struct file *file)
return -ENODEV; return -ENODEV;
/* If this file was open for write, then erase contents */ /* If this file was open for write, then erase contents */
if ((file->f_mode & FMODE_WRITE) && if ((file->f_mode & FMODE_WRITE) && (file->f_flags & O_TRUNC)) {
(file->f_flags & O_TRUNC)) { int cpu = tracing_get_cpu(inode);
if (tc->cpu == RING_BUFFER_ALL_CPUS)
if (cpu == RING_BUFFER_ALL_CPUS)
tracing_reset_online_cpus(&tr->trace_buffer); tracing_reset_online_cpus(&tr->trace_buffer);
else else
tracing_reset(&tr->trace_buffer, tc->cpu); tracing_reset(&tr->trace_buffer, cpu);
} }
if (file->f_mode & FMODE_READ) { if (file->f_mode & FMODE_READ) {
iter = __tracing_open(tr, tc, inode, file, false); iter = __tracing_open(inode, file, false);
if (IS_ERR(iter)) if (IS_ERR(iter))
ret = PTR_ERR(iter); ret = PTR_ERR(iter);
else if (trace_flags & TRACE_ITER_LATENCY_FMT) else if (trace_flags & TRACE_ITER_LATENCY_FMT)
...@@ -4680,8 +4676,7 @@ struct ftrace_buffer_info { ...@@ -4680,8 +4676,7 @@ struct ftrace_buffer_info {
#ifdef CONFIG_TRACER_SNAPSHOT #ifdef CONFIG_TRACER_SNAPSHOT
static int tracing_snapshot_open(struct inode *inode, struct file *file) static int tracing_snapshot_open(struct inode *inode, struct file *file)
{ {
struct trace_cpu *tc = inode->i_private; struct trace_array *tr = inode->i_private;
struct trace_array *tr = tc->tr;
struct trace_iterator *iter; struct trace_iterator *iter;
struct seq_file *m; struct seq_file *m;
int ret = 0; int ret = 0;
...@@ -4690,7 +4685,7 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file) ...@@ -4690,7 +4685,7 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
return -ENODEV; return -ENODEV;
if (file->f_mode & FMODE_READ) { if (file->f_mode & FMODE_READ) {
iter = __tracing_open(tr, tc, inode, file, true); iter = __tracing_open(inode, file, true);
if (IS_ERR(iter)) if (IS_ERR(iter))
ret = PTR_ERR(iter); ret = PTR_ERR(iter);
} else { } else {
...@@ -4707,8 +4702,8 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file) ...@@ -4707,8 +4702,8 @@ static int tracing_snapshot_open(struct inode *inode, struct file *file)
ret = 0; ret = 0;
iter->tr = tr; iter->tr = tr;
iter->trace_buffer = &tc->tr->max_buffer; iter->trace_buffer = &tr->max_buffer;
iter->cpu_file = tc->cpu; iter->cpu_file = tracing_get_cpu(inode);
m->private = iter; m->private = iter;
file->private_data = m; file->private_data = m;
} }
...@@ -5525,7 +5520,6 @@ trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent, ...@@ -5525,7 +5520,6 @@ trace_create_cpu_file(const char *name, umode_t mode, struct dentry *parent,
static void static void
tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
{ {
struct trace_array_cpu *data = per_cpu_ptr(tr->trace_buffer.data, cpu);
struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu); struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
struct dentry *d_cpu; struct dentry *d_cpu;
char cpu_dir[30]; /* 30 characters should be more than enough */ char cpu_dir[30]; /* 30 characters should be more than enough */
...@@ -5546,7 +5540,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) ...@@ -5546,7 +5540,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
/* per cpu trace */ /* per cpu trace */
trace_create_cpu_file("trace", 0644, d_cpu, trace_create_cpu_file("trace", 0644, d_cpu,
&data->trace_cpu, cpu, &tracing_fops); tr, cpu, &tracing_fops);
trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu, trace_create_cpu_file("trace_pipe_raw", 0444, d_cpu,
tr, cpu, &tracing_buffers_fops); tr, cpu, &tracing_buffers_fops);
...@@ -5559,7 +5553,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu) ...@@ -5559,7 +5553,7 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
#ifdef CONFIG_TRACER_SNAPSHOT #ifdef CONFIG_TRACER_SNAPSHOT
trace_create_cpu_file("snapshot", 0644, d_cpu, trace_create_cpu_file("snapshot", 0644, d_cpu,
&data->trace_cpu, cpu, &snapshot_fops); tr, cpu, &snapshot_fops);
trace_create_cpu_file("snapshot_raw", 0444, d_cpu, trace_create_cpu_file("snapshot_raw", 0444, d_cpu,
tr, cpu, &snapshot_raw_fops); tr, cpu, &snapshot_raw_fops);
...@@ -6125,7 +6119,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) ...@@ -6125,7 +6119,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
tr, &tracing_iter_fops); tr, &tracing_iter_fops);
trace_create_file("trace", 0644, d_tracer, trace_create_file("trace", 0644, d_tracer,
(void *)&tr->trace_cpu, &tracing_fops); tr, &tracing_fops);
trace_create_file("trace_pipe", 0444, d_tracer, trace_create_file("trace_pipe", 0444, d_tracer,
tr, &tracing_pipe_fops); tr, &tracing_pipe_fops);
...@@ -6150,7 +6144,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer) ...@@ -6150,7 +6144,7 @@ init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
#ifdef CONFIG_TRACER_SNAPSHOT #ifdef CONFIG_TRACER_SNAPSHOT
trace_create_file("snapshot", 0644, d_tracer, trace_create_file("snapshot", 0644, d_tracer,
(void *)&tr->trace_cpu, &snapshot_fops); tr, &snapshot_fops);
#endif #endif
for_each_tracing_cpu(cpu) for_each_tracing_cpu(cpu)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment