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/nfsserver/nfs_nfsdserv.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 #include "opt_inet.h"
   40 #include "opt_inet6.h"
   41 /*
   42  * nfs version 2, 3 and 4 server calls to vnode ops
   43  * - these routines generally have 3 phases
   44  *   1 - break down and validate rpc request in mbuf list
   45  *   2 - do the vnode ops for the request, usually by calling a nfsvno_XXX()
   46  *       function in nfsd_port.c
   47  *   3 - build the rpc reply in an mbuf list
   48  * For nfsv4, these functions are called for each Op within the Compound RPC.
   49  */
   50 
   51 #include <fs/nfs/nfsport.h>
   52 #include <sys/extattr.h>
   53 #include <sys/filio.h>
   54 
   55 /* Global vars */
   56 extern u_int32_t newnfs_false, newnfs_true;
   57 extern enum vtype nv34tov_type[8];
   58 extern struct timeval nfsboottime;
   59 extern int nfsrv_enable_crossmntpt;
   60 extern int nfsrv_statehashsize;
   61 extern int nfsrv_layouthashsize;
   62 extern time_t nfsdev_time;
   63 extern volatile int nfsrv_devidcnt;
   64 extern int nfsd_debuglevel;
   65 extern u_long sb_max_adj;
   66 extern int nfsrv_pnfsatime;
   67 extern int nfsrv_maxpnfsmirror;
   68 extern uint32_t nfs_srvmaxio;
   69 
   70 static int      nfs_async = 0;
   71 SYSCTL_DECL(_vfs_nfsd);
   72 SYSCTL_INT(_vfs_nfsd, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
   73     "Tell client that writes were synced even though they were not");
   74 extern int      nfsrv_doflexfile;
   75 SYSCTL_INT(_vfs_nfsd, OID_AUTO, default_flexfile, CTLFLAG_RW,
   76     &nfsrv_doflexfile, 0, "Make Flex File Layout the default for pNFS");
   77 static int      nfsrv_linux42server = 1;
   78 SYSCTL_INT(_vfs_nfsd, OID_AUTO, linux42server, CTLFLAG_RW,
   79     &nfsrv_linux42server, 0,
   80     "Enable Linux style NFSv4.2 server (non-RFC compliant)");
   81 static bool     nfsrv_openaccess = true;
   82 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, v4openaccess, CTLFLAG_RW,
   83     &nfsrv_openaccess, 0,
   84     "Enable Linux style NFSv4 Open access check");
   85 static char nfsrv_scope[NFSV4_OPAQUELIMIT];
   86 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, scope, CTLFLAG_RWTUN,
   87     &nfsrv_scope, NFSV4_OPAQUELIMIT, "Server scope");
   88 static char nfsrv_owner_major[NFSV4_OPAQUELIMIT];
   89 SYSCTL_STRING(_vfs_nfsd, OID_AUTO, owner_major, CTLFLAG_RWTUN,
   90     &nfsrv_owner_major, NFSV4_OPAQUELIMIT, "Server owner major");
   91 static uint64_t nfsrv_owner_minor;
   92 SYSCTL_U64(_vfs_nfsd, OID_AUTO, owner_minor, CTLFLAG_RWTUN,
   93     &nfsrv_owner_minor, 0, "Server owner minor");
   94 /*
   95  * Only enable this if all your exported file systems
   96  * (or pNFS DSs for the pNFS case) support VOP_ALLOCATE.
   97  */
   98 static bool     nfsrv_doallocate = false;
   99 SYSCTL_BOOL(_vfs_nfsd, OID_AUTO, enable_v42allocate, CTLFLAG_RW,
  100     &nfsrv_doallocate, 0,
  101     "Enable NFSv4.2 Allocate operation");
  102 
  103 /*
  104  * This list defines the GSS mechanisms supported.
  105  * (Don't ask me how you get these strings from the RFC stuff like
  106  *  iso(1), org(3)... but someone did it, so I don't need to know.)
  107  */
  108 static struct nfsgss_mechlist nfsgss_mechlist[] = {
  109         { 9, "\052\206\110\206\367\022\001\002\002", 11 },
  110         { 0, "", 0 },
  111 };
  112 
  113 /* local functions */
  114 static void nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
  115     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
  116     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
  117     int *diraft_retp, nfsattrbit_t *attrbitp,
  118     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
  119     int pathlen);
  120 static void nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
  121     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
  122     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
  123     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
  124     NFSPROC_T *p, struct nfsexstuff *exp);
  125 
  126 /*
  127  * nfs access service (not a part of NFS V2)
  128  */
  129 int
  130 nfsrvd_access(struct nfsrv_descript *nd, __unused int isdgram,
  131     vnode_t vp, struct nfsexstuff *exp)
  132 {
  133         u_int32_t *tl;
  134         int getret, error = 0;
  135         struct nfsvattr nva;
  136         u_int32_t testmode, nfsmode, supported = 0;
  137         accmode_t deletebit;
  138         struct thread *p = curthread;
  139 
  140         if (nd->nd_repstat) {
  141                 nfsrv_postopattr(nd, 1, &nva);
  142                 goto out;
  143         }
  144         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  145         nfsmode = fxdr_unsigned(u_int32_t, *tl);
  146         if ((nd->nd_flag & ND_NFSV4) &&
  147             (nfsmode & ~(NFSACCESS_READ | NFSACCESS_LOOKUP |
  148              NFSACCESS_MODIFY | NFSACCESS_EXTEND | NFSACCESS_DELETE |
  149              NFSACCESS_EXECUTE | NFSACCESS_XAREAD | NFSACCESS_XAWRITE |
  150              NFSACCESS_XALIST))) {
  151                 nd->nd_repstat = NFSERR_INVAL;
  152                 vput(vp);
  153                 goto out;
  154         }
  155         if (nfsmode & NFSACCESS_READ) {
  156                 supported |= NFSACCESS_READ;
  157                 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
  158                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  159                         nfsmode &= ~NFSACCESS_READ;
  160         }
  161         if (nfsmode & NFSACCESS_MODIFY) {
  162                 supported |= NFSACCESS_MODIFY;
  163                 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
  164                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  165                         nfsmode &= ~NFSACCESS_MODIFY;
  166         }
  167         if (nfsmode & NFSACCESS_EXTEND) {
  168                 supported |= NFSACCESS_EXTEND;
  169                 if (nfsvno_accchk(vp, VWRITE | VAPPEND, nd->nd_cred, exp, p,
  170                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  171                         nfsmode &= ~NFSACCESS_EXTEND;
  172         }
  173         if (nfsmode & NFSACCESS_XAREAD) {
  174                 supported |= NFSACCESS_XAREAD;
  175                 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
  176                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  177                         nfsmode &= ~NFSACCESS_XAREAD;
  178         }
  179         if (nfsmode & NFSACCESS_XAWRITE) {
  180                 supported |= NFSACCESS_XAWRITE;
  181                 if (nfsvno_accchk(vp, VWRITE, nd->nd_cred, exp, p,
  182                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  183                         nfsmode &= ~NFSACCESS_XAWRITE;
  184         }
  185         if (nfsmode & NFSACCESS_XALIST) {
  186                 supported |= NFSACCESS_XALIST;
  187                 if (nfsvno_accchk(vp, VREAD, nd->nd_cred, exp, p,
  188                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  189                         nfsmode &= ~NFSACCESS_XALIST;
  190         }
  191         if (nfsmode & NFSACCESS_DELETE) {
  192                 supported |= NFSACCESS_DELETE;
  193                 if (vp->v_type == VDIR)
  194                         deletebit = VDELETE_CHILD;
  195                 else
  196                         deletebit = VDELETE;
  197                 if (nfsvno_accchk(vp, deletebit, nd->nd_cred, exp, p,
  198                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  199                         nfsmode &= ~NFSACCESS_DELETE;
  200         }
  201         if (vnode_vtype(vp) == VDIR)
  202                 testmode = NFSACCESS_LOOKUP;
  203         else
  204                 testmode = NFSACCESS_EXECUTE;
  205         if (nfsmode & testmode) {
  206                 supported |= (nfsmode & testmode);
  207                 if (nfsvno_accchk(vp, VEXEC, nd->nd_cred, exp, p,
  208                     NFSACCCHK_NOOVERRIDE, NFSACCCHK_VPISLOCKED, &supported))
  209                         nfsmode &= ~testmode;
  210         }
  211         nfsmode &= supported;
  212         if (nd->nd_flag & ND_NFSV3) {
  213                 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
  214                 nfsrv_postopattr(nd, getret, &nva);
  215         }
  216         vput(vp);
  217         if (nd->nd_flag & ND_NFSV4) {
  218                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  219                 *tl++ = txdr_unsigned(supported);
  220         } else
  221                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  222         *tl = txdr_unsigned(nfsmode);
  223 
  224 out:
  225         NFSEXITCODE2(0, nd);
  226         return (0);
  227 nfsmout:
  228         vput(vp);
  229         NFSEXITCODE2(error, nd);
  230         return (error);
  231 }
  232 
  233 /*
  234  * nfs getattr service
  235  */
  236 int
  237 nfsrvd_getattr(struct nfsrv_descript *nd, int isdgram,
  238     vnode_t vp, __unused struct nfsexstuff *exp)
  239 {
  240         struct nfsvattr nva;
  241         fhandle_t fh;
  242         int at_root = 0, error = 0, supports_nfsv4acls;
  243         struct nfsreferral *refp;
  244         nfsattrbit_t attrbits, tmpbits;
  245         struct mount *mp;
  246         struct vnode *tvp = NULL;
  247         struct vattr va;
  248         uint64_t mounted_on_fileno = 0;
  249         accmode_t accmode;
  250         struct thread *p = curthread;
  251 
  252         if (nd->nd_repstat)
  253                 goto out;
  254         if (nd->nd_flag & ND_NFSV4) {
  255                 error = nfsrv_getattrbits(nd, &attrbits, NULL, NULL);
  256                 if (error) {
  257                         vput(vp);
  258                         goto out;
  259                 }
  260 
  261                 /*
  262                  * Check for a referral.
  263                  */
  264                 refp = nfsv4root_getreferral(vp, NULL, 0);
  265                 if (refp != NULL) {
  266                         (void) nfsrv_putreferralattr(nd, &attrbits, refp, 1,
  267                             &nd->nd_repstat);
  268                         vput(vp);
  269                         goto out;
  270                 }
  271                 if (nd->nd_repstat == 0) {
  272                         accmode = 0;
  273                         NFSSET_ATTRBIT(&tmpbits, &attrbits);
  274 
  275                         /*
  276                          * GETATTR with write-only attr time_access_set and time_modify_set
  277                          * should return NFS4ERR_INVAL.
  278                          */
  279                         if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEACCESSSET) ||
  280                                         NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_TIMEMODIFYSET)){
  281                                 error = NFSERR_INVAL;
  282                                 vput(vp);
  283                                 goto out;
  284                         }
  285                         if (NFSISSET_ATTRBIT(&tmpbits, NFSATTRBIT_ACL)) {
  286                                 NFSCLRBIT_ATTRBIT(&tmpbits, NFSATTRBIT_ACL);
  287                                 accmode |= VREAD_ACL;
  288                         }
  289                         if (NFSNONZERO_ATTRBIT(&tmpbits))
  290                                 accmode |= VREAD_ATTRIBUTES;
  291                         if (accmode != 0)
  292                                 nd->nd_repstat = nfsvno_accchk(vp, accmode,
  293                                     nd->nd_cred, exp, p, NFSACCCHK_NOOVERRIDE,
  294                                     NFSACCCHK_VPISLOCKED, NULL);
  295                 }
  296         }
  297         if (!nd->nd_repstat)
  298                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, &attrbits);
  299         if (!nd->nd_repstat) {
  300                 if (nd->nd_flag & ND_NFSV4) {
  301                         if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_FILEHANDLE))
  302                                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
  303                         if (!nd->nd_repstat)
  304                                 nd->nd_repstat = nfsrv_checkgetattr(nd, vp,
  305                                     &nva, &attrbits, p);
  306                         if (nd->nd_repstat == 0) {
  307                                 supports_nfsv4acls = nfs_supportsnfsv4acls(vp);
  308                                 mp = vp->v_mount;
  309                                 if (nfsrv_enable_crossmntpt != 0 &&
  310                                     vp->v_type == VDIR &&
  311                                     (vp->v_vflag & VV_ROOT) != 0 &&
  312                                     vp != rootvnode) {
  313                                         tvp = mp->mnt_vnodecovered;
  314                                         VREF(tvp);
  315                                         at_root = 1;
  316                                 } else
  317                                         at_root = 0;
  318                                 vfs_ref(mp);
  319                                 NFSVOPUNLOCK(vp);
  320                                 if (at_root != 0) {
  321                                         if ((nd->nd_repstat =
  322                                              NFSVOPLOCK(tvp, LK_SHARED)) == 0) {
  323                                                 nd->nd_repstat = VOP_GETATTR(
  324                                                     tvp, &va, nd->nd_cred);
  325                                                 vput(tvp);
  326                                         } else
  327                                                 vrele(tvp);
  328                                         if (nd->nd_repstat == 0)
  329                                                 mounted_on_fileno = (uint64_t)
  330                                                     va.va_fileid;
  331                                         else
  332                                                 at_root = 0;
  333                                 }
  334                                 if (nd->nd_repstat == 0)
  335                                         nd->nd_repstat = vfs_busy(mp, 0);
  336                                 vfs_rel(mp);
  337                                 if (nd->nd_repstat == 0) {
  338                                         (void)nfsvno_fillattr(nd, mp, vp, &nva,
  339                                             &fh, 0, &attrbits, nd->nd_cred, p,
  340                                             isdgram, 1, supports_nfsv4acls,
  341                                             at_root, mounted_on_fileno);
  342                                         vfs_unbusy(mp);
  343                                 }
  344                                 vrele(vp);
  345                         } else
  346                                 vput(vp);
  347                 } else {
  348                         nfsrv_fillattr(nd, &nva);
  349                         vput(vp);
  350                 }
  351         } else {
  352                 vput(vp);
  353         }
  354 
  355 out:
  356         NFSEXITCODE2(error, nd);
  357         return (error);
  358 }
  359 
  360 /*
  361  * nfs setattr service
  362  */
  363 int
  364 nfsrvd_setattr(struct nfsrv_descript *nd, __unused int isdgram,
  365     vnode_t vp, struct nfsexstuff *exp)
  366 {
  367         struct nfsvattr nva, nva2;
  368         u_int32_t *tl;
  369         int preat_ret = 1, postat_ret = 1, gcheck = 0, error = 0;
  370         int gotproxystateid;
  371         struct timespec guard = { 0, 0 };
  372         nfsattrbit_t attrbits, retbits;
  373         nfsv4stateid_t stateid;
  374         NFSACL_T *aclp = NULL;
  375         struct thread *p = curthread;
  376 
  377         if (nd->nd_repstat) {
  378                 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
  379                 goto out;
  380         }
  381 #ifdef NFS4_ACL_EXTATTR_NAME
  382         aclp = acl_alloc(M_WAITOK);
  383         aclp->acl_cnt = 0;
  384 #endif
  385         gotproxystateid = 0;
  386         NFSVNO_ATTRINIT(&nva);
  387         if (nd->nd_flag & ND_NFSV4) {
  388                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
  389                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
  390                 stateid.other[0] = *tl++;
  391                 stateid.other[1] = *tl++;
  392                 stateid.other[2] = *tl;
  393                 if (stateid.other[0] == 0x55555555 &&
  394                     stateid.other[1] == 0x55555555 &&
  395                     stateid.other[2] == 0x55555555 &&
  396                     stateid.seqid == 0xffffffff)
  397                         gotproxystateid = 1;
  398         }
  399         error = nfsrv_sattr(nd, vp, &nva, &attrbits, aclp, p);
  400         if (error)
  401                 goto nfsmout;
  402 
  403         /* For NFSv4, only va_uid is used from nva2. */
  404         NFSZERO_ATTRBIT(&retbits);
  405         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
  406         preat_ret = nfsvno_getattr(vp, &nva2, nd, p, 1, &retbits);
  407         if (!nd->nd_repstat)
  408                 nd->nd_repstat = preat_ret;
  409 
  410         NFSZERO_ATTRBIT(&retbits);
  411         if (nd->nd_flag & ND_NFSV3) {
  412                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
  413                 gcheck = fxdr_unsigned(int, *tl);
  414                 if (gcheck) {
  415                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  416                         fxdr_nfsv3time(tl, &guard);
  417                 }
  418                 if (!nd->nd_repstat && gcheck &&
  419                     (nva2.na_ctime.tv_sec != guard.tv_sec ||
  420                      nva2.na_ctime.tv_nsec != guard.tv_nsec))
  421                         nd->nd_repstat = NFSERR_NOT_SYNC;
  422                 if (nd->nd_repstat) {
  423                         vput(vp);
  424 #ifdef NFS4_ACL_EXTATTR_NAME
  425                         acl_free(aclp);
  426 #endif
  427                         nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
  428                         goto out;
  429                 }
  430         } else if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4))
  431                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
  432 
  433         /*
  434          * Now that we have all the fields, lets do it.
  435          * If the size is being changed write access is required, otherwise
  436          * just check for a read only file system.
  437          */
  438         if (!nd->nd_repstat) {
  439                 if (NFSVNO_NOTSETSIZE(&nva)) {
  440                         if (NFSVNO_EXRDONLY(exp) ||
  441                             (vfs_flags(vp->v_mount) & MNT_RDONLY))
  442                                 nd->nd_repstat = EROFS;
  443                 } else {
  444                         if (vnode_vtype(vp) != VREG)
  445                                 nd->nd_repstat = EINVAL;
  446                         else if (nva2.na_uid != nd->nd_cred->cr_uid ||
  447                             NFSVNO_EXSTRICTACCESS(exp))
  448                                 nd->nd_repstat = nfsvno_accchk(vp,
  449                                     VWRITE, nd->nd_cred, exp, p,
  450                                     NFSACCCHK_NOOVERRIDE,
  451                                     NFSACCCHK_VPISLOCKED, NULL);
  452                 }
  453         }
  454         /*
  455          * Proxy operations from the MDS are allowed via the all 0s special
  456          * stateid.
  457          */
  458         if (nd->nd_repstat == 0 && (nd->nd_flag & ND_NFSV4) != 0 &&
  459             gotproxystateid == 0)
  460                 nd->nd_repstat = nfsrv_checksetattr(vp, nd, &stateid,
  461                     &nva, &attrbits, exp, p);
  462 
  463         if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
  464             /*
  465              * For V4, try setting the attributes in sets, so that the
  466              * reply bitmap will be correct for an error case.
  467              */
  468             if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER) ||
  469                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP)) {
  470                 NFSVNO_ATTRINIT(&nva2);
  471                 NFSVNO_SETATTRVAL(&nva2, uid, nva.na_uid);
  472                 NFSVNO_SETATTRVAL(&nva2, gid, nva.na_gid);
  473                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  474                     exp);
  475                 if (!nd->nd_repstat) {
  476                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNER))
  477                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNER);
  478                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_OWNERGROUP))
  479                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_OWNERGROUP);
  480                 }
  481             }
  482             if (!nd->nd_repstat &&
  483                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_SIZE)) {
  484                 NFSVNO_ATTRINIT(&nva2);
  485                 NFSVNO_SETATTRVAL(&nva2, size, nva.na_size);
  486                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  487                     exp);
  488                 if (!nd->nd_repstat)
  489                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_SIZE);
  490             }
  491             if (!nd->nd_repstat &&
  492                 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET) ||
  493                  NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))) {
  494                 NFSVNO_ATTRINIT(&nva2);
  495                 NFSVNO_SETATTRVAL(&nva2, atime, nva.na_atime);
  496                 NFSVNO_SETATTRVAL(&nva2, mtime, nva.na_mtime);
  497                 if (nva.na_vaflags & VA_UTIMES_NULL) {
  498                         nva2.na_vaflags |= VA_UTIMES_NULL;
  499                         NFSVNO_SETACTIVE(&nva2, vaflags);
  500                 }
  501                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  502                     exp);
  503                 if (!nd->nd_repstat) {
  504                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEACCESSSET))
  505                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEACCESSSET);
  506                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMEMODIFYSET))
  507                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMEMODIFYSET);
  508                 }
  509             }
  510             if (!nd->nd_repstat &&
  511                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_TIMECREATE)) {
  512                 NFSVNO_ATTRINIT(&nva2);
  513                 NFSVNO_SETATTRVAL(&nva2, btime, nva.na_btime);
  514                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  515                     exp);
  516                 if (!nd->nd_repstat)
  517                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_TIMECREATE);
  518             }
  519             if (!nd->nd_repstat &&
  520                 (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE) ||
  521                  NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))) {
  522                 NFSVNO_ATTRINIT(&nva2);
  523                 NFSVNO_SETATTRVAL(&nva2, mode, nva.na_mode);
  524                 nd->nd_repstat = nfsvno_setattr(vp, &nva2, nd->nd_cred, p,
  525                     exp);
  526                 if (!nd->nd_repstat) {
  527                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODE))
  528                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODE);
  529                     if (NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_MODESETMASKED))
  530                         NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_MODESETMASKED);
  531                 }
  532             }
  533 
  534 #ifdef NFS4_ACL_EXTATTR_NAME
  535             if (!nd->nd_repstat && aclp->acl_cnt > 0 &&
  536                 NFSISSET_ATTRBIT(&attrbits, NFSATTRBIT_ACL)) {
  537                 nd->nd_repstat = nfsrv_setacl(vp, aclp, nd->nd_cred, p);
  538                 if (!nd->nd_repstat) 
  539                     NFSSETBIT_ATTRBIT(&retbits, NFSATTRBIT_ACL);
  540             }
  541 #endif
  542         } else if (!nd->nd_repstat) {
  543                 nd->nd_repstat = nfsvno_setattr(vp, &nva, nd->nd_cred, p,
  544                     exp);
  545         }
  546         if (nd->nd_flag & (ND_NFSV2 | ND_NFSV3)) {
  547                 postat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
  548                 if (!nd->nd_repstat)
  549                         nd->nd_repstat = postat_ret;
  550         }
  551         vput(vp);
  552 #ifdef NFS4_ACL_EXTATTR_NAME
  553         acl_free(aclp);
  554 #endif
  555         if (nd->nd_flag & ND_NFSV3)
  556                 nfsrv_wcc(nd, preat_ret, &nva2, postat_ret, &nva);
  557         else if (nd->nd_flag & ND_NFSV4)
  558                 (void) nfsrv_putattrbit(nd, &retbits);
  559         else if (!nd->nd_repstat)
  560                 nfsrv_fillattr(nd, &nva);
  561 
  562 out:
  563         NFSEXITCODE2(0, nd);
  564         return (0);
  565 nfsmout:
  566         vput(vp);
  567 #ifdef NFS4_ACL_EXTATTR_NAME
  568         acl_free(aclp);
  569 #endif
  570         if (nd->nd_flag & ND_NFSV4) {
  571                 /*
  572                  * For all nd_repstat, the V4 reply includes a bitmap,
  573                  * even NFSERR_BADXDR, which is what this will end up
  574                  * returning.
  575                  */
  576                 (void) nfsrv_putattrbit(nd, &retbits);
  577         }
  578         NFSEXITCODE2(error, nd);
  579         return (error);
  580 }
  581 
  582 /*
  583  * nfs lookup rpc
  584  * (Also performs lookup parent for v4)
  585  */
  586 int
  587 nfsrvd_lookup(struct nfsrv_descript *nd, __unused int isdgram,
  588     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
  589 {
  590         struct nameidata named;
  591         vnode_t vp, dirp = NULL;
  592         int error = 0, dattr_ret = 1;
  593         struct nfsvattr nva, dattr;
  594         char *bufp;
  595         u_long *hashp;
  596         struct thread *p = curthread;
  597 
  598         if (nd->nd_repstat) {
  599                 nfsrv_postopattr(nd, dattr_ret, &dattr);
  600                 goto out;
  601         }
  602 
  603         /*
  604          * For some reason, if dp is a symlink, the error
  605          * returned is supposed to be NFSERR_SYMLINK and not NFSERR_NOTDIR.
  606          */
  607         if (dp->v_type == VLNK && (nd->nd_flag & ND_NFSV4)) {
  608                 nd->nd_repstat = NFSERR_SYMLINK;
  609                 vrele(dp);
  610                 goto out;
  611         }
  612 
  613         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
  614             LOCKLEAF | SAVESTART);
  615         nfsvno_setpathbuf(&named, &bufp, &hashp);
  616         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
  617         if (error) {
  618                 vrele(dp);
  619                 nfsvno_relpathbuf(&named);
  620                 goto out;
  621         }
  622         if (!nd->nd_repstat) {
  623                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
  624         } else {
  625                 vrele(dp);
  626                 nfsvno_relpathbuf(&named);
  627         }
  628         if (nd->nd_repstat) {
  629                 if (dirp) {
  630                         if (nd->nd_flag & ND_NFSV3)
  631                                 dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p,
  632                                     0, NULL);
  633                         vrele(dirp);
  634                 }
  635                 if (nd->nd_flag & ND_NFSV3)
  636                         nfsrv_postopattr(nd, dattr_ret, &dattr);
  637                 goto out;
  638         }
  639         if (named.ni_startdir)
  640                 vrele(named.ni_startdir);
  641         nfsvno_relpathbuf(&named);
  642         vp = named.ni_vp;
  643         if ((nd->nd_flag & ND_NFSV4) != 0 && !NFSVNO_EXPORTED(exp) &&
  644             vp->v_type != VDIR && vp->v_type != VLNK)
  645                 /*
  646                  * Only allow lookup of VDIR and VLNK for traversal of
  647                  * non-exported volumes during NFSv4 mounting.
  648                  */
  649                 nd->nd_repstat = ENOENT;
  650         if (nd->nd_repstat == 0) {
  651                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
  652                 /*
  653                  * EOPNOTSUPP indicates the file system cannot be exported,
  654                  * so just pretend the entry does not exist.
  655                  */
  656                 if (nd->nd_repstat == EOPNOTSUPP)
  657                         nd->nd_repstat = ENOENT;
  658         }
  659         if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
  660                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
  661         if (vpp != NULL && nd->nd_repstat == 0)
  662                 *vpp = vp;
  663         else
  664                 vput(vp);
  665         if (dirp) {
  666                 if (nd->nd_flag & ND_NFSV3)
  667                         dattr_ret = nfsvno_getattr(dirp, &dattr, nd, p, 0,
  668                             NULL);
  669                 vrele(dirp);
  670         }
  671         if (nd->nd_repstat) {
  672                 if (nd->nd_flag & ND_NFSV3)
  673                         nfsrv_postopattr(nd, dattr_ret, &dattr);
  674                 goto out;
  675         }
  676         if (nd->nd_flag & ND_NFSV2) {
  677                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
  678                 nfsrv_fillattr(nd, &nva);
  679         } else if (nd->nd_flag & ND_NFSV3) {
  680                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
  681                 nfsrv_postopattr(nd, 0, &nva);
  682                 nfsrv_postopattr(nd, dattr_ret, &dattr);
  683         }
  684 
  685 out:
  686         NFSEXITCODE2(error, nd);
  687         return (error);
  688 }
  689 
  690 /*
  691  * nfs readlink service
  692  */
  693 int
  694 nfsrvd_readlink(struct nfsrv_descript *nd, __unused int isdgram,
  695     vnode_t vp, __unused struct nfsexstuff *exp)
  696 {
  697         u_int32_t *tl;
  698         struct mbuf *mp = NULL, *mpend = NULL;
  699         int getret = 1, len;
  700         struct nfsvattr nva;
  701         struct thread *p = curthread;
  702         uint16_t off;
  703 
  704         if (nd->nd_repstat) {
  705                 nfsrv_postopattr(nd, getret, &nva);
  706                 goto out;
  707         }
  708         if (vnode_vtype(vp) != VLNK) {
  709                 if (nd->nd_flag & ND_NFSV2)
  710                         nd->nd_repstat = ENXIO;
  711                 else
  712                         nd->nd_repstat = EINVAL;
  713         }
  714         if (nd->nd_repstat == 0) {
  715                 if ((nd->nd_flag & ND_EXTPG) != 0)
  716                         nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
  717                             nd->nd_maxextsiz, p, &mp, &mpend, &len);
  718                 else
  719                         nd->nd_repstat = nfsvno_readlink(vp, nd->nd_cred,
  720                             0, p, &mp, &mpend, &len);
  721         }
  722         if (nd->nd_flag & ND_NFSV3)
  723                 getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
  724         vput(vp);
  725         if (nd->nd_flag & ND_NFSV3)
  726                 nfsrv_postopattr(nd, getret, &nva);
  727         if (nd->nd_repstat)
  728                 goto out;
  729         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  730         *tl = txdr_unsigned(len);
  731         if (mp != NULL) {
  732                 nd->nd_mb->m_next = mp;
  733                 nd->nd_mb = mpend;
  734                 if ((mpend->m_flags & M_EXTPG) != 0) {
  735                         nd->nd_bextpg = mpend->m_epg_npgs - 1;
  736                         nd->nd_bpos = (char *)(void *)
  737                             PHYS_TO_DMAP(mpend->m_epg_pa[nd->nd_bextpg]);
  738                         off = (nd->nd_bextpg == 0) ? mpend->m_epg_1st_off : 0;
  739                         nd->nd_bpos += off + mpend->m_epg_last_len;
  740                         nd->nd_bextpgsiz = PAGE_SIZE - mpend->m_epg_last_len -
  741                             off;
  742                 } else
  743                         nd->nd_bpos = mtod(mpend, char *) + mpend->m_len;
  744         }
  745 
  746 out:
  747         NFSEXITCODE2(0, nd);
  748         return (0);
  749 }
  750 
  751 /*
  752  * nfs read service
  753  */
  754 int
  755 nfsrvd_read(struct nfsrv_descript *nd, __unused int isdgram,
  756     vnode_t vp, struct nfsexstuff *exp)
  757 {
  758         u_int32_t *tl;
  759         int error = 0, cnt, getret = 1, gotproxystateid, reqlen, eof = 0;
  760         struct mbuf *m2, *m3;
  761         struct nfsvattr nva;
  762         off_t off = 0x0;
  763         struct nfsstate st, *stp = &st;
  764         struct nfslock lo, *lop = &lo;
  765         nfsv4stateid_t stateid;
  766         nfsquad_t clientid;
  767         struct thread *p = curthread;
  768         uint16_t poff;
  769 
  770         if (nd->nd_repstat) {
  771                 nfsrv_postopattr(nd, getret, &nva);
  772                 goto out;
  773         }
  774         if (nd->nd_flag & ND_NFSV2) {
  775                 NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  776                 off = (off_t)fxdr_unsigned(u_int32_t, *tl++);
  777                 reqlen = fxdr_unsigned(int, *tl);
  778         } else if (nd->nd_flag & ND_NFSV3) {
  779                 NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
  780                 off = fxdr_hyper(tl);
  781                 tl += 2;
  782                 reqlen = fxdr_unsigned(int, *tl);
  783         } else {
  784                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3*NFSX_UNSIGNED);
  785                 reqlen = fxdr_unsigned(int, *(tl + 6));
  786         }
  787         if (reqlen > NFS_SRVMAXDATA(nd)) {
  788                 reqlen = NFS_SRVMAXDATA(nd);
  789         } else if (reqlen < 0) {
  790                 error = EBADRPC;
  791                 goto nfsmout;
  792         }
  793         gotproxystateid = 0;
  794         if (nd->nd_flag & ND_NFSV4) {
  795                 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_READACCESS);
  796                 lop->lo_flags = NFSLCK_READ;
  797                 stp->ls_ownerlen = 0;
  798                 stp->ls_op = NULL;
  799                 stp->ls_uid = nd->nd_cred->cr_uid;
  800                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
  801                 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
  802                 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
  803                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
  804                         if ((nd->nd_flag & ND_NFSV41) != 0)
  805                                 clientid.qval = nd->nd_clientid.qval;
  806                         else if (nd->nd_clientid.qval != clientid.qval)
  807                                 printf("EEK1 multiple clids\n");
  808                 } else {
  809                         if ((nd->nd_flag & ND_NFSV41) != 0)
  810                                 printf("EEK! no clientid from session\n");
  811                         nd->nd_flag |= ND_IMPLIEDCLID;
  812                         nd->nd_clientid.qval = clientid.qval;
  813                 }
  814                 stp->ls_stateid.other[2] = *tl++;
  815                 /*
  816                  * Don't allow the client to use a special stateid for a DS op.
  817                  */
  818                 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
  819                     ((stp->ls_stateid.other[0] == 0x0 &&
  820                     stp->ls_stateid.other[1] == 0x0 &&
  821                     stp->ls_stateid.other[2] == 0x0) ||
  822                     (stp->ls_stateid.other[0] == 0xffffffff &&
  823                     stp->ls_stateid.other[1] == 0xffffffff &&
  824                     stp->ls_stateid.other[2] == 0xffffffff) ||
  825                     stp->ls_stateid.seqid != 0))
  826                         nd->nd_repstat = NFSERR_BADSTATEID;
  827                 /* However, allow the proxy stateid. */
  828                 if (stp->ls_stateid.seqid == 0xffffffff &&
  829                     stp->ls_stateid.other[0] == 0x55555555 &&
  830                     stp->ls_stateid.other[1] == 0x55555555 &&
  831                     stp->ls_stateid.other[2] == 0x55555555)
  832                         gotproxystateid = 1;
  833                 off = fxdr_hyper(tl);
  834                 lop->lo_first = off;
  835                 tl += 2;
  836                 lop->lo_end = off + reqlen;
  837                 /*
  838                  * Paranoia, just in case it wraps around.
  839                  */
  840                 if (lop->lo_end < off)
  841                         lop->lo_end = NFS64BITSSET;
  842         }
  843         if (vnode_vtype(vp) != VREG) {
  844                 if (nd->nd_flag & ND_NFSV3)
  845                         nd->nd_repstat = EINVAL;
  846                 else
  847                         nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
  848                             EINVAL;
  849         }
  850         getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
  851         if (!nd->nd_repstat)
  852                 nd->nd_repstat = getret;
  853         if (!nd->nd_repstat &&
  854             (nva.na_uid != nd->nd_cred->cr_uid ||
  855              NFSVNO_EXSTRICTACCESS(exp))) {
  856                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
  857                     nd->nd_cred, exp, p,
  858                     NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
  859                 if (nd->nd_repstat)
  860                         nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
  861                             nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
  862                             NFSACCCHK_VPISLOCKED, NULL);
  863         }
  864         /*
  865          * DS reads are marked by ND_DSSERVER or use the proxy special
  866          * stateid.
  867          */
  868         if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
  869             ND_NFSV4 && gotproxystateid == 0)
  870                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
  871                     &stateid, exp, nd, p);
  872         if (nd->nd_repstat) {
  873                 vput(vp);
  874                 if (nd->nd_flag & ND_NFSV3)
  875                         nfsrv_postopattr(nd, getret, &nva);
  876                 goto out;
  877         }
  878         if (off >= nva.na_size) {
  879                 cnt = 0;
  880                 eof = 1;
  881         } else if (reqlen == 0)
  882                 cnt = 0;
  883         else if ((off + reqlen) >= nva.na_size) {
  884                 cnt = nva.na_size - off;
  885                 eof = 1;
  886         } else
  887                 cnt = reqlen;
  888         m3 = NULL;
  889         if (cnt > 0) {
  890                 /*
  891                  * If cnt > MCLBYTES and the reply will not be saved, use
  892                  * ext_pgs mbufs for TLS.
  893                  * For NFSv4.0, we do not know for sure if the reply will
  894                  * be saved, so do not use ext_pgs mbufs for NFSv4.0.
  895                  * Always use ext_pgs mbufs if ND_EXTPG is set.
  896                  */
  897                 if ((nd->nd_flag & ND_EXTPG) != 0 || (cnt > MCLBYTES &&
  898                     (nd->nd_flag & (ND_TLS | ND_SAVEREPLY)) == ND_TLS &&
  899                     (nd->nd_flag & (ND_NFSV4 | ND_NFSV41)) != ND_NFSV4))
  900                         nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
  901                             nd->nd_maxextsiz, p, &m3, &m2);
  902                 else
  903                         nd->nd_repstat = nfsvno_read(vp, off, cnt, nd->nd_cred,
  904                             0, p, &m3, &m2);
  905                 if (!(nd->nd_flag & ND_NFSV4)) {
  906                         getret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
  907                         if (!nd->nd_repstat)
  908                                 nd->nd_repstat = getret;
  909                 }
  910                 if (nd->nd_repstat) {
  911                         vput(vp);
  912                         if (m3)
  913                                 m_freem(m3);
  914                         if (nd->nd_flag & ND_NFSV3)
  915                                 nfsrv_postopattr(nd, getret, &nva);
  916                         goto out;
  917                 }
  918         }
  919         vput(vp);
  920         if (nd->nd_flag & ND_NFSV2) {
  921                 nfsrv_fillattr(nd, &nva);
  922                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
  923         } else {
  924                 if (nd->nd_flag & ND_NFSV3) {
  925                         nfsrv_postopattr(nd, getret, &nva);
  926                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
  927                         *tl++ = txdr_unsigned(cnt);
  928                 } else
  929                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
  930                 if (eof)
  931                         *tl++ = newnfs_true;
  932                 else
  933                         *tl++ = newnfs_false;
  934         }
  935         *tl = txdr_unsigned(cnt);
  936         if (m3) {
  937                 nd->nd_mb->m_next = m3;
  938                 nd->nd_mb = m2;
  939                 if ((m2->m_flags & M_EXTPG) != 0) {
  940                         nd->nd_flag |= ND_EXTPG;
  941                         nd->nd_bextpg = m2->m_epg_npgs - 1;
  942                         nd->nd_bpos = (char *)(void *)
  943                             PHYS_TO_DMAP(m2->m_epg_pa[nd->nd_bextpg]);
  944                         poff = (nd->nd_bextpg == 0) ? m2->m_epg_1st_off : 0;
  945                         nd->nd_bpos += poff + m2->m_epg_last_len;
  946                         nd->nd_bextpgsiz = PAGE_SIZE - m2->m_epg_last_len -
  947                             poff;
  948                 } else
  949                         nd->nd_bpos = mtod(m2, char *) + m2->m_len;
  950         }
  951 
  952 out:
  953         NFSEXITCODE2(0, nd);
  954         return (0);
  955 nfsmout:
  956         vput(vp);
  957         NFSEXITCODE2(error, nd);
  958         return (error);
  959 }
  960 
  961 /*
  962  * nfs write service
  963  */
  964 int
  965 nfsrvd_write(struct nfsrv_descript *nd, __unused int isdgram,
  966     vnode_t vp, struct nfsexstuff *exp)
  967 {
  968         u_int32_t *tl;
  969         struct nfsvattr nva, forat;
  970         int aftat_ret = 1, retlen, len, error = 0, forat_ret = 1;
  971         int gotproxystateid, stable = NFSWRITE_FILESYNC;
  972         off_t off;
  973         struct nfsstate st, *stp = &st;
  974         struct nfslock lo, *lop = &lo;
  975         nfsv4stateid_t stateid;
  976         nfsquad_t clientid;
  977         nfsattrbit_t attrbits;
  978         struct thread *p = curthread;
  979 
  980         if (nd->nd_repstat) {
  981                 nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
  982                 goto out;
  983         }
  984         gotproxystateid = 0;
  985         if (nd->nd_flag & ND_NFSV2) {
  986                 NFSM_DISSECT(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
  987                 off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
  988                 tl += 2;
  989                 retlen = len = fxdr_unsigned(int32_t, *tl);
  990         } else if (nd->nd_flag & ND_NFSV3) {
  991                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
  992                 off = fxdr_hyper(tl);
  993                 tl += 3;
  994                 stable = fxdr_unsigned(int, *tl++);
  995                 retlen = len = fxdr_unsigned(int32_t, *tl);
  996         } else {
  997                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 4 * NFSX_UNSIGNED);
  998                 stp->ls_flags = (NFSLCK_CHECK | NFSLCK_WRITEACCESS);
  999                 lop->lo_flags = NFSLCK_WRITE;
 1000                 stp->ls_ownerlen = 0;
 1001                 stp->ls_op = NULL;
 1002                 stp->ls_uid = nd->nd_cred->cr_uid;
 1003                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 1004                 clientid.lval[0] = stp->ls_stateid.other[0] = *tl++;
 1005                 clientid.lval[1] = stp->ls_stateid.other[1] = *tl++;
 1006                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 1007                         if ((nd->nd_flag & ND_NFSV41) != 0)
 1008                                 clientid.qval = nd->nd_clientid.qval;
 1009                         else if (nd->nd_clientid.qval != clientid.qval)
 1010                                 printf("EEK2 multiple clids\n");
 1011                 } else {
 1012                         if ((nd->nd_flag & ND_NFSV41) != 0)
 1013                                 printf("EEK! no clientid from session\n");
 1014                         nd->nd_flag |= ND_IMPLIEDCLID;
 1015                         nd->nd_clientid.qval = clientid.qval;
 1016                 }
 1017                 stp->ls_stateid.other[2] = *tl++;
 1018                 /*
 1019                  * Don't allow the client to use a special stateid for a DS op.
 1020                  */
 1021                 if ((nd->nd_flag & ND_DSSERVER) != 0 &&
 1022                     ((stp->ls_stateid.other[0] == 0x0 &&
 1023                     stp->ls_stateid.other[1] == 0x0 &&
 1024                     stp->ls_stateid.other[2] == 0x0) ||
 1025                     (stp->ls_stateid.other[0] == 0xffffffff &&
 1026                     stp->ls_stateid.other[1] == 0xffffffff &&
 1027                     stp->ls_stateid.other[2] == 0xffffffff) ||
 1028                     stp->ls_stateid.seqid != 0))
 1029                         nd->nd_repstat = NFSERR_BADSTATEID;
 1030                 /* However, allow the proxy stateid. */
 1031                 if (stp->ls_stateid.seqid == 0xffffffff &&
 1032                     stp->ls_stateid.other[0] == 0x55555555 &&
 1033                     stp->ls_stateid.other[1] == 0x55555555 &&
 1034                     stp->ls_stateid.other[2] == 0x55555555)
 1035                         gotproxystateid = 1;
 1036                 off = fxdr_hyper(tl);
 1037                 lop->lo_first = off;
 1038                 tl += 2;
 1039                 stable = fxdr_unsigned(int, *tl++);
 1040                 retlen = len = fxdr_unsigned(int32_t, *tl);
 1041                 lop->lo_end = off + len;
 1042                 /*
 1043                  * Paranoia, just in case it wraps around, which shouldn't
 1044                  * ever happen anyhow.
 1045                  */
 1046                 if (lop->lo_end < lop->lo_first)
 1047                         lop->lo_end = NFS64BITSSET;
 1048         }
 1049 
 1050         if (retlen > nfs_srvmaxio || retlen < 0)
 1051                 nd->nd_repstat = EIO;
 1052         if (vnode_vtype(vp) != VREG && !nd->nd_repstat) {
 1053                 if (nd->nd_flag & ND_NFSV3)
 1054                         nd->nd_repstat = EINVAL;
 1055                 else
 1056                         nd->nd_repstat = (vnode_vtype(vp) == VDIR) ? EISDIR :
 1057                             EINVAL;
 1058         }
 1059         NFSZERO_ATTRBIT(&attrbits);
 1060         NFSSETBIT_ATTRBIT(&attrbits, NFSATTRBIT_OWNER);
 1061         forat_ret = nfsvno_getattr(vp, &forat, nd, p, 1, &attrbits);
 1062         if (!nd->nd_repstat)
 1063                 nd->nd_repstat = forat_ret;
 1064         if (!nd->nd_repstat &&
 1065             (forat.na_uid != nd->nd_cred->cr_uid ||
 1066              NFSVNO_EXSTRICTACCESS(exp)))
 1067                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
 1068                     nd->nd_cred, exp, p,
 1069                     NFSACCCHK_ALLOWOWNER, NFSACCCHK_VPISLOCKED, NULL);
 1070         /*
 1071          * DS reads are marked by ND_DSSERVER or use the proxy special
 1072          * stateid.
 1073          */
 1074         if (nd->nd_repstat == 0 && (nd->nd_flag & (ND_NFSV4 | ND_DSSERVER)) ==
 1075             ND_NFSV4 && gotproxystateid == 0)
 1076                 nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
 1077                     &stateid, exp, nd, p);
 1078         if (nd->nd_repstat) {
 1079                 vput(vp);
 1080                 if (nd->nd_flag & ND_NFSV3)
 1081                         nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
 1082                 goto out;
 1083         }
 1084 
 1085         /*
 1086          * For NFS Version 2, it is not obvious what a write of zero length
 1087          * should do, but I might as well be consistent with Version 3,
 1088          * which is to return ok so long as there are no permission problems.
 1089          */
 1090         if (retlen > 0) {
 1091                 nd->nd_repstat = nfsvno_write(vp, off, retlen, &stable,
 1092                     nd->nd_md, nd->nd_dpos, nd->nd_cred, p);
 1093                 error = nfsm_advance(nd, NFSM_RNDUP(retlen), -1);
 1094                 if (error)
 1095                         goto nfsmout;
 1096         }
 1097         if (nd->nd_flag & ND_NFSV4)
 1098                 aftat_ret = 0;
 1099         else
 1100                 aftat_ret = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 1101         vput(vp);
 1102         if (!nd->nd_repstat)
 1103                 nd->nd_repstat = aftat_ret;
 1104         if (nd->nd_flag & (ND_NFSV3 | ND_NFSV4)) {
 1105                 if (nd->nd_flag & ND_NFSV3)
 1106                         nfsrv_wcc(nd, forat_ret, &forat, aftat_ret, &nva);
 1107                 if (nd->nd_repstat)
 1108                         goto out;
 1109                 NFSM_BUILD(tl, u_int32_t *, 4 * NFSX_UNSIGNED);
 1110                 *tl++ = txdr_unsigned(retlen);
 1111                 /*
 1112                  * If nfs_async is set, then pretend the write was FILESYNC.
 1113                  * Warning: Doing this violates RFC1813 and runs a risk
 1114                  * of data written by a client being lost when the server
 1115                  * crashes/reboots.
 1116                  */
 1117                 if (stable == NFSWRITE_UNSTABLE && nfs_async == 0)
 1118                         *tl++ = txdr_unsigned(stable);
 1119                 else
 1120                         *tl++ = txdr_unsigned(NFSWRITE_FILESYNC);
 1121                 /*
 1122                  * Actually, there is no need to txdr these fields,
 1123                  * but it may make the values more human readable,
 1124                  * for debugging purposes.
 1125                  */
 1126                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
 1127                 *tl = txdr_unsigned(nfsboottime.tv_usec);
 1128         } else if (!nd->nd_repstat)
 1129                 nfsrv_fillattr(nd, &nva);
 1130 
 1131 out:
 1132         NFSEXITCODE2(0, nd);
 1133         return (0);
 1134 nfsmout:
 1135         vput(vp);
 1136         NFSEXITCODE2(error, nd);
 1137         return (error);
 1138 }
 1139 
 1140 /*
 1141  * nfs create service (creates regular files for V2 and V3. Spec. files for V2.)
 1142  * now does a truncate to 0 length via. setattr if it already exists
 1143  * The core creation routine has been extracted out into nfsrv_creatsub(),
 1144  * so it can also be used by nfsrv_open() for V4.
 1145  */
 1146 int
 1147 nfsrvd_create(struct nfsrv_descript *nd, __unused int isdgram,
 1148     vnode_t dp, struct nfsexstuff *exp)
 1149 {
 1150         struct nfsvattr nva, dirfor, diraft;
 1151         struct nfsv2_sattr *sp;
 1152         struct nameidata named;
 1153         u_int32_t *tl;
 1154         int error = 0, tsize, dirfor_ret = 1, diraft_ret = 1;
 1155         int how = NFSCREATE_UNCHECKED, exclusive_flag = 0;
 1156         NFSDEV_T rdev = 0;
 1157         vnode_t vp = NULL, dirp = NULL;
 1158         fhandle_t fh;
 1159         char *bufp;
 1160         u_long *hashp;
 1161         enum vtype vtyp;
 1162         int32_t cverf[2], tverf[2] = { 0, 0 };
 1163         struct thread *p = curthread;
 1164 
 1165         if (nd->nd_repstat) {
 1166                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1167                 goto out;
 1168         }
 1169         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1170             LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
 1171         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1172         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1173         if (error)
 1174                 goto nfsmout;
 1175         if (!nd->nd_repstat) {
 1176                 NFSVNO_ATTRINIT(&nva);
 1177                 if (nd->nd_flag & ND_NFSV2) {
 1178                         NFSM_DISSECT(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
 1179                         vtyp = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
 1180                         if (vtyp == VNON)
 1181                                 vtyp = VREG;
 1182                         NFSVNO_SETATTRVAL(&nva, type, vtyp);
 1183                         NFSVNO_SETATTRVAL(&nva, mode,
 1184                             nfstov_mode(sp->sa_mode));
 1185                         switch (nva.na_type) {
 1186                         case VREG:
 1187                                 tsize = fxdr_unsigned(int32_t, sp->sa_size);
 1188                                 if (tsize != -1)
 1189                                         NFSVNO_SETATTRVAL(&nva, size,
 1190                                             (u_quad_t)tsize);
 1191                                 break;
 1192                         case VCHR:
 1193                         case VBLK:
 1194                         case VFIFO:
 1195                                 rdev = fxdr_unsigned(NFSDEV_T, sp->sa_size);
 1196                                 break;
 1197                         default:
 1198                                 break;
 1199                         }
 1200                 } else {
 1201                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1202                         how = fxdr_unsigned(int, *tl);
 1203                         switch (how) {
 1204                         case NFSCREATE_GUARDED:
 1205                         case NFSCREATE_UNCHECKED:
 1206                                 error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
 1207                                 if (error)
 1208                                         goto nfsmout;
 1209                                 break;
 1210                         case NFSCREATE_EXCLUSIVE:
 1211                                 NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 1212                                 cverf[0] = *tl++;
 1213                                 cverf[1] = *tl;
 1214                                 exclusive_flag = 1;
 1215                                 break;
 1216                         }
 1217                         NFSVNO_SETATTRVAL(&nva, type, VREG);
 1218                 }
 1219         }
 1220         if (nd->nd_repstat) {
 1221                 nfsvno_relpathbuf(&named);
 1222                 if (nd->nd_flag & ND_NFSV3) {
 1223                         dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 1,
 1224                             NULL);
 1225                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1226                             &diraft);
 1227                 }
 1228                 vput(dp);
 1229                 goto out;
 1230         }
 1231 
 1232         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
 1233         if (dirp) {
 1234                 if (nd->nd_flag & ND_NFSV2) {
 1235                         vrele(dirp);
 1236                         dirp = NULL;
 1237                 } else {
 1238                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
 1239                             NULL);
 1240                 }
 1241         }
 1242         if (nd->nd_repstat) {
 1243                 if (nd->nd_flag & ND_NFSV3)
 1244                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1245                             &diraft);
 1246                 if (dirp)
 1247                         vrele(dirp);
 1248                 goto out;
 1249         }
 1250 
 1251         if (!(nd->nd_flag & ND_NFSV2)) {
 1252                 switch (how) {
 1253                 case NFSCREATE_GUARDED:
 1254                         if (named.ni_vp)
 1255                                 nd->nd_repstat = EEXIST;
 1256                         break;
 1257                 case NFSCREATE_UNCHECKED:
 1258                         break;
 1259                 case NFSCREATE_EXCLUSIVE:
 1260                         if (named.ni_vp == NULL)
 1261                                 NFSVNO_SETATTRVAL(&nva, mode, 0);
 1262                         break;
 1263                 }
 1264         }
 1265 
 1266         /*
 1267          * Iff doesn't exist, create it
 1268          * otherwise just truncate to 0 length
 1269          *   should I set the mode too ?
 1270          */
 1271         nd->nd_repstat = nfsvno_createsub(nd, &named, &vp, &nva,
 1272             &exclusive_flag, cverf, rdev, exp);
 1273 
 1274         if (!nd->nd_repstat) {
 1275                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 1276                 if (!nd->nd_repstat)
 1277                         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
 1278                             NULL);
 1279                 vput(vp);
 1280                 if (!nd->nd_repstat) {
 1281                         tverf[0] = nva.na_atime.tv_sec;
 1282                         tverf[1] = nva.na_atime.tv_nsec;
 1283                 }
 1284         }
 1285         if (nd->nd_flag & ND_NFSV2) {
 1286                 if (!nd->nd_repstat) {
 1287                         (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
 1288                         nfsrv_fillattr(nd, &nva);
 1289                 }
 1290         } else {
 1291                 if (exclusive_flag && !nd->nd_repstat && (cverf[0] != tverf[0]
 1292                     || cverf[1] != tverf[1]))
 1293                         nd->nd_repstat = EEXIST;
 1294                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
 1295                 vrele(dirp);
 1296                 if (!nd->nd_repstat) {
 1297                         (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 1);
 1298                         nfsrv_postopattr(nd, 0, &nva);
 1299                 }
 1300                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1301         }
 1302 
 1303 out:
 1304         NFSEXITCODE2(0, nd);
 1305         return (0);
 1306 nfsmout:
 1307         vput(dp);
 1308         nfsvno_relpathbuf(&named);
 1309         NFSEXITCODE2(error, nd);
 1310         return (error);
 1311 }
 1312 
 1313 /*
 1314  * nfs v3 mknod service (and v4 create)
 1315  */
 1316 int
 1317 nfsrvd_mknod(struct nfsrv_descript *nd, __unused int isdgram,
 1318     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
 1319 {
 1320         struct nfsvattr nva, dirfor, diraft;
 1321         u_int32_t *tl;
 1322         struct nameidata named;
 1323         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
 1324         u_int32_t major, minor;
 1325         enum vtype vtyp = VNON;
 1326         nfstype nfs4type = NFNON;
 1327         vnode_t vp, dirp = NULL;
 1328         nfsattrbit_t attrbits;
 1329         char *bufp = NULL, *pathcp = NULL;
 1330         u_long *hashp, cnflags;
 1331         NFSACL_T *aclp = NULL;
 1332         struct thread *p = curthread;
 1333 
 1334         NFSVNO_ATTRINIT(&nva);
 1335         cnflags = (LOCKPARENT | SAVESTART);
 1336         if (nd->nd_repstat) {
 1337                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1338                 goto out;
 1339         }
 1340 #ifdef NFS4_ACL_EXTATTR_NAME
 1341         aclp = acl_alloc(M_WAITOK);
 1342         aclp->acl_cnt = 0;
 1343 #endif
 1344 
 1345         /*
 1346          * For V4, the creation stuff is here, Yuck!
 1347          */
 1348         if (nd->nd_flag & ND_NFSV4) {
 1349                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1350                 vtyp = nfsv34tov_type(*tl);
 1351                 nfs4type = fxdr_unsigned(nfstype, *tl);
 1352                 switch (nfs4type) {
 1353                 case NFLNK:
 1354                         error = nfsvno_getsymlink(nd, &nva, p, &pathcp,
 1355                             &pathlen);
 1356                         if (error)
 1357                                 goto nfsmout;
 1358                         break;
 1359                 case NFCHR:
 1360                 case NFBLK:
 1361                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1362                         major = fxdr_unsigned(u_int32_t, *tl++);
 1363                         minor = fxdr_unsigned(u_int32_t, *tl);
 1364                         nva.na_rdev = NFSMAKEDEV(major, minor);
 1365                         break;
 1366                 case NFSOCK:
 1367                 case NFFIFO:
 1368                         break;
 1369                 case NFDIR:
 1370                         cnflags = (LOCKPARENT | SAVENAME);
 1371                         break;
 1372                 default:
 1373                         nd->nd_repstat = NFSERR_BADTYPE;
 1374                         vrele(dp);
 1375 #ifdef NFS4_ACL_EXTATTR_NAME
 1376                         acl_free(aclp);
 1377 #endif
 1378                         goto out;
 1379                 }
 1380         }
 1381         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE, cnflags | NOCACHE);
 1382         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1383         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1384         if (error)
 1385                 goto nfsmout;
 1386         if (!nd->nd_repstat) {
 1387                 if (nd->nd_flag & ND_NFSV3) {
 1388                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 1389                         vtyp = nfsv34tov_type(*tl);
 1390                 }
 1391                 error = nfsrv_sattr(nd, NULL, &nva, &attrbits, aclp, p);
 1392                 if (error)
 1393                         goto nfsmout;
 1394                 nva.na_type = vtyp;
 1395                 if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV3) &&
 1396                     (vtyp == VCHR || vtyp == VBLK)) {
 1397                         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 1398                         major = fxdr_unsigned(u_int32_t, *tl++);
 1399                         minor = fxdr_unsigned(u_int32_t, *tl);
 1400                         nva.na_rdev = NFSMAKEDEV(major, minor);
 1401                 }
 1402         }
 1403 
 1404         dirfor_ret = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
 1405         if (!nd->nd_repstat && (nd->nd_flag & ND_NFSV4)) {
 1406                 if (!dirfor_ret && NFSVNO_ISSETGID(&nva) &&
 1407                     dirfor.na_gid == nva.na_gid)
 1408                         NFSVNO_UNSET(&nva, gid);
 1409                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
 1410         }
 1411         if (nd->nd_repstat) {
 1412                 vrele(dp);
 1413 #ifdef NFS4_ACL_EXTATTR_NAME
 1414                 acl_free(aclp);
 1415 #endif
 1416                 nfsvno_relpathbuf(&named);
 1417                 if (pathcp)
 1418                         free(pathcp, M_TEMP);
 1419                 if (nd->nd_flag & ND_NFSV3)
 1420                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1421                             &diraft);
 1422                 goto out;
 1423         }
 1424 
 1425         /*
 1426          * Yuck! For V4, mkdir and link are here and some V4 clients don't fill
 1427          * in va_mode, so we'll have to set a default here.
 1428          */
 1429         if (NFSVNO_NOTSETMODE(&nva)) {
 1430                 if (vtyp == VLNK)
 1431                         nva.na_mode = 0755;
 1432                 else
 1433                         nva.na_mode = 0400;
 1434         }
 1435 
 1436         if (vtyp == VDIR)
 1437                 named.ni_cnd.cn_flags |= WILLBEDIR;
 1438         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
 1439         if (nd->nd_repstat) {
 1440                 if (dirp) {
 1441                         if (nd->nd_flag & ND_NFSV3)
 1442                                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd,
 1443                                     p, 0, NULL);
 1444                         vrele(dirp);
 1445                 }
 1446 #ifdef NFS4_ACL_EXTATTR_NAME
 1447                 acl_free(aclp);
 1448 #endif
 1449                 if (nd->nd_flag & ND_NFSV3)
 1450                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1451                             &diraft);
 1452                 goto out;
 1453         }
 1454         if (dirp)
 1455                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
 1456 
 1457         if ((nd->nd_flag & ND_NFSV4) && (vtyp == VDIR || vtyp == VLNK)) {
 1458                 if (vtyp == VDIR) {
 1459                         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp,
 1460                             &dirfor, &diraft, &diraft_ret, &attrbits, aclp, p,
 1461                             exp);
 1462 #ifdef NFS4_ACL_EXTATTR_NAME
 1463                         acl_free(aclp);
 1464 #endif
 1465                         goto out;
 1466                 } else if (vtyp == VLNK) {
 1467                         nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
 1468                             &dirfor, &diraft, &diraft_ret, &attrbits,
 1469                             aclp, p, exp, pathcp, pathlen);
 1470 #ifdef NFS4_ACL_EXTATTR_NAME
 1471                         acl_free(aclp);
 1472 #endif
 1473                         free(pathcp, M_TEMP);
 1474                         goto out;
 1475                 }
 1476         }
 1477 
 1478         nd->nd_repstat = nfsvno_mknod(&named, &nva, nd->nd_cred, p);
 1479         if (!nd->nd_repstat) {
 1480                 vp = named.ni_vp;
 1481                 nfsrv_fixattr(nd, vp, &nva, aclp, p, &attrbits, exp);
 1482                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
 1483                 if ((nd->nd_flag & ND_NFSV3) && !nd->nd_repstat)
 1484                         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1,
 1485                             NULL);
 1486                 if (vpp != NULL && nd->nd_repstat == 0) {
 1487                         NFSVOPUNLOCK(vp);
 1488                         *vpp = vp;
 1489                 } else
 1490                         vput(vp);
 1491         }
 1492 
 1493         diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
 1494         vrele(dirp);
 1495         if (!nd->nd_repstat) {
 1496                 if (nd->nd_flag & ND_NFSV3) {
 1497                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
 1498                         nfsrv_postopattr(nd, 0, &nva);
 1499                 } else {
 1500                         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1501                         *tl++ = newnfs_false;
 1502                         txdr_hyper(dirfor.na_filerev, tl);
 1503                         tl += 2;
 1504                         txdr_hyper(diraft.na_filerev, tl);
 1505                         (void) nfsrv_putattrbit(nd, &attrbits);
 1506                 }
 1507         }
 1508         if (nd->nd_flag & ND_NFSV3)
 1509                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1510 #ifdef NFS4_ACL_EXTATTR_NAME
 1511         acl_free(aclp);
 1512 #endif
 1513 
 1514 out:
 1515         NFSEXITCODE2(0, nd);
 1516         return (0);
 1517 nfsmout:
 1518         vrele(dp);
 1519 #ifdef NFS4_ACL_EXTATTR_NAME
 1520         acl_free(aclp);
 1521 #endif
 1522         if (bufp)
 1523                 nfsvno_relpathbuf(&named);
 1524         if (pathcp)
 1525                 free(pathcp, M_TEMP);
 1526 
 1527         NFSEXITCODE2(error, nd);
 1528         return (error);
 1529 }
 1530 
 1531 /*
 1532  * nfs remove service
 1533  */
 1534 int
 1535 nfsrvd_remove(struct nfsrv_descript *nd, __unused int isdgram,
 1536     vnode_t dp, struct nfsexstuff *exp)
 1537 {
 1538         struct nameidata named;
 1539         u_int32_t *tl;
 1540         int error = 0, dirfor_ret = 1, diraft_ret = 1;
 1541         vnode_t dirp = NULL;
 1542         struct nfsvattr dirfor, diraft;
 1543         char *bufp;
 1544         u_long *hashp;
 1545         struct thread *p = curthread;
 1546 
 1547         if (nd->nd_repstat) {
 1548                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1549                 goto out;
 1550         }
 1551         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, DELETE,
 1552             LOCKPARENT | LOCKLEAF);
 1553         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1554         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1555         if (error) {
 1556                 vput(dp);
 1557                 nfsvno_relpathbuf(&named);
 1558                 goto out;
 1559         }
 1560         if (!nd->nd_repstat) {
 1561                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
 1562         } else {
 1563                 vput(dp);
 1564                 nfsvno_relpathbuf(&named);
 1565         }
 1566         if (dirp) {
 1567                 if (!(nd->nd_flag & ND_NFSV2)) {
 1568                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
 1569                             NULL);
 1570                 } else {
 1571                         vrele(dirp);
 1572                         dirp = NULL;
 1573                 }
 1574         }
 1575         if (!nd->nd_repstat) {
 1576                 if (nd->nd_flag & ND_NFSV4) {
 1577                         if (vnode_vtype(named.ni_vp) == VDIR)
 1578                                 nd->nd_repstat = nfsvno_rmdirsub(&named, 1,
 1579                                     nd->nd_cred, p, exp);
 1580                         else
 1581                                 nd->nd_repstat = nfsvno_removesub(&named, 1,
 1582                                     nd->nd_cred, p, exp);
 1583                 } else if (nd->nd_procnum == NFSPROC_RMDIR) {
 1584                         nd->nd_repstat = nfsvno_rmdirsub(&named, 0,
 1585                             nd->nd_cred, p, exp);
 1586                 } else {
 1587                         nd->nd_repstat = nfsvno_removesub(&named, 0,
 1588                             nd->nd_cred, p, exp);
 1589                 }
 1590         }
 1591         if (!(nd->nd_flag & ND_NFSV2)) {
 1592                 if (dirp) {
 1593                         diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0,
 1594                             NULL);
 1595                         vrele(dirp);
 1596                 }
 1597                 if (nd->nd_flag & ND_NFSV3) {
 1598                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 1599                             &diraft);
 1600                 } else if (!nd->nd_repstat) {
 1601                         NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1602                         *tl++ = newnfs_false;
 1603                         txdr_hyper(dirfor.na_filerev, tl);
 1604                         tl += 2;
 1605                         txdr_hyper(diraft.na_filerev, tl);
 1606                 }
 1607         }
 1608 
 1609 out:
 1610         NFSEXITCODE2(error, nd);
 1611         return (error);
 1612 }
 1613 
 1614 /*
 1615  * nfs rename service
 1616  */
 1617 int
 1618 nfsrvd_rename(struct nfsrv_descript *nd, int isdgram,
 1619     vnode_t dp, vnode_t todp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
 1620 {
 1621         u_int32_t *tl;
 1622         int error = 0, fdirfor_ret = 1, fdiraft_ret = 1;
 1623         int tdirfor_ret = 1, tdiraft_ret = 1;
 1624         struct nameidata fromnd, tond;
 1625         vnode_t fdirp = NULL, tdirp = NULL, tdp = NULL;
 1626         struct nfsvattr fdirfor, fdiraft, tdirfor, tdiraft;
 1627         struct nfsexstuff tnes;
 1628         struct nfsrvfh tfh;
 1629         char *bufp, *tbufp = NULL;
 1630         u_long *hashp;
 1631         fhandle_t fh;
 1632         struct thread *p = curthread;
 1633 
 1634         if (nd->nd_repstat) {
 1635                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
 1636                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
 1637                 goto out;
 1638         }
 1639         if (!(nd->nd_flag & ND_NFSV2))
 1640                 fdirfor_ret = nfsvno_getattr(dp, &fdirfor, nd, p, 1, NULL);
 1641         tond.ni_cnd.cn_nameiop = 0;
 1642         tond.ni_startdir = NULL;
 1643         NFSNAMEICNDSET(&fromnd.ni_cnd, nd->nd_cred, DELETE, WANTPARENT | SAVESTART);
 1644         nfsvno_setpathbuf(&fromnd, &bufp, &hashp);
 1645         error = nfsrv_parsename(nd, bufp, hashp, &fromnd.ni_pathlen);
 1646         if (error) {
 1647                 vput(dp);
 1648                 if (todp)
 1649                         vrele(todp);
 1650                 nfsvno_relpathbuf(&fromnd);
 1651                 goto out;
 1652         }
 1653         /*
 1654          * Unlock dp in this code section, so it is unlocked before
 1655          * tdp gets locked. This avoids a potential LOR if tdp is the
 1656          * parent directory of dp.
 1657          */
 1658         if (nd->nd_flag & ND_NFSV4) {
 1659                 tdp = todp;
 1660                 tnes = *toexp;
 1661                 if (dp != tdp) {
 1662                         NFSVOPUNLOCK(dp);
 1663                         /* Might lock tdp. */
 1664                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 0,
 1665                             NULL);
 1666                 } else {
 1667                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
 1668                             NULL);
 1669                         NFSVOPUNLOCK(dp);
 1670                 }
 1671         } else {
 1672                 tfh.nfsrvfh_len = 0;
 1673                 error = nfsrv_mtofh(nd, &tfh);
 1674                 if (error == 0)
 1675                         error = nfsvno_getfh(dp, &fh, p);
 1676                 if (error) {
 1677                         vput(dp);
 1678                         /* todp is always NULL except NFSv4 */
 1679                         nfsvno_relpathbuf(&fromnd);
 1680                         goto out;
 1681                 }
 1682 
 1683                 /* If this is the same file handle, just VREF() the vnode. */
 1684                 if (tfh.nfsrvfh_len == NFSX_MYFH &&
 1685                     !NFSBCMP(tfh.nfsrvfh_data, &fh, NFSX_MYFH)) {
 1686                         VREF(dp);
 1687                         tdp = dp;
 1688                         tnes = *exp;
 1689                         tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd, p, 1,
 1690                             NULL);
 1691                         NFSVOPUNLOCK(dp);
 1692                 } else {
 1693                         NFSVOPUNLOCK(dp);
 1694                         nd->nd_cred->cr_uid = nd->nd_saveduid;
 1695                         nfsd_fhtovp(nd, &tfh, LK_EXCLUSIVE, &tdp, &tnes, NULL,
 1696                             0, -1);     /* Locks tdp. */
 1697                         if (tdp) {
 1698                                 tdirfor_ret = nfsvno_getattr(tdp, &tdirfor, nd,
 1699                                     p, 1, NULL);
 1700                                 NFSVOPUNLOCK(tdp);
 1701                         }
 1702                 }
 1703         }
 1704         NFSNAMEICNDSET(&tond.ni_cnd, nd->nd_cred, RENAME, LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART);
 1705         nfsvno_setpathbuf(&tond, &tbufp, &hashp);
 1706         if (!nd->nd_repstat) {
 1707                 error = nfsrv_parsename(nd, tbufp, hashp, &tond.ni_pathlen);
 1708                 if (error) {
 1709                         if (tdp)
 1710                                 vrele(tdp);
 1711                         vrele(dp);
 1712                         nfsvno_relpathbuf(&fromnd);
 1713                         nfsvno_relpathbuf(&tond);
 1714                         goto out;
 1715                 }
 1716         }
 1717         if (nd->nd_repstat) {
 1718                 if (nd->nd_flag & ND_NFSV3) {
 1719                         nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
 1720                             &fdiraft);
 1721                         nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
 1722                             &tdiraft);
 1723                 }
 1724                 if (tdp)
 1725                         vrele(tdp);
 1726                 vrele(dp);
 1727                 nfsvno_relpathbuf(&fromnd);
 1728                 nfsvno_relpathbuf(&tond);
 1729                 goto out;
 1730         }
 1731 
 1732         /*
 1733          * Done parsing, now down to business.
 1734          */
 1735         nd->nd_repstat = nfsvno_namei(nd, &fromnd, dp, 0, exp, p, &fdirp);
 1736         if (nd->nd_repstat) {
 1737                 if (nd->nd_flag & ND_NFSV3) {
 1738                         nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret,
 1739                             &fdiraft);
 1740                         nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret,
 1741                             &tdiraft);
 1742                 }
 1743                 if (fdirp)
 1744                         vrele(fdirp);
 1745                 if (tdp)
 1746                         vrele(tdp);
 1747                 nfsvno_relpathbuf(&tond);
 1748                 goto out;
 1749         }
 1750         if (vnode_vtype(fromnd.ni_vp) == VDIR)
 1751                 tond.ni_cnd.cn_flags |= WILLBEDIR;
 1752         nd->nd_repstat = nfsvno_namei(nd, &tond, tdp, 0, &tnes, p, &tdirp);
 1753         nd->nd_repstat = nfsvno_rename(&fromnd, &tond, nd->nd_repstat,
 1754             nd->nd_flag, nd->nd_cred, p);
 1755         if (fdirp)
 1756                 fdiraft_ret = nfsvno_getattr(fdirp, &fdiraft, nd, p, 0, NULL);
 1757         if (tdirp)
 1758                 tdiraft_ret = nfsvno_getattr(tdirp, &tdiraft, nd, p, 0, NULL);
 1759         if (fdirp)
 1760                 vrele(fdirp);
 1761         if (tdirp)
 1762                 vrele(tdirp);
 1763         if (nd->nd_flag & ND_NFSV3) {
 1764                 nfsrv_wcc(nd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
 1765                 nfsrv_wcc(nd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
 1766         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1767                 NFSM_BUILD(tl, u_int32_t *, 10 * NFSX_UNSIGNED);
 1768                 *tl++ = newnfs_false;
 1769                 txdr_hyper(fdirfor.na_filerev, tl);
 1770                 tl += 2;
 1771                 txdr_hyper(fdiraft.na_filerev, tl);
 1772                 tl += 2;
 1773                 *tl++ = newnfs_false;
 1774                 txdr_hyper(tdirfor.na_filerev, tl);
 1775                 tl += 2;
 1776                 txdr_hyper(tdiraft.na_filerev, tl);
 1777         }
 1778 
 1779 out:
 1780         NFSEXITCODE2(error, nd);
 1781         return (error);
 1782 }
 1783 
 1784 /*
 1785  * nfs link service
 1786  */
 1787 int
 1788 nfsrvd_link(struct nfsrv_descript *nd, int isdgram,
 1789     vnode_t vp, vnode_t tovp, struct nfsexstuff *exp, struct nfsexstuff *toexp)
 1790 {
 1791         struct nameidata named;
 1792         u_int32_t *tl;
 1793         int error = 0, dirfor_ret = 1, diraft_ret = 1, getret = 1;
 1794         vnode_t dirp = NULL, dp = NULL;
 1795         struct nfsvattr dirfor, diraft, at;
 1796         struct nfsexstuff tnes;
 1797         struct nfsrvfh dfh;
 1798         char *bufp;
 1799         u_long *hashp;
 1800         struct thread *p = curthread;
 1801 
 1802         if (nd->nd_repstat) {
 1803                 nfsrv_postopattr(nd, getret, &at);
 1804                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1805                 goto out;
 1806         }
 1807         NFSVOPUNLOCK(vp);
 1808         if (vnode_vtype(vp) == VDIR) {
 1809                 if (nd->nd_flag & ND_NFSV4)
 1810                         nd->nd_repstat = NFSERR_ISDIR;
 1811                 else
 1812                         nd->nd_repstat = NFSERR_INVAL;
 1813                 if (tovp)
 1814                         vrele(tovp);
 1815         }
 1816         if (!nd->nd_repstat) {
 1817                 if (nd->nd_flag & ND_NFSV4) {
 1818                         dp = tovp;
 1819                         tnes = *toexp;
 1820                 } else {
 1821                         error = nfsrv_mtofh(nd, &dfh);
 1822                         if (error) {
 1823                                 vrele(vp);
 1824                                 /* tovp is always NULL unless NFSv4 */
 1825                                 goto out;
 1826                         }
 1827                         nfsd_fhtovp(nd, &dfh, LK_EXCLUSIVE, &dp, &tnes, NULL,
 1828                             0, -1);
 1829                         if (dp)
 1830                                 NFSVOPUNLOCK(dp);
 1831                 }
 1832         }
 1833         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1834             LOCKPARENT | SAVENAME | NOCACHE);
 1835         if (!nd->nd_repstat) {
 1836                 nfsvno_setpathbuf(&named, &bufp, &hashp);
 1837                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1838                 if (error) {
 1839                         vrele(vp);
 1840                         if (dp)
 1841                                 vrele(dp);
 1842                         nfsvno_relpathbuf(&named);
 1843                         goto out;
 1844                 }
 1845                 if (!nd->nd_repstat) {
 1846                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, &tnes,
 1847                             p, &dirp);
 1848                 } else {
 1849                         if (dp)
 1850                                 vrele(dp);
 1851                         nfsvno_relpathbuf(&named);
 1852                 }
 1853         }
 1854         if (dirp) {
 1855                 if (nd->nd_flag & ND_NFSV2) {
 1856                         vrele(dirp);
 1857                         dirp = NULL;
 1858                 } else {
 1859                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
 1860                             NULL);
 1861                 }
 1862         }
 1863         if (!nd->nd_repstat)
 1864                 nd->nd_repstat = nfsvno_link(&named, vp, nd->nd_cred, p, exp);
 1865         if (nd->nd_flag & ND_NFSV3)
 1866                 getret = nfsvno_getattr(vp, &at, nd, p, 0, NULL);
 1867         if (dirp) {
 1868                 diraft_ret = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
 1869                 vrele(dirp);
 1870         }
 1871         vrele(vp);
 1872         if (nd->nd_flag & ND_NFSV3) {
 1873                 nfsrv_postopattr(nd, getret, &at);
 1874                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1875         } else if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1876                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1877                 *tl++ = newnfs_false;
 1878                 txdr_hyper(dirfor.na_filerev, tl);
 1879                 tl += 2;
 1880                 txdr_hyper(diraft.na_filerev, tl);
 1881         }
 1882 
 1883 out:
 1884         NFSEXITCODE2(error, nd);
 1885         return (error);
 1886 }
 1887 
 1888 /*
 1889  * nfs symbolic link service
 1890  */
 1891 int
 1892 nfsrvd_symlink(struct nfsrv_descript *nd, __unused int isdgram,
 1893     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
 1894 {
 1895         struct nfsvattr nva, dirfor, diraft;
 1896         struct nameidata named;
 1897         int error = 0, dirfor_ret = 1, diraft_ret = 1, pathlen;
 1898         vnode_t dirp = NULL;
 1899         char *bufp, *pathcp = NULL;
 1900         u_long *hashp;
 1901         struct thread *p = curthread;
 1902 
 1903         if (nd->nd_repstat) {
 1904                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1905                 goto out;
 1906         }
 1907         if (vpp)
 1908                 *vpp = NULL;
 1909         NFSVNO_ATTRINIT(&nva);
 1910         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 1911             LOCKPARENT | SAVESTART | NOCACHE);
 1912         nfsvno_setpathbuf(&named, &bufp, &hashp);
 1913         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 1914         if (!error && !nd->nd_repstat)
 1915                 error = nfsvno_getsymlink(nd, &nva, p, &pathcp, &pathlen);
 1916         if (error) {
 1917                 vrele(dp);
 1918                 nfsvno_relpathbuf(&named);
 1919                 goto out;
 1920         }
 1921         if (!nd->nd_repstat) {
 1922                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
 1923         } else {
 1924                 vrele(dp);
 1925                 nfsvno_relpathbuf(&named);
 1926         }
 1927         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
 1928                 vrele(dirp);
 1929                 dirp = NULL;
 1930         }
 1931 
 1932         /*
 1933          * And call nfsrvd_symlinksub() to do the common code. It will
 1934          * return EBADRPC upon a parsing error, 0 otherwise.
 1935          */
 1936         if (!nd->nd_repstat) {
 1937                 if (dirp != NULL)
 1938                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
 1939                             NULL);
 1940                 nfsrvd_symlinksub(nd, &named, &nva, fhp, vpp, dirp,
 1941                     &dirfor, &diraft, &diraft_ret, NULL, NULL, p, exp,
 1942                     pathcp, pathlen);
 1943         } else if (dirp != NULL) {
 1944                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
 1945                 vrele(dirp);
 1946         }
 1947         if (pathcp)
 1948                 free(pathcp, M_TEMP);
 1949 
 1950         if (nd->nd_flag & ND_NFSV3) {
 1951                 if (!nd->nd_repstat) {
 1952                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
 1953                         nfsrv_postopattr(nd, 0, &nva);
 1954                 }
 1955                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 1956         }
 1957 
 1958 out:
 1959         NFSEXITCODE2(error, nd);
 1960         return (error);
 1961 }
 1962 
 1963 /*
 1964  * Common code for creating a symbolic link.
 1965  */
 1966 static void
 1967 nfsrvd_symlinksub(struct nfsrv_descript *nd, struct nameidata *ndp,
 1968     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
 1969     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
 1970     int *diraft_retp, nfsattrbit_t *attrbitp,
 1971     NFSACL_T *aclp, NFSPROC_T *p, struct nfsexstuff *exp, char *pathcp,
 1972     int pathlen)
 1973 {
 1974         u_int32_t *tl;
 1975 
 1976         nd->nd_repstat = nfsvno_symlink(ndp, nvap, pathcp, pathlen,
 1977             !(nd->nd_flag & ND_NFSV2), nd->nd_saveduid, nd->nd_cred, p, exp);
 1978         if (!nd->nd_repstat && !(nd->nd_flag & ND_NFSV2)) {
 1979                 nfsrv_fixattr(nd, ndp->ni_vp, nvap, aclp, p, attrbitp, exp);
 1980                 if (nd->nd_flag & ND_NFSV3) {
 1981                         nd->nd_repstat = nfsvno_getfh(ndp->ni_vp, fhp, p);
 1982                         if (!nd->nd_repstat)
 1983                                 nd->nd_repstat = nfsvno_getattr(ndp->ni_vp,
 1984                                     nvap, nd, p, 1, NULL);
 1985                 }
 1986                 if (vpp != NULL && nd->nd_repstat == 0) {
 1987                         NFSVOPUNLOCK(ndp->ni_vp);
 1988                         *vpp = ndp->ni_vp;
 1989                 } else
 1990                         vput(ndp->ni_vp);
 1991         }
 1992         if (dirp) {
 1993                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
 1994                 vrele(dirp);
 1995         }
 1996         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 1997                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 1998                 *tl++ = newnfs_false;
 1999                 txdr_hyper(dirforp->na_filerev, tl);
 2000                 tl += 2;
 2001                 txdr_hyper(diraftp->na_filerev, tl);
 2002                 (void) nfsrv_putattrbit(nd, attrbitp);
 2003         }
 2004 
 2005         NFSEXITCODE2(0, nd);
 2006 }
 2007 
 2008 /*
 2009  * nfs mkdir service
 2010  */
 2011 int
 2012 nfsrvd_mkdir(struct nfsrv_descript *nd, __unused int isdgram,
 2013     vnode_t dp, vnode_t *vpp, fhandle_t *fhp, struct nfsexstuff *exp)
 2014 {
 2015         struct nfsvattr nva, dirfor, diraft;
 2016         struct nameidata named;
 2017         u_int32_t *tl;
 2018         int error = 0, dirfor_ret = 1, diraft_ret = 1;
 2019         vnode_t dirp = NULL;
 2020         char *bufp;
 2021         u_long *hashp;
 2022         struct thread *p = curthread;
 2023 
 2024         if (nd->nd_repstat) {
 2025                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 2026                 goto out;
 2027         }
 2028         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 2029             LOCKPARENT | SAVENAME | NOCACHE);
 2030         nfsvno_setpathbuf(&named, &bufp, &hashp);
 2031         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 2032         if (error)
 2033                 goto nfsmout;
 2034         if (!nd->nd_repstat) {
 2035                 NFSVNO_ATTRINIT(&nva);
 2036                 if (nd->nd_flag & ND_NFSV3) {
 2037                         error = nfsrv_sattr(nd, NULL, &nva, NULL, NULL, p);
 2038                         if (error)
 2039                                 goto nfsmout;
 2040                 } else {
 2041                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2042                         nva.na_mode = nfstov_mode(*tl++);
 2043                 }
 2044         }
 2045         if (!nd->nd_repstat) {
 2046                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp, p, &dirp);
 2047         } else {
 2048                 vrele(dp);
 2049                 nfsvno_relpathbuf(&named);
 2050         }
 2051         if (dirp != NULL && !(nd->nd_flag & ND_NFSV3)) {
 2052                 vrele(dirp);
 2053                 dirp = NULL;
 2054         }
 2055         if (nd->nd_repstat) {
 2056                 if (dirp != NULL) {
 2057                         dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0,
 2058                             NULL);
 2059                         vrele(dirp);
 2060                 }
 2061                 if (nd->nd_flag & ND_NFSV3)
 2062                         nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret,
 2063                             &diraft);
 2064                 goto out;
 2065         }
 2066         if (dirp != NULL)
 2067                 dirfor_ret = nfsvno_getattr(dirp, &dirfor, nd, p, 0, NULL);
 2068 
 2069         /*
 2070          * Call nfsrvd_mkdirsub() for the code common to V4 as well.
 2071          */
 2072         nfsrvd_mkdirsub(nd, &named, &nva, fhp, vpp, dirp, &dirfor, &diraft,
 2073             &diraft_ret, NULL, NULL, p, exp);
 2074 
 2075         if (nd->nd_flag & ND_NFSV3) {
 2076                 if (!nd->nd_repstat) {
 2077                         (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 1);
 2078                         nfsrv_postopattr(nd, 0, &nva);
 2079                 }
 2080                 nfsrv_wcc(nd, dirfor_ret, &dirfor, diraft_ret, &diraft);
 2081         } else if (!nd->nd_repstat) {
 2082                 (void) nfsm_fhtom(nd, (u_int8_t *)fhp, 0, 0);
 2083                 nfsrv_fillattr(nd, &nva);
 2084         }
 2085 
 2086 out:
 2087         NFSEXITCODE2(0, nd);
 2088         return (0);
 2089 nfsmout:
 2090         vrele(dp);
 2091         nfsvno_relpathbuf(&named);
 2092         NFSEXITCODE2(error, nd);
 2093         return (error);
 2094 }
 2095 
 2096 /*
 2097  * Code common to mkdir for V2,3 and 4.
 2098  */
 2099 static void
 2100 nfsrvd_mkdirsub(struct nfsrv_descript *nd, struct nameidata *ndp,
 2101     struct nfsvattr *nvap, fhandle_t *fhp, vnode_t *vpp,
 2102     vnode_t dirp, struct nfsvattr *dirforp, struct nfsvattr *diraftp,
 2103     int *diraft_retp, nfsattrbit_t *attrbitp, NFSACL_T *aclp,
 2104     NFSPROC_T *p, struct nfsexstuff *exp)
 2105 {
 2106         vnode_t vp;
 2107         u_int32_t *tl;
 2108 
 2109         NFSVNO_SETATTRVAL(nvap, type, VDIR);
 2110         nd->nd_repstat = nfsvno_mkdir(ndp, nvap, nd->nd_saveduid,
 2111             nd->nd_cred, p, exp);
 2112         if (!nd->nd_repstat) {
 2113                 vp = ndp->ni_vp;
 2114                 nfsrv_fixattr(nd, vp, nvap, aclp, p, attrbitp, exp);
 2115                 nd->nd_repstat = nfsvno_getfh(vp, fhp, p);
 2116                 if (!(nd->nd_flag & ND_NFSV4) && !nd->nd_repstat)
 2117                         nd->nd_repstat = nfsvno_getattr(vp, nvap, nd, p, 1,
 2118                             NULL);
 2119                 if (vpp && !nd->nd_repstat) {
 2120                         NFSVOPUNLOCK(vp);
 2121                         *vpp = vp;
 2122                 } else {
 2123                         vput(vp);
 2124                 }
 2125         }
 2126         if (dirp) {
 2127                 *diraft_retp = nfsvno_getattr(dirp, diraftp, nd, p, 0, NULL);
 2128                 vrele(dirp);
 2129         }
 2130         if ((nd->nd_flag & ND_NFSV4) && !nd->nd_repstat) {
 2131                 NFSM_BUILD(tl, u_int32_t *, 5 * NFSX_UNSIGNED);
 2132                 *tl++ = newnfs_false;
 2133                 txdr_hyper(dirforp->na_filerev, tl);
 2134                 tl += 2;
 2135                 txdr_hyper(diraftp->na_filerev, tl);
 2136                 (void) nfsrv_putattrbit(nd, attrbitp);
 2137         }
 2138 
 2139         NFSEXITCODE2(0, nd);
 2140 }
 2141 
 2142 /*
 2143  * nfs commit service
 2144  */
 2145 int
 2146 nfsrvd_commit(struct nfsrv_descript *nd, __unused int isdgram,
 2147     vnode_t vp, __unused struct nfsexstuff *exp)
 2148 {
 2149         struct nfsvattr bfor, aft;
 2150         u_int32_t *tl;
 2151         int error = 0, for_ret = 1, aft_ret = 1, cnt;
 2152         u_int64_t off;
 2153         struct thread *p = curthread;
 2154 
 2155        if (nd->nd_repstat) {
 2156                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
 2157                 goto out;
 2158         }
 2159 
 2160         /* Return NFSERR_ISDIR in NFSv4 when commit on a directory. */
 2161         if (vp->v_type != VREG) {
 2162                 if (nd->nd_flag & ND_NFSV3)
 2163                         error = NFSERR_NOTSUPP;
 2164                 else
 2165                         error = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_INVAL;
 2166                 goto nfsmout;
 2167         }
 2168         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 2169 
 2170         /*
 2171          * XXX At this time VOP_FSYNC() does not accept offset and byte
 2172          * count parameters, so these arguments are useless (someday maybe).
 2173          */
 2174         off = fxdr_hyper(tl);
 2175         tl += 2;
 2176         cnt = fxdr_unsigned(int, *tl);
 2177         if (nd->nd_flag & ND_NFSV3)
 2178                 for_ret = nfsvno_getattr(vp, &bfor, nd, p, 1, NULL);
 2179         nd->nd_repstat = nfsvno_fsync(vp, off, cnt, nd->nd_cred, p);
 2180         if (nd->nd_flag & ND_NFSV3) {
 2181                 aft_ret = nfsvno_getattr(vp, &aft, nd, p, 1, NULL);
 2182                 nfsrv_wcc(nd, for_ret, &bfor, aft_ret, &aft);
 2183         }
 2184         vput(vp);
 2185         if (!nd->nd_repstat) {
 2186                 NFSM_BUILD(tl, u_int32_t *, NFSX_VERF);
 2187                 *tl++ = txdr_unsigned(nfsboottime.tv_sec);
 2188                 *tl = txdr_unsigned(nfsboottime.tv_usec);
 2189         }
 2190 
 2191 out:
 2192         NFSEXITCODE2(0, nd);
 2193         return (0);
 2194 nfsmout:
 2195         vput(vp);
 2196         NFSEXITCODE2(error, nd);
 2197         return (error);
 2198 }
 2199 
 2200 /*
 2201  * nfs statfs service
 2202  */
 2203 int
 2204 nfsrvd_statfs(struct nfsrv_descript *nd, __unused int isdgram,
 2205     vnode_t vp, __unused struct nfsexstuff *exp)
 2206 {
 2207         struct statfs *sf;
 2208         u_int32_t *tl;
 2209         int getret = 1;
 2210         struct nfsvattr at;
 2211         u_quad_t tval;
 2212         struct thread *p = curthread;
 2213 
 2214         sf = NULL;
 2215         if (nd->nd_repstat) {
 2216                 nfsrv_postopattr(nd, getret, &at);
 2217                 goto out;
 2218         }
 2219         sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
 2220         nd->nd_repstat = nfsvno_statfs(vp, sf);
 2221         getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
 2222         vput(vp);
 2223         if (nd->nd_flag & ND_NFSV3)
 2224                 nfsrv_postopattr(nd, getret, &at);
 2225         if (nd->nd_repstat)
 2226                 goto out;
 2227         if (nd->nd_flag & ND_NFSV2) {
 2228                 NFSM_BUILD(tl, u_int32_t *, NFSX_V2STATFS);
 2229                 *tl++ = txdr_unsigned(NFS_V2MAXDATA);
 2230                 *tl++ = txdr_unsigned(sf->f_bsize);
 2231                 *tl++ = txdr_unsigned(sf->f_blocks);
 2232                 *tl++ = txdr_unsigned(sf->f_bfree);
 2233                 *tl = txdr_unsigned(sf->f_bavail);
 2234         } else {
 2235                 NFSM_BUILD(tl, u_int32_t *, NFSX_V3STATFS);
 2236                 tval = (u_quad_t)sf->f_blocks;
 2237                 tval *= (u_quad_t)sf->f_bsize;
 2238                 txdr_hyper(tval, tl); tl += 2;
 2239                 tval = (u_quad_t)sf->f_bfree;
 2240                 tval *= (u_quad_t)sf->f_bsize;
 2241                 txdr_hyper(tval, tl); tl += 2;
 2242                 tval = (u_quad_t)sf->f_bavail;
 2243                 tval *= (u_quad_t)sf->f_bsize;
 2244                 txdr_hyper(tval, tl); tl += 2;
 2245                 tval = (u_quad_t)sf->f_files;
 2246                 txdr_hyper(tval, tl); tl += 2;
 2247                 tval = (u_quad_t)sf->f_ffree;
 2248                 txdr_hyper(tval, tl); tl += 2;
 2249                 tval = (u_quad_t)sf->f_ffree;
 2250                 txdr_hyper(tval, tl); tl += 2;
 2251                 *tl = 0;
 2252         }
 2253 
 2254 out:
 2255         free(sf, M_STATFS);
 2256         NFSEXITCODE2(0, nd);
 2257         return (0);
 2258 }
 2259 
 2260 /*
 2261  * nfs fsinfo service
 2262  */
 2263 int
 2264 nfsrvd_fsinfo(struct nfsrv_descript *nd, int isdgram,
 2265     vnode_t vp, __unused struct nfsexstuff *exp)
 2266 {
 2267         u_int32_t *tl;
 2268         struct nfsfsinfo fs;
 2269         int getret = 1;
 2270         struct nfsvattr at;
 2271         struct thread *p = curthread;
 2272 
 2273         if (nd->nd_repstat) {
 2274                 nfsrv_postopattr(nd, getret, &at);
 2275                 goto out;
 2276         }
 2277         getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
 2278         nfsvno_getfs(&fs, isdgram);
 2279         vput(vp);
 2280         nfsrv_postopattr(nd, getret, &at);
 2281         NFSM_BUILD(tl, u_int32_t *, NFSX_V3FSINFO);
 2282         *tl++ = txdr_unsigned(fs.fs_rtmax);
 2283         *tl++ = txdr_unsigned(fs.fs_rtpref);
 2284         *tl++ = txdr_unsigned(fs.fs_rtmult);
 2285         *tl++ = txdr_unsigned(fs.fs_wtmax);
 2286         *tl++ = txdr_unsigned(fs.fs_wtpref);
 2287         *tl++ = txdr_unsigned(fs.fs_wtmult);
 2288         *tl++ = txdr_unsigned(fs.fs_dtpref);
 2289         txdr_hyper(fs.fs_maxfilesize, tl);
 2290         tl += 2;
 2291         txdr_nfsv3time(&fs.fs_timedelta, tl);
 2292         tl += 2;
 2293         *tl = txdr_unsigned(fs.fs_properties);
 2294 
 2295 out:
 2296         NFSEXITCODE2(0, nd);
 2297         return (0);
 2298 }
 2299 
 2300 /*
 2301  * nfs pathconf service
 2302  */
 2303 int
 2304 nfsrvd_pathconf(struct nfsrv_descript *nd, __unused int isdgram,
 2305     vnode_t vp, __unused struct nfsexstuff *exp)
 2306 {
 2307         struct nfsv3_pathconf *pc;
 2308         int getret = 1;
 2309         long linkmax, namemax, chownres, notrunc;
 2310         struct nfsvattr at;
 2311         struct thread *p = curthread;
 2312 
 2313         if (nd->nd_repstat) {
 2314                 nfsrv_postopattr(nd, getret, &at);
 2315                 goto out;
 2316         }
 2317         nd->nd_repstat = nfsvno_pathconf(vp, _PC_LINK_MAX, &linkmax,
 2318             nd->nd_cred, p);
 2319         if (!nd->nd_repstat)
 2320                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NAME_MAX, &namemax,
 2321                     nd->nd_cred, p);
 2322         if (!nd->nd_repstat)
 2323                 nd->nd_repstat=nfsvno_pathconf(vp, _PC_CHOWN_RESTRICTED,
 2324                     &chownres, nd->nd_cred, p);
 2325         if (!nd->nd_repstat)
 2326                 nd->nd_repstat = nfsvno_pathconf(vp, _PC_NO_TRUNC, &notrunc,
 2327                     nd->nd_cred, p);
 2328         getret = nfsvno_getattr(vp, &at, nd, p, 1, NULL);
 2329         vput(vp);
 2330         nfsrv_postopattr(nd, getret, &at);
 2331         if (!nd->nd_repstat) {
 2332                 NFSM_BUILD(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
 2333                 pc->pc_linkmax = txdr_unsigned(linkmax);
 2334                 pc->pc_namemax = txdr_unsigned(namemax);
 2335                 pc->pc_notrunc = txdr_unsigned(notrunc);
 2336                 pc->pc_chownrestricted = txdr_unsigned(chownres);
 2337 
 2338                 /*
 2339                  * These should probably be supported by VOP_PATHCONF(), but
 2340                  * until msdosfs is exportable (why would you want to?), the
 2341                  * Unix defaults should be ok.
 2342                  */
 2343                 pc->pc_caseinsensitive = newnfs_false;
 2344                 pc->pc_casepreserving = newnfs_true;
 2345         }
 2346 
 2347 out:
 2348         NFSEXITCODE2(0, nd);
 2349         return (0);
 2350 }
 2351 
 2352 /*
 2353  * nfsv4 lock service
 2354  */
 2355 int
 2356 nfsrvd_lock(struct nfsrv_descript *nd, __unused int isdgram,
 2357     vnode_t vp, struct nfsexstuff *exp)
 2358 {
 2359         u_int32_t *tl;
 2360         int i;
 2361         struct nfsstate *stp = NULL;
 2362         struct nfslock *lop;
 2363         struct nfslockconflict cf;
 2364         int error = 0;
 2365         u_short flags = NFSLCK_LOCK, lflags;
 2366         u_int64_t offset, len;
 2367         nfsv4stateid_t stateid;
 2368         nfsquad_t clientid;
 2369         struct thread *p = curthread;
 2370 
 2371         NFSM_DISSECT(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2372         i = fxdr_unsigned(int, *tl++);
 2373         switch (i) {
 2374         case NFSV4LOCKT_READW:
 2375                 flags |= NFSLCK_BLOCKING;
 2376         case NFSV4LOCKT_READ:
 2377                 lflags = NFSLCK_READ;
 2378                 break;
 2379         case NFSV4LOCKT_WRITEW:
 2380                 flags |= NFSLCK_BLOCKING;
 2381         case NFSV4LOCKT_WRITE:
 2382                 lflags = NFSLCK_WRITE;
 2383                 break;
 2384         default:
 2385                 nd->nd_repstat = NFSERR_BADXDR;
 2386                 goto nfsmout;
 2387         }
 2388         if (*tl++ == newnfs_true)
 2389                 flags |= NFSLCK_RECLAIM;
 2390         offset = fxdr_hyper(tl);
 2391         tl += 2;
 2392         len = fxdr_hyper(tl);
 2393         tl += 2;
 2394         if (*tl == newnfs_true)
 2395                 flags |= NFSLCK_OPENTOLOCK;
 2396         if (flags & NFSLCK_OPENTOLOCK) {
 2397                 NFSM_DISSECT(tl, u_int32_t *, 5 * NFSX_UNSIGNED + NFSX_STATEID);
 2398                 i = fxdr_unsigned(int, *(tl+4+(NFSX_STATEID / NFSX_UNSIGNED)));
 2399                 if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2400                         nd->nd_repstat = NFSERR_BADXDR;
 2401                         goto nfsmout;
 2402                 }
 2403                 stp = malloc(sizeof (struct nfsstate) + i,
 2404                         M_NFSDSTATE, M_WAITOK);
 2405                 stp->ls_ownerlen = i;
 2406                 stp->ls_op = nd->nd_rp;
 2407                 stp->ls_seq = fxdr_unsigned(int, *tl++);
 2408                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2409                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2410                         NFSX_STATEIDOTHER);
 2411                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2412 
 2413                 /*
 2414                  * For the special stateid of other all 0s and seqid == 1, set
 2415                  * the stateid to the current stateid, if it is set.
 2416                  */
 2417                 if ((nd->nd_flag & ND_NFSV41) != 0 &&
 2418                     stp->ls_stateid.seqid == 1 &&
 2419                     stp->ls_stateid.other[0] == 0 &&
 2420                     stp->ls_stateid.other[1] == 0 &&
 2421                     stp->ls_stateid.other[2] == 0) {
 2422                         if ((nd->nd_flag & ND_CURSTATEID) != 0) {
 2423                                 stp->ls_stateid = nd->nd_curstateid;
 2424                                 stp->ls_stateid.seqid = 0;
 2425                         } else {
 2426                                 nd->nd_repstat = NFSERR_BADSTATEID;
 2427                                 goto nfsmout;
 2428                         }
 2429                 }
 2430 
 2431                 stp->ls_opentolockseq = fxdr_unsigned(int, *tl++);
 2432                 clientid.lval[0] = *tl++;
 2433                 clientid.lval[1] = *tl++;
 2434                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 2435                         if ((nd->nd_flag & ND_NFSV41) != 0)
 2436                                 clientid.qval = nd->nd_clientid.qval;
 2437                         else if (nd->nd_clientid.qval != clientid.qval)
 2438                                 printf("EEK3 multiple clids\n");
 2439                 } else {
 2440                         if ((nd->nd_flag & ND_NFSV41) != 0)
 2441                                 printf("EEK! no clientid from session\n");
 2442                         nd->nd_flag |= ND_IMPLIEDCLID;
 2443                         nd->nd_clientid.qval = clientid.qval;
 2444                 }
 2445                 error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2446                 if (error)
 2447                         goto nfsmout;
 2448         } else {
 2449                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 2450                 stp = malloc(sizeof (struct nfsstate),
 2451                         M_NFSDSTATE, M_WAITOK);
 2452                 stp->ls_ownerlen = 0;
 2453                 stp->ls_op = nd->nd_rp;
 2454                 stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2455                 NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2456                         NFSX_STATEIDOTHER);
 2457                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2458 
 2459                 /*
 2460                  * For the special stateid of other all 0s and seqid == 1, set
 2461                  * the stateid to the current stateid, if it is set.
 2462                  */
 2463                 if ((nd->nd_flag & ND_NFSV41) != 0 &&
 2464                     stp->ls_stateid.seqid == 1 &&
 2465                     stp->ls_stateid.other[0] == 0 &&
 2466                     stp->ls_stateid.other[1] == 0 &&
 2467                     stp->ls_stateid.other[2] == 0) {
 2468                         if ((nd->nd_flag & ND_CURSTATEID) != 0) {
 2469                                 stp->ls_stateid = nd->nd_curstateid;
 2470                                 stp->ls_stateid.seqid = 0;
 2471                         } else {
 2472                                 nd->nd_repstat = NFSERR_BADSTATEID;
 2473                                 goto nfsmout;
 2474                         }
 2475                 }
 2476 
 2477                 stp->ls_seq = fxdr_unsigned(int, *tl);
 2478                 clientid.lval[0] = stp->ls_stateid.other[0];
 2479                 clientid.lval[1] = stp->ls_stateid.other[1];
 2480                 if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 2481                         if ((nd->nd_flag & ND_NFSV41) != 0)
 2482                                 clientid.qval = nd->nd_clientid.qval;
 2483                         else if (nd->nd_clientid.qval != clientid.qval)
 2484                                 printf("EEK4 multiple clids\n");
 2485                 } else {
 2486                         if ((nd->nd_flag & ND_NFSV41) != 0)
 2487                                 printf("EEK! no clientid from session\n");
 2488                         nd->nd_flag |= ND_IMPLIEDCLID;
 2489                         nd->nd_clientid.qval = clientid.qval;
 2490                 }
 2491         }
 2492         lop = malloc(sizeof (struct nfslock),
 2493                 M_NFSDLOCK, M_WAITOK);
 2494         lop->lo_first = offset;
 2495         if (len == NFS64BITSSET) {
 2496                 lop->lo_end = NFS64BITSSET;
 2497         } else {
 2498                 lop->lo_end = offset + len;
 2499                 if (lop->lo_end <= lop->lo_first)
 2500                         nd->nd_repstat = NFSERR_INVAL;
 2501         }
 2502         lop->lo_flags = lflags;
 2503         stp->ls_flags = flags;
 2504         stp->ls_uid = nd->nd_cred->cr_uid;
 2505 
 2506         /*
 2507          * Do basic access checking.
 2508          */
 2509         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2510             if (vnode_vtype(vp) == VDIR)
 2511                 nd->nd_repstat = NFSERR_ISDIR;
 2512             else
 2513                 nd->nd_repstat = NFSERR_INVAL;
 2514         }
 2515         if (!nd->nd_repstat) {
 2516             if (lflags & NFSLCK_WRITE) {
 2517                 nd->nd_repstat = nfsvno_accchk(vp, VWRITE,
 2518                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2519                     NFSACCCHK_VPISLOCKED, NULL);
 2520             } else {
 2521                 nd->nd_repstat = nfsvno_accchk(vp, VREAD,
 2522                     nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2523                     NFSACCCHK_VPISLOCKED, NULL);
 2524                 if (nd->nd_repstat)
 2525                     nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
 2526                         nd->nd_cred, exp, p, NFSACCCHK_ALLOWOWNER,
 2527                         NFSACCCHK_VPISLOCKED, NULL);
 2528             }
 2529         }
 2530 
 2531         /*
 2532          * We call nfsrv_lockctrl() even if nd_repstat set, so that the
 2533          * seqid# gets updated. nfsrv_lockctrl() will return the value
 2534          * of nd_repstat, if it gets that far.
 2535          */
 2536         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid, 
 2537                 &stateid, exp, nd, p);
 2538         if (lop)
 2539                 free(lop, M_NFSDLOCK);
 2540         if (stp)
 2541                 free(stp, M_NFSDSTATE);
 2542         if (!nd->nd_repstat) {
 2543                 /* For NFSv4.1, set the Current StateID. */
 2544                 if ((nd->nd_flag & ND_NFSV41) != 0) {
 2545                         nd->nd_curstateid = stateid;
 2546                         nd->nd_flag |= ND_CURSTATEID;
 2547                 }
 2548                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2549                 *tl++ = txdr_unsigned(stateid.seqid);
 2550                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2551         } else if (nd->nd_repstat == NFSERR_DENIED) {
 2552                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2553                 txdr_hyper(cf.cl_first, tl);
 2554                 tl += 2;
 2555                 if (cf.cl_end == NFS64BITSSET)
 2556                         len = NFS64BITSSET;
 2557                 else
 2558                         len = cf.cl_end - cf.cl_first;
 2559                 txdr_hyper(len, tl);
 2560                 tl += 2;
 2561                 if (cf.cl_flags == NFSLCK_WRITE)
 2562                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 2563                 else
 2564                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 2565                 *tl++ = stateid.other[0];
 2566                 *tl = stateid.other[1];
 2567                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
 2568         }
 2569         vput(vp);
 2570         NFSEXITCODE2(0, nd);
 2571         return (0);
 2572 nfsmout:
 2573         vput(vp);
 2574         if (stp)
 2575                 free(stp, M_NFSDSTATE);
 2576         NFSEXITCODE2(error, nd);
 2577         return (error);
 2578 }
 2579 
 2580 /*
 2581  * nfsv4 lock test service
 2582  */
 2583 int
 2584 nfsrvd_lockt(struct nfsrv_descript *nd, __unused int isdgram,
 2585     vnode_t vp, struct nfsexstuff *exp)
 2586 {
 2587         u_int32_t *tl;
 2588         int i;
 2589         struct nfsstate *stp = NULL;
 2590         struct nfslock lo, *lop = &lo;
 2591         struct nfslockconflict cf;
 2592         int error = 0;
 2593         nfsv4stateid_t stateid;
 2594         nfsquad_t clientid;
 2595         u_int64_t len;
 2596         struct thread *p = curthread;
 2597 
 2598         NFSM_DISSECT(tl, u_int32_t *, 8 * NFSX_UNSIGNED);
 2599         i = fxdr_unsigned(int, *(tl + 7));
 2600         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2601                 nd->nd_repstat = NFSERR_BADXDR;
 2602                 goto nfsmout;
 2603         }
 2604         stp = malloc(sizeof (struct nfsstate) + i,
 2605             M_NFSDSTATE, M_WAITOK);
 2606         stp->ls_ownerlen = i;
 2607         stp->ls_op = NULL;
 2608         stp->ls_flags = NFSLCK_TEST;
 2609         stp->ls_uid = nd->nd_cred->cr_uid;
 2610         i = fxdr_unsigned(int, *tl++);
 2611         switch (i) {
 2612         case NFSV4LOCKT_READW:
 2613                 stp->ls_flags |= NFSLCK_BLOCKING;
 2614         case NFSV4LOCKT_READ:
 2615                 lo.lo_flags = NFSLCK_READ;
 2616                 break;
 2617         case NFSV4LOCKT_WRITEW:
 2618                 stp->ls_flags |= NFSLCK_BLOCKING;
 2619         case NFSV4LOCKT_WRITE:
 2620                 lo.lo_flags = NFSLCK_WRITE;
 2621                 break;
 2622         default:
 2623                 nd->nd_repstat = NFSERR_BADXDR;
 2624                 goto nfsmout;
 2625         }
 2626         lo.lo_first = fxdr_hyper(tl);
 2627         tl += 2;
 2628         len = fxdr_hyper(tl);
 2629         if (len == NFS64BITSSET) {
 2630                 lo.lo_end = NFS64BITSSET;
 2631         } else {
 2632                 lo.lo_end = lo.lo_first + len;
 2633                 if (lo.lo_end <= lo.lo_first)
 2634                         nd->nd_repstat = NFSERR_INVAL;
 2635         }
 2636         tl += 2;
 2637         clientid.lval[0] = *tl++;
 2638         clientid.lval[1] = *tl;
 2639         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 2640                 if ((nd->nd_flag & ND_NFSV41) != 0)
 2641                         clientid.qval = nd->nd_clientid.qval;
 2642                 else if (nd->nd_clientid.qval != clientid.qval)
 2643                         printf("EEK5 multiple clids\n");
 2644         } else {
 2645                 if ((nd->nd_flag & ND_NFSV41) != 0)
 2646                         printf("EEK! no clientid from session\n");
 2647                 nd->nd_flag |= ND_IMPLIEDCLID;
 2648                 nd->nd_clientid.qval = clientid.qval;
 2649         }
 2650         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2651         if (error)
 2652                 goto nfsmout;
 2653         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2654             if (vnode_vtype(vp) == VDIR)
 2655                 nd->nd_repstat = NFSERR_ISDIR;
 2656             else
 2657                 nd->nd_repstat = NFSERR_INVAL;
 2658         }
 2659         if (!nd->nd_repstat)
 2660           nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, &cf, clientid,
 2661             &stateid, exp, nd, p);
 2662         if (nd->nd_repstat) {
 2663             if (nd->nd_repstat == NFSERR_DENIED) {
 2664                 NFSM_BUILD(tl, u_int32_t *, 7 * NFSX_UNSIGNED);
 2665                 txdr_hyper(cf.cl_first, tl);
 2666                 tl += 2;
 2667                 if (cf.cl_end == NFS64BITSSET)
 2668                         len = NFS64BITSSET;
 2669                 else
 2670                         len = cf.cl_end - cf.cl_first;
 2671                 txdr_hyper(len, tl);
 2672                 tl += 2;
 2673                 if (cf.cl_flags == NFSLCK_WRITE)
 2674                         *tl++ = txdr_unsigned(NFSV4LOCKT_WRITE);
 2675                 else
 2676                         *tl++ = txdr_unsigned(NFSV4LOCKT_READ);
 2677                 *tl++ = stp->ls_stateid.other[0];
 2678                 *tl = stp->ls_stateid.other[1];
 2679                 (void) nfsm_strtom(nd, cf.cl_owner, cf.cl_ownerlen);
 2680             }
 2681         }
 2682         vput(vp);
 2683         if (stp)
 2684                 free(stp, M_NFSDSTATE);
 2685         NFSEXITCODE2(0, nd);
 2686         return (0);
 2687 nfsmout:
 2688         vput(vp);
 2689         if (stp)
 2690                 free(stp, M_NFSDSTATE);
 2691         NFSEXITCODE2(error, nd);
 2692         return (error);
 2693 }
 2694 
 2695 /*
 2696  * nfsv4 unlock service
 2697  */
 2698 int
 2699 nfsrvd_locku(struct nfsrv_descript *nd, __unused int isdgram,
 2700     vnode_t vp, struct nfsexstuff *exp)
 2701 {
 2702         u_int32_t *tl;
 2703         int i;
 2704         struct nfsstate *stp;
 2705         struct nfslock *lop;
 2706         int error = 0;
 2707         nfsv4stateid_t stateid;
 2708         nfsquad_t clientid;
 2709         u_int64_t len;
 2710         struct thread *p = curthread;
 2711 
 2712         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED + NFSX_STATEID);
 2713         stp = malloc(sizeof (struct nfsstate),
 2714             M_NFSDSTATE, M_WAITOK);
 2715         lop = malloc(sizeof (struct nfslock),
 2716             M_NFSDLOCK, M_WAITOK);
 2717         stp->ls_flags = NFSLCK_UNLOCK;
 2718         lop->lo_flags = NFSLCK_UNLOCK;
 2719         stp->ls_op = nd->nd_rp;
 2720         i = fxdr_unsigned(int, *tl++);
 2721         switch (i) {
 2722         case NFSV4LOCKT_READW:
 2723                 stp->ls_flags |= NFSLCK_BLOCKING;
 2724         case NFSV4LOCKT_READ:
 2725                 break;
 2726         case NFSV4LOCKT_WRITEW:
 2727                 stp->ls_flags |= NFSLCK_BLOCKING;
 2728         case NFSV4LOCKT_WRITE:
 2729                 break;
 2730         default:
 2731                 nd->nd_repstat = NFSERR_BADXDR;
 2732                 free(stp, M_NFSDSTATE);
 2733                 free(lop, M_NFSDLOCK);
 2734                 goto nfsmout;
 2735         }
 2736         stp->ls_ownerlen = 0;
 2737         stp->ls_uid = nd->nd_cred->cr_uid;
 2738         stp->ls_seq = fxdr_unsigned(int, *tl++);
 2739         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 2740         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 2741             NFSX_STATEIDOTHER);
 2742         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 2743 
 2744         /*
 2745          * For the special stateid of other all 0s and seqid == 1, set the
 2746          * stateid to the current stateid, if it is set.
 2747          */
 2748         if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
 2749             stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
 2750             stp->ls_stateid.other[2] == 0) {
 2751                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
 2752                         stp->ls_stateid = nd->nd_curstateid;
 2753                         stp->ls_stateid.seqid = 0;
 2754                 } else {
 2755                         nd->nd_repstat = NFSERR_BADSTATEID;
 2756                         free(stp, M_NFSDSTATE);
 2757                         free(lop, M_NFSDLOCK);
 2758                         goto nfsmout;
 2759                 }
 2760         }
 2761 
 2762         lop->lo_first = fxdr_hyper(tl);
 2763         tl += 2;
 2764         len = fxdr_hyper(tl);
 2765         if (len == NFS64BITSSET) {
 2766                 lop->lo_end = NFS64BITSSET;
 2767         } else {
 2768                 lop->lo_end = lop->lo_first + len;
 2769                 if (lop->lo_end <= lop->lo_first)
 2770                         nd->nd_repstat = NFSERR_INVAL;
 2771         }
 2772         clientid.lval[0] = stp->ls_stateid.other[0];
 2773         clientid.lval[1] = stp->ls_stateid.other[1];
 2774         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 2775                 if ((nd->nd_flag & ND_NFSV41) != 0)
 2776                         clientid.qval = nd->nd_clientid.qval;
 2777                 else if (nd->nd_clientid.qval != clientid.qval)
 2778                         printf("EEK6 multiple clids\n");
 2779         } else {
 2780                 if ((nd->nd_flag & ND_NFSV41) != 0)
 2781                         printf("EEK! no clientid from session\n");
 2782                 nd->nd_flag |= ND_IMPLIEDCLID;
 2783                 nd->nd_clientid.qval = clientid.qval;
 2784         }
 2785         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 2786             if (vnode_vtype(vp) == VDIR)
 2787                 nd->nd_repstat = NFSERR_ISDIR;
 2788             else
 2789                 nd->nd_repstat = NFSERR_INVAL;
 2790         }
 2791         /*
 2792          * Call nfsrv_lockctrl() even if nd_repstat is set, so that the
 2793          * seqid# gets incremented. nfsrv_lockctrl() will return the
 2794          * value of nd_repstat, if it gets that far.
 2795          */
 2796         nd->nd_repstat = nfsrv_lockctrl(vp, &stp, &lop, NULL, clientid,
 2797             &stateid, exp, nd, p);
 2798         if (stp)
 2799                 free(stp, M_NFSDSTATE);
 2800         if (lop)
 2801                 free(lop, M_NFSDLOCK);
 2802         if (!nd->nd_repstat) {
 2803                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 2804                 *tl++ = txdr_unsigned(stateid.seqid);
 2805                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 2806         }
 2807 nfsmout:
 2808         vput(vp);
 2809         NFSEXITCODE2(error, nd);
 2810         return (error);
 2811 }
 2812 
 2813 /*
 2814  * nfsv4 open service
 2815  */
 2816 int
 2817 nfsrvd_open(struct nfsrv_descript *nd, __unused int isdgram,
 2818     vnode_t dp, vnode_t *vpp, __unused fhandle_t *fhp, struct nfsexstuff *exp)
 2819 {
 2820         u_int32_t *tl;
 2821         int i, retext;
 2822         struct nfsstate *stp = NULL;
 2823         int error = 0, create, claim, exclusive_flag = 0, override;
 2824         u_int32_t rflags = NFSV4OPEN_LOCKTYPEPOSIX, acemask;
 2825         int how = NFSCREATE_UNCHECKED;
 2826         int32_t cverf[2], tverf[2] = { 0, 0 };
 2827         vnode_t vp = NULL, dirp = NULL;
 2828         struct nfsvattr nva, dirfor, diraft;
 2829         struct nameidata named;
 2830         nfsv4stateid_t stateid, delegstateid;
 2831         nfsattrbit_t attrbits;
 2832         nfsquad_t clientid;
 2833         char *bufp = NULL;
 2834         u_long *hashp;
 2835         NFSACL_T *aclp = NULL;
 2836         struct thread *p = curthread;
 2837 
 2838 #ifdef NFS4_ACL_EXTATTR_NAME
 2839         aclp = acl_alloc(M_WAITOK);
 2840         aclp->acl_cnt = 0;
 2841 #endif
 2842         NFSZERO_ATTRBIT(&attrbits);
 2843         named.ni_startdir = NULL;
 2844         named.ni_cnd.cn_nameiop = 0;
 2845         NFSM_DISSECT(tl, u_int32_t *, 6 * NFSX_UNSIGNED);
 2846         i = fxdr_unsigned(int, *(tl + 5));
 2847         if (i <= 0 || i > NFSV4_OPAQUELIMIT) {
 2848                 nd->nd_repstat = NFSERR_BADXDR;
 2849                 goto nfsmout;
 2850         }
 2851         stp = malloc(sizeof (struct nfsstate) + i,
 2852             M_NFSDSTATE, M_WAITOK);
 2853         stp->ls_ownerlen = i;
 2854         stp->ls_op = nd->nd_rp;
 2855         stp->ls_flags = NFSLCK_OPEN;
 2856         stp->ls_uid = nd->nd_cred->cr_uid;
 2857         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 2858         i = fxdr_unsigned(int, *tl++);
 2859         retext = 0;
 2860         if ((i & (NFSV4OPEN_WANTDELEGMASK | NFSV4OPEN_WANTSIGNALDELEG |
 2861             NFSV4OPEN_WANTPUSHDELEG)) != 0 && (nd->nd_flag & ND_NFSV41) != 0) {
 2862                 retext = 1;
 2863                 /* For now, ignore these. */
 2864                 i &= ~(NFSV4OPEN_WANTPUSHDELEG | NFSV4OPEN_WANTSIGNALDELEG);
 2865                 switch (i & NFSV4OPEN_WANTDELEGMASK) {
 2866                 case NFSV4OPEN_WANTANYDELEG:
 2867                         stp->ls_flags |= (NFSLCK_WANTRDELEG |
 2868                             NFSLCK_WANTWDELEG);
 2869                         i &= ~NFSV4OPEN_WANTDELEGMASK;
 2870                         break;
 2871                 case NFSV4OPEN_WANTREADDELEG:
 2872                         stp->ls_flags |= NFSLCK_WANTRDELEG;
 2873                         i &= ~NFSV4OPEN_WANTDELEGMASK;
 2874                         break;
 2875                 case NFSV4OPEN_WANTWRITEDELEG:
 2876                         stp->ls_flags |= NFSLCK_WANTWDELEG;
 2877                         i &= ~NFSV4OPEN_WANTDELEGMASK;
 2878                         break;
 2879                 case NFSV4OPEN_WANTNODELEG:
 2880                         stp->ls_flags |= NFSLCK_WANTNODELEG;
 2881                         i &= ~NFSV4OPEN_WANTDELEGMASK;
 2882                         break;
 2883                 case NFSV4OPEN_WANTCANCEL:
 2884                         printf("NFSv4: ignore Open WantCancel\n");
 2885                         i &= ~NFSV4OPEN_WANTDELEGMASK;
 2886                         break;
 2887                 default:
 2888                         /* nd_repstat will be set to NFSERR_INVAL below. */
 2889                         break;
 2890                 }
 2891         }
 2892         switch (i) {
 2893         case NFSV4OPEN_ACCESSREAD:
 2894                 stp->ls_flags |= NFSLCK_READACCESS;
 2895                 break;
 2896         case NFSV4OPEN_ACCESSWRITE:
 2897                 stp->ls_flags |= NFSLCK_WRITEACCESS;
 2898                 break;
 2899         case NFSV4OPEN_ACCESSBOTH:
 2900                 stp->ls_flags |= (NFSLCK_READACCESS | NFSLCK_WRITEACCESS);
 2901                 break;
 2902         default:
 2903                 nd->nd_repstat = NFSERR_INVAL;
 2904         }
 2905         i = fxdr_unsigned(int, *tl++);
 2906         switch (i) {
 2907         case NFSV4OPEN_DENYNONE:
 2908                 break;
 2909         case NFSV4OPEN_DENYREAD:
 2910                 stp->ls_flags |= NFSLCK_READDENY;
 2911                 break;
 2912         case NFSV4OPEN_DENYWRITE:
 2913                 stp->ls_flags |= NFSLCK_WRITEDENY;
 2914                 break;
 2915         case NFSV4OPEN_DENYBOTH:
 2916                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
 2917                 break;
 2918         default:
 2919                 nd->nd_repstat = NFSERR_INVAL;
 2920         }
 2921         clientid.lval[0] = *tl++;
 2922         clientid.lval[1] = *tl;
 2923         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 2924                 if ((nd->nd_flag & ND_NFSV41) != 0)
 2925                         clientid.qval = nd->nd_clientid.qval;
 2926                 else if (nd->nd_clientid.qval != clientid.qval)
 2927                         printf("EEK7 multiple clids\n");
 2928         } else {
 2929                 if ((nd->nd_flag & ND_NFSV41) != 0)
 2930                         printf("EEK! no clientid from session\n");
 2931                 nd->nd_flag |= ND_IMPLIEDCLID;
 2932                 nd->nd_clientid.qval = clientid.qval;
 2933         }
 2934         error = nfsrv_mtostr(nd, stp->ls_owner, stp->ls_ownerlen);
 2935         if (error)
 2936                 goto nfsmout;
 2937         NFSVNO_ATTRINIT(&nva);
 2938         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2939         create = fxdr_unsigned(int, *tl);
 2940         if (!nd->nd_repstat)
 2941                 nd->nd_repstat = nfsvno_getattr(dp, &dirfor, nd, p, 0, NULL);
 2942         if (create == NFSV4OPEN_CREATE) {
 2943                 nva.na_type = VREG;
 2944                 nva.na_mode = 0;
 2945                 NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 2946                 how = fxdr_unsigned(int, *tl);
 2947                 switch (how) {
 2948                 case NFSCREATE_UNCHECKED:
 2949                 case NFSCREATE_GUARDED:
 2950                         error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
 2951                         if (error)
 2952                                 goto nfsmout;
 2953                         /*
 2954                          * If the na_gid being set is the same as that of
 2955                          * the directory it is going in, clear it, since
 2956                          * that is what will be set by default. This allows
 2957                          * a user that isn't in that group to do the create.
 2958                          */
 2959                         if (!nd->nd_repstat && NFSVNO_ISSETGID(&nva) &&
 2960                             nva.na_gid == dirfor.na_gid)
 2961                                 NFSVNO_UNSET(&nva, gid);
 2962                         if (!nd->nd_repstat)
 2963                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
 2964                         break;
 2965                 case NFSCREATE_EXCLUSIVE:
 2966                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 2967                         cverf[0] = *tl++;
 2968                         cverf[1] = *tl;
 2969                         break;
 2970                 case NFSCREATE_EXCLUSIVE41:
 2971                         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF);
 2972                         cverf[0] = *tl++;
 2973                         cverf[1] = *tl;
 2974                         error = nfsv4_sattr(nd, NULL, &nva, &attrbits, aclp, p);
 2975                         if (error != 0)
 2976                                 goto nfsmout;
 2977                         if (NFSISSET_ATTRBIT(&attrbits,
 2978                             NFSATTRBIT_TIMEACCESSSET))
 2979                                 nd->nd_repstat = NFSERR_INVAL;
 2980                         /*
 2981                          * If the na_gid being set is the same as that of
 2982                          * the directory it is going in, clear it, since
 2983                          * that is what will be set by default. This allows
 2984                          * a user that isn't in that group to do the create.
 2985                          */
 2986                         if (nd->nd_repstat == 0 && NFSVNO_ISSETGID(&nva) &&
 2987                             nva.na_gid == dirfor.na_gid)
 2988                                 NFSVNO_UNSET(&nva, gid);
 2989                         if (nd->nd_repstat == 0)
 2990                                 nd->nd_repstat = nfsrv_checkuidgid(nd, &nva);
 2991                         break;
 2992                 default:
 2993                         nd->nd_repstat = NFSERR_BADXDR;
 2994                         goto nfsmout;
 2995                 }
 2996         } else if (create != NFSV4OPEN_NOCREATE) {
 2997                 nd->nd_repstat = NFSERR_BADXDR;
 2998                 goto nfsmout;
 2999         }
 3000 
 3001         /*
 3002          * Now, handle the claim, which usually includes looking up a
 3003          * name in the directory referenced by dp. The exception is
 3004          * NFSV4OPEN_CLAIMPREVIOUS.
 3005          */
 3006         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3007         claim = fxdr_unsigned(int, *tl);
 3008         if (claim == NFSV4OPEN_CLAIMDELEGATECUR || claim ==
 3009             NFSV4OPEN_CLAIMDELEGATECURFH) {
 3010                 NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 3011                 stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3012                 NFSBCOPY((caddr_t)tl,(caddr_t)stateid.other,NFSX_STATEIDOTHER);
 3013                 stp->ls_flags |= NFSLCK_DELEGCUR;
 3014         } else if (claim == NFSV4OPEN_CLAIMDELEGATEPREV || claim ==
 3015             NFSV4OPEN_CLAIMDELEGATEPREVFH) {
 3016                 stp->ls_flags |= NFSLCK_DELEGPREV;
 3017         }
 3018         if (claim == NFSV4OPEN_CLAIMNULL || claim == NFSV4OPEN_CLAIMDELEGATECUR
 3019             || claim == NFSV4OPEN_CLAIMDELEGATEPREV) {
 3020                 if (!nd->nd_repstat && create == NFSV4OPEN_CREATE &&
 3021                     claim != NFSV4OPEN_CLAIMNULL)
 3022                         nd->nd_repstat = NFSERR_INVAL;
 3023                 if (nd->nd_repstat) {
 3024                         nd->nd_repstat = nfsrv_opencheck(clientid,
 3025                             &stateid, stp, NULL, nd, p, nd->nd_repstat);
 3026                         goto nfsmout;
 3027                 }
 3028                 if (create == NFSV4OPEN_CREATE)
 3029                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, CREATE,
 3030                         LOCKPARENT | LOCKLEAF | SAVESTART | NOCACHE);
 3031                 else
 3032                     NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
 3033                         LOCKLEAF | SAVESTART);
 3034                 nfsvno_setpathbuf(&named, &bufp, &hashp);
 3035                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 3036                 if (error) {
 3037                         vrele(dp);
 3038 #ifdef NFS4_ACL_EXTATTR_NAME
 3039                         acl_free(aclp);
 3040 #endif
 3041                         free(stp, M_NFSDSTATE);
 3042                         nfsvno_relpathbuf(&named);
 3043                         NFSEXITCODE2(error, nd);
 3044                         return (error);
 3045                 }
 3046                 if (!nd->nd_repstat) {
 3047                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 0, exp,
 3048                             p, &dirp);
 3049                 } else {
 3050                         vrele(dp);
 3051                         nfsvno_relpathbuf(&named);
 3052                 }
 3053                 if (create == NFSV4OPEN_CREATE) {
 3054                     switch (how) {
 3055                     case NFSCREATE_UNCHECKED:
 3056                         if (named.ni_vp) {
 3057                                 /*
 3058                                  * Clear the setable attribute bits, except
 3059                                  * for Size, if it is being truncated.
 3060                                  */
 3061                                 NFSZERO_ATTRBIT(&attrbits);
 3062                                 if (NFSVNO_ISSETSIZE(&nva))
 3063                                         NFSSETBIT_ATTRBIT(&attrbits,
 3064                                             NFSATTRBIT_SIZE);
 3065                         }
 3066                         break;
 3067                     case NFSCREATE_GUARDED:
 3068                         if (named.ni_vp && !nd->nd_repstat)
 3069                                 nd->nd_repstat = EEXIST;
 3070                         break;
 3071                     case NFSCREATE_EXCLUSIVE:
 3072                         exclusive_flag = 1;
 3073                         if (!named.ni_vp)
 3074                                 nva.na_mode = 0;
 3075                         break;
 3076                     case NFSCREATE_EXCLUSIVE41:
 3077                         exclusive_flag = 1;
 3078                         break;
 3079                     }
 3080                 }
 3081                 nfsvno_open(nd, &named, clientid, &stateid, stp,
 3082                     &exclusive_flag, &nva, cverf, create, aclp, &attrbits,
 3083                     nd->nd_cred, exp, &vp);
 3084         } else if (claim == NFSV4OPEN_CLAIMPREVIOUS || claim ==
 3085             NFSV4OPEN_CLAIMFH || claim == NFSV4OPEN_CLAIMDELEGATECURFH ||
 3086             claim == NFSV4OPEN_CLAIMDELEGATEPREVFH) {
 3087                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
 3088                         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 3089                         i = fxdr_unsigned(int, *tl);
 3090                         switch (i) {
 3091                         case NFSV4OPEN_DELEGATEREAD:
 3092                                 stp->ls_flags |= NFSLCK_DELEGREAD;
 3093                                 break;
 3094                         case NFSV4OPEN_DELEGATEWRITE:
 3095                                 stp->ls_flags |= NFSLCK_DELEGWRITE;
 3096                         case NFSV4OPEN_DELEGATENONE:
 3097                                 break;
 3098                         default:
 3099                                 nd->nd_repstat = NFSERR_BADXDR;
 3100                                 goto nfsmout;
 3101                         }
 3102                         stp->ls_flags |= NFSLCK_RECLAIM;
 3103                 } else {
 3104                         if (nd->nd_repstat == 0 && create == NFSV4OPEN_CREATE)
 3105                                 nd->nd_repstat = NFSERR_INVAL;
 3106                 }
 3107                 vp = dp;
 3108                 NFSVOPLOCK(vp, LK_EXCLUSIVE | LK_RETRY);
 3109                 if (!VN_IS_DOOMED(vp))
 3110                         nd->nd_repstat = nfsrv_opencheck(clientid, &stateid,
 3111                             stp, vp, nd, p, nd->nd_repstat);
 3112                 else
 3113                         nd->nd_repstat = NFSERR_PERM;
 3114         } else {
 3115                 nd->nd_repstat = NFSERR_BADXDR;
 3116                 goto nfsmout;
 3117         }
 3118 
 3119         /*
 3120          * Do basic access checking.
 3121          */
 3122         if (!nd->nd_repstat && vnode_vtype(vp) != VREG) {
 3123                 /*
 3124                  * The IETF working group decided that this is the correct
 3125                  * error return for all non-regular files.
 3126                  */
 3127                 nd->nd_repstat = (vp->v_type == VDIR) ? NFSERR_ISDIR : NFSERR_SYMLINK;
 3128         }
 3129 
 3130         /*
 3131          * If the Open is being done for a file that already exists, apply
 3132          * normal permission checking including for the file owner, if
 3133          * vfs.nfsd.v4openaccess is set.
 3134          * Previously, the owner was always allowed to open the file to
 3135          * be consistent with the NFS tradition of always allowing the
 3136          * owner of the file to write to the file regardless of permissions.
 3137          * It now appears that the Linux client expects the owner
 3138          * permissions to be checked for opens that are not creating the
 3139          * file.  I believe the correct approach is to use the Access
 3140          * operation's results to be consistent with NFSv3, but that is
 3141          * not what the current Linux client appears to be doing.
 3142          * Since both the Linux and OpenSolaris NFSv4 servers do this check,
 3143          * I have enabled it by default.  Since Linux does not apply this
 3144          * check for claim_delegate_cur, this code does the same.
 3145          * If this semantic change causes a problem, it can be disabled by
 3146          * setting the sysctl vfs.nfsd.v4openaccess to 0 to re-enable the
 3147          * previous semantics.
 3148          */
 3149         if (nfsrv_openaccess && create == NFSV4OPEN_NOCREATE &&
 3150             (stp->ls_flags & NFSLCK_DELEGCUR) == 0)
 3151                 override = NFSACCCHK_NOOVERRIDE;
 3152         else
 3153                 override = NFSACCCHK_ALLOWOWNER;
 3154         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_WRITEACCESS))
 3155             nd->nd_repstat = nfsvno_accchk(vp, VWRITE, nd->nd_cred,
 3156                 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
 3157         if (!nd->nd_repstat && (stp->ls_flags & NFSLCK_READACCESS)) {
 3158             nd->nd_repstat = nfsvno_accchk(vp, VREAD, nd->nd_cred,
 3159                 exp, p, override, NFSACCCHK_VPISLOCKED, NULL);
 3160             if (nd->nd_repstat)
 3161                 nd->nd_repstat = nfsvno_accchk(vp, VEXEC,
 3162                     nd->nd_cred, exp, p, override,
 3163                     NFSACCCHK_VPISLOCKED, NULL);
 3164         }
 3165 
 3166         if (!nd->nd_repstat) {
 3167                 nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 3168                 if (!nd->nd_repstat) {
 3169                         tverf[0] = nva.na_atime.tv_sec;
 3170                         tverf[1] = nva.na_atime.tv_nsec;
 3171                 }
 3172         }
 3173         if (!nd->nd_repstat && exclusive_flag && (cverf[0] != tverf[0] ||
 3174             cverf[1] != tverf[1]))
 3175                 nd->nd_repstat = EEXIST;
 3176         /*
 3177          * Do the open locking/delegation stuff.
 3178          */
 3179         if (!nd->nd_repstat)
 3180             nd->nd_repstat = nfsrv_openctrl(nd, vp, &stp, clientid, &stateid,
 3181                 &delegstateid, &rflags, exp, p, nva.na_filerev);
 3182 
 3183         /*
 3184          * vp must be unlocked before the call to nfsvno_getattr(dirp,...)
 3185          * below, to avoid a deadlock with the lookup in nfsvno_namei() above.
 3186          * (ie: Leave the NFSVOPUNLOCK() about here.)
 3187          */
 3188         if (vp)
 3189                 NFSVOPUNLOCK(vp);
 3190         if (stp)
 3191                 free(stp, M_NFSDSTATE);
 3192         if (!nd->nd_repstat && dirp)
 3193                 nd->nd_repstat = nfsvno_getattr(dirp, &diraft, nd, p, 0, NULL);
 3194         if (!nd->nd_repstat) {
 3195                 /* For NFSv4.1, set the Current StateID. */
 3196                 if ((nd->nd_flag & ND_NFSV41) != 0) {
 3197                         nd->nd_curstateid = stateid;
 3198                         nd->nd_flag |= ND_CURSTATEID;
 3199                 }
 3200                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID + 6 * NFSX_UNSIGNED);
 3201                 *tl++ = txdr_unsigned(stateid.seqid);
 3202                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 3203                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 3204                 if (claim == NFSV4OPEN_CLAIMPREVIOUS) {
 3205                         *tl++ = newnfs_true;
 3206                         *tl++ = 0;
 3207                         *tl++ = 0;
 3208                         *tl++ = 0;
 3209                         *tl++ = 0;
 3210                 } else {
 3211                         *tl++ = newnfs_false;   /* Since dirp is not locked */
 3212                         txdr_hyper(dirfor.na_filerev, tl);
 3213                         tl += 2;
 3214                         txdr_hyper(diraft.na_filerev, tl);
 3215                         tl += 2;
 3216                 }
 3217                 *tl = txdr_unsigned(rflags & NFSV4OPEN_RFLAGS);
 3218                 (void) nfsrv_putattrbit(nd, &attrbits);
 3219                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3220                 if (rflags & NFSV4OPEN_READDELEGATE)
 3221                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEREAD);
 3222                 else if (rflags & NFSV4OPEN_WRITEDELEGATE)
 3223                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATEWRITE);
 3224                 else if (retext != 0) {
 3225                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONEEXT);
 3226                         if ((rflags & NFSV4OPEN_WDNOTWANTED) != 0) {
 3227                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3228                                 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
 3229                         } else if ((rflags & NFSV4OPEN_WDSUPPFTYPE) != 0) {
 3230                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3231                                 *tl = txdr_unsigned(NFSV4OPEN_NOTSUPPFTYPE);
 3232                         } else if ((rflags & NFSV4OPEN_WDCONTENTION) != 0) {
 3233                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3234                                 *tl++ = txdr_unsigned(NFSV4OPEN_CONTENTION);
 3235                                 *tl = newnfs_false;
 3236                         } else if ((rflags & NFSV4OPEN_WDRESOURCE) != 0) {
 3237                                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3238                                 *tl++ = txdr_unsigned(NFSV4OPEN_RESOURCE);
 3239                                 *tl = newnfs_false;
 3240                         } else {
 3241                                 NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3242                                 *tl = txdr_unsigned(NFSV4OPEN_NOTWANTED);
 3243                         }
 3244                 } else
 3245                         *tl = txdr_unsigned(NFSV4OPEN_DELEGATENONE);
 3246                 if (rflags & (NFSV4OPEN_READDELEGATE|NFSV4OPEN_WRITEDELEGATE)) {
 3247                         NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID+NFSX_UNSIGNED);
 3248                         *tl++ = txdr_unsigned(delegstateid.seqid);
 3249                         NFSBCOPY((caddr_t)delegstateid.other, (caddr_t)tl,
 3250                             NFSX_STATEIDOTHER);
 3251                         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 3252                         if (rflags & NFSV4OPEN_RECALL)
 3253                                 *tl = newnfs_true;
 3254                         else
 3255                                 *tl = newnfs_false;
 3256                         if (rflags & NFSV4OPEN_WRITEDELEGATE) {
 3257                                 NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3258                                 *tl++ = txdr_unsigned(NFSV4OPEN_LIMITSIZE);
 3259                                 txdr_hyper(nva.na_size, tl);
 3260                         }
 3261                         NFSM_BUILD(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 3262                         *tl++ = txdr_unsigned(NFSV4ACE_ALLOWEDTYPE);
 3263                         *tl++ = txdr_unsigned(0x0);
 3264                         acemask = NFSV4ACE_ALLFILESMASK;
 3265                         if (nva.na_mode & S_IRUSR)
 3266                             acemask |= NFSV4ACE_READMASK;
 3267                         if (nva.na_mode & S_IWUSR)
 3268                             acemask |= NFSV4ACE_WRITEMASK;
 3269                         if (nva.na_mode & S_IXUSR)
 3270                             acemask |= NFSV4ACE_EXECUTEMASK;
 3271                         *tl = txdr_unsigned(acemask);
 3272                         (void) nfsm_strtom(nd, "OWNER@", 6);
 3273                 }
 3274                 *vpp = vp;
 3275         } else if (vp) {
 3276                 vrele(vp);
 3277         }
 3278         if (dirp)
 3279                 vrele(dirp);
 3280 #ifdef NFS4_ACL_EXTATTR_NAME
 3281         acl_free(aclp);
 3282 #endif
 3283         NFSEXITCODE2(0, nd);
 3284         return (0);
 3285 nfsmout:
 3286         vrele(dp);
 3287 #ifdef NFS4_ACL_EXTATTR_NAME
 3288         acl_free(aclp);
 3289 #endif
 3290         if (stp)
 3291                 free(stp, M_NFSDSTATE);
 3292         NFSEXITCODE2(error, nd);
 3293         return (error);
 3294 }
 3295 
 3296 /*
 3297  * nfsv4 close service
 3298  */
 3299 int
 3300 nfsrvd_close(struct nfsrv_descript *nd, __unused int isdgram,
 3301     vnode_t vp, __unused struct nfsexstuff *exp)
 3302 {
 3303         u_int32_t *tl;
 3304         struct nfsstate st, *stp = &st;
 3305         int error = 0, writeacc;
 3306         nfsv4stateid_t stateid;
 3307         nfsquad_t clientid;
 3308         struct nfsvattr na;
 3309         struct thread *p = curthread;
 3310 
 3311         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED + NFSX_STATEID);
 3312         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 3313         stp->ls_ownerlen = 0;
 3314         stp->ls_op = nd->nd_rp;
 3315         stp->ls_uid = nd->nd_cred->cr_uid;
 3316         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3317         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 3318             NFSX_STATEIDOTHER);
 3319 
 3320         /*
 3321          * For the special stateid of other all 0s and seqid == 1, set the
 3322          * stateid to the current stateid, if it is set.
 3323          */
 3324         if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
 3325             stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
 3326             stp->ls_stateid.other[2] == 0) {
 3327                 if ((nd->nd_flag & ND_CURSTATEID) != 0)
 3328                         stp->ls_stateid = nd->nd_curstateid;
 3329                 else {
 3330                         nd->nd_repstat = NFSERR_BADSTATEID;
 3331                         goto nfsmout;
 3332                 }
 3333         }
 3334 
 3335         stp->ls_flags = NFSLCK_CLOSE;
 3336         clientid.lval[0] = stp->ls_stateid.other[0];
 3337         clientid.lval[1] = stp->ls_stateid.other[1];
 3338         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 3339                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3340                         clientid.qval = nd->nd_clientid.qval;
 3341                 else if (nd->nd_clientid.qval != clientid.qval)
 3342                         printf("EEK8 multiple clids\n");
 3343         } else {
 3344                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3345                         printf("EEK! no clientid from session\n");
 3346                 nd->nd_flag |= ND_IMPLIEDCLID;
 3347                 nd->nd_clientid.qval = clientid.qval;
 3348         }
 3349         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
 3350             &writeacc);
 3351         /* For pNFS, update the attributes. */
 3352         if (writeacc != 0 || nfsrv_pnfsatime != 0)
 3353                 nfsrv_updatemdsattr(vp, &na, p);
 3354         vput(vp);
 3355         if (!nd->nd_repstat) {
 3356                 /*
 3357                  * If the stateid that has been closed is the current stateid,
 3358                  * unset it.
 3359                  */
 3360                 if ((nd->nd_flag & ND_CURSTATEID) != 0 &&
 3361                     stateid.other[0] == nd->nd_curstateid.other[0] &&
 3362                     stateid.other[1] == nd->nd_curstateid.other[1] &&
 3363                     stateid.other[2] == nd->nd_curstateid.other[2])
 3364                         nd->nd_flag &= ~ND_CURSTATEID;
 3365                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 3366                 *tl++ = txdr_unsigned(stateid.seqid);
 3367                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 3368         }
 3369         NFSEXITCODE2(0, nd);
 3370         return (0);
 3371 nfsmout:
 3372         vput(vp);
 3373         NFSEXITCODE2(error, nd);
 3374         return (error);
 3375 }
 3376 
 3377 /*
 3378  * nfsv4 delegpurge service
 3379  */
 3380 int
 3381 nfsrvd_delegpurge(struct nfsrv_descript *nd, __unused int isdgram,
 3382     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 3383 {
 3384         u_int32_t *tl;
 3385         int error = 0;
 3386         nfsquad_t clientid;
 3387         struct thread *p = curthread;
 3388 
 3389         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 3390                 goto nfsmout;
 3391         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3392         clientid.lval[0] = *tl++;
 3393         clientid.lval[1] = *tl;
 3394         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 3395                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3396                         clientid.qval = nd->nd_clientid.qval;
 3397                 else if (nd->nd_clientid.qval != clientid.qval)
 3398                         printf("EEK9 multiple clids\n");
 3399         } else {
 3400                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3401                         printf("EEK! no clientid from session\n");
 3402                 nd->nd_flag |= ND_IMPLIEDCLID;
 3403                 nd->nd_clientid.qval = clientid.qval;
 3404         }
 3405         nd->nd_repstat = nfsrv_delegupdate(nd, clientid, NULL, NULL,
 3406             NFSV4OP_DELEGPURGE, nd->nd_cred, p, NULL);
 3407 nfsmout:
 3408         NFSEXITCODE2(error, nd);
 3409         return (error);
 3410 }
 3411 
 3412 /*
 3413  * nfsv4 delegreturn service
 3414  */
 3415 int
 3416 nfsrvd_delegreturn(struct nfsrv_descript *nd, __unused int isdgram,
 3417     vnode_t vp, __unused struct nfsexstuff *exp)
 3418 {
 3419         u_int32_t *tl;
 3420         int error = 0, writeacc;
 3421         nfsv4stateid_t stateid;
 3422         nfsquad_t clientid;
 3423         struct nfsvattr na;
 3424         struct thread *p = curthread;
 3425 
 3426         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID);
 3427         stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3428         NFSBCOPY((caddr_t)tl, (caddr_t)stateid.other, NFSX_STATEIDOTHER);
 3429         clientid.lval[0] = stateid.other[0];
 3430         clientid.lval[1] = stateid.other[1];
 3431         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 3432                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3433                         clientid.qval = nd->nd_clientid.qval;
 3434                 else if (nd->nd_clientid.qval != clientid.qval)
 3435                         printf("EEK10 multiple clids\n");
 3436         } else {
 3437                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3438                         printf("EEK! no clientid from session\n");
 3439                 nd->nd_flag |= ND_IMPLIEDCLID;
 3440                 nd->nd_clientid.qval = clientid.qval;
 3441         }
 3442         nd->nd_repstat = nfsrv_delegupdate(nd, clientid, &stateid, vp,
 3443             NFSV4OP_DELEGRETURN, nd->nd_cred, p, &writeacc);
 3444         /* For pNFS, update the attributes. */
 3445         if (writeacc != 0 || nfsrv_pnfsatime != 0)
 3446                 nfsrv_updatemdsattr(vp, &na, p);
 3447 nfsmout:
 3448         vput(vp);
 3449         NFSEXITCODE2(error, nd);
 3450         return (error);
 3451 }
 3452 
 3453 /*
 3454  * nfsv4 get file handle service
 3455  */
 3456 int
 3457 nfsrvd_getfh(struct nfsrv_descript *nd, __unused int isdgram,
 3458     vnode_t vp, __unused struct nfsexstuff *exp)
 3459 {
 3460         fhandle_t fh;
 3461         struct thread *p = curthread;
 3462 
 3463         nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 3464         vput(vp);
 3465         if (!nd->nd_repstat)
 3466                 (void) nfsm_fhtom(nd, (u_int8_t *)&fh, 0, 0);
 3467         NFSEXITCODE2(0, nd);
 3468         return (0);
 3469 }
 3470 
 3471 /*
 3472  * nfsv4 open confirm service
 3473  */
 3474 int
 3475 nfsrvd_openconfirm(struct nfsrv_descript *nd, __unused int isdgram,
 3476     vnode_t vp, __unused struct nfsexstuff *exp)
 3477 {
 3478         u_int32_t *tl;
 3479         struct nfsstate st, *stp = &st;
 3480         int error = 0;
 3481         nfsv4stateid_t stateid;
 3482         nfsquad_t clientid;
 3483         struct thread *p = curthread;
 3484 
 3485         if ((nd->nd_flag & ND_NFSV41) != 0) {
 3486                 nd->nd_repstat = NFSERR_NOTSUPP;
 3487                 goto nfsmout;
 3488         }
 3489         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + NFSX_UNSIGNED);
 3490         stp->ls_ownerlen = 0;
 3491         stp->ls_op = nd->nd_rp;
 3492         stp->ls_uid = nd->nd_cred->cr_uid;
 3493         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3494         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 3495             NFSX_STATEIDOTHER);
 3496         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 3497         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl);
 3498         stp->ls_flags = NFSLCK_CONFIRM;
 3499         clientid.lval[0] = stp->ls_stateid.other[0];
 3500         clientid.lval[1] = stp->ls_stateid.other[1];
 3501         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 3502                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3503                         clientid.qval = nd->nd_clientid.qval;
 3504                 else if (nd->nd_clientid.qval != clientid.qval)
 3505                         printf("EEK11 multiple clids\n");
 3506         } else {
 3507                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3508                         printf("EEK! no clientid from session\n");
 3509                 nd->nd_flag |= ND_IMPLIEDCLID;
 3510                 nd->nd_clientid.qval = clientid.qval;
 3511         }
 3512         nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid, nd, p,
 3513             NULL);
 3514         if (!nd->nd_repstat) {
 3515                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 3516                 *tl++ = txdr_unsigned(stateid.seqid);
 3517                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 3518         }
 3519 nfsmout:
 3520         vput(vp);
 3521         NFSEXITCODE2(error, nd);
 3522         return (error);
 3523 }
 3524 
 3525 /*
 3526  * nfsv4 open downgrade service
 3527  */
 3528 int
 3529 nfsrvd_opendowngrade(struct nfsrv_descript *nd, __unused int isdgram,
 3530     vnode_t vp, __unused struct nfsexstuff *exp)
 3531 {
 3532         u_int32_t *tl;
 3533         int i;
 3534         struct nfsstate st, *stp = &st;
 3535         int error = 0;
 3536         nfsv4stateid_t stateid;
 3537         nfsquad_t clientid;
 3538         struct thread *p = curthread;
 3539 
 3540         /* opendowngrade can only work on a file object.*/
 3541         if (vp->v_type != VREG) {
 3542                 error = NFSERR_INVAL;
 3543                 goto nfsmout;
 3544         }
 3545         NFSM_DISSECT(tl, u_int32_t *, NFSX_STATEID + 3 * NFSX_UNSIGNED);
 3546         stp->ls_ownerlen = 0;
 3547         stp->ls_op = nd->nd_rp;
 3548         stp->ls_uid = nd->nd_cred->cr_uid;
 3549         stp->ls_stateid.seqid = fxdr_unsigned(u_int32_t, *tl++);
 3550         NFSBCOPY((caddr_t)tl, (caddr_t)stp->ls_stateid.other,
 3551             NFSX_STATEIDOTHER);
 3552         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 3553 
 3554         /*
 3555          * For the special stateid of other all 0s and seqid == 1, set the
 3556          * stateid to the current stateid, if it is set.
 3557          */
 3558         if ((nd->nd_flag & ND_NFSV41) != 0 && stp->ls_stateid.seqid == 1 &&
 3559             stp->ls_stateid.other[0] == 0 && stp->ls_stateid.other[1] == 0 &&
 3560             stp->ls_stateid.other[2] == 0) {
 3561                 if ((nd->nd_flag & ND_CURSTATEID) != 0)
 3562                         stp->ls_stateid = nd->nd_curstateid;
 3563                 else {
 3564                         nd->nd_repstat = NFSERR_BADSTATEID;
 3565                         goto nfsmout;
 3566                 }
 3567         }
 3568 
 3569         stp->ls_seq = fxdr_unsigned(u_int32_t, *tl++);
 3570         i = fxdr_unsigned(int, *tl++);
 3571         if ((nd->nd_flag & ND_NFSV41) != 0)
 3572                 i &= ~NFSV4OPEN_WANTDELEGMASK;
 3573         switch (i) {
 3574         case NFSV4OPEN_ACCESSREAD:
 3575                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_DOWNGRADE);
 3576                 break;
 3577         case NFSV4OPEN_ACCESSWRITE:
 3578                 stp->ls_flags = (NFSLCK_WRITEACCESS | NFSLCK_DOWNGRADE);
 3579                 break;
 3580         case NFSV4OPEN_ACCESSBOTH:
 3581                 stp->ls_flags = (NFSLCK_READACCESS | NFSLCK_WRITEACCESS |
 3582                     NFSLCK_DOWNGRADE);
 3583                 break;
 3584         default:
 3585                 nd->nd_repstat = NFSERR_INVAL;
 3586         }
 3587         i = fxdr_unsigned(int, *tl);
 3588         switch (i) {
 3589         case NFSV4OPEN_DENYNONE:
 3590                 break;
 3591         case NFSV4OPEN_DENYREAD:
 3592                 stp->ls_flags |= NFSLCK_READDENY;
 3593                 break;
 3594         case NFSV4OPEN_DENYWRITE:
 3595                 stp->ls_flags |= NFSLCK_WRITEDENY;
 3596                 break;
 3597         case NFSV4OPEN_DENYBOTH:
 3598                 stp->ls_flags |= (NFSLCK_READDENY | NFSLCK_WRITEDENY);
 3599                 break;
 3600         default:
 3601                 nd->nd_repstat = NFSERR_INVAL;
 3602         }
 3603 
 3604         clientid.lval[0] = stp->ls_stateid.other[0];
 3605         clientid.lval[1] = stp->ls_stateid.other[1];
 3606         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 3607                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3608                         clientid.qval = nd->nd_clientid.qval;
 3609                 else if (nd->nd_clientid.qval != clientid.qval)
 3610                         printf("EEK12 multiple clids\n");
 3611         } else {
 3612                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3613                         printf("EEK! no clientid from session\n");
 3614                 nd->nd_flag |= ND_IMPLIEDCLID;
 3615                 nd->nd_clientid.qval = clientid.qval;
 3616         }
 3617         if (!nd->nd_repstat)
 3618                 nd->nd_repstat = nfsrv_openupdate(vp, stp, clientid, &stateid,
 3619                     nd, p, NULL);
 3620         if (!nd->nd_repstat) {
 3621                 /* For NFSv4.1, set the Current StateID. */
 3622                 if ((nd->nd_flag & ND_NFSV41) != 0) {
 3623                         nd->nd_curstateid = stateid;
 3624                         nd->nd_flag |= ND_CURSTATEID;
 3625                 }
 3626                 NFSM_BUILD(tl, u_int32_t *, NFSX_STATEID);
 3627                 *tl++ = txdr_unsigned(stateid.seqid);
 3628                 NFSBCOPY((caddr_t)stateid.other,(caddr_t)tl,NFSX_STATEIDOTHER);
 3629         }
 3630 nfsmout:
 3631         vput(vp);
 3632         NFSEXITCODE2(error, nd);
 3633         return (error);
 3634 }
 3635 
 3636 /*
 3637  * nfsv4 renew lease service
 3638  */
 3639 int
 3640 nfsrvd_renew(struct nfsrv_descript *nd, __unused int isdgram,
 3641     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 3642 {
 3643         u_int32_t *tl;
 3644         int error = 0;
 3645         nfsquad_t clientid;
 3646         struct thread *p = curthread;
 3647 
 3648         if ((nd->nd_flag & ND_NFSV41) != 0) {
 3649                 nd->nd_repstat = NFSERR_NOTSUPP;
 3650                 goto nfsmout;
 3651         }
 3652         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 3653                 goto nfsmout;
 3654         NFSM_DISSECT(tl, u_int32_t *, NFSX_HYPER);
 3655         clientid.lval[0] = *tl++;
 3656         clientid.lval[1] = *tl;
 3657         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 3658                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3659                         clientid.qval = nd->nd_clientid.qval;
 3660                 else if (nd->nd_clientid.qval != clientid.qval)
 3661                         printf("EEK13 multiple clids\n");
 3662         } else {
 3663                 if ((nd->nd_flag & ND_NFSV41) != 0)
 3664                         printf("EEK! no clientid from session\n");
 3665                 nd->nd_flag |= ND_IMPLIEDCLID;
 3666                 nd->nd_clientid.qval = clientid.qval;
 3667         }
 3668         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_RENEWOP|CLOPS_RENEW),
 3669             NULL, NULL, (nfsquad_t)((u_quad_t)0), 0, nd, p);
 3670 nfsmout:
 3671         NFSEXITCODE2(error, nd);
 3672         return (error);
 3673 }
 3674 
 3675 /*
 3676  * nfsv4 security info service
 3677  */
 3678 int
 3679 nfsrvd_secinfo(struct nfsrv_descript *nd, int isdgram,
 3680     vnode_t dp, struct nfsexstuff *exp)
 3681 {
 3682         u_int32_t *tl;
 3683         int len;
 3684         struct nameidata named;
 3685         vnode_t dirp = NULL, vp;
 3686         struct nfsrvfh fh;
 3687         struct nfsexstuff retnes;
 3688         u_int32_t *sizp;
 3689         int error = 0, i;
 3690         uint64_t savflag;
 3691         char *bufp;
 3692         u_long *hashp;
 3693         struct thread *p = curthread;
 3694 
 3695         /*
 3696          * All this just to get the export flags for the name.
 3697          */
 3698         NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
 3699             LOCKLEAF | SAVESTART);
 3700         nfsvno_setpathbuf(&named, &bufp, &hashp);
 3701         error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 3702         if (error) {
 3703                 vput(dp);
 3704                 nfsvno_relpathbuf(&named);
 3705                 goto out;
 3706         }
 3707         if (!nd->nd_repstat) {
 3708                 nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
 3709         } else {
 3710                 vput(dp);
 3711                 nfsvno_relpathbuf(&named);
 3712         }
 3713         if (dirp)
 3714                 vrele(dirp);
 3715         if (nd->nd_repstat)
 3716                 goto out;
 3717         vrele(named.ni_startdir);
 3718         nfsvno_relpathbuf(&named);
 3719         fh.nfsrvfh_len = NFSX_MYFH;
 3720         vp = named.ni_vp;
 3721         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
 3722         vput(vp);
 3723         savflag = nd->nd_flag;
 3724         if (!nd->nd_repstat) {
 3725                 /*
 3726                  * Pretend the next op is Secinfo, so that no wrongsec
 3727                  * test will be done.
 3728                  */
 3729                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
 3730                     NFSV4OP_SECINFO);
 3731                 if (vp)
 3732                         vput(vp);
 3733         }
 3734         nd->nd_flag = savflag;
 3735         if (nd->nd_repstat)
 3736                 goto out;
 3737 
 3738         /*
 3739          * Finally have the export flags for name, so we can create
 3740          * the security info.
 3741          */
 3742         len = 0;
 3743         NFSM_BUILD(sizp, u_int32_t *, NFSX_UNSIGNED);
 3744 
 3745         /* If nes_numsecflavor == 0, all are allowed. */
 3746         if (retnes.nes_numsecflavor == 0) {
 3747                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 3748                 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
 3749                 *tl = txdr_unsigned(RPCAUTH_GSS);
 3750                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3751                     nfsgss_mechlist[KERBV_MECH].len);
 3752                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
 3753                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3754                 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
 3755                 *tl = txdr_unsigned(RPCAUTH_GSS);
 3756                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3757                     nfsgss_mechlist[KERBV_MECH].len);
 3758                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
 3759                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3760                 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
 3761                 *tl = txdr_unsigned(RPCAUTH_GSS);
 3762                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3763                     nfsgss_mechlist[KERBV_MECH].len);
 3764                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 3765                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3766                 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
 3767                 len = 4;
 3768         }
 3769         for (i = 0; i < retnes.nes_numsecflavor; i++) {
 3770                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
 3771                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3772                         *tl = txdr_unsigned(RPCAUTH_UNIX);
 3773                         len++;
 3774                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
 3775                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3776                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3777                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3778                             nfsgss_mechlist[KERBV_MECH].len);
 3779                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3780                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3781                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
 3782                         len++;
 3783                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
 3784                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3785                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3786                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3787                             nfsgss_mechlist[KERBV_MECH].len);
 3788                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3789                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3790                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
 3791                         len++;
 3792                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
 3793                         NFSM_BUILD(tl, u_int32_t *, NFSX_UNSIGNED);
 3794                         *tl++ = txdr_unsigned(RPCAUTH_GSS);
 3795                         (void) nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3796                             nfsgss_mechlist[KERBV_MECH].len);
 3797                         NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 3798                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3799                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
 3800                         len++;
 3801                 }
 3802         }
 3803         *sizp = txdr_unsigned(len);
 3804 
 3805 out:
 3806         NFSEXITCODE2(error, nd);
 3807         return (error);
 3808 }
 3809 
 3810 /*
 3811  * nfsv4 security info no name service
 3812  */
 3813 int
 3814 nfsrvd_secinfononame(struct nfsrv_descript *nd, int isdgram,
 3815     vnode_t dp, struct nfsexstuff *exp)
 3816 {
 3817         uint32_t *tl, *sizp;
 3818         struct nameidata named;
 3819         vnode_t dirp = NULL, vp;
 3820         struct nfsrvfh fh;
 3821         struct nfsexstuff retnes;
 3822         int error = 0, fhstyle, i, len;
 3823         uint64_t savflag;
 3824         char *bufp;
 3825         u_long *hashp;
 3826         struct thread *p = curthread;
 3827 
 3828         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 3829         fhstyle = fxdr_unsigned(int, *tl);
 3830         switch (fhstyle) {
 3831         case NFSSECINFONONAME_PARENT:
 3832                 if (dp->v_type != VDIR) {
 3833                         vput(dp);
 3834                         nd->nd_repstat = NFSERR_NOTDIR;
 3835                         goto nfsmout;
 3836                 }
 3837                 NFSNAMEICNDSET(&named.ni_cnd, nd->nd_cred, LOOKUP,
 3838                     LOCKLEAF | SAVESTART);
 3839                 nfsvno_setpathbuf(&named, &bufp, &hashp);
 3840                 error = nfsrv_parsename(nd, bufp, hashp, &named.ni_pathlen);
 3841                 if (error != 0) {
 3842                         vput(dp);
 3843                         nfsvno_relpathbuf(&named);
 3844                         goto nfsmout;
 3845                 }
 3846                 if (nd->nd_repstat == 0)
 3847                         nd->nd_repstat = nfsvno_namei(nd, &named, dp, 1, exp, p, &dirp);
 3848                 else
 3849                         vput(dp);
 3850                 if (dirp != NULL)
 3851                         vrele(dirp);
 3852                 vrele(named.ni_startdir);
 3853                 nfsvno_relpathbuf(&named);
 3854                 vp = named.ni_vp;
 3855                 break;
 3856         case NFSSECINFONONAME_CURFH:
 3857                 vp = dp;
 3858                 break;
 3859         default:
 3860                 nd->nd_repstat = NFSERR_INVAL;
 3861                 vput(dp);
 3862         }
 3863         if (nd->nd_repstat != 0)
 3864                 goto nfsmout;
 3865         fh.nfsrvfh_len = NFSX_MYFH;
 3866         nd->nd_repstat = nfsvno_getfh(vp, (fhandle_t *)fh.nfsrvfh_data, p);
 3867         vput(vp);
 3868         savflag = nd->nd_flag;
 3869         if (nd->nd_repstat == 0) {
 3870                 /*
 3871                  * Pretend the next op is Secinfo, so that no wrongsec
 3872                  * test will be done.
 3873                  */
 3874                 nfsd_fhtovp(nd, &fh, LK_SHARED, &vp, &retnes, NULL, 0,
 3875                     NFSV4OP_SECINFO);
 3876                 if (vp != NULL)
 3877                         vput(vp);
 3878         }
 3879         nd->nd_flag = savflag;
 3880         if (nd->nd_repstat != 0)
 3881                 goto nfsmout;
 3882 
 3883         /*
 3884          * Finally have the export flags for fh/parent, so we can create
 3885          * the security info.
 3886          */
 3887         len = 0;
 3888         NFSM_BUILD(sizp, uint32_t *, NFSX_UNSIGNED);
 3889 
 3890         /* If nes_numsecflavor == 0, all are allowed. */
 3891         if (retnes.nes_numsecflavor == 0) {
 3892                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 3893                 *tl++ = txdr_unsigned(RPCAUTH_UNIX);
 3894                 *tl = txdr_unsigned(RPCAUTH_GSS);
 3895                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3896                     nfsgss_mechlist[KERBV_MECH].len);
 3897                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
 3898                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3899                 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCNONE);
 3900                 *tl = txdr_unsigned(RPCAUTH_GSS);
 3901                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3902                     nfsgss_mechlist[KERBV_MECH].len);
 3903                 NFSM_BUILD(tl, uint32_t *, 3 * NFSX_UNSIGNED);
 3904                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3905                 *tl++ = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
 3906                 *tl = txdr_unsigned(RPCAUTH_GSS);
 3907                 nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3908                     nfsgss_mechlist[KERBV_MECH].len);
 3909                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 3910                 *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3911                 *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
 3912                 len = 4;
 3913         }
 3914         for (i = 0; i < retnes.nes_numsecflavor; i++) {
 3915                 if (retnes.nes_secflavors[i] == AUTH_SYS) {
 3916                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 3917                         *tl = txdr_unsigned(RPCAUTH_UNIX);
 3918                         len++;
 3919                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5) {
 3920                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 3921                         *tl = txdr_unsigned(RPCAUTH_GSS);
 3922                         nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3923                             nfsgss_mechlist[KERBV_MECH].len);
 3924                         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 3925                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3926                         *tl = txdr_unsigned(RPCAUTHGSS_SVCNONE);
 3927                         len++;
 3928                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5I) {
 3929                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 3930                         *tl = txdr_unsigned(RPCAUTH_GSS);
 3931                         nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3932                             nfsgss_mechlist[KERBV_MECH].len);
 3933                         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 3934                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3935                         *tl = txdr_unsigned(RPCAUTHGSS_SVCINTEGRITY);
 3936                         len++;
 3937                 } else if (retnes.nes_secflavors[i] == RPCSEC_GSS_KRB5P) {
 3938                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 3939                         *tl = txdr_unsigned(RPCAUTH_GSS);
 3940                         nfsm_strtom(nd, nfsgss_mechlist[KERBV_MECH].str,
 3941                             nfsgss_mechlist[KERBV_MECH].len);
 3942                         NFSM_BUILD(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 3943                         *tl++ = txdr_unsigned(GSS_KERBV_QOP);
 3944                         *tl = txdr_unsigned(RPCAUTHGSS_SVCPRIVACY);
 3945                         len++;
 3946                 }
 3947         }
 3948         *sizp = txdr_unsigned(len);
 3949 
 3950 nfsmout:
 3951         NFSEXITCODE2(error, nd);
 3952         return (error);
 3953 }
 3954 
 3955 /*
 3956  * nfsv4 set client id service
 3957  */
 3958 int
 3959 nfsrvd_setclientid(struct nfsrv_descript *nd, __unused int isdgram,
 3960     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 3961 {
 3962         u_int32_t *tl;
 3963         int i;
 3964         int error = 0, idlen;
 3965         struct nfsclient *clp = NULL;
 3966 #ifdef INET
 3967         struct sockaddr_in *rin;
 3968 #endif
 3969 #ifdef INET6
 3970         struct sockaddr_in6 *rin6;
 3971 #endif
 3972 #if defined(INET) || defined(INET6)
 3973         u_char *ucp, *ucp2;
 3974 #endif
 3975         u_char *verf, *addrbuf;
 3976         nfsquad_t clientid, confirm;
 3977         struct thread *p = curthread;
 3978 
 3979         if ((nd->nd_flag & ND_NFSV41) != 0) {
 3980                 nd->nd_repstat = NFSERR_NOTSUPP;
 3981                 goto nfsmout;
 3982         }
 3983         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 3984                 goto out;
 3985         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
 3986         verf = (u_char *)tl;
 3987         tl += (NFSX_VERF / NFSX_UNSIGNED);
 3988         i = fxdr_unsigned(int, *tl);
 3989         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
 3990                 nd->nd_repstat = NFSERR_BADXDR;
 3991                 goto nfsmout;
 3992         }
 3993         idlen = i;
 3994         if (nd->nd_flag & ND_GSS)
 3995                 i += nd->nd_princlen;
 3996         clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
 3997             M_ZERO);
 3998         clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
 3999             nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
 4000         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
 4001         /* Allocated large enough for an AF_INET or AF_INET6 socket. */
 4002         clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
 4003             M_WAITOK | M_ZERO);
 4004         clp->lc_req.nr_cred = NULL;
 4005         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
 4006         clp->lc_idlen = idlen;
 4007         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
 4008         if (error)
 4009                 goto nfsmout;
 4010         if (nd->nd_flag & ND_GSS) {
 4011                 clp->lc_flags = LCL_GSS;
 4012                 if (nd->nd_flag & ND_GSSINTEGRITY)
 4013                         clp->lc_flags |= LCL_GSSINTEGRITY;
 4014                 else if (nd->nd_flag & ND_GSSPRIVACY)
 4015                         clp->lc_flags |= LCL_GSSPRIVACY;
 4016         } else {
 4017                 clp->lc_flags = 0;
 4018         }
 4019         if ((nd->nd_flag & ND_GSS) && nd->nd_princlen > 0) {
 4020                 clp->lc_flags |= LCL_NAME;
 4021                 clp->lc_namelen = nd->nd_princlen;
 4022                 clp->lc_name = &clp->lc_id[idlen];
 4023                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
 4024         } else {
 4025                 clp->lc_uid = nd->nd_cred->cr_uid;
 4026                 clp->lc_gid = nd->nd_cred->cr_gid;
 4027         }
 4028 
 4029         /* If the client is using TLS, do so for the callback connection. */
 4030         if (nd->nd_flag & ND_TLS)
 4031                 clp->lc_flags |= LCL_TLSCB;
 4032 
 4033         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4034         clp->lc_program = fxdr_unsigned(u_int32_t, *tl);
 4035         error = nfsrv_getclientipaddr(nd, clp);
 4036         if (error)
 4037                 goto nfsmout;
 4038         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4039         clp->lc_callback = fxdr_unsigned(u_int32_t, *tl);
 4040 
 4041         /*
 4042          * nfsrv_setclient() does the actual work of adding it to the
 4043          * client list. If there is no error, the structure has been
 4044          * linked into the client list and clp should no longer be used
 4045          * here. When an error is returned, it has not been linked in,
 4046          * so it should be free'd.
 4047          */
 4048         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
 4049         if (nd->nd_repstat == NFSERR_CLIDINUSE) {
 4050                 /*
 4051                  * 8 is the maximum length of the port# string.
 4052                  */
 4053                 addrbuf = malloc(INET6_ADDRSTRLEN + 8, M_TEMP, M_WAITOK);
 4054                 switch (clp->lc_req.nr_nam->sa_family) {
 4055 #ifdef INET
 4056                 case AF_INET:
 4057                         if (clp->lc_flags & LCL_TCPCALLBACK)
 4058                                 (void) nfsm_strtom(nd, "tcp", 3);
 4059                         else 
 4060                                 (void) nfsm_strtom(nd, "udp", 3);
 4061                         rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
 4062                         ucp = (u_char *)&rin->sin_addr.s_addr;
 4063                         ucp2 = (u_char *)&rin->sin_port;
 4064                         sprintf(addrbuf, "%d.%d.%d.%d.%d.%d", ucp[0] & 0xff,
 4065                             ucp[1] & 0xff, ucp[2] & 0xff, ucp[3] & 0xff,
 4066                             ucp2[0] & 0xff, ucp2[1] & 0xff);
 4067                         break;
 4068 #endif
 4069 #ifdef INET6
 4070                 case AF_INET6:
 4071                         if (clp->lc_flags & LCL_TCPCALLBACK)
 4072                                 (void) nfsm_strtom(nd, "tcp6", 4);
 4073                         else 
 4074                                 (void) nfsm_strtom(nd, "udp6", 4);
 4075                         rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
 4076                         ucp = inet_ntop(AF_INET6, &rin6->sin6_addr, addrbuf,
 4077                             INET6_ADDRSTRLEN);
 4078                         if (ucp != NULL)
 4079                                 i = strlen(ucp);
 4080                         else
 4081                                 i = 0;
 4082                         ucp2 = (u_char *)&rin6->sin6_port;
 4083                         sprintf(&addrbuf[i], ".%d.%d", ucp2[0] & 0xff,
 4084                             ucp2[1] & 0xff);
 4085                         break;
 4086 #endif
 4087                 }
 4088                 (void) nfsm_strtom(nd, addrbuf, strlen(addrbuf));
 4089                 free(addrbuf, M_TEMP);
 4090         }
 4091         if (clp) {
 4092                 free(clp->lc_req.nr_nam, M_SONAME);
 4093                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
 4094                 free(clp->lc_stateid, M_NFSDCLIENT);
 4095                 free(clp, M_NFSDCLIENT);
 4096         }
 4097         if (!nd->nd_repstat) {
 4098                 NFSM_BUILD(tl, u_int32_t *, 2 * NFSX_HYPER);
 4099                 *tl++ = clientid.lval[0];
 4100                 *tl++ = clientid.lval[1];
 4101                 *tl++ = confirm.lval[0];
 4102                 *tl = confirm.lval[1];
 4103         }
 4104 
 4105 out:
 4106         NFSEXITCODE2(0, nd);
 4107         return (0);
 4108 nfsmout:
 4109         if (clp) {
 4110                 free(clp->lc_req.nr_nam, M_SONAME);
 4111                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
 4112                 free(clp->lc_stateid, M_NFSDCLIENT);
 4113                 free(clp, M_NFSDCLIENT);
 4114         }
 4115         NFSEXITCODE2(error, nd);
 4116         return (error);
 4117 }
 4118 
 4119 /*
 4120  * nfsv4 set client id confirm service
 4121  */
 4122 int
 4123 nfsrvd_setclientidcfrm(struct nfsrv_descript *nd,
 4124     __unused int isdgram, __unused vnode_t vp,
 4125     __unused struct nfsexstuff *exp)
 4126 {
 4127         u_int32_t *tl;
 4128         int error = 0;
 4129         nfsquad_t clientid, confirm;
 4130         struct thread *p = curthread;
 4131 
 4132         if ((nd->nd_flag & ND_NFSV41) != 0) {
 4133                 nd->nd_repstat = NFSERR_NOTSUPP;
 4134                 goto nfsmout;
 4135         }
 4136         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 4137                 goto nfsmout;
 4138         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_HYPER);
 4139         clientid.lval[0] = *tl++;
 4140         clientid.lval[1] = *tl++;
 4141         confirm.lval[0] = *tl++;
 4142         confirm.lval[1] = *tl;
 4143 
 4144         /*
 4145          * nfsrv_getclient() searches the client list for a match and
 4146          * returns the appropriate NFSERR status.
 4147          */
 4148         nd->nd_repstat = nfsrv_getclient(clientid, (CLOPS_CONFIRM|CLOPS_RENEW),
 4149             NULL, NULL, confirm, 0, nd, p);
 4150 nfsmout:
 4151         NFSEXITCODE2(error, nd);
 4152         return (error);
 4153 }
 4154 
 4155 /*
 4156  * nfsv4 verify service
 4157  */
 4158 int
 4159 nfsrvd_verify(struct nfsrv_descript *nd, int isdgram,
 4160     vnode_t vp, __unused struct nfsexstuff *exp)
 4161 {
 4162         int error = 0, ret, fhsize = NFSX_MYFH;
 4163         struct nfsvattr nva;
 4164         struct statfs *sf;
 4165         struct nfsfsinfo fs;
 4166         fhandle_t fh;
 4167         struct thread *p = curthread;
 4168 
 4169         sf = malloc(sizeof(struct statfs), M_STATFS, M_WAITOK);
 4170         nd->nd_repstat = nfsvno_getattr(vp, &nva, nd, p, 1, NULL);
 4171         if (!nd->nd_repstat)
 4172                 nd->nd_repstat = nfsvno_statfs(vp, sf);
 4173         if (!nd->nd_repstat)
 4174                 nd->nd_repstat = nfsvno_getfh(vp, &fh, p);
 4175         if (!nd->nd_repstat) {
 4176                 nfsvno_getfs(&fs, isdgram);
 4177                 error = nfsv4_loadattr(nd, vp, &nva, NULL, &fh, fhsize, NULL,
 4178                     sf, NULL, &fs, NULL, 1, &ret, NULL, NULL, p, nd->nd_cred);
 4179                 if (!error) {
 4180                         if (nd->nd_procnum == NFSV4OP_NVERIFY) {
 4181                                 if (ret == 0)
 4182                                         nd->nd_repstat = NFSERR_SAME;
 4183                                 else if (ret != NFSERR_NOTSAME)
 4184                                         nd->nd_repstat = ret;
 4185                         } else if (ret)
 4186                                 nd->nd_repstat = ret;
 4187                 }
 4188         }
 4189         vput(vp);
 4190         free(sf, M_STATFS);
 4191         NFSEXITCODE2(error, nd);
 4192         return (error);
 4193 }
 4194 
 4195 /*
 4196  * nfs openattr rpc
 4197  */
 4198 int
 4199 nfsrvd_openattr(struct nfsrv_descript *nd, __unused int isdgram,
 4200     vnode_t dp, __unused vnode_t *vpp, __unused fhandle_t *fhp,
 4201     __unused struct nfsexstuff *exp)
 4202 {
 4203         u_int32_t *tl;
 4204         int error = 0, createdir __unused;
 4205 
 4206         NFSM_DISSECT(tl, u_int32_t *, NFSX_UNSIGNED);
 4207         createdir = fxdr_unsigned(int, *tl);
 4208         nd->nd_repstat = NFSERR_NOTSUPP;
 4209 nfsmout:
 4210         vrele(dp);
 4211         NFSEXITCODE2(error, nd);
 4212         return (error);
 4213 }
 4214 
 4215 /*
 4216  * nfsv4 release lock owner service
 4217  */
 4218 int
 4219 nfsrvd_releaselckown(struct nfsrv_descript *nd, __unused int isdgram,
 4220     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4221 {
 4222         u_int32_t *tl;
 4223         struct nfsstate *stp = NULL;
 4224         int error = 0, len;
 4225         nfsquad_t clientid;
 4226         struct thread *p = curthread;
 4227 
 4228         if ((nd->nd_flag & ND_NFSV41) != 0) {
 4229                 nd->nd_repstat = NFSERR_NOTSUPP;
 4230                 goto nfsmout;
 4231         }
 4232         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 4233                 goto nfsmout;
 4234         NFSM_DISSECT(tl, u_int32_t *, 3 * NFSX_UNSIGNED);
 4235         len = fxdr_unsigned(int, *(tl + 2));
 4236         if (len <= 0 || len > NFSV4_OPAQUELIMIT) {
 4237                 nd->nd_repstat = NFSERR_BADXDR;
 4238                 goto nfsmout;
 4239         }
 4240         stp = malloc(sizeof (struct nfsstate) + len,
 4241             M_NFSDSTATE, M_WAITOK);
 4242         stp->ls_ownerlen = len;
 4243         stp->ls_op = NULL;
 4244         stp->ls_flags = NFSLCK_RELEASE;
 4245         stp->ls_uid = nd->nd_cred->cr_uid;
 4246         clientid.lval[0] = *tl++;
 4247         clientid.lval[1] = *tl;
 4248         if ((nd->nd_flag & ND_IMPLIEDCLID) != 0) {
 4249                 if ((nd->nd_flag & ND_NFSV41) != 0)
 4250                         clientid.qval = nd->nd_clientid.qval;
 4251                 else if (nd->nd_clientid.qval != clientid.qval)
 4252                         printf("EEK14 multiple clids\n");
 4253         } else {
 4254                 if ((nd->nd_flag & ND_NFSV41) != 0)
 4255                         printf("EEK! no clientid from session\n");
 4256                 nd->nd_flag |= ND_IMPLIEDCLID;
 4257                 nd->nd_clientid.qval = clientid.qval;
 4258         }
 4259         error = nfsrv_mtostr(nd, stp->ls_owner, len);
 4260         if (error)
 4261                 goto nfsmout;
 4262         nd->nd_repstat = nfsrv_releaselckown(stp, clientid, p);
 4263         free(stp, M_NFSDSTATE);
 4264 
 4265         NFSEXITCODE2(0, nd);
 4266         return (0);
 4267 nfsmout:
 4268         if (stp)
 4269                 free(stp, M_NFSDSTATE);
 4270         NFSEXITCODE2(error, nd);
 4271         return (error);
 4272 }
 4273 
 4274 /*
 4275  * nfsv4 exchange_id service
 4276  */
 4277 int
 4278 nfsrvd_exchangeid(struct nfsrv_descript *nd, __unused int isdgram,
 4279     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4280 {
 4281         uint32_t *tl;
 4282         int error = 0, i, idlen;
 4283         struct nfsclient *clp = NULL;
 4284         nfsquad_t clientid, confirm;
 4285         uint8_t *verf;
 4286         uint32_t sp4type, v41flags;
 4287         struct timespec verstime;
 4288 #ifdef INET
 4289         struct sockaddr_in *sin, *rin;
 4290 #endif
 4291 #ifdef INET6
 4292         struct sockaddr_in6 *sin6, *rin6;
 4293 #endif
 4294         struct thread *p = curthread;
 4295         char *s;
 4296 
 4297         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 4298                 goto nfsmout;
 4299         NFSM_DISSECT(tl, u_int32_t *, NFSX_VERF + NFSX_UNSIGNED);
 4300         verf = (uint8_t *)tl;
 4301         tl += (NFSX_VERF / NFSX_UNSIGNED);
 4302         i = fxdr_unsigned(int, *tl);
 4303         if (i > NFSV4_OPAQUELIMIT || i <= 0) {
 4304                 nd->nd_repstat = NFSERR_BADXDR;
 4305                 goto nfsmout;
 4306         }
 4307         idlen = i;
 4308         if (nd->nd_flag & ND_GSS)
 4309                 i += nd->nd_princlen;
 4310         clp = malloc(sizeof(struct nfsclient) + i, M_NFSDCLIENT, M_WAITOK |
 4311             M_ZERO);
 4312         clp->lc_stateid = malloc(sizeof(struct nfsstatehead) *
 4313             nfsrv_statehashsize, M_NFSDCLIENT, M_WAITOK);
 4314         NFSINITSOCKMUTEX(&clp->lc_req.nr_mtx);
 4315         /* Allocated large enough for an AF_INET or AF_INET6 socket. */
 4316         clp->lc_req.nr_nam = malloc(sizeof(struct sockaddr_in6), M_SONAME,
 4317             M_WAITOK | M_ZERO);
 4318         switch (nd->nd_nam->sa_family) {
 4319 #ifdef INET
 4320         case AF_INET:
 4321                 rin = (struct sockaddr_in *)clp->lc_req.nr_nam;
 4322                 sin = (struct sockaddr_in *)nd->nd_nam;
 4323                 rin->sin_family = AF_INET;
 4324                 rin->sin_len = sizeof(struct sockaddr_in);
 4325                 rin->sin_port = 0;
 4326                 rin->sin_addr.s_addr = sin->sin_addr.s_addr;
 4327                 break;
 4328 #endif
 4329 #ifdef INET6
 4330         case AF_INET6:
 4331                 rin6 = (struct sockaddr_in6 *)clp->lc_req.nr_nam;
 4332                 sin6 = (struct sockaddr_in6 *)nd->nd_nam;
 4333                 rin6->sin6_family = AF_INET6;
 4334                 rin6->sin6_len = sizeof(struct sockaddr_in6);
 4335                 rin6->sin6_port = 0;
 4336                 rin6->sin6_addr = sin6->sin6_addr;
 4337                 break;
 4338 #endif
 4339         }
 4340         clp->lc_req.nr_cred = NULL;
 4341         NFSBCOPY(verf, clp->lc_verf, NFSX_VERF);
 4342         clp->lc_idlen = idlen;
 4343         error = nfsrv_mtostr(nd, clp->lc_id, idlen);
 4344         if (error != 0)
 4345                 goto nfsmout;
 4346         if ((nd->nd_flag & ND_GSS) != 0) {
 4347                 clp->lc_flags = LCL_GSS | LCL_NFSV41;
 4348                 if ((nd->nd_flag & ND_GSSINTEGRITY) != 0)
 4349                         clp->lc_flags |= LCL_GSSINTEGRITY;
 4350                 else if ((nd->nd_flag & ND_GSSPRIVACY) != 0)
 4351                         clp->lc_flags |= LCL_GSSPRIVACY;
 4352         } else
 4353                 clp->lc_flags = LCL_NFSV41;
 4354         if ((nd->nd_flag & ND_NFSV42) != 0)
 4355                 clp->lc_flags |= LCL_NFSV42;
 4356         if ((nd->nd_flag & ND_GSS) != 0 && nd->nd_princlen > 0) {
 4357                 clp->lc_flags |= LCL_NAME;
 4358                 clp->lc_namelen = nd->nd_princlen;
 4359                 clp->lc_name = &clp->lc_id[idlen];
 4360                 NFSBCOPY(nd->nd_principal, clp->lc_name, clp->lc_namelen);
 4361         } else {
 4362                 clp->lc_uid = nd->nd_cred->cr_uid;
 4363                 clp->lc_gid = nd->nd_cred->cr_gid;
 4364         }
 4365         NFSM_DISSECT(tl, u_int32_t *, 2 * NFSX_UNSIGNED);
 4366         v41flags = fxdr_unsigned(uint32_t, *tl++);
 4367         if ((v41flags & ~(NFSV4EXCH_SUPPMOVEDREFER | NFSV4EXCH_SUPPMOVEDMIGR |
 4368             NFSV4EXCH_BINDPRINCSTATEID | NFSV4EXCH_MASKPNFS |
 4369             NFSV4EXCH_UPDCONFIRMEDRECA)) != 0) {
 4370                 nd->nd_repstat = NFSERR_INVAL;
 4371                 goto nfsmout;
 4372         }
 4373         if ((v41flags & NFSV4EXCH_UPDCONFIRMEDRECA) != 0)
 4374                 confirm.lval[1] = 1;
 4375         else
 4376                 confirm.lval[1] = 0;
 4377         if (nfsrv_devidcnt == 0)
 4378                 v41flags = NFSV4EXCH_USENONPNFS | NFSV4EXCH_USEPNFSDS;
 4379         else
 4380                 v41flags = NFSV4EXCH_USEPNFSMDS;
 4381         sp4type = fxdr_unsigned(uint32_t, *tl);
 4382         if (sp4type != NFSV4EXCH_SP4NONE) {
 4383                 nd->nd_repstat = NFSERR_NOTSUPP;
 4384                 goto nfsmout;
 4385         }
 4386 
 4387         /*
 4388          * nfsrv_setclient() does the actual work of adding it to the
 4389          * client list. If there is no error, the structure has been
 4390          * linked into the client list and clp should no longer be used
 4391          * here. When an error is returned, it has not been linked in,
 4392          * so it should be free'd.
 4393          */
 4394         nd->nd_repstat = nfsrv_setclient(nd, &clp, &clientid, &confirm, p);
 4395         if (clp != NULL) {
 4396                 free(clp->lc_req.nr_nam, M_SONAME);
 4397                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
 4398                 free(clp->lc_stateid, M_NFSDCLIENT);
 4399                 free(clp, M_NFSDCLIENT);
 4400         }
 4401         if (nd->nd_repstat == 0) {
 4402                 if (confirm.lval[1] != 0)
 4403                         v41flags |= NFSV4EXCH_CONFIRMEDR;
 4404                 NFSM_BUILD(tl, uint32_t *, 2 * NFSX_HYPER + 3 * NFSX_UNSIGNED);
 4405                 *tl++ = clientid.lval[0];                       /* ClientID */
 4406                 *tl++ = clientid.lval[1];
 4407                 *tl++ = txdr_unsigned(confirm.lval[0]);         /* SequenceID */
 4408                 *tl++ = txdr_unsigned(v41flags);                /* Exch flags */
 4409                 *tl++ = txdr_unsigned(NFSV4EXCH_SP4NONE);       /* No SSV */
 4410                 txdr_hyper(nfsrv_owner_minor, tl);      /* Owner Minor */
 4411                 if (nfsrv_owner_major[0] != 0)
 4412                         s = nfsrv_owner_major;
 4413                 else
 4414                         s = nd->nd_cred->cr_prison->pr_hostuuid;
 4415                 nfsm_strtom(nd, s, strlen(s));          /* Owner Major */
 4416                 if (nfsrv_scope[0] != 0)
 4417                         s = nfsrv_scope;
 4418                 else
 4419                         s = nd->nd_cred->cr_prison->pr_hostuuid;
 4420                 nfsm_strtom(nd, s, strlen(s)    );              /* Scope */
 4421                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 4422                 *tl = txdr_unsigned(1);
 4423                 (void)nfsm_strtom(nd, "freebsd.org", strlen("freebsd.org"));
 4424                 (void)nfsm_strtom(nd, version, strlen(version));
 4425                 NFSM_BUILD(tl, uint32_t *, NFSX_V4TIME);
 4426                 verstime.tv_sec = 1293840000;           /* Jan 1, 2011 */
 4427                 verstime.tv_nsec = 0;
 4428                 txdr_nfsv4time(&verstime, tl);
 4429         }
 4430         NFSEXITCODE2(0, nd);
 4431         return (0);
 4432 nfsmout:
 4433         if (clp != NULL) {
 4434                 free(clp->lc_req.nr_nam, M_SONAME);
 4435                 NFSFREEMUTEX(&clp->lc_req.nr_mtx);
 4436                 free(clp->lc_stateid, M_NFSDCLIENT);
 4437                 free(clp, M_NFSDCLIENT);
 4438         }
 4439         NFSEXITCODE2(error, nd);
 4440         return (error);
 4441 }
 4442 
 4443 /*
 4444  * nfsv4 create session service
 4445  */
 4446 int
 4447 nfsrvd_createsession(struct nfsrv_descript *nd, __unused int isdgram,
 4448     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4449 {
 4450         uint32_t *tl;
 4451         int error = 0;
 4452         nfsquad_t clientid, confirm;
 4453         struct nfsdsession *sep = NULL;
 4454         uint32_t rdmacnt;
 4455         struct thread *p = curthread;
 4456         static bool do_printf = true;
 4457 
 4458         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 4459                 goto nfsmout;
 4460         sep = (struct nfsdsession *)malloc(sizeof(struct nfsdsession),
 4461             M_NFSDSESSION, M_WAITOK | M_ZERO);
 4462         sep->sess_refcnt = 1;
 4463         mtx_init(&sep->sess_cbsess.nfsess_mtx, "nfscbsession", NULL, MTX_DEF);
 4464         NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + 2 * NFSX_UNSIGNED);
 4465         clientid.lval[0] = *tl++;
 4466         clientid.lval[1] = *tl++;
 4467         confirm.lval[0] = fxdr_unsigned(uint32_t, *tl++);
 4468         sep->sess_crflags = fxdr_unsigned(uint32_t, *tl);
 4469         /* Persistent sessions and RDMA are not supported. */
 4470         sep->sess_crflags &= NFSV4CRSESS_CONNBACKCHAN;
 4471 
 4472         /* Fore channel attributes. */
 4473         NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
 4474         tl++;                                   /* Header pad always 0. */
 4475         sep->sess_maxreq = fxdr_unsigned(uint32_t, *tl++);
 4476         if (sep->sess_maxreq > sb_max_adj - NFS_MAXXDR) {
 4477                 sep->sess_maxreq = sb_max_adj - NFS_MAXXDR;
 4478                 if (do_printf)
 4479                         printf("Consider increasing kern.ipc.maxsockbuf\n");
 4480                 do_printf = false;
 4481         }
 4482         sep->sess_maxresp = fxdr_unsigned(uint32_t, *tl++);
 4483         if (sep->sess_maxresp > sb_max_adj - NFS_MAXXDR) {
 4484                 sep->sess_maxresp = sb_max_adj - NFS_MAXXDR;
 4485                 if (do_printf)
 4486                         printf("Consider increasing kern.ipc.maxsockbuf\n");
 4487                 do_printf = false;
 4488         }
 4489         sep->sess_maxrespcached = fxdr_unsigned(uint32_t, *tl++);
 4490         sep->sess_maxops = fxdr_unsigned(uint32_t, *tl++);
 4491         sep->sess_maxslots = fxdr_unsigned(uint32_t, *tl++);
 4492         if (sep->sess_maxslots > NFSV4_SLOTS)
 4493                 sep->sess_maxslots = NFSV4_SLOTS;
 4494         rdmacnt = fxdr_unsigned(uint32_t, *tl);
 4495         if (rdmacnt > 1) {
 4496                 nd->nd_repstat = NFSERR_BADXDR;
 4497                 goto nfsmout;
 4498         } else if (rdmacnt == 1)
 4499                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 4500 
 4501         /* Back channel attributes. */
 4502         NFSM_DISSECT(tl, uint32_t *, 7 * NFSX_UNSIGNED);
 4503         tl++;                                   /* Header pad always 0. */
 4504         sep->sess_cbmaxreq = fxdr_unsigned(uint32_t, *tl++);
 4505         sep->sess_cbmaxresp = fxdr_unsigned(uint32_t, *tl++);
 4506         sep->sess_cbmaxrespcached = fxdr_unsigned(uint32_t, *tl++);
 4507         sep->sess_cbmaxops = fxdr_unsigned(uint32_t, *tl++);
 4508         sep->sess_cbsess.nfsess_foreslots = fxdr_unsigned(uint32_t, *tl++);
 4509         rdmacnt = fxdr_unsigned(uint32_t, *tl);
 4510         if (rdmacnt > 1) {
 4511                 nd->nd_repstat = NFSERR_BADXDR;
 4512                 goto nfsmout;
 4513         } else if (rdmacnt == 1)
 4514                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 4515 
 4516         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 4517         sep->sess_cbprogram = fxdr_unsigned(uint32_t, *tl);
 4518 
 4519         /*
 4520          * nfsrv_getclient() searches the client list for a match and
 4521          * returns the appropriate NFSERR status.
 4522          */
 4523         nd->nd_repstat = nfsrv_getclient(clientid, CLOPS_CONFIRM | CLOPS_RENEW,
 4524             NULL, sep, confirm, sep->sess_cbprogram, nd, p);
 4525         if (nd->nd_repstat == 0) {
 4526                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
 4527                 NFSBCOPY(sep->sess_sessionid, tl, NFSX_V4SESSIONID);
 4528                 NFSM_BUILD(tl, uint32_t *, 18 * NFSX_UNSIGNED);
 4529                 *tl++ = txdr_unsigned(confirm.lval[0]); /* sequenceid */
 4530                 *tl++ = txdr_unsigned(sep->sess_crflags);
 4531 
 4532                 /* Fore channel attributes. */
 4533                 *tl++ = 0;
 4534                 *tl++ = txdr_unsigned(sep->sess_maxreq);
 4535                 *tl++ = txdr_unsigned(sep->sess_maxresp);
 4536                 *tl++ = txdr_unsigned(sep->sess_maxrespcached);
 4537                 *tl++ = txdr_unsigned(sep->sess_maxops);
 4538                 *tl++ = txdr_unsigned(sep->sess_maxslots);
 4539                 *tl++ = txdr_unsigned(1);
 4540                 *tl++ = txdr_unsigned(0);                       /* No RDMA. */
 4541 
 4542                 /* Back channel attributes. */
 4543                 *tl++ = 0;
 4544                 *tl++ = txdr_unsigned(sep->sess_cbmaxreq);
 4545                 *tl++ = txdr_unsigned(sep->sess_cbmaxresp);
 4546                 *tl++ = txdr_unsigned(sep->sess_cbmaxrespcached);
 4547                 *tl++ = txdr_unsigned(sep->sess_cbmaxops);
 4548                 *tl++ = txdr_unsigned(sep->sess_cbsess.nfsess_foreslots);
 4549                 *tl++ = txdr_unsigned(1);
 4550                 *tl = txdr_unsigned(0);                 /* No RDMA. */
 4551         }
 4552 nfsmout:
 4553         if (nd->nd_repstat != 0 && sep != NULL)
 4554                 free(sep, M_NFSDSESSION);
 4555         NFSEXITCODE2(error, nd);
 4556         return (error);
 4557 }
 4558 
 4559 /*
 4560  * nfsv4 sequence service
 4561  */
 4562 int
 4563 nfsrvd_sequence(struct nfsrv_descript *nd, __unused int isdgram,
 4564     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4565 {
 4566         uint32_t *tl;
 4567         uint32_t highest_slotid, sequenceid, sflags, target_highest_slotid;
 4568         int cache_this, error = 0;
 4569         struct thread *p = curthread;
 4570 
 4571         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 4572                 goto nfsmout;
 4573         NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID);
 4574         NFSBCOPY(tl, nd->nd_sessionid, NFSX_V4SESSIONID);
 4575         NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
 4576         sequenceid = fxdr_unsigned(uint32_t, *tl++);
 4577         nd->nd_slotid = fxdr_unsigned(uint32_t, *tl++);
 4578         highest_slotid = fxdr_unsigned(uint32_t, *tl++);
 4579         if (*tl == newnfs_true)
 4580                 cache_this = 1;
 4581         else
 4582                 cache_this = 0;
 4583         nd->nd_repstat = nfsrv_checksequence(nd, sequenceid, &highest_slotid,
 4584             &target_highest_slotid, cache_this, &sflags, p);
 4585         if (nd->nd_repstat != NFSERR_BADSLOT)
 4586                 nd->nd_flag |= ND_HASSEQUENCE;
 4587         if (nd->nd_repstat == 0) {
 4588                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID);
 4589                 NFSBCOPY(nd->nd_sessionid, tl, NFSX_V4SESSIONID);
 4590                 NFSM_BUILD(tl, uint32_t *, 5 * NFSX_UNSIGNED);
 4591                 *tl++ = txdr_unsigned(sequenceid);
 4592                 *tl++ = txdr_unsigned(nd->nd_slotid);
 4593                 *tl++ = txdr_unsigned(highest_slotid);
 4594                 *tl++ = txdr_unsigned(target_highest_slotid);
 4595                 *tl = txdr_unsigned(sflags);
 4596         }
 4597 nfsmout:
 4598         NFSEXITCODE2(error, nd);
 4599         return (error);
 4600 }
 4601 
 4602 /*
 4603  * nfsv4 reclaim complete service
 4604  */
 4605 int
 4606 nfsrvd_reclaimcomplete(struct nfsrv_descript *nd, __unused int isdgram,
 4607     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4608 {
 4609         uint32_t *tl;
 4610         int error = 0, onefs;
 4611 
 4612         NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 4613         /*
 4614          * I believe that a ReclaimComplete with rca_one_fs == TRUE is only
 4615          * to be used after a file system has been transferred to a different
 4616          * file server.  However, RFC5661 is somewhat vague w.r.t. this and
 4617          * the ESXi 6.7 client does both a ReclaimComplete with rca_one_fs
 4618          * == TRUE and one with ReclaimComplete with rca_one_fs == FALSE.
 4619          * Therefore, just ignore the rca_one_fs == TRUE operation and return
 4620          * NFS_OK without doing anything.
 4621          */
 4622         onefs = 0;
 4623         if (*tl == newnfs_true)
 4624                 onefs = 1;
 4625         nd->nd_repstat = nfsrv_checkreclaimcomplete(nd, onefs);
 4626 nfsmout:
 4627         NFSEXITCODE2(error, nd);
 4628         return (error);
 4629 }
 4630 
 4631 /*
 4632  * nfsv4 destroy clientid service
 4633  */
 4634 int
 4635 nfsrvd_destroyclientid(struct nfsrv_descript *nd, __unused int isdgram,
 4636     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4637 {
 4638         uint32_t *tl;
 4639         nfsquad_t clientid;
 4640         int error = 0;
 4641         struct thread *p = curthread;
 4642 
 4643         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 4644                 goto nfsmout;
 4645         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 4646         clientid.lval[0] = *tl++;
 4647         clientid.lval[1] = *tl;
 4648         nd->nd_repstat = nfsrv_destroyclient(clientid, p);
 4649 nfsmout:
 4650         NFSEXITCODE2(error, nd);
 4651         return (error);
 4652 }
 4653 
 4654 /*
 4655  * nfsv4 bind connection to session service
 4656  */
 4657 int
 4658 nfsrvd_bindconnsess(struct nfsrv_descript *nd, __unused int isdgram,
 4659     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4660 {
 4661         uint32_t *tl;
 4662         uint8_t sessid[NFSX_V4SESSIONID];
 4663         int error = 0, foreaft;
 4664 
 4665         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 4666                 goto nfsmout;
 4667         NFSM_DISSECT(tl, uint32_t *, NFSX_V4SESSIONID + 2 * NFSX_UNSIGNED);
 4668         NFSBCOPY(tl, sessid, NFSX_V4SESSIONID);
 4669         tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
 4670         foreaft = fxdr_unsigned(int, *tl++);
 4671         if (*tl == newnfs_true) {
 4672                 /* RDMA is not supported. */
 4673                 nd->nd_repstat = NFSERR_NOTSUPP;
 4674                 goto nfsmout;
 4675         }
 4676 
 4677         nd->nd_repstat = nfsrv_bindconnsess(nd, sessid, &foreaft);
 4678         if (nd->nd_repstat == 0) {
 4679                 NFSM_BUILD(tl, uint32_t *, NFSX_V4SESSIONID + 2 *
 4680                     NFSX_UNSIGNED);
 4681                 NFSBCOPY(sessid, tl, NFSX_V4SESSIONID);
 4682                 tl += (NFSX_V4SESSIONID / NFSX_UNSIGNED);
 4683                 *tl++ = txdr_unsigned(foreaft);
 4684                 *tl = newnfs_false;
 4685         }
 4686 nfsmout:
 4687         NFSEXITCODE2(error, nd);
 4688         return (error);
 4689 }
 4690 
 4691 /*
 4692  * nfsv4 destroy session service
 4693  */
 4694 int
 4695 nfsrvd_destroysession(struct nfsrv_descript *nd, __unused int isdgram,
 4696     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4697 {
 4698         uint8_t *cp, sessid[NFSX_V4SESSIONID];
 4699         int error = 0;
 4700 
 4701         if ((nd->nd_repstat = nfsd_checkrootexp(nd)) != 0)
 4702                 goto nfsmout;
 4703         NFSM_DISSECT(cp, uint8_t *, NFSX_V4SESSIONID);
 4704         NFSBCOPY(cp, sessid, NFSX_V4SESSIONID);
 4705         nd->nd_repstat = nfsrv_destroysession(nd, sessid);
 4706 nfsmout:
 4707         NFSEXITCODE2(error, nd);
 4708         return (error);
 4709 }
 4710 
 4711 /*
 4712  * nfsv4 free stateid service
 4713  */
 4714 int
 4715 nfsrvd_freestateid(struct nfsrv_descript *nd, __unused int isdgram,
 4716     __unused vnode_t vp, __unused struct nfsexstuff *exp)
 4717 {
 4718         uint32_t *tl;
 4719         nfsv4stateid_t stateid;
 4720         int error = 0;
 4721         struct thread *p = curthread;
 4722 
 4723         NFSM_DISSECT(tl, uint32_t *, NFSX_STATEID);
 4724         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
 4725         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
 4726 
 4727         /*
 4728          * For the special stateid of other all 0s and seqid == 1, set the
 4729          * stateid to the current stateid, if it is set.
 4730          */
 4731         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
 4732             stateid.other[1] == 0 && stateid.other[2] == 0) {
 4733                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
 4734                         stateid = nd->nd_curstateid;
 4735                         stateid.seqid = 0;
 4736                 } else {
 4737                         nd->nd_repstat = NFSERR_BADSTATEID;
 4738                         goto nfsmout;
 4739                 }
 4740         }
 4741 
 4742         nd->nd_repstat = nfsrv_freestateid(nd, &stateid, p);
 4743 
 4744         /* If the current stateid has been free'd, unset it. */
 4745         if (nd->nd_repstat == 0 && (nd->nd_flag & ND_CURSTATEID) != 0 &&
 4746             stateid.other[0] == nd->nd_curstateid.other[0] &&
 4747             stateid.other[1] == nd->nd_curstateid.other[1] &&
 4748             stateid.other[2] == nd->nd_curstateid.other[2])
 4749                 nd->nd_flag &= ~ND_CURSTATEID;
 4750 nfsmout:
 4751         NFSEXITCODE2(error, nd);
 4752         return (error);
 4753 }
 4754 
 4755 /*
 4756  * nfsv4 layoutget service
 4757  */
 4758 int
 4759 nfsrvd_layoutget(struct nfsrv_descript *nd, __unused int isdgram,
 4760     vnode_t vp, struct nfsexstuff *exp)
 4761 {
 4762         uint32_t *tl;
 4763         nfsv4stateid_t stateid;
 4764         int error = 0, layoutlen, layouttype, iomode, maxcnt, retonclose;
 4765         uint64_t offset, len, minlen;
 4766         char *layp;
 4767         struct thread *p = curthread;
 4768 
 4769         NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED + 3 * NFSX_HYPER +
 4770             NFSX_STATEID);
 4771         tl++;           /* Signal layout available. Ignore for now. */
 4772         layouttype = fxdr_unsigned(int, *tl++);
 4773         iomode = fxdr_unsigned(int, *tl++);
 4774         offset = fxdr_hyper(tl); tl += 2;
 4775         len = fxdr_hyper(tl); tl += 2;
 4776         minlen = fxdr_hyper(tl); tl += 2;
 4777         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
 4778         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
 4779         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 4780         maxcnt = fxdr_unsigned(int, *tl);
 4781         NFSD_DEBUG(4, "layoutget ltyp=%d iom=%d off=%ju len=%ju mlen=%ju\n",
 4782             layouttype, iomode, (uintmax_t)offset, (uintmax_t)len,
 4783             (uintmax_t)minlen);
 4784         if (len < minlen ||
 4785             (minlen != UINT64_MAX && offset + minlen < offset) ||
 4786             (len != UINT64_MAX && offset + len < offset)) {
 4787                 nd->nd_repstat = NFSERR_INVAL;
 4788                 goto nfsmout;
 4789         }
 4790 
 4791         /*
 4792          * For the special stateid of other all 0s and seqid == 1, set the
 4793          * stateid to the current stateid, if it is set.
 4794          */
 4795         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
 4796             stateid.other[1] == 0 && stateid.other[2] == 0) {
 4797                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
 4798                         stateid = nd->nd_curstateid;
 4799                         stateid.seqid = 0;
 4800                 } else {
 4801                         nd->nd_repstat = NFSERR_BADSTATEID;
 4802                         goto nfsmout;
 4803                 }
 4804         }
 4805 
 4806         layp = NULL;
 4807         if (layouttype == NFSLAYOUT_NFSV4_1_FILES && nfsrv_maxpnfsmirror == 1)
 4808                 layp = malloc(NFSX_V4FILELAYOUT, M_TEMP, M_WAITOK);
 4809         else if (layouttype == NFSLAYOUT_FLEXFILE)
 4810                 layp = malloc(NFSX_V4FLEXLAYOUT(nfsrv_maxpnfsmirror), M_TEMP,
 4811                     M_WAITOK);
 4812         else
 4813                 nd->nd_repstat = NFSERR_UNKNLAYOUTTYPE;
 4814         if (layp != NULL)
 4815                 nd->nd_repstat = nfsrv_layoutget(nd, vp, exp, layouttype,
 4816                     &iomode, &offset, &len, minlen, &stateid, maxcnt,
 4817                     &retonclose, &layoutlen, layp, nd->nd_cred, p);
 4818         NFSD_DEBUG(4, "nfsrv_layoutget stat=%u layoutlen=%d\n", nd->nd_repstat,
 4819             layoutlen);
 4820         if (nd->nd_repstat == 0) {
 4821                 /* For NFSv4.1, set the Current StateID. */
 4822                 if ((nd->nd_flag & ND_NFSV41) != 0) {
 4823                         nd->nd_curstateid = stateid;
 4824                         nd->nd_flag |= ND_CURSTATEID;
 4825                 }
 4826                 NFSM_BUILD(tl, uint32_t *, 4 * NFSX_UNSIGNED + NFSX_STATEID +
 4827                     2 * NFSX_HYPER);
 4828                 *tl++ = txdr_unsigned(retonclose);
 4829                 *tl++ = txdr_unsigned(stateid.seqid);
 4830                 NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
 4831                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 4832                 *tl++ = txdr_unsigned(1);       /* Only returns one layout. */
 4833                 txdr_hyper(offset, tl); tl += 2;
 4834                 txdr_hyper(len, tl); tl += 2;
 4835                 *tl++ = txdr_unsigned(iomode);
 4836                 *tl = txdr_unsigned(layouttype);
 4837                 nfsm_strtom(nd, layp, layoutlen);
 4838         } else if (nd->nd_repstat == NFSERR_LAYOUTTRYLATER) {
 4839                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 4840                 *tl = newnfs_false;
 4841         }
 4842         free(layp, M_TEMP);
 4843 nfsmout:
 4844         vput(vp);
 4845         NFSEXITCODE2(error, nd);
 4846         return (error);
 4847 }
 4848 
 4849 /*
 4850  * nfsv4 layoutcommit service
 4851  */
 4852 int
 4853 nfsrvd_layoutcommit(struct nfsrv_descript *nd, __unused int isdgram,
 4854     vnode_t vp, struct nfsexstuff *exp)
 4855 {
 4856         uint32_t *tl;
 4857         nfsv4stateid_t stateid;
 4858         int error = 0, hasnewoff, hasnewmtime, layouttype, maxcnt, reclaim;
 4859         int hasnewsize;
 4860         uint64_t offset, len, newoff = 0, newsize;
 4861         struct timespec newmtime;
 4862         char *layp;
 4863         struct thread *p = curthread;
 4864 
 4865         layp = NULL;
 4866         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED + 2 * NFSX_HYPER +
 4867             NFSX_STATEID);
 4868         offset = fxdr_hyper(tl); tl += 2;
 4869         len = fxdr_hyper(tl); tl += 2;
 4870         reclaim = fxdr_unsigned(int, *tl++);
 4871         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
 4872         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
 4873         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 4874         /*
 4875          * For the special stateid of other all 0s and seqid == 1, set the
 4876          * stateid to the current stateid, if it is set.
 4877          */
 4878         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
 4879             stateid.other[1] == 0 && stateid.other[2] == 0) {
 4880                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
 4881                         stateid = nd->nd_curstateid;
 4882                         stateid.seqid = 0;
 4883                 } else {
 4884                         nd->nd_repstat = NFSERR_BADSTATEID;
 4885                         goto nfsmout;
 4886                 }
 4887         }
 4888 
 4889         hasnewoff = fxdr_unsigned(int, *tl);
 4890         if (hasnewoff != 0) {
 4891                 NFSM_DISSECT(tl, uint32_t *, NFSX_HYPER + NFSX_UNSIGNED);
 4892                 newoff = fxdr_hyper(tl); tl += 2;
 4893         } else
 4894                 NFSM_DISSECT(tl, uint32_t *, NFSX_UNSIGNED);
 4895         hasnewmtime = fxdr_unsigned(int, *tl);
 4896         if (hasnewmtime != 0) {
 4897                 NFSM_DISSECT(tl, uint32_t *, NFSX_V4TIME + 2 * NFSX_UNSIGNED);
 4898                 fxdr_nfsv4time(tl, &newmtime);
 4899                 tl += (NFSX_V4TIME / NFSX_UNSIGNED);
 4900         } else
 4901                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_UNSIGNED);
 4902         layouttype = fxdr_unsigned(int, *tl++);
 4903         maxcnt = fxdr_unsigned(int, *tl);
 4904         if (maxcnt > 0) {
 4905                 layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
 4906                 error = nfsrv_mtostr(nd, layp, maxcnt);
 4907                 if (error != 0)
 4908                         goto nfsmout;
 4909         }
 4910         nd->nd_repstat = nfsrv_layoutcommit(nd, vp, layouttype, hasnewoff,
 4911             newoff, offset, len, hasnewmtime, &newmtime, reclaim, &stateid,
 4912             maxcnt, layp, &hasnewsize, &newsize, nd->nd_cred, p);
 4913         NFSD_DEBUG(4, "nfsrv_layoutcommit stat=%u\n", nd->nd_repstat);
 4914         if (nd->nd_repstat == 0) {
 4915                 if (hasnewsize != 0) {
 4916                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED + NFSX_HYPER);
 4917                         *tl++ = newnfs_true;
 4918                         txdr_hyper(newsize, tl);
 4919                 } else {
 4920                         NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 4921                         *tl = newnfs_false;
 4922                 }
 4923         }
 4924 nfsmout:
 4925         free(layp, M_TEMP);
 4926         vput(vp);
 4927         NFSEXITCODE2(error, nd);
 4928         return (error);
 4929 }
 4930 
 4931 /*
 4932  * nfsv4 layoutreturn service
 4933  */
 4934 int
 4935 nfsrvd_layoutreturn(struct nfsrv_descript *nd, __unused int isdgram,
 4936     vnode_t vp, struct nfsexstuff *exp)
 4937 {
 4938         uint32_t *tl, *layp;
 4939         nfsv4stateid_t stateid;
 4940         int error = 0, fnd, kind, layouttype, iomode, maxcnt, reclaim;
 4941         uint64_t offset, len;
 4942         struct thread *p = curthread;
 4943 
 4944         layp = NULL;
 4945         NFSM_DISSECT(tl, uint32_t *, 4 * NFSX_UNSIGNED);
 4946         reclaim = *tl++;
 4947         layouttype = fxdr_unsigned(int, *tl++);
 4948         iomode = fxdr_unsigned(int, *tl++);
 4949         kind = fxdr_unsigned(int, *tl);
 4950         NFSD_DEBUG(4, "layoutreturn recl=%d ltyp=%d iom=%d kind=%d\n", reclaim,
 4951             layouttype, iomode, kind);
 4952         if (kind == NFSV4LAYOUTRET_FILE) {
 4953                 NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
 4954                     NFSX_UNSIGNED);
 4955                 offset = fxdr_hyper(tl); tl += 2;
 4956                 len = fxdr_hyper(tl); tl += 2;
 4957                 stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
 4958                 NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
 4959                 tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 4960 
 4961                 /*
 4962                  * For the special stateid of other all 0s and seqid == 1, set
 4963                  * the stateid to the current stateid, if it is set.
 4964                  */
 4965                 if (stateid.seqid == 1 && stateid.other[0] == 0 &&
 4966                     stateid.other[1] == 0 && stateid.other[2] == 0) {
 4967                         if ((nd->nd_flag & ND_CURSTATEID) != 0) {
 4968                                 stateid = nd->nd_curstateid;
 4969                                 stateid.seqid = 0;
 4970                         } else {
 4971                                 nd->nd_repstat = NFSERR_BADSTATEID;
 4972                                 goto nfsmout;
 4973                         }
 4974                 }
 4975 
 4976                 maxcnt = fxdr_unsigned(int, *tl);
 4977                 /*
 4978                  * There is no fixed upper bound defined in the RFCs,
 4979                  * but 128Kbytes should be more than sufficient.
 4980                  */
 4981                 if (maxcnt < 0 || maxcnt > 131072)
 4982                         maxcnt = 0;
 4983                 if (maxcnt > 0) {
 4984                         layp = malloc(maxcnt + 1, M_TEMP, M_WAITOK);
 4985                         error = nfsrv_mtostr(nd, (char *)layp, maxcnt);
 4986                         if (error != 0)
 4987                                 goto nfsmout;
 4988                 }
 4989         } else {
 4990                 if (reclaim == newnfs_true) {
 4991                         nd->nd_repstat = NFSERR_INVAL;
 4992                         goto nfsmout;
 4993                 }
 4994                 offset = len = 0;
 4995                 maxcnt = 0;
 4996         }
 4997         nd->nd_repstat = nfsrv_layoutreturn(nd, vp, layouttype, iomode,
 4998             offset, len, reclaim, kind, &stateid, maxcnt, layp, &fnd,
 4999             nd->nd_cred, p);
 5000         NFSD_DEBUG(4, "nfsrv_layoutreturn stat=%u fnd=%d\n", nd->nd_repstat,
 5001             fnd);
 5002         if (nd->nd_repstat == 0) {
 5003                 NFSM_BUILD(tl, uint32_t *, NFSX_UNSIGNED);
 5004                 if (fnd != 0) {
 5005                         *tl = newnfs_true;
 5006                         NFSM_BUILD(tl, uint32_t *, NFSX_STATEID);
 5007                         *tl++ = txdr_unsigned(stateid.seqid);
 5008                         NFSBCOPY(stateid.other, tl, NFSX_STATEIDOTHER);
 5009                 } else
 5010                         *tl = newnfs_false;
 5011         }
 5012 nfsmout:
 5013         free(layp, M_TEMP);
 5014         vput(vp);
 5015         NFSEXITCODE2(error, nd);
 5016         return (error);
 5017 }
 5018 
 5019 /*
 5020  * nfsv4 layout error service
 5021  */
 5022 int
 5023 nfsrvd_layouterror(struct nfsrv_descript *nd, __unused int isdgram,
 5024     vnode_t vp, struct nfsexstuff *exp)
 5025 {
 5026         uint32_t *tl;
 5027         nfsv4stateid_t stateid;
 5028         int cnt, error = 0, i, stat;
 5029         int opnum __unused;
 5030         char devid[NFSX_V4DEVICEID];
 5031         uint64_t offset, len;
 5032 
 5033         NFSM_DISSECT(tl, uint32_t *, 2 * NFSX_HYPER + NFSX_STATEID +
 5034             NFSX_UNSIGNED);
 5035         offset = fxdr_hyper(tl); tl += 2;
 5036         len = fxdr_hyper(tl); tl += 2;
 5037         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
 5038         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
 5039         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 5040         cnt = fxdr_unsigned(int, *tl);
 5041         NFSD_DEBUG(4, "layouterror off=%ju len=%ju cnt=%d\n", (uintmax_t)offset,
 5042             (uintmax_t)len, cnt);
 5043         /*
 5044          * For the special stateid of other all 0s and seqid == 1, set
 5045          * the stateid to the current stateid, if it is set.
 5046          */
 5047         if (stateid.seqid == 1 && stateid.other[0] == 0 &&
 5048             stateid.other[1] == 0 && stateid.other[2] == 0) {
 5049                 if ((nd->nd_flag & ND_CURSTATEID) != 0) {
 5050                         stateid = nd->nd_curstateid;
 5051                         stateid.seqid = 0;
 5052                 } else {
 5053                         nd->nd_repstat = NFSERR_BADSTATEID;
 5054                         goto nfsmout;
 5055                 }
 5056         }
 5057 
 5058         /*
 5059          * Ignore offset, len and stateid for now.
 5060          */
 5061         for (i = 0; i < cnt; i++) {
 5062                 NFSM_DISSECT(tl, uint32_t *, NFSX_V4DEVICEID + 2 *
 5063                     NFSX_UNSIGNED);
 5064                 NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
 5065                 tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
 5066                 stat = fxdr_unsigned(int, *tl++);
 5067                 opnum = fxdr_unsigned(int, *tl);
 5068                 NFSD_DEBUG(4, "nfsrvd_layouterr op=%d stat=%d\n", opnum, stat);
 5069                 /*
 5070                  * Except for NFSERR_ACCES, NFSERR_STALE and NFSERR_NOSPC
 5071                  * errors, disable the mirror.
 5072                  */
 5073                 if (stat != NFSERR_ACCES && stat != NFSERR_STALE &&
 5074                     stat != NFSERR_NOSPC)
 5075                         nfsrv_delds(devid, curthread);
 5076 
 5077                 /* For NFSERR_NOSPC, mark all deviceids and layouts. */
 5078                 if (stat == NFSERR_NOSPC)
 5079                         nfsrv_marknospc(devid, true);
 5080         }
 5081 nfsmout:
 5082         vput(vp);
 5083         NFSEXITCODE2(error, nd);
 5084         return (error);
 5085 }
 5086 
 5087 /*
 5088  * nfsv4 layout stats service
 5089  */
 5090 int
 5091 nfsrvd_layoutstats(struct nfsrv_descript *nd, __unused int isdgram,
 5092     vnode_t vp, struct nfsexstuff *exp)
 5093 {
 5094         uint32_t *tl;
 5095         nfsv4stateid_t stateid;
 5096         int cnt, error = 0;
 5097         int layouttype __unused;
 5098         char devid[NFSX_V4DEVICEID] __unused;
 5099         uint64_t offset, len, readcount, readbytes, writecount, writebytes
 5100             __unused;
 5101 
 5102         NFSM_DISSECT(tl, uint32_t *, 6 * NFSX_HYPER + NFSX_STATEID +
 5103             NFSX_V4DEVICEID + 2 * NFSX_UNSIGNED);
 5104         offset = fxdr_hyper(tl); tl += 2;
 5105         len = fxdr_hyper(tl); tl += 2;
 5106         stateid.seqid = fxdr_unsigned(uint32_t, *tl++);
 5107         NFSBCOPY(tl, stateid.other, NFSX_STATEIDOTHER);
 5108         tl += (NFSX_STATEIDOTHER / NFSX_UNSIGNED);
 5109         readcount = fxdr_hyper(tl); tl += 2;
 5110         readbytes = fxdr_hyper(tl); tl += 2;
 5111         writecount = fxdr_hyper(tl); tl += 2;
 5112         writebytes = fxdr_hyper(tl); tl += 2;
 5113         NFSBCOPY(tl, devid, NFSX_V4DEVICEID);
 5114         tl += (NFSX_V4DEVICEID / NFSX_UNSIGNED);
 5115         layouttype = fxdr_unsigned(int, *tl++);
 5116         cnt = fxdr_unsigned(int, *tl);
 5117         error = nfsm_advance(nd, NFSM_RNDUP(cnt), -1);
 5118         if (error != 0)
 5119                 goto nfsmout;
 5120