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

Cache object: 1218114f1ba492101248856ed5621eeb


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


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