]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - kernel/trace/trace.c
ftrace: return an error when setting a nonexistent tracer
[linux-2.6-omap-h63xx.git] / kernel / trace / trace.c
index ed9e47c18810e1ea1b8b0101d42d4da72a8ed764..78d56614c95be41f14b44c7ce4a9f90015d6bb8f 100644 (file)
 unsigned long __read_mostly    tracing_max_latency = (cycle_t)ULONG_MAX;
 unsigned long __read_mostly    tracing_thresh;
 
+static DEFINE_PER_CPU(local_t, ftrace_cpu_disabled);
+
+static inline void ftrace_disable_cpu(void)
+{
+       preempt_disable();
+       local_inc(&__get_cpu_var(ftrace_cpu_disabled));
+}
+
+static inline void ftrace_enable_cpu(void)
+{
+       local_dec(&__get_cpu_var(ftrace_cpu_disabled));
+       preempt_enable();
+}
+
 static cpumask_t __read_mostly         tracing_buffer_mask;
 
 #define for_each_tracing_cpu(cpu)      \
@@ -406,7 +420,9 @@ update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
        tr->buffer = max_tr.buffer;
        max_tr.buffer = buf;
 
+       ftrace_disable_cpu();
        ring_buffer_reset(tr->buffer);
+       ftrace_enable_cpu();
 
        __update_max_tr(tr, tsk, cpu);
        __raw_spin_unlock(&ftrace_max_lock);
@@ -428,9 +444,13 @@ update_max_tr_single(struct trace_array *tr, struct task_struct *tsk, int cpu)
        WARN_ON_ONCE(!irqs_disabled());
        __raw_spin_lock(&ftrace_max_lock);
 
+       ftrace_disable_cpu();
+
        ring_buffer_reset(max_tr.buffer);
        ret = ring_buffer_swap_cpu(max_tr.buffer, tr->buffer, cpu);
 
+       ftrace_enable_cpu();
+
        WARN_ON_ONCE(ret);
 
        __update_max_tr(tr, tsk, cpu);
@@ -543,7 +563,9 @@ void unregister_tracer(struct tracer *type)
 
 void tracing_reset(struct trace_array *tr, int cpu)
 {
+       ftrace_disable_cpu();
        ring_buffer_reset_cpu(tr->buffer, cpu);
+       ftrace_enable_cpu();
 }
 
 #define SAVED_CMDLINES 128
@@ -630,12 +652,10 @@ void tracing_record_cmdline(struct task_struct *tsk)
 }
 
 void
-tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags)
+tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags,
+                            int pc)
 {
        struct task_struct *tsk = current;
-       unsigned long pc;
-
-       pc = preempt_count();
 
        entry->preempt_count            = pc & 0xff;
        entry->pid                      = (tsk) ? tsk->pid : 0;
@@ -648,18 +668,23 @@ tracing_generic_entry_update(struct trace_entry *entry, unsigned long flags)
 
 void
 trace_function(struct trace_array *tr, struct trace_array_cpu *data,
-              unsigned long ip, unsigned long parent_ip, unsigned long flags)
+              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);
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags);
+       tracing_generic_entry_update(&entry->ent, flags, pc);
        entry->ent.type                 = TRACE_FN;
        entry->ip                       = ip;
        entry->parent_ip                = parent_ip;
@@ -668,16 +693,17 @@ trace_function(struct trace_array *tr, struct trace_array_cpu *data,
 
 void
 ftrace(struct trace_array *tr, struct trace_array_cpu *data,
-       unsigned long ip, unsigned long parent_ip, unsigned long flags)
+       unsigned long ip, unsigned long parent_ip, unsigned long flags,
+       int pc)
 {
        if (likely(!atomic_read(&data->disabled)))
-               trace_function(tr, data, ip, parent_ip, flags);
+               trace_function(tr, data, ip, parent_ip, flags, pc);
 }
 
