xref: /openbmc/linux/fs/lockd/mon.c (revision 460f5cac1e24e947509b6112c99c5bc9ff687b45)
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>
131da177e4SLinus Torvalds #include <linux/sunrpc/svc.h>
141da177e4SLinus Torvalds #include <linux/lockd/lockd.h>
151da177e4SLinus Torvalds #include <linux/lockd/sm_inter.h>
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds 
181da177e4SLinus Torvalds #define NLMDBG_FACILITY		NLMDBG_MONITOR
191da177e4SLinus Torvalds 
201da177e4SLinus Torvalds static struct rpc_clnt *	nsm_create(void);
211da177e4SLinus Torvalds 
221da177e4SLinus Torvalds static struct rpc_program	nsm_program;
231da177e4SLinus Torvalds 
241da177e4SLinus Torvalds /*
251da177e4SLinus Torvalds  * Local NSM state
261da177e4SLinus Torvalds  */
27*460f5cacSOlaf Kirch int				nsm_local_state;
281da177e4SLinus Torvalds 
291da177e4SLinus Torvalds /*
301da177e4SLinus Torvalds  * Common procedure for SM_MON/SM_UNMON calls
311da177e4SLinus Torvalds  */
321da177e4SLinus Torvalds static int
339502c522SOlaf Kirch nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
341da177e4SLinus Torvalds {
351da177e4SLinus Torvalds 	struct rpc_clnt	*clnt;
361da177e4SLinus Torvalds 	int		status;
371da177e4SLinus Torvalds 	struct nsm_args	args;
38dead28daSChuck Lever 	struct rpc_message msg = {
39dead28daSChuck Lever 		.rpc_argp	= &args,
40dead28daSChuck Lever 		.rpc_resp	= res,
41dead28daSChuck Lever 	};
421da177e4SLinus Torvalds 
431da177e4SLinus Torvalds 	clnt = nsm_create();
441da177e4SLinus Torvalds 	if (IS_ERR(clnt)) {
451da177e4SLinus Torvalds 		status = PTR_ERR(clnt);
461da177e4SLinus Torvalds 		goto out;
471da177e4SLinus Torvalds 	}
481da177e4SLinus Torvalds 
499502c522SOlaf Kirch 	memset(&args, 0, sizeof(args));
50abd1f500SOlaf Kirch 	args.mon_name = nsm->sm_name;
519502c522SOlaf Kirch 	args.addr = nsm->sm_addr.sin_addr.s_addr;
521da177e4SLinus Torvalds 	args.prog = NLM_PROGRAM;
539502c522SOlaf Kirch 	args.vers = 3;
541da177e4SLinus Torvalds 	args.proc = NLMPROC_NSM_NOTIFY;
551da177e4SLinus Torvalds 	memset(res, 0, sizeof(*res));
561da177e4SLinus Torvalds 
57dead28daSChuck Lever 	msg.rpc_proc = &clnt->cl_procinfo[proc];
58dead28daSChuck Lever 	status = rpc_call_sync(clnt, &msg, 0);
591da177e4SLinus Torvalds 	if (status < 0)
601da177e4SLinus Torvalds 		printk(KERN_DEBUG "nsm_mon_unmon: rpc failed, status=%d\n",
611da177e4SLinus Torvalds 			status);
621da177e4SLinus Torvalds 	else
631da177e4SLinus Torvalds 		status = 0;
641da177e4SLinus Torvalds  out:
651da177e4SLinus Torvalds 	return status;
661da177e4SLinus Torvalds }
671da177e4SLinus Torvalds 
681da177e4SLinus Torvalds /*
691da177e4SLinus Torvalds  * Set up monitoring of a remote host
701da177e4SLinus Torvalds  */
711da177e4SLinus Torvalds int
721da177e4SLinus Torvalds nsm_monitor(struct nlm_host *host)
731da177e4SLinus Torvalds {
748dead0dbSOlaf Kirch 	struct nsm_handle *nsm = host->h_nsmhandle;
751da177e4SLinus Torvalds 	struct nsm_res	res;
761da177e4SLinus Torvalds 	int		status;
771da177e4SLinus Torvalds 
781da177e4SLinus Torvalds 	dprintk("lockd: nsm_monitor(%s)\n", host->h_name);
798dead0dbSOlaf Kirch 	BUG_ON(nsm == NULL);
808dead0dbSOlaf Kirch 
818dead0dbSOlaf Kirch 	if (nsm->sm_monitored)
82977faf39SOlaf Kirch 		return 0;
831da177e4SLinus Torvalds 
849502c522SOlaf Kirch 	status = nsm_mon_unmon(nsm, SM_MON, &res);
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	if (status < 0 || res.status != 0)
871da177e4SLinus Torvalds 		printk(KERN_NOTICE "lockd: cannot monitor %s\n", host->h_name);
881da177e4SLinus Torvalds 	else
898dead0dbSOlaf Kirch 		nsm->sm_monitored = 1;
901da177e4SLinus Torvalds 	return status;
911da177e4SLinus Torvalds }
921da177e4SLinus Torvalds 
931da177e4SLinus Torvalds /*
941da177e4SLinus Torvalds  * Cease to monitor remote host
951da177e4SLinus Torvalds  */
961da177e4SLinus Torvalds int
971da177e4SLinus Torvalds nsm_unmonitor(struct nlm_host *host)
981da177e4SLinus Torvalds {
998dead0dbSOlaf Kirch 	struct nsm_handle *nsm = host->h_nsmhandle;
1001da177e4SLinus Torvalds 	struct nsm_res	res;
101977faf39SOlaf Kirch 	int		status = 0;
1021da177e4SLinus Torvalds 
1038dead0dbSOlaf Kirch 	if (nsm == NULL)
104977faf39SOlaf Kirch 		return 0;
1058dead0dbSOlaf Kirch 	host->h_nsmhandle = NULL;
1061da177e4SLinus Torvalds 
1079502c522SOlaf Kirch 	if (atomic_read(&nsm->sm_count) == 1
1089502c522SOlaf Kirch 	 && nsm->sm_monitored && !nsm->sm_sticky) {
1099502c522SOlaf Kirch 		dprintk("lockd: nsm_unmonitor(%s)\n", host->h_name);
1109502c522SOlaf Kirch 
1119502c522SOlaf Kirch 		status = nsm_mon_unmon(nsm, SM_UNMON, &res);
1121da177e4SLinus Torvalds 		if (status < 0)
1139502c522SOlaf Kirch 			printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
1149502c522SOlaf Kirch 					host->h_name);
1159502c522SOlaf Kirch 		else
1168dead0dbSOlaf Kirch 			nsm->sm_monitored = 0;
117977faf39SOlaf Kirch 	}
1188dead0dbSOlaf Kirch 	nsm_release(nsm);
1191da177e4SLinus Torvalds 	return status;
1201da177e4SLinus Torvalds }
1211da177e4SLinus Torvalds 
1221da177e4SLinus Torvalds /*
1231da177e4SLinus Torvalds  * Create NSM client for the local host
1241da177e4SLinus Torvalds  */
1251da177e4SLinus Torvalds static struct rpc_clnt *
1261da177e4SLinus Torvalds nsm_create(void)
1271da177e4SLinus Torvalds {
128e1ec7892SChuck Lever 	struct sockaddr_in	sin = {
129e1ec7892SChuck Lever 		.sin_family	= AF_INET,
130e1ec7892SChuck Lever 		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
131e1ec7892SChuck Lever 		.sin_port	= 0,
132e1ec7892SChuck Lever 	};
133e1ec7892SChuck Lever 	struct rpc_create_args args = {
134e1ec7892SChuck Lever 		.protocol	= IPPROTO_UDP,
135e1ec7892SChuck Lever 		.address	= (struct sockaddr *)&sin,
136e1ec7892SChuck Lever 		.addrsize	= sizeof(sin),
137e1ec7892SChuck Lever 		.servername	= "localhost",
138e1ec7892SChuck Lever 		.program	= &nsm_program,
139e1ec7892SChuck Lever 		.version	= SM_VERSION,
140e1ec7892SChuck Lever 		.authflavor	= RPC_AUTH_NULL,
141e1ec7892SChuck Lever 		.flags		= (RPC_CLNT_CREATE_ONESHOT),
142e1ec7892SChuck Lever 	};
1431da177e4SLinus Torvalds 
144e1ec7892SChuck Lever 	return rpc_create(&args);
1451da177e4SLinus Torvalds }
1461da177e4SLinus Torvalds 
1471da177e4SLinus Torvalds /*
1481da177e4SLinus Torvalds  * XDR functions for NSM.
1491da177e4SLinus Torvalds  */
1501da177e4SLinus Torvalds 
1511da177e4SLinus Torvalds static u32 *
1521da177e4SLinus Torvalds xdr_encode_common(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
1531da177e4SLinus Torvalds {
154abd1f500SOlaf Kirch 	char	buffer[20], *name;
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	/*
1571da177e4SLinus Torvalds 	 * Use the dotted-quad IP address of the remote host as
1581da177e4SLinus Torvalds 	 * identifier. Linux statd always looks up the canonical
1591da177e4SLinus Torvalds 	 * hostname first for whatever remote hostname it receives,
1601da177e4SLinus Torvalds 	 * so this works alright.
1611da177e4SLinus Torvalds 	 */
162abd1f500SOlaf Kirch 	if (nsm_use_hostnames) {
163abd1f500SOlaf Kirch 		name = argp->mon_name;
164abd1f500SOlaf Kirch 	} else {
1651da177e4SLinus Torvalds 		sprintf(buffer, "%u.%u.%u.%u", NIPQUAD(argp->addr));
166abd1f500SOlaf Kirch 		name = buffer;
167abd1f500SOlaf Kirch 	}
168abd1f500SOlaf Kirch 	if (!(p = xdr_encode_string(p, name))
169e9ff3990SSerge E. Hallyn 	 || !(p = xdr_encode_string(p, utsname()->nodename)))
1701da177e4SLinus Torvalds 		return ERR_PTR(-EIO);
1711da177e4SLinus Torvalds 	*p++ = htonl(argp->prog);
1721da177e4SLinus Torvalds 	*p++ = htonl(argp->vers);
1731da177e4SLinus Torvalds 	*p++ = htonl(argp->proc);
1741da177e4SLinus Torvalds 
1751da177e4SLinus Torvalds 	return p;
1761da177e4SLinus Torvalds }
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds static int
1791da177e4SLinus Torvalds xdr_encode_mon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
1801da177e4SLinus Torvalds {
1811da177e4SLinus Torvalds 	p = xdr_encode_common(rqstp, p, argp);
1821da177e4SLinus Torvalds 	if (IS_ERR(p))
1831da177e4SLinus Torvalds 		return PTR_ERR(p);
1849502c522SOlaf Kirch 
1859502c522SOlaf Kirch 	/* Surprise - there may even be room for an IPv6 address now */
1861da177e4SLinus Torvalds 	*p++ = argp->addr;
1879502c522SOlaf Kirch 	*p++ = 0;
1889502c522SOlaf Kirch 	*p++ = 0;
1891da177e4SLinus Torvalds 	*p++ = 0;
1901da177e4SLinus Torvalds 	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
1911da177e4SLinus Torvalds 	return 0;
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds 
1941da177e4SLinus Torvalds static int
1951da177e4SLinus Torvalds xdr_encode_unmon(struct rpc_rqst *rqstp, u32 *p, struct nsm_args *argp)
1961da177e4SLinus Torvalds {
1971da177e4SLinus Torvalds 	p = xdr_encode_common(rqstp, p, argp);
1981da177e4SLinus Torvalds 	if (IS_ERR(p))
1991da177e4SLinus Torvalds 		return PTR_ERR(p);
2001da177e4SLinus Torvalds 	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
2011da177e4SLinus Torvalds 	return 0;
2021da177e4SLinus Torvalds }
2031da177e4SLinus Torvalds 
2041da177e4SLinus Torvalds static int
2051da177e4SLinus Torvalds xdr_decode_stat_res(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
2061da177e4SLinus Torvalds {
2071da177e4SLinus Torvalds 	resp->status = ntohl(*p++);
2081da177e4SLinus Torvalds 	resp->state = ntohl(*p++);
2091da177e4SLinus Torvalds 	dprintk("nsm: xdr_decode_stat_res status %d state %d\n",
2101da177e4SLinus Torvalds 			resp->status, resp->state);
2111da177e4SLinus Torvalds 	return 0;
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds 
2141da177e4SLinus Torvalds static int
2151da177e4SLinus Torvalds xdr_decode_stat(struct rpc_rqst *rqstp, u32 *p, struct nsm_res *resp)
2161da177e4SLinus Torvalds {
2171da177e4SLinus Torvalds 	resp->state = ntohl(*p++);
2181da177e4SLinus Torvalds 	return 0;
2191da177e4SLinus Torvalds }
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds #define SM_my_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
2221da177e4SLinus Torvalds #define SM_my_id_sz	(3+1+SM_my_name_sz)
2231da177e4SLinus Torvalds #define SM_mon_id_sz	(1+XDR_QUADLEN(20)+SM_my_id_sz)
2241da177e4SLinus Torvalds #define SM_mon_sz	(SM_mon_id_sz+4)
2251da177e4SLinus Torvalds #define SM_monres_sz	2
2261da177e4SLinus Torvalds #define SM_unmonres_sz	1
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds #ifndef MAX
2291da177e4SLinus Torvalds # define MAX(a, b)	(((a) > (b))? (a) : (b))
2301da177e4SLinus Torvalds #endif
2311da177e4SLinus Torvalds 
2321da177e4SLinus Torvalds static struct rpc_procinfo	nsm_procedures[] = {
2331da177e4SLinus Torvalds [SM_MON] = {
2341da177e4SLinus Torvalds 		.p_proc		= SM_MON,
2351da177e4SLinus Torvalds 		.p_encode	= (kxdrproc_t) xdr_encode_mon,
2361da177e4SLinus Torvalds 		.p_decode	= (kxdrproc_t) xdr_decode_stat_res,
2371da177e4SLinus Torvalds 		.p_bufsiz	= MAX(SM_mon_sz, SM_monres_sz) << 2,
238cc0175c1SChuck Lever 		.p_statidx	= SM_MON,
239cc0175c1SChuck Lever 		.p_name		= "MONITOR",
2401da177e4SLinus Torvalds 	},
2411da177e4SLinus Torvalds [SM_UNMON] = {
2421da177e4SLinus Torvalds 		.p_proc		= SM_UNMON,
2431da177e4SLinus Torvalds 		.p_encode	= (kxdrproc_t) xdr_encode_unmon,
2441da177e4SLinus Torvalds 		.p_decode	= (kxdrproc_t) xdr_decode_stat,
2451da177e4SLinus Torvalds 		.p_bufsiz	= MAX(SM_mon_id_sz, SM_unmonres_sz) << 2,
246cc0175c1SChuck Lever 		.p_statidx	= SM_UNMON,
247cc0175c1SChuck Lever 		.p_name		= "UNMONITOR",
2481da177e4SLinus Torvalds 	},
2491da177e4SLinus Torvalds };
2501da177e4SLinus Torvalds 
2511da177e4SLinus Torvalds static struct rpc_version	nsm_version1 = {
2521da177e4SLinus Torvalds 		.number		= 1,
253e8c96f8cSTobias Klauser 		.nrprocs	= ARRAY_SIZE(nsm_procedures),
2541da177e4SLinus Torvalds 		.procs		= nsm_procedures
2551da177e4SLinus Torvalds };
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds static struct rpc_version *	nsm_version[] = {
2581da177e4SLinus Torvalds 	[1] = &nsm_version1,
2591da177e4SLinus Torvalds };
2601da177e4SLinus Torvalds 
2611da177e4SLinus Torvalds static struct rpc_stat		nsm_stats;
2621da177e4SLinus Torvalds 
2631da177e4SLinus Torvalds static struct rpc_program	nsm_program = {
2641da177e4SLinus Torvalds 		.name		= "statd",
2651da177e4SLinus Torvalds 		.number		= SM_PROGRAM,
266e8c96f8cSTobias Klauser 		.nrvers		= ARRAY_SIZE(nsm_version),
2671da177e4SLinus Torvalds 		.version	= nsm_version,
2681da177e4SLinus Torvalds 		.stats		= &nsm_stats
2691da177e4SLinus Torvalds };
270