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

Cache object: 0e45e9239d44781db91691d22e61acdd


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