xref: /illumos-gate/usr/src/uts/common/klm/nlm_impl.c (revision ac2250cb76bb32944fd2c8a3ba2cd3f79747748d)
1 /*
2  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3  * Authors: Doug Rabson <dfr@rabson.org>
4  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5  *
6  * Redistribution and use in source and binary forms, with or without
7  * modification, are permitted provided that the following conditions
8  * are met:
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25  * SUCH DAMAGE.
26  */
27 
28 /*
29  * Copyright 2026 Edgecast Cloud LLC.
30  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
31  * Copyright (c) 2012 by Delphix. All rights reserved.
32  */
33 
34 /*
35  * NFS LockManager, start/stop, support functions, etc.
36  * Most of the interesting code is here.
37  *
38  * Source code derived from FreeBSD nlm_prot_impl.c
39  */
40 
41 #include <sys/param.h>
42 #include <sys/systm.h>
43 #include <sys/thread.h>
44 #include <sys/fcntl.h>
45 #include <sys/flock.h>
46 #include <sys/mount.h>
47 #include <sys/priv.h>
48 #include <sys/proc.h>
49 #include <sys/share.h>
50 #include <sys/socket.h>
51 #include <sys/syscall.h>
52 #include <sys/syslog.h>
53 #include <sys/systm.h>
54 #include <sys/class.h>
55 #include <sys/unistd.h>
56 #include <sys/vnode.h>
57 #include <sys/vfs.h>
58 #include <sys/queue.h>
59 #include <sys/bitmap.h>
60 #include <sys/sdt.h>
61 #include <netinet/in.h>
62 
63 #include <rpc/rpc.h>
64 #include <rpc/xdr.h>
65 #include <rpc/pmap_prot.h>
66 #include <rpc/pmap_clnt.h>
67 #include <rpc/rpcb_prot.h>
68 
69 #include <rpcsvc/nlm_prot.h>
70 #include <rpcsvc/sm_inter.h>
71 #include <rpcsvc/nsm_addr.h>
72 
73 #include <nfs/nfs.h>
74 #include <nfs/nfs_clnt.h>
75 #include <nfs/export.h>
76 #include <nfs/rnode.h>
77 #include <nfs/lm.h>
78 
79 #include "nlm_impl.h"
80 
81 struct nlm_knc {
82 	struct knetconfig	n_knc;
83 	const char		*n_netid;
84 };
85 
86 /*
87  * Number of attempts NLM tries to obtain RPC binding
88  * of local statd.
89  */
90 #define	NLM_NSM_RPCBIND_RETRIES 10
91 
92 /*
93  * Timeout (in seconds) NLM waits before making another
94  * attempt to obtain RPC binding of local statd.
95  */
96 #define	NLM_NSM_RPCBIND_TIMEOUT 5
97 
98 /*
99  * Total number of sysids in NLM sysid bitmap
100  */
101 #define	NLM_BMAP_NITEMS	(LM_SYSID_MAX + 1)
102 
103 /*
104  * Number of ulong_t words in bitmap that is used
105  * for allocation of sysid numbers.
106  */
107 #define	NLM_BMAP_WORDS  (NLM_BMAP_NITEMS / BT_NBIPUL)
108 
109 /*
110  * Given an integer x, the macro returns
111  * -1 if x is negative,
112  *  0 if x is zero
113  *  1 if x is positive
114  */
115 #define	SIGN(x) (((x) > 0) - ((x) < 0))
116 
117 #define	ARRSIZE(arr)	(sizeof (arr) / sizeof ((arr)[0]))
118 #define	NLM_KNCS	ARRSIZE(nlm_netconfigs)
119 
120 krwlock_t lm_lck;
121 
122 /*
123  * Zero timeout for asynchronous NLM RPC operations
124  */
125 static const struct timeval nlm_rpctv_zero = { 0,  0 };
126 
127 /*
128  * List of all Zone globals nlm_globals instences
129  * linked together.
130  */
131 static struct nlm_globals_list nlm_zones_list; /* (g) */
132 
133 /*
134  * NLM kmem caches
135  */
136 static struct kmem_cache *nlm_hosts_cache = NULL;
137 static struct kmem_cache *nlm_vhold_cache = NULL;
138 
139 /*
140  * A bitmap for allocation of new sysids.
141  * Sysid is a unique number between LM_SYSID
142  * and LM_SYSID_MAX. Sysid represents unique remote
143  * host that does file locks on the given host.
144  */
145 static ulong_t	nlm_sysid_bmap[NLM_BMAP_WORDS];	/* (g) */
146 static int	nlm_sysid_nidx;			/* (g) */
147 
148 /*
149  * RPC service registration for all transports
150  */
151 static SVC_CALLOUT nlm_svcs[] = {
152 	{ NLM_PROG, 4, 4, nlm_prog_4 },	/* NLM4_VERS */
153 	{ NLM_PROG, 1, 3, nlm_prog_3 }	/* NLM_VERS - NLM_VERSX */
154 };
155 
156 static SVC_CALLOUT_TABLE nlm_sct = {
157 	ARRSIZE(nlm_svcs),
158 	FALSE,
159 	nlm_svcs
160 };
161 
162 /*
163  * Static table of all netid/knetconfig network
164  * lock manager can work with. nlm_netconfigs table
165  * is used when we need to get valid knetconfig by
166  * netid and vice versa.
167  *
168  * Knetconfigs are activated either by the call from
169  * user-space lockd daemon (server side) or by taking
170  * knetconfig from NFS mountinfo (client side)
171  */
172 static struct nlm_knc nlm_netconfigs[] = { /* (g) */
173 	/* UDP */
174 	{
175 		{ NC_TPI_CLTS, NC_INET, NC_UDP, NODEV },
176 		"udp",
177 	},
178 	/* TCP */
179 	{
180 		{ NC_TPI_COTS_ORD, NC_INET, NC_TCP, NODEV },
181 		"tcp",
182 	},
183 	/* UDP over IPv6 */
184 	{
185 		{ NC_TPI_CLTS, NC_INET6, NC_UDP, NODEV },
186 		"udp6",
187 	},
188 	/* TCP over IPv6 */
189 	{
190 		{ NC_TPI_COTS_ORD, NC_INET6, NC_TCP, NODEV },
191 		"tcp6",
192 	},
193 	/* ticlts (loopback over UDP) */
194 	{
195 		{ NC_TPI_CLTS, NC_LOOPBACK, NC_NOPROTO, NODEV },
196 		"ticlts",
197 	},
198 	/* ticotsord (loopback over TCP) */
199 	{
200 		{ NC_TPI_COTS_ORD, NC_LOOPBACK, NC_NOPROTO, NODEV },
201 		"ticotsord",
202 	},
203 };
204 
205 /*
206  * NLM misc. function
207  */
208 static void nlm_copy_netbuf(struct netbuf *, struct netbuf *);
209 static int nlm_netbuf_addrs_cmp(struct netbuf *, struct netbuf *);
210 static void nlm_kmem_reclaim(void *);
211 static void nlm_pool_shutdown(void);
212 static void nlm_suspend_zone(struct nlm_globals *);
213 static void nlm_resume_zone(struct nlm_globals *);
214 static void nlm_nsm_clnt_init(CLIENT *, struct nlm_nsm *);
215 static void nlm_netbuf_to_netobj(struct netbuf *, int *, netobj *);
216 
217 /*
218  * NLM thread functions
219  */
220 static void nlm_gc(struct nlm_globals *);
221 static void nlm_reclaimer(struct nlm_host *);
222 
223 /*
224  * NLM NSM functions
225  */
226 static int nlm_init_local_knc(struct knetconfig *);
227 static int nlm_nsm_init_local(struct nlm_nsm *);
228 static int nlm_nsm_init(struct nlm_nsm *, struct knetconfig *, struct netbuf *);
229 static void nlm_nsm_fini(struct nlm_nsm *);
230 static enum clnt_stat nlm_nsm_simu_crash(struct nlm_nsm *);
231 static enum clnt_stat nlm_nsm_stat(struct nlm_nsm *, int32_t *);
232 static enum clnt_stat nlm_nsm_mon(struct nlm_nsm *, char *, uint16_t);
233 static enum clnt_stat nlm_nsm_unmon(struct nlm_nsm *, char *);
234 
235 /*
236  * NLM host functions
237  */
238 static int nlm_host_ctor(void *, void *, int);
239 static void nlm_host_dtor(void *, void *);
240 static void nlm_host_destroy(struct nlm_host *);
241 static struct nlm_host *nlm_host_create(char *, const char *,
242     struct knetconfig *, struct netbuf *, struct netbuf *);
243 static struct nlm_host *nlm_host_find_locked(struct nlm_globals *,
244     const char *, struct netbuf *, avl_index_t *);
245 static void nlm_host_unregister(struct nlm_globals *, struct nlm_host *);
246 static void nlm_host_gc_vholds(struct nlm_host *);
247 static bool_t nlm_host_has_srv_locks(struct nlm_host *);
248 static bool_t nlm_host_has_cli_locks(struct nlm_host *);
249 static bool_t nlm_host_has_locks(struct nlm_host *);
250 
251 /*
252  * NLM vhold functions
253  */
254 static int nlm_vhold_ctor(void *, void *, int);
255 static void nlm_vhold_dtor(void *, void *);
256 static void nlm_vhold_destroy(struct nlm_host *,
257     struct nlm_vhold *);
258 static bool_t nlm_vhold_busy(struct nlm_host *, struct nlm_vhold *);
259 static void nlm_vhold_clean(struct nlm_vhold *, int);
260 
261 /*
262  * NLM client/server sleeping locks/share reservation functions
263  */
264 struct nlm_slreq *nlm_slreq_find_locked(struct nlm_host *,
265     struct nlm_vhold *, struct flock64 *);
266 static struct nlm_shres *nlm_shres_create_item(struct shrlock *, vnode_t *);
267 static void nlm_shres_destroy_item(struct nlm_shres *);
268 static bool_t nlm_shres_equal(struct shrlock *, struct shrlock *);
269 
270 /*
271  * NLM initialization functions.
272  */
273 void
274 nlm_init(void)
275 {
276 	nlm_hosts_cache = kmem_cache_create("nlm_host_cache",
277 	    sizeof (struct nlm_host), 0, nlm_host_ctor, nlm_host_dtor,
278 	    nlm_kmem_reclaim, NULL, NULL, 0);
279 
280 	nlm_vhold_cache = kmem_cache_create("nlm_vhold_cache",
281 	    sizeof (struct nlm_vhold), 0, nlm_vhold_ctor, nlm_vhold_dtor,
282 	    NULL, NULL, NULL, 0);
283 
284 	nlm_rpc_init();
285 	TAILQ_INIT(&nlm_zones_list);
286 
287 	/* initialize sysids bitmap */
288 	bzero(nlm_sysid_bmap, sizeof (nlm_sysid_bmap));
289 	nlm_sysid_nidx = 1;
290 
291 	/*
292 	 * Reserv the sysid #0, because it's associated
293 	 * with local locks only. Don't let to allocate
294 	 * it for remote locks.
295 	 */
296 	BT_SET(nlm_sysid_bmap, 0);
297 }
298 
299 void
300 nlm_globals_register(struct nlm_globals *g)
301 {
302 	rw_enter(&lm_lck, RW_WRITER);
303 	TAILQ_INSERT_TAIL(&nlm_zones_list, g, nlm_link);
304 	rw_exit(&lm_lck);
305 }
306 
307 void
308 nlm_globals_unregister(struct nlm_globals *g)
309 {
310 	rw_enter(&lm_lck, RW_WRITER);
311 	TAILQ_REMOVE(&nlm_zones_list, g, nlm_link);
312 	rw_exit(&lm_lck);
313 }
314 
315 /* ARGSUSED */
316 static void
317 nlm_kmem_reclaim(void *cdrarg)
318 {
319 	struct nlm_globals *g;
320 
321 	rw_enter(&lm_lck, RW_READER);
322 	TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
323 		cv_broadcast(&g->nlm_gc_sched_cv);
324 
325 	rw_exit(&lm_lck);
326 }
327 
328 /*
329  * NLM garbage collector thread (GC).
330  *
331  * NLM GC periodically checks whether there're any host objects
332  * that can be cleaned up. It also releases stale vnodes that
333  * live on the server side (under protection of vhold objects).
334  *
335  * NLM host objects are cleaned up from GC thread because
336  * operations helping us to determine whether given host has
337  * any locks can be quite expensive and it's not good to call
338  * them every time the very last reference to the host is dropped.
339  * Thus we use "lazy" approach for hosts cleanup.
340  *
341  * The work of GC is to release stale vnodes on the server side
342  * and destroy hosts that haven't any locks and any activity for
343  * some time (i.e. idle hosts).
344  */
345 static void
346 nlm_gc(struct nlm_globals *g)
347 {
348 	struct nlm_host *hostp;
349 	clock_t now, idle_period;
350 
351 	idle_period = SEC_TO_TICK(g->cn_idle_tmo);
352 	mutex_enter(&g->lock);
353 	for (;;) {
354 		/*
355 		 * GC thread can be explicitly scheduled from
356 		 * memory reclamation function.
357 		 */
358 		(void) cv_timedwait(&g->nlm_gc_sched_cv, &g->lock,
359 		    ddi_get_lbolt() + idle_period);
360 
361 		/*
362 		 * NLM is shutting down, time to die.
363 		 */
364 		if (g->run_status == NLM_ST_STOPPING)
365 			break;
366 
367 		now = ddi_get_lbolt();
368 		DTRACE_PROBE2(gc__start, struct nlm_globals *, g,
369 		    clock_t, now);
370 
371 		/*
372 		 * Find all obviously unused vholds and destroy them.
373 		 */
374 		for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL;
375 		    hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) {
376 			struct nlm_vhold *nvp;
377 
378 			mutex_enter(&hostp->nh_lock);
379 
380 			nvp = TAILQ_FIRST(&hostp->nh_vholds_list);
381 			while (nvp != NULL) {
382 				struct nlm_vhold *new_nvp;
383 
384 				new_nvp = TAILQ_NEXT(nvp, nv_link);
385 
386 				/*
387 				 * If these conditions are met, the vhold is
388 				 * obviously unused and we will destroy it.  In
389 				 * a case either v_filocks and/or v_shrlocks is
390 				 * non-NULL the vhold might still be unused by
391 				 * the host, but it is expensive to check that.
392 				 * We defer such check until the host is idle.
393 				 * The expensive check is done below without
394 				 * the global lock held.
395 				 */
396 				if (nvp->nv_refcnt == 0 &&
397 				    nvp->nv_vp->v_filocks == NULL &&
398 				    nvp->nv_vp->v_shrlocks == NULL) {
399 					nlm_vhold_destroy(hostp, nvp);
400 				}
401 
402 				nvp = new_nvp;
403 			}
404 
405 			mutex_exit(&hostp->nh_lock);
406 		}
407 
408 		/*
409 		 * Handle all hosts that are unused at the moment
410 		 * until we meet one with idle timeout in future.
411 		 */
412 		while ((hostp = TAILQ_FIRST(&g->nlm_idle_hosts)) != NULL) {
413 			bool_t has_locks;
414 
415 			if (hostp->nh_idle_timeout > now)
416 				break;
417 
418 			/*
419 			 * Drop global lock while doing expensive work
420 			 * on this host. We'll re-check any conditions
421 			 * that might change after retaking the global
422 			 * lock.
423 			 */
424 			mutex_exit(&g->lock);
425 			mutex_enter(&hostp->nh_lock);
426 
427 			/*
428 			 * nlm_globals lock was dropped earlier because
429 			 * garbage collecting of vholds and checking whether
430 			 * host has any locks/shares are expensive operations.
431 			 */
432 			nlm_host_gc_vholds(hostp);
433 			has_locks = nlm_host_has_locks(hostp);
434 
435 			mutex_exit(&hostp->nh_lock);
436 			mutex_enter(&g->lock);
437 
438 			/*
439 			 * While we were doing expensive operations
440 			 * outside of nlm_globals critical section,
441 			 * somebody could take the host and remove it
442 			 * from the idle list.  Whether its been
443 			 * reinserted or not, our information about
444 			 * the host is outdated, and we should take no
445 			 * further action.
446 			 */
447 			if ((hostp->nh_flags & NLM_NH_INIDLE) == 0 ||
448 			    hostp->nh_idle_timeout > now)
449 				continue;
450 
451 			/*
452 			 * If the host has locks we have to renew the
453 			 * host's timeout and put it at the end of LRU
454 			 * list.
455 			 */
456 			if (has_locks) {
457 				TAILQ_REMOVE(&g->nlm_idle_hosts,
458 				    hostp, nh_link);
459 				hostp->nh_idle_timeout = now + idle_period;
460 				TAILQ_INSERT_TAIL(&g->nlm_idle_hosts,
461 				    hostp, nh_link);
462 				continue;
463 			}
464 
465 			/*
466 			 * We're here if all the following conditions hold:
467 			 * 1) Host hasn't any locks or share reservations
468 			 * 2) Host is unused
469 			 * 3) Host wasn't touched by anyone at least for
470 			 *    g->cn_idle_tmo seconds.
471 			 *
472 			 * So, now we can destroy it.
473 			 */
474 			nlm_host_unregister(g, hostp);
475 			mutex_exit(&g->lock);
476 
477 			nlm_host_unmonitor(g, hostp);
478 			nlm_host_destroy(hostp);
479 			mutex_enter(&g->lock);
480 			if (g->run_status == NLM_ST_STOPPING)
481 				break;
482 
483 		}
484 
485 		DTRACE_PROBE(gc__end);
486 	}
487 
488 	DTRACE_PROBE1(gc__exit, struct nlm_globals *, g);
489 
490 	/* Let others know that GC has died */
491 	g->nlm_gc_thread = NULL;
492 	mutex_exit(&g->lock);
493 
494 	cv_broadcast(&g->nlm_gc_finish_cv);
495 	zthread_exit();
496 }
497 
498 /*
499  * Thread reclaim locks/shares acquired by the client side
500  * on the given server represented by hostp.
501  */
502 static void
503 nlm_reclaimer(struct nlm_host *hostp)
504 {
505 	struct nlm_globals *g;
506 
507 	mutex_enter(&hostp->nh_lock);
508 	hostp->nh_reclaimer = curthread;
509 	mutex_exit(&hostp->nh_lock);
510 
511 	g = zone_getspecific(nlm_zone_key, curzone);
512 	nlm_reclaim_client(g, hostp);
513 
514 	mutex_enter(&hostp->nh_lock);
515 	hostp->nh_flags &= ~NLM_NH_RECLAIM;
516 	hostp->nh_reclaimer = NULL;
517 	cv_broadcast(&hostp->nh_recl_cv);
518 	mutex_exit(&hostp->nh_lock);
519 
520 	/*
521 	 * Host was explicitly referenced before
522 	 * nlm_reclaim() was called, release it
523 	 * here.
524 	 */
525 	nlm_host_release(g, hostp);
526 	zthread_exit();
527 }
528 
529 /*
530  * Copy a struct netobj.  (see xdr.h)
531  */
532 void
533 nlm_copy_netobj(struct netobj *dst, struct netobj *src)
534 {
535 	dst->n_len = src->n_len;
536 	dst->n_bytes = kmem_alloc(src->n_len, KM_SLEEP);
537 	bcopy(src->n_bytes, dst->n_bytes, src->n_len);
538 }
539 
540 /*
541  * An NLM specificw replacement for clnt_call().
542  * nlm_clnt_call() is used by all RPC functions generated
543  * from nlm_prot.x specification. The function is aware
544  * about some pitfalls of NLM RPC procedures and has a logic
545  * that handles them properly.
546  */
547 enum clnt_stat
548 nlm_clnt_call(CLIENT *clnt, rpcproc_t procnum, xdrproc_t xdr_args,
549     caddr_t argsp, xdrproc_t xdr_result, caddr_t resultp, struct timeval wait)
550 {
551 	k_sigset_t oldmask;
552 	enum clnt_stat stat;
553 	bool_t sig_blocked = FALSE;
554 
555 	/*
556 	 * If NLM RPC procnum is one of the NLM _RES procedures
557 	 * that are used to reply to asynchronous NLM RPC
558 	 * (MSG calls), explicitly set RPC timeout to zero.
559 	 * Client doesn't send a reply to RES procedures, so
560 	 * we don't need to wait anything.
561 	 *
562 	 * NOTE: we ignore NLM4_*_RES procnums because they are
563 	 * equal to NLM_*_RES numbers.
564 	 */
565 	if (procnum >= NLM_TEST_RES && procnum <= NLM_GRANTED_RES)
566 		wait = nlm_rpctv_zero;
567 
568 	/*
569 	 * We need to block signals in case of NLM_CANCEL RPC
570 	 * in order to prevent interruption of network RPC
571 	 * calls.
572 	 */
573 	if (procnum == NLM_CANCEL) {
574 		k_sigset_t newmask;
575 
576 		sigfillset(&newmask);
577 		sigreplace(&newmask, &oldmask);
578 		sig_blocked = TRUE;
579 	}
580 
581 	stat = clnt_call(clnt, procnum, xdr_args,
582 	    argsp, xdr_result, resultp, wait);
583 
584 	/*
585 	 * Restore signal mask back if signals were blocked
586 	 */
587 	if (sig_blocked)
588 		sigreplace(&oldmask, (k_sigset_t *)NULL);
589 
590 	return (stat);
591 }
592 
593 /*
594  * Suspend NLM client/server in the given zone.
595  *
596  * During suspend operation we mark those hosts
597  * that have any locks with NLM_NH_SUSPEND flags,
598  * so that they can be checked later, when resume
599  * operation occurs.
600  */
601 static void
602 nlm_suspend_zone(struct nlm_globals *g)
603 {
604 	struct nlm_host *hostp;
605 	struct nlm_host_list all_hosts;
606 
607 	/*
608 	 * Note that while we're doing suspend, GC thread is active
609 	 * and it can destroy some hosts while we're walking through
610 	 * the hosts tree. To prevent that and make suspend logic
611 	 * a bit more simple we put all hosts to local "all_hosts"
612 	 * list and increment reference counter of each host.
613 	 * This guaranties that no hosts will be released while
614 	 * we're doing suspend.
615 	 * NOTE: reference of each host must be dropped during
616 	 * resume operation.
617 	 */
618 	TAILQ_INIT(&all_hosts);
619 	mutex_enter(&g->lock);
620 	for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL;
621 	    hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) {
622 		/*
623 		 * If host is idle, remove it from idle list and
624 		 * clear idle flag. That is done to prevent GC
625 		 * from touching this host.
626 		 */
627 		if (hostp->nh_flags & NLM_NH_INIDLE) {
628 			TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
629 			hostp->nh_flags &= ~NLM_NH_INIDLE;
630 		}
631 
632 		hostp->nh_refs++;
633 		TAILQ_INSERT_TAIL(&all_hosts, hostp, nh_link);
634 	}
635 
636 	/*
637 	 * Now we can walk through all hosts on the system
638 	 * with zone globals lock released. The fact the
639 	 * we have taken a reference to each host guaranties
640 	 * that no hosts can be destroyed during that process.
641 	 */
642 	mutex_exit(&g->lock);
643 	while ((hostp = TAILQ_FIRST(&all_hosts)) != NULL) {
644 		mutex_enter(&hostp->nh_lock);
645 		if (nlm_host_has_locks(hostp))
646 			hostp->nh_flags |= NLM_NH_SUSPEND;
647 
648 		mutex_exit(&hostp->nh_lock);
649 		TAILQ_REMOVE(&all_hosts, hostp, nh_link);
650 	}
651 }
652 
653 /*
654  * Resume NLM hosts for the given zone.
655  *
656  * nlm_resume_zone() is called after hosts were suspended
657  * (see nlm_suspend_zone) and its main purpose to check
658  * whether remote locks owned by hosts are still in consistent
659  * state. If they aren't, resume function tries to reclaim
660  * locks (for client side hosts) and clean locks (for
661  * server side hosts).
662  */
663 static void
664 nlm_resume_zone(struct nlm_globals *g)
665 {
666 	struct nlm_host *hostp, *h_next;
667 
668 	mutex_enter(&g->lock);
669 	hostp = avl_first(&g->nlm_hosts_tree);
670 
671 	/*
672 	 * In nlm_suspend_zone() the reference counter of each
673 	 * host was incremented, so we can safely iterate through
674 	 * all hosts without worrying that any host we touch will
675 	 * be removed at the moment.
676 	 */
677 	while (hostp != NULL) {
678 		struct nlm_nsm nsm;
679 		enum clnt_stat stat;
680 		int32_t sm_state;
681 		int error;
682 		bool_t resume_failed = FALSE;
683 
684 		h_next = AVL_NEXT(&g->nlm_hosts_tree, hostp);
685 		mutex_exit(&g->lock);
686 
687 		DTRACE_PROBE1(resume__host, struct nlm_host *, hostp);
688 
689 		/*
690 		 * Suspend operation marked that the host doesn't
691 		 * have any locks. Skip it.
692 		 */
693 		if (!(hostp->nh_flags & NLM_NH_SUSPEND))
694 			goto cycle_end;
695 
696 		error = nlm_nsm_init(&nsm, &hostp->nh_knc, &hostp->nh_addr);
697 		if (error != 0) {
698 			NLM_ERR("Resume: Failed to contact to NSM of host %s "
699 			    "[error=%d]\n", hostp->nh_name, error);
700 			resume_failed = TRUE;
701 			goto cycle_end;
702 		}
703 
704 		stat = nlm_nsm_stat(&nsm, &sm_state);
705 		if (stat != RPC_SUCCESS) {
706 			NLM_ERR("Resume: Failed to call SM_STAT operation for "
707 			    "host %s [stat=%d]\n", hostp->nh_name, stat);
708 			resume_failed = TRUE;
709 			nlm_nsm_fini(&nsm);
710 			goto cycle_end;
711 		}
712 
713 		if (sm_state != hostp->nh_state) {
714 			/*
715 			 * Current SM state of the host isn't equal
716 			 * to the one host had when it was suspended.
717 			 * Probably it was rebooted. Try to reclaim
718 			 * locks if the host has any on its client side.
719 			 * Also try to clean up its server side locks
720 			 * (if the host has any).
721 			 */
722 			nlm_host_notify_client(hostp, sm_state);
723 			nlm_host_notify_server(hostp, sm_state);
724 		}
725 
726 		nlm_nsm_fini(&nsm);
727 
728 cycle_end:
729 		if (resume_failed) {
730 			/*
731 			 * Resume failed for the given host.
732 			 * Just clean up all resources it owns.
733 			 */
734 			nlm_host_notify_server(hostp, 0);
735 			nlm_client_cancel_all(g, hostp);
736 		}
737 
738 		hostp->nh_flags &= ~NLM_NH_SUSPEND;
739 		nlm_host_release(g, hostp);
740 		hostp = h_next;
741 		mutex_enter(&g->lock);
742 	}
743 
744 	mutex_exit(&g->lock);
745 }
746 
747 /*
748  * NLM functions responsible for operations on NSM handle.
749  */
750 
751 /*
752  * Initialize knetconfig that is used for communication
753  * with local statd via loopback interface.
754  */
755 static int
756 nlm_init_local_knc(struct knetconfig *knc)
757 {
758 	int error;
759 	vnode_t *vp;
760 
761 	bzero(knc, sizeof (*knc));
762 	error = lookupname("/dev/tcp", UIO_SYSSPACE,
763 	    FOLLOW, NULLVPP, &vp);
764 	if (error != 0)
765 		return (error);
766 
767 	knc->knc_semantics = NC_TPI_COTS;
768 	knc->knc_protofmly = NC_INET;
769 	knc->knc_proto = NC_TCP;
770 	knc->knc_rdev = vp->v_rdev;
771 	VN_RELE(vp);
772 
773 
774 	return (0);
775 }
776 
777 /*
778  * Initialize NSM handle that will be used to talk
779  * to local statd via loopback interface.
780  */
781 static int
782 nlm_nsm_init_local(struct nlm_nsm *nsm)
783 {
784 	int error;
785 	struct knetconfig knc;
786 	struct sockaddr_in sin;
787 	struct netbuf nb;
788 
789 	error = nlm_init_local_knc(&knc);
790 	if (error != 0)
791 		return (error);
792 
793 	bzero(&sin, sizeof (sin));
794 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
795 	sin.sin_family = AF_INET;
796 
797 	nb.buf = (char *)&sin;
798 	nb.len = nb.maxlen = sizeof (sin);
799 
800 	return (nlm_nsm_init(nsm, &knc, &nb));
801 }
802 
803 /*
804  * Initialize NSM handle used for talking to statd
805  */
806 static int
807 nlm_nsm_init(struct nlm_nsm *nsm, struct knetconfig *knc, struct netbuf *nb)
808 {
809 	enum clnt_stat stat;
810 	int error, retries;
811 
812 	bzero(nsm, sizeof (*nsm));
813 	nsm->ns_knc = *knc;
814 	nlm_copy_netbuf(&nsm->ns_addr, nb);
815 
816 	/*
817 	 * Try several times to get the port of statd service,
818 	 * If rpcbind_getaddr returns  RPC_PROGNOTREGISTERED,
819 	 * retry an attempt, but wait for NLM_NSM_RPCBIND_TIMEOUT
820 	 * seconds berofore.
821 	 */
822 	for (retries = 0; retries < NLM_NSM_RPCBIND_RETRIES; retries++) {
823 		stat = rpcbind_getaddr(&nsm->ns_knc, SM_PROG,
824 		    SM_VERS, &nsm->ns_addr);
825 		if (stat != RPC_SUCCESS) {
826 			if (stat == RPC_PROGNOTREGISTERED) {
827 				delay(SEC_TO_TICK(NLM_NSM_RPCBIND_TIMEOUT));
828 				continue;
829 			}
830 		}
831 
832 		break;
833 	}
834 
835 	if (stat != RPC_SUCCESS) {
836 		DTRACE_PROBE2(rpcbind__error, enum clnt_stat, stat,
837 		    int, retries);
838 		error = ENOENT;
839 		goto error;
840 	}
841 
842 	/*
843 	 * Create an RPC handle that'll be used for communication with local
844 	 * statd using the status monitor protocol.
845 	 */
846 	error = clnt_tli_kcreate(&nsm->ns_knc, &nsm->ns_addr, SM_PROG, SM_VERS,
847 	    0, NLM_RPC_RETRIES, zone_kcred(), &nsm->ns_handle);
848 	if (error != 0)
849 		goto error;
850 
851 	/*
852 	 * Create an RPC handle that'll be used for communication with the
853 	 * local statd using the address registration protocol.
854 	 */
855 	error = clnt_tli_kcreate(&nsm->ns_knc, &nsm->ns_addr, NSM_ADDR_PROGRAM,
856 	    NSM_ADDR_V1, 0, NLM_RPC_RETRIES, zone_kcred(),
857 	    &nsm->ns_addr_handle);
858 	if (error != 0)
859 		goto error;
860 
861 	sema_init(&nsm->ns_sem, 1, NULL, SEMA_DEFAULT, NULL);
862 	return (0);
863 
864 error:
865 	kmem_free(nsm->ns_addr.buf, nsm->ns_addr.maxlen);
866 	if (nsm->ns_handle) {
867 		ASSERT(nsm->ns_handle->cl_auth != NULL);
868 		auth_destroy(nsm->ns_handle->cl_auth);
869 		CLNT_DESTROY(nsm->ns_handle);
870 	}
871 
872 	return (error);
873 }
874 
875 static void
876 nlm_nsm_fini(struct nlm_nsm *nsm)
877 {
878 	kmem_free(nsm->ns_addr.buf, nsm->ns_addr.maxlen);
879 	if (nsm->ns_addr_handle->cl_auth != NULL)
880 		auth_destroy(nsm->ns_addr_handle->cl_auth);
881 	CLNT_DESTROY(nsm->ns_addr_handle);
882 	nsm->ns_addr_handle = NULL;
883 	if (nsm->ns_handle->cl_auth != NULL)
884 		auth_destroy(nsm->ns_handle->cl_auth);
885 	CLNT_DESTROY(nsm->ns_handle);
886 	nsm->ns_handle = NULL;
887 	sema_destroy(&nsm->ns_sem);
888 }
889 
890 static enum clnt_stat
891 nlm_nsm_simu_crash(struct nlm_nsm *nsm)
892 {
893 	enum clnt_stat stat;
894 
895 	sema_p(&nsm->ns_sem);
896 	nlm_nsm_clnt_init(nsm->ns_handle, nsm);
897 	stat = sm_simu_crash_1(NULL, NULL, nsm->ns_handle);
898 	sema_v(&nsm->ns_sem);
899 
900 	return (stat);
901 }
902 
903 static enum clnt_stat
904 nlm_nsm_stat(struct nlm_nsm *nsm, int32_t *out_stat)
905 {
906 	struct sm_name args;
907 	struct sm_stat_res res;
908 	enum clnt_stat stat;
909 
910 	args.mon_name = uts_nodename();
911 	bzero(&res, sizeof (res));
912 
913 	sema_p(&nsm->ns_sem);
914 	nlm_nsm_clnt_init(nsm->ns_handle, nsm);
915 	stat = sm_stat_1(&args, &res, nsm->ns_handle);
916 	sema_v(&nsm->ns_sem);
917 
918 	if (stat == RPC_SUCCESS)
919 		*out_stat = res.state;
920 
921 	return (stat);
922 }
923 
924 static enum clnt_stat
925 nlm_nsm_mon(struct nlm_nsm *nsm, char *hostname, uint16_t priv)
926 {
927 	struct mon args;
928 	struct sm_stat_res res;
929 	enum clnt_stat stat;
930 
931 	bzero(&args, sizeof (args));
932 	bzero(&res, sizeof (res));
933 
934 	args.mon_id.mon_name = hostname;
935 	args.mon_id.my_id.my_name = uts_nodename();
936 	args.mon_id.my_id.my_prog = NLM_PROG;
937 	args.mon_id.my_id.my_vers = NLM_SM;
938 	args.mon_id.my_id.my_proc = NLM_SM_NOTIFY1;
939 	bcopy(&priv, args.priv, sizeof (priv));
940 
941 	sema_p(&nsm->ns_sem);
942 	nlm_nsm_clnt_init(nsm->ns_handle, nsm);
943 	stat = sm_mon_1(&args, &res, nsm->ns_handle);
944 	sema_v(&nsm->ns_sem);
945 
946 	return (stat);
947 }
948 
949 static enum clnt_stat
950 nlm_nsm_unmon(struct nlm_nsm *nsm, char *hostname)
951 {
952 	struct mon_id args;
953 	struct sm_stat res;
954 	enum clnt_stat stat;
955 
956 	bzero(&args, sizeof (args));
957 	bzero(&res, sizeof (res));
958 
959 	args.mon_name = hostname;
960 	args.my_id.my_name = uts_nodename();
961 	args.my_id.my_prog = NLM_PROG;
962 	args.my_id.my_vers = NLM_SM;
963 	args.my_id.my_proc = NLM_SM_NOTIFY1;
964 
965 	sema_p(&nsm->ns_sem);
966 	nlm_nsm_clnt_init(nsm->ns_handle, nsm);
967 	stat = sm_unmon_1(&args, &res, nsm->ns_handle);
968 	sema_v(&nsm->ns_sem);
969 
970 	return (stat);
971 }
972 
973 static enum clnt_stat
974 nlm_nsmaddr_reg(struct nlm_nsm *nsm, char *name, int family, netobj *address)
975 {
976 	struct reg1args args = { 0 };
977 	struct reg1res res = { 0 };
978 	enum clnt_stat stat;
979 
980 	args.family = family;
981 	args.name = name;
982 	args.address = *address;
983 
984 	sema_p(&nsm->ns_sem);
985 	nlm_nsm_clnt_init(nsm->ns_addr_handle, nsm);
986 	stat = nsmaddrproc1_reg_1(&args, &res, nsm->ns_addr_handle);
987 	sema_v(&nsm->ns_sem);
988 
989 	return (stat);
990 }
991 
992 /*
993  * Get NLM vhold object corresponding to vnode "vp".
994  * If no such object was found, create a new one.
995  *
996  * The purpose of this function is to associate vhold
997  * object with given vnode, so that:
998  * 1) vnode is hold (VN_HOLD) while vhold object is alive.
999  * 2) host has a track of all vnodes it touched by lock
1000  *    or share operations. These vnodes are accessible
1001  *    via collection of vhold objects.
1002  */
1003 struct nlm_vhold *
1004 nlm_vhold_get(struct nlm_host *hostp, vnode_t *vp)
1005 {
1006 	struct nlm_vhold *nvp, *new_nvp = NULL;
1007 
1008 	mutex_enter(&hostp->nh_lock);
1009 	nvp = nlm_vhold_find_locked(hostp, vp);
1010 	if (nvp != NULL)
1011 		goto out;
1012 
1013 	/* nlm_vhold wasn't found, then create a new one */
1014 	mutex_exit(&hostp->nh_lock);
1015 	new_nvp = kmem_cache_alloc(nlm_vhold_cache, KM_SLEEP);
1016 
1017 	/*
1018 	 * Check if another thread has already
1019 	 * created the same nlm_vhold.
1020 	 */
1021 	mutex_enter(&hostp->nh_lock);
1022 	nvp = nlm_vhold_find_locked(hostp, vp);
1023 	if (nvp == NULL) {
1024 		nvp = new_nvp;
1025 		new_nvp = NULL;
1026 
1027 		TAILQ_INIT(&nvp->nv_slreqs);
1028 		nvp->nv_vp = vp;
1029 		nvp->nv_refcnt = 1;
1030 		VN_HOLD(nvp->nv_vp);
1031 
1032 		VERIFY(mod_hash_insert(hostp->nh_vholds_by_vp,
1033 		    (mod_hash_key_t)vp, (mod_hash_val_t)nvp) == 0);
1034 		TAILQ_INSERT_TAIL(&hostp->nh_vholds_list, nvp, nv_link);
1035 	}
1036 
1037 out:
1038 	mutex_exit(&hostp->nh_lock);
1039 	if (new_nvp != NULL)
1040 		kmem_cache_free(nlm_vhold_cache, new_nvp);
1041 
1042 	return (nvp);
1043 }
1044 
1045 /*
1046  * Drop a reference to vhold object nvp.
1047  */
1048 void
1049 nlm_vhold_release(struct nlm_host *hostp, struct nlm_vhold *nvp)
1050 {
1051 	if (nvp == NULL)
1052 		return;
1053 
1054 	mutex_enter(&hostp->nh_lock);
1055 	ASSERT(nvp->nv_refcnt > 0);
1056 	nvp->nv_refcnt--;
1057 
1058 	/*
1059 	 * If these conditions are met, the vhold is obviously unused and we
1060 	 * will destroy it.  In a case either v_filocks and/or v_shrlocks is
1061 	 * non-NULL the vhold might still be unused by the host, but it is
1062 	 * expensive to check that.  We defer such check until the host is
1063 	 * idle.  The expensive check is done in the NLM garbage collector.
1064 	 */
1065 	if (nvp->nv_refcnt == 0 &&
1066 	    nvp->nv_vp->v_filocks == NULL &&
1067 	    nvp->nv_vp->v_shrlocks == NULL) {
1068 		nlm_vhold_destroy(hostp, nvp);
1069 	}
1070 
1071 	mutex_exit(&hostp->nh_lock);
1072 }
1073 
1074 /*
1075  * Clean all locks and share reservations on the
1076  * given vhold object that were acquired by the
1077  * given sysid
1078  */
1079 static void
1080 nlm_vhold_clean(struct nlm_vhold *nvp, int sysid)
1081 {
1082 	cleanlocks(nvp->nv_vp, IGN_PID, sysid);
1083 	cleanshares_by_sysid(nvp->nv_vp, sysid);
1084 }
1085 
1086 static void
1087 nlm_vhold_destroy(struct nlm_host *hostp, struct nlm_vhold *nvp)
1088 {
1089 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1090 
1091 	ASSERT(nvp->nv_refcnt == 0);
1092 	ASSERT(TAILQ_EMPTY(&nvp->nv_slreqs));
1093 
1094 	VERIFY(mod_hash_remove(hostp->nh_vholds_by_vp,
1095 	    (mod_hash_key_t)nvp->nv_vp,
1096 	    (mod_hash_val_t)&nvp) == 0);
1097 
1098 	TAILQ_REMOVE(&hostp->nh_vholds_list, nvp, nv_link);
1099 	VN_RELE(nvp->nv_vp);
1100 	nvp->nv_vp = NULL;
1101 
1102 	kmem_cache_free(nlm_vhold_cache, nvp);
1103 }
1104 
1105 /*
1106  * Return TRUE if the given vhold is busy.
1107  * Vhold object is considered to be "busy" when
1108  * all the following conditions hold:
1109  * 1) No one uses it at the moment;
1110  * 2) It hasn't any locks;
1111  * 3) It hasn't any share reservations;
1112  */
1113 static bool_t
1114 nlm_vhold_busy(struct nlm_host *hostp, struct nlm_vhold *nvp)
1115 {
1116 	vnode_t *vp;
1117 	int sysid;
1118 
1119 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1120 
1121 	if (nvp->nv_refcnt > 0)
1122 		return (TRUE);
1123 
1124 	vp = nvp->nv_vp;
1125 	sysid = hostp->nh_sysid;
1126 	if (flk_has_remote_locks_for_sysid(vp, sysid) ||
1127 	    shr_has_remote_shares(vp, sysid))
1128 		return (TRUE);
1129 
1130 	return (FALSE);
1131 }
1132 
1133 /* ARGSUSED */
1134 static int
1135 nlm_vhold_ctor(void *datap, void *cdrarg, int kmflags)
1136 {
1137 	struct nlm_vhold *nvp = (struct nlm_vhold *)datap;
1138 
1139 	bzero(nvp, sizeof (*nvp));
1140 	return (0);
1141 }
1142 
1143 /* ARGSUSED */
1144 static void
1145 nlm_vhold_dtor(void *datap, void *cdrarg)
1146 {
1147 	struct nlm_vhold *nvp = (struct nlm_vhold *)datap;
1148 
1149 	ASSERT(nvp->nv_refcnt == 0);
1150 	ASSERT(TAILQ_EMPTY(&nvp->nv_slreqs));
1151 	ASSERT(nvp->nv_vp == NULL);
1152 }
1153 
1154 struct nlm_vhold *
1155 nlm_vhold_find_locked(struct nlm_host *hostp, const vnode_t *vp)
1156 {
1157 	struct nlm_vhold *nvp = NULL;
1158 
1159 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1160 	(void) mod_hash_find(hostp->nh_vholds_by_vp,
1161 	    (mod_hash_key_t)vp,
1162 	    (mod_hash_val_t)&nvp);
1163 
1164 	if (nvp != NULL)
1165 		nvp->nv_refcnt++;
1166 
1167 	return (nvp);
1168 }
1169 
1170 /*
1171  * NLM host functions
1172  */
1173 static void
1174 nlm_copy_netbuf(struct netbuf *dst, struct netbuf *src)
1175 {
1176 	ASSERT(src->len <= src->maxlen);
1177 
1178 	dst->maxlen = src->maxlen;
1179 	dst->len = src->len;
1180 	dst->buf = kmem_zalloc(src->maxlen, KM_SLEEP);
1181 	bcopy(src->buf, dst->buf, src->len);
1182 }
1183 
1184 /* ARGSUSED */
1185 static int
1186 nlm_host_ctor(void *datap, void *cdrarg, int kmflags)
1187 {
1188 	struct nlm_host *hostp = (struct nlm_host *)datap;
1189 
1190 	bzero(hostp, sizeof (*hostp));
1191 	return (0);
1192 }
1193 
1194 /* ARGSUSED */
1195 static void
1196 nlm_host_dtor(void *datap, void *cdrarg)
1197 {
1198 	struct nlm_host *hostp = (struct nlm_host *)datap;
1199 	ASSERT(hostp->nh_refs == 0);
1200 }
1201 
1202 static void
1203 nlm_host_unregister(struct nlm_globals *g, struct nlm_host *hostp)
1204 {
1205 	ASSERT(hostp->nh_refs == 0);
1206 	ASSERT(hostp->nh_flags & NLM_NH_INIDLE);
1207 
1208 	avl_remove(&g->nlm_hosts_tree, hostp);
1209 	VERIFY(mod_hash_remove(g->nlm_hosts_hash,
1210 	    (mod_hash_key_t)(uintptr_t)hostp->nh_sysid,
1211 	    (mod_hash_val_t)&hostp) == 0);
1212 	TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1213 	hostp->nh_flags &= ~NLM_NH_INIDLE;
1214 }
1215 
1216 /*
1217  * Free resources used by a host. This is called after the reference
1218  * count has reached zero so it doesn't need to worry about locks.
1219  */
1220 static void
1221 nlm_host_destroy(struct nlm_host *hostp)
1222 {
1223 	ASSERT(hostp->nh_name != NULL);
1224 	ASSERT(hostp->nh_netid != NULL);
1225 	ASSERT(TAILQ_EMPTY(&hostp->nh_vholds_list));
1226 
1227 	strfree(hostp->nh_name);
1228 	strfree(hostp->nh_netid);
1229 	kmem_free(hostp->nh_addr.buf, hostp->nh_addr.maxlen);
1230 	if (hostp->nh_laddr.buf != NULL)
1231 		kmem_free(hostp->nh_laddr.buf, hostp->nh_laddr.maxlen);
1232 
1233 	if (hostp->nh_sysid != LM_NOSYSID)
1234 		nlm_sysid_free(hostp->nh_sysid);
1235 
1236 	nlm_rpc_cache_destroy(hostp);
1237 
1238 	ASSERT(TAILQ_EMPTY(&hostp->nh_vholds_list));
1239 	mod_hash_destroy_ptrhash(hostp->nh_vholds_by_vp);
1240 
1241 	mutex_destroy(&hostp->nh_lock);
1242 	cv_destroy(&hostp->nh_rpcb_cv);
1243 	cv_destroy(&hostp->nh_recl_cv);
1244 
1245 	kmem_cache_free(nlm_hosts_cache, hostp);
1246 }
1247 
1248 /*
1249  * Cleanup SERVER-side state after a client restarts,
1250  * or becomes unresponsive, or whatever.
1251  *
1252  * We unlock any active locks owned by the host.
1253  * When rpc.lockd is shutting down,
1254  * this function is called with newstate set to zero
1255  * which allows us to cancel any pending async locks
1256  * and clear the locking state.
1257  *
1258  * When "state" is 0, we don't update host's state,
1259  * but cleanup all remote locks on the host.
1260  * It's useful to call this function for resources
1261  * cleanup.
1262  */
1263 void
1264 nlm_host_notify_server(struct nlm_host *hostp, int32_t state)
1265 {
1266 	struct nlm_vhold *nvp;
1267 	struct nlm_slreq *slr;
1268 	struct nlm_slreq_list slreqs2free;
1269 
1270 	TAILQ_INIT(&slreqs2free);
1271 	mutex_enter(&hostp->nh_lock);
1272 	if (state != 0)
1273 		hostp->nh_state = state;
1274 
1275 	TAILQ_FOREACH(nvp, &hostp->nh_vholds_list, nv_link) {
1276 
1277 		/* cleanup sleeping requests at first */
1278 		while ((slr = TAILQ_FIRST(&nvp->nv_slreqs)) != NULL) {
1279 			TAILQ_REMOVE(&nvp->nv_slreqs, slr, nsr_link);
1280 
1281 			/*
1282 			 * Instead of freeing cancelled sleeping request
1283 			 * here, we add it to the linked list created
1284 			 * on the stack in order to do all frees outside
1285 			 * the critical section.
1286 			 */
1287 			TAILQ_INSERT_TAIL(&slreqs2free, slr, nsr_link);
1288 		}
1289 
1290 		nvp->nv_refcnt++;
1291 		mutex_exit(&hostp->nh_lock);
1292 
1293 		nlm_vhold_clean(nvp, hostp->nh_sysid);
1294 
1295 		mutex_enter(&hostp->nh_lock);
1296 		nvp->nv_refcnt--;
1297 	}
1298 
1299 	mutex_exit(&hostp->nh_lock);
1300 	while ((slr = TAILQ_FIRST(&slreqs2free)) != NULL) {
1301 		TAILQ_REMOVE(&slreqs2free, slr, nsr_link);
1302 		kmem_free(slr, sizeof (*slr));
1303 	}
1304 }
1305 
1306 /*
1307  * Cleanup CLIENT-side state after a server restarts,
1308  * or becomes unresponsive, or whatever.
1309  *
1310  * This is called by the local NFS statd when we receive a
1311  * host state change notification.  (also nlm_svc_stopping)
1312  *
1313  * Deal with a server restart.  If we are stopping the
1314  * NLM service, we'll have newstate == 0, and will just
1315  * cancel all our client-side lock requests.  Otherwise,
1316  * start the "recovery" process to reclaim any locks
1317  * we hold on this server.
1318  */
1319 void
1320 nlm_host_notify_client(struct nlm_host *hostp, int32_t state)
1321 {
1322 	mutex_enter(&hostp->nh_lock);
1323 	hostp->nh_state = state;
1324 	if (hostp->nh_flags & NLM_NH_RECLAIM) {
1325 		/*
1326 		 * Either host's state is up to date or
1327 		 * host is already in recovery.
1328 		 */
1329 		mutex_exit(&hostp->nh_lock);
1330 		return;
1331 	}
1332 
1333 	hostp->nh_flags |= NLM_NH_RECLAIM;
1334 
1335 	/*
1336 	 * Host will be released by the recovery thread,
1337 	 * thus we need to increment refcount.
1338 	 */
1339 	hostp->nh_refs++;
1340 	mutex_exit(&hostp->nh_lock);
1341 
1342 	(void) zthread_create(NULL, 0, nlm_reclaimer,
1343 	    hostp, 0, minclsyspri);
1344 }
1345 
1346 /*
1347  * The function is called when NLM client detects that
1348  * server has entered in grace period and client needs
1349  * to wait until reclamation process (if any) does
1350  * its job.
1351  */
1352 int
1353 nlm_host_wait_grace(struct nlm_host *hostp)
1354 {
1355 	struct nlm_globals *g;
1356 	int error = 0;
1357 
1358 	g = zone_getspecific(nlm_zone_key, curzone);
1359 	mutex_enter(&hostp->nh_lock);
1360 
1361 	do {
1362 		int rc;
1363 
1364 		rc = cv_timedwait_sig(&hostp->nh_recl_cv,
1365 		    &hostp->nh_lock, ddi_get_lbolt() +
1366 		    SEC_TO_TICK(g->retrans_tmo));
1367 
1368 		if (rc == 0) {
1369 			error = EINTR;
1370 			break;
1371 		}
1372 	} while (hostp->nh_flags & NLM_NH_RECLAIM);
1373 
1374 	mutex_exit(&hostp->nh_lock);
1375 	return (error);
1376 }
1377 
1378 /*
1379  * Create a new NLM host.
1380  *
1381  * NOTE: The in-kernel RPC (kRPC) subsystem uses TLI/XTI,
1382  * which needs both a knetconfig and an address when creating
1383  * endpoints. Thus host object stores both knetconfig and
1384  * netid.
1385  */
1386 static struct nlm_host *
1387 nlm_host_create(char *name, const char *netid,
1388     struct knetconfig *knc, struct netbuf *naddr, struct netbuf *laddr)
1389 {
1390 	struct nlm_host *host;
1391 
1392 	host = kmem_cache_alloc(nlm_hosts_cache, KM_SLEEP);
1393 
1394 	mutex_init(&host->nh_lock, NULL, MUTEX_DEFAULT, NULL);
1395 	cv_init(&host->nh_rpcb_cv, NULL, CV_DEFAULT, NULL);
1396 	cv_init(&host->nh_recl_cv, NULL, CV_DEFAULT, NULL);
1397 
1398 	host->nh_sysid = LM_NOSYSID;
1399 	host->nh_refs = 1;
1400 	host->nh_name = strdup(name);
1401 	host->nh_netid = strdup(netid);
1402 	host->nh_knc = *knc;
1403 	nlm_copy_netbuf(&host->nh_addr, naddr);
1404 	if (laddr != NULL) {
1405 		nlm_copy_netbuf(&host->nh_laddr, laddr);
1406 	} else {
1407 		bzero(&host->nh_laddr, sizeof (host->nh_laddr));
1408 	}
1409 
1410 	host->nh_state = 0;
1411 	host->nh_rpcb_state = NRPCB_NEED_UPDATE;
1412 	host->nh_flags = 0;
1413 
1414 	host->nh_vholds_by_vp = mod_hash_create_ptrhash("nlm vholds hash",
1415 	    32, mod_hash_null_valdtor, sizeof (vnode_t));
1416 
1417 	TAILQ_INIT(&host->nh_vholds_list);
1418 	TAILQ_INIT(&host->nh_rpchc);
1419 
1420 	return (host);
1421 }
1422 
1423 /*
1424  * Cancel all client side sleeping locks owned by given host.
1425  */
1426 void
1427 nlm_host_cancel_slocks(struct nlm_globals *g, struct nlm_host *hostp)
1428 {
1429 	struct nlm_slock *nslp;
1430 
1431 	mutex_enter(&g->lock);
1432 	TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) {
1433 		if (nslp->nsl_host == hostp) {
1434 			nslp->nsl_state = NLM_SL_CANCELLED;
1435 			cv_broadcast(&nslp->nsl_cond);
1436 		}
1437 	}
1438 
1439 	mutex_exit(&g->lock);
1440 }
1441 
1442 /*
1443  * Garbage collect stale vhold objects.
1444  *
1445  * In other words check whether vnodes that are
1446  * held by vhold objects still have any locks
1447  * or shares or still in use. If they aren't,
1448  * just destroy them.
1449  */
1450 static void
1451 nlm_host_gc_vholds(struct nlm_host *hostp)
1452 {
1453 	struct nlm_vhold *nvp;
1454 
1455 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1456 
1457 	nvp = TAILQ_FIRST(&hostp->nh_vholds_list);
1458 	while (nvp != NULL) {
1459 		struct nlm_vhold *nvp_tmp;
1460 
1461 		if (nlm_vhold_busy(hostp, nvp)) {
1462 			nvp = TAILQ_NEXT(nvp, nv_link);
1463 			continue;
1464 		}
1465 
1466 		nvp_tmp = TAILQ_NEXT(nvp, nv_link);
1467 		nlm_vhold_destroy(hostp, nvp);
1468 		nvp = nvp_tmp;
1469 	}
1470 }
1471 
1472 /*
1473  * Check whether the given host has any
1474  * server side locks or share reservations.
1475  */
1476 static bool_t
1477 nlm_host_has_srv_locks(struct nlm_host *hostp)
1478 {
1479 	/*
1480 	 * It's cheap and simple: if server has
1481 	 * any locks/shares there must be vhold
1482 	 * object storing the affected vnode.
1483 	 *
1484 	 * NOTE: We don't need to check sleeping
1485 	 * locks on the server side, because if
1486 	 * server side sleeping lock is alive,
1487 	 * there must be a vhold object corresponding
1488 	 * to target vnode.
1489 	 */
1490 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1491 	if (!TAILQ_EMPTY(&hostp->nh_vholds_list))
1492 		return (TRUE);
1493 
1494 	return (FALSE);
1495 }
1496 
1497 /*
1498  * Check whether the given host has any client side
1499  * locks or share reservations.
1500  */
1501 static bool_t
1502 nlm_host_has_cli_locks(struct nlm_host *hostp)
1503 {
1504 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1505 
1506 	/*
1507 	 * XXX: It's not the way I'd like to do the check,
1508 	 * because flk_sysid_has_locks() can be very
1509 	 * expensive by design. Unfortunatelly it iterates
1510 	 * through all locks on the system, doesn't matter
1511 	 * were they made on remote system via NLM or
1512 	 * on local system via reclock. To understand the
1513 	 * problem, consider that there're dozens of thousands
1514 	 * of locks that are made on some ZFS dataset. And there's
1515 	 * another dataset shared by NFS where NLM client had locks
1516 	 * some time ago, but doesn't have them now.
1517 	 * In this case flk_sysid_has_locks() will iterate
1518 	 * thrught dozens of thousands locks until it returns us
1519 	 * FALSE.
1520 	 * Oh, I hope that in shiny future somebody will make
1521 	 * local lock manager (os/flock.c) better, so that
1522 	 * it'd be more friedly to remote locks and
1523 	 * flk_sysid_has_locks() wouldn't be so expensive.
1524 	 */
1525 	if (flk_sysid_has_locks(hostp->nh_sysid |
1526 	    LM_SYSID_CLIENT, FLK_QUERY_ACTIVE))
1527 		return (TRUE);
1528 
1529 	/*
1530 	 * Check whether host has any share reservations
1531 	 * registered on the client side.
1532 	 */
1533 	if (hostp->nh_shrlist != NULL)
1534 		return (TRUE);
1535 
1536 	return (FALSE);
1537 }
1538 
1539 /*
1540  * Determine whether the given host owns any
1541  * locks or share reservations.
1542  */
1543 static bool_t
1544 nlm_host_has_locks(struct nlm_host *hostp)
1545 {
1546 	if (nlm_host_has_srv_locks(hostp))
1547 		return (TRUE);
1548 
1549 	return (nlm_host_has_cli_locks(hostp));
1550 }
1551 
1552 /*
1553  * This function compares only addresses of two netbufs
1554  * that belong to NC_TCP[6] or NC_UDP[6] protofamily.
1555  * Port part of netbuf is ignored.
1556  *
1557  * Return values:
1558  *  -1: nb1's address is "smaller" than nb2's
1559  *   0: addresses are equal
1560  *   1: nb1's address is "greater" than nb2's
1561  */
1562 static int
1563 nlm_netbuf_addrs_cmp(struct netbuf *nb1, struct netbuf *nb2)
1564 {
1565 	union nlm_addr {
1566 		struct sockaddr sa;
1567 		struct sockaddr_in sin;
1568 		struct sockaddr_in6 sin6;
1569 	} *na1, *na2;
1570 	int res;
1571 
1572 	/* LINTED E_BAD_PTR_CAST_ALIGN */
1573 	na1 = (union nlm_addr *)nb1->buf;
1574 	/* LINTED E_BAD_PTR_CAST_ALIGN */
1575 	na2 = (union nlm_addr *)nb2->buf;
1576 
1577 	if (na1->sa.sa_family < na2->sa.sa_family)
1578 		return (-1);
1579 	if (na1->sa.sa_family > na2->sa.sa_family)
1580 		return (1);
1581 
1582 	switch (na1->sa.sa_family) {
1583 	case AF_INET:
1584 		res = memcmp(&na1->sin.sin_addr, &na2->sin.sin_addr,
1585 		    sizeof (na1->sin.sin_addr));
1586 		break;
1587 	case AF_INET6:
1588 		res = memcmp(&na1->sin6.sin6_addr, &na2->sin6.sin6_addr,
1589 		    sizeof (na1->sin6.sin6_addr));
1590 		break;
1591 	default:
1592 		VERIFY(0);
1593 		return (0);
1594 	}
1595 
1596 	return (SIGN(res));
1597 }
1598 
1599 /*
1600  * Compare two nlm hosts.
1601  * Return values:
1602  * -1: host1 is "smaller" than host2
1603  *  0: host1 is equal to host2
1604  *  1: host1 is "greater" than host2
1605  */
1606 int
1607 nlm_host_cmp(const void *p1, const void *p2)
1608 {
1609 	struct nlm_host *h1 = (struct nlm_host *)p1;
1610 	struct nlm_host *h2 = (struct nlm_host *)p2;
1611 	int res;
1612 
1613 	res = strcmp(h1->nh_netid, h2->nh_netid);
1614 	if (res != 0)
1615 		return (SIGN(res));
1616 
1617 	res = nlm_netbuf_addrs_cmp(&h1->nh_addr, &h2->nh_addr);
1618 	return (res);
1619 }
1620 
1621 /*
1622  * Find the host specified by...  (see below)
1623  * If found, increment the ref count.
1624  */
1625 static struct nlm_host *
1626 nlm_host_find_locked(struct nlm_globals *g, const char *netid,
1627     struct netbuf *naddr, avl_index_t *wherep)
1628 {
1629 	struct nlm_host *hostp, key;
1630 	avl_index_t pos;
1631 
1632 	ASSERT(MUTEX_HELD(&g->lock));
1633 
1634 	key.nh_netid = (char *)netid;
1635 	key.nh_addr.buf = naddr->buf;
1636 	key.nh_addr.len = naddr->len;
1637 	key.nh_addr.maxlen = naddr->maxlen;
1638 
1639 	hostp = avl_find(&g->nlm_hosts_tree, &key, &pos);
1640 
1641 	if (hostp != NULL) {
1642 		/*
1643 		 * Host is inuse now. Remove it from idle
1644 		 * hosts list if needed.
1645 		 */
1646 		if (hostp->nh_flags & NLM_NH_INIDLE) {
1647 			TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1648 			hostp->nh_flags &= ~NLM_NH_INIDLE;
1649 		}
1650 
1651 		hostp->nh_refs++;
1652 	}
1653 	if (wherep != NULL)
1654 		*wherep = pos;
1655 
1656 	return (hostp);
1657 }
1658 
1659 /*
1660  * Find NLM host for the given name and address.
1661  */
1662 struct nlm_host *
1663 nlm_host_find(struct nlm_globals *g, const char *netid,
1664     struct netbuf *addr)
1665 {
1666 	struct nlm_host *hostp = NULL;
1667 
1668 	mutex_enter(&g->lock);
1669 	if (g->run_status != NLM_ST_UP)
1670 		goto out;
1671 
1672 	hostp = nlm_host_find_locked(g, netid, addr, NULL);
1673 
1674 out:
1675 	mutex_exit(&g->lock);
1676 	return (hostp);
1677 }
1678 
1679 
1680 /*
1681  * Find or create an NLM host for the given name and address.
1682  *
1683  * The remote host is determined by all of: name, netid, address.
1684  * Note that the netid is whatever nlm_svc_add_ep() gave to
1685  * svc_tli_kcreate() for the service binding.  If any of these
1686  * are different, allocate a new host (new sysid).
1687  */
1688 struct nlm_host *
1689 nlm_host_findcreate(struct nlm_globals *g, char *name,
1690     const char *netid, struct netbuf *addr, struct netbuf *laddr)
1691 {
1692 	int err;
1693 	struct nlm_host *host, *newhost = NULL;
1694 	struct knetconfig knc;
1695 	avl_index_t where;
1696 
1697 	mutex_enter(&g->lock);
1698 	if (g->run_status != NLM_ST_UP) {
1699 		mutex_exit(&g->lock);
1700 		return (NULL);
1701 	}
1702 
1703 	host = nlm_host_find_locked(g, netid, addr, NULL);
1704 	mutex_exit(&g->lock);
1705 	if (host != NULL) {
1706 		if ((&host->nh_laddr)->len != 0 &&
1707 		    (laddr == NULL || laddr->len == 0)) {
1708 			cmn_err(CE_NOTE, "nlm_host_findcreate: "
1709 			    "Incoming laddr is absent but "
1710 			    "host has a recorded nh_laddr.\n");
1711 		} else if ((&host->nh_laddr)->len == 0 &&
1712 		    laddr != NULL && laddr->len != 0) {
1713 			cmn_err(CE_NOTE, "nlm_host_findcreate: "
1714 			    "Incoming laddr is present but "
1715 			    "host has no recorded nh_laddr.\n");
1716 		} else if (laddr != NULL &&
1717 		    (((&host->nh_laddr)->len != laddr->len) ||
1718 		    bcmp((&host->nh_laddr)->buf, laddr->buf,
1719 		    (size_t)laddr->len) != 0)) {
1720 			cmn_err(CE_NOTE, "nlm_host_findcreate: received "
1721 			    "laddr different from recorded nh_laddr.\n");
1722 		}
1723 
1724 		return (host);
1725 	}
1726 
1727 	err = nlm_knc_from_netid(netid, &knc);
1728 	if (err != 0)
1729 		return (NULL);
1730 	/*
1731 	 * Do allocations (etc.) outside of mutex,
1732 	 * and then check again before inserting.
1733 	 */
1734 	newhost = nlm_host_create(name, netid, &knc, addr, laddr);
1735 	newhost->nh_sysid = nlm_sysid_alloc();
1736 	if (newhost->nh_sysid == LM_NOSYSID)
1737 		goto out;
1738 
1739 	mutex_enter(&g->lock);
1740 	host = nlm_host_find_locked(g, netid, addr, &where);
1741 	if (host == NULL) {
1742 		host = newhost;
1743 		newhost = NULL;
1744 
1745 		/*
1746 		 * Insert host to the hosts AVL tree that is
1747 		 * used to lookup by <netid, address> pair.
1748 		 */
1749 		avl_insert(&g->nlm_hosts_tree, host, where);
1750 
1751 		/*
1752 		 * Insert host to the hosts hash table that is
1753 		 * used to lookup host by sysid.
1754 		 */
1755 		VERIFY(mod_hash_insert(g->nlm_hosts_hash,
1756 		    (mod_hash_key_t)(uintptr_t)host->nh_sysid,
1757 		    (mod_hash_val_t)host) == 0);
1758 	}
1759 
1760 	mutex_exit(&g->lock);
1761 
1762 out:
1763 	if (newhost != NULL) {
1764 		/*
1765 		 * We do not need the preallocated nlm_host
1766 		 * so decrement the reference counter
1767 		 * and destroy it.
1768 		 */
1769 		newhost->nh_refs--;
1770 		nlm_host_destroy(newhost);
1771 	}
1772 
1773 	return (host);
1774 }
1775 
1776 /*
1777  * Find the NLM host that matches the value of 'sysid'.
1778  * If found, return it with a new ref,
1779  * else return NULL.
1780  */
1781 struct nlm_host *
1782 nlm_host_find_by_sysid(struct nlm_globals *g, sysid_t sysid)
1783 {
1784 	struct nlm_host *hostp = NULL;
1785 
1786 	mutex_enter(&g->lock);
1787 	if (g->run_status != NLM_ST_UP)
1788 		goto out;
1789 
1790 	(void) mod_hash_find(g->nlm_hosts_hash,
1791 	    (mod_hash_key_t)(uintptr_t)sysid,
1792 	    (mod_hash_val_t)&hostp);
1793 
1794 	if (hostp == NULL)
1795 		goto out;
1796 
1797 	/*
1798 	 * Host is inuse now. Remove it
1799 	 * from idle hosts list if needed.
1800 	 */
1801 	if (hostp->nh_flags & NLM_NH_INIDLE) {
1802 		TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1803 		hostp->nh_flags &= ~NLM_NH_INIDLE;
1804 	}
1805 
1806 	hostp->nh_refs++;
1807 
1808 out:
1809 	mutex_exit(&g->lock);
1810 	return (hostp);
1811 }
1812 
1813 /*
1814  * Release the given host.
1815  * I.e. drop a reference that was taken earlier by one of
1816  * the following functions: nlm_host_findcreate(), nlm_host_find(),
1817  * nlm_host_find_by_sysid().
1818  *
1819  * When the very last reference is dropped, host is moved to
1820  * so-called "idle state". All hosts that are in idle state
1821  * have an idle timeout. If timeout is expired, GC thread
1822  * checks whether hosts have any locks and if they heven't
1823  * any, it removes them.
1824  * NOTE: only unused hosts can be in idle state.
1825  */
1826 static void
1827 nlm_host_release_locked(struct nlm_globals *g, struct nlm_host *hostp)
1828 {
1829 	if (hostp == NULL)
1830 		return;
1831 
1832 	ASSERT(MUTEX_HELD(&g->lock));
1833 	ASSERT(hostp->nh_refs > 0);
1834 
1835 	hostp->nh_refs--;
1836 	if (hostp->nh_refs != 0)
1837 		return;
1838 
1839 	/*
1840 	 * The very last reference to the host was dropped,
1841 	 * thus host is unused now. Set its idle timeout
1842 	 * and move it to the idle hosts LRU list.
1843 	 */
1844 	hostp->nh_idle_timeout = ddi_get_lbolt() +
1845 	    SEC_TO_TICK(g->cn_idle_tmo);
1846 
1847 	ASSERT((hostp->nh_flags & NLM_NH_INIDLE) == 0);
1848 	TAILQ_INSERT_TAIL(&g->nlm_idle_hosts, hostp, nh_link);
1849 	hostp->nh_flags |= NLM_NH_INIDLE;
1850 }
1851 
1852 void
1853 nlm_host_release(struct nlm_globals *g, struct nlm_host *hostp)
1854 {
1855 	if (hostp == NULL)
1856 		return;
1857 
1858 	mutex_enter(&g->lock);
1859 	nlm_host_release_locked(g, hostp);
1860 	mutex_exit(&g->lock);
1861 }
1862 
1863 /*
1864  * Unregister this NLM host (NFS client) with the local statd
1865  * due to idleness (no locks held for a while).
1866  */
1867 void
1868 nlm_host_unmonitor(struct nlm_globals *g, struct nlm_host *host)
1869 {
1870 	enum clnt_stat stat;
1871 
1872 	VERIFY(host->nh_refs == 0);
1873 	if (!(host->nh_flags & NLM_NH_MONITORED))
1874 		return;
1875 
1876 	host->nh_flags &= ~NLM_NH_MONITORED;
1877 	stat = nlm_nsm_unmon(&g->nlm_nsm, host->nh_name);
1878 	if (stat != RPC_SUCCESS) {
1879 		NLM_WARN("NLM: Failed to contact statd, stat=%d\n", stat);
1880 		return;
1881 	}
1882 }
1883 
1884 /*
1885  * Ask the local NFS statd to begin monitoring this host.
1886  * It will call us back when that host restarts, using the
1887  * prog,vers,proc specified below, i.e. NLM_SM_NOTIFY1,
1888  * which is handled in nlm_do_notify1().
1889  */
1890 void
1891 nlm_host_monitor(struct nlm_globals *g, struct nlm_host *host, int state)
1892 {
1893 	int family;
1894 	netobj obj;
1895 	enum clnt_stat stat;
1896 
1897 	if (state != 0 && host->nh_state == 0) {
1898 		/*
1899 		 * This is the first time we have seen an NSM state
1900 		 * Value for this host. We record it here to help
1901 		 * detect host reboots.
1902 		 */
1903 		host->nh_state = state;
1904 	}
1905 
1906 	mutex_enter(&host->nh_lock);
1907 	if (host->nh_flags & NLM_NH_MONITORED) {
1908 		mutex_exit(&host->nh_lock);
1909 		return;
1910 	}
1911 
1912 	host->nh_flags |= NLM_NH_MONITORED;
1913 	mutex_exit(&host->nh_lock);
1914 
1915 	/*
1916 	 * Before we begin monitoring the host register the network address
1917 	 * associated with this hostname.
1918 	 */
1919 	nlm_netbuf_to_netobj(&host->nh_addr, &family, &obj);
1920 	stat = nlm_nsmaddr_reg(&g->nlm_nsm, host->nh_name, family, &obj);
1921 	if (stat != RPC_SUCCESS) {
1922 		NLM_WARN("Failed to register address, stat=%d\n", stat);
1923 		mutex_enter(&g->lock);
1924 		host->nh_flags &= ~NLM_NH_MONITORED;
1925 		mutex_exit(&g->lock);
1926 
1927 		return;
1928 	}
1929 
1930 	/*
1931 	 * Tell statd how to call us with status updates for
1932 	 * this host. Updates arrive via nlm_do_notify1().
1933 	 *
1934 	 * We put our assigned system ID value in the priv field to
1935 	 * make it simpler to find the host if we are notified of a
1936 	 * host restart.
1937 	 */
1938 	stat = nlm_nsm_mon(&g->nlm_nsm, host->nh_name, host->nh_sysid);
1939 	if (stat != RPC_SUCCESS) {
1940 		NLM_WARN("Failed to contact local NSM, stat=%d\n", stat);
1941 		mutex_enter(&g->lock);
1942 		host->nh_flags &= ~NLM_NH_MONITORED;
1943 		mutex_exit(&g->lock);
1944 
1945 		return;
1946 	}
1947 }
1948 
1949 int
1950 nlm_host_get_state(struct nlm_host *hostp)
1951 {
1952 
1953 	return (hostp->nh_state);
1954 }
1955 
1956 /*
1957  * NLM client/server sleeping locks
1958  */
1959 
1960 /*
1961  * Register client side sleeping lock.
1962  *
1963  * Our client code calls this to keep information
1964  * about sleeping lock somewhere. When it receives
1965  * grant callback from server or when it just
1966  * needs to remove all sleeping locks from vnode,
1967  * it uses this information for remove/apply lock
1968  * properly.
1969  */
1970 struct nlm_slock *
1971 nlm_slock_register(
1972 	struct nlm_globals *g,
1973 	struct nlm_host *host,
1974 	struct nlm4_lock *lock,
1975 	struct vnode *vp)
1976 {
1977 	struct nlm_slock *nslp;
1978 
1979 	nslp = kmem_zalloc(sizeof (*nslp), KM_SLEEP);
1980 	cv_init(&nslp->nsl_cond, NULL, CV_DEFAULT, NULL);
1981 	nslp->nsl_lock = *lock;
1982 	nlm_copy_netobj(&nslp->nsl_fh, &nslp->nsl_lock.fh);
1983 	nslp->nsl_state = NLM_SL_BLOCKED;
1984 	nslp->nsl_host = host;
1985 	nslp->nsl_vp = vp;
1986 
1987 	mutex_enter(&g->lock);
1988 	TAILQ_INSERT_TAIL(&g->nlm_slocks, nslp, nsl_link);
1989 	mutex_exit(&g->lock);
1990 
1991 	return (nslp);
1992 }
1993 
1994 /*
1995  * Remove this lock from the wait list and destroy it.
1996  */
1997 void
1998 nlm_slock_unregister(struct nlm_globals *g, struct nlm_slock *nslp)
1999 {
2000 	mutex_enter(&g->lock);
2001 	TAILQ_REMOVE(&g->nlm_slocks, nslp, nsl_link);
2002 	mutex_exit(&g->lock);
2003 
2004 	kmem_free(nslp->nsl_fh.n_bytes, nslp->nsl_fh.n_len);
2005 	cv_destroy(&nslp->nsl_cond);
2006 	kmem_free(nslp, sizeof (*nslp));
2007 }
2008 
2009 /*
2010  * Wait for a granted callback or cancellation event
2011  * for a sleeping lock.
2012  *
2013  * If a signal interrupted the wait or if the lock
2014  * was cancelled, return EINTR - the caller must arrange to send
2015  * a cancellation to the server.
2016  *
2017  * If timeout occurred, return ETIMEDOUT - the caller must
2018  * resend the lock request to the server.
2019  *
2020  * On success return 0.
2021  */
2022 int
2023 nlm_slock_wait(struct nlm_globals *g,
2024     struct nlm_slock *nslp, uint_t timeo_secs)
2025 {
2026 	clock_t timeo_ticks;
2027 	int cv_res, error;
2028 
2029 	/*
2030 	 * If the granted message arrived before we got here,
2031 	 * nslp->nsl_state will be NLM_SL_GRANTED - in that case don't sleep.
2032 	 */
2033 	cv_res = 1;
2034 	timeo_ticks = ddi_get_lbolt() + SEC_TO_TICK(timeo_secs);
2035 
2036 	mutex_enter(&g->lock);
2037 	while (nslp->nsl_state == NLM_SL_BLOCKED && cv_res > 0) {
2038 		cv_res = cv_timedwait_sig(&nslp->nsl_cond,
2039 		    &g->lock, timeo_ticks);
2040 	}
2041 
2042 	/*
2043 	 * No matter why we wake up, if the lock was
2044 	 * cancelled, let the function caller to know
2045 	 * about it by returning EINTR.
2046 	 */
2047 	if (nslp->nsl_state == NLM_SL_CANCELLED) {
2048 		error = EINTR;
2049 		goto out;
2050 	}
2051 
2052 	if (cv_res <= 0) {
2053 		/* We were woken up either by timeout or by interrupt */
2054 		error = (cv_res < 0) ? ETIMEDOUT : EINTR;
2055 
2056 		/*
2057 		 * The granted message may arrive after the
2058 		 * interrupt/timeout but before we manage to lock the
2059 		 * mutex. Detect this by examining nslp.
2060 		 */
2061 		if (nslp->nsl_state == NLM_SL_GRANTED)
2062 			error = 0;
2063 	} else { /* Awaken via cv_signal()/cv_broadcast() or didn't block */
2064 		error = 0;
2065 		VERIFY(nslp->nsl_state == NLM_SL_GRANTED);
2066 	}
2067 
2068 out:
2069 	mutex_exit(&g->lock);
2070 	return (error);
2071 }
2072 
2073 /*
2074  * Mark client side sleeping lock as granted
2075  * and wake up a process blocked on the lock.
2076  * Called from server side NLM_GRANT handler.
2077  *
2078  * If sleeping lock is found return 0, otherwise
2079  * return ENOENT.
2080  */
2081 int
2082 nlm_slock_grant(struct nlm_globals *g,
2083     struct nlm_host *hostp, struct nlm4_lock *alock)
2084 {
2085 	struct nlm_slock *nslp;
2086 	int error = ENOENT;
2087 
2088 	mutex_enter(&g->lock);
2089 	TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) {
2090 		if ((nslp->nsl_state != NLM_SL_BLOCKED) ||
2091 		    (nslp->nsl_host != hostp))
2092 			continue;
2093 
2094 		if (alock->svid		== nslp->nsl_lock.svid &&
2095 		    alock->l_offset	== nslp->nsl_lock.l_offset &&
2096 		    alock->l_len	== nslp->nsl_lock.l_len &&
2097 		    alock->fh.n_len	== nslp->nsl_lock.fh.n_len &&
2098 		    bcmp(alock->fh.n_bytes, nslp->nsl_lock.fh.n_bytes,
2099 		    nslp->nsl_lock.fh.n_len) == 0) {
2100 			nslp->nsl_state = NLM_SL_GRANTED;
2101 			cv_broadcast(&nslp->nsl_cond);
2102 			error = 0;
2103 			break;
2104 		}
2105 	}
2106 
2107 	mutex_exit(&g->lock);
2108 	return (error);
2109 }
2110 
2111 /*
2112  * Register sleeping lock request corresponding to
2113  * flp on the given vhold object.
2114  * On success function returns 0, otherwise (if
2115  * lock request with the same flp is already
2116  * registered) function returns EEXIST.
2117  */
2118 int
2119 nlm_slreq_register(struct nlm_host *hostp, struct nlm_vhold *nvp,
2120     struct flock64 *flp)
2121 {
2122 	struct nlm_slreq *slr, *new_slr = NULL;
2123 	int ret = EEXIST;
2124 
2125 	mutex_enter(&hostp->nh_lock);
2126 	slr = nlm_slreq_find_locked(hostp, nvp, flp);
2127 	if (slr != NULL)
2128 		goto out;
2129 
2130 	mutex_exit(&hostp->nh_lock);
2131 	new_slr = kmem_zalloc(sizeof (*slr), KM_SLEEP);
2132 	bcopy(flp, &new_slr->nsr_fl, sizeof (*flp));
2133 
2134 	mutex_enter(&hostp->nh_lock);
2135 	slr = nlm_slreq_find_locked(hostp, nvp, flp);
2136 	if (slr == NULL) {
2137 		slr = new_slr;
2138 		new_slr = NULL;
2139 		ret = 0;
2140 
2141 		TAILQ_INSERT_TAIL(&nvp->nv_slreqs, slr, nsr_link);
2142 	}
2143 
2144 out:
2145 	mutex_exit(&hostp->nh_lock);
2146 	if (new_slr != NULL)
2147 		kmem_free(new_slr, sizeof (*new_slr));
2148 
2149 	return (ret);
2150 }
2151 
2152 /*
2153  * Unregister sleeping lock request corresponding
2154  * to flp from the given vhold object.
2155  * On success function returns 0, otherwise (if
2156  * lock request corresponding to flp isn't found
2157  * on the given vhold) function returns ENOENT.
2158  */
2159 int
2160 nlm_slreq_unregister(struct nlm_host *hostp, struct nlm_vhold *nvp,
2161     struct flock64 *flp)
2162 {
2163 	struct nlm_slreq *slr;
2164 
2165 	mutex_enter(&hostp->nh_lock);
2166 	slr = nlm_slreq_find_locked(hostp, nvp, flp);
2167 	if (slr == NULL) {
2168 		mutex_exit(&hostp->nh_lock);
2169 		return (ENOENT);
2170 	}
2171 
2172 	TAILQ_REMOVE(&nvp->nv_slreqs, slr, nsr_link);
2173 	mutex_exit(&hostp->nh_lock);
2174 
2175 	kmem_free(slr, sizeof (*slr));
2176 	return (0);
2177 }
2178 
2179 /*
2180  * Find sleeping lock request on the given vhold object by flp.
2181  */
2182 struct nlm_slreq *
2183 nlm_slreq_find_locked(struct nlm_host *hostp, struct nlm_vhold *nvp,
2184     struct flock64 *flp)
2185 {
2186 	struct nlm_slreq *slr = NULL;
2187 
2188 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
2189 	TAILQ_FOREACH(slr, &nvp->nv_slreqs, nsr_link) {
2190 		if (slr->nsr_fl.l_start		== flp->l_start	&&
2191 		    slr->nsr_fl.l_len		== flp->l_len	&&
2192 		    slr->nsr_fl.l_pid		== flp->l_pid	&&
2193 		    slr->nsr_fl.l_type		== flp->l_type)
2194 			break;
2195 	}
2196 
2197 	return (slr);
2198 }
2199 
2200 /*
2201  * NLM tracks active share reservations made on the client side.
2202  * It needs to have a track of share reservations for two purposes
2203  * 1) to determine if nlm_host is busy (if it has active locks and/or
2204  *    share reservations, it is)
2205  * 2) to recover active share reservations when NLM server reports
2206  *    that it has rebooted.
2207  *
2208  * Unfortunately Illumos local share reservations manager (see os/share.c)
2209  * doesn't have an ability to lookup all reservations on the system
2210  * by sysid (like local lock manager) or get all reservations by sysid.
2211  * It tracks reservations per vnode and is able to get/looup them
2212  * on particular vnode. It's not what NLM needs. Thus it has that ugly
2213  * share reservations tracking scheme.
2214  */
2215 
2216 void
2217 nlm_shres_track(struct nlm_host *hostp, vnode_t *vp, struct shrlock *shrp)
2218 {
2219 	struct nlm_shres *nsp, *nsp_new;
2220 
2221 	/*
2222 	 * NFS code must fill the s_owner, so that
2223 	 * s_own_len is never 0.
2224 	 */
2225 	ASSERT(shrp->s_own_len > 0);
2226 	nsp_new = nlm_shres_create_item(shrp, vp);
2227 
2228 	mutex_enter(&hostp->nh_lock);
2229 	for (nsp = hostp->nh_shrlist; nsp != NULL; nsp = nsp->ns_next)
2230 		if (nsp->ns_vp == vp && nlm_shres_equal(shrp, nsp->ns_shr))
2231 			break;
2232 
2233 	if (nsp != NULL) {
2234 		/*
2235 		 * Found a duplicate. Do nothing.
2236 		 */
2237 
2238 		goto out;
2239 	}
2240 
2241 	nsp = nsp_new;
2242 	nsp_new = NULL;
2243 	nsp->ns_next = hostp->nh_shrlist;
2244 	hostp->nh_shrlist = nsp;
2245 
2246 out:
2247 	mutex_exit(&hostp->nh_lock);
2248 	if (nsp_new != NULL)
2249 		nlm_shres_destroy_item(nsp_new);
2250 }
2251 
2252 void
2253 nlm_shres_untrack(struct nlm_host *hostp, vnode_t *vp, struct shrlock *shrp)
2254 {
2255 	struct nlm_shres *nsp, *nsp_prev = NULL;
2256 
2257 	mutex_enter(&hostp->nh_lock);
2258 	nsp = hostp->nh_shrlist;
2259 	while (nsp != NULL) {
2260 		if (nsp->ns_vp == vp && nlm_shres_equal(shrp, nsp->ns_shr)) {
2261 			struct nlm_shres *nsp_del;
2262 
2263 			nsp_del = nsp;
2264 			nsp = nsp->ns_next;
2265 			if (nsp_prev != NULL)
2266 				nsp_prev->ns_next = nsp;
2267 			else
2268 				hostp->nh_shrlist = nsp;
2269 
2270 			nlm_shres_destroy_item(nsp_del);
2271 			continue;
2272 		}
2273 
2274 		nsp_prev = nsp;
2275 		nsp = nsp->ns_next;
2276 	}
2277 
2278 	mutex_exit(&hostp->nh_lock);
2279 }
2280 
2281 /*
2282  * Get a _copy_ of the list of all active share reservations
2283  * made by the given host.
2284  * NOTE: the list function returns _must_ be released using
2285  *       nlm_free_shrlist().
2286  */
2287 struct nlm_shres *
2288 nlm_get_active_shres(struct nlm_host *hostp)
2289 {
2290 	struct nlm_shres *nsp, *nslist = NULL;
2291 
2292 	mutex_enter(&hostp->nh_lock);
2293 	for (nsp = hostp->nh_shrlist; nsp != NULL; nsp = nsp->ns_next) {
2294 		struct nlm_shres *nsp_new;
2295 
2296 		nsp_new = nlm_shres_create_item(nsp->ns_shr, nsp->ns_vp);
2297 		nsp_new->ns_next = nslist;
2298 		nslist = nsp_new;
2299 	}
2300 
2301 	mutex_exit(&hostp->nh_lock);
2302 	return (nslist);
2303 }
2304 
2305 /*
2306  * Free memory allocated for the active share reservations
2307  * list created by nlm_get_active_shres() function.
2308  */
2309 void
2310 nlm_free_shrlist(struct nlm_shres *nslist)
2311 {
2312 	struct nlm_shres *nsp;
2313 
2314 	while (nslist != NULL) {
2315 		nsp =  nslist;
2316 		nslist = nslist->ns_next;
2317 
2318 		nlm_shres_destroy_item(nsp);
2319 	}
2320 }
2321 
2322 static bool_t
2323 nlm_shres_equal(struct shrlock *shrp1, struct shrlock *shrp2)
2324 {
2325 	if (shrp1->s_sysid	== shrp2->s_sysid	&&
2326 	    shrp1->s_pid	== shrp2->s_pid		&&
2327 	    shrp1->s_own_len	== shrp2->s_own_len	&&
2328 	    bcmp(shrp1->s_owner, shrp2->s_owner,
2329 	    shrp1->s_own_len) == 0)
2330 		return (TRUE);
2331 
2332 	return (FALSE);
2333 }
2334 
2335 static struct nlm_shres *
2336 nlm_shres_create_item(struct shrlock *shrp, vnode_t *vp)
2337 {
2338 	struct nlm_shres *nsp;
2339 
2340 	nsp = kmem_alloc(sizeof (*nsp), KM_SLEEP);
2341 	nsp->ns_shr = kmem_alloc(sizeof (*shrp), KM_SLEEP);
2342 	bcopy(shrp, nsp->ns_shr, sizeof (*shrp));
2343 	nsp->ns_shr->s_owner = kmem_alloc(shrp->s_own_len, KM_SLEEP);
2344 	bcopy(shrp->s_owner, nsp->ns_shr->s_owner, shrp->s_own_len);
2345 	nsp->ns_vp = vp;
2346 
2347 	return (nsp);
2348 }
2349 
2350 static void
2351 nlm_shres_destroy_item(struct nlm_shres *nsp)
2352 {
2353 	kmem_free(nsp->ns_shr->s_owner,
2354 	    nsp->ns_shr->s_own_len);
2355 	kmem_free(nsp->ns_shr, sizeof (struct shrlock));
2356 	kmem_free(nsp, sizeof (*nsp));
2357 }
2358 
2359 /*
2360  * Called by klmmod.c when lockd adds a network endpoint
2361  * on which we should begin RPC services.
2362  */
2363 int
2364 nlm_svc_add_ep(struct file *fp, const char *netid, struct knetconfig *knc)
2365 {
2366 	SVCMASTERXPRT *xprt = NULL;
2367 	int error;
2368 
2369 	error = svc_tli_kcreate(fp, 0, (char *)netid, NULL, &xprt,
2370 	    &nlm_sct, NULL, NLM_SVCPOOL_ID, FALSE);
2371 	if (error != 0)
2372 		return (error);
2373 
2374 	(void) nlm_knc_to_netid(knc);
2375 	return (0);
2376 }
2377 
2378 /*
2379  * Start NLM service.
2380  */
2381 int
2382 nlm_svc_starting(struct nlm_globals *g, struct file *fp,
2383     const char *netid, struct knetconfig *knc)
2384 {
2385 	int error;
2386 	enum clnt_stat stat;
2387 
2388 	VERIFY(g->run_status == NLM_ST_STARTING);
2389 	VERIFY(g->nlm_gc_thread == NULL);
2390 
2391 	error = nlm_nsm_init_local(&g->nlm_nsm);
2392 	if (error != 0) {
2393 		NLM_ERR("Failed to initialize NSM handler "
2394 		    "(error=%d)\n", error);
2395 		g->run_status = NLM_ST_DOWN;
2396 		return (error);
2397 	}
2398 
2399 	error = EIO;
2400 
2401 	/*
2402 	 * Create an NLM garbage collector thread that will
2403 	 * clean up stale vholds and hosts objects.
2404 	 */
2405 	g->nlm_gc_thread = zthread_create(NULL, 0, nlm_gc,
2406 	    g, 0, minclsyspri);
2407 
2408 	/*
2409 	 * Send SIMU_CRASH to local statd to report that
2410 	 * NLM started, so that statd can report other hosts
2411 	 * about NLM state change.
2412 	 */
2413 
2414 	stat = nlm_nsm_simu_crash(&g->nlm_nsm);
2415 	if (stat != RPC_SUCCESS) {
2416 		NLM_ERR("Failed to connect to local statd "
2417 		    "(rpcerr=%d)\n", stat);
2418 		goto shutdown_lm;
2419 	}
2420 
2421 	stat = nlm_nsm_stat(&g->nlm_nsm, &g->nsm_state);
2422 	if (stat != RPC_SUCCESS) {
2423 		NLM_ERR("Failed to get the status of local statd "
2424 		    "(rpcerr=%d)\n", stat);
2425 		goto shutdown_lm;
2426 	}
2427 
2428 	g->grace_threshold = ddi_get_lbolt() +
2429 	    SEC_TO_TICK(g->grace_period);
2430 
2431 	/* Register endpoint used for communications with local NLM */
2432 	error = nlm_svc_add_ep(fp, netid, knc);
2433 	if (error != 0)
2434 		goto shutdown_lm;
2435 
2436 	(void) svc_pool_control(NLM_SVCPOOL_ID,
2437 	    SVCPSET_SHUTDOWN_PROC, (void *)nlm_pool_shutdown);
2438 	g->run_status = NLM_ST_UP;
2439 	return (0);
2440 
2441 shutdown_lm:
2442 	mutex_enter(&g->lock);
2443 	g->run_status = NLM_ST_STOPPING;
2444 	mutex_exit(&g->lock);
2445 
2446 	nlm_svc_stopping(g);
2447 	return (error);
2448 }
2449 
2450 /*
2451  * Called when the server pool is destroyed, so that
2452  * all transports are closed and no any server threads
2453  * exist.
2454  *
2455  * Just call lm_shutdown() to shut NLM down properly.
2456  */
2457 static void
2458 nlm_pool_shutdown(void)
2459 {
2460 	(void) lm_shutdown();
2461 }
2462 
2463 /*
2464  * Stop NLM service, cleanup all resources
2465  * NLM owns at the moment.
2466  *
2467  * NOTE: NFS code can call NLM while it's
2468  * stopping or even if it's shut down. Any attempt
2469  * to lock file either on client or on the server
2470  * will fail if NLM isn't in NLM_ST_UP state.
2471  */
2472 void
2473 nlm_svc_stopping(struct nlm_globals *g)
2474 {
2475 	mutex_enter(&g->lock);
2476 	ASSERT(g->run_status == NLM_ST_STOPPING);
2477 
2478 	/*
2479 	 * Ask NLM GC thread to exit and wait until it dies.
2480 	 */
2481 	cv_signal(&g->nlm_gc_sched_cv);
2482 	while (g->nlm_gc_thread != NULL)
2483 		cv_wait(&g->nlm_gc_finish_cv, &g->lock);
2484 
2485 	mutex_exit(&g->lock);
2486 
2487 	/*
2488 	 * Cleanup locks owned by NLM hosts.
2489 	 * NOTE: New hosts won't be created while
2490 	 * NLM is stopping.
2491 	 */
2492 	while (!avl_is_empty(&g->nlm_hosts_tree)) {
2493 		struct nlm_host *hostp;
2494 		int busy_hosts = 0;
2495 
2496 		/*
2497 		 * Iterate through all NLM hosts in the system
2498 		 * and drop the locks they own by force.
2499 		 */
2500 		hostp = avl_first(&g->nlm_hosts_tree);
2501 		while (hostp != NULL) {
2502 			/* Cleanup all client and server side locks */
2503 			nlm_client_cancel_all(g, hostp);
2504 			nlm_host_notify_server(hostp, 0);
2505 
2506 			mutex_enter(&hostp->nh_lock);
2507 			nlm_host_gc_vholds(hostp);
2508 			if (hostp->nh_refs > 0 || nlm_host_has_locks(hostp)) {
2509 				/*
2510 				 * Oh, it seems the host is still busy, let
2511 				 * it some time to release and go to the
2512 				 * next one.
2513 				 */
2514 
2515 				mutex_exit(&hostp->nh_lock);
2516 				hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2517 				busy_hosts++;
2518 				continue;
2519 			}
2520 
2521 			mutex_exit(&hostp->nh_lock);
2522 			hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2523 		}
2524 
2525 		/*
2526 		 * All hosts go to nlm_idle_hosts list after
2527 		 * all locks they own are cleaned up and last refereces
2528 		 * were dropped. Just destroy all hosts in nlm_idle_hosts
2529 		 * list, they can not be removed from there while we're
2530 		 * in stopping state.
2531 		 */
2532 		while ((hostp = TAILQ_FIRST(&g->nlm_idle_hosts)) != NULL) {
2533 			nlm_host_unregister(g, hostp);
2534 			nlm_host_destroy(hostp);
2535 		}
2536 
2537 		if (busy_hosts > 0) {
2538 			/*
2539 			 * There're some hosts that weren't cleaned
2540 			 * up. Probably they're in resource cleanup
2541 			 * process. Give them some time to do drop
2542 			 * references.
2543 			 */
2544 			delay(MSEC_TO_TICK(500));
2545 		}
2546 	}
2547 
2548 	ASSERT(TAILQ_EMPTY(&g->nlm_slocks));
2549 
2550 	nlm_nsm_fini(&g->nlm_nsm);
2551 	g->lockd_pid = 0;
2552 	g->run_status = NLM_ST_DOWN;
2553 }
2554 
2555 /*
2556  * Returns TRUE if the given vnode has
2557  * any active or sleeping locks.
2558  */
2559 int
2560 nlm_vp_active(const vnode_t *vp)
2561 {
2562 	struct nlm_globals *g;
2563 	struct nlm_host *hostp;
2564 	struct nlm_vhold *nvp;
2565 	int active = 0;
2566 
2567 	g = zone_getspecific(nlm_zone_key, curzone);
2568 
2569 	/*
2570 	 * Server side NLM has locks on the given vnode
2571 	 * if there exist a vhold object that holds
2572 	 * the given vnode "vp" in one of NLM hosts.
2573 	 */
2574 	mutex_enter(&g->lock);
2575 	hostp = avl_first(&g->nlm_hosts_tree);
2576 	while (hostp != NULL) {
2577 		mutex_enter(&hostp->nh_lock);
2578 		nvp = nlm_vhold_find_locked(hostp, vp);
2579 		mutex_exit(&hostp->nh_lock);
2580 		if (nvp != NULL) {
2581 			active = 1;
2582 			break;
2583 		}
2584 
2585 		hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2586 	}
2587 
2588 	mutex_exit(&g->lock);
2589 	return (active);
2590 }
2591 
2592 /*
2593  * Called right before NFS export is going to
2594  * dissapear. The function finds all vnodes
2595  * belonging to the given export and cleans
2596  * all remote locks and share reservations
2597  * on them.
2598  */
2599 void
2600 nlm_zone_unexport(struct nlm_globals *g, struct exportinfo *exi)
2601 {
2602 	struct nlm_host *hostp;
2603 
2604 	mutex_enter(&g->lock);
2605 	if (g->run_status != NLM_ST_UP) {
2606 		/* nothing to do */
2607 		mutex_exit(&g->lock);
2608 		return;
2609 	}
2610 
2611 	hostp = avl_first(&g->nlm_hosts_tree);
2612 	while (hostp != NULL) {
2613 		struct nlm_vhold *nvp;
2614 
2615 		if (hostp->nh_flags & NLM_NH_INIDLE) {
2616 			TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
2617 			hostp->nh_flags &= ~NLM_NH_INIDLE;
2618 		}
2619 		hostp->nh_refs++;
2620 
2621 		mutex_exit(&g->lock);
2622 
2623 		mutex_enter(&hostp->nh_lock);
2624 		TAILQ_FOREACH(nvp, &hostp->nh_vholds_list, nv_link) {
2625 			vnode_t *vp;
2626 
2627 			nvp->nv_refcnt++;
2628 			mutex_exit(&hostp->nh_lock);
2629 
2630 			vp = nvp->nv_vp;
2631 
2632 			if (!EQFSID(&exi->exi_fsid, &vp->v_vfsp->vfs_fsid))
2633 				goto next_iter;
2634 
2635 			/*
2636 			 * Ok, it we found out that vnode vp is under
2637 			 * control by the exportinfo exi, now we need
2638 			 * to drop all locks from this vnode, let's
2639 			 * do it.
2640 			 */
2641 			nlm_vhold_clean(nvp, hostp->nh_sysid);
2642 
2643 		next_iter:
2644 			mutex_enter(&hostp->nh_lock);
2645 			nvp->nv_refcnt--;
2646 		}
2647 		mutex_exit(&hostp->nh_lock);
2648 
2649 		mutex_enter(&g->lock);
2650 		nlm_host_release_locked(g, hostp);
2651 
2652 		hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2653 	}
2654 
2655 	mutex_exit(&g->lock);
2656 }
2657 
2658 void
2659 nlm_unexport(struct exportinfo *exi)
2660 {
2661 	struct nlm_globals *g;
2662 
2663 	rw_enter(&lm_lck, RW_READER);
2664 	TAILQ_FOREACH(g, &nlm_zones_list, nlm_link) {
2665 		if (g->nlm_zoneid == exi->exi_zoneid) {
2666 			/*
2667 			 * NOTE: If we want to drop lm_lock before
2668 			 * calling nlm_zone_unexport(), we should break,
2669 			 * and have a post-rw_exit() snippit like:
2670 			 *	if (g != NULL)
2671 			 *		nlm_zone_unexport(g, exi);
2672 			 */
2673 			nlm_zone_unexport(g, exi);
2674 			break; /* Only going to match once! */
2675 		}
2676 	}
2677 	rw_exit(&lm_lck);
2678 }
2679 
2680 /*
2681  * Allocate new unique sysid.
2682  * In case of failure (no available sysids)
2683  * return LM_NOSYSID.
2684  */
2685 sysid_t
2686 nlm_sysid_alloc(void)
2687 {
2688 	sysid_t ret_sysid = LM_NOSYSID;
2689 
2690 	rw_enter(&lm_lck, RW_WRITER);
2691 	if (nlm_sysid_nidx > LM_SYSID_MAX)
2692 		nlm_sysid_nidx = LM_SYSID;
2693 
2694 	if (!BT_TEST(nlm_sysid_bmap, nlm_sysid_nidx)) {
2695 		BT_SET(nlm_sysid_bmap, nlm_sysid_nidx);
2696 		ret_sysid = nlm_sysid_nidx++;
2697 	} else {
2698 		index_t id;
2699 
2700 		id = bt_availbit(nlm_sysid_bmap, NLM_BMAP_NITEMS);
2701 		if (id > 0) {
2702 			nlm_sysid_nidx = id + 1;
2703 			ret_sysid = id;
2704 			BT_SET(nlm_sysid_bmap, id);
2705 		}
2706 	}
2707 
2708 	rw_exit(&lm_lck);
2709 	return (ret_sysid);
2710 }
2711 
2712 void
2713 nlm_sysid_free(sysid_t sysid)
2714 {
2715 	ASSERT(sysid >= LM_SYSID && sysid <= LM_SYSID_MAX);
2716 
2717 	rw_enter(&lm_lck, RW_WRITER);
2718 	ASSERT(BT_TEST(nlm_sysid_bmap, sysid));
2719 	BT_CLEAR(nlm_sysid_bmap, sysid);
2720 	rw_exit(&lm_lck);
2721 }
2722 
2723 /*
2724  * Return true if the request came from a local caller.
2725  * By necessity, this "knows" the netid names invented
2726  * in lm_svc() and nlm_netid_from_knetconfig().
2727  */
2728 bool_t
2729 nlm_caller_is_local(SVCXPRT *transp)
2730 {
2731 	char *netid;
2732 	struct netbuf *rtaddr;
2733 
2734 	netid = svc_getnetid(transp);
2735 	rtaddr = svc_getrpccaller(transp);
2736 
2737 	if (netid == NULL)
2738 		return (FALSE);
2739 
2740 	if (strcmp(netid, "ticlts") == 0 ||
2741 	    strcmp(netid, "ticotsord") == 0)
2742 		return (TRUE);
2743 
2744 	if (strcmp(netid, "tcp") == 0 || strcmp(netid, "udp") == 0) {
2745 		struct sockaddr_in *sin = (void *)rtaddr->buf;
2746 		if (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
2747 			return (TRUE);
2748 	}
2749 	if (strcmp(netid, "tcp6") == 0 || strcmp(netid, "udp6") == 0) {
2750 		struct sockaddr_in6 *sin6 = (void *)rtaddr->buf;
2751 		if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
2752 			return (TRUE);
2753 	}
2754 
2755 	return (FALSE); /* unknown transport */
2756 }
2757 
2758 /*
2759  * Get netid string correspondig to the given knetconfig.
2760  * If not done already, save knc->knc_rdev in our table.
2761  */
2762 const char *
2763 nlm_knc_to_netid(struct knetconfig *knc)
2764 {
2765 	int i;
2766 	dev_t rdev;
2767 	struct nlm_knc *nc;
2768 	const char *netid = NULL;
2769 
2770 	rw_enter(&lm_lck, RW_READER);
2771 	for (i = 0; i < NLM_KNCS; i++) {
2772 		nc = &nlm_netconfigs[i];
2773 
2774 		if (nc->n_knc.knc_semantics == knc->knc_semantics &&
2775 		    strcmp(nc->n_knc.knc_protofmly,
2776 		    knc->knc_protofmly) == 0) {
2777 			netid = nc->n_netid;
2778 			rdev = nc->n_knc.knc_rdev;
2779 			break;
2780 		}
2781 	}
2782 	rw_exit(&lm_lck);
2783 
2784 	if (netid != NULL && rdev == NODEV) {
2785 		rw_enter(&lm_lck, RW_WRITER);
2786 		if (nc->n_knc.knc_rdev == NODEV)
2787 			nc->n_knc.knc_rdev = knc->knc_rdev;
2788 		rw_exit(&lm_lck);
2789 	}
2790 
2791 	return (netid);
2792 }
2793 
2794 /*
2795  * Get a knetconfig corresponding to the given netid.
2796  * If there's no knetconfig for this netid, ENOENT
2797  * is returned.
2798  */
2799 int
2800 nlm_knc_from_netid(const char *netid, struct knetconfig *knc)
2801 {
2802 	int i, ret;
2803 
2804 	ret = ENOENT;
2805 	for (i = 0; i < NLM_KNCS; i++) {
2806 		struct nlm_knc *nknc;
2807 
2808 		nknc = &nlm_netconfigs[i];
2809 		if (strcmp(netid, nknc->n_netid) == 0 &&
2810 		    nknc->n_knc.knc_rdev != NODEV) {
2811 			*knc = nknc->n_knc;
2812 			ret = 0;
2813 			break;
2814 		}
2815 	}
2816 
2817 	return (ret);
2818 }
2819 
2820 void
2821 nlm_cprsuspend(void)
2822 {
2823 	struct nlm_globals *g;
2824 
2825 	rw_enter(&lm_lck, RW_READER);
2826 	TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
2827 		nlm_suspend_zone(g);
2828 
2829 	rw_exit(&lm_lck);
2830 }
2831 
2832 void
2833 nlm_cprresume(void)
2834 {
2835 	struct nlm_globals *g;
2836 
2837 	rw_enter(&lm_lck, RW_READER);
2838 	TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
2839 		nlm_resume_zone(g);
2840 
2841 	rw_exit(&lm_lck);
2842 }
2843 
2844 static void
2845 nlm_nsm_clnt_init(CLIENT *clnt, struct nlm_nsm *nsm)
2846 {
2847 	(void) clnt_tli_kinit(clnt, &nsm->ns_knc, &nsm->ns_addr, 0,
2848 	    NLM_RPC_RETRIES, zone_kcred());
2849 }
2850 
2851 static void
2852 nlm_netbuf_to_netobj(struct netbuf *addr, int *family, netobj *obj)
2853 {
2854 	/* LINTED pointer alignment */
2855 	struct sockaddr *sa = (struct sockaddr *)addr->buf;
2856 
2857 	*family = sa->sa_family;
2858 
2859 	switch (sa->sa_family) {
2860 	case AF_INET: {
2861 		/* LINTED pointer alignment */
2862 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
2863 
2864 		obj->n_len = sizeof (sin->sin_addr);
2865 		obj->n_bytes = (char *)&sin->sin_addr;
2866 		break;
2867 	}
2868 
2869 	case AF_INET6: {
2870 		/* LINTED pointer alignment */
2871 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
2872 
2873 		obj->n_len = sizeof (sin6->sin6_addr);
2874 		obj->n_bytes = (char *)&sin6->sin6_addr;
2875 		break;
2876 	}
2877 
2878 	default:
2879 		VERIFY(0);
2880 		break;
2881 	}
2882 }
2883