diff options
Diffstat (limited to 'net/sunrpc/rpcb_clnt.c')
| -rw-r--r-- | net/sunrpc/rpcb_clnt.c | 188 | 
1 files changed, 102 insertions, 86 deletions
diff --git a/net/sunrpc/rpcb_clnt.c b/net/sunrpc/rpcb_clnt.c index 8761bf8e36fc..207a74696c9f 100644 --- a/net/sunrpc/rpcb_clnt.c +++ b/net/sunrpc/rpcb_clnt.c @@ -23,12 +23,15 @@  #include <linux/errno.h>  #include <linux/mutex.h>  #include <linux/slab.h> +#include <linux/nsproxy.h>  #include <net/ipv6.h>  #include <linux/sunrpc/clnt.h>  #include <linux/sunrpc/sched.h>  #include <linux/sunrpc/xprtsock.h> +#include "netns.h" +  #ifdef RPC_DEBUG  # define RPCDBG_FACILITY	RPCDBG_BIND  #endif @@ -109,13 +112,7 @@ enum {  static void			rpcb_getport_done(struct rpc_task *, void *);  static void			rpcb_map_release(void *data); -static struct rpc_program	rpcb_program; - -static struct rpc_clnt *	rpcb_local_clnt; -static struct rpc_clnt *	rpcb_local_clnt4; - -DEFINE_SPINLOCK(rpcb_clnt_lock); -unsigned int			rpcb_users; +static const struct rpc_program	rpcb_program;  struct rpcbind_args {  	struct rpc_xprt *	r_xprt; @@ -140,8 +137,8 @@ struct rpcb_info {  	struct rpc_procinfo *	rpc_proc;  }; -static struct rpcb_info rpcb_next_version[]; -static struct rpcb_info rpcb_next_version6[]; +static const struct rpcb_info rpcb_next_version[]; +static const struct rpcb_info rpcb_next_version6[];  static const struct rpc_call_ops rpcb_getport_ops = {  	.rpc_call_done		= rpcb_getport_done, @@ -164,32 +161,34 @@ static void rpcb_map_release(void *data)  	kfree(map);  } -static int rpcb_get_local(void) +static int rpcb_get_local(struct net *net)  {  	int cnt; +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); -	spin_lock(&rpcb_clnt_lock); -	if (rpcb_users) -		rpcb_users++; -	cnt = rpcb_users; -	spin_unlock(&rpcb_clnt_lock); +	spin_lock(&sn->rpcb_clnt_lock); +	if (sn->rpcb_users) +		sn->rpcb_users++; +	cnt = sn->rpcb_users; +	spin_unlock(&sn->rpcb_clnt_lock);  	return cnt;  } -void rpcb_put_local(void) +void rpcb_put_local(struct net *net)  { -	struct rpc_clnt *clnt = rpcb_local_clnt; -	struct rpc_clnt *clnt4 = rpcb_local_clnt4; +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); +	struct rpc_clnt *clnt = sn->rpcb_local_clnt; +	struct rpc_clnt *clnt4 = sn->rpcb_local_clnt4;  	int shutdown; -	spin_lock(&rpcb_clnt_lock); -	if (--rpcb_users == 0) { -		rpcb_local_clnt = NULL; -		rpcb_local_clnt4 = NULL; +	spin_lock(&sn->rpcb_clnt_lock); +	if (--sn->rpcb_users == 0) { +		sn->rpcb_local_clnt = NULL; +		sn->rpcb_local_clnt4 = NULL;  	} -	shutdown = !rpcb_users; -	spin_unlock(&rpcb_clnt_lock); +	shutdown = !sn->rpcb_users; +	spin_unlock(&sn->rpcb_clnt_lock);  	if (shutdown) {  		/* @@ -202,30 +201,34 @@ void rpcb_put_local(void)  	}  } -static void rpcb_set_local(struct rpc_clnt *clnt, struct rpc_clnt *clnt4) +static void rpcb_set_local(struct net *net, struct rpc_clnt *clnt, +			struct rpc_clnt *clnt4)  { +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); +  	/* Protected by rpcb_create_local_mutex */ -	rpcb_local_clnt = clnt; -	rpcb_local_clnt4 = clnt4; +	sn->rpcb_local_clnt = clnt; +	sn->rpcb_local_clnt4 = clnt4;  	smp_wmb();  -	rpcb_users = 1; +	sn->rpcb_users = 1;  	dprintk("RPC:       created new rpcb local clients (rpcb_local_clnt: " -			"%p, rpcb_local_clnt4: %p)\n", rpcb_local_clnt, -			rpcb_local_clnt4); +			"%p, rpcb_local_clnt4: %p) for net %p%s\n", +			sn->rpcb_local_clnt, sn->rpcb_local_clnt4, +			net, (net == &init_net) ? " (init_net)" : "");  }  /*   * Returns zero on success, otherwise a negative errno value   * is returned.   */ -static int rpcb_create_local_unix(void) +static int rpcb_create_local_unix(struct net *net)  {  	static const struct sockaddr_un rpcb_localaddr_rpcbind = {  		.sun_family		= AF_LOCAL,  		.sun_path		= RPCBIND_SOCK_PATHNAME,  	};  	struct rpc_create_args args = { -		.net		= &init_net, +		.net		= net,  		.protocol	= XPRT_TRANSPORT_LOCAL,  		.address	= (struct sockaddr *)&rpcb_localaddr_rpcbind,  		.addrsize	= sizeof(rpcb_localaddr_rpcbind), @@ -258,7 +261,7 @@ static int rpcb_create_local_unix(void)  		clnt4 = NULL;  	} -	rpcb_set_local(clnt, clnt4); +	rpcb_set_local(net, clnt, clnt4);  out:  	return result; @@ -268,7 +271,7 @@ out:   * Returns zero on success, otherwise a negative errno value   * is returned.   */ -static int rpcb_create_local_net(void) +static int rpcb_create_local_net(struct net *net)  {  	static const struct sockaddr_in rpcb_inaddr_loopback = {  		.sin_family		= AF_INET, @@ -276,7 +279,7 @@ static int rpcb_create_local_net(void)  		.sin_port		= htons(RPCBIND_PORT),  	};  	struct rpc_create_args args = { -		.net		= &init_net, +		.net		= net,  		.protocol	= XPRT_TRANSPORT_TCP,  		.address	= (struct sockaddr *)&rpcb_inaddr_loopback,  		.addrsize	= sizeof(rpcb_inaddr_loopback), @@ -310,7 +313,7 @@ static int rpcb_create_local_net(void)  		clnt4 = NULL;  	} -	rpcb_set_local(clnt, clnt4); +	rpcb_set_local(net, clnt, clnt4);  out:  	return result; @@ -320,31 +323,32 @@ out:   * Returns zero on success, otherwise a negative errno value   * is returned.   */ -int rpcb_create_local(void) +int rpcb_create_local(struct net *net)  {  	static DEFINE_MUTEX(rpcb_create_local_mutex);  	int result = 0; -	if (rpcb_get_local()) +	if (rpcb_get_local(net))  		return result;  	mutex_lock(&rpcb_create_local_mutex); -	if (rpcb_get_local()) +	if (rpcb_get_local(net))  		goto out; -	if (rpcb_create_local_unix() != 0) -		result = rpcb_create_local_net(); +	if (rpcb_create_local_unix(net) != 0) +		result = rpcb_create_local_net(net);  out:  	mutex_unlock(&rpcb_create_local_mutex);  	return result;  } -static struct rpc_clnt *rpcb_create(char *hostname, struct sockaddr *srvaddr, -				    size_t salen, int proto, u32 version) +static struct rpc_clnt *rpcb_create(struct net *net, const char *hostname, +				    struct sockaddr *srvaddr, size_t salen, +				    int proto, u32 version)  {  	struct rpc_create_args args = { -		.net		= &init_net, +		.net		= net,  		.protocol	= proto,  		.address	= srvaddr,  		.addrsize	= salen, @@ -420,7 +424,7 @@ static int rpcb_register_call(struct rpc_clnt *clnt, struct rpc_message *msg)   * IN6ADDR_ANY (ie available for all AF_INET and AF_INET6   * addresses).   */ -int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port) +int rpcb_register(struct net *net, u32 prog, u32 vers, int prot, unsigned short port)  {  	struct rpcbind_args map = {  		.r_prog		= prog, @@ -431,6 +435,7 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)  	struct rpc_message msg = {  		.rpc_argp	= &map,  	}; +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id);  	dprintk("RPC:       %sregistering (%u, %u, %d, %u) with local "  			"rpcbind\n", (port ? "" : "un"), @@ -440,13 +445,14 @@ int rpcb_register(u32 prog, u32 vers, int prot, unsigned short port)  	if (port)  		msg.rpc_proc = &rpcb_procedures2[RPCBPROC_SET]; -	return rpcb_register_call(rpcb_local_clnt, &msg); +	return rpcb_register_call(sn->rpcb_local_clnt, &msg);  }  /*   * Fill in AF_INET family-specific arguments to register   */ -static int rpcb_register_inet4(const struct sockaddr *sap, +static int rpcb_register_inet4(struct sunrpc_net *sn, +			       const struct sockaddr *sap,  			       struct rpc_message *msg)  {  	const struct sockaddr_in *sin = (const struct sockaddr_in *)sap; @@ -465,7 +471,7 @@ static int rpcb_register_inet4(const struct sockaddr *sap,  	if (port)  		msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; -	result = rpcb_register_call(rpcb_local_clnt4, msg); +	result = rpcb_register_call(sn->rpcb_local_clnt4, msg);  	kfree(map->r_addr);  	return result;  } @@ -473,7 +479,8 @@ static int rpcb_register_inet4(const struct sockaddr *sap,  /*   * Fill in AF_INET6 family-specific arguments to register   */ -static int rpcb_register_inet6(const struct sockaddr *sap, +static int rpcb_register_inet6(struct sunrpc_net *sn, +			       const struct sockaddr *sap,  			       struct rpc_message *msg)  {  	const struct sockaddr_in6 *sin6 = (const struct sockaddr_in6 *)sap; @@ -492,12 +499,13 @@ static int rpcb_register_inet6(const struct sockaddr *sap,  	if (port)  		msg->rpc_proc = &rpcb_procedures4[RPCBPROC_SET]; -	result = rpcb_register_call(rpcb_local_clnt4, msg); +	result = rpcb_register_call(sn->rpcb_local_clnt4, msg);  	kfree(map->r_addr);  	return result;  } -static int rpcb_unregister_all_protofamilies(struct rpc_message *msg) +static int rpcb_unregister_all_protofamilies(struct sunrpc_net *sn, +					     struct rpc_message *msg)  {  	struct rpcbind_args *map = msg->rpc_argp; @@ -508,7 +516,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)  	map->r_addr = "";  	msg->rpc_proc = &rpcb_procedures4[RPCBPROC_UNSET]; -	return rpcb_register_call(rpcb_local_clnt4, msg); +	return rpcb_register_call(sn->rpcb_local_clnt4, msg);  }  /** @@ -554,7 +562,7 @@ static int rpcb_unregister_all_protofamilies(struct rpc_message *msg)   * service on any IPv4 address, but not on IPv6.  The latter   * advertises the service on all IPv4 and IPv6 addresses.   */ -int rpcb_v4_register(const u32 program, const u32 version, +int rpcb_v4_register(struct net *net, const u32 program, const u32 version,  		     const struct sockaddr *address, const char *netid)  {  	struct rpcbind_args map = { @@ -566,18 +574,19 @@ int rpcb_v4_register(const u32 program, const u32 version,  	struct rpc_message msg = {  		.rpc_argp	= &map,  	}; +	struct sunrpc_net *sn = net_generic(net, sunrpc_net_id); -	if (rpcb_local_clnt4 == NULL) +	if (sn->rpcb_local_clnt4 == NULL)  		return -EPROTONOSUPPORT;  	if (address == NULL) -		return rpcb_unregister_all_protofamilies(&msg); +		return rpcb_unregister_all_protofamilies(sn, &msg);  	switch (address->sa_family) {  	case AF_INET: -		return rpcb_register_inet4(address, &msg); +		return rpcb_register_inet4(sn, address, &msg);  	case AF_INET6: -		return rpcb_register_inet6(address, &msg); +		return rpcb_register_inet6(sn, address, &msg);  	}  	return -EAFNOSUPPORT; @@ -611,9 +620,10 @@ static struct rpc_task *rpcb_call_async(struct rpc_clnt *rpcb_clnt, struct rpcbi  static struct rpc_clnt *rpcb_find_transport_owner(struct rpc_clnt *clnt)  {  	struct rpc_clnt *parent = clnt->cl_parent; +	struct rpc_xprt *xprt = rcu_dereference(clnt->cl_xprt);  	while (parent != clnt) { -		if (parent->cl_xprt != clnt->cl_xprt) +		if (rcu_dereference(parent->cl_xprt) != xprt)  			break;  		if (clnt->cl_autobind)  			break; @@ -644,12 +654,16 @@ void rpcb_getport_async(struct rpc_task *task)  	size_t salen;  	int status; -	clnt = rpcb_find_transport_owner(task->tk_client); -	xprt = clnt->cl_xprt; +	rcu_read_lock(); +	do { +		clnt = rpcb_find_transport_owner(task->tk_client); +		xprt = xprt_get(rcu_dereference(clnt->cl_xprt)); +	} while (xprt == NULL); +	rcu_read_unlock();  	dprintk("RPC: %5u %s(%s, %u, %u, %d)\n",  		task->tk_pid, __func__, -		clnt->cl_server, clnt->cl_prog, clnt->cl_vers, xprt->prot); +		xprt->servername, clnt->cl_prog, clnt->cl_vers, xprt->prot);  	/* Put self on the wait queue to ensure we get notified if  	 * some other task is already attempting to bind the port */ @@ -658,6 +672,7 @@ void rpcb_getport_async(struct rpc_task *task)  	if (xprt_test_and_set_binding(xprt)) {  		dprintk("RPC: %5u %s: waiting for another binder\n",  			task->tk_pid, __func__); +		xprt_put(xprt);  		return;  	} @@ -699,8 +714,8 @@ void rpcb_getport_async(struct rpc_task *task)  	dprintk("RPC: %5u %s: trying rpcbind version %u\n",  		task->tk_pid, __func__, bind_version); -	rpcb_clnt = rpcb_create(clnt->cl_server, sap, salen, xprt->prot, -				bind_version); +	rpcb_clnt = rpcb_create(xprt->xprt_net, xprt->servername, sap, salen, +				xprt->prot, bind_version);  	if (IS_ERR(rpcb_clnt)) {  		status = PTR_ERR(rpcb_clnt);  		dprintk("RPC: %5u %s: rpcb_create failed, error %ld\n", @@ -725,7 +740,7 @@ void rpcb_getport_async(struct rpc_task *task)  	switch (bind_version) {  	case RPCBVERS_4:  	case RPCBVERS_3: -		map->r_netid = rpc_peeraddr2str(clnt, RPC_DISPLAY_NETID); +		map->r_netid = xprt->address_strings[RPC_DISPLAY_NETID];  		map->r_addr = rpc_sockaddr2uaddr(sap, GFP_ATOMIC);  		map->r_owner = "";  		break; @@ -754,6 +769,7 @@ bailout_release_client:  bailout_nofree:  	rpcb_wake_rpcbind_waiters(xprt, status);  	task->tk_status = status; +	xprt_put(xprt);  }  EXPORT_SYMBOL_GPL(rpcb_getport_async); @@ -801,11 +817,11 @@ static void rpcb_getport_done(struct rpc_task *child, void *data)  static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,  			     const struct rpcbind_args *rpcb)  { -	struct rpc_task *task = req->rq_task;  	__be32 *p;  	dprintk("RPC: %5u encoding PMAP_%s call (%u, %u, %d, %u)\n", -			task->tk_pid, task->tk_msg.rpc_proc->p_name, +			req->rq_task->tk_pid, +			req->rq_task->tk_msg.rpc_proc->p_name,  			rpcb->r_prog, rpcb->r_vers, rpcb->r_prot, rpcb->r_port);  	p = xdr_reserve_space(xdr, RPCB_mappingargs_sz << 2); @@ -818,7 +834,6 @@ static void rpcb_enc_mapping(struct rpc_rqst *req, struct xdr_stream *xdr,  static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,  			    struct rpcbind_args *rpcb)  { -	struct rpc_task *task = req->rq_task;  	unsigned long port;  	__be32 *p; @@ -829,8 +844,8 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,  		return -EIO;  	port = be32_to_cpup(p); -	dprintk("RPC: %5u PMAP_%s result: %lu\n", task->tk_pid, -			task->tk_msg.rpc_proc->p_name, port); +	dprintk("RPC: %5u PMAP_%s result: %lu\n", req->rq_task->tk_pid, +			req->rq_task->tk_msg.rpc_proc->p_name, port);  	if (unlikely(port > USHRT_MAX))  		return -EIO; @@ -841,7 +856,6 @@ static int rpcb_dec_getport(struct rpc_rqst *req, struct xdr_stream *xdr,  static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr,  			unsigned int *boolp)  { -	struct rpc_task *task = req->rq_task;  	__be32 *p;  	p = xdr_inline_decode(xdr, 4); @@ -853,7 +867,8 @@ static int rpcb_dec_set(struct rpc_rqst *req, struct xdr_stream *xdr,  		*boolp = 1;  	dprintk("RPC: %5u RPCB_%s call %s\n", -			task->tk_pid, task->tk_msg.rpc_proc->p_name, +			req->rq_task->tk_pid, +			req->rq_task->tk_msg.rpc_proc->p_name,  			(*boolp ? "succeeded" : "failed"));  	return 0;  } @@ -873,11 +888,11 @@ static void encode_rpcb_string(struct xdr_stream *xdr, const char *string,  static void rpcb_enc_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,  			     const struct rpcbind_args *rpcb)  { -	struct rpc_task *task = req->rq_task;  	__be32 *p;  	dprintk("RPC: %5u encoding RPCB_%s call (%u, %u, '%s', '%s')\n", -			task->tk_pid, task->tk_msg.rpc_proc->p_name, +			req->rq_task->tk_pid, +			req->rq_task->tk_msg.rpc_proc->p_name,  			rpcb->r_prog, rpcb->r_vers,  			rpcb->r_netid, rpcb->r_addr); @@ -895,7 +910,6 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,  {  	struct sockaddr_storage address;  	struct sockaddr *sap = (struct sockaddr *)&address; -	struct rpc_task *task = req->rq_task;  	__be32 *p;  	u32 len; @@ -912,7 +926,7 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,  	 */  	if (len == 0) {  		dprintk("RPC: %5u RPCB reply: program not registered\n", -				task->tk_pid); +				req->rq_task->tk_pid);  		return 0;  	} @@ -922,10 +936,11 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,  	p = xdr_inline_decode(xdr, len);  	if (unlikely(p == NULL))  		goto out_fail; -	dprintk("RPC: %5u RPCB_%s reply: %s\n", task->tk_pid, -			task->tk_msg.rpc_proc->p_name, (char *)p); +	dprintk("RPC: %5u RPCB_%s reply: %s\n", req->rq_task->tk_pid, +			req->rq_task->tk_msg.rpc_proc->p_name, (char *)p); -	if (rpc_uaddr2sockaddr((char *)p, len, sap, sizeof(address)) == 0) +	if (rpc_uaddr2sockaddr(req->rq_xprt->xprt_net, (char *)p, len, +				sap, sizeof(address)) == 0)  		goto out_fail;  	rpcb->r_port = rpc_get_port(sap); @@ -933,7 +948,8 @@ static int rpcb_dec_getaddr(struct rpc_rqst *req, struct xdr_stream *xdr,  out_fail:  	dprintk("RPC: %5u malformed RPCB_%s reply\n", -			task->tk_pid, task->tk_msg.rpc_proc->p_name); +			req->rq_task->tk_pid, +			req->rq_task->tk_msg.rpc_proc->p_name);  	return -EIO;  } @@ -1041,7 +1057,7 @@ static struct rpc_procinfo rpcb_procedures4[] = {  	},  }; -static struct rpcb_info rpcb_next_version[] = { +static const struct rpcb_info rpcb_next_version[] = {  	{  		.rpc_vers	= RPCBVERS_2,  		.rpc_proc	= &rpcb_procedures2[RPCBPROC_GETPORT], @@ -1051,7 +1067,7 @@ static struct rpcb_info rpcb_next_version[] = {  	},  }; -static struct rpcb_info rpcb_next_version6[] = { +static const struct rpcb_info rpcb_next_version6[] = {  	{  		.rpc_vers	= RPCBVERS_4,  		.rpc_proc	= &rpcb_procedures4[RPCBPROC_GETADDR], @@ -1065,25 +1081,25 @@ static struct rpcb_info rpcb_next_version6[] = {  	},  }; -static struct rpc_version rpcb_version2 = { +static const struct rpc_version rpcb_version2 = {  	.number		= RPCBVERS_2,  	.nrprocs	= ARRAY_SIZE(rpcb_procedures2),  	.procs		= rpcb_procedures2  }; -static struct rpc_version rpcb_version3 = { +static const struct rpc_version rpcb_version3 = {  	.number		= RPCBVERS_3,  	.nrprocs	= ARRAY_SIZE(rpcb_procedures3),  	.procs		= rpcb_procedures3  }; -static struct rpc_version rpcb_version4 = { +static const struct rpc_version rpcb_version4 = {  	.number		= RPCBVERS_4,  	.nrprocs	= ARRAY_SIZE(rpcb_procedures4),  	.procs		= rpcb_procedures4  }; -static struct rpc_version *rpcb_version[] = { +static const struct rpc_version *rpcb_version[] = {  	NULL,  	NULL,  	&rpcb_version2, @@ -1093,7 +1109,7 @@ static struct rpc_version *rpcb_version[] = {  static struct rpc_stat rpcb_stats; -static struct rpc_program rpcb_program = { +static const struct rpc_program rpcb_program = {  	.name		= "rpcbind",  	.number		= RPCBIND_PROGRAM,  	.nrvers		= ARRAY_SIZE(rpcb_version),  | 
