nfs_srvsubs.c revision 6420
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 376420Sphk * $Id: nfs_subs.c,v 1.10 1995/02/15 03:40:00 davidg Exp $ 381541Srgrimes */ 391541Srgrimes 401541Srgrimes/* 411541Srgrimes * These functions support the macros and help fiddle mbuf chains for 421541Srgrimes * the nfs op functions. They do things like create the rpc header and 431541Srgrimes * copy data between mbuf chains and uio lists. 441541Srgrimes */ 451541Srgrimes#include <sys/param.h> 461541Srgrimes#include <sys/proc.h> 471541Srgrimes#include <sys/systm.h> 481541Srgrimes#include <sys/kernel.h> 491541Srgrimes#include <sys/mount.h> 501541Srgrimes#include <sys/vnode.h> 511541Srgrimes#include <sys/namei.h> 521541Srgrimes#include <sys/mbuf.h> 531541Srgrimes#include <sys/socket.h> 541541Srgrimes#include <sys/stat.h> 552997Swollman#ifdef VFS_LKM 562997Swollman#include <sys/sysent.h> 572997Swollman#include <sys/syscall.h> 582997Swollman#endif 591541Srgrimes 603305Sphk#include <vm/vm.h> 613305Sphk 621541Srgrimes#include <nfs/rpcv2.h> 631541Srgrimes#include <nfs/nfsv2.h> 641541Srgrimes#include <nfs/nfsnode.h> 651541Srgrimes#include <nfs/nfs.h> 661541Srgrimes#include <nfs/xdr_subs.h> 671541Srgrimes#include <nfs/nfsm_subs.h> 681541Srgrimes#include <nfs/nfsmount.h> 691541Srgrimes#include <nfs/nqnfs.h> 701541Srgrimes#include <nfs/nfsrtt.h> 711541Srgrimes 721541Srgrimes#include <miscfs/specfs/specdev.h> 731541Srgrimes 746420Sphk#include <vm/vnode_pager.h> 756420Sphk 761541Srgrimes#include <netinet/in.h> 771541Srgrimes#ifdef ISO 781541Srgrimes#include <netiso/iso.h> 791541Srgrimes#endif 801541Srgrimes 811541Srgrimes#define TRUE 1 821541Srgrimes#define FALSE 0 831541Srgrimes 841541Srgrimes/* 851541Srgrimes * Data items converted to xdr at startup, since they are constant 861541Srgrimes * This is kinda hokey, but may save a little time doing byte swaps 871541Srgrimes */ 881541Srgrimesu_long nfs_procids[NFS_NPROCS]; 891541Srgrimesu_long nfs_xdrneg1; 901541Srgrimesu_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, rpc_autherr, 911541Srgrimes rpc_mismatch, rpc_auth_unix, rpc_msgaccepted, rpc_rejectedcred, 921541Srgrimes rpc_auth_kerb; 931541Srgrimesu_long nfs_vers, nfs_prog, nfs_true, nfs_false; 941541Srgrimes 951541Srgrimes/* And other global data */ 961541Srgrimesstatic u_long nfs_xid = 0; 971541Srgrimesenum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON }; 981541Srgrimesextern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON]; 991541Srgrimesextern int nqnfs_piggy[NFS_NPROCS]; 1001541Srgrimesextern struct nfsrtt nfsrtt; 1011541Srgrimesextern time_t nqnfsstarttime; 1021541Srgrimesextern u_long nqnfs_prog, nqnfs_vers; 1031541Srgrimesextern int nqsrv_clockskew; 1041541Srgrimesextern int nqsrv_writeslack; 1051541Srgrimesextern int nqsrv_maxlease; 1061541Srgrimes 1072997Swollman#ifdef VFS_LKM 1082997Swollmanstruct getfh_args; 1092997Swollmanextern int getfh(struct proc *, struct getfh_args *, int *); 1102997Swollmanstruct nfssvc_args; 1112997Swollmanextern int nfssvc(struct proc *, struct nfssvc_args *, int *); 1122997Swollman#endif 1132997Swollman 1143664SphkLIST_HEAD(nfsnodehashhead, nfsnode); 1153664Sphk 1161541Srgrimes/* 1171541Srgrimes * Create the header for an rpc request packet 1181541Srgrimes * The hsiz is the size of the rest of the nfs request header. 1191541Srgrimes * (just used to decide if a cluster is a good idea) 1201541Srgrimes */ 1211541Srgrimesstruct mbuf * 1221541Srgrimesnfsm_reqh(vp, procid, hsiz, bposp) 1231541Srgrimes struct vnode *vp; 1241541Srgrimes u_long procid; 1251541Srgrimes int hsiz; 1261541Srgrimes caddr_t *bposp; 1271541Srgrimes{ 1281541Srgrimes register struct mbuf *mb; 1291541Srgrimes register u_long *tl; 1301541Srgrimes register caddr_t bpos; 1311541Srgrimes struct mbuf *mb2; 1321541Srgrimes struct nfsmount *nmp; 1331541Srgrimes int nqflag; 1341541Srgrimes 1351541Srgrimes MGET(mb, M_WAIT, MT_DATA); 1361541Srgrimes if (hsiz >= MINCLSIZE) 1371541Srgrimes MCLGET(mb, M_WAIT); 1381541Srgrimes mb->m_len = 0; 1391541Srgrimes bpos = mtod(mb, caddr_t); 1401541Srgrimes 1411541Srgrimes /* 1421541Srgrimes * For NQNFS, add lease request. 1431541Srgrimes */ 1441541Srgrimes if (vp) { 1451541Srgrimes nmp = VFSTONFS(vp->v_mount); 1461541Srgrimes if (nmp->nm_flag & NFSMNT_NQNFS) { 1471541Srgrimes nqflag = NQNFS_NEEDLEASE(vp, procid); 1481541Srgrimes if (nqflag) { 1491541Srgrimes nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 1501541Srgrimes *tl++ = txdr_unsigned(nqflag); 1511541Srgrimes *tl = txdr_unsigned(nmp->nm_leaseterm); 1521541Srgrimes } else { 1531541Srgrimes nfsm_build(tl, u_long *, NFSX_UNSIGNED); 1541541Srgrimes *tl = 0; 1551541Srgrimes } 1561541Srgrimes } 1571541Srgrimes } 1581541Srgrimes /* Finally, return values */ 1591541Srgrimes *bposp = bpos; 1601541Srgrimes return (mb); 1611541Srgrimes} 1621541Srgrimes 1631541Srgrimes/* 1641541Srgrimes * Build the RPC header and fill in the authorization info. 1651541Srgrimes * The authorization string argument is only used when the credentials 1661541Srgrimes * come from outside of the kernel. 1671541Srgrimes * Returns the head of the mbuf list. 1681541Srgrimes */ 1691541Srgrimesstruct mbuf * 1701541Srgrimesnfsm_rpchead(cr, nqnfs, procid, auth_type, auth_len, auth_str, mrest, 1711541Srgrimes mrest_len, mbp, xidp) 1721541Srgrimes register struct ucred *cr; 1731541Srgrimes int nqnfs; 1741541Srgrimes int procid; 1751541Srgrimes int auth_type; 1761541Srgrimes int auth_len; 1771541Srgrimes char *auth_str; 1781541Srgrimes struct mbuf *mrest; 1791541Srgrimes int mrest_len; 1801541Srgrimes struct mbuf **mbp; 1811541Srgrimes u_long *xidp; 1821541Srgrimes{ 1831541Srgrimes register struct mbuf *mb; 1841541Srgrimes register u_long *tl; 1851541Srgrimes register caddr_t bpos; 1861541Srgrimes register int i; 1871541Srgrimes struct mbuf *mreq, *mb2; 1881541Srgrimes int siz, grpsiz, authsiz; 1891541Srgrimes 1901541Srgrimes authsiz = nfsm_rndup(auth_len); 1911541Srgrimes if (auth_type == RPCAUTH_NQNFS) 1921541Srgrimes authsiz += 2 * NFSX_UNSIGNED; 1931541Srgrimes MGETHDR(mb, M_WAIT, MT_DATA); 1941541Srgrimes if ((authsiz + 10*NFSX_UNSIGNED) >= MINCLSIZE) { 1951541Srgrimes MCLGET(mb, M_WAIT); 1961541Srgrimes } else if ((authsiz + 10*NFSX_UNSIGNED) < MHLEN) { 1971541Srgrimes MH_ALIGN(mb, authsiz + 10*NFSX_UNSIGNED); 1981541Srgrimes } else { 1991541Srgrimes MH_ALIGN(mb, 8*NFSX_UNSIGNED); 2001541Srgrimes } 2011541Srgrimes mb->m_len = 0; 2021541Srgrimes mreq = mb; 2031541Srgrimes bpos = mtod(mb, caddr_t); 2041541Srgrimes 2051541Srgrimes /* 2061541Srgrimes * First the RPC header. 2071541Srgrimes */ 2081541Srgrimes nfsm_build(tl, u_long *, 8*NFSX_UNSIGNED); 2091541Srgrimes if (++nfs_xid == 0) 2101541Srgrimes nfs_xid++; 2111541Srgrimes *tl++ = *xidp = txdr_unsigned(nfs_xid); 2121541Srgrimes *tl++ = rpc_call; 2131541Srgrimes *tl++ = rpc_vers; 2141541Srgrimes if (nqnfs) { 2151541Srgrimes *tl++ = txdr_unsigned(NQNFS_PROG); 2161541Srgrimes *tl++ = txdr_unsigned(NQNFS_VER1); 2171541Srgrimes } else { 2181541Srgrimes *tl++ = txdr_unsigned(NFS_PROG); 2191541Srgrimes *tl++ = txdr_unsigned(NFS_VER2); 2201541Srgrimes } 2211541Srgrimes *tl++ = txdr_unsigned(procid); 2221541Srgrimes 2231541Srgrimes /* 2241541Srgrimes * And then the authorization cred. 2251541Srgrimes */ 2261541Srgrimes *tl++ = txdr_unsigned(auth_type); 2271541Srgrimes *tl = txdr_unsigned(authsiz); 2281541Srgrimes switch (auth_type) { 2291541Srgrimes case RPCAUTH_UNIX: 2301541Srgrimes nfsm_build(tl, u_long *, auth_len); 2311541Srgrimes *tl++ = 0; /* stamp ?? */ 2321541Srgrimes *tl++ = 0; /* NULL hostname */ 2331541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 2341541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[0]); 2351541Srgrimes grpsiz = (auth_len >> 2) - 5; 2361541Srgrimes *tl++ = txdr_unsigned(grpsiz); 2371541Srgrimes for (i = 1; i <= grpsiz; i++) 2381541Srgrimes *tl++ = txdr_unsigned(cr->cr_groups[i]); 2391541Srgrimes break; 2401541Srgrimes case RPCAUTH_NQNFS: 2411541Srgrimes nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 2421541Srgrimes *tl++ = txdr_unsigned(cr->cr_uid); 2431541Srgrimes *tl = txdr_unsigned(auth_len); 2441541Srgrimes siz = auth_len; 2451541Srgrimes while (siz > 0) { 2461541Srgrimes if (M_TRAILINGSPACE(mb) == 0) { 2471541Srgrimes MGET(mb2, M_WAIT, MT_DATA); 2481541Srgrimes if (siz >= MINCLSIZE) 2491541Srgrimes MCLGET(mb2, M_WAIT); 2501541Srgrimes mb->m_next = mb2; 2511541Srgrimes mb = mb2; 2521541Srgrimes mb->m_len = 0; 2531541Srgrimes bpos = mtod(mb, caddr_t); 2541541Srgrimes } 2551541Srgrimes i = min(siz, M_TRAILINGSPACE(mb)); 2561541Srgrimes bcopy(auth_str, bpos, i); 2571541Srgrimes mb->m_len += i; 2581541Srgrimes auth_str += i; 2591541Srgrimes bpos += i; 2601541Srgrimes siz -= i; 2611541Srgrimes } 2621541Srgrimes if ((siz = (nfsm_rndup(auth_len) - auth_len)) > 0) { 2631541Srgrimes for (i = 0; i < siz; i++) 2641541Srgrimes *bpos++ = '\0'; 2651541Srgrimes mb->m_len += siz; 2661541Srgrimes } 2671541Srgrimes break; 2681541Srgrimes }; 2691541Srgrimes nfsm_build(tl, u_long *, 2*NFSX_UNSIGNED); 2701541Srgrimes *tl++ = txdr_unsigned(RPCAUTH_NULL); 2711541Srgrimes *tl = 0; 2721541Srgrimes mb->m_next = mrest; 2731541Srgrimes mreq->m_pkthdr.len = authsiz + 10*NFSX_UNSIGNED + mrest_len; 2741541Srgrimes mreq->m_pkthdr.rcvif = (struct ifnet *)0; 2751541Srgrimes *mbp = mb; 2761541Srgrimes return (mreq); 2771541Srgrimes} 2781541Srgrimes 2791541Srgrimes/* 2801541Srgrimes * copies mbuf chain to the uio scatter/gather list 2811541Srgrimes */ 2821549Srgrimesint 2831541Srgrimesnfsm_mbuftouio(mrep, uiop, siz, dpos) 2841541Srgrimes struct mbuf **mrep; 2851541Srgrimes register struct uio *uiop; 2861541Srgrimes int siz; 2871541Srgrimes caddr_t *dpos; 2881541Srgrimes{ 2891541Srgrimes register char *mbufcp, *uiocp; 2901541Srgrimes register int xfer, left, len; 2911541Srgrimes register struct mbuf *mp; 2921541Srgrimes long uiosiz, rem; 2931541Srgrimes int error = 0; 2941541Srgrimes 2951541Srgrimes mp = *mrep; 2961541Srgrimes mbufcp = *dpos; 2971541Srgrimes len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 2981541Srgrimes rem = nfsm_rndup(siz)-siz; 2991541Srgrimes while (siz > 0) { 3001541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 3011541Srgrimes return (EFBIG); 3021541Srgrimes left = uiop->uio_iov->iov_len; 3031541Srgrimes uiocp = uiop->uio_iov->iov_base; 3041541Srgrimes if (left > siz) 3051541Srgrimes left = siz; 3061541Srgrimes uiosiz = left; 3071541Srgrimes while (left > 0) { 3081541Srgrimes while (len == 0) { 3091541Srgrimes mp = mp->m_next; 3101541Srgrimes if (mp == NULL) 3111541Srgrimes return (EBADRPC); 3121541Srgrimes mbufcp = mtod(mp, caddr_t); 3131541Srgrimes len = mp->m_len; 3141541Srgrimes } 3151541Srgrimes xfer = (left > len) ? len : left; 3161541Srgrimes#ifdef notdef 3171541Srgrimes /* Not Yet.. */ 3181541Srgrimes if (uiop->uio_iov->iov_op != NULL) 3191541Srgrimes (*(uiop->uio_iov->iov_op)) 3201541Srgrimes (mbufcp, uiocp, xfer); 3211541Srgrimes else 3221541Srgrimes#endif 3231541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 3241541Srgrimes bcopy(mbufcp, uiocp, xfer); 3251541Srgrimes else 3261541Srgrimes copyout(mbufcp, uiocp, xfer); 3271541Srgrimes left -= xfer; 3281541Srgrimes len -= xfer; 3291541Srgrimes mbufcp += xfer; 3301541Srgrimes uiocp += xfer; 3311541Srgrimes uiop->uio_offset += xfer; 3321541Srgrimes uiop->uio_resid -= xfer; 3331541Srgrimes } 3341541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 3351541Srgrimes uiop->uio_iovcnt--; 3361541Srgrimes uiop->uio_iov++; 3371541Srgrimes } else { 3381541Srgrimes uiop->uio_iov->iov_base += uiosiz; 3391541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 3401541Srgrimes } 3411541Srgrimes siz -= uiosiz; 3421541Srgrimes } 3431541Srgrimes *dpos = mbufcp; 3441541Srgrimes *mrep = mp; 3451541Srgrimes if (rem > 0) { 3461541Srgrimes if (len < rem) 3471541Srgrimes error = nfs_adv(mrep, dpos, rem, len); 3481541Srgrimes else 3491541Srgrimes *dpos += rem; 3501541Srgrimes } 3511541Srgrimes return (error); 3521541Srgrimes} 3531541Srgrimes 3541541Srgrimes/* 3551541Srgrimes * copies a uio scatter/gather list to an mbuf chain... 3561541Srgrimes */ 3571549Srgrimesint 3581541Srgrimesnfsm_uiotombuf(uiop, mq, siz, bpos) 3591541Srgrimes register struct uio *uiop; 3601541Srgrimes struct mbuf **mq; 3611541Srgrimes int siz; 3621541Srgrimes caddr_t *bpos; 3631541Srgrimes{ 3641541Srgrimes register char *uiocp; 3651541Srgrimes register struct mbuf *mp, *mp2; 3661541Srgrimes register int xfer, left, mlen; 3671541Srgrimes int uiosiz, clflg, rem; 3681541Srgrimes char *cp; 3691541Srgrimes 3701541Srgrimes if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 3711541Srgrimes clflg = 1; 3721541Srgrimes else 3731541Srgrimes clflg = 0; 3741541Srgrimes rem = nfsm_rndup(siz)-siz; 3751541Srgrimes mp = mp2 = *mq; 3761541Srgrimes while (siz > 0) { 3771541Srgrimes if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 3781541Srgrimes return (EINVAL); 3791541Srgrimes left = uiop->uio_iov->iov_len; 3801541Srgrimes uiocp = uiop->uio_iov->iov_base; 3811541Srgrimes if (left > siz) 3821541Srgrimes left = siz; 3831541Srgrimes uiosiz = left; 3841541Srgrimes while (left > 0) { 3851541Srgrimes mlen = M_TRAILINGSPACE(mp); 3861541Srgrimes if (mlen == 0) { 3871541Srgrimes MGET(mp, M_WAIT, MT_DATA); 3881541Srgrimes if (clflg) 3891541Srgrimes MCLGET(mp, M_WAIT); 3901541Srgrimes mp->m_len = 0; 3911541Srgrimes mp2->m_next = mp; 3921541Srgrimes mp2 = mp; 3931541Srgrimes mlen = M_TRAILINGSPACE(mp); 3941541Srgrimes } 3951541Srgrimes xfer = (left > mlen) ? mlen : left; 3961541Srgrimes#ifdef notdef 3971541Srgrimes /* Not Yet.. */ 3981541Srgrimes if (uiop->uio_iov->iov_op != NULL) 3991541Srgrimes (*(uiop->uio_iov->iov_op)) 4001541Srgrimes (uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 4011541Srgrimes else 4021541Srgrimes#endif 4031541Srgrimes if (uiop->uio_segflg == UIO_SYSSPACE) 4041541Srgrimes bcopy(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 4051541Srgrimes else 4061541Srgrimes copyin(uiocp, mtod(mp, caddr_t)+mp->m_len, xfer); 4071541Srgrimes mp->m_len += xfer; 4081541Srgrimes left -= xfer; 4091541Srgrimes uiocp += xfer; 4101541Srgrimes uiop->uio_offset += xfer; 4111541Srgrimes uiop->uio_resid -= xfer; 4121541Srgrimes } 4131541Srgrimes if (uiop->uio_iov->iov_len <= siz) { 4141541Srgrimes uiop->uio_iovcnt--; 4151541Srgrimes uiop->uio_iov++; 4161541Srgrimes } else { 4171541Srgrimes uiop->uio_iov->iov_base += uiosiz; 4181541Srgrimes uiop->uio_iov->iov_len -= uiosiz; 4191541Srgrimes } 4201541Srgrimes siz -= uiosiz; 4211541Srgrimes } 4221541Srgrimes if (rem > 0) { 4231541Srgrimes if (rem > M_TRAILINGSPACE(mp)) { 4241541Srgrimes MGET(mp, M_WAIT, MT_DATA); 4251541Srgrimes mp->m_len = 0; 4261541Srgrimes mp2->m_next = mp; 4271541Srgrimes } 4281541Srgrimes cp = mtod(mp, caddr_t)+mp->m_len; 4291541Srgrimes for (left = 0; left < rem; left++) 4301541Srgrimes *cp++ = '\0'; 4311541Srgrimes mp->m_len += rem; 4321541Srgrimes *bpos = cp; 4331541Srgrimes } else 4341541Srgrimes *bpos = mtod(mp, caddr_t)+mp->m_len; 4351541Srgrimes *mq = mp; 4361541Srgrimes return (0); 4371541Srgrimes} 4381541Srgrimes 4391541Srgrimes/* 4401541Srgrimes * Help break down an mbuf chain by setting the first siz bytes contiguous 4411541Srgrimes * pointed to by returned val. 4421541Srgrimes * This is used by the macros nfsm_dissect and nfsm_dissecton for tough 4431541Srgrimes * cases. (The macros use the vars. dpos and dpos2) 4441541Srgrimes */ 4451549Srgrimesint 4461541Srgrimesnfsm_disct(mdp, dposp, siz, left, cp2) 4471541Srgrimes struct mbuf **mdp; 4481541Srgrimes caddr_t *dposp; 4491541Srgrimes int siz; 4501541Srgrimes int left; 4511541Srgrimes caddr_t *cp2; 4521541Srgrimes{ 4531541Srgrimes register struct mbuf *mp, *mp2; 4541541Srgrimes register int siz2, xfer; 4551541Srgrimes register caddr_t p; 4561541Srgrimes 4571541Srgrimes mp = *mdp; 4581541Srgrimes while (left == 0) { 4591541Srgrimes *mdp = mp = mp->m_next; 4601541Srgrimes if (mp == NULL) 4611541Srgrimes return (EBADRPC); 4621541Srgrimes left = mp->m_len; 4631541Srgrimes *dposp = mtod(mp, caddr_t); 4641541Srgrimes } 4651541Srgrimes if (left >= siz) { 4661541Srgrimes *cp2 = *dposp; 4671541Srgrimes *dposp += siz; 4681541Srgrimes } else if (mp->m_next == NULL) { 4691541Srgrimes return (EBADRPC); 4701541Srgrimes } else if (siz > MHLEN) { 4711541Srgrimes panic("nfs S too big"); 4721541Srgrimes } else { 4731541Srgrimes MGET(mp2, M_WAIT, MT_DATA); 4741541Srgrimes mp2->m_next = mp->m_next; 4751541Srgrimes mp->m_next = mp2; 4761541Srgrimes mp->m_len -= left; 4771541Srgrimes mp = mp2; 4781541Srgrimes *cp2 = p = mtod(mp, caddr_t); 4791541Srgrimes bcopy(*dposp, p, left); /* Copy what was left */ 4801541Srgrimes siz2 = siz-left; 4811541Srgrimes p += left; 4821541Srgrimes mp2 = mp->m_next; 4831541Srgrimes /* Loop around copying up the siz2 bytes */ 4841541Srgrimes while (siz2 > 0) { 4851541Srgrimes if (mp2 == NULL) 4861541Srgrimes return (EBADRPC); 4871541Srgrimes xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 4881541Srgrimes if (xfer > 0) { 4891541Srgrimes bcopy(mtod(mp2, caddr_t), p, xfer); 4901541Srgrimes NFSMADV(mp2, xfer); 4911541Srgrimes mp2->m_len -= xfer; 4921541Srgrimes p += xfer; 4931541Srgrimes siz2 -= xfer; 4941541Srgrimes } 4951541Srgrimes if (siz2 > 0) 4961541Srgrimes mp2 = mp2->m_next; 4971541Srgrimes } 4981541Srgrimes mp->m_len = siz; 4991541Srgrimes *mdp = mp2; 5001541Srgrimes *dposp = mtod(mp2, caddr_t); 5011541Srgrimes } 5021541Srgrimes return (0); 5031541Srgrimes} 5041541Srgrimes 5051541Srgrimes/* 5061541Srgrimes * Advance the position in the mbuf chain. 5071541Srgrimes */ 5081549Srgrimesint 5091541Srgrimesnfs_adv(mdp, dposp, offs, left) 5101541Srgrimes struct mbuf **mdp; 5111541Srgrimes caddr_t *dposp; 5121541Srgrimes int offs; 5131541Srgrimes int left; 5141541Srgrimes{ 5151541Srgrimes register struct mbuf *m; 5161541Srgrimes register int s; 5171541Srgrimes 5181541Srgrimes m = *mdp; 5191541Srgrimes s = left; 5201541Srgrimes while (s < offs) { 5211541Srgrimes offs -= s; 5221541Srgrimes m = m->m_next; 5231541Srgrimes if (m == NULL) 5241541Srgrimes return (EBADRPC); 5251541Srgrimes s = m->m_len; 5261541Srgrimes } 5271541Srgrimes *mdp = m; 5281541Srgrimes *dposp = mtod(m, caddr_t)+offs; 5291541Srgrimes return (0); 5301541Srgrimes} 5311541Srgrimes 5321541Srgrimes/* 5331541Srgrimes * Copy a string into mbufs for the hard cases... 5341541Srgrimes */ 5351549Srgrimesint 5361541Srgrimesnfsm_strtmbuf(mb, bpos, cp, siz) 5371541Srgrimes struct mbuf **mb; 5381541Srgrimes char **bpos; 5391541Srgrimes char *cp; 5401541Srgrimes long siz; 5411541Srgrimes{ 5421549Srgrimes register struct mbuf *m1 = 0, *m2; 5431541Srgrimes long left, xfer, len, tlen; 5441541Srgrimes u_long *tl; 5451541Srgrimes int putsize; 5461541Srgrimes 5471541Srgrimes putsize = 1; 5481541Srgrimes m2 = *mb; 5491541Srgrimes left = M_TRAILINGSPACE(m2); 5501541Srgrimes if (left > 0) { 5511541Srgrimes tl = ((u_long *)(*bpos)); 5521541Srgrimes *tl++ = txdr_unsigned(siz); 5531541Srgrimes putsize = 0; 5541541Srgrimes left -= NFSX_UNSIGNED; 5551541Srgrimes m2->m_len += NFSX_UNSIGNED; 5561541Srgrimes if (left > 0) { 5571541Srgrimes bcopy(cp, (caddr_t) tl, left); 5581541Srgrimes siz -= left; 5591541Srgrimes cp += left; 5601541Srgrimes m2->m_len += left; 5611541Srgrimes left = 0; 5621541Srgrimes } 5631541Srgrimes } 5641541Srgrimes /* Loop around adding mbufs */ 5651541Srgrimes while (siz > 0) { 5661541Srgrimes MGET(m1, M_WAIT, MT_DATA); 5671541Srgrimes if (siz > MLEN) 5681541Srgrimes MCLGET(m1, M_WAIT); 5691541Srgrimes m1->m_len = NFSMSIZ(m1); 5701541Srgrimes m2->m_next = m1; 5711541Srgrimes m2 = m1; 5721541Srgrimes tl = mtod(m1, u_long *); 5731541Srgrimes tlen = 0; 5741541Srgrimes if (putsize) { 5751541Srgrimes *tl++ = txdr_unsigned(siz); 5761541Srgrimes m1->m_len -= NFSX_UNSIGNED; 5771541Srgrimes tlen = NFSX_UNSIGNED; 5781541Srgrimes putsize = 0; 5791541Srgrimes } 5801541Srgrimes if (siz < m1->m_len) { 5811541Srgrimes len = nfsm_rndup(siz); 5821541Srgrimes xfer = siz; 5831541Srgrimes if (xfer < len) 5841541Srgrimes *(tl+(xfer>>2)) = 0; 5851541Srgrimes } else { 5861541Srgrimes xfer = len = m1->m_len; 5871541Srgrimes } 5881541Srgrimes bcopy(cp, (caddr_t) tl, xfer); 5891541Srgrimes m1->m_len = len+tlen; 5901541Srgrimes siz -= xfer; 5911541Srgrimes cp += xfer; 5921541Srgrimes } 5931541Srgrimes *mb = m1; 5941541Srgrimes *bpos = mtod(m1, caddr_t)+m1->m_len; 5951541Srgrimes return (0); 5961541Srgrimes} 5971541Srgrimes 5981541Srgrimes/* 5991541Srgrimes * Called once to initialize data structures... 6001541Srgrimes */ 6011549Srgrimesint 6021541Srgrimesnfs_init() 6031541Srgrimes{ 6041541Srgrimes register int i; 6051541Srgrimes 6061541Srgrimes nfsrtt.pos = 0; 6071541Srgrimes rpc_vers = txdr_unsigned(RPC_VER2); 6081541Srgrimes rpc_call = txdr_unsigned(RPC_CALL); 6091541Srgrimes rpc_reply = txdr_unsigned(RPC_REPLY); 6101541Srgrimes rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 6111541Srgrimes rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 6121541Srgrimes rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 6131541Srgrimes rpc_autherr = txdr_unsigned(RPC_AUTHERR); 6141541Srgrimes rpc_rejectedcred = txdr_unsigned(AUTH_REJECTCRED); 6151541Srgrimes rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 6161541Srgrimes rpc_auth_kerb = txdr_unsigned(RPCAUTH_NQNFS); 6171541Srgrimes nfs_vers = txdr_unsigned(NFS_VER2); 6181541Srgrimes nfs_prog = txdr_unsigned(NFS_PROG); 6191541Srgrimes nfs_true = txdr_unsigned(TRUE); 6201541Srgrimes nfs_false = txdr_unsigned(FALSE); 6213664Sphk nfs_xdrneg1 = txdr_unsigned(-1); 6221541Srgrimes /* Loop thru nfs procids */ 6231541Srgrimes for (i = 0; i < NFS_NPROCS; i++) 6241541Srgrimes nfs_procids[i] = txdr_unsigned(i); 6251541Srgrimes /* Ensure async daemons disabled */ 6261541Srgrimes for (i = 0; i < NFS_MAXASYNCDAEMON; i++) 6271541Srgrimes nfs_iodwant[i] = (struct proc *)0; 6281541Srgrimes TAILQ_INIT(&nfs_bufq); 6291541Srgrimes nfs_nhinit(); /* Init the nfsnode table */ 6301541Srgrimes nfsrv_init(0); /* Init server data structures */ 6311541Srgrimes nfsrv_initcache(); /* Init the server request cache */ 6321541Srgrimes 6331541Srgrimes /* 6341541Srgrimes * Initialize the nqnfs server stuff. 6351541Srgrimes */ 6361541Srgrimes if (nqnfsstarttime == 0) { 6371541Srgrimes nqnfsstarttime = boottime.tv_sec + nqsrv_maxlease 6381541Srgrimes + nqsrv_clockskew + nqsrv_writeslack; 6391541Srgrimes NQLOADNOVRAM(nqnfsstarttime); 6401541Srgrimes nqnfs_prog = txdr_unsigned(NQNFS_PROG); 6411541Srgrimes nqnfs_vers = txdr_unsigned(NQNFS_VER1); 6423664Sphk CIRCLEQ_INIT(&nqtimerhead); 6433664Sphk nqfhhashtbl = hashinit(NQLCHSZ, M_NQLEASE, &nqfhhash); 6441541Srgrimes } 6451541Srgrimes 6461541Srgrimes /* 6471541Srgrimes * Initialize reply list and start timer 6481541Srgrimes */ 6493664Sphk TAILQ_INIT(&nfs_reqq); 6503305Sphk nfs_timer(0); 6511549Srgrimes 6522997Swollman /* 6532997Swollman * Set up lease_check and lease_updatetime so that other parts 6542997Swollman * of the system can call us, if we are loadable. 6552997Swollman */ 6562997Swollman lease_check = nfs_lease_check; 6572997Swollman lease_updatetime = nfs_lease_updatetime; 6582997Swollman vfsconf[MOUNT_NFS]->vfc_refcount++; /* make us non-unloadable */ 6592997Swollman#ifdef VFS_LKM 6602997Swollman sysent[SYS_nfssvc].sy_narg = 2; 6612997Swollman sysent[SYS_nfssvc].sy_call = nfssvc; 6622997Swollman sysent[SYS_getfh].sy_narg = 2; 6632997Swollman sysent[SYS_getfh].sy_call = getfh; 6642997Swollman#endif 6652997Swollman 6661549Srgrimes return (0); 6671541Srgrimes} 6681541Srgrimes 6691541Srgrimes/* 6701541Srgrimes * Attribute cache routines. 6711541Srgrimes * nfs_loadattrcache() - loads or updates the cache contents from attributes 6721541Srgrimes * that are on the mbuf list 6731541Srgrimes * nfs_getattrcache() - returns valid attributes if found in cache, returns 6741541Srgrimes * error otherwise 6751541Srgrimes */ 6761541Srgrimes 6771541Srgrimes/* 6781541Srgrimes * Load the attribute cache (that lives in the nfsnode entry) with 6791541Srgrimes * the values on the mbuf list and 6801541Srgrimes * Iff vap not NULL 6811541Srgrimes * copy the attributes to *vaper 6821541Srgrimes */ 6831549Srgrimesint 6841541Srgrimesnfs_loadattrcache(vpp, mdp, dposp, vaper) 6851541Srgrimes struct vnode **vpp; 6861541Srgrimes struct mbuf **mdp; 6871541Srgrimes caddr_t *dposp; 6881541Srgrimes struct vattr *vaper; 6891541Srgrimes{ 6901541Srgrimes register struct vnode *vp = *vpp; 6911541Srgrimes register struct vattr *vap; 6921541Srgrimes register struct nfsv2_fattr *fp; 6931541Srgrimes extern int (**spec_nfsv2nodeop_p)(); 6943664Sphk register struct nfsnode *np; 6953664Sphk register struct nfsnodehashhead *nhpp; 6961541Srgrimes register long t1; 6971541Srgrimes caddr_t dpos, cp2; 6981541Srgrimes int error = 0, isnq; 6991541Srgrimes struct mbuf *md; 7001541Srgrimes enum vtype vtyp; 7011541Srgrimes u_short vmode; 7021541Srgrimes long rdev; 7031541Srgrimes struct timespec mtime; 7041541Srgrimes struct vnode *nvp; 7051541Srgrimes 7061541Srgrimes md = *mdp; 7071541Srgrimes dpos = *dposp; 7081541Srgrimes t1 = (mtod(md, caddr_t) + md->m_len) - dpos; 7091541Srgrimes isnq = (VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS); 7103305Sphk error = nfsm_disct(&md, &dpos, NFSX_FATTR(isnq), t1, &cp2); 7113305Sphk if (error) 7121541Srgrimes return (error); 7131541Srgrimes fp = (struct nfsv2_fattr *)cp2; 7141541Srgrimes vtyp = nfstov_type(fp->fa_type); 7151541Srgrimes vmode = fxdr_unsigned(u_short, fp->fa_mode); 7161541Srgrimes if (vtyp == VNON || vtyp == VREG) 7171541Srgrimes vtyp = IFTOVT(vmode); 7181541Srgrimes if (isnq) { 7191541Srgrimes rdev = fxdr_unsigned(long, fp->fa_nqrdev); 7201541Srgrimes fxdr_nqtime(&fp->fa_nqmtime, &mtime); 7211541Srgrimes } else { 7221541Srgrimes rdev = fxdr_unsigned(long, fp->fa_nfsrdev); 7231541Srgrimes fxdr_nfstime(&fp->fa_nfsmtime, &mtime); 7241541Srgrimes } 7251541Srgrimes /* 7261541Srgrimes * If v_type == VNON it is a new node, so fill in the v_type, 7271541Srgrimes * n_mtime fields. Check to see if it represents a special 7281541Srgrimes * device, and if so, check for a possible alias. Once the 7291541Srgrimes * correct vnode has been obtained, fill in the rest of the 7301541Srgrimes * information. 7311541Srgrimes */ 7321541Srgrimes np = VTONFS(vp); 7331541Srgrimes if (vp->v_type == VNON) { 7341541Srgrimes if (vtyp == VCHR && rdev == 0xffffffff) 7351541Srgrimes vp->v_type = vtyp = VFIFO; 7361541Srgrimes else 7371541Srgrimes vp->v_type = vtyp; 7381541Srgrimes if (vp->v_type == VFIFO) { 7391541Srgrimes extern int (**fifo_nfsv2nodeop_p)(); 7401541Srgrimes vp->v_op = fifo_nfsv2nodeop_p; 7411541Srgrimes } 7421541Srgrimes if (vp->v_type == VCHR || vp->v_type == VBLK) { 7431541Srgrimes vp->v_op = spec_nfsv2nodeop_p; 7443305Sphk nvp = checkalias(vp, (dev_t)rdev, vp->v_mount); 7453305Sphk if (nvp) { 7461541Srgrimes /* 7471541Srgrimes * Discard unneeded vnode, but save its nfsnode. 7481541Srgrimes */ 7493664Sphk LIST_REMOVE(np, n_hash); 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; 7593664Sphk nhpp = nfs_hash(&np->n_fh); 7603664Sphk LIST_INSERT_HEAD(nhpp, np, n_hash); 7611541Srgrimes *vpp = vp = nvp; 7621541Srgrimes } 7631541Srgrimes } 7641541Srgrimes np->n_mtime = mtime.ts_sec; 7651541Srgrimes } 7661541Srgrimes vap = &np->n_vattr; 7671541Srgrimes vap->va_type = vtyp; 7681541Srgrimes vap->va_mode = (vmode & 07777); 7691541Srgrimes vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 7701541Srgrimes vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 7711541Srgrimes vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 7721541Srgrimes vap->va_rdev = (dev_t)rdev; 7731541Srgrimes vap->va_mtime = mtime; 7741541Srgrimes vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0]; 7751541Srgrimes if (isnq) { 7761541Srgrimes fxdr_hyper(&fp->fa_nqsize, &vap->va_size); 7771541Srgrimes vap->va_blocksize = fxdr_unsigned(long, fp->fa_nqblocksize); 7781541Srgrimes fxdr_hyper(&fp->fa_nqbytes, &vap->va_bytes); 7791541Srgrimes vap->va_fileid = fxdr_unsigned(long, fp->fa_nqfileid); 7801541Srgrimes fxdr_nqtime(&fp->fa_nqatime, &vap->va_atime); 7811541Srgrimes vap->va_flags = fxdr_unsigned(u_long, fp->fa_nqflags); 7821541Srgrimes fxdr_nqtime(&fp->fa_nqctime, &vap->va_ctime); 7831541Srgrimes vap->va_gen = fxdr_unsigned(u_long, fp->fa_nqgen); 7841541Srgrimes fxdr_hyper(&fp->fa_nqfilerev, &vap->va_filerev); 7851541Srgrimes } else { 7861541Srgrimes vap->va_size = fxdr_unsigned(u_long, fp->fa_nfssize); 7871541Srgrimes vap->va_blocksize = fxdr_unsigned(long, fp->fa_nfsblocksize); 7881541Srgrimes vap->va_bytes = fxdr_unsigned(long, fp->fa_nfsblocks) * NFS_FABLKSIZE; 7891541Srgrimes vap->va_fileid = fxdr_unsigned(long, fp->fa_nfsfileid); 7901541Srgrimes fxdr_nfstime(&fp->fa_nfsatime, &vap->va_atime); 7911541Srgrimes vap->va_flags = 0; 7923664Sphk fxdr_nfstime(&fp->fa_nfsctime, &vap->va_ctime); 7933664Sphk vap->va_gen = 0; 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; 9503305Sphk else { 9513305Sphk error = nfs_adv(mdp, dposp, len, rem); 9523305Sphk if (error) 9533305Sphk goto out; 9543305Sphk } 9551541Srgrimes } 9561541Srgrimes ndp->ni_pathlen = tocp - cnp->cn_pnbuf; 9571541Srgrimes cnp->cn_nameptr = cnp->cn_pnbuf; 9581541Srgrimes /* 9591541Srgrimes * Extract and set starting directory. 9601541Srgrimes */ 9613305Sphk error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cnd.cn_cred, slp, 9623305Sphk nam, &rdonly); 9633305Sphk if (error) 9641541Srgrimes goto out; 9651541Srgrimes if (dp->v_type != VDIR) { 9666417Sdg nfsrv_vrele(dp); 9671541Srgrimes error = ENOTDIR; 9681541Srgrimes goto out; 9691541Srgrimes } 9701541Srgrimes ndp->ni_startdir = dp; 9711541Srgrimes if (rdonly) 9721541Srgrimes cnp->cn_flags |= (NOCROSSMOUNT | RDONLY); 9731541Srgrimes else 9741541Srgrimes cnp->cn_flags |= NOCROSSMOUNT; 9751541Srgrimes /* 9761541Srgrimes * And call lookup() to do the real work 9771541Srgrimes */ 9781541Srgrimes cnp->cn_proc = p; 9793305Sphk error = lookup(ndp); 9803305Sphk if (error) 9811541Srgrimes goto out; 9821541Srgrimes /* 9831541Srgrimes * Check for encountering a symbolic link 9841541Srgrimes */ 9851541Srgrimes if (cnp->cn_flags & ISSYMLINK) { 9861541Srgrimes if ((cnp->cn_flags & LOCKPARENT) && ndp->ni_pathlen == 1) 9871541Srgrimes vput(ndp->ni_dvp); 9881541Srgrimes else 9891541Srgrimes vrele(ndp->ni_dvp); 9901541Srgrimes vput(ndp->ni_vp); 9911541Srgrimes ndp->ni_vp = NULL; 9921541Srgrimes error = EINVAL; 9931541Srgrimes goto out; 9941541Srgrimes } 9951541Srgrimes /* 9961541Srgrimes * Check for saved name request 9971541Srgrimes */ 9981541Srgrimes if (cnp->cn_flags & (SAVENAME | SAVESTART)) { 9991541Srgrimes cnp->cn_flags |= HASBUF; 10005455Sdg nfsrv_vmio( ndp->ni_vp); 10011541Srgrimes return (0); 10021541Srgrimes } 10031541Srgrimesout: 10041541Srgrimes FREE(cnp->cn_pnbuf, M_NAMEI); 10051541Srgrimes return (error); 10061541Srgrimes} 10071541Srgrimes 10081541Srgrimes/* 10091541Srgrimes * A fiddled version of m_adj() that ensures null fill to a long 10101541Srgrimes * boundary and only trims off the back end 10111541Srgrimes */ 10121541Srgrimesvoid 10131541Srgrimesnfsm_adj(mp, len, nul) 10141541Srgrimes struct mbuf *mp; 10151541Srgrimes register int len; 10161541Srgrimes int nul; 10171541Srgrimes{ 10181541Srgrimes register struct mbuf *m; 10191541Srgrimes register int count, i; 10201541Srgrimes register char *cp; 10211541Srgrimes 10221541Srgrimes /* 10231541Srgrimes * Trim from tail. Scan the mbuf chain, 10241541Srgrimes * calculating its length and finding the last mbuf. 10251541Srgrimes * If the adjustment only affects this mbuf, then just 10261541Srgrimes * adjust and return. Otherwise, rescan and truncate 10271541Srgrimes * after the remaining size. 10281541Srgrimes */ 10291541Srgrimes count = 0; 10301541Srgrimes m = mp; 10311541Srgrimes for (;;) { 10321541Srgrimes count += m->m_len; 10331541Srgrimes if (m->m_next == (struct mbuf *)0) 10341541Srgrimes break; 10351541Srgrimes m = m->m_next; 10361541Srgrimes } 10371541Srgrimes if (m->m_len > len) { 10381541Srgrimes m->m_len -= len; 10391541Srgrimes if (nul > 0) { 10401541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 10411541Srgrimes for (i = 0; i < nul; i++) 10421541Srgrimes *cp++ = '\0'; 10431541Srgrimes } 10441541Srgrimes return; 10451541Srgrimes } 10461541Srgrimes count -= len; 10471541Srgrimes if (count < 0) 10481541Srgrimes count = 0; 10491541Srgrimes /* 10501541Srgrimes * Correct length for chain is "count". 10511541Srgrimes * Find the mbuf with last data, adjust its length, 10521541Srgrimes * and toss data from remaining mbufs on chain. 10531541Srgrimes */ 10541541Srgrimes for (m = mp; m; m = m->m_next) { 10551541Srgrimes if (m->m_len >= count) { 10561541Srgrimes m->m_len = count; 10571541Srgrimes if (nul > 0) { 10581541Srgrimes cp = mtod(m, caddr_t)+m->m_len-nul; 10591541Srgrimes for (i = 0; i < nul; i++) 10601541Srgrimes *cp++ = '\0'; 10611541Srgrimes } 10621541Srgrimes break; 10631541Srgrimes } 10641541Srgrimes count -= m->m_len; 10651541Srgrimes } 10663305Sphk for (m = m->m_next;m;m = m->m_next) 10671541Srgrimes m->m_len = 0; 10681541Srgrimes} 10691541Srgrimes 10701541Srgrimes/* 10711541Srgrimes * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 10721541Srgrimes * - look up fsid in mount list (if not found ret error) 10731541Srgrimes * - get vp and export rights by calling VFS_FHTOVP() 10741541Srgrimes * - if cred->cr_uid == 0 or MNT_EXPORTANON set it to credanon 10751541Srgrimes * - if not lockflag unlock it with VOP_UNLOCK() 10761541Srgrimes */ 10771549Srgrimesint 10781541Srgrimesnfsrv_fhtovp(fhp, lockflag, vpp, cred, slp, nam, rdonlyp) 10791541Srgrimes fhandle_t *fhp; 10801541Srgrimes int lockflag; 10811541Srgrimes struct vnode **vpp; 10821541Srgrimes struct ucred *cred; 10831541Srgrimes struct nfssvc_sock *slp; 10841541Srgrimes struct mbuf *nam; 10851541Srgrimes int *rdonlyp; 10861541Srgrimes{ 10871541Srgrimes register struct mount *mp; 10881541Srgrimes register struct nfsuid *uidp; 10891541Srgrimes register int i; 10901541Srgrimes struct ucred *credanon; 10911541Srgrimes int error, exflags; 10921541Srgrimes 10931541Srgrimes *vpp = (struct vnode *)0; 10943305Sphk mp = getvfs(&fhp->fh_fsid); 10953305Sphk if (!mp) 10961541Srgrimes return (ESTALE); 10973305Sphk error = VFS_FHTOVP(mp, &fhp->fh_fid, nam, vpp, &exflags, &credanon); 10983305Sphk if (error) 10991541Srgrimes return (error); 11001541Srgrimes /* 11011541Srgrimes * Check/setup credentials. 11021541Srgrimes */ 11031541Srgrimes if (exflags & MNT_EXKERB) { 11043664Sphk for (uidp = NUIDHASH(slp, cred->cr_uid)->lh_first; uidp != 0; 11053664Sphk uidp = uidp->nu_hash.le_next) { 11061541Srgrimes if (uidp->nu_uid == cred->cr_uid) 11071541Srgrimes break; 11081541Srgrimes } 11093664Sphk if (uidp == 0) { 11101541Srgrimes vput(*vpp); 11111541Srgrimes return (NQNFS_AUTHERR); 11121541Srgrimes } 11133664Sphk cred->cr_uid = uidp->nu_cr.cr_uid; 11143664Sphk for (i = 0; i < uidp->nu_cr.cr_ngroups; i++) 11153664Sphk cred->cr_groups[i] = uidp->nu_cr.cr_groups[i]; 11163664Sphk cred->cr_ngroups = i; 11171541Srgrimes } else if (cred->cr_uid == 0 || (exflags & MNT_EXPORTANON)) { 11181541Srgrimes cred->cr_uid = credanon->cr_uid; 11191541Srgrimes for (i = 0; i < credanon->cr_ngroups && i < NGROUPS; i++) 11201541Srgrimes cred->cr_groups[i] = credanon->cr_groups[i]; 11213664Sphk cred->cr_ngroups = i; 11221541Srgrimes } 11231541Srgrimes if (exflags & MNT_EXRDONLY) 11241541Srgrimes *rdonlyp = 1; 11251541Srgrimes else 11261541Srgrimes *rdonlyp = 0; 11271541Srgrimes if (!lockflag) 11281541Srgrimes VOP_UNLOCK(*vpp); 11295455Sdg nfsrv_vmio(*vpp); 11301541Srgrimes return (0); 11311541Srgrimes} 11321541Srgrimes 11331541Srgrimes/* 11341541Srgrimes * This function compares two net addresses by family and returns TRUE 11351541Srgrimes * if they are the same host. 11361541Srgrimes * If there is any doubt, return FALSE. 11371541Srgrimes * The AF_INET family is handled as a special case so that address mbufs 11381541Srgrimes * don't need to be saved to store "struct in_addr", which is only 4 bytes. 11391541Srgrimes */ 11401549Srgrimesint 11411541Srgrimesnetaddr_match(family, haddr, nam) 11421541Srgrimes int family; 11431541Srgrimes union nethostaddr *haddr; 11441541Srgrimes struct mbuf *nam; 11451541Srgrimes{ 11461541Srgrimes register struct sockaddr_in *inetaddr; 11471541Srgrimes 11481541Srgrimes switch (family) { 11491541Srgrimes case AF_INET: 11501541Srgrimes inetaddr = mtod(nam, struct sockaddr_in *); 11511541Srgrimes if (inetaddr->sin_family == AF_INET && 11521541Srgrimes inetaddr->sin_addr.s_addr == haddr->had_inetaddr) 11531541Srgrimes return (1); 11541541Srgrimes break; 11551541Srgrimes#ifdef ISO 11561541Srgrimes case AF_ISO: 11571541Srgrimes { 11581541Srgrimes register struct sockaddr_iso *isoaddr1, *isoaddr2; 11591541Srgrimes 11601541Srgrimes isoaddr1 = mtod(nam, struct sockaddr_iso *); 11611541Srgrimes isoaddr2 = mtod(haddr->had_nam, struct sockaddr_iso *); 11621541Srgrimes if (isoaddr1->siso_family == AF_ISO && 11631541Srgrimes isoaddr1->siso_nlen > 0 && 11641541Srgrimes isoaddr1->siso_nlen == isoaddr2->siso_nlen && 11651541Srgrimes SAME_ISOADDR(isoaddr1, isoaddr2)) 11661541Srgrimes return (1); 11671541Srgrimes break; 11681541Srgrimes } 11691541Srgrimes#endif /* ISO */ 11701541Srgrimes default: 11711541Srgrimes break; 11721541Srgrimes }; 11731541Srgrimes return (0); 11741541Srgrimes} 11755455Sdg 11765455Sdgint 11775455Sdgnfsrv_vmio( struct vnode *vp) { 11785455Sdg vm_object_t object; 11795455Sdg vm_pager_t pager; 11805455Sdg 11815455Sdg if( (vp == NULL) || (vp->v_type != VREG)) 11825455Sdg return 1; 11835455Sdg 11845455Sdgretry: 11855455Sdg if( (vp->v_flag & VVMIO) == 0) { 11866420Sphk pager = (vm_pager_t) vnode_pager_alloc((caddr_t) vp, 0, 0, 0); 11875455Sdg object = (vm_object_t) vp->v_vmdata; 11885455Sdg if( object->pager != pager) 11895455Sdg panic("nfsrv_vmio: pager/object mismatch"); 11905455Sdg (void) vm_object_lookup( pager); 11915455Sdg pager_cache( object, TRUE); 11925455Sdg vp->v_flag |= VVMIO; 11935455Sdg } else { 11945455Sdg if( (object = (vm_object_t)vp->v_vmdata) && 11955455Sdg (object->flags & OBJ_DEAD)) { 11965455Sdg tsleep( (caddr_t) object, PVM, "nfdead", 0); 11975455Sdg goto retry; 11985455Sdg } 11995455Sdg if( !object) 12005455Sdg panic("nfsrv_vmio: VMIO object missing"); 12015455Sdg pager = object->pager; 12025455Sdg if( !pager) 12035455Sdg panic("nfsrv_vmio: VMIO pager missing"); 12045455Sdg (void) vm_object_lookup( pager); 12055455Sdg } 12065455Sdg return 0; 12075455Sdg} 12085455Sdgint 12095455Sdgnfsrv_vput( struct vnode *vp) { 12105455Sdg if( (vp->v_flag & VVMIO) && vp->v_vmdata) { 12116210Sdg vput( vp); 12125455Sdg vm_object_deallocate( (vm_object_t) vp->v_vmdata); 12136210Sdg } else { 12146210Sdg vput( vp); 12155455Sdg } 12165455Sdg return 0; 12175455Sdg} 12185455Sdgint 12195455Sdgnfsrv_vrele( struct vnode *vp) { 12205455Sdg if( (vp->v_flag & VVMIO) && vp->v_vmdata) { 12216210Sdg vrele( vp); 12225455Sdg vm_object_deallocate( (vm_object_t) vp->v_vmdata); 12236210Sdg } else { 12246210Sdg vrele( vp); 12255455Sdg } 12265455Sdg return 0; 12275455Sdg} 1228