-void __trace_stack(struct trace_array *tr,
-                  struct trace_array_cpu *data,
-                  unsigned long flags,
-                  int skip)
+static void ftrace_trace_stack(struct trace_array *tr,
+                              struct trace_array_cpu *data,
+                              unsigned long flags,
+                              int skip, int pc)
 {
        struct ring_buffer_event *event;
        struct stack_entry *entry;
@@ -692,7 +718,7 @@ void __trace_stack(struct trace_array *tr,
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags);
+       tracing_generic_entry_update(&entry->ent, flags, pc);
        entry->ent.type         = TRACE_STACK;
 
        memset(&entry->caller, 0, sizeof(entry->caller));
@@ -706,9 +732,18 @@ void __trace_stack(struct trace_array *tr,
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 }
 
-void
-__trace_special(void *__tr, void *__data,
-               unsigned long arg1, unsigned long arg2, unsigned long arg3)
+void __trace_stack(struct trace_array *tr,
+                  struct trace_array_cpu *data,
+                  unsigned long flags,
+                  int skip)
+{
+       ftrace_trace_stack(tr, data, flags, skip, preempt_count());
+}
+
+static void
+ftrace_trace_special(void *__tr, void *__data,
+                    unsigned long arg1, unsigned long arg2, unsigned long arg3,
+                    int pc)
 {
        struct ring_buffer_event *event;
        struct trace_array_cpu *data = __data;
@@ -721,23 +756,30 @@ __trace_special(void *__tr, void *__data,
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, 0);
+       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);
-       __trace_stack(tr, data, irq_flags, 4);
+       ftrace_trace_stack(tr, data, irq_flags, 4, pc);
 
        trace_wake_up();
 }
 
+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());
+}
+
 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)
+                          unsigned long flags, int pc)
 {
        struct ring_buffer_event *event;
        struct ctx_switch_entry *entry;
@@ -748,7 +790,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags);
+       tracing_generic_entry_update(&entry->ent, flags, pc);
        entry->ent.type                 = TRACE_CTX;
        entry->prev_pid                 = prev->pid;
        entry->prev_prio                = prev->prio;
@@ -758,7 +800,7 @@ tracing_sched_switch_trace(struct trace_array *tr,
        entry->next_state               = next->state;
        entry->next_cpu = task_cpu(next);
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
-       __trace_stack(tr, data, flags, 5);
+       ftrace_trace_stack(tr, data, flags, 5, pc);
 }
 
 void
@@ -766,7 +808,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
                           struct trace_array_cpu *data,
                           struct task_struct *wakee,
                           struct task_struct *curr,
-                          unsigned long flags)
+                          unsigned long flags, int pc)
 {
        struct ring_buffer_event *event;
        struct ctx_switch_entry *entry;
@@ -777,7 +819,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
        if (!event)
                return;
        entry   = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags);
+       tracing_generic_entry_update(&entry->ent, flags, pc);
        entry->ent.type                 = TRACE_WAKE;
        entry->prev_pid                 = curr->pid;
        entry->prev_prio                = curr->prio;
@@ -787,7 +829,7 @@ tracing_sched_wakeup_trace(struct trace_array *tr,
        entry->next_state               = wakee->state;
        entry->next_cpu                 = task_cpu(wakee);
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
-       __trace_stack(tr, data, flags, 6);
+       ftrace_trace_stack(tr, data, flags, 6, pc);
 
        trace_wake_up();
 }
@@ -797,23 +839,21 @@ ftrace_special(unsigned long arg1, unsigned long arg2, unsigned long arg3)
 {
        struct trace_array *tr = &global_trace;
        struct trace_array_cpu *data;
-       unsigned long flags;
-       long disabled;
        int cpu;
+       int pc;
 
        if (tracing_disabled || !tr->ctrl)
                return;
 
-       local_irq_save(flags);
+       pc = preempt_count();
+       preempt_disable_notrace();
        cpu = raw_smp_processor_id();
        data = tr->data[cpu];
-       disabled = atomic_inc_return(&data->disabled);
 
-       if (likely(disabled == 1))
-               __trace_special(tr, data, arg1, arg2, arg3);
+       if (likely(!atomic_read(&data->disabled)))
+               ftrace_trace_special(tr, data, arg1, arg2, arg3, pc);
 
-       atomic_dec(&data->disabled);
-       local_irq_restore(flags);
+       preempt_enable_notrace();
 }
 
 #ifdef CONFIG_FTRACE
@@ -824,7 +864,8 @@ function_trace_call(unsigned long ip, unsigned long parent_ip)
        struct trace_array_cpu *data;
        unsigned long flags;
        long disabled;
-       int cpu;
+       int cpu, resched;
+       int pc;
 
        if (unlikely(!ftrace_function_enabled))
                return;
@@ -832,16 +873,22 @@ function_trace_call(unsigned long ip, unsigned long parent_ip)
        if (skip_trace(ip))
                return;
 
-       local_irq_save(flags);
+       pc = preempt_count();
+       resched = need_resched();
+       preempt_disable_notrace();
+       local_save_flags(flags);
        cpu = raw_smp_processor_id();
        data = tr->data[cpu];
        disabled = atomic_inc_return(&data->disabled);
 
        if (likely(disabled == 1))
-               trace_function(tr, data, ip, parent_ip, flags);
+               trace_function(tr, data, ip, parent_ip, flags, pc);
 
        atomic_dec(&data->disabled);
-       local_irq_restore(flags);
+       if (resched)
+               preempt_enable_no_resched_notrace();
+       else
+               preempt_enable_notrace();
 }
 
 static struct ftrace_ops trace_ops __read_mostly =
@@ -870,8 +917,14 @@ enum trace_file_type {
 
 static void trace_iterator_increment(struct trace_iterator *iter, int cpu)
 {
+       /* Don't allow ftrace to trace into the ring buffers */
+       ftrace_disable_cpu();
+
        iter->idx++;
-       ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
+       if (iter->buffer_iter[iter->cpu])
+               ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
+
+       ftrace_enable_cpu();
 }
 
 static struct trace_entry *
@@ -880,9 +933,19 @@ peek_next_entry(struct trace_iterator *iter, int cpu, u64 *ts)
        struct ring_buffer_event *event;
        struct ring_buffer_iter *buf_iter = iter->buffer_iter[cpu];
 
-       event = ring_buffer_iter_peek(buf_iter, ts);
+       /* Don't allow ftrace to trace into the ring buffers */
+       ftrace_disable_cpu();
+
+       if (buf_iter)
+               event = ring_buffer_iter_peek(buf_iter, ts);
+       else
+               event = ring_buffer_peek(iter->tr->buffer, cpu, ts);
+
+       ftrace_enable_cpu();
+
        return event ? ring_buffer_event_data(event) : NULL;
 }
+
 static struct trace_entry *
 __find_next_entry(struct trace_iterator *iter, int *ent_cpu, u64 *ent_ts)
 {
@@ -938,7 +1001,10 @@ static void *find_next_entry_inc(struct trace_iterator *iter)
 
 static void trace_consume(struct trace_iterator *iter)
 {
+       /* Don't allow ftrace to trace into the ring buffers */
+       ftrace_disable_cpu();
        ring_buffer_consume(iter->tr->buffer, iter->cpu, &iter->ts);
+       ftrace_enable_cpu();
 }
 
 static void *s_next(struct seq_file *m, void *v, loff_t *pos)
@@ -991,10 +1057,14 @@ static void *s_start(struct seq_file *m, loff_t *pos)
                iter->cpu = 0;
                iter->idx = -1;
 
+               ftrace_disable_cpu();
+
                for_each_tracing_cpu(cpu) {
                        ring_buffer_iter_reset(iter->buffer_iter[cpu]);
                }
 
+               ftrace_enable_cpu();
+
                for (p = iter; p && l < *pos; p = s_next(m, p, &l))
                        ;
 
@@ -1242,7 +1312,16 @@ void trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter)
                cont = (struct trace_field_cont *)ent;
                if (ok)
                        ok = (trace_seq_printf(s, "%s", cont->buf) > 0);
-               ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
+
+               ftrace_disable_cpu();
+
+               if (iter->buffer_iter[iter->cpu])
+                       ring_buffer_read(iter->buffer_iter[iter->cpu], NULL);
+               else
+                       ring_buffer_consume(iter->tr->buffer, iter->cpu, NULL);
+
+               ftrace_enable_cpu();
+
                ent = peek_next_entry(iter, iter->cpu, NULL);
        } while (ent && ent->type == TRACE_CONT);
 
@@ -1250,7 +1329,7 @@ void trace_seq_print_cont(struct trace_seq *s, struct trace_iterator *iter)
                trace_seq_putc(s, '\n');
 }
 
