The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsserver/nfs_nfsdstate.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 45cad35c8a4e3cc3e8c8c707025a460e


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.