]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
rpc: share one xps between all backchannels
authorJ. Bruce Fields <bfields@redhat.com>
Tue, 17 May 2016 16:38:21 +0000 (12:38 -0400)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 27 Jul 2016 15:42:12 +0000 (08:42 -0700)
commit 39a9beab5acb83176e8b9a4f0778749a09341f1f upstream.

The spec allows backchannels for multiple clients to share the same tcp
connection.  When that happens, we need to use the same xprt for all of
them.  Similarly, we need the same xps.

This fixes list corruption introduced by the multipath code.

Signed-off-by: J. Bruce Fields <bfields@redhat.com>
Acked-by: Trond Myklebust <trondmy@primarydata.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
include/linux/sunrpc/svc_xprt.h
include/linux/sunrpc/xprt.h
net/sunrpc/clnt.c
net/sunrpc/svc_xprt.c
net/sunrpc/xprtsock.c

index b7dabc4baafd817d0b2a41c5cf8e54e4b3fddc47..79ba50856707b9b9a619be78335b27b383312ed9 100644 (file)
@@ -84,6 +84,7 @@ struct svc_xprt {
 
        struct net              *xpt_net;
        struct rpc_xprt         *xpt_bc_xprt;   /* NFSv4.1 backchannel */
+       struct rpc_xprt_switch  *xpt_bc_xps;    /* NFSv4.1 backchannel */
 };
 
 static inline void unregister_xpt_user(struct svc_xprt *xpt, struct svc_xpt_user *u)
index fb0d212e0d3af2dd3ed78d4ec181e63f8e72dac1..9f51e1df302308e8c6cc749a960577f2fc2004e6 100644 (file)
@@ -296,6 +296,7 @@ struct xprt_create {
        size_t                  addrlen;
        const char              *servername;
        struct svc_xprt         *bc_xprt;       /* NFSv4.1 backchannel */
+       struct rpc_xprt_switch  *bc_xps;
        unsigned int            flags;
 };
 
index ad3f5ebec2d126dfc695dd40f7fada1dd5f00158..837dd910a25272c7d732641df2f8ad6088dbb0e6 100644 (file)
@@ -452,10 +452,20 @@ static struct rpc_clnt *rpc_create_xprt(struct rpc_create_args *args,
        struct rpc_clnt *clnt = NULL;
        struct rpc_xprt_switch *xps;
 
-       xps = xprt_switch_alloc(xprt, GFP_KERNEL);
-       if (xps == NULL) {
-               xprt_put(xprt);
-               return ERR_PTR(-ENOMEM);
+       if (args->bc_xprt && args->bc_xprt->xpt_bc_xps) {
+               WARN_ON(args->protocol != XPRT_TRANSPORT_BC_TCP);
+               xps = args->bc_xprt->xpt_bc_xps;
+               xprt_switch_get(xps);
+       } else {
+               xps = xprt_switch_alloc(xprt, GFP_KERNEL);
+               if (xps == NULL) {
+                       xprt_put(xprt);
+                       return ERR_PTR(-ENOMEM);
+               }
+               if (xprt->bc_xprt) {
+                       xprt_switch_get(xps);
+                       xprt->bc_xprt->xpt_bc_xps = xps;
+               }
        }
        clnt = rpc_new_client(args, xps, xprt, NULL);
        if (IS_ERR(clnt))
index 7422f28818b24de5e7b36eca01ac2e91f9a7cd4f..7231cb413a2c623751a5b2d823cfb5104d4815c8 100644 (file)
@@ -136,6 +136,8 @@ static void svc_xprt_free(struct kref *kref)
        /* See comment on corresponding get in xs_setup_bc_tcp(): */
        if (xprt->xpt_bc_xprt)
                xprt_put(xprt->xpt_bc_xprt);
+       if (xprt->xpt_bc_xps)
+               xprt_switch_put(xprt->xpt_bc_xps);
        xprt->xpt_ops->xpo_free(xprt);
        module_put(owner);
 }
index 65e759569e4873619735b966cd055b9d634d2d3a..e9e5dd0dc8f488aad89ec8cc4351920673b8349d 100644 (file)
@@ -3050,6 +3050,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
                return xprt;
 
        args->bc_xprt->xpt_bc_xprt = NULL;
+       args->bc_xprt->xpt_bc_xps = NULL;
        xprt_put(xprt);
        ret = ERR_PTR(-EINVAL);
 out_err: