xref: /titanic_52/usr/src/uts/common/klm/nlm_service.c (revision 310a15feb55cff708c66f8fdfadc1be6198d897e)
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 /*
29bbaa8b60SDan Kruchinin  * Copyright (c) 2012 by Delphix. All rights reserved.
3095fa5714SMarcel Telka  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
31b4ecf764SJerry Jelinek  * Copyright 2014 Joyent, Inc.  All rights reserved.
32bbaa8b60SDan Kruchinin  */
33bbaa8b60SDan Kruchinin 
34bbaa8b60SDan Kruchinin /*
35bbaa8b60SDan Kruchinin  * NFS Lock Manager service functions (nlm_do_...)
36bbaa8b60SDan Kruchinin  * Called from nlm_rpc_svc.c wrappers.
37bbaa8b60SDan Kruchinin  *
38bbaa8b60SDan Kruchinin  * Source code derived from FreeBSD nlm_prot_impl.c
39bbaa8b60SDan Kruchinin  */
40bbaa8b60SDan Kruchinin 
41bbaa8b60SDan Kruchinin #include <sys/param.h>
42bbaa8b60SDan Kruchinin #include <sys/systm.h>
43bbaa8b60SDan Kruchinin #include <sys/thread.h>
44bbaa8b60SDan Kruchinin #include <sys/fcntl.h>
45bbaa8b60SDan Kruchinin #include <sys/flock.h>
46bbaa8b60SDan Kruchinin #include <sys/mount.h>
47bbaa8b60SDan Kruchinin #include <sys/priv.h>
48bbaa8b60SDan Kruchinin #include <sys/proc.h>
49bbaa8b60SDan Kruchinin #include <sys/share.h>
50bbaa8b60SDan Kruchinin #include <sys/socket.h>
51bbaa8b60SDan Kruchinin #include <sys/syscall.h>
52bbaa8b60SDan Kruchinin #include <sys/syslog.h>
53bbaa8b60SDan Kruchinin #include <sys/systm.h>
54bbaa8b60SDan Kruchinin #include <sys/taskq.h>
55bbaa8b60SDan Kruchinin #include <sys/unistd.h>
56bbaa8b60SDan Kruchinin #include <sys/vnode.h>
57bbaa8b60SDan Kruchinin #include <sys/vfs.h>
58bbaa8b60SDan Kruchinin #include <sys/queue.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 
71bbaa8b60SDan Kruchinin #include <nfs/nfs.h>
72bbaa8b60SDan Kruchinin #include <nfs/nfs_clnt.h>
73bbaa8b60SDan Kruchinin #include <nfs/export.h>
74bbaa8b60SDan Kruchinin #include <nfs/rnode.h>
75bbaa8b60SDan Kruchinin 
76bbaa8b60SDan Kruchinin #include "nlm_impl.h"
77bbaa8b60SDan Kruchinin 
78bbaa8b60SDan Kruchinin #define	NLM_IN_GRACE(g) (ddi_get_lbolt() < (g)->grace_threshold)
79bbaa8b60SDan Kruchinin 
80bbaa8b60SDan Kruchinin struct nlm_block_cb_data {
81bbaa8b60SDan Kruchinin 	struct nlm_host		*hostp;
82bbaa8b60SDan Kruchinin 	struct nlm_vhold	*nvp;
83bbaa8b60SDan Kruchinin 	struct flock64		*flp;
84bbaa8b60SDan Kruchinin };
85bbaa8b60SDan Kruchinin 
86bbaa8b60SDan Kruchinin /*
87bbaa8b60SDan Kruchinin  * Invoke an asyncronous RPC callbeck
88bbaa8b60SDan Kruchinin  * (used when NLM server needs to reply to MSG NLM procedure).
89bbaa8b60SDan Kruchinin  */
90bbaa8b60SDan Kruchinin #define	NLM_INVOKE_CALLBACK(descr, rpcp, resp, callb)			\
91bbaa8b60SDan Kruchinin 	do {								\
92bbaa8b60SDan Kruchinin 		enum clnt_stat _stat;					\
93bbaa8b60SDan Kruchinin 									\
94bbaa8b60SDan Kruchinin 		_stat = (*(callb))(resp, NULL, (rpcp)->nr_handle);	\
95bbaa8b60SDan Kruchinin 		if (_stat != RPC_SUCCESS && _stat != RPC_TIMEDOUT) {	\
96bbaa8b60SDan Kruchinin 			struct rpc_err _err;				\
97bbaa8b60SDan Kruchinin 									\
98bbaa8b60SDan Kruchinin 			CLNT_GETERR((rpcp)->nr_handle, &_err);		\
99bbaa8b60SDan Kruchinin 			NLM_ERR("NLM: %s callback failed: "		\
100bbaa8b60SDan Kruchinin 			    "stat %d, err %d\n", descr, _stat,		\
101bbaa8b60SDan Kruchinin 			    _err.re_errno);				\
102bbaa8b60SDan Kruchinin 		}							\
103bbaa8b60SDan Kruchinin 									\
104bbaa8b60SDan Kruchinin 	_NOTE(CONSTCOND) } while (0)
105bbaa8b60SDan Kruchinin 
106bbaa8b60SDan Kruchinin static void nlm_block(
107bbaa8b60SDan Kruchinin 	nlm4_lockargs *lockargs,
108bbaa8b60SDan Kruchinin 	struct nlm_host *host,
109bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp,
110bbaa8b60SDan Kruchinin 	nlm_rpc_t *rpcp,
111bbaa8b60SDan Kruchinin 	struct flock64 *fl,
112bbaa8b60SDan Kruchinin 	nlm_testargs_cb grant_cb);
113bbaa8b60SDan Kruchinin 
114bbaa8b60SDan Kruchinin static vnode_t *nlm_fh_to_vp(struct netobj *);
115bbaa8b60SDan Kruchinin static struct nlm_vhold *nlm_fh_to_vhold(struct nlm_host *, struct netobj *);
116bbaa8b60SDan Kruchinin static void nlm_init_shrlock(struct shrlock *, nlm4_share *, struct nlm_host *);
117bbaa8b60SDan Kruchinin static callb_cpr_t *nlm_block_callback(flk_cb_when_t, void *);
118bbaa8b60SDan Kruchinin static int nlm_vop_frlock(vnode_t *, int, flock64_t *, int, offset_t,
119bbaa8b60SDan Kruchinin     struct flk_callback *, cred_t *, caller_context_t *);
120bbaa8b60SDan Kruchinin 
121bbaa8b60SDan Kruchinin /*
122bbaa8b60SDan Kruchinin  * Convert a lock from network to local form, and
123bbaa8b60SDan Kruchinin  * check for valid range (no overflow).
124bbaa8b60SDan Kruchinin  */
125bbaa8b60SDan Kruchinin static int
126bbaa8b60SDan Kruchinin nlm_init_flock(struct flock64 *fl, struct nlm4_lock *nl,
127bbaa8b60SDan Kruchinin     struct nlm_host *host, rpcvers_t vers, short type)
128bbaa8b60SDan Kruchinin {
129bbaa8b60SDan Kruchinin 	uint64_t off, len;
130bbaa8b60SDan Kruchinin 
131bbaa8b60SDan Kruchinin 	bzero(fl, sizeof (*fl));
132bbaa8b60SDan Kruchinin 	off = nl->l_offset;
133bbaa8b60SDan Kruchinin 	len = nl->l_len;
134bbaa8b60SDan Kruchinin 
135bbaa8b60SDan Kruchinin 	if (vers < NLM4_VERS) {
136bbaa8b60SDan Kruchinin 		if (off > MAX_UOFF32 || len > MAX_UOFF32)
137bbaa8b60SDan Kruchinin 			return (EINVAL);
138bbaa8b60SDan Kruchinin 		if (off + len > MAX_UOFF32 + 1)
139bbaa8b60SDan Kruchinin 			return (EINVAL);
140bbaa8b60SDan Kruchinin 	} else {
141bbaa8b60SDan Kruchinin 		/*
142bbaa8b60SDan Kruchinin 		 * Check range for 64-bit client (no overflow).
143bbaa8b60SDan Kruchinin 		 * Again allow len == ~0 to mean lock to EOF.
144bbaa8b60SDan Kruchinin 		 */
145bbaa8b60SDan Kruchinin 		if (len == MAX_U_OFFSET_T)
146bbaa8b60SDan Kruchinin 			len = 0;
147bbaa8b60SDan Kruchinin 		if (len != 0 && off + (len - 1) < off)
148bbaa8b60SDan Kruchinin 			return (EINVAL);
149bbaa8b60SDan Kruchinin 	}
150bbaa8b60SDan Kruchinin 
151bbaa8b60SDan Kruchinin 	fl->l_type = type;
152bbaa8b60SDan Kruchinin 	fl->l_whence = SEEK_SET;
153bbaa8b60SDan Kruchinin 	fl->l_start = off;
154bbaa8b60SDan Kruchinin 	fl->l_len = len;
155bbaa8b60SDan Kruchinin 	fl->l_sysid = host->nh_sysid;
156bbaa8b60SDan Kruchinin 	fl->l_pid = nl->svid;
157bbaa8b60SDan Kruchinin 	/* l_pad */
158bbaa8b60SDan Kruchinin 
159bbaa8b60SDan Kruchinin 	return (0);
160bbaa8b60SDan Kruchinin }
161bbaa8b60SDan Kruchinin 
162bbaa8b60SDan Kruchinin /*
163b4ecf764SJerry Jelinek  * Convert an fhandle into a vnode.
164b4ecf764SJerry Jelinek  * Uses the file id (fh_len + fh_data) in the fhandle to get the vnode.
165b4ecf764SJerry Jelinek  * WARNING: users of this routine must do a VN_RELE on the vnode when they
166b4ecf764SJerry Jelinek  * are done with it.
167b4ecf764SJerry Jelinek  * This is just like nfs_fhtovp() but without the exportinfo argument.
168b4ecf764SJerry Jelinek  */
169b4ecf764SJerry Jelinek static vnode_t *
170b4ecf764SJerry Jelinek lm_fhtovp(fhandle3_t *fh)
171b4ecf764SJerry Jelinek {
172b4ecf764SJerry Jelinek 	vfs_t *vfsp;
173b4ecf764SJerry Jelinek 	vnode_t *vp;
174b4ecf764SJerry Jelinek 	int error;
175b4ecf764SJerry Jelinek 
176b4ecf764SJerry Jelinek 	vfsp = getvfs(&fh->_fh3_fsid);
177b4ecf764SJerry Jelinek 	if (vfsp == NULL)
178b4ecf764SJerry Jelinek 		return (NULL);
179b4ecf764SJerry Jelinek 
180b4ecf764SJerry Jelinek 	/* LINTED E_BAD_PTR_CAST_ALIGN */
181b4ecf764SJerry Jelinek 	error = VFS_VGET(vfsp, &vp, (fid_t *)&(fh->_fh3_len));
182b4ecf764SJerry Jelinek 	VFS_RELE(vfsp);
183b4ecf764SJerry Jelinek 	if (error || vp == NULL)
184b4ecf764SJerry Jelinek 		return (NULL);
185b4ecf764SJerry Jelinek 
186b4ecf764SJerry Jelinek 	return (vp);
187b4ecf764SJerry Jelinek }
188b4ecf764SJerry Jelinek 
189b4ecf764SJerry Jelinek /*
190bbaa8b60SDan Kruchinin  * Gets vnode from client's filehandle
191bbaa8b60SDan Kruchinin  * NOTE: Holds vnode, it _must_ be explicitly
192bbaa8b60SDan Kruchinin  * released by VN_RELE().
193bbaa8b60SDan Kruchinin  */
194bbaa8b60SDan Kruchinin static vnode_t *
195bbaa8b60SDan Kruchinin nlm_fh_to_vp(struct netobj *fh)
196bbaa8b60SDan Kruchinin {
197b4ecf764SJerry Jelinek 	fhandle3_t *fhp;
198bbaa8b60SDan Kruchinin 
199bbaa8b60SDan Kruchinin 	/*
200bbaa8b60SDan Kruchinin 	 * Get a vnode pointer for the given NFS file handle.
201b4ecf764SJerry Jelinek 	 * Note that it could be an NFSv2 or NFSv3 handle,
202bbaa8b60SDan Kruchinin 	 * which means the size might vary.  (don't copy)
203bbaa8b60SDan Kruchinin 	 */
204b4ecf764SJerry Jelinek 	if (fh->n_len < sizeof (fhandle_t))
205bbaa8b60SDan Kruchinin 		return (NULL);
206bbaa8b60SDan Kruchinin 
207bbaa8b60SDan Kruchinin 	/* We know this is aligned (kmem_alloc) */
208bbaa8b60SDan Kruchinin 	/* LINTED E_BAD_PTR_CAST_ALIGN */
209b4ecf764SJerry Jelinek 	fhp = (fhandle3_t *)fh->n_bytes;
210b4ecf764SJerry Jelinek 
211b4ecf764SJerry Jelinek 	/*
212b4ecf764SJerry Jelinek 	 * See the comment for NFS_FH3MAXDATA in uts/common/nfs/nfs.h for
213b4ecf764SJerry Jelinek 	 * converting fhandles. Check the NFSv3 file handle size. The lockmgr
214b4ecf764SJerry Jelinek 	 * is not used for NFS v4.
215b4ecf764SJerry Jelinek 	 */
216b4ecf764SJerry Jelinek 	if (fhp->_fh3_len > NFS_FH3MAXDATA || fhp->_fh3_len == 0)
217b4ecf764SJerry Jelinek 		return (NULL);
218b4ecf764SJerry Jelinek 
219bbaa8b60SDan Kruchinin 	return (lm_fhtovp(fhp));
220bbaa8b60SDan Kruchinin }
221bbaa8b60SDan Kruchinin 
222bbaa8b60SDan Kruchinin /*
223bbaa8b60SDan Kruchinin  * Get vhold from client's filehandle, but in contrast to
224bbaa8b60SDan Kruchinin  * The function tries to check some access rights as well.
225bbaa8b60SDan Kruchinin  *
226bbaa8b60SDan Kruchinin  * NOTE: vhold object _must_ be explicitly released by
227bbaa8b60SDan Kruchinin  * nlm_vhold_release().
228bbaa8b60SDan Kruchinin  */
229bbaa8b60SDan Kruchinin static struct nlm_vhold *
230bbaa8b60SDan Kruchinin nlm_fh_to_vhold(struct nlm_host *hostp, struct netobj *fh)
231bbaa8b60SDan Kruchinin {
232bbaa8b60SDan Kruchinin 	vnode_t *vp;
233bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp;
234bbaa8b60SDan Kruchinin 
235bbaa8b60SDan Kruchinin 	vp = nlm_fh_to_vp(fh);
236bbaa8b60SDan Kruchinin 	if (vp == NULL)
237bbaa8b60SDan Kruchinin 		return (NULL);
238bbaa8b60SDan Kruchinin 
239bbaa8b60SDan Kruchinin 
240bbaa8b60SDan Kruchinin 	nvp = nlm_vhold_get(hostp, vp);
241bbaa8b60SDan Kruchinin 
242bbaa8b60SDan Kruchinin 	/*
243bbaa8b60SDan Kruchinin 	 * Both nlm_fh_to_vp() and nlm_vhold_get()
244bbaa8b60SDan Kruchinin 	 * do VN_HOLD(), so we need to drop one
245bbaa8b60SDan Kruchinin 	 * reference on vnode.
246bbaa8b60SDan Kruchinin 	 */
247bbaa8b60SDan Kruchinin 	VN_RELE(vp);
248bbaa8b60SDan Kruchinin 	return (nvp);
249bbaa8b60SDan Kruchinin }
250bbaa8b60SDan Kruchinin 
251bbaa8b60SDan Kruchinin /* ******************************************************************* */
252bbaa8b60SDan Kruchinin 
253bbaa8b60SDan Kruchinin /*
254bbaa8b60SDan Kruchinin  * NLM implementation details, called from the RPC svc code.
255bbaa8b60SDan Kruchinin  */
256bbaa8b60SDan Kruchinin 
257bbaa8b60SDan Kruchinin /*
258bbaa8b60SDan Kruchinin  * Call-back from NFS statd, used to notify that one of our
259bbaa8b60SDan Kruchinin  * hosts had a status change. The host can be either an
260bbaa8b60SDan Kruchinin  * NFS client, NFS server or both.
261bbaa8b60SDan Kruchinin  * According to NSM protocol description, the state is a
262bbaa8b60SDan Kruchinin  * number that is increases monotonically each time the
263bbaa8b60SDan Kruchinin  * state of host changes. An even number indicates that
264bbaa8b60SDan Kruchinin  * the host is down, while an odd number indicates that
265bbaa8b60SDan Kruchinin  * the host is up.
266bbaa8b60SDan Kruchinin  *
267bbaa8b60SDan Kruchinin  * Here we ignore this even/odd difference of status number
268bbaa8b60SDan Kruchinin  * reported by the NSM, we launch notification handlers
269bbaa8b60SDan Kruchinin  * every time the state is changed. The reason we why do so
270bbaa8b60SDan Kruchinin  * is that client and server can talk to each other using
271bbaa8b60SDan Kruchinin  * connectionless transport and it's easy to lose packet
272bbaa8b60SDan Kruchinin  * containing NSM notification with status number update.
273bbaa8b60SDan Kruchinin  *
274bbaa8b60SDan Kruchinin  * In nlm_host_monitor(), we put the sysid in the private data
275bbaa8b60SDan Kruchinin  * that statd carries in this callback, so we can easliy find
276bbaa8b60SDan Kruchinin  * the host this call applies to.
277bbaa8b60SDan Kruchinin  */
278bbaa8b60SDan Kruchinin /* ARGSUSED */
279bbaa8b60SDan Kruchinin void
280bbaa8b60SDan Kruchinin nlm_do_notify1(nlm_sm_status *argp, void *res, struct svc_req *sr)
281bbaa8b60SDan Kruchinin {
282bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
283bbaa8b60SDan Kruchinin 	struct nlm_host *host;
284bbaa8b60SDan Kruchinin 	uint16_t sysid;
285bbaa8b60SDan Kruchinin 
286bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
287bbaa8b60SDan Kruchinin 	bcopy(&argp->priv, &sysid, sizeof (sysid));
288bbaa8b60SDan Kruchinin 
289bbaa8b60SDan Kruchinin 	DTRACE_PROBE2(nsm__notify, uint16_t, sysid,
290bbaa8b60SDan Kruchinin 	    int, argp->state);
291bbaa8b60SDan Kruchinin 
292bbaa8b60SDan Kruchinin 	host = nlm_host_find_by_sysid(g, (sysid_t)sysid);
293bbaa8b60SDan Kruchinin 	if (host == NULL)
294bbaa8b60SDan Kruchinin 		return;
295bbaa8b60SDan Kruchinin 
296bbaa8b60SDan Kruchinin 	nlm_host_notify_server(host, argp->state);
297bbaa8b60SDan Kruchinin 	nlm_host_notify_client(host, argp->state);
298bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
299bbaa8b60SDan Kruchinin }
300bbaa8b60SDan Kruchinin 
301bbaa8b60SDan Kruchinin /*
302bbaa8b60SDan Kruchinin  * Another available call-back for NFS statd.
303bbaa8b60SDan Kruchinin  * Not currently used.
304bbaa8b60SDan Kruchinin  */
305bbaa8b60SDan Kruchinin /* ARGSUSED */
306bbaa8b60SDan Kruchinin void
307bbaa8b60SDan Kruchinin nlm_do_notify2(nlm_sm_status *argp, void *res, struct svc_req *sr)
308bbaa8b60SDan Kruchinin {
309bbaa8b60SDan Kruchinin 	ASSERT(0);
310bbaa8b60SDan Kruchinin }
311bbaa8b60SDan Kruchinin 
312bbaa8b60SDan Kruchinin 
313bbaa8b60SDan Kruchinin /*
314bbaa8b60SDan Kruchinin  * NLM_TEST, NLM_TEST_MSG,
315bbaa8b60SDan Kruchinin  * NLM4_TEST, NLM4_TEST_MSG,
316bbaa8b60SDan Kruchinin  * Client inquiry about locks, non-blocking.
317bbaa8b60SDan Kruchinin  */
318bbaa8b60SDan Kruchinin void
319bbaa8b60SDan Kruchinin nlm_do_test(nlm4_testargs *argp, nlm4_testres *resp,
320bbaa8b60SDan Kruchinin     struct svc_req *sr, nlm_testres_cb cb)
321bbaa8b60SDan Kruchinin {
322bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
323bbaa8b60SDan Kruchinin 	struct nlm_host *host;
324bbaa8b60SDan Kruchinin 	struct nlm4_holder *lh;
325bbaa8b60SDan Kruchinin 	struct nlm_owner_handle *oh;
326bbaa8b60SDan Kruchinin 	nlm_rpc_t *rpcp = NULL;
327bbaa8b60SDan Kruchinin 	vnode_t *vp = NULL;
328bbaa8b60SDan Kruchinin 	struct netbuf *addr;
329bbaa8b60SDan Kruchinin 	char *netid;
330bbaa8b60SDan Kruchinin 	char *name;
331bbaa8b60SDan Kruchinin 	int error;
332bbaa8b60SDan Kruchinin 	struct flock64 fl;
333bbaa8b60SDan Kruchinin 
334bbaa8b60SDan Kruchinin 	nlm_copy_netobj(&resp->cookie, &argp->cookie);
335bbaa8b60SDan Kruchinin 
336bbaa8b60SDan Kruchinin 	name = argp->alock.caller_name;
337bbaa8b60SDan Kruchinin 	netid = svc_getnetid(sr->rq_xprt);
338bbaa8b60SDan Kruchinin 	addr = svc_getrpccaller(sr->rq_xprt);
339bbaa8b60SDan Kruchinin 
340bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
341bbaa8b60SDan Kruchinin 	host = nlm_host_findcreate(g, name, netid, addr);
342bbaa8b60SDan Kruchinin 	if (host == NULL) {
343bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_denied_nolocks;
344bbaa8b60SDan Kruchinin 		return;
345bbaa8b60SDan Kruchinin 	}
346bbaa8b60SDan Kruchinin 	if (cb != NULL) {
347bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
348bbaa8b60SDan Kruchinin 		if (error != 0) {
349bbaa8b60SDan Kruchinin 			resp->stat.stat = nlm4_denied_nolocks;
350bbaa8b60SDan Kruchinin 			goto out;
351bbaa8b60SDan Kruchinin 		}
352bbaa8b60SDan Kruchinin 	}
353bbaa8b60SDan Kruchinin 
354bbaa8b60SDan Kruchinin 	vp = nlm_fh_to_vp(&argp->alock.fh);
355bbaa8b60SDan Kruchinin 	if (vp == NULL) {
356bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_stale_fh;
357bbaa8b60SDan Kruchinin 		goto out;
358bbaa8b60SDan Kruchinin 	}
359bbaa8b60SDan Kruchinin 
360bbaa8b60SDan Kruchinin 	if (NLM_IN_GRACE(g)) {
361bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_denied_grace_period;
362bbaa8b60SDan Kruchinin 		goto out;
363bbaa8b60SDan Kruchinin 	}
364bbaa8b60SDan Kruchinin 
365bbaa8b60SDan Kruchinin 	/* Convert to local form. */
366bbaa8b60SDan Kruchinin 	error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
367bbaa8b60SDan Kruchinin 	    (argp->exclusive) ? F_WRLCK : F_RDLCK);
368bbaa8b60SDan Kruchinin 	if (error) {
369bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_failed;
370bbaa8b60SDan Kruchinin 		goto out;
371bbaa8b60SDan Kruchinin 	}
372bbaa8b60SDan Kruchinin 
373bbaa8b60SDan Kruchinin 	/* BSD: VOP_ADVLOCK(nv->nv_vp, NULL, F_GETLK, &fl, F_REMOTE); */
374bbaa8b60SDan Kruchinin 	error = nlm_vop_frlock(vp, F_GETLK, &fl,
375bbaa8b60SDan Kruchinin 	    F_REMOTELOCK | FREAD | FWRITE,
376bbaa8b60SDan Kruchinin 	    (u_offset_t)0, NULL, CRED(), NULL);
377bbaa8b60SDan Kruchinin 	if (error) {
378bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_failed;
379bbaa8b60SDan Kruchinin 		goto out;
380bbaa8b60SDan Kruchinin 	}
381bbaa8b60SDan Kruchinin 
382bbaa8b60SDan Kruchinin 	if (fl.l_type == F_UNLCK) {
383bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_granted;
384bbaa8b60SDan Kruchinin 		goto out;
385bbaa8b60SDan Kruchinin 	}
386bbaa8b60SDan Kruchinin 	resp->stat.stat = nlm4_denied;
387bbaa8b60SDan Kruchinin 
388bbaa8b60SDan Kruchinin 	/*
389bbaa8b60SDan Kruchinin 	 * This lock "test" fails due to a conflicting lock.
390bbaa8b60SDan Kruchinin 	 *
391bbaa8b60SDan Kruchinin 	 * If this is a v1 client, make sure the conflicting
392bbaa8b60SDan Kruchinin 	 * lock range we report can be expressed with 32-bit
393bbaa8b60SDan Kruchinin 	 * offsets.  The lock range requested was expressed
394bbaa8b60SDan Kruchinin 	 * as 32-bit offset and length, so at least part of
395bbaa8b60SDan Kruchinin 	 * the conflicting lock should lie below MAX_UOFF32.
396bbaa8b60SDan Kruchinin 	 * If the conflicting lock extends past that, we'll
397bbaa8b60SDan Kruchinin 	 * trim the range to end at MAX_UOFF32 so this lock
398bbaa8b60SDan Kruchinin 	 * can be represented in a 32-bit response.  Check
399bbaa8b60SDan Kruchinin 	 * the start also (paranoid, but a low cost check).
400bbaa8b60SDan Kruchinin 	 */
401bbaa8b60SDan Kruchinin 	if (sr->rq_vers < NLM4_VERS) {
402bbaa8b60SDan Kruchinin 		uint64 maxlen;
403bbaa8b60SDan Kruchinin 		if (fl.l_start > MAX_UOFF32)
404bbaa8b60SDan Kruchinin 			fl.l_start = MAX_UOFF32;
405bbaa8b60SDan Kruchinin 		maxlen = MAX_UOFF32 + 1 - fl.l_start;
406bbaa8b60SDan Kruchinin 		if (fl.l_len > maxlen)
407bbaa8b60SDan Kruchinin 			fl.l_len = maxlen;
408bbaa8b60SDan Kruchinin 	}
409bbaa8b60SDan Kruchinin 
410bbaa8b60SDan Kruchinin 	/*
411bbaa8b60SDan Kruchinin 	 * Build the nlm4_holder result structure.
412bbaa8b60SDan Kruchinin 	 *
413bbaa8b60SDan Kruchinin 	 * Note that lh->oh is freed via xdr_free,
414bbaa8b60SDan Kruchinin 	 * xdr_nlm4_holder, xdr_netobj, xdr_bytes.
415bbaa8b60SDan Kruchinin 	 */
416bbaa8b60SDan Kruchinin 	oh = kmem_zalloc(sizeof (*oh), KM_SLEEP);
417bbaa8b60SDan Kruchinin 	oh->oh_sysid = (sysid_t)fl.l_sysid;
418bbaa8b60SDan Kruchinin 	lh = &resp->stat.nlm4_testrply_u.holder;
419bbaa8b60SDan Kruchinin 	lh->exclusive = (fl.l_type == F_WRLCK);
420bbaa8b60SDan Kruchinin 	lh->svid = fl.l_pid;
421bbaa8b60SDan Kruchinin 	lh->oh.n_len = sizeof (*oh);
422bbaa8b60SDan Kruchinin 	lh->oh.n_bytes = (void *)oh;
423bbaa8b60SDan Kruchinin 	lh->l_offset = fl.l_start;
424bbaa8b60SDan Kruchinin 	lh->l_len = fl.l_len;
425bbaa8b60SDan Kruchinin 
426bbaa8b60SDan Kruchinin out:
427bbaa8b60SDan Kruchinin 	/*
42895fa5714SMarcel Telka 	 * If we have a callback function, use that to
429bbaa8b60SDan Kruchinin 	 * deliver the response via another RPC call.
430bbaa8b60SDan Kruchinin 	 */
431bbaa8b60SDan Kruchinin 	if (cb != NULL && rpcp != NULL)
432bbaa8b60SDan Kruchinin 		NLM_INVOKE_CALLBACK("test", rpcp, resp, cb);
433bbaa8b60SDan Kruchinin 
434bbaa8b60SDan Kruchinin 	if (vp != NULL)
435bbaa8b60SDan Kruchinin 		VN_RELE(vp);
436bbaa8b60SDan Kruchinin 	if (rpcp != NULL)
437bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(host, rpcp);
438bbaa8b60SDan Kruchinin 
439bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
440bbaa8b60SDan Kruchinin }
441bbaa8b60SDan Kruchinin 
442bbaa8b60SDan Kruchinin /*
443bbaa8b60SDan Kruchinin  * NLM_LOCK, NLM_LOCK_MSG, NLM_NM_LOCK
444bbaa8b60SDan Kruchinin  * NLM4_LOCK, NLM4_LOCK_MSG, NLM4_NM_LOCK
445bbaa8b60SDan Kruchinin  *
446bbaa8b60SDan Kruchinin  * Client request to set a lock, possibly blocking.
447bbaa8b60SDan Kruchinin  *
448bbaa8b60SDan Kruchinin  * If the lock needs to block, we return status blocked to
449bbaa8b60SDan Kruchinin  * this RPC call, and then later call back the client with
450bbaa8b60SDan Kruchinin  * a "granted" callback.  Tricky aspects of this include:
451bbaa8b60SDan Kruchinin  * sending a reply before this function returns, and then
452bbaa8b60SDan Kruchinin  * borrowing this thread from the RPC service pool for the
453bbaa8b60SDan Kruchinin  * wait on the lock and doing the later granted callback.
454bbaa8b60SDan Kruchinin  *
455bbaa8b60SDan Kruchinin  * We also have to keep a list of locks (pending + granted)
456bbaa8b60SDan Kruchinin  * both to handle retransmitted requests, and to keep the
457bbaa8b60SDan Kruchinin  * vnodes for those locks active.
458bbaa8b60SDan Kruchinin  */
459bbaa8b60SDan Kruchinin void
460bbaa8b60SDan Kruchinin nlm_do_lock(nlm4_lockargs *argp, nlm4_res *resp, struct svc_req *sr,
461bbaa8b60SDan Kruchinin     nlm_reply_cb reply_cb, nlm_res_cb res_cb, nlm_testargs_cb grant_cb)
462bbaa8b60SDan Kruchinin {
463bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
464bbaa8b60SDan Kruchinin 	struct flock64 fl;
465bbaa8b60SDan Kruchinin 	struct nlm_host *host = NULL;
466bbaa8b60SDan Kruchinin 	struct netbuf *addr;
467bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp = NULL;
468bbaa8b60SDan Kruchinin 	nlm_rpc_t *rpcp = NULL;
469bbaa8b60SDan Kruchinin 	char *netid;
470bbaa8b60SDan Kruchinin 	char *name;
471bbaa8b60SDan Kruchinin 	int error, flags;
472bbaa8b60SDan Kruchinin 	bool_t do_blocking = FALSE;
473bbaa8b60SDan Kruchinin 	bool_t do_mon_req = FALSE;
474bbaa8b60SDan Kruchinin 	enum nlm4_stats status;
475bbaa8b60SDan Kruchinin 
476bbaa8b60SDan Kruchinin 	nlm_copy_netobj(&resp->cookie, &argp->cookie);
477bbaa8b60SDan Kruchinin 
478bbaa8b60SDan Kruchinin 	name = argp->alock.caller_name;
479bbaa8b60SDan Kruchinin 	netid = svc_getnetid(sr->rq_xprt);
480bbaa8b60SDan Kruchinin 	addr = svc_getrpccaller(sr->rq_xprt);
481bbaa8b60SDan Kruchinin 
482bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
483bbaa8b60SDan Kruchinin 	host = nlm_host_findcreate(g, name, netid, addr);
484bbaa8b60SDan Kruchinin 	if (host == NULL) {
485bbaa8b60SDan Kruchinin 		DTRACE_PROBE4(no__host, struct nlm_globals *, g,
486bbaa8b60SDan Kruchinin 		    char *, name, char *, netid, struct netbuf *, addr);
487bbaa8b60SDan Kruchinin 		status = nlm4_denied_nolocks;
488bbaa8b60SDan Kruchinin 		goto doreply;
489bbaa8b60SDan Kruchinin 	}
490bbaa8b60SDan Kruchinin 
491bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(start, struct nlm_globals *, g,
492bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_lockargs *, argp);
493bbaa8b60SDan Kruchinin 
494bbaa8b60SDan Kruchinin 	/*
495bbaa8b60SDan Kruchinin 	 * If we may need to do _msg_ call needing an RPC
496bbaa8b60SDan Kruchinin 	 * callback, get the RPC client handle now,
497bbaa8b60SDan Kruchinin 	 * so we know if we can bind to the NLM service on
498bbaa8b60SDan Kruchinin 	 * this client.
499bbaa8b60SDan Kruchinin 	 *
500bbaa8b60SDan Kruchinin 	 * Note: host object carries transport type.
501bbaa8b60SDan Kruchinin 	 * One client using multiple transports gets
502bbaa8b60SDan Kruchinin 	 * separate sysids for each of its transports.
503bbaa8b60SDan Kruchinin 	 */
504bbaa8b60SDan Kruchinin 	if (res_cb != NULL || (grant_cb != NULL && argp->block == TRUE)) {
505bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
506bbaa8b60SDan Kruchinin 		if (error != 0) {
507bbaa8b60SDan Kruchinin 			status = nlm4_denied_nolocks;
508bbaa8b60SDan Kruchinin 			goto doreply;
509bbaa8b60SDan Kruchinin 		}
510bbaa8b60SDan Kruchinin 	}
511bbaa8b60SDan Kruchinin 
512bbaa8b60SDan Kruchinin 	/*
513bbaa8b60SDan Kruchinin 	 * During the "grace period", only allow reclaim.
514bbaa8b60SDan Kruchinin 	 */
515bbaa8b60SDan Kruchinin 	if (argp->reclaim == 0 && NLM_IN_GRACE(g)) {
516bbaa8b60SDan Kruchinin 		status = nlm4_denied_grace_period;
517bbaa8b60SDan Kruchinin 		goto doreply;
518bbaa8b60SDan Kruchinin 	}
519bbaa8b60SDan Kruchinin 
520bbaa8b60SDan Kruchinin 	/*
521bbaa8b60SDan Kruchinin 	 * Check whether we missed host shutdown event
522bbaa8b60SDan Kruchinin 	 */
523bbaa8b60SDan Kruchinin 	if (nlm_host_get_state(host) != argp->state)
524bbaa8b60SDan Kruchinin 		nlm_host_notify_server(host, argp->state);
525bbaa8b60SDan Kruchinin 
526bbaa8b60SDan Kruchinin 	/*
527bbaa8b60SDan Kruchinin 	 * Get a hold on the vnode for a lock operation.
528bbaa8b60SDan Kruchinin 	 * Only lock() and share() need vhold objects.
529bbaa8b60SDan Kruchinin 	 */
530bbaa8b60SDan Kruchinin 	nvp = nlm_fh_to_vhold(host, &argp->alock.fh);
531bbaa8b60SDan Kruchinin 	if (nvp == NULL) {
532bbaa8b60SDan Kruchinin 		status = nlm4_stale_fh;
533bbaa8b60SDan Kruchinin 		goto doreply;
534bbaa8b60SDan Kruchinin 	}
535bbaa8b60SDan Kruchinin 
536bbaa8b60SDan Kruchinin 	/* Convert to local form. */
537bbaa8b60SDan Kruchinin 	error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
538bbaa8b60SDan Kruchinin 	    (argp->exclusive) ? F_WRLCK : F_RDLCK);
539bbaa8b60SDan Kruchinin 	if (error) {
540bbaa8b60SDan Kruchinin 		status = nlm4_failed;
541bbaa8b60SDan Kruchinin 		goto doreply;
542bbaa8b60SDan Kruchinin 	}
543bbaa8b60SDan Kruchinin 
544bbaa8b60SDan Kruchinin 	/*
545bbaa8b60SDan Kruchinin 	 * Try to lock non-blocking first.  If we succeed
546bbaa8b60SDan Kruchinin 	 * getting the lock, we can reply with the granted
547bbaa8b60SDan Kruchinin 	 * status directly and avoid the complications of
548bbaa8b60SDan Kruchinin 	 * making the "granted" RPC callback later.
549bbaa8b60SDan Kruchinin 	 *
550bbaa8b60SDan Kruchinin 	 * This also let's us find out now about some
551bbaa8b60SDan Kruchinin 	 * possible errors like EROFS, etc.
552bbaa8b60SDan Kruchinin 	 */
553bbaa8b60SDan Kruchinin 	flags = F_REMOTELOCK | FREAD | FWRITE;
554bbaa8b60SDan Kruchinin 	error = nlm_vop_frlock(nvp->nv_vp, F_SETLK, &fl, flags,
555bbaa8b60SDan Kruchinin 	    (u_offset_t)0, NULL, CRED(), NULL);
556bbaa8b60SDan Kruchinin 
557bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(setlk__res, struct flock64 *, &fl,
558bbaa8b60SDan Kruchinin 	    int, flags, int, error);
559bbaa8b60SDan Kruchinin 
560bbaa8b60SDan Kruchinin 	switch (error) {
561bbaa8b60SDan Kruchinin 	case 0:
562bbaa8b60SDan Kruchinin 		/* Got it without waiting! */
563bbaa8b60SDan Kruchinin 		status = nlm4_granted;
564bbaa8b60SDan Kruchinin 		do_mon_req = TRUE;
565bbaa8b60SDan Kruchinin 		break;
566bbaa8b60SDan Kruchinin 
567bbaa8b60SDan Kruchinin 	/* EINPROGRESS too? */
568bbaa8b60SDan Kruchinin 	case EAGAIN:
569bbaa8b60SDan Kruchinin 		/* We did not get the lock. Should we block? */
570bbaa8b60SDan Kruchinin 		if (argp->block == FALSE || grant_cb == NULL) {
571bbaa8b60SDan Kruchinin 			status = nlm4_denied;
572bbaa8b60SDan Kruchinin 			break;
573bbaa8b60SDan Kruchinin 		}
574bbaa8b60SDan Kruchinin 		/*
575bbaa8b60SDan Kruchinin 		 * Should block.  Try to reserve this thread
576bbaa8b60SDan Kruchinin 		 * so we can use it to wait for the lock and
577bbaa8b60SDan Kruchinin 		 * later send the granted message.  If this
578bbaa8b60SDan Kruchinin 		 * reservation fails, say "no resources".
579bbaa8b60SDan Kruchinin 		 */
580bbaa8b60SDan Kruchinin 		if (!svc_reserve_thread(sr->rq_xprt)) {
581bbaa8b60SDan Kruchinin 			status = nlm4_denied_nolocks;
582bbaa8b60SDan Kruchinin 			break;
583bbaa8b60SDan Kruchinin 		}
584bbaa8b60SDan Kruchinin 		/*
585bbaa8b60SDan Kruchinin 		 * OK, can detach this thread, so this call
586bbaa8b60SDan Kruchinin 		 * will block below (after we reply).
587bbaa8b60SDan Kruchinin 		 */
588bbaa8b60SDan Kruchinin 		status = nlm4_blocked;
589bbaa8b60SDan Kruchinin 		do_blocking = TRUE;
590bbaa8b60SDan Kruchinin 		do_mon_req = TRUE;
591bbaa8b60SDan Kruchinin 		break;
592bbaa8b60SDan Kruchinin 
593bbaa8b60SDan Kruchinin 	case ENOLCK:
594bbaa8b60SDan Kruchinin 		/* Failed for lack of resources. */
595bbaa8b60SDan Kruchinin 		status = nlm4_denied_nolocks;
596bbaa8b60SDan Kruchinin 		break;
597bbaa8b60SDan Kruchinin 
598bbaa8b60SDan Kruchinin 	case EROFS:
599bbaa8b60SDan Kruchinin 		/* read-only file system */
600bbaa8b60SDan Kruchinin 		status = nlm4_rofs;
601bbaa8b60SDan Kruchinin 		break;
602bbaa8b60SDan Kruchinin 
603bbaa8b60SDan Kruchinin 	case EFBIG:
604bbaa8b60SDan Kruchinin 		/* file too big */
605bbaa8b60SDan Kruchinin 		status = nlm4_fbig;
606bbaa8b60SDan Kruchinin 		break;
607bbaa8b60SDan Kruchinin 
608bbaa8b60SDan Kruchinin 	case EDEADLK:
609bbaa8b60SDan Kruchinin 		/* dead lock condition */
610bbaa8b60SDan Kruchinin 		status = nlm4_deadlck;
611bbaa8b60SDan Kruchinin 		break;
612bbaa8b60SDan Kruchinin 
613bbaa8b60SDan Kruchinin 	default:
614bbaa8b60SDan Kruchinin 		status = nlm4_denied;
615bbaa8b60SDan Kruchinin 		break;
616bbaa8b60SDan Kruchinin 	}
617bbaa8b60SDan Kruchinin 
618bbaa8b60SDan Kruchinin doreply:
619bbaa8b60SDan Kruchinin 	resp->stat.stat = status;
620bbaa8b60SDan Kruchinin 
621bbaa8b60SDan Kruchinin 	/*
622bbaa8b60SDan Kruchinin 	 * We get one of two function pointers; one for a
623bbaa8b60SDan Kruchinin 	 * normal RPC reply, and another for doing an RPC
624bbaa8b60SDan Kruchinin 	 * "callback" _res reply for a _msg function.
625bbaa8b60SDan Kruchinin 	 * Use either of those to send the reply now.
626bbaa8b60SDan Kruchinin 	 *
627bbaa8b60SDan Kruchinin 	 * If sending this reply fails, just leave the
628bbaa8b60SDan Kruchinin 	 * lock in the list for retransmitted requests.
629bbaa8b60SDan Kruchinin 	 * Cleanup is via unlock or host rele (statmon).
630bbaa8b60SDan Kruchinin 	 */
631bbaa8b60SDan Kruchinin 	if (reply_cb != NULL) {
632bbaa8b60SDan Kruchinin 		/* i.e. nlm_lock_1_reply */
633bbaa8b60SDan Kruchinin 		if (!(*reply_cb)(sr->rq_xprt, resp))
634bbaa8b60SDan Kruchinin 			svcerr_systemerr(sr->rq_xprt);
635bbaa8b60SDan Kruchinin 	}
636bbaa8b60SDan Kruchinin 	if (res_cb != NULL && rpcp != NULL)
637bbaa8b60SDan Kruchinin 		NLM_INVOKE_CALLBACK("lock", rpcp, resp, res_cb);
638bbaa8b60SDan Kruchinin 
639bbaa8b60SDan Kruchinin 	/*
640bbaa8b60SDan Kruchinin 	 * The reply has been sent to the client.
641bbaa8b60SDan Kruchinin 	 * Start monitoring this client (maybe).
642bbaa8b60SDan Kruchinin 	 *
643bbaa8b60SDan Kruchinin 	 * Note that the non-monitored (NM) calls pass grant_cb=NULL
644bbaa8b60SDan Kruchinin 	 * indicating that the client doesn't support RPC callbacks.
645bbaa8b60SDan Kruchinin 	 * No monitoring for these (lame) clients.
646bbaa8b60SDan Kruchinin 	 */
647bbaa8b60SDan Kruchinin 	if (do_mon_req && grant_cb != NULL)
648bbaa8b60SDan Kruchinin 		nlm_host_monitor(g, host, argp->state);
649bbaa8b60SDan Kruchinin 
650bbaa8b60SDan Kruchinin 	if (do_blocking) {
651bbaa8b60SDan Kruchinin 		/*
652bbaa8b60SDan Kruchinin 		 * We need to block on this lock, and when that
653bbaa8b60SDan Kruchinin 		 * completes, do the granted RPC call. Note that
654bbaa8b60SDan Kruchinin 		 * we "reserved" this thread above, so we can now
655bbaa8b60SDan Kruchinin 		 * "detach" it from the RPC SVC pool, allowing it
656bbaa8b60SDan Kruchinin 		 * to block indefinitely if needed.
657bbaa8b60SDan Kruchinin 		 */
658bbaa8b60SDan Kruchinin 		ASSERT(rpcp != NULL);
659bbaa8b60SDan Kruchinin 		(void) svc_detach_thread(sr->rq_xprt);
660bbaa8b60SDan Kruchinin 		nlm_block(argp, host, nvp, rpcp, &fl, grant_cb);
661bbaa8b60SDan Kruchinin 	}
662bbaa8b60SDan Kruchinin 
663bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(lock__end, struct nlm_globals *, g,
664bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_res *, resp);
665bbaa8b60SDan Kruchinin 
666bbaa8b60SDan Kruchinin 	if (rpcp != NULL)
667bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(host, rpcp);
668bbaa8b60SDan Kruchinin 
669bbaa8b60SDan Kruchinin 	nlm_vhold_release(host, nvp);
670bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
671bbaa8b60SDan Kruchinin }
672bbaa8b60SDan Kruchinin 
673bbaa8b60SDan Kruchinin /*
674bbaa8b60SDan Kruchinin  * Helper for nlm_do_lock(), partly for observability,
675bbaa8b60SDan Kruchinin  * (we'll see a call blocked in this function) and
676bbaa8b60SDan Kruchinin  * because nlm_do_lock() was getting quite long.
677bbaa8b60SDan Kruchinin  */
678bbaa8b60SDan Kruchinin static void
679bbaa8b60SDan Kruchinin nlm_block(nlm4_lockargs *lockargs,
680bbaa8b60SDan Kruchinin     struct nlm_host *host,
681bbaa8b60SDan Kruchinin     struct nlm_vhold *nvp,
682bbaa8b60SDan Kruchinin     nlm_rpc_t *rpcp,
683bbaa8b60SDan Kruchinin     struct flock64 *flp,
684bbaa8b60SDan Kruchinin     nlm_testargs_cb grant_cb)
685bbaa8b60SDan Kruchinin {
686bbaa8b60SDan Kruchinin 	nlm4_testargs args;
687bbaa8b60SDan Kruchinin 	int error;
688bbaa8b60SDan Kruchinin 	flk_callback_t flk_cb;
689bbaa8b60SDan Kruchinin 	struct nlm_block_cb_data cb_data;
690bbaa8b60SDan Kruchinin 
691bbaa8b60SDan Kruchinin 	/*
692bbaa8b60SDan Kruchinin 	 * Keep a list of blocked locks on nh_pending, and use it
693bbaa8b60SDan Kruchinin 	 * to cancel these threads in nlm_destroy_client_pending.
694bbaa8b60SDan Kruchinin 	 *
695bbaa8b60SDan Kruchinin 	 * Check to see if this lock is already in the list
696bbaa8b60SDan Kruchinin 	 * and if not, add an entry for it.  Allocate first,
697bbaa8b60SDan Kruchinin 	 * then if we don't insert, free the new one.
698bbaa8b60SDan Kruchinin 	 * Caller already has vp held.
699bbaa8b60SDan Kruchinin 	 */
700bbaa8b60SDan Kruchinin 
701bbaa8b60SDan Kruchinin 	error = nlm_slreq_register(host, nvp, flp);
702bbaa8b60SDan Kruchinin 	if (error != 0) {
703bbaa8b60SDan Kruchinin 		/*
704bbaa8b60SDan Kruchinin 		 * Sleeping lock request with given fl is already
705bbaa8b60SDan Kruchinin 		 * registered by someone else. This means that
706bbaa8b60SDan Kruchinin 		 * some other thread is handling the request, let
707bbaa8b60SDan Kruchinin 		 * him to do its work.
708bbaa8b60SDan Kruchinin 		 */
709bbaa8b60SDan Kruchinin 		ASSERT(error == EEXIST);
710bbaa8b60SDan Kruchinin 		return;
711bbaa8b60SDan Kruchinin 	}
712bbaa8b60SDan Kruchinin 
713bbaa8b60SDan Kruchinin 	cb_data.hostp = host;
714bbaa8b60SDan Kruchinin 	cb_data.nvp = nvp;
715bbaa8b60SDan Kruchinin 	cb_data.flp = flp;
716bbaa8b60SDan Kruchinin 	flk_init_callback(&flk_cb, nlm_block_callback, &cb_data);
717bbaa8b60SDan Kruchinin 
718bbaa8b60SDan Kruchinin 	/* BSD: VOP_ADVLOCK(vp, NULL, F_SETLK, fl, F_REMOTE); */
719bbaa8b60SDan Kruchinin 	error = nlm_vop_frlock(nvp->nv_vp, F_SETLKW, flp,
720bbaa8b60SDan Kruchinin 	    F_REMOTELOCK | FREAD | FWRITE,
721bbaa8b60SDan Kruchinin 	    (u_offset_t)0, &flk_cb, CRED(), NULL);
722bbaa8b60SDan Kruchinin 
723bbaa8b60SDan Kruchinin 	if (error != 0) {
724bbaa8b60SDan Kruchinin 		/*
725bbaa8b60SDan Kruchinin 		 * We failed getting the lock, but have no way to
726bbaa8b60SDan Kruchinin 		 * tell the client about that.  Let 'em time out.
727bbaa8b60SDan Kruchinin 		 */
728bbaa8b60SDan Kruchinin 		(void) nlm_slreq_unregister(host, nvp, flp);
729bbaa8b60SDan Kruchinin 		return;
730bbaa8b60SDan Kruchinin 	}
731bbaa8b60SDan Kruchinin 
732bbaa8b60SDan Kruchinin 	/*
733bbaa8b60SDan Kruchinin 	 * Do the "granted" call-back to the client.
734bbaa8b60SDan Kruchinin 	 */
735bbaa8b60SDan Kruchinin 	args.cookie	= lockargs->cookie;
736bbaa8b60SDan Kruchinin 	args.exclusive	= lockargs->exclusive;
737bbaa8b60SDan Kruchinin 	args.alock	= lockargs->alock;
738bbaa8b60SDan Kruchinin 
739bbaa8b60SDan Kruchinin 	NLM_INVOKE_CALLBACK("grant", rpcp, &args, grant_cb);
740bbaa8b60SDan Kruchinin }
741bbaa8b60SDan Kruchinin 
742bbaa8b60SDan Kruchinin /*
743bbaa8b60SDan Kruchinin  * The function that is used as flk callback when NLM server
744bbaa8b60SDan Kruchinin  * sets new sleeping lock. The function unregisters NLM
745bbaa8b60SDan Kruchinin  * sleeping lock request (nlm_slreq) associated with the
746bbaa8b60SDan Kruchinin  * sleeping lock _before_ lock becomes active. It prevents
747bbaa8b60SDan Kruchinin  * potential race condition between nlm_block() and
748bbaa8b60SDan Kruchinin  * nlm_do_cancel().
749bbaa8b60SDan Kruchinin  */
750bbaa8b60SDan Kruchinin static callb_cpr_t *
751bbaa8b60SDan Kruchinin nlm_block_callback(flk_cb_when_t when, void *data)
752bbaa8b60SDan Kruchinin {
753bbaa8b60SDan Kruchinin 	struct nlm_block_cb_data *cb_data;
754bbaa8b60SDan Kruchinin 
755bbaa8b60SDan Kruchinin 	cb_data = (struct nlm_block_cb_data *)data;
756bbaa8b60SDan Kruchinin 	if (when == FLK_AFTER_SLEEP) {
757bbaa8b60SDan Kruchinin 		(void) nlm_slreq_unregister(cb_data->hostp,
758bbaa8b60SDan Kruchinin 		    cb_data->nvp, cb_data->flp);
759bbaa8b60SDan Kruchinin 	}
760bbaa8b60SDan Kruchinin 
761bbaa8b60SDan Kruchinin 	return (0);
762bbaa8b60SDan Kruchinin }
763bbaa8b60SDan Kruchinin 
764bbaa8b60SDan Kruchinin /*
765bbaa8b60SDan Kruchinin  * NLM_CANCEL, NLM_CANCEL_MSG,
766bbaa8b60SDan Kruchinin  * NLM4_CANCEL, NLM4_CANCEL_MSG,
767bbaa8b60SDan Kruchinin  * Client gives up waiting for a blocking lock.
768bbaa8b60SDan Kruchinin  */
769bbaa8b60SDan Kruchinin void
770bbaa8b60SDan Kruchinin nlm_do_cancel(nlm4_cancargs *argp, nlm4_res *resp,
771bbaa8b60SDan Kruchinin     struct svc_req *sr, nlm_res_cb cb)
772bbaa8b60SDan Kruchinin {
773bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
774bbaa8b60SDan Kruchinin 	struct nlm_host *host;
775bbaa8b60SDan Kruchinin 	struct netbuf *addr;
776bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp = NULL;
777bbaa8b60SDan Kruchinin 	nlm_rpc_t *rpcp = NULL;
778bbaa8b60SDan Kruchinin 	char *netid;
779bbaa8b60SDan Kruchinin 	char *name;
780bbaa8b60SDan Kruchinin 	int error;
781bbaa8b60SDan Kruchinin 	struct flock64 fl;
782bbaa8b60SDan Kruchinin 
783bbaa8b60SDan Kruchinin 	nlm_copy_netobj(&resp->cookie, &argp->cookie);
784bbaa8b60SDan Kruchinin 	netid = svc_getnetid(sr->rq_xprt);
785bbaa8b60SDan Kruchinin 	addr = svc_getrpccaller(sr->rq_xprt);
786bbaa8b60SDan Kruchinin 	name = argp->alock.caller_name;
787bbaa8b60SDan Kruchinin 
788bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
789bbaa8b60SDan Kruchinin 	host = nlm_host_findcreate(g, name, netid, addr);
790bbaa8b60SDan Kruchinin 	if (host == NULL) {
791bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_denied_nolocks;
792bbaa8b60SDan Kruchinin 		return;
793bbaa8b60SDan Kruchinin 	}
794bbaa8b60SDan Kruchinin 	if (cb != NULL) {
795bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
796bbaa8b60SDan Kruchinin 		if (error != 0) {
797bbaa8b60SDan Kruchinin 			resp->stat.stat = nlm4_denied_nolocks;
798*310a15feSMarcel Telka 			goto out;
799bbaa8b60SDan Kruchinin 		}
800bbaa8b60SDan Kruchinin 	}
801bbaa8b60SDan Kruchinin 
802bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(start, struct nlm_globals *, g,
803bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_cancargs *, argp);
804bbaa8b60SDan Kruchinin 
805bbaa8b60SDan Kruchinin 	if (NLM_IN_GRACE(g)) {
806bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_denied_grace_period;
807bbaa8b60SDan Kruchinin 		goto out;
808bbaa8b60SDan Kruchinin 	}
809bbaa8b60SDan Kruchinin 
810bbaa8b60SDan Kruchinin 	nvp = nlm_fh_to_vhold(host, &argp->alock.fh);
811bbaa8b60SDan Kruchinin 	if (nvp == NULL) {
812bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_stale_fh;
813bbaa8b60SDan Kruchinin 		goto out;
814bbaa8b60SDan Kruchinin 	}
815bbaa8b60SDan Kruchinin 
816bbaa8b60SDan Kruchinin 	/* Convert to local form. */
817bbaa8b60SDan Kruchinin 	error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers,
818bbaa8b60SDan Kruchinin 	    (argp->exclusive) ? F_WRLCK : F_RDLCK);
819bbaa8b60SDan Kruchinin 	if (error) {
820bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_failed;
821bbaa8b60SDan Kruchinin 		goto out;
822bbaa8b60SDan Kruchinin 	}
823bbaa8b60SDan Kruchinin 
824bbaa8b60SDan Kruchinin 	error = nlm_slreq_unregister(host, nvp, &fl);
825bbaa8b60SDan Kruchinin 	if (error != 0) {
826bbaa8b60SDan Kruchinin 		/*
827bbaa8b60SDan Kruchinin 		 * There's no sleeping lock request corresponding
828bbaa8b60SDan Kruchinin 		 * to the lock. Then requested sleeping lock
829bbaa8b60SDan Kruchinin 		 * doesn't exist.
830bbaa8b60SDan Kruchinin 		 */
831bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_denied;
832bbaa8b60SDan Kruchinin 		goto out;
833bbaa8b60SDan Kruchinin 	}
834bbaa8b60SDan Kruchinin 
835bbaa8b60SDan Kruchinin 	fl.l_type = F_UNLCK;
836bbaa8b60SDan Kruchinin 	error = nlm_vop_frlock(nvp->nv_vp, F_SETLK, &fl,
837bbaa8b60SDan Kruchinin 	    F_REMOTELOCK | FREAD | FWRITE,
838bbaa8b60SDan Kruchinin 	    (u_offset_t)0, NULL, CRED(), NULL);
839bbaa8b60SDan Kruchinin 
840bbaa8b60SDan Kruchinin 	resp->stat.stat = (error == 0) ?
841bbaa8b60SDan Kruchinin 	    nlm4_granted : nlm4_denied;
842bbaa8b60SDan Kruchinin 
843bbaa8b60SDan Kruchinin out:
844bbaa8b60SDan Kruchinin 	/*
84595fa5714SMarcel Telka 	 * If we have a callback function, use that to
846bbaa8b60SDan Kruchinin 	 * deliver the response via another RPC call.
847bbaa8b60SDan Kruchinin 	 */
848bbaa8b60SDan Kruchinin 	if (cb != NULL && rpcp != NULL)
849bbaa8b60SDan Kruchinin 		NLM_INVOKE_CALLBACK("cancel", rpcp, resp, cb);
850bbaa8b60SDan Kruchinin 
851bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(cancel__end, struct nlm_globals *, g,
852bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_res *, resp);
853bbaa8b60SDan Kruchinin 
854bbaa8b60SDan Kruchinin 	if (rpcp != NULL)
855bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(host, rpcp);
856bbaa8b60SDan Kruchinin 
857bbaa8b60SDan Kruchinin 	nlm_vhold_release(host, nvp);
858bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
859bbaa8b60SDan Kruchinin }
860bbaa8b60SDan Kruchinin 
861bbaa8b60SDan Kruchinin /*
862bbaa8b60SDan Kruchinin  * NLM_UNLOCK, NLM_UNLOCK_MSG,
863bbaa8b60SDan Kruchinin  * NLM4_UNLOCK, NLM4_UNLOCK_MSG,
864bbaa8b60SDan Kruchinin  * Client removes one of their locks.
865bbaa8b60SDan Kruchinin  */
866bbaa8b60SDan Kruchinin void
867bbaa8b60SDan Kruchinin nlm_do_unlock(nlm4_unlockargs *argp, nlm4_res *resp,
868bbaa8b60SDan Kruchinin     struct svc_req *sr, nlm_res_cb cb)
869bbaa8b60SDan Kruchinin {
870bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
871bbaa8b60SDan Kruchinin 	struct nlm_host *host;
872bbaa8b60SDan Kruchinin 	struct netbuf *addr;
873bbaa8b60SDan Kruchinin 	nlm_rpc_t *rpcp = NULL;
874bbaa8b60SDan Kruchinin 	vnode_t *vp = NULL;
875bbaa8b60SDan Kruchinin 	char *netid;
876bbaa8b60SDan Kruchinin 	char *name;
877bbaa8b60SDan Kruchinin 	int error;
878bbaa8b60SDan Kruchinin 	struct flock64 fl;
879bbaa8b60SDan Kruchinin 
880bbaa8b60SDan Kruchinin 	nlm_copy_netobj(&resp->cookie, &argp->cookie);
881bbaa8b60SDan Kruchinin 
882bbaa8b60SDan Kruchinin 	netid = svc_getnetid(sr->rq_xprt);
883bbaa8b60SDan Kruchinin 	addr = svc_getrpccaller(sr->rq_xprt);
884bbaa8b60SDan Kruchinin 	name = argp->alock.caller_name;
885bbaa8b60SDan Kruchinin 
886bbaa8b60SDan Kruchinin 	/*
887bbaa8b60SDan Kruchinin 	 * NLM_UNLOCK operation doesn't have an error code
888bbaa8b60SDan Kruchinin 	 * denoting that operation failed, so we always
889bbaa8b60SDan Kruchinin 	 * return nlm4_granted except when the server is
890bbaa8b60SDan Kruchinin 	 * in a grace period.
891bbaa8b60SDan Kruchinin 	 */
892bbaa8b60SDan Kruchinin 	resp->stat.stat = nlm4_granted;
893bbaa8b60SDan Kruchinin 
894bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
895bbaa8b60SDan Kruchinin 	host = nlm_host_findcreate(g, name, netid, addr);
896bbaa8b60SDan Kruchinin 	if (host == NULL)
897bbaa8b60SDan Kruchinin 		return;
898bbaa8b60SDan Kruchinin 
899bbaa8b60SDan Kruchinin 	if (cb != NULL) {
900bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
901bbaa8b60SDan Kruchinin 		if (error != 0)
902bbaa8b60SDan Kruchinin 			goto out;
903bbaa8b60SDan Kruchinin 	}
904bbaa8b60SDan Kruchinin 
905bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(start, struct nlm_globals *, g,
906bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_unlockargs *, argp);
907bbaa8b60SDan Kruchinin 
908bbaa8b60SDan Kruchinin 	if (NLM_IN_GRACE(g)) {
909bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_denied_grace_period;
910bbaa8b60SDan Kruchinin 		goto out;
911bbaa8b60SDan Kruchinin 	}
912bbaa8b60SDan Kruchinin 
913bbaa8b60SDan Kruchinin 	vp = nlm_fh_to_vp(&argp->alock.fh);
914bbaa8b60SDan Kruchinin 	if (vp == NULL)
915bbaa8b60SDan Kruchinin 		goto out;
916bbaa8b60SDan Kruchinin 
917bbaa8b60SDan Kruchinin 	/* Convert to local form. */
918bbaa8b60SDan Kruchinin 	error = nlm_init_flock(&fl, &argp->alock, host, sr->rq_vers, F_UNLCK);
919bbaa8b60SDan Kruchinin 	if (error)
920bbaa8b60SDan Kruchinin 		goto out;
921bbaa8b60SDan Kruchinin 
922bbaa8b60SDan Kruchinin 	/* BSD: VOP_ADVLOCK(nv->nv_vp, NULL, F_UNLCK, &fl, F_REMOTE); */
923bbaa8b60SDan Kruchinin 	error = nlm_vop_frlock(vp, F_SETLK, &fl,
924bbaa8b60SDan Kruchinin 	    F_REMOTELOCK | FREAD | FWRITE,
925bbaa8b60SDan Kruchinin 	    (u_offset_t)0, NULL, CRED(), NULL);
926bbaa8b60SDan Kruchinin 
927bbaa8b60SDan Kruchinin 	DTRACE_PROBE1(unlock__res, int, error);
928bbaa8b60SDan Kruchinin out:
929bbaa8b60SDan Kruchinin 	/*
93095fa5714SMarcel Telka 	 * If we have a callback function, use that to
931bbaa8b60SDan Kruchinin 	 * deliver the response via another RPC call.
932bbaa8b60SDan Kruchinin 	 */
933bbaa8b60SDan Kruchinin 	if (cb != NULL && rpcp != NULL)
934bbaa8b60SDan Kruchinin 		NLM_INVOKE_CALLBACK("unlock", rpcp, resp, cb);
935bbaa8b60SDan Kruchinin 
936bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(unlock__end, struct nlm_globals *, g,
937bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_res *, resp);
938bbaa8b60SDan Kruchinin 
939bbaa8b60SDan Kruchinin 	if (vp != NULL)
940bbaa8b60SDan Kruchinin 		VN_RELE(vp);
941bbaa8b60SDan Kruchinin 	if (rpcp != NULL)
942bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(host, rpcp);
943bbaa8b60SDan Kruchinin 
944bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
945bbaa8b60SDan Kruchinin }
946bbaa8b60SDan Kruchinin 
947bbaa8b60SDan Kruchinin /*
948bbaa8b60SDan Kruchinin  * NLM_GRANTED, NLM_GRANTED_MSG,
949bbaa8b60SDan Kruchinin  * NLM4_GRANTED, NLM4_GRANTED_MSG,
950bbaa8b60SDan Kruchinin  *
951bbaa8b60SDan Kruchinin  * This service routine is special.  It's the only one that's
952bbaa8b60SDan Kruchinin  * really part of our NLM _client_ support, used by _servers_
953bbaa8b60SDan Kruchinin  * to "call back" when a blocking lock from this NLM client
954bbaa8b60SDan Kruchinin  * is granted by the server.  In this case, we _know_ there is
955bbaa8b60SDan Kruchinin  * already an nlm_host allocated and held by the client code.
956bbaa8b60SDan Kruchinin  * We want to find that nlm_host here.
957bbaa8b60SDan Kruchinin  *
958bbaa8b60SDan Kruchinin  * Over in nlm_call_lock(), the client encoded the sysid for this
959bbaa8b60SDan Kruchinin  * server in the "owner handle" netbuf sent with our lock request.
960bbaa8b60SDan Kruchinin  * We can now use that to find the nlm_host object we used there.
961bbaa8b60SDan Kruchinin  * (NB: The owner handle is opaque to the server.)
962bbaa8b60SDan Kruchinin  */
963bbaa8b60SDan Kruchinin void
964bbaa8b60SDan Kruchinin nlm_do_granted(nlm4_testargs *argp, nlm4_res *resp,
965bbaa8b60SDan Kruchinin     struct svc_req *sr, nlm_res_cb cb)
966bbaa8b60SDan Kruchinin {
967bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
968bbaa8b60SDan Kruchinin 	struct nlm_owner_handle *oh;
969bbaa8b60SDan Kruchinin 	struct nlm_host *host;
970bbaa8b60SDan Kruchinin 	nlm_rpc_t *rpcp = NULL;
971bbaa8b60SDan Kruchinin 	int error;
972bbaa8b60SDan Kruchinin 
973bbaa8b60SDan Kruchinin 	nlm_copy_netobj(&resp->cookie, &argp->cookie);
974bbaa8b60SDan Kruchinin 	resp->stat.stat = nlm4_denied;
975bbaa8b60SDan Kruchinin 
976bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
977bbaa8b60SDan Kruchinin 	oh = (void *) argp->alock.oh.n_bytes;
978bbaa8b60SDan Kruchinin 	if (oh == NULL)
979bbaa8b60SDan Kruchinin 		return;
980bbaa8b60SDan Kruchinin 
981bbaa8b60SDan Kruchinin 	host = nlm_host_find_by_sysid(g, oh->oh_sysid);
982bbaa8b60SDan Kruchinin 	if (host == NULL)
983bbaa8b60SDan Kruchinin 		return;
984bbaa8b60SDan Kruchinin 
985bbaa8b60SDan Kruchinin 	if (cb != NULL) {
986bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(host, sr->rq_vers, &rpcp);
987bbaa8b60SDan Kruchinin 		if (error != 0)
988bbaa8b60SDan Kruchinin 			goto out;
989bbaa8b60SDan Kruchinin 	}
990bbaa8b60SDan Kruchinin 
991bbaa8b60SDan Kruchinin 	if (NLM_IN_GRACE(g)) {
992bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_denied_grace_period;
993bbaa8b60SDan Kruchinin 		goto out;
994bbaa8b60SDan Kruchinin 	}
995bbaa8b60SDan Kruchinin 
996bbaa8b60SDan Kruchinin 	error = nlm_slock_grant(g, host, &argp->alock);
997bbaa8b60SDan Kruchinin 	if (error == 0)
998bbaa8b60SDan Kruchinin 		resp->stat.stat = nlm4_granted;
999bbaa8b60SDan Kruchinin 
1000bbaa8b60SDan Kruchinin out:
1001bbaa8b60SDan Kruchinin 	/*
100295fa5714SMarcel Telka 	 * If we have a callback function, use that to
1003bbaa8b60SDan Kruchinin 	 * deliver the response via another RPC call.
1004bbaa8b60SDan Kruchinin 	 */
1005bbaa8b60SDan Kruchinin 	if (cb != NULL && rpcp != NULL)
1006bbaa8b60SDan Kruchinin 		NLM_INVOKE_CALLBACK("do_granted", rpcp, resp, cb);
1007bbaa8b60SDan Kruchinin 
1008bbaa8b60SDan Kruchinin 	if (rpcp != NULL)
1009bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(host, rpcp);
1010bbaa8b60SDan Kruchinin 
1011bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
1012bbaa8b60SDan Kruchinin }
1013bbaa8b60SDan Kruchinin 
1014bbaa8b60SDan Kruchinin /*
1015bbaa8b60SDan Kruchinin  * NLM_FREE_ALL, NLM4_FREE_ALL
1016bbaa8b60SDan Kruchinin  *
1017bbaa8b60SDan Kruchinin  * Destroy all lock state for the calling client.
1018bbaa8b60SDan Kruchinin  */
1019bbaa8b60SDan Kruchinin void
1020bbaa8b60SDan Kruchinin nlm_do_free_all(nlm4_notify *argp, void *res, struct svc_req *sr)
1021bbaa8b60SDan Kruchinin {
1022bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
1023bbaa8b60SDan Kruchinin 	struct nlm_host_list host_list;
1024bbaa8b60SDan Kruchinin 	struct nlm_host *hostp;
1025bbaa8b60SDan Kruchinin 
1026bbaa8b60SDan Kruchinin 	TAILQ_INIT(&host_list);
1027bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
1028bbaa8b60SDan Kruchinin 
1029bbaa8b60SDan Kruchinin 	/* Serialize calls to clean locks. */
1030bbaa8b60SDan Kruchinin 	mutex_enter(&g->clean_lock);
1031bbaa8b60SDan Kruchinin 
1032bbaa8b60SDan Kruchinin 	/*
1033bbaa8b60SDan Kruchinin 	 * Find all hosts that have the given node name and put them on a
1034bbaa8b60SDan Kruchinin 	 * local list.
1035bbaa8b60SDan Kruchinin 	 */
1036bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
1037bbaa8b60SDan Kruchinin 	for (hostp = avl_first(&g->nlm_hosts_tree); hostp != NULL;
1038bbaa8b60SDan Kruchinin 	    hostp = AVL_NEXT(&g->nlm_hosts_tree, hostp)) {
1039bbaa8b60SDan Kruchinin 		if (strcasecmp(hostp->nh_name, argp->name) == 0) {
1040bbaa8b60SDan Kruchinin 			/*
1041bbaa8b60SDan Kruchinin 			 * If needed take the host out of the idle list since
1042bbaa8b60SDan Kruchinin 			 * we are taking a reference.
1043bbaa8b60SDan Kruchinin 			 */
1044bbaa8b60SDan Kruchinin 			if (hostp->nh_flags & NLM_NH_INIDLE) {
1045bbaa8b60SDan Kruchinin 				TAILQ_REMOVE(&g->nlm_idle_hosts, hostp,
1046bbaa8b60SDan Kruchinin 				    nh_link);
1047bbaa8b60SDan Kruchinin 				hostp->nh_flags &= ~NLM_NH_INIDLE;
1048bbaa8b60SDan Kruchinin 			}
1049bbaa8b60SDan Kruchinin 			hostp->nh_refs++;
1050bbaa8b60SDan Kruchinin 
1051bbaa8b60SDan Kruchinin 			TAILQ_INSERT_TAIL(&host_list, hostp, nh_link);
1052bbaa8b60SDan Kruchinin 		}
1053bbaa8b60SDan Kruchinin 	}
1054bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
1055bbaa8b60SDan Kruchinin 
1056bbaa8b60SDan Kruchinin 	/* Free locks for all hosts on the local list. */
1057bbaa8b60SDan Kruchinin 	while (!TAILQ_EMPTY(&host_list)) {
1058bbaa8b60SDan Kruchinin 		hostp = TAILQ_FIRST(&host_list);
1059bbaa8b60SDan Kruchinin 		TAILQ_REMOVE(&host_list, hostp, nh_link);
1060bbaa8b60SDan Kruchinin 
1061bbaa8b60SDan Kruchinin 		/*
1062bbaa8b60SDan Kruchinin 		 * Note that this does not do client-side cleanup.
1063bbaa8b60SDan Kruchinin 		 * We want to do that ONLY if statd tells us the
1064bbaa8b60SDan Kruchinin 		 * server has restarted.
1065bbaa8b60SDan Kruchinin 		 */
1066bbaa8b60SDan Kruchinin 		nlm_host_notify_server(hostp, argp->state);
1067bbaa8b60SDan Kruchinin 		nlm_host_release(g, hostp);
1068bbaa8b60SDan Kruchinin 	}
1069bbaa8b60SDan Kruchinin 
1070bbaa8b60SDan Kruchinin 	mutex_exit(&g->clean_lock);
1071bbaa8b60SDan Kruchinin 
1072bbaa8b60SDan Kruchinin 	(void) res;
1073bbaa8b60SDan Kruchinin 	(void) sr;
1074bbaa8b60SDan Kruchinin }
1075bbaa8b60SDan Kruchinin 
1076bbaa8b60SDan Kruchinin static void
1077bbaa8b60SDan Kruchinin nlm_init_shrlock(struct shrlock *shr,
1078bbaa8b60SDan Kruchinin     nlm4_share *nshare, struct nlm_host *host)
1079bbaa8b60SDan Kruchinin {
1080bbaa8b60SDan Kruchinin 
1081bbaa8b60SDan Kruchinin 	switch (nshare->access) {
1082bbaa8b60SDan Kruchinin 	default:
1083bbaa8b60SDan Kruchinin 	case fsa_NONE:
1084bbaa8b60SDan Kruchinin 		shr->s_access = 0;
1085bbaa8b60SDan Kruchinin 		break;
1086bbaa8b60SDan Kruchinin 	case fsa_R:
1087bbaa8b60SDan Kruchinin 		shr->s_access = F_RDACC;
1088bbaa8b60SDan Kruchinin 		break;
1089bbaa8b60SDan Kruchinin 	case fsa_W:
1090bbaa8b60SDan Kruchinin 		shr->s_access = F_WRACC;
1091bbaa8b60SDan Kruchinin 		break;
1092bbaa8b60SDan Kruchinin 	case fsa_RW:
1093bbaa8b60SDan Kruchinin 		shr->s_access = F_RWACC;
1094bbaa8b60SDan Kruchinin 		break;
1095bbaa8b60SDan Kruchinin 	}
1096bbaa8b60SDan Kruchinin 
1097bbaa8b60SDan Kruchinin 	switch (nshare->mode) {
1098bbaa8b60SDan Kruchinin 	default:
1099bbaa8b60SDan Kruchinin 	case fsm_DN:
1100bbaa8b60SDan Kruchinin 		shr->s_deny = F_NODNY;
1101bbaa8b60SDan Kruchinin 		break;
1102bbaa8b60SDan Kruchinin 	case fsm_DR:
1103bbaa8b60SDan Kruchinin 		shr->s_deny = F_RDDNY;
1104bbaa8b60SDan Kruchinin 		break;
1105bbaa8b60SDan Kruchinin 	case fsm_DW:
1106bbaa8b60SDan Kruchinin 		shr->s_deny = F_WRDNY;
1107bbaa8b60SDan Kruchinin 		break;
1108bbaa8b60SDan Kruchinin 	case fsm_DRW:
1109bbaa8b60SDan Kruchinin 		shr->s_deny = F_RWDNY;
1110bbaa8b60SDan Kruchinin 		break;
1111bbaa8b60SDan Kruchinin 	}
1112bbaa8b60SDan Kruchinin 
1113bbaa8b60SDan Kruchinin 	shr->s_sysid = host->nh_sysid;
1114bbaa8b60SDan Kruchinin 	shr->s_pid = 0;
1115bbaa8b60SDan Kruchinin 	shr->s_own_len = nshare->oh.n_len;
1116bbaa8b60SDan Kruchinin 	shr->s_owner   = nshare->oh.n_bytes;
1117bbaa8b60SDan Kruchinin }
1118bbaa8b60SDan Kruchinin 
1119bbaa8b60SDan Kruchinin /*
1120bbaa8b60SDan Kruchinin  * NLM_SHARE, NLM4_SHARE
1121bbaa8b60SDan Kruchinin  *
1122bbaa8b60SDan Kruchinin  * Request a DOS-style share reservation
1123bbaa8b60SDan Kruchinin  */
1124bbaa8b60SDan Kruchinin void
1125bbaa8b60SDan Kruchinin nlm_do_share(nlm4_shareargs *argp, nlm4_shareres *resp, struct svc_req *sr)
1126bbaa8b60SDan Kruchinin {
1127bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
1128bbaa8b60SDan Kruchinin 	struct nlm_host *host;
1129bbaa8b60SDan Kruchinin 	struct netbuf *addr;
1130bbaa8b60SDan Kruchinin 	struct nlm_vhold *nvp = NULL;
1131bbaa8b60SDan Kruchinin 	char *netid;
1132bbaa8b60SDan Kruchinin 	char *name;
1133bbaa8b60SDan Kruchinin 	int error;
1134bbaa8b60SDan Kruchinin 	struct shrlock shr;
1135bbaa8b60SDan Kruchinin 
1136bbaa8b60SDan Kruchinin 	nlm_copy_netobj(&resp->cookie, &argp->cookie);
1137bbaa8b60SDan Kruchinin 
1138bbaa8b60SDan Kruchinin 	name = argp->share.caller_name;
1139bbaa8b60SDan Kruchinin 	netid = svc_getnetid(sr->rq_xprt);
1140bbaa8b60SDan Kruchinin 	addr = svc_getrpccaller(sr->rq_xprt);
1141bbaa8b60SDan Kruchinin 
1142bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
1143bbaa8b60SDan Kruchinin 	host = nlm_host_findcreate(g, name, netid, addr);
1144bbaa8b60SDan Kruchinin 	if (host == NULL) {
1145bbaa8b60SDan Kruchinin 		resp->stat = nlm4_denied_nolocks;
1146bbaa8b60SDan Kruchinin 		return;
1147bbaa8b60SDan Kruchinin 	}
1148bbaa8b60SDan Kruchinin 
1149bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(share__start, struct nlm_globals *, g,
1150bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_shareargs *, argp);
1151bbaa8b60SDan Kruchinin 
1152bbaa8b60SDan Kruchinin 	if (argp->reclaim == 0 && NLM_IN_GRACE(g)) {
1153bbaa8b60SDan Kruchinin 		resp->stat = nlm4_denied_grace_period;
1154bbaa8b60SDan Kruchinin 		goto out;
1155bbaa8b60SDan Kruchinin 	}
1156bbaa8b60SDan Kruchinin 
1157bbaa8b60SDan Kruchinin 	/*
1158bbaa8b60SDan Kruchinin 	 * Get holded vnode when on lock operation.
1159bbaa8b60SDan Kruchinin 	 * Only lock() and share() need vhold objects.
1160bbaa8b60SDan Kruchinin 	 */
1161bbaa8b60SDan Kruchinin 	nvp = nlm_fh_to_vhold(host, &argp->share.fh);
1162bbaa8b60SDan Kruchinin 	if (nvp == NULL) {
1163bbaa8b60SDan Kruchinin 		resp->stat = nlm4_stale_fh;
1164bbaa8b60SDan Kruchinin 		goto out;
1165bbaa8b60SDan Kruchinin 	}
1166bbaa8b60SDan Kruchinin 
1167bbaa8b60SDan Kruchinin 	/* Convert to local form. */
1168bbaa8b60SDan Kruchinin 	nlm_init_shrlock(&shr, &argp->share, host);
1169bbaa8b60SDan Kruchinin 	error = VOP_SHRLOCK(nvp->nv_vp, F_SHARE, &shr,
1170bbaa8b60SDan Kruchinin 	    FREAD | FWRITE, CRED(), NULL);
1171bbaa8b60SDan Kruchinin 
1172bbaa8b60SDan Kruchinin 	if (error == 0) {
1173bbaa8b60SDan Kruchinin 		resp->stat = nlm4_granted;
1174bbaa8b60SDan Kruchinin 		nlm_host_monitor(g, host, 0);
1175bbaa8b60SDan Kruchinin 	} else {
1176bbaa8b60SDan Kruchinin 		resp->stat = nlm4_denied;
1177bbaa8b60SDan Kruchinin 	}
1178bbaa8b60SDan Kruchinin 
1179bbaa8b60SDan Kruchinin out:
1180bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(share__end, struct nlm_globals *, g,
1181bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_shareres *, resp);
1182bbaa8b60SDan Kruchinin 
1183bbaa8b60SDan Kruchinin 	nlm_vhold_release(host, nvp);
1184bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
1185bbaa8b60SDan Kruchinin }
1186bbaa8b60SDan Kruchinin 
1187bbaa8b60SDan Kruchinin /*
1188bbaa8b60SDan Kruchinin  * NLM_UNSHARE, NLM4_UNSHARE
1189bbaa8b60SDan Kruchinin  *
1190bbaa8b60SDan Kruchinin  * Release a DOS-style share reservation
1191bbaa8b60SDan Kruchinin  */
1192bbaa8b60SDan Kruchinin void
1193bbaa8b60SDan Kruchinin nlm_do_unshare(nlm4_shareargs *argp, nlm4_shareres *resp, struct svc_req *sr)
1194bbaa8b60SDan Kruchinin {
1195bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
1196bbaa8b60SDan Kruchinin 	struct nlm_host *host;
1197bbaa8b60SDan Kruchinin 	struct netbuf *addr;
1198bbaa8b60SDan Kruchinin 	vnode_t *vp = NULL;
1199bbaa8b60SDan Kruchinin 	char *netid;
1200bbaa8b60SDan Kruchinin 	int error;
1201bbaa8b60SDan Kruchinin 	struct shrlock shr;
1202bbaa8b60SDan Kruchinin 
1203bbaa8b60SDan Kruchinin 	nlm_copy_netobj(&resp->cookie, &argp->cookie);
1204bbaa8b60SDan Kruchinin 
1205bbaa8b60SDan Kruchinin 	netid = svc_getnetid(sr->rq_xprt);
1206bbaa8b60SDan Kruchinin 	addr = svc_getrpccaller(sr->rq_xprt);
1207bbaa8b60SDan Kruchinin 
1208bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
1209bbaa8b60SDan Kruchinin 	host = nlm_host_find(g, netid, addr);
1210bbaa8b60SDan Kruchinin 	if (host == NULL) {
1211bbaa8b60SDan Kruchinin 		resp->stat = nlm4_denied_nolocks;
1212bbaa8b60SDan Kruchinin 		return;
1213bbaa8b60SDan Kruchinin 	}
1214bbaa8b60SDan Kruchinin 
1215bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(unshare__start, struct nlm_globals *, g,
1216bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_shareargs *, argp);
1217bbaa8b60SDan Kruchinin 
1218bbaa8b60SDan Kruchinin 	if (NLM_IN_GRACE(g)) {
1219bbaa8b60SDan Kruchinin 		resp->stat = nlm4_denied_grace_period;
1220bbaa8b60SDan Kruchinin 		goto out;
1221bbaa8b60SDan Kruchinin 	}
1222bbaa8b60SDan Kruchinin 
1223bbaa8b60SDan Kruchinin 	vp = nlm_fh_to_vp(&argp->share.fh);
1224bbaa8b60SDan Kruchinin 	if (vp == NULL) {
1225bbaa8b60SDan Kruchinin 		resp->stat = nlm4_stale_fh;
1226bbaa8b60SDan Kruchinin 		goto out;
1227bbaa8b60SDan Kruchinin 	}
1228bbaa8b60SDan Kruchinin 
1229bbaa8b60SDan Kruchinin 	/* Convert to local form. */
1230bbaa8b60SDan Kruchinin 	nlm_init_shrlock(&shr, &argp->share, host);
1231bbaa8b60SDan Kruchinin 	error = VOP_SHRLOCK(vp, F_UNSHARE, &shr,
1232bbaa8b60SDan Kruchinin 	    FREAD | FWRITE, CRED(), NULL);
1233bbaa8b60SDan Kruchinin 
1234bbaa8b60SDan Kruchinin 	(void) error;
1235bbaa8b60SDan Kruchinin 	resp->stat = nlm4_granted;
1236bbaa8b60SDan Kruchinin 
1237bbaa8b60SDan Kruchinin out:
1238bbaa8b60SDan Kruchinin 	DTRACE_PROBE3(unshare__end, struct nlm_globals *, g,
1239bbaa8b60SDan Kruchinin 	    struct nlm_host *, host, nlm4_shareres *, resp);
1240bbaa8b60SDan Kruchinin 
1241bbaa8b60SDan Kruchinin 	if (vp != NULL)
1242bbaa8b60SDan Kruchinin 		VN_RELE(vp);
1243bbaa8b60SDan Kruchinin 
1244bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
1245bbaa8b60SDan Kruchinin }
1246bbaa8b60SDan Kruchinin 
1247bbaa8b60SDan Kruchinin /*
1248bbaa8b60SDan Kruchinin  * NLM wrapper to VOP_FRLOCK that checks the validity of the lock before
1249bbaa8b60SDan Kruchinin  * invoking the vnode operation.
1250bbaa8b60SDan Kruchinin  */
1251bbaa8b60SDan Kruchinin static int
1252bbaa8b60SDan Kruchinin nlm_vop_frlock(vnode_t *vp, int cmd, flock64_t *bfp, int flag, offset_t offset,
1253bbaa8b60SDan Kruchinin     struct flk_callback *flk_cbp, cred_t *cr, caller_context_t *ct)
1254bbaa8b60SDan Kruchinin {
1255bbaa8b60SDan Kruchinin 	if (bfp->l_len != 0 && bfp->l_start + (bfp->l_len - 1) < bfp->l_start) {
1256bbaa8b60SDan Kruchinin 		return (EOVERFLOW);
1257bbaa8b60SDan Kruchinin 	}
1258bbaa8b60SDan Kruchinin 
1259bbaa8b60SDan Kruchinin 	return (VOP_FRLOCK(vp, cmd, bfp, flag, offset, flk_cbp, cr, ct));
1260bbaa8b60SDan Kruchinin }
1261