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_clrpcops.c

Version: -  FREEBSD  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-2  -  FREEBSD-11-1  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-4  -  FREEBSD-10-3  -  FREEBSD-10-2  -  FREEBSD-10-1  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-3  -  FREEBSD-9-2  -  FREEBSD-9-1  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-4  -  FREEBSD-8-3  -  FREEBSD-8-2  -  FREEBSD-8-1  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-4  -  FREEBSD-7-3  -  FREEBSD-7-2  -  FREEBSD-7-1  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-4  -  FREEBSD-6-3  -  FREEBSD-6-2  -  FREEBSD-6-1  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-5  -  FREEBSD-5-4  -  FREEBSD-5-3  -  FREEBSD-5-2  -  FREEBSD-5-1  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  linux-2.6  -  linux-2.4.22  -  MK83  -  MK84  -  PLAN9  -  DFBSD  -  NETBSD  -  NETBSD5  -  NETBSD4  -  NETBSD3  -  NETBSD20  -  OPENBSD  -  xnu-517  -  xnu-792  -  xnu-792.6.70  -  xnu-1228  -  xnu-1456.1.26  -  xnu-1699.24.8  -  xnu-2050.18.24  -  OPENSOLARIS  -  minix-3-1-1 
SearchContext: -  none  -  3  -  10 

    1 /*-
    2  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Rick Macklem at The University of Guelph.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD: stable/12/sys/fs/nfsclient/nfs_clrpcops.c 371046 2021-11-19 05:33:16Z git2svn $");
   38 
   39 /*
   40  * Rpc op calls, generally called from the vnode op calls or through the
   41  * buffer cache, for NFS v2, 3 and 4.
   42  * These do not normally make any changes to vnode arguments or use
   43  * structures that might change between the VFS variants. The returned
   44  * arguments are all at the end, after the NFSPROC_T *p one.
   45  */
   46 
   47 #include "opt_inet6.h"
   48 
   49 #include <fs/nfs/nfsport.h>
   50 #include <sys/sysctl.h>
   51 #include <sys/taskqueue.h>
   52 
   53 SYSCTL_DECL(_vfs_nfs);
   54 
   55 static int      nfsignore_eexist = 0;
   56 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
   57     &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
   58 
   59 static int      nfscl_dssameconn = 0;
   60 SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW,
   61     &nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs");
   62 
   63 /*
   64  * Global variables
   65  */
   66 extern struct nfsstatsv1 nfsstatsv1;
   67 extern int nfs_numnfscbd;
   68 extern struct timeval nfsboottime;
   69 extern u_int32_t newnfs_false, newnfs_true;
   70 extern nfstype nfsv34_type[9];
   71 extern int nfsrv_useacl;
   72 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
   73 extern int nfscl_debuglevel;
   74 extern int nfs_pnfsiothreads;
   75 NFSCLSTATEMUTEX;
   76 int nfstest_outofseq = 0;
   77 int nfscl_assumeposixlocks = 1;
   78 int nfscl_enablecallb = 0;
   79 short nfsv4_cbport = NFSV4_CBPORT;
   80 int nfstest_openallsetattr = 0;
   81 
   82 #define DIRHDSIZ        offsetof(struct dirent, d_name)
   83 
   84 /*
   85  * nfscl_getsameserver() can return one of three values:
   86  * NFSDSP_USETHISSESSION - Use this session for the DS.
   87  * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
   88  *     session.
   89  * NFSDSP_NOTFOUND - No matching server was found.
   90  */
   91 enum nfsclds_state {
   92         NFSDSP_USETHISSESSION = 0,
   93         NFSDSP_SEQTHISSESSION = 1,
   94         NFSDSP_NOTFOUND = 2,
   95 };
   96 
   97 /*
   98  * Do a write RPC on a DS data file, using this structure for the arguments,
   99  * so that this function can be executed by a separate kernel process.
  100  */
  101 struct nfsclwritedsdorpc {
  102         int                     done;
  103         int                     inprog;
  104         struct task             tsk;
  105         struct vnode            *vp;
  106         int                     iomode;
  107         int                     must_commit;
  108         nfsv4stateid_t          *stateidp;
  109         struct nfsclds          *dsp;
  110         uint64_t                off;
  111         int                     len;
  112         struct nfsfh            *fhp;
  113         struct mbuf             *m;
  114         int                     vers;
  115         int                     minorvers;
  116         struct ucred            *cred;
  117         NFSPROC_T               *p;
  118         int                     err;
  119 };
  120 
  121 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
  122     struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
  123 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
  124     nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
  125 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
  126     struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
  127     void *);
  128 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
  129     nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
  130     struct nfsvattr *, struct nfsfh **, int *, int *, void *);
  131 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
  132     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
  133     NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
  134     int *, void *, int *);
  135 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
  136     struct nfscllockowner *, u_int64_t, u_int64_t,
  137     u_int32_t, struct ucred *, NFSPROC_T *, int);
  138 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
  139     struct acl *, nfsv4stateid_t *, void *);
  140 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
  141     uint32_t, uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
  142     struct ucred *, NFSPROC_T *);
  143 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *,
  144     struct sockaddr_in6 *, sa_family_t, int, struct nfsclds **, NFSPROC_T *);
  145 static void nfscl_initsessionslots(struct nfsclsession *);
  146 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
  147     nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
  148     struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *,
  149     NFSPROC_T *);
  150 static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *,
  151     nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
  152     struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *,
  153     struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
  154 static struct mbuf *nfsm_copym(struct mbuf *, int, int);
  155 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
  156     struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int,
  157     struct ucred *, NFSPROC_T *);
  158 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
  159     nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
  160     struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *);
  161 static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
  162     struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
  163     struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
  164 static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
  165     struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
  166     struct ucred *, NFSPROC_T *);
  167 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
  168     struct nfsclds *, struct nfsclds **, uint32_t *);
  169 static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *,
  170     struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
  171     NFSPROC_T *);
  172 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
  173     struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
  174 static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
  175     uint64_t, uint64_t, nfsv4stateid_t *, int, int, int);
  176 static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *,
  177     NFSPROC_T *);
  178 static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *,
  179     int *, struct nfsclflayouthead *);
  180 static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
  181     int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
  182     struct nfscldeleg **, struct ucred *, NFSPROC_T *);
  183 static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *,
  184     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
  185     struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
  186     struct nfsfh **, int *, int *, void *, int *);
  187 static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *,
  188     int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
  189     struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *,
  190     struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *);
  191 static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *,
  192     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
  193     struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
  194     struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *,
  195     int, int, int, int *, struct nfsclflayouthead *, int *);
  196 static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t,
  197     uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *,
  198     struct nfsclflayouthead *, struct ucred *, NFSPROC_T *, void *);
  199 static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
  200     int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
  201     struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
  202 
  203 int nfs_pnfsio(task_fn_t *, void *);
  204 
  205 /*
  206  * nfs null call from vfs.
  207  */
  208 int
  209 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
  210 {
  211         int error;
  212         struct nfsrv_descript nfsd, *nd = &nfsd;
  213         
  214         NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
  215         error = nfscl_request(nd, vp, p, cred, NULL);
  216         if (nd->nd_repstat && !error)
  217                 error = nd->nd_repstat;
  218         mbuf_freem(nd->nd_mrep);
  219         return (error);
  220 }
  221 
  222 /*
  223  * nfs access rpc op.
  224  * For nfs version 3 and 4, use the access rpc to check accessibility. If file
  225  * modes are changed on the server, accesses might still fail later.
  226  */
  227 int
  228 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
  229     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
  230 {
  231         int error;
  232         u_int32_t mode, rmode;
  233 
  234         if (acmode & VREAD)
  235                 mode = NFSACCESS_READ;
  236         else
  237                 mode = 0;
  238         if (vnode_vtype(vp) == VDIR) {
  239                 if (acmode & VWRITE)
  240                         mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
  241                                  NFSACCESS_DELETE);
  242                 if (acmode & VEXEC)
  243                         mode |= NFSACCESS_LOOKUP;
  244         } else {
  245                 if (acmode & VWRITE)
  246                         mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
  247                 if (acmode & VEXEC)
  248                         mode |= NFSACCESS_EXECUTE;
  249         }
  250 
  251         /*
  252          * Now, just call nfsrpc_accessrpc() to do the actual RPC.
  253          */
  254         error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
  255             NULL);
  256 
  257         /*
  258          * The NFS V3 spec does not clarify whether or not
  259          * the returned access bits can be a superset of
  260          * the ones requested, so...
  261          */
  262         if (!error && (rmode & mode) != mode)
  263                 error = EACCES;
  264         return (error);
  265 }
  266 
  267 /*
  268  * The actual rpc, separated out for Darwin.
  269  */
  270 int
  271 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
  272     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
  273     void *stuff)
  274 {
  275         u_int32_t *tl;
  276         u_int32_t supported, rmode;
  277         int error;
  278         struct nfsrv_descript nfsd, *nd = &nfsd;
  279         nfsattrbit_t attrbits;
  280 
  281         *attrflagp = 0;
  282         supported = mode;
  283         NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
  284         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  285         *tl = txdr_unsigned(mode);
  286         if (nd->nd_flag & ND_NFSV4) {
  287                 /*
  288                  * And do a Getattr op.
  289                  */
  290                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  291                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
  292                 NFSGETATTR_ATTRBIT(&attrbits);
  293                 (void) nfsrv_putattrbit(nd, &attrbits);
  294         }
  295         error = nfscl_request(nd, vp, p, cred, stuff);
  296         if (error)
  297                 return (error);
  298         if (nd->nd_flag & ND_NFSV3) {
  299                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
  300                 if (error)
  301                         goto nfsmout;
  302         }
  303         if (!nd->nd_repstat) {
  304                 if (nd->nd_flag & ND_NFSV4) {
  305                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  306                         supported = fxdr_unsigned(u_int32_t, *tl++);
  307                 } else {
  308                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  309                 }
  310                 rmode = fxdr_unsigned(u_int32_t, *tl);
  311                 if (nd->nd_flag & ND_NFSV4)
  312                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
  313 
  314                 /*
  315                  * It's not obvious what should be done about
  316                  * unsupported access modes. For now, be paranoid
  317                  * and clear the unsupported ones.
  318                  */
  319                 rmode &= supported;
  320                 *rmodep = rmode;
  321         } else
  322                 error = nd->nd_repstat;
  323 nfsmout:
  324         mbuf_freem(nd->nd_mrep);
  325         return (error);
  326 }
  327 
  328 /*
  329  * nfs open rpc
  330  */
  331 int
  332 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
  333 {
  334         struct nfsclopen *op;
  335         struct nfscldeleg *dp;
  336         struct nfsfh *nfhp;
  337         struct nfsnode *np = VTONFS(vp);
  338         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
  339         u_int32_t mode, clidrev;
  340         int ret, newone, error, expireret = 0, retrycnt;
  341 
  342         /*
  343          * For NFSv4, Open Ops are only done on Regular Files.
  344          */
  345         if (vnode_vtype(vp) != VREG)
  346                 return (0);
  347         mode = 0;
  348         if (amode & FREAD)
  349                 mode |= NFSV4OPEN_ACCESSREAD;
  350         if (amode & FWRITE)
  351                 mode |= NFSV4OPEN_ACCESSWRITE;
  352         nfhp = np->n_fhp;
  353 
  354         retrycnt = 0;
  355 #ifdef notdef
  356 { char name[100]; int namel;
  357 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
  358 bcopy(NFS4NODENAME(np->n_v4), name, namel);
  359 name[namel] = '\0';
  360 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
  361 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
  362 else printf(" fhl=0\n");
  363 }
  364 #endif
  365         do {
  366             dp = NULL;
  367             error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
  368                 cred, p, NULL, &op, &newone, &ret, 1, true);
  369             if (error) {
  370                 return (error);
  371             }
  372             if (nmp->nm_clp != NULL)
  373                 clidrev = nmp->nm_clp->nfsc_clientidrev;
  374             else
  375                 clidrev = 0;
  376             if (ret == NFSCLOPEN_DOOPEN) {
  377                 if (np->n_v4 != NULL) {
  378                         /*
  379                          * For the first attempt, try and get a layout, if
  380                          * pNFS is enabled for the mount.
  381                          */
  382                         if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
  383                             nfs_numnfscbd == 0 ||
  384                             (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0)
  385                                 error = nfsrpc_openrpc(nmp, vp,
  386                                     np->n_v4->n4_data,
  387                                     np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
  388                                     np->n_fhp->nfh_len, mode, op,
  389                                     NFS4NODENAME(np->n_v4),
  390                                     np->n_v4->n4_namelen,
  391                                     &dp, 0, 0x0, cred, p, 0, 0);
  392                         else
  393                                 error = nfsrpc_getopenlayout(nmp, vp,
  394                                     np->n_v4->n4_data,
  395                                     np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
  396                                     np->n_fhp->nfh_len, mode, op,
  397                                     NFS4NODENAME(np->n_v4),
  398                                     np->n_v4->n4_namelen, &dp, cred, p);
  399                         if (dp != NULL) {
  400 #ifdef APPLE
  401                                 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
  402 #else
  403                                 NFSLOCKNODE(np);
  404                                 np->n_flag &= ~NDELEGMOD;
  405                                 /*
  406                                  * Invalidate the attribute cache, so that
  407                                  * attributes that pre-date the issue of a
  408                                  * delegation are not cached, since the
  409                                  * cached attributes will remain valid while
  410                                  * the delegation is held.
  411                                  */
  412                                 NFSINVALATTRCACHE(np);
  413                                 NFSUNLOCKNODE(np);
  414 #endif
  415                                 (void) nfscl_deleg(nmp->nm_mountp,
  416                                     op->nfso_own->nfsow_clp,
  417                                     nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
  418                         }
  419                 } else {
  420                         error = EIO;
  421                 }
  422                 newnfs_copyincred(cred, &op->nfso_cred);
  423             } else if (ret == NFSCLOPEN_SETCRED)
  424                 /*
  425                  * This is a new local open on a delegation. It needs
  426                  * to have credentials so that an open can be done
  427                  * against the server during recovery.
  428                  */
  429                 newnfs_copyincred(cred, &op->nfso_cred);
  430 
  431             /*
  432              * nfso_opencnt is the count of how many VOP_OPEN()s have
  433              * been done on this Open successfully and a VOP_CLOSE()
  434              * is expected for each of these.
  435              * If error is non-zero, don't increment it, since the Open
  436              * hasn't succeeded yet.
  437              */
  438             if (!error)
  439                 op->nfso_opencnt++;
  440             nfscl_openrelease(nmp, op, error, newone);
  441             if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
  442                 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
  443                 error == NFSERR_BADSESSION) {
  444                 (void) nfs_catnap(PZERO, error, "nfs_open");
  445             } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
  446                 && clidrev != 0) {
  447                 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
  448                 retrycnt++;
  449             }
  450         } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
  451             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
  452             error == NFSERR_BADSESSION ||
  453             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
  454              expireret == 0 && clidrev != 0 && retrycnt < 4));
  455         if (error && retrycnt >= 4)
  456                 error = EIO;
  457         return (error);
  458 }
  459 
  460 /*
  461  * the actual open rpc
  462  */
  463 int
  464 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
  465     u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
  466     u_int8_t *name, int namelen, struct nfscldeleg **dpp,
  467     int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
  468     int syscred, int recursed)
  469 {
  470         u_int32_t *tl;
  471         struct nfsrv_descript nfsd, *nd = &nfsd;
  472         struct nfscldeleg *dp, *ndp = NULL;
  473         struct nfsvattr nfsva;
  474         u_int32_t rflags, deleg;
  475         nfsattrbit_t attrbits;
  476         int error, ret, acesize, limitby;
  477         struct nfsclsession *tsep;
  478 
  479         dp = *dpp;
  480         *dpp = NULL;
  481         nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0);
  482         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
  483         *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
  484         *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
  485         *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
  486         tsep = nfsmnt_mdssession(nmp);
  487         *tl++ = tsep->nfsess_clientid.lval[0];
  488         *tl = tsep->nfsess_clientid.lval[1];
  489         (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
  490         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  491         *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
  492         if (reclaim) {
  493                 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
  494                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  495                 *tl = txdr_unsigned(delegtype);
  496         } else {
  497                 if (dp != NULL) {
  498                         *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
  499                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
  500                         if (NFSHASNFSV4N(nmp))
  501                                 *tl++ = 0;
  502                         else
  503                                 *tl++ = dp->nfsdl_stateid.seqid;
  504                         *tl++ = dp->nfsdl_stateid.other[0];
  505                         *tl++ = dp->nfsdl_stateid.other[1];
  506                         *tl = dp->nfsdl_stateid.other[2];
  507                 } else {
  508                         *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
  509                 }
  510                 (void) nfsm_strtom(nd, name, namelen);
  511         }
  512         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  513         *tl = txdr_unsigned(NFSV4OP_GETATTR);
  514         NFSZERO_ATTRBIT(&attrbits);
  515         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
  516         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
  517         (void) nfsrv_putattrbit(nd, &attrbits);
  518         if (syscred)
  519                 nd->nd_flag |= ND_USEGSSNAME;
  520         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
  521             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
  522         if (error)
  523                 return (error);
  524         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
  525         if (!nd->nd_repstat) {
  526                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
  527                     6 * NFSX_UNSIGNED);
  528                 op->nfso_stateid.seqid = *tl++;
  529                 op->nfso_stateid.other[0] = *tl++;
  530                 op->nfso_stateid.other[1] = *tl++;
  531                 op->nfso_stateid.other[2] = *tl;
  532                 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
  533                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
  534                 if (error)
  535                         goto nfsmout;
  536                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  537                 deleg = fxdr_unsigned(u_int32_t, *tl);
  538                 if (deleg == NFSV4OPEN_DELEGATEREAD ||
  539                     deleg == NFSV4OPEN_DELEGATEWRITE) {
  540                         if (!(op->nfso_own->nfsow_clp->nfsc_flags &
  541                               NFSCLFLAGS_FIRSTDELEG))
  542                                 op->nfso_own->nfsow_clp->nfsc_flags |=
  543                                   (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
  544                         ndp = malloc(
  545                             sizeof (struct nfscldeleg) + newfhlen,
  546                             M_NFSCLDELEG, M_WAITOK);
  547                         LIST_INIT(&ndp->nfsdl_owner);
  548                         LIST_INIT(&ndp->nfsdl_lock);
  549                         ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
  550                         ndp->nfsdl_fhlen = newfhlen;
  551                         NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
  552                         newnfs_copyincred(cred, &ndp->nfsdl_cred);
  553                         nfscl_lockinit(&ndp->nfsdl_rwlock);
  554                         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
  555                             NFSX_UNSIGNED);
  556                         ndp->nfsdl_stateid.seqid = *tl++;
  557                         ndp->nfsdl_stateid.other[0] = *tl++;
  558                         ndp->nfsdl_stateid.other[1] = *tl++;
  559                         ndp->nfsdl_stateid.other[2] = *tl++;
  560                         ret = fxdr_unsigned(int, *tl);
  561                         if (deleg == NFSV4OPEN_DELEGATEWRITE) {
  562                                 ndp->nfsdl_flags = NFSCLDL_WRITE;
  563                                 /*
  564                                  * Indicates how much the file can grow.
  565                                  */
  566                                 NFSM_DISSECT(tl, u_int32_t *,
  567                                     3 * NFSX_UNSIGNED);
  568                                 limitby = fxdr_unsigned(int, *tl++);
  569                                 switch (limitby) {
  570                                 case NFSV4OPEN_LIMITSIZE:
  571                                         ndp->nfsdl_sizelimit = fxdr_hyper(tl);
  572                                         break;
  573                                 case NFSV4OPEN_LIMITBLOCKS:
  574                                         ndp->nfsdl_sizelimit =
  575                                             fxdr_unsigned(u_int64_t, *tl++);
  576                                         ndp->nfsdl_sizelimit *=
  577                                             fxdr_unsigned(u_int64_t, *tl);
  578                                         break;
  579                                 default:
  580                                         error = NFSERR_BADXDR;
  581                                         goto nfsmout;
  582                                 }
  583                         } else {
  584                                 ndp->nfsdl_flags = NFSCLDL_READ;
  585                         }
  586                         if (ret)
  587                                 ndp->nfsdl_flags |= NFSCLDL_RECALL;
  588                         error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
  589                             &acesize, p);
  590                         if (error)
  591                                 goto nfsmout;
  592                 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
  593                         error = NFSERR_BADXDR;
  594                         goto nfsmout;
  595                 }
  596                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  597                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
  598                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
  599                     NULL, NULL, NULL, p, cred);
  600                 if (error)
  601                         goto nfsmout;
  602                 if (ndp != NULL) {
  603                         ndp->nfsdl_change = nfsva.na_filerev;
  604                         ndp->nfsdl_modtime = nfsva.na_mtime;
  605                         ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
  606                 }
  607                 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
  608                     do {
  609                         ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
  610                             cred, p);
  611                         if (ret == NFSERR_DELAY)
  612                             (void) nfs_catnap(PZERO, ret, "nfs_open");
  613                     } while (ret == NFSERR_DELAY);
  614                     error = ret;
  615                 }
  616                 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
  617                     nfscl_assumeposixlocks)
  618                     op->nfso_posixlock = 1;
  619                 else
  620                     op->nfso_posixlock = 0;
  621 
  622                 /*
  623                  * If the server is handing out delegations, but we didn't
  624                  * get one because an OpenConfirm was required, try the
  625                  * Open again, to get a delegation. This is a harmless no-op,
  626                  * from a server's point of view.
  627                  */
  628                 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
  629                     (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
  630                     && !error && dp == NULL && ndp == NULL && !recursed) {
  631                     do {
  632                         ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
  633                             newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
  634                             cred, p, syscred, 1);
  635                         if (ret == NFSERR_DELAY)
  636                             (void) nfs_catnap(PZERO, ret, "nfs_open2");
  637                     } while (ret == NFSERR_DELAY);
  638                     if (ret) {
  639                         if (ndp != NULL) {
  640                                 free(ndp, M_NFSCLDELEG);
  641                                 ndp = NULL;
  642                         }
  643                         if (ret == NFSERR_STALECLIENTID ||
  644                             ret == NFSERR_STALEDONTRECOVER ||
  645                             ret == NFSERR_BADSESSION)
  646                                 error = ret;
  647                     }
  648                 }
  649         }
  650         if (nd->nd_repstat != 0 && error == 0)
  651                 error = nd->nd_repstat;
  652         if (error == NFSERR_STALECLIENTID)
  653                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
  654 nfsmout:
  655         if (!error)
  656                 *dpp = ndp;
  657         else if (ndp != NULL)
  658                 free(ndp, M_NFSCLDELEG);
  659         mbuf_freem(nd->nd_mrep);
  660         return (error);
  661 }
  662 
  663 /*
  664  * open downgrade rpc
  665  */
  666 int
  667 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
  668     struct ucred *cred, NFSPROC_T *p)
  669 {
  670         u_int32_t *tl;
  671         struct nfsrv_descript nfsd, *nd = &nfsd;
  672         int error;
  673 
  674         NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
  675         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
  676         if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp))))
  677                 *tl++ = 0;
  678         else
  679                 *tl++ = op->nfso_stateid.seqid;
  680         *tl++ = op->nfso_stateid.other[0];
  681         *tl++ = op->nfso_stateid.other[1];
  682         *tl++ = op->nfso_stateid.other[2];
  683         *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
  684         *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
  685         *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
  686         error = nfscl_request(nd, vp, p, cred, NULL);
  687         if (error)
  688                 return (error);
  689         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
  690         if (!nd->nd_repstat) {
  691                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
  692                 op->nfso_stateid.seqid = *tl++;
  693                 op->nfso_stateid.other[0] = *tl++;
  694                 op->nfso_stateid.other[1] = *tl++;
  695                 op->nfso_stateid.other[2] = *tl;
  696         }
  697         if (nd->nd_repstat && error == 0)
  698                 error = nd->nd_repstat;
  699         if (error == NFSERR_STALESTATEID)
  700                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
  701 nfsmout:
  702         mbuf_freem(nd->nd_mrep);
  703         return (error);
  704 }
  705 
  706 /*
  707  * V4 Close operation.
  708  */
  709 int
  710 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
  711 {
  712         struct nfsclclient *clp;
  713         int error;
  714 
  715         if (vnode_vtype(vp) != VREG)
  716                 return (0);
  717         if (doclose)
  718                 error = nfscl_doclose(vp, &clp, p);
  719         else {
  720                 error = nfscl_getclose(vp, &clp);
  721                 if (error == 0)
  722                         nfscl_clientrelease(clp);
  723         }
  724         return (error);
  725 }
  726 
  727 /*
  728  * Close the open.
  729  */
  730 int
  731 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p,
  732     bool loop_on_delayed, bool freeop)
  733 {
  734         struct nfsrv_descript nfsd, *nd = &nfsd;
  735         struct nfscllockowner *lp, *nlp;
  736         struct nfscllock *lop, *nlop;
  737         struct ucred *tcred;
  738         u_int64_t off = 0, len = 0;
  739         u_int32_t type = NFSV4LOCKT_READ;
  740         int error, do_unlock, trycnt;
  741 
  742         tcred = newnfs_getcred();
  743         newnfs_copycred(&op->nfso_cred, tcred);
  744         /*
  745          * (Theoretically this could be done in the same
  746          *  compound as the close, but having multiple
  747          *  sequenced Ops in the same compound might be
  748          *  too scary for some servers.)
  749          */
  750         if (op->nfso_posixlock) {
  751                 off = 0;
  752                 len = NFS64BITSSET;
  753                 type = NFSV4LOCKT_READ;
  754         }
  755 
  756         /*
  757          * Since this function is only called from VOP_INACTIVE(), no
  758          * other thread will be manipulating this Open. As such, the
  759          * lock lists are not being changed by other threads, so it should
  760          * be safe to do this without locking.
  761          */
  762         LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
  763                 do_unlock = 1;
  764                 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
  765                         if (op->nfso_posixlock == 0) {
  766                                 off = lop->nfslo_first;
  767                                 len = lop->nfslo_end - lop->nfslo_first;
  768                                 if (lop->nfslo_type == F_WRLCK)
  769                                         type = NFSV4LOCKT_WRITE;
  770                                 else
  771                                         type = NFSV4LOCKT_READ;
  772                         }
  773                         if (do_unlock) {
  774                                 trycnt = 0;
  775                                 do {
  776                                         error = nfsrpc_locku(nd, nmp, lp, off,
  777                                             len, type, tcred, p, 0);
  778                                         if ((nd->nd_repstat == NFSERR_GRACE ||
  779                                             nd->nd_repstat == NFSERR_DELAY) &&
  780                                             error == 0)
  781                                                 (void) nfs_catnap(PZERO,
  782                                                     (int)nd->nd_repstat,
  783                                                     "nfs_close");
  784                                 } while ((nd->nd_repstat == NFSERR_GRACE ||
  785                                     nd->nd_repstat == NFSERR_DELAY) &&
  786                                     error == 0 && trycnt++ < 5);
  787                                 if (op->nfso_posixlock)
  788                                         do_unlock = 0;
  789                         }
  790                         nfscl_freelock(lop, 0);
  791                 }
  792                 /*
  793                  * Do a ReleaseLockOwner.
  794                  * The lock owner name nfsl_owner may be used by other opens for
  795                  * other files but the lock_owner4 name that nfsrpc_rellockown()
  796                  * puts on the wire has the file handle for this file appended
  797                  * to it, so it can be done now.
  798                  */
  799                 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
  800                     lp->nfsl_open->nfso_fhlen, tcred, p);
  801         }
  802 
  803         /*
  804          * There could be other Opens for different files on the same
  805          * OpenOwner, so locking is required.
  806          */
  807         NFSLOCKCLSTATE();
  808         nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
  809         NFSUNLOCKCLSTATE();
  810         do {
  811                 error = nfscl_tryclose(op, tcred, nmp, p, loop_on_delayed);
  812                 if (error == NFSERR_GRACE)
  813                         (void) nfs_catnap(PZERO, error, "nfs_close");
  814         } while (error == NFSERR_GRACE);
  815         NFSLOCKCLSTATE();
  816         nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
  817 
  818         LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
  819                 nfscl_freelockowner(lp, 0);
  820         if (freeop && error != NFSERR_DELAY)
  821                 nfscl_freeopen(op, 0, true);
  822         NFSUNLOCKCLSTATE();
  823         NFSFREECRED(tcred);
  824         return (error);
  825 }
  826 
  827 /*
  828  * The actual Close RPC.
  829  */
  830 int
  831 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
  832     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
  833     int syscred)
  834 {
  835         u_int32_t *tl;
  836         int error;
  837 
  838         nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
  839             op->nfso_fhlen, NULL, NULL, 0, 0);
  840         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
  841         if (NFSHASNFSV4N(nmp)) {
  842                 *tl++ = 0;
  843                 *tl++ = 0;
  844         } else {
  845                 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
  846                 *tl++ = op->nfso_stateid.seqid;
  847         }
  848         *tl++ = op->nfso_stateid.other[0];
  849         *tl++ = op->nfso_stateid.other[1];
  850         *tl = op->nfso_stateid.other[2];
  851         if (syscred)
  852                 nd->nd_flag |= ND_USEGSSNAME;
  853         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
  854             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
  855         if (error)
  856                 return (error);
  857         if (!NFSHASNFSV4N(nmp))
  858                 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
  859         if (nd->nd_repstat == 0)
  860                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
  861         error = nd->nd_repstat;
  862         if (!NFSHASNFSV4N(nmp) && error == NFSERR_STALESTATEID)
  863                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
  864 nfsmout:
  865         mbuf_freem(nd->nd_mrep);
  866         return (error);
  867 }
  868 
  869 /*
  870  * V4 Open Confirm RPC.
  871  */
  872 int
  873 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
  874     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
  875 {
  876         u_int32_t *tl;
  877         struct nfsrv_descript nfsd, *nd = &nfsd;
  878         struct nfsmount *nmp;
  879         int error;
  880 
  881         nmp = VFSTONFS(vnode_mount(vp));
  882         if (NFSHASNFSV4N(nmp))
  883                 return (0);             /* No confirmation for NFSv4.1. */
  884         nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL,
  885             0, 0);
  886         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
  887         *tl++ = op->nfso_stateid.seqid;
  888         *tl++ = op->nfso_stateid.other[0];
  889         *tl++ = op->nfso_stateid.other[1];
  890         *tl++ = op->nfso_stateid.other[2];
  891         *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
  892         error = nfscl_request(nd, vp, p, cred, NULL);
  893         if (error)
  894                 return (error);
  895         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
  896         if (!nd->nd_repstat) {
  897                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
  898                 op->nfso_stateid.seqid = *tl++;
  899                 op->nfso_stateid.other[0] = *tl++;
  900                 op->nfso_stateid.other[1] = *tl++;
  901                 op->nfso_stateid.other[2] = *tl;
  902         }
  903         error = nd->nd_repstat;
  904         if (error == NFSERR_STALESTATEID)
  905                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
  906 nfsmout:
  907         mbuf_freem(nd->nd_mrep);
  908         return (error);
  909 }
  910 
  911 /*
  912  * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
  913  * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
  914  */
  915 int
  916 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
  917     struct ucred *cred, NFSPROC_T *p)
  918 {
  919         u_int32_t *tl;
  920         struct nfsrv_descript nfsd;
  921         struct nfsrv_descript *nd = &nfsd;
  922         nfsattrbit_t attrbits;
  923         u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
  924         u_short port;
  925         int error, isinet6 = 0, callblen;
  926         nfsquad_t confirm;
  927         u_int32_t lease;
  928         static u_int32_t rev = 0;
  929         struct nfsclds *dsp;
  930         struct in6_addr a6;
  931         struct nfsclsession *tsep;
  932         struct rpc_reconupcall recon;
  933         struct nfscl_reconarg *rcp;
  934 
  935         if (nfsboottime.tv_sec == 0)
  936                 NFSSETBOOTTIME(nfsboottime);
  937         clp->nfsc_rev = rev++;
  938         if (NFSHASNFSV4N(nmp)) {
  939                 /*
  940                  * Either there was no previous session or the
  941                  * previous session has failed, so...
  942                  * do an ExchangeID followed by the CreateSession.
  943                  */
  944                 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq,
  945                     NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p);
  946                 NFSCL_DEBUG(1, "aft exch=%d\n", error);
  947                 if (error == 0)
  948                         error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
  949                             &nmp->nm_sockreq,
  950                             dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
  951                 if (error == 0) {
  952                         /*
  953                          * If the session supports a backchannel, set up
  954                          * the BindConnectionToSession call in the krpc
  955                          * so that it is done on a reconnection.
  956                          */
  957                         if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0) {
  958                                 rcp = mem_alloc(sizeof(*rcp));
  959                                 rcp->minorvers = nmp->nm_minorvers;
  960                                 memcpy(rcp->sessionid,
  961                                     dsp->nfsclds_sess.nfsess_sessionid,
  962                                     NFSX_V4SESSIONID);
  963                                 recon.call = nfsrpc_bindconnsess;
  964                                 recon.arg = rcp;
  965                                 CLNT_CONTROL(nmp->nm_client, CLSET_RECONUPCALL,
  966                                     &recon);
  967                         }
  968 
  969                         NFSLOCKMNT(nmp);
  970                         /*
  971                          * The old sessions cannot be safely free'd
  972                          * here, since they may still be used by
  973                          * in-progress RPCs.
  974                          */
  975                         tsep = NULL;
  976                         if (TAILQ_FIRST(&nmp->nm_sess) != NULL)
  977                                 tsep = NFSMNT_MDSSESSION(nmp);
  978                         TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
  979                             nfsclds_list);
  980                         /*
  981                          * Wake up RPCs waiting for a slot on the
  982                          * old session. These will then fail with
  983                          * NFSERR_BADSESSION and be retried with the
  984                          * new session by nfsv4_setsequence().
  985                          * Also wakeup() processes waiting for the
  986                          * new session.
  987                          */
  988                         if (tsep != NULL)
  989                                 wakeup(&tsep->nfsess_slots);
  990                         wakeup(&nmp->nm_sess);
  991                         NFSUNLOCKMNT(nmp);
  992                 } else
  993                         nfscl_freenfsclds(dsp);
  994                 NFSCL_DEBUG(1, "aft createsess=%d\n", error);
  995                 if (error == 0 && reclaim == 0) {
  996                         error = nfsrpc_reclaimcomplete(nmp, cred, p);
  997                         NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
  998                         if (error == NFSERR_COMPLETEALREADY ||
  999                             error == NFSERR_NOTSUPP)
 1000                                 /* Ignore this error. */
 1001                                 error = 0;
 1002                 }
 1003                 return (error);
 1004         }
 1005 
 1006         /*
 1007          * Allocate a single session structure for NFSv4.0, because some of
 1008          * the fields are used by NFSv4.0 although it doesn't do a session.
 1009          */
 1010         dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
 1011         mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
 1012         mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
 1013         NFSLOCKMNT(nmp);
 1014         TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
 1015         tsep = NFSMNT_MDSSESSION(nmp);
 1016         NFSUNLOCKMNT(nmp);
 1017 
 1018         nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL, 0, 0);
 1019         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1020         *tl++ = txdr_unsigned(nfsboottime.tv_sec);
 1021         *tl = txdr_unsigned(clp->nfsc_rev);
 1022         (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
 1023 
 1024         /*
 1025          * set up the callback address
 1026          */
 1027         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1028         *tl = txdr_unsigned(NFS_CALLBCKPROG);
 1029         callblen = strlen(nfsv4_callbackaddr);
 1030         if (callblen == 0)
 1031                 cp = nfscl_getmyip(nmp, &a6, &isinet6);
 1032         if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
 1033             (callblen > 0 || cp != NULL)) {
 1034                 port = htons(nfsv4_cbport);
 1035                 cp2 = (u_int8_t *)&port;
 1036 #ifdef INET6
 1037                 if ((callblen > 0 &&
 1038                      strchr(nfsv4_callbackaddr, ':')) || isinet6) {
 1039                         char ip6buf[INET6_ADDRSTRLEN], *ip6add;
 1040 
 1041                         (void) nfsm_strtom(nd, "tcp6", 4);
 1042                         if (callblen == 0) {
 1043                                 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
 1044                                 ip6add = ip6buf;
 1045                         } else {
 1046                                 ip6add = nfsv4_callbackaddr;
 1047                         }
 1048                         snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
 1049                             ip6add, cp2[0], cp2[1]);
 1050                 } else
 1051 #endif
 1052                 {
 1053                         (void) nfsm_strtom(nd, "tcp", 3);
 1054                         if (callblen == 0)
 1055                                 snprintf(addr, INET6_ADDRSTRLEN + 9,
 1056                                     "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
 1057                                     cp[2], cp[3], cp2[0], cp2[1]);
 1058                         else
 1059                                 snprintf(addr, INET6_ADDRSTRLEN + 9,
 1060                                     "%s.%d.%d", nfsv4_callbackaddr,
 1061                                     cp2[0], cp2[1]);
 1062                 }
 1063                 (void) nfsm_strtom(nd, addr, strlen(addr));
 1064         } else {
 1065                 (void) nfsm_strtom(nd, "tcp", 3);
 1066                 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
 1067         }
 1068         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1069         *tl = txdr_unsigned(clp->nfsc_cbident);
 1070         nd->nd_flag |= ND_USEGSSNAME;
 1071         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 1072                 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 1073         if (error)
 1074                 return (error);
 1075         if (nd->nd_repstat == 0) {
 1076             NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1077             tsep->nfsess_clientid.lval[0] = *tl++;
 1078             tsep->nfsess_clientid.lval[1] = *tl++;
 1079             confirm.lval[0] = *tl++;
 1080             confirm.lval[1] = *tl;
 1081             mbuf_freem(nd->nd_mrep);
 1082             nd->nd_mrep = NULL;
 1083 
 1084             /*
 1085              * and confirm it.
 1086              */
 1087             nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
 1088                 NULL, 0, 0);
 1089             NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1090             *tl++ = tsep->nfsess_clientid.lval[0];
 1091             *tl++ = tsep->nfsess_clientid.lval[1];
 1092             *tl++ = confirm.lval[0];
 1093             *tl = confirm.lval[1];
 1094             nd->nd_flag |= ND_USEGSSNAME;
 1095             error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
 1096                 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 1097             if (error)
 1098                 return (error);
 1099             mbuf_freem(nd->nd_mrep);
 1100             nd->nd_mrep = NULL;
 1101             if (nd->nd_repstat == 0) {
 1102                 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
 1103                     nmp->nm_fhsize, NULL, NULL, 0, 0);
 1104                 NFSZERO_ATTRBIT(&attrbits);
 1105                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
 1106                 (void) nfsrv_putattrbit(nd, &attrbits);
 1107                 nd->nd_flag |= ND_USEGSSNAME;
 1108                 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
 1109                     cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 1110                 if (error)
 1111                     return (error);
 1112                 if (nd->nd_repstat == 0) {
 1113                     error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
 1114                         NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
 1115                     if (error)
 1116                         goto nfsmout;
 1117                     clp->nfsc_renew = NFSCL_RENEW(lease);
 1118                     clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
 1119                     clp->nfsc_clientidrev++;
 1120                     if (clp->nfsc_clientidrev == 0)
 1121                         clp->nfsc_clientidrev++;
 1122                 }
 1123             }
 1124         }
 1125         error = nd->nd_repstat;
 1126 nfsmout:
 1127         mbuf_freem(nd->nd_mrep);
 1128         return (error);
 1129 }
 1130 
 1131 /*
 1132  * nfs getattr call.
 1133  */
 1134 int
 1135 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
 1136     struct nfsvattr *nap, void *stuff)
 1137 {
 1138         struct nfsrv_descript nfsd, *nd = &nfsd;
 1139         int error;
 1140         nfsattrbit_t attrbits;
 1141         
 1142         NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
 1143         if (nd->nd_flag & ND_NFSV4) {
 1144                 NFSGETATTR_ATTRBIT(&attrbits);
 1145                 (void) nfsrv_putattrbit(nd, &attrbits);
 1146         }
 1147         error = nfscl_request(nd, vp, p, cred, stuff);
 1148         if (error)
 1149                 return (error);
 1150         if (!nd->nd_repstat)
 1151                 error = nfsm_loadattr(nd, nap);
 1152         else
 1153                 error = nd->nd_repstat;
 1154         mbuf_freem(nd->nd_mrep);
 1155         return (error);
 1156 }
 1157 
 1158 /*
 1159  * nfs getattr call with non-vnode arguments.
 1160  */
 1161 int
 1162 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
 1163     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
 1164     uint32_t *leasep)
 1165 {
 1166         struct nfsrv_descript nfsd, *nd = &nfsd;
 1167         int error, vers = NFS_VER2;
 1168         nfsattrbit_t attrbits;
 1169         
 1170         nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0);
 1171         if (nd->nd_flag & ND_NFSV4) {
 1172                 vers = NFS_VER4;
 1173                 NFSGETATTR_ATTRBIT(&attrbits);
 1174                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
 1175                 (void) nfsrv_putattrbit(nd, &attrbits);
 1176         } else if (nd->nd_flag & ND_NFSV3) {
 1177                 vers = NFS_VER3;
 1178         }
 1179         if (syscred)
 1180                 nd->nd_flag |= ND_USEGSSNAME;
 1181         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 1182             NFS_PROG, vers, NULL, 1, xidp, NULL);
 1183         if (error)
 1184                 return (error);
 1185         if (nd->nd_repstat == 0) {
 1186                 if ((nd->nd_flag & ND_NFSV4) != 0)
 1187                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
 1188                             NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
 1189                             NULL, NULL);
 1190                 else
 1191                         error = nfsm_loadattr(nd, nap);
 1192         } else
 1193                 error = nd->nd_repstat;
 1194         mbuf_freem(nd->nd_mrep);
 1195         return (error);
 1196 }
 1197 
 1198 /*
 1199  * Do an nfs setattr operation.
 1200  */
 1201 int
 1202 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
 1203     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
 1204     void *stuff)
 1205 {
 1206         int error, expireret = 0, openerr, retrycnt;
 1207         u_int32_t clidrev = 0, mode;
 1208         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1209         struct nfsfh *nfhp;
 1210         nfsv4stateid_t stateid;
 1211         void *lckp;
 1212 
 1213         if (nmp->nm_clp != NULL)
 1214                 clidrev = nmp->nm_clp->nfsc_clientidrev;
 1215         if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
 1216                 mode = NFSV4OPEN_ACCESSWRITE;
 1217         else
 1218                 mode = NFSV4OPEN_ACCESSREAD;
 1219         retrycnt = 0;
 1220         do {
 1221                 lckp = NULL;
 1222                 openerr = 1;
 1223                 if (NFSHASNFSV4(nmp)) {
 1224                         nfhp = VTONFS(vp)->n_fhp;
 1225                         error = nfscl_getstateid(vp, nfhp->nfh_fh,
 1226                             nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
 1227                         if (error && vnode_vtype(vp) == VREG &&
 1228                             (mode == NFSV4OPEN_ACCESSWRITE ||
 1229                              nfstest_openallsetattr)) {
 1230                                 /*
 1231                                  * No Open stateid, so try and open the file
 1232                                  * now.
 1233                                  */
 1234                                 if (mode == NFSV4OPEN_ACCESSWRITE)
 1235                                         openerr = nfsrpc_open(vp, FWRITE, cred,
 1236                                             p);
 1237                                 else
 1238                                         openerr = nfsrpc_open(vp, FREAD, cred,
 1239                                             p);
 1240                                 if (!openerr)
 1241                                         (void) nfscl_getstateid(vp,
 1242                                             nfhp->nfh_fh, nfhp->nfh_len,
 1243                                             mode, 0, cred, p, &stateid, &lckp);
 1244                         }
 1245                 }
 1246                 if (vap != NULL)
 1247                         error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
 1248                             rnap, attrflagp, stuff);
 1249                 else
 1250                         error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
 1251                             stuff);
 1252                 if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) {
 1253                         NFSLOCKMNT(nmp);
 1254                         nmp->nm_state |= NFSSTA_OPENMODE;
 1255                         NFSUNLOCKMNT(nmp);
 1256                 }
 1257                 if (error == NFSERR_STALESTATEID)
 1258                         nfscl_initiate_recovery(nmp->nm_clp);
 1259                 if (lckp != NULL)
 1260                         nfscl_lockderef(lckp);
 1261                 if (!openerr)
 1262                         (void) nfsrpc_close(vp, 0, p);
 1263                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1264                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1265                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
 1266                         (void) nfs_catnap(PZERO, error, "nfs_setattr");
 1267                 } else if ((error == NFSERR_EXPIRED ||
 1268                     error == NFSERR_BADSTATEID) && clidrev != 0) {
 1269                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 1270                 }
 1271                 retrycnt++;
 1272         } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1273             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1274             error == NFSERR_BADSESSION ||
 1275             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
 1276             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 1277              expireret == 0 && clidrev != 0 && retrycnt < 4) ||
 1278             (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD &&
 1279              retrycnt < 4));
 1280         if (error && retrycnt >= 4)
 1281                 error = EIO;
 1282         return (error);
 1283 }
 1284 
 1285 static int
 1286 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
 1287     nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
 1288     struct nfsvattr *rnap, int *attrflagp, void *stuff)
 1289 {
 1290         u_int32_t *tl;
 1291         struct nfsrv_descript nfsd, *nd = &nfsd;
 1292         int error;
 1293         nfsattrbit_t attrbits;
 1294 
 1295         *attrflagp = 0;
 1296         NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
 1297         if (nd->nd_flag & ND_NFSV4)
 1298                 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 1299         vap->va_type = vnode_vtype(vp);
 1300         nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
 1301         if (nd->nd_flag & ND_NFSV3) {
 1302                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1303                 *tl = newnfs_false;
 1304         } else if (nd->nd_flag & ND_NFSV4) {
 1305                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1306                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1307                 NFSGETATTR_ATTRBIT(&attrbits);
 1308                 (void) nfsrv_putattrbit(nd, &attrbits);
 1309         }
 1310         error = nfscl_request(nd, vp, p, cred, stuff);
 1311         if (error)
 1312                 return (error);
 1313         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
 1314                 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
 1315         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error)
 1316                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 1317         if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
 1318                 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
 1319         mbuf_freem(nd->nd_mrep);
 1320         if (nd->nd_repstat && !error)
 1321                 error = nd->nd_repstat;
 1322         return (error);
 1323 }
 1324 
 1325 /*
 1326  * nfs lookup rpc
 1327  */
 1328 int
 1329 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
 1330     NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
 1331     struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
 1332 {
 1333         u_int32_t *tl;
 1334         struct nfsrv_descript nfsd, *nd = &nfsd;
 1335         struct nfsmount *nmp;
 1336         struct nfsnode *np;
 1337         struct nfsfh *nfhp;
 1338         nfsattrbit_t attrbits;
 1339         int error = 0, lookupp = 0;
 1340 
 1341         *attrflagp = 0;
 1342         *dattrflagp = 0;
 1343         if (vnode_vtype(dvp) != VDIR)
 1344                 return (ENOTDIR);
 1345         nmp = VFSTONFS(vnode_mount(dvp));
 1346         if (len > NFS_MAXNAMLEN)
 1347                 return (ENAMETOOLONG);
 1348         if (NFSHASNFSV4(nmp) && len == 1 &&
 1349                 name[0] == '.') {
 1350                 /*
 1351                  * Just return the current dir's fh.
 1352                  */
 1353                 np = VTONFS(dvp);
 1354                 nfhp = malloc(sizeof (struct nfsfh) +
 1355                         np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
 1356                 nfhp->nfh_len = np->n_fhp->nfh_len;
 1357                 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
 1358                 *nfhpp = nfhp;
 1359                 return (0);
 1360         }
 1361         if (NFSHASNFSV4(nmp) && len == 2 &&
 1362                 name[0] == '.' && name[1] == '.') {
 1363                 lookupp = 1;
 1364                 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
 1365         } else {
 1366                 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
 1367                 (void) nfsm_strtom(nd, name, len);
 1368         }
 1369         if (nd->nd_flag & ND_NFSV4) {
 1370                 NFSGETATTR_ATTRBIT(&attrbits);
 1371                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1372                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 1373                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1374                 (void) nfsrv_putattrbit(nd, &attrbits);
 1375         }
 1376         error = nfscl_request(nd, dvp, p, cred, stuff);
 1377         if (error)
 1378                 return (error);
 1379         if (nd->nd_repstat) {
 1380                 /*
 1381                  * When an NFSv4 Lookupp returns ENOENT, it means that
 1382                  * the lookup is at the root of an fs, so return this dir.
 1383                  */
 1384                 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
 1385                     np = VTONFS(dvp);
 1386                     nfhp = malloc(sizeof (struct nfsfh) +
 1387                         np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
 1388                     nfhp->nfh_len = np->n_fhp->nfh_len;
 1389                     NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
 1390                     *nfhpp = nfhp;
 1391                     mbuf_freem(nd->nd_mrep);
 1392                     return (0);
 1393                 }
 1394                 if (nd->nd_flag & ND_NFSV3)
 1395                     error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
 1396                 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
 1397                     ND_NFSV4) {
 1398                         /* Load the directory attributes. */
 1399                         error = nfsm_loadattr(nd, dnap);
 1400                         if (error == 0)
 1401                                 *dattrflagp = 1;
 1402                 }
 1403                 goto nfsmout;
 1404         }
 1405         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
 1406                 /* Load the directory attributes. */
 1407                 error = nfsm_loadattr(nd, dnap);
 1408                 if (error != 0)
 1409                         goto nfsmout;
 1410                 *dattrflagp = 1;
 1411                 /* Skip over the Lookup and GetFH operation status values. */
 1412                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1413         }
 1414         error = nfsm_getfh(nd, nfhpp);
 1415         if (error)
 1416                 goto nfsmout;
 1417 
 1418         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 1419         if ((nd->nd_flag & ND_NFSV3) && !error)
 1420                 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
 1421 nfsmout:
 1422         mbuf_freem(nd->nd_mrep);
 1423         if (!error && nd->nd_repstat)
 1424                 error = nd->nd_repstat;
 1425         return (error);
 1426 }
 1427 
 1428 /*
 1429  * Do a readlink rpc.
 1430  */
 1431 int
 1432 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
 1433     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 1434 {
 1435         u_int32_t *tl;
 1436         struct nfsrv_descript nfsd, *nd = &nfsd;
 1437         struct nfsnode *np = VTONFS(vp);
 1438         nfsattrbit_t attrbits;
 1439         int error, len, cangetattr = 1;
 1440 
 1441         *attrflagp = 0;
 1442         NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
 1443         if (nd->nd_flag & ND_NFSV4) {
 1444                 /*
 1445                  * And do a Getattr op.
 1446                  */
 1447                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1448                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1449                 NFSGETATTR_ATTRBIT(&attrbits);
 1450                 (void) nfsrv_putattrbit(nd, &attrbits);
 1451         }
 1452         error = nfscl_request(nd, vp, p, cred, stuff);
 1453         if (error)
 1454                 return (error);
 1455         if (nd->nd_flag & ND_NFSV3)
 1456                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 1457         if (!nd->nd_repstat && !error) {
 1458                 NFSM_STRSIZ(len, NFS_MAXPATHLEN);
 1459                 /*
 1460                  * This seems weird to me, but must have been added to
 1461                  * FreeBSD for some reason. The only thing I can think of
 1462                  * is that there was/is some server that replies with
 1463                  * more link data than it should?
 1464                  */
 1465                 if (len == NFS_MAXPATHLEN) {
 1466                         NFSLOCKNODE(np);
 1467                         if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
 1468                                 len = np->n_size;
 1469                                 cangetattr = 0;
 1470                         }
 1471                         NFSUNLOCKNODE(np);
 1472                 }
 1473                 error = nfsm_mbufuio(nd, uiop, len);
 1474                 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
 1475                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 1476         }
 1477         if (nd->nd_repstat && !error)
 1478                 error = nd->nd_repstat;
 1479 nfsmout:
 1480         mbuf_freem(nd->nd_mrep);
 1481         return (error);
 1482 }
 1483 
 1484 /*
 1485  * Read operation.
 1486  */
 1487 int
 1488 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
 1489     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 1490 {
 1491         int error, expireret = 0, retrycnt;
 1492         u_int32_t clidrev = 0;
 1493         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1494         struct nfsnode *np = VTONFS(vp);
 1495         struct ucred *newcred;
 1496         struct nfsfh *nfhp = NULL;
 1497         nfsv4stateid_t stateid;
 1498         void *lckp;
 1499 
 1500         if (nmp->nm_clp != NULL)
 1501                 clidrev = nmp->nm_clp->nfsc_clientidrev;
 1502         newcred = cred;
 1503         if (NFSHASNFSV4(nmp)) {
 1504                 nfhp = np->n_fhp;
 1505                 newcred = NFSNEWCRED(cred);
 1506         }
 1507         retrycnt = 0;
 1508         do {
 1509                 lckp = NULL;
 1510                 if (NFSHASNFSV4(nmp))
 1511                         (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
 1512                             NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
 1513                             &lckp);
 1514                 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
 1515                     attrflagp, stuff);
 1516                 if (error == NFSERR_OPENMODE) {
 1517                         NFSLOCKMNT(nmp);
 1518                         nmp->nm_state |= NFSSTA_OPENMODE;
 1519                         NFSUNLOCKMNT(nmp);
 1520                 }
 1521                 if (error == NFSERR_STALESTATEID)
 1522                         nfscl_initiate_recovery(nmp->nm_clp);
 1523                 if (lckp != NULL)
 1524                         nfscl_lockderef(lckp);
 1525                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1526                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1527                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
 1528                         (void) nfs_catnap(PZERO, error, "nfs_read");
 1529                 } else if ((error == NFSERR_EXPIRED ||
 1530                     error == NFSERR_BADSTATEID) && clidrev != 0) {
 1531                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 1532                 }
 1533                 retrycnt++;
 1534         } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1535             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1536             error == NFSERR_BADSESSION ||
 1537             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
 1538             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 1539              expireret == 0 && clidrev != 0 && retrycnt < 4) ||
 1540             (error == NFSERR_OPENMODE && retrycnt < 4));
 1541         if (error && retrycnt >= 4)
 1542                 error = EIO;
 1543         if (NFSHASNFSV4(nmp))
 1544                 NFSFREECRED(newcred);
 1545         return (error);
 1546 }
 1547 
 1548 /*
 1549  * The actual read RPC.
 1550  */
 1551 static int
 1552 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
 1553     nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
 1554     int *attrflagp, void *stuff)
 1555 {
 1556         u_int32_t *tl;
 1557         int error = 0, len, retlen, tsiz, eof = 0;
 1558         struct nfsrv_descript nfsd;
 1559         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1560         struct nfsrv_descript *nd = &nfsd;
 1561         int rsize;
 1562         off_t tmp_off;
 1563 
 1564         *attrflagp = 0;
 1565         tsiz = uio_uio_resid(uiop);
 1566         tmp_off = uiop->uio_offset + tsiz;
 1567         NFSLOCKMNT(nmp);
 1568         if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
 1569                 NFSUNLOCKMNT(nmp);
 1570                 return (EFBIG);
 1571         }
 1572         rsize = nmp->nm_rsize;
 1573         NFSUNLOCKMNT(nmp);
 1574         nd->nd_mrep = NULL;
 1575         while (tsiz > 0) {
 1576                 *attrflagp = 0;
 1577                 len = (tsiz > rsize) ? rsize : tsiz;
 1578                 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
 1579                 if (nd->nd_flag & ND_NFSV4)
 1580                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 1581                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
 1582                 if (nd->nd_flag & ND_NFSV2) {
 1583                         *tl++ = txdr_unsigned(uiop->uio_offset);
 1584                         *tl++ = txdr_unsigned(len);
 1585                         *tl = 0;
 1586                 } else {
 1587                         txdr_hyper(uiop->uio_offset, tl);
 1588                         *(tl + 2) = txdr_unsigned(len);
 1589                 }
 1590                 /*
 1591                  * Since I can't do a Getattr for NFSv4 for Write, there
 1592                  * doesn't seem any point in doing one here, either.
 1593                  * (See the comment in nfsrpc_writerpc() for more info.)
 1594                  */
 1595                 error = nfscl_request(nd, vp, p, cred, stuff);
 1596                 if (error)
 1597                         return (error);
 1598                 if (nd->nd_flag & ND_NFSV3) {
 1599                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 1600                 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
 1601                         error = nfsm_loadattr(nd, nap);
 1602                         if (!error)
 1603                                 *attrflagp = 1;
 1604                 }
 1605                 if (nd->nd_repstat || error) {
 1606                         if (!error)
 1607                                 error = nd->nd_repstat;
 1608                         goto nfsmout;
 1609                 }
 1610                 if (nd->nd_flag & ND_NFSV3) {
 1611                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1612                         eof = fxdr_unsigned(int, *(tl + 1));
 1613                 } else if (nd->nd_flag & ND_NFSV4) {
 1614                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1615                         eof = fxdr_unsigned(int, *tl);
 1616                 }
 1617                 NFSM_STRSIZ(retlen, len);
 1618                 error = nfsm_mbufuio(nd, uiop, retlen);
 1619                 if (error)
 1620                         goto nfsmout;
 1621                 mbuf_freem(nd->nd_mrep);
 1622                 nd->nd_mrep = NULL;
 1623                 tsiz -= retlen;
 1624                 if (!(nd->nd_flag & ND_NFSV2)) {
 1625                         if (eof || retlen == 0)
 1626                                 tsiz = 0;
 1627                 } else if (retlen < len)
 1628                         tsiz = 0;
 1629         }
 1630         return (0);
 1631 nfsmout:
 1632         if (nd->nd_mrep != NULL)
 1633                 mbuf_freem(nd->nd_mrep);
 1634         return (error);
 1635 }
 1636 
 1637 /*
 1638  * nfs write operation
 1639  * When called_from_strategy != 0, it should return EIO for an error that
 1640  * indicates recovery is in progress, so that the buffer will be left
 1641  * dirty and be written back to the server later. If it loops around,
 1642  * the recovery thread could get stuck waiting for the buffer and recovery
 1643  * will then deadlock.
 1644  */
 1645 int
 1646 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
 1647     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 1648     void *stuff, int called_from_strategy)
 1649 {
 1650         int error, expireret = 0, retrycnt, nostateid;
 1651         u_int32_t clidrev = 0;
 1652         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1653         struct nfsnode *np = VTONFS(vp);
 1654         struct ucred *newcred;
 1655         struct nfsfh *nfhp = NULL;
 1656         nfsv4stateid_t stateid;
 1657         void *lckp;
 1658 
 1659         *must_commit = 0;
 1660         if (nmp->nm_clp != NULL)
 1661                 clidrev = nmp->nm_clp->nfsc_clientidrev;
 1662         newcred = cred;
 1663         if (NFSHASNFSV4(nmp)) {
 1664                 newcred = NFSNEWCRED(cred);
 1665                 nfhp = np->n_fhp;
 1666         }
 1667         retrycnt = 0;
 1668         do {
 1669                 lckp = NULL;
 1670                 nostateid = 0;
 1671                 if (NFSHASNFSV4(nmp)) {
 1672                         (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
 1673                             NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
 1674                             &lckp);
 1675                         if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
 1676                             stateid.other[2] == 0) {
 1677                                 nostateid = 1;
 1678                                 NFSCL_DEBUG(1, "stateid0 in write\n");
 1679                         }
 1680                 }
 1681 
 1682                 /*
 1683                  * If there is no stateid for NFSv4, it means this is an
 1684                  * extraneous write after close. Basically a poorly
 1685                  * implemented buffer cache. Just don't do the write.
 1686                  */
 1687                 if (nostateid)
 1688                         error = 0;
 1689                 else
 1690                         error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
 1691                             newcred, &stateid, p, nap, attrflagp, stuff);
 1692                 if (error == NFSERR_STALESTATEID)
 1693                         nfscl_initiate_recovery(nmp->nm_clp);
 1694                 if (lckp != NULL)
 1695                         nfscl_lockderef(lckp);
 1696                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1697                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1698                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
 1699                         (void) nfs_catnap(PZERO, error, "nfs_write");
 1700                 } else if ((error == NFSERR_EXPIRED ||
 1701                     error == NFSERR_BADSTATEID) && clidrev != 0) {
 1702                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 1703                 }
 1704                 retrycnt++;
 1705         } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
 1706             ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
 1707               error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
 1708             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
 1709             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 1710              expireret == 0 && clidrev != 0 && retrycnt < 4));
 1711         if (error != 0 && (retrycnt >= 4 ||
 1712             ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
 1713               error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
 1714                 error = EIO;
 1715         if (NFSHASNFSV4(nmp))
 1716                 NFSFREECRED(newcred);
 1717         return (error);
 1718 }
 1719 
 1720 /*
 1721  * The actual write RPC.
 1722  */
 1723 static int
 1724 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
 1725     int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
 1726     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 1727 {
 1728         u_int32_t *tl;
 1729         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1730         struct nfsnode *np = VTONFS(vp);
 1731         int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
 1732         int wccflag = 0, wsize;
 1733         int32_t backup;
 1734         struct nfsrv_descript nfsd;
 1735         struct nfsrv_descript *nd = &nfsd;
 1736         nfsattrbit_t attrbits;
 1737         off_t tmp_off;
 1738 
 1739         KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
 1740         *attrflagp = 0;
 1741         tsiz = uio_uio_resid(uiop);
 1742         tmp_off = uiop->uio_offset + tsiz;
 1743         NFSLOCKMNT(nmp);
 1744         if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
 1745                 NFSUNLOCKMNT(nmp);
 1746                 return (EFBIG);
 1747         }
 1748         wsize = nmp->nm_wsize;
 1749         NFSUNLOCKMNT(nmp);
 1750         nd->nd_mrep = NULL;     /* NFSv2 sometimes does a write with */
 1751         nd->nd_repstat = 0;     /* uio_resid == 0, so the while is not done */
 1752         while (tsiz > 0) {
 1753                 *attrflagp = 0;
 1754                 len = (tsiz > wsize) ? wsize : tsiz;
 1755                 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
 1756                 if (nd->nd_flag & ND_NFSV4) {
 1757                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 1758                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
 1759                         txdr_hyper(uiop->uio_offset, tl);
 1760                         tl += 2;
 1761                         *tl++ = txdr_unsigned(*iomode);
 1762                         *tl = txdr_unsigned(len);
 1763                 } else if (nd->nd_flag & ND_NFSV3) {
 1764                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
 1765                         txdr_hyper(uiop->uio_offset, tl);
 1766                         tl += 2;
 1767                         *tl++ = txdr_unsigned(len);
 1768                         *tl++ = txdr_unsigned(*iomode);
 1769                         *tl = txdr_unsigned(len);
 1770                 } else {
 1771                         u_int32_t x;
 1772 
 1773                         NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1774                         /*
 1775                          * Not sure why someone changed this, since the
 1776                          * RFC clearly states that "beginoffset" and
 1777                          * "totalcount" are ignored, but it wouldn't
 1778                          * surprise me if there's a busted server out there.
 1779                          */
 1780                         /* Set both "begin" and "current" to non-garbage. */
 1781                         x = txdr_unsigned((u_int32_t)uiop->uio_offset);
 1782                         *tl++ = x;      /* "begin offset" */
 1783                         *tl++ = x;      /* "current offset" */
 1784                         x = txdr_unsigned(len);
 1785                         *tl++ = x;      /* total to this offset */
 1786                         *tl = x;        /* size of this write */
 1787 
 1788                 }
 1789                 nfsm_uiombuf(nd, uiop, len);
 1790                 /*
 1791                  * Although it is tempting to do a normal Getattr Op in the
 1792                  * NFSv4 compound, the result can be a nearly hung client
 1793                  * system if the Getattr asks for Owner and/or OwnerGroup.
 1794                  * It occurs when the client can't map either the Owner or
 1795                  * Owner_group name in the Getattr reply to a uid/gid. When
 1796                  * there is a cache miss, the kernel does an upcall to the
 1797                  * nfsuserd. Then, it can try and read the local /etc/passwd
 1798                  * or /etc/group file. It can then block in getnewbuf(),
 1799                  * waiting for dirty writes to be pushed to the NFS server.
 1800                  * The only reason this doesn't result in a complete
 1801                  * deadlock, is that the upcall times out and allows
 1802                  * the write to complete. However, progress is so slow
 1803                  * that it might just as well be deadlocked.
 1804                  * As such, we get the rest of the attributes, but not
 1805                  * Owner or Owner_group.
 1806                  * nb: nfscl_loadattrcache() needs to be told that these
 1807                  *     partial attributes from a write rpc are being
 1808                  *     passed in, via a argument flag.
 1809                  */
 1810                 if (nd->nd_flag & ND_NFSV4) {
 1811                         NFSWRITEGETATTR_ATTRBIT(&attrbits);
 1812                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1813                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1814                         (void) nfsrv_putattrbit(nd, &attrbits);
 1815                 }
 1816                 error = nfscl_request(nd, vp, p, cred, stuff);
 1817                 if (error)
 1818                         return (error);
 1819                 if (nd->nd_repstat) {
 1820                         /*
 1821                          * In case the rpc gets retried, roll
 1822                          * the uio fileds changed by nfsm_uiombuf()
 1823                          * back.
 1824                          */
 1825                         uiop->uio_offset -= len;
 1826                         uio_uio_resid_add(uiop, len);
 1827                         uio_iov_base_add(uiop, -len);
 1828                         uio_iov_len_add(uiop, len);
 1829                 }
 1830                 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 1831                         error = nfscl_wcc_data(nd, vp, nap, attrflagp,
 1832                             &wccflag, stuff);
 1833                         if (error)
 1834                                 goto nfsmout;
 1835                 }
 1836                 if (!nd->nd_repstat) {
 1837                         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 1838                                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
 1839                                         + NFSX_VERF);
 1840                                 rlen = fxdr_unsigned(int, *tl++);
 1841                                 if (rlen == 0) {
 1842                                         error = NFSERR_IO;
 1843                                         goto nfsmout;
 1844                                 } else if (rlen < len) {
 1845                                         backup = len - rlen;
 1846                                         uio_iov_base_add(uiop, -(backup));
 1847                                         uio_iov_len_add(uiop, backup);
 1848                                         uiop->uio_offset -= backup;
 1849                                         uio_uio_resid_add(uiop, backup);
 1850                                         len = rlen;
 1851                                 }
 1852                                 commit = fxdr_unsigned(int, *tl++);
 1853 
 1854                                 /*
 1855                                  * Return the lowest commitment level
 1856                                  * obtained by any of the RPCs.
 1857                                  */
 1858                                 if (committed == NFSWRITE_FILESYNC)
 1859                                         committed = commit;
 1860                                 else if (committed == NFSWRITE_DATASYNC &&
 1861                                         commit == NFSWRITE_UNSTABLE)
 1862                                         committed = commit;
 1863                                 NFSLOCKMNT(nmp);
 1864                                 if (!NFSHASWRITEVERF(nmp)) {
 1865                                         NFSBCOPY((caddr_t)tl,
 1866                                             (caddr_t)&nmp->nm_verf[0],
 1867                                             NFSX_VERF);
 1868                                         NFSSETWRITEVERF(nmp);
 1869                                 } else if (NFSBCMP(tl, nmp->nm_verf,
 1870                                     NFSX_VERF)) {
 1871                                         *must_commit = 1;
 1872                                         NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
 1873                                 }
 1874                                 NFSUNLOCKMNT(nmp);
 1875                         }
 1876                         if (nd->nd_flag & ND_NFSV4)
 1877                                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1878                         if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
 1879                                 error = nfsm_loadattr(nd, nap);
 1880                                 if (!error)
 1881                                         *attrflagp = NFS_LATTR_NOSHRINK;
 1882                         }
 1883                 } else {
 1884                         error = nd->nd_repstat;
 1885                 }
 1886                 if (error)
 1887                         goto nfsmout;
 1888                 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4));
 1889                 mbuf_freem(nd->nd_mrep);
 1890                 nd->nd_mrep = NULL;
 1891                 tsiz -= len;
 1892         }
 1893 nfsmout:
 1894         if (nd->nd_mrep != NULL)
 1895                 mbuf_freem(nd->nd_mrep);
 1896         *iomode = committed;
 1897         if (nd->nd_repstat && !error)
 1898                 error = nd->nd_repstat;
 1899         return (error);
 1900 }
 1901 
 1902 /*
 1903  * nfs mknod rpc
 1904  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
 1905  * mode set to specify the file type and the size field for rdev.
 1906  */
 1907 int
 1908 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 1909     u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
 1910     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
 1911     int *attrflagp, int *dattrflagp, void *dstuff)
 1912 {
 1913         u_int32_t *tl;
 1914         int error = 0;
 1915         struct nfsrv_descript nfsd, *nd = &nfsd;
 1916         nfsattrbit_t attrbits;
 1917 
 1918         *nfhpp = NULL;
 1919         *attrflagp = 0;
 1920         *dattrflagp = 0;
 1921         if (namelen > NFS_MAXNAMLEN)
 1922                 return (ENAMETOOLONG);
 1923         NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
 1924         if (nd->nd_flag & ND_NFSV4) {
 1925                 if (vtyp == VBLK || vtyp == VCHR) {
 1926                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 1927                         *tl++ = vtonfsv34_type(vtyp);
 1928                         *tl++ = txdr_unsigned(NFSMAJOR(rdev));
 1929                         *tl = txdr_unsigned(NFSMINOR(rdev));
 1930                 } else {
 1931                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1932                         *tl = vtonfsv34_type(vtyp);
 1933                 }
 1934         }
 1935         (void) nfsm_strtom(nd, name, namelen);
 1936         if (nd->nd_flag & ND_NFSV3) {
 1937                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1938                 *tl = vtonfsv34_type(vtyp);
 1939         }
 1940         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
 1941                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 1942         if ((nd->nd_flag & ND_NFSV3) &&
 1943             (vtyp == VCHR || vtyp == VBLK)) {
 1944                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1945                 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
 1946                 *tl = txdr_unsigned(NFSMINOR(rdev));
 1947         }
 1948         if (nd->nd_flag & ND_NFSV4) {
 1949                 NFSGETATTR_ATTRBIT(&attrbits);
 1950                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1951                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 1952                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1953                 (void) nfsrv_putattrbit(nd, &attrbits);
 1954         }
 1955         if (nd->nd_flag & ND_NFSV2)
 1956                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
 1957         error = nfscl_request(nd, dvp, p, cred, dstuff);
 1958         if (error)
 1959                 return (error);
 1960         if (nd->nd_flag & ND_NFSV4)
 1961                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 1962         if (!nd->nd_repstat) {
 1963                 if (nd->nd_flag & ND_NFSV4) {
 1964                         NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1965                         error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 1966                         if (error)
 1967                                 goto nfsmout;
 1968                 }
 1969                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 1970                 if (error)
 1971                         goto nfsmout;
 1972         }
 1973         if (nd->nd_flag & ND_NFSV3)
 1974                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 1975         if (!error && nd->nd_repstat)
 1976                 error = nd->nd_repstat;
 1977 nfsmout:
 1978         mbuf_freem(nd->nd_mrep);
 1979         return (error);
 1980 }
 1981 
 1982 /*
 1983  * nfs file create call
 1984  * Mostly just call the approriate routine. (I separated out v4, so that
 1985  * error recovery wouldn't be as difficult.)
 1986  */
 1987 int
 1988 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 1989     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
 1990     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
 1991     int *attrflagp, int *dattrflagp, void *dstuff)
 1992 {
 1993         int error = 0, newone, expireret = 0, retrycnt, unlocked;
 1994         struct nfsclowner *owp;
 1995         struct nfscldeleg *dp;
 1996         struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
 1997         u_int32_t clidrev;
 1998 
 1999         if (NFSHASNFSV4(nmp)) {
 2000             retrycnt = 0;
 2001             do {
 2002                 dp = NULL;
 2003                 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
 2004                     NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
 2005                     NULL, 1, true);
 2006                 if (error)
 2007                         return (error);
 2008                 if (nmp->nm_clp != NULL)
 2009                         clidrev = nmp->nm_clp->nfsc_clientidrev;
 2010                 else
 2011                         clidrev = 0;
 2012                 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
 2013                     nfs_numnfscbd == 0 || retrycnt > 0)
 2014                         error = nfsrpc_createv4(dvp, name, namelen, vap, cverf,
 2015                           fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
 2016                           attrflagp, dattrflagp, dstuff, &unlocked);
 2017                 else
 2018                         error = nfsrpc_getcreatelayout(dvp, name, namelen, vap,
 2019                           cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
 2020                           attrflagp, dattrflagp, dstuff, &unlocked);
 2021                 /*
 2022                  * There is no need to invalidate cached attributes here,
 2023                  * since new post-delegation issue attributes are always
 2024                  * returned by nfsrpc_createv4() and these will update the
 2025                  * attribute cache.
 2026                  */
 2027                 if (dp != NULL)
 2028                         (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
 2029                             (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
 2030                 nfscl_ownerrelease(nmp, owp, error, newone, unlocked);
 2031                 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
 2032                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 2033                     error == NFSERR_BADSESSION) {
 2034                         (void) nfs_catnap(PZERO, error, "nfs_open");
 2035                 } else if ((error == NFSERR_EXPIRED ||
 2036                     error == NFSERR_BADSTATEID) && clidrev != 0) {
 2037                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 2038                         retrycnt++;
 2039                 }
 2040             } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
 2041                 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 2042                 error == NFSERR_BADSESSION ||
 2043                 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 2044                  expireret == 0 && clidrev != 0 && retrycnt < 4));
 2045             if (error && retrycnt >= 4)
 2046                     error = EIO;
 2047         } else {
 2048                 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
 2049                     fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
 2050                     dstuff);
 2051         }
 2052         return (error);
 2053 }
 2054 
 2055 /*
 2056  * The create rpc for v2 and 3.
 2057  */
 2058 static int
 2059 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 2060     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
 2061     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
 2062     int *attrflagp, int *dattrflagp, void *dstuff)
 2063 {
 2064         u_int32_t *tl;
 2065         int error = 0;
 2066         struct nfsrv_descript nfsd, *nd = &nfsd;
 2067 
 2068         *nfhpp = NULL;
 2069         *attrflagp = 0;
 2070         *dattrflagp = 0;
 2071         if (namelen > NFS_MAXNAMLEN)
 2072                 return (ENAMETOOLONG);
 2073         NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
 2074         (void) nfsm_strtom(nd, name, namelen);
 2075         if (nd->nd_flag & ND_NFSV3) {
 2076                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2077                 if (fmode & O_EXCL) {
 2078                         *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
 2079                         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 2080                         *tl++ = cverf.lval[0];
 2081                         *tl = cverf.lval[1];
 2082                 } else {
 2083                         *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
 2084                         nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2085                 }
 2086         } else {
 2087                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
 2088         }
 2089         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2090         if (error)
 2091                 return (error);
 2092         if (nd->nd_repstat == 0) {
 2093                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 2094                 if (error)
 2095                         goto nfsmout;
 2096         }
 2097         if (nd->nd_flag & ND_NFSV3)
 2098                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2099         if (nd->nd_repstat != 0 && error == 0)
 2100                 error = nd->nd_repstat;
 2101 nfsmout:
 2102         mbuf_freem(nd->nd_mrep);
 2103         return (error);
 2104 }
 2105 
 2106 static int
 2107 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 2108     nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
 2109     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 2110     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
 2111     int *dattrflagp, void *dstuff, int *unlockedp)
 2112 {
 2113         u_int32_t *tl;
 2114         int error = 0, deleg, newone, ret, acesize, limitby;
 2115         struct nfsrv_descript nfsd, *nd = &nfsd;
 2116         struct nfsclopen *op;
 2117         struct nfscldeleg *dp = NULL;
 2118         struct nfsnode *np;
 2119         struct nfsfh *nfhp;
 2120         nfsattrbit_t attrbits;
 2121         nfsv4stateid_t stateid;
 2122         u_int32_t rflags;
 2123         struct nfsmount *nmp;
 2124         struct nfsclsession *tsep;
 2125 
 2126         nmp = VFSTONFS(dvp->v_mount);
 2127         np = VTONFS(dvp);
 2128         *unlockedp = 0;
 2129         *nfhpp = NULL;
 2130         *dpp = NULL;
 2131         *attrflagp = 0;
 2132         *dattrflagp = 0;
 2133         if (namelen > NFS_MAXNAMLEN)
 2134                 return (ENAMETOOLONG);
 2135         NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
 2136         /*
 2137          * For V4, this is actually an Open op.
 2138          */
 2139         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 2140         *tl++ = txdr_unsigned(owp->nfsow_seqid);
 2141         *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
 2142             NFSV4OPEN_ACCESSREAD);
 2143         *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
 2144         tsep = nfsmnt_mdssession(nmp);
 2145         *tl++ = tsep->nfsess_clientid.lval[0];
 2146         *tl = tsep->nfsess_clientid.lval[1];
 2147         (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
 2148         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2149         *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
 2150         if (fmode & O_EXCL) {
 2151                 if (NFSHASNFSV4N(nmp)) {
 2152                         if (NFSHASSESSPERSIST(nmp)) {
 2153                                 /* Use GUARDED for persistent sessions. */
 2154                                 *tl = txdr_unsigned(NFSCREATE_GUARDED);
 2155                                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2156                         } else {
 2157                                 /* Otherwise, use EXCLUSIVE4_1. */
 2158                                 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
 2159                                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 2160                                 *tl++ = cverf.lval[0];
 2161                                 *tl = cverf.lval[1];
 2162                                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2163                         }
 2164                 } else {
 2165                         /* NFSv4.0 */
 2166                         *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
 2167                         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 2168                         *tl++ = cverf.lval[0];
 2169                         *tl = cverf.lval[1];
 2170                 }
 2171         } else {
 2172                 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
 2173                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2174         }
 2175         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2176         *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
 2177         (void) nfsm_strtom(nd, name, namelen);
 2178         /* Get the new file's handle and attributes. */
 2179         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2180         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 2181         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2182         NFSGETATTR_ATTRBIT(&attrbits);
 2183         (void) nfsrv_putattrbit(nd, &attrbits);
 2184         /* Get the directory's post-op attributes. */
 2185         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2186         *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2187         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
 2188         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2189         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2190         (void) nfsrv_putattrbit(nd, &attrbits);
 2191         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2192         if (error)
 2193                 return (error);
 2194         NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
 2195         if (nd->nd_repstat == 0) {
 2196                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
 2197                     6 * NFSX_UNSIGNED);
 2198                 stateid.seqid = *tl++;
 2199                 stateid.other[0] = *tl++;
 2200                 stateid.other[1] = *tl++;
 2201                 stateid.other[2] = *tl;
 2202                 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
 2203                 (void) nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 2204                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2205                 deleg = fxdr_unsigned(int, *tl);
 2206                 if (deleg == NFSV4OPEN_DELEGATEREAD ||
 2207                     deleg == NFSV4OPEN_DELEGATEWRITE) {
 2208                         if (!(owp->nfsow_clp->nfsc_flags &
 2209                               NFSCLFLAGS_FIRSTDELEG))
 2210                                 owp->nfsow_clp->nfsc_flags |=
 2211                                   (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
 2212                         dp = malloc(
 2213                             sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
 2214                             M_NFSCLDELEG, M_WAITOK);
 2215                         LIST_INIT(&dp->nfsdl_owner);
 2216                         LIST_INIT(&dp->nfsdl_lock);
 2217                         dp->nfsdl_clp = owp->nfsow_clp;
 2218                         newnfs_copyincred(cred, &dp->nfsdl_cred);
 2219                         nfscl_lockinit(&dp->nfsdl_rwlock);
 2220                         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
 2221                             NFSX_UNSIGNED);
 2222                         dp->nfsdl_stateid.seqid = *tl++;
 2223                         dp->nfsdl_stateid.other[0] = *tl++;
 2224                         dp->nfsdl_stateid.other[1] = *tl++;
 2225                         dp->nfsdl_stateid.other[2] = *tl++;
 2226                         ret = fxdr_unsigned(int, *tl);
 2227                         if (deleg == NFSV4OPEN_DELEGATEWRITE) {
 2228                                 dp->nfsdl_flags = NFSCLDL_WRITE;
 2229                                 /*
 2230                                  * Indicates how much the file can grow.
 2231                                  */
 2232                                 NFSM_DISSECT(tl, u_int32_t *,
 2233                                     3 * NFSX_UNSIGNED);
 2234                                 limitby = fxdr_unsigned(int, *tl++);
 2235                                 switch (limitby) {
 2236                                 case NFSV4OPEN_LIMITSIZE:
 2237                                         dp->nfsdl_sizelimit = fxdr_hyper(tl);
 2238                                         break;
 2239                                 case NFSV4OPEN_LIMITBLOCKS:
 2240                                         dp->nfsdl_sizelimit =
 2241                                             fxdr_unsigned(u_int64_t, *tl++);
 2242                                         dp->nfsdl_sizelimit *=
 2243                                             fxdr_unsigned(u_int64_t, *tl);
 2244                                         break;
 2245                                 default:
 2246                                         error = NFSERR_BADXDR;
 2247                                         goto nfsmout;
 2248                                 }
 2249                         } else {
 2250                                 dp->nfsdl_flags = NFSCLDL_READ;
 2251                         }
 2252                         if (ret)
 2253                                 dp->nfsdl_flags |= NFSCLDL_RECALL;
 2254                         error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
 2255                             &acesize, p);
 2256                         if (error)
 2257                                 goto nfsmout;
 2258                 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
 2259                         error = NFSERR_BADXDR;
 2260                         goto nfsmout;
 2261                 }
 2262                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 2263                 if (error)
 2264                         goto nfsmout;
 2265                 /* Get rid of the PutFH and Getattr status values. */
 2266                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 2267                 /* Load the directory attributes. */
 2268                 error = nfsm_loadattr(nd, dnap);
 2269                 if (error)
 2270                         goto nfsmout;
 2271                 *dattrflagp = 1;
 2272                 if (dp != NULL && *attrflagp) {
 2273                         dp->nfsdl_change = nnap->na_filerev;
 2274                         dp->nfsdl_modtime = nnap->na_mtime;
 2275                         dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
 2276                 }
 2277                 /*
 2278                  * We can now complete the Open state.
 2279                  */
 2280                 nfhp = *nfhpp;
 2281                 if (dp != NULL) {
 2282                         dp->nfsdl_fhlen = nfhp->nfh_len;
 2283                         NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
 2284                 }
 2285                 /*
 2286                  * Get an Open structure that will be
 2287                  * attached to the OpenOwner, acquired already.
 2288                  */
 2289                 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 
 2290                     (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
 2291                     cred, p, NULL, &op, &newone, NULL, 0, false);
 2292                 if (error)
 2293                         goto nfsmout;
 2294                 op->nfso_stateid = stateid;
 2295                 newnfs_copyincred(cred, &op->nfso_cred);
 2296                 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
 2297                     do {
 2298                         ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
 2299                             nfhp->nfh_len, op, cred, p);
 2300                         if (ret == NFSERR_DELAY)
 2301                             (void) nfs_catnap(PZERO, ret, "nfs_create");
 2302                     } while (ret == NFSERR_DELAY);
 2303                     error = ret;
 2304                 }
 2305 
 2306                 /*
 2307                  * If the server is handing out delegations, but we didn't
 2308                  * get one because an OpenConfirm was required, try the
 2309                  * Open again, to get a delegation. This is a harmless no-op,
 2310                  * from a server's point of view.
 2311                  */
 2312                 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
 2313                     (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
 2314                     !error && dp == NULL) {
 2315                     do {
 2316                         ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
 2317                             np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
 2318                             nfhp->nfh_fh, nfhp->nfh_len,
 2319                             (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
 2320                             name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
 2321                         if (ret == NFSERR_DELAY)
 2322                             (void) nfs_catnap(PZERO, ret, "nfs_crt2");
 2323                     } while (ret == NFSERR_DELAY);
 2324                     if (ret) {
 2325                         if (dp != NULL) {
 2326                                 free(dp, M_NFSCLDELEG);
 2327                                 dp = NULL;
 2328                         }
 2329                         if (ret == NFSERR_STALECLIENTID ||
 2330                             ret == NFSERR_STALEDONTRECOVER ||
 2331                             ret == NFSERR_BADSESSION)
 2332                                 error = ret;
 2333                     }
 2334                 }
 2335                 nfscl_openrelease(nmp, op, error, newone);
 2336                 *unlockedp = 1;
 2337         }
 2338         if (nd->nd_repstat != 0 && error == 0)
 2339                 error = nd->nd_repstat;
 2340         if (error == NFSERR_STALECLIENTID)
 2341                 nfscl_initiate_recovery(owp->nfsow_clp);
 2342 nfsmout:
 2343         if (!error)
 2344                 *dpp = dp;
 2345         else if (dp != NULL)
 2346                 free(dp, M_NFSCLDELEG);
 2347         mbuf_freem(nd->nd_mrep);
 2348         return (error);
 2349 }
 2350 
 2351 /*
 2352  * Nfs remove rpc
 2353  */
 2354 int
 2355 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
 2356     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
 2357     void *dstuff)
 2358 {
 2359         u_int32_t *tl;
 2360         struct nfsrv_descript nfsd, *nd = &nfsd;
 2361         struct nfsnode *np;
 2362         struct nfsmount *nmp;
 2363         nfsv4stateid_t dstateid;
 2364         int error, ret = 0, i;
 2365 
 2366         *dattrflagp = 0;
 2367         if (namelen > NFS_MAXNAMLEN)
 2368                 return (ENAMETOOLONG);
 2369         nmp = VFSTONFS(vnode_mount(dvp));
 2370 tryagain:
 2371         if (NFSHASNFSV4(nmp) && ret == 0) {
 2372                 ret = nfscl_removedeleg(vp, p, &dstateid);
 2373                 if (ret == 1) {
 2374                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
 2375                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
 2376                             NFSX_UNSIGNED);
 2377                         if (NFSHASNFSV4N(nmp))
 2378                                 *tl++ = 0;
 2379                         else
 2380                                 *tl++ = dstateid.seqid;
 2381                         *tl++ = dstateid.other[0];
 2382                         *tl++ = dstateid.other[1];
 2383                         *tl++ = dstateid.other[2];
 2384                         *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2385                         np = VTONFS(dvp);
 2386                         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
 2387                             np->n_fhp->nfh_len, 0);
 2388                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2389                         *tl = txdr_unsigned(NFSV4OP_REMOVE);
 2390                 }
 2391         } else {
 2392                 ret = 0;
 2393         }
 2394         if (ret == 0)
 2395                 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
 2396         (void) nfsm_strtom(nd, name, namelen);
 2397         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2398         if (error)
 2399                 return (error);
 2400         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 2401                 /* For NFSv4, parse out any Delereturn replies. */
 2402                 if (ret > 0 && nd->nd_repstat != 0 &&
 2403                     (nd->nd_flag & ND_NOMOREDATA)) {
 2404                         /*
 2405                          * If the Delegreturn failed, try again without
 2406                          * it. The server will Recall, as required.
 2407                          */
 2408                         mbuf_freem(nd->nd_mrep);
 2409                         goto tryagain;
 2410                 }
 2411                 for (i = 0; i < (ret * 2); i++) {
 2412                         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
 2413                             ND_NFSV4) {
 2414                             NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2415                             if (*(tl + 1))
 2416                                 nd->nd_flag |= ND_NOMOREDATA;
 2417                         }
 2418                 }
 2419                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2420         }
 2421         if (nd->nd_repstat && !error)
 2422                 error = nd->nd_repstat;
 2423 nfsmout:
 2424         mbuf_freem(nd->nd_mrep);
 2425         return (error);
 2426 }
 2427 
 2428 /*
 2429  * Do an nfs rename rpc.
 2430  */
 2431 int
 2432 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
 2433     vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
 2434     NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
 2435     int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
 2436 {
 2437         u_int32_t *tl;
 2438         struct nfsrv_descript nfsd, *nd = &nfsd;
 2439         struct nfsmount *nmp;
 2440         struct nfsnode *np;
 2441         nfsattrbit_t attrbits;
 2442         nfsv4stateid_t fdstateid, tdstateid;
 2443         int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
 2444         
 2445         *fattrflagp = 0;
 2446         *tattrflagp = 0;
 2447         nmp = VFSTONFS(vnode_mount(fdvp));
 2448         if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
 2449                 return (ENAMETOOLONG);
 2450 tryagain:
 2451         if (NFSHASNFSV4(nmp) && ret == 0) {
 2452                 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
 2453                     &tdstateid, &gottd, p);
 2454                 if (gotfd && gottd) {
 2455                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
 2456                 } else if (gotfd) {
 2457                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
 2458                 } else if (gottd) {
 2459                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
 2460                 }
 2461                 if (gotfd) {
 2462                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2463                         if (NFSHASNFSV4N(nmp))
 2464                                 *tl++ = 0;
 2465                         else
 2466                                 *tl++ = fdstateid.seqid;
 2467                         *tl++ = fdstateid.other[0];
 2468                         *tl++ = fdstateid.other[1];
 2469                         *tl = fdstateid.other[2];
 2470                         if (gottd) {
 2471                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2472                                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2473                                 np = VTONFS(tvp);
 2474                                 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
 2475                                     np->n_fhp->nfh_len, 0);
 2476                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2477                                 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
 2478                         }
 2479                 }
 2480                 if (gottd) {
 2481                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2482                         if (NFSHASNFSV4N(nmp))
 2483                                 *tl++ = 0;
 2484                         else
 2485                                 *tl++ = tdstateid.seqid;
 2486                         *tl++ = tdstateid.other[0];
 2487                         *tl++ = tdstateid.other[1];
 2488                         *tl = tdstateid.other[2];
 2489                 }
 2490                 if (ret > 0) {
 2491                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2492                         *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2493                         np = VTONFS(fdvp);
 2494                         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
 2495                             np->n_fhp->nfh_len, 0);
 2496                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2497                         *tl = txdr_unsigned(NFSV4OP_SAVEFH);
 2498                 }
 2499         } else {
 2500                 ret = 0;
 2501         }
 2502         if (ret == 0)
 2503                 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
 2504         if (nd->nd_flag & ND_NFSV4) {
 2505                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2506                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2507                 NFSWCCATTR_ATTRBIT(&attrbits);
 2508                 (void) nfsrv_putattrbit(nd, &attrbits);
 2509                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2510                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2511                 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
 2512                     VTONFS(tdvp)->n_fhp->nfh_len, 0);
 2513                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2514                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2515                 (void) nfsrv_putattrbit(nd, &attrbits);
 2516                 nd->nd_flag |= ND_V4WCCATTR;
 2517                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2518                 *tl = txdr_unsigned(NFSV4OP_RENAME);
 2519         }
 2520         (void) nfsm_strtom(nd, fnameptr, fnamelen);
 2521         if (!(nd->nd_flag & ND_NFSV4))
 2522                 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
 2523                         VTONFS(tdvp)->n_fhp->nfh_len, 0);
 2524         (void) nfsm_strtom(nd, tnameptr, tnamelen);
 2525         error = nfscl_request(nd, fdvp, p, cred, fstuff);
 2526         if (error)
 2527                 return (error);
 2528         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 2529                 /* For NFSv4, parse out any Delereturn replies. */
 2530                 if (ret > 0 && nd->nd_repstat != 0 &&
 2531                     (nd->nd_flag & ND_NOMOREDATA)) {
 2532                         /*
 2533                          * If the Delegreturn failed, try again without
 2534                          * it. The server will Recall, as required.
 2535                          */
 2536                         mbuf_freem(nd->nd_mrep);
 2537                         goto tryagain;
 2538                 }
 2539                 for (i = 0; i < (ret * 2); i++) {
 2540                         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
 2541                             ND_NFSV4) {
 2542                             NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2543                             if (*(tl + 1)) {
 2544                                 if (i == 0 && ret > 1) {
 2545                                     /*
 2546                                      * If the Delegreturn failed, try again
 2547                                      * without it. The server will Recall, as
 2548                                      * required.
 2549                                      * If ret > 1, the first iteration of this
 2550                                      * loop is the second DelegReturn result.
 2551                                      */
 2552                                     mbuf_freem(nd->nd_mrep);
 2553                                     goto tryagain;
 2554                                 } else {
 2555                                     nd->nd_flag |= ND_NOMOREDATA;
 2556                                 }
 2557                             }
 2558                         }
 2559                 }
 2560                 /* Now, the first wcc attribute reply. */
 2561                 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
 2562                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2563                         if (*(tl + 1))
 2564                                 nd->nd_flag |= ND_NOMOREDATA;
 2565                 }
 2566                 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
 2567                     fstuff);
 2568                 /* and the second wcc attribute reply. */
 2569                 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
 2570                     !error) {
 2571                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2572                         if (*(tl + 1))
 2573                                 nd->nd_flag |= ND_NOMOREDATA;
 2574                 }
 2575                 if (!error)
 2576                         error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
 2577                             NULL, tstuff);
 2578         }
 2579         if (nd->nd_repstat && !error)
 2580                 error = nd->nd_repstat;
 2581 nfsmout:
 2582         mbuf_freem(nd->nd_mrep);
 2583         return (error);
 2584 }
 2585 
 2586 /*
 2587  * nfs hard link create rpc
 2588  */
 2589 int
 2590 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
 2591     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 2592     struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
 2593 {
 2594         u_int32_t *tl;
 2595         struct nfsrv_descript nfsd, *nd = &nfsd;
 2596         nfsattrbit_t attrbits;
 2597         int error = 0;
 2598 
 2599         *attrflagp = 0;
 2600         *dattrflagp = 0;
 2601         if (namelen > NFS_MAXNAMLEN)
 2602                 return (ENAMETOOLONG);
 2603         NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
 2604         if (nd->nd_flag & ND_NFSV4) {
 2605                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2606                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2607         }
 2608         (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
 2609                 VTONFS(dvp)->n_fhp->nfh_len, 0);
 2610         if (nd->nd_flag & ND_NFSV4) {
 2611                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2612                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2613                 NFSWCCATTR_ATTRBIT(&attrbits);
 2614                 (void) nfsrv_putattrbit(nd, &attrbits);
 2615                 nd->nd_flag |= ND_V4WCCATTR;
 2616                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2617                 *tl = txdr_unsigned(NFSV4OP_LINK);
 2618         }
 2619         (void) nfsm_strtom(nd, name, namelen);
 2620         error = nfscl_request(nd, vp, p, cred, dstuff);
 2621         if (error)
 2622                 return (error);
 2623         if (nd->nd_flag & ND_NFSV3) {
 2624                 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
 2625                 if (!error)
 2626                         error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
 2627                             NULL, dstuff);
 2628         } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
 2629                 /*
 2630                  * First, parse out the PutFH and Getattr result.
 2631                  */
 2632                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2633                 if (!(*(tl + 1)))
 2634                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2635                 if (*(tl + 1))
 2636                         nd->nd_flag |= ND_NOMOREDATA;
 2637                 /*
 2638                  * Get the pre-op attributes.
 2639                  */
 2640                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2641         }
 2642         if (nd->nd_repstat && !error)
 2643                 error = nd->nd_repstat;
 2644 nfsmout:
 2645         mbuf_freem(nd->nd_mrep);
 2646         return (error);
 2647 }
 2648 
 2649 /*
 2650  * nfs symbolic link create rpc
 2651  */
 2652 int
 2653 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
 2654     struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 2655     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
 2656     int *dattrflagp, void *dstuff)
 2657 {
 2658         u_int32_t *tl;
 2659         struct nfsrv_descript nfsd, *nd = &nfsd;
 2660         struct nfsmount *nmp;
 2661         int slen, error = 0;
 2662 
 2663         *nfhpp = NULL;
 2664         *attrflagp = 0;
 2665         *dattrflagp = 0;
 2666         nmp = VFSTONFS(vnode_mount(dvp));
 2667         slen = strlen(target);
 2668         if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
 2669                 return (ENAMETOOLONG);
 2670         NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
 2671         if (nd->nd_flag & ND_NFSV4) {
 2672                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2673                 *tl = txdr_unsigned(NFLNK);
 2674                 (void) nfsm_strtom(nd, target, slen);
 2675         }
 2676         (void) nfsm_strtom(nd, name, namelen);
 2677         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
 2678                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2679         if (!(nd->nd_flag & ND_NFSV4))
 2680                 (void) nfsm_strtom(nd, target, slen);
 2681         if (nd->nd_flag & ND_NFSV2)
 2682                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
 2683         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2684         if (error)
 2685                 return (error);
 2686         if (nd->nd_flag & ND_NFSV4)
 2687                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2688         if ((nd->nd_flag & ND_NFSV3) && !error) {
 2689                 if (!nd->nd_repstat)
 2690                         error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 2691                 if (!error)
 2692                         error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
 2693                             NULL, dstuff);
 2694         }
 2695         if (nd->nd_repstat && !error)
 2696                 error = nd->nd_repstat;
 2697         mbuf_freem(nd->nd_mrep);
 2698         /*
 2699          * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
 2700          * Only do this if vfs.nfs.ignore_eexist is set.
 2701          * Never do this for NFSv4.1 or later minor versions, since sessions
 2702          * should guarantee "exactly once" RPC semantics.
 2703          */
 2704         if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
 2705             nmp->nm_minorvers == 0))
 2706                 error = 0;
 2707         return (error);
 2708 }
 2709 
 2710 /*
 2711  * nfs make dir rpc
 2712  */
 2713 int
 2714 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 2715     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 2716     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
 2717     int *dattrflagp, void *dstuff)
 2718 {
 2719         u_int32_t *tl;
 2720         struct nfsrv_descript nfsd, *nd = &nfsd;
 2721         nfsattrbit_t attrbits;
 2722         int error = 0;
 2723         struct nfsfh *fhp;
 2724         struct nfsmount *nmp;
 2725 
 2726         *nfhpp = NULL;
 2727         *attrflagp = 0;
 2728         *dattrflagp = 0;
 2729         nmp = VFSTONFS(vnode_mount(dvp));
 2730         fhp = VTONFS(dvp)->n_fhp;
 2731         if (namelen > NFS_MAXNAMLEN)
 2732                 return (ENAMETOOLONG);
 2733         NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
 2734         if (nd->nd_flag & ND_NFSV4) {
 2735                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2736                 *tl = txdr_unsigned(NFDIR);
 2737         }
 2738         (void) nfsm_strtom(nd, name, namelen);
 2739         nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
 2740         if (nd->nd_flag & ND_NFSV4) {
 2741                 NFSGETATTR_ATTRBIT(&attrbits);
 2742                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2743                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 2744                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2745                 (void) nfsrv_putattrbit(nd, &attrbits);
 2746                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2747                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2748                 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
 2749                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2750                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2751                 (void) nfsrv_putattrbit(nd, &attrbits);
 2752         }
 2753         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2754         if (error)
 2755                 return (error);
 2756         if (nd->nd_flag & ND_NFSV4)
 2757                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2758         if (!nd->nd_repstat && !error) {
 2759                 if (nd->nd_flag & ND_NFSV4) {
 2760                         NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 2761                         error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 2762                 }
 2763                 if (!error)
 2764                         error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 2765                 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
 2766                         /* Get rid of the PutFH and Getattr status values. */
 2767                         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 2768                         /* Load the directory attributes. */
 2769                         error = nfsm_loadattr(nd, dnap);
 2770                         if (error == 0)
 2771                                 *dattrflagp = 1;
 2772                 }
 2773         }
 2774         if ((nd->nd_flag & ND_NFSV3) && !error)
 2775                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2776         if (nd->nd_repstat && !error)
 2777                 error = nd->nd_repstat;
 2778 nfsmout:
 2779         mbuf_freem(nd->nd_mrep);
 2780         /*
 2781          * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
 2782          * Only do this if vfs.nfs.ignore_eexist is set.
 2783          * Never do this for NFSv4.1 or later minor versions, since sessions
 2784          * should guarantee "exactly once" RPC semantics.
 2785          */
 2786         if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
 2787             nmp->nm_minorvers == 0))
 2788                 error = 0;
 2789         return (error);
 2790 }
 2791 
 2792 /*
 2793  * nfs remove directory call
 2794  */
 2795 int
 2796 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
 2797     NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
 2798 {
 2799         struct nfsrv_descript nfsd, *nd = &nfsd;
 2800         int error = 0;
 2801 
 2802         *dattrflagp = 0;
 2803         if (namelen > NFS_MAXNAMLEN)
 2804                 return (ENAMETOOLONG);
 2805         NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
 2806         (void) nfsm_strtom(nd, name, namelen);
 2807         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2808         if (error)
 2809                 return (error);
 2810         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
 2811                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2812         if (nd->nd_repstat && !error)
 2813                 error = nd->nd_repstat;
 2814         mbuf_freem(nd->nd_mrep);
 2815         /*
 2816          * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
 2817          */
 2818         if (error == ENOENT)
 2819                 error = 0;
 2820         return (error);
 2821 }
 2822 
 2823 /*
 2824  * Readdir rpc.
 2825  * Always returns with either uio_resid unchanged, if you are at the
 2826  * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
 2827  * filled in.
 2828  * I felt this would allow caching of directory blocks more easily
 2829  * than returning a pertially filled block.
 2830  * Directory offset cookies:
 2831  * Oh my, what to do with them...
 2832  * I can think of three ways to deal with them:
 2833  * 1 - have the layer above these RPCs maintain a map between logical
 2834  *     directory byte offsets and the NFS directory offset cookies
 2835  * 2 - pass the opaque directory offset cookies up into userland
 2836  *     and let the libc functions deal with them, via the system call
 2837  * 3 - return them to userland in the "struct dirent", so future versions
 2838  *     of libc can use them and do whatever is necessary to make things work
 2839  *     above these rpc calls, in the meantime
 2840  * For now, I do #3 by "hiding" the directory offset cookies after the
 2841  * d_name field in struct dirent. This is space inside d_reclen that
 2842  * will be ignored by anything that doesn't know about them.
 2843  * The directory offset cookies are filled in as the last 8 bytes of
 2844  * each directory entry, after d_name. Someday, the userland libc
 2845  * functions may be able to use these. In the meantime, it satisfies
 2846  * OpenBSD's requirements for cookies being returned.
 2847  * If expects the directory offset cookie for the read to be in uio_offset
 2848  * and returns the one for the next entry after this directory block in
 2849  * there, as well.
 2850  */
 2851 int
 2852 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
 2853     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 2854     int *eofp, void *stuff)
 2855 {
 2856         int len, left;
 2857         struct dirent *dp = NULL;
 2858         u_int32_t *tl;
 2859         nfsquad_t cookie, ncookie;
 2860         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 2861         struct nfsnode *dnp = VTONFS(vp);
 2862         struct nfsvattr nfsva;
 2863         struct nfsrv_descript nfsd, *nd = &nfsd;
 2864         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
 2865         int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
 2866         u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
 2867         char *cp;
 2868         nfsattrbit_t attrbits, dattrbits;
 2869         u_int32_t rderr, *tl2 = NULL;
 2870         size_t tresid;
 2871 
 2872         KASSERT(uiop->uio_iovcnt == 1 &&
 2873             (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
 2874             ("nfs readdirrpc bad uio"));
 2875         ncookie.lval[0] = ncookie.lval[1] = 0;
 2876         /*
 2877          * There is no point in reading a lot more than uio_resid, however
 2878          * adding one additional DIRBLKSIZ makes sense. Since uio_resid
 2879          * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
 2880          * will never make readsize > nm_readdirsize.
 2881          */
 2882         readsize = nmp->nm_readdirsize;
 2883         if (readsize > uio_uio_resid(uiop))
 2884                 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
 2885 
 2886         *attrflagp = 0;
 2887         if (eofp)
 2888                 *eofp = 0;
 2889         tresid = uio_uio_resid(uiop);
 2890         cookie.lval[0] = cookiep->nfsuquad[0];
 2891         cookie.lval[1] = cookiep->nfsuquad[1];
 2892         nd->nd_mrep = NULL;
 2893 
 2894         /*
 2895          * For NFSv4, first create the "." and ".." entries.
 2896          */
 2897         if (NFSHASNFSV4(nmp)) {
 2898                 reqsize = 6 * NFSX_UNSIGNED;
 2899                 NFSGETATTR_ATTRBIT(&dattrbits);
 2900                 NFSZERO_ATTRBIT(&attrbits);
 2901                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
 2902                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
 2903                 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
 2904                     NFSATTRBIT_MOUNTEDONFILEID)) {
 2905                         NFSSETBIT_ATTRBIT(&attrbits,
 2906                             NFSATTRBIT_MOUNTEDONFILEID);
 2907                         gotmnton = 1;
 2908                 } else {
 2909                         /*
 2910                          * Must fake it. Use the fileno, except when the
 2911                          * fsid is != to that of the directory. For that
 2912                          * case, generate a fake fileno that is not the same.
 2913                          */
 2914                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
 2915                         gotmnton = 0;
 2916                 }
 2917 
 2918                 /*
 2919                  * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
 2920                  */
 2921                 if (uiop->uio_offset == 0) {
 2922                         NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
 2923                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2924                         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 2925                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2926                         (void) nfsrv_putattrbit(nd, &attrbits);
 2927                         error = nfscl_request(nd, vp, p, cred, stuff);
 2928                         if (error)
 2929                             return (error);
 2930                         dotfileid = 0;  /* Fake out the compiler. */
 2931                         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
 2932                             error = nfsm_loadattr(nd, &nfsva);
 2933                             if (error != 0)
 2934                                 goto nfsmout;
 2935                             dotfileid = nfsva.na_fileid;
 2936                         }
 2937                         if (nd->nd_repstat == 0) {
 2938                             NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 2939                             len = fxdr_unsigned(int, *(tl + 4));
 2940                             if (len > 0 && len <= NFSX_V4FHMAX)
 2941                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 2942                             else
 2943                                 error = EPERM;
 2944                             if (!error) {
 2945                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
 2946                                 nfsva.na_mntonfileno = UINT64_MAX;
 2947                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
 2948                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 2949                                     NULL, NULL, NULL, p, cred);
 2950                                 if (error) {
 2951                                     dotdotfileid = dotfileid;
 2952                                 } else if (gotmnton) {
 2953                                     if (nfsva.na_mntonfileno != UINT64_MAX)
 2954                                         dotdotfileid = nfsva.na_mntonfileno;
 2955                                     else
 2956                                         dotdotfileid = nfsva.na_fileid;
 2957                                 } else if (nfsva.na_filesid[0] ==
 2958                                     dnp->n_vattr.na_filesid[0] &&
 2959                                     nfsva.na_filesid[1] ==
 2960                                     dnp->n_vattr.na_filesid[1]) {
 2961                                     dotdotfileid = nfsva.na_fileid;
 2962                                 } else {
 2963                                     do {
 2964                                         fakefileno--;
 2965                                     } while (fakefileno ==
 2966                                         nfsva.na_fileid);
 2967                                     dotdotfileid = fakefileno;
 2968                                 }
 2969                             }
 2970                         } else if (nd->nd_repstat == NFSERR_NOENT) {
 2971                             /*
 2972                              * Lookupp returns NFSERR_NOENT when we are
 2973                              * at the root, so just use the current dir.
 2974                              */
 2975                             nd->nd_repstat = 0;
 2976                             dotdotfileid = dotfileid;
 2977                         } else {
 2978                             error = nd->nd_repstat;
 2979                         }
 2980                         mbuf_freem(nd->nd_mrep);
 2981                         if (error)
 2982                             return (error);
 2983                         nd->nd_mrep = NULL;
 2984                         dp = (struct dirent *)uio_iov_base(uiop);
 2985                         dp->d_pad0 = dp->d_pad1 = 0;
 2986                         dp->d_off = 0;
 2987                         dp->d_type = DT_DIR;
 2988                         dp->d_fileno = dotfileid;
 2989                         dp->d_namlen = 1;
 2990                         *((uint64_t *)dp->d_name) = 0;  /* Zero pad it. */
 2991                         dp->d_name[0] = '.';
 2992                         dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
 2993                         /*
 2994                          * Just make these offset cookie 0.
 2995                          */
 2996                         tl = (u_int32_t *)&dp->d_name[8];
 2997                         *tl++ = 0;
 2998                         *tl = 0;
 2999                         blksiz += dp->d_reclen;
 3000                         uio_uio_resid_add(uiop, -(dp->d_reclen));
 3001                         uiop->uio_offset += dp->d_reclen;
 3002                         uio_iov_base_add(uiop, dp->d_reclen);
 3003                         uio_iov_len_add(uiop, -(dp->d_reclen));
 3004                         dp = (struct dirent *)uio_iov_base(uiop);
 3005                         dp->d_pad0 = dp->d_pad1 = 0;
 3006                         dp->d_off = 0;
 3007                         dp->d_type = DT_DIR;
 3008                         dp->d_fileno = dotdotfileid;
 3009                         dp->d_namlen = 2;
 3010                         *((uint64_t *)dp->d_name) = 0;
 3011                         dp->d_name[0] = '.';
 3012                         dp->d_name[1] = '.';
 3013                         dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
 3014                         /*
 3015                          * Just make these offset cookie 0.
 3016                          */
 3017                         tl = (u_int32_t *)&dp->d_name[8];
 3018                         *tl++ = 0;
 3019                         *tl = 0;
 3020                         blksiz += dp->d_reclen;
 3021                         uio_uio_resid_add(uiop, -(dp->d_reclen));
 3022                         uiop->uio_offset += dp->d_reclen;
 3023                         uio_iov_base_add(uiop, dp->d_reclen);
 3024                         uio_iov_len_add(uiop, -(dp->d_reclen));
 3025                 }
 3026                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
 3027         } else {
 3028                 reqsize = 5 * NFSX_UNSIGNED;
 3029         }
 3030 
 3031 
 3032         /*
 3033          * Loop around doing readdir rpc's of size readsize.
 3034          * The stopping criteria is EOF or buffer full.
 3035          */
 3036         while (more_dirs && bigenough) {
 3037                 *attrflagp = 0;
 3038                 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
 3039                 if (nd->nd_flag & ND_NFSV2) {
 3040                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3041                         *tl++ = cookie.lval[1];
 3042                         *tl = txdr_unsigned(readsize);
 3043                 } else {
 3044                         NFSM_BUILD(tl, u_int32_t *, reqsize);
 3045                         *tl++ = cookie.lval[0];
 3046                         *tl++ = cookie.lval[1];
 3047                         if (cookie.qval == 0) {
 3048                                 *tl++ = 0;
 3049                                 *tl++ = 0;
 3050                         } else {
 3051                                 NFSLOCKNODE(dnp);
 3052                                 *tl++ = dnp->n_cookieverf.nfsuquad[0];
 3053                                 *tl++ = dnp->n_cookieverf.nfsuquad[1];
 3054                                 NFSUNLOCKNODE(dnp);
 3055                         }
 3056                         if (nd->nd_flag & ND_NFSV4) {
 3057                                 *tl++ = txdr_unsigned(readsize);
 3058                                 *tl = txdr_unsigned(readsize);
 3059                                 (void) nfsrv_putattrbit(nd, &attrbits);
 3060                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3061                                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 3062                                 (void) nfsrv_putattrbit(nd, &dattrbits);
 3063                         } else {
 3064                                 *tl = txdr_unsigned(readsize);
 3065                         }
 3066                 }
 3067                 error = nfscl_request(nd, vp, p, cred, stuff);
 3068                 if (error)
 3069                         return (error);
 3070                 if (!(nd->nd_flag & ND_NFSV2)) {
 3071                         if (nd->nd_flag & ND_NFSV3)
 3072                                 error = nfscl_postop_attr(nd, nap, attrflagp,
 3073                                     stuff);
 3074                         if (!nd->nd_repstat && !error) {
 3075                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 3076                                 NFSLOCKNODE(dnp);
 3077                                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
 3078                                 dnp->n_cookieverf.nfsuquad[1] = *tl;
 3079                                 NFSUNLOCKNODE(dnp);
 3080                         }
 3081                 }
 3082                 if (nd->nd_repstat || error) {
 3083                         if (!error)
 3084                                 error = nd->nd_repstat;
 3085                         goto nfsmout;
 3086                 }
 3087                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3088                 more_dirs = fxdr_unsigned(int, *tl);
 3089                 if (!more_dirs)
 3090                         tryformoredirs = 0;
 3091         
 3092                 /* loop through the dir entries, doctoring them to 4bsd form */
 3093                 while (more_dirs && bigenough) {
 3094                         if (nd->nd_flag & ND_NFSV4) {
 3095                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
 3096                                 ncookie.lval[0] = *tl++;
 3097                                 ncookie.lval[1] = *tl++;
 3098                                 len = fxdr_unsigned(int, *tl);
 3099                         } else if (nd->nd_flag & ND_NFSV3) {
 3100                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
 3101                                 nfsva.na_fileid = fxdr_hyper(tl);
 3102                                 tl += 2;
 3103                                 len = fxdr_unsigned(int, *tl);
 3104                         } else {
 3105                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
 3106                                 nfsva.na_fileid = fxdr_unsigned(uint64_t,
 3107                                     *tl++);
 3108                                 len = fxdr_unsigned(int, *tl);
 3109                         }
 3110                         if (len <= 0 || len > NFS_MAXNAMLEN) {
 3111                                 error = EBADRPC;
 3112                                 goto nfsmout;
 3113                         }
 3114                         tlen = roundup2(len, 8);
 3115                         if (tlen == len)
 3116                                 tlen += 8;  /* To ensure null termination. */
 3117                         left = DIRBLKSIZ - blksiz;
 3118                         if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
 3119                                 NFSBZERO(uio_iov_base(uiop), left);
 3120                                 dp->d_reclen += left;
 3121                                 uio_iov_base_add(uiop, left);
 3122                                 uio_iov_len_add(uiop, -(left));
 3123                                 uio_uio_resid_add(uiop, -(left));
 3124                                 uiop->uio_offset += left;
 3125                                 blksiz = 0;
 3126                         }
 3127                         if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
 3128                             uio_uio_resid(uiop))
 3129                                 bigenough = 0;
 3130                         if (bigenough) {
 3131                                 dp = (struct dirent *)uio_iov_base(uiop);
 3132                                 dp->d_pad0 = dp->d_pad1 = 0;
 3133                                 dp->d_off = 0;
 3134                                 dp->d_namlen = len;
 3135                                 dp->d_reclen = _GENERIC_DIRLEN(len) +
 3136                                     NFSX_HYPER;
 3137                                 dp->d_type = DT_UNKNOWN;
 3138                                 blksiz += dp->d_reclen;
 3139                                 if (blksiz == DIRBLKSIZ)
 3140                                         blksiz = 0;
 3141                                 uio_uio_resid_add(uiop, -(DIRHDSIZ));
 3142                                 uiop->uio_offset += DIRHDSIZ;
 3143                                 uio_iov_base_add(uiop, DIRHDSIZ);
 3144                                 uio_iov_len_add(uiop, -(DIRHDSIZ));
 3145                                 error = nfsm_mbufuio(nd, uiop, len);
 3146                                 if (error)
 3147                                         goto nfsmout;
 3148                                 cp = uio_iov_base(uiop);
 3149                                 tlen -= len;
 3150                                 NFSBZERO(cp, tlen);
 3151                                 cp += tlen;     /* points to cookie storage */
 3152                                 tl2 = (u_int32_t *)cp;
 3153                                 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
 3154                                 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
 3155                                 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
 3156                                 uiop->uio_offset += (tlen + NFSX_HYPER);
 3157                         } else {
 3158                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 3159                                 if (error)
 3160                                         goto nfsmout;
 3161                         }
 3162                         if (nd->nd_flag & ND_NFSV4) {
 3163                                 rderr = 0;
 3164                                 nfsva.na_mntonfileno = UINT64_MAX;
 3165                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
 3166                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 3167                                     NULL, NULL, &rderr, p, cred);
 3168                                 if (error)
 3169                                         goto nfsmout;
 3170                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3171                         } else if (nd->nd_flag & ND_NFSV3) {
 3172                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
 3173                                 ncookie.lval[0] = *tl++;
 3174                                 ncookie.lval[1] = *tl++;
 3175                         } else {
 3176                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
 3177                                 ncookie.lval[0] = 0;
 3178                                 ncookie.lval[1] = *tl++;
 3179                         }
 3180                         if (bigenough) {
 3181                             if (nd->nd_flag & ND_NFSV4) {
 3182                                 if (rderr) {
 3183                                     dp->d_fileno = 0;
 3184                                 } else {
 3185                                     if (gotmnton) {
 3186                                         if (nfsva.na_mntonfileno != UINT64_MAX)
 3187                                             dp->d_fileno = nfsva.na_mntonfileno;
 3188                                         else
 3189                                             dp->d_fileno = nfsva.na_fileid;
 3190                                     } else if (nfsva.na_filesid[0] ==
 3191                                         dnp->n_vattr.na_filesid[0] &&
 3192                                         nfsva.na_filesid[1] ==
 3193                                         dnp->n_vattr.na_filesid[1]) {
 3194                                         dp->d_fileno = nfsva.na_fileid;
 3195                                     } else {
 3196                                         do {
 3197                                             fakefileno--;
 3198                                         } while (fakefileno ==
 3199                                             nfsva.na_fileid);
 3200                                         dp->d_fileno = fakefileno;
 3201                                     }
 3202                                     dp->d_type = vtonfs_dtype(nfsva.na_type);
 3203                                 }
 3204                             } else {
 3205                                 dp->d_fileno = nfsva.na_fileid;
 3206                             }
 3207                             *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
 3208                                 ncookie.lval[0];
 3209                             *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
 3210                                 ncookie.lval[1];
 3211                         }
 3212                         more_dirs = fxdr_unsigned(int, *tl);
 3213                 }
 3214                 /*
 3215                  * If at end of rpc data, get the eof boolean
 3216                  */
 3217                 if (!more_dirs) {
 3218                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3219                         eof = fxdr_unsigned(int, *tl);
 3220                         if (tryformoredirs)
 3221                                 more_dirs = !eof;
 3222                         if (nd->nd_flag & ND_NFSV4) {
 3223                                 error = nfscl_postop_attr(nd, nap, attrflagp,
 3224                                     stuff);
 3225                                 if (error)
 3226                                         goto nfsmout;
 3227                         }
 3228                 }
 3229                 mbuf_freem(nd->nd_mrep);
 3230                 nd->nd_mrep = NULL;
 3231         }
 3232         /*
 3233          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
 3234          * by increasing d_reclen for the last record.
 3235          */
 3236         if (blksiz > 0) {
 3237                 left = DIRBLKSIZ - blksiz;
 3238                 NFSBZERO(uio_iov_base(uiop), left);
 3239                 dp->d_reclen += left;
 3240                 uio_iov_base_add(uiop, left);
 3241                 uio_iov_len_add(uiop, -(left));
 3242                 uio_uio_resid_add(uiop, -(left));
 3243                 uiop->uio_offset += left;
 3244         }
 3245 
 3246         /*
 3247          * If returning no data, assume end of file.
 3248          * If not bigenough, return not end of file, since you aren't
 3249          *    returning all the data
 3250          * Otherwise, return the eof flag from the server.
 3251          */
 3252         if (eofp) {
 3253                 if (tresid == ((size_t)(uio_uio_resid(uiop))))
 3254                         *eofp = 1;
 3255                 else if (!bigenough)
 3256                         *eofp = 0;
 3257                 else
 3258                         *eofp = eof;
 3259         }
 3260 
 3261         /*
 3262          * Add extra empty records to any remaining DIRBLKSIZ chunks.
 3263          */
 3264         while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
 3265                 dp = (struct dirent *)uio_iov_base(uiop);
 3266                 NFSBZERO(dp, DIRBLKSIZ);
 3267                 dp->d_type = DT_UNKNOWN;
 3268                 tl = (u_int32_t *)&dp->d_name[4];
 3269                 *tl++ = cookie.lval[0];
 3270                 *tl = cookie.lval[1];
 3271                 dp->d_reclen = DIRBLKSIZ;
 3272                 uio_iov_base_add(uiop, DIRBLKSIZ);
 3273                 uio_iov_len_add(uiop, -(DIRBLKSIZ));
 3274                 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
 3275                 uiop->uio_offset += DIRBLKSIZ;
 3276         }
 3277 
 3278 nfsmout:
 3279         if (nd->nd_mrep != NULL)
 3280                 mbuf_freem(nd->nd_mrep);
 3281         return (error);
 3282 }
 3283 
 3284 #ifndef APPLE
 3285 /*
 3286  * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
 3287  * (Also used for NFS V4 when mount flag set.)
 3288  * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
 3289  */
 3290 int
 3291 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
 3292     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 3293     int *eofp, void *stuff)
 3294 {
 3295         int len, left;
 3296         struct dirent *dp = NULL;
 3297         u_int32_t *tl;
 3298         vnode_t newvp = NULLVP;
 3299         struct nfsrv_descript nfsd, *nd = &nfsd;
 3300         struct nameidata nami, *ndp = &nami;
 3301         struct componentname *cnp = &ndp->ni_cnd;
 3302         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 3303         struct nfsnode *dnp = VTONFS(vp), *np;
 3304         struct nfsvattr nfsva;
 3305         struct nfsfh *nfhp;
 3306         nfsquad_t cookie, ncookie;
 3307         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
 3308         int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
 3309         int isdotdot = 0, unlocknewvp = 0;
 3310         u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
 3311         u_int64_t fileno = 0;
 3312         char *cp;
 3313         nfsattrbit_t attrbits, dattrbits;
 3314         size_t tresid;
 3315         u_int32_t *tl2 = NULL, rderr;
 3316         struct timespec dctime, ts;
 3317         bool attr_ok;
 3318 
 3319         KASSERT(uiop->uio_iovcnt == 1 &&
 3320             (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
 3321             ("nfs readdirplusrpc bad uio"));
 3322         ncookie.lval[0] = ncookie.lval[1] = 0;
 3323         timespecclear(&dctime);
 3324         *attrflagp = 0;
 3325         if (eofp != NULL)
 3326                 *eofp = 0;
 3327         ndp->ni_dvp = vp;
 3328         nd->nd_mrep = NULL;
 3329         cookie.lval[0] = cookiep->nfsuquad[0];
 3330         cookie.lval[1] = cookiep->nfsuquad[1];
 3331         tresid = uio_uio_resid(uiop);
 3332 
 3333         /*
 3334          * For NFSv4, first create the "." and ".." entries.
 3335          */
 3336         if (NFSHASNFSV4(nmp)) {
 3337                 NFSGETATTR_ATTRBIT(&dattrbits);
 3338                 NFSZERO_ATTRBIT(&attrbits);
 3339                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
 3340                 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
 3341                     NFSATTRBIT_MOUNTEDONFILEID)) {
 3342                         NFSSETBIT_ATTRBIT(&attrbits,
 3343                             NFSATTRBIT_MOUNTEDONFILEID);
 3344                         gotmnton = 1;
 3345                 } else {
 3346                         /*
 3347                          * Must fake it. Use the fileno, except when the
 3348                          * fsid is != to that of the directory. For that
 3349                          * case, generate a fake fileno that is not the same.
 3350                          */
 3351                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
 3352                         gotmnton = 0;
 3353                 }
 3354 
 3355                 /*
 3356                  * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
 3357                  */
 3358                 if (uiop->uio_offset == 0) {
 3359                         NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
 3360                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3361                         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 3362                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 3363                         (void) nfsrv_putattrbit(nd, &attrbits);
 3364                         error = nfscl_request(nd, vp, p, cred, stuff);
 3365                         if (error)
 3366                             return (error);
 3367                         dotfileid = 0;  /* Fake out the compiler. */
 3368                         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
 3369                             error = nfsm_loadattr(nd, &nfsva);
 3370                             if (error != 0)
 3371                                 goto nfsmout;
 3372                             dctime = nfsva.na_ctime;
 3373                             dotfileid = nfsva.na_fileid;
 3374                         }
 3375                         if (nd->nd_repstat == 0) {
 3376                             NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 3377                             len = fxdr_unsigned(int, *(tl + 4));
 3378                             if (len > 0 && len <= NFSX_V4FHMAX)
 3379                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 3380                             else
 3381                                 error = EPERM;
 3382                             if (!error) {
 3383                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
 3384                                 nfsva.na_mntonfileno = UINT64_MAX;
 3385                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
 3386                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 3387                                     NULL, NULL, NULL, p, cred);
 3388                                 if (error) {
 3389                                     dotdotfileid = dotfileid;
 3390                                 } else if (gotmnton) {
 3391                                     if (nfsva.na_mntonfileno != UINT64_MAX)
 3392                                         dotdotfileid = nfsva.na_mntonfileno;
 3393                                     else
 3394                                         dotdotfileid = nfsva.na_fileid;
 3395                                 } else if (nfsva.na_filesid[0] ==
 3396                                     dnp->n_vattr.na_filesid[0] &&
 3397                                     nfsva.na_filesid[1] ==
 3398                                     dnp->n_vattr.na_filesid[1]) {
 3399                                     dotdotfileid = nfsva.na_fileid;
 3400                                 } else {
 3401                                     do {
 3402                                         fakefileno--;
 3403                                     } while (fakefileno ==
 3404                                         nfsva.na_fileid);
 3405                                     dotdotfileid = fakefileno;
 3406                                 }
 3407                             }
 3408                         } else if (nd->nd_repstat == NFSERR_NOENT) {
 3409                             /*
 3410                              * Lookupp returns NFSERR_NOENT when we are
 3411                              * at the root, so just use the current dir.
 3412                              */
 3413                             nd->nd_repstat = 0;
 3414                             dotdotfileid = dotfileid;
 3415                         } else {
 3416                             error = nd->nd_repstat;
 3417                         }
 3418                         mbuf_freem(nd->nd_mrep);
 3419                         if (error)
 3420                             return (error);
 3421                         nd->nd_mrep = NULL;
 3422                         dp = (struct dirent *)uio_iov_base(uiop);
 3423                         dp->d_pad0 = dp->d_pad1 = 0;
 3424                         dp->d_off = 0;
 3425                         dp->d_type = DT_DIR;
 3426                         dp->d_fileno = dotfileid;
 3427                         dp->d_namlen = 1;
 3428                         *((uint64_t *)dp->d_name) = 0;  /* Zero pad it. */
 3429                         dp->d_name[0] = '.';
 3430                         dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
 3431                         /*
 3432                          * Just make these offset cookie 0.
 3433                          */
 3434                         tl = (u_int32_t *)&dp->d_name[8];
 3435                         *tl++ = 0;
 3436                         *tl = 0;
 3437                         blksiz += dp->d_reclen;
 3438                         uio_uio_resid_add(uiop, -(dp->d_reclen));
 3439                         uiop->uio_offset += dp->d_reclen;
 3440                         uio_iov_base_add(uiop, dp->d_reclen);
 3441                         uio_iov_len_add(uiop, -(dp->d_reclen));
 3442                         dp = (struct dirent *)uio_iov_base(uiop);
 3443                         dp->d_pad0 = dp->d_pad1 = 0;
 3444                         dp->d_off = 0;
 3445                         dp->d_type = DT_DIR;
 3446                         dp->d_fileno = dotdotfileid;
 3447                         dp->d_namlen = 2;
 3448                         *((uint64_t *)dp->d_name) = 0;
 3449                         dp->d_name[0] = '.';
 3450                         dp->d_name[1] = '.';
 3451                         dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
 3452                         /*
 3453                          * Just make these offset cookie 0.
 3454                          */
 3455                         tl = (u_int32_t *)&dp->d_name[8];
 3456                         *tl++ = 0;
 3457                         *tl = 0;
 3458                         blksiz += dp->d_reclen;
 3459                         uio_uio_resid_add(uiop, -(dp->d_reclen));
 3460                         uiop->uio_offset += dp->d_reclen;
 3461                         uio_iov_base_add(uiop, dp->d_reclen);
 3462                         uio_iov_len_add(uiop, -(dp->d_reclen));
 3463                 }
 3464                 NFSREADDIRPLUS_ATTRBIT(&attrbits);
 3465                 if (gotmnton)
 3466                         NFSSETBIT_ATTRBIT(&attrbits,
 3467                             NFSATTRBIT_MOUNTEDONFILEID);
 3468         }
 3469 
 3470         /*
 3471          * Loop around doing readdir rpc's of size nm_readdirsize.
 3472          * The stopping criteria is EOF or buffer full.
 3473          */
 3474         while (more_dirs && bigenough) {
 3475                 *attrflagp = 0;
 3476                 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
 3477                 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
 3478                 *tl++ = cookie.lval[0];
 3479                 *tl++ = cookie.lval[1];
 3480                 if (cookie.qval == 0) {
 3481                         *tl++ = 0;
 3482                         *tl++ = 0;
 3483                 } else {
 3484                         NFSLOCKNODE(dnp);
 3485                         *tl++ = dnp->n_cookieverf.nfsuquad[0];
 3486                         *tl++ = dnp->n_cookieverf.nfsuquad[1];
 3487                         NFSUNLOCKNODE(dnp);
 3488                 }
 3489                 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
 3490                 *tl = txdr_unsigned(nmp->nm_readdirsize);
 3491                 if (nd->nd_flag & ND_NFSV4) {
 3492                         (void) nfsrv_putattrbit(nd, &attrbits);
 3493                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3494                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 3495                         (void) nfsrv_putattrbit(nd, &dattrbits);
 3496                 }
 3497                 nanouptime(&ts);
 3498                 error = nfscl_request(nd, vp, p, cred, stuff);
 3499                 if (error)
 3500                         return (error);
 3501                 if (nd->nd_flag & ND_NFSV3)
 3502                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 3503                 if (nd->nd_repstat || error) {
 3504                         if (!error)
 3505                                 error = nd->nd_repstat;
 3506                         goto nfsmout;
 3507                 }
 3508                 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
 3509                         dctime = nap->na_ctime;
 3510                 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3511                 NFSLOCKNODE(dnp);
 3512                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
 3513                 dnp->n_cookieverf.nfsuquad[1] = *tl++;
 3514                 NFSUNLOCKNODE(dnp);
 3515                 more_dirs = fxdr_unsigned(int, *tl);
 3516                 if (!more_dirs)
 3517                         tryformoredirs = 0;
 3518         
 3519                 /* loop through the dir entries, doctoring them to 4bsd form */
 3520                 while (more_dirs && bigenough) {
 3521                         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3522                         if (nd->nd_flag & ND_NFSV4) {
 3523                                 ncookie.lval[0] = *tl++;
 3524                                 ncookie.lval[1] = *tl++;
 3525                         } else {
 3526                                 fileno = fxdr_hyper(tl);
 3527                                 tl += 2;
 3528                         }
 3529                         len = fxdr_unsigned(int, *tl);
 3530                         if (len <= 0 || len > NFS_MAXNAMLEN) {
 3531                                 error = EBADRPC;
 3532                                 goto nfsmout;
 3533                         }
 3534                         tlen = roundup2(len, 8);
 3535                         if (tlen == len)
 3536                                 tlen += 8;  /* To ensure null termination. */
 3537                         left = DIRBLKSIZ - blksiz;
 3538                         if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
 3539                                 NFSBZERO(uio_iov_base(uiop), left);
 3540                                 dp->d_reclen += left;
 3541                                 uio_iov_base_add(uiop, left);
 3542                                 uio_iov_len_add(uiop, -(left));
 3543                                 uio_uio_resid_add(uiop, -(left));
 3544                                 uiop->uio_offset += left;
 3545                                 blksiz = 0;
 3546                         }
 3547                         if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
 3548                             uio_uio_resid(uiop))
 3549                                 bigenough = 0;
 3550                         if (bigenough) {
 3551                                 dp = (struct dirent *)uio_iov_base(uiop);
 3552                                 dp->d_pad0 = dp->d_pad1 = 0;
 3553                                 dp->d_off = 0;
 3554                                 dp->d_namlen = len;
 3555                                 dp->d_reclen = _GENERIC_DIRLEN(len) +
 3556                                     NFSX_HYPER;
 3557                                 dp->d_type = DT_UNKNOWN;
 3558                                 blksiz += dp->d_reclen;
 3559                                 if (blksiz == DIRBLKSIZ)
 3560                                         blksiz = 0;
 3561                                 uio_uio_resid_add(uiop, -(DIRHDSIZ));
 3562                                 uiop->uio_offset += DIRHDSIZ;
 3563                                 uio_iov_base_add(uiop, DIRHDSIZ);
 3564                                 uio_iov_len_add(uiop, -(DIRHDSIZ));
 3565                                 cnp->cn_nameptr = uio_iov_base(uiop);
 3566                                 cnp->cn_namelen = len;
 3567                                 NFSCNHASHZERO(cnp);
 3568                                 error = nfsm_mbufuio(nd, uiop, len);
 3569                                 if (error)
 3570                                         goto nfsmout;
 3571                                 cp = uio_iov_base(uiop);
 3572                                 tlen -= len;
 3573                                 NFSBZERO(cp, tlen);
 3574                                 cp += tlen;     /* points to cookie storage */
 3575                                 tl2 = (u_int32_t *)cp;
 3576                                 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
 3577                                     cnp->cn_nameptr[1] == '.')
 3578                                         isdotdot = 1;
 3579                                 else
 3580                                         isdotdot = 0;
 3581                                 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
 3582                                 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
 3583                                 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
 3584                                 uiop->uio_offset += (tlen + NFSX_HYPER);
 3585                         } else {
 3586                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 3587                                 if (error)
 3588                                         goto nfsmout;
 3589                         }
 3590                         nfhp = NULL;
 3591                         if (nd->nd_flag & ND_NFSV3) {
 3592                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
 3593                                 ncookie.lval[0] = *tl++;
 3594                                 ncookie.lval[1] = *tl++;
 3595                                 attrflag = fxdr_unsigned(int, *tl);
 3596                                 if (attrflag) {
 3597                                   error = nfsm_loadattr(nd, &nfsva);
 3598                                   if (error)
 3599                                         goto nfsmout;
 3600                                 }
 3601                                 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
 3602                                 if (*tl) {
 3603                                         error = nfsm_getfh(nd, &nfhp);
 3604                                         if (error)
 3605                                             goto nfsmout;
 3606                                 }
 3607                                 if (!attrflag && nfhp != NULL) {
 3608                                         free(nfhp, M_NFSFH);
 3609                                         nfhp = NULL;
 3610                                 }
 3611                         } else {
 3612                                 rderr = 0;
 3613                                 nfsva.na_mntonfileno = 0xffffffff;
 3614                                 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
 3615                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 3616                                     NULL, NULL, &rderr, p, cred);
 3617                                 if (error)
 3618                                         goto nfsmout;
 3619                         }
 3620 
 3621                         if (bigenough) {
 3622                             if (nd->nd_flag & ND_NFSV4) {
 3623                                 if (rderr) {
 3624                                     dp->d_fileno = 0;
 3625                                 } else if (gotmnton) {
 3626                                     if (nfsva.na_mntonfileno != 0xffffffff)
 3627                                         dp->d_fileno = nfsva.na_mntonfileno;
 3628                                     else
 3629                                         dp->d_fileno = nfsva.na_fileid;
 3630                                 } else if (nfsva.na_filesid[0] ==
 3631                                     dnp->n_vattr.na_filesid[0] &&
 3632                                     nfsva.na_filesid[1] ==
 3633                                     dnp->n_vattr.na_filesid[1]) {
 3634                                     dp->d_fileno = nfsva.na_fileid;
 3635                                 } else {
 3636                                     do {
 3637                                         fakefileno--;
 3638                                     } while (fakefileno ==
 3639                                         nfsva.na_fileid);
 3640                                     dp->d_fileno = fakefileno;
 3641                                 }
 3642                             } else {
 3643                                 dp->d_fileno = fileno;
 3644                             }
 3645                             *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
 3646                                 ncookie.lval[0];
 3647                             *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
 3648                                 ncookie.lval[1];
 3649 
 3650                             if (nfhp != NULL) {
 3651                                 attr_ok = true;
 3652                                 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
 3653                                     dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
 3654                                     VREF(vp);
 3655                                     newvp = vp;
 3656                                     unlocknewvp = 0;
 3657                                     free(nfhp, M_NFSFH);
 3658                                     np = dnp;
 3659                                 } else if (isdotdot != 0) {
 3660                                     /*
 3661                                      * Skip doing a nfscl_nget() call for "..".
 3662                                      * There's a race between acquiring the nfs
 3663                                      * node here and lookups that look for the
 3664                                      * directory being read (in the parent).
 3665                                      * It would try to get a lock on ".." here,
 3666                                      * owning the lock on the directory being
 3667                                      * read. Lookup will hold the lock on ".."
 3668                                      * and try to acquire the lock on the
 3669                                      * directory being read.
 3670                                      * If the directory is unlocked/relocked,
 3671                                      * then there is a LOR with the buflock
 3672                                      * vp is relocked.
 3673                                      */
 3674                                     free(nfhp, M_NFSFH);
 3675                                 } else {
 3676                                     error = nfscl_nget(vnode_mount(vp), vp,
 3677                                       nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
 3678                                     if (!error) {
 3679                                         newvp = NFSTOV(np);
 3680                                         unlocknewvp = 1;
 3681                                         /*
 3682                                          * If n_localmodtime >= time before RPC,
 3683                                          * then a file modification operation,
 3684                                          * such as VOP_SETATTR() of size, has
 3685                                          * occurred while the Lookup RPC and
 3686                                          * acquisition of the vnode happened. As
 3687                                          * such, the attributes might be stale,
 3688                                          * with possibly an incorrect size.
 3689                                          */
 3690                                         NFSLOCKNODE(np);
 3691                                         if (timespecisset(
 3692                                             &np->n_localmodtime) &&
 3693                                             timespeccmp(&np->n_localmodtime,
 3694                                             &ts, >=)) {
 3695                                             NFSCL_DEBUG(4, "nfsrpc_readdirplus:"
 3696                                                 " localmod stale attributes\n");
 3697                                             attr_ok = false;
 3698                                         }
 3699                                         NFSUNLOCKNODE(np);
 3700                                     }
 3701                                 }
 3702                                 nfhp = NULL;
 3703                                 if (newvp != NULLVP) {
 3704                                     if (attr_ok)
 3705                                         error = nfscl_loadattrcache(&newvp,
 3706                                             &nfsva, NULL, NULL, 0, 0);
 3707                                     if (error) {
 3708                                         if (unlocknewvp)
 3709                                             vput(newvp);
 3710                                         else
 3711                                             vrele(newvp);
 3712                                         goto nfsmout;
 3713                                     }
 3714                                     dp->d_type =
 3715                                         vtonfs_dtype(np->n_vattr.na_type);
 3716                                     ndp->ni_vp = newvp;
 3717                                     NFSCNHASH(cnp, HASHINIT);
 3718                                     if (cnp->cn_namelen <= NCHNAMLEN &&
 3719                                         ndp->ni_dvp != ndp->ni_vp &&
 3720                                         (newvp->v_type != VDIR ||
 3721                                          dctime.tv_sec != 0)) {
 3722                                         cache_enter_time(ndp->ni_dvp,
 3723                                             ndp->ni_vp, cnp,
 3724                                             &nfsva.na_ctime,
 3725                                             newvp->v_type != VDIR ? NULL :
 3726                                             &dctime);
 3727                                     }
 3728                                     if (unlocknewvp)
 3729                                         vput(newvp);
 3730                                     else
 3731                                         vrele(newvp);
 3732                                     newvp = NULLVP;
 3733                                 }
 3734                             }
 3735                         } else if (nfhp != NULL) {
 3736                             free(nfhp, M_NFSFH);
 3737                         }
 3738                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3739                         more_dirs = fxdr_unsigned(int, *tl);
 3740                 }
 3741                 /*
 3742                  * If at end of rpc data, get the eof boolean
 3743                  */
 3744                 if (!more_dirs) {
 3745                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3746                         eof = fxdr_unsigned(int, *tl);
 3747                         if (tryformoredirs)
 3748                                 more_dirs = !eof;
 3749                         if (nd->nd_flag & ND_NFSV4) {
 3750                                 error = nfscl_postop_attr(nd, nap, attrflagp,
 3751                                     stuff);
 3752                                 if (error)
 3753                                         goto nfsmout;
 3754                         }
 3755                 }
 3756                 mbuf_freem(nd->nd_mrep);
 3757                 nd->nd_mrep = NULL;
 3758         }
 3759         /*
 3760          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
 3761          * by increasing d_reclen for the last record.
 3762          */
 3763         if (blksiz > 0) {
 3764                 left = DIRBLKSIZ - blksiz;
 3765                 NFSBZERO(uio_iov_base(uiop), left);
 3766                 dp->d_reclen += left;
 3767                 uio_iov_base_add(uiop, left);
 3768                 uio_iov_len_add(uiop, -(left));
 3769                 uio_uio_resid_add(uiop, -(left));
 3770                 uiop->uio_offset += left;
 3771         }
 3772 
 3773         /*
 3774          * If returning no data, assume end of file.
 3775          * If not bigenough, return not end of file, since you aren't
 3776          *    returning all the data
 3777          * Otherwise, return the eof flag from the server.
 3778          */
 3779         if (eofp != NULL) {
 3780                 if (tresid == uio_uio_resid(uiop))
 3781                         *eofp = 1;
 3782                 else if (!bigenough)
 3783                         *eofp = 0;
 3784                 else
 3785                         *eofp = eof;
 3786         }
 3787 
 3788         /*
 3789          * Add extra empty records to any remaining DIRBLKSIZ chunks.
 3790          */
 3791         while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
 3792                 dp = (struct dirent *)uio_iov_base(uiop);
 3793                 NFSBZERO(dp, DIRBLKSIZ);
 3794                 dp->d_type = DT_UNKNOWN;
 3795                 tl = (u_int32_t *)&dp->d_name[4];
 3796                 *tl++ = cookie.lval[0];
 3797                 *tl = cookie.lval[1];
 3798                 dp->d_reclen = DIRBLKSIZ;
 3799                 uio_iov_base_add(uiop, DIRBLKSIZ);
 3800                 uio_iov_len_add(uiop, -(DIRBLKSIZ));
 3801                 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
 3802                 uiop->uio_offset += DIRBLKSIZ;
 3803         }
 3804 
 3805 nfsmout:
 3806         if (nd->nd_mrep != NULL)
 3807                 mbuf_freem(nd->nd_mrep);
 3808         return (error);
 3809 }
 3810 #endif  /* !APPLE */
 3811 
 3812 /*
 3813  * Nfs commit rpc
 3814  */
 3815 int
 3816 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
 3817     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 3818 {
 3819         u_int32_t *tl;
 3820         struct nfsrv_descript nfsd, *nd = &nfsd;
 3821         nfsattrbit_t attrbits;
 3822         int error;
 3823         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 3824         
 3825         *attrflagp = 0;
 3826         NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
 3827         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3828         txdr_hyper(offset, tl);
 3829         tl += 2;
 3830         *tl = txdr_unsigned(cnt);
 3831         if (nd->nd_flag & ND_NFSV4) {
 3832                 /*
 3833                  * And do a Getattr op.
 3834                  */
 3835                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3836                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 3837                 NFSGETATTR_ATTRBIT(&attrbits);
 3838                 (void) nfsrv_putattrbit(nd, &attrbits);
 3839         }
 3840         error = nfscl_request(nd, vp, p, cred, stuff);
 3841         if (error)
 3842                 return (error);
 3843         error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
 3844         if (!error && !nd->nd_repstat) {
 3845                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 3846                 NFSLOCKMNT(nmp);
 3847                 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
 3848                         NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
 3849                         nd->nd_repstat = NFSERR_STALEWRITEVERF;
 3850                 }
 3851                 NFSUNLOCKMNT(nmp);
 3852                 if (nd->nd_flag & ND_NFSV4)
 3853                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 3854         }
 3855 nfsmout:
 3856         if (!error && nd->nd_repstat)
 3857                 error = nd->nd_repstat;
 3858         mbuf_freem(nd->nd_mrep);
 3859         return (error);
 3860 }
 3861 
 3862 /*
 3863  * NFS byte range lock rpc.
 3864  * (Mostly just calls one of the three lower level RPC routines.)
 3865  */
 3866 int
 3867 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
 3868     int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
 3869 {
 3870         struct nfscllockowner *lp;
 3871         struct nfsclclient *clp;
 3872         struct nfsfh *nfhp;
 3873         struct nfsrv_descript nfsd, *nd = &nfsd;
 3874         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 3875         u_int64_t off, len;
 3876         off_t start, end;
 3877         u_int32_t clidrev = 0;
 3878         int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
 3879         int callcnt, dorpc;
 3880 
 3881         /*
 3882          * Convert the flock structure into a start and end and do POSIX
 3883          * bounds checking.
 3884          */
 3885         switch (fl->l_whence) {
 3886         case SEEK_SET:
 3887         case SEEK_CUR:
 3888                 /*
 3889                  * Caller is responsible for adding any necessary offset
 3890                  * when SEEK_CUR is used.
 3891                  */
 3892                 start = fl->l_start;
 3893                 off = fl->l_start;
 3894                 break;
 3895         case SEEK_END:
 3896                 start = size + fl->l_start;
 3897                 off = size + fl->l_start;
 3898                 break;
 3899         default:
 3900                 return (EINVAL);
 3901         }
 3902         if (start < 0)
 3903                 return (EINVAL);
 3904         if (fl->l_len != 0) {
 3905                 end = start + fl->l_len - 1;
 3906                 if (end < start)
 3907                         return (EINVAL);
 3908         }
 3909 
 3910         len = fl->l_len;
 3911         if (len == 0)
 3912                 len = NFS64BITSSET;
 3913         retrycnt = 0;
 3914         do {
 3915             nd->nd_repstat = 0;
 3916             if (op == F_GETLK) {
 3917                 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, true, &clp);
 3918                 if (error)
 3919                         return (error);
 3920                 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
 3921                 if (!error) {
 3922                         clidrev = clp->nfsc_clientidrev;
 3923                         error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
 3924                             p, id, flags);
 3925                 } else if (error == -1) {
 3926                         error = 0;
 3927                 }
 3928                 nfscl_clientrelease(clp);
 3929             } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
 3930                 /*
 3931                  * We must loop around for all lockowner cases.
 3932                  */
 3933                 callcnt = 0;
 3934                 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, true, &clp);
 3935                 if (error)
 3936                         return (error);
 3937                 do {
 3938                     error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
 3939                         clp, id, flags, &lp, &dorpc);
 3940                     /*
 3941                      * If it returns a NULL lp, we're done.
 3942                      */
 3943                     if (lp == NULL) {
 3944                         if (callcnt == 0)
 3945                             nfscl_clientrelease(clp);
 3946                         else
 3947                             nfscl_releasealllocks(clp, vp, p, id, flags);
 3948                         return (error);
 3949                     }
 3950                     if (nmp->nm_clp != NULL)
 3951                         clidrev = nmp->nm_clp->nfsc_clientidrev;
 3952                     else
 3953                         clidrev = 0;
 3954                     /*
 3955                      * If the server doesn't support Posix lock semantics,
 3956                      * only allow locks on the entire file, since it won't
 3957                      * handle overlapping byte ranges.
 3958                      * There might still be a problem when a lock
 3959                      * upgrade/downgrade (read<->write) occurs, since the
 3960                      * server "might" expect an unlock first?
 3961                      */
 3962                     if (dorpc && (lp->nfsl_open->nfso_posixlock ||
 3963                         (off == 0 && len == NFS64BITSSET))) {
 3964                         /*
 3965                          * Since the lock records will go away, we must
 3966                          * wait for grace and delay here.
 3967                          */
 3968                         do {
 3969                             error = nfsrpc_locku(nd, nmp, lp, off, len,
 3970                                 NFSV4LOCKT_READ, cred, p, 0);
 3971                             if ((nd->nd_repstat == NFSERR_GRACE ||
 3972                                  nd->nd_repstat == NFSERR_DELAY) &&
 3973                                 error == 0)
 3974                                 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
 3975                                     "nfs_advlock");
 3976                         } while ((nd->nd_repstat == NFSERR_GRACE ||
 3977                             nd->nd_repstat == NFSERR_DELAY) && error == 0);
 3978                     }
 3979                     callcnt++;
 3980                 } while (error == 0 && nd->nd_repstat == 0);
 3981                 nfscl_releasealllocks(clp, vp, p, id, flags);
 3982             } else if (op == F_SETLK) {
 3983                 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
 3984                     NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
 3985                 if (error || donelocally) {
 3986                         return (error);
 3987                 }
 3988                 if (nmp->nm_clp != NULL)
 3989                         clidrev = nmp->nm_clp->nfsc_clientidrev;
 3990                 else
 3991                         clidrev = 0;
 3992                 nfhp = VTONFS(vp)->n_fhp;
 3993                 if (!lp->nfsl_open->nfso_posixlock &&
 3994                     (off != 0 || len != NFS64BITSSET)) {
 3995                         error = EINVAL;
 3996                 } else {
 3997                         error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
 3998                             nfhp->nfh_len, lp, newone, reclaim, off,
 3999                             len, fl->l_type, cred, p, 0);
 4000                 }
 4001                 if (!error)
 4002                         error = nd->nd_repstat;
 4003                 nfscl_lockrelease(lp, error, newone);
 4004             } else {
 4005                 error = EINVAL;
 4006             }
 4007             if (!error)
 4008                 error = nd->nd_repstat;
 4009             if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 4010                 error == NFSERR_STALEDONTRECOVER ||
 4011                 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
 4012                 error == NFSERR_BADSESSION) {
 4013                 (void) nfs_catnap(PZERO, error, "nfs_advlock");
 4014             } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
 4015                 && clidrev != 0) {
 4016                 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 4017                 retrycnt++;
 4018             }
 4019         } while (error == NFSERR_GRACE ||
 4020             error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
 4021             error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
 4022             error == NFSERR_BADSESSION ||
 4023             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 4024              expireret == 0 && clidrev != 0 && retrycnt < 4));
 4025         if (error && retrycnt >= 4)
 4026                 error = EIO;
 4027         return (error);
 4028 }
 4029 
 4030 /*
 4031  * The lower level routine for the LockT case.
 4032  */
 4033 int
 4034 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
 4035     struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
 4036     struct ucred *cred, NFSPROC_T *p, void *id, int flags)
 4037 {
 4038         u_int32_t *tl;
 4039         int error, type, size;
 4040         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
 4041         struct nfsnode *np;
 4042         struct nfsmount *nmp;
 4043         struct nfsclsession *tsep;
 4044 
 4045         nmp = VFSTONFS(vp->v_mount);
 4046         NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
 4047         NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 4048         if (fl->l_type == F_RDLCK)
 4049                 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 4050         else
 4051                 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 4052         txdr_hyper(off, tl);
 4053         tl += 2;
 4054         txdr_hyper(len, tl);
 4055         tl += 2;
 4056         tsep = nfsmnt_mdssession(nmp);
 4057         *tl++ = tsep->nfsess_clientid.lval[0];
 4058         *tl = tsep->nfsess_clientid.lval[1];
 4059         nfscl_filllockowner(id, own, flags);
 4060         np = VTONFS(vp);
 4061         NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
 4062             np->n_fhp->nfh_len);
 4063         (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
 4064         error = nfscl_request(nd, vp, p, cred, NULL);
 4065         if (error)
 4066                 return (error);
 4067         if (nd->nd_repstat == 0) {
 4068                 fl->l_type = F_UNLCK;
 4069         } else if (nd->nd_repstat == NFSERR_DENIED) {
 4070                 nd->nd_repstat = 0;
 4071                 fl->l_whence = SEEK_SET;
 4072                 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
 4073                 fl->l_start = fxdr_hyper(tl);
 4074                 tl += 2;
 4075                 len = fxdr_hyper(tl);
 4076                 tl += 2;
 4077                 if (len == NFS64BITSSET)
 4078                         fl->l_len = 0;
 4079                 else
 4080                         fl->l_len = len;
 4081                 type = fxdr_unsigned(int, *tl++);
 4082                 if (type == NFSV4LOCKT_WRITE)
 4083                         fl->l_type = F_WRLCK;
 4084                 else
 4085                         fl->l_type = F_RDLCK;
 4086                 /*
 4087                  * XXX For now, I have no idea what to do with the
 4088                  * conflicting lock_owner, so I'll just set the pid == 0
 4089                  * and skip over the lock_owner.
 4090                  */
 4091                 fl->l_pid = (pid_t)0;
 4092                 tl += 2;
 4093                 size = fxdr_unsigned(int, *tl);
 4094                 if (size < 0 || size > NFSV4_OPAQUELIMIT)
 4095                         error = EBADRPC;
 4096                 if (!error)
 4097                         error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
 4098         } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
 4099                 nfscl_initiate_recovery(clp);
 4100 nfsmout:
 4101         mbuf_freem(nd->nd_mrep);
 4102         return (error);
 4103 }
 4104 
 4105 /*
 4106  * Lower level function that performs the LockU RPC.
 4107  */
 4108 static int
 4109 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
 4110     struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
 4111     u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
 4112 {
 4113         u_int32_t *tl;
 4114         int error;
 4115 
 4116         nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
 4117             lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0);
 4118         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
 4119         *tl++ = txdr_unsigned(type);
 4120         *tl = txdr_unsigned(lp->nfsl_seqid);
 4121         if (nfstest_outofseq &&
 4122             (arc4random() % nfstest_outofseq) == 0)
 4123                 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
 4124         tl++;
 4125         if (NFSHASNFSV4N(nmp))
 4126                 *tl++ = 0;
 4127         else
 4128                 *tl++ = lp->nfsl_stateid.seqid;
 4129         *tl++ = lp->nfsl_stateid.other[0];
 4130         *tl++ = lp->nfsl_stateid.other[1];
 4131         *tl++ = lp->nfsl_stateid.other[2];
 4132         txdr_hyper(off, tl);
 4133         tl += 2;
 4134         txdr_hyper(len, tl);
 4135         if (syscred)
 4136                 nd->nd_flag |= ND_USEGSSNAME;
 4137         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4138             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4139         NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
 4140         if (error)
 4141                 return (error);
 4142         if (nd->nd_repstat == 0) {
 4143                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 4144                 lp->nfsl_stateid.seqid = *tl++;
 4145                 lp->nfsl_stateid.other[0] = *tl++;
 4146                 lp->nfsl_stateid.other[1] = *tl++;
 4147                 lp->nfsl_stateid.other[2] = *tl;
 4148         } else if (nd->nd_repstat == NFSERR_STALESTATEID)
 4149                 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
 4150 nfsmout:
 4151         mbuf_freem(nd->nd_mrep);
 4152         return (error);
 4153 }
 4154 
 4155 /*
 4156  * The actual Lock RPC.
 4157  */
 4158 int
 4159 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
 4160     u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
 4161     int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
 4162     NFSPROC_T *p, int syscred)
 4163 {
 4164         u_int32_t *tl;
 4165         int error, size;
 4166         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
 4167         struct nfsclsession *tsep;
 4168 
 4169         nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0);
 4170         NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 4171         if (type == F_RDLCK)
 4172                 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 4173         else
 4174                 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 4175         *tl++ = txdr_unsigned(reclaim);
 4176         txdr_hyper(off, tl);
 4177         tl += 2;
 4178         txdr_hyper(len, tl);
 4179         tl += 2;
 4180         if (newone) {
 4181             *tl = newnfs_true;
 4182             NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
 4183                 2 * NFSX_UNSIGNED + NFSX_HYPER);
 4184             *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
 4185             if (NFSHASNFSV4N(nmp))
 4186                 *tl++ = 0;
 4187             else
 4188                 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
 4189             *tl++ = lp->nfsl_open->nfso_stateid.other[0];
 4190             *tl++ = lp->nfsl_open->nfso_stateid.other[1];
 4191             *tl++ = lp->nfsl_open->nfso_stateid.other[2];
 4192             *tl++ = txdr_unsigned(lp->nfsl_seqid);
 4193             tsep = nfsmnt_mdssession(nmp);
 4194             *tl++ = tsep->nfsess_clientid.lval[0];
 4195             *tl = tsep->nfsess_clientid.lval[1];
 4196             NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
 4197             NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
 4198             (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
 4199         } else {
 4200             *tl = newnfs_false;
 4201             NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 4202             if (NFSHASNFSV4N(nmp))
 4203                 *tl++ = 0;
 4204             else
 4205                 *tl++ = lp->nfsl_stateid.seqid;
 4206             *tl++ = lp->nfsl_stateid.other[0];
 4207             *tl++ = lp->nfsl_stateid.other[1];
 4208             *tl++ = lp->nfsl_stateid.other[2];
 4209             *tl = txdr_unsigned(lp->nfsl_seqid);
 4210             if (nfstest_outofseq &&
 4211                 (arc4random() % nfstest_outofseq) == 0)
 4212                     *tl = txdr_unsigned(lp->nfsl_seqid + 1);
 4213         }
 4214         if (syscred)
 4215                 nd->nd_flag |= ND_USEGSSNAME;
 4216         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
 4217             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4218         if (error)
 4219                 return (error);
 4220         if (newone)
 4221             NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
 4222         NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
 4223         if (nd->nd_repstat == 0) {
 4224                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 4225                 lp->nfsl_stateid.seqid = *tl++;
 4226                 lp->nfsl_stateid.other[0] = *tl++;
 4227                 lp->nfsl_stateid.other[1] = *tl++;
 4228                 lp->nfsl_stateid.other[2] = *tl;
 4229         } else if (nd->nd_repstat == NFSERR_DENIED) {
 4230                 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
 4231                 size = fxdr_unsigned(int, *(tl + 7));
 4232                 if (size < 0 || size > NFSV4_OPAQUELIMIT)
 4233                         error = EBADRPC;
 4234                 if (!error)
 4235                         error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
 4236         } else if (nd->nd_repstat == NFSERR_STALESTATEID)
 4237                 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
 4238 nfsmout:
 4239         mbuf_freem(nd->nd_mrep);
 4240         return (error);
 4241 }
 4242 
 4243 /*
 4244  * nfs statfs rpc
 4245  * (always called with the vp for the mount point)
 4246  */
 4247 int
 4248 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
 4249     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 4250     void *stuff)
 4251 {
 4252         u_int32_t *tl = NULL;
 4253         struct nfsrv_descript nfsd, *nd = &nfsd;
 4254         struct nfsmount *nmp;
 4255         nfsattrbit_t attrbits;
 4256         int error;
 4257 
 4258         *attrflagp = 0;
 4259         nmp = VFSTONFS(vnode_mount(vp));
 4260         if (NFSHASNFSV4(nmp)) {
 4261                 /*
 4262                  * For V4, you actually do a getattr.
 4263                  */
 4264                 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
 4265                 NFSSTATFS_GETATTRBIT(&attrbits);
 4266                 (void) nfsrv_putattrbit(nd, &attrbits);
 4267                 nd->nd_flag |= ND_USEGSSNAME;
 4268                 error = nfscl_request(nd, vp, p, cred, stuff);
 4269                 if (error)
 4270                         return (error);
 4271                 if (nd->nd_repstat == 0) {
 4272                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
 4273                             NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
 4274                             cred);
 4275                         if (!error) {
 4276                                 nmp->nm_fsid[0] = nap->na_filesid[0];
 4277                                 nmp->nm_fsid[1] = nap->na_filesid[1];
 4278                                 NFSSETHASSETFSID(nmp);
 4279                                 *attrflagp = 1;
 4280                         }
 4281                 } else {
 4282                         error = nd->nd_repstat;
 4283                 }
 4284                 if (error)
 4285                         goto nfsmout;
 4286         } else {
 4287                 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
 4288                 error = nfscl_request(nd, vp, p, cred, stuff);
 4289                 if (error)
 4290                         return (error);
 4291                 if (nd->nd_flag & ND_NFSV3) {
 4292                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 4293                         if (error)
 4294                                 goto nfsmout;
 4295                 }
 4296                 if (nd->nd_repstat) {
 4297                         error = nd->nd_repstat;
 4298                         goto nfsmout;
 4299                 }
 4300                 NFSM_DISSECT(tl, u_int32_t *,
 4301                     NFSX_STATFS(nd->nd_flag & ND_NFSV3));
 4302         }
 4303         if (NFSHASNFSV3(nmp)) {
 4304                 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
 4305                 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
 4306                 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
 4307                 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
 4308                 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
 4309                 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
 4310                 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
 4311         } else if (NFSHASNFSV4(nmp) == 0) {
 4312                 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
 4313                 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
 4314                 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
 4315                 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
 4316                 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
 4317         }
 4318 nfsmout:
 4319         mbuf_freem(nd->nd_mrep);
 4320         return (error);
 4321 }
 4322 
 4323 /*
 4324  * nfs pathconf rpc
 4325  */
 4326 int
 4327 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
 4328     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 4329     void *stuff)
 4330 {
 4331         struct nfsrv_descript nfsd, *nd = &nfsd;
 4332         struct nfsmount *nmp;
 4333         u_int32_t *tl;
 4334         nfsattrbit_t attrbits;
 4335         int error;
 4336 
 4337         *attrflagp = 0;
 4338         nmp = VFSTONFS(vnode_mount(vp));
 4339         if (NFSHASNFSV4(nmp)) {
 4340                 /*
 4341                  * For V4, you actually do a getattr.
 4342                  */
 4343                 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
 4344                 NFSPATHCONF_GETATTRBIT(&attrbits);
 4345                 (void) nfsrv_putattrbit(nd, &attrbits);
 4346                 nd->nd_flag |= ND_USEGSSNAME;
 4347                 error = nfscl_request(nd, vp, p, cred, stuff);
 4348                 if (error)
 4349                         return (error);
 4350                 if (nd->nd_repstat == 0) {
 4351                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
 4352                             pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
 4353                             cred);
 4354                         if (!error)
 4355                                 *attrflagp = 1;
 4356                 } else {
 4357                         error = nd->nd_repstat;
 4358                 }
 4359         } else {
 4360                 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
 4361                 error = nfscl_request(nd, vp, p, cred, stuff);
 4362                 if (error)
 4363                         return (error);
 4364                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 4365                 if (nd->nd_repstat && !error)
 4366                         error = nd->nd_repstat;
 4367                 if (!error) {
 4368                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
 4369                         pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
 4370                         pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
 4371                         pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
 4372                         pc->pc_chownrestricted =
 4373                             fxdr_unsigned(u_int32_t, *tl++);
 4374                         pc->pc_caseinsensitive =
 4375                             fxdr_unsigned(u_int32_t, *tl++);
 4376                         pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
 4377                 }
 4378         }
 4379 nfsmout:
 4380         mbuf_freem(nd->nd_mrep);
 4381         return (error);
 4382 }
 4383 
 4384 /*
 4385  * nfs version 3 fsinfo rpc call
 4386  */
 4387 int
 4388 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
 4389     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 4390 {
 4391         u_int32_t *tl;
 4392         struct nfsrv_descript nfsd, *nd = &nfsd;
 4393         int error;
 4394 
 4395         *attrflagp = 0;
 4396         NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
 4397         error = nfscl_request(nd, vp, p, cred, stuff);
 4398         if (error)
 4399                 return (error);
 4400         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 4401         if (nd->nd_repstat && !error)
 4402                 error = nd->nd_repstat;
 4403         if (!error) {
 4404                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
 4405                 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
 4406                 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
 4407                 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
 4408                 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
 4409                 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
 4410                 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
 4411                 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
 4412                 fsp->fs_maxfilesize = fxdr_hyper(tl);
 4413                 tl += 2;
 4414                 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
 4415                 tl += 2;
 4416                 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
 4417         }
 4418 nfsmout:
 4419         mbuf_freem(nd->nd_mrep);
 4420         return (error);
 4421 }
 4422 
 4423 /*
 4424  * This function performs the Renew RPC.
 4425  */
 4426 int
 4427 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
 4428     NFSPROC_T *p)
 4429 {
 4430         u_int32_t *tl;
 4431         struct nfsrv_descript nfsd;
 4432         struct nfsrv_descript *nd = &nfsd;
 4433         struct nfsmount *nmp;
 4434         int error;
 4435         struct nfssockreq *nrp;
 4436         struct nfsclsession *tsep;
 4437 
 4438         nmp = clp->nfsc_nmp;
 4439         if (nmp == NULL)
 4440                 return (0);
 4441         if (dsp == NULL)
 4442                 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0,
 4443                     0);
 4444         else
 4445                 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
 4446                     &dsp->nfsclds_sess, 0, 0);
 4447         if (!NFSHASNFSV4N(nmp)) {
 4448                 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
 4449                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 4450                 tsep = nfsmnt_mdssession(nmp);
 4451                 *tl++ = tsep->nfsess_clientid.lval[0];
 4452                 *tl = tsep->nfsess_clientid.lval[1];
 4453         }
 4454         nrp = NULL;
 4455         if (dsp != NULL)
 4456                 nrp = dsp->nfsclds_sockp;
 4457         if (nrp == NULL)
 4458                 /* If NULL, use the MDS socket. */
 4459                 nrp = &nmp->nm_sockreq;
 4460         nd->nd_flag |= ND_USEGSSNAME;
 4461         if (dsp == NULL)
 4462                 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
 4463                     NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4464         else {
 4465                 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
 4466                     NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
 4467                 if (error == ENXIO)
 4468                         nfscl_cancelreqs(dsp);
 4469         }
 4470         if (error)
 4471                 return (error);
 4472         error = nd->nd_repstat;
 4473         mbuf_freem(nd->nd_mrep);
 4474         return (error);
 4475 }
 4476 
 4477 /*
 4478  * This function performs the Releaselockowner RPC.
 4479  */
 4480 int
 4481 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
 4482     uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
 4483 {
 4484         struct nfsrv_descript nfsd, *nd = &nfsd;
 4485         u_int32_t *tl;
 4486         int error;
 4487         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
 4488         struct nfsclsession *tsep;
 4489 
 4490         if (NFSHASNFSV4N(nmp)) {
 4491                 /* For NFSv4.1, do a FreeStateID. */
 4492                 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
 4493                     NULL, 0, 0);
 4494                 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
 4495         } else {
 4496                 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
 4497                     NULL, 0, 0);
 4498                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 4499                 tsep = nfsmnt_mdssession(nmp);
 4500                 *tl++ = tsep->nfsess_clientid.lval[0];
 4501                 *tl = tsep->nfsess_clientid.lval[1];
 4502                 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
 4503                 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
 4504                 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
 4505         }
 4506         nd->nd_flag |= ND_USEGSSNAME;
 4507         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4508             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4509         if (error)
 4510                 return (error);
 4511         error = nd->nd_repstat;
 4512         mbuf_freem(nd->nd_mrep);
 4513         return (error);
 4514 }
 4515 
 4516 /*
 4517  * This function performs the Compound to get the mount pt FH.
 4518  */
 4519 int
 4520 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
 4521     NFSPROC_T *p)
 4522 {
 4523         u_int32_t *tl;
 4524         struct nfsrv_descript nfsd;
 4525         struct nfsrv_descript *nd = &nfsd;
 4526         u_char *cp, *cp2;
 4527         int error, cnt, len, setnil;
 4528         u_int32_t *opcntp;
 4529 
 4530         nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0,
 4531             0);
 4532         cp = dirpath;
 4533         cnt = 0;
 4534         do {
 4535                 setnil = 0;
 4536                 while (*cp == '/')
 4537                         cp++;
 4538                 cp2 = cp;
 4539                 while (*cp2 != '\0' && *cp2 != '/')
 4540                         cp2++;
 4541                 if (*cp2 == '/') {
 4542                         setnil = 1;
 4543                         *cp2 = '\0';
 4544                 }
 4545                 if (cp2 != cp) {
 4546                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 4547                         *tl = txdr_unsigned(NFSV4OP_LOOKUP);
 4548                         nfsm_strtom(nd, cp, strlen(cp));
 4549                         cnt++;
 4550                 }
 4551                 if (setnil)
 4552                         *cp2++ = '/';
 4553                 cp = cp2;
 4554         } while (*cp != '\0');
 4555         if (NFSHASNFSV4N(nmp))
 4556                 /* Has a Sequence Op done by nfscl_reqstart(). */
 4557                 *opcntp = txdr_unsigned(3 + cnt);
 4558         else
 4559                 *opcntp = txdr_unsigned(2 + cnt);
 4560         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 4561         *tl = txdr_unsigned(NFSV4OP_GETFH);
 4562         nd->nd_flag |= ND_USEGSSNAME;
 4563         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4564                 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4565         if (error)
 4566                 return (error);
 4567         if (nd->nd_repstat == 0) {
 4568                 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
 4569                 tl += (2 + 2 * cnt);
 4570                 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
 4571                         len > NFSX_FHMAX) {
 4572                         nd->nd_repstat = NFSERR_BADXDR;
 4573                 } else {
 4574                         nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
 4575                         if (nd->nd_repstat == 0)
 4576                                 nmp->nm_fhsize = len;
 4577                 }
 4578         }
 4579         error = nd->nd_repstat;
 4580 nfsmout:
 4581         mbuf_freem(nd->nd_mrep);
 4582         return (error);
 4583 }
 4584 
 4585 /*
 4586  * This function performs the Delegreturn RPC.
 4587  */
 4588 int
 4589 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
 4590     struct nfsmount *nmp, NFSPROC_T *p, int syscred)
 4591 {
 4592         u_int32_t *tl;
 4593         struct nfsrv_descript nfsd;
 4594         struct nfsrv_descript *nd = &nfsd;
 4595         int error;
 4596 
 4597         nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
 4598             dp->nfsdl_fhlen, NULL, NULL, 0, 0);
 4599         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 4600         if (NFSHASNFSV4N(nmp))
 4601                 *tl++ = 0;
 4602         else
 4603                 *tl++ = dp->nfsdl_stateid.seqid;
 4604         *tl++ = dp->nfsdl_stateid.other[0];
 4605         *tl++ = dp->nfsdl_stateid.other[1];
 4606         *tl = dp->nfsdl_stateid.other[2];
 4607         if (syscred)
 4608                 nd->nd_flag |= ND_USEGSSNAME;
 4609         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4610             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4611         if (error)
 4612                 return (error);
 4613         error = nd->nd_repstat;
 4614         mbuf_freem(nd->nd_mrep);
 4615         return (error);
 4616 }
 4617 
 4618 /*
 4619  * nfs getacl call.
 4620  */
 4621 int
 4622 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
 4623     struct acl *aclp, void *stuff)