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)