> diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
> index 684a8fb72414..ea6f1389245f 100644
> --- a/tools/bpf/bpftool/map.c
> +++ b/tools/bpf/bpftool/map.c

[ ... ]

> +/* Return 1 to use individual lookups, but only before batch traversal 
> starts. */
> +static int dump_map_batch(int fd, void *key, void *value,
> +                       struct bpf_map_info *info, struct btf *btf,
> +                       json_writer_t *wtr, unsigned int *num_elems)
> +{
> +     __u32 capacity, count, batch = 0, next_batch = 0, i;
> +     void *keys = NULL, *values = NULL, *buf;
> +     bool first = true, can_fallback = true;
> +     int err;

[ ... ]

> +     while (true) {
> +             count = capacity;
> +             err = bpf_map_lookup_batch(fd, first ? NULL : &batch,
> +                                        &next_batch, keys, values, &count, 
> NULL);
> +             err = err ? errno : 0;
> +             /*
> +              * Older kernels reject the command before updating count. Do 
> not
> +              * inspect the buffers on these errors, or fall back after 
> progress.
> +              */
> +             if (can_fallback && (err == EINVAL || err == EOPNOTSUPP ||
> +                                  err == 524 /* ENOTSUPP */)) {
> +                     err = 1;
> +                     goto out;
> +             }
> +             can_fallback = false;
> +             if (err == ENOSPC) {
> +                     if (capacity == info->max_entries)
> +                             goto error;
> +                     capacity += min(capacity, info->max_entries - capacity);
> +                     /* Preserve the input cursor: the oversized bucket was 
> not read. */
> +                     goto resize;
> +             }
> +             /* In particular, EFAULT can leave count and the buffers 
> invalid. */
> +             if (err && err != ENOENT)
> +                     goto error;

[ ... ]

> +             if (err == ENOENT) {
> +                     err = 0;
> +                     goto out;
> +             }
> +             first = false;
> +             batch = next_batch;
> +     }
> +error:
> +     fprintf(stderr, "Error: can't lookup map batch: %s\n", strerror(err));
> +     err = -1;
> +out:
> +     free(keys);
> +     free(values);
> +     return err;
> +}

[ ... ]

> @@ -869,6 +965,9 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t 
> *wtr,
>               p_info("Warning: cannot read values from %s map with value_size 
> != 8",
>                      map_type_str);
>       }
> +     err = dump_map_batch(fd, key, value, info, btf, wtr, &num_elems);
> +     if (err != 1)
> +             goto end_dump;

This isn't a bug, but would a separate flag for the fallback case read
more easily here?  The err variable carries three different kinds of
values: negative returns from bpf_map_lookup_batch(), then positive
errno values after the "err = err ? errno : 0" line, and finally the
special value 1 to signal fallback to individual lookups.  The sentinel
1 happens to equal EPERM numerically, though the logic does keep them
separate since all errno comparisons run before "err = 1" is assigned.
Could using something like "bool fall_back" or a small enum let err
stay purely an errno, so the caller's "if (err != 1)" doesn't have to
encode this third outcome?


---
AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md

CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34557203595

Reply via email to