add previous create time for name cache consistency
[unix-history] / usr / src / sys / nfs / nfs_vnops.c
index 4167e3f..570ab88 100644 (file)
@@ -17,7 +17,7 @@
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
  *
- *     @(#)nfs_vnops.c 7.11 (Berkeley) %G%
+ *     @(#)nfs_vnops.c 7.29 (Berkeley) %G%
  */
 
 /*
  */
 
 /*
 
 #include "machine/pte.h"
 #include "machine/mtpr.h"
 
 #include "machine/pte.h"
 #include "machine/mtpr.h"
-#include "strings.h"
 #include "param.h"
 #include "user.h"
 #include "proc.h"
 #include "mount.h"
 #include "buf.h"
 #include "vm.h"
 #include "param.h"
 #include "user.h"
 #include "proc.h"
 #include "mount.h"
 #include "buf.h"
 #include "vm.h"
-#include "../ufs/dir.h"
 #include "malloc.h"
 #include "mbuf.h"
 #include "malloc.h"
 #include "mbuf.h"
-#include "uio.h"
-#include "ucred.h"
-#include "namei.h"
 #include "errno.h"
 #include "file.h"
 #include "conf.h"
 #include "vnode.h"
 #include "errno.h"
 #include "file.h"
 #include "conf.h"
 #include "vnode.h"
-#include "../ufs/inode.h"
 #include "map.h"
 #include "nfsv2.h"
 #include "nfs.h"
 #include "map.h"
 #include "nfsv2.h"
 #include "nfs.h"
@@ -85,39 +79,43 @@ int nfs_lookup(),
        nfs_strategy(),
        nfs_fsync(),
        nfs_inactive(),
        nfs_strategy(),
        nfs_fsync(),
        nfs_inactive(),
-       nfs_reclaim();
+       nfs_reclaim(),
+       nfs_print(),
+       nfs_islocked();
 
 struct vnodeops nfsv2_vnodeops = {
 
 struct vnodeops nfsv2_vnodeops = {
-       nfs_lookup,
-       nfs_create,
-       nfs_mknod,
-       nfs_open,
-       nfs_close,
-       nfs_access,
-       nfs_getattr,
-       nfs_setattr,
-       nfs_read,
-       nfs_write,
-       vfs_noop,
-       vfs_noop,
-       vfs_noop,
-       nfs_fsync,
-       vfs_nullop,
-       nfs_remove,
-       nfs_link,
-       nfs_rename,
-       nfs_mkdir,
-       nfs_rmdir,
-       nfs_symlink,
-       nfs_readdir,
-       nfs_readlink,
-       nfs_abortop,
-       nfs_inactive,
-       nfs_reclaim,
-       nfs_lock,
-       nfs_unlock,
-       nfs_bmap,
-       nfs_strategy,
+       nfs_lookup,             /* lookup */
+       nfs_create,             /* create */
+       nfs_mknod,              /* mknod */
+       nfs_open,               /* open */
+       nfs_close,              /* close */
+       nfs_access,             /* access */
+       nfs_getattr,            /* getattr */
+       nfs_setattr,            /* setattr */
+       nfs_read,               /* read */
+       nfs_write,              /* write */
+       vfs_noop,               /* ioctl */
+       vfs_noop,               /* select */
+       vfs_noop,               /* mmap */
+       nfs_fsync,              /* fsync */
+       vfs_nullop,             /* seek */
+       nfs_remove,             /* remove */
+       nfs_link,               /* link */
+       nfs_rename,             /* rename */
+       nfs_mkdir,              /* mkdir */
+       nfs_rmdir,              /* rmdir */
+       nfs_symlink,            /* symlink */
+       nfs_readdir,            /* readdir */
+       nfs_readlink,           /* readlink */
+       nfs_abortop,            /* abortop */
+       nfs_inactive,           /* inactive */
+       nfs_reclaim,            /* reclaim */
+       nfs_lock,               /* lock */
+       nfs_unlock,             /* unlock */
+       nfs_bmap,               /* bmap */
+       nfs_strategy,           /* strategy */
+       nfs_print,              /* print */
+       nfs_islocked,           /* islocked */
 };
 
 /* Special device vnode ops */
 };
 
 /* Special device vnode ops */
@@ -126,6 +124,7 @@ int spec_lookup(),
        spec_read(),
        spec_write(),
        spec_strategy(),
        spec_read(),
        spec_write(),
        spec_strategy(),
+       spec_bmap(),
        spec_ioctl(),
        spec_select(),
        spec_close(),
        spec_ioctl(),
        spec_select(),
        spec_close(),
@@ -133,41 +132,44 @@ int       spec_lookup(),
        spec_nullop();
 
 struct vnodeops spec_nfsv2nodeops = {
        spec_nullop();
 
 struct vnodeops spec_nfsv2nodeops = {
-       spec_lookup,
-       spec_badop,
-       spec_badop,
-       spec_open,
-       spec_close,
-       nfs_access,
-       nfs_getattr,
-       nfs_setattr,
-       spec_read,
-       spec_write,
-       spec_ioctl,
-       spec_select,
-       spec_badop,
-       spec_nullop,
-       spec_badop,
-       spec_badop,
-       spec_badop,
-       spec_badop,
-       spec_badop,
-       spec_badop,
-       spec_badop,
-       spec_badop,
-       spec_badop,
-       spec_badop,
-       nfs_inactive,
-       nfs_reclaim,
-       nfs_lock,
-       nfs_unlock,
-       spec_badop,
-       spec_strategy,
+       spec_lookup,            /* lookup */
+       spec_badop,             /* create */
+       spec_badop,             /* mknod */
+       spec_open,              /* open */
+       spec_close,             /* close */
+       nfs_access,             /* access */
+       nfs_getattr,            /* getattr */
+       nfs_setattr,            /* setattr */
+       spec_read,              /* read */
+       spec_write,             /* write */
+       spec_ioctl,             /* ioctl */
+       spec_select,            /* select */
+       spec_badop,             /* mmap */
+       spec_nullop,            /* fsync */
+       spec_badop,             /* seek */
+       spec_badop,             /* remove */
+       spec_badop,             /* link */
+       spec_badop,             /* rename */
+       spec_badop,             /* mkdir */
+       spec_badop,             /* rmdir */
+       spec_badop,             /* symlink */
+       spec_badop,             /* readdir */
+       spec_badop,             /* readlink */
+       spec_badop,             /* abortop */
+       nfs_inactive,           /* inactive */
+       nfs_reclaim,            /* reclaim */
+       nfs_lock,               /* lock */
+       nfs_unlock,             /* unlock */
+       spec_bmap,              /* bmap */
+       spec_strategy,          /* strategy */
+       nfs_print,              /* print */
+       nfs_islocked,           /* islocked */
 };
 
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_prog, nfs_vers;
 extern char nfsiobuf[MAXPHYS+NBPG];
 };
 
 extern u_long nfs_procids[NFS_NPROCS];
 extern u_long nfs_prog, nfs_vers;
 extern char nfsiobuf[MAXPHYS+NBPG];
