tracing: Fix uninitialized variable of tracing/trace output
[linux-2.6.git] / kernel / trace / trace_output.c
index 4e3ad36..8e46b33 100644 (file)
 /* must be a power of 2 */
 #define EVENT_HASHSIZE 128
 
-static DEFINE_MUTEX(trace_event_mutex);
+DECLARE_RWSEM(trace_event_mutex);
+
+DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);
+EXPORT_PER_CPU_SYMBOL(ftrace_event_seq);
+
 static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
 
 static int next_event_type = __TRACE_LAST_TYPE + 1;
 
+int trace_print_seq(struct seq_file *m, struct trace_seq *s)
+{
+       int len = s->len >= PAGE_SIZE ? PAGE_SIZE - 1 : s->len;
+       int ret;
+
+       ret = seq_write(m, s->buffer, len);
+
+       /*
+        * Only reset this buffer if we successfully wrote to the
+        * seq_file buffer.
+        */
+       if (!ret)
+               trace_seq_init(s);
+
+       return ret;
+}
+
+enum print_line_t trace_print_bprintk_msg_only(struct trace_iterator *iter)
+{
+       struct trace_seq *s = &iter->seq;
+       struct trace_entry *entry = iter->ent;
+       struct bprint_entry *field;
+       int ret;
+
+       trace_assign_type(field, entry);
+
+       ret = trace_seq_bprintf(s, field->fmt, field->buf);
+       if (!ret)
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       return TRACE_TYPE_HANDLED;
+}
+
+enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
+{
+       struct trace_seq *s = &iter->seq;
+       struct trace_entry *entry = iter->ent;
+       struct print_entry *field;
+       int ret;
+
+       trace_assign_type(field, entry);
+
+       ret = trace_seq_printf(s, "%s", field->buf);
+       if (!ret)
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       return TRACE_TYPE_HANDLED;
+}
+
 /**
  * trace_seq_printf - sequence printing of trace information
  * @s: trace sequence descriptor
  * @fmt: printf format string
  *
+ * It returns 0 if the trace oversizes the buffer's free
+ * space, 1 otherwise.
+ *
  * The tracer may use either sequence operations or its own
  * copy to user routines. To simplify formating of a trace
  * trace_seq_printf is used to store strings into a special
@@ -37,7 +93,7 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
        va_list ap;
        int ret;
 
-       if (!len)
+       if (s->full || !len)
                return 0;
 
        va_start(ap, fmt);
@@ -45,8 +101,66 @@ trace_seq_printf(struct trace_seq *s, const char *fmt, ...)
        va_end(ap);
 
        /* If we can't write it all, don't bother writing anything */
