tracing/core: make the read callbacks reentrants
[linux-2.6-microblaze.git] / kernel / trace / trace.c
index a5e4c0a..d8d899f 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/fs.h>
 #include <linux/kprobes.h>
 #include <linux/writeback.h>
+#include <linux/splice.h>
 
 #include <linux/stacktrace.h>
 #include <linux/ring_buffer.h>
@@ -79,7 +80,7 @@ static int dummy_set_flag(u32 old_flags, u32 bit, int set)
  * of the tracer is successful. But that is the only place that sets
  * this back to zero.
  */
-int tracing_disabled = 1;
+static int tracing_disabled = 1;
 
 static DEFINE_PER_CPU(local_t, ftrace_cpu_disabled);
 
@@ -97,6 +98,9 @@ static inline void ftrace_enable_cpu(void)
 
 static cpumask_var_t __read_mostly     tracing_buffer_mask;
 
+/* Define which cpu buffers are currently read in trace_pipe */
+static cpumask_var_t                   tracing_reader_cpumask;
+
 #define for_each_tracing_cpu(cpu)      \
        for_each_cpu(cpu, tracing_buffer_mask)
 
@@ -335,7 +339,7 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
        data->rt_priority = tsk->rt_priority;
 
        /* record this tasks comm */
-       tracing_record_cmdline(current);
+       tracing_record_cmdline(tsk);
 }
 
 static void
@@ -364,6 +368,25 @@ ssize_t trace_seq_to_user(struct trace_seq *s, char __user *ubuf, size_t cnt)
        return cnt;
 }
 
+ssize_t trace_seq_to_buffer(struct trace_seq *s, void *buf, size_t cnt)
+{
+       int len;
+       void *ret;
+
+       if (s->len <= s->readpos)
+               return -EBUSY;
+
+       len = s->len - s->readpos;
+       if (cnt > len)
+               cnt = len;
+       ret = memcpy(buf, s->buffer + s->readpos, cnt);
+       if (!ret)
+               return -EFAULT;
+
+       s->readpos += len;
+       return cnt;
+}
+
 static void
 trace_print_seq(struct seq_file *m, struct trace_seq *s)
 {
@@ -439,6 +462,8 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
  * Register a new plugin tracer.
  */
 int register_tracer(struct tracer *type)
+__releases(kernel_lock)
+__acquires(kernel_lock)
 {
        struct tracer *t;
        int len;
@@ -477,6 +502,9 @@ int register_tracer(struct tracer *type)
        else
                if (!type->flags->opts)
                        type->flags->opts = dummy_tracer_opt;
+       if (!type->wait_pipe)
+               type->wait_pipe = default_wait_pipe;
+
 
 #ifdef CONFIG_FTRACE_STARTUP_TEST
        if (type->selftest && !tracing_selftest_disabled) {
@@ -522,23 +550,24 @@ int register_tracer(struct tracer *type)
        tracing_selftest_running = false;
        mutex_unlock(&trace_types_lock);
 
-       if (!ret && default_bootup_tracer) {
-               if (!strncmp(default_bootup_tracer, type->name,
-                            BOOTUP_TRACER_SIZE)) {
-                       printk(KERN_INFO "Starting tracer '%s'\n",
-                              type->name);
-                       /* Do we want this tracer to start on bootup? */
-                       tracing_set_tracer(type->name);
-                       default_bootup_tracer = NULL;
-                       /* disable other selftests, since this will break it. */
-                       tracing_selftest_disabled = 1;
+       if (ret || !default_bootup_tracer)
+               goto out_unlock;
+
+       if (strncmp(default_bootup_tracer, type->name, BOOTUP_TRACER_SIZE))
+               goto out_unlock;
+
+       printk(KERN_INFO "Starting tracer '%s'\n", type->name);
+       /* Do we want this tracer to start on bootup? */
+       tracing_set_tracer(type->name);
+       default_bootup_tracer = NULL;
+       /* disable other selftests, since this will break it. */
+       tracing_selftest_disabled = 1;
 #ifdef CONFIG_FTRACE_STARTUP_TEST
-                       printk(KERN_INFO "Disabling FTRACE selftests due"
-                              " to running tracer '%s'\n", type->name);
+       printk(KERN_INFO "Disabling FTRACE selftests due to running tracer '%s'\n",
+              type->name);
 #endif
-               }
-       }
 
+ out_unlock:
        lock_kernel();
        return ret;
 }
@@ -558,6 +587,15 @@ void unregister_tracer(struct tracer *type)
 
  found:
        *t = (*t)->next;
+
+       if (type == current_trace && tracer_enabled) {
+               tracer_enabled = 0;
+               tracing_stop();
+               if (current_trace->stop)
+                       current_trace->stop(&global_trace);
+               current_trace = &nop_trace;
+       }
+
        if (strlen(type->name) != max_tracer_type_len)
                goto out;
 
@@ -596,7 +634,7 @@ static int cmdline_idx;
 static DEFINE_SPINLOCK(trace_cmdline_lock);
 
 /* temporary disable recording */
-atomic_t trace_record_cmdline_disabled __read_mostly;
+static atomic_t trace_record_cmdline_disabled __read_mostly;
 
 static void trace_init_cmdlines(void)
 {
@@ -775,78 +813,100 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
                (need_resched() ? TRACE_FLAG_NEED_RESCHED : 0);
 }
 
+struct ring_buffer_event *trace_buffer_lock_reserve(struct trace_array *tr,
+                                                   unsigned char type,
+                                                   unsigned long len,
+                                                   unsigned long flags, int pc)
+{
+       struct ring_buffer_event *event;
+
+       event = ring_buffer_lock_reserve(tr->buffer, len);
+       if (event != NULL) {
+               struct trace_entry *ent = ring_buffer_event_data(event);
+
+               tracing_generic_entry_update(ent, flags, pc);
+               ent->type = type;
+       }
+
+       return event;
+}
+static void ftrace_trace_stack(struct trace_array *tr,
+                              unsigned long flags, int skip, int pc);
+static void ftrace_trace_userstack(struct trace_array *tr,
+                                  unsigned long flags, int pc);
+
+void trace_buffer_unlock_commit(struct trace_array *tr,
+                               struct ring_buffer_event *event,
+                               unsigned long flags, int pc)
+{
+       ring_buffer_unlock_commit(tr->buffer, event);
+
+       ftrace_trace_stack(tr, flags, 6, pc);
+       ftrace_trace_userstack(tr, flags, pc);
+       trace_wake_up();
+}
+
 void
-trace_function(struct trace_array *tr, struct trace_array_cpu *data,
+trace_function(struct trace_array *tr,
               unsigned long ip, unsigned long parent_ip, unsigned long flags,
               int pc)
 {
        struct ring_buffer_event *event;
        struct ftrace_entry *entry;
-       unsigned long irq_flags;
 
        /* If we are reading the ring buffer, don't trace */
        if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
                return;
 
-       event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
-                                        &irq_flags);
+       event = trace_buffer_lock_reserve(tr, TRACE_FN, sizeof(*entry),
+                                         flags, pc);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags, pc);
-       entry->ent.type                 = TRACE_FN;
        entry->ip                       = ip;
        entry->parent_ip                = parent_ip;
-       ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+       ring_buffer_unlock_commit(tr->buffer, event);
 }
 
 #ifdef CONFIG_FUNCTION_GRAPH_TRACER
 static void __trace_graph_entry(struct trace_array *tr,
-                               struct trace_array_cpu *data,
                                struct ftrace_graph_ent *trace,
                                unsigned long flags,
                                int pc)
 {
        struct ring_buffer_event *event;
        struct ftrace_graph_ent_entry *entry;
-       unsigned long irq_flags;
 
        if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
                return;
 
-       event = ring_buffer_lock_reserve(global_trace.buffer, sizeof(*entry),
-                                        &irq_flags);
+       event = trace_buffer_lock_reserve(&global_trace, TRACE_GRAPH_ENT,
+                                         sizeof(*entry), flags, pc);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags, pc);
-       entry->ent.type                 = TRACE_GRAPH_ENT;
        entry->graph_ent                        = *trace;
-       ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
+       ring_buffer_unlock_commit(global_trace.buffer, event);
 }
 
 static void __trace_graph_return(struct trace_array *tr,
-                               struct trace_array_cpu *data,
                                struct ftrace_graph_ret *trace,
                                unsigned long flags,
                                int pc)
 {
        struct ring_buffer_event *event;
        struct ftrace_graph_ret_entry *entry;
-       unsigned long irq_flags;
 
        if (unlikely(local_read(&__get_cpu_var(ftrace_cpu_disabled))))
                return;
 
-       event = ring_buffer_lock_reserve(global_trace.buffer, sizeof(*entry),
-                                        &irq_flags);
+       event = trace_buffer_lock_reserve(&global_trace, TRACE_GRAPH_RET,
+                                         sizeof(*entry), flags, pc);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags, pc);
-       entry->ent.type                 = TRACE_GRAPH_RET;
        entry->ret                              = *trace;
