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