xref: /freebsd/sys/fs/nfsclient/nfs_clstate.c (revision 675be9115aae86ad6b3d877155d4fd7822892105)
1 /*-
2  * Copyright (c) 2009 Rick Macklem, University of Guelph
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  *    notice, this list of conditions and the following disclaimer in the
12  *    documentation and/or other materials provided with the distribution.
13  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  */
27 
28 #include <sys/cdefs.h>
29 __FBSDID("$FreeBSD$");
30 
31 /*
32  * These functions implement the client side state handling for NFSv4.
33  * NFSv4 state handling:
34  * - A lockowner is used to determine lock contention, so it
35  *   corresponds directly to a Posix pid. (1 to 1 mapping)
36  * - The correct granularity of an OpenOwner is not nearly so
37  *   obvious. An OpenOwner does the following:
38  *   - provides a serial sequencing of Open/Close/Lock-with-new-lockowner
39  *   - is used to check for Open/Share contention (not applicable to
40  *     this client, since all Opens are Deny_None)
41  *   As such, I considered both extreme.
42  *   1 OpenOwner per ClientID - Simple to manage, but fully serializes
43  *   all Open, Close and Lock (with a new lockowner) Ops.
44  *   1 OpenOwner for each Open - This one results in an OpenConfirm for
45  *   every Open, for most servers.
46  *   So, I chose to use the same mapping as I did for LockOwnwers.
47  *   The main concern here is that you can end up with multiple Opens
48  *   for the same File Handle, but on different OpenOwners (opens
49  *   inherited from parents, grandparents...) and you do not know
50  *   which of these the vnodeop close applies to. This is handled by
51  *   delaying the Close Op(s) until all of the Opens have been closed.
52  *   (It is not yet obvious if this is the correct granularity.)
53  * - How the code handles serialization:
54  *   - For the ClientId, it uses an exclusive lock while getting its
55  *     SetClientId and during recovery. Otherwise, it uses a shared
56  *     lock via a reference count.
57  *   - For the rest of the data structures, it uses an SMP mutex
58  *     (once the nfs client is SMP safe) and doesn't sleep while
59  *     manipulating the linked lists.
60  *   - The serialization of Open/Close/Lock/LockU falls out in the
61  *     "wash", since OpenOwners and LockOwners are both mapped from
62  *     Posix pid. In other words, there is only one Posix pid using
63  *     any given owner, so that owner is serialized. (If you change
64  *     the granularity of the OpenOwner, then code must be added to
65  *     serialize Ops on the OpenOwner.)
66  * - When to get rid of OpenOwners and LockOwners.
67  *   - The function nfscl_cleanup_common() is executed after a process exits.
68  *     It goes through the client list looking for all Open and Lock Owners.
69  *     When one is found, it is marked "defunct" or in the case of
70  *     an OpenOwner without any Opens, freed.
71  *     The renew thread scans for defunct Owners and gets rid of them,
72  *     if it can. The LockOwners will also be deleted when the
73  *     associated Open is closed.
74  *   - If the LockU or Close Op(s) fail during close in a way
75  *     that could be recovered upon retry, they are relinked to the
76  *     ClientId's defunct open list and retried by the renew thread
77  *     until they succeed or an unmount/recovery occurs.
78  *     (Since we are done with them, they do not need to be recovered.)
79  */
80 
81 #ifndef APPLEKEXT
82 #include <fs/nfs/nfsport.h>
83 
84 /*
85  * Global variables
86  */
87 extern struct nfsstats newnfsstats;
88 extern struct nfsreqhead nfsd_reqq;
89 NFSREQSPINLOCK;
90 NFSCLSTATEMUTEX;
91 int nfscl_inited = 0;
92 struct nfsclhead nfsclhead;	/* Head of clientid list */
93 int nfscl_deleghighwater = NFSCLDELEGHIGHWATER;
94 #endif	/* !APPLEKEXT */
95 
96 static int nfscl_delegcnt = 0;
97 static int nfscl_getopen(struct nfsclownerhead *, u_int8_t *, int, u_int8_t *,
98     u_int8_t *, u_int32_t, struct nfscllockowner **, struct nfsclopen **);
99 static void nfscl_clrelease(struct nfsclclient *);
100 static void nfscl_cleanclient(struct nfsclclient *);
101 static void nfscl_expireclient(struct nfsclclient *, struct nfsmount *,
102     struct ucred *, NFSPROC_T *);
103 static int nfscl_expireopen(struct nfsclclient *, struct nfsclopen *,
104     struct nfsmount *, struct ucred *, NFSPROC_T *);
105 static void nfscl_recover(struct nfsclclient *, struct ucred *, NFSPROC_T *);
106 static void nfscl_insertlock(struct nfscllockowner *, struct nfscllock *,
107     struct nfscllock *, int);
108 static int nfscl_updatelock(struct nfscllockowner *, struct nfscllock **,
109     struct nfscllock **, int);
110 static void nfscl_delegreturnall(struct nfsclclient *, NFSPROC_T *);
111 static u_int32_t nfscl_nextcbident(void);
112 static mount_t nfscl_getmnt(u_int32_t);
113 static struct nfscldeleg *nfscl_finddeleg(struct nfsclclient *, u_int8_t *,
114     int);
115 static int nfscl_checkconflict(struct nfscllockownerhead *, struct nfscllock *,
116     u_int8_t *, struct nfscllock **);
117 static void nfscl_freealllocks(struct nfscllockownerhead *, int);
118 static int nfscl_localconflict(struct nfsclclient *, u_int8_t *, int,
119     struct nfscllock *, u_int8_t *, struct nfscldeleg *, struct nfscllock **);
120 static void nfscl_newopen(struct nfsclclient *, struct nfscldeleg *,
121     struct nfsclowner **, struct nfsclowner **, struct nfsclopen **,
122     struct nfsclopen **, u_int8_t *, u_int8_t *, int, int *);
123 static int nfscl_moveopen(vnode_t , struct nfsclclient *,
124     struct nfsmount *, struct nfsclopen *, struct nfsclowner *,
125     struct nfscldeleg *, struct ucred *, NFSPROC_T *);
126 static void nfscl_totalrecall(struct nfsclclient *);
127 static int nfscl_relock(vnode_t , struct nfsclclient *, struct nfsmount *,
128     struct nfscllockowner *, struct nfscllock *, struct ucred *, NFSPROC_T *);
129 static int nfscl_tryopen(struct nfsmount *, vnode_t , u_int8_t *, int,
130     u_int8_t *, int, u_int32_t, struct nfsclopen *, u_int8_t *, int,
131     struct nfscldeleg **, int, u_int32_t, struct ucred *, NFSPROC_T *);
132 static int nfscl_trylock(struct nfsmount *, vnode_t , u_int8_t *,
133     int, struct nfscllockowner *, int, int, u_int64_t, u_int64_t, short,
134     struct ucred *, NFSPROC_T *);
135 static int nfsrpc_reopen(struct nfsmount *, u_int8_t *, int, u_int32_t,
136     struct nfsclopen *, struct nfscldeleg **, struct ucred *, NFSPROC_T *);
137 static void nfscl_freedeleg(struct nfscldeleghead *, struct nfscldeleg *);
138 static int nfscl_errmap(struct nfsrv_descript *);
139 static void nfscl_cleanup_common(struct nfsclclient *, u_int8_t *);
140 static int nfscl_recalldeleg(struct nfsclclient *, struct nfsmount *,
141     struct nfscldeleg *, vnode_t, struct ucred *, NFSPROC_T *, int);
142 static void nfscl_freeopenowner(struct nfsclowner *, int);
143 static void nfscl_cleandeleg(struct nfscldeleg *);
144 static int nfscl_trydelegreturn(struct nfscldeleg *, struct ucred *,
145     struct nfsmount *, NFSPROC_T *);
146 static void nfscl_emptylockowner(struct nfscllockowner *,
147     struct nfscllockownerfhhead *);
148 
149 static short nfscberr_null[] = {
150 	0,
151 	0,
152 };
153 
154 static short nfscberr_getattr[] = {
155 	NFSERR_RESOURCE,
156 	NFSERR_BADHANDLE,
157 	NFSERR_BADXDR,
158 	NFSERR_RESOURCE,
159 	NFSERR_SERVERFAULT,
160 	0,
161 };
162 
163 static short nfscberr_recall[] = {
164 	NFSERR_RESOURCE,
165 	NFSERR_BADHANDLE,
166 	NFSERR_BADSTATEID,
167 	NFSERR_BADXDR,
168 	NFSERR_RESOURCE,
169 	NFSERR_SERVERFAULT,
170 	0,
171 };
172 
173 static short *nfscl_cberrmap[] = {
174 	nfscberr_null,
175 	nfscberr_null,
176 	nfscberr_null,
177 	nfscberr_getattr,
178 	nfscberr_recall
179 };
180 
181 #define	NETFAMILY(clp) \
182 		(((clp)->nfsc_flags & NFSCLFLAGS_AFINET6) ? AF_INET6 : AF_INET)
183 
184 /*
185  * Called for an open operation.
186  * If the nfhp argument is NULL, just get an openowner.
187  */
188 APPLESTATIC int
189 nfscl_open(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t amode, int usedeleg,
190     struct ucred *cred, NFSPROC_T *p, struct nfsclowner **owpp,
191     struct nfsclopen **opp, int *newonep, int *retp, int lockit)
192 {
193 	struct nfsclclient *clp;
194 	struct nfsclowner *owp, *nowp;
195 	struct nfsclopen *op = NULL, *nop = NULL;
196 	struct nfscldeleg *dp;
197 	struct nfsclownerhead *ohp;
198 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
199 	int ret;
200 
201 	if (newonep != NULL)
202 		*newonep = 0;
203 	if (opp != NULL)
204 		*opp = NULL;
205 	if (owpp != NULL)
206 		*owpp = NULL;
207 
208 	/*
209 	 * Might need one or both of these, so MALLOC them now, to
210 	 * avoid a tsleep() in MALLOC later.
211 	 */
212 	MALLOC(nowp, struct nfsclowner *, sizeof (struct nfsclowner),
213 	    M_NFSCLOWNER, M_WAITOK);
214 	if (nfhp != NULL)
215 	    MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) +
216 		fhlen - 1, M_NFSCLOPEN, M_WAITOK);
217 	ret = nfscl_getcl(vp, cred, p, &clp);
218 	if (ret != 0) {
219 		FREE((caddr_t)nowp, M_NFSCLOWNER);
220 		if (nop != NULL)
221 			FREE((caddr_t)nop, M_NFSCLOPEN);
222 		return (ret);
223 	}
224 
225 	/*
226 	 * Get the Open iff it already exists.
227 	 * If none found, add the new one or return error, depending upon
228 	 * "create".
229 	 */
230 	nfscl_filllockowner(p->td_proc, own, F_POSIX);
231 	NFSLOCKCLSTATE();
232 	dp = NULL;
233 	/* First check the delegation list */
234 	if (nfhp != NULL && usedeleg) {
235 		LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) {
236 			if (dp->nfsdl_fhlen == fhlen &&
237 			    !NFSBCMP(nfhp, dp->nfsdl_fh, fhlen)) {
238 				if (!(amode & NFSV4OPEN_ACCESSWRITE) ||
239 				    (dp->nfsdl_flags & NFSCLDL_WRITE))
240 					break;
241 				dp = NULL;
242 				break;
243 			}
244 		}
245 	}
246 
247 	if (dp != NULL)
248 		ohp = &dp->nfsdl_owner;
249 	else
250 		ohp = &clp->nfsc_owner;
251 	/* Now, search for an openowner */
252 	LIST_FOREACH(owp, ohp, nfsow_list) {
253 		if (!NFSBCMP(owp->nfsow_owner, own, NFSV4CL_LOCKNAMELEN))
254 			break;
255 	}
256 
257 	/*
258 	 * Create a new open, as required.
259 	 */
260 	nfscl_newopen(clp, dp, &owp, &nowp, &op, &nop, own, nfhp, fhlen,
261 	    newonep);
262 
263 	/*
264 	 * Serialize modifications to the open owner for multiple threads
265 	 * within the same process using a read/write sleep lock.
266 	 */
267 	if (lockit)
268 		nfscl_lockexcl(&owp->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
269 	NFSUNLOCKCLSTATE();
270 	if (nowp != NULL)
271 		FREE((caddr_t)nowp, M_NFSCLOWNER);
272 	if (nop != NULL)
273 		FREE((caddr_t)nop, M_NFSCLOPEN);
274 	if (owpp != NULL)
275 		*owpp = owp;
276 	if (opp != NULL)
277 		*opp = op;
278 	if (retp != NULL) {
279 		if (nfhp != NULL && dp != NULL && nop == NULL)
280 			/* new local open on delegation */
281 			*retp = NFSCLOPEN_SETCRED;
282 		else
283 			*retp = NFSCLOPEN_OK;
284 	}
285 
286 	/*
287 	 * Now, check the mode on the open and return the appropriate
288 	 * value.
289 	 */
290 	if (op != NULL && (amode & ~(op->nfso_mode))) {
291 		op->nfso_mode |= amode;
292 		if (retp != NULL && dp == NULL)
293 			*retp = NFSCLOPEN_DOOPEN;
294 	}
295 	return (0);
296 }
297 
298 /*
299  * Create a new open, as required.
300  */
301 static void
302 nfscl_newopen(struct nfsclclient *clp, struct nfscldeleg *dp,
303     struct nfsclowner **owpp, struct nfsclowner **nowpp, struct nfsclopen **opp,
304     struct nfsclopen **nopp, u_int8_t *own, u_int8_t *fhp, int fhlen,
305     int *newonep)
306 {
307 	struct nfsclowner *owp = *owpp, *nowp;
308 	struct nfsclopen *op, *nop;
309 
310 	if (nowpp != NULL)
311 		nowp = *nowpp;
312 	else
313 		nowp = NULL;
314 	if (nopp != NULL)
315 		nop = *nopp;
316 	else
317 		nop = NULL;
318 	if (owp == NULL && nowp != NULL) {
319 		NFSBCOPY(own, nowp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
320 		LIST_INIT(&nowp->nfsow_open);
321 		nowp->nfsow_clp = clp;
322 		nowp->nfsow_seqid = 0;
323 		nowp->nfsow_defunct = 0;
324 		nfscl_lockinit(&nowp->nfsow_rwlock);
325 		if (dp != NULL) {
326 			newnfsstats.cllocalopenowners++;
327 			LIST_INSERT_HEAD(&dp->nfsdl_owner, nowp, nfsow_list);
328 		} else {
329 			newnfsstats.clopenowners++;
330 			LIST_INSERT_HEAD(&clp->nfsc_owner, nowp, nfsow_list);
331 		}
332 		owp = *owpp = nowp;
333 		*nowpp = NULL;
334 		if (newonep != NULL)
335 			*newonep = 1;
336 	}
337 
338 	 /* If an fhp has been specified, create an Open as well. */
339 	if (fhp != NULL) {
340 		/* and look for the correct open, based upon FH */
341 		LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
342 			if (op->nfso_fhlen == fhlen &&
343 			    !NFSBCMP(op->nfso_fh, fhp, fhlen))
344 				break;
345 		}
346 		if (op == NULL && nop != NULL) {
347 			nop->nfso_own = owp;
348 			nop->nfso_mode = 0;
349 			nop->nfso_opencnt = 0;
350 			nop->nfso_posixlock = 1;
351 			nop->nfso_fhlen = fhlen;
352 			NFSBCOPY(fhp, nop->nfso_fh, fhlen);
353 			LIST_INIT(&nop->nfso_lock);
354 			nop->nfso_stateid.seqid = 0;
355 			nop->nfso_stateid.other[0] = 0;
356 			nop->nfso_stateid.other[1] = 0;
357 			nop->nfso_stateid.other[2] = 0;
358 			if (dp != NULL) {
359 				TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list);
360 				TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp,
361 				    nfsdl_list);
362 				dp->nfsdl_timestamp = NFSD_MONOSEC + 120;
363 				newnfsstats.cllocalopens++;
364 			} else {
365 				newnfsstats.clopens++;
366 			}
367 			LIST_INSERT_HEAD(&owp->nfsow_open, nop, nfso_list);
368 			*opp = nop;
369 			*nopp = NULL;
370 			if (newonep != NULL)
371 				*newonep = 1;
372 		} else {
373 			*opp = op;
374 		}
375 	}
376 }
377 
378 /*
379  * Called to find/add a delegation to a client.
380  */
381 APPLESTATIC int
382 nfscl_deleg(mount_t mp, struct nfsclclient *clp, u_int8_t *nfhp,
383     int fhlen, struct ucred *cred, NFSPROC_T *p, struct nfscldeleg **dpp)
384 {
385 	struct nfscldeleg *dp = *dpp, *tdp;
386 
387 	/*
388 	 * First, if we have received a Read delegation for a file on a
389 	 * read/write file system, just return it, because they aren't
390 	 * useful, imho.
391 	 */
392 	if (mp != NULL && dp != NULL && !NFSMNT_RDONLY(mp) &&
393 	    (dp->nfsdl_flags & NFSCLDL_READ)) {
394 		(void) nfscl_trydelegreturn(dp, cred, VFSTONFS(mp), p);
395 		FREE((caddr_t)dp, M_NFSCLDELEG);
396 		*dpp = NULL;
397 		return (0);
398 	}
399 
400 	/* Look for the correct deleg, based upon FH */
401 	NFSLOCKCLSTATE();
402 	tdp = nfscl_finddeleg(clp, nfhp, fhlen);
403 	if (tdp == NULL) {
404 		if (dp == NULL) {
405 			NFSUNLOCKCLSTATE();
406 			return (NFSERR_BADSTATEID);
407 		}
408 		*dpp = NULL;
409 		TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, nfsdl_list);
410 		LIST_INSERT_HEAD(NFSCLDELEGHASH(clp, nfhp, fhlen), dp,
411 		    nfsdl_hash);
412 		dp->nfsdl_timestamp = NFSD_MONOSEC + 120;
413 		newnfsstats.cldelegates++;
414 		nfscl_delegcnt++;
415 	} else {
416 		/*
417 		 * Delegation already exists, what do we do if a new one??
418 		 */
419 		if (dp != NULL) {
420 			printf("Deleg already exists!\n");
421 			FREE((caddr_t)dp, M_NFSCLDELEG);
422 			*dpp = NULL;
423 		} else {
424 			*dpp = tdp;
425 		}
426 	}
427 	NFSUNLOCKCLSTATE();
428 	return (0);
429 }
430 
431 /*
432  * Find a delegation for this file handle. Return NULL upon failure.
433  */
434 static struct nfscldeleg *
435 nfscl_finddeleg(struct nfsclclient *clp, u_int8_t *fhp, int fhlen)
436 {
437 	struct nfscldeleg *dp;
438 
439 	LIST_FOREACH(dp, NFSCLDELEGHASH(clp, fhp, fhlen), nfsdl_hash) {
440 	    if (dp->nfsdl_fhlen == fhlen &&
441 		!NFSBCMP(dp->nfsdl_fh, fhp, fhlen))
442 		break;
443 	}
444 	return (dp);
445 }
446 
447 /*
448  * Get a stateid for an I/O operation. First, look for an open and iff
449  * found, return either a lockowner stateid or the open stateid.
450  * If no Open is found, just return error and the special stateid of all zeros.
451  */
452 APPLESTATIC int
453 nfscl_getstateid(vnode_t vp, u_int8_t *nfhp, int fhlen, u_int32_t mode,
454     struct ucred *cred, NFSPROC_T *p, nfsv4stateid_t *stateidp,
455     void **lckpp)
456 {
457 	struct nfsclclient *clp;
458 	struct nfsclowner *owp;
459 	struct nfsclopen *op = NULL;
460 	struct nfscllockowner *lp;
461 	struct nfscldeleg *dp;
462 	struct nfsnode *np;
463 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
464 	int error, done;
465 
466 	*lckpp = NULL;
467 	/*
468 	 * Initially, just set the special stateid of all zeros.
469 	 */
470 	stateidp->seqid = 0;
471 	stateidp->other[0] = 0;
472 	stateidp->other[1] = 0;
473 	stateidp->other[2] = 0;
474 	if (vnode_vtype(vp) != VREG)
475 		return (EISDIR);
476 	np = VTONFS(vp);
477 	NFSLOCKCLSTATE();
478 	clp = nfscl_findcl(VFSTONFS(vnode_mount(vp)));
479 	if (clp == NULL) {
480 		NFSUNLOCKCLSTATE();
481 		return (EACCES);
482 	}
483 
484 	/*
485 	 * Wait for recovery to complete.
486 	 */
487 	while ((clp->nfsc_flags & NFSCLFLAGS_RECVRINPROG))
488 		(void) nfsmsleep(&clp->nfsc_flags, NFSCLSTATEMUTEXPTR,
489 		    PZERO, "nfsrecvr", NULL);
490 
491 	/*
492 	 * First, look for a delegation.
493 	 */
494 	LIST_FOREACH(dp, NFSCLDELEGHASH(clp, nfhp, fhlen), nfsdl_hash) {
495 		if (dp->nfsdl_fhlen == fhlen &&
496 		    !NFSBCMP(nfhp, dp->nfsdl_fh, fhlen)) {
497 			if (!(mode & NFSV4OPEN_ACCESSWRITE) ||
498 			    (dp->nfsdl_flags & NFSCLDL_WRITE)) {
499 				stateidp->seqid = dp->nfsdl_stateid.seqid;
500 				stateidp->other[0] = dp->nfsdl_stateid.other[0];
501 				stateidp->other[1] = dp->nfsdl_stateid.other[1];
502 				stateidp->other[2] = dp->nfsdl_stateid.other[2];
503 				if (!(np->n_flag & NDELEGRECALL)) {
504 					TAILQ_REMOVE(&clp->nfsc_deleg, dp,
505 					    nfsdl_list);
506 					TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp,
507 					    nfsdl_list);
508 					dp->nfsdl_timestamp = NFSD_MONOSEC +
509 					    120;
510 					dp->nfsdl_rwlock.nfslock_usecnt++;
511 					*lckpp = (void *)&dp->nfsdl_rwlock;
512 				}
513 				NFSUNLOCKCLSTATE();
514 				return (0);
515 			}
516 			break;
517 		}
518 	}
519 
520 	if (p != NULL) {
521 		/*
522 		 * If p != NULL, we want to search the parentage tree
523 		 * for a matching OpenOwner and use that.
524 		 */
525 		nfscl_filllockowner(p->td_proc, own, F_POSIX);
526 		lp = NULL;
527 		error = nfscl_getopen(&clp->nfsc_owner, nfhp, fhlen, own, own,
528 		    mode, &lp, &op);
529 		if (error == 0 && lp != NULL) {
530 			stateidp->seqid =
531 			    lp->nfsl_stateid.seqid;
532 			stateidp->other[0] =
533 			    lp->nfsl_stateid.other[0];
534 			stateidp->other[1] =
535 			    lp->nfsl_stateid.other[1];
536 			stateidp->other[2] =
537 			    lp->nfsl_stateid.other[2];
538 			NFSUNLOCKCLSTATE();
539 			return (0);
540 		}
541 	}
542 	if (op == NULL) {
543 		/* If not found, just look for any OpenOwner that will work. */
544 		done = 0;
545 		owp = LIST_FIRST(&clp->nfsc_owner);
546 		while (!done && owp != NULL) {
547 			LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
548 				if (op->nfso_fhlen == fhlen &&
549 				    !NFSBCMP(op->nfso_fh, nfhp, fhlen) &&
550 				    (mode & op->nfso_mode) == mode) {
551 					done = 1;
552 					break;
553 				}
554 			}
555 			if (!done)
556 				owp = LIST_NEXT(owp, nfsow_list);
557 		}
558 		if (!done) {
559 			NFSUNLOCKCLSTATE();
560 			return (ENOENT);
561 		}
562 		/* for read aheads or write behinds, use the open cred */
563 		newnfs_copycred(&op->nfso_cred, cred);
564 	}
565 
566 	/*
567 	 * No lock stateid, so return the open stateid.
568 	 */
569 	stateidp->seqid = op->nfso_stateid.seqid;
570 	stateidp->other[0] = op->nfso_stateid.other[0];
571 	stateidp->other[1] = op->nfso_stateid.other[1];
572 	stateidp->other[2] = op->nfso_stateid.other[2];
573 	NFSUNLOCKCLSTATE();
574 	return (0);
575 }
576 
577 /*
578  * Search for a matching file, mode and, optionally, lockowner.
579  */
580 static int
581 nfscl_getopen(struct nfsclownerhead *ohp, u_int8_t *nfhp, int fhlen,
582     u_int8_t *openown, u_int8_t *lockown, u_int32_t mode,
583     struct nfscllockowner **lpp, struct nfsclopen **opp)
584 {
585 	struct nfsclowner *owp;
586 	struct nfsclopen *op, *rop, *rop2;
587 	struct nfscllockowner *lp;
588 	int keep_looping;
589 
590 	if (lpp != NULL)
591 		*lpp = NULL;
592 	/*
593 	 * rop will be set to the open to be returned. There are three
594 	 * variants of this, all for an open of the correct file:
595 	 * 1 - A match of lockown.
596 	 * 2 - A match of the openown, when no lockown match exists.
597 	 * 3 - A match for any open, if no openown or lockown match exists.
598 	 * Looking for #2 over #3 probably isn't necessary, but since
599 	 * RFC3530 is vague w.r.t. the relationship between openowners and
600 	 * lockowners, I think this is the safer way to go.
601 	 */
602 	rop = NULL;
603 	rop2 = NULL;
604 	keep_looping = 1;
605 	/* Search the client list */
606 	owp = LIST_FIRST(ohp);
607 	while (owp != NULL && keep_looping != 0) {
608 		/* and look for the correct open */
609 		op = LIST_FIRST(&owp->nfsow_open);
610 		while (op != NULL && keep_looping != 0) {
611 			if (op->nfso_fhlen == fhlen &&
612 			    !NFSBCMP(op->nfso_fh, nfhp, fhlen)
613 			    && (op->nfso_mode & mode) == mode) {
614 				if (lpp != NULL) {
615 					/* Now look for a matching lockowner. */
616 					LIST_FOREACH(lp, &op->nfso_lock,
617 					    nfsl_list) {
618 						if (!NFSBCMP(lp->nfsl_owner,
619 						    lockown,
620 						    NFSV4CL_LOCKNAMELEN)) {
621 							*lpp = lp;
622 							rop = op;
623 							keep_looping = 0;
624 							break;
625 						}
626 					}
627 				}
628 				if (rop == NULL && !NFSBCMP(owp->nfsow_owner,
629 				    openown, NFSV4CL_LOCKNAMELEN)) {
630 					rop = op;
631 					if (lpp == NULL)
632 						keep_looping = 0;
633 				}
634 				if (rop2 == NULL)
635 					rop2 = op;
636 			}
637 			op = LIST_NEXT(op, nfso_list);
638 		}
639 		owp = LIST_NEXT(owp, nfsow_list);
640 	}
641 	if (rop == NULL)
642 		rop = rop2;
643 	if (rop == NULL)
644 		return (EBADF);
645 	*opp = rop;
646 	return (0);
647 }
648 
649 /*
650  * Release use of an open owner. Called when open operations are done
651  * with the open owner.
652  */
653 APPLESTATIC void
654 nfscl_ownerrelease(struct nfsclowner *owp, __unused int error,
655     __unused int candelete, int unlocked)
656 {
657 
658 	if (owp == NULL)
659 		return;
660 	NFSLOCKCLSTATE();
661 	if (!unlocked)
662 		nfscl_lockunlock(&owp->nfsow_rwlock);
663 	nfscl_clrelease(owp->nfsow_clp);
664 	NFSUNLOCKCLSTATE();
665 }
666 
667 /*
668  * Release use of an open structure under an open owner.
669  */
670 APPLESTATIC void
671 nfscl_openrelease(struct nfsclopen *op, int error, int candelete)
672 {
673 	struct nfsclclient *clp;
674 	struct nfsclowner *owp;
675 
676 	if (op == NULL)
677 		return;
678 	NFSLOCKCLSTATE();
679 	owp = op->nfso_own;
680 	nfscl_lockunlock(&owp->nfsow_rwlock);
681 	clp = owp->nfsow_clp;
682 	if (error && candelete && op->nfso_opencnt == 0)
683 		nfscl_freeopen(op, 0);
684 	nfscl_clrelease(clp);
685 	NFSUNLOCKCLSTATE();
686 }
687 
688 /*
689  * Called to get a clientid structure. It will optionally lock the
690  * client data structures to do the SetClientId/SetClientId_confirm,
691  * but will release that lock and return the clientid with a refernce
692  * count on it.
693  * If the "cred" argument is NULL, a new clientid should not be created.
694  * If the "p" argument is NULL, a SetClientID/SetClientIDConfirm cannot
695  * be done.
696  * It always clpp with a reference count on it, unless returning an error.
697  */
698 APPLESTATIC int
699 nfscl_getcl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
700     struct nfsclclient **clpp)
701 {
702 	struct nfsclclient *clp;
703 	struct nfsclclient *newclp = NULL;
704 	struct mount *mp;
705 	struct nfsmount *nmp;
706 	char uuid[HOSTUUIDLEN];
707 	int igotlock = 0, error, trystalecnt, clidinusedelay, i;
708 	u_int16_t idlen = 0;
709 
710 	mp = vnode_mount(vp);
711 	nmp = VFSTONFS(mp);
712 	if (cred != NULL) {
713 		getcredhostuuid(cred, uuid, sizeof uuid);
714 		idlen = strlen(uuid);
715 		if (idlen > 0)
716 			idlen += sizeof (u_int64_t);
717 		else
718 			idlen += sizeof (u_int64_t) + 16; /* 16 random bytes */
719 		MALLOC(newclp, struct nfsclclient *,
720 		    sizeof (struct nfsclclient) + idlen - 1, M_NFSCLCLIENT,
721 		    M_WAITOK);
722 	}
723 	NFSLOCKCLSTATE();
724 	/*
725 	 * If a forced dismount is already in progress, don't
726 	 * allocate a new clientid and get out now. For the case where
727 	 * clp != NULL, this is a harmless optimization.
728 	 */
729 	if ((mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
730 		NFSUNLOCKCLSTATE();
731 		if (newclp != NULL)
732 			free(newclp, M_NFSCLCLIENT);
733 		return (EBADF);
734 	}
735 	clp = nmp->nm_clp;
736 	if (clp == NULL) {
737 		if (newclp == NULL) {
738 			NFSUNLOCKCLSTATE();
739 			return (EACCES);
740 		}
741 		clp = newclp;
742 		NFSBZERO((caddr_t)clp, sizeof(struct nfsclclient) + idlen - 1);
743 		clp->nfsc_idlen = idlen;
744 		LIST_INIT(&clp->nfsc_owner);
745 		TAILQ_INIT(&clp->nfsc_deleg);
746 		for (i = 0; i < NFSCLDELEGHASHSIZE; i++)
747 			LIST_INIT(&clp->nfsc_deleghash[i]);
748 		clp->nfsc_flags = NFSCLFLAGS_INITED;
749 		clp->nfsc_clientidrev = 1;
750 		clp->nfsc_cbident = nfscl_nextcbident();
751 		nfscl_fillclid(nmp->nm_clval, uuid, clp->nfsc_id,
752 		    clp->nfsc_idlen);
753 		LIST_INSERT_HEAD(&nfsclhead, clp, nfsc_list);
754 		nmp->nm_clp = clp;
755 		clp->nfsc_nmp = nmp;
756 		NFSUNLOCKCLSTATE();
757 		nfscl_start_renewthread(clp);
758 	} else {
759 		NFSUNLOCKCLSTATE();
760 		if (newclp != NULL)
761 			FREE((caddr_t)newclp, M_NFSCLCLIENT);
762 	}
763 	NFSLOCKCLSTATE();
764 	while ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0 && !igotlock &&
765 	    (mp->mnt_kern_flag & MNTK_UNMOUNTF) == 0)
766 		igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
767 		    NFSCLSTATEMUTEXPTR, mp);
768 	if (!igotlock)
769 		nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, mp);
770 	if (igotlock == 0 && (mp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
771 		/*
772 		 * Both nfsv4_lock() and nfsv4_getref() know to check
773 		 * for MNTK_UNMOUNTF and return without sleeping to
774 		 * wait for the exclusive lock to be released, since it
775 		 * might be held by nfscl_umount() and we need to get out
776 		 * now for that case and not wait until nfscl_umount()
777 		 * releases it.
778 		 */
779 		NFSUNLOCKCLSTATE();
780 		return (EBADF);
781 	}
782 	NFSUNLOCKCLSTATE();
783 
784 	/*
785 	 * If it needs a clientid, do the setclientid now.
786 	 */
787 	if ((clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID) == 0) {
788 		if (!igotlock)
789 			panic("nfscl_clget");
790 		if (p == NULL || cred == NULL) {
791 			NFSLOCKCLSTATE();
792 			nfsv4_unlock(&clp->nfsc_lock, 0);
793 			NFSUNLOCKCLSTATE();
794 			return (EACCES);
795 		}
796 		/*
797 		 * If RFC3530 Sec. 14.2.33 is taken literally,
798 		 * NFSERR_CLIDINUSE will be returned persistently for the
799 		 * case where a new mount of the same file system is using
800 		 * a different principal. In practice, NFSERR_CLIDINUSE is
801 		 * only returned when there is outstanding unexpired state
802 		 * on the clientid. As such, try for twice the lease
803 		 * interval, if we know what that is. Otherwise, make a
804 		 * wild ass guess.
805 		 * The case of returning NFSERR_STALECLIENTID is far less
806 		 * likely, but might occur if there is a significant delay
807 		 * between doing the SetClientID and SetClientIDConfirm Ops,
808 		 * such that the server throws away the clientid before
809 		 * receiving the SetClientIDConfirm.
810 		 */
811 		if (clp->nfsc_renew > 0)
812 			clidinusedelay = NFSCL_LEASE(clp->nfsc_renew) * 2;
813 		else
814 			clidinusedelay = 120;
815 		trystalecnt = 3;
816 		do {
817 			error = nfsrpc_setclient(VFSTONFS(vnode_mount(vp)),
818 			    clp, cred, p);
819 			if (error == NFSERR_STALECLIENTID ||
820 			    error == NFSERR_STALEDONTRECOVER ||
821 			    error == NFSERR_CLIDINUSE) {
822 				(void) nfs_catnap(PZERO, error, "nfs_setcl");
823 			}
824 		} while (((error == NFSERR_STALECLIENTID ||
825 		     error == NFSERR_STALEDONTRECOVER) && --trystalecnt > 0) ||
826 		    (error == NFSERR_CLIDINUSE && --clidinusedelay > 0));
827 		if (error) {
828 			NFSLOCKCLSTATE();
829 			nfsv4_unlock(&clp->nfsc_lock, 0);
830 			NFSUNLOCKCLSTATE();
831 			return (error);
832 		}
833 		clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID;
834 	}
835 	if (igotlock) {
836 		NFSLOCKCLSTATE();
837 		nfsv4_unlock(&clp->nfsc_lock, 1);
838 		NFSUNLOCKCLSTATE();
839 	}
840 
841 	*clpp = clp;
842 	return (0);
843 }
844 
845 /*
846  * Get a reference to a clientid and return it, if valid.
847  */
848 APPLESTATIC struct nfsclclient *
849 nfscl_findcl(struct nfsmount *nmp)
850 {
851 	struct nfsclclient *clp;
852 
853 	clp = nmp->nm_clp;
854 	if (clp == NULL || !(clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID))
855 		return (NULL);
856 	return (clp);
857 }
858 
859 /*
860  * Release the clientid structure. It may be locked or reference counted.
861  */
862 static void
863 nfscl_clrelease(struct nfsclclient *clp)
864 {
865 
866 	if (clp->nfsc_lock.nfslock_lock & NFSV4LOCK_LOCK)
867 		nfsv4_unlock(&clp->nfsc_lock, 0);
868 	else
869 		nfsv4_relref(&clp->nfsc_lock);
870 }
871 
872 /*
873  * External call for nfscl_clrelease.
874  */
875 APPLESTATIC void
876 nfscl_clientrelease(struct nfsclclient *clp)
877 {
878 
879 	NFSLOCKCLSTATE();
880 	if (clp->nfsc_lock.nfslock_lock & NFSV4LOCK_LOCK)
881 		nfsv4_unlock(&clp->nfsc_lock, 0);
882 	else
883 		nfsv4_relref(&clp->nfsc_lock);
884 	NFSUNLOCKCLSTATE();
885 }
886 
887 /*
888  * Called when wanting to lock a byte region.
889  */
890 APPLESTATIC int
891 nfscl_getbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
892     short type, struct ucred *cred, NFSPROC_T *p, struct nfsclclient *rclp,
893     int recovery, void *id, int flags, u_int8_t *rownp, u_int8_t *ropenownp,
894     struct nfscllockowner **lpp, int *newonep, int *donelocallyp)
895 {
896 	struct nfscllockowner *lp;
897 	struct nfsclopen *op;
898 	struct nfsclclient *clp;
899 	struct nfscllockowner *nlp;
900 	struct nfscllock *nlop, *otherlop;
901 	struct nfscldeleg *dp = NULL, *ldp = NULL;
902 	struct nfscllockownerhead *lhp = NULL;
903 	struct nfsnode *np;
904 	u_int8_t own[NFSV4CL_LOCKNAMELEN], *ownp, openown[NFSV4CL_LOCKNAMELEN];
905 	u_int8_t *openownp;
906 	int error = 0, ret, donelocally = 0;
907 	u_int32_t mode;
908 
909 	/* For Lock Ops, the open mode doesn't matter, so use 0 to match any. */
910 	mode = 0;
911 	np = VTONFS(vp);
912 	*lpp = NULL;
913 	lp = NULL;
914 	*newonep = 0;
915 	*donelocallyp = 0;
916 
917 	/*
918 	 * Might need these, so MALLOC them now, to
919 	 * avoid a tsleep() in MALLOC later.
920 	 */
921 	MALLOC(nlp, struct nfscllockowner *,
922 	    sizeof (struct nfscllockowner), M_NFSCLLOCKOWNER, M_WAITOK);
923 	MALLOC(otherlop, struct nfscllock *,
924 	    sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
925 	MALLOC(nlop, struct nfscllock *,
926 	    sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
927 	nlop->nfslo_type = type;
928 	nlop->nfslo_first = off;
929 	if (len == NFS64BITSSET) {
930 		nlop->nfslo_end = NFS64BITSSET;
931 	} else {
932 		nlop->nfslo_end = off + len;
933 		if (nlop->nfslo_end <= nlop->nfslo_first)
934 			error = NFSERR_INVAL;
935 	}
936 
937 	if (!error) {
938 		if (recovery)
939 			clp = rclp;
940 		else
941 			error = nfscl_getcl(vp, cred, p, &clp);
942 	}
943 	if (error) {
944 		FREE((caddr_t)nlp, M_NFSCLLOCKOWNER);
945 		FREE((caddr_t)otherlop, M_NFSCLLOCK);
946 		FREE((caddr_t)nlop, M_NFSCLLOCK);
947 		return (error);
948 	}
949 
950 	op = NULL;
951 	if (recovery) {
952 		ownp = rownp;
953 		openownp = ropenownp;
954 	} else {
955 		nfscl_filllockowner(id, own, flags);
956 		ownp = own;
957 		nfscl_filllockowner(p->td_proc, openown, F_POSIX);
958 		openownp = openown;
959 	}
960 	if (!recovery) {
961 		NFSLOCKCLSTATE();
962 		/*
963 		 * First, search for a delegation. If one exists for this file,
964 		 * the lock can be done locally against it, so long as there
965 		 * isn't a local lock conflict.
966 		 */
967 		ldp = dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
968 		    np->n_fhp->nfh_len);
969 		/* Just sanity check for correct type of delegation */
970 		if (dp != NULL && ((dp->nfsdl_flags &
971 		    (NFSCLDL_RECALL | NFSCLDL_DELEGRET)) != 0 ||
972 		     (type == F_WRLCK &&
973 		      (dp->nfsdl_flags & NFSCLDL_WRITE) == 0)))
974 			dp = NULL;
975 	}
976 	if (dp != NULL) {
977 		/* Now, find an open and maybe a lockowner. */
978 		ret = nfscl_getopen(&dp->nfsdl_owner, np->n_fhp->nfh_fh,
979 		    np->n_fhp->nfh_len, openownp, ownp, mode, NULL, &op);
980 		if (ret)
981 			ret = nfscl_getopen(&clp->nfsc_owner,
982 			    np->n_fhp->nfh_fh, np->n_fhp->nfh_len, openownp,
983 			    ownp, mode, NULL, &op);
984 		if (!ret) {
985 			lhp = &dp->nfsdl_lock;
986 			TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list);
987 			TAILQ_INSERT_HEAD(&clp->nfsc_deleg, dp, nfsdl_list);
988 			dp->nfsdl_timestamp = NFSD_MONOSEC + 120;
989 			donelocally = 1;
990 		} else {
991 			dp = NULL;
992 		}
993 	}
994 	if (!donelocally) {
995 		/*
996 		 * Get the related Open and maybe lockowner.
997 		 */
998 		error = nfscl_getopen(&clp->nfsc_owner,
999 		    np->n_fhp->nfh_fh, np->n_fhp->nfh_len, openownp,
1000 		    ownp, mode, &lp, &op);
1001 		if (!error)
1002 			lhp = &op->nfso_lock;
1003 	}
1004 	if (!error && !recovery)
1005 		error = nfscl_localconflict(clp, np->n_fhp->nfh_fh,
1006 		    np->n_fhp->nfh_len, nlop, ownp, ldp, NULL);
1007 	if (error) {
1008 		if (!recovery) {
1009 			nfscl_clrelease(clp);
1010 			NFSUNLOCKCLSTATE();
1011 		}
1012 		FREE((caddr_t)nlp, M_NFSCLLOCKOWNER);
1013 		FREE((caddr_t)otherlop, M_NFSCLLOCK);
1014 		FREE((caddr_t)nlop, M_NFSCLLOCK);
1015 		return (error);
1016 	}
1017 
1018 	/*
1019 	 * Ok, see if a lockowner exists and create one, as required.
1020 	 */
1021 	if (lp == NULL)
1022 		LIST_FOREACH(lp, lhp, nfsl_list) {
1023 			if (!NFSBCMP(lp->nfsl_owner, ownp, NFSV4CL_LOCKNAMELEN))
1024 				break;
1025 		}
1026 	if (lp == NULL) {
1027 		NFSBCOPY(ownp, nlp->nfsl_owner, NFSV4CL_LOCKNAMELEN);
1028 		if (recovery)
1029 			NFSBCOPY(ropenownp, nlp->nfsl_openowner,
1030 			    NFSV4CL_LOCKNAMELEN);
1031 		else
1032 			NFSBCOPY(op->nfso_own->nfsow_owner, nlp->nfsl_openowner,
1033 			    NFSV4CL_LOCKNAMELEN);
1034 		nlp->nfsl_seqid = 0;
1035 		nlp->nfsl_lockflags = flags;
1036 		nlp->nfsl_inprog = NULL;
1037 		nfscl_lockinit(&nlp->nfsl_rwlock);
1038 		LIST_INIT(&nlp->nfsl_lock);
1039 		if (donelocally) {
1040 			nlp->nfsl_open = NULL;
1041 			newnfsstats.cllocallockowners++;
1042 		} else {
1043 			nlp->nfsl_open = op;
1044 			newnfsstats.cllockowners++;
1045 		}
1046 		LIST_INSERT_HEAD(lhp, nlp, nfsl_list);
1047 		lp = nlp;
1048 		nlp = NULL;
1049 		*newonep = 1;
1050 	}
1051 
1052 	/*
1053 	 * Now, update the byte ranges for locks.
1054 	 */
1055 	ret = nfscl_updatelock(lp, &nlop, &otherlop, donelocally);
1056 	if (!ret)
1057 		donelocally = 1;
1058 	if (donelocally) {
1059 		*donelocallyp = 1;
1060 		if (!recovery)
1061 			nfscl_clrelease(clp);
1062 	} else {
1063 		/*
1064 		 * Serial modifications on the lock owner for multiple threads
1065 		 * for the same process using a read/write lock.
1066 		 */
1067 		if (!recovery)
1068 			nfscl_lockexcl(&lp->nfsl_rwlock, NFSCLSTATEMUTEXPTR);
1069 	}
1070 	if (!recovery)
1071 		NFSUNLOCKCLSTATE();
1072 
1073 	if (nlp)
1074 		FREE((caddr_t)nlp, M_NFSCLLOCKOWNER);
1075 	if (nlop)
1076 		FREE((caddr_t)nlop, M_NFSCLLOCK);
1077 	if (otherlop)
1078 		FREE((caddr_t)otherlop, M_NFSCLLOCK);
1079 
1080 	*lpp = lp;
1081 	return (0);
1082 }
1083 
1084 /*
1085  * Called to unlock a byte range, for LockU.
1086  */
1087 APPLESTATIC int
1088 nfscl_relbytelock(vnode_t vp, u_int64_t off, u_int64_t len,
1089     __unused struct ucred *cred, NFSPROC_T *p, int callcnt,
1090     struct nfsclclient *clp, void *id, int flags,
1091     struct nfscllockowner **lpp, int *dorpcp)
1092 {
1093 	struct nfscllockowner *lp;
1094 	struct nfsclowner *owp;
1095 	struct nfsclopen *op;
1096 	struct nfscllock *nlop, *other_lop = NULL;
1097 	struct nfscldeleg *dp;
1098 	struct nfsnode *np;
1099 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
1100 	int ret = 0, fnd;
1101 
1102 	np = VTONFS(vp);
1103 	*lpp = NULL;
1104 	*dorpcp = 0;
1105 
1106 	/*
1107 	 * Might need these, so MALLOC them now, to
1108 	 * avoid a tsleep() in MALLOC later.
1109 	 */
1110 	MALLOC(nlop, struct nfscllock *,
1111 	    sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
1112 	nlop->nfslo_type = F_UNLCK;
1113 	nlop->nfslo_first = off;
1114 	if (len == NFS64BITSSET) {
1115 		nlop->nfslo_end = NFS64BITSSET;
1116 	} else {
1117 		nlop->nfslo_end = off + len;
1118 		if (nlop->nfslo_end <= nlop->nfslo_first) {
1119 			FREE((caddr_t)nlop, M_NFSCLLOCK);
1120 			return (NFSERR_INVAL);
1121 		}
1122 	}
1123 	if (callcnt == 0) {
1124 		MALLOC(other_lop, struct nfscllock *,
1125 		    sizeof (struct nfscllock), M_NFSCLLOCK, M_WAITOK);
1126 		*other_lop = *nlop;
1127 	}
1128 	nfscl_filllockowner(id, own, flags);
1129 	dp = NULL;
1130 	NFSLOCKCLSTATE();
1131 	if (callcnt == 0)
1132 		dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
1133 		    np->n_fhp->nfh_len);
1134 
1135 	/*
1136 	 * First, unlock any local regions on a delegation.
1137 	 */
1138 	if (dp != NULL) {
1139 		/* Look for this lockowner. */
1140 		LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
1141 			if (!NFSBCMP(lp->nfsl_owner, own,
1142 			    NFSV4CL_LOCKNAMELEN))
1143 				break;
1144 		}
1145 		if (lp != NULL)
1146 			/* Use other_lop, so nlop is still available */
1147 			(void)nfscl_updatelock(lp, &other_lop, NULL, 1);
1148 	}
1149 
1150 	/*
1151 	 * Now, find a matching open/lockowner that hasn't already been done,
1152 	 * as marked by nfsl_inprog.
1153 	 */
1154 	lp = NULL;
1155 	fnd = 0;
1156 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
1157 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
1158 		if (op->nfso_fhlen == np->n_fhp->nfh_len &&
1159 		    !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) {
1160 		    LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
1161 			if (lp->nfsl_inprog == NULL &&
1162 			    !NFSBCMP(lp->nfsl_owner, own,
1163 			     NFSV4CL_LOCKNAMELEN)) {
1164 				fnd = 1;
1165 				break;
1166 			}
1167 		    }
1168 		    if (fnd)
1169 			break;
1170 		}
1171 	    }
1172 	    if (fnd)
1173 		break;
1174 	}
1175 
1176 	if (lp != NULL) {
1177 		ret = nfscl_updatelock(lp, &nlop, NULL, 0);
1178 		if (ret)
1179 			*dorpcp = 1;
1180 		/*
1181 		 * Serial modifications on the lock owner for multiple
1182 		 * threads for the same process using a read/write lock.
1183 		 */
1184 		lp->nfsl_inprog = p;
1185 		nfscl_lockexcl(&lp->nfsl_rwlock, NFSCLSTATEMUTEXPTR);
1186 		*lpp = lp;
1187 	}
1188 	NFSUNLOCKCLSTATE();
1189 	if (nlop)
1190 		FREE((caddr_t)nlop, M_NFSCLLOCK);
1191 	if (other_lop)
1192 		FREE((caddr_t)other_lop, M_NFSCLLOCK);
1193 	return (0);
1194 }
1195 
1196 /*
1197  * Release all lockowners marked in progess for this process and file.
1198  */
1199 APPLESTATIC void
1200 nfscl_releasealllocks(struct nfsclclient *clp, vnode_t vp, NFSPROC_T *p,
1201     void *id, int flags)
1202 {
1203 	struct nfsclowner *owp;
1204 	struct nfsclopen *op;
1205 	struct nfscllockowner *lp;
1206 	struct nfsnode *np;
1207 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
1208 
1209 	np = VTONFS(vp);
1210 	nfscl_filllockowner(id, own, flags);
1211 	NFSLOCKCLSTATE();
1212 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
1213 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
1214 		if (op->nfso_fhlen == np->n_fhp->nfh_len &&
1215 		    !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) {
1216 		    LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
1217 			if (lp->nfsl_inprog == p &&
1218 			    !NFSBCMP(lp->nfsl_owner, own,
1219 			    NFSV4CL_LOCKNAMELEN)) {
1220 			    lp->nfsl_inprog = NULL;
1221 			    nfscl_lockunlock(&lp->nfsl_rwlock);
1222 			}
1223 		    }
1224 		}
1225 	    }
1226 	}
1227 	nfscl_clrelease(clp);
1228 	NFSUNLOCKCLSTATE();
1229 }
1230 
1231 /*
1232  * Called to find out if any bytes within the byte range specified are
1233  * write locked by the calling process. Used to determine if flushing
1234  * is required before a LockU.
1235  * If in doubt, return 1, so the flush will occur.
1236  */
1237 APPLESTATIC int
1238 nfscl_checkwritelocked(vnode_t vp, struct flock *fl,
1239     struct ucred *cred, NFSPROC_T *p, void *id, int flags)
1240 {
1241 	struct nfsclowner *owp;
1242 	struct nfscllockowner *lp;
1243 	struct nfsclopen *op;
1244 	struct nfsclclient *clp;
1245 	struct nfscllock *lop;
1246 	struct nfscldeleg *dp;
1247 	struct nfsnode *np;
1248 	u_int64_t off, end;
1249 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
1250 	int error = 0;
1251 
1252 	np = VTONFS(vp);
1253 	switch (fl->l_whence) {
1254 	case SEEK_SET:
1255 	case SEEK_CUR:
1256 		/*
1257 		 * Caller is responsible for adding any necessary offset
1258 		 * when SEEK_CUR is used.
1259 		 */
1260 		off = fl->l_start;
1261 		break;
1262 	case SEEK_END:
1263 		off = np->n_size + fl->l_start;
1264 		break;
1265 	default:
1266 		return (1);
1267 	};
1268 	if (fl->l_len != 0) {
1269 		end = off + fl->l_len;
1270 		if (end < off)
1271 			return (1);
1272 	} else {
1273 		end = NFS64BITSSET;
1274 	}
1275 
1276 	error = nfscl_getcl(vp, cred, p, &clp);
1277 	if (error)
1278 		return (1);
1279 	nfscl_filllockowner(id, own, flags);
1280 	NFSLOCKCLSTATE();
1281 
1282 	/*
1283 	 * First check the delegation locks.
1284 	 */
1285 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
1286 	if (dp != NULL) {
1287 		LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
1288 			if (!NFSBCMP(lp->nfsl_owner, own,
1289 			    NFSV4CL_LOCKNAMELEN))
1290 				break;
1291 		}
1292 		if (lp != NULL) {
1293 			LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
1294 				if (lop->nfslo_first >= end)
1295 					break;
1296 				if (lop->nfslo_end <= off)
1297 					continue;
1298 				if (lop->nfslo_type == F_WRLCK) {
1299 					nfscl_clrelease(clp);
1300 					NFSUNLOCKCLSTATE();
1301 					return (1);
1302 				}
1303 			}
1304 		}
1305 	}
1306 
1307 	/*
1308 	 * Now, check state against the server.
1309 	 */
1310 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
1311 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
1312 		if (op->nfso_fhlen == np->n_fhp->nfh_len &&
1313 		    !NFSBCMP(op->nfso_fh, np->n_fhp->nfh_fh, op->nfso_fhlen)) {
1314 		    LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
1315 			if (!NFSBCMP(lp->nfsl_owner, own,
1316 			    NFSV4CL_LOCKNAMELEN))
1317 			    break;
1318 		    }
1319 		    if (lp != NULL) {
1320 			LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
1321 			    if (lop->nfslo_first >= end)
1322 				break;
1323 			    if (lop->nfslo_end <= off)
1324 				continue;
1325 			    if (lop->nfslo_type == F_WRLCK) {
1326 				nfscl_clrelease(clp);
1327 				NFSUNLOCKCLSTATE();
1328 				return (1);
1329 			    }
1330 			}
1331 		    }
1332 		}
1333 	    }
1334 	}
1335 	nfscl_clrelease(clp);
1336 	NFSUNLOCKCLSTATE();
1337 	return (0);
1338 }
1339 
1340 /*
1341  * Release a byte range lock owner structure.
1342  */
1343 APPLESTATIC void
1344 nfscl_lockrelease(struct nfscllockowner *lp, int error, int candelete)
1345 {
1346 	struct nfsclclient *clp;
1347 
1348 	if (lp == NULL)
1349 		return;
1350 	NFSLOCKCLSTATE();
1351 	clp = lp->nfsl_open->nfso_own->nfsow_clp;
1352 	if (error != 0 && candelete &&
1353 	    (lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED) == 0)
1354 		nfscl_freelockowner(lp, 0);
1355 	else
1356 		nfscl_lockunlock(&lp->nfsl_rwlock);
1357 	nfscl_clrelease(clp);
1358 	NFSUNLOCKCLSTATE();
1359 }
1360 
1361 /*
1362  * Free up an open structure and any associated byte range lock structures.
1363  */
1364 APPLESTATIC void
1365 nfscl_freeopen(struct nfsclopen *op, int local)
1366 {
1367 
1368 	LIST_REMOVE(op, nfso_list);
1369 	nfscl_freealllocks(&op->nfso_lock, local);
1370 	FREE((caddr_t)op, M_NFSCLOPEN);
1371 	if (local)
1372 		newnfsstats.cllocalopens--;
1373 	else
1374 		newnfsstats.clopens--;
1375 }
1376 
1377 /*
1378  * Free up all lock owners and associated locks.
1379  */
1380 static void
1381 nfscl_freealllocks(struct nfscllockownerhead *lhp, int local)
1382 {
1383 	struct nfscllockowner *lp, *nlp;
1384 
1385 	LIST_FOREACH_SAFE(lp, lhp, nfsl_list, nlp) {
1386 		if ((lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED))
1387 			panic("nfscllckw");
1388 		nfscl_freelockowner(lp, local);
1389 	}
1390 }
1391 
1392 /*
1393  * Called for an Open when NFSERR_EXPIRED is received from the server.
1394  * If there are no byte range locks nor a Share Deny lost, try to do a
1395  * fresh Open. Otherwise, free the open.
1396  */
1397 static int
1398 nfscl_expireopen(struct nfsclclient *clp, struct nfsclopen *op,
1399     struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
1400 {
1401 	struct nfscllockowner *lp;
1402 	struct nfscldeleg *dp;
1403 	int mustdelete = 0, error;
1404 
1405 	/*
1406 	 * Look for any byte range lock(s).
1407 	 */
1408 	LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
1409 		if (!LIST_EMPTY(&lp->nfsl_lock)) {
1410 			mustdelete = 1;
1411 			break;
1412 		}
1413 	}
1414 
1415 	/*
1416 	 * If no byte range lock(s) nor a Share deny, try to re-open.
1417 	 */
1418 	if (!mustdelete && (op->nfso_mode & NFSLCK_DENYBITS) == 0) {
1419 		newnfs_copycred(&op->nfso_cred, cred);
1420 		dp = NULL;
1421 		error = nfsrpc_reopen(nmp, op->nfso_fh,
1422 		    op->nfso_fhlen, op->nfso_mode, op, &dp, cred, p);
1423 		if (error) {
1424 			mustdelete = 1;
1425 			if (dp != NULL) {
1426 				FREE((caddr_t)dp, M_NFSCLDELEG);
1427 				dp = NULL;
1428 			}
1429 		}
1430 		if (dp != NULL)
1431 			nfscl_deleg(nmp->nm_mountp, clp, op->nfso_fh,
1432 			    op->nfso_fhlen, cred, p, &dp);
1433 	}
1434 
1435 	/*
1436 	 * If a byte range lock or Share deny or couldn't re-open, free it.
1437 	 */
1438 	if (mustdelete)
1439 		nfscl_freeopen(op, 0);
1440 	return (mustdelete);
1441 }
1442 
1443 /*
1444  * Free up an open owner structure.
1445  */
1446 static void
1447 nfscl_freeopenowner(struct nfsclowner *owp, int local)
1448 {
1449 
1450 	LIST_REMOVE(owp, nfsow_list);
1451 	FREE((caddr_t)owp, M_NFSCLOWNER);
1452 	if (local)
1453 		newnfsstats.cllocalopenowners--;
1454 	else
1455 		newnfsstats.clopenowners--;
1456 }
1457 
1458 /*
1459  * Free up a byte range lock owner structure.
1460  */
1461 APPLESTATIC void
1462 nfscl_freelockowner(struct nfscllockowner *lp, int local)
1463 {
1464 	struct nfscllock *lop, *nlop;
1465 
1466 	LIST_REMOVE(lp, nfsl_list);
1467 	LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
1468 		nfscl_freelock(lop, local);
1469 	}
1470 	FREE((caddr_t)lp, M_NFSCLLOCKOWNER);
1471 	if (local)
1472 		newnfsstats.cllocallockowners--;
1473 	else
1474 		newnfsstats.cllockowners--;
1475 }
1476 
1477 /*
1478  * Free up a byte range lock structure.
1479  */
1480 APPLESTATIC void
1481 nfscl_freelock(struct nfscllock *lop, int local)
1482 {
1483 
1484 	LIST_REMOVE(lop, nfslo_list);
1485 	FREE((caddr_t)lop, M_NFSCLLOCK);
1486 	if (local)
1487 		newnfsstats.cllocallocks--;
1488 	else
1489 		newnfsstats.cllocks--;
1490 }
1491 
1492 /*
1493  * Clean out the state related to a delegation.
1494  */
1495 static void
1496 nfscl_cleandeleg(struct nfscldeleg *dp)
1497 {
1498 	struct nfsclowner *owp, *nowp;
1499 	struct nfsclopen *op;
1500 
1501 	LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) {
1502 		op = LIST_FIRST(&owp->nfsow_open);
1503 		if (op != NULL) {
1504 			if (LIST_NEXT(op, nfso_list) != NULL)
1505 				panic("nfscleandel");
1506 			nfscl_freeopen(op, 1);
1507 		}
1508 		nfscl_freeopenowner(owp, 1);
1509 	}
1510 	nfscl_freealllocks(&dp->nfsdl_lock, 1);
1511 }
1512 
1513 /*
1514  * Free a delegation.
1515  */
1516 static void
1517 nfscl_freedeleg(struct nfscldeleghead *hdp, struct nfscldeleg *dp)
1518 {
1519 
1520 	TAILQ_REMOVE(hdp, dp, nfsdl_list);
1521 	LIST_REMOVE(dp, nfsdl_hash);
1522 	FREE((caddr_t)dp, M_NFSCLDELEG);
1523 	newnfsstats.cldelegates--;
1524 	nfscl_delegcnt--;
1525 }
1526 
1527 /*
1528  * Free up all state related to this client structure.
1529  */
1530 static void
1531 nfscl_cleanclient(struct nfsclclient *clp)
1532 {
1533 	struct nfsclowner *owp, *nowp;
1534 	struct nfsclopen *op, *nop;
1535 
1536 	/* Now, all the OpenOwners, etc. */
1537 	LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) {
1538 		LIST_FOREACH_SAFE(op, &owp->nfsow_open, nfso_list, nop) {
1539 			nfscl_freeopen(op, 0);
1540 		}
1541 		nfscl_freeopenowner(owp, 0);
1542 	}
1543 }
1544 
1545 /*
1546  * Called when an NFSERR_EXPIRED is received from the server.
1547  */
1548 static void
1549 nfscl_expireclient(struct nfsclclient *clp, struct nfsmount *nmp,
1550     struct ucred *cred, NFSPROC_T *p)
1551 {
1552 	struct nfsclowner *owp, *nowp, *towp;
1553 	struct nfsclopen *op, *nop, *top;
1554 	struct nfscldeleg *dp, *ndp;
1555 	int ret, printed = 0;
1556 
1557 	/*
1558 	 * First, merge locally issued Opens into the list for the server.
1559 	 */
1560 	dp = TAILQ_FIRST(&clp->nfsc_deleg);
1561 	while (dp != NULL) {
1562 	    ndp = TAILQ_NEXT(dp, nfsdl_list);
1563 	    owp = LIST_FIRST(&dp->nfsdl_owner);
1564 	    while (owp != NULL) {
1565 		nowp = LIST_NEXT(owp, nfsow_list);
1566 		op = LIST_FIRST(&owp->nfsow_open);
1567 		if (op != NULL) {
1568 		    if (LIST_NEXT(op, nfso_list) != NULL)
1569 			panic("nfsclexp");
1570 		    LIST_FOREACH(towp, &clp->nfsc_owner, nfsow_list) {
1571 			if (!NFSBCMP(towp->nfsow_owner, owp->nfsow_owner,
1572 			    NFSV4CL_LOCKNAMELEN))
1573 			    break;
1574 		    }
1575 		    if (towp != NULL) {
1576 			/* Merge opens in */
1577 			LIST_FOREACH(top, &towp->nfsow_open, nfso_list) {
1578 			    if (top->nfso_fhlen == op->nfso_fhlen &&
1579 				!NFSBCMP(top->nfso_fh, op->nfso_fh,
1580 				 op->nfso_fhlen)) {
1581 				top->nfso_mode |= op->nfso_mode;
1582 				top->nfso_opencnt += op->nfso_opencnt;
1583 				break;
1584 			    }
1585 			}
1586 			if (top == NULL) {
1587 			    /* Just add the open to the owner list */
1588 			    LIST_REMOVE(op, nfso_list);
1589 			    op->nfso_own = towp;
1590 			    LIST_INSERT_HEAD(&towp->nfsow_open, op, nfso_list);
1591 			    newnfsstats.cllocalopens--;
1592 			    newnfsstats.clopens++;
1593 			}
1594 		    } else {
1595 			/* Just add the openowner to the client list */
1596 			LIST_REMOVE(owp, nfsow_list);
1597 			owp->nfsow_clp = clp;
1598 			LIST_INSERT_HEAD(&clp->nfsc_owner, owp, nfsow_list);
1599 			newnfsstats.cllocalopenowners--;
1600 			newnfsstats.clopenowners++;
1601 			newnfsstats.cllocalopens--;
1602 			newnfsstats.clopens++;
1603 		    }
1604 		}
1605 		owp = nowp;
1606 	    }
1607 	    if (!printed && !LIST_EMPTY(&dp->nfsdl_lock)) {
1608 		printed = 1;
1609 		printf("nfsv4 expired locks lost\n");
1610 	    }
1611 	    nfscl_cleandeleg(dp);
1612 	    nfscl_freedeleg(&clp->nfsc_deleg, dp);
1613 	    dp = ndp;
1614 	}
1615 	if (!TAILQ_EMPTY(&clp->nfsc_deleg))
1616 	    panic("nfsclexp");
1617 
1618 	/*
1619 	 * Now, try and reopen against the server.
1620 	 */
1621 	LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) {
1622 		owp->nfsow_seqid = 0;
1623 		LIST_FOREACH_SAFE(op, &owp->nfsow_open, nfso_list, nop) {
1624 			ret = nfscl_expireopen(clp, op, nmp, cred, p);
1625 			if (ret && !printed) {
1626 				printed = 1;
1627 				printf("nfsv4 expired locks lost\n");
1628 			}
1629 		}
1630 		if (LIST_EMPTY(&owp->nfsow_open))
1631 			nfscl_freeopenowner(owp, 0);
1632 	}
1633 }
1634 
1635 /*
1636  * This function must be called after the process represented by "own" has
1637  * exited. Must be called with CLSTATE lock held.
1638  */
1639 static void
1640 nfscl_cleanup_common(struct nfsclclient *clp, u_int8_t *own)
1641 {
1642 	struct nfsclowner *owp, *nowp;
1643 	struct nfscllockowner *lp, *nlp;
1644 	struct nfscldeleg *dp;
1645 
1646 	/* First, get rid of local locks on delegations. */
1647 	TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
1648 		LIST_FOREACH_SAFE(lp, &dp->nfsdl_lock, nfsl_list, nlp) {
1649 		    if (!NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) {
1650 			if ((lp->nfsl_rwlock.nfslock_lock & NFSV4LOCK_WANTED))
1651 			    panic("nfscllckw");
1652 			nfscl_freelockowner(lp, 1);
1653 		    }
1654 		}
1655 	}
1656 	owp = LIST_FIRST(&clp->nfsc_owner);
1657 	while (owp != NULL) {
1658 		nowp = LIST_NEXT(owp, nfsow_list);
1659 		if (!NFSBCMP(owp->nfsow_owner, own,
1660 		    NFSV4CL_LOCKNAMELEN)) {
1661 			/*
1662 			 * If there are children that haven't closed the
1663 			 * file descriptors yet, the opens will still be
1664 			 * here. For that case, let the renew thread clear
1665 			 * out the OpenOwner later.
1666 			 */
1667 			if (LIST_EMPTY(&owp->nfsow_open))
1668 				nfscl_freeopenowner(owp, 0);
1669 			else
1670 				owp->nfsow_defunct = 1;
1671 		}
1672 		owp = nowp;
1673 	}
1674 }
1675 
1676 /*
1677  * Find open/lock owners for processes that have exited.
1678  */
1679 static void
1680 nfscl_cleanupkext(struct nfsclclient *clp, struct nfscllockownerfhhead *lhp)
1681 {
1682 	struct nfsclowner *owp, *nowp;
1683 	struct nfsclopen *op;
1684 	struct nfscllockowner *lp, *nlp;
1685 
1686 	NFSPROCLISTLOCK();
1687 	NFSLOCKCLSTATE();
1688 	LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) {
1689 		LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
1690 			LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp) {
1691 				if (LIST_EMPTY(&lp->nfsl_lock))
1692 					nfscl_emptylockowner(lp, lhp);
1693 			}
1694 		}
1695 		if (nfscl_procdoesntexist(owp->nfsow_owner))
1696 			nfscl_cleanup_common(clp, owp->nfsow_owner);
1697 	}
1698 	NFSUNLOCKCLSTATE();
1699 	NFSPROCLISTUNLOCK();
1700 }
1701 
1702 /*
1703  * Take the empty lock owner and move it to the local lhp list if the
1704  * associated process no longer exists.
1705  */
1706 static void
1707 nfscl_emptylockowner(struct nfscllockowner *lp,
1708     struct nfscllockownerfhhead *lhp)
1709 {
1710 	struct nfscllockownerfh *lfhp, *mylfhp;
1711 	struct nfscllockowner *nlp;
1712 	int fnd_it;
1713 
1714 	/* If not a Posix lock owner, just return. */
1715 	if ((lp->nfsl_lockflags & F_POSIX) == 0)
1716 		return;
1717 
1718 	fnd_it = 0;
1719 	mylfhp = NULL;
1720 	/*
1721 	 * First, search to see if this lock owner is already in the list.
1722 	 * If it is, then the associated process no longer exists.
1723 	 */
1724 	SLIST_FOREACH(lfhp, lhp, nfslfh_list) {
1725 		if (lfhp->nfslfh_len == lp->nfsl_open->nfso_fhlen &&
1726 		    !NFSBCMP(lfhp->nfslfh_fh, lp->nfsl_open->nfso_fh,
1727 		    lfhp->nfslfh_len))
1728 			mylfhp = lfhp;
1729 		LIST_FOREACH(nlp, &lfhp->nfslfh_lock, nfsl_list)
1730 			if (!NFSBCMP(nlp->nfsl_owner, lp->nfsl_owner,
1731 			    NFSV4CL_LOCKNAMELEN))
1732 				fnd_it = 1;
1733 	}
1734 	/* If not found, check if process still exists. */
1735 	if (fnd_it == 0 && nfscl_procdoesntexist(lp->nfsl_owner) == 0)
1736 		return;
1737 
1738 	/* Move the lock owner over to the local list. */
1739 	if (mylfhp == NULL) {
1740 		mylfhp = malloc(sizeof(struct nfscllockownerfh), M_TEMP,
1741 		    M_NOWAIT);
1742 		if (mylfhp == NULL)
1743 			return;
1744 		mylfhp->nfslfh_len = lp->nfsl_open->nfso_fhlen;
1745 		NFSBCOPY(lp->nfsl_open->nfso_fh, mylfhp->nfslfh_fh,
1746 		    mylfhp->nfslfh_len);
1747 		LIST_INIT(&mylfhp->nfslfh_lock);
1748 		SLIST_INSERT_HEAD(lhp, mylfhp, nfslfh_list);
1749 	}
1750 	LIST_REMOVE(lp, nfsl_list);
1751 	LIST_INSERT_HEAD(&mylfhp->nfslfh_lock, lp, nfsl_list);
1752 }
1753 
1754 static int	fake_global;	/* Used to force visibility of MNTK_UNMOUNTF */
1755 /*
1756  * Called from nfs umount to free up the clientid.
1757  */
1758 APPLESTATIC void
1759 nfscl_umount(struct nfsmount *nmp, NFSPROC_T *p)
1760 {
1761 	struct nfsclclient *clp;
1762 	struct ucred *cred;
1763 	int igotlock;
1764 
1765 	/*
1766 	 * For the case that matters, this is the thread that set
1767 	 * MNTK_UNMOUNTF, so it will see it set. The code that follows is
1768 	 * done to ensure that any thread executing nfscl_getcl() after
1769 	 * this time, will see MNTK_UNMOUNTF set. nfscl_getcl() uses the
1770 	 * mutex for NFSLOCKCLSTATE(), so it is "m" for the following
1771 	 * explanation, courtesy of Alan Cox.
1772 	 * What follows is a snippet from Alan Cox's email at:
1773 	 * http://docs.FreeBSD.org/cgi/
1774 	 *     mid.cgi?BANLkTikR3d65zPHo9==08ZfJ2vmqZucEvw
1775 	 *
1776 	 * 1. Set MNTK_UNMOUNTF
1777 	 * 2. Acquire a standard FreeBSD mutex "m".
1778 	 * 3. Update some data structures.
1779 	 * 4. Release mutex "m".
1780 	 *
1781 	 * Then, other threads that acquire "m" after step 4 has occurred will
1782 	 * see MNTK_UNMOUNTF as set.  But, other threads that beat thread X to
1783 	 * step 2 may or may not see MNTK_UNMOUNTF as set.
1784 	 */
1785 	NFSLOCKCLSTATE();
1786 	if ((nmp->nm_mountp->mnt_kern_flag & MNTK_UNMOUNTF) != 0) {
1787 		fake_global++;
1788 		NFSUNLOCKCLSTATE();
1789 		NFSLOCKCLSTATE();
1790 	}
1791 
1792 	clp = nmp->nm_clp;
1793 	if (clp != NULL) {
1794 		if ((clp->nfsc_flags & NFSCLFLAGS_INITED) == 0)
1795 			panic("nfscl umount");
1796 
1797 		/*
1798 		 * First, handshake with the nfscl renew thread, to terminate
1799 		 * it.
1800 		 */
1801 		clp->nfsc_flags |= NFSCLFLAGS_UMOUNT;
1802 		while (clp->nfsc_flags & NFSCLFLAGS_HASTHREAD)
1803 			(void)mtx_sleep(clp, NFSCLSTATEMUTEXPTR, PWAIT,
1804 			    "nfsclumnt", hz);
1805 
1806 		/*
1807 		 * Now, get the exclusive lock on the client state, so
1808 		 * that no uses of the state are still in progress.
1809 		 */
1810 		do {
1811 			igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
1812 			    NFSCLSTATEMUTEXPTR, NULL);
1813 		} while (!igotlock);
1814 		NFSUNLOCKCLSTATE();
1815 
1816 		/*
1817 		 * Free up all the state. It will expire on the server, but
1818 		 * maybe we should do a SetClientId/SetClientIdConfirm so
1819 		 * the server throws it away?
1820 		 */
1821 		LIST_REMOVE(clp, nfsc_list);
1822 		nfscl_delegreturnall(clp, p);
1823 		cred = newnfs_getcred();
1824 		(void) nfsrpc_setclient(nmp, clp, cred, p);
1825 		nfscl_cleanclient(clp);
1826 		nmp->nm_clp = NULL;
1827 		NFSFREECRED(cred);
1828 		FREE((caddr_t)clp, M_NFSCLCLIENT);
1829 	} else
1830 		NFSUNLOCKCLSTATE();
1831 }
1832 
1833 /*
1834  * This function is called when a server replies with NFSERR_STALECLIENTID
1835  * or NFSERR_STALESTATEID. It traverses the clientid lists, doing Opens
1836  * and Locks with reclaim. If these fail, it deletes the corresponding state.
1837  */
1838 static void
1839 nfscl_recover(struct nfsclclient *clp, struct ucred *cred, NFSPROC_T *p)
1840 {
1841 	struct nfsclowner *owp, *nowp;
1842 	struct nfsclopen *op, *nop;
1843 	struct nfscllockowner *lp, *nlp;
1844 	struct nfscllock *lop, *nlop;
1845 	struct nfscldeleg *dp, *ndp, *tdp;
1846 	struct nfsmount *nmp;
1847 	struct ucred *tcred;
1848 	struct nfsclopenhead extra_open;
1849 	struct nfscldeleghead extra_deleg;
1850 	struct nfsreq *rep;
1851 	u_int64_t len;
1852 	u_int32_t delegtype = NFSV4OPEN_DELEGATEWRITE, mode;
1853 	int igotlock = 0, error, trycnt, firstlock, s;
1854 
1855 	/*
1856 	 * First, lock the client structure, so everyone else will
1857 	 * block when trying to use state.
1858 	 */
1859 	NFSLOCKCLSTATE();
1860 	clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG;
1861 	do {
1862 		igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
1863 		    NFSCLSTATEMUTEXPTR, NULL);
1864 	} while (!igotlock);
1865 	NFSUNLOCKCLSTATE();
1866 
1867 	nmp = clp->nfsc_nmp;
1868 	if (nmp == NULL)
1869 		panic("nfscl recover");
1870 	trycnt = 5;
1871 	do {
1872 		error = nfsrpc_setclient(nmp, clp, cred, p);
1873 	} while ((error == NFSERR_STALECLIENTID ||
1874 	     error == NFSERR_STALEDONTRECOVER) && --trycnt > 0);
1875 	if (error) {
1876 		nfscl_cleanclient(clp);
1877 		NFSLOCKCLSTATE();
1878 		clp->nfsc_flags &= ~(NFSCLFLAGS_HASCLIENTID |
1879 		    NFSCLFLAGS_RECOVER | NFSCLFLAGS_RECVRINPROG);
1880 		wakeup(&clp->nfsc_flags);
1881 		nfsv4_unlock(&clp->nfsc_lock, 0);
1882 		NFSUNLOCKCLSTATE();
1883 		return;
1884 	}
1885 	clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID;
1886 	clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER;
1887 
1888 	/*
1889 	 * Mark requests already queued on the server, so that they don't
1890 	 * initiate another recovery cycle. Any requests already in the
1891 	 * queue that handle state information will have the old stale
1892 	 * clientid/stateid and will get a NFSERR_STALESTATEID or
1893 	 * NFSERR_STALECLIENTID reply from the server. This will be
1894 	 * translated to NFSERR_STALEDONTRECOVER when R_DONTRECOVER is set.
1895 	 */
1896 	s = splsoftclock();
1897 	NFSLOCKREQ();
1898 	TAILQ_FOREACH(rep, &nfsd_reqq, r_chain) {
1899 		if (rep->r_nmp == nmp)
1900 			rep->r_flags |= R_DONTRECOVER;
1901 	}
1902 	NFSUNLOCKREQ();
1903 	splx(s);
1904 
1905 	/*
1906 	 * Now, mark all delegations "need reclaim".
1907 	 */
1908 	TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list)
1909 		dp->nfsdl_flags |= NFSCLDL_NEEDRECLAIM;
1910 
1911 	TAILQ_INIT(&extra_deleg);
1912 	LIST_INIT(&extra_open);
1913 	/*
1914 	 * Now traverse the state lists, doing Open and Lock Reclaims.
1915 	 */
1916 	tcred = newnfs_getcred();
1917 	owp = LIST_FIRST(&clp->nfsc_owner);
1918 	while (owp != NULL) {
1919 	    nowp = LIST_NEXT(owp, nfsow_list);
1920 	    owp->nfsow_seqid = 0;
1921 	    op = LIST_FIRST(&owp->nfsow_open);
1922 	    while (op != NULL) {
1923 		nop = LIST_NEXT(op, nfso_list);
1924 		if (error != NFSERR_NOGRACE) {
1925 		    /* Search for a delegation to reclaim with the open */
1926 		    TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
1927 			if (!(dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM))
1928 			    continue;
1929 			if ((dp->nfsdl_flags & NFSCLDL_WRITE)) {
1930 			    mode = NFSV4OPEN_ACCESSWRITE;
1931 			    delegtype = NFSV4OPEN_DELEGATEWRITE;
1932 			} else {
1933 			    mode = NFSV4OPEN_ACCESSREAD;
1934 			    delegtype = NFSV4OPEN_DELEGATEREAD;
1935 			}
1936 			if ((op->nfso_mode & mode) == mode &&
1937 			    op->nfso_fhlen == dp->nfsdl_fhlen &&
1938 			    !NFSBCMP(op->nfso_fh, dp->nfsdl_fh, op->nfso_fhlen))
1939 			    break;
1940 		    }
1941 		    ndp = dp;
1942 		    if (dp == NULL)
1943 			delegtype = NFSV4OPEN_DELEGATENONE;
1944 		    newnfs_copycred(&op->nfso_cred, tcred);
1945 		    error = nfscl_tryopen(nmp, NULL, op->nfso_fh,
1946 			op->nfso_fhlen, op->nfso_fh, op->nfso_fhlen,
1947 			op->nfso_mode, op, NULL, 0, &ndp, 1, delegtype,
1948 			tcred, p);
1949 		    if (!error) {
1950 			/* Handle any replied delegation */
1951 			if (ndp != NULL && ((ndp->nfsdl_flags & NFSCLDL_WRITE)
1952 			    || NFSMNT_RDONLY(nmp->nm_mountp))) {
1953 			    if ((ndp->nfsdl_flags & NFSCLDL_WRITE))
1954 				mode = NFSV4OPEN_ACCESSWRITE;
1955 			    else
1956 				mode = NFSV4OPEN_ACCESSREAD;
1957 			    TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
1958 				if (!(dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM))
1959 				    continue;
1960 				if ((op->nfso_mode & mode) == mode &&
1961 				    op->nfso_fhlen == dp->nfsdl_fhlen &&
1962 				    !NFSBCMP(op->nfso_fh, dp->nfsdl_fh,
1963 				    op->nfso_fhlen)) {
1964 				    dp->nfsdl_stateid = ndp->nfsdl_stateid;
1965 				    dp->nfsdl_sizelimit = ndp->nfsdl_sizelimit;
1966 				    dp->nfsdl_ace = ndp->nfsdl_ace;
1967 				    dp->nfsdl_change = ndp->nfsdl_change;
1968 				    dp->nfsdl_flags &= ~NFSCLDL_NEEDRECLAIM;
1969 				    if ((ndp->nfsdl_flags & NFSCLDL_RECALL))
1970 					dp->nfsdl_flags |= NFSCLDL_RECALL;
1971 				    FREE((caddr_t)ndp, M_NFSCLDELEG);
1972 				    ndp = NULL;
1973 				    break;
1974 				}
1975 			    }
1976 			}
1977 			if (ndp != NULL)
1978 			    TAILQ_INSERT_HEAD(&extra_deleg, ndp, nfsdl_list);
1979 
1980 			/* and reclaim all byte range locks */
1981 			lp = LIST_FIRST(&op->nfso_lock);
1982 			while (lp != NULL) {
1983 			    nlp = LIST_NEXT(lp, nfsl_list);
1984 			    lp->nfsl_seqid = 0;
1985 			    firstlock = 1;
1986 			    lop = LIST_FIRST(&lp->nfsl_lock);
1987 			    while (lop != NULL) {
1988 				nlop = LIST_NEXT(lop, nfslo_list);
1989 				if (lop->nfslo_end == NFS64BITSSET)
1990 				    len = NFS64BITSSET;
1991 				else
1992 				    len = lop->nfslo_end - lop->nfslo_first;
1993 				if (error != NFSERR_NOGRACE)
1994 				    error = nfscl_trylock(nmp, NULL,
1995 					op->nfso_fh, op->nfso_fhlen, lp,
1996 					firstlock, 1, lop->nfslo_first, len,
1997 					lop->nfslo_type, tcred, p);
1998 				if (error != 0)
1999 				    nfscl_freelock(lop, 0);
2000 				else
2001 				    firstlock = 0;
2002 				lop = nlop;
2003 			    }
2004 			    /* If no locks, but a lockowner, just delete it. */
2005 			    if (LIST_EMPTY(&lp->nfsl_lock))
2006 				nfscl_freelockowner(lp, 0);
2007 			    lp = nlp;
2008 			}
2009 		    } else {
2010 			nfscl_freeopen(op, 0);
2011 		    }
2012 		}
2013 		op = nop;
2014 	    }
2015 	    owp = nowp;
2016 	}
2017 
2018 	/*
2019 	 * Now, try and get any delegations not yet reclaimed by cobbling
2020 	 * to-gether an appropriate open.
2021 	 */
2022 	nowp = NULL;
2023 	dp = TAILQ_FIRST(&clp->nfsc_deleg);
2024 	while (dp != NULL) {
2025 	    ndp = TAILQ_NEXT(dp, nfsdl_list);
2026 	    if ((dp->nfsdl_flags & NFSCLDL_NEEDRECLAIM)) {
2027 		if (nowp == NULL) {
2028 		    MALLOC(nowp, struct nfsclowner *,
2029 			sizeof (struct nfsclowner), M_NFSCLOWNER, M_WAITOK);
2030 		    /*
2031 		     * Name must be as long an largest possible
2032 		     * NFSV4CL_LOCKNAMELEN. 12 for now.
2033 		     */
2034 		    NFSBCOPY("RECLAIMDELEG", nowp->nfsow_owner,
2035 			NFSV4CL_LOCKNAMELEN);
2036 		    LIST_INIT(&nowp->nfsow_open);
2037 		    nowp->nfsow_clp = clp;
2038 		    nowp->nfsow_seqid = 0;
2039 		    nowp->nfsow_defunct = 0;
2040 		    nfscl_lockinit(&nowp->nfsow_rwlock);
2041 		}
2042 		nop = NULL;
2043 		if (error != NFSERR_NOGRACE) {
2044 		    MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) +
2045 			dp->nfsdl_fhlen - 1, M_NFSCLOPEN, M_WAITOK);
2046 		    nop->nfso_own = nowp;
2047 		    if ((dp->nfsdl_flags & NFSCLDL_WRITE)) {
2048 			nop->nfso_mode = NFSV4OPEN_ACCESSWRITE;
2049 			delegtype = NFSV4OPEN_DELEGATEWRITE;
2050 		    } else {
2051 			nop->nfso_mode = NFSV4OPEN_ACCESSREAD;
2052 			delegtype = NFSV4OPEN_DELEGATEREAD;
2053 		    }
2054 		    nop->nfso_opencnt = 0;
2055 		    nop->nfso_posixlock = 1;
2056 		    nop->nfso_fhlen = dp->nfsdl_fhlen;
2057 		    NFSBCOPY(dp->nfsdl_fh, nop->nfso_fh, dp->nfsdl_fhlen);
2058 		    LIST_INIT(&nop->nfso_lock);
2059 		    nop->nfso_stateid.seqid = 0;
2060 		    nop->nfso_stateid.other[0] = 0;
2061 		    nop->nfso_stateid.other[1] = 0;
2062 		    nop->nfso_stateid.other[2] = 0;
2063 		    newnfs_copycred(&dp->nfsdl_cred, tcred);
2064 		    newnfs_copyincred(tcred, &nop->nfso_cred);
2065 		    tdp = NULL;
2066 		    error = nfscl_tryopen(nmp, NULL, nop->nfso_fh,
2067 			nop->nfso_fhlen, nop->nfso_fh, nop->nfso_fhlen,
2068 			nop->nfso_mode, nop, NULL, 0, &tdp, 1,
2069 			delegtype, tcred, p);
2070 		    if (tdp != NULL) {
2071 			if ((tdp->nfsdl_flags & NFSCLDL_WRITE))
2072 			    mode = NFSV4OPEN_ACCESSWRITE;
2073 			else
2074 			    mode = NFSV4OPEN_ACCESSREAD;
2075 			if ((nop->nfso_mode & mode) == mode &&
2076 			    nop->nfso_fhlen == tdp->nfsdl_fhlen &&
2077 			    !NFSBCMP(nop->nfso_fh, tdp->nfsdl_fh,
2078 			    nop->nfso_fhlen)) {
2079 			    dp->nfsdl_stateid = tdp->nfsdl_stateid;
2080 			    dp->nfsdl_sizelimit = tdp->nfsdl_sizelimit;
2081 			    dp->nfsdl_ace = tdp->nfsdl_ace;
2082 			    dp->nfsdl_change = tdp->nfsdl_change;
2083 			    dp->nfsdl_flags &= ~NFSCLDL_NEEDRECLAIM;
2084 			    if ((tdp->nfsdl_flags & NFSCLDL_RECALL))
2085 				dp->nfsdl_flags |= NFSCLDL_RECALL;
2086 			    FREE((caddr_t)tdp, M_NFSCLDELEG);
2087 			} else {
2088 			    TAILQ_INSERT_HEAD(&extra_deleg, tdp, nfsdl_list);
2089 			}
2090 		    }
2091 		}
2092 		if (error) {
2093 		    if (nop != NULL)
2094 			FREE((caddr_t)nop, M_NFSCLOPEN);
2095 		    /*
2096 		     * Couldn't reclaim it, so throw the state
2097 		     * away. Ouch!!
2098 		     */
2099 		    nfscl_cleandeleg(dp);
2100 		    nfscl_freedeleg(&clp->nfsc_deleg, dp);
2101 		} else {
2102 		    LIST_INSERT_HEAD(&extra_open, nop, nfso_list);
2103 		}
2104 	    }
2105 	    dp = ndp;
2106 	}
2107 
2108 	/*
2109 	 * Now, get rid of extra Opens and Delegations.
2110 	 */
2111 	LIST_FOREACH_SAFE(op, &extra_open, nfso_list, nop) {
2112 		do {
2113 			newnfs_copycred(&op->nfso_cred, tcred);
2114 			error = nfscl_tryclose(op, tcred, nmp, p);
2115 			if (error == NFSERR_GRACE)
2116 				(void) nfs_catnap(PZERO, error, "nfsexcls");
2117 		} while (error == NFSERR_GRACE);
2118 		LIST_REMOVE(op, nfso_list);
2119 		FREE((caddr_t)op, M_NFSCLOPEN);
2120 	}
2121 	if (nowp != NULL)
2122 		FREE((caddr_t)nowp, M_NFSCLOWNER);
2123 
2124 	TAILQ_FOREACH_SAFE(dp, &extra_deleg, nfsdl_list, ndp) {
2125 		do {
2126 			newnfs_copycred(&dp->nfsdl_cred, tcred);
2127 			error = nfscl_trydelegreturn(dp, tcred, nmp, p);
2128 			if (error == NFSERR_GRACE)
2129 				(void) nfs_catnap(PZERO, error, "nfsexdlg");
2130 		} while (error == NFSERR_GRACE);
2131 		TAILQ_REMOVE(&extra_deleg, dp, nfsdl_list);
2132 		FREE((caddr_t)dp, M_NFSCLDELEG);
2133 	}
2134 
2135 	NFSLOCKCLSTATE();
2136 	clp->nfsc_flags &= ~NFSCLFLAGS_RECVRINPROG;
2137 	wakeup(&clp->nfsc_flags);
2138 	nfsv4_unlock(&clp->nfsc_lock, 0);
2139 	NFSUNLOCKCLSTATE();
2140 	NFSFREECRED(tcred);
2141 }
2142 
2143 /*
2144  * This function is called when a server replies with NFSERR_EXPIRED.
2145  * It deletes all state for the client and does a fresh SetClientId/confirm.
2146  * XXX Someday it should post a signal to the process(es) that hold the
2147  * state, so they know that lock state has been lost.
2148  */
2149 APPLESTATIC int
2150 nfscl_hasexpired(struct nfsclclient *clp, u_int32_t clidrev, NFSPROC_T *p)
2151 {
2152 	struct nfsmount *nmp;
2153 	struct ucred *cred;
2154 	int igotlock = 0, error, trycnt;
2155 
2156 	/*
2157 	 * If the clientid has gone away or a new SetClientid has already
2158 	 * been done, just return ok.
2159 	 */
2160 	if (clp == NULL || clidrev != clp->nfsc_clientidrev)
2161 		return (0);
2162 
2163 	/*
2164 	 * First, lock the client structure, so everyone else will
2165 	 * block when trying to use state. Also, use NFSCLFLAGS_EXPIREIT so
2166 	 * that only one thread does the work.
2167 	 */
2168 	NFSLOCKCLSTATE();
2169 	clp->nfsc_flags |= NFSCLFLAGS_EXPIREIT;
2170 	do {
2171 		igotlock = nfsv4_lock(&clp->nfsc_lock, 1, NULL,
2172 		    NFSCLSTATEMUTEXPTR, NULL);
2173 	} while (!igotlock && (clp->nfsc_flags & NFSCLFLAGS_EXPIREIT));
2174 	if ((clp->nfsc_flags & NFSCLFLAGS_EXPIREIT) == 0) {
2175 		if (igotlock)
2176 			nfsv4_unlock(&clp->nfsc_lock, 0);
2177 		NFSUNLOCKCLSTATE();
2178 		return (0);
2179 	}
2180 	clp->nfsc_flags |= NFSCLFLAGS_RECVRINPROG;
2181 	NFSUNLOCKCLSTATE();
2182 
2183 	nmp = clp->nfsc_nmp;
2184 	if (nmp == NULL)
2185 		panic("nfscl expired");
2186 	cred = newnfs_getcred();
2187 	trycnt = 5;
2188 	do {
2189 		error = nfsrpc_setclient(nmp, clp, cred, p);
2190 	} while ((error == NFSERR_STALECLIENTID ||
2191 	     error == NFSERR_STALEDONTRECOVER) && --trycnt > 0);
2192 	if (error) {
2193 		/*
2194 		 * Clear out any state.
2195 		 */
2196 		nfscl_cleanclient(clp);
2197 		NFSLOCKCLSTATE();
2198 		clp->nfsc_flags &= ~(NFSCLFLAGS_HASCLIENTID |
2199 		    NFSCLFLAGS_RECOVER);
2200 	} else {
2201 		/*
2202 		 * Expire the state for the client.
2203 		 */
2204 		nfscl_expireclient(clp, nmp, cred, p);
2205 		NFSLOCKCLSTATE();
2206 		clp->nfsc_flags |= NFSCLFLAGS_HASCLIENTID;
2207 		clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER;
2208 	}
2209 	clp->nfsc_flags &= ~(NFSCLFLAGS_EXPIREIT | NFSCLFLAGS_RECVRINPROG);
2210 	wakeup(&clp->nfsc_flags);
2211 	nfsv4_unlock(&clp->nfsc_lock, 0);
2212 	NFSUNLOCKCLSTATE();
2213 	NFSFREECRED(cred);
2214 	return (error);
2215 }
2216 
2217 /*
2218  * This function inserts a lock in the list after insert_lop.
2219  */
2220 static void
2221 nfscl_insertlock(struct nfscllockowner *lp, struct nfscllock *new_lop,
2222     struct nfscllock *insert_lop, int local)
2223 {
2224 
2225 	if ((struct nfscllockowner *)insert_lop == lp)
2226 		LIST_INSERT_HEAD(&lp->nfsl_lock, new_lop, nfslo_list);
2227 	else
2228 		LIST_INSERT_AFTER(insert_lop, new_lop, nfslo_list);
2229 	if (local)
2230 		newnfsstats.cllocallocks++;
2231 	else
2232 		newnfsstats.cllocks++;
2233 }
2234 
2235 /*
2236  * This function updates the locking for a lock owner and given file. It
2237  * maintains a list of lock ranges ordered on increasing file offset that
2238  * are NFSCLLOCK_READ or NFSCLLOCK_WRITE and non-overlapping (aka POSIX style).
2239  * It always adds new_lop to the list and sometimes uses the one pointed
2240  * at by other_lopp.
2241  * Returns 1 if the locks were modified, 0 otherwise.
2242  */
2243 static int
2244 nfscl_updatelock(struct nfscllockowner *lp, struct nfscllock **new_lopp,
2245     struct nfscllock **other_lopp, int local)
2246 {
2247 	struct nfscllock *new_lop = *new_lopp;
2248 	struct nfscllock *lop, *tlop, *ilop;
2249 	struct nfscllock *other_lop;
2250 	int unlock = 0, modified = 0;
2251 	u_int64_t tmp;
2252 
2253 	/*
2254 	 * Work down the list until the lock is merged.
2255 	 */
2256 	if (new_lop->nfslo_type == F_UNLCK)
2257 		unlock = 1;
2258 	ilop = (struct nfscllock *)lp;
2259 	lop = LIST_FIRST(&lp->nfsl_lock);
2260 	while (lop != NULL) {
2261 	    /*
2262 	     * Only check locks for this file that aren't before the start of
2263 	     * new lock's range.
2264 	     */
2265 	    if (lop->nfslo_end >= new_lop->nfslo_first) {
2266 		if (new_lop->nfslo_end < lop->nfslo_first) {
2267 		    /*
2268 		     * If the new lock ends before the start of the
2269 		     * current lock's range, no merge, just insert
2270 		     * the new lock.
2271 		     */
2272 		    break;
2273 		}
2274 		if (new_lop->nfslo_type == lop->nfslo_type ||
2275 		    (new_lop->nfslo_first <= lop->nfslo_first &&
2276 		     new_lop->nfslo_end >= lop->nfslo_end)) {
2277 		    /*
2278 		     * This lock can be absorbed by the new lock/unlock.
2279 		     * This happens when it covers the entire range
2280 		     * of the old lock or is contiguous
2281 		     * with the old lock and is of the same type or an
2282 		     * unlock.
2283 		     */
2284 		    if (new_lop->nfslo_type != lop->nfslo_type ||
2285 			new_lop->nfslo_first != lop->nfslo_first ||
2286 			new_lop->nfslo_end != lop->nfslo_end)
2287 			modified = 1;
2288 		    if (lop->nfslo_first < new_lop->nfslo_first)
2289 			new_lop->nfslo_first = lop->nfslo_first;
2290 		    if (lop->nfslo_end > new_lop->nfslo_end)
2291 			new_lop->nfslo_end = lop->nfslo_end;
2292 		    tlop = lop;
2293 		    lop = LIST_NEXT(lop, nfslo_list);
2294 		    nfscl_freelock(tlop, local);
2295 		    continue;
2296 		}
2297 
2298 		/*
2299 		 * All these cases are for contiguous locks that are not the
2300 		 * same type, so they can't be merged.
2301 		 */
2302 		if (new_lop->nfslo_first <= lop->nfslo_first) {
2303 		    /*
2304 		     * This case is where the new lock overlaps with the
2305 		     * first part of the old lock. Move the start of the
2306 		     * old lock to just past the end of the new lock. The
2307 		     * new lock will be inserted in front of the old, since
2308 		     * ilop hasn't been updated. (We are done now.)
2309 		     */
2310 		    if (lop->nfslo_first != new_lop->nfslo_end) {
2311 			lop->nfslo_first = new_lop->nfslo_end;
2312 			modified = 1;
2313 		    }
2314 		    break;
2315 		}
2316 		if (new_lop->nfslo_end >= lop->nfslo_end) {
2317 		    /*
2318 		     * This case is where the new lock overlaps with the
2319 		     * end of the old lock's range. Move the old lock's
2320 		     * end to just before the new lock's first and insert
2321 		     * the new lock after the old lock.
2322 		     * Might not be done yet, since the new lock could
2323 		     * overlap further locks with higher ranges.
2324 		     */
2325 		    if (lop->nfslo_end != new_lop->nfslo_first) {
2326 			lop->nfslo_end = new_lop->nfslo_first;
2327 			modified = 1;
2328 		    }
2329 		    ilop = lop;
2330 		    lop = LIST_NEXT(lop, nfslo_list);
2331 		    continue;
2332 		}
2333 		/*
2334 		 * The final case is where the new lock's range is in the
2335 		 * middle of the current lock's and splits the current lock
2336 		 * up. Use *other_lopp to handle the second part of the
2337 		 * split old lock range. (We are done now.)
2338 		 * For unlock, we use new_lop as other_lop and tmp, since
2339 		 * other_lop and new_lop are the same for this case.
2340 		 * We noted the unlock case above, so we don't need
2341 		 * new_lop->nfslo_type any longer.
2342 		 */
2343 		tmp = new_lop->nfslo_first;
2344 		if (unlock) {
2345 		    other_lop = new_lop;
2346 		    *new_lopp = NULL;
2347 		} else {
2348 		    other_lop = *other_lopp;
2349 		    *other_lopp = NULL;
2350 		}
2351 		other_lop->nfslo_first = new_lop->nfslo_end;
2352 		other_lop->nfslo_end = lop->nfslo_end;
2353 		other_lop->nfslo_type = lop->nfslo_type;
2354 		lop->nfslo_end = tmp;
2355 		nfscl_insertlock(lp, other_lop, lop, local);
2356 		ilop = lop;
2357 		modified = 1;
2358 		break;
2359 	    }
2360 	    ilop = lop;
2361 	    lop = LIST_NEXT(lop, nfslo_list);
2362 	    if (lop == NULL)
2363 		break;
2364 	}
2365 
2366 	/*
2367 	 * Insert the new lock in the list at the appropriate place.
2368 	 */
2369 	if (!unlock) {
2370 		nfscl_insertlock(lp, new_lop, ilop, local);
2371 		*new_lopp = NULL;
2372 		modified = 1;
2373 	}
2374 	return (modified);
2375 }
2376 
2377 /*
2378  * This function must be run as a kernel thread.
2379  * It does Renew Ops and recovery, when required.
2380  */
2381 APPLESTATIC void
2382 nfscl_renewthread(struct nfsclclient *clp, NFSPROC_T *p)
2383 {
2384 	struct nfsclowner *owp, *nowp;
2385 	struct nfsclopen *op;
2386 	struct nfscllockowner *lp, *nlp;
2387 	struct nfscldeleghead dh;
2388 	struct nfscldeleg *dp, *ndp;
2389 	struct ucred *cred;
2390 	u_int32_t clidrev;
2391 	int error, cbpathdown, islept, igotlock, ret, clearok;
2392 	uint32_t recover_done_time = 0;
2393 	struct timespec mytime;
2394 	static time_t prevsec = 0;
2395 	struct nfscllockownerfh *lfhp, *nlfhp;
2396 	struct nfscllockownerfhhead lfh;
2397 
2398 	cred = newnfs_getcred();
2399 	NFSLOCKCLSTATE();
2400 	clp->nfsc_flags |= NFSCLFLAGS_HASTHREAD;
2401 	NFSUNLOCKCLSTATE();
2402 	for(;;) {
2403 		newnfs_setroot(cred);
2404 		cbpathdown = 0;
2405 		if (clp->nfsc_flags & NFSCLFLAGS_RECOVER) {
2406 			/*
2407 			 * Only allow one recover within 1/2 of the lease
2408 			 * duration (nfsc_renew).
2409 			 */
2410 			if (recover_done_time < NFSD_MONOSEC) {
2411 				recover_done_time = NFSD_MONOSEC +
2412 				    clp->nfsc_renew;
2413 				nfscl_recover(clp, cred, p);
2414 			} else {
2415 				NFSLOCKCLSTATE();
2416 				clp->nfsc_flags &= ~NFSCLFLAGS_RECOVER;
2417 				NFSUNLOCKCLSTATE();
2418 			}
2419 		}
2420 		if (clp->nfsc_expire <= NFSD_MONOSEC &&
2421 		    (clp->nfsc_flags & NFSCLFLAGS_HASCLIENTID)) {
2422 			clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
2423 			clidrev = clp->nfsc_clientidrev;
2424 			error = nfsrpc_renew(clp, cred, p);
2425 			if (error == NFSERR_CBPATHDOWN)
2426 			    cbpathdown = 1;
2427 			else if (error == NFSERR_STALECLIENTID) {
2428 			    NFSLOCKCLSTATE();
2429 			    clp->nfsc_flags |= NFSCLFLAGS_RECOVER;
2430 			    NFSUNLOCKCLSTATE();
2431 			} else if (error == NFSERR_EXPIRED)
2432 			    (void) nfscl_hasexpired(clp, clidrev, p);
2433 		}
2434 
2435 		TAILQ_INIT(&dh);
2436 		NFSLOCKCLSTATE();
2437 		if (cbpathdown)
2438 			/* It's a Total Recall! */
2439 			nfscl_totalrecall(clp);
2440 
2441 		/*
2442 		 * Now, handle defunct owners.
2443 		 */
2444 		LIST_FOREACH_SAFE(owp, &clp->nfsc_owner, nfsow_list, nowp) {
2445 			if (LIST_EMPTY(&owp->nfsow_open)) {
2446 				if (owp->nfsow_defunct != 0)
2447 					nfscl_freeopenowner(owp, 0);
2448 			}
2449 		}
2450 
2451 		/*
2452 		 * Do the recall on any delegations. To avoid trouble, always
2453 		 * come back up here after having slept.
2454 		 */
2455 		igotlock = 0;
2456 tryagain:
2457 		dp = TAILQ_FIRST(&clp->nfsc_deleg);
2458 		while (dp != NULL) {
2459 			ndp = TAILQ_NEXT(dp, nfsdl_list);
2460 			if ((dp->nfsdl_flags & NFSCLDL_RECALL)) {
2461 				/*
2462 				 * Wait for outstanding I/O ops to be done.
2463 				 */
2464 				if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
2465 				    if (igotlock) {
2466 					nfsv4_unlock(&clp->nfsc_lock, 0);
2467 					igotlock = 0;
2468 				    }
2469 				    dp->nfsdl_rwlock.nfslock_lock |=
2470 					NFSV4LOCK_WANTED;
2471 				    (void) nfsmsleep(&dp->nfsdl_rwlock,
2472 					NFSCLSTATEMUTEXPTR, PZERO, "nfscld",
2473 					NULL);
2474 				    goto tryagain;
2475 				}
2476 				while (!igotlock) {
2477 				    igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
2478 					&islept, NFSCLSTATEMUTEXPTR, NULL);
2479 				    if (islept)
2480 					goto tryagain;
2481 				}
2482 				NFSUNLOCKCLSTATE();
2483 				newnfs_copycred(&dp->nfsdl_cred, cred);
2484 				ret = nfscl_recalldeleg(clp, clp->nfsc_nmp, dp,
2485 				    NULL, cred, p, 1);
2486 				if (!ret) {
2487 				    nfscl_cleandeleg(dp);
2488 				    TAILQ_REMOVE(&clp->nfsc_deleg, dp,
2489 					nfsdl_list);
2490 				    LIST_REMOVE(dp, nfsdl_hash);
2491 				    TAILQ_INSERT_HEAD(&dh, dp, nfsdl_list);
2492 				    nfscl_delegcnt--;
2493 				    newnfsstats.cldelegates--;
2494 				}
2495 				NFSLOCKCLSTATE();
2496 			}
2497 			dp = ndp;
2498 		}
2499 
2500 		/*
2501 		 * Clear out old delegations, if we are above the high water
2502 		 * mark. Only clear out ones with no state related to them.
2503 		 * The tailq list is in LRU order.
2504 		 */
2505 		dp = TAILQ_LAST(&clp->nfsc_deleg, nfscldeleghead);
2506 		while (nfscl_delegcnt > nfscl_deleghighwater && dp != NULL) {
2507 		    ndp = TAILQ_PREV(dp, nfscldeleghead, nfsdl_list);
2508 		    if (dp->nfsdl_rwlock.nfslock_usecnt == 0 &&
2509 			dp->nfsdl_rwlock.nfslock_lock == 0 &&
2510 			dp->nfsdl_timestamp < NFSD_MONOSEC &&
2511 			(dp->nfsdl_flags & (NFSCLDL_RECALL | NFSCLDL_ZAPPED |
2512 			  NFSCLDL_NEEDRECLAIM | NFSCLDL_DELEGRET)) == 0) {
2513 			clearok = 1;
2514 			LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
2515 			    op = LIST_FIRST(&owp->nfsow_open);
2516 			    if (op != NULL) {
2517 				clearok = 0;
2518 				break;
2519 			    }
2520 			}
2521 			if (clearok) {
2522 			    LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
2523 				if (!LIST_EMPTY(&lp->nfsl_lock)) {
2524 				    clearok = 0;
2525 				    break;
2526 				}
2527 			    }
2528 			}
2529 			if (clearok) {
2530 			    TAILQ_REMOVE(&clp->nfsc_deleg, dp, nfsdl_list);
2531 			    LIST_REMOVE(dp, nfsdl_hash);
2532 			    TAILQ_INSERT_HEAD(&dh, dp, nfsdl_list);
2533 			    nfscl_delegcnt--;
2534 			    newnfsstats.cldelegates--;
2535 			}
2536 		    }
2537 		    dp = ndp;
2538 		}
2539 		if (igotlock)
2540 			nfsv4_unlock(&clp->nfsc_lock, 0);
2541 		NFSUNLOCKCLSTATE();
2542 
2543 		/*
2544 		 * Delegreturn any delegations cleaned out or recalled.
2545 		 */
2546 		TAILQ_FOREACH_SAFE(dp, &dh, nfsdl_list, ndp) {
2547 			newnfs_copycred(&dp->nfsdl_cred, cred);
2548 			(void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p);
2549 			TAILQ_REMOVE(&dh, dp, nfsdl_list);
2550 			FREE((caddr_t)dp, M_NFSCLDELEG);
2551 		}
2552 
2553 		SLIST_INIT(&lfh);
2554 		/*
2555 		 * Call nfscl_cleanupkext() once per second to check for
2556 		 * open/lock owners where the process has exited.
2557 		 */
2558 		NFSGETNANOTIME(&mytime);
2559 		if (prevsec != mytime.tv_sec) {
2560 			prevsec = mytime.tv_sec;
2561 			nfscl_cleanupkext(clp, &lfh);
2562 		}
2563 
2564 		/*
2565 		 * Do a ReleaseLockOwner for all lock owners where the
2566 		 * associated process no longer exists, as found by
2567 		 * nfscl_cleanupkext().
2568 		 */
2569 		newnfs_setroot(cred);
2570 		SLIST_FOREACH_SAFE(lfhp, &lfh, nfslfh_list, nlfhp) {
2571 			LIST_FOREACH_SAFE(lp, &lfhp->nfslfh_lock, nfsl_list,
2572 			    nlp) {
2573 				(void)nfsrpc_rellockown(clp->nfsc_nmp, lp,
2574 				    lfhp->nfslfh_fh, lfhp->nfslfh_len, cred,
2575 				    p);
2576 				nfscl_freelockowner(lp, 0);
2577 			}
2578 			free(lfhp, M_TEMP);
2579 		}
2580 		SLIST_INIT(&lfh);
2581 
2582 		NFSLOCKCLSTATE();
2583 		if ((clp->nfsc_flags & NFSCLFLAGS_RECOVER) == 0)
2584 			(void)mtx_sleep(clp, NFSCLSTATEMUTEXPTR, PWAIT, "nfscl",
2585 			    hz);
2586 		if (clp->nfsc_flags & NFSCLFLAGS_UMOUNT) {
2587 			clp->nfsc_flags &= ~NFSCLFLAGS_HASTHREAD;
2588 			NFSUNLOCKCLSTATE();
2589 			NFSFREECRED(cred);
2590 			wakeup((caddr_t)clp);
2591 			return;
2592 		}
2593 		NFSUNLOCKCLSTATE();
2594 	}
2595 }
2596 
2597 /*
2598  * Initiate state recovery. Called when NFSERR_STALECLIENTID or
2599  * NFSERR_STALESTATEID is received.
2600  */
2601 APPLESTATIC void
2602 nfscl_initiate_recovery(struct nfsclclient *clp)
2603 {
2604 
2605 	if (clp == NULL)
2606 		return;
2607 	NFSLOCKCLSTATE();
2608 	clp->nfsc_flags |= NFSCLFLAGS_RECOVER;
2609 	NFSUNLOCKCLSTATE();
2610 	wakeup((caddr_t)clp);
2611 }
2612 
2613 /*
2614  * Dump out the state stuff for debugging.
2615  */
2616 APPLESTATIC void
2617 nfscl_dumpstate(struct nfsmount *nmp, int openowner, int opens,
2618     int lockowner, int locks)
2619 {
2620 	struct nfsclclient *clp;
2621 	struct nfsclowner *owp;
2622 	struct nfsclopen *op;
2623 	struct nfscllockowner *lp;
2624 	struct nfscllock *lop;
2625 	struct nfscldeleg *dp;
2626 
2627 	clp = nmp->nm_clp;
2628 	if (clp == NULL) {
2629 		printf("nfscl dumpstate NULL clp\n");
2630 		return;
2631 	}
2632 	NFSLOCKCLSTATE();
2633 	TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
2634 	  LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
2635 	    if (openowner && !LIST_EMPTY(&owp->nfsow_open))
2636 		printf("owner=0x%x 0x%x 0x%x 0x%x seqid=%d\n",
2637 		    owp->nfsow_owner[0], owp->nfsow_owner[1],
2638 		    owp->nfsow_owner[2], owp->nfsow_owner[3],
2639 		    owp->nfsow_seqid);
2640 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
2641 		if (opens)
2642 		    printf("open st=0x%x 0x%x 0x%x cnt=%d fh12=0x%x\n",
2643 			op->nfso_stateid.other[0], op->nfso_stateid.other[1],
2644 			op->nfso_stateid.other[2], op->nfso_opencnt,
2645 			op->nfso_fh[12]);
2646 		LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
2647 		    if (lockowner)
2648 			printf("lckown=0x%x 0x%x 0x%x 0x%x seqid=%d st=0x%x 0x%x 0x%x\n",
2649 			    lp->nfsl_owner[0], lp->nfsl_owner[1],
2650 			    lp->nfsl_owner[2], lp->nfsl_owner[3],
2651 			    lp->nfsl_seqid,
2652 			    lp->nfsl_stateid.other[0], lp->nfsl_stateid.other[1],
2653 			    lp->nfsl_stateid.other[2]);
2654 		    LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
2655 			if (locks)
2656 #ifdef __FreeBSD__
2657 			    printf("lck typ=%d fst=%ju end=%ju\n",
2658 				lop->nfslo_type, (intmax_t)lop->nfslo_first,
2659 				(intmax_t)lop->nfslo_end);
2660 #else
2661 			    printf("lck typ=%d fst=%qd end=%qd\n",
2662 				lop->nfslo_type, lop->nfslo_first,
2663 				lop->nfslo_end);
2664 #endif
2665 		    }
2666 		}
2667 	    }
2668 	  }
2669 	}
2670 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
2671 	    if (openowner && !LIST_EMPTY(&owp->nfsow_open))
2672 		printf("owner=0x%x 0x%x 0x%x 0x%x seqid=%d\n",
2673 		    owp->nfsow_owner[0], owp->nfsow_owner[1],
2674 		    owp->nfsow_owner[2], owp->nfsow_owner[3],
2675 		    owp->nfsow_seqid);
2676 	    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
2677 		if (opens)
2678 		    printf("open st=0x%x 0x%x 0x%x cnt=%d fh12=0x%x\n",
2679 			op->nfso_stateid.other[0], op->nfso_stateid.other[1],
2680 			op->nfso_stateid.other[2], op->nfso_opencnt,
2681 			op->nfso_fh[12]);
2682 		LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
2683 		    if (lockowner)
2684 			printf("lckown=0x%x 0x%x 0x%x 0x%x seqid=%d st=0x%x 0x%x 0x%x\n",
2685 			    lp->nfsl_owner[0], lp->nfsl_owner[1],
2686 			    lp->nfsl_owner[2], lp->nfsl_owner[3],
2687 			    lp->nfsl_seqid,
2688 			    lp->nfsl_stateid.other[0], lp->nfsl_stateid.other[1],
2689 			    lp->nfsl_stateid.other[2]);
2690 		    LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
2691 			if (locks)
2692 #ifdef __FreeBSD__
2693 			    printf("lck typ=%d fst=%ju end=%ju\n",
2694 				lop->nfslo_type, (intmax_t)lop->nfslo_first,
2695 				(intmax_t)lop->nfslo_end);
2696 #else
2697 			    printf("lck typ=%d fst=%qd end=%qd\n",
2698 				lop->nfslo_type, lop->nfslo_first,
2699 				lop->nfslo_end);
2700 #endif
2701 		    }
2702 		}
2703 	    }
2704 	}
2705 	NFSUNLOCKCLSTATE();
2706 }
2707 
2708 /*
2709  * Check for duplicate open owners and opens.
2710  * (Only used as a diagnostic aid.)
2711  */
2712 APPLESTATIC void
2713 nfscl_dupopen(vnode_t vp, int dupopens)
2714 {
2715 	struct nfsclclient *clp;
2716 	struct nfsclowner *owp, *owp2;
2717 	struct nfsclopen *op, *op2;
2718 	struct nfsfh *nfhp;
2719 
2720 	clp = VFSTONFS(vnode_mount(vp))->nm_clp;
2721 	if (clp == NULL) {
2722 		printf("nfscl dupopen NULL clp\n");
2723 		return;
2724 	}
2725 	nfhp = VTONFS(vp)->n_fhp;
2726 	NFSLOCKCLSTATE();
2727 
2728 	/*
2729 	 * First, search for duplicate owners.
2730 	 * These should never happen!
2731 	 */
2732 	LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) {
2733 	    LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
2734 		if (owp != owp2 &&
2735 		    !NFSBCMP(owp->nfsow_owner, owp2->nfsow_owner,
2736 		    NFSV4CL_LOCKNAMELEN)) {
2737 			NFSUNLOCKCLSTATE();
2738 			printf("DUP OWNER\n");
2739 			nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 0, 0);
2740 			return;
2741 		}
2742 	    }
2743 	}
2744 
2745 	/*
2746 	 * Now, search for duplicate stateids.
2747 	 * These shouldn't happen, either.
2748 	 */
2749 	LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) {
2750 	    LIST_FOREACH(op2, &owp2->nfsow_open, nfso_list) {
2751 		LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
2752 		    LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
2753 			if (op != op2 &&
2754 			    (op->nfso_stateid.other[0] != 0 ||
2755 			     op->nfso_stateid.other[1] != 0 ||
2756 			     op->nfso_stateid.other[2] != 0) &&
2757 			    op->nfso_stateid.other[0] == op2->nfso_stateid.other[0] &&
2758 			    op->nfso_stateid.other[1] == op2->nfso_stateid.other[1] &&
2759 			    op->nfso_stateid.other[2] == op2->nfso_stateid.other[2]) {
2760 			    NFSUNLOCKCLSTATE();
2761 			    printf("DUP STATEID\n");
2762 			    nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1, 0,
2763 				0);
2764 			    return;
2765 			}
2766 		    }
2767 		}
2768 	    }
2769 	}
2770 
2771 	/*
2772 	 * Now search for duplicate opens.
2773 	 * Duplicate opens for the same owner
2774 	 * should never occur. Other duplicates are
2775 	 * possible and are checked for if "dupopens"
2776 	 * is true.
2777 	 */
2778 	LIST_FOREACH(owp2, &clp->nfsc_owner, nfsow_list) {
2779 	    LIST_FOREACH(op2, &owp2->nfsow_open, nfso_list) {
2780 		if (nfhp->nfh_len == op2->nfso_fhlen &&
2781 		    !NFSBCMP(nfhp->nfh_fh, op2->nfso_fh, nfhp->nfh_len)) {
2782 		    LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
2783 			LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
2784 			    if (op != op2 && nfhp->nfh_len == op->nfso_fhlen &&
2785 				!NFSBCMP(nfhp->nfh_fh, op->nfso_fh, nfhp->nfh_len) &&
2786 				(!NFSBCMP(op->nfso_own->nfsow_owner,
2787 				 op2->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN) ||
2788 				 dupopens)) {
2789 				if (!NFSBCMP(op->nfso_own->nfsow_owner,
2790 				    op2->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN)) {
2791 				    NFSUNLOCKCLSTATE();
2792 				    printf("BADDUP OPEN\n");
2793 				} else {
2794 				    NFSUNLOCKCLSTATE();
2795 				    printf("DUP OPEN\n");
2796 				}
2797 				nfscl_dumpstate(VFSTONFS(vnode_mount(vp)), 1, 1,
2798 				    0, 0);
2799 				return;
2800 			    }
2801 			}
2802 		    }
2803 		}
2804 	    }
2805 	}
2806 	NFSUNLOCKCLSTATE();
2807 }
2808 
2809 /*
2810  * During close, find an open that needs to be dereferenced and
2811  * dereference it. If there are no more opens for this file,
2812  * log a message to that effect.
2813  * Opens aren't actually Close'd until VOP_INACTIVE() is performed
2814  * on the file's vnode.
2815  * This is the safe way, since it is difficult to identify
2816  * which open the close is for and I/O can be performed after the
2817  * close(2) system call when a file is mmap'd.
2818  * If it returns 0 for success, there will be a referenced
2819  * clp returned via clpp.
2820  */
2821 APPLESTATIC int
2822 nfscl_getclose(vnode_t vp, struct nfsclclient **clpp)
2823 {
2824 	struct nfsclclient *clp;
2825 	struct nfsclowner *owp;
2826 	struct nfsclopen *op;
2827 	struct nfscldeleg *dp;
2828 	struct nfsfh *nfhp;
2829 	int error, notdecr;
2830 
2831 	error = nfscl_getcl(vp, NULL, NULL, &clp);
2832 	if (error)
2833 		return (error);
2834 	*clpp = clp;
2835 
2836 	nfhp = VTONFS(vp)->n_fhp;
2837 	notdecr = 1;
2838 	NFSLOCKCLSTATE();
2839 	/*
2840 	 * First, look for one under a delegation that was locally issued
2841 	 * and just decrement the opencnt for it. Since all my Opens against
2842 	 * the server are DENY_NONE, I don't see a problem with hanging
2843 	 * onto them. (It is much easier to use one of the extant Opens
2844 	 * that I already have on the server when a Delegation is recalled
2845 	 * than to do fresh Opens.) Someday, I might need to rethink this, but.
2846 	 */
2847 	dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len);
2848 	if (dp != NULL) {
2849 		LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
2850 			op = LIST_FIRST(&owp->nfsow_open);
2851 			if (op != NULL) {
2852 				/*
2853 				 * Since a delegation is for a file, there
2854 				 * should never be more than one open for
2855 				 * each openowner.
2856 				 */
2857 				if (LIST_NEXT(op, nfso_list) != NULL)
2858 					panic("nfscdeleg opens");
2859 				if (notdecr && op->nfso_opencnt > 0) {
2860 					notdecr = 0;
2861 					op->nfso_opencnt--;
2862 					break;
2863 				}
2864 			}
2865 		}
2866 	}
2867 
2868 	/* Now process the opens against the server. */
2869 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
2870 		LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
2871 			if (op->nfso_fhlen == nfhp->nfh_len &&
2872 			    !NFSBCMP(op->nfso_fh, nfhp->nfh_fh,
2873 			    nfhp->nfh_len)) {
2874 				/* Found an open, decrement cnt if possible */
2875 				if (notdecr && op->nfso_opencnt > 0) {
2876 					notdecr = 0;
2877 					op->nfso_opencnt--;
2878 				}
2879 				/*
2880 				 * There are more opens, so just return.
2881 				 */
2882 				if (op->nfso_opencnt > 0) {
2883 					NFSUNLOCKCLSTATE();
2884 					return (0);
2885 				}
2886 			}
2887 		}
2888 	}
2889 	NFSUNLOCKCLSTATE();
2890 	if (notdecr)
2891 		printf("nfscl: never fnd open\n");
2892 	return (0);
2893 }
2894 
2895 APPLESTATIC int
2896 nfscl_doclose(vnode_t vp, struct nfsclclient **clpp, NFSPROC_T *p)
2897 {
2898 	struct nfsclclient *clp;
2899 	struct nfsclowner *owp, *nowp;
2900 	struct nfsclopen *op;
2901 	struct nfscldeleg *dp;
2902 	struct nfsfh *nfhp;
2903 	int error;
2904 
2905 	error = nfscl_getcl(vp, NULL, NULL, &clp);
2906 	if (error)
2907 		return (error);
2908 	*clpp = clp;
2909 
2910 	nfhp = VTONFS(vp)->n_fhp;
2911 	NFSLOCKCLSTATE();
2912 	/*
2913 	 * First get rid of the local Open structures, which should be no
2914 	 * longer in use.
2915 	 */
2916 	dp = nfscl_finddeleg(clp, nfhp->nfh_fh, nfhp->nfh_len);
2917 	if (dp != NULL) {
2918 		LIST_FOREACH_SAFE(owp, &dp->nfsdl_owner, nfsow_list, nowp) {
2919 			op = LIST_FIRST(&owp->nfsow_open);
2920 			if (op != NULL) {
2921 				KASSERT((op->nfso_opencnt == 0),
2922 				    ("nfscl: bad open cnt on deleg"));
2923 				nfscl_freeopen(op, 1);
2924 			}
2925 			nfscl_freeopenowner(owp, 1);
2926 		}
2927 	}
2928 
2929 	/* Now process the opens against the server. */
2930 lookformore:
2931 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
2932 		op = LIST_FIRST(&owp->nfsow_open);
2933 		while (op != NULL) {
2934 			if (op->nfso_fhlen == nfhp->nfh_len &&
2935 			    !NFSBCMP(op->nfso_fh, nfhp->nfh_fh,
2936 			    nfhp->nfh_len)) {
2937 				/* Found an open, close it. */
2938 				KASSERT((op->nfso_opencnt == 0),
2939 				    ("nfscl: bad open cnt on server"));
2940 				NFSUNLOCKCLSTATE();
2941 				nfsrpc_doclose(VFSTONFS(vnode_mount(vp)), op,
2942 				    p);
2943 				NFSLOCKCLSTATE();
2944 				goto lookformore;
2945 			}
2946 			op = LIST_NEXT(op, nfso_list);
2947 		}
2948 	}
2949 	NFSUNLOCKCLSTATE();
2950 	return (0);
2951 }
2952 
2953 /*
2954  * Return all delegations on this client.
2955  * (Must be called with client sleep lock.)
2956  */
2957 static void
2958 nfscl_delegreturnall(struct nfsclclient *clp, NFSPROC_T *p)
2959 {
2960 	struct nfscldeleg *dp, *ndp;
2961 	struct ucred *cred;
2962 
2963 	cred = newnfs_getcred();
2964 	TAILQ_FOREACH_SAFE(dp, &clp->nfsc_deleg, nfsdl_list, ndp) {
2965 		nfscl_cleandeleg(dp);
2966 		(void) nfscl_trydelegreturn(dp, cred, clp->nfsc_nmp, p);
2967 		nfscl_freedeleg(&clp->nfsc_deleg, dp);
2968 	}
2969 	NFSFREECRED(cred);
2970 }
2971 
2972 /*
2973  * Do a callback RPC.
2974  */
2975 APPLESTATIC void
2976 nfscl_docb(struct nfsrv_descript *nd, NFSPROC_T *p)
2977 {
2978 	int i, op;
2979 	u_int32_t *tl;
2980 	struct nfsclclient *clp;
2981 	struct nfscldeleg *dp = NULL;
2982 	int numops, taglen = -1, error = 0, trunc, ret = 0;
2983 	u_int32_t minorvers, retops = 0, *retopsp = NULL, *repp, cbident;
2984 	u_char tag[NFSV4_SMALLSTR + 1], *tagstr;
2985 	vnode_t vp = NULL;
2986 	struct nfsnode *np;
2987 	struct vattr va;
2988 	struct nfsfh *nfhp;
2989 	mount_t mp;
2990 	nfsattrbit_t attrbits, rattrbits;
2991 	nfsv4stateid_t stateid;
2992 
2993 	nfsrvd_rephead(nd);
2994 	NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
2995 	taglen = fxdr_unsigned(int, *tl);
2996 	if (taglen < 0) {
2997 		error = EBADRPC;
2998 		goto nfsmout;
2999 	}
3000 	if (taglen <= NFSV4_SMALLSTR)
3001 		tagstr = tag;
3002 	else
3003 		tagstr = malloc(taglen + 1, M_TEMP, M_WAITOK);
3004 	error = nfsrv_mtostr(nd, tagstr, taglen);
3005 	if (error) {
3006 		if (taglen > NFSV4_SMALLSTR)
3007 			free(tagstr, M_TEMP);
3008 		taglen = -1;
3009 		goto nfsmout;
3010 	}
3011 	(void) nfsm_strtom(nd, tag, taglen);
3012 	if (taglen > NFSV4_SMALLSTR) {
3013 		free(tagstr, M_TEMP);
3014 	}
3015 	NFSM_BUILD(retopsp, u_int32_t *, NFSX_UNSIGNED);
3016 	NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
3017 	minorvers = fxdr_unsigned(u_int32_t, *tl++);
3018 	if (minorvers != NFSV4_MINORVERSION)
3019 		nd->nd_repstat = NFSERR_MINORVERMISMATCH;
3020 	cbident = fxdr_unsigned(u_int32_t, *tl++);
3021 	if (nd->nd_repstat)
3022 		numops = 0;
3023 	else
3024 		numops = fxdr_unsigned(int, *tl);
3025 	/*
3026 	 * Loop around doing the sub ops.
3027 	 */
3028 	for (i = 0; i < numops; i++) {
3029 		NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3030 		NFSM_BUILD(repp, u_int32_t *, 2 * NFSX_UNSIGNED);
3031 		*repp++ = *tl;
3032 		op = fxdr_unsigned(int, *tl);
3033 		if (op < NFSV4OP_CBGETATTR || op > NFSV4OP_CBRECALL) {
3034 		    nd->nd_repstat = NFSERR_OPILLEGAL;
3035 		    *repp = nfscl_errmap(nd);
3036 		    retops++;
3037 		    break;
3038 		}
3039 		nd->nd_procnum = op;
3040 		newnfsstats.cbrpccnt[nd->nd_procnum]++;
3041 		switch (op) {
3042 		case NFSV4OP_CBGETATTR:
3043 			clp = NULL;
3044 			error = nfsm_getfh(nd, &nfhp);
3045 			if (!error)
3046 				error = nfsrv_getattrbits(nd, &attrbits,
3047 				    NULL, NULL);
3048 			if (!error) {
3049 				mp = nfscl_getmnt(cbident);
3050 				if (mp == NULL)
3051 					error = NFSERR_SERVERFAULT;
3052 			}
3053 			if (!error) {
3054 				dp = NULL;
3055 				NFSLOCKCLSTATE();
3056 				clp = nfscl_findcl(VFSTONFS(mp));
3057 				if (clp != NULL)
3058 					dp = nfscl_finddeleg(clp, nfhp->nfh_fh,
3059 					    nfhp->nfh_len);
3060 				NFSUNLOCKCLSTATE();
3061 				if (dp == NULL)
3062 					error = NFSERR_SERVERFAULT;
3063 			}
3064 			if (!error) {
3065 				ret = nfscl_ngetreopen(mp, nfhp->nfh_fh,
3066 				    nfhp->nfh_len, p, &np);
3067 				if (!ret)
3068 					vp = NFSTOV(np);
3069 			}
3070 			if (nfhp != NULL)
3071 				FREE((caddr_t)nfhp, M_NFSFH);
3072 			if (!error) {
3073 				NFSZERO_ATTRBIT(&rattrbits);
3074 				if (NFSISSET_ATTRBIT(&attrbits,
3075 				    NFSATTRBIT_SIZE)) {
3076 					if (!ret)
3077 						va.va_size = np->n_size;
3078 					else
3079 						va.va_size = dp->nfsdl_size;
3080 					NFSSETBIT_ATTRBIT(&rattrbits,
3081 					    NFSATTRBIT_SIZE);
3082 				}
3083 				if (NFSISSET_ATTRBIT(&attrbits,
3084 				    NFSATTRBIT_CHANGE)) {
3085 					va.va_filerev = dp->nfsdl_change;
3086 					if (ret || (np->n_flag & NDELEGMOD))
3087 						va.va_filerev++;
3088 					NFSSETBIT_ATTRBIT(&rattrbits,
3089 					    NFSATTRBIT_CHANGE);
3090 				}
3091 				(void) nfsv4_fillattr(nd, NULL, NULL, NULL, &va,
3092 				    NULL, 0, &rattrbits, NULL, NULL, 0, 0, 0, 0,
3093 				    (uint64_t)0);
3094 				if (!ret)
3095 					vrele(vp);
3096 			}
3097 			break;
3098 		case NFSV4OP_CBRECALL:
3099 			clp = NULL;
3100 			NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
3101 			    NFSX_UNSIGNED);
3102 			stateid.seqid = *tl++;
3103 			NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other,
3104 			    NFSX_STATEIDOTHER);
3105 			tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
3106 			trunc = fxdr_unsigned(int, *tl);
3107 			error = nfsm_getfh(nd, &nfhp);
3108 			if (!error) {
3109 				mp = nfscl_getmnt(cbident);
3110 				if (mp == NULL)
3111 					error = NFSERR_SERVERFAULT;
3112 			}
3113 			if (!error) {
3114 				NFSLOCKCLSTATE();
3115 				clp = nfscl_findcl(VFSTONFS(mp));
3116 				if (clp != NULL) {
3117 					dp = nfscl_finddeleg(clp, nfhp->nfh_fh,
3118 					    nfhp->nfh_len);
3119 					if (dp != NULL && (dp->nfsdl_flags &
3120 					    NFSCLDL_DELEGRET) == 0) {
3121 						dp->nfsdl_flags |=
3122 						    NFSCLDL_RECALL;
3123 						wakeup((caddr_t)clp);
3124 					}
3125 				} else {
3126 					error = NFSERR_SERVERFAULT;
3127 				}
3128 				NFSUNLOCKCLSTATE();
3129 			}
3130 			if (nfhp != NULL)
3131 				FREE((caddr_t)nfhp, M_NFSFH);
3132 			break;
3133 		};
3134 		if (error) {
3135 			if (error == EBADRPC || error == NFSERR_BADXDR) {
3136 				nd->nd_repstat = NFSERR_BADXDR;
3137 			} else {
3138 				nd->nd_repstat = error;
3139 			}
3140 			error = 0;
3141 		}
3142 		retops++;
3143 		if (nd->nd_repstat) {
3144 			*repp = nfscl_errmap(nd);
3145 			break;
3146 		} else
3147 			*repp = 0;	/* NFS4_OK */
3148 	}
3149 nfsmout:
3150 	if (error) {
3151 		if (error == EBADRPC || error == NFSERR_BADXDR)
3152 			nd->nd_repstat = NFSERR_BADXDR;
3153 		else
3154 			printf("nfsv4 comperr1=%d\n", error);
3155 	}
3156 	if (taglen == -1) {
3157 		NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
3158 		*tl++ = 0;
3159 		*tl = 0;
3160 	} else {
3161 		*retopsp = txdr_unsigned(retops);
3162 	}
3163 	*nd->nd_errp = nfscl_errmap(nd);
3164 }
3165 
3166 /*
3167  * Generate the next cbident value. Basically just increment a static value
3168  * and then check that it isn't already in the list, if it has wrapped around.
3169  */
3170 static u_int32_t
3171 nfscl_nextcbident(void)
3172 {
3173 	struct nfsclclient *clp;
3174 	int matched;
3175 	static u_int32_t nextcbident = 0;
3176 	static int haswrapped = 0;
3177 
3178 	nextcbident++;
3179 	if (nextcbident == 0)
3180 		haswrapped = 1;
3181 	if (haswrapped) {
3182 		/*
3183 		 * Search the clientid list for one already using this cbident.
3184 		 */
3185 		do {
3186 			matched = 0;
3187 			NFSLOCKCLSTATE();
3188 			LIST_FOREACH(clp, &nfsclhead, nfsc_list) {
3189 				if (clp->nfsc_cbident == nextcbident) {
3190 					matched = 1;
3191 					break;
3192 				}
3193 			}
3194 			NFSUNLOCKCLSTATE();
3195 			if (matched == 1)
3196 				nextcbident++;
3197 		} while (matched);
3198 	}
3199 	return (nextcbident);
3200 }
3201 
3202 /*
3203  * Get the mount point related to a given cbident.
3204  */
3205 static mount_t
3206 nfscl_getmnt(u_int32_t cbident)
3207 {
3208 	struct nfsclclient *clp;
3209 	struct nfsmount *nmp;
3210 
3211 	NFSLOCKCLSTATE();
3212 	LIST_FOREACH(clp, &nfsclhead, nfsc_list) {
3213 		if (clp->nfsc_cbident == cbident)
3214 			break;
3215 	}
3216 	if (clp == NULL) {
3217 		NFSUNLOCKCLSTATE();
3218 		return (NULL);
3219 	}
3220 	nmp = clp->nfsc_nmp;
3221 	NFSUNLOCKCLSTATE();
3222 	return (nmp->nm_mountp);
3223 }
3224 
3225 /*
3226  * Search for a lock conflict locally on the client. A conflict occurs if
3227  * - not same owner and overlapping byte range and at least one of them is
3228  *   a write lock or this is an unlock.
3229  */
3230 static int
3231 nfscl_localconflict(struct nfsclclient *clp, u_int8_t *fhp, int fhlen,
3232     struct nfscllock *nlop, u_int8_t *own, struct nfscldeleg *dp,
3233     struct nfscllock **lopp)
3234 {
3235 	struct nfsclowner *owp;
3236 	struct nfsclopen *op;
3237 	int ret;
3238 
3239 	if (dp != NULL) {
3240 		ret = nfscl_checkconflict(&dp->nfsdl_lock, nlop, own, lopp);
3241 		if (ret)
3242 			return (ret);
3243 	}
3244 	LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
3245 		LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
3246 			if (op->nfso_fhlen == fhlen &&
3247 			    !NFSBCMP(op->nfso_fh, fhp, fhlen)) {
3248 				ret = nfscl_checkconflict(&op->nfso_lock, nlop,
3249 				    own, lopp);
3250 				if (ret)
3251 					return (ret);
3252 			}
3253 		}
3254 	}
3255 	return (0);
3256 }
3257 
3258 static int
3259 nfscl_checkconflict(struct nfscllockownerhead *lhp, struct nfscllock *nlop,
3260     u_int8_t *own, struct nfscllock **lopp)
3261 {
3262 	struct nfscllockowner *lp;
3263 	struct nfscllock *lop;
3264 
3265 	LIST_FOREACH(lp, lhp, nfsl_list) {
3266 		if (NFSBCMP(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN)) {
3267 			LIST_FOREACH(lop, &lp->nfsl_lock, nfslo_list) {
3268 				if (lop->nfslo_first >= nlop->nfslo_end)
3269 					break;
3270 				if (lop->nfslo_end <= nlop->nfslo_first)
3271 					continue;
3272 				if (lop->nfslo_type == F_WRLCK ||
3273 				    nlop->nfslo_type == F_WRLCK ||
3274 				    nlop->nfslo_type == F_UNLCK) {
3275 					if (lopp != NULL)
3276 						*lopp = lop;
3277 					return (NFSERR_DENIED);
3278 				}
3279 			}
3280 		}
3281 	}
3282 	return (0);
3283 }
3284 
3285 /*
3286  * Check for a local conflicting lock.
3287  */
3288 APPLESTATIC int
3289 nfscl_lockt(vnode_t vp, struct nfsclclient *clp, u_int64_t off,
3290     u_int64_t len, struct flock *fl, NFSPROC_T *p, void *id, int flags)
3291 {
3292 	struct nfscllock *lop, nlck;
3293 	struct nfscldeleg *dp;
3294 	struct nfsnode *np;
3295 	u_int8_t own[NFSV4CL_LOCKNAMELEN];
3296 	int error;
3297 
3298 	nlck.nfslo_type = fl->l_type;
3299 	nlck.nfslo_first = off;
3300 	if (len == NFS64BITSSET) {
3301 		nlck.nfslo_end = NFS64BITSSET;
3302 	} else {
3303 		nlck.nfslo_end = off + len;
3304 		if (nlck.nfslo_end <= nlck.nfslo_first)
3305 			return (NFSERR_INVAL);
3306 	}
3307 	np = VTONFS(vp);
3308 	nfscl_filllockowner(id, own, flags);
3309 	NFSLOCKCLSTATE();
3310 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
3311 	error = nfscl_localconflict(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
3312 	    &nlck, own, dp, &lop);
3313 	if (error != 0) {
3314 		fl->l_whence = SEEK_SET;
3315 		fl->l_start = lop->nfslo_first;
3316 		if (lop->nfslo_end == NFS64BITSSET)
3317 			fl->l_len = 0;
3318 		else
3319 			fl->l_len = lop->nfslo_end - lop->nfslo_first;
3320 		fl->l_pid = (pid_t)0;
3321 		fl->l_type = lop->nfslo_type;
3322 		error = -1;			/* no RPC required */
3323 	} else if (dp != NULL && ((dp->nfsdl_flags & NFSCLDL_WRITE) ||
3324 	    fl->l_type == F_RDLCK)) {
3325 		/*
3326 		 * The delegation ensures that there isn't a conflicting
3327 		 * lock on the server, so return -1 to indicate an RPC
3328 		 * isn't required.
3329 		 */
3330 		fl->l_type = F_UNLCK;
3331 		error = -1;
3332 	}
3333 	NFSUNLOCKCLSTATE();
3334 	return (error);
3335 }
3336 
3337 /*
3338  * Handle Recall of a delegation.
3339  * The clp must be exclusive locked when this is called.
3340  */
3341 static int
3342 nfscl_recalldeleg(struct nfsclclient *clp, struct nfsmount *nmp,
3343     struct nfscldeleg *dp, vnode_t vp, struct ucred *cred, NFSPROC_T *p,
3344     int called_from_renewthread)
3345 {
3346 	struct nfsclowner *owp, *lowp, *nowp;
3347 	struct nfsclopen *op, *lop;
3348 	struct nfscllockowner *lp;
3349 	struct nfscllock *lckp;
3350 	struct nfsnode *np;
3351 	int error = 0, ret, gotvp = 0;
3352 
3353 	if (vp == NULL) {
3354 		/*
3355 		 * First, get a vnode for the file. This is needed to do RPCs.
3356 		 */
3357 		ret = nfscl_ngetreopen(nmp->nm_mountp, dp->nfsdl_fh,
3358 		    dp->nfsdl_fhlen, p, &np);
3359 		if (ret) {
3360 			/*
3361 			 * File isn't open, so nothing to move over to the
3362 			 * server.
3363 			 */
3364 			return (0);
3365 		}
3366 		vp = NFSTOV(np);
3367 		gotvp = 1;
3368 	} else {
3369 		np = VTONFS(vp);
3370 	}
3371 	dp->nfsdl_flags &= ~NFSCLDL_MODTIMESET;
3372 
3373 	/*
3374 	 * Ok, if it's a write delegation, flush data to the server, so
3375 	 * that close/open consistency is retained.
3376 	 */
3377 	ret = 0;
3378 	NFSLOCKNODE(np);
3379 	if ((dp->nfsdl_flags & NFSCLDL_WRITE) && (np->n_flag & NMODIFIED)) {
3380 		np->n_flag |= NDELEGRECALL;
3381 		NFSUNLOCKNODE(np);
3382 		ret = ncl_flush(vp, MNT_WAIT, cred, p, 1,
3383 		    called_from_renewthread);
3384 		NFSLOCKNODE(np);
3385 		np->n_flag &= ~NDELEGRECALL;
3386 	}
3387 	NFSINVALATTRCACHE(np);
3388 	NFSUNLOCKNODE(np);
3389 	if (ret == EIO && called_from_renewthread != 0) {
3390 		/*
3391 		 * If the flush failed with EIO for the renew thread,
3392 		 * return now, so that the dirty buffer will be flushed
3393 		 * later.
3394 		 */
3395 		if (gotvp != 0)
3396 			vrele(vp);
3397 		return (ret);
3398 	}
3399 
3400 	/*
3401 	 * Now, for each openowner with opens issued locally, move them
3402 	 * over to state against the server.
3403 	 */
3404 	LIST_FOREACH(lowp, &dp->nfsdl_owner, nfsow_list) {
3405 		lop = LIST_FIRST(&lowp->nfsow_open);
3406 		if (lop != NULL) {
3407 			if (LIST_NEXT(lop, nfso_list) != NULL)
3408 				panic("nfsdlg mult opens");
3409 			/*
3410 			 * Look for the same openowner against the server.
3411 			 */
3412 			LIST_FOREACH(owp, &clp->nfsc_owner, nfsow_list) {
3413 				if (!NFSBCMP(lowp->nfsow_owner,
3414 				    owp->nfsow_owner, NFSV4CL_LOCKNAMELEN)) {
3415 					newnfs_copycred(&dp->nfsdl_cred, cred);
3416 					ret = nfscl_moveopen(vp, clp, nmp, lop,
3417 					    owp, dp, cred, p);
3418 					if (ret == NFSERR_STALECLIENTID ||
3419 					    ret == NFSERR_STALEDONTRECOVER) {
3420 						if (gotvp)
3421 							vrele(vp);
3422 						return (ret);
3423 					}
3424 					if (ret) {
3425 						nfscl_freeopen(lop, 1);
3426 						if (!error)
3427 							error = ret;
3428 					}
3429 					break;
3430 				}
3431 			}
3432 
3433 			/*
3434 			 * If no openowner found, create one and get an open
3435 			 * for it.
3436 			 */
3437 			if (owp == NULL) {
3438 				MALLOC(nowp, struct nfsclowner *,
3439 				    sizeof (struct nfsclowner), M_NFSCLOWNER,
3440 				    M_WAITOK);
3441 				nfscl_newopen(clp, NULL, &owp, &nowp, &op,
3442 				    NULL, lowp->nfsow_owner, dp->nfsdl_fh,
3443 				    dp->nfsdl_fhlen, NULL);
3444 				newnfs_copycred(&dp->nfsdl_cred, cred);
3445 				ret = nfscl_moveopen(vp, clp, nmp, lop,
3446 				    owp, dp, cred, p);
3447 				if (ret) {
3448 					nfscl_freeopenowner(owp, 0);
3449 					if (ret == NFSERR_STALECLIENTID ||
3450 					    ret == NFSERR_STALEDONTRECOVER) {
3451 						if (gotvp)
3452 							vrele(vp);
3453 						return (ret);
3454 					}
3455 					if (ret) {
3456 						nfscl_freeopen(lop, 1);
3457 						if (!error)
3458 							error = ret;
3459 					}
3460 				}
3461 			}
3462 		}
3463 	}
3464 
3465 	/*
3466 	 * Now, get byte range locks for any locks done locally.
3467 	 */
3468 	LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
3469 		LIST_FOREACH(lckp, &lp->nfsl_lock, nfslo_list) {
3470 			newnfs_copycred(&dp->nfsdl_cred, cred);
3471 			ret = nfscl_relock(vp, clp, nmp, lp, lckp, cred, p);
3472 			if (ret == NFSERR_STALESTATEID ||
3473 			    ret == NFSERR_STALEDONTRECOVER ||
3474 			    ret == NFSERR_STALECLIENTID) {
3475 				if (gotvp)
3476 					vrele(vp);
3477 				return (ret);
3478 			}
3479 			if (ret && !error)
3480 				error = ret;
3481 		}
3482 	}
3483 	if (gotvp)
3484 		vrele(vp);
3485 	return (error);
3486 }
3487 
3488 /*
3489  * Move a locally issued open over to an owner on the state list.
3490  * SIDE EFFECT: If it needs to sleep (do an rpc), it unlocks clstate and
3491  * returns with it unlocked.
3492  */
3493 static int
3494 nfscl_moveopen(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp,
3495     struct nfsclopen *lop, struct nfsclowner *owp, struct nfscldeleg *dp,
3496     struct ucred *cred, NFSPROC_T *p)
3497 {
3498 	struct nfsclopen *op, *nop;
3499 	struct nfscldeleg *ndp;
3500 	struct nfsnode *np;
3501 	int error = 0, newone;
3502 
3503 	/*
3504 	 * First, look for an appropriate open, If found, just increment the
3505 	 * opencnt in it.
3506 	 */
3507 	LIST_FOREACH(op, &owp->nfsow_open, nfso_list) {
3508 		if ((op->nfso_mode & lop->nfso_mode) == lop->nfso_mode &&
3509 		    op->nfso_fhlen == lop->nfso_fhlen &&
3510 		    !NFSBCMP(op->nfso_fh, lop->nfso_fh, op->nfso_fhlen)) {
3511 			op->nfso_opencnt += lop->nfso_opencnt;
3512 			nfscl_freeopen(lop, 1);
3513 			return (0);
3514 		}
3515 	}
3516 
3517 	/* No appropriate open, so we have to do one against the server. */
3518 	np = VTONFS(vp);
3519 	MALLOC(nop, struct nfsclopen *, sizeof (struct nfsclopen) +
3520 	    lop->nfso_fhlen - 1, M_NFSCLOPEN, M_WAITOK);
3521 	newone = 0;
3522 	nfscl_newopen(clp, NULL, &owp, NULL, &op, &nop, owp->nfsow_owner,
3523 	    lop->nfso_fh, lop->nfso_fhlen, &newone);
3524 	ndp = dp;
3525 	error = nfscl_tryopen(nmp, vp, np->n_v4->n4_data, np->n_v4->n4_fhlen,
3526 	    lop->nfso_fh, lop->nfso_fhlen, lop->nfso_mode, op,
3527 	    NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, &ndp, 0, 0, cred, p);
3528 	if (error) {
3529 		if (newone)
3530 			nfscl_freeopen(op, 0);
3531 	} else {
3532 		if (newone)
3533 			newnfs_copyincred(cred, &op->nfso_cred);
3534 		op->nfso_mode |= lop->nfso_mode;
3535 		op->nfso_opencnt += lop->nfso_opencnt;
3536 		nfscl_freeopen(lop, 1);
3537 	}
3538 	if (nop != NULL)
3539 		FREE((caddr_t)nop, M_NFSCLOPEN);
3540 	if (ndp != NULL) {
3541 		/*
3542 		 * What should I do with the returned delegation, since the
3543 		 * delegation is being recalled? For now, just printf and
3544 		 * through it away.
3545 		 */
3546 		printf("Moveopen returned deleg\n");
3547 		FREE((caddr_t)ndp, M_NFSCLDELEG);
3548 	}
3549 	return (error);
3550 }
3551 
3552 /*
3553  * Recall all delegations on this client.
3554  */
3555 static void
3556 nfscl_totalrecall(struct nfsclclient *clp)
3557 {
3558 	struct nfscldeleg *dp;
3559 
3560 	TAILQ_FOREACH(dp, &clp->nfsc_deleg, nfsdl_list) {
3561 		if ((dp->nfsdl_flags & NFSCLDL_DELEGRET) == 0)
3562 			dp->nfsdl_flags |= NFSCLDL_RECALL;
3563 	}
3564 }
3565 
3566 /*
3567  * Relock byte ranges. Called for delegation recall and state expiry.
3568  */
3569 static int
3570 nfscl_relock(vnode_t vp, struct nfsclclient *clp, struct nfsmount *nmp,
3571     struct nfscllockowner *lp, struct nfscllock *lop, struct ucred *cred,
3572     NFSPROC_T *p)
3573 {
3574 	struct nfscllockowner *nlp;
3575 	struct nfsfh *nfhp;
3576 	u_int64_t off, len;
3577 	u_int32_t clidrev = 0;
3578 	int error, newone, donelocally;
3579 
3580 	off = lop->nfslo_first;
3581 	len = lop->nfslo_end - lop->nfslo_first;
3582 	error = nfscl_getbytelock(vp, off, len, lop->nfslo_type, cred, p,
3583 	    clp, 1, NULL, lp->nfsl_lockflags, lp->nfsl_owner,
3584 	    lp->nfsl_openowner, &nlp, &newone, &donelocally);
3585 	if (error || donelocally)
3586 		return (error);
3587 	if (nmp->nm_clp != NULL)
3588 		clidrev = nmp->nm_clp->nfsc_clientidrev;
3589 	else
3590 		clidrev = 0;
3591 	nfhp = VTONFS(vp)->n_fhp;
3592 	error = nfscl_trylock(nmp, vp, nfhp->nfh_fh,
3593 	    nfhp->nfh_len, nlp, newone, 0, off,
3594 	    len, lop->nfslo_type, cred, p);
3595 	if (error)
3596 		nfscl_freelockowner(nlp, 0);
3597 	return (error);
3598 }
3599 
3600 /*
3601  * Called to re-open a file. Basically get a vnode for the file handle
3602  * and then call nfsrpc_openrpc() to do the rest.
3603  */
3604 static int
3605 nfsrpc_reopen(struct nfsmount *nmp, u_int8_t *fhp, int fhlen,
3606     u_int32_t mode, struct nfsclopen *op, struct nfscldeleg **dpp,
3607     struct ucred *cred, NFSPROC_T *p)
3608 {
3609 	struct nfsnode *np;
3610 	vnode_t vp;
3611 	int error;
3612 
3613 	error = nfscl_ngetreopen(nmp->nm_mountp, fhp, fhlen, p, &np);
3614 	if (error)
3615 		return (error);
3616 	vp = NFSTOV(np);
3617 	if (np->n_v4 != NULL) {
3618 		error = nfscl_tryopen(nmp, vp, np->n_v4->n4_data,
3619 		    np->n_v4->n4_fhlen, fhp, fhlen, mode, op,
3620 		    NFS4NODENAME(np->n_v4), np->n_v4->n4_namelen, dpp, 0, 0,
3621 		    cred, p);
3622 	} else {
3623 		error = EINVAL;
3624 	}
3625 	vrele(vp);
3626 	return (error);
3627 }
3628 
3629 /*
3630  * Try an open against the server. Just call nfsrpc_openrpc(), retrying while
3631  * NFSERR_DELAY. Also, try system credentials, if the passed in credentials
3632  * fail.
3633  */
3634 static int
3635 nfscl_tryopen(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp, int fhlen,
3636     u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
3637     u_int8_t *name, int namelen, struct nfscldeleg **ndpp,
3638     int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p)
3639 {
3640 	int error;
3641 
3642 	do {
3643 		error = nfsrpc_openrpc(nmp, vp, fhp, fhlen, newfhp, newfhlen,
3644 		    mode, op, name, namelen, ndpp, reclaim, delegtype, cred, p,
3645 		    0, 0);
3646 		if (error == NFSERR_DELAY)
3647 			(void) nfs_catnap(PZERO, error, "nfstryop");
3648 	} while (error == NFSERR_DELAY);
3649 	if (error == EAUTH || error == EACCES) {
3650 		/* Try again using system credentials */
3651 		newnfs_setroot(cred);
3652 		do {
3653 		    error = nfsrpc_openrpc(nmp, vp, fhp, fhlen, newfhp,
3654 			newfhlen, mode, op, name, namelen, ndpp, reclaim,
3655 			delegtype, cred, p, 1, 0);
3656 		    if (error == NFSERR_DELAY)
3657 			(void) nfs_catnap(PZERO, error, "nfstryop");
3658 		} while (error == NFSERR_DELAY);
3659 	}
3660 	return (error);
3661 }
3662 
3663 /*
3664  * Try a byte range lock. Just loop on nfsrpc_lock() while it returns
3665  * NFSERR_DELAY. Also, retry with system credentials, if the provided
3666  * cred don't work.
3667  */
3668 static int
3669 nfscl_trylock(struct nfsmount *nmp, vnode_t vp, u_int8_t *fhp,
3670     int fhlen, struct nfscllockowner *nlp, int newone, int reclaim,
3671     u_int64_t off, u_int64_t len, short type, struct ucred *cred, NFSPROC_T *p)
3672 {
3673 	struct nfsrv_descript nfsd, *nd = &nfsd;
3674 	int error;
3675 
3676 	do {
3677 		error = nfsrpc_lock(nd, nmp, vp, fhp, fhlen, nlp, newone,
3678 		    reclaim, off, len, type, cred, p, 0);
3679 		if (!error && nd->nd_repstat == NFSERR_DELAY)
3680 			(void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3681 			    "nfstrylck");
3682 	} while (!error && nd->nd_repstat == NFSERR_DELAY);
3683 	if (!error)
3684 		error = nd->nd_repstat;
3685 	if (error == EAUTH || error == EACCES) {
3686 		/* Try again using root credentials */
3687 		newnfs_setroot(cred);
3688 		do {
3689 			error = nfsrpc_lock(nd, nmp, vp, fhp, fhlen, nlp,
3690 			    newone, reclaim, off, len, type, cred, p, 1);
3691 			if (!error && nd->nd_repstat == NFSERR_DELAY)
3692 				(void) nfs_catnap(PZERO, (int)nd->nd_repstat,
3693 				    "nfstrylck");
3694 		} while (!error && nd->nd_repstat == NFSERR_DELAY);
3695 		if (!error)
3696 			error = nd->nd_repstat;
3697 	}
3698 	return (error);
3699 }
3700 
3701 /*
3702  * Try a delegreturn against the server. Just call nfsrpc_delegreturn(),
3703  * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in
3704  * credentials fail.
3705  */
3706 static int
3707 nfscl_trydelegreturn(struct nfscldeleg *dp, struct ucred *cred,
3708     struct nfsmount *nmp, NFSPROC_T *p)
3709 {
3710 	int error;
3711 
3712 	do {
3713 		error = nfsrpc_delegreturn(dp, cred, nmp, p, 0);
3714 		if (error == NFSERR_DELAY)
3715 			(void) nfs_catnap(PZERO, error, "nfstrydp");
3716 	} while (error == NFSERR_DELAY);
3717 	if (error == EAUTH || error == EACCES) {
3718 		/* Try again using system credentials */
3719 		newnfs_setroot(cred);
3720 		do {
3721 			error = nfsrpc_delegreturn(dp, cred, nmp, p, 1);
3722 			if (error == NFSERR_DELAY)
3723 				(void) nfs_catnap(PZERO, error, "nfstrydp");
3724 		} while (error == NFSERR_DELAY);
3725 	}
3726 	return (error);
3727 }
3728 
3729 /*
3730  * Try a close against the server. Just call nfsrpc_closerpc(),
3731  * retrying while NFSERR_DELAY. Also, try system credentials, if the passed in
3732  * credentials fail.
3733  */
3734 APPLESTATIC int
3735 nfscl_tryclose(struct nfsclopen *op, struct ucred *cred,
3736     struct nfsmount *nmp, NFSPROC_T *p)
3737 {
3738 	struct nfsrv_descript nfsd, *nd = &nfsd;
3739 	int error;
3740 
3741 	do {
3742 		error = nfsrpc_closerpc(nd, nmp, op, cred, p, 0);
3743 		if (error == NFSERR_DELAY)
3744 			(void) nfs_catnap(PZERO, error, "nfstrycl");
3745 	} while (error == NFSERR_DELAY);
3746 	if (error == EAUTH || error == EACCES) {
3747 		/* Try again using system credentials */
3748 		newnfs_setroot(cred);
3749 		do {
3750 			error = nfsrpc_closerpc(nd, nmp, op, cred, p, 1);
3751 			if (error == NFSERR_DELAY)
3752 				(void) nfs_catnap(PZERO, error, "nfstrycl");
3753 		} while (error == NFSERR_DELAY);
3754 	}
3755 	return (error);
3756 }
3757 
3758 /*
3759  * Decide if a delegation on a file permits close without flushing writes
3760  * to the server. This might be a big performance win in some environments.
3761  * (Not useful until the client does caching on local stable storage.)
3762  */
3763 APPLESTATIC int
3764 nfscl_mustflush(vnode_t vp)
3765 {
3766 	struct nfsclclient *clp;
3767 	struct nfscldeleg *dp;
3768 	struct nfsnode *np;
3769 	struct nfsmount *nmp;
3770 
3771 	np = VTONFS(vp);
3772 	nmp = VFSTONFS(vnode_mount(vp));
3773 	if (!NFSHASNFSV4(nmp))
3774 		return (1);
3775 	NFSLOCKCLSTATE();
3776 	clp = nfscl_findcl(nmp);
3777 	if (clp == NULL) {
3778 		NFSUNLOCKCLSTATE();
3779 		return (1);
3780 	}
3781 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
3782 	if (dp != NULL && (dp->nfsdl_flags &
3783 	    (NFSCLDL_WRITE | NFSCLDL_RECALL | NFSCLDL_DELEGRET)) ==
3784 	     NFSCLDL_WRITE &&
3785 	    (dp->nfsdl_sizelimit >= np->n_size ||
3786 	     !NFSHASSTRICT3530(nmp))) {
3787 		NFSUNLOCKCLSTATE();
3788 		return (0);
3789 	}
3790 	NFSUNLOCKCLSTATE();
3791 	return (1);
3792 }
3793 
3794 /*
3795  * See if a (write) delegation exists for this file.
3796  */
3797 APPLESTATIC int
3798 nfscl_nodeleg(vnode_t vp, int writedeleg)
3799 {
3800 	struct nfsclclient *clp;
3801 	struct nfscldeleg *dp;
3802 	struct nfsnode *np;
3803 	struct nfsmount *nmp;
3804 
3805 	np = VTONFS(vp);
3806 	nmp = VFSTONFS(vnode_mount(vp));
3807 	if (!NFSHASNFSV4(nmp))
3808 		return (1);
3809 	NFSLOCKCLSTATE();
3810 	clp = nfscl_findcl(nmp);
3811 	if (clp == NULL) {
3812 		NFSUNLOCKCLSTATE();
3813 		return (1);
3814 	}
3815 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
3816 	if (dp != NULL &&
3817 	    (dp->nfsdl_flags & (NFSCLDL_RECALL | NFSCLDL_DELEGRET)) == 0 &&
3818 	    (writedeleg == 0 || (dp->nfsdl_flags & NFSCLDL_WRITE) ==
3819 	     NFSCLDL_WRITE)) {
3820 		NFSUNLOCKCLSTATE();
3821 		return (0);
3822 	}
3823 	NFSUNLOCKCLSTATE();
3824 	return (1);
3825 }
3826 
3827 /*
3828  * Look for an associated delegation that should be DelegReturned.
3829  */
3830 APPLESTATIC int
3831 nfscl_removedeleg(vnode_t vp, NFSPROC_T *p, nfsv4stateid_t *stp)
3832 {
3833 	struct nfsclclient *clp;
3834 	struct nfscldeleg *dp;
3835 	struct nfsclowner *owp;
3836 	struct nfscllockowner *lp;
3837 	struct nfsmount *nmp;
3838 	struct ucred *cred;
3839 	struct nfsnode *np;
3840 	int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept;
3841 
3842 	nmp = VFSTONFS(vnode_mount(vp));
3843 	np = VTONFS(vp);
3844 	NFSLOCKCLSTATE();
3845 	/*
3846 	 * Loop around waiting for:
3847 	 * - outstanding I/O operations on delegations to complete
3848 	 * - for a delegation on vp that has state, lock the client and
3849 	 *   do a recall
3850 	 * - return delegation with no state
3851 	 */
3852 	while (1) {
3853 		clp = nfscl_findcl(nmp);
3854 		if (clp == NULL) {
3855 			NFSUNLOCKCLSTATE();
3856 			return (retcnt);
3857 		}
3858 		dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
3859 		    np->n_fhp->nfh_len);
3860 		if (dp != NULL) {
3861 		    /*
3862 		     * Wait for outstanding I/O ops to be done.
3863 		     */
3864 		    if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
3865 			if (igotlock) {
3866 			    nfsv4_unlock(&clp->nfsc_lock, 0);
3867 			    igotlock = 0;
3868 			}
3869 			dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
3870 			(void) nfsmsleep(&dp->nfsdl_rwlock,
3871 			    NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
3872 			continue;
3873 		    }
3874 		    needsrecall = 0;
3875 		    LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
3876 			if (!LIST_EMPTY(&owp->nfsow_open)) {
3877 			    needsrecall = 1;
3878 			    break;
3879 			}
3880 		    }
3881 		    if (!needsrecall) {
3882 			LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
3883 			    if (!LIST_EMPTY(&lp->nfsl_lock)) {
3884 				needsrecall = 1;
3885 				break;
3886 			    }
3887 			}
3888 		    }
3889 		    if (needsrecall && !triedrecall) {
3890 			dp->nfsdl_flags |= NFSCLDL_DELEGRET;
3891 			islept = 0;
3892 			while (!igotlock) {
3893 			    igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
3894 				&islept, NFSCLSTATEMUTEXPTR, NULL);
3895 			    if (islept)
3896 				break;
3897 			}
3898 			if (islept)
3899 			    continue;
3900 			NFSUNLOCKCLSTATE();
3901 			cred = newnfs_getcred();
3902 			newnfs_copycred(&dp->nfsdl_cred, cred);
3903 			(void) nfscl_recalldeleg(clp, nmp, dp, vp, cred, p, 0);
3904 			NFSFREECRED(cred);
3905 			triedrecall = 1;
3906 			NFSLOCKCLSTATE();
3907 			nfsv4_unlock(&clp->nfsc_lock, 0);
3908 			igotlock = 0;
3909 			continue;
3910 		    }
3911 		    *stp = dp->nfsdl_stateid;
3912 		    retcnt = 1;
3913 		    nfscl_cleandeleg(dp);
3914 		    nfscl_freedeleg(&clp->nfsc_deleg, dp);
3915 		}
3916 		if (igotlock)
3917 		    nfsv4_unlock(&clp->nfsc_lock, 0);
3918 		NFSUNLOCKCLSTATE();
3919 		return (retcnt);
3920 	}
3921 }
3922 
3923 /*
3924  * Look for associated delegation(s) that should be DelegReturned.
3925  */
3926 APPLESTATIC int
3927 nfscl_renamedeleg(vnode_t fvp, nfsv4stateid_t *fstp, int *gotfdp, vnode_t tvp,
3928     nfsv4stateid_t *tstp, int *gottdp, NFSPROC_T *p)
3929 {
3930 	struct nfsclclient *clp;
3931 	struct nfscldeleg *dp;
3932 	struct nfsclowner *owp;
3933 	struct nfscllockowner *lp;
3934 	struct nfsmount *nmp;
3935 	struct ucred *cred;
3936 	struct nfsnode *np;
3937 	int igotlock = 0, triedrecall = 0, needsrecall, retcnt = 0, islept;
3938 
3939 	nmp = VFSTONFS(vnode_mount(fvp));
3940 	*gotfdp = 0;
3941 	*gottdp = 0;
3942 	NFSLOCKCLSTATE();
3943 	/*
3944 	 * Loop around waiting for:
3945 	 * - outstanding I/O operations on delegations to complete
3946 	 * - for a delegation on fvp that has state, lock the client and
3947 	 *   do a recall
3948 	 * - return delegation(s) with no state.
3949 	 */
3950 	while (1) {
3951 		clp = nfscl_findcl(nmp);
3952 		if (clp == NULL) {
3953 			NFSUNLOCKCLSTATE();
3954 			return (retcnt);
3955 		}
3956 		np = VTONFS(fvp);
3957 		dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
3958 		    np->n_fhp->nfh_len);
3959 		if (dp != NULL && *gotfdp == 0) {
3960 		    /*
3961 		     * Wait for outstanding I/O ops to be done.
3962 		     */
3963 		    if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
3964 			if (igotlock) {
3965 			    nfsv4_unlock(&clp->nfsc_lock, 0);
3966 			    igotlock = 0;
3967 			}
3968 			dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
3969 			(void) nfsmsleep(&dp->nfsdl_rwlock,
3970 			    NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
3971 			continue;
3972 		    }
3973 		    needsrecall = 0;
3974 		    LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
3975 			if (!LIST_EMPTY(&owp->nfsow_open)) {
3976 			    needsrecall = 1;
3977 			    break;
3978 			}
3979 		    }
3980 		    if (!needsrecall) {
3981 			LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
3982 			    if (!LIST_EMPTY(&lp->nfsl_lock)) {
3983 				needsrecall = 1;
3984 				break;
3985 			    }
3986 			}
3987 		    }
3988 		    if (needsrecall && !triedrecall) {
3989 			dp->nfsdl_flags |= NFSCLDL_DELEGRET;
3990 			islept = 0;
3991 			while (!igotlock) {
3992 			    igotlock = nfsv4_lock(&clp->nfsc_lock, 1,
3993 				&islept, NFSCLSTATEMUTEXPTR, NULL);
3994 			    if (islept)
3995 				break;
3996 			}
3997 			if (islept)
3998 			    continue;
3999 			NFSUNLOCKCLSTATE();
4000 			cred = newnfs_getcred();
4001 			newnfs_copycred(&dp->nfsdl_cred, cred);
4002 			(void) nfscl_recalldeleg(clp, nmp, dp, fvp, cred, p, 0);
4003 			NFSFREECRED(cred);
4004 			triedrecall = 1;
4005 			NFSLOCKCLSTATE();
4006 			nfsv4_unlock(&clp->nfsc_lock, 0);
4007 			igotlock = 0;
4008 			continue;
4009 		    }
4010 		    *fstp = dp->nfsdl_stateid;
4011 		    retcnt++;
4012 		    *gotfdp = 1;
4013 		    nfscl_cleandeleg(dp);
4014 		    nfscl_freedeleg(&clp->nfsc_deleg, dp);
4015 		}
4016 		if (igotlock) {
4017 		    nfsv4_unlock(&clp->nfsc_lock, 0);
4018 		    igotlock = 0;
4019 		}
4020 		if (tvp != NULL) {
4021 		    np = VTONFS(tvp);
4022 		    dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh,
4023 			np->n_fhp->nfh_len);
4024 		    if (dp != NULL && *gottdp == 0) {
4025 			/*
4026 			 * Wait for outstanding I/O ops to be done.
4027 			 */
4028 			if (dp->nfsdl_rwlock.nfslock_usecnt > 0) {
4029 			    dp->nfsdl_rwlock.nfslock_lock |= NFSV4LOCK_WANTED;
4030 			    (void) nfsmsleep(&dp->nfsdl_rwlock,
4031 				NFSCLSTATEMUTEXPTR, PZERO, "nfscld", NULL);
4032 			    continue;
4033 			}
4034 			LIST_FOREACH(owp, &dp->nfsdl_owner, nfsow_list) {
4035 			    if (!LIST_EMPTY(&owp->nfsow_open)) {
4036 				NFSUNLOCKCLSTATE();
4037 				return (retcnt);
4038 			    }
4039 			}
4040 			LIST_FOREACH(lp, &dp->nfsdl_lock, nfsl_list) {
4041 			    if (!LIST_EMPTY(&lp->nfsl_lock)) {
4042 				NFSUNLOCKCLSTATE();
4043 				return (retcnt);
4044 			    }
4045 			}
4046 			*tstp = dp->nfsdl_stateid;
4047 			retcnt++;
4048 			*gottdp = 1;
4049 			nfscl_cleandeleg(dp);
4050 			nfscl_freedeleg(&clp->nfsc_deleg, dp);
4051 		    }
4052 		}
4053 		NFSUNLOCKCLSTATE();
4054 		return (retcnt);
4055 	}
4056 }
4057 
4058 /*
4059  * Get a reference on the clientid associated with the mount point.
4060  * Return 1 if success, 0 otherwise.
4061  */
4062 APPLESTATIC int
4063 nfscl_getref(struct nfsmount *nmp)
4064 {
4065 	struct nfsclclient *clp;
4066 
4067 	NFSLOCKCLSTATE();
4068 	clp = nfscl_findcl(nmp);
4069 	if (clp == NULL) {
4070 		NFSUNLOCKCLSTATE();
4071 		return (0);
4072 	}
4073 	nfsv4_getref(&clp->nfsc_lock, NULL, NFSCLSTATEMUTEXPTR, NULL);
4074 	NFSUNLOCKCLSTATE();
4075 	return (1);
4076 }
4077 
4078 /*
4079  * Release a reference on a clientid acquired with the above call.
4080  */
4081 APPLESTATIC void
4082 nfscl_relref(struct nfsmount *nmp)
4083 {
4084 	struct nfsclclient *clp;
4085 
4086 	NFSLOCKCLSTATE();
4087 	clp = nfscl_findcl(nmp);
4088 	if (clp == NULL) {
4089 		NFSUNLOCKCLSTATE();
4090 		return;
4091 	}
4092 	nfsv4_relref(&clp->nfsc_lock);
4093 	NFSUNLOCKCLSTATE();
4094 }
4095 
4096 /*
4097  * Save the size attribute in the delegation, since the nfsnode
4098  * is going away.
4099  */
4100 APPLESTATIC void
4101 nfscl_reclaimnode(vnode_t vp)
4102 {
4103 	struct nfsclclient *clp;
4104 	struct nfscldeleg *dp;
4105 	struct nfsnode *np = VTONFS(vp);
4106 	struct nfsmount *nmp;
4107 
4108 	nmp = VFSTONFS(vnode_mount(vp));
4109 	if (!NFSHASNFSV4(nmp))
4110 		return;
4111 	NFSLOCKCLSTATE();
4112 	clp = nfscl_findcl(nmp);
4113 	if (clp == NULL) {
4114 		NFSUNLOCKCLSTATE();
4115 		return;
4116 	}
4117 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
4118 	if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE))
4119 		dp->nfsdl_size = np->n_size;
4120 	NFSUNLOCKCLSTATE();
4121 }
4122 
4123 /*
4124  * Get the saved size attribute in the delegation, since it is a
4125  * newly allocated nfsnode.
4126  */
4127 APPLESTATIC void
4128 nfscl_newnode(vnode_t vp)
4129 {
4130 	struct nfsclclient *clp;
4131 	struct nfscldeleg *dp;
4132 	struct nfsnode *np = VTONFS(vp);
4133 	struct nfsmount *nmp;
4134 
4135 	nmp = VFSTONFS(vnode_mount(vp));
4136 	if (!NFSHASNFSV4(nmp))
4137 		return;
4138 	NFSLOCKCLSTATE();
4139 	clp = nfscl_findcl(nmp);
4140 	if (clp == NULL) {
4141 		NFSUNLOCKCLSTATE();
4142 		return;
4143 	}
4144 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
4145 	if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE))
4146 		np->n_size = dp->nfsdl_size;
4147 	NFSUNLOCKCLSTATE();
4148 }
4149 
4150 /*
4151  * If there is a valid write delegation for this file, set the modtime
4152  * to the local clock time.
4153  */
4154 APPLESTATIC void
4155 nfscl_delegmodtime(vnode_t vp)
4156 {
4157 	struct nfsclclient *clp;
4158 	struct nfscldeleg *dp;
4159 	struct nfsnode *np = VTONFS(vp);
4160 	struct nfsmount *nmp;
4161 
4162 	nmp = VFSTONFS(vnode_mount(vp));
4163 	if (!NFSHASNFSV4(nmp))
4164 		return;
4165 	NFSLOCKCLSTATE();
4166 	clp = nfscl_findcl(nmp);
4167 	if (clp == NULL) {
4168 		NFSUNLOCKCLSTATE();
4169 		return;
4170 	}
4171 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
4172 	if (dp != NULL && (dp->nfsdl_flags & NFSCLDL_WRITE)) {
4173 		NFSGETNANOTIME(&dp->nfsdl_modtime);
4174 		dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
4175 	}
4176 	NFSUNLOCKCLSTATE();
4177 }
4178 
4179 /*
4180  * If there is a valid write delegation for this file with a modtime set,
4181  * put that modtime in mtime.
4182  */
4183 APPLESTATIC void
4184 nfscl_deleggetmodtime(vnode_t vp, struct timespec *mtime)
4185 {
4186 	struct nfsclclient *clp;
4187 	struct nfscldeleg *dp;
4188 	struct nfsnode *np = VTONFS(vp);
4189 	struct nfsmount *nmp;
4190 
4191 	nmp = VFSTONFS(vnode_mount(vp));
4192 	if (!NFSHASNFSV4(nmp))
4193 		return;
4194 	NFSLOCKCLSTATE();
4195 	clp = nfscl_findcl(nmp);
4196 	if (clp == NULL) {
4197 		NFSUNLOCKCLSTATE();
4198 		return;
4199 	}
4200 	dp = nfscl_finddeleg(clp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len);
4201 	if (dp != NULL &&
4202 	    (dp->nfsdl_flags & (NFSCLDL_WRITE | NFSCLDL_MODTIMESET)) ==
4203 	    (NFSCLDL_WRITE | NFSCLDL_MODTIMESET))
4204 		*mtime = dp->nfsdl_modtime;
4205 	NFSUNLOCKCLSTATE();
4206 }
4207 
4208 static int
4209 nfscl_errmap(struct nfsrv_descript *nd)
4210 {
4211 	short *defaulterrp, *errp;
4212 
4213 	if (!nd->nd_repstat)
4214 		return (0);
4215 	if (nd->nd_procnum == NFSPROC_NOOP)
4216 		return (txdr_unsigned(nd->nd_repstat & 0xffff));
4217 	if (nd->nd_repstat == EBADRPC)
4218 		return (txdr_unsigned(NFSERR_BADXDR));
4219 	if (nd->nd_repstat == NFSERR_MINORVERMISMATCH ||
4220 	    nd->nd_repstat == NFSERR_OPILLEGAL)
4221 		return (txdr_unsigned(nd->nd_repstat));
4222 	errp = defaulterrp = nfscl_cberrmap[nd->nd_procnum];
4223 	while (*++errp)
4224 		if (*errp == (short)nd->nd_repstat)
4225 			return (txdr_unsigned(nd->nd_repstat));
4226 	return (txdr_unsigned(*defaulterrp));
4227 }
4228 
4229