Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 323622
b: refs/heads/master
c: ea701f1
h: refs/heads/master
v: v3
  • Loading branch information
Steven Rostedt authored and Steven Rostedt committed Jul 31, 2012
1 parent e73d8e1 commit 2e772d1
Show file tree
Hide file tree
Showing 4 changed files with 164 additions and 1 deletion.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 47239c4d8d6a24796039cada69d477a2b8cac9d6
refs/heads/master: ea701f11da44b44907af226fe5a5f57d2f26eeb2
6 changes: 6 additions & 0 deletions trunk/include/linux/ftrace.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,6 +220,10 @@ extern void ftrace_stub(unsigned long a0, unsigned long a1,
*/
#define register_ftrace_function(ops) ({ 0; })
#define unregister_ftrace_function(ops) ({ 0; })
static inline int ftrace_nr_registered_ops(void)
{
return 0;
}
static inline void clear_ftrace_function(void) { }
static inline void ftrace_kill(void) { }
static inline void ftrace_stop(void) { }
Expand Down Expand Up @@ -275,6 +279,8 @@ extern void unregister_ftrace_function_probe_all(char *glob);

extern int ftrace_text_reserved(void *start, void *end);

extern int ftrace_nr_registered_ops(void);

/*
* The dyn_ftrace record's flags field is split into two parts.
* the first part which is '0-FTRACE_REF_MAX' is a counter of
Expand Down
21 changes: 21 additions & 0 deletions trunk/kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,27 @@ static void ftrace_ops_no_ops(unsigned long ip, unsigned long parent_ip);
#define ftrace_ops_list_func ((ftrace_func_t)ftrace_ops_no_ops)
#endif

/**
* ftrace_nr_registered_ops - return number of ops registered
*
* Returns the number of ftrace_ops registered and tracing functions
*/
int ftrace_nr_registered_ops(void)
{
struct ftrace_ops *ops;
int cnt = 0;

mutex_lock(&ftrace_lock);

for (ops = ftrace_ops_list;
ops != &ftrace_list_end; ops = ops->next)
cnt++;

mutex_unlock(&ftrace_lock);

return cnt;
}

/*
* Traverse the ftrace_global_list, invoking all entries. The reason that we
* can use rcu_dereference_raw() is that elements removed from this list
Expand Down
136 changes: 136 additions & 0 deletions trunk/kernel/trace/trace_selftest.c
Original file line number Diff line number Diff line change
Expand Up @@ -406,8 +406,141 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,

return ret;
}

static int trace_selftest_recursion_cnt;
static void trace_selftest_test_recursion_func(unsigned long ip,
unsigned long pip,
struct ftrace_ops *op,
struct pt_regs *pt_regs)
{
/*
* This function is registered without the recursion safe flag.
* The ftrace infrastructure should provide the recursion
* protection. If not, this will crash the kernel!
*/
trace_selftest_recursion_cnt++;
DYN_FTRACE_TEST_NAME();
}

static void trace_selftest_test_recursion_safe_func(unsigned long ip,
unsigned long pip,
struct ftrace_ops *op,
struct pt_regs *pt_regs)
{
/*
* We said we would provide our own recursion. By calling
* this function again, we should recurse back into this function
* and count again. But this only happens if the arch supports
* all of ftrace features and nothing else is using the function
* tracing utility.
*/
if (trace_selftest_recursion_cnt++)
return;
DYN_FTRACE_TEST_NAME();
}

static struct ftrace_ops test_rec_probe = {
.func = trace_selftest_test_recursion_func,
};

static struct ftrace_ops test_recsafe_probe = {
.func = trace_selftest_test_recursion_safe_func,
.flags = FTRACE_OPS_FL_RECURSION_SAFE,
};

static int
trace_selftest_function_recursion(void)
{
int save_ftrace_enabled = ftrace_enabled;
int save_tracer_enabled = tracer_enabled;
char *func_name;
int len;
int ret;
int cnt;

/* The previous test PASSED */
pr_cont("PASSED\n");
pr_info("Testing ftrace recursion: ");


/* enable tracing, and record the filter function */
ftrace_enabled = 1;
tracer_enabled = 1;

/* Handle PPC64 '.' name */
func_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
len = strlen(func_name);

ret = ftrace_set_filter(&test_rec_probe, func_name, len, 1);
if (ret) {
pr_cont("*Could not set filter* ");
goto out;
}

ret = register_ftrace_function(&test_rec_probe);
if (ret) {
pr_cont("*could not register callback* ");
goto out;
}

DYN_FTRACE_TEST_NAME();

unregister_ftrace_function(&test_rec_probe);

ret = -1;
if (trace_selftest_recursion_cnt != 1) {
pr_cont("*callback not called once (%d)* ",
trace_selftest_recursion_cnt);
goto out;
}

trace_selftest_recursion_cnt = 1;

pr_cont("PASSED\n");
pr_info("Testing ftrace recursion safe: ");

ret = ftrace_set_filter(&test_recsafe_probe, func_name, len, 1);
if (ret) {
pr_cont("*Could not set filter* ");
goto out;
}

ret = register_ftrace_function(&test_recsafe_probe);
if (ret) {
pr_cont("*could not register callback* ");
goto out;
}

DYN_FTRACE_TEST_NAME();

unregister_ftrace_function(&test_recsafe_probe);

/*
* If arch supports all ftrace features, and no other task
* was on the list, we should be fine.
*/
if (!ftrace_nr_registered_ops() && !FTRACE_FORCE_LIST_FUNC)
cnt = 2; /* Should have recursed */
else
cnt = 1;

ret = -1;
if (trace_selftest_recursion_cnt != cnt) {
pr_cont("*callback not called expected %d times (%d)* ",
cnt, trace_selftest_recursion_cnt);
goto out;
}

ret = 0;
out:
ftrace_enabled = save_ftrace_enabled;
tracer_enabled = save_tracer_enabled;

return ret;
}
#else
# define trace_selftest_startup_dynamic_tracing(trace, tr, func) ({ 0; })
# define trace_selftest_function_recursion() ({ 0; })
#endif /* CONFIG_DYNAMIC_FTRACE */

/*
Expand Down Expand Up @@ -455,7 +588,10 @@ trace_selftest_startup_function(struct tracer *trace, struct trace_array *tr)

ret = trace_selftest_startup_dynamic_tracing(trace, tr,
DYN_FTRACE_TEST_NAME);
if (ret)
goto out;

ret = trace_selftest_function_recursion();
out:
ftrace_enabled = save_ftrace_enabled;
tracer_enabled = save_tracer_enabled;
Expand Down

0 comments on commit 2e772d1

Please sign in to comment.