+extern int nonidempotent[NFS_NPROCS];
 struct map nfsmap[NFS_MSIZ];
 enum vtype v_type[NFLNK+1];
 struct buf nfs_bqueue;         /* Queue head for nfsiod's */
 struct map nfsmap[NFS_MSIZ];
 enum vtype v_type[NFLNK+1];
 struct buf nfs_bqueue;         /* Queue head for nfsiod's */
@@ -182,10 +184,13 @@ nfs_null(vp, cred)
        struct vnode *vp;
        struct ucred *cred;
 {
        struct vnode *vp;
        struct ucred *cred;
 {
-       nfsm_vars;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb;
        
        nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
        
        nfsm_reqhead(nfs_procids[NFSPROC_NULL], cred, 0);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_NULL]);
        nfsm_reqdone;
        return (error);
 }
        nfsm_reqdone;
        return (error);
 }
@@ -238,6 +243,7 @@ found:
  * nfs open vnode op
  * Just check to see if the type is ok
  */
  * nfs open vnode op
  * Just check to see if the type is ok
  */
+/* ARGSUSED */
 nfs_open(vp, mode, cred)
        struct vnode *vp;
        int mode;
 nfs_open(vp, mode, cred)
        struct vnode *vp;
        int mode;
@@ -256,24 +262,23 @@ nfs_open(vp, mode, cred)
  * nfs close vnode op
  * For reg files, invalidate any buffer cache entries.
  */
  * nfs close vnode op
  * For reg files, invalidate any buffer cache entries.
  */
+/* ARGSUSED */
 nfs_close(vp, fflags, cred)
        register struct vnode *vp;
        int fflags;
        struct ucred *cred;
 {
 nfs_close(vp, fflags, cred)
        register struct vnode *vp;
        int fflags;
        struct ucred *cred;
 {
-       struct nfsnode *np = VTONFS(vp);
-       dev_t dev;
+       register struct nfsnode *np = VTONFS(vp);
        int error = 0;
 
        if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) ||
           ((np->n_flag & NBUFFERED) && np->n_sillyrename))) {
                nfs_lock(vp);
                np->n_flag &= ~(NMODIFIED|NBUFFERED);
        int error = 0;
 
        if (vp->v_type == VREG && ((np->n_flag & NMODIFIED) ||
           ((np->n_flag & NBUFFERED) && np->n_sillyrename))) {
                nfs_lock(vp);
                np->n_flag &= ~(NMODIFIED|NBUFFERED);
-               error = nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
+               vinvalbuf(vp, TRUE);
                if (np->n_flag & NWRITEERR) {
                        np->n_flag &= ~NWRITEERR;
                if (np->n_flag & NWRITEERR) {
                        np->n_flag &= ~NWRITEERR;
-                       if (!error)
-                               error = np->n_error ? np->n_error : EIO;
+                       error = np->n_error;
                }
                nfs_unlock(vp);
        }
                }
                nfs_unlock(vp);
        }
@@ -284,11 +289,16 @@ nfs_close(vp, fflags, cred)
  * nfs getattr call from vfs.
  */
 nfs_getattr(vp, vap, cred)
  * nfs getattr call from vfs.
  */
 nfs_getattr(vp, vap, cred)
-       struct vnode *vp;
-       register struct vattr *vap;
+       register struct vnode *vp;
+       struct vattr *vap;
        struct ucred *cred;
 {
        struct ucred *cred;
 {
-       nfsm_vars;
+       register caddr_t cp;
+       register long t1;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        
        /* First look in the cache.. */
        if (nfs_getattrcache(vp, vap) == 0)
        
        /* First look in the cache.. */
        if (nfs_getattrcache(vp, vap) == 0)
@@ -296,7 +306,7 @@ nfs_getattr(vp, vap, cred)
        nfsstats.rpccnt[NFSPROC_GETATTR]++;
        nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
        nfsm_fhtom(vp);
        nfsstats.rpccnt[NFSPROC_GETATTR]++;
        nfsm_reqhead(nfs_procids[NFSPROC_GETATTR], cred, NFSX_FH);
        nfsm_fhtom(vp);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_GETATTR]);
        nfsm_loadattr(vp, vap);
        nfsm_reqdone;
        return (error);
        nfsm_loadattr(vp, vap);
        nfsm_reqdone;
        return (error);
@@ -306,12 +316,17 @@ nfs_getattr(vp, vap, cred)
  * nfs setattr call.
  */
 nfs_setattr(vp, vap, cred)
  * nfs setattr call.
  */
 nfs_setattr(vp, vap, cred)
-       struct vnode *vp;
+       register struct vnode *vp;
        register struct vattr *vap;
        struct ucred *cred;
 {
        register struct nfsv2_sattr *sp;
        register struct vattr *vap;
        struct ucred *cred;
 {
        register struct nfsv2_sattr *sp;
-       nfsm_vars;
+       register caddr_t cp;
+       register long t1;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct nfsnode *np;
 
        nfsstats.rpccnt[NFSPROC_SETATTR]++;
        struct nfsnode *np;
 
        nfsstats.rpccnt[NFSPROC_SETATTR]++;
@@ -335,12 +350,13 @@ nfs_setattr(vp, vap, cred)
                np = VTONFS(vp);
                if (np->n_flag & NMODIFIED) {
                        np->n_flag &= ~NMODIFIED;
                np = VTONFS(vp);
                if (np->n_flag & NMODIFIED) {
                        np->n_flag &= ~NMODIFIED;
-                       nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
+                       vinvalbuf(vp, TRUE);
                }
        }
                }
        }
-       txdr_time(&vap->va_atime, &sp->sa_atime);
+       sp->sa_atime.tv_sec = txdr_unsigned(vap->va_atime.tv_sec);
+       sp->sa_atime.tv_usec = txdr_unsigned(vap->va_flags);
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_SETATTR]);
        nfsm_loadattr(vp, (struct vattr *)0);
        /* should we fill in any vap fields ?? */
        nfsm_reqdone;
        nfsm_loadattr(vp, (struct vattr *)0);
        /* should we fill in any vap fields ?? */
        nfsm_reqdone;
@@ -357,13 +373,17 @@ nfs_lookup(vp, ndp)
        register struct nameidata *ndp;
 {
        register struct vnode *vdp;
        register struct nameidata *ndp;
 {
        register struct vnode *vdp;
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct vnode *newvp;
        long len;
        nfsv2fh_t *fhp;
        struct nfsnode *np;
        struct vnode *newvp;
        long len;
        nfsv2fh_t *fhp;
        struct nfsnode *np;
-       int lockparent, wantparent, flag;
-       dev_t rdev;
+       int lockparent, wantparent, flag, error = 0;
 
        ndp->ni_dvp = vp;
        ndp->ni_vp = NULL;
 
        ndp->ni_dvp = vp;
        ndp->ni_vp = NULL;
@@ -403,9 +423,9 @@ nfs_lookup(vp, ndp)
                                nfs_nput(vdp);
                        }
                }
                                nfs_nput(vdp);
                        }
                }
-               nfs_lock(vp);
                ndp->ni_vp = (struct vnode *)0;
                ndp->ni_vp = (struct vnode *)0;
