On Mon, Jun 22, 2026 at 7:37 AM Leon Hwang <[email protected]> wrote:
>
> Enhance bpftool to generate skeletons that properly handle global percpu
> variables. The generated skeleton now includes a dedicated structure for
> percpu data, allowing users to initialize and access percpu variables more
> efficiently.
>
> For global percpu variables, the skeleton now includes a nested
> structure, e.g.:
>
> struct test_global_percpu_data {
>         struct bpf_object_skeleton *skeleton;
>         struct bpf_object *obj;
>         struct {
>                 struct bpf_map *percpu;
>         } maps;
>         // ...
>         struct test_global_percpu_data__percpu {
>                 int data;
>                 char run;
>                 struct {
>                         char set;
>                         int i;
>                         int nums[7];
>                 } struct_data;
>                 int nums[7];
>         } *percpu;
>
>         // ...
> };
>
>   * The "struct test_global_percpu_data__percpu *percpu" points to
>     initialized data, which is actually "maps.percpu->mmaped".
>   * Before loading the skeleton, updating the
>     "struct test_global_percpu_data__percpu *percpu" modifies the initial
>     value of the corresponding global percpu variables.
>   * After loading the skeleton, "maps.percpu->mmaped" has been marked as
>     read-only in libbpf. If users want to update the global percpu
>     variables, they have to update the "maps.percpu" map instead.
>   * For lightweight skeleton, "lskel->percpu" will be protected by
>     "mprotect(p, sz, PROT_READ)".
>   * For subskeleton, those variables of global percpu data will be
>     skipped.
>
> Assisted-by: Codex:gpt-5.5-xhigh
> Signed-off-by: Leon Hwang <[email protected]>
> ---
>  tools/bpf/bpftool/gen.c       | 43 +++++++++++++++++++++++++++--------
>  tools/lib/bpf/skel_internal.h | 24 +++++++++++++++++--
>  2 files changed, 56 insertions(+), 11 deletions(-)
>

[...]

> @@ -263,13 +268,12 @@ static bool is_mmapable_map(const struct bpf_map *map, 
> char *buf, size_t sz)
>                 return true;
>         }
>
> -       if (!bpf_map__is_internal(map) || !(bpf_map__map_flags(map) & 
> BPF_F_MMAPABLE))
> -               return false;
> -
> -       if (!get_map_ident(map, buf, sz))
> -               return false;
> +       if (bpf_map__is_internal(map) &&
> +           ((bpf_map__map_flags(map) & BPF_F_MMAPABLE) || 
> bpf_map_is_percpu_data(map)) &&
> +           get_map_ident(map, buf, sz))
> +               return true;
>

just add `if (bpf_map_is_percpu_data(map) return true;`? maybe also
move get_map_ident check a bit earlier. I think that will be a bit
cleaner, this condition is quite hard to follow

> -       return true;
> +       return false;
>  }
>
>  static int codegen_datasecs(struct bpf_object *obj, const char *obj_name)
> @@ -343,6 +347,9 @@ static int codegen_subskel_datasecs(struct bpf_object 
> *obj, const char *obj_name
>                 if (!is_mmapable_map(map, map_ident, sizeof(map_ident)))
>                         continue;
>
> +               if (bpf_map_is_percpu_data(map))
> +                       continue;
> +
>                 sec = find_type_for_map(btf, map_ident);
>                 if (!sec)
>                         continue;
> @@ -669,7 +676,7 @@ static void codegen_destroy(struct bpf_object *obj, const 
> char *obj_name)
>                 if (!get_map_ident(map, ident, sizeof(ident)))
>                         continue;
>                 if (bpf_map__is_internal(map) &&
> -                   (bpf_map__map_flags(map) & BPF_F_MMAPABLE))
> +                   ((bpf_map__map_flags(map) & BPF_F_MMAPABLE) || 
> bpf_map_is_percpu_data(map)))

also we can add a helper to check if it's an internal map with a
dedicated data section in the skeleton (too lazy to think of a good
name right now.. ;)

>                         printf("\tskel_free_map_data(skel->%1$s, 
> skel->maps.%1$s.initial_value, %2$zu);\n",
>                                ident, bpf_map_mmap_sz(map));
>                 codegen("\

[...]

Reply via email to