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