mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons
@ 2026-09-18  4:09 Thiébaud Weksteen
  2026-09-18  4:09 ` [PATCH bpf-next v3 2/3] bpftool: Compute light skeleton ctx.sz without relying on links Thiébaud Weksteen
                   ` (2 more replies)
  0 siblings, 3 replies; 6+ messages in thread
From: Thiébaud Weksteen @ 2026-09-18  4:09 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Shuah Khan, Thiébaud Weksteen, KP Singh, Leon Hwang,
	Emil Tsalapatis
  Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Ihor Solodrai, bpf, linux-kernel, linux-kselftest

When generating a light skeleton (bpftool gen skeleton -L),
bpf_object__load() skips loading programs marked as non-autoload (e.g.
SEC("?...")), so the generated loader program only records and populates
file descriptors for autoloaded programs.

Previously, bpftool emitted struct bpf_prog_desc fields, link fields,
and attach/detach/destroy functions for all programs in the BPF object,
causing the loader program to store subsequent program FDs into
incorrect skeleton struct fields when non-autoload programs were
present.

Furthermore, bpf_object__load() can update a program's autoload status
during preparation (e.g. for struct_ops programs when resolving kernel
BTF members or adjusting autoload based on map autocreate settings).
Move bpf_object__gen_loader() and bpf_object__load() out of gen_trace()
into do_skeleton() before counting programs and emitting struct fields so
that struct field declarations and attach/detach/destroy functions all
observe the final post-load autoload state.

Skip programs with !bpf_program__autoload(prog) when counting programs
and generating progs/links struct fields as well as attach, detach, and
destroy functions for light skeletons.

Fixes: d510296d331a ("bpftool: Use syscall/loader program in "prog load" and "gen skeleton" command.")
Signed-off-by: Thiébaud Weksteen <tweek@google.com>
---
v2 -> v3:
  - Move comment from gen_trace() to do_skeleton()
  - Add comment to do_skeleton() why the loader is called early
v1 -> v2:
  - Move bpf_object__gen_loader() and bpf_object__load() out of gen_trace()

 .../bpf/bpftool/Documentation/bpftool-gen.rst |  4 +-
 tools/bpf/bpftool/gen.c                       | 76 ++++++++++++-------
 2 files changed, 52 insertions(+), 28 deletions(-)

diff --git a/tools/bpf/bpftool/Documentation/bpftool-gen.rst b/tools/bpf/bpftool/Documentation/bpftool-gen.rst
index d0a36f442db7..1cdecf3e4fa5 100644
--- a/tools/bpf/bpftool/Documentation/bpftool-gen.rst
+++ b/tools/bpf/bpftool/Documentation/bpftool-gen.rst
@@ -184,7 +184,9 @@ OPTIONS
 -L, --use-loader
     For skeletons, generate a "light" skeleton (also known as "loader"
     skeleton). A light skeleton contains a loader eBPF program. It does not use
-    the majority of the libbpf infrastructure, and does not need libelf.
+    the majority of the libbpf infrastructure, and does not need libelf. BPF
+    programs marked as non-autoload (e.g., via **SEC("?...")**) are skipped and
+    not included in the generated skeleton.
 
 -S, --sign
     For skeletons, generate a signed skeleton. This option must be used with
diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index a50540ef6521..1e55f0e67d91 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -583,6 +583,9 @@ static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
 	bpf_object__for_each_program(prog, obj) {
 		const char *tp_name;
 
+		if (!bpf_program__autoload(prog))
+			continue;
+
 		codegen("\
 			\n\
 			\n\
@@ -629,6 +632,8 @@ static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
 		", obj_name);
 
 	bpf_object__for_each_program(prog, obj) {
+		if (!bpf_program__autoload(prog))
+			continue;
 		codegen("\
 			\n\
 				ret = ret < 0 ? ret : %1$s__%2$s__attach(skel);   \n\
@@ -646,6 +651,8 @@ static void codegen_attach_detach(struct bpf_object *obj, const char *obj_name)
 		", obj_name);
 
 	bpf_object__for_each_program(prog, obj) {
+		if (!bpf_program__autoload(prog))
+			continue;
 		codegen("\
 			\n\
 				skel_closenz(skel->links.%1$s_fd);	    \n\
@@ -676,6 +683,8 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
 		obj_name);
 
 	bpf_object__for_each_program(prog, obj) {
+		if (!bpf_program__autoload(prog))
+			continue;
 		codegen("\
 			\n\
 				skel_closenz(skel->progs.%1$s.prog_fd);	    \n\
@@ -701,9 +710,9 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
 		obj_name);
 }
 
-static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard)
+static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard,
+		     const struct gen_loader_opts *opts)
 {
-	DECLARE_LIBBPF_OPTS(gen_loader_opts, opts);
 	struct bpf_load_and_run_opts sopts = {};
 	char sig_buf[MAX_SIG_SIZE];
 	__u8 prog_sha[SHA256_DIGEST_LENGTH];
@@ -712,23 +721,6 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 	char ident[256];
 	int err = 0;
 
-	if (sign_progs)
-		opts.gen_hash = true;
-
-	err = bpf_object__gen_loader(obj, &opts);
-	if (err)
-		return err;
-
-	err = bpf_object__load(obj);
-	if (err) {
-		p_err("failed to load object file");
-		goto out;
-	}
-
-	/* If there was no error during load then gen_loader_opts
-	 * are populated with the loader program.
-	 */
-
 	/* finish generating 'struct skel' */
 	codegen("\
 		\n\
@@ -752,7 +744,7 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 				goto cleanup;				    \n\
 			skel->ctx.sz = (char *)&skel->links - (char *)skel; \n\
 		",
-		obj_name, opts.data_sz);
+		obj_name, opts->data_sz);
 	bpf_object__for_each_map(map, obj) {
 		const void *mmap_data = NULL;
 		size_t mmap_size = 0;
@@ -795,22 +787,22 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 			static const char opts_data[] __attribute__((__aligned__(8))) = \"\\\n\
 		",
 		obj_name);
-	print_hex(opts.data, opts.data_sz);
+	print_hex(opts->data, opts->data_sz);
 	codegen("\
 		\n\
 		\";							    \n\
 			static const char opts_insn[] __attribute__((__aligned__(8))) = \"\\\n\
 		");
-	print_hex(opts.insns, opts.insns_sz);
+	print_hex(opts->insns, opts->insns_sz);
 	codegen("\
 		\n\
 		\";\n");
 
 	if (sign_progs) {
-		sopts.insns = opts.insns;
-		sopts.insns_sz = opts.insns_sz;
-		sopts.data = opts.data;
-		sopts.data_sz = opts.data_sz;
+		sopts.insns = opts->insns;
+		sopts.insns_sz = opts->insns_sz;
+		sopts.data = opts->data;
+		sopts.data_sz = opts->data_sz;
 		sopts.excl_prog_hash = prog_sha;
 		sopts.excl_prog_hash_sz = sizeof(prog_sha);
 		sopts.signature = sig_buf;
@@ -1250,6 +1242,7 @@ static int do_skeleton(int argc, char **argv)
 	char header_guard[MAX_OBJ_NAME_LEN + sizeof("__SKEL_H__")];
 	size_t map_cnt = 0, prog_cnt = 0, attach_map_cnt = 0, file_sz, mmap_sz;
 	DECLARE_LIBBPF_OPTS(bpf_object_open_opts, opts);
+	DECLARE_LIBBPF_OPTS(gen_loader_opts, gen_opts);
 	char obj_name[MAX_OBJ_NAME_LEN] = "", *obj_data;
 	struct bpf_object *obj = NULL;
 	const char *file;
@@ -1326,6 +1319,29 @@ static int do_skeleton(int argc, char **argv)
 		goto out_obj;
 	}
 
+	/* If we are generating a loader, load the object early (before
+	 * counting programs and emitting skeleton struct definitions), as
+	 * bpf_object__load() may disable (i.e., autoload=false) some programs
+	 * if their requirements are not met.
+	 */
+	if (use_loader) {
+		if (sign_progs)
+			gen_opts.gen_hash = true;
+
+		err = bpf_object__gen_loader(obj, &gen_opts);
+		if (err)
+			goto out;
+
+		err = bpf_object__load(obj);
+		if (err) {
+			p_err("failed to load object file");
+			goto out;
+		}
+		/* If there was no error during load, gen_opts is populated with
+		 * the loader program.
+		 */
+	}
+
 	bpf_object__for_each_map(map, obj) {
 		if (!get_map_ident(map, ident, sizeof(ident))) {
 			p_err("ignoring unrecognized internal map '%s'...",
@@ -1339,6 +1355,8 @@ static int do_skeleton(int argc, char **argv)
 		map_cnt++;
 	}
 	bpf_object__for_each_program(prog, obj) {
+		if (use_loader && !bpf_program__autoload(prog))
+			continue;
 		prog_cnt++;
 	}
 
@@ -1402,6 +1420,8 @@ static int do_skeleton(int argc, char **argv)
 	if (prog_cnt) {
 		printf("\tstruct {\n");
 		bpf_object__for_each_program(prog, obj) {
+			if (use_loader && !bpf_program__autoload(prog))
+				continue;
 			if (use_loader)
 				printf("\t\tstruct bpf_prog_desc %s;\n",
 				       bpf_program__name(prog));
@@ -1415,6 +1435,8 @@ static int do_skeleton(int argc, char **argv)
 	if (prog_cnt + attach_map_cnt) {
 		printf("\tstruct {\n");
 		bpf_object__for_each_program(prog, obj) {
+			if (use_loader && !bpf_program__autoload(prog))
+				continue;
 			if (use_loader)
 				printf("\t\tint %s_fd;\n",
 				       bpf_program__name(prog));
@@ -1451,7 +1473,7 @@ static int do_skeleton(int argc, char **argv)
 			goto out;
 	}
 	if (use_loader) {
-		err = gen_trace(obj, obj_name, header_guard);
+		err = gen_trace(obj, obj_name, header_guard, &gen_opts);
 		goto out;
 	}
 
-- 
2.55.0.1082.g2b9226bbc0-goog


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

* [PATCH bpf-next v3 2/3] bpftool: Compute light skeleton ctx.sz without relying on links
  2026-09-18  4:09 [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons Thiébaud Weksteen
@ 2026-09-18  4:09 ` Thiébaud Weksteen
  2026-09-18  8:42   ` Quentin Monnet
  2026-09-18  4:09 ` [PATCH bpf-next v3 3/3] selftests/bpf: Add iter subtest using lskel in global_data_init Thiébaud Weksteen
  2026-09-18  8:43 ` [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons Quentin Monnet
  2 siblings, 1 reply; 6+ messages in thread
From: Thiébaud Weksteen @ 2026-09-18  4:09 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Shuah Khan, Thiébaud Weksteen, KP Singh, Leon Hwang,
	Emil Tsalapatis
  Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Ihor Solodrai, bpf, linux-kernel, linux-kselftest

When generating a light skeleton, gen_trace() unconditionally sets
skel->ctx.sz using (char *)&skel->links - (char *)skel. However, if a
BPF object has no programs and no struct_ops maps (prog_cnt +
attach_map_cnt == 0), do_skeleton() omits the links struct, causing the
generated skeleton header to fail compilation.

Compute skel->ctx.sz from the end of progs (if prog_cnt > 0), maps (if
map_cnt > 0), or ctx instead of relying on skel->links. Also remove the
unused opts.data_sz argument passed to codegen().

Fixes: d510296d331a ("bpftool: Use syscall/loader program in "prog load" and "gen skeleton" command.")
Signed-off-by: Thiébaud Weksteen <tweek@google.com>
---
No changes since v2

 tools/bpf/bpftool/gen.c | 15 +++++++++++----
 1 file changed, 11 insertions(+), 4 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index 1e55f0e67d91..b275373b3781 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -711,7 +711,7 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
 }
 
 static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *header_guard,
-		     const struct gen_loader_opts *opts)
+		     const struct gen_loader_opts *opts, size_t prog_cnt, size_t map_cnt)
 {
 	struct bpf_load_and_run_opts sopts = {};
 	char sig_buf[MAX_SIG_SIZE];
@@ -742,9 +742,16 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 			skel = (struct %1$s *)skel_alloc(sizeof(*skel));    \n\
 			if (!skel)					    \n\
 				goto cleanup;				    \n\
-			skel->ctx.sz = (char *)&skel->links - (char *)skel; \n\
 		",
-		obj_name, opts->data_sz);
+		obj_name);
+	if (prog_cnt)
+		printf("\tskel->ctx.sz = (char *)&skel->progs - (char *)skel\n"
+		       "\t\t       + sizeof(skel->progs);\n");
+	else if (map_cnt)
+		printf("\tskel->ctx.sz = (char *)&skel->maps - (char *)skel\n"
+		       "\t\t       + sizeof(skel->maps);\n");
+	else
+		printf("\tskel->ctx.sz = sizeof(skel->ctx);\n");
 	bpf_object__for_each_map(map, obj) {
 		const void *mmap_data = NULL;
 		size_t mmap_size = 0;
@@ -1473,7 +1480,7 @@ static int do_skeleton(int argc, char **argv)
 			goto out;
 	}
 	if (use_loader) {
-		err = gen_trace(obj, obj_name, header_guard, &gen_opts);
+		err = gen_trace(obj, obj_name, header_guard, &gen_opts, prog_cnt, map_cnt);
 		goto out;
 	}
 
-- 
2.55.0.1082.g2b9226bbc0-goog


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

* [PATCH bpf-next v3 3/3] selftests/bpf: Add iter subtest using lskel in global_data_init
  2026-09-18  4:09 [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons Thiébaud Weksteen
  2026-09-18  4:09 ` [PATCH bpf-next v3 2/3] bpftool: Compute light skeleton ctx.sz without relying on links Thiébaud Weksteen
@ 2026-09-18  4:09 ` Thiébaud Weksteen
  2026-09-18  5:05   ` bot+bpf-ci
  2026-09-18  8:43 ` [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons Quentin Monnet
  2 siblings, 1 reply; 6+ messages in thread
From: Thiébaud Weksteen @ 2026-09-18  4:09 UTC (permalink / raw)
  To: Quentin Monnet, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Shuah Khan, Thiébaud Weksteen, KP Singh, Leon Hwang,
	Emil Tsalapatis
  Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Ihor Solodrai, bpf, linux-kernel, linux-kselftest

In test_global_percpu_data.c, dump_percpu_data is defined after two
non-autoload SEC("?kprobe") programs (verifier_strncmp and
verifier_snprintf). If bpftool does not skip non-autoload programs when
generating light skeletons, dump_percpu_data.prog_fd is left invalid or
unpopulated.

Factor out a test_global_percpu_data_iter_fd() helper that operates
directly on prog/map file descriptors, and add an iter_lskel subtest to
verify that dump_percpu_data is properly loaded and executes correctly
when using the light skeleton.

Fixes: 4c9241bd731a ("selftests/bpf: Add tests to verify global percpu data")
Fixes: 1ed2294b31fc ("selftests/bpf: Test verifier log for global percpu data")
Signed-off-by: Thiébaud Weksteen <tweek@google.com>
---
v2 -> v3:
  - Running the iter subtest against the lskel.
  - Factor out test_global_percpu_data_iter_fd into a helper.
  - Restore Fixes footers.
v1 -> v2: 
  - Accidentally dropped Fixes footers.

 .../bpf/prog_tests/global_data_init.c         | 92 ++++++++++++++-----
 1 file changed, 69 insertions(+), 23 deletions(-)

diff --git a/tools/testing/selftests/bpf/prog_tests/global_data_init.c b/tools/testing/selftests/bpf/prog_tests/global_data_init.c
index 7c539cbcf3a1..797590127787 100644
--- a/tools/testing/selftests/bpf/prog_tests/global_data_init.c
+++ b/tools/testing/selftests/bpf/prog_tests/global_data_init.c
@@ -375,15 +375,43 @@ static void test_global_percpu_data_verifier_log(void)
 	RUN_TESTS(test_global_percpu_data);
 }
 
-static void test_global_percpu_data_iter(void)
+static void test_global_percpu_data_iter_fd(int prog_fd, int map_fd, int num_cpus,
+					    bool *run_iter, __u32 *sum)
 {
-	DECLARE_LIBBPF_OPTS(bpf_iter_attach_opts, opts);
-	struct test_global_percpu_data *skel;
+	DECLARE_LIBBPF_OPTS(bpf_link_create_opts, opts);
 	union bpf_iter_link_info linfo = {};
-	struct bpf_link *link = NULL;
-	int fd, num_cpus, len, err;
+	int link_fd, iter_fd, len;
 	char buf[16];
 
+	linfo.map.map_fd = map_fd;
+	opts.iter_info = &linfo;
+	opts.iter_info_len = sizeof(linfo);
+
+	link_fd = bpf_link_create(prog_fd, 0, BPF_TRACE_ITER, &opts);
+	if (!ASSERT_GE(link_fd, 0, "bpf_link_create"))
+		return;
+
+	iter_fd = bpf_iter_create(link_fd);
+	if (!ASSERT_GE(iter_fd, 0, "bpf_iter_create"))
+		goto out;
+
+	while ((len = read(iter_fd, buf, sizeof(buf))) > 0) {
+		/* no-op */
+	}
+	ASSERT_EQ(len, 0, "read iter");
+	ASSERT_TRUE(*run_iter, "run_iter");
+	ASSERT_EQ(*sum, 0xc0de * num_cpus, "sum");
+
+	close(iter_fd);
+out:
+	close(link_fd);
+}
+
+static void test_global_percpu_data_iter(void)
+{
+	struct test_global_percpu_data *skel;
+	int num_cpus, err;
+
 	num_cpus = libbpf_num_possible_cpus();
 	if (!ASSERT_GT(num_cpus, 0, "libbpf_num_possible_cpus"))
 		return;
@@ -395,34 +423,50 @@ static void test_global_percpu_data_iter(void)
 	skel->rodata->num_cpus = num_cpus;
 	skel->rodata->num_off = offsetof(struct test_global_percpu_data__percpu,
 					 struct_data.nums[6]);
-	skel->rodata->elem_sz = roundup(sizeof(struct test_global_percpu_data__percpu), 8);
+	skel->rodata->elem_sz = roundup(sizeof(*skel->percpu), 8);
 	skel->percpu->struct_data.nums[6] = 0xc0de;
 
 	err = test_global_percpu_data__load(skel);
 	if (!ASSERT_OK(err, "test_global_percpu_data__load"))
 		goto out;
 
-	linfo.map.map_fd = bpf_map__fd(skel->maps.percpu);
-	opts.link_info = &linfo;
-	opts.link_info_len = sizeof(linfo);
-	link = bpf_program__attach_iter(skel->progs.dump_percpu_data, &opts);
-	if (!ASSERT_OK_PTR(link, "bpf_program__attach_iter"))
-		goto out;
+	test_global_percpu_data_iter_fd(bpf_program__fd(skel->progs.dump_percpu_data),
+					bpf_map__fd(skel->maps.percpu),
+					num_cpus, &skel->bss->run_iter,
+					&skel->bss->sum);
+out:
+	test_global_percpu_data__destroy(skel);
+}
 
-	fd = bpf_iter_create(bpf_link__fd(link));
-	if (!ASSERT_GE(fd, 0, "bpf_iter_create"))
-		goto out;
+static void test_global_percpu_data_iter_lskel(void)
+{
+	struct test_global_percpu_data_lskel *skel;
+	int num_cpus, err;
 
-	while ((len = read(fd, buf, sizeof(buf))) > 0)
-		do { } while (0);
-	ASSERT_EQ(len, 0, "read iter");
-	ASSERT_TRUE(skel->bss->run_iter, "run_iter");
-	ASSERT_EQ(skel->bss->sum, 0xc0de * num_cpus, "sum");
+	num_cpus = libbpf_num_possible_cpus();
+	if (!ASSERT_GT(num_cpus, 0, "libbpf_num_possible_cpus"))
+		return;
 
-	close(fd);
+	skel = test_global_percpu_data_lskel__open();
+	if (!ASSERT_OK_PTR(skel, "test_global_percpu_data_lskel__open"))
+		return;
+
+	skel->rodata->num_cpus = num_cpus;
+	skel->rodata->num_off = offsetof(struct test_global_percpu_data_lskel__percpu,
+					 struct_data.nums[6]);
+	skel->rodata->elem_sz = roundup(sizeof(*skel->percpu), 8);
+	skel->percpu->struct_data.nums[6] = 0xc0de;
+
+	err = test_global_percpu_data_lskel__load(skel);
+	if (!ASSERT_OK(err, "test_global_percpu_data_lskel__load"))
+		goto out;
+
+	test_global_percpu_data_iter_fd(skel->progs.dump_percpu_data.prog_fd,
+					skel->maps.percpu.map_fd,
+					num_cpus, &skel->bss->run_iter,
+					&skel->bss->sum);
 out:
-	bpf_link__destroy(link);
-	test_global_percpu_data__destroy(skel);
+	test_global_percpu_data_lskel__destroy(skel);
 }
 
 void test_global_percpu_data(void)
@@ -445,4 +489,6 @@ void test_global_percpu_data(void)
 	test_global_percpu_data_verifier_log();
 	if (test__start_subtest("iter"))
 		test_global_percpu_data_iter();
+	if (test__start_subtest("iter_lskel"))
+		test_global_percpu_data_iter_lskel();
 }
-- 
2.55.0.1082.g2b9226bbc0-goog


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

* Re: [PATCH bpf-next v3 3/3] selftests/bpf: Add iter subtest using lskel in global_data_init
  2026-09-18  4:09 ` [PATCH bpf-next v3 3/3] selftests/bpf: Add iter subtest using lskel in global_data_init Thiébaud Weksteen
@ 2026-09-18  5:05   ` bot+bpf-ci
  0 siblings, 0 replies; 6+ messages in thread
From: bot+bpf-ci @ 2026-09-18  5:05 UTC (permalink / raw)
  To: tweek, qmo, ast, daniel, andrii, eddyz87, memxor, shuah, tweek,
	kpsingh, leon.hwang, emil
  Cc: martin.lau, song, yonghong.song, jolsa, ihor.solodrai, bpf,
	linux-kernel, linux-kselftest, ast, andrii, daniel, martin.lau,
	eddyz87, yonghong.song, mason, ihor.solodrai

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

> In test_global_percpu_data.c, dump_percpu_data is defined after two
> non-autoload SEC("?kprobe") programs (verifier_strncmp and
> verifier_snprintf). If bpftool does not skip non-autoload programs when
> generating light skeletons, dump_percpu_data.prog_fd is left invalid or
> unpopulated.
>
> Factor out a test_global_percpu_data_iter_fd() helper that operates
> directly on prog/map file descriptors, and add an iter_lskel subtest to
> verify that dump_percpu_data is properly loaded and executes correctly
> when using the light skeleton.
>
> Fixes: 4c9241bd731a ("selftests/bpf: Add tests to verify global percpu data")
> Fixes: 1ed2294b31fc ("selftests/bpf: Test verifier log for global percpu data")
> Signed-off-by: Thiébaud Weksteen <tweek@google.com>

Are the Fixes: tags appropriate for this commit? This patch only adds new
test coverage (a new iter_lskel subtest) and refactors existing test code
(factoring out test_global_percpu_data_iter_fd() with no behavioral change
to the existing "iter" subtest). It doesn't fix anything that
4c9241bd731a or 1ed2294b31fc got wrong.

The bug being tested is in bpftool, introduced by d510296d331a
("bpftool: Use syscall/loader program in "prog load" and "gen skeleton"
command.") and actually fixed by the two preceding patches in this series
(202ee90dee368 and 843762e6f4665), both of which already carry the correct
Fixes: d510296d331a tag.

There's also a backport concern. The Fixes: tags make this patch a
candidate for AUTOSEL/stable pickup independently of 202ee90dee368 and
843762e6f4665. Since this is the last patch of the series, backporting it
alone would land the new iter_lskel subtest in a tree with the unfixed
bpftool, where skel->progs.dump_percpu_data.prog_fd is left at 0 and
bpf_link_create(0, 0, BPF_TRACE_ITER, &opts) fails. The subtest would fail
by construction.

Should the Fixes: tags be removed, or if they're intended to be kept,
should the dependency on the two bpftool patches be stated via
Cc: <stable@vger.kernel.org> prerequisite lines?


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

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

* Re: [PATCH bpf-next v3 2/3] bpftool: Compute light skeleton ctx.sz without relying on links
  2026-09-18  4:09 ` [PATCH bpf-next v3 2/3] bpftool: Compute light skeleton ctx.sz without relying on links Thiébaud Weksteen
@ 2026-09-18  8:42   ` Quentin Monnet
  0 siblings, 0 replies; 6+ messages in thread
From: Quentin Monnet @ 2026-09-18  8:42 UTC (permalink / raw)
  To: Thiébaud Weksteen, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Shuah Khan, KP Singh, Leon Hwang, Emil Tsalapatis
  Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Ihor Solodrai, bpf, linux-kernel, linux-kselftest

2026-09-18 14:09 UTC+1000 ~ Thiébaud Weksteen <tweek@google.com>
> When generating a light skeleton, gen_trace() unconditionally sets
> skel->ctx.sz using (char *)&skel->links - (char *)skel. However, if a
> BPF object has no programs and no struct_ops maps (prog_cnt +
> attach_map_cnt == 0), do_skeleton() omits the links struct, causing the
> generated skeleton header to fail compilation.
> 
> Compute skel->ctx.sz from the end of progs (if prog_cnt > 0), maps (if
> map_cnt > 0), or ctx instead of relying on skel->links. Also remove the
> unused opts.data_sz argument passed to codegen().
> 
> Fixes: d510296d331a ("bpftool: Use syscall/loader program in "prog load" and "gen skeleton" command.")
> Signed-off-by: Thiébaud Weksteen <tweek@google.com>
> ---
> No changes since v2


In that case you're welcome to keep my ack from v2 :)

Acked-by: Quentin Monnet <qmo@kernel.org>

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

* Re: [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons
  2026-09-18  4:09 [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons Thiébaud Weksteen
  2026-09-18  4:09 ` [PATCH bpf-next v3 2/3] bpftool: Compute light skeleton ctx.sz without relying on links Thiébaud Weksteen
  2026-09-18  4:09 ` [PATCH bpf-next v3 3/3] selftests/bpf: Add iter subtest using lskel in global_data_init Thiébaud Weksteen
@ 2026-09-18  8:43 ` Quentin Monnet
  2 siblings, 0 replies; 6+ messages in thread
From: Quentin Monnet @ 2026-09-18  8:43 UTC (permalink / raw)
  To: Thiébaud Weksteen, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Shuah Khan, KP Singh, Leon Hwang, Emil Tsalapatis
  Cc: Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Ihor Solodrai, bpf, linux-kernel, linux-kselftest

2026-09-18 14:09 UTC+1000 ~ Thiébaud Weksteen <tweek@google.com>
> When generating a light skeleton (bpftool gen skeleton -L),
> bpf_object__load() skips loading programs marked as non-autoload (e.g.
> SEC("?...")), so the generated loader program only records and populates
> file descriptors for autoloaded programs.
> 
> Previously, bpftool emitted struct bpf_prog_desc fields, link fields,
> and attach/detach/destroy functions for all programs in the BPF object,
> causing the loader program to store subsequent program FDs into
> incorrect skeleton struct fields when non-autoload programs were
> present.
> 
> Furthermore, bpf_object__load() can update a program's autoload status
> during preparation (e.g. for struct_ops programs when resolving kernel
> BTF members or adjusting autoload based on map autocreate settings).
> Move bpf_object__gen_loader() and bpf_object__load() out of gen_trace()
> into do_skeleton() before counting programs and emitting struct fields so
> that struct field declarations and attach/detach/destroy functions all
> observe the final post-load autoload state.
> 
> Skip programs with !bpf_program__autoload(prog) when counting programs
> and generating progs/links struct fields as well as attach, detach, and
> destroy functions for light skeletons.
> 
> Fixes: d510296d331a ("bpftool: Use syscall/loader program in "prog load" and "gen skeleton" command.")
> Signed-off-by: Thiébaud Weksteen <tweek@google.com>


Reviewed-by: Quentin Monnet <qmo@kernel.org>

Thanks!

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

end of thread, other threads:[~2026-09-18  8:43 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-18  4:09 [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons Thiébaud Weksteen
2026-09-18  4:09 ` [PATCH bpf-next v3 2/3] bpftool: Compute light skeleton ctx.sz without relying on links Thiébaud Weksteen
2026-09-18  8:42   ` Quentin Monnet
2026-09-18  4:09 ` [PATCH bpf-next v3 3/3] selftests/bpf: Add iter subtest using lskel in global_data_init Thiébaud Weksteen
2026-09-18  5:05   ` bot+bpf-ci
2026-09-18  8:43 ` [PATCH bpf-next v3 1/3] bpftool: Skip non-autoload programs when generating light skeletons Quentin Monnet

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

all inboxes | Powered by JetHome®