[PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops

From: Siddharth Nayyar

Date: Wed May 27 2026 - 09:01:15 EST


During light skeleton generation (`bpftool gen skeleton -L`), libbpf
runs in gen_loader mode. Previously, `bpf_object__load_vmlinux_btf()`
completely bypassed loading the kernel vmlinux BTF (`obj->btf_vmlinux`)
if `gen_loader` was active.

However, BPF `struct_ops` maps (such as `sched_ext_ops` maps) require
resolving the kernel-side struct type IDs and member sizes at
compile/skeleton generation time. Without loading `btf_vmlinux`, libbpf
cannot query the kernel BTF types, causing light skeleton generation for
`struct_ops` to fail or omit crucial type information.

Fix this by modifying the check to load `btf_vmlinux` even in
`gen_loader` mode if the BPF object contains `struct_ops` maps.

Signed-off-by: Siddharth Nayyar <sidnayyar@xxxxxxxxxx>
---
tools/lib/bpf/libbpf.c | 24 ++++++++++++++----------
1 file changed, 14 insertions(+), 10 deletions(-)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 3a80a018fc7d..b159faae7f9c 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -3544,15 +3544,20 @@ static bool prog_needs_vmlinux_btf(struct bpf_program *prog)
return false;
}

-static bool map_needs_vmlinux_btf(struct bpf_map *map)
+static bool obj_maps_need_vmlinux_btf(const struct bpf_object *obj)
{
- return bpf_map__is_struct_ops(map);
+ struct bpf_map *map;
+
+ bpf_object__for_each_map(map, obj) {
+ if (bpf_map__is_struct_ops(map))
+ return true;
+ }
+ return false;
}

static bool obj_needs_vmlinux_btf(const struct bpf_object *obj)
{
struct bpf_program *prog;
- struct bpf_map *map;
int i;

/* CO-RE relocations need kernel BTF, only when btf_custom_path
@@ -3577,12 +3582,7 @@ static bool obj_needs_vmlinux_btf(const struct bpf_object *obj)
return true;
}

- bpf_object__for_each_map(map, obj) {
- if (map_needs_vmlinux_btf(map))
- return true;
- }
-
- return false;
+ return obj_maps_need_vmlinux_btf(obj);
}

static int bpf_object__load_vmlinux_btf(struct bpf_object *obj, bool force)
@@ -3590,7 +3590,11 @@ static int bpf_object__load_vmlinux_btf(struct bpf_object *obj, bool force)
int err;

/* btf_vmlinux could be loaded earlier */
- if (obj->btf_vmlinux || obj->gen_loader)
+ if (obj->btf_vmlinux)
+ return 0;
+
+ /* only struct_ops maps need btf_vmlinux in gen_loader */
+ if (obj->gen_loader && !obj_maps_need_vmlinux_btf(obj))
return 0;

if (!force && !obj_needs_vmlinux_btf(obj))

--
2.54.0.746.g67dd491aae-goog