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

Cache object: d484063cb7d457d48565975638d685a9


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


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