]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
selftests/bpf: Use bpf_program__clone() in veristat
authorMykyta Yatsenko <yatsenko@meta.com>
Tue, 17 Mar 2026 17:39:22 +0000 (10:39 -0700)
committerAlexei Starovoitov <ast@kernel.org>
Sat, 21 Mar 2026 20:17:14 +0000 (13:17 -0700)
Replace veristat's per-program object re-opening with
bpf_program__clone().

Previously, veristat opened a separate bpf_object for every program in a
multi-program object file, iterated all programs to enable only the
target one, and then loaded the entire object.

Use bpf_object__prepare() once, then call bpf_program__clone() for each
program individually. This lets veristat load programs one at a time
from a single prepared object.

The caller now owns the returned fd and closes it after collecting stats.
Remove the special single-program fast path and the per-file early exit
in handle_verif_mode() so all files are always processed.

Split fixup_obj() into fixup_obj_maps() for object-wide map fixups that
must run before bpf_object__prepare(), and fixup_obj() for per-program
fixups (struct_ops masking, freplace type guessing) that run before each
bpf_program__clone() call.

Reviewed-by: Emil Tsalapatis <emil@etsalapatis.com>
Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com>
Link: https://lore.kernel.org/r/20260317-veristat_prepare-v4-2-74193d4cc9d9@meta.com
Signed-off-by: Alexei Starovoitov <ast@kernel.org>
tools/testing/selftests/bpf/veristat.c

index 75f85e0362f529cc74426daab58ab443356e439d..9652649171ced8d12108664a12419f8ae5e77d3c 100644 (file)
@@ -1236,7 +1236,7 @@ static void mask_unrelated_struct_ops_progs(struct bpf_object *obj,
        }
 }
 
-static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const char *filename)
+static void fixup_obj_maps(struct bpf_object *obj)
 {
        struct bpf_map *map;
 
@@ -1251,15 +1251,23 @@ static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const ch
                case BPF_MAP_TYPE_INODE_STORAGE:
                case BPF_MAP_TYPE_CGROUP_STORAGE:
                case BPF_MAP_TYPE_CGRP_STORAGE:
-                       break;
                case BPF_MAP_TYPE_STRUCT_OPS:
-                       mask_unrelated_struct_ops_progs(obj, map, prog);
                        break;
                default:
                        if (bpf_map__max_entries(map) == 0)
                                bpf_map__set_max_entries(map, 1);
                }
        }
