138420Smckusick /* 238420Smckusick * Copyright (c) 1989 The Regents of the University of California. 338420Smckusick * All rights reserved. 438420Smckusick * 538420Smckusick * This code is derived from software contributed to Berkeley by 638420Smckusick * Rick Macklem at The University of Guelph. 738420Smckusick * 838420Smckusick * Redistribution and use in source and binary forms are permitted 938420Smckusick * provided that the above copyright notice and this paragraph are 1038420Smckusick * duplicated in all such forms and that any documentation, 1138420Smckusick * advertising materials, and other materials related to such 1238420Smckusick * distribution and use acknowledge that the software was developed 1338420Smckusick * by the University of California, Berkeley. The name of the 1438420Smckusick * University may not be used to endorse or promote products derived 1538420Smckusick * from this software without specific prior written permission. 1638420Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1738420Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1838420Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1938420Smckusick * 20*39345Smckusick * @(#)nfs_subs.c 7.8 (Berkeley) 10/19/89 2138420Smckusick */ 2238420Smckusick 2338420Smckusick /* 2438420Smckusick * These functions support the macros and help fiddle mbuf chains for 2538420Smckusick * the nfs op functions. They do things like create the rpc header and 2638420Smckusick * copy data between mbuf chains and uio lists. 2738420Smckusick */ 2838420Smckusick #include "strings.h" 2938420Smckusick #include "types.h" 3038420Smckusick #include "param.h" 31*39345Smckusick #include "user.h" 32*39345Smckusick #include "proc.h" 3338420Smckusick #include "mount.h" 3438425Smckusick #include "../ufs/dir.h" 3538420Smckusick #include "time.h" 3638420Smckusick #include "errno.h" 3738420Smckusick #include "kernel.h" 3838420Smckusick #include "malloc.h" 3938420Smckusick #include "mbuf.h" 4038420Smckusick #include "file.h" 4138420Smckusick #include "vnode.h" 4238420Smckusick #include "uio.h" 4338420Smckusick #include "namei.h" 4438420Smckusick #include "ucred.h" 4538884Smacklem #include "map.h" 4638420Smckusick #include "rpcv2.h" 4738420Smckusick #include "nfsv2.h" 4838420Smckusick #include "nfsnode.h" 4938420Smckusick #include "nfs.h" 5038884Smacklem #include "nfsiom.h" 5138420Smckusick #include "xdr_subs.h" 5238420Smckusick #include "nfsm_subs.h" 5338420Smckusick 5438420Smckusick #define TRUE 1 5538420Smckusick #define FALSE 0 5638420Smckusick 5738420Smckusick /* 5838420Smckusick * Data items converted to xdr at startup, since they are constant 5938420Smckusick * This is kinda hokey, but may save a little time doing byte swaps 6038420Smckusick */ 6138420Smckusick u_long nfs_procids[NFS_NPROCS]; 6238420Smckusick u_long nfs_xdrneg1; 6338420Smckusick u_long rpc_call, rpc_vers, rpc_reply, rpc_msgdenied, 6438420Smckusick rpc_mismatch, rpc_auth_unix, rpc_msgaccepted; 6538420Smckusick u_long nfs_vers, nfs_prog, nfs_true, nfs_false; 6638420Smckusick /* And other global data */ 6738420Smckusick static u_long *rpc_uidp = (u_long *)0; 6838420Smckusick static u_long nfs_xid = 1; 6938420Smckusick static char *rpc_unixauth; 7038420Smckusick extern long hostid; 7138420Smckusick extern enum vtype v_type[NFLNK+1]; 72*39345Smckusick extern struct proc *nfs_iodwant[MAX_ASYNCDAEMON]; 7338884Smacklem extern struct map nfsmap[NFS_MSIZ]; 7438420Smckusick 7538420Smckusick /* Function ret types */ 7638420Smckusick static char *nfs_unixauth(); 7738420Smckusick 7838420Smckusick /* 7938737Smckusick * Maximum number of groups passed through to NFS server. 8038737Smckusick * For release 3.X systems, the maximum value is 8. 8138737Smckusick * For release 4.X systems, the maximum value is 10. 8238737Smckusick */ 8338737Smckusick int numgrps = 8; 8438737Smckusick 8538737Smckusick /* 8638420Smckusick * Create the header for an rpc request packet 8738420Smckusick * The function nfs_unixauth() creates a unix style authorization string 8838420Smckusick * and returns a ptr to it. 8938420Smckusick * The hsiz is the size of the rest of the nfs request header. 9038420Smckusick * (just used to decide if a cluster is a good idea) 9138420Smckusick * nb: Note that the prog, vers and proc args are already in xdr byte order 9238420Smckusick */ 9338420Smckusick struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid) 9438420Smckusick u_long prog; 9538420Smckusick u_long vers; 9638420Smckusick u_long proc; 9738420Smckusick struct ucred *cred; 9838420Smckusick int hsiz; 9938420Smckusick caddr_t *bpos; 10038420Smckusick struct mbuf **mb; 10138420Smckusick u_long *retxid; 10238420Smckusick { 10338420Smckusick register struct mbuf *mreq, *m; 10438420Smckusick register u_long *p; 10538420Smckusick struct mbuf *m1; 10638420Smckusick char *ap; 10738420Smckusick int asiz, siz; 10838420Smckusick 10938420Smckusick NFSMGETHDR(mreq); 11038737Smckusick asiz = (((cred->cr_ngroups > numgrps) ? numgrps : cred->cr_ngroups)<<2); 11138425Smckusick #ifdef FILLINHOST 11238420Smckusick asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED); 11338425Smckusick #else 11438425Smckusick asiz += 9*NFSX_UNSIGNED; 11538425Smckusick #endif 11638420Smckusick 11738420Smckusick /* If we need a lot, alloc a cluster ?? */ 11838420Smckusick if ((asiz+hsiz+RPC_SIZ) > MHLEN) 11938420Smckusick NFSMCLGET(mreq, M_WAIT); 12038420Smckusick mreq->m_len = NFSMSIZ(mreq); 12138420Smckusick siz = mreq->m_len; 12238420Smckusick m1 = mreq; 12338420Smckusick /* 12438420Smckusick * Alloc enough mbufs 12538420Smckusick * We do it now to avoid all sleeps after the call to nfs_unixauth() 12638420Smckusick */ 12738420Smckusick while ((asiz+RPC_SIZ) > siz) { 12838420Smckusick MGET(m, M_WAIT, MT_DATA); 12938420Smckusick m1->m_next = m; 13038420Smckusick m->m_len = MLEN; 13138420Smckusick siz += MLEN; 13238420Smckusick m1 = m; 13338420Smckusick } 13438420Smckusick p = mtod(mreq, u_long *); 13538420Smckusick *p++ = *retxid = txdr_unsigned(++nfs_xid); 13638420Smckusick *p++ = rpc_call; 13738420Smckusick *p++ = rpc_vers; 13838420Smckusick *p++ = prog; 13938420Smckusick *p++ = vers; 14038420Smckusick *p++ = proc; 14138420Smckusick 14238420Smckusick /* Now we can call nfs_unixauth() and copy it in */ 14338420Smckusick ap = nfs_unixauth(cred); 14438420Smckusick m = mreq; 14538420Smckusick siz = m->m_len-RPC_SIZ; 14638420Smckusick if (asiz <= siz) { 14738420Smckusick bcopy(ap, (caddr_t)p, asiz); 14838420Smckusick m->m_len = asiz+RPC_SIZ; 14938420Smckusick } else { 15038420Smckusick bcopy(ap, (caddr_t)p, siz); 15138420Smckusick ap += siz; 15238420Smckusick asiz -= siz; 15338420Smckusick while (asiz > 0) { 15438420Smckusick siz = (asiz > MLEN) ? MLEN : asiz; 15538420Smckusick m = m->m_next; 15638420Smckusick bcopy(ap, mtod(m, caddr_t), siz); 15738420Smckusick m->m_len = siz; 15838420Smckusick asiz -= siz; 15938420Smckusick ap += siz; 16038420Smckusick } 16138420Smckusick } 16238420Smckusick 16338420Smckusick /* Finally, return values */ 16438420Smckusick *mb = m; 16538420Smckusick *bpos = mtod(m, caddr_t)+m->m_len; 16638420Smckusick return (mreq); 16738420Smckusick } 16838420Smckusick 16938420Smckusick /* 17038420Smckusick * copies mbuf chain to the uio scatter/gather list 17138420Smckusick */ 17238420Smckusick nfsm_mbuftouio(mrep, uiop, siz, dpos) 17338420Smckusick struct mbuf **mrep; 17438420Smckusick struct uio *uiop; 17538420Smckusick int siz; 17638420Smckusick caddr_t *dpos; 17738420Smckusick { 17838420Smckusick register int xfer, left, len; 17938420Smckusick register struct mbuf *mp; 18038420Smckusick register char *mbufcp, *uiocp; 18138420Smckusick long uiosiz, rem; 18238420Smckusick 18338420Smckusick mp = *mrep; 18438420Smckusick mbufcp = *dpos; 18538420Smckusick len = mtod(mp, caddr_t)+mp->m_len-mbufcp; 18638420Smckusick rem = nfsm_rndup(siz)-siz; 18738420Smckusick while (siz > 0) { 18838420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 18938420Smckusick return(EFBIG); 19038420Smckusick left = uiop->uio_iov->iov_len; 19138420Smckusick uiocp = uiop->uio_iov->iov_base; 19238420Smckusick if (left > siz) 19338420Smckusick left = siz; 19438420Smckusick uiosiz = left; 19538420Smckusick while (left > 0) { 19638420Smckusick while (len == 0) { 19738420Smckusick mp = mp->m_next; 19838420Smckusick if (mp == NULL) 19938420Smckusick return (EBADRPC); 20038420Smckusick mbufcp = mtod(mp, caddr_t); 20138420Smckusick len = mp->m_len; 20238420Smckusick } 20338420Smckusick xfer = (left > len) ? len : left; 20438420Smckusick #ifdef notdef 20538420Smckusick /* Not Yet.. */ 20638420Smckusick if (uiop->uio_iov->iov_op != NULL) 20738420Smckusick (*(uiop->uio_iov->iov_op)) 20838420Smckusick (mbufcp, uiocp, xfer); 20938420Smckusick else 21038420Smckusick #endif 21138420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 21238420Smckusick bcopy(mbufcp, uiocp, xfer); 21338420Smckusick else 21438420Smckusick copyout(mbufcp, uiocp, xfer); 21538420Smckusick left -= xfer; 21638420Smckusick len -= xfer; 21738420Smckusick mbufcp += xfer; 21838420Smckusick uiocp += xfer; 21938420Smckusick uiop->uio_resid -= xfer; 22038420Smckusick } 22138420Smckusick if (uiop->uio_iov->iov_len <= siz) { 22238420Smckusick uiop->uio_iovcnt--; 22338420Smckusick uiop->uio_iov++; 22438420Smckusick } else { 22538420Smckusick uiop->uio_iov->iov_base += uiosiz; 22638420Smckusick uiop->uio_iov->iov_len -= uiosiz; 22738420Smckusick } 22838420Smckusick siz -= uiosiz; 22938420Smckusick } 23038420Smckusick if (rem > 0) 23138420Smckusick mbufcp += rem; 23238420Smckusick *dpos = mbufcp; 23338420Smckusick *mrep = mp; 23438420Smckusick return(0); 23538420Smckusick } 23638420Smckusick 23738420Smckusick /* 23838420Smckusick * copies a uio scatter/gather list to an mbuf chain... 23938420Smckusick */ 24038420Smckusick nfsm_uiotombuf(uiop, mq, siz, bpos) 24138420Smckusick register struct uio *uiop; 24238420Smckusick struct mbuf **mq; 24338420Smckusick int siz; 24438420Smckusick caddr_t *bpos; 24538420Smckusick { 24638420Smckusick register struct mbuf *mp; 24738420Smckusick struct mbuf *mp2; 24838420Smckusick long xfer, left, uiosiz, off; 24938420Smckusick int clflg; 25038420Smckusick int rem, len; 25138420Smckusick char *cp, *uiocp; 25238420Smckusick 25338420Smckusick if (siz > MLEN) /* or should it >= MCLBYTES ?? */ 25438420Smckusick clflg = 1; 25538420Smckusick else 25638420Smckusick clflg = 0; 25738420Smckusick rem = nfsm_rndup(siz)-siz; 25838420Smckusick mp2 = *mq; 25938420Smckusick while (siz > 0) { 26038420Smckusick if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL) 26138420Smckusick return(EINVAL); 26238420Smckusick left = uiop->uio_iov->iov_len; 26338420Smckusick uiocp = uiop->uio_iov->iov_base; 26438420Smckusick if (left > siz) 26538420Smckusick left = siz; 26638420Smckusick uiosiz = left; 26738420Smckusick while (left > 0) { 26838420Smckusick MGET(mp, M_WAIT, MT_DATA); 26938420Smckusick if (clflg) 27038420Smckusick NFSMCLGET(mp, M_WAIT); 27138420Smckusick mp->m_len = NFSMSIZ(mp); 27238420Smckusick mp2->m_next = mp; 27338420Smckusick mp2 = mp; 27438420Smckusick xfer = (left > mp->m_len) ? mp->m_len : left; 27538420Smckusick #ifdef notdef 27638420Smckusick /* Not Yet.. */ 27738420Smckusick if (uiop->uio_iov->iov_op != NULL) 27838420Smckusick (*(uiop->uio_iov->iov_op)) 27938420Smckusick (uiocp, mtod(mp, caddr_t), xfer); 28038420Smckusick else 28138420Smckusick #endif 28238420Smckusick if (uiop->uio_segflg == UIO_SYSSPACE) 28338420Smckusick bcopy(uiocp, mtod(mp, caddr_t), xfer); 28438420Smckusick else 28538420Smckusick copyin(uiocp, mtod(mp, caddr_t), xfer); 28638420Smckusick len = mp->m_len; 28738420Smckusick mp->m_len = xfer; 28838420Smckusick left -= xfer; 28938420Smckusick uiocp += xfer; 29038420Smckusick uiop->uio_resid -= xfer; 29138420Smckusick } 29238420Smckusick if (uiop->uio_iov->iov_len <= siz) { 29338420Smckusick uiop->uio_iovcnt--; 29438420Smckusick uiop->uio_iov++; 29538420Smckusick } else { 29638420Smckusick uiop->uio_iov->iov_base += uiosiz; 29738420Smckusick uiop->uio_iov->iov_len -= uiosiz; 29838420Smckusick } 29938420Smckusick siz -= uiosiz; 30038420Smckusick } 30138420Smckusick if (rem > 0) { 30238420Smckusick if (rem > (len-mp->m_len)) { 30338420Smckusick MGET(mp, M_WAIT, MT_DATA); 30438420Smckusick mp->m_len = 0; 30538420Smckusick mp2->m_next = mp; 30638420Smckusick } 30738420Smckusick cp = mtod(mp, caddr_t)+mp->m_len; 30838420Smckusick for (left = 0; left < rem; left++) 30938420Smckusick *cp++ = '\0'; 31038420Smckusick mp->m_len += rem; 31138420Smckusick *bpos = cp; 31238420Smckusick } else 31338420Smckusick *bpos = mtod(mp, caddr_t)+mp->m_len; 31438420Smckusick *mq = mp; 31538420Smckusick return(0); 31638420Smckusick } 31738420Smckusick 31838420Smckusick /* 31938420Smckusick * Help break down an mbuf chain by setting the first siz bytes contiguous 32038420Smckusick * pointed to by returned val. 32138420Smckusick * If Updateflg == True we can overwrite the first part of the mbuf data 32238420Smckusick * This is used by the macros nfsm_disect and nfsm_disecton for tough 32338420Smckusick * cases. (The macros use the vars. dpos and dpos2) 32438420Smckusick */ 32538420Smckusick nfsm_disct(mdp, dposp, siz, left, updateflg, cp2) 32638420Smckusick struct mbuf **mdp; 32738420Smckusick caddr_t *dposp; 32838420Smckusick int siz; 32938420Smckusick int left; 33038420Smckusick int updateflg; 33138420Smckusick caddr_t *cp2; 33238420Smckusick { 33338420Smckusick register struct mbuf *mp, *mp2; 33438420Smckusick register int siz2, xfer; 33538420Smckusick register caddr_t p; 33638420Smckusick caddr_t p2; 33738420Smckusick 33838420Smckusick mp = *mdp; 33938420Smckusick while (left == 0) { 34038420Smckusick *mdp = mp = mp->m_next; 34138420Smckusick if (mp == NULL) 34238420Smckusick return(EBADRPC); 34338420Smckusick left = mp->m_len; 34438420Smckusick *dposp = mtod(mp, caddr_t); 34538420Smckusick } 34638420Smckusick if (left >= siz) { 34738420Smckusick *cp2 = *dposp; 34838420Smckusick *dposp += siz; 34938420Smckusick return(0); 35038420Smckusick } else if (mp->m_next == NULL) { 35138420Smckusick return(EBADRPC); 35238420Smckusick } else if (siz > MCLBYTES) { 35338420Smckusick panic("nfs S too big"); 35438420Smckusick } else { 35538420Smckusick /* Iff update, you can overwrite, else must alloc new mbuf */ 35638420Smckusick if (updateflg) { 35738420Smckusick NFSMINOFF(mp); 35838420Smckusick } else { 35938420Smckusick MGET(mp2, M_WAIT, MT_DATA); 36038420Smckusick mp2->m_next = mp->m_next; 36138420Smckusick mp->m_next = mp2; 36238420Smckusick mp->m_len -= left; 36338420Smckusick mp = mp2; 36438420Smckusick } 36538420Smckusick /* Alloc cluster iff we need it */ 36638420Smckusick if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) { 36738420Smckusick NFSMCLGET(mp, M_WAIT); 36838420Smckusick if (!M_HASCL(mp)) 36938420Smckusick return(ENOBUFS); 37038420Smckusick } 37138420Smckusick *cp2 = p = mtod(mp, caddr_t); 37238420Smckusick bcopy(*dposp, p, left); /* Copy what was left */ 37338420Smckusick siz2 = siz-left; 37438420Smckusick p += left; 37538420Smckusick mp2 = mp->m_next; 37638420Smckusick /* Loop arround copying up the siz2 bytes */ 37738420Smckusick while (siz2 > 0) { 37838420Smckusick if (mp2 == NULL) 37938420Smckusick return (EBADRPC); 38038420Smckusick xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2; 38138420Smckusick bcopy(mtod(mp2, caddr_t), p, xfer); 38238420Smckusick NFSMADV(mp2, xfer); 38338420Smckusick mp2->m_len -= xfer; 38438420Smckusick siz2 -= xfer; 38538420Smckusick if (siz2 > 0) 38638420Smckusick mp2 = mp2->m_next; 38738420Smckusick } 38838420Smckusick mp->m_len = siz; 38938420Smckusick *mdp = mp2; 39038420Smckusick *dposp = mtod(mp2, caddr_t); 39138420Smckusick return (0); 39238420Smckusick } 39338420Smckusick } 39438420Smckusick 39538420Smckusick /* 39638420Smckusick * Advance the position in the mbuf chain with/without freeing mbufs 39738420Smckusick */ 39838420Smckusick nfs_adv(mdp, dposp, offs, left) 39938420Smckusick struct mbuf **mdp; 40038420Smckusick caddr_t *dposp; 40138420Smckusick int offs; 40238420Smckusick int left; 40338420Smckusick { 40438420Smckusick register struct mbuf *m; 40538420Smckusick register int s; 40638420Smckusick 40738420Smckusick m = *mdp; 40838420Smckusick s = left; 40938420Smckusick while (s < offs) { 41038420Smckusick offs -= s; 41138420Smckusick m = m->m_next; 41238420Smckusick if (m == NULL) 41338420Smckusick return(EBADRPC); 41438420Smckusick s = m->m_len; 41538420Smckusick } 41638420Smckusick *mdp = m; 41738420Smckusick *dposp = mtod(m, caddr_t)+offs; 41838420Smckusick return(0); 41938420Smckusick } 42038420Smckusick 42138420Smckusick /* 42238420Smckusick * Copy a string into mbufs for the hard cases... 42338420Smckusick */ 42438420Smckusick nfsm_strtmbuf(mb, bpos, cp, siz) 42538420Smckusick struct mbuf **mb; 42638420Smckusick char **bpos; 42738420Smckusick char *cp; 42838420Smckusick long siz; 42938420Smckusick { 43038420Smckusick register struct mbuf *m1, *m2; 43138420Smckusick long left, xfer, len, tlen; 43238420Smckusick u_long *p; 43338420Smckusick int putsize; 43438420Smckusick 43538420Smckusick putsize = 1; 43638420Smckusick m2 = *mb; 43738420Smckusick left = NFSMSIZ(m2)-m2->m_len; 43838420Smckusick if (left > 0) { 43938420Smckusick p = ((u_long *)(*bpos)); 44038420Smckusick *p++ = txdr_unsigned(siz); 44138420Smckusick putsize = 0; 44238420Smckusick left -= NFSX_UNSIGNED; 44338420Smckusick m2->m_len += NFSX_UNSIGNED; 44438420Smckusick if (left > 0) { 44538420Smckusick bcopy(cp, (caddr_t) p, left); 44638420Smckusick siz -= left; 44738420Smckusick cp += left; 44838420Smckusick m2->m_len += left; 44938420Smckusick left = 0; 45038420Smckusick } 45138420Smckusick } 45238420Smckusick /* Loop arround adding mbufs */ 45338420Smckusick while (siz > 0) { 45438420Smckusick MGET(m1, M_WAIT, MT_DATA); 45538420Smckusick if (siz > MLEN) 45638420Smckusick NFSMCLGET(m1, M_WAIT); 45738420Smckusick m1->m_len = NFSMSIZ(m1); 45838420Smckusick m2->m_next = m1; 45938420Smckusick m2 = m1; 46038420Smckusick p = mtod(m1, u_long *); 46138420Smckusick tlen = 0; 46238420Smckusick if (putsize) { 46338420Smckusick *p++ = txdr_unsigned(siz); 46438420Smckusick m1->m_len -= NFSX_UNSIGNED; 46538420Smckusick tlen = NFSX_UNSIGNED; 46638420Smckusick putsize = 0; 46738420Smckusick } 46838420Smckusick if (siz < m1->m_len) { 46938420Smckusick len = nfsm_rndup(siz); 47038420Smckusick xfer = siz; 47138420Smckusick if (xfer < len) 47238420Smckusick *(p+(xfer>>2)) = 0; 47338420Smckusick } else { 47438420Smckusick xfer = len = m1->m_len; 47538420Smckusick } 47638420Smckusick bcopy(cp, (caddr_t) p, xfer); 47738420Smckusick m1->m_len = len+tlen; 47838420Smckusick siz -= xfer; 47938420Smckusick cp += xfer; 48038420Smckusick } 48138420Smckusick *mb = m1; 48238420Smckusick *bpos = mtod(m1, caddr_t)+m1->m_len; 48338420Smckusick return(0); 48438420Smckusick } 48538420Smckusick 48638420Smckusick /* 48738420Smckusick * Called once to initialize data structures... 48838420Smckusick */ 48938420Smckusick nfsinit() 49038420Smckusick { 49138420Smckusick register int i; 49238420Smckusick 49338420Smckusick rpc_vers = txdr_unsigned(RPC_VER2); 49438420Smckusick rpc_call = txdr_unsigned(RPC_CALL); 49538420Smckusick rpc_reply = txdr_unsigned(RPC_REPLY); 49638420Smckusick rpc_msgdenied = txdr_unsigned(RPC_MSGDENIED); 49738420Smckusick rpc_msgaccepted = txdr_unsigned(RPC_MSGACCEPTED); 49838420Smckusick rpc_mismatch = txdr_unsigned(RPC_MISMATCH); 49938420Smckusick rpc_auth_unix = txdr_unsigned(RPCAUTH_UNIX); 50038420Smckusick nfs_vers = txdr_unsigned(NFS_VER2); 50138420Smckusick nfs_prog = txdr_unsigned(NFS_PROG); 50238420Smckusick nfs_true = txdr_unsigned(TRUE); 50338420Smckusick nfs_false = txdr_unsigned(FALSE); 50438420Smckusick /* Loop thru nfs procids */ 50538420Smckusick for (i = 0; i < NFS_NPROCS; i++) 50638420Smckusick nfs_procids[i] = txdr_unsigned(i); 507*39345Smckusick /* Ensure async daemons disabled */ 508*39345Smckusick for (i = 0; i < MAX_ASYNCDAEMON; i++) 509*39345Smckusick nfs_iodwant[i] = (struct proc *)0; 51038420Smckusick v_type[0] = VNON; 51138420Smckusick v_type[1] = VREG; 51238420Smckusick v_type[2] = VDIR; 51338420Smckusick v_type[3] = VBLK; 51438420Smckusick v_type[4] = VCHR; 51538420Smckusick v_type[5] = VLNK; 51638420Smckusick nfs_xdrneg1 = txdr_unsigned(-1); 51738420Smckusick nfs_nhinit(); /* Init the nfsnode table */ 51838884Smacklem rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ); 51938420Smckusick /* And start timer */ 52038420Smckusick nfs_timer(); 52138420Smckusick } 52238420Smckusick 52338420Smckusick /* 52438420Smckusick * Fill in the rest of the rpc_unixauth and return it 52538420Smckusick */ 52638420Smckusick static char *nfs_unixauth(cr) 52738420Smckusick register struct ucred *cr; 52838420Smckusick { 52938420Smckusick register u_long *p; 53038420Smckusick register int i; 53138420Smckusick int ngr; 53238420Smckusick 53338420Smckusick /* Maybe someday there should be a cache of AUTH_SHORT's */ 53438420Smckusick if ((p = rpc_uidp) == NULL) { 53538425Smckusick #ifdef FILLINHOST 53638420Smckusick i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED); 53738425Smckusick #else 53838425Smckusick i = 19*NFSX_UNSIGNED; 53938425Smckusick #endif 54038420Smckusick MALLOC(p, u_long *, i, M_TEMP, M_WAITOK); 54138420Smckusick bzero((caddr_t)p, i); 54238420Smckusick rpc_unixauth = (caddr_t)p; 54338420Smckusick *p++ = txdr_unsigned(RPCAUTH_UNIX); 54438420Smckusick p++; /* Fill in size later */ 54538420Smckusick *p++ = hostid; 54638425Smckusick #ifdef FILLINHOST 54738420Smckusick *p++ = txdr_unsigned(hostnamelen); 54838420Smckusick i = nfsm_rndup(hostnamelen); 54938420Smckusick bcopy(hostname, (caddr_t)p, hostnamelen); 55038420Smckusick p += (i>>2); 55138425Smckusick #else 55238425Smckusick *p++ = 0; 55338425Smckusick #endif 55438420Smckusick rpc_uidp = p; 55538420Smckusick } 55638420Smckusick *p++ = txdr_unsigned(cr->cr_uid); 55738420Smckusick *p++ = txdr_unsigned(cr->cr_groups[0]); 55838737Smckusick ngr = (cr->cr_ngroups > numgrps) ? numgrps : cr->cr_ngroups; 55938420Smckusick *p++ = txdr_unsigned(ngr); 56038420Smckusick for (i = 0; i < ngr; i++) 56138420Smckusick *p++ = txdr_unsigned(cr->cr_groups[i]); 56238420Smckusick /* And add the AUTH_NULL */ 56338420Smckusick *p++ = 0; 56438420Smckusick *p = 0; 56538420Smckusick i = (((caddr_t)p)-rpc_unixauth)-12; 56638420Smckusick p = (u_long *)(rpc_unixauth+4); 56738420Smckusick *p = txdr_unsigned(i); 56838420Smckusick return(rpc_unixauth); 56938420Smckusick } 57038420Smckusick 57138420Smckusick /* 57238420Smckusick * Attribute cache routines. 57338420Smckusick * nfs_loadattrcache() - loads or updates the cache contents from attributes 57438420Smckusick * that are on the mbuf list 57538420Smckusick * nfs_getattrcache() - returns valid attributes if found in cache, returns 57638420Smckusick * error otherwise 57738420Smckusick */ 57838420Smckusick 57938420Smckusick /* 58038420Smckusick * Load the attribute cache (that lives in the nfsnode table) with 58138420Smckusick * the values on the mbuf list and 58238420Smckusick * Iff vap not NULL 58338420Smckusick * copy the attributes to *vaper 58438420Smckusick */ 58538420Smckusick nfs_loadattrcache(vp, mdp, dposp, vaper) 58638420Smckusick register struct vnode *vp; 58738420Smckusick struct mbuf **mdp; 58838420Smckusick caddr_t *dposp; 58938420Smckusick struct vattr *vaper; 59038420Smckusick { 59138420Smckusick register struct vattr *vap; 59238884Smacklem register struct nfsv2_fattr *fp; 59338420Smckusick nfsm_vars; 59438420Smckusick struct nfsnode *np; 59538420Smckusick 59638420Smckusick md = *mdp; 59738420Smckusick dpos = *dposp; 59838420Smckusick t1 = (mtod(md, caddr_t)+md->m_len)-dpos; 59938420Smckusick if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2)) 60038420Smckusick return (error); 60138884Smacklem fp = (struct nfsv2_fattr *)cp2; 60238420Smckusick np = VTONFS(vp); 60338420Smckusick vap = &np->n_vattr; 60438884Smacklem vap->va_type = nfstov_type(fp->fa_type); 60538884Smacklem vap->va_mode = nfstov_mode(fp->fa_mode); 60638884Smacklem vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink); 60738884Smacklem vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid); 60838884Smacklem vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid); 60938884Smacklem vap->va_size = fxdr_unsigned(u_long, fp->fa_size); 61038884Smacklem if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size) 61138884Smacklem np->n_size = vap->va_size; 61238420Smckusick vap->va_size1 = 0; /* OR -1 ?? */ 61338884Smacklem vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize); 61438884Smacklem vap->va_rdev = fxdr_unsigned(dev_t, fp->fa_rdev); 61538884Smacklem vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * vap->va_blocksize; 61638884Smacklem vap->va_bytes1 = 0; 61738884Smacklem vap->va_fsid = fxdr_unsigned(long, fp->fa_fsid); 61838884Smacklem vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid); 61938884Smacklem fxdr_time(&fp->fa_atime, &vap->va_atime); 62038884Smacklem fxdr_time(&fp->fa_mtime, &vap->va_mtime); 62138884Smacklem fxdr_time(&fp->fa_ctime, &vap->va_ctime); 62238579Smckusick vap->va_gen = 0; 62338579Smckusick vap->va_flags = 0; 62438420Smckusick np->n_attrstamp = time.tv_sec; 62538420Smckusick *dposp = dpos; 62638420Smckusick *mdp = md; 62738884Smacklem if (vaper != NULL) { 62838420Smckusick bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap)); 62938884Smacklem if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 63038884Smacklem vaper->va_size = np->n_size; 63138884Smacklem } 63238420Smckusick return (0); 63338420Smckusick } 63438420Smckusick 63538420Smckusick /* 63638420Smckusick * Check the time stamp 63738420Smckusick * If the cache is valid, copy contents to *vap and return 0 63838420Smckusick * otherwise return an error 63938420Smckusick */ 64038420Smckusick nfs_getattrcache(vp, vap) 64138420Smckusick register struct vnode *vp; 64238420Smckusick struct vattr *vap; 64338420Smckusick { 64438420Smckusick register struct nfsnode *np; 64538420Smckusick 64638420Smckusick np = VTONFS(vp); 64738420Smckusick if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) { 64838420Smckusick nfsstats.attrcache_hits++; 64938420Smckusick bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr)); 65038884Smacklem if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size)) 65138884Smacklem vap->va_size = np->n_size; 65238420Smckusick return (0); 65338420Smckusick } else { 65438420Smckusick nfsstats.attrcache_misses++; 65538420Smckusick return (ENOENT); 65638420Smckusick } 65738420Smckusick } 65838420Smckusick 65938420Smckusick /* 66038420Smckusick * nfs_namei - a liitle like namei(), but for one element only 66138420Smckusick * essentially look up file handle, fill in ndp and call VOP_LOOKUP() 66238420Smckusick */ 66338420Smckusick nfs_namei(ndp, fhp, len, mdp, dposp) 66438420Smckusick register struct nameidata *ndp; 66538420Smckusick fhandle_t *fhp; 66638420Smckusick int len; 66738420Smckusick struct mbuf **mdp; 66838420Smckusick caddr_t *dposp; 66938420Smckusick { 67038420Smckusick register int i, rem; 67138420Smckusick register struct mbuf *md; 67238420Smckusick register char *cp; 67338420Smckusick struct vnode *dp = (struct vnode *)0; 67438420Smckusick struct vnode *tdp; 67538420Smckusick struct mount *mp; 67638420Smckusick int flag; 67738420Smckusick int docache; 67838420Smckusick int wantparent; 67938420Smckusick int lockparent; 68038420Smckusick int rootflg = 0; 68138420Smckusick int error = 0; 68238420Smckusick 68338420Smckusick ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0; 68438420Smckusick flag = ndp->ni_nameiop & OPFLAG; 68538420Smckusick wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT); 68638420Smckusick lockparent = ndp->ni_nameiop & LOCKPARENT; 68738420Smckusick docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE; 68838420Smckusick if (flag == DELETE || wantparent) 68938420Smckusick docache = 0; 69038420Smckusick 69138420Smckusick /* Fill in the nameidata and call lookup */ 69238420Smckusick cp = *dposp; 69338420Smckusick md = *mdp; 69438420Smckusick rem = mtod(md, caddr_t)+md->m_len-cp; 69538420Smckusick ndp->ni_hash = 0; 69638420Smckusick for (i = 0; i < len;) { 69738420Smckusick if (rem == 0) { 69838420Smckusick md = md->m_next; 69938420Smckusick if (md == NULL) 70038420Smckusick return (EBADRPC); 70138420Smckusick cp = mtod(md, caddr_t); 70238420Smckusick rem = md->m_len; 70338420Smckusick } 70438420Smckusick if (*cp == '\0' || *cp == '/') 70538420Smckusick return (EINVAL); 70638420Smckusick if (*cp & 0200) 70738420Smckusick if ((*cp&0377) == ('/'|0200) || flag != DELETE) 70838420Smckusick return (EINVAL); 70938420Smckusick ndp->ni_dent.d_name[i++] = *cp; 71038420Smckusick ndp->ni_hash += (unsigned char)*cp * i; 71138420Smckusick cp++; 71238420Smckusick rem--; 71338420Smckusick } 71438420Smckusick *mdp = md; 71538420Smckusick len = nfsm_rndup(len)-len; 71638420Smckusick if (len > 0) 71738420Smckusick *dposp = cp+len; 71838420Smckusick else 71938420Smckusick *dposp = cp; 72038420Smckusick ndp->ni_namelen = i; 72138420Smckusick ndp->ni_dent.d_namlen = i; 72238420Smckusick ndp->ni_dent.d_name[i] = '\0'; 72338425Smckusick ndp->ni_pathlen = 1; 72438420Smckusick ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0]; 72538420Smckusick ndp->ni_next = &ndp->ni_dent.d_name[i]; 72638420Smckusick ndp->ni_loopcnt = 0; /* Not actually used for now */ 72738420Smckusick ndp->ni_endoff = 0; 72838420Smckusick if (docache) 72938420Smckusick ndp->ni_makeentry = 1; 73038420Smckusick else 73138420Smckusick ndp->ni_makeentry = 0; 73238420Smckusick ndp->ni_isdotdot = (i == 2 && 73338420Smckusick ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.'); 73438420Smckusick 73538420Smckusick if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred)) 73638420Smckusick return (error); 73738425Smckusick if (dp->v_type != VDIR) { 73838425Smckusick vput(dp); 73938425Smckusick return (ENOTDIR); 74038425Smckusick } 741*39345Smckusick /* 742*39345Smckusick * Must set current directory here to avoid confusion in namei() 743*39345Smckusick * called from rename() 744*39345Smckusick */ 74538425Smckusick ndp->ni_cdir = dp; 74638425Smckusick ndp->ni_rdir = (struct vnode *)0; 74738420Smckusick 74838420Smckusick /* 74938425Smckusick * Handle "..": 75038425Smckusick * If this vnode is the root of the mounted 75138425Smckusick * file system, then ignore it so can't get out 75238420Smckusick */ 75338425Smckusick if (ndp->ni_isdotdot && (dp->v_flag & VROOT)) { 75438425Smckusick ndp->ni_dvp = dp; 75538425Smckusick ndp->ni_vp = dp; 75638425Smckusick VREF(dp); 75738425Smckusick goto nextname; 75838420Smckusick } 75938420Smckusick 76038420Smckusick /* 76138420Smckusick * We now have a segment name to search for, and a directory to search. 76238420Smckusick */ 76338420Smckusick if (error = VOP_LOOKUP(dp, ndp)) { 76438420Smckusick if (ndp->ni_vp != NULL) 76538420Smckusick panic("leaf should be empty"); 76638420Smckusick /* 76738420Smckusick * If creating and at end of pathname, then can consider 76838420Smckusick * allowing file to be created. 76938420Smckusick */ 77038420Smckusick if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY)) 77138420Smckusick error = EROFS; 77238420Smckusick if (flag == LOOKUP || flag == DELETE || error != ENOENT) 77338420Smckusick goto bad; 77438420Smckusick /* 77538420Smckusick * We return with ni_vp NULL to indicate that the entry 77638420Smckusick * doesn't currently exist, leaving a pointer to the 77738420Smckusick * (possibly locked) directory inode in ndp->ni_dvp. 77838420Smckusick */ 77938420Smckusick return (0); /* should this be ENOENT? */ 78038420Smckusick } 78138420Smckusick 78238420Smckusick dp = ndp->ni_vp; 78338420Smckusick 78438420Smckusick nextname: 78538425Smckusick ndp->ni_ptr = ndp->ni_next; 78638420Smckusick /* 78738425Smckusick * Check for read-only file systems 78838420Smckusick */ 78938421Smckusick if (flag == DELETE || flag == RENAME) { 79038421Smckusick /* 79138421Smckusick * Disallow directory write attempts on read-only 79238421Smckusick * file systems. 79338421Smckusick */ 79438421Smckusick if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) || 79538425Smckusick (wantparent && (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)))) { 79638421Smckusick error = EROFS; 79738421Smckusick goto bad2; 79838421Smckusick } 79938421Smckusick } 80038420Smckusick 80138420Smckusick if (!wantparent) 80238420Smckusick vrele(ndp->ni_dvp); 80338420Smckusick 80438420Smckusick if ((ndp->ni_nameiop & LOCKLEAF) == 0) 80538420Smckusick VOP_UNLOCK(dp); 80638420Smckusick return (0); 80738420Smckusick 80838420Smckusick bad2: 80938420Smckusick if (lockparent) 81038420Smckusick VOP_UNLOCK(ndp->ni_dvp); 81138420Smckusick vrele(ndp->ni_dvp); 81238420Smckusick bad: 81338420Smckusick vput(dp); 81438420Smckusick ndp->ni_vp = NULL; 81538420Smckusick return (error); 81638420Smckusick } 81738420Smckusick 81838420Smckusick /* 81938420Smckusick * A fiddled version of m_adj() that ensures null fill to a long 82038420Smckusick * boundary and only trims off the back end 82138420Smckusick */ 82238420Smckusick nfsm_adj(mp, len, nul) 82338420Smckusick struct mbuf *mp; 82438420Smckusick register int len; 82538420Smckusick int nul; 82638420Smckusick { 82738420Smckusick register struct mbuf *m; 82838420Smckusick register int count, i; 82938420Smckusick register char *cp; 83038420Smckusick 83138420Smckusick /* 83238420Smckusick * Trim from tail. Scan the mbuf chain, 83338420Smckusick * calculating its length and finding the last mbuf. 83438420Smckusick * If the adjustment only affects this mbuf, then just 83538420Smckusick * adjust and return. Otherwise, rescan and truncate 83638420Smckusick * after the remaining size. 83738420Smckusick */ 83838420Smckusick count = 0; 83938420Smckusick m = mp; 84038420Smckusick for (;;) { 84138420Smckusick count += m->m_len; 84238420Smckusick if (m->m_next == (struct mbuf *)0) 84338420Smckusick break; 84438420Smckusick m = m->m_next; 84538420Smckusick } 84638579Smckusick if (m->m_len > len) { 84738420Smckusick m->m_len -= len; 84838420Smckusick if (nul > 0) { 84938420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 85038420Smckusick for (i = 0; i < nul; i++) 85138420Smckusick *cp++ = '\0'; 85238420Smckusick } 85338420Smckusick return; 85438420Smckusick } 85538420Smckusick count -= len; 85638420Smckusick if (count < 0) 85738420Smckusick count = 0; 85838420Smckusick /* 85938420Smckusick * Correct length for chain is "count". 86038420Smckusick * Find the mbuf with last data, adjust its length, 86138420Smckusick * and toss data from remaining mbufs on chain. 86238420Smckusick */ 86338420Smckusick for (m = mp; m; m = m->m_next) { 86438420Smckusick if (m->m_len >= count) { 86538420Smckusick m->m_len = count; 86638420Smckusick if (nul > 0) { 86738420Smckusick cp = mtod(m, caddr_t)+m->m_len-nul; 86838420Smckusick for (i = 0; i < nul; i++) 86938420Smckusick *cp++ = '\0'; 87038420Smckusick } 87138420Smckusick break; 87238420Smckusick } 87338420Smckusick count -= m->m_len; 87438420Smckusick } 87538420Smckusick while (m = m->m_next) 87638420Smckusick m->m_len = 0; 87738420Smckusick } 87838420Smckusick 87938420Smckusick /* 88038420Smckusick * nfsrv_fhtovp() - convert a fh to a vnode ptr (optionally locked) 88138420Smckusick * - look up fsid in mount list (if not found ret error) 88238420Smckusick * - check that it is exported 88338420Smckusick * - get vp by calling VFS_FHTOVP() macro 88438420Smckusick * - if not lockflag unlock it with VOP_UNLOCK() 88538420Smckusick * - if cred->cr_uid == 0 set it to m_exroot 88638420Smckusick */ 88738420Smckusick nfsrv_fhtovp(fhp, lockflag, vpp, cred) 88838420Smckusick fhandle_t *fhp; 88938420Smckusick int lockflag; 89038420Smckusick struct vnode **vpp; 89138420Smckusick struct ucred *cred; 89238420Smckusick { 89338420Smckusick register struct mount *mp; 89438420Smckusick int error; 89538420Smckusick 89638420Smckusick if ((mp = getvfs(&fhp->fh_fsid)) == NULL) 89738420Smckusick return (ESTALE); 89838420Smckusick if ((mp->m_flag & M_EXPORTED) == 0) 89938420Smckusick return (EACCES); 90038420Smckusick if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp)) 90138420Smckusick return (ESTALE); 90238420Smckusick if (cred->cr_uid == 0) 90338420Smckusick cred->cr_uid = mp->m_exroot; 90438420Smckusick if (!lockflag) 90538420Smckusick VOP_UNLOCK(*vpp); 90638420Smckusick return (0); 90738420Smckusick } 908