xref: /original-bsd/sys/nfs/nfs_serv.c (revision 6afd9275)
1 /*
2  * Copyright (c) 1989 The Regents of the University of California.
3  * All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Rick Macklem at The University of Guelph.
7  *
8  * %sccs.include.redist.c%
9  *
10  *	@(#)nfs_serv.c	7.62 (Berkeley) 11/12/92
11  */
12 
13 /*
14  * nfs version 2 server calls to vnode ops
15  * - these routines generally have 3 phases
16  *   1 - break down and validate rpc request in mbuf list
17  *   2 - do the vnode ops for the request
18  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
19  *   3 - build the rpc reply in an mbuf list
20  *   nb:
21  *	- do not mix the phases, since the nfsm_?? macros can return failures
22  *	  on a bad rpc or similar and do not do any vrele() or vput()'s
23  *
24  *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
25  *	error number iff error != 0 whereas
26  *	returning an error from the server function implies a fatal error
27  *	such as a badly constructed rpc request that should be dropped without
28  *	a reply.
29  */
30 
31 #include <sys/param.h>
32 #include <sys/systm.h>
33 #include <sys/proc.h>
34 #include <sys/file.h>
35 #include <sys/namei.h>
36 #include <sys/vnode.h>
37 #include <sys/mount.h>
38 #include <sys/mbuf.h>
39 #include <sys/dirent.h>
40 #include <sys/stat.h>
41 
42 #include <vm/vm.h>
43 
44 #include <nfs/nfsv2.h>
45 #include <nfs/rpcv2.h>
46 #include <nfs/nfs.h>
47 #include <nfs/xdr_subs.h>
48 #include <nfs/nfsm_subs.h>
49 #include <nfs/nqnfs.h>
50 
51 /* Defs */
52 #define	TRUE	1
53 #define	FALSE	0
54 
55 /* Global vars */
56 extern u_long nfs_procids[NFS_NPROCS];
57 extern u_long nfs_xdrneg1;
58 extern u_long nfs_false, nfs_true;
59 nfstype nfs_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
60 		      NFCHR, NFNON };
61 
62 /*
63  * nqnfs access service
64  */
65 nqnfsrv_access(nfsd, mrep, md, dpos, cred, nam, mrq)
66 	struct nfsd *nfsd;
67 	struct mbuf *mrep, *md;
68 	caddr_t dpos;
69 	struct ucred *cred;
70 	struct mbuf *nam, **mrq;
71 {
72 	struct vnode *vp;
73 	nfsv2fh_t nfh;
74 	fhandle_t *fhp;
75 	register u_long *tl;
76 	register long t1;
77 	caddr_t bpos;
78 	int error = 0, rdonly, cache, mode = 0;
79 	char *cp2;
80 	struct mbuf *mb, *mb2, *mreq;
81 	u_quad_t frev;
82 
83 	fhp = &nfh.fh_generic;
84 	nfsm_srvmtofh(fhp);
85 	nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
86 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
87 		nfsm_reply(0);
88 	if (*tl++ == nfs_true)
89 		mode |= VREAD;
90 	if (*tl++ == nfs_true)
91 		mode |= VWRITE;
92 	if (*tl == nfs_true)
93 		mode |= VEXEC;
94 	error = nfsrv_access(vp, mode, cred, rdonly, nfsd->nd_procp);
95 	vput(vp);
96 	nfsm_reply(0);
97 	nfsm_srvdone;
98 }
99 
100 /*
101  * nfs getattr service
102  */
103 nfsrv_getattr(nfsd, mrep, md, dpos, cred, nam, mrq)
104 	struct nfsd *nfsd;
105 	struct mbuf *mrep, *md;
106 	caddr_t dpos;
107 	struct ucred *cred;
108 	struct mbuf *nam, **mrq;
109 {
110 	register struct nfsv2_fattr *fp;
111 	struct vattr va;
112 	register struct vattr *vap = &va;
113 	struct vnode *vp;
114 	nfsv2fh_t nfh;
115 	fhandle_t *fhp;
116 	register u_long *tl;
117 	register long t1;
118 	caddr_t bpos;
119 	int error = 0, rdonly, cache;
120 	char *cp2;
121 	struct mbuf *mb, *mb2, *mreq;
122 	u_quad_t frev;
123 
124 	fhp = &nfh.fh_generic;
125 	nfsm_srvmtofh(fhp);
126 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
127 		nfsm_reply(0);
128 	nqsrv_getl(vp, NQL_READ);
129 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
130 	vput(vp);
131 	nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
132 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
133 	nfsm_srvfillattr;
134 	nfsm_srvdone;
135 }
136 
137 /*
138  * nfs setattr service
139  */
140 nfsrv_setattr(nfsd, mrep, md, dpos, cred, nam, mrq)
141 	struct nfsd *nfsd;
142 	struct mbuf *mrep, *md;
143 	caddr_t dpos;
144 	struct ucred *cred;
145 	struct mbuf *nam, **mrq;
146 {
147 	struct vattr va;
148 	register struct vattr *vap = &va;
149 	register struct nfsv2_sattr *sp;
150 	register struct nfsv2_fattr *fp;
151 	struct vnode *vp;
152 	nfsv2fh_t nfh;
153 	fhandle_t *fhp;
154 	register u_long *tl;
155 	register long t1;
156 	caddr_t bpos;
157 	int error = 0, rdonly, cache, duration2, cache2;
158 	char *cp2;
159 	struct mbuf *mb, *mb2, *mreq;
160 	u_quad_t frev, frev2;
161 
162 	fhp = &nfh.fh_generic;
163 	nfsm_srvmtofh(fhp);
164 	nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
165 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
166 		nfsm_reply(0);
167 	nqsrv_getl(vp, NQL_WRITE);
168 	if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp))
169 		goto out;
170 	VATTR_NULL(vap);
171 	/*
172 	 * Nah nah nah nah na nah
173 	 * There is a bug in the Sun client that puts 0xffff in the mode
174 	 * field of sattr when it should put in 0xffffffff. The u_short
175 	 * doesn't sign extend.
176 	 * --> check the low order 2 bytes for 0xffff
177 	 */
178 	if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
179 		vap->va_mode = nfstov_mode(sp->sa_mode);
180 	if (sp->sa_uid != nfs_xdrneg1)
181 		vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
182 	if (sp->sa_gid != nfs_xdrneg1)
183 		vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
184 	if (nfsd->nd_nqlflag == NQL_NOVAL) {
185 		if (sp->sa_nfssize != nfs_xdrneg1)
186 			vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_nfssize);
187 		/*
188 		 * The usec field of sa_atime is overloaded with the va_flags field
189 		 * for 4.4BSD clients. Hopefully other clients always set both the
190 		 * sec and usec fields to -1 when not setting the atime.
191 		 */
192 		if (sp->sa_nfsatime.nfs_sec != nfs_xdrneg1) {
193 			vap->va_atime.ts_sec = fxdr_unsigned(long, sp->sa_nfsatime.nfs_sec);
194 			vap->va_atime.ts_nsec = 0;
195 		}
196 		if (sp->sa_nfsatime.nfs_usec != nfs_xdrneg1)
197 			vap->va_flags = fxdr_unsigned(u_long, sp->sa_nfsatime.nfs_usec);
198 		if (sp->sa_nfsmtime.nfs_sec != nfs_xdrneg1)
199 			fxdr_nfstime(&sp->sa_nfsmtime, &vap->va_mtime);
200 	} else {
201 		fxdr_hyper(&sp->sa_nqsize, &vap->va_size);
202 		fxdr_nqtime(&sp->sa_nqatime, &vap->va_atime);
203 		fxdr_nqtime(&sp->sa_nqmtime, &vap->va_mtime);
204 		vap->va_flags = fxdr_unsigned(u_long, sp->sa_nqflags);
205 	}
206 	if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
207 		vput(vp);
208 		nfsm_reply(0);
209 	}
210 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
211 out:
212 	vput(vp);
213 	nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 2*NFSX_UNSIGNED);
214 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
215 	nfsm_srvfillattr;
216 	if (nfsd->nd_nqlflag != NQL_NOVAL) {
217 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
218 		txdr_hyper(&frev2, tl);
219 	}
220 	nfsm_srvdone;
221 }
222 
223 /*
224  * nfs lookup rpc
225  */
226 nfsrv_lookup(nfsd, mrep, md, dpos, cred, nam, mrq)
227 	struct nfsd *nfsd;
228 	struct mbuf *mrep, *md;
229 	caddr_t dpos;
230 	struct ucred *cred;
231 	struct mbuf *nam, **mrq;
232 {
233 	register struct nfsv2_fattr *fp;
234 	struct nameidata nd;
235 	struct vnode *vp;
236 	nfsv2fh_t nfh;
237 	fhandle_t *fhp;
238 	register caddr_t cp;
239 	register u_long *tl;
240 	register long t1;
241 	caddr_t bpos;
242 	int error = 0, rdonly, cache, duration2, cache2, len;
243 	char *cp2;
244 	struct mbuf *mb, *mb2, *mreq;
245 	struct vattr va, *vap = &va;
246 	u_quad_t frev, frev2;
247 
248 	fhp = &nfh.fh_generic;
249 	duration2 = 0;
250 	if (nfsd->nd_nqlflag != NQL_NOVAL) {
251 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
252 		duration2 = fxdr_unsigned(int, *tl);
253 	}
254 	nfsm_srvmtofh(fhp);
255 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
256 	nd.ni_cnd.cn_cred = cred;
257 	nd.ni_cnd.cn_nameiop = LOOKUP;
258 	nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
259 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
260 	    nfsd->nd_procp))
261 		nfsm_reply(0);
262 	nqsrv_getl(nd.ni_startdir, NQL_READ);
263 	vrele(nd.ni_startdir);
264 	FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
265 	vp = nd.ni_vp;
266 	bzero((caddr_t)fhp, sizeof(nfh));
267 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
268 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
269 		vput(vp);
270 		nfsm_reply(0);
271 	}
272 	if (duration2)
273 		(void) nqsrv_getlease(vp, &duration2, NQL_READ, nfsd,
274 			nam, &cache2, &frev2, cred);
275 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
276 	vput(vp);
277 	nfsm_reply(NFSX_FH + NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL) + 5*NFSX_UNSIGNED);
278 	if (nfsd->nd_nqlflag != NQL_NOVAL) {
279 		if (duration2) {
280 			nfsm_build(tl, u_long *, 5*NFSX_UNSIGNED);
281 			*tl++ = txdr_unsigned(NQL_READ);
282 			*tl++ = txdr_unsigned(cache2);
283 			*tl++ = txdr_unsigned(duration2);
284 			txdr_hyper(&frev2, tl);
285 		} else {
286 			nfsm_build(tl, u_long *, NFSX_UNSIGNED);
287 			*tl = 0;
288 		}
289 	}
290 	nfsm_srvfhtom(fhp);
291 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
292 	nfsm_srvfillattr;
293 	nfsm_srvdone;
294 }
295 
296 /*
297  * nfs readlink service
298  */
299 nfsrv_readlink(nfsd, mrep, md, dpos, cred, nam, mrq)
300 	struct nfsd *nfsd;
301 	struct mbuf *mrep, *md;
302 	caddr_t dpos;
303 	struct ucred *cred;
304 	struct mbuf *nam, **mrq;
305 {
306 	struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
307 	register struct iovec *ivp = iv;
308 	register struct mbuf *mp;
309 	register u_long *tl;
310 	register long t1;
311 	caddr_t bpos;
312 	int error = 0, rdonly, cache, i, tlen, len;
313 	char *cp2;
314 	struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
315 	struct vnode *vp;
316 	nfsv2fh_t nfh;
317 	fhandle_t *fhp;
318 	struct uio io, *uiop = &io;
319 	u_quad_t frev;
320 
321 	fhp = &nfh.fh_generic;
322 	nfsm_srvmtofh(fhp);
323 	len = 0;
324 	i = 0;
325 	while (len < NFS_MAXPATHLEN) {
326 		MGET(mp, M_WAIT, MT_DATA);
327 		MCLGET(mp, M_WAIT);
328 		mp->m_len = NFSMSIZ(mp);
329 		if (len == 0)
330 			mp3 = mp2 = mp;
331 		else {
332 			mp2->m_next = mp;
333 			mp2 = mp;
334 		}
335 		if ((len+mp->m_len) > NFS_MAXPATHLEN) {
336 			mp->m_len = NFS_MAXPATHLEN-len;
337 			len = NFS_MAXPATHLEN;
338 		} else
339 			len += mp->m_len;
340 		ivp->iov_base = mtod(mp, caddr_t);
341 		ivp->iov_len = mp->m_len;
342 		i++;
343 		ivp++;
344 	}
345 	uiop->uio_iov = iv;
346 	uiop->uio_iovcnt = i;
347 	uiop->uio_offset = 0;
348 	uiop->uio_resid = len;
349 	uiop->uio_rw = UIO_READ;
350 	uiop->uio_segflg = UIO_SYSSPACE;
351 	uiop->uio_procp = (struct proc *)0;
352 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly)) {
353 		m_freem(mp3);
354 		nfsm_reply(0);
355 	}
356 	if (vp->v_type != VLNK) {
357 		error = EINVAL;
358 		goto out;
359 	}
360 	nqsrv_getl(vp, NQL_READ);
361 	error = VOP_READLINK(vp, uiop, cred);
362 out:
363 	vput(vp);
364 	if (error)
365 		m_freem(mp3);
366 	nfsm_reply(NFSX_UNSIGNED);
367 	if (uiop->uio_resid > 0) {
368 		len -= uiop->uio_resid;
369 		tlen = nfsm_rndup(len);
370 		nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
371 	}
372 	nfsm_build(tl, u_long *, NFSX_UNSIGNED);
373 	*tl = txdr_unsigned(len);
374 	mb->m_next = mp3;
375 	nfsm_srvdone;
376 }
377 
378 /*
379  * nfs read service
380  */
381 nfsrv_read(nfsd, mrep, md, dpos, cred, nam, mrq)
382 	struct nfsd *nfsd;
383 	struct mbuf *mrep, *md;
384 	caddr_t dpos;
385 	struct ucred *cred;
386 	struct mbuf *nam, **mrq;
387 {
388 	register struct iovec *iv;
389 	struct iovec *iv2;
390 	register struct mbuf *m;
391 	register struct nfsv2_fattr *fp;
392 	register u_long *tl;
393 	register long t1;
394 	caddr_t bpos;
395 	int error = 0, rdonly, cache, i, cnt, len, left, siz, tlen;
396 	char *cp2;
397 	struct mbuf *mb, *mb2, *mreq;
398 	struct mbuf *m2;
399 	struct vnode *vp;
400 	nfsv2fh_t nfh;
401 	fhandle_t *fhp;
402 	struct uio io, *uiop = &io;
403 	struct vattr va, *vap = &va;
404 	off_t off;
405 	u_quad_t frev;
406 
407 	fhp = &nfh.fh_generic;
408 	nfsm_srvmtofh(fhp);
409 	if (nfsd->nd_nqlflag == NQL_NOVAL) {
410 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
411 		off = (off_t)fxdr_unsigned(u_long, *tl);
412 	} else {
413 		nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
414 		fxdr_hyper(tl, &off);
415 	}
416 	nfsm_srvstrsiz(cnt, NFS_MAXDATA);
417 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
418 		nfsm_reply(0);
419 	nqsrv_getl(vp, NQL_READ);
420 	if ((error = nfsrv_access(vp, VREAD, cred, rdonly, nfsd->nd_procp)) &&
421 	    (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp))) {
422 		vput(vp);
423 		nfsm_reply(0);
424 	}
425 	if (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp)) {
426 		vput(vp);
427 		nfsm_reply(0);
428 	}
429 	if (off >= vap->va_size)
430 		cnt = 0;
431 	else if ((off + cnt) > vap->va_size)
432 		cnt = nfsm_rndup(vap->va_size - off);
433 	nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL)+NFSX_UNSIGNED+nfsm_rndup(cnt));
434 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
435 	nfsm_build(tl, u_long *, NFSX_UNSIGNED);
436 	len = left = cnt;
437 	if (cnt > 0) {
438 		/*
439 		 * Generate the mbuf list with the uio_iov ref. to it.
440 		 */
441 		i = 0;
442 		m = m2 = mb;
443 		MALLOC(iv, struct iovec *,
444 		       ((NFS_MAXDATA+MLEN-1)/MLEN) * sizeof (struct iovec),
445 		       M_TEMP, M_WAITOK);
446 		iv2 = iv;
447 		while (left > 0) {
448 			siz = min(M_TRAILINGSPACE(m), left);
449 			if (siz > 0) {
450 				m->m_len += siz;
451 				iv->iov_base = bpos;
452 				iv->iov_len = siz;
453 				iv++;
454 				i++;
455 				left -= siz;
456 			}
457 			if (left > 0) {
458 				MGET(m, M_WAIT, MT_DATA);
459 				MCLGET(m, M_WAIT);
460 				m->m_len = 0;
461 				m2->m_next = m;
462 				m2 = m;
463 				bpos = mtod(m, caddr_t);
464 			}
465 		}
466 		uiop->uio_iov = iv2;
467 		uiop->uio_iovcnt = i;
468 		uiop->uio_offset = off;
469 		uiop->uio_resid = cnt;
470 		uiop->uio_rw = UIO_READ;
471 		uiop->uio_segflg = UIO_SYSSPACE;
472 		error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
473 		off = uiop->uio_offset;
474 		FREE((caddr_t)iv2, M_TEMP);
475 		if (error || (error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp))) {
476 			m_freem(mreq);
477 			vput(vp);
478 			nfsm_reply(0);
479 		}
480 	} else
481 		uiop->uio_resid = 0;
482 	vput(vp);
483 	nfsm_srvfillattr;
484 	len -= uiop->uio_resid;
485 	tlen = nfsm_rndup(len);
486 	if (cnt != tlen || tlen != len)
487 		nfsm_adj(mb, cnt-tlen, tlen-len);
488 	*tl = txdr_unsigned(len);
489 	nfsm_srvdone;
490 }
491 
492 /*
493  * nfs write service
494  */
495 nfsrv_write(nfsd, mrep, md, dpos, cred, nam, mrq)
496 	struct nfsd *nfsd;
497 	struct mbuf *mrep, *md;
498 	caddr_t dpos;
499 	struct ucred *cred;
500 	struct mbuf *nam, **mrq;
501 {
502 	register struct iovec *ivp;
503 	register struct mbuf *mp;
504 	register struct nfsv2_fattr *fp;
505 	struct iovec iv[NFS_MAXIOVEC];
506 	struct vattr va;
507 	register struct vattr *vap = &va;
508 	register u_long *tl;
509 	register long t1;
510 	caddr_t bpos;
511 	int error = 0, rdonly, cache, siz, len, xfer;
512 	int ioflags = IO_SYNC | IO_NODELOCKED;
513 	char *cp2;
514 	struct mbuf *mb, *mb2, *mreq;
515 	struct vnode *vp;
516 	nfsv2fh_t nfh;
517 	fhandle_t *fhp;
518 	struct uio io, *uiop = &io;
519 	off_t off;
520 	u_quad_t frev;
521 
522 	fhp = &nfh.fh_generic;
523 	nfsm_srvmtofh(fhp);
524 	nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
525 	if (nfsd->nd_nqlflag == NQL_NOVAL) {
526 		off = (off_t)fxdr_unsigned(u_long, *++tl);
527 		tl += 2;
528 	} else {
529 		fxdr_hyper(tl, &off);
530 		tl += 2;
531 		if (fxdr_unsigned(u_long, *tl++))
532 			ioflags |= IO_APPEND;
533 	}
534 	len = fxdr_unsigned(long, *tl);
535 	if (len > NFS_MAXDATA || len <= 0) {
536 		error = EBADRPC;
537 		nfsm_reply(0);
538 	}
539 	if (dpos == (mtod(md, caddr_t)+md->m_len)) {
540 		mp = md->m_next;
541 		if (mp == NULL) {
542 			error = EBADRPC;
543 			nfsm_reply(0);
544 		}
545 	} else {
546 		mp = md;
547 		siz = dpos-mtod(mp, caddr_t);
548 		mp->m_len -= siz;
549 		NFSMADV(mp, siz);
550 	}
551 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
552 		nfsm_reply(0);
553 	nqsrv_getl(vp, NQL_WRITE);
554 	if (error = nfsrv_access(vp, VWRITE, cred, rdonly, nfsd->nd_procp)) {
555 		vput(vp);
556 		nfsm_reply(0);
557 	}
558 	uiop->uio_resid = 0;
559 	uiop->uio_rw = UIO_WRITE;
560 	uiop->uio_segflg = UIO_SYSSPACE;
561 	uiop->uio_procp = (struct proc *)0;
562 	/*
563 	 * Do up to NFS_MAXIOVEC mbufs of write each iteration of the
564 	 * loop until done.
565 	 */
566 	while (len > 0 && uiop->uio_resid == 0) {
567 		ivp = iv;
568 		siz = 0;
569 		uiop->uio_iov = ivp;
570 		uiop->uio_iovcnt = 0;
571 		uiop->uio_offset = off;
572 		while (len > 0 && uiop->uio_iovcnt < NFS_MAXIOVEC && mp != NULL) {
573 			ivp->iov_base = mtod(mp, caddr_t);
574 			if (len < mp->m_len)
575 				ivp->iov_len = xfer = len;
576 			else
577 				ivp->iov_len = xfer = mp->m_len;
578 #ifdef notdef
579 			/* Not Yet .. */
580 			if (M_HASCL(mp) && (((u_long)ivp->iov_base) & CLOFSET) == 0)
581 				ivp->iov_op = NULL;	/* what should it be ?? */
582 			else
583 				ivp->iov_op = NULL;
584 #endif
585 			uiop->uio_iovcnt++;
586 			ivp++;
587 			len -= xfer;
588 			siz += xfer;
589 			mp = mp->m_next;
590 		}
591 		if (len > 0 && mp == NULL) {
592 			error = EBADRPC;
593 			vput(vp);
594 			nfsm_reply(0);
595 		}
596 		uiop->uio_resid = siz;
597 		if (error = VOP_WRITE(vp, uiop, ioflags, cred)) {
598 			vput(vp);
599 			nfsm_reply(0);
600 		}
601 		off = uiop->uio_offset;
602 	}
603 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
604 	vput(vp);
605 	nfsm_reply(NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
606 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
607 	nfsm_srvfillattr;
608 	if (nfsd->nd_nqlflag != NQL_NOVAL) {
609 		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
610 		txdr_hyper(&vap->va_filerev, tl);
611 	}
612 	nfsm_srvdone;
613 }
614 
615 /*
616  * nfs create service
617  * now does a truncate to 0 length via. setattr if it already exists
618  */
619 nfsrv_create(nfsd, mrep, md, dpos, cred, nam, mrq)
620 	struct nfsd *nfsd;
621 	struct mbuf *mrep, *md;
622 	caddr_t dpos;
623 	struct ucred *cred;
624 	struct mbuf *nam, **mrq;
625 {
626 	register struct nfsv2_fattr *fp;
627 	struct vattr va;
628 	register struct vattr *vap = &va;
629 	register struct nfsv2_sattr *sp;
630 	register u_long *tl;
631 	struct nameidata nd;
632 	register caddr_t cp;
633 	register long t1;
634 	caddr_t bpos;
635 	int error = 0, rdev, cache, len, tsize;
636 	char *cp2;
637 	struct mbuf *mb, *mb2, *mreq;
638 	struct vnode *vp;
639 	nfsv2fh_t nfh;
640 	fhandle_t *fhp;
641 	u_quad_t frev;
642 
643 	nd.ni_cnd.cn_nameiop = 0;
644 	fhp = &nfh.fh_generic;
645 	nfsm_srvmtofh(fhp);
646 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
647 	nd.ni_cnd.cn_cred = cred;
648 	nd.ni_cnd.cn_nameiop = CREATE;
649 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
650 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
651 	    nfsd->nd_procp))
652 		nfsm_reply(0);
653 	VATTR_NULL(vap);
654 	nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
655 	/*
656 	 * Iff doesn't exist, create it
657 	 * otherwise just truncate to 0 length
658 	 *   should I set the mode too ??
659 	 */
660 	if (nd.ni_vp == NULL) {
661 		vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
662 		if (vap->va_type == VNON)
663 			vap->va_type = VREG;
664 		vap->va_mode = nfstov_mode(sp->sa_mode);
665 		if (nfsd->nd_nqlflag == NQL_NOVAL)
666 			rdev = fxdr_unsigned(long, sp->sa_nfssize);
667 		else
668 			rdev = fxdr_unsigned(long, sp->sa_nqrdev);
669 		if (vap->va_type == VREG || vap->va_type == VSOCK) {
670 			vrele(nd.ni_startdir);
671 			nqsrv_getl(nd.ni_dvp, NQL_WRITE);
672 			if (error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
673 				nfsm_reply(0);
674 			FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
675 		} else if (vap->va_type == VCHR || vap->va_type == VBLK ||
676 			vap->va_type == VFIFO) {
677 			if (vap->va_type == VCHR && rdev == 0xffffffff)
678 				vap->va_type = VFIFO;
679 			if (vap->va_type == VFIFO) {
680 #ifndef FIFO
681 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
682 				vput(nd.ni_dvp);
683 				error = ENXIO;
684 				goto out;
685 #endif /* FIFO */
686 			} else if (error = suser(cred, (u_short *)0)) {
687 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
688 				vput(nd.ni_dvp);
689 				goto out;
690 			} else
691 				vap->va_rdev = (dev_t)rdev;
692 			nqsrv_getl(nd.ni_dvp, NQL_WRITE);
693 			if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
694 				vrele(nd.ni_startdir);
695 				nfsm_reply(0);
696 			}
697 			nd.ni_cnd.cn_nameiop = LOOKUP;
698 			nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
699 			nd.ni_cnd.cn_proc = nfsd->nd_procp;
700 			nd.ni_cnd.cn_cred = nfsd->nd_procp->p_ucred;
701 			if (error = lookup(&nd)) {
702 				free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
703 				nfsm_reply(0);
704 			}
705 			FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
706 			if (nd.ni_cnd.cn_flags & ISSYMLINK) {
707 				vrele(nd.ni_dvp);
708 				vput(nd.ni_vp);
709 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
710 				error = EINVAL;
711 				nfsm_reply(0);
712 			}
713 		} else {
714 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
715 			vput(nd.ni_dvp);
716 			error = ENXIO;
717 			goto out;
718 		}
719 		vp = nd.ni_vp;
720 	} else {
721 		vrele(nd.ni_startdir);
722 		free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
723 		vp = nd.ni_vp;
724 		if (nd.ni_dvp == vp)
725 			vrele(nd.ni_dvp);
726 		else
727 			vput(nd.ni_dvp);
728 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
729 		if (nfsd->nd_nqlflag == NQL_NOVAL) {
730 			tsize = fxdr_unsigned(long, sp->sa_nfssize);
731 			if (tsize != -1)
732 				vap->va_size = (u_quad_t)tsize;
733 			else
734 				vap->va_size = -1;
735 		} else
736 			fxdr_hyper(&sp->sa_nqsize, &vap->va_size);
737 		if (vap->va_size != -1) {
738 			nqsrv_getl(vp, NQL_WRITE);
739 			if (error = VOP_SETATTR(vp, vap, cred, nfsd->nd_procp)) {
740 				vput(vp);
741 				nfsm_reply(0);
742 			}
743 		}
744 	}
745 	bzero((caddr_t)fhp, sizeof(nfh));
746 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
747 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
748 		vput(vp);
749 		nfsm_reply(0);
750 	}
751 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
752 	vput(vp);
753 	nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
754 	nfsm_srvfhtom(fhp);
755 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
756 	nfsm_srvfillattr;
757 	return (error);
758 nfsmout:
759 	if (nd.ni_cnd.cn_nameiop || nd.ni_cnd.cn_flags)
760 		vrele(nd.ni_startdir);
761 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
762 	if (nd.ni_dvp == nd.ni_vp)
763 		vrele(nd.ni_dvp);
764 	else
765 		vput(nd.ni_dvp);
766 	if (nd.ni_vp)
767 		vput(nd.ni_vp);
768 	return (error);
769 
770 out:
771 	vrele(nd.ni_startdir);
772 	free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
773 	nfsm_reply(0);
774 }
775 
776 /*
777  * nfs remove service
778  */
779 nfsrv_remove(nfsd, mrep, md, dpos, cred, nam, mrq)
780 	struct nfsd *nfsd;
781 	struct mbuf *mrep, *md;
782 	caddr_t dpos;
783 	struct ucred *cred;
784 	struct mbuf *nam, **mrq;
785 {
786 	struct nameidata nd;
787 	register u_long *tl;
788 	register long t1;
789 	caddr_t bpos;
790 	int error = 0, cache, len;
791 	char *cp2;
792 	struct mbuf *mb, *mreq;
793 	struct vnode *vp;
794 	nfsv2fh_t nfh;
795 	fhandle_t *fhp;
796 	u_quad_t frev;
797 
798 	fhp = &nfh.fh_generic;
799 	nfsm_srvmtofh(fhp);
800 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
801 	nd.ni_cnd.cn_cred = cred;
802 	nd.ni_cnd.cn_nameiop = DELETE;
803 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
804 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
805 	    nfsd->nd_procp))
806 		nfsm_reply(0);
807 	vp = nd.ni_vp;
808 	if (vp->v_type == VDIR &&
809 		(error = suser(cred, (u_short *)0)))
810 		goto out;
811 	/*
812 	 * The root of a mounted filesystem cannot be deleted.
813 	 */
814 	if (vp->v_flag & VROOT) {
815 		error = EBUSY;
816 		goto out;
817 	}
818 	if (vp->v_flag & VTEXT)
819 		(void) vnode_pager_uncache(vp);
820 out:
821 	if (!error) {
822 		nqsrv_getl(nd.ni_dvp, NQL_WRITE);
823 		nqsrv_getl(vp, NQL_WRITE);
824 		error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
825 	} else {
826 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
827 		if (nd.ni_dvp == vp)
828 			vrele(nd.ni_dvp);
829 		else
830 			vput(nd.ni_dvp);
831 		vput(vp);
832 	}
833 	nfsm_reply(0);
834 	nfsm_srvdone;
835 }
836 
837 /*
838  * nfs rename service
839  */
840 nfsrv_rename(nfsd, mrep, md, dpos, cred, nam, mrq)
841 	struct nfsd *nfsd;
842 	struct mbuf *mrep, *md;
843 	caddr_t dpos;
844 	struct ucred *cred;
845 	struct mbuf *nam, **mrq;
846 {
847 	register u_long *tl;
848 	register long t1;
849 	caddr_t bpos;
850 	int error = 0, rdonly, cache, len, len2;
851 	char *cp2;
852 	struct mbuf *mb, *mreq;
853 	struct nameidata fromnd, tond;
854 	struct vnode *fvp, *tvp, *tdvp;
855 	nfsv2fh_t fnfh, tnfh;
856 	fhandle_t *ffhp, *tfhp;
857 	u_quad_t frev;
858 	uid_t saved_uid;
859 
860 	ffhp = &fnfh.fh_generic;
861 	tfhp = &tnfh.fh_generic;
862 	fromnd.ni_cnd.cn_nameiop = 0;
863 	tond.ni_cnd.cn_nameiop = 0;
864 	nfsm_srvmtofh(ffhp);
865 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
866 	/*
867 	 * Remember our original uid so that we can reset cr_uid before
868 	 * the second nfs_namei() call, in case it is remapped.
869 	 */
870 	saved_uid = cred->cr_uid;
871 	fromnd.ni_cnd.cn_cred = cred;
872 	fromnd.ni_cnd.cn_nameiop = DELETE;
873 	fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
874 	if (error = nfs_namei(&fromnd, ffhp, len, nfsd->nd_slp, nam, &md,
875 	    &dpos, nfsd->nd_procp))
876 		nfsm_reply(0);
877 	fvp = fromnd.ni_vp;
878 	nfsm_srvmtofh(tfhp);
879 	nfsm_strsiz(len2, NFS_MAXNAMLEN);
880 	cred->cr_uid = saved_uid;
881 	tond.ni_cnd.cn_cred = cred;
882 	tond.ni_cnd.cn_nameiop = RENAME;
883 	tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
884 	if (error = nfs_namei(&tond, tfhp, len2, nfsd->nd_slp, nam, &md,
885 	    &dpos, nfsd->nd_procp)) {
886 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
887 		vrele(fromnd.ni_dvp);
888 		vrele(fvp);
889 		goto out1;
890 	}
891 	tdvp = tond.ni_dvp;
892 	tvp = tond.ni_vp;
893 	if (tvp != NULL) {
894 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
895 			error = EISDIR;
896 			goto out;
897 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
898 			error = ENOTDIR;
899 			goto out;
900 		}
901 		if (tvp->v_type == VDIR && tvp->v_mountedhere) {
902 			error = EXDEV;
903 			goto out;
904 		}
905 	}
906 	if (fvp->v_type == VDIR && fvp->v_mountedhere) {
907 		error = EBUSY;
908 		goto out;
909 	}
910 	if (fvp->v_mount != tdvp->v_mount) {
911 		error = EXDEV;
912 		goto out;
913 	}
914 	if (fvp == tdvp)
915 		error = EINVAL;
916 	/*
917 	 * If source is the same as the destination (that is the
918 	 * same vnode with the same name in the same directory),
919 	 * then there is nothing to do.
920 	 */
921 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
922 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
923 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
924 	      fromnd.ni_cnd.cn_namelen))
925 		error = -1;
926 out:
927 	if (!error) {
928 		nqsrv_getl(fromnd.ni_dvp, NQL_WRITE);
929 		nqsrv_getl(tdvp, NQL_WRITE);
930 		if (tvp)
931 			nqsrv_getl(tvp, NQL_WRITE);
932 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
933 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
934 	} else {
935 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
936 		if (tdvp == tvp)
937 			vrele(tdvp);
938 		else
939 			vput(tdvp);
940 		if (tvp)
941 			vput(tvp);
942 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
943 		vrele(fromnd.ni_dvp);
944 		vrele(fvp);
945 	}
946 	vrele(tond.ni_startdir);
947 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
948 out1:
949 	vrele(fromnd.ni_startdir);
950 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
951 	nfsm_reply(0);
952 	return (error);
953 
954 nfsmout:
955 	if (tond.ni_cnd.cn_nameiop || tond.ni_cnd.cn_flags) {
956 		vrele(tond.ni_startdir);
957 		FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
958 	}
959 	if (fromnd.ni_cnd.cn_nameiop || fromnd.ni_cnd.cn_flags) {
960 		vrele(fromnd.ni_startdir);
961 		FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
962 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
963 		vrele(fromnd.ni_dvp);
964 		vrele(fvp);
965 	}
966 	return (error);
967 }
968 
969 /*
970  * nfs link service
971  */
972 nfsrv_link(nfsd, mrep, md, dpos, cred, nam, mrq)
973 	struct nfsd *nfsd;
974 	struct mbuf *mrep, *md;
975 	caddr_t dpos;
976 	struct ucred *cred;
977 	struct mbuf *nam, **mrq;
978 {
979 	struct nameidata nd;
980 	register u_long *tl;
981 	register long t1;
982 	caddr_t bpos;
983 	int error = 0, rdonly, cache, len;
984 	char *cp2;
985 	struct mbuf *mb, *mreq;
986 	struct vnode *vp, *xp;
987 	nfsv2fh_t nfh, dnfh;
988 	fhandle_t *fhp, *dfhp;
989 	u_quad_t frev;
990 
991 	fhp = &nfh.fh_generic;
992 	dfhp = &dnfh.fh_generic;
993 	nfsm_srvmtofh(fhp);
994 	nfsm_srvmtofh(dfhp);
995 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
996 	if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
997 		nfsm_reply(0);
998 	if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
999 		goto out1;
1000 	nd.ni_cnd.cn_cred = cred;
1001 	nd.ni_cnd.cn_nameiop = CREATE;
1002 	nd.ni_cnd.cn_flags = LOCKPARENT;
1003 	if (error = nfs_namei(&nd, dfhp, len, nfsd->nd_slp, nam, &md, &dpos,
1004 	    nfsd->nd_procp))
1005 		goto out1;
1006 	xp = nd.ni_vp;
1007 	if (xp != NULL) {
1008 		error = EEXIST;
1009 		goto out;
1010 	}
1011 	xp = nd.ni_dvp;
1012 	if (vp->v_mount != xp->v_mount)
1013 		error = EXDEV;
1014 out:
1015 	if (!error) {
1016 		nqsrv_getl(vp, NQL_WRITE);
1017 		nqsrv_getl(xp, NQL_WRITE);
1018 		error = VOP_LINK(nd.ni_dvp, vp, &nd.ni_cnd);
1019 	} else {
1020 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1021 		if (nd.ni_dvp == nd.ni_vp)
1022 			vrele(nd.ni_dvp);
1023 		else
1024 			vput(nd.ni_dvp);
1025 		if (nd.ni_vp)
1026 			vrele(nd.ni_vp);
1027 	}
1028 out1:
1029 	vrele(vp);
1030 	nfsm_reply(0);
1031 	nfsm_srvdone;
1032 }
1033 
1034 /*
1035  * nfs symbolic link service
1036  */
1037 nfsrv_symlink(nfsd, mrep, md, dpos, cred, nam, mrq)
1038 	struct nfsd *nfsd;
1039 	struct mbuf *mrep, *md;
1040 	caddr_t dpos;
1041 	struct ucred *cred;
1042 	struct mbuf *nam, **mrq;
1043 {
1044 	struct vattr va;
1045 	struct nameidata nd;
1046 	register struct vattr *vap = &va;
1047 	register u_long *tl;
1048 	register long t1;
1049 	struct nfsv2_sattr *sp;
1050 	caddr_t bpos;
1051 	struct uio io;
1052 	struct iovec iv;
1053 	int error = 0, rdonly, cache, len, len2;
1054 	char *pathcp, *cp2;
1055 	struct mbuf *mb, *mreq;
1056 	nfsv2fh_t nfh;
1057 	fhandle_t *fhp;
1058 	u_quad_t frev;
1059 
1060 	pathcp = (char *)0;
1061 	fhp = &nfh.fh_generic;
1062 	nfsm_srvmtofh(fhp);
1063 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1064 	nd.ni_cnd.cn_cred = cred;
1065 	nd.ni_cnd.cn_nameiop = CREATE;
1066 	nd.ni_cnd.cn_flags = LOCKPARENT;
1067 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1068 	    nfsd->nd_procp))
1069 		goto out;
1070 	nfsm_strsiz(len2, NFS_MAXPATHLEN);
1071 	MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
1072 	iv.iov_base = pathcp;
1073 	iv.iov_len = len2;
1074 	io.uio_resid = len2;
1075 	io.uio_offset = 0;
1076 	io.uio_iov = &iv;
1077 	io.uio_iovcnt = 1;
1078 	io.uio_segflg = UIO_SYSSPACE;
1079 	io.uio_rw = UIO_READ;
1080 	io.uio_procp = (struct proc *)0;
1081 	nfsm_mtouio(&io, len2);
1082 	nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_SATTR(nfsd->nd_nqlflag != NQL_NOVAL));
1083 	*(pathcp + len2) = '\0';
1084 	if (nd.ni_vp) {
1085 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1086 		if (nd.ni_dvp == nd.ni_vp)
1087 			vrele(nd.ni_dvp);
1088 		else
1089 			vput(nd.ni_dvp);
1090 		vrele(nd.ni_vp);
1091 		error = EEXIST;
1092 		goto out;
1093 	}
1094 	VATTR_NULL(vap);
1095 	vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
1096 	nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1097 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
1098 out:
1099 	if (pathcp)
1100 		FREE(pathcp, M_TEMP);
1101 	nfsm_reply(0);
1102 	return (error);
1103 nfsmout:
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 		vrele(nd.ni_vp);
1111 	if (pathcp)
1112 		FREE(pathcp, M_TEMP);
1113 	return (error);
1114 }
1115 
1116 /*
1117  * nfs mkdir service
1118  */
1119 nfsrv_mkdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1120 	struct nfsd *nfsd;
1121 	struct mbuf *mrep, *md;
1122 	caddr_t dpos;
1123 	struct ucred *cred;
1124 	struct mbuf *nam, **mrq;
1125 {
1126 	struct vattr va;
1127 	register struct vattr *vap = &va;
1128 	register struct nfsv2_fattr *fp;
1129 	struct nameidata nd;
1130 	register caddr_t cp;
1131 	register u_long *tl;
1132 	register long t1;
1133 	caddr_t bpos;
1134 	int error = 0, rdonly, cache, len;
1135 	char *cp2;
1136 	struct mbuf *mb, *mb2, *mreq;
1137 	struct vnode *vp;
1138 	nfsv2fh_t nfh;
1139 	fhandle_t *fhp;
1140 	u_quad_t frev;
1141 
1142 	fhp = &nfh.fh_generic;
1143 	nfsm_srvmtofh(fhp);
1144 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1145 	nd.ni_cnd.cn_cred = cred;
1146 	nd.ni_cnd.cn_nameiop = CREATE;
1147 	nd.ni_cnd.cn_flags = LOCKPARENT;
1148 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1149 	    nfsd->nd_procp))
1150 		nfsm_reply(0);
1151 	nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1152 	VATTR_NULL(vap);
1153 	vap->va_type = VDIR;
1154 	vap->va_mode = nfstov_mode(*tl++);
1155 	vp = nd.ni_vp;
1156 	if (vp != NULL) {
1157 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1158 		if (nd.ni_dvp == vp)
1159 			vrele(nd.ni_dvp);
1160 		else
1161 			vput(nd.ni_dvp);
1162 		vrele(vp);
1163 		error = EEXIST;
1164 		nfsm_reply(0);
1165 	}
1166 	nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1167 	if (error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap))
1168 		nfsm_reply(0);
1169 	vp = nd.ni_vp;
1170 	bzero((caddr_t)fhp, sizeof(nfh));
1171 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1172 	if (error = VFS_VPTOFH(vp, &fhp->fh_fid)) {
1173 		vput(vp);
1174 		nfsm_reply(0);
1175 	}
1176 	error = VOP_GETATTR(vp, vap, cred, nfsd->nd_procp);
1177 	vput(vp);
1178 	nfsm_reply(NFSX_FH+NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
1179 	nfsm_srvfhtom(fhp);
1180 	nfsm_build(fp, struct nfsv2_fattr *, NFSX_FATTR(nfsd->nd_nqlflag != NQL_NOVAL));
1181 	nfsm_srvfillattr;
1182 	return (error);
1183 nfsmout:
1184 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1185 	if (nd.ni_dvp == nd.ni_vp)
1186 		vrele(nd.ni_dvp);
1187 	else
1188 		vput(nd.ni_dvp);
1189 	if (nd.ni_vp)
1190 		vrele(nd.ni_vp);
1191 	return (error);
1192 }
1193 
1194 /*
1195  * nfs rmdir service
1196  */
1197 nfsrv_rmdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1198 	struct nfsd *nfsd;
1199 	struct mbuf *mrep, *md;
1200 	caddr_t dpos;
1201 	struct ucred *cred;
1202 	struct mbuf *nam, **mrq;
1203 {
1204 	register u_long *tl;
1205 	register long t1;
1206 	caddr_t bpos;
1207 	int error = 0, rdonly, cache, len;
1208 	char *cp2;
1209 	struct mbuf *mb, *mreq;
1210 	struct vnode *vp;
1211 	nfsv2fh_t nfh;
1212 	fhandle_t *fhp;
1213 	struct nameidata nd;
1214 	u_quad_t frev;
1215 
1216 	fhp = &nfh.fh_generic;
1217 	nfsm_srvmtofh(fhp);
1218 	nfsm_srvstrsiz(len, NFS_MAXNAMLEN);
1219 	nd.ni_cnd.cn_cred = cred;
1220 	nd.ni_cnd.cn_nameiop = DELETE;
1221 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1222 	if (error = nfs_namei(&nd, fhp, len, nfsd->nd_slp, nam, &md, &dpos,
1223 	    nfsd->nd_procp))
1224 		nfsm_reply(0);
1225 	vp = nd.ni_vp;
1226 	if (vp->v_type != VDIR) {
1227 		error = ENOTDIR;
1228 		goto out;
1229 	}
1230 	/*
1231 	 * No rmdir "." please.
1232 	 */
1233 	if (nd.ni_dvp == vp) {
1234 		error = EINVAL;
1235 		goto out;
1236 	}
1237 	/*
1238 	 * The root of a mounted filesystem cannot be deleted.
1239 	 */
1240 	if (vp->v_flag & VROOT)
1241 		error = EBUSY;
1242 out:
1243 	if (!error) {
1244 		nqsrv_getl(nd.ni_dvp, NQL_WRITE);
1245 		nqsrv_getl(vp, NQL_WRITE);
1246 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1247 	} else {
1248 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1249 		if (nd.ni_dvp == nd.ni_vp)
1250 			vrele(nd.ni_dvp);
1251 		else
1252 			vput(nd.ni_dvp);
1253 		vput(vp);
1254 	}
1255 	nfsm_reply(0);
1256 	nfsm_srvdone;
1257 }
1258 
1259 /*
1260  * nfs readdir service
1261  * - mallocs what it thinks is enough to read
1262  *	count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
1263  * - calls VOP_READDIR()
1264  * - loops around building the reply
1265  *	if the output generated exceeds count break out of loop
1266  *	The nfsm_clget macro is used here so that the reply will be packed
1267  *	tightly in mbuf clusters.
1268  * - it only knows that it has encountered eof when the VOP_READDIR()
1269  *	reads nothing
1270  * - as such one readdir rpc will return eof false although you are there
1271  *	and then the next will return eof
1272  * - it trims out records with d_fileno == 0
1273  *	this doesn't matter for Unix clients, but they might confuse clients
1274  *	for other os'.
1275  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
1276  *	than requested, but this may not apply to all filesystems. For
1277  *	example, client NFS does not { although it is never remote mounted
1278  *	anyhow }
1279  *     The alternate call nqnfsrv_readdirlook() does lookups as well.
1280  * PS: The NFS protocol spec. does not clarify what the "count" byte
1281  *	argument is a count of.. just name strings and file id's or the
1282  *	entire reply rpc or ...
1283  *	I tried just file name and id sizes and it confused the Sun client,
1284  *	so I am using the full rpc size now. The "paranoia.." comment refers
1285  *	to including the status longwords that are not a part of the dir.
1286  *	"entry" structures, but are in the rpc.
1287  */
1288 struct flrep {
1289 	u_long fl_cachable;
1290 	u_long fl_duration;
1291 	u_long fl_frev[2];
1292 	nfsv2fh_t fl_nfh;
1293 	u_long fl_fattr[NFSX_NQFATTR / sizeof (u_long)];
1294 };
1295 
1296 nfsrv_readdir(nfsd, mrep, md, dpos, cred, nam, mrq)
1297 	struct nfsd *nfsd;
1298 	struct mbuf *mrep, *md;
1299 	caddr_t dpos;
1300 	struct ucred *cred;
1301 	struct mbuf *nam, **mrq;
1302 {
1303 	register char *bp, *be;
1304 	register struct mbuf *mp;
1305 	register struct dirent *dp;
1306 	register caddr_t cp;
1307 	register u_long *tl;
1308 	register long t1;
1309 	caddr_t bpos;
1310 	struct mbuf *mb, *mb2, *mreq, *mp2;
1311 	char *cpos, *cend, *cp2, *rbuf;
1312 	struct vnode *vp;
1313 	nfsv2fh_t nfh;
1314 	fhandle_t *fhp;
1315 	struct uio io;
1316 	struct iovec iv;
1317 	struct vattr va;
1318 	int len, nlen, rem, xfer, tsiz, i, error = 0;
1319 	int siz, cnt, fullsiz, eofflag, rdonly, cache;
1320 	u_quad_t frev;
1321 	u_long on, off, toff;
1322 
1323 	fhp = &nfh.fh_generic;
1324 	nfsm_srvmtofh(fhp);
1325 	nfsm_dissect(tl, u_long *, 2*NFSX_UNSIGNED);
1326 	toff = fxdr_unsigned(u_long, *tl++);
1327 	off = (toff & ~(NFS_DIRBLKSIZ-1));
1328 	on = (toff & (NFS_DIRBLKSIZ-1));
1329 	cnt = fxdr_unsigned(int, *tl);
1330 	siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
1331 	if (cnt > NFS_MAXREADDIR)
1332 		siz = NFS_MAXREADDIR;
1333 	fullsiz = siz;
1334 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1335 		nfsm_reply(0);
1336 	nqsrv_getl(vp, NQL_READ);
1337 	if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
1338 		vput(vp);
1339 		nfsm_reply(0);
1340 	}
1341 	VOP_UNLOCK(vp);
1342 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1343 again:
1344 	iv.iov_base = rbuf;
1345 	iv.iov_len = fullsiz;
1346 	io.uio_iov = &iv;
1347 	io.uio_iovcnt = 1;
1348 	io.uio_offset = (off_t)off;
1349 	io.uio_resid = fullsiz;
1350 	io.uio_segflg = UIO_SYSSPACE;
1351 	io.uio_rw = UIO_READ;
1352 	io.uio_procp = (struct proc *)0;
1353 	error = VOP_READDIR(vp, &io, cred);
1354 	off = (off_t)io.uio_offset;
1355 	if (error) {
1356 		vrele(vp);
1357 		free((caddr_t)rbuf, M_TEMP);
1358 		nfsm_reply(0);
1359 	}
1360 	if (io.uio_resid < fullsiz)
1361 		eofflag = 0;
1362 	else
1363 		eofflag = 1;
1364 	if (io.uio_resid) {
1365 		siz -= io.uio_resid;
1366 
1367 		/*
1368 		 * If nothing read, return eof
1369 		 * rpc reply
1370 		 */
1371 		if (siz == 0) {
1372 			vrele(vp);
1373 			nfsm_reply(2*NFSX_UNSIGNED);
1374 			nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1375 			*tl++ = nfs_false;
1376 			*tl = nfs_true;
1377 			FREE((caddr_t)rbuf, M_TEMP);
1378 			return (0);
1379 		}
1380 	}
1381 
1382 	/*
1383 	 * Check for degenerate cases of nothing useful read.
1384 	 * If so go try again
1385 	 */
1386 	cpos = rbuf + on;
1387 	cend = rbuf + siz;
1388 	dp = (struct dirent *)cpos;
1389 	while (cpos < cend && dp->d_fileno == 0) {
1390 		cpos += dp->d_reclen;
1391 		dp = (struct dirent *)cpos;
1392 	}
1393 	if (cpos >= cend) {
1394 		toff = off;
1395 		siz = fullsiz;
1396 		on = 0;
1397 		goto again;
1398 	}
1399 
1400 	cpos = rbuf + on;
1401 	cend = rbuf + siz;
1402 	dp = (struct dirent *)cpos;
1403 	len = 3*NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
1404 	nfsm_reply(siz);
1405 	mp = mp2 = mb;
1406 	bp = bpos;
1407 	be = bp + M_TRAILINGSPACE(mp);
1408 
1409 	/* Loop through the records and build reply */
1410 	while (cpos < cend) {
1411 		if (dp->d_fileno != 0) {
1412 			nlen = dp->d_namlen;
1413 			rem = nfsm_rndup(nlen)-nlen;
1414 			len += (4*NFSX_UNSIGNED + nlen + rem);
1415 			if (len > cnt) {
1416 				eofflag = 0;
1417 				break;
1418 			}
1419 			/*
1420 			 * Build the directory record xdr from
1421 			 * the dirent entry.
1422 			 */
1423 			nfsm_clget;
1424 			*tl = nfs_true;
1425 			bp += NFSX_UNSIGNED;
1426 			nfsm_clget;
1427 			*tl = txdr_unsigned(dp->d_fileno);
1428 			bp += NFSX_UNSIGNED;
1429 			nfsm_clget;
1430 			*tl = txdr_unsigned(nlen);
1431 			bp += NFSX_UNSIGNED;
1432 
1433 			/* And loop around copying the name */
1434 			xfer = nlen;
1435 			cp = dp->d_name;
1436 			while (xfer > 0) {
1437 				nfsm_clget;
1438 				if ((bp+xfer) > be)
1439 					tsiz = be-bp;
1440 				else
1441 					tsiz = xfer;
1442 				bcopy(cp, bp, tsiz);
1443 				bp += tsiz;
1444 				xfer -= tsiz;
1445 				if (xfer > 0)
1446 					cp += tsiz;
1447 			}
1448 			/* And null pad to a long boundary */
1449 			for (i = 0; i < rem; i++)
1450 				*bp++ = '\0';
1451 			nfsm_clget;
1452 
1453 			/* Finish off the record */
1454 			toff += dp->d_reclen;
1455 			*tl = txdr_unsigned(toff);
1456 			bp += NFSX_UNSIGNED;
1457 		} else
1458 			toff += dp->d_reclen;
1459 		cpos += dp->d_reclen;
1460 		dp = (struct dirent *)cpos;
1461 	}
1462 	vrele(vp);
1463 	nfsm_clget;
1464 	*tl = nfs_false;
1465 	bp += NFSX_UNSIGNED;
1466 	nfsm_clget;
1467 	if (eofflag)
1468 		*tl = nfs_true;
1469 	else
1470 		*tl = nfs_false;
1471 	bp += NFSX_UNSIGNED;
1472 	if (mp != mb) {
1473 		if (bp < be)
1474 			mp->m_len = bp - mtod(mp, caddr_t);
1475 	} else
1476 		mp->m_len += bp - bpos;
1477 	FREE(rbuf, M_TEMP);
1478 	nfsm_srvdone;
1479 }
1480 
1481 nqnfsrv_readdirlook(nfsd, mrep, md, dpos, cred, nam, mrq)
1482 	struct nfsd *nfsd;
1483 	struct mbuf *mrep, *md;
1484 	caddr_t dpos;
1485 	struct ucred *cred;
1486 	struct mbuf *nam, **mrq;
1487 {
1488 	register char *bp, *be;
1489 	register struct mbuf *mp;
1490 	register struct dirent *dp;
1491 	register caddr_t cp;
1492 	register u_long *tl;
1493 	register long t1;
1494 	caddr_t bpos;
1495 	struct mbuf *mb, *mb2, *mreq, *mp2;
1496 	char *cpos, *cend, *cp2, *rbuf;
1497 	struct vnode *vp, *nvp;
1498 	struct flrep fl;
1499 	nfsv2fh_t nfh;
1500 	fhandle_t *fhp;
1501 	struct uio io;
1502 	struct iovec iv;
1503 	struct vattr va, *vap = &va;
1504 	struct nfsv2_fattr *fp;
1505 	int len, nlen, rem, xfer, tsiz, i, error = 0, duration2, cache2;
1506 	int siz, cnt, fullsiz, eofflag, rdonly, cache;
1507 	u_quad_t frev, frev2;
1508 	u_long on, off, toff;
1509 
1510 	fhp = &nfh.fh_generic;
1511 	nfsm_srvmtofh(fhp);
1512 	nfsm_dissect(tl, u_long *, 3*NFSX_UNSIGNED);
1513 	toff = fxdr_unsigned(u_long, *tl++);
1514 	off = (toff & ~(NFS_DIRBLKSIZ-1));
1515 	on = (toff & (NFS_DIRBLKSIZ-1));
1516 	cnt = fxdr_unsigned(int, *tl++);
1517 	duration2 = fxdr_unsigned(int, *tl);
1518 	siz = ((cnt+NFS_DIRBLKSIZ-1) & ~(NFS_DIRBLKSIZ-1));
1519 	if (cnt > NFS_MAXREADDIR)
1520 		siz = NFS_MAXREADDIR;
1521 	fullsiz = siz;
1522 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1523 		nfsm_reply(0);
1524 	nqsrv_getl(vp, NQL_READ);
1525 	if (error = nfsrv_access(vp, VEXEC, cred, rdonly, nfsd->nd_procp)) {
1526 		vput(vp);
1527 		nfsm_reply(0);
1528 	}
1529 	VOP_UNLOCK(vp);
1530 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
1531 again:
1532 	iv.iov_base = rbuf;
1533 	iv.iov_len = fullsiz;
1534 	io.uio_iov = &iv;
1535 	io.uio_iovcnt = 1;
1536 	io.uio_offset = (off_t)off;
1537 	io.uio_resid = fullsiz;
1538 	io.uio_segflg = UIO_SYSSPACE;
1539 	io.uio_rw = UIO_READ;
1540 	io.uio_procp = (struct proc *)0;
1541 	error = VOP_READDIR(vp, &io, cred);
1542 	off = (u_long)io.uio_offset;
1543 	if (error) {
1544 		vrele(vp);
1545 		free((caddr_t)rbuf, M_TEMP);
1546 		nfsm_reply(0);
1547 	}
1548 	if (io.uio_resid < fullsiz)
1549 		eofflag = 0;
1550 	else
1551 		eofflag = 1;
1552 	if (io.uio_resid) {
1553 		siz -= io.uio_resid;
1554 
1555 		/*
1556 		 * If nothing read, return eof
1557 		 * rpc reply
1558 		 */
1559 		if (siz == 0) {
1560 			vrele(vp);
1561 			nfsm_reply(2 * NFSX_UNSIGNED);
1562 			nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
1563 			*tl++ = nfs_false;
1564 			*tl = nfs_true;
1565 			FREE((caddr_t)rbuf, M_TEMP);
1566 			return (0);
1567 		}
1568 	}
1569 
1570 	/*
1571 	 * Check for degenerate cases of nothing useful read.
1572 	 * If so go try again
1573 	 */
1574 	cpos = rbuf + on;
1575 	cend = rbuf + siz;
1576 	dp = (struct dirent *)cpos;
1577 	while (cpos < cend && dp->d_fileno == 0) {
1578 		cpos += dp->d_reclen;
1579 		dp = (struct dirent *)cpos;
1580 	}
1581 	if (cpos >= cend) {
1582 		toff = off;
1583 		siz = fullsiz;
1584 		on = 0;
1585 		goto again;
1586 	}
1587 
1588 	cpos = rbuf + on;
1589 	cend = rbuf + siz;
1590 	dp = (struct dirent *)cpos;
1591 	len = 3 * NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
1592 	nfsm_reply(siz);
1593 	mp = mp2 = mb;
1594 	bp = bpos;
1595 	be = bp + M_TRAILINGSPACE(mp);
1596 
1597 	/* Loop through the records and build reply */
1598 	while (cpos < cend) {
1599 		if (dp->d_fileno != 0) {
1600 			nlen = dp->d_namlen;
1601 			rem = nfsm_rndup(nlen)-nlen;
1602 
1603 			/*
1604 			 * For readdir_and_lookup get the vnode using
1605 			 * the file number.
1606 			 */
1607 			if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
1608 				goto invalid;
1609 			bzero((caddr_t)&fl.fl_nfh, sizeof (nfsv2fh_t));
1610 			fl.fl_nfh.fh_generic.fh_fsid =
1611 				nvp->v_mount->mnt_stat.f_fsid;
1612 			if (VFS_VPTOFH(nvp, &fl.fl_nfh.fh_generic.fh_fid)) {
1613 				vput(nvp);
1614 				goto invalid;
1615 			}
1616 			if (duration2) {
1617 				(void) nqsrv_getlease(nvp, &duration2, NQL_READ,
1618 					nfsd, nam, &cache2, &frev2, cred);
1619 				fl.fl_duration = txdr_unsigned(duration2);
1620 				fl.fl_cachable = txdr_unsigned(cache2);
1621 				txdr_hyper(&frev2, fl.fl_frev);
1622 			} else
1623 				fl.fl_duration = 0;
1624 			if (VOP_GETATTR(nvp, vap, cred, nfsd->nd_procp)) {
1625 				vput(nvp);
1626 				goto invalid;
1627 			}
1628 			vput(nvp);
1629 			fp = (struct nfsv2_fattr *)&fl.fl_fattr;
1630 			nfsm_srvfillattr;
1631 			len += (4*NFSX_UNSIGNED + nlen + rem + NFSX_FH
1632 				+ NFSX_NQFATTR);
1633 			if (len > cnt) {
1634 				eofflag = 0;
1635 				break;
1636 			}
1637 			/*
1638 			 * Build the directory record xdr from
1639 			 * the dirent entry.
1640 			 */
1641 			nfsm_clget;
1642 			*tl = nfs_true;
1643 			bp += NFSX_UNSIGNED;
1644 
1645 			/*
1646 			 * For readdir_and_lookup copy the stuff out.
1647 			 */
1648 			xfer = sizeof (struct flrep);
1649 			cp = (caddr_t)&fl;
1650 			while (xfer > 0) {
1651 				nfsm_clget;
1652 				if ((bp+xfer) > be)
1653 					tsiz = be-bp;
1654 				else
1655 					tsiz = xfer;
1656 				bcopy(cp, bp, tsiz);
1657 				bp += tsiz;
1658 				xfer -= tsiz;
1659 				if (xfer > 0)
1660 					cp += tsiz;
1661 			}
1662 			nfsm_clget;
1663 			*tl = txdr_unsigned(dp->d_fileno);
1664 			bp += NFSX_UNSIGNED;
1665 			nfsm_clget;
1666 			*tl = txdr_unsigned(nlen);
1667 			bp += NFSX_UNSIGNED;
1668 
1669 			/* And loop around copying the name */
1670 			xfer = nlen;
1671 			cp = dp->d_name;
1672 			while (xfer > 0) {
1673 				nfsm_clget;
1674 				if ((bp+xfer) > be)
1675 					tsiz = be-bp;
1676 				else
1677 					tsiz = xfer;
1678 				bcopy(cp, bp, tsiz);
1679 				bp += tsiz;
1680 				xfer -= tsiz;
1681 				if (xfer > 0)
1682 					cp += tsiz;
1683 			}
1684 			/* And null pad to a long boundary */
1685 			for (i = 0; i < rem; i++)
1686 				*bp++ = '\0';
1687 			nfsm_clget;
1688 
1689 			/* Finish off the record */
1690 			toff += dp->d_reclen;
1691 			*tl = txdr_unsigned(toff);
1692 			bp += NFSX_UNSIGNED;
1693 		} else
1694 invalid:
1695 			toff += dp->d_reclen;
1696 		cpos += dp->d_reclen;
1697 		dp = (struct dirent *)cpos;
1698 	}
1699 	vrele(vp);
1700 	nfsm_clget;
1701 	*tl = nfs_false;
1702 	bp += NFSX_UNSIGNED;
1703 	nfsm_clget;
1704 	if (eofflag)
1705 		*tl = nfs_true;
1706 	else
1707 		*tl = nfs_false;
1708 	bp += NFSX_UNSIGNED;
1709 	if (mp != mb) {
1710 		if (bp < be)
1711 			mp->m_len = bp - mtod(mp, caddr_t);
1712 	} else
1713 		mp->m_len += bp - bpos;
1714 	FREE(rbuf, M_TEMP);
1715 	nfsm_srvdone;
1716 }
1717 
1718 /*
1719  * nfs statfs service
1720  */
1721 nfsrv_statfs(nfsd, mrep, md, dpos, cred, nam, mrq)
1722 	struct nfsd *nfsd;
1723 	struct mbuf *mrep, *md;
1724 	caddr_t dpos;
1725 	struct ucred *cred;
1726 	struct mbuf *nam, **mrq;
1727 {
1728 	register struct statfs *sf;
1729 	register struct nfsv2_statfs *sfp;
1730 	register u_long *tl;
1731 	register long t1;
1732 	caddr_t bpos;
1733 	int error = 0, rdonly, cache, isnq;
1734 	char *cp2;
1735 	struct mbuf *mb, *mb2, *mreq;
1736 	struct vnode *vp;
1737 	nfsv2fh_t nfh;
1738 	fhandle_t *fhp;
1739 	struct statfs statfs;
1740 	u_quad_t frev;
1741 
1742 	fhp = &nfh.fh_generic;
1743 	isnq = (nfsd->nd_nqlflag != NQL_NOVAL);
1744 	nfsm_srvmtofh(fhp);
1745 	if (error = nfsrv_fhtovp(fhp, TRUE, &vp, cred, nfsd->nd_slp, nam, &rdonly))
1746 		nfsm_reply(0);
1747 	sf = &statfs;
1748 	error = VFS_STATFS(vp->v_mount, sf, nfsd->nd_procp);
1749 	vput(vp);
1750 	nfsm_reply(NFSX_STATFS(isnq));
1751 	nfsm_build(sfp, struct nfsv2_statfs *, NFSX_STATFS(isnq));
1752 	sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
1753 	sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
1754 	sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
1755 	sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
1756 	sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
1757 	if (isnq) {
1758 		sfp->sf_files = txdr_unsigned(sf->f_files);
1759 		sfp->sf_ffree = txdr_unsigned(sf->f_ffree);
1760 	}
1761 	nfsm_srvdone;
1762 }
1763 
1764 /*
1765  * Null operation, used by clients to ping server
1766  */
1767 /* ARGSUSED */
1768 nfsrv_null(nfsd, mrep, md, dpos, cred, nam, mrq)
1769 	struct nfsd *nfsd;
1770 	struct mbuf *mrep, *md;
1771 	caddr_t dpos;
1772 	struct ucred *cred;
1773 	struct mbuf *nam, **mrq;
1774 {
1775 	caddr_t bpos;
1776 	int error = VNOVAL, cache;
1777 	struct mbuf *mb, *mreq;
1778 	u_quad_t frev;
1779 
1780 	nfsm_reply(0);
1781 	return (error);
1782 }
1783 
1784 /*
1785  * No operation, used for obsolete procedures
1786  */
1787 /* ARGSUSED */
1788 nfsrv_noop(nfsd, mrep, md, dpos, cred, nam, mrq)
1789 	struct nfsd *nfsd;
1790 	struct mbuf *mrep, *md;
1791 	caddr_t dpos;
1792 	struct ucred *cred;
1793 	struct mbuf *nam, **mrq;
1794 {
1795 	caddr_t bpos;
1796 	int error, cache;
1797 	struct mbuf *mb, *mreq;
1798 	u_quad_t frev;
1799 
1800 	if (nfsd->nd_repstat)
1801 		error = nfsd->nd_repstat;
1802 	else
1803 		error = EPROCUNAVAIL;
1804 	nfsm_reply(0);
1805 	return (error);
1806 }
1807 
1808 /*
1809  * Perform access checking for vnodes obtained from file handles that would
1810  * refer to files already opened by a Unix client. You cannot just use
1811  * vn_writechk() and VOP_ACCESS() for two reasons.
1812  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
1813  * 2 - The owner is to be given access irrespective of mode bits so that
1814  *     processes that chmod after opening a file don't break. I don't like
1815  *     this because it opens a security hole, but since the nfs server opens
1816  *     a security hole the size of a barn door anyhow, what the heck.
1817  */
1818 nfsrv_access(vp, flags, cred, rdonly, p)
1819 	register struct vnode *vp;
1820 	int flags;
1821 	register struct ucred *cred;
1822 	int rdonly;
1823 	struct proc *p;
1824 {
1825 	struct vattr vattr;
1826 	int error;
1827 	if (flags & VWRITE) {
1828 		/* Just vn_writechk() changed to check rdonly */
1829 		/*
1830 		 * Disallow write attempts on read-only file systems;
1831 		 * unless the file is a socket or a block or character
1832 		 * device resident on the file system.
1833 		 */
1834 		if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
1835 			switch (vp->v_type) {
1836 			case VREG: case VDIR: case VLNK:
1837 				return (EROFS);
1838 			}
1839 		}
1840 		/*
1841 		 * If there's shared text associated with
1842 		 * the inode, try to free it up once.  If
1843 		 * we fail, we can't allow writing.
1844 		 */
1845 		if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
1846 			return (ETXTBSY);
1847 	}
1848 	if (error = VOP_GETATTR(vp, &vattr, cred, p))
1849 		return (error);
1850 	if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
1851 	    cred->cr_uid != vattr.va_uid)
1852 		return (error);
1853 	return (0);
1854 }
1855