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