mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-08-27 03:10:12 +00:00
tracing: Allow triggers to filter for CPU ids and process names
By extending the filter rules by more generic fields we can write triggers filters like echo 'stacktrace if cpu == 1' > \ /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger or echo 'stacktrace if comm == sshd' > \ /sys/kernel/debug/tracing/events/raw_syscalls/sys_enter/trigger CPU and COMM are not part of struct trace_entry. We could add the two new fields to ftrace_common_field list and fix up all depending sides. But that looks pretty ugly. Another thing I would like to avoid that the 'format' file contents changes. All this can be avoided by introducing another list which contains non field members of struct trace_entry. Link: http://lkml.kernel.org/r/1439210146-24707-1-git-send-email-daniel.wagner@bmw-carit.de Signed-off-by: Daniel Wagner <daniel.wagner@bmw-carit.de> Signed-off-by: Steven Rostedt <rostedt@goodmis.org>
This commit is contained in:
parent
c93bf928fe
commit
9f61668073
2 changed files with 77 additions and 2 deletions
|
@ -30,6 +30,7 @@
|
||||||
DEFINE_MUTEX(event_mutex);
|
DEFINE_MUTEX(event_mutex);
|
||||||
|
|
||||||
LIST_HEAD(ftrace_events);
|
LIST_HEAD(ftrace_events);
|
||||||
|
static LIST_HEAD(ftrace_generic_fields);
|
||||||
static LIST_HEAD(ftrace_common_fields);
|
static LIST_HEAD(ftrace_common_fields);
|
||||||
|
|
||||||
#define GFP_TRACE (GFP_KERNEL | __GFP_ZERO)
|
#define GFP_TRACE (GFP_KERNEL | __GFP_ZERO)
|
||||||
|
@ -94,6 +95,10 @@ trace_find_event_field(struct trace_event_call *call, char *name)
|
||||||
struct ftrace_event_field *field;
|
struct ftrace_event_field *field;
|
||||||
struct list_head *head;
|
struct list_head *head;
|
||||||
|
|
||||||
|
field = __find_event_field(&ftrace_generic_fields, name);
|
||||||
|
if (field)
|
||||||
|
return field;
|
||||||
|
|
||||||
field = __find_event_field(&ftrace_common_fields, name);
|
field = __find_event_field(&ftrace_common_fields, name);
|
||||||
if (field)
|
if (field)
|
||||||
return field;
|
return field;
|
||||||
|
@ -144,6 +149,13 @@ int trace_define_field(struct trace_event_call *call, const char *type,
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(trace_define_field);
|
EXPORT_SYMBOL_GPL(trace_define_field);
|
||||||
|
|
||||||
|
#define __generic_field(type, item, filter_type) \
|
||||||
|
ret = __trace_define_field(&ftrace_generic_fields, #type, \
|
||||||
|
#item, 0, 0, is_signed_type(type), \
|
||||||
|
filter_type); \
|
||||||
|
if (ret) \
|
||||||
|
return ret;
|
||||||
|
|
||||||
#define __common_field(type, item) \
|
#define __common_field(type, item) \
|
||||||
ret = __trace_define_field(&ftrace_common_fields, #type, \
|
ret = __trace_define_field(&ftrace_common_fields, #type, \
|
||||||
"common_" #item, \
|
"common_" #item, \
|
||||||
|
@ -153,6 +165,16 @@ EXPORT_SYMBOL_GPL(trace_define_field);
|
||||||
if (ret) \
|
if (ret) \
|
||||||
return ret;
|
return ret;
|
||||||
|
|
||||||
|
static int trace_define_generic_fields(void)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
__generic_field(int, cpu, FILTER_OTHER);
|
||||||
|
__generic_field(char *, comm, FILTER_PTR_STRING);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int trace_define_common_fields(void)
|
static int trace_define_common_fields(void)
|
||||||
{
|
{
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -2671,6 +2693,9 @@ static __init int event_trace_init(void)
|
||||||
if (!entry)
|
if (!entry)
|
||||||
pr_warn("Could not create tracefs 'available_events' entry\n");
|
pr_warn("Could not create tracefs 'available_events' entry\n");
|
||||||
|
|
||||||
|
if (trace_define_generic_fields())
|
||||||
|
pr_warn("tracing: Failed to allocated generic fields");
|
||||||
|
|
||||||
if (trace_define_common_fields())
|
if (trace_define_common_fields())
|
||||||
pr_warn("tracing: Failed to allocate common fields");
|
pr_warn("tracing: Failed to allocate common fields");
|
||||||
|
|
||||||
|
|
|
@ -252,6 +252,50 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event)
|
||||||
return match;
|
return match;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Filter predicate for CPUs. */
|
||||||
|
static int filter_pred_cpu(struct filter_pred *pred, void *event)
|
||||||
|
{
|
||||||
|
int cpu, cmp;
|
||||||
|
int match = 0;
|
||||||
|
|
||||||
|
cpu = raw_smp_processor_id();
|
||||||
|
cmp = pred->val;
|
||||||
|
|
||||||
|
switch (pred->op) {
|
||||||
|
case OP_EQ:
|
||||||
|
match = cpu == cmp;
|
||||||
|
break;
|
||||||
|
case OP_LT:
|
||||||
|
match = cpu < cmp;
|
||||||
|
break;
|
||||||
|
case OP_LE:
|
||||||
|
match = cpu <= cmp;
|
||||||
|
break;
|
||||||
|
case OP_GT:
|
||||||
|
match = cpu > cmp;
|
||||||
|
break;
|
||||||
|
case OP_GE:
|
||||||
|
match = cpu >= cmp;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return !!match == !pred->not;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Filter predicate for COMM. */
|
||||||
|
static int filter_pred_comm(struct filter_pred *pred, void *event)
|
||||||
|
{
|
||||||
|
int cmp, match;
|
||||||
|
|
||||||
|
cmp = pred->regex.match(current->comm, &pred->regex,
|
||||||
|
pred->regex.field_len);
|
||||||
|
match = cmp ^ pred->not;
|
||||||
|
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
|
||||||
static int filter_pred_none(struct filter_pred *pred, void *event)
|
static int filter_pred_none(struct filter_pred *pred, void *event)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1002,7 +1046,10 @@ static int init_pred(struct filter_parse_state *ps,
|
||||||
if (is_string_field(field)) {
|
if (is_string_field(field)) {
|
||||||
filter_build_regex(pred);
|
filter_build_regex(pred);
|
||||||
|
|
||||||
if (field->filter_type == FILTER_STATIC_STRING) {
|
if (!strcmp(field->name, "comm")) {
|
||||||
|
fn = filter_pred_comm;
|
||||||
|
pred->regex.field_len = TASK_COMM_LEN;
|
||||||
|
} else if (field->filter_type == FILTER_STATIC_STRING) {
|
||||||
fn = filter_pred_string;
|
fn = filter_pred_string;
|
||||||
pred->regex.field_len = field->size;
|
pred->regex.field_len = field->size;
|
||||||
} else if (field->filter_type == FILTER_DYN_STRING)
|
} else if (field->filter_type == FILTER_DYN_STRING)
|
||||||
|
@ -1025,6 +1072,9 @@ static int init_pred(struct filter_parse_state *ps,
|
||||||
}
|
}
|
||||||
pred->val = val;
|
pred->val = val;
|
||||||
|
|
||||||
|
if (!strcmp(field->name, "cpu"))
|
||||||
|
fn = filter_pred_cpu;
|
||||||
|
else
|
||||||
fn = select_comparison_fn(pred->op, field->size,
|
fn = select_comparison_fn(pred->op, field->size,
|
||||||
field->is_signed);
|
field->is_signed);
|
||||||
if (!fn) {
|
if (!fn) {
|
||||||
|
|
Loading…
Reference in a new issue