kernel/trace/ftrace.c | 67 +++++++++++++++++++++++++++++++++++++------ kernel/trace/trace.c | 6 ++++ kernel/trace/trace.h | 2 ++ 3 files changed, 66 insertions(+), 9 deletions(-)
From: Steven Rostedt <rostedt@goodmis.org>
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.
Signed-off-by: Steven Rostedt (Google) <rostedt@goodmis.org>
---
kernel/trace/ftrace.c | 67 +++++++++++++++++++++++++++++++++++++------
kernel/trace/trace.c | 6 ++++
kernel/trace/trace.h | 2 ++
3 files changed, 66 insertions(+), 9 deletions(-)
diff --git a/kernel/trace/ftrace.c b/kernel/trace/ftrace.c
index 2e113f8b13a2..5f6b169e3358 100644
--- a/kernel/trace/ftrace.c
+++ b/kernel/trace/ftrace.c
@@ -4982,10 +4982,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)
@@ -5788,7 +5784,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;
@@ -5814,7 +5810,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;
}
@@ -5839,7 +5843,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
@@ -6217,7 +6221,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, *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;
}
/**
@@ -6381,6 +6416,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);
@@ -7814,9 +7857,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
@@ -7845,7 +7893,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);
}
diff --git a/kernel/trace/trace.c b/kernel/trace/trace.c
index f8aebcb01e62..5451f3e2e17b 100644
--- a/kernel/trace/trace.c
+++ b/kernel/trace/trace.c
@@ -10660,6 +10660,12 @@ __init static int tracer_alloc_buffers(void)
return ret;
}
+/* Used to set module cached ftrace filtering at boot up */
+__init struct trace_array *trace_get_global_array(void)
+{
+ return &global_trace;
+}
+
void __init ftrace_boot_snapshot(void)
{
#ifdef CONFIG_TRACER_MAX_TRACE
diff --git a/kernel/trace/trace.h b/kernel/trace/trace.h
index 9691b47b5f3d..b6e60013ce0f 100644
--- a/kernel/trace/trace.h
+++ b/kernel/trace/trace.h
@@ -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;
@@ -1114,6 +1115,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);
--
2.45.2
Hi Steven,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v6.13-rc6 next-20250110]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Steven-Rostedt/ftrace-Implement-mod-cache-filtering-on-kernel-command-line/20250110-064649
base: linus/master
patch link: https://lore.kernel.org/r/20250109174639.32e6f43a%40gandalf.local.home
patch subject: [PATCH] ftrace: Implement :mod: cache filtering on kernel command line
config: i386-randconfig-013-20250111 (https://download.01.org/0day-ci/archive/20250111/202501110314.8tTxSS0N-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250111/202501110314.8tTxSS0N-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501110314.8tTxSS0N-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> kernel/trace/ftrace.c:6232:6: warning: variable 'mod' is used uninitialized whenever 'if' condition is false [-Wsometimes-uninitialized]
6232 | if (next) {
| ^~~~
kernel/trace/ftrace.c:6246:67: note: uninitialized use occurs here
6246 | ret = ftrace_set_hash(ops, func, len, NULL, 0, 0, reset, enable, mod);
| ^~~
kernel/trace/ftrace.c:6232:2: note: remove the 'if' if its condition is always true
6232 | if (next) {
| ^~~~~~~~~
kernel/trace/ftrace.c:6224:11: note: initialize the variable 'mod' to silence this warning
6224 | char *mod, *func, *command, *next = buf;
| ^
| = NULL
1 warning generated.
vim +6232 kernel/trace/ftrace.c
6219
6220 static int
6221 ftrace_set_regex(struct ftrace_ops *ops, unsigned char *buf, int len,
6222 int reset, int enable)
6223 {
6224 char *mod, *func, *command, *next = buf;
6225 char *tmp __free(kfree) = NULL;
6226 struct trace_array *tr = ops->private;
6227 int ret;
6228
6229 func = strsep(&next, ":");
6230
6231 /* This can also handle :mod: parsing */
> 6232 if (next) {
6233 if (!tr)
6234 return -EINVAL;
6235
6236 command = strsep(&next, ":");
6237 if (strcmp(command, "mod") != 0)
6238 return -EINVAL;
6239
6240 mod = next;
6241 len = command - func;
6242 /* Save the original func as ftrace_set_hash() can modify it */
6243 tmp = kstrdup(func, GFP_KERNEL);
6244 }
6245
6246 ret = ftrace_set_hash(ops, func, len, NULL, 0, 0, reset, enable, mod);
6247
6248 if (tr && mod && ret < 0) {
6249 /* Did tmp fail to allocate? */
6250 if (!tmp)
6251 return -ENOMEM;
6252 ret = cache_mod(tr, tmp, mod, enable);
6253 }
6254
6255 return ret;
6256 }
6257
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
Hi Steven,
kernel test robot noticed the following build warnings:
[auto build test WARNING on linus/master]
[also build test WARNING on v6.13-rc6 next-20250110]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]
url: https://github.com/intel-lab-lkp/linux/commits/Steven-Rostedt/ftrace-Implement-mod-cache-filtering-on-kernel-command-line/20250110-064649
base: linus/master
patch link: https://lore.kernel.org/r/20250109174639.32e6f43a%40gandalf.local.home
patch subject: [PATCH] ftrace: Implement :mod: cache filtering on kernel command line
config: i386-randconfig-012-20250111 (https://download.01.org/0day-ci/archive/20250111/202501110319.xY9ltUxL-lkp@intel.com/config)
compiler: clang version 19.1.3 (https://github.com/llvm/llvm-project ab51eccf88f5321e7c60591c5546b254b6afab99)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20250111/202501110319.xY9ltUxL-lkp@intel.com/reproduce)
If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202501110319.xY9ltUxL-lkp@intel.com/
All warnings (new ones prefixed by >>):
>> kernel/trace/trace.c:10664:28: warning: no previous prototype for function 'trace_get_global_array' [-Wmissing-prototypes]
10664 | __init struct trace_array *trace_get_global_array(void)
| ^
kernel/trace/trace.c:10664:8: note: declare 'static' if the function is not intended to be used outside of this translation unit
10664 | __init struct trace_array *trace_get_global_array(void)
| ^
| static
1 warning generated.
vim +/trace_get_global_array +10664 kernel/trace/trace.c
10662
10663 /* Used to set module cached ftrace filtering at boot up */
10664 __init struct trace_array *trace_get_global_array(void)
10665 {
10666 return &global_trace;
10667 }
10668
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
© 2016 - 2025 Red Hat, Inc.