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: Valentin Schneider <vschneid@redhat.com>
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
This commit is contained in:
Valentin Schneider 2023-07-07 18:21:47 +01:00 committed by Steven Rostedt (Google)
parent 7c1130ea5c
commit cfb58e278c

View File

@ -70,15 +70,15 @@ 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;
int offset;
u64 val;
u64 val2;
enum filter_pred_fn fn_num;
int offset;
int not;
int op;
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 @@ out_free:
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);
}