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

Cache object: 6528c9a13991a820d42c358311377b98


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