|
@@ -101,6 +101,206 @@ static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret)
|
|
|
|
|
|
#ifdef CONFIG_DYNAMIC_FTRACE
|
|
|
|
|
|
+static int trace_selftest_test_probe1_cnt;
|
|
|
+static void trace_selftest_test_probe1_func(unsigned long ip,
|
|
|
+ unsigned long pip)
|
|
|
+{
|
|
|
+ trace_selftest_test_probe1_cnt++;
|
|
|
+}
|
|
|
+
|
|
|
+static int trace_selftest_test_probe2_cnt;
|
|
|
+static void trace_selftest_test_probe2_func(unsigned long ip,
|
|
|
+ unsigned long pip)
|
|
|
+{
|
|
|
+ trace_selftest_test_probe2_cnt++;
|
|
|
+}
|
|
|
+
|
|
|
+static int trace_selftest_test_probe3_cnt;
|
|
|
+static void trace_selftest_test_probe3_func(unsigned long ip,
|
|
|
+ unsigned long pip)
|
|
|
+{
|
|
|
+ trace_selftest_test_probe3_cnt++;
|
|
|
+}
|
|
|
+
|
|
|
+static int trace_selftest_test_global_cnt;
|
|
|
+static void trace_selftest_test_global_func(unsigned long ip,
|
|
|
+ unsigned long pip)
|
|
|
+{
|
|
|
+ trace_selftest_test_global_cnt++;
|
|
|
+}
|
|
|
+
|
|
|
+static int trace_selftest_test_dyn_cnt;
|
|
|
+static void trace_selftest_test_dyn_func(unsigned long ip,
|
|
|
+ unsigned long pip)
|
|
|
+{
|
|
|
+ trace_selftest_test_dyn_cnt++;
|
|
|
+}
|
|
|
+
|
|
|
+static struct ftrace_ops test_probe1 = {
|
|
|
+ .func = trace_selftest_test_probe1_func,
|
|
|
+};
|
|
|
+
|
|
|
+static struct ftrace_ops test_probe2 = {
|
|
|
+ .func = trace_selftest_test_probe2_func,
|
|
|
+};
|
|
|
+
|
|
|
+static struct ftrace_ops test_probe3 = {
|
|
|
+ .func = trace_selftest_test_probe3_func,
|
|
|
+};
|
|
|
+
|
|
|
+static struct ftrace_ops test_global = {
|
|
|
+ .func = trace_selftest_test_global_func,
|
|
|
+ .flags = FTRACE_OPS_FL_GLOBAL,
|
|
|
+};
|
|
|
+
|
|
|
+static void print_counts(void)
|
|
|
+{
|
|
|
+ printk("(%d %d %d %d %d) ",
|
|
|
+ trace_selftest_test_probe1_cnt,
|
|
|
+ trace_selftest_test_probe2_cnt,
|
|
|
+ trace_selftest_test_probe3_cnt,
|
|
|
+ trace_selftest_test_global_cnt,
|
|
|
+ trace_selftest_test_dyn_cnt);
|
|
|
+}
|
|
|
+
|
|
|
+static void reset_counts(void)
|
|
|
+{
|
|
|
+ trace_selftest_test_probe1_cnt = 0;
|
|
|
+ trace_selftest_test_probe2_cnt = 0;
|
|
|
+ trace_selftest_test_probe3_cnt = 0;
|
|
|
+ trace_selftest_test_global_cnt = 0;
|
|
|
+ trace_selftest_test_dyn_cnt = 0;
|
|
|
+}
|
|
|
+
|
|
|
+static int trace_selftest_ops(int cnt)
|
|
|
+{
|
|
|
+ int save_ftrace_enabled = ftrace_enabled;
|
|
|
+ struct ftrace_ops *dyn_ops;
|
|
|
+ char *func1_name;
|
|
|
+ char *func2_name;
|
|
|
+ int len1;
|
|
|
+ int len2;
|
|
|
+ int ret = -1;
|
|
|
+
|
|
|
+ printk(KERN_CONT "PASSED\n");
|
|
|
+ pr_info("Testing dynamic ftrace ops #%d: ", cnt);
|
|
|
+
|
|
|
+ ftrace_enabled = 1;
|
|
|
+ reset_counts();
|
|
|
+
|
|
|
+ /* Handle PPC64 '.' name */
|
|
|
+ func1_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
|
|
|
+ func2_name = "*" __stringify(DYN_FTRACE_TEST_NAME2);
|
|
|
+ len1 = strlen(func1_name);
|
|
|
+ len2 = strlen(func2_name);
|
|
|
+
|
|
|
+ /*
|
|
|
+ * Probe 1 will trace function 1.
|
|
|
+ * Probe 2 will trace function 2.
|
|
|
+ * Probe 3 will trace functions 1 and 2.
|
|
|
+ */
|
|
|
+ ftrace_set_filter(&test_probe1, func1_name, len1, 1);
|
|
|
+ ftrace_set_filter(&test_probe2, func2_name, len2, 1);
|
|
|
+ ftrace_set_filter(&test_probe3, func1_name, len1, 1);
|
|
|
+ ftrace_set_filter(&test_probe3, func2_name, len2, 0);
|
|
|
+
|
|
|
+ register_ftrace_function(&test_probe1);
|
|
|
+ register_ftrace_function(&test_probe2);
|
|
|
+ register_ftrace_function(&test_probe3);
|
|
|
+ register_ftrace_function(&test_global);
|
|
|
+
|
|
|
+ DYN_FTRACE_TEST_NAME();
|
|
|
+
|
|
|
+ print_counts();
|
|
|
+
|
|
|
+ if (trace_selftest_test_probe1_cnt != 1)
|
|
|
+ goto out;
|
|
|
+ if (trace_selftest_test_probe2_cnt != 0)
|
|
|
+ goto out;
|
|
|
+ if (trace_selftest_test_probe3_cnt != 1)
|
|
|
+ goto out;
|
|
|
+ if (trace_selftest_test_global_cnt == 0)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ DYN_FTRACE_TEST_NAME2();
|
|
|
+
|
|
|
+ print_counts();
|
|
|
+
|
|
|
+ if (trace_selftest_test_probe1_cnt != 1)
|
|
|
+ goto out;
|
|
|
+ if (trace_selftest_test_probe2_cnt != 1)
|
|
|
+ goto out;
|
|
|
+ if (trace_selftest_test_probe3_cnt != 2)
|
|
|
+ goto out;
|
|
|
+
|
|
|
+ /* Add a dynamic probe */
|
|
|
+ dyn_ops = kzalloc(sizeof(*dyn_ops), GFP_KERNEL);
|
|
|
+ if (!dyn_ops) {
|
|
|
+ printk("MEMORY ERROR ");
|
|
|
+ goto out;
|
|
|
+ }
|
|
|
+
|
|
|
+ dyn_ops->func = trace_selftest_test_dyn_func;
|
|
|
+
|
|
|
+ register_ftrace_function(dyn_ops);
|
|
|
+
|
|
|
+ trace_selftest_test_global_cnt = 0;
|
|
|
+
|
|
|
+ DYN_FTRACE_TEST_NAME();
|
|
|
+
|
|
|
+ print_counts();
|
|
|
+
|
|
|
+ if (trace_selftest_test_probe1_cnt != 2)
|
|
|
+ goto out_free;
|
|
|
+ if (trace_selftest_test_probe2_cnt != 1)
|
|
|
+ goto out_free;
|
|
|
+ if (trace_selftest_test_probe3_cnt != 3)
|
|
|
+ goto out_free;
|
|
|
+ if (trace_selftest_test_global_cnt == 0)
|
|
|
+ goto out;
|
|
|
+ if (trace_selftest_test_dyn_cnt == 0)
|
|
|
+ goto out_free;
|
|
|
+
|
|
|
+ DYN_FTRACE_TEST_NAME2();
|
|
|
+
|
|
|
+ print_counts();
|
|
|
+
|
|
|
+ if (trace_selftest_test_probe1_cnt != 2)
|
|
|
+ goto out_free;
|
|
|
+ if (trace_selftest_test_probe2_cnt != 2)
|
|
|
+ goto out_free;
|
|
|
+ if (trace_selftest_test_probe3_cnt != 4)
|
|
|
+ goto out_free;
|
|
|
+
|
|
|
+ ret = 0;
|
|
|
+ out_free:
|
|
|
+ unregister_ftrace_function(dyn_ops);
|
|
|
+ kfree(dyn_ops);
|
|
|
+
|
|
|
+ out:
|
|
|
+ /* Purposely unregister in the same order */
|
|
|
+ unregister_ftrace_function(&test_probe1);
|
|
|
+ unregister_ftrace_function(&test_probe2);
|
|
|
+ unregister_ftrace_function(&test_probe3);
|
|
|
+ unregister_ftrace_function(&test_global);
|
|
|
+
|
|
|
+ /* Make sure everything is off */
|
|
|
+ reset_counts();
|
|
|
+ DYN_FTRACE_TEST_NAME();
|
|
|
+ DYN_FTRACE_TEST_NAME();
|
|
|
+
|
|
|
+ if (trace_selftest_test_probe1_cnt ||
|
|
|
+ trace_selftest_test_probe2_cnt ||
|
|
|
+ trace_selftest_test_probe3_cnt ||
|
|
|
+ trace_selftest_test_global_cnt ||
|
|
|
+ trace_selftest_test_dyn_cnt)
|
|
|
+ ret = -1;
|
|
|
+
|
|
|
+ ftrace_enabled = save_ftrace_enabled;
|
|
|
+
|
|
|
+ return ret;
|
|
|
+}
|
|
|
+
|
|
|
/* Test dynamic code modification and ftrace filters */
|
|
|
int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
|
|
struct trace_array *tr,
|
|
@@ -166,16 +366,20 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
|
|
|
|
|
/* 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) {
|
|
|
+ trace->reset(tr);
|
|
|
printk(KERN_CONT ".. filter failed count=%ld ..", count);
|
|
|
ret = -1;
|
|
|
goto out;
|
|
|
}
|
|
|
|
|
|
+ /* Test the ops with global tracing running */
|
|
|
+ ret = trace_selftest_ops(1);
|
|
|
+ trace->reset(tr);
|
|
|
+
|
|
|
out:
|
|
|
ftrace_enabled = save_ftrace_enabled;
|
|
|
tracer_enabled = save_tracer_enabled;
|
|
@@ -183,6 +387,10 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
|
|
/* Enable tracing on all functions again */
|
|
|
ftrace_set_global_filter(NULL, 0, 1);
|
|
|
|
|
|
+ /* Test the ops with global tracing off */
|
|
|
+ if (!ret)
|
|
|
+ ret = trace_selftest_ops(2);
|
|
|
+
|
|
|
return ret;
|
|
|
}
|
|
|
#else
|