nfs_subs.c revision 2997
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
372979Swollman * $Id: nfs_subs.c,v 1.3 1994/08/02 07:52:13 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
601541Srgrimes#include <nfs/rpcv2.h>
611541Srgrimes#include <nfs/nfsv2.h>
621541Srgrimes#include <nfs/nfsnode.h>
631541Srgrimes#include <nfs/nfs.h>
641541Srgrimes#include <nfs/xdr_subs.h>
651541Srgrimes#include <nfs/nfsm_subs.h>
661541Srgrimes#include <nfs/nfsmount.h>
671541Srgrimes#include <nfs/nqnfs.h>
681541Srgrimes#include <nfs/nfsrtt.h>
691541Srgrimes
701541Srgrimes#include <miscfs/specfs/specdev.h>
711541Srgrimes
721541Srgrimes#include <netinet/in.h>
731541Srgrimes#ifdef ISO
741541Srgrimes#include <netiso/iso.h>
751541Srgrimes#endif
761541Srgrimes
771541Srgrimes#define TRUE	1
781541Srgrimes#define	FALSE	0
791541Srgrimes
801541Srgrimes/*
811541Srgrimes * Data items converted to xdr at startup, since they are constant
821541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps
831541Srgrimes */
841541Srgrimesu_long nfs_procids[NFS_NPROCS];
851541Srgrimesu_long nfs_xdrneg1;
861541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr,
871541Srgrimes	rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred,
881541Srgrimes	rpc_auth_kerb;
891541Srgrimesu_long nfs_vers, nfs_prog, nfs_true, nfs_false;
901541Srgrimes
911541Srgrimes/* And other global data */
921541Srgrimesstatic u_long nfs_xid = 0;
931541Srgrimesenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
941541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
951541Srgrimesextern struct nfsreq nfsreqh;
961541Srgrimesextern int nqnfs_piggy[NFS_NPROCS];
971541Srgrimesextern struct nfsrtt nfsrtt;
981541Srgrimesextern time_t nqnfsstarttime;
991541Srgrimesextern u_long nqnfs_prog, nqnfs_vers;
1001541Srgrimesextern int nqsrv_clockskew;
1011541Srgrimesextern int nqsrv_writeslack;
1021541Srgrimesextern int nqsrv_maxlease;
1031541Srgrimes
1042997Swollman#ifdef VFS_LKM
1052997Swollmanstruct getfh_args;
1062997Swollmanextern int getfh(struct proc *, struct getfh_args *, int *);
1072997Swollmanstruct nfssvc_args;
1082997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *);
1092997Swollman#endif
1102997Swollman
1111541Srgrimes/*
1121541Srgrimes * Create the header for an rpc request packet
1131541Srgrimes * The hsiz is the size of the rest of the nfs request header.
1141541Srgrimes * (just used to decide if a cluster is a good idea)
1151541Srgrimes */
1161541Srgrimesstruct mbuf *
1171541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp)
1181541Srgrimes	struct vnode *vp;
1191541Srgrimes	u_long procid;
1201541Srgrimes	int hsiz;
1211541Srgrimes	caddr_t *bposp;
1221541Srgrimes{
1231541Srgrimes	register struct mbuf *mb;
1241541Srgrimes	register u_long *tl;
1251541Srgrimes	register caddr_t bpos;
1261541Srgrimes	struct mbuf *mb2;
1271541Srgrimes	struct nfsmount *nmp;
1281541Srgrimes	int nqflag;
1291541Srgrimes
1301541Srgrimes	MGET(mb, M_WAIT, MT_DATA);
1311541Srgrimes	if (hsiz >= MINCLSIZE)
1321541Srgrimes		MCLGET(mb, M_WAIT);
1331541Srgrimes	mb->m_len = 0;
1341541Srgrimes	bpos = mtod(mb, caddr_t);
1351541Srgrimes
1361541Srgrimes	/*
1371541Srgrimes	 * For NQNFS, add lease request.
1381541Srgrimes	 */
1391541Srgrimes	if (vp) {
1401541Srgrimes		nmp = VFSTONFS(vp->v_mount);
1411541Srgrimes		if (nmp->nm_flag & NFSMNT_NQNFS) {
1421541Srgrimes			nqflag = NQNFS_NEEDLEASE(vp, procid);
1431541Srgrimes			if (nqflag) {
1441541Srgrimes				nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
1451541Srgrimes				*tl++ = txdr_unsigned(nqflag);
1461541Srgrimes				*tl = txdr_unsigned(nmp->nm_leaseterm);
1471541Srgrimes			} else {
1481541Srgrimes				nfsm_build(tl, u_long *, NFSX_UNSIGNED);
1491541Srgrimes				*tl = 0;
1501541Srgrimes			}
1511541Srgrimes		}
1521541Srgrimes	}
1531541Srgrimes	/* Finally, return values */
1541541Srgrimes	*bposp = bpos;
1551541Srgrimes	return (mb);
1561541Srgrimes}
1571541Srgrimes
1581541Srgrimes/*
1591541Srgrimes * Build the RPC header and fill in the authorization info.
1601541Srgrimes * The authorization string argument is only used when the credentials
1611541Srgrimes * come from outside of the kernel.
1621541Srgrimes * Returns the head of the mbuf list.
1631541Srgrimes */
1641541Srgrimesstruct mbuf *
1651541Srgrimesnfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest,
1661541Srgrimes	mrest_len, mbp, xidp)
1671541Srgrimes	register struct ucred *cr;
1681541Srgrimes	int nqnfs;
1691541Srgrimes	int procid;
1701541Srgrimes	int auth_type;
1711541Srgrimes	int auth_len;
1721541Srgrimes	char *auth_str;
1731541Srgrimes	struct mbuf *mrest;
1741541Srgrimes	int mrest_len;
1751541Srgrimes	struct mbuf **mbp;
1761541Srgrimes	u_long *xidp;
1771541Srgrimes{
1781541Srgrimes	register struct mbuf *mb;
1791541Srgrimes	register u_long *tl;
1801541Srgrimes	register caddr_t bpos;
1811541Srgrimes	register int i;
1821541Srgrimes	struct mbuf *mreq, *mb2;
1831541Srgrimes	int siz, grpsiz, authsiz;
1841541Srgrimes
1851541Srgrimes	authsiz = nfsm_rndup(auth_len);
1861541Srgrimes	if (auth_type == RPCAUTH_NQNFS)
1871541Srgrimes		authsiz += 2 * NFSX_UNSIGNED;
1881541Srgrimes	MGETHDR(mb, M_WAIT, MT_DATA);
1891541Srgrimes	if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) {
1901541Srgrimes		MCLGET(mb, M_WAIT);
1911541Srgrimes	} else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) {
1921541Srgrimes		MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED);
1931541Srgrimes	} else {
1941541Srgrimes		MH_ALIGN(mb, 8*NFSX_UNSIGNED);
1951541Srgrimes	}
1961541Srgrimes	mb->m_len = 0;
1971541Srgrimes	mreq = mb;
1981541Srgrimes	bpos = mtod(mb, caddr_t);
1991541Srgrimes
2001541Srgrimes	/*
2011541Srgrimes	 * First the RPC header.
2021541Srgrimes	 */
2031541Srgrimes	nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED);
2041541Srgrimes	if (++nfs_xid == 0)
2051541Srgrimes		nfs_xid++;
2061541Srgrimes	*tl++ = *xidp = txdr_unsigned(nfs_xid);
2071541Srgrimes	*tl++ = rpc_call;
2081541Srgrimes	*tl++ = rpc_vers;
2091541Srgrimes	if (nqnfs) {
2101541Srgrimes		*tl++ = txdr_unsigned(NQNFS_PROG);
2111541Srgrimes		*tl++ = txdr_unsigned(NQNFS_VER1);
2121541Srgrimes	} else {
2131541Srgrimes		*tl++ = txdr_unsigned(NFS_PROG);
2141541Srgrimes		*tl++ = txdr_unsigned(NFS_VER2);
2151541Srgrimes	}
2161541Srgrimes	*tl++ = txdr_unsigned(procid);
2171541Srgrimes
2181541Srgrimes	/*
2191541Srgrimes	 * And then the authorization cred.
2201541Srgrimes	 */
2211541Srgrimes	*tl++ = txdr_unsigned(auth_type);
2221541Srgrimes	*tl = txdr_unsigned(authsiz);
2231541Srgrimes	switch (auth_type) {
2241541Srgrimes	case RPCAUTH_UNIX:
2251541Srgrimes		nfsm_build(tl, u_long *, auth_len);
2261541Srgrimes		*tl++ = 0;		/* stamp ?? */
2271541Srgrimes		*tl++ = 0;		/* NULL hostname */
2281541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
2291541Srgrimes		*tl++ = txdr_unsigned(cr->cr_groups[0]);
2301541Srgrimes		grpsiz = (auth_len >> 2) - 5;
2311541Srgrimes		*tl++ = txdr_unsigned(grpsiz);
2321541Srgrimes		for (i = 1; i <= grpsiz; i++)
2331541Srgrimes			*tl++ = txdr_unsigned(cr->cr_groups[i]);
2341541Srgrimes		break;
2351541Srgrimes	case RPCAUTH_NQNFS:
2361541Srgrimes		nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
2371541Srgrimes		*tl++ = txdr_unsigned(cr->cr_uid);
2381541Srgrimes		*tl = txdr_unsigned(auth_len);
2391541Srgrimes		siz = auth_len;
2401541Srgrimes		while (siz > 0) {
2411541Srgrimes			if (M_TRAILINGSPACE(mb) == 0) {
2421541Srgrimes				MGET(mb2, M_WAIT, MT_DATA);
2431541Srgrimes				if (siz >= MINCLSIZE)
2441541Srgrimes					MCLGET(mb2, M_WAIT);
2451541Srgrimes				mb->m_next = mb2;
2461541Srgrimes				mb = mb2;
2471541Srgrimes				mb->m_len = 0;
2481541Srgrimes				bpos = mtod(mb, caddr_t);
2491541Srgrimes			}
2501541Srgrimes			i = min(siz, M_TRAILINGSPACE(mb));
2511541Srgrimes			bcopy(auth_str, bpos, i);
2521541Srgrimes			mb->m_len += i;
2531541Srgrimes			auth_str += i;
2541541Srgrimes			bpos += i;
2551541Srgrimes			siz -= i;
2561541Srgrimes		}
2571541Srgrimes		if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) {
2581541Srgrimes			for (i = 0; i < siz; i++)
2591541Srgrimes				*bpos++ = '\0';
2601541Srgrimes			mb->m_len += siz;
2611541Srgrimes		}
2621541Srgrimes		break;
2631541Srgrimes	};
2641541Srgrimes	nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED);
2651541Srgrimes	*tl++ = txdr_unsigned(RPCAUTH_NULL);
2661541Srgrimes	*tl = 0;
2671541Srgrimes	mb->m_next = mrest;
2681541Srgrimes	mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len;
2691541Srgrimes	mreq->m_pkthdr.rcvif = (struct ifnet *)0;
2701541Srgrimes	*mbp = mb;
2711541Srgrimes	return (mreq);
2721541Srgrimes}
2731541Srgrimes
2741541Srgrimes/*
2751541Srgrimes * copies mbuf chain to the uio scatter/gather list
2761541Srgrimes */
2771549Srgrimesint
2781541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos)
2791541Srgrimes	struct mbuf **mrep;
2801541Srgrimes	register struct uio *uiop;
2811541Srgrimes	int siz;
2821541Srgrimes	caddr_t *dpos;
2831541Srgrimes{
2841541Srgrimes	register char *mbufcp, *uiocp;
2851541Srgrimes	register int xfer, left, len;
2861541Srgrimes	register struct mbuf *mp;
2871541Srgrimes	long uiosiz, rem;
2881541Srgrimes	int error = 0;
2891541Srgrimes
2901541Srgrimes	mp = *mrep;
2911541Srgrimes	mbufcp = *dpos;
2921541Srgrimes	len = mtod(mp, caddr_t)+mp->m_len-mbufcp;
2931541Srgrimes	rem = nfsm_rndup(siz)-siz;
2941541Srgrimes	while (siz > 0) {
2951541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
2961541Srgrimes			return (EFBIG);
2971541Srgrimes		left = uiop->uio_iov->iov_len;
2981541Srgrimes		uiocp = uiop->uio_iov->iov_base;
2991541Srgrimes		if (left > siz)
3001541Srgrimes			left = siz;
3011541Srgrimes		uiosiz = left;
3021541Srgrimes		while (left > 0) {
3031541Srgrimes			while (len == 0) {
3041541Srgrimes				mp = mp->m_next;
3051541Srgrimes				if (mp == NULL)
3061541Srgrimes					return (EBADRPC);
3071541Srgrimes				mbufcp = mtod(mp, caddr_t);
3081541Srgrimes				len = mp->m_len;
3091541Srgrimes			}
3101541Srgrimes			xfer = (left > len) ? len : left;
3111541Srgrimes#ifdef notdef
3121541Srgrimes			/* Not Yet.. */
3131541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
3141541Srgrimes				(*(uiop->uio_iov->iov_op))
3151541Srgrimes				(mbufcp, uiocp, xfer);
3161541Srgrimes			else
3171541Srgrimes#endif
3181541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
3191541Srgrimes				bcopy(mbufcp, uiocp, xfer);
3201541Srgrimes			else
3211541Srgrimes				copyout(mbufcp, uiocp, xfer);
3221541Srgrimes			left -= xfer;
3231541Srgrimes			len -= xfer;
3241541Srgrimes			mbufcp += xfer;
3251541Srgrimes			uiocp += xfer;
3261541Srgrimes			uiop->uio_offset += xfer;
3271541Srgrimes			uiop->uio_resid -= xfer;
3281541Srgrimes		}
3291541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
3301541Srgrimes			uiop->uio_iovcnt--;
3311541Srgrimes			uiop->uio_iov++;
3321541Srgrimes		} else {
3331541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
3341541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
3351541Srgrimes		}
3361541Srgrimes		siz -= uiosiz;
3371541Srgrimes	}
3381541Srgrimes	*dpos = mbufcp;
3391541Srgrimes	*mrep = mp;
3401541Srgrimes	if (rem > 0) {
3411541Srgrimes		if (len < rem)
3421541Srgrimes			error = nfs_adv(mrep, dpos, rem, len);
3431541Srgrimes		else
3441541Srgrimes			*dpos += rem;
3451541Srgrimes	}
3461541Srgrimes	return (error);
3471541Srgrimes}
3481541Srgrimes
3491541Srgrimes/*
3501541Srgrimes * copies a uio scatter/gather list to an mbuf chain...
3511541Srgrimes */
3521549Srgrimesint
3531541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos)
3541541Srgrimes	register struct uio *uiop;
3551541Srgrimes	struct mbuf **mq;
3561541Srgrimes	int siz;
3571541Srgrimes	caddr_t *bpos;
3581541Srgrimes{
3591541Srgrimes	register char *uiocp;
3601541Srgrimes	register struct mbuf *mp, *mp2;
3611541Srgrimes	register int xfer, left, mlen;
3621541Srgrimes	int uiosiz, clflg, rem;
3631541Srgrimes	char *cp;
3641541Srgrimes
3651541Srgrimes	if (siz > MLEN)		/* or should it >= MCLBYTES ?? */
3661541Srgrimes		clflg = 1;
3671541Srgrimes	else
3681541Srgrimes		clflg = 0;
3691541Srgrimes	rem = nfsm_rndup(siz)-siz;
3701541Srgrimes	mp = mp2 = *mq;
3711541Srgrimes	while (siz > 0) {
3721541Srgrimes		if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
3731541Srgrimes			return (EINVAL);
3741541Srgrimes		left = uiop->uio_iov->iov_len;
3751541Srgrimes		uiocp = uiop->uio_iov->iov_base;
3761541Srgrimes		if (left > siz)
3771541Srgrimes			left = siz;
3781541Srgrimes		uiosiz = left;
3791541Srgrimes		while (left > 0) {
3801541Srgrimes			mlen = M_TRAILINGSPACE(mp);
3811541Srgrimes			if (mlen == 0) {
3821541Srgrimes				MGET(mp, M_WAIT, MT_DATA);
3831541Srgrimes				if (clflg)
3841541Srgrimes					MCLGET(mp, M_WAIT);
3851541Srgrimes				mp->m_len = 0;
3861541Srgrimes				mp2->m_next = mp;
3871541Srgrimes				mp2 = mp;
3881541Srgrimes				mlen = M_TRAILINGSPACE(mp);
3891541Srgrimes			}
3901541Srgrimes			xfer = (left > mlen) ? mlen : left;
3911541Srgrimes#ifdef notdef
3921541Srgrimes			/* Not Yet.. */
3931541Srgrimes			if (uiop->uio_iov->iov_op != NULL)
3941541Srgrimes				(*(uiop->uio_iov->iov_op))
3951541Srgrimes				(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
3961541Srgrimes			else
3971541Srgrimes#endif
3981541Srgrimes			if (uiop->uio_segflg == UIO_SYSSPACE)
3991541Srgrimes				bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
4001541Srgrimes			else
4011541Srgrimes				copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer);
4021541Srgrimes			mp->m_len += xfer;
4031541Srgrimes			left -= xfer;
4041541Srgrimes			uiocp += xfer;
4051541Srgrimes			uiop->uio_offset += xfer;
4061541Srgrimes			uiop->uio_resid -= xfer;
4071541Srgrimes		}
4081541Srgrimes		if (uiop->uio_iov->iov_len <= siz) {
4091541Srgrimes			uiop->uio_iovcnt--;
4101541Srgrimes			uiop->uio_iov++;
4111541Srgrimes		} else {
4121541Srgrimes			uiop->uio_iov->iov_base += uiosiz;
4131541Srgrimes			uiop->uio_iov->iov_len -= uiosiz;
4141541Srgrimes		}
4151541Srgrimes		siz -= uiosiz;
4161541Srgrimes	}
4171541Srgrimes	if (rem > 0) {
4181541Srgrimes		if (rem > M_TRAILINGSPACE(mp)) {
4191541Srgrimes			MGET(mp, M_WAIT, MT_DATA);
4201541Srgrimes			mp->m_len = 0;
4211541Srgrimes			mp2->m_next = mp;
4221541Srgrimes		}
4231541Srgrimes		cp = mtod(mp, caddr_t)+mp->m_len;
4241541Srgrimes		for (left = 0; left < rem; left++)
4251541Srgrimes			*cp++ = '\0';
4261541Srgrimes		mp->m_len += rem;
4271541Srgrimes		*bpos = cp;
4281541Srgrimes	} else
4291541Srgrimes		*bpos = mtod(mp, caddr_t)+mp->m_len;
4301541Srgrimes	*mq = mp;
4311541Srgrimes	return (0);
4321541Srgrimes}
4331541Srgrimes
4341541Srgrimes/*
4351541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous
4361541Srgrimes * pointed to by returned val.
4371541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough
4381541Srgrimes * cases. (The macros use the vars. dpos and dpos2)
4391541Srgrimes */
4401549Srgrimesint
4411541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2)
4421541Srgrimes	struct mbuf **mdp;
4431541Srgrimes	caddr_t *dposp;
4441541Srgrimes	int siz;
4451541Srgrimes	int left;
4461541Srgrimes	caddr_t *cp2;
4471541Srgrimes{
4481541Srgrimes	register struct mbuf *mp, *mp2;
4491541Srgrimes	register int siz2, xfer;
4501541Srgrimes	register caddr_t p;
4511541Srgrimes
4521541Srgrimes	mp = *mdp;
4531541Srgrimes	while (left == 0) {
4541541Srgrimes		*mdp = mp = mp->m_next;
4551541Srgrimes		if (mp == NULL)
4561541Srgrimes			return (EBADRPC);
4571541Srgrimes		left = mp->m_len;
4581541Srgrimes		*dposp = mtod(mp, caddr_t);
4591541Srgrimes	}
4601541Srgrimes	if (left >= siz) {
4611541Srgrimes		*cp2 = *dposp;
4621541Srgrimes		*dposp += siz;
4631541Srgrimes	} else if (mp->m_next == NULL) {
4641541Srgrimes		return (EBADRPC);
4651541Srgrimes	} else if (siz > MHLEN) {
4661541Srgrimes		panic("nfs S too big");
4671541Srgrimes	} else {
4681541Srgrimes		MGET(mp2, M_WAIT, MT_DATA);
4691541Srgrimes		mp2->m_next = mp->m_next;
4701541Srgrimes		mp->m_next = mp2;
4711541Srgrimes		mp->m_len -= left;
4721541Srgrimes		mp = mp2;
4731541Srgrimes		*cp2 = p = mtod(mp, caddr_t);
4741541Srgrimes		bcopy(*dposp, p, left);		/* Copy what was left */
4751541Srgrimes		siz2 = siz-left;
4761541Srgrimes		p += left;
4771541Srgrimes		mp2 = mp->m_next;
4781541Srgrimes		/* Loop around copying up the siz2 bytes */
4791541Srgrimes		while (siz2 > 0) {
4801541Srgrimes			if (mp2 == NULL)
4811541Srgrimes				return (EBADRPC);
4821541Srgrimes			xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
4831541Srgrimes			if (xfer > 0) {
4841541Srgrimes				bcopy(mtod(mp2, caddr_t), p, xfer);
4851541Srgrimes				NFSMADV(mp2, xfer);
4861541Srgrimes				mp2->m_len -= xfer;
4871541Srgrimes				p += xfer;
4881541Srgrimes				siz2 -= xfer;
4891541Srgrimes			}
4901541Srgrimes			if (siz2 > 0)
4911541Srgrimes				mp2 = mp2->m_next;
4921541Srgrimes		}
4931541Srgrimes		mp->m_len = siz;
4941541Srgrimes		*mdp = mp2;
4951541Srgrimes		*dposp = mtod(mp2, caddr_t);
4961541Srgrimes	}
4971541Srgrimes	return (0);
4981541Srgrimes}
4991541Srgrimes
5001541Srgrimes/*
5011541Srgrimes * Advance the position in the mbuf chain.
5021541Srgrimes */
5031549Srgrimesint
5041541Srgrimesnfs_adv(mdp, dposp, offs, left)
5051541Srgrimes	struct mbuf **mdp;
5061541Srgrimes	caddr_t *dposp;
5071541Srgrimes	int offs;
5081541Srgrimes	int left;
5091541Srgrimes{
5101541Srgrimes	register struct mbuf *m;
5111541Srgrimes	register int s;
5121541Srgrimes
5131541Srgrimes	m = *mdp;
5141541Srgrimes	s = left;
5151541Srgrimes	while (s < offs) {
5161541Srgrimes		offs -= s;
5171541Srgrimes		m = m->m_next;
5181541Srgrimes		if (m == NULL)
5191541Srgrimes			return (EBADRPC);
5201541Srgrimes		s = m->m_len;
5211541Srgrimes	}
5221541Srgrimes	*mdp = m;
5231541Srgrimes	*dposp = mtod(m, caddr_t)+offs;
5241541Srgrimes	return (0);
5251541Srgrimes}
5261541Srgrimes
5271541Srgrimes/*
5281541Srgrimes * Copy a string into mbufs for the hard cases...
5291541Srgrimes */
5301549Srgrimesint
5311541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz)
5321541Srgrimes	struct mbuf **mb;
5331541Srgrimes	char **bpos;
5341541Srgrimes	char *cp;
5351541Srgrimes	long siz;
5361541Srgrimes{
5371549Srgrimes	register struct mbuf *m1 = 0, *m2;
5381541Srgrimes	long left, xfer, len, tlen;
5391541Srgrimes	u_long *tl;
5401541Srgrimes	int putsize;
5411541Srgrimes
5421541Srgrimes	putsize = 1;
5431541Srgrimes	m2 = *mb;
5441541Srgrimes	left = M_TRAILINGSPACE(m2);
5451541Srgrimes	if (left > 0) {
5461541Srgrimes		tl = ((u_long *)(*bpos));
5471541Srgrimes		*tl++ = txdr_unsigned(siz);
5481541Srgrimes		putsize = 0;
5491541Srgrimes		left -= NFSX_UNSIGNED;
5501541Srgrimes		m2->m_len += NFSX_UNSIGNED;
5511541Srgrimes		if (left > 0) {
5521541Srgrimes			bcopy(cp, (caddr_t) tl, left);
5531541Srgrimes			siz -= left;
5541541Srgrimes			cp += left;
5551541Srgrimes			m2->m_len += left;
5561541Srgrimes			left = 0;
5571541Srgrimes		}
5581541Srgrimes	}
5591541Srgrimes	/* Loop around adding mbufs */
5601541Srgrimes	while (siz > 0) {
5611541Srgrimes		MGET(m1, M_WAIT, MT_DATA);
5621541Srgrimes		if (siz > MLEN)
5631541Srgrimes			MCLGET(m1, M_WAIT);
5641541Srgrimes		m1->m_len = NFSMSIZ(m1);
5651541Srgrimes		m2->m_next = m1;
5661541Srgrimes		m2 = m1;
5671541Srgrimes		tl = mtod(m1, u_long *);
5681541Srgrimes		tlen = 0;
5691541Srgrimes		if (putsize) {
5701541Srgrimes			*tl++ = txdr_unsigned(siz);
5711541Srgrimes			m1->m_len -= NFSX_UNSIGNED;
5721541Srgrimes			tlen = NFSX_UNSIGNED;
5731541Srgrimes			putsize = 0;
5741541Srgrimes		}
5751541Srgrimes		if (siz < m1->m_len) {
5761541Srgrimes			len = nfsm_rndup(siz);
5771541Srgrimes			xfer = siz;
5781541Srgrimes			if (xfer < len)
5791541Srgrimes				*(tl+(xfer>>2)) = 0;
5801541Srgrimes		} else {
5811541Srgrimes			xfer = len = m1->m_len;
5821541Srgrimes		}
5831541Srgrimes		bcopy(cp, (caddr_t) tl, xfer);
5841541Srgrimes		m1->m_len = len+tlen;
5851541Srgrimes		siz -= xfer;
5861541Srgrimes		cp += xfer;
5871541Srgrimes	}
5881541Srgrimes	*mb = m1;
5891541Srgrimes	*bpos = mtod(m1, caddr_t)+m1->m_len;
5901541Srgrimes	return (0);
5911541Srgrimes}
5921541Srgrimes
5931541Srgrimes/*
5941541Srgrimes * Called once to initialize data structures...
5951541Srgrimes */
5961549Srgrimesint
5971541Srgrimesnfs_init()
5981541Srgrimes{
5991541Srgrimes	register int i;
6001541Srgrimes
6011541Srgrimes	nfsrtt.pos = 0;
6021541Srgrimes	rpc_vers = txdr_unsigned(RPC_VER2);
6031541Srgrimes	rpc_call = txdr_unsigned(RPC_CALL);
6041541Srgrimes	rpc_reply = txdr_unsigned(RPC_REPLY);
6051541Srgrimes	rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED);
6061541Srgrimes	rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED);
6071541Srgrimes	rpc_mismatch = txdr_unsigned(RPC_MISMATCH);
6081541Srgrimes	rpc_autherr = txdr_unsigned(RPC_AUTHERR);
6091541Srgrimes	rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED);
6101541Srgrimes	rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX);
6111541Srgrimes	rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS);
6121541Srgrimes	nfs_vers = txdr_unsigned(NFS_VER2);
6131541Srgrimes	nfs_prog = txdr_unsigned(NFS_PROG);
6141541Srgrimes	nfs_true = txdr_unsigned(TRUE);
6151541Srgrimes	nfs_false = txdr_unsigned(FALSE);
6161541Srgrimes	/* Loop thru nfs procids */
6171541Srgrimes	for (i = 0; i < NFS_NPROCS; i++)
6181541Srgrimes		nfs_procids[i] = txdr_unsigned(i);
6191541Srgrimes	/* Ensure async daemons disabled */
6201541Srgrimes	for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
6211541Srgrimes		nfs_iodwant[i] = (struct proc *)0;
6221541Srgrimes	TAILQ_INIT(&nfs_bufq);
6231541Srgrimes	nfs_xdrneg1 = txdr_unsigned(-1);
6241541Srgrimes	nfs_nhinit();			/* Init the nfsnode table */
6251541Srgrimes	nfsrv_init(0);			/* Init server data structures */
6261541Srgrimes	nfsrv_initcache();		/* Init the server request cache */
6271541Srgrimes
6281541Srgrimes	/*
6291541Srgrimes	 * Initialize the nqnfs server stuff.
6301541Srgrimes	 */
6311541Srgrimes	if (nqnfsstarttime == 0) {
6321541Srgrimes		nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease
6331541Srgrimes			+ nqsrv_clockskew + nqsrv_writeslack;
6341541Srgrimes		NQLOADNOVRAM(nqnfsstarttime);
6351541Srgrimes		nqnfs_prog = txdr_unsigned(NQNFS_PROG);
6361541Srgrimes		nqnfs_vers = txdr_unsigned(NQNFS_VER1);
6371541Srgrimes		nqthead.th_head[0] = &nqthead;
6381541Srgrimes		nqthead.th_head[1] = &nqthead;
6391541Srgrimes		nqfhead = hashinit(NQLCHSZ, M_NQLEASE, &nqfheadhash);
6401541Srgrimes	}
6411541Srgrimes
6421541Srgrimes	/*
6431541Srgrimes	 * Initialize reply list and start timer
6441541Srgrimes	 */
6451541Srgrimes	nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
6461541Srgrimes	nfs_timer();
6471549Srgrimes
6482997Swollman	/*
6492997Swollman	 * Set up lease_check and lease_updatetime so that other parts
6502997Swollman	 * of the system can call us, if we are loadable.
6512997Swollman	 */
6522997Swollman	lease_check = nfs_lease_check;
6532997Swollman	lease_updatetime = nfs_lease_updatetime;
6542997Swollman	vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */
6552997Swollman#ifdef VFS_LKM
6562997Swollman	sysent[SYS_nfssvc].sy_narg = 2;
6572997Swollman	sysent[SYS_nfssvc].sy_call = nfssvc;
6582997Swollman	sysent[SYS_getfh].sy_narg = 2;
6592997Swollman	sysent[SYS_getfh].sy_call = getfh;
6602997Swollman#endif
6612997Swollman
6621549Srgrimes	return (0);
6631541Srgrimes}
6641541Srgrimes
6651541Srgrimes/*
6661541Srgrimes * Attribute cache routines.
6671541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes
6681541Srgrimes *	that are on the mbuf list
6691541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns
6701541Srgrimes *	error otherwise
6711541Srgrimes */
6721541Srgrimes
6731541Srgrimes/*
6741541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with
6751541Srgrimes * the values on the mbuf list and
6761541Srgrimes * Iff vap not NULL
6771541Srgrimes *    copy the attributes to *vaper
6781541Srgrimes */
6791549Srgrimesint
6801541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper)
6811541Srgrimes	struct vnode **vpp;
6821541Srgrimes	struct mbuf **mdp;
6831541Srgrimes	caddr_t *dposp;
6841541Srgrimes	struct vattr *vaper;
6851541Srgrimes{
6861541Srgrimes	register struct vnode *vp = *vpp;
6871541Srgrimes	register struct vattr *vap;
6881541Srgrimes	register struct nfsv2_fattr *fp;
6891541Srgrimes	extern int (**spec_nfsv2nodeop_p)();
6901541Srgrimes	register struct nfsnode *np, *nq, **nhpp;
6911541Srgrimes	register long t1;
6921541Srgrimes	caddr_t dpos, cp2;
6931541Srgrimes	int error = 0, isnq;
6941541Srgrimes	struct mbuf *md;
6951541Srgrimes	enum vtype vtyp;
6961541Srgrimes	u_short vmode;
6971541Srgrimes	long rdev;
6981541Srgrimes	struct timespec mtime;
6991541Srgrimes	struct vnode *nvp;
7001541Srgrimes
7011541Srgrimes	md = *mdp;
7021541Srgrimes	dpos = *dposp;
7031541Srgrimes	t1 = (mtod(md, caddr_t) + md->m_len) - dpos;
7041541Srgrimes	isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS);
7051541Srgrimes	if (error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2))
7061541Srgrimes		return (error);
7071541Srgrimes	fp = (struct nfsv2_fattr *)cp2;
7081541Srgrimes	vtyp = nfstov_type(fp->fa_type);
7091541Srgrimes	vmode = fxdr_unsigned(u_short, fp->fa_mode);
7101541Srgrimes	if (vtyp == VNON || vtyp == VREG)
7111541Srgrimes		vtyp = IFTOVT(vmode);
7121541Srgrimes	if (isnq) {
7131541Srgrimes		rdev = fxdr_unsigned(long, fp->fa_nqrdev);
7141541Srgrimes		fxdr_nqtime(&fp->fa_nqmtime, &mtime);
7151541Srgrimes	} else {
7161541Srgrimes		rdev = fxdr_unsigned(long, fp->fa_nfsrdev);
7171541Srgrimes		fxdr_nfstime(&fp->fa_nfsmtime, &mtime);
7181541Srgrimes	}
7191541Srgrimes	/*
7201541Srgrimes	 * If v_type == VNON it is a new node, so fill in the v_type,
7211541Srgrimes	 * n_mtime fields. Check to see if it represents a special
7221541Srgrimes	 * device, and if so, check for a possible alias. Once the
7231541Srgrimes	 * correct vnode has been obtained, fill in the rest of the
7241541Srgrimes	 * information.
7251541Srgrimes	 */
7261541Srgrimes	np = VTONFS(vp);
7271541Srgrimes	if (vp->v_type == VNON) {
7281541Srgrimes		if (vtyp == VCHR && rdev == 0xffffffff)
7291541Srgrimes			vp->v_type = vtyp = VFIFO;
7301541Srgrimes		else
7311541Srgrimes			vp->v_type = vtyp;
7321541Srgrimes		if (vp->v_type == VFIFO) {
7331541Srgrimes			extern int (**fifo_nfsv2nodeop_p)();
7341541Srgrimes			vp->v_op = fifo_nfsv2nodeop_p;
7351541Srgrimes		}
7361541Srgrimes		if (vp->v_type == VCHR || vp->v_type == VBLK) {
7371541Srgrimes			vp->v_op = spec_nfsv2nodeop_p;
7381541Srgrimes			if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
7391541Srgrimes				/*
7401541Srgrimes				 * Discard unneeded vnode, but save its nfsnode.
7411541Srgrimes				 */
7421541Srgrimes				if (nq = np->n_forw)
7431541Srgrimes					nq->n_back = np->n_back;
7441541Srgrimes				*np->n_back = nq;
7451541Srgrimes				nvp->v_data = vp->v_data;
7461541Srgrimes				vp->v_data = NULL;
7471541Srgrimes				vp->v_op = spec_vnodeop_p;
7481541Srgrimes				vrele(vp);
7491541Srgrimes				vgone(vp);
7501541Srgrimes				/*
7511541Srgrimes				 * Reinitialize aliased node.
7521541Srgrimes				 */
7531541Srgrimes				np->n_vnode = nvp;
7541541Srgrimes				nhpp = (struct nfsnode **)nfs_hash(&np->n_fh);
7551541Srgrimes				if (nq = *nhpp)
7561541Srgrimes					nq->n_back = &np->n_forw;
7571541Srgrimes				np->n_forw = nq;
7581541Srgrimes				np->n_back = nhpp;
7591541Srgrimes				*nhpp = np;
7601541Srgrimes				*vpp = vp = nvp;
7611541Srgrimes			}
7621541Srgrimes		}
7631541Srgrimes		np->n_mtime = mtime.ts_sec;
7641541Srgrimes	}
7651541Srgrimes	vap = &np->n_vattr;
7661541Srgrimes	vap->va_type = vtyp;
7671541Srgrimes	vap->va_mode = (vmode & 07777);
7681541Srgrimes	vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
7691541Srgrimes	vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
7701541Srgrimes	vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
7711541Srgrimes	vap->va_rdev = (dev_t)rdev;
7721541Srgrimes	vap->va_mtime = mtime;
7731541Srgrimes	vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
7741541Srgrimes	if (isnq) {
7751541Srgrimes		fxdr_hyper(&fp->fa_nqsize, &vap->va_size);
7761541Srgrimes		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize);
7771541Srgrimes		fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes);
7781541Srgrimes		vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid);
7791541Srgrimes		fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime);
7801541Srgrimes		vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags);
7811541Srgrimes		fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime);
7821541Srgrimes		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen);
7831541Srgrimes		fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev);
7841541Srgrimes	} else {
7851541Srgrimes		vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize);
7861541Srgrimes		vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize);
7871541Srgrimes		vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE;
7881541Srgrimes		vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid);
7891541Srgrimes		fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime);
7901541Srgrimes		vap->va_flags = 0;
7911541Srgrimes		vap->va_ctime.ts_sec = fxdr_unsigned(long, fp->fa_nfsctime.nfs_sec);
7921541Srgrimes		vap->va_ctime.ts_nsec = 0;
7931541Srgrimes		vap->va_gen = fxdr_unsigned(u_long, fp->fa_nfsctime.nfs_usec);
7941541Srgrimes		vap->va_filerev = 0;
7951541Srgrimes	}
7961541Srgrimes	if (vap->va_size != np->n_size) {
7971541Srgrimes		if (vap->va_type == VREG) {
7981541Srgrimes			if (np->n_flag & NMODIFIED) {
7991541Srgrimes				if (vap->va_size < np->n_size)
8001541Srgrimes					vap->va_size = np->n_size;
8011541Srgrimes				else
8021541Srgrimes					np->n_size = vap->va_size;
8031541Srgrimes			} else
8041541Srgrimes				np->n_size = vap->va_size;
8051541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
8061541Srgrimes		} else
8071541Srgrimes			np->n_size = vap->va_size;
8081541Srgrimes	}
8091541Srgrimes	np->n_attrstamp = time.tv_sec;
8101541Srgrimes	*dposp = dpos;
8111541Srgrimes	*mdp = md;
8121541Srgrimes	if (vaper != NULL) {
8131541Srgrimes		bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
8141541Srgrimes#ifdef notdef
8151541Srgrimes		if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size)
8161541Srgrimes		if (np->n_size > vap->va_size)
8171541Srgrimes			vaper->va_size = np->n_size;
8181541Srgrimes#endif
8191541Srgrimes		if (np->n_flag & NCHG) {
8201541Srgrimes			if (np->n_flag & NACC) {
8211541Srgrimes				vaper->va_atime.ts_sec = np->n_atim.tv_sec;
8221541Srgrimes				vaper->va_atime.ts_nsec =
8231541Srgrimes				    np->n_atim.tv_usec * 1000;
8241541Srgrimes			}
8251541Srgrimes			if (np->n_flag & NUPD) {
8261541Srgrimes				vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
8271541Srgrimes				vaper->va_mtime.ts_nsec =
8281541Srgrimes				    np->n_mtim.tv_usec * 1000;
8291541Srgrimes			}
8301541Srgrimes		}
8311541Srgrimes	}
8321541Srgrimes	return (0);
8331541Srgrimes}
8341541Srgrimes
8351541Srgrimes/*
8361541Srgrimes * Check the time stamp
8371541Srgrimes * If the cache is valid, copy contents to *vap and return 0
8381541Srgrimes * otherwise return an error
8391541Srgrimes */
8401549Srgrimesint
8411541Srgrimesnfs_getattrcache(vp, vaper)
8421541Srgrimes	register struct vnode *vp;
8431541Srgrimes	struct vattr *vaper;
8441541Srgrimes{
8451541Srgrimes	register struct nfsnode *np = VTONFS(vp);
8461541Srgrimes	register struct vattr *vap;
8471541Srgrimes
8481541Srgrimes	if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) {
8491541Srgrimes		if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) {
8501541Srgrimes			nfsstats.attrcache_misses++;
8511541Srgrimes			return (ENOENT);
8521541Srgrimes		}
8531541Srgrimes	} else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) {
8541541Srgrimes		nfsstats.attrcache_misses++;
8551541Srgrimes		return (ENOENT);
8561541Srgrimes	}
8571541Srgrimes	nfsstats.attrcache_hits++;
8581541Srgrimes	vap = &np->n_vattr;
8591541Srgrimes	if (vap->va_size != np->n_size) {
8601541Srgrimes		if (vap->va_type == VREG) {
8611541Srgrimes			if (np->n_flag & NMODIFIED) {
8621541Srgrimes				if (vap->va_size < np->n_size)
8631541Srgrimes					vap->va_size = np->n_size;
8641541Srgrimes				else
8651541Srgrimes					np->n_size = vap->va_size;
8661541Srgrimes			} else
8671541Srgrimes				np->n_size = vap->va_size;
8681541Srgrimes			vnode_pager_setsize(vp, (u_long)np->n_size);
8691541Srgrimes		} else
8701541Srgrimes			np->n_size = vap->va_size;
8711541Srgrimes	}
8721541Srgrimes	bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr));
8731541Srgrimes#ifdef notdef
8741541Srgrimes	if ((np->n_flag & NMODIFIED) == 0) {
8751541Srgrimes		np->n_size = vaper->va_size;
8761541Srgrimes		vnode_pager_setsize(vp, (u_long)np->n_size);
8771541Srgrimes	} else if (np->n_size > vaper->va_size)
8781541Srgrimes	if (np->n_size > vaper->va_size)
8791541Srgrimes		vaper->va_size = np->n_size;
8801541Srgrimes#endif
8811541Srgrimes	if (np->n_flag & NCHG) {
8821541Srgrimes		if (np->n_flag & NACC) {
8831541Srgrimes			vaper->va_atime.ts_sec = np->n_atim.tv_sec;
8841541Srgrimes			vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000;
8851541Srgrimes		}
8861541Srgrimes		if (np->n_flag & NUPD) {
8871541Srgrimes			vaper->va_mtime.ts_sec = np->n_mtim.tv_sec;
8881541Srgrimes			vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000;
8891541Srgrimes		}
8901541Srgrimes	}
8911541Srgrimes	return (0);
8921541Srgrimes}
8931541Srgrimes
8941541Srgrimes/*
8951541Srgrimes * Set up nameidata for a lookup() call and do it
8961541Srgrimes */
8971549Srgrimesint
8981541Srgrimesnfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p)
8991541Srgrimes	register struct nameidata *ndp;
9001541Srgrimes	fhandle_t *fhp;
9011541Srgrimes	int len;
9021541Srgrimes	struct nfssvc_sock *slp;
9031541Srgrimes	struct mbuf *nam;
9041541Srgrimes	struct mbuf **mdp;
9051541Srgrimes	caddr_t *dposp;
9061541Srgrimes	struct proc *p;
9071541Srgrimes{
9081541Srgrimes	register int i, rem;
9091541Srgrimes	register struct mbuf *md;
9101541Srgrimes	register char *fromcp, *tocp;
9111541Srgrimes	struct vnode *dp;
9121541Srgrimes	int error, rdonly;
9131541Srgrimes	struct componentname *cnp = &ndp->ni_cnd;
9141541Srgrimes
9151541Srgrimes	MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK);
9161541Srgrimes	/*
9171541Srgrimes	 * Copy the name from the mbuf list to ndp->ni_pnbuf
9181541Srgrimes	 * and set the various ndp fields appropriately.
9191541Srgrimes	 */
9201541Srgrimes	fromcp = *dposp;
9211541Srgrimes	tocp = cnp->cn_pnbuf;
9221541Srgrimes	md = *mdp;
9231541Srgrimes	rem = mtod(md, caddr_t) + md->m_len - fromcp;
9241541Srgrimes	cnp->cn_hash = 0;
9251541Srgrimes	for (i = 0; i < len; i++) {
9261541Srgrimes		while (rem == 0) {
9271541Srgrimes			md = md->m_next;
9281541Srgrimes			if (md == NULL) {
9291541Srgrimes				error = EBADRPC;
9301541Srgrimes				goto out;
9311541Srgrimes			}
9321541Srgrimes			fromcp = mtod(md, caddr_t);
9331541Srgrimes			rem = md->m_len;
9341541Srgrimes		}
9351541Srgrimes		if (*fromcp == '\0' || *fromcp == '/') {
9361541Srgrimes			error = EINVAL;
9371541Srgrimes			goto out;
9381541Srgrimes		}
9391541Srgrimes		cnp->cn_hash += (unsigned char)*fromcp;
9401541Srgrimes		*tocp++ = *fromcp++;
9411541Srgrimes		rem--;
9421541Srgrimes	}
9431541Srgrimes	*tocp = '\0';
9441541Srgrimes	*mdp = md;
9451541Srgrimes	*dposp = fromcp;
9461541Srgrimes	len = nfsm_rndup(len)-len;
9471541Srgrimes	if (len > 0) {
9481541Srgrimes		if (rem >= len)
9491541Srgrimes			*dposp += len;
9501541Srgrimes		else if (error = nfs_adv(mdp, dposp, len, rem))
9511541Srgrimes			goto out;
9521541Srgrimes	}
9531541Srgrimes	ndp->ni_pathlen = tocp - cnp->cn_pnbuf;
9541541Srgrimes	cnp->cn_nameptr = cnp->cn_pnbuf;
9551541Srgrimes	/*
9561541Srgrimes	 * Extract and set starting directory.
9571541Srgrimes	 */
9581541Srgrimes	if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp,
9591541Srgrimes	    nam, &rdonly))
9601541Srgrimes		goto out;
9611541Srgrimes	if (dp->v_type != VDIR) {
9621541Srgrimes		vrele(dp);
9631541Srgrimes		error = ENOTDIR;
9641541Srgrimes		goto out;
9651541Srgrimes	}
9661541Srgrimes	ndp->ni_startdir = dp;
9671541Srgrimes	if (rdonly)
9681541Srgrimes		cnp->cn_flags |= (NOCROSSMOUNT | RDONLY);
9691541Srgrimes	else
9701541Srgrimes		cnp->cn_flags |= NOCROSSMOUNT;
9711541Srgrimes	/*
9721541Srgrimes	 * And call lookup() to do the real work
9731541Srgrimes	 */
9741541Srgrimes	cnp->cn_proc = p;
9751541Srgrimes	if (error = lookup(ndp))
9761541Srgrimes		goto out;
9771541Srgrimes	/*
9781541Srgrimes	 * Check for encountering a symbolic link
9791541Srgrimes	 */
9801541Srgrimes	if (cnp->cn_flags & ISSYMLINK) {
9811541Srgrimes		if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1)
9821541Srgrimes			vput(ndp->ni_dvp);
9831541Srgrimes		else
9841541Srgrimes			vrele(ndp->ni_dvp);
9851541Srgrimes		vput(ndp->ni_vp);
9861541Srgrimes		ndp->ni_vp = NULL;
9871541Srgrimes		error = EINVAL;
9881541Srgrimes		goto out;
9891541Srgrimes	}
9901541Srgrimes	/*
9911541Srgrimes	 * Check for saved name request
9921541Srgrimes	 */
9931541Srgrimes	if (cnp->cn_flags & (SAVENAME | SAVESTART)) {
9941541Srgrimes		cnp->cn_flags |= HASBUF;
9951541Srgrimes		return (0);
9961541Srgrimes	}
9971541Srgrimesout:
9981541Srgrimes	FREE(cnp->cn_pnbuf, M_NAMEI);
9991541Srgrimes	return (error);
10001541Srgrimes}
10011541Srgrimes
10021541Srgrimes/*
10031541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long
10041541Srgrimes * boundary and only trims off the back end
10051541Srgrimes */
10061541Srgrimesvoid
10071541Srgrimesnfsm_adj(mp, len, nul)
10081541Srgrimes	struct mbuf *mp;
10091541Srgrimes	register int len;
10101541Srgrimes	int nul;
10111541Srgrimes{
10121541Srgrimes	register struct mbuf *m;
10131541Srgrimes	register int count, i;
10141541Srgrimes	register char *cp;
10151541Srgrimes
10161541Srgrimes	/*
10171541Srgrimes	 * Trim from tail.  Scan the mbuf chain,
10181541Srgrimes	 * calculating its length and finding the last mbuf.
10191541Srgrimes	 * If the adjustment only affects this mbuf, then just
10201541Srgrimes	 * adjust and return.  Otherwise, rescan and truncate
10211541Srgrimes	 * after the remaining size.
10221541Srgrimes	 */
10231541Srgrimes	count = 0;
10241541Srgrimes	m = mp;
10251541Srgrimes	for (;;) {
10261541Srgrimes		count += m->m_len;
10271541Srgrimes		if (m->m_next == (struct mbuf *)0)
10281541Srgrimes			break;
10291541Srgrimes		m = m->m_next;
10301541Srgrimes	}
10311541Srgrimes	if (m->m_len > len) {
10321541Srgrimes		m->m_len -= len;
10331541Srgrimes		if (nul > 0) {
10341541Srgrimes			cp = mtod(m, caddr_t)+m->m_len-nul;
10351541Srgrimes			for (i = 0; i < nul; i++)
10361541Srgrimes				*cp++ = '\0';
10371541Srgrimes		}
10381541Srgrimes		return;
10391541Srgrimes	}
10401541Srgrimes	count -= len;
10411541Srgrimes	if (count < 0)
10421541Srgrimes		count = 0;
10431541Srgrimes	/*
10441541Srgrimes	 * Correct length for chain is "count".
10451541Srgrimes	 * Find the mbuf with last data, adjust its length,
10461541Srgrimes	 * and toss data from remaining mbufs on chain.
10471541Srgrimes	 */
10481541Srgrimes	for (m = mp; m; m = m->m_next) {
10491541Srgrimes		if (m->m_len >= count) {
10501541Srgrimes			m->m_len = count;
10511541Srgrimes			if (nul > 0) {
10521541Srgrimes				cp = mtod(m, caddr_t)+m->m_len-nul;
10531541Srgrimes				for (i = 0; i < nul; i++)
10541541Srgrimes					*cp++ = '\0';
10551541Srgrimes			}
10561541Srgrimes			break;
10571541Srgrimes		}
10581541Srgrimes		count -= m->m_len;
10591541Srgrimes	}
10601541Srgrimes	while (m = m->m_next)
10611541Srgrimes		m->m_len = 0;
10621541Srgrimes}
10631541Srgrimes
10641541Srgrimes/*
10651541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked)
10661541Srgrimes * 	- look up fsid in mount list (if not found ret error)
10671541Srgrimes *	- get vp and export rights by calling VFS_FHTOVP()
10681541Srgrimes *	- if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon
10691541Srgrimes *	- if not lockflag unlock it with VOP_UNLOCK()
10701541Srgrimes */
10711549Srgrimesint
10721541Srgrimesnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp)
10731541Srgrimes	fhandle_t *fhp;
10741541Srgrimes	int lockflag;
10751541Srgrimes	struct vnode **vpp;
10761541Srgrimes	struct ucred *cred;
10771541Srgrimes	struct nfssvc_sock *slp;
10781541Srgrimes	struct mbuf *nam;
10791541Srgrimes	int *rdonlyp;
10801541Srgrimes{
10811541Srgrimes	register struct mount *mp;
10821541Srgrimes	register struct nfsuid *uidp;
10831541Srgrimes	register int i;
10841541Srgrimes	struct ucred *credanon;
10851541Srgrimes	int error, exflags;
10861541Srgrimes
10871541Srgrimes	*vpp = (struct vnode *)0;
10881541Srgrimes	if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
10891541Srgrimes		return (ESTALE);
10901541Srgrimes	if (error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon))
10911541Srgrimes		return (error);
10921541Srgrimes	/*
10931541Srgrimes	 * Check/setup credentials.
10941541Srgrimes	 */
10951541Srgrimes	if (exflags & MNT_EXKERB) {
10961541Srgrimes		uidp = slp->ns_uidh[NUIDHASH(cred->cr_uid)];
10971541Srgrimes		while (uidp) {
10981541Srgrimes			if (uidp->nu_uid == cred->cr_uid)
10991541Srgrimes				break;
11001541Srgrimes			uidp = uidp->nu_hnext;
11011541Srgrimes		}
11021541Srgrimes		if (uidp) {
11031541Srgrimes			cred->cr_uid = uidp->nu_cr.cr_uid;
11041541Srgrimes			for (i = 0; i < uidp->nu_cr.cr_ngroups; i++)
11051541Srgrimes				cred->cr_groups[i] = uidp->nu_cr.cr_groups[i];
11061541Srgrimes		} else {
11071541Srgrimes			vput(*vpp);
11081541Srgrimes			return (NQNFS_AUTHERR);
11091541Srgrimes		}
11101541Srgrimes	} else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) {
11111541Srgrimes		cred->cr_uid = credanon->cr_uid;
11121541Srgrimes		for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++)
11131541Srgrimes			cred->cr_groups[i] = credanon->cr_groups[i];
11141541Srgrimes	}
11151541Srgrimes	if (exflags & MNT_EXRDONLY)
11161541Srgrimes		*rdonlyp = 1;
11171541Srgrimes	else
11181541Srgrimes		*rdonlyp = 0;
11191541Srgrimes	if (!lockflag)
11201541Srgrimes		VOP_UNLOCK(*vpp);
11211541Srgrimes	return (0);
11221541Srgrimes}
11231541Srgrimes
11241541Srgrimes/*
11251541Srgrimes * This function compares two net addresses by family and returns TRUE
11261541Srgrimes * if they are the same host.
11271541Srgrimes * If there is any doubt, return FALSE.
11281541Srgrimes * The AF_INET family is handled as a special case so that address mbufs
11291541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes.
11301541Srgrimes */
11311549Srgrimesint
11321541Srgrimesnetaddr_match(family, haddr, nam)
11331541Srgrimes	int family;
11341541Srgrimes	union nethostaddr *haddr;
11351541Srgrimes	struct mbuf *nam;
11361541Srgrimes{
11371541Srgrimes	register struct sockaddr_in *inetaddr;
11381541Srgrimes
11391541Srgrimes	switch (family) {
11401541Srgrimes	case AF_INET:
11411541Srgrimes		inetaddr = mtod(nam, struct sockaddr_in *);
11421541Srgrimes		if (inetaddr->sin_family == AF_INET &&
11431541Srgrimes		    inetaddr->sin_addr.s_addr == haddr->had_inetaddr)
11441541Srgrimes			return (1);
11451541Srgrimes		break;
11461541Srgrimes#ifdef ISO
11471541Srgrimes	case AF_ISO:
11481541Srgrimes	    {
11491541Srgrimes		register struct sockaddr_iso *isoaddr1, *isoaddr2;
11501541Srgrimes
11511541Srgrimes		isoaddr1 = mtod(nam, struct sockaddr_iso *);
11521541Srgrimes		isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *);
11531541Srgrimes		if (isoaddr1->siso_family == AF_ISO &&
11541541Srgrimes		    isoaddr1->siso_nlen > 0 &&
11551541Srgrimes		    isoaddr1->siso_nlen == isoaddr2->siso_nlen &&
11561541Srgrimes		    SAME_ISOADDR(isoaddr1, isoaddr2))
11571541Srgrimes			return (1);
11581541Srgrimes		break;
11591541Srgrimes	    }
11601541Srgrimes#endif	/* ISO */
11611541Srgrimes	default:
11621541Srgrimes		break;
11631541Srgrimes	};
11641541Srgrimes	return (0);
11651541Srgrimes}
1166