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

Cache object: 1e0bb870beb713cf8569a83dafe00b70


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