ftrace: startup tester on dynamic tracing.
This patch adds a startup self test on dynamic code modification and filters. The test filters on a specific function, makes sure that no other function is traced, exectutes the function, then makes sure that the function is traced. This patch also fixes a slight bug with the ftrace selftest, where tracer_enabled was not being set. Signed-off-by: Steven Rostedt <srostedt@redhat.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
This commit is contained in:
parent
7bd2f24c2f
commit
77a2b37d22
3 changed files with 130 additions and 4 deletions
|
@ -55,6 +55,7 @@ struct dyn_ftrace {
|
|||
};
|
||||
|
||||
int ftrace_force_update(void);
|
||||
void ftrace_set_filter(unsigned char *buf, int len, int reset);
|
||||
|
||||
/* defined in arch */
|
||||
extern int ftrace_ip_converted(unsigned long ip);
|
||||
|
@ -70,6 +71,7 @@ extern void ftrace_call(void);
|
|||
extern void mcount_call(void);
|
||||
#else
|
||||
# define ftrace_force_update() ({ 0; })
|
||||
# define ftrace_set_filter(buf, len, reset) do { } while (0)
|
||||
#endif
|
||||
|
||||
static inline void tracer_disable(void)
|
||||
|
|
|
@ -1010,6 +1010,25 @@ ftrace_filter_write(struct file *file, const char __user *ubuf,
|
|||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* ftrace_set_filter - set a function to filter on in ftrace
|
||||
* @buf - the string that holds the function filter text.
|
||||
* @len - the length of the string.
|
||||
* @reset - non zero to reset all filters before applying this filter.
|
||||
*
|
||||
* Filters denote which functions should be enabled when tracing is enabled.
|
||||
* If @buf is NULL and reset is set, all functions will be enabled for tracing.
|
||||
*/
|
||||
notrace void ftrace_set_filter(unsigned char *buf, int len, int reset)
|
||||
{
|
||||
mutex_lock(&ftrace_filter_lock);
|
||||
if (reset)
|
||||
ftrace_filter_reset();
|
||||
if (buf)
|
||||
ftrace_match(buf, len);
|
||||
mutex_unlock(&ftrace_filter_lock);
|
||||
}
|
||||
|
||||
static int notrace
|
||||
ftrace_filter_release(struct inode *inode, struct file *file)
|
||||
{
|
||||
|
|
|
@ -99,6 +99,100 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
|
|||
}
|
||||
|
||||
#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)
|
||||
{
|
||||
/* used to call mcount */
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
/* The ftrace test PASSED */
|
||||
printk(KERN_CONT "PASSED\n");
|
||||
pr_info("Testing dynamic ftrace: ");
|
||||
|
||||
/* enable tracing, and record the filter function */
|
||||
ftrace_enabled = 1;
|
||||
tracer_enabled = 1;
|
||||
|
||||
/* 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;
|
||||
}
|
||||
|
||||
/* filter only on our function */
|
||||
ftrace_set_filter(STR(DYN_FTRACE_TEST_NAME),
|
||||
sizeof(STR(DYN_FTRACE_TEST_NAME)), 1);
|
||||
|
||||
/* enable tracing */
|
||||
tr->ctrl = 1;
|
||||
trace->init(tr);
|
||||
/* Sleep for a 1/10 of a second */
|
||||
msleep(100);
|
||||
|
||||
/* we should have nothing in the buffer */
|
||||
ret = trace_test_buffer(tr, &count);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
if (count) {
|
||||
ret = -1;
|
||||
printk(KERN_CONT ".. filter did not filter .. ");
|
||||
goto out;
|
||||
}
|
||||
|
||||
/* call our function again */
|
||||
func();
|
||||
|
||||
/* sleep again */
|
||||
msleep(100);
|
||||
|
||||
/* stop the tracing. */
|
||||
tr->ctrl = 0;
|
||||
trace->ctrl_update(tr);
|
||||
ftrace_enabled = 0;
|
||||
|
||||
/* check the trace buffer */
|
||||
ret = trace_test_buffer(tr, &count);
|
||||
trace->reset(tr);
|
||||
|
||||
/* we should only have one item */
|
||||
if (!ret && count != 1) {
|
||||
printk(KERN_CONT ".. filter failed ..");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
out:
|
||||
ftrace_enabled = save_ftrace_enabled;
|
||||
tracer_enabled = save_tracer_enabled;
|
||||
|
||||
/* Enable tracing on all functions again */
|
||||
ftrace_set_filter(NULL, 0, 1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
#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
|
||||
|
@ -109,8 +203,13 @@ 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;
|
||||
|
||||
/* make sure functions have been recorded */
|
||||
/* 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 .. ");
|
||||
|
@ -119,6 +218,7 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
|
|||
|
||||
/* start the tracing */
|
||||
ftrace_enabled = 1;
|
||||
tracer_enabled = 1;
|
||||
|
||||
tr->ctrl = 1;
|
||||
trace->init(tr);
|
||||
|
@ -136,8 +236,16 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)
|
|||
if (!ret && !count) {
|
||||
printk(KERN_CONT ".. no entries found ..");
|
||||
ret = -1;
|
||||
goto out;
|
||||
}
|
||||
|
||||
ret = trace_selftest_startup_dynamic_tracing(trace, tr,
|
||||
DYN_FTRACE_TEST_NAME);
|
||||
|
||||
out:
|
||||
ftrace_enabled = save_ftrace_enabled;
|
||||
tracer_enabled = save_tracer_enabled;
|
||||
|
||||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_FTRACE */
|
||||
|
@ -415,6 +523,3 @@ trace_selftest_startup_sched_switch(struct tracer *trace, struct trace_array *tr
|
|||
return ret;
|
||||
}
|
||||
#endif /* CONFIG_CONTEXT_SWITCH_TRACER */
|
||||
|
||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||
|
|
Loading…
Reference in a new issue