-       ring_buffer_unlock_commit(global_trace.buffer, event, irq_flags);
+       ring_buffer_unlock_commit(global_trace.buffer, event);
 }
 #endif
 
@@ -856,11 +916,10 @@ ftrace(struct trace_array *tr, struct trace_array_cpu *data,
        int pc)
 {
        if (likely(!atomic_read(&data->disabled)))
-               trace_function(tr, data, ip, parent_ip, flags, pc);
+               trace_function(tr, ip, parent_ip, flags, pc);
 }
 
 static void __ftrace_trace_stack(struct trace_array *tr,
-                                struct trace_array_cpu *data,
                                 unsigned long flags,
                                 int skip, int pc)
 {
@@ -868,16 +927,12 @@ static void __ftrace_trace_stack(struct trace_array *tr,
        struct ring_buffer_event *event;
        struct stack_entry *entry;
        struct stack_trace trace;
-       unsigned long irq_flags;
 
-       event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
-                                        &irq_flags);
+       event = trace_buffer_lock_reserve(tr, TRACE_STACK,
+                                         sizeof(*entry), flags, pc);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags, pc);
-       entry->ent.type         = TRACE_STACK;
-
        memset(&entry->caller, 0, sizeof(entry->caller));
 
        trace.nr_entries        = 0;
@@ -886,49 +941,43 @@ static void __ftrace_trace_stack(struct trace_array *tr,
        trace.entries           = entry->caller;
 
        save_stack_trace(&trace);
-       ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+       ring_buffer_unlock_commit(tr->buffer, event);
 #endif
 }
 
 static void ftrace_trace_stack(struct trace_array *tr,
-                              struct trace_array_cpu *data,
                               unsigned long flags,
                               int skip, int pc)
 {
        if (!(trace_flags & TRACE_ITER_STACKTRACE))
                return;
 
-       __ftrace_trace_stack(tr, data, flags, skip, pc);
+       __ftrace_trace_stack(tr, flags, skip, pc);
 }
 
 void __trace_stack(struct trace_array *tr,
-                  struct trace_array_cpu *data,
                   unsigned long flags,
                   int skip, int pc)
 {
-       __ftrace_trace_stack(tr, data, flags, skip, pc);
+       __ftrace_trace_stack(tr, flags, skip, pc);
 }
 
 static void ftrace_trace_userstack(struct trace_array *tr,
-                  struct trace_array_cpu *data,
-                  unsigned long flags, int pc)
+                                  unsigned long flags, int pc)
 {
 #ifdef CONFIG_STACKTRACE
        struct ring_buffer_event *event;
        struct userstack_entry *entry;
        struct stack_trace trace;
-       unsigned long irq_flags;
 
        if (!(trace_flags & TRACE_ITER_USERSTACKTRACE))
                return;
 
-       event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
-                                        &irq_flags);
+       event = trace_buffer_lock_reserve(tr, TRACE_USER_STACK,
+                                         sizeof(*entry), flags, pc);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags, pc);
-       entry->ent.type         = TRACE_USER_STACK;
 
        memset(&entry->caller, 0, sizeof(entry->caller));
 
