Commit cfb58e27 authored by Valentin Schneider's avatar Valentin Schneider Committed by Steven Rostedt (Google)
Browse files

tracing/filters: Dynamically allocate filter_pred.regex

Every predicate allocation includes a MAX_FILTER_STR_VAL (256) char array
in the regex field, even if the predicate function does not use the field.

A later commit will introduce a dynamically allocated cpumask to struct
filter_pred, which will require a dedicated freeing function. Bite the
bullet and make filter_pred.regex dynamically allocated.

While at it, reorder the fields of filter_pred to fill in the byte
holes. The struct now fits on a single cacheline.

No change in behaviour intended.

The kfree()'s were patched via Coccinelle:
  @@
  struct filter_pred *pred;
  @@

  -kfree(pred);
  +free_predicate(pred);

Link: https://lkml.kernel.org/r/20230707172155.70873-2-vschneid@redhat.com



Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Jonathan Corbet <corbet@lwn.net>
Cc: Juri Lelli <juri.lelli@redhat.com>
Cc: Daniel Bristot de Oliveira <bristot@redhat.com>
Cc: Marcelo Tosatti <mtosatti@redhat.com>
Cc: Leonardo Bras <leobras@redhat.com>
Cc: Frederic Weisbecker <frederic@kernel.org>
Signed-off-by: default avatarValentin Schneider <vschneid@redhat.com>
Signed-off-by: default avatarSteven Rostedt (Google) <rostedt@goodmis.org>
parent 7c1130ea
Loading
Loading
Loading
Loading
+39 −25
Original line number Diff line number Diff line
@@ -70,12 +70,12 @@ enum filter_pred_fn {
};

struct filter_pred {
	enum filter_pred_fn 	fn_num;
	u64 			val;
	u64 			val2;
	struct regex		regex;
	struct regex		*regex;
	unsigned short		*ops;
	struct ftrace_event_field *field;
	u64			val;
	u64			val2;
	enum filter_pred_fn	fn_num;
	int			offset;
	int			not;
	int			op;
@@ -186,6 +186,14 @@ enum {
	PROCESS_OR	= 4,
};

static void free_predicate(struct filter_pred *pred)
{
	if (pred) {
		kfree(pred->regex);
		kfree(pred);
	}
}

/*
 * Without going into a formal proof, this explains the method that is used in
 * parsing the logical expressions.
@@ -623,7 +631,7 @@ predicate_parse(const char *str, int nr_parens, int nr_preds,
	kfree(inverts);
	if (prog_stack) {
		for (i = 0; prog_stack[i].pred; i++)
			kfree(prog_stack[i].pred);
			free_predicate(prog_stack[i].pred);
		kfree(prog_stack);
	}
	return ERR_PTR(ret);
@@ -750,7 +758,7 @@ static int filter_pred_string(struct filter_pred *pred, void *event)
	char *addr = (char *)(event + pred->offset);
	int cmp, match;

	cmp = pred->regex.match(addr, &pred->regex, pred->regex.field_len);
	cmp = pred->regex->match(addr, pred->regex, pred->regex->field_len);

	match = cmp ^ pred->not;

@@ -763,7 +771,7 @@ static __always_inline int filter_pchar(struct filter_pred *pred, char *str)
	int len;

	len = strlen(str) + 1;	/* including tailing '\0' */
	cmp = pred->regex.match(str, &pred->regex, len);
	cmp = pred->regex->match(str, pred->regex, len);

	match = cmp ^ pred->not;

@@ -813,7 +821,7 @@ static int filter_pred_strloc(struct filter_pred *pred, void *event)
	char *addr = (char *)(event + str_loc);
	int cmp, match;

	cmp = pred->regex.match(addr, &pred->regex, str_len);
	cmp = pred->regex->match(addr, pred->regex, str_len);

	match = cmp ^ pred->not;

@@ -836,7 +844,7 @@ static int filter_pred_strrelloc(struct filter_pred *pred, void *event)
	char *addr = (char *)(&item[1]) + str_loc;
	int cmp, match;

	cmp = pred->regex.match(addr, &pred->regex, str_len);
	cmp = pred->regex->match(addr, pred->regex, str_len);

	match = cmp ^ pred->not;

@@ -874,7 +882,7 @@ static int filter_pred_comm(struct filter_pred *pred, void *event)
{
	int cmp;

	cmp = pred->regex.match(current->comm, &pred->regex,
	cmp = pred->regex->match(current->comm, pred->regex,
				TASK_COMM_LEN);
	return cmp ^ pred->not;
}
@@ -1004,7 +1012,7 @@ enum regex_type filter_parse_regex(char *buff, int len, char **search, int *not)

static void filter_build_regex(struct filter_pred *pred)
{
	struct regex *r = &pred->regex;
	struct regex *r = pred->regex;
	char *search;
	enum regex_type type = MATCH_FULL;

@@ -1169,7 +1177,7 @@ static void free_prog(struct event_filter *filter)
		return;

	for (i = 0; prog[i].pred; i++)
		kfree(prog[i].pred);
		free_predicate(prog[i].pred);
	kfree(prog);
}

@@ -1553,9 +1561,12 @@ static int parse_pred(const char *str, void *data,
			goto err_free;
		}

		pred->regex.len = len;
		strncpy(pred->regex.pattern, str + s, len);
		pred->regex.pattern[len] = 0;
		pred->regex = kzalloc(sizeof(*pred->regex), GFP_KERNEL);
		if (!pred->regex)
			goto err_mem;
		pred->regex->len = len;
		strncpy(pred->regex->pattern, str + s, len);
		pred->regex->pattern[len] = 0;

	/* This is either a string, or an integer */
	} else if (str[i] == '\'' || str[i] == '"') {
@@ -1597,9 +1608,12 @@ static int parse_pred(const char *str, void *data,
			goto err_free;
		}

		pred->regex.len = len;
		strncpy(pred->regex.pattern, str + s, len);
		pred->regex.pattern[len] = 0;
		pred->regex = kzalloc(sizeof(*pred->regex), GFP_KERNEL);
		if (!pred->regex)
			goto err_mem;
		pred->regex->len = len;
		strncpy(pred->regex->pattern, str + s, len);
		pred->regex->pattern[len] = 0;

		filter_build_regex(pred);

@@ -1608,7 +1622,7 @@ static int parse_pred(const char *str, void *data,

		} else if (field->filter_type == FILTER_STATIC_STRING) {
			pred->fn_num = FILTER_PRED_FN_STRING;
			pred->regex.field_len = field->size;
			pred->regex->field_len = field->size;

		} else if (field->filter_type == FILTER_DYN_STRING) {
			pred->fn_num = FILTER_PRED_FN_STRLOC;
@@ -1691,10 +1705,10 @@ static int parse_pred(const char *str, void *data,
	return i;

err_free:
	kfree(pred);
	free_predicate(pred);
	return -EINVAL;
err_mem:
	kfree(pred);
	free_predicate(pred);
	return -ENOMEM;
}

@@ -2287,8 +2301,8 @@ static int ftrace_function_set_filter_pred(struct filter_pred *pred,
		return ret;

	return __ftrace_function_set_filter(pred->op == OP_EQ,
					    pred->regex.pattern,
					    pred->regex.len,
					    pred->regex->pattern,
					    pred->regex->len,
					    data);
}