BSD 4_3_Reno release
[unix-history] / usr / src / sys / nfs / nfs_subs.c
index 13ef5e0..b2344f4 100644 (file)
@@ -5,19 +5,22 @@
  * This code is derived from software contributed to Berkeley by
  * Rick Macklem at The University of Guelph.
  *
  * This code is derived from software contributed to Berkeley by
  * Rick Macklem at The University of Guelph.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution is only permitted until one year after the first shipment
+ * of 4.4BSD by the Regents.  Otherwise, redistribution and use in source and
+ * binary forms are permitted provided that: (1) source distributions retain
+ * this entire copyright notice and comment, and (2) distributions including
+ * binaries display the following acknowledgement:  This product includes
+ * software developed by the University of California, Berkeley and its
+ * contributors'' in the documentation or other materials provided with the
+ * distribution and in all advertising materials mentioning features or use
+ * of this software.  Neither the name of the University nor the names of
+ * its contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  *
- *     @(#)nfs_subs.c  7.2 (Berkeley) %G%
+ *     @(#)nfs_subs.c  7.29 (Berkeley) 7/26/90
  */
 
 /*
  */
 
 /*
  * the nfs op functions. They do things like create the rpc header and
  * copy data between mbuf chains and uio lists.
  */
  * the nfs op functions. They do things like create the rpc header and
  * copy data between mbuf chains and uio lists.
  */
-#include "strings.h"
-#include "types.h"
 #include "param.h"
 #include "param.h"
-#include "mount.h"
-#include "dir.h"
-#include "time.h"
-#include "errno.h"
+#include "user.h"
+#include "proc.h"
+#include "systm.h"
 #include "kernel.h"
 #include "kernel.h"
-#include "malloc.h"
-#include "mbuf.h"
+#include "mount.h"
 #include "file.h"
 #include "vnode.h"
 #include "file.h"
 #include "vnode.h"
-#include "uio.h"
-#include "namei.h"
-#include "ucred.h"
+#include "mbuf.h"
+#include "errno.h"
+#include "map.h"
 #include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfsnode.h"
 #include "nfs.h"
 #include "rpcv2.h"
 #include "nfsv2.h"
 #include "nfsnode.h"
 #include "nfs.h"
+#include "nfsiom.h"
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 
 #include "xdr_subs.h"
 #include "nfsm_subs.h"
 
@@ -64,23 +64,34 @@ static u_long *rpc_uidp = (u_long *)0;
 static u_long nfs_xid = 1;
 static char *rpc_unixauth;
 extern long hostid;
 static u_long nfs_xid = 1;
 static char *rpc_unixauth;
 extern long hostid;
-extern enum vtype v_type[NFLNK+1];
+enum vtype ntov_type[7] = { VNON, VREG, VDIR, VBLK, VCHR, VLNK, VNON };
+extern struct proc *nfs_iodwant[NFS_MAXASYNCDAEMON];
+extern struct map nfsmap[NFS_MSIZ];
+extern struct nfsreq nfsreqh;
 
 /* Function ret types */
 static char *nfs_unixauth();
 
 
 /* Function ret types */
 static char *nfs_unixauth();
 
+/*
+ * Maximum number of groups passed through to NFS server.
+ * According to RFC1057 it should be 16.
+ * For release 3.X systems, the maximum value is 8.
+ * For some other servers, the maximum value is 10.
+ */
+int numgrps = 8;
+
 /*
  * Create the header for an rpc request packet
  * The function nfs_unixauth() creates a unix style authorization string
  * and returns a ptr to it.
  * The hsiz is the size of the rest of the nfs request header.
  * (just used to decide if a cluster is a good idea)
 /*
  * Create the header for an rpc request packet
  * The function nfs_unixauth() creates a unix style authorization string
  * and returns a ptr to it.
  * The hsiz is the size of the rest of the nfs request header.
  * (just used to decide if a cluster is a good idea)
- * nb: Note that the prog, vers and proc args are already in xdr byte order
+ * nb: Note that the prog, vers and procid args are already in xdr byte order
  */
  */
-struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid)
+struct mbuf *nfsm_reqh(prog, vers, procid, cred, hsiz, bpos, mb, retxid)
        u_long prog;
        u_long vers;
        u_long prog;
        u_long vers;
-       u_long proc;
+       u_long procid;
        struct ucred *cred;
        int hsiz;
        caddr_t *bpos;
        struct ucred *cred;
        int hsiz;
        caddr_t *bpos;
@@ -94,12 +105,17 @@ struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid)
        int asiz, siz;
 
        NFSMGETHDR(mreq);
        int asiz, siz;
 
        NFSMGETHDR(mreq);
-       asiz = (((cred->cr_ngroups > 10) ? 10 : cred->cr_ngroups)<<2);
+       asiz = ((((cred->cr_ngroups - 1) > numgrps) ? numgrps :
+                 (cred->cr_ngroups - 1)) << 2);
+#ifdef FILLINHOST
        asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
        asiz += nfsm_rndup(hostnamelen)+(9*NFSX_UNSIGNED);
+#else
+       asiz += 9*NFSX_UNSIGNED;
+#endif
 
        /* If we need a lot, alloc a cluster ?? */
        if ((asiz+hsiz+RPC_SIZ) > MHLEN)
 
        /* If we need a lot, alloc a cluster ?? */
        if ((asiz+hsiz+RPC_SIZ) > MHLEN)
