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