diff options
Diffstat (limited to 'fs/lockd/mon.c')
| -rw-r--r-- | fs/lockd/mon.c | 216 | 
1 files changed, 124 insertions, 92 deletions
diff --git a/fs/lockd/mon.c b/fs/lockd/mon.c index e0c91894964..1812f026960 100644 --- a/fs/lockd/mon.c +++ b/fs/lockd/mon.c @@ -7,18 +7,20 @@   */  #include <linux/types.h> -#include <linux/utsname.h>  #include <linux/kernel.h>  #include <linux/ktime.h>  #include <linux/slab.h>  #include <linux/sunrpc/clnt.h> +#include <linux/sunrpc/addr.h>  #include <linux/sunrpc/xprtsock.h>  #include <linux/sunrpc/svc.h>  #include <linux/lockd/lockd.h>  #include <asm/unaligned.h> +#include "netns.h" +  #define NLMDBG_FACILITY		NLMDBG_MONITOR  #define NSM_PROGRAM		100024  #define NSM_VERSION		1 @@ -40,6 +42,7 @@ struct nsm_args {  	u32			proc;  	char			*mon_name; +	char			*nodename;  };  struct nsm_res { @@ -47,7 +50,7 @@ struct nsm_res {  	u32			state;  }; -static struct rpc_program	nsm_program; +static const struct rpc_program	nsm_program;  static				LIST_HEAD(nsm_handles);  static				DEFINE_SPINLOCK(nsm_lock); @@ -55,22 +58,22 @@ static				DEFINE_SPINLOCK(nsm_lock);   * Local NSM state   */  u32	__read_mostly		nsm_local_state; -int	__read_mostly		nsm_use_hostnames; +bool	__read_mostly		nsm_use_hostnames;  static inline struct sockaddr *nsm_addr(const struct nsm_handle *nsm)  {  	return (struct sockaddr *)&nsm->sm_addr;  } -static struct rpc_clnt *nsm_create(void) +static struct rpc_clnt *nsm_create(struct net *net)  {  	struct sockaddr_in sin = {  		.sin_family		= AF_INET,  		.sin_addr.s_addr	= htonl(INADDR_LOOPBACK),  	};  	struct rpc_create_args args = { -		.net			= &init_net, -		.protocol		= XPRT_TRANSPORT_UDP, +		.net			= net, +		.protocol		= XPRT_TRANSPORT_TCP,  		.address		= (struct sockaddr *)&sin,  		.addrsize		= sizeof(sin),  		.servername		= "rpc.statd", @@ -83,9 +86,61 @@ static struct rpc_clnt *nsm_create(void)  	return rpc_create(&args);  } -static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res) +static struct rpc_clnt *nsm_client_set(struct lockd_net *ln, +		struct rpc_clnt *clnt) +{ +	spin_lock(&ln->nsm_clnt_lock); +	if (ln->nsm_users == 0) { +		if (clnt == NULL) +			goto out; +		ln->nsm_clnt = clnt; +	} +	clnt = ln->nsm_clnt; +	ln->nsm_users++; +out: +	spin_unlock(&ln->nsm_clnt_lock); +	return clnt; +} + +static struct rpc_clnt *nsm_client_get(struct net *net) +{ +	struct rpc_clnt	*clnt, *new; +	struct lockd_net *ln = net_generic(net, lockd_net_id); + +	clnt = nsm_client_set(ln, NULL); +	if (clnt != NULL) +		goto out; + +	clnt = new = nsm_create(net); +	if (IS_ERR(clnt)) +		goto out; + +	clnt = nsm_client_set(ln, new); +	if (clnt != new) +		rpc_shutdown_client(new); +out: +	return clnt; +} + +static void nsm_client_put(struct net *net) +{ +	struct lockd_net *ln = net_generic(net, lockd_net_id); +	struct rpc_clnt	*clnt = NULL; + +	spin_lock(&ln->nsm_clnt_lock); +	ln->nsm_users--; +	if (ln->nsm_users == 0) { +		clnt = ln->nsm_clnt; +		ln->nsm_clnt = NULL; +	} +	spin_unlock(&ln->nsm_clnt_lock); +	if (clnt != NULL) +		rpc_shutdown_client(clnt); +} + +static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res, +			 struct rpc_clnt *clnt)  { -	struct rpc_clnt	*clnt;  	int		status;  	struct nsm_args args = {  		.priv		= &nsm->sm_priv, @@ -93,31 +148,22 @@ static int nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)  		.vers		= 3,  		.proc		= NLMPROC_NSM_NOTIFY,  		.mon_name	= nsm->sm_mon_name, +		.nodename	= clnt->cl_nodename,  	};  	struct rpc_message msg = {  		.rpc_argp	= &args,  		.rpc_resp	= res,  	}; -	clnt = nsm_create(); -	if (IS_ERR(clnt)) { -		status = PTR_ERR(clnt); -		dprintk("lockd: failed to create NSM upcall transport, " -				"status=%d\n", status); -		goto out; -	} -  	memset(res, 0, sizeof(*res));  	msg.rpc_proc = &clnt->cl_procinfo[proc]; -	status = rpc_call_sync(clnt, &msg, 0); +	status = rpc_call_sync(clnt, &msg, RPC_TASK_SOFTCONN);  	if (status < 0)  		dprintk("lockd: NSM upcall RPC failed, status=%d\n",  				status);  	else  		status = 0; -	rpc_shutdown_client(clnt); - out:  	return status;  } @@ -137,6 +183,7 @@ int nsm_monitor(const struct nlm_host *host)  	struct nsm_handle *nsm = host->h_nsmhandle;  	struct nsm_res	res;  	int		status; +	struct rpc_clnt *clnt;  	dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name); @@ -149,7 +196,15 @@ int nsm_monitor(const struct nlm_host *host)  	 */  	nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf; -	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res); +	clnt = nsm_client_get(host->net); +	if (IS_ERR(clnt)) { +		status = PTR_ERR(clnt); +		dprintk("lockd: failed to create NSM upcall transport, " +				"status=%d, net=%p\n", status, host->net); +		return status; +	} + +	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res, clnt);  	if (unlikely(res.status != 0))  		status = -EIO;  	if (unlikely(status < 0)) { @@ -181,9 +236,11 @@ void nsm_unmonitor(const struct nlm_host *host)  	if (atomic_read(&nsm->sm_count) == 1  	 && nsm->sm_monitored && !nsm->sm_sticky) { +		struct lockd_net *ln = net_generic(host->net, lockd_net_id); +  		dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name); -		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res); +		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res, ln->nsm_clnt);  		if (res.status != 0)  			status = -EIO;  		if (status < 0) @@ -191,6 +248,8 @@ void nsm_unmonitor(const struct nlm_host *host)  					nsm->sm_name);  		else  			nsm->sm_monitored = 0; + +		nsm_client_put(host->net);  	}  } @@ -401,26 +460,21 @@ void nsm_release(struct nsm_handle *nsm)   * Status Monitor wire protocol.   */ -static int encode_nsm_string(struct xdr_stream *xdr, const char *string) +static void encode_nsm_string(struct xdr_stream *xdr, const char *string)  {  	const u32 len = strlen(string);  	__be32 *p; -	if (unlikely(len > SM_MAXSTRLEN)) -		return -EIO; -	p = xdr_reserve_space(xdr, sizeof(u32) + len); -	if (unlikely(p == NULL)) -		return -EIO; +	p = xdr_reserve_space(xdr, 4 + len);  	xdr_encode_opaque(p, string, len); -	return 0;  }  /*   * "mon_name" specifies the host to be monitored.   */ -static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp) +static void encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp)  { -	return encode_nsm_string(xdr, argp->mon_name); +	encode_nsm_string(xdr, argp->mon_name);  }  /* @@ -429,35 +483,25 @@ static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp)   * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name"   * has changed.   */ -static int encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp) +static void encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp)  { -	int status;  	__be32 *p; -	status = encode_nsm_string(xdr, utsname()->nodename); -	if (unlikely(status != 0)) -		return status; -	p = xdr_reserve_space(xdr, 3 * sizeof(u32)); -	if (unlikely(p == NULL)) -		return -EIO; -	*p++ = htonl(argp->prog); -	*p++ = htonl(argp->vers); -	*p++ = htonl(argp->proc); -	return 0; +	encode_nsm_string(xdr, argp->nodename); +	p = xdr_reserve_space(xdr, 4 + 4 + 4); +	*p++ = cpu_to_be32(argp->prog); +	*p++ = cpu_to_be32(argp->vers); +	*p = cpu_to_be32(argp->proc);  }  /*   * The "mon_id" argument specifies the non-private arguments   * of an NSMPROC_MON or NSMPROC_UNMON call.   */ -static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp) +static void encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp)  { -	int status; - -	status = encode_mon_name(xdr, argp); -	if (unlikely(status != 0)) -		return status; -	return encode_my_id(xdr, argp); +	encode_mon_name(xdr, argp); +	encode_my_id(xdr, argp);  }  /* @@ -465,68 +509,56 @@ static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp)   * by the NSMPROC_MON call. This information will be supplied in the   * NLMPROC_SM_NOTIFY call.   */ -static int encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp) +static void encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp)  {  	__be32 *p;  	p = xdr_reserve_space(xdr, SM_PRIV_SIZE); -	if (unlikely(p == NULL)) -		return -EIO;  	xdr_encode_opaque_fixed(p, argp->priv->data, SM_PRIV_SIZE); -	return 0;  } -static int xdr_enc_mon(struct rpc_rqst *req, __be32 *p, -		       const struct nsm_args *argp) +static void nsm_xdr_enc_mon(struct rpc_rqst *req, struct xdr_stream *xdr, +			    const struct nsm_args *argp)  { -	struct xdr_stream xdr; -	int status; - -	xdr_init_encode(&xdr, &req->rq_snd_buf, p); -	status = encode_mon_id(&xdr, argp); -	if (unlikely(status)) -		return status; -	return encode_priv(&xdr, argp); +	encode_mon_id(xdr, argp); +	encode_priv(xdr, argp);  } -static int xdr_enc_unmon(struct rpc_rqst *req, __be32 *p, -			 const struct nsm_args *argp) +static void nsm_xdr_enc_unmon(struct rpc_rqst *req, struct xdr_stream *xdr, +			      const struct nsm_args *argp)  { -	struct xdr_stream xdr; - -	xdr_init_encode(&xdr, &req->rq_snd_buf, p); -	return encode_mon_id(&xdr, argp); +	encode_mon_id(xdr, argp);  } -static int xdr_dec_stat_res(struct rpc_rqst *rqstp, __be32 *p, -			    struct nsm_res *resp) +static int nsm_xdr_dec_stat_res(struct rpc_rqst *rqstp, +				struct xdr_stream *xdr, +				struct nsm_res *resp)  { -	struct xdr_stream xdr; +	__be32 *p; -	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); -	p = xdr_inline_decode(&xdr, 2 * sizeof(u32)); +	p = xdr_inline_decode(xdr, 4 + 4);  	if (unlikely(p == NULL))  		return -EIO; -	resp->status = ntohl(*p++); -	resp->state = ntohl(*p); +	resp->status = be32_to_cpup(p++); +	resp->state = be32_to_cpup(p); -	dprintk("lockd: xdr_dec_stat_res status %d state %d\n", -			resp->status, resp->state); +	dprintk("lockd: %s status %d state %d\n", +		__func__, resp->status, resp->state);  	return 0;  } -static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p, -			struct nsm_res *resp) +static int nsm_xdr_dec_stat(struct rpc_rqst *rqstp, +			    struct xdr_stream *xdr, +			    struct nsm_res *resp)  { -	struct xdr_stream xdr; +	__be32 *p; -	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p); -	p = xdr_inline_decode(&xdr, sizeof(u32)); +	p = xdr_inline_decode(xdr, 4);  	if (unlikely(p == NULL))  		return -EIO; -	resp->state = ntohl(*p); +	resp->state = be32_to_cpup(p); -	dprintk("lockd: xdr_dec_stat state %d\n", resp->state); +	dprintk("lockd: %s state %d\n", __func__, resp->state);  	return 0;  } @@ -542,8 +574,8 @@ static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p,  static struct rpc_procinfo	nsm_procedures[] = {  [NSMPROC_MON] = {  		.p_proc		= NSMPROC_MON, -		.p_encode	= (kxdrproc_t)xdr_enc_mon, -		.p_decode	= (kxdrproc_t)xdr_dec_stat_res, +		.p_encode	= (kxdreproc_t)nsm_xdr_enc_mon, +		.p_decode	= (kxdrdproc_t)nsm_xdr_dec_stat_res,  		.p_arglen	= SM_mon_sz,  		.p_replen	= SM_monres_sz,  		.p_statidx	= NSMPROC_MON, @@ -551,8 +583,8 @@ static struct rpc_procinfo	nsm_procedures[] = {  	},  [NSMPROC_UNMON] = {  		.p_proc		= NSMPROC_UNMON, -		.p_encode	= (kxdrproc_t)xdr_enc_unmon, -		.p_decode	= (kxdrproc_t)xdr_dec_stat, +		.p_encode	= (kxdreproc_t)nsm_xdr_enc_unmon, +		.p_decode	= (kxdrdproc_t)nsm_xdr_dec_stat,  		.p_arglen	= SM_mon_id_sz,  		.p_replen	= SM_unmonres_sz,  		.p_statidx	= NSMPROC_UNMON, @@ -560,19 +592,19 @@ static struct rpc_procinfo	nsm_procedures[] = {  	},  }; -static struct rpc_version	nsm_version1 = { +static const struct rpc_version nsm_version1 = {  		.number		= 1,  		.nrprocs	= ARRAY_SIZE(nsm_procedures),  		.procs		= nsm_procedures  }; -static struct rpc_version *	nsm_version[] = { +static const struct rpc_version *nsm_version[] = {  	[1] = &nsm_version1,  };  static struct rpc_stat		nsm_stats; -static struct rpc_program	nsm_program = { +static const struct rpc_program nsm_program = {  		.name		= "statd",  		.number		= NSM_PROGRAM,  		.nrvers		= ARRAY_SIZE(nsm_version),  | 
