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