@@ -938,70 +987,58 @@ static void ftrace_trace_userstack(struct trace_array *tr,
        trace.entries           = entry->caller;
 
        save_stack_trace_user(&trace);
-       ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+       ring_buffer_unlock_commit(tr->buffer, event);
 #endif
 }
 
-void __trace_userstack(struct trace_array *tr,
-                  struct trace_array_cpu *data,
-                  unsigned long flags)
+#ifdef UNUSED
+static void __trace_userstack(struct trace_array *tr, unsigned long flags)
 {
-       ftrace_trace_userstack(tr, data, flags, preempt_count());
+       ftrace_trace_userstack(tr, flags, preempt_count());
 }
+#endif /* UNUSED */
 
 static void
-ftrace_trace_special(void *__tr, void *__data,
+ftrace_trace_special(void *__tr,
                     unsigned long arg1, unsigned long arg2, unsigned long arg3,
                     int pc)
 {
        struct ring_buffer_event *event;
-       struct trace_array_cpu *data = __data;
        struct trace_array *tr = __tr;
        struct special_entry *entry;
-       unsigned long irq_flags;
 
-       event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
-                                        &irq_flags);
+       event = trace_buffer_lock_reserve(tr, TRACE_SPECIAL,
+                                         sizeof(*entry), 0, pc);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, 0, pc);
-       entry->ent.type                 = TRACE_SPECIAL;
        entry->arg1                     = arg1;
        entry->arg2                     = arg2;
        entry->arg3                     = arg3;
-       ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
-       ftrace_trace_stack(tr, data, irq_flags, 4, pc);
-       ftrace_trace_userstack(tr, data, irq_flags, pc);
-
-       trace_wake_up();
+       trace_buffer_unlock_commit(tr, event, 0, pc);
 }
 
 void
 __trace_special(void *__tr, void *__data,
                unsigned long arg1, unsigned long arg2, unsigned long arg3)
 {
-       ftrace_trace_special(__tr, __data, arg1, arg2, arg3, preempt_count());
+       ftrace_trace_special(__tr, arg1, arg2, arg3, preempt_count());
 }
 
 void
 tracing_sched_switch_trace(struct trace_array *tr,
-                          struct trace_array_cpu *data,
                           struct task_struct *prev,
                           struct task_struct *next,
                           unsigned long flags, int pc)
 {
        struct ring_buffer_event *event;
        struct ctx_switch_entry *entry;
-       unsigned long irq_flags;
 
-       event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
-                                          &irq_flags);
+       event = trace_buffer_lock_reserve(tr, TRACE_CTX,
+                                         sizeof(*entry), flags, pc);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags, pc);
-       entry->ent.type                 = TRACE_CTX;
        entry->prev_pid                 = prev->pid;
        entry->prev_prio                = prev->prio;
        entry->prev_state               = prev->state;
@@ -1009,29 +1046,23 @@ tracing_sched_switch_trace(struct trace_array *tr,
        entry->next_prio                = next->prio;
        entry->next_state               = next->state;
        entry->next_cpu = task_cpu(next);
-       ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
-       ftrace_trace_stack(tr, data, flags, 5, pc);
-       ftrace_trace_userstack(tr, data, flags, pc);
+       trace_buffer_unlock_commit(tr, event, flags, pc);
 }
 
 void
 tracing_sched_wakeup_trace(struct trace_array *tr,
-                          struct trace_array_cpu *data,
                           struct task_struct *wakee,
                           struct task_struct *curr,
                           unsigned long flags, int pc)
 {
        struct ring_buffer_event *event;
        struct ctx_switch_entry *entry;
-       unsigned long irq_flags;
 
-       event = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
-                                          &irq_flags);
+       event = trace_buffer_lock_reserve(tr, TRACE_WAKE,
+                                         sizeof(*entry), flags, pc);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags, pc);
-       entry->ent.type                 = TRACE_WAKE;
        entry->prev_pid                 = curr->pid;
        entry->prev_prio                = curr->prio;
        entry->prev_state               = curr->state;
@@ -1039,11 +1070,10 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
        entry->next_prio                = wakee->prio;
        entry->next_state               = wakee->state;
        entry->next_cpu                 = task_cpu(wakee);
-       ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
-       ftrace_trace_stack(tr, data, flags, 6, pc);
-       ftrace_trace_userstack(tr, data, flags, pc);
 
-       trace_wake_up();
+       ring_buffer_unlock_commit(tr->buffer, event);
+       ftrace_trace_stack(tr, flags, 6, pc);
+       ftrace_trace_userstack(tr, flags, pc);
 }
 
 void
@@ -1064,7 +1094,7 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3)
        data = tr->data[cpu];
 
        if (likely(atomic_inc_return(&data->disabled) == 1))
