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