All of lore.kernel.org
 help / color / mirror / Atom feed
* [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs
@ 2026-08-06  4:20 Fuyu Zhao
  2026-08-06  4:20 ` [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao
                   ` (2 more replies)
  0 siblings, 3 replies; 11+ messages in thread
From: Fuyu Zhao @ 2026-08-06  4:20 UTC (permalink / raw)
  To: bpf; +Cc: Fuyu Zhao

Currently, during BPF object loading, load_module_btfs() unconditionally
iterates over all loaded kernel modules and loads their BTFs. This
introduces unnecessary overhead when a BPF program only needs a specific,
small subset of modules. In environments with hundreds of modules,
loading all module measurably increases the loading time.

This series introduces a ".kmod_btfs" ELF section, allowing BPF programs
to declare the modules that need BTF loading. libbpf parses this
section, collects the module names, and skips loading BTFs for any
module not in the list, thereby reducing overhead. It also stops the
iteration early once all declared modules are found.

Usage example:

  DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod" };

Performance impact (<skel>__open_and_load() time):

  Modules loaded | Without .kmod_btfs | With .kmod_btfs | Speedup
  ---------------|--------------------|-----------------|--------
  1              | 35.0 ms            | 35.0 ms         | Baseline
  10             | 36.5 ms            | 35.1 ms         | +3.8%
  100            | 46.2 ms            | 35.9 ms         | +22.3%
  300            | 65.2 ms            | 38.0 ms         | +41.7%

Fuyu Zhao (2):
  libbpf: support selective kernel module BTF loading via .kmod_btfs
    section
  selftests/bpf: add tests for selective kmod BTF loading

 tools/lib/bpf/bpf_helpers.h                   |  14 +++
 tools/lib/bpf/libbpf.c                        | 112 ++++++++++++++++++
 .../selftests/bpf/prog_tests/kmod_btfs.c      |  47 ++++++++
 tools/testing/selftests/bpf/progs/kmod_btfs.c |  14 +++
 .../selftests/bpf/progs/kmod_btfs_mix.c       |  15 +++
 .../selftests/bpf/progs/kmod_btfs_nonexist.c  |  17 +++
 6 files changed, 219 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
 create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs.c
 create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_mix.c
 create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c

-- 
2.34.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section
  2026-08-06  4:20 [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Fuyu Zhao
@ 2026-08-06  4:20 ` Fuyu Zhao
  2026-08-06  4:33   ` sashiko-bot
  2026-08-06  4:20 ` [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao
  2026-08-07 22:18 ` [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Andrii Nakryiko
  2 siblings, 1 reply; 11+ messages in thread
From: Fuyu Zhao @ 2026-08-06  4:20 UTC (permalink / raw)
  To: bpf
  Cc: Fuyu Zhao, Andrii Nakryiko, Eduard Zingerman, Ihor Solodrai,
	Alexei Starovoitov, Daniel Borkmann, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, open list

Add support for a new ELF section ".kmod_btfs" that allows BPF programs
to declare which kernel modules need BTF loading. This avoids loading
all module BTFs and speeds up program load when only a subset of modules
is needed.

Specifically, this patch introduces two internal functions:
  - bpf_object__collect_kmod_btf_names(): parses the ".kmod_btfs"
    section and collects the declared module names.
  - is_kmod_btf_needed(): determines whether a given module's BTF
    should be loaded, allowing libbpf to skip unneeded modules.

Signed-off-by: Fuyu Zhao <zhaofuyu@vivo.com>
---
 tools/lib/bpf/bpf_helpers.h |  14 +++++
 tools/lib/bpf/libbpf.c      | 112 ++++++++++++++++++++++++++++++++++++
 2 files changed, 126 insertions(+)

diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h
index 9d160b5b9c0e..171ea055cd32 100644
--- a/tools/lib/bpf/bpf_helpers.h
+++ b/tools/lib/bpf/bpf_helpers.h
@@ -188,6 +188,20 @@ enum libbpf_tristate {
 	TRI_MODULE = 2,
 };
 
+/* Helper typedef for declaring kernel module names that need BTF loading.
+ *
+ * Usage: define an array in the ".kmod_btfs" ELF section to specify
+ * which modules need BTF loading:
+ *
+ *   DEFINE_KMOD_BTFS(_needed_kmods)= { "module1", "module2", ... };
+ *
+ * This avoids unnecessary BTF loading and speeds up the BPF program
+ * load process.
+ */
+#define KMOD_NAME_LEN 64
+#define DEFINE_KMOD_BTFS(name) \
+	SEC(".kmod_btfs") char name[][KMOD_NAME_LEN]
+
 #define __kconfig __attribute__((section(".kconfig")))
 #define __ksym __attribute__((section(".ksyms")))
 #define __kptr_untrusted __attribute__((btf_type_tag("kptr_untrusted")))
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 514e4e9daa82..5cefe82e4a67 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -548,6 +548,7 @@ struct bpf_struct_ops {
 #define STRUCT_OPS_SEC ".struct_ops"
 #define STRUCT_OPS_LINK_SEC ".struct_ops.link"
 #define ARENA_SEC ".addr_space.1"
+#define KMODS_BTFS_SEC ".kmod_btfs"
 
 enum libbpf_map_type {
 	LIBBPF_MAP_UNSPEC,
@@ -703,6 +704,12 @@ enum bpf_object_state {
 	OBJ_LOADED,
 };
 
+/* Should match typedef in bpf_helpers.h */
+#define KMOD_NAME_LEN 64
+
+#define KMODS_BTF_UNLOADED 0UL
+#define KMODS_BTF_LOADED   1UL
+
 struct bpf_object {
 	char name[BPF_OBJ_NAME_LEN];
 	char license[64];
@@ -779,6 +786,14 @@ struct bpf_object {
 	char *token_path;
 	int token_fd;
 
+	/* kernel module BTFs to load, declared in ".kmod_btfs" ELF section */
+	struct {
+		char (*data)[KMOD_NAME_LEN];
+		size_t nr_names;
+		size_t nr_loaded;
+		struct hashmap *hashmap;
+	} *kmod_btfs;
+
 	char path[];
 };
 
@@ -901,6 +916,68 @@ bpf_object__init_prog(struct bpf_object *obj, struct bpf_program *prog,
 	return -ENOMEM;
 }
 
+static size_t mod_name_hash_fn(long key, void *ctx)
+{
+	return str_hash((char *)key);
+}
+
+static bool mod_name_equal_fn(long key1, long key2, void *ctx)
+{
+	return strcmp((char *)key1, (char *)key2) == 0;
+}
+
+static int
+bpf_object__collect_kmod_btf_names(struct bpf_object *obj, Elf_Data *sec_data,
+				   const char *sec_name)
+{
+	int module_cnt, i, err = 0;
+
+	if (sec_data->d_size % KMOD_NAME_LEN != 0) {
+		pr_warn("sec '%s': size %zu should be multiple of %d\n",
+			sec_name, sec_data->d_size, KMOD_NAME_LEN);
+		return -EINVAL;
+	}
+
+	module_cnt = sec_data->d_size / KMOD_NAME_LEN;
+	obj->kmod_btfs = calloc(1, sizeof(*obj->kmod_btfs));
+	if (!obj->kmod_btfs)
+		return -ENOMEM;
+
+	obj->kmod_btfs->data = calloc(module_cnt, KMOD_NAME_LEN);
+	if (!obj->kmod_btfs->data)
+		goto err_out;
+	memcpy(obj->kmod_btfs->data, sec_data->d_buf, sec_data->d_size);
+
+	obj->kmod_btfs->hashmap = hashmap__new(mod_name_hash_fn,
+					       mod_name_equal_fn, NULL);
+	if (IS_ERR(obj->kmod_btfs->hashmap)) {
+		err = PTR_ERR(obj->kmod_btfs->hashmap);
+		goto err_out;
+	}
+
+	for (i = 0; i < module_cnt; i++) {
+		obj->kmod_btfs->data[i][KMOD_NAME_LEN - 1] = '\0';
+		if (hashmap__find(obj->kmod_btfs->hashmap,
+				  obj->kmod_btfs->data[i], NULL)) {
+			pr_warn("sec '%s': ignored duplicate module '%s'\n",
+				sec_name, obj->kmod_btfs->data[i]);
+			continue;
+		}
+		err = hashmap__set(obj->kmod_btfs->hashmap, obj->kmod_btfs->data[i],
+				   KMODS_BTF_UNLOADED, NULL, NULL);
+		if (err)
+			goto err_out;
+		obj->kmod_btfs->nr_names++;
+	}
+	return 0;
+
+err_out:
+	hashmap__free(obj->kmod_btfs->hashmap);
+	zfree(&obj->kmod_btfs->data);
+	zfree(&obj->kmod_btfs);
+	return err;
+}
+
 static int
 bpf_object__add_programs(struct bpf_object *obj, Elf_Data *sec_data,
 			 const char *sec_name, int sec_idx)
@@ -4034,6 +4111,10 @@ static int bpf_object__elf_collect(struct bpf_object *obj)
 				memcpy(obj->jumptables_data, data->d_buf, data->d_size);
 				obj->jumptables_data_sz = data->d_size;
 				obj->efile.jumptables_data_shndx = idx;
+			} else if (strcmp(name, KMODS_BTFS_SEC) == 0) {
+				err = bpf_object__collect_kmod_btf_names(obj, data, name);
+				if (err)
+					return err;
 			} else {
 				pr_info("elf: skipping unrecognized data section(%d) %s\n",
 					idx, name);
@@ -5803,6 +5884,21 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand,
 	return 0;
 }
 
+static bool is_kmod_btf_needed(struct bpf_object *obj, const char *name)
+{
+	uintptr_t val;
+
+	if (!hashmap__find(obj->kmod_btfs->hashmap, name, &val))
+		return false;
+
+	if (val == KMODS_BTF_LOADED)
+		return false;
+
+	hashmap__set(obj->kmod_btfs->hashmap, name, KMODS_BTF_LOADED, NULL, NULL);
+	obj->kmod_btfs->nr_loaded++;
+	return true;
+}
+
 static int load_module_btfs(struct bpf_object *obj)
 {
 	struct bpf_btf_info info;
@@ -5867,6 +5963,12 @@ static int load_module_btfs(struct bpf_object *obj)
 			continue;
 		}
 
+		if (obj->kmod_btfs && obj->kmod_btfs->hashmap &&
+		    !is_kmod_btf_needed(obj, name)) {
+			close(fd);
+			continue;
+		}
+
 		btf = btf_get_from_fd(fd, obj->btf_vmlinux);
 		err = libbpf_get_error(btf);
 		if (err) {
@@ -5891,6 +5993,10 @@ static int load_module_btfs(struct bpf_object *obj)
 			break;
 		}
 		obj->btf_module_cnt++;
+
+		if (obj->kmod_btfs &&
+		    obj->kmod_btfs->nr_names == obj->kmod_btfs->nr_loaded)
+			break;
 	}
 
 	if (err) {
@@ -9030,6 +9136,12 @@ static void bpf_object_cleanup_btf(struct bpf_object *obj)
 	/* clean up vmlinux BTF */
 	btf__free(obj->btf_vmlinux);
 	obj->btf_vmlinux = NULL;
+
+	if (obj->kmod_btfs) {
+		hashmap__free(obj->kmod_btfs->hashmap);
+		zfree(&obj->kmod_btfs->data);
+		zfree(&obj->kmod_btfs);
+	}
 }
 
 static void bpf_object_post_load_cleanup(struct bpf_object *obj)
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading
  2026-08-06  4:20 [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Fuyu Zhao
  2026-08-06  4:20 ` [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao
@ 2026-08-06  4:20 ` Fuyu Zhao
  2026-08-06  4:29   ` sashiko-bot
  2026-08-07 22:18 ` [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Andrii Nakryiko
  2 siblings, 1 reply; 11+ messages in thread
From: Fuyu Zhao @ 2026-08-06  4:20 UTC (permalink / raw)
  To: bpf
  Cc: Fuyu Zhao, Andrii Nakryiko, Eduard Zingerman, Ihor Solodrai,
	Alexei Starovoitov, Daniel Borkmann, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, Shuah Khan, open list,
	open list:KERNEL SELFTEST FRAMEWORK

Add test cases to verify the new ".kmod_btfs" section logic in libbpf.
The added test cases cover three main scenarios:

  - Valid module: targeting an existing kernel module BTF to ensure
    successful loading.
  - Non-existent module: targeting a fake or missing module, verifying
    that the process results in an expected failure.
  - Duplicates and unneeded: providing a mix of repeated and extra
    module names to ensure the parsing logic remains robust.

Signed-off-by: Fuyu Zhao <zhaofuyu@vivo.com>
---
 .../selftests/bpf/prog_tests/kmod_btfs.c      | 47 +++++++++++++++++++
 tools/testing/selftests/bpf/progs/kmod_btfs.c | 14 ++++++
 .../selftests/bpf/progs/kmod_btfs_mix.c       | 15 ++++++
 .../selftests/bpf/progs/kmod_btfs_nonexist.c  | 17 +++++++
 4 files changed, 93 insertions(+)
 create mode 100644 tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
 create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs.c
 create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_mix.c
 create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c

diff --git a/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
new file mode 100644
index 000000000000..0608f2809223
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
@@ -0,0 +1,47 @@
+// SPDX-License-Identifier: GPL-2.0
+#include <test_progs.h>
+#include "kmod_btfs.skel.h"
+#include "kmod_btfs_nonexist.skel.h"
+#include "kmod_btfs_mix.skel.h"
+
+static void kmod_btfs_pass(void)
+{
+	struct kmod_btfs *kmod_btfs_skel;
+
+	kmod_btfs_skel = kmod_btfs__open_and_load();
+	if (!ASSERT_OK_PTR(kmod_btfs_skel, "kmod_btfs__open_and_load"))
+		return;
+
+	kmod_btfs__destroy(kmod_btfs_skel);
+}
+
+static void kmod_btfs_nonexist(void)
+{
+	struct kmod_btfs_nonexist *kmod_btfs_nonexist_skel;
+
+	kmod_btfs_nonexist_skel = kmod_btfs_nonexist__open_and_load();
+	ASSERT_NULL(kmod_btfs_nonexist_skel, "kmod_btfs_nonexist__open_and_load");
+}
+
+static void kmod_btfs_mix(void)
+{
+	struct kmod_btfs_mix *kmod_btfs_mix_skel;
+
+	kmod_btfs_mix_skel = kmod_btfs_mix__open_and_load();
+	if (!ASSERT_OK_PTR(kmod_btfs_mix_skel, "kmod_btfs_mix__open_and_load"))
+		return;
+
+	kmod_btfs_mix__destroy(kmod_btfs_mix_skel);
+}
+
+void test_kmod_btfs(void)
+{
+	if (test__start_subtest("kmod_btfs_pass"))
+		kmod_btfs_pass();
+
+	if (test__start_subtest("kmod_btfs_nonexist"))
+		kmod_btfs_nonexist();
+
+	if (test__start_subtest("kmod_btfs_mix"))
+		kmod_btfs_mix();
+}
diff --git a/tools/testing/selftests/bpf/progs/kmod_btfs.c b/tools/testing/selftests/bpf/progs/kmod_btfs.c
new file mode 100644
index 000000000000..8b986bc2e9ff
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/kmod_btfs.c
@@ -0,0 +1,14 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+
+SEC("fexit/bpf_testmod_loop_test")
+int test_kmod_btfs(void *ctx)
+{
+	return 0;
+}
+
+DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod" };
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/kmod_btfs_mix.c b/tools/testing/selftests/bpf/progs/kmod_btfs_mix.c
new file mode 100644
index 000000000000..f445cf56ab16
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/kmod_btfs_mix.c
@@ -0,0 +1,15 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+
+SEC("fexit/bpf_testmod_loop_test")
+int test_kmod_btfs_mix(void *ctx)
+{
+	return 0;
+}
+
+/* mix of duplicated and unneeded modules */
+DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod", "bpf_testmod", "bpf_test_no_cfi" };
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c b/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
new file mode 100644
index 000000000000..431e3273821b
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
@@ -0,0 +1,17 @@
+// SPDX-License-Identifier: GPL-2.0
+
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+
+SEC("fexit/bpf_testmod_loop_test")
+int test_kmod_btfs_nonexist(void *ctx)
+{
+	return 0;
+}
+
+/* This should fail to load, because .kmod_btfs does not contain
+ * the needed module 'bpf_testmod'.
+ */
+DEFINE_KMOD_BTFS(_needed_kmods) = { "module_nonexist" };
+
+char _license[] SEC("license") = "GPL";
-- 
2.34.1


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading
  2026-08-06  4:20 ` [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao
@ 2026-08-06  4:29   ` sashiko-bot
  2026-08-06  8:39     ` Fuyu Zhao
  0 siblings, 1 reply; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  4:29 UTC (permalink / raw)
  To: Fuyu Zhao; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
- [Medium] The test `test_kmod_btfs` depends on the `bpf_testmod` kernel module being available, but does not check `env.has_testmod` before running.
- [Low] Multi-line comment does not follow BPF subsystem style guidelines.
--

--- Patch [2]: [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading ---
commit 35262af12350c47550b117d06e881e0de422cb5d
Author: Fuyu Zhao <zhaofuyu@vivo.com>

selftests/bpf: add tests for selective kmod BTF loading

This commit adds test cases to verify the new .kmod_btfs section logic in
libbpf. It covers scenarios with valid, non-existent, and duplicated module
BTF targets to ensure robust loading and parsing.

> diff --git a/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
[ ... ]
> +static void kmod_btfs_mix(void)
> +{
> +	struct kmod_btfs_mix *kmod_btfs_mix_skel;
> +
> +	kmod_btfs_mix_skel = kmod_btfs_mix__open_and_load();
> +	if (!ASSERT_OK_PTR(kmod_btfs_mix_skel, "kmod_btfs_mix__open_and_load"))
> +		return;
> +
> +	kmod_btfs_mix__destroy(kmod_btfs_mix_skel);
> +}
> +
> +void test_kmod_btfs(void)
> +{
> +	if (test__start_subtest("kmod_btfs_pass"))

[Severity: Medium]
Since this test depends on bpf_testmod being available, should we check
env.has_testmod at the start of the test and skip it if not found?

Without it, running the selftests on a system where the test module is not
built or fails to load might cause erroneous test failures instead of being
gracefully skipped.

> +		kmod_btfs_pass();
> +
> +	if (test__start_subtest("kmod_btfs_nonexist"))
> +		kmod_btfs_nonexist();
> +
> +	if (test__start_subtest("kmod_btfs_mix"))
> +		kmod_btfs_mix();
> +}

> diff --git a/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c b/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
[ ... ]
> +SEC("fexit/bpf_testmod_loop_test")
> +int test_kmod_btfs_nonexist(void *ctx)
> +{
> +	return 0;
> +}
> +
> +/* This should fail to load, because .kmod_btfs does not contain
> + * the needed module 'bpf_testmod'.
> + */

[Severity: Low]
This isn't a bug, but does this multi-line comment follow the BPF
subsystem style guidelines?

The BPF guidelines usually require the opening /* to be on its own line.

> +DEFINE_KMOD_BTFS(_needed_kmods) = { "module_nonexist" };
> +
> +char _license[] SEC("license") = "GPL";

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260806042042.3239428-1-zhaofuyu@vivo.com?part=2

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section
  2026-08-06  4:20 ` [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao
@ 2026-08-06  4:33   ` sashiko-bot
  2026-08-06  8:38     ` Fuyu Zhao
  0 siblings, 1 reply; 11+ messages in thread
From: sashiko-bot @ 2026-08-06  4:33 UTC (permalink / raw)
  To: Fuyu Zhao; +Cc: bpf

Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [Medium] Transient stack pointer overwrites persistent hashmap key in is_kmod_btf_needed(), breaking hashmap integrity on bucket collisions.
- [Medium] Memory allocation failure for `obj->kmod_btfs->data` silently returns success (0), masking the error and corrupting intended behavior.
- [Medium] Processing multiple `.kmod_btfs` sections overwrites previous allocations without freeing them.
--

--- Patch [1]: [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section ---
commit 5306ac18160e3a8c2a0f3dd2eda202169f998df6
Author: Fuyu Zhao <zhaofuyu@vivo.com>

libbpf: support selective kernel module BTF loading via .kmod_btfs section

Add support for a new ELF section ".kmod_btfs" that allows BPF programs
to declare which kernel modules need BTF loading. This avoids loading
all module BTFs and speeds up program load when only a subset of modules
is needed.

> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 514e4e9daa825..5cefe82e4a679 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c

[ ... ]

> @@ -901,6 +916,68 @@ bpf_object__init_prog(struct bpf_object *obj, struct bpf_program *prog,
>  	return -ENOMEM;
>  }
>  
> +static size_t mod_name_hash_fn(long key, void *ctx)
> +{
> +	return str_hash((char *)key);
> +}
> +
> +static bool mod_name_equal_fn(long key1, long key2, void *ctx)
> +{
> +	return strcmp((char *)key1, (char *)key2) == 0;
> +}
> +
> +static int
> +bpf_object__collect_kmod_btf_names(struct bpf_object *obj, Elf_Data *sec_data,
> +				   const char *sec_name)
> +{
> +	int module_cnt, i, err = 0;
> +
> +	if (sec_data->d_size % KMOD_NAME_LEN != 0) {
> +		pr_warn("sec '%s': size %zu should be multiple of %d\n",
> +			sec_name, sec_data->d_size, KMOD_NAME_LEN);
> +		return -EINVAL;
> +	}
> +
> +	module_cnt = sec_data->d_size / KMOD_NAME_LEN;
> +	obj->kmod_btfs = calloc(1, sizeof(*obj->kmod_btfs));

[Severity: Medium]
If a crafted ELF file contains multiple .kmod_btfs sections, could this calloc
overwrite a previously allocated obj->kmod_btfs and cause a memory leak of
the hashmap and data arrays?

> +	if (!obj->kmod_btfs)
> +		return -ENOMEM;
> +
> +	obj->kmod_btfs->data = calloc(module_cnt, KMOD_NAME_LEN);
> +	if (!obj->kmod_btfs->data)
> +		goto err_out;

[Severity: Medium]
Does this error path silently return success?

Because err is initialized to 0, this goto err_out will return 0 instead of
-ENOMEM. This causes obj->kmod_btfs to be freed in the cleanup path while
the function signals success, making load_module_btfs() fall back to loading
all module BTFs.

> +	memcpy(obj->kmod_btfs->data, sec_data->d_buf, sec_data->d_size);

[ ... ]

> @@ -5803,6 +5884,21 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand,
>  	return 0;
>  }
>  
> +static bool is_kmod_btf_needed(struct bpf_object *obj, const char *name)
> +{
> +	uintptr_t val;
> +
> +	if (!hashmap__find(obj->kmod_btfs->hashmap, name, &val))
> +		return false;
> +
> +	if (val == KMODS_BTF_LOADED)
> +		return false;
> +
> +	hashmap__set(obj->kmod_btfs->hashmap, name, KMODS_BTF_LOADED, NULL, NULL);

[Severity: Medium]
Can this hashmap__set() corrupt the hashmap by storing a transient stack
pointer as the key?

Looking at load_module_btfs(), name is a local stack array passed to
is_kmod_btf_needed() on every iteration:

load_module_btfs() {
    char name[64];
    ...
        if (obj->kmod_btfs && obj->kmod_btfs->hashmap &&
            !is_kmod_btf_needed(obj, name)) {
    ...
}

Since hashmap__set() only stores the pointer address, all entries will
share the same pointer to the local name array. If a bucket collision
occurs, strcmp(key1, key2) will evaluate to 0 since both point to the
same stack address, falsely matching existing entries and skipping the
requested module.

> +	obj->kmod_btfs->nr_loaded++;
> +	return true;
> +}
> +

-- 
Sashiko AI review · https://sashiko.dev/#/patchset/20260806042042.3239428-1-zhaofuyu@vivo.com?part=1

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section
  2026-08-06  4:33   ` sashiko-bot
@ 2026-08-06  8:38     ` Fuyu Zhao
  0 siblings, 0 replies; 11+ messages in thread
From: Fuyu Zhao @ 2026-08-06  8:38 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: bpf



On 8/6/2026 12:33 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
> - [Medium] Transient stack pointer overwrites persistent hashmap key in is_kmod_btf_needed(), breaking hashmap integrity on bucket collisions.
> - [Medium] Memory allocation failure for `obj->kmod_btfs->data` silently returns success (0), masking the error and corrupting intended behavior.
> - [Medium] Processing multiple `.kmod_btfs` sections overwrites previous allocations without freeing them.
> --
> 
> --- Patch [1]: [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section ---
> commit 5306ac18160e3a8c2a0f3dd2eda202169f998df6
> Author: Fuyu Zhao <zhaofuyu@vivo.com>
> 
> libbpf: support selective kernel module BTF loading via .kmod_btfs section
> 
> Add support for a new ELF section ".kmod_btfs" that allows BPF programs
> to declare which kernel modules need BTF loading. This avoids loading
> all module BTFs and speeds up program load when only a subset of modules
> is needed.
> 
>> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
>> index 514e4e9daa825..5cefe82e4a679 100644
>> --- a/tools/lib/bpf/libbpf.c
>> +++ b/tools/lib/bpf/libbpf.c
> 
> [ ... ]
> 
>> @@ -901,6 +916,68 @@ bpf_object__init_prog(struct bpf_object *obj, struct bpf_program *prog,
>>  	return -ENOMEM;
>>  }
>>  
>> +static size_t mod_name_hash_fn(long key, void *ctx)
>> +{
>> +	return str_hash((char *)key);
>> +}
>> +
>> +static bool mod_name_equal_fn(long key1, long key2, void *ctx)
>> +{
>> +	return strcmp((char *)key1, (char *)key2) == 0;
>> +}
>> +
>> +static int
>> +bpf_object__collect_kmod_btf_names(struct bpf_object *obj, Elf_Data *sec_data,
>> +				   const char *sec_name)
>> +{
>> +	int module_cnt, i, err = 0;
>> +
>> +	if (sec_data->d_size % KMOD_NAME_LEN != 0) {
>> +		pr_warn("sec '%s': size %zu should be multiple of %d\n",
>> +			sec_name, sec_data->d_size, KMOD_NAME_LEN);
>> +		return -EINVAL;
>> +	}
>> +
>> +	module_cnt = sec_data->d_size / KMOD_NAME_LEN;
>> +	obj->kmod_btfs = calloc(1, sizeof(*obj->kmod_btfs));
> 
> [Severity: Medium]
> If a crafted ELF file contains multiple .kmod_btfs sections, could this calloc
> overwrite a previously allocated obj->kmod_btfs and cause a memory leak of
> the hashmap and data arrays?
> 

Good catch, thanks! I missed the sanity check for duplicate sections.
I will add a check `if (obj->kmod_btfs) return -EEXIST;` to prevent duplicate
section parsing and fix this potential memory leak in v2.

>> +	if (!obj->kmod_btfs)
>> +		return -ENOMEM;
>> +
>> +	obj->kmod_btfs->data = calloc(module_cnt, KMOD_NAME_LEN);
>> +	if (!obj->kmod_btfs->data)
>> +		goto err_out;
> 
> [Severity: Medium]
> Does this error path silently return success?
> 
> Because err is initialized to 0, this goto err_out will return 0 instead of
> -ENOMEM. This causes obj->kmod_btfs to be freed in the cleanup path while
> the function signals success, making load_module_btfs() fall back to loading
> all module BTFs.
> 

My apologies for this careless oversight in error handling. Leaving `err` as 0
here indeed creates a dangerous silent error.

I will assign `err = -ENOMEM;` right before jumping to `err_out` and thoroughly
re-check every error path in the patch series for v2. Thanks again

>> +	memcpy(obj->kmod_btfs->data, sec_data->d_buf, sec_data->d_size);
> 
> [ ... ]
> 
>> @@ -5803,6 +5884,21 @@ int bpf_core_add_cands(struct bpf_core_cand *local_cand,
>>  	return 0;
>>  }
>>  
>> +static bool is_kmod_btf_needed(struct bpf_object *obj, const char *name)
>> +{
>> +	uintptr_t val;
>> +
>> +	if (!hashmap__find(obj->kmod_btfs->hashmap, name, &val))
>> +		return false;
>> +
>> +	if (val == KMODS_BTF_LOADED)
>> +		return false;
>> +
>> +	hashmap__set(obj->kmod_btfs->hashmap, name, KMODS_BTF_LOADED, NULL, NULL);
> 
> [Severity: Medium]
> Can this hashmap__set() corrupt the hashmap by storing a transient stack
> pointer as the key?
> 
> Looking at load_module_btfs(), name is a local stack array passed to
> is_kmod_btf_needed() on every iteration:
> 
> load_module_btfs() {
>     char name[64];
>     ...
>         if (obj->kmod_btfs && obj->kmod_btfs->hashmap &&
>             !is_kmod_btf_needed(obj, name)) {
>     ...
> }
> 
> Since hashmap__set() only stores the pointer address, all entries will
> share the same pointer to the local name array. If a bucket collision
> occurs, strcmp(key1, key2) will evaluate to 0 since both point to the
> same stack address, falsely matching existing entries and skipping the
> requested module.
> 

This is a valid point regarding pointer lifetime.

In v2, I will update `is_kmod_btf_needed()` to store persistent string
pointers from the pre-parsed ELF section instead of the stack buffer.

Thanks for pointing this out.

>> +	obj->kmod_btfs->nr_loaded++;
>> +	return true;
>> +}
>> +
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading
  2026-08-06  4:29   ` sashiko-bot
@ 2026-08-06  8:39     ` Fuyu Zhao
  0 siblings, 0 replies; 11+ messages in thread
From: Fuyu Zhao @ 2026-08-06  8:39 UTC (permalink / raw)
  To: sashiko-reviews; +Cc: bpf



On 8/6/2026 12:29 PM, sashiko-bot@kernel.org wrote:
> Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider:
> - [Medium] The test `test_kmod_btfs` depends on the `bpf_testmod` kernel module being available, but does not check `env.has_testmod` before running.
> - [Low] Multi-line comment does not follow BPF subsystem style guidelines.
> --
> 
> --- Patch [2]: [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading ---
> commit 35262af12350c47550b117d06e881e0de422cb5d
> Author: Fuyu Zhao <zhaofuyu@vivo.com>
> 
> selftests/bpf: add tests for selective kmod BTF loading
> 
> This commit adds test cases to verify the new .kmod_btfs section logic in
> libbpf. It covers scenarios with valid, non-existent, and duplicated module
> BTF targets to ensure robust loading and parsing.
> 
>> diff --git a/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
> [ ... ]
>> +static void kmod_btfs_mix(void)
>> +{
>> +	struct kmod_btfs_mix *kmod_btfs_mix_skel;
>> +
>> +	kmod_btfs_mix_skel = kmod_btfs_mix__open_and_load();
>> +	if (!ASSERT_OK_PTR(kmod_btfs_mix_skel, "kmod_btfs_mix__open_and_load"))
>> +		return;
>> +
>> +	kmod_btfs_mix__destroy(kmod_btfs_mix_skel);
>> +}
>> +
>> +void test_kmod_btfs(void)
>> +{
>> +	if (test__start_subtest("kmod_btfs_pass"))
> 
> [Severity: Medium]
> Since this test depends on bpf_testmod being available, should we check
> env.has_testmod at the start of the test and skip it if not found?
> 
> Without it, running the selftests on a system where the test module is not
> built or fails to load might cause erroneous test failures instead of being
> gracefully skipped.
> 

Good point. I will add an `if (!env.has_testmod)` check in v2 to gracefully
skip the test when `bpf_testmod` is unavailable.

Thanks for the feedback.

>> +		kmod_btfs_pass();
>> +
>> +	if (test__start_subtest("kmod_btfs_nonexist"))
>> +		kmod_btfs_nonexist();
>> +
>> +	if (test__start_subtest("kmod_btfs_mix"))
>> +		kmod_btfs_mix();
>> +}
> 
>> diff --git a/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c b/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
> [ ... ]
>> +SEC("fexit/bpf_testmod_loop_test")
>> +int test_kmod_btfs_nonexist(void *ctx)
>> +{
>> +	return 0;
>> +}
>> +
>> +/* This should fail to load, because .kmod_btfs does not contain
>> + * the needed module 'bpf_testmod'.
>> + */
> 
> [Severity: Low]
> This isn't a bug, but does this multi-line comment follow the BPF
> subsystem style guidelines?
> 
> The BPF guidelines usually require the opening /* to be on its own line.
> 

Thanks for the feedback. I will update the comment style in v2.

>> +DEFINE_KMOD_BTFS(_needed_kmods) = { "module_nonexist" };
>> +
>> +char _license[] SEC("license") = "GPL";
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs
  2026-08-06  4:20 [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Fuyu Zhao
  2026-08-06  4:20 ` [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao
  2026-08-06  4:20 ` [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao
@ 2026-08-07 22:18 ` Andrii Nakryiko
  2026-08-10  6:20   ` Fuyu Zhao
  2 siblings, 1 reply; 11+ messages in thread
From: Andrii Nakryiko @ 2026-08-07 22:18 UTC (permalink / raw)
  To: Fuyu Zhao; +Cc: bpf

On Wed, Aug 5, 2026 at 9:21 PM Fuyu Zhao <zhaofuyu@vivo.com> wrote:
>
> Currently, during BPF object loading, load_module_btfs() unconditionally
> iterates over all loaded kernel modules and loads their BTFs. This
> introduces unnecessary overhead when a BPF program only needs a specific,
> small subset of modules. In environments with hundreds of modules,
> loading all module measurably increases the loading time.
>
> This series introduces a ".kmod_btfs" ELF section, allowing BPF programs
> to declare the modules that need BTF loading. libbpf parses this
> section, collects the module names, and skips loading BTFs for any
> module not in the list, thereby reducing overhead. It also stops the
> iteration early once all declared modules are found.
>
> Usage example:
>
>   DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod" };
>
> Performance impact (<skel>__open_and_load() time):
>
>   Modules loaded | Without .kmod_btfs | With .kmod_btfs | Speedup
>   ---------------|--------------------|-----------------|--------
>   1              | 35.0 ms            | 35.0 ms         | Baseline
>   10             | 36.5 ms            | 35.1 ms         | +3.8%
>   100            | 46.2 ms            | 35.9 ms         | +22.3%
>   300            | 65.2 ms            | 38.0 ms         | +41.7%

First, is 30ms start up overhead really such a big deal when it comes
to one-time thing that sets up a bunch of BPF programs? Can you
elaborate on the use case you have that actually is harmed by this
libbpf behavior?

>
> Fuyu Zhao (2):
>   libbpf: support selective kernel module BTF loading via .kmod_btfs
>     section
>   selftests/bpf: add tests for selective kmod BTF loading
>
>  tools/lib/bpf/bpf_helpers.h                   |  14 +++
>  tools/lib/bpf/libbpf.c                        | 112 ++++++++++++++++++
>  .../selftests/bpf/prog_tests/kmod_btfs.c      |  47 ++++++++
>  tools/testing/selftests/bpf/progs/kmod_btfs.c |  14 +++
>  .../selftests/bpf/progs/kmod_btfs_mix.c       |  15 +++
>  .../selftests/bpf/progs/kmod_btfs_nonexist.c  |  17 +++
>  6 files changed, 219 insertions(+)
>  create mode 100644 tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs.c
>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_mix.c
>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
>
> --
> 2.34.1
>
>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs
  2026-08-07 22:18 ` [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Andrii Nakryiko
@ 2026-08-10  6:20   ` Fuyu Zhao
  2026-08-10 12:27     ` Alan Maguire
  0 siblings, 1 reply; 11+ messages in thread
From: Fuyu Zhao @ 2026-08-10  6:20 UTC (permalink / raw)
  To: Andrii Nakryiko; +Cc: bpf



On 8/8/2026 6:18 AM, Andrii Nakryiko wrote:
> On Wed, Aug 5, 2026 at 9:21 PM Fuyu Zhao <zhaofuyu@vivo.com> wrote:
>>
>> Currently, during BPF object loading, load_module_btfs() unconditionally
>> iterates over all loaded kernel modules and loads their BTFs. This
>> introduces unnecessary overhead when a BPF program only needs a specific,
>> small subset of modules. In environments with hundreds of modules,
>> loading all module measurably increases the loading time.
>>
>> This series introduces a ".kmod_btfs" ELF section, allowing BPF programs
>> to declare the modules that need BTF loading. libbpf parses this
>> section, collects the module names, and skips loading BTFs for any
>> module not in the list, thereby reducing overhead. It also stops the
>> iteration early once all declared modules are found.
>>
>> Usage example:
>>
>>   DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod" };
>>
>> Performance impact (<skel>__open_and_load() time):
>>
>>   Modules loaded | Without .kmod_btfs | With .kmod_btfs | Speedup
>>   ---------------|--------------------|-----------------|--------
>>   1              | 35.0 ms            | 35.0 ms         | Baseline
>>   10             | 36.5 ms            | 35.1 ms         | +3.8%
>>   100            | 46.2 ms            | 35.9 ms         | +22.3%
>>   300            | 65.2 ms            | 38.0 ms         | +41.7%
> 
> First, is 30ms start up overhead really such a big deal when it comes
> to one-time thing that sets up a bunch of BPF programs? Can you
> elaborate on the use case you have that actually is harmed by this
> libbpf behavior?
> 

Hi Andrii,

Thanks for the feedback, and sorry for the delayed response.

To clarify the use case, we use `sched_ext` on Android mobile platforms
and dynamically switch schedulers for performance-sensitive scenarios,
such as gaming workloads. The BPF programs are loaded on demand when a
scheduler switch is required, rather than being initialized once during
system startup. Since the scheduler switch happens on the critical path
of user interaction, the setup latency directly affects the perceived
responsiveness of the system.

On Android devices, the impact of `load_module_btfs()` is even more
pronounced in our use case. In our testing, loading BTFs for all modules
takes more than 300 ms (with 93 module BTFs), which accounts for around
69% of the total BPF loading time. Such a delay during the scheduler
transition can cause visible frame drops in latency-sensitive workloads.

We also tried preloading the BPF programs. However, this does not fit
well with our use case. Mobile devices have tighter memory constraints,
and we avoid keeping unused BPF programs resident when they are not
needed. Since different workloads may require different schedulers,
preloading all possible BPF programs would introduce unnecessary memory
overhead.

By allowing a BPF program to explicitly declare the required kernel
modules through `.kmod_btfs`, libbpf can avoid loading unrelated module
BTFs and significantly reduce the loading latency without increasing the
memory footprint of inactive features.

Hope this clarifies the motivation behind this change. Thanks again for
the feedback.

Best regards,
Fuyu

>>
>> Fuyu Zhao (2):
>>   libbpf: support selective kernel module BTF loading via .kmod_btfs
>>     section
>>   selftests/bpf: add tests for selective kmod BTF loading
>>
>>  tools/lib/bpf/bpf_helpers.h                   |  14 +++
>>  tools/lib/bpf/libbpf.c                        | 112 ++++++++++++++++++
>>  .../selftests/bpf/prog_tests/kmod_btfs.c      |  47 ++++++++
>>  tools/testing/selftests/bpf/progs/kmod_btfs.c |  14 +++
>>  .../selftests/bpf/progs/kmod_btfs_mix.c       |  15 +++
>>  .../selftests/bpf/progs/kmod_btfs_nonexist.c  |  17 +++
>>  6 files changed, 219 insertions(+)
>>  create mode 100644 tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs.c
>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_mix.c
>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
>>
>> --
>> 2.34.1
>>
>>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs
  2026-08-10  6:20   ` Fuyu Zhao
@ 2026-08-10 12:27     ` Alan Maguire
  2026-08-11  3:41       ` Fuyu Zhao
  0 siblings, 1 reply; 11+ messages in thread
From: Alan Maguire @ 2026-08-10 12:27 UTC (permalink / raw)
  To: Fuyu Zhao, Andrii Nakryiko; +Cc: bpf

On 10/08/2026 07:20, Fuyu Zhao wrote:
> 
> 
> On 8/8/2026 6:18 AM, Andrii Nakryiko wrote:
>> On Wed, Aug 5, 2026 at 9:21 PM Fuyu Zhao <zhaofuyu@vivo.com> wrote:
>>>
>>> Currently, during BPF object loading, load_module_btfs() unconditionally
>>> iterates over all loaded kernel modules and loads their BTFs. This
>>> introduces unnecessary overhead when a BPF program only needs a specific,
>>> small subset of modules. In environments with hundreds of modules,
>>> loading all module measurably increases the loading time.
>>>
>>> This series introduces a ".kmod_btfs" ELF section, allowing BPF programs
>>> to declare the modules that need BTF loading. libbpf parses this
>>> section, collects the module names, and skips loading BTFs for any
>>> module not in the list, thereby reducing overhead. It also stops the
>>> iteration early once all declared modules are found.
>>>
>>> Usage example:
>>>
>>>   DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod" };
>>>
>>> Performance impact (<skel>__open_and_load() time):
>>>
>>>   Modules loaded | Without .kmod_btfs | With .kmod_btfs | Speedup
>>>   ---------------|--------------------|-----------------|--------
>>>   1              | 35.0 ms            | 35.0 ms         | Baseline
>>>   10             | 36.5 ms            | 35.1 ms         | +3.8%
>>>   100            | 46.2 ms            | 35.9 ms         | +22.3%
>>>   300            | 65.2 ms            | 38.0 ms         | +41.7%
>>
>> First, is 30ms start up overhead really such a big deal when it comes
>> to one-time thing that sets up a bunch of BPF programs? Can you
>> elaborate on the use case you have that actually is harmed by this
>> libbpf behavior?
>>
> 
> Hi Andrii,
> 
> Thanks for the feedback, and sorry for the delayed response.
> 
> To clarify the use case, we use `sched_ext` on Android mobile platforms
> and dynamically switch schedulers for performance-sensitive scenarios,
> such as gaming workloads. The BPF programs are loaded on demand when a
> scheduler switch is required, rather than being initialized once during
> system startup. Since the scheduler switch happens on the critical path
> of user interaction, the setup latency directly affects the perceived
> responsiveness of the system.
> 
> On Android devices, the impact of `load_module_btfs()` is even more
> pronounced in our use case. In our testing, loading BTFs for all modules
> takes more than 300 ms (with 93 module BTFs), which accounts for around
> 69% of the total BPF loading time. Such a delay during the scheduler
> transition can cause visible frame drops in latency-sensitive workloads.
> 
> We also tried preloading the BPF programs. However, this does not fit
> well with our use case. Mobile devices have tighter memory constraints,
> and we avoid keeping unused BPF programs resident when they are not
> needed. Since different workloads may require different schedulers,
> preloading all possible BPF programs would introduce unnecessary memory
> overhead.
> 
> By allowing a BPF program to explicitly declare the required kernel
> modules through `.kmod_btfs`, libbpf can avoid loading unrelated module
> BTFs and significantly reduce the loading latency without increasing the
> memory footprint of inactive features.
>

the approach of having an extra section .kmod_btfs feels a bit unwieldy;
we already support kernel/module qualification in autoload section names
via

SEC("fentry/mymod:foo")
SEC("fexit/vmlinux:bar")

Couldn't you use that instead to inform selective lookup in find_kernel_btf_id()?

 
> Hope this clarifies the motivation behind this change. Thanks again for
> the feedback.
> 
> Best regards,
> Fuyu
> 
>>>
>>> Fuyu Zhao (2):
>>>   libbpf: support selective kernel module BTF loading via .kmod_btfs
>>>     section
>>>   selftests/bpf: add tests for selective kmod BTF loading
>>>
>>>  tools/lib/bpf/bpf_helpers.h                   |  14 +++
>>>  tools/lib/bpf/libbpf.c                        | 112 ++++++++++++++++++
>>>  .../selftests/bpf/prog_tests/kmod_btfs.c      |  47 ++++++++
>>>  tools/testing/selftests/bpf/progs/kmod_btfs.c |  14 +++
>>>  .../selftests/bpf/progs/kmod_btfs_mix.c       |  15 +++
>>>  .../selftests/bpf/progs/kmod_btfs_nonexist.c  |  17 +++
>>>  6 files changed, 219 insertions(+)
>>>  create mode 100644 tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
>>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs.c
>>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_mix.c
>>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
>>>
>>> --
>>> 2.34.1
>>>
>>>
> 
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs
  2026-08-10 12:27     ` Alan Maguire
@ 2026-08-11  3:41       ` Fuyu Zhao
  0 siblings, 0 replies; 11+ messages in thread
From: Fuyu Zhao @ 2026-08-11  3:41 UTC (permalink / raw)
  To: Alan Maguire, Andrii Nakryiko; +Cc: bpf



On 8/10/2026 8:27 PM, Alan Maguire wrote:
> On 10/08/2026 07:20, Fuyu Zhao wrote:
>>
>>
>> On 8/8/2026 6:18 AM, Andrii Nakryiko wrote:
>>> On Wed, Aug 5, 2026 at 9:21 PM Fuyu Zhao <zhaofuyu@vivo.com> wrote:
>>>>
>>>> Currently, during BPF object loading, load_module_btfs() unconditionally
>>>> iterates over all loaded kernel modules and loads their BTFs. This
>>>> introduces unnecessary overhead when a BPF program only needs a specific,
>>>> small subset of modules. In environments with hundreds of modules,
>>>> loading all module measurably increases the loading time.
>>>>
>>>> This series introduces a ".kmod_btfs" ELF section, allowing BPF programs
>>>> to declare the modules that need BTF loading. libbpf parses this
>>>> section, collects the module names, and skips loading BTFs for any
>>>> module not in the list, thereby reducing overhead. It also stops the
>>>> iteration early once all declared modules are found.
>>>>
>>>> Usage example:
>>>>
>>>>   DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod" };
>>>>
>>>> Performance impact (<skel>__open_and_load() time):
>>>>
>>>>   Modules loaded | Without .kmod_btfs | With .kmod_btfs | Speedup
>>>>   ---------------|--------------------|-----------------|--------
>>>>   1              | 35.0 ms            | 35.0 ms         | Baseline
>>>>   10             | 36.5 ms            | 35.1 ms         | +3.8%
>>>>   100            | 46.2 ms            | 35.9 ms         | +22.3%
>>>>   300            | 65.2 ms            | 38.0 ms         | +41.7%
>>>
>>> First, is 30ms start up overhead really such a big deal when it comes
>>> to one-time thing that sets up a bunch of BPF programs? Can you
>>> elaborate on the use case you have that actually is harmed by this
>>> libbpf behavior?
>>>
>>
>> Hi Andrii,
>>
>> Thanks for the feedback, and sorry for the delayed response.
>>
>> To clarify the use case, we use `sched_ext` on Android mobile platforms
>> and dynamically switch schedulers for performance-sensitive scenarios,
>> such as gaming workloads. The BPF programs are loaded on demand when a
>> scheduler switch is required, rather than being initialized once during
>> system startup. Since the scheduler switch happens on the critical path
>> of user interaction, the setup latency directly affects the perceived
>> responsiveness of the system.
>>
>> On Android devices, the impact of `load_module_btfs()` is even more
>> pronounced in our use case. In our testing, loading BTFs for all modules
>> takes more than 300 ms (with 93 module BTFs), which accounts for around
>> 69% of the total BPF loading time. Such a delay during the scheduler
>> transition can cause visible frame drops in latency-sensitive workloads.
>>
>> We also tried preloading the BPF programs. However, this does not fit
>> well with our use case. Mobile devices have tighter memory constraints,
>> and we avoid keeping unused BPF programs resident when they are not
>> needed. Since different workloads may require different schedulers,
>> preloading all possible BPF programs would introduce unnecessary memory
>> overhead.
>>
>> By allowing a BPF program to explicitly declare the required kernel
>> modules through `.kmod_btfs`, libbpf can avoid loading unrelated module
>> BTFs and significantly reduce the loading latency without increasing the
>> memory footprint of inactive features.
>>
> 
> the approach of having an extra section .kmod_btfs feels a bit unwieldy;
> we already support kernel/module qualification in autoload section names
> via
> 
> SEC("fentry/mymod:foo")
> SEC("fexit/vmlinux:bar")
> 
> Couldn't you use that instead to inform selective lookup in find_kernel_btf_id()?
> 
>  

Hi Alan,

Thanks for the feedback.

The existing module qualification in autoload section names allows
`find_kernel_btf_id()` to search for BTF IDs in a specific module BTF
after `load_module_btfs()` has completed. However, it does not reduce
the number of module BTFs that `load_module_btfs()` needs to load.

Also, using SEC() module qualification is only applicable to BPF program
types where the module name can be specified in SEC(). It does not apply
to program types such as `struct_ops`, where the module name cannot be
represented by SEC().

The purpose of `.kmod_btfs` is to let BPF programs explicitly declare
which module BTFs `load_module_btfs()` should load, so unrelated modules
can be skipped. Since `.kmod_btfs` is an optional ELF section, it does
not affect existing BPF programs unless they explicitly provide this
information.

Thanks,
Fuyu

>> Hope this clarifies the motivation behind this change. Thanks again for
>> the feedback.
>>
>> Best regards,
>> Fuyu
>>
>>>>
>>>> Fuyu Zhao (2):
>>>>   libbpf: support selective kernel module BTF loading via .kmod_btfs
>>>>     section
>>>>   selftests/bpf: add tests for selective kmod BTF loading
>>>>
>>>>  tools/lib/bpf/bpf_helpers.h                   |  14 +++
>>>>  tools/lib/bpf/libbpf.c                        | 112 ++++++++++++++++++
>>>>  .../selftests/bpf/prog_tests/kmod_btfs.c      |  47 ++++++++
>>>>  tools/testing/selftests/bpf/progs/kmod_btfs.c |  14 +++
>>>>  .../selftests/bpf/progs/kmod_btfs_mix.c       |  15 +++
>>>>  .../selftests/bpf/progs/kmod_btfs_nonexist.c  |  17 +++
>>>>  6 files changed, 219 insertions(+)
>>>>  create mode 100644 tools/testing/selftests/bpf/prog_tests/kmod_btfs.c
>>>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs.c
>>>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_mix.c
>>>>  create mode 100644 tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c
>>>>
>>>> --
>>>> 2.34.1
>>>>
>>>>
>>
>>
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2026-08-11  3:41 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-06  4:20 [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Fuyu Zhao
2026-08-06  4:20 ` [RFC PATCH bpf-next 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao
2026-08-06  4:33   ` sashiko-bot
2026-08-06  8:38     ` Fuyu Zhao
2026-08-06  4:20 ` [RFC PATCH bpf-next 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao
2026-08-06  4:29   ` sashiko-bot
2026-08-06  8:39     ` Fuyu Zhao
2026-08-07 22:18 ` [RFC PATCH bpf-next 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Andrii Nakryiko
2026-08-10  6:20   ` Fuyu Zhao
2026-08-10 12:27     ` Alan Maguire
2026-08-11  3:41       ` Fuyu Zhao

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.