-               ftrace_trace_special(tr, data, arg1, arg2, arg3, pc);
+               ftrace_trace_special(tr, arg1, arg2, arg3, pc);
 
        atomic_dec(&data->disabled);
        local_irq_restore(flags);
@@ -1092,7 +1122,7 @@ int trace_graph_entry(struct ftrace_graph_ent *trace)
        disabled = atomic_inc_return(&data->disabled);
        if (likely(disabled == 1)) {
                pc = preempt_count();
-               __trace_graph_entry(tr, data, trace, flags, pc);
+               __trace_graph_entry(tr, trace, flags, pc);
        }
        /* Only do the atomic if it is not already set */
        if (!test_tsk_trace_graph(current))
@@ -1118,7 +1148,7 @@ void trace_graph_return(struct ftrace_graph_ret *trace)
        disabled = atomic_inc_return(&data->disabled);
        if (likely(disabled == 1)) {
                pc = preempt_count();
-               __trace_graph_return(tr, data, trace, flags, pc);
+               __trace_graph_return(tr, trace, flags, pc);
        }
        if (!trace->depth)
                clear_tsk_trace_graph(current);
@@ -1168,10 +1198,25 @@ __find_next_entry(struct trace_iterator *iter, int *ent_cpu, u64 *ent_ts)
 {
        struct ring_buffer *buffer = iter->tr->buffer;
        struct trace_entry *ent, *next = NULL;
+       int cpu_file = iter->cpu_file;
        u64 next_ts = 0, ts;
        int next_cpu = -1;
        int 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 (ring_buffer_empty_cpu(buffer, cpu_file))
+                       return NULL;
+               ent = peek_next_entry(iter, cpu_file, ent_ts);
+               if (ent_cpu)
+                       *ent_cpu = cpu_file;
+
+               return ent;
+       }
+
        for_each_tracing_cpu(cpu) {
 
                if (ring_buffer_empty_cpu(buffer, cpu))
@@ -1249,19 +1294,32 @@ static void *s_next(struct seq_file *m, void *v, loff_t *pos)
        return ent;
 }
 
