Skip to content

Commit 403de6c

Browse files
committed
libbpf: Split bpf object load into prepare/load
JIRA: https://issues.redhat.com/browse/RHEL-78202 commit 1315c28 Author: Mykyta Yatsenko <yatsenko@meta.com> Date: Mon Mar 3 13:57:51 2025 +0000 libbpf: Split bpf object load into prepare/load Introduce bpf_object__prepare API: additional intermediate preparation step that performs ELF processing, relocations, prepares final state of BPF program instructions (accessible with bpf_program__insns()), creates and (potentially) pins maps, and stops short of loading BPF programs. We anticipate few use cases for this API, such as: * Use prepare to initialize bpf_token, without loading freplace programs, unlocking possibility to lookup BTF of other programs. * Execute prepare to obtain finalized BPF program instructions without loading programs, enabling tools like veristat to process one program at a time, without incurring cost of ELF parsing and processing. Signed-off-by: Mykyta Yatsenko <yatsenko@meta.com> Signed-off-by: Andrii Nakryiko <andrii@kernel.org> Link: https://lore.kernel.org/bpf/20250303135752.158343-4-mykyta.yatsenko5@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org> Signed-off-by: Gregory Bell <grbell@redhat.com>
1 parent 235feb2 commit 403de6c

File tree

3 files changed

+117
-43
lines changed

3 files changed

+117
-43
lines changed

tools/lib/bpf/libbpf.c

Lines changed: 103 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -7892,13 +7892,6 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level)
78927892
size_t i;
78937893
int err;
78947894

7895-
for (i = 0; i < obj->nr_programs; i++) {
7896-
prog = &obj->programs[i];
7897-
err = bpf_object__sanitize_prog(obj, prog);
7898-
if (err)
7899-
return err;
7900-
}
7901-
79027895
for (i = 0; i < obj->nr_programs; i++) {
79037896
prog = &obj->programs[i];
79047897
if (prog_is_subprog(obj, prog))
@@ -7924,6 +7917,21 @@ bpf_object__load_progs(struct bpf_object *obj, int log_level)
79247917
return 0;
79257918
}
79267919

7920+
static int bpf_object_prepare_progs(struct bpf_object *obj)
7921+
{
7922+
struct bpf_program *prog;
7923+
size_t i;
7924+
int err;
7925+
7926+
for (i = 0; i < obj->nr_programs; i++) {
7927+
prog = &obj->programs[i];
7928+
err = bpf_object__sanitize_prog(obj, prog);
7929+
if (err)
7930+
return err;
7931+
}
7932+
return 0;
7933+
}
7934+
79277935
static const struct bpf_sec_def *find_sec_def(const char *sec_name);
79287936

79297937
static int bpf_object_init_progs(struct bpf_object *obj, const struct bpf_object_open_opts *opts)
@@ -8540,9 +8548,72 @@ static int bpf_object_prepare_struct_ops(struct bpf_object *obj)
85408548
return 0;
85418549
}
85428550

8551+
static void bpf_object_unpin(struct bpf_object *obj)
8552+
{
8553+
int i;
8554+
8555+
/* unpin any maps that were auto-pinned during load */
8556+
for (i = 0; i < obj->nr_maps; i++)
8557+
if (obj->maps[i].pinned && !obj->maps[i].reused)
8558+
bpf_map__unpin(&obj->maps[i], NULL);
8559+
}
8560+
8561+
static void bpf_object_post_load_cleanup(struct bpf_object *obj)
8562+
{
8563+
int i;
8564+
8565+
/* clean up fd_array */
8566+
zfree(&obj->fd_array);
8567+
8568+
/* clean up module BTFs */
8569+
for (i = 0; i < obj->btf_module_cnt; i++) {
8570+
close(obj->btf_modules[i].fd);
8571+
btf__free(obj->btf_modules[i].btf);
8572+
free(obj->btf_modules[i].name);
8573+
}
8574+
obj->btf_module_cnt = 0;
8575+
zfree(&obj->btf_modules);
8576+
8577+
/* clean up vmlinux BTF */
8578+
btf__free(obj->btf_vmlinux);
8579+
obj->btf_vmlinux = NULL;
8580+
}
8581+
8582+
static int bpf_object_prepare(struct bpf_object *obj, const char *target_btf_path)
8583+
{
8584+
int err;
8585+
8586+
if (obj->state >= OBJ_PREPARED) {
8587+
pr_warn("object '%s': prepare loading can't be attempted twice\n", obj->name);
8588+
return -EINVAL;
8589+
}
8590+
8591+
err = bpf_object_prepare_token(obj);
8592+
err = err ? : bpf_object__probe_loading(obj);
8593+
err = err ? : bpf_object__load_vmlinux_btf(obj, false);
8594+
err = err ? : bpf_object__resolve_externs(obj, obj->kconfig);
8595+
err = err ? : bpf_object__sanitize_maps(obj);
8596+
err = err ? : bpf_object__init_kern_struct_ops_maps(obj);
8597+
err = err ? : bpf_object_adjust_struct_ops_autoload(obj);
8598+
err = err ? : bpf_object__relocate(obj, obj->btf_custom_path ? : target_btf_path);
8599+
err = err ? : bpf_object__sanitize_and_load_btf(obj);
8600+
err = err ? : bpf_object__create_maps(obj);
8601+
err = err ? : bpf_object_prepare_progs(obj);
8602+
8603+
if (err) {
8604+
bpf_object_unpin(obj);
8605+
bpf_object_unload(obj);
8606+
obj->state = OBJ_LOADED;
8607+
return err;
8608+
}
8609+
8610+
obj->state = OBJ_PREPARED;
8611+
return 0;
8612+
}
8613+
85438614
static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const char *target_btf_path)
85448615
{
8545-
int err, i;
8616+
int err;
85468617

85478618
if (!obj)
85488619
return libbpf_err(-EINVAL);
@@ -8562,17 +8633,12 @@ static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const ch
85628633
return libbpf_err(-LIBBPF_ERRNO__ENDIAN);
85638634
}
85648635

