From: John Fastabend <john.fastabend@gmail.com>
To: bpf@vger.kernel.org
Cc: john.fastabend@gmail.com, daniel@iogearbox.net
Subject: [PATCH bpf-next 1/2] libbpf: add bpf_map__reuse_fd_from_loader_ctx() to allow shared maps
Date: Fri, 26 Jun 2026 14:51:12 -0700 [thread overview]
Message-ID: <20260626215113.52273-1-john.fastabend@gmail.com> (raw)
This lets the gen_loader use a map that may already be loaded/pinned on
the target system. When we are loading many signed programs on the target
we often need them to share maps to communicate/pass data between the
programs.
Note it is slightly complicated by needing to ensure on error/close that
we only emit_sys_close_blob() for map ids that are not these shared
type otherwise we could close a shared map unintentionally. To track this
we added a borrowed_fd_array.
Signed-off-by: John Fastabend <john.fastabend@gmail.com>
---
tools/lib/bpf/bpf_gen_internal.h | 2 ++
tools/lib/bpf/gen_loader.c | 50 ++++++++++++++++++++++++++++++--
tools/lib/bpf/libbpf.c | 11 +++++++
tools/lib/bpf/libbpf.h | 1 +
tools/lib/bpf/libbpf.map | 1 +
5 files changed, 63 insertions(+), 2 deletions(-)
diff --git a/tools/lib/bpf/bpf_gen_internal.h b/tools/lib/bpf/bpf_gen_internal.h
index 49af4260b8e6..e555c3165105 100644
--- a/tools/lib/bpf/bpf_gen_internal.h
+++ b/tools/lib/bpf/bpf_gen_internal.h
@@ -50,6 +50,7 @@ struct bpf_gen {
struct ksym_desc *ksyms;
__u32 nr_ksyms;
int fd_array;
+ int borrowed_fd_array;
int nr_fd_array;
int hash_insn_offset[SHA256_DWORD_SIZE];
};
@@ -62,6 +63,7 @@ void bpf_gen__map_create(struct bpf_gen *gen,
enum bpf_map_type map_type, const char *map_name,
__u32 key_size, __u32 value_size, __u32 max_entries,
struct bpf_map_create_opts *map_attr, int map_idx);
+void bpf_gen__map_reuse_fd(struct bpf_gen *gen, int map_idx);
void bpf_gen__prog_load(struct bpf_gen *gen,
enum bpf_prog_type prog_type, const char *prog_name,
const char *license, struct bpf_insn *insns, size_t insn_cnt,
diff --git a/tools/lib/bpf/gen_loader.c b/tools/lib/bpf/gen_loader.c
index c7f2d2ac7bb3..1cb00e0244b5 100644
--- a/tools/lib/bpf/gen_loader.c
+++ b/tools/lib/bpf/gen_loader.c
@@ -47,6 +47,11 @@ static int blob_fd_array_off(struct bpf_gen *gen, int index)
return gen->fd_array + index * sizeof(int);
}
+static int blob_borrowed_fd_array_off(struct bpf_gen *gen, int index)
+{
+ return gen->borrowed_fd_array + index * sizeof(int);
+}
+
static int realloc_insn_buf(struct bpf_gen *gen, __u32 size)
{
size_t off = gen->insn_cur - gen->insn_start;
@@ -111,6 +116,7 @@ static void emit2(struct bpf_gen *gen, struct bpf_insn insn1, struct bpf_insn in
static int add_data(struct bpf_gen *gen, const void *data, __u32 size);
static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off);
+static void emit_sys_close_owned_blob(struct bpf_gen *gen, int map_idx);
static void emit_signature_match(struct bpf_gen *gen);
void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps)
@@ -119,6 +125,7 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps
int i;
gen->fd_array = add_data(gen, NULL, MAX_FD_ARRAY_SZ * sizeof(int));
+ gen->borrowed_fd_array = add_data(gen, NULL, nr_maps * sizeof(int));
gen->log_level = log_level;
/* save ctx pointer into R6 */
emit(gen, BPF_MOV64_REG(BPF_REG_6, BPF_REG_1));
@@ -137,9 +144,10 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps
/* size of cleanup code below (including map fd cleanup) */
(nr_progs_sz / 4) * 3 + 2 +
/* 6 insns for emit_sys_close_blob,
+ * 4 insns for borrowed fd check,
* 6 insns for debug_regs in emit_sys_close_blob
*/
- nr_maps * (6 + (gen->log_level ? 6 : 0))));
+ nr_maps * (10 + (gen->log_level ? 6 : 0))));
/* remember the label where all error branches will jump to */
gen->cleanup_label = gen->insn_cur - gen->insn_start;
@@ -150,7 +158,7 @@ void bpf_gen__init(struct bpf_gen *gen, int log_level, int nr_progs, int nr_maps
emit(gen, BPF_EMIT_CALL(BPF_FUNC_sys_close));
}
for (i = 0; i < nr_maps; i++)
- emit_sys_close_blob(gen, blob_fd_array_off(gen, i));
+ emit_sys_close_owned_blob(gen, i);
/* R7 contains the error code from sys_bpf. Copy it into R0 and exit. */
emit(gen, BPF_MOV64_REG(BPF_REG_0, BPF_REG_7));
emit(gen, BPF_EXIT_INSN());
@@ -377,6 +385,17 @@ static void emit_sys_close_blob(struct bpf_gen *gen, int blob_off)
__emit_sys_close(gen);
}
+static void emit_sys_close_owned_blob(struct bpf_gen *gen, int map_idx)
+{
+ int close_insn_cnt = 6 + (gen->log_level ? 6 : 0);
+
+ emit2(gen, BPF_LD_IMM64_RAW_FULL(BPF_REG_0, BPF_PSEUDO_MAP_IDX_VALUE,
+ 0, 0, 0, blob_borrowed_fd_array_off(gen, map_idx)));
+ emit(gen, BPF_LDX_MEM(BPF_W, BPF_REG_1, BPF_REG_0, 0));
+ emit(gen, BPF_JMP_IMM(BPF_JNE, BPF_REG_1, 0, close_insn_cnt));
+ emit_sys_close_blob(gen, blob_fd_array_off(gen, map_idx));
+}
+
static void compute_sha_update_offsets(struct bpf_gen *gen);
int bpf_gen__finish(struct bpf_gen *gen, int nr_progs, int nr_maps)
@@ -460,6 +479,11 @@ void bpf_gen__free(struct bpf_gen *gen)
_val; \
})
+static void set_blob_borrowed_fd_array_off(struct bpf_gen *gen, int index)
+{
+ *(__u32 *)(gen->data_start + blob_borrowed_fd_array_off(gen, index)) = tgt_endian(1);
+}
+
static void compute_sha_update_offsets(struct bpf_gen *gen)
{
__u64 sha[SHA256_DWORD_SIZE];
@@ -596,6 +620,28 @@ void bpf_gen__map_create(struct bpf_gen *gen,
emit_sys_close_stack(gen, stack_off(inner_map_fd));
}
+void bpf_gen__map_reuse_fd(struct bpf_gen *gen, int map_idx)
+{
+ int idx;
+
+ if (map_idx != gen->nr_maps) {
+ gen->error = -EDOM;
+ return;
+ }
+
+ idx = add_map_fd(gen);
+ if (gen->error)
+ return;
+
+ set_blob_borrowed_fd_array_off(gen, idx);
+ move_ctx2blob(gen, blob_fd_array_off(gen, idx), 4,
+ sizeof(struct bpf_loader_ctx) +
+ sizeof(struct bpf_map_desc) * map_idx +
+ offsetof(struct bpf_map_desc, map_fd),
+ false);
+ pr_debug("gen: map_reuse_fd idx %d\n", map_idx);
+}
+
static void emit_signature_match(struct bpf_gen *gen)
{
__s64 off;
diff --git a/tools/lib/bpf/libbpf.c b/tools/lib/bpf/libbpf.c
index 7162146280a8..af1553e9d4df 100644
--- a/tools/lib/bpf/libbpf.c
+++ b/tools/lib/bpf/libbpf.c
@@ -5085,6 +5085,15 @@ int bpf_map__reuse_fd(struct bpf_map *map, int fd)
return libbpf_err(err);
}
+int bpf_map__reuse_fd_from_loader_ctx(struct bpf_map *map)
+{
+ if (map_is_created(map))
+ return libbpf_err(-EBUSY);
+
+ map->reused = true;
+ return 0;
+}
+
__u32 bpf_map__max_entries(const struct bpf_map *map)
{
return map->def.max_entries;
@@ -5659,6 +5668,8 @@ bpf_object__create_maps(struct bpf_object *obj)
}
if (map->reused) {
+ if (obj->gen_loader)
+ bpf_gen__map_reuse_fd(obj->gen_loader, map - obj->maps);
pr_debug("map '%s': skipping creation (preset fd=%d)\n",
map->name, map->fd);
} else {
diff --git a/tools/lib/bpf/libbpf.h b/tools/lib/bpf/libbpf.h
index b965ad571540..4145a16c8963 100644
--- a/tools/lib/bpf/libbpf.h
+++ b/tools/lib/bpf/libbpf.h
@@ -1135,6 +1135,7 @@ LIBBPF_API bool bpf_map__autoattach(const struct bpf_map *map);
*/
LIBBPF_API int bpf_map__fd(const struct bpf_map *map);
LIBBPF_API int bpf_map__reuse_fd(struct bpf_map *map, int fd);
+LIBBPF_API int bpf_map__reuse_fd_from_loader_ctx(struct bpf_map *map);
/* get map name */
LIBBPF_API const char *bpf_map__name(const struct bpf_map *map);
/* get/set map type */
diff --git a/tools/lib/bpf/libbpf.map b/tools/lib/bpf/libbpf.map
index b731df19ae69..d6c2f1d75cda 100644
--- a/tools/lib/bpf/libbpf.map
+++ b/tools/lib/bpf/libbpf.map
@@ -458,6 +458,7 @@ LIBBPF_1.7.0 {
LIBBPF_1.8.0 {
global:
+ bpf_map__reuse_fd_from_loader_ctx;
bpf_program__attach_tracing_multi;
bpf_program__clone;
btf__new_empty_opts;
--
2.53.0
next reply other threads:[~2026-06-26 21:51 UTC|newest]
Thread overview: 2+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-06-26 21:51 John Fastabend [this message]
2026-06-26 21:51 ` [PATCH bpf-next 2/2] libbpf: selftest for bpf_map__reuse_fd_from_loader_ctx() John Fastabend
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20260626215113.52273-1-john.fastabend@gmail.com \
--to=john.fastabend@gmail.com \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox