xref: /openbmc/linux/fs/lockd/mon.c (revision 67c6d107a689243979a2b5f15244b5261634a924)
1 /*
2  * linux/fs/lockd/mon.c
3  *
4  * The kernel statd client.
5  *
6  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
7  */
8 
9 #include <linux/types.h>
10 #include <linux/utsname.h>
11 #include <linux/kernel.h>
12 #include <linux/sunrpc/clnt.h>
13 #include <linux/sunrpc/xprtsock.h>
14 #include <linux/sunrpc/svc.h>
15 #include <linux/lockd/lockd.h>
16 #include <linux/lockd/sm_inter.h>
17 
18 
19 #define NLMDBG_FACILITY		NLMDBG_MONITOR
20 #define NSM_PROGRAM		100024
21 #define NSM_VERSION		1
22 
23 enum {
24 	NSMPROC_NULL,
25 	NSMPROC_STAT,
26 	NSMPROC_MON,
27 	NSMPROC_UNMON,
28 	NSMPROC_UNMON_ALL,
29 	NSMPROC_SIMU_CRASH,
30 	NSMPROC_NOTIFY,
31 };
32 
33 struct nsm_args {
34 	__be32			addr;		/* remote address */
35 	u32			prog;		/* RPC callback info */
36 	u32			vers;
37 	u32			proc;
38 
39 	char			*mon_name;
40 };
41 
42 struct nsm_res {
43 	u32			status;
44 	u32			state;
45 };
46 
47 static struct rpc_clnt *	nsm_create(void);
48 
49 static struct rpc_program	nsm_program;
50 static				LIST_HEAD(nsm_handles);
51 static				DEFINE_SPINLOCK(nsm_lock);
52 
53 /*
54  * Local NSM state
55  */
56 int				nsm_local_state;
57 
58 static void nsm_display_ipv4_address(const struct sockaddr *sap, char *buf,
59 				     const size_t len)
60 {
61 	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
62 	snprintf(buf, len, "%pI4", &sin->sin_addr.s_addr);
63 }
64 
65 static void nsm_display_ipv6_address(const struct sockaddr *sap, char *buf,
66 				     const size_t len)
67 {
68 	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
69 
70 	if (ipv6_addr_v4mapped(&sin6->sin6_addr))
71 		snprintf(buf, len, "%pI4", &sin6->sin6_addr.s6_addr32[3]);
72 	else if (sin6->sin6_scope_id != 0)
73 		snprintf(buf, len, "%pI6%%%u", &sin6->sin6_addr,
74 				sin6->sin6_scope_id);
75 	else
76 		snprintf(buf, len, "%pI6", &sin6->sin6_addr);
77 }
78 
79 static void nsm_display_address(const struct sockaddr *sap,
80 				char *buf, const size_t len)
81 {
82 	switch (sap->sa_family) {
83 	case AF_INET:
84 		nsm_display_ipv4_address(sap, buf, len);
85 		break;
86 	case AF_INET6:
87 		nsm_display_ipv6_address(sap, buf, len);
88 		break;
89 	default:
90 		snprintf(buf, len, "unsupported address family");
91 		break;
92 	}
93 }
94 
95 /*
96  * Common procedure for NSMPROC_MON/NSMPROC_UNMON calls
97  */
98 static int
99 nsm_mon_unmon(struct nsm_handle *nsm, u32 proc, struct nsm_res *res)
100 {
101 	struct rpc_clnt	*clnt;
102 	int		status;
103 	struct nsm_args args = {
104 		.addr		= nsm_addr_in(nsm)->sin_addr.s_addr,
105 		.prog		= NLM_PROGRAM,
106 		.vers		= 3,
107 		.proc		= NLMPROC_NSM_NOTIFY,
108 		.mon_name	= nsm->sm_mon_name,
109 	};
110 	struct rpc_message msg = {
111 		.rpc_argp	= &args,
112 		.rpc_resp	= res,
113 	};
114 
115 	clnt = nsm_create();
116 	if (IS_ERR(clnt)) {
117 		status = PTR_ERR(clnt);
118 		dprintk("lockd: failed to create NSM upcall transport, "
119 				"status=%d\n", status);
120 		goto out;
121 	}
122 
123 	memset(res, 0, sizeof(*res));
124 
125 	msg.rpc_proc = &clnt->cl_procinfo[proc];
126 	status = rpc_call_sync(clnt, &msg, 0);
127 	if (status < 0)
128 		dprintk("lockd: NSM upcall RPC failed, status=%d\n",
129 				status);
130 	else
131 		status = 0;
132 	rpc_shutdown_client(clnt);
133  out:
134 	return status;
135 }
136 
137 /**
138  * nsm_monitor - Notify a peer in case we reboot
139  * @host: pointer to nlm_host of peer to notify
140  *
141  * If this peer is not already monitored, this function sends an
142  * upcall to the local rpc.statd to record the name/address of
143  * the peer to notify in case we reboot.
144  *
145  * Returns zero if the peer is monitored by the local rpc.statd;
146  * otherwise a negative errno value is returned.
147  */
148 int nsm_monitor(const struct nlm_host *host)
149 {
150 	struct nsm_handle *nsm = host->h_nsmhandle;
151 	struct nsm_res	res;
152 	int		status;
153 
154 	dprintk("lockd: nsm_monitor(%s)\n", nsm->sm_name);
155 
156 	if (nsm->sm_monitored)
157 		return 0;
158 
159 	/*
160 	 * Choose whether to record the caller_name or IP address of
161 	 * this peer in the local rpc.statd's database.
162 	 */
163 	nsm->sm_mon_name = nsm_use_hostnames ? nsm->sm_name : nsm->sm_addrbuf;
164 
165 	status = nsm_mon_unmon(nsm, NSMPROC_MON, &res);
166 	if (res.status != 0)
167 		status = -EIO;
168 	if (status < 0)
169 		printk(KERN_NOTICE "lockd: cannot monitor %s\n", nsm->sm_name);
170 	else
171 		nsm->sm_monitored = 1;
172 	return status;
173 }
174 
175 /**
176  * nsm_unmonitor - Unregister peer notification
177  * @host: pointer to nlm_host of peer to stop monitoring
178  *
179  * If this peer is monitored, this function sends an upcall to
180  * tell the local rpc.statd not to send this peer a notification
181  * when we reboot.
182  */
183 void nsm_unmonitor(const struct nlm_host *host)
184 {
185 	struct nsm_handle *nsm = host->h_nsmhandle;
186 	struct nsm_res	res;
187 	int status;
188 
189 	if (atomic_read(&nsm->sm_count) == 1
190 	 && nsm->sm_monitored && !nsm->sm_sticky) {
191 		dprintk("lockd: nsm_unmonitor(%s)\n", nsm->sm_name);
192 
193 		status = nsm_mon_unmon(nsm, NSMPROC_UNMON, &res);
194 		if (res.status != 0)
195 			status = -EIO;
196 		if (status < 0)
197 			printk(KERN_NOTICE "lockd: cannot unmonitor %s\n",
198 					nsm->sm_name);
199 		else
200 			nsm->sm_monitored = 0;
201 	}
202 }
203 
204 /**
205  * nsm_find - Find or create a cached nsm_handle
206  * @sap: pointer to socket address of handle to find
207  * @salen: length of socket address
208  * @hostname: pointer to C string containing hostname to find
209  * @hostname_len: length of C string
210  * @create: one means create new handle if not found in cache
211  *
212  * Behavior is modulated by the global nsm_use_hostnames variable
213  * and by the @create argument.
214  *
215  * Returns a cached nsm_handle after bumping its ref count, or if
216  * @create is set, returns a fresh nsm_handle if a handle that
217  * matches @sap and/or @hostname cannot be found in the handle cache.
218  * Returns NULL if an error occurs.
219  */
220 struct nsm_handle *nsm_find(const struct sockaddr *sap, const size_t salen,
221 			    const char *hostname, const size_t hostname_len,
222 			    const int create)
223 {
224 	struct nsm_handle *nsm = NULL;
225 	struct nsm_handle *pos;
226 
227 	if (!sap)
228 		return NULL;
229 
230 	if (hostname && memchr(hostname, '/', hostname_len) != NULL) {
231 		if (printk_ratelimit()) {
232 			printk(KERN_WARNING "Invalid hostname \"%.*s\" "
233 					    "in NFS lock request\n",
234 				(int)hostname_len, hostname);
235 		}
236 		return NULL;
237 	}
238 
239 retry:
240 	spin_lock(&nsm_lock);
241 	list_for_each_entry(pos, &nsm_handles, sm_link) {
242 
243 		if (hostname && nsm_use_hostnames) {
244 			if (strlen(pos->sm_name) != hostname_len
245 			 || memcmp(pos->sm_name, hostname, hostname_len))
246 				continue;
247 		} else if (!nlm_cmp_addr(nsm_addr(pos), sap))
248 			continue;
249 		atomic_inc(&pos->sm_count);
250 		kfree(nsm);
251 		nsm = pos;
252 		goto found;
253 	}
254 	if (nsm) {
255 		list_add(&nsm->sm_link, &nsm_handles);
256 		goto found;
257 	}
258 	spin_unlock(&nsm_lock);
259 
260 	if (!create)
261 		return NULL;
262 
263 	nsm = kzalloc(sizeof(*nsm) + hostname_len + 1, GFP_KERNEL);
264 	if (nsm == NULL)
265 		return NULL;
266 
267 	memcpy(nsm_addr(nsm), sap, salen);
268 	nsm->sm_addrlen = salen;
269 	nsm->sm_name = (char *) (nsm + 1);
270 	memcpy(nsm->sm_name, hostname, hostname_len);
271 	nsm->sm_name[hostname_len] = '\0';
272 	nsm_display_address((struct sockaddr *)&nsm->sm_addr,
273 				nsm->sm_addrbuf, sizeof(nsm->sm_addrbuf));
274 	atomic_set(&nsm->sm_count, 1);
275 	goto retry;
276 
277 found:
278 	spin_unlock(&nsm_lock);
279 	return nsm;
280 }
281 
282 /**
283  * nsm_release - Release an NSM handle
284  * @nsm: pointer to handle to be released
285  *
286  */
287 void nsm_release(struct nsm_handle *nsm)
288 {
289 	if (!nsm)
290 		return;
291 	if (atomic_dec_and_lock(&nsm->sm_count, &nsm_lock)) {
292 		list_del(&nsm->sm_link);
293 		spin_unlock(&nsm_lock);
294 		kfree(nsm);
295 	}
296 }
297 
298 /*
299  * Create NSM client for the local host
300  */
301 static struct rpc_clnt *
302 nsm_create(void)
303 {
304 	struct sockaddr_in	sin = {
305 		.sin_family	= AF_INET,
306 		.sin_addr.s_addr = htonl(INADDR_LOOPBACK),
307 		.sin_port	= 0,
308 	};
309 	struct rpc_create_args args = {
310 		.protocol	= XPRT_TRANSPORT_UDP,
311 		.address	= (struct sockaddr *)&sin,
312 		.addrsize	= sizeof(sin),
313 		.servername	= "localhost",
314 		.program	= &nsm_program,
315 		.version	= NSM_VERSION,
316 		.authflavor	= RPC_AUTH_NULL,
317 	};
318 
319 	return rpc_create(&args);
320 }
321 
322 /*
323  * XDR functions for NSM.
324  *
325  * See http://www.opengroup.org/ for details on the Network
326  * Status Monitor wire protocol.
327  */
328 
329 static int encode_nsm_string(struct xdr_stream *xdr, const char *string)
330 {
331 	const u32 len = strlen(string);
332 	__be32 *p;
333 
334 	if (unlikely(len > SM_MAXSTRLEN))
335 		return -EIO;
336 	p = xdr_reserve_space(xdr, sizeof(u32) + len);
337 	if (unlikely(p == NULL))
338 		return -EIO;
339 	xdr_encode_opaque(p, string, len);
340 	return 0;
341 }
342 
343 /*
344  * "mon_name" specifies the host to be monitored.
345  */
346 static int encode_mon_name(struct xdr_stream *xdr, const struct nsm_args *argp)
347 {
348 	return encode_nsm_string(xdr, argp->mon_name);
349 }
350 
351 /*
352  * The "my_id" argument specifies the hostname and RPC procedure
353  * to be called when the status manager receives notification
354  * (via the NLMPROC_SM_NOTIFY call) that the state of host "mon_name"
355  * has changed.
356  */
357 static int encode_my_id(struct xdr_stream *xdr, const struct nsm_args *argp)
358 {
359 	int status;
360 	__be32 *p;
361 
362 	status = encode_nsm_string(xdr, utsname()->nodename);
363 	if (unlikely(status != 0))
364 		return status;
365 	p = xdr_reserve_space(xdr, 3 * sizeof(u32));
366 	if (unlikely(p == NULL))
367 		return -EIO;
368 	*p++ = htonl(argp->prog);
369 	*p++ = htonl(argp->vers);
370 	*p++ = htonl(argp->proc);
371 	return 0;
372 }
373 
374 /*
375  * The "mon_id" argument specifies the non-private arguments
376  * of an NSMPROC_MON or NSMPROC_UNMON call.
377  */
378 static int encode_mon_id(struct xdr_stream *xdr, const struct nsm_args *argp)
379 {
380 	int status;
381 
382 	status = encode_mon_name(xdr, argp);
383 	if (unlikely(status != 0))
384 		return status;
385 	return encode_my_id(xdr, argp);
386 }
387 
388 /*
389  * The "priv" argument may contain private information required
390  * by the NSMPROC_MON call. This information will be supplied in the
391  * NLMPROC_SM_NOTIFY call.
392  *
393  * Linux provides the raw IP address of the monitored host,
394  * left in network byte order.
395  */
396 static int encode_priv(struct xdr_stream *xdr, const struct nsm_args *argp)
397 {
398 	__be32 *p;
399 
400 	p = xdr_reserve_space(xdr, SM_PRIV_SIZE);
401 	if (unlikely(p == NULL))
402 		return -EIO;
403 	*p++ = argp->addr;
404 	*p++ = 0;
405 	*p++ = 0;
406 	*p++ = 0;
407 	return 0;
408 }
409 
410 static int xdr_enc_mon(struct rpc_rqst *req, __be32 *p,
411 		       const struct nsm_args *argp)
412 {
413 	struct xdr_stream xdr;
414 	int status;
415 
416 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
417 	status = encode_mon_id(&xdr, argp);
418 	if (unlikely(status))
419 		return status;
420 	return encode_priv(&xdr, argp);
421 }
422 
423 static int xdr_enc_unmon(struct rpc_rqst *req, __be32 *p,
424 			 const struct nsm_args *argp)
425 {
426 	struct xdr_stream xdr;
427 
428 	xdr_init_encode(&xdr, &req->rq_snd_buf, p);
429 	return encode_mon_id(&xdr, argp);
430 }
431 
432 static int xdr_dec_stat_res(struct rpc_rqst *rqstp, __be32 *p,
433 			    struct nsm_res *resp)
434 {
435 	struct xdr_stream xdr;
436 
437 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
438 	p = xdr_inline_decode(&xdr, 2 * sizeof(u32));
439 	if (unlikely(p == NULL))
440 		return -EIO;
441 	resp->status = ntohl(*p++);
442 	resp->state = ntohl(*p);
443 
444 	dprintk("lockd: xdr_dec_stat_res status %d state %d\n",
445 			resp->status, resp->state);
446 	return 0;
447 }
448 
449 static int xdr_dec_stat(struct rpc_rqst *rqstp, __be32 *p,
450 			struct nsm_res *resp)
451 {
452 	struct xdr_stream xdr;
453 
454 	xdr_init_decode(&xdr, &rqstp->rq_rcv_buf, p);
455 	p = xdr_inline_decode(&xdr, sizeof(u32));
456 	if (unlikely(p == NULL))
457 		return -EIO;
458 	resp->state = ntohl(*p);
459 
460 	dprintk("lockd: xdr_dec_stat state %d\n", resp->state);
461 	return 0;
462 }
463 
464 #define SM_my_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
465 #define SM_my_id_sz	(SM_my_name_sz+3)
466 #define SM_mon_name_sz	(1+XDR_QUADLEN(SM_MAXSTRLEN))
467 #define SM_mon_id_sz	(SM_mon_name_sz+SM_my_id_sz)
468 #define SM_priv_sz	(XDR_QUADLEN(SM_PRIV_SIZE))
469 #define SM_mon_sz	(SM_mon_id_sz+SM_priv_sz)
470 #define SM_monres_sz	2
471 #define SM_unmonres_sz	1
472 
473 static struct rpc_procinfo	nsm_procedures[] = {
474 [NSMPROC_MON] = {
475 		.p_proc		= NSMPROC_MON,
476 		.p_encode	= (kxdrproc_t)xdr_enc_mon,
477 		.p_decode	= (kxdrproc_t)xdr_dec_stat_res,
478 		.p_arglen	= SM_mon_sz,
479 		.p_replen	= SM_monres_sz,
480 		.p_statidx	= NSMPROC_MON,
481 		.p_name		= "MONITOR",
482 	},
483 [NSMPROC_UNMON] = {
484 		.p_proc		= NSMPROC_UNMON,
485 		.p_encode	= (kxdrproc_t)xdr_enc_unmon,
486 		.p_decode	= (kxdrproc_t)xdr_dec_stat,
487 		.p_arglen	= SM_mon_id_sz,
488 		.p_replen	= SM_unmonres_sz,
489 		.p_statidx	= NSMPROC_UNMON,
490 		.p_name		= "UNMONITOR",
491 	},
492 };
493 
494 static struct rpc_version	nsm_version1 = {
495 		.number		= 1,
496 		.nrprocs	= ARRAY_SIZE(nsm_procedures),
497 		.procs		= nsm_procedures
498 };
499 
500 static struct rpc_version *	nsm_version[] = {
501 	[1] = &nsm_version1,
502 };
503 
504 static struct rpc_stat		nsm_stats;
505 
506 static struct rpc_program	nsm_program = {
507 		.name		= "statd",
508 		.number		= NSM_PROGRAM,
509 		.nrvers		= ARRAY_SIZE(nsm_version),
510 		.version	= nsm_version,
511 		.stats		= &nsm_stats
512 };
513