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