Received: by 2002:a05:6a10:f347:0:0:0:0 with SMTP id d7csp1569754pxu; Fri, 27 Nov 2020 10:02:24 -0800 (PST) X-Google-Smtp-Source: ABdhPJzqmcEFDJwi8Nhw95DSxg8VPFyEkJLDOjyIsbPrRdynXlO8jAjCnIoKyEGAn8W0pVZWe1e/ X-Received: by 2002:a50:d54a:: with SMTP id f10mr3845622edj.356.1606500144082; Fri, 27 Nov 2020 10:02:24 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1606500144; cv=none; d=google.com; s=arc-20160816; b=uEC0kZVQvOA50Saf0FPHFqXYUb6wn/CtEtNxAlHfEqWRZjCveqW+P4n7fDdd0shv6o 7AVmdMDe4EceGkUHTAVTyR3EHqW9C7bU/lkPvpPKFkuQkITF88o6FNIW6ns4qC/OKBqY weoJnSjZHZnlYnRhcpYK+nsVV5hFjT5VPYc/6k9IZPxVWyxYhwtGcKmk2jK/gv6pbswN k8C7wq7ucsOeXk7IjvUR1dfqRuJg5tIcbDP2uj9l8t+sVJNhUwqwVjvuKUJi10rzlhOi k6+qqsEXGTVyiPm5Ai6Xc2nT/usaHUSQt36UMPOCWrbijDxm0i0R0n5KtRPM9XL9uqHw zabA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=list-id:precedence:cc:to:from:subject:references:mime-version :message-id:in-reply-to:date:sender:dkim-signature; bh=mZvHjAE2xe0rGoIORBV8EUbjbmRNvWQYKWvCzYEAY9I=; b=SUazKSsUtWFU7w5y6lBlcWnZmARIOqSMtB+2JJ8+QidEfb+ehmXCn+ia07D2Isn+Sn LjQaSFCteizW+dH5nrSN2I3uG6H7bD7bsRlv5aO+FQqUBmXD60hEVGsc7j8zhUc21YYh WRLmnOKaFLVALGxBaVg6RyQzJWOdRg5K5r9vtaozBgnHLsjpazxvQjnCrMTGXS216oaL jzY7I2133gs09aTdAo7dKHtgNc9mnV9sS4ZvxdjhTciVZ7lsWo3hVjrLrodwiyCD+mMA 9YeRq59XxUCDHuGFUBQynGF/SPO/EyIEZ+IBy3etVk2PXKj2zzryQL66Hf2L1Q6FFYfz C0KQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=Jcv+0Mqi; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Return-Path: Received: from vger.kernel.org (vger.kernel.org. [23.128.96.18]) by mx.google.com with ESMTP id z59si3633436ede.218.2020.11.27.10.02.01; Fri, 27 Nov 2020 10:02:24 -0800 (PST) Received-SPF: pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) client-ip=23.128.96.18; Authentication-Results: mx.google.com; dkim=pass header.i=@google.com header.s=20161025 header.b=Jcv+0Mqi; spf=pass (google.com: domain of linux-kernel-owner@vger.kernel.org designates 23.128.96.18 as permitted sender) smtp.mailfrom=linux-kernel-owner@vger.kernel.org; dmarc=pass (p=REJECT sp=REJECT dis=NONE) header.from=google.com Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1733004AbgK0R6O (ORCPT + 99 others); Fri, 27 Nov 2020 12:58:14 -0500 Received: from lindbergh.monkeyblade.net ([23.128.96.19]:37802 "EHLO lindbergh.monkeyblade.net" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1732969AbgK0R6L (ORCPT ); Fri, 27 Nov 2020 12:58:11 -0500 Received: from mail-wr1-x44a.google.com (mail-wr1-x44a.google.com [IPv6:2a00:1450:4864:20::44a]) by lindbergh.monkeyblade.net (Postfix) with ESMTPS id 125A9C0613D1 for ; Fri, 27 Nov 2020 09:58:11 -0800 (PST) Received: by mail-wr1-x44a.google.com with SMTP id n13so3785263wrs.10 for ; Fri, 27 Nov 2020 09:58:11 -0800 (PST) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20161025; h=sender:date:in-reply-to:message-id:mime-version:references:subject :from:to:cc; bh=mZvHjAE2xe0rGoIORBV8EUbjbmRNvWQYKWvCzYEAY9I=; b=Jcv+0MqiazH0aK/8MJzRfSyVl6p/4WrnxQ1BydfAbL0drjK+I9i6e9XKme5KyBtQnm wNRtvwRlRLmaRFnf+3koDuPTjZVVhQ/Lj6Z16wDWHDMayyto1hR9vAQgBbHlPFAoswO8 w8ireE+54mev5nvNzwqc8nNJ4/eTvH2eknSR26ErOHXx5Z4fwDZs1WCmQ6Q+dV/gEF2E FJjSIBN9HxWbJjy4aq7D/WrZwprS31r/q0Zv03F2er1YwCOfU5dL612XPKWik4AU7oAl I1DKGbYv6vwG7VbRoMcj3T8Asa7EXeBKUCUIztzj028pv8D5eP1WDKNw8otlGUQxN1iQ 6rFA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:sender:date:in-reply-to:message-id:mime-version :references:subject:from:to:cc; bh=mZvHjAE2xe0rGoIORBV8EUbjbmRNvWQYKWvCzYEAY9I=; b=lKRfZD7X5SnLkABdGl64VGe/HlqTYd7/xKTUiDDRj1/1c3nDGDcv8v1B3XGrsLQMyj a+umaC0RRbBPdm6xEadGoBtN4C0Ojs441+1vK3TqTTBlMYqxoSVmvf+qpHly1LGCGZqX LiSvmFnn/paLnN2CDLPJGNVoC7dMVw9D9T6+Xl2ox6RgVDPvc2KBOIiargD48yk656RS q54z07JCO373N1joOQwQUlOqmtI8L08TVKKtfBvTNUiFT9aVW+0ah9e+dy4xLhCxEEDz 9RUmmnKkEVdQ29jD0Fm+EqOPt/NLsGmqVXbs1SGgzf2yki7cmT4MPf5/dzR9LV4q0whs bczg== X-Gm-Message-State: AOAM531cnHAl7dm63pTMSeaIFKbem4nFZ2ezp37wqHrIbHmmdhTtikrW 0vGl/yO1B8g1DQblz6DqXA+3ItzQGJKkEA== Sender: "jackmanb via sendgmr" X-Received: from beeg.c.googlers.com ([fda3:e722:ac3:cc00:28:9cb1:c0a8:11db]) (user=jackmanb job=sendgmr) by 2002:a7b:c1cc:: with SMTP id a12mr1857681wmj.0.1606499889154; Fri, 27 Nov 2020 09:58:09 -0800 (PST) Date: Fri, 27 Nov 2020 17:57:35 +0000 In-Reply-To: <20201127175738.1085417-1-jackmanb@google.com> Message-Id: <20201127175738.1085417-11-jackmanb@google.com> Mime-Version: 1.0 References: <20201127175738.1085417-1-jackmanb@google.com> X-Mailer: git-send-email 2.29.2.454.gaff20da3a2-goog Subject: [PATCH v2 bpf-next 10/13] bpf: Add instructions for atomic[64]_[fetch_]sub From: Brendan Jackman To: bpf@vger.kernel.org Cc: Alexei Starovoitov , Yonghong Song , Daniel Borkmann , KP Singh , Florent Revest , linux-kernel@vger.kernel.org, Jann Horn , Brendan Jackman Content-Type: text/plain; charset="UTF-8" Precedence: bulk List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Including only interpreter and x86 JIT support. x86 doesn't provide an atomic exchange-and-subtract instruction that could be used for BPF_SUB | BPF_FETCH, however we can just emit a NEG followed by an XADD to get the same effect. Signed-off-by: Brendan Jackman --- arch/x86/net/bpf_jit_comp.c | 16 ++++++++++++++-- include/linux/filter.h | 20 ++++++++++++++++++++ kernel/bpf/core.c | 1 + kernel/bpf/disasm.c | 16 ++++++++++++---- kernel/bpf/verifier.c | 2 ++ tools/include/linux/filter.h | 20 ++++++++++++++++++++ 6 files changed, 69 insertions(+), 6 deletions(-) diff --git a/arch/x86/net/bpf_jit_comp.c b/arch/x86/net/bpf_jit_comp.c index 7431b2937157..a8a9fab13fcf 100644 --- a/arch/x86/net/bpf_jit_comp.c +++ b/arch/x86/net/bpf_jit_comp.c @@ -823,6 +823,7 @@ static int emit_atomic(u8 **pprog, u8 atomic_op, /* emit opcode */ switch (atomic_op) { + case BPF_SUB: case BPF_ADD: /* lock *(u32/u64*)(dst_reg + off) = src_reg */ EMIT1(simple_alu_opcodes[atomic_op]); @@ -1306,8 +1307,19 @@ st: if (is_imm8(insn->off)) case BPF_STX | BPF_ATOMIC | BPF_W: case BPF_STX | BPF_ATOMIC | BPF_DW: - err = emit_atomic(&prog, insn->imm, dst_reg, src_reg, - insn->off, BPF_SIZE(insn->code)); + if (insn->imm == (BPF_SUB | BPF_FETCH)) { + /* + * x86 doesn't have an XSUB insn, so we negate + * and XADD instead. + */ + emit_neg(&prog, src_reg, BPF_SIZE(insn->code) == BPF_DW); + err = emit_atomic(&prog, BPF_ADD | BPF_FETCH, + dst_reg, src_reg, insn->off, + BPF_SIZE(insn->code)); + } else { + err = emit_atomic(&prog, insn->imm, dst_reg, src_reg, + insn->off, BPF_SIZE(insn->code)); + } if (err) return err; break; diff --git a/include/linux/filter.h b/include/linux/filter.h index 6186280715ed..a20a3a536bf5 100644 --- a/include/linux/filter.h +++ b/include/linux/filter.h @@ -280,6 +280,26 @@ static inline bool insn_is_zext(const struct bpf_insn *insn) .off = OFF, \ .imm = BPF_ADD | BPF_FETCH }) +/* Atomic memory sub, *(uint *)(dst_reg + off16) -= src_reg */ + +#define BPF_ATOMIC_SUB(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_ATOMIC, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = BPF_SUB }) + +/* Atomic memory sub with fetch, src_reg = atomic_fetch_sub(*(dst_reg + off), src_reg); */ + +#define BPF_ATOMIC_FETCH_SUB(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_ATOMIC, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = BPF_SUB | BPF_FETCH }) + /* Atomic exchange, src_reg = atomic_xchg((dst_reg + off), src_reg) */ #define BPF_ATOMIC_XCHG(SIZE, DST, SRC, OFF) \ diff --git a/kernel/bpf/core.c b/kernel/bpf/core.c index 20a5351d1dc2..0f700464955f 100644 --- a/kernel/bpf/core.c +++ b/kernel/bpf/core.c @@ -1650,6 +1650,7 @@ static u64 ___bpf_prog_run(u64 *regs, const struct bpf_insn *insn, u64 *stack) STX_ATOMIC_W: switch (IMM) { ATOMIC(BPF_ADD, add) + ATOMIC(BPF_SUB, sub) case BPF_XCHG: if (BPF_SIZE(insn->code) == BPF_W) diff --git a/kernel/bpf/disasm.c b/kernel/bpf/disasm.c index 3441ac54ac65..f33acffdeed0 100644 --- a/kernel/bpf/disasm.c +++ b/kernel/bpf/disasm.c @@ -80,6 +80,11 @@ const char *const bpf_alu_string[16] = { [BPF_END >> 4] = "endian", }; +const char *const bpf_atomic_alu_string[16] = { + [BPF_ADD >> 4] = "add", + [BPF_SUB >> 4] = "sub", +}; + static const char *const bpf_ldst_string[] = { [BPF_W >> 3] = "u32", [BPF_H >> 3] = "u16", @@ -154,17 +159,20 @@ void print_bpf_insn(const struct bpf_insn_cbs *cbs, insn->dst_reg, insn->off, insn->src_reg); else if (BPF_MODE(insn->code) == BPF_ATOMIC && - insn->imm == BPF_ADD) { - verbose(cbs->private_data, "(%02x) lock *(%s *)(r%d %+d) += r%d\n", + (insn->imm == BPF_ADD || insn->imm == BPF_SUB)) { + verbose(cbs->private_data, "(%02x) lock *(%s *)(r%d %+d) %s r%d\n", insn->code, bpf_ldst_string[BPF_SIZE(insn->code) >> 3], insn->dst_reg, insn->off, + bpf_alu_string[BPF_OP(insn->imm) >> 4], insn->src_reg); } else if (BPF_MODE(insn->code) == BPF_ATOMIC && - insn->imm == (BPF_ADD | BPF_FETCH)) { - verbose(cbs->private_data, "(%02x) r%d = atomic%s_fetch_add(*(%s *)(r%d %+d), r%d)\n", + (insn->imm == (BPF_ADD | BPF_FETCH) || + insn->imm == (BPF_SUB | BPF_FETCH))) { + verbose(cbs->private_data, "(%02x) r%d = atomic%s_fetch_%s(*(%s *)(r%d %+d), r%d)\n", insn->code, insn->src_reg, BPF_SIZE(insn->code) == BPF_DW ? "64" : "", + bpf_atomic_alu_string[BPF_OP(insn->imm) >> 4], bpf_ldst_string[BPF_SIZE(insn->code) >> 3], insn->dst_reg, insn->off, insn->src_reg); } else if (BPF_MODE(insn->code) == BPF_ATOMIC && diff --git a/kernel/bpf/verifier.c b/kernel/bpf/verifier.c index c8311cc114ec..dea9ad486ad1 100644 --- a/kernel/bpf/verifier.c +++ b/kernel/bpf/verifier.c @@ -3606,6 +3606,8 @@ static int check_atomic(struct bpf_verifier_env *env, int insn_idx, struct bpf_i switch (insn->imm) { case BPF_ADD: case BPF_ADD | BPF_FETCH: + case BPF_SUB: + case BPF_SUB | BPF_FETCH: case BPF_XCHG: case BPF_CMPXCHG: break; diff --git a/tools/include/linux/filter.h b/tools/include/linux/filter.h index ea99bd17d003..387eddaf11e5 100644 --- a/tools/include/linux/filter.h +++ b/tools/include/linux/filter.h @@ -190,6 +190,26 @@ .off = OFF, \ .imm = BPF_ADD | BPF_FETCH }) +/* Atomic memory sub, *(uint *)(dst_reg + off16) -= src_reg */ + +#define BPF_ATOMIC_SUB(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_ATOMIC, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = BPF_SUB }) + +/* Atomic memory sub with fetch, src_reg = atomic_fetch_sub(*(dst_reg + off), src_reg); */ + +#define BPF_ATOMIC_FETCH_SUB(SIZE, DST, SRC, OFF) \ + ((struct bpf_insn) { \ + .code = BPF_STX | BPF_SIZE(SIZE) | BPF_ATOMIC, \ + .dst_reg = DST, \ + .src_reg = SRC, \ + .off = OFF, \ + .imm = BPF_SUB | BPF_FETCH }) + /* Atomic exchange, src_reg = atomic_xchg((dst_reg + off), src_reg) */ #define BPF_ATOMIC_XCHG(SIZE, DST, SRC, OFF) \ -- 2.29.2.454.gaff20da3a2-goog