summaryrefslogtreecommitdiff
path: root/tools/perf/scripts/python
diff options
context:
space:
mode:
authorPuranjay Mohan <puranjay@kernel.org>2026-10-16 10:13:12 -0700
committerAlexei Starovoitov <ast@kernel.org>2026-10-16 18:50:20 +0000
commitd9efbaed7e614278002c4c1e476b62b3f20ed5df (patch)
treeec9a6d8586c5d47cdad3a216c7e78ea61e4efa42 /tools/perf/scripts/python
parent2d1f101ee619435873ed8a23fcb3bd09204a5024 (diff)
bpf, x86: Support fetching AND/OR/XOR atomics in arena
x86-64 has no single instruction for a fetching AND/OR/XOR, so the JIT lowers them to a CMPXCHG loop. That loop could not be used against arena memory: it contains two memory accesses, the load of the old value and the CMPXCHG itself, either of which can fault when the arena page goes away, while the verifier reserves only one exception table entry per instruction. bpf_jit_supports_insn() therefore rejected the three opcodes and such programs failed to load with BPF_ATOMIC stores into R1 arena is not allowed Emit the same loop with R12-indexed addressing and give each of the two accesses its own exception table entry. The verifier still reserves one per instruction, so the JIT accounts for the extra entry itself by rescanning the instruction stream in bpf_int_jit_compile() before the extable is sized, as s390 does in bpf_jit_alloc() for its BPF_XCHG lowering. The rescan sits after the extra-pass early exit, so a program is counted exactly once. Drop the bpf_jit_supports_insn() rejection. A loop without the load would need only one entry, since a CMPXCHG that loses the comparison reloads RAX, but its first CMPXCHG would then almost always lose. Every operation would pay for a second locked CMPXCHG, which makes the fetching insn more expensive than the load and CMPXCHG loop programs write by hand today. The second entry is paid for once, in the JIT. Both entries resume past the whole loop rather than past the faulting instruction alone, with the fetch destination cleared, so a fault cannot re-enter the loop, and both are reported as writes since the BPF insn is a read-modify-write. This repurposes the INSN_LEN field of the fixup as a resume distance rather than an instruction length; a sequence long enough to overflow its 8 bits would first have to exceed BPF_MAX_INSN_SIZE, which do_jit() rejects before the image is used. The loop needs RAX for CMPXCHG and saves R0 in BPF_REG_AX, which it also substitutes for R0 when either operand is R0. ex_handler_bpf() may then have to name r10 as the register holding the arena address or the one to clear on fault; reg2pt_regs[] already has that entry. An access through a number, made by a program loaded with BPF_F_ARENA_SCALAR, keeps its address in BPF_REG_AX itself (see arena_scalar_access()), which is where the loop would save R0. Save R0 on the stack in that case, as the div and mod lowering does. An R0 operand stays in that stack slot: the new value is built from it, RAX ends up holding the old value that R0 is to return, and the slot is dropped instead of popped. Both entries resume before that pop or drop, so a fault leaves the stack balanced. Signed-off-by: Puranjay Mohan <puranjay@kernel.org> Signed-off-by: Alexei Starovoitov <ast@kernel.org> Acked-by: Tejun Heo <tj@kernel.org> Link: https://patch.msgid.link/20261016171319.1623447-2-puranjay@kernel.org
Diffstat (limited to 'tools/perf/scripts/python')
0 files changed, 0 insertions, 0 deletions