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