The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


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

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsclient/nfs_clrpcops.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 8b5fbc2234651d8ea633583ed5ee8cb2


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