BPF List
 help / color / mirror / Atom feed
From: Jay Wang <wanjay@amazon.com>
To: <bpf@vger.kernel.org>, Alexei Starovoitov <ast@kernel.org>,
	"Daniel Borkmann" <daniel@iogearbox.net>,
	Andrii Nakryiko <andrii@kernel.org>,
	"Eduard Zingerman" <eddyz87@gmail.com>,
	Kumar Kartikeya Dwivedi <memxor@gmail.com>
Cc: Ihor Solodrai <ihor.solodrai@linux.dev>,
	Alan Maguire <almagui@kernel.org>,
	Martin KaFai Lau <martin.lau@linux.dev>,
	Yonghong Song <yonghong.song@linux.dev>,
	Jiri Olsa <jolsa@kernel.org>,
	Steven Rostedt <rostedt@goodmis.org>,
	Masami Hiramatsu <mhiramat@kernel.org>,
	"Mathieu Desnoyers" <mathieu.desnoyers@efficios.com>,
	<linux-trace-kernel@vger.kernel.org>,
	Nathan Chancellor <nathan@kernel.org>,
	Nicolas Schier <nsc@kernel.org>, <linux-kbuild@vger.kernel.org>,
	"Arnd Bergmann" <arnd@arndb.de>, <linux-arch@vger.kernel.org>,
	<x86@kernel.org>, <linux-doc@vger.kernel.org>,
	<linux-kernel@vger.kernel.org>,
	"Hazem Mohamed Abuelfotoh" <abuehaze@amazon.com>,
	Bjoern Doebel <doebel@amazon.de>,
	"Martin Pohlack" <mpohlack@amazon.de>,
	<jay.wang.upstream@gmail.com>
Subject: [PATCH bpf-next 08/13] tracing: parse the vmlinux BTF when BTF-typed output is enabled
Date: Sat, 31 Oct 2026 13:09:54 +0000	[thread overview]
Message-ID: <20261031130959.23472-9-wanjay@amazon.com> (raw)
In-Reply-To: <20261031130959.23472-1-wanjay@amazon.com>

From: Ihor Solodrai <ihor.solodrai@linux.dev>

func-args of the function tracer, and funcgraph-args and
funcgraph-retval of the function_graph tracer, print arguments and
return values by their BTF types: print_function_args() and
btf_trim_retval() look the function up with btf_find_func_proto(),
which parses the vmlinux BTF if nobody has yet.  Since commit
42643ba35deb ("tracing: Avoid BTF lookup in atomic context") they do not
do that in atomic context, but they still can in the readers of the
trace: s_show() and tracing_read_pipe() print under trace_event_sem and
the trace access lock, while the tracer keeps recording, by default
into the buffer being read.

Today the BTF is always parsed at boot, so this cannot happen.  To keep
it that way once the vmlinux BTF can be parsed on first use
(CONFIG_DEBUG_INFO_BTF_LAZY, later in this series), parse it when such
output is enabled instead: trace_btf_prepare() is called from
select_trace_function() when func-args is set, from graph_trace_init()
when funcgraph-args or funcgraph-retval is set, and from
func_graph_set_flag() when either is turned on, all with
trace_types_lock held.  The two printers only peek at the BTF and fall
back to the output without it if it is not parsed, which then cannot
happen while the option is in effect.

"trace_options=" on the command line sets the options from
early_trace_init() in start_kernel(), with interrupts disabled and
before btf_alloc_id() can allocate; while the system is still booting
(system_state < SYSTEM_SCHEDULING) trace_btf_prepare() only records the
request, and a core_initcall parses the BTF.

Reading an event's btf_ids file looks the BTF up under event_mutex;
parse it before taking the mutex, as the CO-RE candidate lookup does
before cand_cache_mutex.

No functional change with today's eager parse, except that with such
an option on the command line the BTF is parsed at core_initcall time,
before the initcalls that would otherwise parse it.

