nfs_subs.c revision 8876
11541Srgrimes/*
21541Srgrimes * Copyright (c) 1989, 1993
31541Srgrimes *	The Regents of the University of California.  All rights reserved.
41541Srgrimes *
51541Srgrimes * This code is derived from software contributed to Berkeley by
61541Srgrimes * Rick Macklem at The University of Guelph.
71541Srgrimes *
81541Srgrimes * Redistribution and use in source and binary forms, with or without
91541Srgrimes * modification, are permitted provided that the following conditions
101541Srgrimes * are met:
111541Srgrimes * 1. Redistributions of source code must retain the above copyright
121541Srgrimes *    notice, this list of conditions and the following disclaimer.
131541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141541Srgrimes *    notice, this list of conditions and the following disclaimer in the
151541Srgrimes *    documentation and/or other materials provided with the distribution.
161541Srgrimes * 3. All advertising materials mentioning features or use of this software
171541Srgrimes *    must display the following acknowledgement:
181541Srgrimes *	This product includes software developed by the University of
191541Srgrimes *	California, Berkeley and its contributors.
201541Srgrimes * 4. Neither the name of the University nor the names of its contributors
211541Srgrimes *    may be used to endorse or promote products derived from this software
221541Srgrimes *    without specific prior written permission.
231541Srgrimes *
241541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251541Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261541Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271541Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281541Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291541Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301541Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311541Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321541Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331541Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341541Srgrimes * SUCH DAMAGE.
351541Srgrimes *
361541Srgrimes *	@(#)nfs_subs.c	8.3 (Berkeley) 1/4/94
378876Srgrimes * $Id: nfs_subs.c,v 1.14 1995/05/29 04:01:09 davidg Exp $
381541Srgrimes */
391541Srgrimes
401541Srgrimes/*
411541Srgrimes * These functions support the macros and help fiddle mbuf chains for
421541Srgrimes * the nfs op functions. They do things like create the rpc header and
431541Srgrimes * copy data between mbuf chains and uio lists.
441541Srgrimes */
451541Srgrimes#include <sys/param.h>
461541Srgrimes#include <sys/proc.h>
471541Srgrimes#include <sys/systm.h>
481541Srgrimes#include <sys/kernel.h>
491541Srgrimes#include <sys/mount.h>
501541Srgrimes#include <sys/vnode.h>
511541Srgrimes#include <sys/namei.h>
521541Srgrimes#include <sys/mbuf.h>
531541Srgrimes#include <sys/socket.h>
541541Srgrimes#include <sys/stat.h>
552997Swollman#ifdef VFS_LKM
562997Swollman#include <sys/sysent.h>
572997Swollman#include <sys/syscall.h>
582997Swollman#endif
591541Srgrimes
603305Sphk#include <vm/vm.h>
613305Sphk
621541Srgrimes#include <nfs/rpcv2.h>
631541Srgrimes#include <nfs/nfsv2.h>
641541Srgrimes#include <nfs/nfsnode.h>
651541Srgrimes#include <nfs/nfs.h>
661541Srgrimes#include <nfs/xdr_subs.h>
671541Srgrimes#include <nfs/nfsm_subs.h>
681541Srgrimes#include <nfs/nfsmount.h>
691541Srgrimes#include <nfs/nqnfs.h>
701541Srgrimes#include <nfs/nfsrtt.h>
711541Srgrimes
721541Srgrimes#include <miscfs/specfs/specdev.h>
731541Srgrimes
746420Sphk#include <vm/vnode_pager.h>
756420Sphk
761541Srgrimes#include <netinet/in.h>
771541Srgrimes#ifdef ISO
781541Srgrimes#include <netiso/iso.h>
791541Srgrimes#endif
801541Srgrimes
811541Srgrimes#define TRUE	1
821541Srgrimes#define	FALSE	0
831541Srgrimes
841541Srgrimes/*
851541Srgrimes * Data items converted to xdr at startup, since they are constant
861541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps
871541Srgrimes */
881541Srgrimesu_long nfs_procids[NFS_NPROCS];
891541Srgrimesu_long nfs_xdrneg1;
901541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
911541Srgrimes	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
921541Srgrimes	rpc_auth_kerb;
931541Srgrimesu_long nfs_vers, nfs_prog, nfs_true, nfs_false;
941541Srgrimes
951541Srgrimes/* And other global data */
961541Srgrimesstatic u_long nfs_xid = 0;
971541Srgrimesenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
981541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
991541Srgrimesextern int nqnfs_piggy[NFS_NPROCS];
1001541Srgrimesextern struct nfsrtt nfsrtt;
1011541Srgrimesextern time_t nqnfsstarttime;
1021541Srgrimesextern u_long nqnfs_prog, nqnfs_vers;
1031541Srgrimesextern int nqsrv_clockskew;
1041541Srgrimesextern int nqsrv_writeslack;
1051541Srgrimesextern int nqsrv_maxlease;
1061541Srgrimes
1072997Swollman#ifdef VFS_LKM
1082997Swollmanstruct getfh_args;
1092997Swollmanextern int getfh(struct proc *, struct getfh_args *, int *);
1102997Swollmanstruct nfssvc_args;
1112997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *);
1122997Swollman#endif
1132997Swollman
1143664SphkLIST_HEAD(nfsnodehashhead, nfsnode);
1153664Sphk
1161541Srgrimes/*
1171541Srgrimes * Create the header for an rpc request packet
1181541Srgrimes * The hsiz is the size of the rest of the nfs request header.
1191541Srgrimes * (just used to decide if a cluster is a good idea)
1201541Srgrimes */
1211541Srgrimesstruct mbuf *
1221541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp)
1231541Srgrimes	struct vnode *vp;
1241541Srgrimes	u_long procid;
1251541Srgrimes	int hsiz;
1261541Srgrimes	caddr_t *bposp;
1271541Srgrimes{
1281541Srgrimes	register struct mbuf *mb;
1291541Srgrimes	register u_long *tl;
1301541Srgrimes	register caddr_t bpos;
1311541Srgrimes	struct mbuf *mb2;
1321541Srgrimes	struct nfsmount *nmp;
1331541Srgrimes	int nqflag;
1341541Srgrimes
1351541Srgrimes	MGET(mb, M_WAIT, MT_DATA);
1361541Srgrimes	if (hsiz >= MINCLSIZE)
1371541Srgrimes		MCLGET(mb, M_WAIT);
1381541Srgrimes	mb->m_len = 0;
1391541Srgrimes	bpos = mtod(mb, caddr_t);
1408876Srgrimes
1411541Srgrimes	/*
1421541Srgrimes	 * For NQNFS, add lease request.
1431541Srgrimes	 */
1441541Srgrimes	if (vp) {
1451541Srgrimes		nmp = VFSTONFS(vp->v_mount);
1461541Srgrimes		if (nmp->nm_flag & NFSMNT_NQNFS) {
1471541Srgrimes			nqflag = NQNFS_NEEDLEASE(vp, procid);
1481541Srgrimes			if (nqflag) {
1491541Srgrimes				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1501541Srgrimes				*tl++ = txdr_unsigned(nqflag);
1511541Srgrimes				*tl = txdr_unsigned(nmp->nm_leaseterm);
1521541Srgrimes			} else {
1531541Srgrimes				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1541541Srgrimes				*tl = 0;
1551541Srgrimes			}
1561541Srgrimes		}
1571541Srgrimes	}
1581541Srgrimes	/* Finally, return values */
1591541Srgrimes	*bposp = bpos;
1601541Srgrimes	return (mb);
1611541Srgrimes}
1621541Srgrimes
1631541Srgrimes/*
1641541Srgrimes * Build the RPC header and fill in the authorization info.
1651541Srgrimes * The authorization string argument is only used when the credentials
1661541Srgrimes * come from outside of the kernel.
1671541Srgrimes * Returns the head of the mbuf list.
1681541Srgrimes */
1691541Srgrimesstruct mbuf *
1701541Srgrimesnfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
1711541Srgrimes	mrest_len, mbp, xidp)
1721541Srgrimes	register struct ucred *cr;
1731541Srgrimes	int nqnfs;
1741541Srgrimes	int procid;
1751541Srgrimes	int auth_type;
1761541Srgrimes	int auth_len;
1771541Srgrimes	char *auth_str;
1781541Srgrimes	struct mbuf *mrest;
1791541Srgrimes	int mrest_len;
1801541Srgrimes	struct mbuf **mbp;
1811541Srgrimes	u_long *xidp;
1821541Srgrimes{
1831541Srgrimes	register struct mbuf *mb;
1841541Srgrimes	register u_long *tl;
1851541Srgrimes	register caddr_t bpos;
1861541Srgrimes	register int i;
1871541Srgrimes	struct mbuf *mreq, *mb2;
1881541Srgrimes	int siz, grpsiz, authsiz;
1891541Srgrimes
1901541Srgrimes	authsiz = nfsm_rndup(auth_len);
1911541Srgrimes	if (auth_type == RPCAUTH_NQNFS)
1921541Srgrimes		authsiz += 2 * NFSX_UNSIGNED;
1931541Srgrimes	MGETHDR(mb, M_WAIT, MT_DATA);
1941541Srgrimes	if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
1951541Srgrimes		MCLGET(mb, M_WAIT);
1961541Srgrimes	} else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
1971541Srgrimes		MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
1981541Srgrimes	} else {
1991541Srgrimes		MH_ALIGN(mb, 8*NFSX_UNSIGNED);
2001541Srgrimes	}
2011541Srgrimes	mb->m_len = 0;
2021541Srgrimes	mreq = mb;
2031541Srgrimes	bpos = mtod(mb, caddr_t);
2041541Srgrimes
2051541Srgrimes	/*
2061541Srgrimes	 * First the RPC header.
2071541Srgrimes	 */
2081541Srgrimes	nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
2091541Srgrimes	if (++nfs_xid == 0)
2101541Srgrimes		nfs_xid++;
2111541Srgrimes	*tl++ = *xidp = txdr_unsigned(nfs_xid);
2121541Srgrimes	*tl++ = rpc_call;
2131541Srgrimes	*tl++ = rpc_vers;
2141541Srgrimes	if (nqnfs) {
2151541Srgrimes		*tl++ = txdr_unsigned(NQNFS_PROG);
2161541Srgrimes		*tl++ = txdr_unsigned(NQNFS_VER1);
2171541Srgrimes	} else {
2181541Srgrimes		*tl++ = txdr_unsigned(NFS_PROG);
2191541Srgrimes		*tl++ = txdr_unsigned(NFS_VER2);
2201541Srgrimes	}
2211541Srgrimes	*tl++ = txdr_unsigned(procid);
2221541Srgrimes
2231541Srgrimes	/*
2241541Srgrimes	 * And then the authorization cred.
2251541Srgrimes	 */
2261541Srgrimes	*tl++ = txdr_unsigned(auth_type);
2271541Srgrimes	*tl = txdr_unsigned(authsiz);
2281541Srgrimes	switch (auth_type) {
2291541Srgrimes	case RPCAUTH_UNIX:
2301541Srgrimes		nfsm_build(tl, u_long *, auth_len);
2311541Srgrimes		*tl++ = 0;		/* stamp ?? */
2321541Srgrimes		*tl++ = 0;		/* NULL hostname */
2331541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
2341541Srgrimes		*tl++ = txdr_unsigned(cr->cr_groups[0]);
2351541Srgrimes		grpsiz = (auth_len >> 2) - 5;
2361541Srgrimes		*tl++ = txdr_unsigned(grpsiz);
2371541Srgrimes		for (i = 1; i <= grpsiz; i++)
2381541Srgrimes			*tl++ = txdr_unsigned(cr->cr_groups[i]);
2391541Srgrimes		break;
2401541Srgrimes	case RPCAUTH_NQNFS:
2411541Srgrimes		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
2421541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
2431541Srgrimes		*tl = txdr_unsigned(auth_len);
2441541Srgrimes		siz = auth_len;
2451541Srgrimes		while (siz > 0) {
2461541Srgrimes			if (M_TRAILINGSPACE(mb) == 0) {
2471541Srgrimes				MGET(mb2, M_WAIT, MT_DATA);
2481541Srgrimes				if (siz >= MINCLSIZE)
2491541Srgrimes					MCLGET(mb2, M_WAIT);
2501541Srgrimes				mb->m_next = mb2;
2511541Srgrimes				mb = mb2;
2521541Srgrimes				mb->m_len = 0;
2531541Srgrimes				bpos = mtod(mb, caddr_t);
2541541Srgrimes			}
2551541Srgrimes			i = min(siz, M_TRAILINGSPACE(mb));
2561541Srgrimes			bcopy(auth_str, bpos, i);
2571541Srgrimes			mb->m_len += i;
2581541Srgrimes			auth_str += i;
2591541Srgrimes			bpos += i;
2601541Srgrimes			siz -= i;
2611541Srgrimes		}
2621541Srgrimes		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
2631541Srgrimes			for (i = 0; i < siz; i++)
2641541Srgrimes				*bpos++ = '\0';
2651541Srgrimes			mb->m_len += siz;
2661541Srgrimes		}
2671541Srgrimes		break;
2681541Srgrimes	};
2691541Srgrimes	nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
2701541Srgrimes	*tl++ = txdr_unsigned(RPCAUTH_NULL);
2711541Srgrimes	*tl = 0;
2721541Srgrimes	mb->m_next = mrest;
2731541Srgrimes	mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
2741541Srgrimes	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
2751541Srgrimes	*mbp = mb;
2761541Srgrimes	return (mreq);
2771541Srgrimes}
2781541Srgrimes
2791541Srgrimes/*
2801541Srgrimes * copies mbuf chain to the uio scatter/gather list
2811541Srgrimes */
2821549Srgrimesint
2831541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos)
2841541Srgrimes	struct mbuf **mrep;
2851541Srgrimes	register struct uio *uiop;
2861541Srgrimes	int siz;
2871541Srgrimes	caddr_t *dpos;
2881541Srgrimes{
2891541Srgrimes	register char *mbufcp, *uiocp;
2901541Srgrimes	register int xfer, left, len;
2911541Srgrimes	register struct mbuf *mp;
2921541Srgrimes	long uiosiz, rem;
2931541Srgrimes	int error = 0;
2941541Srgrimes
2951541Srgrimes	mp = *mrep;
2961541Srgrimes	mbufcp = *dpos;
2971541Srgrimes	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
2981541Srgrimes	rem = nfsm_rndup(siz)-siz;
2991541Srgrimes	while (siz > 0) {
3001541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
3011541Srgrimes			return (EFBIG);
3021541Srgrimes		left = uiop->uio_iov->iov_len;
3031541Srgrimes		uiocp = uiop->uio_iov->iov_base;
3041541Srgrimes		if (left > siz)
3051541Srgrimes			left = siz;
3061541Srgrimes		uiosiz = left;
3071541Srgrimes		while (left > 0) {
3081541Srgrimes			while (len == 0) {
3091541Srgrimes				mp = mp->m_next;
3101541Srgrimes				if (mp == NULL)
3111541Srgrimes					return (EBADRPC);
3121541Srgrimes				mbufcp = mtod(mp, caddr_t);
3131541Srgrimes				len = mp->m_len;
3141541Srgrimes			}
3151541Srgrimes			xfer = (left > len) ? len : left;
3161541Srgrimes#ifdef notdef
3171541Srgrimes			/* Not Yet.. */
3181541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
3191541Srgrimes				(*(uiop->uio_iov->iov_op))
3201541Srgrimes				(mbufcp, uiocp, xfer);
3211541Srgrimes			else
3221541Srgrimes#endif
3231541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
3241541Srgrimes				bcopy(mbufcp, uiocp, xfer);
3251541Srgrimes			else
3261541Srgrimes				copyout(mbufcp, uiocp, xfer);
3271541Srgrimes			left -= xfer;
3281541Srgrimes			len -= xfer;
3291541Srgrimes			mbufcp += xfer;
3301541Srgrimes			uiocp += xfer;
3311541Srgrimes			uiop->uio_offset += xfer;
3321541Srgrimes			uiop->uio_resid -= xfer;
3331541Srgrimes		}
3341541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
3351541Srgrimes			uiop->uio_iovcnt--;
3361541Srgrimes			uiop->uio_iov++;
3371541Srgrimes		} else {
3381541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
3391541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
3401541Srgrimes		}
3411541Srgrimes		siz -= uiosiz;
3421541Srgrimes	}
3431541Srgrimes	*dpos = mbufcp;
3441541Srgrimes	*mrep = mp;
3451541Srgrimes	if (rem > 0) {
3461541Srgrimes		if (len < rem)
3471541Srgrimes			error = nfs_adv(mrep, dpos, rem, len);
3481541Srgrimes		else
3491541Srgrimes			*dpos += rem;
3501541Srgrimes	}
3511541Srgrimes	return (error);
3521541Srgrimes}
3531541Srgrimes
3541541Srgrimes/*
3551541Srgrimes * copies a uio scatter/gather list to an mbuf chain...
3561541Srgrimes */
3571549Srgrimesint
3581541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos)
3591541Srgrimes	register struct uio *uiop;
3601541Srgrimes	struct mbuf **mq;
3611541Srgrimes	int siz;
3621541Srgrimes	caddr_t *bpos;
3631541Srgrimes{
3641541Srgrimes	register char *uiocp;
3651541Srgrimes	register struct mbuf *mp, *mp2;
3661541Srgrimes	register int xfer, left, mlen;
3671541Srgrimes	int uiosiz, clflg, rem;
3681541Srgrimes	char *cp;
3691541Srgrimes
3701541Srgrimes	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
3711541Srgrimes		clflg = 1;
3721541Srgrimes	else
3731541Srgrimes		clflg = 0;
3741541Srgrimes	rem = nfsm_rndup(siz)-siz;
3751541Srgrimes	mp = mp2 = *mq;
3761541Srgrimes	while (siz > 0) {
3771541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
3781541Srgrimes			return (EINVAL);
3791541Srgrimes		left = uiop->uio_iov->iov_len;
3801541Srgrimes		uiocp = uiop->uio_iov->iov_base;
3811541Srgrimes		if (left > siz)
3821541Srgrimes			left = siz;
3831541Srgrimes		uiosiz = left;
3841541Srgrimes		while (left > 0) {
3851541Srgrimes			mlen = M_TRAILINGSPACE(mp);
3861541Srgrimes			if (mlen == 0) {
3871541Srgrimes				MGET(mp, M_WAIT, MT_DATA);
3881541Srgrimes				if (clflg)
3891541Srgrimes					MCLGET(mp, M_WAIT);
3901541Srgrimes				mp->m_len = 0;
3911541Srgrimes				mp2->m_next = mp;
3921541Srgrimes				mp2 = mp;
3931541Srgrimes				mlen = M_TRAILINGSPACE(mp);
3941541Srgrimes			}
3951541Srgrimes			xfer = (left > mlen) ? mlen : left;
3961541Srgrimes#ifdef notdef
3971541Srgrimes			/* Not Yet.. */
3981541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
3991541Srgrimes				(*(uiop->uio_iov->iov_op))
4001541Srgrimes				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
4011541Srgrimes			else
4021541Srgrimes#endif
4031541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
4041541Srgrimes				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
4051541Srgrimes			else
4061541Srgrimes				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
4071541Srgrimes			mp->m_len += xfer;
4081541Srgrimes			left -= xfer;
4091541Srgrimes			uiocp += xfer;
4101541Srgrimes			uiop->uio_offset += xfer;
4111541Srgrimes			uiop->uio_resid -= xfer;
4121541Srgrimes		}
4131541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
4141541Srgrimes			uiop->uio_iovcnt--;
4151541Srgrimes			uiop->uio_iov++;
4161541Srgrimes		} else {
4171541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
4181541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
4191541Srgrimes		}
4201541Srgrimes		siz -= uiosiz;
4211541Srgrimes	}
4221541Srgrimes	if (rem > 0) {
4231541Srgrimes		if (rem > M_TRAILINGSPACE(mp)) {
4241541Srgrimes			MGET(mp, M_WAIT, MT_DATA);
4251541Srgrimes			mp->m_len = 0;
4261541Srgrimes			mp2->m_next = mp;
4271541Srgrimes		}
4281541Srgrimes		cp = mtod(mp, caddr_t)+mp->m_len;
4291541Srgrimes		for (left = 0; left < rem; left++)
4301541Srgrimes			*cp++ = '\0';
4311541Srgrimes		mp->m_len += rem;
4321541Srgrimes		*bpos = cp;
4331541Srgrimes	} else
4341541Srgrimes		*bpos = mtod(mp, caddr_t)+mp->m_len;
4351541Srgrimes	*mq = mp;
4361541Srgrimes	return (0);
4371541Srgrimes}
4381541Srgrimes
4391541Srgrimes/*
4401541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous
4411541Srgrimes * pointed to by returned val.
4421541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
4431541Srgrimes * cases. (The macros use the vars. dpos and dpos2)
4441541Srgrimes */
4451549Srgrimesint
4461541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2)
4471541Srgrimes	struct mbuf **mdp;
4481541Srgrimes	caddr_t *dposp;
4491541Srgrimes	int siz;
4501541Srgrimes	int left;
4511541Srgrimes	caddr_t *cp2;
4521541Srgrimes{
4531541Srgrimes	register struct mbuf *mp, *mp2;
4541541Srgrimes	register int siz2, xfer;
4551541Srgrimes	register caddr_t p;
4561541Srgrimes
4571541Srgrimes	mp = *mdp;
4581541Srgrimes	while (left == 0) {
4591541Srgrimes		*mdp = mp = mp->m_next;
4601541Srgrimes		if (mp == NULL)
4611541Srgrimes			return (EBADRPC);
4621541Srgrimes		left = mp->m_len;
4631541Srgrimes		*dposp = mtod(mp, caddr_t);
4641541Srgrimes	}
4651541Srgrimes	if (left >= siz) {
4661541Srgrimes		*cp2 = *dposp;
4671541Srgrimes		*dposp += siz;
4681541Srgrimes	} else if (mp->m_next == NULL) {
4691541Srgrimes		return (EBADRPC);
4701541Srgrimes	} else if (siz > MHLEN) {
4711541Srgrimes		panic("nfs S too big");
4721541Srgrimes	} else {
4731541Srgrimes		MGET(mp2, M_WAIT, MT_DATA);
4741541Srgrimes		mp2->m_next = mp->m_next;
4751541Srgrimes		mp->m_next = mp2;
4761541Srgrimes		mp->m_len -= left;
4771541Srgrimes		mp = mp2;
4781541Srgrimes		*cp2 = p = mtod(mp, caddr_t);
4791541Srgrimes		bcopy(*dposp, p, left);		/* Copy what was left */
4801541Srgrimes		siz2 = siz-left;
4811541Srgrimes		p += left;
4821541Srgrimes		mp2 = mp->m_next;
4831541Srgrimes		/* Loop around copying up the siz2 bytes */
4841541Srgrimes		while (siz2 > 0) {
4851541Srgrimes			if (mp2 == NULL)
4861541Srgrimes				return (EBADRPC);
4871541Srgrimes			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
4881541Srgrimes			if (xfer > 0) {
4891541Srgrimes				bcopy(mtod(mp2, caddr_t), p, xfer);
4901541Srgrimes				NFSMADV(mp2, xfer);
4911541Srgrimes				mp2->m_len -= xfer;
4921541Srgrimes				p += xfer;
4931541Srgrimes				siz2 -= xfer;
4941541Srgrimes			}
4951541Srgrimes			if (siz2 > 0)
4961541Srgrimes				mp2 = mp2->m_next;
4971541Srgrimes		}
4981541Srgrimes		mp->m_len = siz;
4991541Srgrimes		*mdp = mp2;
5001541Srgrimes		*dposp = mtod(mp2, caddr_t);
5011541Srgrimes	}
5021541Srgrimes	return (0);
5031541Srgrimes}
5041541Srgrimes
5051541Srgrimes/*
5061541Srgrimes * Advance the position in the mbuf chain.
5071541Srgrimes */
5081549Srgrimesint
5091541Srgrimesnfs_adv(mdp, dposp, offs, left)
5101541Srgrimes	struct mbuf **mdp;
5111541Srgrimes	caddr_t *dposp;
5121541Srgrimes	int offs;
5131541Srgrimes	int left;
5141541Srgrimes{
5151541Srgrimes	register struct mbuf *m;
5161541Srgrimes	register int s;
5171541Srgrimes
5181541Srgrimes	m = *mdp;
5191541Srgrimes	s = left;
5201541Srgrimes	while (s < offs) {
5211541Srgrimes		offs -= s;
5221541Srgrimes		m = m->m_next;
5231541Srgrimes		if (m == NULL)
5241541Srgrimes			return (EBADRPC);
5251541Srgrimes		s = m->m_len;
5261541Srgrimes	}
5271541Srgrimes	*mdp = m;
5281541Srgrimes	*dposp = mtod(m, caddr_t)+offs;
5291541Srgrimes	return (0);
5301541Srgrimes}
5311541Srgrimes
5321541Srgrimes/*
5331541Srgrimes * Copy a string into mbufs for the hard cases...
5341541Srgrimes */
5351549Srgrimesint
5361541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz)
5371541Srgrimes	struct mbuf **mb;
5381541Srgrimes	char **bpos;
5391541Srgrimes	char *cp;
5401541Srgrimes	long siz;
5411541Srgrimes{
5421549Srgrimes	register struct mbuf *m1 = 0, *m2;
5431541Srgrimes	long left, xfer, len, tlen;
5441541Srgrimes	u_long *tl;
5451541Srgrimes	int putsize;
5461541Srgrimes
5471541Srgrimes	putsize = 1;
5481541Srgrimes	m2 = *mb;
5491541Srgrimes	left = M_TRAILINGSPACE(m2);
5501541Srgrimes	if (left > 0) {
5511541Srgrimes		tl = ((u_long *)(*bpos));
5521541Srgrimes		*tl++ = txdr_unsigned(siz);
5531541Srgrimes		putsize = 0;
5541541Srgrimes		left -= NFSX_UNSIGNED;
5551541Srgrimes		m2->m_len += NFSX_UNSIGNED;
5561541Srgrimes		if (left > 0) {
5571541Srgrimes			bcopy(cp, (caddr_t) tl, left);
5581541Srgrimes			siz -= left;
5591541Srgrimes			cp += left;
5601541Srgrimes			m2->m_len += left;
5611541Srgrimes			left = 0;
5621541Srgrimes		}
5631541Srgrimes	}
5641541Srgrimes	/* Loop around adding mbufs */
5651541Srgrimes	while (siz > 0) {
5661541Srgrimes		MGET(m1, M_WAIT, MT_DATA);
5671541Srgrimes		if (siz > MLEN)
5681541Srgrimes			MCLGET(m1, M_WAIT);
5691541Srgrimes		m1->m_len = NFSMSIZ(m1);
5701541Srgrimes		m2->m_next = m1;
5711541Srgrimes		m2 = m1;
5721541Srgrimes		tl = mtod(m1, u_long *);
5731541Srgrimes		tlen = 0;
5741541Srgrimes		if (putsize) {
5751541Srgrimes			*tl++ = txdr_unsigned(siz);
5761541Srgrimes			m1->m_len -= NFSX_UNSIGNED;
5771541Srgrimes			tlen = NFSX_UNSIGNED;
5781541Srgrimes			putsize = 0;
5791541Srgrimes		}
5801541Srgrimes		if (siz < m1->m_len) {
5811541Srgrimes			len = nfsm_rndup(siz);
5821541Srgrimes			xfer = siz;
5831541Srgrimes			if (xfer < len)
5841541Srgrimes				*(tl+(xfer>>2)) = 0;
5851541Srgrimes		} else {
5861541Srgrimes			xfer = len = m1->m_len;
5871541Srgrimes		}
5881541Srgrimes		bcopy(cp, (caddr_t) tl, xfer);
5891541Srgrimes		m1->m_len = len+tlen;
5901541Srgrimes		siz -= xfer;
5911541Srgrimes		cp += xfer;
5921541Srgrimes	}
5931541Srgrimes	*mb = m1;
5941541Srgrimes	*bpos = mtod(m1, caddr_t)+m1->m_len;
5951541Srgrimes	return (0);
5961541Srgrimes}
5971541Srgrimes
5981541Srgrimes/*
5991541Srgrimes * Called once to initialize data structures...
6001541Srgrimes */
6011549Srgrimesint
6021541Srgrimesnfs_init()
6031541Srgrimes{
6041541Srgrimes	register int i;
6051541Srgrimes
6061541Srgrimes	nfsrtt.pos = 0;
6071541Srgrimes	rpc_vers = txdr_unsigned(RPC_VER2);
6081541Srgrimes	rpc_call = txdr_unsigned(RPC_CALL);
6091541Srgrimes	rpc_reply = txdr_unsigned(RPC_REPLY);
6101541Srgrimes	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
6111541Srgrimes	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
6121541Srgrimes	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
6131541Srgrimes	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
6141541Srgrimes	rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
6151541Srgrimes	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
6161541Srgrimes	rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
6171541Srgrimes	nfs_vers = txdr_unsigned(NFS_VER2);
6181541Srgrimes	nfs_prog = txdr_unsigned(NFS_PROG);
6191541Srgrimes	nfs_true = txdr_unsigned(TRUE);
6201541Srgrimes	nfs_false = txdr_unsigned(FALSE);
6213664Sphk	nfs_xdrneg1 = txdr_unsigned(-1);
6221541Srgrimes	/* Loop thru nfs procids */
6231541Srgrimes	for (i = 0; i < NFS_NPROCS; i++)
6241541Srgrimes		nfs_procids[i] = txdr_unsigned(i);
6251541Srgrimes	/* Ensure async daemons disabled */
6261541Srgrimes	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
6271541Srgrimes		nfs_iodwant[i] = (struct proc *)0;
6281541Srgrimes	TAILQ_INIT(&nfs_bufq);
6291541Srgrimes	nfs_nhinit();			/* Init the nfsnode table */
6301541Srgrimes	nfsrv_init(0);			/* Init server data structures */
6311541Srgrimes	nfsrv_initcache();		/* Init the server request cache */
6321541Srgrimes
6331541Srgrimes	/*
6341541Srgrimes	 * Initialize the nqnfs server stuff.
6351541Srgrimes	 */
6361541Srgrimes	if (nqnfsstarttime == 0) {
6371541Srgrimes		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
6381541Srgrimes			+ nqsrv_clockskew + nqsrv_writeslack;
6391541Srgrimes		NQLOADNOVRAM(nqnfsstarttime);
6401541Srgrimes		nqnfs_prog = txdr_unsigned(NQNFS_PROG);
6411541Srgrimes		nqnfs_vers = txdr_unsigned(NQNFS_VER1);
6423664Sphk		CIRCLEQ_INIT(&nqtimerhead);
6433664Sphk		nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash);
6441541Srgrimes	}
6451541Srgrimes
6461541Srgrimes	/*
6471541Srgrimes	 * Initialize reply list and start timer
6481541Srgrimes	 */
6493664Sphk	TAILQ_INIT(&nfs_reqq);
6503305Sphk	nfs_timer(0);
6511549Srgrimes
6522997Swollman	/*
6532997Swollman	 * Set up lease_check and lease_updatetime so that other parts
6542997Swollman	 * of the system can call us, if we are loadable.
6552997Swollman	 */
6562997Swollman	lease_check = nfs_lease_check;
6572997Swollman	lease_updatetime = nfs_lease_updatetime;
6582997Swollman	vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
6592997Swollman#ifdef VFS_LKM
6602997Swollman	sysent[SYS_nfssvc].sy_narg = 2;
6612997Swollman	sysent[SYS_nfssvc].sy_call = nfssvc;
6622997Swollman	sysent[SYS_getfh].sy_narg = 2;
6632997Swollman	sysent[SYS_getfh].sy_call = getfh;
6642997Swollman#endif
6652997Swollman
6661549Srgrimes	return (0);
6671541Srgrimes}
6681541Srgrimes
6691541Srgrimes/*
6701541Srgrimes * Attribute cache routines.
6711541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes
6721541Srgrimes *	that are on the mbuf list
6731541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns
6741541Srgrimes *	error otherwise
6751541Srgrimes */
6761541Srgrimes
6771541Srgrimes/*
6781541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with
6791541Srgrimes * the values on the mbuf list and
6801541Srgrimes * Iff vap not NULL
6811541Srgrimes *    copy the attributes to *vaper
6821541Srgrimes */
6831549Srgrimesint
6841541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper)
6851541Srgrimes	struct vnode **vpp;
6861541Srgrimes	struct mbuf **mdp;
6871541Srgrimes	caddr_t *dposp;
6881541Srgrimes	struct vattr *vaper;
6891541Srgrimes{
6901541Srgrimes	register struct vnode *vp = *vpp;
6911541Srgrimes	register struct vattr *vap;
6921541Srgrimes	register struct nfsv2_fattr *fp;
6933664Sphk	register struct nfsnode *np;
6943664Sphk	register struct nfsnodehashhead *nhpp;
6951541Srgrimes	register long t1;
6961541Srgrimes	caddr_t dpos, cp2;
6971541Srgrimes	int error = 0, isnq;
6981541Srgrimes	struct mbuf *md;
6991541Srgrimes	enum vtype vtyp;
7001541Srgrimes	u_short vmode;
7011541Srgrimes	long rdev;
7021541Srgrimes	struct timespec mtime;
7031541Srgrimes	struct vnode *nvp;
7041541Srgrimes
7051541Srgrimes	md = *mdp;
7061541Srgrimes	dpos = *dposp;
7071541Srgrimes	t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
7081541Srgrimes	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
7093305Sphk	error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2);
7103305Sphk	if (error)
7111541Srgrimes		return (error);
7121541Srgrimes	fp = (struct nfsv2_fattr *)cp2;
7131541Srgrimes	vtyp = nfstov_type(fp->fa_type);
7141541Srgrimes	vmode = fxdr_unsigned(u_short, fp->fa_mode);
7151541Srgrimes	if (vtyp == VNON || vtyp == VREG)
7161541Srgrimes		vtyp = IFTOVT(vmode);
7171541Srgrimes	if (isnq) {
7181541Srgrimes		rdev = fxdr_unsigned(long, fp->fa_nqrdev);
7191541Srgrimes		fxdr_nqtime(&fp->fa_nqmtime, &mtime);
7201541Srgrimes	} else {
7211541Srgrimes		rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
7221541Srgrimes		fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
7231541Srgrimes	}
7241541Srgrimes	/*
7251541Srgrimes	 * If v_type == VNON it is a new node, so fill in the v_type,
7268876Srgrimes	 * n_mtime fields. Check to see if it represents a special
7271541Srgrimes	 * device, and if so, check for a possible alias. Once the
7281541Srgrimes	 * correct vnode has been obtained, fill in the rest of the
7291541Srgrimes	 * information.
7301541Srgrimes	 */
7311541Srgrimes	np = VTONFS(vp);
7321541Srgrimes	if (vp->v_type == VNON) {
7331541Srgrimes		if (vtyp == VCHR && rdev == 0xffffffff)
7341541Srgrimes			vp->v_type = vtyp = VFIFO;
7351541Srgrimes		else
7361541Srgrimes			vp->v_type = vtyp;
7371541Srgrimes		if (vp->v_type == VFIFO) {
7381541Srgrimes			vp->v_op = fifo_nfsv2nodeop_p;
7391541Srgrimes		}
7401541Srgrimes		if (vp->v_type == VCHR || vp->v_type == VBLK) {
7411541Srgrimes			vp->v_op = spec_nfsv2nodeop_p;
7423305Sphk			nvp = checkalias(vp, (dev_t)rdev, vp->v_mount);
7433305Sphk			if (nvp) {
7441541Srgrimes				/*
7451541Srgrimes				 * Discard unneeded vnode, but save its nfsnode.
7461541Srgrimes				 */
7473664Sphk				LIST_REMOVE(np, n_hash);
7481541Srgrimes				nvp->v_data = vp->v_data;
7491541Srgrimes				vp->v_data = NULL;
7501541Srgrimes				vp->v_op = spec_vnodeop_p;
7511541Srgrimes				vrele(vp);
7521541Srgrimes				vgone(vp);
7531541Srgrimes				/*
7541541Srgrimes				 * Reinitialize aliased node.
7551541Srgrimes				 */
7561541Srgrimes				np->n_vnode = nvp;
7573664Sphk				nhpp = nfs_hash(&np->n_fh);
7583664Sphk				LIST_INSERT_HEAD(nhpp, np, n_hash);
7591541Srgrimes				*vpp = vp = nvp;
7601541Srgrimes			}
7611541Srgrimes		}
7621541Srgrimes		np->n_mtime = mtime.ts_sec;
7631541Srgrimes	}
7641541Srgrimes	vap = &np->n_vattr;
7651541Srgrimes	vap->va_type = vtyp;
7661541Srgrimes	vap->va_mode = (vmode & 07777);
7671541Srgrimes	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
7681541Srgrimes	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
7691541Srgrimes	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
7701541Srgrimes	vap->va_rdev = (dev_t)rdev;
7711541Srgrimes	vap->va_mtime = mtime;
7721541Srgrimes	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
7731541Srgrimes	if (isnq) {
7741541Srgrimes		fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
7751541Srgrimes		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
7761541Srgrimes		fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
7771541Srgrimes		vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
7781541Srgrimes		fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
7791541Srgrimes		vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
7801541Srgrimes		fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
7811541Srgrimes		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
7821541Srgrimes		fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
7831541Srgrimes	} else {
7841541Srgrimes		vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
7851541Srgrimes		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
7861541Srgrimes		vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
7871541Srgrimes		vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
7881541Srgrimes		fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
7891541Srgrimes		vap->va_flags = 0;
7903664Sphk		fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime);
7913664Sphk		vap->va_gen = 0;
7921541Srgrimes		vap->va_filerev = 0;
7931541Srgrimes	}
7941541Srgrimes	if (vap->va_size != np->n_size) {
7951541Srgrimes		if (vap->va_type == VREG) {
7961541Srgrimes			if (np->n_flag & NMODIFIED) {
7971541Srgrimes				if (vap->va_size < np->n_size)
7981541Srgrimes					vap->va_size = np->n_size;
7991541Srgrimes				else
8001541Srgrimes					np->n_size = vap->va_size;
8011541Srgrimes			} else
8021541Srgrimes				np->n_size = vap->va_size;
8031541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
8041541Srgrimes		} else
8051541Srgrimes			np->n_size = vap->va_size;
8061541Srgrimes	}
8071541Srgrimes	np->n_attrstamp = time.tv_sec;
8081541Srgrimes	*dposp = dpos;
8091541Srgrimes	*mdp = md;
8101541Srgrimes	if (vaper != NULL) {
8111541Srgrimes		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
8121541Srgrimes#ifdef notdef
8131541Srgrimes		if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
8141541Srgrimes		if (np->n_size > vap->va_size)
8151541Srgrimes			vaper->va_size = np->n_size;
8161541Srgrimes#endif
8171541Srgrimes		if (np->n_flag & NCHG) {
8181541Srgrimes			if (np->n_flag & NACC) {
8191541Srgrimes				vaper->va_atime.ts_sec = np->n_atim.tv_sec;
8201541Srgrimes				vaper->va_atime.ts_nsec =
8211541Srgrimes				    np->n_atim.tv_usec * 1000;
8221541Srgrimes			}
8231541Srgrimes			if (np->n_flag & NUPD) {
8241541Srgrimes				vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
8251541Srgrimes				vaper->va_mtime.ts_nsec =
8261541Srgrimes				    np->n_mtim.tv_usec * 1000;
8271541Srgrimes			}
8281541Srgrimes		}
8291541Srgrimes	}
8301541Srgrimes	return (0);
8311541Srgrimes}
8321541Srgrimes
8331541Srgrimes/*
8341541Srgrimes * Check the time stamp
8351541Srgrimes * If the cache is valid, copy contents to *vap and return 0
8361541Srgrimes * otherwise return an error
8371541Srgrimes */
8381549Srgrimesint
8391541Srgrimesnfs_getattrcache(vp, vaper)
8401541Srgrimes	register struct vnode *vp;
8411541Srgrimes	struct vattr *vaper;
8421541Srgrimes{
8431541Srgrimes	register struct nfsnode *np = VTONFS(vp);
8441541Srgrimes	register struct vattr *vap;
8451541Srgrimes
8461541Srgrimes	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
8471541Srgrimes		if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
8481541Srgrimes			nfsstats.attrcache_misses++;
8491541Srgrimes			return (ENOENT);
8501541Srgrimes		}
8511541Srgrimes	} else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
8521541Srgrimes		nfsstats.attrcache_misses++;
8531541Srgrimes		return (ENOENT);
8541541Srgrimes	}
8551541Srgrimes	nfsstats.attrcache_hits++;
8561541Srgrimes	vap = &np->n_vattr;
8571541Srgrimes	if (vap->va_size != np->n_size) {
8581541Srgrimes		if (vap->va_type == VREG) {
8591541Srgrimes			if (np->n_flag & NMODIFIED) {
8601541Srgrimes				if (vap->va_size < np->n_size)
8611541Srgrimes					vap->va_size = np->n_size;
8621541Srgrimes				else
8631541Srgrimes					np->n_size = vap->va_size;
8641541Srgrimes			} else
8651541Srgrimes				np->n_size = vap->va_size;
8661541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
8671541Srgrimes		} else
8681541Srgrimes			np->n_size = vap->va_size;
8691541Srgrimes	}
8701541Srgrimes	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
8711541Srgrimes#ifdef notdef
8721541Srgrimes	if ((np->n_flag & NMODIFIED) == 0) {
8731541Srgrimes		np->n_size = vaper->va_size;
8741541Srgrimes		vnode_pager_setsize(vp, (u_long)np->n_size);
8751541Srgrimes	} else if (np->n_size > vaper->va_size)
8761541Srgrimes	if (np->n_size > vaper->va_size)
8771541Srgrimes		vaper->va_size = np->n_size;
8781541Srgrimes#endif
8791541Srgrimes	if (np->n_flag & NCHG) {
8801541Srgrimes		if (np->n_flag & NACC) {
8811541Srgrimes			vaper->va_atime.ts_sec = np->n_atim.tv_sec;
8821541Srgrimes			vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
8831541Srgrimes		}
8841541Srgrimes		if (np->n_flag & NUPD) {
8851541Srgrimes			vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
8861541Srgrimes			vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
8871541Srgrimes		}
8881541Srgrimes	}
8891541Srgrimes	return (0);
8901541Srgrimes}
8911541Srgrimes
8921541Srgrimes/*
8931541Srgrimes * Set up nameidata for a lookup() call and do it
8941541Srgrimes */
8951549Srgrimesint
8961541Srgrimesnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
8971541Srgrimes	register struct nameidata *ndp;
8981541Srgrimes	fhandle_t *fhp;
8991541Srgrimes	int len;
9001541Srgrimes	struct nfssvc_sock *slp;
9011541Srgrimes	struct mbuf *nam;
9021541Srgrimes	struct mbuf **mdp;
9031541Srgrimes	caddr_t *dposp;
9041541Srgrimes	struct proc *p;
9051541Srgrimes{
9061541Srgrimes	register int i, rem;
9071541Srgrimes	register struct mbuf *md;
9081541Srgrimes	register char *fromcp, *tocp;
9091541Srgrimes	struct vnode *dp;
9101541Srgrimes	int error, rdonly;
9111541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
9121541Srgrimes
9131541Srgrimes	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
9141541Srgrimes	/*
9151541Srgrimes	 * Copy the name from the mbuf list to ndp->ni_pnbuf
9161541Srgrimes	 * and set the various ndp fields appropriately.
9171541Srgrimes	 */
9181541Srgrimes	fromcp = *dposp;
9191541Srgrimes	tocp = cnp->cn_pnbuf;
9201541Srgrimes	md = *mdp;
9211541Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
9221541Srgrimes	cnp->cn_hash = 0;
9231541Srgrimes	for (i = 0; i < len; i++) {
9241541Srgrimes		while (rem == 0) {
9251541Srgrimes			md = md->m_next;
9261541Srgrimes			if (md == NULL) {
9271541Srgrimes				error = EBADRPC;
9281541Srgrimes				goto out;
9291541Srgrimes			}
9301541Srgrimes			fromcp = mtod(md, caddr_t);
9311541Srgrimes			rem = md->m_len;
9321541Srgrimes		}
9331541Srgrimes		if (*fromcp == '\0' || *fromcp == '/') {
9341541Srgrimes			error = EINVAL;
9351541Srgrimes			goto out;
9361541Srgrimes		}
9371541Srgrimes		cnp->cn_hash += (unsigned char)*fromcp;
9381541Srgrimes		*tocp++ = *fromcp++;
9391541Srgrimes		rem--;
9401541Srgrimes	}
9411541Srgrimes	*tocp = '\0';
9421541Srgrimes	*mdp = md;
9431541Srgrimes	*dposp = fromcp;
9441541Srgrimes	len = nfsm_rndup(len)-len;
9451541Srgrimes	if (len > 0) {
9461541Srgrimes		if (rem >= len)
9471541Srgrimes			*dposp += len;
9483305Sphk		else {
9493305Sphk			error = nfs_adv(mdp, dposp, len, rem);
9503305Sphk			if (error)
9513305Sphk				goto out;
9523305Sphk		}
9531541Srgrimes	}
9541541Srgrimes	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
9551541Srgrimes	cnp->cn_nameptr = cnp->cn_pnbuf;
9561541Srgrimes	/*
9571541Srgrimes	 * Extract and set starting directory.
9581541Srgrimes	 */
9593305Sphk	error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
9603305Sphk	    nam, &rdonly);
9613305Sphk	if (error)
9621541Srgrimes		goto out;
9631541Srgrimes	if (dp->v_type != VDIR) {
9646417Sdg		nfsrv_vrele(dp);
9651541Srgrimes		error = ENOTDIR;
9661541Srgrimes		goto out;
9671541Srgrimes	}
9681541Srgrimes	ndp->ni_startdir = dp;
9691541Srgrimes	if (rdonly)
9701541Srgrimes		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
9711541Srgrimes	else
9721541Srgrimes		cnp->cn_flags |= NOCROSSMOUNT;
9731541Srgrimes	/*
9741541Srgrimes	 * And call lookup() to do the real work
9751541Srgrimes	 */
9761541Srgrimes	cnp->cn_proc = p;
9773305Sphk	error = lookup(ndp);
9783305Sphk	if (error)
9791541Srgrimes		goto out;
9801541Srgrimes	/*
9811541Srgrimes	 * Check for encountering a symbolic link
9821541Srgrimes	 */
9831541Srgrimes	if (cnp->cn_flags & ISSYMLINK) {
9841541Srgrimes		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
9851541Srgrimes			vput(ndp->ni_dvp);
9861541Srgrimes		else
9871541Srgrimes			vrele(ndp->ni_dvp);
9881541Srgrimes		vput(ndp->ni_vp);
9891541Srgrimes		ndp->ni_vp = NULL;
9901541Srgrimes		error = EINVAL;
9911541Srgrimes		goto out;
9921541Srgrimes	}
9938832Sdg
9948832Sdg	nfsrv_vmio(ndp->ni_vp);
9958832Sdg
9961541Srgrimes	/*
9971541Srgrimes	 * Check for saved name request
9981541Srgrimes	 */
9991541Srgrimes	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
10001541Srgrimes		cnp->cn_flags |= HASBUF;
10011541Srgrimes		return (0);
10021541Srgrimes	}
10031541Srgrimesout:
10041541Srgrimes	FREE(cnp->cn_pnbuf, M_NAMEI);
10051541Srgrimes	return (error);
10061541Srgrimes}
10071541Srgrimes
10081541Srgrimes/*
10091541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long
10101541Srgrimes * boundary and only trims off the back end
10111541Srgrimes */
10121541Srgrimesvoid
10131541Srgrimesnfsm_adj(mp, len, nul)
10141541Srgrimes	struct mbuf *mp;
10151541Srgrimes	register int len;
10161541Srgrimes	int nul;
10171541Srgrimes{
10181541Srgrimes	register struct mbuf *m;
10191541Srgrimes	register int count, i;
10201541Srgrimes	register char *cp;
10211541Srgrimes
10221541Srgrimes	/*
10231541Srgrimes	 * Trim from tail.  Scan the mbuf chain,
10241541Srgrimes	 * calculating its length and finding the last mbuf.
10251541Srgrimes	 * If the adjustment only affects this mbuf, then just
10261541Srgrimes	 * adjust and return.  Otherwise, rescan and truncate
10271541Srgrimes	 * after the remaining size.
10281541Srgrimes	 */
10291541Srgrimes	count = 0;
10301541Srgrimes	m = mp;
10311541Srgrimes	for (;;) {
10321541Srgrimes		count += m->m_len;
10331541Srgrimes		if (m->m_next == (struct mbuf *)0)
10341541Srgrimes			break;
10351541Srgrimes		m = m->m_next;
10361541Srgrimes	}
10371541Srgrimes	if (m->m_len > len) {
10381541Srgrimes		m->m_len -= len;
10391541Srgrimes		if (nul > 0) {
10401541Srgrimes			cp = mtod(m, caddr_t)+m->m_len-nul;
10411541Srgrimes			for (i = 0; i < nul; i++)
10421541Srgrimes				*cp++ = '\0';
10431541Srgrimes		}
10441541Srgrimes		return;
10451541Srgrimes	}
10461541Srgrimes	count -= len;
10471541Srgrimes	if (count < 0)
10481541Srgrimes		count = 0;
10491541Srgrimes	/*
10501541Srgrimes	 * Correct length for chain is "count".
10511541Srgrimes	 * Find the mbuf with last data, adjust its length,
10521541Srgrimes	 * and toss data from remaining mbufs on chain.
10531541Srgrimes	 */
10541541Srgrimes	for (m = mp; m; m = m->m_next) {
10551541Srgrimes		if (m->m_len >= count) {
10561541Srgrimes			m->m_len = count;
10571541Srgrimes			if (nul > 0) {
10581541Srgrimes				cp = mtod(m, caddr_t)+m->m_len-nul;
10591541Srgrimes				for (i = 0; i < nul; i++)
10601541Srgrimes					*cp++ = '\0';
10611541Srgrimes			}
10621541Srgrimes			break;
10631541Srgrimes		}
10641541Srgrimes		count -= m->m_len;
10651541Srgrimes	}
10663305Sphk	for (m = m->m_next;m;m = m->m_next)
10671541Srgrimes		m->m_len = 0;
10681541Srgrimes}
10691541Srgrimes
10701541Srgrimes/*
10711541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
10721541Srgrimes * 	- look up fsid in mount list (if not found ret error)
10731541Srgrimes *	- get vp and export rights by calling VFS_FHTOVP()
10741541Srgrimes *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
10751541Srgrimes *	- if not lockflag unlock it with VOP_UNLOCK()
10761541Srgrimes */
10771549Srgrimesint
10781541Srgrimesnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
10791541Srgrimes	fhandle_t *fhp;
10801541Srgrimes	int lockflag;
10811541Srgrimes	struct vnode **vpp;
10821541Srgrimes	struct ucred *cred;
10831541Srgrimes	struct nfssvc_sock *slp;
10841541Srgrimes	struct mbuf *nam;
10851541Srgrimes	int *rdonlyp;
10861541Srgrimes{
10871541Srgrimes	register struct mount *mp;
10881541Srgrimes	register struct nfsuid *uidp;
10891541Srgrimes	register int i;
10901541Srgrimes	struct ucred *credanon;
10911541Srgrimes	int error, exflags;
10921541Srgrimes
10931541Srgrimes	*vpp = (struct vnode *)0;
10943305Sphk	mp = getvfs(&fhp->fh_fsid);
10953305Sphk	if (!mp)
10961541Srgrimes		return (ESTALE);
10973305Sphk	error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon);
10983305Sphk	if (error)
10991541Srgrimes		return (error);
11001541Srgrimes	/*
11011541Srgrimes	 * Check/setup credentials.
11021541Srgrimes	 */
11031541Srgrimes	if (exflags & MNT_EXKERB) {
11043664Sphk		for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0;
11053664Sphk		    uidp = uidp->nu_hash.le_next) {
11061541Srgrimes			if (uidp->nu_uid == cred->cr_uid)
11071541Srgrimes				break;
11081541Srgrimes		}
11093664Sphk		if (uidp == 0) {
11101541Srgrimes			vput(*vpp);
11111541Srgrimes			return (NQNFS_AUTHERR);
11121541Srgrimes		}
11133664Sphk		cred->cr_uid = uidp->nu_cr.cr_uid;
11143664Sphk		for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
11153664Sphk			cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
11163664Sphk		cred->cr_ngroups = i;
11171541Srgrimes	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
11181541Srgrimes		cred->cr_uid = credanon->cr_uid;
11191541Srgrimes		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
11201541Srgrimes			cred->cr_groups[i] = credanon->cr_groups[i];
11213664Sphk		cred->cr_ngroups = i;
11221541Srgrimes	}
11231541Srgrimes	if (exflags & MNT_EXRDONLY)
11241541Srgrimes		*rdonlyp = 1;
11251541Srgrimes	else
11261541Srgrimes		*rdonlyp = 0;
11277969Sdyson
11287969Sdyson	nfsrv_vmio(*vpp);
11297969Sdyson
11301541Srgrimes	if (!lockflag)
11311541Srgrimes		VOP_UNLOCK(*vpp);
11321541Srgrimes	return (0);
11331541Srgrimes}
11341541Srgrimes
11351541Srgrimes/*
11361541Srgrimes * This function compares two net addresses by family and returns TRUE
11371541Srgrimes * if they are the same host.
11381541Srgrimes * If there is any doubt, return FALSE.
11391541Srgrimes * The AF_INET family is handled as a special case so that address mbufs
11401541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes.
11411541Srgrimes */
11421549Srgrimesint
11431541Srgrimesnetaddr_match(family, haddr, nam)
11441541Srgrimes	int family;
11451541Srgrimes	union nethostaddr *haddr;
11461541Srgrimes	struct mbuf *nam;
11471541Srgrimes{
11481541Srgrimes	register struct sockaddr_in *inetaddr;
11491541Srgrimes
11501541Srgrimes	switch (family) {
11511541Srgrimes	case AF_INET:
11521541Srgrimes		inetaddr = mtod(nam, struct sockaddr_in *);
11531541Srgrimes		if (inetaddr->sin_family == AF_INET &&
11541541Srgrimes		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
11551541Srgrimes			return (1);
11561541Srgrimes		break;
11571541Srgrimes#ifdef ISO
11581541Srgrimes	case AF_ISO:
11591541Srgrimes	    {
11601541Srgrimes		register struct sockaddr_iso *isoaddr1, *isoaddr2;
11611541Srgrimes
11621541Srgrimes		isoaddr1 = mtod(nam, struct sockaddr_iso *);
11631541Srgrimes		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
11641541Srgrimes		if (isoaddr1->siso_family == AF_ISO &&
11651541Srgrimes		    isoaddr1->siso_nlen > 0 &&
11661541Srgrimes		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
11671541Srgrimes		    SAME_ISOADDR(isoaddr1, isoaddr2))
11681541Srgrimes			return (1);
11691541Srgrimes		break;
11701541Srgrimes	    }
11711541Srgrimes#endif	/* ISO */
11721541Srgrimes	default:
11731541Srgrimes		break;
11741541Srgrimes	};
11751541Srgrimes	return (0);
11761541Srgrimes}
11775455Sdg
11785455Sdgint
11795455Sdgnfsrv_vmio( struct vnode *vp) {
11805455Sdg	vm_object_t object;
11815455Sdg	vm_pager_t pager;
11825455Sdg
11835455Sdg	if( (vp == NULL) || (vp->v_type != VREG))
11845455Sdg		return 1;
11855455Sdg
11865455Sdgretry:
11875455Sdg	if( (vp->v_flag & VVMIO) == 0) {
11886420Sphk		pager = (vm_pager_t) vnode_pager_alloc((caddr_t) vp, 0, 0, 0);
11895455Sdg		object = (vm_object_t) vp->v_vmdata;
11905455Sdg		if( object->pager != pager)
11915455Sdg			panic("nfsrv_vmio: pager/object mismatch");
11925455Sdg		(void) vm_object_lookup( pager);
11935455Sdg		pager_cache( object, TRUE);
11945455Sdg		vp->v_flag |= VVMIO;
11955455Sdg	} else {
11965455Sdg		if( (object = (vm_object_t)vp->v_vmdata) &&
11975455Sdg			(object->flags & OBJ_DEAD)) {
11985455Sdg			tsleep( (caddr_t) object, PVM, "nfdead", 0);
11995455Sdg			goto retry;
12005455Sdg		}
12015455Sdg		if( !object)
12025455Sdg			panic("nfsrv_vmio: VMIO object missing");
12035455Sdg		pager = object->pager;
12045455Sdg		if( !pager)
12055455Sdg			panic("nfsrv_vmio: VMIO pager missing");
12065455Sdg		(void) vm_object_lookup( pager);
12075455Sdg	}
12085455Sdg	return 0;
12095455Sdg}
12105455Sdgint
12115455Sdgnfsrv_vput( struct vnode *vp) {
12125455Sdg	if( (vp->v_flag & VVMIO) && vp->v_vmdata) {
12136210Sdg		vput( vp);
12145455Sdg		vm_object_deallocate( (vm_object_t) vp->v_vmdata);
12156210Sdg	} else {
12166210Sdg		vput( vp);
12175455Sdg	}
12185455Sdg	return 0;
12195455Sdg}
12205455Sdgint
12215455Sdgnfsrv_vrele( struct vnode *vp) {
12225455Sdg	if( (vp->v_flag & VVMIO) && vp->v_vmdata) {
12236210Sdg		vrele( vp);
12245455Sdg		vm_object_deallocate( (vm_object_t) vp->v_vmdata);
12256210Sdg	} else {
12266210Sdg		vrele( vp);
12275455Sdg	}
12285455Sdg	return 0;
12295455Sdg}
1230