-               NFSMCLGET(mreq, M_WAIT);
+               MCLGET(mreq, M_WAIT);
        mreq->m_len = NFSMSIZ(mreq);
        siz = mreq->m_len;
        m1 = mreq;
        mreq->m_len = NFSMSIZ(mreq);
        siz = mreq->m_len;
        m1 = mreq;
@@ -120,7 +136,7 @@ struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid)
        *p++ = rpc_vers;
        *p++ = prog;
        *p++ = vers;
        *p++ = rpc_vers;
        *p++ = prog;
        *p++ = vers;
-       *p++ = proc;
+       *p++ = procid;
 
        /* Now we can call nfs_unixauth() and copy it in */
        ap = nfs_unixauth(cred);
 
        /* Now we can call nfs_unixauth() and copy it in */
        ap = nfs_unixauth(cred);
@@ -154,14 +170,15 @@ struct mbuf *nfsm_reqh(prog, vers, proc, cred, hsiz, bpos, mb, retxid)
  */
 nfsm_mbuftouio(mrep, uiop, siz, dpos)
        struct mbuf **mrep;
  */
 nfsm_mbuftouio(mrep, uiop, siz, dpos)
        struct mbuf **mrep;
-       struct uio *uiop;
+       register struct uio *uiop;
        int siz;
        caddr_t *dpos;
 {
        int siz;
        caddr_t *dpos;
 {
+       register char *mbufcp, *uiocp;
        register int xfer, left, len;
        register struct mbuf *mp;
        register int xfer, left, len;
        register struct mbuf *mp;
-       register char *mbufcp, *uiocp;
        long uiosiz, rem;
        long uiosiz, rem;
+       int error = 0;
 
        mp = *mrep;
        mbufcp = *dpos;
 
        mp = *mrep;
        mbufcp = *dpos;
@@ -169,7 +186,7 @@ nfsm_mbuftouio(mrep, uiop, siz, dpos)
        rem = nfsm_rndup(siz)-siz;
        while (siz > 0) {
                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
        rem = nfsm_rndup(siz)-siz;
        while (siz > 0) {
                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
-                       return(EFBIG);
+                       return (EFBIG);
                left = uiop->uio_iov->iov_len;
                uiocp = uiop->uio_iov->iov_base;
                if (left > siz)
                left = uiop->uio_iov->iov_len;
                uiocp = uiop->uio_iov->iov_base;
                if (left > siz)
@@ -199,6 +216,7 @@ nfsm_mbuftouio(mrep, uiop, siz, dpos)
                        len -= xfer;
                        mbufcp += xfer;
                        uiocp += xfer;
                        len -= xfer;
                        mbufcp += xfer;
                        uiocp += xfer;
+                       uiop->uio_offset += xfer;
                        uiop->uio_resid -= xfer;
                }
                if (uiop->uio_iov->iov_len <= siz) {
                        uiop->uio_resid -= xfer;
                }
                if (uiop->uio_iov->iov_len <= siz) {
@@ -210,11 +228,15 @@ nfsm_mbuftouio(mrep, uiop, siz, dpos)
                }
                siz -= uiosiz;
        }
                }
                siz -= uiosiz;
        }
-       if (rem > 0)
-               mbufcp += rem;
        *dpos = mbufcp;
        *mrep = mp;
        *dpos = mbufcp;
        *mrep = mp;
-       return(0);
+       if (rem > 0) {
+               if (len < rem)
+                       error = nfs_adv(mrep, dpos, rem, len);
+               else
+                       *dpos += rem;
+       }
+       return (error);
 }
 
 /*
 }
 
 /*
@@ -226,12 +248,11 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
        int siz;
        caddr_t *bpos;
 {
        int siz;
        caddr_t *bpos;
 {
-       register struct mbuf *mp;
-       struct mbuf *mp2;
-       long xfer, left, uiosiz, off;
-       int clflg;
-       int rem, len;
-       char *cp, *uiocp;
+       register char *uiocp;
+       register struct mbuf *mp, *mp2;
+       register int xfer, left, len;
+       int uiosiz, clflg, rem;
+       char *cp;
 
        if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
                clflg = 1;
 
        if (siz > MLEN)         /* or should it >= MCLBYTES ?? */
                clflg = 1;