+}
+
+static void fixup_obj(struct bpf_object *obj, struct bpf_program *prog, const char *filename)
+{
+       struct bpf_map *map;
+
+       bpf_object__for_each_map(map, obj) {
+               if (bpf_map__type(map) == BPF_MAP_TYPE_STRUCT_OPS)
+                       mask_unrelated_struct_ops_progs(obj, map, prog);
+       }
 
        /* SEC(freplace) programs can't be loaded with veristat as is,
         * but we can try guessing their target program's expected type by
@@ -1608,6 +1616,7 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
        const char *base_filename = basename(strdupa(filename));
        const char *prog_name = bpf_program__name(prog);
        long mem_peak_a, mem_peak_b, mem_peak = -1;
+       LIBBPF_OPTS(bpf_prog_load_opts, opts);
        char *buf;
        int buf_sz, log_level;
        struct verif_stats *stats;
@@ -1647,9 +1656,6 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
        }
        verif_log_buf[0] = '\0';
 
-       bpf_program__set_log_buf(prog, buf, buf_sz);
-       bpf_program__set_log_level(prog, log_level);
-
        /* increase chances of successful BPF object loading */
        fixup_obj(obj, prog, base_filename);
 
@@ -1658,15 +1664,21 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
        if (env.force_reg_invariants)
                bpf_program__set_flags(prog, bpf_program__flags(prog) | BPF_F_TEST_REG_INVARIANTS);
 
-       err = bpf_object__prepare(obj);
-       if (!err) {
-               cgroup_err = reset_stat_cgroup();
-               mem_peak_a = cgroup_memory_peak();
-               err = bpf_object__load(obj);
-               mem_peak_b = cgroup_memory_peak();
-               if (!cgroup_err && mem_peak_a >= 0 && mem_peak_b >= 0)
-                       mem_peak = mem_peak_b - mem_peak_a;
+       opts.log_buf = buf;
+       opts.log_size = buf_sz;
+       opts.log_level = log_level;
+
+       cgroup_err = reset_stat_cgroup();
+       mem_peak_a = cgroup_memory_peak();
+       fd = bpf_program__clone(prog, &opts);
+       if (fd < 0) {
+               err = fd;
+               fprintf(stderr, "Failed to load program %s %d\n", prog_name, err);
        }
+       mem_peak_b = cgroup_memory_peak();
+       if (!cgroup_err && mem_peak_a >= 0 && mem_peak_b >= 0)
+               mem_peak = mem_peak_b - mem_peak_a;
+
        env.progs_processed++;
 
        stats->file_name = strdup(base_filename);
@@ -1678,7 +1690,6 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
        stats->stats[MEMORY_PEAK] = mem_peak < 0 ? -1 : mem_peak / (1024 * 1024);
 
        memset(&info, 0, info_len);
-       fd = bpf_program__fd(prog);
        if (fd > 0 && bpf_prog_get_info_by_fd(fd, &info, &info_len) == 0) {
                stats->stats[JITED_SIZE] = info.jited_prog_len;
                if (env.dump_mode & DUMP_JITED)
@@ -1699,7 +1710,8 @@ static int process_prog(const char *filename, struct bpf_object *obj, struct bpf
 
        if (verif_log_buf != buf)
                free(buf);
-
+       if (fd > 0)
+               close(fd);
        return 0;
 }
 
@@ -2182,8 +2194,8 @@ static int set_global_vars(struct bpf_object *obj, struct var_preset *presets, i
 static int process_obj(const char *filename)
 {
        const char *base_filename = basename(strdupa(filename));
-       struct bpf_object *obj = NULL, *tobj;
-       struct bpf_program *prog, *tprog, *lprog;
+       struct bpf_object *obj = NULL;
+       struct bpf_program *prog;
        libbpf_print_fn_t old_libbpf_print_fn;
        LIBBPF_OPTS(bpf_object_open_opts, opts);
        int err = 0, prog_cnt = 0;
@@ -2222,51 +2234,24 @@ static int process_obj(const char *filename)
        env.files_processed++;
 
        bpf_object__for_each_program(prog, obj) {
+               bpf_program__set_autoload(prog, true);
                prog_cnt++;
        }
 
-       if (prog_cnt == 1) {
-               prog = bpf_object__next_program(obj, NULL);
-               bpf_program__set_autoload(prog, true);
-               err = set_global_vars(obj, env.presets, env.npresets);
-               if (err) {
-                       fprintf(stderr, "Failed to set global variables %d\n", err);
-                       goto cleanup;
-               }
-               process_prog(filename, obj, prog);
+       fixup_obj_maps(obj);
+
+       err = set_global_vars(obj, env.presets, env.npresets);
+       if (err) {
+               fprintf(stderr, "Failed to set global variables %d\n", err);
                goto cleanup;
        }
 
-       bpf_object__for_each_program(prog, obj) {
-               const char *prog_name = bpf_program__name(prog);
-
-               tobj = bpf_object__open_file(filename, &opts);
-               if (!tobj) {
-                       err = -errno;
-                       fprintf(stderr, "Failed to open '%s': %d\n", filename, err);
-                       goto cleanup;
-               }
-
-               err = set_global_vars(tobj, env.presets, env.npresets);
-               if (err) {
-                       fprintf(stderr, "Failed to set global variables %d\n", err);
-                       goto cleanup;
-               }
-
-               lprog = NULL;
-               bpf_object__for_each_program(tprog, tobj) {
-                       const char *tprog_name = bpf_program__name(tprog);
-
-                       if (strcmp(prog_name, tprog_name) == 0) {
-                               bpf_program__set_autoload(tprog, true);
-                               lprog = tprog;
-                       } else {
-                               bpf_program__set_autoload(tprog, false);
-                       }
-               }
+       err = bpf_object__prepare(obj);
+       if (err) /* run process_prog() anyway to output per program failures */
+               fprintf(stderr, "Failed to prepare BPF object for loading %d\n", err);
 
-               process_prog(filename, tobj, lprog);
-               bpf_object__close(tobj);
+       bpf_object__for_each_program(prog, obj) {
+               process_prog(filename, obj, prog);
        }
 
 cleanup:
@@ -3264,17 +3249,14 @@ static int handle_verif_mode(void)
        create_stat_cgroup();
        for (i = 0; i < env.filename_cnt; i++) {
                err = process_obj(env.filenames[i]);
-               if (err) {
+               if (err)
                        fprintf(stderr, "Failed to process '%s': %d\n", env.filenames[i], err);
-                       goto out;
-               }
        }
 
        qsort(env.prog_stats, env.prog_stat_cnt, sizeof(*env.prog_stats), cmp_prog_stats);
 
        output_prog_stats();
 
-out:
        destroy_stat_cgroup();
        return err;
 }