Commit ec739ef0 authored by Chuck Lever's avatar Chuck Lever Committed by Trond Myklebust
Browse files

SUNRPC: Create a helper to tell whether a transport is bound



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: default avatarChuck Lever <chuck.lever@oracle.com>
Signed-off-by: default avatarTrond Myklebust <Trond.Myklebust@netapp.com>
parent 9c5bf38d
Loading
Loading
Loading
Loading
+16 −0
Original line number Diff line number Diff line
@@ -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 */
+5 −5
Original line number Diff line number Diff line
@@ -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);
	}
}
+4 −1
Original line number Diff line number Diff line
@@ -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;

+1 −1
Original line number Diff line number Diff line
@@ -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;
	}
+10 −4
Original line number Diff line number Diff line
@@ -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;