@@ -241,7 +262,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
        mp2 = *mq;
        while (siz > 0) {
                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
        mp2 = *mq;
        while (siz > 0) {
                if (uiop->uio_iovcnt <= 0 || uiop->uio_iov == NULL)
-                       return(EINVAL);
+                       return (EINVAL);
                left = uiop->uio_iov->iov_len;
                uiocp = uiop->uio_iov->iov_base;
                if (left > siz)
                left = uiop->uio_iov->iov_len;
                uiocp = uiop->uio_iov->iov_base;
                if (left > siz)
@@ -250,7 +271,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
                while (left > 0) {
                        MGET(mp, M_WAIT, MT_DATA);
                        if (clflg)
                while (left > 0) {
                        MGET(mp, M_WAIT, MT_DATA);
                        if (clflg)
-                               NFSMCLGET(mp, M_WAIT);
+                               MCLGET(mp, M_WAIT);
                        mp->m_len = NFSMSIZ(mp);
                        mp2->m_next = mp;
                        mp2 = mp;
                        mp->m_len = NFSMSIZ(mp);
                        mp2->m_next = mp;
                        mp2 = mp;
@@ -270,6 +291,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
                        mp->m_len = xfer;
                        left -= xfer;
                        uiocp += xfer;
                        mp->m_len = xfer;
                        left -= xfer;
                        uiocp += xfer;
+                       uiop->uio_offset += xfer;
                        uiop->uio_resid -= xfer;
                }
                if (uiop->uio_iov->iov_len <= siz) {
                        uiop->uio_resid -= xfer;
                }
                if (uiop->uio_iov->iov_len <= siz) {
@@ -295,7 +317,7 @@ nfsm_uiotombuf(uiop, mq, siz, bpos)
        } else
                *bpos = mtod(mp, caddr_t)+mp->m_len;
        *mq = mp;
        } else
                *bpos = mtod(mp, caddr_t)+mp->m_len;
        *mq = mp;
-       return(0);
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -316,23 +338,21 @@ nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
        register struct mbuf *mp, *mp2;
        register int siz2, xfer;
        register caddr_t p;
        register struct mbuf *mp, *mp2;
        register int siz2, xfer;
        register caddr_t p;
-       caddr_t p2;
 
        mp = *mdp;
        while (left == 0) {
                *mdp = mp = mp->m_next;
                if (mp == NULL)
 
        mp = *mdp;
        while (left == 0) {
                *mdp = mp = mp->m_next;
                if (mp == NULL)
-                       return(EBADRPC);
+                       return (EBADRPC);
                left = mp->m_len;
                *dposp = mtod(mp, caddr_t);
        }
        if (left >= siz) {
                *cp2 = *dposp;
                *dposp += siz;
                left = mp->m_len;
                *dposp = mtod(mp, caddr_t);
        }
        if (left >= siz) {
                *cp2 = *dposp;
                *dposp += siz;
-               return(0);
        } else if (mp->m_next == NULL) {
        } else if (mp->m_next == NULL) {
-               return(EBADRPC);
-       } else if (siz > MCLBYTES) {
+               return (EBADRPC);
+       } else if (siz > MHLEN) {
                panic("nfs S too big");
        } else {
                /* Iff update, you can overwrite, else must alloc new mbuf */
                panic("nfs S too big");
        } else {
                /* Iff update, you can overwrite, else must alloc new mbuf */
@@ -345,38 +365,35 @@ nfsm_disct(mdp, dposp, siz, left, updateflg, cp2)
                        mp->m_len -= left;
                        mp = mp2;
                }
                        mp->m_len -= left;
                        mp = mp2;
                }
-               /* Alloc cluster iff we need it */
-               if (!M_HASCL(mp) && siz > NFSMSIZ(mp)) {
-                       NFSMCLGET(mp, M_WAIT);
-                       if (!M_HASCL(mp))
-                               return(ENOBUFS);
-               }
                *cp2 = p = mtod(mp, caddr_t);
                bcopy(*dposp, p, left);         /* Copy what was left */
                siz2 = siz-left;
                p += left;
                mp2 = mp->m_next;
                *cp2 = p = mtod(mp, caddr_t);
                bcopy(*dposp, p, left);         /* Copy what was left */
                siz2 = siz-left;
                p += left;
                mp2 = mp->m_next;
-               /* Loop arround copying up the siz2 bytes */
+               /* Loop around copying up the siz2 bytes */
                while (siz2 > 0) {
                        if (mp2 == NULL)
                                return (EBADRPC);
                        xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
                while (siz2 > 0) {
                        if (mp2 == NULL)
                                return (EBADRPC);
                        xfer = (siz2 > mp2->m_len) ? mp2->m_len : siz2;
-                       bcopy(mtod(mp2, caddr_t), p, xfer);
-                       NFSMADV(mp2, xfer);
-                       mp2->m_len -= xfer;
-                       siz2 -= xfer;
+                       if (xfer > 0) {
+                               bcopy(mtod(mp2, caddr_t), p, xfer);
+                               NFSMADV(mp2, xfer);
+                               mp2->m_len -= xfer;
+                               p += xfer;
+                               siz2 -= xfer;
+                       }
                        if (siz2 > 0)
                                mp2 = mp2->m_next;
                }
                mp->m_len = siz;
                *mdp = mp2;
                *dposp = mtod(mp2, caddr_t);
                        if (siz2 > 0)
                                mp2 = mp2->m_next;
                }
                mp->m_len = siz;
                *mdp = mp2;
                *dposp = mtod(mp2, caddr_t);
-               return (0);
        }
        }
+       return (0);
 }
 
 /*
 }
 
 /*
- * Advance the position in the mbuf chain with/without freeing mbufs
+ * Advance the position in the mbuf chain.
  */
 nfs_adv(mdp, dposp, offs, left)
        struct mbuf **mdp;
  */
 nfs_adv(mdp, dposp, offs, left)
        struct mbuf **mdp;
@@ -393,12 +410,12 @@ nfs_adv(mdp, dposp, offs, left)
                offs -= s;
                m = m->m_next;
                if (m == NULL)
                offs -= s;
                m = m->m_next;
                if (m == NULL)
-                       return(EBADRPC);
+                       return (EBADRPC);
                s = m->m_len;
        }
        *mdp = m;
        *dposp = mtod(m, caddr_t)+offs;
                s = m->m_len;
        }
        *mdp = m;
        *dposp = mtod(m, caddr_t)+offs;
