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


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

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

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

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

Cache object: df97531da97872bba3b6933520c6e52e


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