From: Yonghong Song <yonghong.song@linux.dev>
To: bpf@vger.kernel.org
Cc: Alexei Starovoitov <ast@kernel.org>,
Andrii Nakryiko <andrii@kernel.org>,
Daniel Borkmann <daniel@iogearbox.net>,
Eduard Zingerman <eddyz87@gmail.com>,
kernel-team@fb.com
Subject: [PATCH bpf-next v9 10/23] bpf: Prepare JITed programs for dispatching cleanup pads
Date: Thu, 8 Oct 2026 00:50:50 -0700 [thread overview]
Message-ID: <20261008075050.3000674-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20261008074959.2993751-1-yonghong.song@linux.dev>
The next patch makes bpf_unwind() rewrite the saved return address of
each frame above its caller: to the pad covering the call, else to the
frame's epilogue. Every frame then just returns, its epilogue restoring
its caller's r6-r9. This patch adds what that relies on:
- Each bpf_unwind() call is followed by 'r0 = 0' and a jump to its pad,
or an exit: the walk leaves the calling frame alone.
- A pad's resume lowers to 'r0 = 0; exit'.
- Each JITed function gets a table of its covered calls as native
address ranges, looked up by bpf_exc_pad_for_ip(). The main
function's table, and its epilogue_ip, go to the outer program.
- Every function the walk can pass needs an epilogue, which x86 emits
at a function's first exit. keep_subprog_exits() keeps one through
dead code removal, and refuses a function with none.
- arch_bpf_stack_walk_ra() walks the stack handing out each
return-address slot. Where an arch has only the weak stub, nothing is
dispatched, so any program that can unwind, table or not, is now held
to bpf_exc_check_prog().
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
include/linux/bpf.h | 30 ++++++++
include/linux/bpf_verifier.h | 1 +
include/linux/filter.h | 2 +
kernel/bpf/core.c | 7 ++
kernel/bpf/exception.c | 77 ++++++++++++++++++++
kernel/bpf/exception.h | 6 ++
kernel/bpf/fixups.c | 135 ++++++++++++++++++++++++++++++++++-
kernel/bpf/verifier.c | 5 +-
8 files changed, 261 insertions(+), 2 deletions(-)
diff --git a/include/linux/bpf.h b/include/linux/bpf.h
index 54144372281c..7f23f4efde01 100644
--- a/include/linux/bpf.h
+++ b/include/linux/bpf.h
@@ -1841,6 +1841,34 @@ enum bpf_sig_keyring {
BPF_SIG_KEYRING_BPF,
};
+/* One cleanup region of a JITed (sub)program. */
+struct bpf_cleanup_range {
+ u64 begin;
+ u64 end;
+ u64 pad;
+};
+
+struct bpf_exception_info {
+ struct bpf_cleanup_info *info;
+ struct bpf_cleanup_range *ranges;
+ u32 nr_info;
+ u32 nr_ranges;
+};
+
+#ifdef CONFIG_BPF_SYSCALL
+void bpf_exc_fill_native_ranges(struct bpf_prog *prog, u32 *addrs, void *image);
+void bpf_exc_free_info(struct bpf_prog_aux *aux);
+#else
+
+static inline void bpf_exc_fill_native_ranges(struct bpf_prog *prog, u32 *addrs, void *image)
+{
+}
+
+static inline void bpf_exc_free_info(struct bpf_prog_aux *aux)
+{
+}
+#endif
+
struct bpf_prog_aux {
atomic64_t refcnt;
u32 used_map_cnt;
@@ -1922,6 +1950,8 @@ struct bpf_prog_aux {
u64 (*bpf_exception_cb)(u64 cookie, u64 sp, u64 bp, u64, u64);
u16 stack_arg_sp_adjust;
u16 freplace_link_cnt; /* counts freplace links extending this prog */
+ struct bpf_exception_info *exc;
+ u64 epilogue_ip; /* native address of this (sub)program's epilogue */
#ifdef CONFIG_SECURITY
void *security;
#endif
diff --git a/include/linux/bpf_verifier.h b/include/linux/bpf_verifier.h
index 6449e4babc60..8f67126719fe 100644
--- a/include/linux/bpf_verifier.h
+++ b/include/linux/bpf_verifier.h
@@ -1853,6 +1853,7 @@ int bpf_opt_subreg_zext_lo32_rnd_hi32(struct bpf_verifier_env *env, const union
int bpf_convert_ctx_accesses(struct bpf_verifier_env *env);
int bpf_jit_subprogs(struct bpf_verifier_env *env);
int bpf_fixup_call_args(struct bpf_verifier_env *env);
+int bpf_exc_patch_unwind_calls(struct bpf_verifier_env *env);
int bpf_do_misc_fixups(struct bpf_verifier_env *env);
int bpf_insn_def32(struct bpf_prog *prog, struct bpf_insn *insn);
diff --git a/include/linux/filter.h b/include/linux/filter.h
index c8ca863e352a..a61a78675d11 100644
--- a/include/linux/filter.h
+++ b/include/linux/filter.h
@@ -1291,6 +1291,8 @@ u32 bpf_jit_plan_arg_moves(const struct bpf_jit_arg_abi *abi,
struct bpf_jit_arg_move *moves);
u64 bpf_arch_uaddress_limit(void);
void arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp), void *cookie);
+void arch_bpf_stack_walk_ra(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp, u64 *ra),
+ void *cookie);
u64 arch_bpf_timed_may_goto(void);
u64 bpf_check_timed_may_goto(struct bpf_timed_may_goto *);
bool bpf_helper_changes_pkt_data(enum bpf_func_id func_id);
diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c
index 078bcccaf242..9ed9da581ed5 100644
--- a/kernel/bpf/core.c
+++ b/kernel/bpf/core.c
@@ -293,6 +293,7 @@ void __bpf_prog_free(struct bpf_prog *fp)
mutex_destroy(&fp->aux->dst_mutex);
mutex_destroy(&fp->aux->st_ops_assoc_mutex);
kfree(fp->aux->poke_tab);
+ bpf_exc_free_info(fp->aux);
kfree(fp->aux);
}
free_percpu(fp->stats);
@@ -3528,6 +3529,12 @@ void __weak arch_bpf_stack_walk(bool (*consume_fn)(void *cookie, u64 ip, u64 sp,
{
}
+void __weak arch_bpf_stack_walk_ra(bool (*consume_fn)(void *cookie, u64 ip, u64 sp, u64 bp,
+ u64 *ra),
+ void *cookie)
+{
+}
+
bool __weak bpf_jit_supports_cleanup_pads(void)
{
return false;
diff --git a/kernel/bpf/exception.c b/kernel/bpf/exception.c
index 035eb4d87588..9f7ed78a65d0 100644
--- a/kernel/bpf/exception.c
+++ b/kernel/bpf/exception.c
@@ -307,3 +307,80 @@ int bpf_exc_pad_of_call(struct bpf_verifier_env *env, u32 idx)
return pad ? (int)pad - 1 : -1;
}
+
+/*
+ * The record covering @ip, which is a return address: the call it belongs to
+ * is the instruction before it, so a range matches on begin < ip <= end.
+ */
+const struct bpf_cleanup_range *bpf_exc_pad_for_ip(const struct bpf_prog *prog, u64 ip)
+{
+ const struct bpf_exception_info *exc = prog->aux->exc;
+ u32 l = 0, r = exc ? exc->nr_ranges : 0;
+
+ while (l < r) {
+ u32 m = l + (r - l) / 2;
+ const struct bpf_cleanup_range *rec = &exc->ranges[m];
+
+ if (ip <= rec->begin)
+ r = m;
+ else if (ip > rec->end)
+ l = m + 1;
+ else
+ return rec;
+ }
+ return NULL;
+}
+
+int bpf_exc_attach_info(struct bpf_prog_aux *aux, struct bpf_cleanup_info *recs, u32 cnt)
+{
+ struct bpf_cleanup_range *ranges;
+ struct bpf_exception_info *exc;
+
+ exc = kzalloc_obj(struct bpf_exception_info, GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
+ ranges = kvcalloc(cnt, sizeof(*ranges), GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
+ if (!exc || !ranges) {
+ kfree(exc);
+ kvfree(ranges);
+ kvfree(recs);
+ return -ENOMEM;
+ }
+
+ exc->info = recs;
+ exc->nr_info = cnt;
+ exc->ranges = ranges;
+ /* Withheld until the JIT has filled the table in. */
+ exc->nr_ranges = 0;
+ aux->exc = exc;
+ return 0;
+}
+
+void bpf_exc_fill_native_ranges(struct bpf_prog *prog, u32 *addrs, void *image)
+{
+ struct bpf_exception_info *exc = prog->aux->exc;
+ u32 i, n;
+
+ if (!exc)
+ return;
+
+ n = exc->nr_info;
+ for (i = 0; i < n; i++) {
+ const struct bpf_cleanup_info *rec = &exc->info[i];
+
+ exc->ranges[i].begin = (u64)(long)image + addrs[rec->begin_off];
+ exc->ranges[i].end = (u64)(long)image + addrs[rec->end_off];
+ exc->ranges[i].pad = (u64)(long)image + addrs[rec->landing_pad_off];
+ }
+ exc->nr_ranges = n;
+}
+
+void bpf_exc_free_info(struct bpf_prog_aux *aux)
+{
+ struct bpf_exception_info *exc = aux->exc;
+
+ if (!exc)
+ return;
+ kvfree(exc->ranges);
+ kvfree(exc->info);
+ kfree(exc);
+ aux->exc = NULL;
+}
diff --git a/kernel/bpf/exception.h b/kernel/bpf/exception.h
index dea45c7e4925..b55ce5c2b9c6 100644
--- a/kernel/bpf/exception.h
+++ b/kernel/bpf/exception.h
@@ -9,6 +9,10 @@
union bpf_attr;
struct bpf_verifier_env;
struct bpf_insn;
+struct bpf_cleanup_info;
+struct bpf_cleanup_range;
+struct bpf_prog;
+struct bpf_prog_aux;
int bpf_exc_check_info(struct bpf_verifier_env *env, const union bpf_attr *attr,
bpfptr_t uattr);
@@ -20,5 +24,7 @@ bool bpf_is_unwind_kfunc(const struct bpf_insn *insn);
bool bpf_is_unwind_resume_kfunc(const struct bpf_insn *insn);
int bpf_exc_check_callback(struct bpf_verifier_env *env, int subprog);
int bpf_exc_check_insn(struct bpf_verifier_env *env, struct bpf_insn *insn);
+int bpf_exc_attach_info(struct bpf_prog_aux *aux, struct bpf_cleanup_info *recs, u32 cnt);
+const struct bpf_cleanup_range *bpf_exc_pad_for_ip(const struct bpf_prog *prog, u64 ip);
#endif /* __BPF_EXCEPTION_H */
diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 64baee1a37e6..1cc025c45ecd 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -9,6 +9,7 @@
#include <linux/sched/signal.h>
#include <net/xdp.h>
#include "disasm.h"
+#include "exception.h"
#define verbose(env, fmt, args...) bpf_verifier_log_write(env, fmt, ##args)
@@ -715,6 +716,32 @@ static void keep_funcs_with_addr_taken(struct bpf_verifier_env *env)
}
}
+static int keep_subprog_exits(struct bpf_verifier_env *env)
+{
+ u32 i, j;
+
+ for (i = 0; i < env->subprog_cnt; i++) {
+ bool found = false;
+ u32 start;
+
+ if (!env->subprog_info[i].might_unwind)
+ continue;
+ start = env->subprog_info[i].start;
+ for (j = env->subprog_info[i + 1].start; j-- > start; ) {
+ if (env->prog->insnsi[j].code != (BPF_JMP | BPF_EXIT))
+ continue;
+ env->insn_aux_data[j].seen = env->pass_cnt;
+ found = true;
+ break;
+ }
+ if (!found) {
+ verbose(env, "subprog %u can be unwound through but has no exit\n", i);
+ return -EINVAL;
+ }
+ }
+ return 0;
+}
+
int bpf_opt_remove_dead_code(struct bpf_verifier_env *env)
{
struct bpf_insn_aux_data *aux_data = env->insn_aux_data;
@@ -722,6 +749,9 @@ int bpf_opt_remove_dead_code(struct bpf_verifier_env *env)
int i, err;
keep_funcs_with_addr_taken(env);
+ err = keep_subprog_exits(env);
+ if (err)
+ return err;
for (i = 0; i < insn_cnt; i++) {
int j;
@@ -1262,6 +1292,40 @@ static int resolve_func_ptrs(struct bpf_verifier_env *env, struct bpf_prog *prog
return 0;
}
+static int exc_info_for_subprog(struct bpf_verifier_env *env, struct bpf_prog *sub,
+ u32 start, u32 end)
+{
+ struct bpf_cleanup_info *recs;
+ u32 i, cnt = 0;
+
+ if (!env->cleanup_info_cnt)
+ return 0;
+
+ for (i = start; i < end; i++) {
+ if (env->insn_aux_data[i].cleanup_pad)
+ cnt++;
+ }
+ if (!cnt)
+ return 0;
+
+ recs = kvmalloc_array(cnt, sizeof(*recs), GFP_KERNEL_ACCOUNT | __GFP_NOWARN);
+ if (!recs)
+ return -ENOMEM;
+
+ for (i = start, cnt = 0; i < end; i++) {
+ u32 pad = env->insn_aux_data[i].cleanup_pad;
+
+ if (!pad)
+ continue;
+ pad--;
+ recs[cnt].begin_off = i - start;
+ recs[cnt].end_off = i - start + 1;
+ recs[cnt].landing_pad_off = pad - start;
+ cnt++;
+ }
+ return bpf_exc_attach_info(sub->aux, recs, cnt);
+}
+
static int jit_subprogs(struct bpf_verifier_env *env)
{
struct bpf_prog *prog = env->prog, **func, *tmp;
@@ -1269,7 +1333,7 @@ static int jit_subprogs(struct bpf_verifier_env *env)
struct bpf_map *map_ptr;
struct bpf_insn *insn;
void *old_bpf_func;
- int err, num_exentries;
+ int err, exc_err, num_exentries;
for (i = 0, insn = prog->insnsi; i < prog->len; i++, insn++) {
if (!bpf_pseudo_func(insn) && !bpf_pseudo_call(insn))
@@ -1399,6 +1463,11 @@ static int jit_subprogs(struct bpf_verifier_env *env)
func[i]->aux->token = prog->aux->token;
if (!i)
func[i]->aux->exception_boundary = env->seen_exception;
+ exc_err = exc_info_for_subprog(env, func[i], subprog_start, subprog_end);
+ if (exc_err) {
+ err = exc_err;
+ goto out_free;
+ }
func[i] = bpf_int_jit_compile(env, func[i]);
if (!func[i]->jited) {
err = -ENOTSUPP;
@@ -1508,6 +1577,9 @@ static int jit_subprogs(struct bpf_verifier_env *env)
prog->aux->bpf_exception_cb = (void *)func[env->exception_callback_subprog]->bpf_func;
prog->aux->exception_boundary = func[0]->aux->exception_boundary;
prog->aux->stack_arg_sp_adjust = func[0]->aux->stack_arg_sp_adjust;
+ prog->aux->exc = func[0]->aux->exc;
+ func[0]->aux->exc = NULL;
+ prog->aux->epilogue_ip = func[0]->aux->epilogue_ip;
bpf_prog_jit_attempt_done(prog);
return 0;
out_free:
@@ -1733,6 +1805,48 @@ static int may_goto_expand(struct bpf_insn *insn_buf, int off, int stack_off,
return cnt + tail_cnt;
}
+/*
+ * Follow each bpf_unwind() call with 'r0 = 0; exit', or with
+ * 'r0 = 0; goto pad' where a record covers the call.
+ */
+int bpf_exc_patch_unwind_calls(struct bpf_verifier_env *env)
+{
+ int insn_cnt = env->prog->len;
+ struct bpf_insn insn_buf[3];
+ struct bpf_prog *new_prog;
+ int i, off, delta = 0;
+
+ if (!bpf_prog_may_unwind(env))
+ return 0;
+
+ for (i = 0; i < insn_cnt; i++) {
+ int call = i + delta, pad;
+ struct bpf_insn *insn = env->prog->insnsi + call;
+
+ if (!bpf_is_unwind_kfunc(insn))
+ continue;
+
+ insn_buf[0] = *insn;
+ insn_buf[1] = BPF_MOV64_IMM(BPF_REG_0, 0);
+ insn_buf[2] = BPF_EXIT_INSN();
+ pad = bpf_exc_pad_of_call(env, call);
+ if (pad >= 0) {
+ /* The goto is at call + 2; a pad after the call moves down by 2. */
+ if (pad > call)
+ pad += 2;
+ off = pad - (call + 3);
+ insn_buf[2] = off == (s16)off ? BPF_JMP_A(off) : BPF_JMP32_A(off);
+ }
+
+ new_prog = bpf_patch_insn_data(env, call, insn_buf, 3);
+ if (!new_prog)
+ return -ENOMEM;
+ delta += 2;
+ env->prog = new_prog;
+ }
+ return 0;
+}
+
/* Do various post-verification rewrites in a single program pass.
* These rewrites simplify JIT and interpreter implementations.
*/
@@ -2125,6 +2239,25 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
goto next_insn;
if (insn->src_reg == BPF_PSEUDO_CALL)
goto next_insn;
+ if (bpf_is_unwind_resume_kfunc(insn)) {
+ /*
+ * A pad's resume is just the frame returning, to
+ * where bpf_unwind() pointed its return address: its
+ * caller's pad or epilogue, or the kernel from the main
+ * program. The verifier checked this exit with r0 a
+ * known zero, so return zero.
+ */
+ insn_buf[0] = BPF_MOV64_IMM(BPF_REG_0, 0);
+ insn_buf[1] = BPF_EXIT_INSN();
+ cnt = 2;
+ new_prog = bpf_patch_insn_data(env, i + delta, insn_buf, cnt);
+ if (!new_prog)
+ return -ENOMEM;
+ delta += cnt - 1;
+ env->prog = prog = new_prog;
+ insn = new_prog->insnsi + i + delta;
+ goto next_insn;
+ }
if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
ret = bpf_fixup_kfunc_call(env, insn, insn_buf, i + delta, &cnt);
if (ret)
diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c
index 585be741c689..668d811d4e4c 100644
--- a/kernel/bpf/verifier.c
+++ b/kernel/bpf/verifier.c
@@ -22928,7 +22928,7 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
if (ret)
goto skip_full_check;
- if (env->cleanup_info_cnt) {
+ if (env->cleanup_info_cnt || bpf_prog_may_unwind(env)) {
ret = bpf_exc_check_prog(env);
if (ret)
goto skip_full_check;
@@ -23005,6 +23005,9 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr, bpfptr_t uattr,
/* program is valid, convert *(u32*)(ctx + off) accesses */
ret = bpf_convert_ctx_accesses(env);
+ if (ret == 0)
+ ret = bpf_exc_patch_unwind_calls(env);
+
if (ret == 0)
ret = bpf_do_misc_fixups(env);
--
2.53.0-Meta
next prev parent reply other threads:[~2026-10-08 7:50 UTC|newest]
Thread overview: 38+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-08 7:49 [PATCH bpf-next v9 00/23] bpf: Run exception cleanup landing pads when bpf_unwind() unwinds Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 01/23] bpf: Pack bpf_insn_aux_data flags into bit fields Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 02/23] bpf: Accept the compiler's exception cleanup table at program load Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 03/23] bpf: Add the bpf_unwind() and bpf_unwind_resume() kfuncs Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 04/23] bpf: Keep a call site's landing pad in insn_aux_data, add lookups Yonghong Song
2026-10-08 8:01 ` sashiko-bot
2026-10-08 15:58 ` Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 05/23] bpf: Mark covered call sites and check a program can take a table Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 06/23] bpf: Make exception landing pads reachable in the CFG Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 07/23] bpf: Verify an unwind through landing pads and epilogues Yonghong Song
2026-10-08 8:57 ` bot+bpf-ci
2026-10-08 16:07 ` Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 08/23] bpf: Refuse a landing pad that does not resume Yonghong Song
2026-10-08 8:57 ` bot+bpf-ci
2026-10-08 16:11 ` Yonghong Song
2026-10-08 7:50 ` [PATCH bpf-next v9 09/23] bpf: Do not use a private stack for a program that can unwind Yonghong Song
2026-10-08 7:50 ` Yonghong Song [this message]
2026-10-08 7:50 ` [PATCH bpf-next v9 11/23] bpf: Dispatch cleanup pads by rewriting return addresses Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 12/23] bpf: Refuse a trampoline that calls a subprog that can unwind Yonghong Song
2026-10-08 8:14 ` sashiko-bot
2026-10-08 16:19 ` Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 13/23] bpf, x86: Dispatch exception cleanup pads at run time Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 14/23] bpf, arm64: " Yonghong Song
2026-10-08 8:39 ` bot+bpf-ci
2026-10-08 16:23 ` Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 15/23] libbpf: Resolve the compiler's _Unwind_Resume to the kernel's kfunc Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 16/23] libbpf: Add cleanup_info to bpf_prog_load_opts Yonghong Song
2026-10-08 8:12 ` sashiko-bot
2026-10-08 16:25 ` Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 17/23] libbpf: Collect .bpf_cleanup records and pass them to the kernel Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 18/23] libbpf: Carry the exception cleanup table through the light skeleton Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 19/23] libbpf: Let the static linker carry .bpf_cleanup relocations Yonghong Song
2026-10-08 8:14 ` sashiko-bot
2026-10-08 16:26 ` Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 20/23] selftests/bpf: Add end-to-end and negative .bpf_cleanup exception tests Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 21/23] selftests/bpf: Add __set_global() and __ret_global() test tags Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 22/23] selftests/bpf: Cover more accepted .bpf_cleanup exception shapes Yonghong Song
2026-10-08 7:51 ` [PATCH bpf-next v9 23/23] selftests/bpf: Load an exception cleanup program from a light skeleton Yonghong Song
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=20261008075050.3000674-1-yonghong.song@linux.dev \
--to=yonghong.song@linux.dev \
--cc=andrii@kernel.org \
--cc=ast@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=daniel@iogearbox.net \
--cc=eddyz87@gmail.com \
--cc=kernel-team@fb.com \
/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