-static int
+static enum print_line_t
 print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
 {
        struct trace_seq *s = &iter->seq;
@@ -1267,7 +1346,7 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
        unsigned state;
 
        if (entry->type == TRACE_CONT)
-               return 1;
+               return TRACE_TYPE_HANDLED;
 
        next_entry = find_next_entry(iter, NULL, &next_ts);
        if (!next_entry)
@@ -1292,7 +1371,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
        }
        switch (entry->type) {
        case TRACE_FN: {
-               struct ftrace_entry *field = (struct ftrace_entry *)entry;
+               struct ftrace_entry *field;
+
+               trace_assign_type(field, entry);
 
                seq_print_ip_sym(s, field->ip, sym_flags);
                trace_seq_puts(s, " (");
@@ -1305,8 +1386,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
        }
        case TRACE_CTX:
        case TRACE_WAKE: {
-               struct ctx_switch_entry *field =
-                       (struct ctx_switch_entry *)entry;
+               struct ctx_switch_entry *field;
+
+               trace_assign_type(field, entry);
 
                T = field->next_state < sizeof(state_to_char) ?
                        state_to_char[field->next_state] : 'X';
@@ -1326,7 +1408,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
                break;
        }
        case TRACE_SPECIAL: {
-               struct special_entry *field = (struct special_entry *)entry;
+               struct special_entry *field;
+
+               trace_assign_type(field, entry);
 
                trace_seq_printf(s, "# %ld %ld %ld\n",
                                 field->arg1,
@@ -1335,7 +1419,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
                break;
        }
        case TRACE_STACK: {
-               struct stack_entry *field = (struct stack_entry *)entry;
+               struct stack_entry *field;
+
+               trace_assign_type(field, entry);
 
                for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
                        if (i)
@@ -1346,7 +1432,9 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
                break;
        }
        case TRACE_PRINT: {
-               struct print_entry *field = (struct print_entry *)entry;
+               struct print_entry *field;
+
+               trace_assign_type(field, entry);
 
                seq_print_ip_sym(s, field->ip, sym_flags);
                trace_seq_printf(s, ": %s", field->buf);
@@ -1357,10 +1445,10 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
        default:
                trace_seq_printf(s, "Unknown type %d\n", entry->type);
        }
-       return 1;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int print_trace_fmt(struct trace_iterator *iter)
+static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
 {
        struct trace_seq *s = &iter->seq;
        unsigned long sym_flags = (trace_flags & TRACE_ITER_SYM_MASK);
@@ -1376,7 +1464,7 @@ static int print_trace_fmt(struct trace_iterator *iter)
        entry = iter->ent;
 
        if (entry->type == TRACE_CONT)
-               return 1;
+               return TRACE_TYPE_HANDLED;
 
        comm = trace_find_cmdline(iter->ent->pid);
 
@@ -1386,26 +1474,28 @@ static int print_trace_fmt(struct trace_iterator *iter)
 
        ret = trace_seq_printf(s, "%16s-%-5d ", comm, entry->pid);
        if (!ret)
-               return 0;
+               return TRACE_TYPE_PARTIAL_LINE;
        ret = trace_seq_printf(s, "[%03d] ", iter->cpu);
        if (!ret)
-               return 0;
+               return TRACE_TYPE_PARTIAL_LINE;
        ret = trace_seq_printf(s, "%5lu.%06lu: ", secs, usec_rem);
        if (!ret)
-               return 0;
+               return TRACE_TYPE_PARTIAL_LINE;
 
        switch (entry->type) {
        case TRACE_FN: {
-               struct ftrace_entry *field = (struct ftrace_entry *)entry;
+               struct ftrace_entry *field;
+
+               trace_assign_type(field, entry);
 
                ret = seq_print_ip_sym(s, field->ip, sym_flags);
                if (!ret)
-                       return 0;
+                       return TRACE_TYPE_PARTIAL_LINE;
                if ((sym_flags & TRACE_ITER_PRINT_PARENT) &&
                                                field->parent_ip) {
                        ret = trace_seq_printf(s, " <-");
                        if (!ret)
-                               return 0;
+                               return TRACE_TYPE_PARTIAL_LINE;
                        if (kretprobed(field->parent_ip))
                                ret = trace_seq_puts(s, KRETPROBE_MSG);
                        else
@@ -1413,17 +1503,18 @@ static int print_trace_fmt(struct trace_iterator *iter)
                                                       field->parent_ip,
                                                       sym_flags);
                        if (!ret)
-                               return 0;
+                               return TRACE_TYPE_PARTIAL_LINE;
                }
                ret = trace_seq_printf(s, "\n");
                if (!ret)
-                       return 0;
+                       return TRACE_TYPE_PARTIAL_LINE;
                break;
        }
        case TRACE_CTX:
        case TRACE_WAKE: {
-               struct ctx_switch_entry *field =
-                       (struct ctx_switch_entry *)entry;
+               struct ctx_switch_entry *field;
+
+               trace_assign_type(field, entry);
 
                S = field->prev_state < sizeof(state_to_char) ?
                        state_to_char[field->prev_state] : 'X';
@@ -1439,41 +1530,47 @@ static int print_trace_fmt(struct trace_iterator *iter)
                                       field->next_prio,
                                       T);
                if (!ret)
-                       return 0;
+                       return TRACE_TYPE_PARTIAL_LINE;
                break;
        }
        case TRACE_SPECIAL: {
-               struct special_entry *field = (struct special_entry *)entry;
+               struct special_entry *field;
+
+               trace_assign_type(field, entry);
 
                ret = trace_seq_printf(s, "# %ld %ld %ld\n",
                                 field->arg1,
                                 field->arg2,
                                 field->arg3);
                if (!ret)
-                       return 0;
+                       return TRACE_TYPE_PARTIAL_LINE;
                break;
        }
        case TRACE_STACK: {
-               struct stack_entry *field = (struct stack_entry *)entry;
+               struct stack_entry *field;
+
+               trace_assign_type(field, entry);
 
                for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
                        if (i) {
                                ret = trace_seq_puts(s, " <= ");
                                if (!ret)
-                                       return 0;
+                                       return TRACE_TYPE_PARTIAL_LINE;
                        }
                        ret = seq_print_ip_sym(s, field->caller[i],
                                               sym_flags);
                        if (!ret)
-                               return 0;
+                               return TRACE_TYPE_PARTIAL_LINE;
                }
                ret = trace_seq_puts(s, "\n");
                if (!ret)
-                       return 0;
+                       return TRACE_TYPE_PARTIAL_LINE;
                break;
        }
        case TRACE_PRINT: {
-               struct print_entry *field = (struct print_entry *)entry;
+               struct print_entry *field;
+
+               trace_assign_type(field, entry);
 
                seq_print_ip_sym(s, field->ip, sym_flags);
                trace_seq_printf(s, ": %s", field->buf);
@@ -1482,10 +1579,10 @@ static int print_trace_fmt(struct trace_iterator *iter)
                break;
        }
        }
