Commit b0073267 authored by Ilya Leoshkevich's avatar Ilya Leoshkevich Committed by Ma Wupeng
Browse files

s390/bpf: Emit a barrier for BPF_FETCH instructions

stable inclusion
from stable-v6.6.33
commit 46f17e7d4fb5a21917894d7d37e805194229d4d5
category: bugfix
bugzilla: https://gitee.com/openeuler/kernel/issues/IAD6H2

Reference: https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/commit/?id=46f17e7d4fb5a21917894d7d37e805194229d4d5



--------------------------------

[ Upstream commit 68378982f0b21de02ac3c6a11e2420badefcb4bc ]

BPF_ATOMIC_OP() macro documentation states that "BPF_ADD | BPF_FETCH"
should be the same as atomic_fetch_add(), which is currently not the
case on s390x: the serialization instruction "bcr 14,0" is missing.
This applies to "and", "or" and "xor" variants too.

s390x is allowed to reorder stores with subsequent fetches from
different addresses, so code relying on BPF_FETCH acting as a barrier,
for example:

  stw [%r0], 1
  afadd [%r1], %r2
  ldxw %r3, [%r4]

may be broken. Fix it by emitting "bcr 14,0".

Note that a separate serialization instruction is not needed for
BPF_XCHG and BPF_CMPXCHG, because COMPARE AND SWAP performs
serialization itself.

Fixes: ba3b86b9 ("s390/bpf: Implement new atomic ops")
Reported-by: default avatarPuranjay Mohan <puranjay12@gmail.com>
Closes: https://lore.kernel.org/bpf/mb61p34qvq3wf.fsf@kernel.org/


Signed-off-by: default avatarIlya Leoshkevich <iii@linux.ibm.com>
Reviewed-by: default avatarPuranjay Mohan <puranjay@kernel.org>
Link: https://lore.kernel.org/r/20240507000557.12048-1-iii@linux.ibm.com


Signed-off-by: default avatarAlexei Starovoitov <ast@kernel.org>
Signed-off-by: default avatarSasha Levin <sashal@kernel.org>
Signed-off-by: default avatarWang Hai <wanghai38@huawei.com>
parent ab74ac39
Loading
Loading
Loading
Loading
+6 −2
Original line number Diff line number Diff line
@@ -1311,8 +1311,12 @@ static noinline int bpf_jit_insn(struct bpf_jit *jit, struct bpf_prog *fp,
	EMIT6_DISP_LH(0xeb000000, is32 ? (op32) : (op64),		\
		      (insn->imm & BPF_FETCH) ? src_reg : REG_W0,	\
		      src_reg, dst_reg, off);				\
	if (is32 && (insn->imm & BPF_FETCH))				\
	if (insn->imm & BPF_FETCH) {					\
		/* bcr 14,0 - see atomic_fetch_{add,and,or,xor}() */	\
		_EMIT2(0x07e0);						\
		if (is32)                                               \
			EMIT_ZERO(src_reg);				\
	}								\
} while (0)
		case BPF_ADD:
		case BPF_ADD | BPF_FETCH: