Merge branch 'tip/perf/core' of git://git.kernel.org/pub/scm/linux/kernel/git/rostedt/linux-trace into perf/core
This commit is contained in:
@@ -2437,6 +2437,14 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
|
|||||||
stacktrace [FTRACE]
|
stacktrace [FTRACE]
|
||||||
Enabled the stack tracer on boot up.
|
Enabled the stack tracer on boot up.
|
||||||
|
|
||||||
|
stacktrace_filter=[function-list]
|
||||||
|
[FTRACE] Limit the functions that the stack tracer
|
||||||
|
will trace at boot up. function-list is a comma separated
|
||||||
|
list of functions. This list can be changed at run
|
||||||
|
time by the stack_trace_filter file in the debugfs
|
||||||
|
tracing directory. Note, this enables stack tracing
|
||||||
|
and the stacktrace above is not needed.
|
||||||
|
|
||||||
sti= [PARISC,HW]
|
sti= [PARISC,HW]
|
||||||
Format: <num>
|
Format: <num>
|
||||||
Set the STI (builtin display/keyboard on the HP-PARISC
|
Set the STI (builtin display/keyboard on the HP-PARISC
|
||||||
|
@@ -50,6 +50,11 @@
|
|||||||
# define inline inline __attribute__((always_inline))
|
# define inline inline __attribute__((always_inline))
|
||||||
# define __inline__ __inline__ __attribute__((always_inline))
|
# define __inline__ __inline__ __attribute__((always_inline))
|
||||||
# define __inline __inline __attribute__((always_inline))
|
# define __inline __inline __attribute__((always_inline))
|
||||||
|
#else
|
||||||
|
/* A lot of inline functions can cause havoc with function tracing */
|
||||||
|
# define inline inline notrace
|
||||||
|
# define __inline__ __inline__ notrace
|
||||||
|
# define __inline __inline notrace
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define __deprecated __attribute__((deprecated))
|
#define __deprecated __attribute__((deprecated))
|
||||||
|
@@ -133,6 +133,8 @@ struct ftrace_func_command {
|
|||||||
int ftrace_arch_code_modify_prepare(void);
|
int ftrace_arch_code_modify_prepare(void);
|
||||||
int ftrace_arch_code_modify_post_process(void);
|
int ftrace_arch_code_modify_post_process(void);
|
||||||
|
|
||||||
|
void ftrace_bug(int err, unsigned long ip);
|
||||||
|
|
||||||
struct seq_file;
|
struct seq_file;
|
||||||
|
|
||||||
struct ftrace_probe_ops {
|
struct ftrace_probe_ops {
|
||||||
@@ -161,7 +163,6 @@ extern int ftrace_text_reserved(void *start, void *end);
|
|||||||
|
|
||||||
enum {
|
enum {
|
||||||
FTRACE_FL_ENABLED = (1 << 30),
|
FTRACE_FL_ENABLED = (1 << 30),
|
||||||
FTRACE_FL_FREE = (1 << 31),
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#define FTRACE_FL_MASK (0x3UL << 30)
|
#define FTRACE_FL_MASK (0x3UL << 30)
|
||||||
@@ -172,10 +173,7 @@ struct dyn_ftrace {
|
|||||||
unsigned long ip; /* address of mcount call-site */
|
unsigned long ip; /* address of mcount call-site */
|
||||||
struct dyn_ftrace *freelist;
|
struct dyn_ftrace *freelist;
|
||||||
};
|
};
|
||||||
union {
|
unsigned long flags;
|
||||||
unsigned long flags;
|
|
||||||
struct dyn_ftrace *newlist;
|
|
||||||
};
|
|
||||||
struct dyn_arch_ftrace arch;
|
struct dyn_arch_ftrace arch;
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -190,6 +188,56 @@ 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);
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FTRACE_UPDATE_CALLS = (1 << 0),
|
||||||
|
FTRACE_DISABLE_CALLS = (1 << 1),
|
||||||
|
FTRACE_UPDATE_TRACE_FUNC = (1 << 2),
|
||||||
|
FTRACE_START_FUNC_RET = (1 << 3),
|
||||||
|
FTRACE_STOP_FUNC_RET = (1 << 4),
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FTRACE_UPDATE_IGNORE,
|
||||||
|
FTRACE_UPDATE_MAKE_CALL,
|
||||||
|
FTRACE_UPDATE_MAKE_NOP,
|
||||||
|
};
|
||||||
|
|
||||||
|
enum {
|
||||||
|
FTRACE_ITER_FILTER = (1 << 0),
|
||||||
|
FTRACE_ITER_NOTRACE = (1 << 1),
|
||||||
|
FTRACE_ITER_PRINTALL = (1 << 2),
|
||||||
|
FTRACE_ITER_DO_HASH = (1 << 3),
|
||||||
|
FTRACE_ITER_HASH = (1 << 4),
|
||||||
|
FTRACE_ITER_ENABLED = (1 << 5),
|
||||||
|
};
|
||||||
|
|
||||||
|
void arch_ftrace_update_code(int command);
|
||||||
|
|
||||||
|
struct ftrace_rec_iter;
|
||||||
|
|
||||||
|
struct ftrace_rec_iter *ftrace_rec_iter_start(void);
|
||||||
|
struct ftrace_rec_iter *ftrace_rec_iter_next(struct ftrace_rec_iter *iter);
|
||||||
|
struct dyn_ftrace *ftrace_rec_iter_record(struct ftrace_rec_iter *iter);
|
||||||
|
|
||||||
|
int ftrace_update_record(struct dyn_ftrace *rec, int enable);
|
||||||
|
int ftrace_test_record(struct dyn_ftrace *rec, int enable);
|
||||||
|
void ftrace_run_stop_machine(int command);
|
||||||
|
int ftrace_location(unsigned long ip);
|
||||||
|
|
||||||
|
extern ftrace_func_t ftrace_trace_function;
|
||||||
|
|
||||||
|
int ftrace_regex_open(struct ftrace_ops *ops, int flag,
|
||||||
|
struct inode *inode, struct file *file);
|
||||||
|
ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
|
||||||
|
size_t cnt, loff_t *ppos);
|
||||||
|
ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf,
|
||||||
|
size_t cnt, loff_t *ppos);
|
||||||
|
loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin);
|
||||||
|
int ftrace_regex_release(struct inode *inode, struct file *file);
|
||||||
|
|
||||||
|
void __init
|
||||||
|
ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable);
|
||||||
|
|
||||||
/* defined in arch */
|
/* defined in arch */
|
||||||
extern int ftrace_ip_converted(unsigned long ip);
|
extern int ftrace_ip_converted(unsigned long ip);
|
||||||
extern int ftrace_dyn_arch_init(void *data);
|
extern int ftrace_dyn_arch_init(void *data);
|
||||||
@@ -284,6 +332,25 @@ static inline int ftrace_text_reserved(void *start, void *end)
|
|||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Again users of functions that have ftrace_ops may not
|
||||||
|
* have them defined when ftrace is not enabled, but these
|
||||||
|
* functions may still be called. Use a macro instead of inline.
|
||||||
|
*/
|
||||||
|
#define ftrace_regex_open(ops, flag, inod, file) ({ -ENODEV; })
|
||||||
|
#define ftrace_set_early_filter(ops, buf, enable) do { } while (0)
|
||||||
|
|
||||||
|
static inline ssize_t ftrace_filter_write(struct file *file, const char __user *ubuf,
|
||||||
|
size_t cnt, loff_t *ppos) { return -ENODEV; }
|
||||||
|
static inline ssize_t ftrace_notrace_write(struct file *file, const char __user *ubuf,
|
||||||
|
size_t cnt, loff_t *ppos) { return -ENODEV; }
|
||||||
|
static inline loff_t ftrace_regex_lseek(struct file *file, loff_t offset, int origin)
|
||||||
|
{
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
static inline int
|
||||||
|
ftrace_regex_release(struct inode *inode, struct file *file) { return -ENODEV; }
|
||||||
#endif /* CONFIG_DYNAMIC_FTRACE */
|
#endif /* CONFIG_DYNAMIC_FTRACE */
|
||||||
|
|
||||||
/* totally disable ftrace - can not re-enable after this */
|
/* totally disable ftrace - can not re-enable after this */
|
||||||
|
File diff suppressed because it is too large
Load Diff
@@ -1738,11 +1738,121 @@ static int replace_system_preds(struct event_subsystem *system,
|
|||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int create_filter_start(char *filter_str, bool set_str,
|
||||||
|
struct filter_parse_state **psp,
|
||||||
|
struct event_filter **filterp)
|
||||||
|
{
|
||||||
|
struct event_filter *filter;
|
||||||
|
struct filter_parse_state *ps = NULL;
|
||||||
|
int err = 0;
|
||||||
|
|
||||||
|
WARN_ON_ONCE(*psp || *filterp);
|
||||||
|
|
||||||
|
/* allocate everything, and if any fails, free all and fail */
|
||||||
|
filter = __alloc_filter();
|
||||||
|
if (filter && set_str)
|
||||||
|
err = replace_filter_string(filter, filter_str);
|
||||||
|
|
||||||
|
ps = kzalloc(sizeof(*ps), GFP_KERNEL);
|
||||||
|
|
||||||
|
if (!filter || !ps || err) {
|
||||||
|
kfree(ps);
|
||||||
|
__free_filter(filter);
|
||||||
|
return -ENOMEM;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* we're committed to creating a new filter */
|
||||||
|
*filterp = filter;
|
||||||
|
*psp = ps;
|
||||||
|
|
||||||
|
parse_init(ps, filter_ops, filter_str);
|
||||||
|
err = filter_parse(ps);
|
||||||
|
if (err && set_str)
|
||||||
|
append_filter_err(ps, filter);
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void create_filter_finish(struct filter_parse_state *ps)
|
||||||
|
{
|
||||||
|
if (ps) {
|
||||||
|
filter_opstack_clear(ps);
|
||||||
|
postfix_clear(ps);
|
||||||
|
kfree(ps);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create_filter - create a filter for a ftrace_event_call
|
||||||
|
* @call: ftrace_event_call to create a filter for
|
||||||
|
* @filter_str: filter string
|
||||||
|
* @set_str: remember @filter_str and enable detailed error in filter
|
||||||
|
* @filterp: out param for created filter (always updated on return)
|
||||||
|
*
|
||||||
|
* Creates a filter for @call with @filter_str. If @set_str is %true,
|
||||||
|
* @filter_str is copied and recorded in the new filter.
|
||||||
|
*
|
||||||
|
* On success, returns 0 and *@filterp points to the new filter. On
|
||||||
|
* failure, returns -errno and *@filterp may point to %NULL or to a new
|
||||||
|
* filter. In the latter case, the returned filter contains error
|
||||||
|
* information if @set_str is %true and the caller is responsible for
|
||||||
|
* freeing it.
|
||||||
|
*/
|
||||||
|
static int create_filter(struct ftrace_event_call *call,
|
||||||
|
char *filter_str, bool set_str,
|
||||||
|
struct event_filter **filterp)
|
||||||
|
{
|
||||||
|
struct event_filter *filter = NULL;
|
||||||
|
struct filter_parse_state *ps = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = create_filter_start(filter_str, set_str, &ps, &filter);
|
||||||
|
if (!err) {
|
||||||
|
err = replace_preds(call, filter, ps, filter_str, false);
|
||||||
|
if (err && set_str)
|
||||||
|
append_filter_err(ps, filter);
|
||||||
|
}
|
||||||
|
create_filter_finish(ps);
|
||||||
|
|
||||||
|
*filterp = filter;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* create_system_filter - create a filter for an event_subsystem
|
||||||
|
* @system: event_subsystem to create a filter for
|
||||||
|
* @filter_str: filter string
|
||||||
|
* @filterp: out param for created filter (always updated on return)
|
||||||
|
*
|
||||||
|
* Identical to create_filter() except that it creates a subsystem filter
|
||||||
|
* and always remembers @filter_str.
|
||||||
|
*/
|
||||||
|
static int create_system_filter(struct event_subsystem *system,
|
||||||
|
char *filter_str, struct event_filter **filterp)
|
||||||
|
{
|
||||||
|
struct event_filter *filter = NULL;
|
||||||
|
struct filter_parse_state *ps = NULL;
|
||||||
|
int err;
|
||||||
|
|
||||||
|
err = create_filter_start(filter_str, true, &ps, &filter);
|
||||||
|
if (!err) {
|
||||||
|
err = replace_system_preds(system, ps, filter_str);
|
||||||
|
if (!err) {
|
||||||
|
/* System filters just show a default message */
|
||||||
|
kfree(filter->filter_string);
|
||||||
|
filter->filter_string = NULL;
|
||||||
|
} else {
|
||||||
|
append_filter_err(ps, filter);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
create_filter_finish(ps);
|
||||||
|
|
||||||
|
*filterp = filter;
|
||||||
|
return err;
|
||||||
|
}
|
||||||
|
|
||||||
int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
|
int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
|
||||||
{
|
{
|
||||||
struct filter_parse_state *ps;
|
|
||||||
struct event_filter *filter;
|
struct event_filter *filter;
|
||||||
struct event_filter *tmp;
|
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
mutex_lock(&event_mutex);
|
mutex_lock(&event_mutex);
|
||||||
@@ -1759,49 +1869,30 @@ int apply_event_filter(struct ftrace_event_call *call, char *filter_string)
|
|||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = create_filter(call, filter_string, true, &filter);
|
||||||
ps = kzalloc(sizeof(*ps), GFP_KERNEL);
|
|
||||||
if (!ps)
|
|
||||||
goto out_unlock;
|
|
||||||
|
|
||||||
filter = __alloc_filter();
|
|
||||||
if (!filter) {
|
|
||||||
kfree(ps);
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
replace_filter_string(filter, filter_string);
|
|
||||||
|
|
||||||
parse_init(ps, filter_ops, filter_string);
|
|
||||||
err = filter_parse(ps);
|
|
||||||
if (err) {
|
|
||||||
append_filter_err(ps, filter);
|
|
||||||
goto out;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = replace_preds(call, filter, ps, filter_string, false);
|
|
||||||
if (err) {
|
|
||||||
filter_disable(call);
|
|
||||||
append_filter_err(ps, filter);
|
|
||||||
} else
|
|
||||||
call->flags |= TRACE_EVENT_FL_FILTERED;
|
|
||||||
out:
|
|
||||||
/*
|
/*
|
||||||
* Always swap the call filter with the new filter
|
* Always swap the call filter with the new filter
|
||||||
* even if there was an error. If there was an error
|
* even if there was an error. If there was an error
|
||||||
* in the filter, we disable the filter and show the error
|
* in the filter, we disable the filter and show the error
|
||||||
* string
|
* string
|
||||||
*/
|
*/
|
||||||
tmp = call->filter;
|
if (filter) {
|
||||||
rcu_assign_pointer(call->filter, filter);
|
struct event_filter *tmp = call->filter;
|
||||||
if (tmp) {
|
|
||||||
/* Make sure the call is done with the filter */
|
if (!err)
|
||||||
synchronize_sched();
|
call->flags |= TRACE_EVENT_FL_FILTERED;
|
||||||
__free_filter(tmp);
|
else
|
||||||
|
filter_disable(call);
|
||||||
|
|
||||||
|
rcu_assign_pointer(call->filter, filter);
|
||||||
|
|
||||||
|
if (tmp) {
|
||||||
|
/* Make sure the call is done with the filter */
|
||||||
|
synchronize_sched();
|
||||||
|
__free_filter(tmp);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
filter_opstack_clear(ps);
|
|
||||||
postfix_clear(ps);
|
|
||||||
kfree(ps);
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&event_mutex);
|
mutex_unlock(&event_mutex);
|
||||||
|
|
||||||
@@ -1811,7 +1902,6 @@ out_unlock:
|
|||||||
int apply_subsystem_event_filter(struct event_subsystem *system,
|
int apply_subsystem_event_filter(struct event_subsystem *system,
|
||||||
char *filter_string)
|
char *filter_string)
|
||||||
{
|
{
|
||||||
struct filter_parse_state *ps;
|
|
||||||
struct event_filter *filter;
|
struct event_filter *filter;
|
||||||
int err = 0;
|
int err = 0;
|
||||||
|
|
||||||
@@ -1835,48 +1925,19 @@ int apply_subsystem_event_filter(struct event_subsystem *system,
|
|||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
}
|
}
|
||||||
|
|
||||||
err = -ENOMEM;
|
err = create_system_filter(system, filter_string, &filter);
|
||||||
ps = kzalloc(sizeof(*ps), GFP_KERNEL);
|
if (filter) {
|
||||||
if (!ps)
|
/*
|
||||||
goto out_unlock;
|
* No event actually uses the system filter
|
||||||
|
* we can free it without synchronize_sched().
|
||||||
filter = __alloc_filter();
|
*/
|
||||||
if (!filter)
|
__free_filter(system->filter);
|
||||||
goto out;
|
system->filter = filter;
|
||||||
|
}
|
||||||
/* System filters just show a default message */
|
|
||||||
kfree(filter->filter_string);
|
|
||||||
filter->filter_string = NULL;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* No event actually uses the system filter
|
|
||||||
* we can free it without synchronize_sched().
|
|
||||||
*/
|
|
||||||
__free_filter(system->filter);
|
|
||||||
system->filter = filter;
|
|
||||||
|
|
||||||
parse_init(ps, filter_ops, filter_string);
|
|
||||||
err = filter_parse(ps);
|
|
||||||
if (err)
|
|
||||||
goto err_filter;
|
|
||||||
|
|
||||||
err = replace_system_preds(system, ps, filter_string);
|
|
||||||
if (err)
|
|
||||||
goto err_filter;
|
|
||||||
|
|
||||||
out:
|
|
||||||
filter_opstack_clear(ps);
|
|
||||||
postfix_clear(ps);
|
|
||||||
kfree(ps);
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
mutex_unlock(&event_mutex);
|
mutex_unlock(&event_mutex);
|
||||||
|
|
||||||
return err;
|
return err;
|
||||||
|
|
||||||
err_filter:
|
|
||||||
replace_filter_string(filter, filter_string);
|
|
||||||
append_filter_err(ps, system->filter);
|
|
||||||
goto out;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef CONFIG_PERF_EVENTS
|
#ifdef CONFIG_PERF_EVENTS
|
||||||
@@ -1894,7 +1955,6 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
|
|||||||
{
|
{
|
||||||
int err;
|
int err;
|
||||||
struct event_filter *filter;
|
struct event_filter *filter;
|
||||||
struct filter_parse_state *ps;
|
|
||||||
struct ftrace_event_call *call;
|
struct ftrace_event_call *call;
|
||||||
|
|
||||||
mutex_lock(&event_mutex);
|
mutex_lock(&event_mutex);
|
||||||
@@ -1909,33 +1969,10 @@ int ftrace_profile_set_filter(struct perf_event *event, int event_id,
|
|||||||
if (event->filter)
|
if (event->filter)
|
||||||
goto out_unlock;
|
goto out_unlock;
|
||||||
|
|
||||||
filter = __alloc_filter();
|
err = create_filter(call, filter_str, false, &filter);
|
||||||
if (!filter) {
|
|
||||||
err = PTR_ERR(filter);
|
|
||||||
goto out_unlock;
|
|
||||||
}
|
|
||||||
|
|
||||||
err = -ENOMEM;
|
|
||||||
ps = kzalloc(sizeof(*ps), GFP_KERNEL);
|
|
||||||
if (!ps)
|
|
||||||
goto free_filter;
|
|
||||||
|
|
||||||
parse_init(ps, filter_ops, filter_str);
|
|
||||||
err = filter_parse(ps);
|
|
||||||
if (err)
|
|
||||||
goto free_ps;
|
|
||||||
|
|
||||||
err = replace_preds(call, filter, ps, filter_str, false);
|
|
||||||
if (!err)
|
if (!err)
|
||||||
event->filter = filter;
|
event->filter = filter;
|
||||||
|
else
|
||||||
free_ps:
|
|
||||||
filter_opstack_clear(ps);
|
|
||||||
postfix_clear(ps);
|
|
||||||
kfree(ps);
|
|
||||||
|
|
||||||
free_filter:
|
|
||||||
if (err)
|
|
||||||
__free_filter(filter);
|
__free_filter(filter);
|
||||||
|
|
||||||
out_unlock:
|
out_unlock:
|
||||||
@@ -1954,43 +1991,6 @@ out_unlock:
|
|||||||
#define CREATE_TRACE_POINTS
|
#define CREATE_TRACE_POINTS
|
||||||
#include "trace_events_filter_test.h"
|
#include "trace_events_filter_test.h"
|
||||||
|
|
||||||
static int test_get_filter(char *filter_str, struct ftrace_event_call *call,
|
|
||||||
struct event_filter **pfilter)
|
|
||||||
{
|
|
||||||
struct event_filter *filter;
|
|
||||||
struct filter_parse_state *ps;
|
|
||||||
int err = -ENOMEM;
|
|
||||||
|
|
||||||
filter = __alloc_filter();
|
|
||||||
if (!filter)
|
|
||||||
goto out;
|
|
||||||
|
|
||||||
ps = kzalloc(sizeof(*ps), GFP_KERNEL);
|
|
||||||
if (!ps)
|
|
||||||
goto free_filter;
|
|
||||||
|
|
||||||
parse_init(ps, filter_ops, filter_str);
|
|
||||||
err = filter_parse(ps);
|
|
||||||
if (err)
|
|
||||||
goto free_ps;
|
|
||||||
|
|
||||||
err = replace_preds(call, filter, ps, filter_str, false);
|
|
||||||
if (!err)
|
|
||||||
*pfilter = filter;
|
|
||||||
|
|
||||||
free_ps:
|
|
||||||
filter_opstack_clear(ps);
|
|
||||||
postfix_clear(ps);
|
|
||||||
kfree(ps);
|
|
||||||
|
|
||||||
free_filter:
|
|
||||||
if (err)
|
|
||||||
__free_filter(filter);
|
|
||||||
|
|
||||||
out:
|
|
||||||
return err;
|
|
||||||
}
|
|
||||||
|
|
||||||
#define DATA_REC(m, va, vb, vc, vd, ve, vf, vg, vh, nvisit) \
|
#define DATA_REC(m, va, vb, vc, vd, ve, vf, vg, vh, nvisit) \
|
||||||
{ \
|
{ \
|
||||||
.filter = FILTER, \
|
.filter = FILTER, \
|
||||||
@@ -2109,12 +2109,13 @@ static __init int ftrace_test_event_filter(void)
|
|||||||
struct test_filter_data_t *d = &test_filter_data[i];
|
struct test_filter_data_t *d = &test_filter_data[i];
|
||||||
int err;
|
int err;
|
||||||
|
|
||||||
err = test_get_filter(d->filter, &event_ftrace_test_filter,
|
err = create_filter(&event_ftrace_test_filter, d->filter,
|
||||||
&filter);
|
false, &filter);
|
||||||
if (err) {
|
if (err) {
|
||||||
printk(KERN_INFO
|
printk(KERN_INFO
|
||||||
"Failed to get filter for '%s', err %d\n",
|
"Failed to get filter for '%s', err %d\n",
|
||||||
d->filter, err);
|
d->filter, err);
|
||||||
|
__free_filter(filter);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -13,6 +13,9 @@
|
|||||||
#include <linux/sysctl.h>
|
#include <linux/sysctl.h>
|
||||||
#include <linux/init.h>
|
#include <linux/init.h>
|
||||||
#include <linux/fs.h>
|
#include <linux/fs.h>
|
||||||
|
|
||||||
|
#include <asm/setup.h>
|
||||||
|
|
||||||
#include "trace.h"
|
#include "trace.h"
|
||||||
|
|
||||||
#define STACK_TRACE_ENTRIES 500
|
#define STACK_TRACE_ENTRIES 500
|
||||||
@@ -133,7 +136,6 @@ 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
|
||||||
@@ -311,6 +313,21 @@ static const struct file_operations stack_trace_fops = {
|
|||||||
.release = seq_release,
|
.release = seq_release,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
stack_trace_filter_open(struct inode *inode, struct file *file)
|
||||||
|
{
|
||||||
|
return ftrace_regex_open(&trace_ops, FTRACE_ITER_FILTER,
|
||||||
|
inode, file);
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct file_operations stack_trace_filter_fops = {
|
||||||
|
.open = stack_trace_filter_open,
|
||||||
|
.read = seq_read,
|
||||||
|
.write = ftrace_filter_write,
|
||||||
|
.llseek = ftrace_regex_lseek,
|
||||||
|
.release = ftrace_regex_release,
|
||||||
|
};
|
||||||
|
|
||||||
int
|
int
|
||||||
stack_trace_sysctl(struct ctl_table *table, int write,
|
stack_trace_sysctl(struct ctl_table *table, int write,
|
||||||
void __user *buffer, size_t *lenp,
|
void __user *buffer, size_t *lenp,
|
||||||
@@ -338,8 +355,13 @@ stack_trace_sysctl(struct ctl_table *table, int write,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static char stack_trace_filter_buf[COMMAND_LINE_SIZE+1] __initdata;
|
||||||
|
|
||||||
static __init int enable_stacktrace(char *str)
|
static __init int enable_stacktrace(char *str)
|
||||||
{
|
{
|
||||||
|
if (strncmp(str, "_filter=", 8) == 0)
|
||||||
|
strncpy(stack_trace_filter_buf, str+8, COMMAND_LINE_SIZE);
|
||||||
|
|
||||||
stack_tracer_enabled = 1;
|
stack_tracer_enabled = 1;
|
||||||
last_stack_tracer_enabled = 1;
|
last_stack_tracer_enabled = 1;
|
||||||
return 1;
|
return 1;
|
||||||
@@ -358,6 +380,12 @@ static __init int stack_trace_init(void)
|
|||||||
trace_create_file("stack_trace", 0444, d_tracer,
|
trace_create_file("stack_trace", 0444, d_tracer,
|
||||||
NULL, &stack_trace_fops);
|
NULL, &stack_trace_fops);
|
||||||
|
|
||||||
|
trace_create_file("stack_trace_filter", 0444, d_tracer,
|
||||||
|
NULL, &stack_trace_filter_fops);
|
||||||
|
|
||||||
|
if (stack_trace_filter_buf[0])
|
||||||
|
ftrace_set_early_filter(&trace_ops, stack_trace_filter_buf, 1);
|
||||||
|
|
||||||
if (stack_tracer_enabled)
|
if (stack_tracer_enabled)
|
||||||
register_ftrace_function(&trace_ops);
|
register_ftrace_function(&trace_ops);
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user