Re: [PATCH] perf trace: Fix wrong size to bpf_map__update_elem call
From: Ian Rogers
Date: Mon Mar 24 2025 - 11:51:06 EST
On Mon, Mar 24, 2025 at 8:38 AM Ian Rogers <irogers@xxxxxxxxxx> wrote:
>
> On Mon, Mar 24, 2025 at 8:28 AM Thomas Richter <tmricht@xxxxxxxxxxxxx> wrote:
> >
> > In linux-next
> > commit c760174401f6 ("perf cpumap: Reduce cpu size from int to int16_t")
> > causes the perf tests 100 126 to fail on s390:
> >
> > Output before:
> > # ./perf test 100
> > 100: perf trace BTF general tests : FAILED!
> > #
> >
> > The root cause is the change from int to int16_t for the
> > cpu maps. The size of the CPU key value pair changes from
> > four bytes to two bytes. However a two byte key size is
> > not supported for bpf_map__update_elem().
>
> Nice catch!
>
> > Note: validate_map_op() in libbpf.c emits warning
> > libbpf: map '__augmented_syscalls__': \
> > unexpected key size 2 provided, expected 4
> > when key size is set to int16_t.
>
> Wow, weird.
Ah, I guess it is a mismatch with the declaration in
tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c:
https://web.git.kernel.org/pub/scm/linux/kernel/git/perf/perf-tools-next.git/tree/tools/perf/util/bpf_skel/augmented_raw_syscalls.bpf.c?h=perf-tools-next#n31
```
/* bpf-output associated map */
struct __augmented_syscalls__ {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__type(key, int);
__type(value, __u32);
__uint(max_entries, MAX_CPUS);
} __augmented_syscalls__ SEC(".maps");
```
but this looks wrong. The values are file descriptors, so should be
ints. I think it should be:
```
struct __augmented_syscalls__ {
__uint(type, BPF_MAP_TYPE_PERF_EVENT_ARRAY);
__type(key, int16_t);
__type(value, int);
__uint(max_entries, MAX_CPUS);
} __augmented_syscalls__ SEC(".maps");
```
I'm not sure if max_entries can be a uint16_t too. I suspect this may
well interfere with BPF_MAP_TYPE_PERF_EVENT_ARRAY and its use by
bpf_perf_event_output. Probably best to keep things in the BPF code as
they are and do your builtin-trace.c fix. Perhaps someone else can
clean this up.
Thanks,
Ian
> > Therefore change to variable size back to 4 bytes for
> > invocation of bpf_map__update_elem().
> >
> > Output after:
> > # ./perf test 100
> > 100: perf trace BTF general tests : Ok
> > #
> >
> > Fixes: c760174401f6 ("perf cpumap: Reduce cpu size from int to int16_t")
> > Signed-off-by: Thomas Richter <tmricht@xxxxxxxxxxxxx>
> > Cc: Ian Rogers <irogers@xxxxxxxxxx>
> > Cc: James Clark <james.clark@xxxxxxxxxx>
> > ---
> > tools/perf/builtin-trace.c | 6 ++++--
> > 1 file changed, 4 insertions(+), 2 deletions(-)
> >
> > diff --git a/tools/perf/builtin-trace.c b/tools/perf/builtin-trace.c
> > index 092c5f6404ba..464c97a11852 100644
> > --- a/tools/perf/builtin-trace.c
> > +++ b/tools/perf/builtin-trace.c
> > @@ -4375,10 +4375,12 @@ static int trace__run(struct trace *trace, int argc, const char **argv)
> > * CPU the bpf-output event's file descriptor.
> > */
> > perf_cpu_map__for_each_cpu(cpu, i, trace->syscalls.events.bpf_output->core.cpus) {
> > + int mycpu = cpu.cpu;
> > +
> > bpf_map__update_elem(trace->skel->maps.__augmented_syscalls__,
> > - &cpu.cpu, sizeof(int),
> > + &mycpu, sizeof(int),
>
> nit: It is usually preferred to do "sizeof(mycpu)" to avoid the
> problems like the one this fix is fixing. And I'm blamed for the bad
> code in:
> 5e6da6be3082 perf trace: Migrate BPF augmentation to use a skeleton
>
> Reviewed-by: Ian Rogers <irogers@xxxxxxxxxx>
>
> Thanks for the fixes!
> Ian
>
> > xyarray__entry(trace->syscalls.events.bpf_output->core.fd,
> > - cpu.cpu, 0),
> > + mycpu, 0),
> > sizeof(__u32), BPF_ANY);
> > }
> > }
> > --
> > 2.48.1
> >