> diff --git a/tools/testing/selftests/bpf/prog_tests/bpftool_map_dump.c
> b/tools/testing/selftests/bpf/prog_tests/bpftool_map_dump.c
> new file mode 100644
> index 000000000000..db547a68d0a2
> --- /dev/null
> +++ b/tools/testing/selftests/bpf/prog_tests/bpftool_map_dump.c
[ ... ]
> + /*
> + * Compare the complete JSON document: a flat array with the root first,
> + * one copy of the shared inner map, and unchanged entry
> representations.
> + */
> + if (entries)
> + snprintf(expected, sizeof(expected),
> + "[{\"id\":%u,\"type\":\"%s\",\"name\":\"dump_outer\","
> +
> "\"flags\":0,\"elements\":%s},{\"id\":%u,\"type\":\"hash\","
> +
> "\"name\":\"dump_inner\",\"flags\":0,\"elements\":%s}]",
> + root_id, type_name, outer, inner_id, inner);
This isn't a bug, but the map-object JSON template appears six times
across test_outer(), test_multiple_roots() and test_unreadable() - would
a small helper that formats one {"id":..,"elements":..} object keep them
from drifting apart?
[ ... ]
> +static void test_many_inner_maps(bool json)
> +{
> + LIBBPF_OPTS(bpf_map_create_opts, opts);
> + const struct rlimit limit = { .rlim_cur = 32, .rlim_max = 32 };
> + char command[MAX_BPFTOOL_CMD_LEN], token[64];
> + __u32 ids[64], root_id, key;
> + int inner_fd = -1, outer_fd = -1, status;
> + int inherited_fds[32], nr_inherited = 0, i;
> + char *output = NULL;
> + pid_t pid;
[ ... ]
> + pid = fork();
> + if (!ASSERT_GE(pid, 0, "fork"))
> + goto out;
> + if (!pid) {
> + struct dirent *entry;
> + DIR *dir;
> +
> + /* Reserve a slot for the directory even if the parent is full.
> */
> + close(inherited_fds[nr_inherited - 1]);
> + dir = opendir("/proc/self/fd");
> + if (!dir)
> + _exit(6);
> + /* The parent keeps the outer map and its inner maps alive. */
> + for (;;) {
> + char *end;
> + long fd;
> +
> + errno = 0;
> + entry = readdir(dir);
> + if (!entry) {
> + if (errno)
> + _exit(6);
> + break;
> + }
> + fd = strtol(entry->d_name, &end, 10);
> + if (*end || fd < 3 || fd == dirfd(dir))
> + continue;
> + close(fd);
> + }
> + if (closedir(dir))
> + _exit(6);
> + if (setrlimit(RLIMIT_NOFILE, &limit))
> + _exit(1);
> + snprintf(command, sizeof(command), "%s -r map dump id %u",
> + json ? "-j" : "", root_id);
> + if (get_bpftool_command_output(command, output, 65535))
> + _exit(2);
> + if (count_token(output, json ? "\"id\":" : "Found ") !=
> ARRAY_SIZE(ids) + 1 ||
> + count_token(output, json ? "\"inner_map_id\":" :
> "inner_map_id:") !=
> + ARRAY_SIZE(ids))
> + _exit(3);
> + for (key = 0; key < ARRAY_SIZE(ids); key++) {
> + if (json)
> + snprintf(token, sizeof(token), "\"id\":%u,",
> ids[key]);
> + else
> + snprintf(token, sizeof(token), "\n%u: hash
> name dump_inner ",
> + ids[key]);
> + if (count_token(output, token) != 1)
> + _exit(4);
> + }
> + if (json && (output[0] != '[' ||
> + strcmp(output + strlen(output) - 2, "]\n")))
> + _exit(5);
> + _exit(0);
> + }
This isn't a bug, but would small named constants (or a one-line comment
table) for these exit codes make a CI failure easier to triage than the
bare numbers?
---
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/34557170753