Blob Blame History Raw
From: Bennett Amodio <bamodio@purestorage.com>
Date: Tue, 15 Aug 2017 17:51:46 -0700
Subject: [PATCH] SUNRPC: Mask XIDs to prevent replay cache collision
Patch-mainline: Submitted, linux-nfs@vger.kernel.org
References: fate#322786

Modify transport behavior so transports mask their XIDs. xid_mask is
the mask which clears the top several bits. masked_xid is the ID
(unique to each transport which belongs to the same NFS mount).

We also removed xprt_init_xid, since the XID is now initialized
through rpc_create (and passed in via xprtargs). Since the
initialization of xid, masked_id and xid_mask occur in
xprt_create_transport, this should work with rpcrdma as well.

Signed-off-by: Bennett Amodio <bamodio@purestorage.com>
Acked-by: NeilBrown <neilb@suse.com>

---
 include/linux/sunrpc/xprt.h |    5 +++++
 net/sunrpc/clnt.c           |    8 ++++++++
 net/sunrpc/xprt.c           |   18 +++++++++---------
 3 files changed, 22 insertions(+), 9 deletions(-)

--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -208,6 +208,8 @@ struct rpc_xprt {
 	 * Multipath
 	 */
 	struct list_head	xprt_switch;
+	u32 masked_id;
+	u32 xid_mask;
 
 	/*
 	 * Connection of transports
@@ -308,6 +310,9 @@ struct xprt_create {
 	struct svc_xprt		*bc_xprt;	/* NFSv4.1 backchannel */
 	struct rpc_xprt_switch	*bc_xps;
 	unsigned int		flags;
+	u32 transport_id;
+	u32 bitmask_len;
+	u32 init_xid;
 };
 
 struct xprt_class {
--- a/net/sunrpc/clnt.c
+++ b/net/sunrpc/clnt.c
@@ -520,6 +520,7 @@ struct rpc_clnt *rpc_create(struct rpc_c
 		.addrlen = args->addrsize,
 		.servername = args->servername,
 		.bc_xprt = args->bc_xprt,
+		.init_xid = prandom_u32(),
 	};
 	char servername[48];
 	struct rpc_clnt *clnt;
@@ -572,6 +573,12 @@ struct rpc_clnt *rpc_create(struct rpc_c
 		xprtargs.servername = servername;
 	}
 
+	if (args->nconnect)
+		xprtargs.bitmask_len = fls(args->nconnect - 1);
+	else
+		xprtargs.bitmask_len = 0;
+	xprtargs.transport_id = 0;
+
 	xprt = xprt_create_transport(&xprtargs);
 	if (IS_ERR(xprt))
 		return (struct rpc_clnt *)xprt;
@@ -591,6 +598,7 @@ struct rpc_clnt *rpc_create(struct rpc_c
 		return clnt;
 
 	for (i = 0; i < args->nconnect - 1; i++) {
+		xprtargs.transport_id += 1;
 		if (rpc_clnt_add_xprt(clnt, &xprtargs, NULL, NULL) < 0)
 			break;
 	}
--- a/net/sunrpc/xprt.c
+++ b/net/sunrpc/xprt.c
@@ -1249,18 +1249,12 @@ xprt_alloc_xid(struct rpc_xprt *xprt)
 	__be32 xid;
 
 	spin_lock(&xprt->reserve_lock);
-	xid = (__force __be32)xprt->xid++;
+	xid = (__force __be32)(xprt->xid++ & xprt->xid_mask) | xprt->masked_id;
 	spin_unlock(&xprt->reserve_lock);
 	return xid;
 }
 
 static void
-xprt_init_xid(struct rpc_xprt *xprt)
-{
-	xprt->xid = prandom_u32();
-}
-
-static void
 xprt_request_init(struct rpc_task *task)
 {
 	struct rpc_xprt *xprt = task->tk_xprt;
@@ -1414,8 +1408,6 @@ static void xprt_init(struct rpc_xprt *x
 	rpc_init_priority_wait_queue(&xprt->sending, "xprt_sending");
 	rpc_init_priority_wait_queue(&xprt->backlog, "xprt_backlog");
 
-	xprt_init_xid(xprt);
-
 	xprt->xprt_net = get_net(net);
 }
 
@@ -1447,6 +1439,14 @@ found:
 				-PTR_ERR(xprt));
 		goto out;
 	}
+
+	xprt->xid_mask = 0xffffffff >> args->bitmask_len;
+	if (args->bitmask_len)
+		xprt->masked_id = args->transport_id << (32 - args->bitmask_len);
+	else
+		xprt->masked_id = 0;
+	xprt->xid = args->init_xid;
+
 	if (args->flags & XPRT_CREATE_NO_IDLE_TIMEOUT)
 		xprt->idle_timeout = 0;
 	INIT_WORK(&xprt->task_cleanup, xprt_autoclose);