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