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