tracing: Add snapshot_raw to extract the raw data from snapshot
Steven Rostedt (Red Hat) [Tue, 5 Mar 2013 21:18:16 +0000 (16:18 -0500)]
Add a 'snapshot_raw' per_cpu file that allows tools to read the raw
binary data of the snapshot buffer.

Signed-off-by: Steven Rostedt <rostedt@goodmis.org>

kernel/trace/trace.c

index 3039326..9bb0b52 100644 (file)
@@ -4206,6 +4206,12 @@ static int tracing_clock_open(struct inode *inode, struct file *file)
        return single_open(file, tracing_clock_show, inode->i_private);
 }
 
+struct ftrace_buffer_info {
+       struct trace_iterator   iter;
+       void                    *spare;
+       unsigned int            read;
+};
+
 #ifdef CONFIG_TRACER_SNAPSHOT
 static int tracing_snapshot_open(struct inode *inode, struct file *file)
 {
@@ -4336,6 +4342,35 @@ static int tracing_snapshot_release(struct inode *inode, struct file *file)
        return 0;
 }
 
+static int tracing_buffers_open(struct inode *inode, struct file *filp);
+static ssize_t tracing_buffers_read(struct file *filp, char __user *ubuf,
+                                   size_t count, loff_t *ppos);
+static int tracing_buffers_release(struct inode *inode, struct file *file);
+static ssize_t tracing_buffers_splice_read(struct file *file, loff_t *ppos,
+                  struct pipe_inode_info *pipe, size_t len, unsigned int flags);
+
+static int snapshot_raw_open(struct inode *inode, struct file *filp)
+{
+       struct ftrace_buffer_info *info;
+       int ret;
+
+       ret = tracing_buffers_open(inode, filp);
+       if (ret < 0)
+               return ret;
+
+       info = filp->private_data;
+
+       if (info->iter.trace->use_max_tr) {
+               tracing_buffers_release(inode, filp);
+               return -EBUSY;
+       }
+
+       info->iter.snapshot = true;
+       info->iter.trace_buffer = &info->iter.tr->max_buffer;
+
+       return ret;
+}
+
 #endif /* CONFIG_TRACER_SNAPSHOT */
 
 
@@ -4402,14 +4437,17 @@ static const struct file_operations snapshot_fops = {
        .llseek         = tracing_seek,
        .release        = tracing_snapshot_release,
 };
-#endif /* CONFIG_TRACER_SNAPSHOT */
 
-struct ftrace_buffer_info {
-       struct trace_iterator   iter;
-       void                    *spare;
-       unsigned int            read;
+static const struct file_operations snapshot_raw_fops = {
+       .open           = snapshot_raw_open,
+       .read           = tracing_buffers_read,
+       .release        = tracing_buffers_release,
+       .splice_read    = tracing_buffers_splice_read,
+       .llseek         = no_llseek,
 };
 
+#endif /* CONFIG_TRACER_SNAPSHOT */
+
 static int tracing_buffers_open(struct inode *inode, struct file *filp)
 {
        struct trace_cpu *tc = inode->i_private;
@@ -4452,16 +4490,26 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
        struct ftrace_buffer_info *info = filp->private_data;
        struct trace_iterator *iter = &info->iter;
        ssize_t ret;
-       size_t size;
+       ssize_t size;
 
        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;
+       }
+#endif
+
        if (!info->spare)
                info->spare = ring_buffer_alloc_read_page(iter->trace_buffer->buffer,
                                                          iter->cpu_file);
+       size = -ENOMEM;
        if (!info->spare)
-               return -ENOMEM;
+               goto out_unlock;
 
        /* Do we have previous read data to read? */
        if (info->read < PAGE_SIZE)
@@ -4477,31 +4525,42 @@ tracing_buffers_read(struct file *filp, char __user *ubuf,
 
        if (ret < 0) {
                if (trace_empty(iter)) {
-                       if ((filp->f_flags & O_NONBLOCK))
-                               return -EAGAIN;
+                       if ((filp->f_flags & O_NONBLOCK)) {
+                               size = -EAGAIN;
+                               goto out_unlock;
+                       }
+                       mutex_unlock(&trace_types_lock);
                        iter->trace->wait_pipe(iter);
-                       if (signal_pending(current))
-                               return -EINTR;
+                       mutex_lock(&trace_types_lock);
+                       if (signal_pending(current)) {
+                               size = -EINTR;
+                               goto out_unlock;
+                       }
                        goto again;
                }
-               return 0;
+               size = 0;
+               goto out_unlock;
        }
 
        info->read = 0;
-
  read:
        size = PAGE_SIZE - info->read;
        if (size > count)
                size = count;
 
        ret = copy_to_user(ubuf, info->spare + info->read, size);
-       if (ret == size)
-               return -EFAULT;
+       if (ret == size) {
+               size = -EFAULT;
+               goto out_unlock;
+       }
        size -= ret;
 
        *ppos += size;
        info->read += size;
 
+ out_unlock:
+       mutex_unlock(&trace_types_lock);
+
        return size;
 }
 
@@ -4591,10 +4650,21 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
        };
        struct buffer_ref *ref;
        int entries, size, i;
-       size_t ret;
+       ssize_t ret;
 
-       if (splice_grow_spd(pipe, &spd))
-               return -ENOMEM;
+       mutex_lock(&trace_types_lock);
+
+#ifdef CONFIG_TRACER_MAX_TRACE
+       if (iter->snapshot && iter->tr->current_trace->use_max_tr) {
+               ret = -EBUSY;
+               goto out;
+       }
+#endif
+
+       if (splice_grow_spd(pipe, &spd)) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
        if (*ppos & (PAGE_SIZE - 1)) {
                ret = -EINVAL;
@@ -4666,7 +4736,9 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
                        ret = -EAGAIN;
                        goto out;
                }
+               mutex_unlock(&trace_types_lock);
                iter->trace->wait_pipe(iter);
+               mutex_lock(&trace_types_lock);
                if (signal_pending(current)) {
                        ret = -EINTR;
                        goto out;
@@ -4677,6 +4749,8 @@ tracing_buffers_splice_read(struct file *file, loff_t *ppos,
        ret = splice_to_pipe(pipe, &spd);
        splice_shrink_spd(&spd);
 out:
+       mutex_unlock(&trace_types_lock);
+
        return ret;
 }
 
@@ -4880,6 +4954,9 @@ tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
 #ifdef CONFIG_TRACER_SNAPSHOT
        trace_create_file("snapshot", 0644, d_cpu,
                          (void *)&data->trace_cpu, &snapshot_fops);
+
+       trace_create_file("snapshot_raw", 0444, d_cpu,
+                       (void *)&data->trace_cpu, &snapshot_raw_fops);
 #endif
 }