drm/vmwgfx: return -EFAULT for copy_to_user errors
[safe/jmp/linux-2.6] / kernel / trace / trace_selftest.c
index a6f1ed7..250e7f9 100644 (file)
@@ -1,69 +1,52 @@
 /* Include in trace.c */
 
+#include <linux/stringify.h>
 #include <linux/kthread.h>
 #include <linux/delay.h>
+#include <linux/slab.h>
 
 static inline int trace_valid_entry(struct trace_entry *entry)
 {
        switch (entry->type) {
        case TRACE_FN:
        case TRACE_CTX:
+       case TRACE_WAKE:
+       case TRACE_STACK:
+       case TRACE_PRINT:
+       case TRACE_SPECIAL:
+       case TRACE_BRANCH:
+       case TRACE_GRAPH_ENT:
+       case TRACE_GRAPH_RET:
+       case TRACE_KSYM:
                return 1;
        }
        return 0;
 }
 
-static int
-trace_test_buffer_cpu(struct trace_array *tr, struct trace_array_cpu *data)
+static int trace_test_buffer_cpu(struct trace_array *tr, int cpu)
 {
-       struct trace_entry *entries;
-       struct page *page;
-       int idx = 0;
-       int i;
+       struct ring_buffer_event *event;
+       struct trace_entry *entry;
+       unsigned int loops = 0;
 
-       BUG_ON(list_empty(&data->trace_pages));
-       page = list_entry(data->trace_pages.next, struct page, lru);
-       entries = page_address(page);
+       while ((event = ring_buffer_consume(tr->buffer, cpu, NULL, NULL))) {
+               entry = ring_buffer_event_data(event);
 
-       if (head_page(data) != entries)
-               goto failed;
-
-       /*
-        * The starting trace buffer always has valid elements,
-        * if any element exists.
-        */
-       entries = head_page(data);
-
-       for (i = 0; i < tr->entries; i++) {
-
-               if (i < data->trace_idx && !trace_valid_entry(&entries[idx])) {
-                       printk(KERN_CONT ".. invalid entry %d ",
-                               entries[idx].type);
+               /*
+                * The ring buffer is a size of trace_buf_size, if
+                * we loop more than the size, there's something wrong
+                * with the ring buffer.
+                */
+               if (loops++ > trace_buf_size) {
+                       printk(KERN_CONT ".. bad ring buffer ");
                        goto failed;
                }
-
-               idx++;
-               if (idx >= ENTRIES_PER_PAGE) {
-                       page = virt_to_page(entries);
-                       if (page->lru.next == &data->trace_pages) {
-                               if (i != tr->entries - 1) {
-                                       printk(KERN_CONT ".. entries buffer mismatch");
-                                       goto failed;
-                               }
-                       } else {
-                               page = list_entry(page->lru.next, struct page, lru);
-                               entries = page_address(page);
-                       }
-                       idx = 0;
+               if (!trace_valid_entry(entry)) {
+                       printk(KERN_CONT ".. invalid entry %d ",
+                               entry->type);
+                       goto failed;
                }
        }
-
-       page = virt_to_page(entries);
-       if (page->lru.next != &data->trace_pages) {
-               printk(KERN_CONT ".. too many entries");
-               goto failed;
-       }
-
        return 0;
 
  failed:
@@ -79,20 +62,31 @@ trace_test_buffer_cpu(struct trace_array *tr, struct trace_array_cpu *data)
  */
 static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
 {
-       unsigned long cnt = 0;
-       int cpu;
-       int ret = 0;
+       unsigned long flags, cnt = 0;
+       int cpu, ret = 0;
 
-       for_each_possible_cpu(cpu) {
-               if (!head_page(tr->data[cpu]))
-                       continue;
+       /* Don't allow flipping of max traces now */
+       local_irq_save(flags);
+       arch_spin_lock(&ftrace_max_lock);
 
-               cnt += tr->data[cpu]->trace_idx;
+       cnt = ring_buffer_entries(tr->buffer);
 
-               ret = trace_test_buffer_cpu(tr, tr->data[cpu]);
+       /*
+        * The trace_test_buffer_cpu runs a while loop to consume all data.
+        * If the calling tracer is broken, and is constantly filling
+        * the buffer, this will run forever, and hard lock the box.
+        * We disable the ring buffer while we do this test to prevent
+        * a hard lock up.
+        */
+       tracing_off();
+       for_each_possible_cpu(cpu) {
+               ret = trace_test_buffer_cpu(tr, cpu);
                if (ret)
                        break;
        }
+       tracing_on();
+       arch_spin_unlock(&ftrace_max_lock);
+       local_irq_restore(flags);
 
        if (count)
                *count = cnt;
@@ -100,28 +94,25 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
        return ret;
 }
 
-#ifdef CONFIG_FTRACE
-
-#ifdef CONFIG_DYNAMIC_FTRACE
-
-#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
-#define __STR(x) #x
-#define STR(x) __STR(x)
-static int DYN_FTRACE_TEST_NAME(void)
+static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret)
 {
-       /* used to call mcount */
-       return 0;
+       printk(KERN_WARNING "Failed to init %s tracer, init returned %d\n",
+               trace->name, init_ret);
 }
+#ifdef CONFIG_FUNCTION_TRACER
+
+#ifdef CONFIG_DYNAMIC_FTRACE
 
 /* Test dynamic code modification and ftrace filters */
 int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
                                           struct trace_array *tr,
                                           int (*func)(void))
 {
-       unsigned long count;
-       int ret;
        int save_ftrace_enabled = ftrace_enabled;
        int save_tracer_enabled = tracer_enabled;
+       unsigned long count;
+       char *func_name;
+       int ret;
 
        /* The ftrace test PASSED */
        printk(KERN_CONT "PASSED\n");
@@ -134,20 +125,23 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
        /* passed in by parameter to fool gcc from optimizing */
        func();
 
-       /* update the records */
-       ret = ftrace_force_update();
-       if (ret) {
-               printk(KERN_CONT ".. ftraced failed .. ");
-               return ret;
-       }
+       /*
+        * Some archs *cough*PowerPC*cough* add characters to the
+        * start of the function names. We simply put a '*' to
+        * accommodate them.
+        */
+       func_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
 
        /* filter only on our function */
-       ftrace_set_filter(STR(DYN_FTRACE_TEST_NAME),
-                         sizeof(STR(DYN_FTRACE_TEST_NAME)), 1);
+       ftrace_set_filter(func_name, strlen(func_name), 1);
 
        /* enable tracing */
-       tr->ctrl = 1;
-       trace->init(tr);
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               goto out;
+       }
+
        /* Sleep for a 1/10 of a second */
        msleep(100);
 
@@ -169,20 +163,21 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
        msleep(100);
 
        /* stop the tracing. */
-       tr->ctrl = 0;
-       trace->ctrl_update(tr);
+       tracing_stop();
        ftrace_enabled = 0;
 
        /* check the trace buffer */
        ret = trace_test_buffer(tr, &count);
        trace->reset(tr);
+       tracing_start();
 
        /* we should only have one item */
        if (!ret && count != 1) {
-               printk(KERN_CONT ".. filter failed ..");
+               printk(KERN_CONT ".. filter failed count=%ld ..", count);
                ret = -1;
                goto out;
        }
+
  out:
        ftrace_enabled = save_ftrace_enabled;
        tracer_enabled = save_tracer_enabled;
@@ -195,6 +190,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 #else
 # define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })
 #endif /* CONFIG_DYNAMIC_FTRACE */
+
 /*
  * Simple verification test of ftrace function tracer.
  * Enable ftrace, sleep 1/10 second, and then read the trace
@@ -203,37 +199,34 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
 int
 trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
 {
-       unsigned long count;
-       int ret;
        int save_ftrace_enabled = ftrace_enabled;
        int save_tracer_enabled = tracer_enabled;
+       unsigned long count;
+       int ret;
 
        /* make sure msleep has been recorded */
        msleep(1);
 
-       /* force the recorded functions to be traced */
-       ret = ftrace_force_update();
-       if (ret) {
-               printk(KERN_CONT ".. ftraced failed .. ");
-               return ret;
-       }
-
        /* start the tracing */
        ftrace_enabled = 1;
        tracer_enabled = 1;
 
-       tr->ctrl = 1;
-       trace->init(tr);
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               goto out;
+       }
+
        /* Sleep for a 1/10 of a second */
        msleep(100);
        /* stop the tracing. */
-       tr->ctrl = 0;
-       trace->ctrl_update(tr);
+       tracing_stop();
        ftrace_enabled = 0;
 
        /* check the trace buffer */
        ret = trace_test_buffer(tr, &count);
        trace->reset(tr);
+       tracing_start();
 
        if (!ret && !count) {
                printk(KERN_CONT ".. no entries found ..");
@@ -248,9 +241,99 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
        ftrace_enabled = save_ftrace_enabled;
        tracer_enabled = save_tracer_enabled;
 
+       /* kill ftrace totally if we failed */
+       if (ret)
+               ftrace_kill();
+
        return ret;
 }
-#endif /* CONFIG_FTRACE */
+#endif /* CONFIG_FUNCTION_TRACER */
+
+
+#ifdef CONFIG_FUNCTION_GRAPH_TRACER
+
+/* Maximum number of functions to trace before diagnosing a hang */
+#define GRAPH_MAX_FUNC_TEST    100000000
+
+static void
+__ftrace_dump(bool disable_tracing, enum ftrace_dump_mode oops_dump_mode);
+static unsigned int graph_hang_thresh;
+
+/* Wrap the real function entry probe to avoid possible hanging */
+static int trace_graph_entry_watchdog(struct ftrace_graph_ent *trace)
+{
+       /* This is harmlessly racy, we want to approximately detect a hang */
+       if (unlikely(++graph_hang_thresh > GRAPH_MAX_FUNC_TEST)) {
+               ftrace_graph_stop();
+               printk(KERN_WARNING "BUG: Function graph tracer hang!\n");
+               if (ftrace_dump_on_oops)
+                       __ftrace_dump(false, DUMP_ALL);
+               return 0;
+       }
+
+       return trace_graph_entry(trace);
+}
+
+/*
+ * Pretty much the same than for the function tracer from which the selftest
+ * has been borrowed.
+ */
+int
+trace_selftest_startup_function_graph(struct tracer *trace,
+                                       struct trace_array *tr)
+{
+       int ret;
+       unsigned long count;
+
+       /*
+        * Simulate the init() callback but we attach a watchdog callback
+        * to detect and recover from possible hangs
+        */
+       tracing_reset_online_cpus(tr);
+       set_graph_array(tr);
+       ret = register_ftrace_graph(&trace_graph_return,
+                                   &trace_graph_entry_watchdog);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               goto out;
+       }
+       tracing_start_cmdline_record();
+
+       /* Sleep for a 1/10 of a second */
+       msleep(100);
+
+       /* Have we just recovered from a hang? */
+       if (graph_hang_thresh > GRAPH_MAX_FUNC_TEST) {
+               tracing_selftest_disabled = true;
+               ret = -1;
+               goto out;
+       }
+
+       tracing_stop();
+
+       /* check the trace buffer */
+       ret = trace_test_buffer(tr, &count);
+
+       trace->reset(tr);
+       tracing_start();
+
+       if (!ret && !count) {
+               printk(KERN_CONT ".. no entries found ..");
+               ret = -1;
+               goto out;
+       }
+
+       /* Don't test dynamic tracing, the function tracer already did */
+
+out:
+       /* Stop it if we failed */
+       if (ret)
+               ftrace_graph_stop();
+
+       return ret;
+}
+#endif /* CONFIG_FUNCTION_GRAPH_TRACER */
+
 
 #ifdef CONFIG_IRQSOFF_TRACER
 int
@@ -261,22 +344,34 @@ trace_selftest_startup_irqsoff(struct tracer *trace, struct trace_array *tr)
        int ret;
 
        /* start the tracing */
-       tr->ctrl = 1;
-       trace->init(tr);
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
        /* reset the max latency */
        tracing_max_latency = 0;
        /* disable interrupts for a bit */
        local_irq_disable();
        udelay(100);
        local_irq_enable();
+
+       /*
+        * Stop the tracer to avoid a warning subsequent
+        * to buffer flipping failure because tracing_stop()
+        * disables the tr and max buffers, making flipping impossible
+        * in case of parallels max irqs off latencies.
+        */
+       trace->stop(tr);
        /* stop the tracing. */
-       tr->ctrl = 0;
-       trace->ctrl_update(tr);
+       tracing_stop();
        /* check both trace buffers */
        ret = trace_test_buffer(tr, NULL);
        if (!ret)
                ret = trace_test_buffer(&max_tr, &count);
        trace->reset(tr);
+       tracing_start();
 
        if (!ret && !count) {
                printk(KERN_CONT ".. no entries found ..");
@@ -297,23 +392,48 @@ trace_selftest_startup_preemptoff(struct tracer *trace, struct trace_array *tr)
        unsigned long count;
        int ret;
 
+       /*
+        * Now that the big kernel lock is no longer preemptable,
+        * and this is called with the BKL held, it will always
+        * fail. If preemption is already disabled, simply
+        * pass the test. When the BKL is removed, or becomes
+        * preemptible again, we will once again test this,
+        * so keep it in.
+        */
+       if (preempt_count()) {
+               printk(KERN_CONT "can not test ... force ");
+               return 0;
+       }
+
        /* start the tracing */
-       tr->ctrl = 1;
-       trace->init(tr);
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
        /* reset the max latency */
        tracing_max_latency = 0;
        /* disable preemption for a bit */
        preempt_disable();
        udelay(100);
        preempt_enable();
+
+       /*
+        * Stop the tracer to avoid a warning subsequent
+        * to buffer flipping failure because tracing_stop()
+        * disables the tr and max buffers, making flipping impossible
+        * in case of parallels max preempt off latencies.
+        */
+       trace->stop(tr);
        /* stop the tracing. */
-       tr->ctrl = 0;
-       trace->ctrl_update(tr);
+       tracing_stop();
        /* check both trace buffers */
        ret = trace_test_buffer(tr, NULL);
        if (!ret)
                ret = trace_test_buffer(&max_tr, &count);
        trace->reset(tr);
+       tracing_start();
 
        if (!ret && !count) {
                printk(KERN_CONT ".. no entries found ..");
@@ -334,9 +454,25 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
        unsigned long count;
        int ret;
 
+       /*
+        * Now that the big kernel lock is no longer preemptable,
+        * and this is called with the BKL held, it will always
+        * fail. If preemption is already disabled, simply
+        * pass the test. When the BKL is removed, or becomes
+        * preemptible again, we will once again test this,
+        * so keep it in.
+        */
+       if (preempt_count()) {
+               printk(KERN_CONT "can not test ... force ");
+               return 0;
+       }
+
        /* start the tracing */
-       tr->ctrl = 1;
-       trace->init(tr);
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               goto out_no_start;
+       }
 
        /* reset the max latency */
        tracing_max_latency = 0;
@@ -349,9 +485,15 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
        /* reverse the order of preempt vs irqs */
        local_irq_enable();
 
+       /*
+        * Stop the tracer to avoid a warning subsequent
+        * to buffer flipping failure because tracing_stop()
+        * disables the tr and max buffers, making flipping impossible
+        * in case of parallels max irqs/preempt off latencies.
+        */
+       trace->stop(tr);
        /* stop the tracing. */
-       tr->ctrl = 0;
-       trace->ctrl_update(tr);
+       tracing_stop();
        /* check both trace buffers */
        ret = trace_test_buffer(tr, NULL);
        if (ret)
@@ -369,8 +511,9 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
 
        /* do the test by disabling interrupts first this time */
        tracing_max_latency = 0;
-       tr->ctrl = 1;
-       trace->ctrl_update(tr);
+       tracing_start();
+       trace->start(tr);
+
        preempt_disable();
        local_irq_disable();
        udelay(100);
@@ -378,9 +521,9 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
        /* reverse the order of preempt vs irqs */
        local_irq_enable();
 
+       trace->stop(tr);
        /* stop the tracing. */
-       tr->ctrl = 0;
-       trace->ctrl_update(tr);
+       tracing_stop();
        /* check both trace buffers */
        ret = trace_test_buffer(tr, NULL);
        if (ret)
@@ -394,7 +537,9 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
                goto out;
        }
 
- out:
+out:
+       tracing_start();
+out_no_start:
        trace->reset(tr);
        tracing_max_latency = save_max;
 
@@ -402,14 +547,23 @@ trace_selftest_startup_preemptirqsoff(struct tracer *trace, struct trace_array *
 }
 #endif /* CONFIG_IRQSOFF_TRACER && CONFIG_PREEMPT_TRACER */
 
+#ifdef CONFIG_NOP_TRACER
+int
+trace_selftest_startup_nop(struct tracer *trace, struct trace_array *tr)
+{
+       /* What could possibly go wrong? */
+       return 0;
+}
+#endif
+
 #ifdef CONFIG_SCHED_TRACER
 static int trace_wakeup_test_thread(void *data)
 {
-       struct completion *x = data;
-
        /* Make this a RT thread, doesn't need to be too high */
+       struct sched_param param = { .sched_priority = 5 };
+       struct completion *x = data;
 
-       rt_mutex_setprio(current, MAX_RT_PRIO - 5);
+       sched_setscheduler(current, SCHED_FIFO, &param);
 
        /* Make it know we have a new prio */
        complete(x);
@@ -452,8 +606,12 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)
        wait_for_completion(&isrt);
 
        /* start the tracing */
-       tr->ctrl = 1;
-       trace->init(tr);
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
        /* reset the max latency */
        tracing_max_latency = 0;
 
@@ -473,9 +631,11 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)
 
        wake_up_process(p);
 