-       if (ret >= len)
+       if (ret >= len) {
+               s->full = 1;
+               return 0;
+       }
+
+       s->len += ret;
+
+       return 1;
+}
+EXPORT_SYMBOL_GPL(trace_seq_printf);
+
+/**
+ * trace_seq_vprintf - sequence printing of trace information
+ * @s: trace sequence descriptor
+ * @fmt: printf format string
+ *
+ * The tracer may use either sequence operations or its own
+ * copy to user routines. To simplify formating of a trace
+ * trace_seq_printf is used to store strings into a special
+ * buffer (@s). Then the output may be either used by
+ * the sequencer or pulled into another buffer.
+ */
+int
+trace_seq_vprintf(struct trace_seq *s, const char *fmt, va_list args)
+{
+       int len = (PAGE_SIZE - 1) - s->len;
+       int ret;
+
+       if (s->full || !len)
+               return 0;
+
+       ret = vsnprintf(s->buffer + s->len, len, fmt, args);
+
+       /* If we can't write it all, don't bother writing anything */
+       if (ret >= len) {
+               s->full = 1;
                return 0;
+       }
+
+       s->len += ret;
+
+       return len;
+}
+EXPORT_SYMBOL_GPL(trace_seq_vprintf);
+
+int trace_seq_bprintf(struct trace_seq *s, const char *fmt, const u32 *binary)
+{
+       int len = (PAGE_SIZE - 1) - s->len;
+       int ret;
+
+       if (s->full || !len)
+               return 0;
+
+       ret = bstr_printf(s->buffer + s->len, len, fmt, binary);
+
+       /* If we can't write it all, don't bother writing anything */
+       if (ret >= len) {
+               s->full = 1;
+               return 0;
+       }
 
        s->len += ret;
 
@@ -67,9 +181,14 @@ int trace_seq_puts(struct trace_seq *s, const char *str)
 {
        int len = strlen(str);
 
-       if (len > ((PAGE_SIZE - 1) - s->len))
+       if (s->full)
                return 0;
 
+       if (len > ((PAGE_SIZE - 1) - s->len)) {
+               s->full = 1;
+               return 0;
+       }
+
        memcpy(s->buffer + s->len, str, len);
        s->len += len;
 
@@ -78,18 +197,28 @@ int trace_seq_puts(struct trace_seq *s, const char *str)
 
 int trace_seq_putc(struct trace_seq *s, unsigned char c)
 {
-       if (s->len >= (PAGE_SIZE - 1))
+       if (s->full)
+               return 0;
+
+       if (s->len >= (PAGE_SIZE - 1)) {
+               s->full = 1;
                return 0;
+       }
 
        s->buffer[s->len++] = c;
 
        return 1;
 }
 
-int trace_seq_putmem(struct trace_seq *s, void *mem, size_t len)
+int trace_seq_putmem(struct trace_seq *s, const void *mem, size_t len)
 {
-       if (len > ((PAGE_SIZE - 1) - s->len))
+       if (s->full)
+               return 0;
+
+       if (len > ((PAGE_SIZE - 1) - s->len)) {
+               s->full = 1;
                return 0;
+       }
 
        memcpy(s->buffer + s->len, mem, len);
        s->len += len;
@@ -97,12 +226,15 @@ int trace_seq_putmem(struct trace_seq *s, void *mem, size_t len)
        return len;
 }
 
-int trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len)
+int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len)
 {
        unsigned char hex[HEX_CHARS];
-       unsigned char *data = mem;
+       const unsigned char *data = mem;
        int i, j;
 
+       if (s->full)
+               return 0;
+
 #ifdef __BIG_ENDIAN
        for (i = 0, j = 0; i < len; i++) {
 #else
@@ -116,12 +248,36 @@ int trace_seq_putmem_hex(struct trace_seq *s, void *mem, size_t len)
        return trace_seq_putmem(s, hex, j);
 }
 
+void *trace_seq_reserve(struct trace_seq *s, size_t len)
+{
+       void *ret;
+
+       if (s->full)
+               return 0;
+
+       if (len > ((PAGE_SIZE - 1) - s->len)) {
+               s->full = 1;
+               return NULL;
+       }
+
+       ret = s->buffer + s->len;
+       s->len += len;
+
+       return ret;
+}
+
 int trace_seq_path(struct trace_seq *s, struct path *path)
 {
        unsigned char *p;
 
-       if (s->len >= (PAGE_SIZE - 1))
+       if (s->full)
+               return 0;
+
+       if (s->len >= (PAGE_SIZE - 1)) {
+               s->full = 1;
                return 0;
+       }
+
        p = d_path(path, s->buffer + s->len, PAGE_SIZE - s->len);
        if (!IS_ERR(p)) {
                p = mangle_path(s->buffer + s->len, p, "\n");
@@ -134,9 +290,71 @@ int trace_seq_path(struct trace_seq *s, struct path *path)
                return 1;
        }
 
+       s->full = 1;
        return 0;
 }
 
+const char *
+ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
+                      unsigned long flags,
+                      const struct trace_print_flags *flag_array)
+{
+       unsigned long mask;
+       const char *str;
+       const char *ret = p->buffer + p->len;
+       int i;
+
+       for (i = 0;  flag_array[i].name && flags; i++) {
+
+               mask = flag_array[i].mask;
+               if ((flags & mask) != mask)
+                       continue;
+
+               str = flag_array[i].name;
+               flags &= ~mask;
+               if (p->len && delim)
+                       trace_seq_puts(p, delim);
+               trace_seq_puts(p, str);
+       }
+
+       /* check for left over flags */
+       if (flags) {
+               if (p->len && delim)
+                       trace_seq_puts(p, delim);
+               trace_seq_printf(p, "0x%lx", flags);
+       }
+
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(ftrace_print_flags_seq);
+
+const char *
+ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
+                        const struct trace_print_flags *symbol_array)
+{
+       int i;
+       const char *ret = p->buffer + p->len;
+
+       for (i = 0;  symbol_array[i].name; i++) {
+
+               if (val != symbol_array[i].mask)
+                       continue;
+
+               trace_seq_puts(p, symbol_array[i].name);
+               break;
+       }
+
+       if (!p->len)
+               trace_seq_printf(p, "0x%lx", val);
+               
+       trace_seq_putc(p, 0);
+
+       return ret;
+}
+EXPORT_SYMBOL(ftrace_print_symbols_seq);
+
 #ifdef CONFIG_KRETPROBES
 static inline const char *kretprobed(const char *name)
 {
@@ -199,6 +417,9 @@ int seq_print_user_ip(struct trace_seq *s, struct mm_struct *mm,
        unsigned long vmstart = 0;
        int ret = 1;
 
+       if (s->full)
+               return 0;
+
        if (mm) {
                const struct vm_area_struct *vma;
 
@@ -236,7 +457,7 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
                 * since individual threads might have already quit!
                 */
                rcu_read_lock();
-               task = find_task_by_vpid(entry->ent.tgid);
+               task = find_task_by_vpid(entry->tgid);
                if (task)
                        mm = get_task_mm(task);
                rcu_read_unlock();
@@ -247,17 +468,20 @@ seq_print_userip_objs(const struct userstack_entry *entry, struct trace_seq *s,
 
                if (ip == ULONG_MAX || !ret)
                        break;
-               if (i && ret)
-                       ret = trace_seq_puts(s, " <- ");
+               if (ret)
+                       ret = trace_seq_puts(s, " => ");
                if (!ip) {
                        if (ret)
                                ret = trace_seq_puts(s, "??");
+                       if (ret)
+                               ret = trace_seq_puts(s, "\n");
                        continue;
                }
                if (!ret)
                        break;
                if (ret)
                        ret = seq_print_user_ip(s, mm, ip, sym_flags);
+               ret = trace_seq_puts(s, "\n");
        }
 
        if (mm)
@@ -286,6 +510,125 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
        return ret;
 }
 
+/**
+ * trace_print_lat_fmt - print the irq, preempt and lockdep fields
+ * @s: trace seq struct to write to
+ * @entry: The trace entry field from the ring buffer
+ *
+ * Prints the generic fields of irqs off, in hard or softirq, preempt
+ * count and lock depth.
+ */
+int trace_print_lat_fmt(struct trace_seq *s, struct trace_entry *entry)
+{
+       int hardirq, softirq;
+       int ret;
+
+       hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
+       softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
+
+       if (!trace_seq_printf(s, "%c%c%c",
+                             (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
+                               (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
+                                 'X' : '.',
+                             (entry->flags & TRACE_FLAG_NEED_RESCHED) ?
+                               'N' : '.',
+                             (hardirq && softirq) ? 'H' :
+                               hardirq ? 'h' : softirq ? 's' : '.'))
+               return 0;
+
+       if (entry->preempt_count)
+               ret = trace_seq_printf(s, "%x", entry->preempt_count);
+       else
+               ret = trace_seq_putc(s, '.');
+
+       if (!ret)
+               return 0;
+
+       if (entry->lock_depth < 0)
+               return trace_seq_putc(s, '.');
+
+       return trace_seq_printf(s, "%d", entry->lock_depth);
+}
+
+static int
+lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu)
+{
+       char comm[TASK_COMM_LEN];
+
+       trace_find_cmdline(entry->pid, comm);
+
+       if (!trace_seq_printf(s, "%8.8s-%-5d %3d",
+                             comm, entry->pid, cpu))
+               return 0;
+
+       return trace_print_lat_fmt(s, entry);
+}
+
+static unsigned long preempt_mark_thresh = 100;
+
+static int
+lat_print_timestamp(struct trace_seq *s, u64 abs_usecs,
+                   unsigned long rel_usecs)
+{
+       return trace_seq_printf(s, " %4lldus%c: ", abs_usecs,
+                               rel_usecs > preempt_mark_thresh ? '!' :
+                                 rel_usecs > 1 ? '+' : ' ');
+}
+
+int trace_print_context(struct trace_iterator *iter)
+{
+       struct trace_seq *s = &iter->seq;
+       struct trace_entry *entry = iter->ent;
+       unsigned long long t = ns2usecs(iter->ts);
+       unsigned long usec_rem = do_div(t, USEC_PER_SEC);
+       unsigned long secs = (unsigned long)t;
+       char comm[TASK_COMM_LEN];
+
+       trace_find_cmdline(entry->pid, comm);
+
+       return trace_seq_printf(s, "%16s-%-5d [%03d] %5lu.%06lu: ",
+                               comm, entry->pid, iter->cpu, secs, usec_rem);
+}
+
+int trace_print_lat_context(struct trace_iterator *iter)
+{
+       u64 next_ts;
+       int ret;
+       struct trace_seq *s = &iter->seq;
+       struct trace_entry *entry = iter->ent,
+                          *next_entry = trace_find_next_entry(iter, NULL,
+                                                              &next_ts);
+       unsigned long verbose = (trace_flags & TRACE_ITER_VERBOSE);
+       unsigned long abs_usecs = ns2usecs(iter->ts - iter->tr->time_start);
+       unsigned long rel_usecs;
+
+       if (!next_entry)
+               next_ts = iter->ts;
+       rel_usecs = ns2usecs(next_ts - iter->ts);
+
+       if (verbose) {
+               char comm[TASK_COMM_LEN];
+
+               trace_find_cmdline(entry->pid, comm);
+
+               ret = trace_seq_printf(s, "%16s %5d %3d %d %08x %08lx [%08llx]"
+                                      " %ld.%03ldms (+%ld.%03ldms): ", comm,
+                                      entry->pid, iter->cpu, entry->flags,
+                                      entry->preempt_count, iter->idx,
+                                      ns2usecs(iter->ts),
+                                      abs_usecs / USEC_PER_MSEC,
+                                      abs_usecs % USEC_PER_MSEC,
+                                      rel_usecs / USEC_PER_MSEC,
+                                      rel_usecs % USEC_PER_MSEC);
+       } else {
+               ret = lat_print_generic(s, entry, iter->cpu);
+               if (ret)
+                       ret = lat_print_timestamp(s, abs_usecs, rel_usecs);
+       }
+
+       return ret;
+}
+
 static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
 
 static int task_state_char(unsigned long state)
@@ -300,6 +643,7 @@ static int task_state_char(unsigned long state)
  * @type: the type of event to look for
  *
  * Returns an event of type @type otherwise NULL
+ * Called with trace_event_read_lock() held.
  */
 struct trace_event *ftrace_find_event(int type)
 {
@@ -309,7 +653,7 @@ struct trace_event *ftrace_find_event(int type)
 
        key = type & (EVENT_HASHSIZE - 1);
 
-       hlist_for_each_entry_rcu(event, n, &event_hash[key], node) {
+       hlist_for_each_entry(event, n, &event_hash[key], node) {
                if (event->type == type)
                        return event;
        }
@@ -317,6 +661,46 @@ struct trace_event *ftrace_find_event(int type)
        return NULL;
 }
 
+static LIST_HEAD(ftrace_event_list);
+
+static int trace_search_list(struct list_head **list)
+{
+       struct trace_event *e;
+       int last = __TRACE_LAST_TYPE;
+
+       if (list_empty(&ftrace_event_list)) {
+               *list = &ftrace_event_list;
+               return last + 1;
+       }
+
+       /*
+        * We used up all possible max events,
+        * lets see if somebody freed one.
+        */
+       list_for_each_entry(e, &ftrace_event_list, list) {
+               if (e->type != last + 1)
+                       break;
+               last++;
+       }
+
+       /* Did we used up all 65 thousand events??? */
+       if ((last + 1) > FTRACE_MAX_EVENT)
+               return 0;
+
+       *list = &e->list;
+       return last + 1;
+}
+
+void trace_event_read_lock(void)
+{
+       down_read(&trace_event_mutex);
+}
+
+void trace_event_read_unlock(void)
+{
+       up_read(&trace_event_mutex);
+}
+
 /**
  * register_ftrace_event - register output for an event type
  * @event: the event type to register
@@ -337,28 +721,73 @@ int register_ftrace_event(struct trace_event *event)
        unsigned key;
        int ret = 0;
 
-       mutex_lock(&trace_event_mutex);
+       down_write(&trace_event_mutex);
+
+       if (WARN_ON(!event))
+               goto out;
+
+       INIT_LIST_HEAD(&event->list);
+
+       if (!event->type) {
+               struct list_head *list = NULL;
+
+               if (next_event_type > FTRACE_MAX_EVENT) {
+
+                       event->type = trace_search_list(&list);
+                       if (!event->type)
+                               goto out;
 
-       if (!event->type)
-               event->type = next_event_type++;
-       else if (event->type > __TRACE_LAST_TYPE) {
+               } else {
+                       
+                       event->type = next_event_type++;
+                       list = &ftrace_event_list;
+               }
+
+               if (WARN_ON(ftrace_find_event(event->type)))
+                       goto out;
+
+               list_add_tail(&event->list, list);
+
+       } else if (event->type > __TRACE_LAST_TYPE) {
                printk(KERN_WARNING "Need to add type to trace.h\n");
                WARN_ON(1);
+               goto out;
+       } else {
+               /* Is this event already used */
+               if (ftrace_find_event(event->type))
+                       goto out;
        }
 
-       if (ftrace_find_event(event->type))
-               goto out;
+       if (event->trace == NULL)
+               event->trace = trace_nop_print;
+       if (event->raw == NULL)
+               event->raw = trace_nop_print;
+       if (event->hex == NULL)
+               event->hex = trace_nop_print;
+       if (event->binary == NULL)
+               event->binary = trace_nop_print;
 
        key = event->type & (EVENT_HASHSIZE - 1);
 
-       hlist_add_head_rcu(&event->node, &event_hash[key]);
+       hlist_add_head(&event->node, &event_hash[key]);
 
        ret = event->type;
  out:
-       mutex_unlock(&trace_event_mutex);
+       up_write(&trace_event_mutex);
 
        return ret;
 }
+EXPORT_SYMBOL_GPL(register_ftrace_event);
+
+/*
+ * Used by module code with the trace_event_mutex held for write.
+ */
+int __unregister_ftrace_event(struct trace_event *event)
+{
+       hlist_del(&event->node);
+       list_del(&event->list);
+       return 0;
+}
 
 /**
  * unregister_ftrace_event - remove a no longer used event
@@ -366,52 +795,30 @@ int register_ftrace_event(struct trace_event *event)
  */
 int unregister_ftrace_event(struct trace_event *event)
 {
-       mutex_lock(&trace_event_mutex);
-       hlist_del(&event->node);
-       mutex_unlock(&trace_event_mutex);
+       down_write(&trace_event_mutex);
+       __unregister_ftrace_event(event);
+       up_write(&trace_event_mutex);
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(unregister_ftrace_event);
 
 /*
  * Standard events
  */
 
-int
-trace_nop_print(struct trace_seq *s, struct trace_entry *entry, int flags)
+enum print_line_t trace_nop_print(struct trace_iterator *iter, int flags)
 {
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
 /* TRACE_FN */
-static int
-trace_fn_latency(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_fn_trace(struct trace_iterator *iter, int flags)
 {
        struct ftrace_entry *field;
+       struct trace_seq *s = &iter->seq;
 
-       trace_assign_type(field, entry);
-
-       if (!seq_print_ip_sym(s, field->ip, flags))
-               goto partial;
-       if (!trace_seq_puts(s, " ("))
-               goto partial;
-       if (!seq_print_ip_sym(s, field->parent_ip, flags))
-               goto partial;
-       if (!trace_seq_puts(s, ")\n"))
-               goto partial;
-
-       return 0;
-
- partial:
-       return TRACE_TYPE_PARTIAL_LINE;
-}
-
-static int
-trace_fn_trace(struct trace_seq *s, struct trace_entry *entry, int flags)
-{
-       struct ftrace_entry *field;
-
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        if (!seq_print_ip_sym(s, field->ip, flags))
                goto partial;
@@ -427,77 +834,76 @@ trace_fn_trace(struct trace_seq *s, struct trace_entry *entry, int flags)
        if (!trace_seq_printf(s, "\n"))
                goto partial;
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 
  partial:
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
-static int
-trace_fn_raw(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_fn_raw(struct trace_iterator *iter, int flags)
 {
        struct ftrace_entry *field;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
-       if (!trace_seq_printf(s, "%x %x\n",
+       if (!trace_seq_printf(&iter->seq, "%lx %lx\n",
                              field->ip,
                              field->parent_ip))
                return TRACE_TYPE_PARTIAL_LINE;
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int
-trace_fn_hex(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_fn_hex(struct trace_iterator *iter, int flags)
 {
        struct ftrace_entry *field;
+       struct trace_seq *s = &iter->seq;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        SEQ_PUT_HEX_FIELD_RET(s, field->ip);
        SEQ_PUT_HEX_FIELD_RET(s, field->parent_ip);
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int
-trace_fn_bin(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_fn_bin(struct trace_iterator *iter, int flags)
 {
        struct ftrace_entry *field;
+       struct trace_seq *s = &iter->seq;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        SEQ_PUT_FIELD_RET(s, field->ip);
        SEQ_PUT_FIELD_RET(s, field->parent_ip);
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
 static struct trace_event trace_fn_event = {
-       .type           = TRACE_FN,
+       .type           = TRACE_FN,
        .trace          = trace_fn_trace,
-       .latency_trace  = trace_fn_latency,
        .raw            = trace_fn_raw,
        .hex            = trace_fn_hex,
        .binary         = trace_fn_bin,
 };
 
 /* TRACE_CTX an TRACE_WAKE */
-static int
-trace_ctxwake_print(struct trace_seq *s, struct trace_entry *entry, int flags,
-                   char *delim)
+static enum print_line_t trace_ctxwake_print(struct trace_iterator *iter,
+                                            char *delim)
 {
        struct ctx_switch_entry *field;
-       char *comm;
+       char comm[TASK_COMM_LEN];
        int S, T;
 
-       trace_assign_type(field, entry);
+
+       trace_assign_type(field, iter->ent);
 
        T = task_state_char(field->next_state);
        S = task_state_char(field->prev_state);
-       comm = trace_find_cmdline(field->next_pid);
-       if (!trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
+       trace_find_cmdline(field->next_pid, comm);
+       if (!trace_seq_printf(&iter->seq,
+                             " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
                              field->prev_pid,
                              field->prev_prio,
                              S, delim,
@@ -507,34 +913,31 @@ trace_ctxwake_print(struct trace_seq *s, struct trace_entry *entry, int flags,
                              T, comm))
                return TRACE_TYPE_PARTIAL_LINE;
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int
-trace_ctx_print(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_ctx_print(struct trace_iterator *iter, int flags)
 {
-       return trace_ctxwake_print(s, entry, flags, "==>");
+       return trace_ctxwake_print(iter, "==>");
 }
 
-static int
-trace_wake_print(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_wake_print(struct trace_iterator *iter,
+                                         int flags)
 {
-       return trace_ctxwake_print(s, entry, flags, "  +");
+       return trace_ctxwake_print(iter, "  +");
 }
 
-static int
-trace_ctxwake_raw(struct trace_seq *s, struct trace_entry *entry, int flags,
-                 char S)
+static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
 {
        struct ctx_switch_entry *field;
        int T;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        if (!S)
-               task_state_char(field->prev_state);
+               S = task_state_char(field->prev_state);
        T = task_state_char(field->next_state);
-       if (!trace_seq_printf(s, "%d %d %c %d %d %d %c\n",
+       if (!trace_seq_printf(&iter->seq, "%d %d %c %d %d %d %c\n",
                              field->prev_pid,
                              field->prev_prio,
                              S,
@@ -544,33 +947,30 @@ trace_ctxwake_raw(struct trace_seq *s, struct trace_entry *entry, int flags,
                              T))
                return TRACE_TYPE_PARTIAL_LINE;
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int
-trace_ctx_raw(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_ctx_raw(struct trace_iterator *iter, int flags)
 {
-       return trace_ctxwake_raw(s, entry, flags, 0);
+       return trace_ctxwake_raw(iter, 0);
 }
 
-static int
-trace_wake_raw(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_wake_raw(struct trace_iterator *iter, int flags)
 {
-       return trace_ctxwake_raw(s, entry, flags, '+');
+       return trace_ctxwake_raw(iter, '+');
 }
 
 
-static int
-trace_ctxwake_hex(struct trace_seq *s, struct trace_entry *entry, int flags,
-                 char S)
+static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
 {
        struct ctx_switch_entry *field;
+       struct trace_seq *s = &iter->seq;
        int T;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        if (!S)
-               task_state_char(field->prev_state);
+               S = task_state_char(field->prev_state);
        T = task_state_char(field->next_state);
 
        SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
@@ -581,27 +981,26 @@ trace_ctxwake_hex(struct trace_seq *s, struct trace_entry *entry, int flags,
        SEQ_PUT_HEX_FIELD_RET(s, field->next_prio);
        SEQ_PUT_HEX_FIELD_RET(s, T);
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int
-trace_ctx_hex(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_ctx_hex(struct trace_iterator *iter, int flags)
 {
-       return trace_ctxwake_hex(s, entry, flags, 0);
+       return trace_ctxwake_hex(iter, 0);
 }
 
-static int
-trace_wake_hex(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_wake_hex(struct trace_iterator *iter, int flags)
 {
-       return trace_ctxwake_hex(s, entry, flags, '+');
+       return trace_ctxwake_hex(iter, '+');
 }
 
-static int
-trace_ctxwake_bin(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_ctxwake_bin(struct trace_iterator *iter,
+                                          int flags)
 {
        struct ctx_switch_entry *field;
+       struct trace_seq *s = &iter->seq;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        SEQ_PUT_FIELD_RET(s, field->prev_pid);
        SEQ_PUT_FIELD_RET(s, field->prev_prio);
@@ -610,76 +1009,75 @@ trace_ctxwake_bin(struct trace_seq *s, struct trace_entry *entry, int flags)
        SEQ_PUT_FIELD_RET(s, field->next_prio);
        SEQ_PUT_FIELD_RET(s, field->next_state);
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
 static struct trace_event trace_ctx_event = {
-       .type           = TRACE_CTX,
+       .type           = TRACE_CTX,
        .trace          = trace_ctx_print,
-       .latency_trace  = trace_ctx_print,
        .raw            = trace_ctx_raw,
        .hex            = trace_ctx_hex,
        .binary         = trace_ctxwake_bin,
 };
 
 static struct trace_event trace_wake_event = {
-       .type           = TRACE_WAKE,
+       .type           = TRACE_WAKE,
        .trace          = trace_wake_print,
-       .latency_trace  = trace_wake_print,
        .raw            = trace_wake_raw,
        .hex            = trace_wake_hex,
        .binary         = trace_ctxwake_bin,
 };
 
 /* TRACE_SPECIAL */
-static int
-trace_special_print(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_special_print(struct trace_iterator *iter,
+                                            int flags)
 {
        struct special_entry *field;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
-       if (!trace_seq_printf(s, "# %ld %ld %ld\n",
+       if (!trace_seq_printf(&iter->seq, "# %ld %ld %ld\n",
                              field->arg1,
                              field->arg2,
                              field->arg3))
                return TRACE_TYPE_PARTIAL_LINE;
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int
-trace_special_hex(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_special_hex(struct trace_iterator *iter,
+                                          int flags)
 {
        struct special_entry *field;
+       struct trace_seq *s = &iter->seq;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        SEQ_PUT_HEX_FIELD_RET(s, field->arg1);
        SEQ_PUT_HEX_FIELD_RET(s, field->arg2);
        SEQ_PUT_HEX_FIELD_RET(s, field->arg3);
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
-static int
-trace_special_bin(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_special_bin(struct trace_iterator *iter,
+                                          int flags)
 {
        struct special_entry *field;
+       struct trace_seq *s = &iter->seq;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        SEQ_PUT_FIELD_RET(s, field->arg1);
        SEQ_PUT_FIELD_RET(s, field->arg2);
        SEQ_PUT_FIELD_RET(s, field->arg3);
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 }
 
 static struct trace_event trace_special_event = {
-       .type           = TRACE_SPECIAL,
+       .type           = TRACE_SPECIAL,
        .trace          = trace_special_print,
-       .latency_trace  = trace_special_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
@@ -687,78 +1085,133 @@ static struct trace_event trace_special_event = {
 
 /* TRACE_STACK */
 
-static int
-trace_stack_print(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_stack_print(struct trace_iterator *iter,
+                                          int flags)
 {
        struct stack_entry *field;
+       struct trace_seq *s = &iter->seq;
        int i;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
+       if (!trace_seq_puts(s, "<stack trace>\n"))
+               goto partial;
        for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
-               if (i) {
-                       if (!trace_seq_puts(s, " <= "))
-                               goto partial;
+               if (!field->caller[i] || (field->caller[i] == ULONG_MAX))
+                       break;
+               if (!trace_seq_puts(s, " => "))
+                       goto partial;
 
-                       if (!seq_print_ip_sym(s, field->caller[i], flags))
-                               goto partial;
-               }
+               if (!seq_print_ip_sym(s, field->caller[i], flags))
+                       goto partial;
                if (!trace_seq_puts(s, "\n"))
                        goto partial;
        }
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 
  partial:
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
 static struct trace_event trace_stack_event = {
-       .type           = TRACE_STACK,
+       .type           = TRACE_STACK,
        .trace          = trace_stack_print,
-       .latency_trace  = trace_stack_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
 };
 
 /* TRACE_USER_STACK */
-static int
-trace_user_stack_print(struct trace_seq *s, struct trace_entry *entry,
-                      int flags)
+static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
+                                               int flags)
 {
        struct userstack_entry *field;
+       struct trace_seq *s = &iter->seq;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
-       if (!seq_print_userip_objs(field, s, flags))
+       if (!trace_seq_puts(s, "<user stack trace>\n"))
                goto partial;
 
-       if (!trace_seq_putc(s, '\n'))
+       if (!seq_print_userip_objs(field, s, flags))
                goto partial;
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 
  partial:
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
 static struct trace_event trace_user_stack_event = {
-       .type           = TRACE_USER_STACK,
+       .type           = TRACE_USER_STACK,
        .trace          = trace_user_stack_print,
-       .latency_trace  = trace_user_stack_print,
        .raw            = trace_special_print,
        .hex            = trace_special_hex,
        .binary         = trace_special_bin,
 };
 
+/* TRACE_BPRINT */
+static enum print_line_t
+trace_bprint_print(struct trace_iterator *iter, int flags)
+{
+       struct trace_entry *entry = iter->ent;
+       struct trace_seq *s = &iter->seq;
+       struct bprint_entry *field;
+
+       trace_assign_type(field, entry);
+
+       if (!seq_print_ip_sym(s, field->ip, flags))
+               goto partial;
+
+       if (!trace_seq_puts(s, ": "))
+               goto partial;
+
+       if (!trace_seq_bprintf(s, field->fmt, field->buf))
+               goto partial;
+
+       return TRACE_TYPE_HANDLED;
+
+ partial:
+       return TRACE_TYPE_PARTIAL_LINE;
+}
+
+
+static enum print_line_t
+trace_bprint_raw(struct trace_iterator *iter, int flags)
+{
+       struct bprint_entry *field;
+       struct trace_seq *s = &iter->seq;
+
+       trace_assign_type(field, iter->ent);
+
+       if (!trace_seq_printf(s, ": %lx : ", field->ip))
+               goto partial;
+
+       if (!trace_seq_bprintf(s, field->fmt, field->buf))
+               goto partial;
+
+       return TRACE_TYPE_HANDLED;
+
+ partial:
+       return TRACE_TYPE_PARTIAL_LINE;
+}
+
+
+static struct trace_event trace_bprint_event = {
+       .type           = TRACE_BPRINT,
+       .trace          = trace_bprint_print,
+       .raw            = trace_bprint_raw,
+};
+
 /* TRACE_PRINT */
-static int
-trace_print_print(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_print_print(struct trace_iterator *iter,
+                                          int flags)
 {
        struct print_entry *field;
+       struct trace_seq *s = &iter->seq;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
        if (!seq_print_ip_sym(s, field->ip, flags))
                goto partial;
@@ -766,23 +1219,22 @@ trace_print_print(struct trace_seq *s, struct trace_entry *entry, int flags)
        if (!trace_seq_printf(s, ": %s", field->buf))
                goto partial;
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 
  partial:
        return TRACE_TYPE_PARTIAL_LINE;
 }
 
-static int
-trace_print_raw(struct trace_seq *s, struct trace_entry *entry, int flags)
+static enum print_line_t trace_print_raw(struct trace_iterator *iter, int flags)
 {
        struct print_entry *field;
 
-       trace_assign_type(field, entry);
+       trace_assign_type(field, iter->ent);
 
-       if (!trace_seq_printf(s, "# %lx %s", field->ip, field->buf))
+       if (!trace_seq_printf(&iter->seq, "# %lx %s", field->ip, field->buf))
                goto partial;
 
-       return 0;
+       return TRACE_TYPE_HANDLED;
 
  partial:
        return TRACE_TYPE_PARTIAL_LINE;
@@ -791,12 +1243,10 @@ trace_print_raw(struct trace_seq *s, struct trace_entry *entry, int flags)
 static struct trace_event trace_print_event = {
        .type           = TRACE_PRINT,
        .trace          = trace_print_print,
-       .latency_trace  = trace_print_print,
        .raw            = trace_print_raw,
-       .hex            = trace_nop_print,
-       .binary         = trace_nop_print,
 };
 
+
 static struct trace_event *events[] __initdata = {
        &trace_fn_event,
        &trace_ctx_event,
@@ -804,6 +1254,7 @@ static struct trace_event *events[] __initdata = {
        &trace_special_event,
        &trace_stack_event,
        &trace_user_stack_event,
+       &trace_bprint_event,
        &trace_print_event,
        NULL
 };