xref: /csrg-svn/sys/nfs/nfs_serv.c (revision 68653)
138418Smckusick /*
263233Sbostic  * Copyright (c) 1989, 1993
363233Sbostic  *	The Regents of the University of California.  All rights reserved.
438418Smckusick  *
538418Smckusick  * This code is derived from software contributed to Berkeley by
638418Smckusick  * Rick Macklem at The University of Guelph.
738418Smckusick  *
844510Sbostic  * %sccs.include.redist.c%
938418Smckusick  *
10*68653Smckusick  *	@(#)nfs_serv.c	8.6 (Berkeley) 03/30/95
1138418Smckusick  */
1238418Smckusick 
1338418Smckusick /*
14*68653Smckusick  * nfs version 2 and 3 server calls to vnode ops
1538418Smckusick  * - these routines generally have 3 phases
1638418Smckusick  *   1 - break down and validate rpc request in mbuf list
1738418Smckusick  *   2 - do the vnode ops for the request
1838425Smckusick  *       (surprisingly ?? many are very similar to syscalls in vfs_syscalls.c)
1938418Smckusick  *   3 - build the rpc reply in an mbuf list
2038418Smckusick  *   nb:
2138418Smckusick  *	- do not mix the phases, since the nfsm_?? macros can return failures
2241899Smckusick  *	  on a bad rpc or similar and do not do any vrele() or vput()'s
2338418Smckusick  *
2438425Smckusick  *      - the nfsm_reply() macro generates an nfs rpc reply with the nfs
2538418Smckusick  *	error number iff error != 0 whereas
2641899Smckusick  *	returning an error from the server function implies a fatal error
2741899Smckusick  *	such as a badly constructed rpc request that should be dropped without
2841899Smckusick  *	a reply.
29*68653Smckusick  *	For Version 3, nfsm_reply() does not return for the error case, since
30*68653Smckusick  *	most version 3 rpcs return more than the status for error cases.
3138418Smckusick  */
3238418Smckusick 
3353322Smckusick #include <sys/param.h>
3455073Spendry #include <sys/systm.h>
3553322Smckusick #include <sys/proc.h>
3653322Smckusick #include <sys/file.h>
3753322Smckusick #include <sys/namei.h>
3853322Smckusick #include <sys/vnode.h>
3953322Smckusick #include <sys/mount.h>
40*68653Smckusick #include <sys/socket.h>
41*68653Smckusick #include <sys/socketvar.h>
4253322Smckusick #include <sys/mbuf.h>
4353322Smckusick #include <sys/dirent.h>
4454446Smckusick #include <sys/stat.h>
45*68653Smckusick #include <sys/kernel.h>
46*68653Smckusick #include <ufs/ufs/dir.h>
4747573Skarels 
4853322Smckusick #include <vm/vm.h>
4947573Skarels 
50*68653Smckusick #include <nfs/nfsproto.h>
5153322Smckusick #include <nfs/rpcv2.h>
5253322Smckusick #include <nfs/nfs.h>
5353322Smckusick #include <nfs/xdr_subs.h>
5453322Smckusick #include <nfs/nfsm_subs.h>
5553322Smckusick #include <nfs/nqnfs.h>
5653322Smckusick 
5738418Smckusick /* Global vars */
5838418Smckusick extern u_long nfs_xdrneg1;
5938418Smckusick extern u_long nfs_false, nfs_true;
60*68653Smckusick extern enum vtype nv3tov_type[8];
61*68653Smckusick extern struct nfsstats nfsstats;
62*68653Smckusick nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
6342242Smckusick 		      NFCHR, NFNON };
64*68653Smckusick nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
65*68653Smckusick 		      NFFIFO, NFNON };
66*68653Smckusick int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
6738418Smckusick 
6838418Smckusick /*
69*68653Smckusick  * nfs v3 access service
7056360Smckusick  */
71*68653Smckusick int
72*68653Smckusick nfsrv3_access(nfsd, slp, procp, mrq)
73*68653Smckusick 	struct nfsrv_descript *nfsd;
74*68653Smckusick 	struct nfssvc_sock *slp;
75*68653Smckusick 	struct proc *procp;
76*68653Smckusick 	struct mbuf **mrq;
7756360Smckusick {
78*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
79*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
80*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
81*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
8256360Smckusick 	struct vnode *vp;
83*68653Smckusick 	nfsfh_t nfh;
8456360Smckusick 	fhandle_t *fhp;
8556360Smckusick 	register u_long *tl;
8656360Smckusick 	register long t1;
8756360Smckusick 	caddr_t bpos;
88*68653Smckusick 	int error = 0, rdonly, cache, getret;
8956360Smckusick 	char *cp2;
90*68653Smckusick 	struct mbuf *mb, *mreq, *mb2;
91*68653Smckusick 	struct vattr vattr, *vap = &vattr;
92*68653Smckusick 	u_long testmode, nfsmode;
9356360Smckusick 	u_quad_t frev;
9456360Smckusick 
95*68653Smckusick #ifndef nolint
96*68653Smckusick 	cache = 0;
97*68653Smckusick #endif
9856360Smckusick 	fhp = &nfh.fh_generic;
9956360Smckusick 	nfsm_srvmtofh(fhp);
100*68653Smckusick 	nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
101*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
102*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
103*68653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
104*68653Smckusick 		nfsm_srvpostop_attr(1, (struct vattr *)0);
105*68653Smckusick 		return (0);
106*68653Smckusick 	}
107*68653Smckusick 	nfsmode = fxdr_unsigned(u_long, *tl);
108*68653Smckusick 	if ((nfsmode & NFSV3ACCESS_READ) &&
109*68653Smckusick 		nfsrv_access(vp, VREAD, cred, rdonly, procp))
110*68653Smckusick 		nfsmode &= ~NFSV3ACCESS_READ;
111*68653Smckusick 	if (vp->v_type == VDIR)
112*68653Smckusick 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
113*68653Smckusick 			NFSV3ACCESS_DELETE);
114*68653Smckusick 	else
115*68653Smckusick 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
116*68653Smckusick 	if ((nfsmode & testmode) &&
117*68653Smckusick 		nfsrv_access(vp, VWRITE, cred, rdonly, procp))
118*68653Smckusick 		nfsmode &= ~testmode;
119*68653Smckusick 	if (vp->v_type == VDIR)
120*68653Smckusick 		testmode = NFSV3ACCESS_LOOKUP;
121*68653Smckusick 	else
122*68653Smckusick 		testmode = NFSV3ACCESS_EXECUTE;
123*68653Smckusick 	if ((nfsmode & testmode) &&
124*68653Smckusick 		nfsrv_access(vp, VEXEC, cred, rdonly, procp))
125*68653Smckusick 		nfsmode &= ~testmode;
126*68653Smckusick 	getret = VOP_GETATTR(vp, vap, cred, procp);
12756360Smckusick 	vput(vp);
128*68653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
129*68653Smckusick 	nfsm_srvpostop_attr(getret, vap);
130*68653Smckusick 	nfsm_build(tl, u_long *, NFSX_UNSIGNED);
131*68653Smckusick 	*tl = txdr_unsigned(nfsmode);
13256360Smckusick 	nfsm_srvdone;
13356360Smckusick }
13456360Smckusick 
13556360Smckusick /*
13638418Smckusick  * nfs getattr service
13738418Smckusick  */
138*68653Smckusick int
139*68653Smckusick nfsrv_getattr(nfsd, slp, procp, mrq)
140*68653Smckusick 	struct nfsrv_descript *nfsd;
141*68653Smckusick 	struct nfssvc_sock *slp;
142*68653Smckusick 	struct proc *procp;
143*68653Smckusick 	struct mbuf **mrq;
14438418Smckusick {
145*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
146*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
147*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
148*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
149*68653Smckusick 	register struct nfs_fattr *fp;
15038418Smckusick 	struct vattr va;
15138418Smckusick 	register struct vattr *vap = &va;
15238418Smckusick 	struct vnode *vp;
153*68653Smckusick 	nfsfh_t nfh;
15438418Smckusick 	fhandle_t *fhp;
15548050Smckusick 	register u_long *tl;
15639494Smckusick 	register long t1;
15739494Smckusick 	caddr_t bpos;
15852196Smckusick 	int error = 0, rdonly, cache;
15939494Smckusick 	char *cp2;
16039753Smckusick 	struct mbuf *mb, *mb2, *mreq;
16152196Smckusick 	u_quad_t frev;
16238418Smckusick 
16338418Smckusick 	fhp = &nfh.fh_generic;
16438418Smckusick 	nfsm_srvmtofh(fhp);
165*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
166*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
16738418Smckusick 		nfsm_reply(0);
168*68653Smckusick 		return (0);
169*68653Smckusick 	}
170*68653Smckusick 	nqsrv_getl(vp, ND_READ);
171*68653Smckusick 	error = VOP_GETATTR(vp, vap, cred, procp);
17238418Smckusick 	vput(vp);
173*68653Smckusick 	nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
174*68653Smckusick 	if (error)
175*68653Smckusick 		return (0);
176*68653Smckusick 	nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
177*68653Smckusick 	nfsm_srvfillattr(vap, fp);
17838418Smckusick 	nfsm_srvdone;
17938418Smckusick }
18038418Smckusick 
18138418Smckusick /*
18238418Smckusick  * nfs setattr service
18338418Smckusick  */
184*68653Smckusick int
185*68653Smckusick nfsrv_setattr(nfsd, slp, procp, mrq)
186*68653Smckusick 	struct nfsrv_descript *nfsd;
187*68653Smckusick 	struct nfssvc_sock *slp;
188*68653Smckusick 	struct proc *procp;
189*68653Smckusick 	struct mbuf **mrq;
19038418Smckusick {
191*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
192*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
193*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
194*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
195*68653Smckusick 	struct vattr va, preat;
19638418Smckusick 	register struct vattr *vap = &va;
19738884Smacklem 	register struct nfsv2_sattr *sp;
198*68653Smckusick 	register struct nfs_fattr *fp;
19938418Smckusick 	struct vnode *vp;
200*68653Smckusick 	nfsfh_t nfh;
20138418Smckusick 	fhandle_t *fhp;
20248050Smckusick 	register u_long *tl;
20339494Smckusick 	register long t1;
20439494Smckusick 	caddr_t bpos;
205*68653Smckusick 	int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
206*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
20739494Smckusick 	char *cp2;
20839753Smckusick 	struct mbuf *mb, *mb2, *mreq;
209*68653Smckusick 	u_quad_t frev;
210*68653Smckusick 	struct timespec guard;
21138418Smckusick 
21238418Smckusick 	fhp = &nfh.fh_generic;
21338418Smckusick 	nfsm_srvmtofh(fhp);
21441361Smckusick 	VATTR_NULL(vap);
215*68653Smckusick 	if (v3) {
216*68653Smckusick 		nfsm_srvsattr(vap);
217*68653Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
218*68653Smckusick 		gcheck = fxdr_unsigned(int, *tl);
219*68653Smckusick 		if (gcheck) {
220*68653Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
221*68653Smckusick 			fxdr_nfsv3time(tl, &guard);
222*68653Smckusick 		}
223*68653Smckusick 	} else {
224*68653Smckusick 		nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
225*68653Smckusick 		/*
226*68653Smckusick 		 * Nah nah nah nah na nah
227*68653Smckusick 		 * There is a bug in the Sun client that puts 0xffff in the mode
228*68653Smckusick 		 * field of sattr when it should put in 0xffffffff. The u_short
229*68653Smckusick 		 * doesn't sign extend.
230*68653Smckusick 		 * --> check the low order 2 bytes for 0xffff
231*68653Smckusick 		 */
232*68653Smckusick 		if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
233*68653Smckusick 			vap->va_mode = nfstov_mode(sp->sa_mode);
234*68653Smckusick 		if (sp->sa_uid != nfs_xdrneg1)
235*68653Smckusick 			vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
236*68653Smckusick 		if (sp->sa_gid != nfs_xdrneg1)
237*68653Smckusick 			vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
238*68653Smckusick 		if (sp->sa_size != nfs_xdrneg1)
239*68653Smckusick 			vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
240*68653Smckusick 		if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
24158880Smckusick #ifdef notyet
242*68653Smckusick 			fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
24358880Smckusick #else
24458880Smckusick 			vap->va_atime.ts_sec =
245*68653Smckusick 				fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
24656285Smckusick 			vap->va_atime.ts_nsec = 0;
24758880Smckusick #endif
24856285Smckusick 		}
249*68653Smckusick 		if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
250*68653Smckusick 			fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
251*68653Smckusick 
25238425Smckusick 	}
25359526Smckusick 
25459526Smckusick 	/*
255*68653Smckusick 	 * Now that we have all the fields, lets do it.
256*68653Smckusick 	 */
257*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
258*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
259*68653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
260*68653Smckusick 		nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
261*68653Smckusick 		return (0);
262*68653Smckusick 	}
263*68653Smckusick 	nqsrv_getl(vp, ND_WRITE);
264*68653Smckusick 	if (v3) {
265*68653Smckusick 		error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
266*68653Smckusick 		if (!error && gcheck &&
267*68653Smckusick 			(preat.va_ctime.ts_sec != guard.ts_sec ||
268*68653Smckusick 			 preat.va_ctime.ts_nsec != guard.ts_nsec))
269*68653Smckusick 			error = NFSERR_NOT_SYNC;
270*68653Smckusick 		if (error) {
271*68653Smckusick 			vput(vp);
272*68653Smckusick 			nfsm_reply(NFSX_WCCDATA(v3));
273*68653Smckusick 			nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
274*68653Smckusick 			return (0);
275*68653Smckusick 		}
276*68653Smckusick 	}
277*68653Smckusick 
278*68653Smckusick 	/*
27959526Smckusick 	 * If the size is being changed write acces is required, otherwise
28059526Smckusick 	 * just check for a read only file system.
28159526Smckusick 	 */
28259526Smckusick 	if (vap->va_size == ((u_quad_t)((quad_t) -1))) {
28359526Smckusick 		if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
28459526Smckusick 			error = EROFS;
28559526Smckusick 			goto out;
28659526Smckusick 		}
28759526Smckusick 	} else {
28859526Smckusick 		if (vp->v_type == VDIR) {
28959526Smckusick 			error = EISDIR;
29059526Smckusick 			goto out;
29159526Smckusick 		} else if (error = nfsrv_access(vp, VWRITE, cred, rdonly,
292*68653Smckusick 			procp))
29359526Smckusick 			goto out;
29459526Smckusick 	}
295*68653Smckusick 	error = VOP_SETATTR(vp, vap, cred, procp);
296*68653Smckusick 	postat_ret = VOP_GETATTR(vp, vap, cred, procp);
297*68653Smckusick 	if (!error)
298*68653Smckusick 		error = postat_ret;
29938418Smckusick out:
30038418Smckusick 	vput(vp);
301*68653Smckusick 	nfsm_reply(NFSX_WCCORFATTR(v3));
302*68653Smckusick 	if (v3) {
303*68653Smckusick 		nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
304*68653Smckusick 		return (0);
305*68653Smckusick 	} else {
306*68653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
307*68653Smckusick 		nfsm_srvfillattr(vap, fp);
30852196Smckusick 	}
30938418Smckusick 	nfsm_srvdone;
31038418Smckusick }
31138418Smckusick 
31238418Smckusick /*
31338418Smckusick  * nfs lookup rpc
31438418Smckusick  */
315*68653Smckusick int
316*68653Smckusick nfsrv_lookup(nfsd, slp, procp, mrq)
317*68653Smckusick 	struct nfsrv_descript *nfsd;
318*68653Smckusick 	struct nfssvc_sock *slp;
319*68653Smckusick 	struct proc *procp;
320*68653Smckusick 	struct mbuf **mrq;
32138418Smckusick {
322*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
323*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
324*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
325*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
326*68653Smckusick 	register struct nfs_fattr *fp;
32749742Smckusick 	struct nameidata nd;
328*68653Smckusick 	struct vnode *vp, *dirp;
329*68653Smckusick 	nfsfh_t nfh;
33038418Smckusick 	fhandle_t *fhp;
33139494Smckusick 	register caddr_t cp;
33248050Smckusick 	register u_long *tl;
33339494Smckusick 	register long t1;
33439494Smckusick 	caddr_t bpos;
335*68653Smckusick 	int error = 0, cache, len, dirattr_ret = 1;
336*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
33739494Smckusick 	char *cp2;
33839753Smckusick 	struct mbuf *mb, *mb2, *mreq;
339*68653Smckusick 	struct vattr va, dirattr, *vap = &va;
340*68653Smckusick 	u_quad_t frev;
34138418Smckusick 
34238418Smckusick 	fhp = &nfh.fh_generic;
34338418Smckusick 	nfsm_srvmtofh(fhp);
344*68653Smckusick 	nfsm_srvnamesiz(len);
34552316Sheideman 	nd.ni_cnd.cn_cred = cred;
34652316Sheideman 	nd.ni_cnd.cn_nameiop = LOOKUP;
34752316Sheideman 	nd.ni_cnd.cn_flags = LOCKLEAF | SAVESTART;
348*68653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
349*68653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
350*68653Smckusick 	if (dirp) {
351*68653Smckusick 		if (v3)
352*68653Smckusick 			dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
353*68653Smckusick 				procp);
354*68653Smckusick 		vrele(dirp);
355*68653Smckusick 	}
356*68653Smckusick 	if (error) {
357*68653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3));
358*68653Smckusick 		nfsm_srvpostop_attr(dirattr_ret, &dirattr);
359*68653Smckusick 		return (0);
360*68653Smckusick 	}
361*68653Smckusick 	nqsrv_getl(nd.ni_startdir, ND_READ);
36252196Smckusick 	vrele(nd.ni_startdir);
36352653Smckusick 	FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
36449742Smckusick 	vp = nd.ni_vp;
36538418Smckusick 	bzero((caddr_t)fhp, sizeof(nfh));
36641398Smckusick 	fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
367*68653Smckusick 	error = VFS_VPTOFH(vp, &fhp->fh_fid);
368*68653Smckusick 	if (!error)
369*68653Smckusick 		error = VOP_GETATTR(vp, vap, cred, procp);
37038418Smckusick 	vput(vp);
371*68653Smckusick 	nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
372*68653Smckusick 	if (error) {
373*68653Smckusick 		nfsm_srvpostop_attr(dirattr_ret, &dirattr);
374*68653Smckusick 		return (0);
37552196Smckusick 	}
376*68653Smckusick 	nfsm_srvfhtom(fhp, v3);
377*68653Smckusick 	if (v3) {
378*68653Smckusick 		nfsm_srvpostop_attr(0, vap);
379*68653Smckusick 		nfsm_srvpostop_attr(dirattr_ret, &dirattr);
380*68653Smckusick 	} else {
381*68653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
382*68653Smckusick 		nfsm_srvfillattr(vap, fp);
383*68653Smckusick 	}
38438418Smckusick 	nfsm_srvdone;
38538418Smckusick }
38638418Smckusick 
38738418Smckusick /*
38838418Smckusick  * nfs readlink service
38938418Smckusick  */
390*68653Smckusick int
391*68653Smckusick nfsrv_readlink(nfsd, slp, procp, mrq)
392*68653Smckusick 	struct nfsrv_descript *nfsd;
393*68653Smckusick 	struct nfssvc_sock *slp;
394*68653Smckusick 	struct proc *procp;
395*68653Smckusick 	struct mbuf **mrq;
39638418Smckusick {
397*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
398*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
399*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
400*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
40141899Smckusick 	struct iovec iv[(NFS_MAXPATHLEN+MLEN-1)/MLEN];
40238418Smckusick 	register struct iovec *ivp = iv;
40338418Smckusick 	register struct mbuf *mp;
40448050Smckusick 	register u_long *tl;
40539494Smckusick 	register long t1;
40639494Smckusick 	caddr_t bpos;
407*68653Smckusick 	int error = 0, rdonly, cache, i, tlen, len, getret;
408*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
40939494Smckusick 	char *cp2;
41039753Smckusick 	struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
41138418Smckusick 	struct vnode *vp;
412*68653Smckusick 	struct vattr attr;
413*68653Smckusick 	nfsfh_t nfh;
41438418Smckusick 	fhandle_t *fhp;
41538418Smckusick 	struct uio io, *uiop = &io;
41652196Smckusick 	u_quad_t frev;
41738418Smckusick 
418*68653Smckusick #ifndef nolint
419*68653Smckusick 	mp2 = mp3 = (struct mbuf *)0;
420*68653Smckusick #endif
42138418Smckusick 	fhp = &nfh.fh_generic;
42238418Smckusick 	nfsm_srvmtofh(fhp);
42338418Smckusick 	len = 0;
42438418Smckusick 	i = 0;
42538418Smckusick 	while (len < NFS_MAXPATHLEN) {
42638418Smckusick 		MGET(mp, M_WAIT, MT_DATA);
42741899Smckusick 		MCLGET(mp, M_WAIT);
42838418Smckusick 		mp->m_len = NFSMSIZ(mp);
42938418Smckusick 		if (len == 0)
43038418Smckusick 			mp3 = mp2 = mp;
43141899Smckusick 		else {
43238418Smckusick 			mp2->m_next = mp;
43341899Smckusick 			mp2 = mp;
43441899Smckusick 		}
43538418Smckusick 		if ((len+mp->m_len) > NFS_MAXPATHLEN) {
43638418Smckusick 			mp->m_len = NFS_MAXPATHLEN-len;
43738418Smckusick 			len = NFS_MAXPATHLEN;
43838418Smckusick 		} else
43938418Smckusick 			len += mp->m_len;
44038418Smckusick 		ivp->iov_base = mtod(mp, caddr_t);
44138418Smckusick 		ivp->iov_len = mp->m_len;
44238418Smckusick 		i++;
44338418Smckusick 		ivp++;
44438418Smckusick 	}
44538418Smckusick 	uiop->uio_iov = iv;
44638418Smckusick 	uiop->uio_iovcnt = i;
44738418Smckusick 	uiop->uio_offset = 0;
44838418Smckusick 	uiop->uio_resid = len;
44938418Smckusick 	uiop->uio_rw = UIO_READ;
45038418Smckusick 	uiop->uio_segflg = UIO_SYSSPACE;
45148050Smckusick 	uiop->uio_procp = (struct proc *)0;
452*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
453*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
45438418Smckusick 		m_freem(mp3);
455*68653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
456*68653Smckusick 		nfsm_srvpostop_attr(1, (struct vattr *)0);
457*68653Smckusick 		return (0);
45838418Smckusick 	}
45938418Smckusick 	if (vp->v_type != VLNK) {
460*68653Smckusick 		if (v3)
461*68653Smckusick 			error = EINVAL;
462*68653Smckusick 		else
463*68653Smckusick 			error = ENXIO;
46438418Smckusick 		goto out;
46538418Smckusick 	}
466*68653Smckusick 	nqsrv_getl(vp, ND_READ);
46738418Smckusick 	error = VOP_READLINK(vp, uiop, cred);
46838418Smckusick out:
469*68653Smckusick 	getret = VOP_GETATTR(vp, &attr, cred, procp);
47038418Smckusick 	vput(vp);
47138418Smckusick 	if (error)
47238418Smckusick 		m_freem(mp3);
473*68653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
474*68653Smckusick 	if (v3) {
475*68653Smckusick 		nfsm_srvpostop_attr(getret, &attr);
476*68653Smckusick 		if (error)
477*68653Smckusick 			return (0);
478*68653Smckusick 	}
47938418Smckusick 	if (uiop->uio_resid > 0) {
48038418Smckusick 		len -= uiop->uio_resid;
48138418Smckusick 		tlen = nfsm_rndup(len);
48238418Smckusick 		nfsm_adj(mp3, NFS_MAXPATHLEN-tlen, tlen-len);
48338418Smckusick 	}
48448050Smckusick 	nfsm_build(tl, u_long *, NFSX_UNSIGNED);
48548050Smckusick 	*tl = txdr_unsigned(len);
48638418Smckusick 	mb->m_next = mp3;
48738418Smckusick 	nfsm_srvdone;
48838418Smckusick }
48938418Smckusick 
49038418Smckusick /*
49138418Smckusick  * nfs read service
49238418Smckusick  */
493*68653Smckusick int
494*68653Smckusick nfsrv_read(nfsd, slp, procp, mrq)
495*68653Smckusick 	struct nfsrv_descript *nfsd;
496*68653Smckusick 	struct nfssvc_sock *slp;
497*68653Smckusick 	struct proc *procp;
498*68653Smckusick 	struct mbuf **mrq;
49938418Smckusick {
500*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
501*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
502*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
503*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
50443350Smckusick 	register struct iovec *iv;
50543350Smckusick 	struct iovec *iv2;
50641899Smckusick 	register struct mbuf *m;
507*68653Smckusick 	register struct nfs_fattr *fp;
50848050Smckusick 	register u_long *tl;
50939494Smckusick 	register long t1;
510*68653Smckusick 	register int i;
51139494Smckusick 	caddr_t bpos;
512*68653Smckusick 	int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
513*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3), reqlen;
51439494Smckusick 	char *cp2;
51539753Smckusick 	struct mbuf *mb, *mb2, *mreq;
51652196Smckusick 	struct mbuf *m2;
51738418Smckusick 	struct vnode *vp;
518*68653Smckusick 	nfsfh_t nfh;
51938418Smckusick 	fhandle_t *fhp;
52038418Smckusick 	struct uio io, *uiop = &io;
52138418Smckusick 	struct vattr va, *vap = &va;
52238418Smckusick 	off_t off;
52352196Smckusick 	u_quad_t frev;
52438418Smckusick 
52538418Smckusick 	fhp = &nfh.fh_generic;
52638418Smckusick 	nfsm_srvmtofh(fhp);
527*68653Smckusick 	if (v3) {
528*68653Smckusick 		nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
529*68653Smckusick 		fxdr_hyper(tl, &off);
530*68653Smckusick 	} else {
53156285Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
53256285Smckusick 		off = (off_t)fxdr_unsigned(u_long, *tl);
53356285Smckusick 	}
534*68653Smckusick 	nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
535*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
536*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
537*68653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
538*68653Smckusick 		nfsm_srvpostop_attr(1, (struct vattr *)0);
539*68653Smckusick 		return (0);
540*68653Smckusick 	}
54160186Smckusick 	if (vp->v_type != VREG) {
542*68653Smckusick 		if (v3)
543*68653Smckusick 			error = EINVAL;
544*68653Smckusick 		else
545*68653Smckusick 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
54660186Smckusick 	}
547*68653Smckusick 	if (!error) {
548*68653Smckusick 	    nqsrv_getl(vp, ND_READ);
549*68653Smckusick 	    if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp))
550*68653Smckusick 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
55138418Smckusick 	}
552*68653Smckusick 	getret = VOP_GETATTR(vp, vap, cred, procp);
553*68653Smckusick 	if (!error)
554*68653Smckusick 		error = getret;
555*68653Smckusick 	if (error) {
55638418Smckusick 		vput(vp);
557*68653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3));
558*68653Smckusick 		nfsm_srvpostop_attr(getret, vap);
559*68653Smckusick 		return (0);
56038418Smckusick 	}
56152196Smckusick 	if (off >= vap->va_size)
56252196Smckusick 		cnt = 0;
563*68653Smckusick 	else if ((off + reqlen) > vap->va_size)
56452196Smckusick 		cnt = nfsm_rndup(vap->va_size - off);
565*68653Smckusick 	else
566*68653Smckusick 		cnt = reqlen;
567*68653Smckusick 	nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
568*68653Smckusick 	if (v3) {
569*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
570*68653Smckusick 		*tl++ = nfs_true;
571*68653Smckusick 		fp = (struct nfs_fattr *)tl;
572*68653Smckusick 		tl += (NFSX_V3FATTR / sizeof (u_long));
573*68653Smckusick 	} else {
574*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
575*68653Smckusick 		fp = (struct nfs_fattr *)tl;
576*68653Smckusick 		tl += (NFSX_V2FATTR / sizeof (u_long));
577*68653Smckusick 	}
57852196Smckusick 	len = left = cnt;
57952196Smckusick 	if (cnt > 0) {
58052196Smckusick 		/*
58152196Smckusick 		 * Generate the mbuf list with the uio_iov ref. to it.
58252196Smckusick 		 */
58352196Smckusick 		i = 0;
58452196Smckusick 		m = m2 = mb;
58552196Smckusick 		while (left > 0) {
58655057Spendry 			siz = min(M_TRAILINGSPACE(m), left);
58752196Smckusick 			if (siz > 0) {
588*68653Smckusick 				left -= siz;
58952196Smckusick 				i++;
59052196Smckusick 			}
59152196Smckusick 			if (left > 0) {
59252196Smckusick 				MGET(m, M_WAIT, MT_DATA);
59352196Smckusick 				MCLGET(m, M_WAIT);
59452196Smckusick 				m->m_len = 0;
59552196Smckusick 				m2->m_next = m;
59652196Smckusick 				m2 = m;
59752196Smckusick 			}
59852196Smckusick 		}
599*68653Smckusick 		MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
600*68653Smckusick 		       M_TEMP, M_WAITOK);
601*68653Smckusick 		uiop->uio_iov = iv2 = iv;
602*68653Smckusick 		m = mb;
603*68653Smckusick 		left = cnt;
604*68653Smckusick 		i = 0;
605*68653Smckusick 		while (left > 0) {
606*68653Smckusick 			if (m == NULL)
607*68653Smckusick 				panic("nfsrv_read iov");
608*68653Smckusick 			siz = min(M_TRAILINGSPACE(m), left);
609*68653Smckusick 			if (siz > 0) {
610*68653Smckusick 				iv->iov_base = mtod(m, caddr_t) + m->m_len;
611*68653Smckusick 				iv->iov_len = siz;
612*68653Smckusick 				m->m_len += siz;
613*68653Smckusick 				left -= siz;
614*68653Smckusick 				iv++;
615*68653Smckusick 				i++;
616*68653Smckusick 			}
617*68653Smckusick 			m = m->m_next;
618*68653Smckusick 		}
61952196Smckusick 		uiop->uio_iovcnt = i;
62052196Smckusick 		uiop->uio_offset = off;
62152196Smckusick 		uiop->uio_resid = cnt;
62252196Smckusick 		uiop->uio_rw = UIO_READ;
62352196Smckusick 		uiop->uio_segflg = UIO_SYSSPACE;
62452196Smckusick 		error = VOP_READ(vp, uiop, IO_NODELOCKED, cred);
62552196Smckusick 		off = uiop->uio_offset;
62652196Smckusick 		FREE((caddr_t)iv2, M_TEMP);
627*68653Smckusick 		if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
628*68653Smckusick 			if (!error)
629*68653Smckusick 				error = getret;
63052196Smckusick 			m_freem(mreq);
63152196Smckusick 			vput(vp);
632*68653Smckusick 			nfsm_reply(NFSX_POSTOPATTR(v3));
633*68653Smckusick 			nfsm_srvpostop_attr(getret, vap);
634*68653Smckusick 			return (0);
63552196Smckusick 		}
63652196Smckusick 	} else
63752196Smckusick 		uiop->uio_resid = 0;
63838418Smckusick 	vput(vp);
639*68653Smckusick 	nfsm_srvfillattr(vap, fp);
64045877Smckusick 	len -= uiop->uio_resid;
64152196Smckusick 	tlen = nfsm_rndup(len);
64252196Smckusick 	if (cnt != tlen || tlen != len)
643*68653Smckusick 		nfsm_adj(mb, cnt - tlen, tlen - len);
644*68653Smckusick 	if (v3) {
645*68653Smckusick 		*tl++ = txdr_unsigned(len);
646*68653Smckusick 		if (len < reqlen)
647*68653Smckusick 			*tl++ = nfs_true;
648*68653Smckusick 		else
649*68653Smckusick 			*tl++ = nfs_false;
650*68653Smckusick 	}
65148050Smckusick 	*tl = txdr_unsigned(len);
65238418Smckusick 	nfsm_srvdone;
65338418Smckusick }
65438418Smckusick 
65538418Smckusick /*
65638418Smckusick  * nfs write service
65738418Smckusick  */
658*68653Smckusick int
659*68653Smckusick nfsrv_write(nfsd, slp, procp, mrq)
660*68653Smckusick 	struct nfsrv_descript *nfsd;
661*68653Smckusick 	struct nfssvc_sock *slp;
662*68653Smckusick 	struct proc *procp;
663*68653Smckusick 	struct mbuf **mrq;
66438418Smckusick {
665*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
666*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
667*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
668*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
66938418Smckusick 	register struct iovec *ivp;
670*68653Smckusick 	register int i, cnt;
67138418Smckusick 	register struct mbuf *mp;
672*68653Smckusick 	register struct nfs_fattr *fp;
673*68653Smckusick 	struct iovec *iv;
674*68653Smckusick 	struct vattr va, forat;
67538418Smckusick 	register struct vattr *vap = &va;
67648050Smckusick 	register u_long *tl;
67739494Smckusick 	register long t1;
67839494Smckusick 	caddr_t bpos;
679*68653Smckusick 	int error = 0, rdonly, cache, siz, len, xfer, forat_ret = 1;
680*68653Smckusick 	int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
681*68653Smckusick 	int stable = NFSV3WRITE_FILESYNC;
682*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
68339494Smckusick 	char *cp2;
68439753Smckusick 	struct mbuf *mb, *mb2, *mreq;
68538418Smckusick 	struct vnode *vp;
686*68653Smckusick 	nfsfh_t nfh;
68738418Smckusick 	fhandle_t *fhp;
68838418Smckusick 	struct uio io, *uiop = &io;
68938418Smckusick 	off_t off;
69052196Smckusick 	u_quad_t frev;
69138418Smckusick 
692*68653Smckusick 	if (mrep == NULL) {
693*68653Smckusick 		*mrq = NULL;
694*68653Smckusick 		return (0);
695*68653Smckusick 	}
69638418Smckusick 	fhp = &nfh.fh_generic;
69738418Smckusick 	nfsm_srvmtofh(fhp);
698*68653Smckusick 	if (v3) {
699*68653Smckusick 		nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
700*68653Smckusick 		fxdr_hyper(tl, &off);
701*68653Smckusick 		tl += 3;
702*68653Smckusick 		stable = fxdr_unsigned(int, *tl++);
703*68653Smckusick 	} else {
704*68653Smckusick 		nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
70556285Smckusick 		off = (off_t)fxdr_unsigned(u_long, *++tl);
70656285Smckusick 		tl += 2;
70756285Smckusick 	}
708*68653Smckusick 	retlen = len = fxdr_unsigned(long, *tl);
709*68653Smckusick 	cnt = i = 0;
710*68653Smckusick 
711*68653Smckusick 	/*
712*68653Smckusick 	 * For NFS Version 2, it is not obvious what a write of zero length
713*68653Smckusick 	 * should do, but I might as well be consistent with Version 3,
714*68653Smckusick 	 * which is to return ok so long as there are no permission problems.
715*68653Smckusick 	 */
716*68653Smckusick 	if (len > 0) {
717*68653Smckusick 	    zeroing = 1;
718*68653Smckusick 	    mp = mrep;
719*68653Smckusick 	    while (mp) {
720*68653Smckusick 		if (mp == md) {
721*68653Smckusick 			zeroing = 0;
722*68653Smckusick 			adjust = dpos - mtod(mp, caddr_t);
723*68653Smckusick 			mp->m_len -= adjust;
724*68653Smckusick 			if (mp->m_len > 0 && adjust > 0)
725*68653Smckusick 				NFSMADV(mp, adjust);
72638418Smckusick 		}
727*68653Smckusick 		if (zeroing)
728*68653Smckusick 			mp->m_len = 0;
729*68653Smckusick 		else if (mp->m_len > 0) {
730*68653Smckusick 			i += mp->m_len;
731*68653Smckusick 			if (i > len) {
732*68653Smckusick 				mp->m_len -= (i - len);
733*68653Smckusick 				zeroing	= 1;
734*68653Smckusick 			}
735*68653Smckusick 			if (mp->m_len > 0)
736*68653Smckusick 				cnt++;
737*68653Smckusick 		}
738*68653Smckusick 		mp = mp->m_next;
739*68653Smckusick 	    }
74038418Smckusick 	}
741*68653Smckusick 	if (len > NFS_MAXDATA || len < 0 || i < len) {
742*68653Smckusick 		error = EIO;
743*68653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
744*68653Smckusick 		nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
745*68653Smckusick 		return (0);
746*68653Smckusick 	}
747*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
748*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
749*68653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
750*68653Smckusick 		nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
751*68653Smckusick 		return (0);
752*68653Smckusick 	}
753*68653Smckusick 	if (v3)
754*68653Smckusick 		forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
75560186Smckusick 	if (vp->v_type != VREG) {
756*68653Smckusick 		if (v3)
757*68653Smckusick 			error = EINVAL;
758*68653Smckusick 		else
759*68653Smckusick 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
76060186Smckusick 	}
761*68653Smckusick 	if (!error) {
762*68653Smckusick 		nqsrv_getl(vp, ND_WRITE);
763*68653Smckusick 		error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
764*68653Smckusick 	}
765*68653Smckusick 	if (error) {
76638418Smckusick 		vput(vp);
767*68653Smckusick 		nfsm_reply(NFSX_WCCDATA(v3));
768*68653Smckusick 		nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
769*68653Smckusick 		return (0);
77038418Smckusick 	}
771*68653Smckusick 
772*68653Smckusick 	if (len > 0) {
773*68653Smckusick 	    MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
774*68653Smckusick 		M_WAITOK);
775*68653Smckusick 	    uiop->uio_iov = iv = ivp;
776*68653Smckusick 	    uiop->uio_iovcnt = cnt;
777*68653Smckusick 	    mp = mrep;
778*68653Smckusick 	    while (mp) {
779*68653Smckusick 		if (mp->m_len > 0) {
780*68653Smckusick 			ivp->iov_base = mtod(mp, caddr_t);
781*68653Smckusick 			ivp->iov_len = mp->m_len;
782*68653Smckusick 			ivp++;
783*68653Smckusick 		}
784*68653Smckusick 		mp = mp->m_next;
785*68653Smckusick 	    }
786*68653Smckusick 
787*68653Smckusick 	    /*
788*68653Smckusick 	     * XXX
789*68653Smckusick 	     * The IO_METASYNC flag indicates that all metadata (and not just
790*68653Smckusick 	     * enough to ensure data integrity) mus be written to stable storage
791*68653Smckusick 	     * synchronously.
792*68653Smckusick 	     * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
793*68653Smckusick 	     */
794*68653Smckusick 	    if (stable == NFSV3WRITE_UNSTABLE)
795*68653Smckusick 		ioflags = IO_NODELOCKED;
796*68653Smckusick 	    else if (stable == NFSV3WRITE_DATASYNC)
797*68653Smckusick 		ioflags = (IO_SYNC | IO_NODELOCKED);
798*68653Smckusick 	    else
799*68653Smckusick 		ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
800*68653Smckusick 	    uiop->uio_resid = len;
801*68653Smckusick 	    uiop->uio_rw = UIO_WRITE;
802*68653Smckusick 	    uiop->uio_segflg = UIO_SYSSPACE;
803*68653Smckusick 	    uiop->uio_procp = (struct proc *)0;
804*68653Smckusick 	    uiop->uio_offset = off;
805*68653Smckusick 	    error = VOP_WRITE(vp, uiop, ioflags, cred);
806*68653Smckusick 	    nfsstats.srvvop_writes++;
807*68653Smckusick 	    FREE((caddr_t)iv, M_TEMP);
808*68653Smckusick 	}
809*68653Smckusick 	aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
810*68653Smckusick 	vput(vp);
811*68653Smckusick 	if (!error)
812*68653Smckusick 		error = aftat_ret;
813*68653Smckusick 	nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
814*68653Smckusick 		2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
815*68653Smckusick 	if (v3) {
816*68653Smckusick 		nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
817*68653Smckusick 		if (error)
818*68653Smckusick 			return (0);
819*68653Smckusick 		nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
820*68653Smckusick 		*tl++ = txdr_unsigned(retlen);
821*68653Smckusick 		if (stable == NFSV3WRITE_UNSTABLE)
822*68653Smckusick 			*tl++ = txdr_unsigned(stable);
823*68653Smckusick 		else
824*68653Smckusick 			*tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
825*68653Smckusick 		/*
826*68653Smckusick 		 * Actually, there is no need to txdr these fields,
827*68653Smckusick 		 * but it may make the values more human readable,
828*68653Smckusick 		 * for debugging purposes.
829*68653Smckusick 		 */
830*68653Smckusick 		*tl++ = txdr_unsigned(boottime.tv_sec);
831*68653Smckusick 		*tl = txdr_unsigned(boottime.tv_usec);
832*68653Smckusick 	} else {
833*68653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
834*68653Smckusick 		nfsm_srvfillattr(vap, fp);
835*68653Smckusick 	}
836*68653Smckusick 	nfsm_srvdone;
837*68653Smckusick }
838*68653Smckusick 
839*68653Smckusick /*
840*68653Smckusick  * NFS write service with write gathering support. Called when
841*68653Smckusick  * nfsrvw_procrastinate > 0.
842*68653Smckusick  * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
843*68653Smckusick  * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
844*68653Smckusick  * Jan. 1994.
845*68653Smckusick  */
846*68653Smckusick int
847*68653Smckusick nfsrv_writegather(ndp, slp, procp, mrq)
848*68653Smckusick 	struct nfsrv_descript **ndp;
849*68653Smckusick 	struct nfssvc_sock *slp;
850*68653Smckusick 	struct proc *procp;
851*68653Smckusick 	struct mbuf **mrq;
852*68653Smckusick {
853*68653Smckusick 	register struct iovec *ivp;
854*68653Smckusick 	register struct mbuf *mp;
855*68653Smckusick 	register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
856*68653Smckusick 	register struct nfs_fattr *fp;
857*68653Smckusick 	register int i;
858*68653Smckusick 	struct iovec *iov;
859*68653Smckusick 	struct nfsrvw_delayhash *wpp;
860*68653Smckusick 	struct ucred *cred;
861*68653Smckusick 	struct vattr va, forat;
862*68653Smckusick 	register u_long *tl;
863*68653Smckusick 	register long t1;
864*68653Smckusick 	caddr_t bpos, dpos;
865*68653Smckusick 	int error = 0, rdonly, cache, len, forat_ret = 1;
866*68653Smckusick 	int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
867*68653Smckusick 	char *cp2;
868*68653Smckusick 	struct mbuf *mb, *mb2, *mreq, *mrep, *md;
869*68653Smckusick 	struct vnode *vp;
870*68653Smckusick 	struct uio io, *uiop = &io;
871*68653Smckusick 	off_t off;
872*68653Smckusick 	u_quad_t frev, cur_usec;
873*68653Smckusick 
874*68653Smckusick #ifndef nolint
875*68653Smckusick 	i = 0;
876*68653Smckusick 	len = 0;
877*68653Smckusick #endif
878*68653Smckusick 	*mrq = NULL;
879*68653Smckusick 	if (*ndp) {
880*68653Smckusick 	    nfsd = *ndp;
881*68653Smckusick 	    *ndp = NULL;
882*68653Smckusick 	    mrep = nfsd->nd_mrep;
883*68653Smckusick 	    md = nfsd->nd_md;
884*68653Smckusick 	    dpos = nfsd->nd_dpos;
885*68653Smckusick 	    cred = &nfsd->nd_cr;
886*68653Smckusick 	    v3 = (nfsd->nd_flag & ND_NFSV3);
887*68653Smckusick 	    LIST_INIT(&nfsd->nd_coalesce);
888*68653Smckusick 	    nfsd->nd_mreq = NULL;
889*68653Smckusick 	    nfsd->nd_stable = NFSV3WRITE_FILESYNC;
890*68653Smckusick 	    cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
891*68653Smckusick 	    nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
892*68653Smckusick 
893*68653Smckusick 	    /*
894*68653Smckusick 	     * Now, get the write header..
895*68653Smckusick 	     */
896*68653Smckusick 	    nfsm_srvmtofh(&nfsd->nd_fh);
897*68653Smckusick 	    if (v3) {
898*68653Smckusick 		nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
899*68653Smckusick 		fxdr_hyper(tl, &nfsd->nd_off);
900*68653Smckusick 		tl += 3;
901*68653Smckusick 		nfsd->nd_stable = fxdr_unsigned(int, *tl++);
902*68653Smckusick 	    } else {
903*68653Smckusick 		nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
904*68653Smckusick 		nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
905*68653Smckusick 		tl += 2;
906*68653Smckusick 	    }
907*68653Smckusick 	    len = fxdr_unsigned(long, *tl);
908*68653Smckusick 	    nfsd->nd_len = len;
909*68653Smckusick 	    nfsd->nd_eoff = nfsd->nd_off + len;
910*68653Smckusick 
911*68653Smckusick 	    /*
912*68653Smckusick 	     * Trim the header out of the mbuf list and trim off any trailing
913*68653Smckusick 	     * junk so that the mbuf list has only the write data.
914*68653Smckusick 	     */
915*68653Smckusick 	    zeroing = 1;
916*68653Smckusick 	    i = 0;
917*68653Smckusick 	    mp = mrep;
918*68653Smckusick 	    while (mp) {
919*68653Smckusick 		if (mp == md) {
920*68653Smckusick 		    zeroing = 0;
921*68653Smckusick 		    adjust = dpos - mtod(mp, caddr_t);
922*68653Smckusick 		    mp->m_len -= adjust;
923*68653Smckusick 		    if (mp->m_len > 0 && adjust > 0)
924*68653Smckusick 			NFSMADV(mp, adjust);
925*68653Smckusick 		}
926*68653Smckusick 		if (zeroing)
927*68653Smckusick 		    mp->m_len = 0;
928*68653Smckusick 		else {
929*68653Smckusick 		    i += mp->m_len;
930*68653Smckusick 		    if (i > len) {
931*68653Smckusick 			mp->m_len -= (i - len);
932*68653Smckusick 			zeroing = 1;
933*68653Smckusick 		    }
934*68653Smckusick 		}
935*68653Smckusick 		mp = mp->m_next;
936*68653Smckusick 	    }
937*68653Smckusick 	    if (len > NFS_MAXDATA || len < 0  || i < len) {
938*68653Smckusick nfsmout:
939*68653Smckusick 		m_freem(mrep);
940*68653Smckusick 		error = EIO;
941*68653Smckusick 		nfsm_writereply(2 * NFSX_UNSIGNED, v3);
942*68653Smckusick 		if (v3)
943*68653Smckusick 		    nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
944*68653Smckusick 		nfsd->nd_mreq = mreq;
945*68653Smckusick 		nfsd->nd_mrep = NULL;
946*68653Smckusick 		nfsd->nd_time = 0;
947*68653Smckusick 	    }
948*68653Smckusick 
949*68653Smckusick 	    /*
950*68653Smckusick 	     * Add this entry to the hash and time queues.
951*68653Smckusick 	     */
952*68653Smckusick 	    s = splsoftclock();
953*68653Smckusick 	    owp = NULL;
954*68653Smckusick 	    wp = slp->ns_tq.lh_first;
955*68653Smckusick 	    while (wp && wp->nd_time < nfsd->nd_time) {
956*68653Smckusick 		owp = wp;
957*68653Smckusick 		wp = wp->nd_tq.le_next;
958*68653Smckusick 	    }
959*68653Smckusick 	    if (owp) {
960*68653Smckusick 		LIST_INSERT_AFTER(owp, nfsd, nd_tq);
961*68653Smckusick 	    } else {
962*68653Smckusick 		LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
963*68653Smckusick 	    }
964*68653Smckusick 	    if (nfsd->nd_mrep) {
965*68653Smckusick 		wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
966*68653Smckusick 		owp = NULL;
967*68653Smckusick 		wp = wpp->lh_first;
968*68653Smckusick 		while (wp &&
969*68653Smckusick 		    bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
970*68653Smckusick 		    owp = wp;
971*68653Smckusick 		    wp = wp->nd_hash.le_next;
972*68653Smckusick 		}
973*68653Smckusick 		while (wp && wp->nd_off < nfsd->nd_off &&
974*68653Smckusick 		    !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
975*68653Smckusick 		    owp = wp;
976*68653Smckusick 		    wp = wp->nd_hash.le_next;
977*68653Smckusick 		}
978*68653Smckusick 		if (owp) {
979*68653Smckusick 		    LIST_INSERT_AFTER(owp, nfsd, nd_hash);
980*68653Smckusick 
981*68653Smckusick 		    /*
982*68653Smckusick 		     * Search the hash list for overlapping entries and
983*68653Smckusick 		     * coalesce.
984*68653Smckusick 		     */
985*68653Smckusick 		    for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
986*68653Smckusick 			wp = nfsd->nd_hash.le_next;
987*68653Smckusick 			if (NFSW_SAMECRED(owp, nfsd))
988*68653Smckusick 			    nfsrvw_coalesce(owp, nfsd);
989*68653Smckusick 		    }
990*68653Smckusick 		} else {
991*68653Smckusick 		    LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
992*68653Smckusick 		}
993*68653Smckusick 	    }
994*68653Smckusick 	    splx(s);
995*68653Smckusick 	}
996*68653Smckusick 
99738418Smckusick 	/*
998*68653Smckusick 	 * Now, do VOP_WRITE()s for any one(s) that need to be done now
999*68653Smckusick 	 * and generate the associated reply mbuf list(s).
100038418Smckusick 	 */
1001*68653Smckusick loop1:
1002*68653Smckusick 	cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
1003*68653Smckusick 	s = splsoftclock();
1004*68653Smckusick 	for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
1005*68653Smckusick 		owp = nfsd->nd_tq.le_next;
1006*68653Smckusick 		if (nfsd->nd_time > cur_usec)
1007*68653Smckusick 		    break;
1008*68653Smckusick 		if (nfsd->nd_mreq)
1009*68653Smckusick 		    continue;
1010*68653Smckusick 		LIST_REMOVE(nfsd, nd_tq);
1011*68653Smckusick 		LIST_REMOVE(nfsd, nd_hash);
1012*68653Smckusick 		splx(s);
1013*68653Smckusick 		mrep = nfsd->nd_mrep;
1014*68653Smckusick 		nfsd->nd_mrep = NULL;
1015*68653Smckusick 		cred = &nfsd->nd_cr;
1016*68653Smckusick 		v3 = (nfsd->nd_flag & ND_NFSV3);
1017*68653Smckusick 		forat_ret = aftat_ret = 1;
1018*68653Smckusick 		error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
1019*68653Smckusick 		    nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
1020*68653Smckusick 		if (!error) {
1021*68653Smckusick 		    if (v3)
1022*68653Smckusick 			forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
1023*68653Smckusick 		    if (vp->v_type != VREG) {
1024*68653Smckusick 			if (v3)
1025*68653Smckusick 			    error = EINVAL;
102638418Smckusick 			else
1027*68653Smckusick 			    error = (vp->v_type == VDIR) ? EISDIR : EACCES;
1028*68653Smckusick 		    }
1029*68653Smckusick 		} else
1030*68653Smckusick 		    vp = NULL;
1031*68653Smckusick 		if (!error) {
1032*68653Smckusick 		    nqsrv_getl(vp, ND_WRITE);
1033*68653Smckusick 		    error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
1034*68653Smckusick 		}
1035*68653Smckusick 
1036*68653Smckusick 		if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
1037*68653Smckusick 		    ioflags = IO_NODELOCKED;
1038*68653Smckusick 		else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
1039*68653Smckusick 		    ioflags = (IO_SYNC | IO_NODELOCKED);
1040*68653Smckusick 		else
1041*68653Smckusick 		    ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
1042*68653Smckusick 		uiop->uio_rw = UIO_WRITE;
1043*68653Smckusick 		uiop->uio_segflg = UIO_SYSSPACE;
1044*68653Smckusick 		uiop->uio_procp = (struct proc *)0;
1045*68653Smckusick 		uiop->uio_offset = nfsd->nd_off;
1046*68653Smckusick 		uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
1047*68653Smckusick 		if (uiop->uio_resid > 0) {
1048*68653Smckusick 		    mp = mrep;
1049*68653Smckusick 		    i = 0;
1050*68653Smckusick 		    while (mp) {
1051*68653Smckusick 			if (mp->m_len > 0)
1052*68653Smckusick 			    i++;
105338418Smckusick 			mp = mp->m_next;
1054*68653Smckusick 		    }
1055*68653Smckusick 		    uiop->uio_iovcnt = i;
1056*68653Smckusick 		    MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
1057*68653Smckusick 			M_TEMP, M_WAITOK);
1058*68653Smckusick 		    uiop->uio_iov = ivp = iov;
1059*68653Smckusick 		    mp = mrep;
1060*68653Smckusick 		    while (mp) {
1061*68653Smckusick 			if (mp->m_len > 0) {
1062*68653Smckusick 			    ivp->iov_base = mtod(mp, caddr_t);
1063*68653Smckusick 			    ivp->iov_len = mp->m_len;
1064*68653Smckusick 			    ivp++;
1065*68653Smckusick 			}
1066*68653Smckusick 			mp = mp->m_next;
1067*68653Smckusick 		    }
1068*68653Smckusick 		    if (!error) {
1069*68653Smckusick 			error = VOP_WRITE(vp, uiop, ioflags, cred);
1070*68653Smckusick 			nfsstats.srvvop_writes++;
1071*68653Smckusick 		    }
1072*68653Smckusick 		    FREE((caddr_t)iov, M_TEMP);
107338418Smckusick 		}
1074*68653Smckusick 		m_freem(mrep);
1075*68653Smckusick 		if (vp) {
1076*68653Smckusick 		    aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
1077*68653Smckusick 		    vput(vp);
107838418Smckusick 		}
1079*68653Smckusick 
1080*68653Smckusick 		/*
1081*68653Smckusick 		 * Loop around generating replies for all write rpcs that have
1082*68653Smckusick 		 * now been completed.
1083*68653Smckusick 		 */
1084*68653Smckusick 		swp = nfsd;
1085*68653Smckusick 		do {
1086*68653Smckusick 		    if (error) {
1087*68653Smckusick 			nfsm_writereply(NFSX_WCCDATA(v3), v3);
1088*68653Smckusick 			if (v3) {
1089*68653Smckusick 			    nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1090*68653Smckusick 			}
1091*68653Smckusick 		    } else {
1092*68653Smckusick 			nfsm_writereply(NFSX_PREOPATTR(v3) +
1093*68653Smckusick 			    NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
1094*68653Smckusick 			    NFSX_WRITEVERF(v3), v3);
1095*68653Smckusick 			if (v3) {
1096*68653Smckusick 			    nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
1097*68653Smckusick 			    nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
1098*68653Smckusick 			    *tl++ = txdr_unsigned(nfsd->nd_len);
1099*68653Smckusick 			    *tl++ = txdr_unsigned(swp->nd_stable);
1100*68653Smckusick 			    /*
1101*68653Smckusick 			     * Actually, there is no need to txdr these fields,
1102*68653Smckusick 			     * but it may make the values more human readable,
1103*68653Smckusick 			     * for debugging purposes.
1104*68653Smckusick 			     */
1105*68653Smckusick 			    *tl++ = txdr_unsigned(boottime.tv_sec);
1106*68653Smckusick 			    *tl = txdr_unsigned(boottime.tv_usec);
1107*68653Smckusick 			} else {
1108*68653Smckusick 			    nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1109*68653Smckusick 			    nfsm_srvfillattr(&va, fp);
1110*68653Smckusick 			}
1111*68653Smckusick 		    }
1112*68653Smckusick 		    nfsd->nd_mreq = mreq;
1113*68653Smckusick 		    if (nfsd->nd_mrep)
1114*68653Smckusick 			panic("nfsrv_write: nd_mrep not free");
1115*68653Smckusick 
1116*68653Smckusick 		    /*
1117*68653Smckusick 		     * Done. Put it at the head of the timer queue so that
1118*68653Smckusick 		     * the final phase can return the reply.
1119*68653Smckusick 		     */
1120*68653Smckusick 		    s = splsoftclock();
1121*68653Smckusick 		    if (nfsd != swp) {
1122*68653Smckusick 			nfsd->nd_time = 0;
1123*68653Smckusick 			LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
1124*68653Smckusick 		    }
1125*68653Smckusick 		    nfsd = swp->nd_coalesce.lh_first;
1126*68653Smckusick 		    if (nfsd) {
1127*68653Smckusick 			LIST_REMOVE(nfsd, nd_tq);
1128*68653Smckusick 		    }
1129*68653Smckusick 		    splx(s);
1130*68653Smckusick 		} while (nfsd);
1131*68653Smckusick 		s = splsoftclock();
1132*68653Smckusick 		swp->nd_time = 0;
1133*68653Smckusick 		LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
1134*68653Smckusick 		splx(s);
1135*68653Smckusick 		goto loop1;
1136*68653Smckusick 	}
1137*68653Smckusick 	splx(s);
1138*68653Smckusick 
1139*68653Smckusick 	/*
1140*68653Smckusick 	 * Search for a reply to return.
1141*68653Smckusick 	 */
1142*68653Smckusick 	s = splsoftclock();
1143*68653Smckusick 	for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
1144*68653Smckusick 		if (nfsd->nd_mreq) {
1145*68653Smckusick 		    LIST_REMOVE(nfsd, nd_tq);
1146*68653Smckusick 		    *mrq = nfsd->nd_mreq;
1147*68653Smckusick 		    *ndp = nfsd;
1148*68653Smckusick 		    break;
114938418Smckusick 		}
1150*68653Smckusick 	splx(s);
1151*68653Smckusick 	return (0);
1152*68653Smckusick }
1153*68653Smckusick 
1154*68653Smckusick /*
1155*68653Smckusick  * Coalesce the write request nfsd into owp. To do this we must:
1156*68653Smckusick  * - remove nfsd from the queues
1157*68653Smckusick  * - merge nfsd->nd_mrep into owp->nd_mrep
1158*68653Smckusick  * - update the nd_eoff and nd_stable for owp
1159*68653Smckusick  * - put nfsd on owp's nd_coalesce list
1160*68653Smckusick  * NB: Must be called at splsoftclock().
1161*68653Smckusick  */
1162*68653Smckusick void
1163*68653Smckusick nfsrvw_coalesce(owp, nfsd)
1164*68653Smckusick         register struct nfsrv_descript *owp;
1165*68653Smckusick         register struct nfsrv_descript *nfsd;
1166*68653Smckusick {
1167*68653Smckusick         register int overlap;
1168*68653Smckusick         register struct mbuf *mp;
1169*68653Smckusick 
1170*68653Smckusick         LIST_REMOVE(nfsd, nd_hash);
1171*68653Smckusick         LIST_REMOVE(nfsd, nd_tq);
1172*68653Smckusick         if (owp->nd_eoff < nfsd->nd_eoff) {
1173*68653Smckusick             overlap = owp->nd_eoff - nfsd->nd_off;
1174*68653Smckusick             if (overlap < 0)
1175*68653Smckusick                 panic("nfsrv_coalesce: bad off");
1176*68653Smckusick             if (overlap > 0)
1177*68653Smckusick                 m_adj(nfsd->nd_mrep, overlap);
1178*68653Smckusick             mp = owp->nd_mrep;
1179*68653Smckusick             while (mp->m_next)
1180*68653Smckusick                 mp = mp->m_next;
1181*68653Smckusick             mp->m_next = nfsd->nd_mrep;
1182*68653Smckusick             owp->nd_eoff = nfsd->nd_eoff;
1183*68653Smckusick         } else
1184*68653Smckusick             m_freem(nfsd->nd_mrep);
1185*68653Smckusick         nfsd->nd_mrep = NULL;
1186*68653Smckusick         if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
1187*68653Smckusick             owp->nd_stable = NFSV3WRITE_FILESYNC;
1188*68653Smckusick         else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
1189*68653Smckusick             owp->nd_stable == NFSV3WRITE_UNSTABLE)
1190*68653Smckusick             owp->nd_stable = NFSV3WRITE_DATASYNC;
1191*68653Smckusick         LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
1192*68653Smckusick }
1193*68653Smckusick 
1194*68653Smckusick /*
1195*68653Smckusick  * Sort the group list in increasing numerical order.
1196*68653Smckusick  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
1197*68653Smckusick  *  that used to be here.)
1198*68653Smckusick  */
1199*68653Smckusick void
1200*68653Smckusick nfsrvw_sort(list, num)
1201*68653Smckusick         register gid_t *list;
1202*68653Smckusick         register int num;
1203*68653Smckusick {
1204*68653Smckusick 	register int i, j;
1205*68653Smckusick 	gid_t v;
1206*68653Smckusick 
1207*68653Smckusick 	/* Insertion sort. */
1208*68653Smckusick 	for (i = 1; i < num; i++) {
1209*68653Smckusick 		v = list[i];
1210*68653Smckusick 		/* find correct slot for value v, moving others up */
1211*68653Smckusick 		for (j = i; --j >= 0 && v < list[j];)
1212*68653Smckusick 			list[j + 1] = list[j];
1213*68653Smckusick 		list[j + 1] = v;
121438418Smckusick 	}
121538418Smckusick }
121638418Smckusick 
121738418Smckusick /*
1218*68653Smckusick  * copy credentials making sure that the result can be compared with bcmp().
1219*68653Smckusick  */
1220*68653Smckusick void
1221*68653Smckusick nfsrv_setcred(incred, outcred)
1222*68653Smckusick 	register struct ucred *incred, *outcred;
1223*68653Smckusick {
1224*68653Smckusick 	register int i;
1225*68653Smckusick 
1226*68653Smckusick 	bzero((caddr_t)outcred, sizeof (struct ucred));
1227*68653Smckusick 	outcred->cr_ref = 1;
1228*68653Smckusick 	outcred->cr_uid = incred->cr_uid;
1229*68653Smckusick 	outcred->cr_ngroups = incred->cr_ngroups;
1230*68653Smckusick 	for (i = 0; i < incred->cr_ngroups; i++)
1231*68653Smckusick 		outcred->cr_groups[i] = incred->cr_groups[i];
1232*68653Smckusick 	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
1233*68653Smckusick }
1234*68653Smckusick 
1235*68653Smckusick /*
123638418Smckusick  * nfs create service
123738418Smckusick  * now does a truncate to 0 length via. setattr if it already exists
123838418Smckusick  */
1239*68653Smckusick int
1240*68653Smckusick nfsrv_create(nfsd, slp, procp, mrq)
1241*68653Smckusick 	struct nfsrv_descript *nfsd;
1242*68653Smckusick 	struct nfssvc_sock *slp;
1243*68653Smckusick 	struct proc *procp;
1244*68653Smckusick 	struct mbuf **mrq;
124538418Smckusick {
1246*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1247*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
1248*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
1249*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
1250*68653Smckusick 	register struct nfs_fattr *fp;
1251*68653Smckusick 	struct vattr va, dirfor, diraft;
125238418Smckusick 	register struct vattr *vap = &va;
125356285Smckusick 	register struct nfsv2_sattr *sp;
125456285Smckusick 	register u_long *tl;
125549742Smckusick 	struct nameidata nd;
125639494Smckusick 	register caddr_t cp;
125739494Smckusick 	register long t1;
125839494Smckusick 	caddr_t bpos;
1259*68653Smckusick 	int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1260*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
126139494Smckusick 	char *cp2;
126239753Smckusick 	struct mbuf *mb, *mb2, *mreq;
1263*68653Smckusick 	struct vnode *vp, *dirp = (struct vnode *)0;
1264*68653Smckusick 	nfsfh_t nfh;
126538418Smckusick 	fhandle_t *fhp;
1266*68653Smckusick 	u_quad_t frev, tempsize;
1267*68653Smckusick 	u_char cverf[NFSX_V3CREATEVERF];
126838418Smckusick 
1269*68653Smckusick #ifndef nolint
1270*68653Smckusick 	rdev = 0;
1271*68653Smckusick #endif
127252316Sheideman 	nd.ni_cnd.cn_nameiop = 0;
127338418Smckusick 	fhp = &nfh.fh_generic;
127438418Smckusick 	nfsm_srvmtofh(fhp);
1275*68653Smckusick 	nfsm_srvnamesiz(len);
127652316Sheideman 	nd.ni_cnd.cn_cred = cred;
127752316Sheideman 	nd.ni_cnd.cn_nameiop = CREATE;
127852316Sheideman 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1279*68653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1280*68653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1281*68653Smckusick 	if (dirp) {
1282*68653Smckusick 		if (v3)
1283*68653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1284*68653Smckusick 				procp);
1285*68653Smckusick 		else {
1286*68653Smckusick 			vrele(dirp);
1287*68653Smckusick 			dirp = (struct vnode *)0;
1288*68653Smckusick 		}
1289*68653Smckusick 	}
1290*68653Smckusick 	if (error) {
1291*68653Smckusick 		nfsm_reply(NFSX_WCCDATA(v3));
1292*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1293*68653Smckusick 		if (dirp)
1294*68653Smckusick 			vrele(dirp);
1295*68653Smckusick 		return (0);
1296*68653Smckusick 	}
129741361Smckusick 	VATTR_NULL(vap);
1298*68653Smckusick 	if (v3) {
1299*68653Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1300*68653Smckusick 		how = fxdr_unsigned(int, *tl);
1301*68653Smckusick 		switch (how) {
1302*68653Smckusick 		case NFSV3CREATE_GUARDED:
1303*68653Smckusick 			if (nd.ni_vp) {
1304*68653Smckusick 				error = EEXIST;
1305*68653Smckusick 				break;
1306*68653Smckusick 			}
1307*68653Smckusick 		case NFSV3CREATE_UNCHECKED:
1308*68653Smckusick 			nfsm_srvsattr(vap);
1309*68653Smckusick 			break;
1310*68653Smckusick 		case NFSV3CREATE_EXCLUSIVE:
1311*68653Smckusick 			nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
1312*68653Smckusick 			bcopy(cp, cverf, NFSX_V3CREATEVERF);
1313*68653Smckusick 			exclusive_flag = 1;
1314*68653Smckusick 			if (nd.ni_vp == NULL)
1315*68653Smckusick 				vap->va_mode = 0;
1316*68653Smckusick 			break;
1317*68653Smckusick 		};
1318*68653Smckusick 		vap->va_type = VREG;
1319*68653Smckusick 	} else {
1320*68653Smckusick 		nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
1321*68653Smckusick 		vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
1322*68653Smckusick 		if (vap->va_type == VNON)
1323*68653Smckusick 			vap->va_type = VREG;
1324*68653Smckusick 		vap->va_mode = nfstov_mode(sp->sa_mode);
1325*68653Smckusick 		switch (vap->va_type) {
1326*68653Smckusick 		case VREG:
1327*68653Smckusick 			tsize = fxdr_unsigned(long, sp->sa_size);
1328*68653Smckusick 			if (tsize != -1)
1329*68653Smckusick 				vap->va_size = (u_quad_t)tsize;
1330*68653Smckusick 			break;
1331*68653Smckusick 		case VCHR:
1332*68653Smckusick 		case VBLK:
1333*68653Smckusick 		case VFIFO:
1334*68653Smckusick 			rdev = fxdr_unsigned(long, sp->sa_size);
1335*68653Smckusick 			break;
1336*68653Smckusick 		};
1337*68653Smckusick 	}
1338*68653Smckusick 
133938418Smckusick 	/*
134038418Smckusick 	 * Iff doesn't exist, create it
134138418Smckusick 	 * otherwise just truncate to 0 length
134238418Smckusick 	 *   should I set the mode too ??
134338418Smckusick 	 */
134449742Smckusick 	if (nd.ni_vp == NULL) {
134546988Smckusick 		if (vap->va_type == VREG || vap->va_type == VSOCK) {
134649742Smckusick 			vrele(nd.ni_startdir);
1347*68653Smckusick 			nqsrv_getl(nd.ni_dvp, ND_WRITE);
1348*68653Smckusick 			error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1349*68653Smckusick 			if (!error) {
1350*68653Smckusick 				FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1351*68653Smckusick 				if (exclusive_flag) {
1352*68653Smckusick 					exclusive_flag = 0;
1353*68653Smckusick 					VATTR_NULL(vap);
1354*68653Smckusick 					bcopy(cverf, (caddr_t)&vap->va_atime,
1355*68653Smckusick 						NFSX_V3CREATEVERF);
1356*68653Smckusick 					error = VOP_SETATTR(nd.ni_vp, vap, cred,
1357*68653Smckusick 						procp);
1358*68653Smckusick 				}
1359*68653Smckusick 			}
136042242Smckusick 		} else if (vap->va_type == VCHR || vap->va_type == VBLK ||
136142242Smckusick 			vap->va_type == VFIFO) {
136242242Smckusick 			if (vap->va_type == VCHR && rdev == 0xffffffff)
136342242Smckusick 				vap->va_type = VFIFO;
1364*68653Smckusick 			if (error = suser(cred, (u_short *)0)) {
1365*68653Smckusick 				vrele(nd.ni_startdir);
1366*68653Smckusick 				free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
136752234Sheideman 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
136849742Smckusick 				vput(nd.ni_dvp);
1369*68653Smckusick 				nfsm_reply(0);
1370*68653Smckusick 				return (error);
137142242Smckusick 			} else
137242242Smckusick 				vap->va_rdev = (dev_t)rdev;
1373*68653Smckusick 			nqsrv_getl(nd.ni_dvp, ND_WRITE);
137452234Sheideman 			if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
137549742Smckusick 				vrele(nd.ni_startdir);
137642242Smckusick 				nfsm_reply(0);
137749742Smckusick 			}
137852316Sheideman 			nd.ni_cnd.cn_nameiop = LOOKUP;
137952316Sheideman 			nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1380*68653Smckusick 			nd.ni_cnd.cn_proc = procp;
1381*68653Smckusick 			nd.ni_cnd.cn_cred = cred;
138252316Sheideman 			if (error = lookup(&nd)) {
138352316Sheideman 				free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
138442242Smckusick 				nfsm_reply(0);
138549742Smckusick 			}
138652316Sheideman 			FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
138752316Sheideman 			if (nd.ni_cnd.cn_flags & ISSYMLINK) {
138849742Smckusick 				vrele(nd.ni_dvp);
138949742Smckusick 				vput(nd.ni_vp);
139052234Sheideman 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
139149742Smckusick 				error = EINVAL;
139249742Smckusick 				nfsm_reply(0);
139349742Smckusick 			}
139442242Smckusick 		} else {
1395*68653Smckusick 			vrele(nd.ni_startdir);
1396*68653Smckusick 			free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
139752234Sheideman 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
139849742Smckusick 			vput(nd.ni_dvp);
139942242Smckusick 			error = ENXIO;
140042242Smckusick 		}
140149742Smckusick 		vp = nd.ni_vp;
140238418Smckusick 	} else {
140349742Smckusick 		vrele(nd.ni_startdir);
140452316Sheideman 		free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
140549742Smckusick 		vp = nd.ni_vp;
140649742Smckusick 		if (nd.ni_dvp == vp)
140749742Smckusick 			vrele(nd.ni_dvp);
140843359Smckusick 		else
140949742Smckusick 			vput(nd.ni_dvp);
141052234Sheideman 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
141156285Smckusick 		if (vap->va_size != -1) {
1412*68653Smckusick 			error = nfsrv_access(vp, VWRITE, cred,
1413*68653Smckusick 			    (nd.ni_cnd.cn_flags & RDONLY), procp);
1414*68653Smckusick 			if (!error) {
1415*68653Smckusick 				nqsrv_getl(vp, ND_WRITE);
1416*68653Smckusick 				tempsize = vap->va_size;
1417*68653Smckusick 				VATTR_NULL(vap);
1418*68653Smckusick 				vap->va_size = tempsize;
1419*68653Smckusick 				error = VOP_SETATTR(vp, vap, cred,
1420*68653Smckusick 					 procp);
142160401Smckusick 			}
1422*68653Smckusick 			if (error)
142356285Smckusick 				vput(vp);
142442506Smckusick 		}
142538418Smckusick 	}
1426*68653Smckusick 	if (!error) {
1427*68653Smckusick 		bzero((caddr_t)fhp, sizeof(nfh));
1428*68653Smckusick 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1429*68653Smckusick 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
1430*68653Smckusick 		if (!error)
1431*68653Smckusick 			error = VOP_GETATTR(vp, vap, cred, procp);
143238418Smckusick 		vput(vp);
143338418Smckusick 	}
1434*68653Smckusick 	if (v3) {
1435*68653Smckusick 		if (exclusive_flag && !error &&
1436*68653Smckusick 			bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
1437*68653Smckusick 			error = EEXIST;
1438*68653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1439*68653Smckusick 		vrele(dirp);
1440*68653Smckusick 	}
1441*68653Smckusick 	nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
1442*68653Smckusick 	if (v3) {
1443*68653Smckusick 		if (!error) {
1444*68653Smckusick 			nfsm_srvpostop_fh(fhp);
1445*68653Smckusick 			nfsm_srvpostop_attr(0, vap);
1446*68653Smckusick 		}
1447*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1448*68653Smckusick 	} else {
1449*68653Smckusick 		nfsm_srvfhtom(fhp, v3);
1450*68653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
1451*68653Smckusick 		nfsm_srvfillattr(vap, fp);
1452*68653Smckusick 	}
1453*68653Smckusick 	return (0);
145438418Smckusick nfsmout:
1455*68653Smckusick 	if (dirp)
1456*68653Smckusick 		vrele(dirp);
1457*68653Smckusick 	if (nd.ni_cnd.cn_nameiop) {
145851464Sbostic 		vrele(nd.ni_startdir);
1459*68653Smckusick 		free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1460*68653Smckusick 	}
146152234Sheideman 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
146249742Smckusick 	if (nd.ni_dvp == nd.ni_vp)
146349742Smckusick 		vrele(nd.ni_dvp);
146443359Smckusick 	else
146549742Smckusick 		vput(nd.ni_dvp);
146649742Smckusick 	if (nd.ni_vp)
146749742Smckusick 		vput(nd.ni_vp);
146838418Smckusick 	return (error);
146938418Smckusick }
147038418Smckusick 
147138418Smckusick /*
1472*68653Smckusick  * nfs v3 mknod service
147338418Smckusick  */
1474*68653Smckusick int
1475*68653Smckusick nfsrv_mknod(nfsd, slp, procp, mrq)
1476*68653Smckusick 	struct nfsrv_descript *nfsd;
1477*68653Smckusick 	struct nfssvc_sock *slp;
1478*68653Smckusick 	struct proc *procp;
1479*68653Smckusick 	struct mbuf **mrq;
148038418Smckusick {
1481*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1482*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
1483*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
1484*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
1485*68653Smckusick 	register struct nfs_fattr *fp;
1486*68653Smckusick 	struct vattr va, dirfor, diraft;
1487*68653Smckusick 	register struct vattr *vap = &va;
1488*68653Smckusick 	register u_long *tl;
148949742Smckusick 	struct nameidata nd;
1490*68653Smckusick 	register caddr_t cp;
149139494Smckusick 	register long t1;
149239494Smckusick 	caddr_t bpos;
1493*68653Smckusick 	int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
1494*68653Smckusick 	u_long major, minor;
1495*68653Smckusick 	enum vtype vtyp;
149639494Smckusick 	char *cp2;
1497*68653Smckusick 	struct mbuf *mb, *mb2, *mreq;
1498*68653Smckusick 	struct vnode *vp, *dirp = (struct vnode *)0;
1499*68653Smckusick 	nfsfh_t nfh;
150038418Smckusick 	fhandle_t *fhp;
150152196Smckusick 	u_quad_t frev;
150238418Smckusick 
1503*68653Smckusick 	nd.ni_cnd.cn_nameiop = 0;
150438418Smckusick 	fhp = &nfh.fh_generic;
150538418Smckusick 	nfsm_srvmtofh(fhp);
1506*68653Smckusick 	nfsm_srvnamesiz(len);
150752316Sheideman 	nd.ni_cnd.cn_cred = cred;
1508*68653Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
1509*68653Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
1510*68653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1511*68653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1512*68653Smckusick 	if (dirp)
1513*68653Smckusick 		dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
1514*68653Smckusick 	if (error) {
1515*68653Smckusick 		nfsm_reply(NFSX_WCCDATA(1));
1516*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1517*68653Smckusick 		if (dirp)
1518*68653Smckusick 			vrele(dirp);
1519*68653Smckusick 		return (0);
1520*68653Smckusick 	}
1521*68653Smckusick 	nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
1522*68653Smckusick 	vtyp = nfsv3tov_type(*tl);
1523*68653Smckusick 	if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
1524*68653Smckusick 		vrele(nd.ni_startdir);
1525*68653Smckusick 		free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1526*68653Smckusick 		error = NFSERR_BADTYPE;
1527*68653Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1528*68653Smckusick 		vput(nd.ni_dvp);
152938418Smckusick 		goto out;
1530*68653Smckusick 	}
1531*68653Smckusick 	VATTR_NULL(vap);
1532*68653Smckusick 	nfsm_srvsattr(vap);
1533*68653Smckusick 	if (vtyp == VCHR || vtyp == VBLK) {
1534*68653Smckusick 		nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
1535*68653Smckusick 		major = fxdr_unsigned(u_long, *tl++);
1536*68653Smckusick 		minor = fxdr_unsigned(u_long, *tl);
1537*68653Smckusick 		vap->va_rdev = makedev(major, minor);
1538*68653Smckusick 	}
1539*68653Smckusick 
154038418Smckusick 	/*
1541*68653Smckusick 	 * Iff doesn't exist, create it.
154238418Smckusick 	 */
1543*68653Smckusick 	if (nd.ni_vp) {
1544*68653Smckusick 		vrele(nd.ni_startdir);
1545*68653Smckusick 		free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1546*68653Smckusick 		error = EEXIST;
1547*68653Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1548*68653Smckusick 		vput(nd.ni_dvp);
154938418Smckusick 		goto out;
155038418Smckusick 	}
1551*68653Smckusick 	vap->va_type = vtyp;
1552*68653Smckusick 	if (vtyp == VSOCK) {
1553*68653Smckusick 		vrele(nd.ni_startdir);
1554*68653Smckusick 		nqsrv_getl(nd.ni_dvp, ND_WRITE);
1555*68653Smckusick 		error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
1556*68653Smckusick 		if (!error)
1557*68653Smckusick 			FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1558*68653Smckusick 	} else {
1559*68653Smckusick 		if (error = suser(cred, (u_short *)0)) {
1560*68653Smckusick 			vrele(nd.ni_startdir);
1561*68653Smckusick 			free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1562*68653Smckusick 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1563*68653Smckusick 			vput(nd.ni_dvp);
1564*68653Smckusick 			goto out;
1565*68653Smckusick 		}
1566*68653Smckusick 		nqsrv_getl(nd.ni_dvp, ND_WRITE);
1567*68653Smckusick 		if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
1568*68653Smckusick 			vrele(nd.ni_startdir);
1569*68653Smckusick 			goto out;
1570*68653Smckusick 		}
1571*68653Smckusick 		nd.ni_cnd.cn_nameiop = LOOKUP;
1572*68653Smckusick 		nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
1573*68653Smckusick 		nd.ni_cnd.cn_proc = procp;
1574*68653Smckusick 		nd.ni_cnd.cn_cred = procp->p_ucred;
1575*68653Smckusick 		error = lookup(&nd);
1576*68653Smckusick 		FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
1577*68653Smckusick 		if (error)
1578*68653Smckusick 			goto out;
1579*68653Smckusick 		if (nd.ni_cnd.cn_flags & ISSYMLINK) {
1580*68653Smckusick 			vrele(nd.ni_dvp);
1581*68653Smckusick 			vput(nd.ni_vp);
1582*68653Smckusick 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1583*68653Smckusick 			error = EINVAL;
1584*68653Smckusick 		}
1585*68653Smckusick 	}
158638418Smckusick out:
1587*68653Smckusick 	vp = nd.ni_vp;
158842467Smckusick 	if (!error) {
1589*68653Smckusick 		bzero((caddr_t)fhp, sizeof(nfh));
1590*68653Smckusick 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
1591*68653Smckusick 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
1592*68653Smckusick 		if (!error)
1593*68653Smckusick 			error = VOP_GETATTR(vp, vap, cred, procp);
159442467Smckusick 		vput(vp);
159542467Smckusick 	}
1596*68653Smckusick 	diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1597*68653Smckusick 	vrele(dirp);
1598*68653Smckusick 	nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
1599*68653Smckusick 	if (!error) {
1600*68653Smckusick 		nfsm_srvpostop_fh(fhp);
1601*68653Smckusick 		nfsm_srvpostop_attr(0, vap);
1602*68653Smckusick 	}
1603*68653Smckusick 	nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1604*68653Smckusick 	return (0);
1605*68653Smckusick nfsmout:
1606*68653Smckusick 	if (dirp)
1607*68653Smckusick 		vrele(dirp);
1608*68653Smckusick 	if (nd.ni_cnd.cn_nameiop) {
1609*68653Smckusick 		vrele(nd.ni_startdir);
1610*68653Smckusick 		free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
1611*68653Smckusick 	}
1612*68653Smckusick 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1613*68653Smckusick 	if (nd.ni_dvp == nd.ni_vp)
1614*68653Smckusick 		vrele(nd.ni_dvp);
1615*68653Smckusick 	else
1616*68653Smckusick 		vput(nd.ni_dvp);
1617*68653Smckusick 	if (nd.ni_vp)
1618*68653Smckusick 		vput(nd.ni_vp);
1619*68653Smckusick 	return (error);
1620*68653Smckusick }
1621*68653Smckusick 
1622*68653Smckusick /*
1623*68653Smckusick  * nfs remove service
1624*68653Smckusick  */
1625*68653Smckusick int
1626*68653Smckusick nfsrv_remove(nfsd, slp, procp, mrq)
1627*68653Smckusick 	struct nfsrv_descript *nfsd;
1628*68653Smckusick 	struct nfssvc_sock *slp;
1629*68653Smckusick 	struct proc *procp;
1630*68653Smckusick 	struct mbuf **mrq;
1631*68653Smckusick {
1632*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1633*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
1634*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
1635*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
1636*68653Smckusick 	struct nameidata nd;
1637*68653Smckusick 	register u_long *tl;
1638*68653Smckusick 	register long t1;
1639*68653Smckusick 	caddr_t bpos;
1640*68653Smckusick 	int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
1641*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
1642*68653Smckusick 	char *cp2;
1643*68653Smckusick 	struct mbuf *mb, *mreq, *mb2;
1644*68653Smckusick 	struct vnode *vp, *dirp;
1645*68653Smckusick 	struct vattr dirfor, diraft;
1646*68653Smckusick 	nfsfh_t nfh;
1647*68653Smckusick 	fhandle_t *fhp;
1648*68653Smckusick 	u_quad_t frev;
1649*68653Smckusick 
1650*68653Smckusick #ifndef nolint
1651*68653Smckusick 	vp = (struct vnode *)0;
1652*68653Smckusick #endif
1653*68653Smckusick 	fhp = &nfh.fh_generic;
1654*68653Smckusick 	nfsm_srvmtofh(fhp);
1655*68653Smckusick 	nfsm_srvnamesiz(len);
1656*68653Smckusick 	nd.ni_cnd.cn_cred = cred;
1657*68653Smckusick 	nd.ni_cnd.cn_nameiop = DELETE;
1658*68653Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
1659*68653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
1660*68653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1661*68653Smckusick 	if (dirp) {
1662*68653Smckusick 		if (v3)
1663*68653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1664*68653Smckusick 				procp);
1665*68653Smckusick 		else
1666*68653Smckusick 			vrele(dirp);
1667*68653Smckusick 	}
1668*68653Smckusick 	if (!error) {
1669*68653Smckusick 		vp = nd.ni_vp;
1670*68653Smckusick 		if (vp->v_type == VDIR &&
1671*68653Smckusick 			(error = suser(cred, (u_short *)0)))
1672*68653Smckusick 			goto out;
1673*68653Smckusick 		/*
1674*68653Smckusick 		 * The root of a mounted filesystem cannot be deleted.
1675*68653Smckusick 		 */
1676*68653Smckusick 		if (vp->v_flag & VROOT) {
1677*68653Smckusick 			error = EBUSY;
1678*68653Smckusick 			goto out;
1679*68653Smckusick 		}
1680*68653Smckusick 		if (vp->v_flag & VTEXT)
1681*68653Smckusick 			(void) vnode_pager_uncache(vp);
1682*68653Smckusick out:
1683*68653Smckusick 		if (!error) {
1684*68653Smckusick 			nqsrv_getl(nd.ni_dvp, ND_WRITE);
1685*68653Smckusick 			nqsrv_getl(vp, ND_WRITE);
1686*68653Smckusick 			error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
1687*68653Smckusick 		} else {
1688*68653Smckusick 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
1689*68653Smckusick 			if (nd.ni_dvp == vp)
1690*68653Smckusick 				vrele(nd.ni_dvp);
1691*68653Smckusick 			else
1692*68653Smckusick 				vput(nd.ni_dvp);
1693*68653Smckusick 			vput(vp);
1694*68653Smckusick 		}
1695*68653Smckusick 	}
1696*68653Smckusick 	if (dirp && v3) {
1697*68653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1698*68653Smckusick 		vrele(dirp);
1699*68653Smckusick 	}
1700*68653Smckusick 	nfsm_reply(NFSX_WCCDATA(v3));
1701*68653Smckusick 	if (v3) {
1702*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1703*68653Smckusick 		return (0);
1704*68653Smckusick 	}
170538418Smckusick 	nfsm_srvdone;
170638418Smckusick }
170738418Smckusick 
170838418Smckusick /*
170938418Smckusick  * nfs rename service
171038418Smckusick  */
1711*68653Smckusick int
1712*68653Smckusick nfsrv_rename(nfsd, slp, procp, mrq)
1713*68653Smckusick 	struct nfsrv_descript *nfsd;
1714*68653Smckusick 	struct nfssvc_sock *slp;
1715*68653Smckusick 	struct proc *procp;
1716*68653Smckusick 	struct mbuf **mrq;
171738418Smckusick {
1718*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1719*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
1720*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
1721*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
172248050Smckusick 	register u_long *tl;
172339494Smckusick 	register long t1;
172439494Smckusick 	caddr_t bpos;
1725*68653Smckusick 	int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
1726*68653Smckusick 	int tdirfor_ret = 1, tdiraft_ret = 1;
1727*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
172839494Smckusick 	char *cp2;
1729*68653Smckusick 	struct mbuf *mb, *mreq, *mb2;
173049742Smckusick 	struct nameidata fromnd, tond;
1731*68653Smckusick 	struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
1732*68653Smckusick 	struct vnode *tdirp = (struct vnode *)0;
1733*68653Smckusick 	struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
1734*68653Smckusick 	nfsfh_t fnfh, tnfh;
173538418Smckusick 	fhandle_t *ffhp, *tfhp;
173652196Smckusick 	u_quad_t frev;
173752196Smckusick 	uid_t saved_uid;
173838418Smckusick 
1739*68653Smckusick #ifndef nolint
1740*68653Smckusick 	fvp = (struct vnode *)0;
1741*68653Smckusick #endif
174238418Smckusick 	ffhp = &fnfh.fh_generic;
174338418Smckusick 	tfhp = &tnfh.fh_generic;
174452316Sheideman 	fromnd.ni_cnd.cn_nameiop = 0;
174552316Sheideman 	tond.ni_cnd.cn_nameiop = 0;
174638418Smckusick 	nfsm_srvmtofh(ffhp);
1747*68653Smckusick 	nfsm_srvnamesiz(len);
174838418Smckusick 	/*
174952196Smckusick 	 * Remember our original uid so that we can reset cr_uid before
175052196Smckusick 	 * the second nfs_namei() call, in case it is remapped.
175138418Smckusick 	 */
175252196Smckusick 	saved_uid = cred->cr_uid;
175352316Sheideman 	fromnd.ni_cnd.cn_cred = cred;
175452316Sheideman 	fromnd.ni_cnd.cn_nameiop = DELETE;
175552316Sheideman 	fromnd.ni_cnd.cn_flags = WANTPARENT | SAVESTART;
1756*68653Smckusick 	error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
1757*68653Smckusick 		&dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1758*68653Smckusick 	if (fdirp) {
1759*68653Smckusick 		if (v3)
1760*68653Smckusick 			fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
1761*68653Smckusick 				procp);
1762*68653Smckusick 		else {
1763*68653Smckusick 			vrele(fdirp);
1764*68653Smckusick 			fdirp = (struct vnode *)0;
1765*68653Smckusick 		}
1766*68653Smckusick 	}
1767*68653Smckusick 	if (error) {
1768*68653Smckusick 		nfsm_reply(2 * NFSX_WCCDATA(v3));
1769*68653Smckusick 		nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1770*68653Smckusick 		nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1771*68653Smckusick 		if (fdirp)
1772*68653Smckusick 			vrele(fdirp);
1773*68653Smckusick 		return (0);
1774*68653Smckusick 	}
177549742Smckusick 	fvp = fromnd.ni_vp;
177638418Smckusick 	nfsm_srvmtofh(tfhp);
177741899Smckusick 	nfsm_strsiz(len2, NFS_MAXNAMLEN);
177852196Smckusick 	cred->cr_uid = saved_uid;
177952316Sheideman 	tond.ni_cnd.cn_cred = cred;
178052316Sheideman 	tond.ni_cnd.cn_nameiop = RENAME;
178152316Sheideman 	tond.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | NOCACHE | SAVESTART;
1782*68653Smckusick 	error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
1783*68653Smckusick 		&dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1784*68653Smckusick 	if (tdirp) {
1785*68653Smckusick 		if (v3)
1786*68653Smckusick 			tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
1787*68653Smckusick 				procp);
1788*68653Smckusick 		else {
1789*68653Smckusick 			vrele(tdirp);
1790*68653Smckusick 			tdirp = (struct vnode *)0;
1791*68653Smckusick 		}
1792*68653Smckusick 	}
1793*68653Smckusick 	if (error) {
179452234Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
179549742Smckusick 		vrele(fromnd.ni_dvp);
179642467Smckusick 		vrele(fvp);
179742467Smckusick 		goto out1;
179842467Smckusick 	}
179938425Smckusick 	tdvp = tond.ni_dvp;
180038425Smckusick 	tvp = tond.ni_vp;
180138418Smckusick 	if (tvp != NULL) {
180238418Smckusick 		if (fvp->v_type == VDIR && tvp->v_type != VDIR) {
1803*68653Smckusick 			if (v3)
1804*68653Smckusick 				error = EEXIST;
1805*68653Smckusick 			else
1806*68653Smckusick 				error = EISDIR;
180738418Smckusick 			goto out;
180838418Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
1809*68653Smckusick 			if (v3)
1810*68653Smckusick 				error = EEXIST;
1811*68653Smckusick 			else
1812*68653Smckusick 				error = ENOTDIR;
181338418Smckusick 			goto out;
181438418Smckusick 		}
181552196Smckusick 		if (tvp->v_type == VDIR && tvp->v_mountedhere) {
1816*68653Smckusick 			if (v3)
1817*68653Smckusick 				error = EXDEV;
1818*68653Smckusick 			else
1819*68653Smckusick 				error = ENOTEMPTY;
182052196Smckusick 			goto out;
182152196Smckusick 		}
182238418Smckusick 	}
182352196Smckusick 	if (fvp->v_type == VDIR && fvp->v_mountedhere) {
1824*68653Smckusick 		if (v3)
1825*68653Smckusick 			error = EXDEV;
1826*68653Smckusick 		else
1827*68653Smckusick 			error = ENOTEMPTY;
182852196Smckusick 		goto out;
182952196Smckusick 	}
183038418Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
1831*68653Smckusick 		if (v3)
1832*68653Smckusick 			error = EXDEV;
1833*68653Smckusick 		else
1834*68653Smckusick 			error = ENOTEMPTY;
183538418Smckusick 		goto out;
183638418Smckusick 	}
183749742Smckusick 	if (fvp == tdvp)
1838*68653Smckusick 		if (v3)
1839*68653Smckusick 			error = EINVAL;
1840*68653Smckusick 		else
1841*68653Smckusick 			error = ENOTEMPTY;
184249742Smckusick 	/*
184349742Smckusick 	 * If source is the same as the destination (that is the
184449742Smckusick 	 * same vnode with the same name in the same directory),
184549742Smckusick 	 * then there is nothing to do.
184649742Smckusick 	 */
184749742Smckusick 	if (fvp == tvp && fromnd.ni_dvp == tdvp &&
184852316Sheideman 	    fromnd.ni_cnd.cn_namelen == tond.ni_cnd.cn_namelen &&
184952316Sheideman 	    !bcmp(fromnd.ni_cnd.cn_nameptr, tond.ni_cnd.cn_nameptr,
185052316Sheideman 	      fromnd.ni_cnd.cn_namelen))
185149742Smckusick 		error = -1;
185238418Smckusick out:
185342467Smckusick 	if (!error) {
1854*68653Smckusick 		nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
1855*68653Smckusick 		nqsrv_getl(tdvp, ND_WRITE);
185652196Smckusick 		if (tvp)
1857*68653Smckusick 			nqsrv_getl(tvp, ND_WRITE);
185852234Sheideman 		error = VOP_RENAME(fromnd.ni_dvp, fromnd.ni_vp, &fromnd.ni_cnd,
185952234Sheideman 				   tond.ni_dvp, tond.ni_vp, &tond.ni_cnd);
186042467Smckusick 	} else {
186152234Sheideman 		VOP_ABORTOP(tond.ni_dvp, &tond.ni_cnd);
186243359Smckusick 		if (tdvp == tvp)
186343359Smckusick 			vrele(tdvp);
186443359Smckusick 		else
186543359Smckusick 			vput(tdvp);
186642467Smckusick 		if (tvp)
186742467Smckusick 			vput(tvp);
186852234Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
186949742Smckusick 		vrele(fromnd.ni_dvp);
187042467Smckusick 		vrele(fvp);
1871*68653Smckusick 		if (error == -1)
1872*68653Smckusick 			error = 0;
187338418Smckusick 	}
187446513Smckusick 	vrele(tond.ni_startdir);
187552316Sheideman 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
187638418Smckusick out1:
1877*68653Smckusick 	if (fdirp) {
1878*68653Smckusick 		fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
1879*68653Smckusick 		vrele(fdirp);
1880*68653Smckusick 	}
1881*68653Smckusick 	if (tdirp) {
1882*68653Smckusick 		tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
1883*68653Smckusick 		vrele(tdirp);
1884*68653Smckusick 	}
188549742Smckusick 	vrele(fromnd.ni_startdir);
188652316Sheideman 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
1887*68653Smckusick 	nfsm_reply(2 * NFSX_WCCDATA(v3));
1888*68653Smckusick 	if (v3) {
1889*68653Smckusick 		nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
1890*68653Smckusick 		nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
1891*68653Smckusick 	}
1892*68653Smckusick 	return (0);
189349742Smckusick 
189438418Smckusick nfsmout:
1895*68653Smckusick 	if (fdirp)
1896*68653Smckusick 		vrele(fdirp);
1897*68653Smckusick 	if (tdirp)
1898*68653Smckusick 		vrele(tdirp);
1899*68653Smckusick 	if (tond.ni_cnd.cn_nameiop) {
190049742Smckusick 		vrele(tond.ni_startdir);
190152316Sheideman 		FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
190249742Smckusick 	}
1903*68653Smckusick 	if (fromnd.ni_cnd.cn_nameiop) {
190449742Smckusick 		vrele(fromnd.ni_startdir);
190552316Sheideman 		FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
190652234Sheideman 		VOP_ABORTOP(fromnd.ni_dvp, &fromnd.ni_cnd);
190749742Smckusick 		vrele(fromnd.ni_dvp);
190849742Smckusick 		vrele(fvp);
190949742Smckusick 	}
191038418Smckusick 	return (error);
191138418Smckusick }
191238418Smckusick 
191338418Smckusick /*
191438418Smckusick  * nfs link service
191538418Smckusick  */
1916*68653Smckusick int
1917*68653Smckusick nfsrv_link(nfsd, slp, procp, mrq)
1918*68653Smckusick 	struct nfsrv_descript *nfsd;
1919*68653Smckusick 	struct nfssvc_sock *slp;
1920*68653Smckusick 	struct proc *procp;
1921*68653Smckusick 	struct mbuf **mrq;
192238418Smckusick {
1923*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
1924*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
1925*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
1926*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
192749742Smckusick 	struct nameidata nd;
192848050Smckusick 	register u_long *tl;
192939494Smckusick 	register long t1;
193039494Smckusick 	caddr_t bpos;
1931*68653Smckusick 	int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
1932*68653Smckusick 	int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
193339494Smckusick 	char *cp2;
1934*68653Smckusick 	struct mbuf *mb, *mreq, *mb2;
1935*68653Smckusick 	struct vnode *vp, *xp, *dirp = (struct vnode *)0;
1936*68653Smckusick 	struct vattr dirfor, diraft, at;
1937*68653Smckusick 	nfsfh_t nfh, dnfh;
193838418Smckusick 	fhandle_t *fhp, *dfhp;
193952196Smckusick 	u_quad_t frev;
194038418Smckusick 
194138418Smckusick 	fhp = &nfh.fh_generic;
194238418Smckusick 	dfhp = &dnfh.fh_generic;
194338418Smckusick 	nfsm_srvmtofh(fhp);
194438418Smckusick 	nfsm_srvmtofh(dfhp);
1945*68653Smckusick 	nfsm_srvnamesiz(len);
1946*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
1947*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
1948*68653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
1949*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
1950*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
1951*68653Smckusick 		return (0);
1952*68653Smckusick 	}
195352196Smckusick 	if (vp->v_type == VDIR && (error = suser(cred, (u_short *)0)))
195438418Smckusick 		goto out1;
195552316Sheideman 	nd.ni_cnd.cn_cred = cred;
195652316Sheideman 	nd.ni_cnd.cn_nameiop = CREATE;
195752316Sheideman 	nd.ni_cnd.cn_flags = LOCKPARENT;
1958*68653Smckusick 	error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
1959*68653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
1960*68653Smckusick 	if (dirp) {
1961*68653Smckusick 		if (v3)
1962*68653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
1963*68653Smckusick 				procp);
1964*68653Smckusick 		else {
1965*68653Smckusick 			vrele(dirp);
1966*68653Smckusick 			dirp = (struct vnode *)0;
1967*68653Smckusick 		}
1968*68653Smckusick 	}
1969*68653Smckusick 	if (error)
197038418Smckusick 		goto out1;
197149742Smckusick 	xp = nd.ni_vp;
197238418Smckusick 	if (xp != NULL) {
197338418Smckusick 		error = EEXIST;
197438418Smckusick 		goto out;
197538418Smckusick 	}
197649742Smckusick 	xp = nd.ni_dvp;
197738418Smckusick 	if (vp->v_mount != xp->v_mount)
197838418Smckusick 		error = EXDEV;
197938418Smckusick out:
198042467Smckusick 	if (!error) {
1981*68653Smckusick 		nqsrv_getl(vp, ND_WRITE);
1982*68653Smckusick 		nqsrv_getl(xp, ND_WRITE);
198368539Smckusick 		error = VOP_LINK(vp, nd.ni_dvp, &nd.ni_cnd);
198442467Smckusick 	} else {
198552234Sheideman 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
198649742Smckusick 		if (nd.ni_dvp == nd.ni_vp)
198749742Smckusick 			vrele(nd.ni_dvp);
198843359Smckusick 		else
198949742Smckusick 			vput(nd.ni_dvp);
199049742Smckusick 		if (nd.ni_vp)
199149742Smckusick 			vrele(nd.ni_vp);
199242467Smckusick 	}
199338418Smckusick out1:
1994*68653Smckusick 	if (v3)
1995*68653Smckusick 		getret = VOP_GETATTR(vp, &at, cred, procp);
1996*68653Smckusick 	if (dirp) {
1997*68653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
1998*68653Smckusick 		vrele(dirp);
1999*68653Smckusick 	}
200038418Smckusick 	vrele(vp);
2001*68653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2002*68653Smckusick 	if (v3) {
2003*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
2004*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2005*68653Smckusick 		return (0);
2006*68653Smckusick 	}
200738418Smckusick 	nfsm_srvdone;
200838418Smckusick }
200938418Smckusick 
201038418Smckusick /*
201138418Smckusick  * nfs symbolic link service
201238418Smckusick  */
2013*68653Smckusick int
2014*68653Smckusick nfsrv_symlink(nfsd, slp, procp, mrq)
2015*68653Smckusick 	struct nfsrv_descript *nfsd;
2016*68653Smckusick 	struct nfssvc_sock *slp;
2017*68653Smckusick 	struct proc *procp;
2018*68653Smckusick 	struct mbuf **mrq;
201938418Smckusick {
2020*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2021*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
2022*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
2023*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
2024*68653Smckusick 	struct vattr va, dirfor, diraft;
202549742Smckusick 	struct nameidata nd;
202638418Smckusick 	register struct vattr *vap = &va;
202748050Smckusick 	register u_long *tl;
202839494Smckusick 	register long t1;
202945285Smckusick 	struct nfsv2_sattr *sp;
2030*68653Smckusick 	char *bpos, *cp, *pathcp = (char *)0, *cp2;
203141899Smckusick 	struct uio io;
203241899Smckusick 	struct iovec iv;
2033*68653Smckusick 	int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
2034*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
2035*68653Smckusick 	struct mbuf *mb, *mreq, *mb2;
2036*68653Smckusick 	struct vnode *dirp = (struct vnode *)0;
2037*68653Smckusick 	nfsfh_t nfh;
203838418Smckusick 	fhandle_t *fhp;
203952196Smckusick 	u_quad_t frev;
204038418Smckusick 
2041*68653Smckusick 	nd.ni_cnd.cn_nameiop = 0;
204238418Smckusick 	fhp = &nfh.fh_generic;
204338418Smckusick 	nfsm_srvmtofh(fhp);
2044*68653Smckusick 	nfsm_srvnamesiz(len);
204552316Sheideman 	nd.ni_cnd.cn_cred = cred;
204652316Sheideman 	nd.ni_cnd.cn_nameiop = CREATE;
2047*68653Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
2048*68653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2049*68653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2050*68653Smckusick 	if (dirp) {
2051*68653Smckusick 		if (v3)
2052*68653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2053*68653Smckusick 				procp);
2054*68653Smckusick 		else {
2055*68653Smckusick 			vrele(dirp);
2056*68653Smckusick 			dirp = (struct vnode *)0;
2057*68653Smckusick 		}
2058*68653Smckusick 	}
2059*68653Smckusick 	if (error)
206042467Smckusick 		goto out;
2061*68653Smckusick 	VATTR_NULL(vap);
2062*68653Smckusick 	if (v3)
2063*68653Smckusick 		nfsm_srvsattr(vap);
206441899Smckusick 	nfsm_strsiz(len2, NFS_MAXPATHLEN);
206541899Smckusick 	MALLOC(pathcp, caddr_t, len2 + 1, M_TEMP, M_WAITOK);
206641899Smckusick 	iv.iov_base = pathcp;
206741899Smckusick 	iv.iov_len = len2;
206841899Smckusick 	io.uio_resid = len2;
206941899Smckusick 	io.uio_offset = 0;
207041899Smckusick 	io.uio_iov = &iv;
207141899Smckusick 	io.uio_iovcnt = 1;
207241899Smckusick 	io.uio_segflg = UIO_SYSSPACE;
207341899Smckusick 	io.uio_rw = UIO_READ;
207448050Smckusick 	io.uio_procp = (struct proc *)0;
207541899Smckusick 	nfsm_mtouio(&io, len2);
2076*68653Smckusick 	if (!v3) {
2077*68653Smckusick 		nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
2078*68653Smckusick 		vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
2079*68653Smckusick 	}
208041899Smckusick 	*(pathcp + len2) = '\0';
208149742Smckusick 	if (nd.ni_vp) {
2082*68653Smckusick 		vrele(nd.ni_startdir);
2083*68653Smckusick 		free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
208452234Sheideman 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
208549742Smckusick 		if (nd.ni_dvp == nd.ni_vp)
208649742Smckusick 			vrele(nd.ni_dvp);
208743359Smckusick 		else
208849742Smckusick 			vput(nd.ni_dvp);
208949742Smckusick 		vrele(nd.ni_vp);
209038418Smckusick 		error = EEXIST;
209138418Smckusick 		goto out;
209238418Smckusick 	}
2093*68653Smckusick 	nqsrv_getl(nd.ni_dvp, ND_WRITE);
209452234Sheideman 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
2095*68653Smckusick 	if (error)
2096*68653Smckusick 		vrele(nd.ni_startdir);
2097*68653Smckusick 	else {
2098*68653Smckusick 	    if (v3) {
2099*68653Smckusick 		nd.ni_cnd.cn_nameiop = LOOKUP;
2100*68653Smckusick 		nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
2101*68653Smckusick 		nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
2102*68653Smckusick 		nd.ni_cnd.cn_proc = procp;
2103*68653Smckusick 		nd.ni_cnd.cn_cred = cred;
2104*68653Smckusick 		error = lookup(&nd);
2105*68653Smckusick 		if (!error) {
2106*68653Smckusick 			bzero((caddr_t)fhp, sizeof(nfh));
2107*68653Smckusick 			fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
2108*68653Smckusick 			error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
2109*68653Smckusick 			if (!error)
2110*68653Smckusick 				error = VOP_GETATTR(nd.ni_vp, vap, cred,
2111*68653Smckusick 					procp);
2112*68653Smckusick 			vput(nd.ni_vp);
2113*68653Smckusick 		}
2114*68653Smckusick 	    } else
2115*68653Smckusick 		vrele(nd.ni_startdir);
2116*68653Smckusick 	    FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2117*68653Smckusick 	}
211838418Smckusick out:
211941899Smckusick 	if (pathcp)
212041899Smckusick 		FREE(pathcp, M_TEMP);
2121*68653Smckusick 	if (dirp) {
2122*68653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2123*68653Smckusick 		vrele(dirp);
2124*68653Smckusick 	}
2125*68653Smckusick 	nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2126*68653Smckusick 	if (v3) {
2127*68653Smckusick 		if (!error) {
2128*68653Smckusick 			nfsm_srvpostop_fh(fhp);
2129*68653Smckusick 			nfsm_srvpostop_attr(0, vap);
2130*68653Smckusick 		}
2131*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2132*68653Smckusick 	}
2133*68653Smckusick 	return (0);
213438418Smckusick nfsmout:
2135*68653Smckusick 	if (nd.ni_cnd.cn_nameiop) {
2136*68653Smckusick 		vrele(nd.ni_startdir);
2137*68653Smckusick 		free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
2138*68653Smckusick 	}
2139*68653Smckusick 	if (dirp)
2140*68653Smckusick 		vrele(dirp);
214152234Sheideman 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
214249742Smckusick 	if (nd.ni_dvp == nd.ni_vp)
214349742Smckusick 		vrele(nd.ni_dvp);
214443359Smckusick 	else
214549742Smckusick 		vput(nd.ni_dvp);
214649742Smckusick 	if (nd.ni_vp)
214749742Smckusick 		vrele(nd.ni_vp);
214841899Smckusick 	if (pathcp)
214941899Smckusick 		FREE(pathcp, M_TEMP);
215038418Smckusick 	return (error);
215138418Smckusick }
215238418Smckusick 
215338418Smckusick /*
215438418Smckusick  * nfs mkdir service
215538418Smckusick  */
2156*68653Smckusick int
2157*68653Smckusick nfsrv_mkdir(nfsd, slp, procp, mrq)
2158*68653Smckusick 	struct nfsrv_descript *nfsd;
2159*68653Smckusick 	struct nfssvc_sock *slp;
2160*68653Smckusick 	struct proc *procp;
2161*68653Smckusick 	struct mbuf **mrq;
216238418Smckusick {
2163*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2164*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
2165*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
2166*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
2167*68653Smckusick 	struct vattr va, dirfor, diraft;
216838418Smckusick 	register struct vattr *vap = &va;
2169*68653Smckusick 	register struct nfs_fattr *fp;
217049742Smckusick 	struct nameidata nd;
217139494Smckusick 	register caddr_t cp;
217248050Smckusick 	register u_long *tl;
217339494Smckusick 	register long t1;
217439494Smckusick 	caddr_t bpos;
2175*68653Smckusick 	int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2176*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
217739494Smckusick 	char *cp2;
217839753Smckusick 	struct mbuf *mb, *mb2, *mreq;
2179*68653Smckusick 	struct vnode *vp, *dirp = (struct vnode *)0;
2180*68653Smckusick 	nfsfh_t nfh;
218138418Smckusick 	fhandle_t *fhp;
218252196Smckusick 	u_quad_t frev;
218338418Smckusick 
218438418Smckusick 	fhp = &nfh.fh_generic;
218538418Smckusick 	nfsm_srvmtofh(fhp);
2186*68653Smckusick 	nfsm_srvnamesiz(len);
218752316Sheideman 	nd.ni_cnd.cn_cred = cred;
218852316Sheideman 	nd.ni_cnd.cn_nameiop = CREATE;
218952316Sheideman 	nd.ni_cnd.cn_flags = LOCKPARENT;
2190*68653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2191*68653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2192*68653Smckusick 	if (dirp) {
2193*68653Smckusick 		if (v3)
2194*68653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2195*68653Smckusick 				procp);
2196*68653Smckusick 		else {
2197*68653Smckusick 			vrele(dirp);
2198*68653Smckusick 			dirp = (struct vnode *)0;
2199*68653Smckusick 		}
2200*68653Smckusick 	}
2201*68653Smckusick 	if (error) {
2202*68653Smckusick 		nfsm_reply(NFSX_WCCDATA(v3));
2203*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2204*68653Smckusick 		if (dirp)
2205*68653Smckusick 			vrele(dirp);
2206*68653Smckusick 		return (0);
2207*68653Smckusick 	}
220841361Smckusick 	VATTR_NULL(vap);
2209*68653Smckusick 	if (v3) {
2210*68653Smckusick 		nfsm_srvsattr(vap);
2211*68653Smckusick 	} else {
2212*68653Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
2213*68653Smckusick 		vap->va_mode = nfstov_mode(*tl++);
2214*68653Smckusick 	}
221538418Smckusick 	vap->va_type = VDIR;
221649742Smckusick 	vp = nd.ni_vp;
221738418Smckusick 	if (vp != NULL) {
221852234Sheideman 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
221949742Smckusick 		if (nd.ni_dvp == vp)
222049742Smckusick 			vrele(nd.ni_dvp);
222143359Smckusick 		else
222249742Smckusick 			vput(nd.ni_dvp);
222342467Smckusick 		vrele(vp);
222438418Smckusick 		error = EEXIST;
2225*68653Smckusick 		goto out;
222638418Smckusick 	}
2227*68653Smckusick 	nqsrv_getl(nd.ni_dvp, ND_WRITE);
2228*68653Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
2229*68653Smckusick 	if (!error) {
2230*68653Smckusick 		vp = nd.ni_vp;
2231*68653Smckusick 		bzero((caddr_t)fhp, sizeof(nfh));
2232*68653Smckusick 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
2233*68653Smckusick 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
2234*68653Smckusick 		if (!error)
2235*68653Smckusick 			error = VOP_GETATTR(vp, vap, cred, procp);
223638418Smckusick 		vput(vp);
223738418Smckusick 	}
2238*68653Smckusick out:
2239*68653Smckusick 	if (dirp) {
2240*68653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2241*68653Smckusick 		vrele(dirp);
2242*68653Smckusick 	}
2243*68653Smckusick 	nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
2244*68653Smckusick 	if (v3) {
2245*68653Smckusick 		if (!error) {
2246*68653Smckusick 			nfsm_srvpostop_fh(fhp);
2247*68653Smckusick 			nfsm_srvpostop_attr(0, vap);
2248*68653Smckusick 		}
2249*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2250*68653Smckusick 	} else {
2251*68653Smckusick 		nfsm_srvfhtom(fhp, v3);
2252*68653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
2253*68653Smckusick 		nfsm_srvfillattr(vap, fp);
2254*68653Smckusick 	}
2255*68653Smckusick 	return (0);
225638418Smckusick nfsmout:
2257*68653Smckusick 	if (dirp)
2258*68653Smckusick 		vrele(dirp);
225952234Sheideman 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
226049742Smckusick 	if (nd.ni_dvp == nd.ni_vp)
226149742Smckusick 		vrele(nd.ni_dvp);
226243359Smckusick 	else
226349742Smckusick 		vput(nd.ni_dvp);
226449742Smckusick 	if (nd.ni_vp)
226549742Smckusick 		vrele(nd.ni_vp);
226638418Smckusick 	return (error);
226738418Smckusick }
226838418Smckusick 
226938418Smckusick /*
227038418Smckusick  * nfs rmdir service
227138418Smckusick  */
2272*68653Smckusick int
2273*68653Smckusick nfsrv_rmdir(nfsd, slp, procp, mrq)
2274*68653Smckusick 	struct nfsrv_descript *nfsd;
2275*68653Smckusick 	struct nfssvc_sock *slp;
2276*68653Smckusick 	struct proc *procp;
2277*68653Smckusick 	struct mbuf **mrq;
227838418Smckusick {
2279*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2280*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
2281*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
2282*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
228348050Smckusick 	register u_long *tl;
228439494Smckusick 	register long t1;
228539494Smckusick 	caddr_t bpos;
2286*68653Smckusick 	int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
2287*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
228839494Smckusick 	char *cp2;
2289*68653Smckusick 	struct mbuf *mb, *mreq, *mb2;
2290*68653Smckusick 	struct vnode *vp, *dirp = (struct vnode *)0;
2291*68653Smckusick 	struct vattr dirfor, diraft;
2292*68653Smckusick 	nfsfh_t nfh;
229338418Smckusick 	fhandle_t *fhp;
229449742Smckusick 	struct nameidata nd;
229552196Smckusick 	u_quad_t frev;
229638418Smckusick 
229738418Smckusick 	fhp = &nfh.fh_generic;
229838418Smckusick 	nfsm_srvmtofh(fhp);
2299*68653Smckusick 	nfsm_srvnamesiz(len);
230052316Sheideman 	nd.ni_cnd.cn_cred = cred;
230152316Sheideman 	nd.ni_cnd.cn_nameiop = DELETE;
230252316Sheideman 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
2303*68653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
2304*68653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
2305*68653Smckusick 	if (dirp) {
2306*68653Smckusick 		if (v3)
2307*68653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
2308*68653Smckusick 				procp);
2309*68653Smckusick 		else {
2310*68653Smckusick 			vrele(dirp);
2311*68653Smckusick 			dirp = (struct vnode *)0;
2312*68653Smckusick 		}
2313*68653Smckusick 	}
2314*68653Smckusick 	if (error) {
2315*68653Smckusick 		nfsm_reply(NFSX_WCCDATA(v3));
2316*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2317*68653Smckusick 		if (dirp)
2318*68653Smckusick 			vrele(dirp);
2319*68653Smckusick 		return (0);
2320*68653Smckusick 	}
232149742Smckusick 	vp = nd.ni_vp;
232238418Smckusick 	if (vp->v_type != VDIR) {
232338418Smckusick 		error = ENOTDIR;
232438418Smckusick 		goto out;
232538418Smckusick 	}
232638418Smckusick 	/*
232738418Smckusick 	 * No rmdir "." please.
232838418Smckusick 	 */
232949742Smckusick 	if (nd.ni_dvp == vp) {
233038418Smckusick 		error = EINVAL;
233138418Smckusick 		goto out;
233238418Smckusick 	}
233338418Smckusick 	/*
233449454Smckusick 	 * The root of a mounted filesystem cannot be deleted.
233538418Smckusick 	 */
233638418Smckusick 	if (vp->v_flag & VROOT)
233738418Smckusick 		error = EBUSY;
233838418Smckusick out:
233942467Smckusick 	if (!error) {
2340*68653Smckusick 		nqsrv_getl(nd.ni_dvp, ND_WRITE);
2341*68653Smckusick 		nqsrv_getl(vp, ND_WRITE);
234252234Sheideman 		error = VOP_RMDIR(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
234342467Smckusick 	} else {
234452234Sheideman 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
234549742Smckusick 		if (nd.ni_dvp == nd.ni_vp)
234649742Smckusick 			vrele(nd.ni_dvp);
234743359Smckusick 		else
234849742Smckusick 			vput(nd.ni_dvp);
234942467Smckusick 		vput(vp);
235042467Smckusick 	}
2351*68653Smckusick 	if (dirp) {
2352*68653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
2353*68653Smckusick 		vrele(dirp);
2354*68653Smckusick 	}
2355*68653Smckusick 	nfsm_reply(NFSX_WCCDATA(v3));
2356*68653Smckusick 	if (v3) {
2357*68653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
2358*68653Smckusick 		return (0);
2359*68653Smckusick 	}
236038418Smckusick 	nfsm_srvdone;
236138418Smckusick }
236238418Smckusick 
236338418Smckusick /*
236438418Smckusick  * nfs readdir service
236538418Smckusick  * - mallocs what it thinks is enough to read
236648050Smckusick  *	count rounded up to a multiple of NFS_DIRBLKSIZ <= NFS_MAXREADDIR
236738418Smckusick  * - calls VOP_READDIR()
236840115Smckusick  * - loops around building the reply
236938425Smckusick  *	if the output generated exceeds count break out of loop
237038425Smckusick  *	The nfsm_clget macro is used here so that the reply will be packed
237138425Smckusick  *	tightly in mbuf clusters.
237238418Smckusick  * - it only knows that it has encountered eof when the VOP_READDIR()
237338425Smckusick  *	reads nothing
237438418Smckusick  * - as such one readdir rpc will return eof false although you are there
237538425Smckusick  *	and then the next will return eof
237652441Smckusick  * - it trims out records with d_fileno == 0
237738425Smckusick  *	this doesn't matter for Unix clients, but they might confuse clients
237838425Smckusick  *	for other os'.
237938418Smckusick  * NB: It is tempting to set eof to true if the VOP_READDIR() reads less
238038425Smckusick  *	than requested, but this may not apply to all filesystems. For
238138425Smckusick  *	example, client NFS does not { although it is never remote mounted
238238425Smckusick  *	anyhow }
2383*68653Smckusick  *     The alternate call nfsrv_readdirplus() does lookups as well.
238438418Smckusick  * PS: The NFS protocol spec. does not clarify what the "count" byte
238538425Smckusick  *	argument is a count of.. just name strings and file id's or the
238638425Smckusick  *	entire reply rpc or ...
238738425Smckusick  *	I tried just file name and id sizes and it confused the Sun client,
238838425Smckusick  *	so I am using the full rpc size now. The "paranoia.." comment refers
238938425Smckusick  *	to including the status longwords that are not a part of the dir.
239038425Smckusick  *	"entry" structures, but are in the rpc.
239138418Smckusick  */
239252196Smckusick struct flrep {
2393*68653Smckusick 	nfsuint64	fl_off;
2394*68653Smckusick 	u_long		fl_postopok;
2395*68653Smckusick 	u_long		fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
2396*68653Smckusick 	u_long		fl_fhok;
2397*68653Smckusick 	u_long		fl_fhsize;
2398*68653Smckusick 	u_long		fl_nfh[NFSX_V3FH / sizeof (u_long)];
239952196Smckusick };
240052196Smckusick 
2401*68653Smckusick int
2402*68653Smckusick nfsrv_readdir(nfsd, slp, procp, mrq)
2403*68653Smckusick 	struct nfsrv_descript *nfsd;
2404*68653Smckusick 	struct nfssvc_sock *slp;
2405*68653Smckusick 	struct proc *procp;
2406*68653Smckusick 	struct mbuf **mrq;
240738418Smckusick {
2408*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2409*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
2410*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
2411*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
241238418Smckusick 	register char *bp, *be;
241338418Smckusick 	register struct mbuf *mp;
241452441Smckusick 	register struct dirent *dp;
241539494Smckusick 	register caddr_t cp;
241648050Smckusick 	register u_long *tl;
241739494Smckusick 	register long t1;
241839494Smckusick 	caddr_t bpos;
241952196Smckusick 	struct mbuf *mb, *mb2, *mreq, *mp2;
242052196Smckusick 	char *cpos, *cend, *cp2, *rbuf;
242138418Smckusick 	struct vnode *vp;
2422*68653Smckusick 	struct vattr at;
2423*68653Smckusick 	nfsfh_t nfh;
242438418Smckusick 	fhandle_t *fhp;
242538418Smckusick 	struct uio io;
242638418Smckusick 	struct iovec iv;
2427*68653Smckusick 	int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2428*68653Smckusick 	int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
2429*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
2430*68653Smckusick 	u_quad_t frev, off, toff, verf;
2431*68653Smckusick 	u_long *cookies = NULL, *cookiep;
243238418Smckusick 
243338418Smckusick 	fhp = &nfh.fh_generic;
243438418Smckusick 	nfsm_srvmtofh(fhp);
2435*68653Smckusick 	if (v3) {
2436*68653Smckusick 		nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
2437*68653Smckusick 		fxdr_hyper(tl, &toff);
2438*68653Smckusick 		tl += 2;
2439*68653Smckusick 		fxdr_hyper(tl, &verf);
2440*68653Smckusick 		tl += 2;
2441*68653Smckusick 	} else {
2442*68653Smckusick 		nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
2443*68653Smckusick 		toff = fxdr_unsigned(u_quad_t, *tl++);
2444*68653Smckusick 	}
2445*68653Smckusick 	off = toff;
244648050Smckusick 	cnt = fxdr_unsigned(int, *tl);
2447*68653Smckusick 	siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2448*68653Smckusick 	xfer = NFS_SRVMAXDATA(nfsd);
2449*68653Smckusick 	if (siz > xfer)
2450*68653Smckusick 		siz = xfer;
245138418Smckusick 	fullsiz = siz;
2452*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2453*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2454*68653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
2455*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
2456*68653Smckusick 		return (0);
2457*68653Smckusick 	}
2458*68653Smckusick 	nqsrv_getl(vp, ND_READ);
2459*68653Smckusick 	if (v3) {
2460*68653Smckusick 		error = getret = VOP_GETATTR(vp, &at, cred, procp);
2461*68653Smckusick 		if (!error && toff && verf != at.va_filerev)
2462*68653Smckusick 			error = NFSERR_BAD_COOKIE;
2463*68653Smckusick 	}
2464*68653Smckusick 	if (!error)
2465*68653Smckusick 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2466*68653Smckusick 	if (error) {
246738418Smckusick 		vput(vp);
2468*68653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3));
2469*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
2470*68653Smckusick 		return (0);
247138418Smckusick 	}
247238418Smckusick 	VOP_UNLOCK(vp);
247338418Smckusick 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
247438418Smckusick again:
247538418Smckusick 	iv.iov_base = rbuf;
247638418Smckusick 	iv.iov_len = fullsiz;
247738418Smckusick 	io.uio_iov = &iv;
247838418Smckusick 	io.uio_iovcnt = 1;
247956285Smckusick 	io.uio_offset = (off_t)off;
248038418Smckusick 	io.uio_resid = fullsiz;
248138418Smckusick 	io.uio_segflg = UIO_SYSSPACE;
248238418Smckusick 	io.uio_rw = UIO_READ;
248348050Smckusick 	io.uio_procp = (struct proc *)0;
2484*68653Smckusick 	eofflag = 0;
2485*68653Smckusick 	if (cookies) {
2486*68653Smckusick 		free((caddr_t)cookies, M_TEMP);
2487*68653Smckusick 		cookies = NULL;
2488*68653Smckusick 	}
2489*68653Smckusick 	error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
249056285Smckusick 	off = (off_t)io.uio_offset;
2491*68653Smckusick 	if (!cookies && !error)
2492*68653Smckusick 		error = NFSERR_PERM;
2493*68653Smckusick 	if (v3) {
2494*68653Smckusick 		getret = VOP_GETATTR(vp, &at, cred, procp);
2495*68653Smckusick 		if (!error)
2496*68653Smckusick 			error = getret;
2497*68653Smckusick 	}
249838418Smckusick 	if (error) {
249938418Smckusick 		vrele(vp);
250038418Smckusick 		free((caddr_t)rbuf, M_TEMP);
2501*68653Smckusick 		if (cookies)
2502*68653Smckusick 			free((caddr_t)cookies, M_TEMP);
2503*68653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3));
2504*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
2505*68653Smckusick 		return (0);
250638418Smckusick 	}
250738418Smckusick 	if (io.uio_resid) {
250838418Smckusick 		siz -= io.uio_resid;
250938418Smckusick 
251038418Smckusick 		/*
251138418Smckusick 		 * If nothing read, return eof
251238418Smckusick 		 * rpc reply
251338418Smckusick 		 */
251438418Smckusick 		if (siz == 0) {
251538418Smckusick 			vrele(vp);
2516*68653Smckusick 			nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
2517*68653Smckusick 				2 * NFSX_UNSIGNED);
2518*68653Smckusick 			if (v3) {
2519*68653Smckusick 				nfsm_srvpostop_attr(getret, &at);
2520*68653Smckusick 				nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2521*68653Smckusick 				txdr_hyper(&at.va_filerev, tl);
2522*68653Smckusick 				tl += 2;
2523*68653Smckusick 			} else
2524*68653Smckusick 				nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
252548050Smckusick 			*tl++ = nfs_false;
252648050Smckusick 			*tl = nfs_true;
252738418Smckusick 			FREE((caddr_t)rbuf, M_TEMP);
2528*68653Smckusick 			FREE((caddr_t)cookies, M_TEMP);
252938418Smckusick 			return (0);
253038418Smckusick 		}
253138418Smckusick 	}
253240115Smckusick 
253338418Smckusick 	/*
253438418Smckusick 	 * Check for degenerate cases of nothing useful read.
253540115Smckusick 	 * If so go try again
253638418Smckusick 	 */
253767363Smckusick 	cpos = rbuf;
253840115Smckusick 	cend = rbuf + siz;
2539*68653Smckusick 	dp = (struct dirent *)cpos;
2540*68653Smckusick 	cookiep = cookies;
2541*68653Smckusick 	while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2542*68653Smckusick 		cpos += dp->d_reclen;
254352441Smckusick 		dp = (struct dirent *)cpos;
2544*68653Smckusick 		cookiep++;
2545*68653Smckusick 		ncookies--;
254640115Smckusick 	}
2547*68653Smckusick 	if (cpos >= cend || ncookies == 0) {
2548*68653Smckusick 		toff = off;
254938418Smckusick 		siz = fullsiz;
255038418Smckusick 		goto again;
255138418Smckusick 	}
255240115Smckusick 
2553*68653Smckusick 	len = 3 * NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
2554*68653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
2555*68653Smckusick 	if (v3) {
2556*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
2557*68653Smckusick 		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2558*68653Smckusick 		txdr_hyper(&at.va_filerev, tl);
2559*68653Smckusick 	}
256052196Smckusick 	mp = mp2 = mb;
256152196Smckusick 	bp = bpos;
256252196Smckusick 	be = bp + M_TRAILINGSPACE(mp);
256352196Smckusick 
256452196Smckusick 	/* Loop through the records and build reply */
2565*68653Smckusick 	while (cpos < cend && ncookies > 0) {
256652441Smckusick 		if (dp->d_fileno != 0) {
256752196Smckusick 			nlen = dp->d_namlen;
256852196Smckusick 			rem = nfsm_rndup(nlen)-nlen;
2569*68653Smckusick 			len += (4 * NFSX_UNSIGNED + nlen + rem);
2570*68653Smckusick 			if (v3)
2571*68653Smckusick 				len += 2 * NFSX_UNSIGNED;
257252196Smckusick 			if (len > cnt) {
257352196Smckusick 				eofflag = 0;
257452196Smckusick 				break;
257552196Smckusick 			}
257652441Smckusick 			/*
257752441Smckusick 			 * Build the directory record xdr from
257852441Smckusick 			 * the dirent entry.
257952441Smckusick 			 */
258052196Smckusick 			nfsm_clget;
258152196Smckusick 			*tl = nfs_true;
258252196Smckusick 			bp += NFSX_UNSIGNED;
2583*68653Smckusick 			if (v3) {
2584*68653Smckusick 				nfsm_clget;
2585*68653Smckusick 				*tl = 0;
2586*68653Smckusick 				bp += NFSX_UNSIGNED;
2587*68653Smckusick 			}
258852196Smckusick 			nfsm_clget;
258952441Smckusick 			*tl = txdr_unsigned(dp->d_fileno);
259052196Smckusick 			bp += NFSX_UNSIGNED;
259152196Smckusick 			nfsm_clget;
259252196Smckusick 			*tl = txdr_unsigned(nlen);
259352196Smckusick 			bp += NFSX_UNSIGNED;
259452196Smckusick 
259552196Smckusick 			/* And loop around copying the name */
259652196Smckusick 			xfer = nlen;
259752196Smckusick 			cp = dp->d_name;
259852196Smckusick 			while (xfer > 0) {
259952196Smckusick 				nfsm_clget;
260052196Smckusick 				if ((bp+xfer) > be)
260152196Smckusick 					tsiz = be-bp;
260252196Smckusick 				else
260352196Smckusick 					tsiz = xfer;
260452196Smckusick 				bcopy(cp, bp, tsiz);
260552196Smckusick 				bp += tsiz;
260652196Smckusick 				xfer -= tsiz;
260752196Smckusick 				if (xfer > 0)
260852196Smckusick 					cp += tsiz;
260952196Smckusick 			}
261052196Smckusick 			/* And null pad to a long boundary */
261152196Smckusick 			for (i = 0; i < rem; i++)
261252196Smckusick 				*bp++ = '\0';
261352196Smckusick 			nfsm_clget;
261452196Smckusick 
261552196Smckusick 			/* Finish off the record */
2616*68653Smckusick 			if (v3) {
2617*68653Smckusick 				*tl = 0;
2618*68653Smckusick 				bp += NFSX_UNSIGNED;
2619*68653Smckusick 				nfsm_clget;
2620*68653Smckusick 			}
2621*68653Smckusick 			*tl = txdr_unsigned(*cookiep);
262252196Smckusick 			bp += NFSX_UNSIGNED;
262367363Smckusick 		}
262452196Smckusick 		cpos += dp->d_reclen;
262552441Smckusick 		dp = (struct dirent *)cpos;
2626*68653Smckusick 		cookiep++;
2627*68653Smckusick 		ncookies--;
262852196Smckusick 	}
262938418Smckusick 	vrele(vp);
263052196Smckusick 	nfsm_clget;
263152196Smckusick 	*tl = nfs_false;
263252196Smckusick 	bp += NFSX_UNSIGNED;
263352196Smckusick 	nfsm_clget;
263452196Smckusick 	if (eofflag)
263552196Smckusick 		*tl = nfs_true;
263652196Smckusick 	else
263752196Smckusick 		*tl = nfs_false;
263852196Smckusick 	bp += NFSX_UNSIGNED;
263952196Smckusick 	if (mp != mb) {
264052196Smckusick 		if (bp < be)
264152196Smckusick 			mp->m_len = bp - mtod(mp, caddr_t);
264252196Smckusick 	} else
264352196Smckusick 		mp->m_len += bp - bpos;
2644*68653Smckusick 	FREE((caddr_t)rbuf, M_TEMP);
2645*68653Smckusick 	FREE((caddr_t)cookies, M_TEMP);
264652196Smckusick 	nfsm_srvdone;
264752196Smckusick }
264852196Smckusick 
2649*68653Smckusick int
2650*68653Smckusick nfsrv_readdirplus(nfsd, slp, procp, mrq)
2651*68653Smckusick 	struct nfsrv_descript *nfsd;
2652*68653Smckusick 	struct nfssvc_sock *slp;
2653*68653Smckusick 	struct proc *procp;
2654*68653Smckusick 	struct mbuf **mrq;
265552196Smckusick {
2656*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2657*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
2658*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
2659*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
266052196Smckusick 	register char *bp, *be;
266152196Smckusick 	register struct mbuf *mp;
266252441Smckusick 	register struct dirent *dp;
266352196Smckusick 	register caddr_t cp;
266452196Smckusick 	register u_long *tl;
266552196Smckusick 	register long t1;
266652196Smckusick 	caddr_t bpos;
266752196Smckusick 	struct mbuf *mb, *mb2, *mreq, *mp2;
266852196Smckusick 	char *cpos, *cend, *cp2, *rbuf;
266952196Smckusick 	struct vnode *vp, *nvp;
267052196Smckusick 	struct flrep fl;
2671*68653Smckusick 	nfsfh_t nfh;
2672*68653Smckusick 	fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
267352196Smckusick 	struct uio io;
267452196Smckusick 	struct iovec iv;
2675*68653Smckusick 	struct vattr va, at, *vap = &va;
2676*68653Smckusick 	struct nfs_fattr *fp;
2677*68653Smckusick 	int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
2678*68653Smckusick 	int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
2679*68653Smckusick 	u_quad_t frev, off, toff, verf;
2680*68653Smckusick 	u_long *cookies = NULL, *cookiep;
268152196Smckusick 
268252196Smckusick 	fhp = &nfh.fh_generic;
268352196Smckusick 	nfsm_srvmtofh(fhp);
2684*68653Smckusick 	nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
2685*68653Smckusick 	fxdr_hyper(tl, &toff);
2686*68653Smckusick 	tl += 2;
2687*68653Smckusick 	fxdr_hyper(tl, &verf);
2688*68653Smckusick 	tl += 2;
2689*68653Smckusick 	siz = fxdr_unsigned(int, *tl++);
2690*68653Smckusick 	cnt = fxdr_unsigned(int, *tl);
2691*68653Smckusick 	off = toff;
2692*68653Smckusick 	siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
2693*68653Smckusick 	xfer = NFS_SRVMAXDATA(nfsd);
2694*68653Smckusick 	if (siz > xfer)
2695*68653Smckusick 		siz = xfer;
269652196Smckusick 	fullsiz = siz;
2697*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2698*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2699*68653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
2700*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
2701*68653Smckusick 		return (0);
2702*68653Smckusick 	}
2703*68653Smckusick 	error = getret = VOP_GETATTR(vp, &at, cred, procp);
2704*68653Smckusick 	if (!error && toff && verf != at.va_filerev)
2705*68653Smckusick 		error = NFSERR_BAD_COOKIE;
2706*68653Smckusick 	if (!error) {
2707*68653Smckusick 		nqsrv_getl(vp, ND_READ);
2708*68653Smckusick 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
2709*68653Smckusick 	}
2710*68653Smckusick 	if (error) {
271152196Smckusick 		vput(vp);
2712*68653Smckusick 		nfsm_reply(NFSX_V3POSTOPATTR);
2713*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
2714*68653Smckusick 		return (0);
271552196Smckusick 	}
271652196Smckusick 	VOP_UNLOCK(vp);
271752196Smckusick 	MALLOC(rbuf, caddr_t, siz, M_TEMP, M_WAITOK);
271852196Smckusick again:
271952196Smckusick 	iv.iov_base = rbuf;
272052196Smckusick 	iv.iov_len = fullsiz;
272152196Smckusick 	io.uio_iov = &iv;
272252196Smckusick 	io.uio_iovcnt = 1;
272356285Smckusick 	io.uio_offset = (off_t)off;
272452196Smckusick 	io.uio_resid = fullsiz;
272552196Smckusick 	io.uio_segflg = UIO_SYSSPACE;
272652196Smckusick 	io.uio_rw = UIO_READ;
272752196Smckusick 	io.uio_procp = (struct proc *)0;
2728*68653Smckusick 	eofflag = 0;
2729*68653Smckusick 	if (cookies) {
2730*68653Smckusick 		free((caddr_t)cookies, M_TEMP);
2731*68653Smckusick 		cookies = NULL;
2732*68653Smckusick 	}
2733*68653Smckusick 	error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
2734*68653Smckusick 	off = (u_quad_t)io.uio_offset;
2735*68653Smckusick 	getret = VOP_GETATTR(vp, &at, cred, procp);
2736*68653Smckusick 	if (!cookies && !error)
2737*68653Smckusick 		error = NFSERR_PERM;
2738*68653Smckusick 	if (!error)
2739*68653Smckusick 		error = getret;
274052196Smckusick 	if (error) {
274152196Smckusick 		vrele(vp);
2742*68653Smckusick 		if (cookies)
2743*68653Smckusick 			free((caddr_t)cookies, M_TEMP);
274452196Smckusick 		free((caddr_t)rbuf, M_TEMP);
2745*68653Smckusick 		nfsm_reply(NFSX_V3POSTOPATTR);
2746*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
2747*68653Smckusick 		return (0);
274852196Smckusick 	}
274952196Smckusick 	if (io.uio_resid) {
275052196Smckusick 		siz -= io.uio_resid;
275152196Smckusick 
275252196Smckusick 		/*
275352196Smckusick 		 * If nothing read, return eof
275452196Smckusick 		 * rpc reply
275552196Smckusick 		 */
275652196Smckusick 		if (siz == 0) {
275752196Smckusick 			vrele(vp);
2758*68653Smckusick 			nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
2759*68653Smckusick 				2 * NFSX_UNSIGNED);
2760*68653Smckusick 			nfsm_srvpostop_attr(getret, &at);
2761*68653Smckusick 			nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
2762*68653Smckusick 			txdr_hyper(&at.va_filerev, tl);
2763*68653Smckusick 			tl += 2;
276452196Smckusick 			*tl++ = nfs_false;
276552196Smckusick 			*tl = nfs_true;
2766*68653Smckusick 			FREE((caddr_t)cookies, M_TEMP);
276752196Smckusick 			FREE((caddr_t)rbuf, M_TEMP);
276852196Smckusick 			return (0);
276952196Smckusick 		}
277052196Smckusick 	}
277152196Smckusick 
277252196Smckusick 	/*
277352196Smckusick 	 * Check for degenerate cases of nothing useful read.
277452196Smckusick 	 * If so go try again
277552196Smckusick 	 */
277667363Smckusick 	cpos = rbuf;
277752196Smckusick 	cend = rbuf + siz;
2778*68653Smckusick 	dp = (struct dirent *)cpos;
2779*68653Smckusick 	cookiep = cookies;
2780*68653Smckusick 	while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
2781*68653Smckusick 		cpos += dp->d_reclen;
278252441Smckusick 		dp = (struct dirent *)cpos;
2783*68653Smckusick 		cookiep++;
2784*68653Smckusick 		ncookies--;
278552196Smckusick 	}
2786*68653Smckusick 	if (cpos >= cend || ncookies == 0) {
2787*68653Smckusick 		toff = off;
278852196Smckusick 		siz = fullsiz;
278952196Smckusick 		goto again;
279052196Smckusick 	}
279152196Smckusick 
2792*68653Smckusick 	dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
2793*68653Smckusick 	nfsm_reply(cnt);
2794*68653Smckusick 	nfsm_srvpostop_attr(getret, &at);
2795*68653Smckusick 	nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
2796*68653Smckusick 	txdr_hyper(&at.va_filerev, tl);
279752196Smckusick 	mp = mp2 = mb;
279852196Smckusick 	bp = bpos;
279952196Smckusick 	be = bp + M_TRAILINGSPACE(mp);
280038418Smckusick 
280138418Smckusick 	/* Loop through the records and build reply */
2802*68653Smckusick 	while (cpos < cend && ncookies > 0) {
280352441Smckusick 		if (dp->d_fileno != 0) {
280438418Smckusick 			nlen = dp->d_namlen;
280538418Smckusick 			rem = nfsm_rndup(nlen)-nlen;
280638425Smckusick 
280738418Smckusick 			/*
280852196Smckusick 			 * For readdir_and_lookup get the vnode using
280952196Smckusick 			 * the file number.
281038418Smckusick 			 */
281154665Smckusick 			if (VFS_VGET(vp->v_mount, dp->d_fileno, &nvp))
281252196Smckusick 				goto invalid;
2813*68653Smckusick 			bzero((caddr_t)nfhp, NFSX_V3FH);
2814*68653Smckusick 			nfhp->fh_fsid =
281555655Smckusick 				nvp->v_mount->mnt_stat.f_fsid;
2816*68653Smckusick 			if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
281755655Smckusick 				vput(nvp);
281855655Smckusick 				goto invalid;
281955655Smckusick 			}
2820*68653Smckusick 			if (VOP_GETATTR(nvp, vap, cred, procp)) {
282152196Smckusick 				vput(nvp);
282252196Smckusick 				goto invalid;
282352196Smckusick 			}
282452196Smckusick 			vput(nvp);
2825*68653Smckusick 
2826*68653Smckusick 			/*
2827*68653Smckusick 			 * If either the dircount or maxcount will be
2828*68653Smckusick 			 * exceeded, get out now. Both of these lengths
2829*68653Smckusick 			 * are calculated conservatively, including all
2830*68653Smckusick 			 * XDR overheads.
2831*68653Smckusick 			 */
2832*68653Smckusick 			len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
2833*68653Smckusick 				NFSX_V3POSTOPATTR);
2834*68653Smckusick 			dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
2835*68653Smckusick 			if (len > cnt || dirlen > fullsiz) {
283641899Smckusick 				eofflag = 0;
283738418Smckusick 				break;
283841899Smckusick 			}
2839*68653Smckusick 
284052441Smckusick 			/*
284152441Smckusick 			 * Build the directory record xdr from
284252441Smckusick 			 * the dirent entry.
284352441Smckusick 			 */
2844*68653Smckusick 			fp = (struct nfs_fattr *)&fl.fl_fattr;
2845*68653Smckusick 			nfsm_srvfillattr(vap, fp);
2846*68653Smckusick 			fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
2847*68653Smckusick 			fl.fl_fhok = nfs_true;
2848*68653Smckusick 			fl.fl_postopok = nfs_true;
2849*68653Smckusick 			fl.fl_off.nfsuquad[0] = 0;
2850*68653Smckusick 			fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
2851*68653Smckusick 
285238418Smckusick 			nfsm_clget;
285348050Smckusick 			*tl = nfs_true;
285438418Smckusick 			bp += NFSX_UNSIGNED;
285538418Smckusick 			nfsm_clget;
2856*68653Smckusick 			*tl = 0;
2857*68653Smckusick 			bp += NFSX_UNSIGNED;
2858*68653Smckusick 			nfsm_clget;
285952441Smckusick 			*tl = txdr_unsigned(dp->d_fileno);
286038418Smckusick 			bp += NFSX_UNSIGNED;
286138418Smckusick 			nfsm_clget;
286248050Smckusick 			*tl = txdr_unsigned(nlen);
286338418Smckusick 			bp += NFSX_UNSIGNED;
286438425Smckusick 
286552196Smckusick 			/* And loop around copying the name */
286638418Smckusick 			xfer = nlen;
286738418Smckusick 			cp = dp->d_name;
286838418Smckusick 			while (xfer > 0) {
286938418Smckusick 				nfsm_clget;
2870*68653Smckusick 				if ((bp + xfer) > be)
2871*68653Smckusick 					tsiz = be - bp;
287238418Smckusick 				else
287338418Smckusick 					tsiz = xfer;
287438418Smckusick 				bcopy(cp, bp, tsiz);
287538418Smckusick 				bp += tsiz;
287638418Smckusick 				xfer -= tsiz;
287738418Smckusick 				if (xfer > 0)
287838418Smckusick 					cp += tsiz;
287938418Smckusick 			}
288038418Smckusick 			/* And null pad to a long boundary */
288138418Smckusick 			for (i = 0; i < rem; i++)
288238418Smckusick 				*bp++ = '\0';
288338425Smckusick 
2884*68653Smckusick 			/*
2885*68653Smckusick 			 * Now copy the flrep structure out.
2886*68653Smckusick 			 */
2887*68653Smckusick 			xfer = sizeof (struct flrep);
2888*68653Smckusick 			cp = (caddr_t)&fl;
2889*68653Smckusick 			while (xfer > 0) {
2890*68653Smckusick 				nfsm_clget;
2891*68653Smckusick 				if ((bp + xfer) > be)
2892*68653Smckusick 					tsiz = be - bp;
2893*68653Smckusick 				else
2894*68653Smckusick 					tsiz = xfer;
2895*68653Smckusick 				bcopy(cp, bp, tsiz);
2896*68653Smckusick 				bp += tsiz;
2897*68653Smckusick 				xfer -= tsiz;
2898*68653Smckusick 				if (xfer > 0)
2899*68653Smckusick 					cp += tsiz;
2900*68653Smckusick 			}
290167363Smckusick 		}
290252196Smckusick invalid:
290338418Smckusick 		cpos += dp->d_reclen;
290452441Smckusick 		dp = (struct dirent *)cpos;
2905*68653Smckusick 		cookiep++;
2906*68653Smckusick 		ncookies--;
290738418Smckusick 	}
290852196Smckusick 	vrele(vp);
290938418Smckusick 	nfsm_clget;
291048050Smckusick 	*tl = nfs_false;
291138418Smckusick 	bp += NFSX_UNSIGNED;
291238418Smckusick 	nfsm_clget;
291340296Smckusick 	if (eofflag)
291448050Smckusick 		*tl = nfs_true;
291540296Smckusick 	else
291648050Smckusick 		*tl = nfs_false;
291738418Smckusick 	bp += NFSX_UNSIGNED;
291852196Smckusick 	if (mp != mb) {
291952196Smckusick 		if (bp < be)
292052196Smckusick 			mp->m_len = bp - mtod(mp, caddr_t);
292152196Smckusick 	} else
292252196Smckusick 		mp->m_len += bp - bpos;
2923*68653Smckusick 	FREE((caddr_t)cookies, M_TEMP);
2924*68653Smckusick 	FREE((caddr_t)rbuf, M_TEMP);
292538418Smckusick 	nfsm_srvdone;
292638418Smckusick }
292738418Smckusick 
292838418Smckusick /*
2929*68653Smckusick  * nfs commit service
2930*68653Smckusick  */
2931*68653Smckusick int
2932*68653Smckusick nfsrv_commit(nfsd, slp, procp, mrq)
2933*68653Smckusick 	struct nfsrv_descript *nfsd;
2934*68653Smckusick 	struct nfssvc_sock *slp;
2935*68653Smckusick 	struct proc *procp;
2936*68653Smckusick 	struct mbuf **mrq;
2937*68653Smckusick {
2938*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
2939*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
2940*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
2941*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
2942*68653Smckusick 	struct vattr bfor, aft;
2943*68653Smckusick 	struct vnode *vp;
2944*68653Smckusick 	nfsfh_t nfh;
2945*68653Smckusick 	fhandle_t *fhp;
2946*68653Smckusick 	register u_long *tl;
2947*68653Smckusick 	register long t1;
2948*68653Smckusick 	caddr_t bpos;
2949*68653Smckusick 	int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
2950*68653Smckusick 	char *cp2;
2951*68653Smckusick 	struct mbuf *mb, *mb2, *mreq;
2952*68653Smckusick 	u_quad_t frev, off;
2953*68653Smckusick 
2954*68653Smckusick #ifndef nolint
2955*68653Smckusick 	cache = 0;
2956*68653Smckusick #endif
2957*68653Smckusick 	fhp = &nfh.fh_generic;
2958*68653Smckusick 	nfsm_srvmtofh(fhp);
2959*68653Smckusick 	nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
2960*68653Smckusick 
2961*68653Smckusick 	/*
2962*68653Smckusick 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
2963*68653Smckusick 	 * count parameters, so these arguments are useless (someday maybe).
2964*68653Smckusick 	 */
2965*68653Smckusick 	fxdr_hyper(tl, &off);
2966*68653Smckusick 	tl += 2;
2967*68653Smckusick 	cnt = fxdr_unsigned(int, *tl);
2968*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
2969*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
2970*68653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
2971*68653Smckusick 		nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
2972*68653Smckusick 		return (0);
2973*68653Smckusick 	}
2974*68653Smckusick 	for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
2975*68653Smckusick 	error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
2976*68653Smckusick 	aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
2977*68653Smckusick 	vput(vp);
2978*68653Smckusick 	nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
2979*68653Smckusick 	nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
2980*68653Smckusick 	if (!error) {
2981*68653Smckusick 		nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
2982*68653Smckusick 		*tl++ = txdr_unsigned(boottime.tv_sec);
2983*68653Smckusick 		*tl = txdr_unsigned(boottime.tv_usec);
2984*68653Smckusick 	} else
2985*68653Smckusick 		return (0);
2986*68653Smckusick 	nfsm_srvdone;
2987*68653Smckusick }
2988*68653Smckusick 
2989*68653Smckusick /*
299038418Smckusick  * nfs statfs service
299138418Smckusick  */
2992*68653Smckusick int
2993*68653Smckusick nfsrv_statfs(nfsd, slp, procp, mrq)
2994*68653Smckusick 	struct nfsrv_descript *nfsd;
2995*68653Smckusick 	struct nfssvc_sock *slp;
2996*68653Smckusick 	struct proc *procp;
2997*68653Smckusick 	struct mbuf **mrq;
299838418Smckusick {
2999*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3000*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
3001*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
3002*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
300338418Smckusick 	register struct statfs *sf;
3004*68653Smckusick 	register struct nfs_statfs *sfp;
300548050Smckusick 	register u_long *tl;
300639494Smckusick 	register long t1;
300739494Smckusick 	caddr_t bpos;
3008*68653Smckusick 	int error = 0, rdonly, cache, getret = 1;
3009*68653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
301039494Smckusick 	char *cp2;
301139753Smckusick 	struct mbuf *mb, *mb2, *mreq;
301238418Smckusick 	struct vnode *vp;
3013*68653Smckusick 	struct vattr at;
3014*68653Smckusick 	nfsfh_t nfh;
301538418Smckusick 	fhandle_t *fhp;
301638418Smckusick 	struct statfs statfs;
3017*68653Smckusick 	u_quad_t frev, tval;
301838418Smckusick 
3019*68653Smckusick #ifndef nolint
3020*68653Smckusick 	cache = 0;
3021*68653Smckusick #endif
302238418Smckusick 	fhp = &nfh.fh_generic;
302338418Smckusick 	nfsm_srvmtofh(fhp);
3024*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3025*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3026*68653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
3027*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
3028*68653Smckusick 		return (0);
3029*68653Smckusick 	}
303038418Smckusick 	sf = &statfs;
3031*68653Smckusick 	error = VFS_STATFS(vp->v_mount, sf, procp);
3032*68653Smckusick 	getret = VOP_GETATTR(vp, &at, cred, procp);
303338418Smckusick 	vput(vp);
3034*68653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
3035*68653Smckusick 	if (v3)
3036*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
3037*68653Smckusick 	if (error)
3038*68653Smckusick 		return (0);
3039*68653Smckusick 	nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
3040*68653Smckusick 	if (v3) {
3041*68653Smckusick 		tval = (u_quad_t)sf->f_blocks;
3042*68653Smckusick 		tval *= (u_quad_t)sf->f_bsize;
3043*68653Smckusick 		txdr_hyper(&tval, &sfp->sf_tbytes);
3044*68653Smckusick 		tval = (u_quad_t)sf->f_bfree;
3045*68653Smckusick 		tval *= (u_quad_t)sf->f_bsize;
3046*68653Smckusick 		txdr_hyper(&tval, &sfp->sf_fbytes);
3047*68653Smckusick 		tval = (u_quad_t)sf->f_bavail;
3048*68653Smckusick 		tval *= (u_quad_t)sf->f_bsize;
3049*68653Smckusick 		txdr_hyper(&tval, &sfp->sf_abytes);
3050*68653Smckusick 		sfp->sf_tfiles.nfsuquad[0] = 0;
3051*68653Smckusick 		sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
3052*68653Smckusick 		sfp->sf_ffiles.nfsuquad[0] = 0;
3053*68653Smckusick 		sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3054*68653Smckusick 		sfp->sf_afiles.nfsuquad[0] = 0;
3055*68653Smckusick 		sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
3056*68653Smckusick 		sfp->sf_invarsec = 0;
3057*68653Smckusick 	} else {
3058*68653Smckusick 		sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
3059*68653Smckusick 		sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
3060*68653Smckusick 		sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
3061*68653Smckusick 		sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
3062*68653Smckusick 		sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
306356285Smckusick 	}
306438418Smckusick 	nfsm_srvdone;
306538418Smckusick }
306638418Smckusick 
306738418Smckusick /*
3068*68653Smckusick  * nfs fsinfo service
3069*68653Smckusick  */
3070*68653Smckusick int
3071*68653Smckusick nfsrv_fsinfo(nfsd, slp, procp, mrq)
3072*68653Smckusick 	struct nfsrv_descript *nfsd;
3073*68653Smckusick 	struct nfssvc_sock *slp;
3074*68653Smckusick 	struct proc *procp;
3075*68653Smckusick 	struct mbuf **mrq;
3076*68653Smckusick {
3077*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3078*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
3079*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
3080*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
3081*68653Smckusick 	register u_long *tl;
3082*68653Smckusick 	register struct nfsv3_fsinfo *sip;
3083*68653Smckusick 	register long t1;
3084*68653Smckusick 	caddr_t bpos;
3085*68653Smckusick 	int error = 0, rdonly, cache, getret = 1, pref;
3086*68653Smckusick 	char *cp2;
3087*68653Smckusick 	struct mbuf *mb, *mb2, *mreq;
3088*68653Smckusick 	struct vnode *vp;
3089*68653Smckusick 	struct vattr at;
3090*68653Smckusick 	nfsfh_t nfh;
3091*68653Smckusick 	fhandle_t *fhp;
3092*68653Smckusick 	u_quad_t frev;
3093*68653Smckusick 
3094*68653Smckusick #ifndef nolint
3095*68653Smckusick 	cache = 0;
3096*68653Smckusick #endif
3097*68653Smckusick 	fhp = &nfh.fh_generic;
3098*68653Smckusick 	nfsm_srvmtofh(fhp);
3099*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3100*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3101*68653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
3102*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
3103*68653Smckusick 		return (0);
3104*68653Smckusick 	}
3105*68653Smckusick 	getret = VOP_GETATTR(vp, &at, cred, procp);
3106*68653Smckusick 	vput(vp);
3107*68653Smckusick 	nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
3108*68653Smckusick 	nfsm_srvpostop_attr(getret, &at);
3109*68653Smckusick 	nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
3110*68653Smckusick 
3111*68653Smckusick 	/*
3112*68653Smckusick 	 * XXX
3113*68653Smckusick 	 * There should be file system VFS OP(s) to get this information.
3114*68653Smckusick 	 * For now, assume ufs.
3115*68653Smckusick 	 */
3116*68653Smckusick 	if (slp->ns_so->so_type == SOCK_DGRAM)
3117*68653Smckusick 		pref = NFS_MAXDGRAMDATA;
3118*68653Smckusick 	else
3119*68653Smckusick 		pref = NFS_MAXDATA;
3120*68653Smckusick 	sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
3121*68653Smckusick 	sip->fs_rtpref = txdr_unsigned(pref);
3122*68653Smckusick 	sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
3123*68653Smckusick 	sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
3124*68653Smckusick 	sip->fs_wtpref = txdr_unsigned(pref);
3125*68653Smckusick 	sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
3126*68653Smckusick 	sip->fs_dtpref = txdr_unsigned(pref);
3127*68653Smckusick 	sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
3128*68653Smckusick 	sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
3129*68653Smckusick 	sip->fs_timedelta.nfsv3_sec = 0;
3130*68653Smckusick 	sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
3131*68653Smckusick 	sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
3132*68653Smckusick 		NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
3133*68653Smckusick 		NFSV3FSINFO_CANSETTIME);
3134*68653Smckusick 	nfsm_srvdone;
3135*68653Smckusick }
3136*68653Smckusick 
3137*68653Smckusick /*
3138*68653Smckusick  * nfs pathconf service
3139*68653Smckusick  */
3140*68653Smckusick int
3141*68653Smckusick nfsrv_pathconf(nfsd, slp, procp, mrq)
3142*68653Smckusick 	struct nfsrv_descript *nfsd;
3143*68653Smckusick 	struct nfssvc_sock *slp;
3144*68653Smckusick 	struct proc *procp;
3145*68653Smckusick 	struct mbuf **mrq;
3146*68653Smckusick {
3147*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3148*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
3149*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
3150*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
3151*68653Smckusick 	register u_long *tl;
3152*68653Smckusick 	register struct nfsv3_pathconf *pc;
3153*68653Smckusick 	register long t1;
3154*68653Smckusick 	caddr_t bpos;
3155*68653Smckusick 	int error = 0, rdonly, cache, getret = 1, linkmax, namemax;
3156*68653Smckusick 	int chownres, notrunc;
3157*68653Smckusick 	char *cp2;
3158*68653Smckusick 	struct mbuf *mb, *mb2, *mreq;
3159*68653Smckusick 	struct vnode *vp;
3160*68653Smckusick 	struct vattr at;
3161*68653Smckusick 	nfsfh_t nfh;
3162*68653Smckusick 	fhandle_t *fhp;
3163*68653Smckusick 	u_quad_t frev;
3164*68653Smckusick 
3165*68653Smckusick #ifndef nolint
3166*68653Smckusick 	cache = 0;
3167*68653Smckusick #endif
3168*68653Smckusick 	fhp = &nfh.fh_generic;
3169*68653Smckusick 	nfsm_srvmtofh(fhp);
3170*68653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
3171*68653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
3172*68653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
3173*68653Smckusick 		nfsm_srvpostop_attr(getret, &at);
3174*68653Smckusick 		return (0);
3175*68653Smckusick 	}
3176*68653Smckusick 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
3177*68653Smckusick 	if (!error)
3178*68653Smckusick 		error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
3179*68653Smckusick 	if (!error)
3180*68653Smckusick 		error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
3181*68653Smckusick 	if (!error)
3182*68653Smckusick 		error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
3183*68653Smckusick 	getret = VOP_GETATTR(vp, &at, cred, procp);
3184*68653Smckusick 	vput(vp);
3185*68653Smckusick 	nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
3186*68653Smckusick 	nfsm_srvpostop_attr(getret, &at);
3187*68653Smckusick 	if (error)
3188*68653Smckusick 		return (0);
3189*68653Smckusick 	nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
3190*68653Smckusick 
3191*68653Smckusick 	pc->pc_linkmax = txdr_unsigned(linkmax);
3192*68653Smckusick 	pc->pc_namemax = txdr_unsigned(namemax);
3193*68653Smckusick 	pc->pc_notrunc = txdr_unsigned(notrunc);
3194*68653Smckusick 	pc->pc_chownrestricted = txdr_unsigned(chownres);
3195*68653Smckusick 
3196*68653Smckusick 	/*
3197*68653Smckusick 	 * These should probably be supported by VOP_PATHCONF(), but
3198*68653Smckusick 	 * until msdosfs is exportable (why would you want to?), the
3199*68653Smckusick 	 * Unix defaults should be ok.
3200*68653Smckusick 	 */
3201*68653Smckusick 	pc->pc_caseinsensitive = nfs_false;
3202*68653Smckusick 	pc->pc_casepreserving = nfs_true;
3203*68653Smckusick 	nfsm_srvdone;
3204*68653Smckusick }
3205*68653Smckusick 
3206*68653Smckusick /*
320738418Smckusick  * Null operation, used by clients to ping server
320838418Smckusick  */
320939494Smckusick /* ARGSUSED */
3210*68653Smckusick int
3211*68653Smckusick nfsrv_null(nfsd, slp, procp, mrq)
3212*68653Smckusick 	struct nfsrv_descript *nfsd;
3213*68653Smckusick 	struct nfssvc_sock *slp;
3214*68653Smckusick 	struct proc *procp;
3215*68653Smckusick 	struct mbuf **mrq;
321638418Smckusick {
3217*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3218*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
3219*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
3220*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
322139494Smckusick 	caddr_t bpos;
3222*68653Smckusick 	int error = NFSERR_RETVOID, cache;
322339753Smckusick 	struct mbuf *mb, *mreq;
322452196Smckusick 	u_quad_t frev;
322538418Smckusick 
3226*68653Smckusick #ifndef nolint
3227*68653Smckusick 	cache = 0;
3228*68653Smckusick #endif
322938418Smckusick 	nfsm_reply(0);
3230*68653Smckusick 	return (0);
323138418Smckusick }
323238418Smckusick 
323338418Smckusick /*
323438418Smckusick  * No operation, used for obsolete procedures
323538418Smckusick  */
323639494Smckusick /* ARGSUSED */
3237*68653Smckusick int
3238*68653Smckusick nfsrv_noop(nfsd, slp, procp, mrq)
3239*68653Smckusick 	struct nfsrv_descript *nfsd;
3240*68653Smckusick 	struct nfssvc_sock *slp;
3241*68653Smckusick 	struct proc *procp;
3242*68653Smckusick 	struct mbuf **mrq;
324338418Smckusick {
3244*68653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
3245*68653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
3246*68653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
3247*68653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
324839494Smckusick 	caddr_t bpos;
324952196Smckusick 	int error, cache;
325039753Smckusick 	struct mbuf *mb, *mreq;
325152196Smckusick 	u_quad_t frev;
325238418Smckusick 
3253*68653Smckusick #ifndef nolint
3254*68653Smckusick 	cache = 0;
3255*68653Smckusick #endif
325652196Smckusick 	if (nfsd->nd_repstat)
325752196Smckusick 		error = nfsd->nd_repstat;
325852196Smckusick 	else
325952196Smckusick 		error = EPROCUNAVAIL;
326038418Smckusick 	nfsm_reply(0);
3261*68653Smckusick 	return (0);
326238418Smckusick }
326338425Smckusick 
326438450Smckusick /*
326538450Smckusick  * Perform access checking for vnodes obtained from file handles that would
326638450Smckusick  * refer to files already opened by a Unix client. You cannot just use
326738450Smckusick  * vn_writechk() and VOP_ACCESS() for two reasons.
326852196Smckusick  * 1 - You must check for exported rdonly as well as MNT_RDONLY for the write case
326938450Smckusick  * 2 - The owner is to be given access irrespective of mode bits so that
327038450Smckusick  *     processes that chmod after opening a file don't break. I don't like
327138450Smckusick  *     this because it opens a security hole, but since the nfs server opens
327238450Smckusick  *     a security hole the size of a barn door anyhow, what the heck.
327338450Smckusick  */
3274*68653Smckusick int
327552196Smckusick nfsrv_access(vp, flags, cred, rdonly, p)
327638450Smckusick 	register struct vnode *vp;
327738450Smckusick 	int flags;
327838450Smckusick 	register struct ucred *cred;
327952196Smckusick 	int rdonly;
328048050Smckusick 	struct proc *p;
328138450Smckusick {
328238450Smckusick 	struct vattr vattr;
328338450Smckusick 	int error;
328438450Smckusick 	if (flags & VWRITE) {
328552196Smckusick 		/* Just vn_writechk() changed to check rdonly */
328638450Smckusick 		/*
328738450Smckusick 		 * Disallow write attempts on read-only file systems;
328838450Smckusick 		 * unless the file is a socket or a block or character
328938450Smckusick 		 * device resident on the file system.
329038450Smckusick 		 */
329152196Smckusick 		if (rdonly || (vp->v_mount->mnt_flag & MNT_RDONLY)) {
329245059Smckusick 			switch (vp->v_type) {
329345059Smckusick 			case VREG: case VDIR: case VLNK:
329438450Smckusick 				return (EROFS);
329545059Smckusick 			}
329645059Smckusick 		}
329738450Smckusick 		/*
329838450Smckusick 		 * If there's shared text associated with
329938450Smckusick 		 * the inode, try to free it up once.  If
330038450Smckusick 		 * we fail, we can't allow writing.
330138450Smckusick 		 */
330245715Smckusick 		if ((vp->v_flag & VTEXT) && !vnode_pager_uncache(vp))
330338450Smckusick 			return (ETXTBSY);
330438450Smckusick 	}
330548050Smckusick 	if (error = VOP_GETATTR(vp, &vattr, cred, p))
330645059Smckusick 		return (error);
330748050Smckusick 	if ((error = VOP_ACCESS(vp, flags, cred, p)) &&
330845059Smckusick 	    cred->cr_uid != vattr.va_uid)
330945059Smckusick 		return (error);
331045059Smckusick 	return (0);
331138450Smckusick }
3312