xref: /openbmc/linux/fs/lockd/host.c (revision 93d90ad7)
1 /*
2  * linux/fs/lockd/host.c
3  *
4  * Management for NLM peer hosts. The nlm_host struct is shared
5  * between client and server implementation. The only reason to
6  * do so is to reduce code bloat.
7  *
8  * Copyright (C) 1996, Olaf Kirch <okir@monad.swb.de>
9  */
10 
11 #include <linux/types.h>
12 #include <linux/slab.h>
13 #include <linux/in.h>
14 #include <linux/in6.h>
15 #include <linux/sunrpc/clnt.h>
16 #include <linux/sunrpc/addr.h>
17 #include <linux/sunrpc/svc.h>
18 #include <linux/lockd/lockd.h>
19 #include <linux/mutex.h>
20 
21 #include <linux/sunrpc/svc_xprt.h>
22 
23 #include <net/ipv6.h>
24 
25 #include "netns.h"
26 
27 #define NLMDBG_FACILITY		NLMDBG_HOSTCACHE
28 #define NLM_HOST_NRHASH		32
29 #define NLM_HOST_REBIND		(60 * HZ)
30 #define NLM_HOST_EXPIRE		(300 * HZ)
31 #define NLM_HOST_COLLECT	(120 * HZ)
32 
33 static struct hlist_head	nlm_server_hosts[NLM_HOST_NRHASH];
34 static struct hlist_head	nlm_client_hosts[NLM_HOST_NRHASH];
35 
36 #define for_each_host(host, chain, table) \
37 	for ((chain) = (table); \
38 	     (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
39 		hlist_for_each_entry((host), (chain), h_hash)
40 
41 #define for_each_host_safe(host, next, chain, table) \
42 	for ((chain) = (table); \
43 	     (chain) < (table) + NLM_HOST_NRHASH; ++(chain)) \
44 		hlist_for_each_entry_safe((host), (next), \
45 						(chain), h_hash)
46 
47 static unsigned long		nrhosts;
48 static DEFINE_MUTEX(nlm_host_mutex);
49 
50 static void			nlm_gc_hosts(struct net *net);
51 
52 struct nlm_lookup_host_info {
53 	const int		server;		/* search for server|client */
54 	const struct sockaddr	*sap;		/* address to search for */
55 	const size_t		salen;		/* it's length */
56 	const unsigned short	protocol;	/* transport to search for*/
57 	const u32		version;	/* NLM version to search for */
58 	const char		*hostname;	/* remote's hostname */
59 	const size_t		hostname_len;	/* it's length */
60 	const int		noresvport;	/* use non-priv port */
61 	struct net		*net;		/* network namespace to bind */
62 };
63 
64 /*
65  * Hash function must work well on big- and little-endian platforms
66  */
67 static unsigned int __nlm_hash32(const __be32 n)
68 {
69 	unsigned int hash = (__force u32)n ^ ((__force u32)n >> 16);
70 	return hash ^ (hash >> 8);
71 }
72 
73 static unsigned int __nlm_hash_addr4(const struct sockaddr *sap)
74 {
75 	const struct sockaddr_in *sin = (struct sockaddr_in *)sap;
76 	return __nlm_hash32(sin->sin_addr.s_addr);
77 }
78 
79 static unsigned int __nlm_hash_addr6(const struct sockaddr *sap)
80 {
81 	const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sap;
82 	const struct in6_addr addr = sin6->sin6_addr;
83 	return __nlm_hash32(addr.s6_addr32[0]) ^
84 	       __nlm_hash32(addr.s6_addr32[1]) ^
85 	       __nlm_hash32(addr.s6_addr32[2]) ^
86 	       __nlm_hash32(addr.s6_addr32[3]);
87 }
88 
89 static unsigned int nlm_hash_address(const struct sockaddr *sap)
90 {
91 	unsigned int hash;
92 
93 	switch (sap->sa_family) {
94 	case AF_INET:
95 		hash = __nlm_hash_addr4(sap);
96 		break;
97 	case AF_INET6:
98 		hash = __nlm_hash_addr6(sap);
99 		break;
100 	default:
101 		hash = 0;
102 	}
103 	return hash & (NLM_HOST_NRHASH - 1);
104 }
105 
106 /*
107  * Allocate and initialize an nlm_host.  Common to both client and server.
108  */
109 static struct nlm_host *nlm_alloc_host(struct nlm_lookup_host_info *ni,
110 				       struct nsm_handle *nsm)
111 {
112 	struct nlm_host *host = NULL;
113 	unsigned long now = jiffies;
114 
115 	if (nsm != NULL)
116 		atomic_inc(&nsm->sm_count);
117 	else {
118 		host = NULL;
119 		nsm = nsm_get_handle(ni->sap, ni->salen,
120 					ni->hostname, ni->hostname_len);
121 		if (unlikely(nsm == NULL)) {
122 			dprintk("lockd: %s failed; no nsm handle\n",
123 				__func__);
124 			goto out;
125 		}
126 	}
127 
128 	host = kmalloc(sizeof(*host), GFP_KERNEL);
129 	if (unlikely(host == NULL)) {
130 		dprintk("lockd: %s failed; no memory\n", __func__);
131 		nsm_release(nsm);
132 		goto out;
133 	}
134 
135 	memcpy(nlm_addr(host), ni->sap, ni->salen);
136 	host->h_addrlen    = ni->salen;
137 	rpc_set_port(nlm_addr(host), 0);
138 	host->h_srcaddrlen = 0;
139 
140 	host->h_rpcclnt    = NULL;
141 	host->h_name	   = nsm->sm_name;
142 	host->h_version    = ni->version;
143 	host->h_proto      = ni->protocol;
144 	host->h_reclaiming = 0;
145 	host->h_server     = ni->server;
146 	host->h_noresvport = ni->noresvport;
147 	host->h_inuse      = 0;
148 	init_waitqueue_head(&host->h_gracewait);
149 	init_rwsem(&host->h_rwsem);
150 	host->h_state      = 0;
151 	host->h_nsmstate   = 0;
152 	host->h_pidcount   = 0;
153 	atomic_set(&host->h_count, 1);
154 	mutex_init(&host->h_mutex);
155 	host->h_nextrebind = now + NLM_HOST_REBIND;
156 	host->h_expires    = now + NLM_HOST_EXPIRE;
157 	INIT_LIST_HEAD(&host->h_lockowners);
158 	spin_lock_init(&host->h_lock);
159 	INIT_LIST_HEAD(&host->h_granted);
160 	INIT_LIST_HEAD(&host->h_reclaim);
161 	host->h_nsmhandle  = nsm;
162 	host->h_addrbuf    = nsm->sm_addrbuf;
163 	host->net	   = ni->net;
164 
165 out:
166 	return host;
167 }
168 
169 /*
170  * Destroy an nlm_host and free associated resources
171  *
172  * Caller must hold nlm_host_mutex.
173  */
174 static void nlm_destroy_host_locked(struct nlm_host *host)
175 {
176 	struct rpc_clnt	*clnt;
177 	struct lockd_net *ln = net_generic(host->net, lockd_net_id);
178 
179 	dprintk("lockd: destroy host %s\n", host->h_name);
180 
181 	hlist_del_init(&host->h_hash);
182 
183 	nsm_unmonitor(host);
184 	nsm_release(host->h_nsmhandle);
185 
186 	clnt = host->h_rpcclnt;
187 	if (clnt != NULL)
188 		rpc_shutdown_client(clnt);
189 	kfree(host);
190 
191 	ln->nrhosts--;
192 	nrhosts--;
193 }
194 
195 /**
196  * nlmclnt_lookup_host - Find an NLM host handle matching a remote server
197  * @sap: network address of server
198  * @salen: length of server address
199  * @protocol: transport protocol to use
200  * @version: NLM protocol version
201  * @hostname: '\0'-terminated hostname of server
202  * @noresvport: 1 if non-privileged port should be used
203  *
204  * Returns an nlm_host structure that matches the passed-in
205  * [server address, transport protocol, NLM version, server hostname].
206  * If one doesn't already exist in the host cache, a new handle is
207  * created and returned.
208  */
209 struct nlm_host *nlmclnt_lookup_host(const struct sockaddr *sap,
210 				     const size_t salen,
211 				     const unsigned short protocol,
212 				     const u32 version,
213 				     const char *hostname,
214 				     int noresvport,
215 				     struct net *net)
216 {
217 	struct nlm_lookup_host_info ni = {
218 		.server		= 0,
219 		.sap		= sap,
220 		.salen		= salen,
221 		.protocol	= protocol,
222 		.version	= version,
223 		.hostname	= hostname,
224 		.hostname_len	= strlen(hostname),
225 		.noresvport	= noresvport,
226 		.net		= net,
227 	};
228 	struct hlist_head *chain;
229 	struct nlm_host	*host;
230 	struct nsm_handle *nsm = NULL;
231 	struct lockd_net *ln = net_generic(net, lockd_net_id);
232 
233 	dprintk("lockd: %s(host='%s', vers=%u, proto=%s)\n", __func__,
234 			(hostname ? hostname : "<none>"), version,
235 			(protocol == IPPROTO_UDP ? "udp" : "tcp"));
236 
237 	mutex_lock(&nlm_host_mutex);
238 
239 	chain = &nlm_client_hosts[nlm_hash_address(sap)];
240 	hlist_for_each_entry(host, chain, h_hash) {
241 		if (host->net != net)
242 			continue;
243 		if (!rpc_cmp_addr(nlm_addr(host), sap))
244 			continue;
245 
246 		/* Same address. Share an NSM handle if we already have one */
247 		if (nsm == NULL)
248 			nsm = host->h_nsmhandle;
249 
250 		if (host->h_proto != protocol)
251 			continue;
252 		if (host->h_version != version)
253 			continue;
254 
255 		nlm_get_host(host);
256 		dprintk("lockd: %s found host %s (%s)\n", __func__,
257 			host->h_name, host->h_addrbuf);
258 		goto out;
259 	}
260 
261 	host = nlm_alloc_host(&ni, nsm);
262 	if (unlikely(host == NULL))
263 		goto out;
264 
265 	hlist_add_head(&host->h_hash, chain);
266 	ln->nrhosts++;
267 	nrhosts++;
268 
269 	dprintk("lockd: %s created host %s (%s)\n", __func__,
270 		host->h_name, host->h_addrbuf);
271 
272 out:
273 	mutex_unlock(&nlm_host_mutex);
274 	return host;
275 }
276 
277 /**
278  * nlmclnt_release_host - release client nlm_host
279  * @host: nlm_host to release
280  *
281  */
282 void nlmclnt_release_host(struct nlm_host *host)
283 {
284 	if (host == NULL)
285 		return;
286 
287 	dprintk("lockd: release client host %s\n", host->h_name);
288 
289 	WARN_ON_ONCE(host->h_server);
290 
291 	if (atomic_dec_and_test(&host->h_count)) {
292 		WARN_ON_ONCE(!list_empty(&host->h_lockowners));
293 		WARN_ON_ONCE(!list_empty(&host->h_granted));
294 		WARN_ON_ONCE(!list_empty(&host->h_reclaim));
295 
296 		mutex_lock(&nlm_host_mutex);
297 		nlm_destroy_host_locked(host);
298 		mutex_unlock(&nlm_host_mutex);
299 	}
300 }
301 
302 /**
303  * nlmsvc_lookup_host - Find an NLM host handle matching a remote client
304  * @rqstp: incoming NLM request
305  * @hostname: name of client host
306  * @hostname_len: length of client hostname
307  *
308  * Returns an nlm_host structure that matches the [client address,
309  * transport protocol, NLM version, client hostname] of the passed-in
310  * NLM request.  If one doesn't already exist in the host cache, a
311  * new handle is created and returned.
312  *
313  * Before possibly creating a new nlm_host, construct a sockaddr
314  * for a specific source address in case the local system has
315  * multiple network addresses.  The family of the address in
316  * rq_daddr is guaranteed to be the same as the family of the
317  * address in rq_addr, so it's safe to use the same family for
318  * the source address.
319  */
320 struct nlm_host *nlmsvc_lookup_host(const struct svc_rqst *rqstp,
321 				    const char *hostname,
322 				    const size_t hostname_len)
323 {
324 	struct hlist_head *chain;
325 	struct nlm_host	*host = NULL;
326 	struct nsm_handle *nsm = NULL;
327 	struct sockaddr *src_sap = svc_daddr(rqstp);
328 	size_t src_len = rqstp->rq_daddrlen;
329 	struct net *net = SVC_NET(rqstp);
330 	struct nlm_lookup_host_info ni = {
331 		.server		= 1,
332 		.sap		= svc_addr(rqstp),
333 		.salen		= rqstp->rq_addrlen,
334 		.protocol	= rqstp->rq_prot,
335 		.version	= rqstp->rq_vers,
336 		.hostname	= hostname,
337 		.hostname_len	= hostname_len,
338 		.net		= net,
339 	};
340 	struct lockd_net *ln = net_generic(net, lockd_net_id);
341 
342 	dprintk("lockd: %s(host='%*s', vers=%u, proto=%s)\n", __func__,
343 			(int)hostname_len, hostname, rqstp->rq_vers,
344 			(rqstp->rq_prot == IPPROTO_UDP ? "udp" : "tcp"));
345 
346 	mutex_lock(&nlm_host_mutex);
347 
348 	if (time_after_eq(jiffies, ln->next_gc))
349 		nlm_gc_hosts(net);
350 
351 	chain = &nlm_server_hosts[nlm_hash_address(ni.sap)];
352 	hlist_for_each_entry(host, chain, h_hash) {
353 		if (host->net != net)
354 			continue;
355 		if (!rpc_cmp_addr(nlm_addr(host), ni.sap))
356 			continue;
357 
358 		/* Same address. Share an NSM handle if we already have one */
359 		if (nsm == NULL)
360 			nsm = host->h_nsmhandle;
361 
362 		if (host->h_proto != ni.protocol)
363 			continue;
364 		if (host->h_version != ni.version)
365 			continue;
366 		if (!rpc_cmp_addr(nlm_srcaddr(host), src_sap))
367 			continue;
368 
369 		/* Move to head of hash chain. */
370 		hlist_del(&host->h_hash);
371 		hlist_add_head(&host->h_hash, chain);
372 
373 		nlm_get_host(host);
374 		dprintk("lockd: %s found host %s (%s)\n",
375 			__func__, host->h_name, host->h_addrbuf);
376 		goto out;
377 	}
378 
379 	host = nlm_alloc_host(&ni, nsm);
380 	if (unlikely(host == NULL))
381 		goto out;
382 
383 	memcpy(nlm_srcaddr(host), src_sap, src_len);
384 	host->h_srcaddrlen = src_len;
385 	hlist_add_head(&host->h_hash, chain);
386 	ln->nrhosts++;
387 	nrhosts++;
388 
389 	dprintk("lockd: %s created host %s (%s)\n",
390 		__func__, host->h_name, host->h_addrbuf);
391 
392 out:
393 	mutex_unlock(&nlm_host_mutex);
394 	return host;
395 }
396 
397 /**
398  * nlmsvc_release_host - release server nlm_host
399  * @host: nlm_host to release
400  *
401  * Host is destroyed later in nlm_gc_host().
402  */
403 void nlmsvc_release_host(struct nlm_host *host)
404 {
405 	if (host == NULL)
406 		return;
407 
408 	dprintk("lockd: release server host %s\n", host->h_name);
409 
410 	WARN_ON_ONCE(!host->h_server);
411 	atomic_dec(&host->h_count);
412 }
413 
414 /*
415  * Create the NLM RPC client for an NLM peer
416  */
417 struct rpc_clnt *
418 nlm_bind_host(struct nlm_host *host)
419 {
420 	struct rpc_clnt	*clnt;
421 
422 	dprintk("lockd: nlm_bind_host %s (%s)\n",
423 			host->h_name, host->h_addrbuf);
424 
425 	/* Lock host handle */
426 	mutex_lock(&host->h_mutex);
427 
428 	/* If we've already created an RPC client, check whether
429 	 * RPC rebind is required
430 	 */
431 	if ((clnt = host->h_rpcclnt) != NULL) {
432 		if (time_after_eq(jiffies, host->h_nextrebind)) {
433 			rpc_force_rebind(clnt);
434 			host->h_nextrebind = jiffies + NLM_HOST_REBIND;
435 			dprintk("lockd: next rebind in %lu jiffies\n",
436 					host->h_nextrebind - jiffies);
437 		}
438 	} else {
439 		unsigned long increment = nlmsvc_timeout;
440 		struct rpc_timeout timeparms = {
441 			.to_initval	= increment,
442 			.to_increment	= increment,
443 			.to_maxval	= increment * 6UL,
444 			.to_retries	= 5U,
445 		};
446 		struct rpc_create_args args = {
447 			.net		= host->net,
448 			.protocol	= host->h_proto,
449 			.address	= nlm_addr(host),
450 			.addrsize	= host->h_addrlen,
451 			.timeout	= &timeparms,
452 			.servername	= host->h_name,
453 			.program	= &nlm_program,
454 			.version	= host->h_version,
455 			.authflavor	= RPC_AUTH_UNIX,
456 			.flags		= (RPC_CLNT_CREATE_NOPING |
457 					   RPC_CLNT_CREATE_AUTOBIND),
458 		};
459 
460 		/*
461 		 * lockd retries server side blocks automatically so we want
462 		 * those to be soft RPC calls. Client side calls need to be
463 		 * hard RPC tasks.
464 		 */
465 		if (!host->h_server)
466 			args.flags |= RPC_CLNT_CREATE_HARDRTRY;
467 		if (host->h_noresvport)
468 			args.flags |= RPC_CLNT_CREATE_NONPRIVPORT;
469 		if (host->h_srcaddrlen)
470 			args.saddress = nlm_srcaddr(host);
471 
472 		clnt = rpc_create(&args);
473 		if (!IS_ERR(clnt))
474 			host->h_rpcclnt = clnt;
475 		else {
476 			printk("lockd: couldn't create RPC handle for %s\n", host->h_name);
477 			clnt = NULL;
478 		}
479 	}
480 
481 	mutex_unlock(&host->h_mutex);
482 	return clnt;
483 }
484 
485 /*
486  * Force a portmap lookup of the remote lockd port
487  */
488 void
489 nlm_rebind_host(struct nlm_host *host)
490 {
491 	dprintk("lockd: rebind host %s\n", host->h_name);
492 	if (host->h_rpcclnt && time_after_eq(jiffies, host->h_nextrebind)) {
493 		rpc_force_rebind(host->h_rpcclnt);
494 		host->h_nextrebind = jiffies + NLM_HOST_REBIND;
495 	}
496 }
497 
498 /*
499  * Increment NLM host count
500  */
501 struct nlm_host * nlm_get_host(struct nlm_host *host)
502 {
503 	if (host) {
504 		dprintk("lockd: get host %s\n", host->h_name);
505 		atomic_inc(&host->h_count);
506 		host->h_expires = jiffies + NLM_HOST_EXPIRE;
507 	}
508 	return host;
509 }
510 
511 static struct nlm_host *next_host_state(struct hlist_head *cache,
512 					struct nsm_handle *nsm,
513 					const struct nlm_reboot *info)
514 {
515 	struct nlm_host *host;
516 	struct hlist_head *chain;
517 
518 	mutex_lock(&nlm_host_mutex);
519 	for_each_host(host, chain, cache) {
520 		if (host->h_nsmhandle == nsm
521 		    && host->h_nsmstate != info->state) {
522 			host->h_nsmstate = info->state;
523 			host->h_state++;
524 
525 			nlm_get_host(host);
526 			mutex_unlock(&nlm_host_mutex);
527 			return host;
528 		}
529 	}
530 
531 	mutex_unlock(&nlm_host_mutex);
532 	return NULL;
533 }
534 
535 /**
536  * nlm_host_rebooted - Release all resources held by rebooted host
537  * @info: pointer to decoded results of NLM_SM_NOTIFY call
538  *
539  * We were notified that the specified host has rebooted.  Release
540  * all resources held by that peer.
541  */
542 void nlm_host_rebooted(const struct nlm_reboot *info)
543 {
544 	struct nsm_handle *nsm;
545 	struct nlm_host	*host;
546 
547 	nsm = nsm_reboot_lookup(info);
548 	if (unlikely(nsm == NULL))
549 		return;
550 
551 	/* Mark all hosts tied to this NSM state as having rebooted.
552 	 * We run the loop repeatedly, because we drop the host table
553 	 * lock for this.
554 	 * To avoid processing a host several times, we match the nsmstate.
555 	 */
556 	while ((host = next_host_state(nlm_server_hosts, nsm, info)) != NULL) {
557 		nlmsvc_free_host_resources(host);
558 		nlmsvc_release_host(host);
559 	}
560 	while ((host = next_host_state(nlm_client_hosts, nsm, info)) != NULL) {
561 		nlmclnt_recovery(host);
562 		nlmclnt_release_host(host);
563 	}
564 
565 	nsm_release(nsm);
566 }
567 
568 static void nlm_complain_hosts(struct net *net)
569 {
570 	struct hlist_head *chain;
571 	struct nlm_host	*host;
572 
573 	if (net) {
574 		struct lockd_net *ln = net_generic(net, lockd_net_id);
575 
576 		if (ln->nrhosts == 0)
577 			return;
578 		printk(KERN_WARNING "lockd: couldn't shutdown host module for net %p!\n", net);
579 		dprintk("lockd: %lu hosts left in net %p:\n", ln->nrhosts, net);
580 	} else {
581 		if (nrhosts == 0)
582 			return;
583 		printk(KERN_WARNING "lockd: couldn't shutdown host module!\n");
584 		dprintk("lockd: %lu hosts left:\n", nrhosts);
585 	}
586 
587 	for_each_host(host, chain, nlm_server_hosts) {
588 		if (net && host->net != net)
589 			continue;
590 		dprintk("       %s (cnt %d use %d exp %ld net %p)\n",
591 			host->h_name, atomic_read(&host->h_count),
592 			host->h_inuse, host->h_expires, host->net);
593 	}
594 }
595 
596 void
597 nlm_shutdown_hosts_net(struct net *net)
598 {
599 	struct hlist_head *chain;
600 	struct nlm_host	*host;
601 
602 	mutex_lock(&nlm_host_mutex);
603 
604 	/* First, make all hosts eligible for gc */
605 	dprintk("lockd: nuking all hosts in net %p...\n", net);
606 	for_each_host(host, chain, nlm_server_hosts) {
607 		if (net && host->net != net)
608 			continue;
609 		host->h_expires = jiffies - 1;
610 		if (host->h_rpcclnt) {
611 			rpc_shutdown_client(host->h_rpcclnt);
612 			host->h_rpcclnt = NULL;
613 		}
614 	}
615 
616 	/* Then, perform a garbage collection pass */
617 	nlm_gc_hosts(net);
618 	mutex_unlock(&nlm_host_mutex);
619 
620 	nlm_complain_hosts(net);
621 }
622 
623 /*
624  * Shut down the hosts module.
625  * Note that this routine is called only at server shutdown time.
626  */
627 void
628 nlm_shutdown_hosts(void)
629 {
630 	dprintk("lockd: shutting down host module\n");
631 	nlm_shutdown_hosts_net(NULL);
632 }
633 
634 /*
635  * Garbage collect any unused NLM hosts.
636  * This GC combines reference counting for async operations with
637  * mark & sweep for resources held by remote clients.
638  */
639 static void
640 nlm_gc_hosts(struct net *net)
641 {
642 	struct hlist_head *chain;
643 	struct hlist_node *next;
644 	struct nlm_host	*host;
645 
646 	dprintk("lockd: host garbage collection for net %p\n", net);
647 	for_each_host(host, chain, nlm_server_hosts) {
648 		if (net && host->net != net)
649 			continue;
650 		host->h_inuse = 0;
651 	}
652 
653 	/* Mark all hosts that hold locks, blocks or shares */
654 	nlmsvc_mark_resources(net);
655 
656 	for_each_host_safe(host, next, chain, nlm_server_hosts) {
657 		if (net && host->net != net)
658 			continue;
659 		if (atomic_read(&host->h_count) || host->h_inuse
660 		 || time_before(jiffies, host->h_expires)) {
661 			dprintk("nlm_gc_hosts skipping %s "
662 				"(cnt %d use %d exp %ld net %p)\n",
663 				host->h_name, atomic_read(&host->h_count),
664 				host->h_inuse, host->h_expires, host->net);
665 			continue;
666 		}
667 		nlm_destroy_host_locked(host);
668 	}
669 
670 	if (net) {
671 		struct lockd_net *ln = net_generic(net, lockd_net_id);
672 
673 		ln->next_gc = jiffies + NLM_HOST_COLLECT;
674 	}
675 }
676