> 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