Merge branch 'for-2.6.38' of git://linux-nfs.org/~bfields/linux
[pandora-kernel.git] / net / sunrpc / xprtsock.c
index 96549df..c431f5a 100644 (file)
@@ -2359,6 +2359,15 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
        struct svc_sock *bc_sock;
        struct rpc_xprt *ret;
 
+       if (args->bc_xprt->xpt_bc_xprt) {
+               /*
+                * This server connection already has a backchannel
+                * export; we can't create a new one, as we wouldn't be
+                * able to match replies based on xid any more.  So,
+                * reuse the already-existing one:
+                */
+                return args->bc_xprt->xpt_bc_xprt;
+       }
        xprt = xs_setup_xprt(args, xprt_tcp_slot_table_entries);
        if (IS_ERR(xprt))
                return xprt;
@@ -2375,16 +2384,6 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
        xprt->reestablish_timeout = 0;
        xprt->idle_timeout = 0;
 
-       /*
-        * The backchannel uses the same socket connection as the
-        * forechannel
-        */
-       xprt->bc_xprt = args->bc_xprt;
-       bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
-       bc_sock->sk_bc_xprt = xprt;
-       transport->sock = bc_sock->sk_sock;
-       transport->inet = bc_sock->sk_sk;
-
        xprt->ops = &bc_tcp_ops;
 
        switch (addr->sa_family) {
@@ -2406,6 +2405,20 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
                        xprt->address_strings[RPC_DISPLAY_PORT],
                        xprt->address_strings[RPC_DISPLAY_PROTO]);
 
+       /*
+        * Once we've associated a backchannel xprt with a connection,
+        * we want to keep it around as long as long as the connection
+        * lasts, in case we need to start using it for a backchannel
+        * again; this reference won't be dropped until bc_xprt is
+        * destroyed.
+        */
+       xprt_get(xprt);
+       args->bc_xprt->xpt_bc_xprt = xprt;
+       xprt->bc_xprt = args->bc_xprt;
+       bc_sock = container_of(args->bc_xprt, struct svc_sock, sk_xprt);
+       transport->sock = bc_sock->sk_sock;
+       transport->inet = bc_sock->sk_sk;
+
        /*
         * Since we don't want connections for the backchannel, we set
         * the xprt status to connected
@@ -2415,6 +2428,7 @@ static struct rpc_xprt *xs_setup_bc_tcp(struct xprt_create *args)
 
        if (try_module_get(THIS_MODULE))
                return xprt;
+       xprt_put(xprt);
        ret = ERR_PTR(-EINVAL);
 out_err:
        xprt_free(xprt);