xref: /linux/fs/lockd/mon.c (revision 9c1bfd037f7ff8badaecb47418f109148d88bf45)
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 
21*9c1bfd03SChuck Lever struct nsm_args {
22*9c1bfd03SChuck Lever 	__be32			addr;		/* remote address */
23*9c1bfd03SChuck Lever 	u32			prog;		/* RPC callback info */
24*9c1bfd03SChuck Lever 	u32			vers;
25*9c1bfd03SChuck Lever 	u32			proc;
26*9c1bfd03SChuck Lever 
27*9c1bfd03SChuck Lever 	char			*mon_name;
28*9c1bfd03SChuck Lever };
29*9c1bfd03SChuck Lever 
30*9c1bfd03SChuck Lever struct nsm_res {
31*9c1bfd03SChuck Lever 	u32			status;
32*9c1bfd03SChuck Lever 	u32			state;
33*9c1bfd03SChuck Lever };
34*9c1bfd03SChuck Lever 
351da177e4SLinus Torvalds static struct rpc_clnt *	nsm_create(void);
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds static struct rpc_program	nsm_program;
381da177e4SLinus Torvalds 
391da177e4SLinus Torvalds /*
401da177e4SLinus Torvalds  * Local NSM state
411da177e4SLinus Torvalds  */
42460f5cacSOlaf Kirch int				nsm_local_state;
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds /*
451da177e4SLinus Torvalds  * Common procedure for SM_MON/SM_UNMON calls
461da177e4SLinus Torvalds  */
471da177e4SLinus Torvalds static int
489502c522SOlaf Kirch nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds 	struct rpc_clnt	*clnt;
511da177e4SLinus Torvalds 	int		status;
52a4846750SChuck Lever 	struct nsm_args args = {
53a4846750SChuck Lever 		.addr		= nsm_addr_in(nsm)->sin_addr.s_addr,
54a4846750SChuck Lever 		.prog		= NLM_PROGRAM,
55a4846750SChuck Lever 		.vers		= 3,
56a4846750SChuck Lever 		.proc		= NLMPROC_NSM_NOTIFY,
5729ed1407SChuck Lever 		.mon_name	= nsm->sm_mon_name,
58a4846750SChuck Lever 	};
59dead28daSChuck Lever 	struct rpc_message msg = {
60dead28daSChuck Lever 		.rpc_argp	= &args,
61dead28daSChuck Lever 		.rpc_resp	= res,
62dead28daSChuck Lever 	};
631da177e4SLinus Torvalds 
641da177e4SLinus Torvalds 	clnt = nsm_create();
651da177e4SLinus Torvalds 	if (IS_ERR(clnt)) {
661da177e4SLinus Torvalds 		status = PTR_ERR(clnt);
675acf4315SChuck Lever 		dprintk("lockd: failed to create NSM upcall transport, "
685acf4315SChuck Lever 				"status=%d\n", status);
691da177e4SLinus Torvalds 		goto out;
701da177e4SLinus Torvalds 	}
711da177e4SLinus Torvalds 
721da177e4SLinus Torvalds 	memset(res, 0, sizeof(*res));
731da177e4SLinus Torvalds 
74dead28daSChuck Lever 	msg.rpc_proc = &clnt->cl_procinfo[proc];
75dead28daSChuck Lever 	status = rpc_call_sync(clnt, &msg, 0);
761da177e4SLinus Torvalds 	if (status < 0)
775acf4315SChuck Lever 		dprintk("lockd: NSM upcall RPC failed, status=%d\n",
781da177e4SLinus Torvalds 				status);
791da177e4SLinus Torvalds 	else
801da177e4SLinus Torvalds 		status = 0;
8190c5755fSTrond Myklebust 	rpc_shutdown_client(clnt);
821da177e4SLinus Torvalds  out:
831da177e4SLinus Torvalds 	return status;
841da177e4SLinus Torvalds }
851da177e4SLinus Torvalds 
861e49323cSChuck Lever /**
871e49323cSChuck Lever  * nsm_monitor - Notify a peer in case we reboot
881e49323cSChuck Lever  * @host: pointer to nlm_host of peer to notify
891e49323cSChuck Lever  *
901e49323cSChuck Lever  * If this peer is not already monitored, this function sends an
911e49323cSChuck Lever  * upcall to the local rpc.statd to record the name/address of
921e49323cSChuck Lever  * the peer to notify in case we reboot.
931e49323cSChuck Lever  *
941e49323cSChuck Lever  * Returns zero if the peer is monitored by the local rpc.statd;
951e49323cSChuck Lever  * otherwise a negative errno value is returned.
961da177e4SLinus Torvalds  */
971e49323cSChuck Lever int nsm_monitor(const struct nlm_host *host)
981da177e4SLinus Torvalds {
998dead0dbSOlaf Kirch 	struct nsm_handle *nsm = host->h_nsmhandle;
1001da177e4SLinus Torvalds 	struct nsm_res	res;
1011da177e4SLinus Torvalds 	int		status;
1021da177e4SLinus Torvalds 
1039fee4902SChuck Lever 	dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
1048dead0dbSOlaf Kirch 
1058dead0dbSOlaf Kirch 	if (nsm->sm_monitored)
106977faf39SOlaf Kirch 		return 0;
1071da177e4SLinus Torvalds 
10829ed1407SChuck Lever 	/*
10929ed1407SChuck Lever 	 * Choose whether to record the caller_name or IP address of
11029ed1407SChuck Lever 	 * this peer in the local rpc.statd's database.
11129ed1407SChuck Lever 	 */
11229ed1407SChuck Lever 	nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
11329ed1407SChuck Lever 
1149502c522SOlaf Kirch 	status = nsm_mon_unmon(nsm, SM_MON, &res);
1155d254b11SChuck Lever 	if (res.status != 0)
1165d254b11SChuck Lever 		status = -EIO;
1175d254b11SChuck Lever 	if (status < 0)
1189fee4902SChuck Lever 		printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name);
1191da177e4SLinus Torvalds 	else
1208dead0dbSOlaf Kirch 		nsm->sm_monitored = 1;
1211da177e4SLinus Torvalds 	return status;
1221da177e4SLinus Torvalds }
1231da177e4SLinus Torvalds 
124356c3eb4SChuck Lever /**
125356c3eb4SChuck Lever  * nsm_unmonitor - Unregister peer notification
126356c3eb4SChuck Lever  * @host: pointer to nlm_host of peer to stop monitoring
127356c3eb4SChuck Lever  *
128356c3eb4SChuck Lever  * If this peer is monitored, this function sends an upcall to
129356c3eb4SChuck Lever  * tell the local rpc.statd not to send this peer a notification
130356c3eb4SChuck Lever  * when we reboot.
1311da177e4SLinus Torvalds  */
132356c3eb4SChuck Lever void nsm_unmonitor(const struct nlm_host *host)
1331da177e4SLinus Torvalds {
1348dead0dbSOlaf Kirch 	struct nsm_handle *nsm = host->h_nsmhandle;
1351da177e4SLinus Torvalds 	struct nsm_res	res;
136356c3eb4SChuck Lever 	int status;
1371da177e4SLinus Torvalds 
1389502c522SOlaf Kirch 	if (atomic_read(&nsm->sm_count) == 1
1399502c522SOlaf Kirch 	 && nsm->sm_monitored && !nsm->sm_sticky) {
1409fee4902SChuck Lever 		dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
1419502c522SOlaf Kirch 
1429502c522SOlaf Kirch 		status = nsm_mon_unmon(nsm, SM_UNMON, &res);
1430c7aef45SChuck Lever 		if (res.status != 0)
1440c7aef45SChuck Lever 			status = -EIO;
1451da177e4SLinus Torvalds 		if (status < 0)
1469502c522SOlaf Kirch 			printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
1479fee4902SChuck Lever 					nsm->sm_name);
1489502c522SOlaf Kirch 		else
1498dead0dbSOlaf Kirch 			nsm->sm_monitored = 0;
150977faf39SOlaf Kirch 	}
1511da177e4SLinus Torvalds }
1521da177e4SLinus Torvalds 
1531da177e4SLinus Torvalds /*
1541da177e4SLinus Torvalds  * Create NSM client for the local host
1551da177e4SLinus Torvalds  */
1561da177e4SLinus Torvalds static struct rpc_clnt *
1571da177e4SLinus Torvalds nsm_create(void)
1581da177e4SLinus Torvalds {
159e1ec7892SChuck Lever 	struct sockaddr_in	sin = {
160e1ec7892SChuck Lever 		.sin_family	= AF_INET,
161e1ec7892SChuck Lever 		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
162e1ec7892SChuck Lever 		.sin_port	= 0,
163e1ec7892SChuck Lever 	};
164e1ec7892SChuck Lever 	struct rpc_create_args args = {
1650896a725S\"Talpey, Thomas\ 		.protocol	= XPRT_TRANSPORT_UDP,
166e1ec7892SChuck Lever 		.address	= (struct sockaddr *)&sin,
167e1ec7892SChuck Lever 		.addrsize	= sizeof(sin),
168e1ec7892SChuck Lever 		.servername	= "localhost",
169e1ec7892SChuck Lever 		.program	= &nsm_program,
170e1ec7892SChuck Lever 		.version	= SM_VERSION,
171e1ec7892SChuck Lever 		.authflavor	= RPC_AUTH_NULL,
172e1ec7892SChuck Lever 	};
1731da177e4SLinus Torvalds 
174e1ec7892SChuck Lever 	return rpc_create(&args);
1751da177e4SLinus Torvalds }
1761da177e4SLinus Torvalds 
1771da177e4SLinus Torvalds /*
1781da177e4SLinus Torvalds  * XDR functions for NSM.
1792ca7754dSChuck Lever  *
1802ca7754dSChuck Lever  * See http://www.opengroup.org/ for details on the Network
1812ca7754dSChuck Lever  * Status Monitor wire protocol.
1821da177e4SLinus Torvalds  */
1831da177e4SLinus Torvalds 
184099bd05fSChuck Lever static __be32 *xdr_encode_nsm_string(__be32 *p, char *string)
185099bd05fSChuck Lever {
186099bd05fSChuck Lever 	size_t len = strlen(string);
187099bd05fSChuck Lever 
188099bd05fSChuck Lever 	if (len > SM_MAXSTRLEN)
189099bd05fSChuck Lever 		len = SM_MAXSTRLEN;
190099bd05fSChuck Lever 	return xdr_encode_opaque(p, string, len);
191099bd05fSChuck Lever }
192099bd05fSChuck Lever 
19349695174SChuck Lever /*
19449695174SChuck Lever  * "mon_name" specifies the host to be monitored.
19549695174SChuck Lever  */
19649695174SChuck Lever static __be32 *xdr_encode_mon_name(__be32 *p, struct nsm_args *argp)
19749695174SChuck Lever {
19829ed1407SChuck Lever 	return xdr_encode_nsm_string(p, argp->mon_name);
19949695174SChuck Lever }
20049695174SChuck Lever 
201850c95fdSChuck Lever /*
202850c95fdSChuck Lever  * The "my_id" argument specifies the hostname and RPC procedure
203850c95fdSChuck Lever  * to be called when the status manager receives notification
204850c95fdSChuck Lever  * (via the SM_NOTIFY call) that the state of host "mon_name"
205850c95fdSChuck Lever  * has changed.
206850c95fdSChuck Lever  */
207850c95fdSChuck Lever static __be32 *xdr_encode_my_id(__be32 *p, struct nsm_args *argp)
208850c95fdSChuck Lever {
209850c95fdSChuck Lever 	p = xdr_encode_nsm_string(p, utsname()->nodename);
210850c95fdSChuck Lever 	if (!p)
211850c95fdSChuck Lever 		return ERR_PTR(-EIO);
212850c95fdSChuck Lever 
213850c95fdSChuck Lever 	*p++ = htonl(argp->prog);
214850c95fdSChuck Lever 	*p++ = htonl(argp->vers);
215850c95fdSChuck Lever 	*p++ = htonl(argp->proc);
216850c95fdSChuck Lever 
217850c95fdSChuck Lever 	return p;
218850c95fdSChuck Lever }
219850c95fdSChuck Lever 
220ea72a7f1SChuck Lever /*
221ea72a7f1SChuck Lever  * The "mon_id" argument specifies the non-private arguments
222ea72a7f1SChuck Lever  * of an SM_MON or SM_UNMON call.
223ea72a7f1SChuck Lever  */
224ea72a7f1SChuck Lever static __be32 *xdr_encode_mon_id(__be32 *p, struct nsm_args *argp)
225ea72a7f1SChuck Lever {
226ea72a7f1SChuck Lever 	p = xdr_encode_mon_name(p, argp);
227ea72a7f1SChuck Lever 	if (!p)
228ea72a7f1SChuck Lever 		return ERR_PTR(-EIO);
229ea72a7f1SChuck Lever 
230ea72a7f1SChuck Lever 	return xdr_encode_my_id(p, argp);
231ea72a7f1SChuck Lever }
232ea72a7f1SChuck Lever 
2330490a54aSChuck Lever /*
2340490a54aSChuck Lever  * The "priv" argument may contain private information required
2350490a54aSChuck Lever  * by the SM_MON call. This information will be supplied in the
2360490a54aSChuck Lever  * SM_NOTIFY call.
2370490a54aSChuck Lever  *
2380490a54aSChuck Lever  * Linux provides the raw IP address of the monitored host,
2390490a54aSChuck Lever  * left in network byte order.
2400490a54aSChuck Lever  */
2410490a54aSChuck Lever static __be32 *xdr_encode_priv(__be32 *p, struct nsm_args *argp)
2420490a54aSChuck Lever {
2430490a54aSChuck Lever 	*p++ = argp->addr;
2440490a54aSChuck Lever 	*p++ = 0;
2450490a54aSChuck Lever 	*p++ = 0;
2460490a54aSChuck Lever 	*p++ = 0;
2470490a54aSChuck Lever 
2480490a54aSChuck Lever 	return p;
2490490a54aSChuck Lever }
2500490a54aSChuck Lever 
2511da177e4SLinus Torvalds static int
25252921e02SAl Viro xdr_encode_mon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
2531da177e4SLinus Torvalds {
2542ca7754dSChuck Lever 	p = xdr_encode_mon_id(p, argp);
2551da177e4SLinus Torvalds 	if (IS_ERR(p))
2561da177e4SLinus Torvalds 		return PTR_ERR(p);
2579502c522SOlaf Kirch 
2580490a54aSChuck Lever 	p = xdr_encode_priv(p, argp);
2590490a54aSChuck Lever 	if (IS_ERR(p))
2600490a54aSChuck Lever 		return PTR_ERR(p);
2610490a54aSChuck Lever 
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_encode_unmon(struct rpc_rqst *rqstp, __be32 *p, struct nsm_args *argp)
2681da177e4SLinus Torvalds {
2692ca7754dSChuck Lever 	p = xdr_encode_mon_id(p, argp);
2701da177e4SLinus Torvalds 	if (IS_ERR(p))
2711da177e4SLinus Torvalds 		return PTR_ERR(p);
2721da177e4SLinus Torvalds 	rqstp->rq_slen = xdr_adjust_iovec(rqstp->rq_svec, p);
2731da177e4SLinus Torvalds 	return 0;
2741da177e4SLinus Torvalds }
2751da177e4SLinus Torvalds 
2761da177e4SLinus Torvalds static int
27752921e02SAl Viro xdr_decode_stat_res(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
2781da177e4SLinus Torvalds {
2791da177e4SLinus Torvalds 	resp->status = ntohl(*p++);
2801da177e4SLinus Torvalds 	resp->state = ntohl(*p++);
2811da177e4SLinus Torvalds 	dprintk("nsm: xdr_decode_stat_res status %d state %d\n",
2821da177e4SLinus Torvalds 			resp->status, resp->state);
2831da177e4SLinus Torvalds 	return 0;
2841da177e4SLinus Torvalds }
2851da177e4SLinus Torvalds 
2861da177e4SLinus Torvalds static int
28752921e02SAl Viro xdr_decode_stat(struct rpc_rqst *rqstp, __be32 *p, struct nsm_res *resp)
2881da177e4SLinus Torvalds {
2891da177e4SLinus Torvalds 	resp->state = ntohl(*p++);
2901da177e4SLinus Torvalds 	return 0;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds 
2931da177e4SLinus Torvalds #define SM_my_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
2942ca7754dSChuck Lever #define SM_my_id_sz	(SM_my_name_sz+3)
2952ca7754dSChuck Lever #define SM_mon_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
2962ca7754dSChuck Lever #define SM_mon_id_sz	(SM_mon_name_sz+SM_my_id_sz)
2970490a54aSChuck Lever #define SM_priv_sz	(XDR_QUADLEN(SM_PRIV_SIZE))
2980490a54aSChuck Lever #define SM_mon_sz	(SM_mon_id_sz+SM_priv_sz)
2991da177e4SLinus Torvalds #define SM_monres_sz	2
3001da177e4SLinus Torvalds #define SM_unmonres_sz	1
3011da177e4SLinus Torvalds 
3021da177e4SLinus Torvalds static struct rpc_procinfo	nsm_procedures[] = {
3031da177e4SLinus Torvalds [SM_MON] = {
3041da177e4SLinus Torvalds 		.p_proc		= SM_MON,
3051da177e4SLinus Torvalds 		.p_encode	= (kxdrproc_t) xdr_encode_mon,
3061da177e4SLinus Torvalds 		.p_decode	= (kxdrproc_t) xdr_decode_stat_res,
3072bea90d4SChuck Lever 		.p_arglen	= SM_mon_sz,
3082bea90d4SChuck Lever 		.p_replen	= SM_monres_sz,
309cc0175c1SChuck Lever 		.p_statidx	= SM_MON,
310cc0175c1SChuck Lever 		.p_name		= "MONITOR",
3111da177e4SLinus Torvalds 	},
3121da177e4SLinus Torvalds [SM_UNMON] = {
3131da177e4SLinus Torvalds 		.p_proc		= SM_UNMON,
3141da177e4SLinus Torvalds 		.p_encode	= (kxdrproc_t) xdr_encode_unmon,
3151da177e4SLinus Torvalds 		.p_decode	= (kxdrproc_t) xdr_decode_stat,
3162bea90d4SChuck Lever 		.p_arglen	= SM_mon_id_sz,
3172bea90d4SChuck Lever 		.p_replen	= SM_unmonres_sz,
318cc0175c1SChuck Lever 		.p_statidx	= SM_UNMON,
319cc0175c1SChuck Lever 		.p_name		= "UNMONITOR",
3201da177e4SLinus Torvalds 	},
3211da177e4SLinus Torvalds };
3221da177e4SLinus Torvalds 
3231da177e4SLinus Torvalds static struct rpc_version	nsm_version1 = {
3241da177e4SLinus Torvalds 		.number		= 1,
325e8c96f8cSTobias Klauser 		.nrprocs	= ARRAY_SIZE(nsm_procedures),
3261da177e4SLinus Torvalds 		.procs		= nsm_procedures
3271da177e4SLinus Torvalds };
3281da177e4SLinus Torvalds 
3291da177e4SLinus Torvalds static struct rpc_version *	nsm_version[] = {
3301da177e4SLinus Torvalds 	[1] = &nsm_version1,
3311da177e4SLinus Torvalds };
3321da177e4SLinus Torvalds 
3331da177e4SLinus Torvalds static struct rpc_stat		nsm_stats;
3341da177e4SLinus Torvalds 
3351da177e4SLinus Torvalds static struct rpc_program	nsm_program = {
3361da177e4SLinus Torvalds 		.name		= "statd",
3371da177e4SLinus Torvalds 		.number		= SM_PROGRAM,
338e8c96f8cSTobias Klauser 		.nrvers		= ARRAY_SIZE(nsm_version),
3391da177e4SLinus Torvalds 		.version	= nsm_version,
3401da177e4SLinus Torvalds 		.stats		= &nsm_stats
3411da177e4SLinus Torvalds };
342