xref: /dragonfly/sys/vfs/nfs/nfs_serv.c (revision 527b525a)
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  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  * 3. Neither the name of the University nor the names of its contributors
17  *    may be used to endorse or promote products derived from this software
18  *    without specific prior written permission.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30  * SUCH DAMAGE.
31  *
32  *	@(#)nfs_serv.c  8.8 (Berkeley) 7/31/95
33  * $FreeBSD: src/sys/nfs/nfs_serv.c,v 1.93.2.6 2002/12/29 18:19:53 dillon Exp $
34  */
35 
36 /*
37  * nfs version 2 and 3 server calls to vnode ops
38  * - these routines generally have 3 phases
39  *   1 - break down and validate rpc request in mbuf list
40  *   2 - do the vnode ops for the request
41  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
42  *   3 - build the rpc reply in an mbuf list
43  *   nb:
44  *	- do not mix the phases, since the nfsm_?? macros can return failures
45  *	  on a bad rpc or similar and do not do any vrele() or vput()'s
46  *
47  *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
48  *	error number iff error != 0 whereas
49  *	returning an error from the server function implies a fatal error
50  *	such as a badly constructed rpc request that should be dropped without
51  *	a reply.
52  *	For Version 3, nfsm_reply() does not return for the error case, since
53  *	most version 3 rpcs return more than the status for error cases.
54  *
55  * Other notes:
56  *	Warning: always pay careful attention to resource cleanup on return
57  *	and note that nfsm_*() macros can terminate a procedure on certain
58  *	errors.
59  */
60 
61 #include <sys/param.h>
62 #include <sys/systm.h>
63 #include <sys/proc.h>
64 #include <sys/priv.h>
65 #include <sys/nlookup.h>
66 #include <sys/namei.h>
67 #include <sys/unistd.h>
68 #include <sys/vnode.h>
69 #include <sys/mount.h>
70 #include <sys/socket.h>
71 #include <sys/socketvar.h>
72 #include <sys/malloc.h>
73 #include <sys/mbuf.h>
74 #include <sys/dirent.h>
75 #include <sys/stat.h>
76 #include <sys/kernel.h>
77 #include <sys/sysctl.h>
78 #include <sys/buf.h>
79 
80 #include <vm/vm.h>
81 #include <vm/vm_extern.h>
82 #include <vm/vm_object.h>
83 
84 #include <sys/buf2.h>
85 
86 #include <sys/thread2.h>
87 
88 #include "nfsproto.h"
89 #include "rpcv2.h"
90 #include "nfs.h"
91 #include "xdr_subs.h"
92 #include "nfsm_subs.h"
93 
94 #ifdef NFSRV_DEBUG
95 #define nfsdbprintf(info)	kprintf info
96 #else
97 #define nfsdbprintf(info)
98 #endif
99 
100 #define MAX_REORDERED_RPC	(16)
101 #define MAX_COMMIT_COUNT	(1024 * 1024)
102 
103 #define NUM_HEURISTIC		1031
104 #define NHUSE_INIT		64
105 #define NHUSE_INC		16
106 #define NHUSE_MAX		2048
107 
108 static struct nfsheur {
109     struct vnode *nh_vp;	/* vp to match (unreferenced pointer) */
110     off_t nh_nextoff;		/* next offset for sequential detection */
111     int nh_use;			/* use count for selection */
112     int nh_seqcount;		/* heuristic */
113 } nfsheur[NUM_HEURISTIC];
114 
115 nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
116 		      NFFIFO, NFNON };
117 #ifndef NFS_NOSERVER
118 nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
119 		      NFCHR, NFNON };
120 
121 int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
122 int nfsrvw_procrastinate_v3 = 0;
123 
124 static struct timespec	nfsver;
125 
126 SYSCTL_DECL(_vfs_nfs);
127 
128 int nfs_async;
129 SYSCTL_INT(_vfs_nfs, OID_AUTO, async, CTLFLAG_RW, &nfs_async, 0,
130     "Enable unstable and fast writes");
131 static int nfs_commit_blks;
132 static int nfs_commit_miss;
133 SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_blks, CTLFLAG_RW, &nfs_commit_blks, 0,
134     "Number of committed blocks");
135 SYSCTL_INT(_vfs_nfs, OID_AUTO, commit_miss, CTLFLAG_RW, &nfs_commit_miss, 0,
136     "Number of nfs blocks committed from dirty buffers");
137 
138 static int nfsrv_access (struct mount *, struct vnode *, int,
139 			struct ucred *, int, struct thread *, int);
140 static void nfsrvw_coalesce (struct nfsrv_descript *,
141 		struct nfsrv_descript *);
142 
143 /*
144  * Heuristic to detect sequential operation.
145  */
146 static struct nfsheur *
147 nfsrv_sequential_heuristic(struct uio *uio, struct vnode *vp, int writeop)
148 {
149 	struct nfsheur *nh;
150 	int hi, try;
151 
152 	/* Locate best candidate */
153 	try = 32;
154 	hi = ((int)(vm_offset_t) vp / sizeof(struct vnode)) % NUM_HEURISTIC;
155 	nh = &nfsheur[hi];
156 
157 	while (try--) {
158 		if (nfsheur[hi].nh_vp == vp) {
159 			nh = &nfsheur[hi];
160 			break;
161 		}
162 		if (nfsheur[hi].nh_use > 0)
163 			--nfsheur[hi].nh_use;
164 		hi = (hi + 1) % NUM_HEURISTIC;
165 		if (nfsheur[hi].nh_use < nh->nh_use)
166 			nh = &nfsheur[hi];
167 	}
168 
169 	/* Initialize hint if this is a new file */
170 	if (nh->nh_vp != vp) {
171 		nh->nh_vp = vp;
172 		nh->nh_nextoff = uio->uio_offset;
173 		nh->nh_use = NHUSE_INIT;
174 		if (uio->uio_offset == 0)
175 			nh->nh_seqcount = 4;
176 		else
177 			nh->nh_seqcount = 1;
178 	}
179 
180 	/*
181 	 * Calculate heuristic
182 	 *
183 	 * See vfs_vnops.c:sequential_heuristic().
184 	 */
185 	if ((uio->uio_offset == 0 && nh->nh_seqcount > 0) ||
186 	    uio->uio_offset == nh->nh_nextoff) {
187 		nh->nh_seqcount += howmany(uio->uio_resid, 16384);
188 		if (nh->nh_seqcount > IO_SEQMAX)
189 			nh->nh_seqcount = IO_SEQMAX;
190 	} else if (qabs(uio->uio_offset - nh->nh_nextoff) <= MAX_REORDERED_RPC *
191 		imax(vp->v_mount->mnt_stat.f_iosize, uio->uio_resid)) {
192 		    /* Probably a reordered RPC, leave seqcount alone. */
193 	} else if (nh->nh_seqcount > 1) {
194 		nh->nh_seqcount /= 2;
195 	} else {
196 		nh->nh_seqcount = 0;
197 	}
198 	nh->nh_use += NHUSE_INC;
199 	if (nh->nh_use > NHUSE_MAX)
200 		nh->nh_use = NHUSE_MAX;
201 	return (nh);
202 }
203 
204 /*
205  * nfs v3 access service
206  */
207 int
208 nfsrv3_access(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
209 	      struct thread *td, struct mbuf **mrq)
210 {
211 	struct sockaddr *nam = nfsd->nd_nam;
212 	struct ucred *cred = &nfsd->nd_cr;
213 	struct vnode *vp = NULL;
214 	struct mount *mp = NULL;
215 	nfsfh_t nfh;
216 	fhandle_t *fhp;
217 	int error = 0, rdonly, getret;
218 	struct vattr vattr, *vap = &vattr;
219 	u_long testmode, nfsmode;
220 	struct nfsm_info info;
221 	u_int32_t *tl;
222 
223 	info.dpos = nfsd->nd_dpos;
224 	info.md = nfsd->nd_md;
225 	info.mrep = nfsd->nd_mrep;
226 	info.mreq = NULL;
227 
228 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
229 	fhp = &nfh.fh_generic;
230 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
231 	NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
232 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, &rdonly,
233 	    (nfsd->nd_flag & ND_KERBAUTH), TRUE);
234 	if (error) {
235 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
236 		nfsm_srvpostop_attr(&info, nfsd, 1, NULL);
237 		error = 0;
238 		goto nfsmout;
239 	}
240 	nfsmode = fxdr_unsigned(u_int32_t, *tl);
241 	if ((nfsmode & NFSV3ACCESS_READ) &&
242 		nfsrv_access(mp, vp, VREAD, cred, rdonly, td, 0))
243 		nfsmode &= ~NFSV3ACCESS_READ;
244 	if (vp->v_type == VDIR)
245 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
246 			NFSV3ACCESS_DELETE);
247 	else
248 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
249 	if ((nfsmode & testmode) &&
250 		nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 0))
251 		nfsmode &= ~testmode;
252 	if (vp->v_type == VDIR)
253 		testmode = NFSV3ACCESS_LOOKUP;
254 	else
255 		testmode = NFSV3ACCESS_EXECUTE;
256 	if ((nfsmode & testmode) &&
257 		nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0))
258 		nfsmode &= ~testmode;
259 	getret = VOP_GETATTR(vp, vap);
260 	vput(vp);
261 	vp = NULL;
262 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
263 			      NFSX_POSTOPATTR(1) + NFSX_UNSIGNED, &error));
264 	nfsm_srvpostop_attr(&info, nfsd, getret, vap);
265 	tl = nfsm_build(&info, NFSX_UNSIGNED);
266 	*tl = txdr_unsigned(nfsmode);
267 nfsmout:
268 	*mrq = info.mreq;
269 	if (vp)
270 		vput(vp);
271 	return(error);
272 }
273 
274 /*
275  * nfs getattr service
276  */
277 int
278 nfsrv_getattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
279 	      struct thread *td, struct mbuf **mrq)
280 {
281 	struct sockaddr *nam = nfsd->nd_nam;
282 	struct ucred *cred = &nfsd->nd_cr;
283 	struct nfs_fattr *fp;
284 	struct vattr va;
285 	struct vattr *vap = &va;
286 	struct vnode *vp = NULL;
287 	struct mount *mp = NULL;
288 	nfsfh_t nfh;
289 	fhandle_t *fhp;
290 	int error = 0, rdonly;
291 	struct nfsm_info info;
292 
293 	info.mrep = nfsd->nd_mrep;
294 	info.md = nfsd->nd_md;
295 	info.dpos = nfsd->nd_dpos;
296 	info.mreq = NULL;
297 
298 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
299 	fhp = &nfh.fh_generic;
300 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
301 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
302 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
303 	if (error) {
304 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error));
305 		error = 0;
306 		goto nfsmout;
307 	}
308 	error = VOP_GETATTR(vp, vap);
309 	vput(vp);
310 	vp = NULL;
311 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
312 			      NFSX_FATTR(nfsd->nd_flag & ND_NFSV3), &error));
313 	if (error) {
314 		error = 0;
315 		goto nfsmout;
316 	}
317 	fp = nfsm_build(&info, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
318 	nfsm_srvfattr(nfsd, vap, fp);
319 	/* fall through */
320 
321 nfsmout:
322 	*mrq = info.mreq;
323 	if (vp)
324 		vput(vp);
325 	return(error);
326 }
327 
328 /*
329  * nfs setattr service
330  */
331 int
332 nfsrv_setattr(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
333 	      struct thread *td, struct mbuf **mrq)
334 {
335 	struct sockaddr *nam = nfsd->nd_nam;
336 	struct ucred *cred = &nfsd->nd_cr;
337 	struct vattr va, preat;
338 	struct vattr *vap = &va;
339 	struct nfsv2_sattr *sp;
340 	struct nfs_fattr *fp;
341 	struct vnode *vp = NULL;
342 	struct mount *mp = NULL;
343 	nfsfh_t nfh;
344 	fhandle_t *fhp;
345 	u_int32_t *tl;
346 	int error = 0, rdonly, preat_ret = 1, postat_ret = 1;
347 	int gcheck = 0;
348 	struct timespec guard;
349 	struct nfsm_info info;
350 
351 	info.mrep = nfsd->nd_mrep;
352 	info.mreq = NULL;
353 	info.md = nfsd->nd_md;
354 	info.dpos = nfsd->nd_dpos;
355 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
356 
357 	guard.tv_sec = 0;	/* fix compiler warning */
358 	guard.tv_nsec = 0;
359 
360 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
361 	fhp = &nfh.fh_generic;
362 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
363 	VATTR_NULL(vap);
364 	if (info.v3) {
365 		ERROROUT(nfsm_srvsattr(&info, vap));
366 		NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
367 		gcheck = fxdr_unsigned(int, *tl);
368 		if (gcheck) {
369 			NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED));
370 			fxdr_nfsv3time(tl, &guard);
371 		}
372 	} else {
373 		NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR));
374 		/*
375 		 * Nah nah nah nah na nah
376 		 * There is a bug in the Sun client that puts 0xffff in the mode
377 		 * field of sattr when it should put in 0xffffffff. The u_short
378 		 * doesn't sign extend.
379 		 * --> check the low order 2 bytes for 0xffff
380 		 */
381 		if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
382 			vap->va_mode = nfstov_mode(sp->sa_mode);
383 		if (sp->sa_uid != nfs_xdrneg1)
384 			vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
385 		if (sp->sa_gid != nfs_xdrneg1)
386 			vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
387 		if (sp->sa_size != nfs_xdrneg1)
388 			vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
389 		if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
390 #ifdef notyet
391 			fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
392 #else
393 			vap->va_atime.tv_sec =
394 				fxdr_unsigned(int32_t, sp->sa_atime.nfsv2_sec);
395 			vap->va_atime.tv_nsec = 0;
396 #endif
397 		}
398 		if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
399 			fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
400 
401 	}
402 
403 	/*
404 	 * Now that we have all the fields, lets do it.
405 	 */
406 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam, &rdonly,
407 		(nfsd->nd_flag & ND_KERBAUTH), TRUE);
408 	if (error) {
409 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
410 				      2 * NFSX_UNSIGNED, &error));
411 		nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat,
412 				 postat_ret, vap);
413 		error = 0;
414 		goto nfsmout;
415 	}
416 
417 	/*
418 	 * vp now an active resource, pay careful attention to cleanup
419 	 */
420 
421 	if (info.v3) {
422 		error = preat_ret = VOP_GETATTR(vp, &preat);
423 		if (!error && gcheck &&
424 			(preat.va_ctime.tv_sec != guard.tv_sec ||
425 			 preat.va_ctime.tv_nsec != guard.tv_nsec))
426 			error = NFSERR_NOT_SYNC;
427 		if (error) {
428 			vput(vp);
429 			vp = NULL;
430 			NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
431 					      NFSX_WCCDATA(info.v3), &error));
432 			nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat,
433 					 postat_ret, vap);
434 			error = 0;
435 			goto nfsmout;
436 		}
437 	}
438 
439 	/*
440 	 * If the size is being changed write acces is required, otherwise
441 	 * just check for a read only file system.
442 	 */
443 	if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
444 		if (rdonly || (mp->mnt_flag & MNT_RDONLY)) {
445 			error = EROFS;
446 			goto out;
447 		}
448 	} else {
449 		if (vp->v_type == VDIR) {
450 			error = EISDIR;
451 			goto out;
452 		} else if ((error = nfsrv_access(mp, vp, VWRITE, cred, rdonly,
453 			    td, 0)) != 0){
454 			goto out;
455 		}
456 	}
457 	error = VOP_SETATTR(vp, vap, cred);
458 	postat_ret = VOP_GETATTR(vp, vap);
459 	if (!error)
460 		error = postat_ret;
461 out:
462 	vput(vp);
463 	vp = NULL;
464 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
465 		   NFSX_WCCORFATTR(info.v3), &error));
466 	if (info.v3) {
467 		nfsm_srvwcc_data(&info, nfsd, preat_ret, &preat,
468 				 postat_ret, vap);
469 		error = 0;
470 		goto nfsmout;
471 	}
472 	fp = nfsm_build(&info, NFSX_V2FATTR);
473 	nfsm_srvfattr(nfsd, vap, fp);
474 	/* fall through */
475 
476 nfsmout:
477 	*mrq = info.mreq;
478 	if (vp)
479 		vput(vp);
480 	return(error);
481 }
482 
483 /*
484  * nfs lookup rpc
485  */
486 int
487 nfsrv_lookup(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
488 	     struct thread *td, struct mbuf **mrq)
489 {
490 	struct sockaddr *nam = nfsd->nd_nam;
491 	struct ucred *cred = &nfsd->nd_cr;
492 	struct nfs_fattr *fp;
493 	struct nlookupdata nd;
494 	struct vnode *vp;
495 	struct vnode *dirp;
496 	struct nchandle nch;
497 	nfsfh_t nfh;
498 	fhandle_t *fhp;
499 	int error = 0, len, dirattr_ret = 1;
500 	int pubflag;
501 	struct vattr va, dirattr, *vap = &va;
502 	struct nfsm_info info;
503 
504 	info.mrep = nfsd->nd_mrep;
505 	info.mreq = NULL;
506 	info.md = nfsd->nd_md;
507 	info.dpos = nfsd->nd_dpos;
508 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
509 
510 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
511 	nlookup_zero(&nd);
512 	dirp = NULL;
513 	vp = NULL;
514 
515 	fhp = &nfh.fh_generic;
516 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
517 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
518 
519 	pubflag = nfs_ispublicfh(fhp);
520 
521 	error = nfs_namei(&nd, cred, 0, NULL, &vp,
522 		fhp, len, slp, nam, &info.md, &info.dpos,
523 		&dirp, td, (nfsd->nd_flag & ND_KERBAUTH), pubflag);
524 
525 	/*
526 	 * namei failure, only dirp to cleanup.  Clear out garbarge from
527 	 * structure in case macros jump to nfsmout.
528 	 */
529 
530 	if (error) {
531 		if (dirp) {
532 			if (info.v3)
533 				dirattr_ret = VOP_GETATTR(dirp, &dirattr);
534 			vrele(dirp);
535 			dirp = NULL;
536 		}
537 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
538 				      NFSX_POSTOPATTR(info.v3), &error));
539 		nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr);
540 		error = 0;
541 		goto nfsmout;
542 	}
543 
544 	/*
545 	 * Locate index file for public filehandle
546 	 *
547 	 * error is 0 on entry and 0 on exit from this block.
548 	 */
549 
550 	if (pubflag) {
551 		if (vp->v_type == VDIR && nfs_pub.np_index != NULL) {
552 			/*
553 			 * Setup call to lookup() to see if we can find
554 			 * the index file. Arguably, this doesn't belong
555 			 * in a kernel.. Ugh.  If an error occurs, do not
556 			 * try to install an index file and then clear the
557 			 * error.
558 			 *
559 			 * When we replace nd with ind and redirect ndp,
560 			 * maintenance of ni_startdir and ni_vp shift to
561 			 * ind and we have to clean them up in the old nd.
562 			 * However, the cnd resource continues to be maintained
563 			 * via the original nd.  Confused?  You aren't alone!
564 			 */
565 			vn_unlock(vp);
566 			cache_copy(&nd.nl_nch, &nch);
567 			nlookup_done(&nd);
568 			error = nlookup_init_raw(&nd, nfs_pub.np_index,
569 						UIO_SYSSPACE, 0, cred, &nch);
570 			cache_drop(&nch);
571 			if (error == 0)
572 				error = nlookup(&nd);
573 
574 			if (error == 0) {
575 				/*
576 				 * Found an index file. Get rid of
577 				 * the old references.  transfer vp and
578 				 * load up the new vp.  Fortunately we do
579 				 * not have to deal with dvp, that would be
580 				 * a huge mess.
581 				 */
582 				if (dirp)
583 					vrele(dirp);
584 				dirp = vp;
585 				vp = NULL;
586 				error = cache_vget(&nd.nl_nch, nd.nl_cred,
587 							LK_EXCLUSIVE, &vp);
588 				KKASSERT(error == 0);
589 			}
590 			error = 0;
591 		}
592 		/*
593 		 * If the public filehandle was used, check that this lookup
594 		 * didn't result in a filehandle outside the publicly exported
595 		 * filesystem.  We clear the poor vp here to avoid lockups due
596 		 * to NFS I/O.
597 		 */
598 
599 		if (vp->v_mount != nfs_pub.np_mount) {
600 			vput(vp);
601 			vp = NULL;
602 			error = EPERM;
603 		}
604 	}
605 
606 	if (dirp) {
607 		if (info.v3)
608 			dirattr_ret = VOP_GETATTR(dirp, &dirattr);
609 		vrele(dirp);
610 		dirp = NULL;
611 	}
612 
613 	/*
614 	 * Resources at this point:
615 	 *	ndp->ni_vp	may not be NULL
616 	 *
617 	 */
618 
619 	if (error) {
620 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
621 				      NFSX_POSTOPATTR(info.v3), &error));
622 		nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr);
623 		error = 0;
624 		goto nfsmout;
625 	}
626 
627 	/*
628 	 * Clear out some resources prior to potentially blocking.  This
629 	 * is not as critical as ni_dvp resources in other routines, but
630 	 * it helps.
631 	 */
632 	nlookup_done(&nd);
633 
634 	/*
635 	 * Get underlying attribute, then release remaining resources ( for
636 	 * the same potential blocking reason ) and reply.
637 	 */
638 	bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
639 	error = VFS_VPTOFH(vp, &fhp->fh_fid);
640 	if (!error)
641 		error = VOP_GETATTR(vp, vap);
642 
643 	vput(vp);
644 	vp = NULL;
645 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
646 			      NFSX_SRVFH(info.v3) +
647 			      NFSX_POSTOPORFATTR(info.v3) +
648 			      NFSX_POSTOPATTR(info.v3),
649 			      &error));
650 	if (error) {
651 		nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr);
652 		error = 0;
653 		goto nfsmout;
654 	}
655 	nfsm_srvfhtom(&info, fhp);
656 	if (info.v3) {
657 		nfsm_srvpostop_attr(&info, nfsd, 0, vap);
658 		nfsm_srvpostop_attr(&info, nfsd, dirattr_ret, &dirattr);
659 	} else {
660 		fp = nfsm_build(&info, NFSX_V2FATTR);
661 		nfsm_srvfattr(nfsd, vap, fp);
662 	}
663 
664 nfsmout:
665 	*mrq = info.mreq;
666 	if (dirp)
667 		vrele(dirp);
668 	nlookup_done(&nd);		/* may be called twice */
669 	if (vp)
670 		vput(vp);
671 	return (error);
672 }
673 
674 /*
675  * nfs readlink service
676  */
677 int
678 nfsrv_readlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
679 	       struct thread *td, struct mbuf **mrq)
680 {
681 	struct sockaddr *nam = nfsd->nd_nam;
682 	struct ucred *cred = &nfsd->nd_cr;
683 	struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
684 	struct iovec *ivp = iv;
685 	u_int32_t *tl;
686 	int error = 0, rdonly, i, tlen, len, getret;
687 	struct mbuf *mp1, *mp2, *mp3;
688 	struct vnode *vp = NULL;
689 	struct mount *mp = NULL;
690 	struct vattr attr;
691 	nfsfh_t nfh;
692 	fhandle_t *fhp;
693 	struct uio io, *uiop = &io;
694 	struct nfsm_info info;
695 
696 	info.mrep = nfsd->nd_mrep;
697 	info.mreq = NULL;
698 	info.md = nfsd->nd_md;
699 	info.dpos = nfsd->nd_dpos;
700 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
701 
702 	bzero(&io, sizeof(struct uio));
703 
704 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
705 #ifndef nolint
706 	mp2 = NULL;
707 #endif
708 	mp3 = NULL;
709 	fhp = &nfh.fh_generic;
710 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
711 	len = 0;
712 	i = 0;
713 	while (len < NFS_MAXPATHLEN) {
714 		mp1 = m_getcl(M_WAITOK, MT_DATA, 0);
715 		mp1->m_len = MCLBYTES;
716 		if (len == 0)
717 			mp3 = mp2 = mp1;
718 		else {
719 			mp2->m_next = mp1;
720 			mp2 = mp1;
721 		}
722 		if ((len + mp1->m_len) > NFS_MAXPATHLEN) {
723 			mp1->m_len = NFS_MAXPATHLEN-len;
724 			len = NFS_MAXPATHLEN;
725 		} else
726 			len += mp1->m_len;
727 		ivp->iov_base = mtod(mp1, caddr_t);
728 		ivp->iov_len = mp1->m_len;
729 		i++;
730 		ivp++;
731 	}
732 	uiop->uio_iov = iv;
733 	uiop->uio_iovcnt = i;
734 	uiop->uio_offset = 0;
735 	uiop->uio_resid = len;
736 	uiop->uio_rw = UIO_READ;
737 	uiop->uio_segflg = UIO_SYSSPACE;
738 	uiop->uio_td = NULL;
739 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
740 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
741 	if (error) {
742 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
743 				      2 * NFSX_UNSIGNED, &error));
744 		nfsm_srvpostop_attr(&info, nfsd, 1, NULL);
745 		error = 0;
746 		goto nfsmout;
747 	}
748 	if (vp->v_type != VLNK) {
749 		if (info.v3)
750 			error = EINVAL;
751 		else
752 			error = ENXIO;
753 		goto out;
754 	}
755 	error = VOP_READLINK(vp, uiop, cred);
756 out:
757 	getret = VOP_GETATTR(vp, &attr);
758 	vput(vp);
759 	vp = NULL;
760 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
761 			     NFSX_POSTOPATTR(info.v3) + NFSX_UNSIGNED,
762 			     &error));
763 	if (info.v3) {
764 		nfsm_srvpostop_attr(&info, nfsd, getret, &attr);
765 		if (error) {
766 			error = 0;
767 			goto nfsmout;
768 		}
769 	}
770 	if (uiop->uio_resid > 0) {
771 		len -= uiop->uio_resid;
772 		tlen = nfsm_rndup(len);
773 		nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
774 	}
775 	tl = nfsm_build(&info, NFSX_UNSIGNED);
776 	*tl = txdr_unsigned(len);
777 	info.mb->m_next = mp3;
778 	mp3 = NULL;
779 nfsmout:
780 	*mrq = info.mreq;
781 	if (mp3)
782 		m_freem(mp3);
783 	if (vp)
784 		vput(vp);
785 	return(error);
786 }
787 
788 /*
789  * nfs read service
790  */
791 int
792 nfsrv_read(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
793 	   struct thread *td, struct mbuf **mrq)
794 {
795 	struct nfsm_info info;
796 	struct sockaddr *nam = nfsd->nd_nam;
797 	struct ucred *cred = &nfsd->nd_cr;
798 	struct iovec *iv;
799 	struct iovec *iv2;
800 	struct mbuf *m;
801 	struct nfs_fattr *fp;
802 	u_int32_t *tl;
803 	int i;
804 	int reqlen;
805 	int error = 0, rdonly, cnt, len, left, siz, tlen, getret;
806 	struct mbuf *m2;
807 	struct vnode *vp = NULL;
808 	struct mount *mp = NULL;
809 	nfsfh_t nfh;
810 	fhandle_t *fhp;
811 	struct uio io, *uiop = &io;
812 	struct vattr va, *vap = &va;
813 	struct nfsheur *nh;
814 	off_t off;
815 	int ioflag = 0;
816 
817 	info.mrep = nfsd->nd_mrep;
818 	info.mreq = NULL;
819 	info.md = nfsd->nd_md;
820 	info.dpos = nfsd->nd_dpos;
821 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
822 
823 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
824 	fhp = &nfh.fh_generic;
825 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
826 	if (info.v3) {
827 		NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED));
828 		off = fxdr_hyper(tl);
829 	} else {
830 		NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
831 		off = (off_t)fxdr_unsigned(u_int32_t, *tl);
832 	}
833 	NEGREPLYOUT(reqlen = nfsm_srvstrsiz(&info,
834 					    NFS_SRVMAXDATA(nfsd), &error));
835 
836 	/*
837 	 * Reference vp.  If an error occurs, vp will be invalid, but we
838 	 * have to NULL it just in case.  The macros might goto nfsmout
839 	 * as well.
840 	 */
841 
842 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
843 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
844 	if (error) {
845 		vp = NULL;
846 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
847 				      2 * NFSX_UNSIGNED, &error));
848 		nfsm_srvpostop_attr(&info, nfsd, 1, NULL);
849 		error = 0;
850 		goto nfsmout;
851 	}
852 
853 	if (vp->v_type != VREG) {
854 		if (info.v3)
855 			error = EINVAL;
856 		else
857 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
858 	}
859 	if (!error) {
860 	    if ((error = nfsrv_access(mp, vp, VREAD, cred, rdonly, td, 1)) != 0)
861 		error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 1);
862 	}
863 	getret = VOP_GETATTR(vp, vap);
864 	if (!error)
865 		error = getret;
866 	if (error) {
867 		vput(vp);
868 		vp = NULL;
869 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
870 				      NFSX_POSTOPATTR(info.v3), &error));
871 		nfsm_srvpostop_attr(&info, nfsd, getret, vap);
872 		error = 0;
873 		goto nfsmout;
874 	}
875 
876 	/*
877 	 * Calculate byte count to read
878 	 */
879 
880 	if (off >= vap->va_size)
881 		cnt = 0;
882 	else if ((off + reqlen) > vap->va_size)
883 		cnt = vap->va_size - off;
884 	else
885 		cnt = reqlen;
886 
887 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
888 			      NFSX_POSTOPORFATTR(info.v3) +
889 			      3 * NFSX_UNSIGNED + nfsm_rndup(cnt),
890 			      &error));
891 	if (info.v3) {
892 		tl = nfsm_build(&info, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
893 		*tl++ = nfs_true;
894 		fp = (struct nfs_fattr *)tl;
895 		tl += (NFSX_V3FATTR / sizeof (u_int32_t));
896 	} else {
897 		tl = nfsm_build(&info, NFSX_V2FATTR + NFSX_UNSIGNED);
898 		fp = (struct nfs_fattr *)tl;
899 		tl += (NFSX_V2FATTR / sizeof (u_int32_t));
900 	}
901 	len = left = nfsm_rndup(cnt);
902 	if (cnt > 0) {
903 		/*
904 		 * Generate the mbuf list with the uio_iov ref. to it.
905 		 */
906 		i = 0;
907 		m = m2 = info.mb;
908 		while (left > 0) {
909 			siz = min(M_TRAILINGSPACE(m), left);
910 			if (siz > 0) {
911 				left -= siz;
912 				i++;
913 			}
914 			if (left > 0) {
915 				m = m_getcl(M_WAITOK, MT_DATA, 0);
916 				m->m_len = 0;
917 				m2->m_next = m;
918 				m2 = m;
919 			}
920 		}
921 		iv = kmalloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK);
922 		uiop->uio_iov = iv2 = iv;
923 		m = info.mb;
924 		left = len;
925 		i = 0;
926 		while (left > 0) {
927 			if (m == NULL)
928 				panic("nfsrv_read iov");
929 			siz = min(M_TRAILINGSPACE(m), left);
930 			if (siz > 0) {
931 				iv->iov_base = mtod(m, caddr_t) + m->m_len;
932 				iv->iov_len = siz;
933 				m->m_len += siz;
934 				left -= siz;
935 				iv++;
936 				i++;
937 			}
938 			m = m->m_next;
939 		}
940 		uiop->uio_iovcnt = i;
941 		uiop->uio_offset = off;
942 		uiop->uio_resid = len;
943 		uiop->uio_rw = UIO_READ;
944 		uiop->uio_segflg = UIO_SYSSPACE;
945 		nh = nfsrv_sequential_heuristic(uiop, vp, 0);
946 		ioflag |= nh->nh_seqcount << IO_SEQSHIFT;
947 		error = VOP_READ(vp, uiop, IO_NODELOCKED | ioflag, cred);
948 		if (error == 0) {
949 			off = uiop->uio_offset;
950 			nh->nh_nextoff = off;
951 		}
952 		kfree((caddr_t)iv2, M_TEMP);
953 		if (error || (getret = VOP_GETATTR(vp, vap))) {
954 			if (!error)
955 				error = getret;
956 			m_freem(info.mreq);
957 			info.mreq = NULL;
958 			vput(vp);
959 			vp = NULL;
960 			NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
961 					      NFSX_POSTOPATTR(info.v3),
962 					      &error));
963 			nfsm_srvpostop_attr(&info, nfsd, getret, vap);
964 			error = 0;
965 			goto nfsmout;
966 		}
967 	} else {
968 		uiop->uio_resid = 0;
969 	}
970 	vput(vp);
971 	vp = NULL;
972 	nfsm_srvfattr(nfsd, vap, fp);
973 	tlen = len - uiop->uio_resid;
974 	cnt = cnt < tlen ? cnt : tlen;
975 	tlen = nfsm_rndup(cnt);
976 	if (len != tlen || tlen != cnt)
977 		nfsm_adj(info.mb, len - tlen, tlen - cnt);
978 	if (info.v3) {
979 		*tl++ = txdr_unsigned(cnt);
980 		if (cnt < reqlen)
981 			*tl++ = nfs_true;
982 		else
983 			*tl++ = nfs_false;
984 	}
985 	*tl = txdr_unsigned(cnt);
986 nfsmout:
987 	*mrq = info.mreq;
988 	if (vp)
989 		vput(vp);
990 	return(error);
991 }
992 
993 /*
994  * nfs write service
995  */
996 int
997 nfsrv_write(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
998 	    struct thread *td, struct mbuf **mrq)
999 {
1000 	struct sockaddr *nam = nfsd->nd_nam;
1001 	struct ucred *cred = &nfsd->nd_cr;
1002 	struct iovec *ivp;
1003 	int i, cnt;
1004 	struct mbuf *mp1;
1005 	struct nfs_fattr *fp;
1006 	struct iovec *iv;
1007 	struct vattr va, forat;
1008 	struct vattr *vap = &va;
1009 	u_int32_t *tl;
1010 	int error = 0, rdonly, len, forat_ret = 1;
1011 	int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
1012 	int stable = NFSV3WRITE_FILESYNC;
1013 	struct vnode *vp = NULL;
1014 	struct mount *mp = NULL;
1015 	struct nfsheur *nh;
1016 	nfsfh_t nfh;
1017 	fhandle_t *fhp;
1018 	struct uio io, *uiop = &io;
1019 	struct nfsm_info info;
1020 	off_t off;
1021 
1022 	info.mrep = nfsd->nd_mrep;
1023 	info.mreq = NULL;
1024 	info.md = nfsd->nd_md;
1025 	info.dpos = nfsd->nd_dpos;
1026 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
1027 
1028 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
1029 	if (info.mrep == NULL) {
1030 		error = 0;
1031 		goto nfsmout;
1032 	}
1033 	fhp = &nfh.fh_generic;
1034 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
1035 	if (info.v3) {
1036 		NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED));
1037 		off = fxdr_hyper(tl);
1038 		tl += 3;
1039 		stable = fxdr_unsigned(int, *tl++);
1040 	} else {
1041 		NULLOUT(tl = nfsm_dissect(&info, 4 * NFSX_UNSIGNED));
1042 		off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1043 		tl += 2;
1044 		if (nfs_async)
1045 	    		stable = NFSV3WRITE_UNSTABLE;
1046 	}
1047 	retlen = len = fxdr_unsigned(int32_t, *tl);
1048 	cnt = i = 0;
1049 
1050 	/*
1051 	 * For NFS Version 2, it is not obvious what a write of zero length
1052 	 * should do, but I might as well be consistent with Version 3,
1053 	 * which is to return ok so long as there are no permission problems.
1054 	 */
1055 	if (len > 0) {
1056 	    zeroing = 1;
1057 	    mp1 = info.mrep;
1058 	    while (mp1) {
1059 		if (mp1 == info.md) {
1060 			zeroing = 0;
1061 			adjust = info.dpos - mtod(mp1, caddr_t);
1062 			mp1->m_len -= adjust;
1063 			if (mp1->m_len > 0 && adjust > 0)
1064 				mp1->m_data += adjust;
1065 		}
1066 		if (zeroing)
1067 			mp1->m_len = 0;
1068 		else if (mp1->m_len > 0) {
1069 			i += mp1->m_len;
1070 			if (i > len) {
1071 				mp1->m_len -= (i - len);
1072 				zeroing	= 1;
1073 			}
1074 			if (mp1->m_len > 0)
1075 				cnt++;
1076 		}
1077 		mp1 = mp1->m_next;
1078 	    }
1079 	}
1080 	if (len > NFS_MAXDATA || len < 0 || i < len) {
1081 		error = EIO;
1082 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1083 				      2 * NFSX_UNSIGNED, &error));
1084 		nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1085 				 aftat_ret, vap);
1086 		error = 0;
1087 		goto nfsmout;
1088 	}
1089 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
1090 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
1091 	if (error) {
1092 		vp = NULL;
1093 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1094 				      2 * NFSX_UNSIGNED, &error));
1095 		nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1096 				 aftat_ret, vap);
1097 		error = 0;
1098 		goto nfsmout;
1099 	}
1100 	if (info.v3)
1101 		forat_ret = VOP_GETATTR(vp, &forat);
1102 	if (vp->v_type != VREG) {
1103 		if (info.v3)
1104 			error = EINVAL;
1105 		else
1106 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1107 	}
1108 	if (!error) {
1109 		error = nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 1);
1110 	}
1111 	if (error) {
1112 		vput(vp);
1113 		vp = NULL;
1114 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1115 				      NFSX_WCCDATA(info.v3), &error));
1116 		nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1117 				 aftat_ret, vap);
1118 		error = 0;
1119 		goto nfsmout;
1120 	}
1121 
1122 	if (len > 0) {
1123 	    ivp = kmalloc(cnt * sizeof(struct iovec), M_TEMP, M_WAITOK);
1124 	    uiop->uio_iov = iv = ivp;
1125 	    uiop->uio_iovcnt = cnt;
1126 	    mp1 = info.mrep;
1127 	    while (mp1) {
1128 		if (mp1->m_len > 0) {
1129 			ivp->iov_base = mtod(mp1, caddr_t);
1130 			ivp->iov_len = mp1->m_len;
1131 			ivp++;
1132 		}
1133 		mp1 = mp1->m_next;
1134 	    }
1135 
1136 	    /*
1137 	     * XXX
1138 	     * The IO_METASYNC flag indicates that all metadata (and not just
1139 	     * enough to ensure data integrity) mus be written to stable storage
1140 	     * synchronously.
1141 	     * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
1142 	     */
1143 	    if (stable == NFSV3WRITE_UNSTABLE)
1144 		ioflags = IO_NODELOCKED;
1145 	    else if (stable == NFSV3WRITE_DATASYNC)
1146 		ioflags = (IO_SYNC | IO_NODELOCKED);
1147 	    else
1148 		ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1149 	    uiop->uio_resid = len;
1150 	    uiop->uio_rw = UIO_WRITE;
1151 	    uiop->uio_segflg = UIO_SYSSPACE;
1152 	    uiop->uio_td = NULL;
1153 	    uiop->uio_offset = off;
1154 	    nh = nfsrv_sequential_heuristic(uiop, vp, 1);
1155 	    ioflags |= nh->nh_seqcount << IO_SEQSHIFT;
1156 	    error = VOP_WRITE(vp, uiop, ioflags, cred);
1157 	    if (error == 0)
1158 		nh->nh_nextoff = uiop->uio_offset;
1159 	    nfsstats.srvvop_writes++;
1160 	    kfree((caddr_t)iv, M_TEMP);
1161 	}
1162 	aftat_ret = VOP_GETATTR(vp, vap);
1163 	vput(vp);
1164 	vp = NULL;
1165 	if (!error)
1166 		error = aftat_ret;
1167 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1168 			      NFSX_PREOPATTR(info.v3) +
1169 			      NFSX_POSTOPORFATTR(info.v3) +
1170 			      2 * NFSX_UNSIGNED + NFSX_WRITEVERF(info.v3),
1171 			      &error));
1172 	if (info.v3) {
1173 		nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1174 				 aftat_ret, vap);
1175 		if (error) {
1176 			error = 0;
1177 			goto nfsmout;
1178 		}
1179 		tl = nfsm_build(&info, 4 * NFSX_UNSIGNED);
1180 		*tl++ = txdr_unsigned(retlen);
1181 		/*
1182 		 * If nfs_async is set, then pretend the write was FILESYNC.
1183 		 */
1184 		if (stable == NFSV3WRITE_UNSTABLE && !nfs_async)
1185 			*tl++ = txdr_unsigned(stable);
1186 		else
1187 			*tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
1188 		/*
1189 		 * Actually, there is no need to txdr these fields,
1190 		 * but it may make the values more human readable,
1191 		 * for debugging purposes.
1192 		 */
1193 		if (nfsver.tv_sec == 0)
1194 			nfsver = boottime;
1195 		*tl++ = txdr_unsigned(nfsver.tv_sec);
1196 		*tl = txdr_unsigned(nfsver.tv_nsec / 1000);
1197 	} else {
1198 		fp = nfsm_build(&info, NFSX_V2FATTR);
1199 		nfsm_srvfattr(nfsd, vap, fp);
1200 	}
1201 nfsmout:
1202 	*mrq = info.mreq;
1203 	if (vp)
1204 		vput(vp);
1205 	return(error);
1206 }
1207 
1208 /*
1209  * NFS write service with write gathering support. Called when
1210  * nfsrvw_procrastinate > 0.
1211  * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
1212  * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
1213  * Jan. 1994.
1214  */
1215 int
1216 nfsrv_writegather(struct nfsrv_descript **ndp, struct nfssvc_sock *slp,
1217 		  struct thread *td, struct mbuf **mrq)
1218 {
1219 	struct iovec *ivp;
1220 	struct nfsrv_descript *wp, *nfsd, *owp, *swp;
1221 	struct nfs_fattr *fp;
1222 	int i;
1223 	struct iovec *iov;
1224 	struct nfsrvw_delayhash *wpp;
1225 	struct ucred *cred;
1226 	struct vattr va, forat;
1227 	u_int32_t *tl;
1228 	int error = 0, rdonly, len, forat_ret = 1;
1229 	int ioflags, aftat_ret = 1, adjust, zeroing;
1230 	struct mbuf *mp1;
1231 	struct vnode *vp = NULL;
1232 	struct mount *mp = NULL;
1233 	struct uio io, *uiop = &io;
1234 	u_quad_t cur_usec;
1235 	struct nfsm_info info;
1236 
1237 	info.mreq = NULL;
1238 
1239 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
1240 #ifndef nolint
1241 	i = 0;
1242 	len = 0;
1243 #endif
1244 	if (*ndp) {
1245 	    nfsd = *ndp;
1246 	    *ndp = NULL;
1247 	    info.mrep = nfsd->nd_mrep;
1248 	    info.mreq = NULL;
1249 	    info.md = nfsd->nd_md;
1250 	    info.dpos = nfsd->nd_dpos;
1251 	    info.v3 = (nfsd->nd_flag & ND_NFSV3);
1252 	    cred = &nfsd->nd_cr;
1253 	    LIST_INIT(&nfsd->nd_coalesce);
1254 	    nfsd->nd_mreq = NULL;
1255 	    nfsd->nd_stable = NFSV3WRITE_FILESYNC;
1256 	    cur_usec = nfs_curusec();
1257 	    nfsd->nd_time = cur_usec +
1258 		(info.v3 ? nfsrvw_procrastinate_v3 : nfsrvw_procrastinate);
1259 
1260 	    /*
1261 	     * Now, get the write header..
1262 	     */
1263 	    NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, &nfsd->nd_fh, &error));
1264 	    if (info.v3) {
1265 		NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED));
1266 		nfsd->nd_off = fxdr_hyper(tl);
1267 		tl += 3;
1268 		nfsd->nd_stable = fxdr_unsigned(int, *tl++);
1269 	    } else {
1270 		NULLOUT(tl = nfsm_dissect(&info, 4 * NFSX_UNSIGNED));
1271 		nfsd->nd_off = (off_t)fxdr_unsigned(u_int32_t, *++tl);
1272 		tl += 2;
1273 		if (nfs_async)
1274 			nfsd->nd_stable = NFSV3WRITE_UNSTABLE;
1275 	    }
1276 	    len = fxdr_unsigned(int32_t, *tl);
1277 	    nfsd->nd_len = len;
1278 	    nfsd->nd_eoff = nfsd->nd_off + len;
1279 
1280 	    /*
1281 	     * Trim the header out of the mbuf list and trim off any trailing
1282 	     * junk so that the mbuf list has only the write data.
1283 	     */
1284 	    zeroing = 1;
1285 	    i = 0;
1286 	    mp1 = info.mrep;
1287 	    while (mp1) {
1288 		if (mp1 == info.md) {
1289 		    zeroing = 0;
1290 		    adjust = info.dpos - mtod(mp1, caddr_t);
1291 		    mp1->m_len -= adjust;
1292 		    if (mp1->m_len > 0 && adjust > 0)
1293 			mp1->m_data += adjust;
1294 		}
1295 		if (zeroing)
1296 		    mp1->m_len = 0;
1297 		else {
1298 		    i += mp1->m_len;
1299 		    if (i > len) {
1300 			mp1->m_len -= (i - len);
1301 			zeroing = 1;
1302 		    }
1303 		}
1304 		mp1 = mp1->m_next;
1305 	    }
1306 	    if (len > NFS_MAXDATA || len < 0  || i < len) {
1307 nfsmout:
1308 		m_freem(info.mrep);
1309 		info.mrep = NULL;
1310 		error = EIO;
1311 		nfsm_writereply(&info, nfsd, slp, error, 2 * NFSX_UNSIGNED);
1312 		if (info.v3) {
1313 		    nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1314 				     aftat_ret, &va);
1315 		}
1316 		nfsd->nd_mreq = info.mreq;
1317 		nfsd->nd_mrep = NULL;
1318 		nfsd->nd_time = 0;
1319 	    }
1320 
1321 	    /*
1322 	     * Add this entry to the hash and time queues.
1323 	     */
1324 	    owp = NULL;
1325 	    wp = slp->ns_tq.lh_first;
1326 	    while (wp && wp->nd_time < nfsd->nd_time) {
1327 		owp = wp;
1328 		wp = wp->nd_tq.le_next;
1329 	    }
1330 	    NFS_DPF(WG, ("Q%03x", nfsd->nd_retxid & 0xfff));
1331 	    if (owp) {
1332 		LIST_INSERT_AFTER(owp, nfsd, nd_tq);
1333 	    } else {
1334 		LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1335 	    }
1336 	    if (nfsd->nd_mrep) {
1337 		wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
1338 		owp = NULL;
1339 		wp = wpp->lh_first;
1340 		while (wp &&
1341 		    bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1342 		    owp = wp;
1343 		    wp = wp->nd_hash.le_next;
1344 		}
1345 		while (wp && wp->nd_off < nfsd->nd_off &&
1346 		    !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
1347 		    owp = wp;
1348 		    wp = wp->nd_hash.le_next;
1349 		}
1350 		if (owp) {
1351 		    LIST_INSERT_AFTER(owp, nfsd, nd_hash);
1352 
1353 		    /*
1354 		     * Search the hash list for overlapping entries and
1355 		     * coalesce.
1356 		     */
1357 		    for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
1358 			wp = nfsd->nd_hash.le_next;
1359 			if (NFSW_SAMECRED(owp, nfsd))
1360 			    nfsrvw_coalesce(owp, nfsd);
1361 		    }
1362 		} else {
1363 		    LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
1364 		}
1365 	    }
1366 	}
1367 
1368 	/*
1369 	 * Now, do VOP_WRITE()s for any one(s) that need to be done now
1370 	 * and generate the associated reply mbuf list(s).
1371 	 */
1372 loop1:
1373 	cur_usec = nfs_curusec();
1374 	for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1375 		owp = nfsd->nd_tq.le_next;
1376 		if (nfsd->nd_time > cur_usec)
1377 		    break;
1378 		if (nfsd->nd_mreq)
1379 		    continue;
1380 		NFS_DPF(WG, ("P%03x", nfsd->nd_retxid & 0xfff));
1381 		LIST_REMOVE(nfsd, nd_tq);
1382 		LIST_REMOVE(nfsd, nd_hash);
1383 		info.mrep = nfsd->nd_mrep;
1384 		info.mreq = NULL;
1385 		info.v3 = (nfsd->nd_flag & ND_NFSV3);
1386 		nfsd->nd_mrep = NULL;
1387 		cred = &nfsd->nd_cr;
1388 		forat_ret = aftat_ret = 1;
1389 		error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &mp, &vp, cred, slp,
1390 				     nfsd->nd_nam, &rdonly,
1391 				     (nfsd->nd_flag & ND_KERBAUTH), TRUE);
1392 		if (!error) {
1393 		    if (info.v3)
1394 			forat_ret = VOP_GETATTR(vp, &forat);
1395 		    if (vp->v_type != VREG) {
1396 			if (info.v3)
1397 			    error = EINVAL;
1398 			else
1399 			    error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1400 		    }
1401 		} else {
1402 		    vp = NULL;
1403 		}
1404 		if (!error) {
1405 		    error = nfsrv_access(mp, vp, VWRITE, cred, rdonly, td, 1);
1406 		}
1407 
1408 		if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1409 		    ioflags = IO_NODELOCKED;
1410 		else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1411 		    ioflags = (IO_SYNC | IO_NODELOCKED);
1412 		else
1413 		    ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1414 		uiop->uio_rw = UIO_WRITE;
1415 		uiop->uio_segflg = UIO_SYSSPACE;
1416 		uiop->uio_td = NULL;
1417 		uiop->uio_offset = nfsd->nd_off;
1418 		uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1419 		if (uiop->uio_resid > 0) {
1420 		    mp1 = info.mrep;
1421 		    i = 0;
1422 		    while (mp1) {
1423 			if (mp1->m_len > 0)
1424 			    i++;
1425 			mp1 = mp1->m_next;
1426 		    }
1427 		    uiop->uio_iovcnt = i;
1428 		    iov = kmalloc(i * sizeof(struct iovec), M_TEMP, M_WAITOK);
1429 		    uiop->uio_iov = ivp = iov;
1430 		    mp1 = info.mrep;
1431 		    while (mp1) {
1432 			if (mp1->m_len > 0) {
1433 			    ivp->iov_base = mtod(mp1, caddr_t);
1434 			    ivp->iov_len = mp1->m_len;
1435 			    ivp++;
1436 			}
1437 			mp1 = mp1->m_next;
1438 		    }
1439 		    if (!error) {
1440 			error = VOP_WRITE(vp, uiop, ioflags, cred);
1441 			nfsstats.srvvop_writes++;
1442 		    }
1443 		    kfree((caddr_t)iov, M_TEMP);
1444 		}
1445 		m_freem(info.mrep);
1446 		info.mrep = NULL;
1447 		if (vp) {
1448 		    aftat_ret = VOP_GETATTR(vp, &va);
1449 		    vput(vp);
1450 		    vp = NULL;
1451 		}
1452 
1453 		/*
1454 		 * Loop around generating replies for all write rpcs that have
1455 		 * now been completed.
1456 		 */
1457 		swp = nfsd;
1458 		do {
1459 		    NFS_DPF(WG, ("R%03x", nfsd->nd_retxid & 0xfff));
1460 		    if (error) {
1461 			nfsm_writereply(&info, nfsd, slp, error,
1462 					NFSX_WCCDATA(info.v3));
1463 			if (info.v3) {
1464 			    nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1465 					     aftat_ret, &va);
1466 			}
1467 		    } else {
1468 			nfsm_writereply(&info, nfsd, slp, error,
1469 					NFSX_PREOPATTR(info.v3) +
1470 					NFSX_POSTOPORFATTR(info.v3) +
1471 					2 * NFSX_UNSIGNED +
1472 					NFSX_WRITEVERF(info.v3));
1473 			if (info.v3) {
1474 			    nfsm_srvwcc_data(&info, nfsd, forat_ret, &forat,
1475 					     aftat_ret, &va);
1476 			    tl = nfsm_build(&info, 4 * NFSX_UNSIGNED);
1477 			    *tl++ = txdr_unsigned(nfsd->nd_len);
1478 			    *tl++ = txdr_unsigned(swp->nd_stable);
1479 			    /*
1480 			     * Actually, there is no need to txdr these fields,
1481 			     * but it may make the values more human readable,
1482 			     * for debugging purposes.
1483 			     */
1484 			    if (nfsver.tv_sec == 0)
1485 				    nfsver = boottime;
1486 			    *tl++ = txdr_unsigned(nfsver.tv_sec);
1487 			    *tl = txdr_unsigned(nfsver.tv_nsec / 1000);
1488 			} else {
1489 			    fp = nfsm_build(&info, NFSX_V2FATTR);
1490 			    nfsm_srvfattr(nfsd, &va, fp);
1491 			}
1492 		    }
1493 		    nfsd->nd_mreq = info.mreq;
1494 		    if (nfsd->nd_mrep)
1495 			panic("nfsrv_write: nd_mrep not free");
1496 
1497 		    /*
1498 		     * Done. Put it at the head of the timer queue so that
1499 		     * the final phase can return the reply.
1500 		     */
1501 		    if (nfsd != swp) {
1502 			nfsd->nd_time = 0;
1503 			LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1504 		    }
1505 		    nfsd = swp->nd_coalesce.lh_first;
1506 		    if (nfsd) {
1507 			LIST_REMOVE(nfsd, nd_tq);
1508 		    }
1509 		} while (nfsd);
1510 		swp->nd_time = 0;
1511 		LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1512 		goto loop1;
1513 	}
1514 
1515 	/*
1516 	 * Search for a reply to return.
1517 	 */
1518 	for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next) {
1519 		if (nfsd->nd_mreq) {
1520 		    NFS_DPF(WG, ("X%03x", nfsd->nd_retxid & 0xfff));
1521 		    LIST_REMOVE(nfsd, nd_tq);
1522 		    break;
1523 		}
1524 	}
1525 	if (nfsd) {
1526 		*ndp = nfsd;
1527 		*mrq = nfsd->nd_mreq;
1528 	} else {
1529 		*ndp = NULL;
1530 		*mrq = NULL;
1531 	}
1532 	return (0);
1533 }
1534 
1535 /*
1536  * Coalesce the write request nfsd into owp. To do this we must:
1537  * - remove nfsd from the queues
1538  * - merge nfsd->nd_mrep into owp->nd_mrep
1539  * - update the nd_eoff and nd_stable for owp
1540  * - put nfsd on owp's nd_coalesce list
1541  * NB: Must be called at splsoftclock().
1542  */
1543 static void
1544 nfsrvw_coalesce(struct nfsrv_descript *owp, struct nfsrv_descript *nfsd)
1545 {
1546         int overlap;
1547         struct mbuf *mp1;
1548 	struct nfsrv_descript *p;
1549 
1550 	NFS_DPF(WG, ("C%03x-%03x",
1551 		     nfsd->nd_retxid & 0xfff, owp->nd_retxid & 0xfff));
1552         LIST_REMOVE(nfsd, nd_hash);
1553         LIST_REMOVE(nfsd, nd_tq);
1554         if (owp->nd_eoff < nfsd->nd_eoff) {
1555             overlap = owp->nd_eoff - nfsd->nd_off;
1556             if (overlap < 0)
1557                 panic("nfsrv_coalesce: bad off");
1558             if (overlap > 0)
1559                 m_adj(nfsd->nd_mrep, overlap);
1560             mp1 = owp->nd_mrep;
1561             while (mp1->m_next)
1562                 mp1 = mp1->m_next;
1563             mp1->m_next = nfsd->nd_mrep;
1564             owp->nd_eoff = nfsd->nd_eoff;
1565         } else
1566             m_freem(nfsd->nd_mrep);
1567         nfsd->nd_mrep = NULL;
1568         if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1569             owp->nd_stable = NFSV3WRITE_FILESYNC;
1570         else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1571             owp->nd_stable == NFSV3WRITE_UNSTABLE)
1572             owp->nd_stable = NFSV3WRITE_DATASYNC;
1573         LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1574 
1575 	/*
1576 	 * If nfsd had anything else coalesced into it, transfer them
1577 	 * to owp, otherwise their replies will never get sent.
1578 	 */
1579 	for (p = nfsd->nd_coalesce.lh_first; p;
1580 	     p = nfsd->nd_coalesce.lh_first) {
1581 	    LIST_REMOVE(p, nd_tq);
1582 	    LIST_INSERT_HEAD(&owp->nd_coalesce, p, nd_tq);
1583 	}
1584 }
1585 
1586 /*
1587  * nfs create service
1588  * now does a truncate to 0 length via. setattr if it already exists
1589  */
1590 int
1591 nfsrv_create(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1592 	     struct thread *td, struct mbuf **mrq)
1593 {
1594 	struct sockaddr *nam = nfsd->nd_nam;
1595 	struct ucred *cred = &nfsd->nd_cr;
1596 	struct nfs_fattr *fp;
1597 	struct vattr va, dirfor, diraft;
1598 	struct vattr *vap = &va;
1599 	struct nfsv2_sattr *sp;
1600 	u_int32_t *tl;
1601 	struct nlookupdata nd;
1602 	int error = 0, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1603 	dev_t rdev = NOUDEV;
1604 	caddr_t cp;
1605 	int how, exclusive_flag = 0;
1606 	struct vnode *dirp;
1607 	struct vnode *dvp;
1608 	struct vnode *vp;
1609 	struct mount *mp = NULL;
1610 	nfsfh_t nfh;
1611 	fhandle_t *fhp;
1612 	u_quad_t tempsize;
1613 	u_char cverf[NFSX_V3CREATEVERF];
1614 	struct nfsm_info info;
1615 
1616 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
1617 	nlookup_zero(&nd);
1618 	dirp = NULL;
1619 	dvp = NULL;
1620 	vp = NULL;
1621 
1622 	info.mrep = nfsd->nd_mrep;
1623 	info.mreq = NULL;
1624 	info.md = nfsd->nd_md;
1625 	info.dpos = nfsd->nd_dpos;
1626 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
1627 
1628 	fhp = &nfh.fh_generic;
1629 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
1630 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
1631 
1632 	/*
1633 	 * Call namei and do initial cleanup to get a few things
1634 	 * out of the way.  If we get an initial error we cleanup
1635 	 * and return here to avoid special-casing the invalid nd
1636 	 * structure through the rest of the case.  dirp may be
1637 	 * set even if an error occurs, but the nd structure will not
1638 	 * be valid at all if an error occurs so we have to invalidate it
1639 	 * prior to calling nfsm_reply ( which might goto nfsmout ).
1640 	 */
1641 	error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
1642 			  fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
1643 			  td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1644 	mp = vfs_getvfs(&fhp->fh_fsid);
1645 
1646 	if (dirp) {
1647 		if (info.v3) {
1648 			dirfor_ret = VOP_GETATTR(dirp, &dirfor);
1649 		} else {
1650 			vrele(dirp);
1651 			dirp = NULL;
1652 		}
1653 	}
1654 	if (error) {
1655 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1656 				      NFSX_WCCDATA(info.v3), &error));
1657 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
1658 				 diraft_ret, &diraft);
1659 		error = 0;
1660 		goto nfsmout;
1661 	}
1662 
1663 	/*
1664 	 * No error.  Continue.  State:
1665 	 *
1666 	 *	dirp 		may be valid
1667 	 *	vp		may be valid or NULL if the target does not
1668 	 *			exist.
1669 	 *	dvp		is valid
1670 	 *
1671 	 * The error state is set through the code and we may also do some
1672 	 * opportunistic releasing of vnodes to avoid holding locks through
1673 	 * NFS I/O.  The cleanup at the end is a catch-all
1674 	 */
1675 
1676 	VATTR_NULL(vap);
1677 	if (info.v3) {
1678 		NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
1679 		how = fxdr_unsigned(int, *tl);
1680 		switch (how) {
1681 		case NFSV3CREATE_GUARDED:
1682 			if (vp) {
1683 				error = EEXIST;
1684 				break;
1685 			}
1686 			/* fall through */
1687 		case NFSV3CREATE_UNCHECKED:
1688 			ERROROUT(nfsm_srvsattr(&info, vap));
1689 			break;
1690 		case NFSV3CREATE_EXCLUSIVE:
1691 			NULLOUT(cp = nfsm_dissect(&info, NFSX_V3CREATEVERF));
1692 			bcopy(cp, cverf, NFSX_V3CREATEVERF);
1693 			exclusive_flag = 1;
1694 			break;
1695 		}
1696 		vap->va_type = VREG;
1697 	} else {
1698 		NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR));
1699 		vap->va_type = IFTOVT(fxdr_unsigned(u_int32_t, sp->sa_mode));
1700 		if (vap->va_type == VNON)
1701 			vap->va_type = VREG;
1702 		vap->va_mode = nfstov_mode(sp->sa_mode);
1703 		switch (vap->va_type) {
1704 		case VREG:
1705 			tsize = fxdr_unsigned(int32_t, sp->sa_size);
1706 			if (tsize != -1)
1707 				vap->va_size = (u_quad_t)tsize;
1708 			break;
1709 		case VCHR:
1710 		case VBLK:
1711 		case VFIFO:
1712 			rdev = fxdr_unsigned(long, sp->sa_size);
1713 			break;
1714 		default:
1715 			break;
1716 		}
1717 	}
1718 
1719 	/*
1720 	 * Iff doesn't exist, create it
1721 	 * otherwise just truncate to 0 length
1722 	 *   should I set the mode too ?
1723 	 *
1724 	 * The only possible error we can have at this point is EEXIST.
1725 	 * nd.ni_vp will also be non-NULL in that case.
1726 	 */
1727 	if (vp == NULL) {
1728 		if (vap->va_mode == (mode_t)VNOVAL)
1729 			vap->va_mode = 0;
1730 		if (vap->va_type == VREG || vap->va_type == VSOCK) {
1731 			vn_unlock(dvp);
1732 			error = VOP_NCREATE(&nd.nl_nch, dvp, &vp,
1733 					    nd.nl_cred, vap);
1734 			vrele(dvp);
1735 			dvp = NULL;
1736 			if (error == 0) {
1737 				if (exclusive_flag) {
1738 					exclusive_flag = 0;
1739 					VATTR_NULL(vap);
1740 					bcopy(cverf, (caddr_t)&vap->va_atime,
1741 						NFSX_V3CREATEVERF);
1742 					error = VOP_SETATTR(vp, vap, cred);
1743 				}
1744 			}
1745 		} else if (
1746 			vap->va_type == VCHR ||
1747 			vap->va_type == VBLK ||
1748 			vap->va_type == VFIFO
1749 		) {
1750 			/*
1751 			 * Handle SysV FIFO node special cases.  All other
1752 			 * devices require super user to access.
1753 			 */
1754 			if (vap->va_type == VCHR && rdev == 0xffffffff)
1755 				vap->va_type = VFIFO;
1756                         if (vap->va_type != VFIFO &&
1757                             (error = priv_check_cred(cred, PRIV_ROOT, 0))) {
1758 				goto nfsmreply0;
1759                         }
1760 			vap->va_rmajor = umajor(rdev);
1761 			vap->va_rminor = uminor(rdev);
1762 
1763 			vn_unlock(dvp);
1764 			error = VOP_NMKNOD(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap);
1765 			vrele(dvp);
1766 			dvp = NULL;
1767 			if (error)
1768 				goto nfsmreply0;
1769 #if 0
1770 			/*
1771 			 * XXX what is this junk supposed to do ?
1772 			 */
1773 
1774 			vput(vp);
1775 			vp = NULL;
1776 
1777 			/*
1778 			 * release dvp prior to lookup
1779 			 */
1780 			vput(dvp);
1781 			dvp = NULL;
1782 
1783 			/*
1784 			 * Setup for lookup.
1785 			 *
1786 			 * Even though LOCKPARENT was cleared, ni_dvp may
1787 			 * be garbage.
1788 			 */
1789 			nd.ni_cnd.cn_nameiop = NAMEI_LOOKUP;
1790 			nd.ni_cnd.cn_flags &= ~(CNP_LOCKPARENT);
1791 			nd.ni_cnd.cn_td = td;
1792 			nd.ni_cnd.cn_cred = cred;
1793 
1794 			error = lookup(&nd);
1795 			nd.ni_dvp = NULL;
1796 
1797 			if (error != 0) {
1798 				NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1799 						      0, &error));
1800 				/* fall through on certain errors */
1801 			}
1802 			nfsrv_object_create(nd.ni_vp);
1803 			if (nd.ni_cnd.cn_flags & CNP_ISSYMLINK) {
1804 				error = EINVAL;
1805 				goto nfsmreply0;
1806 			}
1807 #endif
1808 		} else {
1809 			error = ENXIO;
1810 		}
1811 	} else {
1812 		if (vap->va_size != -1) {
1813 			error = nfsrv_access(mp, vp, VWRITE, cred,
1814 			    (nd.nl_flags & NLC_NFS_RDONLY), td, 0);
1815 			if (!error) {
1816 				tempsize = vap->va_size;
1817 				VATTR_NULL(vap);
1818 				vap->va_size = tempsize;
1819 				error = VOP_SETATTR(vp, vap, cred);
1820 			}
1821 		}
1822 	}
1823 
1824 	if (!error) {
1825 		bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
1826 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
1827 		if (!error)
1828 			error = VOP_GETATTR(vp, vap);
1829 	}
1830 	if (info.v3) {
1831 		if (exclusive_flag && !error &&
1832 			bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
1833 			error = EEXIST;
1834 		diraft_ret = VOP_GETATTR(dirp, &diraft);
1835 		vrele(dirp);
1836 		dirp = NULL;
1837 	}
1838 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1839 			      NFSX_SRVFH(info.v3) + NFSX_FATTR(info.v3) +
1840 			      NFSX_WCCDATA(info.v3),
1841 			      &error));
1842 	if (info.v3) {
1843 		if (!error) {
1844 			nfsm_srvpostop_fh(&info, fhp);
1845 			nfsm_srvpostop_attr(&info, nfsd, 0, vap);
1846 		}
1847 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
1848 				 diraft_ret, &diraft);
1849 		error = 0;
1850 	} else {
1851 		nfsm_srvfhtom(&info, fhp);
1852 		fp = nfsm_build(&info, NFSX_V2FATTR);
1853 		nfsm_srvfattr(nfsd, vap, fp);
1854 	}
1855 	goto nfsmout;
1856 
1857 nfsmreply0:
1858 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error));
1859 	error = 0;
1860 	/* fall through */
1861 
1862 nfsmout:
1863 	*mrq = info.mreq;
1864 	if (dirp)
1865 		vrele(dirp);
1866 	nlookup_done(&nd);
1867 	if (dvp) {
1868 		if (dvp == vp)
1869 			vrele(dvp);
1870 		else
1871 			vput(dvp);
1872 	}
1873 	if (vp)
1874 		vput(vp);
1875 	if (mp)
1876 		mount_drop(mp);
1877 	return (error);
1878 }
1879 
1880 /*
1881  * nfs v3 mknod service
1882  */
1883 int
1884 nfsrv_mknod(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
1885 	    struct thread *td, struct mbuf **mrq)
1886 {
1887 	struct sockaddr *nam = nfsd->nd_nam;
1888 	struct ucred *cred = &nfsd->nd_cr;
1889 	struct vattr va, dirfor, diraft;
1890 	struct vattr *vap = &va;
1891 	u_int32_t *tl;
1892 	struct nlookupdata nd;
1893 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
1894 	enum vtype vtyp;
1895 	struct vnode *dirp;
1896 	struct vnode *dvp;
1897 	struct vnode *vp;
1898 	nfsfh_t nfh;
1899 	fhandle_t *fhp;
1900 	struct nfsm_info info;
1901 
1902 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
1903 	nlookup_zero(&nd);
1904 	dirp = NULL;
1905 	dvp = NULL;
1906 	vp = NULL;
1907 
1908 	info.mrep = nfsd->nd_mrep;
1909 	info.mreq = NULL;
1910 	info.md = nfsd->nd_md;
1911 	info.dpos = nfsd->nd_dpos;
1912 
1913 	fhp = &nfh.fh_generic;
1914 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
1915 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
1916 
1917 	/*
1918 	 * Handle nfs_namei() call.  If an error occurs, the nd structure
1919 	 * is not valid.  However, nfsm_*() routines may still jump to
1920 	 * nfsmout.
1921 	 */
1922 
1923 	error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
1924 			  fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
1925 			  td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
1926 	if (dirp)
1927 		dirfor_ret = VOP_GETATTR(dirp, &dirfor);
1928 	if (error) {
1929 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
1930 			   NFSX_WCCDATA(1), &error));
1931 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
1932 				 diraft_ret, &diraft);
1933 		error = 0;
1934 		goto nfsmout;
1935 	}
1936 	NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
1937 	vtyp = nfsv3tov_type(*tl);
1938 	if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1939 		error = NFSERR_BADTYPE;
1940 		goto out;
1941 	}
1942 	VATTR_NULL(vap);
1943 	ERROROUT(nfsm_srvsattr(&info, vap));
1944 	if (vtyp == VCHR || vtyp == VBLK) {
1945 		NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED));
1946 		vap->va_rmajor = fxdr_unsigned(u_int32_t, *tl++);
1947 		vap->va_rminor = fxdr_unsigned(u_int32_t, *tl);
1948 	}
1949 
1950 	/*
1951 	 * Iff doesn't exist, create it.
1952 	 */
1953 	if (vp) {
1954 		error = EEXIST;
1955 		goto out;
1956 	}
1957 	vap->va_type = vtyp;
1958 	if (vap->va_mode == (mode_t)VNOVAL)
1959 		vap->va_mode = 0;
1960 	if (vtyp == VSOCK) {
1961 		vn_unlock(dvp);
1962 		error = VOP_NCREATE(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap);
1963 		vrele(dvp);
1964 		dvp = NULL;
1965 	} else {
1966 		if (vtyp != VFIFO && (error = priv_check_cred(cred, PRIV_ROOT, 0)))
1967 			goto out;
1968 
1969 		vn_unlock(dvp);
1970 		error = VOP_NMKNOD(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap);
1971 		vrele(dvp);
1972 		dvp = NULL;
1973 		if (error)
1974 			goto out;
1975 	}
1976 
1977 	/*
1978 	 * send response, cleanup, return.
1979 	 */
1980 out:
1981 	nlookup_done(&nd);
1982 	if (dvp) {
1983 		if (dvp == vp)
1984 			vrele(dvp);
1985 		else
1986 			vput(dvp);
1987 		dvp = NULL;
1988 	}
1989 	if (!error) {
1990 		bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
1991 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
1992 		if (!error)
1993 			error = VOP_GETATTR(vp, vap);
1994 	}
1995 	if (vp) {
1996 		vput(vp);
1997 		vp = NULL;
1998 	}
1999 	diraft_ret = VOP_GETATTR(dirp, &diraft);
2000 	if (dirp) {
2001 		vrele(dirp);
2002 		dirp = NULL;
2003 	}
2004 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2005 			      NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) +
2006 			      NFSX_WCCDATA(1), &error));
2007 	if (!error) {
2008 		nfsm_srvpostop_fh(&info, fhp);
2009 		nfsm_srvpostop_attr(&info, nfsd, 0, vap);
2010 	}
2011 	nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2012 			 diraft_ret, &diraft);
2013 	*mrq = info.mreq;
2014 	return (0);
2015 nfsmout:
2016 	*mrq = info.mreq;
2017 	if (dirp)
2018 		vrele(dirp);
2019 	nlookup_done(&nd);
2020 	if (dvp) {
2021 		if (dvp == vp)
2022 			vrele(dvp);
2023 		else
2024 			vput(dvp);
2025 	}
2026 	if (vp)
2027 		vput(vp);
2028 	return (error);
2029 }
2030 
2031 /*
2032  * nfs remove service
2033  */
2034 int
2035 nfsrv_remove(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2036 	     struct thread *td, struct mbuf **mrq)
2037 {
2038 	struct sockaddr *nam = nfsd->nd_nam;
2039 	struct ucred *cred = &nfsd->nd_cr;
2040 	struct nlookupdata nd;
2041 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2042 	struct vnode *dirp;
2043 	struct vnode *dvp;
2044 	struct vnode *vp;
2045 	struct vattr dirfor, diraft;
2046 	nfsfh_t nfh;
2047 	fhandle_t *fhp;
2048 	struct nfsm_info info;
2049 
2050 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2051 	nlookup_zero(&nd);
2052 	dirp = NULL;
2053 	dvp = NULL;
2054 	vp = NULL;
2055 
2056 	info.mrep = nfsd->nd_mrep;
2057 	info.mreq = NULL;
2058 	info.md = nfsd->nd_md;
2059 	info.dpos = nfsd->nd_dpos;
2060 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
2061 
2062 	fhp = &nfh.fh_generic;
2063 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2064 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
2065 
2066 	error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp,
2067 			  fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
2068 			  td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2069 	if (dirp) {
2070 		if (info.v3)
2071 			dirfor_ret = VOP_GETATTR(dirp, &dirfor);
2072 	}
2073 	if (error == 0) {
2074 		if (vp->v_type == VDIR) {
2075 			error = EPERM;		/* POSIX */
2076 			goto out;
2077 		}
2078 		/*
2079 		 * The root of a mounted filesystem cannot be deleted.
2080 		 */
2081 		if (vp->v_flag & VROOT) {
2082 			error = EBUSY;
2083 			goto out;
2084 		}
2085 out:
2086 		if (!error) {
2087 			if (dvp != vp)
2088 				vn_unlock(dvp);
2089 			if (vp) {
2090 				vput(vp);
2091 				vp = NULL;
2092 			}
2093 			error = VOP_NREMOVE(&nd.nl_nch, dvp, nd.nl_cred);
2094 			vrele(dvp);
2095 			dvp = NULL;
2096 		}
2097 	}
2098 	if (dirp && info.v3)
2099 		diraft_ret = VOP_GETATTR(dirp, &diraft);
2100 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error));
2101 	if (info.v3) {
2102 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2103 				 diraft_ret, &diraft);
2104 		error = 0;
2105 	}
2106 nfsmout:
2107 	*mrq = info.mreq;
2108 	nlookup_done(&nd);
2109 	if (dirp)
2110 		vrele(dirp);
2111 	if (dvp) {
2112 		if (dvp == vp)
2113 			vrele(dvp);
2114 		else
2115 			vput(dvp);
2116 	}
2117 	if (vp)
2118 		vput(vp);
2119 	return(error);
2120 }
2121 
2122 /*
2123  * nfs rename service
2124  */
2125 int
2126 nfsrv_rename(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2127 	     struct thread *td, struct mbuf **mrq)
2128 {
2129 	struct sockaddr *nam = nfsd->nd_nam;
2130 	struct ucred *cred = &nfsd->nd_cr;
2131 	int error = 0, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
2132 	int tdirfor_ret = 1, tdiraft_ret = 1;
2133 	struct nlookupdata fromnd, tond;
2134 	struct nchandle fnchd;
2135 	struct nchandle tnchd;
2136 	struct vnode *fvp, *fdirp, *fdvp;
2137 	struct vnode *tvp, *tdirp, *tdvp;
2138 	struct namecache *ncp;
2139 	struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
2140 	int fnchd_status = 0;
2141 	int tnchd_status = 0;
2142 	nfsfh_t fnfh, tnfh;
2143 	fhandle_t *ffhp, *tfhp;
2144 	uid_t saved_uid;
2145 	struct nfsm_info info;
2146 
2147 	info.mrep = nfsd->nd_mrep;
2148 	info.mreq = NULL;
2149 	info.md = nfsd->nd_md;
2150 	info.dpos = nfsd->nd_dpos;
2151 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
2152 
2153 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2154 #ifndef nolint
2155 	fvp = NULL;
2156 #endif
2157 	ffhp = &fnfh.fh_generic;
2158 	tfhp = &tnfh.fh_generic;
2159 
2160 	/*
2161 	 * Clear fields incase goto nfsmout occurs from macro.
2162 	 */
2163 
2164 	nlookup_zero(&fromnd);
2165 	nlookup_zero(&tond);
2166 	fdirp = NULL;
2167 	tdirp = NULL;
2168 
2169 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, ffhp, &error));
2170 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
2171 
2172 	/*
2173 	 * Remember our original uid so that we can reset cr_uid before
2174 	 * the second nfs_namei() call, in case it is remapped.
2175 	 *
2176 	 * NOTE! If nfs_namei() is called twice on the same nd, it assumes
2177 	 *	 a retry and does not try to reparse the path.
2178 	 */
2179 	saved_uid = cred->cr_uid;
2180 again:
2181 	error = nfs_namei(&fromnd, cred, NLC_RENAME_SRC,
2182 			  NULL, NULL,
2183 			  ffhp, len, slp, nam, &info.md, &info.dpos, &fdirp,
2184 			  td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2185 	if (fdirp) {
2186 		if (info.v3)
2187 			fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor);
2188 	}
2189 	if (error) {
2190 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2191 				      2 * NFSX_WCCDATA(info.v3), &error));
2192 		nfsm_srvwcc_data(&info, nfsd, fdirfor_ret, &fdirfor,
2193 				 fdiraft_ret, &fdiraft);
2194 		nfsm_srvwcc_data(&info, nfsd, tdirfor_ret, &tdirfor,
2195 				 tdiraft_ret, &tdiraft);
2196 		error = 0;
2197 		goto nfsmout;
2198 	}
2199 
2200 	fnchd.mount = fromnd.nl_nch.mount;
2201 	fnchd.ncp = fromnd.nl_nch.ncp->nc_parent;
2202 	if (fnchd.ncp == NULL) {
2203 		error = ENOENT;
2204 		goto nfsmout;
2205 	}
2206 	cache_hold(&fnchd);
2207 	fnchd_status = 1;
2208 
2209 	/*
2210 	 * We have to unlock the from ncp before we can safely lookup
2211 	 * the target ncp.
2212 	 */
2213 	KKASSERT(fromnd.nl_flags & NLC_NCPISLOCKED);
2214 	cache_unlock(&fromnd.nl_nch);
2215 	fromnd.nl_flags &= ~NLC_NCPISLOCKED;
2216 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, tfhp, &error));
2217 	NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXNAMLEN));
2218 	cred->cr_uid = saved_uid;
2219 
2220 	error = nfs_namei(&tond, cred, NLC_RENAME_DST, NULL, NULL,
2221 			  tfhp, len2, slp, nam, &info.md, &info.dpos, &tdirp,
2222 			  td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2223 	if (tdirp) {
2224 		if (info.v3)
2225 			tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor);
2226 	}
2227 	if (error)
2228 		goto out1;
2229 	tnchd.mount = tond.nl_nch.mount;
2230 	tnchd.ncp = tond.nl_nch.ncp->nc_parent;
2231 	if (tnchd.ncp == NULL) {
2232 		error = ENOENT;
2233 		goto nfsmout;
2234 	}
2235 	cache_hold(&tnchd);
2236 	tnchd_status = 1;
2237 
2238 	cache_lock4_tondlocked(&fnchd, &fromnd.nl_nch,
2239 			       &tnchd, &tond.nl_nch,
2240                                fromnd.nl_cred, tond.nl_cred);
2241 	fromnd.nl_flags |= NLC_NCPISLOCKED;
2242 	fnchd_status = 2;
2243 	tnchd_status = 2;
2244 
2245 	/*
2246 	 * Revalidate namecache records and retry the lookups if necessary.
2247 	 */
2248 	if (fnchd.ncp != fromnd.nl_nch.ncp->nc_parent ||
2249 	    tnchd.ncp != tond.nl_nch.ncp->nc_parent ||
2250 	    (fromnd.nl_nch.ncp->nc_flag & (NCF_DESTROYED | NCF_UNRESOLVED)) ||
2251             fromnd.nl_nch.ncp->nc_vp == NULL ||
2252             (tond.nl_nch.ncp->nc_flag & (NCF_DESTROYED | NCF_UNRESOLVED))) {
2253 		cache_put(&fnchd);
2254 		cache_put(&tnchd);
2255 		if (tdirp)
2256 			vrele(tdirp);
2257 		if (fdirp)
2258 			vrele(fdirp);
2259 		kprintf("nfs - retry rename %s to %s\n",
2260 			fromnd.nl_path, tond.nl_path);
2261 		goto again;
2262 	}
2263 
2264 	/*
2265 	 * Source and target vnodes (tvp might be NULL)
2266 	 */
2267 	fvp = fromnd.nl_nch.ncp->nc_vp;
2268 	tvp = tond.nl_nch.ncp->nc_vp;
2269 
2270 	/*
2271 	 * Set fdvp and tdvp.  We haven't done all the topology checks
2272 	 * so these can wind up NULL (e.g. if either fvp or tvp is a mount
2273 	 * point).  If we get through the checks these will be guarenteed
2274 	 * to be non-NULL.
2275 	 *
2276 	 * Holding the children ncp's should be sufficient to prevent
2277 	 * fdvp and tdvp ripouts.
2278 	 */
2279 	fdvp = fromnd.nl_nch.ncp->nc_parent->nc_vp;
2280 	tdvp = tond.nl_nch.ncp->nc_parent->nc_vp;
2281 
2282 	if (tvp != NULL) {
2283 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
2284 			if (info.v3)
2285 				error = EEXIST;
2286 			else
2287 				error = EISDIR;
2288 			goto out;
2289 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
2290 			if (info.v3)
2291 				error = EEXIST;
2292 			else
2293 				error = ENOTDIR;
2294 			goto out;
2295 		}
2296 		if (tvp->v_type == VDIR && (tond.nl_nch.ncp->nc_flag & NCF_ISMOUNTPT)) {
2297 			if (info.v3)
2298 				error = EXDEV;
2299 			else
2300 				error = ENOTEMPTY;
2301 			goto out;
2302 		}
2303 	}
2304 	if (fvp->v_type == VDIR && (fromnd.nl_nch.ncp->nc_flag & NCF_ISMOUNTPT)) {
2305 		if (info.v3)
2306 			error = EXDEV;
2307 		else
2308 			error = ENOTEMPTY;
2309 		goto out;
2310 	}
2311 	if (fromnd.nl_nch.mount != tond.nl_nch.mount) {
2312 		if (info.v3)
2313 			error = EXDEV;
2314 		else
2315 			error = ENOTEMPTY;
2316 		goto out;
2317 	}
2318 	if (fromnd.nl_nch.ncp == tond.nl_nch.ncp->nc_parent) {
2319 		if (info.v3)
2320 			error = EINVAL;
2321 		else
2322 			error = ENOTEMPTY;
2323 	}
2324 
2325 	/*
2326 	 * You cannot rename a source into itself or a subdirectory of itself.
2327 	 * We check this by travsering the target directory upwards looking
2328 	 * for a match against the source.
2329 	 */
2330 	if (error == 0) {
2331 		for (ncp = tond.nl_nch.ncp; ncp; ncp = ncp->nc_parent) {
2332 			if (fromnd.nl_nch.ncp == ncp) {
2333 				error = EINVAL;
2334 				break;
2335 			}
2336 		}
2337 	}
2338 
2339 	/*
2340 	 * If source is the same as the destination (that is the
2341 	 * same vnode with the same name in the same directory),
2342 	 * then there is nothing to do.
2343 	 */
2344 	if (fromnd.nl_nch.ncp == tond.nl_nch.ncp)
2345 		error = -1;
2346 out:
2347 	if (!error) {
2348 		/*
2349 		 * The VOP_NRENAME function releases all vnode references &
2350 		 * locks prior to returning so we need to clear the pointers
2351 		 * to bypass cleanup code later on.
2352 		 */
2353 		error = VOP_NRENAME(&fromnd.nl_nch, &tond.nl_nch,
2354 				    fdvp, tdvp, tond.nl_cred);
2355 	} else {
2356 		if (error == -1)
2357 			error = 0;
2358 	}
2359 	/* fall through */
2360 
2361 out1:
2362 	if (fdirp)
2363 		fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft);
2364 	if (tdirp)
2365 		tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft);
2366 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2367 			      2 * NFSX_WCCDATA(info.v3), &error));
2368 	if (info.v3) {
2369 		nfsm_srvwcc_data(&info, nfsd, fdirfor_ret, &fdirfor,
2370 				 fdiraft_ret, &fdiraft);
2371 		nfsm_srvwcc_data(&info, nfsd, tdirfor_ret, &tdirfor,
2372 				 tdiraft_ret, &tdiraft);
2373 	}
2374 	error = 0;
2375 	/* fall through */
2376 
2377 nfsmout:
2378 	if (fnchd_status > 1)
2379 		cache_unlock(&fnchd);
2380 	if (fnchd_status > 0)
2381 		cache_drop(&fnchd);
2382 	if (tnchd_status > 1)
2383 		cache_unlock(&tnchd);
2384 	if (tnchd_status > 0)
2385 		cache_drop(&tnchd);
2386 
2387 	*mrq = info.mreq;
2388 	if (tdirp)
2389 		vrele(tdirp);
2390 	nlookup_done(&tond);
2391 	if (fdirp)
2392 		vrele(fdirp);
2393 	nlookup_done(&fromnd);
2394 	return (error);
2395 }
2396 
2397 /*
2398  * nfs link service
2399  */
2400 int
2401 nfsrv_link(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2402 	   struct thread *td, struct mbuf **mrq)
2403 {
2404 	struct sockaddr *nam = nfsd->nd_nam;
2405 	struct ucred *cred = &nfsd->nd_cr;
2406 	struct nlookupdata nd;
2407 	int error = 0, rdonly, len, dirfor_ret = 1, diraft_ret = 1;
2408 	int getret = 1;
2409 	struct vnode *dirp;
2410 	struct vnode *dvp;
2411 	struct vnode *vp;
2412 	struct vnode *xp;
2413 	struct mount *xmp;
2414 	struct vattr dirfor, diraft, at;
2415 	nfsfh_t nfh, dnfh;
2416 	fhandle_t *fhp, *dfhp;
2417 	struct nfsm_info info;
2418 
2419 	info.mrep = nfsd->nd_mrep;
2420 	info.mreq = NULL;
2421 	info.md = nfsd->nd_md;
2422 	info.dpos = nfsd->nd_dpos;
2423 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
2424 
2425 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2426 	nlookup_zero(&nd);
2427 	dirp = dvp = vp = xp = NULL;
2428 	xmp = NULL;
2429 
2430 	fhp = &nfh.fh_generic;
2431 	dfhp = &dnfh.fh_generic;
2432 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2433 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, dfhp, &error));
2434 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
2435 
2436 	error = nfsrv_fhtovp(fhp, FALSE, &xmp, &xp, cred, slp, nam,
2437 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
2438 	if (error) {
2439 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2440 				      NFSX_POSTOPATTR(info.v3) +
2441 				      NFSX_WCCDATA(info.v3),
2442 				      &error));
2443 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
2444 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2445 				 diraft_ret, &diraft);
2446 		xp = NULL;
2447 		error = 0;
2448 		goto nfsmout;
2449 	}
2450 	if (xp->v_type == VDIR) {
2451 		error = EPERM;		/* POSIX */
2452 		goto out1;
2453 	}
2454 
2455 	error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
2456 			  dfhp, len, slp, nam, &info.md, &info.dpos, &dirp,
2457 			  td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2458 	if (dirp) {
2459 		if (info.v3)
2460 			dirfor_ret = VOP_GETATTR(dirp, &dirfor);
2461 	}
2462 	if (error)
2463 		goto out1;
2464 
2465 	if (vp != NULL) {
2466 		error = EEXIST;
2467 		goto out;
2468 	}
2469 	if (xp->v_mount != dvp->v_mount)
2470 		error = EXDEV;
2471 out:
2472 	if (!error) {
2473 		vn_unlock(dvp);
2474 		error = VOP_NLINK(&nd.nl_nch, dvp, xp, nd.nl_cred);
2475 		vrele(dvp);
2476 		dvp = NULL;
2477 	}
2478 	/* fall through */
2479 
2480 out1:
2481 	if (info.v3)
2482 		getret = VOP_GETATTR(xp, &at);
2483 	if (dirp)
2484 		diraft_ret = VOP_GETATTR(dirp, &diraft);
2485 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2486 			      NFSX_POSTOPATTR(info.v3) + NFSX_WCCDATA(info.v3),
2487 			      &error));
2488 	if (info.v3) {
2489 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
2490 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2491 				 diraft_ret, &diraft);
2492 		error = 0;
2493 	}
2494 	/* fall through */
2495 
2496 nfsmout:
2497 	*mrq = info.mreq;
2498 	nlookup_done(&nd);
2499 	if (dirp)
2500 		vrele(dirp);
2501 	if (xp)
2502 		vrele(xp);
2503 	if (dvp) {
2504 		if (dvp == vp)
2505 			vrele(dvp);
2506 		else
2507 			vput(dvp);
2508 	}
2509 	if (vp)
2510 		vput(vp);
2511 	return(error);
2512 }
2513 
2514 /*
2515  * nfs symbolic link service
2516  */
2517 int
2518 nfsrv_symlink(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2519 	      struct thread *td, struct mbuf **mrq)
2520 {
2521 	struct sockaddr *nam = nfsd->nd_nam;
2522 	struct ucred *cred = &nfsd->nd_cr;
2523 	struct vattr va, dirfor, diraft;
2524 	struct nlookupdata nd;
2525 	struct vattr *vap = &va;
2526 	struct nfsv2_sattr *sp;
2527 	char *pathcp = NULL;
2528 	struct uio io;
2529 	struct iovec iv;
2530 	int error = 0, len, len2, dirfor_ret = 1, diraft_ret = 1;
2531 	struct vnode *dirp;
2532 	struct vnode *vp;
2533 	struct vnode *dvp;
2534 	nfsfh_t nfh;
2535 	fhandle_t *fhp;
2536 	struct nfsm_info info;
2537 
2538 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2539 	nlookup_zero(&nd);
2540 	dirp = NULL;
2541 	dvp = NULL;
2542 	vp = NULL;
2543 
2544 	info.mrep = nfsd->nd_mrep;
2545 	info.mreq =  NULL;
2546 	info.md = nfsd->nd_md;
2547 	info.dpos = nfsd->nd_dpos;
2548 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
2549 
2550 	fhp = &nfh.fh_generic;
2551 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2552 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
2553 
2554 	error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
2555 			fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
2556 			td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2557 	if (dirp) {
2558 		if (info.v3)
2559 			dirfor_ret = VOP_GETATTR(dirp, &dirfor);
2560 	}
2561 	if (error)
2562 		goto out;
2563 
2564 	VATTR_NULL(vap);
2565 	if (info.v3) {
2566 		ERROROUT(nfsm_srvsattr(&info, vap));
2567 	}
2568 	NEGATIVEOUT(len2 = nfsm_strsiz(&info, NFS_MAXPATHLEN));
2569 	pathcp = kmalloc(len2 + 1, M_TEMP, M_WAITOK);
2570 	iv.iov_base = pathcp;
2571 	iv.iov_len = len2;
2572 	io.uio_resid = len2;
2573 	io.uio_offset = 0;
2574 	io.uio_iov = &iv;
2575 	io.uio_iovcnt = 1;
2576 	io.uio_segflg = UIO_SYSSPACE;
2577 	io.uio_rw = UIO_READ;
2578 	io.uio_td = NULL;
2579 	ERROROUT(nfsm_mtouio(&info, &io, len2));
2580 	if (info.v3 == 0) {
2581 		NULLOUT(sp = nfsm_dissect(&info, NFSX_V2SATTR));
2582 		vap->va_mode = nfstov_mode(sp->sa_mode);
2583 	}
2584 	*(pathcp + len2) = '\0';
2585 	if (vp) {
2586 		error = EEXIST;
2587 		goto out;
2588 	}
2589 
2590 	if (vap->va_mode == (mode_t)VNOVAL)
2591 		vap->va_mode = 0;
2592 	if (dvp != vp)
2593 		vn_unlock(dvp);
2594 	error = VOP_NSYMLINK(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap, pathcp);
2595 	vrele(dvp);
2596 	dvp = NULL;
2597 	if (error == 0) {
2598 		bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
2599 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
2600 		if (!error)
2601 			error = VOP_GETATTR(vp, vap);
2602 	}
2603 
2604 out:
2605 	if (dvp) {
2606 		if (dvp == vp)
2607 			vrele(dvp);
2608 		else
2609 			vput(dvp);
2610 	}
2611 	if (vp) {
2612 		vput(vp);
2613 		vp = NULL;
2614 	}
2615 	if (pathcp) {
2616 		kfree(pathcp, M_TEMP);
2617 		pathcp = NULL;
2618 	}
2619 	if (dirp) {
2620 		diraft_ret = VOP_GETATTR(dirp, &diraft);
2621 		vrele(dirp);
2622 		dirp = NULL;
2623 	}
2624 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2625 			      NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) +
2626 			      NFSX_WCCDATA(info.v3),
2627 			      &error));
2628 	if (info.v3) {
2629 		if (!error) {
2630 			nfsm_srvpostop_fh(&info, fhp);
2631 			nfsm_srvpostop_attr(&info, nfsd, 0, vap);
2632 		}
2633 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2634 				 diraft_ret, &diraft);
2635 	}
2636 	error = 0;
2637 	/* fall through */
2638 
2639 nfsmout:
2640 	*mrq = info.mreq;
2641 	nlookup_done(&nd);
2642 	if (vp)
2643 		vput(vp);
2644 	if (dirp)
2645 		vrele(dirp);
2646 	if (pathcp)
2647 		kfree(pathcp, M_TEMP);
2648 	return (error);
2649 }
2650 
2651 /*
2652  * nfs mkdir service
2653  */
2654 int
2655 nfsrv_mkdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2656 	    struct thread *td, struct mbuf **mrq)
2657 {
2658 	struct sockaddr *nam = nfsd->nd_nam;
2659 	struct ucred *cred = &nfsd->nd_cr;
2660 	struct vattr va, dirfor, diraft;
2661 	struct vattr *vap = &va;
2662 	struct nfs_fattr *fp;
2663 	struct nlookupdata nd;
2664 	u_int32_t *tl;
2665 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2666 	struct vnode *dirp;
2667 	struct vnode *dvp;
2668 	struct vnode *vp;
2669 	nfsfh_t nfh;
2670 	fhandle_t *fhp;
2671 	struct nfsm_info info;
2672 
2673 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2674 	nlookup_zero(&nd);
2675 	dirp = NULL;
2676 	dvp = NULL;
2677 	vp = NULL;
2678 
2679 	info.dpos = nfsd->nd_dpos;
2680 	info.mrep = nfsd->nd_mrep;
2681 	info.mreq =  NULL;
2682 	info.md = nfsd->nd_md;
2683 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
2684 
2685 	fhp = &nfh.fh_generic;
2686 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2687 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
2688 
2689 	error = nfs_namei(&nd, cred, NLC_CREATE, &dvp, &vp,
2690 			  fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
2691 			  td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2692 	if (dirp) {
2693 		if (info.v3)
2694 			dirfor_ret = VOP_GETATTR(dirp, &dirfor);
2695 	}
2696 	if (error) {
2697 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2698 				      NFSX_WCCDATA(info.v3), &error));
2699 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2700 				 diraft_ret, &diraft);
2701 		error = 0;
2702 		goto nfsmout;
2703 	}
2704 	VATTR_NULL(vap);
2705 	if (info.v3) {
2706 		ERROROUT(nfsm_srvsattr(&info, vap));
2707 	} else {
2708 		NULLOUT(tl = nfsm_dissect(&info, NFSX_UNSIGNED));
2709 		vap->va_mode = nfstov_mode(*tl++);
2710 	}
2711 
2712 	/*
2713 	 * At this point nd.ni_dvp is referenced and exclusively locked and
2714 	 * nd.ni_vp, if it exists, is referenced but not locked.
2715 	 */
2716 
2717 	vap->va_type = VDIR;
2718 	if (vp != NULL) {
2719 		error = EEXIST;
2720 		goto out;
2721 	}
2722 
2723 	/*
2724 	 * Issue mkdir op.  Since SAVESTART is not set, the pathname
2725 	 * component is freed by the VOP call.  This will fill-in
2726 	 * nd.ni_vp, reference, and exclusively lock it.
2727 	 */
2728 	if (vap->va_mode == (mode_t)VNOVAL)
2729 		vap->va_mode = 0;
2730 	vn_unlock(dvp);
2731 	error = VOP_NMKDIR(&nd.nl_nch, dvp, &vp, nd.nl_cred, vap);
2732 	vrele(dvp);
2733 	dvp = NULL;
2734 
2735 	if (error == 0) {
2736 		bzero(&fhp->fh_fid, sizeof(fhp->fh_fid));
2737 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
2738 		if (error == 0)
2739 			error = VOP_GETATTR(vp, vap);
2740 	}
2741 out:
2742 	if (dirp)
2743 		diraft_ret = VOP_GETATTR(dirp, &diraft);
2744 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2745 			      NFSX_SRVFH(info.v3) + NFSX_POSTOPATTR(info.v3) +
2746 			      NFSX_WCCDATA(info.v3),
2747 			      &error));
2748 	if (info.v3) {
2749 		if (!error) {
2750 			nfsm_srvpostop_fh(&info, fhp);
2751 			nfsm_srvpostop_attr(&info, nfsd, 0, vap);
2752 		}
2753 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2754 				 diraft_ret, &diraft);
2755 	} else {
2756 		nfsm_srvfhtom(&info, fhp);
2757 		fp = nfsm_build(&info, NFSX_V2FATTR);
2758 		nfsm_srvfattr(nfsd, vap, fp);
2759 	}
2760 	error = 0;
2761 	/* fall through */
2762 
2763 nfsmout:
2764 	*mrq = info.mreq;
2765 	nlookup_done(&nd);
2766 	if (dirp)
2767 		vrele(dirp);
2768 	if (dvp) {
2769 		if (dvp == vp)
2770 			vrele(dvp);
2771 		else
2772 			vput(dvp);
2773 	}
2774 	if (vp)
2775 		vput(vp);
2776 	return (error);
2777 }
2778 
2779 /*
2780  * nfs rmdir service
2781  */
2782 int
2783 nfsrv_rmdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2784 	    struct thread *td, struct mbuf **mrq)
2785 {
2786 	struct sockaddr *nam = nfsd->nd_nam;
2787 	struct ucred *cred = &nfsd->nd_cr;
2788 	int error = 0, len, dirfor_ret = 1, diraft_ret = 1;
2789 	struct vnode *dirp;
2790 	struct vnode *dvp;
2791 	struct vnode *vp;
2792 	struct vattr dirfor, diraft;
2793 	nfsfh_t nfh;
2794 	fhandle_t *fhp;
2795 	struct nlookupdata nd;
2796 	struct nfsm_info info;
2797 
2798 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2799 	nlookup_zero(&nd);
2800 	dirp = NULL;
2801 	dvp = NULL;
2802 	vp = NULL;
2803 
2804 	info.mrep = nfsd->nd_mrep;
2805 	info.mreq = NULL;
2806 	info.md = nfsd->nd_md;
2807 	info.dpos = nfsd->nd_dpos;
2808 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
2809 
2810 	fhp = &nfh.fh_generic;
2811 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2812 	NEGREPLYOUT(len = nfsm_srvnamesiz(&info, &error));
2813 
2814 	error = nfs_namei(&nd, cred, NLC_DELETE, &dvp, &vp,
2815 			  fhp, len, slp, nam, &info.md, &info.dpos, &dirp,
2816 			  td, (nfsd->nd_flag & ND_KERBAUTH), FALSE);
2817 	if (dirp) {
2818 		if (info.v3)
2819 			dirfor_ret = VOP_GETATTR(dirp, &dirfor);
2820 	}
2821 	if (error) {
2822 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
2823 				      NFSX_WCCDATA(info.v3), &error));
2824 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2825 				 diraft_ret, &diraft);
2826 		error = 0;
2827 		goto nfsmout;
2828 	}
2829 	if (vp->v_type != VDIR) {
2830 		error = ENOTDIR;
2831 		goto out;
2832 	}
2833 
2834 	/*
2835 	 * The root of a mounted filesystem cannot be deleted.
2836 	 */
2837 	if (vp->v_flag & VROOT)
2838 		error = EBUSY;
2839 out:
2840 	/*
2841 	 * Issue or abort op.  Since SAVESTART is not set, path name
2842 	 * component is freed by the VOP after either.
2843 	 */
2844 	if (!error) {
2845 		if (dvp != vp)
2846 			vn_unlock(dvp);
2847 		vput(vp);
2848 		vp = NULL;
2849 		error = VOP_NRMDIR(&nd.nl_nch, dvp, nd.nl_cred);
2850 		vrele(dvp);
2851 		dvp = NULL;
2852 	}
2853 	nlookup_done(&nd);
2854 
2855 	if (dirp)
2856 		diraft_ret = VOP_GETATTR(dirp, &diraft);
2857 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_WCCDATA(info.v3), &error));
2858 	if (info.v3) {
2859 		nfsm_srvwcc_data(&info, nfsd, dirfor_ret, &dirfor,
2860 				 diraft_ret, &diraft);
2861 		error = 0;
2862 	}
2863 	/* fall through */
2864 
2865 nfsmout:
2866 	*mrq = info.mreq;
2867 	if (dvp) {
2868 		if (dvp == vp)
2869 			vrele(dvp);
2870 		else
2871 			vput(dvp);
2872 	}
2873 	nlookup_done(&nd);
2874 	if (dirp)
2875 		vrele(dirp);
2876 	if (vp)
2877 		vput(vp);
2878 	return(error);
2879 }
2880 
2881 /*
2882  * nfs readdir service
2883  * - mallocs what it thinks is enough to read
2884  *	count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
2885  * - calls VOP_READDIR()
2886  * - loops around building the reply
2887  *	if the output generated exceeds count break out of loop
2888  *	The nfsm_clget macro is used here so that the reply will be packed
2889  *	tightly in mbuf clusters.
2890  * - it only knows that it has encountered eof when the VOP_READDIR()
2891  *	reads nothing
2892  * - as such one readdir rpc will return eof false although you are there
2893  *	and then the next will return eof
2894  * - it trims out records with d_fileno == 0
2895  *	this doesn't matter for Unix clients, but they might confuse clients
2896  *	for other os'.
2897  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
2898  *	than requested, but this may not apply to all filesystems. For
2899  *	example, client NFS does not { although it is never remote mounted
2900  *	anyhow }
2901  *     The alternate call nfsrv_readdirplus() does lookups as well.
2902  * PS: The NFS protocol spec. does not clarify what the "count" byte
2903  *	argument is a count of.. just name strings and file id's or the
2904  *	entire reply rpc or ...
2905  *	I tried just file name and id sizes and it confused the Sun client,
2906  *	so I am using the full rpc size now. The "paranoia.." comment refers
2907  *	to including the status longwords that are not a part of the dir.
2908  *	"entry" structures, but are in the rpc.
2909  */
2910 struct flrep {
2911 	nfsuint64	fl_off;
2912 	u_int32_t	fl_postopok;
2913 	u_int32_t	fl_fattr[NFSX_V3FATTR / sizeof (u_int32_t)];
2914 	u_int32_t	fl_fhok;
2915 	u_int32_t	fl_fhsize;
2916 	u_int32_t	fl_nfh[NFSX_V3FH / sizeof (u_int32_t)];
2917 };
2918 
2919 int
2920 nfsrv_readdir(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
2921 	      struct thread *td, struct mbuf **mrq)
2922 {
2923 	struct sockaddr *nam = nfsd->nd_nam;
2924 	struct ucred *cred = &nfsd->nd_cr;
2925 	char *bp, *be;
2926 	struct dirent *dp;
2927 	caddr_t cp;
2928 	u_int32_t *tl;
2929 	struct mbuf *mp1, *mp2;
2930 	char *cpos, *cend, *rbuf;
2931 	struct vnode *vp = NULL;
2932 	struct mount *mp = NULL;
2933 	struct vattr at;
2934 	nfsfh_t nfh;
2935 	fhandle_t *fhp;
2936 	struct uio io;
2937 	struct iovec iv;
2938 	int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2939 	int siz, cnt, fullsiz, eofflag, rdonly, ncookies;
2940 	u_quad_t off, toff;
2941 #if 0
2942 	u_quad_t verf;
2943 #endif
2944 	off_t *cookies = NULL, *cookiep;
2945 	struct nfsm_info info;
2946 
2947 	info.mrep = nfsd->nd_mrep;
2948 	info.mreq = NULL;
2949 	info.md = nfsd->nd_md;
2950 	info.dpos = nfsd->nd_dpos;
2951 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
2952 
2953 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
2954 	fhp = &nfh.fh_generic;
2955 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
2956 	if (info.v3) {
2957 		NULLOUT(tl = nfsm_dissect(&info, 5 * NFSX_UNSIGNED));
2958 		toff = fxdr_hyper(tl);
2959 		tl += 2;
2960 #if 0
2961 		verf = fxdr_hyper(tl);
2962 #endif
2963 		tl += 2;
2964 	} else {
2965 		NULLOUT(tl = nfsm_dissect(&info, 2 * NFSX_UNSIGNED));
2966 		toff = fxdr_unsigned(u_quad_t, *tl++);
2967 #if 0
2968 		verf = 0;	/* shut up gcc */
2969 #endif
2970 	}
2971 	off = toff;
2972 	cnt = fxdr_unsigned(int, *tl);
2973 	siz = roundup2(cnt, DIRBLKSIZ);
2974 	xfer = NFS_SRVMAXDATA(nfsd);
2975 	if ((unsigned)cnt > xfer)
2976 		cnt = xfer;
2977 	if ((unsigned)siz > xfer)
2978 		siz = xfer;
2979 	fullsiz = siz;
2980 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
2981 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
2982 	if (!error && vp->v_type != VDIR) {
2983 		error = ENOTDIR;
2984 		vput(vp);
2985 		vp = NULL;
2986 	}
2987 	if (error) {
2988 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
2989 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
2990 		error = 0;
2991 		goto nfsmout;
2992 	}
2993 
2994 	/*
2995 	 * Obtain lock on vnode for this section of the code
2996 	 */
2997 
2998 	if (info.v3) {
2999 		error = getret = VOP_GETATTR(vp, &at);
3000 #if 0
3001 		/*
3002 		 * XXX This check may be too strict for Solaris 2.5 clients.
3003 		 */
3004 		if (!error && toff && verf && verf != at.va_filerev)
3005 			error = NFSERR_BAD_COOKIE;
3006 #endif
3007 	}
3008 	if (!error)
3009 		error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0);
3010 	if (error) {
3011 		vput(vp);
3012 		vp = NULL;
3013 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3014 				      NFSX_POSTOPATTR(info.v3), &error));
3015 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3016 		error = 0;
3017 		goto nfsmout;
3018 	}
3019 	vn_unlock(vp);
3020 
3021 	/*
3022 	 * end section.  Allocate rbuf and continue
3023 	 */
3024 	rbuf = kmalloc(siz, M_TEMP, M_WAITOK);
3025 again:
3026 	iv.iov_base = rbuf;
3027 	iv.iov_len = fullsiz;
3028 	io.uio_iov = &iv;
3029 	io.uio_iovcnt = 1;
3030 	io.uio_offset = (off_t)off;
3031 	io.uio_resid = fullsiz;
3032 	io.uio_segflg = UIO_SYSSPACE;
3033 	io.uio_rw = UIO_READ;
3034 	io.uio_td = NULL;
3035 	eofflag = 0;
3036 	if (cookies) {
3037 		kfree((caddr_t)cookies, M_TEMP);
3038 		cookies = NULL;
3039 	}
3040 	error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
3041 	off = (off_t)io.uio_offset;
3042 	if (!cookies && !error)
3043 		error = NFSERR_PERM;
3044 	if (info.v3) {
3045 		getret = VOP_GETATTR(vp, &at);
3046 		if (!error)
3047 			error = getret;
3048 	}
3049 	if (error) {
3050 		vrele(vp);
3051 		vp = NULL;
3052 		kfree((caddr_t)rbuf, M_TEMP);
3053 		if (cookies)
3054 			kfree((caddr_t)cookies, M_TEMP);
3055 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3056 				      NFSX_POSTOPATTR(info.v3), &error));
3057 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3058 		error = 0;
3059 		goto nfsmout;
3060 	}
3061 	if (io.uio_resid) {
3062 		siz -= io.uio_resid;
3063 
3064 		/*
3065 		 * If nothing read, return eof
3066 		 * rpc reply
3067 		 */
3068 		if (siz == 0) {
3069 			vrele(vp);
3070 			vp = NULL;
3071 			NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3072 					      NFSX_POSTOPATTR(info.v3) +
3073 					      NFSX_COOKIEVERF(info.v3) +
3074 					      2 * NFSX_UNSIGNED,
3075 					      &error));
3076 			if (info.v3) {
3077 				nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3078 				tl = nfsm_build(&info, 4 * NFSX_UNSIGNED);
3079 				txdr_hyper(at.va_filerev, tl);
3080 				tl += 2;
3081 			} else
3082 				tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
3083 			*tl++ = nfs_false;
3084 			*tl = nfs_true;
3085 			kfree((caddr_t)rbuf, M_TEMP);
3086 			kfree((caddr_t)cookies, M_TEMP);
3087 			error = 0;
3088 			goto nfsmout;
3089 		}
3090 	}
3091 
3092 	/*
3093 	 * Check for degenerate cases of nothing useful read.
3094 	 * If so go try again
3095 	 */
3096 	cpos = rbuf;
3097 	cend = rbuf + siz;
3098 	dp = (struct dirent *)cpos;
3099 	cookiep = cookies;
3100 	/*
3101 	 * For some reason FreeBSD's ufs_readdir() chooses to back the
3102 	 * directory offset up to a block boundary, so it is necessary to
3103 	 * skip over the records that preceed the requested offset. This
3104 	 * requires the assumption that file offset cookies monotonically
3105 	 * increase.
3106 	 */
3107 	while (cpos < cend && ncookies > 0 &&
3108 		(dp->d_ino == 0 || dp->d_type == DT_WHT ||
3109 		 ((u_quad_t)(*cookiep)) <= toff)) {
3110 		dp = _DIRENT_NEXT(dp);
3111 		cpos = (char *)dp;
3112 		cookiep++;
3113 		ncookies--;
3114 	}
3115 	if (cpos >= cend || ncookies == 0) {
3116 		toff = off;
3117 		siz = fullsiz;
3118 		goto again;
3119 	}
3120 
3121 	len = 3 * NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
3122 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3123 			      NFSX_POSTOPATTR(info.v3) +
3124 			      NFSX_COOKIEVERF(info.v3) + siz,
3125 			      &error));
3126 	if (info.v3) {
3127 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3128 		tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
3129 		txdr_hyper(at.va_filerev, tl);
3130 	}
3131 	mp1 = mp2 = info.mb;
3132 	bp = info.bpos;
3133 	be = bp + M_TRAILINGSPACE(mp1);
3134 
3135 	/* Loop through the records and build reply */
3136 	while (cpos < cend && ncookies > 0) {
3137 		if (dp->d_ino != 0 && dp->d_type != DT_WHT) {
3138 			nlen = dp->d_namlen;
3139 			rem = nfsm_rndup(nlen) - nlen;
3140 			len += (4 * NFSX_UNSIGNED + nlen + rem);
3141 			if (info.v3)
3142 				len += 2 * NFSX_UNSIGNED;
3143 			if (len > cnt) {
3144 				eofflag = 0;
3145 				break;
3146 			}
3147 			/*
3148 			 * Build the directory record xdr from
3149 			 * the dirent entry.
3150 			 */
3151 			tl = nfsm_clget(&info, mp1, mp2, bp, be);
3152 			*tl = nfs_true;
3153 			bp += NFSX_UNSIGNED;
3154 			if (info.v3) {
3155 				tl = nfsm_clget(&info, mp1, mp2, bp, be);
3156 				*tl = txdr_unsigned(dp->d_ino >> 32);
3157 				bp += NFSX_UNSIGNED;
3158 			}
3159 			tl = nfsm_clget(&info, mp1, mp2, bp, be);
3160 			*tl = txdr_unsigned(dp->d_ino);
3161 			bp += NFSX_UNSIGNED;
3162 			tl = nfsm_clget(&info, mp1, mp2, bp, be);
3163 			*tl = txdr_unsigned(nlen);
3164 			bp += NFSX_UNSIGNED;
3165 
3166 			/* And loop around copying the name */
3167 			xfer = nlen;
3168 			cp = dp->d_name;
3169 			while (xfer > 0) {
3170 				tl = nfsm_clget(&info, mp1, mp2, bp, be);
3171 				if ((bp+xfer) > be)
3172 					tsiz = be-bp;
3173 				else
3174 					tsiz = xfer;
3175 				bcopy(cp, bp, tsiz);
3176 				bp += tsiz;
3177 				xfer -= tsiz;
3178 				if (xfer > 0)
3179 					cp += tsiz;
3180 			}
3181 			/* And null pad to a int32_t boundary */
3182 			for (i = 0; i < rem; i++)
3183 				*bp++ = '\0';
3184 			tl = nfsm_clget(&info, mp1, mp2, bp, be);
3185 
3186 			/* Finish off the record */
3187 			if (info.v3) {
3188 				*tl = txdr_unsigned(*cookiep >> 32);
3189 				bp += NFSX_UNSIGNED;
3190 				tl = nfsm_clget(&info, mp1, mp2, bp, be);
3191 			}
3192 			*tl = txdr_unsigned(*cookiep);
3193 			bp += NFSX_UNSIGNED;
3194 		}
3195 		dp = _DIRENT_NEXT(dp);
3196 		cpos = (char *)dp;
3197 		cookiep++;
3198 		ncookies--;
3199 	}
3200 	vrele(vp);
3201 	vp = NULL;
3202 	tl = nfsm_clget(&info, mp1, mp2, bp, be);
3203 	*tl = nfs_false;
3204 	bp += NFSX_UNSIGNED;
3205 	tl = nfsm_clget(&info, mp1, mp2, bp, be);
3206 	if (eofflag)
3207 		*tl = nfs_true;
3208 	else
3209 		*tl = nfs_false;
3210 	bp += NFSX_UNSIGNED;
3211 	if (mp1 != info.mb) {
3212 		if (bp < be)
3213 			mp1->m_len = bp - mtod(mp1, caddr_t);
3214 	} else
3215 		mp1->m_len += bp - info.bpos;
3216 	kfree((caddr_t)rbuf, M_TEMP);
3217 	kfree((caddr_t)cookies, M_TEMP);
3218 
3219 nfsmout:
3220 	*mrq = info.mreq;
3221 	if (vp)
3222 		vrele(vp);
3223 	return(error);
3224 }
3225 
3226 int
3227 nfsrv_readdirplus(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3228 		  struct thread *td, struct mbuf **mrq)
3229 {
3230 	struct sockaddr *nam = nfsd->nd_nam;
3231 	struct ucred *cred = &nfsd->nd_cr;
3232 	char *bp, *be;
3233 	struct dirent *dp;
3234 	caddr_t cp;
3235 	u_int32_t *tl;
3236 	struct mbuf *mp1, *mp2;
3237 	char *cpos, *cend, *rbuf;
3238 	struct vnode *vp = NULL, *nvp;
3239 	struct mount *mp = NULL;
3240 	struct flrep fl;
3241 	nfsfh_t nfh;
3242 	fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
3243 	struct uio io;
3244 	struct iovec iv;
3245 	struct vattr va, at, *vap = &va;
3246 	struct nfs_fattr *fp;
3247 	int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
3248 	int siz, cnt, fullsiz, eofflag, rdonly, dirlen, ncookies;
3249 	u_quad_t off, toff;
3250 #if 0
3251 	u_quad_t verf;
3252 #endif
3253 	off_t *cookies = NULL, *cookiep; /* needs to be int64_t or off_t */
3254 	struct nfsm_info info;
3255 
3256 	info.mrep = nfsd->nd_mrep;
3257 	info.mreq = NULL;
3258 	info.md = nfsd->nd_md;
3259 	info.dpos = nfsd->nd_dpos;
3260 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
3261 
3262 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3263 	fhp = &nfh.fh_generic;
3264 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
3265 	NULLOUT(tl = nfsm_dissect(&info, 6 * NFSX_UNSIGNED));
3266 	toff = fxdr_hyper(tl);
3267 	tl += 2;
3268 #if 0
3269 	verf = fxdr_hyper(tl);
3270 #endif
3271 	tl += 2;
3272 	siz = fxdr_unsigned(int, *tl++);
3273 	cnt = fxdr_unsigned(int, *tl);
3274 	off = toff;
3275 	siz = roundup2(siz, DIRBLKSIZ);
3276 	xfer = NFS_SRVMAXDATA(nfsd);
3277 	if ((unsigned)cnt > xfer)
3278 		cnt = xfer;
3279 	if ((unsigned)siz > xfer)
3280 		siz = xfer;
3281 	fullsiz = siz;
3282 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
3283 			     &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3284 	if (!error && vp->v_type != VDIR) {
3285 		error = ENOTDIR;
3286 		vput(vp);
3287 		vp = NULL;
3288 	}
3289 	if (error) {
3290 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
3291 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3292 		error = 0;
3293 		goto nfsmout;
3294 	}
3295 	error = getret = VOP_GETATTR(vp, &at);
3296 #if 0
3297 	/*
3298 	 * XXX This check may be too strict for Solaris 2.5 clients.
3299 	 */
3300 	if (!error && toff && verf && verf != at.va_filerev)
3301 		error = NFSERR_BAD_COOKIE;
3302 #endif
3303 	if (!error) {
3304 		error = nfsrv_access(mp, vp, VEXEC, cred, rdonly, td, 0);
3305 	}
3306 	if (error) {
3307 		vput(vp);
3308 		vp = NULL;
3309 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3310 				      NFSX_V3POSTOPATTR, &error));
3311 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3312 		error = 0;
3313 		goto nfsmout;
3314 	}
3315 	vn_unlock(vp);
3316 	rbuf = kmalloc(siz, M_TEMP, M_WAITOK);
3317 again:
3318 	iv.iov_base = rbuf;
3319 	iv.iov_len = fullsiz;
3320 	io.uio_iov = &iv;
3321 	io.uio_iovcnt = 1;
3322 	io.uio_offset = (off_t)off;
3323 	io.uio_resid = fullsiz;
3324 	io.uio_segflg = UIO_SYSSPACE;
3325 	io.uio_rw = UIO_READ;
3326 	io.uio_td = NULL;
3327 	eofflag = 0;
3328 	if (cookies) {
3329 		kfree((caddr_t)cookies, M_TEMP);
3330 		cookies = NULL;
3331 	}
3332 	error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
3333 	off = (u_quad_t)io.uio_offset;
3334 	getret = VOP_GETATTR(vp, &at);
3335 	if (!cookies && !error)
3336 		error = NFSERR_PERM;
3337 	if (!error)
3338 		error = getret;
3339 	if (error) {
3340 		vrele(vp);
3341 		vp = NULL;
3342 		if (cookies)
3343 			kfree((caddr_t)cookies, M_TEMP);
3344 		kfree((caddr_t)rbuf, M_TEMP);
3345 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3346 				      NFSX_V3POSTOPATTR, &error));
3347 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3348 		error = 0;
3349 		goto nfsmout;
3350 	}
3351 	if (io.uio_resid) {
3352 		siz -= io.uio_resid;
3353 
3354 		/*
3355 		 * If nothing read, return eof
3356 		 * rpc reply
3357 		 */
3358 		if (siz == 0) {
3359 			vrele(vp);
3360 			vp = NULL;
3361 			NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3362 					      NFSX_V3POSTOPATTR +
3363 					      NFSX_V3COOKIEVERF +
3364 					      2 * NFSX_UNSIGNED,
3365 					      &error));
3366 			nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3367 			tl = nfsm_build(&info, 4 * NFSX_UNSIGNED);
3368 			txdr_hyper(at.va_filerev, tl);
3369 			tl += 2;
3370 			*tl++ = nfs_false;
3371 			*tl = nfs_true;
3372 			kfree((caddr_t)cookies, M_TEMP);
3373 			kfree((caddr_t)rbuf, M_TEMP);
3374 			error = 0;
3375 			goto nfsmout;
3376 		}
3377 	}
3378 
3379 	/*
3380 	 * Check for degenerate cases of nothing useful read.
3381 	 * If so go try again
3382 	 */
3383 	cpos = rbuf;
3384 	cend = rbuf + siz;
3385 	dp = (struct dirent *)cpos;
3386 	cookiep = cookies;
3387 	/*
3388 	 * For some reason FreeBSD's ufs_readdir() chooses to back the
3389 	 * directory offset up to a block boundary, so it is necessary to
3390 	 * skip over the records that preceed the requested offset. This
3391 	 * requires the assumption that file offset cookies monotonically
3392 	 * increase.
3393 	 */
3394 	while (cpos < cend && ncookies > 0 &&
3395 		(dp->d_ino == 0 || dp->d_type == DT_WHT ||
3396 		 ((u_quad_t)(*cookiep)) <= toff)) {
3397 		dp = _DIRENT_NEXT(dp);
3398 		cpos = (char *)dp;
3399 		cookiep++;
3400 		ncookies--;
3401 	}
3402 	if (cpos >= cend || ncookies == 0) {
3403 		toff = off;
3404 		siz = fullsiz;
3405 		goto again;
3406 	}
3407 
3408 	/*
3409 	 * Probe one of the directory entries to see if the filesystem
3410 	 * supports VGET.
3411 	 */
3412 	if (VFS_VGET(vp->v_mount, vp, dp->d_ino, &nvp) == EOPNOTSUPP) {
3413 		error = NFSERR_NOTSUPP;
3414 		vrele(vp);
3415 		vp = NULL;
3416 		kfree((caddr_t)cookies, M_TEMP);
3417 		kfree((caddr_t)rbuf, M_TEMP);
3418 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3419 				      NFSX_V3POSTOPATTR, &error));
3420 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3421 		error = 0;
3422 		goto nfsmout;
3423 	}
3424 	if (nvp) {
3425 		vput(nvp);
3426 		nvp = NULL;
3427 	}
3428 
3429 	dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
3430 			2 * NFSX_UNSIGNED;
3431 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, cnt, &error));
3432 	nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3433 	tl = nfsm_build(&info, 2 * NFSX_UNSIGNED);
3434 	txdr_hyper(at.va_filerev, tl);
3435 	mp1 = mp2 = info.mb;
3436 	bp = info.bpos;
3437 	be = bp + M_TRAILINGSPACE(mp1);
3438 
3439 	/* Loop through the records and build reply */
3440 	while (cpos < cend && ncookies > 0) {
3441 		if (dp->d_ino != 0 && dp->d_type != DT_WHT) {
3442 			nlen = dp->d_namlen;
3443 			rem = nfsm_rndup(nlen) - nlen;
3444 
3445 			/*
3446 			 * For readdir_and_lookup get the vnode using
3447 			 * the file number.
3448 			 */
3449 			if (VFS_VGET(vp->v_mount, vp, dp->d_ino, &nvp))
3450 				goto invalid;
3451 			bzero((caddr_t)nfhp, NFSX_V3FH);
3452 			nfhp->fh_fsid = fhp->fh_fsid;
3453 			if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
3454 				vput(nvp);
3455 				nvp = NULL;
3456 				goto invalid;
3457 			}
3458 			if (VOP_GETATTR(nvp, vap)) {
3459 				vput(nvp);
3460 				nvp = NULL;
3461 				goto invalid;
3462 			}
3463 			vput(nvp);
3464 			nvp = NULL;
3465 
3466 			/*
3467 			 * If either the dircount or maxcount will be
3468 			 * exceeded, get out now. Both of these lengths
3469 			 * are calculated conservatively, including all
3470 			 * XDR overheads.
3471 			 */
3472 			len += (8 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
3473 				NFSX_V3POSTOPATTR);
3474 			dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
3475 			if (len > cnt || dirlen > fullsiz) {
3476 				eofflag = 0;
3477 				break;
3478 			}
3479 
3480 			/*
3481 			 * Build the directory record xdr from
3482 			 * the dirent entry.
3483 			 */
3484 			fp = (struct nfs_fattr *)&fl.fl_fattr;
3485 			nfsm_srvfattr(nfsd, vap, fp);
3486 			fl.fl_off.nfsuquad[0] = txdr_unsigned(*cookiep >> 32);
3487 			fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
3488 			fl.fl_postopok = nfs_true;
3489 			fl.fl_fhok = nfs_true;
3490 			fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
3491 
3492 			tl = nfsm_clget(&info, mp1, mp2, bp, be);
3493 			*tl = nfs_true;
3494 			bp += NFSX_UNSIGNED;
3495 			tl = nfsm_clget(&info, mp1, mp2, bp, be);
3496 			*tl = txdr_unsigned(dp->d_ino >> 32);
3497 			bp += NFSX_UNSIGNED;
3498 			tl = nfsm_clget(&info, mp1, mp2, bp, be);
3499 			*tl = txdr_unsigned(dp->d_ino);
3500 			bp += NFSX_UNSIGNED;
3501 			tl = nfsm_clget(&info, mp1, mp2, bp, be);
3502 			*tl = txdr_unsigned(nlen);
3503 			bp += NFSX_UNSIGNED;
3504 
3505 			/* And loop around copying the name */
3506 			xfer = nlen;
3507 			cp = dp->d_name;
3508 			while (xfer > 0) {
3509 				tl = nfsm_clget(&info, mp1, mp2, bp, be);
3510 				if ((bp + xfer) > be)
3511 					tsiz = be - bp;
3512 				else
3513 					tsiz = xfer;
3514 				bcopy(cp, bp, tsiz);
3515 				bp += tsiz;
3516 				xfer -= tsiz;
3517 				cp += tsiz;
3518 			}
3519 			/* And null pad to a int32_t boundary */
3520 			for (i = 0; i < rem; i++)
3521 				*bp++ = '\0';
3522 
3523 			/*
3524 			 * Now copy the flrep structure out.
3525 			 */
3526 			xfer = sizeof (struct flrep);
3527 			cp = (caddr_t)&fl;
3528 			while (xfer > 0) {
3529 				tl = nfsm_clget(&info, mp1, mp2, bp, be);
3530 				if ((bp + xfer) > be)
3531 					tsiz = be - bp;
3532 				else
3533 					tsiz = xfer;
3534 				bcopy(cp, bp, tsiz);
3535 				bp += tsiz;
3536 				xfer -= tsiz;
3537 				cp += tsiz;
3538 			}
3539 		}
3540 invalid:
3541 		dp = _DIRENT_NEXT(dp);
3542 		cpos = (char *)dp;
3543 		cookiep++;
3544 		ncookies--;
3545 	}
3546 	vrele(vp);
3547 	vp = NULL;
3548 	tl = nfsm_clget(&info, mp1, mp2, bp, be);
3549 	*tl = nfs_false;
3550 	bp += NFSX_UNSIGNED;
3551 	tl = nfsm_clget(&info, mp1, mp2, bp, be);
3552 	if (eofflag)
3553 		*tl = nfs_true;
3554 	else
3555 		*tl = nfs_false;
3556 	bp += NFSX_UNSIGNED;
3557 	if (mp1 != info.mb) {
3558 		if (bp < be)
3559 			mp1->m_len = bp - mtod(mp1, caddr_t);
3560 	} else
3561 		mp1->m_len += bp - info.bpos;
3562 	kfree((caddr_t)cookies, M_TEMP);
3563 	kfree((caddr_t)rbuf, M_TEMP);
3564 nfsmout:
3565 	*mrq = info.mreq;
3566 	if (vp)
3567 		vrele(vp);
3568 	return(error);
3569 }
3570 
3571 /*
3572  * nfs commit service
3573  */
3574 int
3575 nfsrv_commit(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3576 	     struct thread *td, struct mbuf **mrq)
3577 {
3578 	struct sockaddr *nam = nfsd->nd_nam;
3579 	struct ucred *cred = &nfsd->nd_cr;
3580 	struct vattr bfor, aft;
3581 	struct vnode *vp = NULL;
3582 	struct mount *mp = NULL;
3583 	nfsfh_t nfh;
3584 	fhandle_t *fhp;
3585 	u_int32_t *tl;
3586 	int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt;
3587 	u_quad_t off;
3588 	struct nfsm_info info;
3589 
3590 	info.mrep = nfsd->nd_mrep;
3591 	info.mreq = NULL;
3592 	info.md = nfsd->nd_md;
3593 	info.dpos = nfsd->nd_dpos;
3594 
3595 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3596 	fhp = &nfh.fh_generic;
3597 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
3598 	NULLOUT(tl = nfsm_dissect(&info, 3 * NFSX_UNSIGNED));
3599 
3600 	/*
3601 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
3602 	 * count parameters, so these arguments are useless (someday maybe).
3603 	 */
3604 	off = fxdr_hyper(tl);
3605 	tl += 2;
3606 	cnt = fxdr_unsigned(int, *tl);
3607 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
3608 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3609 	if (error) {
3610 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3611 				      2 * NFSX_UNSIGNED, &error));
3612 		nfsm_srvwcc_data(&info, nfsd, for_ret, &bfor,
3613 				 aft_ret, &aft);
3614 		error = 0;
3615 		goto nfsmout;
3616 	}
3617 	for_ret = VOP_GETATTR(vp, &bfor);
3618 
3619 	/*
3620 	 * RFC 1813 3.3.21: If count is 0, a flush from offset to the end of
3621 	 * file is done. At this time VOP_FSYNC does not accept offset and
3622 	 * byte count parameters, so call VOP_FSYNC the whole file for now.
3623 	 */
3624 	if (cnt == 0 || cnt > MAX_COMMIT_COUNT) {
3625 		/*
3626 		 * Give up and do the whole thing
3627 		 */
3628 		if (vp->v_object &&
3629 		   (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
3630 			vm_object_page_clean(vp->v_object, 0, 0, OBJPC_SYNC);
3631 		}
3632 		error = VOP_FSYNC(vp, MNT_WAIT, 0);
3633 	} else {
3634 		/*
3635 		 * Locate and synchronously write any buffers that fall
3636 		 * into the requested range.  Note:  we are assuming that
3637 		 * f_iosize is a power of 2.
3638 		 */
3639 		int iosize = vp->v_mount->mnt_stat.f_iosize;
3640 		int iomask = iosize - 1;
3641 		off_t loffset;
3642 
3643 		/*
3644 		 * Align to iosize boundry, super-align to page boundry.
3645 		 */
3646 		if (off & iomask) {
3647 			cnt += off & iomask;
3648 			off &= ~(u_quad_t)iomask;
3649 		}
3650 		if (off & PAGE_MASK) {
3651 			cnt += off & PAGE_MASK;
3652 			off &= ~(u_quad_t)PAGE_MASK;
3653 		}
3654 		loffset = off;
3655 
3656 		if (vp->v_object &&
3657 		   (vp->v_object->flags & OBJ_MIGHTBEDIRTY)) {
3658 			vm_object_page_clean(vp->v_object, off / PAGE_SIZE,
3659 			    (cnt + PAGE_MASK) / PAGE_SIZE, OBJPC_SYNC);
3660 		}
3661 
3662 		crit_enter();
3663 		while (error == 0 || cnt > 0) {
3664 			struct buf *bp;
3665 
3666 			/*
3667 			 * If we have a buffer and it is marked B_DELWRI we
3668 			 * have to lock and write it.  Otherwise the prior
3669 			 * write is assumed to have already been committed.
3670 			 *
3671 			 * WARNING: FINDBLK_TEST buffers represent stable
3672 			 *	    storage but not necessarily stable
3673 			 *	    content.  It is ok in this case.
3674 			 */
3675 			if ((bp = findblk(vp, loffset, FINDBLK_TEST)) != NULL) {
3676 				if (bp->b_flags & B_DELWRI)
3677 					bp = findblk(vp, loffset, 0);
3678 				else
3679 					bp = NULL;
3680 			}
3681 			if (bp) {
3682 				if (bp->b_flags & B_DELWRI) {
3683 					bremfree(bp);
3684 					error = bwrite(bp);
3685 					++nfs_commit_miss;
3686 				} else {
3687 					BUF_UNLOCK(bp);
3688 				}
3689 			}
3690 			++nfs_commit_blks;
3691 			if (cnt < iosize)
3692 				break;
3693 			cnt -= iosize;
3694 			loffset += iosize;
3695 		}
3696 		crit_exit();
3697 	}
3698 
3699 	aft_ret = VOP_GETATTR(vp, &aft);
3700 	vput(vp);
3701 	vp = NULL;
3702 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3703 			      NFSX_V3WCCDATA + NFSX_V3WRITEVERF,
3704 			      &error));
3705 	nfsm_srvwcc_data(&info, nfsd, for_ret, &bfor,
3706 			 aft_ret, &aft);
3707 	if (!error) {
3708 		tl = nfsm_build(&info, NFSX_V3WRITEVERF);
3709 		if (nfsver.tv_sec == 0)
3710 			nfsver = boottime;
3711 		*tl++ = txdr_unsigned(nfsver.tv_sec);
3712 		*tl = txdr_unsigned(nfsver.tv_nsec / 1000);
3713 	} else {
3714 		error = 0;
3715 	}
3716 nfsmout:
3717 	*mrq = info.mreq;
3718 	if (vp)
3719 		vput(vp);
3720 	return(error);
3721 }
3722 
3723 /*
3724  * nfs statfs service
3725  */
3726 int
3727 nfsrv_statfs(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3728 	     struct thread *td, struct mbuf **mrq)
3729 {
3730 	struct sockaddr *nam = nfsd->nd_nam;
3731 	struct ucred *cred = &nfsd->nd_cr;
3732 	struct statfs *sf;
3733 	struct nfs_statfs *sfp;
3734 	int error = 0, rdonly, getret = 1;
3735 	struct vnode *vp = NULL;
3736 	struct mount *mp = NULL;
3737 	struct vattr at;
3738 	nfsfh_t nfh;
3739 	fhandle_t *fhp;
3740 	struct statfs statfs;
3741 	u_quad_t tval;
3742 	struct nfsm_info info;
3743 
3744 	info.mrep = nfsd->nd_mrep;
3745 	info.mreq = NULL;
3746 	info.md = nfsd->nd_md;
3747 	info.dpos = nfsd->nd_dpos;
3748 	info.v3 = (nfsd->nd_flag & ND_NFSV3);
3749 
3750 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3751 	fhp = &nfh.fh_generic;
3752 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
3753 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
3754 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3755 	if (error) {
3756 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
3757 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3758 		error = 0;
3759 		goto nfsmout;
3760 	}
3761 	sf = &statfs;
3762 	error = VFS_STATFS(vp->v_mount, sf, proc0.p_ucred);
3763 	getret = VOP_GETATTR(vp, &at);
3764 	vput(vp);
3765 	vp = NULL;
3766 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3767 			      NFSX_POSTOPATTR(info.v3) + NFSX_STATFS(info.v3),
3768 			      &error));
3769 	if (info.v3)
3770 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3771 	if (error) {
3772 		error = 0;
3773 		goto nfsmout;
3774 	}
3775 	sfp = nfsm_build(&info, NFSX_STATFS(info.v3));
3776 	if (info.v3) {
3777 		tval = (u_quad_t)sf->f_blocks;
3778 		tval *= (u_quad_t)sf->f_bsize;
3779 		txdr_hyper(tval, &sfp->sf_tbytes);
3780 		tval = (u_quad_t)sf->f_bfree;
3781 		tval *= (u_quad_t)sf->f_bsize;
3782 		txdr_hyper(tval, &sfp->sf_fbytes);
3783 		tval = (u_quad_t)sf->f_bavail;
3784 		tval *= (u_quad_t)sf->f_bsize;
3785 		txdr_hyper(tval, &sfp->sf_abytes);
3786 		sfp->sf_tfiles.nfsuquad[0] = 0;
3787 		sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3788 		sfp->sf_ffiles.nfsuquad[0] = 0;
3789 		sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3790 		sfp->sf_afiles.nfsuquad[0] = 0;
3791 		sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3792 		sfp->sf_invarsec = 0;
3793 	} else {
3794 		sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3795 		sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3796 		sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3797 		sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3798 		sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
3799 	}
3800 nfsmout:
3801 	*mrq = info.mreq;
3802 	if (vp)
3803 		vput(vp);
3804 	return(error);
3805 }
3806 
3807 /*
3808  * nfs fsinfo service
3809  */
3810 int
3811 nfsrv_fsinfo(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3812 	     struct thread *td, struct mbuf **mrq)
3813 {
3814 	struct sockaddr *nam = nfsd->nd_nam;
3815 	struct ucred *cred = &nfsd->nd_cr;
3816 	struct nfsv3_fsinfo *sip;
3817 	int error = 0, rdonly, getret = 1, pref;
3818 	struct vnode *vp = NULL;
3819 	struct mount *mp = NULL;
3820 	struct vattr at;
3821 	nfsfh_t nfh;
3822 	fhandle_t *fhp;
3823 	u_quad_t maxfsize;
3824 	struct statfs sb;
3825 	struct nfsm_info info;
3826 
3827 	info.mrep = nfsd->nd_mrep;
3828 	info.mreq = NULL;
3829 	info.md = nfsd->nd_md;
3830 	info.dpos = nfsd->nd_dpos;
3831 
3832 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3833 	fhp = &nfh.fh_generic;
3834 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
3835 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
3836 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3837 	if (error) {
3838 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
3839 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3840 		error = 0;
3841 		goto nfsmout;
3842 	}
3843 
3844 	/* XXX Try to make a guess on the max file size. */
3845 	VFS_STATFS(vp->v_mount, &sb, proc0.p_ucred);
3846 	maxfsize = (u_quad_t)0x80000000 * sb.f_bsize - 1;
3847 
3848 	getret = VOP_GETATTR(vp, &at);
3849 	vput(vp);
3850 	vp = NULL;
3851 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3852 			      NFSX_V3POSTOPATTR + NFSX_V3FSINFO, &error));
3853 	nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3854 	sip = nfsm_build(&info, NFSX_V3FSINFO);
3855 
3856 	/*
3857 	 * XXX
3858 	 * There should be file system VFS OP(s) to get this information.
3859 	 * For now, assume ufs.
3860 	 */
3861 	if (slp->ns_so->so_type == SOCK_DGRAM)
3862 		pref = NFS_MAXDGRAMDATA;
3863 	else
3864 		pref = NFS_MAXDATA;
3865 	sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3866 	sip->fs_rtpref = txdr_unsigned(pref);
3867 	sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3868 	sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3869 	sip->fs_wtpref = txdr_unsigned(pref);
3870 	sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3871 	sip->fs_dtpref = txdr_unsigned(pref);
3872 	txdr_hyper(maxfsize, &sip->fs_maxfilesize);
3873 	sip->fs_timedelta.nfsv3_sec = 0;
3874 	sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3875 	sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3876 		NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3877 		NFSV3FSINFO_CANSETTIME);
3878 nfsmout:
3879 	*mrq = info.mreq;
3880 	if (vp)
3881 		vput(vp);
3882 	return(error);
3883 }
3884 
3885 /*
3886  * nfs pathconf service
3887  */
3888 int
3889 nfsrv_pathconf(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3890 	       struct thread *td, struct mbuf **mrq)
3891 {
3892 	struct sockaddr *nam = nfsd->nd_nam;
3893 	struct ucred *cred = &nfsd->nd_cr;
3894 	struct nfsv3_pathconf *pc;
3895 	int error = 0, rdonly, getret = 1;
3896 	register_t linkmax, namemax, chownres, notrunc;
3897 	struct vnode *vp = NULL;
3898 	struct mount *mp = NULL;
3899 	struct vattr at;
3900 	nfsfh_t nfh;
3901 	fhandle_t *fhp;
3902 	struct nfsm_info info;
3903 
3904 	info.mrep = nfsd->nd_mrep;
3905 	info.mreq = NULL;
3906 	info.md = nfsd->nd_md;
3907 	info.dpos = nfsd->nd_dpos;
3908 
3909 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3910 	fhp = &nfh.fh_generic;
3911 	NEGREPLYOUT(nfsm_srvmtofh(&info, nfsd, fhp, &error));
3912 	error = nfsrv_fhtovp(fhp, 1, &mp, &vp, cred, slp, nam,
3913 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH), TRUE);
3914 	if (error) {
3915 		NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, NFSX_UNSIGNED, &error));
3916 		nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3917 		error = 0;
3918 		goto nfsmout;
3919 	}
3920 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3921 	if (!error)
3922 		error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3923 	if (!error)
3924 		error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3925 	if (!error)
3926 		error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
3927 	getret = VOP_GETATTR(vp, &at);
3928 	vput(vp);
3929 	vp = NULL;
3930 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp,
3931 			      NFSX_V3POSTOPATTR + NFSX_V3PATHCONF,
3932 			      &error));
3933 	nfsm_srvpostop_attr(&info, nfsd, getret, &at);
3934 	if (error) {
3935 		error = 0;
3936 		goto nfsmout;
3937 	}
3938 	pc = nfsm_build(&info, NFSX_V3PATHCONF);
3939 
3940 	pc->pc_linkmax = txdr_unsigned(linkmax);
3941 	pc->pc_namemax = txdr_unsigned(namemax);
3942 	pc->pc_notrunc = txdr_unsigned(notrunc);
3943 	pc->pc_chownrestricted = txdr_unsigned(chownres);
3944 
3945 	/*
3946 	 * These should probably be supported by VOP_PATHCONF(), but
3947 	 * until msdosfs is exportable (why would you want to?), the
3948 	 * Unix defaults should be ok.
3949 	 */
3950 	pc->pc_caseinsensitive = nfs_false;
3951 	pc->pc_casepreserving = nfs_true;
3952 nfsmout:
3953 	*mrq = info.mreq;
3954 	if (vp)
3955 		vput(vp);
3956 	return(error);
3957 }
3958 
3959 /*
3960  * Null operation, used by clients to ping server
3961  */
3962 /* ARGSUSED */
3963 int
3964 nfsrv_null(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3965 	   struct thread *td, struct mbuf **mrq)
3966 {
3967 	struct nfsm_info info;
3968 	int error = NFSERR_RETVOID;
3969 
3970 	info.mrep = nfsd->nd_mrep;
3971 	info.mreq = NULL;
3972 
3973 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3974 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error));
3975 nfsmout:
3976 	*mrq = info.mreq;
3977 	return (error);
3978 }
3979 
3980 /*
3981  * No operation, used for obsolete procedures
3982  */
3983 /* ARGSUSED */
3984 int
3985 nfsrv_noop(struct nfsrv_descript *nfsd, struct nfssvc_sock *slp,
3986 	   struct thread *td, struct mbuf **mrq)
3987 {
3988 	struct nfsm_info info;
3989 	int error;
3990 
3991 	info.mrep = nfsd->nd_mrep;
3992 	info.mreq = NULL;
3993 
3994 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
3995 	if (nfsd->nd_repstat)
3996 		error = nfsd->nd_repstat;
3997 	else
3998 		error = EPROCUNAVAIL;
3999 	NEGKEEPOUT(nfsm_reply(&info, nfsd, slp, 0, &error));
4000 	error = 0;
4001 nfsmout:
4002 	*mrq = info.mreq;
4003 	return (error);
4004 }
4005 
4006 /*
4007  * Perform access checking for vnodes obtained from file handles that would
4008  * refer to files already opened by a Unix client. You cannot just use
4009  * vn_writechk() and VOP_ACCESS() for two reasons:
4010  *
4011  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
4012  * 2 - The owner is to be given access irrespective of mode bits for some
4013  *     operations, so that processes that chmod after opening a file don't
4014  *     break. I don't like this because it opens a security hole, but since
4015  *     the nfs server opens a security hole the size of a barn door anyhow,
4016  *     what the heck.
4017  *
4018  * The exception to rule 2 is EPERM. If a file is IMMUTABLE, VOP_ACCESS()
4019  * will return EPERM instead of EACCESS. EPERM is always an error.
4020  */
4021 static int
4022 nfsrv_access(struct mount *mp, struct vnode *vp, int flags, struct ucred *cred,
4023 	     int rdonly, struct thread *td, int override)
4024 {
4025 	struct vattr vattr;
4026 	int error;
4027 
4028 	nfsdbprintf(("%s %d\n", __FILE__, __LINE__));
4029 	if (flags & VWRITE) {
4030 		/* Just vn_writechk() changed to check rdonly */
4031 		/*
4032 		 * Disallow write attempts on read-only file systems;
4033 		 * unless the file is a socket or a block or character
4034 		 * device resident on the file system.
4035 		 */
4036 		if (rdonly ||
4037 		    ((mp->mnt_flag | vp->v_mount->mnt_flag) & MNT_RDONLY)) {
4038 			switch (vp->v_type) {
4039 			case VREG:
4040 			case VDIR:
4041 			case VLNK:
4042 				return (EROFS);
4043 			default:
4044 				break;
4045 			}
4046 		}
4047 		/*
4048 		 * If there's shared text associated with
4049 		 * the inode, we can't allow writing.
4050 		 */
4051 		if (vp->v_flag & VTEXT)
4052 			return (ETXTBSY);
4053 	}
4054 	error = VOP_GETATTR(vp, &vattr);
4055 	if (error)
4056 		return (error);
4057 	error = VOP_ACCESS(vp, flags, cred);	/* XXX ruid/rgid vs uid/gid */
4058 	/*
4059 	 * Allow certain operations for the owner (reads and writes
4060 	 * on files that are already open).
4061 	 */
4062 	if (override && error == EACCES && cred->cr_uid == vattr.va_uid)
4063 		error = 0;
4064 	return error;
4065 }
4066 #endif /* NFS_NOSERVER */
4067 
4068