+       /* give a little time to let the thread wake up */
+       msleep(100);
+
        /* stop the tracing. */
-       tr->ctrl = 0;
-       trace->ctrl_update(tr);
+       tracing_stop();
        /* check both trace buffers */
        ret = trace_test_buffer(tr, NULL);
        if (!ret)
@@ -483,6 +643,7 @@ trace_selftest_startup_wakeup(struct tracer *trace, struct trace_array *tr)
 
 
        trace->reset(tr);
+       tracing_start();
 
        tracing_max_latency = save_max;
 
@@ -506,16 +667,20 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr
        int ret;
 
        /* start the tracing */
-       tr->ctrl = 1;
-       trace->init(tr);
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
        /* Sleep for a 1/10 of a second */
        msleep(100);
        /* stop the tracing. */
-       tr->ctrl = 0;
-       trace->ctrl_update(tr);
+       tracing_stop();
        /* check the trace buffer */
        ret = trace_test_buffer(tr, &count);
        trace->reset(tr);
+       tracing_start();
 
        if (!ret && !count) {
                printk(KERN_CONT ".. no entries found ..");
@@ -525,3 +690,121 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr
        return ret;
 }
 #endif /* CONFIG_CONTEXT_SWITCH_TRACER */
+
+#ifdef CONFIG_SYSPROF_TRACER
+int
+trace_selftest_startup_sysprof(struct tracer *trace, struct trace_array *tr)
+{
+       unsigned long count;
+       int ret;
+
+       /* start the tracing */
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
+       /* Sleep for a 1/10 of a second */
+       msleep(100);
+       /* stop the tracing. */
+       tracing_stop();
+       /* check the trace buffer */
+       ret = trace_test_buffer(tr, &count);
+       trace->reset(tr);
+       tracing_start();
+
+       if (!ret && !count) {
+               printk(KERN_CONT ".. no entries found ..");
+               ret = -1;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_SYSPROF_TRACER */
+
+#ifdef CONFIG_BRANCH_TRACER
+int
+trace_selftest_startup_branch(struct tracer *trace, struct trace_array *tr)
+{
+       unsigned long count;
+       int ret;
+
+       /* start the tracing */
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
+       /* Sleep for a 1/10 of a second */
+       msleep(100);
+       /* stop the tracing. */
+       tracing_stop();
+       /* check the trace buffer */
+       ret = trace_test_buffer(tr, &count);
+       trace->reset(tr);
+       tracing_start();
+
+       if (!ret && !count) {
+               printk(KERN_CONT ".. no entries found ..");
+               ret = -1;
+       }
+
+       return ret;
+}
+#endif /* CONFIG_BRANCH_TRACER */
+
+#ifdef CONFIG_KSYM_TRACER
+static int ksym_selftest_dummy;
+
+int
+trace_selftest_startup_ksym(struct tracer *trace, struct trace_array *tr)
+{
+       unsigned long count;
+       int ret;
+
+       /* start the tracing */
+       ret = tracer_init(trace, tr);
+       if (ret) {
+               warn_failed_init_tracer(trace, ret);
+               return ret;
+       }
+
+       ksym_selftest_dummy = 0;
+       /* Register the read-write tracing request */
+
+       ret = process_new_ksym_entry("ksym_selftest_dummy",
+                                    HW_BREAKPOINT_R | HW_BREAKPOINT_W,
+                                       (unsigned long)(&ksym_selftest_dummy));
+
+       if (ret < 0) {
+               printk(KERN_CONT "ksym_trace read-write startup test failed\n");
+               goto ret_path;
+       }
+       /* Perform a read and a write operation over the dummy variable to
+        * trigger the tracer
+        */
+       if (ksym_selftest_dummy == 0)
+               ksym_selftest_dummy++;
+
+       /* stop the tracing. */
+       tracing_stop();
+       /* check the trace buffer */
+       ret = trace_test_buffer(tr, &count);
+       trace->reset(tr);
+       tracing_start();
+
+       /* read & write operations - one each is performed on the dummy variable
+        * triggering two entries in the trace buffer
+        */
+       if (!ret && count != 2) {
+               printk(KERN_CONT "Ksym tracer startup test failed");
+               ret = -1;
+       }
+
+ret_path:
+       return ret;
+}
+#endif /* CONFIG_KSYM_TRACER */
+