All of lore.kernel.org
 help / color / mirror / Atom feed
From: Yonghong Song <yonghong.song@linux.dev>
To: bot+bpf-ci@kernel.org, bpf@vger.kernel.org
Cc: ast@kernel.org, andrii@kernel.org, daniel@iogearbox.net,
	eddyz87@gmail.com, kernel-team@fb.com, martin.lau@kernel.org,
	mason@kernel.org, ihor.solodrai@linux.dev
Subject: Re: [PATCH bpf-next v2 12/12] selftests/bpf: Add tests for by-value kfunc arguments
Date: Thu, 10 Sep 2026 22:57:29 -0700	[thread overview]
Message-ID: <5b019db0-332f-428a-8cfe-2aa7b362145e@linux.dev> (raw)
In-Reply-To: <08f0a36fb18cbbd2a82a3666f443a96518054f785e8bccc0c18e476f00ec63a6@mail.kernel.org>



On 9/9/26 12:30 AM, bot+bpf-ci@kernel.org wrote:
>> Add kfuncs taking a 16-byte struct and an __int128 by value, with
>> combinations of <= 8 byte arguments and '> 8 && <= 16' byte arguments,
>> and tests that call them. Each checks the value the kfunc returns, so a
>> misplaced argument shows up rather than passing quietly.
>>
>> Between them the cases cover an argument the two conventions place
>> alike, one arm64 moves between registers, one an ABI moves to or from
>> the stack, and one both ABIs pad the stack for. All of them run on both
>> arches; what differs is how many instructions the JIT emits to get
>> there. Two more cover the rejections that hold everywhere, an aggregate
>> holding a pointer and one too large to pass by value.
> The changelog describes two new rejection ('__failure') cases, but only
> one of the two is added by this commit, and a third rejection case that
> IS added is never mentioned.
>
> Looking at the added tests:
>
> 1. 'an aggregate holding a pointer' -> present:
>
> progs/aggregate_arg_kfunc.c adds:
>      SEC("tc") __arch_x86_64 __arch_arm64
>      __failure __msg("R1 type STRUCT is not composed of scalars")
>      int aggregate_arg_kfunc_ptr_member(struct __sk_buff *skb)
>
> 2. 'one too large to pass by value' -> NOT added here:
>
> progs/aggregate_arg_kfunc.c contains exactly one __failure program (the
> ptr_member one above), and the commit declares no kfunc taking a by-value
> aggregate larger than 16 bytes in test_kmods/bpf_testmod_kfunc.h, so such
> a case cannot exist in this commit.
>
> The only test matching that description is aggregate_arg_too_big_fail()
> in progs/aggregate_arg_func.c with:
>      __failure __msg("... has size 24, only 1 to 16 bytes can be passed by value")
>
> which was added by the earlier commit b3f328dbfb8a ("selftests/bpf: Add
> inline-asm tests for by-value arguments") and is untouched here.
>
> 3. This commit adds a rejection case the changelog never mentions:
>
> progs/arena_kfunc.c gains 16 lines adding:
>      /* The struct takes two slots, so the arena pointer is the sixth. */
>      SEC("syscall") __arch_x86_64 __arch_arm64
>      __failure __msg("arena pointer cannot be a stack argument")
>      int arena_arg_stack_after_pair(void *ctx)
>
> together with the new bpf_kfunc_call_test_pair_arena_arg() kfunc and its
> __ksym declaration. arena_kfunc.c is one of the six files in the diffstat
> but is not described anywhere in the message.
>
> Could the message be updated to say that one new rejection case is added
> for an aggregate holding a pointer (with the too-large rejection being
> already covered by aggregate_arg_func.c), and add a sentence for the
> arena stack-argument rejection in arena_kfunc.c?

Yes, I can do this.

>
>> diff --git a/tools/testing/selftests/bpf/progs/aggregate_arg_kfunc.c b/tools/testing/selftests/bpf/progs/aggregate_arg_kfunc.c
>> new file mode 100644
>> index 000000000000..c8a088e2f5e3
>> --- /dev/null
>> +++ b/tools/testing/selftests/bpf/progs/aggregate_arg_kfunc.c
> [ ... ]
>
>> +/*
>> + * One argument further and the hole pushes the last one off x7 and onto the
>> + * arm64 stack, which the JIT does not shift into. The x86-64 ABI packs the
>> + * eightbytes, so its last two are on the stack where BPF put them.
>> + */
> Does the comment accurately reflect what the arm64 JIT does? Looking at
> bpf_jit_place_args() with arm64_arg_abi:
>
> For bpf_kfunc_call_test_i128_arg_ovf(u64 a, __int128 v, u64 b, u64 c, u64 d,
> u64 e, u64 f), the arm64 calling convention computes:
>    slot0(a)->pos0, slot1/2(v)->pos2/3, slot3(b)->4, slot4(c)->5,
>    slot5(d)->6, slot6(e)->7, slot7(f)->pos8
>
> Position 8 is the first arm64 stack slot (a64_arg_on_stack(8) is true),
> so bpf_jit_plan_arg_moves() emits the move {dst=8, src=7}.
>
> arch/arm64/net/bpf_jit_comp.c:emit_kfunc_arg_moves() handles this with:
>
>      if (a64_arg_on_stack(dst))
>              emit(A64_STR64I(reg, A64_SP, a64_arg_stack_off(dst)), ctx);
>
> The space is reserved by kfunc_abi_slots() returning 9 for this kfunc,
> giving out_stack_arg_cnt = 4, nr_on_stack = 1, and ctx->stack_arg_size
> becomes 16 bytes.
>
> This test is annotated '__success __retval(0)', which depends on the JIT
> correctly placing argument f into the arm64 stack. Does the comment need
> updating to reflect that the JIT does shift into the arm64 stack?

The prog should already mentioned this. Not all of them but a couple of
cases to illustrate.

>
>> diff --git a/tools/testing/selftests/bpf/progs/stack_arg_fail.c b/tools/testing/selftests/bpf/progs/stack_arg_fail.c
>> index 1cd3eee07802..80b8cbf15cdb 100644
>> --- a/tools/testing/selftests/bpf/progs/stack_arg_fail.c
>> +++ b/tools/testing/selftests/bpf/progs/stack_arg_fail.c
> [ ... ]
>
>> @@ -3,20 +3,10 @@
>>
>>   #include <vmlinux.h>
>>   #include <bpf/bpf_helpers.h>
>> -#include "../test_kmods/bpf_testmod_kfunc.h"
>>   #include "bpf_misc.h"
>>
>>   #if defined(__BPF_FEATURE_STACK_ARGUMENT)
>>
>> -SEC("socket")
>> -__failure __msg("Unrecognized *(R11-8) type STRUCT")
>> -int test_stack_arg_big(struct __sk_buff *ctx)
>> -{
>> -	struct prog_test_big_arg s = {1, 2};
>> -
>> -	return bpf_kfunc_call_stack_arg_big(1, 2, 3, 4, 5, s);
>> -}
>> -
> The changelog says "the test is removed and the same call is covered by
> the cases above." That holds only on x86_64 and arm64.
>
> The replacement, aggregate_arg_kfunc_straddle() in
> progs/aggregate_arg_kfunc.c:97-107, makes the byte-identical call
> bpf_kfunc_call_stack_arg_big(1, 2, 3, 4, 5, s) and correctly checks the
> return value, but it is tagged:
>
>    SEC("tc")
>    __arch_x86_64 __arch_arm64
>    __load_if_JITed()
>    __success __retval(0)
>
> test_loader.c:1339 skips a test whose arch_mask excludes the host arch.
> The deleted test was gated only on __BPF_FEATURE_STACK_ARGUMENT and ran
> everywhere.
>
> On riscv64, s390x and loongarch this call is no longer exercised at all.
> Only x86 and arm64 define bpf_jit_arg_abi(); elsewhere
> gen_kfunc_arg_proto() takes the '!abi && nslots > 1' branch at
> verifier.c:12428 and rejects the argument with:
>
>    "Function %s arg#%d type %s cannot be passed at argument slot %d on this architecture"
>
> That message is new in this series and has no selftest coverage.
>
> So on the non-ABI architectures the series swapped one rejection message
> for another and this commit removed the only test that exercised the call
> there. Should a __failure __msg("cannot be passed at argument slot") case
> be added to restore coverage on those architectures?

I didn't test on riscv64, s390x and loongarch. That is why I skipped them.

>
>> diff --git a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
>> index 1ae88a12d0c4..1d71ba0bc6ad 100644
>> --- a/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
>> +++ b/tools/testing/selftests/bpf/test_kmods/bpf_testmod.c
> [ ... ]
>
>> +__bpf_kfunc u64 bpf_kfunc_call_test_pair_arg(u64 a, struct prog_test_pair_arg s, u64 b)
>> +{
>> +	return a + s.lo + s.hi + b;
>> +}
>> +
>> +__bpf_kfunc u64 bpf_kfunc_call_test_i128_arg(u64 a, u64 b, __int128 v)
>> +{
>> +	return a + b + (u64)((unsigned __int128)v >> 64) + (u64)v;
>> +}
>> +
>> +__bpf_kfunc u64 bpf_kfunc_call_test_i128_arg_odd(u64 a, __int128 v, u64 b)
>> +{
>> +	return a + b + (u64)((unsigned __int128)v >> 64) + (u64)v;
>> +}
> [ ... ]
>
>> +__bpf_kfunc u64 bpf_kfunc_call_test_i128_arg_shift(u64 a, __int128 v, u64 b, u64 c, u64 d)
>> +{
>> +	return a + b + c + d + (u64)((unsigned __int128)v >> 64) + (u64)v;
>> +}
>> +
>> +__bpf_kfunc u64 bpf_kfunc_call_test_i128_arg_ovf(u64 a, __int128 v, u64 b, u64 c, u64 d, u64 e, u64 f)
>> +{
>> +	return a + b + c + d + e + f + (u64)((unsigned __int128)v >> 64) + (u64)v;
>> +}
> [ ... ]
>
>> +__bpf_kfunc u64 bpf_kfunc_call_test_i128_arg_pad(u64 a, u64 b, u64 c, u64 d, u64 e, u64 f, u64 g, __int128 v)
>> +{
>> +	return a + b + c + d + e + f + g + (u64)((unsigned __int128)v >> 64) + (u64)v;
>> +}
> Three of the new kfuncs place the __int128 after a single-register
> scalar: bpf_kfunc_call_test_i128_arg_odd(), i128_arg_shift(), and
> i128_arg_ovf(), all of the shape 'u64 a, __int128 v, ...'.
>
> This is exactly the shape a comment already in this same file warns
> against. bpf_testmod.c:174-186 says, above bpf_testmod_test_int128_arg():
>
>    /*
>     * The __int128 'a' is the first argument on purpose. On arm64 a 16-byte
>     * argument must start in an even-numbered register pair, so placing it
>     * after a single-register scalar would leave a padding register (x1)
>     * unused. pahole maps parameters to registers positionally and would then
>     * see the following argument in an "unexpected" register and skip BTF
>     * encoding of the whole function, making it unattachable. [...]
>     */
>
> On arm64 AAPCS64 rounds NGRN up to an even number for a 16-byte-aligned
> type, so for (u64 a, __int128 v, u64 b) the actual placement is a=x0,
> x1 padding, v=x2:x3, b=x4, while a positional mapping expects v=x1:x2
> and b=x3.
>
> Per the in-file comment that makes pahole drop the BTF FUNC record for
> the whole function on arm64. For a kfunc that is worse than for an fentry
> target: the name is registered with BTF_ID_FLAGS(), so resolve_btfids
> would leave the ID at 0 and emit:
>
>    'WARN: resolve_btfids: unresolved symbol bpf_kfunc_call_test_i128_arg_odd'
>
> which is fatal when CONFIG_WERROR selects --fatal_warnings. Even when
> only a warning, libbpf cannot resolve the ksym against the module BTF,
> so aggregate_arg_kfunc_int128_odd, aggregate_arg_kfunc_int128_shift and
> aggregate_arg_kfunc_int128_ovf fail to load on arm64 instead of testing
> the JIT.
>
> bpf_kfunc_call_test_i128_arg_pad() has the same hazard in the milder
> stack-vs-register form (a..g fill x0..x6, then v is pushed to the stack
> where x7 would be expected positionally).
>
> The pre-existing bpf_kfunc_call_test_i128() and
> bpf_testmod_test_int128_arg() both deliberately keep the __int128 in the
> first position, and only bpf_kfunc_call_test_i128_arg() (u64 a, u64 b,
> __int128 v) among the new ones happens to land on an even register with
> no padding.
>
> Is the placement worth confirming against the pahole version used for CI
> before this lands, given it's the one thing in the change that the
> in-tree documentation says should not work on arm64?

this pahole patch should fix the issue:
   https://lore.kernel.org/bpf/20260911040955.339939-1-yonghong.song@linux.dev/

>
>
> ---
> AI reviewed your patch. Please fix the bug or email reply why it's not a bug.
> See: https://github.com/kernel-patches/vmtest/blob/master/ci/claude/README.md
>
> CI run summary: https://github.com/kernel-patches/bpf/actions/runs/34320399441


      reply	other threads:[~2026-09-11  5:57 UTC|newest]

Thread overview: 31+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-09-09  6:25 [PATCH bpf-next v2 00/12] bpf: Support by-value struct and __int128 arguments Yonghong Song
2026-09-09  6:25 ` [PATCH bpf-next v2 01/12] selftests/bpf: Add a test for an __int128 by-value argument Yonghong Song
2026-09-09  7:13   ` bot+bpf-ci
2026-09-11  4:25     ` Yonghong Song
2026-09-09  6:25 ` [PATCH bpf-next v2 02/12] bpf: Index global function arguments by argument slot Yonghong Song
2026-09-09  7:13   ` bot+bpf-ci
2026-09-11  4:27     ` Yonghong Song
2026-09-09  6:25 ` [PATCH bpf-next v2 03/12] bpf: Support by-value struct arguments up to 16 bytes Yonghong Song
2026-09-09  7:13   ` bot+bpf-ci
2026-09-11  4:29     ` Yonghong Song
2026-09-09  6:25 ` [PATCH bpf-next v2 04/12] bpf: Support __int128 as a by-value function argument Yonghong Song
2026-09-09  6:25 ` [PATCH bpf-next v2 05/12] bpf: Rename bpf_call_summary::num_params to arg_slot_cnt Yonghong Song
2026-09-09  6:25 ` [PATCH bpf-next v2 06/12] bpf: Recognize by-value struct and __int128 kfunc arguments Yonghong Song
2026-09-09  6:46   ` sashiko-bot
2026-09-11  4:31     ` Yonghong Song
2026-09-09  6:25 ` [PATCH bpf-next v2 07/12] bpf: Prepare kfunc arguments for the JIT from an ABI description Yonghong Song
2026-09-09  6:46   ` sashiko-bot
2026-09-11  5:05     ` Yonghong Song
2026-09-09  6:26 ` [PATCH bpf-next v2 08/12] bpf, x86: Move kfunc arguments into the x86-64 calling convention Yonghong Song
2026-09-09  7:29   ` bot+bpf-ci
2026-09-11  5:32     ` Yonghong Song
2026-09-09  6:26 ` [PATCH bpf-next v2 09/12] bpf, arm64: Move kfunc arguments into the arm64 " Yonghong Song
2026-09-09  7:30   ` bot+bpf-ci
2026-09-11  5:34     ` Yonghong Song
2026-09-09  6:26 ` [PATCH bpf-next v2 10/12] selftests/bpf: Add C tests for by-value arguments up to 16 bytes Yonghong Song
2026-09-09  6:26 ` [PATCH bpf-next v2 11/12] selftests/bpf: Add inline-asm tests for by-value arguments Yonghong Song
2026-09-09  7:30   ` bot+bpf-ci
2026-09-11  5:37     ` Yonghong Song
2026-09-09  6:26 ` [PATCH bpf-next v2 12/12] selftests/bpf: Add tests for by-value kfunc arguments Yonghong Song
2026-09-09  7:30   ` bot+bpf-ci
2026-09-11  5:57     ` Yonghong Song [this message]

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=5b019db0-332f-428a-8cfe-2aa7b362145e@linux.dev \
    --to=yonghong.song@linux.dev \
    --cc=andrii@kernel.org \
    --cc=ast@kernel.org \
    --cc=bot+bpf-ci@kernel.org \
    --cc=bpf@vger.kernel.org \
    --cc=daniel@iogearbox.net \
    --cc=eddyz87@gmail.com \
    --cc=ihor.solodrai@linux.dev \
    --cc=kernel-team@fb.com \
    --cc=martin.lau@kernel.org \
    --cc=mason@kernel.org \
    /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.