xref: /illumos-gate/usr/src/uts/common/klm/nlm_impl.c (revision 0dfe541e)
1bbaa8b60SDan Kruchinin /*
2bbaa8b60SDan Kruchinin  * Copyright (c) 2008 Isilon Inc http://www.isilon.com/
3bbaa8b60SDan Kruchinin  * Authors: Doug Rabson <dfr@rabson.org>
4bbaa8b60SDan Kruchinin  * Developed with Red Inc: Alfred Perlstein <alfred@freebsd.org>
5bbaa8b60SDan Kruchinin  *
6bbaa8b60SDan Kruchinin  * Redistribution and use in source and binary forms, with or without
7bbaa8b60SDan Kruchinin  * modification, are permitted provided that the following conditions
8bbaa8b60SDan Kruchinin  * are met:
9bbaa8b60SDan Kruchinin  * 1. Redistributions of source code must retain the above copyright
10bbaa8b60SDan Kruchinin  *    notice, this list of conditions and the following disclaimer.
11bbaa8b60SDan Kruchinin  * 2. Redistributions in binary form must reproduce the above copyright
12bbaa8b60SDan Kruchinin  *    notice, this list of conditions and the following disclaimer in the
13bbaa8b60SDan Kruchinin  *    documentation and/or other materials provided with the distribution.
14bbaa8b60SDan Kruchinin  *
15bbaa8b60SDan Kruchinin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16bbaa8b60SDan Kruchinin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17bbaa8b60SDan Kruchinin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18bbaa8b60SDan Kruchinin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19bbaa8b60SDan Kruchinin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20bbaa8b60SDan Kruchinin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21bbaa8b60SDan Kruchinin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22bbaa8b60SDan Kruchinin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23bbaa8b60SDan Kruchinin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24bbaa8b60SDan Kruchinin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25bbaa8b60SDan Kruchinin  * SUCH DAMAGE.
26bbaa8b60SDan Kruchinin  */
27bbaa8b60SDan Kruchinin 
28bbaa8b60SDan Kruchinin /*
29b1087aecSMarcel Telka  * Copyright 2015 Nexenta Systems, Inc.  All rights reserved.
30bbaa8b60SDan Kruchinin  * Copyright (c) 2012 by Delphix. All rights reserved.
31bbaa8b60SDan Kruchinin  */
32bbaa8b60SDan Kruchinin 
33bbaa8b60SDan Kruchinin /*
34bbaa8b60SDan Kruchinin  * NFS LockManager, start/stop, support functions, etc.
35bbaa8b60SDan Kruchinin  * Most of the interesting code is here.
36bbaa8b60SDan Kruchinin  *
37bbaa8b60SDan Kruchinin  * Source code derived from FreeBSD nlm_prot_impl.c
38bbaa8b60SDan Kruchinin  */
39bbaa8b60SDan Kruchinin 
40bbaa8b60SDan Kruchinin #include <sys/param.h>
41bbaa8b60SDan Kruchinin #include <sys/systm.h>
42bbaa8b60SDan Kruchinin #include <sys/thread.h>
43bbaa8b60SDan Kruchinin #include <sys/fcntl.h>
44bbaa8b60SDan Kruchinin #include <sys/flock.h>
45bbaa8b60SDan Kruchinin #include <sys/mount.h>
46bbaa8b60SDan Kruchinin #include <sys/priv.h>
47bbaa8b60SDan Kruchinin #include <sys/proc.h>
48bbaa8b60SDan Kruchinin #include <sys/share.h>
49bbaa8b60SDan Kruchinin #include <sys/socket.h>
50bbaa8b60SDan Kruchinin #include <sys/syscall.h>
51bbaa8b60SDan Kruchinin #include <sys/syslog.h>
52bbaa8b60SDan Kruchinin #include <sys/systm.h>
53bbaa8b60SDan Kruchinin #include <sys/class.h>
54bbaa8b60SDan Kruchinin #include <sys/unistd.h>
55bbaa8b60SDan Kruchinin #include <sys/vnode.h>
56bbaa8b60SDan Kruchinin #include <sys/vfs.h>
57bbaa8b60SDan Kruchinin #include <sys/queue.h>
58bbaa8b60SDan Kruchinin #include <sys/bitmap.h>
59bbaa8b60SDan Kruchinin #include <sys/sdt.h>
60bbaa8b60SDan Kruchinin #include <netinet/in.h>
61bbaa8b60SDan Kruchinin 
62bbaa8b60SDan Kruchinin #include <rpc/rpc.h>
63bbaa8b60SDan Kruchinin #include <rpc/xdr.h>
64bbaa8b60SDan Kruchinin #include <rpc/pmap_prot.h>
65bbaa8b60SDan Kruchinin #include <rpc/pmap_clnt.h>
66bbaa8b60SDan Kruchinin #include <rpc/rpcb_prot.h>
67bbaa8b60SDan Kruchinin 
68bbaa8b60SDan Kruchinin #include <rpcsvc/nlm_prot.h>
69bbaa8b60SDan Kruchinin #include <rpcsvc/sm_inter.h>
70bbaa8b60SDan Kruchinin #include <rpcsvc/nsm_addr.h>
71bbaa8b60SDan Kruchinin 
72bbaa8b60SDan Kruchinin #include <nfs/nfs.h>
73bbaa8b60SDan Kruchinin #include <nfs/nfs_clnt.h>
74bbaa8b60SDan Kruchinin #include <nfs/export.h>
75bbaa8b60SDan Kruchinin #include <nfs/rnode.h>
76bbaa8b60SDan Kruchinin #include <nfs/lm.h>
77bbaa8b60SDan Kruchinin 
78bbaa8b60SDan Kruchinin #include "nlm_impl.h"
79bbaa8b60SDan Kruchinin 
80bbaa8b60SDan Kruchinin struct nlm_knc {
81bbaa8b60SDan Kruchinin 	struct knetconfig	n_knc;
82bbaa8b60SDan Kruchinin 	const char		*n_netid;
83bbaa8b60SDan Kruchinin };
84bbaa8b60SDan Kruchinin 
85bbaa8b60SDan Kruchinin /*
86bbaa8b60SDan Kruchinin  * Number of attempts NLM tries to obtain RPC binding
87bbaa8b60SDan Kruchinin  * of local statd.
88bbaa8b60SDan Kruchinin  */
89bbaa8b60SDan Kruchinin #define	NLM_NSM_RPCBIND_RETRIES 10
90bbaa8b60SDan Kruchinin 
91bbaa8b60SDan Kruchinin /*
92bbaa8b60SDan Kruchinin  * Timeout (in seconds) NLM waits before making another
93bbaa8b60SDan Kruchinin  * attempt to obtain RPC binding of local statd.
94bbaa8b60SDan Kruchinin  */
95bbaa8b60SDan Kruchinin #define	NLM_NSM_RPCBIND_TIMEOUT 5
96bbaa8b60SDan Kruchinin 
97bbaa8b60SDan Kruchinin /*
98bbaa8b60SDan Kruchinin  * Total number of sysids in NLM sysid bitmap
99bbaa8b60SDan Kruchinin  */
100bbaa8b60SDan Kruchinin #define	NLM_BMAP_NITEMS	(LM_SYSID_MAX + 1)
101bbaa8b60SDan Kruchinin 
102bbaa8b60SDan Kruchinin /*
103bbaa8b60SDan Kruchinin  * Number of ulong_t words in bitmap that is used
104bbaa8b60SDan Kruchinin  * for allocation of sysid numbers.
105bbaa8b60SDan Kruchinin  */
106bbaa8b60SDan Kruchinin #define	NLM_BMAP_WORDS  (NLM_BMAP_NITEMS / BT_NBIPUL)
107bbaa8b60SDan Kruchinin 
108bbaa8b60SDan Kruchinin /*
109bbaa8b60SDan Kruchinin  * Given an integer x, the macro returns
110bbaa8b60SDan Kruchinin  * -1 if x is negative,
111bbaa8b60SDan Kruchinin  *  0 if x is zero
112bbaa8b60SDan Kruchinin  *  1 if x is positive
113bbaa8b60SDan Kruchinin  */
114bbaa8b60SDan Kruchinin #define	SIGN(x) (((x) > 0) - ((x) < 0))
115bbaa8b60SDan Kruchinin 
116bbaa8b60SDan Kruchinin #define	ARRSIZE(arr)	(sizeof (arr) / sizeof ((arr)[0]))
117bbaa8b60SDan Kruchinin #define	NLM_KNCS	ARRSIZE(nlm_netconfigs)
118bbaa8b60SDan Kruchinin 
119bbaa8b60SDan Kruchinin krwlock_t lm_lck;
120bbaa8b60SDan Kruchinin 
121bbaa8b60SDan Kruchinin /*
122bbaa8b60SDan Kruchinin  * Zero timeout for asynchronous NLM RPC operations
123bbaa8b60SDan Kruchinin  */
124bbaa8b60SDan Kruchinin static const struct timeval nlm_rpctv_zero = { 0,  0 };
125bbaa8b60SDan Kruchinin 
126bbaa8b60SDan Kruchinin /*
127bbaa8b60SDan Kruchinin  * List of all Zone globals nlm_globals instences
128bbaa8b60SDan Kruchinin  * linked together.
129bbaa8b60SDan Kruchinin  */
130bbaa8b60SDan Kruchinin static struct nlm_globals_list nlm_zones_list; /* (g) */
131bbaa8b60SDan Kruchinin 
132bbaa8b60SDan Kruchinin /*
133bbaa8b60SDan Kruchinin  * NLM kmem caches
134bbaa8b60SDan Kruchinin  */
135bbaa8b60SDan Kruchinin static struct kmem_cache *nlm_hosts_cache = NULL;
136bbaa8b60SDan Kruchinin static struct kmem_cache *nlm_vhold_cache = NULL;
137bbaa8b60SDan Kruchinin 
138bbaa8b60SDan Kruchinin /*
139bbaa8b60SDan Kruchinin  * A bitmap for allocation of new sysids.
140bbaa8b60SDan Kruchinin  * Sysid is a unique number between LM_SYSID
141bbaa8b60SDan Kruchinin  * and LM_SYSID_MAX. Sysid represents unique remote
142bbaa8b60SDan Kruchinin  * host that does file locks on the given host.
143bbaa8b60SDan Kruchinin  */
144bbaa8b60SDan Kruchinin static ulong_t	nlm_sysid_bmap[NLM_BMAP_WORDS];	/* (g) */
145bbaa8b60SDan Kruchinin static int	nlm_sysid_nidx;			/* (g) */
146bbaa8b60SDan Kruchinin 
147bbaa8b60SDan Kruchinin /*
148bbaa8b60SDan Kruchinin  * RPC service registration for all transports
149bbaa8b60SDan Kruchinin  */
150bbaa8b60SDan Kruchinin static SVC_CALLOUT nlm_svcs[] = {
151bbaa8b60SDan Kruchinin 	{ NLM_PROG, 4, 4, nlm_prog_4 },	/* NLM4_VERS */
152bbaa8b60SDan Kruchinin 	{ NLM_PROG, 1, 3, nlm_prog_3 }	/* NLM_VERS - NLM_VERSX */
153bbaa8b60SDan Kruchinin };
154bbaa8b60SDan Kruchinin 
155bbaa8b60SDan Kruchinin static SVC_CALLOUT_TABLE nlm_sct = {
156bbaa8b60SDan Kruchinin 	ARRSIZE(nlm_svcs),
157bbaa8b60SDan Kruchinin 	FALSE,
158bbaa8b60SDan Kruchinin 	nlm_svcs
159bbaa8b60SDan Kruchinin };
160bbaa8b60SDan Kruchinin 
161bbaa8b60SDan Kruchinin /*
162bbaa8b60SDan Kruchinin  * Static table of all netid/knetconfig network
163bbaa8b60SDan Kruchinin  * lock manager can work with. nlm_netconfigs table
164bbaa8b60SDan Kruchinin  * is used when we need to get valid knetconfig by
165bbaa8b60SDan Kruchinin  * netid and vice versa.
166bbaa8b60SDan Kruchinin  *
167bbaa8b60SDan Kruchinin  * Knetconfigs are activated either by the call from
168bbaa8b60SDan Kruchinin  * user-space lockd daemon (server side) or by taking
169bbaa8b60SDan Kruchinin  * knetconfig from NFS mountinfo (client side)
170bbaa8b60SDan Kruchinin  */
171bbaa8b60SDan Kruchinin static struct nlm_knc nlm_netconfigs[] = { /* (g) */
172bbaa8b60SDan Kruchinin 	/* UDP */
173bbaa8b60SDan Kruchinin 	{
174bbaa8b60SDan Kruchinin 		{ NC_TPI_CLTS, NC_INET, NC_UDP, NODEV },
175bbaa8b60SDan Kruchinin 		"udp",
176bbaa8b60SDan Kruchinin 	},
177bbaa8b60SDan Kruchinin 	/* TCP */
178bbaa8b60SDan Kruchinin 	{
179bbaa8b60SDan Kruchinin 		{ NC_TPI_COTS_ORD, NC_INET, NC_TCP, NODEV },
180bbaa8b60SDan Kruchinin 		"tcp",
181bbaa8b60SDan Kruchinin 	},
182bbaa8b60SDan Kruchinin 	/* UDP over IPv6 */
183bbaa8b60SDan Kruchinin 	{
184bbaa8b60SDan Kruchinin 		{ NC_TPI_CLTS, NC_INET6, NC_UDP, NODEV },
185bbaa8b60SDan Kruchinin 		"udp6",
186bbaa8b60SDan Kruchinin 	},
187bbaa8b60SDan Kruchinin 	/* TCP over IPv6 */
188bbaa8b60SDan Kruchinin 	{
189bbaa8b60SDan Kruchinin 		{ NC_TPI_COTS_ORD, NC_INET6, NC_TCP, NODEV },
190bbaa8b60SDan Kruchinin 		"tcp6",
191bbaa8b60SDan Kruchinin 	},
192bbaa8b60SDan Kruchinin 	/* ticlts (loopback over UDP) */
193bbaa8b60SDan Kruchinin 	{
194bbaa8b60SDan Kruchinin 		{ NC_TPI_CLTS, NC_LOOPBACK, NC_NOPROTO, NODEV },
195bbaa8b60SDan Kruchinin 		"ticlts",
196bbaa8b60SDan Kruchinin 	},
197bbaa8b60SDan Kruchinin 	/* ticotsord (loopback over TCP) */
198bbaa8b60SDan Kruchinin 	{
199bbaa8b60SDan Kruchinin 		{ NC_TPI_COTS_ORD, NC_LOOPBACK, NC_NOPROTO, NODEV },
200bbaa8b60SDan Kruchinin 		"ticotsord",
201bbaa8b60SDan Kruchinin 	},
202bbaa8b60SDan Kruchinin };
203bbaa8b60SDan Kruchinin 
204bbaa8b60SDan Kruchinin /*
205bbaa8b60SDan Kruchinin  * NLM misc. function
206bbaa8b60SDan Kruchinin  */
207bbaa8b60SDan Kruchinin static void nlm_copy_netbuf(struct netbuf *, struct netbuf *);
208bbaa8b60SDan Kruchinin static int nlm_netbuf_addrs_cmp(struct netbuf *, struct netbuf *);
209bbaa8b60SDan Kruchinin static void nlm_kmem_reclaim(void *);
210bbaa8b60SDan Kruchinin static void nlm_pool_shutdown(void);
211bbaa8b60SDan Kruchinin static void nlm_suspend_zone(struct nlm_globals *);
212bbaa8b60SDan Kruchinin static void nlm_resume_zone(struct nlm_globals *);
213bbaa8b60SDan Kruchinin static void nlm_nsm_clnt_init(CLIENT *, struct nlm_nsm *);
214bbaa8b60SDan Kruchinin static void nlm_netbuf_to_netobj(struct netbuf *, int *, netobj *);
215bbaa8b60SDan Kruchinin 
216bbaa8b60SDan Kruchinin /*
217bbaa8b60SDan Kruchinin  * NLM thread functions
218bbaa8b60SDan Kruchinin  */
219bbaa8b60SDan Kruchinin static void nlm_gc(struct nlm_globals *);
220bbaa8b60SDan Kruchinin static void nlm_reclaimer(struct nlm_host *);
221bbaa8b60SDan Kruchinin 
222bbaa8b60SDan Kruchinin /*
223bbaa8b60SDan Kruchinin  * NLM NSM functions
224bbaa8b60SDan Kruchinin  */
225bbaa8b60SDan Kruchinin static int nlm_init_local_knc(struct knetconfig *);
226bbaa8b60SDan Kruchinin static int nlm_nsm_init_local(struct nlm_nsm *);
227bbaa8b60SDan Kruchinin static int nlm_nsm_init(struct nlm_nsm *, struct knetconfig *, struct netbuf *);
228bbaa8b60SDan Kruchinin static void nlm_nsm_fini(struct nlm_nsm *);
229bbaa8b60SDan Kruchinin static enum clnt_stat nlm_nsm_simu_crash(struct nlm_nsm *);
230bbaa8b60SDan Kruchinin static enum clnt_stat nlm_nsm_stat(struct nlm_nsm *, int32_t *);
231bbaa8b60SDan Kruchinin static enum clnt_stat nlm_nsm_mon(struct nlm_nsm *, char *, uint16_t);
232bbaa8b60SDan Kruchinin static enum clnt_stat nlm_nsm_unmon(struct nlm_nsm *, char *);
233bbaa8b60SDan Kruchinin 
234bbaa8b60SDan Kruchinin /*
235bbaa8b60SDan Kruchinin  * NLM host functions
236bbaa8b60SDan Kruchinin  */
237bbaa8b60SDan Kruchinin static int nlm_host_ctor(void *, void *, int);
238bbaa8b60SDan Kruchinin static void nlm_host_dtor(void *, void *);
239bbaa8b60SDan Kruchinin static void nlm_host_destroy(struct nlm_host *);
240bbaa8b60SDan Kruchinin static struct nlm_host *nlm_host_create(char *, const char *,
241bbaa8b60SDan Kruchinin     struct knetconfig *, struct netbuf *);
242bbaa8b60SDan Kruchinin static struct nlm_host *nlm_host_find_locked(struct nlm_globals *,
243bbaa8b60SDan Kruchinin     const char *, struct netbuf *, avl_index_t *);
244bbaa8b60SDan Kruchinin static void nlm_host_unregister(struct nlm_globals *, struct nlm_host *);
245bbaa8b60SDan Kruchinin static void nlm_host_gc_vholds(struct nlm_host *);
246bbaa8b60SDan Kruchinin static bool_t nlm_host_has_srv_locks(struct nlm_host *);
247bbaa8b60SDan Kruchinin static bool_t nlm_host_has_cli_locks(struct nlm_host *);
248bbaa8b60SDan Kruchinin static bool_t nlm_host_has_locks(struct nlm_host *);
249bbaa8b60SDan Kruchinin 
250bbaa8b60SDan Kruchinin /*
251bbaa8b60SDan Kruchinin  * NLM vhold functions
252bbaa8b60SDan Kruchinin  */
253bbaa8b60SDan Kruchinin static int nlm_vhold_ctor(void *, void *, int);
254bbaa8b60SDan Kruchinin static void nlm_vhold_dtor(void *, void *);
255bbaa8b60SDan Kruchinin static void nlm_vhold_destroy(struct nlm_host *,
256bbaa8b60SDan Kruchinin     struct nlm_vhold *);
257bbaa8b60SDan Kruchinin static bool_t nlm_vhold_busy(struct nlm_host *, struct nlm_vhold *);
258bbaa8b60SDan Kruchinin static void nlm_vhold_clean(struct nlm_vhold *, int);
259bbaa8b60SDan Kruchinin 
260bbaa8b60SDan Kruchinin /*
261bbaa8b60SDan Kruchinin  * NLM client/server sleeping locks/share reservation functions
262bbaa8b60SDan Kruchinin  */
263bbaa8b60SDan Kruchinin struct nlm_slreq *nlm_slreq_find_locked(struct nlm_host *,
264bbaa8b60SDan Kruchinin     struct nlm_vhold *, struct flock64 *);
265bbaa8b60SDan Kruchinin static struct nlm_shres *nlm_shres_create_item(struct shrlock *, vnode_t *);
266bbaa8b60SDan Kruchinin static void nlm_shres_destroy_item(struct nlm_shres *);
267bbaa8b60SDan Kruchinin static bool_t nlm_shres_equal(struct shrlock *, struct shrlock *);
268bbaa8b60SDan Kruchinin 
269bbaa8b60SDan Kruchinin /*
270bbaa8b60SDan Kruchinin  * NLM initialization functions.
271bbaa8b60SDan Kruchinin  */
272bbaa8b60SDan Kruchinin void
nlm_init(void)273bbaa8b60SDan Kruchinin nlm_init(void)
274bbaa8b60SDan Kruchinin {
275bbaa8b60SDan Kruchinin 	nlm_hosts_cache = kmem_cache_create("nlm_host_cache",
276bbaa8b60SDan Kruchinin 	    sizeof (struct nlm_host), 0, nlm_host_ctor, nlm_host_dtor,
277bbaa8b60SDan Kruchinin 	    nlm_kmem_reclaim, NULL, NULL, 0);
278bbaa8b60SDan Kruchinin 
279bbaa8b60SDan Kruchinin 	nlm_vhold_cache = kmem_cache_create("nlm_vhold_cache",
280bbaa8b60SDan Kruchinin 	    sizeof (struct nlm_vhold), 0, nlm_vhold_ctor, nlm_vhold_dtor,
281bbaa8b60SDan Kruchinin 	    NULL, NULL, NULL, 0);
282bbaa8b60SDan Kruchinin 
283bbaa8b60SDan Kruchinin 	nlm_rpc_init();
284bbaa8b60SDan Kruchinin 	TAILQ_INIT(&nlm_zones_list);
285bbaa8b60SDan Kruchinin 
286bbaa8b60SDan Kruchinin 	/* initialize sysids bitmap */
287bbaa8b60SDan Kruchinin 	bzero(nlm_sysid_bmap, sizeof (nlm_sysid_bmap));
288bbaa8b60SDan Kruchinin 	nlm_sysid_nidx = 1;
289bbaa8b60SDan Kruchinin 
290bbaa8b60SDan Kruchinin 	/*
291bbaa8b60SDan Kruchinin 	 * Reserv the sysid #0, because it's associated
292bbaa8b60SDan Kruchinin 	 * with local locks only. Don't let to allocate
293bbaa8b60SDan Kruchinin 	 * it for remote locks.
294bbaa8b60SDan Kruchinin 	 */
295bbaa8b60SDan Kruchinin 	BT_SET(nlm_sysid_bmap, 0);
296bbaa8b60SDan Kruchinin }
297bbaa8b60SDan Kruchinin 
298bbaa8b60SDan Kruchinin void
nlm_globals_register(struct nlm_globals * g)299bbaa8b60SDan Kruchinin nlm_globals_register(struct nlm_globals *g)
300bbaa8b60SDan Kruchinin {
301bbaa8b60SDan Kruchinin 	rw_enter(&lm_lck, RW_WRITER);
302bbaa8b60SDan Kruchinin 	TAILQ_INSERT_TAIL(&nlm_zones_list, g, nlm_link);
303bbaa8b60SDan Kruchinin 	rw_exit(&lm_lck);
304bbaa8b60SDan Kruchinin }
305bbaa8b60SDan Kruchinin 
306bbaa8b60SDan Kruchinin void
nlm_globals_unregister(struct nlm_globals * g)307bbaa8b60SDan Kruchinin nlm_globals_unregister(struct nlm_globals *g)
308bbaa8b60SDan Kruchinin {
309bbaa8b60SDan Kruchinin 	rw_enter(&lm_lck, RW_WRITER);
310bbaa8b60SDan Kruchinin 	TAILQ_REMOVE(&nlm_zones_list, g, nlm_link);
311bbaa8b60SDan Kruchinin 	rw_exit(&lm_lck);
312bbaa8b60SDan Kruchinin }
313bbaa8b60SDan Kruchinin 
314bbaa8b60SDan Kruchinin /* ARGSUSED */
315bbaa8b60SDan Kruchinin static void
nlm_kmem_reclaim(void * cdrarg)316bbaa8b60SDan Kruchinin nlm_kmem_reclaim(void *cdrarg)
317bbaa8b60SDan Kruchinin {
318bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
319bbaa8b60SDan Kruchinin 
320bbaa8b60SDan Kruchinin 	rw_enter(&lm_lck, RW_READER);
321bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
322bbaa8b60SDan Kruchinin 		cv_broadcast(&g->nlm_gc_sched_cv);
323bbaa8b60SDan Kruchinin 
324bbaa8b60SDan Kruchinin 	rw_exit(&lm_lck);
325bbaa8b60SDan Kruchinin }
326bbaa8b60SDan Kruchinin 
327bbaa8b60SDan Kruchinin /*
328bbaa8b60SDan Kruchinin  * NLM garbage collector thread (GC).
329bbaa8b60SDan Kruchinin  *
330bbaa8b60SDan Kruchinin  * NLM GC periodically checks whether there're any host objects
331bbaa8b60SDan Kruchinin  * that can be cleaned up. It also releases stale vnodes that
332bbaa8b60SDan Kruchinin  * live on the server side (under protection of vhold objects).
333bbaa8b60SDan Kruchinin  *
334bbaa8b60SDan Kruchinin  * NLM host objects are cleaned up from GC thread because
335bbaa8b60SDan Kruchinin  * operations helping us to determine whether given host has
336bbaa8b60SDan Kruchinin  * any locks can be quite expensive and it's not good to call
337bbaa8b60SDan Kruchinin  * them every time the very last reference to the host is dropped.
338bbaa8b60SDan Kruchinin  * Thus we use "lazy" approach for hosts cleanup.
339bbaa8b60SDan Kruchinin  *
340bbaa8b60SDan Kruchinin  * The work of GC is to release stale vnodes on the server side
341bbaa8b60SDan Kruchinin  * and destroy hosts that haven't any locks and any activity for
342bbaa8b60SDan Kruchinin  * some time (i.e. idle hosts).
343bbaa8b60SDan Kruchinin  */
344bbaa8b60SDan Kruchinin static void
nlm_gc(struct nlm_globals * g)345bbaa8b60SDan Kruchinin nlm_gc(struct nlm_globals *g)
346bbaa8b60SDan Kruchinin {
347bbaa8b60SDan Kruchinin 	struct nlm_host *hostp;
348bbaa8b60SDan Kruchinin 	clock_t now, idle_period;
349bbaa8b60SDan Kruchinin 
350bbaa8b60SDan Kruchinin 	idle_period = SEC_TO_TICK(g->cn_idle_tmo);
351bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
352bbaa8b60SDan Kruchinin 	for (;;) {
353bbaa8b60SDan Kruchinin 		/*
354bbaa8b60SDan Kruchinin 		 * GC thread can be explicitly scheduled from
355bbaa8b60SDan Kruchinin 		 * memory reclamation function.
356bbaa8b60SDan Kruchinin 		 */
357bbaa8b60SDan Kruchinin 		(void) cv_timedwait(&g->nlm_gc_sched_cv, &g->lock,
358bbaa8b60SDan Kruchinin 		    ddi_get_lbolt() + idle_period);
359bbaa8b60SDan Kruchinin 
360bbaa8b60SDan Kruchinin 		/*
361bbaa8b60SDan Kruchinin 		 * NLM is shutting down, time to die.
362bbaa8b60SDan Kruchinin 		 */
363bbaa8b60SDan Kruchinin 		if (g->run_status == NLM_ST_STOPPING)
364bbaa8b60SDan Kruchinin 			break;
365bbaa8b60SDan Kruchinin 
366bbaa8b60SDan Kruchinin 		now = ddi_get_lbolt();
367bbaa8b60SDan Kruchinin 		DTRACE_PROBE2(gc__start, struct nlm_globals *, g,
368bbaa8b60SDan Kruchinin 		    clock_t, now);
369bbaa8b60SDan Kruchinin 
370b1087aecSMarcel Telka 		/*
371b1087aecSMarcel Telka 		 * Find all obviously unused vholds and destroy them.
372b1087aecSMarcel Telka 		 */
373b1087aecSMarcel Telka 		for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL;
374b1087aecSMarcel Telka 		    hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) {
375b1087aecSMarcel Telka 			struct nlm_vhold *nvp;
376b1087aecSMarcel Telka 
377b1087aecSMarcel Telka 			mutex_enter(&hostp->nh_lock);
378b1087aecSMarcel Telka 
379b1087aecSMarcel Telka 			nvp = TAILQ_FIRST(&hostp->nh_vholds_list);
380b1087aecSMarcel Telka 			while (nvp != NULL) {
381b1087aecSMarcel Telka 				struct nlm_vhold *new_nvp;
382b1087aecSMarcel Telka 
383b1087aecSMarcel Telka 				new_nvp = TAILQ_NEXT(nvp, nv_link);
384b1087aecSMarcel Telka 
385b1087aecSMarcel Telka 				/*
386b1087aecSMarcel Telka 				 * If these conditions are met, the vhold is
387b1087aecSMarcel Telka 				 * obviously unused and we will destroy it.  In
388b1087aecSMarcel Telka 				 * a case either v_filocks and/or v_shrlocks is
389b1087aecSMarcel Telka 				 * non-NULL the vhold might still be unused by
390b1087aecSMarcel Telka 				 * the host, but it is expensive to check that.
391b1087aecSMarcel Telka 				 * We defer such check until the host is idle.
392b1087aecSMarcel Telka 				 * The expensive check is done below without
393b1087aecSMarcel Telka 				 * the global lock held.
394b1087aecSMarcel Telka 				 */
395b1087aecSMarcel Telka 				if (nvp->nv_refcnt == 0 &&
396b1087aecSMarcel Telka 				    nvp->nv_vp->v_filocks == NULL &&
397b1087aecSMarcel Telka 				    nvp->nv_vp->v_shrlocks == NULL) {
398b1087aecSMarcel Telka 					nlm_vhold_destroy(hostp, nvp);
399b1087aecSMarcel Telka 				}
400b1087aecSMarcel Telka 
401b1087aecSMarcel Telka 				nvp = new_nvp;
402b1087aecSMarcel Telka 			}
403b1087aecSMarcel Telka 
404b1087aecSMarcel Telka 			mutex_exit(&hostp->nh_lock);
405b1087aecSMarcel Telka 		}
406b1087aecSMarcel Telka 
407bbaa8b60SDan Kruchinin 		/*
408bbaa8b60SDan Kruchinin 		 * Handle all hosts that are unused at the moment
409bbaa8b60SDan Kruchinin 		 * until we meet one with idle timeout in future.
410bbaa8b60SDan Kruchinin 		 */
411bbaa8b60SDan Kruchinin 		while ((hostp = TAILQ_FIRST(&g->nlm_idle_hosts)) != NULL) {
412b1087aecSMarcel Telka 			bool_t has_locks;
413bbaa8b60SDan Kruchinin 
414bbaa8b60SDan Kruchinin 			if (hostp->nh_idle_timeout > now)
415bbaa8b60SDan Kruchinin 				break;
416bbaa8b60SDan Kruchinin 
417bbaa8b60SDan Kruchinin 			/*
418bbaa8b60SDan Kruchinin 			 * Drop global lock while doing expensive work
419bbaa8b60SDan Kruchinin 			 * on this host. We'll re-check any conditions
420bbaa8b60SDan Kruchinin 			 * that might change after retaking the global
421bbaa8b60SDan Kruchinin 			 * lock.
422bbaa8b60SDan Kruchinin 			 */
423bbaa8b60SDan Kruchinin 			mutex_exit(&g->lock);
424bbaa8b60SDan Kruchinin 			mutex_enter(&hostp->nh_lock);
425bbaa8b60SDan Kruchinin 
426bbaa8b60SDan Kruchinin 			/*
427bbaa8b60SDan Kruchinin 			 * nlm_globals lock was dropped earlier because
428bbaa8b60SDan Kruchinin 			 * garbage collecting of vholds and checking whether
429bbaa8b60SDan Kruchinin 			 * host has any locks/shares are expensive operations.
430bbaa8b60SDan Kruchinin 			 */
431bbaa8b60SDan Kruchinin 			nlm_host_gc_vholds(hostp);
432bbaa8b60SDan Kruchinin 			has_locks = nlm_host_has_locks(hostp);
433bbaa8b60SDan Kruchinin 
434bbaa8b60SDan Kruchinin 			mutex_exit(&hostp->nh_lock);
435bbaa8b60SDan Kruchinin 			mutex_enter(&g->lock);
436bbaa8b60SDan Kruchinin 
437bbaa8b60SDan Kruchinin 			/*
438096e63b2SPaul Dagnelie 			 * While we were doing expensive operations
439096e63b2SPaul Dagnelie 			 * outside of nlm_globals critical section,
440096e63b2SPaul Dagnelie 			 * somebody could take the host and remove it
441096e63b2SPaul Dagnelie 			 * from the idle list.  Whether its been
442096e63b2SPaul Dagnelie 			 * reinserted or not, our information about
443096e63b2SPaul Dagnelie 			 * the host is outdated, and we should take no
444096e63b2SPaul Dagnelie 			 * further action.
445bbaa8b60SDan Kruchinin 			 */
446b1087aecSMarcel Telka 			if ((hostp->nh_flags & NLM_NH_INIDLE) == 0 ||
447b1087aecSMarcel Telka 			    hostp->nh_idle_timeout > now)
448bbaa8b60SDan Kruchinin 				continue;
449bbaa8b60SDan Kruchinin 
450bbaa8b60SDan Kruchinin 			/*
451096e63b2SPaul Dagnelie 			 * If the host has locks we have to renew the
452096e63b2SPaul Dagnelie 			 * host's timeout and put it at the end of LRU
453096e63b2SPaul Dagnelie 			 * list.
454bbaa8b60SDan Kruchinin 			 */
455096e63b2SPaul Dagnelie 			if (has_locks) {
456bbaa8b60SDan Kruchinin 				TAILQ_REMOVE(&g->nlm_idle_hosts,
457bbaa8b60SDan Kruchinin 				    hostp, nh_link);
458bbaa8b60SDan Kruchinin 				hostp->nh_idle_timeout = now + idle_period;
459bbaa8b60SDan Kruchinin 				TAILQ_INSERT_TAIL(&g->nlm_idle_hosts,
460bbaa8b60SDan Kruchinin 				    hostp, nh_link);
461bbaa8b60SDan Kruchinin 				continue;
462bbaa8b60SDan Kruchinin 			}
463bbaa8b60SDan Kruchinin 
464bbaa8b60SDan Kruchinin 			/*
465bbaa8b60SDan Kruchinin 			 * We're here if all the following conditions hold:
466bbaa8b60SDan Kruchinin 			 * 1) Host hasn't any locks or share reservations
467bbaa8b60SDan Kruchinin 			 * 2) Host is unused
468bbaa8b60SDan Kruchinin 			 * 3) Host wasn't touched by anyone at least for
469bbaa8b60SDan Kruchinin 			 *    g->cn_idle_tmo seconds.
470bbaa8b60SDan Kruchinin 			 *
471bbaa8b60SDan Kruchinin 			 * So, now we can destroy it.
472bbaa8b60SDan Kruchinin 			 */
473bbaa8b60SDan Kruchinin 			nlm_host_unregister(g, hostp);
474bbaa8b60SDan Kruchinin 			mutex_exit(&g->lock);
475bbaa8b60SDan Kruchinin 
476bbaa8b60SDan Kruchinin 			nlm_host_unmonitor(g, hostp);
477bbaa8b60SDan Kruchinin 			nlm_host_destroy(hostp);
478bbaa8b60SDan Kruchinin 			mutex_enter(&g->lock);
479bbaa8b60SDan Kruchinin 			if (g->run_status == NLM_ST_STOPPING)
480bbaa8b60SDan Kruchinin 				break;
481bbaa8b60SDan Kruchinin 
482bbaa8b60SDan Kruchinin 		}
483bbaa8b60SDan Kruchinin 
484bbaa8b60SDan Kruchinin 		DTRACE_PROBE(gc__end);
485bbaa8b60SDan Kruchinin 	}
486bbaa8b60SDan Kruchinin 
487bbaa8b60SDan Kruchinin 	DTRACE_PROBE1(gc__exit, struct nlm_globals *, g);
488bbaa8b60SDan Kruchinin 
489bbaa8b60SDan Kruchinin 	/* Let others know that GC has died */
490bbaa8b60SDan Kruchinin 	g->nlm_gc_thread = NULL;
491bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
492bbaa8b60SDan Kruchinin 
493bbaa8b60SDan Kruchinin 	cv_broadcast(&g->nlm_gc_finish_cv);
494bbaa8b60SDan Kruchinin 	zthread_exit();
495bbaa8b60SDan Kruchinin }
496bbaa8b60SDan Kruchinin 
497bbaa8b60SDan Kruchinin /*
498bbaa8b60SDan Kruchinin  * Thread reclaim locks/shares acquired by the client side
499bbaa8b60SDan Kruchinin  * on the given server represented by hostp.
500bbaa8b60SDan Kruchinin  */
501bbaa8b60SDan Kruchinin static void
nlm_reclaimer(struct nlm_host * hostp)502bbaa8b60SDan Kruchinin nlm_reclaimer(struct nlm_host *hostp)
503bbaa8b60SDan Kruchinin {
504bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
505bbaa8b60SDan Kruchinin 
506bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
507bbaa8b60SDan Kruchinin 	hostp->nh_reclaimer = curthread;
508bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
509bbaa8b60SDan Kruchinin 
510bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
511bbaa8b60SDan Kruchinin 	nlm_reclaim_client(g, hostp);
512bbaa8b60SDan Kruchinin 
513bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
514bbaa8b60SDan Kruchinin 	hostp->nh_flags &= ~NLM_NH_RECLAIM;
515bbaa8b60SDan Kruchinin 	hostp->nh_reclaimer = NULL;
516bbaa8b60SDan Kruchinin 	cv_broadcast(&hostp->nh_recl_cv);
517bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
518bbaa8b60SDan Kruchinin 
519bbaa8b60SDan Kruchinin 	/*
520bbaa8b60SDan Kruchinin 	 * Host was explicitly referenced before
521bbaa8b60SDan Kruchinin 	 * nlm_reclaim() was called, release it
522bbaa8b60SDan Kruchinin 	 * here.
523bbaa8b60SDan Kruchinin 	 */
524bbaa8b60SDan Kruchinin 	nlm_host_release(g, hostp);
525bbaa8b60SDan Kruchinin 	zthread_exit();
526bbaa8b60SDan Kruchinin }
527bbaa8b60SDan Kruchinin 
528bbaa8b60SDan Kruchinin /*
529bbaa8b60SDan Kruchinin  * Copy a struct netobj.  (see xdr.h)
530bbaa8b60SDan Kruchinin  */
531bbaa8b60SDan Kruchinin void
nlm_copy_netobj(struct netobj * dst,struct netobj * src)532bbaa8b60SDan Kruchinin nlm_copy_netobj(struct netobj *dst, struct netobj *src)
533bbaa8b60SDan Kruchinin {
534bbaa8b60SDan Kruchinin 	dst->n_len = src->n_len;
535bbaa8b60SDan Kruchinin 	dst->n_bytes = kmem_alloc(src->n_len, KM_SLEEP);
536bbaa8b60SDan Kruchinin 	bcopy(src->n_bytes, dst->n_bytes, src->n_len);
537bbaa8b60SDan Kruchinin }
538bbaa8b60SDan Kruchinin 
539bbaa8b60SDan Kruchinin /*
540bbaa8b60SDan Kruchinin  * An NLM specificw replacement for clnt_call().
541bbaa8b60SDan Kruchinin  * nlm_clnt_call() is used by all RPC functions generated
542bbaa8b60SDan Kruchinin  * from nlm_prot.x specification. The function is aware
543bbaa8b60SDan Kruchinin  * about some pitfalls of NLM RPC procedures and has a logic
544bbaa8b60SDan Kruchinin  * that handles them properly.
545bbaa8b60SDan Kruchinin  */
546bbaa8b60SDan Kruchinin enum clnt_stat
nlm_clnt_call(CLIENT * clnt,rpcproc_t procnum,xdrproc_t xdr_args,caddr_t argsp,xdrproc_t xdr_result,caddr_t resultp,struct timeval wait)547bbaa8b60SDan Kruchinin nlm_clnt_call(CLIENT *clnt, rpcproc_t procnum, xdrproc_t xdr_args,
548bbaa8b60SDan Kruchinin     caddr_t argsp, xdrproc_t xdr_result, caddr_t resultp, struct timeval wait)
549bbaa8b60SDan Kruchinin {
550bbaa8b60SDan Kruchinin 	k_sigset_t oldmask;
551bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
552bbaa8b60SDan Kruchinin 	bool_t sig_blocked = FALSE;
553bbaa8b60SDan Kruchinin 
554bbaa8b60SDan Kruchinin 	/*
555bbaa8b60SDan Kruchinin 	 * If NLM RPC procnum is one of the NLM _RES procedures
556bbaa8b60SDan Kruchinin 	 * that are used to reply to asynchronous NLM RPC
557bbaa8b60SDan Kruchinin 	 * (MSG calls), explicitly set RPC timeout to zero.
558bbaa8b60SDan Kruchinin 	 * Client doesn't send a reply to RES procedures, so
559bbaa8b60SDan Kruchinin 	 * we don't need to wait anything.
560bbaa8b60SDan Kruchinin 	 *
561bbaa8b60SDan Kruchinin 	 * NOTE: we ignore NLM4_*_RES procnums because they are
562bbaa8b60SDan Kruchinin 	 * equal to NLM_*_RES numbers.
563bbaa8b60SDan Kruchinin 	 */
564bbaa8b60SDan Kruchinin 	if (procnum >= NLM_TEST_RES && procnum <= NLM_GRANTED_RES)
565bbaa8b60SDan Kruchinin 		wait = nlm_rpctv_zero;
566bbaa8b60SDan Kruchinin 
567bbaa8b60SDan Kruchinin 	/*
568bbaa8b60SDan Kruchinin 	 * We need to block signals in case of NLM_CANCEL RPC
569bbaa8b60SDan Kruchinin 	 * in order to prevent interruption of network RPC
570bbaa8b60SDan Kruchinin 	 * calls.
571bbaa8b60SDan Kruchinin 	 */
572bbaa8b60SDan Kruchinin 	if (procnum == NLM_CANCEL) {
573bbaa8b60SDan Kruchinin 		k_sigset_t newmask;
574bbaa8b60SDan Kruchinin 
575bbaa8b60SDan Kruchinin 		sigfillset(&newmask);
576bbaa8b60SDan Kruchinin 		sigreplace(&newmask, &oldmask);
577bbaa8b60SDan Kruchinin 		sig_blocked = TRUE;
578bbaa8b60SDan Kruchinin 	}
579bbaa8b60SDan Kruchinin 
580bbaa8b60SDan Kruchinin 	stat = clnt_call(clnt, procnum, xdr_args,
581bbaa8b60SDan Kruchinin 	    argsp, xdr_result, resultp, wait);
582bbaa8b60SDan Kruchinin 
583bbaa8b60SDan Kruchinin 	/*
584bbaa8b60SDan Kruchinin 	 * Restore signal mask back if signals were blocked
585bbaa8b60SDan Kruchinin 	 */
586bbaa8b60SDan Kruchinin 	if (sig_blocked)
587bbaa8b60SDan Kruchinin 		sigreplace(&oldmask, (k_sigset_t *)NULL);
588bbaa8b60SDan Kruchinin 
589bbaa8b60SDan Kruchinin 	return (stat);
590bbaa8b60SDan Kruchinin }
591bbaa8b60SDan Kruchinin 
592bbaa8b60SDan Kruchinin /*
593bbaa8b60SDan Kruchinin  * Suspend NLM client/server in the given zone.
594bbaa8b60SDan Kruchinin  *
595bbaa8b60SDan Kruchinin  * During suspend operation we mark those hosts
596bbaa8b60SDan Kruchinin  * that have any locks with NLM_NH_SUSPEND flags,
597bbaa8b60SDan Kruchinin  * so that they can be checked later, when resume
598bbaa8b60SDan Kruchinin  * operation occurs.
599bbaa8b60SDan Kruchinin  */
600bbaa8b60SDan Kruchinin static void
nlm_suspend_zone(struct nlm_globals * g)601bbaa8b60SDan Kruchinin nlm_suspend_zone(struct nlm_globals *g)
602bbaa8b60SDan Kruchinin {
603bbaa8b60SDan Kruchinin 	struct nlm_host *hostp;
604bbaa8b60SDan Kruchinin 	struct nlm_host_list all_hosts;
605bbaa8b60SDan Kruchinin 
606bbaa8b60SDan Kruchinin 	/*
607bbaa8b60SDan Kruchinin 	 * Note that while we're doing suspend, GC thread is active
608bbaa8b60SDan Kruchinin 	 * and it can destroy some hosts while we're walking through
609bbaa8b60SDan Kruchinin 	 * the hosts tree. To prevent that and make suspend logic
610bbaa8b60SDan Kruchinin 	 * a bit more simple we put all hosts to local "all_hosts"
611bbaa8b60SDan Kruchinin 	 * list and increment reference counter of each host.
612bbaa8b60SDan Kruchinin 	 * This guaranties that no hosts will be released while
613bbaa8b60SDan Kruchinin 	 * we're doing suspend.
614bbaa8b60SDan Kruchinin 	 * NOTE: reference of each host must be dropped during
615bbaa8b60SDan Kruchinin 	 * resume operation.
616bbaa8b60SDan Kruchinin 	 */
617bbaa8b60SDan Kruchinin 	TAILQ_INIT(&all_hosts);
618bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
619bbaa8b60SDan Kruchinin 	for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL;
620bbaa8b60SDan Kruchinin 	    hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) {
621bbaa8b60SDan Kruchinin 		/*
622bbaa8b60SDan Kruchinin 		 * If host is idle, remove it from idle list and
623bbaa8b60SDan Kruchinin 		 * clear idle flag. That is done to prevent GC
624bbaa8b60SDan Kruchinin 		 * from touching this host.
625bbaa8b60SDan Kruchinin 		 */
626bbaa8b60SDan Kruchinin 		if (hostp->nh_flags & NLM_NH_INIDLE) {
627bbaa8b60SDan Kruchinin 			TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
628bbaa8b60SDan Kruchinin 			hostp->nh_flags &= ~NLM_NH_INIDLE;
629bbaa8b60SDan Kruchinin 		}
630bbaa8b60SDan Kruchinin 
631bbaa8b60SDan Kruchinin 		hostp->nh_refs++;
632bbaa8b60SDan Kruchinin 		TAILQ_INSERT_TAIL(&all_hosts, hostp, nh_link);
633bbaa8b60SDan Kruchinin 	}
634bbaa8b60SDan Kruchinin 
635bbaa8b60SDan Kruchinin 	/*
636bbaa8b60SDan Kruchinin 	 * Now we can walk through all hosts on the system
637bbaa8b60SDan Kruchinin 	 * with zone globals lock released. The fact the
638bbaa8b60SDan Kruchinin 	 * we have taken a reference to each host guaranties
639bbaa8b60SDan Kruchinin 	 * that no hosts can be destroyed during that process.
640bbaa8b60SDan Kruchinin 	 */
641bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
642bbaa8b60SDan Kruchinin 	while ((hostp = TAILQ_FIRST(&all_hosts)) != NULL) {
643bbaa8b60SDan Kruchinin 		mutex_enter(&hostp->nh_lock);
644bbaa8b60SDan Kruchinin 		if (nlm_host_has_locks(hostp))
645bbaa8b60SDan Kruchinin 			hostp->nh_flags |= NLM_NH_SUSPEND;
646bbaa8b60SDan Kruchinin 
647bbaa8b60SDan Kruchinin 		mutex_exit(&hostp->nh_lock);
648bbaa8b60SDan Kruchinin 		TAILQ_REMOVE(&all_hosts, hostp, nh_link);
649bbaa8b60SDan Kruchinin 	}
650bbaa8b60SDan Kruchinin }
651bbaa8b60SDan Kruchinin 
652bbaa8b60SDan Kruchinin /*
653bbaa8b60SDan Kruchinin  * Resume NLM hosts for the given zone.
654bbaa8b60SDan Kruchinin  *
655bbaa8b60SDan Kruchinin  * nlm_resume_zone() is called after hosts were suspended
656bbaa8b60SDan Kruchinin  * (see nlm_suspend_zone) and its main purpose to check
657bbaa8b60SDan Kruchinin  * whether remote locks owned by hosts are still in consistent
658bbaa8b60SDan Kruchinin  * state. If they aren't, resume function tries to reclaim
659b1087aecSMarcel Telka  * locks (for client side hosts) and clean locks (for
660bbaa8b60SDan Kruchinin  * server side hosts).
661bbaa8b60SDan Kruchinin  */
662bbaa8b60SDan Kruchinin static void
nlm_resume_zone(struct nlm_globals * g)663bbaa8b60SDan Kruchinin nlm_resume_zone(struct nlm_globals *g)
664bbaa8b60SDan Kruchinin {
665bbaa8b60SDan Kruchinin 	struct nlm_host *hostp, *h_next;
666bbaa8b60SDan Kruchinin 
667bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
668bbaa8b60SDan Kruchinin 	hostp = avl_first(&g->nlm_hosts_tree);
669bbaa8b60SDan Kruchinin 
670bbaa8b60SDan Kruchinin 	/*
671bbaa8b60SDan Kruchinin 	 * In nlm_suspend_zone() the reference counter of each
672bbaa8b60SDan Kruchinin 	 * host was incremented, so we can safely iterate through
673bbaa8b60SDan Kruchinin 	 * all hosts without worrying that any host we touch will
674bbaa8b60SDan Kruchinin 	 * be removed at the moment.
675bbaa8b60SDan Kruchinin 	 */
676bbaa8b60SDan Kruchinin 	while (hostp != NULL) {
677bbaa8b60SDan Kruchinin 		struct nlm_nsm nsm;
678bbaa8b60SDan Kruchinin 		enum clnt_stat stat;
679bbaa8b60SDan Kruchinin 		int32_t sm_state;
680bbaa8b60SDan Kruchinin 		int error;
681bbaa8b60SDan Kruchinin 		bool_t resume_failed = FALSE;
682bbaa8b60SDan Kruchinin 
683bbaa8b60SDan Kruchinin 		h_next = AVL_NEXT(&g->nlm_hosts_tree, hostp);
684bbaa8b60SDan Kruchinin 		mutex_exit(&g->lock);
685bbaa8b60SDan Kruchinin 
686bbaa8b60SDan Kruchinin 		DTRACE_PROBE1(resume__host, struct nlm_host *, hostp);
687bbaa8b60SDan Kruchinin 
688bbaa8b60SDan Kruchinin 		/*
689bbaa8b60SDan Kruchinin 		 * Suspend operation marked that the host doesn't
690bbaa8b60SDan Kruchinin 		 * have any locks. Skip it.
691bbaa8b60SDan Kruchinin 		 */
692bbaa8b60SDan Kruchinin 		if (!(hostp->nh_flags & NLM_NH_SUSPEND))
693bbaa8b60SDan Kruchinin 			goto cycle_end;
694bbaa8b60SDan Kruchinin 
695bbaa8b60SDan Kruchinin 		error = nlm_nsm_init(&nsm, &hostp->nh_knc, &hostp->nh_addr);
696bbaa8b60SDan Kruchinin 		if (error != 0) {
697bbaa8b60SDan Kruchinin 			NLM_ERR("Resume: Failed to contact to NSM of host %s "
698bbaa8b60SDan Kruchinin 			    "[error=%d]\n", hostp->nh_name, error);
699bbaa8b60SDan Kruchinin 			resume_failed = TRUE;
700bbaa8b60SDan Kruchinin 			goto cycle_end;
701bbaa8b60SDan Kruchinin 		}
702bbaa8b60SDan Kruchinin 
703bbaa8b60SDan Kruchinin 		stat = nlm_nsm_stat(&nsm, &sm_state);
704bbaa8b60SDan Kruchinin 		if (stat != RPC_SUCCESS) {
705bbaa8b60SDan Kruchinin 			NLM_ERR("Resume: Failed to call SM_STAT operation for "
706bbaa8b60SDan Kruchinin 			    "host %s [stat=%d]\n", hostp->nh_name, stat);
707bbaa8b60SDan Kruchinin 			resume_failed = TRUE;
708bbaa8b60SDan Kruchinin 			nlm_nsm_fini(&nsm);
709bbaa8b60SDan Kruchinin 			goto cycle_end;
710bbaa8b60SDan Kruchinin 		}
711bbaa8b60SDan Kruchinin 
712bbaa8b60SDan Kruchinin 		if (sm_state != hostp->nh_state) {
713bbaa8b60SDan Kruchinin 			/*
714bbaa8b60SDan Kruchinin 			 * Current SM state of the host isn't equal
715bbaa8b60SDan Kruchinin 			 * to the one host had when it was suspended.
716bbaa8b60SDan Kruchinin 			 * Probably it was rebooted. Try to reclaim
717bbaa8b60SDan Kruchinin 			 * locks if the host has any on its client side.
718bbaa8b60SDan Kruchinin 			 * Also try to clean up its server side locks
719bbaa8b60SDan Kruchinin 			 * (if the host has any).
720bbaa8b60SDan Kruchinin 			 */
721bbaa8b60SDan Kruchinin 			nlm_host_notify_client(hostp, sm_state);
722bbaa8b60SDan Kruchinin 			nlm_host_notify_server(hostp, sm_state);
723bbaa8b60SDan Kruchinin 		}
724bbaa8b60SDan Kruchinin 
725bbaa8b60SDan Kruchinin 		nlm_nsm_fini(&nsm);
726bbaa8b60SDan Kruchinin 
727bbaa8b60SDan Kruchinin cycle_end:
728bbaa8b60SDan Kruchinin 		if (resume_failed) {
729bbaa8b60SDan Kruchinin 			/*
730bbaa8b60SDan Kruchinin 			 * Resume failed for the given host.
731bbaa8b60SDan Kruchinin 			 * Just clean up all resources it owns.
732bbaa8b60SDan Kruchinin 			 */
733bbaa8b60SDan Kruchinin 			nlm_host_notify_server(hostp, 0);
734bbaa8b60SDan Kruchinin 			nlm_client_cancel_all(g, hostp);
735bbaa8b60SDan Kruchinin 		}
736bbaa8b60SDan Kruchinin 
737bbaa8b60SDan Kruchinin 		hostp->nh_flags &= ~NLM_NH_SUSPEND;
738bbaa8b60SDan Kruchinin 		nlm_host_release(g, hostp);
739bbaa8b60SDan Kruchinin 		hostp = h_next;
740bbaa8b60SDan Kruchinin 		mutex_enter(&g->lock);
741bbaa8b60SDan Kruchinin 	}
742bbaa8b60SDan Kruchinin 
743bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
744bbaa8b60SDan Kruchinin }
745bbaa8b60SDan Kruchinin 
746bbaa8b60SDan Kruchinin /*
747bbaa8b60SDan Kruchinin  * NLM functions responsible for operations on NSM handle.
748bbaa8b60SDan Kruchinin  */
749bbaa8b60SDan Kruchinin 
750bbaa8b60SDan Kruchinin /*
751bbaa8b60SDan Kruchinin  * Initialize knetconfig that is used for communication
752bbaa8b60SDan Kruchinin  * with local statd via loopback interface.
753bbaa8b60SDan Kruchinin  */
754bbaa8b60SDan Kruchinin static int
nlm_init_local_knc(struct knetconfig * knc)755bbaa8b60SDan Kruchinin nlm_init_local_knc(struct knetconfig *knc)
756bbaa8b60SDan Kruchinin {
757bbaa8b60SDan Kruchinin 	int error;
758bbaa8b60SDan Kruchinin 	vnode_t *vp;
759bbaa8b60SDan Kruchinin 
760bbaa8b60SDan Kruchinin 	bzero(knc, sizeof (*knc));
761bbaa8b60SDan Kruchinin 	error = lookupname("/dev/tcp", UIO_SYSSPACE,
762bbaa8b60SDan Kruchinin 	    FOLLOW, NULLVPP, &vp);
763bbaa8b60SDan Kruchinin 	if (error != 0)
764bbaa8b60SDan Kruchinin 		return (error);
765bbaa8b60SDan Kruchinin 
766bbaa8b60SDan Kruchinin 	knc->knc_semantics = NC_TPI_COTS;
767bbaa8b60SDan Kruchinin 	knc->knc_protofmly = NC_INET;
768bbaa8b60SDan Kruchinin 	knc->knc_proto = NC_TCP;
769bbaa8b60SDan Kruchinin 	knc->knc_rdev = vp->v_rdev;
770bbaa8b60SDan Kruchinin 	VN_RELE(vp);
771bbaa8b60SDan Kruchinin 
772bbaa8b60SDan Kruchinin 
773bbaa8b60SDan Kruchinin 	return (0);
774bbaa8b60SDan Kruchinin }
775bbaa8b60SDan Kruchinin 
776bbaa8b60SDan Kruchinin /*
777