-       return(0);
+       return (0);
 }
 
 /*
 }
 
 /*
@@ -436,7 +453,7 @@ nfsm_strtmbuf(mb, bpos, cp, siz)
        while (siz > 0) {
                MGET(m1, M_WAIT, MT_DATA);
                if (siz > MLEN)
        while (siz > 0) {
                MGET(m1, M_WAIT, MT_DATA);
                if (siz > MLEN)
-                       NFSMCLGET(m1, M_WAIT);
+                       MCLGET(m1, M_WAIT);
                m1->m_len = NFSMSIZ(m1);
                m2->m_next = m1;
                m2 = m1;
                m1->m_len = NFSMSIZ(m1);
                m2->m_next = m1;
                m2 = m1;
@@ -463,13 +480,13 @@ nfsm_strtmbuf(mb, bpos, cp, siz)
        }
        *mb = m1;
        *bpos = mtod(m1, caddr_t)+m1->m_len;
        }
        *mb = m1;
        *bpos = mtod(m1, caddr_t)+m1->m_len;
-       return(0);
+       return (0);
 }
 
 /*
  * Called once to initialize data structures...
  */
 }
 
 /*
  * Called once to initialize data structures...
  */
-nfsinit()
+nfs_init()
 {
        register int i;
 
 {
        register int i;
 
@@ -487,15 +504,18 @@ nfsinit()
        /* Loop thru nfs procids */
        for (i = 0; i < NFS_NPROCS; i++)
                nfs_procids[i] = txdr_unsigned(i);
        /* Loop thru nfs procids */
        for (i = 0; i < NFS_NPROCS; i++)
                nfs_procids[i] = txdr_unsigned(i);
-       v_type[0] = VNON;
-       v_type[1] = VREG;
-       v_type[2] = VDIR;
-       v_type[3] = VBLK;
-       v_type[4] = VCHR;
-       v_type[5] = VLNK;
+       /* Ensure async daemons disabled */
+       for (i = 0; i < NFS_MAXASYNCDAEMON; i++)
+               nfs_iodwant[i] = (struct proc *)0;
        nfs_xdrneg1 = txdr_unsigned(-1);
        nfs_nhinit();                   /* Init the nfsnode table */
        nfs_xdrneg1 = txdr_unsigned(-1);
        nfs_nhinit();                   /* Init the nfsnode table */
-       /* And start timer */
+       nfsrv_initcache();              /* Init the server request cache */
+       rminit(nfsmap, (long)NFS_MAPREG, (long)1, "nfs mapreg", NFS_MSIZ);
+
+       /*
+        * Initialize reply list and start timer
+        */
+       nfsreqh.r_prev = nfsreqh.r_next = &nfsreqh;
        nfs_timer();
 }
 
        nfs_timer();
 }
 
@@ -511,24 +531,32 @@ static char *nfs_unixauth(cr)
 
        /* Maybe someday there should be a cache of AUTH_SHORT's */
        if ((p = rpc_uidp) == NULL) {
 
        /* Maybe someday there should be a cache of AUTH_SHORT's */
        if ((p = rpc_uidp) == NULL) {
-               i = nfsm_rndup(hostnamelen)+(19*NFSX_UNSIGNED);
+#ifdef FILLINHOST
+               i = nfsm_rndup(hostnamelen)+(25*NFSX_UNSIGNED);
+#else
+               i = 25*NFSX_UNSIGNED;
+#endif
                MALLOC(p, u_long *, i, M_TEMP, M_WAITOK);
                bzero((caddr_t)p, i);
                rpc_unixauth = (caddr_t)p;
                *p++ = txdr_unsigned(RPCAUTH_UNIX);
                p++;    /* Fill in size later */
                *p++ = hostid;
                MALLOC(p, u_long *, i, M_TEMP, M_WAITOK);
                bzero((caddr_t)p, i);
                rpc_unixauth = (caddr_t)p;
                *p++ = txdr_unsigned(RPCAUTH_UNIX);
                p++;    /* Fill in size later */
                *p++ = hostid;
+#ifdef FILLINHOST
                *p++ = txdr_unsigned(hostnamelen);
                i = nfsm_rndup(hostnamelen);
                bcopy(hostname, (caddr_t)p, hostnamelen);
                p += (i>>2);
                *p++ = txdr_unsigned(hostnamelen);
                i = nfsm_rndup(hostnamelen);
                bcopy(hostname, (caddr_t)p, hostnamelen);
                p += (i>>2);
+#else
+               *p++ = 0;
+#endif
                rpc_uidp = p;
        }
        *p++ = txdr_unsigned(cr->cr_uid);
        *p++ = txdr_unsigned(cr->cr_groups[0]);
                rpc_uidp = p;
        }
        *p++ = txdr_unsigned(cr->cr_uid);
        *p++ = txdr_unsigned(cr->cr_groups[0]);
-       ngr = (cr->cr_ngroups > 10) ? 10 : cr->cr_ngroups;
+       ngr = ((cr->cr_ngroups - 1) > numgrps) ? numgrps : (cr->cr_ngroups - 1);
        *p++ = txdr_unsigned(ngr);
        *p++ = txdr_unsigned(ngr);
-       for (i = 0; i < ngr; i++)
+       for (i = 1; i <= ngr; i++)
                *p++ = txdr_unsigned(cr->cr_groups[i]);
        /* And add the AUTH_NULL */
        *p++ = 0;
                *p++ = txdr_unsigned(cr->cr_groups[i]);
        /* And add the AUTH_NULL */
        *p++ = 0;
@@ -536,7 +564,7 @@ static char *nfs_unixauth(cr)
        i = (((caddr_t)p)-rpc_unixauth)-12;
        p = (u_long *)(rpc_unixauth+4);
        *p = txdr_unsigned(i);
        i = (((caddr_t)p)-rpc_unixauth)-12;
        p = (u_long *)(rpc_unixauth+4);
        *p = txdr_unsigned(i);
