xref: /openbsd/sys/nfs/nfs_serv.c (revision 98d98fd9)
1 /*	$OpenBSD: nfs_serv.c,v 1.127 2024/08/17 07:02:13 jsg Exp $	*/
2 /*     $NetBSD: nfs_serv.c,v 1.34 1997/05/12 23:37:12 fvdl Exp $       */
3 
4 /*
5  * Copyright (c) 1989, 1993
6  *	The Regents of the University of California.  All rights reserved.
7  *
8  * This code is derived from software contributed to Berkeley by
9  * Rick Macklem at The University of Guelph.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. Neither the name of the University nor the names of its contributors
20  *    may be used to endorse or promote products derived from this software
21  *    without specific prior written permission.
22  *
23  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
24  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
25  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
26  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
27  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
28  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
29  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
30  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
31  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
32  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33  * SUCH DAMAGE.
34  *
35  *	@(#)nfs_serv.c	8.7 (Berkeley) 5/14/95
36  */
37 
38 /*
39  * nfs version 2 and 3 server calls to vnode ops
40  * - these routines generally have 3 phases
41  *   1 - break down and validate rpc request in mbuf list
42  *   2 - do the vnode ops for the request
43  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
44  *   3 - build the rpc reply in an mbuf list
45  *   nb:
46  *	- do not mix the phases, since use of the nfsm_?? functions can cause
47  *	  us to return failures on a bad rpc or similar without doing any
48  *	  vrele() or vput()'s
49  *      - the nfsm_reply() function generates an nfs rpc reply with the nfs
50  *	  error number iff error != 0 whereas returning an error from the
51  *	  server function implies a fatal error such as a badly constructed rpc
52  *	  request that should be dropped without a reply.
53  *	For Version 3, we do not return after nfsm_reply() for the error case,
54  *	since most version 3 rpcs return more than the status for error cases.
55  */
56 
57 #include <sys/param.h>
58 #include <sys/systm.h>
59 #include <sys/proc.h>
60 #include <sys/namei.h>
61 #include <sys/vnode.h>
62 #include <sys/lock.h>
63 #include <sys/mount.h>
64 #include <sys/socket.h>
65 #include <sys/socketvar.h>
66 #include <sys/mbuf.h>
67 #include <sys/dirent.h>
68 #include <sys/stat.h>
69 #include <sys/pool.h>
70 #include <sys/unistd.h>
71 
72 #include <ufs/ufs/dir.h>
73 
74 #include <nfs/nfsproto.h>
75 #include <nfs/nfs.h>
76 #include <nfs/xdr_subs.h>
77 #include <nfs/nfs_var.h>
78 #include <nfs/nfsm_subs.h>
79 
80 /* Global vars */
81 extern u_int32_t nfs_xdrneg1;
82 extern u_int32_t nfs_false, nfs_true;
83 extern const enum vtype nv3tov_type[8];
84 extern struct nfsstats nfsstats;
85 
86 int nfsrv_access(struct vnode *, int, struct ucred *, int, struct proc *, int);
87 
88 static inline int
89 nfsm_reply(struct nfsm_info *infop, struct nfsrv_descript *nfsd,
90     struct nfssvc_sock *slp, struct mbuf **mrq, int error, int statuslen)
91 {
92 	nfsd->nd_repstat = error;
93 	if (error && !infop->nmi_v3)
94 		statuslen = 0;
95 	(void)nfs_rephead(statuslen, nfsd, slp, error,
96 		&infop->nmi_mreq, &infop->nmi_mb);
97 	if (infop->nmi_mrep != NULL) {
98 		m_freem(infop->nmi_mrep);
99 		infop->nmi_mrep = NULL;
100 	}
101 	*mrq = infop->nmi_mreq;
102 	if (error && (!infop->nmi_v3 || error == EBADRPC))
103 		return error;
104 	return 0;
105 }
106 
107 static inline int
108 nfsm_srvmtofh1(struct nfsm_info *infop, struct nfsrv_descript *nfsd,
109     struct nfssvc_sock *slp, struct mbuf **mrq)
110 {
111 	if (infop->nmi_v3) {
112 		uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_UNSIGNED);
113 		if (tl == NULL)
114 			return 0; /* *infop->nmi_errorp set */
115 		if (fxdr_unsigned(int, *tl) != NFSX_V3FH) {
116 			*infop->nmi_errorp = EBADRPC;
117 			return nfsm_reply(infop, nfsd, slp, mrq,
118 			    *infop->nmi_errorp, 0);
119 		}
120 	}
121 	return 0;
122 }
123 
124 static inline int
125 nfsm_srvmtofh2(struct nfsm_info *infop, fhandle_t *fhp)
126 {
127 	uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_V3FH);
128 	if (tl == NULL)
129 		return 1;
130 	bcopy(tl, fhp, NFSX_V3FH);
131 	if (infop->nmi_v3 == 0) {
132 		if (nfsm_adv(infop, NFSX_V2FH - NFSX_V3FH) != 0)
133 			return 1;
134 	}
135 	return 0;
136 }
137 
138 /*
139  * nfs v3 access service
140  */
141 int
142 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
143     struct proc *procp, struct mbuf **mrq)
144 {
145 	struct mbuf *nam = nfsd->nd_nam;
146 	struct nfsm_info	info;
147 	struct ucred *cred = &nfsd->nd_cr;
148 	struct vnode *vp;
149 	nfsfh_t nfh;
150 	fhandle_t *fhp;
151 	u_int32_t *tl;
152 	int error = 0, rdonly, getret;
153 	struct vattr va;
154 	u_long testmode, nfsmode;
155 
156 	info.nmi_mreq = NULL;
157 	info.nmi_mrep = nfsd->nd_mrep;
158 	info.nmi_md = nfsd->nd_md;
159 	info.nmi_dpos = nfsd->nd_dpos;
160 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
161 	info.nmi_errorp = &error;
162 
163 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
164 		return 0;
165 	else if (error != 0)
166 		goto nfsmout;
167 	fhp = &nfh.fh_generic;
168 	if (nfsm_srvmtofh2(&info, fhp) != 0)
169 		goto nfsmout;
170 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
171 	if (tl == NULL)
172 		goto nfsmout;
173 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
174 	if (error) {
175 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
176 		    NFSX_UNSIGNED) != 0)
177 			return 0;
178 		nfsm_srvpostop_attr(nfsd, 1, NULL, &info);
179 		error = 0;
180 		goto nfsmout;
181 	}
182 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
183 	if ((nfsmode & NFSV3ACCESS_READ) &&
184 		nfsrv_access(vp, VREAD, cred, rdonly, procp, 0))
185 		nfsmode &= ~NFSV3ACCESS_READ;
186 	if (vp->v_type == VDIR)
187 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
188 			NFSV3ACCESS_DELETE);
189 	else
190 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
191 	if ((nfsmode & testmode) &&
192 		nfsrv_access(vp, VWRITE, cred, rdonly, procp, 0))
193 		nfsmode &= ~testmode;
194 	if (vp->v_type == VDIR)
195 		testmode = NFSV3ACCESS_LOOKUP;
196 	else
197 		testmode = NFSV3ACCESS_EXECUTE;
198 	if ((nfsmode & testmode) &&
199 		nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0))
200 		nfsmode &= ~testmode;
201 	getret = VOP_GETATTR(vp, &va, cred, procp);
202 	vput(vp);
203 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
204 	    NFSX_POSTOPATTR(1) + NFSX_UNSIGNED) != 0)
205 		return 0;
206 	nfsm_srvpostop_attr(nfsd, getret, &va, &info);
207 	tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED);
208 	*tl = txdr_unsigned(nfsmode);
209 nfsmout:
210 	return(error);
211 }
212 
213 /*
214  * nfs getattr service
215  */
216 int
217 nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
218     struct proc *procp, struct mbuf **mrq)
219 {
220 	struct mbuf *nam = nfsd->nd_nam;
221 	struct nfsm_info	info;
222 	struct ucred *cred = &nfsd->nd_cr;
223 	struct nfs_fattr *fp;
224 	struct vattr va;
225 	struct vnode *vp;
226 	nfsfh_t nfh;
227 	fhandle_t *fhp;
228 	int error = 0, rdonly;
229 
230 	info.nmi_mreq = NULL;
231 	info.nmi_mrep = nfsd->nd_mrep;
232 	info.nmi_md = nfsd->nd_md;
233 	info.nmi_dpos = nfsd->nd_dpos;
234 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
235 	info.nmi_errorp = &error;
236 
237 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
238 		return 0;
239 	else if (error != 0)
240 		goto nfsmout;
241 	fhp = &nfh.fh_generic;
242 	if (nfsm_srvmtofh2(&info, fhp) != 0)
243 		goto nfsmout;
244 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
245 	if (error) {
246 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
247 			return 0;
248 		error = 0;
249 		goto nfsmout;
250 	}
251 	error = VOP_GETATTR(vp, &va, cred, procp);
252 	vput(vp);
253 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
254 	    NFSX_FATTR(nfsd->nd_flag & ND_NFSV3)) != 0)
255 		return 0;
256 	if (error) {
257 		error = 0;
258 		goto nfsmout;
259 	}
260 	fp = nfsm_build(&info.nmi_mb, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
261 	nfsm_srvfattr(nfsd, &va, fp);
262 nfsmout:
263 	return(error);
264 }
265 
266 /*
267  * nfs setattr service
268  */
269 int
270 nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
271     struct proc *procp, struct mbuf **mrq)
272 {
273 	struct mbuf *nam = nfsd->nd_nam;
274 	struct nfsm_info	info;
275 	struct ucred *cred = &nfsd->nd_cr;
276 	struct vattr va, preat;
277 	struct nfsv2_sattr *sp;
278 	struct nfs_fattr *fp;
279 	struct vnode *vp;
280 	nfsfh_t nfh;
281 	fhandle_t *fhp;
282 	u_int32_t *tl;
283 	int error = 0, rdonly, preat_ret = 1, postat_ret = 1;
284 	int gcheck = 0;
285 	struct timespec guard;
286 
287 	info.nmi_mreq = NULL;
288 	info.nmi_mrep = nfsd->nd_mrep;
289 	info.nmi_md = nfsd->nd_md;
290 	info.nmi_dpos = nfsd->nd_dpos;
291 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
292 	info.nmi_errorp = &error;
293 
294 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
295 		return 0;
296 	else if (error != 0)
297 		goto nfsmout;
298 	fhp = &nfh.fh_generic;
299 	if (nfsm_srvmtofh2(&info, fhp) != 0)
300 		goto nfsmout;
301 	VATTR_NULL(&va);
302 	if (info.nmi_v3) {
303 		va.va_vaflags |= VA_UTIMES_NULL;
304 		error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos);
305 		if (error)
306 			goto nfsmout;
307 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
308 		if (tl == NULL)
309 			goto nfsmout;
310 		gcheck = fxdr_unsigned(int, *tl);
311 		if (gcheck) {
312 			tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
313 			if (tl == NULL)
314 				goto nfsmout;
315 			fxdr_nfsv3time(tl, &guard);
316 		}
317 	} else {
318 		sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR);
319 		if (sp == NULL)
320 			goto nfsmout;
321 		/*
322 		 * Nah nah nah nah na nah
323 		 * There is a bug in the Sun client that puts 0xffff in the mode
324 		 * field of sattr when it should put in 0xffffffff. The u_short
325 		 * doesn't sign extend.
326 		 * --> check the low order 2 bytes for 0xffff
327 		 */
328 		if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
329 			va.va_mode = nfstov_mode(sp->sa_mode);
330 		if (sp->sa_uid != nfs_xdrneg1)
331 			va.va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
332 		if (sp->sa_gid != nfs_xdrneg1)
333 			va.va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
334 		if (sp->sa_size != nfs_xdrneg1)
335 			va.va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
336 		if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
337 #ifdef notyet
338 			fxdr_nfsv2time(&sp->sa_atime, &va.va_atime);
339 #else
340 			va.va_atime.tv_sec =
341 				fxdr_unsigned(u_int32_t,sp->sa_atime.nfsv2_sec);
342 			va.va_atime.tv_nsec = 0;
343 #endif
344 		}
345 		if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
346 			fxdr_nfsv2time(&sp->sa_mtime, &va.va_mtime);
347 
348 	}
349 
350 	/*
351 	 * Now that we have all the fields, lets do it.
352 	 */
353 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
354 	if (error) {
355 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
356 		    2 * NFSX_UNSIGNED) != 0)
357 			return 0;
358 		nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va, &info);
359 		error = 0;
360 		goto nfsmout;
361 	}
362 	if (info.nmi_v3) {
363 		error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
364 		if (!error && gcheck &&
365 			(preat.va_ctime.tv_sec != guard.tv_sec ||
366 			 preat.va_ctime.tv_nsec != guard.tv_nsec))
367 			error = NFSERR_NOT_SYNC;
368 		if (error) {
369 			vput(vp);
370 			if (nfsm_reply(&info, nfsd, slp, mrq, error,
371 			    NFSX_WCCDATA(info.nmi_v3)) != 0)
372 				return 0;
373 			nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va,
374 			    &info);
375 			error = 0;
376 			goto nfsmout;
377 		}
378 	}
379 
380 	/*
381 	 * If the size is being changed write access is required, otherwise
382 	 * just check for a read only file system.
383 	 */
384 	if (va.va_size == ((u_quad_t)((quad_t) -1))) {
385 		if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
386 			error = EROFS;
387 			goto out;
388 		}
389 	} else {
390 		if (vp->v_type == VDIR) {
391 			error = EISDIR;
392 			goto out;
393 		} else if ((error = nfsrv_access(vp, VWRITE, cred, rdonly,
394 			procp, 1)) != 0)
395 			goto out;
396 	}
397 	error = VOP_SETATTR(vp, &va, cred, procp);
398 	postat_ret = VOP_GETATTR(vp, &va, cred, procp);
399 	if (!error)
400 		error = postat_ret;
401 out:
402 	vput(vp);
403 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
404 	    NFSX_WCCORFATTR(info.nmi_v3)) != 0)
405 		return 0;
406 	if (info.nmi_v3) {
407 		nfsm_srvwcc(nfsd, preat_ret, &preat, postat_ret, &va,
408 		    &info);
409 		error = 0;
410 		goto nfsmout;
411 	} else {
412 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
413 		nfsm_srvfattr(nfsd, &va, fp);
414 	}
415 nfsmout:
416 	return(error);
417 }
418 
419 static inline int
420 nfsm_srvnamesiz(struct nfsm_info *infop, int *lenp)
421 {
422 	int len;
423 	uint32_t *tl = (uint32_t *)nfsm_dissect(infop, NFSX_UNSIGNED);
424 	if (tl == NULL)
425 		return 1;
426 	len = fxdr_unsigned(int32_t, *tl);
427 	if (len > NFS_MAXNAMLEN)
428 		*infop->nmi_errorp = NFSERR_NAMETOL;
429 	else if (len <= 0)
430 		*infop->nmi_errorp = EBADRPC;
431 	else {
432 		*infop->nmi_errorp = 0;
433 		*lenp = len;
434 	}
435 	return 0;
436 }
437 
438 /*
439  * nfs lookup rpc
440  */
441 int
442 nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
443     struct proc *procp, struct mbuf **mrq)
444 {
445 	struct mbuf *nam = nfsd->nd_nam;
446 	struct ucred *cred = &nfsd->nd_cr;
447 	struct nfs_fattr *fp;
448 	struct nameidata nd;
449 	struct vnode *vp, *dirp;
450 	struct nfsm_info	info;
451 	nfsfh_t nfh;
452 	fhandle_t *fhp;
453 	int error = 0, len, dirattr_ret = 1;
454 	int v3 = (nfsd->nd_flag & ND_NFSV3);
455 	struct vattr va, dirattr;
456 
457 	info.nmi_mrep = nfsd->nd_mrep;
458 	info.nmi_mreq = NULL;
459 	info.nmi_md = nfsd->nd_md;
460 	info.nmi_dpos = nfsd->nd_dpos;
461 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
462 	info.nmi_errorp = &error;
463 
464 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
465 		return 0;
466 	else if (error != 0)
467 		goto nfsmout;
468 	fhp = &nfh.fh_generic;
469 	if (nfsm_srvmtofh2(&info, fhp) != 0)
470 		goto nfsmout;
471 	if (nfsm_srvnamesiz(&info, &len) != 0)
472 		goto nfsmout;
473 	if (error) {
474 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
475 			return 0;
476 	}
477 
478 	NDINIT(&nd, LOOKUP, LOCKLEAF | SAVESTART, UIO_SYSSPACE, NULL, procp);
479 	nd.ni_cnd.cn_cred = cred;
480 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp);
481 	if (dirp) {
482 		if (info.nmi_v3)
483 			dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
484 				procp);
485 		vrele(dirp);
486 	}
487 	if (error) {
488 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
489 		    NFSX_POSTOPATTR(info.nmi_v3)) != 0)
490 			return 0;
491 		nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info);
492 		return (0);
493 	}
494 	vrele(nd.ni_startdir);
495 	pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
496 	vp = nd.ni_vp;
497 	memset(fhp, 0, sizeof(nfh));
498 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
499 	error = VFS_VPTOFH(vp, &fhp->fh_fid);
500 	if (!error)
501 		error = VOP_GETATTR(vp, &va, cred, procp);
502 	vput(vp);
503 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
504 	    NFSX_SRVFH(info.nmi_v3) + NFSX_POSTOPORFATTR(info.nmi_v3) +
505 	    NFSX_POSTOPATTR(info.nmi_v3)) != 0)
506 		return 0;
507 	if (error) {
508 		nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info);
509 		error = 0;
510 		goto nfsmout;
511 	}
512 	nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3);
513 	if (v3) {
514 		nfsm_srvpostop_attr(nfsd, 0, &va, &info);
515 		nfsm_srvpostop_attr(nfsd, dirattr_ret, &dirattr, &info);
516 	} else {
517 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
518 		nfsm_srvfattr(nfsd, &va, fp);
519 	}
520 nfsmout:
521 	return(error);
522 }
523 
524 /*
525  * nfs readlink service
526  */
527 int
528 nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
529     struct proc *procp, struct mbuf **mrq)
530 {
531 	struct mbuf *nam = nfsd->nd_nam;
532 	struct ucred *cred = &nfsd->nd_cr;
533 	struct iovec iov;
534 	struct mbuf *mp = NULL;
535 	struct nfsm_info	info;
536 	u_int32_t *tl;
537 	int error = 0, rdonly, tlen, len = 0, getret;
538 	struct vnode *vp;
539 	struct vattr attr;
540 	nfsfh_t nfh;
541 	fhandle_t *fhp;
542 	struct uio uio;
543 
544 	info.nmi_mreq = NULL;
545 	info.nmi_mrep = nfsd->nd_mrep;
546 	info.nmi_md = nfsd->nd_md;
547 	info.nmi_dpos = nfsd->nd_dpos;
548 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
549 	info.nmi_errorp = &error;
550 
551 	memset(&uio, 0, sizeof(uio));
552 
553 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
554 		return 0;
555 	else if (error != 0)
556 		goto nfsmout;
557 	fhp = &nfh.fh_generic;
558 	if (nfsm_srvmtofh2(&info, fhp) != 0)
559 		goto nfsmout;
560 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
561 	if (error) {
562 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
563 		    2 * NFSX_UNSIGNED) != 0)
564 			return 0;
565 		nfsm_srvpostop_attr(nfsd, 1, NULL, &info);
566 		error = 0;
567 		goto nfsmout;
568 	}
569 	if (vp->v_type != VLNK) {
570 		if (info.nmi_v3)
571 			error = EINVAL;
572 		else
573 			error = ENXIO;
574 		goto out;
575 	}
576 
577 	MGET(mp, M_WAIT, MT_DATA);
578 	MCLGET(mp, M_WAIT);		/* MLEN < NFS_MAXPATHLEN < MCLBYTES */
579 	mp->m_len = NFS_MAXPATHLEN;
580 	len = NFS_MAXPATHLEN;
581 	iov.iov_base = mtod(mp, caddr_t);
582 	iov.iov_len = mp->m_len;
583 
584 	uio.uio_iov = &iov;
585 	uio.uio_iovcnt = 1;
586 	uio.uio_offset = 0;
587 	uio.uio_resid = NFS_MAXPATHLEN;
588 	uio.uio_rw = UIO_READ;
589 	uio.uio_segflg = UIO_SYSSPACE;
590 	uio.uio_procp = NULL;
591 
592 	error = VOP_READLINK(vp, &uio, cred);
593 out:
594 	getret = VOP_GETATTR(vp, &attr, cred, procp);
595 	vput(vp);
596 	if (error)
597 		m_freem(mp);
598 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
599 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_UNSIGNED) != 0)
600 		return 0;
601 	if (info.nmi_v3) {
602 		nfsm_srvpostop_attr(nfsd, getret, &attr, &info);
603 		if (error) {
604 			error = 0;
605 			goto nfsmout;
606 		}
607 	}
608 	if (uio.uio_resid > 0) {
609 		len -= uio.uio_resid;
610 		tlen = nfsm_rndup(len);
611 		nfsm_adj(mp, NFS_MAXPATHLEN-tlen, tlen-len);
612 	}
613 	tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED);
614 	*tl = txdr_unsigned(len);
615 	info.nmi_mb->m_next = mp;
616 
617 nfsmout:
618 	return (error);
619 }
620 
621 /*
622  * nfs read service
623  */
624 int
625 nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
626     struct proc *procp, struct mbuf **mrq)
627 {
628 	struct mbuf *nam = nfsd->nd_nam;
629 	struct ucred *cred = &nfsd->nd_cr;
630 	struct mbuf *m;
631 	struct nfs_fattr *fp;
632 	struct nfsm_info	info;
633 	u_int32_t *tl;
634 	int i, reqlen;
635 	int error = 0, rdonly, cnt, len, left, siz, tlen, getret = 1;
636 	struct mbuf *m2;
637 	struct vnode *vp;
638 	nfsfh_t nfh;
639 	fhandle_t *fhp;
640 	struct uio io, *uiop = &io;
641 	struct vattr va;
642 	off_t off;
643 
644 	info.nmi_mreq = NULL;
645 	info.nmi_mrep = nfsd->nd_mrep;
646 	info.nmi_md = nfsd->nd_md;
647 	info.nmi_dpos = nfsd->nd_dpos;
648 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
649 	info.nmi_errorp = &error;
650 
651 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
652 		return 0;
653 	else if (error != 0)
654 		goto nfsmout;
655 	fhp = &nfh.fh_generic;
656 	if (nfsm_srvmtofh2(&info, fhp) != 0)
657 		goto nfsmout;
658 	if (info.nmi_v3) {
659 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
660 		if (tl == NULL)
661 			goto nfsmout;
662 		off = fxdr_hyper(tl);
663 	} else {
664 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
665 		if (tl == NULL)
666 			goto nfsmout;
667 		off = (off_t)fxdr_unsigned(u_int32_t, *tl);
668 	}
669 
670 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
671 	if (tl == NULL)
672 		goto nfsmout;
673 	reqlen = fxdr_unsigned(int32_t, *tl);
674 	if (reqlen > (NFS_SRVMAXDATA(nfsd)) || reqlen <= 0) {
675 		error = EBADRPC;
676 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
677 			return 0;
678 	}
679 
680 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
681 	if (error)
682 		goto bad;
683 
684 	if (vp->v_type != VREG) {
685 		if (info.nmi_v3)
686 			error = EINVAL;
687 		else
688 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
689 	}
690 	if (!error) {
691 	    if ((error = nfsrv_access(vp, VREAD, cred, rdonly, procp, 1)) != 0)
692 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 1);
693 	}
694 	getret = VOP_GETATTR(vp, &va, cred, procp);
695 	if (!error)
696 		error = getret;
697 	if (error)
698 		goto vbad;
699 
700 	if (off >= va.va_size)
701 		cnt = 0;
702 	else if ((off + reqlen) > va.va_size)
703 		cnt = va.va_size - off;
704 	else
705 		cnt = reqlen;
706 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
707 	    NFSX_POSTOPORFATTR(info.nmi_v3) +
708 	    3 * NFSX_UNSIGNED+nfsm_rndup(cnt)) != 0)
709 		return 0;
710 	if (info.nmi_v3) {
711 		tl = nfsm_build(&info.nmi_mb, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
712 		*tl++ = nfs_true;
713 		fp = (struct nfs_fattr *)tl;
714 		tl += (NFSX_V3FATTR / sizeof (u_int32_t));
715 	} else {
716 		tl = nfsm_build(&info.nmi_mb, NFSX_V2FATTR + NFSX_UNSIGNED);
717 		fp = (struct nfs_fattr *)tl;
718 		tl += (NFSX_V2FATTR / sizeof (u_int32_t));
719 	}
720 	len = left = nfsm_rndup (cnt);
721 	if (cnt > 0) {
722 		struct iovec *iv, *iv2;
723 		size_t ivlen;
724 		/*
725 		 * Generate the mbuf list with the uio_iov ref. to it.
726 		 */
727 		i = 0;
728 		m = m2 = info.nmi_mb;
729 		while (left > 0) {
730 			siz = min(m_trailingspace(m), left);
731 			if (siz > 0) {
732 				left -= siz;
733 				i++;
734 			}
735 			if (left > 0) {
736 				MGET(m, M_WAIT, MT_DATA);
737 				if (left >= MINCLSIZE)
738 					MCLGET(m, M_WAIT);
739 				m->m_len = 0;
740 				m2->m_next = m;
741 				m2 = m;
742 			}
743 		}
744 		iv = mallocarray(i, sizeof(*iv), M_TEMP, M_WAITOK);
745 		ivlen = i * sizeof(*iv);
746 		uiop->uio_iov = iv2 = iv;
747 		m = info.nmi_mb;
748 		left = len;
749 		i = 0;
750 		while (left > 0) {
751 			if (m == NULL)
752 				panic("nfsrv_read iov");
753 			siz = min(m_trailingspace(m), left);
754 			if (siz > 0) {
755 				iv->iov_base = mtod(m, caddr_t) + m->m_len;
756 				iv->iov_len = siz;
757 				m->m_len += siz;
758 				left -= siz;
759 				iv++;
760 				i++;
761 			}
762 			m = m->m_next;
763 		}
764 		uiop->uio_iovcnt = i;
765 		uiop->uio_offset = off;
766 		uiop->uio_resid = len;
767 		uiop->uio_rw = UIO_READ;
768 		uiop->uio_segflg = UIO_SYSSPACE;
769 		error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
770 		off = uiop->uio_offset;
771 		free(iv2, M_TEMP, ivlen);
772 		if (error || (getret = VOP_GETATTR(vp, &va, cred, procp)) != 0){
773 			if (!error)
774 				error = getret;
775 			m_freem(info.nmi_mreq);
776 			goto vbad;
777 		}
778 	} else
779 		uiop->uio_resid = 0;
780 	vput(vp);
781 	nfsm_srvfattr(nfsd, &va, fp);
782 	tlen = len - uiop->uio_resid;
783 	cnt = cnt < tlen ? cnt : tlen;
784 	tlen = nfsm_rndup (cnt);
785 	if (len != tlen || tlen != cnt)
786 		nfsm_adj(info.nmi_mb, len - tlen, tlen - cnt);
787 	if (info.nmi_v3) {
788 		*tl++ = txdr_unsigned(cnt);
789 		if (len < reqlen)
790 			*tl++ = nfs_true;
791 		else
792 			*tl++ = nfs_false;
793 	}
794 	*tl = txdr_unsigned(cnt);
795 nfsmout:
796 	return(error);
797 
798 vbad:
799 	vput(vp);
800 bad:
801 	if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
802 		return 0;
803 	nfsm_srvpostop_attr(nfsd, getret, &va, &info);
804 	return (0);
805 }
806 
807 /*
808  * nfs write service
809  */
810 int
811 nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
812     struct proc *procp, struct mbuf **mrq)
813 {
814 	struct mbuf *nam = nfsd->nd_nam;
815 	struct ucred *cred = &nfsd->nd_cr;
816 	struct nfsm_info	info;
817 	int i, cnt;
818 	struct mbuf *mp;
819 	struct nfs_fattr *fp;
820 	struct timeval boottime;
821 	struct vattr va, forat;
822 	u_int32_t *tl;
823 	int error = 0, rdonly, len, forat_ret = 1;
824 	int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
825 	int stable = NFSV3WRITE_FILESYNC;
826 	struct vnode *vp;
827 	nfsfh_t nfh;
828 	fhandle_t *fhp;
829 	struct uio io, *uiop = &io;
830 	off_t off;
831 
832 	info.nmi_mreq = NULL;
833 	info.nmi_mrep = nfsd->nd_mrep;
834 	info.nmi_md = nfsd->nd_md;
835 	info.nmi_dpos = nfsd->nd_dpos;
836 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
837 	info.nmi_errorp = &error;
838 
839 	if (info.nmi_mrep == NULL) {
840 		*mrq = NULL;
841 		return (0);
842 	}
843 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
844 		return 0;
845 	else if (error != 0)
846 		goto nfsmout;
847 	fhp = &nfh.fh_generic;
848 	if (nfsm_srvmtofh2(&info, fhp) != 0)
849 		goto nfsmout;
850 	if (info.nmi_v3) {
851 		tl = (uint32_t *)nfsm_dissect(&info, 5 * NFSX_UNSIGNED);
852 		if (tl == NULL)
853 			goto nfsmout;
854 		off = fxdr_hyper(tl);
855 		tl += 3;
856 		stable = fxdr_unsigned(int, *tl++);
857 	} else {
858 		tl = (uint32_t *)nfsm_dissect(&info, 4 * NFSX_UNSIGNED);
859 		if (tl == NULL)
860 			goto nfsmout;
861 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
862 		tl += 2;
863 	}
864 	retlen = len = fxdr_unsigned(int32_t, *tl);
865 	cnt = i = 0;
866 
867 	/*
868 	 * For NFS Version 2, it is not obvious what a write of zero length
869 	 * should do, but I might as well be consistent with Version 3,
870 	 * which is to return ok so long as there are no permission problems.
871 	 */
872 	if (len > 0) {
873 	    zeroing = 1;
874 	    mp = info.nmi_mrep;
875 	    while (mp) {
876 		if (mp == info.nmi_md) {
877 			zeroing = 0;
878 			adjust = info.nmi_dpos - mtod(mp, caddr_t);
879 			mp->m_len -= adjust;
880 			if (mp->m_len > 0 && adjust > 0)
881 				mp->m_data += adjust;
882 		}
883 		if (zeroing)
884 			mp->m_len = 0;
885 		else if (mp->m_len > 0) {
886 			i += mp->m_len;
887 			if (i > len) {
888 				mp->m_len -= (i - len);
889 				zeroing	= 1;
890 			}
891 			if (mp->m_len > 0)
892 				cnt++;
893 		}
894 		mp = mp->m_next;
895 	    }
896 	}
897 	if (len > NFS_MAXDATA || len < 0 || i < len) {
898 		error = EIO;
899 		goto bad;
900 	}
901 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
902 	if (error)
903 		goto bad;
904 	if (info.nmi_v3)
905 		forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
906 	if (vp->v_type != VREG) {
907 		if (info.nmi_v3)
908 			error = EINVAL;
909 		else
910 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
911 		goto vbad;
912 	}
913 	error = nfsrv_access(vp, VWRITE, cred, rdonly, procp, 1);
914 	if (error)
915 		goto vbad;
916 
917 	if (len > 0) {
918 	    struct iovec *iv, *ivp;
919 	    size_t ivlen;
920 
921 	    ivp = mallocarray(cnt, sizeof(*ivp), M_TEMP, M_WAITOK);
922 	    ivlen = cnt * sizeof(*ivp);
923 	    uiop->uio_iov = iv = ivp;
924 	    uiop->uio_iovcnt = cnt;
925 	    mp = info.nmi_mrep;
926 	    while (mp) {
927 		if (mp->m_len > 0) {
928 			ivp->iov_base = mtod(mp, caddr_t);
929 			ivp->iov_len = mp->m_len;
930 			ivp++;
931 		}
932 		mp = mp->m_next;
933 	    }
934 
935 	    if (stable == NFSV3WRITE_UNSTABLE)
936 		ioflags = IO_NODELOCKED;
937 	    else if (stable == NFSV3WRITE_DATASYNC)
938 		ioflags = (IO_SYNC | IO_NODELOCKED);
939 	    else
940 		ioflags = (IO_SYNC | IO_NODELOCKED);
941 	    uiop->uio_resid = len;
942 	    uiop->uio_rw = UIO_WRITE;
943 	    uiop->uio_segflg = UIO_SYSSPACE;
944 	    uiop->uio_procp = NULL;
945 	    uiop->uio_offset = off;
946 	    error = VOP_WRITE(vp, uiop, ioflags, cred);
947 	    nfsstats.srvvop_writes++;
948 	    free(iv, M_TEMP, ivlen);
949 	}
950 	aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
951 	vput(vp);
952 	if (!error)
953 		error = aftat_ret;
954 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
955 	    NFSX_PREOPATTR(info.nmi_v3) + NFSX_POSTOPORFATTR(info.nmi_v3) +
956 	    2 * NFSX_UNSIGNED + NFSX_WRITEVERF(info.nmi_v3)) != 0)
957 		return 0;
958 	if (info.nmi_v3) {
959 		nfsm_srvwcc(nfsd, forat_ret, &forat, aftat_ret, &va, &info);
960 		if (error) {
961 			error = 0;
962 			goto nfsmout;
963 		}
964 		tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED);
965 		*tl++ = txdr_unsigned(retlen);
966 		if (stable == NFSV3WRITE_UNSTABLE)
967 			*tl++ = txdr_unsigned(stable);
968 		else
969 			*tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
970 		/*
971 		 * Actually, there is no need to txdr these fields,
972 		 * but it may make the values more human readable,
973 		 * for debugging purposes.
974 		 */
975 		microboottime(&boottime);
976 		*tl++ = txdr_unsigned(boottime.tv_sec);
977 		*tl = txdr_unsigned(boottime.tv_usec);
978 	} else {
979 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
980 		nfsm_srvfattr(nfsd, &va, fp);
981 	}
982 nfsmout:
983 	return(error);
984 
985 vbad:
986 	vput(vp);
987 bad:
988 	if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
989 		return 0;
990 	nfsm_srvwcc(nfsd, forat_ret, &forat, aftat_ret, &va, &info);
991 	return (0);
992 }
993 
994 static inline void
995 nfsm_srvpostop_fh(struct nfsm_info *infop, fhandle_t *fhp)
996 {
997 	uint32_t *tl;
998 
999 	tl = nfsm_build(&infop->nmi_mb, 2 * NFSX_UNSIGNED + NFSX_V3FH);
1000 	*tl++ = nfs_true;
1001 	*tl++ = txdr_unsigned(NFSX_V3FH);
1002 	bcopy(fhp, tl, NFSX_V3FH);
1003 }
1004 
1005 /*
1006  * nfs create service
1007  * now does a truncate to 0 length via. setattr if it already exists
1008  */
1009 int
1010 nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1011     struct proc *procp, struct mbuf **mrq)
1012 {
1013 	struct mbuf *nam = nfsd->nd_nam;
1014 	struct ucred *cred = &nfsd->nd_cr;
1015 	struct nfs_fattr *fp;
1016 	struct vattr va, dirfor, diraft;
1017 	struct nfsv2_sattr *sp;
1018 	struct nfsm_info	info;
1019 	u_int32_t *tl;
1020 	struct nameidata nd;
1021 	caddr_t cp;
1022 	int error = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1023 	dev_t rdev = 0;
1024 	int how, exclusive_flag = 0;
1025 	struct vnode *vp = NULL, *dirp = NULL;
1026 	nfsfh_t nfh;
1027 	fhandle_t *fhp;
1028 	u_quad_t tempsize;
1029 	u_char cverf[NFSX_V3CREATEVERF];
1030 
1031 	info.nmi_mreq = NULL;
1032 	info.nmi_mrep = nfsd->nd_mrep;
1033 	info.nmi_md = nfsd->nd_md;
1034 	info.nmi_dpos = nfsd->nd_dpos;
1035 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1036 	info.nmi_errorp = &error;
1037 
1038 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1039 		return 0;
1040 	else if (error != 0)
1041 		return error;
1042 	fhp = &nfh.fh_generic;
1043 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1044 		return error;
1045 	if (nfsm_srvnamesiz(&info, &len) != 0)
1046 		return error;
1047 	if (error) {
1048 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1049 			return 0;
1050 	}
1051 
1052 	NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | SAVESTART, UIO_SYSSPACE,
1053 	    NULL, procp);
1054 	nd.ni_cnd.cn_cred = cred;
1055 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md,
1056 	    &info.nmi_dpos, &dirp, procp);
1057 	if (dirp) {
1058 		if (info.nmi_v3)
1059 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1060 		else {
1061 			vrele(dirp);
1062 			dirp = NULL;
1063 		}
1064 	}
1065 	if (error) {
1066 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
1067 		    NFSX_WCCDATA(info.nmi_v3)) != 0)
1068 			return 0;
1069 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1070 		    &info);
1071 		if (dirp)
1072 			vrele(dirp);
1073 		return (0);
1074 	}
1075 
1076 	VATTR_NULL(&va);
1077 	if (info.nmi_v3) {
1078 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1079 		if (tl == NULL)
1080 			goto nfsmout;
1081 		how = fxdr_unsigned(int, *tl);
1082 		switch (how) {
1083 		case NFSV3CREATE_GUARDED:
1084 			if (nd.ni_vp) {
1085 				error = EEXIST;
1086 				break;
1087 			}
1088 		case NFSV3CREATE_UNCHECKED:
1089 			error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep,
1090 			    &info.nmi_dpos);
1091 			if (error)
1092 				goto nfsmout;
1093 			break;
1094 		case NFSV3CREATE_EXCLUSIVE:
1095 			cp = (caddr_t)nfsm_dissect(&info, NFSX_V3CREATEVERF);
1096 			if (cp == NULL)
1097 				goto nfsmout;
1098 			bcopy(cp, cverf, NFSX_V3CREATEVERF);
1099 			exclusive_flag = 1;
1100 			if (nd.ni_vp == NULL)
1101 				va.va_mode = 0;
1102 			break;
1103 		};
1104 		va.va_type = VREG;
1105 	} else {
1106 		sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR);
1107 		if (sp == NULL)
1108 			goto nfsmout;
1109 		va.va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1110 		if (va.va_type == VNON)
1111 			va.va_type = VREG;
1112 		va.va_mode = nfstov_mode(sp->sa_mode);
1113 		switch (va.va_type) {
1114 		case VREG:
1115 			tsize = fxdr_unsigned(int32_t, sp->sa_size);
1116 			if (tsize != -1)
1117 				va.va_size = (u_quad_t)tsize;
1118 			break;
1119 		case VCHR:
1120 		case VBLK:
1121 		case VFIFO:
1122 			rdev = (dev_t)fxdr_unsigned(int32_t, sp->sa_size);
1123 			break;
1124 		default:
1125 			break;
1126 		};
1127 	}
1128 
1129 	/*
1130 	 * Iff doesn't exist, create it
1131 	 * otherwise just truncate to 0 length
1132 	 *   should I set the mode too ??
1133 	 */
1134 	if (nd.ni_vp == NULL) {
1135 		if (va.va_type == VREG || va.va_type == VSOCK) {
1136 			vrele(nd.ni_startdir);
1137 			error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd,
1138 			    &va);
1139 			vput(nd.ni_dvp);
1140 			if (!error) {
1141 				pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1142 				if (exclusive_flag) {
1143 					exclusive_flag = 0;
1144 					VATTR_NULL(&va);
1145 					bcopy(cverf, (caddr_t)&va.va_atime,
1146 						NFSX_V3CREATEVERF);
1147 					error = VOP_SETATTR(nd.ni_vp, &va, cred,
1148 						procp);
1149 				}
1150 			}
1151 		} else if (va.va_type == VCHR || va.va_type == VBLK ||
1152 			va.va_type == VFIFO) {
1153 			if (va.va_type == VCHR && rdev == 0xffffffff)
1154 				va.va_type = VFIFO;
1155 			if (va.va_type != VFIFO &&
1156 			    (error = suser_ucred(cred))) {
1157 				vrele(nd.ni_startdir);
1158 				if (nd.ni_cnd.cn_flags & HASBUF) {
1159 					pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1160 					nd.ni_cnd.cn_flags &= ~HASBUF;
1161 				}
1162 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1163 				vput(nd.ni_dvp);
1164 				if (nfsm_reply(&info, nfsd, slp, mrq, error,
1165 				    0) != 0)
1166 					return 0;
1167 				error = 0;
1168 				goto nfsmout;
1169 			} else
1170 				va.va_rdev = (dev_t)rdev;
1171 			error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd,
1172 			    &va);
1173 			vput(nd.ni_dvp);
1174 			if (error) {
1175 				vrele(nd.ni_startdir);
1176 				if (nd.ni_cnd.cn_flags & HASBUF) {
1177 					pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1178 					nd.ni_cnd.cn_flags &= ~HASBUF;
1179 				}
1180 				if (nfsm_reply(&info, nfsd, slp, mrq, error,
1181 				    0) != 0)
1182 					return 0;
1183 				error = 0;
1184 				goto nfsmout;
1185 			}
1186 			nd.ni_cnd.cn_nameiop = LOOKUP;
1187 			nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1188 			nd.ni_cnd.cn_proc = procp;
1189 			nd.ni_cnd.cn_cred = cred;
1190 			if ((error = vfs_lookup(&nd)) != 0) {
1191 				if (nd.ni_cnd.cn_flags & HASBUF) {
1192 					pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1193 					nd.ni_cnd.cn_flags &= ~HASBUF;
1194 				}
1195 				if (nfsm_reply(&info, nfsd, slp, mrq, error,
1196 				    0) != 0)
1197 					return 0;
1198 				error = 0;
1199 				goto nfsmout;
1200 			}
1201 
1202 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1203 			if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1204 				vrele(nd.ni_dvp);
1205 				vput(nd.ni_vp);
1206 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1207 				error = EINVAL;
1208 				if (nfsm_reply(&info, nfsd, slp, mrq, error,
1209 				    0) != 0)
1210 					return 0;
1211 				error = 0;
1212 				goto nfsmout;
1213 			}
1214 		} else {
1215 			vrele(nd.ni_startdir);
1216 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1217 			nd.ni_cnd.cn_flags &= ~HASBUF;
1218 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1219 			vput(nd.ni_dvp);
1220 			error = ENXIO;
1221 		}
1222 		vp = nd.ni_vp;
1223 	} else {
1224 		vrele(nd.ni_startdir);
1225 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1226 		nd.ni_cnd.cn_flags &= ~HASBUF;
1227 		vp = nd.ni_vp;
1228 		if (nd.ni_dvp == vp)
1229 			vrele(nd.ni_dvp);
1230 		else
1231 			vput(nd.ni_dvp);
1232 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1233 		if (va.va_size != -1) {
1234 			error = nfsrv_access(vp, VWRITE, cred,
1235 			    (nd.ni_cnd.cn_flags & RDONLY), procp, 0);
1236 			if (!error) {
1237 				tempsize = va.va_size;
1238 				VATTR_NULL(&va);
1239 				va.va_size = tempsize;
1240 				error = VOP_SETATTR(vp, &va, cred,
1241 					 procp);
1242 			}
1243 			if (error)
1244 				vput(vp);
1245 		}
1246 	}
1247 	if (!error) {
1248 		memset(fhp, 0, sizeof(nfh));
1249 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1250 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
1251 		if (!error)
1252 			error = VOP_GETATTR(vp, &va, cred, procp);
1253 		vput(vp);
1254 	}
1255 	if (info.nmi_v3) {
1256 		if (exclusive_flag && !error &&
1257 			bcmp(cverf, (caddr_t)&va.va_atime, NFSX_V3CREATEVERF))
1258 			error = EEXIST;
1259 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1260 		vrele(dirp);
1261 	}
1262 	if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) +
1263 	    NFSX_FATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0)
1264 		return 0;
1265 	if (info.nmi_v3) {
1266 		if (!error) {
1267 			nfsm_srvpostop_fh(&info, fhp);
1268 			nfsm_srvpostop_attr(nfsd, 0, &va, &info);
1269 		}
1270 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1271 		    &info);
1272 	} else {
1273 		nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3);
1274 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
1275 		nfsm_srvfattr(nfsd, &va, fp);
1276 	}
1277 	return (0);
1278 nfsmout:
1279 	if (dirp)
1280 		vrele(dirp);
1281 	if (nd.ni_cnd.cn_nameiop != LOOKUP) {
1282 		vrele(nd.ni_startdir);
1283 		if (nd.ni_cnd.cn_flags & HASBUF) {
1284 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1285 			nd.ni_cnd.cn_flags &= ~HASBUF;
1286 		}
1287 	}
1288 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1289 	if (nd.ni_dvp == nd.ni_vp)
1290 		vrele(nd.ni_dvp);
1291 	else
1292 		vput(nd.ni_dvp);
1293 	if (nd.ni_vp)
1294 		vput(nd.ni_vp);
1295 	return (error);
1296 }
1297 
1298 /*
1299  * nfs v3 mknod service
1300  */
1301 int
1302 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1303     struct proc *procp, struct mbuf **mrq)
1304 {
1305 	struct mbuf *nam = nfsd->nd_nam;
1306 	struct ucred *cred = &nfsd->nd_cr;
1307 	struct vattr va, dirfor, diraft;
1308 	struct nfsm_info	info;
1309 	u_int32_t *tl;
1310 	struct nameidata nd;
1311 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
1312 	u_int32_t major, minor;
1313 	enum vtype vtyp;
1314 	struct vnode *vp, *dirp = NULL;
1315 	nfsfh_t nfh;
1316 	fhandle_t *fhp;
1317 
1318 	info.nmi_mreq = NULL;
1319 	info.nmi_mrep = nfsd->nd_mrep;
1320 	info.nmi_md = nfsd->nd_md;
1321 	info.nmi_dpos = nfsd->nd_dpos;
1322 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1323 	info.nmi_errorp = &error;
1324 
1325 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1326 		return 0;
1327 	else if (error != 0)
1328 		return error;
1329 	fhp = &nfh.fh_generic;
1330 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1331 		return error;
1332 	if (nfsm_srvnamesiz(&info, &len) != 0)
1333 		return error;
1334 	if (error) {
1335 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1336 			return 0;
1337 	}
1338 
1339 	NDINIT(&nd, CREATE, LOCKPARENT | LOCKLEAF | SAVESTART, UIO_SYSSPACE,
1340 	    NULL, procp);
1341 	nd.ni_cnd.cn_cred = cred;
1342 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp);
1343 	if (dirp)
1344 		dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1345 	if (error) {
1346 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
1347 		    NFSX_WCCDATA(1)) != 0)
1348 			return 0;
1349 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1350 		    &info);
1351 		if (dirp)
1352 			vrele(dirp);
1353 		return (0);
1354 	}
1355 
1356 	tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
1357 	if (tl == NULL)
1358 		goto nfsmout;
1359 	vtyp = nfsv3tov_type(*tl);
1360 	if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1361 		vrele(nd.ni_startdir);
1362 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1363 		error = NFSERR_BADTYPE;
1364 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1365 		if (nd.ni_dvp == nd.ni_vp)
1366 			vrele(nd.ni_dvp);
1367 		else
1368 			vput(nd.ni_dvp);
1369 		if (nd.ni_vp)
1370 			vput(nd.ni_vp);
1371 		goto out;
1372 	}
1373 	VATTR_NULL(&va);
1374 	error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep, &info.nmi_dpos);
1375 	if (error)
1376 		goto nfsmout;
1377 	if (vtyp == VCHR || vtyp == VBLK) {
1378 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
1379 		if (tl == NULL)
1380 			goto nfsmout;
1381 		major = fxdr_unsigned(u_int32_t, *tl++);
1382 		minor = fxdr_unsigned(u_int32_t, *tl);
1383 		va.va_rdev = makedev(major, minor);
1384 	}
1385 
1386 	/*
1387 	 * Iff doesn't exist, create it.
1388 	 */
1389 	if (nd.ni_vp) {
1390 		vrele(nd.ni_startdir);
1391 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1392 		error = EEXIST;
1393 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1394 		if (nd.ni_dvp == nd.ni_vp)
1395 			vrele(nd.ni_dvp);
1396 		else
1397 			vput(nd.ni_dvp);
1398 		vput(nd.ni_vp);
1399 		goto out;
1400 	}
1401 	va.va_type = vtyp;
1402 	if (vtyp == VSOCK) {
1403 		vrele(nd.ni_startdir);
1404 		error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1405 		vput(nd.ni_dvp);
1406 		if (!error)
1407 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1408 	} else {
1409 		if (va.va_type != VFIFO &&
1410 		    (error = suser_ucred(cred))) {
1411 			vrele(nd.ni_startdir);
1412 			pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1413 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1414 			vput(nd.ni_dvp);
1415 			goto out;
1416 		}
1417 		error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
1418 		vput(nd.ni_dvp);
1419 		if (error) {
1420 			vrele(nd.ni_startdir);
1421 			goto out;
1422 		}
1423 		nd.ni_cnd.cn_nameiop = LOOKUP;
1424 		nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1425 		nd.ni_cnd.cn_proc = procp;
1426 		nd.ni_cnd.cn_cred = procp->p_ucred;
1427 		error = vfs_lookup(&nd);
1428 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1429 		if (error)
1430 			goto out;
1431 		if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1432 			vrele(nd.ni_dvp);
1433 			vput(nd.ni_vp);
1434 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1435 			error = EINVAL;
1436 		}
1437 	}
1438 out:
1439 	vp = nd.ni_vp;
1440 	if (!error) {
1441 		memset(fhp, 0, sizeof(nfh));
1442 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1443 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
1444 		if (!error)
1445 			error = VOP_GETATTR(vp, &va, cred, procp);
1446 		vput(vp);
1447 	}
1448 	diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1449 	vrele(dirp);
1450 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
1451 	    NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1)) != 0)
1452 		return 0;
1453 	if (!error) {
1454 		nfsm_srvpostop_fh(&info, fhp);
1455 		nfsm_srvpostop_attr(nfsd, 0, &va, &info);
1456 	}
1457 	nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft, &info);
1458 	return (0);
1459 nfsmout:
1460 	if (dirp)
1461 		vrele(dirp);
1462 	if (nd.ni_cnd.cn_nameiop) {
1463 		vrele(nd.ni_startdir);
1464 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1465 	}
1466 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1467 	if (nd.ni_dvp == nd.ni_vp)
1468 		vrele(nd.ni_dvp);
1469 	else
1470 		vput(nd.ni_dvp);
1471 	if (nd.ni_vp)
1472 		vput(nd.ni_vp);
1473 	return (error);
1474 }
1475 
1476 /*
1477  * nfs remove service
1478  */
1479 int
1480 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1481     struct proc *procp, struct mbuf **mrq)
1482 {
1483 	struct mbuf *nam = nfsd->nd_nam;
1484 	struct ucred *cred = &nfsd->nd_cr;
1485 	struct nameidata nd;
1486 	struct nfsm_info	info;
1487 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
1488 	struct vnode *vp, *dirp;
1489 	struct vattr dirfor, diraft;
1490 	nfsfh_t nfh;
1491 	fhandle_t *fhp;
1492 
1493 	info.nmi_mreq = NULL;
1494 	info.nmi_mrep = nfsd->nd_mrep;
1495 	info.nmi_md = nfsd->nd_md;
1496 	info.nmi_dpos = nfsd->nd_dpos;
1497 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1498 	info.nmi_errorp = &error;
1499 
1500 	vp = NULL;
1501 
1502 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1503 		return 0;
1504 	else if (error != 0)
1505 		goto nfsmout;
1506 	fhp = &nfh.fh_generic;
1507 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1508 		goto nfsmout;
1509 	if (nfsm_srvnamesiz(&info, &len) != 0)
1510 		goto nfsmout;
1511 	if (error) {
1512 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1513 			return 0;
1514 	}
1515 
1516  	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, NULL, procp);
1517 	nd.ni_cnd.cn_cred = cred;
1518 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md, &info.nmi_dpos, &dirp, procp);
1519 	if (dirp) {
1520 		if (info.nmi_v3)
1521 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1522 		else {
1523 			vrele(dirp);
1524 			dirp = NULL;
1525 		}
1526 	}
1527 
1528 	if (!error) {
1529 		vp = nd.ni_vp;
1530 		if (vp->v_type == VDIR &&
1531 		    (error = suser_ucred(cred)) != 0)
1532 			goto out;
1533 		/*
1534 		 * The root of a mounted filesystem cannot be deleted.
1535 		 */
1536 		if (vp->v_flag & VROOT) {
1537 			error = EBUSY;
1538 			goto out;
1539 		}
1540 		if (vp->v_flag & VTEXT)
1541 			uvm_vnp_uncache(vp);
1542 out:
1543 		if (!error) {
1544 			error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1545 		} else {
1546 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1547 			if (nd.ni_dvp == vp)
1548 				vrele(nd.ni_dvp);
1549 			else
1550 				vput(nd.ni_dvp);
1551 			vput(vp);
1552 		}
1553 	}
1554 	if (dirp && info.nmi_v3) {
1555 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1556 		vrele(dirp);
1557 	}
1558 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
1559 	    NFSX_WCCDATA(info.nmi_v3)) != 0)
1560 		return 0;
1561 	if (info.nmi_v3) {
1562 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1563 		    &info);
1564 		return (0);
1565 	}
1566 
1567 nfsmout:
1568 	return(error);
1569 }
1570 
1571 /*
1572  * nfs rename service
1573  */
1574 int
1575 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1576     struct proc *procp, struct mbuf **mrq)
1577 {
1578 	struct mbuf *nam = nfsd->nd_nam;
1579 	struct ucred *cred = &nfsd->nd_cr;
1580 	struct nfsm_info	info;
1581 	int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
1582 	int tdirfor_ret = 1, tdiraft_ret = 1;
1583 	struct nameidata fromnd, tond;
1584 	struct vnode *fvp = NULL, *tvp, *tdvp, *fdirp = NULL;
1585 	struct vnode *tdirp = NULL;
1586 	struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1587 	nfsfh_t fnfh, tnfh;
1588 	fhandle_t *ffhp, *tfhp;
1589 	uid_t saved_uid;
1590 
1591 	info.nmi_mreq = NULL;
1592 	info.nmi_mrep = nfsd->nd_mrep;
1593 	info.nmi_md = nfsd->nd_md;
1594 	info.nmi_dpos = nfsd->nd_dpos;
1595 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1596 	info.nmi_errorp = &error;
1597 
1598 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1599 		return 0;
1600 	else if (error != 0)
1601 		return error;
1602 	ffhp = &fnfh.fh_generic;
1603 	if (nfsm_srvmtofh2(&info, ffhp) != 0)
1604 		return error;
1605 	if (nfsm_srvnamesiz(&info, &len) != 0)
1606 		return error;
1607 	if (error) {
1608 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1609 			return 0;
1610 	}
1611 
1612 	/*
1613 	 * Remember our original uid so that we can reset cr_uid before
1614 	 * the second nfs_namei() call, in case it is remapped.
1615 	 */
1616 	saved_uid = cred->cr_uid;
1617 
1618 	NDINIT(&fromnd, DELETE, WANTPARENT | SAVESTART, UIO_SYSSPACE, NULL,
1619 	    procp);
1620 	fromnd.ni_cnd.cn_cred = cred;
1621 	error = nfs_namei(&fromnd, ffhp, len, slp, nam, &info.nmi_md,
1622 	    &info.nmi_dpos, &fdirp, procp);
1623 	if (fdirp) {
1624 		if (info.nmi_v3)
1625 			fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
1626 				procp);
1627 		else {
1628 			vrele(fdirp);
1629 			fdirp = NULL;
1630 		}
1631 	}
1632 	if (error) {
1633 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
1634 		    2 * NFSX_WCCDATA(info.nmi_v3)) != 0)
1635 			return 0;
1636 		nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft,
1637 		    &info);
1638 		nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft,
1639 		    &info);
1640 		if (fdirp)
1641 			vrele(fdirp);
1642 		return (0);
1643 	}
1644 
1645 	fvp = fromnd.ni_vp;
1646 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1647 		return 0;
1648 	else if (error != 0)
1649 		goto nfsmout;
1650 	tfhp = &tnfh.fh_generic;
1651 	if (nfsm_srvmtofh2(&info, tfhp) != 0)
1652 		goto nfsmout;
1653 	if (nfsm_strsiz(&info, &len2, NFS_MAXNAMLEN) != 0)
1654 		goto nfsmout;
1655 	cred->cr_uid = saved_uid;
1656 
1657 	NDINIT(&tond, RENAME, LOCKPARENT | LOCKLEAF| NOCACHE | SAVESTART,
1658 	    UIO_SYSSPACE, NULL, procp);
1659 	tond.ni_cnd.cn_cred = cred;
1660 	error = nfs_namei(&tond, tfhp, len2, slp, nam, &info.nmi_md,
1661 	    &info.nmi_dpos, &tdirp, procp);
1662 	if (tdirp) {
1663 		if (info.nmi_v3)
1664 			tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
1665 				procp);
1666 		else {
1667 			vrele(tdirp);
1668 			tdirp = NULL;
1669 		}
1670 	}
1671 	if (error) {
1672 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1673 		vrele(fromnd.ni_dvp);
1674 		vrele(fvp);
1675 		goto out1;
1676 	}
1677 	tdvp = tond.ni_dvp;
1678 	tvp = tond.ni_vp;
1679 	if (tvp != NULL) {
1680 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1681 			error = info.nmi_v3 ? EEXIST : EISDIR;
1682 			goto out;
1683 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1684 			error = info.nmi_v3 ? EEXIST : ENOTDIR;
1685 			goto out;
1686 		}
1687 		if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1688 			error = info.nmi_v3 ? EXDEV : ENOTEMPTY;
1689 			goto out;
1690 		}
1691 	}
1692 	if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1693 		error = info.nmi_v3 ? EXDEV : ENOTEMPTY;
1694 		goto out;
1695 	}
1696 	if (fvp->v_mount != tdvp->v_mount) {
1697 		error = info.nmi_v3 ? EXDEV : ENOTEMPTY;
1698 		goto out;
1699 	}
1700 	if (fvp == tdvp)
1701 		error = info.nmi_v3 ? EINVAL : ENOTEMPTY;
1702 	/*
1703 	 * If source is the same as the destination (that is the
1704 	 * same vnode with the same name in the same directory),
1705 	 * then there is nothing to do.
1706 	 */
1707 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
1708 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
1709 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
1710 	      fromnd.ni_cnd.cn_namelen))
1711 		error = -1;
1712 out:
1713 	if (!error) {
1714 		if (tvp) {
1715 			(void)uvm_vnp_uncache(tvp);
1716 		}
1717 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
1718 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
1719 	} else {
1720 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
1721 		if (tdvp == tvp)
1722 			vrele(tdvp);
1723 		else
1724 			vput(tdvp);
1725 		if (tvp)
1726 			vput(tvp);
1727 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1728 		vrele(fromnd.ni_dvp);
1729 		vrele(fvp);
1730 		if (error == -1)
1731 			error = 0;
1732 	}
1733 	vrele(tond.ni_startdir);
1734 	pool_put(&namei_pool, tond.ni_cnd.cn_pnbuf);
1735 out1:
1736 	if (fdirp) {
1737 		fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
1738 		vrele(fdirp);
1739 	}
1740 	if (tdirp) {
1741 		tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
1742 		vrele(tdirp);
1743 	}
1744 	vrele(fromnd.ni_startdir);
1745 	pool_put(&namei_pool, fromnd.ni_cnd.cn_pnbuf);
1746 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
1747 	    2 * NFSX_WCCDATA(info.nmi_v3)) != 0)
1748 		return 0;
1749 	if (info.nmi_v3) {
1750 		nfsm_srvwcc(nfsd, fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft,
1751 		    &info);
1752 		nfsm_srvwcc(nfsd, tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft,
1753 		    &info);
1754 	}
1755 	return (0);
1756 
1757 nfsmout:
1758 	if (fdirp)
1759 		vrele(fdirp);
1760 	if (fromnd.ni_cnd.cn_nameiop) {
1761 		if (fromnd.ni_startdir)
1762 			vrele(fromnd.ni_startdir);
1763 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
1764 
1765 		/*
1766 		 * XXX: Workaround the fact that fromnd.ni_dvp can point
1767 		 * to the same vnode as fdirp.
1768 		 */
1769 		if (fromnd.ni_dvp != NULL && fromnd.ni_dvp != fdirp)
1770 			vrele(fromnd.ni_dvp);
1771 		if (fvp)
1772 			vrele(fvp);
1773 	}
1774 	return (error);
1775 }
1776 
1777 /*
1778  * nfs link service
1779  */
1780 int
1781 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1782     struct proc *procp, struct mbuf **mrq)
1783 {
1784 	struct mbuf *nam = nfsd->nd_nam;
1785 	struct nfsm_info	info;
1786 	struct ucred *cred = &nfsd->nd_cr;
1787 	struct nameidata nd;
1788 	int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1;
1789 	int getret = 1;
1790 	struct vnode *vp, *xp, *dirp = NULL;
1791 	struct vattr dirfor, diraft, at;
1792 	nfsfh_t nfh, dnfh;
1793 	fhandle_t *fhp, *dfhp;
1794 
1795 	info.nmi_mreq = NULL;
1796 	info.nmi_mrep = nfsd->nd_mrep;
1797 	info.nmi_md = nfsd->nd_md;
1798 	info.nmi_dpos = nfsd->nd_dpos;
1799 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1800 	info.nmi_errorp = &error;
1801 
1802 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1803 		return 0;
1804 	else if (error != 0)
1805 		goto nfsmout;
1806 	fhp = &nfh.fh_generic;
1807 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1808 		goto nfsmout;
1809 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1810 		return 0;
1811 	else if (error != 0)
1812 		goto nfsmout;
1813 	dfhp = &dnfh.fh_generic;
1814 	if (nfsm_srvmtofh2(&info, dfhp) != 0)
1815 		goto nfsmout;
1816 	if (nfsm_srvnamesiz(&info, &len) != 0)
1817 		goto nfsmout;
1818 	if (error) {
1819 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1820 			return 0;
1821 	}
1822 
1823 	error = nfsrv_fhtovp(fhp, 0, &vp, cred, slp, nam, &rdonly);
1824 	if (error) {
1825 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
1826 		    NFSX_POSTOPATTR(info.nmi_v3) +
1827 		    NFSX_WCCDATA(info.nmi_v3)) != 0)
1828 			return 0;
1829 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
1830 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1831 		    &info);
1832 		error = 0;
1833 		goto nfsmout;
1834 	}
1835 	if (vp->v_type == VDIR)
1836 		goto out1;
1837 
1838 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, NULL, procp);
1839 	nd.ni_cnd.cn_cred = cred;
1840 	error = nfs_namei(&nd, dfhp, len, slp, nam, &info.nmi_md,
1841 	    &info.nmi_dpos, &dirp, procp);
1842 	if (dirp) {
1843 		if (info.nmi_v3)
1844 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1845 				procp);
1846 		else {
1847 			vrele(dirp);
1848 			dirp = NULL;
1849 		}
1850 	}
1851 	if (error)
1852 		goto out1;
1853 	xp = nd.ni_vp;
1854 	if (xp != NULL) {
1855 		error = EEXIST;
1856 		goto out;
1857 	}
1858 	xp = nd.ni_dvp;
1859 	if (vp->v_mount != xp->v_mount)
1860 		error = EXDEV;
1861 out:
1862 	if (!error) {
1863 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1864 	} else {
1865 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1866 		if (nd.ni_dvp == nd.ni_vp)
1867 			vrele(nd.ni_dvp);
1868 		else
1869 			vput(nd.ni_dvp);
1870 		if (nd.ni_vp)
1871 			vrele(nd.ni_vp);
1872 	}
1873 out1:
1874 	if (info.nmi_v3)
1875 		getret = VOP_GETATTR(vp, &at, cred, procp);
1876 	if (dirp) {
1877 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1878 		vrele(dirp);
1879 	}
1880 	vrele(vp);
1881 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
1882 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0)
1883 		return 0;
1884 	if (info.nmi_v3) {
1885 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
1886 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
1887 		     &info);
1888 		error = 0;
1889 	}
1890 nfsmout:
1891 	return(error);
1892 }
1893 
1894 /*
1895  * nfs symbolic link service
1896  */
1897 int
1898 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1899     struct proc *procp, struct mbuf **mrq)
1900 {
1901 	struct mbuf *nam = nfsd->nd_nam;
1902 	struct ucred *cred = &nfsd->nd_cr;
1903 	struct vattr va, dirfor, diraft;
1904 	struct nameidata nd;
1905 	struct nfsm_info	info;
1906 	struct nfsv2_sattr *sp;
1907 	char *pathcp = NULL;
1908 	struct uio io;
1909 	struct iovec iv;
1910 	int error = 0, len, pathlen, len2, dirfor_ret = 1, diraft_ret = 1;
1911 	struct vnode *dirp = NULL;
1912 	nfsfh_t nfh;
1913 	fhandle_t *fhp;
1914 
1915 	info.nmi_mreq = NULL;
1916 	info.nmi_mrep = nfsd->nd_mrep;
1917 	info.nmi_md = nfsd->nd_md;
1918 	info.nmi_dpos = nfsd->nd_dpos;
1919 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
1920 	info.nmi_errorp = &error;
1921 
1922 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
1923 		return 0;
1924 	else if (error != 0)
1925 		return error;
1926 	fhp = &nfh.fh_generic;
1927 	if (nfsm_srvmtofh2(&info, fhp) != 0)
1928 		return error;
1929 	if (nfsm_srvnamesiz(&info, &len) != 0)
1930 		return error;
1931 	if (error) {
1932 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
1933 			return 0;
1934 	}
1935 
1936 	NDINIT(&nd, CREATE, LOCKPARENT | SAVESTART, UIO_SYSSPACE, NULL, procp);
1937 	nd.ni_cnd.cn_cred = cred;
1938 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md,
1939 	    &info.nmi_dpos, &dirp, procp);
1940 	if (dirp) {
1941 		if (info.nmi_v3)
1942 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1943 				procp);
1944 		else {
1945 			vrele(dirp);
1946 			dirp = NULL;
1947 		}
1948 	}
1949 	if (error)
1950 		goto out;
1951 	VATTR_NULL(&va);
1952 	if (info.nmi_v3) {
1953 		error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep,
1954 		    &info.nmi_dpos);
1955 		if (error)
1956 			goto nfsmout;
1957 	}
1958 	if (nfsm_strsiz(&info, &len2, NFS_MAXPATHLEN) != 0)
1959 		goto nfsmout;
1960 	pathlen = len2 + 1;
1961 	pathcp = malloc(pathlen, M_TEMP, M_WAITOK);
1962 	iv.iov_base = pathcp;
1963 	iv.iov_len = len2;
1964 	io.uio_resid = len2;
1965 	io.uio_offset = 0;
1966 	io.uio_iov = &iv;
1967 	io.uio_iovcnt = 1;
1968 	io.uio_segflg = UIO_SYSSPACE;
1969 	io.uio_rw = UIO_READ;
1970 	io.uio_procp = NULL;
1971 	if (nfsm_mtouio(&info, &io, len2) != 0)
1972 		goto nfsmout;
1973 	if (!info.nmi_v3) {
1974 		sp = (struct nfsv2_sattr *)nfsm_dissect(&info, NFSX_V2SATTR);
1975 		if (sp == NULL)
1976 			goto nfsmout;
1977 		va.va_mode = nfstov_mode(sp->sa_mode);
1978 	}
1979 	*(pathcp + len2) = '\0';
1980 	if (nd.ni_vp) {
1981 		vrele(nd.ni_startdir);
1982 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
1983 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1984 		if (nd.ni_dvp == nd.ni_vp)
1985 			vrele(nd.ni_dvp);
1986 		else
1987 			vput(nd.ni_dvp);
1988 		vrele(nd.ni_vp);
1989 		error = EEXIST;
1990 		goto out;
1991 	}
1992 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va, pathcp);
1993 	if (error)
1994 		vrele(nd.ni_startdir);
1995 	else {
1996 		if (info.nmi_v3) {
1997 			nd.ni_cnd.cn_nameiop = LOOKUP;
1998 			nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART |
1999 			    FOLLOW);
2000 			nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2001 			nd.ni_cnd.cn_proc = procp;
2002 			nd.ni_cnd.cn_cred = cred;
2003 			error = vfs_lookup(&nd);
2004 			if (!error) {
2005 				memset(fhp, 0, sizeof(nfh));
2006 				fhp->fh_fsid =
2007 				    nd.ni_vp->v_mount->mnt_stat.f_fsid;
2008 				error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2009 				if (!error)
2010 					error = VOP_GETATTR(nd.ni_vp, &va, cred,
2011 					    procp);
2012 				vput(nd.ni_vp);
2013 			}
2014 		} else
2015 			vrele(nd.ni_startdir);
2016 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
2017 	}
2018 out:
2019 	if (pathcp)
2020 		free(pathcp, M_TEMP, pathlen);
2021 	if (dirp) {
2022 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2023 		vrele(dirp);
2024 	}
2025 	if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) +
2026 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0)
2027 		return 0;
2028 	if (info.nmi_v3) {
2029 		if (!error) {
2030 			nfsm_srvpostop_fh(&info, fhp);
2031 			nfsm_srvpostop_attr(nfsd, 0, &va, &info);
2032 		}
2033 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2034 		    &info);
2035 	}
2036 	return (0);
2037 nfsmout:
2038 	if (nd.ni_cnd.cn_nameiop) {
2039 		vrele(nd.ni_startdir);
2040 		pool_put(&namei_pool, nd.ni_cnd.cn_pnbuf);
2041 	}
2042 	if (dirp)
2043 		vrele(dirp);
2044 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2045 	if (nd.ni_dvp == nd.ni_vp)
2046 		vrele(nd.ni_dvp);
2047 	else
2048 		vput(nd.ni_dvp);
2049 	if (nd.ni_vp)
2050 		vrele(nd.ni_vp);
2051 	if (pathcp)
2052 		free(pathcp, M_TEMP, pathlen);
2053 	return (error);
2054 }
2055 
2056 /*
2057  * nfs mkdir service
2058  */
2059 int
2060 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2061     struct proc *procp, struct mbuf **mrq)
2062 {
2063 	struct mbuf *nam = nfsd->nd_nam;
2064 	struct ucred *cred = &nfsd->nd_cr;
2065 	struct vattr va, dirfor, diraft;
2066 	struct nfs_fattr *fp;
2067 	struct nameidata nd;
2068 	struct nfsm_info	info;
2069 	u_int32_t *tl;
2070 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2071 	struct vnode *vp, *dirp = NULL;
2072 	nfsfh_t nfh;
2073 	fhandle_t *fhp;
2074 
2075 	info.nmi_mreq = NULL;
2076 	info.nmi_mrep = nfsd->nd_mrep;
2077 	info.nmi_md = nfsd->nd_md;
2078 	info.nmi_dpos = nfsd->nd_dpos;
2079 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2080 	info.nmi_errorp = &error;
2081 
2082 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2083 		return 0;
2084 	else if (error != 0)
2085 		return error;
2086 	fhp = &nfh.fh_generic;
2087 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2088 		return error;
2089 	if (nfsm_srvnamesiz(&info, &len) != 0)
2090 		return error;
2091 	if (error) {
2092 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
2093 			return 0;
2094 	}
2095 
2096 	NDINIT(&nd, CREATE, LOCKPARENT, UIO_SYSSPACE, NULL, procp);
2097 	nd.ni_cnd.cn_cred = cred;
2098 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md,
2099 	    &info.nmi_dpos, &dirp, procp);
2100 	if (dirp) {
2101 		if (info.nmi_v3)
2102 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
2103 		else {
2104 			vrele(dirp);
2105 			dirp = NULL;
2106 		}
2107 	}
2108 	if (error) {
2109 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2110 		    NFSX_WCCDATA(info.nmi_v3)) != 0)
2111 			return 0;
2112 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2113 		    &info);
2114 		if (dirp)
2115 			vrele(dirp);
2116 		return (0);
2117 	}
2118 
2119 	VATTR_NULL(&va);
2120 	if (info.nmi_v3) {
2121 		error = nfsm_srvsattr(&info.nmi_md, &va, info.nmi_mrep,
2122 		    &info.nmi_dpos);
2123 		if (error)
2124 			goto nfsmout;
2125 	} else {
2126 		tl = (uint32_t *)nfsm_dissect(&info, NFSX_UNSIGNED);
2127 		if (tl == NULL)
2128 			goto nfsmout;
2129 		va.va_mode = nfstov_mode(*tl++);
2130 	}
2131 	va.va_type = VDIR;
2132 	vp = nd.ni_vp;
2133 	if (vp != NULL) {
2134 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2135 		if (nd.ni_dvp == vp)
2136 			vrele(nd.ni_dvp);
2137 		else
2138 			vput(nd.ni_dvp);
2139 		vrele(vp);
2140 		error = EEXIST;
2141 		goto out;
2142 	}
2143 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, &va);
2144 	if (!error) {
2145 		vp = nd.ni_vp;
2146 		memset(fhp, 0, sizeof(nfh));
2147 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2148 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
2149 		if (!error)
2150 			error = VOP_GETATTR(vp, &va, cred, procp);
2151 		vput(vp);
2152 	}
2153 out:
2154 	if (dirp) {
2155 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2156 		vrele(dirp);
2157 	}
2158 	if (nfsm_reply(&info, nfsd, slp, mrq, error, NFSX_SRVFH(info.nmi_v3) +
2159 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_WCCDATA(info.nmi_v3)) != 0)
2160 		return 0;
2161 	if (info.nmi_v3) {
2162 		if (!error) {
2163 			nfsm_srvpostop_fh(&info, fhp);
2164 			nfsm_srvpostop_attr(nfsd, 0, &va, &info);
2165 		}
2166 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2167 		    &info);
2168 	} else {
2169 		nfsm_srvfhtom(&info.nmi_mb, fhp, info.nmi_v3);
2170 		fp = nfsm_build(&info.nmi_mb, NFSX_V2FATTR);
2171 		nfsm_srvfattr(nfsd, &va, fp);
2172 	}
2173 	return (0);
2174 nfsmout:
2175 	if (dirp)
2176 		vrele(dirp);
2177 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2178 	if (nd.ni_dvp == nd.ni_vp)
2179 		vrele(nd.ni_dvp);
2180 	else
2181 		vput(nd.ni_dvp);
2182 	if (nd.ni_vp)
2183 		vrele(nd.ni_vp);
2184 	return (error);
2185 }
2186 
2187 /*
2188  * nfs rmdir service
2189  */
2190 int
2191 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2192     struct proc *procp, struct mbuf **mrq)
2193 {
2194 	struct mbuf *nam = nfsd->nd_nam;
2195 	struct ucred *cred = &nfsd->nd_cr;
2196 	struct nfsm_info	info;
2197 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2198 	struct vnode *vp, *dirp = NULL;
2199 	struct vattr dirfor, diraft;
2200 	nfsfh_t nfh;
2201 	fhandle_t *fhp;
2202 	struct nameidata nd;
2203 
2204 	info.nmi_mreq = NULL;
2205 	info.nmi_mrep = nfsd->nd_mrep;
2206 	info.nmi_md = nfsd->nd_md;
2207 	info.nmi_dpos = nfsd->nd_dpos;
2208 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2209 	info.nmi_errorp = &error;
2210 
2211 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2212 		return 0;
2213 	else if (error != 0)
2214 		goto nfsmout;
2215 	fhp = &nfh.fh_generic;
2216 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2217 		goto nfsmout;
2218 	if (nfsm_srvnamesiz(&info, &len) != 0)
2219 		goto nfsmout;
2220 	if (error) {
2221 		if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
2222 			return 0;
2223 	}
2224 
2225 	NDINIT(&nd, DELETE, LOCKPARENT | LOCKLEAF, UIO_SYSSPACE, NULL, procp);
2226 	nd.ni_cnd.cn_cred = cred;
2227 	error = nfs_namei(&nd, fhp, len, slp, nam, &info.nmi_md,
2228 	    &info.nmi_dpos, &dirp, procp);
2229 	if (dirp) {
2230 		if (info.nmi_v3)
2231 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2232 				procp);
2233 		else {
2234 			vrele(dirp);
2235 			dirp = NULL;
2236 		}
2237 	}
2238 	if (error) {
2239 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2240 		    NFSX_WCCDATA(info.nmi_v3)) != 0)
2241 			return 0;
2242 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2243 		    &info);
2244 		if (dirp)
2245 			vrele(dirp);
2246 		return (0);
2247 	}
2248 	vp = nd.ni_vp;
2249 	if (vp->v_type != VDIR) {
2250 		error = ENOTDIR;
2251 		goto out;
2252 	}
2253 	/*
2254 	 * No rmdir "." please.
2255 	 */
2256 	if (nd.ni_dvp == vp) {
2257 		error = EINVAL;
2258 		goto out;
2259 	}
2260 	/*
2261 	 * A mounted on directory cannot be deleted.
2262 	 */
2263 	if (vp->v_mountedhere != NULL) {
2264 		error = EBUSY;
2265 		goto out;
2266 	}
2267 	/*
2268 	 * The root of a mounted filesystem cannot be deleted.
2269 	 */
2270 	if (vp->v_flag & VROOT)
2271 		error = EBUSY;
2272 out:
2273 	if (!error) {
2274 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
2275 	} else {
2276 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
2277 		if (nd.ni_dvp == nd.ni_vp)
2278 			vrele(nd.ni_dvp);
2279 		else
2280 			vput(nd.ni_dvp);
2281 		vput(vp);
2282 	}
2283 	if (dirp) {
2284 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2285 		vrele(dirp);
2286 	}
2287 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
2288 	    NFSX_WCCDATA(info.nmi_v3)) != 0)
2289 		return 0;
2290 	if (info.nmi_v3) {
2291 		nfsm_srvwcc(nfsd, dirfor_ret, &dirfor, diraft_ret, &diraft,
2292 		    &info);
2293 		error = 0;
2294 	}
2295 nfsmout:
2296 	return(error);
2297 }
2298 
2299 /*
2300  * nfs readdir service
2301  * - mallocs what it thinks is enough to read
2302  *	count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2303  * - calls VOP_READDIR()
2304  * - loops around building the reply
2305  *	if the output generated exceeds count break out of loop
2306  * - it only knows that it has encountered eof when the VOP_READDIR()
2307  *	reads nothing
2308  * - as such one readdir rpc will return eof false although you are there
2309  *	and then the next will return eof
2310  * - it trims out records with d_fileno == 0
2311  *	this doesn't matter for Unix clients, but they might confuse clients
2312  *	for other os'.
2313  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2314  *	than requested, but this may not apply to all filesystems. For
2315  *	example, client NFS does not { although it is never remote mounted
2316  *	anyhow }
2317  *     The alternate call nfsrv_readdirplus() does lookups as well.
2318  * PS: The NFS protocol spec. does not clarify what the "count" byte
2319  *	argument is a count of.. just name strings and file id's or the
2320  *	entire reply rpc or ...
2321  *	I tried just file name and id sizes and it confused the Sun client,
2322  *	so I am using the full rpc size now. The "paranoia.." comment refers
2323  *	to including the status longwords that are not a part of the dir.
2324  *	"entry" structures, but are in the rpc.
2325  */
2326 struct flrep {
2327 	nfsuint64 fl_off;
2328 	u_int32_t fl_postopok;
2329 	u_int32_t fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
2330 	u_int32_t fl_fhok;
2331 	u_int32_t fl_fhsize;
2332 	u_int32_t fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
2333 };
2334 
2335 int
2336 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2337     struct proc *procp, struct mbuf **mrq)
2338 {
2339 	struct mbuf *nam = nfsd->nd_nam;
2340 	struct ucred *cred = &nfsd->nd_cr;
2341 	struct dirent *dp;
2342 	struct nfsm_info	info;
2343 	u_int32_t *tl;
2344 	char *cpos, *cend, *rbuf;
2345 	struct vnode *vp;
2346 	struct vattr at;
2347 	nfsfh_t nfh;
2348 	fhandle_t *fhp;
2349 	struct uio io;
2350 	struct iovec iv;
2351 	int len, nlen, pad, xfer, error = 0, getret = 1;
2352 	int siz, cnt, fullsiz, eofflag, rdonly;
2353 	u_quad_t off, toff, verf;
2354 
2355 	info.nmi_mreq = NULL;
2356 	info.nmi_mrep = nfsd->nd_mrep;
2357 	info.nmi_md = nfsd->nd_md;
2358 	info.nmi_dpos = nfsd->nd_dpos;
2359 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2360 	info.nmi_errorp = &error;
2361 
2362 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2363 		return 0;
2364 	else if (error != 0)
2365 		goto nfsmout;
2366 	fhp = &nfh.fh_generic;
2367 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2368 		goto nfsmout;
2369 	if (info.nmi_v3) {
2370 		tl = (uint32_t *)nfsm_dissect(&info, 5 * NFSX_UNSIGNED);
2371 		if (tl == NULL)
2372 			goto nfsmout;
2373 		toff = fxdr_hyper(tl);
2374 		tl += 2;
2375 		verf = fxdr_hyper(tl);
2376 		tl += 2;
2377 	} else {
2378 		tl = (uint32_t *)nfsm_dissect(&info, 2 * NFSX_UNSIGNED);
2379 		if (tl == NULL)
2380 			goto nfsmout;
2381 		toff = fxdr_unsigned(u_quad_t, *tl++);
2382 	}
2383 	off = toff;
2384 	cnt = fxdr_unsigned(int, *tl);
2385 	xfer = NFS_SRVMAXDATA(nfsd);
2386 	if (cnt > xfer || cnt < 0)
2387 		cnt = xfer;
2388 	siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2389 	if (siz > xfer)
2390 		siz = xfer;
2391 	fullsiz = siz;
2392 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
2393 	if (error) {
2394 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2395 		    NFSX_UNSIGNED) != 0)
2396 			return 0;
2397 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2398 		error = 0;
2399 		goto nfsmout;
2400 	}
2401 	if (info.nmi_v3)
2402 		error = getret = VOP_GETATTR(vp, &at, cred, procp);
2403 	if (!error)
2404 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0);
2405 	if (error) {
2406 		vput(vp);
2407 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2408 		    NFSX_POSTOPATTR(info.nmi_v3)) != 0)
2409 			return 0;
2410 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2411 		error = 0;
2412 		goto nfsmout;
2413 	}
2414 	VOP_UNLOCK(vp);
2415 	rbuf = malloc(fullsiz, M_TEMP, M_WAITOK);
2416 again:
2417 	iv.iov_base = rbuf;
2418 	iv.iov_len = fullsiz;
2419 	io.uio_iov = &iv;
2420 	io.uio_iovcnt = 1;
2421 	io.uio_offset = (off_t)off;
2422 	io.uio_resid = fullsiz;
2423 	io.uio_segflg = UIO_SYSSPACE;
2424 	io.uio_rw = UIO_READ;
2425 	io.uio_procp = NULL;
2426 	eofflag = 0;
2427 
2428 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2429 	error = VOP_READDIR(vp, &io, cred, &eofflag);
2430 
2431 	off = (off_t)io.uio_offset;
2432 	if (info.nmi_v3) {
2433 		getret = VOP_GETATTR(vp, &at, cred, procp);
2434 		if (!error)
2435 			error = getret;
2436 	}
2437 
2438 	VOP_UNLOCK(vp);
2439 	if (error) {
2440 		vrele(vp);
2441 		free(rbuf, M_TEMP, fullsiz);
2442 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2443 		    NFSX_POSTOPATTR(info.nmi_v3)) != 0)
2444 			return 0;
2445 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2446 		error = 0;
2447 		goto nfsmout;
2448 	}
2449 	if (io.uio_resid) {
2450 		siz -= io.uio_resid;
2451 
2452 		/*
2453 		 * If nothing read, return eof
2454 		 * rpc reply
2455 		 */
2456 		if (siz == 0) {
2457 			vrele(vp);
2458 			if (nfsm_reply(&info, nfsd, slp, mrq, error,
2459 			    NFSX_POSTOPATTR(info.nmi_v3) +
2460 			    NFSX_COOKIEVERF(info.nmi_v3) +
2461 			    2 * NFSX_UNSIGNED) != 0)
2462 				return 0;
2463 			if (info.nmi_v3) {
2464 				nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2465 				tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED);
2466 				txdr_hyper(at.va_filerev, tl);
2467 				tl += 2;
2468 			} else
2469 				tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2470 			*tl++ = nfs_false;
2471 			*tl = nfs_true;
2472 			free(rbuf, M_TEMP, fullsiz);
2473 			error = 0;
2474 			goto nfsmout;
2475 		}
2476 	}
2477 
2478 	/*
2479 	 * Check for degenerate cases of nothing useful read.
2480 	 * If so go try again
2481 	 */
2482 	cpos = rbuf;
2483 	cend = rbuf + siz;
2484 	dp = (struct dirent *)cpos;
2485 
2486 	while (cpos < cend && dp->d_fileno == 0) {
2487 		cpos += dp->d_reclen;
2488 		dp = (struct dirent *)cpos;
2489 	}
2490 	if (cpos >= cend) {
2491 		toff = off;
2492 		siz = fullsiz;
2493 		goto again;
2494 	}
2495 
2496 	len = 3 * NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
2497 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
2498 	    NFSX_POSTOPATTR(info.nmi_v3) +
2499 	    NFSX_COOKIEVERF(info.nmi_v3) + siz) != 0)
2500 		return 0;
2501 	if (info.nmi_v3) {
2502 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2503 		tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2504 		txdr_hyper(at.va_filerev, tl);
2505 	}
2506 
2507 	/* Loop through the records and build reply */
2508 	while (cpos < cend) {
2509 		if (dp->d_fileno != 0) {
2510 			nlen = dp->d_namlen;
2511 			pad = nfsm_padlen(nlen);
2512 			len += (4 * NFSX_UNSIGNED + nlen + pad);
2513 			if (info.nmi_v3)
2514 				len += 2 * NFSX_UNSIGNED;
2515 			if (len > cnt) {
2516 				eofflag = 0;
2517 				break;
2518 			}
2519 			/*
2520 			 * Build the directory record xdr from
2521 			 * the dirent entry.
2522 			 */
2523 			tl = nfsm_build(&info.nmi_mb,
2524 			    (info.nmi_v3 ? 3 : 2) * NFSX_UNSIGNED);
2525 			*tl++ = nfs_true;
2526 			if (info.nmi_v3)
2527 				txdr_hyper(dp->d_fileno, tl);
2528 			else
2529 				*tl = txdr_unsigned((u_int32_t)dp->d_fileno);
2530 
2531 			/* And copy the name */
2532 			nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen);
2533 
2534 			/* Finish off the record */
2535 			if (info.nmi_v3) {
2536 				tl = nfsm_build(&info.nmi_mb, 2*NFSX_UNSIGNED);
2537 				txdr_hyper(dp->d_off, tl);
2538 			} else {
2539 				tl = nfsm_build(&info.nmi_mb, NFSX_UNSIGNED);
2540 				*tl = txdr_unsigned((u_int32_t)dp->d_off);
2541 			}
2542 		}
2543 		cpos += dp->d_reclen;
2544 		dp = (struct dirent *)cpos;
2545 	}
2546 	vrele(vp);
2547 	tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2548 	*tl++ = nfs_false;
2549 	if (eofflag)
2550 		*tl = nfs_true;
2551 	else
2552 		*tl = nfs_false;
2553 	free(rbuf, M_TEMP, fullsiz);
2554 nfsmout:
2555 	return(error);
2556 }
2557 
2558 int
2559 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2560     struct proc *procp, struct mbuf **mrq)
2561 {
2562 	struct mbuf *nam = nfsd->nd_nam;
2563 	struct ucred *cred = &nfsd->nd_cr;
2564 	struct dirent *dp;
2565 	struct nfsm_info	info;
2566 	u_int32_t *tl;
2567 	char *cpos, *cend, *rbuf;
2568 	struct vnode *vp, *nvp;
2569 	struct flrep fl;
2570 	nfsfh_t nfh;
2571 	fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
2572 	struct uio io;
2573 	struct iovec iv;
2574 	struct vattr va, at, *vap = &va;
2575 	struct nfs_fattr *fp;
2576 	int len, nlen, pad, xfer, error = 0, getret = 1;
2577 	int siz, cnt, fullsiz, eofflag, rdonly, dirlen;
2578 	u_quad_t off, toff, verf;
2579 
2580 	info.nmi_mreq = NULL;
2581 	info.nmi_mrep = nfsd->nd_mrep;
2582 	info.nmi_md = nfsd->nd_md;
2583 	info.nmi_dpos = nfsd->nd_dpos;
2584 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2585 	info.nmi_errorp = &error;
2586 
2587 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2588 		return 0;
2589 	else if (error != 0)
2590 		goto nfsmout;
2591 	fhp = &nfh.fh_generic;
2592 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2593 		goto nfsmout;
2594 	tl = (uint32_t *)nfsm_dissect(&info, 6 * NFSX_UNSIGNED);
2595 	if (tl == NULL)
2596 		goto nfsmout;
2597 	off = toff = fxdr_hyper(tl);
2598 	tl += 2;
2599 	verf = fxdr_hyper(tl);
2600 	tl += 2;
2601 	siz = fxdr_unsigned(int, *tl++);
2602 	cnt = fxdr_unsigned(int, *tl);
2603 	xfer = NFS_SRVMAXDATA(nfsd);
2604 	if (cnt > xfer || cnt < 0)
2605 		cnt = xfer;
2606 	siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2607 	if (siz > xfer)
2608 		siz = xfer;
2609 	fullsiz = siz;
2610 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
2611 	if (error) {
2612 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2613 		    NFSX_UNSIGNED) != 0)
2614 			return 0;
2615 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2616 		error = 0;
2617 		goto nfsmout;
2618 	}
2619 	error = getret = VOP_GETATTR(vp, &at, cred, procp);
2620 	if (!error)
2621 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp, 0);
2622 	if (error) {
2623 		vput(vp);
2624 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2625 		    NFSX_V3POSTOPATTR) != 0)
2626 			return 0;
2627 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2628 		error = 0;
2629 		goto nfsmout;
2630 	}
2631 	VOP_UNLOCK(vp);
2632 
2633 	rbuf = malloc(fullsiz, M_TEMP, M_WAITOK);
2634 again:
2635 	iv.iov_base = rbuf;
2636 	iv.iov_len = fullsiz;
2637 	io.uio_iov = &iv;
2638 	io.uio_iovcnt = 1;
2639 	io.uio_offset = (off_t)off;
2640 	io.uio_resid = fullsiz;
2641 	io.uio_segflg = UIO_SYSSPACE;
2642 	io.uio_rw = UIO_READ;
2643 	io.uio_procp = NULL;
2644 	eofflag = 0;
2645 
2646 	vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
2647 	error = VOP_READDIR(vp, &io, cred, &eofflag);
2648 
2649 	off = (u_quad_t)io.uio_offset;
2650 	getret = VOP_GETATTR(vp, &at, cred, procp);
2651 
2652 	VOP_UNLOCK(vp);
2653 
2654 	if (!error)
2655 		error = getret;
2656 	if (error) {
2657 		vrele(vp);
2658 		free(rbuf, M_TEMP, fullsiz);
2659 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2660 		    NFSX_V3POSTOPATTR) != 0)
2661 			return 0;
2662 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2663 		error = 0;
2664 		goto nfsmout;
2665 	}
2666 	if (io.uio_resid) {
2667 		siz -= io.uio_resid;
2668 
2669 		/*
2670 		 * If nothing read, return eof
2671 		 * rpc reply
2672 		 */
2673 		if (siz == 0) {
2674 			vrele(vp);
2675 			if (nfsm_reply(&info, nfsd, slp, mrq, error,
2676 			    NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2677 			    2 * NFSX_UNSIGNED) != 0)
2678 				return 0;
2679 			nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2680 			tl = nfsm_build(&info.nmi_mb, 4 * NFSX_UNSIGNED);
2681 			txdr_hyper(at.va_filerev, tl);
2682 			tl += 2;
2683 			*tl++ = nfs_false;
2684 			*tl = nfs_true;
2685 			free(rbuf, M_TEMP, fullsiz);
2686 			error = 0;
2687 			goto nfsmout;
2688 		}
2689 	}
2690 
2691 	/*
2692 	 * Check for degenerate cases of nothing useful read.
2693 	 * If so go try again
2694 	 */
2695 	cpos = rbuf;
2696 	cend = rbuf + siz;
2697 	dp = (struct dirent *)cpos;
2698 
2699 	while (cpos < cend && dp->d_fileno == 0) {
2700 		cpos += dp->d_reclen;
2701 		dp = (struct dirent *)cpos;
2702 	}
2703 	if (cpos >= cend) {
2704 		toff = off;
2705 		siz = fullsiz;
2706 		goto again;
2707 	}
2708 
2709 	/*
2710 	 * struct READDIRPLUS3resok {
2711 	 *     postop_attr dir_attributes;
2712 	 *     cookieverf3 cookieverf;
2713 	 *     dirlistplus3 reply;
2714 	 * }
2715 	 *
2716 	 * struct dirlistplus3 {
2717 	 *     entryplus3  *entries;
2718 	 *     bool eof;
2719 	 *  }
2720 	 */
2721 	dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
2722 	if (nfsm_reply(&info, nfsd, slp, mrq, error, cnt) != 0)
2723 		return 0;
2724 	nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2725 	tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2726 	txdr_hyper(at.va_filerev, tl);
2727 
2728 	/* Loop through the records and build reply */
2729 	while (cpos < cend) {
2730 		if (dp->d_fileno != 0) {
2731 			nlen = dp->d_namlen;
2732 			pad = nfsm_padlen(nlen);
2733 
2734 			/*
2735 			 * For readdir_and_lookup get the vnode using
2736 			 * the file number.
2737 			 */
2738 			if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
2739 				goto invalid;
2740 			memset(nfhp, 0, NFSX_V3FH);
2741 			nfhp->fh_fsid =
2742 				nvp->v_mount->mnt_stat.f_fsid;
2743 			if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
2744 				vput(nvp);
2745 				goto invalid;
2746 			}
2747 			if (VOP_GETATTR(nvp, vap, cred, procp)) {
2748 				vput(nvp);
2749 				goto invalid;
2750 			}
2751 			vput(nvp);
2752 
2753 			/*
2754 			 * If either the dircount or maxcount will be
2755 			 * exceeded, get out now. Both of these lengths
2756 			 * are calculated conservatively, including all
2757 			 * XDR overheads.
2758 			 *
2759 			 * Each entry:
2760 			 * 2 * NFSX_UNSIGNED for fileid3
2761 			 * 1 * NFSX_UNSIGNED for length of name
2762 			 * nlen + pad == space the name takes up
2763 			 * 2 * NFSX_UNSIGNED for the cookie
2764 			 * 1 * NFSX_UNSIGNED to indicate if file handle present
2765 			 * 1 * NFSX_UNSIGNED for the file handle length
2766 			 * NFSX_V3FH == space our file handle takes up
2767 			 * NFSX_V3POSTOPATTR == space the attributes take up
2768 			 * 1 * NFSX_UNSIGNED for next pointer
2769 			 */
2770 			len += (8 * NFSX_UNSIGNED + nlen + pad + NFSX_V3FH +
2771 				NFSX_V3POSTOPATTR);
2772 			dirlen += (6 * NFSX_UNSIGNED + nlen + pad);
2773 			if (len > cnt || dirlen > fullsiz) {
2774 				eofflag = 0;
2775 				break;
2776 			}
2777 
2778 			tl = nfsm_build(&info.nmi_mb, 3 * NFSX_UNSIGNED);
2779 			*tl++ = nfs_true;
2780 			txdr_hyper(dp->d_fileno, tl);
2781 
2782 			/* And copy the name */
2783 			nfsm_strtombuf(&info.nmi_mb, dp->d_name, nlen);
2784 
2785 			/*
2786 			 * Build the directory record xdr from
2787 			 * the dirent entry.
2788 			 */
2789 			fp = (struct nfs_fattr *)&fl.fl_fattr;
2790 			nfsm_srvfattr(nfsd, vap, fp);
2791 			fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
2792 			fl.fl_fhok = nfs_true;
2793 			fl.fl_postopok = nfs_true;
2794 			txdr_hyper(dp->d_off, fl.fl_off.nfsuquad);
2795 
2796 			/* Now copy the flrep structure out. */
2797 			nfsm_buftombuf(&info.nmi_mb, &fl, sizeof(struct flrep));
2798 		}
2799 invalid:
2800 		cpos += dp->d_reclen;
2801 		dp = (struct dirent *)cpos;
2802 	}
2803 	vrele(vp);
2804 	tl = nfsm_build(&info.nmi_mb, 2 * NFSX_UNSIGNED);
2805 	*tl++ = nfs_false;
2806 	if (eofflag)
2807 		*tl = nfs_true;
2808 	else
2809 		*tl = nfs_false;
2810 	free(rbuf, M_TEMP, fullsiz);
2811 nfsmout:
2812 	return(error);
2813 }
2814 
2815 /*
2816  * nfs commit service
2817  */
2818 int
2819 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2820     struct proc *procp, struct mbuf **mrq)
2821 {
2822 	struct mbuf *nam = nfsd->nd_nam;
2823 	struct ucred *cred = &nfsd->nd_cr;
2824 	struct vattr bfor, aft;
2825 	struct vnode *vp;
2826 	struct nfsm_info	info;
2827 	struct timeval boottime;
2828 	nfsfh_t nfh;
2829 	fhandle_t *fhp;
2830 	u_int32_t *tl;
2831 	int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt;
2832 	u_quad_t off;
2833 
2834 	info.nmi_mreq = NULL;
2835 	info.nmi_mrep = nfsd->nd_mrep;
2836 	info.nmi_md = nfsd->nd_md;
2837 	info.nmi_dpos = nfsd->nd_dpos;
2838 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2839 	info.nmi_errorp = &error;
2840 
2841 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2842 		return 0;
2843 	else if (error != 0)
2844 		goto nfsmout;
2845 	fhp = &nfh.fh_generic;
2846 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2847 		goto nfsmout;
2848 	tl = (uint32_t *)nfsm_dissect(&info, 3 * NFSX_UNSIGNED);
2849 	if (tl == NULL)
2850 		goto nfsmout;
2851 
2852 	/*
2853 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
2854 	 * count parameters, so these arguments are useless (someday maybe).
2855 	 */
2856 	off = fxdr_hyper(tl);
2857 	tl += 2;
2858 	cnt = fxdr_unsigned(int, *tl);
2859 	if (cnt < 0)
2860 		cnt = 0;
2861 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
2862 	if (error) {
2863 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2864 		    2 * NFSX_UNSIGNED) != 0)
2865 			return 0;
2866 		nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info);
2867 		error = 0;
2868 		goto nfsmout;
2869 	}
2870 	for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
2871 	error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
2872 	aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
2873 	vput(vp);
2874 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
2875 	    NFSX_V3WCCDATA + NFSX_V3WRITEVERF) != 0)
2876 		return 0;
2877 	nfsm_srvwcc(nfsd, for_ret, &bfor, aft_ret, &aft, &info);
2878 	if (!error) {
2879 		tl = nfsm_build(&info.nmi_mb, NFSX_V3WRITEVERF);
2880 		microboottime(&boottime);
2881 		*tl++ = txdr_unsigned(boottime.tv_sec);
2882 		*tl = txdr_unsigned(boottime.tv_usec);
2883 	} else
2884 		error = 0;
2885 nfsmout:
2886 	return(error);
2887 }
2888 
2889 /*
2890  * nfs statfs service
2891  */
2892 int
2893 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2894     struct proc *procp, struct mbuf **mrq)
2895 {
2896 	struct mbuf *nam = nfsd->nd_nam;
2897 	struct ucred *cred = &nfsd->nd_cr;
2898 	struct statfs *sf;
2899 	struct nfs_statfs *sfp;
2900 	struct nfsm_info	info;
2901 	int error = 0, rdonly, getret = 1;
2902 	struct vnode *vp;
2903 	struct vattr at;
2904 	nfsfh_t nfh;
2905 	fhandle_t *fhp;
2906 	struct statfs statfs;
2907 	u_quad_t tval;
2908 
2909 	info.nmi_mreq = NULL;
2910 	info.nmi_mrep = nfsd->nd_mrep;
2911 	info.nmi_md = nfsd->nd_md;
2912 	info.nmi_dpos = nfsd->nd_dpos;
2913 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2914 	info.nmi_errorp = &error;
2915 
2916 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2917 		return 0;
2918 	else if (error != 0)
2919 		goto nfsmout;
2920 	fhp = &nfh.fh_generic;
2921 	if (nfsm_srvmtofh2(&info, fhp) != 0)
2922 		goto nfsmout;
2923 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
2924 	if (error) {
2925 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
2926 		    NFSX_UNSIGNED) != 0)
2927 			return 0;
2928 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2929 		error = 0;
2930 		goto nfsmout;
2931 	}
2932 	sf = &statfs;
2933 	error = VFS_STATFS(vp->v_mount, sf, procp);
2934 	getret = VOP_GETATTR(vp, &at, cred, procp);
2935 	vput(vp);
2936 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
2937 	    NFSX_POSTOPATTR(info.nmi_v3) + NFSX_STATFS(info.nmi_v3)) != 0)
2938 		return 0;
2939 	if (info.nmi_v3)
2940 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
2941 	if (error) {
2942 		error = 0;
2943 		goto nfsmout;
2944 	}
2945 	sfp = nfsm_build(&info.nmi_mb, NFSX_STATFS(info.nmi_v3));
2946 	if (info.nmi_v3) {
2947 		tval = (u_quad_t)sf->f_blocks;
2948 		tval *= (u_quad_t)sf->f_bsize;
2949 		txdr_hyper(tval, &sfp->sf_tbytes);
2950 		tval = (u_quad_t)sf->f_bfree;
2951 		tval *= (u_quad_t)sf->f_bsize;
2952 		txdr_hyper(tval, &sfp->sf_fbytes);
2953 		tval = (u_quad_t)sf->f_bavail;
2954 		tval *= (u_quad_t)sf->f_bsize;
2955 		txdr_hyper(tval, &sfp->sf_abytes);
2956 		tval = (u_quad_t)sf->f_files;
2957 		txdr_hyper(tval, &sfp->sf_tfiles);
2958 		tval = (u_quad_t)sf->f_ffree;
2959 		txdr_hyper(tval, &sfp->sf_ffiles);
2960 		txdr_hyper(tval, &sfp->sf_afiles);
2961 		sfp->sf_invarsec = 0;
2962 	} else {
2963 		sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
2964 		sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
2965 		sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
2966 		sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
2967 		sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
2968 	}
2969 nfsmout:
2970 	return(error);
2971 }
2972 
2973 /*
2974  * nfs fsinfo service
2975  */
2976 int
2977 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2978     struct proc *procp, struct mbuf **mrq)
2979 {
2980 	struct mbuf *nam = nfsd->nd_nam;
2981 	struct ucred *cred = &nfsd->nd_cr;
2982 	struct nfsm_info	info;
2983 	struct nfsv3_fsinfo *sip;
2984 	int error = 0, rdonly, getret = 1, pref;
2985 	struct vnode *vp;
2986 	struct vattr at;
2987 	nfsfh_t nfh;
2988 	fhandle_t *fhp;
2989 
2990 	info.nmi_mreq = NULL;
2991 	info.nmi_mrep = nfsd->nd_mrep;
2992 	info.nmi_md = nfsd->nd_md;
2993 	info.nmi_dpos = nfsd->nd_dpos;
2994 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
2995 	info.nmi_errorp = &error;
2996 
2997 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
2998 		return 0;
2999 	else if (error != 0)
3000 		goto nfsmout;
3001 	fhp = &nfh.fh_generic;
3002 	if (nfsm_srvmtofh2(&info, fhp) != 0)
3003 		goto nfsmout;
3004 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
3005 	if (error) {
3006 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
3007 		    NFSX_UNSIGNED) != 0)
3008 			return 0;
3009 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
3010 		error = 0;
3011 		goto nfsmout;
3012 	}
3013 	getret = VOP_GETATTR(vp, &at, cred, procp);
3014 	vput(vp);
3015 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
3016 	    NFSX_V3POSTOPATTR + NFSX_V3FSINFO) != 0)
3017 		return 0;
3018 	nfsm_srvpostop_attr(nfsd, getret, &at, &info);
3019 	sip = nfsm_build(&info.nmi_mb, NFSX_V3FSINFO);
3020 
3021 	/*
3022 	 * XXX
3023 	 * There should be file system VFS OP(s) to get this information.
3024 	 * For now, assume ufs.
3025 	 */
3026 	if (slp->ns_so->so_type == SOCK_DGRAM)
3027 		pref = NFS_MAXDGRAMDATA;
3028 	else
3029 		pref = NFS_MAXDATA;
3030 	sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3031 	sip->fs_rtpref = txdr_unsigned(pref);
3032 	sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3033 	sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3034 	sip->fs_wtpref = txdr_unsigned(pref);
3035 	sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3036 	sip->fs_dtpref = txdr_unsigned(pref);
3037 	sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
3038 	sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
3039 	sip->fs_timedelta.nfsv3_sec = 0;
3040 	sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3041 	sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3042 		NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3043 		NFSV3FSINFO_CANSETTIME);
3044 nfsmout:
3045 	return(error);
3046 }
3047 
3048 /*
3049  * nfs pathconf service
3050  */
3051 int
3052 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3053     struct proc *procp, struct mbuf **mrq)
3054 {
3055 	struct mbuf *nam = nfsd->nd_nam;
3056 	struct ucred *cred = &nfsd->nd_cr;
3057 	struct nfsm_info	info;
3058 	struct nfsv3_pathconf *pc;
3059 	int error = 0, rdonly, getret = 1;
3060 	register_t linkmax, namemax, chownres, notrunc;
3061 	struct vnode *vp;
3062 	struct vattr at;
3063 	nfsfh_t nfh;
3064 	fhandle_t *fhp;
3065 
3066 	info.nmi_mreq = NULL;
3067 	info.nmi_mrep = nfsd->nd_mrep;
3068 	info.nmi_md = nfsd->nd_md;
3069 	info.nmi_dpos = nfsd->nd_dpos;
3070 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
3071 	info.nmi_errorp = &error;
3072 
3073 	if (nfsm_srvmtofh1(&info, nfsd, slp, mrq) != 0)
3074 		return 0;
3075 	else if (error != 0)
3076 		goto nfsmout;
3077 	fhp = &nfh.fh_generic;
3078 	if (nfsm_srvmtofh2(&info, fhp) != 0)
3079 		goto nfsmout;
3080 	error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam, &rdonly);
3081 	if (error) {
3082 		if (nfsm_reply(&info, nfsd, slp, mrq, error,
3083 		    NFSX_UNSIGNED) != 0)
3084 			return 0;
3085 		nfsm_srvpostop_attr(nfsd, getret, &at, &info);
3086 		error = 0;
3087 		goto nfsmout;
3088 	}
3089 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3090 	if (!error)
3091 		error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3092 	if (!error)
3093 		error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3094 	if (!error)
3095 		error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
3096 	getret = VOP_GETATTR(vp, &at, cred, procp);
3097 	vput(vp);
3098 	if (nfsm_reply(&info, nfsd, slp, mrq, error,
3099 	    NFSX_V3POSTOPATTR + NFSX_V3PATHCONF) != 0)
3100 		return 0;
3101 	nfsm_srvpostop_attr(nfsd, getret, &at, &info);
3102 	if (error) {
3103 		error = 0;
3104 		goto nfsmout;
3105 	}
3106 	pc = nfsm_build(&info.nmi_mb, NFSX_V3PATHCONF);
3107 
3108 	pc->pc_linkmax = txdr_unsigned(linkmax);
3109 	pc->pc_namemax = txdr_unsigned(namemax);
3110 	pc->pc_notrunc = txdr_unsigned(notrunc);
3111 	pc->pc_chownrestricted = txdr_unsigned(chownres);
3112 
3113 	/*
3114 	 * These should probably be supported by VOP_PATHCONF(), but
3115 	 * until msdosfs is exportable (why would you want to?), the
3116 	 * Unix defaults should be ok.
3117 	 */
3118 	pc->pc_caseinsensitive = nfs_false;
3119 	pc->pc_casepreserving = nfs_true;
3120 nfsmout:
3121 	return(error);
3122 }
3123 
3124 /*
3125  * Null operation, used by clients to ping server
3126  */
3127 int
3128 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3129     struct proc *procp, struct mbuf **mrq)
3130 {
3131 	struct nfsm_info	info;
3132 	int error = NFSERR_RETVOID;
3133 
3134 	info.nmi_mreq = NULL;
3135 	info.nmi_mrep = nfsd->nd_mrep;
3136 	info.nmi_md = nfsd->nd_md;
3137 	info.nmi_dpos = nfsd->nd_dpos;
3138 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
3139 	info.nmi_errorp = &error;
3140 
3141 	if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
3142 		return 0;
3143 	return (0);
3144 }
3145 
3146 /*
3147  * No operation, used for obsolete procedures
3148  */
3149 int
3150 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3151     struct proc *procp, struct mbuf **mrq)
3152 {
3153 	struct nfsm_info	info;
3154 	int error;
3155 
3156 	info.nmi_mreq = NULL;
3157 	info.nmi_mrep = nfsd->nd_mrep;
3158 	info.nmi_md = nfsd->nd_md;
3159 	info.nmi_dpos = nfsd->nd_dpos;
3160 	info.nmi_v3 = (nfsd->nd_flag & ND_NFSV3);
3161 	info.nmi_errorp = &error;
3162 
3163 	if (nfsd->nd_repstat)
3164 		error = nfsd->nd_repstat;
3165 	else
3166 		error = EPROCUNAVAIL;
3167 	if (nfsm_reply(&info, nfsd, slp, mrq, error, 0) != 0)
3168 		return 0;
3169 	return (0);
3170 }
3171 
3172 /*
3173  * Perform access checking for vnodes obtained from file handles that would
3174  * refer to files already opened by a Unix client.
3175  * You cannot just use vn_writechk() and VOP_ACCESS() for two reasons:
3176  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the
3177  *     write case
3178  * 2 - The owner is to be given access irrespective of mode bits for some
3179  *     operations, so that processes that chmod after opening a file don't
3180  *     break. I don't like this because it opens a security hole, but since
3181  *     the nfs server opens a security hole the size of a barn door anyhow,
3182  *     what the heck. A notable exception to this rule is when VOP_ACCESS()
3183  *     returns EPERM (e.g. when a file is immutable) which is always an
3184  *     error.
3185  */
3186 int
3187 nfsrv_access(struct vnode *vp, int flags, struct ucred *cred, int rdonly,
3188     struct proc *p, int override)
3189 {
3190 	struct vattr vattr;
3191 	int error;
3192 
3193 	if (flags & VWRITE) {
3194 		/* Just vn_writechk() changed to check rdonly */
3195 		/*
3196 		 * Disallow write attempts on read-only file systems;
3197 		 * unless the file is a socket or a block or character
3198 		 * device resident on the file system.
3199 		 */
3200 		if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
3201 			switch (vp->v_type) {
3202 			case VREG:
3203 			case VDIR:
3204 			case VLNK:
3205 				return (EROFS);
3206 			default:
3207 				break;
3208 			}
3209 		}
3210 		/*
3211 		 * If there's shared text associated with
3212 		 * the inode, try to free it up once.  If
3213 		 * we fail, we can't allow writing.
3214 		 */
3215 		if ((vp->v_flag & VTEXT) && !uvm_vnp_uncache(vp))
3216 			return (ETXTBSY);
3217 	}
3218 	error = VOP_ACCESS(vp, flags, cred, p);
3219 	/*
3220 	 * Allow certain operations for the owner (reads and writes
3221 	 * on files that are already open).
3222 	 */
3223 	if (override && error == EACCES &&
3224 	    VOP_GETATTR(vp, &vattr, cred, p) == 0 &&
3225 	    cred->cr_uid == vattr.va_uid)
3226 		error = 0;
3227 	return error;
3228 }
3229