[PATCH bpf-next v2 15/22] bpf: Insert the may_goto counter setup through the patch list

From: Qiliang Yuan

Date: Fri Oct 30 2026 - 08:09:54 EST


bpf_do_misc_fixups() sets up the counter of may_goto in front of each
subprog that needs one.

It patches the program for each of these subprogs, and then walks all
jumps again with adjust_jmp_off() to move the ones to the first
instruction of the subprog past the setup.

Insert the setup with bpf_patch_list_insert(), which leaves the jumps
to the instruction it inserts in front of on that instruction, and
commit once. adjust_jmp_off() has no users left, remove it.

Signed-off-by: Qiliang Yuan <odys.yuan@xxxxxxxxx>
---
kernel/bpf/fixups.c | 73 ++++++++---------------------------------------------
1 file changed, 10 insertions(+), 63 deletions(-)

diff --git a/kernel/bpf/fixups.c b/kernel/bpf/fixups.c
index 08c89f2baffb6..f55ac904b4e78 100644
--- a/kernel/bpf/fixups.c
+++ b/kernel/bpf/fixups.c
@@ -723,44 +723,6 @@ static int bpf_adj_moved_insn(struct bpf_insn *insn, u32 delta)
return 0;
}

-/*
- * For all jmp insns in a given 'prog' that point to 'tgt_idx' insn adjust the
- * jump offset by 'delta'.
- */
-static int adjust_jmp_off(struct bpf_prog *prog, u32 tgt_idx, u32 delta)
-{
- struct bpf_insn *insn = prog->insnsi;
- u32 insn_cnt = prog->len, i;
- s32 imm;
- s16 off;
-
- for (i = 0; i < insn_cnt; i++, insn++) {
- u8 code = insn->code;
-
- if (tgt_idx <= i && i < tgt_idx + delta)
- continue;
-
- if ((BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32) ||
- BPF_OP(code) == BPF_CALL || BPF_OP(code) == BPF_EXIT)
- continue;
-
- if (insn->code == (BPF_JMP32 | BPF_JA)) {
- if (i + 1 + insn->imm != tgt_idx)
- continue;
- if (check_add_overflow(insn->imm, delta, &imm))
- return -ERANGE;
- insn->imm = imm;
- } else {
- if (i + 1 + insn->off != tgt_idx)
- continue;
- if (check_add_overflow(insn->off, delta, &off))
- return -ERANGE;
- insn->off = off;
- }
- }
- return 0;
-}
-
/* Clean up dynamically allocated fields of aux data for instructions [start, ...] */
void bpf_clear_insn_aux_data(struct bpf_verifier_env *env, int start, int len)
{
@@ -1988,7 +1950,6 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
const struct bpf_map_ops *ops;
struct bpf_insn_aux_data *aux;
struct bpf_insn *insn_buf = env->insn_buf;
- struct bpf_prog *new_prog;
struct bpf_map *map_ptr;
int i, ret, cnt, cur_subprog = 0;
struct bpf_subprog_info *subprogs = env->subprog_info;
@@ -2828,10 +2789,8 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)

env->prog->aux->stack_depth = subprogs[0].stack_depth;
for (i = 0; i < env->subprog_cnt; i++) {
- int delta = bpf_jit_supports_timed_may_goto() ? 2 : 1;
- int subprog_start = subprogs[i].start;
+ int slots = bpf_jit_supports_timed_may_goto() ? 2 : 1;
int stack_slots = subprogs[i].stack_extra / 8;
- int slots = delta, cnt = 0;

if (!stack_slots)
continue;
@@ -2841,6 +2800,7 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
return -EFAULT;
}

+ cnt = 0;
stack_depth = subprogs[i].stack_depth;
if (bpf_jit_supports_timed_may_goto()) {
insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -stack_depth,
@@ -2851,30 +2811,17 @@ int bpf_do_misc_fixups(struct bpf_verifier_env *env)
insn_buf[cnt++] = BPF_ST_MEM(BPF_DW, BPF_REG_FP, -stack_depth,
BPF_MAX_LOOPS);
}
- /* Copy first actual insn to preserve it */
- insn_buf[cnt] = env->prog->insnsi[subprog_start];
- ret = bpf_adj_moved_insn(&insn_buf[cnt], cnt);
- if (ret) {
- verbose(env, "insn %d cannot be patched due to 16-bit range\n",
- env->insn_aux_data[subprog_start].orig_idx);
+ /* jumps to the first insn of the subprog skip the setup */
+ ret = bpf_patch_list_insert(env, subprogs[i].start, insn_buf, cnt);
+ if (ret)
return ret;
- }
- cnt++;
-
- new_prog = __bpf_patch_insn_data(env, subprog_start, insn_buf, cnt,
- BPF_PATCH_MOVE_TARGET);
- if (!new_prog)
- return -ENOMEM;
- env->prog = prog = new_prog;
- /*
- * If may_goto is a first insn of a prog there could be a jmp
- * insn that points to it, hence adjust all such jmps to point
- * to insn after BPF_ST that inits may_goto count.
- * Adjustment will succeed because bpf_patch_insn_data() didn't fail.
- */
- WARN_ON(adjust_jmp_off(env->prog, subprog_start, delta));
}

+ ret = bpf_patch_list_commit(env);
+ if (ret)
+ return ret;
+ prog = env->prog;
+
/* Since poke tab is now finalized, publish aux to tracker. */
for (i = 0; i < prog->aux->size_poke_tab; i++) {
map_ptr = prog->aux->poke_tab[i].tail_call.map;

--
2.43.0