On Mon, 2013-07-01 at 21:35 -0400, Steven Rostedt wrote:

> > 
> > Is there a better way to fix this problem?
> > 
> > Also unaddressed are all of the other files which use a trace_array,
> > trace_cpu, or ftrace_event_file in their operation - these would need
> > the same fix.
> 
> Hmm, really? Just the initiator. That is, when an event is enabled or
> anything gets opened, we block deletion from happening. That way we
> don't need to care about the rest. Only open and enabling events.

I added two helper functions to handle this. trace_array_get() and
trace_array_put(). This patch prevents your example from crashing.

This probably needs to be added to opening of other files if not already
done.

-- Steve

diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index e36da7f..89a3930 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -204,6 +204,37 @@ static struct trace_array  global_trace;
 
 LIST_HEAD(ftrace_trace_arrays);
 
+int trace_array_get(struct trace_array *this_tr)
+{
+       struct trace_array *tr;
+       int ret = -ENODEV;
+
+       mutex_lock(&trace_types_lock);
+       list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+               if (tr == this_tr) {
+                       tr->ref++;
+                       ret = 0;
+                       break;
+               }
+       }
+       mutex_unlock(&trace_types_lock);
+
+       return ret;
+}
+
+static void __trace_array_put(struct trace_array *this_tr)
+{
+       WARN_ON(!this_tr->ref);
+       this_tr->ref--;
+}
+
+void trace_array_put(struct trace_array *this_tr)
+{
+       mutex_lock(&trace_types_lock);
+       __trace_array_put(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)
@@ -2831,10 +2862,9 @@ static const struct seq_operations tracer_seq_ops = {
 };
 
 static struct trace_iterator *
-__tracing_open(struct inode *inode, struct file *file, bool snapshot)
+__tracing_open(struct trace_array *tr, struct trace_cpu *tc,
+              struct inode *inode, struct file *file, bool snapshot)
 {
-       struct trace_cpu *tc = inode->i_private;
-       struct trace_array *tr = tc->tr;
        struct trace_iterator *iter;
        int cpu;
 
@@ -2913,8 +2943,6 @@ __tracing_open(struct inode *inode, struct file *file, 
bool snapshot)
                tracing_iter_reset(iter, cpu);
        }
 
-       tr->ref++;
-
        mutex_unlock(&trace_types_lock);
 
        return iter;
@@ -2944,17 +2972,20 @@ static int tracing_release(struct inode *inode, struct 
file *file)
        struct trace_array *tr;
        int cpu;
 
-       if (!(file->f_mode & FMODE_READ))
+       /* Writes do not use seq_file, need to grab tr from inode */
+       if (!(file->f_mode & FMODE_READ)) {
+               struct trace_cpu *tc = inode->i_private;
+
+               trace_array_put(tc->tr);
                return 0;
+       }
 
        iter = m->private;
        tr = iter->tr;
+       trace_array_put(tr);
 
        mutex_lock(&trace_types_lock);
 
-       WARN_ON(!tr->ref);
-       tr->ref--;
-
        for_each_tracing_cpu(cpu) {
                if (iter->buffer_iter[cpu])
                        ring_buffer_read_finish(iter->buffer_iter[cpu]);
@@ -2973,20 +3004,23 @@ static int tracing_release(struct inode *inode, struct 
file *file)
        kfree(iter->trace);
        kfree(iter->buffer_iter);
        seq_release_private(inode, file);
+
        return 0;
 }
 
 static int tracing_open(struct inode *inode, struct file *file)
 {
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
        struct trace_iterator *iter;
        int ret = 0;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        /* If this file was open for write, then erase contents */
        if ((file->f_mode & FMODE_WRITE) &&
            (file->f_flags & O_TRUNC)) {
-               struct trace_cpu *tc = inode->i_private;
-               struct trace_array *tr = tc->tr;
-
                if (tc->cpu == RING_BUFFER_ALL_CPUS)
                        tracing_reset_online_cpus(&tr->trace_buffer);
                else
@@ -2994,12 +3028,16 @@ static int tracing_open(struct inode *inode, struct 
file *file)
        }
 
        if (file->f_mode & FMODE_READ) {
-               iter = __tracing_open(inode, file, false);
+               iter = __tracing_open(tr, tc, inode, file, false);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
                else if (trace_flags & TRACE_ITER_LATENCY_FMT)
                        iter->iter_flags |= TRACE_FILE_LAT_FMT;
        }
+
+       if (ret < 0)
+               trace_array_put(tr);
+
        return ret;
 }
 
@@ -4575,12 +4613,16 @@ struct ftrace_buffer_info {
 static int tracing_snapshot_open(struct inode *inode, struct file *file)
 {
        struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
        struct trace_iterator *iter;
        struct seq_file *m;
        int ret = 0;
 
+       if (trace_array_get(tr) < 0)
+               return -ENODEV;
+
        if (file->f_mode & FMODE_READ) {
-               iter = __tracing_open(inode, file, true);
+               iter = __tracing_open(tr, tc, inode, file, true);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
        } else {
@@ -4593,13 +4635,16 @@ static int tracing_snapshot_open(struct inode *inode, 
struct file *file)
                        kfree(m);
                        return -ENOMEM;
                }
-               iter->tr = tc->tr;
+               iter->tr = tr;
                iter->trace_buffer = &tc->tr->max_buffer;
                iter->cpu_file = tc->cpu;
                m->private = iter;
                file->private_data = m;
        }
 
+       if (ret < 0)
+               trace_array_put(tr);
+
        return ret;
 }
 
@@ -4680,9 +4725,12 @@ out:
 static int tracing_snapshot_release(struct inode *inode, struct file *file)
 {
        struct seq_file *m = file->private_data;
+       int ret;
+
+       ret = tracing_release(inode, file);
 
        if (file->f_mode & FMODE_READ)
-               return tracing_release(inode, file);
+               return ret;
 
        /* If write only, the seq_file is just a stub */
        if (m)
@@ -4927,8 +4975,7 @@ static int tracing_buffers_release(struct inode *inode, 
struct file *file)
 
        mutex_lock(&trace_types_lock);
 
-       WARN_ON(!iter->tr->ref);
-       iter->tr->ref--;
+       trace_array_put(iter->tr);
 
        if (info->spare)
                ring_buffer_free_read_page(iter->trace_buffer->buffer, 
info->spare);



--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Reply via email to