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  * SPDX-License-Identifier: BSD-3-Clause
    3  *
    4  * Copyright (c) 1989, 1993
    5  *      The Regents of the University of California.  All rights reserved.
    6  *
    7  * This code is derived from software contributed to Berkeley by
    8  * Rick Macklem at The University of Guelph.
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  * 3. Neither the name of the University nor the names of its contributors
   19  *    may be used to endorse or promote products derived from this software
   20  *    without specific prior written permission.
   21  *
   22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
   23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
   26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   32  * SUCH DAMAGE.
   33  *
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __FBSDID("$FreeBSD$");
   38 
   39 /*
   40  * Rpc op calls, generally called from the vnode op calls or through the
   41  * buffer cache, for NFS v2, 3 and 4.
   42  * These do not normally make any changes to vnode arguments or use
   43  * structures that might change between the VFS variants. The returned
   44  * arguments are all at the end, after the NFSPROC_T *p one.
   45  */
   46 
   47 #include "opt_inet6.h"
   48 
   49 #include <fs/nfs/nfsport.h>
   50 #include <sys/sysctl.h>
   51 #include <sys/taskqueue.h>
   52 
   53 SYSCTL_DECL(_vfs_nfs);
   54 
   55 static int      nfsignore_eexist = 0;
   56 SYSCTL_INT(_vfs_nfs, OID_AUTO, ignore_eexist, CTLFLAG_RW,
   57     &nfsignore_eexist, 0, "NFS ignore EEXIST replies for mkdir/symlink");
   58 
   59 static int      nfscl_dssameconn = 0;
   60 SYSCTL_INT(_vfs_nfs, OID_AUTO, dssameconn, CTLFLAG_RW,
   61     &nfscl_dssameconn, 0, "Use same TCP connection to multiple DSs");
   62 
   63 /*
   64  * Global variables
   65  */
   66 extern struct nfsstatsv1 nfsstatsv1;
   67 extern int nfs_numnfscbd;
   68 extern struct timeval nfsboottime;
   69 extern u_int32_t newnfs_false, newnfs_true;
   70 extern nfstype nfsv34_type[9];
   71 extern int nfsrv_useacl;
   72 extern char nfsv4_callbackaddr[INET6_ADDRSTRLEN];
   73 extern int nfscl_debuglevel;
   74 extern int nfs_pnfsiothreads;
   75 NFSCLSTATEMUTEX;
   76 int nfstest_outofseq = 0;
   77 int nfscl_assumeposixlocks = 1;
   78 int nfscl_enablecallb = 0;
   79 short nfsv4_cbport = NFSV4_CBPORT;
   80 int nfstest_openallsetattr = 0;
   81 
   82 #define DIRHDSIZ        offsetof(struct dirent, d_name)
   83 
   84 /*
   85  * nfscl_getsameserver() can return one of three values:
   86  * NFSDSP_USETHISSESSION - Use this session for the DS.
   87  * NFSDSP_SEQTHISSESSION - Use the nfsclds_sequence field of this dsp for new
   88  *     session.
   89  * NFSDSP_NOTFOUND - No matching server was found.
   90  */
   91 enum nfsclds_state {
   92         NFSDSP_USETHISSESSION = 0,
   93         NFSDSP_SEQTHISSESSION = 1,
   94         NFSDSP_NOTFOUND = 2,
   95 };
   96 
   97 /*
   98  * Do a write RPC on a DS data file, using this structure for the arguments,
   99  * so that this function can be executed by a separate kernel process.
  100  */
  101 struct nfsclwritedsdorpc {
  102         int                     done;
  103         int                     inprog;
  104         struct task             tsk;
  105         struct vnode            *vp;
  106         int                     iomode;
  107         int                     must_commit;
  108         nfsv4stateid_t          *stateidp;
  109         struct nfsclds          *dsp;
  110         uint64_t                off;
  111         int                     len;
  112         struct nfsfh            *fhp;
  113         struct mbuf             *m;
  114         int                     vers;
  115         int                     minorvers;
  116         struct ucred            *cred;
  117         NFSPROC_T               *p;
  118         int                     err;
  119 };
  120 
  121 static int nfsrpc_setattrrpc(vnode_t , struct vattr *, nfsv4stateid_t *,
  122     struct ucred *, NFSPROC_T *, struct nfsvattr *, int *, void *);
  123 static int nfsrpc_readrpc(vnode_t , struct uio *, struct ucred *,
  124     nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *, void *);
  125 static int nfsrpc_writerpc(vnode_t , struct uio *, int *, int *,
  126     struct ucred *, nfsv4stateid_t *, NFSPROC_T *, struct nfsvattr *, int *,
  127     void *);
  128 static int nfsrpc_createv23(vnode_t , char *, int, struct vattr *,
  129     nfsquad_t, int, struct ucred *, NFSPROC_T *, struct nfsvattr *,
  130     struct nfsvattr *, struct nfsfh **, int *, int *, void *);
  131 static int nfsrpc_createv4(vnode_t , char *, int, struct vattr *,
  132     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **, struct ucred *,
  133     NFSPROC_T *, struct nfsvattr *, struct nfsvattr *, struct nfsfh **, int *,
  134     int *, void *, int *);
  135 static int nfsrpc_locku(struct nfsrv_descript *, struct nfsmount *,
  136     struct nfscllockowner *, u_int64_t, u_int64_t,
  137     u_int32_t, struct ucred *, NFSPROC_T *, int);
  138 static int nfsrpc_setaclrpc(vnode_t, struct ucred *, NFSPROC_T *,
  139     struct acl *, nfsv4stateid_t *, void *);
  140 static int nfsrpc_getlayout(struct nfsmount *, vnode_t, struct nfsfh *, int,
  141     uint32_t, uint32_t *, nfsv4stateid_t *, uint64_t, struct nfscllayout **,
  142     struct ucred *, NFSPROC_T *);
  143 static int nfsrpc_fillsa(struct nfsmount *, struct sockaddr_in *,
  144     struct sockaddr_in6 *, sa_family_t, int, struct nfsclds **, NFSPROC_T *);
  145 static void nfscl_initsessionslots(struct nfsclsession *);
  146 static int nfscl_doflayoutio(vnode_t, struct uio *, int *, int *, int *,
  147     nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
  148     struct nfsclflayout *, uint64_t, uint64_t, int, struct ucred *,
  149     NFSPROC_T *);
  150 static int nfscl_dofflayoutio(vnode_t, struct uio *, int *, int *, int *,
  151     nfsv4stateid_t *, int, struct nfscldevinfo *, struct nfscllayout *,
  152     struct nfsclflayout *, uint64_t, uint64_t, int, int, struct mbuf *,
  153     struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
  154 static struct mbuf *nfsm_copym(struct mbuf *, int, int);
  155 static int nfsrpc_readds(vnode_t, struct uio *, nfsv4stateid_t *, int *,
  156     struct nfsclds *, uint64_t, int, struct nfsfh *, int, int, int,
  157     struct ucred *, NFSPROC_T *);
  158 static int nfsrpc_writeds(vnode_t, struct uio *, int *, int *,
  159     nfsv4stateid_t *, struct nfsclds *, uint64_t, int,
  160     struct nfsfh *, int, int, int, int, struct ucred *, NFSPROC_T *);
  161 static int nfsio_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
  162     struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
  163     struct nfsclwritedsdorpc *, struct ucred *, NFSPROC_T *);
  164 static int nfsrpc_writedsmir(vnode_t, int *, int *, nfsv4stateid_t *,
  165     struct nfsclds *, uint64_t, int, struct nfsfh *, struct mbuf *, int, int,
  166     struct ucred *, NFSPROC_T *);
  167 static enum nfsclds_state nfscl_getsameserver(struct nfsmount *,
  168     struct nfsclds *, struct nfsclds **, uint32_t *);
  169 static int nfsio_commitds(vnode_t, uint64_t, int, struct nfsclds *,
  170     struct nfsfh *, int, int, struct nfsclwritedsdorpc *, struct ucred *,
  171     NFSPROC_T *);
  172 static int nfsrpc_commitds(vnode_t, uint64_t, int, struct nfsclds *,
  173     struct nfsfh *, int, int, struct ucred *, NFSPROC_T *);
  174 static void nfsrv_setuplayoutget(struct nfsrv_descript *, int, uint64_t,
  175     uint64_t, uint64_t, nfsv4stateid_t *, int, int, int);
  176 static int nfsrv_parseug(struct nfsrv_descript *, int, uid_t *, gid_t *,
  177     NFSPROC_T *);
  178 static int nfsrv_parselayoutget(struct nfsrv_descript *, nfsv4stateid_t *,
  179     int *, struct nfsclflayouthead *);
  180 static int nfsrpc_getopenlayout(struct nfsmount *, vnode_t, u_int8_t *,
  181     int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
  182     struct nfscldeleg **, struct ucred *, NFSPROC_T *);
  183 static int nfsrpc_getcreatelayout(vnode_t, char *, int, struct vattr *,
  184     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
  185     struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
  186     struct nfsfh **, int *, int *, void *, int *);
  187 static int nfsrpc_openlayoutrpc(struct nfsmount *, vnode_t, u_int8_t *,
  188     int, uint8_t *, int, uint32_t, struct nfsclopen *, uint8_t *, int,
  189     struct nfscldeleg **, nfsv4stateid_t *, int, int, int, int *,
  190     struct nfsclflayouthead *, int *, struct ucred *, NFSPROC_T *);
  191 static int nfsrpc_createlayout(vnode_t, char *, int, struct vattr *,
  192     nfsquad_t, int, struct nfsclowner *, struct nfscldeleg **,
  193     struct ucred *, NFSPROC_T *, struct nfsvattr *, struct nfsvattr *,
  194     struct nfsfh **, int *, int *, void *, int *, nfsv4stateid_t *,
  195     int, int, int, int *, struct nfsclflayouthead *, int *);
  196 static int nfsrpc_layoutget(struct nfsmount *, uint8_t *, int, int, uint64_t,
  197     uint64_t, uint64_t, int, int, nfsv4stateid_t *, int *,
  198     struct nfsclflayouthead *, struct ucred *, NFSPROC_T *, void *);
  199 static int nfsrpc_layoutgetres(struct nfsmount *, vnode_t, uint8_t *,
  200     int, nfsv4stateid_t *, int, uint32_t *, struct nfscllayout **,
  201     struct nfsclflayouthead *, int, int, int *, struct ucred *, NFSPROC_T *);
  202 
  203 int nfs_pnfsio(task_fn_t *, void *);
  204 
  205 /*
  206  * nfs null call from vfs.
  207  */
  208 int
  209 nfsrpc_null(vnode_t vp, struct ucred *cred, NFSPROC_T *p)
  210 {
  211         int error;
  212         struct nfsrv_descript nfsd, *nd = &nfsd;
  213         
  214         NFSCL_REQSTART(nd, NFSPROC_NULL, vp);
  215         error = nfscl_request(nd, vp, p, cred, NULL);
  216         if (nd->nd_repstat && !error)
  217                 error = nd->nd_repstat;
  218         mbuf_freem(nd->nd_mrep);
  219         return (error);
  220 }
  221 
  222 /*
  223  * nfs access rpc op.
  224  * For nfs version 3 and 4, use the access rpc to check accessibility. If file
  225  * modes are changed on the server, accesses might still fail later.
  226  */
  227 int
  228 nfsrpc_access(vnode_t vp, int acmode, struct ucred *cred,
  229     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp)
  230 {
  231         int error;
  232         u_int32_t mode, rmode;
  233 
  234         if (acmode & VREAD)
  235                 mode = NFSACCESS_READ;
  236         else
  237                 mode = 0;
  238         if (vnode_vtype(vp) == VDIR) {
  239                 if (acmode & VWRITE)
  240                         mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND |
  241                                  NFSACCESS_DELETE);
  242                 if (acmode & VEXEC)
  243                         mode |= NFSACCESS_LOOKUP;
  244         } else {
  245                 if (acmode & VWRITE)
  246                         mode |= (NFSACCESS_MODIFY | NFSACCESS_EXTEND);
  247                 if (acmode & VEXEC)
  248                         mode |= NFSACCESS_EXECUTE;
  249         }
  250 
  251         /*
  252          * Now, just call nfsrpc_accessrpc() to do the actual RPC.
  253          */
  254         error = nfsrpc_accessrpc(vp, mode, cred, p, nap, attrflagp, &rmode,
  255             NULL);
  256 
  257         /*
  258          * The NFS V3 spec does not clarify whether or not
  259          * the returned access bits can be a superset of
  260          * the ones requested, so...
  261          */
  262         if (!error && (rmode & mode) != mode)
  263                 error = EACCES;
  264         return (error);
  265 }
  266 
  267 /*
  268  * The actual rpc, separated out for Darwin.
  269  */
  270 int
  271 nfsrpc_accessrpc(vnode_t vp, u_int32_t mode, struct ucred *cred,
  272     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, u_int32_t *rmodep,
  273     void *stuff)
  274 {
  275         u_int32_t *tl;
  276         u_int32_t supported, rmode;
  277         int error;
  278         struct nfsrv_descript nfsd, *nd = &nfsd;
  279         nfsattrbit_t attrbits;
  280 
  281         *attrflagp = 0;
  282         supported = mode;
  283         NFSCL_REQSTART(nd, NFSPROC_ACCESS, vp);
  284         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  285         *tl = txdr_unsigned(mode);
  286         if (nd->nd_flag & ND_NFSV4) {
  287                 /*
  288                  * And do a Getattr op.
  289                  */
  290                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  291                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
  292                 NFSGETATTR_ATTRBIT(&attrbits);
  293                 (void) nfsrv_putattrbit(nd, &attrbits);
  294         }
  295         error = nfscl_request(nd, vp, p, cred, stuff);
  296         if (error)
  297                 return (error);
  298         if (nd->nd_flag & ND_NFSV3) {
  299                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
  300                 if (error)
  301                         goto nfsmout;
  302         }
  303         if (!nd->nd_repstat) {
  304                 if (nd->nd_flag & ND_NFSV4) {
  305                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  306                         supported = fxdr_unsigned(u_int32_t, *tl++);
  307                 } else {
  308                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  309                 }
  310                 rmode = fxdr_unsigned(u_int32_t, *tl);
  311                 if (nd->nd_flag & ND_NFSV4)
  312                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
  313 
  314                 /*
  315                  * It's not obvious what should be done about
  316                  * unsupported access modes. For now, be paranoid
  317                  * and clear the unsupported ones.
  318                  */
  319                 rmode &= supported;
  320                 *rmodep = rmode;
  321         } else
  322                 error = nd->nd_repstat;
  323 nfsmout:
  324         mbuf_freem(nd->nd_mrep);
  325         return (error);
  326 }
  327 
  328 /*
  329  * nfs open rpc
  330  */
  331 int
  332 nfsrpc_open(vnode_t vp, int amode, struct ucred *cred, NFSPROC_T *p)
  333 {
  334         struct nfsclopen *op;
  335         struct nfscldeleg *dp;
  336         struct nfsfh *nfhp;
  337         struct nfsnode *np = VTONFS(vp);
  338         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
  339         u_int32_t mode, clidrev;
  340         int ret, newone, error, expireret = 0, retrycnt;
  341 
  342         /*
  343          * For NFSv4, Open Ops are only done on Regular Files.
  344          */
  345         if (vnode_vtype(vp) != VREG)
  346                 return (0);
  347         mode = 0;
  348         if (amode & FREAD)
  349                 mode |= NFSV4OPEN_ACCESSREAD;
  350         if (amode & FWRITE)
  351                 mode |= NFSV4OPEN_ACCESSWRITE;
  352         nfhp = np->n_fhp;
  353 
  354         retrycnt = 0;
  355 #ifdef notdef
  356 { char name[100]; int namel;
  357 namel = (np->n_v4->n4_namelen < 100) ? np->n_v4->n4_namelen : 99;
  358 bcopy(NFS4NODENAME(np->n_v4), name, namel);
  359 name[namel] = '\0';
  360 printf("rpcopen p=0x%x name=%s",p->p_pid,name);
  361 if (nfhp->nfh_len > 0) printf(" fh=0x%x\n",nfhp->nfh_fh[12]);
  362 else printf(" fhl=0\n");
  363 }
  364 #endif
  365         do {
  366             dp = NULL;
  367             error = nfscl_open(vp, nfhp->nfh_fh, nfhp->nfh_len, mode, 1,
  368                 cred, p, NULL, &op, &newone, &ret, 1, true);
  369             if (error) {
  370                 return (error);
  371             }
  372             if (nmp->nm_clp != NULL)
  373                 clidrev = nmp->nm_clp->nfsc_clientidrev;
  374             else
  375                 clidrev = 0;
  376             if (ret == NFSCLOPEN_DOOPEN) {
  377                 if (np->n_v4 != NULL) {
  378                         /*
  379                          * For the first attempt, try and get a layout, if
  380                          * pNFS is enabled for the mount.
  381                          */
  382                         if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
  383                             nfs_numnfscbd == 0 ||
  384                             (np->n_flag & NNOLAYOUT) != 0 || retrycnt > 0)
  385                                 error = nfsrpc_openrpc(nmp, vp,
  386                                     np->n_v4->n4_data,
  387                                     np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
  388                                     np->n_fhp->nfh_len, mode, op,
  389                                     NFS4NODENAME(np->n_v4),
  390                                     np->n_v4->n4_namelen,
  391                                     &dp, 0, 0x0, cred, p, 0, 0);
  392                         else
  393                                 error = nfsrpc_getopenlayout(nmp, vp,
  394                                     np->n_v4->n4_data,
  395                                     np->n_v4->n4_fhlen, np->n_fhp->nfh_fh,
  396                                     np->n_fhp->nfh_len, mode, op,
  397                                     NFS4NODENAME(np->n_v4),
  398                                     np->n_v4->n4_namelen, &dp, cred, p);
  399                         if (dp != NULL) {
  400 #ifdef APPLE
  401                                 OSBitAndAtomic((int32_t)~NDELEGMOD, (UInt32 *)&np->n_flag);
  402 #else
  403                                 NFSLOCKNODE(np);
  404                                 np->n_flag &= ~NDELEGMOD;
  405                                 /*
  406                                  * Invalidate the attribute cache, so that
  407                                  * attributes that pre-date the issue of a
  408                                  * delegation are not cached, since the
  409                                  * cached attributes will remain valid while
  410                                  * the delegation is held.
  411                                  */
  412                                 NFSINVALATTRCACHE(np);
  413                                 NFSUNLOCKNODE(np);
  414 #endif
  415                                 (void) nfscl_deleg(nmp->nm_mountp,
  416                                     op->nfso_own->nfsow_clp,
  417                                     nfhp->nfh_fh, nfhp->nfh_len, cred, p, &dp);
  418                         }
  419                 } else {
  420                         error = EIO;
  421                 }
  422                 newnfs_copyincred(cred, &op->nfso_cred);
  423             } else if (ret == NFSCLOPEN_SETCRED)
  424                 /*
  425                  * This is a new local open on a delegation. It needs
  426                  * to have credentials so that an open can be done
  427                  * against the server during recovery.
  428                  */
  429                 newnfs_copyincred(cred, &op->nfso_cred);
  430 
  431             /*
  432              * nfso_opencnt is the count of how many VOP_OPEN()s have
  433              * been done on this Open successfully and a VOP_CLOSE()
  434              * is expected for each of these.
  435              * If error is non-zero, don't increment it, since the Open
  436              * hasn't succeeded yet.
  437              */
  438             if (!error)
  439                 op->nfso_opencnt++;
  440             nfscl_openrelease(nmp, op, error, newone);
  441             if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
  442                 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
  443                 error == NFSERR_BADSESSION) {
  444                 (void) nfs_catnap(PZERO, error, "nfs_open");
  445             } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
  446                 && clidrev != 0) {
  447                 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
  448                 retrycnt++;
  449             }
  450         } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
  451             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
  452             error == NFSERR_BADSESSION ||
  453             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
  454              expireret == 0 && clidrev != 0 && retrycnt < 4));
  455         if (error && retrycnt >= 4)
  456                 error = EIO;
  457         return (error);
  458 }
  459 
  460 /*
  461  * the actual open rpc
  462  */
  463 int
  464 nfsrpc_openrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp, int fhlen,
  465     u_int8_t *newfhp, int newfhlen, u_int32_t mode, struct nfsclopen *op,
  466     u_int8_t *name, int namelen, struct nfscldeleg **dpp,
  467     int reclaim, u_int32_t delegtype, struct ucred *cred, NFSPROC_T *p,
  468     int syscred, int recursed)
  469 {
  470         u_int32_t *tl;
  471         struct nfsrv_descript nfsd, *nd = &nfsd;
  472         struct nfscldeleg *dp, *ndp = NULL;
  473         struct nfsvattr nfsva;
  474         u_int32_t rflags, deleg;
  475         nfsattrbit_t attrbits;
  476         int error, ret, acesize, limitby;
  477         struct nfsclsession *tsep;
  478 
  479         dp = *dpp;
  480         *dpp = NULL;
  481         nfscl_reqstart(nd, NFSPROC_OPEN, nmp, nfhp, fhlen, NULL, NULL, 0, 0);
  482         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
  483         *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
  484         *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
  485         *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
  486         tsep = nfsmnt_mdssession(nmp);
  487         *tl++ = tsep->nfsess_clientid.lval[0];
  488         *tl = tsep->nfsess_clientid.lval[1];
  489         (void) nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
  490         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  491         *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
  492         if (reclaim) {
  493                 *tl = txdr_unsigned(NFSV4OPEN_CLAIMPREVIOUS);
  494                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  495                 *tl = txdr_unsigned(delegtype);
  496         } else {
  497                 if (dp != NULL) {
  498                         *tl = txdr_unsigned(NFSV4OPEN_CLAIMDELEGATECUR);
  499                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
  500                         if (NFSHASNFSV4N(nmp))
  501                                 *tl++ = 0;
  502                         else
  503                                 *tl++ = dp->nfsdl_stateid.seqid;
  504                         *tl++ = dp->nfsdl_stateid.other[0];
  505                         *tl++ = dp->nfsdl_stateid.other[1];
  506                         *tl = dp->nfsdl_stateid.other[2];
  507                 } else {
  508                         *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
  509                 }
  510                 (void) nfsm_strtom(nd, name, namelen);
  511         }
  512         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  513         *tl = txdr_unsigned(NFSV4OP_GETATTR);
  514         NFSZERO_ATTRBIT(&attrbits);
  515         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
  516         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
  517         (void) nfsrv_putattrbit(nd, &attrbits);
  518         if (syscred)
  519                 nd->nd_flag |= ND_USEGSSNAME;
  520         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
  521             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
  522         if (error)
  523                 return (error);
  524         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
  525         if (!nd->nd_repstat) {
  526                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
  527                     6 * NFSX_UNSIGNED);
  528                 op->nfso_stateid.seqid = *tl++;
  529                 op->nfso_stateid.other[0] = *tl++;
  530                 op->nfso_stateid.other[1] = *tl++;
  531                 op->nfso_stateid.other[2] = *tl;
  532                 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
  533                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
  534                 if (error)
  535                         goto nfsmout;
  536                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  537                 deleg = fxdr_unsigned(u_int32_t, *tl);
  538                 if (deleg == NFSV4OPEN_DELEGATEREAD ||
  539                     deleg == NFSV4OPEN_DELEGATEWRITE) {
  540                         if (!(op->nfso_own->nfsow_clp->nfsc_flags &
  541                               NFSCLFLAGS_FIRSTDELEG))
  542                                 op->nfso_own->nfsow_clp->nfsc_flags |=
  543                                   (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
  544                         ndp = malloc(
  545                             sizeof (struct nfscldeleg) + newfhlen,
  546                             M_NFSCLDELEG, M_WAITOK);
  547                         LIST_INIT(&ndp->nfsdl_owner);
  548                         LIST_INIT(&ndp->nfsdl_lock);
  549                         ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
  550                         ndp->nfsdl_fhlen = newfhlen;
  551                         NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
  552                         newnfs_copyincred(cred, &ndp->nfsdl_cred);
  553                         nfscl_lockinit(&ndp->nfsdl_rwlock);
  554                         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
  555                             NFSX_UNSIGNED);
  556                         ndp->nfsdl_stateid.seqid = *tl++;
  557                         ndp->nfsdl_stateid.other[0] = *tl++;
  558                         ndp->nfsdl_stateid.other[1] = *tl++;
  559                         ndp->nfsdl_stateid.other[2] = *tl++;
  560                         ret = fxdr_unsigned(int, *tl);
  561                         if (deleg == NFSV4OPEN_DELEGATEWRITE) {
  562                                 ndp->nfsdl_flags = NFSCLDL_WRITE;
  563                                 /*
  564                                  * Indicates how much the file can grow.
  565                                  */
  566                                 NFSM_DISSECT(tl, u_int32_t *,
  567                                     3 * NFSX_UNSIGNED);
  568                                 limitby = fxdr_unsigned(int, *tl++);
  569                                 switch (limitby) {
  570                                 case NFSV4OPEN_LIMITSIZE:
  571                                         ndp->nfsdl_sizelimit = fxdr_hyper(tl);
  572                                         break;
  573                                 case NFSV4OPEN_LIMITBLOCKS:
  574                                         ndp->nfsdl_sizelimit =
  575                                             fxdr_unsigned(u_int64_t, *tl++);
  576                                         ndp->nfsdl_sizelimit *=
  577                                             fxdr_unsigned(u_int64_t, *tl);
  578                                         break;
  579                                 default:
  580                                         error = NFSERR_BADXDR;
  581                                         goto nfsmout;
  582                                 }
  583                         } else {
  584                                 ndp->nfsdl_flags = NFSCLDL_READ;
  585                         }
  586                         if (ret)
  587                                 ndp->nfsdl_flags |= NFSCLDL_RECALL;
  588                         error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
  589                             &acesize, p);
  590                         if (error)
  591                                 goto nfsmout;
  592                 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
  593                         error = NFSERR_BADXDR;
  594                         goto nfsmout;
  595                 }
  596                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  597                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
  598                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
  599                     NULL, NULL, NULL, p, cred);
  600                 if (error)
  601                         goto nfsmout;
  602                 if (ndp != NULL) {
  603                         ndp->nfsdl_change = nfsva.na_filerev;
  604                         ndp->nfsdl_modtime = nfsva.na_mtime;
  605                         ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
  606                 }
  607                 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM)) {
  608                     do {
  609                         ret = nfsrpc_openconfirm(vp, newfhp, newfhlen, op,
  610                             cred, p);
  611                         if (ret == NFSERR_DELAY)
  612                             (void) nfs_catnap(PZERO, ret, "nfs_open");
  613                     } while (ret == NFSERR_DELAY);
  614                     error = ret;
  615                 }
  616                 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) ||
  617                     nfscl_assumeposixlocks)
  618                     op->nfso_posixlock = 1;
  619                 else
  620                     op->nfso_posixlock = 0;
  621 
  622                 /*
  623                  * If the server is handing out delegations, but we didn't
  624                  * get one because an OpenConfirm was required, try the
  625                  * Open again, to get a delegation. This is a harmless no-op,
  626                  * from a server's point of view.
  627                  */
  628                 if (!reclaim && (rflags & NFSV4OPEN_RESULTCONFIRM) &&
  629                     (op->nfso_own->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG)
  630                     && !error && dp == NULL && ndp == NULL && !recursed) {
  631                     do {
  632                         ret = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp,
  633                             newfhlen, mode, op, name, namelen, &ndp, 0, 0x0,
  634                             cred, p, syscred, 1);
  635                         if (ret == NFSERR_DELAY)
  636                             (void) nfs_catnap(PZERO, ret, "nfs_open2");
  637                     } while (ret == NFSERR_DELAY);
  638                     if (ret) {
  639                         if (ndp != NULL) {
  640                                 free(ndp, M_NFSCLDELEG);
  641                                 ndp = NULL;
  642                         }
  643                         if (ret == NFSERR_STALECLIENTID ||
  644                             ret == NFSERR_STALEDONTRECOVER ||
  645                             ret == NFSERR_BADSESSION)
  646                                 error = ret;
  647                     }
  648                 }
  649         }
  650         if (nd->nd_repstat != 0 && error == 0)
  651                 error = nd->nd_repstat;
  652         if (error == NFSERR_STALECLIENTID)
  653                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
  654 nfsmout:
  655         if (!error)
  656                 *dpp = ndp;
  657         else if (ndp != NULL)
  658                 free(ndp, M_NFSCLDELEG);
  659         mbuf_freem(nd->nd_mrep);
  660         return (error);
  661 }
  662 
  663 /*
  664  * open downgrade rpc
  665  */
  666 int
  667 nfsrpc_opendowngrade(vnode_t vp, u_int32_t mode, struct nfsclopen *op,
  668     struct ucred *cred, NFSPROC_T *p)
  669 {
  670         u_int32_t *tl;
  671         struct nfsrv_descript nfsd, *nd = &nfsd;
  672         int error;
  673 
  674         NFSCL_REQSTART(nd, NFSPROC_OPENDOWNGRADE, vp);
  675         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
  676         if (NFSHASNFSV4N(VFSTONFS(vnode_mount(vp))))
  677                 *tl++ = 0;
  678         else
  679                 *tl++ = op->nfso_stateid.seqid;
  680         *tl++ = op->nfso_stateid.other[0];
  681         *tl++ = op->nfso_stateid.other[1];
  682         *tl++ = op->nfso_stateid.other[2];
  683         *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
  684         *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
  685         *tl = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
  686         error = nfscl_request(nd, vp, p, cred, NULL);
  687         if (error)
  688                 return (error);
  689         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
  690         if (!nd->nd_repstat) {
  691                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
  692                 op->nfso_stateid.seqid = *tl++;
  693                 op->nfso_stateid.other[0] = *tl++;
  694                 op->nfso_stateid.other[1] = *tl++;
  695                 op->nfso_stateid.other[2] = *tl;
  696         }
  697         if (nd->nd_repstat && error == 0)
  698                 error = nd->nd_repstat;
  699         if (error == NFSERR_STALESTATEID)
  700                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
  701 nfsmout:
  702         mbuf_freem(nd->nd_mrep);
  703         return (error);
  704 }
  705 
  706 /*
  707  * V4 Close operation.
  708  */
  709 int
  710 nfsrpc_close(vnode_t vp, int doclose, NFSPROC_T *p)
  711 {
  712         struct nfsclclient *clp;
  713         int error;
  714 
  715         if (vnode_vtype(vp) != VREG)
  716                 return (0);
  717         if (doclose)
  718                 error = nfscl_doclose(vp, &clp, p);
  719         else {
  720                 error = nfscl_getclose(vp, &clp);
  721                 if (error == 0)
  722                         nfscl_clientrelease(clp);
  723         }
  724         return (error);
  725 }
  726 
  727 /*
  728  * Close the open.
  729  */
  730 int
  731 nfsrpc_doclose(struct nfsmount *nmp, struct nfsclopen *op, NFSPROC_T *p,
  732     bool loop_on_delayed, bool freeop)
  733 {
  734         struct nfsrv_descript nfsd, *nd = &nfsd;
  735         struct nfscllockowner *lp, *nlp;
  736         struct nfscllock *lop, *nlop;
  737         struct ucred *tcred;
  738         u_int64_t off = 0, len = 0;
  739         u_int32_t type = NFSV4LOCKT_READ;
  740         int error, do_unlock, trycnt;
  741 
  742         tcred = newnfs_getcred();
  743         newnfs_copycred(&op->nfso_cred, tcred);
  744         /*
  745          * (Theoretically this could be done in the same
  746          *  compound as the close, but having multiple
  747          *  sequenced Ops in the same compound might be
  748          *  too scary for some servers.)
  749          */
  750         if (op->nfso_posixlock) {
  751                 off = 0;
  752                 len = NFS64BITSSET;
  753                 type = NFSV4LOCKT_READ;
  754         }
  755 
  756         /*
  757          * Since this function is only called from VOP_INACTIVE(), no
  758          * other thread will be manipulating this Open. As such, the
  759          * lock lists are not being changed by other threads, so it should
  760          * be safe to do this without locking.
  761          */
  762         LIST_FOREACH(lp, &op->nfso_lock, nfsl_list) {
  763                 do_unlock = 1;
  764                 LIST_FOREACH_SAFE(lop, &lp->nfsl_lock, nfslo_list, nlop) {
  765                         if (op->nfso_posixlock == 0) {
  766                                 off = lop->nfslo_first;
  767                                 len = lop->nfslo_end - lop->nfslo_first;
  768                                 if (lop->nfslo_type == F_WRLCK)
  769                                         type = NFSV4LOCKT_WRITE;
  770                                 else
  771                                         type = NFSV4LOCKT_READ;
  772                         }
  773                         if (do_unlock) {
  774                                 trycnt = 0;
  775                                 do {
  776                                         error = nfsrpc_locku(nd, nmp, lp, off,
  777                                             len, type, tcred, p, 0);
  778                                         if ((nd->nd_repstat == NFSERR_GRACE ||
  779                                             nd->nd_repstat == NFSERR_DELAY) &&
  780                                             error == 0)
  781                                                 (void) nfs_catnap(PZERO,
  782                                                     (int)nd->nd_repstat,
  783                                                     "nfs_close");
  784                                 } while ((nd->nd_repstat == NFSERR_GRACE ||
  785                                     nd->nd_repstat == NFSERR_DELAY) &&
  786                                     error == 0 && trycnt++ < 5);
  787                                 if (op->nfso_posixlock)
  788                                         do_unlock = 0;
  789                         }
  790                         nfscl_freelock(lop, 0);
  791                 }
  792                 /*
  793                  * Do a ReleaseLockOwner.
  794                  * The lock owner name nfsl_owner may be used by other opens for
  795                  * other files but the lock_owner4 name that nfsrpc_rellockown()
  796                  * puts on the wire has the file handle for this file appended
  797                  * to it, so it can be done now.
  798                  */
  799                 (void)nfsrpc_rellockown(nmp, lp, lp->nfsl_open->nfso_fh,
  800                     lp->nfsl_open->nfso_fhlen, tcred, p);
  801         }
  802 
  803         /*
  804          * There could be other Opens for different files on the same
  805          * OpenOwner, so locking is required.
  806          */
  807         NFSLOCKCLSTATE();
  808         nfscl_lockexcl(&op->nfso_own->nfsow_rwlock, NFSCLSTATEMUTEXPTR);
  809         NFSUNLOCKCLSTATE();
  810         do {
  811                 error = nfscl_tryclose(op, tcred, nmp, p, loop_on_delayed);
  812                 if (error == NFSERR_GRACE)
  813                         (void) nfs_catnap(PZERO, error, "nfs_close");
  814         } while (error == NFSERR_GRACE);
  815         NFSLOCKCLSTATE();
  816         nfscl_lockunlock(&op->nfso_own->nfsow_rwlock);
  817 
  818         LIST_FOREACH_SAFE(lp, &op->nfso_lock, nfsl_list, nlp)
  819                 nfscl_freelockowner(lp, 0);
  820         if (freeop && error != NFSERR_DELAY)
  821                 nfscl_freeopen(op, 0, true);
  822         NFSUNLOCKCLSTATE();
  823         NFSFREECRED(tcred);
  824         return (error);
  825 }
  826 
  827 /*
  828  * The actual Close RPC.
  829  */
  830 int
  831 nfsrpc_closerpc(struct nfsrv_descript *nd, struct nfsmount *nmp,
  832     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p,
  833     int syscred)
  834 {
  835         u_int32_t *tl;
  836         int error;
  837 
  838         nfscl_reqstart(nd, NFSPROC_CLOSE, nmp, op->nfso_fh,
  839             op->nfso_fhlen, NULL, NULL, 0, 0);
  840         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
  841         if (NFSHASNFSV4N(nmp)) {
  842                 *tl++ = 0;
  843                 *tl++ = 0;
  844         } else {
  845                 *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
  846                 *tl++ = op->nfso_stateid.seqid;
  847         }
  848         *tl++ = op->nfso_stateid.other[0];
  849         *tl++ = op->nfso_stateid.other[1];
  850         *tl = op->nfso_stateid.other[2];
  851         if (syscred)
  852                 nd->nd_flag |= ND_USEGSSNAME;
  853         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
  854             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
  855         if (error)
  856                 return (error);
  857         if (!NFSHASNFSV4N(nmp))
  858                 NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
  859         if (nd->nd_repstat == 0)
  860                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
  861         error = nd->nd_repstat;
  862         if (!NFSHASNFSV4N(nmp) && error == NFSERR_STALESTATEID)
  863                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
  864 nfsmout:
  865         mbuf_freem(nd->nd_mrep);
  866         return (error);
  867 }
  868 
  869 /*
  870  * V4 Open Confirm RPC.
  871  */
  872 int
  873 nfsrpc_openconfirm(vnode_t vp, u_int8_t *nfhp, int fhlen,
  874     struct nfsclopen *op, struct ucred *cred, NFSPROC_T *p)
  875 {
  876         u_int32_t *tl;
  877         struct nfsrv_descript nfsd, *nd = &nfsd;
  878         struct nfsmount *nmp;
  879         int error;
  880 
  881         nmp = VFSTONFS(vnode_mount(vp));
  882         if (NFSHASNFSV4N(nmp))
  883                 return (0);             /* No confirmation for NFSv4.1. */
  884         nfscl_reqstart(nd, NFSPROC_OPENCONFIRM, nmp, nfhp, fhlen, NULL, NULL,
  885             0, 0);
  886         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
  887         *tl++ = op->nfso_stateid.seqid;
  888         *tl++ = op->nfso_stateid.other[0];
  889         *tl++ = op->nfso_stateid.other[1];
  890         *tl++ = op->nfso_stateid.other[2];
  891         *tl = txdr_unsigned(op->nfso_own->nfsow_seqid);
  892         error = nfscl_request(nd, vp, p, cred, NULL);
  893         if (error)
  894                 return (error);
  895         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
  896         if (!nd->nd_repstat) {
  897                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
  898                 op->nfso_stateid.seqid = *tl++;
  899                 op->nfso_stateid.other[0] = *tl++;
  900                 op->nfso_stateid.other[1] = *tl++;
  901                 op->nfso_stateid.other[2] = *tl;
  902         }
  903         error = nd->nd_repstat;
  904         if (error == NFSERR_STALESTATEID)
  905                 nfscl_initiate_recovery(op->nfso_own->nfsow_clp);
  906 nfsmout:
  907         mbuf_freem(nd->nd_mrep);
  908         return (error);
  909 }
  910 
  911 /*
  912  * Do the setclientid and setclientid confirm RPCs. Called from nfs_statfs()
  913  * when a mount has just occurred and when the server replies NFSERR_EXPIRED.
  914  */
  915 int
  916 nfsrpc_setclient(struct nfsmount *nmp, struct nfsclclient *clp, int reclaim,
  917     struct ucred *cred, NFSPROC_T *p)
  918 {
  919         u_int32_t *tl;
  920         struct nfsrv_descript nfsd;
  921         struct nfsrv_descript *nd = &nfsd;
  922         nfsattrbit_t attrbits;
  923         u_int8_t *cp = NULL, *cp2, addr[INET6_ADDRSTRLEN + 9];
  924         u_short port;
  925         int error, isinet6 = 0, callblen;
  926         nfsquad_t confirm;
  927         u_int32_t lease;
  928         static u_int32_t rev = 0;
  929         struct nfsclds *dsp;
  930         struct in6_addr a6;
  931         struct nfsclsession *tsep;
  932         struct rpc_reconupcall recon;
  933         struct nfscl_reconarg *rcp;
  934 
  935         if (nfsboottime.tv_sec == 0)
  936                 NFSSETBOOTTIME(nfsboottime);
  937         clp->nfsc_rev = rev++;
  938         if (NFSHASNFSV4N(nmp)) {
  939                 /*
  940                  * Either there was no previous session or the
  941                  * previous session has failed, so...
  942                  * do an ExchangeID followed by the CreateSession.
  943                  */
  944                 error = nfsrpc_exchangeid(nmp, clp, &nmp->nm_sockreq,
  945                     NFSV4EXCH_USEPNFSMDS | NFSV4EXCH_USENONPNFS, &dsp, cred, p);
  946                 NFSCL_DEBUG(1, "aft exch=%d\n", error);
  947                 if (error == 0)
  948                         error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
  949                             &nmp->nm_sockreq,
  950                             dsp->nfsclds_sess.nfsess_sequenceid, 1, cred, p);
  951                 if (error == 0) {
  952                         /*
  953                          * If the session supports a backchannel, set up
  954                          * the BindConnectionToSession call in the krpc
  955                          * so that it is done on a reconnection.
  956                          */
  957                         if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0) {
  958                                 rcp = mem_alloc(sizeof(*rcp));
  959                                 rcp->minorvers = nmp->nm_minorvers;
  960                                 memcpy(rcp->sessionid,
  961                                     dsp->nfsclds_sess.nfsess_sessionid,
  962                                     NFSX_V4SESSIONID);
  963                                 recon.call = nfsrpc_bindconnsess;
  964                                 recon.arg = rcp;
  965                                 CLNT_CONTROL(nmp->nm_client, CLSET_RECONUPCALL,
  966                                     &recon);
  967                         }
  968 
  969                         NFSLOCKMNT(nmp);
  970                         /*
  971                          * The old sessions cannot be safely free'd
  972                          * here, since they may still be used by
  973                          * in-progress RPCs.
  974                          */
  975                         tsep = NULL;
  976                         if (TAILQ_FIRST(&nmp->nm_sess) != NULL) {
  977                                 /*
  978                                  * Mark the old session defunct.  Needed
  979                                  * when called from nfscl_hasexpired().
  980                                  */
  981                                 tsep = NFSMNT_MDSSESSION(nmp);
  982                                 tsep->nfsess_defunct = 1;
  983                         }
  984                         TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp,
  985                             nfsclds_list);
  986                         /*
  987                          * Wake up RPCs waiting for a slot on the
  988                          * old session. These will then fail with
  989                          * NFSERR_BADSESSION and be retried with the
  990                          * new session by nfsv4_setsequence().
  991                          * Also wakeup() processes waiting for the
  992                          * new session.
  993                          */
  994                         if (tsep != NULL)
  995                                 wakeup(&tsep->nfsess_slots);
  996                         wakeup(&nmp->nm_sess);
  997                         NFSUNLOCKMNT(nmp);
  998                 } else
  999                         nfscl_freenfsclds(dsp);
 1000                 NFSCL_DEBUG(1, "aft createsess=%d\n", error);
 1001                 if (error == 0 && reclaim == 0) {
 1002                         error = nfsrpc_reclaimcomplete(nmp, cred, p);
 1003                         NFSCL_DEBUG(1, "aft reclaimcomp=%d\n", error);
 1004                         if (error == NFSERR_COMPLETEALREADY ||
 1005                             error == NFSERR_NOTSUPP)
 1006                                 /* Ignore this error. */
 1007                                 error = 0;
 1008                 }
 1009                 return (error);
 1010         }
 1011 
 1012         /*
 1013          * Allocate a single session structure for NFSv4.0, because some of
 1014          * the fields are used by NFSv4.0 although it doesn't do a session.
 1015          */
 1016         dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS, M_WAITOK | M_ZERO);
 1017         mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
 1018         mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession", NULL, MTX_DEF);
 1019         NFSLOCKMNT(nmp);
 1020         TAILQ_INSERT_HEAD(&nmp->nm_sess, dsp, nfsclds_list);
 1021         tsep = NFSMNT_MDSSESSION(nmp);
 1022         NFSUNLOCKMNT(nmp);
 1023 
 1024         nfscl_reqstart(nd, NFSPROC_SETCLIENTID, nmp, NULL, 0, NULL, NULL, 0, 0);
 1025         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1026         *tl++ = txdr_unsigned(nfsboottime.tv_sec);
 1027         *tl = txdr_unsigned(clp->nfsc_rev);
 1028         (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
 1029 
 1030         /*
 1031          * set up the callback address
 1032          */
 1033         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1034         *tl = txdr_unsigned(NFS_CALLBCKPROG);
 1035         callblen = strlen(nfsv4_callbackaddr);
 1036         if (callblen == 0)
 1037                 cp = nfscl_getmyip(nmp, &a6, &isinet6);
 1038         if (nfscl_enablecallb && nfs_numnfscbd > 0 &&
 1039             (callblen > 0 || cp != NULL)) {
 1040                 port = htons(nfsv4_cbport);
 1041                 cp2 = (u_int8_t *)&port;
 1042 #ifdef INET6
 1043                 if ((callblen > 0 &&
 1044                      strchr(nfsv4_callbackaddr, ':')) || isinet6) {
 1045                         char ip6buf[INET6_ADDRSTRLEN], *ip6add;
 1046 
 1047                         (void) nfsm_strtom(nd, "tcp6", 4);
 1048                         if (callblen == 0) {
 1049                                 ip6_sprintf(ip6buf, (struct in6_addr *)cp);
 1050                                 ip6add = ip6buf;
 1051                         } else {
 1052                                 ip6add = nfsv4_callbackaddr;
 1053                         }
 1054                         snprintf(addr, INET6_ADDRSTRLEN + 9, "%s.%d.%d",
 1055                             ip6add, cp2[0], cp2[1]);
 1056                 } else
 1057 #endif
 1058                 {
 1059                         (void) nfsm_strtom(nd, "tcp", 3);
 1060                         if (callblen == 0)
 1061                                 snprintf(addr, INET6_ADDRSTRLEN + 9,
 1062                                     "%d.%d.%d.%d.%d.%d", cp[0], cp[1],
 1063                                     cp[2], cp[3], cp2[0], cp2[1]);
 1064                         else
 1065                                 snprintf(addr, INET6_ADDRSTRLEN + 9,
 1066                                     "%s.%d.%d", nfsv4_callbackaddr,
 1067                                     cp2[0], cp2[1]);
 1068                 }
 1069                 (void) nfsm_strtom(nd, addr, strlen(addr));
 1070         } else {
 1071                 (void) nfsm_strtom(nd, "tcp", 3);
 1072                 (void) nfsm_strtom(nd, "0.0.0.0.0.0", 11);
 1073         }
 1074         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1075         *tl = txdr_unsigned(clp->nfsc_cbident);
 1076         nd->nd_flag |= ND_USEGSSNAME;
 1077         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 1078                 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 1079         if (error)
 1080                 return (error);
 1081         if (nd->nd_repstat == 0) {
 1082             NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1083             tsep->nfsess_clientid.lval[0] = *tl++;
 1084             tsep->nfsess_clientid.lval[1] = *tl++;
 1085             confirm.lval[0] = *tl++;
 1086             confirm.lval[1] = *tl;
 1087             mbuf_freem(nd->nd_mrep);
 1088             nd->nd_mrep = NULL;
 1089 
 1090             /*
 1091              * and confirm it.
 1092              */
 1093             nfscl_reqstart(nd, NFSPROC_SETCLIENTIDCFRM, nmp, NULL, 0, NULL,
 1094                 NULL, 0, 0);
 1095             NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1096             *tl++ = tsep->nfsess_clientid.lval[0];
 1097             *tl++ = tsep->nfsess_clientid.lval[1];
 1098             *tl++ = confirm.lval[0];
 1099             *tl = confirm.lval[1];
 1100             nd->nd_flag |= ND_USEGSSNAME;
 1101             error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
 1102                 cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 1103             if (error)
 1104                 return (error);
 1105             mbuf_freem(nd->nd_mrep);
 1106             nd->nd_mrep = NULL;
 1107             if (nd->nd_repstat == 0) {
 1108                 nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, nmp->nm_fh,
 1109                     nmp->nm_fhsize, NULL, NULL, 0, 0);
 1110                 NFSZERO_ATTRBIT(&attrbits);
 1111                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
 1112                 (void) nfsrv_putattrbit(nd, &attrbits);
 1113                 nd->nd_flag |= ND_USEGSSNAME;
 1114                 error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p,
 1115                     cred, NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 1116                 if (error)
 1117                     return (error);
 1118                 if (nd->nd_repstat == 0) {
 1119                     error = nfsv4_loadattr(nd, NULL, NULL, NULL, NULL, 0, NULL,
 1120                         NULL, NULL, NULL, NULL, 0, NULL, &lease, NULL, p, cred);
 1121                     if (error)
 1122                         goto nfsmout;
 1123                     clp->nfsc_renew = NFSCL_RENEW(lease);
 1124                     clp->nfsc_expire = NFSD_MONOSEC + clp->nfsc_renew;
 1125                     clp->nfsc_clientidrev++;
 1126                     if (clp->nfsc_clientidrev == 0)
 1127                         clp->nfsc_clientidrev++;
 1128                 }
 1129             }
 1130         }
 1131         error = nd->nd_repstat;
 1132 nfsmout:
 1133         mbuf_freem(nd->nd_mrep);
 1134         return (error);
 1135 }
 1136 
 1137 /*
 1138  * nfs getattr call.
 1139  */
 1140 int
 1141 nfsrpc_getattr(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
 1142     struct nfsvattr *nap, void *stuff)
 1143 {
 1144         struct nfsrv_descript nfsd, *nd = &nfsd;
 1145         int error;
 1146         nfsattrbit_t attrbits;
 1147         
 1148         NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
 1149         if (nd->nd_flag & ND_NFSV4) {
 1150                 NFSGETATTR_ATTRBIT(&attrbits);
 1151                 (void) nfsrv_putattrbit(nd, &attrbits);
 1152         }
 1153         error = nfscl_request(nd, vp, p, cred, stuff);
 1154         if (error)
 1155                 return (error);
 1156         if (!nd->nd_repstat)
 1157                 error = nfsm_loadattr(nd, nap);
 1158         else
 1159                 error = nd->nd_repstat;
 1160         mbuf_freem(nd->nd_mrep);
 1161         return (error);
 1162 }
 1163 
 1164 /*
 1165  * nfs getattr call with non-vnode arguments.
 1166  */
 1167 int
 1168 nfsrpc_getattrnovp(struct nfsmount *nmp, u_int8_t *fhp, int fhlen, int syscred,
 1169     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, u_int64_t *xidp,
 1170     uint32_t *leasep)
 1171 {
 1172         struct nfsrv_descript nfsd, *nd = &nfsd;
 1173         int error, vers = NFS_VER2;
 1174         nfsattrbit_t attrbits;
 1175         
 1176         nfscl_reqstart(nd, NFSPROC_GETATTR, nmp, fhp, fhlen, NULL, NULL, 0, 0);
 1177         if (nd->nd_flag & ND_NFSV4) {
 1178                 vers = NFS_VER4;
 1179                 NFSGETATTR_ATTRBIT(&attrbits);
 1180                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_LEASETIME);
 1181                 (void) nfsrv_putattrbit(nd, &attrbits);
 1182         } else if (nd->nd_flag & ND_NFSV3) {
 1183                 vers = NFS_VER3;
 1184         }
 1185         if (syscred)
 1186                 nd->nd_flag |= ND_USEGSSNAME;
 1187         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 1188             NFS_PROG, vers, NULL, 1, xidp, NULL);
 1189         if (error)
 1190                 return (error);
 1191         if (nd->nd_repstat == 0) {
 1192                 if ((nd->nd_flag & ND_NFSV4) != 0)
 1193                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
 1194                             NULL, NULL, NULL, NULL, NULL, 0, NULL, leasep, NULL,
 1195                             NULL, NULL);
 1196                 else
 1197                         error = nfsm_loadattr(nd, nap);
 1198         } else
 1199                 error = nd->nd_repstat;
 1200         mbuf_freem(nd->nd_mrep);
 1201         return (error);
 1202 }
 1203 
 1204 /*
 1205  * Do an nfs setattr operation.
 1206  */
 1207 int
 1208 nfsrpc_setattr(vnode_t vp, struct vattr *vap, NFSACL_T *aclp,
 1209     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *rnap, int *attrflagp,
 1210     void *stuff)
 1211 {
 1212         int error, expireret = 0, openerr, retrycnt;
 1213         u_int32_t clidrev = 0, mode;
 1214         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1215         struct nfsfh *nfhp;
 1216         nfsv4stateid_t stateid;
 1217         void *lckp;
 1218 
 1219         if (nmp->nm_clp != NULL)
 1220                 clidrev = nmp->nm_clp->nfsc_clientidrev;
 1221         if (vap != NULL && NFSATTRISSET(u_quad_t, vap, va_size))
 1222                 mode = NFSV4OPEN_ACCESSWRITE;
 1223         else
 1224                 mode = NFSV4OPEN_ACCESSREAD;
 1225         retrycnt = 0;
 1226         do {
 1227                 lckp = NULL;
 1228                 openerr = 1;
 1229                 if (NFSHASNFSV4(nmp)) {
 1230                         nfhp = VTONFS(vp)->n_fhp;
 1231                         error = nfscl_getstateid(vp, nfhp->nfh_fh,
 1232                             nfhp->nfh_len, mode, 0, cred, p, &stateid, &lckp);
 1233                         if (error && vnode_vtype(vp) == VREG &&
 1234                             (mode == NFSV4OPEN_ACCESSWRITE ||
 1235                              nfstest_openallsetattr)) {
 1236                                 /*
 1237                                  * No Open stateid, so try and open the file
 1238                                  * now.
 1239                                  */
 1240                                 if (mode == NFSV4OPEN_ACCESSWRITE)
 1241                                         openerr = nfsrpc_open(vp, FWRITE, cred,
 1242                                             p);
 1243                                 else
 1244                                         openerr = nfsrpc_open(vp, FREAD, cred,
 1245                                             p);
 1246                                 if (!openerr)
 1247                                         (void) nfscl_getstateid(vp,
 1248                                             nfhp->nfh_fh, nfhp->nfh_len,
 1249                                             mode, 0, cred, p, &stateid, &lckp);
 1250                         }
 1251                 }
 1252                 if (vap != NULL)
 1253                         error = nfsrpc_setattrrpc(vp, vap, &stateid, cred, p,
 1254                             rnap, attrflagp, stuff);
 1255                 else
 1256                         error = nfsrpc_setaclrpc(vp, cred, p, aclp, &stateid,
 1257                             stuff);
 1258                 if (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD) {
 1259                         NFSLOCKMNT(nmp);
 1260                         nmp->nm_state |= NFSSTA_OPENMODE;
 1261                         NFSUNLOCKMNT(nmp);
 1262                 }
 1263                 if (error == NFSERR_STALESTATEID)
 1264                         nfscl_initiate_recovery(nmp->nm_clp);
 1265                 if (lckp != NULL)
 1266                         nfscl_lockderef(lckp);
 1267                 if (!openerr)
 1268                         (void) nfsrpc_close(vp, 0, p);
 1269                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1270                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1271                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
 1272                         (void) nfs_catnap(PZERO, error, "nfs_setattr");
 1273                 } else if ((error == NFSERR_EXPIRED ||
 1274                     error == NFSERR_BADSTATEID) && clidrev != 0) {
 1275                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 1276                 }
 1277                 retrycnt++;
 1278         } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1279             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1280             error == NFSERR_BADSESSION ||
 1281             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
 1282             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 1283              expireret == 0 && clidrev != 0 && retrycnt < 4) ||
 1284             (error == NFSERR_OPENMODE && mode == NFSV4OPEN_ACCESSREAD &&
 1285              retrycnt < 4));
 1286         if (error && retrycnt >= 4)
 1287                 error = EIO;
 1288         return (error);
 1289 }
 1290 
 1291 static int
 1292 nfsrpc_setattrrpc(vnode_t vp, struct vattr *vap,
 1293     nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
 1294     struct nfsvattr *rnap, int *attrflagp, void *stuff)
 1295 {
 1296         u_int32_t *tl;
 1297         struct nfsrv_descript nfsd, *nd = &nfsd;
 1298         int error;
 1299         nfsattrbit_t attrbits;
 1300 
 1301         *attrflagp = 0;
 1302         NFSCL_REQSTART(nd, NFSPROC_SETATTR, vp);
 1303         if (nd->nd_flag & ND_NFSV4)
 1304                 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 1305         vap->va_type = vnode_vtype(vp);
 1306         nfscl_fillsattr(nd, vap, vp, NFSSATTR_FULL, 0);
 1307         if (nd->nd_flag & ND_NFSV3) {
 1308                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1309                 *tl = newnfs_false;
 1310         } else if (nd->nd_flag & ND_NFSV4) {
 1311                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1312                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1313                 NFSGETATTR_ATTRBIT(&attrbits);
 1314                 (void) nfsrv_putattrbit(nd, &attrbits);
 1315         }
 1316         error = nfscl_request(nd, vp, p, cred, stuff);
 1317         if (error)
 1318                 return (error);
 1319         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
 1320                 error = nfscl_wcc_data(nd, vp, rnap, attrflagp, NULL, stuff);
 1321         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 && !error)
 1322                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 1323         if (!(nd->nd_flag & ND_NFSV3) && !nd->nd_repstat && !error)
 1324                 error = nfscl_postop_attr(nd, rnap, attrflagp, stuff);
 1325         mbuf_freem(nd->nd_mrep);
 1326         if (nd->nd_repstat && !error)
 1327                 error = nd->nd_repstat;
 1328         return (error);
 1329 }
 1330 
 1331 /*
 1332  * nfs lookup rpc
 1333  */
 1334 int
 1335 nfsrpc_lookup(vnode_t dvp, char *name, int len, struct ucred *cred,
 1336     NFSPROC_T *p, struct nfsvattr *dnap, struct nfsvattr *nap,
 1337     struct nfsfh **nfhpp, int *attrflagp, int *dattrflagp, void *stuff)
 1338 {
 1339         u_int32_t *tl;
 1340         struct nfsrv_descript nfsd, *nd = &nfsd;
 1341         struct nfsmount *nmp;
 1342         struct nfsnode *np;
 1343         struct nfsfh *nfhp;
 1344         nfsattrbit_t attrbits;
 1345         int error = 0, lookupp = 0;
 1346 
 1347         *attrflagp = 0;
 1348         *dattrflagp = 0;
 1349         if (vnode_vtype(dvp) != VDIR)
 1350                 return (ENOTDIR);
 1351         nmp = VFSTONFS(vnode_mount(dvp));
 1352         if (len > NFS_MAXNAMLEN)
 1353                 return (ENAMETOOLONG);
 1354         if (NFSHASNFSV4(nmp) && len == 1 &&
 1355                 name[0] == '.') {
 1356                 /*
 1357                  * Just return the current dir's fh.
 1358                  */
 1359                 np = VTONFS(dvp);
 1360                 nfhp = malloc(sizeof (struct nfsfh) +
 1361                         np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
 1362                 nfhp->nfh_len = np->n_fhp->nfh_len;
 1363                 NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
 1364                 *nfhpp = nfhp;
 1365                 return (0);
 1366         }
 1367         if (NFSHASNFSV4(nmp) && len == 2 &&
 1368                 name[0] == '.' && name[1] == '.') {
 1369                 lookupp = 1;
 1370                 NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, dvp);
 1371         } else {
 1372                 NFSCL_REQSTART(nd, NFSPROC_LOOKUP, dvp);
 1373                 (void) nfsm_strtom(nd, name, len);
 1374         }
 1375         if (nd->nd_flag & ND_NFSV4) {
 1376                 NFSGETATTR_ATTRBIT(&attrbits);
 1377                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1378                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 1379                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1380                 (void) nfsrv_putattrbit(nd, &attrbits);
 1381         }
 1382         error = nfscl_request(nd, dvp, p, cred, stuff);
 1383         if (error)
 1384                 return (error);
 1385         if (nd->nd_repstat) {
 1386                 /*
 1387                  * When an NFSv4 Lookupp returns ENOENT, it means that
 1388                  * the lookup is at the root of an fs, so return this dir.
 1389                  */
 1390                 if (nd->nd_repstat == NFSERR_NOENT && lookupp) {
 1391                     np = VTONFS(dvp);
 1392                     nfhp = malloc(sizeof (struct nfsfh) +
 1393                         np->n_fhp->nfh_len, M_NFSFH, M_WAITOK);
 1394                     nfhp->nfh_len = np->n_fhp->nfh_len;
 1395                     NFSBCOPY(np->n_fhp->nfh_fh, nfhp->nfh_fh, nfhp->nfh_len);
 1396                     *nfhpp = nfhp;
 1397                     mbuf_freem(nd->nd_mrep);
 1398                     return (0);
 1399                 }
 1400                 if (nd->nd_flag & ND_NFSV3)
 1401                     error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
 1402                 else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
 1403                     ND_NFSV4) {
 1404                         /* Load the directory attributes. */
 1405                         error = nfsm_loadattr(nd, dnap);
 1406                         if (error == 0)
 1407                                 *dattrflagp = 1;
 1408                 }
 1409                 goto nfsmout;
 1410         }
 1411         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
 1412                 /* Load the directory attributes. */
 1413                 error = nfsm_loadattr(nd, dnap);
 1414                 if (error != 0)
 1415                         goto nfsmout;
 1416                 *dattrflagp = 1;
 1417                 /* Skip over the Lookup and GetFH operation status values. */
 1418                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1419         }
 1420         error = nfsm_getfh(nd, nfhpp);
 1421         if (error)
 1422                 goto nfsmout;
 1423 
 1424         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 1425         if ((nd->nd_flag & ND_NFSV3) && !error)
 1426                 error = nfscl_postop_attr(nd, dnap, dattrflagp, stuff);
 1427 nfsmout:
 1428         mbuf_freem(nd->nd_mrep);
 1429         if (!error && nd->nd_repstat)
 1430                 error = nd->nd_repstat;
 1431         return (error);
 1432 }
 1433 
 1434 /*
 1435  * Do a readlink rpc.
 1436  */
 1437 int
 1438 nfsrpc_readlink(vnode_t vp, struct uio *uiop, struct ucred *cred,
 1439     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 1440 {
 1441         u_int32_t *tl;
 1442         struct nfsrv_descript nfsd, *nd = &nfsd;
 1443         struct nfsnode *np = VTONFS(vp);
 1444         nfsattrbit_t attrbits;
 1445         int error, len, cangetattr = 1;
 1446 
 1447         *attrflagp = 0;
 1448         NFSCL_REQSTART(nd, NFSPROC_READLINK, vp);
 1449         if (nd->nd_flag & ND_NFSV4) {
 1450                 /*
 1451                  * And do a Getattr op.
 1452                  */
 1453                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1454                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1455                 NFSGETATTR_ATTRBIT(&attrbits);
 1456                 (void) nfsrv_putattrbit(nd, &attrbits);
 1457         }
 1458         error = nfscl_request(nd, vp, p, cred, stuff);
 1459         if (error)
 1460                 return (error);
 1461         if (nd->nd_flag & ND_NFSV3)
 1462                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 1463         if (!nd->nd_repstat && !error) {
 1464                 NFSM_STRSIZ(len, NFS_MAXPATHLEN);
 1465                 /*
 1466                  * This seems weird to me, but must have been added to
 1467                  * FreeBSD for some reason. The only thing I can think of
 1468                  * is that there was/is some server that replies with
 1469                  * more link data than it should?
 1470                  */
 1471                 if (len == NFS_MAXPATHLEN) {
 1472                         NFSLOCKNODE(np);
 1473                         if (np->n_size > 0 && np->n_size < NFS_MAXPATHLEN) {
 1474                                 len = np->n_size;
 1475                                 cangetattr = 0;
 1476                         }
 1477                         NFSUNLOCKNODE(np);
 1478                 }
 1479                 error = nfsm_mbufuio(nd, uiop, len);
 1480                 if ((nd->nd_flag & ND_NFSV4) && !error && cangetattr)
 1481                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 1482         }
 1483         if (nd->nd_repstat && !error)
 1484                 error = nd->nd_repstat;
 1485 nfsmout:
 1486         mbuf_freem(nd->nd_mrep);
 1487         return (error);
 1488 }
 1489 
 1490 /*
 1491  * Read operation.
 1492  */
 1493 int
 1494 nfsrpc_read(vnode_t vp, struct uio *uiop, struct ucred *cred,
 1495     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 1496 {
 1497         int error, expireret = 0, retrycnt;
 1498         u_int32_t clidrev = 0;
 1499         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1500         struct nfsnode *np = VTONFS(vp);
 1501         struct ucred *newcred;
 1502         struct nfsfh *nfhp = NULL;
 1503         nfsv4stateid_t stateid;
 1504         void *lckp;
 1505 
 1506         if (nmp->nm_clp != NULL)
 1507                 clidrev = nmp->nm_clp->nfsc_clientidrev;
 1508         newcred = cred;
 1509         if (NFSHASNFSV4(nmp)) {
 1510                 nfhp = np->n_fhp;
 1511                 newcred = NFSNEWCRED(cred);
 1512         }
 1513         retrycnt = 0;
 1514         do {
 1515                 lckp = NULL;
 1516                 if (NFSHASNFSV4(nmp))
 1517                         (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
 1518                             NFSV4OPEN_ACCESSREAD, 0, newcred, p, &stateid,
 1519                             &lckp);
 1520                 error = nfsrpc_readrpc(vp, uiop, newcred, &stateid, p, nap,
 1521                     attrflagp, stuff);
 1522                 if (error == NFSERR_OPENMODE) {
 1523                         NFSLOCKMNT(nmp);
 1524                         nmp->nm_state |= NFSSTA_OPENMODE;
 1525                         NFSUNLOCKMNT(nmp);
 1526                 }
 1527                 if (error == NFSERR_STALESTATEID)
 1528                         nfscl_initiate_recovery(nmp->nm_clp);
 1529                 if (lckp != NULL)
 1530                         nfscl_lockderef(lckp);
 1531                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1532                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1533                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
 1534                         (void) nfs_catnap(PZERO, error, "nfs_read");
 1535                 } else if ((error == NFSERR_EXPIRED ||
 1536                     error == NFSERR_BADSTATEID) && clidrev != 0) {
 1537                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 1538                 }
 1539                 retrycnt++;
 1540         } while (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1541             error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1542             error == NFSERR_BADSESSION ||
 1543             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
 1544             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 1545              expireret == 0 && clidrev != 0 && retrycnt < 4) ||
 1546             (error == NFSERR_OPENMODE && retrycnt < 4));
 1547         if (error && retrycnt >= 4)
 1548                 error = EIO;
 1549         if (NFSHASNFSV4(nmp))
 1550                 NFSFREECRED(newcred);
 1551         return (error);
 1552 }
 1553 
 1554 /*
 1555  * The actual read RPC.
 1556  */
 1557 static int
 1558 nfsrpc_readrpc(vnode_t vp, struct uio *uiop, struct ucred *cred,
 1559     nfsv4stateid_t *stateidp, NFSPROC_T *p, struct nfsvattr *nap,
 1560     int *attrflagp, void *stuff)
 1561 {
 1562         u_int32_t *tl;
 1563         int error = 0, len, retlen, tsiz, eof = 0;
 1564         struct nfsrv_descript nfsd;
 1565         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1566         struct nfsrv_descript *nd = &nfsd;
 1567         int rsize;
 1568         off_t tmp_off;
 1569 
 1570         *attrflagp = 0;
 1571         tsiz = uio_uio_resid(uiop);
 1572         tmp_off = uiop->uio_offset + tsiz;
 1573         NFSLOCKMNT(nmp);
 1574         if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
 1575                 NFSUNLOCKMNT(nmp);
 1576                 return (EFBIG);
 1577         }
 1578         rsize = nmp->nm_rsize;
 1579         NFSUNLOCKMNT(nmp);
 1580         nd->nd_mrep = NULL;
 1581         while (tsiz > 0) {
 1582                 *attrflagp = 0;
 1583                 len = (tsiz > rsize) ? rsize : tsiz;
 1584                 NFSCL_REQSTART(nd, NFSPROC_READ, vp);
 1585                 if (nd->nd_flag & ND_NFSV4)
 1586                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 1587                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED * 3);
 1588                 if (nd->nd_flag & ND_NFSV2) {
 1589                         *tl++ = txdr_unsigned(uiop->uio_offset);
 1590                         *tl++ = txdr_unsigned(len);
 1591                         *tl = 0;
 1592                 } else {
 1593                         txdr_hyper(uiop->uio_offset, tl);
 1594                         *(tl + 2) = txdr_unsigned(len);
 1595                 }
 1596                 /*
 1597                  * Since I can't do a Getattr for NFSv4 for Write, there
 1598                  * doesn't seem any point in doing one here, either.
 1599                  * (See the comment in nfsrpc_writerpc() for more info.)
 1600                  */
 1601                 error = nfscl_request(nd, vp, p, cred, stuff);
 1602                 if (error)
 1603                         return (error);
 1604                 if (nd->nd_flag & ND_NFSV3) {
 1605                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 1606                 } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV2)) {
 1607                         error = nfsm_loadattr(nd, nap);
 1608                         if (!error)
 1609                                 *attrflagp = 1;
 1610                 }
 1611                 if (nd->nd_repstat || error) {
 1612                         if (!error)
 1613                                 error = nd->nd_repstat;
 1614                         goto nfsmout;
 1615                 }
 1616                 if (nd->nd_flag & ND_NFSV3) {
 1617                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1618                         eof = fxdr_unsigned(int, *(tl + 1));
 1619                 } else if (nd->nd_flag & ND_NFSV4) {
 1620                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1621                         eof = fxdr_unsigned(int, *tl);
 1622                 }
 1623                 NFSM_STRSIZ(retlen, len);
 1624                 error = nfsm_mbufuio(nd, uiop, retlen);
 1625                 if (error)
 1626                         goto nfsmout;
 1627                 mbuf_freem(nd->nd_mrep);
 1628                 nd->nd_mrep = NULL;
 1629                 tsiz -= retlen;
 1630                 if (!(nd->nd_flag & ND_NFSV2)) {
 1631                         if (eof || retlen == 0)
 1632                                 tsiz = 0;
 1633                 } else if (retlen < len)
 1634                         tsiz = 0;
 1635         }
 1636         return (0);
 1637 nfsmout:
 1638         if (nd->nd_mrep != NULL)
 1639                 mbuf_freem(nd->nd_mrep);
 1640         return (error);
 1641 }
 1642 
 1643 /*
 1644  * nfs write operation
 1645  * When called_from_strategy != 0, it should return EIO for an error that
 1646  * indicates recovery is in progress, so that the buffer will be left
 1647  * dirty and be written back to the server later. If it loops around,
 1648  * the recovery thread could get stuck waiting for the buffer and recovery
 1649  * will then deadlock.
 1650  */
 1651 int
 1652 nfsrpc_write(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
 1653     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 1654     void *stuff, int called_from_strategy)
 1655 {
 1656         int error, expireret = 0, retrycnt, nostateid;
 1657         u_int32_t clidrev = 0;
 1658         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1659         struct nfsnode *np = VTONFS(vp);
 1660         struct ucred *newcred;
 1661         struct nfsfh *nfhp = NULL;
 1662         nfsv4stateid_t stateid;
 1663         void *lckp;
 1664 
 1665         KASSERT(*must_commit >= 0 && *must_commit <= 2,
 1666             ("nfsrpc_write: must_commit out of range=%d", *must_commit));
 1667         if (nmp->nm_clp != NULL)
 1668                 clidrev = nmp->nm_clp->nfsc_clientidrev;
 1669         newcred = cred;
 1670         if (NFSHASNFSV4(nmp)) {
 1671                 newcred = NFSNEWCRED(cred);
 1672                 nfhp = np->n_fhp;
 1673         }
 1674         retrycnt = 0;
 1675         do {
 1676                 lckp = NULL;
 1677                 nostateid = 0;
 1678                 if (NFSHASNFSV4(nmp)) {
 1679                         (void)nfscl_getstateid(vp, nfhp->nfh_fh, nfhp->nfh_len,
 1680                             NFSV4OPEN_ACCESSWRITE, 0, newcred, p, &stateid,
 1681                             &lckp);
 1682                         if (stateid.other[0] == 0 && stateid.other[1] == 0 &&
 1683                             stateid.other[2] == 0) {
 1684                                 nostateid = 1;
 1685                                 NFSCL_DEBUG(1, "stateid0 in write\n");
 1686                         }
 1687                 }
 1688 
 1689                 /*
 1690                  * If there is no stateid for NFSv4, it means this is an
 1691                  * extraneous write after close. Basically a poorly
 1692                  * implemented buffer cache. Just don't do the write.
 1693                  */
 1694                 if (nostateid)
 1695                         error = 0;
 1696                 else
 1697                         error = nfsrpc_writerpc(vp, uiop, iomode, must_commit,
 1698                             newcred, &stateid, p, nap, attrflagp, stuff);
 1699                 if (error == NFSERR_STALESTATEID)
 1700                         nfscl_initiate_recovery(nmp->nm_clp);
 1701                 if (lckp != NULL)
 1702                         nfscl_lockderef(lckp);
 1703                 if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 1704                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 1705                     error == NFSERR_OLDSTATEID || error == NFSERR_BADSESSION) {
 1706                         (void) nfs_catnap(PZERO, error, "nfs_write");
 1707                 } else if ((error == NFSERR_EXPIRED ||
 1708                     error == NFSERR_BADSTATEID) && clidrev != 0) {
 1709                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 1710                 }
 1711                 retrycnt++;
 1712         } while (error == NFSERR_GRACE || error == NFSERR_DELAY ||
 1713             ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
 1714               error == NFSERR_STALEDONTRECOVER) && called_from_strategy == 0) ||
 1715             (error == NFSERR_OLDSTATEID && retrycnt < 20) ||
 1716             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 1717              expireret == 0 && clidrev != 0 && retrycnt < 4));
 1718         if (error != 0 && (retrycnt >= 4 ||
 1719             ((error == NFSERR_STALESTATEID || error == NFSERR_BADSESSION ||
 1720               error == NFSERR_STALEDONTRECOVER) && called_from_strategy != 0)))
 1721                 error = EIO;
 1722         if (NFSHASNFSV4(nmp))
 1723                 NFSFREECRED(newcred);
 1724         return (error);
 1725 }
 1726 
 1727 /*
 1728  * The actual write RPC.
 1729  */
 1730 static int
 1731 nfsrpc_writerpc(vnode_t vp, struct uio *uiop, int *iomode,
 1732     int *must_commit, struct ucred *cred, nfsv4stateid_t *stateidp,
 1733     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 1734 {
 1735         u_int32_t *tl;
 1736         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 1737         struct nfsnode *np = VTONFS(vp);
 1738         int error = 0, len, tsiz, rlen, commit, committed = NFSWRITE_FILESYNC;
 1739         int wccflag = 0, wsize;
 1740         int32_t backup;
 1741         struct nfsrv_descript nfsd;
 1742         struct nfsrv_descript *nd = &nfsd;
 1743         nfsattrbit_t attrbits;
 1744         off_t tmp_off;
 1745 
 1746         KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
 1747         *attrflagp = 0;
 1748         tsiz = uio_uio_resid(uiop);
 1749         tmp_off = uiop->uio_offset + tsiz;
 1750         NFSLOCKMNT(nmp);
 1751         if (tmp_off > nmp->nm_maxfilesize || tmp_off < uiop->uio_offset) {
 1752                 NFSUNLOCKMNT(nmp);
 1753                 return (EFBIG);
 1754         }
 1755         wsize = nmp->nm_wsize;
 1756         NFSUNLOCKMNT(nmp);
 1757         nd->nd_mrep = NULL;     /* NFSv2 sometimes does a write with */
 1758         nd->nd_repstat = 0;     /* uio_resid == 0, so the while is not done */
 1759         while (tsiz > 0) {
 1760                 *attrflagp = 0;
 1761                 len = (tsiz > wsize) ? wsize : tsiz;
 1762                 NFSCL_REQSTART(nd, NFSPROC_WRITE, vp);
 1763                 if (nd->nd_flag & ND_NFSV4) {
 1764                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 1765                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+2*NFSX_UNSIGNED);
 1766                         txdr_hyper(uiop->uio_offset, tl);
 1767                         tl += 2;
 1768                         *tl++ = txdr_unsigned(*iomode);
 1769                         *tl = txdr_unsigned(len);
 1770                 } else if (nd->nd_flag & ND_NFSV3) {
 1771                         NFSM_BUILD(tl, u_int32_t *, NFSX_HYPER+3*NFSX_UNSIGNED);
 1772                         txdr_hyper(uiop->uio_offset, tl);
 1773                         tl += 2;
 1774                         *tl++ = txdr_unsigned(len);
 1775                         *tl++ = txdr_unsigned(*iomode);
 1776                         *tl = txdr_unsigned(len);
 1777                 } else {
 1778                         u_int32_t x;
 1779 
 1780                         NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1781                         /*
 1782                          * Not sure why someone changed this, since the
 1783                          * RFC clearly states that "beginoffset" and
 1784                          * "totalcount" are ignored, but it wouldn't
 1785                          * surprise me if there's a busted server out there.
 1786                          */
 1787                         /* Set both "begin" and "current" to non-garbage. */
 1788                         x = txdr_unsigned((u_int32_t)uiop->uio_offset);
 1789                         *tl++ = x;      /* "begin offset" */
 1790                         *tl++ = x;      /* "current offset" */
 1791                         x = txdr_unsigned(len);
 1792                         *tl++ = x;      /* total to this offset */
 1793                         *tl = x;        /* size of this write */
 1794 
 1795                 }
 1796                 nfsm_uiombuf(nd, uiop, len);
 1797                 /*
 1798                  * Although it is tempting to do a normal Getattr Op in the
 1799                  * NFSv4 compound, the result can be a nearly hung client
 1800                  * system if the Getattr asks for Owner and/or OwnerGroup.
 1801                  * It occurs when the client can't map either the Owner or
 1802                  * Owner_group name in the Getattr reply to a uid/gid. When
 1803                  * there is a cache miss, the kernel does an upcall to the
 1804                  * nfsuserd. Then, it can try and read the local /etc/passwd
 1805                  * or /etc/group file. It can then block in getnewbuf(),
 1806                  * waiting for dirty writes to be pushed to the NFS server.
 1807                  * The only reason this doesn't result in a complete
 1808                  * deadlock, is that the upcall times out and allows
 1809                  * the write to complete. However, progress is so slow
 1810                  * that it might just as well be deadlocked.
 1811                  * As such, we get the rest of the attributes, but not
 1812                  * Owner or Owner_group.
 1813                  * nb: nfscl_loadattrcache() needs to be told that these
 1814                  *     partial attributes from a write rpc are being
 1815                  *     passed in, via a argument flag.
 1816                  */
 1817                 if (nd->nd_flag & ND_NFSV4) {
 1818                         NFSWRITEGETATTR_ATTRBIT(&attrbits);
 1819                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1820                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1821                         (void) nfsrv_putattrbit(nd, &attrbits);
 1822                 }
 1823                 error = nfscl_request(nd, vp, p, cred, stuff);
 1824                 if (error)
 1825                         return (error);
 1826                 if (nd->nd_repstat) {
 1827                         /*
 1828                          * In case the rpc gets retried, roll
 1829                          * the uio fileds changed by nfsm_uiombuf()
 1830                          * back.
 1831                          */
 1832                         uiop->uio_offset -= len;
 1833                         uio_uio_resid_add(uiop, len);
 1834                         uio_iov_base_add(uiop, -len);
 1835                         uio_iov_len_add(uiop, len);
 1836                 }
 1837                 if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 1838                         error = nfscl_wcc_data(nd, vp, nap, attrflagp,
 1839                             &wccflag, stuff);
 1840                         if (error)
 1841                                 goto nfsmout;
 1842                 }
 1843                 if (!nd->nd_repstat) {
 1844                         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 1845                                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED
 1846                                         + NFSX_VERF);
 1847                                 rlen = fxdr_unsigned(int, *tl++);
 1848                                 if (rlen == 0) {
 1849                                         error = NFSERR_IO;
 1850                                         goto nfsmout;
 1851                                 } else if (rlen < len) {
 1852                                         backup = len - rlen;
 1853                                         uio_iov_base_add(uiop, -(backup));
 1854                                         uio_iov_len_add(uiop, backup);
 1855                                         uiop->uio_offset -= backup;
 1856                                         uio_uio_resid_add(uiop, backup);
 1857                                         len = rlen;
 1858                                 }
 1859                                 commit = fxdr_unsigned(int, *tl++);
 1860 
 1861                                 /*
 1862                                  * Return the lowest commitment level
 1863                                  * obtained by any of the RPCs.
 1864                                  */
 1865                                 if (committed == NFSWRITE_FILESYNC)
 1866                                         committed = commit;
 1867                                 else if (committed == NFSWRITE_DATASYNC &&
 1868                                         commit == NFSWRITE_UNSTABLE)
 1869                                         committed = commit;
 1870                                 NFSLOCKMNT(nmp);
 1871                                 if (!NFSHASWRITEVERF(nmp)) {
 1872                                         NFSBCOPY((caddr_t)tl,
 1873                                             (caddr_t)&nmp->nm_verf[0],
 1874                                             NFSX_VERF);
 1875                                         NFSSETWRITEVERF(nmp);
 1876                                 } else if (NFSBCMP(tl, nmp->nm_verf,
 1877                                     NFSX_VERF) && *must_commit != 2) {
 1878                                         *must_commit = 1;
 1879                                         NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
 1880                                 }
 1881                                 NFSUNLOCKMNT(nmp);
 1882                         }
 1883                         if (nd->nd_flag & ND_NFSV4)
 1884                                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1885                         if (nd->nd_flag & (ND_NFSV2 | ND_NFSV4)) {
 1886                                 error = nfsm_loadattr(nd, nap);
 1887                                 if (!error)
 1888                                         *attrflagp = NFS_LATTR_NOSHRINK;
 1889                         }
 1890                 } else {
 1891                         error = nd->nd_repstat;
 1892                 }
 1893                 if (error)
 1894                         goto nfsmout;
 1895                 NFSWRITERPC_SETTIME(wccflag, np, nap, (nd->nd_flag & ND_NFSV4));
 1896                 mbuf_freem(nd->nd_mrep);
 1897                 nd->nd_mrep = NULL;
 1898                 tsiz -= len;
 1899         }
 1900 nfsmout:
 1901         if (nd->nd_mrep != NULL)
 1902                 mbuf_freem(nd->nd_mrep);
 1903         *iomode = committed;
 1904         if (nd->nd_repstat && !error)
 1905                 error = nd->nd_repstat;
 1906         return (error);
 1907 }
 1908 
 1909 /*
 1910  * nfs mknod rpc
 1911  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
 1912  * mode set to specify the file type and the size field for rdev.
 1913  */
 1914 int
 1915 nfsrpc_mknod(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 1916     u_int32_t rdev, enum vtype vtyp, struct ucred *cred, NFSPROC_T *p,
 1917     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
 1918     int *attrflagp, int *dattrflagp, void *dstuff)
 1919 {
 1920         u_int32_t *tl;
 1921         int error = 0;
 1922         struct nfsrv_descript nfsd, *nd = &nfsd;
 1923         nfsattrbit_t attrbits;
 1924 
 1925         *nfhpp = NULL;
 1926         *attrflagp = 0;
 1927         *dattrflagp = 0;
 1928         if (namelen > NFS_MAXNAMLEN)
 1929                 return (ENAMETOOLONG);
 1930         NFSCL_REQSTART(nd, NFSPROC_MKNOD, dvp);
 1931         if (nd->nd_flag & ND_NFSV4) {
 1932                 if (vtyp == VBLK || vtyp == VCHR) {
 1933                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 1934                         *tl++ = vtonfsv34_type(vtyp);
 1935                         *tl++ = txdr_unsigned(NFSMAJOR(rdev));
 1936                         *tl = txdr_unsigned(NFSMINOR(rdev));
 1937                 } else {
 1938                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1939                         *tl = vtonfsv34_type(vtyp);
 1940                 }
 1941         }
 1942         (void) nfsm_strtom(nd, name, namelen);
 1943         if (nd->nd_flag & ND_NFSV3) {
 1944                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 1945                 *tl = vtonfsv34_type(vtyp);
 1946         }
 1947         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
 1948                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 1949         if ((nd->nd_flag & ND_NFSV3) &&
 1950             (vtyp == VCHR || vtyp == VBLK)) {
 1951                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1952                 *tl++ = txdr_unsigned(NFSMAJOR(rdev));
 1953                 *tl = txdr_unsigned(NFSMINOR(rdev));
 1954         }
 1955         if (nd->nd_flag & ND_NFSV4) {
 1956                 NFSGETATTR_ATTRBIT(&attrbits);
 1957                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1958                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 1959                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 1960                 (void) nfsrv_putattrbit(nd, &attrbits);
 1961         }
 1962         if (nd->nd_flag & ND_NFSV2)
 1963                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZERDEV, rdev);
 1964         error = nfscl_request(nd, dvp, p, cred, dstuff);
 1965         if (error)
 1966                 return (error);
 1967         if (nd->nd_flag & ND_NFSV4)
 1968                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 1969         if (!nd->nd_repstat) {
 1970                 if (nd->nd_flag & ND_NFSV4) {
 1971                         NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1972                         error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 1973                         if (error)
 1974                                 goto nfsmout;
 1975                 }
 1976                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 1977                 if (error)
 1978                         goto nfsmout;
 1979         }
 1980         if (nd->nd_flag & ND_NFSV3)
 1981                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 1982         if (!error && nd->nd_repstat)
 1983                 error = nd->nd_repstat;
 1984 nfsmout:
 1985         mbuf_freem(nd->nd_mrep);
 1986         return (error);
 1987 }
 1988 
 1989 /*
 1990  * nfs file create call
 1991  * Mostly just call the approriate routine. (I separated out v4, so that
 1992  * error recovery wouldn't be as difficult.)
 1993  */
 1994 int
 1995 nfsrpc_create(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 1996     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
 1997     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
 1998     int *attrflagp, int *dattrflagp, void *dstuff)
 1999 {
 2000         int error = 0, newone, expireret = 0, retrycnt, unlocked;
 2001         struct nfsclowner *owp;
 2002         struct nfscldeleg *dp;
 2003         struct nfsmount *nmp = VFSTONFS(vnode_mount(dvp));
 2004         u_int32_t clidrev;
 2005 
 2006         if (NFSHASNFSV4(nmp)) {
 2007             retrycnt = 0;
 2008             do {
 2009                 dp = NULL;
 2010                 error = nfscl_open(dvp, NULL, 0, (NFSV4OPEN_ACCESSWRITE |
 2011                     NFSV4OPEN_ACCESSREAD), 0, cred, p, &owp, NULL, &newone,
 2012                     NULL, 1, true);
 2013                 if (error)
 2014                         return (error);
 2015                 if (nmp->nm_clp != NULL)
 2016                         clidrev = nmp->nm_clp->nfsc_clientidrev;
 2017                 else
 2018                         clidrev = 0;
 2019                 if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 ||
 2020                     nfs_numnfscbd == 0 || retrycnt > 0)
 2021                         error = nfsrpc_createv4(dvp, name, namelen, vap, cverf,
 2022                           fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
 2023                           attrflagp, dattrflagp, dstuff, &unlocked);
 2024                 else
 2025                         error = nfsrpc_getcreatelayout(dvp, name, namelen, vap,
 2026                           cverf, fmode, owp, &dp, cred, p, dnap, nnap, nfhpp,
 2027                           attrflagp, dattrflagp, dstuff, &unlocked);
 2028                 /*
 2029                  * There is no need to invalidate cached attributes here,
 2030                  * since new post-delegation issue attributes are always
 2031                  * returned by nfsrpc_createv4() and these will update the
 2032                  * attribute cache.
 2033                  */
 2034                 if (dp != NULL)
 2035                         (void) nfscl_deleg(nmp->nm_mountp, owp->nfsow_clp,
 2036                             (*nfhpp)->nfh_fh, (*nfhpp)->nfh_len, cred, p, &dp);
 2037                 nfscl_ownerrelease(nmp, owp, error, newone, unlocked);
 2038                 if (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
 2039                     error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 2040                     error == NFSERR_BADSESSION) {
 2041                         (void) nfs_catnap(PZERO, error, "nfs_open");
 2042                 } else if ((error == NFSERR_EXPIRED ||
 2043                     error == NFSERR_BADSTATEID) && clidrev != 0) {
 2044                         expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 2045                         retrycnt++;
 2046                 }
 2047             } while (error == NFSERR_GRACE || error == NFSERR_STALECLIENTID ||
 2048                 error == NFSERR_STALEDONTRECOVER || error == NFSERR_DELAY ||
 2049                 error == NFSERR_BADSESSION ||
 2050                 ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 2051                  expireret == 0 && clidrev != 0 && retrycnt < 4));
 2052             if (error && retrycnt >= 4)
 2053                     error = EIO;
 2054         } else {
 2055                 error = nfsrpc_createv23(dvp, name, namelen, vap, cverf,
 2056                     fmode, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
 2057                     dstuff);
 2058         }
 2059         return (error);
 2060 }
 2061 
 2062 /*
 2063  * The create rpc for v2 and 3.
 2064  */
 2065 static int
 2066 nfsrpc_createv23(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 2067     nfsquad_t cverf, int fmode, struct ucred *cred, NFSPROC_T *p,
 2068     struct nfsvattr *dnap, struct nfsvattr *nnap, struct nfsfh **nfhpp,
 2069     int *attrflagp, int *dattrflagp, void *dstuff)
 2070 {
 2071         u_int32_t *tl;
 2072         int error = 0;
 2073         struct nfsrv_descript nfsd, *nd = &nfsd;
 2074 
 2075         *nfhpp = NULL;
 2076         *attrflagp = 0;
 2077         *dattrflagp = 0;
 2078         if (namelen > NFS_MAXNAMLEN)
 2079                 return (ENAMETOOLONG);
 2080         NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
 2081         (void) nfsm_strtom(nd, name, namelen);
 2082         if (nd->nd_flag & ND_NFSV3) {
 2083                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2084                 if (fmode & O_EXCL) {
 2085                         *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
 2086                         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 2087                         *tl++ = cverf.lval[0];
 2088                         *tl = cverf.lval[1];
 2089                 } else {
 2090                         *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
 2091                         nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2092                 }
 2093         } else {
 2094                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZE0, 0);
 2095         }
 2096         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2097         if (error)
 2098                 return (error);
 2099         if (nd->nd_repstat == 0) {
 2100                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 2101                 if (error)
 2102                         goto nfsmout;
 2103         }
 2104         if (nd->nd_flag & ND_NFSV3)
 2105                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2106         if (nd->nd_repstat != 0 && error == 0)
 2107                 error = nd->nd_repstat;
 2108 nfsmout:
 2109         mbuf_freem(nd->nd_mrep);
 2110         return (error);
 2111 }
 2112 
 2113 static int
 2114 nfsrpc_createv4(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 2115     nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
 2116     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 2117     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
 2118     int *dattrflagp, void *dstuff, int *unlockedp)
 2119 {
 2120         u_int32_t *tl;
 2121         int error = 0, deleg, newone, ret, acesize, limitby;
 2122         struct nfsrv_descript nfsd, *nd = &nfsd;
 2123         struct nfsclopen *op;
 2124         struct nfscldeleg *dp = NULL;
 2125         struct nfsnode *np;
 2126         struct nfsfh *nfhp;
 2127         nfsattrbit_t attrbits;
 2128         nfsv4stateid_t stateid;
 2129         u_int32_t rflags;
 2130         struct nfsmount *nmp;
 2131         struct nfsclsession *tsep;
 2132 
 2133         nmp = VFSTONFS(dvp->v_mount);
 2134         np = VTONFS(dvp);
 2135         *unlockedp = 0;
 2136         *nfhpp = NULL;
 2137         *dpp = NULL;
 2138         *attrflagp = 0;
 2139         *dattrflagp = 0;
 2140         if (namelen > NFS_MAXNAMLEN)
 2141                 return (ENAMETOOLONG);
 2142         NFSCL_REQSTART(nd, NFSPROC_CREATE, dvp);
 2143         /*
 2144          * For V4, this is actually an Open op.
 2145          */
 2146         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 2147         *tl++ = txdr_unsigned(owp->nfsow_seqid);
 2148         *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
 2149             NFSV4OPEN_ACCESSREAD);
 2150         *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
 2151         tsep = nfsmnt_mdssession(nmp);
 2152         *tl++ = tsep->nfsess_clientid.lval[0];
 2153         *tl = tsep->nfsess_clientid.lval[1];
 2154         (void) nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
 2155         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2156         *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
 2157         if (fmode & O_EXCL) {
 2158                 if (NFSHASNFSV4N(nmp)) {
 2159                         if (NFSHASSESSPERSIST(nmp)) {
 2160                                 /* Use GUARDED for persistent sessions. */
 2161                                 *tl = txdr_unsigned(NFSCREATE_GUARDED);
 2162                                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2163                         } else {
 2164                                 /* Otherwise, use EXCLUSIVE4_1. */
 2165                                 *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
 2166                                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 2167                                 *tl++ = cverf.lval[0];
 2168                                 *tl = cverf.lval[1];
 2169                                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2170                         }
 2171                 } else {
 2172                         /* NFSv4.0 */
 2173                         *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE);
 2174                         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 2175                         *tl++ = cverf.lval[0];
 2176                         *tl = cverf.lval[1];
 2177                 }
 2178         } else {
 2179                 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
 2180                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2181         }
 2182         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2183         *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
 2184         (void) nfsm_strtom(nd, name, namelen);
 2185         /* Get the new file's handle and attributes. */
 2186         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2187         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 2188         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2189         NFSGETATTR_ATTRBIT(&attrbits);
 2190         (void) nfsrv_putattrbit(nd, &attrbits);
 2191         /* Get the directory's post-op attributes. */
 2192         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2193         *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2194         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
 2195         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2196         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2197         (void) nfsrv_putattrbit(nd, &attrbits);
 2198         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2199         if (error)
 2200                 return (error);
 2201         NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
 2202         if (nd->nd_repstat == 0) {
 2203                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
 2204                     6 * NFSX_UNSIGNED);
 2205                 stateid.seqid = *tl++;
 2206                 stateid.other[0] = *tl++;
 2207                 stateid.other[1] = *tl++;
 2208                 stateid.other[2] = *tl;
 2209                 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
 2210                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 2211                 if (error)
 2212                         goto nfsmout;
 2213                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2214                 deleg = fxdr_unsigned(int, *tl);
 2215                 if (deleg == NFSV4OPEN_DELEGATEREAD ||
 2216                     deleg == NFSV4OPEN_DELEGATEWRITE) {
 2217                         if (!(owp->nfsow_clp->nfsc_flags &
 2218                               NFSCLFLAGS_FIRSTDELEG))
 2219                                 owp->nfsow_clp->nfsc_flags |=
 2220                                   (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
 2221                         dp = malloc(
 2222                             sizeof (struct nfscldeleg) + NFSX_V4FHMAX,
 2223                             M_NFSCLDELEG, M_WAITOK);
 2224                         LIST_INIT(&dp->nfsdl_owner);
 2225                         LIST_INIT(&dp->nfsdl_lock);
 2226                         dp->nfsdl_clp = owp->nfsow_clp;
 2227                         newnfs_copyincred(cred, &dp->nfsdl_cred);
 2228                         nfscl_lockinit(&dp->nfsdl_rwlock);
 2229                         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
 2230                             NFSX_UNSIGNED);
 2231                         dp->nfsdl_stateid.seqid = *tl++;
 2232                         dp->nfsdl_stateid.other[0] = *tl++;
 2233                         dp->nfsdl_stateid.other[1] = *tl++;
 2234                         dp->nfsdl_stateid.other[2] = *tl++;
 2235                         ret = fxdr_unsigned(int, *tl);
 2236                         if (deleg == NFSV4OPEN_DELEGATEWRITE) {
 2237                                 dp->nfsdl_flags = NFSCLDL_WRITE;
 2238                                 /*
 2239                                  * Indicates how much the file can grow.
 2240                                  */
 2241                                 NFSM_DISSECT(tl, u_int32_t *,
 2242                                     3 * NFSX_UNSIGNED);
 2243                                 limitby = fxdr_unsigned(int, *tl++);
 2244                                 switch (limitby) {
 2245                                 case NFSV4OPEN_LIMITSIZE:
 2246                                         dp->nfsdl_sizelimit = fxdr_hyper(tl);
 2247                                         break;
 2248                                 case NFSV4OPEN_LIMITBLOCKS:
 2249                                         dp->nfsdl_sizelimit =
 2250                                             fxdr_unsigned(u_int64_t, *tl++);
 2251                                         dp->nfsdl_sizelimit *=
 2252                                             fxdr_unsigned(u_int64_t, *tl);
 2253                                         break;
 2254                                 default:
 2255                                         error = NFSERR_BADXDR;
 2256                                         goto nfsmout;
 2257                                 }
 2258                         } else {
 2259                                 dp->nfsdl_flags = NFSCLDL_READ;
 2260                         }
 2261                         if (ret)
 2262                                 dp->nfsdl_flags |= NFSCLDL_RECALL;
 2263                         error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
 2264                             &acesize, p);
 2265                         if (error)
 2266                                 goto nfsmout;
 2267                 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
 2268                         error = NFSERR_BADXDR;
 2269                         goto nfsmout;
 2270                 }
 2271                 error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 2272                 if (error)
 2273                         goto nfsmout;
 2274                 /* Get rid of the PutFH and Getattr status values. */
 2275                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 2276                 /* Load the directory attributes. */
 2277                 error = nfsm_loadattr(nd, dnap);
 2278                 if (error)
 2279                         goto nfsmout;
 2280                 *dattrflagp = 1;
 2281                 if (dp != NULL && *attrflagp) {
 2282                         dp->nfsdl_change = nnap->na_filerev;
 2283                         dp->nfsdl_modtime = nnap->na_mtime;
 2284                         dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
 2285                 }
 2286                 /*
 2287                  * We can now complete the Open state.
 2288                  */
 2289                 nfhp = *nfhpp;
 2290                 if (dp != NULL) {
 2291                         dp->nfsdl_fhlen = nfhp->nfh_len;
 2292                         NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh, nfhp->nfh_len);
 2293                 }
 2294                 /*
 2295                  * Get an Open structure that will be
 2296                  * attached to the OpenOwner, acquired already.
 2297                  */
 2298                 error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 
 2299                     (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
 2300                     cred, p, NULL, &op, &newone, NULL, 0, false);
 2301                 if (error)
 2302                         goto nfsmout;
 2303                 op->nfso_stateid = stateid;
 2304                 newnfs_copyincred(cred, &op->nfso_cred);
 2305                 if ((rflags & NFSV4OPEN_RESULTCONFIRM)) {
 2306                     do {
 2307                         ret = nfsrpc_openconfirm(dvp, nfhp->nfh_fh,
 2308                             nfhp->nfh_len, op, cred, p);
 2309                         if (ret == NFSERR_DELAY)
 2310                             (void) nfs_catnap(PZERO, ret, "nfs_create");
 2311                     } while (ret == NFSERR_DELAY);
 2312                     error = ret;
 2313                 }
 2314 
 2315                 /*
 2316                  * If the server is handing out delegations, but we didn't
 2317                  * get one because an OpenConfirm was required, try the
 2318                  * Open again, to get a delegation. This is a harmless no-op,
 2319                  * from a server's point of view.
 2320                  */
 2321                 if ((rflags & NFSV4OPEN_RESULTCONFIRM) &&
 2322                     (owp->nfsow_clp->nfsc_flags & NFSCLFLAGS_GOTDELEG) &&
 2323                     !error && dp == NULL) {
 2324                     do {
 2325                         ret = nfsrpc_openrpc(VFSTONFS(vnode_mount(dvp)), dvp,
 2326                             np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
 2327                             nfhp->nfh_fh, nfhp->nfh_len,
 2328                             (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), op,
 2329                             name, namelen, &dp, 0, 0x0, cred, p, 0, 1);
 2330                         if (ret == NFSERR_DELAY)
 2331                             (void) nfs_catnap(PZERO, ret, "nfs_crt2");
 2332                     } while (ret == NFSERR_DELAY);
 2333                     if (ret) {
 2334                         if (dp != NULL) {
 2335                                 free(dp, M_NFSCLDELEG);
 2336                                 dp = NULL;
 2337                         }
 2338                         if (ret == NFSERR_STALECLIENTID ||
 2339                             ret == NFSERR_STALEDONTRECOVER ||
 2340                             ret == NFSERR_BADSESSION)
 2341                                 error = ret;
 2342                     }
 2343                 }
 2344                 nfscl_openrelease(nmp, op, error, newone);
 2345                 *unlockedp = 1;
 2346         }
 2347         if (nd->nd_repstat != 0 && error == 0)
 2348                 error = nd->nd_repstat;
 2349         if (error == NFSERR_STALECLIENTID)
 2350                 nfscl_initiate_recovery(owp->nfsow_clp);
 2351 nfsmout:
 2352         if (!error)
 2353                 *dpp = dp;
 2354         else if (dp != NULL)
 2355                 free(dp, M_NFSCLDELEG);
 2356         mbuf_freem(nd->nd_mrep);
 2357         return (error);
 2358 }
 2359 
 2360 /*
 2361  * Nfs remove rpc
 2362  */
 2363 int
 2364 nfsrpc_remove(vnode_t dvp, char *name, int namelen, vnode_t vp,
 2365     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp,
 2366     void *dstuff)
 2367 {
 2368         u_int32_t *tl;
 2369         struct nfsrv_descript nfsd, *nd = &nfsd;
 2370         struct nfsnode *np;
 2371         struct nfsmount *nmp;
 2372         nfsv4stateid_t dstateid;
 2373         int error, ret = 0, i;
 2374 
 2375         *dattrflagp = 0;
 2376         if (namelen > NFS_MAXNAMLEN)
 2377                 return (ENAMETOOLONG);
 2378         nmp = VFSTONFS(vnode_mount(dvp));
 2379 tryagain:
 2380         if (NFSHASNFSV4(nmp) && ret == 0) {
 2381                 ret = nfscl_removedeleg(vp, p, &dstateid);
 2382                 if (ret == 1) {
 2383                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGREMOVE, vp);
 2384                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
 2385                             NFSX_UNSIGNED);
 2386                         if (NFSHASNFSV4N(nmp))
 2387                                 *tl++ = 0;
 2388                         else
 2389                                 *tl++ = dstateid.seqid;
 2390                         *tl++ = dstateid.other[0];
 2391                         *tl++ = dstateid.other[1];
 2392                         *tl++ = dstateid.other[2];
 2393                         *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2394                         np = VTONFS(dvp);
 2395                         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
 2396                             np->n_fhp->nfh_len, 0);
 2397                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2398                         *tl = txdr_unsigned(NFSV4OP_REMOVE);
 2399                 }
 2400         } else {
 2401                 ret = 0;
 2402         }
 2403         if (ret == 0)
 2404                 NFSCL_REQSTART(nd, NFSPROC_REMOVE, dvp);
 2405         (void) nfsm_strtom(nd, name, namelen);
 2406         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2407         if (error)
 2408                 return (error);
 2409         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 2410                 /* For NFSv4, parse out any Delereturn replies. */
 2411                 if (ret > 0 && nd->nd_repstat != 0 &&
 2412                     (nd->nd_flag & ND_NOMOREDATA)) {
 2413                         /*
 2414                          * If the Delegreturn failed, try again without
 2415                          * it. The server will Recall, as required.
 2416                          */
 2417                         mbuf_freem(nd->nd_mrep);
 2418                         goto tryagain;
 2419                 }
 2420                 for (i = 0; i < (ret * 2); i++) {
 2421                         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
 2422                             ND_NFSV4) {
 2423                             NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2424                             if (*(tl + 1))
 2425                                 nd->nd_flag |= ND_NOMOREDATA;
 2426                         }
 2427                 }
 2428                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2429         }
 2430         if (nd->nd_repstat && !error)
 2431                 error = nd->nd_repstat;
 2432 nfsmout:
 2433         mbuf_freem(nd->nd_mrep);
 2434         return (error);
 2435 }
 2436 
 2437 /*
 2438  * Do an nfs rename rpc.
 2439  */
 2440 int
 2441 nfsrpc_rename(vnode_t fdvp, vnode_t fvp, char *fnameptr, int fnamelen,
 2442     vnode_t tdvp, vnode_t tvp, char *tnameptr, int tnamelen, struct ucred *cred,
 2443     NFSPROC_T *p, struct nfsvattr *fnap, struct nfsvattr *tnap,
 2444     int *fattrflagp, int *tattrflagp, void *fstuff, void *tstuff)
 2445 {
 2446         u_int32_t *tl;
 2447         struct nfsrv_descript nfsd, *nd = &nfsd;
 2448         struct nfsmount *nmp;
 2449         struct nfsnode *np;
 2450         nfsattrbit_t attrbits;
 2451         nfsv4stateid_t fdstateid, tdstateid;
 2452         int error = 0, ret = 0, gottd = 0, gotfd = 0, i;
 2453         
 2454         *fattrflagp = 0;
 2455         *tattrflagp = 0;
 2456         nmp = VFSTONFS(vnode_mount(fdvp));
 2457         if (fnamelen > NFS_MAXNAMLEN || tnamelen > NFS_MAXNAMLEN)
 2458                 return (ENAMETOOLONG);
 2459 tryagain:
 2460         if (NFSHASNFSV4(nmp) && ret == 0) {
 2461                 ret = nfscl_renamedeleg(fvp, &fdstateid, &gotfd, tvp,
 2462                     &tdstateid, &gottd, p);
 2463                 if (gotfd && gottd) {
 2464                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME2, fvp);
 2465                 } else if (gotfd) {
 2466                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, fvp);
 2467                 } else if (gottd) {
 2468                         NFSCL_REQSTART(nd, NFSPROC_RETDELEGRENAME1, tvp);
 2469                 }
 2470                 if (gotfd) {
 2471                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2472                         if (NFSHASNFSV4N(nmp))
 2473                                 *tl++ = 0;
 2474                         else
 2475                                 *tl++ = fdstateid.seqid;
 2476                         *tl++ = fdstateid.other[0];
 2477                         *tl++ = fdstateid.other[1];
 2478                         *tl = fdstateid.other[2];
 2479                         if (gottd) {
 2480                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2481                                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2482                                 np = VTONFS(tvp);
 2483                                 (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
 2484                                     np->n_fhp->nfh_len, 0);
 2485                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2486                                 *tl = txdr_unsigned(NFSV4OP_DELEGRETURN);
 2487                         }
 2488                 }
 2489                 if (gottd) {
 2490                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2491                         if (NFSHASNFSV4N(nmp))
 2492                                 *tl++ = 0;
 2493                         else
 2494                                 *tl++ = tdstateid.seqid;
 2495                         *tl++ = tdstateid.other[0];
 2496                         *tl++ = tdstateid.other[1];
 2497                         *tl = tdstateid.other[2];
 2498                 }
 2499                 if (ret > 0) {
 2500                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2501                         *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2502                         np = VTONFS(fdvp);
 2503                         (void) nfsm_fhtom(nd, np->n_fhp->nfh_fh,
 2504                             np->n_fhp->nfh_len, 0);
 2505                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2506                         *tl = txdr_unsigned(NFSV4OP_SAVEFH);
 2507                 }
 2508         } else {
 2509                 ret = 0;
 2510         }
 2511         if (ret == 0)
 2512                 NFSCL_REQSTART(nd, NFSPROC_RENAME, fdvp);
 2513         if (nd->nd_flag & ND_NFSV4) {
 2514                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2515                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2516                 NFSWCCATTR_ATTRBIT(&attrbits);
 2517                 (void) nfsrv_putattrbit(nd, &attrbits);
 2518                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2519                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2520                 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
 2521                     VTONFS(tdvp)->n_fhp->nfh_len, 0);
 2522                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2523                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2524                 (void) nfsrv_putattrbit(nd, &attrbits);
 2525                 nd->nd_flag |= ND_V4WCCATTR;
 2526                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2527                 *tl = txdr_unsigned(NFSV4OP_RENAME);
 2528         }
 2529         (void) nfsm_strtom(nd, fnameptr, fnamelen);
 2530         if (!(nd->nd_flag & ND_NFSV4))
 2531                 (void) nfsm_fhtom(nd, VTONFS(tdvp)->n_fhp->nfh_fh,
 2532                         VTONFS(tdvp)->n_fhp->nfh_len, 0);
 2533         (void) nfsm_strtom(nd, tnameptr, tnamelen);
 2534         error = nfscl_request(nd, fdvp, p, cred, fstuff);
 2535         if (error)
 2536                 return (error);
 2537         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 2538                 /* For NFSv4, parse out any Delereturn replies. */
 2539                 if (ret > 0 && nd->nd_repstat != 0 &&
 2540                     (nd->nd_flag & ND_NOMOREDATA)) {
 2541                         /*
 2542                          * If the Delegreturn failed, try again without
 2543                          * it. The server will Recall, as required.
 2544                          */
 2545                         mbuf_freem(nd->nd_mrep);
 2546                         goto tryagain;
 2547                 }
 2548                 for (i = 0; i < (ret * 2); i++) {
 2549                         if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) ==
 2550                             ND_NFSV4) {
 2551                             NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2552                             if (*(tl + 1)) {
 2553                                 if (i == 0 && ret > 1) {
 2554                                     /*
 2555                                      * If the Delegreturn failed, try again
 2556                                      * without it. The server will Recall, as
 2557                                      * required.
 2558                                      * If ret > 1, the first iteration of this
 2559                                      * loop is the second DelegReturn result.
 2560                                      */
 2561                                     mbuf_freem(nd->nd_mrep);
 2562                                     goto tryagain;
 2563                                 } else {
 2564                                     nd->nd_flag |= ND_NOMOREDATA;
 2565                                 }
 2566                             }
 2567                         }
 2568                 }
 2569                 /* Now, the first wcc attribute reply. */
 2570                 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
 2571                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2572                         if (*(tl + 1))
 2573                                 nd->nd_flag |= ND_NOMOREDATA;
 2574                 }
 2575                 error = nfscl_wcc_data(nd, fdvp, fnap, fattrflagp, NULL,
 2576                     fstuff);
 2577                 /* and the second wcc attribute reply. */
 2578                 if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4 &&
 2579                     !error) {
 2580                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2581                         if (*(tl + 1))
 2582                                 nd->nd_flag |= ND_NOMOREDATA;
 2583                 }
 2584                 if (!error)
 2585                         error = nfscl_wcc_data(nd, tdvp, tnap, tattrflagp,
 2586                             NULL, tstuff);
 2587         }
 2588         if (nd->nd_repstat && !error)
 2589                 error = nd->nd_repstat;
 2590 nfsmout:
 2591         mbuf_freem(nd->nd_mrep);
 2592         return (error);
 2593 }
 2594 
 2595 /*
 2596  * nfs hard link create rpc
 2597  */
 2598 int
 2599 nfsrpc_link(vnode_t dvp, vnode_t vp, char *name, int namelen,
 2600     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 2601     struct nfsvattr *nap, int *attrflagp, int *dattrflagp, void *dstuff)
 2602 {
 2603         u_int32_t *tl;
 2604         struct nfsrv_descript nfsd, *nd = &nfsd;
 2605         nfsattrbit_t attrbits;
 2606         int error = 0;
 2607 
 2608         *attrflagp = 0;
 2609         *dattrflagp = 0;
 2610         if (namelen > NFS_MAXNAMLEN)
 2611                 return (ENAMETOOLONG);
 2612         NFSCL_REQSTART(nd, NFSPROC_LINK, vp);
 2613         if (nd->nd_flag & ND_NFSV4) {
 2614                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2615                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2616         }
 2617         (void) nfsm_fhtom(nd, VTONFS(dvp)->n_fhp->nfh_fh,
 2618                 VTONFS(dvp)->n_fhp->nfh_len, 0);
 2619         if (nd->nd_flag & ND_NFSV4) {
 2620                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2621                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2622                 NFSWCCATTR_ATTRBIT(&attrbits);
 2623                 (void) nfsrv_putattrbit(nd, &attrbits);
 2624                 nd->nd_flag |= ND_V4WCCATTR;
 2625                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2626                 *tl = txdr_unsigned(NFSV4OP_LINK);
 2627         }
 2628         (void) nfsm_strtom(nd, name, namelen);
 2629         error = nfscl_request(nd, vp, p, cred, dstuff);
 2630         if (error)
 2631                 return (error);
 2632         if (nd->nd_flag & ND_NFSV3) {
 2633                 error = nfscl_postop_attr(nd, nap, attrflagp, dstuff);
 2634                 if (!error)
 2635                         error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
 2636                             NULL, dstuff);
 2637         } else if ((nd->nd_flag & (ND_NFSV4 | ND_NOMOREDATA)) == ND_NFSV4) {
 2638                 /*
 2639                  * First, parse out the PutFH and Getattr result.
 2640                  */
 2641                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2642                 if (!(*(tl + 1)))
 2643                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2644                 if (*(tl + 1))
 2645                         nd->nd_flag |= ND_NOMOREDATA;
 2646                 /*
 2647                  * Get the pre-op attributes.
 2648                  */
 2649                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2650         }
 2651         if (nd->nd_repstat && !error)
 2652                 error = nd->nd_repstat;
 2653 nfsmout:
 2654         mbuf_freem(nd->nd_mrep);
 2655         return (error);
 2656 }
 2657 
 2658 /*
 2659  * nfs symbolic link create rpc
 2660  */
 2661 int
 2662 nfsrpc_symlink(vnode_t dvp, char *name, int namelen, char *target,
 2663     struct vattr *vap, struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 2664     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
 2665     int *dattrflagp, void *dstuff)
 2666 {
 2667         u_int32_t *tl;
 2668         struct nfsrv_descript nfsd, *nd = &nfsd;
 2669         struct nfsmount *nmp;
 2670         int slen, error = 0;
 2671 
 2672         *nfhpp = NULL;
 2673         *attrflagp = 0;
 2674         *dattrflagp = 0;
 2675         nmp = VFSTONFS(vnode_mount(dvp));
 2676         slen = strlen(target);
 2677         if (slen > NFS_MAXPATHLEN || namelen > NFS_MAXNAMLEN)
 2678                 return (ENAMETOOLONG);
 2679         NFSCL_REQSTART(nd, NFSPROC_SYMLINK, dvp);
 2680         if (nd->nd_flag & ND_NFSV4) {
 2681                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2682                 *tl = txdr_unsigned(NFLNK);
 2683                 (void) nfsm_strtom(nd, target, slen);
 2684         }
 2685         (void) nfsm_strtom(nd, name, namelen);
 2686         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
 2687                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 2688         if (!(nd->nd_flag & ND_NFSV4))
 2689                 (void) nfsm_strtom(nd, target, slen);
 2690         if (nd->nd_flag & ND_NFSV2)
 2691                 nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
 2692         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2693         if (error)
 2694                 return (error);
 2695         if (nd->nd_flag & ND_NFSV4)
 2696                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2697         if ((nd->nd_flag & ND_NFSV3) && !error) {
 2698                 if (!nd->nd_repstat)
 2699                         error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 2700                 if (!error)
 2701                         error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp,
 2702                             NULL, dstuff);
 2703         }
 2704         if (nd->nd_repstat && !error)
 2705                 error = nd->nd_repstat;
 2706         mbuf_freem(nd->nd_mrep);
 2707         /*
 2708          * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
 2709          * Only do this if vfs.nfs.ignore_eexist is set.
 2710          * Never do this for NFSv4.1 or later minor versions, since sessions
 2711          * should guarantee "exactly once" RPC semantics.
 2712          */
 2713         if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
 2714             nmp->nm_minorvers == 0))
 2715                 error = 0;
 2716         return (error);
 2717 }
 2718 
 2719 /*
 2720  * nfs make dir rpc
 2721  */
 2722 int
 2723 nfsrpc_mkdir(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 2724     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 2725     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
 2726     int *dattrflagp, void *dstuff)
 2727 {
 2728         u_int32_t *tl;
 2729         struct nfsrv_descript nfsd, *nd = &nfsd;
 2730         nfsattrbit_t attrbits;
 2731         int error = 0;
 2732         struct nfsfh *fhp;
 2733         struct nfsmount *nmp;
 2734 
 2735         *nfhpp = NULL;
 2736         *attrflagp = 0;
 2737         *dattrflagp = 0;
 2738         nmp = VFSTONFS(vnode_mount(dvp));
 2739         fhp = VTONFS(dvp)->n_fhp;
 2740         if (namelen > NFS_MAXNAMLEN)
 2741                 return (ENAMETOOLONG);
 2742         NFSCL_REQSTART(nd, NFSPROC_MKDIR, dvp);
 2743         if (nd->nd_flag & ND_NFSV4) {
 2744                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2745                 *tl = txdr_unsigned(NFDIR);
 2746         }
 2747         (void) nfsm_strtom(nd, name, namelen);
 2748         nfscl_fillsattr(nd, vap, dvp, NFSSATTR_SIZENEG1, 0);
 2749         if (nd->nd_flag & ND_NFSV4) {
 2750                 NFSGETATTR_ATTRBIT(&attrbits);
 2751                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2752                 *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 2753                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2754                 (void) nfsrv_putattrbit(nd, &attrbits);
 2755                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2756                 *tl = txdr_unsigned(NFSV4OP_PUTFH);
 2757                 (void) nfsm_fhtom(nd, fhp->nfh_fh, fhp->nfh_len, 0);
 2758                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 2759                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2760                 (void) nfsrv_putattrbit(nd, &attrbits);
 2761         }
 2762         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2763         if (error)
 2764                 return (error);
 2765         if (nd->nd_flag & ND_NFSV4)
 2766                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2767         if (!nd->nd_repstat && !error) {
 2768                 if (nd->nd_flag & ND_NFSV4) {
 2769                         NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 2770                         error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 2771                 }
 2772                 if (!error)
 2773                         error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 2774                 if (error == 0 && (nd->nd_flag & ND_NFSV4) != 0) {
 2775                         /* Get rid of the PutFH and Getattr status values. */
 2776                         NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 2777                         /* Load the directory attributes. */
 2778                         error = nfsm_loadattr(nd, dnap);
 2779                         if (error == 0)
 2780                                 *dattrflagp = 1;
 2781                 }
 2782         }
 2783         if ((nd->nd_flag & ND_NFSV3) && !error)
 2784                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2785         if (nd->nd_repstat && !error)
 2786                 error = nd->nd_repstat;
 2787 nfsmout:
 2788         mbuf_freem(nd->nd_mrep);
 2789         /*
 2790          * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
 2791          * Only do this if vfs.nfs.ignore_eexist is set.
 2792          * Never do this for NFSv4.1 or later minor versions, since sessions
 2793          * should guarantee "exactly once" RPC semantics.
 2794          */
 2795         if (error == EEXIST && nfsignore_eexist != 0 && (!NFSHASNFSV4(nmp) ||
 2796             nmp->nm_minorvers == 0))
 2797                 error = 0;
 2798         return (error);
 2799 }
 2800 
 2801 /*
 2802  * nfs remove directory call
 2803  */
 2804 int
 2805 nfsrpc_rmdir(vnode_t dvp, char *name, int namelen, struct ucred *cred,
 2806     NFSPROC_T *p, struct nfsvattr *dnap, int *dattrflagp, void *dstuff)
 2807 {
 2808         struct nfsrv_descript nfsd, *nd = &nfsd;
 2809         int error = 0;
 2810 
 2811         *dattrflagp = 0;
 2812         if (namelen > NFS_MAXNAMLEN)
 2813                 return (ENAMETOOLONG);
 2814         NFSCL_REQSTART(nd, NFSPROC_RMDIR, dvp);
 2815         (void) nfsm_strtom(nd, name, namelen);
 2816         error = nfscl_request(nd, dvp, p, cred, dstuff);
 2817         if (error)
 2818                 return (error);
 2819         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4))
 2820                 error = nfscl_wcc_data(nd, dvp, dnap, dattrflagp, NULL, dstuff);
 2821         if (nd->nd_repstat && !error)
 2822                 error = nd->nd_repstat;
 2823         mbuf_freem(nd->nd_mrep);
 2824         /*
 2825          * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
 2826          */
 2827         if (error == ENOENT)
 2828                 error = 0;
 2829         return (error);
 2830 }
 2831 
 2832 /*
 2833  * Readdir rpc.
 2834  * Always returns with either uio_resid unchanged, if you are at the
 2835  * end of the directory, or uio_resid == 0, with all DIRBLKSIZ chunks
 2836  * filled in.
 2837  * I felt this would allow caching of directory blocks more easily
 2838  * than returning a pertially filled block.
 2839  * Directory offset cookies:
 2840  * Oh my, what to do with them...
 2841  * I can think of three ways to deal with them:
 2842  * 1 - have the layer above these RPCs maintain a map between logical
 2843  *     directory byte offsets and the NFS directory offset cookies
 2844  * 2 - pass the opaque directory offset cookies up into userland
 2845  *     and let the libc functions deal with them, via the system call
 2846  * 3 - return them to userland in the "struct dirent", so future versions
 2847  *     of libc can use them and do whatever is necessary to make things work
 2848  *     above these rpc calls, in the meantime
 2849  * For now, I do #3 by "hiding" the directory offset cookies after the
 2850  * d_name field in struct dirent. This is space inside d_reclen that
 2851  * will be ignored by anything that doesn't know about them.
 2852  * The directory offset cookies are filled in as the last 8 bytes of
 2853  * each directory entry, after d_name. Someday, the userland libc
 2854  * functions may be able to use these. In the meantime, it satisfies
 2855  * OpenBSD's requirements for cookies being returned.
 2856  * If expects the directory offset cookie for the read to be in uio_offset
 2857  * and returns the one for the next entry after this directory block in
 2858  * there, as well.
 2859  */
 2860 int
 2861 nfsrpc_readdir(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
 2862     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 2863     int *eofp, void *stuff)
 2864 {
 2865         int len, left;
 2866         struct dirent *dp = NULL;
 2867         u_int32_t *tl;
 2868         nfsquad_t cookie, ncookie;
 2869         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 2870         struct nfsnode *dnp = VTONFS(vp);
 2871         struct nfsvattr nfsva;
 2872         struct nfsrv_descript nfsd, *nd = &nfsd;
 2873         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
 2874         int reqsize, tryformoredirs = 1, readsize, eof = 0, gotmnton = 0;
 2875         u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
 2876         char *cp;
 2877         nfsattrbit_t attrbits, dattrbits;
 2878         u_int32_t rderr, *tl2 = NULL;
 2879         size_t tresid;
 2880 
 2881         KASSERT(uiop->uio_iovcnt == 1 &&
 2882             (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
 2883             ("nfs readdirrpc bad uio"));
 2884         ncookie.lval[0] = ncookie.lval[1] = 0;
 2885         /*
 2886          * There is no point in reading a lot more than uio_resid, however
 2887          * adding one additional DIRBLKSIZ makes sense. Since uio_resid
 2888          * and nm_readdirsize are both exact multiples of DIRBLKSIZ, this
 2889          * will never make readsize > nm_readdirsize.
 2890          */
 2891         readsize = nmp->nm_readdirsize;
 2892         if (readsize > uio_uio_resid(uiop))
 2893                 readsize = uio_uio_resid(uiop) + DIRBLKSIZ;
 2894 
 2895         *attrflagp = 0;
 2896         if (eofp)
 2897                 *eofp = 0;
 2898         tresid = uio_uio_resid(uiop);
 2899         cookie.lval[0] = cookiep->nfsuquad[0];
 2900         cookie.lval[1] = cookiep->nfsuquad[1];
 2901         nd->nd_mrep = NULL;
 2902 
 2903         /*
 2904          * For NFSv4, first create the "." and ".." entries.
 2905          */
 2906         if (NFSHASNFSV4(nmp)) {
 2907                 reqsize = 6 * NFSX_UNSIGNED;
 2908                 NFSGETATTR_ATTRBIT(&dattrbits);
 2909                 NFSZERO_ATTRBIT(&attrbits);
 2910                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
 2911                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TYPE);
 2912                 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
 2913                     NFSATTRBIT_MOUNTEDONFILEID)) {
 2914                         NFSSETBIT_ATTRBIT(&attrbits,
 2915                             NFSATTRBIT_MOUNTEDONFILEID);
 2916                         gotmnton = 1;
 2917                 } else {
 2918                         /*
 2919                          * Must fake it. Use the fileno, except when the
 2920                          * fsid is != to that of the directory. For that
 2921                          * case, generate a fake fileno that is not the same.
 2922                          */
 2923                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
 2924                         gotmnton = 0;
 2925                 }
 2926 
 2927                 /*
 2928                  * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
 2929                  */
 2930                 if (uiop->uio_offset == 0) {
 2931                         NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
 2932                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 2933                         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 2934                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 2935                         (void) nfsrv_putattrbit(nd, &attrbits);
 2936                         error = nfscl_request(nd, vp, p, cred, stuff);
 2937                         if (error)
 2938                             return (error);
 2939                         dotfileid = 0;  /* Fake out the compiler. */
 2940                         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
 2941                             error = nfsm_loadattr(nd, &nfsva);
 2942                             if (error != 0)
 2943                                 goto nfsmout;
 2944                             dotfileid = nfsva.na_fileid;
 2945                         }
 2946                         if (nd->nd_repstat == 0) {
 2947                             NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 2948                             len = fxdr_unsigned(int, *(tl + 4));
 2949                             if (len > 0 && len <= NFSX_V4FHMAX)
 2950                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 2951                             else
 2952                                 error = EPERM;
 2953                             if (!error) {
 2954                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
 2955                                 nfsva.na_mntonfileno = UINT64_MAX;
 2956                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
 2957                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 2958                                     NULL, NULL, NULL, p, cred);
 2959                                 if (error) {
 2960                                     dotdotfileid = dotfileid;
 2961                                 } else if (gotmnton) {
 2962                                     if (nfsva.na_mntonfileno != UINT64_MAX)
 2963                                         dotdotfileid = nfsva.na_mntonfileno;
 2964                                     else
 2965                                         dotdotfileid = nfsva.na_fileid;
 2966                                 } else if (nfsva.na_filesid[0] ==
 2967                                     dnp->n_vattr.na_filesid[0] &&
 2968                                     nfsva.na_filesid[1] ==
 2969                                     dnp->n_vattr.na_filesid[1]) {
 2970                                     dotdotfileid = nfsva.na_fileid;
 2971                                 } else {
 2972                                     do {
 2973                                         fakefileno--;
 2974                                     } while (fakefileno ==
 2975                                         nfsva.na_fileid);
 2976                                     dotdotfileid = fakefileno;
 2977                                 }
 2978                             }
 2979                         } else if (nd->nd_repstat == NFSERR_NOENT) {
 2980                             /*
 2981                              * Lookupp returns NFSERR_NOENT when we are
 2982                              * at the root, so just use the current dir.
 2983                              */
 2984                             nd->nd_repstat = 0;
 2985                             dotdotfileid = dotfileid;
 2986                         } else {
 2987                             error = nd->nd_repstat;
 2988                         }
 2989                         mbuf_freem(nd->nd_mrep);
 2990                         if (error)
 2991                             return (error);
 2992                         nd->nd_mrep = NULL;
 2993                         dp = (struct dirent *)uio_iov_base(uiop);
 2994                         dp->d_pad0 = dp->d_pad1 = 0;
 2995                         dp->d_off = 0;
 2996                         dp->d_type = DT_DIR;
 2997                         dp->d_fileno = dotfileid;
 2998                         dp->d_namlen = 1;
 2999                         *((uint64_t *)dp->d_name) = 0;  /* Zero pad it. */
 3000                         dp->d_name[0] = '.';
 3001                         dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
 3002                         /*
 3003                          * Just make these offset cookie 0.
 3004                          */
 3005                         tl = (u_int32_t *)&dp->d_name[8];
 3006                         *tl++ = 0;
 3007                         *tl = 0;
 3008                         blksiz += dp->d_reclen;
 3009                         uio_uio_resid_add(uiop, -(dp->d_reclen));
 3010                         uiop->uio_offset += dp->d_reclen;
 3011                         uio_iov_base_add(uiop, dp->d_reclen);
 3012                         uio_iov_len_add(uiop, -(dp->d_reclen));
 3013                         dp = (struct dirent *)uio_iov_base(uiop);
 3014                         dp->d_pad0 = dp->d_pad1 = 0;
 3015                         dp->d_off = 0;
 3016                         dp->d_type = DT_DIR;
 3017                         dp->d_fileno = dotdotfileid;
 3018                         dp->d_namlen = 2;
 3019                         *((uint64_t *)dp->d_name) = 0;
 3020                         dp->d_name[0] = '.';
 3021                         dp->d_name[1] = '.';
 3022                         dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
 3023                         /*
 3024                          * Just make these offset cookie 0.
 3025                          */
 3026                         tl = (u_int32_t *)&dp->d_name[8];
 3027                         *tl++ = 0;
 3028                         *tl = 0;
 3029                         blksiz += dp->d_reclen;
 3030                         uio_uio_resid_add(uiop, -(dp->d_reclen));
 3031                         uiop->uio_offset += dp->d_reclen;
 3032                         uio_iov_base_add(uiop, dp->d_reclen);
 3033                         uio_iov_len_add(uiop, -(dp->d_reclen));
 3034                 }
 3035                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_RDATTRERROR);
 3036         } else {
 3037                 reqsize = 5 * NFSX_UNSIGNED;
 3038         }
 3039 
 3040 
 3041         /*
 3042          * Loop around doing readdir rpc's of size readsize.
 3043          * The stopping criteria is EOF or buffer full.
 3044          */
 3045         while (more_dirs && bigenough) {
 3046                 *attrflagp = 0;
 3047                 NFSCL_REQSTART(nd, NFSPROC_READDIR, vp);
 3048                 if (nd->nd_flag & ND_NFSV2) {
 3049                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3050                         *tl++ = cookie.lval[1];
 3051                         *tl = txdr_unsigned(readsize);
 3052                 } else {
 3053                         NFSM_BUILD(tl, u_int32_t *, reqsize);
 3054                         *tl++ = cookie.lval[0];
 3055                         *tl++ = cookie.lval[1];
 3056                         if (cookie.qval == 0) {
 3057                                 *tl++ = 0;
 3058                                 *tl++ = 0;
 3059                         } else {
 3060                                 NFSLOCKNODE(dnp);
 3061                                 *tl++ = dnp->n_cookieverf.nfsuquad[0];
 3062                                 *tl++ = dnp->n_cookieverf.nfsuquad[1];
 3063                                 NFSUNLOCKNODE(dnp);
 3064                         }
 3065                         if (nd->nd_flag & ND_NFSV4) {
 3066                                 *tl++ = txdr_unsigned(readsize);
 3067                                 *tl = txdr_unsigned(readsize);
 3068                                 (void) nfsrv_putattrbit(nd, &attrbits);
 3069                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3070                                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 3071                                 (void) nfsrv_putattrbit(nd, &dattrbits);
 3072                         } else {
 3073                                 *tl = txdr_unsigned(readsize);
 3074                         }
 3075                 }
 3076                 error = nfscl_request(nd, vp, p, cred, stuff);
 3077                 if (error)
 3078                         return (error);
 3079                 if (!(nd->nd_flag & ND_NFSV2)) {
 3080                         if (nd->nd_flag & ND_NFSV3)
 3081                                 error = nfscl_postop_attr(nd, nap, attrflagp,
 3082                                     stuff);
 3083                         if (!nd->nd_repstat && !error) {
 3084                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 3085                                 NFSLOCKNODE(dnp);
 3086                                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
 3087                                 dnp->n_cookieverf.nfsuquad[1] = *tl;
 3088                                 NFSUNLOCKNODE(dnp);
 3089                         }
 3090                 }
 3091                 if (nd->nd_repstat || error) {
 3092                         if (!error)
 3093                                 error = nd->nd_repstat;
 3094                         goto nfsmout;
 3095                 }
 3096                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3097                 more_dirs = fxdr_unsigned(int, *tl);
 3098                 if (!more_dirs)
 3099                         tryformoredirs = 0;
 3100         
 3101                 /* loop through the dir entries, doctoring them to 4bsd form */
 3102                 while (more_dirs && bigenough) {
 3103                         if (nd->nd_flag & ND_NFSV4) {
 3104                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
 3105                                 ncookie.lval[0] = *tl++;
 3106                                 ncookie.lval[1] = *tl++;
 3107                                 len = fxdr_unsigned(int, *tl);
 3108                         } else if (nd->nd_flag & ND_NFSV3) {
 3109                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
 3110                                 nfsva.na_fileid = fxdr_hyper(tl);
 3111                                 tl += 2;
 3112                                 len = fxdr_unsigned(int, *tl);
 3113                         } else {
 3114                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
 3115                                 nfsva.na_fileid = fxdr_unsigned(uint64_t,
 3116                                     *tl++);
 3117                                 len = fxdr_unsigned(int, *tl);
 3118                         }
 3119                         if (len <= 0 || len > NFS_MAXNAMLEN) {
 3120                                 error = EBADRPC;
 3121                                 goto nfsmout;
 3122                         }
 3123                         tlen = roundup2(len, 8);
 3124                         if (tlen == len)
 3125                                 tlen += 8;  /* To ensure null termination. */
 3126                         left = DIRBLKSIZ - blksiz;
 3127                         if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
 3128                                 NFSBZERO(uio_iov_base(uiop), left);
 3129                                 dp->d_reclen += left;
 3130                                 uio_iov_base_add(uiop, left);
 3131                                 uio_iov_len_add(uiop, -(left));
 3132                                 uio_uio_resid_add(uiop, -(left));
 3133                                 uiop->uio_offset += left;
 3134                                 blksiz = 0;
 3135                         }
 3136                         if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
 3137                             uio_uio_resid(uiop))
 3138                                 bigenough = 0;
 3139                         if (bigenough) {
 3140                                 dp = (struct dirent *)uio_iov_base(uiop);
 3141                                 dp->d_pad0 = dp->d_pad1 = 0;
 3142                                 dp->d_off = 0;
 3143                                 dp->d_namlen = len;
 3144                                 dp->d_reclen = _GENERIC_DIRLEN(len) +
 3145                                     NFSX_HYPER;
 3146                                 dp->d_type = DT_UNKNOWN;
 3147                                 blksiz += dp->d_reclen;
 3148                                 if (blksiz == DIRBLKSIZ)
 3149                                         blksiz = 0;
 3150                                 uio_uio_resid_add(uiop, -(DIRHDSIZ));
 3151                                 uiop->uio_offset += DIRHDSIZ;
 3152                                 uio_iov_base_add(uiop, DIRHDSIZ);
 3153                                 uio_iov_len_add(uiop, -(DIRHDSIZ));
 3154                                 error = nfsm_mbufuio(nd, uiop, len);
 3155                                 if (error)
 3156                                         goto nfsmout;
 3157                                 cp = uio_iov_base(uiop);
 3158                                 tlen -= len;
 3159                                 NFSBZERO(cp, tlen);
 3160                                 cp += tlen;     /* points to cookie storage */
 3161                                 tl2 = (u_int32_t *)cp;
 3162                                 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
 3163                                 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
 3164                                 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
 3165                                 uiop->uio_offset += (tlen + NFSX_HYPER);
 3166                         } else {
 3167                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 3168                                 if (error)
 3169                                         goto nfsmout;
 3170                         }
 3171                         if (nd->nd_flag & ND_NFSV4) {
 3172                                 rderr = 0;
 3173                                 nfsva.na_mntonfileno = UINT64_MAX;
 3174                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
 3175                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 3176                                     NULL, NULL, &rderr, p, cred);
 3177                                 if (error)
 3178                                         goto nfsmout;
 3179                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3180                         } else if (nd->nd_flag & ND_NFSV3) {
 3181                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
 3182                                 ncookie.lval[0] = *tl++;
 3183                                 ncookie.lval[1] = *tl++;
 3184                         } else {
 3185                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
 3186                                 ncookie.lval[0] = 0;
 3187                                 ncookie.lval[1] = *tl++;
 3188                         }
 3189                         if (bigenough) {
 3190                             if (nd->nd_flag & ND_NFSV4) {
 3191                                 if (rderr) {
 3192                                     dp->d_fileno = 0;
 3193                                 } else {
 3194                                     if (gotmnton) {
 3195                                         if (nfsva.na_mntonfileno != UINT64_MAX)
 3196                                             dp->d_fileno = nfsva.na_mntonfileno;
 3197                                         else
 3198                                             dp->d_fileno = nfsva.na_fileid;
 3199                                     } else if (nfsva.na_filesid[0] ==
 3200                                         dnp->n_vattr.na_filesid[0] &&
 3201                                         nfsva.na_filesid[1] ==
 3202                                         dnp->n_vattr.na_filesid[1]) {
 3203                                         dp->d_fileno = nfsva.na_fileid;
 3204                                     } else {
 3205                                         do {
 3206                                             fakefileno--;
 3207                                         } while (fakefileno ==
 3208                                             nfsva.na_fileid);
 3209                                         dp->d_fileno = fakefileno;
 3210                                     }
 3211                                     dp->d_type = vtonfs_dtype(nfsva.na_type);
 3212                                 }
 3213                             } else {
 3214                                 dp->d_fileno = nfsva.na_fileid;
 3215                             }
 3216                             *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
 3217                                 ncookie.lval[0];
 3218                             *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
 3219                                 ncookie.lval[1];
 3220                         }
 3221                         more_dirs = fxdr_unsigned(int, *tl);
 3222                 }
 3223                 /*
 3224                  * If at end of rpc data, get the eof boolean
 3225                  */
 3226                 if (!more_dirs) {
 3227                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3228                         eof = fxdr_unsigned(int, *tl);
 3229                         if (tryformoredirs)
 3230                                 more_dirs = !eof;
 3231                         if (nd->nd_flag & ND_NFSV4) {
 3232                                 error = nfscl_postop_attr(nd, nap, attrflagp,
 3233                                     stuff);
 3234                                 if (error)
 3235                                         goto nfsmout;
 3236                         }
 3237                 }
 3238                 mbuf_freem(nd->nd_mrep);
 3239                 nd->nd_mrep = NULL;
 3240         }
 3241         /*
 3242          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
 3243          * by increasing d_reclen for the last record.
 3244          */
 3245         if (blksiz > 0) {
 3246                 left = DIRBLKSIZ - blksiz;
 3247                 NFSBZERO(uio_iov_base(uiop), left);
 3248                 dp->d_reclen += left;
 3249                 uio_iov_base_add(uiop, left);
 3250                 uio_iov_len_add(uiop, -(left));
 3251                 uio_uio_resid_add(uiop, -(left));
 3252                 uiop->uio_offset += left;
 3253         }
 3254 
 3255         /*
 3256          * If returning no data, assume end of file.
 3257          * If not bigenough, return not end of file, since you aren't
 3258          *    returning all the data
 3259          * Otherwise, return the eof flag from the server.
 3260          */
 3261         if (eofp) {
 3262                 if (tresid == ((size_t)(uio_uio_resid(uiop))))
 3263                         *eofp = 1;
 3264                 else if (!bigenough)
 3265                         *eofp = 0;
 3266                 else
 3267                         *eofp = eof;
 3268         }
 3269 
 3270         /*
 3271          * Add extra empty records to any remaining DIRBLKSIZ chunks.
 3272          */
 3273         while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
 3274                 dp = (struct dirent *)uio_iov_base(uiop);
 3275                 NFSBZERO(dp, DIRBLKSIZ);
 3276                 dp->d_type = DT_UNKNOWN;
 3277                 tl = (u_int32_t *)&dp->d_name[4];
 3278                 *tl++ = cookie.lval[0];
 3279                 *tl = cookie.lval[1];
 3280                 dp->d_reclen = DIRBLKSIZ;
 3281                 uio_iov_base_add(uiop, DIRBLKSIZ);
 3282                 uio_iov_len_add(uiop, -(DIRBLKSIZ));
 3283                 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
 3284                 uiop->uio_offset += DIRBLKSIZ;
 3285         }
 3286 
 3287 nfsmout:
 3288         if (nd->nd_mrep != NULL)
 3289                 mbuf_freem(nd->nd_mrep);
 3290         return (error);
 3291 }
 3292 
 3293 #ifndef APPLE
 3294 /*
 3295  * NFS V3 readdir plus RPC. Used in place of nfsrpc_readdir().
 3296  * (Also used for NFS V4 when mount flag set.)
 3297  * (ditto above w.r.t. multiple of DIRBLKSIZ, etc.)
 3298  */
 3299 int
 3300 nfsrpc_readdirplus(vnode_t vp, struct uio *uiop, nfsuint64 *cookiep,
 3301     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 3302     int *eofp, void *stuff)
 3303 {
 3304         int len, left;
 3305         struct dirent *dp = NULL;
 3306         u_int32_t *tl;
 3307         vnode_t newvp = NULLVP;
 3308         struct nfsrv_descript nfsd, *nd = &nfsd;
 3309         struct nameidata nami, *ndp = &nami;
 3310         struct componentname *cnp = &ndp->ni_cnd;
 3311         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 3312         struct nfsnode *dnp = VTONFS(vp), *np;
 3313         struct nfsvattr nfsva;
 3314         struct nfsfh *nfhp;
 3315         nfsquad_t cookie, ncookie;
 3316         int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
 3317         int attrflag, tryformoredirs = 1, eof = 0, gotmnton = 0;
 3318         int isdotdot = 0, unlocknewvp = 0;
 3319         u_int64_t dotfileid, dotdotfileid = 0, fakefileno = UINT64_MAX;
 3320         u_int64_t fileno = 0;
 3321         char *cp;
 3322         nfsattrbit_t attrbits, dattrbits;
 3323         size_t tresid;
 3324         u_int32_t *tl2 = NULL, rderr;
 3325         struct timespec dctime, ts;
 3326         bool attr_ok;
 3327 
 3328         KASSERT(uiop->uio_iovcnt == 1 &&
 3329             (uio_uio_resid(uiop) & (DIRBLKSIZ - 1)) == 0,
 3330             ("nfs readdirplusrpc bad uio"));
 3331         ncookie.lval[0] = ncookie.lval[1] = 0;
 3332         timespecclear(&dctime);
 3333         *attrflagp = 0;
 3334         if (eofp != NULL)
 3335                 *eofp = 0;
 3336         ndp->ni_dvp = vp;
 3337         nd->nd_mrep = NULL;
 3338         cookie.lval[0] = cookiep->nfsuquad[0];
 3339         cookie.lval[1] = cookiep->nfsuquad[1];
 3340         tresid = uio_uio_resid(uiop);
 3341 
 3342         /*
 3343          * For NFSv4, first create the "." and ".." entries.
 3344          */
 3345         if (NFSHASNFSV4(nmp)) {
 3346                 NFSGETATTR_ATTRBIT(&dattrbits);
 3347                 NFSZERO_ATTRBIT(&attrbits);
 3348                 NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FILEID);
 3349                 if (NFSISSET_ATTRBIT(&dnp->n_vattr.na_suppattr,
 3350                     NFSATTRBIT_MOUNTEDONFILEID)) {
 3351                         NFSSETBIT_ATTRBIT(&attrbits,
 3352                             NFSATTRBIT_MOUNTEDONFILEID);
 3353                         gotmnton = 1;
 3354                 } else {
 3355                         /*
 3356                          * Must fake it. Use the fileno, except when the
 3357                          * fsid is != to that of the directory. For that
 3358                          * case, generate a fake fileno that is not the same.
 3359                          */
 3360                         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_FSID);
 3361                         gotmnton = 0;
 3362                 }
 3363 
 3364                 /*
 3365                  * Joy, oh joy. For V4 we get to hand craft '.' and '..'.
 3366                  */
 3367                 if (uiop->uio_offset == 0) {
 3368                         NFSCL_REQSTART(nd, NFSPROC_LOOKUPP, vp);
 3369                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3370                         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 3371                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 3372                         (void) nfsrv_putattrbit(nd, &attrbits);
 3373                         error = nfscl_request(nd, vp, p, cred, stuff);
 3374                         if (error)
 3375                             return (error);
 3376                         dotfileid = 0;  /* Fake out the compiler. */
 3377                         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
 3378                             error = nfsm_loadattr(nd, &nfsva);
 3379                             if (error != 0)
 3380                                 goto nfsmout;
 3381                             dctime = nfsva.na_ctime;
 3382                             dotfileid = nfsva.na_fileid;
 3383                         }
 3384                         if (nd->nd_repstat == 0) {
 3385                             NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 3386                             len = fxdr_unsigned(int, *(tl + 4));
 3387                             if (len > 0 && len <= NFSX_V4FHMAX)
 3388                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 3389                             else
 3390                                 error = EPERM;
 3391                             if (!error) {
 3392                                 NFSM_DISSECT(tl, u_int32_t *, 2*NFSX_UNSIGNED);
 3393                                 nfsva.na_mntonfileno = UINT64_MAX;
 3394                                 error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
 3395                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 3396                                     NULL, NULL, NULL, p, cred);
 3397                                 if (error) {
 3398                                     dotdotfileid = dotfileid;
 3399                                 } else if (gotmnton) {
 3400                                     if (nfsva.na_mntonfileno != UINT64_MAX)
 3401                                         dotdotfileid = nfsva.na_mntonfileno;
 3402                                     else
 3403                                         dotdotfileid = nfsva.na_fileid;
 3404                                 } else if (nfsva.na_filesid[0] ==
 3405                                     dnp->n_vattr.na_filesid[0] &&
 3406                                     nfsva.na_filesid[1] ==
 3407                                     dnp->n_vattr.na_filesid[1]) {
 3408                                     dotdotfileid = nfsva.na_fileid;
 3409                                 } else {
 3410                                     do {
 3411                                         fakefileno--;
 3412                                     } while (fakefileno ==
 3413                                         nfsva.na_fileid);
 3414                                     dotdotfileid = fakefileno;
 3415                                 }
 3416                             }
 3417                         } else if (nd->nd_repstat == NFSERR_NOENT) {
 3418                             /*
 3419                              * Lookupp returns NFSERR_NOENT when we are
 3420                              * at the root, so just use the current dir.
 3421                              */
 3422                             nd->nd_repstat = 0;
 3423                             dotdotfileid = dotfileid;
 3424                         } else {
 3425                             error = nd->nd_repstat;
 3426                         }
 3427                         mbuf_freem(nd->nd_mrep);
 3428                         if (error)
 3429                             return (error);
 3430                         nd->nd_mrep = NULL;
 3431                         dp = (struct dirent *)uio_iov_base(uiop);
 3432                         dp->d_pad0 = dp->d_pad1 = 0;
 3433                         dp->d_off = 0;
 3434                         dp->d_type = DT_DIR;
 3435                         dp->d_fileno = dotfileid;
 3436                         dp->d_namlen = 1;
 3437                         *((uint64_t *)dp->d_name) = 0;  /* Zero pad it. */
 3438                         dp->d_name[0] = '.';
 3439                         dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
 3440                         /*
 3441                          * Just make these offset cookie 0.
 3442                          */
 3443                         tl = (u_int32_t *)&dp->d_name[8];
 3444                         *tl++ = 0;
 3445                         *tl = 0;
 3446                         blksiz += dp->d_reclen;
 3447                         uio_uio_resid_add(uiop, -(dp->d_reclen));
 3448                         uiop->uio_offset += dp->d_reclen;
 3449                         uio_iov_base_add(uiop, dp->d_reclen);
 3450                         uio_iov_len_add(uiop, -(dp->d_reclen));
 3451                         dp = (struct dirent *)uio_iov_base(uiop);
 3452                         dp->d_pad0 = dp->d_pad1 = 0;
 3453                         dp->d_off = 0;
 3454                         dp->d_type = DT_DIR;
 3455                         dp->d_fileno = dotdotfileid;
 3456                         dp->d_namlen = 2;
 3457                         *((uint64_t *)dp->d_name) = 0;
 3458                         dp->d_name[0] = '.';
 3459                         dp->d_name[1] = '.';
 3460                         dp->d_reclen = _GENERIC_DIRSIZ(dp) + NFSX_HYPER;
 3461                         /*
 3462                          * Just make these offset cookie 0.
 3463                          */
 3464                         tl = (u_int32_t *)&dp->d_name[8];
 3465                         *tl++ = 0;
 3466                         *tl = 0;
 3467                         blksiz += dp->d_reclen;
 3468                         uio_uio_resid_add(uiop, -(dp->d_reclen));
 3469                         uiop->uio_offset += dp->d_reclen;
 3470                         uio_iov_base_add(uiop, dp->d_reclen);
 3471                         uio_iov_len_add(uiop, -(dp->d_reclen));
 3472                 }
 3473                 NFSREADDIRPLUS_ATTRBIT(&attrbits);
 3474                 if (gotmnton)
 3475                         NFSSETBIT_ATTRBIT(&attrbits,
 3476                             NFSATTRBIT_MOUNTEDONFILEID);
 3477         }
 3478 
 3479         /*
 3480          * Loop around doing readdir rpc's of size nm_readdirsize.
 3481          * The stopping criteria is EOF or buffer full.
 3482          */
 3483         while (more_dirs && bigenough) {
 3484                 *attrflagp = 0;
 3485                 NFSCL_REQSTART(nd, NFSPROC_READDIRPLUS, vp);
 3486                 NFSM_BUILD(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
 3487                 *tl++ = cookie.lval[0];
 3488                 *tl++ = cookie.lval[1];
 3489                 if (cookie.qval == 0) {
 3490                         *tl++ = 0;
 3491                         *tl++ = 0;
 3492                 } else {
 3493                         NFSLOCKNODE(dnp);
 3494                         *tl++ = dnp->n_cookieverf.nfsuquad[0];
 3495                         *tl++ = dnp->n_cookieverf.nfsuquad[1];
 3496                         NFSUNLOCKNODE(dnp);
 3497                 }
 3498                 *tl++ = txdr_unsigned(nmp->nm_readdirsize);
 3499                 *tl = txdr_unsigned(nmp->nm_readdirsize);
 3500                 if (nd->nd_flag & ND_NFSV4) {
 3501                         (void) nfsrv_putattrbit(nd, &attrbits);
 3502                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3503                         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 3504                         (void) nfsrv_putattrbit(nd, &dattrbits);
 3505                 }
 3506                 nanouptime(&ts);
 3507                 error = nfscl_request(nd, vp, p, cred, stuff);
 3508                 if (error)
 3509                         return (error);
 3510                 if (nd->nd_flag & ND_NFSV3)
 3511                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 3512                 if (nd->nd_repstat || error) {
 3513                         if (!error)
 3514                                 error = nd->nd_repstat;
 3515                         goto nfsmout;
 3516                 }
 3517                 if ((nd->nd_flag & ND_NFSV3) != 0 && *attrflagp != 0)
 3518                         dctime = nap->na_ctime;
 3519                 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3520                 NFSLOCKNODE(dnp);
 3521                 dnp->n_cookieverf.nfsuquad[0] = *tl++;
 3522                 dnp->n_cookieverf.nfsuquad[1] = *tl++;
 3523                 NFSUNLOCKNODE(dnp);
 3524                 more_dirs = fxdr_unsigned(int, *tl);
 3525                 if (!more_dirs)
 3526                         tryformoredirs = 0;
 3527         
 3528                 /* loop through the dir entries, doctoring them to 4bsd form */
 3529                 while (more_dirs && bigenough) {
 3530                         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3531                         if (nd->nd_flag & ND_NFSV4) {
 3532                                 ncookie.lval[0] = *tl++;
 3533                                 ncookie.lval[1] = *tl++;
 3534                         } else {
 3535                                 fileno = fxdr_hyper(tl);
 3536                                 tl += 2;
 3537                         }
 3538                         len = fxdr_unsigned(int, *tl);
 3539                         if (len <= 0 || len > NFS_MAXNAMLEN) {
 3540                                 error = EBADRPC;
 3541                                 goto nfsmout;
 3542                         }
 3543                         tlen = roundup2(len, 8);
 3544                         if (tlen == len)
 3545                                 tlen += 8;  /* To ensure null termination. */
 3546                         left = DIRBLKSIZ - blksiz;
 3547                         if (_GENERIC_DIRLEN(len) + NFSX_HYPER > left) {
 3548                                 NFSBZERO(uio_iov_base(uiop), left);
 3549                                 dp->d_reclen += left;
 3550                                 uio_iov_base_add(uiop, left);
 3551                                 uio_iov_len_add(uiop, -(left));
 3552                                 uio_uio_resid_add(uiop, -(left));
 3553                                 uiop->uio_offset += left;
 3554                                 blksiz = 0;
 3555                         }
 3556                         if (_GENERIC_DIRLEN(len) + NFSX_HYPER >
 3557                             uio_uio_resid(uiop))
 3558                                 bigenough = 0;
 3559                         if (bigenough) {
 3560                                 dp = (struct dirent *)uio_iov_base(uiop);
 3561                                 dp->d_pad0 = dp->d_pad1 = 0;
 3562                                 dp->d_off = 0;
 3563                                 dp->d_namlen = len;
 3564                                 dp->d_reclen = _GENERIC_DIRLEN(len) +
 3565                                     NFSX_HYPER;
 3566                                 dp->d_type = DT_UNKNOWN;
 3567                                 blksiz += dp->d_reclen;
 3568                                 if (blksiz == DIRBLKSIZ)
 3569                                         blksiz = 0;
 3570                                 uio_uio_resid_add(uiop, -(DIRHDSIZ));
 3571                                 uiop->uio_offset += DIRHDSIZ;
 3572                                 uio_iov_base_add(uiop, DIRHDSIZ);
 3573                                 uio_iov_len_add(uiop, -(DIRHDSIZ));
 3574                                 cnp->cn_nameptr = uio_iov_base(uiop);
 3575                                 cnp->cn_namelen = len;
 3576                                 NFSCNHASHZERO(cnp);
 3577                                 error = nfsm_mbufuio(nd, uiop, len);
 3578                                 if (error)
 3579                                         goto nfsmout;
 3580                                 cp = uio_iov_base(uiop);
 3581                                 tlen -= len;
 3582                                 NFSBZERO(cp, tlen);
 3583                                 cp += tlen;     /* points to cookie storage */
 3584                                 tl2 = (u_int32_t *)cp;
 3585                                 if (len == 2 && cnp->cn_nameptr[0] == '.' &&
 3586                                     cnp->cn_nameptr[1] == '.')
 3587                                         isdotdot = 1;
 3588                                 else
 3589                                         isdotdot = 0;
 3590                                 uio_iov_base_add(uiop, (tlen + NFSX_HYPER));
 3591                                 uio_iov_len_add(uiop, -(tlen + NFSX_HYPER));
 3592                                 uio_uio_resid_add(uiop, -(tlen + NFSX_HYPER));
 3593                                 uiop->uio_offset += (tlen + NFSX_HYPER);
 3594                         } else {
 3595                                 error = nfsm_advance(nd, NFSM_RNDUP(len), -1);
 3596                                 if (error)
 3597                                         goto nfsmout;
 3598                         }
 3599                         nfhp = NULL;
 3600                         if (nd->nd_flag & ND_NFSV3) {
 3601                                 NFSM_DISSECT(tl, u_int32_t *, 3*NFSX_UNSIGNED);
 3602                                 ncookie.lval[0] = *tl++;
 3603                                 ncookie.lval[1] = *tl++;
 3604                                 attrflag = fxdr_unsigned(int, *tl);
 3605                                 if (attrflag) {
 3606                                   error = nfsm_loadattr(nd, &nfsva);
 3607                                   if (error)
 3608                                         goto nfsmout;
 3609                                 }
 3610                                 NFSM_DISSECT(tl,u_int32_t *,NFSX_UNSIGNED);
 3611                                 if (*tl) {
 3612                                         error = nfsm_getfh(nd, &nfhp);
 3613                                         if (error)
 3614                                             goto nfsmout;
 3615                                 }
 3616                                 if (!attrflag && nfhp != NULL) {
 3617                                         free(nfhp, M_NFSFH);
 3618                                         nfhp = NULL;
 3619                                 }
 3620                         } else {
 3621                                 rderr = 0;
 3622                                 nfsva.na_mntonfileno = 0xffffffff;
 3623                                 error = nfsv4_loadattr(nd, NULL, &nfsva, &nfhp,
 3624                                     NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 3625                                     NULL, NULL, &rderr, p, cred);
 3626                                 if (error)
 3627                                         goto nfsmout;
 3628                         }
 3629 
 3630                         if (bigenough) {
 3631                             if (nd->nd_flag & ND_NFSV4) {
 3632                                 if (rderr) {
 3633                                     dp->d_fileno = 0;
 3634                                 } else if (gotmnton) {
 3635                                     if (nfsva.na_mntonfileno != 0xffffffff)
 3636                                         dp->d_fileno = nfsva.na_mntonfileno;
 3637                                     else
 3638                                         dp->d_fileno = nfsva.na_fileid;
 3639                                 } else if (nfsva.na_filesid[0] ==
 3640                                     dnp->n_vattr.na_filesid[0] &&
 3641                                     nfsva.na_filesid[1] ==
 3642                                     dnp->n_vattr.na_filesid[1]) {
 3643                                     dp->d_fileno = nfsva.na_fileid;
 3644                                 } else {
 3645                                     do {
 3646                                         fakefileno--;
 3647                                     } while (fakefileno ==
 3648                                         nfsva.na_fileid);
 3649                                     dp->d_fileno = fakefileno;
 3650                                 }
 3651                             } else {
 3652                                 dp->d_fileno = fileno;
 3653                             }
 3654                             *tl2++ = cookiep->nfsuquad[0] = cookie.lval[0] =
 3655                                 ncookie.lval[0];
 3656                             *tl2 = cookiep->nfsuquad[1] = cookie.lval[1] =
 3657                                 ncookie.lval[1];
 3658 
 3659                             if (nfhp != NULL) {
 3660                                 attr_ok = true;
 3661                                 if (NFSRV_CMPFH(nfhp->nfh_fh, nfhp->nfh_len,
 3662                                     dnp->n_fhp->nfh_fh, dnp->n_fhp->nfh_len)) {
 3663                                     VREF(vp);
 3664                                     newvp = vp;
 3665                                     unlocknewvp = 0;
 3666                                     free(nfhp, M_NFSFH);
 3667                                     np = dnp;
 3668                                 } else if (isdotdot != 0) {
 3669                                     /*
 3670                                      * Skip doing a nfscl_nget() call for "..".
 3671                                      * There's a race between acquiring the nfs
 3672                                      * node here and lookups that look for the
 3673                                      * directory being read (in the parent).
 3674                                      * It would try to get a lock on ".." here,
 3675                                      * owning the lock on the directory being
 3676                                      * read. Lookup will hold the lock on ".."
 3677                                      * and try to acquire the lock on the
 3678                                      * directory being read.
 3679                                      * If the directory is unlocked/relocked,
 3680                                      * then there is a LOR with the buflock
 3681                                      * vp is relocked.
 3682                                      */
 3683                                     free(nfhp, M_NFSFH);
 3684                                 } else {
 3685                                     error = nfscl_nget(vnode_mount(vp), vp,
 3686                                       nfhp, cnp, p, &np, NULL, LK_EXCLUSIVE);
 3687                                     if (!error) {
 3688                                         newvp = NFSTOV(np);
 3689                                         unlocknewvp = 1;
 3690                                         /*
 3691                                          * If n_localmodtime >= time before RPC,
 3692                                          * then a file modification operation,
 3693                                          * such as VOP_SETATTR() of size, has
 3694                                          * occurred while the Lookup RPC and
 3695                                          * acquisition of the vnode happened. As
 3696                                          * such, the attributes might be stale,
 3697                                          * with possibly an incorrect size.
 3698                                          */
 3699                                         NFSLOCKNODE(np);
 3700                                         if (timespecisset(
 3701                                             &np->n_localmodtime) &&
 3702                                             timespeccmp(&np->n_localmodtime,
 3703                                             &ts, >=)) {
 3704                                             NFSCL_DEBUG(4, "nfsrpc_readdirplus:"
 3705                                                 " localmod stale attributes\n");
 3706                                             attr_ok = false;
 3707                                         }
 3708                                         NFSUNLOCKNODE(np);
 3709                                     }
 3710                                 }
 3711                                 nfhp = NULL;
 3712                                 if (newvp != NULLVP) {
 3713                                     if (attr_ok)
 3714                                         error = nfscl_loadattrcache(&newvp,
 3715                                             &nfsva, NULL, NULL, 0, 0);
 3716                                     if (error) {
 3717                                         if (unlocknewvp)
 3718                                             vput(newvp);
 3719                                         else
 3720                                             vrele(newvp);
 3721                                         goto nfsmout;
 3722                                     }
 3723                                     dp->d_type =
 3724                                         vtonfs_dtype(np->n_vattr.na_type);
 3725                                     ndp->ni_vp = newvp;
 3726                                     NFSCNHASH(cnp, HASHINIT);
 3727                                     if (cnp->cn_namelen <= NCHNAMLEN &&
 3728                                         ndp->ni_dvp != ndp->ni_vp &&
 3729                                         (newvp->v_type != VDIR ||
 3730                                          dctime.tv_sec != 0)) {
 3731                                         cache_enter_time(ndp->ni_dvp,
 3732                                             ndp->ni_vp, cnp,
 3733                                             &nfsva.na_ctime,
 3734                                             newvp->v_type != VDIR ? NULL :
 3735                                             &dctime);
 3736                                     }
 3737                                     if (unlocknewvp)
 3738                                         vput(newvp);
 3739                                     else
 3740                                         vrele(newvp);
 3741                                     newvp = NULLVP;
 3742                                 }
 3743                             }
 3744                         } else if (nfhp != NULL) {
 3745                             free(nfhp, M_NFSFH);
 3746                         }
 3747                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3748                         more_dirs = fxdr_unsigned(int, *tl);
 3749                 }
 3750                 /*
 3751                  * If at end of rpc data, get the eof boolean
 3752                  */
 3753                 if (!more_dirs) {
 3754                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3755                         eof = fxdr_unsigned(int, *tl);
 3756                         if (tryformoredirs)
 3757                                 more_dirs = !eof;
 3758                         if (nd->nd_flag & ND_NFSV4) {
 3759                                 error = nfscl_postop_attr(nd, nap, attrflagp,
 3760                                     stuff);
 3761                                 if (error)
 3762                                         goto nfsmout;
 3763                         }
 3764                 }
 3765                 mbuf_freem(nd->nd_mrep);
 3766                 nd->nd_mrep = NULL;
 3767         }
 3768         /*
 3769          * Fill last record, iff any, out to a multiple of DIRBLKSIZ
 3770          * by increasing d_reclen for the last record.
 3771          */
 3772         if (blksiz > 0) {
 3773                 left = DIRBLKSIZ - blksiz;
 3774                 NFSBZERO(uio_iov_base(uiop), left);
 3775                 dp->d_reclen += left;
 3776                 uio_iov_base_add(uiop, left);
 3777                 uio_iov_len_add(uiop, -(left));
 3778                 uio_uio_resid_add(uiop, -(left));
 3779                 uiop->uio_offset += left;
 3780         }
 3781 
 3782         /*
 3783          * If returning no data, assume end of file.
 3784          * If not bigenough, return not end of file, since you aren't
 3785          *    returning all the data
 3786          * Otherwise, return the eof flag from the server.
 3787          */
 3788         if (eofp != NULL) {
 3789                 if (tresid == uio_uio_resid(uiop))
 3790                         *eofp = 1;
 3791                 else if (!bigenough)
 3792                         *eofp = 0;
 3793                 else
 3794                         *eofp = eof;
 3795         }
 3796 
 3797         /*
 3798          * Add extra empty records to any remaining DIRBLKSIZ chunks.
 3799          */
 3800         while (uio_uio_resid(uiop) > 0 && uio_uio_resid(uiop) != tresid) {
 3801                 dp = (struct dirent *)uio_iov_base(uiop);
 3802                 NFSBZERO(dp, DIRBLKSIZ);
 3803                 dp->d_type = DT_UNKNOWN;
 3804                 tl = (u_int32_t *)&dp->d_name[4];
 3805                 *tl++ = cookie.lval[0];
 3806                 *tl = cookie.lval[1];
 3807                 dp->d_reclen = DIRBLKSIZ;
 3808                 uio_iov_base_add(uiop, DIRBLKSIZ);
 3809                 uio_iov_len_add(uiop, -(DIRBLKSIZ));
 3810                 uio_uio_resid_add(uiop, -(DIRBLKSIZ));
 3811                 uiop->uio_offset += DIRBLKSIZ;
 3812         }
 3813 
 3814 nfsmout:
 3815         if (nd->nd_mrep != NULL)
 3816                 mbuf_freem(nd->nd_mrep);
 3817         return (error);
 3818 }
 3819 #endif  /* !APPLE */
 3820 
 3821 /*
 3822  * Nfs commit rpc
 3823  */
 3824 int
 3825 nfsrpc_commit(vnode_t vp, u_quad_t offset, int cnt, struct ucred *cred,
 3826     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 3827 {
 3828         u_int32_t *tl;
 3829         struct nfsrv_descript nfsd, *nd = &nfsd;
 3830         nfsattrbit_t attrbits;
 3831         int error;
 3832         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 3833         
 3834         *attrflagp = 0;
 3835         NFSCL_REQSTART(nd, NFSPROC_COMMIT, vp);
 3836         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3837         txdr_hyper(offset, tl);
 3838         tl += 2;
 3839         *tl = txdr_unsigned(cnt);
 3840         if (nd->nd_flag & ND_NFSV4) {
 3841                 /*
 3842                  * And do a Getattr op.
 3843                  */
 3844                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3845                 *tl = txdr_unsigned(NFSV4OP_GETATTR);
 3846                 NFSGETATTR_ATTRBIT(&attrbits);
 3847                 (void) nfsrv_putattrbit(nd, &attrbits);
 3848         }
 3849         error = nfscl_request(nd, vp, p, cred, stuff);
 3850         if (error)
 3851                 return (error);
 3852         error = nfscl_wcc_data(nd, vp, nap, attrflagp, NULL, stuff);
 3853         if (!error && !nd->nd_repstat) {
 3854                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 3855                 NFSLOCKMNT(nmp);
 3856                 if (NFSBCMP(nmp->nm_verf, tl, NFSX_VERF)) {
 3857                         NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
 3858                         nd->nd_repstat = NFSERR_STALEWRITEVERF;
 3859                 }
 3860                 NFSUNLOCKMNT(nmp);
 3861                 if (nd->nd_flag & ND_NFSV4)
 3862                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 3863         }
 3864 nfsmout:
 3865         if (!error && nd->nd_repstat)
 3866                 error = nd->nd_repstat;
 3867         mbuf_freem(nd->nd_mrep);
 3868         return (error);
 3869 }
 3870 
 3871 /*
 3872  * NFS byte range lock rpc.
 3873  * (Mostly just calls one of the three lower level RPC routines.)
 3874  */
 3875 int
 3876 nfsrpc_advlock(vnode_t vp, off_t size, int op, struct flock *fl,
 3877     int reclaim, struct ucred *cred, NFSPROC_T *p, void *id, int flags)
 3878 {
 3879         struct nfscllockowner *lp;
 3880         struct nfsclclient *clp;
 3881         struct nfsfh *nfhp;
 3882         struct nfsrv_descript nfsd, *nd = &nfsd;
 3883         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 3884         u_int64_t off, len;
 3885         off_t start, end;
 3886         u_int32_t clidrev = 0;
 3887         int error = 0, newone = 0, expireret = 0, retrycnt, donelocally;
 3888         int callcnt, dorpc;
 3889 
 3890         /*
 3891          * Convert the flock structure into a start and end and do POSIX
 3892          * bounds checking.
 3893          */
 3894         switch (fl->l_whence) {
 3895         case SEEK_SET:
 3896         case SEEK_CUR:
 3897                 /*
 3898                  * Caller is responsible for adding any necessary offset
 3899                  * when SEEK_CUR is used.
 3900                  */
 3901                 start = fl->l_start;
 3902                 off = fl->l_start;
 3903                 break;
 3904         case SEEK_END:
 3905                 start = size + fl->l_start;
 3906                 off = size + fl->l_start;
 3907                 break;
 3908         default:
 3909                 return (EINVAL);
 3910         }
 3911         if (start < 0)
 3912                 return (EINVAL);
 3913         if (fl->l_len != 0) {
 3914                 end = start + fl->l_len - 1;
 3915                 if (end < start)
 3916                         return (EINVAL);
 3917         }
 3918 
 3919         len = fl->l_len;
 3920         if (len == 0)
 3921                 len = NFS64BITSSET;
 3922         retrycnt = 0;
 3923         do {
 3924             nd->nd_repstat = 0;
 3925             if (op == F_GETLK) {
 3926                 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, true, &clp);
 3927                 if (error)
 3928                         return (error);
 3929                 error = nfscl_lockt(vp, clp, off, len, fl, p, id, flags);
 3930                 if (!error) {
 3931                         clidrev = clp->nfsc_clientidrev;
 3932                         error = nfsrpc_lockt(nd, vp, clp, off, len, fl, cred,
 3933                             p, id, flags);
 3934                 } else if (error == -1) {
 3935                         error = 0;
 3936                 }
 3937                 nfscl_clientrelease(clp);
 3938             } else if (op == F_UNLCK && fl->l_type == F_UNLCK) {
 3939                 /*
 3940                  * We must loop around for all lockowner cases.
 3941                  */
 3942                 callcnt = 0;
 3943                 error = nfscl_getcl(vnode_mount(vp), cred, p, 1, true, &clp);
 3944                 if (error)
 3945                         return (error);
 3946                 do {
 3947                     error = nfscl_relbytelock(vp, off, len, cred, p, callcnt,
 3948                         clp, id, flags, &lp, &dorpc);
 3949                     /*
 3950                      * If it returns a NULL lp, we're done.
 3951                      */
 3952                     if (lp == NULL) {
 3953                         if (callcnt == 0)
 3954                             nfscl_clientrelease(clp);
 3955                         else
 3956                             nfscl_releasealllocks(clp, vp, p, id, flags);
 3957                         return (error);
 3958                     }
 3959                     if (nmp->nm_clp != NULL)
 3960                         clidrev = nmp->nm_clp->nfsc_clientidrev;
 3961                     else
 3962                         clidrev = 0;
 3963                     /*
 3964                      * If the server doesn't support Posix lock semantics,
 3965                      * only allow locks on the entire file, since it won't
 3966                      * handle overlapping byte ranges.
 3967                      * There might still be a problem when a lock
 3968                      * upgrade/downgrade (read<->write) occurs, since the
 3969                      * server "might" expect an unlock first?
 3970                      */
 3971                     if (dorpc && (lp->nfsl_open->nfso_posixlock ||
 3972                         (off == 0 && len == NFS64BITSSET))) {
 3973                         /*
 3974                          * Since the lock records will go away, we must
 3975                          * wait for grace and delay here.
 3976                          */
 3977                         do {
 3978                             error = nfsrpc_locku(nd, nmp, lp, off, len,
 3979                                 NFSV4LOCKT_READ, cred, p, 0);
 3980                             if ((nd->nd_repstat == NFSERR_GRACE ||
 3981                                  nd->nd_repstat == NFSERR_DELAY) &&
 3982                                 error == 0)
 3983                                 (void) nfs_catnap(PZERO, (int)nd->nd_repstat,
 3984                                     "nfs_advlock");
 3985                         } while ((nd->nd_repstat == NFSERR_GRACE ||
 3986                             nd->nd_repstat == NFSERR_DELAY) && error == 0);
 3987                     }
 3988                     callcnt++;
 3989                 } while (error == 0 && nd->nd_repstat == 0);
 3990                 nfscl_releasealllocks(clp, vp, p, id, flags);
 3991             } else if (op == F_SETLK) {
 3992                 error = nfscl_getbytelock(vp, off, len, fl->l_type, cred, p,
 3993                     NULL, 0, id, flags, NULL, NULL, &lp, &newone, &donelocally);
 3994                 if (error || donelocally) {
 3995                         return (error);
 3996                 }
 3997                 if (nmp->nm_clp != NULL)
 3998                         clidrev = nmp->nm_clp->nfsc_clientidrev;
 3999                 else
 4000                         clidrev = 0;
 4001                 nfhp = VTONFS(vp)->n_fhp;
 4002                 if (!lp->nfsl_open->nfso_posixlock &&
 4003                     (off != 0 || len != NFS64BITSSET)) {
 4004                         error = EINVAL;
 4005                 } else {
 4006                         error = nfsrpc_lock(nd, nmp, vp, nfhp->nfh_fh,
 4007                             nfhp->nfh_len, lp, newone, reclaim, off,
 4008                             len, fl->l_type, cred, p, 0);
 4009                 }
 4010                 if (!error)
 4011                         error = nd->nd_repstat;
 4012                 nfscl_lockrelease(lp, error, newone);
 4013             } else {
 4014                 error = EINVAL;
 4015             }
 4016             if (!error)
 4017                 error = nd->nd_repstat;
 4018             if (error == NFSERR_GRACE || error == NFSERR_STALESTATEID ||
 4019                 error == NFSERR_STALEDONTRECOVER ||
 4020                 error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
 4021                 error == NFSERR_BADSESSION) {
 4022                 (void) nfs_catnap(PZERO, error, "nfs_advlock");
 4023             } else if ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID)
 4024                 && clidrev != 0) {
 4025                 expireret = nfscl_hasexpired(nmp->nm_clp, clidrev, p);
 4026                 retrycnt++;
 4027             }
 4028         } while (error == NFSERR_GRACE ||
 4029             error == NFSERR_STALECLIENTID || error == NFSERR_DELAY ||
 4030             error == NFSERR_STALEDONTRECOVER || error == NFSERR_STALESTATEID ||
 4031             error == NFSERR_BADSESSION ||
 4032             ((error == NFSERR_EXPIRED || error == NFSERR_BADSTATEID) &&
 4033              expireret == 0 && clidrev != 0 && retrycnt < 4));
 4034         if (error && retrycnt >= 4)
 4035                 error = EIO;
 4036         return (error);
 4037 }
 4038 
 4039 /*
 4040  * The lower level routine for the LockT case.
 4041  */
 4042 int
 4043 nfsrpc_lockt(struct nfsrv_descript *nd, vnode_t vp,
 4044     struct nfsclclient *clp, u_int64_t off, u_int64_t len, struct flock *fl,
 4045     struct ucred *cred, NFSPROC_T *p, void *id, int flags)
 4046 {
 4047         u_int32_t *tl;
 4048         int error, type, size;
 4049         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
 4050         struct nfsnode *np;
 4051         struct nfsmount *nmp;
 4052         struct nfsclsession *tsep;
 4053 
 4054         nmp = VFSTONFS(vp->v_mount);
 4055         NFSCL_REQSTART(nd, NFSPROC_LOCKT, vp);
 4056         NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 4057         if (fl->l_type == F_RDLCK)
 4058                 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 4059         else
 4060                 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 4061         txdr_hyper(off, tl);
 4062         tl += 2;
 4063         txdr_hyper(len, tl);
 4064         tl += 2;
 4065         tsep = nfsmnt_mdssession(nmp);
 4066         *tl++ = tsep->nfsess_clientid.lval[0];
 4067         *tl = tsep->nfsess_clientid.lval[1];
 4068         nfscl_filllockowner(id, own, flags);
 4069         np = VTONFS(vp);
 4070         NFSBCOPY(np->n_fhp->nfh_fh, &own[NFSV4CL_LOCKNAMELEN],
 4071             np->n_fhp->nfh_len);
 4072         (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + np->n_fhp->nfh_len);
 4073         error = nfscl_request(nd, vp, p, cred, NULL);
 4074         if (error)
 4075                 return (error);
 4076         if (nd->nd_repstat == 0) {
 4077                 fl->l_type = F_UNLCK;
 4078         } else if (nd->nd_repstat == NFSERR_DENIED) {
 4079                 nd->nd_repstat = 0;
 4080                 fl->l_whence = SEEK_SET;
 4081                 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
 4082                 fl->l_start = fxdr_hyper(tl);
 4083                 tl += 2;
 4084                 len = fxdr_hyper(tl);
 4085                 tl += 2;
 4086                 if (len == NFS64BITSSET)
 4087                         fl->l_len = 0;
 4088                 else
 4089                         fl->l_len = len;
 4090                 type = fxdr_unsigned(int, *tl++);
 4091                 if (type == NFSV4LOCKT_WRITE)
 4092                         fl->l_type = F_WRLCK;
 4093                 else
 4094                         fl->l_type = F_RDLCK;
 4095                 /*
 4096                  * XXX For now, I have no idea what to do with the
 4097                  * conflicting lock_owner, so I'll just set the pid == 0
 4098                  * and skip over the lock_owner.
 4099                  */
 4100                 fl->l_pid = (pid_t)0;
 4101                 tl += 2;
 4102                 size = fxdr_unsigned(int, *tl);
 4103                 if (size < 0 || size > NFSV4_OPAQUELIMIT)
 4104                         error = EBADRPC;
 4105                 if (!error)
 4106                         error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
 4107         } else if (nd->nd_repstat == NFSERR_STALECLIENTID)
 4108                 nfscl_initiate_recovery(clp);
 4109 nfsmout:
 4110         mbuf_freem(nd->nd_mrep);
 4111         return (error);
 4112 }
 4113 
 4114 /*
 4115  * Lower level function that performs the LockU RPC.
 4116  */
 4117 static int
 4118 nfsrpc_locku(struct nfsrv_descript *nd, struct nfsmount *nmp,
 4119     struct nfscllockowner *lp, u_int64_t off, u_int64_t len,
 4120     u_int32_t type, struct ucred *cred, NFSPROC_T *p, int syscred)
 4121 {
 4122         u_int32_t *tl;
 4123         int error;
 4124 
 4125         nfscl_reqstart(nd, NFSPROC_LOCKU, nmp, lp->nfsl_open->nfso_fh,
 4126             lp->nfsl_open->nfso_fhlen, NULL, NULL, 0, 0);
 4127         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
 4128         *tl++ = txdr_unsigned(type);
 4129         *tl = txdr_unsigned(lp->nfsl_seqid);
 4130         if (nfstest_outofseq &&
 4131             (arc4random() % nfstest_outofseq) == 0)
 4132                 *tl = txdr_unsigned(lp->nfsl_seqid + 1);
 4133         tl++;
 4134         if (NFSHASNFSV4N(nmp))
 4135                 *tl++ = 0;
 4136         else
 4137                 *tl++ = lp->nfsl_stateid.seqid;
 4138         *tl++ = lp->nfsl_stateid.other[0];
 4139         *tl++ = lp->nfsl_stateid.other[1];
 4140         *tl++ = lp->nfsl_stateid.other[2];
 4141         txdr_hyper(off, tl);
 4142         tl += 2;
 4143         txdr_hyper(len, tl);
 4144         if (syscred)
 4145                 nd->nd_flag |= ND_USEGSSNAME;
 4146         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4147             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4148         NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
 4149         if (error)
 4150                 return (error);
 4151         if (nd->nd_repstat == 0) {
 4152                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 4153                 lp->nfsl_stateid.seqid = *tl++;
 4154                 lp->nfsl_stateid.other[0] = *tl++;
 4155                 lp->nfsl_stateid.other[1] = *tl++;
 4156                 lp->nfsl_stateid.other[2] = *tl;
 4157         } else if (nd->nd_repstat == NFSERR_STALESTATEID)
 4158                 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
 4159 nfsmout:
 4160         mbuf_freem(nd->nd_mrep);
 4161         return (error);
 4162 }
 4163 
 4164 /*
 4165  * The actual Lock RPC.
 4166  */
 4167 int
 4168 nfsrpc_lock(struct nfsrv_descript *nd, struct nfsmount *nmp, vnode_t vp,
 4169     u_int8_t *nfhp, int fhlen, struct nfscllockowner *lp, int newone,
 4170     int reclaim, u_int64_t off, u_int64_t len, short type, struct ucred *cred,
 4171     NFSPROC_T *p, int syscred)
 4172 {
 4173         u_int32_t *tl;
 4174         int error, size;
 4175         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
 4176         struct nfsclsession *tsep;
 4177 
 4178         nfscl_reqstart(nd, NFSPROC_LOCK, nmp, nfhp, fhlen, NULL, NULL, 0, 0);
 4179         NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 4180         if (type == F_RDLCK)
 4181                 *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 4182         else
 4183                 *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 4184         *tl++ = txdr_unsigned(reclaim);
 4185         txdr_hyper(off, tl);
 4186         tl += 2;
 4187         txdr_hyper(len, tl);
 4188         tl += 2;
 4189         if (newone) {
 4190             *tl = newnfs_true;
 4191             NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID +
 4192                 2 * NFSX_UNSIGNED + NFSX_HYPER);
 4193             *tl++ = txdr_unsigned(lp->nfsl_open->nfso_own->nfsow_seqid);
 4194             if (NFSHASNFSV4N(nmp))
 4195                 *tl++ = 0;
 4196             else
 4197                 *tl++ = lp->nfsl_open->nfso_stateid.seqid;
 4198             *tl++ = lp->nfsl_open->nfso_stateid.other[0];
 4199             *tl++ = lp->nfsl_open->nfso_stateid.other[1];
 4200             *tl++ = lp->nfsl_open->nfso_stateid.other[2];
 4201             *tl++ = txdr_unsigned(lp->nfsl_seqid);
 4202             tsep = nfsmnt_mdssession(nmp);
 4203             *tl++ = tsep->nfsess_clientid.lval[0];
 4204             *tl = tsep->nfsess_clientid.lval[1];
 4205             NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
 4206             NFSBCOPY(nfhp, &own[NFSV4CL_LOCKNAMELEN], fhlen);
 4207             (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
 4208         } else {
 4209             *tl = newnfs_false;
 4210             NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 4211             if (NFSHASNFSV4N(nmp))
 4212                 *tl++ = 0;
 4213             else
 4214                 *tl++ = lp->nfsl_stateid.seqid;
 4215             *tl++ = lp->nfsl_stateid.other[0];
 4216             *tl++ = lp->nfsl_stateid.other[1];
 4217             *tl++ = lp->nfsl_stateid.other[2];
 4218             *tl = txdr_unsigned(lp->nfsl_seqid);
 4219             if (nfstest_outofseq &&
 4220                 (arc4random() % nfstest_outofseq) == 0)
 4221                     *tl = txdr_unsigned(lp->nfsl_seqid + 1);
 4222         }
 4223         if (syscred)
 4224                 nd->nd_flag |= ND_USEGSSNAME;
 4225         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
 4226             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4227         if (error)
 4228                 return (error);
 4229         if (newone)
 4230             NFSCL_INCRSEQID(lp->nfsl_open->nfso_own->nfsow_seqid, nd);
 4231         NFSCL_INCRSEQID(lp->nfsl_seqid, nd);
 4232         if (nd->nd_repstat == 0) {
 4233                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 4234                 lp->nfsl_stateid.seqid = *tl++;
 4235                 lp->nfsl_stateid.other[0] = *tl++;
 4236                 lp->nfsl_stateid.other[1] = *tl++;
 4237                 lp->nfsl_stateid.other[2] = *tl;
 4238         } else if (nd->nd_repstat == NFSERR_DENIED) {
 4239                 NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
 4240                 size = fxdr_unsigned(int, *(tl + 7));
 4241                 if (size < 0 || size > NFSV4_OPAQUELIMIT)
 4242                         error = EBADRPC;
 4243                 if (!error)
 4244                         error = nfsm_advance(nd, NFSM_RNDUP(size), -1);
 4245         } else if (nd->nd_repstat == NFSERR_STALESTATEID)
 4246                 nfscl_initiate_recovery(lp->nfsl_open->nfso_own->nfsow_clp);
 4247 nfsmout:
 4248         mbuf_freem(nd->nd_mrep);
 4249         return (error);
 4250 }
 4251 
 4252 /*
 4253  * nfs statfs rpc
 4254  * (always called with the vp for the mount point)
 4255  */
 4256 int
 4257 nfsrpc_statfs(vnode_t vp, struct nfsstatfs *sbp, struct nfsfsinfo *fsp,
 4258     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 4259     void *stuff)
 4260 {
 4261         u_int32_t *tl = NULL;
 4262         struct nfsrv_descript nfsd, *nd = &nfsd;
 4263         struct nfsmount *nmp;
 4264         nfsattrbit_t attrbits;
 4265         int error;
 4266 
 4267         *attrflagp = 0;
 4268         nmp = VFSTONFS(vnode_mount(vp));
 4269         if (NFSHASNFSV4(nmp)) {
 4270                 /*
 4271                  * For V4, you actually do a getattr.
 4272                  */
 4273                 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
 4274                 NFSSTATFS_GETATTRBIT(&attrbits);
 4275                 (void) nfsrv_putattrbit(nd, &attrbits);
 4276                 nd->nd_flag |= ND_USEGSSNAME;
 4277                 error = nfscl_request(nd, vp, p, cred, stuff);
 4278                 if (error)
 4279                         return (error);
 4280                 if (nd->nd_repstat == 0) {
 4281                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
 4282                             NULL, NULL, sbp, fsp, NULL, 0, NULL, NULL, NULL, p,
 4283                             cred);
 4284                         if (!error) {
 4285                                 nmp->nm_fsid[0] = nap->na_filesid[0];
 4286                                 nmp->nm_fsid[1] = nap->na_filesid[1];
 4287                                 NFSSETHASSETFSID(nmp);
 4288                                 *attrflagp = 1;
 4289                         }
 4290                 } else {
 4291                         error = nd->nd_repstat;
 4292                 }
 4293                 if (error)
 4294                         goto nfsmout;
 4295         } else {
 4296                 NFSCL_REQSTART(nd, NFSPROC_FSSTAT, vp);
 4297                 error = nfscl_request(nd, vp, p, cred, stuff);
 4298                 if (error)
 4299                         return (error);
 4300                 if (nd->nd_flag & ND_NFSV3) {
 4301                         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 4302                         if (error)
 4303                                 goto nfsmout;
 4304                 }
 4305                 if (nd->nd_repstat) {
 4306                         error = nd->nd_repstat;
 4307                         goto nfsmout;
 4308                 }
 4309                 NFSM_DISSECT(tl, u_int32_t *,
 4310                     NFSX_STATFS(nd->nd_flag & ND_NFSV3));
 4311         }
 4312         if (NFSHASNFSV3(nmp)) {
 4313                 sbp->sf_tbytes = fxdr_hyper(tl); tl += 2;
 4314                 sbp->sf_fbytes = fxdr_hyper(tl); tl += 2;
 4315                 sbp->sf_abytes = fxdr_hyper(tl); tl += 2;
 4316                 sbp->sf_tfiles = fxdr_hyper(tl); tl += 2;
 4317                 sbp->sf_ffiles = fxdr_hyper(tl); tl += 2;
 4318                 sbp->sf_afiles = fxdr_hyper(tl); tl += 2;
 4319                 sbp->sf_invarsec = fxdr_unsigned(u_int32_t, *tl);
 4320         } else if (NFSHASNFSV4(nmp) == 0) {
 4321                 sbp->sf_tsize = fxdr_unsigned(u_int32_t, *tl++);
 4322                 sbp->sf_bsize = fxdr_unsigned(u_int32_t, *tl++);
 4323                 sbp->sf_blocks = fxdr_unsigned(u_int32_t, *tl++);
 4324                 sbp->sf_bfree = fxdr_unsigned(u_int32_t, *tl++);
 4325                 sbp->sf_bavail = fxdr_unsigned(u_int32_t, *tl);
 4326         }
 4327 nfsmout:
 4328         mbuf_freem(nd->nd_mrep);
 4329         return (error);
 4330 }
 4331 
 4332 /*
 4333  * nfs pathconf rpc
 4334  */
 4335 int
 4336 nfsrpc_pathconf(vnode_t vp, struct nfsv3_pathconf *pc,
 4337     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp,
 4338     void *stuff)
 4339 {
 4340         struct nfsrv_descript nfsd, *nd = &nfsd;
 4341         struct nfsmount *nmp;
 4342         u_int32_t *tl;
 4343         nfsattrbit_t attrbits;
 4344         int error;
 4345 
 4346         *attrflagp = 0;
 4347         nmp = VFSTONFS(vnode_mount(vp));
 4348         if (NFSHASNFSV4(nmp)) {
 4349                 /*
 4350                  * For V4, you actually do a getattr.
 4351                  */
 4352                 NFSCL_REQSTART(nd, NFSPROC_GETATTR, vp);
 4353                 NFSPATHCONF_GETATTRBIT(&attrbits);
 4354                 (void) nfsrv_putattrbit(nd, &attrbits);
 4355                 nd->nd_flag |= ND_USEGSSNAME;
 4356                 error = nfscl_request(nd, vp, p, cred, stuff);
 4357                 if (error)
 4358                         return (error);
 4359                 if (nd->nd_repstat == 0) {
 4360                         error = nfsv4_loadattr(nd, NULL, nap, NULL, NULL, 0,
 4361                             pc, NULL, NULL, NULL, NULL, 0, NULL, NULL, NULL, p,
 4362                             cred);
 4363                         if (!error)
 4364                                 *attrflagp = 1;
 4365                 } else {
 4366                         error = nd->nd_repstat;
 4367                 }
 4368         } else {
 4369                 NFSCL_REQSTART(nd, NFSPROC_PATHCONF, vp);
 4370                 error = nfscl_request(nd, vp, p, cred, stuff);
 4371                 if (error)
 4372                         return (error);
 4373                 error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 4374                 if (nd->nd_repstat && !error)
 4375                         error = nd->nd_repstat;
 4376                 if (!error) {
 4377                         NFSM_DISSECT(tl, u_int32_t *, NFSX_V3PATHCONF);
 4378                         pc->pc_linkmax = fxdr_unsigned(u_int32_t, *tl++);
 4379                         pc->pc_namemax = fxdr_unsigned(u_int32_t, *tl++);
 4380                         pc->pc_notrunc = fxdr_unsigned(u_int32_t, *tl++);
 4381                         pc->pc_chownrestricted =
 4382                             fxdr_unsigned(u_int32_t, *tl++);
 4383                         pc->pc_caseinsensitive =
 4384                             fxdr_unsigned(u_int32_t, *tl++);
 4385                         pc->pc_casepreserving = fxdr_unsigned(u_int32_t, *tl);
 4386                 }
 4387         }
 4388 nfsmout:
 4389         mbuf_freem(nd->nd_mrep);
 4390         return (error);
 4391 }
 4392 
 4393 /*
 4394  * nfs version 3 fsinfo rpc call
 4395  */
 4396 int
 4397 nfsrpc_fsinfo(vnode_t vp, struct nfsfsinfo *fsp, struct ucred *cred,
 4398     NFSPROC_T *p, struct nfsvattr *nap, int *attrflagp, void *stuff)
 4399 {
 4400         u_int32_t *tl;
 4401         struct nfsrv_descript nfsd, *nd = &nfsd;
 4402         int error;
 4403 
 4404         *attrflagp = 0;
 4405         NFSCL_REQSTART(nd, NFSPROC_FSINFO, vp);
 4406         error = nfscl_request(nd, vp, p, cred, stuff);
 4407         if (error)
 4408                 return (error);
 4409         error = nfscl_postop_attr(nd, nap, attrflagp, stuff);
 4410         if (nd->nd_repstat && !error)
 4411                 error = nd->nd_repstat;
 4412         if (!error) {
 4413                 NFSM_DISSECT(tl, u_int32_t *, NFSX_V3FSINFO);
 4414                 fsp->fs_rtmax = fxdr_unsigned(u_int32_t, *tl++);
 4415                 fsp->fs_rtpref = fxdr_unsigned(u_int32_t, *tl++);
 4416                 fsp->fs_rtmult = fxdr_unsigned(u_int32_t, *tl++);
 4417                 fsp->fs_wtmax = fxdr_unsigned(u_int32_t, *tl++);
 4418                 fsp->fs_wtpref = fxdr_unsigned(u_int32_t, *tl++);
 4419                 fsp->fs_wtmult = fxdr_unsigned(u_int32_t, *tl++);
 4420                 fsp->fs_dtpref = fxdr_unsigned(u_int32_t, *tl++);
 4421                 fsp->fs_maxfilesize = fxdr_hyper(tl);
 4422                 tl += 2;
 4423                 fxdr_nfsv3time(tl, &fsp->fs_timedelta);
 4424                 tl += 2;
 4425                 fsp->fs_properties = fxdr_unsigned(u_int32_t, *tl);
 4426         }
 4427 nfsmout:
 4428         mbuf_freem(nd->nd_mrep);
 4429         return (error);
 4430 }
 4431 
 4432 /*
 4433  * This function performs the Renew RPC.
 4434  */
 4435 int
 4436 nfsrpc_renew(struct nfsclclient *clp, struct nfsclds *dsp, struct ucred *cred,
 4437     NFSPROC_T *p)
 4438 {
 4439         u_int32_t *tl;
 4440         struct nfsrv_descript nfsd;
 4441         struct nfsrv_descript *nd = &nfsd;
 4442         struct nfsmount *nmp;
 4443         int error;
 4444         struct nfssockreq *nrp;
 4445         struct nfsclsession *tsep;
 4446 
 4447         nmp = clp->nfsc_nmp;
 4448         if (nmp == NULL)
 4449                 return (0);
 4450         if (dsp == NULL)
 4451                 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL, NULL, 0,
 4452                     0);
 4453         else
 4454                 nfscl_reqstart(nd, NFSPROC_RENEW, nmp, NULL, 0, NULL,
 4455                     &dsp->nfsclds_sess, 0, 0);
 4456         if (!NFSHASNFSV4N(nmp)) {
 4457                 /* NFSv4.1 just uses a Sequence Op and not a Renew. */
 4458                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 4459                 tsep = nfsmnt_mdssession(nmp);
 4460                 *tl++ = tsep->nfsess_clientid.lval[0];
 4461                 *tl = tsep->nfsess_clientid.lval[1];
 4462         }
 4463         nrp = NULL;
 4464         if (dsp != NULL)
 4465                 nrp = dsp->nfsclds_sockp;
 4466         if (nrp == NULL)
 4467                 /* If NULL, use the MDS socket. */
 4468                 nrp = &nmp->nm_sockreq;
 4469         nd->nd_flag |= ND_USEGSSNAME;
 4470         if (dsp == NULL)
 4471                 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
 4472                     NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4473         else {
 4474                 error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
 4475                     NFS_PROG, NFS_VER4, NULL, 1, NULL, &dsp->nfsclds_sess);
 4476                 if (error == ENXIO)
 4477                         nfscl_cancelreqs(dsp);
 4478         }
 4479         if (error)
 4480                 return (error);
 4481         error = nd->nd_repstat;
 4482         mbuf_freem(nd->nd_mrep);
 4483         return (error);
 4484 }
 4485 
 4486 /*
 4487  * This function performs the Releaselockowner RPC.
 4488  */
 4489 int
 4490 nfsrpc_rellockown(struct nfsmount *nmp, struct nfscllockowner *lp,
 4491     uint8_t *fh, int fhlen, struct ucred *cred, NFSPROC_T *p)
 4492 {
 4493         struct nfsrv_descript nfsd, *nd = &nfsd;
 4494         u_int32_t *tl;
 4495         int error;
 4496         uint8_t own[NFSV4CL_LOCKNAMELEN + NFSX_V4FHMAX];
 4497         struct nfsclsession *tsep;
 4498 
 4499         if (NFSHASNFSV4N(nmp)) {
 4500                 /* For NFSv4.1, do a FreeStateID. */
 4501                 nfscl_reqstart(nd, NFSPROC_FREESTATEID, nmp, NULL, 0, NULL,
 4502                     NULL, 0, 0);
 4503                 nfsm_stateidtom(nd, &lp->nfsl_stateid, NFSSTATEID_PUTSTATEID);
 4504         } else {
 4505                 nfscl_reqstart(nd, NFSPROC_RELEASELCKOWN, nmp, NULL, 0, NULL,
 4506                     NULL, 0, 0);
 4507                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 4508                 tsep = nfsmnt_mdssession(nmp);
 4509                 *tl++ = tsep->nfsess_clientid.lval[0];
 4510                 *tl = tsep->nfsess_clientid.lval[1];
 4511                 NFSBCOPY(lp->nfsl_owner, own, NFSV4CL_LOCKNAMELEN);
 4512                 NFSBCOPY(fh, &own[NFSV4CL_LOCKNAMELEN], fhlen);
 4513                 (void)nfsm_strtom(nd, own, NFSV4CL_LOCKNAMELEN + fhlen);
 4514         }
 4515         nd->nd_flag |= ND_USEGSSNAME;
 4516         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4517             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4518         if (error)
 4519                 return (error);
 4520         error = nd->nd_repstat;
 4521         mbuf_freem(nd->nd_mrep);
 4522         return (error);
 4523 }
 4524 
 4525 /*
 4526  * This function performs the Compound to get the mount pt FH.
 4527  */
 4528 int
 4529 nfsrpc_getdirpath(struct nfsmount *nmp, u_char *dirpath, struct ucred *cred,
 4530     NFSPROC_T *p)
 4531 {
 4532         u_int32_t *tl;
 4533         struct nfsrv_descript nfsd;
 4534         struct nfsrv_descript *nd = &nfsd;
 4535         u_char *cp, *cp2;
 4536         int error, cnt, len, setnil;
 4537         u_int32_t *opcntp;
 4538 
 4539         nfscl_reqstart(nd, NFSPROC_PUTROOTFH, nmp, NULL, 0, &opcntp, NULL, 0,
 4540             0);
 4541         cp = dirpath;
 4542         cnt = 0;
 4543         do {
 4544                 setnil = 0;
 4545                 while (*cp == '/')
 4546                         cp++;
 4547                 cp2 = cp;
 4548                 while (*cp2 != '\0' && *cp2 != '/')
 4549                         cp2++;
 4550                 if (*cp2 == '/') {
 4551                         setnil = 1;
 4552                         *cp2 = '\0';
 4553                 }
 4554                 if (cp2 != cp) {
 4555                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 4556                         *tl = txdr_unsigned(NFSV4OP_LOOKUP);
 4557                         nfsm_strtom(nd, cp, strlen(cp));
 4558                         cnt++;
 4559                 }
 4560                 if (setnil)
 4561                         *cp2++ = '/';
 4562                 cp = cp2;
 4563         } while (*cp != '\0');
 4564         if (NFSHASNFSV4N(nmp))
 4565                 /* Has a Sequence Op done by nfscl_reqstart(). */
 4566                 *opcntp = txdr_unsigned(3 + cnt);
 4567         else
 4568                 *opcntp = txdr_unsigned(2 + cnt);
 4569         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 4570         *tl = txdr_unsigned(NFSV4OP_GETFH);
 4571         nd->nd_flag |= ND_USEGSSNAME;
 4572         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4573                 NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4574         if (error)
 4575                 return (error);
 4576         if (nd->nd_repstat == 0) {
 4577                 NFSM_DISSECT(tl, u_int32_t *, (3 + 2 * cnt) * NFSX_UNSIGNED);
 4578                 tl += (2 + 2 * cnt);
 4579                 if ((len = fxdr_unsigned(int, *tl)) <= 0 ||
 4580                         len > NFSX_FHMAX) {
 4581                         nd->nd_repstat = NFSERR_BADXDR;
 4582                 } else {
 4583                         nd->nd_repstat = nfsrv_mtostr(nd, nmp->nm_fh, len);
 4584                         if (nd->nd_repstat == 0)
 4585                                 nmp->nm_fhsize = len;
 4586                 }
 4587         }
 4588         error = nd->nd_repstat;
 4589 nfsmout:
 4590         mbuf_freem(nd->nd_mrep);
 4591         return (error);
 4592 }
 4593 
 4594 /*
 4595  * This function performs the Delegreturn RPC.
 4596  */
 4597 int
 4598 nfsrpc_delegreturn(struct nfscldeleg *dp, struct ucred *cred,
 4599     struct nfsmount *nmp, NFSPROC_T *p, int syscred)
 4600 {
 4601         u_int32_t *tl;
 4602         struct nfsrv_descript nfsd;
 4603         struct nfsrv_descript *nd = &nfsd;
 4604         int error;
 4605 
 4606         nfscl_reqstart(nd, NFSPROC_DELEGRETURN, nmp, dp->nfsdl_fh,
 4607             dp->nfsdl_fhlen, NULL, NULL, 0, 0);
 4608         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 4609         if (NFSHASNFSV4N(nmp))
 4610                 *tl++ = 0;
 4611         else
 4612                 *tl++ = dp->nfsdl_stateid.seqid;
 4613         *tl++ = dp->nfsdl_stateid.other[0];
 4614         *tl++ = dp->nfsdl_stateid.other[1];
 4615         *tl = dp->nfsdl_stateid.other[2];
 4616         if (syscred)
 4617                 nd->nd_flag |= ND_USEGSSNAME;
 4618         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4619             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4620         if (error)
 4621                 return (error);
 4622         error = nd->nd_repstat;
 4623         mbuf_freem(nd->nd_mrep);
 4624         return (error);
 4625 }
 4626 
 4627 /*
 4628  * nfs getacl call.
 4629  */
 4630 int
 4631 nfsrpc_getacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
 4632     struct acl *aclp, void *stuff)
 4633 {
 4634         struct nfsrv_descript nfsd, *nd = &nfsd;
 4635         int error;
 4636         nfsattrbit_t attrbits;
 4637         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 4638         
 4639         if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
 4640                 return (EOPNOTSUPP);
 4641         NFSCL_REQSTART(nd, NFSPROC_GETACL, vp);
 4642         NFSZERO_ATTRBIT(&attrbits);
 4643         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
 4644         (void) nfsrv_putattrbit(nd, &attrbits);
 4645         error = nfscl_request(nd, vp, p, cred, stuff);
 4646         if (error)
 4647                 return (error);
 4648         if (!nd->nd_repstat)
 4649                 error = nfsv4_loadattr(nd, vp, NULL, NULL, NULL, 0, NULL,
 4650                     NULL, NULL, NULL, aclp, 0, NULL, NULL, NULL, p, cred);
 4651         else
 4652                 error = nd->nd_repstat;
 4653         mbuf_freem(nd->nd_mrep);
 4654         return (error);
 4655 }
 4656 
 4657 /*
 4658  * nfs setacl call.
 4659  */
 4660 int
 4661 nfsrpc_setacl(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
 4662     struct acl *aclp, void *stuff)
 4663 {
 4664         int error;
 4665         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 4666         
 4667         if (nfsrv_useacl == 0 || !NFSHASNFSV4(nmp))
 4668                 return (EOPNOTSUPP);
 4669         error = nfsrpc_setattr(vp, NULL, aclp, cred, p, NULL, NULL, stuff);
 4670         return (error);
 4671 }
 4672 
 4673 /*
 4674  * nfs setacl call.
 4675  */
 4676 static int
 4677 nfsrpc_setaclrpc(vnode_t vp, struct ucred *cred, NFSPROC_T *p,
 4678     struct acl *aclp, nfsv4stateid_t *stateidp, void *stuff)
 4679 {
 4680         struct nfsrv_descript nfsd, *nd = &nfsd;
 4681         int error;
 4682         nfsattrbit_t attrbits;
 4683         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 4684         
 4685         if (!NFSHASNFSV4(nmp))
 4686                 return (EOPNOTSUPP);
 4687         NFSCL_REQSTART(nd, NFSPROC_SETACL, vp);
 4688         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 4689         NFSZERO_ATTRBIT(&attrbits);
 4690         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_ACL);
 4691         (void) nfsv4_fillattr(nd, vnode_mount(vp), vp, aclp, NULL, NULL, 0,
 4692             &attrbits, NULL, NULL, 0, 0, 0, 0, (uint64_t)0, NULL);
 4693         error = nfscl_request(nd, vp, p, cred, stuff);
 4694         if (error)
 4695                 return (error);
 4696         /* Don't care about the pre/postop attributes */
 4697         mbuf_freem(nd->nd_mrep);
 4698         return (nd->nd_repstat);
 4699 }
 4700 
 4701 /*
 4702  * Do the NFSv4.1 Exchange ID.
 4703  */
 4704 int
 4705 nfsrpc_exchangeid(struct nfsmount *nmp, struct nfsclclient *clp,
 4706     struct nfssockreq *nrp, uint32_t exchflags, struct nfsclds **dspp,
 4707     struct ucred *cred, NFSPROC_T *p)
 4708 {
 4709         uint32_t *tl, v41flags;
 4710         struct nfsrv_descript nfsd;
 4711         struct nfsrv_descript *nd = &nfsd;
 4712         struct nfsclds *dsp;
 4713         struct timespec verstime;
 4714         int error, len;
 4715 
 4716         *dspp = NULL;
 4717         nfscl_reqstart(nd, NFSPROC_EXCHANGEID, nmp, NULL, 0, NULL, NULL, 0, 0);
 4718         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 4719         *tl++ = txdr_unsigned(nfsboottime.tv_sec);      /* Client owner */
 4720         *tl = txdr_unsigned(clp->nfsc_rev);
 4721         (void) nfsm_strtom(nd, clp->nfsc_id, clp->nfsc_idlen);
 4722 
 4723         NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
 4724         *tl++ = txdr_unsigned(exchflags);
 4725         *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);
 4726 
 4727         /* Set the implementation id4 */
 4728         *tl = txdr_unsigned(1);
 4729         (void) nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
 4730         (void) nfsm_strtom(nd, version, strlen(version));
 4731         NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
 4732         verstime.tv_sec = 1293840000;           /* Jan 1, 2011 */
 4733         verstime.tv_nsec = 0;
 4734         txdr_nfsv4time(&verstime, tl);
 4735         nd->nd_flag |= ND_USEGSSNAME;
 4736         error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred,
 4737             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4738         NFSCL_DEBUG(1, "exchangeid err=%d reps=%d\n", error,
 4739             (int)nd->nd_repstat);
 4740         if (error != 0)
 4741                 return (error);
 4742         if (nd->nd_repstat == 0) {
 4743                 NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_UNSIGNED + NFSX_HYPER);
 4744                 len = fxdr_unsigned(int, *(tl + 7));
 4745                 if (len < 0 || len > NFSV4_OPAQUELIMIT) {
 4746                         error = NFSERR_BADXDR;
 4747                         goto nfsmout;
 4748                 }
 4749                 dsp = malloc(sizeof(struct nfsclds) + len + 1, M_NFSCLDS,
 4750                     M_WAITOK | M_ZERO);
 4751                 dsp->nfsclds_expire = NFSD_MONOSEC + clp->nfsc_renew;
 4752                 dsp->nfsclds_servownlen = len;
 4753                 dsp->nfsclds_sess.nfsess_clientid.lval[0] = *tl++;
 4754                 dsp->nfsclds_sess.nfsess_clientid.lval[1] = *tl++;
 4755                 dsp->nfsclds_sess.nfsess_sequenceid =
 4756                     fxdr_unsigned(uint32_t, *tl++);
 4757                 v41flags = fxdr_unsigned(uint32_t, *tl);
 4758                 if ((v41flags & NFSV4EXCH_USEPNFSMDS) != 0 &&
 4759                     NFSHASPNFSOPT(nmp)) {
 4760                         NFSCL_DEBUG(1, "set PNFS\n");
 4761                         NFSLOCKMNT(nmp);
 4762                         nmp->nm_state |= NFSSTA_PNFS;
 4763                         NFSUNLOCKMNT(nmp);
 4764                         dsp->nfsclds_flags |= NFSCLDS_MDS;
 4765                 }
 4766                 if ((v41flags & NFSV4EXCH_USEPNFSDS) != 0)
 4767                         dsp->nfsclds_flags |= NFSCLDS_DS;
 4768                 if (len > 0)
 4769                         nd->nd_repstat = nfsrv_mtostr(nd,
 4770                             dsp->nfsclds_serverown, len);
 4771                 if (nd->nd_repstat == 0) {
 4772                         mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
 4773                         mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
 4774                             NULL, MTX_DEF);
 4775                         nfscl_initsessionslots(&dsp->nfsclds_sess);
 4776                         *dspp = dsp;
 4777                 } else
 4778                         free(dsp, M_NFSCLDS);
 4779         }
 4780         error = nd->nd_repstat;
 4781 nfsmout:
 4782         mbuf_freem(nd->nd_mrep);
 4783         return (error);
 4784 }
 4785 
 4786 /*
 4787  * Do the NFSv4.1 Create Session.
 4788  */
 4789 int
 4790 nfsrpc_createsession(struct nfsmount *nmp, struct nfsclsession *sep,
 4791     struct nfssockreq *nrp, uint32_t sequenceid, int mds, struct ucred *cred,
 4792     NFSPROC_T *p)
 4793 {
 4794         uint32_t crflags, maxval, *tl;
 4795         struct nfsrv_descript nfsd;
 4796         struct nfsrv_descript *nd = &nfsd;
 4797         int error, irdcnt;
 4798 
 4799         /* Make sure nm_rsize, nm_wsize is set. */
 4800         if (nmp->nm_rsize > NFS_MAXBSIZE || nmp->nm_rsize == 0)
 4801                 nmp->nm_rsize = NFS_MAXBSIZE;
 4802         if (nmp->nm_wsize > NFS_MAXBSIZE || nmp->nm_wsize == 0)
 4803                 nmp->nm_wsize = NFS_MAXBSIZE;
 4804         nfscl_reqstart(nd, NFSPROC_CREATESESSION, nmp, NULL, 0, NULL, NULL, 0,
 4805             0);
 4806         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
 4807         *tl++ = sep->nfsess_clientid.lval[0];
 4808         *tl++ = sep->nfsess_clientid.lval[1];
 4809         *tl++ = txdr_unsigned(sequenceid);
 4810         crflags = (NFSMNT_RDONLY(nmp->nm_mountp) ? 0 : NFSV4CRSESS_PERSIST);
 4811         if (nfscl_enablecallb != 0 && nfs_numnfscbd > 0 && mds != 0)
 4812                 crflags |= NFSV4CRSESS_CONNBACKCHAN;
 4813         *tl = txdr_unsigned(crflags);
 4814 
 4815         /* Fill in fore channel attributes. */
 4816         NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
 4817         *tl++ = 0;                              /* Header pad size */
 4818         *tl++ = txdr_unsigned(nmp->nm_wsize + NFS_MAXXDR);/* Max request size */
 4819         *tl++ = txdr_unsigned(nmp->nm_rsize + NFS_MAXXDR);/* Max reply size */
 4820         *tl++ = txdr_unsigned(4096);            /* Max response size cached */
 4821         *tl++ = txdr_unsigned(20);              /* Max operations */
 4822         *tl++ = txdr_unsigned(64);              /* Max slots */
 4823         *tl = 0;                                /* No rdma ird */
 4824 
 4825         /* Fill in back channel attributes. */
 4826         NFSM_BUILD(tl, uint32_t *, 7 * NFSX_UNSIGNED);
 4827         *tl++ = 0;                              /* Header pad size */
 4828         *tl++ = txdr_unsigned(10000);           /* Max request size */
 4829         *tl++ = txdr_unsigned(10000);           /* Max response size */
 4830         *tl++ = txdr_unsigned(4096);            /* Max response size cached */
 4831         *tl++ = txdr_unsigned(4);               /* Max operations */
 4832         *tl++ = txdr_unsigned(NFSV4_CBSLOTS);   /* Max slots */
 4833         *tl = 0;                                /* No rdma ird */
 4834 
 4835         NFSM_BUILD(tl, uint32_t *, 8 * NFSX_UNSIGNED);
 4836         *tl++ = txdr_unsigned(NFS_CALLBCKPROG); /* Call back prog # */
 4837 
 4838         /* Allow AUTH_SYS callbacks as uid, gid == 0. */
 4839         *tl++ = txdr_unsigned(1);               /* Auth_sys only */
 4840         *tl++ = txdr_unsigned(AUTH_SYS);        /* AUTH_SYS type */
 4841         *tl++ = txdr_unsigned(nfsboottime.tv_sec); /* time stamp */
 4842         *tl++ = 0;                              /* Null machine name */
 4843         *tl++ = 0;                              /* Uid == 0 */
 4844         *tl++ = 0;                              /* Gid == 0 */
 4845         *tl = 0;                                /* No additional gids */
 4846         nd->nd_flag |= ND_USEGSSNAME;
 4847         error = newnfs_request(nd, nmp, NULL, nrp, NULL, p, cred, NFS_PROG,
 4848             NFS_VER4, NULL, 1, NULL, NULL);
 4849         if (error != 0)
 4850                 return (error);
 4851         if (nd->nd_repstat == 0) {
 4852                 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
 4853                     2 * NFSX_UNSIGNED);
 4854                 bcopy(tl, sep->nfsess_sessionid, NFSX_V4SESSIONID);
 4855                 tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
 4856                 sep->nfsess_sequenceid = fxdr_unsigned(uint32_t, *tl++);
 4857                 crflags = fxdr_unsigned(uint32_t, *tl);
 4858                 if ((crflags & NFSV4CRSESS_PERSIST) != 0 && mds != 0) {
 4859                         NFSLOCKMNT(nmp);
 4860                         nmp->nm_state |= NFSSTA_SESSPERSIST;
 4861                         NFSUNLOCKMNT(nmp);
 4862                 }
 4863 
 4864                 /* Get the fore channel slot count. */
 4865                 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
 4866                 tl++;                   /* Skip the header pad size. */
 4867 
 4868                 /* Make sure nm_wsize is small enough. */
 4869                 maxval = fxdr_unsigned(uint32_t, *tl++);
 4870                 while (maxval < nmp->nm_wsize + NFS_MAXXDR) {
 4871                         if (nmp->nm_wsize > 8096)
 4872                                 nmp->nm_wsize /= 2;
 4873                         else
 4874                                 break;
 4875                 }
 4876 
 4877                 /* Make sure nm_rsize is small enough. */
 4878                 maxval = fxdr_unsigned(uint32_t, *tl++);
 4879                 while (maxval < nmp->nm_rsize + NFS_MAXXDR) {
 4880                         if (nmp->nm_rsize > 8096)
 4881                                 nmp->nm_rsize /= 2;
 4882                         else
 4883                                 break;
 4884                 }
 4885 
 4886                 sep->nfsess_maxcache = fxdr_unsigned(int, *tl++);
 4887                 tl++;
 4888                 sep->nfsess_foreslots = fxdr_unsigned(uint16_t, *tl++);
 4889                 NFSCL_DEBUG(4, "fore slots=%d\n", (int)sep->nfsess_foreslots);
 4890                 irdcnt = fxdr_unsigned(int, *tl);
 4891                 if (irdcnt < 0 || irdcnt > 1) {
 4892                         error = NFSERR_BADXDR;
 4893                         goto nfsmout;
 4894                 }
 4895                 if (irdcnt > 0)
 4896                         NFSM_DISSECT(tl, uint32_t *, irdcnt * NFSX_UNSIGNED);
 4897 
 4898                 /* and the back channel slot count. */
 4899                 NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
 4900                 tl += 5;
 4901                 sep->nfsess_backslots = fxdr_unsigned(uint16_t, *tl);
 4902                 NFSCL_DEBUG(4, "back slots=%d\n", (int)sep->nfsess_backslots);
 4903         }
 4904         error = nd->nd_repstat;
 4905 nfsmout:
 4906         mbuf_freem(nd->nd_mrep);
 4907         return (error);
 4908 }
 4909 
 4910 /*
 4911  * Do the NFSv4.1 Destroy Session.
 4912  */
 4913 int
 4914 nfsrpc_destroysession(struct nfsmount *nmp, struct nfsclclient *clp,
 4915     struct ucred *cred, NFSPROC_T *p)
 4916 {
 4917         uint32_t *tl;
 4918         struct nfsrv_descript nfsd;
 4919         struct nfsrv_descript *nd = &nfsd;
 4920         int error;
 4921         struct nfsclsession *tsep;
 4922 
 4923         nfscl_reqstart(nd, NFSPROC_DESTROYSESSION, nmp, NULL, 0, NULL, NULL, 0,
 4924             0);
 4925         NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
 4926         tsep = nfsmnt_mdssession(nmp);
 4927         bcopy(tsep->nfsess_sessionid, tl, NFSX_V4SESSIONID);
 4928         nd->nd_flag |= ND_USEGSSNAME;
 4929         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4930             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4931         if (error != 0)
 4932                 return (error);
 4933         error = nd->nd_repstat;
 4934         mbuf_freem(nd->nd_mrep);
 4935         return (error);
 4936 }
 4937 
 4938 /*
 4939  * Do the NFSv4.1 Destroy Client.
 4940  */
 4941 int
 4942 nfsrpc_destroyclient(struct nfsmount *nmp, struct nfsclclient *clp,
 4943     struct ucred *cred, NFSPROC_T *p)
 4944 {
 4945         uint32_t *tl;
 4946         struct nfsrv_descript nfsd;
 4947         struct nfsrv_descript *nd = &nfsd;
 4948         int error;
 4949         struct nfsclsession *tsep;
 4950 
 4951         nfscl_reqstart(nd, NFSPROC_DESTROYCLIENT, nmp, NULL, 0, NULL, NULL, 0,
 4952             0);
 4953         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 4954         tsep = nfsmnt_mdssession(nmp);
 4955         *tl++ = tsep->nfsess_clientid.lval[0];
 4956         *tl = tsep->nfsess_clientid.lval[1];
 4957         nd->nd_flag |= ND_USEGSSNAME;
 4958         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4959             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4960         if (error != 0)
 4961                 return (error);
 4962         error = nd->nd_repstat;
 4963         mbuf_freem(nd->nd_mrep);
 4964         return (error);
 4965 }
 4966 
 4967 /*
 4968  * Do the NFSv4.1 LayoutGet.
 4969  */
 4970 static int
 4971 nfsrpc_layoutget(struct nfsmount *nmp, uint8_t *fhp, int fhlen, int iomode,
 4972     uint64_t offset, uint64_t len, uint64_t minlen, int layouttype,
 4973     int layoutlen, nfsv4stateid_t *stateidp, int *retonclosep,
 4974     struct nfsclflayouthead *flhp, struct ucred *cred, NFSPROC_T *p,
 4975     void *stuff)
 4976 {
 4977         struct nfsrv_descript nfsd, *nd = &nfsd;
 4978         int error;
 4979 
 4980         nfscl_reqstart(nd, NFSPROC_LAYOUTGET, nmp, fhp, fhlen, NULL, NULL, 0,
 4981             0);
 4982         nfsrv_setuplayoutget(nd, iomode, offset, len, minlen, stateidp,
 4983             layouttype, layoutlen, 0);
 4984         nd->nd_flag |= ND_USEGSSNAME;
 4985         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 4986             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 4987         NFSCL_DEBUG(4, "layget err=%d st=%d\n", error, nd->nd_repstat);
 4988         if (error != 0)
 4989                 return (error);
 4990         if (nd->nd_repstat == 0)
 4991                 error = nfsrv_parselayoutget(nd, stateidp, retonclosep, flhp);
 4992         if (error == 0 && nd->nd_repstat != 0)
 4993                 error = nd->nd_repstat;
 4994         mbuf_freem(nd->nd_mrep);
 4995         return (error);
 4996 }
 4997 
 4998 /*
 4999  * Do the NFSv4.1 Get Device Info.
 5000  */
 5001 int
 5002 nfsrpc_getdeviceinfo(struct nfsmount *nmp, uint8_t *deviceid, int layouttype,
 5003     uint32_t *notifybitsp, struct nfscldevinfo **ndip, struct ucred *cred,
 5004     NFSPROC_T *p)
 5005 {
 5006         uint32_t cnt, *tl, vers, minorvers;
 5007         struct nfsrv_descript nfsd;
 5008         struct nfsrv_descript *nd = &nfsd;
 5009         struct sockaddr_in sin, ssin;
 5010         struct sockaddr_in6 sin6, ssin6;
 5011         struct nfsclds *dsp = NULL, **dspp, **gotdspp;
 5012         struct nfscldevinfo *ndi;
 5013         int addrcnt = 0, bitcnt, error, gotvers, i, isudp, j, stripecnt;
 5014         uint8_t stripeindex;
 5015         sa_family_t af, safilled;
 5016 
 5017         *ndip = NULL;
 5018         ndi = NULL;
 5019         gotdspp = NULL;
 5020         nfscl_reqstart(nd, NFSPROC_GETDEVICEINFO, nmp, NULL, 0, NULL, NULL, 0,
 5021             0);
 5022         NFSM_BUILD(tl, uint32_t *, NFSX_V4DEVICEID + 3 * NFSX_UNSIGNED);
 5023         NFSBCOPY(deviceid, tl, NFSX_V4DEVICEID);
 5024         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
 5025         *tl++ = txdr_unsigned(layouttype);
 5026         *tl++ = txdr_unsigned(100000);
 5027         if (notifybitsp != NULL && *notifybitsp != 0) {
 5028                 *tl = txdr_unsigned(1);         /* One word of bits. */
 5029                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 5030                 *tl = txdr_unsigned(*notifybitsp);
 5031         } else
 5032                 *tl = txdr_unsigned(0);
 5033         nd->nd_flag |= ND_USEGSSNAME;
 5034         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 5035             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 5036         if (error != 0)
 5037                 return (error);
 5038         if (nd->nd_repstat == 0) {
 5039                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 5040                 if (layouttype != fxdr_unsigned(int, *tl))
 5041                         printf("EEK! devinfo layout type not same!\n");
 5042                 if (layouttype == NFSLAYOUT_NFSV4_1_FILES) {
 5043                         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 5044                         stripecnt = fxdr_unsigned(int, *tl);
 5045                         NFSCL_DEBUG(4, "stripecnt=%d\n", stripecnt);
 5046                         if (stripecnt < 1 || stripecnt > 4096) {
 5047                                 printf("pNFS File layout devinfo stripecnt %d:"
 5048                                     " out of range\n", stripecnt);
 5049                                 error = NFSERR_BADXDR;
 5050                                 goto nfsmout;
 5051                         }
 5052                         NFSM_DISSECT(tl, uint32_t *, (stripecnt + 1) *
 5053                             NFSX_UNSIGNED);
 5054                         addrcnt = fxdr_unsigned(int, *(tl + stripecnt));
 5055                         NFSCL_DEBUG(4, "addrcnt=%d\n", addrcnt);
 5056                         if (addrcnt < 1 || addrcnt > 128) {
 5057                                 printf("NFS devinfo addrcnt %d: out of range\n",
 5058                                     addrcnt);
 5059                                 error = NFSERR_BADXDR;
 5060                                 goto nfsmout;
 5061                         }
 5062         
 5063                         /*
 5064                          * Now we know how many stripe indices and addresses, so
 5065                          * we can allocate the structure the correct size.
 5066                          */
 5067                         i = (stripecnt * sizeof(uint8_t)) /
 5068                             sizeof(struct nfsclds *) + 1;
 5069                         NFSCL_DEBUG(4, "stripeindices=%d\n", i);
 5070                         ndi = malloc(sizeof(*ndi) + (addrcnt + i) *
 5071                             sizeof(struct nfsclds *), M_NFSDEVINFO, M_WAITOK |
 5072                             M_ZERO);
 5073                         NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
 5074                             NFSX_V4DEVICEID);
 5075                         ndi->nfsdi_refcnt = 0;
 5076                         ndi->nfsdi_flags = NFSDI_FILELAYOUT;
 5077                         ndi->nfsdi_stripecnt = stripecnt;
 5078                         ndi->nfsdi_addrcnt = addrcnt;
 5079                         /* Fill in the stripe indices. */
 5080                         for (i = 0; i < stripecnt; i++) {
 5081                                 stripeindex = fxdr_unsigned(uint8_t, *tl++);
 5082                                 NFSCL_DEBUG(4, "stripeind=%d\n", stripeindex);
 5083                                 if (stripeindex >= addrcnt) {
 5084                                         printf("pNFS File Layout devinfo"
 5085                                             " stripeindex %d: too big\n",
 5086                                             (int)stripeindex);
 5087                                         error = NFSERR_BADXDR;
 5088                                         goto nfsmout;
 5089                                 }
 5090                                 nfsfldi_setstripeindex(ndi, i, stripeindex);
 5091                         }
 5092                 } else if (layouttype == NFSLAYOUT_FLEXFILE) {
 5093                         /* For Flex File, we only get one address list. */
 5094                         ndi = malloc(sizeof(*ndi) + sizeof(struct nfsclds *),
 5095                             M_NFSDEVINFO, M_WAITOK | M_ZERO);
 5096                         NFSBCOPY(deviceid, ndi->nfsdi_deviceid,
 5097                             NFSX_V4DEVICEID);
 5098                         ndi->nfsdi_refcnt = 0;
 5099                         ndi->nfsdi_flags = NFSDI_FLEXFILE;
 5100                         addrcnt = ndi->nfsdi_addrcnt = 1;
 5101                 }
 5102 
 5103                 /* Now, dissect the server address(es). */
 5104                 safilled = AF_UNSPEC;
 5105                 for (i = 0; i < addrcnt; i++) {
 5106                         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 5107                         cnt = fxdr_unsigned(uint32_t, *tl);
 5108                         if (cnt == 0) {
 5109                                 printf("NFS devinfo 0 len addrlist\n");
 5110                                 error = NFSERR_BADXDR;
 5111                                 goto nfsmout;
 5112                         }
 5113                         dspp = nfsfldi_addr(ndi, i);
 5114                         safilled = AF_UNSPEC;
 5115                         for (j = 0; j < cnt; j++) {
 5116                                 error = nfsv4_getipaddr(nd, &sin, &sin6, &af,
 5117                                     &isudp);
 5118                                 if (error != 0 && error != EPERM) {
 5119                                         error = NFSERR_BADXDR;
 5120                                         goto nfsmout;
 5121                                 }
 5122                                 if (error == 0 && isudp == 0) {
 5123                                         /*
 5124                                          * The priority is:
 5125                                          * - Same address family.
 5126                                          * Save the address and dspp, so that
 5127                                          * the connection can be done after
 5128                                          * parsing is complete.
 5129                                          */
 5130                                         if (safilled == AF_UNSPEC ||
 5131                                             (af == nmp->nm_nam->sa_family &&
 5132                                              safilled != nmp->nm_nam->sa_family)
 5133                                            ) {
 5134                                                 if (af == AF_INET)
 5135                                                         ssin = sin;
 5136                                                 else
 5137                                                         ssin6 = sin6;
 5138                                                 safilled = af;
 5139                                                 gotdspp = dspp;
 5140                                         }
 5141                                 }
 5142                         }
 5143                 }
 5144 
 5145                 gotvers = NFS_VER4;     /* Always NFSv4 for File Layout. */
 5146                 /* For Flex File, we will take one of the versions to use. */
 5147                 if (layouttype == NFSLAYOUT_FLEXFILE) {
 5148                         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 5149                         j = fxdr_unsigned(int, *tl);
 5150                         if (j < 1 || j > NFSDEV_MAXVERS) {
 5151                                 printf("pNFS: too many versions\n");
 5152                                 error = NFSERR_BADXDR;
 5153                                 goto nfsmout;
 5154                         }
 5155                         gotvers = 0;
 5156                         for (i = 0; i < j; i++) {
 5157                                 NFSM_DISSECT(tl, uint32_t *, 5 * NFSX_UNSIGNED);
 5158                                 vers = fxdr_unsigned(uint32_t, *tl++);
 5159                                 minorvers = fxdr_unsigned(uint32_t, *tl++);
 5160                                 if ((vers == NFS_VER4 && minorvers ==
 5161                                     NFSV41_MINORVERSION) || (vers == NFS_VER3 &&
 5162                                     gotvers == 0)) {
 5163                                         gotvers = vers;
 5164                                         /* We'll take this one. */
 5165                                         ndi->nfsdi_versindex = i;
 5166                                         ndi->nfsdi_vers = vers;
 5167                                         ndi->nfsdi_minorvers = minorvers;
 5168                                         ndi->nfsdi_rsize = fxdr_unsigned(
 5169                                             uint32_t, *tl++);
 5170                                         ndi->nfsdi_wsize = fxdr_unsigned(
 5171                                             uint32_t, *tl++);
 5172                                         if (*tl == newnfs_true)
 5173                                                 ndi->nfsdi_flags |=
 5174                                                     NFSDI_TIGHTCOUPLED;
 5175                                         else
 5176                                                 ndi->nfsdi_flags &=
 5177                                                     ~NFSDI_TIGHTCOUPLED;
 5178                                 }
 5179                         }
 5180                         if (gotvers == 0) {
 5181                                 printf("pNFS: no NFSv3 or NFSv4.1\n");
 5182                                 error = NFSERR_BADXDR;
 5183                                 goto nfsmout;
 5184                         }
 5185                 }
 5186 
 5187                 /* And the notify bits. */
 5188                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 5189                 bitcnt = fxdr_unsigned(int, *tl);
 5190                 if (bitcnt > 0) {
 5191                         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 5192                         if (notifybitsp != NULL)
 5193                                 *notifybitsp =
 5194                                     fxdr_unsigned(uint32_t, *tl);
 5195                 }
 5196                 if (safilled != AF_UNSPEC) {
 5197                         KASSERT(ndi != NULL, ("ndi is NULL"));
 5198                         *ndip = ndi;
 5199                 } else
 5200                         error = EPERM;
 5201                 if (error == 0) {
 5202                         /*
 5203                          * Now we can do a TCP connection for the correct
 5204                          * NFS version and IP address.
 5205                          */
 5206                         error = nfsrpc_fillsa(nmp, &ssin, &ssin6, safilled,
 5207                             gotvers, &dsp, p);
 5208                 }
 5209                 if (error == 0) {
 5210                         KASSERT(gotdspp != NULL, ("gotdspp is NULL"));
 5211                         *gotdspp = dsp;
 5212                 }
 5213         }
 5214         if (nd->nd_repstat != 0 && error == 0)
 5215                 error = nd->nd_repstat;
 5216 nfsmout:
 5217         if (error != 0 && ndi != NULL)
 5218                 nfscl_freedevinfo(ndi);
 5219         mbuf_freem(nd->nd_mrep);
 5220         return (error);
 5221 }
 5222 
 5223 /*
 5224  * Do the NFSv4.1 LayoutCommit.
 5225  */
 5226 int
 5227 nfsrpc_layoutcommit(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
 5228     uint64_t off, uint64_t len, uint64_t lastbyte, nfsv4stateid_t *stateidp,
 5229     int layouttype, struct ucred *cred, NFSPROC_T *p, void *stuff)
 5230 {
 5231         uint32_t *tl;
 5232         struct nfsrv_descript nfsd, *nd = &nfsd;
 5233         int error;
 5234 
 5235         nfscl_reqstart(nd, NFSPROC_LAYOUTCOMMIT, nmp, fh, fhlen, NULL, NULL,
 5236             0, 0);
 5237         NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
 5238             NFSX_STATEID);
 5239         txdr_hyper(off, tl);
 5240         tl += 2;
 5241         txdr_hyper(len, tl);
 5242         tl += 2;
 5243         if (reclaim != 0)
 5244                 *tl++ = newnfs_true;
 5245         else
 5246                 *tl++ = newnfs_false;
 5247         *tl++ = txdr_unsigned(stateidp->seqid);
 5248         *tl++ = stateidp->other[0];
 5249         *tl++ = stateidp->other[1];
 5250         *tl++ = stateidp->other[2];
 5251         *tl++ = newnfs_true;
 5252         if (lastbyte < off)
 5253                 lastbyte = off;
 5254         else if (lastbyte >= (off + len))
 5255                 lastbyte = off + len - 1;
 5256         txdr_hyper(lastbyte, tl);
 5257         tl += 2;
 5258         *tl++ = newnfs_false;
 5259         *tl++ = txdr_unsigned(layouttype);
 5260         /* All supported layouts are 0 length. */
 5261         *tl = txdr_unsigned(0);
 5262         nd->nd_flag |= ND_USEGSSNAME;
 5263         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 5264             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 5265         if (error != 0)
 5266                 return (error);
 5267         error = nd->nd_repstat;
 5268         mbuf_freem(nd->nd_mrep);
 5269         return (error);
 5270 }
 5271 
 5272 /*
 5273  * Do the NFSv4.1 LayoutReturn.
 5274  */
 5275 int
 5276 nfsrpc_layoutreturn(struct nfsmount *nmp, uint8_t *fh, int fhlen, int reclaim,
 5277     int layouttype, uint32_t iomode, int layoutreturn, uint64_t offset,
 5278     uint64_t len, nfsv4stateid_t *stateidp, struct ucred *cred, NFSPROC_T *p,
 5279     uint32_t stat, uint32_t op, char *devid)
 5280 {
 5281         uint32_t *tl;
 5282         struct nfsrv_descript nfsd, *nd = &nfsd;
 5283         uint64_t tu64;
 5284         int error;
 5285 
 5286         nfscl_reqstart(nd, NFSPROC_LAYOUTRETURN, nmp, fh, fhlen, NULL, NULL,
 5287             0, 0);
 5288         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED);
 5289         if (reclaim != 0)
 5290                 *tl++ = newnfs_true;
 5291         else
 5292                 *tl++ = newnfs_false;
 5293         *tl++ = txdr_unsigned(layouttype);
 5294         *tl++ = txdr_unsigned(iomode);
 5295         *tl = txdr_unsigned(layoutreturn);
 5296         if (layoutreturn == NFSLAYOUTRETURN_FILE) {
 5297                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
 5298                     NFSX_UNSIGNED);
 5299                 txdr_hyper(offset, tl);
 5300                 tl += 2;
 5301                 txdr_hyper(len, tl);
 5302                 tl += 2;
 5303                 NFSCL_DEBUG(4, "layoutret stseq=%d\n", (int)stateidp->seqid);
 5304                 *tl++ = txdr_unsigned(stateidp->seqid);
 5305                 *tl++ = stateidp->other[0];
 5306                 *tl++ = stateidp->other[1];
 5307                 *tl++ = stateidp->other[2];
 5308                 if (layouttype == NFSLAYOUT_NFSV4_1_FILES)
 5309                         *tl = txdr_unsigned(0);
 5310                 else if (layouttype == NFSLAYOUT_FLEXFILE) {
 5311                         if (stat != 0) {
 5312                                 *tl = txdr_unsigned(2 * NFSX_HYPER +
 5313                                     NFSX_STATEID + NFSX_V4DEVICEID + 5 *
 5314                                     NFSX_UNSIGNED);
 5315                                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER +
 5316                                     NFSX_STATEID + NFSX_V4DEVICEID + 5 *
 5317                                     NFSX_UNSIGNED);
 5318                                 *tl++ = txdr_unsigned(1);       /* One error. */
 5319                                 tu64 = 0;                       /* Offset. */
 5320                                 txdr_hyper(tu64, tl); tl += 2;
 5321                                 tu64 = UINT64_MAX;              /* Length. */
 5322                                 txdr_hyper(tu64, tl); tl += 2;
 5323                                 NFSBCOPY(stateidp, tl, NFSX_STATEID);
 5324                                 tl += (NFSX_STATEID / NFSX_UNSIGNED);
 5325                                 *tl++ = txdr_unsigned(1);       /* One error. */
 5326                                 NFSBCOPY(devid, tl, NFSX_V4DEVICEID);
 5327                                 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
 5328                                 *tl++ = txdr_unsigned(stat);
 5329                                 *tl++ = txdr_unsigned(op);
 5330                         } else {
 5331                                 *tl = txdr_unsigned(2 * NFSX_UNSIGNED);
 5332                                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 5333                                 /* No ioerrs. */
 5334                                 *tl++ = 0;
 5335                         }
 5336                         *tl = 0;        /* No stats yet. */
 5337                 }
 5338         }
 5339         nd->nd_flag |= ND_USEGSSNAME;
 5340         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 5341             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 5342         if (error != 0)
 5343                 return (error);
 5344         if (nd->nd_repstat == 0) {
 5345                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 5346                 if (*tl != 0) {
 5347                         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
 5348                         stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
 5349                         stateidp->other[0] = *tl++;
 5350                         stateidp->other[1] = *tl++;
 5351                         stateidp->other[2] = *tl;
 5352                 }
 5353         } else
 5354                 error = nd->nd_repstat;
 5355 nfsmout:
 5356         mbuf_freem(nd->nd_mrep);
 5357         return (error);
 5358 }
 5359 
 5360 /*
 5361  * Acquire a layout and devinfo, if possible. The caller must have acquired
 5362  * a reference count on the nfsclclient structure before calling this.
 5363  * Return the layout in lypp with a reference count on it, if successful.
 5364  */
 5365 static int
 5366 nfsrpc_getlayout(struct nfsmount *nmp, vnode_t vp, struct nfsfh *nfhp,
 5367     int iomode, uint32_t rw, uint32_t *notifybitsp, nfsv4stateid_t *stateidp,
 5368     uint64_t off, struct nfscllayout **lypp, struct ucred *cred, NFSPROC_T *p)
 5369 {
 5370         struct nfscllayout *lyp;
 5371         struct nfsclflayout *flp;
 5372         struct nfsclflayouthead flh;
 5373         int error = 0, islocked, layoutlen, layouttype, recalled, retonclose;
 5374         nfsv4stateid_t stateid;
 5375         struct nfsclsession *tsep;
 5376 
 5377         *lypp = NULL;
 5378         if (NFSHASFLEXFILE(nmp))
 5379                 layouttype = NFSLAYOUT_FLEXFILE;
 5380         else
 5381                 layouttype = NFSLAYOUT_NFSV4_1_FILES;
 5382         /*
 5383          * If lyp is returned non-NULL, there will be a refcnt (shared lock)
 5384          * on it, iff flp != NULL or a lock (exclusive lock) on it iff
 5385          * flp == NULL.
 5386          */
 5387         lyp = nfscl_getlayout(nmp->nm_clp, nfhp->nfh_fh, nfhp->nfh_len,
 5388             off, rw, &flp, &recalled);
 5389         islocked = 0;
 5390         if (lyp == NULL || flp == NULL) {
 5391                 if (recalled != 0)
 5392                         return (EIO);
 5393                 LIST_INIT(&flh);
 5394                 tsep = nfsmnt_mdssession(nmp);
 5395                 layoutlen = tsep->nfsess_maxcache -
 5396                     (NFSX_STATEID + 3 * NFSX_UNSIGNED);
 5397                 if (lyp == NULL) {
 5398                         stateid.seqid = 0;
 5399                         stateid.other[0] = stateidp->other[0];
 5400                         stateid.other[1] = stateidp->other[1];
 5401                         stateid.other[2] = stateidp->other[2];
 5402                         error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
 5403                             nfhp->nfh_len, iomode, (uint64_t)0, UINT64_MAX,
 5404                             (uint64_t)0, layouttype, layoutlen, &stateid,
 5405                             &retonclose, &flh, cred, p, NULL);
 5406                 } else {
 5407                         islocked = 1;
 5408                         stateid.seqid = lyp->nfsly_stateid.seqid;
 5409                         stateid.other[0] = lyp->nfsly_stateid.other[0];
 5410                         stateid.other[1] = lyp->nfsly_stateid.other[1];
 5411                         stateid.other[2] = lyp->nfsly_stateid.other[2];
 5412                         error = nfsrpc_layoutget(nmp, nfhp->nfh_fh,
 5413                             nfhp->nfh_len, iomode, off, UINT64_MAX,
 5414                             (uint64_t)0, layouttype, layoutlen, &stateid,
 5415                             &retonclose, &flh, cred, p, NULL);
 5416                 }
 5417                 error = nfsrpc_layoutgetres(nmp, vp, nfhp->nfh_fh,
 5418                     nfhp->nfh_len, &stateid, retonclose, notifybitsp, &lyp,
 5419                     &flh, layouttype, error, NULL, cred, p);
 5420                 if (error == 0)
 5421                         *lypp = lyp;
 5422                 else if (islocked != 0)
 5423                         nfscl_rellayout(lyp, 1);
 5424         } else
 5425                 *lypp = lyp;
 5426         return (error);
 5427 }
 5428 
 5429 /*
 5430  * Do a TCP connection plus exchange id and create session.
 5431  * If successful, a "struct nfsclds" is linked into the list for the
 5432  * mount point and a pointer to it is returned.
 5433  */
 5434 static int
 5435 nfsrpc_fillsa(struct nfsmount *nmp, struct sockaddr_in *sin,
 5436     struct sockaddr_in6 *sin6, sa_family_t af, int vers, struct nfsclds **dspp,
 5437     NFSPROC_T *p)
 5438 {
 5439         struct sockaddr_in *msad, *sad;
 5440         struct sockaddr_in6 *msad6, *sad6;
 5441         struct nfsclclient *clp;
 5442         struct nfssockreq *nrp;
 5443         struct nfsclds *dsp, *tdsp;
 5444         int error;
 5445         enum nfsclds_state retv;
 5446         uint32_t sequenceid;
 5447 
 5448         KASSERT(nmp->nm_sockreq.nr_cred != NULL,
 5449             ("nfsrpc_fillsa: NULL nr_cred"));
 5450         NFSLOCKCLSTATE();
 5451         clp = nmp->nm_clp;
 5452         NFSUNLOCKCLSTATE();
 5453         if (clp == NULL)
 5454                 return (EPERM);
 5455         if (af == AF_INET) {
 5456                 NFSLOCKMNT(nmp);
 5457                 /*
 5458                  * Check to see if we already have a session for this
 5459                  * address that is usable for a DS.
 5460                  * Note that the MDS's address is in a different place
 5461                  * than the sessions already acquired for DS's.
 5462                  */
 5463                 msad = (struct sockaddr_in *)nmp->nm_sockreq.nr_nam;
 5464                 tdsp = TAILQ_FIRST(&nmp->nm_sess);
 5465                 while (tdsp != NULL) {
 5466                         if (msad != NULL && msad->sin_family == AF_INET &&
 5467                             sin->sin_addr.s_addr == msad->sin_addr.s_addr &&
 5468                             sin->sin_port == msad->sin_port &&
 5469                             (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
 5470                             tdsp->nfsclds_sess.nfsess_defunct == 0) {
 5471                                 *dspp = tdsp;
 5472                                 NFSUNLOCKMNT(nmp);
 5473                                 NFSCL_DEBUG(4, "fnd same addr\n");
 5474                                 return (0);
 5475                         }
 5476                         tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
 5477                         if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
 5478                                 msad = (struct sockaddr_in *)
 5479                                     tdsp->nfsclds_sockp->nr_nam;
 5480                         else
 5481                                 msad = NULL;
 5482                 }
 5483                 NFSUNLOCKMNT(nmp);
 5484 
 5485                 /* No IP address match, so look for new/trunked one. */
 5486                 sad = malloc(sizeof(*sad), M_SONAME, M_WAITOK | M_ZERO);
 5487                 sad->sin_len = sizeof(*sad);
 5488                 sad->sin_family = AF_INET;
 5489                 sad->sin_port = sin->sin_port;
 5490                 sad->sin_addr.s_addr = sin->sin_addr.s_addr;
 5491                 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
 5492                 nrp->nr_nam = (struct sockaddr *)sad;
 5493         } else if (af == AF_INET6) {
 5494                 NFSLOCKMNT(nmp);
 5495                 /*
 5496                  * Check to see if we already have a session for this
 5497                  * address that is usable for a DS.
 5498                  * Note that the MDS's address is in a different place
 5499                  * than the sessions already acquired for DS's.
 5500                  */
 5501                 msad6 = (struct sockaddr_in6 *)nmp->nm_sockreq.nr_nam;
 5502                 tdsp = TAILQ_FIRST(&nmp->nm_sess);
 5503                 while (tdsp != NULL) {
 5504                         if (msad6 != NULL && msad6->sin6_family == AF_INET6 &&
 5505                             IN6_ARE_ADDR_EQUAL(&sin6->sin6_addr,
 5506                             &msad6->sin6_addr) &&
 5507                             sin6->sin6_port == msad6->sin6_port &&
 5508                             (tdsp->nfsclds_flags & NFSCLDS_DS) != 0 &&
 5509                             tdsp->nfsclds_sess.nfsess_defunct == 0) {
 5510                                 *dspp = tdsp;
 5511                                 NFSUNLOCKMNT(nmp);
 5512                                 return (0);
 5513                         }
 5514                         tdsp = TAILQ_NEXT(tdsp, nfsclds_list);
 5515                         if (tdsp != NULL && tdsp->nfsclds_sockp != NULL)
 5516                                 msad6 = (struct sockaddr_in6 *)
 5517                                     tdsp->nfsclds_sockp->nr_nam;
 5518                         else
 5519                                 msad6 = NULL;
 5520                 }
 5521                 NFSUNLOCKMNT(nmp);
 5522 
 5523                 /* No IP address match, so look for new/trunked one. */
 5524                 sad6 = malloc(sizeof(*sad6), M_SONAME, M_WAITOK | M_ZERO);
 5525                 sad6->sin6_len = sizeof(*sad6);
 5526                 sad6->sin6_family = AF_INET6;
 5527                 sad6->sin6_port = sin6->sin6_port;
 5528                 NFSBCOPY(&sin6->sin6_addr, &sad6->sin6_addr,
 5529                     sizeof(struct in6_addr));
 5530                 nrp = malloc(sizeof(*nrp), M_NFSSOCKREQ, M_WAITOK | M_ZERO);
 5531                 nrp->nr_nam = (struct sockaddr *)sad6;
 5532         } else
 5533                 return (EPERM);
 5534 
 5535         nrp->nr_sotype = SOCK_STREAM;
 5536         mtx_init(&nrp->nr_mtx, "nfssock", NULL, MTX_DEF);
 5537         nrp->nr_prog = NFS_PROG;
 5538         nrp->nr_vers = vers;
 5539 
 5540         /*
 5541          * Use the credentials that were used for the mount, which are
 5542          * in nmp->nm_sockreq.nr_cred for newnfs_connect() etc.
 5543          * Ref. counting the credentials with crhold() is probably not
 5544          * necessary, since nm_sockreq.nr_cred won't be crfree()'d until
 5545          * unmount, but I did it anyhow.
 5546          */
 5547         nrp->nr_cred = crhold(nmp->nm_sockreq.nr_cred);
 5548         error = newnfs_connect(nmp, nrp, NULL, p, 0);
 5549         NFSCL_DEBUG(3, "DS connect=%d\n", error);
 5550 
 5551         dsp = NULL;
 5552         /* Now, do the exchangeid and create session. */
 5553         if (error == 0) {
 5554                 if (vers == NFS_VER4) {
 5555                         error = nfsrpc_exchangeid(nmp, clp, nrp,
 5556                             NFSV4EXCH_USEPNFSDS, &dsp, nrp->nr_cred, p);
 5557                         NFSCL_DEBUG(3, "DS exchangeid=%d\n", error);
 5558                         if (error != 0)
 5559                                 newnfs_disconnect(nrp);
 5560                 } else {
 5561                         dsp = malloc(sizeof(struct nfsclds), M_NFSCLDS,
 5562                             M_WAITOK | M_ZERO);
 5563                         dsp->nfsclds_flags |= NFSCLDS_DS;
 5564                         dsp->nfsclds_expire = INT32_MAX; /* No renews needed. */
 5565                         mtx_init(&dsp->nfsclds_mtx, "nfsds", NULL, MTX_DEF);
 5566                         mtx_init(&dsp->nfsclds_sess.nfsess_mtx, "nfssession",
 5567                             NULL, MTX_DEF);
 5568                 }
 5569         }
 5570         if (error == 0) {
 5571                 dsp->nfsclds_sockp = nrp;
 5572                 if (vers == NFS_VER4) {
 5573                         NFSLOCKMNT(nmp);
 5574                         retv = nfscl_getsameserver(nmp, dsp, &tdsp,
 5575                             &sequenceid);
 5576                         NFSCL_DEBUG(3, "getsame ret=%d\n", retv);
 5577                         if (retv == NFSDSP_USETHISSESSION &&
 5578                             nfscl_dssameconn != 0) {
 5579                                 NFSLOCKDS(tdsp);
 5580                                 tdsp->nfsclds_flags |= NFSCLDS_SAMECONN;
 5581                                 NFSUNLOCKDS(tdsp);
 5582                                 NFSUNLOCKMNT(nmp);
 5583                                 /*
 5584                                  * If there is already a session for this
 5585                                  * server, use it.
 5586                                  */
 5587                                 (void)newnfs_disconnect(nrp);
 5588                                 nfscl_freenfsclds(dsp);
 5589                                 *dspp = tdsp;
 5590                                 return (0);
 5591                         }
 5592                         if (retv == NFSDSP_NOTFOUND)
 5593                                 sequenceid =
 5594                                     dsp->nfsclds_sess.nfsess_sequenceid;
 5595                         NFSUNLOCKMNT(nmp);
 5596                         error = nfsrpc_createsession(nmp, &dsp->nfsclds_sess,
 5597                             nrp, sequenceid, 0, nrp->nr_cred, p);
 5598                         NFSCL_DEBUG(3, "DS createsess=%d\n", error);
 5599                 }
 5600         } else {
 5601                 NFSFREECRED(nrp->nr_cred);
 5602                 NFSFREEMUTEX(&nrp->nr_mtx);
 5603                 free(nrp->nr_nam, M_SONAME);
 5604                 free(nrp, M_NFSSOCKREQ);
 5605         }
 5606         if (error == 0) {
 5607                 NFSCL_DEBUG(3, "add DS session\n");
 5608                 /*
 5609                  * Put it at the end of the list. That way the list
 5610                  * is ordered by when the entry was added. This matters
 5611                  * since the one done first is the one that should be
 5612                  * used for sequencid'ing any subsequent create sessions.
 5613                  */
 5614                 NFSLOCKMNT(nmp);
 5615                 TAILQ_INSERT_TAIL(&nmp->nm_sess, dsp, nfsclds_list);
 5616                 NFSUNLOCKMNT(nmp);
 5617                 *dspp = dsp;
 5618         } else if (dsp != NULL) {
 5619                 newnfs_disconnect(nrp);
 5620                 nfscl_freenfsclds(dsp);
 5621         }
 5622         return (error);
 5623 }
 5624 
 5625 /*
 5626  * Do the NFSv4.1 Reclaim Complete.
 5627  */
 5628 int
 5629 nfsrpc_reclaimcomplete(struct nfsmount *nmp, struct ucred *cred, NFSPROC_T *p)
 5630 {
 5631         uint32_t *tl;
 5632         struct nfsrv_descript nfsd;
 5633         struct nfsrv_descript *nd = &nfsd;
 5634         int error;
 5635 
 5636         nfscl_reqstart(nd, NFSPROC_RECLAIMCOMPL, nmp, NULL, 0, NULL, NULL, 0,
 5637             0);
 5638         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 5639         *tl = newnfs_false;
 5640         nd->nd_flag |= ND_USEGSSNAME;
 5641         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, NULL, p, cred,
 5642             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 5643         if (error != 0)
 5644                 return (error);
 5645         error = nd->nd_repstat;
 5646         mbuf_freem(nd->nd_mrep);
 5647         return (error);
 5648 }
 5649 
 5650 /*
 5651  * Initialize the slot tables for a session.
 5652  */
 5653 static void
 5654 nfscl_initsessionslots(struct nfsclsession *sep)
 5655 {
 5656         int i;
 5657 
 5658         for (i = 0; i < NFSV4_CBSLOTS; i++) {
 5659                 if (sep->nfsess_cbslots[i].nfssl_reply != NULL)
 5660                         m_freem(sep->nfsess_cbslots[i].nfssl_reply);
 5661                 NFSBZERO(&sep->nfsess_cbslots[i], sizeof(struct nfsslot));
 5662         }
 5663         for (i = 0; i < 64; i++)
 5664                 sep->nfsess_slotseq[i] = 0;
 5665         sep->nfsess_slots = 0;
 5666 }
 5667 
 5668 /*
 5669  * Called to try and do an I/O operation via an NFSv4.1 Data Server (DS).
 5670  */
 5671 int
 5672 nfscl_doiods(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
 5673     uint32_t rwaccess, int docommit, struct ucred *cred, NFSPROC_T *p)
 5674 {
 5675         struct nfsnode *np = VTONFS(vp);
 5676         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 5677         struct nfscllayout *layp;
 5678         struct nfscldevinfo *dip;
 5679         struct nfsclflayout *rflp;
 5680         struct mbuf *m;
 5681         struct nfsclwritedsdorpc *drpc, *tdrpc;
 5682         nfsv4stateid_t stateid;
 5683         struct ucred *newcred;
 5684         uint64_t lastbyte, len, off, oresid, xfer;
 5685         int eof, error, firstmirror, i, iolaymode, mirrorcnt, recalled, timo;
 5686         void *lckp;
 5687         uint8_t *dev;
 5688         void *iovbase = NULL;
 5689         size_t iovlen = 0;
 5690         off_t offs = 0;
 5691         ssize_t resid = 0;
 5692 
 5693         if (!NFSHASPNFS(nmp) || nfscl_enablecallb == 0 || nfs_numnfscbd == 0 ||
 5694             (np->n_flag & NNOLAYOUT) != 0)
 5695                 return (EIO);
 5696         /* Now, get a reference cnt on the clientid for this mount. */
 5697         if (nfscl_getref(nmp) == 0)
 5698                 return (EIO);
 5699 
 5700         /* Find an appropriate stateid. */
 5701         newcred = NFSNEWCRED(cred);
 5702         error = nfscl_getstateid(vp, np->n_fhp->nfh_fh, np->n_fhp->nfh_len,
 5703             rwaccess, 1, newcred, p, &stateid, &lckp);
 5704         if (error != 0) {
 5705                 NFSFREECRED(newcred);
 5706                 nfscl_relref(nmp);
 5707                 return (error);
 5708         }
 5709         /* Search for a layout for this file. */
 5710         off = uiop->uio_offset;
 5711         layp = nfscl_getlayout(nmp->nm_clp, np->n_fhp->nfh_fh,
 5712             np->n_fhp->nfh_len, off, rwaccess, &rflp, &recalled);
 5713         if (layp == NULL || rflp == NULL) {
 5714                 if (recalled != 0) {
 5715                         NFSFREECRED(newcred);
 5716                         if (lckp != NULL)
 5717                                 nfscl_lockderef(lckp);
 5718                         nfscl_relref(nmp);
 5719                         return (EIO);
 5720                 }
 5721                 if (layp != NULL) {
 5722                         nfscl_rellayout(layp, (rflp == NULL) ? 1 : 0);
 5723                         layp = NULL;
 5724                 }
 5725                 /* Try and get a Layout, if it is supported. */
 5726                 if (rwaccess == NFSV4OPEN_ACCESSWRITE ||
 5727                     (np->n_flag & NWRITEOPENED) != 0)
 5728                         iolaymode = NFSLAYOUTIOMODE_RW;
 5729                 else
 5730                         iolaymode = NFSLAYOUTIOMODE_READ;
 5731                 error = nfsrpc_getlayout(nmp, vp, np->n_fhp, iolaymode,
 5732                     rwaccess, NULL, &stateid, off, &layp, newcred, p);
 5733                 if (error != 0) {
 5734                         NFSLOCKNODE(np);
 5735                         np->n_flag |= NNOLAYOUT;
 5736                         NFSUNLOCKNODE(np);
 5737                         if (lckp != NULL)
 5738                                 nfscl_lockderef(lckp);
 5739                         NFSFREECRED(newcred);
 5740                         if (layp != NULL)
 5741                                 nfscl_rellayout(layp, 0);
 5742                         nfscl_relref(nmp);
 5743                         return (error);
 5744                 }
 5745         }
 5746 
 5747         /*
 5748          * Loop around finding a layout that works for the first part of
 5749          * this I/O operation, and then call the function that actually
 5750          * does the RPC.
 5751          */
 5752         eof = 0;
 5753         len = (uint64_t)uiop->uio_resid;
 5754         while (len > 0 && error == 0 && eof == 0) {
 5755                 off = uiop->uio_offset;
 5756                 error = nfscl_findlayoutforio(layp, off, rwaccess, &rflp);
 5757                 if (error == 0) {
 5758                         oresid = xfer = (uint64_t)uiop->uio_resid;
 5759                         if (xfer > (rflp->nfsfl_end - rflp->nfsfl_off))
 5760                                 xfer = rflp->nfsfl_end - rflp->nfsfl_off;
 5761                         /*
 5762                          * For Flex File layout with mirrored DSs, select one
 5763                          * of them at random for reads. For writes and commits,
 5764                          * do all mirrors.
 5765                          */
 5766                         m = NULL;
 5767                         tdrpc = drpc = NULL;
 5768                         firstmirror = 0;
 5769                         mirrorcnt = 1;
 5770                         if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0 &&
 5771                             (mirrorcnt = rflp->nfsfl_mirrorcnt) > 1) {
 5772                                 if (rwaccess == NFSV4OPEN_ACCESSREAD) {
 5773                                         firstmirror = arc4random() % mirrorcnt;
 5774                                         mirrorcnt = firstmirror + 1;
 5775                                 } else {
 5776                                         if (docommit == 0) {
 5777                                                 /*
 5778                                                  * Save values, so uiop can be
 5779                                                  * rolled back upon a write
 5780                                                  * error.
 5781                                                  */
 5782                                                 offs = uiop->uio_offset;
 5783                                                 resid = uiop->uio_resid;
 5784                                                 iovbase =
 5785                                                     uiop->uio_iov->iov_base;
 5786                                                 iovlen = uiop->uio_iov->iov_len;
 5787                                                 m = nfsm_uiombuflist(uiop, len,
 5788                                                     NULL, NULL);
 5789                                         }
 5790                                         tdrpc = drpc = malloc(sizeof(*drpc) *
 5791                                             (mirrorcnt - 1), M_TEMP, M_WAITOK |
 5792                                             M_ZERO);
 5793                                 }
 5794                         }
 5795                         for (i = firstmirror; i < mirrorcnt && error == 0; i++){
 5796                                 if ((layp->nfsly_flags & NFSLY_FLEXFILE) != 0) {
 5797                                         dev = rflp->nfsfl_ffm[i].dev;
 5798                                         dip = nfscl_getdevinfo(nmp->nm_clp, dev,
 5799                                             rflp->nfsfl_ffm[i].devp);
 5800                                 } else {
 5801                                         dev = rflp->nfsfl_dev;
 5802                                         dip = nfscl_getdevinfo(nmp->nm_clp, dev,
 5803                                             rflp->nfsfl_devp);
 5804                                 }
 5805                                 if (dip != NULL) {
 5806                                         if ((rflp->nfsfl_flags & NFSFL_FLEXFILE)
 5807                                             != 0)
 5808                                                 error = nfscl_dofflayoutio(vp,
 5809                                                     uiop, iomode, must_commit,
 5810                                                     &eof, &stateid, rwaccess,
 5811                                                     dip, layp, rflp, off, xfer,
 5812                                                     i, docommit, m, tdrpc,
 5813                                                     newcred, p);
 5814                                         else
 5815                                                 error = nfscl_doflayoutio(vp,
 5816                                                     uiop, iomode, must_commit,
 5817                                                     &eof, &stateid, rwaccess,
 5818                                                     dip, layp, rflp, off, xfer,
 5819                                                     docommit, newcred, p);
 5820                                         nfscl_reldevinfo(dip);
 5821                                 } else
 5822                                         error = EIO;
 5823                                 tdrpc++;
 5824                         }
 5825                         if (m != NULL)
 5826                                 m_freem(m);
 5827                         tdrpc = drpc;
 5828                         timo = hz / 50;         /* Wait for 20msec. */
 5829                         if (timo < 1)
 5830                                 timo = 1;
 5831                         for (i = firstmirror; i < mirrorcnt - 1 &&
 5832                             tdrpc != NULL; i++, tdrpc++) {
 5833                                 /*
 5834                                  * For the unused drpc entries, both inprog and
 5835                                  * err == 0, so this loop won't break.
 5836                                  */
 5837                                 while (tdrpc->inprog != 0 && tdrpc->done == 0)
 5838                                         tsleep(&tdrpc->tsk, PVFS, "clrpcio",
 5839                                             timo);
 5840                                 if (error == 0 && tdrpc->err != 0)
 5841                                         error = tdrpc->err;
 5842                                 if (rwaccess != NFSV4OPEN_ACCESSREAD &&
 5843                                     docommit == 0 && *must_commit == 0 &&
 5844                                     tdrpc->must_commit == 1)
 5845                                         *must_commit = 1;
 5846                         }
 5847                         free(drpc, M_TEMP);
 5848                         if (error == 0) {
 5849                                 if (mirrorcnt > 1 && rwaccess ==
 5850                                     NFSV4OPEN_ACCESSWRITE && docommit == 0) {
 5851                                         NFSLOCKCLSTATE();
 5852                                         layp->nfsly_flags |= NFSLY_WRITTEN;
 5853                                         NFSUNLOCKCLSTATE();
 5854                                 }
 5855                                 lastbyte = off + xfer - 1;
 5856                                 NFSLOCKCLSTATE();
 5857                                 if (lastbyte > layp->nfsly_lastbyte)
 5858                                         layp->nfsly_lastbyte = lastbyte;
 5859                                 NFSUNLOCKCLSTATE();
 5860                         } else if (error == NFSERR_OPENMODE &&
 5861                             rwaccess == NFSV4OPEN_ACCESSREAD) {
 5862                                 NFSLOCKMNT(nmp);
 5863                                 nmp->nm_state |= NFSSTA_OPENMODE;
 5864                                 NFSUNLOCKMNT(nmp);
 5865                         } else
 5866                                 error = EIO;
 5867                         if (error == 0)
 5868                                 len -= (oresid - (uint64_t)uiop->uio_resid);
 5869                         else if (mirrorcnt > 1 && rwaccess ==
 5870                             NFSV4OPEN_ACCESSWRITE && docommit == 0) {
 5871                                 /*
 5872                                  * In case the rpc gets retried, roll the
 5873                                  * uio fields changed by nfsm_uiombuflist()
 5874                                  * back.
 5875                                  */
 5876                                 uiop->uio_offset = offs;
 5877                                 uiop->uio_resid = resid;
 5878                                 uiop->uio_iov->iov_base = iovbase;
 5879                                 uiop->uio_iov->iov_len = iovlen;
 5880                         }
 5881                 }
 5882         }
 5883         if (lckp != NULL)
 5884                 nfscl_lockderef(lckp);
 5885         NFSFREECRED(newcred);
 5886         nfscl_rellayout(layp, 0);
 5887         nfscl_relref(nmp);
 5888         return (error);
 5889 }
 5890 
 5891 /*
 5892  * Make a copy of the mbuf chain and add an mbuf for null padding, as required.
 5893  */
 5894 static struct mbuf *
 5895 nfsm_copym(struct mbuf *m, int off, int xfer)
 5896 {
 5897         struct mbuf *m2, *m3, *m4;
 5898         uint32_t *tl;
 5899         int rem;
 5900 
 5901         m2 = m_copym(m, off, xfer, M_WAITOK);
 5902         rem = NFSM_RNDUP(xfer) - xfer;
 5903         if (rem > 0) {
 5904                 /*
 5905                  * The zero padding to a multiple of 4 bytes is required by
 5906                  * the XDR. So that the mbufs copied by reference aren't
 5907                  * modified, add an mbuf with the zero'd bytes to the list.
 5908                  * rem will be a maximum of 3, so one zero'd uint32_t is
 5909                  * sufficient.
 5910                  */
 5911                 m3 = m2;
 5912                 while (m3->m_next != NULL)
 5913                         m3 = m3->m_next;
 5914                 NFSMGET(m4);
 5915                 tl = NFSMTOD(m4, uint32_t *);
 5916                 *tl = 0;
 5917                 mbuf_setlen(m4, rem);
 5918                 mbuf_setnext(m3, m4);
 5919         }
 5920         return (m2);
 5921 }
 5922 
 5923 /*
 5924  * Find a file layout that will handle the first bytes of the requested
 5925  * range and return the information from it needed to the I/O operation.
 5926  */
 5927 int
 5928 nfscl_findlayoutforio(struct nfscllayout *lyp, uint64_t off, uint32_t rwaccess,
 5929     struct nfsclflayout **retflpp)
 5930 {
 5931         struct nfsclflayout *flp, *nflp, *rflp;
 5932         uint32_t rw;
 5933 
 5934         rflp = NULL;
 5935         rw = rwaccess;
 5936         /* For reading, do the Read list first and then the Write list. */
 5937         do {
 5938                 if (rw == NFSV4OPEN_ACCESSREAD)
 5939                         flp = LIST_FIRST(&lyp->nfsly_flayread);
 5940                 else
 5941                         flp = LIST_FIRST(&lyp->nfsly_flayrw);
 5942                 while (flp != NULL) {
 5943                         nflp = LIST_NEXT(flp, nfsfl_list);
 5944                         if (flp->nfsfl_off > off)
 5945                                 break;
 5946                         if (flp->nfsfl_end > off &&
 5947                             (rflp == NULL || rflp->nfsfl_end < flp->nfsfl_end))
 5948                                 rflp = flp;
 5949                         flp = nflp;
 5950                 }
 5951                 if (rw == NFSV4OPEN_ACCESSREAD)
 5952                         rw = NFSV4OPEN_ACCESSWRITE;
 5953                 else
 5954                         rw = 0;
 5955         } while (rw != 0);
 5956         if (rflp != NULL) {
 5957                 /* This one covers the most bytes starting at off. */
 5958                 *retflpp = rflp;
 5959                 return (0);
 5960         }
 5961         return (EIO);
 5962 }
 5963 
 5964 /*
 5965  * Do I/O using an NFSv4.1 file layout.
 5966  */
 5967 static int
 5968 nfscl_doflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
 5969     int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
 5970     struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
 5971     uint64_t len, int docommit, struct ucred *cred, NFSPROC_T *p)
 5972 {
 5973         uint64_t io_off, rel_off, stripe_unit_size, transfer, xfer;
 5974         int commit_thru_mds, error, stripe_index, stripe_pos;
 5975         struct nfsnode *np;
 5976         struct nfsfh *fhp;
 5977         struct nfsclds **dspp;
 5978 
 5979         np = VTONFS(vp);
 5980         rel_off = off - flp->nfsfl_patoff;
 5981         stripe_unit_size = flp->nfsfl_util & NFSFLAYUTIL_STRIPE_MASK;
 5982         stripe_pos = (rel_off / stripe_unit_size + flp->nfsfl_stripe1) %
 5983             dp->nfsdi_stripecnt;
 5984         transfer = stripe_unit_size - (rel_off % stripe_unit_size);
 5985         error = 0;
 5986 
 5987         /* Loop around, doing I/O for each stripe unit. */
 5988         while (len > 0 && error == 0) {
 5989                 stripe_index = nfsfldi_stripeindex(dp, stripe_pos);
 5990                 dspp = nfsfldi_addr(dp, stripe_index);
 5991                 if (len > transfer && docommit == 0)
 5992                         xfer = transfer;
 5993                 else
 5994                         xfer = len;
 5995                 if ((flp->nfsfl_util & NFSFLAYUTIL_DENSE) != 0) {
 5996                         /* Dense layout. */
 5997                         if (stripe_pos >= flp->nfsfl_fhcnt)
 5998                                 return (EIO);
 5999                         fhp = flp->nfsfl_fh[stripe_pos];
 6000                         io_off = (rel_off / (stripe_unit_size *
 6001                             dp->nfsdi_stripecnt)) * stripe_unit_size +
 6002                             rel_off % stripe_unit_size;
 6003                 } else {
 6004                         /* Sparse layout. */
 6005                         if (flp->nfsfl_fhcnt > 1) {
 6006                                 if (stripe_index >= flp->nfsfl_fhcnt)
 6007                                         return (EIO);
 6008                                 fhp = flp->nfsfl_fh[stripe_index];
 6009                         } else if (flp->nfsfl_fhcnt == 1)
 6010                                 fhp = flp->nfsfl_fh[0];
 6011                         else
 6012                                 fhp = np->n_fhp;
 6013                         io_off = off;
 6014                 }
 6015                 if ((flp->nfsfl_util & NFSFLAYUTIL_COMMIT_THRU_MDS) != 0) {
 6016                         commit_thru_mds = 1;
 6017                         if (docommit != 0)
 6018                                 error = EIO;
 6019                 } else {
 6020                         commit_thru_mds = 0;
 6021                         NFSLOCKNODE(np);
 6022                         np->n_flag |= NDSCOMMIT;
 6023                         NFSUNLOCKNODE(np);
 6024                 }
 6025                 if (docommit != 0) {
 6026                         if (error == 0)
 6027                                 error = nfsrpc_commitds(vp, io_off, xfer,
 6028                                     *dspp, fhp, 0, 0, cred, p);
 6029                         if (error == 0) {
 6030                                 /*
 6031                                  * Set both eof and uio_resid = 0 to end any
 6032                                  * loops.
 6033                                  */
 6034                                 *eofp = 1;
 6035                                 uiop->uio_resid = 0;
 6036                         } else {
 6037                                 NFSLOCKNODE(np);
 6038                                 np->n_flag &= ~NDSCOMMIT;
 6039                                 NFSUNLOCKNODE(np);
 6040                         }
 6041                 } else if (rwflag == NFSV4OPEN_ACCESSREAD)
 6042                         error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
 6043                             io_off, xfer, fhp, 0, 0, 0, cred, p);
 6044                 else {
 6045                         error = nfsrpc_writeds(vp, uiop, iomode, must_commit,
 6046                             stateidp, *dspp, io_off, xfer, fhp, commit_thru_mds,
 6047                             0, 0, 0, cred, p);
 6048                         if (error == 0) {
 6049                                 NFSLOCKCLSTATE();
 6050                                 lyp->nfsly_flags |= NFSLY_WRITTEN;
 6051                                 NFSUNLOCKCLSTATE();
 6052                         }
 6053                 }
 6054                 if (error == 0) {
 6055                         transfer = stripe_unit_size;
 6056                         stripe_pos = (stripe_pos + 1) % dp->nfsdi_stripecnt;
 6057                         len -= xfer;
 6058                         off += xfer;
 6059                 }
 6060         }
 6061         return (error);
 6062 }
 6063 
 6064 /*
 6065  * Do I/O using an NFSv4.1 flex file layout.
 6066  */
 6067 static int
 6068 nfscl_dofflayoutio(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
 6069     int *eofp, nfsv4stateid_t *stateidp, int rwflag, struct nfscldevinfo *dp,
 6070     struct nfscllayout *lyp, struct nfsclflayout *flp, uint64_t off,
 6071     uint64_t len, int mirror, int docommit, struct mbuf *mp,
 6072     struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
 6073 {
 6074         uint64_t transfer, xfer;
 6075         int error, rel_off;
 6076         struct nfsnode *np;
 6077         struct nfsfh *fhp;
 6078         struct nfsclds **dspp;
 6079         struct ucred *tcred;
 6080         struct mbuf *m;
 6081 
 6082         np = VTONFS(vp);
 6083         error = 0;
 6084         rel_off = 0;
 6085         NFSCL_DEBUG(4, "nfscl_dofflayoutio: off=%ju len=%ju\n", (uintmax_t)off,
 6086             (uintmax_t)len);
 6087         /* Loop around, doing I/O for each stripe unit. */
 6088         while (len > 0 && error == 0) {
 6089                 dspp = nfsfldi_addr(dp, 0);
 6090                 fhp = flp->nfsfl_ffm[mirror].fh[dp->nfsdi_versindex];
 6091                 stateidp = &flp->nfsfl_ffm[mirror].st;
 6092                 NFSCL_DEBUG(4, "mirror=%d vind=%d fhlen=%d st.seqid=0x%x\n",
 6093                     mirror, dp->nfsdi_versindex, fhp->nfh_len, stateidp->seqid);
 6094                 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0) {
 6095                         tcred = NFSNEWCRED(cred);
 6096                         tcred->cr_uid = flp->nfsfl_ffm[mirror].user;
 6097                         tcred->cr_groups[0] = flp->nfsfl_ffm[mirror].group;
 6098                         tcred->cr_ngroups = 1;
 6099                 } else
 6100                         tcred = cred;
 6101                 if (rwflag == NFSV4OPEN_ACCESSREAD)
 6102                         transfer = dp->nfsdi_rsize;
 6103                 else
 6104                         transfer = dp->nfsdi_wsize;
 6105                 NFSLOCKNODE(np);
 6106                 np->n_flag |= NDSCOMMIT;
 6107                 NFSUNLOCKNODE(np);
 6108                 if (len > transfer && docommit == 0)
 6109                         xfer = transfer;
 6110                 else
 6111                         xfer = len;
 6112                 if (docommit != 0) {
 6113                         if (error == 0) {
 6114                                 /*
 6115                                  * Do last mirrored DS commit with this thread.
 6116                                  */
 6117                                 if (mirror < flp->nfsfl_mirrorcnt - 1)
 6118                                         error = nfsio_commitds(vp, off, xfer,
 6119                                             *dspp, fhp, dp->nfsdi_vers,
 6120                                             dp->nfsdi_minorvers, drpc, tcred,
 6121                                             p);
 6122                                 else
 6123                                         error = nfsrpc_commitds(vp, off, xfer,
 6124                                             *dspp, fhp, dp->nfsdi_vers,
 6125                                             dp->nfsdi_minorvers, tcred, p);
 6126                                 NFSCL_DEBUG(4, "commitds=%d\n", error);
 6127                                 if (error != 0 && error != EACCES && error !=
 6128                                     ESTALE) {
 6129                                         NFSCL_DEBUG(4,
 6130                                             "DS layreterr for commit\n");
 6131                                         nfscl_dserr(NFSV4OP_COMMIT, error, dp,
 6132                                             lyp, *dspp);
 6133                                 }
 6134                         }
 6135                         NFSCL_DEBUG(4, "aft nfsio_commitds=%d\n", error);
 6136                         if (error == 0) {
 6137                                 /*
 6138                                  * Set both eof and uio_resid = 0 to end any
 6139                                  * loops.
 6140                                  */
 6141                                 *eofp = 1;
 6142                                 uiop->uio_resid = 0;
 6143                         } else {
 6144                                 NFSLOCKNODE(np);
 6145                                 np->n_flag &= ~NDSCOMMIT;
 6146                                 NFSUNLOCKNODE(np);
 6147                         }
 6148                 } else if (rwflag == NFSV4OPEN_ACCESSREAD) {
 6149                         error = nfsrpc_readds(vp, uiop, stateidp, eofp, *dspp,
 6150                             off, xfer, fhp, 1, dp->nfsdi_vers,
 6151                             dp->nfsdi_minorvers, tcred, p);
 6152                         NFSCL_DEBUG(4, "readds=%d\n", error);
 6153                         if (error != 0 && error != EACCES && error != ESTALE) {
 6154                                 NFSCL_DEBUG(4, "DS layreterr for read\n");
 6155                                 nfscl_dserr(NFSV4OP_READ, error, dp, lyp,
 6156                                     *dspp);
 6157                         }
 6158                 } else {
 6159                         if (flp->nfsfl_mirrorcnt == 1) {
 6160                                 error = nfsrpc_writeds(vp, uiop, iomode,
 6161                                     must_commit, stateidp, *dspp, off, xfer,
 6162                                     fhp, 0, 1, dp->nfsdi_vers,
 6163                                     dp->nfsdi_minorvers, tcred, p);
 6164                                 if (error == 0) {
 6165                                         NFSLOCKCLSTATE();
 6166                                         lyp->nfsly_flags |= NFSLY_WRITTEN;
 6167                                         NFSUNLOCKCLSTATE();
 6168                                 }
 6169                         } else {
 6170                                 m = nfsm_copym(mp, rel_off, xfer);
 6171                                 NFSCL_DEBUG(4, "mcopy reloff=%d xfer=%jd\n",
 6172                                     rel_off, (uintmax_t)xfer);
 6173                                 /*
 6174                                  * Do the writes after the first loop iteration
 6175                                  * and the write for the last mirror via this
 6176                                  * thread.
 6177                                  * This loop only iterates for small values
 6178                                  * of nfsdi_wsize, which may never occur in
 6179                                  * practice.  However, the drpc is completely
 6180                                  * used by the first iteration and, as such,
 6181                                  * cannot be used after that.
 6182                                  */
 6183                                 if (mirror < flp->nfsfl_mirrorcnt - 1 &&
 6184                                     rel_off == 0)
 6185                                         error = nfsio_writedsmir(vp, iomode,
 6186                                             must_commit, stateidp, *dspp, off,
 6187                                             xfer, fhp, m, dp->nfsdi_vers,
 6188                                             dp->nfsdi_minorvers, drpc, tcred,
 6189                                             p);
 6190                                 else
 6191                                         error = nfsrpc_writedsmir(vp, iomode,
 6192                                             must_commit, stateidp, *dspp, off,
 6193                                             xfer, fhp, m, dp->nfsdi_vers,
 6194                                             dp->nfsdi_minorvers, tcred, p);
 6195                                 NFSCL_DEBUG(4, "nfsio_writedsmir=%d\n", error);
 6196                                 if (error != 0 && error != EACCES && error !=
 6197                                     ESTALE) {
 6198                                         NFSCL_DEBUG(4,
 6199                                             "DS layreterr for write\n");
 6200                                         nfscl_dserr(NFSV4OP_WRITE, error, dp,
 6201                                             lyp, *dspp);
 6202                                 }
 6203                         }
 6204                 }
 6205                 NFSCL_DEBUG(4, "aft read/writeds=%d\n", error);
 6206                 if (error == 0) {
 6207                         len -= xfer;
 6208                         off += xfer;
 6209                         rel_off += xfer;
 6210                 }
 6211                 if ((dp->nfsdi_flags & NFSDI_TIGHTCOUPLED) == 0)
 6212                         NFSFREECRED(tcred);
 6213         }
 6214         NFSCL_DEBUG(4, "eo nfscl_dofflayoutio=%d\n", error);
 6215         return (error);
 6216 }
 6217 
 6218 /*
 6219  * The actual read RPC done to a DS.
 6220  */
 6221 static int
 6222 nfsrpc_readds(vnode_t vp, struct uio *uiop, nfsv4stateid_t *stateidp, int *eofp,
 6223     struct nfsclds *dsp, uint64_t io_off, int len, struct nfsfh *fhp, int flex,
 6224     int vers, int minorvers, struct ucred *cred, NFSPROC_T *p)
 6225 {
 6226         uint32_t *tl;
 6227         int attrflag, error, retlen;
 6228         struct nfsrv_descript nfsd;
 6229         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 6230         struct nfsrv_descript *nd = &nfsd;
 6231         struct nfssockreq *nrp;
 6232         struct nfsvattr na;
 6233 
 6234         nd->nd_mrep = NULL;
 6235         if (vers == 0 || vers == NFS_VER4) {
 6236                 nfscl_reqstart(nd, NFSPROC_READDS, nmp, fhp->nfh_fh,
 6237                     fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
 6238                 vers = NFS_VER4;
 6239                 NFSCL_DEBUG(4, "nfsrpc_readds: vers4 minvers=%d\n", minorvers);
 6240                 if (flex != 0)
 6241                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 6242                 else
 6243                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
 6244         } else {
 6245                 nfscl_reqstart(nd, NFSPROC_READ, nmp, fhp->nfh_fh,
 6246                     fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
 6247                 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READ]);
 6248                 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_READDS]);
 6249                 NFSCL_DEBUG(4, "nfsrpc_readds: vers3\n");
 6250         }
 6251         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED * 3);
 6252         txdr_hyper(io_off, tl);
 6253         *(tl + 2) = txdr_unsigned(len);
 6254         nrp = dsp->nfsclds_sockp;
 6255         NFSCL_DEBUG(4, "nfsrpc_readds: nrp=%p\n", nrp);
 6256         if (nrp == NULL)
 6257                 /* If NULL, use the MDS socket. */
 6258                 nrp = &nmp->nm_sockreq;
 6259         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
 6260             NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
 6261         NFSCL_DEBUG(4, "nfsrpc_readds: stat=%d err=%d\n", nd->nd_repstat,
 6262             error);
 6263         if (error != 0)
 6264                 return (error);
 6265         if (vers == NFS_VER3) {
 6266                 error = nfscl_postop_attr(nd, &na, &attrflag, NULL);
 6267                 NFSCL_DEBUG(4, "nfsrpc_readds: postop=%d\n", error);
 6268                 if (error != 0)
 6269                         goto nfsmout;
 6270         }
 6271         if (nd->nd_repstat != 0) {
 6272                 error = nd->nd_repstat;
 6273                 goto nfsmout;
 6274         }
 6275         if (vers == NFS_VER3) {
 6276                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 6277                 *eofp = fxdr_unsigned(int, *(tl + 1));
 6278         } else {
 6279                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 6280                 *eofp = fxdr_unsigned(int, *tl);
 6281         }
 6282         NFSM_STRSIZ(retlen, len);
 6283         NFSCL_DEBUG(4, "nfsrpc_readds: retlen=%d eof=%d\n", retlen, *eofp);
 6284         error = nfsm_mbufuio(nd, uiop, retlen);
 6285 nfsmout:
 6286         if (nd->nd_mrep != NULL)
 6287                 mbuf_freem(nd->nd_mrep);
 6288         return (error);
 6289 }
 6290 
 6291 /*
 6292  * The actual write RPC done to a DS.
 6293  */
 6294 static int
 6295 nfsrpc_writeds(vnode_t vp, struct uio *uiop, int *iomode, int *must_commit,
 6296     nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
 6297     struct nfsfh *fhp, int commit_thru_mds, int flex, int vers, int minorvers,
 6298     struct ucred *cred, NFSPROC_T *p)
 6299 {
 6300         uint32_t *tl;
 6301         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 6302         int attrflag, error, rlen, commit, committed = NFSWRITE_FILESYNC;
 6303         int32_t backup;
 6304         struct nfsrv_descript nfsd;
 6305         struct nfsrv_descript *nd = &nfsd;
 6306         struct nfssockreq *nrp;
 6307         struct nfsvattr na;
 6308 
 6309         KASSERT(uiop->uio_iovcnt == 1, ("nfs: writerpc iovcnt > 1"));
 6310         nd->nd_mrep = NULL;
 6311         if (vers == 0 || vers == NFS_VER4) {
 6312                 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
 6313                     fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
 6314                 NFSCL_DEBUG(4, "nfsrpc_writeds: vers4 minvers=%d\n", minorvers);
 6315                 vers = NFS_VER4;
 6316                 if (flex != 0)
 6317                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 6318                 else
 6319                         nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSEQIDZERO);
 6320                 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
 6321         } else {
 6322                 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
 6323                     fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
 6324                 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]);
 6325                 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]);
 6326                 NFSCL_DEBUG(4, "nfsrpc_writeds: vers3\n");
 6327                 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
 6328         }
 6329         txdr_hyper(io_off, tl);
 6330         tl += 2;
 6331         if (vers == NFS_VER3)
 6332                 *tl++ = txdr_unsigned(len);
 6333         *tl++ = txdr_unsigned(*iomode);
 6334         *tl = txdr_unsigned(len);
 6335         nfsm_uiombuf(nd, uiop, len);
 6336         nrp = dsp->nfsclds_sockp;
 6337         if (nrp == NULL)
 6338                 /* If NULL, use the MDS socket. */
 6339                 nrp = &nmp->nm_sockreq;
 6340         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
 6341             NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
 6342         NFSCL_DEBUG(4, "nfsrpc_writeds: err=%d stat=%d\n", error,
 6343             nd->nd_repstat);
 6344         if (error != 0)
 6345                 return (error);
 6346         if (nd->nd_repstat != 0) {
 6347                 /*
 6348                  * In case the rpc gets retried, roll
 6349                  * the uio fileds changed by nfsm_uiombuf()
 6350                  * back.
 6351                  */
 6352                 uiop->uio_offset -= len;
 6353                 uio_uio_resid_add(uiop, len);
 6354                 uio_iov_base_add(uiop, -len);
 6355                 uio_iov_len_add(uiop, len);
 6356                 error = nd->nd_repstat;
 6357         } else {
 6358                 if (vers == NFS_VER3) {
 6359                         error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
 6360                             NULL);
 6361                         NFSCL_DEBUG(4, "nfsrpc_writeds: wcc_data=%d\n", error);
 6362                         if (error != 0)
 6363                                 goto nfsmout;
 6364                 }
 6365                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
 6366                 rlen = fxdr_unsigned(int, *tl++);
 6367                 NFSCL_DEBUG(4, "nfsrpc_writeds: len=%d rlen=%d\n", len, rlen);
 6368                 if (rlen == 0) {
 6369                         error = NFSERR_IO;
 6370                         goto nfsmout;
 6371                 } else if (rlen < len) {
 6372                         backup = len - rlen;
 6373                         uio_iov_base_add(uiop, -(backup));
 6374                         uio_iov_len_add(uiop, backup);
 6375                         uiop->uio_offset -= backup;
 6376                         uio_uio_resid_add(uiop, backup);
 6377                         len = rlen;
 6378                 }
 6379                 commit = fxdr_unsigned(int, *tl++);
 6380 
 6381                 /*
 6382                  * Return the lowest commitment level
 6383                  * obtained by any of the RPCs.
 6384                  */
 6385                 if (committed == NFSWRITE_FILESYNC)
 6386                         committed = commit;
 6387                 else if (committed == NFSWRITE_DATASYNC &&
 6388                     commit == NFSWRITE_UNSTABLE)
 6389                         committed = commit;
 6390                 if (commit_thru_mds != 0) {
 6391                         NFSLOCKMNT(nmp);
 6392                         if (!NFSHASWRITEVERF(nmp)) {
 6393                                 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
 6394                                 NFSSETWRITEVERF(nmp);
 6395                         } else if (NFSBCMP(tl, nmp->nm_verf, NFSX_VERF) &&
 6396                             *must_commit != 2) {
 6397                                 *must_commit = 1;
 6398                                 NFSBCOPY(tl, nmp->nm_verf, NFSX_VERF);
 6399                         }
 6400                         NFSUNLOCKMNT(nmp);
 6401                 } else {
 6402                         NFSLOCKDS(dsp);
 6403                         if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
 6404                                 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
 6405                                 dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
 6406                         } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) &&
 6407                             *must_commit != 2) {
 6408                                 *must_commit = 1;
 6409                                 NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
 6410                         }
 6411                         NFSUNLOCKDS(dsp);
 6412                 }
 6413         }
 6414 nfsmout:
 6415         if (nd->nd_mrep != NULL)
 6416                 mbuf_freem(nd->nd_mrep);
 6417         *iomode = committed;
 6418         if (nd->nd_repstat != 0 && error == 0)
 6419                 error = nd->nd_repstat;
 6420         return (error);
 6421 }
 6422 
 6423 /*
 6424  * The actual write RPC done to a DS.
 6425  * This variant is called from a separate kernel process for mirrors.
 6426  * Any short write is considered an IO error.
 6427  */
 6428 static int
 6429 nfsrpc_writedsmir(vnode_t vp, int *iomode, int *must_commit,
 6430     nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t io_off, int len,
 6431     struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
 6432     struct ucred *cred, NFSPROC_T *p)
 6433 {
 6434         uint32_t *tl;
 6435         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 6436         int attrflag, error, commit, committed = NFSWRITE_FILESYNC, rlen;
 6437         struct nfsrv_descript nfsd;
 6438         struct nfsrv_descript *nd = &nfsd;
 6439         struct nfssockreq *nrp;
 6440         struct nfsvattr na;
 6441 
 6442         nd->nd_mrep = NULL;
 6443         if (vers == 0 || vers == NFS_VER4) {
 6444                 nfscl_reqstart(nd, NFSPROC_WRITEDS, nmp, fhp->nfh_fh,
 6445                     fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
 6446                 vers = NFS_VER4;
 6447                 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers4 minvers=%d\n",
 6448                     minorvers);
 6449                 nfsm_stateidtom(nd, stateidp, NFSSTATEID_PUTSTATEID);
 6450                 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
 6451         } else {
 6452                 nfscl_reqstart(nd, NFSPROC_WRITE, nmp, fhp->nfh_fh,
 6453                     fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
 6454                 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITE]);
 6455                 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_WRITEDS]);
 6456                 NFSCL_DEBUG(4, "nfsrpc_writedsmir: vers3\n");
 6457                 NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + 3 * NFSX_UNSIGNED);
 6458         }
 6459         txdr_hyper(io_off, tl);
 6460         tl += 2;
 6461         if (vers == NFS_VER3)
 6462                 *tl++ = txdr_unsigned(len);
 6463         *tl++ = txdr_unsigned(*iomode);
 6464         *tl = txdr_unsigned(len);
 6465         if (len > 0) {
 6466                 /* Put data in mbuf chain. */
 6467                 nd->nd_mb->m_next = m;
 6468                 /* Set nd_mb and nd_bpos to end of data. */
 6469                 while (m->m_next != NULL)
 6470                         m = m->m_next;
 6471                 nd->nd_mb = m;
 6472                 nd->nd_bpos = mtod(m, char *) + m->m_len;
 6473                 NFSCL_DEBUG(4, "nfsrpc_writedsmir: lastmb len=%d\n", m->m_len);
 6474         }
 6475         nrp = dsp->nfsclds_sockp;
 6476         if (nrp == NULL)
 6477                 /* If NULL, use the MDS socket. */
 6478                 nrp = &nmp->nm_sockreq;
 6479         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
 6480             NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
 6481         NFSCL_DEBUG(4, "nfsrpc_writedsmir: err=%d stat=%d\n", error,
 6482             nd->nd_repstat);
 6483         if (error != 0)
 6484                 return (error);
 6485         if (nd->nd_repstat != 0)
 6486                 error = nd->nd_repstat;
 6487         else {
 6488                 if (vers == NFS_VER3) {
 6489                         error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
 6490                             NULL);
 6491                         NFSCL_DEBUG(4, "nfsrpc_writedsmir: wcc_data=%d\n",
 6492                             error);
 6493                         if (error != 0)
 6494                                 goto nfsmout;
 6495                 }
 6496                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_VERF);
 6497                 rlen = fxdr_unsigned(int, *tl++);
 6498                 NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n", len,
 6499                     rlen);
 6500                 if (rlen != len) {
 6501                         error = NFSERR_IO;
 6502                         NFSCL_DEBUG(4, "nfsrpc_writedsmir: len=%d rlen=%d\n",
 6503                             len, rlen);
 6504                         goto nfsmout;
 6505                 }
 6506                 commit = fxdr_unsigned(int, *tl++);
 6507 
 6508                 /*
 6509                  * Return the lowest commitment level
 6510                  * obtained by any of the RPCs.
 6511                  */
 6512                 if (committed == NFSWRITE_FILESYNC)
 6513                         committed = commit;
 6514                 else if (committed == NFSWRITE_DATASYNC &&
 6515                     commit == NFSWRITE_UNSTABLE)
 6516                         committed = commit;
 6517                 NFSLOCKDS(dsp);
 6518                 if ((dsp->nfsclds_flags & NFSCLDS_HASWRITEVERF) == 0) {
 6519                         NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
 6520                         dsp->nfsclds_flags |= NFSCLDS_HASWRITEVERF;
 6521                 } else if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF) &&
 6522                     *must_commit != 2) {
 6523                         *must_commit = 1;
 6524                         NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
 6525                 }
 6526                 NFSUNLOCKDS(dsp);
 6527         }
 6528 nfsmout:
 6529         if (nd->nd_mrep != NULL)
 6530                 mbuf_freem(nd->nd_mrep);
 6531         *iomode = committed;
 6532         if (nd->nd_repstat != 0 && error == 0)
 6533                 error = nd->nd_repstat;
 6534         return (error);
 6535 }
 6536 
 6537 /*
 6538  * Start up the thread that will execute nfsrpc_writedsmir().
 6539  */
 6540 static void
 6541 start_writedsmir(void *arg, int pending)
 6542 {
 6543         struct nfsclwritedsdorpc *drpc;
 6544 
 6545         drpc = (struct nfsclwritedsdorpc *)arg;
 6546         drpc->err = nfsrpc_writedsmir(drpc->vp, &drpc->iomode,
 6547             &drpc->must_commit, drpc->stateidp, drpc->dsp, drpc->off, drpc->len,
 6548             drpc->fhp, drpc->m, drpc->vers, drpc->minorvers, drpc->cred,
 6549             drpc->p);
 6550         drpc->done = 1;
 6551         NFSCL_DEBUG(4, "start_writedsmir: err=%d\n", drpc->err);
 6552 }
 6553 
 6554 /*
 6555  * Set up the write DS mirror call for the pNFS I/O thread.
 6556  */
 6557 static int
 6558 nfsio_writedsmir(vnode_t vp, int *iomode, int *must_commit,
 6559     nfsv4stateid_t *stateidp, struct nfsclds *dsp, uint64_t off, int len,
 6560     struct nfsfh *fhp, struct mbuf *m, int vers, int minorvers,
 6561     struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
 6562 {
 6563         int error, ret;
 6564 
 6565         error = 0;
 6566         drpc->done = 0;
 6567         drpc->vp = vp;
 6568         drpc->iomode = *iomode;
 6569         drpc->must_commit = *must_commit;
 6570         drpc->stateidp = stateidp;
 6571         drpc->dsp = dsp;
 6572         drpc->off = off;
 6573         drpc->len = len;
 6574         drpc->fhp = fhp;
 6575         drpc->m = m;
 6576         drpc->vers = vers;
 6577         drpc->minorvers = minorvers;
 6578         drpc->cred = cred;
 6579         drpc->p = p;
 6580         drpc->inprog = 0;
 6581         ret = EIO;
 6582         if (nfs_pnfsiothreads != 0) {
 6583                 ret = nfs_pnfsio(start_writedsmir, drpc);
 6584                 NFSCL_DEBUG(4, "nfsio_writedsmir: nfs_pnfsio=%d\n", ret);
 6585         }
 6586         if (ret != 0)
 6587                 error = nfsrpc_writedsmir(vp, iomode, &drpc->must_commit,
 6588                     stateidp, dsp, off, len, fhp, m, vers, minorvers, cred, p);
 6589         NFSCL_DEBUG(4, "nfsio_writedsmir: error=%d\n", error);
 6590         return (error);
 6591 }
 6592 
 6593 /*
 6594  * Free up the nfsclds structure.
 6595  */
 6596 void
 6597 nfscl_freenfsclds(struct nfsclds *dsp)
 6598 {
 6599         int i;
 6600 
 6601         if (dsp == NULL)
 6602                 return;
 6603         if (dsp->nfsclds_sockp != NULL) {
 6604                 NFSFREECRED(dsp->nfsclds_sockp->nr_cred);
 6605                 NFSFREEMUTEX(&dsp->nfsclds_sockp->nr_mtx);
 6606                 free(dsp->nfsclds_sockp->nr_nam, M_SONAME);
 6607                 free(dsp->nfsclds_sockp, M_NFSSOCKREQ);
 6608         }
 6609         NFSFREEMUTEX(&dsp->nfsclds_mtx);
 6610         NFSFREEMUTEX(&dsp->nfsclds_sess.nfsess_mtx);
 6611         for (i = 0; i < NFSV4_CBSLOTS; i++) {
 6612                 if (dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply != NULL)
 6613                         m_freem(
 6614                             dsp->nfsclds_sess.nfsess_cbslots[i].nfssl_reply);
 6615         }
 6616         free(dsp, M_NFSCLDS);
 6617 }
 6618 
 6619 static enum nfsclds_state
 6620 nfscl_getsameserver(struct nfsmount *nmp, struct nfsclds *newdsp,
 6621     struct nfsclds **retdspp, uint32_t *sequencep)
 6622 {
 6623         struct nfsclds *dsp;
 6624         int fndseq;
 6625 
 6626         /*
 6627          * Search the list of nfsclds structures for one with the same
 6628          * server.
 6629          */
 6630         fndseq = 0;
 6631         TAILQ_FOREACH(dsp, &nmp->nm_sess, nfsclds_list) {
 6632                 if (dsp->nfsclds_servownlen == newdsp->nfsclds_servownlen &&
 6633                     dsp->nfsclds_servownlen != 0 &&
 6634                     !NFSBCMP(dsp->nfsclds_serverown, newdsp->nfsclds_serverown,
 6635                     dsp->nfsclds_servownlen) &&
 6636                     dsp->nfsclds_sess.nfsess_defunct == 0) {
 6637                         NFSCL_DEBUG(4, "fnd same fdsp=%p dsp=%p flg=0x%x\n",
 6638                             TAILQ_FIRST(&nmp->nm_sess), dsp,
 6639                             dsp->nfsclds_flags);
 6640                         if (fndseq == 0) {
 6641                                 /* Get sequenceid# from first entry. */
 6642                                 *sequencep =
 6643                                     dsp->nfsclds_sess.nfsess_sequenceid;
 6644                                 fndseq = 1;
 6645                         }
 6646                         /* Server major id matches. */
 6647                         if ((dsp->nfsclds_flags & NFSCLDS_DS) != 0) {
 6648                                 *retdspp = dsp;
 6649                                 return (NFSDSP_USETHISSESSION);
 6650                         }
 6651 
 6652                 }
 6653         }
 6654         if (fndseq != 0)
 6655                 return (NFSDSP_SEQTHISSESSION);
 6656         return (NFSDSP_NOTFOUND);
 6657 }
 6658 
 6659 /*
 6660  * NFS commit rpc to a NFSv4.1 DS.
 6661  */
 6662 static int
 6663 nfsrpc_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
 6664     struct nfsfh *fhp, int vers, int minorvers, struct ucred *cred,
 6665     NFSPROC_T *p)
 6666 {
 6667         uint32_t *tl;
 6668         struct nfsrv_descript nfsd, *nd = &nfsd;
 6669         struct nfsmount *nmp = VFSTONFS(vnode_mount(vp));
 6670         struct nfssockreq *nrp;
 6671         struct nfsvattr na;
 6672         int attrflag, error;
 6673         
 6674         nd->nd_mrep = NULL;
 6675         if (vers == 0 || vers == NFS_VER4) {
 6676                 nfscl_reqstart(nd, NFSPROC_COMMITDS, nmp, fhp->nfh_fh,
 6677                     fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
 6678                 vers = NFS_VER4;
 6679         } else {
 6680                 nfscl_reqstart(nd, NFSPROC_COMMIT, nmp, fhp->nfh_fh,
 6681                     fhp->nfh_len, NULL, &dsp->nfsclds_sess, vers, minorvers);
 6682                 NFSDECRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMIT]);
 6683                 NFSINCRGLOBAL(nfsstatsv1.rpccnt[NFSPROC_COMMITDS]);
 6684         }
 6685         NFSCL_DEBUG(4, "nfsrpc_commitds: vers=%d minvers=%d\n", vers,
 6686             minorvers);
 6687         NFSM_BUILD(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
 6688         txdr_hyper(offset, tl);
 6689         tl += 2;
 6690         *tl = txdr_unsigned(cnt);
 6691         nrp = dsp->nfsclds_sockp;
 6692         if (nrp == NULL)
 6693                 /* If NULL, use the MDS socket. */
 6694                 nrp = &nmp->nm_sockreq;
 6695         error = newnfs_request(nd, nmp, NULL, nrp, vp, p, cred,
 6696             NFS_PROG, vers, NULL, 1, NULL, &dsp->nfsclds_sess);
 6697         NFSCL_DEBUG(4, "nfsrpc_commitds: err=%d stat=%d\n", error,
 6698             nd->nd_repstat);
 6699         if (error != 0)
 6700                 return (error);
 6701         if (nd->nd_repstat == 0) {
 6702                 if (vers == NFS_VER3) {
 6703                         error = nfscl_wcc_data(nd, vp, &na, &attrflag, NULL,
 6704                             NULL);
 6705                         NFSCL_DEBUG(4, "nfsrpc_commitds: wccdata=%d\n", error);
 6706                         if (error != 0)
 6707                                 goto nfsmout;
 6708                 }
 6709                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 6710                 NFSLOCKDS(dsp);
 6711                 if (NFSBCMP(tl, dsp->nfsclds_verf, NFSX_VERF)) {
 6712                         NFSBCOPY(tl, dsp->nfsclds_verf, NFSX_VERF);
 6713                         error = NFSERR_STALEWRITEVERF;
 6714                 }
 6715                 NFSUNLOCKDS(dsp);
 6716         }
 6717 nfsmout:
 6718         if (error == 0 && nd->nd_repstat != 0)
 6719                 error = nd->nd_repstat;
 6720         mbuf_freem(nd->nd_mrep);
 6721         return (error);
 6722 }
 6723 
 6724 /*
 6725  * Start up the thread that will execute nfsrpc_commitds().
 6726  */
 6727 static void
 6728 start_commitds(void *arg, int pending)
 6729 {
 6730         struct nfsclwritedsdorpc *drpc;
 6731 
 6732         drpc = (struct nfsclwritedsdorpc *)arg;
 6733         drpc->err = nfsrpc_commitds(drpc->vp, drpc->off, drpc->len,
 6734             drpc->dsp, drpc->fhp, drpc->vers, drpc->minorvers, drpc->cred,
 6735             drpc->p);
 6736         drpc->done = 1;
 6737         NFSCL_DEBUG(4, "start_commitds: err=%d\n", drpc->err);
 6738 }
 6739 
 6740 /*
 6741  * Set up the commit DS mirror call for the pNFS I/O thread.
 6742  */
 6743 static int
 6744 nfsio_commitds(vnode_t vp, uint64_t offset, int cnt, struct nfsclds *dsp,
 6745     struct nfsfh *fhp, int vers, int minorvers,
 6746     struct nfsclwritedsdorpc *drpc, struct ucred *cred, NFSPROC_T *p)
 6747 {
 6748         int error, ret;
 6749 
 6750         error = 0;
 6751         drpc->done = 0;
 6752         drpc->vp = vp;
 6753         drpc->off = offset;
 6754         drpc->len = cnt;
 6755         drpc->dsp = dsp;
 6756         drpc->fhp = fhp;
 6757         drpc->vers = vers;
 6758         drpc->minorvers = minorvers;
 6759         drpc->cred = cred;
 6760         drpc->p = p;
 6761         drpc->inprog = 0;
 6762         ret = EIO;
 6763         if (nfs_pnfsiothreads != 0) {
 6764                 ret = nfs_pnfsio(start_commitds, drpc);
 6765                 NFSCL_DEBUG(4, "nfsio_commitds: nfs_pnfsio=%d\n", ret);
 6766         }
 6767         if (ret != 0)
 6768                 error = nfsrpc_commitds(vp, offset, cnt, dsp, fhp, vers,
 6769                     minorvers, cred, p);
 6770         NFSCL_DEBUG(4, "nfsio_commitds: error=%d\n", error);
 6771         return (error);
 6772 }
 6773 
 6774 /*
 6775  * Set up the XDR arguments for the LayoutGet operation.
 6776  */
 6777 static void
 6778 nfsrv_setuplayoutget(struct nfsrv_descript *nd, int iomode, uint64_t offset,
 6779     uint64_t len, uint64_t minlen, nfsv4stateid_t *stateidp, int layouttype,
 6780     int layoutlen, int usecurstateid)
 6781 {
 6782         uint32_t *tl;
 6783 
 6784         NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
 6785             NFSX_STATEID);
 6786         *tl++ = newnfs_false;           /* Don't signal availability. */
 6787         *tl++ = txdr_unsigned(layouttype);
 6788         *tl++ = txdr_unsigned(iomode);
 6789         txdr_hyper(offset, tl);
 6790         tl += 2;
 6791         txdr_hyper(len, tl);
 6792         tl += 2;
 6793         txdr_hyper(minlen, tl);
 6794         tl += 2;
 6795         if (usecurstateid != 0) {
 6796                 /* Special stateid for Current stateid. */
 6797                 *tl++ = txdr_unsigned(1);
 6798                 *tl++ = 0;
 6799                 *tl++ = 0;
 6800                 *tl++ = 0;
 6801         } else {
 6802                 *tl++ = txdr_unsigned(stateidp->seqid);
 6803                 NFSCL_DEBUG(4, "layget seq=%d\n", (int)stateidp->seqid);
 6804                 *tl++ = stateidp->other[0];
 6805                 *tl++ = stateidp->other[1];
 6806                 *tl++ = stateidp->other[2];
 6807         }
 6808         *tl = txdr_unsigned(layoutlen);
 6809 }
 6810 
 6811 /*
 6812  * Parse the reply for a successful LayoutGet operation.
 6813  */
 6814 static int
 6815 nfsrv_parselayoutget(struct nfsrv_descript *nd, nfsv4stateid_t *stateidp,
 6816     int *retonclosep, struct nfsclflayouthead *flhp)
 6817 {
 6818         uint32_t *tl;
 6819         struct nfsclflayout *flp, *prevflp, *tflp;
 6820         int cnt, error, fhcnt, gotiomode, i, iomode, j, k, l, laytype, nfhlen;
 6821         int m, mirrorcnt;
 6822         uint64_t retlen, off;
 6823         struct nfsfh *nfhp;
 6824         uint8_t *cp;
 6825         uid_t user;
 6826         gid_t grp;
 6827 
 6828         NFSCL_DEBUG(4, "in nfsrv_parselayoutget\n");
 6829         error = 0;
 6830         flp = NULL;
 6831         gotiomode = -1;
 6832         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + NFSX_STATEID);
 6833         if (*tl++ != 0)
 6834                 *retonclosep = 1;
 6835         else
 6836                 *retonclosep = 0;
 6837         stateidp->seqid = fxdr_unsigned(uint32_t, *tl++);
 6838         NFSCL_DEBUG(4, "retoncls=%d stseq=%d\n", *retonclosep,
 6839             (int)stateidp->seqid);
 6840         stateidp->other[0] = *tl++;
 6841         stateidp->other[1] = *tl++;
 6842         stateidp->other[2] = *tl++;
 6843         cnt = fxdr_unsigned(int, *tl);
 6844         NFSCL_DEBUG(4, "layg cnt=%d\n", cnt);
 6845         if (cnt <= 0 || cnt > 10000) {
 6846                 /* Don't accept more than 10000 layouts in reply. */
 6847                 error = NFSERR_BADXDR;
 6848                 goto nfsmout;
 6849         }
 6850         for (i = 0; i < cnt; i++) {
 6851                 /* Dissect to the layout type. */
 6852                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER +
 6853                     3 * NFSX_UNSIGNED);
 6854                 off = fxdr_hyper(tl); tl += 2;
 6855                 retlen = fxdr_hyper(tl); tl += 2;
 6856                 iomode = fxdr_unsigned(int, *tl++);
 6857                 laytype = fxdr_unsigned(int, *tl);
 6858                 NFSCL_DEBUG(4, "layt=%d off=%ju len=%ju iom=%d\n", laytype,
 6859                     (uintmax_t)off, (uintmax_t)retlen, iomode);
 6860                 /* Ignore length of layout body for now. */
 6861                 if (laytype == NFSLAYOUT_NFSV4_1_FILES) {
 6862                         /* Parse the File layout up to fhcnt. */
 6863                         NFSM_DISSECT(tl, uint32_t *, 3 * NFSX_UNSIGNED +
 6864                             NFSX_HYPER + NFSX_V4DEVICEID);
 6865                         fhcnt = fxdr_unsigned(int, *(tl + 4 +
 6866                             NFSX_V4DEVICEID / NFSX_UNSIGNED));
 6867                         NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
 6868                         if (fhcnt < 0 || fhcnt > 100) {
 6869                                 /* Don't accept more than 100 file handles. */
 6870                                 error = NFSERR_BADXDR;
 6871                                 goto nfsmout;
 6872                         }
 6873                         if (fhcnt > 0)
 6874                                 flp = malloc(sizeof(*flp) + fhcnt *
 6875                                     sizeof(struct nfsfh *), M_NFSFLAYOUT,
 6876                                     M_WAITOK);
 6877                         else
 6878                                 flp = malloc(sizeof(*flp), M_NFSFLAYOUT,
 6879                                     M_WAITOK);
 6880                         flp->nfsfl_flags = NFSFL_FILE;
 6881                         flp->nfsfl_fhcnt = 0;
 6882                         flp->nfsfl_devp = NULL;
 6883                         flp->nfsfl_off = off;
 6884                         if (flp->nfsfl_off + retlen < flp->nfsfl_off)
 6885                                 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
 6886                         else
 6887                                 flp->nfsfl_end = flp->nfsfl_off + retlen;
 6888                         flp->nfsfl_iomode = iomode;
 6889                         if (gotiomode == -1)
 6890                                 gotiomode = flp->nfsfl_iomode;
 6891                         /* Ignore layout body length for now. */
 6892                         NFSBCOPY(tl, flp->nfsfl_dev, NFSX_V4DEVICEID);
 6893                         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
 6894                         flp->nfsfl_util = fxdr_unsigned(uint32_t, *tl++);
 6895                         NFSCL_DEBUG(4, "flutil=0x%x\n", flp->nfsfl_util);
 6896                         flp->nfsfl_stripe1 = fxdr_unsigned(uint32_t, *tl++);
 6897                         flp->nfsfl_patoff = fxdr_hyper(tl); tl += 2;
 6898                         NFSCL_DEBUG(4, "stripe1=%u poff=%ju\n",
 6899                             flp->nfsfl_stripe1, (uintmax_t)flp->nfsfl_patoff);
 6900                         for (j = 0; j < fhcnt; j++) {
 6901                                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 6902                                 nfhlen = fxdr_unsigned(int, *tl);
 6903                                 if (nfhlen <= 0 || nfhlen > NFSX_V4FHMAX) {
 6904                                         error = NFSERR_BADXDR;
 6905                                         goto nfsmout;
 6906                                 }
 6907                                 nfhp = malloc(sizeof(*nfhp) + nfhlen - 1,
 6908                                     M_NFSFH, M_WAITOK);
 6909                                 flp->nfsfl_fh[j] = nfhp;
 6910                                 flp->nfsfl_fhcnt++;
 6911                                 nfhp->nfh_len = nfhlen;
 6912                                 NFSM_DISSECT(cp, uint8_t *, NFSM_RNDUP(nfhlen));
 6913                                 NFSBCOPY(cp, nfhp->nfh_fh, nfhlen);
 6914                         }
 6915                 } else if (laytype == NFSLAYOUT_FLEXFILE) {
 6916                         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED +
 6917                             NFSX_HYPER);
 6918                         mirrorcnt = fxdr_unsigned(int, *(tl + 2));
 6919                         NFSCL_DEBUG(4, "mirrorcnt=%d\n", mirrorcnt);
 6920                         if (mirrorcnt < 1 || mirrorcnt > NFSDEV_MAXMIRRORS) {
 6921                                 error = NFSERR_BADXDR;
 6922                                 goto nfsmout;
 6923                         }
 6924                         flp = malloc(sizeof(*flp) + mirrorcnt *
 6925                             sizeof(struct nfsffm), M_NFSFLAYOUT, M_WAITOK);
 6926                         flp->nfsfl_flags = NFSFL_FLEXFILE;
 6927                         flp->nfsfl_mirrorcnt = mirrorcnt;
 6928                         for (j = 0; j < mirrorcnt; j++)
 6929                                 flp->nfsfl_ffm[j].devp = NULL;
 6930                         flp->nfsfl_off = off;
 6931                         if (flp->nfsfl_off + retlen < flp->nfsfl_off)
 6932                                 flp->nfsfl_end = UINT64_MAX - flp->nfsfl_off;
 6933                         else
 6934                                 flp->nfsfl_end = flp->nfsfl_off + retlen;
 6935                         flp->nfsfl_iomode = iomode;
 6936                         if (gotiomode == -1)
 6937                                 gotiomode = flp->nfsfl_iomode;
 6938                         flp->nfsfl_stripeunit = fxdr_hyper(tl);
 6939                         NFSCL_DEBUG(4, "stripeunit=%ju\n",
 6940                             (uintmax_t)flp->nfsfl_stripeunit);
 6941                         for (j = 0; j < mirrorcnt; j++) {
 6942                                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 6943                                 k = fxdr_unsigned(int, *tl);
 6944                                 if (k < 1 || k > 128) {
 6945                                         error = NFSERR_BADXDR;
 6946                                         goto nfsmout;
 6947                                 }
 6948                                 NFSCL_DEBUG(4, "servercnt=%d\n", k);
 6949                                 for (l = 0; l < k; l++) {
 6950                                         NFSM_DISSECT(tl, uint32_t *,
 6951                                             NFSX_V4DEVICEID + NFSX_STATEID +
 6952                                             2 * NFSX_UNSIGNED);
 6953                                         if (l == 0) {
 6954                                                 /* Just use the first server. */
 6955                                                 NFSBCOPY(tl,
 6956                                                     flp->nfsfl_ffm[j].dev,
 6957                                                     NFSX_V4DEVICEID);
 6958                                                 tl += (NFSX_V4DEVICEID /
 6959                                                     NFSX_UNSIGNED);
 6960                                                 tl++;
 6961                                                 flp->nfsfl_ffm[j].st.seqid =
 6962                                                     *tl++;
 6963                                                 flp->nfsfl_ffm[j].st.other[0] =
 6964                                                     *tl++;
 6965                                                 flp->nfsfl_ffm[j].st.other[1] =
 6966                                                     *tl++;
 6967                                                 flp->nfsfl_ffm[j].st.other[2] =
 6968                                                     *tl++;
 6969                                                 NFSCL_DEBUG(4, "st.seqid=%u "
 6970                                                  "st.o0=0x%x st.o1=0x%x "
 6971                                                  "st.o2=0x%x\n",
 6972                                                  flp->nfsfl_ffm[j].st.seqid,
 6973                                                  flp->nfsfl_ffm[j].st.other[0],
 6974                                                  flp->nfsfl_ffm[j].st.other[1],
 6975                                                  flp->nfsfl_ffm[j].st.other[2]);
 6976                                         } else
 6977                                                 tl += ((NFSX_V4DEVICEID +
 6978                                                     NFSX_STATEID +
 6979                                                     NFSX_UNSIGNED) /
 6980                                                     NFSX_UNSIGNED);
 6981                                         fhcnt = fxdr_unsigned(int, *tl);
 6982                                         NFSCL_DEBUG(4, "fhcnt=%d\n", fhcnt);
 6983                                         if (fhcnt < 1 ||
 6984                                             fhcnt > NFSDEV_MAXVERS) {
 6985                                                 error = NFSERR_BADXDR;
 6986                                                 goto nfsmout;
 6987                                         }
 6988                                         for (m = 0; m < fhcnt; m++) {
 6989                                                 NFSM_DISSECT(tl, uint32_t *,
 6990                                                     NFSX_UNSIGNED);
 6991                                                 nfhlen = fxdr_unsigned(int,
 6992                                                     *tl);
 6993                                                 NFSCL_DEBUG(4, "nfhlen=%d\n",
 6994                                                     nfhlen);
 6995                                                 if (nfhlen <= 0 || nfhlen >
 6996                                                     NFSX_V4FHMAX) {
 6997                                                         error = NFSERR_BADXDR;
 6998                                                         goto nfsmout;
 6999                                                 }
 7000                                                 NFSM_DISSECT(cp, uint8_t *,
 7001                                                     NFSM_RNDUP(nfhlen));
 7002                                                 if (l == 0) {
 7003                                                         flp->nfsfl_ffm[j].fhcnt 
 7004                                                             = fhcnt;
 7005                                                         nfhp = malloc(
 7006                                                             sizeof(*nfhp) +
 7007                                                             nfhlen - 1, M_NFSFH,
 7008                                                             M_WAITOK);
 7009                                                         flp->nfsfl_ffm[j].fh[m]
 7010                                                             = nfhp;
 7011                                                         nfhp->nfh_len = nfhlen;
 7012                                                         NFSBCOPY(cp,
 7013                                                             nfhp->nfh_fh,
 7014                                                             nfhlen);
 7015                                                         NFSCL_DEBUG(4,
 7016                                                             "got fh\n");
 7017                                                 }
 7018                                         }
 7019                                         /* Now, get the ffsd_user/ffds_group. */
 7020                                         error = nfsrv_parseug(nd, 0, &user,
 7021                                             &grp, curthread);
 7022                                         NFSCL_DEBUG(4, "after parseu=%d\n",
 7023                                             error);
 7024                                         if (error == 0)
 7025                                                 error = nfsrv_parseug(nd, 1,
 7026                                                     &user, &grp, curthread);
 7027                                         NFSCL_DEBUG(4, "aft parseg=%d\n",
 7028                                             grp);
 7029                                         if (error != 0)
 7030                                                 goto nfsmout;
 7031                                         NFSCL_DEBUG(4, "user=%d group=%d\n",
 7032                                             user, grp);
 7033                                         if (l == 0) {
 7034                                                 flp->nfsfl_ffm[j].user = user;
 7035                                                 flp->nfsfl_ffm[j].group = grp;
 7036                                                 NFSCL_DEBUG(4,
 7037                                                     "usr=%d grp=%d\n", user,
 7038                                                     grp);
 7039                                         }
 7040                                 }
 7041                         }
 7042                         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 7043                         flp->nfsfl_fflags = fxdr_unsigned(uint32_t, *tl++);
 7044                         flp->nfsfl_statshint = fxdr_unsigned(uint32_t, *tl);
 7045                         NFSCL_DEBUG(4, "fflags=0x%x statshint=%d\n",
 7046                             flp->nfsfl_fflags, flp->nfsfl_statshint);
 7047                 } else {
 7048                         error = NFSERR_BADXDR;
 7049                         goto nfsmout;
 7050                 }
 7051                 if (flp->nfsfl_iomode == gotiomode) {
 7052                         /* Keep the list in increasing offset order. */
 7053                         tflp = LIST_FIRST(flhp);
 7054                         prevflp = NULL;
 7055                         while (tflp != NULL &&
 7056                             tflp->nfsfl_off < flp->nfsfl_off) {
 7057                                 prevflp = tflp;
 7058                                 tflp = LIST_NEXT(tflp, nfsfl_list);
 7059                         }
 7060                         if (prevflp == NULL)
 7061                                 LIST_INSERT_HEAD(flhp, flp, nfsfl_list);
 7062                         else
 7063                                 LIST_INSERT_AFTER(prevflp, flp,
 7064                                     nfsfl_list);
 7065                         NFSCL_DEBUG(4, "flp inserted\n");
 7066                 } else {
 7067                         printf("nfscl_layoutget(): got wrong iomode\n");
 7068                         nfscl_freeflayout(flp);
 7069                 }
 7070                 flp = NULL;
 7071         }
 7072 nfsmout:
 7073         NFSCL_DEBUG(4, "eo nfsrv_parselayoutget=%d\n", error);
 7074         if (error != 0 && flp != NULL)
 7075                 nfscl_freeflayout(flp);
 7076         return (error);
 7077 }
 7078 
 7079 /*
 7080  * Parse a user/group digit string.
 7081  */
 7082 static int
 7083 nfsrv_parseug(struct nfsrv_descript *nd, int dogrp, uid_t *uidp, gid_t *gidp,
 7084     NFSPROC_T *p)
 7085 {
 7086         uint32_t *tl;
 7087         char *cp, *str, str0[NFSV4_SMALLSTR + 1];
 7088         uint32_t len = 0;
 7089         int error = 0;
 7090 
 7091         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 7092         len = fxdr_unsigned(uint32_t, *tl);
 7093         str = NULL;
 7094         if (len > NFSV4_OPAQUELIMIT) {
 7095                 error = NFSERR_BADXDR;
 7096                 goto nfsmout;
 7097         }
 7098         NFSCL_DEBUG(4, "nfsrv_parseug: len=%d\n", len);
 7099         if (len == 0) {
 7100                 if (dogrp != 0)
 7101                         *gidp = GID_NOGROUP;
 7102                 else
 7103                         *uidp = UID_NOBODY;
 7104                 return (0);
 7105         }
 7106         if (len > NFSV4_SMALLSTR)
 7107                 str = malloc(len + 1, M_TEMP, M_WAITOK);
 7108         else
 7109                 str = str0;
 7110         NFSM_DISSECT(cp, char *, NFSM_RNDUP(len));
 7111         NFSBCOPY(cp, str, len);
 7112         str[len] = '\0';
 7113         NFSCL_DEBUG(4, "nfsrv_parseug: str=%s\n", str);
 7114         if (dogrp != 0)
 7115                 error = nfsv4_strtogid(nd, str, len, gidp, p);
 7116         else
 7117                 error = nfsv4_strtouid(nd, str, len, uidp, p);
 7118 nfsmout:
 7119         if (len > NFSV4_SMALLSTR)
 7120                 free(str, M_TEMP);
 7121         NFSCL_DEBUG(4, "eo nfsrv_parseug=%d\n", error);
 7122         return (error);
 7123 }
 7124 
 7125 /*
 7126  * Similar to nfsrpc_getlayout(), except that it uses nfsrpc_openlayget(),
 7127  * so that it does both an Open and a Layoutget.
 7128  */
 7129 static int
 7130 nfsrpc_getopenlayout(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
 7131     int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
 7132     struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
 7133     struct ucred *cred, NFSPROC_T *p)
 7134 {
 7135         struct nfscllayout *lyp;
 7136         struct nfsclflayout *flp;
 7137         struct nfsclflayouthead flh;
 7138         int error, islocked, layoutlen, recalled, retonclose, usecurstateid;
 7139         int layouttype, laystat;
 7140         nfsv4stateid_t stateid;
 7141         struct nfsclsession *tsep;
 7142 
 7143         error = 0;
 7144         if (NFSHASFLEXFILE(nmp))
 7145                 layouttype = NFSLAYOUT_FLEXFILE;
 7146         else
 7147                 layouttype = NFSLAYOUT_NFSV4_1_FILES;
 7148         /*
 7149          * If lyp is returned non-NULL, there will be a refcnt (shared lock)
 7150          * on it, iff flp != NULL or a lock (exclusive lock) on it iff
 7151          * flp == NULL.
 7152          */
 7153         lyp = nfscl_getlayout(nmp->nm_clp, newfhp, newfhlen, 0, mode, &flp,
 7154             &recalled);
 7155         NFSCL_DEBUG(4, "nfsrpc_getopenlayout nfscl_getlayout lyp=%p\n", lyp);
 7156         if (lyp == NULL)
 7157                 islocked = 0;
 7158         else if (flp != NULL)
 7159                 islocked = 1;
 7160         else
 7161                 islocked = 2;
 7162         if ((lyp == NULL || flp == NULL) && recalled == 0) {
 7163                 LIST_INIT(&flh);
 7164                 tsep = nfsmnt_mdssession(nmp);
 7165                 layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID +
 7166                     3 * NFSX_UNSIGNED);
 7167                 if (lyp == NULL)
 7168                         usecurstateid = 1;
 7169                 else {
 7170                         usecurstateid = 0;
 7171                         stateid.seqid = lyp->nfsly_stateid.seqid;
 7172                         stateid.other[0] = lyp->nfsly_stateid.other[0];
 7173                         stateid.other[1] = lyp->nfsly_stateid.other[1];
 7174                         stateid.other[2] = lyp->nfsly_stateid.other[2];
 7175                 }
 7176                 error = nfsrpc_openlayoutrpc(nmp, vp, nfhp, fhlen,
 7177                     newfhp, newfhlen, mode, op, name, namelen,
 7178                     dpp, &stateid, usecurstateid, layouttype, layoutlen,
 7179                     &retonclose, &flh, &laystat, cred, p);
 7180                 NFSCL_DEBUG(4, "aft nfsrpc_openlayoutrpc laystat=%d err=%d\n",
 7181                     laystat, error);
 7182                 laystat = nfsrpc_layoutgetres(nmp, vp, newfhp, newfhlen,
 7183                     &stateid, retonclose, NULL, &lyp, &flh, layouttype, laystat,
 7184                     &islocked, cred, p);
 7185         } else
 7186                 error = nfsrpc_openrpc(nmp, vp, nfhp, fhlen, newfhp, newfhlen,
 7187                     mode, op, name, namelen, dpp, 0, 0, cred, p, 0, 0);
 7188         if (islocked == 2)
 7189                 nfscl_rellayout(lyp, 1);
 7190         else if (islocked == 1)
 7191                 nfscl_rellayout(lyp, 0);
 7192         return (error);
 7193 }
 7194 
 7195 /*
 7196  * This function does an Open+LayoutGet for an NFSv4.1 mount with pNFS
 7197  * enabled, only for the CLAIM_NULL case.  All other NFSv4 Opens are
 7198  * handled by nfsrpc_openrpc().
 7199  * For the case where op == NULL, dvp is the directory.  When op != NULL, it
 7200  * can be NULL.
 7201  */
 7202 static int
 7203 nfsrpc_openlayoutrpc(struct nfsmount *nmp, vnode_t vp, u_int8_t *nfhp,
 7204     int fhlen, uint8_t *newfhp, int newfhlen, uint32_t mode,
 7205     struct nfsclopen *op, uint8_t *name, int namelen, struct nfscldeleg **dpp,
 7206     nfsv4stateid_t *stateidp, int usecurstateid, int layouttype,
 7207     int layoutlen, int *retonclosep, struct nfsclflayouthead *flhp,
 7208     int *laystatp, struct ucred *cred, NFSPROC_T *p)
 7209 {
 7210         uint32_t *tl;
 7211         struct nfsrv_descript nfsd, *nd = &nfsd;
 7212         struct nfscldeleg *ndp = NULL;
 7213         struct nfsvattr nfsva;
 7214         struct nfsclsession *tsep;
 7215         uint32_t rflags, deleg;
 7216         nfsattrbit_t attrbits;
 7217         int error, ret, acesize, limitby, iomode;
 7218 
 7219         *dpp = NULL;
 7220         *laystatp = ENXIO;
 7221         nfscl_reqstart(nd, NFSPROC_OPENLAYGET, nmp, nfhp, fhlen, NULL, NULL,
 7222             0, 0);
 7223         NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
 7224         *tl++ = txdr_unsigned(op->nfso_own->nfsow_seqid);
 7225         *tl++ = txdr_unsigned(mode & NFSV4OPEN_ACCESSBOTH);
 7226         *tl++ = txdr_unsigned((mode >> NFSLCK_SHIFT) & NFSV4OPEN_DENYBOTH);
 7227         tsep = nfsmnt_mdssession(nmp);
 7228         *tl++ = tsep->nfsess_clientid.lval[0];
 7229         *tl = tsep->nfsess_clientid.lval[1];
 7230         nfsm_strtom(nd, op->nfso_own->nfsow_owner, NFSV4CL_LOCKNAMELEN);
 7231         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 7232         *tl++ = txdr_unsigned(NFSV4OPEN_NOCREATE);
 7233         *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
 7234         nfsm_strtom(nd, name, namelen);
 7235         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 7236         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 7237         NFSZERO_ATTRBIT(&attrbits);
 7238         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_CHANGE);
 7239         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFY);
 7240         nfsrv_putattrbit(nd, &attrbits);
 7241         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 7242         *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
 7243         if ((mode & NFSV4OPEN_ACCESSWRITE) != 0)
 7244                 iomode = NFSLAYOUTIOMODE_RW;
 7245         else
 7246                 iomode = NFSLAYOUTIOMODE_READ;
 7247         nfsrv_setuplayoutget(nd, iomode, 0, UINT64_MAX, 0, stateidp,
 7248             layouttype, layoutlen, usecurstateid);
 7249         error = newnfs_request(nd, nmp, NULL, &nmp->nm_sockreq, vp, p, cred,
 7250             NFS_PROG, NFS_VER4, NULL, 1, NULL, NULL);
 7251         if (error != 0)
 7252                 return (error);
 7253         NFSCL_INCRSEQID(op->nfso_own->nfsow_seqid, nd);
 7254         if (nd->nd_repstat != 0)
 7255                 *laystatp = nd->nd_repstat;
 7256         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
 7257                 /* ND_NOMOREDATA will be set if the Open operation failed. */
 7258                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
 7259                     6 * NFSX_UNSIGNED);
 7260                 op->nfso_stateid.seqid = *tl++;
 7261                 op->nfso_stateid.other[0] = *tl++;
 7262                 op->nfso_stateid.other[1] = *tl++;
 7263                 op->nfso_stateid.other[2] = *tl;
 7264                 rflags = fxdr_unsigned(u_int32_t, *(tl + 6));
 7265                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 7266                 if (error != 0)
 7267                         goto nfsmout;
 7268                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 7269                 deleg = fxdr_unsigned(u_int32_t, *tl);
 7270                 if (deleg == NFSV4OPEN_DELEGATEREAD ||
 7271                     deleg == NFSV4OPEN_DELEGATEWRITE) {
 7272                         if (!(op->nfso_own->nfsow_clp->nfsc_flags &
 7273                               NFSCLFLAGS_FIRSTDELEG))
 7274                                 op->nfso_own->nfsow_clp->nfsc_flags |=
 7275                                   (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
 7276                         ndp = malloc(sizeof(struct nfscldeleg) + newfhlen,
 7277                             M_NFSCLDELEG, M_WAITOK);
 7278                         LIST_INIT(&ndp->nfsdl_owner);
 7279                         LIST_INIT(&ndp->nfsdl_lock);
 7280                         ndp->nfsdl_clp = op->nfso_own->nfsow_clp;
 7281                         ndp->nfsdl_fhlen = newfhlen;
 7282                         NFSBCOPY(newfhp, ndp->nfsdl_fh, newfhlen);
 7283                         newnfs_copyincred(cred, &ndp->nfsdl_cred);
 7284                         nfscl_lockinit(&ndp->nfsdl_rwlock);
 7285                         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
 7286                             NFSX_UNSIGNED);
 7287                         ndp->nfsdl_stateid.seqid = *tl++;
 7288                         ndp->nfsdl_stateid.other[0] = *tl++;
 7289                         ndp->nfsdl_stateid.other[1] = *tl++;
 7290                         ndp->nfsdl_stateid.other[2] = *tl++;
 7291                         ret = fxdr_unsigned(int, *tl);
 7292                         if (deleg == NFSV4OPEN_DELEGATEWRITE) {
 7293                                 ndp->nfsdl_flags = NFSCLDL_WRITE;
 7294                                 /*
 7295                                  * Indicates how much the file can grow.
 7296                                  */
 7297                                 NFSM_DISSECT(tl, u_int32_t *,
 7298                                     3 * NFSX_UNSIGNED);
 7299                                 limitby = fxdr_unsigned(int, *tl++);
 7300                                 switch (limitby) {
 7301                                 case NFSV4OPEN_LIMITSIZE:
 7302                                         ndp->nfsdl_sizelimit = fxdr_hyper(tl);
 7303                                         break;
 7304                                 case NFSV4OPEN_LIMITBLOCKS:
 7305                                         ndp->nfsdl_sizelimit =
 7306                                             fxdr_unsigned(u_int64_t, *tl++);
 7307                                         ndp->nfsdl_sizelimit *=
 7308                                             fxdr_unsigned(u_int64_t, *tl);
 7309                                         break;
 7310                                 default:
 7311                                         error = NFSERR_BADXDR;
 7312                                         goto nfsmout;
 7313                                 };
 7314                         } else
 7315                                 ndp->nfsdl_flags = NFSCLDL_READ;
 7316                         if (ret != 0)
 7317                                 ndp->nfsdl_flags |= NFSCLDL_RECALL;
 7318                         error = nfsrv_dissectace(nd, &ndp->nfsdl_ace, &ret,
 7319                             &acesize, p);
 7320                         if (error != 0)
 7321                                 goto nfsmout;
 7322                 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
 7323                         error = NFSERR_BADXDR;
 7324                         goto nfsmout;
 7325                 }
 7326                 if ((rflags & NFSV4OPEN_LOCKTYPEPOSIX) != 0 ||
 7327                     nfscl_assumeposixlocks)
 7328                         op->nfso_posixlock = 1;
 7329                 else
 7330                         op->nfso_posixlock = 0;
 7331                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 7332                 /* If the 2nd element == NFS_OK, the Getattr succeeded. */
 7333                 if (*++tl == 0) {
 7334                         error = nfsv4_loadattr(nd, NULL, &nfsva, NULL,
 7335                             NULL, 0, NULL, NULL, NULL, NULL, NULL, 0,
 7336                             NULL, NULL, NULL, p, cred);
 7337                         if (error != 0)
 7338                                 goto nfsmout;
 7339                         if (ndp != NULL) {
 7340                                 ndp->nfsdl_change = nfsva.na_filerev;
 7341                                 ndp->nfsdl_modtime = nfsva.na_mtime;
 7342                                 ndp->nfsdl_flags |= NFSCLDL_MODTIMESET;
 7343                                 *dpp = ndp;
 7344                                 ndp = NULL;
 7345                         }
 7346                         /*
 7347                          * At this point, the Open has succeeded, so set
 7348                          * nd_repstat = NFS_OK.  If the Layoutget failed,
 7349                          * this function just won't return a layout.
 7350                          */
 7351                         if (nd->nd_repstat == 0) {
 7352                                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 7353                                 *laystatp = fxdr_unsigned(int, *++tl);
 7354                                 if (*laystatp == 0) {
 7355                                         error = nfsrv_parselayoutget(nd,
 7356                                             stateidp, retonclosep, flhp);
 7357                                         if (error != 0)
 7358                                                 *laystatp = error;
 7359                                 }
 7360                         } else
 7361                                 nd->nd_repstat = 0;     /* Return 0 for Open. */
 7362                 }
 7363         }
 7364         if (nd->nd_repstat != 0 && error == 0)
 7365                 error = nd->nd_repstat;
 7366 nfsmout:
 7367         free(ndp, M_NFSCLDELEG);
 7368         mbuf_freem(nd->nd_mrep);
 7369         return (error);
 7370 }
 7371 
 7372 /*
 7373  * Similar nfsrpc_createv4(), but also does the LayoutGet operation.
 7374  * Used only for mounts with pNFS enabled.
 7375  */
 7376 static int
 7377 nfsrpc_createlayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 7378     nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
 7379     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 7380     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
 7381     int *dattrflagp, void *dstuff, int *unlockedp, nfsv4stateid_t *stateidp,
 7382     int usecurstateid, int layouttype, int layoutlen, int *retonclosep,
 7383     struct nfsclflayouthead *flhp, int *laystatp)
 7384 {
 7385         uint32_t *tl;
 7386         int error = 0, deleg, newone, ret, acesize, limitby;
 7387         struct nfsrv_descript nfsd, *nd = &nfsd;
 7388         struct nfsclopen *op;
 7389         struct nfscldeleg *dp = NULL;
 7390         struct nfsnode *np;
 7391         struct nfsfh *nfhp;
 7392         struct nfsclsession *tsep;
 7393         nfsattrbit_t attrbits;
 7394         nfsv4stateid_t stateid;
 7395         struct nfsmount *nmp;
 7396 
 7397         nmp = VFSTONFS(dvp->v_mount);
 7398         np = VTONFS(dvp);
 7399         *laystatp = ENXIO;
 7400         *unlockedp = 0;
 7401         *nfhpp = NULL;
 7402         *dpp = NULL;
 7403         *attrflagp = 0;
 7404         *dattrflagp = 0;
 7405         if (namelen > NFS_MAXNAMLEN)
 7406                 return (ENAMETOOLONG);
 7407         NFSCL_REQSTART(nd, NFSPROC_CREATELAYGET, dvp);
 7408         /*
 7409          * For V4, this is actually an Open op.
 7410          */
 7411         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 7412         *tl++ = txdr_unsigned(owp->nfsow_seqid);
 7413         *tl++ = txdr_unsigned(NFSV4OPEN_ACCESSWRITE |
 7414             NFSV4OPEN_ACCESSREAD);
 7415         *tl++ = txdr_unsigned(NFSV4OPEN_DENYNONE);
 7416         tsep = nfsmnt_mdssession(nmp);
 7417         *tl++ = tsep->nfsess_clientid.lval[0];
 7418         *tl = tsep->nfsess_clientid.lval[1];
 7419         nfsm_strtom(nd, owp->nfsow_owner, NFSV4CL_LOCKNAMELEN);
 7420         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 7421         *tl++ = txdr_unsigned(NFSV4OPEN_CREATE);
 7422         if ((fmode & O_EXCL) != 0) {
 7423                 if (NFSHASSESSPERSIST(nmp)) {
 7424                         /* Use GUARDED for persistent sessions. */
 7425                         *tl = txdr_unsigned(NFSCREATE_GUARDED);
 7426                         nfscl_fillsattr(nd, vap, dvp, 0, 0);
 7427                 } else {
 7428                         /* Otherwise, use EXCLUSIVE4_1. */
 7429                         *tl = txdr_unsigned(NFSCREATE_EXCLUSIVE41);
 7430                         NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 7431                         *tl++ = cverf.lval[0];
 7432                         *tl = cverf.lval[1];
 7433                         nfscl_fillsattr(nd, vap, dvp, 0, 0);
 7434                 }
 7435         } else {
 7436                 *tl = txdr_unsigned(NFSCREATE_UNCHECKED);
 7437                 nfscl_fillsattr(nd, vap, dvp, 0, 0);
 7438         }
 7439         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 7440         *tl = txdr_unsigned(NFSV4OPEN_CLAIMNULL);
 7441         nfsm_strtom(nd, name, namelen);
 7442         /* Get the new file's handle and attributes, plus save the FH. */
 7443         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 7444         *tl++ = txdr_unsigned(NFSV4OP_SAVEFH);
 7445         *tl++ = txdr_unsigned(NFSV4OP_GETFH);
 7446         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 7447         NFSGETATTR_ATTRBIT(&attrbits);
 7448         nfsrv_putattrbit(nd, &attrbits);
 7449         /* Get the directory's post-op attributes. */
 7450         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 7451         *tl = txdr_unsigned(NFSV4OP_PUTFH);
 7452         nfsm_fhtom(nd, np->n_fhp->nfh_fh, np->n_fhp->nfh_len, 0);
 7453         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 7454         *tl = txdr_unsigned(NFSV4OP_GETATTR);
 7455         nfsrv_putattrbit(nd, &attrbits);
 7456         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 7457         *tl++ = txdr_unsigned(NFSV4OP_RESTOREFH);
 7458         *tl = txdr_unsigned(NFSV4OP_LAYOUTGET);
 7459         nfsrv_setuplayoutget(nd, NFSLAYOUTIOMODE_RW, 0, UINT64_MAX, 0, stateidp,
 7460             layouttype, layoutlen, usecurstateid);
 7461         error = nfscl_request(nd, dvp, p, cred, dstuff);
 7462         if (error != 0)
 7463                 return (error);
 7464         NFSCL_DEBUG(4, "nfsrpc_createlayout stat=%d err=%d\n", nd->nd_repstat,
 7465             error);
 7466         if (nd->nd_repstat != 0)
 7467                 *laystatp = nd->nd_repstat;
 7468         NFSCL_INCRSEQID(owp->nfsow_seqid, nd);
 7469         if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
 7470                 NFSCL_DEBUG(4, "nfsrpc_createlayout open succeeded\n");
 7471                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
 7472                     6 * NFSX_UNSIGNED);
 7473                 stateid.seqid = *tl++;
 7474                 stateid.other[0] = *tl++;
 7475                 stateid.other[1] = *tl++;
 7476                 stateid.other[2] = *tl;
 7477                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
 7478                 if (error != 0)
 7479                         goto nfsmout;
 7480                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 7481                 deleg = fxdr_unsigned(int, *tl);
 7482                 if (deleg == NFSV4OPEN_DELEGATEREAD ||
 7483                     deleg == NFSV4OPEN_DELEGATEWRITE) {
 7484                         if (!(owp->nfsow_clp->nfsc_flags &
 7485                               NFSCLFLAGS_FIRSTDELEG))
 7486                                 owp->nfsow_clp->nfsc_flags |=
 7487                                   (NFSCLFLAGS_FIRSTDELEG | NFSCLFLAGS_GOTDELEG);
 7488                         dp = malloc(sizeof(struct nfscldeleg) + NFSX_V4FHMAX,
 7489                             M_NFSCLDELEG, M_WAITOK);
 7490                         LIST_INIT(&dp->nfsdl_owner);
 7491                         LIST_INIT(&dp->nfsdl_lock);
 7492                         dp->nfsdl_clp = owp->nfsow_clp;
 7493                         newnfs_copyincred(cred, &dp->nfsdl_cred);
 7494                         nfscl_lockinit(&dp->nfsdl_rwlock);
 7495                         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID +
 7496                             NFSX_UNSIGNED);
 7497                         dp->nfsdl_stateid.seqid = *tl++;
 7498                         dp->nfsdl_stateid.other[0] = *tl++;
 7499                         dp->nfsdl_stateid.other[1] = *tl++;
 7500                         dp->nfsdl_stateid.other[2] = *tl++;
 7501                         ret = fxdr_unsigned(int, *tl);
 7502                         if (deleg == NFSV4OPEN_DELEGATEWRITE) {
 7503                                 dp->nfsdl_flags = NFSCLDL_WRITE;
 7504                                 /*
 7505                                  * Indicates how much the file can grow.
 7506                                  */
 7507                                 NFSM_DISSECT(tl, u_int32_t *,
 7508                                     3 * NFSX_UNSIGNED);
 7509                                 limitby = fxdr_unsigned(int, *tl++);
 7510                                 switch (limitby) {
 7511                                 case NFSV4OPEN_LIMITSIZE:
 7512                                         dp->nfsdl_sizelimit = fxdr_hyper(tl);
 7513                                         break;
 7514                                 case NFSV4OPEN_LIMITBLOCKS:
 7515                                         dp->nfsdl_sizelimit =
 7516                                             fxdr_unsigned(u_int64_t, *tl++);
 7517                                         dp->nfsdl_sizelimit *=
 7518                                             fxdr_unsigned(u_int64_t, *tl);
 7519                                         break;
 7520                                 default:
 7521                                         error = NFSERR_BADXDR;
 7522                                         goto nfsmout;
 7523                                 };
 7524                         } else {
 7525                                 dp->nfsdl_flags = NFSCLDL_READ;
 7526                         }
 7527                         if (ret != 0)
 7528                                 dp->nfsdl_flags |= NFSCLDL_RECALL;
 7529                         error = nfsrv_dissectace(nd, &dp->nfsdl_ace, &ret,
 7530                             &acesize, p);
 7531                         if (error != 0)
 7532                                 goto nfsmout;
 7533                 } else if (deleg != NFSV4OPEN_DELEGATENONE) {
 7534                         error = NFSERR_BADXDR;
 7535                         goto nfsmout;
 7536                 }
 7537 
 7538                 /* Now, we should have the status for the SaveFH. */
 7539                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 7540                 if (*++tl == 0) {
 7541                         NFSCL_DEBUG(4, "nfsrpc_createlayout SaveFH ok\n");
 7542                         /*
 7543                          * Now, process the GetFH and Getattr for the newly
 7544                          * created file. nfscl_mtofh() will set
 7545                          * ND_NOMOREDATA if these weren't successful.
 7546                          */
 7547                         error = nfscl_mtofh(nd, nfhpp, nnap, attrflagp);
 7548                         NFSCL_DEBUG(4, "aft nfscl_mtofh err=%d\n", error);
 7549                         if (error != 0)
 7550                                 goto nfsmout;
 7551                 } else
 7552                         nd->nd_flag |= ND_NOMOREDATA;
 7553                 /* Now we have the PutFH and Getattr for the directory. */
 7554                 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
 7555                         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 7556                         if (*++tl != 0)
 7557                                 nd->nd_flag |= ND_NOMOREDATA;
 7558                         else {
 7559                                 NFSM_DISSECT(tl, uint32_t *, 2 *
 7560                                     NFSX_UNSIGNED);
 7561                                 if (*++tl != 0)
 7562                                         nd->nd_flag |= ND_NOMOREDATA;
 7563                         }
 7564                 }
 7565                 if ((nd->nd_flag & ND_NOMOREDATA) == 0) {
 7566                         /* Load the directory attributes. */
 7567                         error = nfsm_loadattr(nd, dnap);
 7568                         NFSCL_DEBUG(4, "aft nfsm_loadattr err=%d\n", error);
 7569                         if (error != 0)
 7570                                 goto nfsmout;
 7571                         *dattrflagp = 1;
 7572                         if (dp != NULL && *attrflagp != 0) {
 7573                                 dp->nfsdl_change = nnap->na_filerev;
 7574                                 dp->nfsdl_modtime = nnap->na_mtime;
 7575                                 dp->nfsdl_flags |= NFSCLDL_MODTIMESET;
 7576                         }
 7577                         /*
 7578                          * We can now complete the Open state.
 7579                          */
 7580                         nfhp = *nfhpp;
 7581                         if (dp != NULL) {
 7582                                 dp->nfsdl_fhlen = nfhp->nfh_len;
 7583                                 NFSBCOPY(nfhp->nfh_fh, dp->nfsdl_fh,
 7584                                     nfhp->nfh_len);
 7585                         }
 7586                         /*
 7587                          * Get an Open structure that will be
 7588                          * attached to the OpenOwner, acquired already.
 7589                          */
 7590                         error = nfscl_open(dvp, nfhp->nfh_fh, nfhp->nfh_len, 
 7591                             (NFSV4OPEN_ACCESSWRITE | NFSV4OPEN_ACCESSREAD), 0,
 7592                             cred, p, NULL, &op, &newone, NULL, 0, false);
 7593                         if (error != 0)
 7594                                 goto nfsmout;
 7595                         op->nfso_stateid = stateid;
 7596                         newnfs_copyincred(cred, &op->nfso_cred);
 7597         
 7598                         nfscl_openrelease(nmp, op, error, newone);
 7599                         *unlockedp = 1;
 7600 
 7601                         /* Now, handle the RestoreFH and LayoutGet. */
 7602                         if (nd->nd_repstat == 0) {
 7603                                 NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
 7604                                 *laystatp = fxdr_unsigned(int, *(tl + 3));
 7605                                 if (*laystatp == 0) {
 7606                                         error = nfsrv_parselayoutget(nd,
 7607                                             stateidp, retonclosep, flhp);
 7608                                         if (error != 0)
 7609                                                 *laystatp = error;
 7610                                 }
 7611                                 NFSCL_DEBUG(4, "aft nfsrv_parselayout err=%d\n",
 7612                                     error);
 7613                         } else
 7614                                 nd->nd_repstat = 0;
 7615                 }
 7616         }
 7617         if (nd->nd_repstat != 0 && error == 0)
 7618                 error = nd->nd_repstat;
 7619         if (error == NFSERR_STALECLIENTID)
 7620                 nfscl_initiate_recovery(owp->nfsow_clp);
 7621 nfsmout:
 7622         NFSCL_DEBUG(4, "eo nfsrpc_createlayout err=%d\n", error);
 7623         if (error == 0)
 7624                 *dpp = dp;
 7625         else
 7626                 free(dp, M_NFSCLDELEG);
 7627         mbuf_freem(nd->nd_mrep);
 7628         return (error);
 7629 }
 7630 
 7631 /*
 7632  * Similar to nfsrpc_getopenlayout(), except that it used for the Create case.
 7633  */
 7634 static int
 7635 nfsrpc_getcreatelayout(vnode_t dvp, char *name, int namelen, struct vattr *vap,
 7636     nfsquad_t cverf, int fmode, struct nfsclowner *owp, struct nfscldeleg **dpp,
 7637     struct ucred *cred, NFSPROC_T *p, struct nfsvattr *dnap,
 7638     struct nfsvattr *nnap, struct nfsfh **nfhpp, int *attrflagp,
 7639     int *dattrflagp, void *dstuff, int *unlockedp)
 7640 {
 7641         struct nfscllayout *lyp;
 7642         struct nfsclflayouthead flh;
 7643         struct nfsfh *nfhp;
 7644         struct nfsclsession *tsep;
 7645         struct nfsmount *nmp;
 7646         nfsv4stateid_t stateid;
 7647         int error, layoutlen, layouttype, retonclose, laystat;
 7648 
 7649         error = 0;
 7650         nmp = VFSTONFS(dvp->v_mount);
 7651         if (NFSHASFLEXFILE(nmp))
 7652                 layouttype = NFSLAYOUT_FLEXFILE;
 7653         else
 7654                 layouttype = NFSLAYOUT_NFSV4_1_FILES;
 7655         LIST_INIT(&flh);
 7656         tsep = nfsmnt_mdssession(nmp);
 7657         layoutlen = tsep->nfsess_maxcache - (NFSX_STATEID + 3 * NFSX_UNSIGNED);
 7658         error = nfsrpc_createlayout(dvp, name, namelen, vap, cverf, fmode,
 7659             owp, dpp, cred, p, dnap, nnap, nfhpp, attrflagp, dattrflagp,
 7660             dstuff, unlockedp, &stateid, 1, layouttype, layoutlen, &retonclose,
 7661             &flh, &laystat);
 7662         NFSCL_DEBUG(4, "aft nfsrpc_createlayoutrpc laystat=%d err=%d\n",
 7663             laystat, error);
 7664         lyp = NULL;
 7665         if (laystat == 0) {
 7666                 nfhp = *nfhpp;
 7667                 laystat = nfsrpc_layoutgetres(nmp, dvp, nfhp->nfh_fh,
 7668                     nfhp->nfh_len, &stateid, retonclose, NULL, &lyp, &flh,
 7669                     layouttype, laystat, NULL, cred, p);
 7670         } else
 7671                 laystat = nfsrpc_layoutgetres(nmp, dvp, NULL, 0, &stateid,
 7672                     retonclose, NULL, &lyp, &flh, layouttype, laystat, NULL,
 7673                     cred, p);
 7674         if (laystat == 0)
 7675                 nfscl_rellayout(lyp, 0);
 7676         return (error);
 7677 }
 7678 
 7679 /*
 7680  * Process the results of a layoutget() operation.
 7681  */
 7682 static int
 7683 nfsrpc_layoutgetres(struct nfsmount *nmp, vnode_t vp, uint8_t *newfhp,
 7684     int newfhlen, nfsv4stateid_t *stateidp, int retonclose, uint32_t *notifybit,
 7685     struct nfscllayout **lypp, struct nfsclflayouthead *flhp, int layouttype,
 7686     int laystat, int *islockedp, struct ucred *cred, NFSPROC_T *p)
 7687 {
 7688         struct nfsclflayout *tflp;
 7689         struct nfscldevinfo *dip;
 7690         uint8_t *dev;
 7691         int i, mirrorcnt;
 7692 
 7693         if (laystat == NFSERR_UNKNLAYOUTTYPE) {
 7694                 NFSLOCKMNT(nmp);
 7695                 if (!NFSHASFLEXFILE(nmp)) {
 7696                         /* Switch to using Flex File Layout. */
 7697                         nmp->nm_state |= NFSSTA_FLEXFILE;
 7698                 } else if (layouttype == NFSLAYOUT_FLEXFILE) {
 7699                         /* Disable pNFS. */
 7700                         NFSCL_DEBUG(1, "disable PNFS\n");
 7701                         nmp->nm_state &= ~(NFSSTA_PNFS | NFSSTA_FLEXFILE);
 7702                 }
 7703                 NFSUNLOCKMNT(nmp);
 7704         }
 7705         if (laystat == 0) {
 7706                 NFSCL_DEBUG(4, "nfsrpc_layoutgetres at FOREACH\n");
 7707                 LIST_FOREACH(tflp, flhp, nfsfl_list) {
 7708                         if (layouttype == NFSLAYOUT_FLEXFILE)
 7709                                 mirrorcnt = tflp->nfsfl_mirrorcnt;
 7710                         else
 7711                                 mirrorcnt = 1;
 7712                         for (i = 0; i < mirrorcnt; i++) {
 7713                                 laystat = nfscl_adddevinfo(nmp, NULL, i, tflp);
 7714                                 NFSCL_DEBUG(4, "aft adddev=%d\n", laystat);
 7715                                 if (laystat != 0) {
 7716                                         if (layouttype == NFSLAYOUT_FLEXFILE)
 7717                                                 dev = tflp->nfsfl_ffm[i].dev;
 7718                                         else
 7719                                                 dev = tflp->nfsfl_dev;
 7720                                         laystat = nfsrpc_getdeviceinfo(nmp, dev,
 7721                                             layouttype, notifybit, &dip, cred,
 7722                                             p);
 7723                                         NFSCL_DEBUG(4, "aft nfsrpc_gdi=%d\n",
 7724                                             laystat);
 7725                                         if (laystat != 0)
 7726                                                 goto out;
 7727                                         laystat = nfscl_adddevinfo(nmp, dip, i,
 7728                                             tflp);
 7729                                         if (laystat != 0)
 7730                                                 printf("nfsrpc_layoutgetresout"
 7731                                                     ": cannot add\n");
 7732                                 }
 7733                         }
 7734                 }
 7735         }
 7736 out:
 7737         if (laystat == 0) {
 7738                 /*
 7739                  * nfscl_layout() always returns with the nfsly_lock
 7740                  * set to a refcnt (shared lock).
 7741                  * Passing in dvp is sufficient, since it is only used to
 7742                  * get the fsid for the file system.
 7743                  */
 7744                 laystat = nfscl_layout(nmp, vp, newfhp, newfhlen, stateidp,
 7745                     layouttype, retonclose, flhp, lypp, cred, p);
 7746                 NFSCL_DEBUG(4, "nfsrpc_layoutgetres: aft nfscl_layout=%d\n",
 7747                     laystat);
 7748                 if (laystat == 0 && islockedp != NULL)
 7749                         *islockedp = 1;
 7750         }
 7751         return (laystat);
 7752 }
 7753 
 7754 /*
 7755  * Do the NFSv4.1 Bind Connection to Session.
 7756  * Called from the reconnect layer of the krpc (sys/rpc/clnt_rc.c).
 7757  */
 7758 void
 7759 nfsrpc_bindconnsess(CLIENT *cl, void *arg, struct ucred *cr)
 7760 {
 7761         struct nfscl_reconarg *rcp = (struct nfscl_reconarg *)arg;
 7762         uint32_t res, *tl;
 7763         struct nfsrv_descript nfsd;
 7764         struct nfsrv_descript *nd = &nfsd;
 7765         struct rpc_callextra ext;
 7766         struct timeval utimeout;
 7767         enum clnt_stat stat;
 7768         int error;
 7769 
 7770         nfscl_reqstart(nd, NFSPROC_BINDCONNTOSESS, NULL, NULL, 0, NULL, NULL,
 7771             NFS_VER4, rcp->minorvers);
 7772         NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
 7773         memcpy(tl, rcp->sessionid, NFSX_V4SESSIONID);
 7774         tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
 7775         *tl++ = txdr_unsigned(NFSCDFC4_FORE_OR_BOTH);
 7776         *tl = newnfs_false;
 7777 
 7778         memset(&ext, 0, sizeof(ext));
 7779         utimeout.tv_sec = 30;
 7780         utimeout.tv_usec = 0;
 7781         ext.rc_auth = authunix_create(cr);
 7782         nd->nd_mrep = NULL;
 7783         stat = CLNT_CALL_MBUF(cl, &ext, NFSV4PROC_COMPOUND, nd->nd_mreq,
 7784             &nd->nd_mrep, utimeout);
 7785         AUTH_DESTROY(ext.rc_auth);
 7786         if (stat != RPC_SUCCESS) {
 7787                 printf("nfsrpc_bindconnsess: call failed stat=%d\n", stat);
 7788                 return;
 7789         }
 7790         if (nd->nd_mrep == NULL) {
 7791                 printf("nfsrpc_bindconnsess: no reply args\n");
 7792                 return;
 7793         }
 7794         error = 0;
 7795         newnfs_realign(&nd->nd_mrep, M_WAITOK);
 7796         nd->nd_md = nd->nd_mrep;
 7797         nd->nd_dpos = mtod(nd->nd_md, char *);
 7798         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 7799         nd->nd_repstat = fxdr_unsigned(uint32_t, *tl++);
 7800         if (nd->nd_repstat == NFSERR_OK) {
 7801                 res = fxdr_unsigned(uint32_t, *tl);
 7802                 if (res > 0 && (error = nfsm_advance(nd, NFSM_RNDUP(res),
 7803                     -1)) != 0)
 7804                         goto nfsmout;
 7805                 NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID +
 7806                     4 * NFSX_UNSIGNED);
 7807                 tl += 3;
 7808                 if (!NFSBCMP(tl, rcp->sessionid, NFSX_V4SESSIONID)) {
 7809                         tl += NFSX_V4SESSIONID / NFSX_UNSIGNED;
 7810                         res = fxdr_unsigned(uint32_t, *tl);
 7811                         if (res != NFSCDFS4_BOTH)
 7812                                 printf("nfsrpc_bindconnsess: did not "
 7813                                     "return FS4_BOTH\n");
 7814                 } else
 7815                         printf("nfsrpc_bindconnsess: not same "
 7816                             "sessionid\n");
 7817         } else if (nd->nd_repstat != NFSERR_BADSESSION)
 7818                 printf("nfsrpc_bindconnsess: returned %d\n", nd->nd_repstat);
 7819 nfsmout:
 7820         if (error != 0)
 7821                 printf("nfsrpc_bindconnsess: reply bad xdr\n");
 7822         m_freem(nd->nd_mrep);
 7823 }

Cache object: e3c7dedd7afacc14c8d0da99aeaf17d4


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