summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--kernel/trace/trace_events.c178
1 files changed, 178 insertions, 0 deletions
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 6591d83e1e7..f81d6eec4e4 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -8,10 +8,14 @@
*
*/
+#include <linux/workqueue.h>
+#include <linux/spinlock.h>
+#include <linux/kthread.h>
#include <linux/debugfs.h>
#include <linux/uaccess.h>
#include <linux/module.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include "trace_output.h"
@@ -920,3 +924,177 @@ static __init int event_trace_init(void)
return 0;
}
fs_initcall(event_trace_init);
+
+#ifdef CONFIG_FTRACE_STARTUP_TEST
+
+static DEFINE_SPINLOCK(test_spinlock);
+static DEFINE_SPINLOCK(test_spinlock_irq);
+static DEFINE_MUTEX(test_mutex);
+
+static __init void test_work(struct work_struct *dummy)
+{
+ spin_lock(&test_spinlock);
+ spin_lock_irq(&test_spinlock_irq);
+ udelay(1);
+ spin_unlock_irq(&test_spinlock_irq);
+ spin_unlock(&test_spinlock);
+
+ mutex_lock(&test_mutex);
+ msleep(1);
+ mutex_unlock(&test_mutex);
+}
+
+static __init int event_test_thread(void *unused)
+{
+ void *test_malloc;
+
+ test_malloc = kmalloc(1234, GFP_KERNEL);
+ if (!test_malloc)
+ pr_info("failed to kmalloc\n");
+
+ schedule_on_each_cpu(test_work);
+
+ kfree(test_malloc);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ while (!kthread_should_stop())
+ schedule();
+
+ return 0;
+}
+
+/*
+ * Do various things that may trigger events.
+ */
+static __init void event_test_stuff(void)
+{
+ struct task_struct *test_thread;
+
+ test_thread = kthread_run(event_test_thread, NULL, "test-events");
+ msleep(1);
+ kthread_stop(test_thread);
+}
+
+/*
+ * For every trace event defined, we will test each trace point separately,
+ * and then by groups, and finally all trace points.
+ */
+static __init int event_trace_self_tests(void)
+{
+ struct ftrace_event_call *call;
+ struct event_subsystem *system;
+ char *sysname;
+ int ret;
+
+ pr_info("Running tests on trace events:\n");
+
+ list_for_each_entry(call, &ftrace_events, list) {
+
+ /* Only test those that have a regfunc */
+ if (!call->regfunc)
+ continue;
+
+ pr_info("Testing event %s: ", call->name);
+
+ /*
+ * If an event is already enabled, someone is using
+ * it and the self test should not be on.
+ */
+ if (call->enabled) {
+ pr_warning("Enabled event during self test!\n");
+ WARN_ON_ONCE(1);
+ continue;
+ }
+
+ call->enabled = 1;
+ call->regfunc();
+
+ event_test_stuff();
+
+ call->unregfunc();
+ call->enabled = 0;
+
+ pr_cont("OK\n");
+ }
+
+ /* Now test at the sub system level */
+
+ pr_info("Running tests on trace event systems:\n");
+
+ list_for_each_entry(system, &event_subsystems, list) {
+
+ /* the ftrace system is special, skip it */
+ if (strcmp(system->name, "ftrace") == 0)
+ continue;
+
+ pr_info("Testing event system %s: ", system->name);
+
+ /* ftrace_set_clr_event can modify the name passed in. */
+ sysname = kstrdup(system->name, GFP_KERNEL);
+ if (WARN_ON(!sysname)) {
+ pr_warning("Can't allocate memory, giving up!\n");
+ return 0;
+ }
+ ret = ftrace_set_clr_event(sysname, 1);
+ kfree(sysname);
+ if (WARN_ON_ONCE(ret)) {
+ pr_warning("error enabling system %s\n",
+ system->name);
+ continue;
+ }
+
+ event_test_stuff();
+
+ sysname = kstrdup(system->name, GFP_KERNEL);
+ if (WARN_ON(!sysname)) {
+ pr_warning("Can't allocate memory, giving up!\n");
+ return 0;
+ }
+ ret = ftrace_set_clr_event(sysname, 0);
+ kfree(sysname);
+
+ if (WARN_ON_ONCE(ret))
+ pr_warning("error disabling system %s\n",
+ system->name);
+
+ pr_cont("OK\n");
+ }
+
+ /* Test with all events enabled */
+
+ pr_info("Running tests on all trace events:\n");
+ pr_info("Testing all events: ");
+
+ sysname = kmalloc(4, GFP_KERNEL);
+ if (WARN_ON(!sysname)) {
+ pr_warning("Can't allocate memory, giving up!\n");
+ return 0;
+ }
+ memcpy(sysname, "*:*", 4);
+ ret = ftrace_set_clr_event(sysname, 1);
+ if (WARN_ON_ONCE(ret)) {
+ kfree(sysname);
+ pr_warning("error enabling all events\n");
+ return 0;
+ }
+
+ event_test_stuff();
+
+ /* reset sysname */
+ memcpy(sysname, "*:*", 4);
+ ret = ftrace_set_clr_event(sysname, 0);
+ kfree(sysname);
+
+ if (WARN_ON_ONCE(ret)) {
+ pr_warning("error disabling all events\n");
+ return 0;
+ }
+
+ pr_cont("OK\n");
+
+ return 0;
+}
+
+late_initcall(event_trace_self_tests);
+
+#endif