* Re: [PATCH V2 1/2] tools/lib/bpf/libbpf: Prioritize module kfuncs over vmlinux kfuncs
2026-05-10 3:01 [PATCH V2 1/2] tools/lib/bpf/libbpf: Prioritize module kfuncs over vmlinux kfuncs Song Chen
@ 2026-05-10 3:37 ` bot+bpf-ci
2026-05-12 1:33 ` Kumar Kartikeya Dwivedi
2026-05-12 3:18 ` Kaitao Cheng
2 siblings, 0 replies; 4+ messages in thread
From: bot+bpf-ci @ 2026-05-10 3:37 UTC (permalink / raw)
To: chensong_2000, andrii, eddyz87, ast, daniel, martin.lau, song,
yonghong.song, john.fastabend, kpsingh, sdf, haoluo, jolsa,
alexei.starovoitov
Cc: bpf, linux-kernel, chensong_2000, ast, andrii, daniel, martin.lau,
eddyz87, yonghong.song, clm, ihor.solodrai
[-- Attachment #1: Type: text/plain, Size: 6393 bytes --]
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index ab2071fdd3e8..b62ec39685e9 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -8587,35 +8587,65 @@ static int bpf_object__read_kallsyms_file(struct bpf_object *obj)
> return libbpf_kallsyms_parse(kallsyms_cb, obj);
> }
>
> +static void split_module_from_ksym(const char *ksym_name,
> + const char **module_name,
> + size_t *module_name_len,
> + const char **kfunc_name)
> +{
> + const char *sep = strstr(ksym_name, "__");
> +
> + if (!sep) {
> + *module_name = NULL;
> + *module_name_len = 0;
> + *kfunc_name = ksym_name;
> + } else {
> + *module_name = ksym_name;
> + *module_name_len = sep - ksym_name;
> + *kfunc_name = sep + strlen("__");
> + }
> +}
> +
> static int find_ksym_btf_id(struct bpf_object *obj, const char *ksym_name,
> - __u16 kind, struct btf **res_btf,
> - struct module_btf **res_mod_btf)
> + __u16 kind, struct btf **res_btf,
> + struct module_btf **res_mod_btf)
> {
> struct module_btf *mod_btf;
> struct btf *btf;
> - int i, id, err;
> + int i, id = 0, err;
> + const char *module_name;
> + const char *kfunc_name;
> + size_t module_name_len;
> +
> + split_module_from_ksym(ksym_name, &module_name, &module_name_len, &kfunc_name);
> + if (module_name_len == 0)
> + goto search_vmlinux;
Does this break resolution of existing kfuncs and ksyms that live in kernel
modules?
For any ksym name that does NOT contain '__' (the default for essentially all
existing BPF programs and in-tree selftests), split_module_from_ksym sets
module_name_len = 0 and the code takes 'goto search_vmlinux' and never
iterates obj->btf_modules.
In the old code, when a ksym was not found in vmlinux BTF (id == -ENOENT),
load_module_btfs() was called and every loaded module BTF was searched with
btf__find_by_name_kind_own(btf, ksym_name, kind). That fallback is now gone
for names without '__'.
Concrete breaking example: tools/testing/selftests/bpf/progs/kfunc_call_test.c
uses kfuncs registered in bpf_testmod.ko such as bpf_kfunc_call_test1,
bpf_kfunc_call_test5, bpf_kfunc_call_test_acquire, bpf_kfunc_call_test_pass_ctx,
bpf_kfunc_call_test_release. None contain '__', so split_module_from_ksym sets
module_name_len = 0 and find_ksym_btf_id jumps straight to search_vmlinux.
Since these kfuncs live in bpf_testmod.ko's BTF (not vmlinux),
btf__find_by_name_kind() returns -ENOENT and find_ksym_btf_id returns -ESRCH.
The BPF program load then fails at bpf_object__resolve_ksym_func_btf_id with
'extern (func ksym) ...: not found in kernel or module BTFs'.
Call chain demonstrating the breakage:
bpf_object__load (libbpf.c)
-> bpf_object__resolve_externs
-> bpf_object__resolve_ksyms_btf_id
-> bpf_object__resolve_ksym_func_btf_id
-> find_ksym_btf_id(obj, ext->essent_name ?: ext->name, BTF_KIND_FUNC, ...)
-> split_module_from_ksym
-> module_name_len == 0
-> goto search_vmlinux
-> returns -ESRCH
Same issue applies to struct_ops registered in modules. For example,
test_kmods/bpf_testmod.c calls register_bpf_struct_ops(&bpf_bpf_testmod_ops,
bpf_testmod_ops). bpf_map__init_kern_struct_ops -> find_struct_ops_kern_types
calls find_ksym_btf_id with stname = "bpf_struct_ops_bpf_testmod_ops" (no
'__'), so the module BTF search is skipped and the struct_ops map can no
longer be initialized.
Same issue applies to bpf_object__resolve_ksym_var_btf_id for any
variable-kind ksym that lives in a module.
>
> - btf = obj->btf_vmlinux;
> mod_btf = NULL;
> - id = btf__find_by_name_kind(btf, ksym_name, kind);
>
> - if (id == -ENOENT) {
> - err = load_module_btfs(obj);
> - if (err)
> - return err;
> + err = load_module_btfs(obj);
> + if (err)
> + goto search_vmlinux;
>
> - for (i = 0; i < obj->btf_module_cnt; i++) {
> - /* we assume module_btf's BTF FD is always >0 */
> - mod_btf = &obj->btf_modules[i];
> + for (i = 0; i < obj->btf_module_cnt; i++) {
> + /* we assume module_btf's BTF FD is always >0 */
> + mod_btf = &obj->btf_modules[i];
> + if (strlen(mod_btf->name) == module_name_len &&
> + !strncmp(mod_btf->name, module_name, module_name_len)) {
> btf = mod_btf->btf;
> - id = btf__find_by_name_kind_own(btf, ksym_name, kind);
> + id = btf__find_by_name_kind_own(btf, kfunc_name, kind);
> if (id != -ENOENT)
> - break;
> + goto found;
> }
> }
> - if (id <= 0)
> +
> +search_vmlinux:
> + btf = obj->btf_vmlinux;
> + mod_btf = NULL;
> + id = btf__find_by_name_kind(btf, ksym_name, kind);
> + if (id == -ENOENT)
> return -ESRCH;
>
> +found:
> *res_btf = btf;
> *res_mod_btf = mod_btf;
> return id;
The commit message states:
> Change the kfunc resolution order in find_ksym_btf_id() to search
> module BTFs before vmlinux BTF. This allows kernel modules to override
> vmlinux kfuncs with the same name, enabling a form of live-patching
Does the implementation match this description?
For any ksym_name without '__', split_module_from_ksym sets module_name_len = 0
and find_ksym_btf_id jumps directly to the search_vmlinux label, never touching
obj->btf_modules. So there is no module-first ordering for ordinary kfunc
names.
For ksym_names that contain '__', the code treats the substring before '__' as
a module name and only searches the single module whose mod_btf->name matches
that prefix (strlen(mod_btf->name) == module_name_len && !strncmp(...)). It
does not iterate all modules.
So a kernel module cannot 'override vmlinux kfuncs with the same name' unless
the BPF program author explicitly spells the kfunc as
'<module-name>__<kfunc-name>'. That is a new opt-in naming convention, not a
transparent override, and it is not documented anywhere in the patch.
Either the implementation should actually search modules first for all names
(and reviewers should then decide if that is acceptable), or the commit message
should be rewritten to describe the real semantics: 'introduce a module__kfunc
naming convention so BPF programs can explicitly target a specific module's
kfunc' and document the new convention and its impact on existing callers of
find_ksym_btf_id.
---
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/25618517155
^ permalink raw reply [flat|nested] 4+ messages in thread* Re: [PATCH V2 1/2] tools/lib/bpf/libbpf: Prioritize module kfuncs over vmlinux kfuncs
2026-05-10 3:01 [PATCH V2 1/2] tools/lib/bpf/libbpf: Prioritize module kfuncs over vmlinux kfuncs Song Chen
2026-05-10 3:37 ` bot+bpf-ci
@ 2026-05-12 1:33 ` Kumar Kartikeya Dwivedi
2026-05-12 3:18 ` Kaitao Cheng
2 siblings, 0 replies; 4+ messages in thread
From: Kumar Kartikeya Dwivedi @ 2026-05-12 1:33 UTC (permalink / raw)
To: Song Chen, andrii, eddyz87, alexei.starovoitov
Cc: ast, daniel, martin.lau, song, yonghong.song, john.fastabend,
kpsingh, sdf, haoluo, jolsa, bpf, linux-kernel
On Sun, 10 May 2026 at 05:05, Song Chen <chensong_2000@126.com> wrote:
>
> Change the kfunc resolution order in find_ksym_btf_id() to search
> module BTFs before vmlinux BTF. This allows kernel modules to override
> vmlinux kfuncs with the same name, enabling a form of live-patching
> for kfuncs.
>
> Previously, vmlinux kfuncs were always preferred, making it impossible
> for modules to provide enhanced or fixed versions of existing kfuncs.
> With this change, modules can now override kernel kfuncs, while
> programs that don't use module BTFs remain unaffected.
>
> Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
> Signed-off-by: Song Chen <chensong_2000@126.com>
>
> ---
> changelog:
> v1 --> v2:
> 1, introduce namespace to specify which module the kfunc belongs to, like:
> modulea__foo
> moduleb__foo
> foo
> As a result, kfunc foo can co-exist in modulea, moduleb and vmlinux, ebpf
> code owner can specify which one he wants to call.
> ---
> tools/lib/bpf/libbpf.c | 60 +++++++++++++++++++++++++++++++-----------
> 1 file changed, 45 insertions(+), 15 deletions(-)
>
Instead of modulea___ prefix, how about using declaration tags instead?
We can use `namespace:vmlinux` and `namespace:module` to choose
precedence for module or vmlinux.
Then further scope using `namespace:moduleA` or `namespace:moduleB`.
By default, I think preferring vmlinux symbols over modules makes
sense. If one wants to prefer an overload with the same name coming
from a module, they can place the right tag. But we need more
consensus from other folks before you respin again. If we didn't have
a way of indicating the preference, I would agree picking the one in
module would allow more interesting cases by default, but since we do
have a mechanism, it makes sense to pick a more sensible conservative
default, in my opinion.
Anyway, let's see what others might say.
pw-bot: cr
> [...]
^ permalink raw reply [flat|nested] 4+ messages in thread
* Re: [PATCH V2 1/2] tools/lib/bpf/libbpf: Prioritize module kfuncs over vmlinux kfuncs
2026-05-10 3:01 [PATCH V2 1/2] tools/lib/bpf/libbpf: Prioritize module kfuncs over vmlinux kfuncs Song Chen
2026-05-10 3:37 ` bot+bpf-ci
2026-05-12 1:33 ` Kumar Kartikeya Dwivedi
@ 2026-05-12 3:18 ` Kaitao Cheng
2 siblings, 0 replies; 4+ messages in thread
From: Kaitao Cheng @ 2026-05-12 3:18 UTC (permalink / raw)
To: Song Chen
Cc: bpf, martin.lau, alexei.starovoitov, jolsa, haoluo, kpsingh, song,
linux-kernel, daniel, ast, andrii, eddyz87, yonghong.song,
john.fastabend, sdf
在 2026/5/10 11:01, Song Chen 写道:
> Change the kfunc resolution order in find_ksym_btf_id() to search
> module BTFs before vmlinux BTF. This allows kernel modules to override
> vmlinux kfuncs with the same name, enabling a form of live-patching
> for kfuncs.
>
> Previously, vmlinux kfuncs were always preferred, making it impossible
> for modules to provide enhanced or fixed versions of existing kfuncs.
> With this change, modules can now override kernel kfuncs, while
> programs that don't use module BTFs remain unaffected.
>
> Suggested-by: Alexei Starovoitov <alexei.starovoitov@gmail.com>
> Signed-off-by: Song Chen <chensong_2000@126.com>
>
> ---
> changelog:
> v1 --> v2:
> 1, introduce namespace to specify which module the kfunc belongs to, like:
> modulea__foo
> moduleb__foo
> foo
> As a result, kfunc foo can co-exist in modulea, moduleb and vmlinux, ebpf
> code owner can specify which one he wants to call.
> ---
> tools/lib/bpf/libbpf.c | 60 +++++++++++++++++++++++++++++++-----------
> 1 file changed, 45 insertions(+), 15 deletions(-)
>
> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 0be7017800fe..9c9e5ff4d754 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -8532,35 +8532,65 @@ static int bpf_object__read_kallsyms_file(struct bpf_object *obj)
> return libbpf_kallsyms_parse(kallsyms_cb, obj);
> }
>
> +static void split_module_from_ksym(const char *ksym_name,
> + const char **module_name,
> + size_t *module_name_len,
> + const char **kfunc_name)
> +{
> + const char *sep = strstr(ksym_name, "__");
> +
> + if (!sep) {
> + *module_name = NULL;
> + *module_name_len = 0;
> + *kfunc_name = ksym_name;
> + } else {
> + *module_name = ksym_name;
> + *module_name_len = sep - ksym_name;
> + *kfunc_name = sep + strlen("__");
> + }
> +}
I don't think overloading "__" in ksym_name is safe.
1. "__" itself is very common in kernel symbol names. Forcibly
treating the first "__" as the separator between the module name
and the kfunc name is seriously ambiguous. We cannot rule out
existing kfuncs, either defined by a module or by the core kernel,
whose names already contain "__".
2. ksym_name is not used only locally inside find_ksym_btf_id(). If
ext->name / ext->essent_name becomes inconsistent with the actual
kfunc name, it may affect other code paths as well.
It seems that there are two problems to solve here:
1. Allowing kernel modules to override vmlinux kfuncs with the same
name.
This should be relatively straightforward to implement by matching
names in kernel modules first, and then falling back to vmlinux.
2. Handling the case where different kernel modules have kfuncs with
the same name.
Could we use a new libbpf API to establish the mapping manually?
for example:
bpf_object__set_ksym_btf(obj, "kfunc_name", "module_name")
Or define a new attribute, for example:
extern void kfunc_name(void) __ksym __module("module_name");
We probably need to hear suggestions from other developers on this.
Note: Adding the module name as a prefix to the kfunc name is
technically feasible, but it has significant historical compatibility
issues, which are hard to solve.
> static int find_ksym_btf_id(struct bpf_object *obj, const char *ksym_name,
> - __u16 kind, struct btf **res_btf,
> - struct module_btf **res_mod_btf)
> + __u16 kind, struct btf **res_btf,
> + struct module_btf **res_mod_btf)
> {
> struct module_btf *mod_btf;
> struct btf *btf;
> - int i, id, err;
> + int i, id = 0, err;
> + const char *module_name;
> + const char *kfunc_name;
> + size_t module_name_len;
> +
> + split_module_from_ksym(ksym_name, &module_name, &module_name_len, &kfunc_name);
> + if (module_name_len == 0)
> + goto search_vmlinux;
>
> - btf = obj->btf_vmlinux;
> mod_btf = NULL;
> - id = btf__find_by_name_kind(btf, ksym_name, kind);
>
> - if (id == -ENOENT) {
> - err = load_module_btfs(obj);
> - if (err)
> - return err;
> + err = load_module_btfs(obj);
> + if (err)
> + goto search_vmlinux;
>
> - for (i = 0; i < obj->btf_module_cnt; i++) {
> - /* we assume module_btf's BTF FD is always >0 */
> - mod_btf = &obj->btf_modules[i];
> + for (i = 0; i < obj->btf_module_cnt; i++) {
> + /* we assume module_btf's BTF FD is always >0 */
> + mod_btf = &obj->btf_modules[i];
> + if (strlen(mod_btf->name) == module_name_len &&
> + !strncmp(mod_btf->name, module_name, module_name_len)) {
> btf = mod_btf->btf;
> - id = btf__find_by_name_kind_own(btf, ksym_name, kind);
> + id = btf__find_by_name_kind_own(btf, kfunc_name, kind);
> if (id != -ENOENT)
> - break;
> + goto found;
> }
> }
> - if (id <= 0)
> +
> +search_vmlinux:
> + btf = obj->btf_vmlinux;
> + mod_btf = NULL;
> + id = btf__find_by_name_kind(btf, ksym_name, kind);
> + if (id == -ENOENT)
> return -ESRCH;
>
> +found:
> *res_btf = btf;
> *res_mod_btf = mod_btf;
> return id;
--
Thanks
Kaitao Cheng
^ permalink raw reply [flat|nested] 4+ messages in thread