xref: /illumos-gate/usr/src/uts/common/klm/nlm_client.c (revision 745caa42)
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 2011 Nexenta Systems, Inc.  All rights reserved.
30bbaa8b60SDan Kruchinin  * Copyright (c) 2012 by Delphix. All rights reserved.
315cd496e3SBryan Cantrill  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
32bbaa8b60SDan Kruchinin  */
33bbaa8b60SDan Kruchinin 
34bbaa8b60SDan Kruchinin /*
35bbaa8b60SDan Kruchinin  * Client-side support for (NFS) VOP_FRLOCK, VOP_SHRLOCK.
36bbaa8b60SDan Kruchinin  * (called via klmops.c: lm_frlock, lm4_frlock)
37bbaa8b60SDan Kruchinin  *
38bbaa8b60SDan Kruchinin  * Source code derived from FreeBSD nlm_advlock.c
39bbaa8b60SDan Kruchinin  */
40bbaa8b60SDan Kruchinin 
41bbaa8b60SDan Kruchinin #include <sys/param.h>
42bbaa8b60SDan Kruchinin #include <sys/fcntl.h>
43bbaa8b60SDan Kruchinin #include <sys/lock.h>
44bbaa8b60SDan Kruchinin #include <sys/flock.h>
45bbaa8b60SDan Kruchinin #include <sys/mount.h>
46bbaa8b60SDan Kruchinin #include <sys/mutex.h>
47bbaa8b60SDan Kruchinin #include <sys/proc.h>
48bbaa8b60SDan Kruchinin #include <sys/share.h>
49bbaa8b60SDan Kruchinin #include <sys/syslog.h>
50bbaa8b60SDan Kruchinin #include <sys/systm.h>
51bbaa8b60SDan Kruchinin #include <sys/unistd.h>
52bbaa8b60SDan Kruchinin #include <sys/vnode.h>
53bbaa8b60SDan Kruchinin #include <sys/queue.h>
54bbaa8b60SDan Kruchinin #include <sys/sdt.h>
55bbaa8b60SDan Kruchinin #include <netinet/in.h>
56bbaa8b60SDan Kruchinin 
57bbaa8b60SDan Kruchinin #include <fs/fs_subr.h>
58bbaa8b60SDan Kruchinin #include <rpcsvc/nlm_prot.h>
59bbaa8b60SDan Kruchinin 
60bbaa8b60SDan Kruchinin #include <nfs/nfs.h>
61bbaa8b60SDan Kruchinin #include <nfs/nfs_clnt.h>
62bbaa8b60SDan Kruchinin #include <nfs/export.h>
63bbaa8b60SDan Kruchinin #include <nfs/rnode.h>
64bbaa8b60SDan Kruchinin #include <nfs/lm.h>
65bbaa8b60SDan Kruchinin 
66bbaa8b60SDan Kruchinin #include "nlm_impl.h"
67bbaa8b60SDan Kruchinin 
68bbaa8b60SDan Kruchinin /* Extra flags for nlm_call_lock() - xflags */
69bbaa8b60SDan Kruchinin #define	NLM_X_RECLAIM	1
70bbaa8b60SDan Kruchinin #define	NLM_X_BLOCKING	2
71bbaa8b60SDan Kruchinin 
72bbaa8b60SDan Kruchinin /*
73bbaa8b60SDan Kruchinin  * Max. number of retries nlm_call_cancel() does
74bbaa8b60SDan Kruchinin  * when NLM server is in grace period or doesn't
75bbaa8b60SDan Kruchinin  * respond correctly.
76bbaa8b60SDan Kruchinin  */
77bbaa8b60SDan Kruchinin #define	NLM_CANCEL_NRETRS 5
78bbaa8b60SDan Kruchinin 
79bbaa8b60SDan Kruchinin /*
80bbaa8b60SDan Kruchinin  * Determines wether given lock "flp" is safe.
81bbaa8b60SDan Kruchinin  * The lock is considered to be safe when it
82bbaa8b60SDan Kruchinin  * acquires the whole file (i.e. its start
83bbaa8b60SDan Kruchinin  * and len are zeroes).
84bbaa8b60SDan Kruchinin  */
85bbaa8b60SDan Kruchinin #define	NLM_FLOCK_IS_SAFE(flp) \
86bbaa8b60SDan Kruchinin 	((flp)->l_start == 0 && (flp)->l_len == 0)
87bbaa8b60SDan Kruchinin 
88bbaa8b60SDan Kruchinin static volatile uint32_t nlm_xid = 1;
89bbaa8b60SDan Kruchinin 
90bbaa8b60SDan Kruchinin static int nlm_init_fh_by_vp(vnode_t *, struct netobj *, rpcvers_t *);
91bbaa8b60SDan Kruchinin static int nlm_map_status(nlm4_stats);
92bbaa8b60SDan Kruchinin static int nlm_map_clnt_stat(enum clnt_stat);
93bbaa8b60SDan Kruchinin static void nlm_send_siglost(pid_t);
94bbaa8b60SDan Kruchinin 
95bbaa8b60SDan Kruchinin static int nlm_frlock_getlk(struct nlm_host *, vnode_t *,
96bbaa8b60SDan Kruchinin     struct flock64 *, int, u_offset_t, struct netobj *, int);
97bbaa8b60SDan Kruchinin 
98bbaa8b60SDan Kruchinin static int nlm_frlock_setlk(struct nlm_host *, vnode_t *,
99bbaa8b60SDan Kruchinin     struct flock64 *, int, u_offset_t, struct netobj *,
100bbaa8b60SDan Kruchinin     struct flk_callback *, int, bool_t);
101bbaa8b60SDan Kruchinin 
102bbaa8b60SDan Kruchinin static int nlm_reclaim_lock(struct nlm_host *, vnode_t *,
103bbaa8b60SDan Kruchinin     struct flock64 *, int32_t);
104bbaa8b60SDan Kruchinin 
105bbaa8b60SDan Kruchinin static void nlm_init_lock(struct nlm4_lock *,
106bbaa8b60SDan Kruchinin     const struct flock64 *, struct netobj *,
107bbaa8b60SDan Kruchinin     struct nlm_owner_handle *);
108bbaa8b60SDan Kruchinin 
109bbaa8b60SDan Kruchinin static int nlm_call_lock(vnode_t *, struct flock64 *,
110bbaa8b60SDan Kruchinin     struct nlm_host *, struct netobj *,
111bbaa8b60SDan Kruchinin     struct flk_callback *, int, int);
112bbaa8b60SDan Kruchinin static int nlm_call_unlock(struct flock64 *, struct nlm_host *,
113bbaa8b60SDan Kruchinin     struct netobj *, int);
114bbaa8b60SDan Kruchinin static int nlm_call_test(struct flock64 *, struct nlm_host *,
115bbaa8b60SDan Kruchinin     struct netobj *, int);
116bbaa8b60SDan Kruchinin static int nlm_call_cancel(struct nlm4_lockargs *,
117bbaa8b60SDan Kruchinin     struct nlm_host *, int);
118bbaa8b60SDan Kruchinin 
119bbaa8b60SDan Kruchinin static int nlm_local_getlk(vnode_t *, struct flock64 *, int);
120bbaa8b60SDan Kruchinin static int nlm_local_setlk(vnode_t *, struct flock64 *, int);
121bbaa8b60SDan Kruchinin static void nlm_local_cancelk(vnode_t *, struct flock64 *);
122bbaa8b60SDan Kruchinin 
123bbaa8b60SDan Kruchinin static void nlm_init_share(struct nlm4_share *,
124bbaa8b60SDan Kruchinin     const struct shrlock *, struct netobj *);
125bbaa8b60SDan Kruchinin 
126bbaa8b60SDan Kruchinin static int nlm_call_share(struct shrlock *, struct nlm_host *,
127bbaa8b60SDan Kruchinin     struct netobj *, int, int);
128bbaa8b60SDan Kruchinin static int nlm_call_unshare(struct shrlock *, struct nlm_host *,
129bbaa8b60SDan Kruchinin     struct netobj *, int);
130bbaa8b60SDan Kruchinin static int nlm_reclaim_share(struct nlm_host *, vnode_t *,
131bbaa8b60SDan Kruchinin     struct shrlock *, uint32_t);
132bbaa8b60SDan Kruchinin static int nlm_local_shrlock(vnode_t *, struct shrlock *, int, int);
133bbaa8b60SDan Kruchinin static void nlm_local_shrcancel(vnode_t *, struct shrlock *);
134bbaa8b60SDan Kruchinin 
135bbaa8b60SDan Kruchinin /*
136bbaa8b60SDan Kruchinin  * Reclaim locks/shares acquired by the client side
137bbaa8b60SDan Kruchinin  * on the given server represented by hostp.
138bbaa8b60SDan Kruchinin  * The function is called from a dedicated thread
139bbaa8b60SDan Kruchinin  * when server reports us that it's entered grace
140bbaa8b60SDan Kruchinin  * period.
141bbaa8b60SDan Kruchinin  */
142bbaa8b60SDan Kruchinin void
nlm_reclaim_client(struct nlm_globals * g,struct nlm_host * hostp)143bbaa8b60SDan Kruchinin nlm_reclaim_client(struct nlm_globals *g, struct nlm_host *hostp)
144bbaa8b60SDan Kruchinin {
145bbaa8b60SDan Kruchinin 	int32_t state;
146bbaa8b60SDan Kruchinin 	int error, sysid;
147bbaa8b60SDan Kruchinin 	struct locklist *llp_head, *llp;
148bbaa8b60SDan Kruchinin 	struct nlm_shres *nsp_head, *nsp;
149bbaa8b60SDan Kruchinin 	bool_t restart;
150bbaa8b60SDan Kruchinin 
151bbaa8b60SDan Kruchinin 	sysid = hostp->nh_sysid | LM_SYSID_CLIENT;
152bbaa8b60SDan Kruchinin 	do {
153bbaa8b60SDan Kruchinin 		error = 0;
154bbaa8b60SDan Kruchinin 		restart = FALSE;
155bbaa8b60SDan Kruchinin 		state = nlm_host_get_state(hostp);
156bbaa8b60SDan Kruchinin 
157bbaa8b60SDan Kruchinin 		DTRACE_PROBE3(reclaim__iter, struct nlm_globals *, g,
158bbaa8b60SDan Kruchinin 		    struct nlm_host *, hostp, int, state);
159bbaa8b60SDan Kruchinin 
160bbaa8b60SDan Kruchinin 		/*
161bbaa8b60SDan Kruchinin 		 * We cancel all sleeping locks that were
162bbaa8b60SDan Kruchinin 		 * done by the host, because we don't allow
163bbaa8b60SDan Kruchinin 		 * reclamation of sleeping locks. The reason
164bbaa8b60SDan Kruchinin 		 * we do this is that allowing of sleeping locks
165bbaa8b60SDan Kruchinin 		 * reclamation can potentially break locks recovery
166bbaa8b60SDan Kruchinin 		 * order.
167bbaa8b60SDan Kruchinin 		 *
168bbaa8b60SDan Kruchinin 		 * Imagine that we have two client machines A and B
169bbaa8b60SDan Kruchinin 		 * and an NLM server machine. A adds a non sleeping
170bbaa8b60SDan Kruchinin 		 * lock to the file F and aquires this file. Machine
171bbaa8b60SDan Kruchinin 		 * B in its turn adds sleeping lock to the file
172bbaa8b60SDan Kruchinin 		 * F and blocks because F is already aquired by
173bbaa8b60SDan Kruchinin 		 * the machine A. Then server crashes and after the
174bbaa8b60SDan Kruchinin 		 * reboot it notifies its clients about the crash.
175bbaa8b60SDan Kruchinin 		 * If we would allow sleeping locks reclamation,
176bbaa8b60SDan Kruchinin 		 * there would be possible that machine B recovers
177bbaa8b60SDan Kruchinin 		 * its lock faster than machine A (by some reason).
178bbaa8b60SDan Kruchinin 		 * So that B aquires the file F after server crash and
179bbaa8b60SDan Kruchinin 		 * machine A (that by some reason recovers slower) fails
180bbaa8b60SDan Kruchinin 		 * to recover its non sleeping lock. Thus the original
181bbaa8b60SDan Kruchinin 		 * locks order becames broken.
182bbaa8b60SDan Kruchinin 		 */
183bbaa8b60SDan Kruchinin 		nlm_host_cancel_slocks(g, hostp);
184bbaa8b60SDan Kruchinin 
185bbaa8b60SDan Kruchinin 		/*
186bbaa8b60SDan Kruchinin 		 * Try to reclaim all active locks we have
187bbaa8b60SDan Kruchinin 		 */
188bbaa8b60SDan Kruchinin 		llp_head = llp = flk_get_active_locks(sysid, NOPID);
189bbaa8b60SDan Kruchinin 		while (llp != NULL) {
190bbaa8b60SDan Kruchinin 			error = nlm_reclaim_lock(hostp, llp->ll_vp,
191bbaa8b60SDan Kruchinin 			    &llp->ll_flock, state);
192bbaa8b60SDan Kruchinin 
193bbaa8b60SDan Kruchinin 			if (error == 0) {
194bbaa8b60SDan Kruchinin 				llp = llp->ll_next;
195bbaa8b60SDan Kruchinin 				continue;
196bbaa8b60SDan Kruchinin 			} else if (error == ERESTART) {
197bbaa8b60SDan Kruchinin 				restart = TRUE;
198bbaa8b60SDan Kruchinin 				break;
199bbaa8b60SDan Kruchinin 			} else {
200bbaa8b60SDan Kruchinin 				/*
201bbaa8b60SDan Kruchinin 				 * Critical error occurred, the lock
202bbaa8b60SDan Kruchinin 				 * can not be recovered, just take it away.
203bbaa8b60SDan Kruchinin 				 */
204bbaa8b60SDan Kruchinin 				nlm_local_cancelk(llp->ll_vp, &llp->ll_flock);
205bbaa8b60SDan Kruchinin 			}
206bbaa8b60SDan Kruchinin 
207bbaa8b60SDan Kruchinin 			llp = llp->ll_next;
208bbaa8b60SDan Kruchinin 		}
209bbaa8b60SDan Kruchinin 
210bbaa8b60SDan Kruchinin 		flk_free_locklist(llp_head);
211bbaa8b60SDan Kruchinin 		if (restart) {
212bbaa8b60SDan Kruchinin 			/*
213bbaa8b60SDan Kruchinin 			 * Lock reclamation fucntion reported us that
214bbaa8b60SDan Kruchinin 			 * the server state was changed (again), so
215bbaa8b60SDan Kruchinin 			 * try to repeat the whole reclamation process.
216bbaa8b60SDan Kruchinin 			 */
217bbaa8b60SDan Kruchinin 			continue;
218bbaa8b60SDan Kruchinin 		}
219bbaa8b60SDan Kruchinin 
220bbaa8b60SDan Kruchinin 		nsp_head = nsp = nlm_get_active_shres(hostp);
221bbaa8b60SDan Kruchinin 		while (nsp != NULL) {
222bbaa8b60SDan Kruchinin 			error = nlm_reclaim_share(hostp, nsp->ns_vp,
223bbaa8b60SDan Kruchinin 			    nsp->ns_shr, state);
224bbaa8b60SDan Kruchinin 
225bbaa8b60SDan Kruchinin 			if (error == 0) {
226bbaa8b60SDan Kruchinin 				nsp = nsp->ns_next;
227bbaa8b60SDan Kruchinin 				continue;
228bbaa8b60SDan Kruchinin 			} else if (error == ERESTART) {
229bbaa8b60SDan Kruchinin 				break;
230bbaa8b60SDan Kruchinin 			} else {
231bbaa8b60SDan Kruchinin 				/* Failed to reclaim share */
232bbaa8b60SDan Kruchinin 				nlm_shres_untrack(hostp, nsp->ns_vp,
233bbaa8b60SDan Kruchinin 				    nsp->ns_shr);
234bbaa8b60SDan Kruchinin 				nlm_local_shrcancel(nsp->ns_vp,
235bbaa8b60SDan Kruchinin 				    nsp->ns_shr);
236bbaa8b60SDan Kruchinin 			}
237bbaa8b60SDan Kruchinin 
238bbaa8b60SDan Kruchinin 			nsp = nsp->ns_next;
239bbaa8b60SDan Kruchinin 		}
240bbaa8b60SDan Kruchinin 
241bbaa8b60SDan Kruchinin 		nlm_free_shrlist(nsp_head);
242bbaa8b60SDan Kruchinin 	} while (state != nlm_host_get_state(hostp));
243bbaa8b60SDan Kruchinin }
244bbaa8b60SDan Kruchinin 
245bbaa8b60SDan Kruchinin /*
246bbaa8b60SDan Kruchinin  * nlm_frlock --
247bbaa8b60SDan Kruchinin  *      NFS advisory byte-range locks.
248bbaa8b60SDan Kruchinin  *	Called in klmops.c
249bbaa8b60SDan Kruchinin  *
250bbaa8b60SDan Kruchinin  * Note that the local locking code (os/flock.c) is used to
251bbaa8b60SDan Kruchinin  * keep track of remote locks granted by some server, so we
252bbaa8b60SDan Kruchinin  * can reclaim those locks after a server restarts.  We can
253bbaa8b60SDan Kruchinin  * also sometimes use this as a cache of lock information.
254bbaa8b60SDan Kruchinin  *
255bbaa8b60SDan Kruchinin  * Was: nlm_advlock()
256bbaa8b60SDan Kruchinin  */
257bbaa8b60SDan Kruchinin /* ARGSUSED */
258bbaa8b60SDan Kruchinin int
nlm_frlock(struct vnode * vp,int cmd,struct flock64 * flkp,int flags,u_offset_t offset,struct cred * crp,struct netobj * fhp,struct flk_callback * flcb,int vers)259bbaa8b60SDan Kruchinin nlm_frlock(struct vnode *vp, int cmd, struct flock64 *flkp,
260*745caa42SMarcel Telka     int flags, u_offset_t offset, struct cred *crp,
261*745caa42SMarcel Telka     struct netobj *fhp, struct flk_callback *flcb, int vers)
262bbaa8b60SDan Kruchinin {
263bbaa8b60SDan Kruchinin 	mntinfo_t *mi;
264bbaa8b60SDan Kruchinin 	servinfo_t *sv;
265bbaa8b60SDan Kruchinin 	const char *netid;
266bbaa8b60SDan Kruchinin 	struct nlm_host *hostp;
267bbaa8b60SDan Kruchinin 	int error;
268bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
269bbaa8b60SDan Kruchinin 
270bbaa8b60SDan Kruchinin 	mi = VTOMI(vp);
271bbaa8b60SDan Kruchinin 	sv = mi->mi_curr_serv;
272bbaa8b60SDan Kruchinin 
273bbaa8b60SDan Kruchinin 	netid = nlm_knc_to_netid(sv->sv_knconf);
274bbaa8b60SDan Kruchinin 	if (netid == NULL) {
275bbaa8b60SDan Kruchinin 		NLM_ERR("nlm_frlock: unknown NFS netid");
276bbaa8b60SDan Kruchinin 		return (ENOSYS);
277bbaa8b60SDan Kruchinin 	}
278bbaa8b60SDan Kruchinin 
279bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
280bbaa8b60SDan Kruchinin 	hostp = nlm_host_findcreate(g, sv->sv_hostname, netid, &sv->sv_addr);
281bbaa8b60SDan Kruchinin 	if (hostp == NULL)
282bbaa8b60SDan Kruchinin 		return (ENOSYS);
283bbaa8b60SDan Kruchinin 
284bbaa8b60SDan Kruchinin 	/*
285bbaa8b60SDan Kruchinin 	 * Purge cached attributes in order to make sure that
286bbaa8b60SDan Kruchinin 	 * future calls of convoff()/VOP_GETATTR() will get the
287bbaa8b60SDan Kruchinin 	 * latest data.
288bbaa8b60SDan Kruchinin 	 */
289bbaa8b60SDan Kruchinin 	if (flkp->l_whence == SEEK_END)
290bbaa8b60SDan Kruchinin 		PURGE_ATTRCACHE(vp);
291bbaa8b60SDan Kruchinin 
292bbaa8b60SDan Kruchinin 	/* Now flk0 is the zero-based lock request. */
293bbaa8b60SDan Kruchinin 	switch (cmd) {
294bbaa8b60SDan Kruchinin 	case F_GETLK:
295bbaa8b60SDan Kruchinin 		error = nlm_frlock_getlk(hostp, vp, flkp, flags,
296bbaa8b60SDan Kruchinin 		    offset, fhp, vers);
297bbaa8b60SDan Kruchinin 		break;
298bbaa8b60SDan Kruchinin 
299bbaa8b60SDan Kruchinin 	case F_SETLK:
300bbaa8b60SDan Kruchinin 	case F_SETLKW:
301bbaa8b60SDan Kruchinin 		error = nlm_frlock_setlk(hostp, vp, flkp, flags,
302bbaa8b60SDan Kruchinin 		    offset, fhp, flcb, vers, (cmd == F_SETLKW));
303bbaa8b60SDan Kruchinin 		if (error == 0)
304bbaa8b60SDan Kruchinin 			nlm_host_monitor(g, hostp, 0);
305bbaa8b60SDan Kruchinin 		break;
306bbaa8b60SDan Kruchinin 
307bbaa8b60SDan Kruchinin 	default:
308bbaa8b60SDan Kruchinin 		error = EINVAL;
309bbaa8b60SDan Kruchinin 		break;
310bbaa8b60SDan Kruchinin 	}
311bbaa8b60SDan Kruchinin 
312bbaa8b60SDan Kruchinin 	nlm_host_release(g, hostp);
313bbaa8b60SDan Kruchinin 	return (error);
314bbaa8b60SDan Kruchinin }
315bbaa8b60SDan Kruchinin 
316bbaa8b60SDan Kruchinin static int
nlm_frlock_getlk(struct nlm_host * hostp,vnode_t * vp,struct flock64 * flkp,int flags,u_offset_t offset,struct netobj * fhp,int vers)317bbaa8b60SDan Kruchinin nlm_frlock_getlk(struct nlm_host *hostp, vnode_t *vp,
318bbaa8b60SDan Kruchinin     struct flock64 *flkp, int flags, u_offset_t offset,
319bbaa8b60SDan Kruchinin     struct netobj *fhp, int vers)
320bbaa8b60SDan Kruchinin {
321bbaa8b60SDan Kruchinin 	struct flock64 flk0;
322bbaa8b60SDan Kruchinin 	int error;
323bbaa8b60SDan Kruchinin 
324bbaa8b60SDan Kruchinin 	/*
325bbaa8b60SDan Kruchinin 	 * Check local (cached) locks first.
326bbaa8b60SDan Kruchinin 	 * If we find one, no need for RPC.
327bbaa8b60SDan Kruchinin 	 */
328bbaa8b60SDan Kruchinin 	flk0 = *flkp;
329bbaa8b60SDan Kruchinin 	flk0.l_pid = curproc->p_pid;
330bbaa8b60SDan Kruchinin 	error = nlm_local_getlk(vp, &flk0, flags);
331bbaa8b60SDan Kruchinin 	if (error != 0)
332bbaa8b60SDan Kruchinin 		return (error);
333bbaa8b60SDan Kruchinin 	if (flk0.l_type != F_UNLCK) {
334bbaa8b60SDan Kruchinin 		*flkp = flk0;
335bbaa8b60SDan Kruchinin 		return (0);
336bbaa8b60SDan Kruchinin 	}
337bbaa8b60SDan Kruchinin 
338bbaa8b60SDan Kruchinin 	/* Not found locally.  Try remote. */
339bbaa8b60SDan Kruchinin 	flk0 = *flkp;
340bbaa8b60SDan Kruchinin 	flk0.l_pid = curproc->p_pid;
341bbaa8b60SDan Kruchinin 	error = convoff(vp, &flk0, 0, (offset_t)offset);
342bbaa8b60SDan Kruchinin 	if (error != 0)
343bbaa8b60SDan Kruchinin 		return (error);
344bbaa8b60SDan Kruchinin 
345bbaa8b60SDan Kruchinin 	error = nlm_call_test(&flk0, hostp, fhp, vers);
346bbaa8b60SDan Kruchinin 	if (error != 0)
347bbaa8b60SDan Kruchinin 		return (error);
348bbaa8b60SDan Kruchinin 
349bbaa8b60SDan Kruchinin 	if (flk0.l_type == F_UNLCK) {
350bbaa8b60SDan Kruchinin 		/*
351bbaa8b60SDan Kruchinin 		 * Update the caller's *flkp with information
352bbaa8b60SDan Kruchinin 		 * on the conflicting lock (or lack thereof).
353bbaa8b60SDan Kruchinin 		 */
354bbaa8b60SDan Kruchinin 		flkp->l_type = F_UNLCK;
355bbaa8b60SDan Kruchinin 	} else {
356bbaa8b60SDan Kruchinin 		/*
357bbaa8b60SDan Kruchinin 		 * Found a conflicting lock.  Set the
358bbaa8b60SDan Kruchinin 		 * caller's *flkp with the info, first
359bbaa8b60SDan Kruchinin 		 * converting to the caller's whence.
360bbaa8b60SDan Kruchinin 		 */
361bbaa8b60SDan Kruchinin 		(void) convoff(vp, &flk0, flkp->l_whence, (offset_t)offset);
362bbaa8b60SDan Kruchinin 		*flkp = flk0;
363bbaa8b60SDan Kruchinin 	}
364bbaa8b60SDan Kruchinin 
365bbaa8b60SDan Kruchinin 	return (0);
366bbaa8b60SDan Kruchinin }
367bbaa8b60SDan Kruchinin 
368bbaa8b60SDan Kruchinin static int
nlm_frlock_setlk(struct nlm_host * hostp,vnode_t * vp,struct flock64 * flkp,int flags,u_offset_t offset,struct netobj * fhp,struct flk_callback * flcb,int vers,bool_t do_block)369bbaa8b60SDan Kruchinin nlm_frlock_setlk(struct nlm_host *hostp, vnode_t *vp,
370bbaa8b60SDan Kruchinin     struct flock64 *flkp, int flags, u_offset_t offset,
371bbaa8b60SDan Kruchinin     struct netobj *fhp, struct flk_callback *flcb,
372bbaa8b60SDan Kruchinin     int vers, bool_t do_block)
373bbaa8b60SDan Kruchinin {
374bbaa8b60SDan Kruchinin 	int error, xflags;
375bbaa8b60SDan Kruchinin 
376bbaa8b60SDan Kruchinin 	error = convoff(vp, flkp, 0, (offset_t)offset);
377bbaa8b60SDan Kruchinin 	if (error != 0)
378bbaa8b60SDan Kruchinin 		return (error);
379bbaa8b60SDan Kruchinin 
380bbaa8b60SDan Kruchinin 	/*
381bbaa8b60SDan Kruchinin 	 * NFS v2 clients should not request locks where any part
382bbaa8b60SDan Kruchinin 	 * of the lock range is beyond 0xffffffff.  The NFS code
383bbaa8b60SDan Kruchinin 	 * checks that (see nfs_frlock, flk_check_lock_data), but
384bbaa8b60SDan Kruchinin 	 * as that's outside this module, let's check here too.
385bbaa8b60SDan Kruchinin 	 * This check ensures that we will be able to convert this
386bbaa8b60SDan Kruchinin 	 * lock request into 32-bit form without change, and that
387bbaa8b60SDan Kruchinin 	 * (more importantly) when the granted call back arrives,
388bbaa8b60SDan Kruchinin 	 * it's unchanged when converted back into 64-bit form.
389bbaa8b60SDan Kruchinin 	 * If this lock range were to change in any way during
390bbaa8b60SDan Kruchinin 	 * either of those conversions, the "granted" call back
391bbaa8b60SDan Kruchinin 	 * from the NLM server would not find our sleeping lock.
392bbaa8b60SDan Kruchinin 	 */
393bbaa8b60SDan Kruchinin 	if (vers < NLM4_VERS) {
394bbaa8b60SDan Kruchinin 		if (flkp->l_start > MAX_UOFF32 ||
395bbaa8b60SDan Kruchinin 		    flkp->l_start + flkp->l_len > MAX_UOFF32 + 1)
396bbaa8b60SDan Kruchinin 			return (EINVAL);
397bbaa8b60SDan Kruchinin 	}
398bbaa8b60SDan Kruchinin 
399bbaa8b60SDan Kruchinin 	/*
400bbaa8b60SDan Kruchinin 	 * Fill in l_sysid for the local locking calls.
401bbaa8b60SDan Kruchinin 	 * Also, let's not trust the caller's l_pid.
402bbaa8b60SDan Kruchinin 	 */
403bbaa8b60SDan Kruchinin 	flkp->l_sysid = hostp->nh_sysid | LM_SYSID_CLIENT;
404bbaa8b60SDan Kruchinin 	flkp->l_pid = curproc->p_pid;
405bbaa8b60SDan Kruchinin 
406bbaa8b60SDan Kruchinin 	if (flkp->l_type == F_UNLCK) {
407bbaa8b60SDan Kruchinin 		/*
408bbaa8b60SDan Kruchinin 		 * Purge local (cached) lock information first,
409bbaa8b60SDan Kruchinin 		 * then clear the remote lock.
410bbaa8b60SDan Kruchinin 		 */
411bbaa8b60SDan Kruchinin 		(void) nlm_local_setlk(vp, flkp, flags);
412bbaa8b60SDan Kruchinin 		error = nlm_call_unlock(flkp, hostp, fhp, vers);
413bbaa8b60SDan Kruchinin 
414bbaa8b60SDan Kruchinin 		return (error);
415bbaa8b60SDan Kruchinin 	}
416bbaa8b60SDan Kruchinin 
417bbaa8b60SDan Kruchinin 	if (!do_block) {
418bbaa8b60SDan Kruchinin 		/*
419bbaa8b60SDan Kruchinin 		 * This is a non-blocking "set" request,
420bbaa8b60SDan Kruchinin 		 * so we can check locally first, and
421bbaa8b60SDan Kruchinin 		 * sometimes avoid an RPC call.
422bbaa8b60SDan Kruchinin 		 */
423bbaa8b60SDan Kruchinin 		struct flock64 flk0;
424bbaa8b60SDan Kruchinin 
425bbaa8b60SDan Kruchinin 		flk0 = *flkp;
426bbaa8b60SDan Kruchinin 		error = nlm_local_getlk(vp, &flk0, flags);
427bbaa8b60SDan Kruchinin 		if (error != 0 && flk0.l_type != F_UNLCK) {
428bbaa8b60SDan Kruchinin 			/* Found a conflicting lock. */
429bbaa8b60SDan Kruchinin 			return (EAGAIN);
430bbaa8b60SDan Kruchinin 		}
431bbaa8b60SDan Kruchinin 
432bbaa8b60SDan Kruchinin 		xflags = 0;
433bbaa8b60SDan Kruchinin 	} else {
434bbaa8b60SDan Kruchinin 		xflags = NLM_X_BLOCKING;
435bbaa8b60SDan Kruchinin 	}
436bbaa8b60SDan Kruchinin 
437bbaa8b60SDan Kruchinin 	nfs_add_locking_id(vp, curproc->p_pid, RLMPL_PID,
438bbaa8b60SDan Kruchinin 	    (char *)&curproc->p_pid, sizeof (pid_t));
439bbaa8b60SDan Kruchinin 
440bbaa8b60SDan Kruchinin 	error = nlm_call_lock(vp, flkp, hostp, fhp, flcb, vers, xflags);
441bbaa8b60SDan Kruchinin 	if (error != 0)
442bbaa8b60SDan Kruchinin 		return (error);
443bbaa8b60SDan Kruchinin 
444bbaa8b60SDan Kruchinin 	/*
445bbaa8b60SDan Kruchinin 	 * Save the lock locally.  This should not fail,
446bbaa8b60SDan Kruchinin 	 * because the server is authoritative about locks
447bbaa8b60SDan Kruchinin 	 * and it just told us we have the lock!
448bbaa8b60SDan Kruchinin 	 */
449bbaa8b60SDan Kruchinin 	error = nlm_local_setlk(vp, flkp, flags);
450bbaa8b60SDan Kruchinin 	if (error != 0) {
451bbaa8b60SDan Kruchinin 		/*
452bbaa8b60SDan Kruchinin 		 * That's unexpected situation. Just ignore the error.
453bbaa8b60SDan Kruchinin 		 */
454bbaa8b60SDan Kruchinin 		NLM_WARN("nlm_frlock_setlk: Failed to set local lock. "
455bbaa8b60SDan Kruchinin 		    "[err=%d]\n", error);
456bbaa8b60SDan Kruchinin 		error = 0;
457bbaa8b60SDan Kruchinin 	}
458bbaa8b60SDan Kruchinin 
459bbaa8b60SDan Kruchinin 	return (error);
460bbaa8b60SDan Kruchinin }
461bbaa8b60SDan Kruchinin 
462bbaa8b60SDan Kruchinin /*
463bbaa8b60SDan Kruchinin  * Cancel all client side remote locks/shares on the
464bbaa8b60SDan Kruchinin  * given host. Report to the processes that own
465bbaa8b60SDan Kruchinin  * cancelled locks that they are removed by force
466bbaa8b60SDan Kruchinin  * by sending SIGLOST.
467bbaa8b60SDan Kruchinin  */
468bbaa8b60SDan Kruchinin void
nlm_client_cancel_all(struct nlm_globals * g,struct nlm_host * hostp)469bbaa8b60SDan Kruchinin nlm_client_cancel_all(struct nlm_globals *g, struct nlm_host *hostp)
470bbaa8b60SDan Kruchinin {
471bbaa8b60SDan Kruchinin 	struct locklist *llp_head, *llp;
472bbaa8b60SDan Kruchinin 	struct nlm_shres *nsp_head, *nsp;
473bbaa8b60SDan Kruchinin 	struct netobj lm_fh;
474bbaa8b60SDan Kruchinin 	rpcvers_t vers;
475bbaa8b60SDan Kruchinin 	int error, sysid;
476bbaa8b60SDan Kruchinin 
477bbaa8b60SDan Kruchinin 	sysid = hostp->nh_sysid | LM_SYSID_CLIENT;
478bbaa8b60SDan Kruchinin 	nlm_host_cancel_slocks(g, hostp);
479bbaa8b60SDan Kruchinin 
480bbaa8b60SDan Kruchinin 	/*
481bbaa8b60SDan Kruchinin 	 * Destroy all active locks
482bbaa8b60SDan Kruchinin 	 */
483bbaa8b60SDan Kruchinin 	llp_head = llp = flk_get_active_locks(sysid, NOPID);
484bbaa8b60SDan Kruchinin 	while (llp != NULL) {
485bbaa8b60SDan Kruchinin 		llp->ll_flock.l_type = F_UNLCK;
486bbaa8b60SDan Kruchinin 
487bbaa8b60SDan Kruchinin 		error = nlm_init_fh_by_vp(llp->ll_vp, &lm_fh, &vers);
488bbaa8b60SDan Kruchinin 		if (error == 0)
489bbaa8b60SDan Kruchinin 			(void) nlm_call_unlock(&llp->ll_flock, hostp,
490bbaa8b60SDan Kruchinin 			    &lm_fh, vers);
491bbaa8b60SDan Kruchinin 
492bbaa8b60SDan Kruchinin 		nlm_local_cancelk(llp->ll_vp, &llp->ll_flock);
493bbaa8b60SDan Kruchinin 		llp = llp->ll_next;
494bbaa8b60SDan Kruchinin 	}
495bbaa8b60SDan Kruchinin 
496bbaa8b60SDan Kruchinin 	flk_free_locklist(llp_head);
497bbaa8b60SDan Kruchinin 
498bbaa8b60SDan Kruchinin 	/*
499bbaa8b60SDan Kruchinin 	 * Destroy all active share reservations
500bbaa8b60SDan Kruchinin 	 */
501bbaa8b60SDan Kruchinin 	nsp_head = nsp = nlm_get_active_shres(hostp);
502bbaa8b60SDan Kruchinin 	while (nsp != NULL) {
503bbaa8b60SDan Kruchinin 		error = nlm_init_fh_by_vp(nsp->ns_vp, &lm_fh, &vers);
504bbaa8b60SDan Kruchinin 		if (error == 0)
505bbaa8b60SDan Kruchinin 			(void) nlm_call_unshare(nsp->ns_shr, hostp,
506bbaa8b60SDan Kruchinin 			    &lm_fh, vers);
507bbaa8b60SDan Kruchinin 
508bbaa8b60SDan Kruchinin 		nlm_local_shrcancel(nsp->ns_vp, nsp->ns_shr);
509bbaa8b60SDan Kruchinin 		nlm_shres_untrack(hostp, nsp->ns_vp, nsp->ns_shr);
510bbaa8b60SDan Kruchinin 		nsp = nsp->ns_next;
511bbaa8b60SDan Kruchinin 	}
512bbaa8b60SDan Kruchinin 
513bbaa8b60SDan Kruchinin 	nlm_free_shrlist(nsp_head);
514bbaa8b60SDan Kruchinin }
515bbaa8b60SDan Kruchinin 
516bbaa8b60SDan Kruchinin /*
517bbaa8b60SDan Kruchinin  * The function determines whether the lock "fl" can
518bbaa8b60SDan Kruchinin  * be safely applied to the file vnode "vp" corresponds to.
519bbaa8b60SDan Kruchinin  * The lock can be "safely" applied if all the conditions
520bbaa8b60SDan Kruchinin  * above are held:
521bbaa8b60SDan Kruchinin  *  - It's not a mandatory lock
522bbaa8b60SDan Kruchinin  *  - The vnode wasn't mapped by anyone
523bbaa8b60SDan Kruchinin  *  - The vnode was mapped, but it hasn't any locks on it.
524bbaa8b60SDan Kruchinin  *  - The vnode was mapped and all locks it has occupies
525bbaa8b60SDan Kruchinin  *    the whole file.
526bbaa8b60SDan Kruchinin  */
527bbaa8b60SDan Kruchinin int
nlm_safelock(vnode_t * vp,const struct flock64 * fl,cred_t * cr)528bbaa8b60SDan Kruchinin nlm_safelock(vnode_t *vp, const struct flock64 *fl, cred_t *cr)
529bbaa8b60SDan Kruchinin {
530bbaa8b60SDan Kruchinin 	rnode_t *rp = VTOR(vp);
531bbaa8b60SDan Kruchinin 	struct vattr va;
532bbaa8b60SDan Kruchinin 	int err;
533bbaa8b60SDan Kruchinin 
534bbaa8b60SDan Kruchinin 	if ((rp->r_mapcnt > 0) && (fl->l_start != 0 || fl->l_len != 0))
535bbaa8b60SDan Kruchinin 		return (0);
536bbaa8b60SDan Kruchinin 
537bbaa8b60SDan Kruchinin 	va.va_mask = AT_MODE;
538bbaa8b60SDan Kruchinin 	err = VOP_GETATTR(vp, &va, 0, cr, NULL);
539bbaa8b60SDan Kruchinin 	if (err != 0)
540bbaa8b60SDan Kruchinin 		return (0);
541bbaa8b60SDan Kruchinin 
542bbaa8b60SDan Kruchinin 	/* NLM4 doesn't allow mandatory file locking */
543bbaa8b60SDan Kruchinin 	if (MANDLOCK(vp, va.va_mode))
544bbaa8b60SDan Kruchinin 		return (0);
545bbaa8b60SDan Kruchinin 
546bbaa8b60SDan Kruchinin 	return (1);
547bbaa8b60SDan Kruchinin }
548bbaa8b60SDan Kruchinin 
549bbaa8b60SDan Kruchinin /*
550bbaa8b60SDan Kruchinin  * The function determines whether it's safe to map
551bbaa8b60SDan Kruchinin  * a file correspoding to vnode vp.
552bbaa8b60SDan Kruchinin  * The mapping is considered to be "safe" if file
553bbaa8b60SDan Kruchinin  * either has no any locks on it or all locks it
554bbaa8b60SDan Kruchinin  * has occupy the whole file.
555bbaa8b60SDan Kruchinin  */
556bbaa8b60SDan Kruchinin int
nlm_safemap(const vnode_t * vp)557bbaa8b60SDan Kruchinin nlm_safemap(const vnode_t *vp)
558bbaa8b60SDan Kruchinin {
559bbaa8b60SDan Kruchinin 	struct locklist *llp, *llp_next;
560bbaa8b60SDan Kruchinin 	struct nlm_slock *nslp;
561bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
562bbaa8b60SDan Kruchinin 	int safe = 1;
563bbaa8b60SDan Kruchinin 
564bbaa8b60SDan Kruchinin 	/* Check active locks at first */
565bbaa8b60SDan Kruchinin 	llp = flk_active_locks_for_vp(vp);
566bbaa8b60SDan Kruchinin 	while (llp != NULL) {
567bbaa8b60SDan Kruchinin 		if ((llp->ll_vp == vp) &&
568bbaa8b60SDan Kruchinin 		    !NLM_FLOCK_IS_SAFE(&llp->ll_flock))
569bbaa8b60SDan Kruchinin 			safe = 0;
570bbaa8b60SDan Kruchinin 
571bbaa8b60SDan Kruchinin 		llp_next = llp->ll_next;
572bbaa8b60SDan Kruchinin 		VN_RELE(llp->ll_vp);
573bbaa8b60SDan Kruchinin 		kmem_free(llp, sizeof (*llp));
574bbaa8b60SDan Kruchinin 		llp = llp_next;
575bbaa8b60SDan Kruchinin 	}
576bbaa8b60SDan Kruchinin 	if (!safe)
577bbaa8b60SDan Kruchinin 		return (safe);
578bbaa8b60SDan Kruchinin 
579bbaa8b60SDan Kruchinin 	/* Then check sleeping locks if any */
580bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
581bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
582bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) {
583bbaa8b60SDan Kruchinin 		if (nslp->nsl_state == NLM_SL_BLOCKED &&
584bbaa8b60SDan Kruchinin 		    nslp->nsl_vp == vp &&
585bbaa8b60SDan Kruchinin 		    (nslp->nsl_lock.l_offset != 0 ||
586bbaa8b60SDan Kruchinin 		    nslp->nsl_lock.l_len != 0)) {
587bbaa8b60SDan Kruchinin 			safe = 0;
588bbaa8b60SDan Kruchinin 			break;
589bbaa8b60SDan Kruchinin 		}
590bbaa8b60SDan Kruchinin 	}
591bbaa8b60SDan Kruchinin 
592bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
593bbaa8b60SDan Kruchinin 	return (safe);
594bbaa8b60SDan Kruchinin }
595bbaa8b60SDan Kruchinin 
596bbaa8b60SDan Kruchinin int
nlm_has_sleep(const vnode_t * vp)597bbaa8b60SDan Kruchinin nlm_has_sleep(const vnode_t *vp)
598bbaa8b60SDan Kruchinin {
599bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
600bbaa8b60SDan Kruchinin 	struct nlm_slock *nslp;
601bbaa8b60SDan Kruchinin 	int has_slocks = FALSE;
602bbaa8b60SDan Kruchinin 
603bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
604bbaa8b60SDan Kruchinin 	mutex_enter(&g->lock);
605bbaa8b60SDan Kruchinin 	TAILQ_FOREACH(nslp, &g->nlm_slocks, nsl_link) {
606bbaa8b60SDan Kruchinin 		if (nslp->nsl_state == NLM_SL_BLOCKED &&
607bbaa8b60SDan Kruchinin 		    nslp->nsl_vp == vp) {
608bbaa8b60SDan Kruchinin 			has_slocks = TRUE;
609bbaa8b60SDan Kruchinin 			break;
610bbaa8b60SDan Kruchinin 		}
611bbaa8b60SDan Kruchinin 	}
612bbaa8b60SDan Kruchinin 
613bbaa8b60SDan Kruchinin 	mutex_exit(&g->lock);
614bbaa8b60SDan Kruchinin 	return (has_slocks);
615bbaa8b60SDan Kruchinin }
616bbaa8b60SDan Kruchinin 
617bbaa8b60SDan Kruchinin void
nlm_register_lock_locally(struct vnode * vp,struct nlm_host * hostp,struct flock64 * flk,int flags,u_offset_t offset)618bbaa8b60SDan Kruchinin nlm_register_lock_locally(struct vnode *vp, struct nlm_host *hostp,
619bbaa8b60SDan Kruchinin     struct flock64 *flk, int flags, u_offset_t offset)
620bbaa8b60SDan Kruchinin {
621*745caa42SMarcel Telka 	struct nlm_globals *g = NULL;
622bbaa8b60SDan Kruchinin 	int sysid = 0;
623bbaa8b60SDan Kruchinin 
6245cd496e3SBryan Cantrill 	if (hostp == NULL) {
6255cd496e3SBryan Cantrill 		mntinfo_t *mi;
6265cd496e3SBryan Cantrill 		servinfo_t *sv;
6275cd496e3SBryan Cantrill 		const char *netid;
6285cd496e3SBryan Cantrill 
6295cd496e3SBryan Cantrill 		mi = VTOMI(vp);
6305cd496e3SBryan Cantrill 		sv = mi->mi_curr_serv;
6315cd496e3SBryan Cantrill 		netid = nlm_knc_to_netid(sv->sv_knconf);
6325cd496e3SBryan Cantrill 
6335cd496e3SBryan Cantrill 		if (netid != NULL) {
6345cd496e3SBryan Cantrill 			g = zone_getspecific(nlm_zone_key, curzone);
6355cd496e3SBryan Cantrill 			hostp = nlm_host_findcreate(g, sv->sv_hostname,
6365cd496e3SBryan Cantrill 			    netid, &sv->sv_addr);
6375cd496e3SBryan Cantrill 		}
6385cd496e3SBryan Cantrill 	}
6395cd496e3SBryan Cantrill 
640bbaa8b60SDan Kruchinin 	if (hostp != NULL) {
641bbaa8b60SDan Kruchinin 		sysid = hostp->nh_sysid | LM_SYSID_CLIENT;
642*745caa42SMarcel Telka 
643*745caa42SMarcel Telka 		if (g != NULL)
644*745caa42SMarcel Telka 			nlm_host_release(g, hostp);
645bbaa8b60SDan Kruchinin 	}
646bbaa8b60SDan Kruchinin 
647bbaa8b60SDan Kruchinin 	flk->l_sysid = sysid;
648bbaa8b60SDan Kruchinin 	(void) convoff(vp, flk, 0, (offset_t)offset);
649bbaa8b60SDan Kruchinin 	(void) nlm_local_setlk(vp, flk, flags);
650bbaa8b60SDan Kruchinin }
651bbaa8b60SDan Kruchinin 
652bbaa8b60SDan Kruchinin 
653bbaa8b60SDan Kruchinin /*
654bbaa8b60SDan Kruchinin  * The BSD code had functions here to "reclaim" (destroy)
655bbaa8b60SDan Kruchinin  * remote locks when a vnode is being forcibly destroyed.
656bbaa8b60SDan Kruchinin  * We just keep vnodes around until statd tells us the
657bbaa8b60SDan Kruchinin  * client has gone away.
658bbaa8b60SDan Kruchinin  */
659bbaa8b60SDan Kruchinin 
660bbaa8b60SDan Kruchinin static int
nlm_reclaim_lock(struct nlm_host * hostp,vnode_t * vp,struct flock64 * flp,int32_t orig_state)661bbaa8b60SDan Kruchinin nlm_reclaim_lock(struct nlm_host *hostp, vnode_t *vp,
662bbaa8b60SDan Kruchinin     struct flock64 *flp, int32_t orig_state)
663bbaa8b60SDan Kruchinin {
664bbaa8b60SDan Kruchinin 	struct netobj lm_fh;
665bbaa8b60SDan Kruchinin 	int error, state;
666bbaa8b60SDan Kruchinin 	rpcvers_t vers;
667bbaa8b60SDan Kruchinin 
668bbaa8b60SDan Kruchinin 	/*
669bbaa8b60SDan Kruchinin 	 * If the remote NSM state changes during recovery, the host
670bbaa8b60SDan Kruchinin 	 * must have rebooted a second time. In that case, we must
671bbaa8b60SDan Kruchinin 	 * restart the recovery.
672bbaa8b60SDan Kruchinin 	 */
673bbaa8b60SDan Kruchinin 	state = nlm_host_get_state(hostp);
674bbaa8b60SDan Kruchinin 	if (state != orig_state)
675bbaa8b60SDan Kruchinin 		return (ERESTART);
676bbaa8b60SDan Kruchinin 
677bbaa8b60SDan Kruchinin 	error = nlm_init_fh_by_vp(vp, &lm_fh, &vers);
678bbaa8b60SDan Kruchinin 	if (error != 0)
679bbaa8b60SDan Kruchinin 		return (error);
680bbaa8b60SDan Kruchinin 
681bbaa8b60SDan Kruchinin 	return (nlm_call_lock(vp, flp, hostp, &lm_fh,
682bbaa8b60SDan Kruchinin 	    NULL, vers, NLM_X_RECLAIM));
683bbaa8b60SDan Kruchinin }
684bbaa8b60SDan Kruchinin 
685bbaa8b60SDan Kruchinin /*
686bbaa8b60SDan Kruchinin  * Get local lock information for some NFS server.
687bbaa8b60SDan Kruchinin  *
688bbaa8b60SDan Kruchinin  * This gets (checks for) a local conflicting lock.
689bbaa8b60SDan Kruchinin  * Note: Modifies passed flock, if a conflict is found,
690bbaa8b60SDan Kruchinin  * but the caller expects that.
691bbaa8b60SDan Kruchinin  */
692bbaa8b60SDan Kruchinin static int
nlm_local_getlk(vnode_t * vp,struct flock64 * fl,int flags)693bbaa8b60SDan Kruchinin nlm_local_getlk(vnode_t *vp, struct flock64 *fl, int flags)
694bbaa8b60SDan Kruchinin {
695bbaa8b60SDan Kruchinin 	VERIFY(fl->l_whence == SEEK_SET);
696bbaa8b60SDan Kruchinin 	return (reclock(vp, fl, 0, flags, 0, NULL));
697bbaa8b60SDan Kruchinin }
698bbaa8b60SDan Kruchinin 
699bbaa8b60SDan Kruchinin /*
700bbaa8b60SDan Kruchinin  * Set local lock information for some NFS server.
701bbaa8b60SDan Kruchinin  *
702bbaa8b60SDan Kruchinin  * Called after a lock request (set or clear) succeeded. We record the
703bbaa8b60SDan Kruchinin  * details in the local lock manager. Note that since the remote
704bbaa8b60SDan Kruchinin  * server has granted the lock, we can be sure that it doesn't
705bbaa8b60SDan Kruchinin  * conflict with any other locks we have in the local lock manager.
706bbaa8b60SDan Kruchinin  *
707bbaa8b60SDan Kruchinin  * Since it is possible that host may also make NLM client requests to
708bbaa8b60SDan Kruchinin  * our NLM server, we use a different sysid value to record our own
709bbaa8b60SDan Kruchinin  * client locks.
710bbaa8b60SDan Kruchinin  *
711bbaa8b60SDan Kruchinin  * Note that since it is possible for us to receive replies from the
712bbaa8b60SDan Kruchinin  * server in a different order than the locks were granted (e.g. if
713bbaa8b60SDan Kruchinin  * many local threads are contending for the same lock), we must use a
714bbaa8b60SDan Kruchinin  * blocking operation when registering with the local lock manager.
715bbaa8b60SDan Kruchinin  * We expect that any actual wait will be rare and short hence we
716bbaa8b60SDan Kruchinin  * ignore signals for this.
717bbaa8b60SDan Kruchinin  */
718bbaa8b60SDan Kruchinin static int
nlm_local_setlk(vnode_t * vp,struct flock64 * fl,int flags)719bbaa8b60SDan Kruchinin nlm_local_setlk(vnode_t *vp, struct flock64 *fl, int flags)
720bbaa8b60SDan Kruchinin {
721bbaa8b60SDan Kruchinin 	VERIFY(fl->l_whence == SEEK_SET);
722bbaa8b60SDan Kruchinin 	return (reclock(vp, fl, SETFLCK, flags, 0, NULL));
723bbaa8b60SDan Kruchinin }
724bbaa8b60SDan Kruchinin 
725bbaa8b60SDan Kruchinin /*
726bbaa8b60SDan Kruchinin  * Cancel local lock and send send SIGLOST signal
727bbaa8b60SDan Kruchinin  * to the lock owner.
728bbaa8b60SDan Kruchinin  *
729bbaa8b60SDan Kruchinin  * NOTE: modifies flp
730bbaa8b60SDan Kruchinin  */
731bbaa8b60SDan Kruchinin static void
nlm_local_cancelk(vnode_t * vp,struct flock64 * flp)732bbaa8b60SDan Kruchinin nlm_local_cancelk(vnode_t *vp, struct flock64 *flp)
733bbaa8b60SDan Kruchinin {
734bbaa8b60SDan Kruchinin 	flp->l_type = F_UNLCK;
735bbaa8b60SDan Kruchinin 	(void) nlm_local_setlk(vp, flp, FREAD | FWRITE);
736bbaa8b60SDan Kruchinin 	nlm_send_siglost(flp->l_pid);
737bbaa8b60SDan Kruchinin }
738bbaa8b60SDan Kruchinin 
739bbaa8b60SDan Kruchinin /*
740bbaa8b60SDan Kruchinin  * Do NLM_LOCK call.
741bbaa8b60SDan Kruchinin  * Was: nlm_setlock()
742bbaa8b60SDan Kruchinin  *
743bbaa8b60SDan Kruchinin  * NOTE: nlm_call_lock() function should care about locking/unlocking
744bbaa8b60SDan Kruchinin  * of rnode->r_lkserlock which should be released before nlm_call_lock()
745bbaa8b60SDan Kruchinin  * sleeps on waiting lock and acquired when it wakes up.
746bbaa8b60SDan Kruchinin  */
747bbaa8b60SDan Kruchinin static int
nlm_call_lock(vnode_t * vp,struct flock64 * flp,struct nlm_host * hostp,struct netobj * fhp,struct flk_callback * flcb,int vers,int xflags)748bbaa8b60SDan Kruchinin nlm_call_lock(vnode_t *vp, struct flock64 *flp,
749*745caa42SMarcel Telka     struct nlm_host *hostp, struct netobj *fhp,
750*745caa42SMarcel Telka     struct flk_callback *flcb, int vers, int xflags)
751bbaa8b60SDan Kruchinin {
752bbaa8b60SDan Kruchinin 	struct nlm4_lockargs args;
753bbaa8b60SDan Kruchinin 	struct nlm_owner_handle oh;
754bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
755bbaa8b60SDan Kruchinin 	rnode_t *rnp = VTOR(vp);
756bbaa8b60SDan Kruchinin 	struct nlm_slock *nslp = NULL;
757bbaa8b60SDan Kruchinin 	uint32_t xid;
758bbaa8b60SDan Kruchinin 	int error = 0;
759bbaa8b60SDan Kruchinin 
760bbaa8b60SDan Kruchinin 	bzero(&args, sizeof (args));
761bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
762bbaa8b60SDan Kruchinin 	nlm_init_lock(&args.alock, flp, fhp, &oh);
763bbaa8b60SDan Kruchinin 
764bbaa8b60SDan Kruchinin 	args.exclusive = (flp->l_type == F_WRLCK);
765bbaa8b60SDan Kruchinin 	args.reclaim = xflags & NLM_X_RECLAIM;
766bbaa8b60SDan Kruchinin 	args.state = g->nsm_state;
767bbaa8b60SDan Kruchinin 	args.cookie.n_len = sizeof (xid);
768bbaa8b60SDan Kruchinin 	args.cookie.n_bytes = (char *)&xid;
769bbaa8b60SDan Kruchinin 
770bbaa8b60SDan Kruchinin 	oh.oh_sysid = hostp->nh_sysid;
771bbaa8b60SDan Kruchinin 	xid = atomic_inc_32_nv(&nlm_xid);
772bbaa8b60SDan Kruchinin 
773bbaa8b60SDan Kruchinin 	if (xflags & NLM_X_BLOCKING) {
774bbaa8b60SDan Kruchinin 		args.block = TRUE;
775bbaa8b60SDan Kruchinin 		nslp = nlm_slock_register(g, hostp, &args.alock, vp);
776bbaa8b60SDan Kruchinin 	}
777bbaa8b60SDan Kruchinin 
778bbaa8b60SDan Kruchinin 	for (;;) {
779bbaa8b60SDan Kruchinin 		nlm_rpc_t *rpcp;
780bbaa8b60SDan Kruchinin 		enum clnt_stat stat;
781bbaa8b60SDan Kruchinin 		struct nlm4_res res;
782bbaa8b60SDan Kruchinin 		enum nlm4_stats nlm_err;
783bbaa8b60SDan Kruchinin 
784bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(hostp, vers, &rpcp);
785bbaa8b60SDan Kruchinin 		if (error != 0) {
786bbaa8b60SDan Kruchinin 			error = ENOLCK;
787bbaa8b60SDan Kruchinin 			goto out;
788bbaa8b60SDan Kruchinin 		}
789bbaa8b60SDan Kruchinin 
790bbaa8b60SDan Kruchinin 		bzero(&res, sizeof (res));
791bbaa8b60SDan Kruchinin 		stat = nlm_lock_rpc(&args, &res, rpcp->nr_handle, vers);
792bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(hostp, rpcp);
793bbaa8b60SDan Kruchinin 
794bbaa8b60SDan Kruchinin 		error = nlm_map_clnt_stat(stat);
795bbaa8b60SDan Kruchinin 		if (error != 0) {
796bbaa8b60SDan Kruchinin 			if (error == EAGAIN)
797bbaa8b60SDan Kruchinin 				continue;
798bbaa8b60SDan Kruchinin 
799bbaa8b60SDan Kruchinin 			goto out;
800bbaa8b60SDan Kruchinin 		}
801bbaa8b60SDan Kruchinin 
802bbaa8b60SDan Kruchinin 		DTRACE_PROBE1(lock__res, enum nlm4_stats, res.stat.stat);
803bbaa8b60SDan Kruchinin 		nlm_err = res.stat.stat;
804bbaa8b60SDan Kruchinin 		xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res);
805bbaa8b60SDan Kruchinin 		if (nlm_err == nlm4_denied_grace_period) {
806bbaa8b60SDan Kruchinin 			if (args.reclaim) {
807bbaa8b60SDan Kruchinin 				error = ENOLCK;
808bbaa8b60SDan Kruchinin 				goto out;
809bbaa8b60SDan Kruchinin 			}
810bbaa8b60SDan Kruchinin 
811bbaa8b60SDan Kruchinin 			error = nlm_host_wait_grace(hostp);
812bbaa8b60SDan Kruchinin 			if (error != 0)
813bbaa8b60SDan Kruchinin 				goto out;
814bbaa8b60SDan Kruchinin 
815bbaa8b60SDan Kruchinin 			continue;
816bbaa8b60SDan Kruchinin 		}
817bbaa8b60SDan Kruchinin 
818bbaa8b60SDan Kruchinin 		switch (nlm_err) {
819bbaa8b60SDan Kruchinin 		case nlm4_granted:
820bbaa8b60SDan Kruchinin 		case nlm4_blocked:
821bbaa8b60SDan Kruchinin 			error = 0;
822bbaa8b60SDan Kruchinin 			break;
823bbaa8b60SDan Kruchinin 
824bbaa8b60SDan Kruchinin 		case nlm4_denied:
825bbaa8b60SDan Kruchinin 			if (nslp != NULL) {
826bbaa8b60SDan Kruchinin 				NLM_WARN("nlm_call_lock: got nlm4_denied for "
827bbaa8b60SDan Kruchinin 				    "blocking lock\n");
828bbaa8b60SDan Kruchinin 			}
829bbaa8b60SDan Kruchinin 
830bbaa8b60SDan Kruchinin 			error = EAGAIN;
831bbaa8b60SDan Kruchinin 			break;
832bbaa8b60SDan Kruchinin 
833bbaa8b60SDan Kruchinin 		default:
834bbaa8b60SDan Kruchinin 			error = nlm_map_status(nlm_err);
835bbaa8b60SDan Kruchinin 		}
836bbaa8b60SDan Kruchinin 
837bbaa8b60SDan Kruchinin 		/*
838bbaa8b60SDan Kruchinin 		 * If we deal with either non-blocking lock or
839bbaa8b60SDan Kruchinin 		 * with a blocking locks that wasn't blocked on
840bbaa8b60SDan Kruchinin 		 * the server side (by some reason), our work
841bbaa8b60SDan Kruchinin 		 * is finished.
842bbaa8b60SDan Kruchinin 		 */
843bbaa8b60SDan Kruchinin 		if (nslp == NULL			||
844bbaa8b60SDan Kruchinin 		    nlm_err != nlm4_blocked		||
845bbaa8b60SDan Kruchinin 		    error != 0)
846bbaa8b60SDan Kruchinin 			goto out;
847bbaa8b60SDan Kruchinin 
848bbaa8b60SDan Kruchinin 		/*
849bbaa8b60SDan Kruchinin 		 * Before releasing the r_lkserlock of rnode, we should
850bbaa8b60SDan Kruchinin 		 * check whether the new lock is "safe". If it's not
851bbaa8b60SDan Kruchinin 		 * safe, disable caching for the given vnode. That is done
852bbaa8b60SDan Kruchinin 		 * for sleeping locks only that are waiting for a GRANT reply
853bbaa8b60SDan Kruchinin 		 * from the NLM server.
854bbaa8b60SDan Kruchinin 		 *
855bbaa8b60SDan Kruchinin 		 * NOTE: the vnode cache can be enabled back later if an
856bbaa8b60SDan Kruchinin 		 * unsafe lock will be merged with existent locks so that
857bbaa8b60SDan Kruchinin 		 * it will become safe. This condition is checked in the
858bbaa8b60SDan Kruchinin 		 * NFSv3 code (see nfs_lockcompletion).
859bbaa8b60SDan Kruchinin 		 */
860bbaa8b60SDan Kruchinin 		if (!NLM_FLOCK_IS_SAFE(flp)) {
861bbaa8b60SDan Kruchinin 			mutex_enter(&vp->v_lock);
862bbaa8b60SDan Kruchinin 			vp->v_flag &= ~VNOCACHE;
863bbaa8b60SDan Kruchinin 			mutex_exit(&vp->v_lock);
864bbaa8b60SDan Kruchinin 		}
865bbaa8b60SDan Kruchinin 
866bbaa8b60SDan Kruchinin 		/*
867bbaa8b60SDan Kruchinin 		 * The server should call us back with a
868bbaa8b60SDan Kruchinin 		 * granted message when the lock succeeds.
869bbaa8b60SDan Kruchinin 		 * In order to deal with broken servers,
870bbaa8b60SDan Kruchinin 		 * lost granted messages, or server reboots,
871bbaa8b60SDan Kruchinin 		 * we will also re-try every few seconds.
872bbaa8b60SDan Kruchinin 		 *
873bbaa8b60SDan Kruchinin 		 * Note: We're supposed to call these
874bbaa8b60SDan Kruchinin 		 * flk_invoke_callbacks when blocking.
875bbaa8b60SDan Kruchinin 		 * Take care on rnode->r_lkserlock, we should
876bbaa8b60SDan Kruchinin 		 * release it before going to sleep.
877bbaa8b60SDan Kruchinin 		 */
878bbaa8b60SDan Kruchinin 		(void) flk_invoke_callbacks(flcb, FLK_BEFORE_SLEEP);
879bbaa8b60SDan Kruchinin 		nfs_rw_exit(&rnp->r_lkserlock);
880bbaa8b60SDan Kruchinin 
881bbaa8b60SDan Kruchinin 		error = nlm_slock_wait(g, nslp, g->retrans_tmo);
882bbaa8b60SDan Kruchinin 
883bbaa8b60SDan Kruchinin 		/*
884bbaa8b60SDan Kruchinin 		 * NFS expects that we return with rnode->r_lkserlock
885bbaa8b60SDan Kruchinin 		 * locked on write, lock it back.
886bbaa8b60SDan Kruchinin 		 *
887bbaa8b60SDan Kruchinin 		 * NOTE: nfs_rw_enter_sig() can be either interruptible
888bbaa8b60SDan Kruchinin 		 * or not. It depends on options of NFS mount. Here
889bbaa8b60SDan Kruchinin 		 * we're _always_ uninterruptible (independently of mount
890bbaa8b60SDan Kruchinin 		 * options), because nfs_frlock/nfs3_frlock expects that
891bbaa8b60SDan Kruchinin 		 * we return with rnode->r_lkserlock acquired. So we don't
892bbaa8b60SDan Kruchinin 		 * want our lock attempt to be interrupted by a signal.
893bbaa8b60SDan Kruchinin 		 */
894bbaa8b60SDan Kruchinin 		(void) nfs_rw_enter_sig(&rnp->r_lkserlock, RW_WRITER, 0);
895bbaa8b60SDan Kruchinin 		(void) flk_invoke_callbacks(flcb, FLK_AFTER_SLEEP);
896bbaa8b60SDan Kruchinin 
897bbaa8b60SDan Kruchinin 		if (error == 0) {
898bbaa8b60SDan Kruchinin 			break;
899bbaa8b60SDan Kruchinin 		} else if (error == EINTR) {
900bbaa8b60SDan Kruchinin 			/*
901bbaa8b60SDan Kruchinin 			 * We need to call the server to cancel our
902bbaa8b60SDan Kruchinin 			 * lock request.
903bbaa8b60SDan Kruchinin 			 */
904bbaa8b60SDan Kruchinin 			DTRACE_PROBE1(cancel__lock, int, error);
905bbaa8b60SDan Kruchinin 			(void) nlm_call_cancel(&args, hostp, vers);
906bbaa8b60SDan Kruchinin 			break;
907bbaa8b60SDan Kruchinin 		} else {
908bbaa8b60SDan Kruchinin 			/*
909bbaa8b60SDan Kruchinin 			 * Timeout happened, resend the lock request to
910bbaa8b60SDan Kruchinin 			 * the server. Well, we're a bit paranoid here,
911bbaa8b60SDan Kruchinin 			 * but keep in mind previous request could lost
912bbaa8b60SDan Kruchinin 			 * (especially with conectionless transport).
913bbaa8b60SDan Kruchinin 			 */
914bbaa8b60SDan Kruchinin 
915bbaa8b60SDan Kruchinin 			ASSERT(error == ETIMEDOUT);
916bbaa8b60SDan Kruchinin 			continue;
917bbaa8b60SDan Kruchinin 		}
918bbaa8b60SDan Kruchinin 	}
919bbaa8b60SDan Kruchinin 
920bbaa8b60SDan Kruchinin 	/*
921bbaa8b60SDan Kruchinin 	 * We could disable the vnode cache for the given _sleeping_
922bbaa8b60SDan Kruchinin 	 * (codition: nslp != NULL) lock if it was unsafe. Normally,
923bbaa8b60SDan Kruchinin 	 * nfs_lockcompletion() function can enable the vnode cache
924bbaa8b60SDan Kruchinin 	 * back if the lock becomes safe after activativation. But it
925bbaa8b60SDan Kruchinin 	 * will not happen if any error occurs on the locking path.
926bbaa8b60SDan Kruchinin 	 *
927bbaa8b60SDan Kruchinin 	 * Here we enable the vnode cache back if the error occurred
928bbaa8b60SDan Kruchinin 	 * and if there aren't any unsafe locks on the given vnode.
929bbaa8b60SDan Kruchinin 	 * Note that if error happened, sleeping lock was derigistered.
930bbaa8b60SDan Kruchinin 	 */
931bbaa8b60SDan Kruchinin 	if (error != 0 && nslp != NULL && nlm_safemap(vp)) {
932bbaa8b60SDan Kruchinin 		mutex_enter(&vp->v_lock);
933bbaa8b60SDan Kruchinin 		vp->v_flag |= VNOCACHE;
934bbaa8b60SDan Kruchinin 		mutex_exit(&vp->v_lock);
935bbaa8b60SDan Kruchinin 	}
936bbaa8b60SDan Kruchinin 
937bbaa8b60SDan Kruchinin out:
938bbaa8b60SDan Kruchinin 	if (nslp != NULL)
939bbaa8b60SDan Kruchinin 		nlm_slock_unregister(g, nslp);
940bbaa8b60SDan Kruchinin 
941bbaa8b60SDan Kruchinin 	return (error);
942bbaa8b60SDan Kruchinin }
943bbaa8b60SDan Kruchinin 
944bbaa8b60SDan Kruchinin /*
945bbaa8b60SDan Kruchinin  * Do NLM_CANCEL call.
946bbaa8b60SDan Kruchinin  * Helper for nlm_call_lock() error recovery.
947bbaa8b60SDan Kruchinin  */
948bbaa8b60SDan Kruchinin static int
nlm_call_cancel(struct nlm4_lockargs * largs,struct nlm_host * hostp,int vers)949bbaa8b60SDan Kruchinin nlm_call_cancel(struct nlm4_lockargs *largs,
950*745caa42SMarcel Telka     struct nlm_host *hostp, int vers)
951bbaa8b60SDan Kruchinin {
952bbaa8b60SDan Kruchinin 	nlm4_cancargs cargs;
953bbaa8b60SDan Kruchinin 	uint32_t xid;
954bbaa8b60SDan Kruchinin 	int error, retries;
955bbaa8b60SDan Kruchinin 
956bbaa8b60SDan Kruchinin 	bzero(&cargs, sizeof (cargs));
957bbaa8b60SDan Kruchinin 
958bbaa8b60SDan Kruchinin 	xid = atomic_inc_32_nv(&nlm_xid);
959bbaa8b60SDan Kruchinin 	cargs.cookie.n_len = sizeof (xid);
960bbaa8b60SDan Kruchinin 	cargs.cookie.n_bytes = (char *)&xid;
961bbaa8b60SDan Kruchinin 	cargs.block	= largs->block;
962bbaa8b60SDan Kruchinin 	cargs.exclusive	= largs->exclusive;
963bbaa8b60SDan Kruchinin 	cargs.alock	= largs->alock;
964bbaa8b60SDan Kruchinin 
965bbaa8b60SDan Kruchinin 	/*
966bbaa8b60SDan Kruchinin 	 * Unlike all other nlm_call_* functions, nlm_call_cancel
967bbaa8b60SDan Kruchinin 	 * doesn't spin forever until it gets reasonable response
968bbaa8b60SDan Kruchinin 	 * from NLM server. It makes limited number of retries and
969bbaa8b60SDan Kruchinin 	 * if server doesn't send a reasonable reply, it returns an
970bbaa8b60SDan Kruchinin 	 * error. It behaves like that because it's called from nlm_call_lock
971bbaa8b60SDan Kruchinin 	 * with blocked signals and thus it can not be interrupted from
972bbaa8b60SDan Kruchinin 	 * user space.
973bbaa8b60SDan Kruchinin 	 */
974bbaa8b60SDan Kruchinin 	for (retries = 0; retries < NLM_CANCEL_NRETRS; retries++) {
975bbaa8b60SDan Kruchinin 		nlm_rpc_t *rpcp;
976bbaa8b60SDan Kruchinin 		enum clnt_stat stat;
977bbaa8b60SDan Kruchinin 		struct nlm4_res res;
978bbaa8b60SDan Kruchinin 
979bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(hostp, vers, &rpcp);
980bbaa8b60SDan Kruchinin 		if (error != 0)
981bbaa8b60SDan Kruchinin 			return (ENOLCK);
982bbaa8b60SDan Kruchinin 
983bbaa8b60SDan Kruchinin 		bzero(&res, sizeof (res));
984bbaa8b60SDan Kruchinin 		stat = nlm_cancel_rpc(&cargs, &res, rpcp->nr_handle, vers);
985bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(hostp, rpcp);
986bbaa8b60SDan Kruchinin 
987bbaa8b60SDan Kruchinin 		DTRACE_PROBE1(cancel__rloop_end, enum clnt_stat, stat);
988bbaa8b60SDan Kruchinin 		error = nlm_map_clnt_stat(stat);
989bbaa8b60SDan Kruchinin 		if (error != 0) {
990bbaa8b60SDan Kruchinin 			if (error == EAGAIN)
991bbaa8b60SDan Kruchinin 				continue;
992bbaa8b60SDan Kruchinin 
993bbaa8b60SDan Kruchinin 			return (error);
994bbaa8b60SDan Kruchinin 		}
995bbaa8b60SDan Kruchinin 
996bbaa8b60SDan Kruchinin 		DTRACE_PROBE1(cancel__res, enum nlm4_stats, res.stat.stat);
997bbaa8b60SDan Kruchinin 		switch (res.stat.stat) {
998bbaa8b60SDan Kruchinin 			/*
999bbaa8b60SDan Kruchinin 			 * There was nothing to cancel. We are going to go ahead
1000bbaa8b60SDan Kruchinin 			 * and assume we got the lock.
1001bbaa8b60SDan Kruchinin 			 */
1002bbaa8b60SDan Kruchinin 		case nlm_denied:
1003bbaa8b60SDan Kruchinin 			/*
1004bbaa8b60SDan Kruchinin 			 * The server has recently rebooted.  Treat this as a
1005bbaa8b60SDan Kruchinin 			 * successful cancellation.
1006bbaa8b60SDan Kruchinin 			 */
1007bbaa8b60SDan Kruchinin 		case nlm4_denied_grace_period:
1008bbaa8b60SDan Kruchinin 			/*
1009bbaa8b60SDan Kruchinin 			 * We managed to cancel.
1010bbaa8b60SDan Kruchinin 			 */
1011bbaa8b60SDan Kruchinin 		case nlm4_granted:
1012bbaa8b60SDan Kruchinin 			error = 0;
1013bbaa8b60SDan Kruchinin 			break;
1014bbaa8b60SDan Kruchinin 
1015bbaa8b60SDan Kruchinin 		default:
1016bbaa8b60SDan Kruchinin 			/*
1017bbaa8b60SDan Kruchinin 			 * Broken server implementation.  Can't really do
1018bbaa8b60SDan Kruchinin 			 * anything here.
1019bbaa8b60SDan Kruchinin 			 */
1020bbaa8b60SDan Kruchinin 			error = EIO;
1021bbaa8b60SDan Kruchinin 			break;
1022bbaa8b60SDan Kruchinin 		}
1023bbaa8b60SDan Kruchinin 
1024bbaa8b60SDan Kruchinin 		xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res);
1025bbaa8b60SDan Kruchinin 		break;
1026bbaa8b60SDan Kruchinin 	}
1027bbaa8b60SDan Kruchinin 
1028bbaa8b60SDan Kruchinin 	return (error);
1029bbaa8b60SDan Kruchinin }
1030bbaa8b60SDan Kruchinin 
1031bbaa8b60SDan Kruchinin /*
1032bbaa8b60SDan Kruchinin  * Do NLM_UNLOCK call.
1033bbaa8b60SDan Kruchinin  * Was: nlm_clearlock
1034bbaa8b60SDan Kruchinin  */
1035bbaa8b60SDan Kruchinin static int
nlm_call_unlock(struct flock64 * flp,struct nlm_host * hostp,struct netobj * fhp,int vers)1036bbaa8b60SDan Kruchinin nlm_call_unlock(struct flock64 *flp, struct nlm_host *hostp,
1037bbaa8b60SDan Kruchinin     struct netobj *fhp, int vers)
1038bbaa8b60SDan Kruchinin {
1039bbaa8b60SDan Kruchinin 	struct nlm4_unlockargs args;
1040bbaa8b60SDan Kruchinin 	struct nlm_owner_handle oh;
1041bbaa8b60SDan Kruchinin 	enum nlm4_stats nlm_err;
1042bbaa8b60SDan Kruchinin 	uint32_t xid;
1043bbaa8b60SDan Kruchinin 	int error;
1044bbaa8b60SDan Kruchinin 
1045bbaa8b60SDan Kruchinin 	bzero(&args, sizeof (args));
1046bbaa8b60SDan Kruchinin 	nlm_init_lock(&args.alock, flp, fhp, &oh);
1047bbaa8b60SDan Kruchinin 
1048bbaa8b60SDan Kruchinin 	oh.oh_sysid = hostp->nh_sysid;
1049bbaa8b60SDan Kruchinin 	xid = atomic_inc_32_nv(&nlm_xid);
1050bbaa8b60SDan Kruchinin 	args.cookie.n_len = sizeof (xid);
1051bbaa8b60SDan Kruchinin 	args.cookie.n_bytes = (char *)&xid;
1052bbaa8b60SDan Kruchinin 
1053bbaa8b60SDan Kruchinin 	for (;;) {
1054bbaa8b60SDan Kruchinin 		nlm_rpc_t *rpcp;
1055bbaa8b60SDan Kruchinin 		struct nlm4_res res;
1056bbaa8b60SDan Kruchinin 		enum clnt_stat stat;
1057bbaa8b60SDan Kruchinin 
1058bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(hostp, vers, &rpcp);
1059bbaa8b60SDan Kruchinin 		if (error != 0)
1060bbaa8b60SDan Kruchinin 			return (ENOLCK);
1061bbaa8b60SDan Kruchinin 
1062bbaa8b60SDan Kruchinin 		bzero(&res, sizeof (res));
1063bbaa8b60SDan Kruchinin 		stat = nlm_unlock_rpc(&args, &res, rpcp->nr_handle, vers);
1064bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(hostp, rpcp);
1065bbaa8b60SDan Kruchinin 
1066bbaa8b60SDan Kruchinin 		error = nlm_map_clnt_stat(stat);
1067bbaa8b60SDan Kruchinin 		if (error != 0) {
1068bbaa8b60SDan Kruchinin 			if (error == EAGAIN)
1069bbaa8b60SDan Kruchinin 				continue;
1070bbaa8b60SDan Kruchinin 
1071bbaa8b60SDan Kruchinin 			return (error);
1072bbaa8b60SDan Kruchinin 		}
1073bbaa8b60SDan Kruchinin 
1074bbaa8b60SDan Kruchinin 		DTRACE_PROBE1(unlock__res, enum nlm4_stats, res.stat.stat);
1075bbaa8b60SDan Kruchinin 		nlm_err = res.stat.stat;
1076bbaa8b60SDan Kruchinin 		xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res);
1077bbaa8b60SDan Kruchinin 		if (nlm_err == nlm4_denied_grace_period) {
1078bbaa8b60SDan Kruchinin 			error = nlm_host_wait_grace(hostp);
1079bbaa8b60SDan Kruchinin 			if (error != 0)
1080bbaa8b60SDan Kruchinin 				return (error);
1081bbaa8b60SDan Kruchinin 
1082bbaa8b60SDan Kruchinin 			continue;
1083bbaa8b60SDan Kruchinin 		}
1084bbaa8b60SDan Kruchinin 
1085bbaa8b60SDan Kruchinin 		break;
1086bbaa8b60SDan Kruchinin 	}
1087bbaa8b60SDan Kruchinin 
1088bbaa8b60SDan Kruchinin 	/* special cases */
1089bbaa8b60SDan Kruchinin 	switch (nlm_err) {
1090bbaa8b60SDan Kruchinin 	case nlm4_denied:
1091bbaa8b60SDan Kruchinin 		error = EINVAL;
1092bbaa8b60SDan Kruchinin 		break;
1093bbaa8b60SDan Kruchinin 	default:
1094bbaa8b60SDan Kruchinin 		error = nlm_map_status(nlm_err);
1095bbaa8b60SDan Kruchinin 		break;
1096bbaa8b60SDan Kruchinin 	}
1097bbaa8b60SDan Kruchinin 
1098bbaa8b60SDan Kruchinin 	return (error);
1099bbaa8b60SDan Kruchinin }
1100bbaa8b60SDan Kruchinin 
1101bbaa8b60SDan Kruchinin /*
1102bbaa8b60SDan Kruchinin  * Do NLM_TEST call.
1103bbaa8b60SDan Kruchinin  * Was: nlm_getlock()
1104bbaa8b60SDan Kruchinin  */
1105bbaa8b60SDan Kruchinin static int
nlm_call_test(struct flock64 * flp,struct nlm_host * hostp,struct netobj * fhp,int vers)1106bbaa8b60SDan Kruchinin nlm_call_test(struct flock64 *flp, struct nlm_host *hostp,
1107bbaa8b60SDan Kruchinin     struct netobj *fhp, int vers)
1108bbaa8b60SDan Kruchinin {
1109bbaa8b60SDan Kruchinin 	struct nlm4_testargs args;
1110bbaa8b60SDan Kruchinin 	struct nlm4_holder h;
1111bbaa8b60SDan Kruchinin 	struct nlm_owner_handle oh;
1112bbaa8b60SDan Kruchinin 	enum nlm4_stats nlm_err;
1113bbaa8b60SDan Kruchinin 	uint32_t xid;
1114bbaa8b60SDan Kruchinin 	int error;
1115bbaa8b60SDan Kruchinin 
1116bbaa8b60SDan Kruchinin 	bzero(&args, sizeof (args));
1117bbaa8b60SDan Kruchinin 	nlm_init_lock(&args.alock, flp, fhp, &oh);
1118bbaa8b60SDan Kruchinin 
1119bbaa8b60SDan Kruchinin 	args.exclusive = (flp->l_type == F_WRLCK);
1120bbaa8b60SDan Kruchinin 	oh.oh_sysid = hostp->nh_sysid;
1121bbaa8b60SDan Kruchinin 	xid = atomic_inc_32_nv(&nlm_xid);
1122bbaa8b60SDan Kruchinin 	args.cookie.n_len = sizeof (xid);
1123bbaa8b60SDan Kruchinin 	args.cookie.n_bytes = (char *)&xid;
1124bbaa8b60SDan Kruchinin 
1125bbaa8b60SDan Kruchinin 	for (;;) {
1126bbaa8b60SDan Kruchinin 		nlm_rpc_t *rpcp;
1127bbaa8b60SDan Kruchinin 		struct nlm4_testres res;
1128bbaa8b60SDan Kruchinin 		enum clnt_stat stat;
1129bbaa8b60SDan Kruchinin 
1130bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(hostp, vers, &rpcp);
1131bbaa8b60SDan Kruchinin 		if (error != 0)
1132bbaa8b60SDan Kruchinin 			return (ENOLCK);
1133bbaa8b60SDan Kruchinin 
1134bbaa8b60SDan Kruchinin 		bzero(&res, sizeof (res));
1135bbaa8b60SDan Kruchinin 		stat = nlm_test_rpc(&args, &res, rpcp->nr_handle, vers);
1136bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(hostp, rpcp);
1137bbaa8b60SDan Kruchinin 
1138bbaa8b60SDan Kruchinin 		error = nlm_map_clnt_stat(stat);
1139bbaa8b60SDan Kruchinin 		if (error != 0) {
1140bbaa8b60SDan Kruchinin 			if (error == EAGAIN)
1141bbaa8b60SDan Kruchinin 				continue;
1142bbaa8b60SDan Kruchinin 
1143bbaa8b60SDan Kruchinin 			return (error);
1144bbaa8b60SDan Kruchinin 		}
1145bbaa8b60SDan Kruchinin 
1146bbaa8b60SDan Kruchinin 		DTRACE_PROBE1(test__res, enum nlm4_stats, res.stat.stat);
1147bbaa8b60SDan Kruchinin 		nlm_err = res.stat.stat;
1148bbaa8b60SDan Kruchinin 		bcopy(&res.stat.nlm4_testrply_u.holder, &h, sizeof (h));
1149bbaa8b60SDan Kruchinin 		xdr_free((xdrproc_t)xdr_nlm4_testres, (void *)&res);
1150bbaa8b60SDan Kruchinin 		if (nlm_err == nlm4_denied_grace_period) {
1151bbaa8b60SDan Kruchinin 			error = nlm_host_wait_grace(hostp);
1152bbaa8b60SDan Kruchinin 			if (error != 0)
1153bbaa8b60SDan Kruchinin 				return (error);
1154bbaa8b60SDan Kruchinin 
1155bbaa8b60SDan Kruchinin 			continue;
1156bbaa8b60SDan Kruchinin 		}
1157bbaa8b60SDan Kruchinin 
1158bbaa8b60SDan Kruchinin 		break;
1159bbaa8b60SDan Kruchinin 	}
1160bbaa8b60SDan Kruchinin 
1161bbaa8b60SDan Kruchinin 	switch (nlm_err) {
1162bbaa8b60SDan Kruchinin 	case nlm4_granted:
1163bbaa8b60SDan Kruchinin 		flp->l_type = F_UNLCK;
1164bbaa8b60SDan Kruchinin 		error = 0;
1165bbaa8b60SDan Kruchinin 		break;
1166bbaa8b60SDan Kruchinin 
1167bbaa8b60SDan Kruchinin 	case nlm4_denied:
1168bbaa8b60SDan Kruchinin 		flp->l_start = h.l_offset;
1169bbaa8b60SDan Kruchinin 		flp->l_len = h.l_len;
1170bbaa8b60SDan Kruchinin 		flp->l_pid = h.svid;
1171bbaa8b60SDan Kruchinin 		flp->l_type = (h.exclusive) ? F_WRLCK : F_RDLCK;
1172bbaa8b60SDan Kruchinin 		flp->l_whence = SEEK_SET;
1173bbaa8b60SDan Kruchinin 		flp->l_sysid = 0;
1174bbaa8b60SDan Kruchinin 		error = 0;
1175bbaa8b60SDan Kruchinin 		break;
1176bbaa8b60SDan Kruchinin 
1177bbaa8b60SDan Kruchinin 	default:
1178bbaa8b60SDan Kruchinin 		error = nlm_map_status(nlm_err);
1179bbaa8b60SDan Kruchinin 		break;
1180bbaa8b60SDan Kruchinin 	}
1181bbaa8b60SDan Kruchinin 
1182bbaa8b60SDan Kruchinin 	return (error);
1183bbaa8b60SDan Kruchinin }
1184bbaa8b60SDan Kruchinin 
1185bbaa8b60SDan Kruchinin 
1186bbaa8b60SDan Kruchinin static void
nlm_init_lock(struct nlm4_lock * lock,const struct flock64 * fl,struct netobj * fh,struct nlm_owner_handle * oh)1187bbaa8b60SDan Kruchinin nlm_init_lock(struct nlm4_lock *lock,
1188*745caa42SMarcel Telka     const struct flock64 *fl, struct netobj *fh,
1189*745caa42SMarcel Telka     struct nlm_owner_handle *oh)
1190bbaa8b60SDan Kruchinin {
1191bbaa8b60SDan Kruchinin 
1192bbaa8b60SDan Kruchinin 	/* Caller converts to zero-base. */
1193bbaa8b60SDan Kruchinin 	VERIFY(fl->l_whence == SEEK_SET);
1194bbaa8b60SDan Kruchinin 	bzero(lock, sizeof (*lock));
1195bbaa8b60SDan Kruchinin 	bzero(oh, sizeof (*oh));
1196bbaa8b60SDan Kruchinin 
1197bbaa8b60SDan Kruchinin 	lock->caller_name = uts_nodename();
1198bbaa8b60SDan Kruchinin 	lock->fh.n_len = fh->n_len;
1199bbaa8b60SDan Kruchinin 	lock->fh.n_bytes = fh->n_bytes;
1200bbaa8b60SDan Kruchinin 	lock->oh.n_len = sizeof (*oh);
1201bbaa8b60SDan Kruchinin 	lock->oh.n_bytes = (void *)oh;
1202bbaa8b60SDan Kruchinin 	lock->svid = fl->l_pid;
1203bbaa8b60SDan Kruchinin 	lock->l_offset = fl->l_start;
1204bbaa8b60SDan Kruchinin 	lock->l_len = fl->l_len;
1205bbaa8b60SDan Kruchinin }
1206bbaa8b60SDan Kruchinin 
1207bbaa8b60SDan Kruchinin /* ************************************************************** */
1208bbaa8b60SDan Kruchinin 
1209bbaa8b60SDan Kruchinin int
nlm_shrlock(struct vnode * vp,int cmd,struct shrlock * shr,int flags,struct netobj * fh,int vers)1210bbaa8b60SDan Kruchinin nlm_shrlock(struct vnode *vp, int cmd, struct shrlock *shr,
1211*745caa42SMarcel Telka     int flags, struct netobj *fh, int vers)
1212bbaa8b60SDan Kruchinin {
1213bbaa8b60SDan Kruchinin 	struct shrlock shlk;
1214bbaa8b60SDan Kruchinin 	mntinfo_t *mi;
1215bbaa8b60SDan Kruchinin 	servinfo_t *sv;
1216bbaa8b60SDan Kruchinin 	const char *netid;
1217bbaa8b60SDan Kruchinin 	struct nlm_host *host = NULL;
1218bbaa8b60SDan Kruchinin 	int error;
1219bbaa8b60SDan Kruchinin 	struct nlm_globals *g;
1220bbaa8b60SDan Kruchinin 
1221bbaa8b60SDan Kruchinin 	mi = VTOMI(vp);
1222bbaa8b60SDan Kruchinin 	sv = mi->mi_curr_serv;
1223bbaa8b60SDan Kruchinin 
1224bbaa8b60SDan Kruchinin 	netid = nlm_knc_to_netid(sv->sv_knconf);
1225bbaa8b60SDan Kruchinin 	if (netid == NULL) {
1226bbaa8b60SDan Kruchinin 		NLM_ERR("nlm_shrlock: unknown NFS netid\n");
1227bbaa8b60SDan Kruchinin 		return (ENOSYS);
1228bbaa8b60SDan Kruchinin 	}
1229bbaa8b60SDan Kruchinin 
1230bbaa8b60SDan Kruchinin 	g = zone_getspecific(nlm_zone_key, curzone);
1231bbaa8b60SDan Kruchinin 	host = nlm_host_findcreate(g, sv->sv_hostname, netid, &sv->sv_addr);
1232bbaa8b60SDan Kruchinin 	if (host == NULL)
1233bbaa8b60SDan Kruchinin 		return (ENOSYS);
1234bbaa8b60SDan Kruchinin 
1235bbaa8b60SDan Kruchinin 	/*
1236bbaa8b60SDan Kruchinin 	 * Fill in s_sysid for the local locking calls.
1237bbaa8b60SDan Kruchinin 	 * Also, let's not trust the caller's l_pid.
1238bbaa8b60SDan Kruchinin 	 */
1239bbaa8b60SDan Kruchinin 	shlk = *shr;
1240bbaa8b60SDan Kruchinin 	shlk.s_sysid = host->nh_sysid | LM_SYSID_CLIENT;
1241bbaa8b60SDan Kruchinin 	shlk.s_pid = curproc->p_pid;
1242bbaa8b60SDan Kruchinin 
1243bbaa8b60SDan Kruchinin 	if (cmd == F_UNSHARE) {
1244bbaa8b60SDan Kruchinin 		/*
1245bbaa8b60SDan Kruchinin 		 * Purge local (cached) share information first,
1246bbaa8b60SDan Kruchinin 		 * then clear the remote share.
1247bbaa8b60SDan Kruchinin 		 */
1248bbaa8b60SDan Kruchinin 		(void) nlm_local_shrlock(vp, &shlk, cmd, flags);
1249bbaa8b60SDan Kruchinin 		nlm_shres_untrack(host, vp, &shlk);
1250bbaa8b60SDan Kruchinin 		error = nlm_call_unshare(&shlk, host, fh, vers);
1251bbaa8b60SDan Kruchinin 		goto out;
1252bbaa8b60SDan Kruchinin 	}
1253bbaa8b60SDan Kruchinin 
1254bbaa8b60SDan Kruchinin 	nfs_add_locking_id(vp, curproc->p_pid, RLMPL_OWNER,
1255bbaa8b60SDan Kruchinin 	    shr->s_owner, shr->s_own_len);
1256bbaa8b60SDan Kruchinin 
1257bbaa8b60SDan Kruchinin 	error = nlm_call_share(&shlk, host, fh, vers, FALSE);
1258bbaa8b60SDan Kruchinin 	if (error != 0)
1259bbaa8b60SDan Kruchinin 		goto out;
1260bbaa8b60SDan Kruchinin 
1261bbaa8b60SDan Kruchinin 	/*
1262bbaa8b60SDan Kruchinin 	 * Save the share locally.  This should not fail,
1263bbaa8b60SDan Kruchinin 	 * because the server is authoritative about shares
1264bbaa8b60SDan Kruchinin 	 * and it just told us we have the share reservation!
1265bbaa8b60SDan Kruchinin 	 */
1266bbaa8b60SDan Kruchinin 	error = nlm_local_shrlock(vp, shr, cmd, flags);
1267bbaa8b60SDan Kruchinin 	if (error != 0) {
1268bbaa8b60SDan Kruchinin 		/*
1269bbaa8b60SDan Kruchinin 		 * Oh oh, we really don't expect an error here.
1270bbaa8b60SDan Kruchinin 		 */
1271bbaa8b60SDan Kruchinin 		NLM_WARN("nlm_shrlock: set locally, err %d\n", error);
1272bbaa8b60SDan Kruchinin 		error = 0;
1273bbaa8b60SDan Kruchinin 	}
1274bbaa8b60SDan Kruchinin 
1275bbaa8b60SDan Kruchinin 	nlm_shres_track(host, vp, &shlk);
1276bbaa8b60SDan Kruchinin 	nlm_host_monitor(g, host, 0);
1277bbaa8b60SDan Kruchinin 
1278bbaa8b60SDan Kruchinin out:
1279bbaa8b60SDan Kruchinin 	nlm_host_release(g, host);
1280bbaa8b60SDan Kruchinin 
1281bbaa8b60SDan Kruchinin 	return (error);
1282bbaa8b60SDan Kruchinin }
1283bbaa8b60SDan Kruchinin 
1284bbaa8b60SDan Kruchinin static int
nlm_reclaim_share(struct nlm_host * hostp,vnode_t * vp,struct shrlock * shr,uint32_t orig_state)1285bbaa8b60SDan Kruchinin nlm_reclaim_share(struct nlm_host *hostp, vnode_t *vp,
1286bbaa8b60SDan Kruchinin     struct shrlock *shr, uint32_t orig_state)
1287bbaa8b60SDan Kruchinin {
1288bbaa8b60SDan Kruchinin 	struct netobj lm_fh;
1289bbaa8b60SDan Kruchinin 	int error, state;
1290bbaa8b60SDan Kruchinin 	rpcvers_t vers;
1291bbaa8b60SDan Kruchinin 
1292bbaa8b60SDan Kruchinin 	state = nlm_host_get_state(hostp);
1293bbaa8b60SDan Kruchinin 	if (state != orig_state) {
1294bbaa8b60SDan Kruchinin 		/*
1295bbaa8b60SDan Kruchinin 		 * It seems that NLM server rebooted while
1296bbaa8b60SDan Kruchinin 		 * we were busy with recovery.
1297bbaa8b60SDan Kruchinin 		 */
1298bbaa8b60SDan Kruchinin 		return (ERESTART);
1299bbaa8b60SDan Kruchinin 	}
1300bbaa8b60SDan Kruchinin 
1301bbaa8b60SDan Kruchinin 	error = nlm_init_fh_by_vp(vp, &lm_fh, &vers);
1302bbaa8b60SDan Kruchinin 	if (error != 0)
1303bbaa8b60SDan Kruchinin 		return (error);
1304bbaa8b60SDan Kruchinin 
1305bbaa8b60SDan Kruchinin 	return (nlm_call_share(shr, hostp, &lm_fh, vers, 1));
1306bbaa8b60SDan Kruchinin }
1307bbaa8b60SDan Kruchinin 
1308bbaa8b60SDan Kruchinin /*
1309bbaa8b60SDan Kruchinin  * Set local share information for some NFS server.
1310bbaa8b60SDan Kruchinin  *
1311bbaa8b60SDan Kruchinin  * Called after a share request (set or clear) succeeded. We record
1312bbaa8b60SDan Kruchinin  * the details in the local lock manager. Note that since the remote
1313bbaa8b60SDan Kruchinin  * server has granted the share, we can be sure that it doesn't
1314bbaa8b60SDan Kruchinin  * conflict with any other shares we have in the local lock manager.
1315bbaa8b60SDan Kruchinin  *
1316bbaa8b60SDan Kruchinin  * Since it is possible that host may also make NLM client requests to
1317bbaa8b60SDan Kruchinin  * our NLM server, we use a different sysid value to record our own
1318bbaa8b60SDan Kruchinin  * client shares.
1319bbaa8b60SDan Kruchinin  */
1320bbaa8b60SDan Kruchinin int
nlm_local_shrlock(vnode_t * vp,struct shrlock * shr,int cmd,int flags)1321bbaa8b60SDan Kruchinin nlm_local_shrlock(vnode_t *vp, struct shrlock *shr, int cmd, int flags)
1322bbaa8b60SDan Kruchinin {
1323bbaa8b60SDan Kruchinin 	return (fs_shrlock(vp, cmd, shr, flags, CRED(), NULL));
1324bbaa8b60SDan Kruchinin }
1325bbaa8b60SDan Kruchinin 
1326bbaa8b60SDan Kruchinin static void
nlm_local_shrcancel(vnode_t * vp,struct shrlock * shr)1327bbaa8b60SDan Kruchinin nlm_local_shrcancel(vnode_t *vp, struct shrlock *shr)
1328bbaa8b60SDan Kruchinin {
1329bbaa8b60SDan Kruchinin 	(void) nlm_local_shrlock(vp, shr, F_UNSHARE, FREAD | FWRITE);
1330bbaa8b60SDan Kruchinin 	nlm_send_siglost(shr->s_pid);
1331bbaa8b60SDan Kruchinin }
1332bbaa8b60SDan Kruchinin 
1333bbaa8b60SDan Kruchinin /*
1334bbaa8b60SDan Kruchinin  * Do NLM_SHARE call.
1335bbaa8b60SDan Kruchinin  * Was: nlm_setshare()
1336bbaa8b60SDan Kruchinin  */
1337bbaa8b60SDan Kruchinin static int
nlm_call_share(struct shrlock * shr,struct nlm_host * host,struct netobj * fh,int vers,int reclaim)1338bbaa8b60SDan Kruchinin nlm_call_share(struct shrlock *shr, struct nlm_host *host,
1339bbaa8b60SDan Kruchinin     struct netobj *fh, int vers, int reclaim)
1340bbaa8b60SDan Kruchinin {
1341bbaa8b60SDan Kruchinin 	struct nlm4_shareargs args;
1342bbaa8b60SDan Kruchinin 	enum nlm4_stats nlm_err;
1343bbaa8b60SDan Kruchinin 	uint32_t xid;
1344bbaa8b60SDan Kruchinin 	int error;
1345bbaa8b60SDan Kruchinin 
1346bbaa8b60SDan Kruchinin 	bzero(&args, sizeof (args));
1347bbaa8b60SDan Kruchinin 	nlm_init_share(&args.share, shr, fh);
1348bbaa8b60SDan Kruchinin 
1349bbaa8b60SDan Kruchinin 	args.reclaim = reclaim;
1350bbaa8b60SDan Kruchinin 	xid = atomic_inc_32_nv(&nlm_xid);
1351bbaa8b60SDan Kruchinin 	args.cookie.n_len = sizeof (xid);
1352bbaa8b60SDan Kruchinin 	args.cookie.n_bytes = (char *)&xid;
1353bbaa8b60SDan Kruchinin 
1354bbaa8b60SDan Kruchinin 
1355bbaa8b60SDan Kruchinin 	for (;;) {
1356bbaa8b60SDan Kruchinin 		nlm_rpc_t *rpcp;
1357bbaa8b60SDan Kruchinin 		struct nlm4_shareres res;
1358bbaa8b60SDan Kruchinin 		enum clnt_stat stat;
1359bbaa8b60SDan Kruchinin 
1360bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(host, vers, &rpcp);
1361bbaa8b60SDan Kruchinin 		if (error != 0)
1362bbaa8b60SDan Kruchinin 			return (ENOLCK);
1363bbaa8b60SDan Kruchinin 
1364bbaa8b60SDan Kruchinin 		bzero(&res, sizeof (res));
1365bbaa8b60SDan Kruchinin 		stat = nlm_share_rpc(&args, &res, rpcp->nr_handle, vers);
1366bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(host, rpcp);
1367bbaa8b60SDan Kruchinin 
1368bbaa8b60SDan Kruchinin 		error = nlm_map_clnt_stat(stat);
1369bbaa8b60SDan Kruchinin 		if (error != 0) {
1370bbaa8b60SDan Kruchinin 			if (error == EAGAIN)
1371bbaa8b60SDan Kruchinin 				continue;
1372bbaa8b60SDan Kruchinin 
1373bbaa8b60SDan Kruchinin 			return (error);
1374bbaa8b60SDan Kruchinin 		}
1375bbaa8b60SDan Kruchinin 
1376bbaa8b60SDan Kruchinin 		DTRACE_PROBE1(share__res, enum nlm4_stats, res.stat);
1377bbaa8b60SDan Kruchinin 		nlm_err = res.stat;
1378bbaa8b60SDan Kruchinin 		xdr_free((xdrproc_t)xdr_nlm4_shareres, (void *)&res);
1379bbaa8b60SDan Kruchinin 		if (nlm_err == nlm4_denied_grace_period) {
1380bbaa8b60SDan Kruchinin 			if (args.reclaim)
1381bbaa8b60SDan Kruchinin 				return (ENOLCK);
1382bbaa8b60SDan Kruchinin 
1383bbaa8b60SDan Kruchinin 			error = nlm_host_wait_grace(host);
1384bbaa8b60SDan Kruchinin 			if (error != 0)
1385bbaa8b60SDan Kruchinin 				return (error);
1386bbaa8b60SDan Kruchinin 
1387bbaa8b60SDan Kruchinin 			continue;
1388bbaa8b60SDan Kruchinin 		}
1389bbaa8b60SDan Kruchinin 
1390bbaa8b60SDan Kruchinin 		break;
1391bbaa8b60SDan Kruchinin 	}
1392bbaa8b60SDan Kruchinin 
1393bbaa8b60SDan Kruchinin 	switch (nlm_err) {
1394bbaa8b60SDan Kruchinin 	case nlm4_granted:
1395bbaa8b60SDan Kruchinin 		error = 0;
1396bbaa8b60SDan Kruchinin 		break;
1397bbaa8b60SDan Kruchinin 	case nlm4_blocked:
1398bbaa8b60SDan Kruchinin 	case nlm4_denied:
1399bbaa8b60SDan Kruchinin 		error = EAGAIN;
1400bbaa8b60SDan Kruchinin 		break;
1401bbaa8b60SDan Kruchinin 	case nlm4_denied_nolocks:
1402bbaa8b60SDan Kruchinin 	case nlm4_deadlck:
1403bbaa8b60SDan Kruchinin 		error = ENOLCK;
1404bbaa8b60SDan Kruchinin 		break;
1405bbaa8b60SDan Kruchinin 	default:
1406bbaa8b60SDan Kruchinin 		error = EINVAL;
1407bbaa8b60SDan Kruchinin 		break;
1408bbaa8b60SDan Kruchinin 	}
1409bbaa8b60SDan Kruchinin 
1410bbaa8b60SDan Kruchinin 	return (error);
1411bbaa8b60SDan Kruchinin }
1412bbaa8b60SDan Kruchinin 
1413bbaa8b60SDan Kruchinin /*
1414bbaa8b60SDan Kruchinin  * Do NLM_UNSHARE call.
1415bbaa8b60SDan Kruchinin  */
1416bbaa8b60SDan Kruchinin static int
nlm_call_unshare(struct shrlock * shr,struct nlm_host * host,struct netobj * fh,int vers)1417bbaa8b60SDan Kruchinin nlm_call_unshare(struct shrlock *shr, struct nlm_host *host,
1418bbaa8b60SDan Kruchinin     struct netobj *fh, int vers)
1419bbaa8b60SDan Kruchinin {
1420bbaa8b60SDan Kruchinin 	struct nlm4_shareargs args;
1421bbaa8b60SDan Kruchinin 	enum nlm4_stats nlm_err;
1422bbaa8b60SDan Kruchinin 	uint32_t xid;
1423bbaa8b60SDan Kruchinin 	int error;
1424bbaa8b60SDan Kruchinin 
1425bbaa8b60SDan Kruchinin 	bzero(&args, sizeof (args));
1426bbaa8b60SDan Kruchinin 	nlm_init_share(&args.share, shr, fh);
1427bbaa8b60SDan Kruchinin 
1428bbaa8b60SDan Kruchinin 	xid = atomic_inc_32_nv(&nlm_xid);
1429bbaa8b60SDan Kruchinin 	args.cookie.n_len = sizeof (xid);
1430bbaa8b60SDan Kruchinin 	args.cookie.n_bytes = (char *)&xid;
1431bbaa8b60SDan Kruchinin 
1432bbaa8b60SDan Kruchinin 	for (;;) {
1433bbaa8b60SDan Kruchinin 		nlm_rpc_t *rpcp;
1434bbaa8b60SDan Kruchinin 		struct nlm4_shareres res;
1435bbaa8b60SDan Kruchinin 		enum clnt_stat stat;
1436bbaa8b60SDan Kruchinin 
1437bbaa8b60SDan Kruchinin 		error = nlm_host_get_rpc(host, vers, &rpcp);
1438bbaa8b60SDan Kruchinin 		if (error != 0)
1439bbaa8b60SDan Kruchinin 			return (ENOLCK);
1440bbaa8b60SDan Kruchinin 
1441bbaa8b60SDan Kruchinin 		bzero(&res, sizeof (res));
1442bbaa8b60SDan Kruchinin 		stat = nlm_unshare_rpc(&args, &res, rpcp->nr_handle, vers);
1443bbaa8b60SDan Kruchinin 		nlm_host_rele_rpc(host, rpcp);
1444bbaa8b60SDan Kruchinin 
1445bbaa8b60SDan Kruchinin 		error = nlm_map_clnt_stat(stat);
1446bbaa8b60SDan Kruchinin 		if (error != 0) {
1447bbaa8b60SDan Kruchinin 			if (error == EAGAIN)
1448bbaa8b60SDan Kruchinin 				continue;
1449bbaa8b60SDan Kruchinin 
1450bbaa8b60SDan Kruchinin 			return (error);
1451bbaa8b60SDan Kruchinin 		}
1452bbaa8b60SDan Kruchinin 
1453bbaa8b60SDan Kruchinin 		DTRACE_PROBE1(unshare__res, enum nlm4_stats, res.stat);
1454bbaa8b60SDan Kruchinin 		nlm_err = res.stat;
1455bbaa8b60SDan Kruchinin 		xdr_free((xdrproc_t)xdr_nlm4_res, (void *)&res);
1456bbaa8b60SDan Kruchinin 		if (nlm_err == nlm4_denied_grace_period) {
1457bbaa8b60SDan Kruchinin 			error = nlm_host_wait_grace(host);
1458bbaa8b60SDan Kruchinin 			if (error != 0)
1459bbaa8b60SDan Kruchinin 				return (error);
1460bbaa8b60SDan Kruchinin 
1461bbaa8b60SDan Kruchinin 			continue;
1462bbaa8b60SDan Kruchinin 		}
1463bbaa8b60SDan Kruchinin 
1464bbaa8b60SDan Kruchinin 		break;
1465bbaa8b60SDan Kruchinin 	}
1466bbaa8b60SDan Kruchinin 
1467bbaa8b60SDan Kruchinin 	switch (nlm_err) {
1468bbaa8b60SDan Kruchinin 	case nlm4_granted:
1469bbaa8b60SDan Kruchinin 		error = 0;
1470bbaa8b60SDan Kruchinin 		break;
1471bbaa8b60SDan Kruchinin 	case nlm4_denied:
1472bbaa8b60SDan Kruchinin 		error = EAGAIN;
1473bbaa8b60SDan Kruchinin 		break;
1474bbaa8b60SDan Kruchinin 	case nlm4_denied_nolocks:
1475bbaa8b60SDan Kruchinin 		error = ENOLCK;
1476bbaa8b60SDan Kruchinin 		break;
1477bbaa8b60SDan Kruchinin 	default:
1478bbaa8b60SDan Kruchinin 		error = EINVAL;
1479bbaa8b60SDan Kruchinin 		break;
1480bbaa8b60SDan Kruchinin 	}
1481bbaa8b60SDan Kruchinin 
1482bbaa8b60SDan Kruchinin 	return (error);
1483bbaa8b60SDan Kruchinin }
1484bbaa8b60SDan Kruchinin 
1485bbaa8b60SDan Kruchinin static void
nlm_init_share(struct nlm4_share * args,const struct shrlock * shr,struct netobj * fh)1486bbaa8b60SDan Kruchinin nlm_init_share(struct nlm4_share *args,
1487*745caa42SMarcel Telka     const struct shrlock *shr, struct netobj *fh)
1488bbaa8b60SDan Kruchinin {
1489bbaa8b60SDan Kruchinin 
1490bbaa8b60SDan Kruchinin 	bzero(args, sizeof (*args));
1491bbaa8b60SDan Kruchinin 
1492bbaa8b60SDan Kruchinin 	args->caller_name = uts_nodename();
1493bbaa8b60SDan Kruchinin 	args->fh.n_len = fh->n_len;
1494bbaa8b60SDan Kruchinin 	args->fh.n_bytes = fh->n_bytes;
1495bbaa8b60SDan Kruchinin 	args->oh.n_len = shr->s_own_len;
1496bbaa8b60SDan Kruchinin 	args->oh.n_bytes = (void *)shr->s_owner;
1497bbaa8b60SDan Kruchinin 
1498bbaa8b60SDan Kruchinin 	switch (shr->s_deny) {
1499bbaa8b60SDan Kruchinin 	default:
1500bbaa8b60SDan Kruchinin 	case F_NODNY:
1501bbaa8b60SDan Kruchinin 		args->mode = fsm_DN;
1502bbaa8b60SDan Kruchinin 		break;
1503bbaa8b60SDan Kruchinin 	case F_RDDNY:
1504bbaa8b60SDan Kruchinin 		args->mode = fsm_DR;
1505bbaa8b60SDan Kruchinin 		break;
1506bbaa8b60SDan Kruchinin 	case F_WRDNY:
1507bbaa8b60SDan Kruchinin 		args->mode = fsm_DW;
1508bbaa8b60SDan Kruchinin 		break;
1509bbaa8b60SDan Kruchinin 	case F_RWDNY:
1510bbaa8b60SDan Kruchinin 		args->mode = fsm_DRW;
1511bbaa8b60SDan Kruchinin 		break;
1512bbaa8b60SDan Kruchinin 	}
1513bbaa8b60SDan Kruchinin 
1514bbaa8b60SDan Kruchinin 	switch (shr->s_access) {
1515bbaa8b60SDan Kruchinin 	default:
1516bbaa8b60SDan Kruchinin 	case 0:	/* seen with F_UNSHARE */
1517bbaa8b60SDan Kruchinin 		args->access = fsa_NONE;
1518bbaa8b60SDan Kruchinin 		break;
1519bbaa8b60SDan Kruchinin 	case F_RDACC:
1520bbaa8b60SDan Kruchinin 		args->access = fsa_R;
1521bbaa8b60SDan Kruchinin 		break;
1522bbaa8b60SDan Kruchinin 	case F_WRACC:
1523bbaa8b60SDan Kruchinin 		args->access = fsa_W;
1524bbaa8b60SDan Kruchinin 		break;
1525bbaa8b60SDan Kruchinin 	case F_RWACC:
1526bbaa8b60SDan Kruchinin 		args->access = fsa_RW;
1527bbaa8b60SDan Kruchinin 		break;
1528bbaa8b60SDan Kruchinin 	}
1529bbaa8b60SDan Kruchinin }
1530bbaa8b60SDan Kruchinin 
1531bbaa8b60SDan Kruchinin /*
1532bbaa8b60SDan Kruchinin  * Initialize filehandle according to the version
1533bbaa8b60SDan Kruchinin  * of NFS vnode was created on. The version of
1534bbaa8b60SDan Kruchinin  * NLM that can be used with given NFS version
1535bbaa8b60SDan Kruchinin  * is saved to lm_vers.
1536bbaa8b60SDan Kruchinin  */
1537bbaa8b60SDan Kruchinin static int
nlm_init_fh_by_vp(vnode_t * vp,struct netobj * fh,rpcvers_t * lm_vers)1538bbaa8b60SDan Kruchinin nlm_init_fh_by_vp(vnode_t *vp, struct netobj *fh, rpcvers_t *lm_vers)
1539bbaa8b60SDan Kruchinin {
1540bbaa8b60SDan Kruchinin 	mntinfo_t *mi = VTOMI(vp);
1541bbaa8b60SDan Kruchinin 
1542bbaa8b60SDan Kruchinin 	/*
1543bbaa8b60SDan Kruchinin 	 * Too bad the NFS code doesn't just carry the FH
1544bbaa8b60SDan Kruchinin 	 * in a netobj or a netbuf.
1545bbaa8b60SDan Kruchinin 	 */
1546bbaa8b60SDan Kruchinin 	switch (mi->mi_vers) {
1547bbaa8b60SDan Kruchinin 	case NFS_V3:
1548bbaa8b60SDan Kruchinin 		/* See nfs3_frlock() */
1549bbaa8b60SDan Kruchinin 		*lm_vers = NLM4_VERS;
1550bbaa8b60SDan Kruchinin 		fh->n_len = VTOFH3(vp)->fh3_length;
1551bbaa8b60SDan Kruchinin 		fh->n_bytes = (char *)&(VTOFH3(vp)->fh3_u.data);
1552bbaa8b60SDan Kruchinin 		break;
1553bbaa8b60SDan Kruchinin 
1554bbaa8b60SDan Kruchinin 	case NFS_VERSION:
1555bbaa8b60SDan Kruchinin 		/* See nfs_frlock() */
1556bbaa8b60SDan Kruchinin 		*lm_vers = NLM_VERS;
1557bbaa8b60SDan Kruchinin 		fh->n_len = sizeof (fhandle_t);
1558bbaa8b60SDan Kruchinin 		/* LINTED E_BAD_PTR_CAST_ALIGN */
1559bbaa8b60SDan Kruchinin 		fh->n_bytes = (char *)VTOFH(vp);
1560bbaa8b60SDan Kruchinin 		break;
1561bbaa8b60SDan Kruchinin 	default:
1562bbaa8b60SDan Kruchinin 		return (ENOSYS);
1563bbaa8b60SDan Kruchinin 	}
1564bbaa8b60SDan Kruchinin 
1565bbaa8b60SDan Kruchinin 	return (0);
1566bbaa8b60SDan Kruchinin }
1567bbaa8b60SDan Kruchinin 
1568bbaa8b60SDan Kruchinin /*
1569bbaa8b60SDan Kruchinin  * Send SIGLOST to the process identified by pid.
1570bbaa8b60SDan Kruchinin  * NOTE: called when NLM decides to remove lock
1571bbaa8b60SDan Kruchinin  * or share reservation ownder by the process
1572bbaa8b60SDan Kruchinin  * by force.
1573bbaa8b60SDan Kruchinin  */
1574bbaa8b60SDan Kruchinin static void
nlm_send_siglost(pid_t pid)1575bbaa8b60SDan Kruchinin nlm_send_siglost(pid_t pid)
1576bbaa8b60SDan Kruchinin {
1577bbaa8b60SDan Kruchinin 	proc_t *p;
1578bbaa8b60SDan Kruchinin 
1579bbaa8b60SDan Kruchinin 	mutex_enter(&pidlock);
1580bbaa8b60SDan Kruchinin 	p = prfind(pid);
1581bbaa8b60SDan Kruchinin 	if (p != NULL)
1582bbaa8b60SDan Kruchinin 		psignal(p, SIGLOST);
1583bbaa8b60SDan Kruchinin 
1584bbaa8b60SDan Kruchinin 	mutex_exit(&pidlock);
1585bbaa8b60SDan Kruchinin }
1586bbaa8b60SDan Kruchinin 
1587bbaa8b60SDan Kruchinin static int
nlm_map_clnt_stat(enum clnt_stat stat)1588bbaa8b60SDan Kruchinin nlm_map_clnt_stat(enum clnt_stat stat)
1589bbaa8b60SDan Kruchinin {
1590bbaa8b60SDan Kruchinin 	switch (stat) {
1591bbaa8b60SDan Kruchinin 	case RPC_SUCCESS:
1592bbaa8b60SDan Kruchinin 		return (0);
1593bbaa8b60SDan Kruchinin 
1594bbaa8b60SDan Kruchinin 	case RPC_TIMEDOUT:
1595bbaa8b60SDan Kruchinin 	case RPC_PROGUNAVAIL:
1596bbaa8b60SDan Kruchinin 		return (EAGAIN);
1597bbaa8b60SDan Kruchinin 
1598bbaa8b60SDan Kruchinin 	case RPC_INTR:
1599bbaa8b60SDan Kruchinin 		return (EINTR);
1600bbaa8b60SDan Kruchinin 
1601bbaa8b60SDan Kruchinin 	default:
1602bbaa8b60SDan Kruchinin 		return (EINVAL);
1603bbaa8b60SDan Kruchinin 	}
1604bbaa8b60SDan Kruchinin }
1605bbaa8b60SDan Kruchinin 
1606bbaa8b60SDan Kruchinin static int
nlm_map_status(enum nlm4_stats stat)1607bbaa8b60SDan Kruchinin nlm_map_status(enum nlm4_stats stat)
1608bbaa8b60SDan Kruchinin {
1609bbaa8b60SDan Kruchinin 	switch (stat) {
1610bbaa8b60SDan Kruchinin 	case nlm4_granted:
1611bbaa8b60SDan Kruchinin 		return (0);
1612bbaa8b60SDan Kruchinin 
1613bbaa8b60SDan Kruchinin 	case nlm4_denied:
1614bbaa8b60SDan Kruchinin 		return (EAGAIN);
1615bbaa8b60SDan Kruchinin 
1616bbaa8b60SDan Kruchinin 	case nlm4_denied_nolocks:
1617bbaa8b60SDan Kruchinin 		return (ENOLCK);
1618bbaa8b60SDan Kruchinin 
1619bbaa8b60SDan Kruchinin 	case nlm4_blocked:
1620bbaa8b60SDan Kruchinin 		return (EAGAIN);
1621bbaa8b60SDan Kruchinin 
1622bbaa8b60SDan Kruchinin 	case nlm4_denied_grace_period:
1623bbaa8b60SDan Kruchinin 		return (EAGAIN);
1624bbaa8b60SDan Kruchinin 
1625bbaa8b60SDan Kruchinin 	case nlm4_deadlck:
1626bbaa8b60SDan Kruchinin 		return (EDEADLK);
1627bbaa8b60SDan Kruchinin 
1628bbaa8b60SDan Kruchinin 	case nlm4_rofs:
1629bbaa8b60SDan Kruchinin 		return (EROFS);
1630bbaa8b60SDan Kruchinin 
1631bbaa8b60SDan Kruchinin 	case nlm4_stale_fh:
1632bbaa8b60SDan Kruchinin 		return (ESTALE);
1633bbaa8b60SDan Kruchinin 
1634bbaa8b60SDan Kruchinin 	case nlm4_fbig:
1635bbaa8b60SDan Kruchinin 		return (EFBIG);
1636bbaa8b60SDan Kruchinin 
1637bbaa8b60SDan Kruchinin 	case nlm4_failed:
1638bbaa8b60SDan Kruchinin 		return (EACCES);
1639bbaa8b60SDan Kruchinin 
1640bbaa8b60SDan Kruchinin 	default:
1641bbaa8b60SDan Kruchinin 		return (EINVAL);
1642bbaa8b60SDan Kruchinin 	}
1643bbaa8b60SDan Kruchinin }
1644