-       }
+       } else
+               nfs_unlock(vp);
        error = 0;
        nfsstats.lookupcache_misses++;
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
        error = 0;
        nfsstats.lookupcache_misses++;
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
@@ -413,14 +433,12 @@ nfs_lookup(vp, ndp)
        nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
        nfsm_fhtom(vp);
        nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
        nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
        nfsm_fhtom(vp);
        nfsm_strtom(ndp->ni_ptr, len, NFS_MAXNAMLEN);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_LOOKUP]);
 nfsmout:
        if (error) {
 nfsmout:
        if (error) {
-               if ((flag == CREATE || flag == RENAME) &&
-                       *ndp->ni_next == 0) {
-                       if (!lockparent)
-                               nfs_unlock(vp);
-               }
+               if (lockparent || (flag != CREATE && flag != RENAME) ||
+                   *ndp->ni_next != 0)
+                       nfs_lock(vp);
                return (ENOENT);
        }
        nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
                return (ENOENT);
        }
        nfsm_disect(fhp,nfsv2fh_t *,NFSX_FH);
@@ -435,6 +453,7 @@ nfsmout:
                        np = VTONFS(vp);
                } else {
                        if (error = nfs_nget(vp->v_mount, fhp, &np)) {
                        np = VTONFS(vp);
                } else {
                        if (error = nfs_nget(vp->v_mount, fhp, &np)) {
+                               nfs_lock(vp);
                                m_freem(mrep);
                                return (error);
                        }
                                m_freem(mrep);
                                return (error);
                        }
@@ -442,6 +461,7 @@ nfsmout:
                }
                if (error =
                    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
                }
                if (error =
                    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
+                       nfs_lock(vp);
                        if (newvp != vp)
                                nfs_nput(newvp);
                        else
                        if (newvp != vp)
                                nfs_nput(newvp);
                        else
@@ -450,31 +470,34 @@ nfsmout:
                        return (error);
                }
                ndp->ni_vp = newvp;
                        return (error);
                }
                ndp->ni_vp = newvp;
-               if (!lockparent)
-                       nfs_unlock(vp);
+               if (lockparent || vp == newvp)
+                       nfs_lock(vp);
                m_freem(mrep);
                return (0);
        }
 
        if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
                if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
                m_freem(mrep);
                return (0);
        }
 
        if (flag == RENAME && wantparent && *ndp->ni_next == 0) {
                if (!bcmp(VTONFS(vp)->n_fh.fh_bytes, (caddr_t)fhp, NFSX_FH)) {
+                       nfs_lock(vp);
                        m_freem(mrep);
                        return (EISDIR);
                }
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
                        m_freem(mrep);
                        return (EISDIR);
                }
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
+                       nfs_lock(vp);
                        m_freem(mrep);
                        return (error);
                }
                newvp = NFSTOV(np);
                if (error =
                    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
                        m_freem(mrep);
                        return (error);
                }
                newvp = NFSTOV(np);
                if (error =
                    nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
+                       nfs_lock(vp);
                        nfs_nput(newvp);
                        m_freem(mrep);
                        return (error);
                }
                ndp->ni_vp = newvp;
                        nfs_nput(newvp);
                        m_freem(mrep);
                        return (error);
                }
                ndp->ni_vp = newvp;
-               if (!lockparent)
-                       nfs_unlock(vp);
+               if (lockparent)
+                       nfs_lock(vp);
                return (0);
        }
 
                return (0);
        }
 
@@ -483,22 +506,22 @@ nfsmout:
                newvp = vp;
                np = VTONFS(vp);
        } else if (ndp->ni_isdotdot) {
                newvp = vp;
                np = VTONFS(vp);
        } else if (ndp->ni_isdotdot) {
-               nfs_unlock(vp);
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
                        nfs_lock(vp);
                        m_freem(mrep);
                        return (error);
                }
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
                        nfs_lock(vp);
                        m_freem(mrep);
                        return (error);
                }
-               nfs_lock(vp);
                newvp = NFSTOV(np);
        } else {
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
                newvp = NFSTOV(np);
        } else {
                if (error = nfs_nget(vp->v_mount, fhp, &np)) {
+                       nfs_lock(vp);
                        m_freem(mrep);
                        return (error);
                }
                newvp = NFSTOV(np);
        }
        if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
                        m_freem(mrep);
                        return (error);
                }
                newvp = NFSTOV(np);
        }
        if (error = nfs_loadattrcache(&newvp, &md, &dpos, (struct vattr *)0)) {
+               nfs_lock(vp);
                if (newvp != vp)
                        nfs_nput(newvp);
                else
                if (newvp != vp)
                        nfs_nput(newvp);
                else
@@ -508,8 +531,8 @@ nfsmout:
        }
        m_freem(mrep);
 
        }
        m_freem(mrep);
 
-       if (vp != newvp && (!lockparent || *ndp->ni_next != '\0'))
-               nfs_unlock(vp);
+       if (vp == newvp || (lockparent && *ndp->ni_next == '\0'))
+               nfs_lock(vp);
        ndp->ni_vp = newvp;
        if (error == 0 && ndp->ni_makeentry)
                cache_enter(ndp);
        ndp->ni_vp = newvp;
        if (error == 0 && ndp->ni_makeentry)
                cache_enter(ndp);
@@ -520,17 +543,23 @@ nfsmout:
  * nfs readlink call
  */
 nfs_readlink(vp, uiop, cred)
  * nfs readlink call
  */
 nfs_readlink(vp, uiop, cred)
-       struct vnode *vp;
+       register struct vnode *vp;
        struct uio *uiop;
        struct ucred *cred;
 {
        struct uio *uiop;
        struct ucred *cred;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        long len;
 
        nfsstats.rpccnt[NFSPROC_READLINK]++;
        nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
        nfsm_fhtom(vp);
        long len;
 
        nfsstats.rpccnt[NFSPROC_READLINK]++;
        nfsm_reqhead(nfs_procids[NFSPROC_READLINK], cred, NFSX_FH);
        nfsm_fhtom(vp);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_READLINK]);
        nfsm_strsiz(len, NFS_MAXPATHLEN);
        nfsm_mtouio(uiop, len);
        nfsm_reqdone;
        nfsm_strsiz(len, NFS_MAXPATHLEN);
        nfsm_mtouio(uiop, len);
        nfsm_reqdone;
@@ -540,13 +569,18 @@ nfs_readlink(vp, uiop, cred)
 /*
  * nfs read call
  */
 /*
  * nfs read call
  */
-nfs_readrpc(vp, uiop, offp, cred)
-       struct vnode *vp;
+nfs_readrpc(vp, uiop, cred)
+       register struct vnode *vp;
        struct uio *uiop;
        struct uio *uiop;
