Skip to content

Commit 31f505d

Browse files
committed
ftrace: Implement :mod: cache filtering on kernel command line
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 <[email protected]> Cc: Mark Rutland <[email protected]> Cc: Mathieu Desnoyers <[email protected]> Link: https://lore.kernel.org/[email protected] Signed-off-by: Steven Rostedt (Google) <[email protected]>
1 parent 8275637 commit 31f505d

File tree

3 files changed

+68
-9
lines changed

3 files changed

+68
-9
lines changed

kernel/trace/ftrace.c

Lines changed: 58 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -4968,10 +4968,6 @@ static int cache_mod(struct trace_array *tr,
49684968
return ftrace_add_mod(tr, func, module, enable);
49694969
}
49704970

4971-
static int
4972-
ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
4973-
int reset, int enable);
4974-
49754971
#ifdef CONFIG_MODULES
49764972
static void process_mod_list(struct list_head *head, struct ftrace_ops *ops,
49774973
char *mod, bool enable)
@@ -5761,7 +5757,7 @@ ftrace_match_addr(struct ftrace_hash *hash, unsigned long *ips,
57615757
static int
57625758
ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
57635759
unsigned long *ips, unsigned int cnt,
5764-
int remove, int reset, int enable)
5760+
int remove, int reset, int enable, char *mod)
57655761
{
57665762
struct ftrace_hash **orig_hash;
57675763
struct ftrace_hash *hash;
@@ -5787,7 +5783,15 @@ ftrace_set_hash(struct ftrace_ops *ops, unsigned char *buf, int len,
57875783
goto out_regex_unlock;
57885784
}
57895785

5790-
if (buf && !ftrace_match_records(hash, buf, len)) {
5786+
if (buf && !match_records(hash, buf, len, mod)) {
5787+
/* If this was for a module and nothing was enabled, flag it */
5788+
if (mod)
5789+
(*orig_hash)->flags |= FTRACE_HASH_FL_MOD;
5790+
5791+
/*
5792+
* Even if it is a mod, return error to let caller know
5793+
* nothing was added
5794+
*/
57915795
ret = -EINVAL;
57925796
goto out_regex_unlock;
57935797
}
@@ -5812,7 +5816,7 @@ static int
58125816
ftrace_set_addr(struct ftrace_ops *ops, unsigned long *ips, unsigned int cnt,
58135817
int remove, int reset, int enable)
58145818
{
5815-
return ftrace_set_hash(ops, NULL, 0, ips, cnt, remove, reset, enable);
5819+
return ftrace_set_hash(ops, NULL, 0, ips, cnt, remove, reset, enable, NULL);
58165820
}
58175821

58185822
#ifdef CONFIG_DYNAMIC_FTRACE_WITH_DIRECT_CALLS
@@ -6190,7 +6194,38 @@ static int
61906194
ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
61916195
int reset, int enable)
61926196
{
6193-
return ftrace_set_hash(ops, buf, len, NULL, 0, 0, reset, enable);
6197+
char *mod = NULL, *func, *command, *next = buf;
6198+
char *tmp __free(kfree) = NULL;
6199+
struct trace_array *tr = ops->private;
6200+
int ret;
6201+
6202+
func = strsep(&next, ":");
6203+
6204+
/* This can also handle :mod: parsing */
6205+
if (next) {
6206+
if (!tr)
6207+
return -EINVAL;
6208+
6209+
command = strsep(&next, ":");
6210+
if (strcmp(command, "mod") != 0)
6211+
return -EINVAL;
6212+
6213+
mod = next;
6214+
len = command - func;
6215+
/* Save the original func as ftrace_set_hash() can modify it */
6216+
tmp = kstrdup(func, GFP_KERNEL);
6217+
}
6218+
6219+
ret = ftrace_set_hash(ops, func, len, NULL, 0, 0, reset, enable, mod);
6220+
6221+
if (tr && mod && ret < 0) {
6222+
/* Did tmp fail to allocate? */
6223+
if (!tmp)
6224+
return -ENOMEM;
6225+
ret = cache_mod(tr, tmp, mod, enable);
6226+
}
6227+
6228+
return ret;
61946229
}
61956230

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

63556390
ftrace_ops_init(ops);
63566391

6392+
/* The trace_array is needed for caching module function filters */
6393+
if (!ops->private) {
6394+
struct trace_array *tr = trace_get_global_array();
6395+
6396+
ops->private = tr;
6397+
ftrace_init_trace_array(tr);
6398+
}
6399+
63576400
while (buf) {
63586401
func = strsep(&buf, ",");
63596402
ftrace_set_regex(ops, func, strlen(func), 0, enable);
@@ -7787,9 +7830,14 @@ static void ftrace_update_trampoline(struct ftrace_ops *ops)
77877830

77887831
void ftrace_init_trace_array(struct trace_array *tr)
77897832
{
7833+
if (tr->flags & TRACE_ARRAY_FL_MOD_INIT)
7834+
return;
7835+
77907836
INIT_LIST_HEAD(&tr->func_probes);
77917837
INIT_LIST_HEAD(&tr->mod_trace);
77927838
INIT_LIST_HEAD(&tr->mod_notrace);
7839+
7840+
tr->flags |= TRACE_ARRAY_FL_MOD_INIT;
77937841
}
77947842
#else
77957843

@@ -7818,7 +7866,8 @@ static void ftrace_update_trampoline(struct ftrace_ops *ops)
78187866
__init void ftrace_init_global_array_ops(struct trace_array *tr)
78197867
{
78207868
tr->ops = &global_ops;
7821-
tr->ops->private = tr;
7869+
if (!global_ops.private)
7870+
global_ops.private = tr;
78227871
ftrace_init_trace_array(tr);
78237872
init_array_fgraph_ops(tr, tr->ops);
78247873
}

kernel/trace/trace.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10657,6 +10657,14 @@ __init static int tracer_alloc_buffers(void)
1065710657
return ret;
1065810658
}
1065910659

10660+
#ifdef CONFIG_FUNCTION_TRACER
10661+
/* Used to set module cached ftrace filtering at boot up */
10662+
__init struct trace_array *trace_get_global_array(void)
10663+
{
10664+
return &global_trace;
10665+
}
10666+
#endif
10667+
1066010668
void __init ftrace_boot_snapshot(void)
1066110669
{
1066210670
#ifdef CONFIG_TRACER_MAX_TRACE

kernel/trace/trace.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,7 @@ struct trace_array {
432432
enum {
433433
TRACE_ARRAY_FL_GLOBAL = BIT(0),
434434
TRACE_ARRAY_FL_BOOT = BIT(1),
435+
TRACE_ARRAY_FL_MOD_INIT = BIT(2),
435436
};
436437

437438
extern struct list_head ftrace_trace_arrays;
@@ -1116,6 +1117,7 @@ void ftrace_destroy_function_files(struct trace_array *tr);
11161117
int ftrace_allocate_ftrace_ops(struct trace_array *tr);
11171118
void ftrace_free_ftrace_ops(struct trace_array *tr);
11181119
void ftrace_init_global_array_ops(struct trace_array *tr);
1120+
struct trace_array *trace_get_global_array(void);
11191121
void ftrace_init_array_ops(struct trace_array *tr, ftrace_func_t func);
11201122
void ftrace_reset_array_ops(struct trace_array *tr);
11211123
void ftrace_init_tracefs(struct trace_array *tr, struct dentry *d_tracer);

0 commit comments

Comments
 (0)