]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - sys/fs/nfsserver/nfs_nfsdstate.c
MFC: r286790
[FreeBSD/stable/10.git] / sys / fs / nfsserver / nfs_nfsdstate.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 #ifndef APPLEKEXT
32 #include <fs/nfs/nfsport.h>
33
34 struct nfsrv_stablefirst nfsrv_stablefirst;
35 int nfsrv_issuedelegs = 0;
36 int nfsrv_dolocallocks = 0;
37 struct nfsv4lock nfsv4rootfs_lock;
38
39 extern int newnfs_numnfsd;
40 extern struct nfsstats newnfsstats;
41 extern int nfsrv_lease;
42 extern struct timeval nfsboottime;
43 extern u_int32_t newnfs_true, newnfs_false;
44 NFSV4ROOTLOCKMUTEX;
45 NFSSTATESPINLOCK;
46
47 SYSCTL_DECL(_vfs_nfsd);
48 int     nfsrv_statehashsize = NFSSTATEHASHSIZE;
49 TUNABLE_INT("vfs.nfsd.statehashsize", &nfsrv_statehashsize);
50 SYSCTL_INT(_vfs_nfsd, OID_AUTO, statehashsize, CTLFLAG_RDTUN,
51     &nfsrv_statehashsize, 0,
52     "Size of state hash table set via loader.conf");
53
54 int     nfsrv_clienthashsize = NFSCLIENTHASHSIZE;
55 TUNABLE_INT("vfs.nfsd.clienthashsize", &nfsrv_clienthashsize);
56 SYSCTL_INT(_vfs_nfsd, OID_AUTO, clienthashsize, CTLFLAG_RDTUN,
57     &nfsrv_clienthashsize, 0,
58     "Size of client hash table set via loader.conf");
59
60 int     nfsrv_lockhashsize = NFSLOCKHASHSIZE;
61 TUNABLE_INT("vfs.nfsd.fhhashsize", &nfsrv_lockhashsize);
62 SYSCTL_INT(_vfs_nfsd, OID_AUTO, fhhashsize, CTLFLAG_RDTUN,
63     &nfsrv_lockhashsize, 0,
64     "Size of file handle hash table set via loader.conf");
65
66 int     nfsrv_sessionhashsize = NFSSESSIONHASHSIZE;
67 TUNABLE_INT("vfs.nfsd.sessionhashsize", &nfsrv_sessionhashsize);
68 SYSCTL_INT(_vfs_nfsd, OID_AUTO, sessionhashsize, CTLFLAG_RDTUN,
69     &nfsrv_sessionhashsize, 0,
70     "Size of session hash table set via loader.conf");
71
72 static int      nfsrv_v4statelimit = NFSRV_V4STATELIMIT;
73 TUNABLE_INT("vfs.nfsd.v4statelimit", &nfsrv_v4statelimit);
74 SYSCTL_INT(_vfs_nfsd, OID_AUTO, v4statelimit, CTLFLAG_RWTUN,
75     &nfsrv_v4statelimit, 0,
76     "High water limit for NFSv4 opens+locks+delegations");
77
78 /*
79  * Hash lists for nfs V4.
80  */
81 struct nfsclienthashhead        *nfsclienthash;
82 struct nfslockhashhead          *nfslockhash;
83 struct nfssessionhash           *nfssessionhash;
84 #endif  /* !APPLEKEXT */
85
86 static u_int32_t nfsrv_openpluslock = 0, nfsrv_delegatecnt = 0;
87 static time_t nfsrvboottime;
88 static int nfsrv_writedelegifpos = 1;
89 static int nfsrv_returnoldstateid = 0, nfsrv_clients = 0;
90 static int nfsrv_clienthighwater = NFSRV_CLIENTHIGHWATER;
91 static int nfsrv_nogsscallback = 0;
92
93 /* local functions */
94 static void nfsrv_dumpaclient(struct nfsclient *clp,
95     struct nfsd_dumpclients *dumpp);
96 static void nfsrv_freeopenowner(struct nfsstate *stp, int cansleep,
97     NFSPROC_T *p);
98 static int nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep,
99     NFSPROC_T *p);
100 static void nfsrv_freelockowner(struct nfsstate *stp, vnode_t vp, int cansleep,
101     NFSPROC_T *p);
102 static void nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp,
103     int cansleep, NFSPROC_T *p);
104 static void nfsrv_freenfslock(struct nfslock *lop);
105 static void nfsrv_freenfslockfile(struct nfslockfile *lfp);
106 static void nfsrv_freedeleg(struct nfsstate *);
107 static int nfsrv_getstate(struct nfsclient *clp, nfsv4stateid_t *stateidp, 
108     u_int32_t flags, struct nfsstate **stpp);
109 static void nfsrv_getowner(struct nfsstatehead *hp, struct nfsstate *new_stp,
110     struct nfsstate **stpp);
111 static int nfsrv_getlockfh(vnode_t vp, u_short flags,
112     struct nfslockfile *new_lfp, fhandle_t *nfhp, NFSPROC_T *p);
113 static int nfsrv_getlockfile(u_short flags, struct nfslockfile **new_lfpp,
114     struct nfslockfile **lfpp, fhandle_t *nfhp, int lockit);
115 static void nfsrv_insertlock(struct nfslock *new_lop,
116     struct nfslock *insert_lop, struct nfsstate *stp, struct nfslockfile *lfp);
117 static void nfsrv_updatelock(struct nfsstate *stp, struct nfslock **new_lopp,
118     struct nfslock **other_lopp, struct nfslockfile *lfp);
119 static int nfsrv_getipnumber(u_char *cp);
120 static int nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags,
121     nfsv4stateid_t *stateidp, int specialid);
122 static int nfsrv_checkgrace(struct nfsrv_descript *nd, struct nfsclient *clp,
123     u_int32_t flags);
124 static int nfsrv_docallback(struct nfsclient *clp, int procnum,
125     nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp,
126     struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p);
127 static int nfsrv_cbcallargs(struct nfsrv_descript *nd, struct nfsclient *clp,
128     uint32_t callback, int op, const char *optag, struct nfsdsession **sepp);
129 static u_int32_t nfsrv_nextclientindex(void);
130 static u_int32_t nfsrv_nextstateindex(struct nfsclient *clp);
131 static void nfsrv_markstable(struct nfsclient *clp);
132 static int nfsrv_checkstable(struct nfsclient *clp);
133 static int nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, struct 
134     vnode *vp, NFSPROC_T *p);
135 static int nfsrv_delegconflict(struct nfsstate *stp, int *haslockp,
136     NFSPROC_T *p, vnode_t vp);
137 static int nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp,
138     struct nfsclient *clp, int *haslockp, NFSPROC_T *p);
139 static int nfsrv_notsamecredname(struct nfsrv_descript *nd,
140     struct nfsclient *clp);
141 static time_t nfsrv_leaseexpiry(void);
142 static void nfsrv_delaydelegtimeout(struct nfsstate *stp);
143 static int nfsrv_checkseqid(struct nfsrv_descript *nd, u_int32_t seqid,
144     struct nfsstate *stp, struct nfsrvcache *op);
145 static int nfsrv_nootherstate(struct nfsstate *stp);
146 static int nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags,
147     uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p);
148 static void nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp,
149     uint64_t init_first, uint64_t init_end, NFSPROC_T *p);
150 static int nfsrv_dolocal(vnode_t vp, struct nfslockfile *lfp, int flags,
151     int oldflags, uint64_t first, uint64_t end, struct nfslockconflict *cfp,
152     NFSPROC_T *p);
153 static void nfsrv_locallock_rollback(vnode_t vp, struct nfslockfile *lfp,
154     NFSPROC_T *p);
155 static void nfsrv_locallock_commit(struct nfslockfile *lfp, int flags,
156     uint64_t first, uint64_t end);
157 static void nfsrv_locklf(struct nfslockfile *lfp);
158 static void nfsrv_unlocklf(struct nfslockfile *lfp);
159 static struct nfsdsession *nfsrv_findsession(uint8_t *sessionid);
160 static int nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid);
161 static int nfsv4_setcbsequence(struct nfsrv_descript *nd, struct nfsclient *clp,
162     int dont_replycache, struct nfsdsession **sepp);
163 static int nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp);
164
165 /*
166  * Scan the client list for a match and either return the current one,
167  * create a new entry or return an error.
168  * If returning a non-error, the clp structure must either be linked into
169  * the client list or free'd.
170  */
171 APPLESTATIC int
172 nfsrv_setclient(struct nfsrv_descript *nd, struct nfsclient **new_clpp,
173     nfsquad_t *clientidp, nfsquad_t *confirmp, NFSPROC_T *p)
174 {
175         struct nfsclient *clp = NULL, *new_clp = *new_clpp;
176         int i, error = 0;
177         struct nfsstate *stp, *tstp;
178         struct sockaddr_in *sad, *rad;
179         int zapit = 0, gotit, hasstate = 0, igotlock;
180         static u_int64_t confirm_index = 0;
181
182         /*
183          * Check for state resource limit exceeded.
184          */
185         if (nfsrv_openpluslock > nfsrv_v4statelimit) {
186                 error = NFSERR_RESOURCE;
187                 goto out;
188         }
189
190         if (nfsrv_issuedelegs == 0 ||
191             ((nd->nd_flag & ND_GSS) != 0 && nfsrv_nogsscallback != 0))
192                 /*
193                  * Don't do callbacks when delegations are disabled or
194                  * for AUTH_GSS unless enabled via nfsrv_nogsscallback.
195                  * If establishing a callback connection is attempted
196                  * when a firewall is blocking the callback path, the
197                  * server may wait too long for the connect attempt to
198                  * succeed during the Open. Some clients, such as Linux,
199                  * may timeout and give up on the Open before the server
200                  * replies. Also, since AUTH_GSS callbacks are not
201                  * yet interoperability tested, they might cause the
202                  * server to crap out, if they get past the Init call to
203                  * the client.
204                  */
205                 new_clp->lc_program = 0;
206
207         /* Lock out other nfsd threads */
208         NFSLOCKV4ROOTMUTEX();
209         nfsv4_relref(&nfsv4rootfs_lock);
210         do {
211                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
212                     NFSV4ROOTLOCKMUTEXPTR, NULL);
213         } while (!igotlock);
214         NFSUNLOCKV4ROOTMUTEX();
215
216         /*
217          * Search for a match in the client list.
218          */
219         gotit = i = 0;
220         while (i < nfsrv_clienthashsize && !gotit) {
221             LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) {
222                 if (new_clp->lc_idlen == clp->lc_idlen &&
223                     !NFSBCMP(new_clp->lc_id, clp->lc_id, clp->lc_idlen)) {
224                         gotit = 1;
225                         break;
226                 }
227             }
228             if (gotit == 0)
229                 i++;
230         }
231         if (!gotit ||
232             (clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_ADMINREVOKED))) {
233                 if ((nd->nd_flag & ND_NFSV41) != 0 && confirmp->lval[1] != 0) {
234                         /*
235                          * For NFSv4.1, if confirmp->lval[1] is non-zero, the
236                          * client is trying to update a confirmed clientid.
237                          */
238                         NFSLOCKV4ROOTMUTEX();
239                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
240                         NFSUNLOCKV4ROOTMUTEX();
241                         confirmp->lval[1] = 0;
242                         error = NFSERR_NOENT;
243                         goto out;
244                 }
245                 /*
246                  * Get rid of the old one.
247                  */
248                 if (i != nfsrv_clienthashsize) {
249                         LIST_REMOVE(clp, lc_hash);
250                         nfsrv_cleanclient(clp, p);
251                         nfsrv_freedeleglist(&clp->lc_deleg);
252                         nfsrv_freedeleglist(&clp->lc_olddeleg);
253                         zapit = 1;
254                 }
255                 /*
256                  * Add it after assigning a client id to it.
257                  */
258                 new_clp->lc_flags |= LCL_NEEDSCONFIRM;
259                 if ((nd->nd_flag & ND_NFSV41) != 0)
260                         new_clp->lc_confirm.lval[0] = confirmp->lval[0] =
261                             ++confirm_index;
262                 else
263                         confirmp->qval = new_clp->lc_confirm.qval =
264                             ++confirm_index;
265                 clientidp->lval[0] = new_clp->lc_clientid.lval[0] =
266                     (u_int32_t)nfsrvboottime;
267                 clientidp->lval[1] = new_clp->lc_clientid.lval[1] =
268                     nfsrv_nextclientindex();
269                 new_clp->lc_stateindex = 0;
270                 new_clp->lc_statemaxindex = 0;
271                 new_clp->lc_cbref = 0;
272                 new_clp->lc_expiry = nfsrv_leaseexpiry();
273                 LIST_INIT(&new_clp->lc_open);
274                 LIST_INIT(&new_clp->lc_deleg);
275                 LIST_INIT(&new_clp->lc_olddeleg);
276                 LIST_INIT(&new_clp->lc_session);
277                 for (i = 0; i < nfsrv_statehashsize; i++)
278                         LIST_INIT(&new_clp->lc_stateid[i]);
279                 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp,
280                     lc_hash);
281                 newnfsstats.srvclients++;
282                 nfsrv_openpluslock++;
283                 nfsrv_clients++;
284                 NFSLOCKV4ROOTMUTEX();
285                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
286                 NFSUNLOCKV4ROOTMUTEX();
287                 if (zapit)
288                         nfsrv_zapclient(clp, p);
289                 *new_clpp = NULL;
290                 goto out;
291         }
292
293         /*
294          * Now, handle the cases where the id is already issued.
295          */
296         if (nfsrv_notsamecredname(nd, clp)) {
297             /*
298              * Check to see if there is expired state that should go away.
299              */
300             if (clp->lc_expiry < NFSD_MONOSEC &&
301                 (!LIST_EMPTY(&clp->lc_open) || !LIST_EMPTY(&clp->lc_deleg))) {
302                 nfsrv_cleanclient(clp, p);
303                 nfsrv_freedeleglist(&clp->lc_deleg);
304             }
305
306             /*
307              * If there is outstanding state, then reply NFSERR_CLIDINUSE per
308              * RFC3530 Sec. 8.1.2 last para.
309              */
310             if (!LIST_EMPTY(&clp->lc_deleg)) {
311                 hasstate = 1;
312             } else if (LIST_EMPTY(&clp->lc_open)) {
313                 hasstate = 0;
314             } else {
315                 hasstate = 0;
316                 /* Look for an Open on the OpenOwner */
317                 LIST_FOREACH(stp, &clp->lc_open, ls_list) {
318                     if (!LIST_EMPTY(&stp->ls_open)) {
319                         hasstate = 1;
320                         break;
321                     }
322                 }
323             }
324             if (hasstate) {
325                 /*
326                  * If the uid doesn't match, return NFSERR_CLIDINUSE after
327                  * filling out the correct ipaddr and portnum.
328                  */
329                 sad = NFSSOCKADDR(new_clp->lc_req.nr_nam, struct sockaddr_in *);
330                 rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
331                 sad->sin_addr.s_addr = rad->sin_addr.s_addr;
332                 sad->sin_port = rad->sin_port;
333                 NFSLOCKV4ROOTMUTEX();
334                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
335                 NFSUNLOCKV4ROOTMUTEX();
336                 error = NFSERR_CLIDINUSE;
337                 goto out;
338             }
339         }
340
341         if (NFSBCMP(new_clp->lc_verf, clp->lc_verf, NFSX_VERF)) {
342                 /*
343                  * If the verifier has changed, the client has rebooted
344                  * and a new client id is issued. The old state info
345                  * can be thrown away once the SETCLIENTID_CONFIRM occurs.
346                  */
347                 LIST_REMOVE(clp, lc_hash);
348                 new_clp->lc_flags |= LCL_NEEDSCONFIRM;
349                 if ((nd->nd_flag & ND_NFSV41) != 0)
350                         new_clp->lc_confirm.lval[0] = confirmp->lval[0] =
351                             ++confirm_index;
352                 else
353                         confirmp->qval = new_clp->lc_confirm.qval =
354                             ++confirm_index;
355                 clientidp->lval[0] = new_clp->lc_clientid.lval[0] =
356                     nfsrvboottime;
357                 clientidp->lval[1] = new_clp->lc_clientid.lval[1] =
358                     nfsrv_nextclientindex();
359                 new_clp->lc_stateindex = 0;
360                 new_clp->lc_statemaxindex = 0;
361                 new_clp->lc_cbref = 0;
362                 new_clp->lc_expiry = nfsrv_leaseexpiry();
363
364                 /*
365                  * Save the state until confirmed.
366                  */
367                 LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list);
368                 LIST_FOREACH(tstp, &new_clp->lc_open, ls_list)
369                         tstp->ls_clp = new_clp;
370                 LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list);
371                 LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list)
372                         tstp->ls_clp = new_clp;
373                 LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg,
374                     ls_list);
375                 LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list)
376                         tstp->ls_clp = new_clp;
377                 for (i = 0; i < nfsrv_statehashsize; i++) {
378                         LIST_NEWHEAD(&new_clp->lc_stateid[i],
379                             &clp->lc_stateid[i], ls_hash);
380                         LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash)
381                                 tstp->ls_clp = new_clp;
382                 }
383                 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp,
384                     lc_hash);
385                 newnfsstats.srvclients++;
386                 nfsrv_openpluslock++;
387                 nfsrv_clients++;
388                 NFSLOCKV4ROOTMUTEX();
389                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
390                 NFSUNLOCKV4ROOTMUTEX();
391
392                 /*
393                  * Must wait until any outstanding callback on the old clp
394                  * completes.
395                  */
396                 NFSLOCKSTATE();
397                 while (clp->lc_cbref) {
398                         clp->lc_flags |= LCL_WAKEUPWANTED;
399                         (void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1,
400                             "nfsd clp", 10 * hz);
401                 }
402                 NFSUNLOCKSTATE();
403                 nfsrv_zapclient(clp, p);
404                 *new_clpp = NULL;
405                 goto out;
406         }
407
408         /* For NFSv4.1, mark that we found a confirmed clientid. */
409         if ((nd->nd_flag & ND_NFSV41) != 0) {
410                 clientidp->lval[0] = clp->lc_clientid.lval[0];
411                 clientidp->lval[1] = clp->lc_clientid.lval[1];
412                 confirmp->lval[0] = 0;  /* Ignored by client */
413                 confirmp->lval[1] = 1;
414         } else {
415                 /*
416                  * id and verifier match, so update the net address info
417                  * and get rid of any existing callback authentication
418                  * handle, so a new one will be acquired.
419                  */
420                 LIST_REMOVE(clp, lc_hash);
421                 new_clp->lc_flags |= (LCL_NEEDSCONFIRM | LCL_DONTCLEAN);
422                 new_clp->lc_expiry = nfsrv_leaseexpiry();
423                 confirmp->qval = new_clp->lc_confirm.qval = ++confirm_index;
424                 clientidp->lval[0] = new_clp->lc_clientid.lval[0] =
425                     clp->lc_clientid.lval[0];
426                 clientidp->lval[1] = new_clp->lc_clientid.lval[1] =
427                     clp->lc_clientid.lval[1];
428                 new_clp->lc_delegtime = clp->lc_delegtime;
429                 new_clp->lc_stateindex = clp->lc_stateindex;
430                 new_clp->lc_statemaxindex = clp->lc_statemaxindex;
431                 new_clp->lc_cbref = 0;
432                 LIST_NEWHEAD(&new_clp->lc_open, &clp->lc_open, ls_list);
433                 LIST_FOREACH(tstp, &new_clp->lc_open, ls_list)
434                         tstp->ls_clp = new_clp;
435                 LIST_NEWHEAD(&new_clp->lc_deleg, &clp->lc_deleg, ls_list);
436                 LIST_FOREACH(tstp, &new_clp->lc_deleg, ls_list)
437                         tstp->ls_clp = new_clp;
438                 LIST_NEWHEAD(&new_clp->lc_olddeleg, &clp->lc_olddeleg, ls_list);
439                 LIST_FOREACH(tstp, &new_clp->lc_olddeleg, ls_list)
440                         tstp->ls_clp = new_clp;
441                 for (i = 0; i < nfsrv_statehashsize; i++) {
442                         LIST_NEWHEAD(&new_clp->lc_stateid[i],
443                             &clp->lc_stateid[i], ls_hash);
444                         LIST_FOREACH(tstp, &new_clp->lc_stateid[i], ls_hash)
445                                 tstp->ls_clp = new_clp;
446                 }
447                 LIST_INSERT_HEAD(NFSCLIENTHASH(new_clp->lc_clientid), new_clp,
448                     lc_hash);
449                 newnfsstats.srvclients++;
450                 nfsrv_openpluslock++;
451                 nfsrv_clients++;
452         }
453         NFSLOCKV4ROOTMUTEX();
454         nfsv4_unlock(&nfsv4rootfs_lock, 1);
455         NFSUNLOCKV4ROOTMUTEX();
456
457         if ((nd->nd_flag & ND_NFSV41) == 0) {
458                 /*
459                  * Must wait until any outstanding callback on the old clp
460                  * completes.
461                  */
462                 NFSLOCKSTATE();
463                 while (clp->lc_cbref) {
464                         clp->lc_flags |= LCL_WAKEUPWANTED;
465                         (void)mtx_sleep(clp, NFSSTATEMUTEXPTR, PZERO - 1,
466                             "nfsdclp", 10 * hz);
467                 }
468                 NFSUNLOCKSTATE();
469                 nfsrv_zapclient(clp, p);
470                 *new_clpp = NULL;
471         }
472
473 out:
474         NFSEXITCODE2(error, nd);
475         return (error);
476 }
477
478 /*
479  * Check to see if the client id exists and optionally confirm it.
480  */
481 APPLESTATIC int
482 nfsrv_getclient(nfsquad_t clientid, int opflags, struct nfsclient **clpp,
483     struct nfsdsession *nsep, nfsquad_t confirm, uint32_t cbprogram,
484     struct nfsrv_descript *nd, NFSPROC_T *p)
485 {
486         struct nfsclient *clp;
487         struct nfsstate *stp;
488         int i;
489         struct nfsclienthashhead *hp;
490         int error = 0, igotlock, doneok;
491         struct nfssessionhash *shp;
492         struct nfsdsession *sep;
493         uint64_t sessid[2];
494         static uint64_t next_sess = 0;
495
496         if (clpp)
497                 *clpp = NULL;
498         if ((nd == NULL || (nd->nd_flag & ND_NFSV41) == 0 ||
499             opflags != CLOPS_RENEW) && nfsrvboottime != clientid.lval[0]) {
500                 error = NFSERR_STALECLIENTID;
501                 goto out;
502         }
503
504         /*
505          * If called with opflags == CLOPS_RENEW, the State Lock is
506          * already held. Otherwise, we need to get either that or,
507          * for the case of Confirm, lock out the nfsd threads.
508          */
509         if (opflags & CLOPS_CONFIRM) {
510                 NFSLOCKV4ROOTMUTEX();
511                 nfsv4_relref(&nfsv4rootfs_lock);
512                 do {
513                         igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
514                             NFSV4ROOTLOCKMUTEXPTR, NULL);
515                 } while (!igotlock);
516                 /*
517                  * Create a new sessionid here, since we need to do it where
518                  * there is a mutex held to serialize update of next_sess.
519                  */
520                 if ((nd->nd_flag & ND_NFSV41) != 0) {
521                         sessid[0] = ++next_sess;
522                         sessid[1] = clientid.qval;
523                 }
524                 NFSUNLOCKV4ROOTMUTEX();
525         } else if (opflags != CLOPS_RENEW) {
526                 NFSLOCKSTATE();
527         }
528
529         /* For NFSv4.1, the clp is acquired from the associated session. */
530         if (nd != NULL && (nd->nd_flag & ND_NFSV41) != 0 &&
531             opflags == CLOPS_RENEW) {
532                 clp = NULL;
533                 if ((nd->nd_flag & ND_HASSEQUENCE) != 0) {
534                         shp = NFSSESSIONHASH(nd->nd_sessionid);
535                         NFSLOCKSESSION(shp);
536                         sep = nfsrv_findsession(nd->nd_sessionid);
537                         if (sep != NULL)
538                                 clp = sep->sess_clp;
539                         NFSUNLOCKSESSION(shp);
540                 }
541         } else {
542                 hp = NFSCLIENTHASH(clientid);
543                 LIST_FOREACH(clp, hp, lc_hash) {
544                         if (clp->lc_clientid.lval[1] == clientid.lval[1])
545                                 break;
546                 }
547         }
548         if (clp == NULL) {
549                 if (opflags & CLOPS_CONFIRM)
550                         error = NFSERR_STALECLIENTID;
551                 else
552                         error = NFSERR_EXPIRED;
553         } else if (clp->lc_flags & LCL_ADMINREVOKED) {
554                 /*
555                  * If marked admin revoked, just return the error.
556                  */
557                 error = NFSERR_ADMINREVOKED;
558         }
559         if (error) {
560                 if (opflags & CLOPS_CONFIRM) {
561                         NFSLOCKV4ROOTMUTEX();
562                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
563                         NFSUNLOCKV4ROOTMUTEX();
564                 } else if (opflags != CLOPS_RENEW) {
565                         NFSUNLOCKSTATE();
566                 }
567                 goto out;
568         }
569
570         /*
571          * Perform any operations specified by the opflags.
572          */
573         if (opflags & CLOPS_CONFIRM) {
574                 if (((nd->nd_flag & ND_NFSV41) != 0 &&
575                      clp->lc_confirm.lval[0] != confirm.lval[0]) ||
576                     ((nd->nd_flag & ND_NFSV41) == 0 &&
577                      clp->lc_confirm.qval != confirm.qval))
578                         error = NFSERR_STALECLIENTID;
579                 else if (nfsrv_notsamecredname(nd, clp))
580                         error = NFSERR_CLIDINUSE;
581
582                 if (!error) {
583                     if ((clp->lc_flags & (LCL_NEEDSCONFIRM | LCL_DONTCLEAN)) ==
584                         LCL_NEEDSCONFIRM) {
585                         /*
586                          * Hang onto the delegations (as old delegations)
587                          * for an Open with CLAIM_DELEGATE_PREV unless in
588                          * grace, but get rid of the rest of the state.
589                          */
590                         nfsrv_cleanclient(clp, p);
591                         nfsrv_freedeleglist(&clp->lc_olddeleg);
592                         if (nfsrv_checkgrace(nd, clp, 0)) {
593                             /* In grace, so just delete delegations */
594                             nfsrv_freedeleglist(&clp->lc_deleg);
595                         } else {
596                             LIST_FOREACH(stp, &clp->lc_deleg, ls_list)
597                                 stp->ls_flags |= NFSLCK_OLDDELEG;
598                             clp->lc_delegtime = NFSD_MONOSEC +
599                                 nfsrv_lease + NFSRV_LEASEDELTA;
600                             LIST_NEWHEAD(&clp->lc_olddeleg, &clp->lc_deleg,
601                                 ls_list);
602                         }
603                         if ((nd->nd_flag & ND_NFSV41) != 0)
604                             clp->lc_program = cbprogram;
605                     }
606                     clp->lc_flags &= ~(LCL_NEEDSCONFIRM | LCL_DONTCLEAN);
607                     if (clp->lc_program)
608                         clp->lc_flags |= LCL_NEEDSCBNULL;
609                     /* For NFSv4.1, link the session onto the client. */
610                     if (nsep != NULL) {
611                         /* Hold a reference on the xprt for a backchannel. */
612                         if ((nsep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN)
613                             != 0 && clp->lc_req.nr_client == NULL) {
614                             clp->lc_req.nr_client = (struct __rpc_client *)
615                                 clnt_bck_create(nd->nd_xprt->xp_socket,
616                                 cbprogram, NFSV4_CBVERS);
617                             if (clp->lc_req.nr_client != NULL) {
618                                 SVC_ACQUIRE(nd->nd_xprt);
619                                 nd->nd_xprt->xp_p2 =
620                                     clp->lc_req.nr_client->cl_private;
621                                 /* Disable idle timeout. */
622                                 nd->nd_xprt->xp_idletimeout = 0;
623                                 nsep->sess_cbsess.nfsess_xprt = nd->nd_xprt;
624                             } else
625                                 nsep->sess_crflags &= ~NFSV4CRSESS_CONNBACKCHAN;
626                         }
627                         NFSBCOPY(sessid, nsep->sess_sessionid,
628                             NFSX_V4SESSIONID);
629                         NFSBCOPY(sessid, nsep->sess_cbsess.nfsess_sessionid,
630                             NFSX_V4SESSIONID);
631                         shp = NFSSESSIONHASH(nsep->sess_sessionid);
632                         NFSLOCKSESSION(shp);
633                         LIST_INSERT_HEAD(&shp->list, nsep, sess_hash);
634                         NFSLOCKSTATE();
635                         LIST_INSERT_HEAD(&clp->lc_session, nsep, sess_list);
636                         nsep->sess_clp = clp;
637                         NFSUNLOCKSTATE();
638                         NFSUNLOCKSESSION(shp);
639                     }
640                 }
641         } else if (clp->lc_flags & LCL_NEEDSCONFIRM) {
642                 error = NFSERR_EXPIRED;
643         }
644
645         /*
646          * If called by the Renew Op, we must check the principal.
647          */
648         if (!error && (opflags & CLOPS_RENEWOP)) {
649             if (nfsrv_notsamecredname(nd, clp)) {
650                 doneok = 0;
651                 for (i = 0; i < nfsrv_statehashsize && doneok == 0; i++) {
652                     LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) {
653                         if ((stp->ls_flags & NFSLCK_OPEN) &&
654                             stp->ls_uid == nd->nd_cred->cr_uid) {
655                                 doneok = 1;
656                                 break;
657                         }
658                     }
659                 }
660                 if (!doneok)
661                         error = NFSERR_ACCES;
662             }
663             if (!error && (clp->lc_flags & LCL_CBDOWN))
664                 error = NFSERR_CBPATHDOWN;
665         }
666         if ((!error || error == NFSERR_CBPATHDOWN) &&
667              (opflags & CLOPS_RENEW)) {
668                 clp->lc_expiry = nfsrv_leaseexpiry();
669         }
670         if (opflags & CLOPS_CONFIRM) {
671                 NFSLOCKV4ROOTMUTEX();
672                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
673                 NFSUNLOCKV4ROOTMUTEX();
674         } else if (opflags != CLOPS_RENEW) {
675                 NFSUNLOCKSTATE();
676         }
677         if (clpp)
678                 *clpp = clp;
679
680 out:
681         NFSEXITCODE2(error, nd);
682         return (error);
683 }
684
685 /*
686  * Perform the NFSv4.1 destroy clientid.
687  */
688 int
689 nfsrv_destroyclient(nfsquad_t clientid, NFSPROC_T *p)
690 {
691         struct nfsclient *clp;
692         struct nfsclienthashhead *hp;
693         int error = 0, i, igotlock;
694
695         if (nfsrvboottime != clientid.lval[0]) {
696                 error = NFSERR_STALECLIENTID;
697                 goto out;
698         }
699
700         /* Lock out other nfsd threads */
701         NFSLOCKV4ROOTMUTEX();
702         nfsv4_relref(&nfsv4rootfs_lock);
703         do {
704                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
705                     NFSV4ROOTLOCKMUTEXPTR, NULL);
706         } while (igotlock == 0);
707         NFSUNLOCKV4ROOTMUTEX();
708
709         hp = NFSCLIENTHASH(clientid);
710         LIST_FOREACH(clp, hp, lc_hash) {
711                 if (clp->lc_clientid.lval[1] == clientid.lval[1])
712                         break;
713         }
714         if (clp == NULL) {
715                 NFSLOCKV4ROOTMUTEX();
716                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
717                 NFSUNLOCKV4ROOTMUTEX();
718                 /* Just return ok, since it is gone. */
719                 goto out;
720         }
721
722         /* Scan for state on the clientid. */
723         for (i = 0; i < nfsrv_statehashsize; i++)
724                 if (!LIST_EMPTY(&clp->lc_stateid[i])) {
725                         NFSLOCKV4ROOTMUTEX();
726                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
727                         NFSUNLOCKV4ROOTMUTEX();
728                         error = NFSERR_CLIENTIDBUSY;
729                         goto out;
730                 }
731         if (!LIST_EMPTY(&clp->lc_session) || !LIST_EMPTY(&clp->lc_deleg)) {
732                 NFSLOCKV4ROOTMUTEX();
733                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
734                 NFSUNLOCKV4ROOTMUTEX();
735                 error = NFSERR_CLIENTIDBUSY;
736                 goto out;
737         }
738
739         /* Destroy the clientid and return ok. */
740         nfsrv_cleanclient(clp, p);
741         nfsrv_freedeleglist(&clp->lc_deleg);
742         nfsrv_freedeleglist(&clp->lc_olddeleg);
743         LIST_REMOVE(clp, lc_hash);
744         NFSLOCKV4ROOTMUTEX();
745         nfsv4_unlock(&nfsv4rootfs_lock, 1);
746         NFSUNLOCKV4ROOTMUTEX();
747         nfsrv_zapclient(clp, p);
748 out:
749         NFSEXITCODE2(error, nd);
750         return (error);
751 }
752
753 /*
754  * Called from the new nfssvc syscall to admin revoke a clientid.
755  * Returns 0 for success, error otherwise.
756  */
757 APPLESTATIC int
758 nfsrv_adminrevoke(struct nfsd_clid *revokep, NFSPROC_T *p)
759 {
760         struct nfsclient *clp = NULL;
761         int i, error = 0;
762         int gotit, igotlock;
763
764         /*
765          * First, lock out the nfsd so that state won't change while the
766          * revocation record is being written to the stable storage restart
767          * file.
768          */
769         NFSLOCKV4ROOTMUTEX();
770         do {
771                 igotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
772                     NFSV4ROOTLOCKMUTEXPTR, NULL);
773         } while (!igotlock);
774         NFSUNLOCKV4ROOTMUTEX();
775
776         /*
777          * Search for a match in the client list.
778          */
779         gotit = i = 0;
780         while (i < nfsrv_clienthashsize && !gotit) {
781             LIST_FOREACH(clp, &nfsclienthash[i], lc_hash) {
782                 if (revokep->nclid_idlen == clp->lc_idlen &&
783                     !NFSBCMP(revokep->nclid_id, clp->lc_id, clp->lc_idlen)) {
784                         gotit = 1;
785                         break;
786                 }
787             }
788             i++;
789         }
790         if (!gotit) {
791                 NFSLOCKV4ROOTMUTEX();
792                 nfsv4_unlock(&nfsv4rootfs_lock, 0);
793                 NFSUNLOCKV4ROOTMUTEX();
794                 error = EPERM;
795                 goto out;
796         }
797
798         /*
799          * Now, write out the revocation record
800          */
801         nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p);
802         nfsrv_backupstable();
803
804         /*
805          * and clear out the state, marking the clientid revoked.
806          */
807         clp->lc_flags &= ~LCL_CALLBACKSON;
808         clp->lc_flags |= LCL_ADMINREVOKED;
809         nfsrv_cleanclient(clp, p);
810         nfsrv_freedeleglist(&clp->lc_deleg);
811         nfsrv_freedeleglist(&clp->lc_olddeleg);
812         NFSLOCKV4ROOTMUTEX();
813         nfsv4_unlock(&nfsv4rootfs_lock, 0);
814         NFSUNLOCKV4ROOTMUTEX();
815
816 out:
817         NFSEXITCODE(error);
818         return (error);
819 }
820
821 /*
822  * Dump out stats for all clients. Called from nfssvc(2), that is used
823  * newnfsstats.
824  */
825 APPLESTATIC void
826 nfsrv_dumpclients(struct nfsd_dumpclients *dumpp, int maxcnt)
827 {
828         struct nfsclient *clp;
829         int i = 0, cnt = 0;
830
831         /*
832          * First, get a reference on the nfsv4rootfs_lock so that an
833          * exclusive lock cannot be acquired while dumping the clients.
834          */
835         NFSLOCKV4ROOTMUTEX();
836         nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL);
837         NFSUNLOCKV4ROOTMUTEX();
838         NFSLOCKSTATE();
839         /*
840          * Rattle through the client lists until done.
841          */
842         while (i < nfsrv_clienthashsize && cnt < maxcnt) {
843             clp = LIST_FIRST(&nfsclienthash[i]);
844             while (clp != LIST_END(&nfsclienthash[i]) && cnt < maxcnt) {
845                 nfsrv_dumpaclient(clp, &dumpp[cnt]);
846                 cnt++;
847                 clp = LIST_NEXT(clp, lc_hash);
848             }
849             i++;
850         }
851         if (cnt < maxcnt)
852             dumpp[cnt].ndcl_clid.nclid_idlen = 0;
853         NFSUNLOCKSTATE();
854         NFSLOCKV4ROOTMUTEX();
855         nfsv4_relref(&nfsv4rootfs_lock);
856         NFSUNLOCKV4ROOTMUTEX();
857 }
858
859 /*
860  * Dump stats for a client. Must be called with the NFSSTATELOCK and spl'd.
861  */
862 static void
863 nfsrv_dumpaclient(struct nfsclient *clp, struct nfsd_dumpclients *dumpp)
864 {
865         struct nfsstate *stp, *openstp, *lckownstp;
866         struct nfslock *lop;
867         struct sockaddr *sad;
868         struct sockaddr_in *rad;
869         struct sockaddr_in6 *rad6;
870
871         dumpp->ndcl_nopenowners = dumpp->ndcl_nlockowners = 0;
872         dumpp->ndcl_nopens = dumpp->ndcl_nlocks = 0;
873         dumpp->ndcl_ndelegs = dumpp->ndcl_nolddelegs = 0;
874         dumpp->ndcl_flags = clp->lc_flags;
875         dumpp->ndcl_clid.nclid_idlen = clp->lc_idlen;
876         NFSBCOPY(clp->lc_id, dumpp->ndcl_clid.nclid_id, clp->lc_idlen);
877         sad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr *);
878         dumpp->ndcl_addrfam = sad->sa_family;
879         if (sad->sa_family == AF_INET) {
880                 rad = (struct sockaddr_in *)sad;
881                 dumpp->ndcl_cbaddr.sin_addr = rad->sin_addr;
882         } else {
883                 rad6 = (struct sockaddr_in6 *)sad;
884                 dumpp->ndcl_cbaddr.sin6_addr = rad6->sin6_addr;
885         }
886
887         /*
888          * Now, scan the state lists and total up the opens and locks.
889          */
890         LIST_FOREACH(stp, &clp->lc_open, ls_list) {
891             dumpp->ndcl_nopenowners++;
892             LIST_FOREACH(openstp, &stp->ls_open, ls_list) {
893                 dumpp->ndcl_nopens++;
894                 LIST_FOREACH(lckownstp, &openstp->ls_open, ls_list) {
895                     dumpp->ndcl_nlockowners++;
896                     LIST_FOREACH(lop, &lckownstp->ls_lock, lo_lckowner) {
897                         dumpp->ndcl_nlocks++;
898                     }
899                 }
900             }
901         }
902
903         /*
904          * and the delegation lists.
905          */
906         LIST_FOREACH(stp, &clp->lc_deleg, ls_list) {
907             dumpp->ndcl_ndelegs++;
908         }
909         LIST_FOREACH(stp, &clp->lc_olddeleg, ls_list) {
910             dumpp->ndcl_nolddelegs++;
911         }
912 }
913
914 /*
915  * Dump out lock stats for a file.
916  */
917 APPLESTATIC void
918 nfsrv_dumplocks(vnode_t vp, struct nfsd_dumplocks *ldumpp, int maxcnt,
919     NFSPROC_T *p)
920 {
921         struct nfsstate *stp;
922         struct nfslock *lop;
923         int cnt = 0;
924         struct nfslockfile *lfp;
925         struct sockaddr *sad;
926         struct sockaddr_in *rad;
927         struct sockaddr_in6 *rad6;
928         int ret;
929         fhandle_t nfh;
930
931         ret = nfsrv_getlockfh(vp, 0, NULL, &nfh, p);
932         /*
933          * First, get a reference on the nfsv4rootfs_lock so that an
934          * exclusive lock on it cannot be acquired while dumping the locks.
935          */
936         NFSLOCKV4ROOTMUTEX();
937         nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL);
938         NFSUNLOCKV4ROOTMUTEX();
939         NFSLOCKSTATE();
940         if (!ret)
941                 ret = nfsrv_getlockfile(0, NULL, &lfp, &nfh, 0);
942         if (ret) {
943                 ldumpp[0].ndlck_clid.nclid_idlen = 0;
944                 NFSUNLOCKSTATE();
945                 NFSLOCKV4ROOTMUTEX();
946                 nfsv4_relref(&nfsv4rootfs_lock);
947                 NFSUNLOCKV4ROOTMUTEX();
948                 return;
949         }
950
951         /*
952          * For each open share on file, dump it out.
953          */
954         stp = LIST_FIRST(&lfp->lf_open);
955         while (stp != LIST_END(&lfp->lf_open) && cnt < maxcnt) {
956                 ldumpp[cnt].ndlck_flags = stp->ls_flags;
957                 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid;
958                 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0];
959                 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1];
960                 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2];
961                 ldumpp[cnt].ndlck_owner.nclid_idlen =
962                     stp->ls_openowner->ls_ownerlen;
963                 NFSBCOPY(stp->ls_openowner->ls_owner,
964                     ldumpp[cnt].ndlck_owner.nclid_id,
965                     stp->ls_openowner->ls_ownerlen);
966                 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen;
967                 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id,
968                     stp->ls_clp->lc_idlen);
969                 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *);
970                 ldumpp[cnt].ndlck_addrfam = sad->sa_family;
971                 if (sad->sa_family == AF_INET) {
972                         rad = (struct sockaddr_in *)sad;
973                         ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr;
974                 } else {
975                         rad6 = (struct sockaddr_in6 *)sad;
976                         ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr;
977                 }
978                 stp = LIST_NEXT(stp, ls_file);
979                 cnt++;
980         }
981
982         /*
983          * and all locks.
984          */
985         lop = LIST_FIRST(&lfp->lf_lock);
986         while (lop != LIST_END(&lfp->lf_lock) && cnt < maxcnt) {
987                 stp = lop->lo_stp;
988                 ldumpp[cnt].ndlck_flags = lop->lo_flags;
989                 ldumpp[cnt].ndlck_first = lop->lo_first;
990                 ldumpp[cnt].ndlck_end = lop->lo_end;
991                 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid;
992                 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0];
993                 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1];
994                 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2];
995                 ldumpp[cnt].ndlck_owner.nclid_idlen = stp->ls_ownerlen;
996                 NFSBCOPY(stp->ls_owner, ldumpp[cnt].ndlck_owner.nclid_id,
997                     stp->ls_ownerlen);
998                 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen;
999                 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id,
1000                     stp->ls_clp->lc_idlen);
1001                 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *);
1002                 ldumpp[cnt].ndlck_addrfam = sad->sa_family;
1003                 if (sad->sa_family == AF_INET) {
1004                         rad = (struct sockaddr_in *)sad;
1005                         ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr;
1006                 } else {
1007                         rad6 = (struct sockaddr_in6 *)sad;
1008                         ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr;
1009                 }
1010                 lop = LIST_NEXT(lop, lo_lckfile);
1011                 cnt++;
1012         }
1013
1014         /*
1015          * and the delegations.
1016          */
1017         stp = LIST_FIRST(&lfp->lf_deleg);
1018         while (stp != LIST_END(&lfp->lf_deleg) && cnt < maxcnt) {
1019                 ldumpp[cnt].ndlck_flags = stp->ls_flags;
1020                 ldumpp[cnt].ndlck_stateid.seqid = stp->ls_stateid.seqid;
1021                 ldumpp[cnt].ndlck_stateid.other[0] = stp->ls_stateid.other[0];
1022                 ldumpp[cnt].ndlck_stateid.other[1] = stp->ls_stateid.other[1];
1023                 ldumpp[cnt].ndlck_stateid.other[2] = stp->ls_stateid.other[2];
1024                 ldumpp[cnt].ndlck_owner.nclid_idlen = 0;
1025                 ldumpp[cnt].ndlck_clid.nclid_idlen = stp->ls_clp->lc_idlen;
1026                 NFSBCOPY(stp->ls_clp->lc_id, ldumpp[cnt].ndlck_clid.nclid_id,
1027                     stp->ls_clp->lc_idlen);
1028                 sad=NFSSOCKADDR(stp->ls_clp->lc_req.nr_nam, struct sockaddr *);
1029                 ldumpp[cnt].ndlck_addrfam = sad->sa_family;
1030                 if (sad->sa_family == AF_INET) {
1031                         rad = (struct sockaddr_in *)sad;
1032                         ldumpp[cnt].ndlck_cbaddr.sin_addr = rad->sin_addr;
1033                 } else {
1034                         rad6 = (struct sockaddr_in6 *)sad;
1035                         ldumpp[cnt].ndlck_cbaddr.sin6_addr = rad6->sin6_addr;
1036                 }
1037                 stp = LIST_NEXT(stp, ls_file);
1038                 cnt++;
1039         }
1040
1041         /*
1042          * If list isn't full, mark end of list by setting the client name
1043          * to zero length.
1044          */
1045         if (cnt < maxcnt)
1046                 ldumpp[cnt].ndlck_clid.nclid_idlen = 0;
1047         NFSUNLOCKSTATE();
1048         NFSLOCKV4ROOTMUTEX();
1049         nfsv4_relref(&nfsv4rootfs_lock);
1050         NFSUNLOCKV4ROOTMUTEX();
1051 }
1052
1053 /*
1054  * Server timer routine. It can scan any linked list, so long
1055  * as it holds the spin/mutex lock and there is no exclusive lock on
1056  * nfsv4rootfs_lock.
1057  * (For OpenBSD, a kthread is ok. For FreeBSD, I think it is ok
1058  *  to do this from a callout, since the spin locks work. For
1059  *  Darwin, I'm not sure what will work correctly yet.)
1060  * Should be called once per second.
1061  */
1062 APPLESTATIC void
1063 nfsrv_servertimer(void)
1064 {
1065         struct nfsclient *clp, *nclp;
1066         struct nfsstate *stp, *nstp;
1067         int got_ref, i;
1068
1069         /*
1070          * Make sure nfsboottime is set. This is used by V3 as well
1071          * as V4. Note that nfsboottime is not nfsrvboottime, which is
1072          * only used by the V4 server for leases.
1073          */
1074         if (nfsboottime.tv_sec == 0)
1075                 NFSSETBOOTTIME(nfsboottime);
1076
1077         /*
1078          * If server hasn't started yet, just return.
1079          */
1080         NFSLOCKSTATE();
1081         if (nfsrv_stablefirst.nsf_eograce == 0) {
1082                 NFSUNLOCKSTATE();
1083                 return;
1084         }
1085         if (!(nfsrv_stablefirst.nsf_flags & NFSNSF_UPDATEDONE)) {
1086                 if (!(nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) &&
1087                     NFSD_MONOSEC > nfsrv_stablefirst.nsf_eograce)
1088                         nfsrv_stablefirst.nsf_flags |=
1089                             (NFSNSF_GRACEOVER | NFSNSF_NEEDLOCK);
1090                 NFSUNLOCKSTATE();
1091                 return;
1092         }
1093
1094         /*
1095          * Try and get a reference count on the nfsv4rootfs_lock so that
1096          * no nfsd thread can acquire an exclusive lock on it before this
1097          * call is done. If it is already exclusively locked, just return.
1098          */
1099         NFSLOCKV4ROOTMUTEX();
1100         got_ref = nfsv4_getref_nonblock(&nfsv4rootfs_lock);
1101         NFSUNLOCKV4ROOTMUTEX();
1102         if (got_ref == 0) {
1103                 NFSUNLOCKSTATE();
1104                 return;
1105         }
1106
1107         /*
1108          * For each client...
1109          */
1110         for (i = 0; i < nfsrv_clienthashsize; i++) {
1111             clp = LIST_FIRST(&nfsclienthash[i]);
1112             while (clp != LIST_END(&nfsclienthash[i])) {
1113                 nclp = LIST_NEXT(clp, lc_hash);
1114                 if (!(clp->lc_flags & LCL_EXPIREIT)) {
1115                     if (((clp->lc_expiry + NFSRV_STALELEASE) < NFSD_MONOSEC
1116                          && ((LIST_EMPTY(&clp->lc_deleg)
1117                               && LIST_EMPTY(&clp->lc_open)) ||
1118                              nfsrv_clients > nfsrv_clienthighwater)) ||
1119                         (clp->lc_expiry + NFSRV_MOULDYLEASE) < NFSD_MONOSEC ||
1120                         (clp->lc_expiry < NFSD_MONOSEC &&
1121                          (nfsrv_openpluslock * 10 / 9) > nfsrv_v4statelimit)) {
1122                         /*
1123                          * Lease has expired several nfsrv_lease times ago:
1124                          * PLUS
1125                          *    - no state is associated with it
1126                          *    OR
1127                          *    - above high water mark for number of clients
1128                          *      (nfsrv_clienthighwater should be large enough
1129                          *       that this only occurs when clients fail to
1130                          *       use the same nfs_client_id4.id. Maybe somewhat
1131                          *       higher that the maximum number of clients that
1132                          *       will mount this server?)
1133                          * OR
1134                          * Lease has expired a very long time ago
1135                          * OR
1136                          * Lease has expired PLUS the number of opens + locks
1137                          * has exceeded 90% of capacity
1138                          *
1139                          * --> Mark for expiry. The actual expiry will be done
1140                          *     by an nfsd sometime soon.
1141                          */
1142                         clp->lc_flags |= LCL_EXPIREIT;
1143                         nfsrv_stablefirst.nsf_flags |=
1144                             (NFSNSF_NEEDLOCK | NFSNSF_EXPIREDCLIENT);
1145                     } else {
1146                         /*
1147                          * If there are no opens, increment no open tick cnt
1148                          * If time exceeds NFSNOOPEN, mark it to be thrown away
1149                          * otherwise, if there is an open, reset no open time
1150                          * Hopefully, this will avoid excessive re-creation
1151                          * of open owners and subsequent open confirms.
1152                          */
1153                         stp = LIST_FIRST(&clp->lc_open);
1154                         while (stp != LIST_END(&clp->lc_open)) {
1155                                 nstp = LIST_NEXT(stp, ls_list);
1156                                 if (LIST_EMPTY(&stp->ls_open)) {
1157                                         stp->ls_noopens++;
1158                                         if (stp->ls_noopens > NFSNOOPEN ||
1159                                             (nfsrv_openpluslock * 2) >
1160                                             nfsrv_v4statelimit)
1161                                                 nfsrv_stablefirst.nsf_flags |=
1162                                                         NFSNSF_NOOPENS;
1163                                 } else {
1164                                         stp->ls_noopens = 0;
1165                                 }
1166                                 stp = nstp;
1167                         }
1168                     }
1169                 }
1170                 clp = nclp;
1171             }
1172         }
1173         NFSUNLOCKSTATE();
1174         NFSLOCKV4ROOTMUTEX();
1175         nfsv4_relref(&nfsv4rootfs_lock);
1176         NFSUNLOCKV4ROOTMUTEX();
1177 }
1178
1179 /*
1180  * The following set of functions free up the various data structures.
1181  */
1182 /*
1183  * Clear out all open/lock state related to this nfsclient.
1184  * Caller must hold an exclusive lock on nfsv4rootfs_lock, so that
1185  * there are no other active nfsd threads.
1186  */
1187 APPLESTATIC void
1188 nfsrv_cleanclient(struct nfsclient *clp, NFSPROC_T *p)
1189 {
1190         struct nfsstate *stp, *nstp;
1191         struct nfsdsession *sep, *nsep;
1192
1193         LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp)
1194                 nfsrv_freeopenowner(stp, 1, p);
1195         if ((clp->lc_flags & LCL_ADMINREVOKED) == 0)
1196                 LIST_FOREACH_SAFE(sep, &clp->lc_session, sess_list, nsep)
1197                         (void)nfsrv_freesession(sep, NULL);
1198 }
1199
1200 /*
1201  * Free a client that has been cleaned. It should also already have been
1202  * removed from the lists.
1203  * (Just to be safe w.r.t. newnfs_disconnect(), call this function when
1204  *  softclock interrupts are enabled.)
1205  */
1206 APPLESTATIC void
1207 nfsrv_zapclient(struct nfsclient *clp, NFSPROC_T *p)
1208 {
1209
1210 #ifdef notyet
1211         if ((clp->lc_flags & (LCL_GSS | LCL_CALLBACKSON)) ==
1212              (LCL_GSS | LCL_CALLBACKSON) &&
1213             (clp->lc_hand.nfsh_flag & NFSG_COMPLETE) &&
1214             clp->lc_handlelen > 0) {
1215                 clp->lc_hand.nfsh_flag &= ~NFSG_COMPLETE;
1216                 clp->lc_hand.nfsh_flag |= NFSG_DESTROYED;
1217                 (void) nfsrv_docallback(clp, NFSV4PROC_CBNULL,
1218                         NULL, 0, NULL, NULL, NULL, p);
1219         }
1220 #endif
1221         newnfs_disconnect(&clp->lc_req);
1222         NFSSOCKADDRFREE(clp->lc_req.nr_nam);
1223         NFSFREEMUTEX(&clp->lc_req.nr_mtx);
1224         free(clp->lc_stateid, M_NFSDCLIENT);
1225         free(clp, M_NFSDCLIENT);
1226         NFSLOCKSTATE();
1227         newnfsstats.srvclients--;
1228         nfsrv_openpluslock--;
1229         nfsrv_clients--;
1230         NFSUNLOCKSTATE();
1231 }
1232
1233 /*
1234  * Free a list of delegation state structures.
1235  * (This function will also free all nfslockfile structures that no
1236  *  longer have associated state.)
1237  */
1238 APPLESTATIC void
1239 nfsrv_freedeleglist(struct nfsstatehead *sthp)
1240 {
1241         struct nfsstate *stp, *nstp;
1242
1243         LIST_FOREACH_SAFE(stp, sthp, ls_list, nstp) {
1244                 nfsrv_freedeleg(stp);
1245         }
1246         LIST_INIT(sthp);
1247 }
1248
1249 /*
1250  * Free up a delegation.
1251  */
1252 static void
1253 nfsrv_freedeleg(struct nfsstate *stp)
1254 {
1255         struct nfslockfile *lfp;
1256
1257         LIST_REMOVE(stp, ls_hash);
1258         LIST_REMOVE(stp, ls_list);
1259         LIST_REMOVE(stp, ls_file);
1260         lfp = stp->ls_lfp;
1261         if (LIST_EMPTY(&lfp->lf_open) &&
1262             LIST_EMPTY(&lfp->lf_lock) && LIST_EMPTY(&lfp->lf_deleg) &&
1263             LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) &&
1264             lfp->lf_usecount == 0 &&
1265             nfsv4_testlock(&lfp->lf_locallock_lck) == 0)
1266                 nfsrv_freenfslockfile(lfp);
1267         FREE((caddr_t)stp, M_NFSDSTATE);
1268         newnfsstats.srvdelegates--;
1269         nfsrv_openpluslock--;
1270         nfsrv_delegatecnt--;
1271 }
1272
1273 /*
1274  * This function frees an open owner and all associated opens.
1275  */
1276 static void
1277 nfsrv_freeopenowner(struct nfsstate *stp, int cansleep, NFSPROC_T *p)
1278 {
1279         struct nfsstate *nstp, *tstp;
1280
1281         LIST_REMOVE(stp, ls_list);
1282         /*
1283          * Now, free all associated opens.
1284          */
1285         nstp = LIST_FIRST(&stp->ls_open);
1286         while (nstp != LIST_END(&stp->ls_open)) {
1287                 tstp = nstp;
1288                 nstp = LIST_NEXT(nstp, ls_list);
1289                 (void) nfsrv_freeopen(tstp, NULL, cansleep, p);
1290         }
1291         if (stp->ls_op)
1292                 nfsrvd_derefcache(stp->ls_op);
1293         FREE((caddr_t)stp, M_NFSDSTATE);
1294         newnfsstats.srvopenowners--;
1295         nfsrv_openpluslock--;
1296 }
1297
1298 /*
1299  * This function frees an open (nfsstate open structure) with all associated
1300  * lock_owners and locks. It also frees the nfslockfile structure iff there
1301  * are no other opens on the file.
1302  * Returns 1 if it free'd the nfslockfile, 0 otherwise.
1303  */
1304 static int
1305 nfsrv_freeopen(struct nfsstate *stp, vnode_t vp, int cansleep, NFSPROC_T *p)
1306 {
1307         struct nfsstate *nstp, *tstp;
1308         struct nfslockfile *lfp;
1309         int ret;
1310
1311         LIST_REMOVE(stp, ls_hash);
1312         LIST_REMOVE(stp, ls_list);
1313         LIST_REMOVE(stp, ls_file);
1314
1315         lfp = stp->ls_lfp;
1316         /*
1317          * Now, free all lockowners associated with this open.
1318          */
1319         LIST_FOREACH_SAFE(tstp, &stp->ls_open, ls_list, nstp)
1320                 nfsrv_freelockowner(tstp, vp, cansleep, p);
1321
1322         /*
1323          * The nfslockfile is freed here if there are no locks
1324          * associated with the open.
1325          * If there are locks associated with the open, the
1326          * nfslockfile structure can be freed via nfsrv_freelockowner().
1327          * Acquire the state mutex to avoid races with calls to
1328          * nfsrv_getlockfile().
1329          */
1330         if (cansleep != 0)
1331                 NFSLOCKSTATE();
1332         if (lfp != NULL && LIST_EMPTY(&lfp->lf_open) &&
1333             LIST_EMPTY(&lfp->lf_deleg) && LIST_EMPTY(&lfp->lf_lock) &&
1334             LIST_EMPTY(&lfp->lf_locallock) && LIST_EMPTY(&lfp->lf_rollback) &&
1335             lfp->lf_usecount == 0 &&
1336             (cansleep != 0 || nfsv4_testlock(&lfp->lf_locallock_lck) == 0)) {
1337                 nfsrv_freenfslockfile(lfp);
1338                 ret = 1;
1339         } else
1340                 ret = 0;
1341         if (cansleep != 0)
1342                 NFSUNLOCKSTATE();
1343         FREE((caddr_t)stp, M_NFSDSTATE);
1344         newnfsstats.srvopens--;
1345         nfsrv_openpluslock--;
1346         return (ret);
1347 }
1348
1349 /*
1350  * Frees a lockowner and all associated locks.
1351  */
1352 static void
1353 nfsrv_freelockowner(struct nfsstate *stp, vnode_t vp, int cansleep,
1354     NFSPROC_T *p)
1355 {
1356
1357         LIST_REMOVE(stp, ls_hash);
1358         LIST_REMOVE(stp, ls_list);
1359         nfsrv_freeallnfslocks(stp, vp, cansleep, p);
1360         if (stp->ls_op)
1361                 nfsrvd_derefcache(stp->ls_op);
1362         FREE((caddr_t)stp, M_NFSDSTATE);
1363         newnfsstats.srvlockowners--;
1364         nfsrv_openpluslock--;
1365 }
1366
1367 /*
1368  * Free all the nfs locks on a lockowner.
1369  */
1370 static void
1371 nfsrv_freeallnfslocks(struct nfsstate *stp, vnode_t vp, int cansleep,
1372     NFSPROC_T *p)
1373 {
1374         struct nfslock *lop, *nlop;
1375         struct nfsrollback *rlp, *nrlp;
1376         struct nfslockfile *lfp = NULL;
1377         int gottvp = 0;
1378         vnode_t tvp = NULL;
1379         uint64_t first, end;
1380
1381         if (vp != NULL)
1382                 ASSERT_VOP_UNLOCKED(vp, "nfsrv_freeallnfslocks: vnode locked");
1383         lop = LIST_FIRST(&stp->ls_lock);
1384         while (lop != LIST_END(&stp->ls_lock)) {
1385                 nlop = LIST_NEXT(lop, lo_lckowner);
1386                 /*
1387                  * Since all locks should be for the same file, lfp should
1388                  * not change.
1389                  */
1390                 if (lfp == NULL)
1391                         lfp = lop->lo_lfp;
1392                 else if (lfp != lop->lo_lfp)
1393                         panic("allnfslocks");
1394                 /*
1395                  * If vp is NULL and cansleep != 0, a vnode must be acquired
1396                  * from the file handle. This only occurs when called from
1397                  * nfsrv_cleanclient().
1398                  */
1399                 if (gottvp == 0) {
1400                         if (nfsrv_dolocallocks == 0)
1401                                 tvp = NULL;
1402                         else if (vp == NULL && cansleep != 0) {
1403                                 tvp = nfsvno_getvp(&lfp->lf_fh);
1404                                 NFSVOPUNLOCK(tvp, 0);
1405                         } else
1406                                 tvp = vp;
1407                         gottvp = 1;
1408                 }
1409
1410                 if (tvp != NULL) {
1411                         if (cansleep == 0)
1412                                 panic("allnfs2");
1413                         first = lop->lo_first;
1414                         end = lop->lo_end;
1415                         nfsrv_freenfslock(lop);
1416                         nfsrv_localunlock(tvp, lfp, first, end, p);
1417                         LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list,
1418                             nrlp)
1419                                 free(rlp, M_NFSDROLLBACK);
1420                         LIST_INIT(&lfp->lf_rollback);
1421                 } else
1422                         nfsrv_freenfslock(lop);
1423                 lop = nlop;
1424         }
1425         if (vp == NULL && tvp != NULL)
1426                 vrele(tvp);
1427 }
1428
1429 /*
1430  * Free an nfslock structure.
1431  */
1432 static void
1433 nfsrv_freenfslock(struct nfslock *lop)
1434 {
1435
1436         if (lop->lo_lckfile.le_prev != NULL) {
1437                 LIST_REMOVE(lop, lo_lckfile);
1438                 newnfsstats.srvlocks--;
1439                 nfsrv_openpluslock--;
1440         }
1441         LIST_REMOVE(lop, lo_lckowner);
1442         FREE((caddr_t)lop, M_NFSDLOCK);
1443 }
1444
1445 /*
1446  * This function frees an nfslockfile structure.
1447  */
1448 static void
1449 nfsrv_freenfslockfile(struct nfslockfile *lfp)
1450 {
1451
1452         LIST_REMOVE(lfp, lf_hash);
1453         FREE((caddr_t)lfp, M_NFSDLOCKFILE);
1454 }
1455
1456 /*
1457  * This function looks up an nfsstate structure via stateid.
1458  */
1459 static int
1460 nfsrv_getstate(struct nfsclient *clp, nfsv4stateid_t *stateidp, __unused u_int32_t flags,
1461     struct nfsstate **stpp)
1462 {
1463         struct nfsstate *stp;
1464         struct nfsstatehead *hp;
1465         int error = 0;
1466
1467         *stpp = NULL;
1468         hp = NFSSTATEHASH(clp, *stateidp);
1469         LIST_FOREACH(stp, hp, ls_hash) {
1470                 if (!NFSBCMP(stp->ls_stateid.other, stateidp->other,
1471                         NFSX_STATEIDOTHER))
1472                         break;
1473         }
1474
1475         /*
1476          * If no state id in list, return NFSERR_BADSTATEID.
1477          */
1478         if (stp == LIST_END(hp)) {
1479                 error = NFSERR_BADSTATEID;
1480                 goto out;
1481         }
1482         *stpp = stp;
1483
1484 out:
1485         NFSEXITCODE(error);
1486         return (error);
1487 }
1488
1489 /*
1490  * This function gets an nfsstate structure via owner string.
1491  */
1492 static void
1493 nfsrv_getowner(struct nfsstatehead *hp, struct nfsstate *new_stp,
1494     struct nfsstate **stpp)
1495 {
1496         struct nfsstate *stp;
1497
1498         *stpp = NULL;
1499         LIST_FOREACH(stp, hp, ls_list) {
1500                 if (new_stp->ls_ownerlen == stp->ls_ownerlen &&
1501                   !NFSBCMP(new_stp->ls_owner,stp->ls_owner,stp->ls_ownerlen)) {
1502                         *stpp = stp;
1503                         return;
1504                 }
1505         }
1506 }
1507
1508 /*
1509  * Lock control function called to update lock status.
1510  * Returns 0 upon success, -1 if there is no lock and the flags indicate
1511  * that one isn't to be created and an NFSERR_xxx for other errors.
1512  * The structures new_stp and new_lop are passed in as pointers that should
1513  * be set to NULL if the structure is used and shouldn't be free'd.
1514  * For the NFSLCK_TEST and NFSLCK_CHECK cases, the structures are
1515  * never used and can safely be allocated on the stack. For all other
1516  * cases, *new_stpp and *new_lopp should be malloc'd before the call,
1517  * in case they are used.
1518  */
1519 APPLESTATIC int
1520 nfsrv_lockctrl(vnode_t vp, struct nfsstate **new_stpp,
1521     struct nfslock **new_lopp, struct nfslockconflict *cfp,
1522     nfsquad_t clientid, nfsv4stateid_t *stateidp,
1523     __unused struct nfsexstuff *exp,
1524     struct nfsrv_descript *nd, NFSPROC_T *p)
1525 {
1526         struct nfslock *lop;
1527         struct nfsstate *new_stp = *new_stpp;
1528         struct nfslock *new_lop = *new_lopp;
1529         struct nfsstate *tstp, *mystp, *nstp;
1530         int specialid = 0;
1531         struct nfslockfile *lfp;
1532         struct nfslock *other_lop = NULL;
1533         struct nfsstate *stp, *lckstp = NULL;
1534         struct nfsclient *clp = NULL;
1535         u_int32_t bits;
1536         int error = 0, haslock = 0, ret, reterr;
1537         int getlckret, delegation = 0, filestruct_locked, vnode_unlocked = 0;
1538         fhandle_t nfh;
1539         uint64_t first, end;
1540         uint32_t lock_flags;
1541
1542         if (new_stp->ls_flags & (NFSLCK_CHECK | NFSLCK_SETATTR)) {
1543                 /*
1544                  * Note the special cases of "all 1s" or "all 0s" stateids and
1545                  * let reads with all 1s go ahead.
1546                  */
1547                 if (new_stp->ls_stateid.seqid == 0x0 &&
1548                     new_stp->ls_stateid.other[0] == 0x0 &&
1549                     new_stp->ls_stateid.other[1] == 0x0 &&
1550                     new_stp->ls_stateid.other[2] == 0x0)
1551                         specialid = 1;
1552                 else if (new_stp->ls_stateid.seqid == 0xffffffff &&
1553                     new_stp->ls_stateid.other[0] == 0xffffffff &&
1554                     new_stp->ls_stateid.other[1] == 0xffffffff &&
1555                     new_stp->ls_stateid.other[2] == 0xffffffff)
1556                         specialid = 2;
1557         }
1558
1559         /*
1560          * Check for restart conditions (client and server).
1561          */
1562         error = nfsrv_checkrestart(clientid, new_stp->ls_flags,
1563             &new_stp->ls_stateid, specialid);
1564         if (error)
1565                 goto out;
1566
1567         /*
1568          * Check for state resource limit exceeded.
1569          */
1570         if ((new_stp->ls_flags & NFSLCK_LOCK) &&
1571             nfsrv_openpluslock > nfsrv_v4statelimit) {
1572                 error = NFSERR_RESOURCE;
1573                 goto out;
1574         }
1575
1576         /*
1577          * For the lock case, get another nfslock structure,
1578          * just in case we need it.
1579          * Malloc now, before we start sifting through the linked lists,
1580          * in case we have to wait for memory.
1581          */
1582 tryagain:
1583         if (new_stp->ls_flags & NFSLCK_LOCK)
1584                 MALLOC(other_lop, struct nfslock *, sizeof (struct nfslock),
1585                     M_NFSDLOCK, M_WAITOK);
1586         filestruct_locked = 0;
1587         reterr = 0;
1588         lfp = NULL;
1589
1590         /*
1591          * Get the lockfile structure for CFH now, so we can do a sanity
1592          * check against the stateid, before incrementing the seqid#, since
1593          * we want to return NFSERR_BADSTATEID on failure and the seqid#
1594          * shouldn't be incremented for this case.
1595          * If nfsrv_getlockfile() returns -1, it means "not found", which
1596          * will be handled later.
1597          * If we are doing Lock/LockU and local locking is enabled, sleep
1598          * lock the nfslockfile structure.
1599          */
1600         getlckret = nfsrv_getlockfh(vp, new_stp->ls_flags, NULL, &nfh, p);
1601         NFSLOCKSTATE();
1602         if (getlckret == 0) {
1603                 if ((new_stp->ls_flags & (NFSLCK_LOCK | NFSLCK_UNLOCK)) != 0 &&
1604                     nfsrv_dolocallocks != 0 && nd->nd_repstat == 0) {
1605                         getlckret = nfsrv_getlockfile(new_stp->ls_flags, NULL,
1606                             &lfp, &nfh, 1);
1607                         if (getlckret == 0)
1608                                 filestruct_locked = 1;
1609                 } else
1610                         getlckret = nfsrv_getlockfile(new_stp->ls_flags, NULL,
1611                             &lfp, &nfh, 0);
1612         }
1613         if (getlckret != 0 && getlckret != -1)
1614                 reterr = getlckret;
1615
1616         if (filestruct_locked != 0) {
1617                 LIST_INIT(&lfp->lf_rollback);
1618                 if ((new_stp->ls_flags & NFSLCK_LOCK)) {
1619                         /*
1620                          * For local locking, do the advisory locking now, so
1621                          * that any conflict can be detected. A failure later
1622                          * can be rolled back locally. If an error is returned,
1623                          * struct nfslockfile has been unlocked and any local
1624                          * locking rolled back.
1625                          */
1626                         NFSUNLOCKSTATE();
1627                         if (vnode_unlocked == 0) {
1628                                 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl1");
1629                                 vnode_unlocked = 1;
1630                                 NFSVOPUNLOCK(vp, 0);
1631                         }
1632                         reterr = nfsrv_locallock(vp, lfp,
1633                             (new_lop->lo_flags & (NFSLCK_READ | NFSLCK_WRITE)),
1634                             new_lop->lo_first, new_lop->lo_end, cfp, p);
1635                         NFSLOCKSTATE();
1636                 }
1637         }
1638
1639         if (specialid == 0) {
1640             if (new_stp->ls_flags & NFSLCK_TEST) {
1641                 /*
1642                  * RFC 3530 does not list LockT as an op that renews a
1643                  * lease, but the concensus seems to be that it is ok
1644                  * for a server to do so.
1645                  */
1646                 error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
1647                     (nfsquad_t)((u_quad_t)0), 0, nd, p);
1648
1649                 /*
1650                  * Since NFSERR_EXPIRED, NFSERR_ADMINREVOKED are not valid
1651                  * error returns for LockT, just go ahead and test for a lock,
1652                  * since there are no locks for this client, but other locks
1653                  * can conflict. (ie. same client will always be false)
1654                  */
1655                 if (error == NFSERR_EXPIRED || error == NFSERR_ADMINREVOKED)
1656                     error = 0;
1657                 lckstp = new_stp;
1658             } else {
1659               error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
1660                 (nfsquad_t)((u_quad_t)0), 0, nd, p);
1661               if (error == 0)
1662                 /*
1663                  * Look up the stateid
1664                  */
1665                 error = nfsrv_getstate(clp, &new_stp->ls_stateid,
1666                   new_stp->ls_flags, &stp);
1667               /*
1668                * do some sanity checks for an unconfirmed open or a
1669                * stateid that refers to the wrong file, for an open stateid
1670                */
1671               if (error == 0 && (stp->ls_flags & NFSLCK_OPEN) &&
1672                   ((stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM) ||
1673                    (getlckret == 0 && stp->ls_lfp != lfp)))
1674                         error = NFSERR_BADSTATEID;
1675               if (error == 0 &&
1676                   (stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) &&
1677                   getlckret == 0 && stp->ls_lfp != lfp)
1678                         error = NFSERR_BADSTATEID;
1679
1680               /*
1681                * If the lockowner stateid doesn't refer to the same file,
1682                * I believe that is considered ok, since some clients will
1683                * only create a single lockowner and use that for all locks
1684                * on all files.
1685                * For now, log it as a diagnostic, instead of considering it
1686                * a BadStateid.
1687                */
1688               if (error == 0 && (stp->ls_flags &
1689                   (NFSLCK_OPEN | NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) == 0 &&
1690                   getlckret == 0 && stp->ls_lfp != lfp) {
1691 #ifdef DIAGNOSTIC
1692                   printf("Got a lock statid for different file open\n");
1693 #endif
1694                   /*
1695                   error = NFSERR_BADSTATEID;
1696                   */
1697               }
1698
1699               if (error == 0) {
1700                     if (new_stp->ls_flags & NFSLCK_OPENTOLOCK) {
1701                         /*
1702                          * If haslock set, we've already checked the seqid.
1703                          */
1704                         if (!haslock) {
1705                             if (stp->ls_flags & NFSLCK_OPEN)
1706                                 error = nfsrv_checkseqid(nd, new_stp->ls_seq,
1707                                     stp->ls_openowner, new_stp->ls_op);
1708                             else
1709                                 error = NFSERR_BADSTATEID;
1710                         }
1711                         if (!error)
1712                             nfsrv_getowner(&stp->ls_open, new_stp, &lckstp);
1713                         if (lckstp)
1714                             /*
1715                              * I believe this should be an error, but it
1716                              * isn't obvious what NFSERR_xxx would be
1717                              * appropriate, so I'll use NFSERR_INVAL for now.
1718                              */
1719                             error = NFSERR_INVAL;
1720                         else
1721                             lckstp = new_stp;
1722                     } else if (new_stp->ls_flags&(NFSLCK_LOCK|NFSLCK_UNLOCK)) {
1723                         /*
1724                          * If haslock set, ditto above.
1725                          */
1726                         if (!haslock) {
1727                             if (stp->ls_flags & NFSLCK_OPEN)
1728                                 error = NFSERR_BADSTATEID;
1729                             else
1730                                 error = nfsrv_checkseqid(nd, new_stp->ls_seq,
1731                                     stp, new_stp->ls_op);
1732                         }
1733                         lckstp = stp;
1734                     } else {
1735                         lckstp = stp;
1736                     }
1737               }
1738               /*
1739                * If the seqid part of the stateid isn't the same, return
1740                * NFSERR_OLDSTATEID for cases other than I/O Ops.
1741                * For I/O Ops, only return NFSERR_OLDSTATEID if
1742                * nfsrv_returnoldstateid is set. (The concensus on the email
1743                * list was that most clients would prefer to not receive
1744                * NFSERR_OLDSTATEID for I/O Ops, but the RFC suggests that that
1745                * is what will happen, so I use the nfsrv_returnoldstateid to
1746                * allow for either server configuration.)
1747                */
1748               if (!error && stp->ls_stateid.seqid!=new_stp->ls_stateid.seqid &&
1749                   (((nd->nd_flag & ND_NFSV41) == 0 &&
1750                    (!(new_stp->ls_flags & NFSLCK_CHECK) ||
1751                     nfsrv_returnoldstateid)) ||
1752                    ((nd->nd_flag & ND_NFSV41) != 0 &&
1753                     new_stp->ls_stateid.seqid != 0)))
1754                     error = NFSERR_OLDSTATEID;
1755             }
1756         }
1757
1758         /*
1759          * Now we can check for grace.
1760          */
1761         if (!error)
1762                 error = nfsrv_checkgrace(nd, clp, new_stp->ls_flags);
1763         if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error &&
1764                 nfsrv_checkstable(clp))
1765                 error = NFSERR_NOGRACE;
1766         /*
1767          * If we successfully Reclaimed state, note that.
1768          */
1769         if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error)
1770                 nfsrv_markstable(clp);
1771
1772         /*
1773          * At this point, either error == NFSERR_BADSTATEID or the
1774          * seqid# has been updated, so we can return any error.
1775          * If error == 0, there may be an error in:
1776          *    nd_repstat - Set by the calling function.
1777          *    reterr - Set above, if getting the nfslockfile structure
1778          *       or acquiring the local lock failed.
1779          *    (If both of these are set, nd_repstat should probably be
1780          *     returned, since that error was detected before this
1781          *     function call.)
1782          */
1783         if (error != 0 || nd->nd_repstat != 0 || reterr != 0) {
1784                 if (error == 0) {
1785                         if (nd->nd_repstat != 0)
1786                                 error = nd->nd_repstat;
1787                         else
1788                                 error = reterr;
1789                 }
1790                 if (filestruct_locked != 0) {
1791                         /* Roll back local locks. */
1792                         NFSUNLOCKSTATE();
1793                         if (vnode_unlocked == 0) {
1794                                 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl2");
1795                                 vnode_unlocked = 1;
1796                                 NFSVOPUNLOCK(vp, 0);
1797                         }
1798                         nfsrv_locallock_rollback(vp, lfp, p);
1799                         NFSLOCKSTATE();
1800                         nfsrv_unlocklf(lfp);
1801                 }
1802                 NFSUNLOCKSTATE();
1803                 goto out;
1804         }
1805
1806         /*
1807          * Check the nfsrv_getlockfile return.
1808          * Returned -1 if no structure found.
1809          */
1810         if (getlckret == -1) {
1811                 error = NFSERR_EXPIRED;
1812                 /*
1813                  * Called from lockt, so no lock is OK.
1814                  */
1815                 if (new_stp->ls_flags & NFSLCK_TEST) {
1816                         error = 0;
1817                 } else if (new_stp->ls_flags &
1818                     (NFSLCK_CHECK | NFSLCK_SETATTR)) {
1819                         /*
1820                          * Called to check for a lock, OK if the stateid is all
1821                          * 1s or all 0s, but there should be an nfsstate
1822                          * otherwise.
1823                          * (ie. If there is no open, I'll assume no share
1824                          *  deny bits.)
1825                          */
1826                         if (specialid)
1827                                 error = 0;
1828                         else
1829                                 error = NFSERR_BADSTATEID;
1830                 }
1831                 NFSUNLOCKSTATE();
1832                 goto out;
1833         }
1834
1835         /*
1836          * For NFSLCK_CHECK and NFSLCK_LOCK, test for a share conflict.
1837          * For NFSLCK_CHECK, allow a read if write access is granted,
1838          * but check for a deny. For NFSLCK_LOCK, require correct access,
1839          * which implies a conflicting deny can't exist.
1840          */
1841         if (new_stp->ls_flags & (NFSLCK_CHECK | NFSLCK_LOCK)) {
1842             /*
1843              * Four kinds of state id:
1844              * - specialid (all 0s or all 1s), only for NFSLCK_CHECK
1845              * - stateid for an open
1846              * - stateid for a delegation
1847              * - stateid for a lock owner
1848              */
1849             if (!specialid) {
1850                 if (stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) {
1851                     delegation = 1;
1852                     mystp = stp;
1853                     nfsrv_delaydelegtimeout(stp);
1854                 } else if (stp->ls_flags & NFSLCK_OPEN) {
1855                     mystp = stp;
1856                 } else {
1857                     mystp = stp->ls_openstp;
1858                 }
1859                 /*
1860                  * If locking or checking, require correct access
1861                  * bit set.
1862                  */
1863                 if (((new_stp->ls_flags & NFSLCK_LOCK) &&
1864                      !((new_lop->lo_flags >> NFSLCK_LOCKSHIFT) &
1865                        mystp->ls_flags & NFSLCK_ACCESSBITS)) ||
1866                     ((new_stp->ls_flags & (NFSLCK_CHECK|NFSLCK_READACCESS)) ==
1867                       (NFSLCK_CHECK | NFSLCK_READACCESS) &&
1868                      !(mystp->ls_flags & NFSLCK_READACCESS)) ||
1869                     ((new_stp->ls_flags & (NFSLCK_CHECK|NFSLCK_WRITEACCESS)) ==
1870                       (NFSLCK_CHECK | NFSLCK_WRITEACCESS) &&
1871                      !(mystp->ls_flags & NFSLCK_WRITEACCESS))) {
1872                         if (filestruct_locked != 0) {
1873                                 /* Roll back local locks. */
1874                                 NFSUNLOCKSTATE();
1875                                 if (vnode_unlocked == 0) {
1876                                         ASSERT_VOP_ELOCKED(vp,
1877                                             "nfsrv_lockctrl3");
1878                                         vnode_unlocked = 1;
1879                                         NFSVOPUNLOCK(vp, 0);
1880                                 }
1881                                 nfsrv_locallock_rollback(vp, lfp, p);
1882                                 NFSLOCKSTATE();
1883                                 nfsrv_unlocklf(lfp);
1884                         }
1885                         NFSUNLOCKSTATE();
1886                         error = NFSERR_OPENMODE;
1887                         goto out;
1888                 }
1889             } else
1890                 mystp = NULL;
1891             if ((new_stp->ls_flags & NFSLCK_CHECK) && !delegation) {
1892                 /*
1893                  * Check for a conflicting deny bit.
1894                  */
1895                 LIST_FOREACH(tstp, &lfp->lf_open, ls_file) {
1896                     if (tstp != mystp) {
1897                         bits = tstp->ls_flags;
1898                         bits >>= NFSLCK_SHIFT;
1899                         if (new_stp->ls_flags & bits & NFSLCK_ACCESSBITS) {
1900                             KASSERT(vnode_unlocked == 0,
1901                                 ("nfsrv_lockctrl: vnode unlocked1"));
1902                             ret = nfsrv_clientconflict(tstp->ls_clp, &haslock,
1903                                 vp, p);
1904                             if (ret == 1) {
1905                                 /*
1906                                 * nfsrv_clientconflict unlocks state
1907                                  * when it returns non-zero.
1908                                  */
1909                                 lckstp = NULL;
1910                                 goto tryagain;
1911                             }
1912                             if (ret == 0)
1913                                 NFSUNLOCKSTATE();
1914                             if (ret == 2)
1915                                 error = NFSERR_PERM;
1916                             else
1917                                 error = NFSERR_OPENMODE;
1918                             goto out;
1919                         }
1920                     }
1921                 }
1922
1923                 /* We're outta here */
1924                 NFSUNLOCKSTATE();
1925                 goto out;
1926             }
1927         }
1928
1929         /*
1930          * For setattr, just get rid of all the Delegations for other clients.
1931          */
1932         if (new_stp->ls_flags & NFSLCK_SETATTR) {
1933                 KASSERT(vnode_unlocked == 0,
1934                     ("nfsrv_lockctrl: vnode unlocked2"));
1935                 ret = nfsrv_cleandeleg(vp, lfp, clp, &haslock, p);
1936                 if (ret) {
1937                         /*
1938                          * nfsrv_cleandeleg() unlocks state when it
1939                          * returns non-zero.
1940                          */
1941                         if (ret == -1) {
1942                                 lckstp = NULL;
1943                                 goto tryagain;
1944                         }
1945                         error = ret;
1946                         goto out;
1947                 }
1948                 if (!(new_stp->ls_flags & NFSLCK_CHECK) ||
1949                     (LIST_EMPTY(&lfp->lf_open) && LIST_EMPTY(&lfp->lf_lock) &&
1950                      LIST_EMPTY(&lfp->lf_deleg))) {
1951                         NFSUNLOCKSTATE();
1952                         goto out;
1953                 }
1954         }
1955
1956         /*
1957          * Check for a conflicting delegation. If one is found, call
1958          * nfsrv_delegconflict() to handle it. If the v4root lock hasn't
1959          * been set yet, it will get the lock. Otherwise, it will recall
1960          * the delegation. Then, we try try again...
1961          * I currently believe the conflict algorithm to be:
1962          * For Lock Ops (Lock/LockT/LockU)
1963          * - there is a conflict iff a different client has a write delegation
1964          * For Reading (Read Op)
1965          * - there is a conflict iff a different client has a write delegation
1966          *   (the specialids are always a different client)
1967          * For Writing (Write/Setattr of size)
1968          * - there is a conflict if a different client has any delegation
1969          * - there is a conflict if the same client has a read delegation
1970          *   (I don't understand why this isn't allowed, but that seems to be
1971          *    the current concensus?)
1972          */
1973         tstp = LIST_FIRST(&lfp->lf_deleg);
1974         while (tstp != LIST_END(&lfp->lf_deleg)) {
1975             nstp = LIST_NEXT(tstp, ls_file);
1976             if ((((new_stp->ls_flags&(NFSLCK_LOCK|NFSLCK_UNLOCK|NFSLCK_TEST))||
1977                  ((new_stp->ls_flags & NFSLCK_CHECK) &&
1978                   (new_lop->lo_flags & NFSLCK_READ))) &&
1979                   clp != tstp->ls_clp &&
1980                  (tstp->ls_flags & NFSLCK_DELEGWRITE)) ||
1981                  ((new_stp->ls_flags & NFSLCK_CHECK) &&
1982                    (new_lop->lo_flags & NFSLCK_WRITE) &&
1983                   (clp != tstp->ls_clp ||
1984                    (tstp->ls_flags & NFSLCK_DELEGREAD)))) {
1985                 ret = 0;
1986                 if (filestruct_locked != 0) {
1987                         /* Roll back local locks. */
1988                         NFSUNLOCKSTATE();
1989                         if (vnode_unlocked == 0) {
1990                                 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl4");
1991                                 NFSVOPUNLOCK(vp, 0);
1992                         }
1993                         nfsrv_locallock_rollback(vp, lfp, p);
1994                         NFSLOCKSTATE();
1995                         nfsrv_unlocklf(lfp);
1996                         NFSUNLOCKSTATE();
1997                         NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
1998                         vnode_unlocked = 0;
1999                         if ((vp->v_iflag & VI_DOOMED) != 0)
2000                                 ret = NFSERR_SERVERFAULT;
2001                         NFSLOCKSTATE();
2002                 }
2003                 if (ret == 0)
2004                         ret = nfsrv_delegconflict(tstp, &haslock, p, vp);
2005                 if (ret) {
2006                     /*
2007                      * nfsrv_delegconflict unlocks state when it
2008                      * returns non-zero, which it always does.
2009                      */
2010                     if (other_lop) {
2011                         FREE((caddr_t)other_lop, M_NFSDLOCK);
2012                         other_lop = NULL;
2013                     }
2014                     if (ret == -1) {
2015                         lckstp = NULL;
2016                         goto tryagain;
2017                     }
2018                     error = ret;
2019                     goto out;
2020                 }
2021                 /* Never gets here. */
2022             }
2023             tstp = nstp;
2024         }
2025
2026         /*
2027          * Handle the unlock case by calling nfsrv_updatelock().
2028          * (Should I have done some access checking above for unlock? For now,
2029          *  just let it happen.)
2030          */
2031         if (new_stp->ls_flags & NFSLCK_UNLOCK) {
2032                 first = new_lop->lo_first;
2033                 end = new_lop->lo_end;
2034                 nfsrv_updatelock(stp, new_lopp, &other_lop, lfp);
2035                 stateidp->seqid = ++(stp->ls_stateid.seqid);
2036                 if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0)
2037                         stateidp->seqid = stp->ls_stateid.seqid = 1;
2038                 stateidp->other[0] = stp->ls_stateid.other[0];
2039                 stateidp->other[1] = stp->ls_stateid.other[1];
2040                 stateidp->other[2] = stp->ls_stateid.other[2];
2041                 if (filestruct_locked != 0) {
2042                         NFSUNLOCKSTATE();
2043                         if (vnode_unlocked == 0) {
2044                                 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl5");
2045                                 vnode_unlocked = 1;
2046                                 NFSVOPUNLOCK(vp, 0);
2047                         }
2048                         /* Update the local locks. */
2049                         nfsrv_localunlock(vp, lfp, first, end, p);
2050                         NFSLOCKSTATE();
2051                         nfsrv_unlocklf(lfp);
2052                 }
2053                 NFSUNLOCKSTATE();
2054                 goto out;
2055         }
2056
2057         /*
2058          * Search for a conflicting lock. A lock conflicts if:
2059          * - the lock range overlaps and
2060          * - at least one lock is a write lock and
2061          * - it is not owned by the same lock owner
2062          */
2063         if (!delegation) {
2064           LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) {
2065             if (new_lop->lo_end > lop->lo_first &&
2066                 new_lop->lo_first < lop->lo_end &&
2067                 (new_lop->lo_flags == NFSLCK_WRITE ||
2068                  lop->lo_flags == NFSLCK_WRITE) &&
2069                 lckstp != lop->lo_stp &&
2070                 (clp != lop->lo_stp->ls_clp ||
2071                  lckstp->ls_ownerlen != lop->lo_stp->ls_ownerlen ||
2072                  NFSBCMP(lckstp->ls_owner, lop->lo_stp->ls_owner,
2073                     lckstp->ls_ownerlen))) {
2074                 if (other_lop) {
2075                     FREE((caddr_t)other_lop, M_NFSDLOCK);
2076                     other_lop = NULL;
2077                 }
2078                 if (vnode_unlocked != 0)
2079                     ret = nfsrv_clientconflict(lop->lo_stp->ls_clp, &haslock,
2080                         NULL, p);
2081                 else
2082                     ret = nfsrv_clientconflict(lop->lo_stp->ls_clp, &haslock,
2083                         vp, p);
2084                 if (ret == 1) {
2085                     if (filestruct_locked != 0) {
2086                         if (vnode_unlocked == 0) {
2087                                 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl6");
2088                                 NFSVOPUNLOCK(vp, 0);
2089                         }
2090                         /* Roll back local locks. */
2091                         nfsrv_locallock_rollback(vp, lfp, p);
2092                         NFSLOCKSTATE();
2093                         nfsrv_unlocklf(lfp);
2094                         NFSUNLOCKSTATE();
2095                         NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2096                         vnode_unlocked = 0;
2097                         if ((vp->v_iflag & VI_DOOMED) != 0) {
2098                                 error = NFSERR_SERVERFAULT;
2099                                 goto out;
2100                         }
2101                     }
2102                     /*
2103                      * nfsrv_clientconflict() unlocks state when it
2104                      * returns non-zero.
2105                      */
2106                     lckstp = NULL;
2107                     goto tryagain;
2108                 }
2109                 /*
2110                  * Found a conflicting lock, so record the conflict and
2111                  * return the error.
2112                  */
2113                 if (cfp != NULL && ret == 0) {
2114                     cfp->cl_clientid.lval[0]=lop->lo_stp->ls_stateid.other[0];
2115                     cfp->cl_clientid.lval[1]=lop->lo_stp->ls_stateid.other[1];
2116                     cfp->cl_first = lop->lo_first;
2117                     cfp->cl_end = lop->lo_end;
2118                     cfp->cl_flags = lop->lo_flags;
2119                     cfp->cl_ownerlen = lop->lo_stp->ls_ownerlen;
2120                     NFSBCOPY(lop->lo_stp->ls_owner, cfp->cl_owner,
2121                         cfp->cl_ownerlen);
2122                 }
2123                 if (ret == 2)
2124                     error = NFSERR_PERM;
2125                 else if (new_stp->ls_flags & NFSLCK_RECLAIM)
2126                     error = NFSERR_RECLAIMCONFLICT;
2127                 else if (new_stp->ls_flags & NFSLCK_CHECK)
2128                     error = NFSERR_LOCKED;
2129                 else
2130                     error = NFSERR_DENIED;
2131                 if (filestruct_locked != 0 && ret == 0) {
2132                         /* Roll back local locks. */
2133                         NFSUNLOCKSTATE();
2134                         if (vnode_unlocked == 0) {
2135                                 ASSERT_VOP_ELOCKED(vp, "nfsrv_lockctrl7");
2136                                 vnode_unlocked = 1;
2137                                 NFSVOPUNLOCK(vp, 0);
2138                         }
2139                         nfsrv_locallock_rollback(vp, lfp, p);
2140                         NFSLOCKSTATE();
2141                         nfsrv_unlocklf(lfp);
2142                 }
2143                 if (ret == 0)
2144                         NFSUNLOCKSTATE();
2145                 goto out;
2146             }
2147           }
2148         }
2149
2150         /*
2151          * We only get here if there was no lock that conflicted.
2152          */
2153         if (new_stp->ls_flags & (NFSLCK_TEST | NFSLCK_CHECK)) {
2154                 NFSUNLOCKSTATE();
2155                 goto out;
2156         }
2157
2158         /*
2159          * We only get here when we are creating or modifying a lock.
2160          * There are two variants:
2161          * - exist_lock_owner where lock_owner exists
2162          * - open_to_lock_owner with new lock_owner
2163          */
2164         first = new_lop->lo_first;
2165         end = new_lop->lo_end;
2166         lock_flags = new_lop->lo_flags;
2167         if (!(new_stp->ls_flags & NFSLCK_OPENTOLOCK)) {
2168                 nfsrv_updatelock(lckstp, new_lopp, &other_lop, lfp);
2169                 stateidp->seqid = ++(lckstp->ls_stateid.seqid);
2170                 if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0)
2171                         stateidp->seqid = lckstp->ls_stateid.seqid = 1;
2172                 stateidp->other[0] = lckstp->ls_stateid.other[0];
2173                 stateidp->other[1] = lckstp->ls_stateid.other[1];
2174                 stateidp->other[2] = lckstp->ls_stateid.other[2];
2175         } else {
2176                 /*
2177                  * The new open_to_lock_owner case.
2178                  * Link the new nfsstate into the lists.
2179                  */
2180                 new_stp->ls_seq = new_stp->ls_opentolockseq;
2181                 nfsrvd_refcache(new_stp->ls_op);
2182                 stateidp->seqid = new_stp->ls_stateid.seqid = 1;
2183                 stateidp->other[0] = new_stp->ls_stateid.other[0] =
2184                     clp->lc_clientid.lval[0];
2185                 stateidp->other[1] = new_stp->ls_stateid.other[1] =
2186                     clp->lc_clientid.lval[1];
2187                 stateidp->other[2] = new_stp->ls_stateid.other[2] =
2188                     nfsrv_nextstateindex(clp);
2189                 new_stp->ls_clp = clp;
2190                 LIST_INIT(&new_stp->ls_lock);
2191                 new_stp->ls_openstp = stp;
2192                 new_stp->ls_lfp = lfp;
2193                 nfsrv_insertlock(new_lop, (struct nfslock *)new_stp, new_stp,
2194                     lfp);
2195                 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_stp->ls_stateid),
2196                     new_stp, ls_hash);
2197                 LIST_INSERT_HEAD(&stp->ls_open, new_stp, ls_list);
2198                 *new_lopp = NULL;
2199                 *new_stpp = NULL;
2200                 newnfsstats.srvlockowners++;
2201                 nfsrv_openpluslock++;
2202         }
2203         if (filestruct_locked != 0) {
2204                 NFSUNLOCKSTATE();
2205                 nfsrv_locallock_commit(lfp, lock_flags, first, end);
2206                 NFSLOCKSTATE();
2207                 nfsrv_unlocklf(lfp);
2208         }
2209         NFSUNLOCKSTATE();
2210
2211 out:
2212         if (haslock) {
2213                 NFSLOCKV4ROOTMUTEX();
2214                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
2215                 NFSUNLOCKV4ROOTMUTEX();
2216         }
2217         if (vnode_unlocked != 0) {
2218                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
2219                 if (error == 0 && (vp->v_iflag & VI_DOOMED) != 0)
2220                         error = NFSERR_SERVERFAULT;
2221         }
2222         if (other_lop)
2223                 FREE((caddr_t)other_lop, M_NFSDLOCK);
2224         NFSEXITCODE2(error, nd);
2225         return (error);
2226 }
2227
2228 /*
2229  * Check for state errors for Open.
2230  * repstat is passed back out as an error if more critical errors
2231  * are not detected.
2232  */
2233 APPLESTATIC int
2234 nfsrv_opencheck(nfsquad_t clientid, nfsv4stateid_t *stateidp,
2235     struct nfsstate *new_stp, vnode_t vp, struct nfsrv_descript *nd,
2236     NFSPROC_T *p, int repstat)
2237 {
2238         struct nfsstate *stp, *nstp;
2239         struct nfsclient *clp;
2240         struct nfsstate *ownerstp;
2241         struct nfslockfile *lfp, *new_lfp;
2242         int error = 0, haslock = 0, ret, readonly = 0, getfhret = 0;
2243
2244         if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS)
2245                 readonly = 1;
2246         /*
2247          * Check for restart conditions (client and server).
2248          */
2249         error = nfsrv_checkrestart(clientid, new_stp->ls_flags,
2250                 &new_stp->ls_stateid, 0);
2251         if (error)
2252                 goto out;
2253
2254         /*
2255          * Check for state resource limit exceeded.
2256          * Technically this should be SMP protected, but the worst
2257          * case error is "out by one or two" on the count when it
2258          * returns NFSERR_RESOURCE and the limit is just a rather
2259          * arbitrary high water mark, so no harm is done.
2260          */
2261         if (nfsrv_openpluslock > nfsrv_v4statelimit) {
2262                 error = NFSERR_RESOURCE;
2263                 goto out;
2264         }
2265
2266 tryagain:
2267         MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile),
2268             M_NFSDLOCKFILE, M_WAITOK);
2269         if (vp)
2270                 getfhret = nfsrv_getlockfh(vp, new_stp->ls_flags, new_lfp,
2271                     NULL, p);
2272         NFSLOCKSTATE();
2273         /*
2274          * Get the nfsclient structure.
2275          */
2276         error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
2277             (nfsquad_t)((u_quad_t)0), 0, nd, p);
2278
2279         /*
2280          * Look up the open owner. See if it needs confirmation and
2281          * check the seq#, as required.
2282          */
2283         if (!error)
2284                 nfsrv_getowner(&clp->lc_open, new_stp, &ownerstp);
2285
2286         if (!error && ownerstp) {
2287                 error = nfsrv_checkseqid(nd, new_stp->ls_seq, ownerstp,
2288                     new_stp->ls_op);
2289                 /*
2290                  * If the OpenOwner hasn't been confirmed, assume the
2291                  * old one was a replay and this one is ok.
2292                  * See: RFC3530 Sec. 14.2.18.
2293                  */
2294                 if (error == NFSERR_BADSEQID &&
2295                     (ownerstp->ls_flags & NFSLCK_NEEDSCONFIRM))
2296                         error = 0;
2297         }
2298
2299         /*
2300          * Check for grace.
2301          */
2302         if (!error)
2303                 error = nfsrv_checkgrace(nd, clp, new_stp->ls_flags);
2304         if ((new_stp->ls_flags & NFSLCK_RECLAIM) && !error &&
2305                 nfsrv_checkstable(clp))
2306                 error = NFSERR_NOGRACE;
2307
2308         /*
2309          * If none of the above errors occurred, let repstat be
2310          * returned.
2311          */
2312         if (repstat && !error)
2313                 error = repstat;
2314         if (error) {
2315                 NFSUNLOCKSTATE();
2316                 if (haslock) {
2317                         NFSLOCKV4ROOTMUTEX();
2318                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
2319                         NFSUNLOCKV4ROOTMUTEX();
2320                 }
2321                 free((caddr_t)new_lfp, M_NFSDLOCKFILE);
2322                 goto out;
2323         }
2324
2325         /*
2326          * If vp == NULL, the file doesn't exist yet, so return ok.
2327          * (This always happens on the first pass, so haslock must be 0.)
2328          */
2329         if (vp == NULL) {
2330                 NFSUNLOCKSTATE();
2331                 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE);
2332                 goto out;
2333         }
2334
2335         /*
2336          * Get the structure for the underlying file.
2337          */
2338         if (getfhret)
2339                 error = getfhret;
2340         else
2341                 error = nfsrv_getlockfile(new_stp->ls_flags, &new_lfp, &lfp,
2342                     NULL, 0);
2343         if (new_lfp)
2344                 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE);
2345         if (error) {
2346                 NFSUNLOCKSTATE();
2347                 if (haslock) {
2348                         NFSLOCKV4ROOTMUTEX();
2349                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
2350                         NFSUNLOCKV4ROOTMUTEX();
2351                 }
2352                 goto out;
2353         }
2354
2355         /*
2356          * Search for a conflicting open/share.
2357          */
2358         if (new_stp->ls_flags & NFSLCK_DELEGCUR) {
2359             /*
2360              * For Delegate_Cur, search for the matching Delegation,
2361              * which indicates no conflict.
2362              * An old delegation should have been recovered by the
2363              * client doing a Claim_DELEGATE_Prev, so I won't let
2364              * it match and return NFSERR_EXPIRED. Should I let it
2365              * match?
2366              */
2367             LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) {
2368                 if (!(stp->ls_flags & NFSLCK_OLDDELEG) &&
2369                     (((nd->nd_flag & ND_NFSV41) != 0 &&
2370                     stateidp->seqid == 0) ||
2371                     stateidp->seqid == stp->ls_stateid.seqid) &&
2372                     !NFSBCMP(stateidp->other, stp->ls_stateid.other,
2373                           NFSX_STATEIDOTHER))
2374                         break;
2375             }
2376             if (stp == LIST_END(&lfp->lf_deleg) ||
2377                 ((new_stp->ls_flags & NFSLCK_WRITEACCESS) &&
2378                  (stp->ls_flags & NFSLCK_DELEGREAD))) {
2379                 NFSUNLOCKSTATE();
2380                 if (haslock) {
2381                         NFSLOCKV4ROOTMUTEX();
2382                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
2383                         NFSUNLOCKV4ROOTMUTEX();
2384                 }
2385                 error = NFSERR_EXPIRED;
2386                 goto out;
2387             }
2388         }
2389
2390         /*
2391          * Check for access/deny bit conflicts. I check for the same
2392          * owner as well, in case the client didn't bother.
2393          */
2394         LIST_FOREACH(stp, &lfp->lf_open, ls_file) {
2395                 if (!(new_stp->ls_flags & NFSLCK_DELEGCUR) &&
2396                     (((new_stp->ls_flags & NFSLCK_ACCESSBITS) &
2397                       ((stp->ls_flags>>NFSLCK_SHIFT) & NFSLCK_ACCESSBITS))||
2398                      ((stp->ls_flags & NFSLCK_ACCESSBITS) &
2399                       ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS)))){
2400                         ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p);
2401                         if (ret == 1) {
2402                                 /*
2403                                  * nfsrv_clientconflict() unlocks
2404                                  * state when it returns non-zero.
2405                                  */
2406                                 goto tryagain;
2407                         }
2408                         if (ret == 2)
2409                                 error = NFSERR_PERM;
2410                         else if (new_stp->ls_flags & NFSLCK_RECLAIM)
2411                                 error = NFSERR_RECLAIMCONFLICT;
2412                         else
2413                                 error = NFSERR_SHAREDENIED;
2414                         if (ret == 0)
2415                                 NFSUNLOCKSTATE();
2416                         if (haslock) {
2417                                 NFSLOCKV4ROOTMUTEX();
2418                                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
2419                                 NFSUNLOCKV4ROOTMUTEX();
2420                         }
2421                         goto out;
2422                 }
2423         }
2424
2425         /*
2426          * Check for a conflicting delegation. If one is found, call
2427          * nfsrv_delegconflict() to handle it. If the v4root lock hasn't
2428          * been set yet, it will get the lock. Otherwise, it will recall
2429          * the delegation. Then, we try try again...
2430          * (If NFSLCK_DELEGCUR is set, it has a delegation, so there
2431          *  isn't a conflict.)
2432          * I currently believe the conflict algorithm to be:
2433          * For Open with Read Access and Deny None
2434          * - there is a conflict iff a different client has a write delegation
2435          * For Open with other Write Access or any Deny except None
2436          * - there is a conflict if a different client has any delegation
2437          * - there is a conflict if the same client has a read delegation
2438          *   (The current concensus is that this last case should be
2439          *    considered a conflict since the client with a read delegation
2440          *    could have done an Open with ReadAccess and WriteDeny
2441          *    locally and then not have checked for the WriteDeny.)
2442          * Don't check for a Reclaim, since that will be dealt with
2443          * by nfsrv_openctrl().
2444          */
2445         if (!(new_stp->ls_flags &
2446                 (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR | NFSLCK_RECLAIM))) {
2447             stp = LIST_FIRST(&lfp->lf_deleg);
2448             while (stp != LIST_END(&lfp->lf_deleg)) {
2449                 nstp = LIST_NEXT(stp, ls_file);
2450                 if ((readonly && stp->ls_clp != clp &&
2451                        (stp->ls_flags & NFSLCK_DELEGWRITE)) ||
2452                     (!readonly && (stp->ls_clp != clp ||
2453                          (stp->ls_flags & NFSLCK_DELEGREAD)))) {
2454                         ret = nfsrv_delegconflict(stp, &haslock, p, vp);
2455                         if (ret) {
2456                             /*
2457                              * nfsrv_delegconflict() unlocks state
2458                              * when it returns non-zero.
2459                              */
2460                             if (ret == -1)
2461                                 goto tryagain;
2462                             error = ret;
2463                             goto out;
2464                         }
2465                 }
2466                 stp = nstp;
2467             }
2468         }
2469         NFSUNLOCKSTATE();
2470         if (haslock) {
2471                 NFSLOCKV4ROOTMUTEX();
2472                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
2473                 NFSUNLOCKV4ROOTMUTEX();
2474         }
2475
2476 out:
2477         NFSEXITCODE2(error, nd);
2478         return (error);
2479 }
2480
2481 /*
2482  * Open control function to create/update open state for an open.
2483  */
2484 APPLESTATIC int
2485 nfsrv_openctrl(struct nfsrv_descript *nd, vnode_t vp,
2486     struct nfsstate **new_stpp, nfsquad_t clientid, nfsv4stateid_t *stateidp,
2487     nfsv4stateid_t *delegstateidp, u_int32_t *rflagsp, struct nfsexstuff *exp,
2488     NFSPROC_T *p, u_quad_t filerev)
2489 {
2490         struct nfsstate *new_stp = *new_stpp;
2491         struct nfsstate *stp, *nstp;
2492         struct nfsstate *openstp = NULL, *new_open, *ownerstp, *new_deleg;
2493         struct nfslockfile *lfp, *new_lfp;
2494         struct nfsclient *clp;
2495         int error = 0, haslock = 0, ret, delegate = 1, writedeleg = 1;
2496         int readonly = 0, cbret = 1, getfhret = 0;
2497
2498         if ((new_stp->ls_flags & NFSLCK_SHAREBITS) == NFSLCK_READACCESS)
2499                 readonly = 1;
2500         /*
2501          * Check for restart conditions (client and server).
2502          * (Paranoia, should have been detected by nfsrv_opencheck().)
2503          * If an error does show up, return NFSERR_EXPIRED, since the
2504          * the seqid# has already been incremented.
2505          */
2506         error = nfsrv_checkrestart(clientid, new_stp->ls_flags,
2507             &new_stp->ls_stateid, 0);
2508         if (error) {
2509                 printf("Nfsd: openctrl unexpected restart err=%d\n",
2510                     error);
2511                 error = NFSERR_EXPIRED;
2512                 goto out;
2513         }
2514
2515 tryagain:
2516         MALLOC(new_lfp, struct nfslockfile *, sizeof (struct nfslockfile),
2517             M_NFSDLOCKFILE, M_WAITOK);
2518         MALLOC(new_open, struct nfsstate *, sizeof (struct nfsstate),
2519             M_NFSDSTATE, M_WAITOK);
2520         MALLOC(new_deleg, struct nfsstate *, sizeof (struct nfsstate),
2521             M_NFSDSTATE, M_WAITOK);
2522         getfhret = nfsrv_getlockfh(vp, new_stp->ls_flags, new_lfp,
2523             NULL, p);
2524         NFSLOCKSTATE();
2525         /*
2526          * Get the client structure. Since the linked lists could be changed
2527          * by other nfsd processes if this process does a tsleep(), one of
2528          * two things must be done.
2529          * 1 - don't tsleep()
2530          * or
2531          * 2 - get the nfsv4_lock() { indicated by haslock == 1 }
2532          *     before using the lists, since this lock stops the other
2533          *     nfsd. This should only be used for rare cases, since it
2534          *     essentially single threads the nfsd.
2535          *     At this time, it is only done for cases where the stable
2536          *     storage file must be written prior to completion of state
2537          *     expiration.
2538          */
2539         error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
2540             (nfsquad_t)((u_quad_t)0), 0, nd, p);
2541         if (!error && (clp->lc_flags & LCL_NEEDSCBNULL) &&
2542             clp->lc_program) {
2543                 /*
2544                  * This happens on the first open for a client
2545                  * that supports callbacks.
2546                  */
2547                 NFSUNLOCKSTATE();
2548                 /*
2549                  * Although nfsrv_docallback() will sleep, clp won't
2550                  * go away, since they are only removed when the
2551                  * nfsv4_lock() has blocked the nfsd threads. The
2552                  * fields in clp can change, but having multiple
2553                  * threads do this Null callback RPC should be
2554                  * harmless.
2555                  */
2556                 cbret = nfsrv_docallback(clp, NFSV4PROC_CBNULL,
2557                     NULL, 0, NULL, NULL, NULL, p);
2558                 NFSLOCKSTATE();
2559                 clp->lc_flags &= ~LCL_NEEDSCBNULL;
2560                 if (!cbret)
2561                         clp->lc_flags |= LCL_CALLBACKSON;
2562         }
2563
2564         /*
2565          * Look up the open owner. See if it needs confirmation and
2566          * check the seq#, as required.
2567          */
2568         if (!error)
2569                 nfsrv_getowner(&clp->lc_open, new_stp, &ownerstp);
2570
2571         if (error) {
2572                 NFSUNLOCKSTATE();
2573                 printf("Nfsd: openctrl unexpected state err=%d\n",
2574                         error);
2575                 free((caddr_t)new_lfp, M_NFSDLOCKFILE);
2576                 free((caddr_t)new_open, M_NFSDSTATE);
2577                 free((caddr_t)new_deleg, M_NFSDSTATE);
2578                 if (haslock) {
2579                         NFSLOCKV4ROOTMUTEX();
2580                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
2581                         NFSUNLOCKV4ROOTMUTEX();
2582                 }
2583                 error = NFSERR_EXPIRED;
2584                 goto out;
2585         }
2586
2587         if (new_stp->ls_flags & NFSLCK_RECLAIM)
2588                 nfsrv_markstable(clp);
2589
2590         /*
2591          * Get the structure for the underlying file.
2592          */
2593         if (getfhret)
2594                 error = getfhret;
2595         else
2596                 error = nfsrv_getlockfile(new_stp->ls_flags, &new_lfp, &lfp,
2597                     NULL, 0);
2598         if (new_lfp)
2599                 FREE((caddr_t)new_lfp, M_NFSDLOCKFILE);
2600         if (error) {
2601                 NFSUNLOCKSTATE();
2602                 printf("Nfsd openctrl unexpected getlockfile err=%d\n",
2603                     error);
2604                 free((caddr_t)new_open, M_NFSDSTATE);
2605                 free((caddr_t)new_deleg, M_NFSDSTATE);
2606                 if (haslock) {
2607                         NFSLOCKV4ROOTMUTEX();
2608                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
2609                         NFSUNLOCKV4ROOTMUTEX();
2610                 }
2611                 goto out;
2612         }
2613
2614         /*
2615          * Search for a conflicting open/share.
2616          */
2617         if (new_stp->ls_flags & NFSLCK_DELEGCUR) {
2618             /*
2619              * For Delegate_Cur, search for the matching Delegation,
2620              * which indicates no conflict.
2621              * An old delegation should have been recovered by the
2622              * client doing a Claim_DELEGATE_Prev, so I won't let
2623              * it match and return NFSERR_EXPIRED. Should I let it
2624              * match?
2625              */
2626             LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) {
2627                 if (!(stp->ls_flags & NFSLCK_OLDDELEG) &&
2628                     (((nd->nd_flag & ND_NFSV41) != 0 &&
2629                     stateidp->seqid == 0) ||
2630                     stateidp->seqid == stp->ls_stateid.seqid) &&
2631                     !NFSBCMP(stateidp->other, stp->ls_stateid.other,
2632                         NFSX_STATEIDOTHER))
2633                         break;
2634             }
2635             if (stp == LIST_END(&lfp->lf_deleg) ||
2636                 ((new_stp->ls_flags & NFSLCK_WRITEACCESS) &&
2637                  (stp->ls_flags & NFSLCK_DELEGREAD))) {
2638                 NFSUNLOCKSTATE();
2639                 printf("Nfsd openctrl unexpected expiry\n");
2640                 free((caddr_t)new_open, M_NFSDSTATE);
2641                 free((caddr_t)new_deleg, M_NFSDSTATE);
2642                 if (haslock) {
2643                         NFSLOCKV4ROOTMUTEX();
2644                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
2645                         NFSUNLOCKV4ROOTMUTEX();
2646                 }
2647                 error = NFSERR_EXPIRED;
2648                 goto out;
2649             }
2650
2651             /*
2652              * Don't issue a Delegation, since one already exists and
2653              * delay delegation timeout, as required.
2654              */
2655             delegate = 0;
2656             nfsrv_delaydelegtimeout(stp);
2657         }
2658
2659         /*
2660          * Check for access/deny bit conflicts. I also check for the
2661          * same owner, since the client might not have bothered to check.
2662          * Also, note an open for the same file and owner, if found,
2663          * which is all we do here for Delegate_Cur, since conflict
2664          * checking is already done.
2665          */
2666         LIST_FOREACH(stp, &lfp->lf_open, ls_file) {
2667                 if (ownerstp && stp->ls_openowner == ownerstp)
2668                         openstp = stp;
2669                 if (!(new_stp->ls_flags & NFSLCK_DELEGCUR)) {
2670                     /*
2671                      * If another client has the file open, the only
2672                      * delegation that can be issued is a Read delegation
2673                      * and only if it is a Read open with Deny none.
2674                      */
2675                     if (clp != stp->ls_clp) {
2676                         if ((stp->ls_flags & NFSLCK_SHAREBITS) ==
2677                             NFSLCK_READACCESS)
2678                             writedeleg = 0;
2679                         else
2680                             delegate = 0;
2681                     }
2682                     if(((new_stp->ls_flags & NFSLCK_ACCESSBITS) &
2683                         ((stp->ls_flags>>NFSLCK_SHIFT) & NFSLCK_ACCESSBITS))||
2684                        ((stp->ls_flags & NFSLCK_ACCESSBITS) &
2685                         ((new_stp->ls_flags>>NFSLCK_SHIFT)&NFSLCK_ACCESSBITS))){
2686                         ret = nfsrv_clientconflict(stp->ls_clp,&haslock,vp,p);
2687                         if (ret == 1) {
2688                                 /*
2689                                  * nfsrv_clientconflict() unlocks state
2690                                  * when it returns non-zero.
2691                                  */
2692                                 free((caddr_t)new_open, M_NFSDSTATE);
2693                                 free((caddr_t)new_deleg, M_NFSDSTATE);
2694                                 openstp = NULL;
2695                                 goto tryagain;
2696                         }
2697                         if (ret == 2)
2698                                 error = NFSERR_PERM;
2699                         else if (new_stp->ls_flags & NFSLCK_RECLAIM)
2700                                 error = NFSERR_RECLAIMCONFLICT;
2701                         else
2702                                 error = NFSERR_SHAREDENIED;
2703                         if (ret == 0)
2704                                 NFSUNLOCKSTATE();
2705                         if (haslock) {
2706                                 NFSLOCKV4ROOTMUTEX();
2707                                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
2708                                 NFSUNLOCKV4ROOTMUTEX();
2709                         }
2710                         free((caddr_t)new_open, M_NFSDSTATE);
2711                         free((caddr_t)new_deleg, M_NFSDSTATE);
2712                         printf("nfsd openctrl unexpected client cnfl\n");
2713                         goto out;
2714                     }
2715                 }
2716         }
2717
2718         /*
2719          * Check for a conflicting delegation. If one is found, call
2720          * nfsrv_delegconflict() to handle it. If the v4root lock hasn't
2721          * been set yet, it will get the lock. Otherwise, it will recall
2722          * the delegation. Then, we try try again...
2723          * (If NFSLCK_DELEGCUR is set, it has a delegation, so there
2724          *  isn't a conflict.)
2725          * I currently believe the conflict algorithm to be:
2726          * For Open with Read Access and Deny None
2727          * - there is a conflict iff a different client has a write delegation
2728          * For Open with other Write Access or any Deny except None
2729          * - there is a conflict if a different client has any delegation
2730          * - there is a conflict if the same client has a read delegation
2731          *   (The current concensus is that this last case should be
2732          *    considered a conflict since the client with a read delegation
2733          *    could have done an Open with ReadAccess and WriteDeny
2734          *    locally and then not have checked for the WriteDeny.)
2735          */
2736         if (!(new_stp->ls_flags & (NFSLCK_DELEGPREV | NFSLCK_DELEGCUR))) {
2737             stp = LIST_FIRST(&lfp->lf_deleg);
2738             while (stp != LIST_END(&lfp->lf_deleg)) {
2739                 nstp = LIST_NEXT(stp, ls_file);
2740                 if (stp->ls_clp != clp && (stp->ls_flags & NFSLCK_DELEGREAD))
2741                         writedeleg = 0;
2742                 else
2743                         delegate = 0;
2744                 if ((readonly && stp->ls_clp != clp &&
2745                        (stp->ls_flags & NFSLCK_DELEGWRITE)) ||
2746                     (!readonly && (stp->ls_clp != clp ||
2747                          (stp->ls_flags & NFSLCK_DELEGREAD)))) {
2748                     if (new_stp->ls_flags & NFSLCK_RECLAIM) {
2749                         delegate = 2;
2750                     } else {
2751                         ret = nfsrv_delegconflict(stp, &haslock, p, vp);
2752                         if (ret) {
2753                             /*
2754                              * nfsrv_delegconflict() unlocks state
2755                              * when it returns non-zero.
2756                              */
2757                             printf("Nfsd openctrl unexpected deleg cnfl\n");
2758                             free((caddr_t)new_open, M_NFSDSTATE);
2759                             free((caddr_t)new_deleg, M_NFSDSTATE);
2760                             if (ret == -1) {
2761                                 openstp = NULL;
2762                                 goto tryagain;
2763                             }
2764                             error = ret;
2765                             goto out;
2766                         }
2767                     }
2768                 }
2769                 stp = nstp;
2770             }
2771         }
2772
2773         /*
2774          * We only get here if there was no open that conflicted.
2775          * If an open for the owner exists, or in the access/deny bits.
2776          * Otherwise it is a new open. If the open_owner hasn't been
2777          * confirmed, replace the open with the new one needing confirmation,
2778          * otherwise add the open.
2779          */
2780         if (new_stp->ls_flags & NFSLCK_DELEGPREV) {
2781             /*
2782              * Handle NFSLCK_DELEGPREV by searching the old delegations for
2783              * a match. If found, just move the old delegation to the current
2784              * delegation list and issue open. If not found, return
2785              * NFSERR_EXPIRED.
2786              */
2787             LIST_FOREACH(stp, &clp->lc_olddeleg, ls_list) {
2788                 if (stp->ls_lfp == lfp) {
2789                     /* Found it */
2790                     if (stp->ls_clp != clp)
2791                         panic("olddeleg clp");
2792                     LIST_REMOVE(stp, ls_list);
2793                     LIST_REMOVE(stp, ls_hash);
2794                     stp->ls_flags &= ~NFSLCK_OLDDELEG;
2795                     stp->ls_stateid.seqid = delegstateidp->seqid = 1;
2796                     stp->ls_stateid.other[0] = delegstateidp->other[0] =
2797                         clp->lc_clientid.lval[0];
2798                     stp->ls_stateid.other[1] = delegstateidp->other[1] =
2799                         clp->lc_clientid.lval[1];
2800                     stp->ls_stateid.other[2] = delegstateidp->other[2] =
2801                         nfsrv_nextstateindex(clp);
2802                     stp->ls_compref = nd->nd_compref;
2803                     LIST_INSERT_HEAD(&clp->lc_deleg, stp, ls_list);
2804                     LIST_INSERT_HEAD(NFSSTATEHASH(clp,
2805                         stp->ls_stateid), stp, ls_hash);
2806                     if (stp->ls_flags & NFSLCK_DELEGWRITE)
2807                         *rflagsp |= NFSV4OPEN_WRITEDELEGATE;
2808                     else
2809                         *rflagsp |= NFSV4OPEN_READDELEGATE;
2810                     clp->lc_delegtime = NFSD_MONOSEC +
2811                         nfsrv_lease + NFSRV_LEASEDELTA;
2812
2813                     /*
2814                      * Now, do the associated open.
2815                      */
2816                     new_open->ls_stateid.seqid = 1;
2817                     new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0];
2818                     new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1];
2819                     new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp);
2820                     new_open->ls_flags = (new_stp->ls_flags&NFSLCK_DENYBITS)|
2821                         NFSLCK_OPEN;
2822                     if (stp->ls_flags & NFSLCK_DELEGWRITE)
2823                         new_open->ls_flags |= (NFSLCK_READACCESS |
2824                             NFSLCK_WRITEACCESS);
2825                     else
2826                         new_open->ls_flags |= NFSLCK_READACCESS;
2827                     new_open->ls_uid = new_stp->ls_uid;
2828                     new_open->ls_lfp = lfp;
2829                     new_open->ls_clp = clp;
2830                     LIST_INIT(&new_open->ls_open);
2831                     LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file);
2832                     LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid),
2833                         new_open, ls_hash);
2834                     /*
2835                      * and handle the open owner
2836                      */
2837                     if (ownerstp) {
2838                         new_open->ls_openowner = ownerstp;
2839                         LIST_INSERT_HEAD(&ownerstp->ls_open,new_open,ls_list);
2840                     } else {
2841                         new_open->ls_openowner = new_stp;
2842                         new_stp->ls_flags = 0;
2843                         nfsrvd_refcache(new_stp->ls_op);
2844                         new_stp->ls_noopens = 0;
2845                         LIST_INIT(&new_stp->ls_open);
2846                         LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list);
2847                         LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list);
2848                         *new_stpp = NULL;
2849                         newnfsstats.srvopenowners++;
2850                         nfsrv_openpluslock++;
2851                     }
2852                     openstp = new_open;
2853                     new_open = NULL;
2854                     newnfsstats.srvopens++;
2855                     nfsrv_openpluslock++;
2856                     break;
2857                 }
2858             }
2859             if (stp == LIST_END(&clp->lc_olddeleg))
2860                 error = NFSERR_EXPIRED;
2861         } else if (new_stp->ls_flags & (NFSLCK_DELEGREAD | NFSLCK_DELEGWRITE)) {
2862             /*
2863              * Scan to see that no delegation for this client and file
2864              * doesn't already exist.
2865              * There also shouldn't yet be an Open for this file and
2866              * openowner.
2867              */
2868             LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) {
2869                 if (stp->ls_clp == clp)
2870                     break;
2871             }
2872             if (stp == LIST_END(&lfp->lf_deleg) && openstp == NULL) {
2873                 /*
2874                  * This is the Claim_Previous case with a delegation
2875                  * type != Delegate_None.
2876                  */
2877                 /*
2878                  * First, add the delegation. (Although we must issue the
2879                  * delegation, we can also ask for an immediate return.)
2880                  */
2881                 new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1;
2882                 new_deleg->ls_stateid.other[0] = delegstateidp->other[0] =
2883                     clp->lc_clientid.lval[0];
2884                 new_deleg->ls_stateid.other[1] = delegstateidp->other[1] =
2885                     clp->lc_clientid.lval[1];
2886                 new_deleg->ls_stateid.other[2] = delegstateidp->other[2] =
2887                     nfsrv_nextstateindex(clp);
2888                 if (new_stp->ls_flags & NFSLCK_DELEGWRITE) {
2889                     new_deleg->ls_flags = (NFSLCK_DELEGWRITE |
2890                         NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
2891                     *rflagsp |= NFSV4OPEN_WRITEDELEGATE;
2892                 } else {
2893                     new_deleg->ls_flags = (NFSLCK_DELEGREAD |
2894                         NFSLCK_READACCESS);
2895                     *rflagsp |= NFSV4OPEN_READDELEGATE;
2896                 }
2897                 new_deleg->ls_uid = new_stp->ls_uid;
2898                 new_deleg->ls_lfp = lfp;
2899                 new_deleg->ls_clp = clp;
2900                 new_deleg->ls_filerev = filerev;
2901                 new_deleg->ls_compref = nd->nd_compref;
2902                 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file);
2903                 LIST_INSERT_HEAD(NFSSTATEHASH(clp,
2904                     new_deleg->ls_stateid), new_deleg, ls_hash);
2905                 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list);
2906                 new_deleg = NULL;
2907                 if (delegate == 2 || nfsrv_issuedelegs == 0 ||
2908                     (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) !=
2909                      LCL_CALLBACKSON ||
2910                     NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) ||
2911                     !NFSVNO_DELEGOK(vp))
2912                     *rflagsp |= NFSV4OPEN_RECALL;
2913                 newnfsstats.srvdelegates++;
2914                 nfsrv_openpluslock++;
2915                 nfsrv_delegatecnt++;
2916
2917                 /*
2918                  * Now, do the associated open.
2919                  */
2920                 new_open->ls_stateid.seqid = 1;
2921                 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0];
2922                 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1];
2923                 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp);
2924                 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_DENYBITS) |
2925                     NFSLCK_OPEN;
2926                 if (new_stp->ls_flags & NFSLCK_DELEGWRITE)
2927                         new_open->ls_flags |= (NFSLCK_READACCESS |
2928                             NFSLCK_WRITEACCESS);
2929                 else
2930                         new_open->ls_flags |= NFSLCK_READACCESS;
2931                 new_open->ls_uid = new_stp->ls_uid;
2932                 new_open->ls_lfp = lfp;
2933                 new_open->ls_clp = clp;
2934                 LIST_INIT(&new_open->ls_open);
2935                 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file);
2936                 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid),
2937                    new_open, ls_hash);
2938                 /*
2939                  * and handle the open owner
2940                  */
2941                 if (ownerstp) {
2942                     new_open->ls_openowner = ownerstp;
2943                     LIST_INSERT_HEAD(&ownerstp->ls_open, new_open, ls_list);
2944                 } else {
2945                     new_open->ls_openowner = new_stp;
2946                     new_stp->ls_flags = 0;
2947                     nfsrvd_refcache(new_stp->ls_op);
2948                     new_stp->ls_noopens = 0;
2949                     LIST_INIT(&new_stp->ls_open);
2950                     LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list);
2951                     LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list);
2952                     *new_stpp = NULL;
2953                     newnfsstats.srvopenowners++;
2954                     nfsrv_openpluslock++;
2955                 }
2956                 openstp = new_open;
2957                 new_open = NULL;
2958                 newnfsstats.srvopens++;
2959                 nfsrv_openpluslock++;
2960             } else {
2961                 error = NFSERR_RECLAIMCONFLICT;
2962             }
2963         } else if (ownerstp) {
2964                 if (ownerstp->ls_flags & NFSLCK_NEEDSCONFIRM) {
2965                     /* Replace the open */
2966                     if (ownerstp->ls_op)
2967                         nfsrvd_derefcache(ownerstp->ls_op);
2968                     ownerstp->ls_op = new_stp->ls_op;
2969                     nfsrvd_refcache(ownerstp->ls_op);
2970                     ownerstp->ls_seq = new_stp->ls_seq;
2971                     *rflagsp |= NFSV4OPEN_RESULTCONFIRM;
2972                     stp = LIST_FIRST(&ownerstp->ls_open);
2973                     stp->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) |
2974                         NFSLCK_OPEN;
2975                     stp->ls_stateid.seqid = 1;
2976                     stp->ls_uid = new_stp->ls_uid;
2977                     if (lfp != stp->ls_lfp) {
2978                         LIST_REMOVE(stp, ls_file);
2979                         LIST_INSERT_HEAD(&lfp->lf_open, stp, ls_file);
2980                         stp->ls_lfp = lfp;
2981                     }
2982                     openstp = stp;
2983                 } else if (openstp) {
2984                     openstp->ls_flags |= (new_stp->ls_flags & NFSLCK_SHAREBITS);
2985                     openstp->ls_stateid.seqid++;
2986                     if ((nd->nd_flag & ND_NFSV41) != 0 &&
2987                         openstp->ls_stateid.seqid == 0)
2988                         openstp->ls_stateid.seqid = 1;
2989
2990                     /*
2991                      * This is where we can choose to issue a delegation.
2992                      */
2993                     if (delegate == 0 || writedeleg == 0 ||
2994                         NFSVNO_EXRDONLY(exp) || (readonly != 0 &&
2995                         nfsrv_writedelegifpos == 0) ||
2996                         !NFSVNO_DELEGOK(vp) ||
2997                         (new_stp->ls_flags & NFSLCK_WANTRDELEG) != 0 ||
2998                         (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) !=
2999                          LCL_CALLBACKSON)
3000                         *rflagsp |= NFSV4OPEN_WDCONTENTION;
3001                     else if (nfsrv_issuedelegs == 0 ||
3002                         NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt))
3003                         *rflagsp |= NFSV4OPEN_WDRESOURCE;
3004                     else if ((new_stp->ls_flags & NFSLCK_WANTNODELEG) != 0)
3005                         *rflagsp |= NFSV4OPEN_WDNOTWANTED;
3006                     else {
3007                         new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1;
3008                         new_deleg->ls_stateid.other[0] = delegstateidp->other[0]
3009                             = clp->lc_clientid.lval[0];
3010                         new_deleg->ls_stateid.other[1] = delegstateidp->other[1]
3011                             = clp->lc_clientid.lval[1];
3012                         new_deleg->ls_stateid.other[2] = delegstateidp->other[2]
3013                             = nfsrv_nextstateindex(clp);
3014                         new_deleg->ls_flags = (NFSLCK_DELEGWRITE |
3015                             NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
3016                         *rflagsp |= NFSV4OPEN_WRITEDELEGATE;
3017                         new_deleg->ls_uid = new_stp->ls_uid;
3018                         new_deleg->ls_lfp = lfp;
3019                         new_deleg->ls_clp = clp;
3020                         new_deleg->ls_filerev = filerev;
3021                         new_deleg->ls_compref = nd->nd_compref;
3022                         LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file);
3023                         LIST_INSERT_HEAD(NFSSTATEHASH(clp,
3024                             new_deleg->ls_stateid), new_deleg, ls_hash);
3025                         LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list);
3026                         new_deleg = NULL;
3027                         newnfsstats.srvdelegates++;
3028                         nfsrv_openpluslock++;
3029                         nfsrv_delegatecnt++;
3030                     }
3031                 } else {
3032                     new_open->ls_stateid.seqid = 1;
3033                     new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0];
3034                     new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1];
3035                     new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp);
3036                     new_open->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS)|
3037                         NFSLCK_OPEN;
3038                     new_open->ls_uid = new_stp->ls_uid;
3039                     new_open->ls_openowner = ownerstp;
3040                     new_open->ls_lfp = lfp;
3041                     new_open->ls_clp = clp;
3042                     LIST_INIT(&new_open->ls_open);
3043                     LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file);
3044                     LIST_INSERT_HEAD(&ownerstp->ls_open, new_open, ls_list);
3045                     LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid),
3046                         new_open, ls_hash);
3047                     openstp = new_open;
3048                     new_open = NULL;
3049                     newnfsstats.srvopens++;
3050                     nfsrv_openpluslock++;
3051
3052                     /*
3053                      * This is where we can choose to issue a delegation.
3054                      */
3055                     if (delegate == 0 || (writedeleg == 0 && readonly == 0) ||
3056                         !NFSVNO_DELEGOK(vp) ||
3057                         (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) !=
3058                          LCL_CALLBACKSON)
3059                         *rflagsp |= NFSV4OPEN_WDCONTENTION;
3060                     else if (nfsrv_issuedelegs == 0 ||
3061                         NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt))
3062                         *rflagsp |= NFSV4OPEN_WDRESOURCE;
3063                     else if ((new_stp->ls_flags & NFSLCK_WANTNODELEG) != 0)
3064                         *rflagsp |= NFSV4OPEN_WDNOTWANTED;
3065                     else {
3066                         new_deleg->ls_stateid.seqid = delegstateidp->seqid = 1;
3067                         new_deleg->ls_stateid.other[0] = delegstateidp->other[0]
3068                             = clp->lc_clientid.lval[0];
3069                         new_deleg->ls_stateid.other[1] = delegstateidp->other[1]
3070                             = clp->lc_clientid.lval[1];
3071                         new_deleg->ls_stateid.other[2] = delegstateidp->other[2]
3072                             = nfsrv_nextstateindex(clp);
3073                         if (writedeleg && !NFSVNO_EXRDONLY(exp) &&
3074                             (nfsrv_writedelegifpos || !readonly) &&
3075                             (new_stp->ls_flags & NFSLCK_WANTRDELEG) == 0) {
3076                             new_deleg->ls_flags = (NFSLCK_DELEGWRITE |
3077                                 NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
3078                             *rflagsp |= NFSV4OPEN_WRITEDELEGATE;
3079                         } else {
3080                             new_deleg->ls_flags = (NFSLCK_DELEGREAD |
3081                                 NFSLCK_READACCESS);
3082                             *rflagsp |= NFSV4OPEN_READDELEGATE;
3083                         }
3084                         new_deleg->ls_uid = new_stp->ls_uid;
3085                         new_deleg->ls_lfp = lfp;
3086                         new_deleg->ls_clp = clp;
3087                         new_deleg->ls_filerev = filerev;
3088                         new_deleg->ls_compref = nd->nd_compref;
3089                         LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg, ls_file);
3090                         LIST_INSERT_HEAD(NFSSTATEHASH(clp,
3091                             new_deleg->ls_stateid), new_deleg, ls_hash);
3092                         LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg, ls_list);
3093                         new_deleg = NULL;
3094                         newnfsstats.srvdelegates++;
3095                         nfsrv_openpluslock++;
3096                         nfsrv_delegatecnt++;
3097                     }
3098                 }
3099         } else {
3100                 /*
3101                  * New owner case. Start the open_owner sequence with a
3102                  * Needs confirmation (unless a reclaim) and hang the
3103                  * new open off it.
3104                  */
3105                 new_open->ls_stateid.seqid = 1;
3106                 new_open->ls_stateid.other[0] = clp->lc_clientid.lval[0];
3107                 new_open->ls_stateid.other[1] = clp->lc_clientid.lval[1];
3108                 new_open->ls_stateid.other[2] = nfsrv_nextstateindex(clp);
3109                 new_open->ls_flags = (new_stp->ls_flags & NFSLCK_SHAREBITS) |
3110                     NFSLCK_OPEN;
3111                 new_open->ls_uid = new_stp->ls_uid;
3112                 LIST_INIT(&new_open->ls_open);
3113                 new_open->ls_openowner = new_stp;
3114                 new_open->ls_lfp = lfp;
3115                 new_open->ls_clp = clp;
3116                 LIST_INSERT_HEAD(&lfp->lf_open, new_open, ls_file);
3117                 if (new_stp->ls_flags & NFSLCK_RECLAIM) {
3118                         new_stp->ls_flags = 0;
3119                 } else if ((nd->nd_flag & ND_NFSV41) != 0) {
3120                         /* NFSv4.1 never needs confirmation. */
3121                         new_stp->ls_flags = 0;
3122
3123                         /*
3124                          * This is where we can choose to issue a delegation.
3125                          */
3126                         if (delegate && nfsrv_issuedelegs &&
3127                             (writedeleg || readonly) &&
3128                             (clp->lc_flags & (LCL_CALLBACKSON | LCL_CBDOWN)) ==
3129                              LCL_CALLBACKSON &&
3130                             !NFSRV_V4DELEGLIMIT(nfsrv_delegatecnt) &&
3131                             NFSVNO_DELEGOK(vp) &&
3132                             ((nd->nd_flag & ND_NFSV41) == 0 ||
3133                              (new_stp->ls_flags & NFSLCK_WANTNODELEG) == 0)) {
3134                                 new_deleg->ls_stateid.seqid =
3135                                     delegstateidp->seqid = 1;
3136                                 new_deleg->ls_stateid.other[0] =
3137                                     delegstateidp->other[0]
3138                                     = clp->lc_clientid.lval[0];
3139                                 new_deleg->ls_stateid.other[1] =
3140                                     delegstateidp->other[1]
3141                                     = clp->lc_clientid.lval[1];
3142                                 new_deleg->ls_stateid.other[2] =
3143                                     delegstateidp->other[2]
3144                                     = nfsrv_nextstateindex(clp);
3145                                 if (writedeleg && !NFSVNO_EXRDONLY(exp) &&
3146                                     (nfsrv_writedelegifpos || !readonly) &&
3147                                     ((nd->nd_flag & ND_NFSV41) == 0 ||
3148                                      (new_stp->ls_flags & NFSLCK_WANTRDELEG) ==
3149                                      0)) {
3150                                         new_deleg->ls_flags =
3151                                             (NFSLCK_DELEGWRITE |
3152                                              NFSLCK_READACCESS |
3153                                              NFSLCK_WRITEACCESS);
3154                                         *rflagsp |= NFSV4OPEN_WRITEDELEGATE;
3155                                 } else {
3156                                         new_deleg->ls_flags =
3157                                             (NFSLCK_DELEGREAD |
3158                                              NFSLCK_READACCESS);
3159                                         *rflagsp |= NFSV4OPEN_READDELEGATE;
3160                                 }
3161                                 new_deleg->ls_uid = new_stp->ls_uid;
3162                                 new_deleg->ls_lfp = lfp;
3163                                 new_deleg->ls_clp = clp;
3164                                 new_deleg->ls_filerev = filerev;
3165                                 new_deleg->ls_compref = nd->nd_compref;
3166                                 LIST_INSERT_HEAD(&lfp->lf_deleg, new_deleg,
3167                                     ls_file);
3168                                 LIST_INSERT_HEAD(NFSSTATEHASH(clp,
3169                                     new_deleg->ls_stateid), new_deleg, ls_hash);
3170                                 LIST_INSERT_HEAD(&clp->lc_deleg, new_deleg,
3171                                     ls_list);
3172                                 new_deleg = NULL;
3173                                 newnfsstats.srvdelegates++;
3174                                 nfsrv_openpluslock++;
3175                                 nfsrv_delegatecnt++;
3176                         }
3177                 } else {
3178                         *rflagsp |= NFSV4OPEN_RESULTCONFIRM;
3179                         new_stp->ls_flags = NFSLCK_NEEDSCONFIRM;
3180                 }
3181                 nfsrvd_refcache(new_stp->ls_op);
3182                 new_stp->ls_noopens = 0;
3183                 LIST_INIT(&new_stp->ls_open);
3184                 LIST_INSERT_HEAD(&new_stp->ls_open, new_open, ls_list);
3185                 LIST_INSERT_HEAD(&clp->lc_open, new_stp, ls_list);
3186                 LIST_INSERT_HEAD(NFSSTATEHASH(clp, new_open->ls_stateid),
3187                     new_open, ls_hash);
3188                 openstp = new_open;
3189                 new_open = NULL;
3190                 *new_stpp = NULL;
3191                 newnfsstats.srvopens++;
3192                 nfsrv_openpluslock++;
3193                 newnfsstats.srvopenowners++;
3194                 nfsrv_openpluslock++;
3195         }
3196         if (!error) {
3197                 stateidp->seqid = openstp->ls_stateid.seqid;
3198                 stateidp->other[0] = openstp->ls_stateid.other[0];
3199                 stateidp->other[1] = openstp->ls_stateid.other[1];
3200                 stateidp->other[2] = openstp->ls_stateid.other[2];
3201         }
3202         NFSUNLOCKSTATE();
3203         if (haslock) {
3204                 NFSLOCKV4ROOTMUTEX();
3205                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
3206                 NFSUNLOCKV4ROOTMUTEX();
3207         }
3208         if (new_open)
3209                 FREE((caddr_t)new_open, M_NFSDSTATE);
3210         if (new_deleg)
3211                 FREE((caddr_t)new_deleg, M_NFSDSTATE);
3212
3213 out:
3214         NFSEXITCODE2(error, nd);
3215         return (error);
3216 }
3217
3218 /*
3219  * Open update. Does the confirm, downgrade and close.
3220  */
3221 APPLESTATIC int
3222 nfsrv_openupdate(vnode_t vp, struct nfsstate *new_stp, nfsquad_t clientid,
3223     nfsv4stateid_t *stateidp, struct nfsrv_descript *nd, NFSPROC_T *p)
3224 {
3225         struct nfsstate *stp, *ownerstp;
3226         struct nfsclient *clp;
3227         struct nfslockfile *lfp;
3228         u_int32_t bits;
3229         int error = 0, gotstate = 0, len = 0;
3230         u_char client[NFSV4_OPAQUELIMIT];
3231
3232         /*
3233          * Check for restart conditions (client and server).
3234          */
3235         error = nfsrv_checkrestart(clientid, new_stp->ls_flags,
3236             &new_stp->ls_stateid, 0);
3237         if (error)
3238                 goto out;
3239
3240         NFSLOCKSTATE();
3241         /*
3242          * Get the open structure via clientid and stateid.
3243          */
3244         error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
3245             (nfsquad_t)((u_quad_t)0), 0, nd, p);
3246         if (!error)
3247                 error = nfsrv_getstate(clp, &new_stp->ls_stateid,
3248                     new_stp->ls_flags, &stp);
3249
3250         /*
3251          * Sanity check the open.
3252          */
3253         if (!error && (!(stp->ls_flags & NFSLCK_OPEN) ||
3254                 (!(new_stp->ls_flags & NFSLCK_CONFIRM) &&
3255                  (stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM)) ||
3256                 ((new_stp->ls_flags & NFSLCK_CONFIRM) &&
3257                  (!(stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM)))))
3258                 error = NFSERR_BADSTATEID;
3259
3260         if (!error)
3261                 error = nfsrv_checkseqid(nd, new_stp->ls_seq,
3262                     stp->ls_openowner, new_stp->ls_op);
3263         if (!error && stp->ls_stateid.seqid != new_stp->ls_stateid.seqid &&
3264             (((nd->nd_flag & ND_NFSV41) == 0 &&
3265               !(new_stp->ls_flags & NFSLCK_CONFIRM)) ||
3266              ((nd->nd_flag & ND_NFSV41) != 0 &&
3267               new_stp->ls_stateid.seqid != 0)))
3268                 error = NFSERR_OLDSTATEID;
3269         if (!error && vnode_vtype(vp) != VREG) {
3270                 if (vnode_vtype(vp) == VDIR)
3271                         error = NFSERR_ISDIR;
3272                 else
3273                         error = NFSERR_INVAL;
3274         }
3275
3276         if (error) {
3277                 /*
3278                  * If a client tries to confirm an Open with a bad
3279                  * seqid# and there are no byte range locks or other Opens
3280                  * on the openowner, just throw it away, so the next use of the
3281                  * openowner will start a fresh seq#.
3282                  */
3283                 if (error == NFSERR_BADSEQID &&
3284                     (new_stp->ls_flags & NFSLCK_CONFIRM) &&
3285                     nfsrv_nootherstate(stp))
3286                         nfsrv_freeopenowner(stp->ls_openowner, 0, p);
3287                 NFSUNLOCKSTATE();
3288                 goto out;
3289         }
3290
3291         /*
3292          * Set the return stateid.
3293          */
3294         stateidp->seqid = stp->ls_stateid.seqid + 1;
3295         if ((nd->nd_flag & ND_NFSV41) != 0 && stateidp->seqid == 0)
3296                 stateidp->seqid = 1;
3297         stateidp->other[0] = stp->ls_stateid.other[0];
3298         stateidp->other[1] = stp->ls_stateid.other[1];
3299         stateidp->other[2] = stp->ls_stateid.other[2];
3300         /*
3301          * Now, handle the three cases.
3302          */
3303         if (new_stp->ls_flags & NFSLCK_CONFIRM) {
3304                 /*
3305                  * If the open doesn't need confirmation, it seems to me that
3306                  * there is a client error, but I'll just log it and keep going?
3307                  */
3308                 if (!(stp->ls_openowner->ls_flags & NFSLCK_NEEDSCONFIRM))
3309                         printf("Nfsv4d: stray open confirm\n");
3310                 stp->ls_openowner->ls_flags = 0;
3311                 stp->ls_stateid.seqid++;
3312                 if ((nd->nd_flag & ND_NFSV41) != 0 &&
3313                     stp->ls_stateid.seqid == 0)
3314                         stp->ls_stateid.seqid = 1;
3315                 if (!(clp->lc_flags & LCL_STAMPEDSTABLE)) {
3316                         clp->lc_flags |= LCL_STAMPEDSTABLE;
3317                         len = clp->lc_idlen;
3318                         NFSBCOPY(clp->lc_id, client, len);
3319                         gotstate = 1;
3320                 }
3321                 NFSUNLOCKSTATE();
3322         } else if (new_stp->ls_flags & NFSLCK_CLOSE) {
3323                 ownerstp = stp->ls_openowner;
3324                 lfp = stp->ls_lfp;
3325                 if (nfsrv_dolocallocks != 0 && !LIST_EMPTY(&stp->ls_open)) {
3326                         /* Get the lf lock */
3327                         nfsrv_locklf(lfp);
3328                         NFSUNLOCKSTATE();
3329                         ASSERT_VOP_ELOCKED(vp, "nfsrv_openupdate");
3330                         NFSVOPUNLOCK(vp, 0);
3331                         if (nfsrv_freeopen(stp, vp, 1, p) == 0) {
3332                                 NFSLOCKSTATE();
3333                                 nfsrv_unlocklf(lfp);
3334                                 NFSUNLOCKSTATE();
3335                         }
3336                         NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
3337                 } else {
3338                         (void) nfsrv_freeopen(stp, NULL, 0, p);
3339                         NFSUNLOCKSTATE();
3340                 }
3341         } else {
3342                 /*
3343                  * Update the share bits, making sure that the new set are a
3344                  * subset of the old ones.
3345                  */
3346                 bits = (new_stp->ls_flags & NFSLCK_SHAREBITS);
3347                 if (~(stp->ls_flags) & bits) {
3348                         NFSUNLOCKSTATE();
3349                         error = NFSERR_INVAL;
3350                         goto out;
3351                 }
3352                 stp->ls_flags = (bits | NFSLCK_OPEN);
3353                 stp->ls_stateid.seqid++;
3354                 if ((nd->nd_flag & ND_NFSV41) != 0 &&
3355                     stp->ls_stateid.seqid == 0)
3356                         stp->ls_stateid.seqid = 1;
3357                 NFSUNLOCKSTATE();
3358         }
3359
3360         /*
3361          * If the client just confirmed its first open, write a timestamp
3362          * to the stable storage file.
3363          */
3364         if (gotstate != 0) {
3365                 nfsrv_writestable(client, len, NFSNST_NEWSTATE, p);
3366                 nfsrv_backupstable();
3367         }
3368
3369 out:
3370         NFSEXITCODE2(error, nd);
3371         return (error);
3372 }
3373
3374 /*
3375  * Delegation update. Does the purge and return.
3376  */
3377 APPLESTATIC int
3378 nfsrv_delegupdate(struct nfsrv_descript *nd, nfsquad_t clientid,
3379     nfsv4stateid_t *stateidp, vnode_t vp, int op, struct ucred *cred,
3380     NFSPROC_T *p)
3381 {
3382         struct nfsstate *stp;
3383         struct nfsclient *clp;
3384         int error = 0;
3385         fhandle_t fh;
3386
3387         /*
3388          * Do a sanity check against the file handle for DelegReturn.
3389          */
3390         if (vp) {
3391                 error = nfsvno_getfh(vp, &fh, p);
3392                 if (error)
3393                         goto out;
3394         }
3395         /*
3396          * Check for restart conditions (client and server).
3397          */
3398         if (op == NFSV4OP_DELEGRETURN)
3399                 error = nfsrv_checkrestart(clientid, NFSLCK_DELEGRETURN,
3400                         stateidp, 0);
3401         else
3402                 error = nfsrv_checkrestart(clientid, NFSLCK_DELEGPURGE,
3403                         stateidp, 0);
3404
3405         NFSLOCKSTATE();
3406         /*
3407          * Get the open structure via clientid and stateid.
3408          */
3409         if (!error)
3410             error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
3411                 (nfsquad_t)((u_quad_t)0), 0, nd, p);
3412         if (error) {
3413                 if (error == NFSERR_CBPATHDOWN)
3414                         error = 0;
3415                 if (error == NFSERR_STALECLIENTID && op == NFSV4OP_DELEGRETURN)
3416                         error = NFSERR_STALESTATEID;
3417         }
3418         if (!error && op == NFSV4OP_DELEGRETURN) {
3419             error = nfsrv_getstate(clp, stateidp, NFSLCK_DELEGRETURN, &stp);
3420             if (!error && stp->ls_stateid.seqid != stateidp->seqid &&
3421                 ((nd->nd_flag & ND_NFSV41) == 0 || stateidp->seqid != 0))
3422                 error = NFSERR_OLDSTATEID;
3423         }
3424         /*
3425          * NFSERR_EXPIRED means that the state has gone away,
3426          * so Delegations have been purged. Just return ok.
3427          */
3428         if (error == NFSERR_EXPIRED && op == NFSV4OP_DELEGPURGE) {
3429                 NFSUNLOCKSTATE();
3430                 error = 0;
3431                 goto out;
3432         }
3433         if (error) {
3434                 NFSUNLOCKSTATE();
3435                 goto out;
3436         }
3437
3438         if (op == NFSV4OP_DELEGRETURN) {
3439                 if (NFSBCMP((caddr_t)&fh, (caddr_t)&stp->ls_lfp->lf_fh,
3440                     sizeof (fhandle_t))) {
3441                         NFSUNLOCKSTATE();
3442                         error = NFSERR_BADSTATEID;
3443                         goto out;
3444                 }
3445                 nfsrv_freedeleg(stp);
3446         } else {
3447                 nfsrv_freedeleglist(&clp->lc_olddeleg);
3448         }
3449         NFSUNLOCKSTATE();
3450         error = 0;
3451
3452 out:
3453         NFSEXITCODE(error);
3454         return (error);
3455 }
3456
3457 /*
3458  * Release lock owner.
3459  */
3460 APPLESTATIC int
3461 nfsrv_releaselckown(struct nfsstate *new_stp, nfsquad_t clientid,
3462     NFSPROC_T *p)
3463 {
3464         struct nfsstate *stp, *nstp, *openstp, *ownstp;
3465         struct nfsclient *clp;
3466         int error = 0;
3467
3468         /*
3469          * Check for restart conditions (client and server).
3470          */
3471         error = nfsrv_checkrestart(clientid, new_stp->ls_flags,
3472             &new_stp->ls_stateid, 0);
3473         if (error)
3474                 goto out;
3475
3476         NFSLOCKSTATE();
3477         /*
3478          * Get the lock owner by name.
3479          */
3480         error = nfsrv_getclient(clientid, CLOPS_RENEW, &clp, NULL,
3481             (nfsquad_t)((u_quad_t)0), 0, NULL, p);
3482         if (error) {
3483                 NFSUNLOCKSTATE();
3484                 goto out;
3485         }
3486         LIST_FOREACH(ownstp, &clp->lc_open, ls_list) {
3487             LIST_FOREACH(openstp, &ownstp->ls_open, ls_list) {
3488                 stp = LIST_FIRST(&openstp->ls_open);
3489                 while (stp != LIST_END(&openstp->ls_open)) {
3490                     nstp = LIST_NEXT(stp, ls_list);
3491                     /*
3492                      * If the owner matches, check for locks and
3493                      * then free or return an error.
3494                      */
3495                     if (stp->ls_ownerlen == new_stp->ls_ownerlen &&
3496                         !NFSBCMP(stp->ls_owner, new_stp->ls_owner,
3497                          stp->ls_ownerlen)){
3498                         if (LIST_EMPTY(&stp->ls_lock)) {
3499                             nfsrv_freelockowner(stp, NULL, 0, p);
3500                         } else {
3501                             NFSUNLOCKSTATE();
3502                             error = NFSERR_LOCKSHELD;
3503                             goto out;
3504                         }
3505                     }
3506                     stp = nstp;
3507                 }
3508             }
3509         }
3510         NFSUNLOCKSTATE();
3511
3512 out:
3513         NFSEXITCODE(error);
3514         return (error);
3515 }
3516
3517 /*
3518  * Get the file handle for a lock structure.
3519  */
3520 static int
3521 nfsrv_getlockfh(vnode_t vp, u_short flags, struct nfslockfile *new_lfp,
3522     fhandle_t *nfhp, NFSPROC_T *p)
3523 {
3524         fhandle_t *fhp = NULL;
3525         int error;
3526
3527         /*
3528          * For lock, use the new nfslock structure, otherwise just
3529          * a fhandle_t on the stack.
3530          */
3531         if (flags & NFSLCK_OPEN) {
3532                 KASSERT(new_lfp != NULL, ("nfsrv_getlockfh: new_lfp NULL"));
3533                 fhp = &new_lfp->lf_fh;
3534         } else if (nfhp) {
3535                 fhp = nfhp;
3536         } else {
3537                 panic("nfsrv_getlockfh");
3538         }
3539         error = nfsvno_getfh(vp, fhp, p);
3540         NFSEXITCODE(error);
3541         return (error);
3542 }
3543
3544 /*
3545  * Get an nfs lock structure. Allocate one, as required, and return a
3546  * pointer to it.
3547  * Returns an NFSERR_xxx upon failure or -1 to indicate no current lock.
3548  */
3549 static int
3550 nfsrv_getlockfile(u_short flags, struct nfslockfile **new_lfpp,
3551     struct nfslockfile **lfpp, fhandle_t *nfhp, int lockit)
3552 {
3553         struct nfslockfile *lfp;
3554         fhandle_t *fhp = NULL, *tfhp;
3555         struct nfslockhashhead *hp;
3556         struct nfslockfile *new_lfp = NULL;
3557
3558         /*
3559          * For lock, use the new nfslock structure, otherwise just
3560          * a fhandle_t on the stack.
3561          */
3562         if (flags & NFSLCK_OPEN) {
3563                 new_lfp = *new_lfpp;
3564                 fhp = &new_lfp->lf_fh;
3565         } else if (nfhp) {
3566                 fhp = nfhp;
3567         } else {
3568                 panic("nfsrv_getlockfile");
3569         }
3570
3571         hp = NFSLOCKHASH(fhp);
3572         LIST_FOREACH(lfp, hp, lf_hash) {
3573                 tfhp = &lfp->lf_fh;
3574                 if (NFSVNO_CMPFH(fhp, tfhp)) {
3575                         if (lockit)
3576                                 nfsrv_locklf(lfp);
3577                         *lfpp = lfp;
3578                         return (0);
3579                 }
3580         }
3581         if (!(flags & NFSLCK_OPEN))
3582                 return (-1);
3583
3584         /*
3585          * No match, so chain the new one into the list.
3586          */
3587         LIST_INIT(&new_lfp->lf_open);
3588         LIST_INIT(&new_lfp->lf_lock);
3589         LIST_INIT(&new_lfp->lf_deleg);
3590         LIST_INIT(&new_lfp->lf_locallock);
3591         LIST_INIT(&new_lfp->lf_rollback);
3592         new_lfp->lf_locallock_lck.nfslock_usecnt = 0;
3593         new_lfp->lf_locallock_lck.nfslock_lock = 0;
3594         new_lfp->lf_usecount = 0;
3595         LIST_INSERT_HEAD(hp, new_lfp, lf_hash);
3596         *lfpp = new_lfp;
3597         *new_lfpp = NULL;
3598         return (0);
3599 }
3600
3601 /*
3602  * This function adds a nfslock lock structure to the list for the associated
3603  * nfsstate and nfslockfile structures. It will be inserted after the
3604  * entry pointed at by insert_lop.
3605  */
3606 static void
3607 nfsrv_insertlock(struct nfslock *new_lop, struct nfslock *insert_lop,
3608     struct nfsstate *stp, struct nfslockfile *lfp)
3609 {
3610         struct nfslock *lop, *nlop;
3611
3612         new_lop->lo_stp = stp;
3613         new_lop->lo_lfp = lfp;
3614
3615         if (stp != NULL) {
3616                 /* Insert in increasing lo_first order */
3617                 lop = LIST_FIRST(&lfp->lf_lock);
3618                 if (lop == LIST_END(&lfp->lf_lock) ||
3619                     new_lop->lo_first <= lop->lo_first) {
3620                         LIST_INSERT_HEAD(&lfp->lf_lock, new_lop, lo_lckfile);
3621                 } else {
3622                         nlop = LIST_NEXT(lop, lo_lckfile);
3623                         while (nlop != LIST_END(&lfp->lf_lock) &&
3624                                nlop->lo_first < new_lop->lo_first) {
3625                                 lop = nlop;
3626                                 nlop = LIST_NEXT(lop, lo_lckfile);
3627                         }
3628                         LIST_INSERT_AFTER(lop, new_lop, lo_lckfile);
3629                 }
3630         } else {
3631                 new_lop->lo_lckfile.le_prev = NULL;     /* list not used */
3632         }
3633
3634         /*
3635          * Insert after insert_lop, which is overloaded as stp or lfp for
3636          * an empty list.
3637          */
3638         if (stp == NULL && (struct nfslockfile *)insert_lop == lfp)
3639                 LIST_INSERT_HEAD(&lfp->lf_locallock, new_lop, lo_lckowner);
3640         else if ((struct nfsstate *)insert_lop == stp)
3641                 LIST_INSERT_HEAD(&stp->ls_lock, new_lop, lo_lckowner);
3642         else
3643                 LIST_INSERT_AFTER(insert_lop, new_lop, lo_lckowner);
3644         if (stp != NULL) {
3645                 newnfsstats.srvlocks++;
3646                 nfsrv_openpluslock++;
3647         }
3648 }
3649
3650 /*
3651  * This function updates the locking for a lock owner and given file. It
3652  * maintains a list of lock ranges ordered on increasing file offset that
3653  * are NFSLCK_READ or NFSLCK_WRITE and non-overlapping (aka POSIX style).
3654  * It always adds new_lop to the list and sometimes uses the one pointed
3655  * at by other_lopp.
3656  */
3657 static void
3658 nfsrv_updatelock(struct nfsstate *stp, struct nfslock **new_lopp,
3659     struct nfslock **other_lopp, struct nfslockfile *lfp)
3660 {
3661         struct nfslock *new_lop = *new_lopp;
3662         struct nfslock *lop, *tlop, *ilop;
3663         struct nfslock *other_lop = *other_lopp;
3664         int unlock = 0, myfile = 0;
3665         u_int64_t tmp;
3666
3667         /*
3668          * Work down the list until the lock is merged.
3669          */
3670         if (new_lop->lo_flags & NFSLCK_UNLOCK)
3671                 unlock = 1;
3672         if (stp != NULL) {
3673                 ilop = (struct nfslock *)stp;
3674                 lop = LIST_FIRST(&stp->ls_lock);
3675         } else {
3676                 ilop = (struct nfslock *)lfp;
3677                 lop = LIST_FIRST(&lfp->lf_locallock);
3678         }
3679         while (lop != NULL) {
3680             /*
3681              * Only check locks for this file that aren't before the start of
3682              * new lock's range.
3683              */
3684             if (lop->lo_lfp == lfp) {
3685               myfile = 1;
3686               if (lop->lo_end >= new_lop->lo_first) {
3687                 if (new_lop->lo_end < lop->lo_first) {
3688                         /*
3689                          * If the new lock ends before the start of the
3690                          * current lock's range, no merge, just insert
3691                          * the new lock.
3692                          */
3693                         break;
3694                 }
3695                 if (new_lop->lo_flags == lop->lo_flags ||
3696                     (new_lop->lo_first <= lop->lo_first &&
3697                      new_lop->lo_end >= lop->lo_end)) {
3698                         /*
3699                          * This lock can be absorbed by the new lock/unlock.
3700                          * This happens when it covers the entire range
3701                          * of the old lock or is contiguous
3702                          * with the old lock and is of the same type or an
3703                          * unlock.
3704                          */
3705                         if (lop->lo_first < new_lop->lo_first)
3706                                 new_lop->lo_first = lop->lo_first;
3707                         if (lop->lo_end > new_lop->lo_end)
3708                                 new_lop->lo_end = lop->lo_end;
3709                         tlop = lop;
3710                         lop = LIST_NEXT(lop, lo_lckowner);
3711                         nfsrv_freenfslock(tlop);
3712                         continue;
3713                 }
3714
3715                 /*
3716                  * All these cases are for contiguous locks that are not the
3717                  * same type, so they can't be merged.
3718                  */
3719                 if (new_lop->lo_first <= lop->lo_first) {
3720                         /*
3721                          * This case is where the new lock overlaps with the
3722                          * first part of the old lock. Move the start of the
3723                          * old lock to just past the end of the new lock. The
3724                          * new lock will be inserted in front of the old, since
3725                          * ilop hasn't been updated. (We are done now.)
3726                          */
3727                         lop->lo_first = new_lop->lo_end;
3728                         break;
3729                 }
3730                 if (new_lop->lo_end >= lop->lo_end) {
3731                         /*
3732                          * This case is where the new lock overlaps with the
3733                          * end of the old lock's range. Move the old lock's
3734                          * end to just before the new lock's first and insert
3735                          * the new lock after the old lock.
3736                          * Might not be done yet, since the new lock could
3737                          * overlap further locks with higher ranges.
3738                          */
3739                         lop->lo_end = new_lop->lo_first;
3740                         ilop = lop;
3741                         lop = LIST_NEXT(lop, lo_lckowner);
3742                         continue;
3743                 }
3744                 /*
3745                  * The final case is where the new lock's range is in the
3746                  * middle of the current lock's and splits the current lock
3747                  * up. Use *other_lopp to handle the second part of the
3748                  * split old lock range. (We are done now.)
3749                  * For unlock, we use new_lop as other_lop and tmp, since
3750                  * other_lop and new_lop are the same for this case.
3751                  * We noted the unlock case above, so we don't need
3752                  * new_lop->lo_flags any longer.
3753                  */
3754                 tmp = new_lop->lo_first;
3755                 if (other_lop == NULL) {
3756                         if (!unlock)
3757                                 panic("nfsd srv update unlock");
3758                         other_lop = new_lop;
3759                         *new_lopp = NULL;
3760                 }
3761                 other_lop->lo_first = new_lop->lo_end;
3762                 other_lop->lo_end = lop->lo_end;
3763                 other_lop->lo_flags = lop->lo_flags;
3764                 other_lop->lo_stp = stp;
3765                 other_lop->lo_lfp = lfp;
3766                 lop->lo_end = tmp;
3767                 nfsrv_insertlock(other_lop, lop, stp, lfp);
3768                 *other_lopp = NULL;
3769                 ilop = lop;
3770                 break;
3771               }
3772             }
3773             ilop = lop;
3774             lop = LIST_NEXT(lop, lo_lckowner);
3775             if (myfile && (lop == NULL || lop->lo_lfp != lfp))
3776                 break;
3777         }
3778
3779         /*
3780          * Insert the new lock in the list at the appropriate place.
3781          */
3782         if (!unlock) {
3783                 nfsrv_insertlock(new_lop, ilop, stp, lfp);
3784                 *new_lopp = NULL;
3785         }
3786 }
3787
3788 /*
3789  * This function handles sequencing of locks, etc.
3790  * It returns an error that indicates what the caller should do.
3791  */
3792 static int
3793 nfsrv_checkseqid(struct nfsrv_descript *nd, u_int32_t seqid,
3794     struct nfsstate *stp, struct nfsrvcache *op)
3795 {
3796         int error = 0;
3797
3798         if ((nd->nd_flag & ND_NFSV41) != 0)
3799                 /* NFSv4.1 ignores the open_seqid and lock_seqid. */
3800                 goto out;
3801         if (op != nd->nd_rp)
3802                 panic("nfsrvstate checkseqid");
3803         if (!(op->rc_flag & RC_INPROG))
3804                 panic("nfsrvstate not inprog");
3805         if (stp->ls_op && stp->ls_op->rc_refcnt <= 0) {
3806                 printf("refcnt=%d\n", stp->ls_op->rc_refcnt);
3807                 panic("nfsrvstate op refcnt");
3808         }
3809         if ((stp->ls_seq + 1) == seqid) {
3810                 if (stp->ls_op)
3811                         nfsrvd_derefcache(stp->ls_op);
3812                 stp->ls_op = op;
3813                 nfsrvd_refcache(op);
3814                 stp->ls_seq = seqid;
3815                 goto out;
3816         } else if (stp->ls_seq == seqid && stp->ls_op &&
3817                 op->rc_xid == stp->ls_op->rc_xid &&
3818                 op->rc_refcnt == 0 &&
3819                 op->rc_reqlen == stp->ls_op->rc_reqlen &&
3820                 op->rc_cksum == stp->ls_op->rc_cksum) {
3821                 if (stp->ls_op->rc_flag & RC_INPROG) {
3822                         error = NFSERR_DONTREPLY;
3823                         goto out;
3824                 }
3825                 nd->nd_rp = stp->ls_op;
3826                 nd->nd_rp->rc_flag |= RC_INPROG;
3827                 nfsrvd_delcache(op);
3828                 error = NFSERR_REPLYFROMCACHE;
3829                 goto out;
3830         }
3831         error = NFSERR_BADSEQID;
3832
3833 out:
3834         NFSEXITCODE2(error, nd);
3835         return (error);
3836 }
3837
3838 /*
3839  * Get the client ip address for callbacks. If the strings can't be parsed,
3840  * just set lc_program to 0 to indicate no callbacks are possible.
3841  * (For cases where the address can't be parsed or is 0.0.0.0.0.0, set
3842  *  the address to the client's transport address. This won't be used
3843  *  for callbacks, but can be printed out by newnfsstats for info.)
3844  * Return error if the xdr can't be parsed, 0 otherwise.
3845  */
3846 APPLESTATIC int
3847 nfsrv_getclientipaddr(struct nfsrv_descript *nd, struct nfsclient *clp)
3848 {
3849         u_int32_t *tl;
3850         u_char *cp, *cp2;
3851         int i, j;
3852         struct sockaddr_in *rad, *sad;
3853         u_char protocol[5], addr[24];
3854         int error = 0, cantparse = 0;
3855         union {
3856                 u_long ival;
3857                 u_char cval[4];
3858         } ip;
3859         union {
3860                 u_short sval;
3861                 u_char cval[2];
3862         } port;
3863
3864         rad = NFSSOCKADDR(clp->lc_req.nr_nam, struct sockaddr_in *);
3865         rad->sin_family = AF_INET;
3866         rad->sin_len = sizeof (struct sockaddr_in);
3867         rad->sin_addr.s_addr = 0;
3868         rad->sin_port = 0;
3869         clp->lc_req.nr_client = NULL;
3870         clp->lc_req.nr_lock = 0;
3871         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3872         i = fxdr_unsigned(int, *tl);
3873         if (i >= 3 && i <= 4) {
3874                 error = nfsrv_mtostr(nd, protocol, i);
3875                 if (error)
3876                         goto nfsmout;
3877                 if (!strcmp(protocol, "tcp")) {
3878                         clp->lc_flags |= LCL_TCPCALLBACK;
3879                         clp->lc_req.nr_sotype = SOCK_STREAM;
3880                         clp->lc_req.nr_soproto = IPPROTO_TCP;
3881                 } else if (!strcmp(protocol, "udp")) {
3882                         clp->lc_req.nr_sotype = SOCK_DGRAM;
3883                         clp->lc_req.nr_soproto = IPPROTO_UDP;
3884                 } else {
3885                         cantparse = 1;
3886                 }
3887         } else {
3888                 cantparse = 1;
3889                 if (i > 0) {
3890                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3891                         if (error)
3892                                 goto nfsmout;
3893                 }
3894         }
3895         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
3896         i = fxdr_unsigned(int, *tl);
3897         if (i < 0) {
3898                 error = NFSERR_BADXDR;
3899                 goto nfsmout;
3900         } else if (i == 0) {
3901                 cantparse = 1;
3902         } else if (!cantparse && i <= 23 && i >= 11) {
3903                 error = nfsrv_mtostr(nd, addr, i);
3904                 if (error)
3905                         goto nfsmout;
3906
3907                 /*
3908                  * Parse out the address fields. We expect 6 decimal numbers
3909                  * separated by '.'s.
3910                  */
3911                 cp = addr;
3912                 i = 0;
3913                 while (*cp && i < 6) {
3914                         cp2 = cp;
3915                         while (*cp2 && *cp2 != '.')
3916                                 cp2++;
3917                         if (*cp2)
3918                                 *cp2++ = '\0';
3919                         else if (i != 5) {
3920                                 cantparse = 1;
3921                                 break;
3922                         }
3923                         j = nfsrv_getipnumber(cp);
3924                         if (j >= 0) {
3925                                 if (i < 4)
3926                                         ip.cval[3 - i] = j;
3927                                 else
3928                                         port.cval[5 - i] = j;
3929                         } else {
3930                                 cantparse = 1;
3931                                 break;
3932                         }
3933                         cp = cp2;
3934                         i++;
3935                 }
3936                 if (!cantparse) {
3937                         if (ip.ival != 0x0) {
3938                                 rad->sin_addr.s_addr = htonl(ip.ival);
3939                                 rad->sin_port = htons(port.sval);
3940                         } else {
3941                                 cantparse = 1;
3942                         }
3943                 }
3944         } else {
3945                 cantparse = 1;
3946                 if (i > 0) {
3947                         error = nfsm_advance(nd, NFSM_RNDUP(i), -1);
3948                         if (error)
3949                                 goto nfsmout;
3950                 }
3951         }
3952         if (cantparse) {
3953                 sad = NFSSOCKADDR(nd->nd_nam, struct sockaddr_in *);
3954                 rad->sin_addr.s_addr = sad->sin_addr.s_addr;
3955                 rad->sin_port = 0x0;
3956                 clp->lc_program = 0;
3957         }
3958 nfsmout:
3959         NFSEXITCODE2(error, nd);
3960         return (error);
3961 }
3962
3963 /*
3964  * Turn a string of up to three decimal digits into a number. Return -1 upon
3965  * error.
3966  */
3967 static int
3968 nfsrv_getipnumber(u_char *cp)
3969 {
3970         int i = 0, j = 0;
3971
3972         while (*cp) {
3973                 if (j > 2 || *cp < '0' || *cp > '9')
3974                         return (-1);
3975                 i *= 10;
3976                 i += (*cp - '0');
3977                 cp++;
3978                 j++;
3979         }
3980         if (i < 256)
3981                 return (i);
3982         return (-1);
3983 }
3984
3985 /*
3986  * This function checks for restart conditions.
3987  */
3988 static int
3989 nfsrv_checkrestart(nfsquad_t clientid, u_int32_t flags,
3990     nfsv4stateid_t *stateidp, int specialid)
3991 {
3992         int ret = 0;
3993
3994         /*
3995          * First check for a server restart. Open, LockT, ReleaseLockOwner
3996          * and DelegPurge have a clientid, the rest a stateid.
3997          */
3998         if (flags &
3999             (NFSLCK_OPEN | NFSLCK_TEST | NFSLCK_RELEASE | NFSLCK_DELEGPURGE)) {
4000                 if (clientid.lval[0] != nfsrvboottime) {
4001                         ret = NFSERR_STALECLIENTID;
4002                         goto out;
4003                 }
4004         } else if (stateidp->other[0] != nfsrvboottime &&
4005                 specialid == 0) {
4006                 ret = NFSERR_STALESTATEID;
4007                 goto out;
4008         }
4009
4010         /*
4011          * Read, Write, Setattr and LockT can return NFSERR_GRACE and do
4012          * not use a lock/open owner seqid#, so the check can be done now.
4013          * (The others will be checked, as required, later.)
4014          */
4015         if (!(flags & (NFSLCK_CHECK | NFSLCK_TEST)))
4016                 goto out;
4017
4018         NFSLOCKSTATE();
4019         ret = nfsrv_checkgrace(NULL, NULL, flags);
4020         NFSUNLOCKSTATE();
4021
4022 out:
4023         NFSEXITCODE(ret);
4024         return (ret);
4025 }
4026
4027 /*
4028  * Check for grace.
4029  */
4030 static int
4031 nfsrv_checkgrace(struct nfsrv_descript *nd, struct nfsclient *clp,
4032     u_int32_t flags)
4033 {
4034         int error = 0;
4035
4036         if ((nfsrv_stablefirst.nsf_flags & NFSNSF_GRACEOVER) != 0) {
4037                 if (flags & NFSLCK_RECLAIM) {
4038                         error = NFSERR_NOGRACE;
4039                         goto out;
4040                 }
4041         } else {
4042                 if (!(flags & NFSLCK_RECLAIM)) {
4043                         error = NFSERR_GRACE;
4044                         goto out;
4045                 }
4046                 if (nd != NULL && clp != NULL &&
4047                     (nd->nd_flag & ND_NFSV41) != 0 &&
4048                     (clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0) {
4049                         error = NFSERR_NOGRACE;
4050                         goto out;
4051                 }
4052
4053                 /*
4054                  * If grace is almost over and we are still getting Reclaims,
4055                  * extend grace a bit.
4056                  */
4057                 if ((NFSD_MONOSEC + NFSRV_LEASEDELTA) >
4058                     nfsrv_stablefirst.nsf_eograce)
4059                         nfsrv_stablefirst.nsf_eograce = NFSD_MONOSEC +
4060                                 NFSRV_LEASEDELTA;
4061         }
4062
4063 out:
4064         NFSEXITCODE(error);
4065         return (error);
4066 }
4067
4068 /*
4069  * Do a server callback.
4070  */
4071 static int
4072 nfsrv_docallback(struct nfsclient *clp, int procnum,
4073     nfsv4stateid_t *stateidp, int trunc, fhandle_t *fhp,
4074     struct nfsvattr *nap, nfsattrbit_t *attrbitp, NFSPROC_T *p)
4075 {
4076         mbuf_t m;
4077         u_int32_t *tl;
4078         struct nfsrv_descript nfsd, *nd = &nfsd;
4079         struct ucred *cred;
4080         int error = 0;
4081         u_int32_t callback;
4082         struct nfsdsession *sep = NULL;
4083
4084         cred = newnfs_getcred();
4085         NFSLOCKSTATE(); /* mostly for lc_cbref++ */
4086         if (clp->lc_flags & LCL_NEEDSCONFIRM) {
4087                 NFSUNLOCKSTATE();
4088                 panic("docallb");
4089         }
4090         clp->lc_cbref++;
4091
4092         /*
4093          * Fill the callback program# and version into the request
4094          * structure for newnfs_connect() to use.
4095          */
4096         clp->lc_req.nr_prog = clp->lc_program;
4097 #ifdef notnow
4098         if ((clp->lc_flags & LCL_NFSV41) != 0)
4099                 clp->lc_req.nr_vers = NFSV41_CBVERS;
4100         else
4101 #endif
4102                 clp->lc_req.nr_vers = NFSV4_CBVERS;
4103
4104         /*
4105          * First, fill in some of the fields of nd and cr.
4106          */
4107         nd->nd_flag = ND_NFSV4;
4108         if (clp->lc_flags & LCL_GSS)
4109                 nd->nd_flag |= ND_KERBV;
4110         if ((clp->lc_flags & LCL_NFSV41) != 0)
4111                 nd->nd_flag |= ND_NFSV41;
4112         nd->nd_repstat = 0;
4113         cred->cr_uid = clp->lc_uid;
4114         cred->cr_gid = clp->lc_gid;
4115         callback = clp->lc_callback;
4116         NFSUNLOCKSTATE();
4117         cred->cr_ngroups = 1;
4118
4119         /*
4120          * Get the first mbuf for the request.
4121          */
4122         MGET(m, M_WAITOK, MT_DATA);
4123         mbuf_setlen(m, 0);
4124         nd->nd_mreq = nd->nd_mb = m;
4125         nd->nd_bpos = NFSMTOD(m, caddr_t);
4126         
4127         /*
4128          * and build the callback request.
4129          */
4130         if (procnum == NFSV4OP_CBGETATTR) {
4131                 nd->nd_procnum = NFSV4PROC_CBCOMPOUND;
4132                 error = nfsrv_cbcallargs(nd, clp, callback, NFSV4OP_CBGETATTR,
4133                     "CB Getattr", &sep);
4134                 if (error != 0) {
4135                         mbuf_freem(nd->nd_mreq);
4136                         goto errout;
4137                 }
4138                 (void)nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0);
4139                 (void)nfsrv_putattrbit(nd, attrbitp);
4140         } else if (procnum == NFSV4OP_CBRECALL) {
4141                 nd->nd_procnum = NFSV4PROC_CBCOMPOUND;
4142                 error = nfsrv_cbcallargs(nd, clp, callback, NFSV4OP_CBRECALL,
4143                     "CB Recall", &sep);
4144                 if (error != 0) {
4145                         mbuf_freem(nd->nd_mreq);
4146                         goto errout;
4147                 }
4148                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
4149                 *tl++ = txdr_unsigned(stateidp->seqid);
4150                 NFSBCOPY((caddr_t)stateidp->other, (caddr_t)tl,
4151                     NFSX_STATEIDOTHER);
4152                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
4153                 if (trunc)
4154                         *tl = newnfs_true;
4155                 else
4156                         *tl = newnfs_false;
4157                 (void)nfsm_fhtom(nd, (u_int8_t *)fhp, NFSX_MYFH, 0);
4158         } else if (procnum == NFSV4PROC_CBNULL) {
4159                 nd->nd_procnum = NFSV4PROC_CBNULL;
4160                 if ((clp->lc_flags & LCL_NFSV41) != 0) {
4161                         error = nfsv4_getcbsession(clp, &sep);
4162                         if (error != 0) {
4163                                 mbuf_freem(nd->nd_mreq);
4164                                 goto errout;
4165                         }
4166                 }
4167         } else {
4168                 error = NFSERR_SERVERFAULT;
4169                 mbuf_freem(nd->nd_mreq);
4170                 goto errout;
4171         }
4172
4173         /*
4174          * Call newnfs_connect(), as required, and then newnfs_request().
4175          */
4176         (void) newnfs_sndlock(&clp->lc_req.nr_lock);
4177         if (clp->lc_req.nr_client == NULL) {
4178                 if ((clp->lc_flags & LCL_NFSV41) != 0)
4179                         error = ECONNREFUSED;
4180                 else if (nd->nd_procnum == NFSV4PROC_CBNULL)
4181                         error = newnfs_connect(NULL, &clp->lc_req, cred,
4182                             NULL, 1);
4183                 else
4184                         error = newnfs_connect(NULL, &clp->lc_req, cred,
4185                             NULL, 3);
4186         }
4187         newnfs_sndunlock(&clp->lc_req.nr_lock);
4188         if (!error) {
4189                 if ((nd->nd_flag & ND_NFSV41) != 0) {
4190                         KASSERT(sep != NULL, ("sep NULL"));
4191                         error = newnfs_request(nd, NULL, clp, &clp->lc_req,
4192                             NULL, NULL, cred, clp->lc_program,
4193                             clp->lc_req.nr_vers, NULL, 1, NULL,
4194                             &sep->sess_cbsess);
4195                         nfsrv_freesession(sep, NULL);
4196                 } else
4197                         error = newnfs_request(nd, NULL, clp, &clp->lc_req,
4198                             NULL, NULL, cred, clp->lc_program,
4199                             clp->lc_req.nr_vers, NULL, 1, NULL, NULL);
4200         }
4201 errout:
4202         NFSFREECRED(cred);
4203
4204         /*
4205          * If error is set here, the Callback path isn't working
4206          * properly, so twiddle the appropriate LCL_ flags.
4207          * (nd_repstat != 0 indicates the Callback path is working,
4208          *  but the callback failed on the client.)
4209          */
4210         if (error) {
4211                 /*
4212                  * Mark the callback pathway down, which disabled issuing
4213                  * of delegations and gets Renew to return NFSERR_CBPATHDOWN.
4214                  */
4215                 NFSLOCKSTATE();
4216                 clp->lc_flags |= LCL_CBDOWN;
4217                 NFSUNLOCKSTATE();
4218         } else {
4219                 /*
4220                  * Callback worked. If the callback path was down, disable
4221                  * callbacks, so no more delegations will be issued. (This
4222                  * is done on the assumption that the callback pathway is
4223                  * flakey.)
4224                  */
4225                 NFSLOCKSTATE();
4226                 if (clp->lc_flags & LCL_CBDOWN)
4227                         clp->lc_flags &= ~(LCL_CBDOWN | LCL_CALLBACKSON);
4228                 NFSUNLOCKSTATE();
4229                 if (nd->nd_repstat)
4230                         error = nd->nd_repstat;
4231                 else if (error == 0 && procnum == NFSV4OP_CBGETATTR)
4232                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
4233                             NULL, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL,
4234                             p, NULL);
4235                 mbuf_freem(nd->nd_mrep);
4236         }
4237         NFSLOCKSTATE();
4238         clp->lc_cbref--;
4239         if ((clp->lc_flags & LCL_WAKEUPWANTED) && clp->lc_cbref == 0) {
4240                 clp->lc_flags &= ~LCL_WAKEUPWANTED;
4241                 wakeup(clp);
4242         }
4243         NFSUNLOCKSTATE();
4244
4245         NFSEXITCODE(error);
4246         return (error);
4247 }
4248
4249 /*
4250  * Set up the compound RPC for the callback.
4251  */
4252 static int
4253 nfsrv_cbcallargs(struct nfsrv_descript *nd, struct nfsclient *clp,
4254     uint32_t callback, int op, const char *optag, struct nfsdsession **sepp)
4255 {
4256         uint32_t *tl;
4257         int error, len;
4258
4259         len = strlen(optag);
4260         (void)nfsm_strtom(nd, optag, len);
4261         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
4262         if ((nd->nd_flag & ND_NFSV41) != 0) {
4263                 *tl++ = txdr_unsigned(NFSV41_MINORVERSION);
4264                 *tl++ = txdr_unsigned(callback);
4265                 *tl++ = txdr_unsigned(2);
4266                 *tl = txdr_unsigned(NFSV4OP_CBSEQUENCE);
4267                 error = nfsv4_setcbsequence(nd, clp, 1, sepp);
4268                 if (error != 0)
4269                         return (error);
4270                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
4271                 *tl = txdr_unsigned(op);
4272         } else {
4273                 *tl++ = txdr_unsigned(NFSV4_MINORVERSION);
4274                 *tl++ = txdr_unsigned(callback);
4275                 *tl++ = txdr_unsigned(1);
4276                 *tl = txdr_unsigned(op);
4277         }
4278         return (0);
4279 }
4280
4281 /*
4282  * Return the next index# for a clientid. Mostly just increment and return
4283  * the next one, but... if the 32bit unsigned does actually wrap around,
4284  * it should be rebooted.
4285  * At an average rate of one new client per second, it will wrap around in
4286  * approximately 136 years. (I think the server will have been shut
4287  * down or rebooted before then.)
4288  */
4289 static u_int32_t
4290 nfsrv_nextclientindex(void)
4291 {
4292         static u_int32_t client_index = 0;
4293
4294         client_index++;
4295         if (client_index != 0)
4296                 return (client_index);
4297
4298         printf("%s: out of clientids\n", __func__);
4299         return (client_index);
4300 }
4301
4302 /*
4303  * Return the next index# for a stateid. Mostly just increment and return
4304  * the next one, but... if the 32bit unsigned does actually wrap around
4305  * (will a BSD server stay up that long?), find
4306  * new start and end values.
4307  */
4308 static u_int32_t
4309 nfsrv_nextstateindex(struct nfsclient *clp)
4310 {
4311         struct nfsstate *stp;
4312         int i;
4313         u_int32_t canuse, min_index, max_index;
4314
4315         if (!(clp->lc_flags & LCL_INDEXNOTOK)) {
4316                 clp->lc_stateindex++;
4317                 if (clp->lc_stateindex != clp->lc_statemaxindex)
4318                         return (clp->lc_stateindex);
4319         }
4320
4321         /*
4322          * Yuck, we've hit the end.
4323          * Look for a new min and max.
4324          */
4325         min_index = 0;
4326         max_index = 0xffffffff;
4327         for (i = 0; i < nfsrv_statehashsize; i++) {
4328             LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) {
4329                 if (stp->ls_stateid.other[2] > 0x80000000) {
4330                     if (stp->ls_stateid.other[2] < max_index)
4331                         max_index = stp->ls_stateid.other[2];
4332                 } else {
4333                     if (stp->ls_stateid.other[2] > min_index)
4334                         min_index = stp->ls_stateid.other[2];
4335                 }
4336             }
4337         }
4338
4339         /*
4340          * Yikes, highly unlikely, but I'll handle it anyhow.
4341          */
4342         if (min_index == 0x80000000 && max_index == 0x80000001) {
4343             canuse = 0;
4344             /*
4345              * Loop around until we find an unused entry. Return that
4346              * and set LCL_INDEXNOTOK, so the search will continue next time.
4347              * (This is one of those rare cases where a goto is the
4348              *  cleanest way to code the loop.)
4349              */
4350 tryagain:
4351             for (i = 0; i < nfsrv_statehashsize; i++) {
4352                 LIST_FOREACH(stp, &clp->lc_stateid[i], ls_hash) {
4353                     if (stp->ls_stateid.other[2] == canuse) {
4354                         canuse++;
4355                         goto tryagain;
4356                     }
4357                 }
4358             }
4359             clp->lc_flags |= LCL_INDEXNOTOK;
4360             return (canuse);
4361         }
4362
4363         /*
4364          * Ok to start again from min + 1.
4365          */
4366         clp->lc_stateindex = min_index + 1;
4367         clp->lc_statemaxindex = max_index;
4368         clp->lc_flags &= ~LCL_INDEXNOTOK;
4369         return (clp->lc_stateindex);
4370 }
4371
4372 /*
4373  * The following functions handle the stable storage file that deals with
4374  * the edge conditions described in RFC3530 Sec. 8.6.3.
4375  * The file is as follows:
4376  * - a single record at the beginning that has the lease time of the
4377  *   previous server instance (before the last reboot) and the nfsrvboottime
4378  *   values for the previous server boots.
4379  *   These previous boot times are used to ensure that the current
4380  *   nfsrvboottime does not, somehow, get set to a previous one.
4381  *   (This is important so that Stale ClientIDs and StateIDs can
4382  *    be recognized.)
4383  *   The number of previous nfsvrboottime values preceeds the list.
4384  * - followed by some number of appended records with:
4385  *   - client id string
4386  *   - flag that indicates it is a record revoking state via lease
4387  *     expiration or similar
4388  *     OR has successfully acquired state.
4389  * These structures vary in length, with the client string at the end, up
4390  * to NFSV4_OPAQUELIMIT in size.
4391  *
4392  * At the end of the grace period, the file is truncated, the first
4393  * record is rewritten with updated information and any acquired state
4394  * records for successful reclaims of state are written.
4395  *
4396  * Subsequent records are appended when the first state is issued to
4397  * a client and when state is revoked for a client.
4398  *
4399  * When reading the file in, state issued records that come later in
4400  * the file override older ones, since the append log is in cronological order.
4401  * If, for some reason, the file can't be read, the grace period is
4402  * immediately terminated and all reclaims get NFSERR_NOGRACE.
4403  */
4404
4405 /*
4406  * Read in the stable storage file. Called by nfssvc() before the nfsd
4407  * processes start servicing requests.
4408  */
4409 APPLESTATIC void
4410 nfsrv_setupstable(NFSPROC_T *p)
4411 {
4412         struct nfsrv_stablefirst *sf = &nfsrv_stablefirst;
4413         struct nfsrv_stable *sp, *nsp;
4414         struct nfst_rec *tsp;
4415         int error, i, tryagain;
4416         off_t off = 0;
4417         ssize_t aresid, len;
4418
4419         /*
4420          * If NFSNSF_UPDATEDONE is set, this is a restart of the nfsds without
4421          * a reboot, so state has not been lost.
4422          */
4423         if (sf->nsf_flags & NFSNSF_UPDATEDONE)
4424                 return;
4425         /*
4426          * Set Grace over just until the file reads successfully.
4427          */
4428         nfsrvboottime = time_second;
4429         LIST_INIT(&sf->nsf_head);
4430         sf->nsf_flags = (NFSNSF_GRACEOVER | NFSNSF_NEEDLOCK);
4431         sf->nsf_eograce = NFSD_MONOSEC + NFSRV_LEASEDELTA;
4432         if (sf->nsf_fp == NULL)
4433                 return;
4434         error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp),
4435             (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), off, UIO_SYSSPACE,
4436             0, NFSFPCRED(sf->nsf_fp), &aresid, p);
4437         if (error || aresid || sf->nsf_numboots == 0 ||
4438                 sf->nsf_numboots > NFSNSF_MAXNUMBOOTS)
4439                 return;
4440
4441         /*
4442          * Now, read in the boottimes.
4443          */
4444         sf->nsf_bootvals = (time_t *)malloc((sf->nsf_numboots + 1) *
4445                 sizeof (time_t), M_TEMP, M_WAITOK);
4446         off = sizeof (struct nfsf_rec);
4447         error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp),
4448             (caddr_t)sf->nsf_bootvals, sf->nsf_numboots * sizeof (time_t), off,
4449             UIO_SYSSPACE, 0, NFSFPCRED(sf->nsf_fp), &aresid, p);
4450         if (error || aresid) {
4451                 free((caddr_t)sf->nsf_bootvals, M_TEMP);
4452                 sf->nsf_bootvals = NULL;
4453                 return;
4454         }
4455
4456         /*
4457          * Make sure this nfsrvboottime is different from all recorded
4458          * previous ones.
4459          */
4460         do {
4461                 tryagain = 0;
4462                 for (i = 0; i < sf->nsf_numboots; i++) {
4463                         if (nfsrvboottime == sf->nsf_bootvals[i]) {
4464                                 nfsrvboottime++;
4465                                 tryagain = 1;
4466                                 break;
4467                         }
4468                 }
4469         } while (tryagain);
4470
4471         sf->nsf_flags |= NFSNSF_OK;
4472         off += (sf->nsf_numboots * sizeof (time_t));
4473
4474         /*
4475          * Read through the file, building a list of records for grace
4476          * checking.
4477          * Each record is between sizeof (struct nfst_rec) and
4478          * sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1
4479          * and is actually sizeof (struct nfst_rec) + nst_len - 1.
4480          */
4481         tsp = (struct nfst_rec *)malloc(sizeof (struct nfst_rec) +
4482                 NFSV4_OPAQUELIMIT - 1, M_TEMP, M_WAITOK);
4483         do {
4484             error = NFSD_RDWR(UIO_READ, NFSFPVNODE(sf->nsf_fp),
4485                 (caddr_t)tsp, sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1,
4486                 off, UIO_SYSSPACE, 0, NFSFPCRED(sf->nsf_fp), &aresid, p);
4487             len = (sizeof (struct nfst_rec) + NFSV4_OPAQUELIMIT - 1) - aresid;
4488             if (error || (len > 0 && (len < sizeof (struct nfst_rec) ||
4489                 len < (sizeof (struct nfst_rec) + tsp->len - 1)))) {
4490                 /*
4491                  * Yuck, the file has been corrupted, so just return
4492                  * after clearing out any restart state, so the grace period
4493                  * is over.
4494                  */
4495                 LIST_FOREACH_SAFE(sp, &sf->nsf_head, nst_list, nsp) {
4496                         LIST_REMOVE(sp, nst_list);
4497                         free((caddr_t)sp, M_TEMP);
4498                 }
4499                 free((caddr_t)tsp, M_TEMP);
4500                 sf->nsf_flags &= ~NFSNSF_OK;
4501                 free((caddr_t)sf->nsf_bootvals, M_TEMP);
4502                 sf->nsf_bootvals = NULL;
4503                 return;
4504             }
4505             if (len > 0) {
4506                 off += sizeof (struct nfst_rec) + tsp->len - 1;
4507                 /*
4508                  * Search the list for a matching client.
4509                  */
4510                 LIST_FOREACH(sp, &sf->nsf_head, nst_list) {
4511                         if (tsp->len == sp->nst_len &&
4512                             !NFSBCMP(tsp->client, sp->nst_client, tsp->len))
4513                                 break;
4514                 }
4515                 if (sp == LIST_END(&sf->nsf_head)) {
4516                         sp = (struct nfsrv_stable *)malloc(tsp->len +
4517                                 sizeof (struct nfsrv_stable) - 1, M_TEMP,
4518                                 M_WAITOK);
4519                         NFSBCOPY((caddr_t)tsp, (caddr_t)&sp->nst_rec,
4520                                 sizeof (struct nfst_rec) + tsp->len - 1);
4521                         LIST_INSERT_HEAD(&sf->nsf_head, sp, nst_list);
4522                 } else {
4523                         if (tsp->flag == NFSNST_REVOKE)
4524                                 sp->nst_flag |= NFSNST_REVOKE;
4525                         else
4526                                 /*
4527                                  * A subsequent timestamp indicates the client
4528                                  * did a setclientid/confirm and any previous
4529                                  * revoke is no longer relevant.
4530                                  */
4531                                 sp->nst_flag &= ~NFSNST_REVOKE;
4532                 }
4533             }
4534         } while (len > 0);
4535         free((caddr_t)tsp, M_TEMP);
4536         sf->nsf_flags = NFSNSF_OK;
4537         sf->nsf_eograce = NFSD_MONOSEC + sf->nsf_lease +
4538                 NFSRV_LEASEDELTA;
4539 }
4540
4541 /*
4542  * Update the stable storage file, now that the grace period is over.
4543  */
4544 APPLESTATIC void
4545 nfsrv_updatestable(NFSPROC_T *p)
4546 {
4547         struct nfsrv_stablefirst *sf = &nfsrv_stablefirst;
4548         struct nfsrv_stable *sp, *nsp;
4549         int i;
4550         struct nfsvattr nva;
4551         vnode_t vp;
4552 #if defined(__FreeBSD_version) && (__FreeBSD_version >= 500000)
4553         mount_t mp = NULL;
4554 #endif
4555         int error;
4556
4557         if (sf->nsf_fp == NULL || (sf->nsf_flags & NFSNSF_UPDATEDONE))
4558                 return;
4559         sf->nsf_flags |= NFSNSF_UPDATEDONE;
4560         /*
4561          * Ok, we need to rewrite the stable storage file.
4562          * - truncate to 0 length
4563          * - write the new first structure
4564          * - loop through the data structures, writing out any that
4565          *   have timestamps older than the old boot
4566          */
4567         if (sf->nsf_bootvals) {
4568                 sf->nsf_numboots++;
4569                 for (i = sf->nsf_numboots - 2; i >= 0; i--)
4570                         sf->nsf_bootvals[i + 1] = sf->nsf_bootvals[i];
4571         } else {
4572                 sf->nsf_numboots = 1;
4573                 sf->nsf_bootvals = (time_t *)malloc(sizeof (time_t),
4574                         M_TEMP, M_WAITOK);
4575         }
4576         sf->nsf_bootvals[0] = nfsrvboottime;
4577         sf->nsf_lease = nfsrv_lease;
4578         NFSVNO_ATTRINIT(&nva);
4579         NFSVNO_SETATTRVAL(&nva, size, 0);
4580         vp = NFSFPVNODE(sf->nsf_fp);
4581         vn_start_write(vp, &mp, V_WAIT);
4582         if (NFSVOPLOCK(vp, LK_EXCLUSIVE) == 0) {
4583                 error = nfsvno_setattr(vp, &nva, NFSFPCRED(sf->nsf_fp), p,
4584                     NULL);
4585                 NFSVOPUNLOCK(vp, 0);
4586         } else
4587                 error = EPERM;
4588         vn_finished_write(mp);
4589         if (!error)
4590             error = NFSD_RDWR(UIO_WRITE, vp,
4591                 (caddr_t)&sf->nsf_rec, sizeof (struct nfsf_rec), (off_t)0,
4592                 UIO_SYSSPACE, IO_SYNC, NFSFPCRED(sf->nsf_fp), NULL, p);
4593         if (!error)
4594             error = NFSD_RDWR(UIO_WRITE, vp,
4595                 (caddr_t)sf->nsf_bootvals,
4596                 sf->nsf_numboots * sizeof (time_t),
4597                 (off_t)(sizeof (struct nfsf_rec)),
4598                 UIO_SYSSPACE, IO_SYNC, NFSFPCRED(sf->nsf_fp), NULL, p);
4599         free((caddr_t)sf->nsf_bootvals, M_TEMP);
4600         sf->nsf_bootvals = NULL;
4601         if (error) {
4602                 sf->nsf_flags &= ~NFSNSF_OK;
4603                 printf("EEK! Can't write NfsV4 stable storage file\n");
4604                 return;
4605         }
4606         sf->nsf_flags |= NFSNSF_OK;
4607
4608         /*
4609          * Loop through the list and write out timestamp records for
4610          * any clients that successfully reclaimed state.
4611          */
4612         LIST_FOREACH_SAFE(sp, &sf->nsf_head, nst_list, nsp) {
4613                 if (sp->nst_flag & NFSNST_GOTSTATE) {
4614                         nfsrv_writestable(sp->nst_client, sp->nst_len,
4615                                 NFSNST_NEWSTATE, p);
4616                         sp->nst_clp->lc_flags |= LCL_STAMPEDSTABLE;
4617                 }
4618                 LIST_REMOVE(sp, nst_list);
4619                 free((caddr_t)sp, M_TEMP);
4620         }
4621         nfsrv_backupstable();
4622 }
4623
4624 /*
4625  * Append a record to the stable storage file.
4626  */
4627 APPLESTATIC void
4628 nfsrv_writestable(u_char *client, int len, int flag, NFSPROC_T *p)
4629 {
4630         struct nfsrv_stablefirst *sf = &nfsrv_stablefirst;
4631         struct nfst_rec *sp;
4632         int error;
4633
4634         if (!(sf->nsf_flags & NFSNSF_OK) || sf->nsf_fp == NULL)
4635                 return;
4636         sp = (struct nfst_rec *)malloc(sizeof (struct nfst_rec) +
4637                 len - 1, M_TEMP, M_WAITOK);
4638         sp->len = len;
4639         NFSBCOPY(client, sp->client, len);
4640         sp->flag = flag;
4641         error = NFSD_RDWR(UIO_WRITE, NFSFPVNODE(sf->nsf_fp),
4642             (caddr_t)sp, sizeof (struct nfst_rec) + len - 1, (off_t)0,
4643             UIO_SYSSPACE, (IO_SYNC | IO_APPEND), NFSFPCRED(sf->nsf_fp), NULL, p);
4644         free((caddr_t)sp, M_TEMP);
4645         if (error) {
4646                 sf->nsf_flags &= ~NFSNSF_OK;
4647                 printf("EEK! Can't write NfsV4 stable storage file\n");
4648         }
4649 }
4650
4651 /*
4652  * This function is called during the grace period to mark a client
4653  * that successfully reclaimed state.
4654  */
4655 static void
4656 nfsrv_markstable(struct nfsclient *clp)
4657 {
4658         struct nfsrv_stable *sp;
4659
4660         /*
4661          * First find the client structure.
4662          */
4663         LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) {
4664                 if (sp->nst_len == clp->lc_idlen &&
4665                     !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len))
4666                         break;
4667         }
4668         if (sp == LIST_END(&nfsrv_stablefirst.nsf_head))
4669                 return;
4670
4671         /*
4672          * Now, just mark it and set the nfsclient back pointer.
4673          */
4674         sp->nst_flag |= NFSNST_GOTSTATE;
4675         sp->nst_clp = clp;
4676 }
4677
4678 /*
4679  * This function is called for a reclaim, to see if it gets grace.
4680  * It returns 0 if a reclaim is allowed, 1 otherwise.
4681  */
4682 static int
4683 nfsrv_checkstable(struct nfsclient *clp)
4684 {
4685         struct nfsrv_stable *sp;
4686
4687         /*
4688          * First, find the entry for the client.
4689          */
4690         LIST_FOREACH(sp, &nfsrv_stablefirst.nsf_head, nst_list) {
4691                 if (sp->nst_len == clp->lc_idlen &&
4692                     !NFSBCMP(sp->nst_client, clp->lc_id, sp->nst_len))
4693                         break;
4694         }
4695
4696         /*
4697          * If not in the list, state was revoked or no state was issued
4698          * since the previous reboot, a reclaim is denied.
4699          */
4700         if (sp == LIST_END(&nfsrv_stablefirst.nsf_head) ||
4701             (sp->nst_flag & NFSNST_REVOKE) ||
4702             !(nfsrv_stablefirst.nsf_flags & NFSNSF_OK))
4703                 return (1);
4704         return (0);
4705 }
4706
4707 /*
4708  * Test for and try to clear out a conflicting client. This is called by
4709  * nfsrv_lockctrl() and nfsrv_openctrl() when conflicts with other clients
4710  * a found.
4711  * The trick here is that it can't revoke a conflicting client with an
4712  * expired lease unless it holds the v4root lock, so...
4713  * If no v4root lock, get the lock and return 1 to indicate "try again".
4714  * Return 0 to indicate the conflict can't be revoked and 1 to indicate
4715  * the revocation worked and the conflicting client is "bye, bye", so it
4716  * can be tried again.
4717  * Return 2 to indicate that the vnode is VI_DOOMED after NFSVOPLOCK().
4718  * Unlocks State before a non-zero value is returned.
4719  */
4720 static int
4721 nfsrv_clientconflict(struct nfsclient *clp, int *haslockp, vnode_t vp,
4722     NFSPROC_T *p)
4723 {
4724         int gotlock, lktype = 0;
4725
4726         /*
4727          * If lease hasn't expired, we can't fix it.
4728          */
4729         if (clp->lc_expiry >= NFSD_MONOSEC ||
4730             !(nfsrv_stablefirst.nsf_flags & NFSNSF_UPDATEDONE))
4731                 return (0);
4732         if (*haslockp == 0) {
4733                 NFSUNLOCKSTATE();
4734                 if (vp != NULL) {
4735                         lktype = NFSVOPISLOCKED(vp);
4736                         NFSVOPUNLOCK(vp, 0);
4737                 }
4738                 NFSLOCKV4ROOTMUTEX();
4739                 nfsv4_relref(&nfsv4rootfs_lock);
4740                 do {
4741                         gotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
4742                             NFSV4ROOTLOCKMUTEXPTR, NULL);
4743                 } while (!gotlock);
4744                 NFSUNLOCKV4ROOTMUTEX();
4745                 *haslockp = 1;
4746                 if (vp != NULL) {
4747                         NFSVOPLOCK(vp, lktype | LK_RETRY);
4748                         if ((vp->v_iflag & VI_DOOMED) != 0)
4749                                 return (2);
4750                 }
4751                 return (1);
4752         }
4753         NFSUNLOCKSTATE();
4754
4755         /*
4756          * Ok, we can expire the conflicting client.
4757          */
4758         nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p);
4759         nfsrv_backupstable();
4760         nfsrv_cleanclient(clp, p);
4761         nfsrv_freedeleglist(&clp->lc_deleg);
4762         nfsrv_freedeleglist(&clp->lc_olddeleg);
4763         LIST_REMOVE(clp, lc_hash);
4764         nfsrv_zapclient(clp, p);
4765         return (1);
4766 }
4767
4768 /*
4769  * Resolve a delegation conflict.
4770  * Returns 0 to indicate the conflict was resolved without sleeping.
4771  * Return -1 to indicate that the caller should check for conflicts again.
4772  * Return > 0 for an error that should be returned, normally NFSERR_DELAY.
4773  *
4774  * Also, manipulate the nfsv4root_lock, as required. It isn't changed
4775  * for a return of 0, since there was no sleep and it could be required
4776  * later. It is released for a return of NFSERR_DELAY, since the caller
4777  * will return that error. It is released when a sleep was done waiting
4778  * for the delegation to be returned or expire (so that other nfsds can
4779  * handle ops). Then, it must be acquired for the write to stable storage.
4780  * (This function is somewhat similar to nfsrv_clientconflict(), but
4781  *  the semantics differ in a couple of subtle ways. The return of 0
4782  *  indicates the conflict was resolved without sleeping here, not
4783  *  that the conflict can't be resolved and the handling of nfsv4root_lock
4784  *  differs, as noted above.)
4785  * Unlocks State before returning a non-zero value.
4786  */
4787 static int
4788 nfsrv_delegconflict(struct nfsstate *stp, int *haslockp, NFSPROC_T *p,
4789     vnode_t vp)
4790 {
4791         struct nfsclient *clp = stp->ls_clp;
4792         int gotlock, error, lktype = 0, retrycnt, zapped_clp;
4793         nfsv4stateid_t tstateid;
4794         fhandle_t tfh;
4795
4796         /*
4797          * If the conflict is with an old delegation...
4798          */
4799         if (stp->ls_flags & NFSLCK_OLDDELEG) {
4800                 /*
4801                  * You can delete it, if it has expired.
4802                  */
4803                 if (clp->lc_delegtime < NFSD_MONOSEC) {
4804                         nfsrv_freedeleg(stp);
4805                         NFSUNLOCKSTATE();
4806                         error = -1;
4807                         goto out;
4808                 }
4809                 NFSUNLOCKSTATE();
4810                 /*
4811                  * During this delay, the old delegation could expire or it
4812                  * could be recovered by the client via an Open with
4813                  * CLAIM_DELEGATE_PREV.
4814                  * Release the nfsv4root_lock, if held.
4815                  */
4816                 if (*haslockp) {
4817                         *haslockp = 0;
4818                         NFSLOCKV4ROOTMUTEX();
4819                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
4820                         NFSUNLOCKV4ROOTMUTEX();
4821                 }
4822                 error = NFSERR_DELAY;
4823                 goto out;
4824         }
4825
4826         /*
4827          * It's a current delegation, so:
4828          * - check to see if the delegation has expired
4829          *   - if so, get the v4root lock and then expire it
4830          */
4831         if (!(stp->ls_flags & NFSLCK_DELEGRECALL)) {
4832                 /*
4833                  * - do a recall callback, since not yet done
4834                  * For now, never allow truncate to be set. To use
4835                  * truncate safely, it must be guaranteed that the
4836                  * Remove, Rename or Setattr with size of 0 will
4837                  * succeed and that would require major changes to
4838                  * the VFS/Vnode OPs.
4839                  * Set the expiry time large enough so that it won't expire
4840                  * until after the callback, then set it correctly, once
4841                  * the callback is done. (The delegation will now time
4842                  * out whether or not the Recall worked ok. The timeout
4843                  * will be extended when ops are done on the delegation
4844                  * stateid, up to the timelimit.)
4845                  */
4846                 stp->ls_delegtime = NFSD_MONOSEC + (2 * nfsrv_lease) +
4847                     NFSRV_LEASEDELTA;
4848                 stp->ls_delegtimelimit = NFSD_MONOSEC + (6 * nfsrv_lease) +
4849                     NFSRV_LEASEDELTA;
4850                 stp->ls_flags |= NFSLCK_DELEGRECALL;
4851
4852                 /*
4853                  * Loop NFSRV_CBRETRYCNT times while the CBRecall replies
4854                  * NFSERR_BADSTATEID or NFSERR_BADHANDLE. This is done
4855                  * in order to try and avoid a race that could happen
4856                  * when a CBRecall request passed the Open reply with
4857                  * the delegation in it when transitting the network.
4858                  * Since nfsrv_docallback will sleep, don't use stp after
4859                  * the call.
4860                  */
4861                 NFSBCOPY((caddr_t)&stp->ls_stateid, (caddr_t)&tstateid,
4862                     sizeof (tstateid));
4863                 NFSBCOPY((caddr_t)&stp->ls_lfp->lf_fh, (caddr_t)&tfh,
4864                     sizeof (tfh));
4865                 NFSUNLOCKSTATE();
4866                 if (*haslockp) {
4867                         *haslockp = 0;
4868                         NFSLOCKV4ROOTMUTEX();
4869                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
4870                         NFSUNLOCKV4ROOTMUTEX();
4871                 }
4872                 retrycnt = 0;
4873                 do {
4874                     error = nfsrv_docallback(clp, NFSV4OP_CBRECALL,
4875                         &tstateid, 0, &tfh, NULL, NULL, p);
4876                     retrycnt++;
4877                 } while ((error == NFSERR_BADSTATEID ||
4878                     error == NFSERR_BADHANDLE) && retrycnt < NFSV4_CBRETRYCNT);
4879                 error = NFSERR_DELAY;
4880                 goto out;
4881         }
4882
4883         if (clp->lc_expiry >= NFSD_MONOSEC &&
4884             stp->ls_delegtime >= NFSD_MONOSEC) {
4885                 NFSUNLOCKSTATE();
4886                 /*
4887                  * A recall has been done, but it has not yet expired.
4888                  * So, RETURN_DELAY.
4889                  */
4890                 if (*haslockp) {
4891                         *haslockp = 0;
4892                         NFSLOCKV4ROOTMUTEX();
4893                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
4894                         NFSUNLOCKV4ROOTMUTEX();
4895                 }
4896                 error = NFSERR_DELAY;
4897                 goto out;
4898         }
4899
4900         /*
4901          * If we don't yet have the lock, just get it and then return,
4902          * since we need that before deleting expired state, such as
4903          * this delegation.
4904          * When getting the lock, unlock the vnode, so other nfsds that
4905          * are in progress, won't get stuck waiting for the vnode lock.
4906          */
4907         if (*haslockp == 0) {
4908                 NFSUNLOCKSTATE();
4909                 if (vp != NULL) {
4910                         lktype = NFSVOPISLOCKED(vp);
4911                         NFSVOPUNLOCK(vp, 0);
4912                 }
4913                 NFSLOCKV4ROOTMUTEX();
4914                 nfsv4_relref(&nfsv4rootfs_lock);
4915                 do {
4916                         gotlock = nfsv4_lock(&nfsv4rootfs_lock, 1, NULL,
4917                             NFSV4ROOTLOCKMUTEXPTR, NULL);
4918                 } while (!gotlock);
4919                 NFSUNLOCKV4ROOTMUTEX();
4920                 *haslockp = 1;
4921                 if (vp != NULL) {
4922                         NFSVOPLOCK(vp, lktype | LK_RETRY);
4923                         if ((vp->v_iflag & VI_DOOMED) != 0) {
4924                                 *haslockp = 0;
4925                                 NFSLOCKV4ROOTMUTEX();
4926                                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
4927                                 NFSUNLOCKV4ROOTMUTEX();
4928                                 error = NFSERR_PERM;
4929                                 goto out;
4930                         }
4931                 }
4932                 error = -1;
4933                 goto out;
4934         }
4935
4936         NFSUNLOCKSTATE();
4937         /*
4938          * Ok, we can delete the expired delegation.
4939          * First, write the Revoke record to stable storage and then
4940          * clear out the conflict.
4941          * Since all other nfsd threads are now blocked, we can safely
4942          * sleep without the state changing.
4943          */
4944         nfsrv_writestable(clp->lc_id, clp->lc_idlen, NFSNST_REVOKE, p);
4945         nfsrv_backupstable();
4946         if (clp->lc_expiry < NFSD_MONOSEC) {
4947                 nfsrv_cleanclient(clp, p);
4948                 nfsrv_freedeleglist(&clp->lc_deleg);
4949                 nfsrv_freedeleglist(&clp->lc_olddeleg);
4950                 LIST_REMOVE(clp, lc_hash);
4951                 zapped_clp = 1;
4952         } else {
4953                 nfsrv_freedeleg(stp);
4954                 zapped_clp = 0;
4955         }
4956         if (zapped_clp)
4957                 nfsrv_zapclient(clp, p);
4958         error = -1;
4959
4960 out:
4961         NFSEXITCODE(error);
4962         return (error);
4963 }
4964
4965 /*
4966  * Check for a remove allowed, if remove is set to 1 and get rid of
4967  * delegations.
4968  */
4969 APPLESTATIC int
4970 nfsrv_checkremove(vnode_t vp, int remove, NFSPROC_T *p)
4971 {
4972         struct nfsstate *stp;
4973         struct nfslockfile *lfp;
4974         int error, haslock = 0;
4975         fhandle_t nfh;
4976
4977         /*
4978          * First, get the lock file structure.
4979          * (A return of -1 means no associated state, so remove ok.)
4980          */
4981         error = nfsrv_getlockfh(vp, NFSLCK_CHECK, NULL, &nfh, p);
4982 tryagain:
4983         NFSLOCKSTATE();
4984         if (!error)
4985                 error = nfsrv_getlockfile(NFSLCK_CHECK, NULL, &lfp, &nfh, 0);
4986         if (error) {
4987                 NFSUNLOCKSTATE();
4988                 if (haslock) {
4989                         NFSLOCKV4ROOTMUTEX();
4990                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
4991                         NFSUNLOCKV4ROOTMUTEX();
4992                 }
4993                 if (error == -1)
4994                         error = 0;
4995                 goto out;
4996         }
4997
4998         /*
4999          * Now, we must Recall any delegations.
5000          */
5001         error = nfsrv_cleandeleg(vp, lfp, NULL, &haslock, p);
5002         if (error) {
5003                 /*
5004                  * nfsrv_cleandeleg() unlocks state for non-zero
5005                  * return.
5006                  */
5007                 if (error == -1)
5008                         goto tryagain;
5009                 if (haslock) {
5010                         NFSLOCKV4ROOTMUTEX();
5011                         nfsv4_unlock(&nfsv4rootfs_lock, 1);
5012                         NFSUNLOCKV4ROOTMUTEX();
5013                 }
5014                 goto out;
5015         }
5016
5017         /*
5018          * Now, look for a conflicting open share.
5019          */
5020         if (remove) {
5021                 LIST_FOREACH(stp, &lfp->lf_open, ls_file) {
5022                         if (stp->ls_flags & NFSLCK_WRITEDENY) {
5023                                 error = NFSERR_FILEOPEN;
5024                                 break;
5025                         }
5026                 }
5027         }
5028
5029         NFSUNLOCKSTATE();
5030         if (haslock) {
5031                 NFSLOCKV4ROOTMUTEX();
5032                 nfsv4_unlock(&nfsv4rootfs_lock, 1);
5033                 NFSUNLOCKV4ROOTMUTEX();
5034         }
5035
5036 out:
5037         NFSEXITCODE(error);
5038         return (error);
5039 }
5040
5041 /*
5042  * Clear out all delegations for the file referred to by lfp.
5043  * May return NFSERR_DELAY, if there will be a delay waiting for
5044  * delegations to expire.
5045  * Returns -1 to indicate it slept while recalling a delegation.
5046  * This function has the side effect of deleting the nfslockfile structure,
5047  * if it no longer has associated state and didn't have to sleep.
5048  * Unlocks State before a non-zero value is returned.
5049  */
5050 static int
5051 nfsrv_cleandeleg(vnode_t vp, struct nfslockfile *lfp,
5052     struct nfsclient *clp, int *haslockp, NFSPROC_T *p)
5053 {
5054         struct nfsstate *stp, *nstp;
5055         int ret = 0;
5056
5057         stp = LIST_FIRST(&lfp->lf_deleg);
5058         while (stp != LIST_END(&lfp->lf_deleg)) {
5059                 nstp = LIST_NEXT(stp, ls_file);
5060                 if (stp->ls_clp != clp) {
5061                         ret = nfsrv_delegconflict(stp, haslockp, p, vp);
5062                         if (ret) {
5063                                 /*
5064                                  * nfsrv_delegconflict() unlocks state
5065                                  * when it returns non-zero.
5066                                  */
5067                                 goto out;
5068                         }
5069                 }
5070                 stp = nstp;
5071         }
5072 out:
5073         NFSEXITCODE(ret);
5074         return (ret);
5075 }
5076
5077 /*
5078  * There are certain operations that, when being done outside of NFSv4,
5079  * require that any NFSv4 delegation for the file be recalled.
5080  * This function is to be called for those cases:
5081  * VOP_RENAME() - When a delegation is being recalled for any reason,
5082  *      the client may have to do Opens against the server, using the file's
5083  *      final component name. If the file has been renamed on the server,
5084  *      that component name will be incorrect and the Open will fail.
5085  * VOP_REMOVE() - Theoretically, a client could Open a file after it has
5086  *      been removed on the server, if there is a delegation issued to
5087  *      that client for the file. I say "theoretically" since clients
5088  *      normally do an Access Op before the Open and that Access Op will
5089  *      fail with ESTALE. Note that NFSv2 and 3 don't even do Opens, so
5090  *      they will detect the file's removal in the same manner. (There is
5091  *      one case where RFC3530 allows a client to do an Open without first
5092  *      doing an Access Op, which is passage of a check against the ACE
5093  *      returned with a Write delegation, but current practice is to ignore
5094  *      the ACE and always do an Access Op.)
5095  *      Since the functions can only be called with an unlocked vnode, this
5096  *      can't be done at this time.
5097  * VOP_ADVLOCK() - When a client holds a delegation, it can issue byte range
5098  *      locks locally in the client, which are not visible to the server. To
5099  *      deal with this, issuing of delegations for a vnode must be disabled
5100  *      and all delegations for the vnode recalled. This is done via the
5101  *      second function, using the VV_DISABLEDELEG vflag on the vnode.
5102  */
5103 APPLESTATIC void
5104 nfsd_recalldelegation(vnode_t vp, NFSPROC_T *p)
5105 {
5106         time_t starttime;
5107         int error;
5108
5109         /*
5110          * First, check to see if the server is currently running and it has
5111          * been called for a regular file when issuing delegations.
5112          */
5113         if (newnfs_numnfsd == 0 || vp->v_type != VREG ||
5114             nfsrv_issuedelegs == 0)
5115                 return;
5116
5117         KASSERT((NFSVOPISLOCKED(vp) != LK_EXCLUSIVE), ("vp %p is locked", vp));
5118         /*
5119          * First, get a reference on the nfsv4rootfs_lock so that an
5120          * exclusive lock cannot be acquired by another thread.
5121          */
5122         NFSLOCKV4ROOTMUTEX();
5123         nfsv4_getref(&nfsv4rootfs_lock, NULL, NFSV4ROOTLOCKMUTEXPTR, NULL);
5124         NFSUNLOCKV4ROOTMUTEX();
5125
5126         /*
5127          * Now, call nfsrv_checkremove() in a loop while it returns
5128          * NFSERR_DELAY. Return upon any other error or when timed out.
5129          */
5130         starttime = NFSD_MONOSEC;
5131         do {
5132                 if (NFSVOPLOCK(vp, LK_EXCLUSIVE) == 0) {
5133                         error = nfsrv_checkremove(vp, 0, p);
5134                         NFSVOPUNLOCK(vp, 0);
5135                 } else
5136                         error = EPERM;
5137                 if (error == NFSERR_DELAY) {
5138                         if (NFSD_MONOSEC - starttime > NFS_REMOVETIMEO)
5139                                 break;
5140                         /* Sleep for a short period of time */
5141                         (void) nfs_catnap(PZERO, 0, "nfsremove");
5142                 }
5143         } while (error == NFSERR_DELAY);
5144         NFSLOCKV4ROOTMUTEX();
5145         nfsv4_relref(&nfsv4rootfs_lock);
5146         NFSUNLOCKV4ROOTMUTEX();
5147 }
5148
5149 APPLESTATIC void
5150 nfsd_disabledelegation(vnode_t vp, NFSPROC_T *p)
5151 {
5152
5153 #ifdef VV_DISABLEDELEG
5154         /*
5155          * First, flag issuance of delegations disabled.
5156          */
5157         atomic_set_long(&vp->v_vflag, VV_DISABLEDELEG);
5158 #endif
5159
5160         /*
5161          * Then call nfsd_recalldelegation() to get rid of all extant
5162          * delegations.
5163          */
5164         nfsd_recalldelegation(vp, p);
5165 }
5166
5167 /*
5168  * Check for conflicting locks, etc. and then get rid of delegations.
5169  * (At one point I thought that I should get rid of delegations for any
5170  *  Setattr, since it could potentially disallow the I/O op (read or write)
5171  *  allowed by the delegation. However, Setattr Ops that aren't changing
5172  *  the size get a stateid of all 0s, so you can't tell if it is a delegation
5173  *  for the same client or a different one, so I decided to only get rid
5174  *  of delegations for other clients when the size is being changed.)
5175  * In general, a Setattr can disable NFS I/O Ops that are outstanding, such
5176  * as Write backs, even if there is no delegation, so it really isn't any
5177  * different?)
5178  */
5179 APPLESTATIC int
5180 nfsrv_checksetattr(vnode_t vp, struct nfsrv_descript *nd,
5181     nfsv4stateid_t *stateidp, struct nfsvattr *nvap, nfsattrbit_t *attrbitp,
5182     struct nfsexstuff *exp, NFSPROC_T *p)
5183 {
5184         struct nfsstate st, *stp = &st;
5185         struct nfslock lo, *lop = &lo;
5186         int error = 0;
5187         nfsquad_t clientid;
5188
5189         if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_SIZE)) {
5190                 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
5191                 lop->lo_first = nvap->na_size;
5192         } else {
5193                 stp->ls_flags = 0;
5194                 lop->lo_first = 0;
5195         }
5196         if (NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNER) ||
5197             NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_OWNERGROUP) ||
5198             NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_MODE) ||
5199             NFSISSET_ATTRBIT(attrbitp, NFSATTRBIT_ACL))
5200                 stp->ls_flags |= NFSLCK_SETATTR;
5201         if (stp->ls_flags == 0)
5202                 goto out;
5203         lop->lo_end = NFS64BITSSET;
5204         lop->lo_flags = NFSLCK_WRITE;
5205         stp->ls_ownerlen = 0;
5206         stp->ls_op = NULL;
5207         stp->ls_uid = nd->nd_cred->cr_uid;
5208         stp->ls_stateid.seqid = stateidp->seqid;
5209         clientid.lval[0] = stp->ls_stateid.other[0] = stateidp->other[0];
5210         clientid.lval[1] = stp->ls_stateid.other[1] = stateidp->other[1];
5211         stp->ls_stateid.other[2] = stateidp->other[2];
5212         error = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
5213             stateidp, exp, nd, p);
5214
5215 out:
5216         NFSEXITCODE2(error, nd);
5217         return (error);
5218 }
5219
5220 /*
5221  * Check for a write delegation and do a CBGETATTR if there is one, updating
5222  * the attributes, as required.
5223  * Should I return an error if I can't get the attributes? (For now, I'll
5224  * just return ok.
5225  */
5226 APPLESTATIC int
5227 nfsrv_checkgetattr(struct nfsrv_descript *nd, vnode_t vp,
5228     struct nfsvattr *nvap, nfsattrbit_t *attrbitp, struct ucred *cred,
5229     NFSPROC_T *p)
5230 {
5231         struct nfsstate *stp;
5232         struct nfslockfile *lfp;
5233         struct nfsclient *clp;
5234         struct nfsvattr nva;
5235         fhandle_t nfh;
5236         int error = 0;
5237         nfsattrbit_t cbbits;
5238         u_quad_t delegfilerev;
5239
5240         NFSCBGETATTR_ATTRBIT(attrbitp, &cbbits);
5241         if (!NFSNONZERO_ATTRBIT(&cbbits))
5242                 goto out;
5243
5244         /*
5245          * Get the lock file structure.
5246          * (A return of -1 means no associated state, so return ok.)
5247          */
5248         error = nfsrv_getlockfh(vp, NFSLCK_CHECK, NULL, &nfh, p);
5249         NFSLOCKSTATE();
5250         if (!error)
5251                 error = nfsrv_getlockfile(NFSLCK_CHECK, NULL, &lfp, &nfh, 0);
5252         if (error) {
5253                 NFSUNLOCKSTATE();
5254                 if (error == -1)
5255                         error = 0;
5256                 goto out;
5257         }
5258
5259         /*
5260          * Now, look for a write delegation.
5261          */
5262         LIST_FOREACH(stp, &lfp->lf_deleg, ls_file) {
5263                 if (stp->ls_flags & NFSLCK_DELEGWRITE)
5264                         break;
5265         }
5266         if (stp == LIST_END(&lfp->lf_deleg)) {
5267                 NFSUNLOCKSTATE();
5268                 goto out;
5269         }
5270         clp = stp->ls_clp;
5271         delegfilerev = stp->ls_filerev;
5272
5273         /*
5274          * If the Write delegation was issued as a part of this Compound RPC
5275          * or if we have an Implied Clientid (used in a previous Op in this
5276          * compound) and it is the client the delegation was issued to,
5277          * just return ok.
5278          * I also assume that it is from the same client iff the network
5279          * host IP address is the same as the callback address. (Not
5280          * exactly correct by the RFC, but avoids a lot of Getattr
5281          * callbacks.)
5282          */
5283         if (nd->nd_compref == stp->ls_compref ||
5284             ((nd->nd_flag & ND_IMPLIEDCLID) &&
5285              clp->lc_clientid.qval == nd->nd_clientid.qval) ||
5286              nfsaddr2_match(clp->lc_req.nr_nam, nd->nd_nam)) {
5287                 NFSUNLOCKSTATE();
5288                 goto out;
5289         }
5290
5291         /*
5292          * We are now done with the delegation state structure,
5293          * so the statelock can be released and we can now tsleep().
5294          */
5295
5296         /*
5297          * Now, we must do the CB Getattr callback, to see if Change or Size
5298          * has changed.
5299          */
5300         if (clp->lc_expiry >= NFSD_MONOSEC) {
5301                 NFSUNLOCKSTATE();
5302                 NFSVNO_ATTRINIT(&nva);
5303                 nva.na_filerev = NFS64BITSSET;
5304                 error = nfsrv_docallback(clp, NFSV4OP_CBGETATTR, NULL,
5305                     0, &nfh, &nva, &cbbits, p);
5306                 if (!error) {
5307                         if ((nva.na_filerev != NFS64BITSSET &&
5308                             nva.na_filerev > delegfilerev) ||
5309                             (NFSVNO_ISSETSIZE(&nva) &&
5310                              nva.na_size != nvap->na_size)) {
5311                                 error = nfsvno_updfilerev(vp, nvap, cred, p);
5312                                 if (NFSVNO_ISSETSIZE(&nva))
5313                                         nvap->na_size = nva.na_size;
5314                         }
5315                 } else
5316                         error = 0;      /* Ignore callback errors for now. */
5317         } else {
5318                 NFSUNLOCKSTATE();
5319         }
5320
5321 out:
5322         NFSEXITCODE2(error, nd);
5323         return (error);
5324 }
5325
5326 /*
5327  * This function looks for openowners that haven't had any opens for
5328  * a while and throws them away. Called by an nfsd when NFSNSF_NOOPENS
5329  * is set.
5330  */
5331 APPLESTATIC void
5332 nfsrv_throwawayopens(NFSPROC_T *p)
5333 {
5334         struct nfsclient *clp, *nclp;
5335         struct nfsstate *stp, *nstp;
5336         int i;
5337
5338         NFSLOCKSTATE();
5339         nfsrv_stablefirst.nsf_flags &= ~NFSNSF_NOOPENS;
5340         /*
5341          * For each client...
5342          */
5343         for (i = 0; i < nfsrv_clienthashsize; i++) {
5344             LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) {
5345                 LIST_FOREACH_SAFE(stp, &clp->lc_open, ls_list, nstp) {
5346                         if (LIST_EMPTY(&stp->ls_open) &&
5347                             (stp->ls_noopens > NFSNOOPEN ||
5348                              (nfsrv_openpluslock * 2) >
5349                              nfsrv_v4statelimit))
5350                                 nfsrv_freeopenowner(stp, 0, p);
5351                 }
5352             }
5353         }
5354         NFSUNLOCKSTATE();
5355 }
5356
5357 /*
5358  * This function checks to see if the credentials are the same.
5359  * Returns 1 for not same, 0 otherwise.
5360  */
5361 static int
5362 nfsrv_notsamecredname(struct nfsrv_descript *nd, struct nfsclient *clp)
5363 {
5364
5365         if (nd->nd_flag & ND_GSS) {
5366                 if (!(clp->lc_flags & LCL_GSS))
5367                         return (1);
5368                 if (clp->lc_flags & LCL_NAME) {
5369                         if (nd->nd_princlen != clp->lc_namelen ||
5370                             NFSBCMP(nd->nd_principal, clp->lc_name,
5371                                 clp->lc_namelen))
5372                                 return (1);
5373                         else
5374                                 return (0);
5375                 }
5376                 if (nd->nd_cred->cr_uid == clp->lc_uid)
5377                         return (0);
5378                 else
5379                         return (1);
5380         } else if (clp->lc_flags & LCL_GSS)
5381                 return (1);
5382         /*
5383          * For AUTH_SYS, allow the same uid or root. (This is underspecified
5384          * in RFC3530, which talks about principals, but doesn't say anything
5385          * about uids for AUTH_SYS.)
5386          */
5387         if (nd->nd_cred->cr_uid == clp->lc_uid || nd->nd_cred->cr_uid == 0)
5388                 return (0);
5389         else
5390                 return (1);
5391 }
5392
5393 /*
5394  * Calculate the lease expiry time.
5395  */
5396 static time_t
5397 nfsrv_leaseexpiry(void)
5398 {
5399
5400         if (nfsrv_stablefirst.nsf_eograce > NFSD_MONOSEC)
5401                 return (NFSD_MONOSEC + 2 * (nfsrv_lease + NFSRV_LEASEDELTA));
5402         return (NFSD_MONOSEC + nfsrv_lease + NFSRV_LEASEDELTA);
5403 }
5404
5405 /*
5406  * Delay the delegation timeout as far as ls_delegtimelimit, as required.
5407  */
5408 static void
5409 nfsrv_delaydelegtimeout(struct nfsstate *stp)
5410 {
5411
5412         if ((stp->ls_flags & NFSLCK_DELEGRECALL) == 0)
5413                 return;
5414
5415         if ((stp->ls_delegtime + 15) > NFSD_MONOSEC &&
5416             stp->ls_delegtime < stp->ls_delegtimelimit) {
5417                 stp->ls_delegtime += nfsrv_lease;
5418                 if (stp->ls_delegtime > stp->ls_delegtimelimit)
5419                         stp->ls_delegtime = stp->ls_delegtimelimit;
5420         }
5421 }
5422
5423 /*
5424  * This function checks to see if there is any other state associated
5425  * with the openowner for this Open.
5426  * It returns 1 if there is no other state, 0 otherwise.
5427  */
5428 static int
5429 nfsrv_nootherstate(struct nfsstate *stp)
5430 {
5431         struct nfsstate *tstp;
5432
5433         LIST_FOREACH(tstp, &stp->ls_openowner->ls_open, ls_list) {
5434                 if (tstp != stp || !LIST_EMPTY(&tstp->ls_lock))
5435                         return (0);
5436         }
5437         return (1);
5438 }
5439
5440 /*
5441  * Create a list of lock deltas (changes to local byte range locking
5442  * that can be rolled back using the list) and apply the changes via
5443  * nfsvno_advlock(). Optionally, lock the list. It is expected that either
5444  * the rollback or update function will be called after this.
5445  * It returns an error (and rolls back, as required), if any nfsvno_advlock()
5446  * call fails. If it returns an error, it will unlock the list.
5447  */
5448 static int
5449 nfsrv_locallock(vnode_t vp, struct nfslockfile *lfp, int flags,
5450     uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p)
5451 {
5452         struct nfslock *lop, *nlop;
5453         int error = 0;
5454
5455         /* Loop through the list of locks. */
5456         lop = LIST_FIRST(&lfp->lf_locallock);
5457         while (first < end && lop != NULL) {
5458                 nlop = LIST_NEXT(lop, lo_lckowner);
5459                 if (first >= lop->lo_end) {
5460                         /* not there yet */
5461                         lop = nlop;
5462                 } else if (first < lop->lo_first) {
5463                         /* new one starts before entry in list */
5464                         if (end <= lop->lo_first) {
5465                                 /* no overlap between old and new */
5466                                 error = nfsrv_dolocal(vp, lfp, flags,
5467                                     NFSLCK_UNLOCK, first, end, cfp, p);
5468                                 if (error != 0)
5469                                         break;
5470                                 first = end;
5471                         } else {
5472                                 /* handle fragment overlapped with new one */
5473                                 error = nfsrv_dolocal(vp, lfp, flags,
5474                                     NFSLCK_UNLOCK, first, lop->lo_first, cfp,
5475                                     p);
5476                                 if (error != 0)
5477                                         break;
5478                                 first = lop->lo_first;
5479                         }
5480                 } else {
5481                         /* new one overlaps this entry in list */
5482                         if (end <= lop->lo_end) {
5483                                 /* overlaps all of new one */
5484                                 error = nfsrv_dolocal(vp, lfp, flags,
5485                                     lop->lo_flags, first, end, cfp, p);
5486                                 if (error != 0)
5487                                         break;
5488                                 first = end;
5489                         } else {
5490                                 /* handle fragment overlapped with new one */
5491                                 error = nfsrv_dolocal(vp, lfp, flags,
5492                                     lop->lo_flags, first, lop->lo_end, cfp, p);
5493                                 if (error != 0)
5494                                         break;
5495                                 first = lop->lo_end;
5496                                 lop = nlop;
5497                         }
5498                 }
5499         }
5500         if (first < end && error == 0)
5501                 /* handle fragment past end of list */
5502                 error = nfsrv_dolocal(vp, lfp, flags, NFSLCK_UNLOCK, first,
5503                     end, cfp, p);
5504
5505         NFSEXITCODE(error);
5506         return (error);
5507 }
5508
5509 /*
5510  * Local lock unlock. Unlock all byte ranges that are no longer locked
5511  * by NFSv4. To do this, unlock any subranges of first-->end that
5512  * do not overlap with the byte ranges of any lock in the lfp->lf_lock
5513  * list. This list has all locks for the file held by other
5514  * <clientid, lockowner> tuples. The list is ordered by increasing
5515  * lo_first value, but may have entries that overlap each other, for
5516  * the case of read locks.
5517  */
5518 static void
5519 nfsrv_localunlock(vnode_t vp, struct nfslockfile *lfp, uint64_t init_first,
5520     uint64_t init_end, NFSPROC_T *p)
5521 {
5522         struct nfslock *lop;
5523         uint64_t first, end, prevfirst;
5524
5525         first = init_first;
5526         end = init_end;
5527         while (first < init_end) {
5528                 /* Loop through all nfs locks, adjusting first and end */
5529                 prevfirst = 0;
5530                 LIST_FOREACH(lop, &lfp->lf_lock, lo_lckfile) {
5531                         KASSERT(prevfirst <= lop->lo_first,
5532                             ("nfsv4 locks out of order"));
5533                         KASSERT(lop->lo_first < lop->lo_end,
5534                             ("nfsv4 bogus lock"));
5535                         prevfirst = lop->lo_first;
5536                         if (first >= lop->lo_first &&
5537                             first < lop->lo_end)
5538                                 /*
5539                                  * Overlaps with initial part, so trim
5540                                  * off that initial part by moving first past
5541                                  * it.
5542                                  */
5543                                 first = lop->lo_end;
5544                         else if (end > lop->lo_first &&
5545                             lop->lo_first > first) {
5546                                 /*
5547                                  * This lock defines the end of the
5548                                  * segment to unlock, so set end to the
5549                                  * start of it and break out of the loop.
5550                                  */
5551                                 end = lop->lo_first;
5552                                 break;
5553                         }
5554                         if (first >= end)
5555                                 /*
5556                                  * There is no segment left to do, so
5557                                  * break out of this loop and then exit
5558                                  * the outer while() since first will be set
5559                                  * to end, which must equal init_end here.
5560                                  */
5561                                 break;
5562                 }
5563                 if (first < end) {
5564                         /* Unlock this segment */
5565                         (void) nfsrv_dolocal(vp, lfp, NFSLCK_UNLOCK,
5566                             NFSLCK_READ, first, end, NULL, p);
5567                         nfsrv_locallock_commit(lfp, NFSLCK_UNLOCK,
5568                             first, end);
5569                 }
5570                 /*
5571                  * Now move past this segment and look for any further
5572                  * segment in the range, if there is one.
5573                  */
5574                 first = end;
5575                 end = init_end;
5576         }
5577 }
5578
5579 /*
5580  * Do the local lock operation and update the rollback list, as required.
5581  * Perform the rollback and return the error if nfsvno_advlock() fails.
5582  */
5583 static int
5584 nfsrv_dolocal(vnode_t vp, struct nfslockfile *lfp, int flags, int oldflags,
5585     uint64_t first, uint64_t end, struct nfslockconflict *cfp, NFSPROC_T *p)
5586 {
5587         struct nfsrollback *rlp;
5588         int error = 0, ltype, oldltype;
5589
5590         if (flags & NFSLCK_WRITE)
5591                 ltype = F_WRLCK;
5592         else if (flags & NFSLCK_READ)
5593                 ltype = F_RDLCK;
5594         else
5595                 ltype = F_UNLCK;
5596         if (oldflags & NFSLCK_WRITE)
5597                 oldltype = F_WRLCK;
5598         else if (oldflags & NFSLCK_READ)
5599                 oldltype = F_RDLCK;
5600         else
5601                 oldltype = F_UNLCK;
5602         if (ltype == oldltype || (oldltype == F_WRLCK && ltype == F_RDLCK))
5603                 /* nothing to do */
5604                 goto out;
5605         error = nfsvno_advlock(vp, ltype, first, end, p);
5606         if (error != 0) {
5607                 if (cfp != NULL) {
5608                         cfp->cl_clientid.lval[0] = 0;
5609                         cfp->cl_clientid.lval[1] = 0;
5610                         cfp->cl_first = 0;
5611                         cfp->cl_end = NFS64BITSSET;
5612                         cfp->cl_flags = NFSLCK_WRITE;
5613                         cfp->cl_ownerlen = 5;
5614                         NFSBCOPY("LOCAL", cfp->cl_owner, 5);
5615                 }
5616                 nfsrv_locallock_rollback(vp, lfp, p);
5617         } else if (ltype != F_UNLCK) {
5618                 rlp = malloc(sizeof (struct nfsrollback), M_NFSDROLLBACK,
5619                     M_WAITOK);
5620                 rlp->rlck_first = first;
5621                 rlp->rlck_end = end;
5622                 rlp->rlck_type = oldltype;
5623                 LIST_INSERT_HEAD(&lfp->lf_rollback, rlp, rlck_list);
5624         }
5625
5626 out:
5627         NFSEXITCODE(error);
5628         return (error);
5629 }
5630
5631 /*
5632  * Roll back local lock changes and free up the rollback list.
5633  */
5634 static void
5635 nfsrv_locallock_rollback(vnode_t vp, struct nfslockfile *lfp, NFSPROC_T *p)
5636 {
5637         struct nfsrollback *rlp, *nrlp;
5638
5639         LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp) {
5640                 (void) nfsvno_advlock(vp, rlp->rlck_type, rlp->rlck_first,
5641                     rlp->rlck_end, p);
5642                 free(rlp, M_NFSDROLLBACK);
5643         }
5644         LIST_INIT(&lfp->lf_rollback);
5645 }
5646
5647 /*
5648  * Update local lock list and delete rollback list (ie now committed to the
5649  * local locks). Most of the work is done by the internal function.
5650  */
5651 static void
5652 nfsrv_locallock_commit(struct nfslockfile *lfp, int flags, uint64_t first,
5653     uint64_t end)
5654 {
5655         struct nfsrollback *rlp, *nrlp;
5656         struct nfslock *new_lop, *other_lop;
5657
5658         new_lop = malloc(sizeof (struct nfslock), M_NFSDLOCK, M_WAITOK);
5659         if (flags & (NFSLCK_READ | NFSLCK_WRITE))
5660                 other_lop = malloc(sizeof (struct nfslock), M_NFSDLOCK,
5661                     M_WAITOK);
5662         else
5663                 other_lop = NULL;
5664         new_lop->lo_flags = flags;
5665         new_lop->lo_first = first;
5666         new_lop->lo_end = end;
5667         nfsrv_updatelock(NULL, &new_lop, &other_lop, lfp);
5668         if (new_lop != NULL)
5669                 free(new_lop, M_NFSDLOCK);
5670         if (other_lop != NULL)
5671                 free(other_lop, M_NFSDLOCK);
5672
5673         /* and get rid of the rollback list */
5674         LIST_FOREACH_SAFE(rlp, &lfp->lf_rollback, rlck_list, nrlp)
5675                 free(rlp, M_NFSDROLLBACK);
5676         LIST_INIT(&lfp->lf_rollback);
5677 }
5678
5679 /*
5680  * Lock the struct nfslockfile for local lock updating.
5681  */
5682 static void
5683 nfsrv_locklf(struct nfslockfile *lfp)
5684 {
5685         int gotlock;
5686
5687         /* lf_usecount ensures *lfp won't be free'd */
5688         lfp->lf_usecount++;
5689         do {
5690                 gotlock = nfsv4_lock(&lfp->lf_locallock_lck, 1, NULL,
5691                     NFSSTATEMUTEXPTR, NULL);
5692         } while (gotlock == 0);
5693         lfp->lf_usecount--;
5694 }
5695
5696 /*
5697  * Unlock the struct nfslockfile after local lock updating.
5698  */
5699 static void
5700 nfsrv_unlocklf(struct nfslockfile *lfp)
5701 {
5702
5703         nfsv4_unlock(&lfp->lf_locallock_lck, 0);
5704 }
5705
5706 /*
5707  * Clear out all state for the NFSv4 server.
5708  * Must be called by a thread that can sleep when no nfsds are running.
5709  */
5710 void
5711 nfsrv_throwawayallstate(NFSPROC_T *p)
5712 {
5713         struct nfsclient *clp, *nclp;
5714         struct nfslockfile *lfp, *nlfp;
5715         int i;
5716
5717         /*
5718          * For each client, clean out the state and then free the structure.
5719          */
5720         for (i = 0; i < nfsrv_clienthashsize; i++) {
5721                 LIST_FOREACH_SAFE(clp, &nfsclienthash[i], lc_hash, nclp) {
5722                         nfsrv_cleanclient(clp, p);
5723                         nfsrv_freedeleglist(&clp->lc_deleg);
5724                         nfsrv_freedeleglist(&clp->lc_olddeleg);
5725                         free(clp->lc_stateid, M_NFSDCLIENT);
5726                         free(clp, M_NFSDCLIENT);
5727                 }
5728         }
5729
5730         /*
5731          * Also, free up any remaining lock file structures.
5732          */
5733         for (i = 0; i < nfsrv_lockhashsize; i++) {
5734                 LIST_FOREACH_SAFE(lfp, &nfslockhash[i], lf_hash, nlfp) {
5735                         printf("nfsd unload: fnd a lock file struct\n");
5736                         nfsrv_freenfslockfile(lfp);
5737                 }
5738         }
5739 }
5740
5741 /*
5742  * Check the sequence# for the session and slot provided as an argument.
5743  * Also, renew the lease if the session will return NFS_OK.
5744  */
5745 int
5746 nfsrv_checksequence(struct nfsrv_descript *nd, uint32_t sequenceid,
5747     uint32_t *highest_slotidp, uint32_t *target_highest_slotidp, int cache_this,
5748     uint32_t *sflagsp, NFSPROC_T *p)
5749 {
5750         struct nfsdsession *sep;
5751         struct nfssessionhash *shp;
5752         int error;
5753         SVCXPRT *savxprt;
5754
5755         shp = NFSSESSIONHASH(nd->nd_sessionid);
5756         NFSLOCKSESSION(shp);
5757         sep = nfsrv_findsession(nd->nd_sessionid);
5758         if (sep == NULL) {
5759                 NFSUNLOCKSESSION(shp);
5760                 return (NFSERR_BADSESSION);
5761         }
5762         error = nfsv4_seqsession(sequenceid, nd->nd_slotid, *highest_slotidp,
5763             sep->sess_slots, NULL, NFSV4_SLOTS - 1);
5764         if (error != 0) {
5765                 NFSUNLOCKSESSION(shp);
5766                 return (error);
5767         }
5768         if (cache_this != 0)
5769                 nd->nd_flag |= ND_SAVEREPLY;
5770         /* Renew the lease. */
5771         sep->sess_clp->lc_expiry = nfsrv_leaseexpiry();
5772         nd->nd_clientid.qval = sep->sess_clp->lc_clientid.qval;
5773         nd->nd_flag |= ND_IMPLIEDCLID;
5774
5775         /*
5776          * If this session handles the backchannel, save the nd_xprt for this
5777          * RPC, since this is the one being used.
5778          */
5779         if (sep->sess_cbsess.nfsess_xprt != NULL &&
5780             (sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0) {
5781                 savxprt = sep->sess_cbsess.nfsess_xprt;
5782                 SVC_ACQUIRE(nd->nd_xprt);
5783                 nd->nd_xprt->xp_p2 = savxprt->xp_p2;
5784                 nd->nd_xprt->xp_idletimeout = 0;        /* Disable timeout. */
5785                 sep->sess_cbsess.nfsess_xprt = nd->nd_xprt;
5786                 SVC_RELEASE(savxprt);
5787         }
5788
5789         *sflagsp = 0;
5790         if (sep->sess_clp->lc_req.nr_client == NULL)
5791                 *sflagsp |= NFSV4SEQ_CBPATHDOWN;
5792         NFSUNLOCKSESSION(shp);
5793         if (error == NFSERR_EXPIRED) {
5794                 *sflagsp |= NFSV4SEQ_EXPIREDALLSTATEREVOKED;
5795                 error = 0;
5796         } else if (error == NFSERR_ADMINREVOKED) {
5797                 *sflagsp |= NFSV4SEQ_ADMINSTATEREVOKED;
5798                 error = 0;
5799         }
5800         *highest_slotidp = *target_highest_slotidp = NFSV4_SLOTS - 1;
5801         return (0);
5802 }
5803
5804 /*
5805  * Check/set reclaim complete for this session/clientid.
5806  */
5807 int
5808 nfsrv_checkreclaimcomplete(struct nfsrv_descript *nd)
5809 {
5810         struct nfsdsession *sep;
5811         struct nfssessionhash *shp;
5812         int error = 0;
5813
5814         shp = NFSSESSIONHASH(nd->nd_sessionid);
5815         NFSLOCKSTATE();
5816         NFSLOCKSESSION(shp);
5817         sep = nfsrv_findsession(nd->nd_sessionid);
5818         if (sep == NULL) {
5819                 NFSUNLOCKSESSION(shp);
5820                 NFSUNLOCKSTATE();
5821                 return (NFSERR_BADSESSION);
5822         }
5823
5824         /* Check to see if reclaim complete has already happened. */
5825         if ((sep->sess_clp->lc_flags & LCL_RECLAIMCOMPLETE) != 0)
5826                 error = NFSERR_COMPLETEALREADY;
5827         else
5828                 sep->sess_clp->lc_flags |= LCL_RECLAIMCOMPLETE;
5829         NFSUNLOCKSESSION(shp);
5830         NFSUNLOCKSTATE();
5831         return (error);
5832 }
5833
5834 /*
5835  * Cache the reply in a session slot.
5836  */
5837 void
5838 nfsrv_cache_session(uint8_t *sessionid, uint32_t slotid, int repstat,
5839    struct mbuf **m)
5840 {
5841         struct nfsdsession *sep;
5842         struct nfssessionhash *shp;
5843
5844         shp = NFSSESSIONHASH(sessionid);
5845         NFSLOCKSESSION(shp);
5846         sep = nfsrv_findsession(sessionid);
5847         if (sep == NULL) {
5848                 NFSUNLOCKSESSION(shp);
5849                 printf("nfsrv_cache_session: no session\n");
5850                 m_freem(*m);
5851                 return;
5852         }
5853         nfsv4_seqsess_cacherep(slotid, sep->sess_slots, repstat, m);
5854         NFSUNLOCKSESSION(shp);
5855 }
5856
5857 /*
5858  * Search for a session that matches the sessionid.
5859  */
5860 static struct nfsdsession *
5861 nfsrv_findsession(uint8_t *sessionid)
5862 {
5863         struct nfsdsession *sep;
5864         struct nfssessionhash *shp;
5865
5866         shp = NFSSESSIONHASH(sessionid);
5867         LIST_FOREACH(sep, &shp->list, sess_hash) {
5868                 if (!NFSBCMP(sessionid, sep->sess_sessionid, NFSX_V4SESSIONID))
5869                         break;
5870         }
5871         return (sep);
5872 }
5873
5874 /*
5875  * Destroy a session.
5876  */
5877 int
5878 nfsrv_destroysession(struct nfsrv_descript *nd, uint8_t *sessionid)
5879 {
5880         int error, samesess;
5881
5882         samesess = 0;
5883         if (!NFSBCMP(sessionid, nd->nd_sessionid, NFSX_V4SESSIONID)) {
5884                 samesess = 1;
5885                 if ((nd->nd_flag & ND_LASTOP) == 0)
5886                         return (NFSERR_BADSESSION);
5887         }
5888         error = nfsrv_freesession(NULL, sessionid);
5889         if (error == 0 && samesess != 0)
5890                 nd->nd_flag &= ~ND_HASSEQUENCE;
5891         return (error);
5892 }
5893
5894 /*
5895  * Free up a session structure.
5896  */
5897 static int
5898 nfsrv_freesession(struct nfsdsession *sep, uint8_t *sessionid)
5899 {
5900         struct nfssessionhash *shp;
5901         int i;
5902
5903         if (sep == NULL) {
5904                 shp = NFSSESSIONHASH(sessionid);
5905                 NFSLOCKSESSION(shp);
5906                 sep = nfsrv_findsession(sessionid);
5907         } else {
5908                 shp = NFSSESSIONHASH(sep->sess_sessionid);
5909                 NFSLOCKSESSION(shp);
5910         }
5911         if (sep != NULL) {
5912                 NFSLOCKSTATE();
5913                 sep->sess_refcnt--;
5914                 if (sep->sess_refcnt > 0) {
5915                         NFSUNLOCKSTATE();
5916                         NFSUNLOCKSESSION(shp);
5917                         return (0);
5918                 }
5919                 LIST_REMOVE(sep, sess_hash);
5920                 LIST_REMOVE(sep, sess_list);
5921                 NFSUNLOCKSTATE();
5922         }
5923         NFSUNLOCKSESSION(shp);
5924         if (sep == NULL)
5925                 return (NFSERR_BADSESSION);
5926         for (i = 0; i < NFSV4_SLOTS; i++)
5927                 if (sep->sess_slots[i].nfssl_reply != NULL)
5928                         m_freem(sep->sess_slots[i].nfssl_reply);
5929         if (sep->sess_cbsess.nfsess_xprt != NULL)
5930                 SVC_RELEASE(sep->sess_cbsess.nfsess_xprt);
5931         free(sep, M_NFSDSESSION);
5932         return (0);
5933 }
5934
5935 /*
5936  * Free a stateid.
5937  * RFC5661 says that it should fail when there are associated opens, locks
5938  * or delegations. Since stateids represent opens, I don't see how you can
5939  * free an open stateid (it will be free'd when closed), so this function
5940  * only works for lock stateids (freeing the lock_owner) or delegations.
5941  */
5942 int
5943 nfsrv_freestateid(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
5944     NFSPROC_T *p)
5945 {
5946         struct nfsclient *clp;
5947         struct nfsstate *stp;
5948         int error;
5949
5950         NFSLOCKSTATE();
5951         /*
5952          * Look up the stateid
5953          */
5954         error = nfsrv_getclient((nfsquad_t)((u_quad_t)0), CLOPS_RENEW, &clp,
5955             NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
5956         if (error == 0) {
5957                 /* First, check for a delegation. */
5958                 LIST_FOREACH(stp, &clp->lc_deleg, ls_list) {
5959                         if (!NFSBCMP(stp->ls_stateid.other, stateidp->other,
5960                             NFSX_STATEIDOTHER))
5961                                 break;
5962                 }
5963                 if (stp != NULL) {
5964                         nfsrv_freedeleg(stp);
5965                         NFSUNLOCKSTATE();
5966                         return (error);
5967                 }
5968         }
5969         /* Not a delegation, try for a lock_owner. */
5970         if (error == 0)
5971                 error = nfsrv_getstate(clp, stateidp, 0, &stp);
5972         if (error == 0 && ((stp->ls_flags & (NFSLCK_OPEN | NFSLCK_DELEGREAD |
5973             NFSLCK_DELEGWRITE)) != 0 || (stp->ls_flags & NFSLCK_LOCK) == 0))
5974                 /* Not a lock_owner stateid. */
5975                 error = NFSERR_LOCKSHELD;
5976         if (error == 0 && !LIST_EMPTY(&stp->ls_lock))
5977                 error = NFSERR_LOCKSHELD;
5978         if (error == 0)
5979                 nfsrv_freelockowner(stp, NULL, 0, p);
5980         NFSUNLOCKSTATE();
5981         return (error);
5982 }
5983
5984 /*
5985  * Generate the xdr for an NFSv4.1 CBSequence Operation.
5986  */
5987 static int
5988 nfsv4_setcbsequence(struct nfsrv_descript *nd, struct nfsclient *clp,
5989     int dont_replycache, struct nfsdsession **sepp)
5990 {
5991         struct nfsdsession *sep;
5992         uint32_t *tl, slotseq = 0;
5993         int maxslot, slotpos;
5994         uint8_t sessionid[NFSX_V4SESSIONID];
5995         int error;
5996
5997         error = nfsv4_getcbsession(clp, sepp);
5998         if (error != 0)
5999                 return (error);
6000         sep = *sepp;
6001         (void)nfsv4_sequencelookup(NULL, &sep->sess_cbsess, &slotpos, &maxslot,
6002             &slotseq, sessionid);
6003         KASSERT(maxslot >= 0, ("nfsv4_setcbsequence neg maxslot"));
6004
6005         /* Build the Sequence arguments. */
6006         NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 5 * NFSX_UNSIGNED);
6007         bcopy(sessionid, tl, NFSX_V4SESSIONID);
6008         tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
6009         nd->nd_slotseq = tl;
6010         *tl++ = txdr_unsigned(slotseq);
6011         *tl++ = txdr_unsigned(slotpos);
6012         *tl++ = txdr_unsigned(maxslot);
6013         if (dont_replycache == 0)
6014                 *tl++ = newnfs_true;
6015         else
6016                 *tl++ = newnfs_false;
6017         *tl = 0;                        /* No referring call list, for now. */
6018         nd->nd_flag |= ND_HASSEQUENCE;
6019         return (0);
6020 }
6021
6022 /*
6023  * Get a session for the callback.
6024  */
6025 static int
6026 nfsv4_getcbsession(struct nfsclient *clp, struct nfsdsession **sepp)
6027 {
6028         struct nfsdsession *sep;
6029
6030         NFSLOCKSTATE();
6031         LIST_FOREACH(sep, &clp->lc_session, sess_list) {
6032                 if ((sep->sess_crflags & NFSV4CRSESS_CONNBACKCHAN) != 0)
6033                         break;
6034         }
6035         if (sep == NULL) {
6036                 NFSUNLOCKSTATE();
6037                 return (NFSERR_BADSESSION);
6038         }
6039         sep->sess_refcnt++;
6040         *sepp = sep;
6041         NFSUNLOCKSTATE();
6042         return (0);
6043 }
6044