-       return(rpc_unixauth);
+       return (rpc_unixauth);
 }
 
 /*
 }
 
 /*
@@ -548,52 +576,116 @@ static char *nfs_unixauth(cr)
  */
 
 /*
  */
 
 /*
- * Load the attribute cache (that lives in the nfsnode table) with
+ * Load the attribute cache (that lives in the nfsnode entry) with
  * the values on the mbuf list and
  * Iff vap not NULL
  *    copy the attributes to *vaper
  */
  * the values on the mbuf list and
  * Iff vap not NULL
  *    copy the attributes to *vaper
  */
-nfs_loadattrcache(vp, mdp, dposp, vaper)
-       register struct vnode *vp;
+nfs_loadattrcache(vpp, mdp, dposp, vaper)
+       struct vnode **vpp;
        struct mbuf **mdp;
        caddr_t *dposp;
        struct vattr *vaper;
 {
        struct mbuf **mdp;
        caddr_t *dposp;
        struct vattr *vaper;
 {
+       register struct vnode *vp = *vpp;
        register struct vattr *vap;
        register struct vattr *vap;
-       nfsm_vars;
-       struct nfsnode *np;
+       register struct nfsv2_fattr *fp;
+       extern struct vnodeops spec_nfsv2nodeops;
+       register struct nfsnode *np;
+       register long t1;
+       caddr_t dpos, cp2;
+       int error = 0;
+       struct mbuf *md;
+       enum vtype type;
+       long rdev;
+       struct timeval mtime;
+       struct vnode *nvp;
 
        md = *mdp;
        dpos = *dposp;
        t1 = (mtod(md, caddr_t)+md->m_len)-dpos;
        if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
                return (error);
 
        md = *mdp;
        dpos = *dposp;
        t1 = (mtod(md, caddr_t)+md->m_len)-dpos;
        if (error = nfsm_disct(&md, &dpos, NFSX_FATTR, t1, TRUE, &cp2))
                return (error);
-       p = (u_long *)cp2;
+       fp = (struct nfsv2_fattr *)cp2;
+       type = nfstov_type(fp->fa_type);
+       rdev = fxdr_unsigned(long, fp->fa_rdev);
+       fxdr_time(&fp->fa_mtime, &mtime);
+       /*
+        * If v_type == VNON it is a new node, so fill in the v_type,
+        * n_mtime fields. Check to see if it represents a special 
+        * device, and if so, check for a possible alias. Once the
+        * correct vnode has been obtained, fill in the rest of the
+        * information.
+        */
        np = VTONFS(vp);
        np = VTONFS(vp);
+       if (vp->v_type == VNON) {
+               if (type == VCHR && rdev == 0xffffffff)
+                       vp->v_type = type = VFIFO;
+               else
+                       vp->v_type = type;
+               if (vp->v_type == VFIFO) {
+#ifdef FIFO
+                       extern struct vnodeops fifo_nfsv2nodeops;
+                       vp->v_op = &fifo_nfsv2nodeops;
+#else
+                       return (EOPNOTSUPP);
+#endif /* FIFO */
+               }
+               if (vp->v_type == VCHR || vp->v_type == VBLK) {
+                       vp->v_op = &spec_nfsv2nodeops;
+                       if (nvp = checkalias(vp, (dev_t)rdev, vp->v_mount)) {
+                               /*
+                                * Reinitialize aliased node.
+                                */
+                               np = VTONFS(nvp);
+                               np->n_vnode = nvp;
+                               np->n_flag = 0;
+                               nfs_lock(nvp);
+                               bcopy((caddr_t)&VTONFS(vp)->n_fh,
+                                       (caddr_t)&np->n_fh, NFSX_FH);
+                               insque(np, nfs_hash(&np->n_fh));
+                               np->n_attrstamp = 0;
+                               np->n_sillyrename = (struct sillyrename *)0;
+                               /*
+                                * Discard unneeded vnode and update actual one
+                                */
+                               vput(vp);
+                               *vpp = nvp;
+                       }
+               }
+               np->n_mtime = mtime.tv_sec;
+       }
        vap = &np->n_vattr;
        vap = &np->n_vattr;
-       vap->va_type = nfstov_type(*p++);
-       vap->va_mode = nfstov_mode(*p++);
-       vap->va_nlink = fxdr_unsigned(u_short, *p++);
-       vap->va_uid = fxdr_unsigned(uid_t, *p++);
-       vap->va_gid = fxdr_unsigned(gid_t, *p++);
-       vap->va_size = fxdr_unsigned(u_long, *p++);
-       vap->va_size1 = 0;              /* OR -1 ?? */
-       vap->va_blocksize = fxdr_unsigned(long, *p++);
-       vap->va_rdev = fxdr_unsigned(dev_t, *p++);
-       vap->va_bytes = fxdr_unsigned(long, *p++);
-       vap->va_bytes1 = -1;
-       vap->va_fsid = fxdr_unsigned(long, *p++);
-       vap->va_fileid = fxdr_unsigned(long, *p++);
-       fxdr_time(p, &(vap->va_atime));
-       p += 2;
-       fxdr_time(p, &(vap->va_mtime));
-       p += 2;
-       fxdr_time(p, &(vap->va_ctime));
+       vap->va_type = type;
+       vap->va_mode = nfstov_mode(fp->fa_mode);
+       vap->va_nlink = fxdr_unsigned(u_short, fp->fa_nlink);
+       vap->va_uid = fxdr_unsigned(uid_t, fp->fa_uid);
+       vap->va_gid = fxdr_unsigned(gid_t, fp->fa_gid);
+       vap->va_size = fxdr_unsigned(u_long, fp->fa_size);
+       if ((np->n_flag & NMODIFIED) == 0 || vap->va_size > np->n_size)
+               np->n_size = vap->va_size;
+       vap->va_size_rsv = 0;
+       vap->va_blocksize = fxdr_unsigned(long, fp->fa_blocksize);
+       vap->va_rdev = (dev_t)rdev;
+       vap->va_bytes = fxdr_unsigned(long, fp->fa_blocks) * NFS_FABLKSIZE;
+       vap->va_bytes_rsv = 0;
+       vap->va_fsid = vp->v_mount->mnt_stat.f_fsid.val[0];
+       vap->va_fileid = fxdr_unsigned(long, fp->fa_fileid);
+       vap->va_atime.tv_sec = fxdr_unsigned(long, fp->fa_atime.tv_sec);
+       vap->va_atime.tv_usec = 0;
+       vap->va_flags = fxdr_unsigned(u_long, fp->fa_atime.tv_usec);
+       vap->va_mtime = mtime;
+       vap->va_ctime.tv_sec = fxdr_unsigned(long, fp->fa_ctime.tv_sec);
+       vap->va_ctime.tv_usec = 0;
+       vap->va_gen = fxdr_unsigned(u_long, fp->fa_ctime.tv_usec);
        np->n_attrstamp = time.tv_sec;
        *dposp = dpos;
        *mdp = md;
        np->n_attrstamp = time.tv_sec;
        *dposp = dpos;
        *mdp = md;
-       if (vaper != NULL)
+       if (vaper != NULL) {
                bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
                bcopy((caddr_t)vap, (caddr_t)vaper, sizeof(*vap));
+               if ((np->n_flag & NMODIFIED) && (np->n_size > vap->va_size))
+                       vaper->va_size = np->n_size;
+       }
        return (0);
 }
 
        return (0);
 }
 
