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

Cache object: 48474d18ead98622a208cc2de1aafd8a


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