* [RFC PATCH bpf-next v2 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs
@ 2026-08-13 3:26 Fuyu Zhao
2026-08-13 3:26 ` [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao
2026-08-13 3:26 ` [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao
0 siblings, 2 replies; 13+ messages in thread
From: Fuyu Zhao @ 2026-08-13 3:26 UTC (permalink / raw)
To: bpf, andrii, alan.maguire
Cc: ast, daniel, eddyz87, memxor, martin.lau, song, yonghong.song,
jolsa, emil, ihor.solodrai, shuah, yatsenko, linux-kernel,
linux-kselftest, Fuyu Zhao
Currently, during BPF object loading, load_module_btfs() unconditionally
iterates over all module BTFs and loads each one. This introduces
unnecessary overhead when a BPF program only needs BTFs from a specific,
small subset of modules. In environments with hundreds of modules,
loading all module BTFs can measurably increase the loading time.
This series introduces an optional ".kmod_btfs" ELF section, allowing BPF
programs to declare the modules whose BTFs should be loaded by
load_module_btfs(). libbpf uses this information to skip unrelated module
BTFs and stops the iteration early once all declared modules are found.
Without this section, the existing behavior remains unchanged.
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%
There are use cases where BPF programs are loaded on demand rather than
as a one-time setup. In our Android testing, the impact is even more
pronounced: the total BPF loading time exceeds 300 ms with 93 module
BTFs, with loading module BTFs accounting for around 69% of the total
loading time. Preloading all BPF programs is not suitable in this case,
as unused programs should remain unloaded to minimize memory usage.
The existing module qualification in SEC(), such as
SEC("fentry/mymod:foo"), is only supported for BPF program types with
explicit attach targets. It only guides find_kernel_btf_id() to search
for the BTF ID in the specified module after load_module_btfs(), and
does not reduce the number of module BTFs loaded by load_module_btfs().
Changelog:
v2:
- Addressed issues with allocation error handling, multiple .kmod_btfs
sections, the transient stack pointer in is_kmod_btf_needed(), and
selftest dependency and comment formatting. (sashiko-bot)
- Removed KMODS_BTF_LOADED and KMODS_BTF_UNLOADED and simplified the
related logic.
v1:
- Link: https://lore.kernel.org/bpf/20260806042042.3239428-1-zhaofuyu@vivo.com/
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 | 106 ++++++++++++++++++
.../selftests/bpf/prog_tests/kmod_btfs.c | 52 +++++++++
tools/testing/selftests/bpf/progs/kmod_btfs.c | 14 +++
.../selftests/bpf/progs/kmod_btfs_mix.c | 15 +++
.../selftests/bpf/progs/kmod_btfs_nonexist.c | 18 +++
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] 13+ messages in thread* [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section 2026-08-13 3:26 [RFC PATCH bpf-next v2 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Fuyu Zhao @ 2026-08-13 3:26 ` Fuyu Zhao 2026-08-13 3:37 ` sashiko-bot ` (2 more replies) 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao 1 sibling, 3 replies; 13+ messages in thread From: Fuyu Zhao @ 2026-08-13 3:26 UTC (permalink / raw) To: bpf, andrii, alan.maguire Cc: ast, daniel, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, yatsenko, linux-kernel, linux-kselftest, Fuyu Zhao 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 | 106 ++++++++++++++++++++++++++++++++++++ 2 files changed, 120 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..9fe8a653e8b6 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,9 @@ enum bpf_object_state { OBJ_LOADED, }; +/* Should match the definition in bpf_helpers.h */ +#define KMOD_NAME_LEN 64 + struct bpf_object { char name[BPF_OBJ_NAME_LEN]; char license[64]; @@ -779,6 +783,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 +913,75 @@ 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 (obj->kmod_btfs) { + pr_warn("sec '%s': duplicate sections detected\n", sec_name); + return -EEXIST; + } + + 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) { + err = -ENOMEM; + 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], + 0, 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 +4115,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 +5888,11 @@ 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) +{ + return hashmap_find(obj->kmod_btfs->hashmap, (long)name, NULL); +} + static int load_module_btfs(struct bpf_object *obj) { struct bpf_btf_info info; @@ -5867,6 +5957,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 +5987,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 +9130,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] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao @ 2026-08-13 3:37 ` sashiko-bot 2026-08-13 12:00 ` Fuyu Zhao 2026-08-13 4:22 ` bot+bpf-ci 2026-08-14 19:57 ` Andrii Nakryiko 2 siblings, 1 reply; 13+ messages in thread From: sashiko-bot @ 2026-08-13 3:37 UTC (permalink / raw) To: Fuyu Zhao; +Cc: bpf Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: - [Medium] Missing increment of `nr_loaded` prevents early loop termination. - [Low] Multi-line comment formatting violation. -- --- Patch [1]: [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section --- commit 3f4fb04bbfb95d7f7ea0012b5651135983af6e62 Author: Fuyu Zhao <zhaofuyu@vivo.com> libbpf: support selective kernel module BTF loading via .kmod_btfs section This patch adds support for a ".kmod_btfs" ELF section to allow BPF programs to specify which kernel modules need BTF loading. It introduces functions to collect the module names and filter the BTF loading process to avoid loading unneeded modules. > diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h > index 9d160b5b9c0ee..171ea055cd323 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. > + * [Severity: Low] This isn't a bug, but the BPF subsystem coding style expects multi-line comments to have the opening /* on its own line. Should this be reformatted to match the preferred kernel style? > + * Usage: define an array in the ".kmod_btfs" ELF section to specify > + * which modules need BTF loading: > + * [ ... ] > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c > index 514e4e9daa825..9fe8a653e8b6b 100644 > --- a/tools/lib/bpf/libbpf.c > +++ b/tools/lib/bpf/libbpf.c [ ... ] > @@ -5891,6 +5987,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; [Severity: Medium] Is obj->kmod_btfs->nr_loaded missing an increment? Looking at the loop in load_module_btfs(), when a module BTF is successfully loaded and obj->btf_module_cnt is incremented, obj->kmod_btfs->nr_loaded doesn't appear to be updated anywhere. Will this prevent the intended optimization of breaking out of the loop early, causing it to always scan all remaining kernel BTF IDs unnecessarily? > } > > if (err) { -- Sashiko AI review · https://sashiko.dev/#/patchset/20260813032613.2755-1-zhaofuyu@vivo.com?part=1 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section 2026-08-13 3:37 ` sashiko-bot @ 2026-08-13 12:00 ` Fuyu Zhao 0 siblings, 0 replies; 13+ messages in thread From: Fuyu Zhao @ 2026-08-13 12:00 UTC (permalink / raw) To: sashiko-reviews; +Cc: bpf On 8/13/2026 11:37 AM, sashiko-bot@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 2 potential issue(s) to consider: > - [Medium] Missing increment of `nr_loaded` prevents early loop termination. > - [Low] Multi-line comment formatting violation. > -- > > --- Patch [1]: [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section --- > commit 3f4fb04bbfb95d7f7ea0012b5651135983af6e62 > Author: Fuyu Zhao <zhaofuyu@vivo.com> > > libbpf: support selective kernel module BTF loading via .kmod_btfs section > > This patch adds support for a ".kmod_btfs" ELF section to allow BPF programs > to specify which kernel modules need BTF loading. It introduces functions to > collect the module names and filter the BTF loading process to avoid loading > unneeded modules. > >> diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h >> index 9d160b5b9c0ee..171ea055cd323 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. >> + * > > [Severity: Low] > This isn't a bug, but the BPF subsystem coding style expects multi-line > comments to have the opening /* on its own line. Should this be reformatted > to match the preferred kernel style? > Thanks. I'll also fix the comment formatting. >> + * Usage: define an array in the ".kmod_btfs" ELF section to specify >> + * which modules need BTF loading: >> + * > > [ ... ] > >> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c >> index 514e4e9daa825..9fe8a653e8b6b 100644 >> --- a/tools/lib/bpf/libbpf.c >> +++ b/tools/lib/bpf/libbpf.c > > [ ... ] > >> @@ -5891,6 +5987,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; > > [Severity: Medium] > Is obj->kmod_btfs->nr_loaded missing an increment? > > Looking at the loop in load_module_btfs(), when a module BTF is successfully > loaded and obj->btf_module_cnt is incremented, obj->kmod_btfs->nr_loaded > doesn't appear to be updated anywhere. > > Will this prevent the intended optimization of breaking out of the loop early, > causing it to always scan all remaining kernel BTF IDs unnecessarily? > My bad, this is a simple oversight. I forgot to preserve the nr_loaded increment when removing KMODS_BTF_* and simplifying the related logic. I'll fix it and pay closer attention to such changes next time. >> } >> >> if (err) { > ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao 2026-08-13 3:37 ` sashiko-bot @ 2026-08-13 4:22 ` bot+bpf-ci 2026-08-13 12:04 ` Fuyu Zhao 2026-08-14 19:57 ` Andrii Nakryiko 2 siblings, 1 reply; 13+ messages in thread From: bot+bpf-ci @ 2026-08-13 4:22 UTC (permalink / raw) To: zhaofuyu, bpf, andrii, alan.maguire Cc: ast, daniel, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, yatsenko, linux-kernel, linux-kselftest, zhaofuyu, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 4944 bytes --] > diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h > index 9d160b5b9c0ee..171ea055cd323 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] KMOD_NAME_LEN establishes the on-disk record size for the .kmod_btfs section format, yet it's duplicated in two files with only a prose comment connecting them: tools/lib/bpf/bpf_helpers.h:201 #define KMOD_NAME_LEN 64 tools/lib/bpf/libbpf.c:707-708 /* Should match the definition in ... */ #define KMOD_NAME_LEN 64 If the two ever diverge, bpf_object__collect_kmod_btf_names() will silently mis-slice the section. The d_size % KMOD_NAME_LEN check only catches non-multiples, not a mismatch between the two values. Could this use a shared header or a static assert to ensure they stay in sync? Also, the new macro has no #ifndef guard. This header is included by nearly every BPF program alongside vmlinux.h and user headers. Other unprefixed names this header exports (NULL at lines 78-80, KERNEL_VERSION at 82-84) all have #ifndef wrappers. Should KMOD_NAME_LEN follow that pattern? > diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c > index 514e4e9daa825..9fe8a653e8b6b 100644 > --- a/tools/lib/bpf/libbpf.c > +++ b/tools/lib/bpf/libbpf.c [ ... ] > @@ -5803,6 +5888,11 @@ 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) > +{ > + return hashmap_find(obj->kmod_btfs->hashmap, (long)name, NULL); > +} This calls the raw hashmap_find() with a manual (long) cast, rather than the hashmap__find() wrapper that hashmap.h provides: hashmap.h:159 #define hashmap__find(map, key, value) \ hashmap_find((map), (long)(key), hashmap_cast_ptr(value)) The header comments at lines 50 and 54 say the intent is to use the wrapper ("behind auxiliary macros") so that the _Static_assert on the value pointer runs. Bypassing the macro also bypasses that check. This is the only direct caller of the unversioned function in the whole library. The other function added by this same patch does use the wrapper (bpf_object__collect_kmod_btf_names at libbpf.c:964 uses hashmap__find), so the two halves of the change are inconsistent. Should this use the wrapper too? [ ... ] > @@ -9030,6 +9130,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); > + } > } The .kmod_btfs filter list is ELF open-time data, but it's freed from bpf_object_cleanup_btf(), which runs while the bpf_object is still alive and load_module_btfs() can still be called. The filter therefore stops applying part-way through the object's lifetime. Concrete path: bpf_object_load() libbpf.c:9182 ... -> bpf_object_post_load_cleanup() libbpf.c:9229 -> bpf_object_cleanup_btf() libbpf.c:9147 obj->btf_modules_loaded = false; (libbpf.c:9128) zfree(&obj->kmod_btfs); (libbpf.c:9137) bpf_program__attach_tracing_multi() libbpf.c:12791 -> collect_func_ids_by_glob() libbpf.c:12752 -> find_attach_module() libbpf.c:7877 -> load_module_btfs() libbpf.c:5896 At this second entry into load_module_btfs(), btf_modules_loaded is false so the full scan re-runs, but obj->kmod_btfs is NULL. The filter at libbpf.c:5960 is skipped and every module BTF in the system is loaded, exactly what the section is supposed to prevent. collect_func_ids_by_glob() also calls bpf_object_cleanup_btf(obj) unconditionally at its cleanup: label (libbpf.c:12786), so the list is destroyed again on every attach. The other open-time members with the same lifetime (obj->jumptables_data, obj->arena_data, obj->kconfig) are freed in bpf_object__close() (libbpf.c:9720-9733), not in the BTF cleanup helper. Should obj->kmod_btfs be freed there instead? --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31664172915 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section 2026-08-13 4:22 ` bot+bpf-ci @ 2026-08-13 12:04 ` Fuyu Zhao 0 siblings, 0 replies; 13+ messages in thread From: Fuyu Zhao @ 2026-08-13 12:04 UTC (permalink / raw) To: bot+bpf-ci; +Cc: bpf On 8/13/2026 12:22 PM, bot+bpf-ci@kernel.org wrote: >> diff --git a/tools/lib/bpf/bpf_helpers.h b/tools/lib/bpf/bpf_helpers.h >> index 9d160b5b9c0ee..171ea055cd323 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] > > KMOD_NAME_LEN establishes the on-disk record size for the .kmod_btfs section > format, yet it's duplicated in two files with only a prose comment connecting > them: > > tools/lib/bpf/bpf_helpers.h:201 #define KMOD_NAME_LEN 64 > tools/lib/bpf/libbpf.c:707-708 /* Should match the definition in ... */ > #define KMOD_NAME_LEN 64 > > If the two ever diverge, bpf_object__collect_kmod_btf_names() will silently > mis-slice the section. The d_size % KMOD_NAME_LEN check only catches > non-multiples, not a mismatch between the two values. Could this use a shared > header or a static assert to ensure they stay in sync? > > Also, the new macro has no #ifndef guard. This header is included by nearly > every BPF program alongside vmlinux.h and user headers. Other unprefixed > names this header exports (NULL at lines 78-80, KERNEL_VERSION at 82-84) all > have #ifndef wrappers. Should KMOD_NAME_LEN follow that pattern? > Thanks, I agree this is worth addressing. I'm not sure there is a suitable shared header for this definition, and a static assertion cannot directly ensure that the two definitions stay in sync. I'll keep looking for a better solution. Suggestions are welcome. >> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c >> index 514e4e9daa825..9fe8a653e8b6b 100644 >> --- a/tools/lib/bpf/libbpf.c >> +++ b/tools/lib/bpf/libbpf.c > > [ ... ] > >> @@ -5803,6 +5888,11 @@ 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) >> +{ >> + return hashmap_find(obj->kmod_btfs->hashmap, (long)name, NULL); >> +} > > This calls the raw hashmap_find() with a manual (long) cast, rather than > the hashmap__find() wrapper that hashmap.h provides: > > hashmap.h:159 > #define hashmap__find(map, key, value) \ > hashmap_find((map), (long)(key), hashmap_cast_ptr(value)) > > The header comments at lines 50 and 54 say the intent is to use the wrapper > ("behind auxiliary macros") so that the _Static_assert on the value pointer > runs. Bypassing the macro also bypasses that check. > > This is the only direct caller of the unversioned function in the whole > library. The other function added by this same patch does use the wrapper > (bpf_object__collect_kmod_btf_names at libbpf.c:964 uses hashmap__find), so > the two halves of the change are inconsistent. Should this use the wrapper > too? > > [ ... ] > Agreed. I'll use hashmap__find() here for consistency. >> @@ -9030,6 +9130,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); >> + } >> } > > The .kmod_btfs filter list is ELF open-time data, but it's freed from > bpf_object_cleanup_btf(), which runs while the bpf_object is still alive and > load_module_btfs() can still be called. The filter therefore stops applying > part-way through the object's lifetime. Concrete path: > > bpf_object_load() libbpf.c:9182 > ... -> bpf_object_post_load_cleanup() libbpf.c:9229 > -> bpf_object_cleanup_btf() libbpf.c:9147 > obj->btf_modules_loaded = false; (libbpf.c:9128) > zfree(&obj->kmod_btfs); (libbpf.c:9137) > > bpf_program__attach_tracing_multi() libbpf.c:12791 > -> collect_func_ids_by_glob() libbpf.c:12752 > -> find_attach_module() libbpf.c:7877 > -> load_module_btfs() libbpf.c:5896 > > At this second entry into load_module_btfs(), btf_modules_loaded is false so > the full scan re-runs, but obj->kmod_btfs is NULL. The filter at > libbpf.c:5960 is skipped and every module BTF in the system is loaded, > exactly what the section is supposed to prevent. collect_func_ids_by_glob() > also calls bpf_object_cleanup_btf(obj) unconditionally at its cleanup: label > (libbpf.c:12786), so the list is destroyed again on every attach. > > The other open-time members with the same lifetime (obj->jumptables_data, > obj->arena_data, obj->kconfig) are freed in bpf_object__close() > (libbpf.c:9720-9733), not in the BTF cleanup helper. Should obj->kmod_btfs > be freed there instead? > Thanks, this makes sense. I'll look into this more carefully and check the appropriate lifetime for kmod_btfs. > > --- > AI reviewed your patch. Please fix the bug or email reply why it's not a bug. > See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md > > CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31664172915 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao 2026-08-13 3:37 ` sashiko-bot 2026-08-13 4:22 ` bot+bpf-ci @ 2026-08-14 19:57 ` Andrii Nakryiko 2026-08-15 15:35 ` Fuyu Zhao 2 siblings, 1 reply; 13+ messages in thread From: Andrii Nakryiko @ 2026-08-14 19:57 UTC (permalink / raw) To: Fuyu Zhao Cc: bpf, andrii, alan.maguire, ast, daniel, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, yatsenko, linux-kernel, linux-kselftest On Wed, Aug 12, 2026 at 8:26 PM Fuyu Zhao <zhaofuyu@vivo.com> wrote: > > 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 | 106 ++++++++++++++++++++++++++++++++++++ > 2 files changed, 120 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] > + I don't really like another special ELF section just to provide a custom list of modules. If we have to do a customization of BTF searching behavior of libbpf, let's do this through bpf_object_open_opts struct and pass NULL or a empty/non-empty list of kernel modules, or whatever other appropriate way to specify this. But in any case, extending ELF format for BPF object file for this seems like an overkill and overcomplication. pw-bot: cr > #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..9fe8a653e8b6 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,9 @@ enum bpf_object_state { > OBJ_LOADED, > }; > > +/* Should match the definition in bpf_helpers.h */ > +#define KMOD_NAME_LEN 64 > + > struct bpf_object { > char name[BPF_OBJ_NAME_LEN]; > char license[64]; > @@ -779,6 +783,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 +913,75 @@ 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 (obj->kmod_btfs) { > + pr_warn("sec '%s': duplicate sections detected\n", sec_name); > + return -EEXIST; > + } > + > + 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) { > + err = -ENOMEM; > + 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], > + 0, 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 +4115,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 +5888,11 @@ 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) > +{ > + return hashmap_find(obj->kmod_btfs->hashmap, (long)name, NULL); > +} > + > static int load_module_btfs(struct bpf_object *obj) > { > struct bpf_btf_info info; > @@ -5867,6 +5957,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 +5987,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 +9130,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 [flat|nested] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section 2026-08-14 19:57 ` Andrii Nakryiko @ 2026-08-15 15:35 ` Fuyu Zhao 0 siblings, 0 replies; 13+ messages in thread From: Fuyu Zhao @ 2026-08-15 15:35 UTC (permalink / raw) To: Andrii Nakryiko Cc: bpf, andrii, alan.maguire, ast, daniel, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, yatsenko, linux-kernel, linux-kselftest On 8/15/2026 3:57 AM, Andrii Nakryiko wrote: > On Wed, Aug 12, 2026 at 8:26 PM Fuyu Zhao <zhaofuyu@vivo.com> wrote: >> >> 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 | 106 ++++++++++++++++++++++++++++++++++++ >> 2 files changed, 120 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] >> + > > I don't really like another special ELF section just to provide a > custom list of modules. > > If we have to do a customization of BTF searching behavior of libbpf, > let's do this through bpf_object_open_opts struct and pass NULL or a > empty/non-empty list of kernel modules, or whatever other appropriate > way to specify this. > > But in any case, extending ELF format for BPF object file for this > seems like an overkill and overcomplication. > > pw-bot: cr > Hi Andrii, Thanks for the feedback. I also considered passing the module list through bpf_object_open_opts. The main reason for using an ELF section is that it keeps the module dependency information together with the BPF object and requires minimal changes for existing users. However, I understand the concern that extending the ELF format introduces additional complexity. I'll explore bpf_object_open_opts or other more suitable approaches. Best regards, Fuyu >> #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..9fe8a653e8b6 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,9 @@ enum bpf_object_state { >> OBJ_LOADED, >> }; >> >> +/* Should match the definition in bpf_helpers.h */ >> +#define KMOD_NAME_LEN 64 >> + >> struct bpf_object { >> char name[BPF_OBJ_NAME_LEN]; >> char license[64]; >> @@ -779,6 +783,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 +913,75 @@ 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 (obj->kmod_btfs) { >> + pr_warn("sec '%s': duplicate sections detected\n", sec_name); >> + return -EEXIST; >> + } >> + >> + 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) { >> + err = -ENOMEM; >> + 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], >> + 0, 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 +4115,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 +5888,11 @@ 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) >> +{ >> + return hashmap_find(obj->kmod_btfs->hashmap, (long)name, NULL); >> +} >> + >> static int load_module_btfs(struct bpf_object *obj) >> { >> struct bpf_btf_info info; >> @@ -5867,6 +5957,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 +5987,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 +9130,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 [flat|nested] 13+ messages in thread
* [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading 2026-08-13 3:26 [RFC PATCH bpf-next v2 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Fuyu Zhao 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao @ 2026-08-13 3:26 ` Fuyu Zhao 2026-08-13 3:37 ` sashiko-bot 2026-08-13 4:22 ` bot+bpf-ci 1 sibling, 2 replies; 13+ messages in thread From: Fuyu Zhao @ 2026-08-13 3:26 UTC (permalink / raw) To: bpf, andrii, alan.maguire Cc: ast, daniel, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, yatsenko, linux-kernel, linux-kselftest, Fuyu Zhao 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 | 52 +++++++++++++++++++ tools/testing/selftests/bpf/progs/kmod_btfs.c | 14 +++++ .../selftests/bpf/progs/kmod_btfs_mix.c | 15 ++++++ .../selftests/bpf/progs/kmod_btfs_nonexist.c | 18 +++++++ 4 files changed, 99 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..d875fcce6681 --- /dev/null +++ b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c @@ -0,0 +1,52 @@ +// 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 (!env.has_testmod) { + test__skip(); + return; + } + + 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..1638361e5732 --- /dev/null +++ b/tools/testing/selftests/bpf/progs/kmod_btfs_nonexist.c @@ -0,0 +1,18 @@ +// 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] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao @ 2026-08-13 3:37 ` sashiko-bot 2026-08-13 12:00 ` Fuyu Zhao 2026-08-13 4:22 ` bot+bpf-ci 1 sibling, 1 reply; 13+ messages in thread From: sashiko-bot @ 2026-08-13 3:37 UTC (permalink / raw) To: Fuyu Zhao; +Cc: bpf Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: - [Medium] The tracking counter `obj->kmod_btfs->nr_loaded` is never updated, rendering the early termination optimization for BTF loading completely ineffective. -- --- Patch [2]: [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading --- commit 506359525a106f517e013e060ee2c6feb17720c8 Author: Fuyu Zhao <zhaofuyu@vivo.com> selftests/bpf: add tests for selective kmod BTF loading Add test cases to verify the new ".kmod_btfs" section logic in libbpf. The added test cases cover three main scenarios: valid module, non-existent module, and duplicates/unneeded modules. > diff --git a/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c > index 0000000000000..d875fcce6681d > --- /dev/null > +++ b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c > @@ -0,0 +1,52 @@ > +// 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" > + [ ... ] [Severity: Medium] While reviewing these tests, I noticed a potential regression in the libbpf code they exercise. In load_module_btfs(): tools/lib/bpf/libbpf.c:load_module_btfs() { ... if (obj->kmod_btfs && obj->kmod_btfs->nr_names == obj->kmod_btfs->nr_loaded) break; ... } Is obj->kmod_btfs->nr_loaded ever incremented when a module BTF is successfully loaded? If it is not incremented, will this early termination condition ever be met? It appears this might unnecessarily iterate over all remaining system BTFs, which would bypass the intended performance optimization of the .kmod_btfs section. -- Sashiko AI review · https://sashiko.dev/#/patchset/20260813032613.2755-1-zhaofuyu@vivo.com?part=2 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading 2026-08-13 3:37 ` sashiko-bot @ 2026-08-13 12:00 ` Fuyu Zhao 0 siblings, 0 replies; 13+ messages in thread From: Fuyu Zhao @ 2026-08-13 12:00 UTC (permalink / raw) To: sashiko-reviews; +Cc: bpf On 8/13/2026 11:37 AM, sashiko-bot@kernel.org wrote: > Thank you for your contribution! Sashiko AI review found 1 potential issue(s) to consider: > - [Medium] The tracking counter `obj->kmod_btfs->nr_loaded` is never updated, rendering the early termination optimization for BTF loading completely ineffective. > -- > > --- Patch [2]: [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading --- > commit 506359525a106f517e013e060ee2c6feb17720c8 > Author: Fuyu Zhao <zhaofuyu@vivo.com> > > selftests/bpf: add tests for selective kmod BTF loading > > Add test cases to verify the new ".kmod_btfs" section logic in libbpf. > The added test cases cover three main scenarios: valid module, non-existent > module, and duplicates/unneeded modules. > >> diff --git a/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c >> index 0000000000000..d875fcce6681d >> --- /dev/null >> +++ b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c >> @@ -0,0 +1,52 @@ >> +// 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" >> + > > [ ... ] > > [Severity: Medium] > While reviewing these tests, I noticed a potential regression in the libbpf > code they exercise. In load_module_btfs(): > > tools/lib/bpf/libbpf.c:load_module_btfs() { > ... > if (obj->kmod_btfs && > obj->kmod_btfs->nr_names == obj->kmod_btfs->nr_loaded) > break; > ... > } > > Is obj->kmod_btfs->nr_loaded ever incremented when a module BTF is > successfully loaded? > > If it is not incremented, will this early termination condition ever be > met? It appears this might unnecessarily iterate over all remaining > system BTFs, which would bypass the intended performance optimization > of the .kmod_btfs section. > Thanks for catching this. This is the same oversight mentioned above. I'll fix the nr_loaded accounting in v3. ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao 2026-08-13 3:37 ` sashiko-bot @ 2026-08-13 4:22 ` bot+bpf-ci 2026-08-13 12:05 ` Fuyu Zhao 1 sibling, 1 reply; 13+ messages in thread From: bot+bpf-ci @ 2026-08-13 4:22 UTC (permalink / raw) To: zhaofuyu, bpf, andrii, alan.maguire Cc: ast, daniel, eddyz87, memxor, martin.lau, song, yonghong.song, jolsa, emil, ihor.solodrai, shuah, yatsenko, linux-kernel, linux-kselftest, zhaofuyu, ast, andrii, daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai [-- Attachment #1: Type: text/plain, Size: 3297 bytes --] > 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 0000000000000..d875fcce6681d > --- /dev/null > +++ b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c > @@ -0,0 +1,52 @@ [ ... ] > +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"); > +} On the path where this assertion unexpectedly fails (i.e. the skeleton loads when it should not), does the bpf_object leak? There is no 'kmod_btfs_nonexist__destroy()' call before the function returns. The other two subtests (kmod_btfs_pass and kmod_btfs_mix) call '__destroy()'. Test_progs runs hundreds of subtests in one process, so leaked fds stay open for the rest of the run. The usual pattern is: if (!ASSERT_NULL(skel, "kmod_btfs_nonexist__open_and_load")) kmod_btfs_nonexist__destroy(skel); Also, the ASSERT_NULL check accepts any load failure at all. Without privileges, load_module_btfs() returns 0 early ('skipping module BTFs loading, missing privileges'), so '__open_and_load()' returns NULL and this subtest passes without exercising '.kmod_btfs' handling. The same is true if vmlinux BTF is unavailable, ftrace cannot hook the target, or there is a typo in the SEC() name. The positive baseline that rules those out lives in kmod_btfs_pass, but test_progs subtests are individually selectable: ./test_progs -t kmod_btfs/kmod_btfs_nonexist so running this subtest alone gives green with no baseline. Would it be clearer to check the error more precisely (find_kernel_btf_id() returns -ESRCH here), or load a known-good variant inside the same subtest? [ ... ] > 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 0000000000000..f445cf56ab161 > --- /dev/null > +++ b/tools/testing/selftests/bpf/progs/kmod_btfs_mix.c > @@ -0,0 +1,15 @@ [ ... ] > +/* mix of duplicated and unneeded modules */ > +DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod", "bpf_testmod", "bpf_test_no_cfi" }; Is 'bpf_test_no_cfi' loaded when this subtest runs? Looking at test_progs.c, load_bpf_testmod() at lines 2083-2092 loads only bpf_testmod.ko. The bpf_test_no_cfi.ko module is inserted and immediately removed by prog_tests/test_struct_ops_no_cfi.c via open()/finit_module()/delete_module(). That means the third entry has no module BTF in the system and exercises the same path as the 'module_nonexist' entry in kmod_btfs_nonexist.c: the name is simply never matched in load_module_btfs(). That leaves the interesting case untested: a module whose BTF is present but which the program does not need, which would prove libbpf actually skips it as the commit message advertises ('providing a mix of repeated and extra module names'). Would naming a module that is guaranteed loaded exercise that path? --- AI reviewed your patch. Please fix the bug or email reply why it's not a bug. See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31664172915 ^ permalink raw reply [flat|nested] 13+ messages in thread
* Re: [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading 2026-08-13 4:22 ` bot+bpf-ci @ 2026-08-13 12:05 ` Fuyu Zhao 0 siblings, 0 replies; 13+ messages in thread From: Fuyu Zhao @ 2026-08-13 12:05 UTC (permalink / raw) To: bot+bpf-ci; +Cc: bpf On 8/13/2026 12:22 PM, bot+bpf-ci@kernel.org wrote: >> 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 0000000000000..d875fcce6681d >> --- /dev/null >> +++ b/tools/testing/selftests/bpf/prog_tests/kmod_btfs.c >> @@ -0,0 +1,52 @@ > > [ ... ] > >> +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"); >> +} > > On the path where this assertion unexpectedly fails (i.e. the skeleton > loads when it should not), does the bpf_object leak? There is no > 'kmod_btfs_nonexist__destroy()' call before the function returns. > > The other two subtests (kmod_btfs_pass and kmod_btfs_mix) call > '__destroy()'. Test_progs runs hundreds of subtests in one process, > so leaked fds stay open for the rest of the run. The usual pattern is: > > if (!ASSERT_NULL(skel, "kmod_btfs_nonexist__open_and_load")) > kmod_btfs_nonexist__destroy(skel); > > Also, the ASSERT_NULL check accepts any load failure at all. Without > privileges, load_module_btfs() returns 0 early ('skipping module BTFs > loading, missing privileges'), so '__open_and_load()' returns NULL and > this subtest passes without exercising '.kmod_btfs' handling. The same > is true if vmlinux BTF is unavailable, ftrace cannot hook the target, > or there is a typo in the SEC() name. > > The positive baseline that rules those out lives in kmod_btfs_pass, but > test_progs subtests are individually selectable: > > ./test_progs -t kmod_btfs/kmod_btfs_nonexist > > so running this subtest alone gives green with no baseline. Would it > be clearer to check the error more precisely (find_kernel_btf_id() > returns -ESRCH here), or load a known-good variant inside the same > subtest? > Thanks, good points. I'll fix the leak and make the test distinguish the expected failure from unrelated load failures. > [ ... ] > >> 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 0000000000000..f445cf56ab161 >> --- /dev/null >> +++ b/tools/testing/selftests/bpf/progs/kmod_btfs_mix.c >> @@ -0,0 +1,15 @@ > > [ ... ] > >> +/* mix of duplicated and unneeded modules */ >> +DEFINE_KMOD_BTFS(_needed_kmods) = { "bpf_testmod", "bpf_testmod", "bpf_test_no_cfi" }; > > Is 'bpf_test_no_cfi' loaded when this subtest runs? Looking at > test_progs.c, load_bpf_testmod() at lines 2083-2092 loads only > bpf_testmod.ko. The bpf_test_no_cfi.ko module is inserted and > immediately removed by prog_tests/test_struct_ops_no_cfi.c via > open()/finit_module()/delete_module(). > > That means the third entry has no module BTF in the system and exercises > the same path as the 'module_nonexist' entry in kmod_btfs_nonexist.c: > the name is simply never matched in load_module_btfs(). > > That leaves the interesting case untested: a module whose BTF is present > but which the program does not need, which would prove libbpf actually > skips it as the commit message advertises ('providing a mix of repeated > and extra module names'). Would naming a module that is guaranteed > loaded exercise that path? > Thanks for pointing this out. I'll use a guaranteed loaded module to test the unneeded module BTF case. > > --- > AI reviewed your patch. Please fix the bug or email reply why it's not a bug. > See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md > > CI run summary: https://github.com/kernel-patches/bpf/actions/runs/31664172915 ^ permalink raw reply [flat|nested] 13+ messages in thread
end of thread, other threads:[~2026-08-15 15:35 UTC | newest] Thread overview: 13+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2026-08-13 3:26 [RFC PATCH bpf-next v2 0/2] libbpf: Improve BPF load performance by selectively loading kmod BTFs Fuyu Zhao 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 1/2] libbpf: support selective kernel module BTF loading via .kmod_btfs section Fuyu Zhao 2026-08-13 3:37 ` sashiko-bot 2026-08-13 12:00 ` Fuyu Zhao 2026-08-13 4:22 ` bot+bpf-ci 2026-08-13 12:04 ` Fuyu Zhao 2026-08-14 19:57 ` Andrii Nakryiko 2026-08-15 15:35 ` Fuyu Zhao 2026-08-13 3:26 ` [RFC PATCH bpf-next v2 2/2] selftests/bpf: add tests for selective kmod BTF loading Fuyu Zhao 2026-08-13 3:37 ` sashiko-bot 2026-08-13 12:00 ` Fuyu Zhao 2026-08-13 4:22 ` bot+bpf-ci 2026-08-13 12:05 ` 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.