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