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

Cache object: 51d80e8f21cc81ba87c804af69afcf4a


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