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

Cache object: 767fbadfb09aaf80140ad9fb877485da


[ 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.