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

Cache object: c16e072b895d39de819fd00e5435b7b3


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