xref: /openbmc/linux/fs/lockd/mon.c (revision 5acf43155d1bcc412d892c73f64044f9a826cde6)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * linux/fs/lockd/mon.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * The kernel statd client.
51da177e4SLinus Torvalds  *
61da177e4SLinus Torvalds  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
71da177e4SLinus Torvalds  */
81da177e4SLinus Torvalds 
91da177e4SLinus Torvalds #include <linux/types.h>
101da177e4SLinus Torvalds #include <linux/utsname.h>
111da177e4SLinus Torvalds #include <linux/kernel.h>
121da177e4SLinus Torvalds #include <linux/sunrpc/clnt.h>
130896a725S\"Talpey, Thomas\ #include <linux/sunrpc/xprtsock.h>
141da177e4SLinus Torvalds #include <linux/sunrpc/svc.h>
151da177e4SLinus Torvalds #include <linux/lockd/lockd.h>
161da177e4SLinus Torvalds #include <linux/lockd/sm_inter.h>
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds 
191da177e4SLinus Torvalds #define NLMDBG_FACILITY		NLMDBG_MONITOR
201da177e4SLinus Torvalds 
2149695174SChuck Lever #define XDR_ADDRBUF_LEN		(20)
2249695174SChuck Lever 
231da177e4SLinus Torvalds static struct rpc_clnt *	nsm_create(void);
241da177e4SLinus Torvalds 
251da177e4SLinus Torvalds static struct rpc_program	nsm_program;
261da177e4SLinus Torvalds 
271da177e4SLinus Torvalds /*
281da177e4SLinus Torvalds  * Local NSM state
291da177e4SLinus Torvalds  */
30460f5cacSOlaf Kirch int				nsm_local_state;
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds /*
331da177e4SLinus Torvalds  * Common procedure for SM_MON/SM_UNMON calls
341da177e4SLinus Torvalds  */
351da177e4SLinus Torvalds static int
369502c522SOlaf Kirch nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
371da177e4SLinus Torvalds {
381da177e4SLinus Torvalds 	struct rpc_clnt	*clnt;
391da177e4SLinus Torvalds 	int		status;
40a4846750SChuck Lever 	struct nsm_args args = {
41a4846750SChuck Lever 		.addr		= nsm_addr_in(nsm)->sin_addr.s_addr,
42a4846750SChuck Lever 		.prog		= NLM_PROGRAM,
43a4846750SChuck Lever 		.vers		= 3,
44a4846750SChuck Lever 		.proc		= NLMPROC_NSM_NOTIFY,
45a4846750SChuck Lever 		.mon_name	= nsm->sm_name,
46a4846750SChuck Lever 	};
47dead28daSChuck Lever 	struct rpc_message msg = {
48dead28daSChuck Lever 		.rpc_argp	= &args,
49dead28daSChuck Lever 		.rpc_resp	= res,
50dead28daSChuck Lever 	};
511da177e4SLinus Torvalds 
521da177e4SLinus Torvalds 	clnt = nsm_create();
531da177e4SLinus Torvalds 	if (IS_ERR(clnt)) {
541da177e4SLinus Torvalds 		status = PTR_ERR(clnt);
55*5acf4315SChuck Lever 		dprintk("lockd: failed to create NSM upcall transport, "
56*5acf4315SChuck Lever 				"status=%d\n", status);
571da177e4SLinus Torvalds 		goto out;
581da177e4SLinus Torvalds 	}
591da177e4SLinus Torvalds 
601da177e4SLinus Torvalds 	memset(res, 0, sizeof(*res));
611da177e4SLinus Torvalds 
62dead28daSChuck Lever 	msg.rpc_proc = &clnt->cl_procinfo[proc];
63dead28daSChuck Lever 	status = rpc_call_sync(clnt, &msg, 0);
641da177e4SLinus Torvalds 	if (status < 0)
65*5acf4315SChuck Lever 		dprintk("lockd: NSM upcall RPC failed, status=%d\n",
661da177e4SLinus Torvalds 				status);
671da177e4SLinus Torvalds 	else
681da177e4SLinus Torvalds 		status = 0;
6990c5755fSTrond Myklebust 	rpc_shutdown_client(clnt);
701da177e4SLinus Torvalds  out:
711da177e4SLinus Torvalds 	return status;
721da177e4SLinus Torvalds }
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds /*
751da177e4SLinus Torvalds  * Set up monitoring of a remote host
761da177e4SLinus Torvalds  */
771da177e4SLinus Torvalds int
781da177e4SLinus Torvalds nsm_monitor(struct nlm_host *host)
791da177e4SLinus Torvalds {
808dead0dbSOlaf Kirch 	struct nsm_handle *nsm = host->h_nsmhandle;
811da177e4SLinus Torvalds 	struct nsm_res	res;
821da177e4SLinus Torvalds 	int		status;
831da177e4SLinus Torvalds 
841da177e4SLinus Torvalds 	dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
858dead0dbSOlaf Kirch 	BUG_ON(nsm == NULL);
868dead0dbSOlaf Kirch 
878dead0dbSOlaf Kirch 	if (nsm->sm_monitored)
88977faf39SOlaf Kirch 		return 0;
891da177e4SLinus Torvalds 
909502c522SOlaf Kirch 	status = nsm_mon_unmon(nsm, SM_MON, &res);
911da177e4SLinus Torvalds 
921da177e4SLinus Torvalds 	if (status < 0 || res.status != 0)
931da177e4SLinus Torvalds 		printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
941da177e4SLinus Torvalds 	else
958dead0dbSOlaf Kirch 		nsm->sm_monitored = 1;
961da177e4SLinus Torvalds 	return status;
971da177e4SLinus Torvalds }
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds /*
1001da177e4SLinus Torvalds  * Cease to monitor remote host
1011da177e4SLinus Torvalds  */
1021da177e4SLinus Torvalds int
1031da177e4SLinus Torvalds nsm_unmonitor(struct nlm_host *host)
1041da177e4SLinus Torvalds {
1058dead0dbSOlaf Kirch 	struct nsm_handle *nsm = host->h_nsmhandle;
1061da177e4SLinus Torvalds 	struct nsm_res	res;
107977faf39SOlaf Kirch 	int		status = 0;
1081da177e4SLinus Torvalds 
1098dead0dbSOlaf Kirch 	if (nsm == NULL)
110977faf39SOlaf Kirch 		return 0;
1118dead0dbSOlaf Kirch 	host->h_nsmhandle = NULL;
1121da177e4SLinus Torvalds 
1139502c522SOlaf Kirch 	if (atomic_read(&nsm->sm_count) == 1
1149502c522SOlaf Kirch 	 && nsm->sm_monitored && !nsm->sm_sticky) {
1159502c522SOlaf Kirch 		dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
1169502c522SOlaf Kirch 
1179502c522SOlaf Kirch 		status = nsm_mon_unmon(nsm, SM_UNMON, &res);
1181da177e4SLinus Torvalds 		if (status < 0)
1199502c522SOlaf Kirch 			printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
1209502c522SOlaf Kirch 					host->h_name);
1219502c522SOlaf Kirch 		else
1228dead0dbSOlaf Kirch 			nsm->sm_monitored = 0;
123977faf39SOlaf Kirch 	}
1248dead0dbSOlaf Kirch 	nsm_release(nsm);
1251da177e4SLinus Torvalds 	return status;
1261da177e4SLinus Torvalds }
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds /*
1291da177e4SLinus Torvalds  * Create NSM client for the local host
1301da177e4SLinus Torvalds  */
1311da177e4SLinus Torvalds static struct rpc_clnt *
1321da177e4SLinus Torvalds nsm_create(void)
1331da177e4SLinus Torvalds {
134e1ec7892SChuck Lever 	struct sockaddr_in	sin = {
135e1ec7892SChuck Lever 		.sin_family	= AF_INET,
136e1ec7892SChuck Lever 		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
137e1ec7892SChuck Lever 		.sin_port	= 0,
138e1ec7892SChuck Lever 	};
139e1ec7892SChuck Lever 	struct rpc_create_args args = {
1400896a725S\"Talpey, Thomas\ 		.protocol	= XPRT_TRANSPORT_UDP,
141e1ec7892SChuck Lever 		.address	= (struct sockaddr *)&sin,
142e1ec7892SChuck Lever 		.addrsize	= sizeof(sin),
143e1ec7892SChuck Lever 		.servername	= "localhost",
144e1ec7892SChuck Lever 		.program	= &nsm_program,
145e1ec7892SChuck Lever 		.version	= SM_VERSION,
146e1ec7892SChuck Lever 		.authflavor	= RPC_AUTH_NULL,
147e1ec7892SChuck Lever 	};
1481da177e4SLinus Torvalds 
149e1ec7892SChuck Lever 	return rpc_create(&args);
1501da177e4SLinus Torvalds }
1511da177e4SLinus Torvalds 
1521da177e4SLinus Torvalds /*
1531da177e4SLinus Torvalds  * XDR functions for NSM.
1542ca7754dSChuck Lever  *
1552ca7754dSChuck Lever  * See http://www.opengroup.org/ for details on the Network
1562ca7754dSChuck Lever  * Status Monitor wire protocol.
1571da177e4SLinus Torvalds  */
1581da177e4SLinus Torvalds 
159099bd05fSChuck Lever static __be32 *xdr_encode_nsm_string(__be32 *p, char *string)
160099bd05fSChuck Lever {
161099bd05fSChuck Lever 	size_t len = strlen(string);
162099bd05fSChuck Lever 
163099bd05fSChuck Lever 	if (len > SM_MAXSTRLEN)
164099bd05fSChuck Lever 		len = SM_MAXSTRLEN;
165099bd05fSChuck Lever 	return xdr_encode_opaque(p, string, len);
166099bd05fSChuck Lever }
167099bd05fSChuck Lever 
16849695174SChuck Lever /*
16949695174SChuck Lever  * "mon_name" specifies the host to be monitored.
17049695174SChuck Lever  *
17149695174SChuck Lever  * Linux uses a text version of the IP address of the remote
17249695174SChuck Lever  * host as the host identifier (the "mon_name" argument).
17349695174SChuck Lever  *
17449695174SChuck Lever  * Linux statd always looks up the canonical hostname first for
17549695174SChuck Lever  * whatever remote hostname it receives, so this works alright.
17649695174SChuck Lever  */
17749695174SChuck Lever static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp)
17849695174SChuck Lever {
17949695174SChuck Lever 	char	buffer[XDR_ADDRBUF_LEN + 1];
18049695174SChuck Lever 	char	*name = argp->mon_name;
18149695174SChuck Lever 
18249695174SChuck Lever 	if (!nsm_use_hostnames) {
18349695174SChuck Lever 		snprintf(buffer, XDR_ADDRBUF_LEN,
184be859405SHarvey Harrison 			 "%pI4", &argp->addr);
18549695174SChuck Lever 		name = buffer;
18649695174SChuck Lever 	}
18749695174SChuck Lever 
18849695174SChuck Lever 	return xdr_encode_nsm_string(p, name);
18949695174SChuck Lever }
19049695174SChuck Lever 
191850c95fdSChuck Lever /*
192850c95fdSChuck Lever  * The "my_id" argument specifies the hostname and RPC procedure
193850c95fdSChuck Lever  * to be called when the status manager receives notification
194850c95fdSChuck Lever  * (via the SM_NOTIFY call) that the state of host "mon_name"
195850c95fdSChuck Lever  * has changed.
196850c95fdSChuck Lever  */
197850c95fdSChuck Lever static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp)
198850c95fdSChuck Lever {
199850c95fdSChuck Lever 	p = xdr_encode_nsm_string(p, utsname()->nodename);
200850c95fdSChuck Lever 	if (!p)
201850c95fdSChuck Lever 		return ERR_PTR(-EIO);
202850c95fdSChuck Lever 
203850c95fdSChuck Lever 	*p++ = htonl(argp->prog);
204850c95fdSChuck Lever 	*p++ = htonl(argp->vers);
205850c95fdSChuck Lever 	*p++ = htonl(argp->proc);
206850c95fdSChuck Lever 
207850c95fdSChuck Lever 	return p;
208850c95fdSChuck Lever }
209850c95fdSChuck Lever 
210ea72a7f1SChuck Lever /*
211ea72a7f1SChuck Lever  * The "mon_id" argument specifies the non-private arguments
212ea72a7f1SChuck Lever  * of an SM_MON or SM_UNMON call.
213ea72a7f1SChuck Lever  */
214ea72a7f1SChuck Lever static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp)
215ea72a7f1SChuck Lever {
216ea72a7f1SChuck Lever 	p = xdr_encode_mon_name(p, argp);
217ea72a7f1SChuck Lever 	if (!p)
218ea72a7f1SChuck Lever 		return ERR_PTR(-EIO);
219ea72a7f1SChuck Lever 
220ea72a7f1SChuck Lever 	return xdr_encode_my_id(p, argp);
221ea72a7f1SChuck Lever }
222ea72a7f1SChuck Lever 
2230490a54aSChuck Lever /*
2240490a54aSChuck Lever  * The "priv" argument may contain private information required
2250490a54aSChuck Lever  * by the SM_MON call. This information will be supplied in the
2260490a54aSChuck Lever  * SM_NOTIFY call.
2270490a54aSChuck Lever  *
2280490a54aSChuck Lever  * Linux provides the raw IP address of the monitored host,
2290490a54aSChuck Lever  * left in network byte order.
2300490a54aSChuck Lever  */
2310490a54aSChuck Lever static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp)
2320490a54aSChuck Lever {
2330490a54aSChuck Lever 	*p++ = argp->addr;
2340490a54aSChuck Lever 	*p++ = 0;
2350490a54aSChuck Lever 	*p++ = 0;
2360490a54aSChuck Lever 	*p++ = 0;
2370490a54aSChuck Lever 
2380490a54aSChuck Lever 	return p;
2390490a54aSChuck Lever }
2400490a54aSChuck Lever 
2411da177e4SLinus Torvalds static int
24252921e02SAl Viro xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
2431da177e4SLinus Torvalds {
2442ca7754dSChuck Lever 	p = xdr_encode_mon_id(p, argp);
2451da177e4SLinus Torvalds 	if (IS_ERR(p))
2461da177e4SLinus Torvalds 		return PTR_ERR(p);
2479502c522SOlaf Kirch 
2480490a54aSChuck Lever 	p = xdr_encode_priv(p, argp);
2490490a54aSChuck Lever 	if (IS_ERR(p))
2500490a54aSChuck Lever 		return PTR_ERR(p);
2510490a54aSChuck Lever 
2521da177e4SLinus Torvalds 	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
2531da177e4SLinus Torvalds 	return 0;
2541da177e4SLinus Torvalds }
2551da177e4SLinus Torvalds 
2561da177e4SLinus Torvalds static int
25752921e02SAl Viro xdr_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
2581da177e4SLinus Torvalds {
2592ca7754dSChuck Lever 	p = xdr_encode_mon_id(p, argp);
2601da177e4SLinus Torvalds 	if (IS_ERR(p))
2611da177e4SLinus Torvalds 		return PTR_ERR(p);
2621da177e4SLinus Torvalds 	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
2631da177e4SLinus Torvalds 	return 0;
2641da177e4SLinus Torvalds }
2651da177e4SLinus Torvalds 
2661da177e4SLinus Torvalds static int
26752921e02SAl Viro xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
2681da177e4SLinus Torvalds {
2691da177e4SLinus Torvalds 	resp->status = ntohl(*p++);
2701da177e4SLinus Torvalds 	resp->state = ntohl(*p++);
2711da177e4SLinus Torvalds 	dprintk("nsm: xdr_decode_stat_res status %d state %d\n",
2721da177e4SLinus Torvalds 			resp->status, resp->state);
2731da177e4SLinus Torvalds 	return 0;
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static int
27752921e02SAl Viro xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
2781da177e4SLinus Torvalds {
2791da177e4SLinus Torvalds 	resp->state = ntohl(*p++);
2801da177e4SLinus Torvalds 	return 0;
2811da177e4SLinus Torvalds }
2821da177e4SLinus Torvalds 
2831da177e4SLinus Torvalds #define SM_my_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
2842ca7754dSChuck Lever #define SM_my_id_sz	(SM_my_name_sz+3)
2852ca7754dSChuck Lever #define SM_mon_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
2862ca7754dSChuck Lever #define SM_mon_id_sz	(SM_mon_name_sz+SM_my_id_sz)
2870490a54aSChuck Lever #define SM_priv_sz	(XDR_QUADLEN(SM_PRIV_SIZE))
2880490a54aSChuck Lever #define SM_mon_sz	(SM_mon_id_sz+SM_priv_sz)
2891da177e4SLinus Torvalds #define SM_monres_sz	2
2901da177e4SLinus Torvalds #define SM_unmonres_sz	1
2911da177e4SLinus Torvalds 
2921da177e4SLinus Torvalds static struct rpc_procinfo	nsm_procedures[] = {
2931da177e4SLinus Torvalds [SM_MON] = {
2941da177e4SLinus Torvalds 		.p_proc		= SM_MON,
2951da177e4SLinus Torvalds 		.p_encode	= (kxdrproc_t) xdr_encode_mon,
2961da177e4SLinus Torvalds 		.p_decode	= (kxdrproc_t) xdr_decode_stat_res,
2972bea90d4SChuck Lever 		.p_arglen	= SM_mon_sz,
2982bea90d4SChuck Lever 		.p_replen	= SM_monres_sz,
299cc0175c1SChuck Lever 		.p_statidx	= SM_MON,
300cc0175c1SChuck Lever 		.p_name		= "MONITOR",
3011da177e4SLinus Torvalds 	},
3021da177e4SLinus Torvalds [SM_UNMON] = {
3031da177e4SLinus Torvalds 		.p_proc		= SM_UNMON,
3041da177e4SLinus Torvalds 		.p_encode	= (kxdrproc_t) xdr_encode_unmon,
3051da177e4SLinus Torvalds 		.p_decode	= (kxdrproc_t) xdr_decode_stat,
3062bea90d4SChuck Lever 		.p_arglen	= SM_mon_id_sz,
3072bea90d4SChuck Lever 		.p_replen	= SM_unmonres_sz,
308cc0175c1SChuck Lever 		.p_statidx	= SM_UNMON,
309cc0175c1SChuck Lever 		.p_name		= "UNMONITOR",
3101da177e4SLinus Torvalds 	},
3111da177e4SLinus Torvalds };
3121da177e4SLinus Torvalds 
3131da177e4SLinus Torvalds static struct rpc_version	nsm_version1 = {
3141da177e4SLinus Torvalds 		.number		= 1,
315e8c96f8cSTobias Klauser 		.nrprocs	= ARRAY_SIZE(nsm_procedures),
3161da177e4SLinus Torvalds 		.procs		= nsm_procedures
3171da177e4SLinus Torvalds };
3181da177e4SLinus Torvalds 
3191da177e4SLinus Torvalds static struct rpc_version *	nsm_version[] = {
3201da177e4SLinus Torvalds 	[1] = &nsm_version1,
3211da177e4SLinus Torvalds };
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds static struct rpc_stat		nsm_stats;
3241da177e4SLinus Torvalds 
3251da177e4SLinus Torvalds static struct rpc_program	nsm_program = {
3261da177e4SLinus Torvalds 		.name		= "statd",
3271da177e4SLinus Torvalds 		.number		= SM_PROGRAM,
328e8c96f8cSTobias Klauser 		.nrvers		= ARRAY_SIZE(nsm_version),
3291da177e4SLinus Torvalds 		.version	= nsm_version,
3301da177e4SLinus Torvalds 		.stats		= &nsm_stats
3311da177e4SLinus Torvalds };
332