8565-
err = bpf_object_prepare_token(obj);
8566-
err = err ? : bpf_object__probe_loading(obj);
8567-
err = err ? : bpf_object__load_vmlinux_btf(obj, false);
8568-
err = err ? : bpf_object__resolve_externs(obj, obj->kconfig);
8569-
err = err ? : bpf_object__sanitize_maps(obj);
8570-
err = err ? : bpf_object__init_kern_struct_ops_maps(obj);
8571-
err = err ? : bpf_object_adjust_struct_ops_autoload(obj);
8572-
err = err ? : bpf_object__relocate(obj, obj->btf_custom_path ? : target_btf_path);
8573-
err = err ? : bpf_object__sanitize_and_load_btf(obj);
8574-
err = err ? : bpf_object__create_maps(obj);
8575-
err = err ? : bpf_object__load_progs(obj, extra_log_level);
8636+
if (obj->state < OBJ_PREPARED) {
8637+
err = bpf_object_prepare(obj, target_btf_path);
8638+
if (err)
8639+
return libbpf_err(err);
8640+
}
8641+
err = bpf_object__load_progs(obj, extra_log_level);
85768642
err = err ? : bpf_object_init_prog_arrays(obj);
85778643
err = err ? : bpf_object_prepare_struct_ops(obj);
85788644

@@ -8584,35 +8650,22 @@ static int bpf_object_load(struct bpf_object *obj, int extra_log_level, const ch
85848650
err = bpf_gen__finish(obj->gen_loader, obj->nr_programs, obj->nr_maps);
85858651
}
85868652

8587-
/* clean up fd_array */
8588-
zfree(&obj->fd_array);
8653+
bpf_object_post_load_cleanup(obj);
8654+
obj->state = OBJ_LOADED; /* doesn't matter if successfully or not */
85898655

8590-
/* clean up module BTFs */
8591-
for (i = 0; i < obj->btf_module_cnt; i++) {
8592-
close(obj->btf_modules[i].fd);
8593-
btf__free(obj->btf_modules[i].btf);
8594-
free(obj->btf_modules[i].name);
8656+
if (err) {
8657+
bpf_object_unpin(obj);
8658+
bpf_object_unload(obj);
8659+
pr_warn("failed to load object '%s'\n", obj->path);
8660+
return libbpf_err(err);
85958661
}
8596-
free(obj->btf_modules);
8597-
8598-
/* clean up vmlinux BTF */
8599-
btf__free(obj->btf_vmlinux);
8600-
obj->btf_vmlinux = NULL;
8601-
8602-
obj->state = OBJ_LOADED; /* doesn't matter if successfully or not */
8603-
if (err)
8604-
goto out;
86058662

86068663
return 0;
8607-
out:
8608-
/* unpin any maps that were auto-pinned during load */
8609-
for (i = 0; i < obj->nr_maps; i++)
8610-
if (obj->maps[i].pinned && !obj->maps[i].reused)
8611-
bpf_map__unpin(&obj->maps[i], NULL);
8664+
}
86128665

8613-
bpf_object_unload(obj);
8614-
pr_warn("failed to load object '%s'\n", obj->path);
8615-
return libbpf_err(err);
8666+
int bpf_object__prepare(struct bpf_object *obj)
8667+
{
8668+
return libbpf_err(bpf_object_prepare(obj, NULL));
86168669
}
86178670

86188671
int bpf_object__load(struct bpf_object *obj)
@@ -9060,6 +9113,13 @@ void bpf_object__close(struct bpf_object *obj)
90609113
if (IS_ERR_OR_NULL(obj))
90619114
return;
90629115

9116+
/*
9117+
* if user called bpf_object__prepare() without ever getting to
9118+
* bpf_object__load(), we need to clean up stuff that is normally
9119+
* cleaned up at the end of loading step
9120+
*/
9121+
bpf_object_post_load_cleanup(obj);
9122+
90639123
usdt_manager_free(obj->usdt_man);
90649124
obj->usdt_man = NULL;
90659125

tools/lib/bpf/libbpf.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -241,6 +241,19 @@ LIBBPF_API struct bpf_object *
241241
bpf_object__open_mem(const void *obj_buf, size_t obj_buf_sz,
242242
const struct bpf_object_open_opts *opts);
243243

244+
/**
245+
* @brief **bpf_object__prepare()** prepares BPF object for loading:
246+
* performs ELF processing, relocations, prepares final state of BPF program
247+
* instructions (accessible with bpf_program__insns()), creates and
248+
* (potentially) pins maps. Leaves BPF object in the state ready for program
249+
* loading.
250+
* @param obj Pointer to a valid BPF object instance returned by
251+
* **bpf_object__open*()** API
252+
* @return 0, on success; negative error code, otherwise, error code is
253+
* stored in errno
254+
*/
255+
int bpf_object__prepare(struct bpf_object *obj);
256+
244257
/**
245258
* @brief **bpf_object__load()** loads BPF object into kernel.
246259
* @param obj Pointer to a valid BPF object instance returned by

tools/lib/bpf/libbpf.map

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -436,6 +436,7 @@ LIBBPF_1.6.0 {
436436
bpf_linker__add_buf;
437437
bpf_linker__add_fd;
438438
bpf_linker__new_fd;
439+
bpf_object__prepare;
439440
btf__add_decl_attr;
440441
btf__add_type_attr;
441442
} LIBBPF_1.5.0;

0 commit comments

Comments
 (0)