tracing: Add interface to allow multiple trace buffers
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / kernel / trace / trace.c
index 3c13e46d7d24e1ecbdeb532f6538354f6eca7ddf..07a63114d938ad30b9b9cb888d20ea08b2eb8191 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * ring buffer based function tracer
  *
- * Copyright (C) 2007-2008 Steven Rostedt <srostedt@redhat.com>
+ * Copyright (C) 2007-2012 Steven Rostedt <srostedt@redhat.com>
  * Copyright (C) 2008 Ingo Molnar <mingo@redhat.com>
  *
  * Originally taken from the RT patch by:
@@ -39,6 +39,7 @@
 #include <linux/poll.h>
 #include <linux/nmi.h>
 #include <linux/fs.h>
+#include <linux/sched/rt.h>
 
 #include "trace.h"
 #include "trace_output.h"
@@ -188,7 +189,7 @@ unsigned long long ns2usecs(cycle_t nsec)
  */
 static struct trace_array      global_trace;
 
-static DEFINE_PER_CPU(struct trace_array_cpu, global_trace_cpu);
+LIST_HEAD(ftrace_trace_arrays);
 
 int filter_current_check_discard(struct ring_buffer *buffer,
                                 struct ftrace_event_call *call, void *rec,
@@ -224,8 +225,6 @@ cycle_t ftrace_now(int cpu)
  */
 static struct trace_array      max_tr;
 
-static DEFINE_PER_CPU(struct trace_array_cpu, max_tr_data);
-
 int tracing_is_enabled(void)
 {
        return tracing_is_on();
@@ -248,9 +247,6 @@ static unsigned long                trace_buf_size = TRACE_BUF_SIZE_DEFAULT;
 /* trace_types holds a link list of available tracers. */
 static struct tracer           *trace_types __read_mostly;
 
-/* current_trace points to the tracer that is currently active */
-static struct tracer           *current_trace __read_mostly;
-
 /*
  * trace_types_lock is used to protect the trace_types list.
  */
@@ -284,13 +280,13 @@ static DEFINE_PER_CPU(struct mutex, cpu_access_lock);
 
 static inline void trace_access_lock(int cpu)
 {
-       if (cpu == TRACE_PIPE_ALL_CPU) {
+       if (cpu == RING_BUFFER_ALL_CPUS) {
                /* gain it for accessing the whole ring buffer. */
                down_write(&all_cpu_access_lock);
        } else {
                /* gain it for accessing a cpu ring buffer. */
 
-               /* Firstly block other trace_access_lock(TRACE_PIPE_ALL_CPU). */
+               /* Firstly block other trace_access_lock(RING_BUFFER_ALL_CPUS). */
                down_read(&all_cpu_access_lock);
 
                /* Secondly block other access to this @cpu ring buffer. */
@@ -300,7 +296,7 @@ static inline void trace_access_lock(int cpu)
 
 static inline void trace_access_unlock(int cpu)
 {
-       if (cpu == TRACE_PIPE_ALL_CPU) {
+       if (cpu == RING_BUFFER_ALL_CPUS) {
                up_write(&all_cpu_access_lock);
        } else {
                mutex_unlock(&per_cpu(cpu_access_lock, cpu));
@@ -347,9 +343,6 @@ unsigned long trace_flags = TRACE_ITER_PRINT_PARENT | TRACE_ITER_PRINTK |
        TRACE_ITER_GRAPH_TIME | TRACE_ITER_RECORD_CMD | TRACE_ITER_OVERWRITE |
        TRACE_ITER_IRQ_INFO | TRACE_ITER_MARKERS;
 
-static int trace_stop_count;
-static DEFINE_RAW_SPINLOCK(tracing_start_lock);
-
 /**
  * trace_wake_up - wake up tasks waiting for trace input
  *
@@ -669,13 +662,13 @@ unsigned long __read_mostly       tracing_max_latency;
 static void
 __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
 {
-       struct trace_array_cpu *data = tr->data[cpu];
+       struct trace_array_cpu *data = per_cpu_ptr(tr->data, cpu);
        struct trace_array_cpu *max_data;
 
        max_tr.cpu = cpu;
        max_tr.time_start = data->preempt_timestamp;
 
-       max_data = max_tr.data[cpu];
+       max_data = per_cpu_ptr(max_tr.data, cpu);
        max_data->saved_latency = tracing_max_latency;
        max_data->critical_start = data->critical_start;
        max_data->critical_end = data->critical_end;
@@ -703,18 +696,22 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
 void
 update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
 {
-       struct ring_buffer *buf = tr->buffer;
+       struct ring_buffer *buf;
 
-       if (trace_stop_count)
+       if (tr->stop_count)
                return;
 
        WARN_ON_ONCE(!irqs_disabled());
-       if (!current_trace->use_max_tr) {
-               WARN_ON_ONCE(1);
+
+       if (!tr->current_trace->allocated_snapshot) {
+               /* Only the nop tracer should hit this when disabling */
+               WARN_ON_ONCE(tr->current_trace != &nop_trace);
                return;
        }
+
        arch_spin_lock(&ftrace_max_lock);
 
+       buf = tr->buffer;
        tr->buffer = max_tr.buffer;
        max_tr.buffer = buf;
 
@@ -735,14 +732,12 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
 {
        int ret;
 
-       if (trace_stop_count)
+       if (tr->stop_count)
                return;
 
        WARN_ON_ONCE(!irqs_disabled());
-       if (!current_trace->use_max_tr) {
-               WARN_ON_ONCE(1);
+       if (WARN_ON_ONCE(!tr->current_trace->allocated_snapshot))
                return;
-       }
 
        arch_spin_lock(&ftrace_max_lock);
 
@@ -848,8 +843,8 @@ int register_tracer(struct tracer *type)
 
 #ifdef CONFIG_FTRACE_STARTUP_TEST
        if (type->selftest && !tracing_selftest_disabled) {
-               struct tracer *saved_tracer = current_trace;
                struct trace_array *tr = &global_trace;
+               struct tracer *saved_tracer = tr->current_trace;
 
                /*
                 * Run a selftest on this tracer.
@@ -860,18 +855,21 @@ int register_tracer(struct tracer *type)
                 */
                tracing_reset_online_cpus(tr);
 
-               current_trace = type;
+               tr->current_trace = type;
 
-               /* If we expanded the buffers, make sure the max is expanded too */
-               if (ring_buffer_expanded && type->use_max_tr)
-                       ring_buffer_resize(max_tr.buffer, trace_buf_size,
-                                               RING_BUFFER_ALL_CPUS);
+               if (type->use_max_tr) {
+                       /* If we expanded the buffers, make sure the max is expanded too */
+                       if (ring_buffer_expanded)
+                               ring_buffer_resize(max_tr.buffer, trace_buf_size,
+                                                  RING_BUFFER_ALL_CPUS);
+                       type->allocated_snapshot = true;
+               }
 
                /* the test is responsible for initializing and enabling */
                pr_info("Testing tracer %s: ", type->name);
                ret = type->selftest(type, tr);
                /* the test is responsible for resetting too */
-               current_trace = saved_tracer;
+               tr->current_trace = saved_tracer;
                if (ret) {
                        printk(KERN_CONT "FAILED!\n");
                        /* Add the warning after printing 'FAILED' */
@@ -881,10 +879,14 @@ int register_tracer(struct tracer *type)
                /* Only reset on passing, to avoid touching corrupted buffers */
                tracing_reset_online_cpus(tr);
 
-               /* Shrink the max buffer again */
-               if (ring_buffer_expanded && type->use_max_tr)
-                       ring_buffer_resize(max_tr.buffer, 1,
-                                               RING_BUFFER_ALL_CPUS);
+               if (type->use_max_tr) {
+                       type->allocated_snapshot = false;
+
+                       /* Shrink the max buffer again */
+                       if (ring_buffer_expanded)
+                               ring_buffer_resize(max_tr.buffer, 1,
+                                                  RING_BUFFER_ALL_CPUS);
+               }
 
                printk(KERN_CONT "PASSED\n");
        }
@@ -922,6 +924,9 @@ void tracing_reset(struct trace_array *tr, int cpu)
 {
        struct ring_buffer *buffer = tr->buffer;
 
+       if (!buffer)
+               return;
+
        ring_buffer_record_disable(buffer);
 
        /* Make sure all commits have finished */
@@ -936,6 +941,9 @@ void tracing_reset_online_cpus(struct trace_array *tr)
        struct ring_buffer *buffer = tr->buffer;
        int cpu;
 
+       if (!buffer)
+               return;
+
        ring_buffer_record_disable(buffer);
 
        /* Make sure all commits have finished */
@@ -979,7 +987,7 @@ static void trace_init_cmdlines(void)
 
 int is_tracing_stopped(void)
 {
-       return trace_stop_count;
+       return global_trace.stop_count;
 }
 
 /**
@@ -1011,12 +1019,12 @@ void tracing_start(void)
        if (tracing_disabled)
                return;
 
-       raw_spin_lock_irqsave(&tracing_start_lock, flags);
-       if (--trace_stop_count) {
-               if (trace_stop_count < 0) {
+       raw_spin_lock_irqsave(&global_trace.start_lock, flags);
+       if (--global_trace.stop_count) {
+               if (global_trace.stop_count < 0) {
                        /* Someone screwed up their debugging */
                        WARN_ON_ONCE(1);
-                       trace_stop_count = 0;
+                       global_trace.stop_count = 0;
                }
                goto out;
        }
@@ -1036,7 +1044,38 @@ void tracing_start(void)
 
        ftrace_start();
  out:
-       raw_spin_unlock_irqrestore(&tracing_start_lock, flags);
+       raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);
+}
+
+static void tracing_start_tr(struct trace_array *tr)
+{
+       struct ring_buffer *buffer;
+       unsigned long flags;
+
+       if (tracing_disabled)
+               return;
+
+       /* If global, we need to also start the max tracer */
+       if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
+               return tracing_start();
+
+       raw_spin_lock_irqsave(&tr->start_lock, flags);
+
+       if (--tr->stop_count) {
+               if (tr->stop_count < 0) {
+                       /* Someone screwed up their debugging */
+                       WARN_ON_ONCE(1);
+                       tr->stop_count = 0;
+               }
+               goto out;
+       }
+
+       buffer = tr->buffer;
+       if (buffer)
+               ring_buffer_record_enable(buffer);
+
+ out:
+       raw_spin_unlock_irqrestore(&tr->start_lock, flags);
 }
 
 /**
@@ -1051,8 +1090,8 @@ void tracing_stop(void)
        unsigned long flags;
 
        ftrace_stop();
-       raw_spin_lock_irqsave(&tracing_start_lock, flags);
-       if (trace_stop_count++)
+       raw_spin_lock_irqsave(&global_trace.start_lock, flags);
+       if (global_trace.stop_count++)
                goto out;
 
        /* Prevent the buffers from switching */
@@ -1069,7 +1108,28 @@ void tracing_stop(void)
        arch_spin_unlock(&ftrace_max_lock);
 
  out:
-       raw_spin_unlock_irqrestore(&tracing_start_lock, flags);
+       raw_spin_unlock_irqrestore(&global_trace.start_lock, flags);
+}
+
+static void tracing_stop_tr(struct trace_array *tr)
+{
+       struct ring_buffer *buffer;
+       unsigned long flags;
+
+       /* If global, we need to also stop the max tracer */
+       if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
+               return tracing_stop();
+
+       raw_spin_lock_irqsave(&tr->start_lock, flags);
+       if (tr->stop_count++)
+               goto out;
+
+       buffer = tr->buffer;
+       if (buffer)
+               ring_buffer_record_disable(buffer);
+
+ out:
+       raw_spin_unlock_irqrestore(&tr->start_lock, flags);
 }
 
 void trace_stop_cmdline_recording(void);
@@ -1167,7 +1227,6 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
 
        entry->preempt_count            = pc & 0xff;
        entry->pid                      = (tsk) ? tsk->pid : 0;
-       entry->padding                  = 0;
        entry->flags =
 #ifdef CONFIG_TRACE_IRQFLAGS_SUPPORT
                (irqs_disabled_flags(flags) ? TRACE_FLAG_IRQS_OFF : 0) |
@@ -1230,6 +1289,18 @@ void trace_buffer_unlock_commit(struct ring_buffer *buffer,
 }
 EXPORT_SYMBOL_GPL(trace_buffer_unlock_commit);
 
+struct ring_buffer_event *
+trace_event_buffer_lock_reserve(struct ring_buffer **current_rb,
+                         struct ftrace_event_file *ftrace_file,
+                         int type, unsigned long len,
+                         unsigned long flags, int pc)
+{
+       *current_rb = ftrace_file->tr->buffer;
+       return trace_buffer_lock_reserve(*current_rb,
+                                        type, len, flags, pc);
+}
+EXPORT_SYMBOL_GPL(trace_event_buffer_lock_reserve);
+
 struct ring_buffer_event *
 trace_current_buffer_lock_reserve(struct ring_buffer **current_rb,
                                  int type, unsigned long len,
@@ -1335,7 +1406,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,
         */
        preempt_disable_notrace();
 
-       use_stack = ++__get_cpu_var(ftrace_stack_reserve);
+       use_stack = __this_cpu_inc_return(ftrace_stack_reserve);
        /*
         * We don't need any atomic variables, just a barrier.
         * If an interrupt comes in, we don't care, because it would
@@ -1389,7 +1460,7 @@ static void __ftrace_trace_stack(struct ring_buffer *buffer,
  out:
        /* Again, don't let gcc optimize things here */
        barrier();
-       __get_cpu_var(ftrace_stack_reserve)--;
+       __this_cpu_dec(ftrace_stack_reserve);
        preempt_enable_notrace();
 
 }
@@ -1517,7 +1588,6 @@ static struct trace_buffer_struct *trace_percpu_nmi_buffer;
 static char *get_trace_buf(void)
 {
        struct trace_buffer_struct *percpu_buffer;
-       struct trace_buffer_struct *buffer;
 
        /*
         * If we have allocated per cpu buffers, then we do not
@@ -1535,9 +1605,7 @@ static char *get_trace_buf(void)
        if (!percpu_buffer)
                return NULL;
 
-       buffer = per_cpu_ptr(percpu_buffer, smp_processor_id());
-
-       return buffer->buffer;
+       return this_cpu_ptr(&percpu_buffer->buffer[0]);
 }
 
 static int alloc_percpu_trace_buffer(void)
@@ -1809,7 +1877,7 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu,
         * If we are in a per_cpu trace file, don't bother by iterating over
         * all cpu and peek directly.
         */
-       if (cpu_file > TRACE_PIPE_ALL_CPU) {
+       if (cpu_file > RING_BUFFER_ALL_CPUS) {
                if (ring_buffer_empty_cpu(buffer, cpu_file))
                        return NULL;
                ent = peek_next_entry(iter, cpu_file, ent_ts, missing_events);
@@ -1912,7 +1980,7 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
        unsigned long entries = 0;
        u64 ts;
 
-       tr->data[cpu]->skipped_entries = 0;
+       per_cpu_ptr(tr->data, cpu)->skipped_entries = 0;
 
        buf_iter = trace_buffer_iter(iter, cpu);
        if (!buf_iter)
@@ -1932,7 +2000,7 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
                ring_buffer_read(buf_iter, NULL);
        }
 
-       tr->data[cpu]->skipped_entries = entries;
+       per_cpu_ptr(tr->data, cpu)->skipped_entries = entries;
 }
 
 /*
@@ -1942,28 +2010,35 @@ void tracing_iter_reset(struct trace_iterator *iter, int cpu)
 static void *s_start(struct seq_file *m, loff_t *pos)
 {
        struct trace_iterator *iter = m->private;
-       static struct tracer *old_tracer;
+       struct trace_array *tr = iter->tr;
        int cpu_file = iter->cpu_file;
        void *p = NULL;
        loff_t l = 0;
        int cpu;
 
-       /* copy the tracer to avoid using a global lock all around */
+       /*
+        * copy the tracer to avoid using a global lock all around.
+        * iter->trace is a copy of current_trace, the pointer to the
+        * name may be used instead of a strcmp(), as iter->trace->name
+        * will point to the same string as current_trace->name.
+        */
        mutex_lock(&trace_types_lock);
-       if (unlikely(old_tracer != current_trace && current_trace)) {
-               old_tracer = current_trace;
-               *iter->trace = *current_trace;
-       }
+       if (unlikely(tr->current_trace && iter->trace->name != tr->current_trace->name))
+               *iter->trace = *tr->current_trace;
        mutex_unlock(&trace_types_lock);
 
-       atomic_inc(&trace_record_cmdline_disabled);
+       if (iter->snapshot && iter->trace->use_max_tr)
+               return ERR_PTR(-EBUSY);
+
+       if (!iter->snapshot)
+               atomic_inc(&trace_record_cmdline_disabled);
 
        if (*pos != iter->pos) {
                iter->ent = NULL;
                iter->cpu = 0;
                iter->idx = -1;
 
-               if (cpu_file == TRACE_PIPE_ALL_CPU) {
+               if (cpu_file == RING_BUFFER_ALL_CPUS) {
                        for_each_tracing_cpu(cpu)
                                tracing_iter_reset(iter, cpu);
                } else
@@ -1995,7 +2070,11 @@ static void s_stop(struct seq_file *m, void *p)
 {
        struct trace_iterator *iter = m->private;
 
-       atomic_dec(&trace_record_cmdline_disabled);
+       if (iter->snapshot && iter->trace->use_max_tr)
+               return;
+
+       if (!iter->snapshot)
+               atomic_dec(&trace_record_cmdline_disabled);
        trace_access_unlock(iter->cpu_file);
        trace_event_read_unlock();
 }
@@ -2016,8 +2095,8 @@ get_total_entries(struct trace_array *tr, unsigned long *total, unsigned long *e
                 * entries for the trace and we need to ignore the
                 * ones before the time stamp.
                 */
-               if (tr->data[cpu]->skipped_entries) {
-                       count -= tr->data[cpu]->skipped_entries;
+               if (per_cpu_ptr(tr->data, cpu)->skipped_entries) {
+                       count -= per_cpu_ptr(tr->data, cpu)->skipped_entries;
                        /* total is the same as the entries */
                        *total += count;
                } else
@@ -2074,14 +2153,13 @@ print_trace_header(struct seq_file *m, struct trace_iterator *iter)
 {
        unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
        struct trace_array *tr = iter->tr;
-       struct trace_array_cpu *data = tr->data[tr->cpu];
-       struct tracer *type = current_trace;
+       struct trace_array_cpu *data = per_cpu_ptr(tr->data, tr->cpu);
+       struct tracer *type = iter->trace;
        unsigned long entries;
        unsigned long total;
        const char *name = "preemption";
 
-       if (type)
-               name = type->name;
+       name = type->name;
 
        get_total_entries(tr, &total, &entries);
 
@@ -2145,7 +2223,7 @@ static void test_cpu_buff_start(struct trace_iterator *iter)
        if (cpumask_test_cpu(iter->cpu, iter->started))
                return;
 
-       if (iter->tr->data[iter->cpu]->skipped_entries)
+       if (per_cpu_ptr(iter->tr->data, iter->cpu)->skipped_entries)
                return;
 
        cpumask_set_cpu(iter->cpu, iter->started);
@@ -2268,7 +2346,7 @@ int trace_empty(struct trace_iterator *iter)
        int cpu;
 
        /* If we are looking at one CPU buffer, only check that one */
-       if (iter->cpu_file != TRACE_PIPE_ALL_CPU) {
+       if (iter->cpu_file != RING_BUFFER_ALL_CPUS) {
                cpu = iter->cpu_file;
                buf_iter = trace_buffer_iter(iter, cpu);
                if (buf_iter) {
@@ -2380,6 +2458,27 @@ static void test_ftrace_alive(struct seq_file *m)
        seq_printf(m, "#          MAY BE MISSING FUNCTION EVENTS\n");
 }
 
+#ifdef CONFIG_TRACER_MAX_TRACE
+static void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter)
+{
+       if (iter->trace->allocated_snapshot)
+               seq_printf(m, "#\n# * Snapshot is allocated *\n#\n");
+       else
+               seq_printf(m, "#\n# * Snapshot is freed *\n#\n");
+
+       seq_printf(m, "# Snapshot commands:\n");
+       seq_printf(m, "# echo 0 > snapshot : Clears and frees snapshot buffer\n");
+       seq_printf(m, "# echo 1 > snapshot : Allocates snapshot buffer, if not already allocated.\n");
+       seq_printf(m, "#                      Takes a snapshot of the main buffer.\n");
+       seq_printf(m, "# echo 2 > snapshot : Clears snapshot buffer (but does not allocate)\n");
+       seq_printf(m, "#                      (Doesn't have to be '2' works with any number that\n");
+       seq_printf(m, "#                       is not a '0' or '1')\n");
+}
+#else
+/* Should never be called */
+static inline void print_snapshot_help(struct seq_file *m, struct trace_iterator *iter) { }
+#endif
+
 static int s_show(struct seq_file *m, void *v)
 {
        struct trace_iterator *iter = v;
@@ -2391,7 +2490,9 @@ static int s_show(struct seq_file *m, void *v)
                        seq_puts(m, "#\n");
                        test_ftrace_alive(m);
                }
-               if (iter->trace && iter->trace->print_header)
+               if (iter->snapshot && trace_empty(iter))
+                       print_snapshot_help(m, iter);
+               else if (iter->trace && iter->trace->print_header)
                        iter->trace->print_header(m);
                else
                        trace_default_header(m);
@@ -2430,9 +2531,10 @@ static const struct seq_operations tracer_seq_ops = {
 };
 
 static struct trace_iterator *
-__tracing_open(struct inode *inode, struct file *file)
+__tracing_open(struct inode *inode, struct file *file, bool snapshot)
 {
-       long cpu_file = (long) inode->i_private;
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
        struct trace_iterator *iter;
        int cpu;
 
@@ -2457,19 +2559,20 @@ __tracing_open(struct inode *inode, struct file *file)
        if (!iter->trace)
                goto fail;
 
-       if (current_trace)
-               *iter->trace = *current_trace;
+       *iter->trace = *tr->current_trace;
 
        if (!zalloc_cpumask_var(&iter->started, GFP_KERNEL))
                goto fail;
 
-       if (current_trace && current_trace->print_max)
+       /* Currently only the top directory has a snapshot */
+       if (tr->current_trace->print_max || snapshot)
                iter->tr = &max_tr;
        else
-               iter->tr = &global_trace;
+               iter->tr = tr;
+       iter->snapshot = snapshot;
        iter->pos = -1;
        mutex_init(&iter->mutex);
-       iter->cpu_file = cpu_file;
+       iter->cpu_file = tc->cpu;
 
        /* Notify the tracer early; before we stop tracing. */
        if (iter->trace && iter->trace->open)
@@ -2483,10 +2586,11 @@ __tracing_open(struct inode *inode, struct file *file)
        if (trace_clocks[trace_clock_id].in_ns)
                iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
 
-       /* stop the trace while dumping */
-       tracing_stop();
+       /* stop the trace while dumping if we are not opening "snapshot" */
+       if (!iter->snapshot)
+               tracing_stop_tr(tr);
 
-       if (iter->cpu_file == TRACE_PIPE_ALL_CPU) {
+       if (iter->cpu_file == RING_BUFFER_ALL_CPUS) {
                for_each_tracing_cpu(cpu) {
                        iter->buffer_iter[cpu] =
                                ring_buffer_read_prepare(iter->tr->buffer, cpu);
@@ -2531,6 +2635,7 @@ static int tracing_release(struct inode *inode, struct file *file)
 {
        struct seq_file *m = file->private_data;
        struct trace_iterator *iter;
+       struct trace_array *tr;
        int cpu;
 
        if (!(file->f_mode & FMODE_READ))
@@ -2538,6 +2643,12 @@ static int tracing_release(struct inode *inode, struct file *file)
 
        iter = m->private;
 
+       /* Only the global tracer has a matching max_tr */
+       if (iter->tr == &max_tr)
+               tr = &global_trace;
+       else
+               tr = iter->tr;
+
        mutex_lock(&trace_types_lock);
        for_each_tracing_cpu(cpu) {
                if (iter->buffer_iter[cpu])
@@ -2547,8 +2658,9 @@ static int tracing_release(struct inode *inode, struct file *file)
        if (iter->trace && iter->trace->close)
                iter->trace->close(iter);
 
-       /* reenable tracing if it was previously enabled */
-       tracing_start();
+       if (!iter->snapshot)
+               /* reenable tracing if it was previously enabled */
+               tracing_start_tr(tr);
        mutex_unlock(&trace_types_lock);
 
        mutex_destroy(&iter->mutex);
@@ -2567,16 +2679,17 @@ static int tracing_open(struct inode *inode, struct file *file)
        /* If this file was open for write, then erase contents */
        if ((file->f_mode & FMODE_WRITE) &&
            (file->f_flags & O_TRUNC)) {
-               long cpu = (long) inode->i_private;
+               struct trace_cpu *tc = inode->i_private;
+               struct trace_array *tr = tc->tr;
 
-               if (cpu == TRACE_PIPE_ALL_CPU)
-                       tracing_reset_online_cpus(&global_trace);
+               if (tc->cpu == RING_BUFFER_ALL_CPUS)
+                       tracing_reset_online_cpus(tr);
                else
-                       tracing_reset(&global_trace, cpu);
+                       tracing_reset(tr, tc->cpu);
        }
 
        if (file->f_mode & FMODE_READ) {
-               iter = __tracing_open(inode, file);
+               iter = __tracing_open(inode, file, false);
                if (IS_ERR(iter))
                        ret = PTR_ERR(iter);
                else if (trace_flags & TRACE_ITER_LATENCY_FMT)
@@ -2719,8 +2832,9 @@ static ssize_t
 tracing_cpumask_write(struct file *filp, const char __user *ubuf,
                      size_t count, loff_t *ppos)
 {
-       int err, cpu;
+       struct trace_array *tr = filp->private_data;
        cpumask_var_t tracing_cpumask_new;
+       int err, cpu;
 
        if (!alloc_cpumask_var(&tracing_cpumask_new, GFP_KERNEL))
                return -ENOMEM;
@@ -2740,13 +2854,13 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
                 */
                if (cpumask_test_cpu(cpu, tracing_cpumask) &&
                                !cpumask_test_cpu(cpu, tracing_cpumask_new)) {
-                       atomic_inc(&global_trace.data[cpu]->disabled);
-                       ring_buffer_record_disable_cpu(global_trace.buffer, cpu);
+                       atomic_inc(&per_cpu_ptr(tr->data, cpu)->disabled);
+                       ring_buffer_record_disable_cpu(tr->buffer, cpu);
                }
                if (!cpumask_test_cpu(cpu, tracing_cpumask) &&
                                cpumask_test_cpu(cpu, tracing_cpumask_new)) {
-                       atomic_dec(&global_trace.data[cpu]->disabled);
-                       ring_buffer_record_enable_cpu(global_trace.buffer, cpu);
+                       atomic_dec(&per_cpu_ptr(tr->data, cpu)->disabled);
+                       ring_buffer_record_enable_cpu(tr->buffer, cpu);
                }
        }
        arch_spin_unlock(&ftrace_max_lock);
@@ -2775,12 +2889,13 @@ static const struct file_operations tracing_cpumask_fops = {
 static int tracing_trace_options_show(struct seq_file *m, void *v)
 {
        struct tracer_opt *trace_opts;
+       struct trace_array *tr = m->private;
        u32 tracer_flags;
        int i;
 
        mutex_lock(&trace_types_lock);
-       tracer_flags = current_trace->flags->val;
-       trace_opts = current_trace->flags->opts;
+       tracer_flags = tr->current_trace->flags->val;
+       trace_opts = tr->current_trace->flags->opts;
 
        for (i = 0; trace_options[i]; i++) {
                if (trace_flags & (1 << i))
@@ -2835,11 +2950,25 @@ static int set_tracer_option(struct tracer *trace, char *cmp, int neg)
        return -EINVAL;
 }
 
-static void set_tracer_flags(unsigned int mask, int enabled)
+/* Some tracers require overwrite to stay enabled */
+int trace_keep_overwrite(struct tracer *tracer, u32 mask, int set)
+{
+       if (tracer->enabled && (mask & TRACE_ITER_OVERWRITE) && !set)
+               return -1;
+
+       return 0;
+}
+
+int set_tracer_flag(struct trace_array *tr, unsigned int mask, int enabled)
 {
        /* do nothing if flag is already set */
        if (!!(trace_flags & mask) == !!enabled)
-               return;
+               return 0;
+
+       /* Give the tracer a chance to approve the change */
+       if (tr->current_trace->flag_changed)
+               if (tr->current_trace->flag_changed(tr->current_trace, mask, !!enabled))
+                       return -EINVAL;
 
        if (enabled)
                trace_flags |= mask;
@@ -2849,18 +2978,24 @@ static void set_tracer_flags(unsigned int mask, int enabled)
        if (mask == TRACE_ITER_RECORD_CMD)
                trace_event_enable_cmd_record(enabled);
 
-       if (mask == TRACE_ITER_OVERWRITE)
+       if (mask == TRACE_ITER_OVERWRITE) {
                ring_buffer_change_overwrite(global_trace.buffer, enabled);
+#ifdef CONFIG_TRACER_MAX_TRACE
+               ring_buffer_change_overwrite(max_tr.buffer, enabled);
+#endif
+       }
 
        if (mask == TRACE_ITER_PRINTK)
                trace_printk_start_stop_comm(enabled);
+
+       return 0;
 }
 
-static int trace_set_options(char *option)
+static int trace_set_options(struct trace_array *tr, char *option)
 {
        char *cmp;
        int neg = 0;
-       int ret = 0;
+       int ret = -ENODEV;
        int i;
 
        cmp = strstrip(option);
@@ -2870,19 +3005,20 @@ static int trace_set_options(char *option)
                cmp += 2;
        }
 
+       mutex_lock(&trace_types_lock);
+
        for (i = 0; trace_options[i]; i++) {
                if (strcmp(cmp, trace_options[i]) == 0) {
-                       set_tracer_flags(1 << i, !neg);
+                       ret = set_tracer_flag(tr, 1 << i, !neg);
                        break;
                }
        }
 
        /* If no option could be set, test the specific tracer options */
-       if (!trace_options[i]) {
-               mutex_lock(&trace_types_lock);
-               ret = set_tracer_option(current_trace, cmp, neg);
-               mutex_unlock(&trace_types_lock);
-       }
+       if (!trace_options[i])
+               ret = set_tracer_option(tr->current_trace, cmp, neg);
+
+       mutex_unlock(&trace_types_lock);
 
        return ret;
 }
@@ -2891,7 +3027,10 @@ static ssize_t
 tracing_trace_options_write(struct file *filp, const char __user *ubuf,
                        size_t cnt, loff_t *ppos)
 {
+       struct seq_file *m = filp->private_data;
+       struct trace_array *tr = m->private;
        char buf[64];
+       int ret;
 
        if (cnt >= sizeof(buf))
                return -EINVAL;
@@ -2901,7 +3040,9 @@ tracing_trace_options_write(struct file *filp, const char __user *ubuf,
 
        buf[cnt] = 0;
 
-       trace_set_options(buf);
+       ret = trace_set_options(tr, buf);
+       if (ret < 0)
+               return ret;
 
        *ppos += cnt;
 
@@ -2912,7 +3053,8 @@ static int tracing_trace_options_open(struct inode *inode, struct file *file)
 {
        if (tracing_disabled)
                return -ENODEV;
-       return single_open(file, tracing_trace_options_show, NULL);
+
+       return single_open(file, tracing_trace_options_show, inode->i_private);
 }
 
 static const struct file_operations tracing_iter_fops = {
@@ -3010,14 +3152,12 @@ static ssize_t
 tracing_set_trace_read(struct file *filp, char __user *ubuf,
                       size_t cnt, loff_t *ppos)
 {
+       struct trace_array *tr = filp->private_data;
        char buf[MAX_TRACER_SIZE+2];
        int r;
 
        mutex_lock(&trace_types_lock);
-       if (current_trace)
-               r = sprintf(buf, "%s\n", current_trace->name);
-       else
-               r = sprintf(buf, "\n");
+       r = sprintf(buf, "%s\n", tr->current_trace->name);
        mutex_unlock(&trace_types_lock);
 
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
@@ -3033,7 +3173,7 @@ static void set_buffer_entries(struct trace_array *tr, unsigned long val)
 {
        int cpu;
        for_each_tracing_cpu(cpu)
-               tr->data[cpu]->entries = val;
+               per_cpu_ptr(tr->data, cpu)->entries = val;
 }
 
 /* resize @tr's buffer to the size of @size_tr's entries */
@@ -3045,23 +3185,25 @@ static int resize_buffer_duplicate_size(struct trace_array *tr,
        if (cpu_id == RING_BUFFER_ALL_CPUS) {
                for_each_tracing_cpu(cpu) {
                        ret = ring_buffer_resize(tr->buffer,
-                                       size_tr->data[cpu]->entries, cpu);
+                                per_cpu_ptr(size_tr->data, cpu)->entries, cpu);
                        if (ret < 0)
                                break;
-                       tr->data[cpu]->entries = size_tr->data[cpu]->entries;
+                       per_cpu_ptr(tr->data, cpu)->entries =
+                               per_cpu_ptr(size_tr->data, cpu)->entries;
                }
        } else {
                ret = ring_buffer_resize(tr->buffer,
-                                       size_tr->data[cpu_id]->entries, cpu_id);
+                                per_cpu_ptr(size_tr->data, cpu_id)->entries, cpu_id);
                if (ret == 0)
-                       tr->data[cpu_id]->entries =
-                               size_tr->data[cpu_id]->entries;
+                       per_cpu_ptr(tr->data, cpu_id)->entries =
+                               per_cpu_ptr(size_tr->data, cpu_id)->entries;
        }
 
        return ret;
 }
 
-static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
+static int __tracing_resize_ring_buffer(struct trace_array *tr,
+                                       unsigned long size, int cpu)
 {
        int ret;
 
@@ -3073,20 +3215,20 @@ static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
        ring_buffer_expanded = 1;
 
        /* May be called before buffers are initialized */
-       if (!global_trace.buffer)
+       if (!tr->buffer)
                return 0;
 
-       ret = ring_buffer_resize(global_trace.buffer, size, cpu);
+       ret = ring_buffer_resize(tr->buffer, size, cpu);
        if (ret < 0)
                return ret;
 
-       if (!current_trace->use_max_tr)
+       if (!(tr->flags & TRACE_ARRAY_FL_GLOBAL) ||
+           !tr->current_trace->use_max_tr)
                goto out;
 
        ret = ring_buffer_resize(max_tr.buffer, size, cpu);
        if (ret < 0) {
-               int r = resize_buffer_duplicate_size(&global_trace,
-                                                    &global_trace, cpu);
+               int r = resize_buffer_duplicate_size(tr, tr, cpu);
                if (r < 0) {
                        /*
                         * AARGH! We are left with different
@@ -3111,18 +3253,19 @@ static int __tracing_resize_ring_buffer(unsigned long size, int cpu)
        if (cpu == RING_BUFFER_ALL_CPUS)
                set_buffer_entries(&max_tr, size);
        else
-               max_tr.data[cpu]->entries = size;
+               per_cpu_ptr(max_tr.data, cpu)->entries = size;
 
  out:
        if (cpu == RING_BUFFER_ALL_CPUS)
-               set_buffer_entries(&global_trace, size);
+               set_buffer_entries(tr, size);
        else
-               global_trace.data[cpu]->entries = size;
+               per_cpu_ptr(tr->data, cpu)->entries = size;
 
        return ret;
 }
 
-static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
+static ssize_t tracing_resize_ring_buffer(struct trace_array *tr,
+                                         unsigned long size, int cpu_id)
 {
        int ret = size;
 
@@ -3136,7 +3279,7 @@ static ssize_t tracing_resize_ring_buffer(unsigned long size, int cpu_id)
                }
        }
 
-       ret = __tracing_resize_ring_buffer(size, cpu_id);
+       ret = __tracing_resize_ring_buffer(tr, size, cpu_id);
        if (ret < 0)
                ret = -ENOMEM;
 
@@ -3163,7 +3306,7 @@ int tracing_update_buffers(void)
 
        mutex_lock(&trace_types_lock);
        if (!ring_buffer_expanded)
-               ret = __tracing_resize_ring_buffer(trace_buf_size,
+               ret = __tracing_resize_ring_buffer(&global_trace, trace_buf_size,
                                                RING_BUFFER_ALL_CPUS);
        mutex_unlock(&trace_types_lock);
 
@@ -3173,7 +3316,7 @@ int tracing_update_buffers(void)
 struct trace_option_dentry;
 
 static struct trace_option_dentry *
-create_trace_option_files(struct tracer *tracer);
+create_trace_option_files(struct trace_array *tr, struct tracer *tracer);
 
 static void
 destroy_trace_option_files(struct trace_option_dentry *topts);
@@ -3183,12 +3326,13 @@ static int tracing_set_tracer(const char *buf)
        static struct trace_option_dentry *topts;
        struct trace_array *tr = &global_trace;
        struct tracer *t;
+       bool had_max_tr;
        int ret = 0;
 
        mutex_lock(&trace_types_lock);
 
        if (!ring_buffer_expanded) {
-               ret = __tracing_resize_ring_buffer(trace_buf_size,
+               ret = __tracing_resize_ring_buffer(tr, trace_buf_size,
                                                RING_BUFFER_ALL_CPUS);
                if (ret < 0)
                        goto out;
@@ -3203,13 +3347,28 @@ static int tracing_set_tracer(const char *buf)
                ret = -EINVAL;
                goto out;
        }
-       if (t == current_trace)
+       if (t == tr->current_trace)
                goto out;
 
        trace_branch_disable();
-       if (current_trace && current_trace->reset)
-               current_trace->reset(tr);
-       if (current_trace && current_trace->use_max_tr) {
+
+       tr->current_trace->enabled = false;
+
+       if (tr->current_trace->reset)
+               tr->current_trace->reset(tr);
+
+       had_max_tr = tr->current_trace->allocated_snapshot;
+       tr->current_trace = &nop_trace;
+
+       if (had_max_tr && !t->use_max_tr) {
+               /*
+                * We need to make sure that the update_max_tr sees that
+                * current_trace changed to nop_trace to keep it from
+                * swapping the buffers after we resize it.
+                * The update_max_tr is called from interrupts disabled
+                * so a synchronized_sched() is sufficient.
+                */
+               synchronize_sched();
                /*
                 * We don't free the ring buffer. instead, resize it because
                 * The max_tr ring buffer has some state (e.g. ring->clock) and
@@ -3217,18 +3376,19 @@ static int tracing_set_tracer(const char *buf)
                 */
                ring_buffer_resize(max_tr.buffer, 1, RING_BUFFER_ALL_CPUS);
                set_buffer_entries(&max_tr, 1);
+               tracing_reset_online_cpus(&max_tr);
+               tr->current_trace->allocated_snapshot = false;
        }
        destroy_trace_option_files(topts);
 
-       current_trace = &nop_trace;
-
-       topts = create_trace_option_files(t);
-       if (t->use_max_tr) {
+       topts = create_trace_option_files(tr, t);
+       if (t->use_max_tr && !had_max_tr) {
                /* we need to make per cpu buffer sizes equivalent */
                ret = resize_buffer_duplicate_size(&max_tr, &global_trace,
                                                   RING_BUFFER_ALL_CPUS);
                if (ret < 0)
                        goto out;
+               t->allocated_snapshot = true;
        }
 
        if (t->init) {
@@ -3237,7 +3397,8 @@ static int tracing_set_tracer(const char *buf)
                        goto out;
        }
 
-       current_trace = t;
+       tr->current_trace = t;
+       tr->current_trace->enabled = true;
        trace_branch_enable(tr);
  out:
        mutex_unlock(&trace_types_lock);
@@ -3311,7 +3472,8 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf,
 
 static int tracing_open_pipe(struct inode *inode, struct file *filp)
 {
-       long cpu_file = (long) inode->i_private;
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
        struct trace_iterator *iter;
        int ret = 0;
 
@@ -3336,8 +3498,7 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
                ret = -ENOMEM;
                goto fail;
        }
-       if (current_trace)
-               *iter->trace = *current_trace;
+       *iter->trace = *tr->current_trace;
 
        if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {
                ret = -ENOMEM;
@@ -3354,8 +3515,8 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
        if (trace_clocks[trace_clock_id].in_ns)
                iter->iter_flags |= TRACE_FILE_TIME_IN_NS;
 
-       iter->cpu_file = cpu_file;
-       iter->tr = &global_trace;
+       iter->cpu_file = tc->cpu;
+       iter->tr = tc->tr;
        mutex_init(&iter->mutex);
        filp->private_data = iter;
 
@@ -3477,7 +3638,7 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
                  size_t cnt, loff_t *ppos)
 {
        struct trace_iterator *iter = filp->private_data;
-       static struct tracer *old_tracer;
+       struct trace_array *tr = iter->tr;
        ssize_t sret;
 
        /* return any leftover data */
@@ -3489,10 +3650,8 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
 
        /* copy the tracer to avoid using a global lock all around */
        mutex_lock(&trace_types_lock);
-       if (unlikely(old_tracer != current_trace && current_trace)) {
-               old_tracer = current_trace;
-               *iter->trace = *current_trace;
-       }
+       if (unlikely(iter->trace->name != tr->current_trace->name))
+               *iter->trace = *tr->current_trace;
        mutex_unlock(&trace_types_lock);
 
        /*
@@ -3648,7 +3807,7 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
                .ops            = &tracing_pipe_buf_ops,
                .spd_release    = tracing_spd_release_pipe,
        };
-       static struct tracer *old_tracer;
+       struct trace_array *tr = iter->tr;
        ssize_t ret;
        size_t rem;
        unsigned int i;
@@ -3658,10 +3817,8 @@ static ssize_t tracing_splice_read_pipe(struct file *filp,
 
        /* copy the tracer to avoid using a global lock all around */
        mutex_lock(&trace_types_lock);
-       if (unlikely(old_tracer != current_trace && current_trace)) {
-               old_tracer = current_trace;
-               *iter->trace = *current_trace;
-       }
+       if (unlikely(iter->trace->name != tr->current_trace->name))
+               *iter->trace = *tr->current_trace;
        mutex_unlock(&trace_types_lock);
 
        mutex_lock(&iter->mutex);
@@ -3723,43 +3880,19 @@ out_err:
        goto out;
 }
 
-struct ftrace_entries_info {
-       struct trace_array      *tr;
-       int                     cpu;
-};
-
-static int tracing_entries_open(struct inode *inode, struct file *filp)
-{
-       struct ftrace_entries_info *info;
-
-       if (tracing_disabled)
-               return -ENODEV;
-
-       info = kzalloc(sizeof(*info), GFP_KERNEL);
-       if (!info)
-               return -ENOMEM;
-
-       info->tr = &global_trace;
-       info->cpu = (unsigned long)inode->i_private;
-
-       filp->private_data = info;
-
-       return 0;
-}
-
 static ssize_t
 tracing_entries_read(struct file *filp, char __user *ubuf,
                     size_t cnt, loff_t *ppos)
 {
-       struct ftrace_entries_info *info = filp->private_data;
-       struct trace_array *tr = info->tr;
+       struct trace_cpu *tc = filp->private_data;
+       struct trace_array *tr = tc->tr;
        char buf[64];
        int r = 0;
        ssize_t ret;
 
        mutex_lock(&trace_types_lock);
 
-       if (info->cpu == RING_BUFFER_ALL_CPUS) {
+       if (tc->cpu == RING_BUFFER_ALL_CPUS) {
                int cpu, buf_size_same;
                unsigned long size;
 
@@ -3769,8 +3902,8 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
                for_each_tracing_cpu(cpu) {
                        /* fill in the size from first enabled cpu */
                        if (size == 0)
-                               size = tr->data[cpu]->entries;
-                       if (size != tr->data[cpu]->entries) {
+                               size = per_cpu_ptr(tr->data, cpu)->entries;
+                       if (size != per_cpu_ptr(tr->data, cpu)->entries) {
                                buf_size_same = 0;
                                break;
                        }
@@ -3786,7 +3919,7 @@ tracing_entries_read(struct file *filp, char __user *ubuf,
                } else
                        r = sprintf(buf, "X\n");
        } else
-               r = sprintf(buf, "%lu\n", tr->data[info->cpu]->entries >> 10);
+               r = sprintf(buf, "%lu\n", per_cpu_ptr(tr->data, tc->cpu)->entries >> 10);
 
        mutex_unlock(&trace_types_lock);
 
@@ -3798,7 +3931,7 @@ static ssize_t
 tracing_entries_write(struct file *filp, const char __user *ubuf,
                      size_t cnt, loff_t *ppos)
 {
-       struct ftrace_entries_info *info = filp->private_data;
+       struct trace_cpu *tc = filp->private_data;
        unsigned long val;
        int ret;
 
@@ -3813,7 +3946,7 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
        /* value is in KB */
        val <<= 10;
 
-       ret = tracing_resize_ring_buffer(val, info->cpu);
+       ret = tracing_resize_ring_buffer(tc->tr, val, tc->cpu);
        if (ret < 0)
                return ret;
 
@@ -3822,16 +3955,6 @@ tracing_entries_write(struct file *filp, const char __user *ubuf,
        return cnt;
 }
 
-static int
-tracing_entries_release(struct inode *inode, struct file *filp)
-{
-       struct ftrace_entries_info *info = filp->private_data;
-
-       kfree(info);
-
-       return 0;
-}
-
 static ssize_t
 tracing_total_entries_read(struct file *filp, char __user *ubuf,
                                size_t cnt, loff_t *ppos)
@@ -3843,7 +3966,7 @@ tracing_total_entries_read(struct file *filp, char __user *ubuf,
 
        mutex_lock(&trace_types_lock);
        for_each_tracing_cpu(cpu) {
-               size += tr->data[cpu]->entries >> 10;
+               size += per_cpu_ptr(tr->data, cpu)->entries >> 10;
                if (!ring_buffer_expanded)
                        expanded_size += trace_buf_size >> 10;
        }
@@ -3873,11 +3996,13 @@ tracing_free_buffer_write(struct file *filp, const char __user *ubuf,
 static int
 tracing_free_buffer_release(struct inode *inode, struct file *filp)
 {
+       struct trace_array *tr = inode->i_private;
+
        /* disable tracing ? */
        if (trace_flags & TRACE_ITER_STOP_ON_FREE)
                tracing_off();
        /* resize the ring buffer to 0 */
-       tracing_resize_ring_buffer(0, RING_BUFFER_ALL_CPUS);
+       tracing_resize_ring_buffer(tr, 0, RING_BUFFER_ALL_CPUS);
 
        return 0;
 }
@@ -3988,13 +4113,14 @@ tracing_mark_write(struct file *filp, const char __user *ubuf,
 
 static int tracing_clock_show(struct seq_file *m, void *v)
 {
+       struct trace_array *tr = m->private;
        int i;
 
        for (i = 0; i < ARRAY_SIZE(trace_clocks); i++)
                seq_printf(m,
                        "%s%s%s%s", i ? " " : "",
-                       i == trace_clock_id ? "[" : "", trace_clocks[i].name,
-                       i == trace_clock_id ? "]" : "");
+                       i == tr->clock_id ? "[" : "", trace_clocks[i].name,
+                       i == tr->clock_id ? "]" : "");
        seq_putc(m, '\n');
 
        return 0;
@@ -4003,6 +4129,8 @@ static int tracing_clock_show(struct seq_file *m, void *v)
 static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
                                   size_t cnt, loff_t *fpos)
 {
+       struct seq_file *m = filp->private_data;
+       struct trace_array *tr = m->private;
        char buf[64];
        const char *clockstr;
        int i;
@@ -4024,12 +4152,12 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
        if (i == ARRAY_SIZE(trace_clocks))
                return -EINVAL;
 
-       trace_clock_id = i;
-
        mutex_lock(&trace_types_lock);
 
-       ring_buffer_set_clock(global_trace.buffer, trace_clocks[i].func);
-       if (max_tr.buffer)
+       tr->clock_id = i;
+
+       ring_buffer_set_clock(tr->buffer, trace_clocks[i].func);
+       if (tr->flags & TRACE_ARRAY_FL_GLOBAL && max_tr.buffer)
                ring_buffer_set_clock(max_tr.buffer, trace_clocks[i].func);
 
        /*
@@ -4037,8 +4165,7 @@ static ssize_t tracing_clock_write(struct file *filp, const char __user *ubuf,
         * Reset the buffer so that it doesn't have incomparable timestamps.
         */
        tracing_reset_online_cpus(&global_trace);
-       if (max_tr.buffer)
-               tracing_reset_online_cpus(&max_tr);
+       tracing_reset_online_cpus(&max_tr);
 
        mutex_unlock(&trace_types_lock);
 
@@ -4051,9 +4178,124 @@ static int tracing_clock_open(struct inode *inode, struct file *file)
 {
        if (tracing_disabled)
                return -ENODEV;
-       return single_open(file, tracing_clock_show, NULL);
+
+       return single_open(file, tracing_clock_show, inode->i_private);
 }
 
+#ifdef CONFIG_TRACER_SNAPSHOT
+static int tracing_snapshot_open(struct inode *inode, struct file *file)
+{
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_iterator *iter;
+       struct seq_file *m;
+       int ret = 0;
+
+       if (file->f_mode & FMODE_READ) {
+               iter = __tracing_open(inode, file, true);
+               if (IS_ERR(iter))
+                       ret = PTR_ERR(iter);
+       } else {
+               /* Writes still need the seq_file to hold the private data */
+               m = kzalloc(sizeof(*m), GFP_KERNEL);
+               if (!m)
+                       return -ENOMEM;
+               iter = kzalloc(sizeof(*iter), GFP_KERNEL);
+               if (!iter) {
+                       kfree(m);
+                       return -ENOMEM;
+               }
+               iter->tr = tc->tr;
+               m->private = iter;
+               file->private_data = m;
+       }
+
+       return ret;
+}
+
+static ssize_t
+tracing_snapshot_write(struct file *filp, const char __user *ubuf, size_t cnt,
+                      loff_t *ppos)
+{
+       struct seq_file *m = filp->private_data;
+       struct trace_iterator *iter = m->private;
+       struct trace_array *tr = iter->tr;
+       unsigned long val;
+       int ret;
+
+       ret = tracing_update_buffers();
+       if (ret < 0)
+               return ret;
+
+       ret = kstrtoul_from_user(ubuf, cnt, 10, &val);
+       if (ret)
+               return ret;
+
+       mutex_lock(&trace_types_lock);
+
+       if (tr->current_trace->use_max_tr) {
+               ret = -EBUSY;
+               goto out;
+       }
+
+       switch (val) {
+       case 0:
+               if (tr->current_trace->allocated_snapshot) {
+                       /* free spare buffer */
+                       ring_buffer_resize(max_tr.buffer, 1,
+                                          RING_BUFFER_ALL_CPUS);
+                       set_buffer_entries(&max_tr, 1);
+                       tracing_reset_online_cpus(&max_tr);
+                       tr->current_trace->allocated_snapshot = false;
+               }
+               break;
+       case 1:
+               if (!tr->current_trace->allocated_snapshot) {
+                       /* allocate spare buffer */
+                       ret = resize_buffer_duplicate_size(&max_tr,
+                                       &global_trace, RING_BUFFER_ALL_CPUS);
+                       if (ret < 0)
+                               break;
+                       tr->current_trace->allocated_snapshot = true;
+               }
+
+               local_irq_disable();
+               /* Now, we're going to swap */
+               update_max_tr(&global_trace, current, smp_processor_id());
+               local_irq_enable();
+               break;
+       default:
+               if (tr->current_trace->allocated_snapshot)
+                       tracing_reset_online_cpus(&max_tr);
+               break;
+       }
+
+       if (ret >= 0) {
+               *ppos += cnt;
+               ret = cnt;
+       }
+out:
+       mutex_unlock(&trace_types_lock);
+       return ret;
+}
+
+static int tracing_snapshot_release(struct inode *inode, struct file *file)
+{
+       struct seq_file *m = file->private_data;
+
+       if (file->f_mode & FMODE_READ)
+               return tracing_release(inode, file);
+
+       /* If write only, the seq_file is just a stub */
+       if (m)
+               kfree(m->private);
+       kfree(m);
+
+       return 0;
+}
+
+#endif /* CONFIG_TRACER_SNAPSHOT */
+
+
 static const struct file_operations tracing_max_lat_fops = {
        .open           = tracing_open_generic,
        .read           = tracing_max_lat_read,
@@ -4078,10 +4320,9 @@ static const struct file_operations tracing_pipe_fops = {
 };
 
 static const struct file_operations tracing_entries_fops = {
-       .open           = tracing_entries_open,
+       .open           = tracing_open_generic,
        .read           = tracing_entries_read,
        .write          = tracing_entries_write,
-       .release        = tracing_entries_release,
        .llseek         = generic_file_llseek,
 };
 
@@ -4110,6 +4351,16 @@ static const struct file_operations trace_clock_fops = {
        .write          = tracing_clock_write,
 };
 
+#ifdef CONFIG_TRACER_SNAPSHOT
+static const struct file_operations snapshot_fops = {
+       .open           = tracing_snapshot_open,
+       .read           = seq_read,
+       .write          = tracing_snapshot_write,
+       .llseek         = tracing_seek,
+       .release        = tracing_snapshot_release,
+};
+#endif /* CONFIG_TRACER_SNAPSHOT */
+
 struct ftrace_buffer_info {
        struct trace_array      *tr;
        void                    *spare;
@@ -4119,7 +4370,8 @@ struct ftrace_buffer_info {
 
 static int tracing_buffers_open(struct inode *inode, struct file *filp)
 {
-       int cpu = (int)(long)inode->i_private;
+       struct trace_cpu *tc = inode->i_private;
+       struct trace_array *tr = tc->tr;
        struct ftrace_buffer_info *info;
 
        if (tracing_disabled)
@@ -4129,8 +4381,8 @@ static int tracing_buffers_open(struct inode *inode, struct file *filp)
        if (!info)
                return -ENOMEM;
 
-       info->tr        = &global_trace;
-       info->cpu       = cpu;
+       info->tr        = tr;
+       info->cpu       = tc->cpu;
        info->spare     = NULL;
        /* Force reading ring buffer for first read */
        info->read      = (unsigned int)-1;
@@ -4367,12 +4619,13 @@ static ssize_t
 tracing_stats_read(struct file *filp, char __user *ubuf,
                   size_t count, loff_t *ppos)
 {
-       unsigned long cpu = (unsigned long)filp->private_data;
-       struct trace_array *tr = &global_trace;
+       struct trace_cpu *tc = filp->private_data;
+       struct trace_array *tr = tc->tr;
        struct trace_seq *s;
        unsigned long cnt;
        unsigned long long t;
        unsigned long usec_rem;
+       int cpu = tc->cpu;
 
        s = kmalloc(sizeof(*s), GFP_KERNEL);
        if (!s)
@@ -4414,6 +4667,9 @@ tracing_stats_read(struct file *filp, char __user *ubuf,
        cnt = ring_buffer_dropped_events_cpu(tr->buffer, cpu);
        trace_seq_printf(s, "dropped events: %ld\n", cnt);
 
+       cnt = ring_buffer_read_events_cpu(tr->buffer, cpu);
+       trace_seq_printf(s, "read events: %ld\n", cnt);
+
        count = simple_read_from_buffer(ubuf, count, ppos, s->buffer, s->len);
 
        kfree(s);
@@ -4465,58 +4721,57 @@ static const struct file_operations tracing_dyn_info_fops = {
 };
 #endif
 
-static struct dentry *d_tracer;
-
-struct dentry *tracing_init_dentry(void)
+struct dentry *tracing_init_dentry_tr(struct trace_array *tr)
 {
        static int once;
 
-       if (d_tracer)
-               return d_tracer;
+       if (tr->dir)
+               return tr->dir;
 
        if (!debugfs_initialized())
                return NULL;
 
-       d_tracer = debugfs_create_dir("tracing", NULL);
+       if (tr->flags & TRACE_ARRAY_FL_GLOBAL)
+               tr->dir = debugfs_create_dir("tracing", NULL);
 
-       if (!d_tracer && !once) {
+       if (!tr->dir && !once) {
                once = 1;
                pr_warning("Could not create debugfs directory 'tracing'\n");
                return NULL;
        }
 
-       return d_tracer;
+       return tr->dir;
 }
 
-static struct dentry *d_percpu;
+struct dentry *tracing_init_dentry(void)
+{
+       return tracing_init_dentry_tr(&global_trace);
+}
 
-struct dentry *tracing_dentry_percpu(void)
+static struct dentry *tracing_dentry_percpu(struct trace_array *tr, int cpu)
 {
-       static int once;
        struct dentry *d_tracer;
 
-       if (d_percpu)
-               return d_percpu;
-
-       d_tracer = tracing_init_dentry();
+       if (tr->percpu_dir)
+               return tr->percpu_dir;
 
+       d_tracer = tracing_init_dentry_tr(tr);
        if (!d_tracer)
                return NULL;
 
-       d_percpu = debugfs_create_dir("per_cpu", d_tracer);
+       tr->percpu_dir = debugfs_create_dir("per_cpu", d_tracer);
 
-       if (!d_percpu && !once) {
-               once = 1;
-               pr_warning("Could not create debugfs directory 'per_cpu'\n");
-               return NULL;
-       }
+       WARN_ONCE(!tr->percpu_dir,
+                 "Could not create debugfs directory 'per_cpu/%d'\n", cpu);
 
-       return d_percpu;
+       return tr->percpu_dir;
 }
 
-static void tracing_init_debugfs_percpu(long cpu)
+static void
+tracing_init_debugfs_percpu(struct trace_array *tr, long cpu)
 {
-       struct dentry *d_percpu = tracing_dentry_percpu();
+       struct trace_array_cpu *data = per_cpu_ptr(tr->data, cpu);
+       struct dentry *d_percpu = tracing_dentry_percpu(tr, cpu);
        struct dentry *d_cpu;
        char cpu_dir[30]; /* 30 characters should be more than enough */
 
@@ -4532,20 +4787,20 @@ static void tracing_init_debugfs_percpu(long cpu)
 
        /* per cpu trace_pipe */
        trace_create_file("trace_pipe", 0444, d_cpu,
-                       (void *) cpu, &tracing_pipe_fops);
+                       (void *)&data->trace_cpu, &tracing_pipe_fops);
 
        /* per cpu trace */
        trace_create_file("trace", 0644, d_cpu,
-                       (void *) cpu, &tracing_fops);
+                       (void *)&data->trace_cpu, &tracing_fops);
 
        trace_create_file("trace_pipe_raw", 0444, d_cpu,
-                       (void *) cpu, &tracing_buffers_fops);
+                       (void *)&data->trace_cpu, &tracing_buffers_fops);
 
        trace_create_file("stats", 0444, d_cpu,
-                       (void *) cpu, &tracing_stats_fops);
+                       (void *)&data->trace_cpu, &tracing_stats_fops);
 
        trace_create_file("buffer_size_kb", 0444, d_cpu,
-                       (void *) cpu, &tracing_entries_fops);
+                       (void *)&data->trace_cpu, &tracing_entries_fops);
 }
 
 #ifdef CONFIG_FTRACE_SELFTEST
@@ -4556,6 +4811,7 @@ static void tracing_init_debugfs_percpu(long cpu)
 struct trace_option_dentry {
        struct tracer_opt               *opt;
        struct tracer_flags             *flags;
+       struct trace_array              *tr;
        struct dentry                   *entry;
 };
 
@@ -4591,7 +4847,7 @@ trace_options_write(struct file *filp, const char __user *ubuf, size_t cnt,
 
        if (!!(topt->flags->val & topt->opt->bit) != val) {
                mutex_lock(&trace_types_lock);
-               ret = __set_tracer_option(current_trace, topt->flags,
+               ret = __set_tracer_option(topt->tr->current_trace, topt->flags,
                                          topt->opt, !val);
                mutex_unlock(&trace_types_lock);
                if (ret)
@@ -4630,6 +4886,7 @@ static ssize_t
 trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
                         loff_t *ppos)
 {
+       struct trace_array *tr = &global_trace;
        long index = (long)filp->private_data;
        unsigned long val;
        int ret;
@@ -4640,7 +4897,13 @@ trace_options_core_write(struct file *filp, const char __user *ubuf, size_t cnt,
 
        if (val != 0 && val != 1)
                return -EINVAL;
-       set_tracer_flags(1 << index, val);
+
+       mutex_lock(&trace_types_lock);
+       ret = set_tracer_flag(tr, 1 << index, val);
+       mutex_unlock(&trace_types_lock);
+
+       if (ret < 0)
+               return ret;
 
        *ppos += cnt;
 
@@ -4670,40 +4933,41 @@ struct dentry *trace_create_file(const char *name,
 }
 
 
-static struct dentry *trace_options_init_dentry(void)
+static struct dentry *trace_options_init_dentry(struct trace_array *tr)
 {
        struct dentry *d_tracer;
-       static struct dentry *t_options;
 
-       if (t_options)
-               return t_options;
+       if (tr->options)
+               return tr->options;
 
-       d_tracer = tracing_init_dentry();
+       d_tracer = tracing_init_dentry_tr(tr);
        if (!d_tracer)
                return NULL;
 
-       t_options = debugfs_create_dir("options", d_tracer);
-       if (!t_options) {
+       tr->options = debugfs_create_dir("options", d_tracer);
+       if (!tr->options) {
                pr_warning("Could not create debugfs directory 'options'\n");
                return NULL;
        }
 
-       return t_options;
+       return tr->options;
 }
 
 static void
-create_trace_option_file(struct trace_option_dentry *topt,
+create_trace_option_file(struct trace_array *tr,
+                        struct trace_option_dentry *topt,
                         struct tracer_flags *flags,
                         struct tracer_opt *opt)
 {
        struct dentry *t_options;
 
-       t_options = trace_options_init_dentry();
+       t_options = trace_options_init_dentry(tr);
        if (!t_options)
                return;
 
        topt->flags = flags;
        topt->opt = opt;
+       topt->tr = tr;
 
        topt->entry = trace_create_file(opt->name, 0644, t_options, topt,
                                    &trace_options_fops);
@@ -4711,7 +4975,7 @@ create_trace_option_file(struct trace_option_dentry *topt,
 }
 
 static struct trace_option_dentry *
-create_trace_option_files(struct tracer *tracer)
+create_trace_option_files(struct trace_array *tr, struct tracer *tracer)
 {
        struct trace_option_dentry *topts;
        struct tracer_flags *flags;
@@ -4736,7 +5000,7 @@ create_trace_option_files(struct tracer *tracer)
                return NULL;
 
        for (cnt = 0; opts[cnt].name; cnt++)
-               create_trace_option_file(&topts[cnt], flags,
+               create_trace_option_file(tr, &topts[cnt], flags,
                                         &opts[cnt]);
 
        return topts;
@@ -4759,11 +5023,12 @@ destroy_trace_option_files(struct trace_option_dentry *topts)
 }
 
 static struct dentry *
-create_trace_option_core_file(const char *option, long index)
+create_trace_option_core_file(struct trace_array *tr,
+                             const char *option, long index)
 {
        struct dentry *t_options;
 
-       t_options = trace_options_init_dentry();
+       t_options = trace_options_init_dentry(tr);
        if (!t_options)
                return NULL;
 
@@ -4771,17 +5036,17 @@ create_trace_option_core_file(const char *option, long index)
                                    &trace_options_core_fops);
 }
 
-static __init void create_trace_options_dir(void)
+static __init void create_trace_options_dir(struct trace_array *tr)
 {
        struct dentry *t_options;
        int i;
 
-       t_options = trace_options_init_dentry();
+       t_options = trace_options_init_dentry(tr);
        if (!t_options)
                return;
 
        for (i = 0; trace_options[i]; i++)
-               create_trace_option_core_file(trace_options[i], i);
+               create_trace_option_core_file(tr, trace_options[i], i);
 }
 
 static ssize_t
@@ -4820,12 +5085,12 @@ rb_simple_write(struct file *filp, const char __user *ubuf,
                mutex_lock(&trace_types_lock);
                if (val) {
                        ring_buffer_record_on(buffer);
-                       if (current_trace->start)
-                               current_trace->start(tr);
+                       if (tr->current_trace->start)
+                               tr->current_trace->start(tr);
                } else {
                        ring_buffer_record_off(buffer);
-                       if (current_trace->stop)
-                               current_trace->stop(tr);
+                       if (tr->current_trace->stop)
+                               tr->current_trace->stop(tr);
                }
                mutex_unlock(&trace_types_lock);
        }
@@ -4842,6 +5107,165 @@ static const struct file_operations rb_simple_fops = {
        .llseek         = default_llseek,
 };
 
+struct dentry *trace_instance_dir;
+
+static void
+init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer);
+
+static int new_instance_create(const char *name)
+{
+       enum ring_buffer_flags rb_flags;
+       struct trace_array *tr;
+       int ret;
+       int i;
+
+       mutex_lock(&trace_types_lock);
+
+       ret = -EEXIST;
+       list_for_each_entry(tr, &ftrace_trace_arrays, list) {
+               if (tr->name && strcmp(tr->name, name) == 0)
+                       goto out_unlock;
+       }
+
+       ret = -ENOMEM;
+       tr = kzalloc(sizeof(*tr), GFP_KERNEL);
+       if (!tr)
+               goto out_unlock;
+
+       tr->name = kstrdup(name, GFP_KERNEL);
+       if (!tr->name)
+               goto out_free_tr;
+
+       raw_spin_lock_init(&tr->start_lock);
+
+       tr->current_trace = &nop_trace;
+
+       INIT_LIST_HEAD(&tr->systems);
+       INIT_LIST_HEAD(&tr->events);
+
+       rb_flags = trace_flags & TRACE_ITER_OVERWRITE ? RB_FL_OVERWRITE : 0;
+
+       tr->buffer = ring_buffer_alloc(trace_buf_size, rb_flags);
+       if (!tr->buffer)
+               goto out_free_tr;
+
+       tr->data = alloc_percpu(struct trace_array_cpu);
+       if (!tr->data)
+               goto out_free_tr;
+
+       for_each_tracing_cpu(i) {
+               memset(per_cpu_ptr(tr->data, i), 0, sizeof(struct trace_array_cpu));
+               per_cpu_ptr(tr->data, i)->trace_cpu.cpu = i;
+               per_cpu_ptr(tr->data, i)->trace_cpu.tr = tr;
+       }
+
+       /* Holder for file callbacks */
+       tr->trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
+       tr->trace_cpu.tr = tr;
+
+       tr->dir = debugfs_create_dir(name, trace_instance_dir);
+       if (!tr->dir)
+               goto out_free_tr;
+
+       ret = event_trace_add_tracer(tr->dir, tr);
+       if (ret)
+               goto out_free_tr;
+
+       init_tracer_debugfs(tr, tr->dir);
+
+       list_add(&tr->list, &ftrace_trace_arrays);
+
+       mutex_unlock(&trace_types_lock);
+
+       return 0;
+
+ out_free_tr:
+       if (tr->buffer)
+               ring_buffer_free(tr->buffer);
+       kfree(tr->name);
+       kfree(tr);
+
+ out_unlock:
+       mutex_unlock(&trace_types_lock);
+
+       return ret;
+
+}
+
+static int instance_mkdir (struct inode *inode, struct dentry *dentry, umode_t mode)
+{
+       struct dentry *parent;
+       int ret;
+
+       /* Paranoid: Make sure the parent is the "instances" directory */
+       parent = hlist_entry(inode->i_dentry.first, struct dentry, d_alias);
+       if (WARN_ON_ONCE(parent != trace_instance_dir))
+               return -ENOENT;
+
+       /*
+        * The inode mutex is locked, but debugfs_create_dir() will also
+        * take the mutex. As the instances directory can not be destroyed
+        * or changed in any other way, it is safe to unlock it, and
+        * let the dentry try. If two users try to make the same dir at
+        * the same time, then the new_instance_create() will determine the
+        * winner.
+        */
+       mutex_unlock(&inode->i_mutex);
+
+       ret = new_instance_create(dentry->d_iname);
+
+       mutex_lock(&inode->i_mutex);
+
+       return ret;
+}
+
+static const struct inode_operations instance_dir_inode_operations = {
+       .lookup         = simple_lookup,
+       .mkdir          = instance_mkdir,
+};
+
+static __init void create_trace_instances(struct dentry *d_tracer)
+{
+       trace_instance_dir = debugfs_create_dir("instances", d_tracer);
+       if (WARN_ON(!trace_instance_dir))
+               return;
+
+       /* Hijack the dir inode operations, to allow mkdir */
+       trace_instance_dir->d_inode->i_op = &instance_dir_inode_operations;
+}
+
+static void
+init_tracer_debugfs(struct trace_array *tr, struct dentry *d_tracer)
+{
+
+       trace_create_file("trace_options", 0644, d_tracer,
+                         tr, &tracing_iter_fops);
+
+       trace_create_file("trace", 0644, d_tracer,
+                       (void *)&tr->trace_cpu, &tracing_fops);
+
+       trace_create_file("trace_pipe", 0444, d_tracer,
+                       (void *)&tr->trace_cpu, &tracing_pipe_fops);
+
+       trace_create_file("buffer_size_kb", 0644, d_tracer,
+                       (void *)&tr->trace_cpu, &tracing_entries_fops);
+
+       trace_create_file("buffer_total_size_kb", 0444, d_tracer,
+                         tr, &tracing_total_entries_fops);
+
+       trace_create_file("free_buffer", 0644, d_tracer,
+                         tr, &tracing_free_buffer_fops);
+
+       trace_create_file("trace_marker", 0220, d_tracer,
+                         tr, &tracing_mark_fops);
+
+       trace_create_file("trace_clock", 0644, d_tracer, tr,
+                         &trace_clock_fops);
+
+       trace_create_file("tracing_on", 0644, d_tracer,
+                           tr, &rb_simple_fops);
+}
+
 static __init int tracer_init_debugfs(void)
 {
        struct dentry *d_tracer;
@@ -4851,14 +5275,10 @@ static __init int tracer_init_debugfs(void)
 
        d_tracer = tracing_init_dentry();
 
-       trace_create_file("trace_options", 0644, d_tracer,
-                       NULL, &tracing_iter_fops);
+       init_tracer_debugfs(&global_trace, d_tracer);
 
        trace_create_file("tracing_cpumask", 0644, d_tracer,
-                       NULL, &tracing_cpumask_fops);
-
-       trace_create_file("trace", 0644, d_tracer,
-                       (void *) TRACE_PIPE_ALL_CPU, &tracing_fops);
+                       &global_trace, &tracing_cpumask_fops);
 
        trace_create_file("available_tracers", 0444, d_tracer,
                        &global_trace, &show_traces_fops);
@@ -4877,39 +5297,25 @@ static __init int tracer_init_debugfs(void)
        trace_create_file("README", 0444, d_tracer,
                        NULL, &tracing_readme_fops);
 
-       trace_create_file("trace_pipe", 0444, d_tracer,
-                       (void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops);
-
-       trace_create_file("buffer_size_kb", 0644, d_tracer,
-                       (void *) RING_BUFFER_ALL_CPUS, &tracing_entries_fops);
-
-       trace_create_file("buffer_total_size_kb", 0444, d_tracer,
-                       &global_trace, &tracing_total_entries_fops);
-
-       trace_create_file("free_buffer", 0644, d_tracer,
-                       &global_trace, &tracing_free_buffer_fops);
-
-       trace_create_file("trace_marker", 0220, d_tracer,
-                       NULL, &tracing_mark_fops);
-
        trace_create_file("saved_cmdlines", 0444, d_tracer,
                        NULL, &tracing_saved_cmdlines_fops);
 
-       trace_create_file("trace_clock", 0644, d_tracer, NULL,
-                         &trace_clock_fops);
-
-       trace_create_file("tracing_on", 0644, d_tracer,
-                           &global_trace, &rb_simple_fops);
-
 #ifdef CONFIG_DYNAMIC_FTRACE
        trace_create_file("dyn_ftrace_total_info", 0444, d_tracer,
                        &ftrace_update_tot_cnt, &tracing_dyn_info_fops);
 #endif
 
-       create_trace_options_dir();
+#ifdef CONFIG_TRACER_SNAPSHOT
+       trace_create_file("snapshot", 0644, d_tracer,
+                         (void *)&global_trace.trace_cpu, &snapshot_fops);
+#endif
+
+       create_trace_instances(d_tracer);
+
+       create_trace_options_dir(&global_trace);
 
        for_each_tracing_cpu(cpu)
-               tracing_init_debugfs_percpu(cpu);
+               tracing_init_debugfs_percpu(&global_trace, cpu);
 
        return 0;
 }
@@ -4979,8 +5385,8 @@ trace_printk_seq(struct trace_seq *s)
 void trace_init_global_iter(struct trace_iterator *iter)
 {
        iter->tr = &global_trace;
-       iter->trace = current_trace;
-       iter->cpu_file = TRACE_PIPE_ALL_CPU;
+       iter->trace = iter->tr->current_trace;
+       iter->cpu_file = RING_BUFFER_ALL_CPUS;
 }
 
 static void
@@ -5014,10 +5420,11 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
        if (disable_tracing)
                ftrace_kill();
 
+       /* Simulate the iterator */
        trace_init_global_iter(&iter);
 
        for_each_tracing_cpu(cpu) {
-               atomic_inc(&iter.tr->data[cpu]->disabled);
+               atomic_inc(&per_cpu_ptr(iter.tr->data, cpu)->disabled);
        }
 
        old_userobj = trace_flags & TRACE_ITER_SYM_USEROBJ;
@@ -5025,13 +5432,9 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
        /* don't look at user memory in panic mode */
        trace_flags &= ~TRACE_ITER_SYM_USEROBJ;
 
-       /* Simulate the iterator */
-       iter.tr = &global_trace;
-       iter.trace = current_trace;
-
        switch (oops_dump_mode) {
        case DUMP_ALL:
-               iter.cpu_file = TRACE_PIPE_ALL_CPU;
+               iter.cpu_file = RING_BUFFER_ALL_CPUS;
                break;
        case DUMP_ORIG:
                iter.cpu_file = raw_smp_processor_id();
@@ -5040,7 +5443,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
                goto out_enable;
        default:
                printk(KERN_TRACE "Bad dumping mode, switching to all CPUs dump\n");
-               iter.cpu_file = TRACE_PIPE_ALL_CPU;
+               iter.cpu_file = RING_BUFFER_ALL_CPUS;
        }
 
        printk(KERN_TRACE "Dumping ftrace buffer:\n");
@@ -5089,7 +5492,7 @@ __ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode)
                trace_flags |= old_userobj;
 
                for_each_tracing_cpu(cpu) {
-                       atomic_dec(&iter.tr->data[cpu]->disabled);
+                       atomic_dec(&per_cpu_ptr(iter.tr->data, cpu)->disabled);
                }
                tracing_on();
        }
@@ -5136,6 +5539,8 @@ __init static int tracer_alloc_buffers(void)
        cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
        cpumask_copy(tracing_cpumask, cpu_all_mask);
 
+       raw_spin_lock_init(&global_trace.start_lock);
+
        /* TODO: make the number of buffers hot pluggable with CPUS */
        global_trace.buffer = ring_buffer_alloc(ring_buf_size, rb_flags);
        if (!global_trace.buffer) {
@@ -5143,26 +5548,48 @@ __init static int tracer_alloc_buffers(void)
                WARN_ON(1);
                goto out_free_cpumask;
        }
+
+       global_trace.data = alloc_percpu(struct trace_array_cpu);
+
+       if (!global_trace.data) {
+               printk(KERN_ERR "tracer: failed to allocate percpu memory!\n");
+               WARN_ON(1);
+               goto out_free_cpumask;
+       }
+
+       for_each_tracing_cpu(i) {
+               memset(per_cpu_ptr(global_trace.data, i), 0, sizeof(struct trace_array_cpu));
+               per_cpu_ptr(global_trace.data, i)->trace_cpu.cpu = i;
+               per_cpu_ptr(global_trace.data, i)->trace_cpu.tr = &global_trace;
+       }
+
        if (global_trace.buffer_disabled)
                tracing_off();
 
-
 #ifdef CONFIG_TRACER_MAX_TRACE
+       max_tr.data = alloc_percpu(struct trace_array_cpu);
+       if (!max_tr.data) {
+               printk(KERN_ERR "tracer: failed to allocate percpu memory!\n");
+               WARN_ON(1);
+               goto out_free_cpumask;
+       }
        max_tr.buffer = ring_buffer_alloc(1, rb_flags);
+       raw_spin_lock_init(&max_tr.start_lock);
        if (!max_tr.buffer) {
                printk(KERN_ERR "tracer: failed to allocate max ring buffer!\n");
                WARN_ON(1);
                ring_buffer_free(global_trace.buffer);
                goto out_free_cpumask;
        }
-#endif
 
-       /* Allocate the first page for all buffers */
        for_each_tracing_cpu(i) {
-               global_trace.data[i] = &per_cpu(global_trace_cpu, i);
-               max_tr.data[i] = &per_cpu(max_tr_data, i);
+               memset(per_cpu_ptr(max_tr.data, i), 0, sizeof(struct trace_array_cpu));
+               per_cpu_ptr(max_tr.data, i)->trace_cpu.cpu = i;
+               per_cpu_ptr(max_tr.data, i)->trace_cpu.tr = &max_tr;
        }
+#endif
 
+       /* Allocate the first page for all buffers */
        set_buffer_entries(&global_trace,
                           ring_buffer_size(global_trace.buffer, 0));
 #ifdef CONFIG_TRACER_MAX_TRACE
@@ -5173,7 +5600,9 @@ __init static int tracer_alloc_buffers(void)
        init_irq_work(&trace_work_wakeup, trace_wake_up);
 
        register_tracer(&nop_trace);
-       current_trace = &nop_trace;
+
+       global_trace.current_trace = &nop_trace;
+
        /* All seems OK, enable tracing */
        tracing_disabled = 0;
 
@@ -5182,16 +5611,28 @@ __init static int tracer_alloc_buffers(void)
 
        register_die_notifier(&trace_die_notifier);
 
+       global_trace.flags = TRACE_ARRAY_FL_GLOBAL;
+
+       /* Holder for file callbacks */
+       global_trace.trace_cpu.cpu = RING_BUFFER_ALL_CPUS;
+       global_trace.trace_cpu.tr = &global_trace;
+
+       INIT_LIST_HEAD(&global_trace.systems);
+       INIT_LIST_HEAD(&global_trace.events);
+       list_add(&global_trace.list, &ftrace_trace_arrays);
+
        while (trace_boot_options) {
                char *option;
 
                option = strsep(&trace_boot_options, ",");
-               trace_set_options(option);
+               trace_set_options(&global_trace, option);
        }
 
        return 0;
 
 out_free_cpumask:
+       free_percpu(global_trace.data);
+       free_percpu(max_tr.data);
        free_cpumask_var(tracing_cpumask);
 out_free_buffer_mask:
        free_cpumask_var(tracing_buffer_mask);