From patchwork Mon Nov 28 14:43:03 2022 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tim Gardner X-Patchwork-Id: 1709792 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@legolas.ozlabs.org Authentication-Results: legolas.ozlabs.org; spf=pass (sender SPF authorized) smtp.mailfrom=lists.ubuntu.com (client-ip=91.189.94.19; helo=huckleberry.canonical.com; envelope-from=kernel-team-bounces@lists.ubuntu.com; receiver=) Authentication-Results: legolas.ozlabs.org; dkim=fail reason="signature verification failed" (2048-bit key; unprotected) header.d=canonical.com header.i=@canonical.com header.a=rsa-sha256 header.s=20210705 header.b=kIfoR20h; dkim-atps=neutral Received: from huckleberry.canonical.com (huckleberry.canonical.com [91.189.94.19]) (using TLSv1.2 with cipher ECDHE-ECDSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by legolas.ozlabs.org (Postfix) with ESMTPS id 4NLSs75Xzrz23nB for ; Tue, 29 Nov 2022 01:43:55 +1100 (AEDT) Received: from localhost ([127.0.0.1] helo=huckleberry.canonical.com) by huckleberry.canonical.com with esmtp (Exim 4.86_2) (envelope-from ) id 1ozfML-0003ax-Tn; Mon, 28 Nov 2022 14:43:49 +0000 Received: from smtp-relay-internal-1.internal ([10.131.114.114] helo=smtp-relay-internal-1.canonical.com) by huckleberry.canonical.com with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.86_2) (envelope-from ) id 1ozfMJ-0003YX-AF for kernel-team@lists.ubuntu.com; Mon, 28 Nov 2022 14:43:47 +0000 Received: from mail-pf1-f198.google.com (mail-pf1-f198.google.com [209.85.210.198]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits) server-digest SHA256) (No client certificate requested) by smtp-relay-internal-1.canonical.com (Postfix) with ESMTPS id 0F57A3F0E9 for ; Mon, 28 Nov 2022 14:43:47 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=canonical.com; s=20210705; t=1669646627; bh=HJjYI/mpenmDLRdjf34D2rjkajIKRi+cgQNQl/+Y3GA=; h=From:To:Cc:Subject:Date:Message-Id:In-Reply-To:References: MIME-Version; b=kIfoR20hTVWbc4LCyca/A8bLiXOhnMMQ0TFi0mgvXdCo4E3tboKMsU1J+Ok8Ic+D3 DxNmMG26vP2W9ADpFAQuGxTkq6UiTOs+h/NtX2wt0BdLxbCfBXCB987JSJA3YpA12z xslU3Ci/OQWbrnedOk7sFtjAv18Z7qGi6/fu8Z8WaLZ085I6ZuDladn1h4WeatnupZ SDsxv9BMUD6sldoBnaLqY8D/3GGXlCNmsxSAm2pi6MOCO69BVNZJXrQNOAppszfho7 Uyfvo3jOUk0eaS01ynJmCGmtc6Y/9WzpBhkRFhJjDIzxR3uamV58dQ6EXBrg7eNxSC 1HbfW30J5lH9w== Received: by mail-pf1-f198.google.com with SMTP id z19-20020a056a001d9300b0056df4b6f421so8512900pfw.4 for ; Mon, 28 Nov 2022 06:43:46 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=content-transfer-encoding:mime-version:references:in-reply-to :message-id:date:subject:cc:to:from:x-gm-message-state:from:to:cc :subject:date:message-id:reply-to; bh=HJjYI/mpenmDLRdjf34D2rjkajIKRi+cgQNQl/+Y3GA=; b=aaj+SYxF3oAEVaQV//nT1ngIj/PuJsTcTaFLEdz4RYLfHwJ3x9oK1tQrVH8NcX3PD7 GgDvREfnk0JFxAZSREM902UvWFB2KcSBGxs/Us2wSAh8JnHIk2Q7Z4E3TgGw5NjWjFz+ QTKmTxluCmy5hj7DmJX9fWA+5xMtqKgGaMwqMXVV3jKF7y8kZqG/rRvUsmeLm7a1mJnM bQIQLuqzFUsh/Qz80Ij6LVNl07GLm1dys4K4fkMANuLK3MsgcfnciL86qvBUfXcyMBNq ZwWJN8fbFpAsc56LgoGlRg9n0QVmo4OvjFuia+inQ80M59VWNdTLkNhexNelSqSrYJmc yfUQ== X-Gm-Message-State: ANoB5pkpZCZhL5zJWSO+DFpIQtf8XO7fXA5O/dP5NqjnjTsCTLK0eFDj IvDZa9GjOH9gmgcZqr/hQTwuffBOdgQ5R3iB11vhJUXWSQbivG88BsTpxQ9OiY0T9RQYcW8kHX/ ngSGyIhuR1ueACk6nZrzVKjeSnLctn48Wrig3FyDH2w== X-Received: by 2002:a17:902:e1cb:b0:17f:74f8:c0ca with SMTP id t11-20020a170902e1cb00b0017f74f8c0camr30813352pla.169.1669646625424; Mon, 28 Nov 2022 06:43:45 -0800 (PST) X-Google-Smtp-Source: AA0mqf58YjTIvunN1JG4OTAbTAmIDfhowjzH2jXJ/HB2ln/ULK7SaIFu0rycuiAPvv4TxXJgJee4Bg== X-Received: by 2002:a17:902:e1cb:b0:17f:74f8:c0ca with SMTP id t11-20020a170902e1cb00b0017f74f8c0camr30813332pla.169.1669646625081; Mon, 28 Nov 2022 06:43:45 -0800 (PST) Received: from localhost.localdomain ([69.163.84.166]) by smtp.gmail.com with ESMTPSA id y6-20020a626406000000b005745a586badsm8102167pfb.218.2022.11.28.06.43.44 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Mon, 28 Nov 2022 06:43:44 -0800 (PST) From: Tim Gardner To: kernel-team@lists.ubuntu.com Subject: [PATCH] NFSv4.1: Don't rebind to the same source port when reconnecting to the server Date: Mon, 28 Nov 2022 07:43:03 -0700 Message-Id: <20221128144303.380283-2-tim.gardner@canonical.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20221128144303.380283-1-tim.gardner@canonical.com> References: <20221128144303.380283-1-tim.gardner@canonical.com> MIME-Version: 1.0 X-BeenThere: kernel-team@lists.ubuntu.com X-Mailman-Version: 2.1.20 Precedence: list List-Id: Kernel team discussions List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: kernel-team-bounces@lists.ubuntu.com Sender: "kernel-team" From: Trond Myklebust BugLink: https://bugs.launchpad.net/bugs/1997488 NFSv2, v3 and NFSv4 servers often have duplicate replay caches that look at the source port when deciding whether or not an RPC call is a replay of a previous call. This requires clients to perform strange TCP gymnastics in order to ensure that when they reconnect to the server, they bind to the same source port. NFSv4.1 and NFSv4.2 have sessions that provide proper replay semantics, that do not look at the source port of the connection. This patch therefore ensures they can ignore the rebind requirement. Signed-off-by: Trond Myklebust (backported from commit e6237b6feb37582fbd6bd7a8336d1256a6b4b4f9) [rtg - missing commits 4b1b69cedf9de8c203101ea74510c07d428538f7 and c6eb58435b98bd843d3179664a0195ff25adb2c3] Signed-off-by: Tim Gardner --- fs/lockd/host.c | 3 ++- fs/nfs/client.c | 3 +++ fs/nfs/nfs4client.c | 5 ++++- include/linux/nfs_fs_sb.h | 1 + include/linux/sunrpc/clnt.h | 1 + include/linux/sunrpc/xprt.h | 3 ++- net/sunrpc/clnt.c | 7 ++++++- net/sunrpc/xprtsock.c | 2 +- 8 files changed, 20 insertions(+), 5 deletions(-) diff --git a/fs/lockd/host.c b/fs/lockd/host.c index 584c03e11844..771c289f6df7 100644 --- a/fs/lockd/host.c +++ b/fs/lockd/host.c @@ -459,7 +459,8 @@ nlm_bind_host(struct nlm_host *host) .version = host->h_version, .authflavor = RPC_AUTH_UNIX, .flags = (RPC_CLNT_CREATE_NOPING | - RPC_CLNT_CREATE_AUTOBIND), + RPC_CLNT_CREATE_AUTOBIND | + RPC_CLNT_CREATE_REUSEPORT), .cred = host->h_cred, }; diff --git a/fs/nfs/client.c b/fs/nfs/client.c index 35abe63655a9..b6a6316656d2 100644 --- a/fs/nfs/client.c +++ b/fs/nfs/client.c @@ -516,6 +516,8 @@ int nfs_create_rpc_client(struct nfs_client *clp, args.flags |= RPC_CLNT_CREATE_NONPRIVPORT; if (test_bit(NFS_CS_INFINITE_SLOTS, &clp->cl_flags)) args.flags |= RPC_CLNT_CREATE_INFINITE_SLOTS; + if (test_bit(NFS_CS_REUSEPORT, &clp->cl_flags)) + args.flags |= RPC_CLNT_CREATE_REUSEPORT; if (!IS_ERR(clp->cl_rpcclient)) return 0; @@ -663,6 +665,7 @@ static int nfs_init_server(struct nfs_server *server, .timeparms = &timeparms, .cred = server->cred, .nconnect = data->nfs_server.nconnect, + .init_flags = (1UL << NFS_CS_REUSEPORT), }; struct nfs_client *clp; int error; diff --git a/fs/nfs/nfs4client.c b/fs/nfs/nfs4client.c index 3671a51fe5eb..70e770b7dd12 100644 --- a/fs/nfs/nfs4client.c +++ b/fs/nfs/nfs4client.c @@ -880,8 +880,11 @@ static int nfs4_set_client(struct nfs_server *server, }; struct nfs_client *clp; - if (minorversion > 0 && proto == XPRT_TRANSPORT_TCP) + if (minorversion == 0) + __set_bit(NFS_CS_REUSEPORT, &cl_init.init_flags); + else if (proto == XPRT_TRANSPORT_TCP) cl_init.nconnect = nconnect; + if (server->flags & NFS_MOUNT_NORESVPORT) set_bit(NFS_CS_NORESVPORT, &cl_init.init_flags); if (server->options & NFS_OPTION_MIGRATION) diff --git a/include/linux/nfs_fs_sb.h b/include/linux/nfs_fs_sb.h index a87fe854f008..76b2149d5468 100644 --- a/include/linux/nfs_fs_sb.h +++ b/include/linux/nfs_fs_sb.h @@ -45,6 +45,7 @@ struct nfs_client { #define NFS_CS_INFINITE_SLOTS 3 /* - don't limit TCP slots */ #define NFS_CS_NO_RETRANS_TIMEOUT 4 /* - Disable retransmit timeouts */ #define NFS_CS_TSM_POSSIBLE 5 /* - Maybe state migration */ +#define NFS_CS_REUSEPORT 8 /* - reuse src port on reconnect */ struct sockaddr_storage cl_addr; /* server identifier */ size_t cl_addrlen; char * cl_hostname; /* hostname of server */ diff --git a/include/linux/sunrpc/clnt.h b/include/linux/sunrpc/clnt.h index 336802acc629..eca293c139b4 100644 --- a/include/linux/sunrpc/clnt.h +++ b/include/linux/sunrpc/clnt.h @@ -149,6 +149,7 @@ struct rpc_add_xprt_test { #define RPC_CLNT_CREATE_NO_IDLE_TIMEOUT (1UL << 8) #define RPC_CLNT_CREATE_NO_RETRANS_TIMEOUT (1UL << 9) #define RPC_CLNT_CREATE_SOFTERR (1UL << 10) +#define RPC_CLNT_CREATE_REUSEPORT (1UL << 11) struct rpc_clnt *rpc_create(struct rpc_create_args *args); struct rpc_clnt *rpc_bind_new_program(struct rpc_clnt *, diff --git a/include/linux/sunrpc/xprt.h b/include/linux/sunrpc/xprt.h index 3c6c4b1dbf1a..86fb981adbf0 100644 --- a/include/linux/sunrpc/xprt.h +++ b/include/linux/sunrpc/xprt.h @@ -207,7 +207,8 @@ struct rpc_xprt { unsigned int min_reqs; /* min number of slots */ unsigned int num_reqs; /* total slots */ unsigned long state; /* transport state */ - unsigned char resvport : 1; /* use a reserved port */ + unsigned char resvport : 1, /* use a reserved port */ + reuseport : 1; /* reuse port on reconnect */ atomic_t swapper; /* we're swapping over this transport */ unsigned int bind_index; /* bind function index */ diff --git a/net/sunrpc/clnt.c b/net/sunrpc/clnt.c index 1893203cc94f..a6d579bdefd8 100644 --- a/net/sunrpc/clnt.c +++ b/net/sunrpc/clnt.c @@ -591,6 +591,9 @@ struct rpc_clnt *rpc_create(struct rpc_create_args *args) xprt->resvport = 1; if (args->flags & RPC_CLNT_CREATE_NONPRIVPORT) xprt->resvport = 0; + xprt->reuseport = 0; + if (args->flags & RPC_CLNT_CREATE_REUSEPORT) + xprt->reuseport = 1; clnt = rpc_create_xprt(args, xprt); if (IS_ERR(clnt) || args->nconnect <= 1) @@ -2917,7 +2920,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt, struct rpc_xprt *xprt; unsigned long connect_timeout; unsigned long reconnect_timeout; - unsigned char resvport; + unsigned char resvport, reuseport; int ret = 0; rcu_read_lock(); @@ -2929,6 +2932,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt, return -EAGAIN; } resvport = xprt->resvport; + reuseport = xprt->reuseport; connect_timeout = xprt->connect_timeout; reconnect_timeout = xprt->max_reconnect_timeout; rcu_read_unlock(); @@ -2939,6 +2943,7 @@ int rpc_clnt_add_xprt(struct rpc_clnt *clnt, goto out_put_switch; } xprt->resvport = resvport; + xprt->reuseport = reuseport; if (xprt->ops->set_connect_timeout != NULL) xprt->ops->set_connect_timeout(xprt, connect_timeout, diff --git a/net/sunrpc/xprtsock.c b/net/sunrpc/xprtsock.c index 91c8249ee818..68fc5539b123 100644 --- a/net/sunrpc/xprtsock.c +++ b/net/sunrpc/xprtsock.c @@ -1787,7 +1787,7 @@ static void xs_set_port(struct rpc_xprt *xprt, unsigned short port) static void xs_set_srcport(struct sock_xprt *transport, struct socket *sock) { - if (transport->srcport == 0) + if (transport->srcport == 0 && transport->xprt.reuseport) transport->srcport = xs_sock_getport(sock); }