From b68bed3090091f8e9c001a5dbd216c45146e694c Mon Sep 17 00:00:00 2001 From: Leon Hwang Date: Wed, 16 Sep 2026 00:14:50 +0800 Subject: [PATCH] bpftool: Compute map size of light skeletons at runtime 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 and max entries to the generated code and round mmap size 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 Signed-off-by: Andrii Nakryiko Acked-by: Quentin Monnet Link: https://lore.kernel.org/bpf/20260915161450.96249-1-leon.hwang@linux.dev --- src/skel_internal.h | 48 ++++++++++++++++++++++++++++++++------------- 1 file changed, 34 insertions(+), 14 deletions(-) diff --git a/src/skel_internal.h b/src/skel_internal.h index 1f3f332..9e16b8e 100644 --- a/src/skel_internal.h +++ b/src/skel_internal.h @@ -11,6 +11,7 @@ #include #else #include +#include #include #include #include @@ -127,7 +128,7 @@ static inline void skel_free(const void *p) * either bpf_probe_read_kernel() or bpf_copy_from_user() from initial_value * depending on bpf_loader_ctx->flags. */ -static inline void skel_free_map_data(void *p, __u64 addr, size_t sz) +static inline void skel_free_map_data(void *p, __u64 addr, size_t val_sz, __u32 max_entries) { if (addr != ~0ULL) kvfree(p); @@ -138,18 +139,20 @@ 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, __u32 max_entries, + size_t data_sz) { void *addr; - addr = kvmalloc(val_sz, GFP_KERNEL); + addr = kvmalloc(data_sz, GFP_KERNEL); if (!addr) return NULL; - memcpy(addr, val, val_sz); + memcpy(addr, val, data_sz); 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, __u32 max_entries, + int flags, int fd) { struct bpf_map *map; void *addr = NULL; @@ -172,9 +175,10 @@ out: return addr; } -static inline int skel_protect_map_data(void *p, __u64 *init_val, size_t sz) +static inline int skel_protect_map_data(void *p, __u64 *init_val, size_t val_sz, __u32 max_entries) { - (void)sz; + (void)val_sz; + (void)max_entries; kvfree(p); *init_val = ~0ULL; @@ -193,25 +197,39 @@ static inline void skel_free(void *p) free(p); } -static inline void skel_free_map_data(void *p, __u64 addr, size_t sz) +static inline size_t skel_map_mmap_sz(size_t val_sz, __u32 max_entries) { - munmap(p, sz); + const long page_sz = sysconf(_SC_PAGE_SIZE); + size_t mmap_sz; + + mmap_sz = roundup(val_sz, 8) * max_entries; + mmap_sz = roundup(mmap_sz, page_sz); + return mmap_sz; } -static inline void *skel_prep_map_data(const void *val, size_t mmap_sz, size_t val_sz) +static inline void skel_free_map_data(void *p, __u64 addr, size_t val_sz, __u32 max_entries) { + munmap(p, skel_map_mmap_sz(val_sz, max_entries)); +} + +static inline void *skel_prep_map_data(const void *val, size_t val_sz, __u32 max_entries, + size_t data_sz) +{ + size_t mmap_sz = skel_map_mmap_sz(val_sz, max_entries); void *addr; addr = mmap(NULL, mmap_sz, PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANONYMOUS, -1, 0); if (addr == (void *) -1) return NULL; - memcpy(addr, val, val_sz); + memcpy(addr, val, data_sz); 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, __u32 max_entries, + int flags, int fd) { + size_t mmap_sz = skel_map_mmap_sz(val_sz, max_entries); void *addr; addr = mmap((void *) (long) *init_val, mmap_sz, flags, MAP_SHARED | MAP_FIXED, fd, 0); @@ -220,11 +238,13 @@ static inline void *skel_finalize_map_data(__u64 *init_val, size_t mmap_sz, int return addr; } -static inline int skel_protect_map_data(void *p, __u64 *init_val, size_t sz) +static inline int skel_protect_map_data(void *p, __u64 *init_val, size_t val_sz, __u32 max_entries) { + size_t mmap_sz = skel_map_mmap_sz(val_sz, max_entries); + (void)init_val; - if (mprotect(p, sz, PROT_READ)) + if (mprotect(p, mmap_sz, PROT_READ)) return -errno; return 0; }