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