mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH bpf-next] bpftool: Compute map size of light skeletons at runtime
@ 2026-09-11 14:59 Leon Hwang
  2026-09-11 19:09 ` Andrii Nakryiko
  0 siblings, 1 reply; 2+ messages in thread
From: Leon Hwang @ 2026-09-11 14:59 UTC (permalink / raw)
  To: bpf
  Cc: Quentin Monnet, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, Ihor Solodrai, linux-kernel, Leon Hwang

bpftool rounds memory-mapped data map sizes to the host page size when
generating a light skeleton. The generated code therefore uses a 64K
mapping size when bpftool runs on a 64K-page host, even if the skeleton
runs on a 4K-page target. The target rejects the oversized map mmap(),
causing failure of loading the light skeleton.

When try to run 64K-page selftests on 4K-page VM, the error message does
not provide the reason about page size.

 test_atomics:PASS:atomics skeleton open 0 nsec
 test_atomics:FAIL:atomics skeleton load unexpected error: -12 (errno 22)
 #15      atomics:FAIL

Pass the original map value size to the generated code and round it to the
runtime page size in the user-space light skeleton helpers. This keeps
generated light skeletons independent of the build host page size.

Fixes: d510296d331a ("bpftool: Use syscall/loader program in "prog load" and "gen skeleton" command.")
Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
---
 tools/bpf/bpftool/gen.c       | 27 ++++++++-------------------
 tools/lib/bpf/skel_internal.h | 18 +++++++++++++-----
 2 files changed, 21 insertions(+), 24 deletions(-)

diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
index a50540ef6521..77f04c28fee9 100644
--- a/tools/bpf/bpftool/gen.c
+++ b/tools/bpf/bpftool/gen.c
@@ -500,16 +500,6 @@ static void print_hex(const char *data, int data_sz)
 	}
 }
 
-static size_t bpf_map_mmap_sz(const struct bpf_map *map)
-{
-	long page_sz = sysconf(_SC_PAGE_SIZE);
-	size_t map_sz;
-
-	map_sz = (size_t)roundup(bpf_map__value_size(map), 8) * bpf_map__max_entries(map);
-	map_sz = roundup(map_sz, page_sz);
-	return map_sz;
-}
-
 /* Emit type size asserts for all top-level fields in memory-mapped internal maps. */
 static void codegen_asserts(struct bpf_object *obj, const char *obj_name)
 {
@@ -686,8 +676,8 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
 		if (!get_map_ident(map, ident, sizeof(ident)))
 			continue;
 		if (is_skel_data(map, ident, sizeof(ident)))
-			printf("\tskel_free_map_data(skel->%1$s, skel->maps.%1$s.initial_value, %2$zu);\n",
-			       ident, bpf_map_mmap_sz(map));
+			printf("\tskel_free_map_data(skel->%1$s, skel->maps.%1$s.initial_value, %2$u);\n",
+			       ident, bpf_map__value_size(map));
 		codegen("\
 			\n\
 				skel_closenz(skel->maps.%1$s.map_fd);	    \n\
@@ -771,13 +761,12 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		\n\
 		\";							    \n\
 									    \n\
-				skel->%1$s = (__typeof__(skel->%1$s))skel_prep_map_data((void *)data, %2$zd,\n\
-								sizeof(data) - 1);\n\
+				skel->%1$s = (__typeof__(skel->%1$s))skel_prep_map_data((void *)data, sizeof(data) - 1);\n\
 				if (!skel->%1$s)			    \n\
 					goto cleanup;			    \n\
 				skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\
 			}						    \n\
-			", ident, bpf_map_mmap_sz(map));
+			", ident);
 	}
 	codegen("\
 		\n\
@@ -871,14 +860,14 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		if (bpf_map__type(map) == BPF_MAP_TYPE_PERCPU_ARRAY) {
 			codegen("\
 		\n\
-			err = skel_protect_map_data(skel->%1$s, &skel->maps.%1$s.initial_value, %2$zd);\n\
+			err = skel_protect_map_data(skel->%1$s, &skel->maps.%1$s.initial_value, %2$u);\n\
 			if (err)					    \n\
 				return err;				    \n\
 		#ifdef __KERNEL__					    \n\
 			skel->%1$s = NULL;				    \n\
 		#endif							    \n\
 			",
-			ident, bpf_map_mmap_sz(map));
+			ident, bpf_map__value_size(map));
 			continue;
 		}
 
@@ -890,11 +879,11 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
 		codegen("\
 		\n\
 			skel->%1$s = (__typeof__(skel->%1$s))skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\
-							%2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
+							%2$u, %3$s, skel->maps.%1$s.map_fd);\n\
 			if (!skel->%1$s)				    \n\
 				return -ENOMEM;				    \n\
 			",
-		       ident, bpf_map_mmap_sz(map), mmap_flags);
+		       ident, bpf_map__value_size(map), mmap_flags);
 	}
 	codegen("\
 		\n\
diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
index 1f3f332dffbe..5787911f17f5 100644
--- a/tools/lib/bpf/skel_internal.h
+++ b/tools/lib/bpf/skel_internal.h
@@ -11,6 +11,7 @@
 #include <linux/bpf.h>
 #else
 #include <unistd.h>
+#include <sys/param.h>
 #include <sys/syscall.h>
 #include <sys/mman.h>
 #include <linux/keyctl.h>
@@ -138,7 +139,7 @@ static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
 	 */
 }
 
-static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
+static inline void *skel_prep_map_data(const void *val, size_t val_sz)
 {
 	void *addr;
 
@@ -149,7 +150,7 @@ static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t v
 	return addr;
 }
 
-static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
+static inline void *skel_finalize_map_data(__u64 *init_val, size_t val_sz, int flags, int fd)
 {
 	struct bpf_map *map;
 	void *addr = NULL;
@@ -193,13 +194,19 @@ static inline void skel_free(void *p)
 	free(p);
 }
 
+static inline size_t skel_map_mmap_sz(size_t sz)
+{
+	return roundup(sz, sysconf(_SC_PAGE_SIZE));
+}
+
 static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
 {
-	munmap(p, sz);
+	munmap(p, skel_map_mmap_sz(sz));
 }
 
-static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
+static inline void *skel_prep_map_data(const void *val, size_t val_sz)
 {
+	size_t mmap_sz = skel_map_mmap_sz(val_sz);
 	void *addr;
 
 	addr = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
@@ -210,8 +217,9 @@ static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t v
 	return addr;
 }
 
-static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
+static inline void *skel_finalize_map_data(__u64 *init_val, size_t val_sz, int flags, int fd)
 {
+	size_t mmap_sz = skel_map_mmap_sz(val_sz);
 	void *addr;
 
 	addr = mmap((void *) (long) *init_val, mmap_sz, flags, MAP_SHARED | MAP_FIXED, fd, 0);
-- 
2.55.0


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

* Re: [PATCH bpf-next] bpftool: Compute map size of light skeletons at runtime
  2026-09-11 14:59 [PATCH bpf-next] bpftool: Compute map size of light skeletons at runtime Leon Hwang
@ 2026-09-11 19:09 ` Andrii Nakryiko
  0 siblings, 0 replies; 2+ messages in thread
From: Andrii Nakryiko @ 2026-09-11 19:09 UTC (permalink / raw)
  To: Leon Hwang
  Cc: bpf, Quentin Monnet, Alexei Starovoitov, Daniel Borkmann,
	Andrii Nakryiko, Eduard Zingerman, Kumar Kartikeya Dwivedi,
	Martin KaFai Lau, Song Liu, Yonghong Song, Jiri Olsa,
	Emil Tsalapatis, Ihor Solodrai, linux-kernel

On Fri, Sep 11, 2026 at 7:59 AM Leon Hwang <leon.hwang@linux.dev> wrote:
>
> bpftool rounds memory-mapped data map sizes to the host page size when
> generating a light skeleton. The generated code therefore uses a 64K
> mapping size when bpftool runs on a 64K-page host, even if the skeleton
> runs on a 4K-page target. The target rejects the oversized map mmap(),
> causing failure of loading the light skeleton.
>
> When try to run 64K-page selftests on 4K-page VM, the error message does
> not provide the reason about page size.
>
>  test_atomics:PASS:atomics skeleton open 0 nsec
>  test_atomics:FAIL:atomics skeleton load unexpected error: -12 (errno 22)
>  #15      atomics:FAIL
>
> Pass the original map value size to the generated code and round it to the
> runtime page size in the user-space light skeleton helpers. This keeps
> generated light skeletons independent of the build host page size.
>
> Fixes: d510296d331a ("bpftool: Use syscall/loader program in "prog load" and "gen skeleton" command.")
> Signed-off-by: Leon Hwang <leon.hwang@linux.dev>
> ---
>  tools/bpf/bpftool/gen.c       | 27 ++++++++-------------------
>  tools/lib/bpf/skel_internal.h | 18 +++++++++++++-----
>  2 files changed, 21 insertions(+), 24 deletions(-)
>
> diff --git a/tools/bpf/bpftool/gen.c b/tools/bpf/bpftool/gen.c
> index a50540ef6521..77f04c28fee9 100644
> --- a/tools/bpf/bpftool/gen.c
> +++ b/tools/bpf/bpftool/gen.c
> @@ -500,16 +500,6 @@ static void print_hex(const char *data, int data_sz)
>         }
>  }
>
> -static size_t bpf_map_mmap_sz(const struct bpf_map *map)
> -{
> -       long page_sz = sysconf(_SC_PAGE_SIZE);
> -       size_t map_sz;
> -
> -       map_sz = (size_t)roundup(bpf_map__value_size(map), 8) * bpf_map__max_entries(map);
> -       map_sz = roundup(map_sz, page_sz);
> -       return map_sz;
> -}
> -
>  /* Emit type size asserts for all top-level fields in memory-mapped internal maps. */
>  static void codegen_asserts(struct bpf_object *obj, const char *obj_name)
>  {
> @@ -686,8 +676,8 @@ static void codegen_destroy(struct bpf_object *obj, const char *obj_name)
>                 if (!get_map_ident(map, ident, sizeof(ident)))
>                         continue;
>                 if (is_skel_data(map, ident, sizeof(ident)))
> -                       printf("\tskel_free_map_data(skel->%1$s, skel->maps.%1$s.initial_value, %2$zu);\n",
> -                              ident, bpf_map_mmap_sz(map));
> +                       printf("\tskel_free_map_data(skel->%1$s, skel->maps.%1$s.initial_value, %2$u);\n",
> +                              ident, bpf_map__value_size(map));
>                 codegen("\
>                         \n\
>                                 skel_closenz(skel->maps.%1$s.map_fd);       \n\
> @@ -771,13 +761,12 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>                 \n\
>                 \";                                                         \n\
>                                                                             \n\
> -                               skel->%1$s = (__typeof__(skel->%1$s))skel_prep_map_data((void *)data, %2$zd,\n\
> -                                                               sizeof(data) - 1);\n\
> +                               skel->%1$s = (__typeof__(skel->%1$s))skel_prep_map_data((void *)data, sizeof(data) - 1);\n\
>                                 if (!skel->%1$s)                            \n\
>                                         goto cleanup;                       \n\
>                                 skel->maps.%1$s.initial_value = (__u64) (long) skel->%1$s;\n\
>                         }                                                   \n\
> -                       ", ident, bpf_map_mmap_sz(map));
> +                       ", ident);
>         }
>         codegen("\
>                 \n\
> @@ -871,14 +860,14 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>                 if (bpf_map__type(map) == BPF_MAP_TYPE_PERCPU_ARRAY) {
>                         codegen("\
>                 \n\
> -                       err = skel_protect_map_data(skel->%1$s, &skel->maps.%1$s.initial_value, %2$zd);\n\
> +                       err = skel_protect_map_data(skel->%1$s, &skel->maps.%1$s.initial_value, %2$u);\n\
>                         if (err)                                            \n\
>                                 return err;                                 \n\
>                 #ifdef __KERNEL__                                           \n\
>                         skel->%1$s = NULL;                                  \n\
>                 #endif                                                      \n\
>                         ",
> -                       ident, bpf_map_mmap_sz(map));
> +                       ident, bpf_map__value_size(map));
>                         continue;
>                 }
>
> @@ -890,11 +879,11 @@ static int gen_trace(struct bpf_object *obj, const char *obj_name, const char *h
>                 codegen("\
>                 \n\
>                         skel->%1$s = (__typeof__(skel->%1$s))skel_finalize_map_data(&skel->maps.%1$s.initial_value,\n\
> -                                                       %2$zd, %3$s, skel->maps.%1$s.map_fd);\n\
> +                                                       %2$u, %3$s, skel->maps.%1$s.map_fd);\n\
>                         if (!skel->%1$s)                                    \n\
>                                 return -ENOMEM;                             \n\
>                         ",
> -                      ident, bpf_map_mmap_sz(map), mmap_flags);
> +                      ident, bpf_map__value_size(map), mmap_flags);
>         }
>         codegen("\
>                 \n\
> diff --git a/tools/lib/bpf/skel_internal.h b/tools/lib/bpf/skel_internal.h
> index 1f3f332dffbe..5787911f17f5 100644
> --- a/tools/lib/bpf/skel_internal.h
> +++ b/tools/lib/bpf/skel_internal.h
> @@ -11,6 +11,7 @@
>  #include <linux/bpf.h>
>  #else
>  #include <unistd.h>
> +#include <sys/param.h>
>  #include <sys/syscall.h>
>  #include <sys/mman.h>
>  #include <linux/keyctl.h>
> @@ -138,7 +139,7 @@ static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
>          */
>  }
>
> -static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
> +static inline void *skel_prep_map_data(const void *val, size_t val_sz)
>  {
>         void *addr;
>
> @@ -149,7 +150,7 @@ static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t v
>         return addr;
>  }
>
> -static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
> +static inline void *skel_finalize_map_data(__u64 *init_val, size_t val_sz, int flags, int fd)
>  {
>         struct bpf_map *map;
>         void *addr = NULL;
> @@ -193,13 +194,19 @@ static inline void skel_free(void *p)
>         free(p);
>  }
>
> +static inline size_t skel_map_mmap_sz(size_t sz)
> +{
> +       return roundup(sz, sysconf(_SC_PAGE_SIZE));

original code had this logic:

map_sz = (size_t)roundup(bpf_map__value_size(map), 8) *
bpf_map__max_entries(map);
map_sz = roundup(map_sz, page_sz);

you completely ignore max_entries in a new code now, which works for
global data because that have max_entires 1, but at the very least we
should add some check or assert for that so that we don't miss a case
when max_entries is not 1

pw-bot: cr

> +}
> +
>  static inline void skel_free_map_data(void *p, __u64 addr, size_t sz)
>  {
> -       munmap(p, sz);
> +       munmap(p, skel_map_mmap_sz(sz));
>  }
>
> -static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz)
> +static inline void *skel_prep_map_data(const void *val, size_t val_sz)
>  {
> +       size_t mmap_sz = skel_map_mmap_sz(val_sz);
>         void *addr;
>
>         addr = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE,
> @@ -210,8 +217,9 @@ static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t v
>         return addr;
>  }
>
> -static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int flags, int fd)
> +static inline void *skel_finalize_map_data(__u64 *init_val, size_t val_sz, int flags, int fd)
>  {
> +       size_t mmap_sz = skel_map_mmap_sz(val_sz);
>         void *addr;
>
>         addr = mmap((void *) (long) *init_val, mmap_sz, flags, MAP_SHARED | MAP_FIXED, fd, 0);
> --
> 2.55.0
>

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

end of thread, other threads:[~2026-09-11 19:09 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-11 14:59 [PATCH bpf-next] bpftool: Compute map size of light skeletons at runtime Leon Hwang
2026-09-11 19:09 ` Andrii Nakryiko

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®