-       return 1;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int print_raw_fmt(struct trace_iterator *iter)
+static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
 {
        struct trace_seq *s = &iter->seq;
        struct trace_entry *entry;
@@ -1495,28 +1592,31 @@ static int print_raw_fmt(struct trace_iterator *iter)
        entry = iter->ent;
 
        if (entry->type == TRACE_CONT)
-               return 1;
+               return TRACE_TYPE_HANDLED;
 
        ret = trace_seq_printf(s, "%d %d %llu ",
                entry->pid, iter->cpu, iter->ts);
        if (!ret)
-               return 0;
+               return TRACE_TYPE_PARTIAL_LINE;
 
        switch (entry->type) {
        case TRACE_FN: {
-               struct ftrace_entry *field = (struct ftrace_entry *)entry;
+               struct ftrace_entry *field;
+
+               trace_assign_type(field, entry);
 
                ret = trace_seq_printf(s, "%x %x\n",
                                        field->ip,
                                        field->parent_ip);
                if (!ret)
-                       return 0;
+                       return TRACE_TYPE_PARTIAL_LINE;
                break;
        }
        case TRACE_CTX:
        case TRACE_WAKE: {
-               struct ctx_switch_entry *field =
-                       (struct ctx_switch_entry *)entry;
+               struct ctx_switch_entry *field;
+
+               trace_assign_type(field, entry);
 
                S = field->prev_state < sizeof(state_to_char) ?
                        state_to_char[field->prev_state] : 'X';
@@ -1533,23 +1633,27 @@ static int print_raw_fmt(struct trace_iterator *iter)
                                       field->next_prio,
                                       T);
                if (!ret)
-                       return 0;
+                       return TRACE_TYPE_PARTIAL_LINE;
                break;
        }
        case TRACE_SPECIAL:
        case TRACE_STACK: {
-               struct special_entry *field = (struct special_entry *)entry;
+               struct special_entry *field;
+
+               trace_assign_type(field, entry);
 
                ret = trace_seq_printf(s, "# %ld %ld %ld\n",
                                 field->arg1,
                                 field->arg2,
                                 field->arg3);
                if (!ret)
-                       return 0;
+                       return TRACE_TYPE_PARTIAL_LINE;
                break;
        }
        case TRACE_PRINT: {
-               struct print_entry *field = (struct print_entry *)entry;
+               struct print_entry *field;
+
+               trace_assign_type(field, entry);
 
                trace_seq_printf(s, "# %lx %s", field->ip, field->buf);
                if (entry->flags & TRACE_FLAG_CONT)
@@ -1557,7 +1661,7 @@ static int print_raw_fmt(struct trace_iterator *iter)
                break;
        }
        }
-       return 1;
+       return TRACE_TYPE_HANDLED;
 }
 
 #define SEQ_PUT_FIELD_RET(s, x)                                \
@@ -1572,7 +1676,7 @@ do {                                                      \
                return 0;                               \
 } while (0)
 
-static int print_hex_fmt(struct trace_iterator *iter)
+static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
 {
        struct trace_seq *s = &iter->seq;
        unsigned char newline = '\n';
@@ -1582,7 +1686,7 @@ static int print_hex_fmt(struct trace_iterator *iter)
        entry = iter->ent;
 
        if (entry->type == TRACE_CONT)
-               return 1;
+               return TRACE_TYPE_HANDLED;
 
        SEQ_PUT_HEX_FIELD_RET(s, entry->pid);
        SEQ_PUT_HEX_FIELD_RET(s, iter->cpu);
@@ -1590,7 +1694,9 @@ static int print_hex_fmt(struct trace_iterator *iter)
 
        switch (entry->type) {
        case TRACE_FN: {
-               struct ftrace_entry *field = (struct ftrace_entry *)entry;
+               struct ftrace_entry *field;
+
+               trace_assign_type(field, entry);
 
                SEQ_PUT_HEX_FIELD_RET(s, field->ip);
                SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);
@@ -1598,8 +1704,9 @@ static int print_hex_fmt(struct trace_iterator *iter)
        }
        case TRACE_CTX:
        case TRACE_WAKE: {
-               struct ctx_switch_entry *field =
-                       (struct ctx_switch_entry *)entry;
+               struct ctx_switch_entry *field;
+
+               trace_assign_type(field, entry);
 
                S = field->prev_state < sizeof(state_to_char) ?
                        state_to_char[field->prev_state] : 'X';
@@ -1618,7 +1725,9 @@ static int print_hex_fmt(struct trace_iterator *iter)
        }
        case TRACE_SPECIAL:
        case TRACE_STACK: {
-               struct special_entry *field = (struct special_entry *)entry;
+               struct special_entry *field;
+
+               trace_assign_type(field, entry);
 
                SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
                SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
@@ -1628,10 +1737,10 @@ static int print_hex_fmt(struct trace_iterator *iter)
        }
        SEQ_PUT_FIELD_RET(s, newline);
 
-       return 1;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int print_bin_fmt(struct trace_iterator *iter)
+static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
 {
        struct trace_seq *s = &iter->seq;
        struct trace_entry *entry;
@@ -1639,7 +1748,7 @@ static int print_bin_fmt(struct trace_iterator *iter)
        entry = iter->ent;
 
        if (entry->type == TRACE_CONT)
-               return 1;
+               return TRACE_TYPE_HANDLED;
 
        SEQ_PUT_FIELD_RET(s, entry->pid);
        SEQ_PUT_FIELD_RET(s, iter->cpu);
@@ -1647,15 +1756,18 @@ static int print_bin_fmt(struct trace_iterator *iter)
 
        switch (entry->type) {
        case TRACE_FN: {
-               struct ftrace_entry *field = (struct ftrace_entry *)entry;
+               struct ftrace_entry *field;
+
+               trace_assign_type(field, entry);
 
                SEQ_PUT_FIELD_RET(s, field->ip);
                SEQ_PUT_FIELD_RET(s, field->parent_ip);
                break;
        }
        case TRACE_CTX: {
-               struct ctx_switch_entry *field =
-                       (struct ctx_switch_entry *)entry;
+               struct ctx_switch_entry *field;
+
+               trace_assign_type(field, entry);
 
                SEQ_PUT_FIELD_RET(s, field->prev_pid);
                SEQ_PUT_FIELD_RET(s, field->prev_prio);
@@ -1667,7 +1779,9 @@ static int print_bin_fmt(struct trace_iterator *iter)
        }
        case TRACE_SPECIAL:
        case TRACE_STACK: {
-               struct special_entry *field = (struct special_entry *)entry;
+               struct special_entry *field;
+
+               trace_assign_type(field, entry);
 
                SEQ_PUT_FIELD_RET(s, field->arg1);
                SEQ_PUT_FIELD_RET(s, field->arg2);
@@ -1683,16 +1797,27 @@ static int trace_empty(struct trace_iterator *iter)
        int cpu;
 
        for_each_tracing_cpu(cpu) {
-               if (!ring_buffer_iter_empty(iter->buffer_iter[cpu]))
-                       return 0;
+               if (iter->buffer_iter[cpu]) {
+                       if (!ring_buffer_iter_empty(iter->buffer_iter[cpu]))
+                               return 0;
+               } else {
+                       if (!ring_buffer_empty_cpu(iter->tr->buffer, cpu))
+                               return 0;
+               }
        }
+
        return 1;
 }
 
-static int print_trace_line(struct trace_iterator *iter)
+static enum print_line_t print_trace_line(struct trace_iterator *iter)
 {
-       if (iter->trace && iter->trace->print_line)
-               return iter->trace->print_line(iter);
+       enum print_line_t ret;
+
+       if (iter->trace && iter->trace->print_line) {
+               ret = iter->trace->print_line(iter);
+               if (ret != TRACE_TYPE_UNHANDLED)
+                       return ret;
+       }
 
        if (trace_flags & TRACE_ITER_BIN)
                return print_bin_fmt(iter);
@@ -1771,8 +1896,10 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
        iter->pos = -1;
 
        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;
        }
@@ -2254,9 +2381,11 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,
        struct tracer *t;
        char buf[max_tracer_type_len+1];
        int i;
+       size_t ret;
 
        if (cnt > max_tracer_type_len)
                cnt = max_tracer_type_len;
+       ret = cnt;
 
        if (copy_from_user(&buf, ubuf, cnt))
                return -EFAULT;
@@ -2272,7 +2401,11 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,
                if (strcmp(t->name, buf) == 0)
                        break;
        }
-       if (!t || t == current_trace)
+       if (!t) {
+               ret = -EINVAL;
+               goto out;
+       }
+       if (t == current_trace)
                goto out;
 
        if (current_trace && current_trace->reset)
@@ -2285,9 +2418,10 @@ tracing_set_trace_write(struct file *filp, const char __user *ubuf,
  out:
        mutex_unlock(&trace_types_lock);
 
-       filp->f_pos += cnt;
+       if (ret == cnt)
+               filp->f_pos += cnt;
 
-       return cnt;
+       return ret;
 }
 
 static ssize_t
@@ -2336,7 +2470,6 @@ static atomic_t tracing_reader;
 static int tracing_open_pipe(struct inode *inode, struct file *filp)
 {
        struct trace_iterator *iter;
-       int cpu;
 
        if (tracing_disabled)
                return -ENODEV;
@@ -2357,38 +2490,17 @@ static int tracing_open_pipe(struct inode *inode, struct file *filp)
        iter->trace = current_trace;
        filp->private_data = iter;
 
-       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;
-       }
-
        if (iter->trace->pipe_open)
                iter->trace->pipe_open(iter);
        mutex_unlock(&trace_types_lock);
 
        return 0;
-
- fail_buffer:
-       for_each_tracing_cpu(cpu) {
-               if (iter->buffer_iter[cpu])
-                       ring_buffer_read_finish(iter->buffer_iter[cpu]);
-       }
-       mutex_unlock(&trace_types_lock);
-
-       return -ENOMEM;
 }
 
 static int tracing_release_pipe(struct inode *inode, struct file *file)
 {
        struct trace_iterator *iter = file->private_data;
-       int cpu;
 
-       for_each_tracing_cpu(cpu) {
-               if (iter->buffer_iter[cpu])
-                       ring_buffer_read_finish(iter->buffer_iter[cpu]);
-       }
        kfree(iter);
        atomic_dec(&tracing_reader);
 
@@ -2424,17 +2536,12 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
                  size_t cnt, loff_t *ppos)
 {
        struct trace_iterator *iter = filp->private_data;
-       unsigned long flags;
-#ifdef CONFIG_FTRACE
-       int ftrace_save;
-#endif
        ssize_t sret;
 
        /* return any leftover data */
        sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
        if (sret != -EBUSY)
                return sret;
-       sret = 0;
 
        trace_seq_reset(&iter->seq);
 
@@ -2445,6 +2552,8 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
                        goto out;
        }
 
+waitagain:
+       sret = 0;
        while (trace_empty(iter)) {
 
                if ((filp->f_flags & O_NONBLOCK)) {
@@ -2509,27 +2618,12 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
               offsetof(struct trace_iterator, seq));
        iter->pos = -1;
 
-       /*
-        * We need to stop all tracing on all CPUS to read the
-        * the next buffer. This is a bit expensive, but is
-        * not done often. We fill all what we can read,
-        * and then release the locks again.
-        */
-
-       local_irq_disable();
-#ifdef CONFIG_FTRACE
-       ftrace_save = ftrace_enabled;
-       ftrace_enabled = 0;
-#endif
-       smp_wmb();
-       ring_buffer_lock(iter->tr->buffer, &flags);
-
        while (find_next_entry_inc(iter) != NULL) {
-               int ret;
+               enum print_line_t ret;
                int len = iter->seq.len;
 
                ret = print_trace_line(iter);
-               if (!ret) {
+               if (ret == TRACE_TYPE_PARTIAL_LINE) {
                        /* don't print partial lines */
                        iter->seq.len = len;
                        break;
@@ -2541,18 +2635,17 @@ tracing_read_pipe(struct file *filp, char __user *ubuf,
                        break;
        }
 
-       ring_buffer_unlock(iter->tr->buffer, flags);
-#ifdef CONFIG_FTRACE
-       ftrace_enabled = ftrace_save;
-#endif
-       local_irq_enable();
-
        /* Now copy what we have to the user */
        sret = trace_seq_to_user(&iter->seq, ubuf, cnt);
        if (iter->seq.readpos >= iter->seq.len)
                trace_seq_reset(&iter->seq);
+
+       /*
+        * If there was nothing to send to user, inspite of consuming trace
+        * entries, go back to wait for more entries.
+        */
        if (sret == -EBUSY)
-               sret = 0;
+               goto waitagain;
 
 out:
        mutex_unlock(&trace_types_lock);
@@ -2872,21 +2965,20 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
        struct trace_array_cpu *data;
        struct print_entry *entry;
        unsigned long flags, irq_flags;
-       long disabled;
-       int cpu, len = 0, size;
+       int cpu, len = 0, size, pc;
 
        if (!tr->ctrl || tracing_disabled)
                return 0;
 
-       local_irq_save(flags);
+       pc = preempt_count();
+       preempt_disable_notrace();
        cpu = raw_smp_processor_id();
        data = tr->data[cpu];
-       disabled = atomic_inc_return(&data->disabled);
 
-       if (unlikely(disabled != 1))
+       if (unlikely(atomic_read(&data->disabled)))
                goto out;
 
-       spin_lock(&trace_buf_lock);
+       spin_lock_irqsave(&trace_buf_lock, flags);
        len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args);
 
        len = min(len, TRACE_BUF_SIZE-1);
@@ -2897,7 +2989,7 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
        if (!event)
                goto out_unlock;
        entry = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags);
+       tracing_generic_entry_update(&entry->ent, flags, pc);
        entry->ent.type                 = TRACE_PRINT;
        entry->ip                       = ip;
 
@@ -2906,11 +2998,10 @@ int trace_vprintk(unsigned long ip, const char *fmt, va_list args)
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 
  out_unlock:
-       spin_unlock(&trace_buf_lock);
+       spin_unlock_irqrestore(&trace_buf_lock, flags);
 
  out:
-       atomic_dec(&data->disabled);
-       local_irq_restore(flags);
+       preempt_enable_notrace();
 
        return len;
 }
@@ -2999,8 +3090,8 @@ void ftrace_dump(void)
        static struct trace_iterator iter;
        static cpumask_t mask;
        static int dump_ran;
-       unsigned long flags, irq_flags;
-       int cnt = 0;
+       unsigned long flags;
+       int cnt = 0, cpu;
 
        /* only one dump */
        spin_lock_irqsave(&ftrace_dump_lock, flags);
@@ -3012,6 +3103,10 @@ void ftrace_dump(void)
        /* No turning back! */
        ftrace_kill_atomic();
 
+       for_each_tracing_cpu(cpu) {
+               atomic_inc(&global_trace.data[cpu]->disabled);
+       }
+
        printk(KERN_TRACE "Dumping ftrace buffer:\n");
 
        iter.tr = &global_trace;
@@ -3026,8 +3121,6 @@ void ftrace_dump(void)
 
        cpus_clear(mask);
 
-       ring_buffer_lock(iter.tr->buffer, &irq_flags);
-
        while (!trace_empty(&iter)) {
 
                if (!cnt)
@@ -3055,8 +3148,6 @@ void ftrace_dump(void)
        else
                printk(KERN_TRACE "---------------------------------\n");
 
-       ring_buffer_unlock(iter.tr->buffer, irq_flags);
-
  out:
        spin_unlock_irqrestore(&ftrace_dump_lock, flags);
 }