nfs_common.c revision 6210
133965Sjdp/* 233965Sjdp * Copyright (c) 1989, 1993 333965Sjdp * The Regents of the University of California. All rights reserved. 433965Sjdp * 533965Sjdp * This code is derived from software contributed to Berkeley by 633965Sjdp * Rick Macklem at The University of Guelph. 733965Sjdp * 833965Sjdp * Redistribution and use in source and binary forms, with or without 933965Sjdp * modification, are permitted provided that the following conditions 1033965Sjdp * are met: 1133965Sjdp * 1. Redistributions of source code must retain the above copyright 1233965Sjdp * notice, this list of conditions and the following disclaimer. 1333965Sjdp * 2. Redistributions in binary form must reproduce the above copyright 1433965Sjdp * notice, this list of conditions and the following disclaimer in the 1533965Sjdp * documentation and/or other materials provided with the distribution. 1633965Sjdp * 3. All advertising materials mentioning features or use of this software 1733965Sjdp * must display the following acknowledgement: 1833965Sjdp * This product includes software developed by the University of 1933965Sjdp * California, Berkeley and its contributors. 2033965Sjdp * 4. Neither the name of the University nor the names of its contributors 2133965Sjdp * may be used to endorse or promote products derived from this software 2233965Sjdp * without specific prior written permission. 2333965Sjdp * 2433965Sjdp * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2533965Sjdp * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2633965Sjdp * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2733965Sjdp * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2833965Sjdp * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2933965Sjdp * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3033965Sjdp * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3133965Sjdp * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3233965Sjdp * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3333965Sjdp * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3433965Sjdp * SUCH DAMAGE. 3533965Sjdp * 3633965Sjdp * @(#)nfs_subs.c 8.3 (Berkeley) 1/4/94 3733965Sjdp * $Id: nfs_subs.c,v 1.8 1995/01/09 16:05:08 davidg Exp $ 3833965Sjdp */ 3933965Sjdp 4033965Sjdp/* 4133965Sjdp * These functions support the macros and help fiddle mbuf chains for 4233965Sjdp * the nfs op functions. They do things like create the rpc header and 4333965Sjdp * copy data between mbuf chains and uio lists. 4433965Sjdp */ 4533965Sjdp#include <sys/param.h> 4633965Sjdp#include <sys/proc.h> 4733965Sjdp#include <sys/systm.h> 4833965Sjdp#include <sys/kernel.h> 4933965Sjdp#include <sys/mount.h> 5033965Sjdp#include <sys/vnode.h> 5133965Sjdp#include <sys/namei.h> 5233965Sjdp#include <sys/mbuf.h> 5333965Sjdp#include <sys/socket.h> 5433965Sjdp#include <sys/stat.h> 5533965Sjdp#ifdef VFS_LKM 5633965Sjdp#include <sys/sysent.h> 5733965Sjdp#include <sys/syscall.h> 5833965Sjdp#endif 5933965Sjdp 6033965Sjdp#include <vm/vm.h> 6133965Sjdp 6233965Sjdp#include <nfs/rpcv2.h> 6333965Sjdp#include <nfs/nfsv2.h> 6433965Sjdp#include <nfs/nfsnode.h> 6533965Sjdp#include <nfs/nfs.h> 6633965Sjdp#include <nfs/xdr_subs.h> 6733965Sjdp#include <nfs/nfsm_subs.h> 6833965Sjdp#include <nfs/nfsmount.h> 6933965Sjdp#include <nfs/nqnfs.h> 7033965Sjdp#include <nfs/nfsrtt.h> 7133965Sjdp 7233965Sjdp#include <miscfs/specfs/specdev.h> 7333965Sjdp 7433965Sjdp#include <netinet/in.h> 7533965Sjdp#ifdef ISO 7633965Sjdp#include <netiso/iso.h> 7733965Sjdp#endif 7833965Sjdp 7933965Sjdp#define TRUE 1 8033965Sjdp#define FALSE 0 8133965Sjdp 8233965Sjdp/* 8333965Sjdp * Data items converted to xdr at startup, since they are constant 8433965Sjdp * This is kinda hokey, but may save a little time doing byte swaps 8533965Sjdp */ 8633965Sjdpu_long nfs_procids[NFS_NPROCS]; 8733965Sjdpu_long nfs_xdrneg1; 8833965Sjdpu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 8933965Sjdp rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, 9033965Sjdp rpc_auth_kerb; 9133965Sjdpu_long nfs_vers, nfs_prog, nfs_true, nfs_false; 9233965Sjdp 9333965Sjdp/* And other global data */ 9433965Sjdpstatic u_long nfs_xid = 0; 9533965Sjdpenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 9633965Sjdpextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 9733965Sjdpextern int nqnfs_piggy[NFS_NPROCS]; 9833965Sjdpextern struct nfsrtt nfsrtt; 9933965Sjdpextern time_t nqnfsstarttime; 10033965Sjdpextern u_long nqnfs_prog, nqnfs_vers; 10133965Sjdpextern int nqsrv_clockskew; 10233965Sjdpextern int nqsrv_writeslack; 10333965Sjdpextern int nqsrv_maxlease; 10433965Sjdp 10533965Sjdp#ifdef VFS_LKM 10633965Sjdpstruct getfh_args; 10733965Sjdpextern int getfh(struct proc *, struct getfh_args *, int *); 10833965Sjdpstruct nfssvc_args; 10933965Sjdpextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 11033965Sjdp#endif 11133965Sjdp 11233965SjdpLIST_HEAD(nfsnodehashhead, nfsnode); 11333965Sjdp 11433965Sjdp/* 11533965Sjdp * Create the header for an rpc request packet 11633965Sjdp * The hsiz is the size of the rest of the nfs request header. 11733965Sjdp * (just used to decide if a cluster is a good idea) 11833965Sjdp */ 11933965Sjdpstruct mbuf * 12033965Sjdpnfsm_reqh(vp, procid, hsiz, bposp) 12133965Sjdp struct vnode *vp; 12233965Sjdp u_long procid; 12333965Sjdp int hsiz; 12433965Sjdp caddr_t *bposp; 12533965Sjdp{ 12633965Sjdp register struct mbuf *mb; 12733965Sjdp register u_long *tl; 12833965Sjdp register caddr_t bpos; 12933965Sjdp struct mbuf *mb2; 13033965Sjdp struct nfsmount *nmp; 13133965Sjdp int nqflag; 13233965Sjdp 13333965Sjdp MGET(mb, M_WAIT, MT_DATA); 13433965Sjdp if (hsiz >= MINCLSIZE) 13533965Sjdp MCLGET(mb, M_WAIT); 13633965Sjdp mb->m_len = 0; 13733965Sjdp bpos = mtod(mb, caddr_t); 13833965Sjdp 13933965Sjdp /* 14033965Sjdp * For NQNFS, add lease request. 14133965Sjdp */ 14233965Sjdp if (vp) { 14333965Sjdp nmp = VFSTONFS(vp->v_mount); 14433965Sjdp if (nmp->nm_flag & NFSMNT_NQNFS) { 14533965Sjdp nqflag = NQNFS_NEEDLEASE(vp, procid); 14633965Sjdp if (nqflag) { 14733965Sjdp nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 14833965Sjdp *tl++ = txdr_unsigned(nqflag); 14933965Sjdp *tl = txdr_unsigned(nmp->nm_leaseterm); 15033965Sjdp } else { 15133965Sjdp nfsm_build(tl, u_long *, NFSX_UNSIGNED); 15233965Sjdp *tl = 0; 15333965Sjdp } 15433965Sjdp } 15533965Sjdp } 15633965Sjdp /* Finally, return values */ 15733965Sjdp *bposp = bpos; 15833965Sjdp return (mb); 15933965Sjdp} 16033965Sjdp 16133965Sjdp/* 16233965Sjdp * Build the RPC header and fill in the authorization info. 16333965Sjdp * The authorization string argument is only used when the credentials 16433965Sjdp * come from outside of the kernel. 16533965Sjdp * Returns the head of the mbuf list. 16633965Sjdp */ 16733965Sjdpstruct mbuf * 16833965Sjdpnfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, 16933965Sjdp mrest_len, mbp, xidp) 17033965Sjdp register struct ucred *cr; 17133965Sjdp int nqnfs; 17233965Sjdp int procid; 17333965Sjdp int auth_type; 17433965Sjdp int auth_len; 17533965Sjdp char *auth_str; 17633965Sjdp struct mbuf *mrest; 17733965Sjdp int mrest_len; 17833965Sjdp struct mbuf **mbp; 17933965Sjdp u_long *xidp; 18033965Sjdp{ 18133965Sjdp register struct mbuf *mb; 18233965Sjdp register u_long *tl; 18333965Sjdp register caddr_t bpos; 18433965Sjdp register int i; 18533965Sjdp struct mbuf *mreq, *mb2; 18633965Sjdp int siz, grpsiz, authsiz; 18733965Sjdp 18833965Sjdp authsiz = nfsm_rndup(auth_len); 18933965Sjdp if (auth_type == RPCAUTH_NQNFS) 19033965Sjdp authsiz += 2 * NFSX_UNSIGNED; 19133965Sjdp MGETHDR(mb, M_WAIT, MT_DATA); 19233965Sjdp if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { 19333965Sjdp MCLGET(mb, M_WAIT); 19433965Sjdp } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { 19533965Sjdp MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); 19633965Sjdp } else { 19733965Sjdp MH_ALIGN(mb, 8*NFSX_UNSIGNED); 19833965Sjdp } 19933965Sjdp mb->m_len = 0; 20033965Sjdp mreq = mb; 20133965Sjdp bpos = mtod(mb, caddr_t); 20233965Sjdp 20333965Sjdp /* 20433965Sjdp * First the RPC header. 20533965Sjdp */ 20633965Sjdp nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); 20733965Sjdp if (++nfs_xid == 0) 20833965Sjdp nfs_xid++; 20933965Sjdp *tl++ = *xidp = txdr_unsigned(nfs_xid); 21033965Sjdp *tl++ = rpc_call; 21133965Sjdp *tl++ = rpc_vers; 21233965Sjdp if (nqnfs) { 21333965Sjdp *tl++ = txdr_unsigned(NQNFS_PROG); 21433965Sjdp *tl++ = txdr_unsigned(NQNFS_VER1); 21533965Sjdp } else { 21633965Sjdp *tl++ = txdr_unsigned(NFS_PROG); 21733965Sjdp *tl++ = txdr_unsigned(NFS_VER2); 21833965Sjdp } 21933965Sjdp *tl++ = txdr_unsigned(procid); 22033965Sjdp 22133965Sjdp /* 22233965Sjdp * And then the authorization cred. 22333965Sjdp */ 22433965Sjdp *tl++ = txdr_unsigned(auth_type); 22533965Sjdp *tl = txdr_unsigned(authsiz); 22633965Sjdp switch (auth_type) { 22733965Sjdp case RPCAUTH_UNIX: 22833965Sjdp nfsm_build(tl, u_long *, auth_len); 22933965Sjdp *tl++ = 0; /* stamp ?? */ 23033965Sjdp *tl++ = 0; /* NULL hostname */ 23133965Sjdp *tl++ = txdr_unsigned(cr->cr_uid); 23233965Sjdp *tl++ = txdr_unsigned(cr->cr_groups[0]); 23333965Sjdp grpsiz = (auth_len >> 2) - 5; 23433965Sjdp *tl++ = txdr_unsigned(grpsiz); 23533965Sjdp for (i = 1; i <= grpsiz; i++) 23633965Sjdp *tl++ = txdr_unsigned(cr->cr_groups[i]); 23733965Sjdp break; 23833965Sjdp case RPCAUTH_NQNFS: 23933965Sjdp nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 24033965Sjdp *tl++ = txdr_unsigned(cr->cr_uid); 24133965Sjdp *tl = txdr_unsigned(auth_len); 24233965Sjdp siz = auth_len; 24333965Sjdp while (siz > 0) { 24433965Sjdp if (M_TRAILINGSPACE(mb) == 0) { 24533965Sjdp MGET(mb2, M_WAIT, MT_DATA); 24633965Sjdp if (siz >= MINCLSIZE) 24733965Sjdp MCLGET(mb2, M_WAIT); 24833965Sjdp mb->m_next = mb2; 24933965Sjdp mb = mb2; 25033965Sjdp mb->m_len = 0; 25133965Sjdp bpos = mtod(mb, caddr_t); 25233965Sjdp } 25333965Sjdp i = min(siz, M_TRAILINGSPACE(mb)); 25433965Sjdp bcopy(auth_str, bpos, i); 25533965Sjdp mb->m_len += i; 25633965Sjdp auth_str += i; 25733965Sjdp bpos += i; 25833965Sjdp siz -= i; 25933965Sjdp } 26033965Sjdp if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 26133965Sjdp for (i = 0; i < siz; i++) 26233965Sjdp *bpos++ = '\0'; 26333965Sjdp mb->m_len += siz; 26433965Sjdp } 26533965Sjdp break; 26633965Sjdp }; 26733965Sjdp nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 26833965Sjdp *tl++ = txdr_unsigned(RPCAUTH_NULL); 26933965Sjdp *tl = 0; 27033965Sjdp mb->m_next = mrest; 27133965Sjdp mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; 27233965Sjdp mreq->m_pkthdr.rcvif = (struct ifnet *)0; 27333965Sjdp *mbp = mb; 27433965Sjdp return (mreq); 27533965Sjdp} 27633965Sjdp 27733965Sjdp/* 27833965Sjdp * copies mbuf chain to the uio scatter/gather list 27933965Sjdp */ 28033965Sjdpint 28133965Sjdpnfsm_mbuftouio(mrep, uiop, siz, dpos) 28233965Sjdp struct mbuf **mrep; 28333965Sjdp register struct uio *uiop; 28433965Sjdp int siz; 28533965Sjdp caddr_t *dpos; 28633965Sjdp{ 28733965Sjdp register char *mbufcp, *uiocp; 28833965Sjdp register int xfer, left, len; 28933965Sjdp register struct mbuf *mp; 29033965Sjdp long uiosiz, rem; 29133965Sjdp int error = 0; 29233965Sjdp 29333965Sjdp mp = *mrep; 29433965Sjdp mbufcp = *dpos; 29533965Sjdp len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 29633965Sjdp rem = nfsm_rndup(siz)-siz; 29733965Sjdp while (siz > 0) { 29833965Sjdp if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 29933965Sjdp return (EFBIG); 30033965Sjdp left = uiop->uio_iov->iov_len; 30133965Sjdp uiocp = uiop->uio_iov->iov_base; 30233965Sjdp if (left > siz) 30333965Sjdp left = siz; 30433965Sjdp uiosiz = left; 30533965Sjdp while (left > 0) { 30633965Sjdp while (len == 0) { 30733965Sjdp mp = mp->m_next; 30833965Sjdp if (mp == NULL) 30933965Sjdp return (EBADRPC); 31033965Sjdp mbufcp = mtod(mp, caddr_t); 31133965Sjdp len = mp->m_len; 31233965Sjdp } 31333965Sjdp xfer = (left > len) ? len : left; 31433965Sjdp#ifdef notdef 31533965Sjdp /* Not Yet.. */ 31633965Sjdp if (uiop->uio_iov->iov_op != NULL) 31733965Sjdp (*(uiop->uio_iov->iov_op)) 31833965Sjdp (mbufcp, uiocp, xfer); 31933965Sjdp else 32033965Sjdp#endif 32133965Sjdp if (uiop->uio_segflg == UIO_SYSSPACE) 32233965Sjdp bcopy(mbufcp, uiocp, xfer); 32333965Sjdp else 32433965Sjdp copyout(mbufcp, uiocp, xfer); 32533965Sjdp left -= xfer; 32633965Sjdp len -= xfer; 32733965Sjdp mbufcp += xfer; 32833965Sjdp uiocp += xfer; 32933965Sjdp uiop->uio_offset += xfer; 33033965Sjdp uiop->uio_resid -= xfer; 33133965Sjdp } 33233965Sjdp if (uiop->uio_iov->iov_len <= siz) { 33333965Sjdp uiop->uio_iovcnt--; 33433965Sjdp uiop->uio_iov++; 33533965Sjdp } else { 33633965Sjdp uiop->uio_iov->iov_base += uiosiz; 33733965Sjdp uiop->uio_iov->iov_len -= uiosiz; 33833965Sjdp } 33933965Sjdp siz -= uiosiz; 34033965Sjdp } 34133965Sjdp *dpos = mbufcp; 34233965Sjdp *mrep = mp; 34333965Sjdp if (rem > 0) { 34433965Sjdp if (len < rem) 34533965Sjdp error = nfs_adv(mrep, dpos, rem, len); 34633965Sjdp else 34733965Sjdp *dpos += rem; 34833965Sjdp } 34933965Sjdp return (error); 35033965Sjdp} 35133965Sjdp 35233965Sjdp/* 35333965Sjdp * copies a uio scatter/gather list to an mbuf chain... 35433965Sjdp */ 35533965Sjdpint 35633965Sjdpnfsm_uiotombuf(uiop, mq, siz, bpos) 35733965Sjdp register struct uio *uiop; 35833965Sjdp struct mbuf **mq; 35933965Sjdp int siz; 36033965Sjdp caddr_t *bpos; 36133965Sjdp{ 36233965Sjdp register char *uiocp; 36333965Sjdp register struct mbuf *mp, *mp2; 36433965Sjdp register int xfer, left, mlen; 36533965Sjdp int uiosiz, clflg, rem; 36633965Sjdp char *cp; 36733965Sjdp 36833965Sjdp if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 36933965Sjdp clflg = 1; 37033965Sjdp else 37133965Sjdp clflg = 0; 37233965Sjdp rem = nfsm_rndup(siz)-siz; 37333965Sjdp mp = mp2 = *mq; 37433965Sjdp while (siz > 0) { 37533965Sjdp if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 37633965Sjdp return (EINVAL); 37733965Sjdp left = uiop->uio_iov->iov_len; 37833965Sjdp uiocp = uiop->uio_iov->iov_base; 37933965Sjdp if (left > siz) 38033965Sjdp left = siz; 38133965Sjdp uiosiz = left; 38233965Sjdp while (left > 0) { 38333965Sjdp mlen = M_TRAILINGSPACE(mp); 38433965Sjdp if (mlen == 0) { 38533965Sjdp MGET(mp, M_WAIT, MT_DATA); 38633965Sjdp if (clflg) 38733965Sjdp MCLGET(mp, M_WAIT); 38833965Sjdp mp->m_len = 0; 38933965Sjdp mp2->m_next = mp; 39033965Sjdp mp2 = mp; 39133965Sjdp mlen = M_TRAILINGSPACE(mp); 39233965Sjdp } 39333965Sjdp xfer = (left > mlen) ? mlen : left; 39433965Sjdp#ifdef notdef 39533965Sjdp /* Not Yet.. */ 39633965Sjdp if (uiop->uio_iov->iov_op != NULL) 39733965Sjdp (*(uiop->uio_iov->iov_op)) 39833965Sjdp (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 39933965Sjdp else 40033965Sjdp#endif 40133965Sjdp if (uiop->uio_segflg == UIO_SYSSPACE) 40233965Sjdp bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 40333965Sjdp else 40433965Sjdp copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 40533965Sjdp mp->m_len += xfer; 40633965Sjdp left -= xfer; 40733965Sjdp uiocp += xfer; 40833965Sjdp uiop->uio_offset += xfer; 40933965Sjdp uiop->uio_resid -= xfer; 41033965Sjdp } 41133965Sjdp if (uiop->uio_iov->iov_len <= siz) { 41233965Sjdp uiop->uio_iovcnt--; 41333965Sjdp uiop->uio_iov++; 41433965Sjdp } else { 41533965Sjdp uiop->uio_iov->iov_base += uiosiz; 41633965Sjdp uiop->uio_iov->iov_len -= uiosiz; 41733965Sjdp } 41833965Sjdp siz -= uiosiz; 41933965Sjdp } 42033965Sjdp if (rem > 0) { 42133965Sjdp if (rem > M_TRAILINGSPACE(mp)) { 42233965Sjdp MGET(mp, M_WAIT, MT_DATA); 42333965Sjdp mp->m_len = 0; 42433965Sjdp mp2->m_next = mp; 42533965Sjdp } 42633965Sjdp cp = mtod(mp, caddr_t)+mp->m_len; 42733965Sjdp for (left = 0; left < rem; left++) 42833965Sjdp *cp++ = '\0'; 42933965Sjdp mp->m_len += rem; 43033965Sjdp *bpos = cp; 43133965Sjdp } else 43233965Sjdp *bpos = mtod(mp, caddr_t)+mp->m_len; 43333965Sjdp *mq = mp; 43433965Sjdp return (0); 43533965Sjdp} 43633965Sjdp 43733965Sjdp/* 43833965Sjdp * Help break down an mbuf chain by setting the first siz bytes contiguous 43933965Sjdp * pointed to by returned val. 44033965Sjdp * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 44133965Sjdp * cases. (The macros use the vars. dpos and dpos2) 44233965Sjdp */ 44333965Sjdpint 44433965Sjdpnfsm_disct(mdp, dposp, siz, left, cp2) 44533965Sjdp struct mbuf **mdp; 44633965Sjdp caddr_t *dposp; 44733965Sjdp int siz; 44833965Sjdp int left; 44933965Sjdp caddr_t *cp2; 45033965Sjdp{ 45133965Sjdp register struct mbuf *mp, *mp2; 45233965Sjdp register int siz2, xfer; 45333965Sjdp register caddr_t p; 45433965Sjdp 45533965Sjdp mp = *mdp; 45633965Sjdp while (left == 0) { 45733965Sjdp *mdp = mp = mp->m_next; 45833965Sjdp if (mp == NULL) 45933965Sjdp return (EBADRPC); 46033965Sjdp left = mp->m_len; 46133965Sjdp *dposp = mtod(mp, caddr_t); 46233965Sjdp } 46333965Sjdp if (left >= siz) { 46433965Sjdp *cp2 = *dposp; 46533965Sjdp *dposp += siz; 46633965Sjdp } else if (mp->m_next == NULL) { 46733965Sjdp return (EBADRPC); 46833965Sjdp } else if (siz > MHLEN) { 46933965Sjdp panic("nfs S too big"); 47033965Sjdp } else { 47133965Sjdp MGET(mp2, M_WAIT, MT_DATA); 47233965Sjdp mp2->m_next = mp->m_next; 47333965Sjdp mp->m_next = mp2; 47433965Sjdp mp->m_len -= left; 47533965Sjdp mp = mp2; 47633965Sjdp *cp2 = p = mtod(mp, caddr_t); 47733965Sjdp bcopy(*dposp, p, left); /* Copy what was left */ 47833965Sjdp siz2 = siz-left; 47933965Sjdp p += left; 48033965Sjdp mp2 = mp->m_next; 48133965Sjdp /* Loop around copying up the siz2 bytes */ 48233965Sjdp while (siz2 > 0) { 48333965Sjdp if (mp2 == NULL) 48433965Sjdp return (EBADRPC); 48533965Sjdp xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 48633965Sjdp if (xfer > 0) { 48733965Sjdp bcopy(mtod(mp2, caddr_t), p, xfer); 48833965Sjdp NFSMADV(mp2, xfer); 48933965Sjdp mp2->m_len -= xfer; 49033965Sjdp p += xfer; 49133965Sjdp siz2 -= xfer; 49233965Sjdp } 49333965Sjdp if (siz2 > 0) 49433965Sjdp mp2 = mp2->m_next; 49533965Sjdp } 49633965Sjdp mp->m_len = siz; 49733965Sjdp *mdp = mp2; 49833965Sjdp *dposp = mtod(mp2, caddr_t); 49933965Sjdp } 50033965Sjdp return (0); 50133965Sjdp} 50233965Sjdp 50333965Sjdp/* 50433965Sjdp * Advance the position in the mbuf chain. 50533965Sjdp */ 50633965Sjdpint 50733965Sjdpnfs_adv(mdp, dposp, offs, left) 50833965Sjdp struct mbuf **mdp; 50933965Sjdp caddr_t *dposp; 51033965Sjdp int offs; 51133965Sjdp int left; 51233965Sjdp{ 51333965Sjdp register struct mbuf *m; 51433965Sjdp register int s; 51533965Sjdp 51633965Sjdp m = *mdp; 51733965Sjdp s = left; 51833965Sjdp while (s < offs) { 51933965Sjdp offs -= s; 52033965Sjdp m = m->m_next; 52133965Sjdp if (m == NULL) 52233965Sjdp return (EBADRPC); 52333965Sjdp s = m->m_len; 52433965Sjdp } 52533965Sjdp *mdp = m; 52633965Sjdp *dposp = mtod(m, caddr_t)+offs; 52733965Sjdp return (0); 52833965Sjdp} 52933965Sjdp 53033965Sjdp/* 53133965Sjdp * Copy a string into mbufs for the hard cases... 53233965Sjdp */ 53333965Sjdpint 53433965Sjdpnfsm_strtmbuf(mb, bpos, cp, siz) 53533965Sjdp struct mbuf **mb; 53633965Sjdp char **bpos; 53733965Sjdp char *cp; 53833965Sjdp long siz; 53933965Sjdp{ 54033965Sjdp register struct mbuf *m1 = 0, *m2; 54133965Sjdp long left, xfer, len, tlen; 54233965Sjdp u_long *tl; 54333965Sjdp int putsize; 54433965Sjdp 54533965Sjdp putsize = 1; 54633965Sjdp m2 = *mb; 54733965Sjdp left = M_TRAILINGSPACE(m2); 54833965Sjdp if (left > 0) { 54933965Sjdp tl = ((u_long *)(*bpos)); 55033965Sjdp *tl++ = txdr_unsigned(siz); 55133965Sjdp putsize = 0; 55233965Sjdp left -= NFSX_UNSIGNED; 55333965Sjdp m2->m_len += NFSX_UNSIGNED; 55433965Sjdp if (left > 0) { 55533965Sjdp bcopy(cp, (caddr_t) tl, left); 55633965Sjdp siz -= left; 55733965Sjdp cp += left; 55833965Sjdp m2->m_len += left; 55933965Sjdp left = 0; 56033965Sjdp } 56133965Sjdp } 56233965Sjdp /* Loop around adding mbufs */ 56333965Sjdp while (siz > 0) { 56433965Sjdp MGET(m1, M_WAIT, MT_DATA); 56533965Sjdp if (siz > MLEN) 56633965Sjdp MCLGET(m1, M_WAIT); 56733965Sjdp m1->m_len = NFSMSIZ(m1); 56833965Sjdp m2->m_next = m1; 56933965Sjdp m2 = m1; 57033965Sjdp tl = mtod(m1, u_long *); 57133965Sjdp tlen = 0; 57233965Sjdp if (putsize) { 57333965Sjdp *tl++ = txdr_unsigned(siz); 57433965Sjdp m1->m_len -= NFSX_UNSIGNED; 57533965Sjdp tlen = NFSX_UNSIGNED; 57633965Sjdp putsize = 0; 57733965Sjdp } 57833965Sjdp if (siz < m1->m_len) { 57933965Sjdp len = nfsm_rndup(siz); 58033965Sjdp xfer = siz; 58133965Sjdp if (xfer < len) 58233965Sjdp *(tl+(xfer>>2)) = 0; 58333965Sjdp } else { 58433965Sjdp xfer = len = m1->m_len; 58533965Sjdp } 58633965Sjdp bcopy(cp, (caddr_t) tl, xfer); 58733965Sjdp m1->m_len = len+tlen; 58833965Sjdp siz -= xfer; 58933965Sjdp cp += xfer; 59033965Sjdp } 59133965Sjdp *mb = m1; 59233965Sjdp *bpos = mtod(m1, caddr_t)+m1->m_len; 59333965Sjdp return (0); 59433965Sjdp} 59533965Sjdp 59633965Sjdp/* 59733965Sjdp * Called once to initialize data structures... 59833965Sjdp */ 59933965Sjdpint 60033965Sjdpnfs_init() 60133965Sjdp{ 60233965Sjdp register int i; 60333965Sjdp 60433965Sjdp nfsrtt.pos = 0; 60533965Sjdp rpc_vers = txdr_unsigned(RPC_VER2); 60633965Sjdp rpc_call = txdr_unsigned(RPC_CALL); 60733965Sjdp rpc_reply = txdr_unsigned(RPC_REPLY); 60833965Sjdp rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 60933965Sjdp rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 61033965Sjdp rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 61133965Sjdp rpc_autherr = txdr_unsigned(RPC_AUTHERR); 61233965Sjdp rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 61333965Sjdp rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 61433965Sjdp rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 61533965Sjdp nfs_vers = txdr_unsigned(NFS_VER2); 61633965Sjdp nfs_prog = txdr_unsigned(NFS_PROG); 61733965Sjdp nfs_true = txdr_unsigned(TRUE); 61833965Sjdp nfs_false = txdr_unsigned(FALSE); 61933965Sjdp nfs_xdrneg1 = txdr_unsigned(-1); 62033965Sjdp /* Loop thru nfs procids */ 62133965Sjdp for (i = 0; i < NFS_NPROCS; i++) 62233965Sjdp nfs_procids[i] = txdr_unsigned(i); 62333965Sjdp /* Ensure async daemons disabled */ 62433965Sjdp for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 62533965Sjdp nfs_iodwant[i] = (struct proc *)0; 62633965Sjdp TAILQ_INIT(&nfs_bufq); 62733965Sjdp nfs_nhinit(); /* Init the nfsnode table */ 62833965Sjdp nfsrv_init(0); /* Init server data structures */ 62933965Sjdp nfsrv_initcache(); /* Init the server request cache */ 63033965Sjdp 63133965Sjdp /* 63233965Sjdp * Initialize the nqnfs server stuff. 63333965Sjdp */ 63433965Sjdp if (nqnfsstarttime == 0) { 63533965Sjdp nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 63633965Sjdp + nqsrv_clockskew + nqsrv_writeslack; 63733965Sjdp NQLOADNOVRAM(nqnfsstarttime); 63833965Sjdp nqnfs_prog = txdr_unsigned(NQNFS_PROG); 63933965Sjdp nqnfs_vers = txdr_unsigned(NQNFS_VER1); 64033965Sjdp CIRCLEQ_INIT(&nqtimerhead); 64133965Sjdp nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 64233965Sjdp } 64333965Sjdp 64433965Sjdp /* 64533965Sjdp * Initialize reply list and start timer 64633965Sjdp */ 64733965Sjdp TAILQ_INIT(&nfs_reqq); 64833965Sjdp nfs_timer(0); 64933965Sjdp 65033965Sjdp /* 65133965Sjdp * Set up lease_check and lease_updatetime so that other parts 65233965Sjdp * of the system can call us, if we are loadable. 65333965Sjdp */ 65433965Sjdp lease_check = nfs_lease_check; 65533965Sjdp lease_updatetime = nfs_lease_updatetime; 65633965Sjdp vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ 65733965Sjdp#ifdef VFS_LKM 65833965Sjdp sysent[SYS_nfssvc].sy_narg = 2; 65933965Sjdp sysent[SYS_nfssvc].sy_call = nfssvc; 66033965Sjdp sysent[SYS_getfh].sy_narg = 2; 66133965Sjdp sysent[SYS_getfh].sy_call = getfh; 66233965Sjdp#endif 66333965Sjdp 66433965Sjdp return (0); 66533965Sjdp} 66633965Sjdp 66733965Sjdp/* 66833965Sjdp * Attribute cache routines. 66933965Sjdp * nfs_loadattrcache() - loads or updates the cache contents from attributes 67033965Sjdp * that are on the mbuf list 67133965Sjdp * nfs_getattrcache() - returns valid attributes if found in cache, returns 67233965Sjdp * error otherwise 67333965Sjdp */ 67433965Sjdp 67533965Sjdp/* 67633965Sjdp * Load the attribute cache (that lives in the nfsnode entry) with 67733965Sjdp * the values on the mbuf list and 67833965Sjdp * Iff vap not NULL 67933965Sjdp * copy the attributes to *vaper 68033965Sjdp */ 68133965Sjdpint 68233965Sjdpnfs_loadattrcache(vpp, mdp, dposp, vaper) 68333965Sjdp struct vnode **vpp; 68433965Sjdp struct mbuf **mdp; 68533965Sjdp caddr_t *dposp; 68633965Sjdp struct vattr *vaper; 68733965Sjdp{ 68833965Sjdp register struct vnode *vp = *vpp; 68933965Sjdp register struct vattr *vap; 69033965Sjdp register struct nfsv2_fattr *fp; 69133965Sjdp extern int (**spec_nfsv2nodeop_p)(); 69233965Sjdp register struct nfsnode *np; 69333965Sjdp register struct nfsnodehashhead *nhpp; 69433965Sjdp register long t1; 69533965Sjdp caddr_t dpos, cp2; 69633965Sjdp int error = 0, isnq; 69733965Sjdp struct mbuf *md; 69833965Sjdp enum vtype vtyp; 69933965Sjdp u_short vmode; 70033965Sjdp long rdev; 70133965Sjdp struct timespec mtime; 70233965Sjdp struct vnode *nvp; 70333965Sjdp 70433965Sjdp md = *mdp; 70533965Sjdp dpos = *dposp; 70633965Sjdp t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 70733965Sjdp isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 70833965Sjdp error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2); 70933965Sjdp if (error) 71033965Sjdp return (error); 71133965Sjdp fp = (struct nfsv2_fattr *)cp2; 71233965Sjdp vtyp = nfstov_type(fp->fa_type); 71333965Sjdp vmode = fxdr_unsigned(u_short, fp->fa_mode); 71433965Sjdp if (vtyp == VNON || vtyp == VREG) 71533965Sjdp vtyp = IFTOVT(vmode); 71633965Sjdp if (isnq) { 71733965Sjdp rdev = fxdr_unsigned(long, fp->fa_nqrdev); 71833965Sjdp fxdr_nqtime(&fp->fa_nqmtime, &mtime); 71933965Sjdp } else { 72033965Sjdp rdev = fxdr_unsigned(long, fp->fa_nfsrdev); 72133965Sjdp fxdr_nfstime(&fp->fa_nfsmtime, &mtime); 72233965Sjdp } 72333965Sjdp /* 72433965Sjdp * If v_type == VNON it is a new node, so fill in the v_type, 72533965Sjdp * n_mtime fields. Check to see if it represents a special 72633965Sjdp * device, and if so, check for a possible alias. Once the 72733965Sjdp * correct vnode has been obtained, fill in the rest of the 72833965Sjdp * information. 72933965Sjdp */ 73033965Sjdp np = VTONFS(vp); 73133965Sjdp if (vp->v_type == VNON) { 73233965Sjdp if (vtyp == VCHR && rdev == 0xffffffff) 73333965Sjdp vp->v_type = vtyp = VFIFO; 73433965Sjdp else 73533965Sjdp vp->v_type = vtyp; 73633965Sjdp if (vp->v_type == VFIFO) { 73733965Sjdp extern int (**fifo_nfsv2nodeop_p)(); 73833965Sjdp vp->v_op = fifo_nfsv2nodeop_p; 73933965Sjdp } 74033965Sjdp if (vp->v_type == VCHR || vp->v_type == VBLK) { 74133965Sjdp vp->v_op = spec_nfsv2nodeop_p; 74233965Sjdp nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 74333965Sjdp if (nvp) { 74433965Sjdp /* 74533965Sjdp * Discard unneeded vnode, but save its nfsnode. 74633965Sjdp */ 74733965Sjdp LIST_REMOVE(np, n_hash); 74833965Sjdp nvp->v_data = vp->v_data; 74933965Sjdp vp->v_data = NULL; 75033965Sjdp vp->v_op = spec_vnodeop_p; 75133965Sjdp vrele(vp); 75233965Sjdp vgone(vp); 75333965Sjdp /* 75433965Sjdp * Reinitialize aliased node. 75533965Sjdp */ 75633965Sjdp np->n_vnode = nvp; 75733965Sjdp nhpp = nfs_hash(&np->n_fh); 75833965Sjdp LIST_INSERT_HEAD(nhpp, np, n_hash); 75933965Sjdp *vpp = vp = nvp; 76033965Sjdp } 76133965Sjdp } 76233965Sjdp np->n_mtime = mtime.ts_sec; 76333965Sjdp } 76433965Sjdp vap = &np->n_vattr; 76533965Sjdp vap->va_type = vtyp; 76633965Sjdp vap->va_mode = (vmode & 07777); 76733965Sjdp vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 76833965Sjdp vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 76933965Sjdp vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 77033965Sjdp vap->va_rdev = (dev_t)rdev; 77133965Sjdp vap->va_mtime = mtime; 77233965Sjdp vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 77333965Sjdp if (isnq) { 77433965Sjdp fxdr_hyper(&fp->fa_nqsize, &vap->va_size); 77533965Sjdp vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); 77633965Sjdp fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); 77733965Sjdp vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); 77833965Sjdp fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); 77933965Sjdp vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); 78033965Sjdp fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); 78133965Sjdp vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); 78233965Sjdp fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); 78333965Sjdp } else { 78433965Sjdp vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); 78533965Sjdp vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); 78633965Sjdp vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; 78733965Sjdp vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); 78833965Sjdp fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime); 78933965Sjdp vap->va_flags = 0; 79033965Sjdp fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime); 79133965Sjdp vap->va_gen = 0; 79233965Sjdp vap->va_filerev = 0; 79333965Sjdp } 79433965Sjdp if (vap->va_size != np->n_size) { 79533965Sjdp if (vap->va_type == VREG) { 79633965Sjdp if (np->n_flag & NMODIFIED) { 79733965Sjdp if (vap->va_size < np->n_size) 79833965Sjdp vap->va_size = np->n_size; 79933965Sjdp else 80033965Sjdp np->n_size = vap->va_size; 80133965Sjdp } else 80233965Sjdp np->n_size = vap->va_size; 80333965Sjdp vnode_pager_setsize(vp, (u_long)np->n_size); 80433965Sjdp } else 80533965Sjdp np->n_size = vap->va_size; 80633965Sjdp } 80733965Sjdp np->n_attrstamp = time.tv_sec; 80833965Sjdp *dposp = dpos; 80933965Sjdp *mdp = md; 81033965Sjdp if (vaper != NULL) { 81133965Sjdp bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 81233965Sjdp#ifdef notdef 81333965Sjdp if ((np->n_flag & NMODIFIED) && np->n_size > vap->va_size) 81433965Sjdp if (np->n_size > vap->va_size) 81533965Sjdp vaper->va_size = np->n_size; 81633965Sjdp#endif 81733965Sjdp if (np->n_flag & NCHG) { 81833965Sjdp if (np->n_flag & NACC) { 81933965Sjdp vaper->va_atime.ts_sec = np->n_atim.tv_sec; 82033965Sjdp vaper->va_atime.ts_nsec = 82133965Sjdp np->n_atim.tv_usec * 1000; 82233965Sjdp } 82333965Sjdp if (np->n_flag & NUPD) { 82433965Sjdp vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 82533965Sjdp vaper->va_mtime.ts_nsec = 82633965Sjdp np->n_mtim.tv_usec * 1000; 82733965Sjdp } 82833965Sjdp } 82933965Sjdp } 83033965Sjdp return (0); 83133965Sjdp} 83233965Sjdp 83333965Sjdp/* 83433965Sjdp * Check the time stamp 83533965Sjdp * If the cache is valid, copy contents to *vap and return 0 83633965Sjdp * otherwise return an error 83733965Sjdp */ 83833965Sjdpint 83933965Sjdpnfs_getattrcache(vp, vaper) 84033965Sjdp register struct vnode *vp; 84133965Sjdp struct vattr *vaper; 84233965Sjdp{ 84333965Sjdp register struct nfsnode *np = VTONFS(vp); 84433965Sjdp register struct vattr *vap; 84533965Sjdp 84633965Sjdp if (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQLOOKLEASE) { 84733965Sjdp if (!NQNFS_CKCACHABLE(vp, NQL_READ) || np->n_attrstamp == 0) { 84833965Sjdp nfsstats.attrcache_misses++; 84933965Sjdp return (ENOENT); 85033965Sjdp } 851 } else if ((time.tv_sec - np->n_attrstamp) >= NFS_ATTRTIMEO(np)) { 852 nfsstats.attrcache_misses++; 853 return (ENOENT); 854 } 855 nfsstats.attrcache_hits++; 856 vap = &np->n_vattr; 857 if (vap->va_size != np->n_size) { 858 if (vap->va_type == VREG) { 859 if (np->n_flag & NMODIFIED) { 860 if (vap->va_size < np->n_size) 861 vap->va_size = np->n_size; 862 else 863 np->n_size = vap->va_size; 864 } else 865 np->n_size = vap->va_size; 866 vnode_pager_setsize(vp, (u_long)np->n_size); 867 } else 868 np->n_size = vap->va_size; 869 } 870 bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(struct vattr)); 871#ifdef notdef 872 if ((np->n_flag & NMODIFIED) == 0) { 873 np->n_size = vaper->va_size; 874 vnode_pager_setsize(vp, (u_long)np->n_size); 875 } else if (np->n_size > vaper->va_size) 876 if (np->n_size > vaper->va_size) 877 vaper->va_size = np->n_size; 878#endif 879 if (np->n_flag & NCHG) { 880 if (np->n_flag & NACC) { 881 vaper->va_atime.ts_sec = np->n_atim.tv_sec; 882 vaper->va_atime.ts_nsec = np->n_atim.tv_usec * 1000; 883 } 884 if (np->n_flag & NUPD) { 885 vaper->va_mtime.ts_sec = np->n_mtim.tv_sec; 886 vaper->va_mtime.ts_nsec = np->n_mtim.tv_usec * 1000; 887 } 888 } 889 return (0); 890} 891 892/* 893 * Set up nameidata for a lookup() call and do it 894 */ 895int 896nfs_namei(ndp, fhp, len, slp, nam, mdp, dposp, p) 897 register struct nameidata *ndp; 898 fhandle_t *fhp; 899 int len; 900 struct nfssvc_sock *slp; 901 struct mbuf *nam; 902 struct mbuf **mdp; 903 caddr_t *dposp; 904 struct proc *p; 905{ 906 register int i, rem; 907 register struct mbuf *md; 908 register char *fromcp, *tocp; 909 struct vnode *dp; 910 int error, rdonly; 911 struct componentname *cnp = &ndp->ni_cnd; 912 913 MALLOC(cnp->cn_pnbuf, char *, len + 1, M_NAMEI, M_WAITOK); 914 /* 915 * Copy the name from the mbuf list to ndp->ni_pnbuf 916 * and set the various ndp fields appropriately. 917 */ 918 fromcp = *dposp; 919 tocp = cnp->cn_pnbuf; 920 md = *mdp; 921 rem = mtod(md, caddr_t) + md->m_len - fromcp; 922 cnp->cn_hash = 0; 923 for (i = 0; i < len; i++) { 924 while (rem == 0) { 925 md = md->m_next; 926 if (md == NULL) { 927 error = EBADRPC; 928 goto out; 929 } 930 fromcp = mtod(md, caddr_t); 931 rem = md->m_len; 932 } 933 if (*fromcp == '\0' || *fromcp == '/') { 934 error = EINVAL; 935 goto out; 936 } 937 cnp->cn_hash += (unsigned char)*fromcp; 938 *tocp++ = *fromcp++; 939 rem--; 940 } 941 *tocp = '\0'; 942 *mdp = md; 943 *dposp = fromcp; 944 len = nfsm_rndup(len)-len; 945 if (len > 0) { 946 if (rem >= len) 947 *dposp += len; 948 else { 949 error = nfs_adv(mdp, dposp, len, rem); 950 if (error) 951 goto out; 952 } 953 } 954 ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 955 cnp->cn_nameptr = cnp->cn_pnbuf; 956 /* 957 * Extract and set starting directory. 958 */ 959 error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 960 nam, &rdonly); 961 if (error) 962 goto out; 963 if (dp->v_type != VDIR) { 964 vrele(dp); 965 error = ENOTDIR; 966 goto out; 967 } 968 ndp->ni_startdir = dp; 969 if (rdonly) 970 cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 971 else 972 cnp->cn_flags |= NOCROSSMOUNT; 973 /* 974 * And call lookup() to do the real work 975 */ 976 cnp->cn_proc = p; 977 error = lookup(ndp); 978 if (error) 979 goto out; 980 /* 981 * Check for encountering a symbolic link 982 */ 983 if (cnp->cn_flags & ISSYMLINK) { 984 if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 985 vput(ndp->ni_dvp); 986 else 987 vrele(ndp->ni_dvp); 988 vput(ndp->ni_vp); 989 ndp->ni_vp = NULL; 990 error = EINVAL; 991 goto out; 992 } 993 /* 994 * Check for saved name request 995 */ 996 if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 997 cnp->cn_flags |= HASBUF; 998 nfsrv_vmio( ndp->ni_vp); 999 return (0); 1000 } 1001out: 1002 FREE(cnp->cn_pnbuf, M_NAMEI); 1003 return (error); 1004} 1005 1006/* 1007 * A fiddled version of m_adj() that ensures null fill to a long 1008 * boundary and only trims off the back end 1009 */ 1010void 1011nfsm_adj(mp, len, nul) 1012 struct mbuf *mp; 1013 register int len; 1014 int nul; 1015{ 1016 register struct mbuf *m; 1017 register int count, i; 1018 register char *cp; 1019 1020 /* 1021 * Trim from tail. Scan the mbuf chain, 1022 * calculating its length and finding the last mbuf. 1023 * If the adjustment only affects this mbuf, then just 1024 * adjust and return. Otherwise, rescan and truncate 1025 * after the remaining size. 1026 */ 1027 count = 0; 1028 m = mp; 1029 for (;;) { 1030 count += m->m_len; 1031 if (m->m_next == (struct mbuf *)0) 1032 break; 1033 m = m->m_next; 1034 } 1035 if (m->m_len > len) { 1036 m->m_len -= len; 1037 if (nul > 0) { 1038 cp = mtod(m, caddr_t)+m->m_len-nul; 1039 for (i = 0; i < nul; i++) 1040 *cp++ = '\0'; 1041 } 1042 return; 1043 } 1044 count -= len; 1045 if (count < 0) 1046 count = 0; 1047 /* 1048 * Correct length for chain is "count". 1049 * Find the mbuf with last data, adjust its length, 1050 * and toss data from remaining mbufs on chain. 1051 */ 1052 for (m = mp; m; m = m->m_next) { 1053 if (m->m_len >= count) { 1054 m->m_len = count; 1055 if (nul > 0) { 1056 cp = mtod(m, caddr_t)+m->m_len-nul; 1057 for (i = 0; i < nul; i++) 1058 *cp++ = '\0'; 1059 } 1060 break; 1061 } 1062 count -= m->m_len; 1063 } 1064 for (m = m->m_next;m;m = m->m_next) 1065 m->m_len = 0; 1066} 1067 1068/* 1069 * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 1070 * - look up fsid in mount list (if not found ret error) 1071 * - get vp and export rights by calling VFS_FHTOVP() 1072 * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 1073 * - if not lockflag unlock it with VOP_UNLOCK() 1074 */ 1075int 1076nfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 1077 fhandle_t *fhp; 1078 int lockflag; 1079 struct vnode **vpp; 1080 struct ucred *cred; 1081 struct nfssvc_sock *slp; 1082 struct mbuf *nam; 1083 int *rdonlyp; 1084{ 1085 register struct mount *mp; 1086 register struct nfsuid *uidp; 1087 register int i; 1088 struct ucred *credanon; 1089 int error, exflags; 1090 1091 *vpp = (struct vnode *)0; 1092 mp = getvfs(&fhp->fh_fsid); 1093 if (!mp) 1094 return (ESTALE); 1095 error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 1096 if (error) 1097 return (error); 1098 /* 1099 * Check/setup credentials. 1100 */ 1101 if (exflags & MNT_EXKERB) { 1102 for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0; 1103 uidp = uidp->nu_hash.le_next) { 1104 if (uidp->nu_uid == cred->cr_uid) 1105 break; 1106 } 1107 if (uidp == 0) { 1108 vput(*vpp); 1109 return (NQNFS_AUTHERR); 1110 } 1111 cred->cr_uid = uidp->nu_cr.cr_uid; 1112 for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) 1113 cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; 1114 cred->cr_ngroups = i; 1115 } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 1116 cred->cr_uid = credanon->cr_uid; 1117 for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 1118 cred->cr_groups[i] = credanon->cr_groups[i]; 1119 cred->cr_ngroups = i; 1120 } 1121 if (exflags & MNT_EXRDONLY) 1122 *rdonlyp = 1; 1123 else 1124 *rdonlyp = 0; 1125 if (!lockflag) 1126 VOP_UNLOCK(*vpp); 1127 nfsrv_vmio(*vpp); 1128 return (0); 1129} 1130 1131/* 1132 * This function compares two net addresses by family and returns TRUE 1133 * if they are the same host. 1134 * If there is any doubt, return FALSE. 1135 * The AF_INET family is handled as a special case so that address mbufs 1136 * don't need to be saved to store "struct in_addr", which is only 4 bytes. 1137 */ 1138int 1139netaddr_match(family, haddr, nam) 1140 int family; 1141 union nethostaddr *haddr; 1142 struct mbuf *nam; 1143{ 1144 register struct sockaddr_in *inetaddr; 1145 1146 switch (family) { 1147 case AF_INET: 1148 inetaddr = mtod(nam, struct sockaddr_in *); 1149 if (inetaddr->sin_family == AF_INET && 1150 inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 1151 return (1); 1152 break; 1153#ifdef ISO 1154 case AF_ISO: 1155 { 1156 register struct sockaddr_iso *isoaddr1, *isoaddr2; 1157 1158 isoaddr1 = mtod(nam, struct sockaddr_iso *); 1159 isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 1160 if (isoaddr1->siso_family == AF_ISO && 1161 isoaddr1->siso_nlen > 0 && 1162 isoaddr1->siso_nlen == isoaddr2->siso_nlen && 1163 SAME_ISOADDR(isoaddr1, isoaddr2)) 1164 return (1); 1165 break; 1166 } 1167#endif /* ISO */ 1168 default: 1169 break; 1170 }; 1171 return (0); 1172} 1173 1174int 1175nfsrv_vmio( struct vnode *vp) { 1176 int rtval; 1177 vm_object_t object; 1178 vm_pager_t pager; 1179 1180 if( (vp == NULL) || (vp->v_type != VREG)) 1181 return 1; 1182 1183retry: 1184 if( (vp->v_flag & VVMIO) == 0) { 1185 pager = (vm_pager_t) vnode_pager_alloc(vp, 0, 0, 0); 1186 object = (vm_object_t) vp->v_vmdata; 1187 if( object->pager != pager) 1188 panic("nfsrv_vmio: pager/object mismatch"); 1189 (void) vm_object_lookup( pager); 1190 pager_cache( object, TRUE); 1191 vp->v_flag |= VVMIO; 1192 } else { 1193 if( (object = (vm_object_t)vp->v_vmdata) && 1194 (object->flags & OBJ_DEAD)) { 1195 tsleep( (caddr_t) object, PVM, "nfdead", 0); 1196 goto retry; 1197 } 1198 if( !object) 1199 panic("nfsrv_vmio: VMIO object missing"); 1200 pager = object->pager; 1201 if( !pager) 1202 panic("nfsrv_vmio: VMIO pager missing"); 1203 (void) vm_object_lookup( pager); 1204 } 1205 return 0; 1206} 1207int 1208nfsrv_vput( struct vnode *vp) { 1209 if( (vp->v_flag & VVMIO) && vp->v_vmdata) { 1210 vput( vp); 1211 vm_object_deallocate( (vm_object_t) vp->v_vmdata); 1212 } else { 1213 vput( vp); 1214 } 1215 return 0; 1216} 1217int 1218nfsrv_vrele( struct vnode *vp) { 1219 if( (vp->v_flag & VVMIO) && vp->v_vmdata) { 1220 vrele( vp); 1221 vm_object_deallocate( (vm_object_t) vp->v_vmdata); 1222 } else { 1223 vrele( vp); 1224 } 1225 return 0; 1226} 1227