SUNRPC: Create a helper to tell whether a transport is bound
authorChuck Lever <chuck.lever@oracle.com>
Wed, 23 Aug 2006 00:06:15 +0000 (20:06 -0400)
committerTrond Myklebust <Trond.Myklebust@netapp.com>
Sat, 23 Sep 2006 03:24:39 +0000 (23:24 -0400)
Hide the contents and format of xprt->addr by eliminating direct uses
of the xprt->addr.sin_port field.  This change is required to support
alternate RPC host address formats (eg IPv6).

Test-plan:
Destructive testing (unplugging the network temporarily).  Repeated runs of
Connectathon locking suite with UDP and TCP.

Signed-off-by: Chuck Lever <chuck.lever@oracle.com>
Signed-off-by: Trond Myklebust <Trond.Myklebust@netapp.com>
include/linux/sunrpc/xprt.h
net/sunrpc/clnt.c
net/sunrpc/pmap_clnt.c
net/sunrpc/xprt.c
net/sunrpc/xprtsock.c

index 3a0cca255b76ee6b1b7ba674c9e52d35bb0e3a9b..a71106723d7196a2099a42905bbea955eac9799d 100644 (file)
@@ -269,6 +269,7 @@ int                 xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to);
 #define XPRT_CONNECTED         (1)
 #define XPRT_CONNECTING                (2)
 #define XPRT_CLOSE_WAIT                (3)
+#define XPRT_BOUND             (4)
 
 static inline void xprt_set_connected(struct rpc_xprt *xprt)
 {
@@ -312,6 +313,21 @@ static inline int xprt_test_and_set_connecting(struct rpc_xprt *xprt)
        return test_and_set_bit(XPRT_CONNECTING, &xprt->state);
 }
 
+static inline void xprt_set_bound(struct rpc_xprt *xprt)
+{
+       test_and_set_bit(XPRT_BOUND, &xprt->state);
+}
+
+static inline int xprt_bound(struct rpc_xprt *xprt)
+{
+       return test_bit(XPRT_BOUND, &xprt->state);
+}
+
+static inline void xprt_clear_bound(struct rpc_xprt *xprt)
+{
+       clear_bit(XPRT_BOUND, &xprt->state);
+}
+
 #endif /* __KERNEL__*/
 
 #endif /* _LINUX_SUNRPC_XPRT_H */
index 3e19d321067a9ce16db7aa37f65449638e2aba32..0b8d03d0856112541e15bd5851f708363869035b 100644 (file)
@@ -148,7 +148,6 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
        clnt->cl_maxproc  = version->nrprocs;
        clnt->cl_protname = program->name;
        clnt->cl_pmap     = &clnt->cl_pmap_default;
-       clnt->cl_port     = xprt->addr.sin_port;
        clnt->cl_prog     = program->number;
        clnt->cl_vers     = version->number;
        clnt->cl_prot     = xprt->prot;
