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


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

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

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

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

Cache object: 1e850c471d7987a548b1ca6d02ec2059


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