Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-2.6-trace into perf/core
This commit is contained in:
commit
29510ec3b6
@ -29,9 +29,22 @@ ftrace_enable_sysctl(struct ctl_table *table, int write,
|
|||||||
|
|
||||||
typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
|
typedef void (*ftrace_func_t)(unsigned long ip, unsigned long parent_ip);
|
||||||
|
|
||||||
|
struct ftrace_hash;
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FTRACE_OPS_FL_ENABLED = 1 << 0,
|
||||||
|
FTRACE_OPS_FL_GLOBAL = 1 << 1,
|
||||||
|
FTRACE_OPS_FL_DYNAMIC = 1 << 2,
|
||||||
|
};
|
||||||
|
|
||||||
struct ftrace_ops {
|
struct ftrace_ops {
|
||||||
ftrace_func_t func;
|
ftrace_func_t func;
|
||||||
struct ftrace_ops *next;
|
struct ftrace_ops *next;
|
||||||
|
unsigned long flags;
|
||||||
|
#ifdef CONFIG_DYNAMIC_FTRACE
|
||||||
|
struct ftrace_hash *notrace_hash;
|
||||||
|
struct ftrace_hash *filter_hash;
|
||||||
|
#endif
|
||||||
};
|
};
|
||||||
|
|
||||||
extern int function_trace_stop;
|
extern int function_trace_stop;
|
||||||
@ -146,12 +159,13 @@ extern void unregister_ftrace_function_probe_all(char *glob);
|
|||||||
extern int ftrace_text_reserved(void *start, void *end);
|
extern int ftrace_text_reserved(void *start, void *end);
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
FTRACE_FL_FREE = (1 << 0),
|
FTRACE_FL_ENABLED = (1 << 30),
|
||||||
FTRACE_FL_FILTER = (1 << 1),
|
FTRACE_FL_FREE = (1 << 31),
|
||||||
FTRACE_FL_ENABLED = (1 << 2),
|
|
||||||
FTRACE_FL_NOTRACE = (1 << 3),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#define FTRACE_FL_MASK (0x3UL << 30)
|
||||||
|
#define FTRACE_REF_MAX ((1 << 30) - 1)
|
||||||
|
|
||||||
struct dyn_ftrace {
|
struct dyn_ftrace {
|
||||||
union {
|
union {
|
||||||
unsigned long ip; /* address of mcount call-site */
|
unsigned long ip; /* address of mcount call-site */
|
||||||
@ -165,7 +179,12 @@ struct dyn_ftrace {
|
|||||||
};
|
};
|
||||||
|
|
||||||
int ftrace_force_update(void);
|
int ftrace_force_update(void);
|
||||||
void ftrace_set_filter(unsigned char *buf, int len, int reset);
|
void ftrace_set_filter(struct ftrace_ops *ops, unsigned char *buf,
|
||||||
|
int len, int reset);
|
||||||
|
void ftrace_set_notrace(struct ftrace_ops *ops, unsigned char *buf,
|
||||||
|
int len, int reset);
|
||||||
|
void ftrace_set_global_filter(unsigned char *buf, int len, int reset);
|
||||||
|
void ftrace_set_global_notrace(unsigned char *buf, int len, int reset);
|
||||||
|
|
||||||
int register_ftrace_command(struct ftrace_func_command *cmd);
|
int register_ftrace_command(struct ftrace_func_command *cmd);
|
||||||
int unregister_ftrace_command(struct ftrace_func_command *cmd);
|
int unregister_ftrace_command(struct ftrace_func_command *cmd);
|
||||||
|
@ -283,6 +283,7 @@ extern char *get_options(const char *str, int nints, int *ints);
|
|||||||
extern unsigned long long memparse(const char *ptr, char **retptr);
|
extern unsigned long long memparse(const char *ptr, char **retptr);
|
||||||
|
|
||||||
extern int core_kernel_text(unsigned long addr);
|
extern int core_kernel_text(unsigned long addr);
|
||||||
|
extern int core_kernel_data(unsigned long addr);
|
||||||
extern int __kernel_text_address(unsigned long addr);
|
extern int __kernel_text_address(unsigned long addr);
|
||||||
extern int kernel_text_address(unsigned long addr);
|
extern int kernel_text_address(unsigned long addr);
|
||||||
extern int func_ptr_is_kernel_text(void *ptr);
|
extern int func_ptr_is_kernel_text(void *ptr);
|
||||||
|
@ -72,6 +72,14 @@ int core_kernel_text(unsigned long addr)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int core_kernel_data(unsigned long addr)
|
||||||
|
{
|
||||||
|
if (addr >= (unsigned long)_sdata &&
|
||||||
|
addr < (unsigned long)_edata)
|
||||||
|
return 1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
int __kernel_text_address(unsigned long addr)
|
int __kernel_text_address(unsigned long addr)
|
||||||
{
|
{
|
||||||
if (core_kernel_text(addr))
|
if (core_kernel_text(addr))
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -419,6 +419,8 @@ extern void trace_find_cmdline(int pid, char comm[]);
|
|||||||
extern unsigned long ftrace_update_tot_cnt;
|
extern unsigned long ftrace_update_tot_cnt;
|
||||||
#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
|
#define DYN_FTRACE_TEST_NAME trace_selftest_dynamic_test_func
|
||||||
extern int DYN_FTRACE_TEST_NAME(void);
|
extern int DYN_FTRACE_TEST_NAME(void);
|
||||||
|
#define DYN_FTRACE_TEST_NAME2 trace_selftest_dynamic_test_func2
|
||||||
|
extern int DYN_FTRACE_TEST_NAME2(void);
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
extern int ring_buffer_expanded;
|
extern int ring_buffer_expanded;
|
||||||
|
@ -149,11 +149,13 @@ function_stack_trace_call(unsigned long ip, unsigned long parent_ip)
|
|||||||
static struct ftrace_ops trace_ops __read_mostly =
|
static struct ftrace_ops trace_ops __read_mostly =
|
||||||
{
|
{
|
||||||
.func = function_trace_call,
|
.func = function_trace_call,
|
||||||
|
.flags = FTRACE_OPS_FL_GLOBAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static struct ftrace_ops trace_stack_ops __read_mostly =
|
static struct ftrace_ops trace_stack_ops __read_mostly =
|
||||||
{
|
{
|
||||||
.func = function_stack_trace_call,
|
.func = function_stack_trace_call,
|
||||||
|
.flags = FTRACE_OPS_FL_GLOBAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Our two options */
|
/* Our two options */
|
||||||
|
@ -153,6 +153,7 @@ irqsoff_tracer_call(unsigned long ip, unsigned long parent_ip)
|
|||||||
static struct ftrace_ops trace_ops __read_mostly =
|
static struct ftrace_ops trace_ops __read_mostly =
|
||||||
{
|
{
|
||||||
.func = irqsoff_tracer_call,
|
.func = irqsoff_tracer_call,
|
||||||
|
.flags = FTRACE_OPS_FL_GLOBAL,
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_FUNCTION_TRACER */
|
#endif /* CONFIG_FUNCTION_TRACER */
|
||||||
|
|
||||||
|
@ -129,6 +129,7 @@ wakeup_tracer_call(unsigned long ip, unsigned long parent_ip)
|
|||||||
static struct ftrace_ops trace_ops __read_mostly =
|
static struct ftrace_ops trace_ops __read_mostly =
|
||||||
{
|
{
|
||||||
.func = wakeup_tracer_call,
|
.func = wakeup_tracer_call,
|
||||||
|
.flags = FTRACE_OPS_FL_GLOBAL,
|
||||||
};
|
};
|
||||||
#endif /* CONFIG_FUNCTION_TRACER */
|
#endif /* CONFIG_FUNCTION_TRACER */
|
||||||
|
|
||||||
|
@ -101,6 +101,206 @@ static inline void warn_failed_init_tracer(struct tracer *trace, int init_ret)
|
|||||||
|
|
||||||
#ifdef CONFIG_DYNAMIC_FTRACE
|
#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 */
|
/* Test dynamic code modification and ftrace filters */
|
||||||
int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
||||||
struct trace_array *tr,
|
struct trace_array *tr,
|
||||||
@ -131,7 +331,7 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
|||||||
func_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
|
func_name = "*" __stringify(DYN_FTRACE_TEST_NAME);
|
||||||
|
|
||||||
/* filter only on our function */
|
/* filter only on our function */
|
||||||
ftrace_set_filter(func_name, strlen(func_name), 1);
|
ftrace_set_global_filter(func_name, strlen(func_name), 1);
|
||||||
|
|
||||||
/* enable tracing */
|
/* enable tracing */
|
||||||
ret = tracer_init(trace, tr);
|
ret = tracer_init(trace, tr);
|
||||||
@ -166,22 +366,30 @@ int trace_selftest_startup_dynamic_tracing(struct tracer *trace,
|
|||||||
|
|
||||||
/* check the trace buffer */
|
/* check the trace buffer */
|
||||||
ret = trace_test_buffer(tr, &count);
|
ret = trace_test_buffer(tr, &count);
|
||||||
trace->reset(tr);
|
|
||||||
tracing_start();
|
tracing_start();
|
||||||
|
|
||||||
/* we should only have one item */
|
/* we should only have one item */
|
||||||
if (!ret && count != 1) {
|
if (!ret && count != 1) {
|
||||||
|
trace->reset(tr);
|
||||||
printk(KERN_CONT ".. filter failed count=%ld ..", count);
|
printk(KERN_CONT ".. filter failed count=%ld ..", count);
|
||||||
ret = -1;
|
ret = -1;
|
||||||
goto out;
|
goto out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Test the ops with global tracing running */
|
||||||
|
ret = trace_selftest_ops(1);
|
||||||
|
trace->reset(tr);
|
||||||
|
|
||||||
out:
|
out:
|
||||||
ftrace_enabled = save_ftrace_enabled;
|
ftrace_enabled = save_ftrace_enabled;
|
||||||
tracer_enabled = save_tracer_enabled;
|
tracer_enabled = save_tracer_enabled;
|
||||||
|
|
||||||
/* Enable tracing on all functions again */
|
/* Enable tracing on all functions again */
|
||||||
ftrace_set_filter(NULL, 0, 1);
|
ftrace_set_global_filter(NULL, 0, 1);
|
||||||
|
|
||||||
|
/* Test the ops with global tracing off */
|
||||||
|
if (!ret)
|
||||||
|
ret = trace_selftest_ops(2);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
@ -5,3 +5,9 @@ int DYN_FTRACE_TEST_NAME(void)
|
|||||||
/* used to call mcount */
|
/* used to call mcount */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int DYN_FTRACE_TEST_NAME2(void)
|
||||||
|
{
|
||||||
|
/* used to call mcount */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
@ -133,6 +133,7 @@ stack_trace_call(unsigned long ip, unsigned long parent_ip)
|
|||||||
static struct ftrace_ops trace_ops __read_mostly =
|
static struct ftrace_ops trace_ops __read_mostly =
|
||||||
{
|
{
|
||||||
.func = stack_trace_call,
|
.func = stack_trace_call,
|
||||||
|
.flags = FTRACE_OPS_FL_GLOBAL,
|
||||||
};
|
};
|
||||||
|
|
||||||
static ssize_t
|
static ssize_t
|
||||||
|
Loading…
Reference in New Issue
Block a user