-       off_t *offp;
        struct ucred *cred;
 {
        struct ucred *cred;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct nfsmount *nmp;
        long len, retlen, tsiz;
 
        struct nfsmount *nmp;
        long len, retlen, tsiz;
 
@@ -558,15 +592,14 @@ nfs_readrpc(vp, uiop, offp, cred)
                nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
                nfsm_fhtom(vp);
                nfsm_build(p, u_long *, NFSX_UNSIGNED*3);
                nfsm_reqhead(nfs_procids[NFSPROC_READ], cred, NFSX_FH+NFSX_UNSIGNED*3);
                nfsm_fhtom(vp);
                nfsm_build(p, u_long *, NFSX_UNSIGNED*3);
-               *p++ = txdr_unsigned(*offp);
+               *p++ = txdr_unsigned(uiop->uio_offset);
                *p++ = txdr_unsigned(len);
                *p = 0;
                *p++ = txdr_unsigned(len);
                *p = 0;
-               nfsm_request(vp);
+               nfsm_request(vp, nonidempotent[NFSPROC_READ]);
                nfsm_loadattr(vp, (struct vattr *)0);
                nfsm_strsiz(retlen, nmp->nm_rsize);
                nfsm_mtouio(uiop, retlen);
                m_freem(mrep);
                nfsm_loadattr(vp, (struct vattr *)0);
                nfsm_strsiz(retlen, nmp->nm_rsize);
                nfsm_mtouio(uiop, retlen);
                m_freem(mrep);
-               *offp += retlen;
                if (retlen < len)
                        tsiz = 0;
                else
                if (retlen < len)
                        tsiz = 0;
                else
@@ -579,13 +612,18 @@ nfsmout:
 /*
  * nfs write call
  */
 /*
  * nfs write call
  */
-nfs_writerpc(vp, uiop, offp, cred)
-       struct vnode *vp;
+nfs_writerpc(vp, uiop, cred)
+       register struct vnode *vp;
        struct uio *uiop;
        struct uio *uiop;
-       off_t *offp;
        struct ucred *cred;
 {
        struct ucred *cred;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct nfsmount *nmp;
        long len, tsiz;
 
        struct nfsmount *nmp;
        long len, tsiz;
 
@@ -598,14 +636,13 @@ nfs_writerpc(vp, uiop, offp, cred)
                        NFSX_FH+NFSX_UNSIGNED*4);
                nfsm_fhtom(vp);
                nfsm_build(p, u_long *, NFSX_UNSIGNED*4);
                        NFSX_FH+NFSX_UNSIGNED*4);
                nfsm_fhtom(vp);
                nfsm_build(p, u_long *, NFSX_UNSIGNED*4);
-               *(p+1) = txdr_unsigned(*offp);
+               *(p+1) = txdr_unsigned(uiop->uio_offset);
                *(p+3) = txdr_unsigned(len);
                nfsm_uiotom(uiop, len);
                *(p+3) = txdr_unsigned(len);
                nfsm_uiotom(uiop, len);
-               nfsm_request(vp);
+               nfsm_request(vp, nonidempotent[NFSPROC_WRITE]);
                nfsm_loadattr(vp, (struct vattr *)0);
                m_freem(mrep);
                tsiz -= len;
                nfsm_loadattr(vp, (struct vattr *)0);
                m_freem(mrep);
                tsiz -= len;
-               *offp += len;
        }
 nfsmout:
        return (error);
        }
 nfsmout:
        return (error);
@@ -634,7 +671,13 @@ nfs_create(ndp, vap)
        register struct vattr *vap;
 {
        register struct nfsv2_sattr *sp;
        register struct vattr *vap;
 {
        register struct nfsv2_sattr *sp;
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_CREATE]++;
        nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
 
        nfsstats.rpccnt[NFSPROC_CREATE]++;
        nfsm_reqhead(nfs_procids[NFSPROC_CREATE], ndp->ni_cred,
@@ -649,7 +692,7 @@ nfs_create(ndp, vap)
        /* or should these be VNOVAL ?? */
        txdr_time(&vap->va_atime, &sp->sa_atime);
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
        /* or should these be VNOVAL ?? */
        txdr_time(&vap->va_atime, &sp->sa_atime);
        txdr_time(&vap->va_mtime, &sp->sa_mtime);
-       nfsm_request(ndp->ni_dvp);
+       nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_CREATE]);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        nfs_nput(ndp->ni_dvp);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        nfs_nput(ndp->ni_dvp);
@@ -668,7 +711,7 @@ nfs_create(ndp, vap)
  *       mpurge the vnode to flush out cmap references
  *       (This is necessary to update the vnode ref cnt as well as sensible
  *        for actual removes, to free up the buffers)
  *       mpurge the vnode to flush out cmap references
  *       (This is necessary to update the vnode ref cnt as well as sensible
  *        for actual removes, to free up the buffers)
- * 2 - If v_count > 1
+ * 2 - If v_usecount > 1
  *       If a rename is not already in the works
  *          call nfs_sillyrename() to set it up
  *     else
  *       If a rename is not already in the works
  *          call nfs_sillyrename() to set it up
  *     else
@@ -679,17 +722,25 @@ nfs_remove(ndp)
 {
        register struct vnode *vp = ndp->ni_vp;
        register struct nfsnode *np = VTONFS(ndp->ni_vp);
 {
        register struct vnode *vp = ndp->ni_vp;
        register struct nfsnode *np = VTONFS(ndp->ni_vp);
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        if (vp->v_type == VREG) {
                if (np->n_flag & (NMODIFIED|NBUFFERED)) {
                        np->n_flag &= ~(NMODIFIED|NBUFFERED);
 
        if (vp->v_type == VREG) {
                if (np->n_flag & (NMODIFIED|NBUFFERED)) {
                        np->n_flag &= ~(NMODIFIED|NBUFFERED);
-                       nfs_blkflush(vp, (daddr_t)0, np->n_size, TRUE);
+                       vinvalbuf(vp, TRUE);
                }
                }
-               if (np->n_flag & NPAGEDON)
+               if (np->n_flag & NPAGEDON) {
+                       np->n_flag &= ~NPAGEDON;
                        mpurge(vp);     /* In case cmap entries still ref it */
                        mpurge(vp);     /* In case cmap entries still ref it */
+               }
        }
        }
-       if (vp->v_count > 1) {
+       if (vp->v_usecount > 1) {
                if (!np->n_sillyrename)
                        error = nfs_sillyrename(ndp, REMOVE);
        } else {
                if (!np->n_sillyrename)
                        error = nfs_sillyrename(ndp, REMOVE);
        } else {
@@ -698,14 +749,23 @@ nfs_remove(ndp)
                        NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
                nfsm_fhtom(ndp->ni_dvp);
                nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
                        NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
                nfsm_fhtom(ndp->ni_dvp);
                nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
-               nfsm_request(ndp->ni_dvp);
+               nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
                nfsm_reqdone;
                nfsm_reqdone;
+               /*
+                * Kludge City: If the first reply to the remove rpc is lost..
+                *   the reply to the retransmitted request will be ENOENT
+                *   since the file was in fact removed
+                *   Therefore, we cheat and return success.
+                */
+               if (error == ENOENT)
+                       error = 0;
        }
        }
-       if (ndp->ni_dvp == ndp->ni_vp)
-               vrele(ndp->ni_vp);
+       np->n_attrstamp = 0;
+       if (ndp->ni_dvp == vp)
+               vrele(vp);
        else
        else
-               nfs_nput(ndp->ni_vp);
-       nfs_nput(ndp->ni_dvp);
+               nfs_nput(ndp->ni_dvp);
+       nfs_nput(vp);
        return (error);
 }
 
        return (error);
 }
 
