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