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-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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