Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f616680 authored by Daniel Wagner's avatar Daniel Wagner Committed by Steven Rostedt
Browse files

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: default avatarDaniel Wagner <daniel.wagner@bmw-carit.de>
Signed-off-by: default avatarSteven Rostedt <rostedt@goodmis.org>
parent c93bf928
Loading
Loading
Loading
Loading
+25 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
DEFINE_MUTEX(event_mutex);

LIST_HEAD(ftrace_events);
static LIST_HEAD(ftrace_generic_fields);
static LIST_HEAD(ftrace_common_fields);

#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 list_head *head;

	field = __find_event_field(&ftrace_generic_fields, name);
	if (field)
		return field;

	field = __find_event_field(&ftrace_common_fields, name);
	if (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);

#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)					\
	ret = __trace_define_field(&ftrace_common_fields, #type,	\
				   "common_" #item,			\
@@ -153,6 +165,16 @@ EXPORT_SYMBOL_GPL(trace_define_field);
	if (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)
{
	int ret;
@@ -2671,6 +2693,9 @@ static __init int event_trace_init(void)
	if (!entry)
		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())
		pr_warn("tracing: Failed to allocate common fields");

+52 −2
Original line number Diff line number Diff line
@@ -252,6 +252,50 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event)
	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)
{
	return 0;
@@ -1002,7 +1046,10 @@ static int init_pred(struct filter_parse_state *ps,
	if (is_string_field(field)) {
		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;
			pred->regex.field_len = field->size;
		} else if (field->filter_type == FILTER_DYN_STRING)
@@ -1025,6 +1072,9 @@ static int init_pred(struct filter_parse_state *ps,
		}
		pred->val = val;

		if (!strcmp(field->name, "cpu"))
			fn = filter_pred_cpu;
		else
			fn = select_comparison_fn(pred->op, field->size,
					  field->is_signed);
		if (!fn) {