@@ -612,6 +704,10 @@ nfs_getattrcache(vp, vap)
        if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) {
                nfsstats.attrcache_hits++;
                bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
        if ((time.tv_sec-np->n_attrstamp) < NFS_ATTRTIMEO) {
                nfsstats.attrcache_hits++;
                bcopy((caddr_t)&np->n_vattr,(caddr_t)vap,sizeof(struct vattr));
+               if ((np->n_flag & NMODIFIED) == 0)
+                       np->n_size = vap->va_size;
+               else if (np->n_size > vap->va_size)
+                       vap->va_size = np->n_size;
                return (0);
        } else {
                nfsstats.attrcache_misses++;
                return (0);
        } else {
                nfsstats.attrcache_misses++;
@@ -619,13 +715,8 @@ nfs_getattrcache(vp, vap)
        }
 }
 
        }
 }
 
-#ifndef OPFLAG
-#define        OPFLAG  (CREATE | DELETE | LOOKUP)
-#endif
-
 /*
 /*
- * nfs_namei - a liitle like namei(), but for one element only
- *     essentially look up file handle, fill in ndp and call VOP_LOOKUP()
+ * Set up nameidata for a namei() call and do it
  */
 nfs_namei(ndp, fhp, len, mdp, dposp)
        register struct nameidata *ndp;
  */
 nfs_namei(ndp, fhp, len, mdp, dposp)
        register struct nameidata *ndp;
@@ -637,236 +728,77 @@ nfs_namei(ndp, fhp, len, mdp, dposp)
        register int i, rem;
        register struct mbuf *md;
        register char *cp;
        register int i, rem;
        register struct mbuf *md;
        register char *cp;
-       struct vnode *dp = (struct vnode *)0;
-       struct vnode *tdp;
-       struct mount *mp;
+       struct vnode *dp;
        int flag;
        int flag;