@@ -715,14 +775,20 @@ nfs_remove(ndp)
 nfs_removeit(ndp)
        register struct nameidata *ndp;
 {
 nfs_removeit(ndp)
        register struct nameidata *ndp;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_REMOVE]++;
        nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
                NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
 
        nfsstats.rpccnt[NFSPROC_REMOVE]++;
        nfsm_reqhead(nfs_procids[NFSPROC_REMOVE], ndp->ni_cred,
                NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
-       nfsm_request(ndp->ni_dvp);
+       nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_REMOVE]);
        nfsm_reqdone;
        return (error);
 }
        nfsm_reqdone;
        return (error);
 }
@@ -733,7 +799,13 @@ nfs_removeit(ndp)
 nfs_rename(sndp, tndp)
        register struct nameidata *sndp, *tndp;
 {
 nfs_rename(sndp, tndp)
        register struct nameidata *sndp, *tndp;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
        nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
        nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
@@ -743,7 +815,7 @@ nfs_rename(sndp, tndp)
        nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_fhtom(tndp->ni_dvp);
        nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_fhtom(tndp->ni_dvp);
        nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
-       nfsm_request(sndp->ni_dvp);
+       nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
        nfsm_reqdone;
        if (sndp->ni_vp->v_type == VDIR) {
                if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
        nfsm_reqdone;
        if (sndp->ni_vp->v_type == VDIR) {
                if (tndp->ni_vp != NULL && tndp->ni_vp->v_type == VDIR)
@@ -752,6 +824,11 @@ nfs_rename(sndp, tndp)
        }
        nfs_abortop(sndp);
        nfs_abortop(tndp);
        }
        nfs_abortop(sndp);
        nfs_abortop(tndp);
+       /*
+        * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
+        */
+       if (error == ENOENT)
+               error = 0;
        return (error);
 }
 
        return (error);
 }
 
@@ -761,7 +838,13 @@ nfs_rename(sndp, tndp)
 nfs_renameit(sndp, tndp)
        register struct nameidata *sndp, *tndp;
 {
 nfs_renameit(sndp, tndp)
        register struct nameidata *sndp, *tndp;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
        nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
        nfsm_reqhead(nfs_procids[NFSPROC_RENAME], tndp->ni_cred,
@@ -771,7 +854,7 @@ nfs_renameit(sndp, tndp)
        nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_fhtom(tndp->ni_dvp);
        nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_strtom(sndp->ni_dent.d_name,sndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
        nfsm_fhtom(tndp->ni_dvp);
        nfsm_strtom(tndp->ni_dent.d_name,tndp->ni_dent.d_namlen,NFS_MAXNAMLEN);
-       nfsm_request(sndp->ni_dvp);
+       nfsm_request(sndp->ni_dvp, nonidempotent[NFSPROC_RENAME]);
        nfsm_reqdone;
        return (error);
 }
        nfsm_reqdone;
        return (error);
 }
@@ -780,10 +863,16 @@ nfs_renameit(sndp, tndp)
  * nfs hard link create call
  */
 nfs_link(vp, ndp)
  * nfs hard link create call
  */
 nfs_link(vp, ndp)
-       struct vnode *vp;
+       register struct vnode *vp;
        register struct nameidata *ndp;
 {
        register struct nameidata *ndp;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        if (ndp->ni_dvp != vp)
                nfs_lock(vp);
 
        if (ndp->ni_dvp != vp)
                nfs_lock(vp);
@@ -793,11 +882,17 @@ nfs_link(vp, ndp)
        nfsm_fhtom(vp);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
        nfsm_fhtom(vp);
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_LINK]);
        nfsm_reqdone;
        nfsm_reqdone;
+       VTONFS(vp)->n_attrstamp = 0;
        if (ndp->ni_dvp != vp)
                nfs_unlock(vp);
        nfs_nput(ndp->ni_dvp);
        if (ndp->ni_dvp != vp)
                nfs_unlock(vp);
        nfs_nput(ndp->ni_dvp);
+       /*
+        * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
+        */
+       if (error == EEXIST)
+               error = 0;
        return (error);
 }
 
        return (error);
 }
 
@@ -810,7 +905,13 @@ nfs_symlink(ndp, vap, nm)
        char *nm;               /* is this the path ?? */
 {
        register struct nfsv2_sattr *sp;
        char *nm;               /* is this the path ?? */
 {
        register struct nfsv2_sattr *sp;
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_SYMLINK]++;
        nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
 
        nfsstats.rpccnt[NFSPROC_SYMLINK]++;
        nfsm_reqhead(nfs_procids[NFSPROC_SYMLINK], ndp->ni_cred,
@@ -823,11 +924,16 @@ nfs_symlink(ndp, vap, nm)
        sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
        sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
        sp->sa_size = txdr_unsigned(VNOVAL);
        sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
        sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
        sp->sa_size = txdr_unsigned(VNOVAL);
-       txdr_time(&vap->va_atime, &sp->sa_atime);               /* or VNOVAL ?? */
+       txdr_time(&vap->va_atime, &sp->sa_atime);       /* or VNOVAL ?? */
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
-       nfsm_request(ndp->ni_dvp);
+       nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_SYMLINK]);
        nfsm_reqdone;
        nfs_nput(ndp->ni_dvp);
        nfsm_reqdone;
        nfs_nput(ndp->ni_dvp);
+       /*
+        * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
+        */
+       if (error == EEXIST)
+               error = 0;
        return (error);
 }
 
        return (error);
 }
 
@@ -835,11 +941,17 @@ nfs_symlink(ndp, vap, nm)
  * nfs make dir call
  */
 nfs_mkdir(ndp, vap)
  * nfs make dir call
  */
 nfs_mkdir(ndp, vap)
-       struct nameidata *ndp;
+       register struct nameidata *ndp;
        struct vattr *vap;
 {
        register struct nfsv2_sattr *sp;
        struct vattr *vap;
 {
        register struct nfsv2_sattr *sp;
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        nfsstats.rpccnt[NFSPROC_MKDIR]++;
        nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
 
        nfsstats.rpccnt[NFSPROC_MKDIR]++;
        nfsm_reqhead(nfs_procids[NFSPROC_MKDIR], ndp->ni_cred,
@@ -851,12 +963,17 @@ nfs_mkdir(ndp, vap)
        sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
        sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
        sp->sa_size = txdr_unsigned(VNOVAL);
        sp->sa_uid = txdr_unsigned(ndp->ni_cred->cr_uid);
        sp->sa_gid = txdr_unsigned(ndp->ni_cred->cr_gid);
        sp->sa_size = txdr_unsigned(VNOVAL);
-       txdr_time(&vap->va_atime, &sp->sa_atime);               /* or VNOVAL ?? */
+       txdr_time(&vap->va_atime, &sp->sa_atime);       /* or VNOVAL ?? */
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
        txdr_time(&vap->va_mtime, &sp->sa_mtime);       /* or VNOVAL ?? */
-       nfsm_request(ndp->ni_dvp);
+       nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_MKDIR]);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        nfs_nput(ndp->ni_dvp);
        nfsm_mtofh(ndp->ni_dvp, ndp->ni_vp);
        nfsm_reqdone;
        nfs_nput(ndp->ni_dvp);
+       /*
+        * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry.
+        */
+       if (error == EEXIST)
+               error = 0;
        return (error);
 }
 
        return (error);
 }
 
