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