diff mbox series

ftrace: Implement :mod: cache filtering on kernel command line

Message ID 20250109174639.32e6f43a@gandalf.local.home (mailing list archive)
State Superseded
Headers show
Series ftrace: Implement :mod: cache filtering on kernel command line | expand

Commit Message

Steven Rostedt Jan. 9, 2025, 10:46 p.m. UTC
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(-)

Comments

kernel test robot Jan. 10, 2025, 7:35 p.m. UTC | #1
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
kernel test robot Jan. 10, 2025, 7:57 p.m. UTC | #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
diff mbox series

Patch

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);