-       int docache;
-       int wantparent;
-       int lockparent;
-       int rootflg = 0;
-       int error = 0;
-
-       ndp->ni_vp = ndp->ni_dvp = (struct vnode *)0;
-       flag = ndp->ni_nameiop & OPFLAG;
-       wantparent = ndp->ni_nameiop & (LOCKPARENT | WANTPARENT);
-       lockparent = ndp->ni_nameiop & LOCKPARENT;
-       docache = (ndp->ni_nameiop & NOCACHE) ^ NOCACHE;
-       if (flag == DELETE || wantparent)
-               docache = 0;
+       int error;
 
 
-       /* Fill in the nameidata and call lookup */
-       cp = *dposp;
-       md = *mdp;
-       rem = mtod(md, caddr_t)+md->m_len-cp;
-       ndp->ni_hash = 0;
-       for (i = 0; i < len;) {
-               if (rem == 0) {
-                       md = md->m_next;
-                       if (md == NULL)
-                               return (EBADRPC);
-                       cp = mtod(md, caddr_t);
-                       rem = md->m_len;
-               }
-               if (*cp == '\0' || *cp == '/')
-                       return (EINVAL);
-               if (*cp & 0200)
-                       if ((*cp&0377) == ('/'|0200) || flag != DELETE)
+       if ((ndp->ni_nameiop & HASBUF) == 0) {
+               flag = ndp->ni_nameiop & OPFLAG;
+               /*
+                * Copy the name from the mbuf list to the d_name field of ndp
+                * and set the various ndp fields appropriately.
+                */
+               cp = *dposp;
+               md = *mdp;
+               rem = mtod(md, caddr_t)+md->m_len-cp;
+               ndp->ni_hash = 0;
+               for (i = 0; i < len;) {
+                       while (rem == 0) {
+                               md = md->m_next;
+                               if (md == NULL)
+                                       return (EBADRPC);
+                               cp = mtod(md, caddr_t);
+                               rem = md->m_len;
+                       }
+                       if (*cp == '\0' || *cp == '/')
                                return (EINVAL);
                                return (EINVAL);
-               ndp->ni_dent.d_name[i++] = *cp;
-               ndp->ni_hash += (unsigned char)*cp * i;
-               cp++;
-               rem--;
-       }
-       *mdp = md;
-       len = nfsm_rndup(len)-len;
-       if (len > 0)
-               *dposp = cp+len;
-       else
+                       if (*cp & 0200)
+                               if ((*cp&0377) == ('/'|0200) || flag != DELETE)
+                                       return (EINVAL);
+                       ndp->ni_dent.d_name[i++] = *cp;
+                       ndp->ni_hash += (unsigned char)*cp * i;
+                       cp++;
+                       rem--;
+               }
+               *mdp = md;
                *dposp = cp;
                *dposp = cp;
+               len = nfsm_rndup(len)-len;
+               if (len > 0) {
+                       if (rem < len) {
+                               if (error = nfs_adv(mdp, dposp, len, rem))
+                                       return (error);
+                       } else
+                               *dposp += len;
+               }
+       } else
+               i = len;
        ndp->ni_namelen = i;
        ndp->ni_dent.d_namlen = i;
        ndp->ni_dent.d_name[i] = '\0';
        ndp->ni_namelen = i;
        ndp->ni_dent.d_namlen = i;
        ndp->ni_dent.d_name[i] = '\0';
-       ndp->ni_pathlen = 0;
-       ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0];
+       ndp->ni_segflg = UIO_SYSSPACE;
+       ndp->ni_pathlen = 1;
+       ndp->ni_pnbuf = ndp->ni_dirp = ndp->ni_ptr = &ndp->ni_dent.d_name[0];
        ndp->ni_next = &ndp->ni_dent.d_name[i];
        ndp->ni_next = &ndp->ni_dent.d_name[i];
-       ndp->ni_loopcnt = 0;    /* Not actually used for now */
-       ndp->ni_endoff = 0;
-       if (docache)
-               ndp->ni_makeentry = 1;
-       else
-               ndp->ni_makeentry = 0;
-       ndp->ni_isdotdot = (i == 2 && 
-               ndp->ni_dent.d_name[1] == '.' && ndp->ni_dent.d_name[0] == '.');
+       ndp->ni_nameiop |= (NOCROSSMOUNT | REMOTE | HASBUF);
 
 
-       /*
-        * Must remember if this is root so that cr_uid can be set to
-        * mp->m_exroot at mount points
-        * Then call nfsrv_fhtovp() to get the locked directory vnode
-        */
-       if (ndp->ni_cred->cr_uid == 0)
-               rootflg++;
-       if (error = nfsrv_fhtovp(fhp, TRUE, &dp, ndp->ni_cred))
+       if (error = nfsrv_fhtovp(fhp, FALSE, &dp, ndp->ni_cred))
                return (error);
                return (error);
-
-       /*
-        * Handle "..": two special cases.
-        * 1. If at root directory (e.g. after chroot)
-        *    then ignore it so can't get out.
-        * 2. If this vnode is the root of a mounted
-        *    file system, then replace it with the
-        *    vnode which was mounted on so we take the
-        *    .. in the other file system.
-        */
-       if (ndp->ni_isdotdot) {
-               for (;;) {
-                       if (dp == rootdir) {
-                               ndp->ni_dvp = dp;
-                               dp->v_count++;
-                               goto nextname;
-                       }
-                       if ((dp->v_flag & VROOT) == 0)
-                               break;
-                       tdp = dp;
-                       dp = dp->v_mount->m_vnodecovered;
-                       vput(tdp);
-                       if ((dp->v_mount->m_flag & M_EXPORTED) == 0)
-                               return (EACCES);
-                       VOP_LOCK(dp);
-                       dp->v_count++;
-                       if (rootflg)
-                               ndp->ni_cred->cr_uid = dp->v_mount->m_exroot;
-               }
-       }
-
-       /*
-        * We now have a segment name to search for, and a directory to search.
-        */
-       if (error = VOP_LOOKUP(dp, ndp)) {
-               if (ndp->ni_vp != NULL)
-                       panic("leaf should be empty");
-               /*
-                * If creating and at end of pathname, then can consider
-                * allowing file to be created.
-                */
-               if (ndp->ni_dvp->v_mount->m_flag & (M_RDONLY | M_EXRDONLY))
-                       error = EROFS;
-               if (flag == LOOKUP || flag == DELETE || error != ENOENT)
-                       goto bad;
-               /*
-                * We return with ni_vp NULL to indicate that the entry
-                * doesn't currently exist, leaving a pointer to the
-                * (possibly locked) directory inode in ndp->ni_dvp.
-                */
-               return (0);     /* should this be ENOENT? */
-       }
-
-       /*
-        * Check for symbolic link
-        */
-       dp = ndp->ni_vp;
-#ifdef notdef
-       if ((dp->v_type == VLNK) &&
-           (ndp->ni_nameiop & FOLLOW)) {
-               struct iovec aiov;
-               struct uio auio;
-               int linklen;
-
-               if (++ndp->ni_loopcnt > MAXSYMLINKS) {
-                       error = ELOOP;
-                       goto bad2;
-               }
-               MALLOC(cp, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
-               aiov.iov_base = cp;
-               aiov.iov_len = MAXPATHLEN;
-               auio.uio_iov = &aiov;
-               auio.uio_iovcnt = 1;
-               auio.uio_offset = 0;
-               auio.uio_rw = UIO_READ;
-               auio.uio_segflg = UIO_SYSSPACE;
-               auio.uio_resid = MAXPATHLEN;
-               if (error = VOP_READLINK(dp, &auio, ndp->ni_cred)) {
-                       free(cp, M_NAMEI);
-                       goto bad2;
-               }
-               linklen = MAXPATHLEN - auio.uio_resid;
-               if (linklen + ndp->ni_pathlen >= MAXPATHLEN) {
-                       free(cp, M_NAMEI);
-                       error = ENAMETOOLONG;
-                       goto bad2;
-               }
-               bcopy(ndp->ni_next, cp + linklen, ndp->ni_pathlen);
-               ndp->ni_pnbuf = cp;
-               } else
-                       ndp->ni_pnbuf[linklen] = '\0';
-               ndp->ni_ptr = cp;
-               ndp->ni_pathlen += linklen;
-               vput(dp);
-               dp = ndp->ni_dvp;
-               goto start;
-       }
-#endif
-
-       /*
-        * Check to see if the vnode has been mounted on;
-        * if so find the root of the mounted file system.
-        * Ignore NFS mount points
-        */
-mntloop:
-       while (dp->v_type == VDIR && (mp = dp->v_mountedhere) &&
-               mp->m_fsid.val[1] != MOUNT_NFS) {
-               while(mp->m_flag & M_MLOCK) {
-                       mp->m_flag |= M_MWAIT;
-                       sleep((caddr_t)mp, PVFS);
-                       goto mntloop;
-               }
-               error = VFS_ROOT(mp, &tdp);
-               if (error || (mp->m_flag & M_EXPORTED) == 0)
-                       goto bad2;
-               vput(dp);
-               ndp->ni_vp = dp = tdp;
-               if (rootflg)
-                       ndp->ni_cred->cr_uid = mp->m_exroot;
+       if (dp->v_type != VDIR) {
+               vrele(dp);
+               return (ENOTDIR);
        }
        }
-
-nextname:
        /*
        /*
-        * Check for read-only file systems.
+        * Must set current directory here to avoid confusion in namei()
+        * called from rename()
         */
         */
-       if (flag == DELETE || flag == RENAME) {
-               /*
-                * Disallow directory write attempts on read-only
-                * file systems.
-                */
-               if ((dp->v_mount->m_flag & (M_RDONLY|M_EXRDONLY)) ||
-                   (wantparent && (ndp->ni_dvp->v_mount->m_flag & M_RDONLY))) {
-                       error = EROFS;
-                       goto bad2;
-               }
-       }
+       ndp->ni_cdir = dp;
+       ndp->ni_rdir = NULLVP;
 
        /*
 
        /*
-        * Kludge city... This is hokey, but since ufs_rename() calls
-        * namei() and namei() expects ni_cdir to be set, what can I
-        * do. Fortunately rename() holds onto the parent so I don't
-        * have to increment the v_count.
+        * And call namei() to do the real work
         */
         */
-       if (!wantparent)
-               vrele(ndp->ni_dvp);
-       else
-               ndp->ni_cdir = ndp->ni_dvp;
-
-       if ((ndp->ni_nameiop & LOCKLEAF) == 0)
-               VOP_UNLOCK(dp);
-       return (0);
-
-bad2:
-       if (lockparent)
-               VOP_UNLOCK(ndp->ni_dvp);
-       vrele(ndp->ni_dvp);
-bad:
-       vput(dp);
-       ndp->ni_vp = NULL;
+       error = namei(ndp);
+       vrele(dp);
        return (error);
 }
 
        return (error);
 }
 
@@ -898,7 +830,7 @@ nfsm_adj(mp, len, nul)
                        break;
                m = m->m_next;
        }
                        break;
                m = m->m_next;
        }
-       if (m->m_len >= len) {
+       if (m->m_len > len) {
                m->m_len -= len;
                if (nul > 0) {
                        cp = mtod(m, caddr_t)+m->m_len-nul;
                m->m_len -= len;
                if (nul > 0) {
                        cp = mtod(m, caddr_t)+m->m_len-nul;
@@ -946,18 +878,16 @@ nfsrv_fhtovp(fhp, lockflag, vpp, cred)
        struct ucred *cred;
 {
        register struct mount *mp;
        struct ucred *cred;
 {
        register struct mount *mp;
-       int error;
 
        if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
                return (ESTALE);
 
        if ((mp = getvfs(&fhp->fh_fsid)) == NULL)
                return (ESTALE);
-       if ((mp->m_flag & M_EXPORTED) == 0)
+       if ((mp->mnt_flag & MNT_EXPORTED) == 0)
                return (EACCES);
        if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
                return (ESTALE);
        if (cred->cr_uid == 0)
                return (EACCES);
        if (VFS_FHTOVP(mp, &fhp->fh_fid, vpp))
                return (ESTALE);
        if (cred->cr_uid == 0)
-               cred->cr_uid = mp->m_exroot;
+               cred->cr_uid = mp->mnt_exroot;
        if (!lockflag)
                VOP_UNLOCK(*vpp);
        return (0);
 }
        if (!lockflag)
                VOP_UNLOCK(*vpp);
        return (0);
 }
-