The Linux Kernel Mailing List
 help / color / mirror / Atom feed
* [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons
@ 2026-05-27 12:52 Siddharth Nayyar
  2026-05-27 12:52 ` [PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops Siddharth Nayyar
                   ` (3 more replies)
  0 siblings, 4 replies; 10+ messages in thread
From: Siddharth Nayyar @ 2026-05-27 12:52 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa
  Cc: bpf, linux-kernel, gprocida, maennich, Siddharth Nayyar

This series enables support for BPF `STRUCT_OPS` maps (such as
`sched_ext_ops` used by sched_ext) when using light skeletons (i.e.
`gen_loader` mode).

Previously, generating light skeletons for objects containing
`STRUCT_OPS` maps would fail or produce incomplete results because
`gen_loader` lacked support for several key features required by
`STRUCT_OPS` maps, specifically:

1. Loading `vmlinux` BTF to resolve kernel-side type information.
2. Correctly plumbing `btf_vmlinux_value_type_id` into map creation
   attributes.
3. Ensuring `btf_key_type_id` is zeroed out to satisfy kernel safety
   checks.
4. Plumbing the userspace BTF FD (`btf_fd`) when
   `btf_vmlinux_value_type_id` is present but `btf_value_type_id` is
   zero (which is always the case for `STRUCT_OPS` maps).

This series addresses these limitations by:

- Loading `vmlinux` BTF in `gen_loader` mode when the BPF object
  contains `struct_ops` maps.
- Explicitly zeroing out `btf_key_type_id` for `STRUCT_OPS` maps to
  satisfy kernel validations.
- Plumbing `btf_vmlinux_value_type_id` during map creation in
  `gen_loader`.
- Fixing `btf_fd` copying logic in `gen_loader` to populate it if either
  `btf_value_type_id` or `btf_vmlinux_value_type_id` is set.

With these changes, it is now possible to generate and use light
skeletons for BPF programs utilizing `STRUCT_OPS`, such as custom
sched_ext schedulers.

Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
Changes in v4:
- Load btf_vmlinux in gen_loader mode only when BPF object contains
  STRUCT_OPS map.
- Link to v3:
  https://lore.kernel.org/r/20260526-libbpf-load-vmlinux-btf-in-gen_loader-mode-v3-0-5b4fa2a5e1a4@google.com

Changes in v3:
- Remove erroneous change contracting map creation attribute size in
  gen_loader.
- Link to v2:
  https://lore.kernel.org/r/20260526-libbpf-load-vmlinux-btf-in-gen_loader-mode-v2-0-6750f5859bc6@google.com

Changes in v2:
- Expand the series to 3 patches to fully support STRUCT_OPS in
  gen_loader.
- Add a patch to explicitly zero out btf_key_type_id for STRUCT_OPS
  maps.
- Add a patch to plumb btf_vmlinux_value_type_id and btf_fd in
  gen_loader.
- Link to v1:
  https://lore.kernel.org/r/20260524-libbpf-load-vmlinux-btf-in-gen_loader-mode-v1-1-6f57f191a7ad@google.com

---
Siddharth Nayyar (3):
      libbpf: load vmlinux BTF in gen_loader mode for struct_ops
      libbpf: zero out btf_key_type_id for STRUCT_OPS maps
      libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader

 tools/lib/bpf/gen_loader.c |  3 ++-
 tools/lib/bpf/libbpf.c     | 25 +++++++++++++++----------
 2 files changed, 17 insertions(+), 11 deletions(-)
---
base-commit: c6e99c10fd9855082568cbd71bb2cc5dc90eda53
change-id: 20260522-libbpf-load-vmlinux-btf-in-gen_loader-mode-4474834aa467

Best regards,
-- 
Siddharth Nayyar <sidnayyar@google.com>


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

* [PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops
  2026-05-27 12:52 [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Siddharth Nayyar
@ 2026-05-27 12:52 ` Siddharth Nayyar
  2026-05-27 13:39   ` bot+bpf-ci
  2026-05-27 12:52 ` [PATCH v4 2/3] libbpf: zero out btf_key_type_id for STRUCT_OPS maps Siddharth Nayyar
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 10+ messages in thread
From: Siddharth Nayyar @ 2026-05-27 12:52 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa
  Cc: bpf, linux-kernel, gprocida, maennich, Siddharth Nayyar

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@google.com>
---
 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


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

* [PATCH v4 2/3] libbpf: zero out btf_key_type_id for STRUCT_OPS maps
  2026-05-27 12:52 [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Siddharth Nayyar
  2026-05-27 12:52 ` [PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops Siddharth Nayyar
@ 2026-05-27 12:52 ` Siddharth Nayyar
  2026-05-27 13:39   ` bot+bpf-ci
  2026-05-27 12:52 ` [PATCH v4 3/3] libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader Siddharth Nayyar
  2026-05-28 21:35 ` [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Andrii Nakryiko
  3 siblings, 1 reply; 10+ messages in thread
From: Siddharth Nayyar @ 2026-05-27 12:52 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa
  Cc: bpf, linux-kernel, gprocida, maennich, Siddharth Nayyar

For BPF `STRUCT_OPS` maps (such as `sched_ext_ops` maps), the kernel BPF
subsystem enforces strict map-creation safety validations inside
`map_create()`.  That is, if `btf_vmlinux_value_type_id` is set, the
kernel forbids passing any userspace `btf_key_type_id` or
`btf_value_type_id` (they must both be `0`).

However, inside libbpf's map-creation options initialization
(`bpf_object__create_map()`), libbpf zeroed out
`create_attr.btf_value_type_id` but does not zero out
`create_attr.btf_key_type_id`.

Fix this by explicitly zeroing out `create_attr.btf_key_type_id`.

Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
 tools/lib/bpf/libbpf.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index b159faae7f9c..f9c653541005 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -5440,6 +5440,7 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
 		map->btf_value_type_id = 0;
 		break;
 	case BPF_MAP_TYPE_STRUCT_OPS:
+		create_attr.btf_key_type_id = 0;
 		create_attr.btf_value_type_id = 0;
 		break;
 	default:

-- 
2.54.0.746.g67dd491aae-goog


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

* [PATCH v4 3/3] libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader
  2026-05-27 12:52 [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Siddharth Nayyar
  2026-05-27 12:52 ` [PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops Siddharth Nayyar
  2026-05-27 12:52 ` [PATCH v4 2/3] libbpf: zero out btf_key_type_id for STRUCT_OPS maps Siddharth Nayyar
@ 2026-05-27 12:52 ` Siddharth Nayyar
  2026-05-27 13:39   ` bot+bpf-ci
  2026-05-28 21:35 ` [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Andrii Nakryiko
  3 siblings, 1 reply; 10+ messages in thread
From: Siddharth Nayyar @ 2026-05-27 12:52 UTC (permalink / raw)
  To: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa
  Cc: bpf, linux-kernel, gprocida, maennich, Siddharth Nayyar

BPF `STRUCT_OPS` maps (such as `sched_ext_ops` maps) require resolving
and plumbing the kernel-side structure value type ID
(`btf_vmlinux_value_type_id`) into the BPF map creation system call
attributes. Additionally, when `btf_vmlinux_value_type_id` is supplied,
the kernel requires a valid userspace BTF file descriptor (`btf_fd`) to
be supplied to verify types.

Previously, the `gen_loader` map creation generator
(`bpf_gen__map_create()`) omitted plumbing `btf_vmlinux_value_type_id`.
Furthermore, `gen_loader.c` only copied the loaded `btf_fd` from the
stack to the attributes blob if `btf_value_type_id` was non-zero.
Because `STRUCT_OPS` maps explicitly zero out `btf_value_type_id`, the
loader program skipped copying `btf_fd`, leaving it as `0` (standard
input), which caused the kernel's `btf_get_by_fd(0)` check to fail.

Fix this by:

1. Copying `btf_vmlinux_value_type_id` from the options inside
   `bpf_gen__map_create()`.
2. Modifying the `btf_fd` copying condition to populate `btf_fd` if
   either `btf_value_type_id` OR `btf_vmlinux_value_type_id` is set.

Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
---
 tools/lib/bpf/gen_loader.c | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c
index cd5c2543f54d..a9be0c241025 100644
--- a/tools/lib/bpf/gen_loader.c
+++ b/tools/lib/bpf/gen_loader.c
@@ -525,13 +525,14 @@ void bpf_gen__map_create(struct bpf_gen *gen,
 	attr.max_entries = tgt_endian(max_entries);
 	attr.btf_key_type_id = tgt_endian(map_attr->btf_key_type_id);
 	attr.btf_value_type_id = tgt_endian(map_attr->btf_value_type_id);
+	attr.btf_vmlinux_value_type_id = tgt_endian(map_attr->btf_vmlinux_value_type_id);
 
 	map_create_attr = add_data(gen, &attr, attr_size);
 	pr_debug("gen: map_create: %s idx %d type %d value_type_id %d, attr: off %d size %d\n",
 		 map_name, map_idx, map_type, map_attr->btf_value_type_id,
 		 map_create_attr, attr_size);
 
-	if (map_attr->btf_value_type_id)
+	if (map_attr->btf_value_type_id || map_attr->btf_vmlinux_value_type_id)
 		/* populate union bpf_attr with btf_fd saved in the stack earlier */
 		move_stack2blob(gen, attr_field(map_create_attr, btf_fd), 4,
 				stack_off(btf_fd));

-- 
2.54.0.746.g67dd491aae-goog


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

* Re: [PATCH v4 3/3] libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader
  2026-05-27 12:52 ` [PATCH v4 3/3] libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader Siddharth Nayyar
@ 2026-05-27 13:39   ` bot+bpf-ci
  0 siblings, 0 replies; 10+ messages in thread
From: bot+bpf-ci @ 2026-05-27 13:39 UTC (permalink / raw)
  To: sidnayyar, andrii, eddyz87, ast, daniel, martin.lau, memxor, song,
	yonghong.song, jolsa
  Cc: bpf, linux-kernel, gprocida, maennich, sidnayyar, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 4716 bytes --]

> diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c
> index 9478b8f78f26..b0d8551272f2 100644
> --- a/tools/lib/bpf/gen_loader.c
> +++ b/tools/lib/bpf/gen_loader.c
> @@ -525,13 +525,14 @@ void bpf_gen__map_create(struct bpf_gen *gen,
>  	attr.max_entries = tgt_endian(max_entries);
>  	attr.btf_key_type_id = tgt_endian(map_attr->btf_key_type_id);
>  	attr.btf_value_type_id = tgt_endian(map_attr->btf_value_type_id);
> +	attr.btf_vmlinux_value_type_id = tgt_endian(map_attr->btf_vmlinux_value_type_id);

Does hardcoding btf_vmlinux_value_type_id here break cross-kernel
portability for STRUCT_OPS light skeletons?

Light skeletons are designed to be portable across different kernel
versions without relying on libbpf at runtime. Because BTF type IDs are
not stable across kernel builds, passing the build machine's BTF ID to
the target kernel might cause the target kernel's sys_bpf(MAP_CREATE) to
resolve to the wrong type or fail entirely with -EINVAL.

Should gen_loader dynamically resolve the target kernel's BTF ID at
runtime, similarly to how it handles attach_btf_id?

>
>  	map_create_attr = add_data(gen, &attr, attr_size);

Does this also miss plumbing value_type_btf_obj_fd for STRUCT_OPS
interfaces defined in kernel modules?

When a STRUCT_OPS map targets a kernel module, libbpf sets
value_type_btf_obj_fd in bpf_map_create_opts and adds
BPF_F_VTYPE_BTF_OBJ_FD to map_flags. The patch propagates map_flags into
gen_loader's map creation attributes but ignores value_type_btf_obj_fd.

In bpf_gen__map_create(), attr_size is calculated as offsetofend(union
bpf_attr, map_extra), which truncates the struct before
value_type_btf_obj_fd. As a result, the generated loader program passes
the BPF_F_VTYPE_BTF_OBJ_FD flag to the kernel but implicitly provides 0
for the FD. The target kernel attempts to read BTF from fd=0 (stdin) and
rejects the map with -EINVAL.

Furthermore, even if the FD field were included, the loader cannot
hardcode the build machine's module FD; it must dynamically resolve the
module BTF FD on the target machine.

>  	pr_debug("gen: map_create: %s idx %d type %d value_type_id %d, attr: off %d size %d\n",
>  		 map_name, map_idx, map_type, map_attr->btf_value_type_id,
>  		 map_create_attr, attr_size);
>
> -	if (map_attr->btf_value_type_id)
> +	if (map_attr->btf_value_type_id || map_attr->btf_vmlinux_value_type_id)
>  		/* populate union bpf_attr with btf_fd saved in the stack earlier */
>  		move_stack2blob(gen, attr_field(map_create_attr, btf_fd), 4,
>  				stack_off(btf_fd));

--- Commit Message ---

>     libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader
>
>     BPF `STRUCT_OPS` maps (such as `sched_ext_ops` maps) require resolving
>     and plumbing the kernel-side structure value type ID
>     (`btf_vmlinux_value_type_id`) into the BPF map creation system call
>     attributes. Additionally, when `btf_vmlinux_value_type_id` is supplied,
>     the kernel requires a valid userspace BTF file descriptor (`btf_fd`) to
>     be supplied to verify types.
>
>     Previously, the `gen_loader` map creation generator
>     (`bpf_gen__map_create()`) omitted plumbing `btf_vmlinux_value_type_id`.
>     Furthermore, `gen_loader.c` only copied the loaded `btf_fd` from the
>     stack to the attributes blob if `btf_value_type_id` was non-zero.
>     Because `STRUCT_OPS` maps explicitly zero out `btf_value_type_id`, the
>     loader program skipped copying `btf_fd`, leaving it as `0` (standard
>     input), which caused the kernel's `btf_get_by_fd(0)` check to fail.
>
>     Fix this by:
>
>     1. Copying `btf_vmlinux_value_type_id` from the options inside
>        `bpf_gen__map_create()`.
>     2. Modifying the `btf_fd` copying condition to populate `btf_fd` if
>        either `btf_value_type_id` OR `btf_vmlinux_value_type_id` is set.
>
>     Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>

This looks like a bug fix for STRUCT_OPS map creation in gen_loader. The
bug was introduced in commit 67234743736a ("libbpf: Generate loader
program out of BPF ELF file.") which created gen_loader.c but omitted
copying btf_vmlinux_value_type_id to the map creation attributes and only
conditionally copied btf_fd when btf_value_type_id was set. This caused
STRUCT_OPS maps (which zero out btf_value_type_id but set
btf_vmlinux_value_type_id) to fail with btf_get_by_fd(0) errors. Should
this include:

  Fixes: 67234743736a ("libbpf: Generate loader program out of BPF ELF file.")


---
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/26512949106

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

* Re: [PATCH v4 2/3] libbpf: zero out btf_key_type_id for STRUCT_OPS maps
  2026-05-27 12:52 ` [PATCH v4 2/3] libbpf: zero out btf_key_type_id for STRUCT_OPS maps Siddharth Nayyar
@ 2026-05-27 13:39   ` bot+bpf-ci
  0 siblings, 0 replies; 10+ messages in thread
From: bot+bpf-ci @ 2026-05-27 13:39 UTC (permalink / raw)
  To: sidnayyar, andrii, eddyz87, ast, daniel, martin.lau, memxor, song,
	yonghong.song, jolsa
  Cc: bpf, linux-kernel, gprocida, maennich, sidnayyar, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 3475 bytes --]

> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index 420d37f215ea..673fa0242b4c 100644
> --- a/tools/lib/bpf/libbpf.c
> +++ b/tools/lib/bpf/libbpf.c
> @@ -5440,6 +5440,7 @@ static int bpf_object__create_map(struct bpf_object *obj, struct bpf_map *map, b
>  		map->btf_value_type_id = 0;
>  		break;
>  	case BPF_MAP_TYPE_STRUCT_OPS:
> +		create_attr.btf_key_type_id = 0;
>  		create_attr.btf_value_type_id = 0;
>  		break;
>  	default:

This change fixes the issue in bpf_object__create_map(), but what about
gen_loader mode?

In bpf_gen__map_create() (tools/lib/bpf/gen_loader.c), when
btf_vmlinux_value_type_id is set for STRUCT_OPS maps, it's not copied
to the attr structure:

    attr.btf_key_type_id = tgt_endian(map_attr->btf_key_type_id);
    attr.btf_value_type_id = tgt_endian(map_attr->btf_value_type_id);
    /* btf_vmlinux_value_type_id is never copied */

This means gen_loader mode (light skeletons) will pass
btf_vmlinux_value_type_id=0 to the kernel, breaking STRUCT_OPS map
creation. Does this need to be addressed?

Also, the conditional that copies btf_fd in bpf_gen__map_create():

    if (map_attr->btf_value_type_id)
        move_stack2blob(gen, attr_field(map_create_attr, btf_fd), 4,
                        stack_off(btf_fd));

This condition evaluates to false for STRUCT_OPS maps since
btf_value_type_id is now explicitly zeroed. Won't this prevent
btf_fd from being copied to the kernel attributes?

The kernel expects a valid btf_fd even for STRUCT_OPS maps (see
kernel/bpf/syscall.c comments: "Even the map's value is a kernel's
struct, the bpf_prog.o must have BTF to begin with to figure out
the corresponding kernel's counter part."). Without btf_fd,
btf_get_by_fd(0) will fail.

It looks like both of these issues are fixed in the next commit
(fe6415fcc857b593808826b2e8d157237162782b), but should they be addressed
in this patch to avoid bisection breakage?

Regarding the commit message:

> libbpf: zero out btf_key_type_id for STRUCT_OPS maps
>
> For BPF `STRUCT_OPS` maps (such as `sched_ext_ops` maps), the kernel BPF
> subsystem enforces strict map-creation safety validations inside
> `map_create()`.  That is, if `btf_vmlinux_value_type_id` is set, the
> kernel forbids passing any userspace `btf_key_type_id` or
> `btf_value_type_id` (they must both be `0`).
>
> However, inside libbpf's map-creation options initialization
> (`bpf_object__create_map()`), libbpf zeroed out
> `create_attr.btf_value_type_id` but does not zero out
> `create_attr.btf_key_type_id`.
>
> Fix this by explicitly zeroing out `create_attr.btf_key_type_id`.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>

This looks like a bug fix but lacks a Fixes: tag. The bug was
introduced when STRUCT_OPS support was added to libbpf. Should this
include:

  Fixes: 590a00888250 ("bpf: libbpf: Add STRUCT_OPS support")

Also, Alexei Starovoitov requested a selftest in v3 of the patch series:

  "The selftest is mandatory to prove that."

  https://lore.kernel.org/bpf/CAADnVQ+AA_fmRw7uRwdL2TMyMbpWeebOQKb=0wvpKiQR6Ee5xQ@mail.gmail.com/

Has this been addressed in v4? Without a selftest proving that
STRUCT_OPS maps work correctly in light skeleton mode, how can we
verify the fix is complete?


---
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/26512949106

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

* Re: [PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops
  2026-05-27 12:52 ` [PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops Siddharth Nayyar
@ 2026-05-27 13:39   ` bot+bpf-ci
  2026-05-27 14:17     ` Alexei Starovoitov
  0 siblings, 1 reply; 10+ messages in thread
From: bot+bpf-ci @ 2026-05-27 13:39 UTC (permalink / raw)
  To: sidnayyar, andrii, eddyz87, ast, daniel, martin.lau, memxor, song,
	yonghong.song, jolsa
  Cc: bpf, linux-kernel, gprocida, maennich, sidnayyar, ast, andrii,
	daniel, martin.lau, eddyz87, yonghong.song, clm, ihor.solodrai

[-- Attachment #1: Type: text/plain, Size: 3757 bytes --]

> commit 29cedaf6d7d80a7e880a2e639f40fbafcbaf2e65
> Author: Siddharth Nayyar <sidnayyar@google.com>
> Date:   Wed May 27 12:52:57 2026 +0000
>
>     libbpf: load vmlinux BTF in gen_loader mode for struct_ops
>
>     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@google.com>

Alexei Starovoitov requested in v3 review that a selftest be added to
prove struct_ops light skeletons work end-to-end:

  "The selftest is mandatory to prove that."
  https://lore.kernel.org/bpf/CAADnVQ+AA_fmRw7uRwdL2TMyMbpWeebOQKb=0wvpKiQR6Ee5xQ@mail.gmail.com/

This requirement has not been addressed in v4. Should a selftest be added
to demonstrate that struct_ops light skeletons work correctly with this
change?

> diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
> index ab2071fdd3e8..420d37f215ea 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))

This looks like a bug fix for gen_loader mode with struct_ops maps.
Multiple CI reviews (v1 and v3) noted that this should include:

  Fixes: 67234743736a ("libbpf: Generate loader program out of BPF ELF file.")
  https://lore.kernel.org/bpf/b4b4ca51ae8e281a37707cbcd2ba8349dabc6c630e96461929be0872fd8ed0e6@mail.kernel.org/

Should this tag be added to indicate it fixes a limitation in the original
gen_loader implementation?


---
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/26512949106

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

* Re: [PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops
  2026-05-27 13:39   ` bot+bpf-ci
@ 2026-05-27 14:17     ` Alexei Starovoitov
  0 siblings, 0 replies; 10+ messages in thread
From: Alexei Starovoitov @ 2026-05-27 14:17 UTC (permalink / raw)
  To: bot+bpf-ci, sidnayyar, andrii, eddyz87, ast, daniel, martin.lau,
	memxor, song, yonghong.song, jolsa
  Cc: bpf, linux-kernel, gprocida, maennich, martin.lau, clm,
	ihor.solodrai

On Wed May 27, 2026 at 6:39 AM PDT, bot+bpf-ci wrote:
>> commit 29cedaf6d7d80a7e880a2e639f40fbafcbaf2e65
>> Author: Siddharth Nayyar <sidnayyar@google.com>
>> Date:   Wed May 27 12:52:57 2026 +0000
>>
>>     libbpf: load vmlinux BTF in gen_loader mode for struct_ops
>>
>>     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@google.com>
>
> Alexei Starovoitov requested in v3 review that a selftest be added to
> prove struct_ops light skeletons work end-to-end:
>
>   "The selftest is mandatory to prove that."
>   https://lore.kernel.org/bpf/CAADnVQ+AA_fmRw7uRwdL2TMyMbpWeebOQKb=0wvpKiQR6Ee5xQ@mail.gmail.com/
>
> This requirement has not been addressed in v4. Should a selftest be added
> to demonstrate that struct_ops light skeletons work correctly with this
> change?

thanks bot.

pw-bot: cr

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

* Re: [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons
  2026-05-27 12:52 [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Siddharth Nayyar
                   ` (2 preceding siblings ...)
  2026-05-27 12:52 ` [PATCH v4 3/3] libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader Siddharth Nayyar
@ 2026-05-28 21:35 ` Andrii Nakryiko
  2026-05-29 10:31   ` Sid Nayyar
  3 siblings, 1 reply; 10+ messages in thread
From: Andrii Nakryiko @ 2026-05-28 21:35 UTC (permalink / raw)
  To: Siddharth Nayyar
  Cc: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, bpf, linux-kernel, gprocida,
	maennich

On Wed, May 27, 2026 at 5:53 AM Siddharth Nayyar <sidnayyar@google.com> wrote:
>
> This series enables support for BPF `STRUCT_OPS` maps (such as
> `sched_ext_ops` used by sched_ext) when using light skeletons (i.e.
> `gen_loader` mode).
>
> Previously, generating light skeletons for objects containing
> `STRUCT_OPS` maps would fail or produce incomplete results because
> `gen_loader` lacked support for several key features required by
> `STRUCT_OPS` maps, specifically:
>
> 1. Loading `vmlinux` BTF to resolve kernel-side type information.
> 2. Correctly plumbing `btf_vmlinux_value_type_id` into map creation
>    attributes.
> 3. Ensuring `btf_key_type_id` is zeroed out to satisfy kernel safety
>    checks.
> 4. Plumbing the userspace BTF FD (`btf_fd`) when
>    `btf_vmlinux_value_type_id` is present but `btf_value_type_id` is
>    zero (which is always the case for `STRUCT_OPS` maps).
>
> This series addresses these limitations by:
>
> - Loading `vmlinux` BTF in `gen_loader` mode when the BPF object
>   contains `struct_ops` maps.
> - Explicitly zeroing out `btf_key_type_id` for `STRUCT_OPS` maps to
>   satisfy kernel validations.
> - Plumbing `btf_vmlinux_value_type_id` during map creation in
>   `gen_loader`.

this type ID search has to happen on target kernel at runtime,
otherwise your lskel will be bound to work only on exact kernel you
used to run bpftool to generate lskel

> - Fixing `btf_fd` copying logic in `gen_loader` to populate it if either
>   `btf_value_type_id` or `btf_vmlinux_value_type_id` is set.
>
> With these changes, it is now possible to generate and use light
> skeletons for BPF programs utilizing `STRUCT_OPS`, such as custom
> sched_ext schedulers.
>
> Signed-off-by: Siddharth Nayyar <sidnayyar@google.com>
> ---
> Changes in v4:
> - Load btf_vmlinux in gen_loader mode only when BPF object contains
>   STRUCT_OPS map.
> - Link to v3:
>   https://lore.kernel.org/r/20260526-libbpf-load-vmlinux-btf-in-gen_loader-mode-v3-0-5b4fa2a5e1a4@google.com
>
> Changes in v3:
> - Remove erroneous change contracting map creation attribute size in
>   gen_loader.
> - Link to v2:
>   https://lore.kernel.org/r/20260526-libbpf-load-vmlinux-btf-in-gen_loader-mode-v2-0-6750f5859bc6@google.com
>
> Changes in v2:
> - Expand the series to 3 patches to fully support STRUCT_OPS in
>   gen_loader.
> - Add a patch to explicitly zero out btf_key_type_id for STRUCT_OPS
>   maps.
> - Add a patch to plumb btf_vmlinux_value_type_id and btf_fd in
>   gen_loader.
> - Link to v1:
>   https://lore.kernel.org/r/20260524-libbpf-load-vmlinux-btf-in-gen_loader-mode-v1-1-6f57f191a7ad@google.com
>
> ---
> Siddharth Nayyar (3):
>       libbpf: load vmlinux BTF in gen_loader mode for struct_ops
>       libbpf: zero out btf_key_type_id for STRUCT_OPS maps
>       libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader
>
>  tools/lib/bpf/gen_loader.c |  3 ++-
>  tools/lib/bpf/libbpf.c     | 25 +++++++++++++++----------
>  2 files changed, 17 insertions(+), 11 deletions(-)
> ---
> base-commit: c6e99c10fd9855082568cbd71bb2cc5dc90eda53
> change-id: 20260522-libbpf-load-vmlinux-btf-in-gen_loader-mode-4474834aa467
>
> Best regards,
> --
> Siddharth Nayyar <sidnayyar@google.com>
>

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

* Re: [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons
  2026-05-28 21:35 ` [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Andrii Nakryiko
@ 2026-05-29 10:31   ` Sid Nayyar
  0 siblings, 0 replies; 10+ messages in thread
From: Sid Nayyar @ 2026-05-29 10:31 UTC (permalink / raw)
  To: Andrii Nakryiko
  Cc: Andrii Nakryiko, Eduard Zingerman, Alexei Starovoitov,
	Daniel Borkmann, Martin KaFai Lau, Kumar Kartikeya Dwivedi,
	Song Liu, Yonghong Song, Jiri Olsa, bpf, linux-kernel, gprocida,
	maennich

On Thu, May 28, 2026 at 10:35 PM Andrii Nakryiko
<andrii.nakryiko@gmail.com> wrote:
>
> On Wed, May 27, 2026 at 5:53 AM Siddharth Nayyar <sidnayyar@google.com> wrote:
> >
> > This series enables support for BPF `STRUCT_OPS` maps (such as
> > `sched_ext_ops` used by sched_ext) when using light skeletons (i.e.
> > `gen_loader` mode).
> >
> > Previously, generating light skeletons for objects containing
> > `STRUCT_OPS` maps would fail or produce incomplete results because
> > `gen_loader` lacked support for several key features required by
> > `STRUCT_OPS` maps, specifically:
> >
> > 1. Loading `vmlinux` BTF to resolve kernel-side type information.
> > 2. Correctly plumbing `btf_vmlinux_value_type_id` into map creation
> >    attributes.
> > 3. Ensuring `btf_key_type_id` is zeroed out to satisfy kernel safety
> >    checks.
> > 4. Plumbing the userspace BTF FD (`btf_fd`) when
> >    `btf_vmlinux_value_type_id` is present but `btf_value_type_id` is
> >    zero (which is always the case for `STRUCT_OPS` maps).
> >
> > This series addresses these limitations by:
> >
> > - Loading `vmlinux` BTF in `gen_loader` mode when the BPF object
> >   contains `struct_ops` maps.
> > - Explicitly zeroing out `btf_key_type_id` for `STRUCT_OPS` maps to
> >   satisfy kernel validations.
> > - Plumbing `btf_vmlinux_value_type_id` during map creation in
> >   `gen_loader`.
>
> this type ID search has to happen on target kernel at runtime,
> otherwise your lskel will be bound to work only on exact kernel you
> used to run bpftool to generate lskel

Thank you for pointing this out. I realized the flaw in my approach
shortly after sending these patches. You're absolutely right,
performing the type ID search at generation time would incorrectly
bind the light skeleton to the specific kernel used during the bpftool
run.

I am currently working on a more robust solution that handles the
STRUCT_OPS type ID resolution on the target kernel at runtime. I’ll
follow up with a revised series once I have properly addressed this.

Regards,
Siddharth Nayyar

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

end of thread, other threads:[~2026-05-29 10:31 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-27 12:52 [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Siddharth Nayyar
2026-05-27 12:52 ` [PATCH v4 1/3] libbpf: load vmlinux BTF in gen_loader mode for struct_ops Siddharth Nayyar
2026-05-27 13:39   ` bot+bpf-ci
2026-05-27 14:17     ` Alexei Starovoitov
2026-05-27 12:52 ` [PATCH v4 2/3] libbpf: zero out btf_key_type_id for STRUCT_OPS maps Siddharth Nayyar
2026-05-27 13:39   ` bot+bpf-ci
2026-05-27 12:52 ` [PATCH v4 3/3] libbpf: plumb btf_vmlinux_value_type_id and btf_fd in gen_loader Siddharth Nayyar
2026-05-27 13:39   ` bot+bpf-ci
2026-05-28 21:35 ` [PATCH v4 0/3] libbpf: support STRUCT_OPS in light skeletons Andrii Nakryiko
2026-05-29 10:31   ` Sid Nayyar

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox