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