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 v4 10/13] selftests/bpf: Add C tests for 16-byte returns in R0:R2
Date: Mon, 10 Aug 2026 17:10:02 -0700 [thread overview]
Message-ID: <20260811001002.2383554-1-yonghong.song@linux.dev> (raw)
In-Reply-To: <20260811000911.2378679-1-yonghong.song@linux.dev>
Add selftests that exercise a 16-byte return value passed in the R0:R2
register pair, written in C so that they depend on the compiler lowering
the register-pair return. Covered are an __int128 return, a 16-byte struct
return (from a static and from a global subprogram) and a 16-byte union
return, plus __int128 and 16-byte struct returns from a kfunc, for which
bpf_kfunc_call_test_i128() and bpf_kfunc_call_test_ret_pair() are added to
bpf_testmod.
The R0:R2 convention is only emitted by LLVM 23 and newer. Each object
records in a read-only has_reg_pair_ret flag which compiler built it; where
that is false the programs are stubs and subtests report a skip rather than
a pass.
The two kfunc subtests further depend on the JIT: bpf_add_kfunc_call()
rejects a kfunc returning more than 8 bytes with -EOPNOTSUPP where
bpf_jit_supports_kfunc_ret_reg_pair() is false. Those calls therefore live
in an object of their own, and that load failing with -EOPNOTSUPP is what
turns the two subtests into skips, so no list of the JITs implementing the
pair needs to be kept here. A register-pair return from a BPF subprogram
needs no JIT support, so the remaining subtests run everywhere.
Both kfuncs are restricted to x86_64 and arm64, and the two subtests report
a skip elsewhere. pahole only BTF-encodes a function whose declared
arguments sit in the ABI's argument registers, and an architecture that
returns a value larger than 8 bytes through a hidden pointer (sret) shifts
every one of them by a register. s390x is such an architecture: there
pahole drops the function, resolve_btfids leaves the kfunc ID at 0, and
register_btf_kfunc_id_set() then fails at module init, so bpf_testmod does
not load at all and every test that needs it fails. This is not a property
of the compiler -- __SIZEOF_INT128__ is defined by gcc on s390x, and a
by-value struct return has nothing to do with __int128 in the first place --
so the guard is on the architecture. prog_tests/tracing_failure.c already
restricts a __int128 return the same way.
Signed-off-by: Yonghong Song <yonghong.song@linux.dev>
---
.../selftests/bpf/prog_tests/aggregate_ret.c | 148 ++++++++++++++++++
.../bpf/progs/aggregate_ret_int128_c.c | 48 ++++++
.../bpf/progs/aggregate_ret_kfunc_c.c | 66 ++++++++
.../bpf/progs/aggregate_ret_struct_c.c | 82 ++++++++++
.../bpf/progs/aggregate_ret_union_c.c | 58 +++++++
.../selftests/bpf/test_kmods/bpf_testmod.c | 32 ++++
.../bpf/test_kmods/bpf_testmod_kfunc.h | 13 ++
7 files changed, 447 insertions(+)
create mode 100644 tools/testing/selftests/bpf/prog_tests/aggregate_ret.c
create mode 100644 tools/testing/selftests/bpf/progs/aggregate_ret_int128_c.c
create mode 100644 tools/testing/selftests/bpf/progs/aggregate_ret_kfunc_c.c
create mode 100644 tools/testing/selftests/bpf/progs/aggregate_ret_struct_c.c
create mode 100644 tools/testing/selftests/bpf/progs/aggregate_ret_union_c.c
diff --git a/tools/testing/selftests/bpf/prog_tests/aggregate_ret.c b/tools/testing/selftests/bpf/prog_tests/aggregate_ret.c
new file mode 100644
index 000000000000..bd18bad17472
--- /dev/null
+++ b/tools/testing/selftests/bpf/prog_tests/aggregate_ret.c
@@ -0,0 +1,148 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <test_progs.h>
+#include "aggregate_ret_int128_c.skel.h"
+#include "aggregate_ret_struct_c.skel.h"
+#include "aggregate_ret_union_c.skel.h"
+#include "aggregate_ret_kfunc_c.skel.h"
+
+/*
+ * The bpf_testmod kfuncs returning more than 8 bytes are only built on x86_64
+ * and arm64 (see bpf_testmod.c); everywhere else the tests calling them are
+ * skipped.
+ */
+static bool has_ret_pair_kfuncs(void)
+{
+#if defined(__x86_64__) || defined(__aarch64__)
+ return true;
+#else
+ return false;
+#endif
+}
+
+static void run_prog(struct bpf_program *prog)
+{
+ char buf[64] = {};
+ int err, prog_fd;
+ LIBBPF_OPTS(bpf_test_run_opts, topts,
+ .data_in = buf,
+ .data_size_in = sizeof(buf),
+ .repeat = 1,
+ );
+
+ prog_fd = bpf_program__fd(prog);
+ err = bpf_prog_test_run_opts(prog_fd, &topts);
+ if (!ASSERT_OK(err, "test_run"))
+ return;
+
+ ASSERT_EQ(topts.retval, 0, "aggregate_ret_result");
+}
+
+/*
+ * Run @prog as subtest @name. Where the register-pair return is unsupported
+ * the subtest reports a skip instead, so that the list of subtests does not
+ * depend on the compiler or on the architecture; @prog is unused then and may
+ * be NULL, for a caller that could not even open its object.
+ */
+static void run_subtest(const char *name, struct bpf_program *prog, bool supported)
+{
+ if (!test__start_subtest(name))
+ return;
+
+ if (!supported) {
+ test__skip();
+ return;
+ }
+
+ run_prog(prog);
+}
+
+static void test_int128_c(void)
+{
+ struct aggregate_ret_int128_c *skel;
+
+ skel = aggregate_ret_int128_c__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_int128_c_open_load"))
+ return;
+
+ run_subtest("int128_c", skel->progs.aggregate_ret_int128_c_test,
+ skel->rodata->has_reg_pair_ret);
+
+ aggregate_ret_int128_c__destroy(skel);
+}
+
+static void test_struct_c(void)
+{
+ struct aggregate_ret_struct_c *skel;
+
+ skel = aggregate_ret_struct_c__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_struct_c_open_load"))
+ return;
+
+ run_subtest("struct_c", skel->progs.aggregate_ret_struct_c_test,
+ skel->rodata->has_reg_pair_ret);
+
+ run_subtest("global_struct_c", skel->progs.aggregate_ret_global_struct_c_test,
+ skel->rodata->has_reg_pair_ret);
+
+ aggregate_ret_struct_c__destroy(skel);
+}
+
+static void test_union_c(void)
+{
+ struct aggregate_ret_union_c *skel;
+
+ skel = aggregate_ret_union_c__open_and_load();
+ if (!ASSERT_OK_PTR(skel, "skel_union_c_open_load"))
+ return;
+
+ run_subtest("union_c", skel->progs.aggregate_ret_union_c_test,
+ skel->rodata->has_reg_pair_ret);
+
+ aggregate_ret_union_c__destroy(skel);
+}
+
+static void test_kfunc_c(void)
+{
+ struct aggregate_ret_kfunc_c *skel;
+ bool supported;
+ int err;
+
+ skel = aggregate_ret_kfunc_c__open();
+ if (!ASSERT_OK_PTR(skel, "skel_kfunc_c_open"))
+ return;
+
+ supported = skel->rodata->has_reg_pair_ret && has_ret_pair_kfuncs();
+
+ if (supported) {
+ /*
+ * Where the JIT cannot hand the second half of a >8-byte kfunc
+ * return back in R0:R2, bpf_add_kfunc_call() rejects the call
+ * with -EOPNOTSUPP. Asking the kernel keeps this test free of a
+ * list of the JITs that can, which would have to be updated as
+ * the rest of them learn.
+ */
+ err = aggregate_ret_kfunc_c__load(skel);
+ if (err == -EOPNOTSUPP)
+ supported = false;
+ else if (!ASSERT_OK(err, "skel_kfunc_c_load"))
+ goto out;
+ }
+
+ run_subtest("kfunc_int128_c", skel->progs.aggregate_ret_kfunc_int128_c_test,
+ supported);
+
+ run_subtest("kfunc_struct_c", skel->progs.aggregate_ret_kfunc_struct_c_test,
+ supported);
+
+out:
+ aggregate_ret_kfunc_c__destroy(skel);
+}
+
+void test_aggregate_ret(void)
+{
+ test_int128_c();
+ test_struct_c();
+ test_union_c();
+ test_kfunc_c();
+}
diff --git a/tools/testing/selftests/bpf/progs/aggregate_ret_int128_c.c b/tools/testing/selftests/bpf/progs/aggregate_ret_int128_c.c
new file mode 100644
index 000000000000..f2e09c8be0be
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/aggregate_ret_int128_c.c
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+
+#if defined(__clang_major__) && __clang_major__ >= 23
+
+const volatile bool has_reg_pair_ret = true;
+
+#define MIX_A 0xdeadbeefcafef00dULL
+#define MIX_B 0x0123456789abcdefULL
+
+typedef unsigned __int128 u128;
+
+static __noinline u128 make_i128(__u64 a, __u64 b)
+{
+ return ((u128)(a + b) << 64) | (a - b);
+}
+
+SEC("tc")
+int aggregate_ret_int128_c_test(struct __sk_buff *skb)
+{
+ __u64 a = skb->len ^ MIX_A;
+ __u64 b = skb->len ^ MIX_B;
+ u128 v;
+
+ v = make_i128(a, b);
+ if ((__u64)(v >> 64) != a + b)
+ return 1;
+ if ((__u64)v != a - b)
+ return 2;
+
+ return 0;
+}
+
+#else
+
+const volatile bool has_reg_pair_ret = false;
+
+SEC("tc")
+int aggregate_ret_int128_c_test(struct __sk_buff *skb)
+{
+ return 0;
+}
+
+#endif
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/aggregate_ret_kfunc_c.c b/tools/testing/selftests/bpf/progs/aggregate_ret_kfunc_c.c
new file mode 100644
index 000000000000..fd000620f314
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/aggregate_ret_kfunc_c.c
@@ -0,0 +1,66 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+#include "../test_kmods/bpf_testmod_kfunc.h"
+
+#if defined(__clang_major__) && __clang_major__ >= 23
+
+const volatile bool has_reg_pair_ret = true;
+
+#define MIX_A 0xdeadbeefcafef00dULL
+#define MIX_B 0x0123456789abcdefULL
+
+typedef unsigned __int128 u128;
+
+SEC("tc")
+int aggregate_ret_kfunc_int128_c_test(struct __sk_buff *skb)
+{
+ __u64 a = skb->len ^ MIX_A;
+ __u64 b = skb->len ^ MIX_B;
+ u128 v;
+
+ v = bpf_kfunc_call_test_i128(a, b);
+ if ((__u64)(v >> 64) != a + b)
+ return 1;
+ if ((__u64)v != a - b)
+ return 2;
+
+ return 0;
+}
+
+SEC("tc")
+int aggregate_ret_kfunc_struct_c_test(struct __sk_buff *skb)
+{
+ __u64 a = skb->len ^ MIX_A;
+ __u64 b = skb->len ^ MIX_B;
+ struct prog_test_ret_pair p;
+
+ p = bpf_kfunc_call_test_ret_pair(a, b);
+ if (p.hi != a + b)
+ return 1;
+ if (p.lo != a - b)
+ return 2;
+
+ return 0;
+}
+
+#else
+
+const volatile bool has_reg_pair_ret = false;
+
+SEC("tc")
+int aggregate_ret_kfunc_int128_c_test(struct __sk_buff *skb)
+{
+ return 0;
+}
+
+SEC("tc")
+int aggregate_ret_kfunc_struct_c_test(struct __sk_buff *skb)
+{
+ return 0;
+}
+
+#endif
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/aggregate_ret_struct_c.c b/tools/testing/selftests/bpf/progs/aggregate_ret_struct_c.c
new file mode 100644
index 000000000000..5296e41da3f0
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/aggregate_ret_struct_c.c
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+
+#if defined(__clang_major__) && __clang_major__ >= 23
+
+const volatile bool has_reg_pair_ret = true;
+
+#define MIX_A 0xdeadbeefcafef00dULL
+#define MIX_B 0x0123456789abcdefULL
+
+struct pair {
+ __u64 hi; /* R0 */
+ __u64 lo; /* R2 */
+};
+
+static __noinline struct pair make_pair(__u64 a, __u64 b)
+{
+ struct pair p = { .hi = a + b, .lo = a - b };
+
+ return p;
+}
+
+SEC("tc")
+int aggregate_ret_struct_c_test(struct __sk_buff *skb)
+{
+ __u64 a = skb->len ^ MIX_A;
+ __u64 b = skb->len ^ MIX_B;
+ struct pair p;
+
+ p = make_pair(a, b);
+ if (p.hi != a + b)
+ return 1;
+ if (p.lo != a - b)
+ return 2;
+
+ return 0;
+}
+
+__noinline struct pair make_pair_global(__u64 a, __u64 b)
+{
+ struct pair p = { .hi = a + b, .lo = a - b };
+
+ return p;
+}
+
+SEC("tc")
+int aggregate_ret_global_struct_c_test(struct __sk_buff *skb)
+{
+ __u64 a = skb->len ^ MIX_A;
+ __u64 b = skb->len ^ MIX_B;
+ struct pair p;
+
+ p = make_pair_global(a, b);
+ if (p.hi != a + b)
+ return 1;
+ if (p.lo != a - b)
+ return 2;
+
+ return 0;
+}
+
+#else
+
+const volatile bool has_reg_pair_ret = false;
+
+SEC("tc")
+int aggregate_ret_struct_c_test(struct __sk_buff *skb)
+{
+ return 0;
+}
+
+SEC("tc")
+int aggregate_ret_global_struct_c_test(struct __sk_buff *skb)
+{
+ return 0;
+}
+
+#endif
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/progs/aggregate_ret_union_c.c b/tools/testing/selftests/bpf/progs/aggregate_ret_union_c.c
new file mode 100644
index 000000000000..5547fa6cbd49
--- /dev/null
+++ b/tools/testing/selftests/bpf/progs/aggregate_ret_union_c.c
@@ -0,0 +1,58 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (c) 2026 Meta Platforms, Inc. and affiliates. */
+#include <vmlinux.h>
+#include <bpf/bpf_helpers.h>
+
+#if defined(__clang_major__) && __clang_major__ >= 23
+
+const volatile bool has_reg_pair_ret = true;
+
+#define MIX_A 0xdeadbeefcafef00dULL
+#define MIX_B 0x0123456789abcdefULL
+
+union pair {
+ __u64 halves[2];
+ struct {
+ __u64 lo; /* R0 */
+ __u64 hi; /* R2 */
+ } parts;
+};
+
+static __noinline union pair make_pair(__u64 a, __u64 b)
+{
+ union pair p;
+
+ p.halves[0] = a + b;
+ p.halves[1] = a - b;
+ return p;
+}
+
+SEC("tc")
+int aggregate_ret_union_c_test(struct __sk_buff *skb)
+{
+ __u64 a = skb->len ^ MIX_A;
+ __u64 b = skb->len ^ MIX_B;
+ union pair p;
+
+ p = make_pair(a, b);
+ if (p.parts.lo != a + b)
+ return 1;
+ if (p.parts.hi != a - b)
+ return 2;
+
+ return 0;
+}
+
+#else
+
+const volatile bool has_reg_pair_ret = false;
+
+SEC("tc")
+int aggregate_ret_union_c_test(struct __sk_buff *skb)
+{
+ return 0;
+}
+
+#endif
+
+char _license[] SEC("license") = "GPL";
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
index a6133f7521f3..242d3e2913dc 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
@@ -939,6 +939,34 @@ __bpf_kfunc int bpf_kfunc_call_test5(u8 a, u16 b, u32 c)
return 0;
}
+/*
+ * A kfunc is only usable where the ABI hands its return value back in
+ * registers. s390x, for example, returns a by-value struct or union through a
+ * hidden pointer argument (sret) whatever its size. That pointer shifts every
+ * declared argument by one register, and pahole, which maps parameters to
+ * registers positionally, then skips the function with "unexpected register
+ * usage for parameter". resolve_btfids reports "no BTF func for kfunc" and
+ * leaves the ID at 0, which makes register_btf_kfunc_id_set() fail at module
+ * init, so the module does not load at all.
+ *
+ * Restrict these kfuncs to the architectures where the return value comes back
+ * in registers. A kfunc taking no argument has nothing for the sret pointer to
+ * displace and needs no guard, whatever it returns.
+ */
+#if defined(__x86_64__) || defined(__aarch64__)
+__bpf_kfunc __int128 bpf_kfunc_call_test_i128(u64 a, u64 b)
+{
+ return (__int128)(((unsigned __int128)(a + b) << 64) | (a - b));
+}
+
+__bpf_kfunc struct prog_test_ret_pair bpf_kfunc_call_test_ret_pair(u64 a, u64 b)
+{
+ struct prog_test_ret_pair r = { .hi = a + b, .lo = a - b };
+
+ return r;
+}
+#endif /* __x86_64__ || __aarch64__ */
+
__bpf_kfunc u64 bpf_kfunc_call_stack_arg(u64 a, u64 b, u64 c, u64 d,
u64 e, u64 f, u64 g, u64 h,
u64 i, u64 j)
@@ -1472,6 +1500,10 @@ BTF_ID_FLAGS(func, bpf_kfunc_call_test2)
BTF_ID_FLAGS(func, bpf_kfunc_call_test3)
BTF_ID_FLAGS(func, bpf_kfunc_call_test4)
BTF_ID_FLAGS(func, bpf_kfunc_call_test5)
+#if defined(__x86_64__) || defined(__aarch64__)
+BTF_ID_FLAGS(func, bpf_kfunc_call_test_i128)
+BTF_ID_FLAGS(func, bpf_kfunc_call_test_ret_pair)
+#endif
BTF_ID_FLAGS(func, bpf_kfunc_call_stack_arg)
BTF_ID_FLAGS(func, bpf_kfunc_call_stack_arg_ptr)
BTF_ID_FLAGS(func, bpf_kfunc_call_stack_arg_mix)
diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
index c4383acb53c1..b190917f36b8 100644
--- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
+++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod_kfunc.h
@@ -55,6 +55,15 @@ struct prog_test_big_arg {
__u64 b;
};
+/*
+ * A 16-byte struct returned by value from a kfunc: .hi comes back in R0 and
+ * .lo in R2.
+ */
+struct prog_test_ret_pair {
+ __u64 hi;
+ __u64 lo;
+};
+
struct prog_test_fail1 {
void *p;
int x;
@@ -130,6 +139,10 @@ int bpf_kfunc_call_test2(struct sock *sk, __u32 a, __u32 b) __ksym;
struct sock *bpf_kfunc_call_test3(struct sock *sk) __ksym;
long bpf_kfunc_call_test4(signed char a, short b, int c, long d) __ksym;
int bpf_kfunc_call_test5(__u8 a, __u16 b, __u32 c) __ksym;
+#ifdef __SIZEOF_INT128__
+__int128 bpf_kfunc_call_test_i128(__u64 a, __u64 b) __ksym;
+#endif
+struct prog_test_ret_pair bpf_kfunc_call_test_ret_pair(__u64 a, __u64 b) __ksym;
__u64 bpf_kfunc_call_stack_arg(__u64 a, __u64 b, __u64 c, __u64 d,
__u64 e, __u64 f, __u64 g, __u64 h,
__u64 i, __u64 j) __ksym;
--
2.53.0-Meta
next prev parent reply other threads:[~2026-08-11 0:10 UTC|newest]
Thread overview: 23+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-11 0:09 [PATCH bpf-next v4 00/13] bpf: Support aggregate return values up to 16 bytes Yonghong Song
2026-08-11 0:09 ` [PATCH bpf-next v4 01/13] bpf: Factor check_global_ret_scalar_reg() out of the global return check Yonghong Song
2026-08-11 0:09 ` [PATCH bpf-next v4 02/13] bpf: Add helpers to describe the R0:R2 return register pair Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-11 0:09 ` [PATCH bpf-next v4 03/13] bpf: Wire up JIT support for 16-byte kfunc returns Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-11 0:09 ` [PATCH bpf-next v4 04/13] bpf: Track R2 of register-pair returns in precision backtracking Yonghong Song
2026-08-11 0:09 ` [PATCH bpf-next v4 05/13] bpf: Account R2 of register-pair returns in live register analysis Yonghong Song
2026-08-11 1:09 ` bot+bpf-ci
2026-08-11 0:09 ` [PATCH bpf-next v4 06/13] bpf: Reject callbacks returning more than 8 bytes Yonghong Song
2026-08-11 0:09 ` [PATCH bpf-next v4 07/13] bpf: Add verifier support for 16-byte returns in R0:R2 Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-11 0:09 ` [PATCH bpf-next v4 08/13] bpf: Reject register-pair returns when the subprog BTF is unreliable Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-11 0:09 ` [PATCH bpf-next v4 09/13] bpf: Enable aggregate return types up to 16 bytes Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-11 0:10 ` Yonghong Song [this message]
2026-08-11 1:24 ` [PATCH bpf-next v4 10/13] selftests/bpf: Add C tests for 16-byte returns in R0:R2 bot+bpf-ci
2026-08-11 0:10 ` [PATCH bpf-next v4 11/13] selftests/bpf: Add inline-asm and subprog tests for R0:R2 returns Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-11 0:10 ` [PATCH bpf-next v4 12/13] selftests/bpf: Add tests for callbacks returning more than 8 bytes Yonghong Song
2026-08-11 1:24 ` bot+bpf-ci
2026-08-11 0:10 ` [PATCH bpf-next v4 13/13] Documentation/bpf: Document up to 16-byte kfunc return values in R0:R2 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=20260811001002.2383554-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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.