TODO-NEEDS-IHOR: Signed-off-by: Ihor Solodrai <ihor.solodrai@linux.dev>
[moved trace_func_args_prepare() to trace_btf.c as trace_btf_prepare();
 extended it to funcgraph-retval and the btf_ids file; the printers check
 the BTF with bpf_peek_btf_vmlinux() in front of btf_find_func_proto()]
Signed-off-by: Jay Wang <wanjay@amazon.com>
---
 kernel/trace/trace_btf.c             | 32 ++++++++++++++++++++++++++++
 kernel/trace/trace_btf.h             |  3 +++
 kernel/trace/trace_events.c          |  4 ++++
 kernel/trace/trace_functions.c       |  4 ++++
 kernel/trace/trace_functions_graph.c | 15 +++++++++++--
 kernel/trace/trace_output.c          |  3 +++
 6 files changed, 59 insertions(+), 2 deletions(-)

diff --git a/kernel/trace/trace_btf.c b/kernel/trace/trace_btf.c
index f0e0c04d58d9..693c1a1083c5 100644
--- a/kernel/trace/trace_btf.c
+++ b/kernel/trace/trace_btf.c
@@ -1,4 +1,5 @@
 // SPDX-License-Identifier: GPL-2.0
+#include <linux/bpf.h>
 #include <linux/btf.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
@@ -141,6 +142,34 @@ const struct btf_member *btf_find_struct_member(struct btf *btf,
 	return member;
 }
 
