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

Cache object: fd6d5c26ca4ef1c8f6142cce756a377b


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