@@ -866,7 +983,13 @@ nfs_mkdir(ndp, vap)
 nfs_rmdir(ndp)
        register struct nameidata *ndp;
 {
 nfs_rmdir(ndp)
        register struct nameidata *ndp;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
 
        if (ndp->ni_dvp == ndp->ni_vp) {
                vrele(ndp->ni_dvp);
 
        if (ndp->ni_dvp == ndp->ni_vp) {
                vrele(ndp->ni_dvp);
@@ -878,12 +1001,17 @@ nfs_rmdir(ndp)
                NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
                NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(ndp->ni_dent.d_namlen));
        nfsm_fhtom(ndp->ni_dvp);
        nfsm_strtom(ndp->ni_dent.d_name, ndp->ni_dent.d_namlen, NFS_MAXNAMLEN);
-       nfsm_request(ndp->ni_dvp);
+       nfsm_request(ndp->ni_dvp, nonidempotent[NFSPROC_RMDIR]);
        nfsm_reqdone;
        cache_purge(ndp->ni_dvp);
        cache_purge(ndp->ni_vp);
        nfs_nput(ndp->ni_vp);
        nfs_nput(ndp->ni_dvp);
        nfsm_reqdone;
        cache_purge(ndp->ni_dvp);
        cache_purge(ndp->ni_vp);
        nfs_nput(ndp->ni_vp);
        nfs_nput(ndp->ni_dvp);
+       /*
+        * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
+        */
+       if (error == ENOENT)
+               error = 0;
        return (error);
 }
 
        return (error);
 }
 
@@ -893,31 +1021,35 @@ nfs_rmdir(ndp)
  * order so that it looks more sensible. This appears consistent with the
  * Ultrix implementation of NFS.
  */
  * order so that it looks more sensible. This appears consistent with the
  * Ultrix implementation of NFS.
  */
-nfs_readdir(vp, uiop, offp, cred)
-       struct vnode *vp;
+nfs_readdir(vp, uiop, cred)
+       register struct vnode *vp;
        struct uio *uiop;
        struct uio *uiop;
-       off_t *offp;
        struct ucred *cred;
 {
        register long len;
        register struct direct *dp;
        struct ucred *cred;
 {
        register long len;
        register struct direct *dp;
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1;
+       long tlen;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct mbuf *md2;
        caddr_t dpos2;
        int siz;
        struct mbuf *md2;
        caddr_t dpos2;
        int siz;
-       int more_dirs, eofflg;
+       int more_dirs;
        off_t off, savoff;
        struct direct *savdp;
 
        off_t off, savoff;
        struct direct *savdp;
 
-       nfs_lock(vp);
        nfsstats.rpccnt[NFSPROC_READDIR]++;
        nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
        nfsm_fhtom(vp);
        nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
        nfsstats.rpccnt[NFSPROC_READDIR]++;
        nfsm_reqhead(nfs_procids[NFSPROC_READDIR], cred, xid);
        nfsm_fhtom(vp);
        nfsm_build(p, u_long *, 2*NFSX_UNSIGNED);
-       off = *offp;
-       *p++ = txdr_unsigned(off);
+       *p++ = txdr_unsigned(uiop->uio_offset);
        *p = txdr_unsigned(uiop->uio_resid);
        *p = txdr_unsigned(uiop->uio_resid);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_READDIR]);
        siz = 0;
        nfsm_disect(p, u_long *, NFSX_UNSIGNED);
        more_dirs = fxdr_unsigned(int, *p);
        siz = 0;
        nfsm_disect(p, u_long *, NFSX_UNSIGNED);
        more_dirs = fxdr_unsigned(int, *p);
@@ -927,6 +1059,8 @@ nfs_readdir(vp, uiop, offp, cred)
        md2 = md;
 
        /* loop thru the dir entries, doctoring them to 4bsd form */
        md2 = md;
 
        /* loop thru the dir entries, doctoring them to 4bsd form */
+       savoff = off = 0;
+       savdp = dp = NULL;
        while (more_dirs && siz < uiop->uio_resid) {
                savoff = off;           /* Hold onto offset and dp */
                savdp = dp;
        while (more_dirs && siz < uiop->uio_resid) {
                savoff = off;           /* Hold onto offset and dp */
                savdp = dp;
@@ -940,8 +1074,13 @@ nfs_readdir(vp, uiop, offp, cred)
                        goto nfsmout;
                }
                dp->d_namlen = (u_short)len;
                        goto nfsmout;
                }
                dp->d_namlen = (u_short)len;
-               len = nfsm_rndup(len);
-               nfsm_adv(len);
+               nfsm_adv(len);          /* Point past name */
+               tlen = nfsm_rndup(len);
+               if (tlen != len) {      /* If name not on rounded boundary */
+                       *dpos = '\0';   /* Null-terminate */
+                       nfsm_adv(tlen - len);
+                       len = tlen;
+               }
                nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
                off = fxdr_unsigned(off_t, *p);
                *p++ = 0;               /* Ensures null termination of name */
                nfsm_disecton(p, u_long *, 2*NFSX_UNSIGNED);
                off = fxdr_unsigned(off_t, *p);
                *p++ = 0;               /* Ensures null termination of name */
@@ -952,37 +1091,25 @@ nfs_readdir(vp, uiop, offp, cred)
        /*
         * If at end of rpc data, get the eof boolean
         */
        /*
         * If at end of rpc data, get the eof boolean
         */
-       if (!more_dirs) {
+       if (!more_dirs)
                nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
                nfsm_disecton(p, u_long *, NFSX_UNSIGNED);
-               eofflg = fxdr_unsigned(long, *p);
-       }
        /*
         * If there is too much to fit in the data buffer, use savoff and
         * savdp to trim off the last record.
         * --> we are not at eof
         */
        if (siz > uiop->uio_resid) {
        /*
         * If there is too much to fit in the data buffer, use savoff and
         * savdp to trim off the last record.
         * --> we are not at eof
         */
        if (siz > uiop->uio_resid) {
-               eofflg = FALSE;
                off = savoff;
                siz -= dp->d_reclen;
                dp = savdp;
        }
        if (siz > 0) {
                off = savoff;
                siz -= dp->d_reclen;
                dp = savdp;
        }
        if (siz > 0) {
-#ifdef notdef
-               if (!eofflg)
-                       dp->d_reclen += (uiop->uio_resid-siz);
-#endif
                md = md2;
                dpos = dpos2;
                nfsm_mtouio(uiop, siz);
                md = md2;
                dpos = dpos2;
                nfsm_mtouio(uiop, siz);
-#ifdef notdef
-               if (!eofflg)
-                       uiop->uio_resid = 0;
-#endif
-               *offp = off;
+               uiop->uio_offset = off;
        }
        nfsm_reqdone;
        }
        nfsm_reqdone;
-       nfs_unlock(vp);
        return (error);
 }
 
        return (error);
 }
 
