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


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

FreeBSD/Linux Kernel Cross Reference
sys/fs/nfsserver/nfs_nfsdserv.c

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

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