tracing: Fix uninitialized variable of tracing/trace output
[linux-2.6.git] / kernel / trace / trace_output.c
index 8dadbbb..8e46b33 100644 (file)
@@ -14,7 +14,7 @@
 /* must be a power of 2 */
 #define EVENT_HASHSIZE 128
 
-static DECLARE_RWSEM(trace_event_mutex);
+DECLARE_RWSEM(trace_event_mutex);
 
 DEFINE_PER_CPU(struct trace_seq, ftrace_event_seq);
 EXPORT_PER_CPU_SYMBOL(ftrace_event_seq);
@@ -23,14 +23,21 @@ static struct hlist_head event_hash[EVENT_HASHSIZE] __read_mostly;
 
 static int next_event_type = __TRACE_LAST_TYPE + 1;
 
-void trace_print_seq(struct seq_file *m, struct trace_seq *s)
+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;
 
-       s->buffer[len] = 0;
-       seq_puts(m, s->buffer);
+       ret = seq_write(m, s->buffer, len);
 
-       trace_seq_init(s);
+       /*
+        * 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)
@@ -70,6 +77,9 @@ enum print_line_t trace_print_printk_msg_only(struct trace_iterator *iter)
  * @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
@@ -83,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);
@@ -91,28 +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 len;
+       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 (!len)
+       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)
+       if (ret >= len) {
+               s->full = 1;
                return 0;
+       }
 
        s->len += ret;
 
@@ -133,8 +181,13 @@ 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;
@@ -144,8 +197,13 @@ 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;
 
@@ -154,8 +212,13 @@ int trace_seq_putc(struct trace_seq *s, unsigned char c)
 
 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;
@@ -169,6 +232,9 @@ int trace_seq_putmem_hex(struct trace_seq *s, const void *mem, size_t len)
        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
@@ -186,8 +252,13 @@ void *trace_seq_reserve(struct trace_seq *s, size_t len)
 {
        void *ret;
 
-       if (len > ((PAGE_SIZE - 1) - s->len))
+       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;
@@ -199,8 +270,14 @@ 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");
@@ -213,6 +290,7 @@ int trace_seq_path(struct trace_seq *s, struct path *path)
                return 1;
        }
 
+       s->full = 1;
        return 0;
 }
 
@@ -223,10 +301,9 @@ ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
 {
        unsigned long mask;
        const char *str;
+       const char *ret = p->buffer + p->len;
        int i;
 
-       trace_seq_init(p);
-
        for (i = 0;  flag_array[i].name && flags; i++) {
 
                mask = flag_array[i].mask;
@@ -249,7 +326,7 @@ ftrace_print_flags_seq(struct trace_seq *p, const char *delim,
 
        trace_seq_putc(p, 0);
 
-       return p->buffer;
+       return ret;
 }
 EXPORT_SYMBOL(ftrace_print_flags_seq);
 
@@ -258,8 +335,7 @@ ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
                         const struct trace_print_flags *symbol_array)
 {
        int i;
-
-       trace_seq_init(p);
+       const char *ret = p->buffer + p->len;
 
        for (i = 0;  symbol_array[i].name; i++) {
 
@@ -275,7 +351,7 @@ ftrace_print_symbols_seq(struct trace_seq *p, unsigned long val,
                
        trace_seq_putc(p, 0);
 
-       return p->buffer;
+       return ret;
 }
 EXPORT_SYMBOL(ftrace_print_symbols_seq);
 
@@ -341,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;
 
@@ -378,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();
@@ -431,18 +510,23 @@ seq_print_ip_sym(struct trace_seq *s, unsigned long ip, unsigned long sym_flags)
        return ret;
 }
 
-static int
-lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu)
+/**
+ * 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;
-       char comm[TASK_COMM_LEN];
+       int ret;
 
-       trace_find_cmdline(entry->pid, comm);
        hardirq = entry->flags & TRACE_FLAG_HARDIRQ;
        softirq = entry->flags & TRACE_FLAG_SOFTIRQ;
 
-       if (!trace_seq_printf(s, "%8.8s-%-5d %3d%c%c%c",
-                             comm, entry->pid, cpu,
+       if (!trace_seq_printf(s, "%c%c%c",
                              (entry->flags & TRACE_FLAG_IRQS_OFF) ? 'd' :
                                (entry->flags & TRACE_FLAG_IRQS_NOSUPPORT) ?
                                  'X' : '.',
@@ -453,8 +537,31 @@ lat_print_generic(struct trace_seq *s, struct trace_entry *entry, int cpu)
                return 0;
 
        if (entry->preempt_count)
-               return trace_seq_printf(s, "%x", entry->preempt_count);
-       return trace_seq_puts(s, ".");
+               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;
@@ -672,6 +779,16 @@ int register_ftrace_event(struct trace_event *event)
 }
 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
  * @event: the event to remove
@@ -679,8 +796,7 @@ EXPORT_SYMBOL_GPL(register_ftrace_event);
 int unregister_ftrace_event(struct trace_event *event)
 {
        down_write(&trace_event_mutex);
-       hlist_del(&event->node);
-       list_del(&event->list);
+       __unregister_ftrace_event(event);
        up_write(&trace_event_mutex);
 
        return 0;
@@ -819,7 +935,7 @@ static int trace_ctxwake_raw(struct trace_iterator *iter, char S)
        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(&iter->seq, "%d %d %c %d %d %d %c\n",
                              field->prev_pid,
@@ -854,7 +970,7 @@ static int trace_ctxwake_hex(struct trace_iterator *iter, char S)
        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);
@@ -978,7 +1094,7 @@ static enum print_line_t trace_stack_print(struct trace_iterator *iter,
 
        trace_assign_type(field, iter->ent);
 
-       if (!trace_seq_puts(s, "\n"))
+       if (!trace_seq_puts(s, "<stack trace>\n"))
                goto partial;
        for (i = 0; i < FTRACE_STACK_ENTRIES; i++) {
                if (!field->caller[i] || (field->caller[i] == ULONG_MAX))
@@ -1015,7 +1131,7 @@ static enum print_line_t trace_user_stack_print(struct trace_iterator *iter,
 
        trace_assign_type(field, iter->ent);
 
-       if (!trace_seq_putc(s, '\n'))
+       if (!trace_seq_puts(s, "<user stack trace>\n"))
                goto partial;
 
        if (!seq_print_userip_objs(field, s, flags))