]> rtime.felk.cvut.cz Git - linux-imx.git/blobdiff - net/sunrpc/rpcb_clnt.c
Merge tag 'nfs-for-3.11-4' of git://git.linux-nfs.org/projects/trondmy/linux-nfs
[linux-imx.git] / net / sunrpc / rpcb_clnt.c
index 3df764dc330cbdb398e7dbbd5c6558d894bfc386..1891a1022c17e9d7d4c1686ff30c2ef13ebbf7b8 100644 (file)
@@ -204,13 +204,15 @@ void rpcb_put_local(struct net *net)
 }
 
 static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt,
-                       struct rpc_clnt *clnt4)
+                       struct rpc_clnt *clnt4,
+                       bool is_af_local)
 {
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
 
        /* Protected by rpcb_create_local_mutex */
        sn->rpcb_local_clnt = clnt;
        sn->rpcb_local_clnt4 = clnt4;
+       sn->rpcb_is_af_local = is_af_local ? 1 : 0;
        smp_wmb(); 
        sn->rpcb_users = 1;
        dprintk("RPC:       created new rpcb local clients (rpcb_local_clnt: "
@@ -238,6 +240,14 @@ static int rpcb_create_local_unix(struct net *net)
                .program        = &rpcb_program,
                .version        = RPCBVERS_2,
                .authflavor     = RPC_AUTH_NULL,
+               /*
+                * We turn off the idle timeout to prevent the kernel
+                * from automatically disconnecting the socket.
+                * Otherwise, we'd have to cache the mount namespace
+                * of the caller and somehow pass that to the socket
+                * reconnect code.
+                */
+               .flags          = RPC_CLNT_CREATE_NO_IDLE_TIMEOUT,
        };
        struct rpc_clnt *clnt, *clnt4;
        int result = 0;
@@ -263,7 +273,7 @@ static int rpcb_create_local_unix(struct net *net)
                clnt4 = NULL;
        }
 
-       rpcb_set_local(net, clnt, clnt4);
+       rpcb_set_local(net, clnt, clnt4, true);
 
 out:
        return result;
@@ -315,7 +325,7 @@ static int rpcb_create_local_net(struct net *net)
                clnt4 = NULL;
        }
 
-       rpcb_set_local(net, clnt, clnt4);
+       rpcb_set_local(net, clnt, clnt4, false);
 
 out:
        return result;
@@ -376,13 +386,16 @@ static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname,
        return rpc_create(&args);
 }
 
-static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg)
+static int rpcb_register_call(struct sunrpc_net *sn, struct rpc_clnt *clnt, struct rpc_message *msg, bool is_set)
 {
-       int result, error = 0;
+       int flags = RPC_TASK_NOCONNECT;
+       int error, result = 0;
 
+       if (is_set || !sn->rpcb_is_af_local)
+               flags = RPC_TASK_SOFTCONN;
        msg->rpc_resp = &result;
 
-       error = rpc_call_sync(clnt, msg, RPC_TASK_SOFTCONN);
+       error = rpc_call_sync(clnt, msg, flags);
        if (error < 0) {
                dprintk("RPC:       failed to contact local rpcbind "
                                "server (errno %d).\n", -error);
@@ -439,16 +452,19 @@ int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short
                .rpc_argp       = &map,
        };
        struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);
+       bool is_set = false;
 
        dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "
                        "rpcbind\n", (port ? "" : "un"),
                        prog, vers, prot, port);
 
        msg.rpc_proc = &rpcb_procedures2[RPCBPROC_UNSET];
-       if (port)
+       if (port != 0) {
                msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET];
+               is_set = true;
+       }
 
-       return rpcb_register_call(sn->rpcb_local_clnt, &msg);
+       return rpcb_register_call(sn, sn->rpcb_local_clnt, &msg, is_set);
 }
 
 /*
@@ -461,6 +477,7 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
        const struct sockaddr_in *sin = (const struct sockaddr_in *)sap;
        struct rpcbind_args *map = msg->rpc_argp;
        unsigned short port = ntohs(sin->sin_port);
+       bool is_set = false;
        int result;
 
        map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
@@ -471,10 +488,12 @@ static int rpcb_register_inet4(struct sunrpc_net *sn,
                        map->r_addr, map->r_netid);
 
        msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
-       if (port)
+       if (port != 0) {
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
+               is_set = true;
+       }
 
-       result = rpcb_register_call(sn->rpcb_local_clnt4, msg);
+       result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
        kfree(map->r_addr);
        return result;
 }
@@ -489,6 +508,7 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
        const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap;
        struct rpcbind_args *map = msg->rpc_argp;
        unsigned short port = ntohs(sin6->sin6_port);
+       bool is_set = false;
        int result;
 
        map->r_addr = rpc_sockaddr2uaddr(sap, GFP_KERNEL);
@@ -499,10 +519,12 @@ static int rpcb_register_inet6(struct sunrpc_net *sn,
                        map->r_addr, map->r_netid);
 
        msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
-       if (port)
+       if (port != 0) {
                msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET];
+               is_set = true;
+       }
 
-       result = rpcb_register_call(sn->rpcb_local_clnt4, msg);
+       result = rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, is_set);
        kfree(map->r_addr);
        return result;
 }
@@ -519,7 +541,7 @@ static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn,
        map->r_addr = "";
        msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET];
 
-       return rpcb_register_call(sn->rpcb_local_clnt4, msg);
+       return rpcb_register_call(sn, sn->rpcb_local_clnt4, msg, false);
 }
 
 /**