@@ -994,12 +1121,17 @@ nfs_statfs(mp, sbp)
        struct mount *mp;
        register struct statfs *sbp;
 {
        struct mount *mp;
        register struct statfs *sbp;
 {
+       register struct vnode *vp;
        register struct nfsv2_statfs *sfp;
        register struct nfsv2_statfs *sfp;
-       nfsm_vars;
+       register caddr_t cp;
+       register long t1;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct nfsmount *nmp;
        struct ucred *cred;
        struct nfsnode *np;
        struct nfsmount *nmp;
        struct ucred *cred;
        struct nfsnode *np;
-       struct vnode *vp;
 
        nmp = vfs_to_nfs(mp);
        if (error = nfs_nget(mp, &nmp->nm_fh, &np))
 
        nmp = vfs_to_nfs(mp);
        if (error = nfs_nget(mp, &nmp->nm_fh, &np))
@@ -1010,7 +1142,7 @@ nfs_statfs(mp, sbp)
        cred->cr_ngroups = 1;
        nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
        nfsm_fhtom(vp);
        cred->cr_ngroups = 1;
        nfsm_reqhead(nfs_procids[NFSPROC_STATFS], cred, NFSX_FH);
        nfsm_fhtom(vp);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_STATFS]);
        nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
        sbp->f_type = MOUNT_NFS;
        sbp->f_flags = nmp->nm_flag;
        nfsm_disect(sfp, struct nfsv2_statfs *, NFSX_STATFS);
        sbp->f_type = MOUNT_NFS;
        sbp->f_flags = nmp->nm_flag;
@@ -1031,7 +1163,7 @@ nfs_statfs(mp, sbp)
        return (error);
 }
 
        return (error);
 }
 
-#define        HEXTOASC(x)     "0123456789abcdef"[x]
+static char hextoasc[] = "0123456789abcdef";
 
 /*
  * Silly rename. To make the NFS filesystem that is stateless look a little
 
 /*
  * Silly rename. To make the NFS filesystem that is stateless look a little
@@ -1042,7 +1174,7 @@ nfs_statfs(mp, sbp)
  * nfs_rename() completes, but...
  */
 nfs_sillyrename(ndp, flag)
  * nfs_rename() completes, but...
  */
 nfs_sillyrename(ndp, flag)
-       struct nameidata *ndp;
+       register struct nameidata *ndp;
        int flag;
 {
        register struct nfsnode *np;
        int flag;
 {
        register struct nfsnode *np;
@@ -1065,10 +1197,10 @@ nfs_sillyrename(ndp, flag)
        pid = u.u_procp->p_pid;
        bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13);
        tndp->ni_dent.d_namlen = 12;
        pid = u.u_procp->p_pid;
        bcopy(".nfsAxxxx4.4", tndp->ni_dent.d_name, 13);
        tndp->ni_dent.d_namlen = 12;
-       tndp->ni_dent.d_name[8] = HEXTOASC(pid & 0xf);
-       tndp->ni_dent.d_name[7] = HEXTOASC((pid >> 4) & 0xf);
-       tndp->ni_dent.d_name[6] = HEXTOASC((pid >> 8) & 0xf);
-       tndp->ni_dent.d_name[5] = HEXTOASC((pid >> 12) & 0xf);
+       tndp->ni_dent.d_name[8] = hextoasc[pid & 0xf];
+       tndp->ni_dent.d_name[7] = hextoasc[(pid >> 4) & 0xf];
+       tndp->ni_dent.d_name[6] = hextoasc[(pid >> 8) & 0xf];
+       tndp->ni_dent.d_name[5] = hextoasc[(pid >> 12) & 0xf];
 
        /* Try lookitups until we get one that isn't there */
        while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) {
 
        /* Try lookitups until we get one that isn't there */
        while (nfs_lookitup(ndp->ni_dvp, tndp, (nfsv2fh_t *)0) == 0) {
@@ -1100,7 +1232,13 @@ nfs_lookitup(vp, ndp, fhp)
        register struct nameidata *ndp;
        nfsv2fh_t *fhp;
 {
        register struct nameidata *ndp;
        nfsv2fh_t *fhp;
 {
-       nfsm_vars;
+       register u_long *p;
+       register caddr_t cp;
+       register long t1, t2;
+       caddr_t bpos, dpos, cp2;
+       u_long xid;
+       int error = 0;
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        long len;
 
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
        long len;
 
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
@@ -1110,7 +1248,7 @@ nfs_lookitup(vp, ndp, fhp)
        nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
        nfsm_fhtom(vp);
        nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN);
        nfsm_reqhead(nfs_procids[NFSPROC_LOOKUP], ndp->ni_cred, NFSX_FH+NFSX_UNSIGNED+nfsm_rndup(len));
        nfsm_fhtom(vp);
        nfsm_strtom(ndp->ni_dent.d_name, len, NFS_MAXNAMLEN);
-       nfsm_request(vp);
+       nfsm_request(vp, nonidempotent[NFSPROC_LOOKUP]);
        if (fhp != NULL) {
                nfsm_disect(cp, caddr_t, NFSX_FH);
                bcopy(cp, (caddr_t)fhp, NFSX_FH);
        if (fhp != NULL) {
                nfsm_disect(cp, caddr_t, NFSX_FH);
                bcopy(cp, (caddr_t)fhp, NFSX_FH);
@@ -1214,12 +1352,9 @@ nfs_doio(bp)
        int npf, npf2;
        int reg;
        caddr_t vbase;
        int npf, npf2;
        int reg;
        caddr_t vbase;
-       caddr_t addr;
        unsigned v;
        struct proc *rp;
        int o, error;
        unsigned v;
        struct proc *rp;
        int o, error;
-       int bcnt;
-       off_t off;
        struct uio uio;
        struct iovec io;
 
        struct uio uio;
        struct iovec io;
 
@@ -1228,17 +1363,7 @@ nfs_doio(bp)
        uiop->uio_iov = &io;
        uiop->uio_iovcnt = 1;
        uiop->uio_segflg = UIO_SYSSPACE;
        uiop->uio_iov = &io;
        uiop->uio_iovcnt = 1;
        uiop->uio_segflg = UIO_SYSSPACE;
-       if (bp->b_flags & B_READ) {
-               io.iov_len = uiop->uio_resid = bp->b_bcount;
-               uiop->uio_offset = off = bp->b_blkno*DEV_BSIZE;
-               addr = bp->b_un.b_addr;
-               bcnt = bp->b_bcount;
-       } else {
-               io.iov_len = uiop->uio_resid = bp->b_dirtyend-bp->b_dirtyoff;
-               uiop->uio_offset = off = (bp->b_blkno*DEV_BSIZE)+bp->b_dirtyoff;
-               addr = bp->b_un.b_addr+bp->b_dirtyoff;
-               bcnt = bp->b_dirtyend-bp->b_dirtyoff;
-       }
+
        /*
         * For phys i/o, map the b_addr into kernel virtual space using
         * the Nfsiomap pte's
        /*
         * For phys i/o, map the b_addr into kernel virtual space using
         * the Nfsiomap pte's
@@ -1252,8 +1377,9 @@ nfs_doio(bp)
                cr->cr_uid = rp->p_uid;
                cr->cr_gid = 0;         /* Anything ?? */
                cr->cr_ngroups = 1;
                cr->cr_uid = rp->p_uid;
                cr->cr_gid = 0;         /* Anything ?? */
                cr->cr_ngroups = 1;
-               o = (int)addr & PGOFSET;
-               npf2 = npf = btoc(bcnt + o);
+               o = (int)bp->b_un.b_addr & PGOFSET;
+               npf2 = npf = btoc(bp->b_bcount + o);
+
                /*
                 * Get some mapping page table entries
                 */
                /*
                 * Get some mapping page table entries
                 */
@@ -1262,10 +1388,7 @@ nfs_doio(bp)
                        sleep((caddr_t)&nfsmap_want, PZERO-1);
                }
                reg--;
                        sleep((caddr_t)&nfsmap_want, PZERO-1);
                }
                reg--;
-               /* I know it is always the else, but that may change someday */
-               if ((bp->b_flags & B_PHYS) == 0)
-                       pte = kvtopte(bp->b_un.b_addr);
-               else if (bp->b_flags & B_PAGET)
+               if (bp->b_flags & B_PAGET)
                        pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
                else {
                        v = btop(bp->b_un.b_addr);
                        pte = &Usrptmap[btokmx((struct pte *)bp->b_un.b_addr)];
                else {
                        v = btop(bp->b_un.b_addr);
@@ -1274,6 +1397,7 @@ nfs_doio(bp)
                        else
                                pte = vtopte(rp, v);
                }
                        else
                                pte = vtopte(rp, v);
                }
+
                /*
                 * Play vmaccess() but with the Nfsiomap page table
                 */
                /*
                 * Play vmaccess() but with the Nfsiomap page table
                 */
@@ -1289,37 +1413,60 @@ nfs_doio(bp)
                        vaddr += NBPG;
                        --npf;
                }
                        vaddr += NBPG;
                        --npf;
                }
+
+               /*
+                * And do the i/o rpc
+                */
                io.iov_base = vbase+o;
                io.iov_base = vbase+o;
-       } else {
-               io.iov_base = addr;
-       }
-       if (bp->b_flags & B_READ) {
-               uiop->uio_rw = UIO_READ;
-               bp->b_error = error = nfs_readrpc(vp, uiop, &off, bp->b_rcred);
-       } else {
-               uiop->uio_rw = UIO_WRITE;
-               bp->b_error = error = nfs_writerpc(vp, uiop, &off, bp->b_wcred);
-               if (error) {
-                       np = VTONFS(vp);
-                       np->n_error = error;
-                       np->n_flag |= NWRITEERR;
+               io.iov_len = uiop->uio_resid = bp->b_bcount;
+               uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
+               if (bp->b_flags & B_READ) {
+                       uiop->uio_rw = UIO_READ;
+                       nfsstats.read_physios++;
+                       bp->b_error = error = nfs_readrpc(vp, uiop, bp->b_rcred);
+               } else {
+                       uiop->uio_rw = UIO_WRITE;
+                       nfsstats.write_physios++;
+                       bp->b_error = error = nfs_writerpc(vp, uiop, bp->b_wcred);
                }
                }
-               bp->b_dirtyoff = bp->b_dirtyend = 0;
-       }
-       if (error)
-               bp->b_flags |= B_ERROR;
-       bp->b_resid = uiop->uio_resid;
-       /*
-        * Release pte's used by physical i/o
-        */
-       if (bp->b_flags & B_PHYS) {
+
+               /*
+                * Finally, release pte's used by physical i/o
+                */
                crfree(cr);
                rmfree(nfsmap, (long)npf2, (long)++reg);
                if (nfsmap_want) {
                        nfsmap_want = 0;
                        wakeup((caddr_t)&nfsmap_want);
                }
                crfree(cr);
                rmfree(nfsmap, (long)npf2, (long)++reg);
                if (nfsmap_want) {
                        nfsmap_want = 0;
                        wakeup((caddr_t)&nfsmap_want);
                }
+       } else {
+               if (bp->b_flags & B_READ) {
+                       io.iov_len = uiop->uio_resid = bp->b_bcount;
+                       uiop->uio_offset = bp->b_blkno * DEV_BSIZE;
+                       io.iov_base = bp->b_un.b_addr;
+                       uiop->uio_rw = UIO_READ;
+                       nfsstats.read_bios++;
+                       bp->b_error = error = nfs_readrpc(vp, uiop, bp->b_rcred);
+               } else {
+                       io.iov_len = uiop->uio_resid = bp->b_dirtyend
+                               - bp->b_dirtyoff;
+                       uiop->uio_offset = (bp->b_blkno * DEV_BSIZE)
+                               + bp->b_dirtyoff;
+                       io.iov_base = bp->b_un.b_addr + bp->b_dirtyoff;
+                       uiop->uio_rw = UIO_WRITE;
+                       nfsstats.write_bios++;
+                       bp->b_error = error = nfs_writerpc(vp, uiop, bp->b_wcred);
+                       if (error) {
+                               np = VTONFS(vp);
+                               np->n_error = error;
+                               np->n_flag |= NWRITEERR;
+                       }
+                       bp->b_dirtyoff = bp->b_dirtyend = 0;
+               }
        }
        }
+       if (error)
+               bp->b_flags |= B_ERROR;
+       bp->b_resid = uiop->uio_resid;
        biodone(bp);
        return (error);
 }
        biodone(bp);
        return (error);
 }
@@ -1329,19 +1476,40 @@ nfs_doio(bp)
  *     Walk through the buffer pool and push any dirty pages
  *     associated with the vnode.
  */
  *     Walk through the buffer pool and push any dirty pages
  *     associated with the vnode.
  */
-nfs_fsync(vp, fflags, cred)
+/* ARGSUSED */
+nfs_fsync(vp, fflags, cred, waitfor)
        register struct vnode *vp;
        int fflags;
        struct ucred *cred;
        register struct vnode *vp;
        int fflags;
        struct ucred *cred;
+       int waitfor;
 {
        register struct nfsnode *np = VTONFS(vp);
 {
        register struct nfsnode *np = VTONFS(vp);
-       int error;
+       int error = 0;
 
 
-       nfs_lock(vp);
        if (np->n_flag & NMODIFIED) {
                np->n_flag &= ~NMODIFIED;
        if (np->n_flag & NMODIFIED) {
                np->n_flag &= ~NMODIFIED;
-               error = nfs_blkflush(vp, (daddr_t)0, np->n_size, FALSE);
+               vflushbuf(vp, waitfor == MNT_WAIT ? B_SYNC : 0);
        }
        }
-       nfs_unlock(vp);
+       if (!error && (np->n_flag & NWRITEERR))
+               error = np->n_error;
        return (error);
 }
        return (error);
 }
+
+/*
+ * Print out the contents of an nfsnode.
+ */
+nfs_print(vp)
+       struct vnode *vp;
+{
+       register struct nfsnode *np = VTONFS(vp);
+
+       printf("tag VT_NFS, fileid %d fsid 0x%x%s\n",
+               np->n_vattr.va_fileid, np->n_vattr.va_fsid,
+               (np->n_flag & NLOCKED) ? " (LOCKED)" : "");
+       if (np->n_lockholder == 0)
+               return;
+       printf("\towner pid %d", np->n_lockholder);
+       if (np->n_lockwaiter)
+               printf(" waiting pid %d", np->n_lockwaiter);
+       printf("\n");
+}