Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux-2.6
[pandora-kernel.git] / kernel / trace / trace.c
index ea38652..c8760ec 100644 (file)
 unsigned long __read_mostly    tracing_max_latency = (cycle_t)ULONG_MAX;
 unsigned long __read_mostly    tracing_thresh;
 
+/*
+ * We need to change this state when a selftest is running.
+ * A selftest will lurk into the ring-buffer to count the
+ * entries inserted during the selftest although some concurrent
+ * insertions into the ring-buffer such as ftrace_printk could occurred
+ * at the same time, giving false positive or negative results.
+ */
+static bool __read_mostly tracing_selftest_running;
+
 /* For tracers that don't implement custom flags */
 static struct tracer_opt dummy_tracer_opt[] = {
        { }
@@ -278,6 +287,7 @@ static const char *trace_options[] = {
        "annotate",
        "userstacktrace",
        "sym-userobj",
+       "printk-msg-only",
        NULL
 };
 
@@ -311,7 +321,7 @@ __update_max_tr(struct trace_array *tr, struct task_struct *tsk, int cpu)
 
        memcpy(data->comm, tsk->comm, TASK_COMM_LEN);
        data->pid = tsk->pid;
-       data->uid = tsk->uid;
+       data->uid = task_uid(tsk);
        data->nice = tsk->static_prio - 20 - MAX_RT_PRIO;
        data->policy = tsk->policy;
        data->rt_priority = tsk->rt_priority;
@@ -566,6 +576,8 @@ int register_tracer(struct tracer *type)
        unlock_kernel();
        mutex_lock(&trace_types_lock);
 
+       tracing_selftest_running = true;
+
        for (t = trace_types; t; t = t->next) {
                if (strcmp(type->name, t->name) == 0) {
                        /* already found */
@@ -589,6 +601,7 @@ int register_tracer(struct tracer *type)
                struct tracer *saved_tracer = current_trace;
                struct trace_array *tr = &global_trace;
                int i;
+
                /*
                 * Run a selftest on this tracer.
                 * Here we reset the trace buffer, and set the current
@@ -624,6 +637,7 @@ int register_tracer(struct tracer *type)
                max_tracer_type_len = len;
 
  out:
+       tracing_selftest_running = false;
        mutex_unlock(&trace_types_lock);
        lock_kernel();
 
@@ -665,6 +679,16 @@ void tracing_reset(struct trace_array *tr, int cpu)
        ftrace_enable_cpu();
 }
 
+void tracing_reset_online_cpus(struct trace_array *tr)
+{
+       int cpu;
+
+       tr->time_start = ftrace_now(tr->cpu);
+
+       for_each_online_cpu(cpu)
+               tracing_reset(tr, cpu);
+}
+
 #define SAVED_CMDLINES 128
 static unsigned map_pid_to_cmdline[PID_MAX_DEFAULT+1];
 static unsigned map_cmdline_to_pid[SAVED_CMDLINES];
@@ -1734,6 +1758,13 @@ lat_print_timestamp(struct trace_seq *s, u64 abs_usecs,
 
 static const char state_to_char[] = TASK_STATE_TO_CHAR_STR;
 
+static int task_state_char(unsigned long state)
+{
+       int bit = state ? __ffs(state) + 1 : 0;
+
+       return bit < sizeof(state_to_char) - 1 ? state_to_char[bit] : '?';
+}
+
 /*
  * The message is supposed to contain an ending newline.
  * If the printing stops prematurely, try to add a newline of our own.
@@ -1802,7 +1833,6 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
        char *comm;
        int S, T;
        int i;
-       unsigned state;
 
        if (entry->type == TRACE_CONT)
                return TRACE_TYPE_HANDLED;
@@ -1848,12 +1878,8 @@ print_lat_fmt(struct trace_iterator *iter, unsigned int trace_idx, int cpu)
 
                trace_assign_type(field, entry);
 
-               T = field->next_state < sizeof(state_to_char) ?
-                       state_to_char[field->next_state] : 'X';
-
-               state = field->prev_state ?
-                       __ffs(field->prev_state) + 1 : 0;
-               S = state < sizeof(state_to_char) - 1 ? state_to_char[state] : 'X';
+               T = task_state_char(field->next_state);
+               S = task_state_char(field->prev_state);
                comm = trace_find_cmdline(field->next_pid);
                trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c %s\n",
                                 field->prev_pid,
@@ -1994,10 +2020,8 @@ static enum print_line_t print_trace_fmt(struct trace_iterator *iter)
 
                trace_assign_type(field, entry);
 
-               S = field->prev_state < sizeof(state_to_char) ?
-                       state_to_char[field->prev_state] : 'X';
-               T = field->next_state < sizeof(state_to_char) ?
-                       state_to_char[field->next_state] : 'X';
+               T = task_state_char(field->next_state);
+               S = task_state_char(field->prev_state);
                ret = trace_seq_printf(s, " %5d:%3d:%c %s [%03d] %5d:%3d:%c\n",
                                       field->prev_pid,
                                       field->prev_prio,
@@ -2127,12 +2151,9 @@ static enum print_line_t print_raw_fmt(struct trace_iterator *iter)
 
                trace_assign_type(field, entry);
 
-               S = field->prev_state < sizeof(state_to_char) ?
-                       state_to_char[field->prev_state] : 'X';
-               T = field->next_state < sizeof(state_to_char) ?
-                       state_to_char[field->next_state] : 'X';
-               if (entry->type == TRACE_WAKE)
-                       S = '+';
+               T = task_state_char(field->next_state);
+               S = entry->type == TRACE_WAKE ? '+' :
+                       task_state_char(field->prev_state);
                ret = trace_seq_printf(s, "%d %d %c %d %d %d %c\n",
                                       field->prev_pid,
                                       field->prev_prio,
@@ -2219,12 +2240,9 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
 
                trace_assign_type(field, entry);
 
-               S = field->prev_state < sizeof(state_to_char) ?
-                       state_to_char[field->prev_state] : 'X';
-               T = field->next_state < sizeof(state_to_char) ?
-                       state_to_char[field->next_state] : 'X';
-               if (entry->type == TRACE_WAKE)
-                       S = '+';
+               T = task_state_char(field->next_state);
+               S = entry->type == TRACE_WAKE ? '+' :
+                       task_state_char(field->prev_state);
                SEQ_PUT_HEX_FIELD_RET(s, field->prev_pid);
                SEQ_PUT_HEX_FIELD_RET(s, field->prev_prio);
                SEQ_PUT_HEX_FIELD_RET(s, S);
@@ -2252,6 +2270,25 @@ static enum print_line_t print_hex_fmt(struct trace_iterator *iter)
        return TRACE_TYPE_HANDLED;
 }
 
+static enum print_line_t 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, field->buf);
+       if (!ret)
+               return TRACE_TYPE_PARTIAL_LINE;
+
+       if (entry->flags & TRACE_FLAG_CONT)
+               trace_seq_print_cont(s, iter);
+
+       return TRACE_TYPE_HANDLED;
+}
+
 static enum print_line_t print_bin_fmt(struct trace_iterator *iter)
 {
        struct trace_seq *s = &iter->seq;
@@ -2332,6 +2369,11 @@ static enum print_line_t print_trace_line(struct trace_iterator *iter)
                        return ret;
        }
 
+       if (iter->ent->type == TRACE_PRINT &&
+                       trace_flags & TRACE_ITER_PRINTK &&
+                       trace_flags & TRACE_ITER_PRINTK_MSGONLY)
+               return print_printk_msg_only(iter);
+
        if (trace_flags & TRACE_ITER_BIN)
                return print_bin_fmt(iter);
 
@@ -2412,7 +2454,7 @@ __tracing_open(struct inode *inode, struct file *file, int *ret)
 
        /* Notify the tracer early; before we stop tracing. */
        if (iter->trace && iter->trace->open)
-                       iter->trace->open(iter);
+               iter->trace->open(iter);
 
        /* Annotate start of buffers if we had overruns */
        if (ring_buffer_overruns(iter->tr->buffer))
@@ -2633,7 +2675,7 @@ tracing_cpumask_read(struct file *filp, char __user *ubuf,
 
        mutex_lock(&tracing_cpumask_update_lock);
 
-       len = cpumask_scnprintf(mask_str, count, tracing_cpumask);
+       len = cpumask_scnprintf(mask_str, count, &tracing_cpumask);
        if (count - len < 2) {
                count = -EINVAL;
                goto out_err;
@@ -2654,7 +2696,7 @@ tracing_cpumask_write(struct file *filp, const char __user *ubuf,
        int err, cpu;
 
        mutex_lock(&tracing_cpumask_update_lock);
-       err = cpumask_parse_user(ubuf, count, tracing_cpumask_new);
+       err = cpumask_parse_user(ubuf, count, &tracing_cpumask_new);
        if (err)
                goto err_unlock;
 
@@ -3577,24 +3619,17 @@ static __init int tracer_init_debugfs(void)
 
 int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
 {
-       /*
-        * Raw Spinlock because a normal spinlock would be traced here
-        * and append an irrelevant couple spin_lock_irqsave/
-        * spin_unlock_irqrestore traced by ftrace around this
-        * TRACE_PRINTK trace.
-        */
-       static raw_spinlock_t trace_buf_lock =
-                               (raw_spinlock_t)__RAW_SPIN_LOCK_UNLOCKED;
+       static DEFINE_SPINLOCK(trace_buf_lock);
        static char trace_buf[TRACE_BUF_SIZE];
 
        struct ring_buffer_event *event;
        struct trace_array *tr = &global_trace;
        struct trace_array_cpu *data;
-       struct print_entry *entry;
-       unsigned long flags, irq_flags;
        int cpu, len = 0, size, pc;
+       struct print_entry *entry;
+       unsigned long irq_flags;
 
-       if (tracing_disabled)
+       if (tracing_disabled || tracing_selftest_running)
                return 0;
 
        pc = preempt_count();
@@ -3605,8 +3640,8 @@ int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
        if (unlikely(atomic_read(&data->disabled)))
                goto out;
 
-       local_irq_save(flags);
-       __raw_spin_lock(&trace_buf_lock);
+       pause_graph_tracing();
+       spin_lock_irqsave(&trace_buf_lock, irq_flags);
        len = vsnprintf(trace_buf, TRACE_BUF_SIZE, fmt, args);
 
        len = min(len, TRACE_BUF_SIZE-1);
@@ -3617,7 +3652,7 @@ int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
        if (!event)
                goto out_unlock;
        entry = ring_buffer_event_data(event);
-       tracing_generic_entry_update(&entry->ent, flags, pc);
+       tracing_generic_entry_update(&entry->ent, irq_flags, pc);
        entry->ent.type                 = TRACE_PRINT;
        entry->ip                       = ip;
        entry->depth                    = depth;
@@ -3627,9 +3662,8 @@ int trace_vprintk(unsigned long ip, int depth, const char *fmt, va_list args)
        ring_buffer_unlock_commit(tr->buffer, event, irq_flags);
 
  out_unlock:
-       __raw_spin_unlock(&trace_buf_lock);
-       local_irq_restore(flags);
-
+       spin_unlock_irqrestore(&trace_buf_lock, irq_flags);
+       unpause_graph_tracing();
  out:
        preempt_enable_notrace();
 
@@ -3646,13 +3680,7 @@ int __ftrace_printk(unsigned long ip, const char *fmt, ...)
                return 0;
 
        va_start(ap, fmt);
-
-#ifdef CONFIG_FUNCTION_GRAPH_TRACER
-       ret = trace_vprintk(ip, current->curr_ret_stack, fmt, ap);
-#else
-       ret = trace_vprintk(ip, -1, fmt, ap);
-#endif
-
+       ret = trace_vprintk(ip, task_curr_ret_stack(current), fmt, ap);
        va_end(ap);
        return ret;
 }