+/*
+ * No necessary locking here. The worst thing which can
+ * happen is loosing events consumed at the same time
+ * by a trace_pipe reader.
+ * Other than that, we don't risk to crash the ring buffer
+ * because it serializes the readers.
+ *
+ * The current tracer is copied to avoid a global locking
+ * all around.
+ */
 static void *s_start(struct seq_file *m, loff_t *pos)
 {
        struct trace_iterator *iter = m->private;
+       static struct tracer *old_tracer;
+       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 */
        mutex_lock(&trace_types_lock);
-
-       if (!current_trace || current_trace != iter->trace) {
-               mutex_unlock(&trace_types_lock);
-               return NULL;
+       if (unlikely(old_tracer != current_trace && current_trace)) {
+               old_tracer = current_trace;
+               *iter->trace = *current_trace;
        }
+       mutex_unlock(&trace_types_lock);
 
        atomic_inc(&trace_record_cmdline_disabled);
 
@@ -1272,9 +1330,12 @@ static void *s_start(struct seq_file *m, loff_t *pos)
 
                ftrace_disable_cpu();
 
-               for_each_tracing_cpu(cpu) {
-                       ring_buffer_iter_reset(iter->buffer_iter[cpu]);
-               }
+               if (cpu_file == TRACE_PIPE_ALL_CPU) {
+                       for_each_tracing_cpu(cpu)
+                               ring_buffer_iter_reset(iter->buffer_iter[cpu]);
+               } else
+                       ring_buffer_iter_reset(iter->buffer_iter[cpu_file]);
+
 
                ftrace_enable_cpu();
 
@@ -1292,7 +1353,6 @@ static void *s_start(struct seq_file *m, loff_t *pos)
 static void s_stop(struct seq_file *m, void *p)
 {
        atomic_dec(&trace_record_cmdline_disabled);
-       mutex_unlock(&trace_types_lock);
 }
 
 static void print_lat_help_header(struct seq_file *m)
@@ -1531,7 +1591,7 @@ static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
 
        if (trace_flags & TRACE_ITER_CONTEXT_INFO) {
                SEQ_PUT_FIELD_RET(s, entry->pid);
-               SEQ_PUT_FIELD_RET(s, entry->cpu);
+               SEQ_PUT_FIELD_RET(s, iter->cpu);
                SEQ_PUT_FIELD_RET(s, iter->ts);
        }
 
@@ -1626,6 +1686,7 @@ static struct seq_operations tracer_seq_ops = {
 static struct trace_iterator *
 __tracing_open(struct inode *inode, struct file *file, int *ret)
 {
+       long cpu_file = (long) inode->i_private;
        struct trace_iterator *iter;
        struct seq_file *m;
        int cpu;
@@ -1641,13 +1702,26 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
                goto out;
        }
 
+       /*
+        * We make a copy of the current tracer to avoid concurrent
+        * changes on it while we are reading.
+        */
        mutex_lock(&trace_types_lock);
+       iter->trace = kzalloc(sizeof(*iter->trace), GFP_KERNEL);
+       if (!iter->trace) {
+               *ret = -ENOMEM;
+               goto fail;
+       }
+       if (current_trace)
+               *iter->trace = *current_trace;
+
        if (current_trace && current_trace->print_max)
                iter->tr = &max_tr;
        else
-               iter->tr = inode->i_private;
-       iter->trace = current_trace;
+               iter->tr = &global_trace;
        iter->pos = -1;
+       mutex_init(&iter->mutex);
+       iter->cpu_file = cpu_file;
 
        /* Notify the tracer early; before we stop tracing. */
        if (iter->trace && iter->trace->open)
@@ -1657,14 +1731,22 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
        if (ring_buffer_overruns(iter->tr->buffer))
                iter->iter_flags |= TRACE_FILE_ANNOTATE;
 
+       if (iter->cpu_file == TRACE_PIPE_ALL_CPU) {
+               for_each_tracing_cpu(cpu) {
 
-       for_each_tracing_cpu(cpu) {
+                       iter->buffer_iter[cpu] =
+                               ring_buffer_read_start(iter->tr->buffer, cpu);
 
+                       if (!iter->buffer_iter[cpu])
+                               goto fail_buffer;
+               }
+       } else {
+               cpu = iter->cpu_file;
                iter->buffer_iter[cpu] =
-                       ring_buffer_read_start(iter->tr->buffer, cpu);
+                               ring_buffer_read_start(iter->tr->buffer, cpu);
 
                if (!iter->buffer_iter[cpu])
-                       goto fail_buffer;
+                       goto fail;
        }
 
        /* TODO stop tracer */
@@ -1688,7 +1770,9 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
                if (iter->buffer_iter[cpu])
                        ring_buffer_read_finish(iter->buffer_iter[cpu]);
        }
+ fail:
        mutex_unlock(&trace_types_lock);
+       kfree(iter->trace);
        kfree(iter);
 
        return ERR_PTR(-ENOMEM);
@@ -1703,7 +1787,7 @@ int tracing_open_generic(struct inode *inode, struct file *filp)
        return 0;
 }
 
-int tracing_release(struct inode *inode, struct file *file)
+static int tracing_release(struct inode *inode, struct file *file)
 {
        struct seq_file *m = (struct seq_file *)file->private_data;
        struct trace_iterator *iter = m->private;
@@ -1723,6 +1807,8 @@ int tracing_release(struct inode *inode, struct file *file)
        mutex_unlock(&trace_types_lock);
 
        seq_release(inode, file);
+       mutex_destroy(&iter->mutex);
+       kfree(iter->trace);
        kfree(iter);
        return 0;
 }
@@ -1946,7 +2032,7 @@ tracing_trace_options_read(struct file *filp, char __user *ubuf,
        struct tracer_opt *trace_opts = current_trace->flags->opts;
 
 
-       /* calulate max size */
+       /* calculate max size */
        for (i = 0; trace_options[i]; i++) {
                len += strlen(trace_options[i]);
                len += 3; /* "no" and space */
@@ -2128,7 +2214,7 @@ tracing_ctrl_write(struct file *filp, const char __user *ubuf,
 {
        struct trace_array *tr = filp->private_data;
        char buf[64];
-       long val;
+       unsigned long val;
        int ret;
 
        if (cnt >= sizeof(buf))
@@ -2183,6 +2269,12 @@ tracing_set_trace_read(struct file *filp, char __user *ubuf,
        return simple_read_from_buffer(ubuf, cnt, ppos, buf, r);
 }
 
+int tracer_init(struct tracer *t, struct trace_array *tr)
+{
+       tracing_reset_online_cpus(tr);
+       return t->init(tr);
+}
+
 static int tracing_set_tracer(const char *buf)
 {
        struct trace_array *tr = &global_trace;
@@ -2207,7 +2299,7 @@ static int tracing_set_tracer(const char *buf)
 
        current_trace = t;
        if (t->init) {
-               ret = t->init(tr);
+               ret = tracer_init(t, tr);
                if (ret)
                        goto out;
        }
@@ -2270,9 +2362,9 @@ static ssize_t
 tracing_max_lat_write(struct file *filp, const char __user *ubuf,
                      size_t cnt, loff_t *ppos)
 {
-       long *ptr = filp->private_data;
+       unsigned long *ptr = filp->private_data;
        char buf[64];
-       long val;
+       unsigned long val;
        int ret;
 
        if (cnt >= sizeof(buf))
@@ -2292,54 +2384,96 @@ tracing_max_lat_write(struct file *filp, const char __user *ubuf,
        return cnt;
 }
 
-static atomic_t tracing_reader;
-
 static int tracing_open_pipe(struct inode *inode, struct file *filp)
 {
+       long cpu_file = (long) inode->i_private;
        struct trace_iterator *iter;
+       int ret = 0;
 
        if (tracing_disabled)
                return -ENODEV;
 
-       /* We only allow for reader of the pipe */
-       if (atomic_inc_return(&tracing_reader) != 1) {
-               atomic_dec(&tracing_reader);
-               return -EBUSY;
+       mutex_lock(&trace_types_lock);
+
+       /* We only allow one reader per cpu */
+       if (cpu_file == TRACE_PIPE_ALL_CPU) {
+               if (!cpumask_empty(tracing_reader_cpumask)) {
+                       ret = -EBUSY;
+                       goto out;
+               }
+               cpumask_setall(tracing_reader_cpumask);
+       } else {
+               if (!cpumask_test_cpu(cpu_file, tracing_reader_cpumask))
+                       cpumask_set_cpu(cpu_file, tracing_reader_cpumask);
+               else {
+                       ret = -EBUSY;
+                       goto out;
+               }
        }
 
        /* create a buffer to store the information to pass to userspace */
        iter = kzalloc(sizeof(*iter), GFP_KERNEL);
-       if (!iter)
-               return -ENOMEM;
+       if (!iter) {
+               ret = -ENOMEM;
+               goto out;
+       }
 
-       if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {
-               kfree(iter);
-               return -ENOMEM;
+       /*
+        * We make a copy of the current tracer to avoid concurrent
+        * changes on it while we are reading.
+        */
+       iter->trace = kmalloc(sizeof(*iter->trace), GFP_KERNEL);
+       if (!iter->trace) {
+               ret = -ENOMEM;
+               goto fail;
        }
+       if (current_trace)
+               *iter->trace = *current_trace;
 
-       mutex_lock(&trace_types_lock);
+       if (!alloc_cpumask_var(&iter->started, GFP_KERNEL)) {
+               ret = -ENOMEM;
+               goto fail;
+       }
 
        /* trace pipe does not show start of buffer */
        cpumask_setall(iter->started);
 
+       iter->cpu_file = cpu_file;
        iter->tr = &global_trace;
-       iter->trace = current_trace;
+       mutex_init(&iter->mutex);
        filp->private_data = iter;
 
        if (iter->trace->pipe_open)
                iter->trace->pipe_open(iter);
+
+out:
        mutex_unlock(&trace_types_lock);
+       return ret;
 
-       return 0;
+fail:
+       kfree(iter->trace);
+       kfree(iter);
+       mutex_unlock(&trace_types_lock);
+       return ret;
 }
 
 static int tracing_release_pipe(struct inode *inode, struct file *file)
 {
        struct trace_iterator *iter = file->private_data;
 
+       mutex_lock(&trace_types_lock);
+
+       if (iter->cpu_file == TRACE_PIPE_ALL_CPU)
+               cpumask_clear(tracing_reader_cpumask);
+       else
+               cpumask_clear_cpu(iter->cpu_file, tracing_reader_cpumask);
+
+       mutex_unlock(&trace_types_lock);
+
        free_cpumask_var(iter->started);
+       mutex_destroy(&iter->mutex);
+       kfree(iter->trace);
        kfree(iter);
-       atomic_dec(&tracing_reader);
 
        return 0;
 }
@@ -2365,67 +2499,57 @@ tracing_poll_pipe(struct file *filp, poll_table *poll_table)
        }
 }
 
-/*
- * Consumer reader.
- */
-static ssize_t
-tracing_read_pipe(struct file *filp, char __user *ubuf,
-                 size_t cnt, loff_t *ppos)
+
+void default_wait_pipe(struct trace_iterator *iter)
 {
-       struct trace_iterator *iter = filp->private_data;
-       ssize_t sret;
+       DEFINE_WAIT(wait);
 
-       /* return any leftover data */
-       sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
-       if (sret != -EBUSY)
-               return sret;
+       prepare_to_wait(&trace_wait, &wait, TASK_INTERRUPTIBLE);
 
-       trace_seq_reset(&iter->seq);
+       if (trace_empty(iter))
+               schedule();
 
-       mutex_lock(&trace_types_lock);
-       if (iter->trace->read) {
-               sret = iter->trace->read(iter, filp, ubuf, cnt, ppos);
-               if (sret)
-                       goto out;
-       }
+       finish_wait(&trace_wait, &wait);
+}
+
+/*
+ * This is a make-shift waitqueue.
+ * A tracer might use this callback on some rare cases:
+ *
+ *  1) the current tracer might hold the runqueue lock when it wakes up
+ *     a reader, hence a deadlock (sched, function, and function graph tracers)
+ *  2) the function tracers, trace all functions, we don't want
+ *     the overhead of calling wake_up and friends
+ *     (and tracing them too)
+ *
+ *     Anyway, this is really very primitive wakeup.
+ */
+void poll_wait_pipe(struct trace_iterator *iter)
+{
+       set_current_state(TASK_INTERRUPTIBLE);
+       /* sleep for 100 msecs, and try again. */
+       schedule_timeout(HZ / 10);
+}
+
+/* Must be called with trace_types_lock mutex held. */
+static int tracing_wait_pipe(struct file *filp)
+{
+       struct trace_iterator *iter = filp->private_data;
 
-waitagain:
-       sret = 0;
        while (trace_empty(iter)) {
 
                if ((filp->f_flags & O_NONBLOCK)) {
-                       sret = -EAGAIN;
-                       goto out;
+                       return -EAGAIN;
                }
 
-               /*
-                * This is a make-shift waitqueue. The reason we don't use
-                * an actual wait queue is because:
-                *  1) we only ever have one waiter
-                *  2) the tracing, traces all functions, we don't want
-                *     the overhead of calling wake_up and friends
-                *     (and tracing them too)
-                *     Anyway, this is really very primitive wakeup.
-                */
-               set_current_state(TASK_INTERRUPTIBLE);
-               iter->tr->waiter = current;
-
-               mutex_unlock(&trace_types_lock);
+               mutex_unlock(&iter->mutex);
 
-               /* sleep for 100 msecs, and try again. */
-               schedule_timeout(HZ/10);
+               iter->trace->wait_pipe(iter);
 
-               mutex_lock(&trace_types_lock);
+               mutex_lock(&iter->mutex);
 
-               iter->tr->waiter = NULL;
-
-               if (signal_pending(current)) {
-                       sret = -EINTR;
-                       goto out;
-               }
-
-               if (iter->trace != current_trace)
-                       goto out;
+               if (signal_pending(current))
+                       return -EINTR;
 
                /*
                 * We block until we read something and tracing is disabled.
@@ -2438,13 +2562,59 @@ waitagain:
                 */
                if (!tracer_enabled && iter->pos)
                        break;
+       }
+
+       return 1;
+}
+
+/*
+ * Consumer reader.
+ */
+static ssize_t
+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;
+       ssize_t sret;
+
+       /* return any leftover data */
+       sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
+       if (sret != -EBUSY)
+               return sret;
+
+       trace_seq_reset(&iter->seq);
+
+       /* 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;
+       }
+       mutex_unlock(&trace_types_lock);
 
-               continue;
+       /*
+        * Avoid more than one consumer on a single file descriptor
+        * This is just a matter of traces coherency, the ring buffer itself
+        * is protected.
+        */
+       mutex_lock(&iter->mutex);
+       if (iter->trace->read) {
+               sret = iter->trace->read(iter, filp, ubuf, cnt, ppos);
+               if (sret)
+                       goto out;
        }
 
+waitagain:
+       sret = tracing_wait_pipe(filp);
+       if (sret <= 0)
+               goto out;
+
        /* stop when tracing is finished */
-       if (trace_empty(iter))
+       if (trace_empty(iter)) {
+               sret = 0;
                goto out;
+       }
 
        if (cnt >= PAGE_SIZE)
                cnt = PAGE_SIZE - 1;
@@ -2465,8 +2635,8 @@ waitagain:
                        iter->seq.len = len;
                        break;
                }
-
-               trace_consume(iter);
+               if (ret != TRACE_TYPE_NO_CONSUME)
+                       trace_consume(iter);
 
                if (iter->seq.len >= cnt)
                        break;
@@ -2485,11 +2655,148 @@ waitagain:
                goto waitagain;
 
 out:
-       mutex_unlock(&trace_types_lock);
+       mutex_unlock(&iter->mutex);
 
        return sret;
 }
 
+static void tracing_pipe_buf_release(struct pipe_inode_info *pipe,
+                                    struct pipe_buffer *buf)
+{
+       __free_page(buf->page);
+}
+
+static void tracing_spd_release_pipe(struct splice_pipe_desc *spd,
+                                    unsigned int idx)
+{
+       __free_page(spd->pages[idx]);
+}
+
+static struct pipe_buf_operations tracing_pipe_buf_ops = {
+       .can_merge              = 0,
+       .map                    = generic_pipe_buf_map,
+       .unmap                  = generic_pipe_buf_unmap,
+       .confirm                = generic_pipe_buf_confirm,
+       .release                = tracing_pipe_buf_release,
+       .steal                  = generic_pipe_buf_steal,
+       .get                    = generic_pipe_buf_get,
+};
+
+static size_t
+tracing_fill_pipe_page(size_t rem, struct trace_iterator *iter)
+{
+       size_t count;
+       int ret;
+
+       /* Seq buffer is page-sized, exactly what we need. */
+       for (;;) {
+               count = iter->seq.len;
+               ret = print_trace_line(iter);
+               count = iter->seq.len - count;
+               if (rem < count) {
+                       rem = 0;
+                       iter->seq.len -= count;
+                       break;
+               }
+               if (ret == TRACE_TYPE_PARTIAL_LINE) {
+                       iter->seq.len -= count;
+                       break;
+               }
+
+               trace_consume(iter);
+               rem -= count;
+               if (!find_next_entry_inc(iter)) {
+                       rem = 0;
+                       iter->ent = NULL;
+                       break;
+               }
+       }
+
+       return rem;
+}
+
+static ssize_t tracing_splice_read_pipe(struct file *filp,
+                                       loff_t *ppos,
+                                       struct pipe_inode_info *pipe,
+                                       size_t len,
+                                       unsigned int flags)
+{
+       struct page *pages[PIPE_BUFFERS];
+       struct partial_page partial[PIPE_BUFFERS];
+       struct trace_iterator *iter = filp->private_data;
+       struct splice_pipe_desc spd = {
+               .pages          = pages,
+               .partial        = partial,
+               .nr_pages       = 0, /* This gets updated below. */
+               .flags          = flags,
+               .ops            = &tracing_pipe_buf_ops,
+               .spd_release    = tracing_spd_release_pipe,
+       };
+       static struct tracer *old_tracer;
+       ssize_t ret;
+       size_t rem;
+       unsigned int i;
+
+       /* 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;
+       }
+       mutex_unlock(&trace_types_lock);
+
+       mutex_lock(&iter->mutex);
+
+       if (iter->trace->splice_read) {
+               ret = iter->trace->splice_read(iter, filp,
+                                              ppos, pipe, len, flags);
+               if (ret)
+                       goto out_err;
+       }
+
+       ret = tracing_wait_pipe(filp);
+       if (ret <= 0)
+               goto out_err;
+
+       if (!iter->ent && !find_next_entry_inc(iter)) {
+               ret = -EFAULT;
+               goto out_err;
+       }
+
+       /* Fill as many pages as possible. */
+       for (i = 0, rem = len; i < PIPE_BUFFERS && rem; i++) {
+               pages[i] = alloc_page(GFP_KERNEL);
+               if (!pages[i])
+                       break;
+
+               rem = tracing_fill_pipe_page(rem, iter);
+
+               /* Copy the data into the page, so we can start over. */
+               ret = trace_seq_to_buffer(&iter->seq,
+                                         page_address(pages[i]),
+                                         iter->seq.len);
+               if (ret < 0) {
+                       __free_page(pages[i]);
+                       break;
+               }
+               partial[i].offset = 0;
+               partial[i].len = iter->seq.len;
+
+               trace_seq_reset(&iter->seq);
+       }
+
+       mutex_unlock(&iter->mutex);
+
+       spd.nr_pages = i;
+
+       return splice_to_pipe(pipe, &spd);
+
+out_err:
+       mutex_unlock(&iter->mutex);
+
+       return ret;
+}
+
 static ssize_t
 tracing_entries_read(struct file *filp, char __user *ubuf,
                     size_t cnt, loff_t *ppos)
@@ -2653,6 +2960,7 @@ static struct file_operations tracing_pipe_fops = {
        .open           = tracing_open_pipe,
        .poll           = tracing_poll_pipe,
        .read           = tracing_read_pipe,
+       .splice_read    = tracing_splice_read_pipe,
        .release        = tracing_release_pipe,
 };
 
@@ -2724,6 +3032,59 @@ struct dentry *tracing_init_dentry(void)
        return d_tracer;
 }
 
+static struct dentry *d_percpu;
+
+struct dentry *tracing_dentry_percpu(void)
+{
+       static int once;
+       struct dentry *d_tracer;
+
+       if (d_percpu)
+               return d_percpu;
+
+       d_tracer = tracing_init_dentry();
+
+       if (!d_tracer)
+               return NULL;
+
+       d_percpu = 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;
+       }
+
+       return d_percpu;
+}
+
+static void tracing_init_debugfs_percpu(long cpu)
+{
+       struct dentry *d_percpu = tracing_dentry_percpu();
+       struct dentry *entry;
+       /* strlen(trace_pipe) + MAX(log10(cpu)) + '\0' */
+       char filename[17];
+
+       if (cpu > 999 || cpu < 0)
+               return;
+
+       /* per cpu trace_pipe */
+       sprintf(filename, "trace_pipe%ld", cpu);
+
+       entry = debugfs_create_file(filename, 0444, d_percpu,
+                               (void *) cpu, &tracing_pipe_fops);
+       if (!entry)
+               pr_warning("Could not create debugfs '%s' entry\n", filename);
+
+       /* per cpu trace */
+       sprintf(filename, "trace%ld", cpu);
+
+       entry = debugfs_create_file(filename, 0444, d_percpu,
+                               (void *) cpu, &tracing_fops);
+       if (!entry)
+               pr_warning("Could not create debugfs '%s' entry\n", filename);
+}
+
 #ifdef CONFIG_FTRACE_SELFTEST
 /* Let selftest have access to static functions in this file */
 #include "trace_selftest.c"
@@ -2733,6 +3094,7 @@ static __init int tracer_init_debugfs(void)
 {
        struct dentry *d_tracer;
        struct dentry *entry;
+       int cpu;
 
        d_tracer = tracing_init_dentry();
 
@@ -2751,13 +3113,8 @@ static __init int tracer_init_debugfs(void)
        if (!entry)
                pr_warning("Could not create debugfs 'tracing_cpumask' entry\n");
 
-       entry = debugfs_create_file("latency_trace", 0444, d_tracer,
-                                   &global_trace, &tracing_lt_fops);
-       if (!entry)
-               pr_warning("Could not create debugfs 'latency_trace' entry\n");
-
        entry = debugfs_create_file("trace", 0444, d_tracer,
-                                   &global_trace, &tracing_fops);
+                                (void *) TRACE_PIPE_ALL_CPU, &tracing_fops);
        if (!entry)
                pr_warning("Could not create debugfs 'trace' entry\n");
 
@@ -2788,8 +3145,8 @@ static __init int tracer_init_debugfs(void)
        if (!entry)
                pr_warning("Could not create debugfs 'README' entry\n");
 
-       entry = debugfs_create_file("trace_pipe", 0644, d_tracer,
-                                   NULL, &tracing_pipe_fops);
+       entry = debugfs_create_file("trace_pipe", 0444, d_tracer,
+                       (void *) TRACE_PIPE_ALL_CPU, &tracing_pipe_fops);
        if (!entry)
                pr_warning("Could not create debugfs "
                           "'trace_pipe' entry\n");
@@ -2817,6 +3174,10 @@ static __init int tracer_init_debugfs(void)
 #ifdef CONFIG_SYSPROF_TRACER
        init_tracer_sysprof_debugfs(d_tracer);
 #endif
+
+       for_each_tracing_cpu(cpu)
+               tracing_init_debugfs_percpu(cpu);
+
        return 0;
 }
 
@@ -2851,18 +3212,16 @@ int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
        trace_buf[len] = 0;
 
        size = sizeof(*entry) + len + 1;
-       event = ring_buffer_lock_reserve(tr->buffer, size, &irq_flags);
+       event = trace_buffer_lock_reserve(tr, TRACE_PRINT, size, irq_flags, pc);
        if (!event)
                goto out_unlock;
        entry = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, irq_flags, pc);
-       entry->ent.type                 = TRACE_PRINT;
        entry->ip                       = ip;
        entry->depth                    = depth;
 
        memcpy(&entry->buf, trace_buf, len);
        entry->buf[len] = 0;
-       ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
+       ring_buffer_unlock_commit(tr->buffer, event);
 
  out_unlock:
        spin_unlock_irqrestore(&trace_buf_lock, irq_flags);
@@ -3042,8 +3401,12 @@ __init static int tracer_alloc_buffers(void)
        if (!alloc_cpumask_var(&tracing_cpumask, GFP_KERNEL))
                goto out_free_buffer_mask;
 
+       if (!alloc_cpumask_var(&tracing_reader_cpumask, GFP_KERNEL))
+               goto out_free_tracing_cpumask;
+
        cpumask_copy(tracing_buffer_mask, cpu_possible_mask);
        cpumask_copy(tracing_cpumask, cpu_all_mask);
+       cpumask_clear(tracing_reader_cpumask);
 
        /* TODO: make the number of buffers hot pluggable with CPUS */
        global_trace.buffer = ring_buffer_alloc(trace_buf_size,
@@ -3092,6 +3455,8 @@ __init static int tracer_alloc_buffers(void)
        ret = 0;
 
 out_free_cpumask:
+       free_cpumask_var(tracing_reader_cpumask);
+out_free_tracing_cpumask:
        free_cpumask_var(tracing_cpumask);
 out_free_buffer_mask:
        free_cpumask_var(tracing_buffer_mask);