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


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

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

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

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

Cache object: 10b68a935af8e2c45830e119993fda2f


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