From: Alan Maguire <alan.maguire@oracle.com>
To: ast@kernel.org, andrii@kernel.org
Cc: daniel@iogearbox.net, eddyz87@gmail.com, jolsa@kernel.org,
ihor.solodrai@linux.dev, yonghong.song@linux.dev,
song@kernel.org, qmo@kernel.org, martin.lau@linux.dev,
memxor@gmail.com, emil@etsalapatis.com, mcgrof@kernel.org,
petr.pavlu@suse.com, tj@kernel.org, kees@kernel.org,
bpf@vger.kernel.org, nathan@kernel.org, nsc@kernel.org,
arnd@arndb.de, puranjay@kernel.org, yatsenko@meta.com,
atenart@kernel.org, ojeda@kernel.org,
linux-modules@vger.kernel.org,
Alan Maguire <alan.maguire@oracle.com>
Subject: [PATCH v2 bpf-next 15/18] btf: Support CONFIG_DEBUG_INFO_BTF_INLINE=m
Date: Tue, 1 Sep 2026 17:57:54 +0100 [thread overview]
Message-ID: <20260901165757.801449-16-alan.maguire@oracle.com> (raw)
In-Reply-To: <20260901165757.801449-1-alan.maguire@oracle.com>
Allow vmlinux BTF inline info to be delivered via a loadable
module btf_vmlinux_inline.ko; this reduces the vmlinux binary size.
We cannot use the standard sysfs_create_bin_file() interface
for this because when the user open()s vmlinux.inline() we
want to trigger module load. To do this we need to use
a kernfs representation for vmlinux.inline which we initialize
with NULL data, 0 size. When open() is called the kernfs
callback uses request_module() to trigger the module load
and the module notifier allocates the BTF data and sets the
size in the bin_attribute. Once this is complete we can
update the file inode and the caller will see the updated
size and be able to fseek(), ftell() and fread() normally.
With all this in place vmlinux.inline is created on startup
with size 0 and when open()ed we will synchronously load
the module and assign the binary data. So a user running
"bpftool btf dump -B vmlinux file vmlinux.inline" sees identical
behaviour whether the inline info is module-delivered or otherwise;
we simply save memory allocation if the inline info is not needed.
Inline BTF module delivery relies on the module BTF notifier, so select
DEBUG_INFO_BTF_MODULES when modules are enabled. Keep built-in-only
CONFIG_DEBUG_INFO_BTF_INLINE=y configurations independent of module BTF.
Signed-off-by: Alan Maguire <alan.maguire@oracle.com>
---
Makefile | 1 +
kernel/bpf/btf.c | 114 +++++++++++++++++++++++++++++++-
kernel/bpf/btf_vmlinux_inline.c | 7 ++
lib/Kconfig.debug | 3 +-
scripts/gen-btf.sh | 18 ++++-
5 files changed, 139 insertions(+), 4 deletions(-)
diff --git a/Makefile b/Makefile
index 130926fa592e..4fa15fa5d1ed 100644
--- a/Makefile
+++ b/Makefile
@@ -1733,6 +1733,7 @@ endif # CONFIG_MODULES
CLEAN_FILES += vmlinux.symvers modules-only.symvers \
modules.builtin modules.builtin.modinfo modules.nsdeps \
modules.builtin.ranges vmlinux.o.map vmlinux.unstripped \
+ vmlinux.BTF.inline \
vmlinux.thinlto-index builtin.order \
compile_commands.json rust/test \
rust-project.json .vmlinux.objs .vmlinux.export.c \
diff --git a/kernel/bpf/btf.c b/kernel/bpf/btf.c
index 3e5890aed2db..2ac1f1d39660 100644
--- a/kernel/bpf/btf.c
+++ b/kernel/bpf/btf.c
@@ -8,6 +8,7 @@
#include <linux/seq_file.h>
#include <linux/compiler.h>
#include <linux/ctype.h>
+#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/slab.h>
#include <linux/anon_inodes.h>
@@ -25,6 +26,7 @@
#include <linux/perf_event.h>
#include <linux/bsearch.h>
#include <linux/kobject.h>
+#include <linux/kernfs.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/overflow.h>
@@ -8736,10 +8738,82 @@ enum {
};
#if IS_ENABLED(CONFIG_SYSFS)
+#if IS_ENABLED(CONFIG_DEBUG_INFO_BTF_INLINE)
+static struct bin_attribute *vmlinux_inline_attr;
+#endif
+
+static int sysfs_btf_bin_attr_load(struct bin_attribute *attr)
+{
+ char modname[MODULE_NAME_LEN + sizeof("btf_vmlinux_inline")];
+ int retries = 0;
+
+ /* First on-demand read; load module. */
+ snprintf(modname, sizeof(modname), "btf_%s", attr->attr.name);
+ strreplace(modname, '.', '_');
+ request_module("%s", modname);
+
+ /*
+ * request_module() is synchronous, but the module notifier is
+ * responsible for updating private data, so retries are required.
+ */
+ while (retries++ < 10) {
+ if (smp_load_acquire(&attr->size))
+ return 0;
+ udelay(50);
+ }
+ return -ENODEV;
+}
+
+static int sysfs_btf_kernfs_open(struct kernfs_open_file *of)
+{
+ struct bin_attribute *attr = of->kn->priv;
+ size_t data_size;
+ int err;
+
+ if (!smp_load_acquire(&attr->size)) {
+ err = sysfs_btf_bin_attr_load(attr);
+ if (err)
+ return err;
+ }
+ /* Refresh file size or the open() caller will not see updated size. */
+ data_size = smp_load_acquire(&attr->size);
+ of->kn->attr.size = data_size;
+ if (of->file) {
+ struct inode *inode = file_inode(of->file);
+
+ if (inode)
+ i_size_write(inode, data_size);
+ }
+ return 0;
+}
+
+static ssize_t sysfs_btf_kernfs_read(struct kernfs_open_file *of, char *buf,
+ size_t bytes_requested, loff_t offset)
+{
+ struct bin_attribute *attr = of->kn->priv;
+ void *data;
+ size_t data_size;
+
+ data_size = smp_load_acquire(&attr->size);
+ if (offset >= data_size)
+ return 0;
+ if (offset + bytes_requested > data_size)
+ bytes_requested = data_size - offset;
+ data = READ_ONCE(attr->private);
+ memcpy(buf, data + offset, bytes_requested);
+
+ return bytes_requested;
+}
+
+static const struct kernfs_ops sysfs_btf_kernfs_ops = {
+ .open = sysfs_btf_kernfs_open,
+ .read = sysfs_btf_kernfs_read,
+};
+
struct bin_attribute *sysfs_btf_add(const char *name, void *data, size_t data_size)
{
struct bin_attribute *attr;
- int err;
+ int err = 0;
attr = kzalloc_obj(*attr);
if (!attr)
@@ -8755,7 +8829,18 @@ struct bin_attribute *sysfs_btf_add(const char *name, void *data, size_t data_si
err = -ENOMEM;
goto err_free;
}
- err = sysfs_create_bin_file(btf_kobj, attr);
+ if (data_size > 0) {
+ err = sysfs_create_bin_file(btf_kobj, attr);
+ } else {
+ struct kernfs_node *node;
+
+ node = __kernfs_create_file(btf_kobj->sd, attr->attr.name,
+ attr->attr.mode, GLOBAL_ROOT_UID,
+ GLOBAL_ROOT_GID, data_size,
+ &sysfs_btf_kernfs_ops, attr, NULL, NULL);
+ if (IS_ERR(node))
+ err = PTR_ERR(node);
+ }
if (err) {
pr_warn("failed to register [%s] BTF in sysfs: %d\n", name, err);
goto err_free;
@@ -8775,6 +8860,17 @@ struct bin_attribute *sysfs_btf_add(const char *name, void *data, size_t data_si
}
#endif
+#if IS_ENABLED(CONFIG_DEBUG_INFO_BTF_INLINE)
+static void sysfs_btf_update(struct bin_attribute *attr, void *data, size_t data_size)
+{
+ if (!attr)
+ return;
+ WRITE_ONCE(attr->private, data);
+ /* Publish data before its non-zero size makes it readable. */
+ smp_store_release(&attr->size, data_size);
+}
+#endif
+
#ifdef CONFIG_DEBUG_INFO_BTF_MODULES
#if IS_ENABLED(CONFIG_SYSFS)
static void sysfs_btf_remove(struct bin_attribute *attr)
@@ -8872,6 +8968,14 @@ static int btf_module_notify(struct notifier_block *nb, unsigned long op,
err = 0;
goto out;
}
+ if (strcmp(mod->name, "btf_vmlinux_inline") == 0) {
+ if (vmlinux_inline_attr)
+ sysfs_btf_update(vmlinux_inline_attr, data,
+ mod->btf_inline_data_size);
+ else
+ kvfree(data);
+ break;
+ }
snprintf(name, sizeof(name), "%s.inline", mod->name);
attr = sysfs_btf_add(name, data, mod->btf_inline_data_size);
if (IS_ERR(attr)) {
@@ -8937,6 +9041,12 @@ static struct notifier_block btf_module_nb = {
static int __init btf_module_init(void)
{
register_module_notifier(&btf_module_nb);
+#if IS_MODULE(CONFIG_DEBUG_INFO_BTF_INLINE)
+ /* Attribute data will be filled in on-demand if vmlinux.inline is read. */
+ vmlinux_inline_attr = sysfs_btf_add("vmlinux.inline", NULL, 0);
+ if (IS_ERR(vmlinux_inline_attr))
+ vmlinux_inline_attr = NULL;
+#endif
return 0;
}
diff --git a/kernel/bpf/btf_vmlinux_inline.c b/kernel/bpf/btf_vmlinux_inline.c
index b155df9849b9..13ed962ffceb 100644
--- a/kernel/bpf/btf_vmlinux_inline.c
+++ b/kernel/bpf/btf_vmlinux_inline.c
@@ -26,5 +26,12 @@ static int __init btf_vmlinux_inline_init(void)
}
subsys_initcall(btf_vmlinux_inline_init);
+#if IS_MODULE(CONFIG_DEBUG_INFO_BTF_INLINE)
+static void __exit btf_vmlinux_inline_fini(void)
+{
+}
+module_exit(btf_vmlinux_inline_fini);
+#endif
+
MODULE_DESCRIPTION("BTF inline information for vmlinux");
MODULE_LICENSE("GPL");
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index dd1b2d9ebe99..1b96d6acfdce 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -439,9 +439,10 @@ config DEBUG_INFO_BTF_MODULES
Generate compact split BTF type information for kernel modules.
config DEBUG_INFO_BTF_INLINE
- bool "Provide information about inline sites in BTF"
+ tristate "Provide information about inline sites in BTF"
default n
depends on DEBUG_INFO_BTF && PAHOLE_HAS_INLINE && SYSFS
+ select DEBUG_INFO_BTF_MODULES if MODULES
help
Generate information about inline sites in .BTF.inline sections.
These sections contain split BTF relative to the kernel or module BTF
diff --git a/scripts/gen-btf.sh b/scripts/gen-btf.sh
index a75f41878c32..cd6588588fb8 100755
--- a/scripts/gen-btf.sh
+++ b/scripts/gen-btf.sh
@@ -93,7 +93,16 @@ gen_btf_o()
--set-section-flags .BTF=alloc,readonly ${btf_data}
ONLY_SEC="--only-section=.BTF"
btf_inline=${ELF_FILE}.BTF.inline
- if [ -n "${BTF_INLINE}" ] && [ -f "${btf_inline}" ]; then
+ if [ "${BTF_INLINE}" = "m" ]; then
+ # vmlinux BTF is generated from a temporary ELF. Retain its
+ # vmlinux-relative inline BTF for btf_vmlinux_inline.ko.
+ if [ -f "${btf_inline}" ]; then
+ cp "${btf_inline}" "${objtree}/vmlinux.BTF.inline"
+ else
+ rm -f "${objtree}/vmlinux.BTF.inline"
+ fi
+ fi
+ if [ "${BTF_INLINE}" = "y" ] && [ -f "${btf_inline}" ]; then
${OBJCOPY} --add-section .BTF.inline=${btf_inline} \
--set-section-flags .BTF.inline=alloc,readonly ${btf_data}
ONLY_SEC="${ONLY_SEC} --only-section=.BTF.inline"
@@ -120,6 +129,13 @@ embed_btf_data()
${OBJCOPY} --add-section .BTF.base=${btf_base} ${ELF_FILE}
fi
btf_inline=${ELF_FILE}.BTF.inline
+ case "${ELF_FILE}" in
+ */btf_vmlinux_inline.ko)
+ # With CONFIG_DEBUG_INFO_BTF_INLINE=m, deliver vmlinux
+ # .BTF.inline via module
+ btf_inline=${BTF_BASE}.BTF.inline
+ ;;
+ esac
if [ -n "${BTF_INLINE}" ] && [ -f "${btf_inline}" ]; then
${OBJCOPY} --add-section .BTF.inline=${btf_inline} ${ELF_FILE}
fi
--
2.43.5
next prev parent reply other threads:[~2026-09-01 16:59 UTC|newest]
Thread overview: 42+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-09-01 16:57 [PATCH v2 bpf-next 00/18] Support inline functions in BTF Alan Maguire
2026-09-01 16:57 ` [PATCH v2 bpf-next 01/18] btf: Extend UAPI to support BTF location (inline site) info Alan Maguire
2026-09-01 17:17 ` sashiko-bot
2026-09-01 17:55 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 02/18] libbpf: Add support for BTF kinds LOC[_PARAM|_PROTO|SEC] Alan Maguire
2026-09-01 17:11 ` sashiko-bot
2026-09-01 16:57 ` [PATCH v2 bpf-next 03/18] libbpf: Support moving permuted BTF types into split BTF Alan Maguire
2026-09-01 17:15 ` sashiko-bot
2026-09-01 18:14 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 04/18] selftests/bpf: Test helper support for BTF_KIND_LOC[_PARAM|_PROTO|SEC] Alan Maguire
2026-09-01 17:06 ` sashiko-bot
2026-09-01 16:57 ` [PATCH v2 bpf-next 05/18] selftests/bpf: Add LOC_PARAM, LOC_PROTO, LOCSEC to field iter tests Alan Maguire
2026-09-01 16:57 ` [PATCH v2 bpf-next 06/18] selftests/bpf: Add LOC_PARAM, LOC_PROTO, LOCSEC to dedup split tests Alan Maguire
2026-09-01 17:55 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 07/18] selftests/bpf: BTF distill tests to ensure LOC[_PARAM|_PROTO] add to split BTF Alan Maguire
2026-09-01 17:55 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 08/18] selftests/bpf: Validate that btf__permute transfer works Alan Maguire
2026-09-01 17:16 ` sashiko-bot
2026-09-01 17:55 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 09/18] bpftool: Handle multi-split BTF by supporting multiple base BTFs Alan Maguire
2026-09-01 17:13 ` sashiko-bot
2026-09-01 16:57 ` [PATCH v2 bpf-next 10/18] bpftool: Document support for multi-split BTF Alan Maguire
2026-09-01 17:12 ` sashiko-bot
2026-09-01 16:57 ` [PATCH v2 bpf-next 11/18] bpftool: Add ability to dump LOC_PARAM, LOC_PROTO and LOCSEC Alan Maguire
2026-09-01 17:16 ` sashiko-bot
2026-09-01 17:55 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 12/18] resolve_btfids: Extract inline BTF Alan Maguire
2026-09-01 17:23 ` sashiko-bot
2026-09-01 16:57 ` [PATCH v2 bpf-next 13/18] kbuild: Add support for BTF inline information Alan Maguire
2026-09-01 17:55 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 14/18] btf: Make vmlinux, module inline info available in /sys/kernel/btf Alan Maguire
2026-09-01 16:57 ` Alan Maguire [this message]
2026-09-01 17:24 ` [PATCH v2 bpf-next 15/18] btf: Support CONFIG_DEBUG_INFO_BTF_INLINE=m sashiko-bot
2026-09-01 16:57 ` [PATCH v2 bpf-next 16/18] btf: Relocate inline BTF for modules with distilled base BTF Alan Maguire
2026-09-01 17:29 ` sashiko-bot
2026-09-01 17:55 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 17/18] selftests/bpf: Test BTF sysfs inline representations Alan Maguire
2026-09-01 17:22 ` sashiko-bot
2026-09-01 17:55 ` bot+bpf-ci
2026-09-01 16:57 ` [PATCH v2 bpf-next 18/18] selftests/bpf: Add a test verifying inline information Alan Maguire
2026-09-01 17:28 ` sashiko-bot
2026-09-01 17:55 ` bot+bpf-ci
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=20260901165757.801449-16-alan.maguire@oracle.com \
--to=alan.maguire@oracle.com \
--cc=andrii@kernel.org \
--cc=arnd@arndb.de \
--cc=ast@kernel.org \
--cc=atenart@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=emil@etsalapatis.com \
--cc=ihor.solodrai@linux.dev \
--cc=jolsa@kernel.org \
--cc=kees@kernel.org \
--cc=linux-modules@vger.kernel.org \
--cc=martin.lau@linux.dev \
--cc=mcgrof@kernel.org \
--cc=memxor@gmail.com \
--cc=nathan@kernel.org \
--cc=nsc@kernel.org \
--cc=ojeda@kernel.org \
--cc=petr.pavlu@suse.com \
--cc=puranjay@kernel.org \
--cc=qmo@kernel.org \
--cc=song@kernel.org \
--cc=tj@kernel.org \
--cc=yatsenko@meta.com \
--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