"bpftool map dump" walks the map with bpf_map_get_next_key() and treats
ENOENT as the end of the map. Map types that can't be iterated fail that
call on the very first key: local storage and ringbuf with ENOTSUPP,
bloom filter and arena with EOPNOTSUPP, queue and stack with EINVAL.
bpftool then ends the walk without a word and prints what it prints for
an empty map, "[]" with BTF or "Found 0 elements" without, and only the
exit status tells that the map was not read. On a socket storage map
that holds storage for a socket:

  # bpftool map dump pinned /sys/fs/bpf/sk_storage
  []

Ask for the first key before printing anything, and when that fails with
anything but ENOENT, fail with the map type and the error instead of a
dump:

  # bpftool map dump pinned /sys/fs/bpf/sk_storage
  Error: can't dump sk_storage map: Operation not supported
  # bpftool -j map dump pinned /sys/fs/bpf/sk_storage
  {"error":"can't dump sk_storage map: Operation not supported"}

An error later in the walk is now reported too, as "bpftool map getnext"
reports it, and the element count is printed only after a complete walk.

Assisted-by: LLM
Signed-off-by: Maxim Skokov <[email protected]>
Acked-by: Quentin Monnet <[email protected]>
---
 tools/bpf/bpftool/map.c | 22 ++++++++++++++++++++--
 1 file changed, 20 insertions(+), 2 deletions(-)

diff --git a/tools/bpf/bpftool/map.c b/tools/bpf/bpftool/map.c
index d809b075e734f..4b65edf74859b 100644
--- a/tools/bpf/bpftool/map.c
+++ b/tools/bpf/bpftool/map.c
@@ -856,6 +856,21 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t 
*wtr,
                }
        }
 
+       /* Fail early to avoid an empty dump if map type cannot be iterated */
+       if (bpf_map_get_next_key(fd, NULL, key) && errno != ENOENT) {
+               const char *map_type_str, *err_str;
+
+               err_str = bpf_strerror(errno);
+               map_type_str = libbpf_bpf_map_type_str(info->type);
+               if (map_type_str)
+                       p_err("can't dump %s map: %s", map_type_str, err_str);
+               else
+                       p_err("can't dump map of type %u: %s", info->type,
+                             err_str);
+               err = -1;
+               goto exit_free;
+       }
+
        if (wtr) {
                err = get_map_kv_btf(info, &btf);
                if (err) {
@@ -883,8 +898,11 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t 
*wtr,
        while (true) {
                err = bpf_map_get_next_key(fd, prev_key, key);
                if (err) {
-                       if (errno == ENOENT)
+                       if (errno == ENOENT) {
                                err = 0;
+                               break;
+                       }
+                       p_err("can't get next key: %s", bpf_strerror(errno));
                        break;
                }
                if (!dump_map_elem(fd, key, value, info, btf, wtr,
@@ -897,7 +915,7 @@ map_dump(int fd, struct bpf_map_info *info, json_writer_t 
*wtr,
                jsonw_end_array(wtr);   /* elements */
                if (show_header)
                        jsonw_end_object(wtr);  /* map object */
-       } else {
+       } else if (!err) {
                printf("Found %u element%s\n", num_elems,
                       num_elems != 1 ? "s" : "");
        }
-- 
2.47.3


Reply via email to