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

Cache object: a57d50cbf105200badf22bfd6fcda68c


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


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.