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 /*
777bbaa8b60SDan Kruchinin  * Initialize NSM handle that will be used to talk
778bbaa8b60SDan Kruchinin  * to local statd via loopback interface.
779bbaa8b60SDan Kruchinin  */
780bbaa8b60SDan Kruchinin static int
nlm_nsm_init_local(struct nlm_nsm * nsm)781bbaa8b60SDan Kruchinin nlm_nsm_init_local(struct nlm_nsm *nsm)
782bbaa8b60SDan Kruchinin {
783bbaa8b60SDan Kruchinin 	int error;
784bbaa8b60SDan Kruchinin 	struct knetconfig knc;
785bbaa8b60SDan Kruchinin 	struct sockaddr_in sin;
786bbaa8b60SDan Kruchinin 	struct netbuf nb;
787bbaa8b60SDan Kruchinin 
788bbaa8b60SDan Kruchinin 	error = nlm_init_local_knc(&knc);
789bbaa8b60SDan Kruchinin 	if (error != 0)
790bbaa8b60SDan Kruchinin 		return (error);
791bbaa8b60SDan Kruchinin 
792bbaa8b60SDan Kruchinin 	bzero(&sin, sizeof (sin));
793bbaa8b60SDan Kruchinin 	sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
794bbaa8b60SDan Kruchinin 	sin.sin_family = AF_INET;
795bbaa8b60SDan Kruchinin 
796bbaa8b60SDan Kruchinin 	nb.buf = (char *)&sin;
797bbaa8b60SDan Kruchinin 	nb.len = nb.maxlen = sizeof (sin);
798bbaa8b60SDan Kruchinin 
799bbaa8b60SDan Kruchinin 	return (nlm_nsm_init(nsm, &knc, &nb));
800bbaa8b60SDan Kruchinin }
801bbaa8b60SDan Kruchinin 
802bbaa8b60SDan Kruchinin /*
803bbaa8b60SDan Kruchinin  * Initialize NSM handle used for talking to statd
804bbaa8b60SDan Kruchinin  */
805bbaa8b60SDan Kruchinin static int
nlm_nsm_init(struct nlm_nsm * nsm,struct knetconfig * knc,struct netbuf * nb)806bbaa8b60SDan Kruchinin nlm_nsm_init(struct nlm_nsm *nsm, struct knetconfig *knc, struct netbuf *nb)
807bbaa8b60SDan Kruchinin {
808bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
809bbaa8b60SDan Kruchinin 	int error, retries;
810bbaa8b60SDan Kruchinin 
811bbaa8b60SDan Kruchinin 	bzero(nsm, sizeof (*nsm));
812bbaa8b60SDan Kruchinin 	nsm->ns_knc = *knc;
813bbaa8b60SDan Kruchinin 	nlm_copy_netbuf(&nsm->ns_addr, nb);
814bbaa8b60SDan Kruchinin 
815bbaa8b60SDan Kruchinin 	/*
816bbaa8b60SDan Kruchinin 	 * Try several times to get the port of statd service,
817bbaa8b60SDan Kruchinin 	 * If rpcbind_getaddr returns  RPC_PROGNOTREGISTERED,
818bbaa8b60SDan Kruchinin 	 * retry an attempt, but wait for NLM_NSM_RPCBIND_TIMEOUT
819bbaa8b60SDan Kruchinin 	 * seconds berofore.
820bbaa8b60SDan Kruchinin 	 */
821bbaa8b60SDan Kruchinin 	for (retries = 0; retries < NLM_NSM_RPCBIND_RETRIES; retries++) {
822bbaa8b60SDan Kruchinin 		stat = rpcbind_getaddr(&nsm->ns_knc, SM_PROG,
823bbaa8b60SDan Kruchinin 		    SM_VERS, &nsm->ns_addr);
824bbaa8b60SDan Kruchinin 		if (stat != RPC_SUCCESS) {
825bbaa8b60SDan Kruchinin 			if (stat == RPC_PROGNOTREGISTERED) {
826bbaa8b60SDan Kruchinin 				delay(SEC_TO_TICK(NLM_NSM_RPCBIND_TIMEOUT));
827bbaa8b60SDan Kruchinin 				continue;
828bbaa8b60SDan Kruchinin 			}
829bbaa8b60SDan Kruchinin 		}
830bbaa8b60SDan Kruchinin 
831bbaa8b60SDan Kruchinin 		break;
832bbaa8b60SDan Kruchinin 	}
833bbaa8b60SDan Kruchinin 
834bbaa8b60SDan Kruchinin 	if (stat != RPC_SUCCESS) {
835bbaa8b60SDan Kruchinin 		DTRACE_PROBE2(rpcbind__error, enum clnt_stat, stat,
836bbaa8b60SDan Kruchinin 		    int, retries);
837bbaa8b60SDan Kruchinin 		error = ENOENT;
838bbaa8b60SDan Kruchinin 		goto error;
839bbaa8b60SDan Kruchinin 	}
840bbaa8b60SDan Kruchinin 
841bbaa8b60SDan Kruchinin 	/*
842bbaa8b60SDan Kruchinin 	 * Create an RPC handle that'll be used for communication with local
843bbaa8b60SDan Kruchinin 	 * statd using the status monitor protocol.
844bbaa8b60SDan Kruchinin 	 */
845bbaa8b60SDan Kruchinin 	error = clnt_tli_kcreate(&nsm->ns_knc, &nsm->ns_addr, SM_PROG, SM_VERS,
846*0dfe541eSEvan Layton 	    0, NLM_RPC_RETRIES, zone_kcred(), &nsm->ns_handle);
847bbaa8b60SDan Kruchinin 	if (error != 0)
848bbaa8b60SDan Kruchinin 		goto error;
849bbaa8b60SDan Kruchinin 
850bbaa8b60SDan Kruchinin 	/*
851bbaa8b60SDan Kruchinin 	 * Create an RPC handle that'll be used for communication with the
852bbaa8b60SDan Kruchinin 	 * local statd using the address registration protocol.
853bbaa8b60SDan Kruchinin 	 */
854bbaa8b60SDan Kruchinin 	error = clnt_tli_kcreate(&nsm->ns_knc, &nsm->ns_addr, NSM_ADDR_PROGRAM,
855*0dfe541eSEvan Layton 	    NSM_ADDR_V1, 0, NLM_RPC_RETRIES, zone_kcred(),
856*0dfe541eSEvan Layton 	    &nsm->ns_addr_handle);
857bbaa8b60SDan Kruchinin 	if (error != 0)
858bbaa8b60SDan Kruchinin 		goto error;
859bbaa8b60SDan Kruchinin 
860bbaa8b60SDan Kruchinin 	sema_init(&nsm->ns_sem, 1, NULL, SEMA_DEFAULT, NULL);
861bbaa8b60SDan Kruchinin 	return (0);
862bbaa8b60SDan Kruchinin 
863bbaa8b60SDan Kruchinin error:
864bbaa8b60SDan Kruchinin 	kmem_free(nsm->ns_addr.buf, nsm->ns_addr.maxlen);
865*0dfe541eSEvan Layton 	if (nsm->ns_handle) {
866*0dfe541eSEvan Layton 		ASSERT(nsm->ns_handle->cl_auth != NULL);
867*0dfe541eSEvan Layton 		auth_destroy(nsm->ns_handle->cl_auth);
868bbaa8b60SDan Kruchinin 		CLNT_DESTROY(nsm->ns_handle);
869*0dfe541eSEvan Layton 	}
870bbaa8b60SDan Kruchinin 
871bbaa8b60SDan Kruchinin 	return (error);
872bbaa8b60SDan Kruchinin }
873bbaa8b60SDan Kruchinin 
874bbaa8b60SDan Kruchinin static void
nlm_nsm_fini(struct nlm_nsm * nsm)875bbaa8b60SDan Kruchinin nlm_nsm_fini(struct nlm_nsm *nsm)
876bbaa8b60SDan Kruchinin {
877bbaa8b60SDan Kruchinin 	kmem_free(nsm->ns_addr.buf, nsm->ns_addr.maxlen);
878*0dfe541eSEvan Layton 	if (nsm->ns_addr_handle->cl_auth != NULL)
879*0dfe541eSEvan Layton 		auth_destroy(nsm->ns_addr_handle->cl_auth);
880bbaa8b60SDan Kruchinin 	CLNT_DESTROY(nsm->ns_addr_handle);
881bbaa8b60SDan Kruchinin 	nsm->ns_addr_handle = NULL;
882*0dfe541eSEvan Layton 	if (nsm->ns_handle->cl_auth != NULL)
883*0dfe541eSEvan Layton 		auth_destroy(nsm->ns_handle->cl_auth);
884bbaa8b60SDan Kruchinin 	CLNT_DESTROY(nsm->ns_handle);
885bbaa8b60SDan Kruchinin 	nsm->ns_handle = NULL;
886bbaa8b60SDan Kruchinin 	sema_destroy(&nsm->ns_sem);
887bbaa8b60SDan Kruchinin }
888bbaa8b60SDan Kruchinin 
889bbaa8b60SDan Kruchinin static enum clnt_stat
nlm_nsm_simu_crash(struct nlm_nsm * nsm)890bbaa8b60SDan Kruchinin nlm_nsm_simu_crash(struct nlm_nsm *nsm)
891bbaa8b60SDan Kruchinin {
892bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
893bbaa8b60SDan Kruchinin 
894bbaa8b60SDan Kruchinin 	sema_p(&nsm->ns_sem);
895bbaa8b60SDan Kruchinin 	nlm_nsm_clnt_init(nsm->ns_handle, nsm);
896bbaa8b60SDan Kruchinin 	stat = sm_simu_crash_1(NULL, NULL, nsm->ns_handle);
897bbaa8b60SDan Kruchinin 	sema_v(&nsm->ns_sem);
898bbaa8b60SDan Kruchinin 
899bbaa8b60SDan Kruchinin 	return (stat);
900bbaa8b60SDan Kruchinin }
901bbaa8b60SDan Kruchinin 
902bbaa8b60SDan Kruchinin static enum clnt_stat
nlm_nsm_stat(struct nlm_nsm * nsm,int32_t * out_stat)903bbaa8b60SDan Kruchinin nlm_nsm_stat(struct nlm_nsm *nsm, int32_t *out_stat)
904bbaa8b60SDan Kruchinin {
905bbaa8b60SDan Kruchinin 	struct sm_name args;
906bbaa8b60SDan Kruchinin 	struct sm_stat_res res;
907bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
908bbaa8b60SDan Kruchinin 
909bbaa8b60SDan Kruchinin 	args.mon_name = uts_nodename();
910bbaa8b60SDan Kruchinin 	bzero(&res, sizeof (res));
911bbaa8b60SDan Kruchinin 
912bbaa8b60SDan Kruchinin 	sema_p(&nsm->ns_sem);
913bbaa8b60SDan Kruchinin 	nlm_nsm_clnt_init(nsm->ns_handle, nsm);
914bbaa8b60SDan Kruchinin 	stat = sm_stat_1(&args, &res, nsm->ns_handle);
915bbaa8b60SDan Kruchinin 	sema_v(&nsm->ns_sem);
916bbaa8b60SDan Kruchinin 
917bbaa8b60SDan Kruchinin 	if (stat == RPC_SUCCESS)
918bbaa8b60SDan Kruchinin 		*out_stat = res.state;
919bbaa8b60SDan Kruchinin 
920bbaa8b60SDan Kruchinin 	return (stat);
921bbaa8b60SDan Kruchinin }
922bbaa8b60SDan Kruchinin 
923bbaa8b60SDan Kruchinin static enum clnt_stat
nlm_nsm_mon(struct nlm_nsm * nsm,char * hostname,uint16_t priv)924bbaa8b60SDan Kruchinin nlm_nsm_mon(struct nlm_nsm *nsm, char *hostname, uint16_t priv)
925bbaa8b60SDan Kruchinin {
926bbaa8b60SDan Kruchinin 	struct mon args;
927bbaa8b60SDan Kruchinin 	struct sm_stat_res res;
928bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
929bbaa8b60SDan Kruchinin 
930bbaa8b60SDan Kruchinin 	bzero(&args, sizeof (args));
931bbaa8b60SDan Kruchinin 	bzero(&res, sizeof (res));
932bbaa8b60SDan Kruchinin 
933bbaa8b60SDan Kruchinin 	args.mon_id.mon_name = hostname;
934bbaa8b60SDan Kruchinin 	args.mon_id.my_id.my_name = uts_nodename();
935bbaa8b60SDan Kruchinin 	args.mon_id.my_id.my_prog = NLM_PROG;
936bbaa8b60SDan Kruchinin 	args.mon_id.my_id.my_vers = NLM_SM;
937bbaa8b60SDan Kruchinin 	args.mon_id.my_id.my_proc = NLM_SM_NOTIFY1;
938bbaa8b60SDan Kruchinin 	bcopy(&priv, args.priv, sizeof (priv));
939bbaa8b60SDan Kruchinin 
940bbaa8b60SDan Kruchinin 	sema_p(&nsm->ns_sem);
941bbaa8b60SDan Kruchinin 	nlm_nsm_clnt_init(nsm->ns_handle, nsm);
942bbaa8b60SDan Kruchinin 	stat = sm_mon_1(&args, &res, nsm->ns_handle);
943bbaa8b60SDan Kruchinin 	sema_v(&nsm->ns_sem);
944bbaa8b60SDan Kruchinin 
945bbaa8b60SDan Kruchinin 	return (stat);
946bbaa8b60SDan Kruchinin }
947bbaa8b60SDan Kruchinin 
948bbaa8b60SDan Kruchinin static enum clnt_stat
nlm_nsm_unmon(struct nlm_nsm * nsm,char * hostname)949bbaa8b60SDan Kruchinin nlm_nsm_unmon(struct nlm_nsm *nsm, char *hostname)
950bbaa8b60SDan Kruchinin {
951bbaa8b60SDan Kruchinin 	struct mon_id args;
952bbaa8b60SDan Kruchinin 	struct sm_stat res;
953bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
954bbaa8b60SDan Kruchinin 
955bbaa8b60SDan Kruchinin 	bzero(&args, sizeof (args));
956bbaa8b60SDan Kruchinin 	bzero(&res, sizeof (res));
957bbaa8b60SDan Kruchinin 
958bbaa8b60SDan Kruchinin 	args.mon_name = hostname;
959bbaa8b60SDan Kruchinin 	args.my_id.my_name = uts_nodename();
960bbaa8b60SDan Kruchinin 	args.my_id.my_prog = NLM_PROG;
961bbaa8b60SDan Kruchinin 	args.my_id.my_vers = NLM_SM;
962bbaa8b60SDan Kruchinin 	args.my_id.my_proc = NLM_SM_NOTIFY1;
963bbaa8b60SDan Kruchinin 
964bbaa8b60SDan Kruchinin 	sema_p(&nsm->ns_sem);
965bbaa8b60SDan Kruchinin 	nlm_nsm_clnt_init(nsm->ns_handle, nsm);
966bbaa8b60SDan Kruchinin 	stat = sm_unmon_1(&args, &res, nsm->ns_handle);
967bbaa8b60SDan Kruchinin 	sema_v(&nsm->ns_sem);
968bbaa8b60SDan Kruchinin 
969bbaa8b60SDan Kruchinin 	return (stat);
970bbaa8b60SDan Kruchinin }
971bbaa8b60SDan Kruchinin 
972bbaa8b60SDan Kruchinin static enum clnt_stat
nlm_nsmaddr_reg(struct nlm_nsm * nsm,char * name,int family,netobj * address)973bbaa8b60SDan Kruchinin nlm_nsmaddr_reg(struct nlm_nsm *nsm, char *name, int family, netobj *address)
974bbaa8b60SDan Kruchinin {
975bbaa8b60SDan Kruchinin 	struct reg1args args = { 0 };
976bbaa8b60SDan Kruchinin 	struct reg1res res = { 0 };
977bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
978bbaa8b60SDan Kruchinin 
979bbaa8b60SDan Kruchinin 	args.family = family;
980bbaa8b60SDan Kruchinin 	args.name = name;
981bbaa8b60SDan Kruchinin 	args.address = *address;
982bbaa8b60SDan Kruchinin 
983bbaa8b60SDan Kruchinin 	sema_p(&nsm->ns_sem);
984bbaa8b60SDan Kruchinin 	nlm_nsm_clnt_init(nsm->ns_addr_handle, nsm);
985bbaa8b60SDan Kruchinin 	stat = nsmaddrproc1_reg_1(&args, &res, nsm->ns_addr_handle);
986bbaa8b60SDan Kruchinin 	sema_v(&nsm->ns_sem);
987bbaa8b60SDan Kruchinin 
988bbaa8b60SDan Kruchinin 	return (stat);
989bbaa8b60SDan Kruchinin }
990bbaa8b60SDan Kruchinin 
991bbaa8b60SDan Kruchinin /*
992bbaa8b60SDan Kruchinin  * Get NLM vhold object corresponding to vnode "vp".
993bbaa8b60SDan Kruchinin  * If no such object was found, create a new one.
994bbaa8b60SDan Kruchinin  *
995bbaa8b60SDan Kruchinin  * The purpose of this function is to associate vhold
996bbaa8b60SDan Kruchinin  * object with given vnode, so that:
997bbaa8b60SDan Kruchinin  * 1) vnode is hold (VN_HOLD) while vhold object is alive.
998bbaa8b60SDan Kruchinin  * 2) host has a track of all vnodes it touched by lock
999bbaa8b60SDan Kruchinin  *    or share operations. These vnodes are accessible
1000bbaa8b60SDan Kruchinin  *    via collection of vhold objects.
1001bbaa8b60SDan Kruchinin  */
1002bbaa8b60SDan Kruchinin struct nlm_vhold *
nlm_vhold_get(struct nlm_host * hostp,vnode_t * vp)1003bbaa8b60SDan Kruchinin nlm_vhold_get(struct nlm_host *hostp, vnode_t *vp)
1004bbaa8b60SDan Kruchinin {
1005bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp, *new_nvp = NULL;
1006bbaa8b60SDan Kruchinin 
1007bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
1008bbaa8b60SDan Kruchinin 	nvp = nlm_vhold_find_locked(hostp, vp);
1009bbaa8b60SDan Kruchinin 	if (nvp != NULL)
1010bbaa8b60SDan Kruchinin 		goto out;
1011bbaa8b60SDan Kruchinin 
1012bbaa8b60SDan Kruchinin 	/* nlm_vhold wasn't found, then create a new one */
1013bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
1014bbaa8b60SDan Kruchinin 	new_nvp = kmem_cache_alloc(nlm_vhold_cache, KM_SLEEP);
1015bbaa8b60SDan Kruchinin 
1016bbaa8b60SDan Kruchinin 	/*
1017bbaa8b60SDan Kruchinin 	 * Check if another thread has already
1018bbaa8b60SDan Kruchinin 	 * created the same nlm_vhold.
1019bbaa8b60SDan Kruchinin 	 */
1020bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
1021bbaa8b60SDan Kruchinin 	nvp = nlm_vhold_find_locked(hostp, vp);
1022bbaa8b60SDan Kruchinin 	if (nvp == NULL) {
1023bbaa8b60SDan Kruchinin 		nvp = new_nvp;
1024bbaa8b60SDan Kruchinin 		new_nvp = NULL;
1025bbaa8b60SDan Kruchinin 
1026bbaa8b60SDan Kruchinin 		TAILQ_INIT(&nvp->nv_slreqs);
1027bbaa8b60SDan Kruchinin 		nvp->nv_vp = vp;
1028bbaa8b60SDan Kruchinin 		nvp->nv_refcnt = 1;
1029bbaa8b60SDan Kruchinin 		VN_HOLD(nvp->nv_vp);
1030bbaa8b60SDan Kruchinin 
1031bbaa8b60SDan Kruchinin 		VERIFY(mod_hash_insert(hostp->nh_vholds_by_vp,
1032bbaa8b60SDan Kruchinin 		    (mod_hash_key_t)vp, (mod_hash_val_t)nvp) == 0);
1033bbaa8b60SDan Kruchinin 		TAILQ_INSERT_TAIL(&hostp->nh_vholds_list, nvp, nv_link);
1034bbaa8b60SDan Kruchinin 	}
1035bbaa8b60SDan Kruchinin 
1036bbaa8b60SDan Kruchinin out:
1037bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
1038bbaa8b60SDan Kruchinin 	if (new_nvp != NULL)
1039bbaa8b60SDan Kruchinin 		kmem_cache_free(nlm_vhold_cache, new_nvp);
1040bbaa8b60SDan Kruchinin 
1041bbaa8b60SDan Kruchinin 	return (nvp);
1042bbaa8b60SDan Kruchinin }
1043bbaa8b60SDan Kruchinin 
1044bbaa8b60SDan Kruchinin /*
1045bbaa8b60SDan Kruchinin  * Drop a reference to vhold object nvp.
1046bbaa8b60SDan Kruchinin  */
1047bbaa8b60SDan Kruchinin void
nlm_vhold_release(struct nlm_host * hostp,struct nlm_vhold * nvp)1048bbaa8b60SDan Kruchinin nlm_vhold_release(struct nlm_host *hostp, struct nlm_vhold *nvp)
1049bbaa8b60SDan Kruchinin {
1050bbaa8b60SDan Kruchinin 	if (nvp == NULL)
1051bbaa8b60SDan Kruchinin 		return;
1052bbaa8b60SDan Kruchinin 
1053bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
1054bbaa8b60SDan Kruchinin 	ASSERT(nvp->nv_refcnt > 0);
1055bbaa8b60SDan Kruchinin 	nvp->nv_refcnt--;
1056b1087aecSMarcel Telka 
1057b1087aecSMarcel Telka 	/*
1058b1087aecSMarcel Telka 	 * If these conditions are met, the vhold is obviously unused and we
1059b1087aecSMarcel Telka 	 * will destroy it.  In a case either v_filocks and/or v_shrlocks is
1060b1087aecSMarcel Telka 	 * non-NULL the vhold might still be unused by the host, but it is
1061b1087aecSMarcel Telka 	 * expensive to check that.  We defer such check until the host is
1062b1087aecSMarcel Telka 	 * idle.  The expensive check is done in the NLM garbage collector.
1063b1087aecSMarcel Telka 	 */
1064b1087aecSMarcel Telka 	if (nvp->nv_refcnt == 0 &&
1065b1087aecSMarcel Telka 	    nvp->nv_vp->v_filocks == NULL &&
1066b1087aecSMarcel Telka 	    nvp->nv_vp->v_shrlocks == NULL) {
1067b1087aecSMarcel Telka 		nlm_vhold_destroy(hostp, nvp);
1068b1087aecSMarcel Telka 	}
1069b1087aecSMarcel Telka 
1070bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
1071bbaa8b60SDan Kruchinin }
1072bbaa8b60SDan Kruchinin 
1073bbaa8b60SDan Kruchinin /*
1074bbaa8b60SDan Kruchinin  * Clean all locks and share reservations on the
1075bbaa8b60SDan Kruchinin  * given vhold object that were acquired by the
1076bbaa8b60SDan Kruchinin  * given sysid
1077bbaa8b60SDan Kruchinin  */
1078bbaa8b60SDan Kruchinin static void
nlm_vhold_clean(struct nlm_vhold * nvp,int sysid)1079bbaa8b60SDan Kruchinin nlm_vhold_clean(struct nlm_vhold *nvp, int sysid)
1080bbaa8b60SDan Kruchinin {
1081bbaa8b60SDan Kruchinin 	cleanlocks(nvp->nv_vp, IGN_PID, sysid);
1082bbaa8b60SDan Kruchinin 	cleanshares_by_sysid(nvp->nv_vp, sysid);
1083bbaa8b60SDan Kruchinin }
1084bbaa8b60SDan Kruchinin 
1085bbaa8b60SDan Kruchinin static void
nlm_vhold_destroy(struct nlm_host * hostp,struct nlm_vhold * nvp)1086bbaa8b60SDan Kruchinin nlm_vhold_destroy(struct nlm_host *hostp, struct nlm_vhold *nvp)
1087bbaa8b60SDan Kruchinin {
1088bbaa8b60SDan Kruchinin 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1089bbaa8b60SDan Kruchinin 
1090b1087aecSMarcel Telka 	ASSERT(nvp->nv_refcnt == 0);
1091b1087aecSMarcel Telka 	ASSERT(TAILQ_EMPTY(&nvp->nv_slreqs));
1092b1087aecSMarcel Telka 
1093bbaa8b60SDan Kruchinin 	VERIFY(mod_hash_remove(hostp->nh_vholds_by_vp,
1094bbaa8b60SDan Kruchinin 	    (mod_hash_key_t)nvp->nv_vp,
1095bbaa8b60SDan Kruchinin 	    (mod_hash_val_t)&nvp) == 0);
1096bbaa8b60SDan Kruchinin 
1097bbaa8b60SDan Kruchinin 	TAILQ_REMOVE(&hostp->nh_vholds_list, nvp, nv_link);
1098bbaa8b60SDan Kruchinin 	VN_RELE(nvp->nv_vp);
1099bbaa8b60SDan Kruchinin 	nvp->nv_vp = NULL;
1100bbaa8b60SDan Kruchinin 
1101bbaa8b60SDan Kruchinin 	kmem_cache_free(nlm_vhold_cache, nvp);
1102bbaa8b60SDan Kruchinin }
1103bbaa8b60SDan Kruchinin 
1104bbaa8b60SDan Kruchinin /*
1105bbaa8b60SDan Kruchinin  * Return TRUE if the given vhold is busy.
1106bbaa8b60SDan Kruchinin  * Vhold object is considered to be "busy" when
1107bbaa8b60SDan Kruchinin  * all the following conditions hold:
1108bbaa8b60SDan Kruchinin  * 1) No one uses it at the moment;
1109bbaa8b60SDan Kruchinin  * 2) It hasn't any locks;
1110bbaa8b60SDan Kruchinin  * 3) It hasn't any share reservations;
1111bbaa8b60SDan Kruchinin  */
1112bbaa8b60SDan Kruchinin static bool_t
nlm_vhold_busy(struct nlm_host * hostp,struct nlm_vhold * nvp)1113bbaa8b60SDan Kruchinin nlm_vhold_busy(struct nlm_host *hostp, struct nlm_vhold *nvp)
1114bbaa8b60SDan Kruchinin {
1115bbaa8b60SDan Kruchinin 	vnode_t *vp;
1116bbaa8b60SDan Kruchinin 	int sysid;
1117bbaa8b60SDan Kruchinin 
1118bbaa8b60SDan Kruchinin 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1119bbaa8b60SDan Kruchinin 
1120bbaa8b60SDan Kruchinin 	if (nvp->nv_refcnt > 0)
1121bbaa8b60SDan Kruchinin 		return (TRUE);
1122bbaa8b60SDan Kruchinin 
1123bbaa8b60SDan Kruchinin 	vp = nvp->nv_vp;
1124bbaa8b60SDan Kruchinin 	sysid = hostp->nh_sysid;
1125bbaa8b60SDan Kruchinin 	if (flk_has_remote_locks_for_sysid(vp, sysid) ||
1126bbaa8b60SDan Kruchinin 	    shr_has_remote_shares(vp, sysid))
1127bbaa8b60SDan Kruchinin 		return (TRUE);
1128bbaa8b60SDan Kruchinin 
1129bbaa8b60SDan Kruchinin 	return (FALSE);
1130bbaa8b60SDan Kruchinin }
1131bbaa8b60SDan Kruchinin 
1132bbaa8b60SDan Kruchinin /* ARGSUSED */
1133bbaa8b60SDan Kruchinin static int
nlm_vhold_ctor(void * datap,void * cdrarg,int kmflags)1134bbaa8b60SDan Kruchinin nlm_vhold_ctor(void *datap, void *cdrarg, int kmflags)
1135bbaa8b60SDan Kruchinin {
1136bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp = (struct nlm_vhold *)datap;
1137bbaa8b60SDan Kruchinin 
1138bbaa8b60SDan Kruchinin 	bzero(nvp, sizeof (*nvp));
1139bbaa8b60SDan Kruchinin 	return (0);
1140bbaa8b60SDan Kruchinin }
1141bbaa8b60SDan Kruchinin 
1142bbaa8b60SDan Kruchinin /* ARGSUSED */
1143bbaa8b60SDan Kruchinin static void
nlm_vhold_dtor(void * datap,void * cdrarg)1144bbaa8b60SDan Kruchinin nlm_vhold_dtor(void *datap, void *cdrarg)
1145bbaa8b60SDan Kruchinin {
1146bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp = (struct nlm_vhold *)datap;
1147bbaa8b60SDan Kruchinin 
1148bbaa8b60SDan Kruchinin 	ASSERT(nvp->nv_refcnt == 0);
1149bbaa8b60SDan Kruchinin 	ASSERT(TAILQ_EMPTY(&nvp->nv_slreqs));
1150bbaa8b60SDan Kruchinin 	ASSERT(nvp->nv_vp == NULL);
1151bbaa8b60SDan Kruchinin }
1152bbaa8b60SDan Kruchinin 
1153bbaa8b60SDan Kruchinin struct nlm_vhold *
nlm_vhold_find_locked(struct nlm_host * hostp,const vnode_t * vp)1154bbaa8b60SDan Kruchinin nlm_vhold_find_locked(struct nlm_host *hostp, const vnode_t *vp)
1155bbaa8b60SDan Kruchinin {
1156bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp = NULL;
1157bbaa8b60SDan Kruchinin 
1158bbaa8b60SDan Kruchinin 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1159bbaa8b60SDan Kruchinin 	(void) mod_hash_find(hostp->nh_vholds_by_vp,
1160bbaa8b60SDan Kruchinin 	    (mod_hash_key_t)vp,
1161bbaa8b60SDan Kruchinin 	    (mod_hash_val_t)&nvp);
1162bbaa8b60SDan Kruchinin 
1163bbaa8b60SDan Kruchinin 	if (nvp != NULL)
1164bbaa8b60SDan Kruchinin 		nvp->nv_refcnt++;
1165bbaa8b60SDan Kruchinin 
1166bbaa8b60SDan Kruchinin 	return (nvp);
1167bbaa8b60SDan Kruchinin }
1168bbaa8b60SDan Kruchinin 
1169bbaa8b60SDan Kruchinin /*
1170bbaa8b60SDan Kruchinin  * NLM host functions
1171bbaa8b60SDan Kruchinin  */
1172bbaa8b60SDan Kruchinin static void
nlm_copy_netbuf(struct netbuf * dst,struct netbuf * src)1173bbaa8b60SDan Kruchinin nlm_copy_netbuf(struct netbuf *dst, struct netbuf *src)
1174bbaa8b60SDan Kruchinin {
1175bbaa8b60SDan Kruchinin 	ASSERT(src->len <= src->maxlen);
1176bbaa8b60SDan Kruchinin 
1177bbaa8b60SDan Kruchinin 	dst->maxlen = src->maxlen;
1178bbaa8b60SDan Kruchinin 	dst->len = src->len;
1179bbaa8b60SDan Kruchinin 	dst->buf = kmem_zalloc(src->maxlen, KM_SLEEP);
1180bbaa8b60SDan Kruchinin 	bcopy(src->buf, dst->buf, src->len);
1181bbaa8b60SDan Kruchinin }
1182bbaa8b60SDan Kruchinin 
1183bbaa8b60SDan Kruchinin /* ARGSUSED */
1184bbaa8b60SDan Kruchinin static int
nlm_host_ctor(void * datap,void * cdrarg,int kmflags)1185bbaa8b60SDan Kruchinin nlm_host_ctor(void *datap, void *cdrarg, int kmflags)
1186bbaa8b60SDan Kruchinin {
1187bbaa8b60SDan Kruchinin 	struct nlm_host *hostp = (struct nlm_host *)datap;
1188bbaa8b60SDan Kruchinin 
1189bbaa8b60SDan Kruchinin 	bzero(hostp, sizeof (*hostp));
1190bbaa8b60SDan Kruchinin 	return (0);
1191bbaa8b60SDan Kruchinin }
1192bbaa8b60SDan Kruchinin 
1193bbaa8b60SDan Kruchinin /* ARGSUSED */
1194bbaa8b60SDan Kruchinin static void
nlm_host_dtor(void * datap,void * cdrarg)1195bbaa8b60SDan Kruchinin nlm_host_dtor(void *datap, void *cdrarg)
1196bbaa8b60SDan Kruchinin {
1197bbaa8b60SDan Kruchinin 	struct nlm_host *hostp = (struct nlm_host *)datap;
1198bbaa8b60SDan Kruchinin 	ASSERT(hostp->nh_refs == 0);
1199bbaa8b60SDan Kruchinin }
1200bbaa8b60SDan Kruchinin 
1201bbaa8b60SDan Kruchinin static void
nlm_host_unregister(struct nlm_globals * g,struct nlm_host * hostp)1202bbaa8b60SDan Kruchinin nlm_host_unregister(struct nlm_globals *g, struct nlm_host *hostp)
1203bbaa8b60SDan Kruchinin {
1204bbaa8b60SDan Kruchinin 	ASSERT(hostp->nh_refs == 0);
1205096e63b2SPaul Dagnelie 	ASSERT(hostp->nh_flags & NLM_NH_INIDLE);
1206bbaa8b60SDan Kruchinin 
1207bbaa8b60SDan Kruchinin 	avl_remove(&g->nlm_hosts_tree, hostp);
1208bbaa8b60SDan Kruchinin 	VERIFY(mod_hash_remove(g->nlm_hosts_hash,
1209bbaa8b60SDan Kruchinin 	    (mod_hash_key_t)(uintptr_t)hostp->nh_sysid,
1210bbaa8b60SDan Kruchinin 	    (mod_hash_val_t)&hostp) == 0);
1211bbaa8b60SDan Kruchinin 	TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1212bbaa8b60SDan Kruchinin 	hostp->nh_flags &= ~NLM_NH_INIDLE;
1213bbaa8b60SDan Kruchinin }
1214bbaa8b60SDan Kruchinin 
1215bbaa8b60SDan Kruchinin /*
1216bbaa8b60SDan Kruchinin  * Free resources used by a host. This is called after the reference
1217bbaa8b60SDan Kruchinin  * count has reached zero so it doesn't need to worry about locks.
1218bbaa8b60SDan Kruchinin  */
1219bbaa8b60SDan Kruchinin static void
nlm_host_destroy(struct nlm_host * hostp)1220bbaa8b60SDan Kruchinin nlm_host_destroy(struct nlm_host *hostp)
1221bbaa8b60SDan Kruchinin {
1222bbaa8b60SDan Kruchinin 	ASSERT(hostp->nh_name != NULL);
1223bbaa8b60SDan Kruchinin 	ASSERT(hostp->nh_netid != NULL);
1224bbaa8b60SDan Kruchinin 	ASSERT(TAILQ_EMPTY(&hostp->nh_vholds_list));
1225bbaa8b60SDan Kruchinin 
1226bbaa8b60SDan Kruchinin 	strfree(hostp->nh_name);
1227bbaa8b60SDan Kruchinin 	strfree(hostp->nh_netid);
1228bbaa8b60SDan Kruchinin 	kmem_free(hostp->nh_addr.buf, hostp->nh_addr.maxlen);
1229bbaa8b60SDan Kruchinin 
1230bbaa8b60SDan Kruchinin 	if (hostp->nh_sysid != LM_NOSYSID)
1231bbaa8b60SDan Kruchinin 		nlm_sysid_free(hostp->nh_sysid);
1232bbaa8b60SDan Kruchinin 
1233bbaa8b60SDan Kruchinin 	nlm_rpc_cache_destroy(hostp);
1234bbaa8b60SDan Kruchinin 
1235bbaa8b60SDan Kruchinin 	ASSERT(TAILQ_EMPTY(&hostp->nh_vholds_list));
1236bbaa8b60SDan Kruchinin 	mod_hash_destroy_ptrhash(hostp->nh_vholds_by_vp);
1237bbaa8b60SDan Kruchinin 
1238bbaa8b60SDan Kruchinin 	mutex_destroy(&hostp->nh_lock);
1239bbaa8b60SDan Kruchinin 	cv_destroy(&hostp->nh_rpcb_cv);
1240bbaa8b60SDan Kruchinin 	cv_destroy(&hostp->nh_recl_cv);
1241bbaa8b60SDan Kruchinin 
1242bbaa8b60SDan Kruchinin 	kmem_cache_free(nlm_hosts_cache, hostp);
1243bbaa8b60SDan Kruchinin }
1244bbaa8b60SDan Kruchinin 
1245bbaa8b60SDan Kruchinin /*
1246bbaa8b60SDan Kruchinin  * Cleanup SERVER-side state after a client restarts,
1247bbaa8b60SDan Kruchinin  * or becomes unresponsive, or whatever.
1248bbaa8b60SDan Kruchinin  *
1249bbaa8b60SDan Kruchinin  * We unlock any active locks owned by the host.
1250bbaa8b60SDan Kruchinin  * When rpc.lockd is shutting down,
1251bbaa8b60SDan Kruchinin  * this function is called with newstate set to zero
1252bbaa8b60SDan Kruchinin  * which allows us to cancel any pending async locks
1253bbaa8b60SDan Kruchinin  * and clear the locking state.
1254bbaa8b60SDan Kruchinin  *
1255bbaa8b60SDan Kruchinin  * When "state" is 0, we don't update host's state,
1256bbaa8b60SDan Kruchinin  * but cleanup all remote locks on the host.
1257bbaa8b60SDan Kruchinin  * It's useful to call this function for resources
1258bbaa8b60SDan Kruchinin  * cleanup.
1259bbaa8b60SDan Kruchinin  */
1260bbaa8b60SDan Kruchinin void
nlm_host_notify_server(struct nlm_host * hostp,int32_t state)1261bbaa8b60SDan Kruchinin nlm_host_notify_server(struct nlm_host *hostp, int32_t state)
1262bbaa8b60SDan Kruchinin {
1263bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp;
1264bbaa8b60SDan Kruchinin 	struct nlm_slreq *slr;
1265bbaa8b60SDan Kruchinin 	struct nlm_slreq_list slreqs2free;
1266bbaa8b60SDan Kruchinin 
1267bbaa8b60SDan Kruchinin 	TAILQ_INIT(&slreqs2free);
1268bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
1269bbaa8b60SDan Kruchinin 	if (state != 0)
1270bbaa8b60SDan Kruchinin 		hostp->nh_state = state;
1271bbaa8b60SDan Kruchinin 
1272bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(nvp, &hostp->nh_vholds_list, nv_link) {
1273bbaa8b60SDan Kruchinin 
1274bbaa8b60SDan Kruchinin 		/* cleanup sleeping requests at first */
1275bbaa8b60SDan Kruchinin 		while ((slr = TAILQ_FIRST(&nvp->nv_slreqs)) != NULL) {
1276bbaa8b60SDan Kruchinin 			TAILQ_REMOVE(&nvp->nv_slreqs, slr, nsr_link);
1277bbaa8b60SDan Kruchinin 
1278bbaa8b60SDan Kruchinin 			/*
1279bbaa8b60SDan Kruchinin 			 * Instead of freeing cancelled sleeping request
1280bbaa8b60SDan Kruchinin 			 * here, we add it to the linked list created
1281bbaa8b60SDan Kruchinin 			 * on the stack in order to do all frees outside
1282bbaa8b60SDan Kruchinin 			 * the critical section.
1283bbaa8b60SDan Kruchinin 			 */
1284bbaa8b60SDan Kruchinin 			TAILQ_INSERT_TAIL(&slreqs2free, slr, nsr_link);
1285bbaa8b60SDan Kruchinin 		}
1286bbaa8b60SDan Kruchinin 
1287bbaa8b60SDan Kruchinin 		nvp->nv_refcnt++;
1288bbaa8b60SDan Kruchinin 		mutex_exit(&hostp->nh_lock);
1289bbaa8b60SDan Kruchinin 
1290bbaa8b60SDan Kruchinin 		nlm_vhold_clean(nvp, hostp->nh_sysid);
1291bbaa8b60SDan Kruchinin 
1292bbaa8b60SDan Kruchinin 		mutex_enter(&hostp->nh_lock);
1293bbaa8b60SDan Kruchinin 		nvp->nv_refcnt--;
1294bbaa8b60SDan Kruchinin 	}
1295bbaa8b60SDan Kruchinin 
1296bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
1297bbaa8b60SDan Kruchinin 	while ((slr = TAILQ_FIRST(&slreqs2free)) != NULL) {
1298bbaa8b60SDan Kruchinin 		TAILQ_REMOVE(&slreqs2free, slr, nsr_link);
1299bbaa8b60SDan Kruchinin 		kmem_free(slr, sizeof (*slr));
1300bbaa8b60SDan Kruchinin 	}
1301bbaa8b60SDan Kruchinin }
1302bbaa8b60SDan Kruchinin 
1303bbaa8b60SDan Kruchinin /*
1304bbaa8b60SDan Kruchinin  * Cleanup CLIENT-side state after a server restarts,
1305bbaa8b60SDan Kruchinin  * or becomes unresponsive, or whatever.
1306bbaa8b60SDan Kruchinin  *
1307bbaa8b60SDan Kruchinin  * This is called by the local NFS statd when we receive a
1308bbaa8b60SDan Kruchinin  * host state change notification.  (also nlm_svc_stopping)
1309bbaa8b60SDan Kruchinin  *
1310bbaa8b60SDan Kruchinin  * Deal with a server restart.  If we are stopping the
1311bbaa8b60SDan Kruchinin  * NLM service, we'll have newstate == 0, and will just
1312bbaa8b60SDan Kruchinin  * cancel all our client-side lock requests.  Otherwise,
1313bbaa8b60SDan Kruchinin  * start the "recovery" process to reclaim any locks
1314bbaa8b60SDan Kruchinin  * we hold on this server.
1315bbaa8b60SDan Kruchinin  */
1316bbaa8b60SDan Kruchinin void
nlm_host_notify_client(struct nlm_host * hostp,int32_t state)1317bbaa8b60SDan Kruchinin nlm_host_notify_client(struct nlm_host *hostp, int32_t state)
1318bbaa8b60SDan Kruchinin {
1319bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
1320bbaa8b60SDan Kruchinin 	hostp->nh_state = state;
1321bbaa8b60SDan Kruchinin 	if (hostp->nh_flags & NLM_NH_RECLAIM) {
1322bbaa8b60SDan Kruchinin 		/*
1323bbaa8b60SDan Kruchinin 		 * Either host's state is up to date or
1324bbaa8b60SDan Kruchinin 		 * host is already in recovery.
1325bbaa8b60SDan Kruchinin 		 */
1326bbaa8b60SDan Kruchinin 		mutex_exit(&hostp->nh_lock);
1327bbaa8b60SDan Kruchinin 		return;
1328bbaa8b60SDan Kruchinin 	}
1329bbaa8b60SDan Kruchinin 
1330bbaa8b60SDan Kruchinin 	hostp->nh_flags |= NLM_NH_RECLAIM;
1331bbaa8b60SDan Kruchinin 
1332bbaa8b60SDan Kruchinin 	/*
1333bbaa8b60SDan Kruchinin 	 * Host will be released by the recovery thread,
1334bbaa8b60SDan Kruchinin 	 * thus we need to increment refcount.
1335bbaa8b60SDan Kruchinin 	 */
1336bbaa8b60SDan Kruchinin 	hostp->nh_refs++;
1337bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
1338bbaa8b60SDan Kruchinin 
1339bbaa8b60SDan Kruchinin 	(void) zthread_create(NULL, 0, nlm_reclaimer,
1340bbaa8b60SDan Kruchinin 	    hostp, 0, minclsyspri);
1341bbaa8b60SDan Kruchinin }
1342bbaa8b60SDan Kruchinin 
1343bbaa8b60SDan Kruchinin /*
1344bbaa8b60SDan Kruchinin  * The function is called when NLM client detects that
1345bbaa8b60SDan Kruchinin  * server has entered in grace period and client needs
1346bbaa8b60SDan Kruchinin  * to wait until reclamation process (if any) does
1347bbaa8b60SDan Kruchinin  * its job.
1348bbaa8b60SDan Kruchinin  */
1349bbaa8b60SDan Kruchinin int
nlm_host_wait_grace(struct nlm_host * hostp)1350bbaa8b60SDan Kruchinin nlm_host_wait_grace(struct nlm_host *hostp)
1351bbaa8b60SDan Kruchinin {
1352bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
1353bbaa8b60SDan Kruchinin 	int error = 0;
1354bbaa8b60SDan Kruchinin 
1355bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
1356bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
1357bbaa8b60SDan Kruchinin 
1358bbaa8b60SDan Kruchinin 	do {
1359bbaa8b60SDan Kruchinin 		int rc;
1360bbaa8b60SDan Kruchinin 
1361bbaa8b60SDan Kruchinin 		rc = cv_timedwait_sig(&hostp->nh_recl_cv,
1362bbaa8b60SDan Kruchinin 		    &hostp->nh_lock, ddi_get_lbolt() +
1363bbaa8b60SDan Kruchinin 		    SEC_TO_TICK(g->retrans_tmo));
1364bbaa8b60SDan Kruchinin 
1365bbaa8b60SDan Kruchinin 		if (rc == 0) {
1366bbaa8b60SDan Kruchinin 			error = EINTR;
1367bbaa8b60SDan Kruchinin 			break;
1368bbaa8b60SDan Kruchinin 		}
1369bbaa8b60SDan Kruchinin 	} while (hostp->nh_flags & NLM_NH_RECLAIM);
1370bbaa8b60SDan Kruchinin 
1371bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
1372bbaa8b60SDan Kruchinin 	return (error);
1373bbaa8b60SDan Kruchinin }
1374bbaa8b60SDan Kruchinin 
1375bbaa8b60SDan Kruchinin /*
1376bbaa8b60SDan Kruchinin  * Create a new NLM host.
1377bbaa8b60SDan Kruchinin  *
1378bbaa8b60SDan Kruchinin  * NOTE: The in-kernel RPC (kRPC) subsystem uses TLI/XTI,
1379bbaa8b60SDan Kruchinin  * which needs both a knetconfig and an address when creating
1380bbaa8b60SDan Kruchinin  * endpoints. Thus host object stores both knetconfig and
1381bbaa8b60SDan Kruchinin  * netid.
1382bbaa8b60SDan Kruchinin  */
1383bbaa8b60SDan Kruchinin static struct nlm_host *
nlm_host_create(char * name,const char * netid,struct knetconfig * knc,struct netbuf * naddr)1384bbaa8b60SDan Kruchinin nlm_host_create(char *name, const char *netid,
1385bbaa8b60SDan Kruchinin     struct knetconfig *knc, struct netbuf *naddr)
1386bbaa8b60SDan Kruchinin {
1387bbaa8b60SDan Kruchinin 	struct nlm_host *host;
1388bbaa8b60SDan Kruchinin 
1389bbaa8b60SDan Kruchinin 	host = kmem_cache_alloc(nlm_hosts_cache, KM_SLEEP);
1390bbaa8b60SDan Kruchinin 
1391bbaa8b60SDan Kruchinin 	mutex_init(&host->nh_lock, NULL, MUTEX_DEFAULT, NULL);
1392bbaa8b60SDan Kruchinin 	cv_init(&host->nh_rpcb_cv, NULL, CV_DEFAULT, NULL);
1393bbaa8b60SDan Kruchinin 	cv_init(&host->nh_recl_cv, NULL, CV_DEFAULT, NULL);
1394bbaa8b60SDan Kruchinin 
1395bbaa8b60SDan Kruchinin 	host->nh_sysid = LM_NOSYSID;
1396bbaa8b60SDan Kruchinin 	host->nh_refs = 1;
1397bbaa8b60SDan Kruchinin 	host->nh_name = strdup(name);
1398bbaa8b60SDan Kruchinin 	host->nh_netid = strdup(netid);
1399bbaa8b60SDan Kruchinin 	host->nh_knc = *knc;
1400bbaa8b60SDan Kruchinin 	nlm_copy_netbuf(&host->nh_addr, naddr);
1401bbaa8b60SDan Kruchinin 
1402bbaa8b60SDan Kruchinin 	host->nh_state = 0;
1403bbaa8b60SDan Kruchinin 	host->nh_rpcb_state = NRPCB_NEED_UPDATE;
1404bbaa8b60SDan Kruchinin 	host->nh_flags = 0;
1405bbaa8b60SDan Kruchinin 
1406bbaa8b60SDan Kruchinin 	host->nh_vholds_by_vp = mod_hash_create_ptrhash("nlm vholds hash",
1407bbaa8b60SDan Kruchinin 	    32, mod_hash_null_valdtor, sizeof (vnode_t));
1408bbaa8b60SDan Kruchinin 
1409bbaa8b60SDan Kruchinin 	TAILQ_INIT(&host->nh_vholds_list);
1410bbaa8b60SDan Kruchinin 	TAILQ_INIT(&host->nh_rpchc);
1411bbaa8b60SDan Kruchinin 
1412bbaa8b60SDan Kruchinin 	return (host);
1413bbaa8b60SDan Kruchinin }
1414bbaa8b60SDan Kruchinin 
1415bbaa8b60SDan Kruchinin /*
1416bbaa8b60SDan Kruchinin  * Cancel all client side sleeping locks owned by given host.
1417bbaa8b60SDan Kruchinin  */
1418bbaa8b60SDan Kruchinin void
nlm_host_cancel_slocks(struct nlm_globals * g,struct nlm_host * hostp)1419bbaa8b60SDan Kruchinin nlm_host_cancel_slocks(struct nlm_globals *g, struct nlm_host *hostp)
1420bbaa8b60SDan Kruchinin {
1421bbaa8b60SDan Kruchinin 	struct nlm_slock *nslp;
1422bbaa8b60SDan Kruchinin 
1423bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
1424bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) {
1425bbaa8b60SDan Kruchinin 		if (nslp->nsl_host == hostp) {
1426bbaa8b60SDan Kruchinin 			nslp->nsl_state = NLM_SL_CANCELLED;
1427bbaa8b60SDan Kruchinin 			cv_broadcast(&nslp->nsl_cond);
1428bbaa8b60SDan Kruchinin 		}
1429bbaa8b60SDan Kruchinin 	}
1430bbaa8b60SDan Kruchinin 
1431bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1432bbaa8b60SDan Kruchinin }
1433bbaa8b60SDan Kruchinin 
1434bbaa8b60SDan Kruchinin /*
1435bbaa8b60SDan Kruchinin  * Garbage collect stale vhold objects.
1436bbaa8b60SDan Kruchinin  *
1437bbaa8b60SDan Kruchinin  * In other words check whether vnodes that are
1438bbaa8b60SDan Kruchinin  * held by vhold objects still have any locks
1439bbaa8b60SDan Kruchinin  * or shares or still in use. If they aren't,
1440bbaa8b60SDan Kruchinin  * just destroy them.
1441bbaa8b60SDan Kruchinin  */
1442bbaa8b60SDan Kruchinin static void
nlm_host_gc_vholds(struct nlm_host * hostp)1443bbaa8b60SDan Kruchinin nlm_host_gc_vholds(struct nlm_host *hostp)
1444bbaa8b60SDan Kruchinin {
1445bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp;
1446bbaa8b60SDan Kruchinin 
1447bbaa8b60SDan Kruchinin 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1448bbaa8b60SDan Kruchinin 
1449bbaa8b60SDan Kruchinin 	nvp = TAILQ_FIRST(&hostp->nh_vholds_list);
1450bbaa8b60SDan Kruchinin 	while (nvp != NULL) {
1451bbaa8b60SDan Kruchinin 		struct nlm_vhold *nvp_tmp;
1452bbaa8b60SDan Kruchinin 
1453bbaa8b60SDan Kruchinin 		if (nlm_vhold_busy(hostp, nvp)) {
1454bbaa8b60SDan Kruchinin 			nvp = TAILQ_NEXT(nvp, nv_link);
1455bbaa8b60SDan Kruchinin 			continue;
1456bbaa8b60SDan Kruchinin 		}
1457bbaa8b60SDan Kruchinin 
1458bbaa8b60SDan Kruchinin 		nvp_tmp = TAILQ_NEXT(nvp, nv_link);
1459bbaa8b60SDan Kruchinin 		nlm_vhold_destroy(hostp, nvp);
1460bbaa8b60SDan Kruchinin 		nvp = nvp_tmp;
1461bbaa8b60SDan Kruchinin 	}
1462bbaa8b60SDan Kruchinin }
1463bbaa8b60SDan Kruchinin 
1464bbaa8b60SDan Kruchinin /*
1465bbaa8b60SDan Kruchinin  * Check whether the given host has any
1466bbaa8b60SDan Kruchinin  * server side locks or share reservations.
1467bbaa8b60SDan Kruchinin  */
1468bbaa8b60SDan Kruchinin static bool_t
nlm_host_has_srv_locks(struct nlm_host * hostp)1469bbaa8b60SDan Kruchinin nlm_host_has_srv_locks(struct nlm_host *hostp)
1470bbaa8b60SDan Kruchinin {
1471bbaa8b60SDan Kruchinin 	/*
1472bbaa8b60SDan Kruchinin 	 * It's cheap and simple: if server has
1473bbaa8b60SDan Kruchinin 	 * any locks/shares there must be vhold
1474bbaa8b60SDan Kruchinin 	 * object storing the affected vnode.
1475bbaa8b60SDan Kruchinin 	 *
1476bbaa8b60SDan Kruchinin 	 * NOTE: We don't need to check sleeping
1477bbaa8b60SDan Kruchinin 	 * locks on the server side, because if
1478bbaa8b60SDan Kruchinin 	 * server side sleeping lock is alive,
1479bbaa8b60SDan Kruchinin 	 * there must be a vhold object corresponding
1480bbaa8b60SDan Kruchinin 	 * to target vnode.
1481bbaa8b60SDan Kruchinin 	 */
1482bbaa8b60SDan Kruchinin 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1483bbaa8b60SDan Kruchinin 	if (!TAILQ_EMPTY(&hostp->nh_vholds_list))
1484bbaa8b60SDan Kruchinin 		return (TRUE);
1485bbaa8b60SDan Kruchinin 
1486bbaa8b60SDan Kruchinin 	return (FALSE);
1487bbaa8b60SDan Kruchinin }
1488bbaa8b60SDan Kruchinin 
1489bbaa8b60SDan Kruchinin /*
1490bbaa8b60SDan Kruchinin  * Check whether the given host has any client side
1491bbaa8b60SDan Kruchinin  * locks or share reservations.
1492bbaa8b60SDan Kruchinin  */
1493bbaa8b60SDan Kruchinin static bool_t
nlm_host_has_cli_locks(struct nlm_host * hostp)1494bbaa8b60SDan Kruchinin nlm_host_has_cli_locks(struct nlm_host *hostp)
1495bbaa8b60SDan Kruchinin {
1496bbaa8b60SDan Kruchinin 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
1497bbaa8b60SDan Kruchinin 
1498bbaa8b60SDan Kruchinin 	/*
1499bbaa8b60SDan Kruchinin 	 * XXX: It's not the way I'd like to do the check,
1500bbaa8b60SDan Kruchinin 	 * because flk_sysid_has_locks() can be very
1501bbaa8b60SDan Kruchinin 	 * expensive by design. Unfortunatelly it iterates
1502bbaa8b60SDan Kruchinin 	 * through all locks on the system, doesn't matter
1503bbaa8b60SDan Kruchinin 	 * were they made on remote system via NLM or
1504bbaa8b60SDan Kruchinin 	 * on local system via reclock. To understand the
1505bbaa8b60SDan Kruchinin 	 * problem, consider that there're dozens of thousands
1506bbaa8b60SDan Kruchinin 	 * of locks that are made on some ZFS dataset. And there's
1507bbaa8b60SDan Kruchinin 	 * another dataset shared by NFS where NLM client had locks
1508bbaa8b60SDan Kruchinin 	 * some time ago, but doesn't have them now.
1509bbaa8b60SDan Kruchinin 	 * In this case flk_sysid_has_locks() will iterate
1510bbaa8b60SDan Kruchinin 	 * thrught dozens of thousands locks until it returns us
1511bbaa8b60SDan Kruchinin 	 * FALSE.
1512bbaa8b60SDan Kruchinin 	 * Oh, I hope that in shiny future somebody will make
1513bbaa8b60SDan Kruchinin 	 * local lock manager (os/flock.c) better, so that
1514bbaa8b60SDan Kruchinin 	 * it'd be more friedly to remote locks and
1515bbaa8b60SDan Kruchinin 	 * flk_sysid_has_locks() wouldn't be so expensive.
1516bbaa8b60SDan Kruchinin 	 */
1517bbaa8b60SDan Kruchinin 	if (flk_sysid_has_locks(hostp->nh_sysid |
1518bbaa8b60SDan Kruchinin 	    LM_SYSID_CLIENT, FLK_QUERY_ACTIVE))
1519bbaa8b60SDan Kruchinin 		return (TRUE);
1520bbaa8b60SDan Kruchinin 
1521bbaa8b60SDan Kruchinin 	/*
1522bbaa8b60SDan Kruchinin 	 * Check whether host has any share reservations
1523bbaa8b60SDan Kruchinin 	 * registered on the client side.
1524bbaa8b60SDan Kruchinin 	 */
1525bbaa8b60SDan Kruchinin 	if (hostp->nh_shrlist != NULL)
1526bbaa8b60SDan Kruchinin 		return (TRUE);
1527bbaa8b60SDan Kruchinin 
1528bbaa8b60SDan Kruchinin 	return (FALSE);
1529bbaa8b60SDan Kruchinin }
1530bbaa8b60SDan Kruchinin 
1531bbaa8b60SDan Kruchinin /*
1532bbaa8b60SDan Kruchinin  * Determine whether the given host owns any
1533bbaa8b60SDan Kruchinin  * locks or share reservations.
1534bbaa8b60SDan Kruchinin  */
1535bbaa8b60SDan Kruchinin static bool_t
nlm_host_has_locks(struct nlm_host * hostp)1536bbaa8b60SDan Kruchinin nlm_host_has_locks(struct nlm_host *hostp)
1537bbaa8b60SDan Kruchinin {
1538bbaa8b60SDan Kruchinin 	if (nlm_host_has_srv_locks(hostp))
1539bbaa8b60SDan Kruchinin 		return (TRUE);
1540bbaa8b60SDan Kruchinin 
1541bbaa8b60SDan Kruchinin 	return (nlm_host_has_cli_locks(hostp));
1542bbaa8b60SDan Kruchinin }
1543bbaa8b60SDan Kruchinin 
1544bbaa8b60SDan Kruchinin /*
1545bbaa8b60SDan Kruchinin  * This function compares only addresses of two netbufs
1546bbaa8b60SDan Kruchinin  * that belong to NC_TCP[6] or NC_UDP[6] protofamily.
1547bbaa8b60SDan Kruchinin  * Port part of netbuf is ignored.
1548bbaa8b60SDan Kruchinin  *
1549bbaa8b60SDan Kruchinin  * Return values:
1550bbaa8b60SDan Kruchinin  *  -1: nb1's address is "smaller" than nb2's
1551bbaa8b60SDan Kruchinin  *   0: addresses are equal
1552bbaa8b60SDan Kruchinin  *   1: nb1's address is "greater" than nb2's
1553bbaa8b60SDan Kruchinin  */
1554bbaa8b60SDan Kruchinin static int
nlm_netbuf_addrs_cmp(struct netbuf * nb1,struct netbuf * nb2)1555bbaa8b60SDan Kruchinin nlm_netbuf_addrs_cmp(struct netbuf *nb1, struct netbuf *nb2)
1556bbaa8b60SDan Kruchinin {
1557bbaa8b60SDan Kruchinin 	union nlm_addr {
1558bbaa8b60SDan Kruchinin 		struct sockaddr sa;
1559bbaa8b60SDan Kruchinin 		struct sockaddr_in sin;
1560bbaa8b60SDan Kruchinin 		struct sockaddr_in6 sin6;
1561bbaa8b60SDan Kruchinin 	} *na1, *na2;
1562bbaa8b60SDan Kruchinin 	int res;
1563bbaa8b60SDan Kruchinin 
1564bbaa8b60SDan Kruchinin 	/* LINTED E_BAD_PTR_CAST_ALIGN */
1565bbaa8b60SDan Kruchinin 	na1 = (union nlm_addr *)nb1->buf;
1566bbaa8b60SDan Kruchinin 	/* LINTED E_BAD_PTR_CAST_ALIGN */
1567bbaa8b60SDan Kruchinin 	na2 = (union nlm_addr *)nb2->buf;
1568bbaa8b60SDan Kruchinin 
1569bbaa8b60SDan Kruchinin 	if (na1->sa.sa_family < na2->sa.sa_family)
1570bbaa8b60SDan Kruchinin 		return (-1);
1571bbaa8b60SDan Kruchinin 	if (na1->sa.sa_family > na2->sa.sa_family)
1572bbaa8b60SDan Kruchinin 		return (1);
1573bbaa8b60SDan Kruchinin 
1574bbaa8b60SDan Kruchinin 	switch (na1->sa.sa_family) {
1575bbaa8b60SDan Kruchinin 	case AF_INET:
1576bbaa8b60SDan Kruchinin 		res = memcmp(&na1->sin.sin_addr, &na2->sin.sin_addr,
1577bbaa8b60SDan Kruchinin 		    sizeof (na1->sin.sin_addr));
1578bbaa8b60SDan Kruchinin 		break;
1579bbaa8b60SDan Kruchinin 	case AF_INET6:
1580bbaa8b60SDan Kruchinin 		res = memcmp(&na1->sin6.sin6_addr, &na2->sin6.sin6_addr,
1581bbaa8b60SDan Kruchinin 		    sizeof (na1->sin6.sin6_addr));
1582bbaa8b60SDan Kruchinin 		break;
1583bbaa8b60SDan Kruchinin 	default:
1584bbaa8b60SDan Kruchinin 		VERIFY(0);
1585bbaa8b60SDan Kruchinin 		return (0);
1586bbaa8b60SDan Kruchinin 	}
1587bbaa8b60SDan Kruchinin 
1588bbaa8b60SDan Kruchinin 	return (SIGN(res));
1589bbaa8b60SDan Kruchinin }
1590bbaa8b60SDan Kruchinin 
1591bbaa8b60SDan Kruchinin /*
1592bbaa8b60SDan Kruchinin  * Compare two nlm hosts.
1593bbaa8b60SDan Kruchinin  * Return values:
1594bbaa8b60SDan Kruchinin  * -1: host1 is "smaller" than host2
1595bbaa8b60SDan Kruchinin  *  0: host1 is equal to host2
1596bbaa8b60SDan Kruchinin  *  1: host1 is "greater" than host2
1597bbaa8b60SDan Kruchinin  */
1598bbaa8b60SDan Kruchinin int
nlm_host_cmp(const void * p1,const void * p2)1599bbaa8b60SDan Kruchinin nlm_host_cmp(const void *p1, const void *p2)
1600bbaa8b60SDan Kruchinin {
1601bbaa8b60SDan Kruchinin 	struct nlm_host *h1 = (struct nlm_host *)p1;
1602bbaa8b60SDan Kruchinin 	struct nlm_host *h2 = (struct nlm_host *)p2;
1603bbaa8b60SDan Kruchinin 	int res;
1604bbaa8b60SDan Kruchinin 
1605bbaa8b60SDan Kruchinin 	res = strcmp(h1->nh_netid, h2->nh_netid);
1606bbaa8b60SDan Kruchinin 	if (res != 0)
1607bbaa8b60SDan Kruchinin 		return (SIGN(res));
1608bbaa8b60SDan Kruchinin 
1609bbaa8b60SDan Kruchinin 	res = nlm_netbuf_addrs_cmp(&h1->nh_addr, &h2->nh_addr);
1610bbaa8b60SDan Kruchinin 	return (res);
1611bbaa8b60SDan Kruchinin }
1612bbaa8b60SDan Kruchinin 
1613bbaa8b60SDan Kruchinin /*
1614bbaa8b60SDan Kruchinin  * Find the host specified by...  (see below)
1615bbaa8b60SDan Kruchinin  * If found, increment the ref count.
1616bbaa8b60SDan Kruchinin  */
1617bbaa8b60SDan Kruchinin static struct nlm_host *
nlm_host_find_locked(struct nlm_globals * g,const char * netid,struct netbuf * naddr,avl_index_t * wherep)1618bbaa8b60SDan Kruchinin nlm_host_find_locked(struct nlm_globals *g, const char *netid,
1619bbaa8b60SDan Kruchinin     struct netbuf *naddr, avl_index_t *wherep)
1620bbaa8b60SDan Kruchinin {
1621bbaa8b60SDan Kruchinin 	struct nlm_host *hostp, key;
1622bbaa8b60SDan Kruchinin 	avl_index_t pos;
1623bbaa8b60SDan Kruchinin 
1624bbaa8b60SDan Kruchinin 	ASSERT(MUTEX_HELD(&g->lock));
1625bbaa8b60SDan Kruchinin 
1626bbaa8b60SDan Kruchinin 	key.nh_netid = (char *)netid;
1627bbaa8b60SDan Kruchinin 	key.nh_addr.buf = naddr->buf;
1628bbaa8b60SDan Kruchinin 	key.nh_addr.len = naddr->len;
1629bbaa8b60SDan Kruchinin 	key.nh_addr.maxlen = naddr->maxlen;
1630bbaa8b60SDan Kruchinin 
1631bbaa8b60SDan Kruchinin 	hostp = avl_find(&g->nlm_hosts_tree, &key, &pos);
1632bbaa8b60SDan Kruchinin 
1633bbaa8b60SDan Kruchinin 	if (hostp != NULL) {
1634bbaa8b60SDan Kruchinin 		/*
1635bbaa8b60SDan Kruchinin 		 * Host is inuse now. Remove it from idle
1636bbaa8b60SDan Kruchinin 		 * hosts list if needed.
1637bbaa8b60SDan Kruchinin 		 */
1638bbaa8b60SDan Kruchinin 		if (hostp->nh_flags & NLM_NH_INIDLE) {
1639bbaa8b60SDan Kruchinin 			TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1640bbaa8b60SDan Kruchinin 			hostp->nh_flags &= ~NLM_NH_INIDLE;
1641bbaa8b60SDan Kruchinin 		}
1642bbaa8b60SDan Kruchinin 
1643bbaa8b60SDan Kruchinin 		hostp->nh_refs++;
1644bbaa8b60SDan Kruchinin 	}
1645bbaa8b60SDan Kruchinin 	if (wherep != NULL)
1646bbaa8b60SDan Kruchinin 		*wherep = pos;
1647bbaa8b60SDan Kruchinin 
1648bbaa8b60SDan Kruchinin 	return (hostp);
1649bbaa8b60SDan Kruchinin }
1650bbaa8b60SDan Kruchinin 
1651bbaa8b60SDan Kruchinin /*
1652bbaa8b60SDan Kruchinin  * Find NLM host for the given name and address.
1653bbaa8b60SDan Kruchinin  */
1654bbaa8b60SDan Kruchinin struct nlm_host *
nlm_host_find(struct nlm_globals * g,const char * netid,struct netbuf * addr)1655bbaa8b60SDan Kruchinin nlm_host_find(struct nlm_globals *g, const char *netid,
1656bbaa8b60SDan Kruchinin     struct netbuf *addr)
1657bbaa8b60SDan Kruchinin {
1658bbaa8b60SDan Kruchinin 	struct nlm_host *hostp = NULL;
1659bbaa8b60SDan Kruchinin 
1660bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
1661bbaa8b60SDan Kruchinin 	if (g->run_status != NLM_ST_UP)
1662bbaa8b60SDan Kruchinin 		goto out;
1663bbaa8b60SDan Kruchinin 
1664bbaa8b60SDan Kruchinin 	hostp = nlm_host_find_locked(g, netid, addr, NULL);
1665bbaa8b60SDan Kruchinin 
1666bbaa8b60SDan Kruchinin out:
1667bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1668bbaa8b60SDan Kruchinin 	return (hostp);
1669bbaa8b60SDan Kruchinin }
1670bbaa8b60SDan Kruchinin 
1671bbaa8b60SDan Kruchinin 
1672bbaa8b60SDan Kruchinin /*
1673bbaa8b60SDan Kruchinin  * Find or create an NLM host for the given name and address.
1674bbaa8b60SDan Kruchinin  *
16756ab697caSMarcel Telka  * The remote host is determined by all of: name, netid, address.
1676bbaa8b60SDan Kruchinin  * Note that the netid is whatever nlm_svc_add_ep() gave to
1677bbaa8b60SDan Kruchinin  * svc_tli_kcreate() for the service binding.  If any of these
1678bbaa8b60SDan Kruchinin  * are different, allocate a new host (new sysid).
1679bbaa8b60SDan Kruchinin  */
1680bbaa8b60SDan Kruchinin struct nlm_host *
nlm_host_findcreate(struct nlm_globals * g,char * name,const char * netid,struct netbuf * addr)1681bbaa8b60SDan Kruchinin nlm_host_findcreate(struct nlm_globals *g, char *name,
1682bbaa8b60SDan Kruchinin     const char *netid, struct netbuf *addr)
1683bbaa8b60SDan Kruchinin {
1684bbaa8b60SDan Kruchinin 	int err;
1685bbaa8b60SDan Kruchinin 	struct nlm_host *host, *newhost = NULL;
1686bbaa8b60SDan Kruchinin 	struct knetconfig knc;
1687bbaa8b60SDan Kruchinin 	avl_index_t where;
1688bbaa8b60SDan Kruchinin 
1689bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
1690bbaa8b60SDan Kruchinin 	if (g->run_status != NLM_ST_UP) {
1691bbaa8b60SDan Kruchinin 		mutex_exit(&g->lock);
1692bbaa8b60SDan Kruchinin 		return (NULL);
1693bbaa8b60SDan Kruchinin 	}
1694bbaa8b60SDan Kruchinin 
1695bbaa8b60SDan Kruchinin 	host = nlm_host_find_locked(g, netid, addr, NULL);
1696bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1697bbaa8b60SDan Kruchinin 	if (host != NULL)
1698bbaa8b60SDan Kruchinin 		return (host);
1699bbaa8b60SDan Kruchinin 
1700bbaa8b60SDan Kruchinin 	err = nlm_knc_from_netid(netid, &knc);
1701bbaa8b60SDan Kruchinin 	if (err != 0)
1702bbaa8b60SDan Kruchinin 		return (NULL);
1703bbaa8b60SDan Kruchinin 	/*
1704bbaa8b60SDan Kruchinin 	 * Do allocations (etc.) outside of mutex,
1705bbaa8b60SDan Kruchinin 	 * and then check again before inserting.
1706bbaa8b60SDan Kruchinin 	 */
1707bbaa8b60SDan Kruchinin 	newhost = nlm_host_create(name, netid, &knc, addr);
1708bbaa8b60SDan Kruchinin 	newhost->nh_sysid = nlm_sysid_alloc();
1709bbaa8b60SDan Kruchinin 	if (newhost->nh_sysid == LM_NOSYSID)
1710bbaa8b60SDan Kruchinin 		goto out;
1711bbaa8b60SDan Kruchinin 
1712bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
1713bbaa8b60SDan Kruchinin 	host = nlm_host_find_locked(g, netid, addr, &where);
1714bbaa8b60SDan Kruchinin 	if (host == NULL) {
1715bbaa8b60SDan Kruchinin 		host = newhost;
1716bbaa8b60SDan Kruchinin 		newhost = NULL;
1717bbaa8b60SDan Kruchinin 
1718bbaa8b60SDan Kruchinin 		/*
1719bbaa8b60SDan Kruchinin 		 * Insert host to the hosts AVL tree that is
1720bbaa8b60SDan Kruchinin 		 * used to lookup by <netid, address> pair.
1721bbaa8b60SDan Kruchinin 		 */
1722bbaa8b60SDan Kruchinin 		avl_insert(&g->nlm_hosts_tree, host, where);
1723bbaa8b60SDan Kruchinin 
1724bbaa8b60SDan Kruchinin 		/*
17256ab697caSMarcel Telka 		 * Insert host to the hosts hash table that is
1726bbaa8b60SDan Kruchinin 		 * used to lookup host by sysid.
1727bbaa8b60SDan Kruchinin 		 */
1728bbaa8b60SDan Kruchinin 		VERIFY(mod_hash_insert(g->nlm_hosts_hash,
1729bbaa8b60SDan Kruchinin 		    (mod_hash_key_t)(uintptr_t)host->nh_sysid,
1730bbaa8b60SDan Kruchinin 		    (mod_hash_val_t)host) == 0);
1731bbaa8b60SDan Kruchinin 	}
1732bbaa8b60SDan Kruchinin 
1733bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1734bbaa8b60SDan Kruchinin 
1735bbaa8b60SDan Kruchinin out:
17366ab697caSMarcel Telka 	if (newhost != NULL) {
17376ab697caSMarcel Telka 		/*
17386ab697caSMarcel Telka 		 * We do not need the preallocated nlm_host
17396ab697caSMarcel Telka 		 * so decrement the reference counter
17406ab697caSMarcel Telka 		 * and destroy it.
17416ab697caSMarcel Telka 		 */
17426ab697caSMarcel Telka 		newhost->nh_refs--;
1743bbaa8b60SDan Kruchinin 		nlm_host_destroy(newhost);
17446ab697caSMarcel Telka 	}
1745bbaa8b60SDan Kruchinin 
1746bbaa8b60SDan Kruchinin 	return (host);
1747bbaa8b60SDan Kruchinin }
1748bbaa8b60SDan Kruchinin 
1749bbaa8b60SDan Kruchinin /*
1750bbaa8b60SDan Kruchinin  * Find the NLM host that matches the value of 'sysid'.
1751bbaa8b60SDan Kruchinin  * If found, return it with a new ref,
1752bbaa8b60SDan Kruchinin  * else return NULL.
1753bbaa8b60SDan Kruchinin  */
1754bbaa8b60SDan Kruchinin struct nlm_host *
nlm_host_find_by_sysid(struct nlm_globals * g,sysid_t sysid)1755bbaa8b60SDan Kruchinin nlm_host_find_by_sysid(struct nlm_globals *g, sysid_t sysid)
1756bbaa8b60SDan Kruchinin {
1757bbaa8b60SDan Kruchinin 	struct nlm_host *hostp = NULL;
1758bbaa8b60SDan Kruchinin 
1759bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
1760bbaa8b60SDan Kruchinin 	if (g->run_status != NLM_ST_UP)
1761bbaa8b60SDan Kruchinin 		goto out;
1762bbaa8b60SDan Kruchinin 
1763bbaa8b60SDan Kruchinin 	(void) mod_hash_find(g->nlm_hosts_hash,
1764bbaa8b60SDan Kruchinin 	    (mod_hash_key_t)(uintptr_t)sysid,
1765bbaa8b60SDan Kruchinin 	    (mod_hash_val_t)&hostp);
1766bbaa8b60SDan Kruchinin 
1767bbaa8b60SDan Kruchinin 	if (hostp == NULL)
1768bbaa8b60SDan Kruchinin 		goto out;
1769bbaa8b60SDan Kruchinin 
1770bbaa8b60SDan Kruchinin 	/*
1771bbaa8b60SDan Kruchinin 	 * Host is inuse now. Remove it
1772bbaa8b60SDan Kruchinin 	 * from idle hosts list if needed.
1773bbaa8b60SDan Kruchinin 	 */
1774bbaa8b60SDan Kruchinin 	if (hostp->nh_flags & NLM_NH_INIDLE) {
1775bbaa8b60SDan Kruchinin 		TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
1776bbaa8b60SDan Kruchinin 		hostp->nh_flags &= ~NLM_NH_INIDLE;
1777bbaa8b60SDan Kruchinin 	}
1778bbaa8b60SDan Kruchinin 
1779bbaa8b60SDan Kruchinin 	hostp->nh_refs++;
1780bbaa8b60SDan Kruchinin 
1781bbaa8b60SDan Kruchinin out:
1782bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1783bbaa8b60SDan Kruchinin 	return (hostp);
1784bbaa8b60SDan Kruchinin }
1785bbaa8b60SDan Kruchinin 
1786bbaa8b60SDan Kruchinin /*
1787bbaa8b60SDan Kruchinin  * Release the given host.
1788bbaa8b60SDan Kruchinin  * I.e. drop a reference that was taken earlier by one of
1789bbaa8b60SDan Kruchinin  * the following functions: nlm_host_findcreate(), nlm_host_find(),
1790bbaa8b60SDan Kruchinin  * nlm_host_find_by_sysid().
1791bbaa8b60SDan Kruchinin  *
1792bbaa8b60SDan Kruchinin  * When the very last reference is dropped, host is moved to
1793bbaa8b60SDan Kruchinin  * so-called "idle state". All hosts that are in idle state
1794bbaa8b60SDan Kruchinin  * have an idle timeout. If timeout is expired, GC thread
1795bbaa8b60SDan Kruchinin  * checks whether hosts have any locks and if they heven't
1796bbaa8b60SDan Kruchinin  * any, it removes them.
1797bbaa8b60SDan Kruchinin  * NOTE: only unused hosts can be in idle state.
1798bbaa8b60SDan Kruchinin  */
1799b2b464a4SMarcel Telka static void
nlm_host_release_locked(struct nlm_globals * g,struct nlm_host * hostp)1800b2b464a4SMarcel Telka nlm_host_release_locked(struct nlm_globals *g, struct nlm_host *hostp)
1801bbaa8b60SDan Kruchinin {
1802bbaa8b60SDan Kruchinin 	if (hostp == NULL)
1803bbaa8b60SDan Kruchinin 		return;
1804bbaa8b60SDan Kruchinin 
1805b2b464a4SMarcel Telka 	ASSERT(MUTEX_HELD(&g->lock));
1806bbaa8b60SDan Kruchinin 	ASSERT(hostp->nh_refs > 0);
1807bbaa8b60SDan Kruchinin 
1808bbaa8b60SDan Kruchinin 	hostp->nh_refs--;
1809b2b464a4SMarcel Telka 	if (hostp->nh_refs != 0)
1810bbaa8b60SDan Kruchinin 		return;
1811bbaa8b60SDan Kruchinin 
1812bbaa8b60SDan Kruchinin 	/*
1813bbaa8b60SDan Kruchinin 	 * The very last reference to the host was dropped,
1814bbaa8b60SDan Kruchinin 	 * thus host is unused now. Set its idle timeout
1815bbaa8b60SDan Kruchinin 	 * and move it to the idle hosts LRU list.
1816bbaa8b60SDan Kruchinin 	 */
1817bbaa8b60SDan Kruchinin 	hostp->nh_idle_timeout = ddi_get_lbolt() +
1818bbaa8b60SDan Kruchinin 	    SEC_TO_TICK(g->cn_idle_tmo);
1819bbaa8b60SDan Kruchinin 
1820bbaa8b60SDan Kruchinin 	ASSERT((hostp->nh_flags & NLM_NH_INIDLE) == 0);
1821bbaa8b60SDan Kruchinin 	TAILQ_INSERT_TAIL(&g->nlm_idle_hosts, hostp, nh_link);
1822bbaa8b60SDan Kruchinin 	hostp->nh_flags |= NLM_NH_INIDLE;
1823b2b464a4SMarcel Telka }
1824b2b464a4SMarcel Telka 
1825b2b464a4SMarcel Telka void
nlm_host_release(struct nlm_globals * g,struct nlm_host * hostp)1826b2b464a4SMarcel Telka nlm_host_release(struct nlm_globals *g, struct nlm_host *hostp)
1827b2b464a4SMarcel Telka {
1828b2b464a4SMarcel Telka 	if (hostp == NULL)
1829b2b464a4SMarcel Telka 		return;
1830b2b464a4SMarcel Telka 
1831b2b464a4SMarcel Telka 	mutex_enter(&g->lock);
1832b2b464a4SMarcel Telka 	nlm_host_release_locked(g, hostp);
1833bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1834bbaa8b60SDan Kruchinin }
1835bbaa8b60SDan Kruchinin 
1836bbaa8b60SDan Kruchinin /*
1837bbaa8b60SDan Kruchinin  * Unregister this NLM host (NFS client) with the local statd
1838bbaa8b60SDan Kruchinin  * due to idleness (no locks held for a while).
1839bbaa8b60SDan Kruchinin  */
1840bbaa8b60SDan Kruchinin void
nlm_host_unmonitor(struct nlm_globals * g,struct nlm_host * host)1841bbaa8b60SDan Kruchinin nlm_host_unmonitor(struct nlm_globals *g, struct nlm_host *host)
1842bbaa8b60SDan Kruchinin {
1843bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
1844bbaa8b60SDan Kruchinin 
1845bbaa8b60SDan Kruchinin 	VERIFY(host->nh_refs == 0);
1846bbaa8b60SDan Kruchinin 	if (!(host->nh_flags & NLM_NH_MONITORED))
1847bbaa8b60SDan Kruchinin 		return;
1848bbaa8b60SDan Kruchinin 
1849bbaa8b60SDan Kruchinin 	host->nh_flags &= ~NLM_NH_MONITORED;
1850bbaa8b60SDan Kruchinin 	stat = nlm_nsm_unmon(&g->nlm_nsm, host->nh_name);
1851bbaa8b60SDan Kruchinin 	if (stat != RPC_SUCCESS) {
1852bbaa8b60SDan Kruchinin 		NLM_WARN("NLM: Failed to contact statd, stat=%d\n", stat);
1853bbaa8b60SDan Kruchinin 		return;
1854bbaa8b60SDan Kruchinin 	}
1855bbaa8b60SDan Kruchinin }
1856bbaa8b60SDan Kruchinin 
1857bbaa8b60SDan Kruchinin /*
1858bbaa8b60SDan Kruchinin  * Ask the local NFS statd to begin monitoring this host.
1859bbaa8b60SDan Kruchinin  * It will call us back when that host restarts, using the
1860bbaa8b60SDan Kruchinin  * prog,vers,proc specified below, i.e. NLM_SM_NOTIFY1,
1861bbaa8b60SDan Kruchinin  * which is handled in nlm_do_notify1().
1862bbaa8b60SDan Kruchinin  */
1863bbaa8b60SDan Kruchinin void
nlm_host_monitor(struct nlm_globals * g,struct nlm_host * host,int state)1864bbaa8b60SDan Kruchinin nlm_host_monitor(struct nlm_globals *g, struct nlm_host *host, int state)
1865bbaa8b60SDan Kruchinin {
1866bbaa8b60SDan Kruchinin 	int family;
1867bbaa8b60SDan Kruchinin 	netobj obj;
1868bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
1869bbaa8b60SDan Kruchinin 
1870bbaa8b60SDan Kruchinin 	if (state != 0 && host->nh_state == 0) {
1871bbaa8b60SDan Kruchinin 		/*
1872bbaa8b60SDan Kruchinin 		 * This is the first time we have seen an NSM state
1873bbaa8b60SDan Kruchinin 		 * Value for this host. We record it here to help
1874bbaa8b60SDan Kruchinin 		 * detect host reboots.
1875bbaa8b60SDan Kruchinin 		 */
1876bbaa8b60SDan Kruchinin 		host->nh_state = state;
1877bbaa8b60SDan Kruchinin 	}
1878bbaa8b60SDan Kruchinin 
1879bbaa8b60SDan Kruchinin 	mutex_enter(&host->nh_lock);
1880bbaa8b60SDan Kruchinin 	if (host->nh_flags & NLM_NH_MONITORED) {
1881bbaa8b60SDan Kruchinin 		mutex_exit(&host->nh_lock);
1882bbaa8b60SDan Kruchinin 		return;
1883bbaa8b60SDan Kruchinin 	}
1884bbaa8b60SDan Kruchinin 
1885bbaa8b60SDan Kruchinin 	host->nh_flags |= NLM_NH_MONITORED;
1886bbaa8b60SDan Kruchinin 	mutex_exit(&host->nh_lock);
1887bbaa8b60SDan Kruchinin 
1888bbaa8b60SDan Kruchinin 	/*
1889bbaa8b60SDan Kruchinin 	 * Before we begin monitoring the host register the network address
1890bbaa8b60SDan Kruchinin 	 * associated with this hostname.
1891bbaa8b60SDan Kruchinin 	 */
1892bbaa8b60SDan Kruchinin 	nlm_netbuf_to_netobj(&host->nh_addr, &family, &obj);
1893bbaa8b60SDan Kruchinin 	stat = nlm_nsmaddr_reg(&g->nlm_nsm, host->nh_name, family, &obj);
1894bbaa8b60SDan Kruchinin 	if (stat != RPC_SUCCESS) {
1895bbaa8b60SDan Kruchinin 		NLM_WARN("Failed to register address, stat=%d\n", stat);
1896bbaa8b60SDan Kruchinin 		mutex_enter(&g->lock);
1897bbaa8b60SDan Kruchinin 		host->nh_flags &= ~NLM_NH_MONITORED;
1898bbaa8b60SDan Kruchinin 		mutex_exit(&g->lock);
1899bbaa8b60SDan Kruchinin 
1900bbaa8b60SDan Kruchinin 		return;
1901bbaa8b60SDan Kruchinin 	}
1902bbaa8b60SDan Kruchinin 
1903bbaa8b60SDan Kruchinin 	/*
1904bbaa8b60SDan Kruchinin 	 * Tell statd how to call us with status updates for
1905bbaa8b60SDan Kruchinin 	 * this host. Updates arrive via nlm_do_notify1().
1906bbaa8b60SDan Kruchinin 	 *
1907bbaa8b60SDan Kruchinin 	 * We put our assigned system ID value in the priv field to
1908bbaa8b60SDan Kruchinin 	 * make it simpler to find the host if we are notified of a
1909bbaa8b60SDan Kruchinin 	 * host restart.
1910bbaa8b60SDan Kruchinin 	 */
1911bbaa8b60SDan Kruchinin 	stat = nlm_nsm_mon(&g->nlm_nsm, host->nh_name, host->nh_sysid);
1912bbaa8b60SDan Kruchinin 	if (stat != RPC_SUCCESS) {
1913bbaa8b60SDan Kruchinin 		NLM_WARN("Failed to contact local NSM, stat=%d\n", stat);
1914bbaa8b60SDan Kruchinin 		mutex_enter(&g->lock);
1915bbaa8b60SDan Kruchinin 		host->nh_flags &= ~NLM_NH_MONITORED;
1916bbaa8b60SDan Kruchinin 		mutex_exit(&g->lock);
1917bbaa8b60SDan Kruchinin 
1918bbaa8b60SDan Kruchinin 		return;
1919bbaa8b60SDan Kruchinin 	}
1920bbaa8b60SDan Kruchinin }
1921bbaa8b60SDan Kruchinin 
1922bbaa8b60SDan Kruchinin int
nlm_host_get_state(struct nlm_host * hostp)1923bbaa8b60SDan Kruchinin nlm_host_get_state(struct nlm_host *hostp)
1924bbaa8b60SDan Kruchinin {
1925bbaa8b60SDan Kruchinin 
1926bbaa8b60SDan Kruchinin 	return (hostp->nh_state);
1927bbaa8b60SDan Kruchinin }
1928bbaa8b60SDan Kruchinin 
1929bbaa8b60SDan Kruchinin /*
1930bbaa8b60SDan Kruchinin  * NLM client/server sleeping locks
1931bbaa8b60SDan Kruchinin  */
1932bbaa8b60SDan Kruchinin 
1933bbaa8b60SDan Kruchinin /*
1934bbaa8b60SDan Kruchinin  * Register client side sleeping lock.
1935bbaa8b60SDan Kruchinin  *
1936bbaa8b60SDan Kruchinin  * Our client code calls this to keep information
1937bbaa8b60SDan Kruchinin  * about sleeping lock somewhere. When it receives
1938bbaa8b60SDan Kruchinin  * grant callback from server or when it just
1939bbaa8b60SDan Kruchinin  * needs to remove all sleeping locks from vnode,
1940bbaa8b60SDan Kruchinin  * it uses this information for remove/apply lock
1941bbaa8b60SDan Kruchinin  * properly.
1942bbaa8b60SDan Kruchinin  */
1943bbaa8b60SDan Kruchinin struct nlm_slock *
nlm_slock_register(struct nlm_globals * g,struct nlm_host * host,struct nlm4_lock * lock,struct vnode * vp)1944bbaa8b60SDan Kruchinin nlm_slock_register(
1945bbaa8b60SDan Kruchinin 	struct nlm_globals *g,
1946bbaa8b60SDan Kruchinin 	struct nlm_host *host,
1947bbaa8b60SDan Kruchinin 	struct nlm4_lock *lock,
1948bbaa8b60SDan Kruchinin 	struct vnode *vp)
1949bbaa8b60SDan Kruchinin {
1950bbaa8b60SDan Kruchinin 	struct nlm_slock *nslp;
1951bbaa8b60SDan Kruchinin 
1952bbaa8b60SDan Kruchinin 	nslp = kmem_zalloc(sizeof (*nslp), KM_SLEEP);
1953bbaa8b60SDan Kruchinin 	cv_init(&nslp->nsl_cond, NULL, CV_DEFAULT, NULL);
1954bbaa8b60SDan Kruchinin 	nslp->nsl_lock = *lock;
1955bbaa8b60SDan Kruchinin 	nlm_copy_netobj(&nslp->nsl_fh, &nslp->nsl_lock.fh);
1956bbaa8b60SDan Kruchinin 	nslp->nsl_state = NLM_SL_BLOCKED;
1957bbaa8b60SDan Kruchinin 	nslp->nsl_host = host;
1958bbaa8b60SDan Kruchinin 	nslp->nsl_vp = vp;
1959bbaa8b60SDan Kruchinin 
1960bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
1961bbaa8b60SDan Kruchinin 	TAILQ_INSERT_TAIL(&g->nlm_slocks, nslp, nsl_link);
1962bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1963bbaa8b60SDan Kruchinin 
1964bbaa8b60SDan Kruchinin 	return (nslp);
1965bbaa8b60SDan Kruchinin }
1966bbaa8b60SDan Kruchinin 
1967bbaa8b60SDan Kruchinin /*
1968bbaa8b60SDan Kruchinin  * Remove this lock from the wait list and destroy it.
1969bbaa8b60SDan Kruchinin  */
1970bbaa8b60SDan Kruchinin void
nlm_slock_unregister(struct nlm_globals * g,struct nlm_slock * nslp)1971bbaa8b60SDan Kruchinin nlm_slock_unregister(struct nlm_globals *g, struct nlm_slock *nslp)
1972bbaa8b60SDan Kruchinin {
1973bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
1974bbaa8b60SDan Kruchinin 	TAILQ_REMOVE(&g->nlm_slocks, nslp, nsl_link);
1975bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1976bbaa8b60SDan Kruchinin 
1977bbaa8b60SDan Kruchinin 	kmem_free(nslp->nsl_fh.n_bytes, nslp->nsl_fh.n_len);
1978bbaa8b60SDan Kruchinin 	cv_destroy(&nslp->nsl_cond);
1979bbaa8b60SDan Kruchinin 	kmem_free(nslp, sizeof (*nslp));
1980bbaa8b60SDan Kruchinin }
1981bbaa8b60SDan Kruchinin 
1982bbaa8b60SDan Kruchinin /*
1983bbaa8b60SDan Kruchinin  * Wait for a granted callback or cancellation event
1984bbaa8b60SDan Kruchinin  * for a sleeping lock.
1985bbaa8b60SDan Kruchinin  *
1986bbaa8b60SDan Kruchinin  * If a signal interrupted the wait or if the lock
1987bbaa8b60SDan Kruchinin  * was cancelled, return EINTR - the caller must arrange to send
1988bbaa8b60SDan Kruchinin  * a cancellation to the server.
1989bbaa8b60SDan Kruchinin  *
1990bbaa8b60SDan Kruchinin  * If timeout occurred, return ETIMEDOUT - the caller must
1991bbaa8b60SDan Kruchinin  * resend the lock request to the server.
1992bbaa8b60SDan Kruchinin  *
1993bbaa8b60SDan Kruchinin  * On success return 0.
1994bbaa8b60SDan Kruchinin  */
1995bbaa8b60SDan Kruchinin int
nlm_slock_wait(struct nlm_globals * g,struct nlm_slock * nslp,uint_t timeo_secs)1996bbaa8b60SDan Kruchinin nlm_slock_wait(struct nlm_globals *g,
1997bbaa8b60SDan Kruchinin     struct nlm_slock *nslp, uint_t timeo_secs)
1998bbaa8b60SDan Kruchinin {
1999bbaa8b60SDan Kruchinin 	clock_t timeo_ticks;
2000bbaa8b60SDan Kruchinin 	int cv_res, error;
2001bbaa8b60SDan Kruchinin 
2002bbaa8b60SDan Kruchinin 	/*
2003bbaa8b60SDan Kruchinin 	 * If the granted message arrived before we got here,
200495fa5714SMarcel Telka 	 * nslp->nsl_state will be NLM_SL_GRANTED - in that case don't sleep.
2005bbaa8b60SDan Kruchinin 	 */
2006bbaa8b60SDan Kruchinin 	cv_res = 1;
2007bbaa8b60SDan Kruchinin 	timeo_ticks = ddi_get_lbolt() + SEC_TO_TICK(timeo_secs);
2008bbaa8b60SDan Kruchinin 
2009bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
201095fa5714SMarcel Telka 	while (nslp->nsl_state == NLM_SL_BLOCKED && cv_res > 0) {
2011bbaa8b60SDan Kruchinin 		cv_res = cv_timedwait_sig(&nslp->nsl_cond,
2012bbaa8b60SDan Kruchinin 		    &g->lock, timeo_ticks);
2013bbaa8b60SDan Kruchinin 	}
2014bbaa8b60SDan Kruchinin 
2015bbaa8b60SDan Kruchinin 	/*
2016bbaa8b60SDan Kruchinin 	 * No matter why we wake up, if the lock was
2017bbaa8b60SDan Kruchinin 	 * cancelled, let the function caller to know
2018bbaa8b60SDan Kruchinin 	 * about it by returning EINTR.
2019bbaa8b60SDan Kruchinin 	 */
2020bbaa8b60SDan Kruchinin 	if (nslp->nsl_state == NLM_SL_CANCELLED) {
2021bbaa8b60SDan Kruchinin 		error = EINTR;
2022bbaa8b60SDan Kruchinin 		goto out;
2023bbaa8b60SDan Kruchinin 	}
2024bbaa8b60SDan Kruchinin 
2025bbaa8b60SDan Kruchinin 	if (cv_res <= 0) {
202695fa5714SMarcel Telka 		/* We were woken up either by timeout or by interrupt */
2027bbaa8b60SDan Kruchinin 		error = (cv_res < 0) ? ETIMEDOUT : EINTR;
2028bbaa8b60SDan Kruchinin 
2029bbaa8b60SDan Kruchinin 		/*
2030bbaa8b60SDan Kruchinin 		 * The granted message may arrive after the
2031bbaa8b60SDan Kruchinin 		 * interrupt/timeout but before we manage to lock the
2032bbaa8b60SDan Kruchinin 		 * mutex. Detect this by examining nslp.
2033bbaa8b60SDan Kruchinin 		 */
2034bbaa8b60SDan Kruchinin 		if (nslp->nsl_state == NLM_SL_GRANTED)
2035bbaa8b60SDan Kruchinin 			error = 0;
203695fa5714SMarcel Telka 	} else { /* Awaken via cv_signal()/cv_broadcast() or didn't block */
2037bbaa8b60SDan Kruchinin 		error = 0;
2038bbaa8b60SDan Kruchinin 		VERIFY(nslp->nsl_state == NLM_SL_GRANTED);
2039bbaa8b60SDan Kruchinin 	}
2040bbaa8b60SDan Kruchinin 
2041bbaa8b60SDan Kruchinin out:
2042bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
2043bbaa8b60SDan Kruchinin 	return (error);
2044bbaa8b60SDan Kruchinin }
2045bbaa8b60SDan Kruchinin 
2046bbaa8b60SDan Kruchinin /*
2047bbaa8b60SDan Kruchinin  * Mark client side sleeping lock as granted
2048bbaa8b60SDan Kruchinin  * and wake up a process blocked on the lock.
2049bbaa8b60SDan Kruchinin  * Called from server side NLM_GRANT handler.
2050bbaa8b60SDan Kruchinin  *
2051bbaa8b60SDan Kruchinin  * If sleeping lock is found return 0, otherwise
2052bbaa8b60SDan Kruchinin  * return ENOENT.
2053bbaa8b60SDan Kruchinin  */
2054bbaa8b60SDan Kruchinin int
nlm_slock_grant(struct nlm_globals * g,struct nlm_host * hostp,struct nlm4_lock * alock)2055bbaa8b60SDan Kruchinin nlm_slock_grant(struct nlm_globals *g,
2056bbaa8b60SDan Kruchinin     struct nlm_host *hostp, struct nlm4_lock *alock)
2057bbaa8b60SDan Kruchinin {
2058bbaa8b60SDan Kruchinin 	struct nlm_slock *nslp;
2059bbaa8b60SDan Kruchinin 	int error = ENOENT;
2060bbaa8b60SDan Kruchinin 
2061bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
2062bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) {
2063bbaa8b60SDan Kruchinin 		if ((nslp->nsl_state != NLM_SL_BLOCKED) ||
2064bbaa8b60SDan Kruchinin 		    (nslp->nsl_host != hostp))
2065bbaa8b60SDan Kruchinin 			continue;
2066bbaa8b60SDan Kruchinin 
2067bbaa8b60SDan Kruchinin 		if (alock->svid		== nslp->nsl_lock.svid &&
2068bbaa8b60SDan Kruchinin 		    alock->l_offset	== nslp->nsl_lock.l_offset &&
2069bbaa8b60SDan Kruchinin 		    alock->l_len	== nslp->nsl_lock.l_len &&
2070bbaa8b60SDan Kruchinin 		    alock->fh.n_len	== nslp->nsl_lock.fh.n_len &&
2071bbaa8b60SDan Kruchinin 		    bcmp(alock->fh.n_bytes, nslp->nsl_lock.fh.n_bytes,
2072bbaa8b60SDan Kruchinin 		    nslp->nsl_lock.fh.n_len) == 0) {
2073bbaa8b60SDan Kruchinin 			nslp->nsl_state = NLM_SL_GRANTED;
2074bbaa8b60SDan Kruchinin 			cv_broadcast(&nslp->nsl_cond);
2075bbaa8b60SDan Kruchinin 			error = 0;
2076bbaa8b60SDan Kruchinin 			break;
2077bbaa8b60SDan Kruchinin 		}
2078bbaa8b60SDan Kruchinin 	}
2079bbaa8b60SDan Kruchinin 
2080bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
2081bbaa8b60SDan Kruchinin 	return (error);
2082bbaa8b60SDan Kruchinin }
2083bbaa8b60SDan Kruchinin 
2084bbaa8b60SDan Kruchinin /*
2085bbaa8b60SDan Kruchinin  * Register sleeping lock request corresponding to
2086bbaa8b60SDan Kruchinin  * flp on the given vhold object.
2087bbaa8b60SDan Kruchinin  * On success function returns 0, otherwise (if
2088bbaa8b60SDan Kruchinin  * lock request with the same flp is already
2089bbaa8b60SDan Kruchinin  * registered) function returns EEXIST.
2090bbaa8b60SDan Kruchinin  */
2091bbaa8b60SDan Kruchinin int
nlm_slreq_register(struct nlm_host * hostp,struct nlm_vhold * nvp,struct flock64 * flp)2092bbaa8b60SDan Kruchinin nlm_slreq_register(struct nlm_host *hostp, struct nlm_vhold *nvp,
2093b2b464a4SMarcel Telka     struct flock64 *flp)
2094bbaa8b60SDan Kruchinin {
2095bbaa8b60SDan Kruchinin 	struct nlm_slreq *slr, *new_slr = NULL;
2096bbaa8b60SDan Kruchinin 	int ret = EEXIST;
2097bbaa8b60SDan Kruchinin 
2098bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
2099bbaa8b60SDan Kruchinin 	slr = nlm_slreq_find_locked(hostp, nvp, flp);
2100bbaa8b60SDan Kruchinin 	if (slr != NULL)
2101bbaa8b60SDan Kruchinin 		goto out;
2102bbaa8b60SDan Kruchinin 
2103bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
2104bbaa8b60SDan Kruchinin 	new_slr = kmem_zalloc(sizeof (*slr), KM_SLEEP);
2105bbaa8b60SDan Kruchinin 	bcopy(flp, &new_slr->nsr_fl, sizeof (*flp));
2106bbaa8b60SDan Kruchinin 
2107bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
2108bbaa8b60SDan Kruchinin 	slr = nlm_slreq_find_locked(hostp, nvp, flp);
2109bbaa8b60SDan Kruchinin 	if (slr == NULL) {
2110bbaa8b60SDan Kruchinin 		slr = new_slr;
2111bbaa8b60SDan Kruchinin 		new_slr = NULL;
2112bbaa8b60SDan Kruchinin 		ret = 0;
2113bbaa8b60SDan Kruchinin 
2114bbaa8b60SDan Kruchinin 		TAILQ_INSERT_TAIL(&nvp->nv_slreqs, slr, nsr_link);
2115bbaa8b60SDan Kruchinin 	}
2116bbaa8b60SDan Kruchinin 
2117bbaa8b60SDan Kruchinin out:
2118bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
2119bbaa8b60SDan Kruchinin 	if (new_slr != NULL)
2120bbaa8b60SDan Kruchinin 		kmem_free(new_slr, sizeof (*new_slr));
2121bbaa8b60SDan Kruchinin 
2122bbaa8b60SDan Kruchinin 	return (ret);
2123bbaa8b60SDan Kruchinin }
2124bbaa8b60SDan Kruchinin 
2125bbaa8b60SDan Kruchinin /*
2126bbaa8b60SDan Kruchinin  * Unregister sleeping lock request corresponding
2127bbaa8b60SDan Kruchinin  * to flp from the given vhold object.
2128bbaa8b60SDan Kruchinin  * On success function returns 0, otherwise (if
2129bbaa8b60SDan Kruchinin  * lock request corresponding to flp isn't found
2130bbaa8b60SDan Kruchinin  * on the given vhold) function returns ENOENT.
2131bbaa8b60SDan Kruchinin  */
2132bbaa8b60SDan Kruchinin int
nlm_slreq_unregister(struct nlm_host * hostp,struct nlm_vhold * nvp,struct flock64 * flp)2133bbaa8b60SDan Kruchinin nlm_slreq_unregister(struct nlm_host *hostp, struct nlm_vhold *nvp,
2134b2b464a4SMarcel Telka     struct flock64 *flp)
2135bbaa8b60SDan Kruchinin {
2136bbaa8b60SDan Kruchinin 	struct nlm_slreq *slr;
2137bbaa8b60SDan Kruchinin 
2138bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
2139bbaa8b60SDan Kruchinin 	slr = nlm_slreq_find_locked(hostp, nvp, flp);
2140bbaa8b60SDan Kruchinin 	if (slr == NULL) {
2141bbaa8b60SDan Kruchinin 		mutex_exit(&hostp->nh_lock);
2142bbaa8b60SDan Kruchinin 		return (ENOENT);
2143bbaa8b60SDan Kruchinin 	}
2144bbaa8b60SDan Kruchinin 
2145bbaa8b60SDan Kruchinin 	TAILQ_REMOVE(&nvp->nv_slreqs, slr, nsr_link);
2146bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
2147bbaa8b60SDan Kruchinin 
2148bbaa8b60SDan Kruchinin 	kmem_free(slr, sizeof (*slr));
2149bbaa8b60SDan Kruchinin 	return (0);
2150bbaa8b60SDan Kruchinin }
2151bbaa8b60SDan Kruchinin 
2152bbaa8b60SDan Kruchinin /*
2153bbaa8b60SDan Kruchinin  * Find sleeping lock request on the given vhold object by flp.
2154bbaa8b60SDan Kruchinin  */
2155bbaa8b60SDan Kruchinin struct nlm_slreq *
nlm_slreq_find_locked(struct nlm_host * hostp,struct nlm_vhold * nvp,struct flock64 * flp)2156bbaa8b60SDan Kruchinin nlm_slreq_find_locked(struct nlm_host *hostp, struct nlm_vhold *nvp,
2157bbaa8b60SDan Kruchinin     struct flock64 *flp)
2158bbaa8b60SDan Kruchinin {
2159bbaa8b60SDan Kruchinin 	struct nlm_slreq *slr = NULL;
2160bbaa8b60SDan Kruchinin 
2161bbaa8b60SDan Kruchinin 	ASSERT(MUTEX_HELD(&hostp->nh_lock));
2162bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(slr, &nvp->nv_slreqs, nsr_link) {
2163bbaa8b60SDan Kruchinin 		if (slr->nsr_fl.l_start		== flp->l_start	&&
2164bbaa8b60SDan Kruchinin 		    slr->nsr_fl.l_len		== flp->l_len	&&
2165bbaa8b60SDan Kruchinin 		    slr->nsr_fl.l_pid		== flp->l_pid	&&
2166bbaa8b60SDan Kruchinin 		    slr->nsr_fl.l_type		== flp->l_type)
2167bbaa8b60SDan Kruchinin 			break;
2168bbaa8b60SDan Kruchinin 	}
2169bbaa8b60SDan Kruchinin 
2170bbaa8b60SDan Kruchinin 	return (slr);
2171bbaa8b60SDan Kruchinin }
2172bbaa8b60SDan Kruchinin 
2173bbaa8b60SDan Kruchinin /*
2174bbaa8b60SDan Kruchinin  * NLM tracks active share reservations made on the client side.
2175bbaa8b60SDan Kruchinin  * It needs to have a track of share reservations for two purposes
2176bbaa8b60SDan Kruchinin  * 1) to determine if nlm_host is busy (if it has active locks and/or
2177bbaa8b60SDan Kruchinin  *    share reservations, it is)
2178bbaa8b60SDan Kruchinin  * 2) to recover active share reservations when NLM server reports
2179bbaa8b60SDan Kruchinin  *    that it has rebooted.
2180bbaa8b60SDan Kruchinin  *
2181bbaa8b60SDan Kruchinin  * Unfortunately Illumos local share reservations manager (see os/share.c)
2182bbaa8b60SDan Kruchinin  * doesn't have an ability to lookup all reservations on the system
2183bbaa8b60SDan Kruchinin  * by sysid (like local lock manager) or get all reservations by sysid.
2184bbaa8b60SDan Kruchinin  * It tracks reservations per vnode and is able to get/looup them
2185bbaa8b60SDan Kruchinin  * on particular vnode. It's not what NLM needs. Thus it has that ugly
2186bbaa8b60SDan Kruchinin  * share reservations tracking scheme.
2187bbaa8b60SDan Kruchinin  */
2188bbaa8b60SDan Kruchinin 
2189bbaa8b60SDan Kruchinin void
nlm_shres_track(struct nlm_host * hostp,vnode_t * vp,struct shrlock * shrp)2190bbaa8b60SDan Kruchinin nlm_shres_track(struct nlm_host *hostp, vnode_t *vp, struct shrlock *shrp)
2191bbaa8b60SDan Kruchinin {
2192bbaa8b60SDan Kruchinin 	struct nlm_shres *nsp, *nsp_new;
2193bbaa8b60SDan Kruchinin 
2194bbaa8b60SDan Kruchinin 	/*
2195bbaa8b60SDan Kruchinin 	 * NFS code must fill the s_owner, so that
2196bbaa8b60SDan Kruchinin 	 * s_own_len is never 0.
2197bbaa8b60SDan Kruchinin 	 */
2198bbaa8b60SDan Kruchinin 	ASSERT(shrp->s_own_len > 0);
2199bbaa8b60SDan Kruchinin 	nsp_new = nlm_shres_create_item(shrp, vp);
2200bbaa8b60SDan Kruchinin 
2201bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
2202bbaa8b60SDan Kruchinin 	for (nsp = hostp->nh_shrlist; nsp != NULL; nsp = nsp->ns_next)
2203bbaa8b60SDan Kruchinin 		if (nsp->ns_vp == vp && nlm_shres_equal(shrp, nsp->ns_shr))
2204bbaa8b60SDan Kruchinin 			break;
2205bbaa8b60SDan Kruchinin 
2206bbaa8b60SDan Kruchinin 	if (nsp != NULL) {
2207bbaa8b60SDan Kruchinin 		/*
2208bbaa8b60SDan Kruchinin 		 * Found a duplicate. Do nothing.
2209bbaa8b60SDan Kruchinin 		 */
2210bbaa8b60SDan Kruchinin 
2211bbaa8b60SDan Kruchinin 		goto out;
2212bbaa8b60SDan Kruchinin 	}
2213bbaa8b60SDan Kruchinin 
2214bbaa8b60SDan Kruchinin 	nsp = nsp_new;
2215bbaa8b60SDan Kruchinin 	nsp_new = NULL;
2216bbaa8b60SDan Kruchinin 	nsp->ns_next = hostp->nh_shrlist;
2217bbaa8b60SDan Kruchinin 	hostp->nh_shrlist = nsp;
2218bbaa8b60SDan Kruchinin 
2219bbaa8b60SDan Kruchinin out:
2220bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
2221bbaa8b60SDan Kruchinin 	if (nsp_new != NULL)
2222bbaa8b60SDan Kruchinin 		nlm_shres_destroy_item(nsp_new);
2223bbaa8b60SDan Kruchinin }
2224bbaa8b60SDan Kruchinin 
2225bbaa8b60SDan Kruchinin void
nlm_shres_untrack(struct nlm_host * hostp,vnode_t * vp,struct shrlock * shrp)2226bbaa8b60SDan Kruchinin nlm_shres_untrack(struct nlm_host *hostp, vnode_t *vp, struct shrlock *shrp)
2227bbaa8b60SDan Kruchinin {
2228bbaa8b60SDan Kruchinin 	struct nlm_shres *nsp, *nsp_prev = NULL;
2229bbaa8b60SDan Kruchinin 
2230bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
2231bbaa8b60SDan Kruchinin 	nsp = hostp->nh_shrlist;
2232bbaa8b60SDan Kruchinin 	while (nsp != NULL) {
2233bbaa8b60SDan Kruchinin 		if (nsp->ns_vp == vp && nlm_shres_equal(shrp, nsp->ns_shr)) {
2234bbaa8b60SDan Kruchinin 			struct nlm_shres *nsp_del;
2235bbaa8b60SDan Kruchinin 
2236bbaa8b60SDan Kruchinin 			nsp_del = nsp;
2237bbaa8b60SDan Kruchinin 			nsp = nsp->ns_next;
2238bbaa8b60SDan Kruchinin 			if (nsp_prev != NULL)
2239bbaa8b60SDan Kruchinin 				nsp_prev->ns_next = nsp;
2240bbaa8b60SDan Kruchinin 			else
2241bbaa8b60SDan Kruchinin 				hostp->nh_shrlist = nsp;
2242bbaa8b60SDan Kruchinin 
2243bbaa8b60SDan Kruchinin 			nlm_shres_destroy_item(nsp_del);
2244bbaa8b60SDan Kruchinin 			continue;
2245bbaa8b60SDan Kruchinin 		}
2246bbaa8b60SDan Kruchinin 
2247bbaa8b60SDan Kruchinin 		nsp_prev = nsp;
2248bbaa8b60SDan Kruchinin 		nsp = nsp->ns_next;
2249bbaa8b60SDan Kruchinin 	}
2250bbaa8b60SDan Kruchinin 
2251bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
2252bbaa8b60SDan Kruchinin }
2253bbaa8b60SDan Kruchinin 
2254bbaa8b60SDan Kruchinin /*
2255bbaa8b60SDan Kruchinin  * Get a _copy_ of the list of all active share reservations
2256bbaa8b60SDan Kruchinin  * made by the given host.
2257bbaa8b60SDan Kruchinin  * NOTE: the list function returns _must_ be released using
2258bbaa8b60SDan Kruchinin  *       nlm_free_shrlist().
2259bbaa8b60SDan Kruchinin  */
2260bbaa8b60SDan Kruchinin struct nlm_shres *
nlm_get_active_shres(struct nlm_host * hostp)2261bbaa8b60SDan Kruchinin nlm_get_active_shres(struct nlm_host *hostp)
2262bbaa8b60SDan Kruchinin {
2263bbaa8b60SDan Kruchinin 	struct nlm_shres *nsp, *nslist = NULL;
2264bbaa8b60SDan Kruchinin 
2265bbaa8b60SDan Kruchinin 	mutex_enter(&hostp->nh_lock);
2266bbaa8b60SDan Kruchinin 	for (nsp = hostp->nh_shrlist; nsp != NULL; nsp = nsp->ns_next) {
2267bbaa8b60SDan Kruchinin 		struct nlm_shres *nsp_new;
2268bbaa8b60SDan Kruchinin 
2269bbaa8b60SDan Kruchinin 		nsp_new = nlm_shres_create_item(nsp->ns_shr, nsp->ns_vp);
2270bbaa8b60SDan Kruchinin 		nsp_new->ns_next = nslist;
2271bbaa8b60SDan Kruchinin 		nslist = nsp_new;
2272bbaa8b60SDan Kruchinin 	}
2273bbaa8b60SDan Kruchinin 
2274bbaa8b60SDan Kruchinin 	mutex_exit(&hostp->nh_lock);
2275bbaa8b60SDan Kruchinin 	return (nslist);
2276bbaa8b60SDan Kruchinin }
2277bbaa8b60SDan Kruchinin 
2278bbaa8b60SDan Kruchinin /*
2279bbaa8b60SDan Kruchinin  * Free memory allocated for the active share reservations
2280bbaa8b60SDan Kruchinin  * list created by nlm_get_active_shres() function.
2281bbaa8b60SDan Kruchinin  */
2282bbaa8b60SDan Kruchinin void
nlm_free_shrlist(struct nlm_shres * nslist)2283bbaa8b60SDan Kruchinin nlm_free_shrlist(struct nlm_shres *nslist)
2284bbaa8b60SDan Kruchinin {
2285bbaa8b60SDan Kruchinin 	struct nlm_shres *nsp;
2286bbaa8b60SDan Kruchinin 
2287bbaa8b60SDan Kruchinin 	while (nslist != NULL) {
2288bbaa8b60SDan Kruchinin 		nsp =  nslist;
2289bbaa8b60SDan Kruchinin 		nslist = nslist->ns_next;
2290bbaa8b60SDan Kruchinin 
2291bbaa8b60SDan Kruchinin 		nlm_shres_destroy_item(nsp);
2292bbaa8b60SDan Kruchinin 	}
2293bbaa8b60SDan Kruchinin }
2294bbaa8b60SDan Kruchinin 
2295bbaa8b60SDan Kruchinin static bool_t
nlm_shres_equal(struct shrlock * shrp1,struct shrlock * shrp2)2296bbaa8b60SDan Kruchinin nlm_shres_equal(struct shrlock *shrp1, struct shrlock *shrp2)
2297bbaa8b60SDan Kruchinin {
2298bbaa8b60SDan Kruchinin 	if (shrp1->s_sysid	== shrp2->s_sysid	&&
2299bbaa8b60SDan Kruchinin 	    shrp1->s_pid	== shrp2->s_pid		&&
2300bbaa8b60SDan Kruchinin 	    shrp1->s_own_len	== shrp2->s_own_len	&&
2301bbaa8b60SDan Kruchinin 	    bcmp(shrp1->s_owner, shrp2->s_owner,
2302bbaa8b60SDan Kruchinin 	    shrp1->s_own_len) == 0)
2303bbaa8b60SDan Kruchinin 		return (TRUE);
2304bbaa8b60SDan Kruchinin 
2305bbaa8b60SDan Kruchinin 	return (FALSE);
2306bbaa8b60SDan Kruchinin }
2307bbaa8b60SDan Kruchinin 
2308bbaa8b60SDan Kruchinin static struct nlm_shres *
nlm_shres_create_item(struct shrlock * shrp,vnode_t * vp)2309bbaa8b60SDan Kruchinin nlm_shres_create_item(struct shrlock *shrp, vnode_t *vp)
2310bbaa8b60SDan Kruchinin {
2311bbaa8b60SDan Kruchinin 	struct nlm_shres *nsp;
2312bbaa8b60SDan Kruchinin 
2313bbaa8b60SDan Kruchinin 	nsp = kmem_alloc(sizeof (*nsp), KM_SLEEP);
2314bbaa8b60SDan Kruchinin 	nsp->ns_shr = kmem_alloc(sizeof (*shrp), KM_SLEEP);
2315bbaa8b60SDan Kruchinin 	bcopy(shrp, nsp->ns_shr, sizeof (*shrp));
2316bbaa8b60SDan Kruchinin 	nsp->ns_shr->s_owner = kmem_alloc(shrp->s_own_len, KM_SLEEP);
2317bbaa8b60SDan Kruchinin 	bcopy(shrp->s_owner, nsp->ns_shr->s_owner, shrp->s_own_len);
2318bbaa8b60SDan Kruchinin 	nsp->ns_vp = vp;
2319bbaa8b60SDan Kruchinin 
2320bbaa8b60SDan Kruchinin 	return (nsp);
2321bbaa8b60SDan Kruchinin }
2322bbaa8b60SDan Kruchinin 
2323bbaa8b60SDan Kruchinin static void
nlm_shres_destroy_item(struct nlm_shres * nsp)2324bbaa8b60SDan Kruchinin nlm_shres_destroy_item(struct nlm_shres *nsp)
2325bbaa8b60SDan Kruchinin {
2326bbaa8b60SDan Kruchinin 	kmem_free(nsp->ns_shr->s_owner,
2327bbaa8b60SDan Kruchinin 	    nsp->ns_shr->s_own_len);
2328bbaa8b60SDan Kruchinin 	kmem_free(nsp->ns_shr, sizeof (struct shrlock));
2329bbaa8b60SDan Kruchinin 	kmem_free(nsp, sizeof (*nsp));
2330bbaa8b60SDan Kruchinin }
2331bbaa8b60SDan Kruchinin 
2332bbaa8b60SDan Kruchinin /*
2333bbaa8b60SDan Kruchinin  * Called by klmmod.c when lockd adds a network endpoint
2334bbaa8b60SDan Kruchinin  * on which we should begin RPC services.
2335bbaa8b60SDan Kruchinin  */
2336bbaa8b60SDan Kruchinin int
nlm_svc_add_ep(struct file * fp,const char * netid,struct knetconfig * knc)2337bbaa8b60SDan Kruchinin nlm_svc_add_ep(struct file *fp, const char *netid, struct knetconfig *knc)
2338bbaa8b60SDan Kruchinin {
2339bbaa8b60SDan Kruchinin 	SVCMASTERXPRT *xprt = NULL;
2340bbaa8b60SDan Kruchinin 	int error;
2341bbaa8b60SDan Kruchinin 
2342bbaa8b60SDan Kruchinin 	error = svc_tli_kcreate(fp, 0, (char *)netid, NULL, &xprt,
2343bbaa8b60SDan Kruchinin 	    &nlm_sct, NULL, NLM_SVCPOOL_ID, FALSE);
2344bbaa8b60SDan Kruchinin 	if (error != 0)
2345bbaa8b60SDan Kruchinin 		return (error);
2346bbaa8b60SDan Kruchinin 
2347bbaa8b60SDan Kruchinin 	(void) nlm_knc_to_netid(knc);
2348bbaa8b60SDan Kruchinin 	return (0);
2349bbaa8b60SDan Kruchinin }
2350bbaa8b60SDan Kruchinin 
2351bbaa8b60SDan Kruchinin /*
2352bbaa8b60SDan Kruchinin  * Start NLM service.
2353bbaa8b60SDan Kruchinin  */
2354bbaa8b60SDan Kruchinin int
nlm_svc_starting(struct nlm_globals * g,struct file * fp,const char * netid,struct knetconfig * knc)2355bbaa8b60SDan Kruchinin nlm_svc_starting(struct nlm_globals *g, struct file *fp,
2356bbaa8b60SDan Kruchinin     const char *netid, struct knetconfig *knc)
2357bbaa8b60SDan Kruchinin {
2358bbaa8b60SDan Kruchinin 	int error;
2359bbaa8b60SDan Kruchinin 	enum clnt_stat stat;
2360bbaa8b60SDan Kruchinin 
2361bbaa8b60SDan Kruchinin 	VERIFY(g->run_status == NLM_ST_STARTING);
2362bbaa8b60SDan Kruchinin 	VERIFY(g->nlm_gc_thread == NULL);
2363bbaa8b60SDan Kruchinin 
2364bbaa8b60SDan Kruchinin 	error = nlm_nsm_init_local(&g->nlm_nsm);
2365bbaa8b60SDan Kruchinin 	if (error != 0) {
2366bbaa8b60SDan Kruchinin 		NLM_ERR("Failed to initialize NSM handler "
2367bbaa8b60SDan Kruchinin 		    "(error=%d)\n", error);
2368bbaa8b60SDan Kruchinin 		g->run_status = NLM_ST_DOWN;
2369bbaa8b60SDan Kruchinin 		return (error);
2370bbaa8b60SDan Kruchinin 	}
2371bbaa8b60SDan Kruchinin 
2372bbaa8b60SDan Kruchinin 	error = EIO;
2373bbaa8b60SDan Kruchinin 
2374bbaa8b60SDan Kruchinin 	/*
2375bbaa8b60SDan Kruchinin 	 * Create an NLM garbage collector thread that will
2376bbaa8b60SDan Kruchinin 	 * clean up stale vholds and hosts objects.
2377bbaa8b60SDan Kruchinin 	 */
2378bbaa8b60SDan Kruchinin 	g->nlm_gc_thread = zthread_create(NULL, 0, nlm_gc,
2379bbaa8b60SDan Kruchinin 	    g, 0, minclsyspri);
2380bbaa8b60SDan Kruchinin 
2381bbaa8b60SDan Kruchinin 	/*
2382bbaa8b60SDan Kruchinin 	 * Send SIMU_CRASH to local statd to report that
2383bbaa8b60SDan Kruchinin 	 * NLM started, so that statd can report other hosts
2384bbaa8b60SDan Kruchinin 	 * about NLM state change.
2385bbaa8b60SDan Kruchinin 	 */
2386bbaa8b60SDan Kruchinin 
2387bbaa8b60SDan Kruchinin 	stat = nlm_nsm_simu_crash(&g->nlm_nsm);
2388bbaa8b60SDan Kruchinin 	if (stat != RPC_SUCCESS) {
2389bbaa8b60SDan Kruchinin 		NLM_ERR("Failed to connect to local statd "
2390bbaa8b60SDan Kruchinin 		    "(rpcerr=%d)\n", stat);
2391bbaa8b60SDan Kruchinin 		goto shutdown_lm;
2392bbaa8b60SDan Kruchinin 	}
2393bbaa8b60SDan Kruchinin 
2394bbaa8b60SDan Kruchinin 	stat = nlm_nsm_stat(&g->nlm_nsm, &g->nsm_state);
2395bbaa8b60SDan Kruchinin 	if (stat != RPC_SUCCESS) {
2396bbaa8b60SDan Kruchinin 		NLM_ERR("Failed to get the status of local statd "
2397bbaa8b60SDan Kruchinin 		    "(rpcerr=%d)\n", stat);
2398bbaa8b60SDan Kruchinin 		goto shutdown_lm;
2399bbaa8b60SDan Kruchinin 	}
2400bbaa8b60SDan Kruchinin 
2401bbaa8b60SDan Kruchinin 	g->grace_threshold = ddi_get_lbolt() +
2402bbaa8b60SDan Kruchinin 	    SEC_TO_TICK(g->grace_period);
2403bbaa8b60SDan Kruchinin 
2404bbaa8b60SDan Kruchinin 	/* Register endpoint used for communications with local NLM */
2405bbaa8b60SDan Kruchinin 	error = nlm_svc_add_ep(fp, netid, knc);
2406bbaa8b60SDan Kruchinin 	if (error != 0)
2407bbaa8b60SDan Kruchinin 		goto shutdown_lm;
2408bbaa8b60SDan Kruchinin 
2409bbaa8b60SDan Kruchinin 	(void) svc_pool_control(NLM_SVCPOOL_ID,
2410bbaa8b60SDan Kruchinin 	    SVCPSET_SHUTDOWN_PROC, (void *)nlm_pool_shutdown);
2411bbaa8b60SDan Kruchinin 	g->run_status = NLM_ST_UP;
2412bbaa8b60SDan Kruchinin 	return (0);
2413bbaa8b60SDan Kruchinin 
2414bbaa8b60SDan Kruchinin shutdown_lm:
2415bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
2416bbaa8b60SDan Kruchinin 	g->run_status = NLM_ST_STOPPING;
2417bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
2418bbaa8b60SDan Kruchinin 
2419bbaa8b60SDan Kruchinin 	nlm_svc_stopping(g);
2420bbaa8b60SDan Kruchinin 	return (error);
2421bbaa8b60SDan Kruchinin }
2422bbaa8b60SDan Kruchinin 
2423bbaa8b60SDan Kruchinin /*
2424bbaa8b60SDan Kruchinin  * Called when the server pool is destroyed, so that
2425bbaa8b60SDan Kruchinin  * all transports are closed and no any server threads
2426bbaa8b60SDan Kruchinin  * exist.
2427bbaa8b60SDan Kruchinin  *
2428bbaa8b60SDan Kruchinin  * Just call lm_shutdown() to shut NLM down properly.
2429bbaa8b60SDan Kruchinin  */
2430bbaa8b60SDan Kruchinin static void
nlm_pool_shutdown(void)2431bbaa8b60SDan Kruchinin nlm_pool_shutdown(void)
2432bbaa8b60SDan Kruchinin {
2433bbaa8b60SDan Kruchinin 	(void) lm_shutdown();
2434bbaa8b60SDan Kruchinin }
2435bbaa8b60SDan Kruchinin 
2436bbaa8b60SDan Kruchinin /*
2437bbaa8b60SDan Kruchinin  * Stop NLM service, cleanup all resources
2438bbaa8b60SDan Kruchinin  * NLM owns at the moment.
2439bbaa8b60SDan Kruchinin  *
2440bbaa8b60SDan Kruchinin  * NOTE: NFS code can call NLM while it's
2441bbaa8b60SDan Kruchinin  * stopping or even if it's shut down. Any attempt
2442bbaa8b60SDan Kruchinin  * to lock file either on client or on the server
2443bbaa8b60SDan Kruchinin  * will fail if NLM isn't in NLM_ST_UP state.
2444bbaa8b60SDan Kruchinin  */
2445bbaa8b60SDan Kruchinin void
nlm_svc_stopping(struct nlm_globals * g)2446bbaa8b60SDan Kruchinin nlm_svc_stopping(struct nlm_globals *g)
2447bbaa8b60SDan Kruchinin {
2448bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
2449bbaa8b60SDan Kruchinin 	ASSERT(g->run_status == NLM_ST_STOPPING);
2450bbaa8b60SDan Kruchinin 
2451bbaa8b60SDan Kruchinin 	/*
2452bbaa8b60SDan Kruchinin 	 * Ask NLM GC thread to exit and wait until it dies.
2453bbaa8b60SDan Kruchinin 	 */
2454bbaa8b60SDan Kruchinin 	cv_signal(&g->nlm_gc_sched_cv);
2455bbaa8b60SDan Kruchinin 	while (g->nlm_gc_thread != NULL)
2456bbaa8b60SDan Kruchinin 		cv_wait(&g->nlm_gc_finish_cv, &g->lock);
2457bbaa8b60SDan Kruchinin 
2458bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
2459bbaa8b60SDan Kruchinin 
2460bbaa8b60SDan Kruchinin 	/*
2461bbaa8b60SDan Kruchinin 	 * Cleanup locks owned by NLM hosts.
2462bbaa8b60SDan Kruchinin 	 * NOTE: New hosts won't be created while
2463bbaa8b60SDan Kruchinin 	 * NLM is stopping.
2464bbaa8b60SDan Kruchinin 	 */
2465bbaa8b60SDan Kruchinin 	while (!avl_is_empty(&g->nlm_hosts_tree)) {
2466bbaa8b60SDan Kruchinin 		struct nlm_host *hostp;
2467bbaa8b60SDan Kruchinin 		int busy_hosts = 0;
2468bbaa8b60SDan Kruchinin 
2469bbaa8b60SDan Kruchinin 		/*
2470bbaa8b60SDan Kruchinin 		 * Iterate through all NLM hosts in the system
2471bbaa8b60SDan Kruchinin 		 * and drop the locks they own by force.
2472bbaa8b60SDan Kruchinin 		 */
2473bbaa8b60SDan Kruchinin 		hostp = avl_first(&g->nlm_hosts_tree);
2474bbaa8b60SDan Kruchinin 		while (hostp != NULL) {
2475bbaa8b60SDan Kruchinin 			/* Cleanup all client and server side locks */
2476bbaa8b60SDan Kruchinin 			nlm_client_cancel_all(g, hostp);
2477bbaa8b60SDan Kruchinin 			nlm_host_notify_server(hostp, 0);
2478bbaa8b60SDan Kruchinin 
2479bbaa8b60SDan Kruchinin 			mutex_enter(&hostp->nh_lock);
2480bbaa8b60SDan Kruchinin 			nlm_host_gc_vholds(hostp);
2481bbaa8b60SDan Kruchinin 			if (hostp->nh_refs > 0 || nlm_host_has_locks(hostp)) {
2482bbaa8b60SDan Kruchinin 				/*
2483bbaa8b60SDan Kruchinin 				 * Oh, it seems the host is still busy, let
2484bbaa8b60SDan Kruchinin 				 * it some time to release and go to the
2485bbaa8b60SDan Kruchinin 				 * next one.
2486bbaa8b60SDan Kruchinin 				 */
2487bbaa8b60SDan Kruchinin 
2488bbaa8b60SDan Kruchinin 				mutex_exit(&hostp->nh_lock);
2489bbaa8b60SDan Kruchinin 				hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2490bbaa8b60SDan Kruchinin 				busy_hosts++;
2491bbaa8b60SDan Kruchinin 				continue;
2492bbaa8b60SDan Kruchinin 			}
2493bbaa8b60SDan Kruchinin 
2494bbaa8b60SDan Kruchinin 			mutex_exit(&hostp->nh_lock);
2495bbaa8b60SDan Kruchinin 			hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2496bbaa8b60SDan Kruchinin 		}
2497bbaa8b60SDan Kruchinin 
2498bbaa8b60SDan Kruchinin 		/*
2499bbaa8b60SDan Kruchinin 		 * All hosts go to nlm_idle_hosts list after
2500bbaa8b60SDan Kruchinin 		 * all locks they own are cleaned up and last refereces
2501bbaa8b60SDan Kruchinin 		 * were dropped. Just destroy all hosts in nlm_idle_hosts
2502bbaa8b60SDan Kruchinin 		 * list, they can not be removed from there while we're
2503bbaa8b60SDan Kruchinin 		 * in stopping state.
2504bbaa8b60SDan Kruchinin 		 */
2505bbaa8b60SDan Kruchinin 		while ((hostp = TAILQ_FIRST(&g->nlm_idle_hosts)) != NULL) {
2506bbaa8b60SDan Kruchinin 			nlm_host_unregister(g, hostp);
2507bbaa8b60SDan Kruchinin 			nlm_host_destroy(hostp);
2508bbaa8b60SDan Kruchinin 		}
2509bbaa8b60SDan Kruchinin 
2510bbaa8b60SDan Kruchinin 		if (busy_hosts > 0) {
2511bbaa8b60SDan Kruchinin 			/*
2512bbaa8b60SDan Kruchinin 			 * There're some hosts that weren't cleaned
2513bbaa8b60SDan Kruchinin 			 * up. Probably they're in resource cleanup
2514bbaa8b60SDan Kruchinin 			 * process. Give them some time to do drop
2515bbaa8b60SDan Kruchinin 			 * references.
2516bbaa8b60SDan Kruchinin 			 */
2517bbaa8b60SDan Kruchinin 			delay(MSEC_TO_TICK(500));
2518bbaa8b60SDan Kruchinin 		}
2519bbaa8b60SDan Kruchinin 	}
2520bbaa8b60SDan Kruchinin 
2521bbaa8b60SDan Kruchinin 	ASSERT(TAILQ_EMPTY(&g->nlm_slocks));
2522bbaa8b60SDan Kruchinin 
2523bbaa8b60SDan Kruchinin 	nlm_nsm_fini(&g->nlm_nsm);
2524bbaa8b60SDan Kruchinin 	g->lockd_pid = 0;
2525bbaa8b60SDan Kruchinin 	g->run_status = NLM_ST_DOWN;
2526bbaa8b60SDan Kruchinin }
2527bbaa8b60SDan Kruchinin 
2528bbaa8b60SDan Kruchinin /*
2529bbaa8b60SDan Kruchinin  * Returns TRUE if the given vnode has
2530bbaa8b60SDan Kruchinin  * any active or sleeping locks.
2531bbaa8b60SDan Kruchinin  */
2532bbaa8b60SDan Kruchinin int
nlm_vp_active(const vnode_t * vp)2533bbaa8b60SDan Kruchinin nlm_vp_active(const vnode_t *vp)
2534bbaa8b60SDan Kruchinin {
2535bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
2536bbaa8b60SDan Kruchinin 	struct nlm_host *hostp;
2537bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp;
2538bbaa8b60SDan Kruchinin 	int active = 0;
2539bbaa8b60SDan Kruchinin 
2540bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
2541bbaa8b60SDan Kruchinin 
2542bbaa8b60SDan Kruchinin 	/*
2543bbaa8b60SDan Kruchinin 	 * Server side NLM has locks on the given vnode
2544bbaa8b60SDan Kruchinin 	 * if there exist a vhold object that holds
2545bbaa8b60SDan Kruchinin 	 * the given vnode "vp" in one of NLM hosts.
2546bbaa8b60SDan Kruchinin 	 */
2547bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
2548bbaa8b60SDan Kruchinin 	hostp = avl_first(&g->nlm_hosts_tree);
2549bbaa8b60SDan Kruchinin 	while (hostp != NULL) {
2550bbaa8b60SDan Kruchinin 		mutex_enter(&hostp->nh_lock);
2551bbaa8b60SDan Kruchinin 		nvp = nlm_vhold_find_locked(hostp, vp);
2552bbaa8b60SDan Kruchinin 		mutex_exit(&hostp->nh_lock);
2553bbaa8b60SDan Kruchinin 		if (nvp != NULL) {
2554bbaa8b60SDan Kruchinin 			active = 1;
2555bbaa8b60SDan Kruchinin 			break;
2556bbaa8b60SDan Kruchinin 		}
2557bbaa8b60SDan Kruchinin 
2558bbaa8b60SDan Kruchinin 		hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2559bbaa8b60SDan Kruchinin 	}
2560bbaa8b60SDan Kruchinin 
2561bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
2562bbaa8b60SDan Kruchinin 	return (active);
2563bbaa8b60SDan Kruchinin }
2564bbaa8b60SDan Kruchinin 
2565bbaa8b60SDan Kruchinin /*
2566bbaa8b60SDan Kruchinin  * Called right before NFS export is going to
2567bbaa8b60SDan Kruchinin  * dissapear. The function finds all vnodes
2568bbaa8b60SDan Kruchinin  * belonging to the given export and cleans
2569bbaa8b60SDan Kruchinin  * all remote locks and share reservations
2570bbaa8b60SDan Kruchinin  * on them.
2571bbaa8b60SDan Kruchinin  */
2572bbaa8b60SDan Kruchinin void
nlm_zone_unexport(struct nlm_globals * g,struct exportinfo * exi)2573*0dfe541eSEvan Layton nlm_zone_unexport(struct nlm_globals *g, struct exportinfo *exi)
2574bbaa8b60SDan Kruchinin {
2575bbaa8b60SDan Kruchinin 	struct nlm_host *hostp;
2576bbaa8b60SDan Kruchinin 
2577bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
2578*0dfe541eSEvan Layton 	if (g->run_status != NLM_ST_UP) {
2579*0dfe541eSEvan Layton 		/* nothing to do */
2580*0dfe541eSEvan Layton 		mutex_exit(&g->lock);
2581*0dfe541eSEvan Layton 		return;
2582*0dfe541eSEvan Layton 	}
2583*0dfe541eSEvan Layton 
2584bbaa8b60SDan Kruchinin 	hostp = avl_first(&g->nlm_hosts_tree);
2585bbaa8b60SDan Kruchinin 	while (hostp != NULL) {
2586bbaa8b60SDan Kruchinin 		struct nlm_vhold *nvp;
2587bbaa8b60SDan Kruchinin 
2588b2b464a4SMarcel Telka 		if (hostp->nh_flags & NLM_NH_INIDLE) {
2589b2b464a4SMarcel Telka 			TAILQ_REMOVE(&g->nlm_idle_hosts, hostp, nh_link);
2590b2b464a4SMarcel Telka 			hostp->nh_flags &= ~NLM_NH_INIDLE;
2591b2b464a4SMarcel Telka 		}
2592b2b464a4SMarcel Telka 		hostp->nh_refs++;
2593b2b464a4SMarcel Telka 
2594b2b464a4SMarcel Telka 		mutex_exit(&g->lock);
2595b2b464a4SMarcel Telka 
2596bbaa8b60SDan Kruchinin 		mutex_enter(&hostp->nh_lock);
2597bbaa8b60SDan Kruchinin 		TAILQ_FOREACH(nvp, &hostp->nh_vholds_list, nv_link) {
2598bbaa8b60SDan Kruchinin 			vnode_t *vp;
2599bbaa8b60SDan Kruchinin 
2600bbaa8b60SDan Kruchinin 			nvp->nv_refcnt++;
2601bbaa8b60SDan Kruchinin 			mutex_exit(&hostp->nh_lock);
2602bbaa8b60SDan Kruchinin 
2603bbaa8b60SDan Kruchinin 			vp = nvp->nv_vp;
2604bbaa8b60SDan Kruchinin 
2605bbaa8b60SDan Kruchinin 			if (!EQFSID(&exi->exi_fsid, &vp->v_vfsp->vfs_fsid))
2606bbaa8b60SDan Kruchinin 				goto next_iter;
2607bbaa8b60SDan Kruchinin 
2608bbaa8b60SDan Kruchinin 			/*
2609bbaa8b60SDan Kruchinin 			 * Ok, it we found out that vnode vp is under
2610bbaa8b60SDan Kruchinin 			 * control by the exportinfo exi, now we need
2611bbaa8b60SDan Kruchinin 			 * to drop all locks from this vnode, let's
2612bbaa8b60SDan Kruchinin 			 * do it.
2613bbaa8b60SDan Kruchinin 			 */
2614bbaa8b60SDan Kruchinin 			nlm_vhold_clean(nvp, hostp->nh_sysid);
2615bbaa8b60SDan Kruchinin 
2616bbaa8b60SDan Kruchinin 		next_iter:
2617bbaa8b60SDan Kruchinin 			mutex_enter(&hostp->nh_lock);
2618bbaa8b60SDan Kruchinin 			nvp->nv_refcnt--;
2619bbaa8b60SDan Kruchinin 		}
2620bbaa8b60SDan Kruchinin 		mutex_exit(&hostp->nh_lock);
2621b2b464a4SMarcel Telka 
2622b2b464a4SMarcel Telka 		mutex_enter(&g->lock);
2623b2b464a4SMarcel Telka 		nlm_host_release_locked(g, hostp);
2624b2b464a4SMarcel Telka 
2625bbaa8b60SDan Kruchinin 		hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp);
2626bbaa8b60SDan Kruchinin 	}
2627bbaa8b60SDan Kruchinin 
2628bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
2629bbaa8b60SDan Kruchinin }
2630bbaa8b60SDan Kruchinin 
2631*0dfe541eSEvan Layton void
nlm_unexport(struct exportinfo * exi)2632*0dfe541eSEvan Layton nlm_unexport(struct exportinfo *exi)
2633*0dfe541eSEvan Layton {
2634*0dfe541eSEvan Layton 	struct nlm_globals *g;
2635*0dfe541eSEvan Layton 
2636*0dfe541eSEvan Layton 	rw_enter(&lm_lck, RW_READER);
2637*0dfe541eSEvan Layton 	TAILQ_FOREACH(g, &nlm_zones_list, nlm_link) {
2638*0dfe541eSEvan Layton 		if (g->nlm_zoneid == exi->exi_zoneid) {
2639*0dfe541eSEvan Layton 			/*
2640*0dfe541eSEvan Layton 			 * NOTE: If we want to drop lm_lock before
2641*0dfe541eSEvan Layton 			 * calling nlm_zone_unexport(), we should break,
2642*0dfe541eSEvan Layton 			 * and have a post-rw_exit() snippit like:
2643*0dfe541eSEvan Layton 			 *	if (g != NULL)
2644*0dfe541eSEvan Layton 			 *		nlm_zone_unexport(g, exi);
2645*0dfe541eSEvan Layton 			 */
2646*0dfe541eSEvan Layton 			nlm_zone_unexport(g, exi);
2647*0dfe541eSEvan Layton 			break; /* Only going to match once! */
2648*0dfe541eSEvan Layton 		}
2649*0dfe541eSEvan Layton 	}
2650*0dfe541eSEvan Layton 	rw_exit(&lm_lck);
2651*0dfe541eSEvan Layton }
2652*0dfe541eSEvan Layton 
2653bbaa8b60SDan Kruchinin /*
2654bbaa8b60SDan Kruchinin  * Allocate new unique sysid.
2655bbaa8b60SDan Kruchinin  * In case of failure (no available sysids)
2656bbaa8b60SDan Kruchinin  * return LM_NOSYSID.
2657bbaa8b60SDan Kruchinin  */
2658bbaa8b60SDan Kruchinin sysid_t
nlm_sysid_alloc(void)2659bbaa8b60SDan Kruchinin nlm_sysid_alloc(void)
2660bbaa8b60SDan Kruchinin {
2661bbaa8b60SDan Kruchinin 	sysid_t ret_sysid = LM_NOSYSID;
2662bbaa8b60SDan Kruchinin 
2663bbaa8b60SDan Kruchinin 	rw_enter(&lm_lck, RW_WRITER);
2664bbaa8b60SDan Kruchinin 	if (nlm_sysid_nidx > LM_SYSID_MAX)
2665bbaa8b60SDan Kruchinin 		nlm_sysid_nidx = LM_SYSID;
2666bbaa8b60SDan Kruchinin 
2667bbaa8b60SDan Kruchinin 	if (!BT_TEST(nlm_sysid_bmap, nlm_sysid_nidx)) {
2668bbaa8b60SDan Kruchinin 		BT_SET(nlm_sysid_bmap, nlm_sysid_nidx);
2669bbaa8b60SDan Kruchinin 		ret_sysid = nlm_sysid_nidx++;
2670bbaa8b60SDan Kruchinin 	} else {
2671bbaa8b60SDan Kruchinin 		index_t id;
2672bbaa8b60SDan Kruchinin 
2673bbaa8b60SDan Kruchinin 		id = bt_availbit(nlm_sysid_bmap, NLM_BMAP_NITEMS);
2674bbaa8b60SDan Kruchinin 		if (id > 0) {
2675bbaa8b60SDan Kruchinin 			nlm_sysid_nidx = id + 1;
2676bbaa8b60SDan Kruchinin 			ret_sysid = id;
2677bbaa8b60SDan Kruchinin 			BT_SET(nlm_sysid_bmap, id);
2678bbaa8b60SDan Kruchinin 		}
2679bbaa8b60SDan Kruchinin 	}
2680bbaa8b60SDan Kruchinin 
2681bbaa8b60SDan Kruchinin 	rw_exit(&lm_lck);
2682bbaa8b60SDan Kruchinin 	return (ret_sysid);
2683bbaa8b60SDan Kruchinin }
2684bbaa8b60SDan Kruchinin 
2685bbaa8b60SDan Kruchinin void
nlm_sysid_free(sysid_t sysid)2686bbaa8b60SDan Kruchinin nlm_sysid_free(sysid_t sysid)
2687bbaa8b60SDan Kruchinin {
2688bbaa8b60SDan Kruchinin 	ASSERT(sysid >= LM_SYSID && sysid <= LM_SYSID_MAX);
2689bbaa8b60SDan Kruchinin 
2690bbaa8b60SDan Kruchinin 	rw_enter(&lm_lck, RW_WRITER);
2691bbaa8b60SDan Kruchinin 	ASSERT(BT_TEST(nlm_sysid_bmap, sysid));
2692bbaa8b60SDan Kruchinin 	BT_CLEAR(nlm_sysid_bmap, sysid);
2693bbaa8b60SDan Kruchinin 	rw_exit(&lm_lck);
2694bbaa8b60SDan Kruchinin }
2695bbaa8b60SDan Kruchinin 
2696bbaa8b60SDan Kruchinin /*
2697bbaa8b60SDan Kruchinin  * Return true if the request came from a local caller.
2698bbaa8b60SDan Kruchinin  * By necessity, this "knows" the netid names invented
2699bbaa8b60SDan Kruchinin  * in lm_svc() and nlm_netid_from_knetconfig().
2700bbaa8b60SDan Kruchinin  */
2701bbaa8b60SDan Kruchinin bool_t
nlm_caller_is_local(SVCXPRT * transp)2702bbaa8b60SDan Kruchinin nlm_caller_is_local(SVCXPRT *transp)
2703bbaa8b60SDan Kruchinin {
2704bbaa8b60SDan Kruchinin 	char *netid;
2705bbaa8b60SDan Kruchinin 	struct netbuf *rtaddr;
2706bbaa8b60SDan Kruchinin 
2707bbaa8b60SDan Kruchinin 	netid = svc_getnetid(transp);
2708bbaa8b60SDan Kruchinin 	rtaddr = svc_getrpccaller(transp);
2709bbaa8b60SDan Kruchinin 
2710bbaa8b60SDan Kruchinin 	if (netid == NULL)
2711bbaa8b60SDan Kruchinin 		return (FALSE);
2712bbaa8b60SDan Kruchinin 
2713bbaa8b60SDan Kruchinin 	if (strcmp(netid, "ticlts") == 0 ||
2714bbaa8b60SDan Kruchinin 	    strcmp(netid, "ticotsord") == 0)
2715bbaa8b60SDan Kruchinin 		return (TRUE);
2716bbaa8b60SDan Kruchinin 
2717bbaa8b60SDan Kruchinin 	if (strcmp(netid, "tcp") == 0 || strcmp(netid, "udp") == 0) {
2718bbaa8b60SDan Kruchinin 		struct sockaddr_in *sin = (void *)rtaddr->buf;
2719bbaa8b60SDan Kruchinin 		if (sin->sin_addr.s_addr == htonl(INADDR_LOOPBACK))
2720bbaa8b60SDan Kruchinin 			return (TRUE);
2721bbaa8b60SDan Kruchinin 	}
2722bbaa8b60SDan Kruchinin 	if (strcmp(netid, "tcp6") == 0 || strcmp(netid, "udp6") == 0) {
2723bbaa8b60SDan Kruchinin 		struct sockaddr_in6 *sin6 = (void *)rtaddr->buf;
2724bbaa8b60SDan Kruchinin 		if (IN6_IS_ADDR_LOOPBACK(&sin6->sin6_addr))
2725bbaa8b60SDan Kruchinin 			return (TRUE);
2726bbaa8b60SDan Kruchinin 	}
2727bbaa8b60SDan Kruchinin 
2728bbaa8b60SDan Kruchinin 	return (FALSE); /* unknown transport */
2729bbaa8b60SDan Kruchinin }
2730bbaa8b60SDan Kruchinin 
2731bbaa8b60SDan Kruchinin /*
2732bbaa8b60SDan Kruchinin  * Get netid string correspondig to the given knetconfig.
2733bbaa8b60SDan Kruchinin  * If not done already, save knc->knc_rdev in our table.
2734bbaa8b60SDan Kruchinin  */
2735bbaa8b60SDan Kruchinin const char *
nlm_knc_to_netid(struct knetconfig * knc)2736bbaa8b60SDan Kruchinin nlm_knc_to_netid(struct knetconfig *knc)
2737bbaa8b60SDan Kruchinin {
2738bbaa8b60SDan Kruchinin 	int i;
2739bbaa8b60SDan Kruchinin 	dev_t rdev;
2740bbaa8b60SDan Kruchinin 	struct nlm_knc *nc;
2741bbaa8b60SDan Kruchinin 	const char *netid = NULL;
2742bbaa8b60SDan Kruchinin 
2743bbaa8b60SDan Kruchinin 	rw_enter(&lm_lck, RW_READER);
2744bbaa8b60SDan Kruchinin 	for (i = 0; i < NLM_KNCS; i++) {
2745bbaa8b60SDan Kruchinin 		nc = &nlm_netconfigs[i];
2746bbaa8b60SDan Kruchinin 
2747bbaa8b60SDan Kruchinin 		if (nc->n_knc.knc_semantics == knc->knc_semantics &&
2748bbaa8b60SDan Kruchinin 		    strcmp(nc->n_knc.knc_protofmly,
2749bbaa8b60SDan Kruchinin 		    knc->knc_protofmly) == 0) {
2750bbaa8b60SDan Kruchinin 			netid = nc->n_netid;
2751bbaa8b60SDan Kruchinin 			rdev = nc->n_knc.knc_rdev;
2752bbaa8b60SDan Kruchinin 			break;
2753bbaa8b60SDan Kruchinin 		}
2754bbaa8b60SDan Kruchinin 	}
2755bbaa8b60SDan Kruchinin 	rw_exit(&lm_lck);
2756bbaa8b60SDan Kruchinin 
2757bbaa8b60SDan Kruchinin 	if (netid != NULL && rdev == NODEV) {
2758bbaa8b60SDan Kruchinin 		rw_enter(&lm_lck, RW_WRITER);
2759bbaa8b60SDan Kruchinin 		if (nc->n_knc.knc_rdev == NODEV)
2760bbaa8b60SDan Kruchinin 			nc->n_knc.knc_rdev = knc->knc_rdev;
2761bbaa8b60SDan Kruchinin 		rw_exit(&lm_lck);
2762bbaa8b60SDan Kruchinin 	}
2763bbaa8b60SDan Kruchinin 
2764bbaa8b60SDan Kruchinin 	return (netid);
2765bbaa8b60SDan Kruchinin }
2766bbaa8b60SDan Kruchinin 
2767bbaa8b60SDan Kruchinin /*
2768bbaa8b60SDan Kruchinin  * Get a knetconfig corresponding to the given netid.
2769bbaa8b60SDan Kruchinin  * If there's no knetconfig for this netid, ENOENT
2770bbaa8b60SDan Kruchinin  * is returned.
2771bbaa8b60SDan Kruchinin  */
2772bbaa8b60SDan Kruchinin int
nlm_knc_from_netid(const char * netid,struct knetconfig * knc)2773bbaa8b60SDan Kruchinin nlm_knc_from_netid(const char *netid, struct knetconfig *knc)
2774bbaa8b60SDan Kruchinin {
2775bbaa8b60SDan Kruchinin 	int i, ret;
2776bbaa8b60SDan Kruchinin 
2777bbaa8b60SDan Kruchinin 	ret = ENOENT;
2778bbaa8b60SDan Kruchinin 	for (i = 0; i < NLM_KNCS; i++) {
2779bbaa8b60SDan Kruchinin 		struct nlm_knc *nknc;
2780bbaa8b60SDan Kruchinin 
2781bbaa8b60SDan Kruchinin 		nknc = &nlm_netconfigs[i];
2782bbaa8b60SDan Kruchinin 		if (strcmp(netid, nknc->n_netid) == 0 &&
2783bbaa8b60SDan Kruchinin 		    nknc->n_knc.knc_rdev != NODEV) {
2784bbaa8b60SDan Kruchinin 			*knc = nknc->n_knc;
2785bbaa8b60SDan Kruchinin 			ret = 0;
2786bbaa8b60SDan Kruchinin 			break;
2787bbaa8b60SDan Kruchinin 		}
2788bbaa8b60SDan Kruchinin 	}
2789bbaa8b60SDan Kruchinin 
2790bbaa8b60SDan Kruchinin 	return (ret);
2791bbaa8b60SDan Kruchinin }
2792bbaa8b60SDan Kruchinin 
2793bbaa8b60SDan Kruchinin void
nlm_cprsuspend(void)2794bbaa8b60SDan Kruchinin nlm_cprsuspend(void)
2795bbaa8b60SDan Kruchinin {
2796bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
2797bbaa8b60SDan Kruchinin 
2798bbaa8b60SDan Kruchinin 	rw_enter(&lm_lck, RW_READER);
2799bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
2800bbaa8b60SDan Kruchinin 		nlm_suspend_zone(g);
2801bbaa8b60SDan Kruchinin 
2802bbaa8b60SDan Kruchinin 	rw_exit(&lm_lck);
2803bbaa8b60SDan Kruchinin }
2804bbaa8b60SDan Kruchinin 
2805bbaa8b60SDan Kruchinin void
nlm_cprresume(void)2806bbaa8b60SDan Kruchinin nlm_cprresume(void)
2807bbaa8b60SDan Kruchinin {
2808bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
2809bbaa8b60SDan Kruchinin 
2810bbaa8b60SDan Kruchinin 	rw_enter(&lm_lck, RW_READER);
2811bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(g, &nlm_zones_list, nlm_link)
2812bbaa8b60SDan Kruchinin 		nlm_resume_zone(g);
2813bbaa8b60SDan Kruchinin 
2814bbaa8b60SDan Kruchinin 	rw_exit(&lm_lck);
2815bbaa8b60SDan Kruchinin }
2816bbaa8b60SDan Kruchinin 
2817bbaa8b60SDan Kruchinin static void
nlm_nsm_clnt_init(CLIENT * clnt,struct nlm_nsm * nsm)2818bbaa8b60SDan Kruchinin nlm_nsm_clnt_init(CLIENT *clnt, struct nlm_nsm *nsm)
2819bbaa8b60SDan Kruchinin {
2820bbaa8b60SDan Kruchinin 	(void) clnt_tli_kinit(clnt, &nsm->ns_knc, &nsm->ns_addr, 0,
2821*0dfe541eSEvan Layton 	    NLM_RPC_RETRIES, zone_kcred());
2822bbaa8b60SDan Kruchinin }
2823bbaa8b60SDan Kruchinin 
2824bbaa8b60SDan Kruchinin static void
nlm_netbuf_to_netobj(struct netbuf * addr,int * family,netobj * obj)2825bbaa8b60SDan Kruchinin nlm_netbuf_to_netobj(struct netbuf *addr, int *family, netobj *obj)
2826bbaa8b60SDan Kruchinin {
2827bbaa8b60SDan Kruchinin 	/* LINTED pointer alignment */
2828bbaa8b60SDan Kruchinin 	struct sockaddr *sa = (struct sockaddr *)addr->buf;
2829bbaa8b60SDan Kruchinin 
2830bbaa8b60SDan Kruchinin 	*family = sa->sa_family;
2831bbaa8b60SDan Kruchinin 
2832bbaa8b60SDan Kruchinin 	switch (sa->sa_family) {
2833bbaa8b60SDan Kruchinin 	case AF_INET: {
2834bbaa8b60SDan Kruchinin 		/* LINTED pointer alignment */
2835bbaa8b60SDan Kruchinin 		struct sockaddr_in *sin = (struct sockaddr_in *)sa;
2836bbaa8b60SDan Kruchinin 
2837bbaa8b60SDan Kruchinin 		obj->n_len = sizeof (sin->sin_addr);
2838bbaa8b60SDan Kruchinin 		obj->n_bytes = (char *)&sin->sin_addr;
2839bbaa8b60SDan Kruchinin 		break;
2840bbaa8b60SDan Kruchinin 	}
2841bbaa8b60SDan Kruchinin 
2842bbaa8b60SDan Kruchinin 	case AF_INET6: {
2843bbaa8b60SDan Kruchinin 		/* LINTED pointer alignment */
2844bbaa8b60SDan Kruchinin 		struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)sa;
2845bbaa8b60SDan Kruchinin 
2846bbaa8b60SDan Kruchinin 		obj->n_len = sizeof (sin6->sin6_addr);
2847bbaa8b60SDan Kruchinin 		obj->n_bytes = (char *)&sin6->sin6_addr;
2848bbaa8b60SDan Kruchinin 		break;
2849bbaa8b60SDan Kruchinin 	}
2850bbaa8b60SDan Kruchinin 
2851bbaa8b60SDan Kruchinin 	default:
2852bbaa8b60SDan Kruchinin 		VERIFY(0);
2853bbaa8b60SDan Kruchinin 		break;
2854bbaa8b60SDan Kruchinin 	}
2855bbaa8b60SDan Kruchinin }
2856