@@ -156,7 +155,7 @@ rpc_new_client(struct rpc_xprt *xprt, char *servname,
        clnt->cl_metrics  = rpc_alloc_iostats(clnt);
        rpc_init_wait_queue(&clnt->cl_pmap_default.pm_bindwait, "bindwait");
 
-       if (!clnt->cl_port)
+       if (!xprt_bound(clnt->cl_xprt))
                clnt->cl_autobind = 1;
 
        clnt->cl_rtt = &clnt->cl_rtt_default;
@@ -570,7 +569,7 @@ EXPORT_SYMBOL(rpc_max_payload);
 void rpc_force_rebind(struct rpc_clnt *clnt)
 {
        if (clnt->cl_autobind)
-               clnt->cl_port = 0;
+               xprt_clear_bound(clnt->cl_xprt);
 }
 EXPORT_SYMBOL(rpc_force_rebind);
 
@@ -782,14 +781,15 @@ static void
 call_bind(struct rpc_task *task)
 {
        struct rpc_clnt *clnt = task->tk_client;
+       struct rpc_xprt *xprt = task->tk_xprt;
 
        dprintk("RPC: %4d call_bind (status %d)\n",
                                task->tk_pid, task->tk_status);
 
        task->tk_action = call_connect;
-       if (!clnt->cl_port) {
+       if (!xprt_bound(xprt)) {
                task->tk_action = call_bind_status;
-               task->tk_timeout = task->tk_xprt->bind_timeout;
+               task->tk_timeout = xprt->bind_timeout;
                rpc_getport(task, clnt);
        }
 }
index 623180f224c97990a0389299014520fc5f5412ca..209ffdfee10be93b52ae49569bd4ccd081da38e0 100644 (file)
@@ -142,15 +142,17 @@ pmap_getport_done(struct rpc_task *task)
        dprintk("RPC: %4d pmap_getport_done(status %d, port %d)\n",
                        task->tk_pid, task->tk_status, clnt->cl_port);
 
-       xprt->ops->set_port(xprt, 0);
        if (task->tk_status < 0) {
                /* Make the calling task exit with an error */
+               xprt->ops->set_port(xprt, 0);
                task->tk_action = rpc_exit_task;
        } else if (clnt->cl_port == 0) {
                /* Program not registered */
+               xprt->ops->set_port(xprt, 0);
                rpc_exit(task, -EACCES);
        } else {
                xprt->ops->set_port(xprt, clnt->cl_port);
+               xprt_set_bound(xprt);
                clnt->cl_port = htons(clnt->cl_port);
        }
        spin_lock(&pmap_lock);
@@ -218,6 +220,7 @@ pmap_create(char *hostname, struct sockaddr_in *srvaddr, int proto, int privileg
        if (IS_ERR(xprt))
                return (struct rpc_clnt *)xprt;
        xprt->ops->set_port(xprt, RPC_PMAP_PORT);
+       xprt_set_bound(xprt);
        if (!privileged)
                xprt->resvport = 0;
 
index e8c2bc4977f3a41dbfbd6c3a85a4c15b6a14e6eb..e239ef985ef743c6a906e7315d342230b0842b8c 100644 (file)
@@ -534,7 +534,7 @@ void xprt_connect(struct rpc_task *task)
        dprintk("RPC: %4d xprt_connect xprt %p %s connected\n", task->tk_pid,
                        xprt, (xprt_connected(xprt) ? "is" : "is not"));
 
-       if (!xprt->addr.sin_port) {
+       if (!xprt_bound(xprt)) {
                task->tk_status = -EIO;
                return;
        }
index 441bd53f5eca81fbb8d4bb495f5c72bfac1aebb0..123ac1e5ba15a0b0f2a2be776db33b3fc2e42178 100644 (file)
@@ -1016,7 +1016,7 @@ static void xs_udp_connect_worker(void *args)
        struct socket *sock = xprt->sock;
        int err, status = -EIO;
 
-       if (xprt->shutdown || xprt->addr.sin_port == 0)
+       if (xprt->shutdown || !xprt_bound(xprt))
                goto out;
 
        dprintk("RPC:      xs_udp_connect_worker for xprt %p\n", xprt);
@@ -1099,7 +1099,7 @@ static void xs_tcp_connect_worker(void *args)
        struct socket *sock = xprt->sock;
        int err, status = -EIO;
 
-       if (xprt->shutdown || xprt->addr.sin_port == 0)
+       if (xprt->shutdown || !xprt_bound(xprt))
                goto out;
 
        dprintk("RPC:      xs_tcp_connect_worker for xprt %p\n", xprt);
@@ -1307,8 +1307,11 @@ int xs_setup_udp(struct rpc_xprt *xprt, struct rpc_timeout *to)
        if (xprt->slot == NULL)
                return -ENOMEM;
 
-       xprt->prot = IPPROTO_UDP;
+       if (ntohs(xprt->addr.sin_port) != 0)
+               xprt_set_bound(xprt);
        xprt->port = xs_get_random_port();
+
+       xprt->prot = IPPROTO_UDP;
        xprt->tsh_size = 0;
        xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
        /* XXX: header size can vary due to auth type, IPv6, etc. */
@@ -1348,8 +1351,11 @@ int xs_setup_tcp(struct rpc_xprt *xprt, struct rpc_timeout *to)
        if (xprt->slot == NULL)
                return -ENOMEM;
 
-       xprt->prot = IPPROTO_TCP;
+       if (ntohs(xprt->addr.sin_port) != 0)
+               xprt_set_bound(xprt);
        xprt->port = xs_get_random_port();
+
+       xprt->prot = IPPROTO_TCP;
        xprt->tsh_size = sizeof(rpc_fraghdr) / sizeof(u32);
        xprt->resvport = capable(CAP_NET_BIND_SERVICE) ? 1 : 0;
        xprt->max_payload = RPC_MAX_FRAGMENT_SIZE;