Skip to content

Commit

Permalink
ftrace: Implement :mod: cache filtering on kernel command line
Browse files Browse the repository at this point in the history
Module functions can be set to set_ftrace_filter before the module is
loaded.

  # echo :mod:snd_hda_intel > set_ftrace_filter

This will enable all the functions for the module snd_hda_intel. If that
module is not loaded, it is "cached" in the trace array for when the
module is loaded, its functions will be traced.

But this is not implemented in the kernel command line. That's because the
kernel command line filtering is added very early in boot up as it is
needed to be done before boot time function tracing can start, which is
also available very early in boot up. The code used by the
"set_ftrace_filter" file can not be used that early as it depends on some
other initialization to occur first. But some of the functions can.

Implement the ":mod:" feature of "set_ftrace_filter" in the kernel command
line parsing. Now function tracing on just a single module that is loaded
at boot up can be done.

Adding:

 ftrace=function ftrace_filter=:mod:sna_hda_intel

To the kernel command line will only enable the sna_hda_intel module
functions when the module is loaded, and it will start tracing.

Cc: Masami Hiramatsu <mhiramat@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Mathieu Desnoyers <mathieu.desnoyers@efficios.com>
Link: https://lore.kernel.org/20250116175832.34e39779@gandalf.local.home
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
  • Loading branch information
Steven Rostedt committed Jan 17, 2025
1 parent 8275637 commit 31f505d
Show file tree
Hide file tree
Showing 3 changed files with 68 additions and 9 deletions.
67 changes: 58 additions & 9 deletions kernel/trace/ftrace.c
Original file line number Diff line number Diff line change
Expand Up @@ -4968,10 +4968,6 @@ static int cache_mod(struct trace_array *tr,
return ftrace_add_mod(tr, func, module, enable);
}

static int
ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
int reset, int enable);

#ifdef CONFIG_MODULES
static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
char *mod, bool enable)
Expand Down Expand Up @@ -5761,7 +5757,7 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long *ips,
static int
ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
unsigned long *ips, unsigned int cnt,
int remove, int reset, int enable)
int remove, int reset, int enable, char *mod)
{
struct ftrace_hash **orig_hash;
struct ftrace_hash *hash;
Expand All @@ -5787,7 +5783,15 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
goto out_regex_unlock;
}

if (buf && !ftrace_match_records(hash, buf, len)) {
if (buf && !match_records(hash, buf, len, mod)) {
/* If this was for a module and nothing was enabled, flag it */
if (mod)
(*orig_hash)->flags |= FTRACE_HASH_FL_MOD;

/*
* Even if it is a mod, return error to let caller know
* nothing was added
*/
ret = -EINVAL;
goto out_regex_unlock;
}
Expand All @@ -5812,7 +5816,7 @@ static int
ftrace_set_addr(struct ftrace_ops *ops, unsigned long *ips, unsigned int cnt,
int remove, int reset, int enable)
{
return ftrace_set_hash(ops, NULL, 0, ips, cnt, remove, reset, enable);
return ftrace_set_hash(ops, NULL, 0, ips, cnt, remove, reset, enable, NULL);
}

#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
Expand Down Expand Up @@ -6190,7 +6194,38 @@ static int
ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
int reset, int enable)
{
return ftrace_set_hash(ops, buf, len, NULL, 0, 0, reset, enable);
char *mod = NULL, *func, *command, *next = buf;
char *tmp __free(kfree) = NULL;
struct trace_array *tr = ops->private;
int ret;

func = strsep(&next, ":");

/* This can also handle :mod: parsing */
if (next) {
if (!tr)
return -EINVAL;

command = strsep(&next, ":");
if (strcmp(command, "mod") != 0)
return -EINVAL;

mod = next;
len = command - func;
/* Save the original func as ftrace_set_hash() can modify it */
tmp = kstrdup(func, GFP_KERNEL);
}

ret = ftrace_set_hash(ops, func, len, NULL, 0, 0, reset, enable, mod);

if (tr && mod && ret < 0) {
/* Did tmp fail to allocate? */
if (!tmp)
return -ENOMEM;
ret = cache_mod(tr, tmp, mod, enable);
}

return ret;
}

/**
Expand Down Expand Up @@ -6354,6 +6389,14 @@ ftrace_set_early_filter(struct ftrace_ops *ops, char *buf, int enable)

ftrace_ops_init(ops);

/* The trace_array is needed for caching module function filters */
if (!ops->private) {
struct trace_array *tr = trace_get_global_array();

ops->private = tr;
ftrace_init_trace_array(tr);
}

while (buf) {
func = strsep(&buf, ",");
ftrace_set_regex(ops, func, strlen(func), 0, enable);
Expand Down Expand Up @@ -7787,9 +7830,14 @@ static void ftrace_update_trampoline(struct ftrace_ops *ops)

void ftrace_init_trace_array(struct trace_array *tr)
{
if (tr->flags & TRACE_ARRAY_FL_MOD_INIT)
return;

INIT_LIST_HEAD(&tr->func_probes);
INIT_LIST_HEAD(&tr->mod_trace);
INIT_LIST_HEAD(&tr->mod_notrace);

tr->flags |= TRACE_ARRAY_FL_MOD_INIT;
}
#else

Expand Down Expand Up @@ -7818,7 +7866,8 @@ static void ftrace_update_trampoline(struct ftrace_ops *ops)
__init void ftrace_init_global_array_ops(struct trace_array *tr)
{
tr->ops = &global_ops;
tr->ops->private = tr;
if (!global_ops.private)
global_ops.private = tr;
ftrace_init_trace_array(tr);
init_array_fgraph_ops(tr, tr->ops);
}
Expand Down
8 changes: 8 additions & 0 deletions kernel/trace/trace.c
Original file line number Diff line number Diff line change
Expand Up @@ -10657,6 +10657,14 @@ __init static int tracer_alloc_buffers(void)
return ret;
}

#ifdef CONFIG_FUNCTION_TRACER
/* Used to set module cached ftrace filtering at boot up */
__init struct trace_array *trace_get_global_array(void)
{
return &global_trace;
}
#endif

void __init ftrace_boot_snapshot(void)
{
#ifdef CONFIG_TRACER_MAX_TRACE
Expand Down
2 changes: 2 additions & 0 deletions kernel/trace/trace.h
Original file line number Diff line number Diff line change
Expand Up @@ -432,6 +432,7 @@ struct trace_array {
enum {
TRACE_ARRAY_FL_GLOBAL = BIT(0),
TRACE_ARRAY_FL_BOOT = BIT(1),
TRACE_ARRAY_FL_MOD_INIT = BIT(2),
};

extern struct list_head ftrace_trace_arrays;
Expand Down Expand Up @@ -1116,6 +1117,7 @@ void ftrace_destroy_function_files(struct trace_array *tr);
int ftrace_allocate_ftrace_ops(struct trace_array *tr);
void ftrace_free_ftrace_ops(struct trace_array *tr);
void ftrace_init_global_array_ops(struct trace_array *tr);
struct trace_array *trace_get_global_array(void);
void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func);
void ftrace_reset_array_ops(struct trace_array *tr);
void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer);
Expand Down

0 comments on commit 31f505d

Please sign in to comment.