+static bool trace_btf_deferred;
+
+/*
+ * func-args, funcgraph-args and funcgraph-retval print arguments and return
+ * values by their BTF types, and the readers of the trace use the vmlinux
+ * BTF only if it is parsed already: parse it when such output is enabled.
+ * With CONFIG_DEBUG_INFO_BTF_LAZY that may be its first use, which should
+ * not happen in a reader that holds the trace read locks while the tracer
+ * records its work.
+ */
+void trace_btf_prepare(void)
+{
+	/* trace_options= on the command line is applied by early_trace_init() */
+	if (system_state < SYSTEM_SCHEDULING) {
+		trace_btf_deferred = true;
+		return;
+	}
+	bpf_get_btf_vmlinux();
+}
+
+static int __init trace_btf_init(void)
+{
+	if (trace_btf_deferred)
+		bpf_get_btf_vmlinux();
+	return 0;
+}
+core_initcall(trace_btf_init);
+
 void btf_trim_retval(unsigned long func, unsigned long *retval, bool *print_retval,
 			int *fmt, bool hex)
 {
@@ -151,6 +180,9 @@ void btf_trim_retval(unsigned long func, unsigned long *retval, bool *print_retv
 	bool signed_type;
 	int kind;
 
+	/* see trace_btf_prepare() */
+	if (IS_ERR_OR_NULL(bpf_peek_btf_vmlinux()))
+		return;
 	if (lookup_symbol_name(func, name))
 		return;
 
diff --git a/kernel/trace/trace_btf.h b/kernel/trace/trace_btf.h
index b3d408e6a7f6..47407eff1339 100644
--- a/kernel/trace/trace_btf.h
+++ b/kernel/trace/trace_btf.h
@@ -23,9 +23,12 @@ const struct btf_member *btf_find_struct_member(struct btf *btf,
 #ifdef CONFIG_DEBUG_INFO_BTF
 void btf_trim_retval(unsigned long func, unsigned long *retval, bool *print_retval,
 		     int *fmt, bool hex);
+void trace_btf_prepare(void);
 #else
 static inline void btf_trim_retval(unsigned long func, unsigned long *retval,
 				   bool *print_retval, int *fmt, bool hex)
 {
 }
+
+static inline void trace_btf_prepare(void) { }
 #endif
diff --git a/kernel/trace/trace_events.c b/kernel/trace/trace_events.c
index 49d135bc2fbf..adc422fbe16e 100644
--- a/kernel/trace/trace_events.c
+++ b/kernel/trace/trace_events.c
@@ -23,6 +23,7 @@
 #include <linux/sort.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
+#include <linux/bpf.h>
 #include <linux/btf.h>
 
 #include <kunit/visibility.h>
@@ -2282,6 +2283,9 @@ event_btf_ids_read(struct file *filp, char __user *ubuf, size_t cnt, loff_t *ppo
 	char buf[128];
 	int len;
 
+	/* parse the vmlinux BTF, if this is its first use, without event_mutex */
+	bpf_get_btf_vmlinux();
+
 	/* Module unload could free call->class and ids[] mid-read. */
 	scoped_guard(mutex, &event_mutex) {
 		file = event_file_file(filp);
diff --git a/kernel/trace/trace_functions.c b/kernel/trace/trace_functions.c
index acaba990aaaa..2cebaacda526 100644
--- a/kernel/trace/trace_functions.c
+++ b/kernel/trace/trace_functions.c
@@ -18,6 +18,7 @@
 #include <linux/fs.h>
 
 #include "trace.h"
+#include "trace_btf.h"
 
 static void tracing_start_function_trace(struct trace_array *tr);
 static void tracing_stop_function_trace(struct trace_array *tr);
@@ -115,6 +116,9 @@ void ftrace_destroy_function_files(struct trace_array *tr)
 
 static ftrace_func_t select_trace_function(u32 flags_val)
 {
+	if (flags_val & TRACE_FUNC_OPT_ARGS)
+		trace_btf_prepare();
+
 	switch (flags_val & TRACE_FUNC_OPT_MASK) {
 	case TRACE_FUNC_NO_OPTS:
 		return function_trace_call;
diff --git a/kernel/trace/trace_functions_graph.c b/kernel/trace/trace_functions_graph.c
index 78a608315dd3..cf5f433dd26e 100644
--- a/kernel/trace/trace_functions_graph.c
+++ b/kernel/trace/trace_functions_graph.c
@@ -474,6 +474,10 @@ static int graph_trace_init(struct trace_array *tr)
 {
 	int ret;
 
+	if (tracer_flags_is_set(tr, TRACE_GRAPH_ARGS) ||
+	    tracer_flags_is_set(tr, TRACE_GRAPH_PRINT_RETVAL))
+		trace_btf_prepare();
+
 	if (tracer_flags_is_set(tr, TRACE_GRAPH_ARGS))
 		tr->gops->entryfunc = trace_graph_entry_args;
 	else
@@ -507,10 +511,12 @@ static int ftrace_graph_trace_args(struct trace_array *tr, int set)
 {
 	trace_func_graph_ent_t entry;
 
-	if (set)
+	if (set) {
+		trace_btf_prepare();
 		entry = trace_graph_entry_args;
-	else
+	} else {
 		entry = trace_graph_entry;
+	}
 
 	/* See if there's any changes */
 	if (tr->gops->entryfunc == entry)
@@ -1746,6 +1752,11 @@ func_graph_set_flag(struct trace_array *tr, u32 old_flags, u32 bit, int set)
 
 	case TRACE_GRAPH_ARGS:
 		return ftrace_graph_trace_args(tr, set);
+
+	case TRACE_GRAPH_PRINT_RETVAL:
+		if (set)
+			trace_btf_prepare();
+		break;
 	}
 
 	return 0;
diff --git a/kernel/trace/trace_output.c b/kernel/trace/trace_output.c
index a5ad76175d10..cdb926c9d4e2 100644
--- a/kernel/trace/trace_output.c
+++ b/kernel/trace/trace_output.c
@@ -739,6 +739,9 @@ void print_function_args(struct trace_seq *s, unsigned long *args,
 	if (lookup_symbol_name(func, name))
 		goto out;
 
+	/* see trace_btf_prepare() */
+	if (IS_ERR_OR_NULL(bpf_peek_btf_vmlinux()))
+		goto out;
 	/* TODO: Pass module name here too */
 	t = btf_find_func_proto(name, &btf);
 	if (IS_ERR_OR_NULL(t))
-- 
2.47.3


  parent reply	other threads:[~2026-10-31 13:12 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-10-31 13:09 [PATCH bpf-next 00/13] bpf: keep the vmlinux BTF compressed until first use (CONFIG_DEBUG_INFO_BTF_LAZY) to save ~6 MB memory Jay Wang
2026-10-31 13:09 ` [PATCH bpf-next 01/13] bpf: match program context types by name without vmlinux BTF Jay Wang
2026-10-31 13:43   ` bot+bpf-ci
2026-10-31 13:09 ` [PATCH bpf-next 02/13] bpf: fetch the vmlinux BTF where kernel types enter a program Jay Wang
2026-10-31 13:42   ` sashiko-bot
2026-10-31 13:55   ` bot+bpf-ci
2026-10-31 13:09 ` [PATCH bpf-next 03/13] bpf: check CAP_SYS_ADMIN before looking up bpffs delegation names Jay Wang
2026-10-31 13:43   ` bot+bpf-ci
2026-10-31 17:03   ` Alexei Starovoitov
2026-10-31 13:09 ` [PATCH bpf-next 04/13] bpf: move bpf_get_btf_vmlinux() to btf.c Jay Wang
2026-10-31 13:43   ` bot+bpf-ci
2026-10-31 13:09 ` [PATCH bpf-next 05/13] bpf: let btf_parse_module() adopt the caller's copy of the module BTF Jay Wang
2026-10-31 13:09 ` [PATCH bpf-next 06/13] bpf: look up the struct_ops common value type in the given BTF Jay Wang
2026-10-31 13:09 ` [PATCH bpf-next 07/13] bpf: parse the vmlinux BTF before taking cand_cache_mutex Jay Wang
2026-10-31 13:43   ` bot+bpf-ci
2026-10-31 13:09 ` Jay Wang [this message]
2026-10-31 13:37   ` [PATCH bpf-next 08/13] tracing: parse the vmlinux BTF when BTF-typed output is enabled sashiko-bot
2026-10-31 13:43   ` bot+bpf-ci
2026-10-31 13:09 ` [PATCH bpf-next 09/13] bpf: keep the vmlinux BTF zstd-compressed in the kernel image Jay Wang
2026-10-31 13:33   ` sashiko-bot
2026-10-31 13:55   ` bot+bpf-ci
2026-10-31 13:09 ` [PATCH bpf-next 10/13] bpf: defer kfunc and struct_ops registrations until first BTF use Jay Wang
2026-10-31 13:38   ` sashiko-bot
2026-10-31 13:55   ` bot+bpf-ci
2026-10-31 17:07   ` Alexei Starovoitov
2026-10-31 13:09 ` [PATCH bpf-next 11/13] bpf: keep module BTF until the vmlinux BTF is parsed Jay Wang
2026-10-31 13:37   ` sashiko-bot
2026-10-31 13:55   ` bot+bpf-ci
2026-10-31 17:10     ` Alexei Starovoitov
2026-10-31 13:09 ` [PATCH bpf-next 12/13] selftests/bpf: keep ksyms and linked_vars working without __start_BTF Jay Wang
2026-10-31 13:09 ` [PATCH bpf-next 13/13] Documentation/bpf: describe CONFIG_DEBUG_INFO_BTF_LAZY Jay Wang

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20261031130959.23472-9-wanjay@amazon.com \
    --to=wanjay@amazon.com \
    --cc=abuehaze@amazon.com \
    --cc=almagui@kernel.org \
    --cc=andrii@kernel.org \
    --cc=arnd@arndb.de \
    --cc=ast@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=doebel@amazon.de \
    --cc=eddyz87@gmail.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=jay.wang.upstream@gmail.com \
    --cc=jolsa@kernel.org \
    --cc=linux-arch@vger.kernel.org \
    --cc=linux-doc@vger.kernel.org \
    --cc=linux-kbuild@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-trace-kernel@vger.kernel.org \
    --cc=martin.lau@linux.dev \
    --cc=mathieu.desnoyers@efficios.com \
    --cc=memxor@gmail.com \
    --cc=mhiramat@kernel.org \
    --cc=mpohlack@amazon.de \
    --cc=nathan@kernel.org \
    --cc=nsc@kernel.org \
    --cc=rostedt@goodmis.org \
    --cc=x86@kernel.org \
    --cc=yonghong.song@linux.dev \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox