On Mon, Jun 29, 2026 at 8:25 AM Leon Hwang <[email protected]> wrote:
>
> Add support for global percpu data in libbpf by adding a new ".percpu"
> section, similar to ".data". It enables efficient handling of percpu
> global variables in bpf programs.
>
> When generating loader for lightweight skeleton, update the percpu_array
> map used for global percpu data using BPF_F_ALL_CPUS, in order to update
> values across all CPUs using one value slot.
>
> Unlike global data, the mmaped data for global percpu data will be marked
> as read-only after populating the percpu_array map. Thereafter, users can
> read those initialized percpu data after loading prog. If they want to
> update the percpu data after loading prog, they have to update the
> percpu_array map using key=0 instead.
>
> Signed-off-by: Leon Hwang <[email protected]>
> ---
> tools/lib/bpf/bpf_gen_internal.h | 3 +-
> tools/lib/bpf/gen_loader.c | 3 +-
> tools/lib/bpf/libbpf.c | 57 +++++++++++++++++++++++++++-----
> 3 files changed, 53 insertions(+), 10 deletions(-)
>
[...]
> @@ -1975,7 +1981,7 @@ bpf_object__init_internal_map(struct bpf_object *obj,
> enum libbpf_map_type type,
> map->sec_idx = sec_idx;
> map->sec_offset = 0;
> map->real_name = strdup(real_name);
> - map->name = internal_map_name(obj, real_name);
> + map->name = is_percpu ? strdup(real_name) : internal_map_name(obj,
> real_name);
nit: I'd probably pass type into internal_map_name() and let it handle
all this in one place, consider that for follow up
> if (!map->real_name || !map->name) {
> zfree(&map->real_name);
> zfree(&map->name);
> @@ -1983,7 +1989,7 @@ bpf_object__init_internal_map(struct bpf_object *obj,
> enum libbpf_map_type type,
> }
>
> def = &map->def;
> - def->type = BPF_MAP_TYPE_ARRAY;
> + def->type = is_percpu ? BPF_MAP_TYPE_PERCPU_ARRAY :
> BPF_MAP_TYPE_ARRAY;
> def->key_size = sizeof(int);
> def->value_size = data_sz;
> def->max_entries = 1;
[...]