xref: /csrg-svn/sys/nfs/nfs_serv.c (revision 69424)
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*69424Smckusick  *	@(#)nfs_serv.c	8.7 (Berkeley) 05/14/95
1138418Smckusick  */
1238418Smckusick 
1338418Smckusick /*
1468653Smckusick  * 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.
2968653Smckusick  *	For Version 3, nfsm_reply() does not return for the error case, since
3068653Smckusick  *	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>
4068653Smckusick #include <sys/socket.h>
4168653Smckusick #include <sys/socketvar.h>
4253322Smckusick #include <sys/mbuf.h>
4353322Smckusick #include <sys/dirent.h>
4454446Smckusick #include <sys/stat.h>
4568653Smckusick #include <sys/kernel.h>
4668653Smckusick #include <ufs/ufs/dir.h>
4747573Skarels 
4853322Smckusick #include <vm/vm.h>
4947573Skarels 
5068653Smckusick #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;
6068653Smckusick extern enum vtype nv3tov_type[8];
6168653Smckusick extern struct nfsstats nfsstats;
6268653Smckusick nfstype nfsv2_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFNON,
6342242Smckusick 		      NFCHR, NFNON };
6468653Smckusick nfstype nfsv3_type[9] = { NFNON, NFREG, NFDIR, NFBLK, NFCHR, NFLNK, NFSOCK,
6568653Smckusick 		      NFFIFO, NFNON };
6668653Smckusick int nfsrvw_procrastinate = NFS_GATHERDELAY * 1000;
6738418Smckusick 
6838418Smckusick /*
6968653Smckusick  * nfs v3 access service
7056360Smckusick  */
7168653Smckusick int
nfsrv3_access(nfsd,slp,procp,mrq)7268653Smckusick nfsrv3_access(nfsd, slp, procp, mrq)
7368653Smckusick 	struct nfsrv_descript *nfsd;
7468653Smckusick 	struct nfssvc_sock *slp;
7568653Smckusick 	struct proc *procp;
7668653Smckusick 	struct mbuf **mrq;
7756360Smckusick {
7868653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
7968653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
8068653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
8168653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
8256360Smckusick 	struct vnode *vp;
8368653Smckusick 	nfsfh_t nfh;
8456360Smckusick 	fhandle_t *fhp;
8556360Smckusick 	register u_long *tl;
8656360Smckusick 	register long t1;
8756360Smckusick 	caddr_t bpos;
8868653Smckusick 	int error = 0, rdonly, cache, getret;
8956360Smckusick 	char *cp2;
9068653Smckusick 	struct mbuf *mb, *mreq, *mb2;
9168653Smckusick 	struct vattr vattr, *vap = &vattr;
9268653Smckusick 	u_long testmode, nfsmode;
9356360Smckusick 	u_quad_t frev;
9456360Smckusick 
9568653Smckusick #ifndef nolint
9668653Smckusick 	cache = 0;
9768653Smckusick #endif
9856360Smckusick 	fhp = &nfh.fh_generic;
9956360Smckusick 	nfsm_srvmtofh(fhp);
10068653Smckusick 	nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
10168653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
10268653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
10368653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
10468653Smckusick 		nfsm_srvpostop_attr(1, (struct vattr *)0);
10568653Smckusick 		return (0);
10668653Smckusick 	}
10768653Smckusick 	nfsmode = fxdr_unsigned(u_long, *tl);
10868653Smckusick 	if ((nfsmode & NFSV3ACCESS_READ) &&
10968653Smckusick 		nfsrv_access(vp, VREAD, cred, rdonly, procp))
11068653Smckusick 		nfsmode &= ~NFSV3ACCESS_READ;
11168653Smckusick 	if (vp->v_type == VDIR)
11268653Smckusick 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
11368653Smckusick 			NFSV3ACCESS_DELETE);
11468653Smckusick 	else
11568653Smckusick 		testmode = (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
11668653Smckusick 	if ((nfsmode & testmode) &&
11768653Smckusick 		nfsrv_access(vp, VWRITE, cred, rdonly, procp))
11868653Smckusick 		nfsmode &= ~testmode;
11968653Smckusick 	if (vp->v_type == VDIR)
12068653Smckusick 		testmode = NFSV3ACCESS_LOOKUP;
12168653Smckusick 	else
12268653Smckusick 		testmode = NFSV3ACCESS_EXECUTE;
12368653Smckusick 	if ((nfsmode & testmode) &&
12468653Smckusick 		nfsrv_access(vp, VEXEC, cred, rdonly, procp))
12568653Smckusick 		nfsmode &= ~testmode;
12668653Smckusick 	getret = VOP_GETATTR(vp, vap, cred, procp);
12756360Smckusick 	vput(vp);
12868653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(1) + NFSX_UNSIGNED);
12968653Smckusick 	nfsm_srvpostop_attr(getret, vap);
13068653Smckusick 	nfsm_build(tl, u_long *, NFSX_UNSIGNED);
13168653Smckusick 	*tl = txdr_unsigned(nfsmode);
13256360Smckusick 	nfsm_srvdone;
13356360Smckusick }
13456360Smckusick 
13556360Smckusick /*
13638418Smckusick  * nfs getattr service
13738418Smckusick  */
13868653Smckusick int
nfsrv_getattr(nfsd,slp,procp,mrq)13968653Smckusick nfsrv_getattr(nfsd, slp, procp, mrq)
14068653Smckusick 	struct nfsrv_descript *nfsd;
14168653Smckusick 	struct nfssvc_sock *slp;
14268653Smckusick 	struct proc *procp;
14368653Smckusick 	struct mbuf **mrq;
14438418Smckusick {
14568653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
14668653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
14768653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
14868653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
14968653Smckusick 	register struct nfs_fattr *fp;
15038418Smckusick 	struct vattr va;
15138418Smckusick 	register struct vattr *vap = &va;
15238418Smckusick 	struct vnode *vp;
15368653Smckusick 	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);
16568653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
16668653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
16738418Smckusick 		nfsm_reply(0);
16868653Smckusick 		return (0);
16968653Smckusick 	}
17068653Smckusick 	nqsrv_getl(vp, ND_READ);
17168653Smckusick 	error = VOP_GETATTR(vp, vap, cred, procp);
17238418Smckusick 	vput(vp);
17368653Smckusick 	nfsm_reply(NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
17468653Smckusick 	if (error)
17568653Smckusick 		return (0);
17668653Smckusick 	nfsm_build(fp, struct nfs_fattr *, NFSX_FATTR(nfsd->nd_flag & ND_NFSV3));
17768653Smckusick 	nfsm_srvfillattr(vap, fp);
17838418Smckusick 	nfsm_srvdone;
17938418Smckusick }
18038418Smckusick 
18138418Smckusick /*
18238418Smckusick  * nfs setattr service
18338418Smckusick  */
18468653Smckusick int
nfsrv_setattr(nfsd,slp,procp,mrq)18568653Smckusick nfsrv_setattr(nfsd, slp, procp, mrq)
18668653Smckusick 	struct nfsrv_descript *nfsd;
18768653Smckusick 	struct nfssvc_sock *slp;
18868653Smckusick 	struct proc *procp;
18968653Smckusick 	struct mbuf **mrq;
19038418Smckusick {
19168653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
19268653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
19368653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
19468653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
19568653Smckusick 	struct vattr va, preat;
19638418Smckusick 	register struct vattr *vap = &va;
19738884Smacklem 	register struct nfsv2_sattr *sp;
19868653Smckusick 	register struct nfs_fattr *fp;
19938418Smckusick 	struct vnode *vp;
20068653Smckusick 	nfsfh_t nfh;
20138418Smckusick 	fhandle_t *fhp;
20248050Smckusick 	register u_long *tl;
20339494Smckusick 	register long t1;
20439494Smckusick 	caddr_t bpos;
20568653Smckusick 	int error = 0, rdonly, cache, preat_ret = 1, postat_ret = 1;
20668653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3), gcheck = 0;
20739494Smckusick 	char *cp2;
20839753Smckusick 	struct mbuf *mb, *mb2, *mreq;
20968653Smckusick 	u_quad_t frev;
21068653Smckusick 	struct timespec guard;
21138418Smckusick 
21238418Smckusick 	fhp = &nfh.fh_generic;
21338418Smckusick 	nfsm_srvmtofh(fhp);
21441361Smckusick 	VATTR_NULL(vap);
21568653Smckusick 	if (v3) {
21668653Smckusick 		nfsm_srvsattr(vap);
21768653Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
21868653Smckusick 		gcheck = fxdr_unsigned(int, *tl);
21968653Smckusick 		if (gcheck) {
22068653Smckusick 			nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
22168653Smckusick 			fxdr_nfsv3time(tl, &guard);
22268653Smckusick 		}
22368653Smckusick 	} else {
22468653Smckusick 		nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
22568653Smckusick 		/*
22668653Smckusick 		 * Nah nah nah nah na nah
22768653Smckusick 		 * There is a bug in the Sun client that puts 0xffff in the mode
22868653Smckusick 		 * field of sattr when it should put in 0xffffffff. The u_short
22968653Smckusick 		 * doesn't sign extend.
23068653Smckusick 		 * --> check the low order 2 bytes for 0xffff
23168653Smckusick 		 */
23268653Smckusick 		if ((fxdr_unsigned(int, sp->sa_mode) & 0xffff) != 0xffff)
23368653Smckusick 			vap->va_mode = nfstov_mode(sp->sa_mode);
23468653Smckusick 		if (sp->sa_uid != nfs_xdrneg1)
23568653Smckusick 			vap->va_uid = fxdr_unsigned(uid_t, sp->sa_uid);
23668653Smckusick 		if (sp->sa_gid != nfs_xdrneg1)
23768653Smckusick 			vap->va_gid = fxdr_unsigned(gid_t, sp->sa_gid);
23868653Smckusick 		if (sp->sa_size != nfs_xdrneg1)
23968653Smckusick 			vap->va_size = fxdr_unsigned(u_quad_t, sp->sa_size);
24068653Smckusick 		if (sp->sa_atime.nfsv2_sec != nfs_xdrneg1) {
24158880Smckusick #ifdef notyet
24268653Smckusick 			fxdr_nfsv2time(&sp->sa_atime, &vap->va_atime);
24358880Smckusick #else
24458880Smckusick 			vap->va_atime.ts_sec =
24568653Smckusick 				fxdr_unsigned(long, sp->sa_atime.nfsv2_sec);
24656285Smckusick 			vap->va_atime.ts_nsec = 0;
24758880Smckusick #endif
24856285Smckusick 		}
24968653Smckusick 		if (sp->sa_mtime.nfsv2_sec != nfs_xdrneg1)
25068653Smckusick 			fxdr_nfsv2time(&sp->sa_mtime, &vap->va_mtime);
25168653Smckusick 
25238425Smckusick 	}
25359526Smckusick 
25459526Smckusick 	/*
25568653Smckusick 	 * Now that we have all the fields, lets do it.
25668653Smckusick 	 */
25768653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
25868653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
25968653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
26068653Smckusick 		nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
26168653Smckusick 		return (0);
26268653Smckusick 	}
26368653Smckusick 	nqsrv_getl(vp, ND_WRITE);
26468653Smckusick 	if (v3) {
26568653Smckusick 		error = preat_ret = VOP_GETATTR(vp, &preat, cred, procp);
26668653Smckusick 		if (!error && gcheck &&
26768653Smckusick 			(preat.va_ctime.ts_sec != guard.ts_sec ||
26868653Smckusick 			 preat.va_ctime.ts_nsec != guard.ts_nsec))
26968653Smckusick 			error = NFSERR_NOT_SYNC;
27068653Smckusick 		if (error) {
27168653Smckusick 			vput(vp);
27268653Smckusick 			nfsm_reply(NFSX_WCCDATA(v3));
27368653Smckusick 			nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
27468653Smckusick 			return (0);
27568653Smckusick 		}
27668653Smckusick 	}
27768653Smckusick 
27868653Smckusick 	/*
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,
29268653Smckusick 			procp))
29359526Smckusick 			goto out;
29459526Smckusick 	}
29568653Smckusick 	error = VOP_SETATTR(vp, vap, cred, procp);
29668653Smckusick 	postat_ret = VOP_GETATTR(vp, vap, cred, procp);
29768653Smckusick 	if (!error)
29868653Smckusick 		error = postat_ret;
29938418Smckusick out:
30038418Smckusick 	vput(vp);
30168653Smckusick 	nfsm_reply(NFSX_WCCORFATTR(v3));
30268653Smckusick 	if (v3) {
30368653Smckusick 		nfsm_srvwcc_data(preat_ret, &preat, postat_ret, vap);
30468653Smckusick 		return (0);
30568653Smckusick 	} else {
30668653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
30768653Smckusick 		nfsm_srvfillattr(vap, fp);
30852196Smckusick 	}
30938418Smckusick 	nfsm_srvdone;
31038418Smckusick }
31138418Smckusick 
31238418Smckusick /*
31338418Smckusick  * nfs lookup rpc
31438418Smckusick  */
31568653Smckusick int
nfsrv_lookup(nfsd,slp,procp,mrq)31668653Smckusick nfsrv_lookup(nfsd, slp, procp, mrq)
31768653Smckusick 	struct nfsrv_descript *nfsd;
31868653Smckusick 	struct nfssvc_sock *slp;
31968653Smckusick 	struct proc *procp;
32068653Smckusick 	struct mbuf **mrq;
32138418Smckusick {
32268653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
32368653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
32468653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
32568653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
32668653Smckusick 	register struct nfs_fattr *fp;
32749742Smckusick 	struct nameidata nd;
32868653Smckusick 	struct vnode *vp, *dirp;
32968653Smckusick 	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;
33568653Smckusick 	int error = 0, cache, len, dirattr_ret = 1;
33668653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
33739494Smckusick 	char *cp2;
33839753Smckusick 	struct mbuf *mb, *mb2, *mreq;
33968653Smckusick 	struct vattr va, dirattr, *vap = &va;
34068653Smckusick 	u_quad_t frev;
34138418Smckusick 
34238418Smckusick 	fhp = &nfh.fh_generic;
34338418Smckusick 	nfsm_srvmtofh(fhp);
34468653Smckusick 	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;
34868653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
34968653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
35068653Smckusick 	if (dirp) {
35168653Smckusick 		if (v3)
35268653Smckusick 			dirattr_ret = VOP_GETATTR(dirp, &dirattr, cred,
35368653Smckusick 				procp);
35468653Smckusick 		vrele(dirp);
35568653Smckusick 	}
35668653Smckusick 	if (error) {
35768653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3));
35868653Smckusick 		nfsm_srvpostop_attr(dirattr_ret, &dirattr);
35968653Smckusick 		return (0);
36068653Smckusick 	}
36168653Smckusick 	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;
36768653Smckusick 	error = VFS_VPTOFH(vp, &fhp->fh_fid);
36868653Smckusick 	if (!error)
36968653Smckusick 		error = VOP_GETATTR(vp, vap, cred, procp);
37038418Smckusick 	vput(vp);
37168653Smckusick 	nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPORFATTR(v3) + NFSX_POSTOPATTR(v3));
37268653Smckusick 	if (error) {
37368653Smckusick 		nfsm_srvpostop_attr(dirattr_ret, &dirattr);
37468653Smckusick 		return (0);
37552196Smckusick 	}
37668653Smckusick 	nfsm_srvfhtom(fhp, v3);
37768653Smckusick 	if (v3) {
37868653Smckusick 		nfsm_srvpostop_attr(0, vap);
37968653Smckusick 		nfsm_srvpostop_attr(dirattr_ret, &dirattr);
38068653Smckusick 	} else {
38168653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
38268653Smckusick 		nfsm_srvfillattr(vap, fp);
38368653Smckusick 	}
38438418Smckusick 	nfsm_srvdone;
38538418Smckusick }
38638418Smckusick 
38738418Smckusick /*
38838418Smckusick  * nfs readlink service
38938418Smckusick  */
39068653Smckusick int
nfsrv_readlink(nfsd,slp,procp,mrq)39168653Smckusick nfsrv_readlink(nfsd, slp, procp, mrq)
39268653Smckusick 	struct nfsrv_descript *nfsd;
39368653Smckusick 	struct nfssvc_sock *slp;
39468653Smckusick 	struct proc *procp;
39568653Smckusick 	struct mbuf **mrq;
39638418Smckusick {
39768653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
39868653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
39968653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
40068653Smckusick 	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;
40768653Smckusick 	int error = 0, rdonly, cache, i, tlen, len, getret;
40868653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
40939494Smckusick 	char *cp2;
41039753Smckusick 	struct mbuf *mb, *mb2, *mp2, *mp3, *mreq;
41138418Smckusick 	struct vnode *vp;
41268653Smckusick 	struct vattr attr;
41368653Smckusick 	nfsfh_t nfh;
41438418Smckusick 	fhandle_t *fhp;
41538418Smckusick 	struct uio io, *uiop = &io;
41652196Smckusick 	u_quad_t frev;
41738418Smckusick 
41868653Smckusick #ifndef nolint
41968653Smckusick 	mp2 = mp3 = (struct mbuf *)0;
42068653Smckusick #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;
45268653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
45368653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
45438418Smckusick 		m_freem(mp3);
45568653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
45668653Smckusick 		nfsm_srvpostop_attr(1, (struct vattr *)0);
45768653Smckusick 		return (0);
45838418Smckusick 	}
45938418Smckusick 	if (vp->v_type != VLNK) {
46068653Smckusick 		if (v3)
46168653Smckusick 			error = EINVAL;
46268653Smckusick 		else
46368653Smckusick 			error = ENXIO;
46438418Smckusick 		goto out;
46538418Smckusick 	}
46668653Smckusick 	nqsrv_getl(vp, ND_READ);
46738418Smckusick 	error = VOP_READLINK(vp, uiop, cred);
46838418Smckusick out:
46968653Smckusick 	getret = VOP_GETATTR(vp, &attr, cred, procp);
47038418Smckusick 	vput(vp);
47138418Smckusick 	if (error)
47238418Smckusick 		m_freem(mp3);
47368653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_UNSIGNED);
47468653Smckusick 	if (v3) {
47568653Smckusick 		nfsm_srvpostop_attr(getret, &attr);
47668653Smckusick 		if (error)
47768653Smckusick 			return (0);
47868653Smckusick 	}
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  */
49368653Smckusick int
nfsrv_read(nfsd,slp,procp,mrq)49468653Smckusick nfsrv_read(nfsd, slp, procp, mrq)
49568653Smckusick 	struct nfsrv_descript *nfsd;
49668653Smckusick 	struct nfssvc_sock *slp;
49768653Smckusick 	struct proc *procp;
49868653Smckusick 	struct mbuf **mrq;
49938418Smckusick {
50068653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
50168653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
50268653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
50368653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
50443350Smckusick 	register struct iovec *iv;
50543350Smckusick 	struct iovec *iv2;
50641899Smckusick 	register struct mbuf *m;
50768653Smckusick 	register struct nfs_fattr *fp;
50848050Smckusick 	register u_long *tl;
50939494Smckusick 	register long t1;
51068653Smckusick 	register int i;
51139494Smckusick 	caddr_t bpos;
51268653Smckusick 	int error = 0, rdonly, cache, cnt, len, left, siz, tlen, getret;
51368653Smckusick 	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;
51868653Smckusick 	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);
52768653Smckusick 	if (v3) {
52868653Smckusick 		nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
52968653Smckusick 		fxdr_hyper(tl, &off);
53068653Smckusick 	} else {
53156285Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
53256285Smckusick 		off = (off_t)fxdr_unsigned(u_long, *tl);
53356285Smckusick 	}
53468653Smckusick 	nfsm_srvstrsiz(reqlen, NFS_SRVMAXDATA(nfsd));
53568653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
53668653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
53768653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
53868653Smckusick 		nfsm_srvpostop_attr(1, (struct vattr *)0);
53968653Smckusick 		return (0);
54068653Smckusick 	}
54160186Smckusick 	if (vp->v_type != VREG) {
54268653Smckusick 		if (v3)
54368653Smckusick 			error = EINVAL;
54468653Smckusick 		else
54568653Smckusick 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
54660186Smckusick 	}
54768653Smckusick 	if (!error) {
54868653Smckusick 	    nqsrv_getl(vp, ND_READ);
54968653Smckusick 	    if (error = nfsrv_access(vp, VREAD, cred, rdonly, procp))
55068653Smckusick 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
55138418Smckusick 	}
55268653Smckusick 	getret = VOP_GETATTR(vp, vap, cred, procp);
55368653Smckusick 	if (!error)
55468653Smckusick 		error = getret;
55568653Smckusick 	if (error) {
55638418Smckusick 		vput(vp);
55768653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3));
55868653Smckusick 		nfsm_srvpostop_attr(getret, vap);
55968653Smckusick 		return (0);
56038418Smckusick 	}
56152196Smckusick 	if (off >= vap->va_size)
56252196Smckusick 		cnt = 0;
56368653Smckusick 	else if ((off + reqlen) > vap->va_size)
56452196Smckusick 		cnt = nfsm_rndup(vap->va_size - off);
56568653Smckusick 	else
56668653Smckusick 		cnt = reqlen;
56768653Smckusick 	nfsm_reply(NFSX_POSTOPORFATTR(v3) + 3 * NFSX_UNSIGNED+nfsm_rndup(cnt));
56868653Smckusick 	if (v3) {
56968653Smckusick 		nfsm_build(tl, u_long *, NFSX_V3FATTR + 4 * NFSX_UNSIGNED);
57068653Smckusick 		*tl++ = nfs_true;
57168653Smckusick 		fp = (struct nfs_fattr *)tl;
57268653Smckusick 		tl += (NFSX_V3FATTR / sizeof (u_long));
57368653Smckusick 	} else {
57468653Smckusick 		nfsm_build(tl, u_long *, NFSX_V2FATTR + NFSX_UNSIGNED);
57568653Smckusick 		fp = (struct nfs_fattr *)tl;
57668653Smckusick 		tl += (NFSX_V2FATTR / sizeof (u_long));
57768653Smckusick 	}
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) {
58868653Smckusick 				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 		}
59968653Smckusick 		MALLOC(iv, struct iovec *, i * sizeof (struct iovec),
60068653Smckusick 		       M_TEMP, M_WAITOK);
60168653Smckusick 		uiop->uio_iov = iv2 = iv;
60268653Smckusick 		m = mb;
60368653Smckusick 		left = cnt;
60468653Smckusick 		i = 0;
60568653Smckusick 		while (left > 0) {
60668653Smckusick 			if (m == NULL)
60768653Smckusick 				panic("nfsrv_read iov");
60868653Smckusick 			siz = min(M_TRAILINGSPACE(m), left);
60968653Smckusick 			if (siz > 0) {
61068653Smckusick 				iv->iov_base = mtod(m, caddr_t) + m->m_len;
61168653Smckusick 				iv->iov_len = siz;
61268653Smckusick 				m->m_len += siz;
61368653Smckusick 				left -= siz;
61468653Smckusick 				iv++;
61568653Smckusick 				i++;
61668653Smckusick 			}
61768653Smckusick 			m = m->m_next;
61868653Smckusick 		}
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);
62768653Smckusick 		if (error || (getret = VOP_GETATTR(vp, vap, cred, procp))) {
62868653Smckusick 			if (!error)
62968653Smckusick 				error = getret;
63052196Smckusick 			m_freem(mreq);
63152196Smckusick 			vput(vp);
63268653Smckusick 			nfsm_reply(NFSX_POSTOPATTR(v3));
63368653Smckusick 			nfsm_srvpostop_attr(getret, vap);
63468653Smckusick 			return (0);
63552196Smckusick 		}
63652196Smckusick 	} else
63752196Smckusick 		uiop->uio_resid = 0;
63838418Smckusick 	vput(vp);
63968653Smckusick 	nfsm_srvfillattr(vap, fp);
64045877Smckusick 	len -= uiop->uio_resid;
64152196Smckusick 	tlen = nfsm_rndup(len);
64252196Smckusick 	if (cnt != tlen || tlen != len)
64368653Smckusick 		nfsm_adj(mb, cnt - tlen, tlen - len);
64468653Smckusick 	if (v3) {
64568653Smckusick 		*tl++ = txdr_unsigned(len);
64668653Smckusick 		if (len < reqlen)
64768653Smckusick 			*tl++ = nfs_true;
64868653Smckusick 		else
64968653Smckusick 			*tl++ = nfs_false;
65068653Smckusick 	}
65148050Smckusick 	*tl = txdr_unsigned(len);
65238418Smckusick 	nfsm_srvdone;
65338418Smckusick }
65438418Smckusick 
65538418Smckusick /*
65638418Smckusick  * nfs write service
65738418Smckusick  */
65868653Smckusick int
nfsrv_write(nfsd,slp,procp,mrq)65968653Smckusick nfsrv_write(nfsd, slp, procp, mrq)
66068653Smckusick 	struct nfsrv_descript *nfsd;
66168653Smckusick 	struct nfssvc_sock *slp;
66268653Smckusick 	struct proc *procp;
66368653Smckusick 	struct mbuf **mrq;
66438418Smckusick {
66568653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
66668653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
66768653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
66868653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
66938418Smckusick 	register struct iovec *ivp;
67068653Smckusick 	register int i, cnt;
67138418Smckusick 	register struct mbuf *mp;
67268653Smckusick 	register struct nfs_fattr *fp;
67368653Smckusick 	struct iovec *iv;
67468653Smckusick 	struct vattr va, forat;
67538418Smckusick 	register struct vattr *vap = &va;
67648050Smckusick 	register u_long *tl;
67739494Smckusick 	register long t1;
67839494Smckusick 	caddr_t bpos;
67968653Smckusick 	int error = 0, rdonly, cache, siz, len, xfer, forat_ret = 1;
68068653Smckusick 	int ioflags, aftat_ret = 1, retlen, zeroing, adjust;
68168653Smckusick 	int stable = NFSV3WRITE_FILESYNC;
68268653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
68339494Smckusick 	char *cp2;
68439753Smckusick 	struct mbuf *mb, *mb2, *mreq;
68538418Smckusick 	struct vnode *vp;
68668653Smckusick 	nfsfh_t nfh;
68738418Smckusick 	fhandle_t *fhp;
68838418Smckusick 	struct uio io, *uiop = &io;
68938418Smckusick 	off_t off;
69052196Smckusick 	u_quad_t frev;
69138418Smckusick 
69268653Smckusick 	if (mrep == NULL) {
69368653Smckusick 		*mrq = NULL;
69468653Smckusick 		return (0);
69568653Smckusick 	}
69638418Smckusick 	fhp = &nfh.fh_generic;
69738418Smckusick 	nfsm_srvmtofh(fhp);
69868653Smckusick 	if (v3) {
69968653Smckusick 		nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
70068653Smckusick 		fxdr_hyper(tl, &off);
70168653Smckusick 		tl += 3;
70268653Smckusick 		stable = fxdr_unsigned(int, *tl++);
70368653Smckusick 	} else {
70468653Smckusick 		nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
70556285Smckusick 		off = (off_t)fxdr_unsigned(u_long, *++tl);
70656285Smckusick 		tl += 2;
70756285Smckusick 	}
70868653Smckusick 	retlen = len = fxdr_unsigned(long, *tl);
70968653Smckusick 	cnt = i = 0;
71068653Smckusick 
71168653Smckusick 	/*
71268653Smckusick 	 * For NFS Version 2, it is not obvious what a write of zero length
71368653Smckusick 	 * should do, but I might as well be consistent with Version 3,
71468653Smckusick 	 * which is to return ok so long as there are no permission problems.
71568653Smckusick 	 */
71668653Smckusick 	if (len > 0) {
71768653Smckusick 	    zeroing = 1;
71868653Smckusick 	    mp = mrep;
71968653Smckusick 	    while (mp) {
72068653Smckusick 		if (mp == md) {
72168653Smckusick 			zeroing = 0;
72268653Smckusick 			adjust = dpos - mtod(mp, caddr_t);
72368653Smckusick 			mp->m_len -= adjust;
72468653Smckusick 			if (mp->m_len > 0 && adjust > 0)
72568653Smckusick 				NFSMADV(mp, adjust);
72638418Smckusick 		}
72768653Smckusick 		if (zeroing)
72868653Smckusick 			mp->m_len = 0;
72968653Smckusick 		else if (mp->m_len > 0) {
73068653Smckusick 			i += mp->m_len;
73168653Smckusick 			if (i > len) {
73268653Smckusick 				mp->m_len -= (i - len);
73368653Smckusick 				zeroing	= 1;
73468653Smckusick 			}
73568653Smckusick 			if (mp->m_len > 0)
73668653Smckusick 				cnt++;
73768653Smckusick 		}
73868653Smckusick 		mp = mp->m_next;
73968653Smckusick 	    }
74038418Smckusick 	}
74168653Smckusick 	if (len > NFS_MAXDATA || len < 0 || i < len) {
74268653Smckusick 		error = EIO;
74368653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
74468653Smckusick 		nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
74568653Smckusick 		return (0);
74668653Smckusick 	}
74768653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
74868653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
74968653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
75068653Smckusick 		nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
75168653Smckusick 		return (0);
75268653Smckusick 	}
75368653Smckusick 	if (v3)
75468653Smckusick 		forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
75560186Smckusick 	if (vp->v_type != VREG) {
75668653Smckusick 		if (v3)
75768653Smckusick 			error = EINVAL;
75868653Smckusick 		else
75968653Smckusick 			error = (vp->v_type == VDIR) ? EISDIR : EACCES;
76060186Smckusick 	}
76168653Smckusick 	if (!error) {
76268653Smckusick 		nqsrv_getl(vp, ND_WRITE);
76368653Smckusick 		error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
76468653Smckusick 	}
76568653Smckusick 	if (error) {
76638418Smckusick 		vput(vp);
76768653Smckusick 		nfsm_reply(NFSX_WCCDATA(v3));
76868653Smckusick 		nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
76968653Smckusick 		return (0);
77038418Smckusick 	}
77168653Smckusick 
77268653Smckusick 	if (len > 0) {
77368653Smckusick 	    MALLOC(ivp, struct iovec *, cnt * sizeof (struct iovec), M_TEMP,
77468653Smckusick 		M_WAITOK);
77568653Smckusick 	    uiop->uio_iov = iv = ivp;
77668653Smckusick 	    uiop->uio_iovcnt = cnt;
77768653Smckusick 	    mp = mrep;
77868653Smckusick 	    while (mp) {
77968653Smckusick 		if (mp->m_len > 0) {
78068653Smckusick 			ivp->iov_base = mtod(mp, caddr_t);
78168653Smckusick 			ivp->iov_len = mp->m_len;
78268653Smckusick 			ivp++;
78368653Smckusick 		}
78468653Smckusick 		mp = mp->m_next;
78568653Smckusick 	    }
78668653Smckusick 
78768653Smckusick 	    /*
78868653Smckusick 	     * XXX
78968653Smckusick 	     * The IO_METASYNC flag indicates that all metadata (and not just
79068653Smckusick 	     * enough to ensure data integrity) mus be written to stable storage
79168653Smckusick 	     * synchronously.
79268653Smckusick 	     * (IO_METASYNC is not yet implemented in 4.4BSD-Lite.)
79368653Smckusick 	     */
79468653Smckusick 	    if (stable == NFSV3WRITE_UNSTABLE)
79568653Smckusick 		ioflags = IO_NODELOCKED;
79668653Smckusick 	    else if (stable == NFSV3WRITE_DATASYNC)
79768653Smckusick 		ioflags = (IO_SYNC | IO_NODELOCKED);
79868653Smckusick 	    else
79968653Smckusick 		ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
80068653Smckusick 	    uiop->uio_resid = len;
80168653Smckusick 	    uiop->uio_rw = UIO_WRITE;
80268653Smckusick 	    uiop->uio_segflg = UIO_SYSSPACE;
80368653Smckusick 	    uiop->uio_procp = (struct proc *)0;
80468653Smckusick 	    uiop->uio_offset = off;
80568653Smckusick 	    error = VOP_WRITE(vp, uiop, ioflags, cred);
80668653Smckusick 	    nfsstats.srvvop_writes++;
80768653Smckusick 	    FREE((caddr_t)iv, M_TEMP);
80868653Smckusick 	}
80968653Smckusick 	aftat_ret = VOP_GETATTR(vp, vap, cred, procp);
81068653Smckusick 	vput(vp);
81168653Smckusick 	if (!error)
81268653Smckusick 		error = aftat_ret;
81368653Smckusick 	nfsm_reply(NFSX_PREOPATTR(v3) + NFSX_POSTOPORFATTR(v3) +
81468653Smckusick 		2 * NFSX_UNSIGNED + NFSX_WRITEVERF(v3));
81568653Smckusick 	if (v3) {
81668653Smckusick 		nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, vap);
81768653Smckusick 		if (error)
81868653Smckusick 			return (0);
81968653Smckusick 		nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
82068653Smckusick 		*tl++ = txdr_unsigned(retlen);
82168653Smckusick 		if (stable == NFSV3WRITE_UNSTABLE)
82268653Smckusick 			*tl++ = txdr_unsigned(stable);
82368653Smckusick 		else
82468653Smckusick 			*tl++ = txdr_unsigned(NFSV3WRITE_FILESYNC);
82568653Smckusick 		/*
82668653Smckusick 		 * Actually, there is no need to txdr these fields,
82768653Smckusick 		 * but it may make the values more human readable,
82868653Smckusick 		 * for debugging purposes.
82968653Smckusick 		 */
83068653Smckusick 		*tl++ = txdr_unsigned(boottime.tv_sec);
83168653Smckusick 		*tl = txdr_unsigned(boottime.tv_usec);
83268653Smckusick 	} else {
83368653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
83468653Smckusick 		nfsm_srvfillattr(vap, fp);
83568653Smckusick 	}
83668653Smckusick 	nfsm_srvdone;
83768653Smckusick }
83868653Smckusick 
83968653Smckusick /*
84068653Smckusick  * NFS write service with write gathering support. Called when
84168653Smckusick  * nfsrvw_procrastinate > 0.
84268653Smckusick  * See: Chet Juszczak, "Improving the Write Performance of an NFS Server",
84368653Smckusick  * in Proc. of the Winter 1994 Usenix Conference, pg. 247-259, San Franscisco,
84468653Smckusick  * Jan. 1994.
84568653Smckusick  */
84668653Smckusick int
nfsrv_writegather(ndp,slp,procp,mrq)84768653Smckusick nfsrv_writegather(ndp, slp, procp, mrq)
84868653Smckusick 	struct nfsrv_descript **ndp;
84968653Smckusick 	struct nfssvc_sock *slp;
85068653Smckusick 	struct proc *procp;
85168653Smckusick 	struct mbuf **mrq;
85268653Smckusick {
85368653Smckusick 	register struct iovec *ivp;
85468653Smckusick 	register struct mbuf *mp;
85568653Smckusick 	register struct nfsrv_descript *wp, *nfsd, *owp, *swp;
85668653Smckusick 	register struct nfs_fattr *fp;
85768653Smckusick 	register int i;
85868653Smckusick 	struct iovec *iov;
85968653Smckusick 	struct nfsrvw_delayhash *wpp;
86068653Smckusick 	struct ucred *cred;
86168653Smckusick 	struct vattr va, forat;
86268653Smckusick 	register u_long *tl;
86368653Smckusick 	register long t1;
86468653Smckusick 	caddr_t bpos, dpos;
86568653Smckusick 	int error = 0, rdonly, cache, len, forat_ret = 1;
86668653Smckusick 	int ioflags, aftat_ret = 1, s, adjust, v3, zeroing;
86768653Smckusick 	char *cp2;
86868653Smckusick 	struct mbuf *mb, *mb2, *mreq, *mrep, *md;
86968653Smckusick 	struct vnode *vp;
87068653Smckusick 	struct uio io, *uiop = &io;
87168653Smckusick 	off_t off;
87268653Smckusick 	u_quad_t frev, cur_usec;
87368653Smckusick 
87468653Smckusick #ifndef nolint
87568653Smckusick 	i = 0;
87668653Smckusick 	len = 0;
87768653Smckusick #endif
87868653Smckusick 	*mrq = NULL;
87968653Smckusick 	if (*ndp) {
88068653Smckusick 	    nfsd = *ndp;
88168653Smckusick 	    *ndp = NULL;
88268653Smckusick 	    mrep = nfsd->nd_mrep;
88368653Smckusick 	    md = nfsd->nd_md;
88468653Smckusick 	    dpos = nfsd->nd_dpos;
88568653Smckusick 	    cred = &nfsd->nd_cr;
88668653Smckusick 	    v3 = (nfsd->nd_flag & ND_NFSV3);
88768653Smckusick 	    LIST_INIT(&nfsd->nd_coalesce);
88868653Smckusick 	    nfsd->nd_mreq = NULL;
88968653Smckusick 	    nfsd->nd_stable = NFSV3WRITE_FILESYNC;
89068653Smckusick 	    cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
89168653Smckusick 	    nfsd->nd_time = cur_usec + nfsrvw_procrastinate;
89268653Smckusick 
89368653Smckusick 	    /*
89468653Smckusick 	     * Now, get the write header..
89568653Smckusick 	     */
89668653Smckusick 	    nfsm_srvmtofh(&nfsd->nd_fh);
89768653Smckusick 	    if (v3) {
89868653Smckusick 		nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
89968653Smckusick 		fxdr_hyper(tl, &nfsd->nd_off);
90068653Smckusick 		tl += 3;
90168653Smckusick 		nfsd->nd_stable = fxdr_unsigned(int, *tl++);
90268653Smckusick 	    } else {
90368653Smckusick 		nfsm_dissect(tl, u_long *, 4 * NFSX_UNSIGNED);
90468653Smckusick 		nfsd->nd_off = (off_t)fxdr_unsigned(u_long, *++tl);
90568653Smckusick 		tl += 2;
90668653Smckusick 	    }
90768653Smckusick 	    len = fxdr_unsigned(long, *tl);
90868653Smckusick 	    nfsd->nd_len = len;
90968653Smckusick 	    nfsd->nd_eoff = nfsd->nd_off + len;
91068653Smckusick 
91168653Smckusick 	    /*
91268653Smckusick 	     * Trim the header out of the mbuf list and trim off any trailing
91368653Smckusick 	     * junk so that the mbuf list has only the write data.
91468653Smckusick 	     */
91568653Smckusick 	    zeroing = 1;
91668653Smckusick 	    i = 0;
91768653Smckusick 	    mp = mrep;
91868653Smckusick 	    while (mp) {
91968653Smckusick 		if (mp == md) {
92068653Smckusick 		    zeroing = 0;
92168653Smckusick 		    adjust = dpos - mtod(mp, caddr_t);
92268653Smckusick 		    mp->m_len -= adjust;
92368653Smckusick 		    if (mp->m_len > 0 && adjust > 0)
92468653Smckusick 			NFSMADV(mp, adjust);
92568653Smckusick 		}
92668653Smckusick 		if (zeroing)
92768653Smckusick 		    mp->m_len = 0;
92868653Smckusick 		else {
92968653Smckusick 		    i += mp->m_len;
93068653Smckusick 		    if (i > len) {
93168653Smckusick 			mp->m_len -= (i - len);
93268653Smckusick 			zeroing = 1;
93368653Smckusick 		    }
93468653Smckusick 		}
93568653Smckusick 		mp = mp->m_next;
93668653Smckusick 	    }
93768653Smckusick 	    if (len > NFS_MAXDATA || len < 0  || i < len) {
93868653Smckusick nfsmout:
93968653Smckusick 		m_freem(mrep);
94068653Smckusick 		error = EIO;
94168653Smckusick 		nfsm_writereply(2 * NFSX_UNSIGNED, v3);
94268653Smckusick 		if (v3)
94368653Smckusick 		    nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
94468653Smckusick 		nfsd->nd_mreq = mreq;
94568653Smckusick 		nfsd->nd_mrep = NULL;
94668653Smckusick 		nfsd->nd_time = 0;
94768653Smckusick 	    }
94868653Smckusick 
94968653Smckusick 	    /*
95068653Smckusick 	     * Add this entry to the hash and time queues.
95168653Smckusick 	     */
95268653Smckusick 	    s = splsoftclock();
95368653Smckusick 	    owp = NULL;
95468653Smckusick 	    wp = slp->ns_tq.lh_first;
95568653Smckusick 	    while (wp && wp->nd_time < nfsd->nd_time) {
95668653Smckusick 		owp = wp;
95768653Smckusick 		wp = wp->nd_tq.le_next;
95868653Smckusick 	    }
95968653Smckusick 	    if (owp) {
96068653Smckusick 		LIST_INSERT_AFTER(owp, nfsd, nd_tq);
96168653Smckusick 	    } else {
96268653Smckusick 		LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
96368653Smckusick 	    }
96468653Smckusick 	    if (nfsd->nd_mrep) {
96568653Smckusick 		wpp = NWDELAYHASH(slp, nfsd->nd_fh.fh_fid.fid_data);
96668653Smckusick 		owp = NULL;
96768653Smckusick 		wp = wpp->lh_first;
96868653Smckusick 		while (wp &&
96968653Smckusick 		    bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
97068653Smckusick 		    owp = wp;
97168653Smckusick 		    wp = wp->nd_hash.le_next;
97268653Smckusick 		}
97368653Smckusick 		while (wp && wp->nd_off < nfsd->nd_off &&
97468653Smckusick 		    !bcmp((caddr_t)&nfsd->nd_fh,(caddr_t)&wp->nd_fh,NFSX_V3FH)) {
97568653Smckusick 		    owp = wp;
97668653Smckusick 		    wp = wp->nd_hash.le_next;
97768653Smckusick 		}
97868653Smckusick 		if (owp) {
97968653Smckusick 		    LIST_INSERT_AFTER(owp, nfsd, nd_hash);
98068653Smckusick 
98168653Smckusick 		    /*
98268653Smckusick 		     * Search the hash list for overlapping entries and
98368653Smckusick 		     * coalesce.
98468653Smckusick 		     */
98568653Smckusick 		    for(; nfsd && NFSW_CONTIG(owp, nfsd); nfsd = wp) {
98668653Smckusick 			wp = nfsd->nd_hash.le_next;
98768653Smckusick 			if (NFSW_SAMECRED(owp, nfsd))
98868653Smckusick 			    nfsrvw_coalesce(owp, nfsd);
98968653Smckusick 		    }
99068653Smckusick 		} else {
99168653Smckusick 		    LIST_INSERT_HEAD(wpp, nfsd, nd_hash);
99268653Smckusick 		}
99368653Smckusick 	    }
99468653Smckusick 	    splx(s);
99568653Smckusick 	}
99668653Smckusick 
99738418Smckusick 	/*
99868653Smckusick 	 * Now, do VOP_WRITE()s for any one(s) that need to be done now
99968653Smckusick 	 * and generate the associated reply mbuf list(s).
100038418Smckusick 	 */
100168653Smckusick loop1:
100268653Smckusick 	cur_usec = (u_quad_t)time.tv_sec * 1000000 + (u_quad_t)time.tv_usec;
100368653Smckusick 	s = splsoftclock();
100468653Smckusick 	for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = owp) {
100568653Smckusick 		owp = nfsd->nd_tq.le_next;
100668653Smckusick 		if (nfsd->nd_time > cur_usec)
100768653Smckusick 		    break;
100868653Smckusick 		if (nfsd->nd_mreq)
100968653Smckusick 		    continue;
101068653Smckusick 		LIST_REMOVE(nfsd, nd_tq);
101168653Smckusick 		LIST_REMOVE(nfsd, nd_hash);
101268653Smckusick 		splx(s);
101368653Smckusick 		mrep = nfsd->nd_mrep;
101468653Smckusick 		nfsd->nd_mrep = NULL;
101568653Smckusick 		cred = &nfsd->nd_cr;
101668653Smckusick 		v3 = (nfsd->nd_flag & ND_NFSV3);
101768653Smckusick 		forat_ret = aftat_ret = 1;
101868653Smckusick 		error = nfsrv_fhtovp(&nfsd->nd_fh, 1, &vp, cred, slp,
101968653Smckusick 		    nfsd->nd_nam, &rdonly, (nfsd->nd_flag & ND_KERBAUTH));
102068653Smckusick 		if (!error) {
102168653Smckusick 		    if (v3)
102268653Smckusick 			forat_ret = VOP_GETATTR(vp, &forat, cred, procp);
102368653Smckusick 		    if (vp->v_type != VREG) {
102468653Smckusick 			if (v3)
102568653Smckusick 			    error = EINVAL;
102638418Smckusick 			else
102768653Smckusick 			    error = (vp->v_type == VDIR) ? EISDIR : EACCES;
102868653Smckusick 		    }
102968653Smckusick 		} else
103068653Smckusick 		    vp = NULL;
103168653Smckusick 		if (!error) {
103268653Smckusick 		    nqsrv_getl(vp, ND_WRITE);
103368653Smckusick 		    error = nfsrv_access(vp, VWRITE, cred, rdonly, procp);
103468653Smckusick 		}
103568653Smckusick 
103668653Smckusick 		if (nfsd->nd_stable == NFSV3WRITE_UNSTABLE)
103768653Smckusick 		    ioflags = IO_NODELOCKED;
103868653Smckusick 		else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC)
103968653Smckusick 		    ioflags = (IO_SYNC | IO_NODELOCKED);
104068653Smckusick 		else
104168653Smckusick 		    ioflags = (IO_METASYNC | IO_SYNC | IO_NODELOCKED);
104268653Smckusick 		uiop->uio_rw = UIO_WRITE;
104368653Smckusick 		uiop->uio_segflg = UIO_SYSSPACE;
104468653Smckusick 		uiop->uio_procp = (struct proc *)0;
104568653Smckusick 		uiop->uio_offset = nfsd->nd_off;
104668653Smckusick 		uiop->uio_resid = nfsd->nd_eoff - nfsd->nd_off;
104768653Smckusick 		if (uiop->uio_resid > 0) {
104868653Smckusick 		    mp = mrep;
104968653Smckusick 		    i = 0;
105068653Smckusick 		    while (mp) {
105168653Smckusick 			if (mp->m_len > 0)
105268653Smckusick 			    i++;
105338418Smckusick 			mp = mp->m_next;
105468653Smckusick 		    }
105568653Smckusick 		    uiop->uio_iovcnt = i;
105668653Smckusick 		    MALLOC(iov, struct iovec *, i * sizeof (struct iovec),
105768653Smckusick 			M_TEMP, M_WAITOK);
105868653Smckusick 		    uiop->uio_iov = ivp = iov;
105968653Smckusick 		    mp = mrep;
106068653Smckusick 		    while (mp) {
106168653Smckusick 			if (mp->m_len > 0) {
106268653Smckusick 			    ivp->iov_base = mtod(mp, caddr_t);
106368653Smckusick 			    ivp->iov_len = mp->m_len;
106468653Smckusick 			    ivp++;
106568653Smckusick 			}
106668653Smckusick 			mp = mp->m_next;
106768653Smckusick 		    }
106868653Smckusick 		    if (!error) {
106968653Smckusick 			error = VOP_WRITE(vp, uiop, ioflags, cred);
107068653Smckusick 			nfsstats.srvvop_writes++;
107168653Smckusick 		    }
107268653Smckusick 		    FREE((caddr_t)iov, M_TEMP);
107338418Smckusick 		}
107468653Smckusick 		m_freem(mrep);
107568653Smckusick 		if (vp) {
107668653Smckusick 		    aftat_ret = VOP_GETATTR(vp, &va, cred, procp);
107768653Smckusick 		    vput(vp);
107838418Smckusick 		}
107968653Smckusick 
108068653Smckusick 		/*
108168653Smckusick 		 * Loop around generating replies for all write rpcs that have
108268653Smckusick 		 * now been completed.
108368653Smckusick 		 */
108468653Smckusick 		swp = nfsd;
108568653Smckusick 		do {
108668653Smckusick 		    if (error) {
108768653Smckusick 			nfsm_writereply(NFSX_WCCDATA(v3), v3);
108868653Smckusick 			if (v3) {
108968653Smckusick 			    nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
109068653Smckusick 			}
109168653Smckusick 		    } else {
109268653Smckusick 			nfsm_writereply(NFSX_PREOPATTR(v3) +
109368653Smckusick 			    NFSX_POSTOPORFATTR(v3) + 2 * NFSX_UNSIGNED +
109468653Smckusick 			    NFSX_WRITEVERF(v3), v3);
109568653Smckusick 			if (v3) {
109668653Smckusick 			    nfsm_srvwcc_data(forat_ret, &forat, aftat_ret, &va);
109768653Smckusick 			    nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
109868653Smckusick 			    *tl++ = txdr_unsigned(nfsd->nd_len);
109968653Smckusick 			    *tl++ = txdr_unsigned(swp->nd_stable);
110068653Smckusick 			    /*
110168653Smckusick 			     * Actually, there is no need to txdr these fields,
110268653Smckusick 			     * but it may make the values more human readable,
110368653Smckusick 			     * for debugging purposes.
110468653Smckusick 			     */
110568653Smckusick 			    *tl++ = txdr_unsigned(boottime.tv_sec);
110668653Smckusick 			    *tl = txdr_unsigned(boottime.tv_usec);
110768653Smckusick 			} else {
110868653Smckusick 			    nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
110968653Smckusick 			    nfsm_srvfillattr(&va, fp);
111068653Smckusick 			}
111168653Smckusick 		    }
111268653Smckusick 		    nfsd->nd_mreq = mreq;
111368653Smckusick 		    if (nfsd->nd_mrep)
111468653Smckusick 			panic("nfsrv_write: nd_mrep not free");
111568653Smckusick 
111668653Smckusick 		    /*
111768653Smckusick 		     * Done. Put it at the head of the timer queue so that
111868653Smckusick 		     * the final phase can return the reply.
111968653Smckusick 		     */
112068653Smckusick 		    s = splsoftclock();
112168653Smckusick 		    if (nfsd != swp) {
112268653Smckusick 			nfsd->nd_time = 0;
112368653Smckusick 			LIST_INSERT_HEAD(&slp->ns_tq, nfsd, nd_tq);
112468653Smckusick 		    }
112568653Smckusick 		    nfsd = swp->nd_coalesce.lh_first;
112668653Smckusick 		    if (nfsd) {
112768653Smckusick 			LIST_REMOVE(nfsd, nd_tq);
112868653Smckusick 		    }
112968653Smckusick 		    splx(s);
113068653Smckusick 		} while (nfsd);
113168653Smckusick 		s = splsoftclock();
113268653Smckusick 		swp->nd_time = 0;
113368653Smckusick 		LIST_INSERT_HEAD(&slp->ns_tq, swp, nd_tq);
113468653Smckusick 		splx(s);
113568653Smckusick 		goto loop1;
113668653Smckusick 	}
113768653Smckusick 	splx(s);
113868653Smckusick 
113968653Smckusick 	/*
114068653Smckusick 	 * Search for a reply to return.
114168653Smckusick 	 */
114268653Smckusick 	s = splsoftclock();
114368653Smckusick 	for (nfsd = slp->ns_tq.lh_first; nfsd; nfsd = nfsd->nd_tq.le_next)
114468653Smckusick 		if (nfsd->nd_mreq) {
114568653Smckusick 		    LIST_REMOVE(nfsd, nd_tq);
114668653Smckusick 		    *mrq = nfsd->nd_mreq;
114768653Smckusick 		    *ndp = nfsd;
114868653Smckusick 		    break;
114938418Smckusick 		}
115068653Smckusick 	splx(s);
115168653Smckusick 	return (0);
115268653Smckusick }
115368653Smckusick 
115468653Smckusick /*
115568653Smckusick  * Coalesce the write request nfsd into owp. To do this we must:
115668653Smckusick  * - remove nfsd from the queues
115768653Smckusick  * - merge nfsd->nd_mrep into owp->nd_mrep
115868653Smckusick  * - update the nd_eoff and nd_stable for owp
115968653Smckusick  * - put nfsd on owp's nd_coalesce list
116068653Smckusick  * NB: Must be called at splsoftclock().
116168653Smckusick  */
116268653Smckusick void
nfsrvw_coalesce(owp,nfsd)116368653Smckusick nfsrvw_coalesce(owp, nfsd)
116468653Smckusick         register struct nfsrv_descript *owp;
116568653Smckusick         register struct nfsrv_descript *nfsd;
116668653Smckusick {
116768653Smckusick         register int overlap;
116868653Smckusick         register struct mbuf *mp;
116968653Smckusick 
117068653Smckusick         LIST_REMOVE(nfsd, nd_hash);
117168653Smckusick         LIST_REMOVE(nfsd, nd_tq);
117268653Smckusick         if (owp->nd_eoff < nfsd->nd_eoff) {
117368653Smckusick             overlap = owp->nd_eoff - nfsd->nd_off;
117468653Smckusick             if (overlap < 0)
117568653Smckusick                 panic("nfsrv_coalesce: bad off");
117668653Smckusick             if (overlap > 0)
117768653Smckusick                 m_adj(nfsd->nd_mrep, overlap);
117868653Smckusick             mp = owp->nd_mrep;
117968653Smckusick             while (mp->m_next)
118068653Smckusick                 mp = mp->m_next;
118168653Smckusick             mp->m_next = nfsd->nd_mrep;
118268653Smckusick             owp->nd_eoff = nfsd->nd_eoff;
118368653Smckusick         } else
118468653Smckusick             m_freem(nfsd->nd_mrep);
118568653Smckusick         nfsd->nd_mrep = NULL;
118668653Smckusick         if (nfsd->nd_stable == NFSV3WRITE_FILESYNC)
118768653Smckusick             owp->nd_stable = NFSV3WRITE_FILESYNC;
118868653Smckusick         else if (nfsd->nd_stable == NFSV3WRITE_DATASYNC &&
118968653Smckusick             owp->nd_stable == NFSV3WRITE_UNSTABLE)
119068653Smckusick             owp->nd_stable = NFSV3WRITE_DATASYNC;
119168653Smckusick         LIST_INSERT_HEAD(&owp->nd_coalesce, nfsd, nd_tq);
119268653Smckusick }
119368653Smckusick 
119468653Smckusick /*
119568653Smckusick  * Sort the group list in increasing numerical order.
119668653Smckusick  * (Insertion sort by Chris Torek, who was grossed out by the bubble sort
119768653Smckusick  *  that used to be here.)
119868653Smckusick  */
119968653Smckusick void
nfsrvw_sort(list,num)120068653Smckusick nfsrvw_sort(list, num)
120168653Smckusick         register gid_t *list;
120268653Smckusick         register int num;
120368653Smckusick {
120468653Smckusick 	register int i, j;
120568653Smckusick 	gid_t v;
120668653Smckusick 
120768653Smckusick 	/* Insertion sort. */
120868653Smckusick 	for (i = 1; i < num; i++) {
120968653Smckusick 		v = list[i];
121068653Smckusick 		/* find correct slot for value v, moving others up */
121168653Smckusick 		for (j = i; --j >= 0 && v < list[j];)
121268653Smckusick 			list[j + 1] = list[j];
121368653Smckusick 		list[j + 1] = v;
121438418Smckusick 	}
121538418Smckusick }
121638418Smckusick 
121738418Smckusick /*
121868653Smckusick  * copy credentials making sure that the result can be compared with bcmp().
121968653Smckusick  */
122068653Smckusick void
nfsrv_setcred(incred,outcred)122168653Smckusick nfsrv_setcred(incred, outcred)
122268653Smckusick 	register struct ucred *incred, *outcred;
122368653Smckusick {
122468653Smckusick 	register int i;
122568653Smckusick 
122668653Smckusick 	bzero((caddr_t)outcred, sizeof (struct ucred));
122768653Smckusick 	outcred->cr_ref = 1;
122868653Smckusick 	outcred->cr_uid = incred->cr_uid;
122968653Smckusick 	outcred->cr_ngroups = incred->cr_ngroups;
123068653Smckusick 	for (i = 0; i < incred->cr_ngroups; i++)
123168653Smckusick 		outcred->cr_groups[i] = incred->cr_groups[i];
123268653Smckusick 	nfsrvw_sort(outcred->cr_groups, outcred->cr_ngroups);
123368653Smckusick }
123468653Smckusick 
123568653Smckusick /*
123638418Smckusick  * nfs create service
123738418Smckusick  * now does a truncate to 0 length via. setattr if it already exists
123838418Smckusick  */
123968653Smckusick int
nfsrv_create(nfsd,slp,procp,mrq)124068653Smckusick nfsrv_create(nfsd, slp, procp, mrq)
124168653Smckusick 	struct nfsrv_descript *nfsd;
124268653Smckusick 	struct nfssvc_sock *slp;
124368653Smckusick 	struct proc *procp;
124468653Smckusick 	struct mbuf **mrq;
124538418Smckusick {
124668653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
124768653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
124868653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
124968653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
125068653Smckusick 	register struct nfs_fattr *fp;
125168653Smckusick 	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;
125968653Smckusick 	int error = 0, rdev, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
126068653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3), how, exclusive_flag = 0;
126139494Smckusick 	char *cp2;
126239753Smckusick 	struct mbuf *mb, *mb2, *mreq;
126368653Smckusick 	struct vnode *vp, *dirp = (struct vnode *)0;
126468653Smckusick 	nfsfh_t nfh;
126538418Smckusick 	fhandle_t *fhp;
126668653Smckusick 	u_quad_t frev, tempsize;
126768653Smckusick 	u_char cverf[NFSX_V3CREATEVERF];
126838418Smckusick 
126968653Smckusick #ifndef nolint
127068653Smckusick 	rdev = 0;
127168653Smckusick #endif
127252316Sheideman 	nd.ni_cnd.cn_nameiop = 0;
127338418Smckusick 	fhp = &nfh.fh_generic;
127438418Smckusick 	nfsm_srvmtofh(fhp);
127568653Smckusick 	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;
127968653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
128068653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
128168653Smckusick 	if (dirp) {
128268653Smckusick 		if (v3)
128368653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
128468653Smckusick 				procp);
128568653Smckusick 		else {
128668653Smckusick 			vrele(dirp);
128768653Smckusick 			dirp = (struct vnode *)0;
128868653Smckusick 		}
128968653Smckusick 	}
129068653Smckusick 	if (error) {
129168653Smckusick 		nfsm_reply(NFSX_WCCDATA(v3));
129268653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
129368653Smckusick 		if (dirp)
129468653Smckusick 			vrele(dirp);
129568653Smckusick 		return (0);
129668653Smckusick 	}
129741361Smckusick 	VATTR_NULL(vap);
129868653Smckusick 	if (v3) {
129968653Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
130068653Smckusick 		how = fxdr_unsigned(int, *tl);
130168653Smckusick 		switch (how) {
130268653Smckusick 		case NFSV3CREATE_GUARDED:
130368653Smckusick 			if (nd.ni_vp) {
130468653Smckusick 				error = EEXIST;
130568653Smckusick 				break;
130668653Smckusick 			}
130768653Smckusick 		case NFSV3CREATE_UNCHECKED:
130868653Smckusick 			nfsm_srvsattr(vap);
130968653Smckusick 			break;
131068653Smckusick 		case NFSV3CREATE_EXCLUSIVE:
131168653Smckusick 			nfsm_dissect(cp, caddr_t, NFSX_V3CREATEVERF);
131268653Smckusick 			bcopy(cp, cverf, NFSX_V3CREATEVERF);
131368653Smckusick 			exclusive_flag = 1;
131468653Smckusick 			if (nd.ni_vp == NULL)
131568653Smckusick 				vap->va_mode = 0;
131668653Smckusick 			break;
131768653Smckusick 		};
131868653Smckusick 		vap->va_type = VREG;
131968653Smckusick 	} else {
132068653Smckusick 		nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
132168653Smckusick 		vap->va_type = IFTOVT(fxdr_unsigned(u_long, sp->sa_mode));
132268653Smckusick 		if (vap->va_type == VNON)
132368653Smckusick 			vap->va_type = VREG;
132468653Smckusick 		vap->va_mode = nfstov_mode(sp->sa_mode);
132568653Smckusick 		switch (vap->va_type) {
132668653Smckusick 		case VREG:
132768653Smckusick 			tsize = fxdr_unsigned(long, sp->sa_size);
132868653Smckusick 			if (tsize != -1)
132968653Smckusick 				vap->va_size = (u_quad_t)tsize;
133068653Smckusick 			break;
133168653Smckusick 		case VCHR:
133268653Smckusick 		case VBLK:
133368653Smckusick 		case VFIFO:
133468653Smckusick 			rdev = fxdr_unsigned(long, sp->sa_size);
133568653Smckusick 			break;
133668653Smckusick 		};
133768653Smckusick 	}
133868653Smckusick 
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);
134768653Smckusick 			nqsrv_getl(nd.ni_dvp, ND_WRITE);
134868653Smckusick 			error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
134968653Smckusick 			if (!error) {
135068653Smckusick 				FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
135168653Smckusick 				if (exclusive_flag) {
135268653Smckusick 					exclusive_flag = 0;
135368653Smckusick 					VATTR_NULL(vap);
135468653Smckusick 					bcopy(cverf, (caddr_t)&vap->va_atime,
135568653Smckusick 						NFSX_V3CREATEVERF);
135668653Smckusick 					error = VOP_SETATTR(nd.ni_vp, vap, cred,
135768653Smckusick 						procp);
135868653Smckusick 				}
135968653Smckusick 			}
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;
136468653Smckusick 			if (error = suser(cred, (u_short *)0)) {
136568653Smckusick 				vrele(nd.ni_startdir);
136668653Smckusick 				free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
136752234Sheideman 				VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
136849742Smckusick 				vput(nd.ni_dvp);
136968653Smckusick 				nfsm_reply(0);
137068653Smckusick 				return (error);
137142242Smckusick 			} else
137242242Smckusick 				vap->va_rdev = (dev_t)rdev;
137368653Smckusick 			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);
138068653Smckusick 			nd.ni_cnd.cn_proc = procp;
138168653Smckusick 			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 {
139568653Smckusick 			vrele(nd.ni_startdir);
139668653Smckusick 			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) {
141268653Smckusick 			error = nfsrv_access(vp, VWRITE, cred,
141368653Smckusick 			    (nd.ni_cnd.cn_flags & RDONLY), procp);
141468653Smckusick 			if (!error) {
141568653Smckusick 				nqsrv_getl(vp, ND_WRITE);
141668653Smckusick 				tempsize = vap->va_size;
141768653Smckusick 				VATTR_NULL(vap);
141868653Smckusick 				vap->va_size = tempsize;
141968653Smckusick 				error = VOP_SETATTR(vp, vap, cred,
142068653Smckusick 					 procp);
142160401Smckusick 			}
142268653Smckusick 			if (error)
142356285Smckusick 				vput(vp);
142442506Smckusick 		}
142538418Smckusick 	}
142668653Smckusick 	if (!error) {
142768653Smckusick 		bzero((caddr_t)fhp, sizeof(nfh));
142868653Smckusick 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
142968653Smckusick 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
143068653Smckusick 		if (!error)
143168653Smckusick 			error = VOP_GETATTR(vp, vap, cred, procp);
143238418Smckusick 		vput(vp);
143338418Smckusick 	}
143468653Smckusick 	if (v3) {
143568653Smckusick 		if (exclusive_flag && !error &&
143668653Smckusick 			bcmp(cverf, (caddr_t)&vap->va_atime, NFSX_V3CREATEVERF))
143768653Smckusick 			error = EEXIST;
143868653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
143968653Smckusick 		vrele(dirp);
144068653Smckusick 	}
144168653Smckusick 	nfsm_reply(NFSX_SRVFH(v3) + NFSX_FATTR(v3) + NFSX_WCCDATA(v3));
144268653Smckusick 	if (v3) {
144368653Smckusick 		if (!error) {
144468653Smckusick 			nfsm_srvpostop_fh(fhp);
144568653Smckusick 			nfsm_srvpostop_attr(0, vap);
144668653Smckusick 		}
144768653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
144868653Smckusick 	} else {
144968653Smckusick 		nfsm_srvfhtom(fhp, v3);
145068653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
145168653Smckusick 		nfsm_srvfillattr(vap, fp);
145268653Smckusick 	}
145368653Smckusick 	return (0);
145438418Smckusick nfsmout:
145568653Smckusick 	if (dirp)
145668653Smckusick 		vrele(dirp);
145768653Smckusick 	if (nd.ni_cnd.cn_nameiop) {
145851464Sbostic 		vrele(nd.ni_startdir);
145968653Smckusick 		free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
146068653Smckusick 	}
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 /*
147268653Smckusick  * nfs v3 mknod service
147338418Smckusick  */
147468653Smckusick int
nfsrv_mknod(nfsd,slp,procp,mrq)147568653Smckusick nfsrv_mknod(nfsd, slp, procp, mrq)
147668653Smckusick 	struct nfsrv_descript *nfsd;
147768653Smckusick 	struct nfssvc_sock *slp;
147868653Smckusick 	struct proc *procp;
147968653Smckusick 	struct mbuf **mrq;
148038418Smckusick {
148168653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
148268653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
148368653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
148468653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
148568653Smckusick 	register struct nfs_fattr *fp;
148668653Smckusick 	struct vattr va, dirfor, diraft;
148768653Smckusick 	register struct vattr *vap = &va;
148868653Smckusick 	register u_long *tl;
148949742Smckusick 	struct nameidata nd;
149068653Smckusick 	register caddr_t cp;
149139494Smckusick 	register long t1;
149239494Smckusick 	caddr_t bpos;
149368653Smckusick 	int error = 0, cache, len, tsize, dirfor_ret = 1, diraft_ret = 1;
149468653Smckusick 	u_long major, minor;
149568653Smckusick 	enum vtype vtyp;
149639494Smckusick 	char *cp2;
149768653Smckusick 	struct mbuf *mb, *mb2, *mreq;
149868653Smckusick 	struct vnode *vp, *dirp = (struct vnode *)0;
149968653Smckusick 	nfsfh_t nfh;
150038418Smckusick 	fhandle_t *fhp;
150152196Smckusick 	u_quad_t frev;
150238418Smckusick 
150368653Smckusick 	nd.ni_cnd.cn_nameiop = 0;
150438418Smckusick 	fhp = &nfh.fh_generic;
150538418Smckusick 	nfsm_srvmtofh(fhp);
150668653Smckusick 	nfsm_srvnamesiz(len);
150752316Sheideman 	nd.ni_cnd.cn_cred = cred;
150868653Smckusick 	nd.ni_cnd.cn_nameiop = CREATE;
150968653Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF | SAVESTART;
151068653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
151168653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
151268653Smckusick 	if (dirp)
151368653Smckusick 		dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred, procp);
151468653Smckusick 	if (error) {
151568653Smckusick 		nfsm_reply(NFSX_WCCDATA(1));
151668653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
151768653Smckusick 		if (dirp)
151868653Smckusick 			vrele(dirp);
151968653Smckusick 		return (0);
152068653Smckusick 	}
152168653Smckusick 	nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
152268653Smckusick 	vtyp = nfsv3tov_type(*tl);
152368653Smckusick 	if (vtyp != VCHR && vtyp != VBLK && vtyp != VSOCK && vtyp != VFIFO) {
152468653Smckusick 		vrele(nd.ni_startdir);
152568653Smckusick 		free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
152668653Smckusick 		error = NFSERR_BADTYPE;
152768653Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
152868653Smckusick 		vput(nd.ni_dvp);
152938418Smckusick 		goto out;
153068653Smckusick 	}
153168653Smckusick 	VATTR_NULL(vap);
153268653Smckusick 	nfsm_srvsattr(vap);
153368653Smckusick 	if (vtyp == VCHR || vtyp == VBLK) {
153468653Smckusick 		nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
153568653Smckusick 		major = fxdr_unsigned(u_long, *tl++);
153668653Smckusick 		minor = fxdr_unsigned(u_long, *tl);
153768653Smckusick 		vap->va_rdev = makedev(major, minor);
153868653Smckusick 	}
153968653Smckusick 
154038418Smckusick 	/*
154168653Smckusick 	 * Iff doesn't exist, create it.
154238418Smckusick 	 */
154368653Smckusick 	if (nd.ni_vp) {
154468653Smckusick 		vrele(nd.ni_startdir);
154568653Smckusick 		free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
154668653Smckusick 		error = EEXIST;
154768653Smckusick 		VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
154868653Smckusick 		vput(nd.ni_dvp);
154938418Smckusick 		goto out;
155038418Smckusick 	}
155168653Smckusick 	vap->va_type = vtyp;
155268653Smckusick 	if (vtyp == VSOCK) {
155368653Smckusick 		vrele(nd.ni_startdir);
155468653Smckusick 		nqsrv_getl(nd.ni_dvp, ND_WRITE);
155568653Smckusick 		error = VOP_CREATE(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
155668653Smckusick 		if (!error)
155768653Smckusick 			FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
155868653Smckusick 	} else {
155968653Smckusick 		if (error = suser(cred, (u_short *)0)) {
156068653Smckusick 			vrele(nd.ni_startdir);
156168653Smckusick 			free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
156268653Smckusick 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
156368653Smckusick 			vput(nd.ni_dvp);
156468653Smckusick 			goto out;
156568653Smckusick 		}
156668653Smckusick 		nqsrv_getl(nd.ni_dvp, ND_WRITE);
156768653Smckusick 		if (error = VOP_MKNOD(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap)) {
156868653Smckusick 			vrele(nd.ni_startdir);
156968653Smckusick 			goto out;
157068653Smckusick 		}
157168653Smckusick 		nd.ni_cnd.cn_nameiop = LOOKUP;
157268653Smckusick 		nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART);
157368653Smckusick 		nd.ni_cnd.cn_proc = procp;
157468653Smckusick 		nd.ni_cnd.cn_cred = procp->p_ucred;
157568653Smckusick 		error = lookup(&nd);
157668653Smckusick 		FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
157768653Smckusick 		if (error)
157868653Smckusick 			goto out;
157968653Smckusick 		if (nd.ni_cnd.cn_flags & ISSYMLINK) {
158068653Smckusick 			vrele(nd.ni_dvp);
158168653Smckusick 			vput(nd.ni_vp);
158268653Smckusick 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
158368653Smckusick 			error = EINVAL;
158468653Smckusick 		}
158568653Smckusick 	}
158638418Smckusick out:
158768653Smckusick 	vp = nd.ni_vp;
158842467Smckusick 	if (!error) {
158968653Smckusick 		bzero((caddr_t)fhp, sizeof(nfh));
159068653Smckusick 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
159168653Smckusick 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
159268653Smckusick 		if (!error)
159368653Smckusick 			error = VOP_GETATTR(vp, vap, cred, procp);
159442467Smckusick 		vput(vp);
159542467Smckusick 	}
159668653Smckusick 	diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
159768653Smckusick 	vrele(dirp);
159868653Smckusick 	nfsm_reply(NFSX_SRVFH(1) + NFSX_POSTOPATTR(1) + NFSX_WCCDATA(1));
159968653Smckusick 	if (!error) {
160068653Smckusick 		nfsm_srvpostop_fh(fhp);
160168653Smckusick 		nfsm_srvpostop_attr(0, vap);
160268653Smckusick 	}
160368653Smckusick 	nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
160468653Smckusick 	return (0);
160568653Smckusick nfsmout:
160668653Smckusick 	if (dirp)
160768653Smckusick 		vrele(dirp);
160868653Smckusick 	if (nd.ni_cnd.cn_nameiop) {
160968653Smckusick 		vrele(nd.ni_startdir);
161068653Smckusick 		free((caddr_t)nd.ni_cnd.cn_pnbuf, M_NAMEI);
161168653Smckusick 	}
161268653Smckusick 	VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
161368653Smckusick 	if (nd.ni_dvp == nd.ni_vp)
161468653Smckusick 		vrele(nd.ni_dvp);
161568653Smckusick 	else
161668653Smckusick 		vput(nd.ni_dvp);
161768653Smckusick 	if (nd.ni_vp)
161868653Smckusick 		vput(nd.ni_vp);
161968653Smckusick 	return (error);
162068653Smckusick }
162168653Smckusick 
162268653Smckusick /*
162368653Smckusick  * nfs remove service
162468653Smckusick  */
162568653Smckusick int
nfsrv_remove(nfsd,slp,procp,mrq)162668653Smckusick nfsrv_remove(nfsd, slp, procp, mrq)
162768653Smckusick 	struct nfsrv_descript *nfsd;
162868653Smckusick 	struct nfssvc_sock *slp;
162968653Smckusick 	struct proc *procp;
163068653Smckusick 	struct mbuf **mrq;
163168653Smckusick {
163268653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
163368653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
163468653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
163568653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
163668653Smckusick 	struct nameidata nd;
163768653Smckusick 	register u_long *tl;
163868653Smckusick 	register long t1;
163968653Smckusick 	caddr_t bpos;
164068653Smckusick 	int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
164168653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
164268653Smckusick 	char *cp2;
164368653Smckusick 	struct mbuf *mb, *mreq, *mb2;
164468653Smckusick 	struct vnode *vp, *dirp;
164568653Smckusick 	struct vattr dirfor, diraft;
164668653Smckusick 	nfsfh_t nfh;
164768653Smckusick 	fhandle_t *fhp;
164868653Smckusick 	u_quad_t frev;
164968653Smckusick 
165068653Smckusick #ifndef nolint
165168653Smckusick 	vp = (struct vnode *)0;
165268653Smckusick #endif
165368653Smckusick 	fhp = &nfh.fh_generic;
165468653Smckusick 	nfsm_srvmtofh(fhp);
165568653Smckusick 	nfsm_srvnamesiz(len);
165668653Smckusick 	nd.ni_cnd.cn_cred = cred;
165768653Smckusick 	nd.ni_cnd.cn_nameiop = DELETE;
165868653Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT | LOCKLEAF;
165968653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
166068653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
166168653Smckusick 	if (dirp) {
166268653Smckusick 		if (v3)
166368653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
166468653Smckusick 				procp);
166568653Smckusick 		else
166668653Smckusick 			vrele(dirp);
166768653Smckusick 	}
166868653Smckusick 	if (!error) {
166968653Smckusick 		vp = nd.ni_vp;
167068653Smckusick 		if (vp->v_type == VDIR &&
167168653Smckusick 			(error = suser(cred, (u_short *)0)))
167268653Smckusick 			goto out;
167368653Smckusick 		/*
167468653Smckusick 		 * The root of a mounted filesystem cannot be deleted.
167568653Smckusick 		 */
167668653Smckusick 		if (vp->v_flag & VROOT) {
167768653Smckusick 			error = EBUSY;
167868653Smckusick 			goto out;
167968653Smckusick 		}
168068653Smckusick 		if (vp->v_flag & VTEXT)
168168653Smckusick 			(void) vnode_pager_uncache(vp);
168268653Smckusick out:
168368653Smckusick 		if (!error) {
168468653Smckusick 			nqsrv_getl(nd.ni_dvp, ND_WRITE);
168568653Smckusick 			nqsrv_getl(vp, ND_WRITE);
168668653Smckusick 			error = VOP_REMOVE(nd.ni_dvp, nd.ni_vp, &nd.ni_cnd);
168768653Smckusick 		} else {
168868653Smckusick 			VOP_ABORTOP(nd.ni_dvp, &nd.ni_cnd);
168968653Smckusick 			if (nd.ni_dvp == vp)
169068653Smckusick 				vrele(nd.ni_dvp);
169168653Smckusick 			else
169268653Smckusick 				vput(nd.ni_dvp);
169368653Smckusick 			vput(vp);
169468653Smckusick 		}
169568653Smckusick 	}
169668653Smckusick 	if (dirp && v3) {
169768653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
169868653Smckusick 		vrele(dirp);
169968653Smckusick 	}
170068653Smckusick 	nfsm_reply(NFSX_WCCDATA(v3));
170168653Smckusick 	if (v3) {
170268653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
170368653Smckusick 		return (0);
170468653Smckusick 	}
170538418Smckusick 	nfsm_srvdone;
170638418Smckusick }
170738418Smckusick 
170838418Smckusick /*
170938418Smckusick  * nfs rename service
171038418Smckusick  */
171168653Smckusick int
nfsrv_rename(nfsd,slp,procp,mrq)171268653Smckusick nfsrv_rename(nfsd, slp, procp, mrq)
171368653Smckusick 	struct nfsrv_descript *nfsd;
171468653Smckusick 	struct nfssvc_sock *slp;
171568653Smckusick 	struct proc *procp;
171668653Smckusick 	struct mbuf **mrq;
171738418Smckusick {
171868653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
171968653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
172068653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
172168653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
172248050Smckusick 	register u_long *tl;
172339494Smckusick 	register long t1;
172439494Smckusick 	caddr_t bpos;
172568653Smckusick 	int error = 0, cache, len, len2, fdirfor_ret = 1, fdiraft_ret = 1;
172668653Smckusick 	int tdirfor_ret = 1, tdiraft_ret = 1;
172768653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
172839494Smckusick 	char *cp2;
172968653Smckusick 	struct mbuf *mb, *mreq, *mb2;
173049742Smckusick 	struct nameidata fromnd, tond;
173168653Smckusick 	struct vnode *fvp, *tvp, *tdvp, *fdirp = (struct vnode *)0;
173268653Smckusick 	struct vnode *tdirp = (struct vnode *)0;
173368653Smckusick 	struct vattr fdirfor, fdiraft, tdirfor, tdiraft;
173468653Smckusick 	nfsfh_t fnfh, tnfh;
173538418Smckusick 	fhandle_t *ffhp, *tfhp;
173652196Smckusick 	u_quad_t frev;
173752196Smckusick 	uid_t saved_uid;
173838418Smckusick 
173968653Smckusick #ifndef nolint
174068653Smckusick 	fvp = (struct vnode *)0;
174168653Smckusick #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);
174768653Smckusick 	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;
175668653Smckusick 	error = nfs_namei(&fromnd, ffhp, len, slp, nam, &md,
175768653Smckusick 		&dpos, &fdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
175868653Smckusick 	if (fdirp) {
175968653Smckusick 		if (v3)
176068653Smckusick 			fdirfor_ret = VOP_GETATTR(fdirp, &fdirfor, cred,
176168653Smckusick 				procp);
176268653Smckusick 		else {
176368653Smckusick 			vrele(fdirp);
176468653Smckusick 			fdirp = (struct vnode *)0;
176568653Smckusick 		}
176668653Smckusick 	}
176768653Smckusick 	if (error) {
176868653Smckusick 		nfsm_reply(2 * NFSX_WCCDATA(v3));
176968653Smckusick 		nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
177068653Smckusick 		nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
177168653Smckusick 		if (fdirp)
177268653Smckusick 			vrele(fdirp);
177368653Smckusick 		return (0);
177468653Smckusick 	}
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;
178268653Smckusick 	error = nfs_namei(&tond, tfhp, len2, slp, nam, &md,
178368653Smckusick 		&dpos, &tdirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
178468653Smckusick 	if (tdirp) {
178568653Smckusick 		if (v3)
178668653Smckusick 			tdirfor_ret = VOP_GETATTR(tdirp, &tdirfor, cred,
178768653Smckusick 				procp);
178868653Smckusick 		else {
178968653Smckusick 			vrele(tdirp);
179068653Smckusick 			tdirp = (struct vnode *)0;
179168653Smckusick 		}
179268653Smckusick 	}
179368653Smckusick 	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) {
180368653Smckusick 			if (v3)
180468653Smckusick 				error = EEXIST;
180568653Smckusick 			else
180668653Smckusick 				error = EISDIR;
180738418Smckusick 			goto out;
180838418Smckusick 		} else if (fvp->v_type != VDIR && tvp->v_type == VDIR) {
180968653Smckusick 			if (v3)
181068653Smckusick 				error = EEXIST;
181168653Smckusick 			else
181268653Smckusick 				error = ENOTDIR;
181338418Smckusick 			goto out;
181438418Smckusick 		}
181552196Smckusick 		if (tvp->v_type == VDIR && tvp->v_mountedhere) {
181668653Smckusick 			if (v3)
181768653Smckusick 				error = EXDEV;
181868653Smckusick 			else
181968653Smckusick 				error = ENOTEMPTY;
182052196Smckusick 			goto out;
182152196Smckusick 		}
182238418Smckusick 	}
182352196Smckusick 	if (fvp->v_type == VDIR && fvp->v_mountedhere) {
182468653Smckusick 		if (v3)
182568653Smckusick 			error = EXDEV;
182668653Smckusick 		else
182768653Smckusick 			error = ENOTEMPTY;
182852196Smckusick 		goto out;
182952196Smckusick 	}
183038418Smckusick 	if (fvp->v_mount != tdvp->v_mount) {
183168653Smckusick 		if (v3)
183268653Smckusick 			error = EXDEV;
183368653Smckusick 		else
183468653Smckusick 			error = ENOTEMPTY;
183538418Smckusick 		goto out;
183638418Smckusick 	}
183749742Smckusick 	if (fvp == tdvp)
183868653Smckusick 		if (v3)
183968653Smckusick 			error = EINVAL;
184068653Smckusick 		else
184168653Smckusick 			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) {
185468653Smckusick 		nqsrv_getl(fromnd.ni_dvp, ND_WRITE);
185568653Smckusick 		nqsrv_getl(tdvp, ND_WRITE);
185652196Smckusick 		if (tvp)
185768653Smckusick 			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);
187168653Smckusick 		if (error == -1)
187268653Smckusick 			error = 0;
187338418Smckusick 	}
187446513Smckusick 	vrele(tond.ni_startdir);
187552316Sheideman 	FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
187638418Smckusick out1:
187768653Smckusick 	if (fdirp) {
187868653Smckusick 		fdiraft_ret = VOP_GETATTR(fdirp, &fdiraft, cred, procp);
187968653Smckusick 		vrele(fdirp);
188068653Smckusick 	}
188168653Smckusick 	if (tdirp) {
188268653Smckusick 		tdiraft_ret = VOP_GETATTR(tdirp, &tdiraft, cred, procp);
188368653Smckusick 		vrele(tdirp);
188468653Smckusick 	}
188549742Smckusick 	vrele(fromnd.ni_startdir);
188652316Sheideman 	FREE(fromnd.ni_cnd.cn_pnbuf, M_NAMEI);
188768653Smckusick 	nfsm_reply(2 * NFSX_WCCDATA(v3));
188868653Smckusick 	if (v3) {
188968653Smckusick 		nfsm_srvwcc_data(fdirfor_ret, &fdirfor, fdiraft_ret, &fdiraft);
189068653Smckusick 		nfsm_srvwcc_data(tdirfor_ret, &tdirfor, tdiraft_ret, &tdiraft);
189168653Smckusick 	}
189268653Smckusick 	return (0);
189349742Smckusick 
189438418Smckusick nfsmout:
189568653Smckusick 	if (fdirp)
189668653Smckusick 		vrele(fdirp);
189768653Smckusick 	if (tdirp)
189868653Smckusick 		vrele(tdirp);
189968653Smckusick 	if (tond.ni_cnd.cn_nameiop) {
190049742Smckusick 		vrele(tond.ni_startdir);
190152316Sheideman 		FREE(tond.ni_cnd.cn_pnbuf, M_NAMEI);
190249742Smckusick 	}
190368653Smckusick 	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  */
191668653Smckusick int
nfsrv_link(nfsd,slp,procp,mrq)191768653Smckusick nfsrv_link(nfsd, slp, procp, mrq)
191868653Smckusick 	struct nfsrv_descript *nfsd;
191968653Smckusick 	struct nfssvc_sock *slp;
192068653Smckusick 	struct proc *procp;
192168653Smckusick 	struct mbuf **mrq;
192238418Smckusick {
192368653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
192468653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
192568653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
192668653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
192749742Smckusick 	struct nameidata nd;
192848050Smckusick 	register u_long *tl;
192939494Smckusick 	register long t1;
193039494Smckusick 	caddr_t bpos;
193168653Smckusick 	int error = 0, rdonly, cache, len, dirfor_ret = 1, diraft_ret = 1;
193268653Smckusick 	int getret = 1, v3 = (nfsd->nd_flag & ND_NFSV3);
193339494Smckusick 	char *cp2;
193468653Smckusick 	struct mbuf *mb, *mreq, *mb2;
193568653Smckusick 	struct vnode *vp, *xp, *dirp = (struct vnode *)0;
193668653Smckusick 	struct vattr dirfor, diraft, at;
193768653Smckusick 	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);
194568653Smckusick 	nfsm_srvnamesiz(len);
194668653Smckusick 	if (error = nfsrv_fhtovp(fhp, FALSE, &vp, cred, slp, nam,
194768653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
194868653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
194968653Smckusick 		nfsm_srvpostop_attr(getret, &at);
195068653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
195168653Smckusick 		return (0);
195268653Smckusick 	}
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;
195868653Smckusick 	error = nfs_namei(&nd, dfhp, len, slp, nam, &md, &dpos,
195968653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
196068653Smckusick 	if (dirp) {
196168653Smckusick 		if (v3)
196268653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
196368653Smckusick 				procp);
196468653Smckusick 		else {
196568653Smckusick 			vrele(dirp);
196668653Smckusick 			dirp = (struct vnode *)0;
196768653Smckusick 		}
196868653Smckusick 	}
196968653Smckusick 	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) {
198168653Smckusick 		nqsrv_getl(vp, ND_WRITE);
198268653Smckusick 		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:
199468653Smckusick 	if (v3)
199568653Smckusick 		getret = VOP_GETATTR(vp, &at, cred, procp);
199668653Smckusick 	if (dirp) {
199768653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
199868653Smckusick 		vrele(dirp);
199968653Smckusick 	}
200038418Smckusick 	vrele(vp);
200168653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
200268653Smckusick 	if (v3) {
200368653Smckusick 		nfsm_srvpostop_attr(getret, &at);
200468653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
200568653Smckusick 		return (0);
200668653Smckusick 	}
200738418Smckusick 	nfsm_srvdone;
200838418Smckusick }
200938418Smckusick 
201038418Smckusick /*
201138418Smckusick  * nfs symbolic link service
201238418Smckusick  */
201368653Smckusick int
nfsrv_symlink(nfsd,slp,procp,mrq)201468653Smckusick nfsrv_symlink(nfsd, slp, procp, mrq)
201568653Smckusick 	struct nfsrv_descript *nfsd;
201668653Smckusick 	struct nfssvc_sock *slp;
201768653Smckusick 	struct proc *procp;
201868653Smckusick 	struct mbuf **mrq;
201938418Smckusick {
202068653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
202168653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
202268653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
202368653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
202468653Smckusick 	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;
203068653Smckusick 	char *bpos, *cp, *pathcp = (char *)0, *cp2;
203141899Smckusick 	struct uio io;
203241899Smckusick 	struct iovec iv;
203368653Smckusick 	int error = 0, cache, len, len2, dirfor_ret = 1, diraft_ret = 1;
203468653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
203568653Smckusick 	struct mbuf *mb, *mreq, *mb2;
203668653Smckusick 	struct vnode *dirp = (struct vnode *)0;
203768653Smckusick 	nfsfh_t nfh;
203838418Smckusick 	fhandle_t *fhp;
203952196Smckusick 	u_quad_t frev;
204038418Smckusick 
204168653Smckusick 	nd.ni_cnd.cn_nameiop = 0;
204238418Smckusick 	fhp = &nfh.fh_generic;
204338418Smckusick 	nfsm_srvmtofh(fhp);
204468653Smckusick 	nfsm_srvnamesiz(len);
204552316Sheideman 	nd.ni_cnd.cn_cred = cred;
204652316Sheideman 	nd.ni_cnd.cn_nameiop = CREATE;
204768653Smckusick 	nd.ni_cnd.cn_flags = LOCKPARENT | SAVESTART;
204868653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
204968653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
205068653Smckusick 	if (dirp) {
205168653Smckusick 		if (v3)
205268653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
205368653Smckusick 				procp);
205468653Smckusick 		else {
205568653Smckusick 			vrele(dirp);
205668653Smckusick 			dirp = (struct vnode *)0;
205768653Smckusick 		}
205868653Smckusick 	}
205968653Smckusick 	if (error)
206042467Smckusick 		goto out;
206168653Smckusick 	VATTR_NULL(vap);
206268653Smckusick 	if (v3)
206368653Smckusick 		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);
207668653Smckusick 	if (!v3) {
207768653Smckusick 		nfsm_dissect(sp, struct nfsv2_sattr *, NFSX_V2SATTR);
207868653Smckusick 		vap->va_mode = fxdr_unsigned(u_short, sp->sa_mode);
207968653Smckusick 	}
208041899Smckusick 	*(pathcp + len2) = '\0';
208149742Smckusick 	if (nd.ni_vp) {
208268653Smckusick 		vrele(nd.ni_startdir);
208368653Smckusick 		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 	}
209368653Smckusick 	nqsrv_getl(nd.ni_dvp, ND_WRITE);
209452234Sheideman 	error = VOP_SYMLINK(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap, pathcp);
209568653Smckusick 	if (error)
209668653Smckusick 		vrele(nd.ni_startdir);
209768653Smckusick 	else {
209868653Smckusick 	    if (v3) {
209968653Smckusick 		nd.ni_cnd.cn_nameiop = LOOKUP;
210068653Smckusick 		nd.ni_cnd.cn_flags &= ~(LOCKPARENT | SAVESTART | FOLLOW);
210168653Smckusick 		nd.ni_cnd.cn_flags |= (NOFOLLOW | LOCKLEAF);
210268653Smckusick 		nd.ni_cnd.cn_proc = procp;
210368653Smckusick 		nd.ni_cnd.cn_cred = cred;
210468653Smckusick 		error = lookup(&nd);
210568653Smckusick 		if (!error) {
210668653Smckusick 			bzero((caddr_t)fhp, sizeof(nfh));
210768653Smckusick 			fhp->fh_fsid = nd.ni_vp->v_mount->mnt_stat.f_fsid;
210868653Smckusick 			error = VFS_VPTOFH(nd.ni_vp, &fhp->fh_fid);
210968653Smckusick 			if (!error)
211068653Smckusick 				error = VOP_GETATTR(nd.ni_vp, vap, cred,
211168653Smckusick 					procp);
211268653Smckusick 			vput(nd.ni_vp);
211368653Smckusick 		}
211468653Smckusick 	    } else
211568653Smckusick 		vrele(nd.ni_startdir);
211668653Smckusick 	    FREE(nd.ni_cnd.cn_pnbuf, M_NAMEI);
211768653Smckusick 	}
211838418Smckusick out:
211941899Smckusick 	if (pathcp)
212041899Smckusick 		FREE(pathcp, M_TEMP);
212168653Smckusick 	if (dirp) {
212268653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
212368653Smckusick 		vrele(dirp);
212468653Smckusick 	}
212568653Smckusick 	nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
212668653Smckusick 	if (v3) {
212768653Smckusick 		if (!error) {
212868653Smckusick 			nfsm_srvpostop_fh(fhp);
212968653Smckusick 			nfsm_srvpostop_attr(0, vap);
213068653Smckusick 		}
213168653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
213268653Smckusick 	}
213368653Smckusick 	return (0);
213438418Smckusick nfsmout:
213568653Smckusick 	if (nd.ni_cnd.cn_nameiop) {
213668653Smckusick 		vrele(nd.ni_startdir);
213768653Smckusick 		free(nd.ni_cnd.cn_pnbuf, M_NAMEI);
213868653Smckusick 	}
213968653Smckusick 	if (dirp)
214068653Smckusick 		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  */
215668653Smckusick int
nfsrv_mkdir(nfsd,slp,procp,mrq)215768653Smckusick nfsrv_mkdir(nfsd, slp, procp, mrq)
215868653Smckusick 	struct nfsrv_descript *nfsd;
215968653Smckusick 	struct nfssvc_sock *slp;
216068653Smckusick 	struct proc *procp;
216168653Smckusick 	struct mbuf **mrq;
216238418Smckusick {
216368653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
216468653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
216568653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
216668653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
216768653Smckusick 	struct vattr va, dirfor, diraft;
216838418Smckusick 	register struct vattr *vap = &va;
216968653Smckusick 	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;
217568653Smckusick 	int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
217668653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
217739494Smckusick 	char *cp2;
217839753Smckusick 	struct mbuf *mb, *mb2, *mreq;
217968653Smckusick 	struct vnode *vp, *dirp = (struct vnode *)0;
218068653Smckusick 	nfsfh_t nfh;
218138418Smckusick 	fhandle_t *fhp;
218252196Smckusick 	u_quad_t frev;
218338418Smckusick 
218438418Smckusick 	fhp = &nfh.fh_generic;
218538418Smckusick 	nfsm_srvmtofh(fhp);
218668653Smckusick 	nfsm_srvnamesiz(len);
218752316Sheideman 	nd.ni_cnd.cn_cred = cred;
218852316Sheideman 	nd.ni_cnd.cn_nameiop = CREATE;
218952316Sheideman 	nd.ni_cnd.cn_flags = LOCKPARENT;
219068653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
219168653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
219268653Smckusick 	if (dirp) {
219368653Smckusick 		if (v3)
219468653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
219568653Smckusick 				procp);
219668653Smckusick 		else {
219768653Smckusick 			vrele(dirp);
219868653Smckusick 			dirp = (struct vnode *)0;
219968653Smckusick 		}
220068653Smckusick 	}
220168653Smckusick 	if (error) {
220268653Smckusick 		nfsm_reply(NFSX_WCCDATA(v3));
220368653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
220468653Smckusick 		if (dirp)
220568653Smckusick 			vrele(dirp);
220668653Smckusick 		return (0);
220768653Smckusick 	}
220841361Smckusick 	VATTR_NULL(vap);
220968653Smckusick 	if (v3) {
221068653Smckusick 		nfsm_srvsattr(vap);
221168653Smckusick 	} else {
221268653Smckusick 		nfsm_dissect(tl, u_long *, NFSX_UNSIGNED);
221368653Smckusick 		vap->va_mode = nfstov_mode(*tl++);
221468653Smckusick 	}
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;
222568653Smckusick 		goto out;
222638418Smckusick 	}
222768653Smckusick 	nqsrv_getl(nd.ni_dvp, ND_WRITE);
222868653Smckusick 	error = VOP_MKDIR(nd.ni_dvp, &nd.ni_vp, &nd.ni_cnd, vap);
222968653Smckusick 	if (!error) {
223068653Smckusick 		vp = nd.ni_vp;
223168653Smckusick 		bzero((caddr_t)fhp, sizeof(nfh));
223268653Smckusick 		fhp->fh_fsid = vp->v_mount->mnt_stat.f_fsid;
223368653Smckusick 		error = VFS_VPTOFH(vp, &fhp->fh_fid);
223468653Smckusick 		if (!error)
223568653Smckusick 			error = VOP_GETATTR(vp, vap, cred, procp);
223638418Smckusick 		vput(vp);
223738418Smckusick 	}
223868653Smckusick out:
223968653Smckusick 	if (dirp) {
224068653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
224168653Smckusick 		vrele(dirp);
224268653Smckusick 	}
224368653Smckusick 	nfsm_reply(NFSX_SRVFH(v3) + NFSX_POSTOPATTR(v3) + NFSX_WCCDATA(v3));
224468653Smckusick 	if (v3) {
224568653Smckusick 		if (!error) {
224668653Smckusick 			nfsm_srvpostop_fh(fhp);
224768653Smckusick 			nfsm_srvpostop_attr(0, vap);
224868653Smckusick 		}
224968653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
225068653Smckusick 	} else {
225168653Smckusick 		nfsm_srvfhtom(fhp, v3);
225268653Smckusick 		nfsm_build(fp, struct nfs_fattr *, NFSX_V2FATTR);
225368653Smckusick 		nfsm_srvfillattr(vap, fp);
225468653Smckusick 	}
225568653Smckusick 	return (0);
225638418Smckusick nfsmout:
225768653Smckusick 	if (dirp)
225868653Smckusick 		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  */
227268653Smckusick int
nfsrv_rmdir(nfsd,slp,procp,mrq)227368653Smckusick nfsrv_rmdir(nfsd, slp, procp, mrq)
227468653Smckusick 	struct nfsrv_descript *nfsd;
227568653Smckusick 	struct nfssvc_sock *slp;
227668653Smckusick 	struct proc *procp;
227768653Smckusick 	struct mbuf **mrq;
227838418Smckusick {
227968653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
228068653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
228168653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
228268653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
228348050Smckusick 	register u_long *tl;
228439494Smckusick 	register long t1;
228539494Smckusick 	caddr_t bpos;
228668653Smckusick 	int error = 0, cache, len, dirfor_ret = 1, diraft_ret = 1;
228768653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
228839494Smckusick 	char *cp2;
228968653Smckusick 	struct mbuf *mb, *mreq, *mb2;
229068653Smckusick 	struct vnode *vp, *dirp = (struct vnode *)0;
229168653Smckusick 	struct vattr dirfor, diraft;
229268653Smckusick 	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);
229968653Smckusick 	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;
230368653Smckusick 	error = nfs_namei(&nd, fhp, len, slp, nam, &md, &dpos,
230468653Smckusick 		&dirp, procp, (nfsd->nd_flag & ND_KERBAUTH));
230568653Smckusick 	if (dirp) {
230668653Smckusick 		if (v3)
230768653Smckusick 			dirfor_ret = VOP_GETATTR(dirp, &dirfor, cred,
230868653Smckusick 				procp);
230968653Smckusick 		else {
231068653Smckusick 			vrele(dirp);
231168653Smckusick 			dirp = (struct vnode *)0;
231268653Smckusick 		}
231368653Smckusick 	}
231468653Smckusick 	if (error) {
231568653Smckusick 		nfsm_reply(NFSX_WCCDATA(v3));
231668653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
231768653Smckusick 		if (dirp)
231868653Smckusick 			vrele(dirp);
231968653Smckusick 		return (0);
232068653Smckusick 	}
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) {
234068653Smckusick 		nqsrv_getl(nd.ni_dvp, ND_WRITE);
234168653Smckusick 		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 	}
235168653Smckusick 	if (dirp) {
235268653Smckusick 		diraft_ret = VOP_GETATTR(dirp, &diraft, cred, procp);
235368653Smckusick 		vrele(dirp);
235468653Smckusick 	}
235568653Smckusick 	nfsm_reply(NFSX_WCCDATA(v3));
235668653Smckusick 	if (v3) {
235768653Smckusick 		nfsm_srvwcc_data(dirfor_ret, &dirfor, diraft_ret, &diraft);
235868653Smckusick 		return (0);
235968653Smckusick 	}
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 }
238368653Smckusick  *     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 {
239368653Smckusick 	nfsuint64	fl_off;
239468653Smckusick 	u_long		fl_postopok;
239568653Smckusick 	u_long		fl_fattr[NFSX_V3FATTR / sizeof (u_long)];
239668653Smckusick 	u_long		fl_fhok;
239768653Smckusick 	u_long		fl_fhsize;
239868653Smckusick 	u_long		fl_nfh[NFSX_V3FH / sizeof (u_long)];
239952196Smckusick };
240052196Smckusick 
240168653Smckusick int
nfsrv_readdir(nfsd,slp,procp,mrq)240268653Smckusick nfsrv_readdir(nfsd, slp, procp, mrq)
240368653Smckusick 	struct nfsrv_descript *nfsd;
240468653Smckusick 	struct nfssvc_sock *slp;
240568653Smckusick 	struct proc *procp;
240668653Smckusick 	struct mbuf **mrq;
240738418Smckusick {
240868653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
240968653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
241068653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
241168653Smckusick 	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;
242268653Smckusick 	struct vattr at;
242368653Smckusick 	nfsfh_t nfh;
242438418Smckusick 	fhandle_t *fhp;
242538418Smckusick 	struct uio io;
242638418Smckusick 	struct iovec iv;
242768653Smckusick 	int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
242868653Smckusick 	int siz, cnt, fullsiz, eofflag, rdonly, cache, ncookies;
242968653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
243068653Smckusick 	u_quad_t frev, off, toff, verf;
243168653Smckusick 	u_long *cookies = NULL, *cookiep;
243238418Smckusick 
243338418Smckusick 	fhp = &nfh.fh_generic;
243438418Smckusick 	nfsm_srvmtofh(fhp);
243568653Smckusick 	if (v3) {
243668653Smckusick 		nfsm_dissect(tl, u_long *, 5 * NFSX_UNSIGNED);
243768653Smckusick 		fxdr_hyper(tl, &toff);
243868653Smckusick 		tl += 2;
243968653Smckusick 		fxdr_hyper(tl, &verf);
244068653Smckusick 		tl += 2;
244168653Smckusick 	} else {
244268653Smckusick 		nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
244368653Smckusick 		toff = fxdr_unsigned(u_quad_t, *tl++);
244468653Smckusick 	}
244568653Smckusick 	off = toff;
244648050Smckusick 	cnt = fxdr_unsigned(int, *tl);
244768653Smckusick 	siz = ((cnt + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
244868653Smckusick 	xfer = NFS_SRVMAXDATA(nfsd);
244968653Smckusick 	if (siz > xfer)
245068653Smckusick 		siz = xfer;
245138418Smckusick 	fullsiz = siz;
245268653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
245368653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
245468653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
245568653Smckusick 		nfsm_srvpostop_attr(getret, &at);
245668653Smckusick 		return (0);
245768653Smckusick 	}
245868653Smckusick 	nqsrv_getl(vp, ND_READ);
245968653Smckusick 	if (v3) {
246068653Smckusick 		error = getret = VOP_GETATTR(vp, &at, cred, procp);
246168653Smckusick 		if (!error && toff && verf != at.va_filerev)
246268653Smckusick 			error = NFSERR_BAD_COOKIE;
246368653Smckusick 	}
246468653Smckusick 	if (!error)
246568653Smckusick 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
246668653Smckusick 	if (error) {
246738418Smckusick 		vput(vp);
246868653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3));
246968653Smckusick 		nfsm_srvpostop_attr(getret, &at);
247068653Smckusick 		return (0);
247138418Smckusick 	}
2472*69424Smckusick 	VOP_UNLOCK(vp, 0, procp);
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;
248468653Smckusick 	eofflag = 0;
248568653Smckusick 	if (cookies) {
248668653Smckusick 		free((caddr_t)cookies, M_TEMP);
248768653Smckusick 		cookies = NULL;
248868653Smckusick 	}
248968653Smckusick 	error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
249056285Smckusick 	off = (off_t)io.uio_offset;
249168653Smckusick 	if (!cookies && !error)
249268653Smckusick 		error = NFSERR_PERM;
249368653Smckusick 	if (v3) {
249468653Smckusick 		getret = VOP_GETATTR(vp, &at, cred, procp);
249568653Smckusick 		if (!error)
249668653Smckusick 			error = getret;
249768653Smckusick 	}
249838418Smckusick 	if (error) {
249938418Smckusick 		vrele(vp);
250038418Smckusick 		free((caddr_t)rbuf, M_TEMP);
250168653Smckusick 		if (cookies)
250268653Smckusick 			free((caddr_t)cookies, M_TEMP);
250368653Smckusick 		nfsm_reply(NFSX_POSTOPATTR(v3));
250468653Smckusick 		nfsm_srvpostop_attr(getret, &at);
250568653Smckusick 		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);
251668653Smckusick 			nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) +
251768653Smckusick 				2 * NFSX_UNSIGNED);
251868653Smckusick 			if (v3) {
251968653Smckusick 				nfsm_srvpostop_attr(getret, &at);
252068653Smckusick 				nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
252168653Smckusick 				txdr_hyper(&at.va_filerev, tl);
252268653Smckusick 				tl += 2;
252368653Smckusick 			} else
252468653Smckusick 				nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
252548050Smckusick 			*tl++ = nfs_false;
252648050Smckusick 			*tl = nfs_true;
252738418Smckusick 			FREE((caddr_t)rbuf, M_TEMP);
252868653Smckusick 			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;
253968653Smckusick 	dp = (struct dirent *)cpos;
254068653Smckusick 	cookiep = cookies;
254168653Smckusick 	while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
254268653Smckusick 		cpos += dp->d_reclen;
254352441Smckusick 		dp = (struct dirent *)cpos;
254468653Smckusick 		cookiep++;
254568653Smckusick 		ncookies--;
254640115Smckusick 	}
254768653Smckusick 	if (cpos >= cend || ncookies == 0) {
254868653Smckusick 		toff = off;
254938418Smckusick 		siz = fullsiz;
255038418Smckusick 		goto again;
255138418Smckusick 	}
255240115Smckusick 
255368653Smckusick 	len = 3 * NFSX_UNSIGNED;	/* paranoia, probably can be 0 */
255468653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_COOKIEVERF(v3) + siz);
255568653Smckusick 	if (v3) {
255668653Smckusick 		nfsm_srvpostop_attr(getret, &at);
255768653Smckusick 		nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
255868653Smckusick 		txdr_hyper(&at.va_filerev, tl);
255968653Smckusick 	}
256052196Smckusick 	mp = mp2 = mb;
256152196Smckusick 	bp = bpos;
256252196Smckusick 	be = bp + M_TRAILINGSPACE(mp);
256352196Smckusick 
256452196Smckusick 	/* Loop through the records and build reply */
256568653Smckusick 	while (cpos < cend && ncookies > 0) {
256652441Smckusick 		if (dp->d_fileno != 0) {
256752196Smckusick 			nlen = dp->d_namlen;
256852196Smckusick 			rem = nfsm_rndup(nlen)-nlen;
256968653Smckusick 			len += (4 * NFSX_UNSIGNED + nlen + rem);
257068653Smckusick 			if (v3)
257168653Smckusick 				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;
258368653Smckusick 			if (v3) {
258468653Smckusick 				nfsm_clget;
258568653Smckusick 				*tl = 0;
258668653Smckusick 				bp += NFSX_UNSIGNED;
258768653Smckusick 			}
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 */
261668653Smckusick 			if (v3) {
261768653Smckusick 				*tl = 0;
261868653Smckusick 				bp += NFSX_UNSIGNED;
261968653Smckusick 				nfsm_clget;
262068653Smckusick 			}
262168653Smckusick 			*tl = txdr_unsigned(*cookiep);
262252196Smckusick 			bp += NFSX_UNSIGNED;
262367363Smckusick 		}
262452196Smckusick 		cpos += dp->d_reclen;
262552441Smckusick 		dp = (struct dirent *)cpos;
262668653Smckusick 		cookiep++;
262768653Smckusick 		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;
264468653Smckusick 	FREE((caddr_t)rbuf, M_TEMP);
264568653Smckusick 	FREE((caddr_t)cookies, M_TEMP);
264652196Smckusick 	nfsm_srvdone;
264752196Smckusick }
264852196Smckusick 
264968653Smckusick int
nfsrv_readdirplus(nfsd,slp,procp,mrq)265068653Smckusick nfsrv_readdirplus(nfsd, slp, procp, mrq)
265168653Smckusick 	struct nfsrv_descript *nfsd;
265268653Smckusick 	struct nfssvc_sock *slp;
265368653Smckusick 	struct proc *procp;
265468653Smckusick 	struct mbuf **mrq;
265552196Smckusick {
265668653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
265768653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
265868653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
265968653Smckusick 	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;
267168653Smckusick 	nfsfh_t nfh;
267268653Smckusick 	fhandle_t *fhp, *nfhp = (fhandle_t *)fl.fl_nfh;
267352196Smckusick 	struct uio io;
267452196Smckusick 	struct iovec iv;
267568653Smckusick 	struct vattr va, at, *vap = &va;
267668653Smckusick 	struct nfs_fattr *fp;
267768653Smckusick 	int len, nlen, rem, xfer, tsiz, i, error = 0, getret = 1;
267868653Smckusick 	int siz, cnt, fullsiz, eofflag, rdonly, cache, dirlen, ncookies;
267968653Smckusick 	u_quad_t frev, off, toff, verf;
268068653Smckusick 	u_long *cookies = NULL, *cookiep;
268152196Smckusick 
268252196Smckusick 	fhp = &nfh.fh_generic;
268352196Smckusick 	nfsm_srvmtofh(fhp);
268468653Smckusick 	nfsm_dissect(tl, u_long *, 6 * NFSX_UNSIGNED);
268568653Smckusick 	fxdr_hyper(tl, &toff);
268668653Smckusick 	tl += 2;
268768653Smckusick 	fxdr_hyper(tl, &verf);
268868653Smckusick 	tl += 2;
268968653Smckusick 	siz = fxdr_unsigned(int, *tl++);
269068653Smckusick 	cnt = fxdr_unsigned(int, *tl);
269168653Smckusick 	off = toff;
269268653Smckusick 	siz = ((siz + DIRBLKSIZ - 1) & ~(DIRBLKSIZ - 1));
269368653Smckusick 	xfer = NFS_SRVMAXDATA(nfsd);
269468653Smckusick 	if (siz > xfer)
269568653Smckusick 		siz = xfer;
269652196Smckusick 	fullsiz = siz;
269768653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
269868653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
269968653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
270068653Smckusick 		nfsm_srvpostop_attr(getret, &at);
270168653Smckusick 		return (0);
270268653Smckusick 	}
270368653Smckusick 	error = getret = VOP_GETATTR(vp, &at, cred, procp);
270468653Smckusick 	if (!error && toff && verf != at.va_filerev)
270568653Smckusick 		error = NFSERR_BAD_COOKIE;
270668653Smckusick 	if (!error) {
270768653Smckusick 		nqsrv_getl(vp, ND_READ);
270868653Smckusick 		error = nfsrv_access(vp, VEXEC, cred, rdonly, procp);
270968653Smckusick 	}
271068653Smckusick 	if (error) {
271152196Smckusick 		vput(vp);
271268653Smckusick 		nfsm_reply(NFSX_V3POSTOPATTR);
271368653Smckusick 		nfsm_srvpostop_attr(getret, &at);
271468653Smckusick 		return (0);
271552196Smckusick 	}
2716*69424Smckusick 	VOP_UNLOCK(vp, 0, procp);
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;
272868653Smckusick 	eofflag = 0;
272968653Smckusick 	if (cookies) {
273068653Smckusick 		free((caddr_t)cookies, M_TEMP);
273168653Smckusick 		cookies = NULL;
273268653Smckusick 	}
273368653Smckusick 	error = VOP_READDIR(vp, &io, cred, &eofflag, &ncookies, &cookies);
273468653Smckusick 	off = (u_quad_t)io.uio_offset;
273568653Smckusick 	getret = VOP_GETATTR(vp, &at, cred, procp);
273668653Smckusick 	if (!cookies && !error)
273768653Smckusick 		error = NFSERR_PERM;
273868653Smckusick 	if (!error)
273968653Smckusick 		error = getret;
274052196Smckusick 	if (error) {
274152196Smckusick 		vrele(vp);
274268653Smckusick 		if (cookies)
274368653Smckusick 			free((caddr_t)cookies, M_TEMP);
274452196Smckusick 		free((caddr_t)rbuf, M_TEMP);
274568653Smckusick 		nfsm_reply(NFSX_V3POSTOPATTR);
274668653Smckusick 		nfsm_srvpostop_attr(getret, &at);
274768653Smckusick 		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);
275868653Smckusick 			nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF +
275968653Smckusick 				2 * NFSX_UNSIGNED);
276068653Smckusick 			nfsm_srvpostop_attr(getret, &at);
276168653Smckusick 			nfsm_build(tl, u_long *, 4 * NFSX_UNSIGNED);
276268653Smckusick 			txdr_hyper(&at.va_filerev, tl);
276368653Smckusick 			tl += 2;
276452196Smckusick 			*tl++ = nfs_false;
276552196Smckusick 			*tl = nfs_true;
276668653Smckusick 			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;
277868653Smckusick 	dp = (struct dirent *)cpos;
277968653Smckusick 	cookiep = cookies;
278068653Smckusick 	while (dp->d_fileno == 0 && cpos < cend && ncookies > 0) {
278168653Smckusick 		cpos += dp->d_reclen;
278252441Smckusick 		dp = (struct dirent *)cpos;
278368653Smckusick 		cookiep++;
278468653Smckusick 		ncookies--;
278552196Smckusick 	}
278668653Smckusick 	if (cpos >= cend || ncookies == 0) {
278768653Smckusick 		toff = off;
278852196Smckusick 		siz = fullsiz;
278952196Smckusick 		goto again;
279052196Smckusick 	}
279152196Smckusick 
279268653Smckusick 	dirlen = len = NFSX_V3POSTOPATTR + NFSX_V3COOKIEVERF + 2 * NFSX_UNSIGNED;
279368653Smckusick 	nfsm_reply(cnt);
279468653Smckusick 	nfsm_srvpostop_attr(getret, &at);
279568653Smckusick 	nfsm_build(tl, u_long *, 2 * NFSX_UNSIGNED);
279668653Smckusick 	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 */
280268653Smckusick 	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;
281368653Smckusick 			bzero((caddr_t)nfhp, NFSX_V3FH);
281468653Smckusick 			nfhp->fh_fsid =
281555655Smckusick 				nvp->v_mount->mnt_stat.f_fsid;
281668653Smckusick 			if (VFS_VPTOFH(nvp, &nfhp->fh_fid)) {
281755655Smckusick 				vput(nvp);
281855655Smckusick 				goto invalid;
281955655Smckusick 			}
282068653Smckusick 			if (VOP_GETATTR(nvp, vap, cred, procp)) {
282152196Smckusick 				vput(nvp);
282252196Smckusick 				goto invalid;
282352196Smckusick 			}
282452196Smckusick 			vput(nvp);
282568653Smckusick 
282668653Smckusick 			/*
282768653Smckusick 			 * If either the dircount or maxcount will be
282868653Smckusick 			 * exceeded, get out now. Both of these lengths
282968653Smckusick 			 * are calculated conservatively, including all
283068653Smckusick 			 * XDR overheads.
283168653Smckusick 			 */
283268653Smckusick 			len += (7 * NFSX_UNSIGNED + nlen + rem + NFSX_V3FH +
283368653Smckusick 				NFSX_V3POSTOPATTR);
283468653Smckusick 			dirlen += (6 * NFSX_UNSIGNED + nlen + rem);
283568653Smckusick 			if (len > cnt || dirlen > fullsiz) {
283641899Smckusick 				eofflag = 0;
283738418Smckusick 				break;
283841899Smckusick 			}
283968653Smckusick 
284052441Smckusick 			/*
284152441Smckusick 			 * Build the directory record xdr from
284252441Smckusick 			 * the dirent entry.
284352441Smckusick 			 */
284468653Smckusick 			fp = (struct nfs_fattr *)&fl.fl_fattr;
284568653Smckusick 			nfsm_srvfillattr(vap, fp);
284668653Smckusick 			fl.fl_fhsize = txdr_unsigned(NFSX_V3FH);
284768653Smckusick 			fl.fl_fhok = nfs_true;
284868653Smckusick 			fl.fl_postopok = nfs_true;
284968653Smckusick 			fl.fl_off.nfsuquad[0] = 0;
285068653Smckusick 			fl.fl_off.nfsuquad[1] = txdr_unsigned(*cookiep);
285168653Smckusick 
285238418Smckusick 			nfsm_clget;
285348050Smckusick 			*tl = nfs_true;
285438418Smckusick 			bp += NFSX_UNSIGNED;
285538418Smckusick 			nfsm_clget;
285668653Smckusick 			*tl = 0;
285768653Smckusick 			bp += NFSX_UNSIGNED;
285868653Smckusick 			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;
287068653Smckusick 				if ((bp + xfer) > be)
287168653Smckusick 					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 
288468653Smckusick 			/*
288568653Smckusick 			 * Now copy the flrep structure out.
288668653Smckusick 			 */
288768653Smckusick 			xfer = sizeof (struct flrep);
288868653Smckusick 			cp = (caddr_t)&fl;
288968653Smckusick 			while (xfer > 0) {
289068653Smckusick 				nfsm_clget;
289168653Smckusick 				if ((bp + xfer) > be)
289268653Smckusick 					tsiz = be - bp;
289368653Smckusick 				else
289468653Smckusick 					tsiz = xfer;
289568653Smckusick 				bcopy(cp, bp, tsiz);
289668653Smckusick 				bp += tsiz;
289768653Smckusick 				xfer -= tsiz;
289868653Smckusick 				if (xfer > 0)
289968653Smckusick 					cp += tsiz;
290068653Smckusick 			}
290167363Smckusick 		}
290252196Smckusick invalid:
290338418Smckusick 		cpos += dp->d_reclen;
290452441Smckusick 		dp = (struct dirent *)cpos;
290568653Smckusick 		cookiep++;
290668653Smckusick 		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;
292368653Smckusick 	FREE((caddr_t)cookies, M_TEMP);
292468653Smckusick 	FREE((caddr_t)rbuf, M_TEMP);
292538418Smckusick 	nfsm_srvdone;
292638418Smckusick }
292738418Smckusick 
292838418Smckusick /*
292968653Smckusick  * nfs commit service
293068653Smckusick  */
293168653Smckusick int
nfsrv_commit(nfsd,slp,procp,mrq)293268653Smckusick nfsrv_commit(nfsd, slp, procp, mrq)
293368653Smckusick 	struct nfsrv_descript *nfsd;
293468653Smckusick 	struct nfssvc_sock *slp;
293568653Smckusick 	struct proc *procp;
293668653Smckusick 	struct mbuf **mrq;
293768653Smckusick {
293868653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
293968653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
294068653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
294168653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
294268653Smckusick 	struct vattr bfor, aft;
294368653Smckusick 	struct vnode *vp;
294468653Smckusick 	nfsfh_t nfh;
294568653Smckusick 	fhandle_t *fhp;
294668653Smckusick 	register u_long *tl;
294768653Smckusick 	register long t1;
294868653Smckusick 	caddr_t bpos;
294968653Smckusick 	int error = 0, rdonly, for_ret = 1, aft_ret = 1, cnt, cache;
295068653Smckusick 	char *cp2;
295168653Smckusick 	struct mbuf *mb, *mb2, *mreq;
295268653Smckusick 	u_quad_t frev, off;
295368653Smckusick 
295468653Smckusick #ifndef nolint
295568653Smckusick 	cache = 0;
295668653Smckusick #endif
295768653Smckusick 	fhp = &nfh.fh_generic;
295868653Smckusick 	nfsm_srvmtofh(fhp);
295968653Smckusick 	nfsm_dissect(tl, u_long *, 3 * NFSX_UNSIGNED);
296068653Smckusick 
296168653Smckusick 	/*
296268653Smckusick 	 * XXX At this time VOP_FSYNC() does not accept offset and byte
296368653Smckusick 	 * count parameters, so these arguments are useless (someday maybe).
296468653Smckusick 	 */
296568653Smckusick 	fxdr_hyper(tl, &off);
296668653Smckusick 	tl += 2;
296768653Smckusick 	cnt = fxdr_unsigned(int, *tl);
296868653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
296968653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
297068653Smckusick 		nfsm_reply(2 * NFSX_UNSIGNED);
297168653Smckusick 		nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
297268653Smckusick 		return (0);
297368653Smckusick 	}
297468653Smckusick 	for_ret = VOP_GETATTR(vp, &bfor, cred, procp);
297568653Smckusick 	error = VOP_FSYNC(vp, cred, MNT_WAIT, procp);
297668653Smckusick 	aft_ret = VOP_GETATTR(vp, &aft, cred, procp);
297768653Smckusick 	vput(vp);
297868653Smckusick 	nfsm_reply(NFSX_V3WCCDATA + NFSX_V3WRITEVERF);
297968653Smckusick 	nfsm_srvwcc_data(for_ret, &bfor, aft_ret, &aft);
298068653Smckusick 	if (!error) {
298168653Smckusick 		nfsm_build(tl, u_long *, NFSX_V3WRITEVERF);
298268653Smckusick 		*tl++ = txdr_unsigned(boottime.tv_sec);
298368653Smckusick 		*tl = txdr_unsigned(boottime.tv_usec);
298468653Smckusick 	} else
298568653Smckusick 		return (0);
298668653Smckusick 	nfsm_srvdone;
298768653Smckusick }
298868653Smckusick 
298968653Smckusick /*
299038418Smckusick  * nfs statfs service
299138418Smckusick  */
299268653Smckusick int
nfsrv_statfs(nfsd,slp,procp,mrq)299368653Smckusick nfsrv_statfs(nfsd, slp, procp, mrq)
299468653Smckusick 	struct nfsrv_descript *nfsd;
299568653Smckusick 	struct nfssvc_sock *slp;
299668653Smckusick 	struct proc *procp;
299768653Smckusick 	struct mbuf **mrq;
299838418Smckusick {
299968653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
300068653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
300168653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
300268653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
300338418Smckusick 	register struct statfs *sf;
300468653Smckusick 	register struct nfs_statfs *sfp;
300548050Smckusick 	register u_long *tl;
300639494Smckusick 	register long t1;
300739494Smckusick 	caddr_t bpos;
300868653Smckusick 	int error = 0, rdonly, cache, getret = 1;
300968653Smckusick 	int v3 = (nfsd->nd_flag & ND_NFSV3);
301039494Smckusick 	char *cp2;
301139753Smckusick 	struct mbuf *mb, *mb2, *mreq;
301238418Smckusick 	struct vnode *vp;
301368653Smckusick 	struct vattr at;
301468653Smckusick 	nfsfh_t nfh;
301538418Smckusick 	fhandle_t *fhp;
301638418Smckusick 	struct statfs statfs;
301768653Smckusick 	u_quad_t frev, tval;
301838418Smckusick 
301968653Smckusick #ifndef nolint
302068653Smckusick 	cache = 0;
302168653Smckusick #endif
302238418Smckusick 	fhp = &nfh.fh_generic;
302338418Smckusick 	nfsm_srvmtofh(fhp);
302468653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
302568653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
302668653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
302768653Smckusick 		nfsm_srvpostop_attr(getret, &at);
302868653Smckusick 		return (0);
302968653Smckusick 	}
303038418Smckusick 	sf = &statfs;
303168653Smckusick 	error = VFS_STATFS(vp->v_mount, sf, procp);
303268653Smckusick 	getret = VOP_GETATTR(vp, &at, cred, procp);
303338418Smckusick 	vput(vp);
303468653Smckusick 	nfsm_reply(NFSX_POSTOPATTR(v3) + NFSX_STATFS(v3));
303568653Smckusick 	if (v3)
303668653Smckusick 		nfsm_srvpostop_attr(getret, &at);
303768653Smckusick 	if (error)
303868653Smckusick 		return (0);
303968653Smckusick 	nfsm_build(sfp, struct nfs_statfs *, NFSX_STATFS(v3));
304068653Smckusick 	if (v3) {
304168653Smckusick 		tval = (u_quad_t)sf->f_blocks;
304268653Smckusick 		tval *= (u_quad_t)sf->f_bsize;
304368653Smckusick 		txdr_hyper(&tval, &sfp->sf_tbytes);
304468653Smckusick 		tval = (u_quad_t)sf->f_bfree;
304568653Smckusick 		tval *= (u_quad_t)sf->f_bsize;
304668653Smckusick 		txdr_hyper(&tval, &sfp->sf_fbytes);
304768653Smckusick 		tval = (u_quad_t)sf->f_bavail;
304868653Smckusick 		tval *= (u_quad_t)sf->f_bsize;
304968653Smckusick 		txdr_hyper(&tval, &sfp->sf_abytes);
305068653Smckusick 		sfp->sf_tfiles.nfsuquad[0] = 0;
305168653Smckusick 		sfp->sf_tfiles.nfsuquad[1] = txdr_unsigned(sf->f_files);
305268653Smckusick 		sfp->sf_ffiles.nfsuquad[0] = 0;
305368653Smckusick 		sfp->sf_ffiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
305468653Smckusick 		sfp->sf_afiles.nfsuquad[0] = 0;
305568653Smckusick 		sfp->sf_afiles.nfsuquad[1] = txdr_unsigned(sf->f_ffree);
305668653Smckusick 		sfp->sf_invarsec = 0;
305768653Smckusick 	} else {
305868653Smckusick 		sfp->sf_tsize = txdr_unsigned(NFS_MAXDGRAMDATA);
305968653Smckusick 		sfp->sf_bsize = txdr_unsigned(sf->f_bsize);
306068653Smckusick 		sfp->sf_blocks = txdr_unsigned(sf->f_blocks);
306168653Smckusick 		sfp->sf_bfree = txdr_unsigned(sf->f_bfree);
306268653Smckusick 		sfp->sf_bavail = txdr_unsigned(sf->f_bavail);
306356285Smckusick 	}
306438418Smckusick 	nfsm_srvdone;
306538418Smckusick }
306638418Smckusick 
306738418Smckusick /*
306868653Smckusick  * nfs fsinfo service
306968653Smckusick  */
307068653Smckusick int
nfsrv_fsinfo(nfsd,slp,procp,mrq)307168653Smckusick nfsrv_fsinfo(nfsd, slp, procp, mrq)
307268653Smckusick 	struct nfsrv_descript *nfsd;
307368653Smckusick 	struct nfssvc_sock *slp;
307468653Smckusick 	struct proc *procp;
307568653Smckusick 	struct mbuf **mrq;
307668653Smckusick {
307768653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
307868653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
307968653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
308068653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
308168653Smckusick 	register u_long *tl;
308268653Smckusick 	register struct nfsv3_fsinfo *sip;
308368653Smckusick 	register long t1;
308468653Smckusick 	caddr_t bpos;
308568653Smckusick 	int error = 0, rdonly, cache, getret = 1, pref;
308668653Smckusick 	char *cp2;
308768653Smckusick 	struct mbuf *mb, *mb2, *mreq;
308868653Smckusick 	struct vnode *vp;
308968653Smckusick 	struct vattr at;
309068653Smckusick 	nfsfh_t nfh;
309168653Smckusick 	fhandle_t *fhp;
309268653Smckusick 	u_quad_t frev;
309368653Smckusick 
309468653Smckusick #ifndef nolint
309568653Smckusick 	cache = 0;
309668653Smckusick #endif
309768653Smckusick 	fhp = &nfh.fh_generic;
309868653Smckusick 	nfsm_srvmtofh(fhp);
309968653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
310068653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
310168653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
310268653Smckusick 		nfsm_srvpostop_attr(getret, &at);
310368653Smckusick 		return (0);
310468653Smckusick 	}
310568653Smckusick 	getret = VOP_GETATTR(vp, &at, cred, procp);
310668653Smckusick 	vput(vp);
310768653Smckusick 	nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3FSINFO);
310868653Smckusick 	nfsm_srvpostop_attr(getret, &at);
310968653Smckusick 	nfsm_build(sip, struct nfsv3_fsinfo *, NFSX_V3FSINFO);
311068653Smckusick 
311168653Smckusick 	/*
311268653Smckusick 	 * XXX
311368653Smckusick 	 * There should be file system VFS OP(s) to get this information.
311468653Smckusick 	 * For now, assume ufs.
311568653Smckusick 	 */
311668653Smckusick 	if (slp->ns_so->so_type == SOCK_DGRAM)
311768653Smckusick 		pref = NFS_MAXDGRAMDATA;
311868653Smckusick 	else
311968653Smckusick 		pref = NFS_MAXDATA;
312068653Smckusick 	sip->fs_rtmax = txdr_unsigned(NFS_MAXDATA);
312168653Smckusick 	sip->fs_rtpref = txdr_unsigned(pref);
312268653Smckusick 	sip->fs_rtmult = txdr_unsigned(NFS_FABLKSIZE);
312368653Smckusick 	sip->fs_wtmax = txdr_unsigned(NFS_MAXDATA);
312468653Smckusick 	sip->fs_wtpref = txdr_unsigned(pref);
312568653Smckusick 	sip->fs_wtmult = txdr_unsigned(NFS_FABLKSIZE);
312668653Smckusick 	sip->fs_dtpref = txdr_unsigned(pref);
312768653Smckusick 	sip->fs_maxfilesize.nfsuquad[0] = 0xffffffff;
312868653Smckusick 	sip->fs_maxfilesize.nfsuquad[1] = 0xffffffff;
312968653Smckusick 	sip->fs_timedelta.nfsv3_sec = 0;
313068653Smckusick 	sip->fs_timedelta.nfsv3_nsec = txdr_unsigned(1);
313168653Smckusick 	sip->fs_properties = txdr_unsigned(NFSV3FSINFO_LINK |
313268653Smckusick 		NFSV3FSINFO_SYMLINK | NFSV3FSINFO_HOMOGENEOUS |
313368653Smckusick 		NFSV3FSINFO_CANSETTIME);
313468653Smckusick 	nfsm_srvdone;
313568653Smckusick }
313668653Smckusick 
313768653Smckusick /*
313868653Smckusick  * nfs pathconf service
313968653Smckusick  */
314068653Smckusick int
nfsrv_pathconf(nfsd,slp,procp,mrq)314168653Smckusick nfsrv_pathconf(nfsd, slp, procp, mrq)
314268653Smckusick 	struct nfsrv_descript *nfsd;
314368653Smckusick 	struct nfssvc_sock *slp;
314468653Smckusick 	struct proc *procp;
314568653Smckusick 	struct mbuf **mrq;
314668653Smckusick {
314768653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
314868653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
314968653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
315068653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
315168653Smckusick 	register u_long *tl;
315268653Smckusick 	register struct nfsv3_pathconf *pc;
315368653Smckusick 	register long t1;
315468653Smckusick 	caddr_t bpos;
315568653Smckusick 	int error = 0, rdonly, cache, getret = 1, linkmax, namemax;
315668653Smckusick 	int chownres, notrunc;
315768653Smckusick 	char *cp2;
315868653Smckusick 	struct mbuf *mb, *mb2, *mreq;
315968653Smckusick 	struct vnode *vp;
316068653Smckusick 	struct vattr at;
316168653Smckusick 	nfsfh_t nfh;
316268653Smckusick 	fhandle_t *fhp;
316368653Smckusick 	u_quad_t frev;
316468653Smckusick 
316568653Smckusick #ifndef nolint
316668653Smckusick 	cache = 0;
316768653Smckusick #endif
316868653Smckusick 	fhp = &nfh.fh_generic;
316968653Smckusick 	nfsm_srvmtofh(fhp);
317068653Smckusick 	if (error = nfsrv_fhtovp(fhp, 1, &vp, cred, slp, nam,
317168653Smckusick 		 &rdonly, (nfsd->nd_flag & ND_KERBAUTH))) {
317268653Smckusick 		nfsm_reply(NFSX_UNSIGNED);
317368653Smckusick 		nfsm_srvpostop_attr(getret, &at);
317468653Smckusick 		return (0);
317568653Smckusick 	}
317668653Smckusick 	error = VOP_PATHCONF(vp, _PC_LINK_MAX, &linkmax);
317768653Smckusick 	if (!error)
317868653Smckusick 		error = VOP_PATHCONF(vp, _PC_NAME_MAX, &namemax);
317968653Smckusick 	if (!error)
318068653Smckusick 		error = VOP_PATHCONF(vp, _PC_CHOWN_RESTRICTED, &chownres);
318168653Smckusick 	if (!error)
318268653Smckusick 		error = VOP_PATHCONF(vp, _PC_NO_TRUNC, &notrunc);
318368653Smckusick 	getret = VOP_GETATTR(vp, &at, cred, procp);
318468653Smckusick 	vput(vp);
318568653Smckusick 	nfsm_reply(NFSX_V3POSTOPATTR + NFSX_V3PATHCONF);
318668653Smckusick 	nfsm_srvpostop_attr(getret, &at);
318768653Smckusick 	if (error)
318868653Smckusick 		return (0);
318968653Smckusick 	nfsm_build(pc, struct nfsv3_pathconf *, NFSX_V3PATHCONF);
319068653Smckusick 
319168653Smckusick 	pc->pc_linkmax = txdr_unsigned(linkmax);
319268653Smckusick 	pc->pc_namemax = txdr_unsigned(namemax);
319368653Smckusick 	pc->pc_notrunc = txdr_unsigned(notrunc);
319468653Smckusick 	pc->pc_chownrestricted = txdr_unsigned(chownres);
319568653Smckusick 
319668653Smckusick 	/*
319768653Smckusick 	 * These should probably be supported by VOP_PATHCONF(), but
319868653Smckusick 	 * until msdosfs is exportable (why would you want to?), the
319968653Smckusick 	 * Unix defaults should be ok.
320068653Smckusick 	 */
320168653Smckusick 	pc->pc_caseinsensitive = nfs_false;
320268653Smckusick 	pc->pc_casepreserving = nfs_true;
320368653Smckusick 	nfsm_srvdone;
320468653Smckusick }
320568653Smckusick 
320668653Smckusick /*
320738418Smckusick  * Null operation, used by clients to ping server
320838418Smckusick  */
320939494Smckusick /* ARGSUSED */
321068653Smckusick int
nfsrv_null(nfsd,slp,procp,mrq)321168653Smckusick nfsrv_null(nfsd, slp, procp, mrq)
321268653Smckusick 	struct nfsrv_descript *nfsd;
321368653Smckusick 	struct nfssvc_sock *slp;
321468653Smckusick 	struct proc *procp;
321568653Smckusick 	struct mbuf **mrq;
321638418Smckusick {
321768653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
321868653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
321968653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
322068653Smckusick 	struct ucred *cred = &nfsd->nd_cr;
322139494Smckusick 	caddr_t bpos;
322268653Smckusick 	int error = NFSERR_RETVOID, cache;
322339753Smckusick 	struct mbuf *mb, *mreq;
322452196Smckusick 	u_quad_t frev;
322538418Smckusick 
322668653Smckusick #ifndef nolint
322768653Smckusick 	cache = 0;
322868653Smckusick #endif
322938418Smckusick 	nfsm_reply(0);
323068653Smckusick 	return (0);
323138418Smckusick }
323238418Smckusick 
323338418Smckusick /*
323438418Smckusick  * No operation, used for obsolete procedures
323538418Smckusick  */
323639494Smckusick /* ARGSUSED */
323768653Smckusick int
nfsrv_noop(nfsd,slp,procp,mrq)323868653Smckusick nfsrv_noop(nfsd, slp, procp, mrq)
323968653Smckusick 	struct nfsrv_descript *nfsd;
324068653Smckusick 	struct nfssvc_sock *slp;
324168653Smckusick 	struct proc *procp;
324268653Smckusick 	struct mbuf **mrq;
324338418Smckusick {
324468653Smckusick 	struct mbuf *mrep = nfsd->nd_mrep, *md = nfsd->nd_md;
324568653Smckusick 	struct mbuf *nam = nfsd->nd_nam;
324668653Smckusick 	caddr_t dpos = nfsd->nd_dpos;
324768653Smckusick 	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 
325368653Smckusick #ifndef nolint
325468653Smckusick 	cache = 0;
325568653Smckusick #endif
325652196Smckusick 	if (nfsd->nd_repstat)
325752196Smckusick 		error = nfsd->nd_repstat;
325852196Smckusick 	else
325952196Smckusick 		error = EPROCUNAVAIL;
326038418Smckusick 	nfsm_reply(0);
326168653Smckusick 	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  */
327468653Smckusick int
nfsrv_access(vp,flags,cred,rdonly,p)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