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 | 17 +++++++++--------
3 files changed, 22 insertions(+), 8 deletions(-)
--- a/include/linux/sunrpc/xprt.h
+++ b/include/linux/sunrpc/xprt.h
@@ -207,6 +207,8 @@ struct rpc_xprt {
* Multipath
*/
struct list_head xprt_switch;
+ u32 masked_id;
+ u32 xid_mask;
/*
* Connection of transports
@@ -306,6 +308,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
@@ -1231,12 +1231,7 @@ void xprt_retry_reserve(struct rpc_task
static inline __be32 xprt_alloc_xid(struct rpc_xprt *xprt)
{
- return (__force __be32)xprt->xid++;
-}
-
-static inline void xprt_init_xid(struct rpc_xprt *xprt)
-{
- xprt->xid = prandom_u32();
+ return (__force __be32)(xprt->xid++& xprt->xid_mask) | xprt->masked_id;
}
static void xprt_request_init(struct rpc_task *task, struct rpc_xprt *xprt)
@@ -1334,8 +1329,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);
}
@@ -1367,6 +1360,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);