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