]> git.saurik.com Git - apple/xnu.git/blobdiff - bsd/nfs/nfs_vnops.c
xnu-344.12.2.tar.gz
[apple/xnu.git] / bsd / nfs / nfs_vnops.c
index 06f5961e339682c40e8ced030d1f7f61dadf71e9..e8c78eee83e2f04ce212067c680c982471170cd5 100644 (file)
@@ -63,7 +63,6 @@
 /*
  * vnode op calls for Sun NFS version 2 and 3
  */
-
 #include <sys/param.h>
 #include <sys/kernel.h>
 #include <sys/systm.h>
 #include <net/if.h>
 #include <netinet/in.h>
 #include <netinet/in_var.h>
-#include <kern/task.h>
 #include <vm/vm_kern.h>
 
+#include <kern/task.h>
+#include <kern/sched_prim.h>
+
 #include <sys/kdebug.h>
 
+#define FSDBG(A, B, C, D, E) \
+       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_NONE, \
+               (int)(B), (int)(C), (int)(D), (int)(E), 0)
+#define FSDBG_TOP(A, B, C, D, E) \
+       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_START, \
+               (int)(B), (int)(C), (int)(D), (int)(E), 0)
+#define FSDBG_BOT(A, B, C, D, E) \
+       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, (A))) | DBG_FUNC_END, \
+               (int)(B), (int)(C), (int)(D), (int)(E), 0)
+
 #define        TRUE    1
 #define        FALSE   0
 
@@ -324,7 +335,7 @@ static struct vnodeopv_entry_desc fifo_nfsv2nodeop_entries[] = {
        { &vop_lock_desc, (vop_t *)nfs_lock },          /* lock */
        { &vop_unlock_desc, (vop_t *)nfs_unlock },      /* unlock */
        { &vop_bmap_desc, (vop_t *)fifo_bmap },         /* bmap */
-       { &vop_strategy_desc, (vop_t *)fifo_badop },    /* strategy */
+       { &vop_strategy_desc, (vop_t *)fifo_strategy }, /* strategy */
        { &vop_print_desc, (vop_t *)nfs_print },        /* print */
        { &vop_islocked_desc, (vop_t *)nfs_islocked },  /* islocked */
        { &vop_pathconf_desc, (vop_t *)fifo_pathconf }, /* pathconf */
@@ -383,41 +394,164 @@ static int       nfsaccess_cache_timeout = NFS_MAXATTRTIMO;
                         | NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE     \
                         | NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP)
                          
-                         
+
+/* 
+ * the following are needed only by nfs_pageout to know how to handle errors
+ * see nfs_pageout comments on explanation of actions.
+ * the errors here are copied from errno.h and errors returned by servers
+ * are expected to match the same numbers here. If not, our actions maybe
+ * erroneous.
+ */
+enum actiontype {NOACTION, DUMP, DUMPANDLOG, RETRY, RETRYWITHSLEEP, SEVER};
+
+static int errorcount[ELAST+1]; /* better be zeros when initialized */
+
+static const short errortooutcome[ELAST+1] = {
+       NOACTION,
+       DUMP,                   /* EPERM        1       Operation not permitted */
+       DUMP,                   /* ENOENT       2       No such file or directory */
+       DUMPANDLOG,             /* ESRCH        3       No such process */
+       RETRY,                  /* EINTR        4       Interrupted system call */
+       DUMP,                   /* EIO          5       Input/output error */
+       DUMP,                   /* ENXIO        6       Device not configured */
+       DUMPANDLOG,             /* E2BIG        7       Argument list too long */
+       DUMPANDLOG,             /* ENOEXEC      8       Exec format error */
+       DUMPANDLOG,             /* EBADF        9       Bad file descriptor */
+       DUMPANDLOG,             /* ECHILD       10      No child processes */
+       DUMPANDLOG,             /* EDEADLK      11      Resource deadlock avoided - was EAGAIN */
+       RETRY,                  /* ENOMEM       12      Cannot allocate memory */
+       DUMP,                   /* EACCES       13      Permission denied */
+       DUMPANDLOG,             /* EFAULT       14      Bad address */
+       DUMPANDLOG,             /* ENOTBLK      15      POSIX - Block device required */
+       RETRY,                  /* EBUSY        16      Device busy */
+       DUMP,                   /* EEXIST       17      File exists */
+       DUMP,                   /* EXDEV        18      Cross-device link */
+       DUMP,                   /* ENODEV       19      Operation not supported by device */
+       DUMP,                   /* ENOTDIR      20      Not a directory */
+       DUMP,                   /* EISDIR       21      Is a directory */
+       DUMP,                   /* EINVAL       22      Invalid argument */
+       DUMPANDLOG,             /* ENFILE       23      Too many open files in system */
+       DUMPANDLOG,             /* EMFILE       24      Too many open files */
+       DUMPANDLOG,             /* ENOTTY       25      Inappropriate ioctl for device */
+       DUMPANDLOG,             /* ETXTBSY      26      Text file busy - POSIX */
+       DUMP,                   /* EFBIG        27      File too large */
+       DUMP,                   /* ENOSPC       28      No space left on device */
+       DUMPANDLOG,             /* ESPIPE       29      Illegal seek */
+       DUMP,                   /* EROFS        30      Read-only file system */
+       DUMP,                   /* EMLINK       31      Too many links */
+       RETRY,                  /* EPIPE        32      Broken pipe */
+       /* math software */
+       DUMPANDLOG,             /* EDOM                         33      Numerical argument out of domain */
+       DUMPANDLOG,             /* ERANGE                       34      Result too large */
+       RETRY,                  /* EAGAIN/EWOULDBLOCK   35      Resource temporarily unavailable */
+       DUMPANDLOG,             /* EINPROGRESS          36      Operation now in progress */
+       DUMPANDLOG,             /* EALREADY                     37      Operation already in progress */
+       /* ipc/network software -- argument errors */
+       DUMPANDLOG,             /* ENOTSOC                      38      Socket operation on non-socket */
+       DUMPANDLOG,             /* EDESTADDRREQ         39      Destination address required */
+       DUMPANDLOG,             /* EMSGSIZE                     40      Message too long */
+       DUMPANDLOG,             /* EPROTOTYPE           41      Protocol wrong type for socket */
+       DUMPANDLOG,             /* ENOPROTOOPT          42      Protocol not available */
+       DUMPANDLOG,             /* EPROTONOSUPPORT      43      Protocol not supported */
+       DUMPANDLOG,             /* ESOCKTNOSUPPORT      44      Socket type not supported */
+       DUMPANDLOG,             /* ENOTSUP                      45      Operation not supported */
+       DUMPANDLOG,             /* EPFNOSUPPORT         46      Protocol family not supported */
+       DUMPANDLOG,             /* EAFNOSUPPORT         47      Address family not supported by protocol family */
+       DUMPANDLOG,             /* EADDRINUSE           48      Address already in use */
+       DUMPANDLOG,             /* EADDRNOTAVAIL        49      Can't assign requested address */
+       /* ipc/network software -- operational errors */
+       RETRY,                  /* ENETDOWN                     50      Network is down */
+       RETRY,                  /* ENETUNREACH          51      Network is unreachable */
+       RETRY,                  /* ENETRESET            52      Network dropped connection on reset */
+       RETRY,                  /* ECONNABORTED         53      Software caused connection abort */
+       RETRY,                  /* ECONNRESET           54      Connection reset by peer */
+       RETRY,                  /* ENOBUFS                      55      No buffer space available */
+       RETRY,                  /* EISCONN                      56      Socket is already connected */
+       RETRY,                  /* ENOTCONN                     57      Socket is not connected */
+       RETRY,                  /* ESHUTDOWN            58      Can't send after socket shutdown */
+       RETRY,                  /* ETOOMANYREFS         59      Too many references: can't splice */
+       RETRY,                  /* ETIMEDOUT            60      Operation timed out */
+       RETRY,                  /* ECONNREFUSED         61      Connection refused */
+
+       DUMPANDLOG,             /* ELOOP                        62      Too many levels of symbolic links */
+       DUMP,                   /* ENAMETOOLONG         63      File name too long */
+       RETRY,                  /* EHOSTDOWN            64      Host is down */ 
+       RETRY,                  /* EHOSTUNREACH         65      No route to host */
+       DUMP,                   /* ENOTEMPTY            66      Directory not empty */
+       /* quotas & mush */     
+       DUMPANDLOG,             /* PROCLIM                      67      Too many processes */
+       DUMPANDLOG,             /* EUSERS                       68      Too many users */
+       DUMPANDLOG,             /* EDQUOT                       69      Disc quota exceeded */   
+       /* Network File System */
+       DUMP,                   /* ESTALE                       70      Stale NFS file handle */
+       DUMP,                   /* EREMOTE                      71      Too many levels of remote in path */
+       DUMPANDLOG,             /* EBADRPC                      72      RPC struct is bad */
+       DUMPANDLOG,             /* ERPCMISMATCH         73      RPC version wrong */
+       DUMPANDLOG,             /* EPROGUNAVAIL         74      RPC prog. not avail */
+       DUMPANDLOG,             /* EPROGMISMATCH        75      Program version wrong */
+       DUMPANDLOG,             /* EPROCUNAVAIL         76      Bad procedure for program */
+
+       DUMPANDLOG,             /* ENOLCK                       77      No locks available */
+       DUMPANDLOG,             /* ENOSYS                       78      Function not implemented */
+       DUMPANDLOG,             /* EFTYPE                       79      Inappropriate file type or format */  
+       DUMPANDLOG,             /* EAUTH                        80      Authentication error */
+       DUMPANDLOG,             /* ENEEDAUTH            81      Need authenticator */
+       /* Intelligent device errors */
+       DUMPANDLOG,             /* EPWROFF                      82      Device power is off */
+       DUMPANDLOG,             /* EDEVERR                      83      Device error, e.g. paper out */
+       DUMPANDLOG,             /* EOVERFLOW            84      Value too large to be stored in data type */
+       /* Program loading errors */
+       DUMPANDLOG,             /* EBADEXEC                     85      Bad executable */
+       DUMPANDLOG,             /* EBADARCH                     86      Bad CPU type in executable */
+       DUMPANDLOG,             /* ESHLIBVERS           87      Shared library version mismatch */
+       DUMPANDLOG,             /* EBADMACHO            88      Malformed Macho file */
+};
+
+
+static short
+nfs_pageouterrorhandler(error)
+       int error;
+{
+       if (error > ELAST) 
+               return(DUMP);
+       else 
+               return(errortooutcome[error]);
+}
 
 static int
 nfs3_access_otw(struct vnode *vp,  
-                int wmode,
-                struct proc *p,
-                struct ucred *cred)  
+               int wmode,
+               struct proc *p,
+               struct ucred *cred)  
 {
-        const int v3 = 1;
-        u_int32_t *tl;
-        int error = 0, attrflag;
-
-        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-        caddr_t bpos, dpos, cp2;
-        register int32_t t1, t2;
-        register caddr_t cp;
-        u_int32_t rmode;
-        struct nfsnode *np = VTONFS(vp);
-
-        nfsstats.rpccnt[NFSPROC_ACCESS]++;   
-        nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
-        nfsm_fhtom(vp, v3);
-        nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
-        *tl = txdr_unsigned(wmode);
-        nfsm_request(vp, NFSPROC_ACCESS, p, cred);
-        nfsm_postop_attr(vp, attrflag);
-        if (!error) {
-                nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
-                rmode = fxdr_unsigned(u_int32_t, *tl);
-                np->n_mode = rmode;
-                np->n_modeuid = cred->cr_uid;
-                np->n_modestamp = time_second;
-        }
-        nfsm_reqdone;
-        return error;
+       const int v3 = 1;
+       u_int32_t *tl;
+       int error = 0, attrflag;
+
+       struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       caddr_t bpos, dpos, cp2;
+       register int32_t t1, t2;
+       register caddr_t cp;
+       u_int32_t rmode;
+       struct nfsnode *np = VTONFS(vp);
+       u_int64_t xid;
+
+       nfsstats.rpccnt[NFSPROC_ACCESS]++;   
+       nfsm_reqhead(vp, NFSPROC_ACCESS, NFSX_FH(v3) + NFSX_UNSIGNED);
+       nfsm_fhtom(vp, v3);
+       nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
+       *tl = txdr_unsigned(wmode);
+       nfsm_request(vp, NFSPROC_ACCESS, p, cred, &xid);
+       nfsm_postop_attr(vp, attrflag, &xid);
+       if (!error) {
+               nfsm_dissect(tl, u_int32_t *, NFSX_UNSIGNED);
+               rmode = fxdr_unsigned(u_int32_t, *tl);
+               np->n_mode = rmode;
+               np->n_modeuid = cred->cr_uid;
+               np->n_modestamp = time_second;
+       }
+       nfsm_reqdone;
+       return error;
 }
 
 /*
@@ -436,10 +570,10 @@ nfs_access(ap)
        } */ *ap;
 {
        register struct vnode *vp = ap->a_vp;
-        int error = 0;
-        u_long mode, wmode;
+       int error = 0;
+       u_long mode, wmode;
        int v3 = NFS_ISV3(vp);
-        struct nfsnode *np = VTONFS(vp);
+       struct nfsnode *np = VTONFS(vp);
 
        /*
         * For nfs v3, do an access rpc, otherwise you are stuck emulating
@@ -456,63 +590,62 @@ nfs_access(ap)
                        mode = 0;
                if (vp->v_type == VDIR) {
                        if (ap->a_mode & VWRITE)
-                               mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND |
-                                        NFSV3ACCESS_DELETE);
+                               mode |= NFSV3ACCESS_MODIFY |
+                                       NFSV3ACCESS_EXTEND | NFSV3ACCESS_DELETE;
                        if (ap->a_mode & VEXEC)
                                mode |= NFSV3ACCESS_LOOKUP;
                } else {
                        if (ap->a_mode & VWRITE)
-                               mode |= (NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND);
+                               mode |= NFSV3ACCESS_MODIFY | NFSV3ACCESS_EXTEND;
                        if (ap->a_mode & VEXEC)
                                mode |= NFSV3ACCESS_EXECUTE;
                }
-                /* XXX safety belt, only make blanket request if caching */
-                if (nfsaccess_cache_timeout > 0) {
-                        wmode = NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY |
-                                NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE |
-                                NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP;
-                } else {
-                        wmode = mode;
-                }
+               /* XXX safety belt, only make blanket request if caching */
+               if (nfsaccess_cache_timeout > 0) {
+                       wmode = NFSV3ACCESS_READ | NFSV3ACCESS_MODIFY |
+                               NFSV3ACCESS_EXTEND | NFSV3ACCESS_EXECUTE |
+                               NFSV3ACCESS_DELETE | NFSV3ACCESS_LOOKUP;
+               } else
+                       wmode = mode;
                 
-                /*
-                 * Does our cached result allow us to give a definite yes to
-                 * this request?
-                 */     
-                if ((time_second < (np->n_modestamp + nfsaccess_cache_timeout)) &&
-                    (ap->a_cred->cr_uid == np->n_modeuid) &&
-                    ((np->n_mode & mode) == mode)) {
-                        /* nfsstats.accesscache_hits++; */
-                } else {
-                        /*
-                         * Either a no, or a don't know.  Go to the wire.
-                         */
-                       /* nfsstats.accesscache_misses++; */
-                       error = nfs3_access_otw(vp, wmode, ap->a_p,ap->a_cred);
-                       if (!error) {
-                            if ((np->n_mode & mode) != mode)
-                               error = EACCES;
-                        }
-                }
+               /*
+                * Does our cached result allow us to give a definite yes to
+                * this request?
+                */     
+               if (time_second < np->n_modestamp + nfsaccess_cache_timeout &&
+                   ap->a_cred->cr_uid == np->n_modeuid &&
+                   (np->n_mode & mode) == mode) {
+                       /* nfsstats.accesscache_hits++; */
+               } else {
+                       /*
+                        * Either a no, or a don't know.  Go to the wire.
+                        */
+                       /* nfsstats.accesscache_misses++; */
+                       error = nfs3_access_otw(vp, wmode, ap->a_p,ap->a_cred);
+                       if (!error) {
+                               if ((np->n_mode & mode) != mode)
+                                       error = EACCES;
+                       }
+               }
        } else
-               return (nfsspec_access(ap)); /* NFSv2 case checks for EROFS here*/
-       /* CSM - moved EROFS check down per NetBSD rev 1.71.  So you
-        * get the correct error value with layered filesystems. 
-         * EKN - moved the return(error) below this so it does get called.*/
+               return (nfsspec_access(ap)); /* NFSv2 case checks for EROFS here */
        /*
         * Disallow write attempts on filesystems mounted read-only;
         * unless the file is a socket, fifo, or a block or character
         * device resident on the filesystem.
+        * CSM - moved EROFS check down per NetBSD rev 1.71.  So you
+        * get the correct error value with layered filesystems. 
+        * EKN - moved the return(error) below this so it does get called.       
         */
        if (!error && (ap->a_mode & VWRITE) && (vp->v_mount->mnt_flag & MNT_RDONLY)) {
                switch (vp->v_type) {
-               case VREG: case VDIR: case VLNK:
-                       error = EROFS;
-                default: 
-                        break;
+                       case VREG: case VDIR: case VLNK:
+                               error = EROFS;
+                       default: 
+                               break;
                }
        }
-        return (error);
+       return (error);
 }
 
 /*
@@ -523,6 +656,7 @@ nfs_access(ap)
  * if consistency is lost.
  */
 /* ARGSUSED */
+
 static int
 nfs_open(ap)
        struct vop_open_args /* {
@@ -538,10 +672,9 @@ nfs_open(ap)
        struct vattr vattr;
        int error;
 
-       if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK)
-{ printf("open eacces vtyp=%d\n",vp->v_type);
+       if (vp->v_type != VREG && vp->v_type != VDIR && vp->v_type != VLNK) {
                return (EACCES);
-}
+       }
        /*
         * Get a valid lease. If cached data is stale, flush it.
         */
@@ -648,8 +781,13 @@ nfs_close(ap)
            if ((VFSTONFS(vp->v_mount)->nm_flag & NFSMNT_NQNFS) == 0 &&
                (np->n_flag & NMODIFIED)) {
                if (NFS_ISV3(vp)) {
-                   error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 0);
-                   np->n_flag &= ~NMODIFIED;
+                   error = nfs_flush(vp, ap->a_cred, MNT_WAIT, ap->a_p, 1);
+                    /*
+                     * We cannot clear the NMODIFIED bit in np->n_flag due to
+                     * potential races with other processes
+                    * NMODIFIED is a hint
+                     */
+                   /* np->n_flag &= ~NMODIFIED; */
                } else
                    error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred, ap->a_p, 1);
                np->n_attrstamp = 0;
@@ -683,65 +821,72 @@ nfs_getattr(ap)
        int error = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        int v3 = NFS_ISV3(vp);
+       u_int64_t xid;
+       int avoidfloods;
        
+       FSDBG_TOP(513, np->n_size, np, np->n_vattr.va_size, np->n_flag);
        /*
         * Update local times for special files.
         */
        if (np->n_flag & (NACC | NUPD))
                np->n_flag |= NCHG;
-
-       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 513)) | DBG_FUNC_START,
-                    (int)np->n_size, 0, (int)np->n_vattr.va_size, np->n_flag, 0);
-
        /*
         * First look in the cache.
         */
        if ((error = nfs_getattrcache(vp, ap->a_vap)) == 0) {
-               KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 513)) | DBG_FUNC_END,
-                            (int)np->n_size, 0, (int)np->n_vattr.va_size, np->n_flag, 0);
-
+               FSDBG_BOT(513, np->n_size, 0, np->n_vattr.va_size, np->n_flag);
                return (0);
        }
-       if (error != ENOENT)
+       if (error != ENOENT) {
+               FSDBG_BOT(513, np->n_size, error, np->n_vattr.va_size,
+                         np->n_flag);
                return (error);
+       }
        error = 0;
-        
+
        if (v3 && nfsaccess_cache_timeout > 0) {
                /*  nfsstats.accesscache_misses++; */
-               if (error = nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_p, ap->a_cred))
-                    return (error);
+               if (error = nfs3_access_otw(vp, NFSV3ACCESS_ALL, ap->a_p,
+                                           ap->a_cred))
+                       return (error);
                if ((error = nfs_getattrcache(vp, ap->a_vap)) == 0)
                        return (0);
                if (error != ENOENT)
                        return (error);
                error = 0;
        }
-
+       avoidfloods = 0;
+tryagain:
        nfsstats.rpccnt[NFSPROC_GETATTR]++;
        nfsm_reqhead(vp, NFSPROC_GETATTR, NFSX_FH(v3));
        nfsm_fhtom(vp, v3);
-       nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred);
+       nfsm_request(vp, NFSPROC_GETATTR, ap->a_p, ap->a_cred, &xid);
        if (!error) {
-               nfsm_loadattr(vp, ap->a_vap);
+               nfsm_loadattr(vp, ap->a_vap, &xid);
+               if (!xid) { /* out-of-order rpc - attributes were dropped */
+                       m_freem(mrep);
+                       FSDBG(513, -1, np, np->n_xid << 32, np->n_xid);
+                       if (avoidfloods++ < 100)
+                               goto tryagain;
+                       /*
+                        * avoidfloods>1 is bizarre.  at 100 pull the plug
+                        */
+                       panic("nfs_getattr: getattr flood\n");
+               }
                if (np->n_mtime != ap->a_vap->va_mtime.tv_sec) {
-                       NFSTRACE(NFSTRC_GA_INV, vp);
+                       FSDBG(513, -1, np, -1, vp);
                        if (vp->v_type == VDIR)
                                nfs_invaldir(vp);
                        error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
                                              ap->a_p, 1);
-                       if (!error) {
-                               NFSTRACE(NFSTRC_GA_INV1, vp);
+                       FSDBG(513, -1, np, -2, error);
+                       if (!error)
                                np->n_mtime = ap->a_vap->va_mtime.tv_sec;
-                       } else {
-                               NFSTRACE(NFSTRC_GA_INV2, error);
-                       }
                }
        }
        nfsm_reqdone;
 
-       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 513)) | DBG_FUNC_END,
-                    (int)np->n_size, -1, (int)np->n_vattr.va_size, error, 0);
-
+       FSDBG_BOT(513, np->n_size, -1, np->n_vattr.va_size, error);
        return (error);
 }
 
@@ -767,6 +912,15 @@ nfs_setattr(ap)
 #ifndef nolint
        tsize = (u_quad_t)0;
 #endif
+
+#ifdef XXX /* enable this code soon! (but test it first) */
+       /*                
+        * Setting of flags is not supported.
+        */
+       if (vap->va_flags != VNOVAL)
+               return (EOPNOTSUPP);
+#endif
+
        /*
         * Disallow write attempts if the filesystem is mounted read-only.
         */
@@ -798,72 +952,63 @@ nfs_setattr(ap)
                         */
                        if (vp->v_mount->mnt_flag & MNT_RDONLY)
                                return (EROFS);
-                       np->n_flag |= NMODIFIED;
-                       tsize = np->n_size;
-                       
-                       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 512)) | DBG_FUNC_START,
-                                    (int)np->n_size, (int)vap->va_size, (int)np->n_vattr.va_size, np->n_flag, 0);
-
-                       if (vap->va_size == 0)
-                               error = nfs_vinvalbuf(vp, 0,
-                                       ap->a_cred, ap->a_p, 1);
-                       else
-                               error = nfs_vinvalbuf(vp, V_SAVE,
-                                       ap->a_cred, ap->a_p, 1);
-
-                       if (UBCISVALID(vp))
-                               ubc_setsize(vp, (off_t)vap->va_size); /* XXX check error */
-
-                       if (error) {
-                               printf("nfs_setattr: nfs_vinvalbuf %d\n", error);
-
-#if DIAGNOSTIC
-                               kprintf("nfs_setattr: nfs_vinvalbuf %d\n",
-                                       error);
-#endif /* DIAGNOSTIC */
-                               if (UBCISVALID(vp))
-                                       ubc_setsize(vp, (off_t)tsize); /* XXX check error */
-
-                               KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 512)) | DBG_FUNC_END,
-                                            (int)np->n_size, (int)vap->va_size, (int)np->n_vattr.va_size, -1, 0);
-
-                               return (error);
+                       FSDBG_TOP(512, np->n_size, vap->va_size,
+                                 np->n_vattr.va_size, np->n_flag);
+                       if (np->n_flag & NMODIFIED) {
+                               if (vap->va_size == 0)
+                                       error = nfs_vinvalbuf(vp, 0,
+                                               ap->a_cred, ap->a_p, 1);
+                               else
+                                       error = nfs_vinvalbuf(vp, V_SAVE,
+                                               ap->a_cred, ap->a_p, 1);
+                               if (error) {
+                                       printf("nfs_setattr: nfs_vinvalbuf %d\n", error);
+                                       FSDBG_BOT(512, np->n_size, vap->va_size,
+                                                 np->n_vattr.va_size, -1);
+                                       return (error);
+                               }
+                       } else if (np->n_size > vap->va_size) { /* shrinking? */
+                               daddr_t obn, bn;
+                               int biosize;
+                               struct buf *bp;
+
+                               biosize = min(vp->v_mount->mnt_stat.f_iosize,
+                                             PAGE_SIZE);
+                               obn = (np->n_size - 1) / biosize;
+                               bn = vap->va_size / biosize; 
+                               for ( ; obn >= bn; obn--)
+                                       if (incore(vp, obn)) {
+                                               bp = getblk(vp, obn, biosize, 0,
+                                                           0, BLK_READ);
+                                               FSDBG(512, bp, bp->b_flags,
+                                                     0, obn);
+                                               SET(bp->b_flags, B_INVAL);
+                                               brelse(bp);
+                                       }
                        }
+                       tsize = np->n_size;
                        np->n_size = np->n_vattr.va_size = vap->va_size;
-
+                       ubc_setsize(vp, (off_t)vap->va_size); /* XXX */
                };
        } else if ((vap->va_mtime.tv_sec != VNOVAL ||
-                   vap->va_atime.tv_sec != VNOVAL) && (np->n_flag & NMODIFIED) &&
-                  vp->v_type == VREG &&
+                   vap->va_atime.tv_sec != VNOVAL) &&
+                  (np->n_flag & NMODIFIED) && vp->v_type == VREG &&
                   (error = nfs_vinvalbuf(vp, V_SAVE, ap->a_cred,
                                          ap->a_p, 1)) == EINTR)
-               return (error);
-
+               return (error);
        error = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
-
-       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 512)) | DBG_FUNC_END,
-                    (int)np->n_size, (int)vap->va_size, (int)np->n_vattr.va_size, error, 0);
-
+       FSDBG_BOT(512, np->n_size, vap->va_size, np->n_vattr.va_size, error);
        if (error && vap->va_size != VNOVAL) {
                /* make every effort to resync file size w/ server... */
                int err = 0; /* preserve "error" for return */
 
                printf("nfs_setattr: nfs_setattrrpc %d\n", error);
-#if DIAGNOSTIC
-               kprintf("nfs_setattr: nfs_setattrrpc %d\n", error);
-#endif /* DIAGNOSTIC */
                np->n_size = np->n_vattr.va_size = tsize;
-               if (UBCISVALID(vp))
-                       ubc_setsize(vp, (off_t)np->n_size); /* XXX check error */
+               ubc_setsize(vp, (off_t)np->n_size); /* XXX check error */
                vap->va_size = tsize;
                err = nfs_setattrrpc(vp, vap, ap->a_cred, ap->a_p);
-
                if (err)
                        printf("nfs_setattr1: nfs_setattrrpc %d\n", err);
-#if DIAGNOSTIC
-               if (err)
-                       kprintf("nfs_setattr nfs_setattrrpc %d\n", err);
-#endif /* DIAGNOSTIC */
        }
        return (error);
 }
@@ -886,6 +1031,7 @@ nfs_setattrrpc(vp, vap, cred, procp)
        int error = 0, wccflag = NFSV3_WCCRATTR;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        int v3 = NFS_ISV3(vp);
+       u_int64_t xid;
 
        nfsstats.rpccnt[NFSPROC_SETATTR]++;
        nfsm_reqhead(vp, NFSPROC_SETATTR, NFSX_FH(v3) + NFSX_SATTR(v3));
@@ -969,13 +1115,13 @@ nfs_setattrrpc(vp, vap, cred, procp)
                txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
                txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
        }
-       nfsm_request(vp, NFSPROC_SETATTR, procp, cred);
+       nfsm_request(vp, NFSPROC_SETATTR, procp, cred, &xid);
        if (v3) {
-               nfsm_wcc_data(vp, wccflag);
-               if ((!wccflag) && (vp->v_type != VBAD)) /* EINVAL set on VBAD vnode */
-                       VTONFS(vp)->n_attrstamp = 0;
+               nfsm_wcc_data(vp, wccflag, &xid);
+               if (!wccflag && vp->v_type != VBAD) /* EINVAL on VBAD node */
+                       VTONFS(vp)->n_attrstamp = 0;
        } else
-               nfsm_loadattr(vp, (struct vattr *)0);
+               nfsm_loadattr(vp, (struct vattr *)0, &xid);
        nfsm_reqdone;
        return (error);
 }
@@ -1011,7 +1157,8 @@ nfs_lookup(ap)
        int lockparent, wantparent, error = 0, attrflag, fhsize;
        int v3 = NFS_ISV3(dvp);
        struct proc *p = cnp->cn_proc;
-        int worldbuildworkaround = 1;
+       int worldbuildworkaround = 1;
+       u_int64_t xid;
 
        if ((flags & ISLASTCN) && (dvp->v_mount->mnt_flag & MNT_RDONLY) &&
            (cnp->cn_nameiop == DELETE || cnp->cn_nameiop == RENAME))
@@ -1023,20 +1170,22 @@ nfs_lookup(ap)
        wantparent = flags & (LOCKPARENT|WANTPARENT);
        nmp = VFSTONFS(dvp->v_mount);
        np = VTONFS(dvp);
-        
-        if (worldbuildworkaround) {
-        /* temporary workaround for world builds to not have dvp go
-            VBAD on during server calls in this routine. When
-            the real ref counting problem is found take this out.
-            Note if this was later and before the nfsm_request
-            set up, the workaround did not work (NOTE other difference
-            was I only put one VREF in that time. Thus it needs
-            to be above the cache_lookup branch or with 2 VREFS. Not
-            sure which. Can't play with world builds right now to see
-            which.  VOP_ACCESS could also make it go to server.  - EKN */
-            VREF(dvp);   /* hang on to this dvp - EKN */
-            VREF(dvp);   /* hang on tight - EKN  */
-        }
+
+       if (worldbuildworkaround) {
+               /* 
+                * Temporary workaround for world builds to not have dvp go
+                * VBAD on during server calls in this routine. When
+                * the real ref counting problem is found take this out.
+                * Note if this was later and before the nfsm_request
+                * set up, the workaround did not work (NOTE other difference
+                * was I only put one VREF in that time. Thus it needs
+                * to be above the cache_lookup branch or with 2 VREFS. Not
+                * sure which. Can't play with world builds right now to see
+                * which.  VOP_ACCESS could also make it go to server.  - EKN
+                */
+               VREF(dvp);   /* hang on to this dvp - EKN */
+               VREF(dvp);   /* hang on tight - EKN  */
+               }
 
        if ((error = cache_lookup(dvp, vpp, cnp)) && error != ENOENT) {
                struct vattr vattr;
@@ -1044,21 +1193,14 @@ nfs_lookup(ap)
 
                if ((error = VOP_ACCESS(dvp, VEXEC, cnp->cn_cred, p))) {
                        *vpp = NULLVP;
-                        if (worldbuildworkaround) {
-                            vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                            vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                        }
-                       return (error);
-               }
-                
-                /* got to check to make sure the vnode didn't go away if access went to server */
-                if ((*vpp)->v_type == VBAD) {
-                       if (worldbuildworkaround) {
-                            vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                            vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                        }
-                        return(EINVAL);
-                }
+                       goto error_return;
+                       }
+
+               /* got to check to make sure the vnode didn't go away if access went to server */
+               if ((*vpp)->v_type == VBAD) {
+                       error = EINVAL;
+                       goto error_return;
+                       }
 
                newvp = *vpp;
                vpid = newvp->v_id;
@@ -1082,47 +1224,33 @@ nfs_lookup(ap)
                if (!error) {
                        if (vpid == newvp->v_id) {
                           if (!VOP_GETATTR(newvp, &vattr, cnp->cn_cred, p)
-                           && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
-                               nfsstats.lookupcache_hits++;
-                               if (cnp->cn_nameiop != LOOKUP &&
-                                   (flags & ISLASTCN))
-                                       cnp->cn_flags |= SAVENAME;
-                                        
-                                if (worldbuildworkaround) {
-                                    vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                                    vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                                }
-                                
-                               return (0);
-                          }
-                          cache_purge(newvp);
-                        }
+                                       && vattr.va_ctime.tv_sec == VTONFS(newvp)->n_ctime) {
+                                       nfsstats.lookupcache_hits++;
+                                       if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
+                                               cnp->cn_flags |= SAVENAME;
+                                       error = 0; /* ignore any from VOP_GETATTR  */
+                                       goto error_return;
+                               }
+                               cache_purge(newvp);
+                       }
                        vput(newvp);
                        if (lockparent && dvp != newvp && (flags & ISLASTCN))
                                VOP_UNLOCK(dvp, 0, p);
                }
                error = vn_lock(dvp, LK_EXCLUSIVE, p);
                *vpp = NULLVP;
-               if (error) {
-                        if (worldbuildworkaround) {
-                            vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                            vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                        }
-                       return (error);
-                }
+               if (error) 
+                       goto error_return;
        }
-        
+
        /* 
-         * Got to check to make sure the vnode didn't go away if VOP_GETATTR went to server
+        * Got to check to make sure the vnode didn't go away if VOP_GETATTR went to server
         * or callers prior to this blocked and had it go VBAD.
-         */
-       if (dvp->v_type == VBAD) {                   
-            if (worldbuildworkaround) {
-                vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-                }
-            return(EINVAL);
-        }
+        */
+       if (dvp->v_type == VBAD) { 
+               error = EINVAL;
+               goto error_return;
+       }
 
        error = 0;
        newvp = NULLVP;
@@ -1133,19 +1261,11 @@ nfs_lookup(ap)
                NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
        nfsm_fhtom(dvp, v3);
        nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
-       nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred);
-        
-        /* this two lines set dvp refcounts back to where they were
-        * before we took extra 2 VREFS to avoid VBAD vnode on dvp
-        * during server calls for world builds. Remove when real
-        * fix is found. - EKN */
-        if (worldbuildworkaround) {
-            vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-            vrele(dvp);  /* end of hanging on tight to dvp - EKN */
-            }
+       /* nfsm_request for NFSv2 causes you to goto to nfsmout upon errors */
+       nfsm_request(dvp, NFSPROC_LOOKUP, cnp->cn_proc, cnp->cn_cred, &xid); 
 
        if (error) {
-               nfsm_postop_attr(dvp, attrflag);
+               nfsm_postop_attr(dvp, attrflag, &xid);
                m_freem(mrep);
                goto nfsmout;
        }
@@ -1157,24 +1277,28 @@ nfs_lookup(ap)
        if (cnp->cn_nameiop == RENAME && wantparent && (flags & ISLASTCN)) {
                if (NFS_CMPFH(np, fhp, fhsize)) {
                        m_freem(mrep);
-                       return (EISDIR);
+                       error = EISDIR;
+                       goto error_return;
                }
                if ((error = nfs_nget(dvp->v_mount, fhp, fhsize, &np))) {
                        m_freem(mrep);
-                       return (error);
+                       goto error_return;
                }
                newvp = NFSTOV(np);
                if (v3) {
-                       nfsm_postop_attr(newvp, attrflag);
-                       nfsm_postop_attr(dvp, attrflag);
+                       u_int64_t dxid = xid;
+
+                       nfsm_postop_attr(newvp, attrflag, &xid);
+                       nfsm_postop_attr(dvp, attrflag, &dxid);
                } else
-                       nfsm_loadattr(newvp, (struct vattr *)0);
+                       nfsm_loadattr(newvp, (struct vattr *)0, &xid);
                *vpp = newvp;
                m_freem(mrep);
                cnp->cn_flags |= SAVENAME;
                if (!lockparent)
                        VOP_UNLOCK(dvp, 0, p);
-               return (0);
+               error = 0;
+               goto error_return;
        }
 
        if (flags & ISDOTDOT) {
@@ -1182,13 +1306,13 @@ nfs_lookup(ap)
                error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
                if (error) {
                        vn_lock(dvp, LK_EXCLUSIVE + LK_RETRY, p);
-                       return (error);
+                       goto error_return;
                }
                newvp = NFSTOV(np);
                if (lockparent && (flags & ISLASTCN) &&
                    (error = vn_lock(dvp, LK_EXCLUSIVE, p))) {
                        vput(newvp);
-                       return (error);
+                       goto error_return;
                }
        } else if (NFS_CMPFH(np, fhp, fhsize)) {
                VREF(dvp);
@@ -1196,17 +1320,19 @@ nfs_lookup(ap)
        } else {
                if ((error = nfs_nget(dvp->v_mount, fhp, fhsize, &np))) {
                        m_freem(mrep);
-                       return (error);
+                       goto error_return;
                }
                if (!lockparent || !(flags & ISLASTCN))
                        VOP_UNLOCK(dvp, 0, p);
                newvp = NFSTOV(np);
        }
        if (v3) {
-               nfsm_postop_attr(newvp, attrflag);
-               nfsm_postop_attr(dvp, attrflag);
+               u_int64_t dxid = xid;
+
+               nfsm_postop_attr(newvp, attrflag, &xid);
+               nfsm_postop_attr(dvp, attrflag, &dxid);
        } else
-               nfsm_loadattr(newvp, (struct vattr *)0);
+               nfsm_loadattr(newvp, (struct vattr *)0, &xid);
        if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
                cnp->cn_flags |= SAVENAME;
        if ((cnp->cn_flags & MAKEENTRY) &&
@@ -1233,6 +1359,18 @@ nfs_lookup(ap)
                if (cnp->cn_nameiop != LOOKUP && (flags & ISLASTCN))
                        cnp->cn_flags |= SAVENAME;
        }
+error_return:
+       /*
+        * These "vreles" set dvp refcounts back to where they were
+        * before we took extra 2 VREFS to avoid VBAD vnode on dvp
+        * during server calls for world builds. Remove when real
+        * fix is found. - EKN 
+        */
+       if (worldbuildworkaround) {
+               vrele(dvp);  /* end of hanging on tight to dvp - EKN */
+               vrele(dvp);  /* end of hanging on tight to dvp - EKN */
+       }
+
        return (error);
 }
 
@@ -1256,6 +1394,7 @@ nfs_read(ap)
        return (nfs_bioread(vp, ap->a_uio, ap->a_ioflag, ap->a_cred, 0));
 }
 
+
 /*
  * nfs readlink call
  */
@@ -1291,17 +1430,18 @@ nfs_readlinkrpc(vp, uiop, cred)
        int error = 0, len, attrflag;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        int v3 = NFS_ISV3(vp);
+       u_int64_t xid;
 
        nfsstats.rpccnt[NFSPROC_READLINK]++;
        nfsm_reqhead(vp, NFSPROC_READLINK, NFSX_FH(v3));
        nfsm_fhtom(vp, v3);
-       nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred);
+       nfsm_request(vp, NFSPROC_READLINK, uiop->uio_procp, cred, &xid);
        if (v3)
-               nfsm_postop_attr(vp, attrflag);
+               nfsm_postop_attr(vp, attrflag, &xid);
        if (!error) {
                nfsm_strsiz(len, NFS_MAXPATHLEN);
-               if (len == NFS_MAXPATHLEN) {
-                        struct nfsnode *np = VTONFS(vp);
+               if (len == NFS_MAXPATHLEN) {
+                       struct nfsnode *np = VTONFS(vp);
 #if DIAGNOSTIC
                         if (!np)
                                 panic("nfs_readlinkrpc: null np");
@@ -1333,13 +1473,15 @@ nfs_readrpc(vp, uiop, cred)
        struct nfsmount *nmp;
        int error = 0, len, retlen, tsiz, eof, attrflag;
        int v3 = NFS_ISV3(vp);
+       u_int64_t xid;
 
 #ifndef nolint
        eof = 0;
 #endif
        nmp = VFSTONFS(vp->v_mount);
        tsiz = uiop->uio_resid;
-        if (((u_int64_t)uiop->uio_offset + (unsigned int)tsiz > 0xffffffff) && !v3)
+        if (((u_int64_t)uiop->uio_offset + (unsigned int)tsiz > 0xffffffff) &&
+            !v3)
                return (EFBIG);
        while (tsiz > 0) {
                nfsstats.rpccnt[NFSPROC_READ]++;
@@ -1355,9 +1497,9 @@ nfs_readrpc(vp, uiop, cred)
                        *tl++ = txdr_unsigned(len);
                        *tl = 0;
                }
-               nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred);
+               nfsm_request(vp, NFSPROC_READ, uiop->uio_procp, cred, &xid);
                if (v3) {
-                       nfsm_postop_attr(vp, attrflag);
+                       nfsm_postop_attr(vp, attrflag, &xid);
                        if (error) {
                                m_freem(mrep);
                                goto nfsmout;
@@ -1365,7 +1507,7 @@ nfs_readrpc(vp, uiop, cred)
                        nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
                        eof = fxdr_unsigned(int, *(tl + 1));
                } else
-                       nfsm_loadattr(vp, (struct vattr *)0);
+                       nfsm_loadattr(vp, (struct vattr *)0, &xid);
                nfsm_strsiz(retlen, nmp->nm_rsize);
                nfsm_mtouio(uiop, retlen);
                m_freem(mrep);
@@ -1398,6 +1540,7 @@ nfs_writerpc(vp, uiop, cred, iomode, must_commit)
        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
        int error = 0, len, tsiz, wccflag = NFSV3_WCCRATTR, rlen, commit;
        int v3 = NFS_ISV3(vp), committed = NFSV3WRITE_FILESYNC;
+       u_int64_t xid;
 
 #if DIAGNOSTIC
        if (uiop->uio_iovcnt != 1)
@@ -1426,10 +1569,10 @@ nfs_writerpc(vp, uiop, cred, iomode, must_commit)
                }
                *tl = txdr_unsigned(len);
                nfsm_uiotom(uiop, len);
-               nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred);
+               nfsm_request(vp, NFSPROC_WRITE, uiop->uio_procp, cred, &xid);
                if (v3) {
                        wccflag = NFSV3_WCCCHK;
-                       nfsm_wcc_data(vp, wccflag);
+                       nfsm_wcc_data(vp, wccflag, &xid);
                        if (!error) {
                                nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED +
                                        NFSX_V3WRITEVERF);
@@ -1468,23 +1611,29 @@ nfs_writerpc(vp, uiop, cred, iomode, must_commit)
                                }
                        }
                } else
-                   nfsm_loadattr(vp, (struct vattr *)0);
-               if ((wccflag) && (vp->v_type != VBAD))  /* EINVAL set on VBAD vnode */
+                   nfsm_loadattr(vp, (struct vattr *)0, &xid);
+
+               if (wccflag && vp->v_type != VBAD) /* EINVAL set on VBAD node */
                    VTONFS(vp)->n_mtime = VTONFS(vp)->n_vattr.va_mtime.tv_sec;
                m_freem(mrep);
-                /*
-                 * we seem to have a case where we end up looping on shutdown and taking down nfs servers.
-                 * For V3, error cases, there is no way to terminate loop, if the len was 0, meaning,
-                 * nmp->nm_wsize was trashed. FreeBSD has this fix in it. Let's try it.
-                 */
-                if (error)
-                    break;
-                tsiz -= len;
+               /*
+                * we seem to have a case where we end up looping on shutdown
+                * and taking down nfs servers.  For V3, error cases, there is
+                * no way to terminate loop, if the len was 0, meaning,
+                * nmp->nm_wsize was trashed. FreeBSD has this fix in it.
+                * Let's try it.
+                */
+               if (error)
+                       break;
+               tsiz -= len;
        }
 nfsmout:
-        /* does it make sense to even say it was committed if we had an error? EKN */
-        /* okay well just don't on bad vnodes then. EINVAL will be returned on bad vnodes */
-        if ((vp->v_type != VBAD) && (vp->v_mount->mnt_flag & MNT_ASYNC))
+        /* EKN
+         * does it make sense to even say it was committed if we had an error?
+         * okay well just don't on bad vnodes then.  EINVAL will be
+         * returned on bad vnodes
+         */
+        if (vp->v_type != VBAD && (vp->v_mount->mnt_flag & MNT_ASYNC))
                committed = NFSV3WRITE_FILESYNC;
         *iomode = committed;
        if (error)
@@ -1517,6 +1666,7 @@ nfs_mknodrpc(dvp, vpp, cnp, vap)
        int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        u_long rdev;
+       u_int64_t xid;
        int v3 = NFS_ISV3(dvp);
 
        if (vap->va_type == VCHR || vap->va_type == VBLK)
@@ -1557,9 +1707,9 @@ nfs_mknodrpc(dvp, vpp, cnp, vap)
                txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
                txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
        }
-       nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred);
+       nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_proc, cnp->cn_cred, &xid);
        if (!error) {
-               nfsm_mtofh(dvp, newvp, v3, gotvp);
+               nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
                if (!gotvp) {
                        if (newvp) {
                                vput(newvp);
@@ -1572,7 +1722,7 @@ nfs_mknodrpc(dvp, vpp, cnp, vap)
                }
        }
        if (v3)
-               nfsm_wcc_data(dvp, wccflag);
+               nfsm_wcc_data(dvp, wccflag, &xid);
        nfsm_reqdone;
        if (error) {
                if (newvp)
@@ -1583,11 +1733,11 @@ nfs_mknodrpc(dvp, vpp, cnp, vap)
                *vpp = newvp;
        }
        FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
-        if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
-            VTONFS(dvp)->n_flag |= NMODIFIED;
-            if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-            }
+       if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
+               VTONFS(dvp)->n_flag |= NMODIFIED;
+               if (!wccflag)
+                       VTONFS(dvp)->n_attrstamp = 0;
+       }
        vput(dvp);
        return (error);
 }
@@ -1610,8 +1760,9 @@ nfs_mknod(ap)
        int error;
 
        error = nfs_mknodrpc(ap->a_dvp, &newvp, ap->a_cnp, ap->a_vap);
-       if (!error)
+       if (!error && newvp)
                vput(newvp);
+       *ap->a_vpp = 0;
        return (error);
 }
 
@@ -1643,6 +1794,7 @@ nfs_create(ap)
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct vattr vattr;
        int v3 = NFS_ISV3(dvp);
+       u_int64_t xid;
 
        /*
         * Oops, not for me..
@@ -1688,9 +1840,9 @@ again:
                txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
                txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
        }
-       nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred);
+       nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_proc, cnp->cn_cred, &xid);
        if (!error) {
-               nfsm_mtofh(dvp, newvp, v3, gotvp);
+               nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
                if (!gotvp) {
                        if (newvp) {
                                vput(newvp);
@@ -1703,7 +1855,7 @@ again:
                }
        }
        if (v3)
-               nfsm_wcc_data(dvp, wccflag);
+               nfsm_wcc_data(dvp, wccflag, &xid);
        nfsm_reqdone;
        if (error) {
                if (v3 && (fmode & O_EXCL) && error == NFSERR_NOTSUPP) {
@@ -1753,9 +1905,8 @@ nfs_remove(ap)
        register struct vnode *dvp = ap->a_dvp;
        register struct componentname *cnp = ap->a_cnp;
        register struct nfsnode *np = VTONFS(vp);
-       int error = 0;
+       int error = 0, gofree = 0;
        struct vattr vattr;
-       int file_deleted = 0;
 
 #if DIAGNOSTIC
        if ((cnp->cn_flags & HASBUF) == 0)
@@ -1763,11 +1914,26 @@ nfs_remove(ap)
        if (vp->v_usecount < 1)
                panic("nfs_remove: bad v_usecount");
 #endif
-       if (vp->v_usecount == 1 || 
-               (UBCISVALID(vp)&&(vp->v_usecount==2)) || 
-               (np->n_sillyrename &&
-           VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
-           vattr.va_nlink > 1)) {
+
+       if (UBCISVALID(vp)) {
+               /* regular files */
+               if (UBCINFOEXISTS(vp))
+                       gofree = (ubc_isinuse(vp, 1)) ? 0 : 1;
+               else {
+                       /* dead or dying vnode.With vnode locking panic instead of error */
+                       FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
+                       vput(dvp);
+                       vput(vp);
+                       return (EIO);
+               }
+       } else {
+               /* UBC not in play */
+               if (vp->v_usecount == 1)
+                       gofree = 1;
+       }
+       if (gofree || (np->n_sillyrename &&
+               VOP_GETATTR(vp, &vattr, cnp->cn_cred, cnp->cn_proc) == 0 &&
+               vattr.va_nlink > 1)) {
                /*
                 * Purge the name cache so that the chance of a lookup for
                 * the name succeeding while the remove is in progress is
@@ -1781,7 +1947,8 @@ nfs_remove(ap)
                 * unnecessary delayed writes later.
                 */
                error = nfs_vinvalbuf(vp, 0, cnp->cn_cred, cnp->cn_proc, 1);
-               ubc_setsize(vp, (off_t)0);
+               np->n_size = 0;
+               ubc_setsize(vp, (off_t)0); /* XXX check error */
                /* Do the rpc */
                if (error != EINTR)
                        error = nfs_removerpc(dvp, cnp->cn_nameptr,
@@ -1794,7 +1961,6 @@ nfs_remove(ap)
                 */
                if (error == ENOENT)
                        error = 0;
-               file_deleted = 1;
        } else if (!np->n_sillyrename) {
                error = nfs_sillyrename(dvp, vp, cnp);
        }
@@ -1803,17 +1969,9 @@ nfs_remove(ap)
        np->n_attrstamp = 0;
        vput(dvp);
 
-
-       if (vp == dvp)
-               vrele(vp);
-       else
-               vput(vp);
-
-       if (file_deleted && UBCINFOEXISTS(vp)) {
-               (void) ubc_uncache(vp); 
-               ubc_release(vp);
-               /* WARNING vp may not be valid after this */
-       }
+       VOP_UNLOCK(vp, 0, cnp->cn_proc);
+       ubc_uncache(vp);
+       vrele(vp);
 
        return (error);
 }
@@ -1848,21 +2006,22 @@ nfs_removerpc(dvp, name, namelen, cred, proc)
        int error = 0, wccflag = NFSV3_WCCRATTR;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        int v3 = NFS_ISV3(dvp);
+       u_int64_t xid;
 
        nfsstats.rpccnt[NFSPROC_REMOVE]++;
        nfsm_reqhead(dvp, NFSPROC_REMOVE,
                NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
        nfsm_fhtom(dvp, v3);
        nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
-       nfsm_request(dvp, NFSPROC_REMOVE, proc, cred);
+       nfsm_request(dvp, NFSPROC_REMOVE, proc, cred, &xid);
        if (v3)
-               nfsm_wcc_data(dvp, wccflag);
+               nfsm_wcc_data(dvp, wccflag, &xid);
        nfsm_reqdone;
-        if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
-            VTONFS(dvp)->n_flag |= NMODIFIED;
-            if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-        }
+       if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
+               VTONFS(dvp)->n_flag |= NMODIFIED;
+               if (!wccflag)
+                       VTONFS(dvp)->n_attrstamp = 0;
+       }
        return (error);
 }
 
@@ -1886,7 +2045,7 @@ nfs_rename(ap)
        register struct vnode *tdvp = ap->a_tdvp;
        register struct componentname *tcnp = ap->a_tcnp;
        register struct componentname *fcnp = ap->a_fcnp;
-       int error;
+       int error, purged=0, inuse=0;
 
 #if DIAGNOSTIC
        if ((tcnp->cn_flags & HASBUF) == 0 ||
@@ -1897,6 +2056,8 @@ nfs_rename(ap)
        if ((fvp->v_mount != tdvp->v_mount) ||
            (tvp && (fvp->v_mount != tvp->v_mount))) {
                error = EXDEV;
+               if (tvp)
+                       VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
                goto out;
        }
 
@@ -1904,12 +2065,37 @@ nfs_rename(ap)
         * If the tvp exists and is in use, sillyrename it before doing the
         * rename of the new file over it.
         * XXX Can't sillyrename a directory.
+        * Don't sillyrename if source and target are same vnode (hard
+        * links or case-variants)
         */
-       if (tvp && (tvp->v_usecount>(UBCISVALID(tvp) ? 2 : 1)) &&
-                !VTONFS(tvp)->n_sillyrename &&
-               tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
-               vput(tvp);
-               tvp = NULL;
+       if (tvp && tvp != fvp) {
+               if (UBCISVALID(tvp)) {
+                       /* regular files */
+                       if (UBCINFOEXISTS(tvp))
+                               inuse = (ubc_isinuse(tvp, 1)) ? 1 : 0;
+                       else {
+                               /* dead or dying vnode.With vnode locking panic instead of error */
+                               error = EIO;
+                               VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
+                               goto out;  
+                       }
+               } else {
+                       /* UBC not in play */
+                       if (tvp->v_usecount > 1)
+                               inuse = 1;
+               }
+       }
+       if (inuse && !VTONFS(tvp)->n_sillyrename && tvp->v_type != VDIR) {
+               if  (error = nfs_sillyrename(tdvp, tvp, tcnp)) {
+                       /* sillyrename failed. Instead of pressing on, return error */
+                       goto out; /* should not be ENOENT. */
+               } else {
+                       /* sillyrename succeeded.*/
+                       VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
+                       ubc_uncache(tvp); /* get the nfs turd file to disappear */
+                       vrele(tvp);
+                       tvp = NULL;
+               }
        }
 
        error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
@@ -1917,17 +2103,29 @@ nfs_rename(ap)
                tcnp->cn_proc);
 
        if (fvp->v_type == VDIR) {
-               if (tvp != NULL && tvp->v_type == VDIR)
+               if (tvp != NULL && tvp->v_type == VDIR) {
                        cache_purge(tdvp);
+                       if (tvp == tdvp) 
+                               purged = 1;
+               }
                cache_purge(fdvp);
        }
+       
+       cache_purge(fvp);
+       if (tvp) {
+               if (!purged)
+                       cache_purge(tvp);
+               VOP_UNLOCK(tvp, 0, tcnp->cn_proc);
+               ubc_uncache(tvp); /* get the nfs turd file to disappear */
+       }
+       
 out:
        if (tdvp == tvp)
                vrele(tdvp);
        else
                vput(tdvp);
        if (tvp)
-               vput(tvp);
+               vrele(tvp); /* already unlocked */
        vrele(fdvp);
        vrele(fvp);
        /*
@@ -1972,30 +2170,33 @@ nfs_renamerpc(fdvp, fnameptr, fnamelen, tdvp, tnameptr, tnamelen, cred, proc)
        int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        int v3 = NFS_ISV3(fdvp);
+       u_int64_t xid;
 
        nfsstats.rpccnt[NFSPROC_RENAME]++;
        nfsm_reqhead(fdvp, NFSPROC_RENAME,
-               (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
-               nfsm_rndup(tnamelen));
+                    (NFSX_FH(v3) + NFSX_UNSIGNED)*2 + nfsm_rndup(fnamelen) +
+                     nfsm_rndup(tnamelen));
        nfsm_fhtom(fdvp, v3);
        nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
        nfsm_fhtom(tdvp, v3);
        nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
-       nfsm_request(fdvp, NFSPROC_RENAME, proc, cred);
+       nfsm_request(fdvp, NFSPROC_RENAME, proc, cred, &xid);
        if (v3) {
-               nfsm_wcc_data(fdvp, fwccflag);
-               nfsm_wcc_data(tdvp, twccflag);
+               u_int64_t txid = xid;
+
+               nfsm_wcc_data(fdvp, fwccflag, &xid);
+               nfsm_wcc_data(tdvp, twccflag, &txid);
        }
        nfsm_reqdone;
-        if (fdvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
-            VTONFS(fdvp)->n_flag |= NMODIFIED;
-            if (!fwccflag)
-               VTONFS(fdvp)->n_attrstamp = 0;
-        }
-        if (tdvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
-            VTONFS(tdvp)->n_flag |= NMODIFIED;
-            if (!twccflag)
-                    VTONFS(tdvp)->n_attrstamp = 0;
+       if (fdvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
+               VTONFS(fdvp)->n_flag |= NMODIFIED;
+               if (!fwccflag)
+                       VTONFS(fdvp)->n_attrstamp = 0;
+       }
+       if (tdvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
+               VTONFS(tdvp)->n_flag |= NMODIFIED;
+               if (!twccflag)
+                       VTONFS(tdvp)->n_attrstamp = 0;
         }
        return (error);
 }
@@ -2021,6 +2222,7 @@ nfs_link(ap)
        int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        int v3 = NFS_ISV3(vp);
+       u_int64_t xid;
 
        if (vp->v_mount != tdvp->v_mount) {
                VOP_ABORTOP(vp, cnp);
@@ -2044,18 +2246,20 @@ nfs_link(ap)
        nfsm_fhtom(vp, v3);
        nfsm_fhtom(tdvp, v3);
        nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
-       nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred);
+       nfsm_request(vp, NFSPROC_LINK, cnp->cn_proc, cnp->cn_cred, &xid);
        if (v3) {
-               nfsm_postop_attr(vp, attrflag);
-               nfsm_wcc_data(tdvp, wccflag);
+               u_int64_t txid = xid;
+
+               nfsm_postop_attr(vp, attrflag, &xid);
+               nfsm_wcc_data(tdvp, wccflag, &txid);
        }
        nfsm_reqdone;
        FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
 
        VTONFS(tdvp)->n_flag |= NMODIFIED;
-       if ((!attrflag) && (vp->v_type != VBAD))  /* EINVAL set on VBAD vnode */
+       if (!attrflag && vp->v_type != VBAD)  /* EINVAL set on VBAD vnode */
                VTONFS(vp)->n_attrstamp = 0;
-       if ((!wccflag) && (tdvp->v_type != VBAD))  /* EINVAL set on VBAD vnode */
+       if (!wccflag && tdvp->v_type != VBAD)  /* EINVAL set on VBAD vnode */
                VTONFS(tdvp)->n_attrstamp = 0;
        vput(tdvp);
        /*
@@ -2092,6 +2296,7 @@ nfs_symlink(ap)
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct vnode *newvp = (struct vnode *)0;
        int v3 = NFS_ISV3(dvp);
+       u_int64_t xid;
 
        nfsstats.rpccnt[NFSPROC_SYMLINK]++;
        slen = strlen(ap->a_target);
@@ -2114,21 +2319,23 @@ nfs_symlink(ap)
                txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
                txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
        }
-       nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred);
+       nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_proc, cnp->cn_cred, &xid);
        if (v3) {
+               u_int64_t dxid = xid;
+
                if (!error)
-                       nfsm_mtofh(dvp, newvp, v3, gotvp);
-               nfsm_wcc_data(dvp, wccflag);
+                       nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
+               nfsm_wcc_data(dvp, wccflag, &dxid);
        }
        nfsm_reqdone;
        if (newvp)
                vput(newvp);
        FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
-        if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
-            VTONFS(dvp)->n_flag |= NMODIFIED;
-            if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-        }
+       if (dvp->v_type != VBAD) { /* EINVAL set on VBAD vnode */
+               VTONFS(dvp)->n_flag |= NMODIFIED;
+               if (!wccflag)
+                       VTONFS(dvp)->n_attrstamp = 0;
+       }
        vput(dvp);
        /*
         * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
@@ -2167,6 +2374,7 @@ nfs_mkdir(ap)
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        struct vattr vattr;
        int v3 = NFS_ISV3(dvp);
+       u_int64_t xid, dxid;
 
        if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_cred, cnp->cn_proc))) {
                VOP_ABORTOP(dvp, cnp);
@@ -2191,17 +2399,18 @@ nfs_mkdir(ap)
                txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
                txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
        }
-       nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred);
+       nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_proc, cnp->cn_cred, &xid);
+       dxid = xid;
        if (!error)
-               nfsm_mtofh(dvp, newvp, v3, gotvp);
+               nfsm_mtofh(dvp, newvp, v3, gotvp, &xid);
        if (v3)
-               nfsm_wcc_data(dvp, wccflag);
+               nfsm_wcc_data(dvp, wccflag, &dxid);
        nfsm_reqdone;
-        if (dvp->v_type != VBAD) { /* EINVAL set on this case */
-            VTONFS(dvp)->n_flag |= NMODIFIED;
-            if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-        }
+       if (dvp->v_type != VBAD) { /* EINVAL set on this case */
+               VTONFS(dvp)->n_flag |= NMODIFIED;
+               if (!wccflag)
+                       VTONFS(dvp)->n_attrstamp = 0;
+       }
        /*
         * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
         * if we can succeed in looking up the directory.
@@ -2212,7 +2421,7 @@ nfs_mkdir(ap)
                        newvp = (struct vnode *)0;
                }
                error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
-                       cnp->cn_proc, &np);
+                                    cnp->cn_proc, &np);
                if (!error) {
                        newvp = NFSTOV(np);
                        if (newvp->v_type != VDIR)
@@ -2250,22 +2459,23 @@ nfs_rmdir(ap)
        int error = 0, wccflag = NFSV3_WCCRATTR;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        int v3 = NFS_ISV3(dvp);
+       u_int64_t xid;
 
        nfsstats.rpccnt[NFSPROC_RMDIR]++;
        nfsm_reqhead(dvp, NFSPROC_RMDIR,
                NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
        nfsm_fhtom(dvp, v3);
        nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
-       nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred);
+       nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_proc, cnp->cn_cred, &xid);
        if (v3)
-               nfsm_wcc_data(dvp, wccflag);
+               nfsm_wcc_data(dvp, wccflag, &xid);
        nfsm_reqdone;
        FREE_ZONE(cnp->cn_pnbuf, cnp->cn_pnlen, M_NAMEI);
-        if (dvp->v_type != VBAD) { /* EINVAL set on this case */
-            VTONFS(dvp)->n_flag |= NMODIFIED;
-            if (!wccflag)
-               VTONFS(dvp)->n_attrstamp = 0;
-        }
+       if (dvp->v_type != VBAD) { /* EINVAL set on this case */
+               VTONFS(dvp)->n_flag |= NMODIFIED;
+               if (!wccflag)
+                       VTONFS(dvp)->n_attrstamp = 0;
+       }
        cache_purge(dvp);
        cache_purge(vp);
        vput(vp);
@@ -2351,6 +2561,7 @@ nfs_readdirrpc(vp, uiop, cred)
        int error = 0, tlen, more_dirs = 1, blksiz = 0, bigenough = 1;
        int attrflag;
        int v3 = NFS_ISV3(vp);
+       u_int64_t xid;
 
 #ifndef nolint
        dp = (struct dirent *)0;
@@ -2390,9 +2601,9 @@ nfs_readdirrpc(vp, uiop, cred)
                        *tl++ = cookie.nfsuquad[0];
                }
                *tl = txdr_unsigned(nmp->nm_readdirsize);
-               nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred);
+               nfsm_request(vp, NFSPROC_READDIR, uiop->uio_procp, cred, &xid);
                if (v3) {
-                       nfsm_postop_attr(vp, attrflag);
+                       nfsm_postop_attr(vp, attrflag, &xid);
                        if (!error) {
                                nfsm_dissect(tl, u_long *, 2 * NFSX_UNSIGNED);
                                dnp->n_cookieverf.nfsuquad[0] = *tl++;
@@ -2538,6 +2749,7 @@ nfs_readdirplusrpc(vp, uiop, cred)
        u_quad_t fileno;
        int error = 0, tlen, more_dirs = 1, blksiz = 0, doit, bigenough = 1, i;
        int attrflag, fhsize;
+       u_int64_t xid, savexid;
 
 #ifndef nolint
        dp = (struct dirent *)0;
@@ -2575,8 +2787,10 @@ nfs_readdirplusrpc(vp, uiop, cred)
                *tl++ = dnp->n_cookieverf.nfsuquad[1];
                *tl++ = txdr_unsigned(nmp->nm_readdirsize);
                *tl = txdr_unsigned(nmp->nm_rsize);
-               nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred);
-               nfsm_postop_attr(vp, attrflag);
+               nfsm_request(vp, NFSPROC_READDIRPLUS, uiop->uio_procp, cred,
+                            &xid);
+               savexid = xid;
+               nfsm_postop_attr(vp, attrflag, &xid);
                if (error) {
                        m_freem(mrep);
                        goto nfsmout;
@@ -2673,7 +2887,8 @@ nfs_readdirplusrpc(vp, uiop, cred)
                                dpos = dpossav1;
                                mdsav2 = md;
                                md = mdsav1;
-                               nfsm_loadattr(newvp, (struct vattr *)0);
+                               xid = savexid;
+                               nfsm_loadattr(newvp, (struct vattr *)0, &xid);
                                dpos = dpossav2;
                                md = mdsav2;
                                dp->d_type =
@@ -2834,13 +3049,14 @@ nfs_lookitup(dvp, name, len, cred, procp, npp)
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
        nfsfh_t *nfhp;
        int v3 = NFS_ISV3(dvp);
+       u_int64_t xid;
 
        nfsstats.rpccnt[NFSPROC_LOOKUP]++;
        nfsm_reqhead(dvp, NFSPROC_LOOKUP,
                NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
        nfsm_fhtom(dvp, v3);
        nfsm_strtom(name, len, NFS_MAXNAMLEN);
-       nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred);
+       nfsm_request(dvp, NFSPROC_LOOKUP, procp, cred, &xid);
        if (npp && !error) {
                nfsm_getfh(nfhp, fhlen, v3);
                if (*npp) {
@@ -2867,7 +3083,7 @@ nfs_lookitup(dvp, name, len, cred, procp, npp)
                    newvp = NFSTOV(np);
                }
                if (v3) {
-                       nfsm_postop_attr(newvp, attrflag);
+                       nfsm_postop_attr(newvp, attrflag, &xid);
                        if (!attrflag && *npp == NULL) {
                                m_freem(mrep);
                                if (newvp == dvp)
@@ -2877,7 +3093,7 @@ nfs_lookitup(dvp, name, len, cred, procp, npp)
                                return (ENOENT);
                        }
                } else
-                       nfsm_loadattr(newvp, (struct vattr *)0);
+                       nfsm_loadattr(newvp, (struct vattr *)0, &xid);
        }
        nfsm_reqdone;
        if (npp && *npp == NULL) {
@@ -2911,7 +3127,9 @@ nfs_commit(vp, offset, cnt, cred, procp)
        caddr_t bpos, dpos, cp2;
        int error = 0, wccflag = NFSV3_WCCRATTR;
        struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+       u_int64_t xid;
        
+       FSDBG(521, vp, offset, cnt, nmp->nm_flag);
        if ((nmp->nm_flag & NFSMNT_HASWRITEVERF) == 0)
                return (0);
        nfsstats.rpccnt[NFSPROC_COMMIT]++;
@@ -2921,12 +3139,12 @@ nfs_commit(vp, offset, cnt, cred, procp)
        txdr_hyper(&offset, tl);
        tl += 2;
        *tl = txdr_unsigned(cnt);
-       nfsm_request(vp, NFSPROC_COMMIT, procp, cred);
-       nfsm_wcc_data(vp, wccflag);
+       nfsm_request(vp, NFSPROC_COMMIT, procp, cred, &xid);
+       nfsm_wcc_data(vp, wccflag, &xid);
        if (!error) {
                nfsm_dissect(tl, u_long *, NFSX_V3WRITEVERF);
                if (bcmp((caddr_t)nmp->nm_verf, (caddr_t)tl,
-                       NFSX_V3WRITEVERF)) {
+                        NFSX_V3WRITEVERF)) {
                        bcopy((caddr_t)tl, (caddr_t)nmp->nm_verf,
                                NFSX_V3WRITEVERF);
                        error = NFSERR_STALEWRITEVERF;
@@ -3041,7 +3259,6 @@ nfs_fsync(ap)
                struct proc * a_p;
        } */ *ap;
 {
-
        return (nfs_flush(ap->a_vp, ap->a_cred, ap->a_waitfor, ap->a_p, 1));
 }
 
@@ -3068,17 +3285,15 @@ nfs_flush(vp, cred, waitfor, p, commit)
        u_quad_t off, endoff, toff;
        struct ucred* wcred = NULL;
        struct buf **bvec = NULL;
-        void * object;
-        kern_return_t kret;
-        upl_t *upls = NULL;
-
-
 #ifndef NFS_COMMITBVECSIZ
 #define NFS_COMMITBVECSIZ      20
 #endif
        struct buf *bvec_on_stack[NFS_COMMITBVECSIZ];
-        struct upl_t *upls_on_stack[NFS_COMMITBVECSIZ]; 
-        int bvecsize = 0, bveccount, buplpos;
+       int bvecsize = 0, bveccount;
+       kern_return_t kret;
+       upl_t         upl;
+
+       FSDBG_TOP(517, vp, np, waitfor, commit);
 
        if (nmp->nm_flag & NFSMNT_INT)
                slpflag = PCATCH;
@@ -3093,16 +3308,18 @@ nfs_flush(vp, cred, waitfor, p, commit)
         * job.
         */
 again:
+       FSDBG(518, vp->v_dirtyblkhd.lh_first, np->n_flag, 0, 0);
        if (vp->v_dirtyblkhd.lh_first)
                np->n_flag |= NMODIFIED;
        off = (u_quad_t)-1;
        endoff = 0;
        bvecpos = 0;
-        buplpos = 0;
        if (NFS_ISV3(vp) && commit) {
                s = splbio();
                /*
                 * Count up how many buffers waiting for a commit.
+                * This is an upper bound - any with dirty pages must be
+                * written not commited.
                 */
                bveccount = 0;
                for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
@@ -3110,48 +3327,88 @@ again:
                        if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
                            == (B_DELWRI | B_NEEDCOMMIT))
                                bveccount++;
+                       FSDBG(519, bp, bp->b_flags, bveccount, 0);
                }
                /*
                 * Allocate space to remember the list of bufs to commit.  It is
-                * important to use M_NOWAIT here to avoid a race with nfs_write.
+                * important to use M_NOWAIT here to avoid a race with nfs_write
                 * If we can't get memory (for whatever reason), we will end up
                 * committing the buffers one-by-one in the loop below.
                 */
+               if (bvec != NULL && bvec != bvec_on_stack)
+                       _FREE(bvec, M_TEMP);
                if (bveccount > NFS_COMMITBVECSIZ) {
-                       if (bvec != NULL && bvec != bvec_on_stack)
-                               _FREE(bvec, M_TEMP);
                        MALLOC(bvec, struct buf **,
-                              bveccount * sizeof(struct buf *), M_TEMP, M_NOWAIT);
+                              bveccount * sizeof(struct buf *), M_TEMP,
+                              M_NOWAIT);
                        if (bvec == NULL) {
                                bvec = bvec_on_stack;
                                bvecsize = NFS_COMMITBVECSIZ;
                        } else
                                bvecsize = bveccount;
-                        /* allocate the upl structure before the loop based on buffers to commit */
-                       if (upls != NULL && upls != upls_on_stack)
-                                       _FREE(upls, M_TEMP);
-                       MALLOC(upls, struct upl_t *,
-                            bveccount * sizeof(upl_t), M_TEMP, M_NOWAIT);
-                        if (upls == NULL)
-                            upls = upls_on_stack;
                } else {
-                       if (bvec && bvec != bvec_on_stack)
-                               _FREE(bvec, M_TEMP);
                        bvec = bvec_on_stack;
                        bvecsize = NFS_COMMITBVECSIZ;
-                       if (upls && upls != upls_on_stack)
-                                       _FREE(upls, M_TEMP);
-                        upls = upls_on_stack;
                }
+               FSDBG(519, 0, bvecsize, bveccount, 0);
 
                for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
                        nbp = bp->b_vnbufs.le_next;
+
+                       FSDBG(520, bp, bp->b_flags, bvecpos, bp->b_bufsize);
+                       FSDBG(520, bp->b_validoff, bp->b_validend,
+                             bp->b_dirtyoff, bp->b_dirtyend);
                        if (bvecpos >= bvecsize)
                                break;
                        if ((bp->b_flags & (B_BUSY | B_DELWRI | B_NEEDCOMMIT))
                                != (B_DELWRI | B_NEEDCOMMIT))
                                continue;
+
                        bremfree(bp);
+                       SET(bp->b_flags, B_BUSY);
+                       /*
+                        * we need a upl to see if the page has been
+                        * dirtied (think mmap) since the unstable write, and
+                        * so to prevent vm from paging during our commit rpc
+                        */
+                       if (ISSET(bp->b_flags, B_PAGELIST)) {
+                               upl = bp->b_pagelist;
+                       } else {
+                               kret = ubc_create_upl(vp, ubc_blktooff(vp, bp->b_lblkno),
+                                                     bp->b_bufsize, &upl,
+                                                     NULL, UPL_PRECIOUS);
+                               if (kret != KERN_SUCCESS) 
+                                       panic("nfs_flush: create upl %d", kret);
+#ifdef UBC_DEBUG
+                               upl_ubc_alias_set(upl, current_act(), 1);
+#endif /* UBC_DEBUG */
+                       }
+                       if (upl_dirty_page(ubc_upl_pageinfo(upl), 0)) {
+                               if (!ISSET(bp->b_flags, B_PAGELIST)) {
+                                       err = ubc_upl_abort(upl, NULL); 
+                                       if (err)
+                                               printf("nfs_flush: upl abort %d\n", err);
+                               }
+                               /*
+                                * Any/all of it may be modified...
+                                */
+                               bp->b_dirtyoff = bp->b_validoff;
+                               bp->b_dirtyend = bp->b_validend;
+                               CLR(bp->b_flags, B_NEEDCOMMIT);
+                               /* blocking calls were made, re-evaluate nbp */
+                               nbp = bp->b_vnbufs.le_next;
+                               brelse(bp);     /* XXX may block. Is using nbp ok??? */
+                               continue;
+                       }
+                       if (!ISSET(bp->b_flags, B_PAGELIST)) {
+                               bp->b_pagelist = upl;
+                               SET(bp->b_flags, B_PAGELIST);
+                               ubc_upl_map(upl, (vm_address_t *)&bp->b_data);
+                       }
+
+                       /* blocking calls were made, re-evaluate nbp */
+                       nbp = bp->b_vnbufs.le_next;
+
                        /*
                         * Work out if all buffers are using the same cred
                         * so we can deal with them all with one commit.
@@ -3160,33 +3417,7 @@ again:
                                wcred = bp->b_wcred;
                        else if (wcred != bp->b_wcred)
                                wcred = NOCRED;
-                       SET(bp->b_flags, (B_BUSY | B_WRITEINPROG));
-
-                       /*
-                        * we need vm_fault_list_request so if vm decides to
-                        * do paging while we are waiting on commit rpc,
-                        * that it doesn't pick these pages.
-                        */
-                       if (!ISSET(bp->b_flags, B_PAGELIST)) {
-                               /* if pagelist exists, assume vm pages are locked/busy already */                               off_t file_offset = ubc_blktooff(vp, bp->b_lblkno);
-                               object = ubc_getobject(vp, (UBC_NOREACTIVATE|UBC_HOLDOBJECT));
-                               if (object == (void*)NULL)
-                                       panic("nfs_getcacheblk: NULL vmobject");
-                               if(bp->b_bufsize & 0xfff)
-                                       panic("nfs_getcacheblk: list request is less than 4k");
-                               kret = vm_fault_list_request(
-                                               object, (vm_object_offset_t)file_offset,
-                                               bp->b_bufsize, &(upls[buplpos]), NULL, 0,
-                                               (int)(UPL_NO_SYNC | UPL_CLEAN_IN_PLACE |UPL_PRECIOUS |
-                                               UPL_SET_INTERNAL));
-                               if (kret != KERN_SUCCESS) 
-                                       panic("nfs_getcacheblk: get pagelists failed with (%d)", kret);
-                                    
-#ifdef UBC_DEBUG
-                               upl_ubc_alias_set(pl, ioaddr, 1);
-#endif /* UBC_DEBUG */
-                               buplpos++; /* not same as bvecpos if upl existed already */
-                       }
+                       SET(bp->b_flags, B_WRITEINPROG);
 
                        /*
                         * A list of these buffers is kept so that the
@@ -3221,6 +3452,8 @@ again:
                        for (i = 0; i < bvecpos; i++) {
                                off_t off, size;
                                bp = bvec[i];
+                               FSDBG(522, bp, bp->b_blkno * DEV_BSIZE,
+                                     bp->b_dirtyoff, bp->b_dirtyend);
                                off = ((u_quad_t)bp->b_blkno) * DEV_BSIZE +
                                        bp->b_dirtyoff;
                                size = (u_quad_t)(bp->b_dirtyend
@@ -3233,20 +3466,6 @@ again:
 
                if (retv == NFSERR_STALEWRITEVERF)
                        nfs_clearcommit(vp->v_mount);
-                        
-                for (i = 0; i < buplpos; i++) {
-                    /*
-                    * before the VOP_BWRITE and biodone(ASYNC)/brelse, we have to undo
-                    * holding the vm page or we we will deadlock on another vm_fault_list_request.
-                    * Here's a convenient place to put it. 
-                    * Better if we could hold it by setting the PAGELIST flag and kernel_upl_map
-                    * as does nfs_writebp. Then normal biodones and brelse will clean it up and 
-                    * we can avoid this abort. For now make minimal changse and test this out.
-                    */
-                    err = kernel_upl_abort(upls[i], NULL); 
-                    if (err)
-                        printf("nfs_flush: kernel_upl_abort %d\n", err);
-                    }
 
                /*
                 * Now, either mark the blocks I/O done or mark the
@@ -3254,31 +3473,38 @@ again:
                 * succeeded.
                 */
                for (i = 0; i < bvecpos; i++) {
-                        
                        bp = bvec[i];
+                       FSDBG(523, bp, retv, bp->b_flags, 0);
                        CLR(bp->b_flags, (B_NEEDCOMMIT | B_WRITEINPROG));
                        if (retv) {
-                           brelse(bp);
+                               brelse(bp);
                        } else {
-                           vp->v_numoutput++;
-                           SET(bp->b_flags, B_ASYNC);
-                           s = splbio();
-                           CLR(bp->b_flags, (B_READ|B_DONE|B_ERROR|B_DELWRI));
-                           bp->b_dirtyoff = bp->b_dirtyend = 0;
-                           reassignbuf(bp, vp);
-                           splx(s);
-                           biodone(bp);
+                               int oldflags = bp->b_flags;
+
+                               s = splbio();
+                               vp->v_numoutput++;
+                               SET(bp->b_flags, B_ASYNC);
+                               CLR(bp->b_flags,
+                                   (B_READ|B_DONE|B_ERROR|B_DELWRI));
+                               if (ISSET(oldflags, B_DELWRI)) {
+                                       extern int nbdwrite;
+                                       nbdwrite--;
+                                       wakeup((caddr_t)&nbdwrite);
+                               }
+                               bp->b_dirtyoff = bp->b_dirtyend = 0;
+                               reassignbuf(bp, vp);
+                               splx(s);
+                               biodone(bp);
                        }
                }
 
        }
-
        /*
-        * Start/do any write(s) that are required.
-         * There is a window here where B_BUSY protects the buffer. The vm pages have been
-         * freed up, yet B_BUSY is set. Don't think you will hit any busy/incore problems while
-         * we sleep, but not absolutely sure. Keep an eye on it. Otherwise we will have to hold
-         * vm page across this locked. - EKN
+        * Start/do any write(s) that are required.  There is a window here
+        * where B_BUSY protects the buffer. The vm pages have been freed up,
+        * yet B_BUSY is set. Don't think you will hit any busy/incore problems
+        * while we sleep, but not absolutely sure. Keep an eye on it. Otherwise
+        * we will have to hold vm page across this locked. - EKN
         */
 loop:
        if (current_thread_aborted()) {
@@ -3289,34 +3515,36 @@ loop:
        for (bp = vp->v_dirtyblkhd.lh_first; bp; bp = nbp) {
                nbp = bp->b_vnbufs.le_next;
                if (ISSET(bp->b_flags, B_BUSY)) {
+                       FSDBG(524, bp, waitfor, passone, bp->b_flags);
                        if (waitfor != MNT_WAIT || passone)
                                continue;
                        SET(bp->b_flags, B_WANTED);
                        error = tsleep((caddr_t)bp, slpflag | (PRIBIO + 1),
-                               "nfsfsync", slptimeo);
+                                      "nfsfsync", slptimeo);
                        splx(s);
                        if (error) {
-                           if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
-                               error = EINTR;
-                               goto done;
-                           }
-                           if (slpflag == PCATCH) {
-                               slpflag = 0;
-                               slptimeo = 2 * hz;
-                           }
+                               if (nfs_sigintr(nmp, (struct nfsreq *)0, p)) {
+                                       error = EINTR;
+                                       goto done;
+                               }
+                               if (slpflag == PCATCH) {
+                                       slpflag = 0;
+                                       slptimeo = 2 * hz;
+                               }
                        }
                        goto loop;
                }
                if (!ISSET(bp->b_flags, B_DELWRI))
                        panic("nfs_fsync: not dirty");
+               FSDBG(525, bp, passone, commit, bp->b_flags);
                if ((passone || !commit) && ISSET(bp->b_flags, B_NEEDCOMMIT))
                        continue;
                bremfree(bp);
                if (passone || !commit)
-                   SET(bp->b_flags, (B_BUSY|B_ASYNC));
+                       SET(bp->b_flags, B_BUSY|B_ASYNC);
                else
-                   SET(bp->b_flags, (B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT));
-
+                       SET(bp->b_flags,
+                           B_BUSY|B_ASYNC|B_WRITEINPROG|B_NEEDCOMMIT);
                splx(s);
                VOP_BWRITE(bp);
                goto loop;
@@ -3346,15 +3574,15 @@ loop:
                        goto loop;
                }
        }
+       FSDBG(526, np->n_flag, np->n_error, 0, 0);
        if (np->n_flag & NWRITEERR) {
                error = np->n_error;
                np->n_flag &= ~NWRITEERR;
        }
 done:
+       FSDBG_BOT(517, vp, np, error, 0);
        if (bvec != NULL && bvec != bvec_on_stack)
                _FREE(bvec, M_TEMP);
-        if (upls != NULL && upls != upls_on_stack)
-                _FREE(upls, M_TEMP);
        return (error);
 }
 
@@ -3617,7 +3845,6 @@ nfs_writebp(bp, force)
        register int oldflags = bp->b_flags, retv = 1;
        off_t off;
        upl_t upl;
-       void * object;
        kern_return_t kret;
        struct vnode *vp = bp->b_vp;
        upl_page_info_t *pl;
@@ -3627,6 +3854,11 @@ nfs_writebp(bp, force)
 
        s = splbio();
        CLR(bp->b_flags, (B_READ|B_DONE|B_ERROR|B_DELWRI));
+       if (ISSET(oldflags, B_DELWRI)) {
+               extern int nbdwrite;
+               nbdwrite--;
+               wakeup((caddr_t)&nbdwrite);
+       }
 
        if (ISSET(oldflags, (B_ASYNC|B_DELWRI))) {
                reassignbuf(bp, vp);
@@ -3637,60 +3869,32 @@ nfs_writebp(bp, force)
        splx(s);
         
         /* 
-         * Since the B_BUSY flag is set, we need to lock the page before doing nfs_commit.
-         * Otherwise we may block and get a busy incore pages during a vm pageout.
-         * Move the existing code up before the commit.
+         * Since the B_BUSY flag is set, we need to lock the page before doing
+         * nfs_commit.  Otherwise we may block and get a busy incore pages
+         * during a vm pageout.  Move the existing code up before the commit.
          */
-
-        if (!ISSET(bp->b_flags, B_META) && UBCISVALID(vp)) {
-    
-            if (!ISSET(bp->b_flags, B_PAGELIST)) {
-
-                               off_t file_offset = ubc_blktooff(vp, bp->b_lblkno);
-
-                               object = ubc_getobject(vp, (UBC_NOREACTIVATE|UBC_HOLDOBJECT));
-                               if (object == (void*)NULL)
-                                       panic("nfs_writebp: NULL vmobject");
-
-                               if(bp->b_bufsize & 0xfff)
-                                       panic("nfs_writebp: list request is with less than 4k");
-       
-                               kret = vm_fault_list_request(object, (vm_object_offset_t)file_offset, 
-                                                       bp->b_bufsize, &upl, NULL, 0, 
-                                                       (int)(UPL_NO_SYNC | UPL_CLEAN_IN_PLACE | UPL_PRECIOUS | UPL_SET_INTERNAL));
-                               if (kret != KERN_SUCCESS) {
-                                       panic("nfs_writebp: get pagelists failed with (%d)", kret);
-                               }
-                    
+        if (!ISSET(bp->b_flags, B_META) && UBCISVALID(vp) &&
+            !ISSET(bp->b_flags, B_PAGELIST)) {
+               kret = ubc_create_upl(vp, ubc_blktooff(vp, bp->b_lblkno),
+                                     bp->b_bufsize, &upl, &pl, UPL_PRECIOUS);
+               if (kret != KERN_SUCCESS)
+                       panic("nfs_writebp: ubc_create_upl %d", kret);
 #ifdef UBC_DEBUG
-                    upl_ubc_alias_set(pl, ioaddr, 2);
+               upl_ubc_alias_set(upl, current_act(), 2);
 #endif /* UBC_DEBUG */
+               s = splbio();
+               bp->b_pagelist = upl;
+               SET(bp->b_flags, B_PAGELIST);
+               splx(s);
 
-                    s = splbio();
-
-                    pl = UPL_GET_INTERNAL_PAGE_LIST(upl);
-                    bp->b_pagelist = upl;
-                    SET(bp->b_flags, B_PAGELIST);
-                    splx(s);
-                    
-                    kret = kernel_upl_map(kernel_map, upl, 
-                            (vm_address_t *)&(bp->b_data));
-                    if (kret != KERN_SUCCESS) {
-                            panic("nfs_writebp: kernel_upl_map() failed with (%d)", kret);
-                    }
-                    if(bp->b_data == 0) 
-                            panic("nfs_writebp: upl_map mapped 0");
-                    if (!upl_page_present(pl, 0)) {
-                            /* 
-                                * may be the page got paged out.
-                                * let's just read it in. It is marked
-                                * busy so we should not have any one
-                                * yanking this page underneath the fileIO
-                                */
-                            panic("nfs_writebp: nopage");
-                    }
-            }
-        }
+               kret = ubc_upl_map(upl, (vm_address_t *)&(bp->b_data));
+               if (kret != KERN_SUCCESS)
+                       panic("nfs_writebp: ubc_upl_map %d", kret);
+               if(bp->b_data == 0) 
+                       panic("nfs_writebp: ubc_upl_map mapped 0");
+               if (!upl_page_present(pl, 0)) /* even more paranoia */
+                       panic("nfs_writebp: nopage");
+       }
 
        /*
         * If B_NEEDCOMMIT is set, a commit rpc may do the trick. If not
@@ -3714,9 +3918,7 @@ nfs_writebp(bp, force)
        if (retv) {
                if (force)
                        SET(bp->b_flags, B_WRITEINPROG);
-                
-                VOP_STRATEGY(bp);
-                
+               VOP_STRATEGY(bp);
        } 
         
        if( (oldflags & B_ASYNC) == 0) {
@@ -4016,6 +4218,7 @@ nfs_pagein(ap)
        struct ucred *cred;
        register struct nfsnode *np = VTONFS(vp);
        register int biosize;
+       register int iosize;
        register int xsize;
        struct vattr vattr;
        struct proc *p = current_proc();
@@ -4025,46 +4228,42 @@ nfs_pagein(ap)
        struct uio      auio;
        struct iovec    aiov;
        struct uio * uio = &auio;
-       int nocommit = flags & UPL_NOCOMMIT;
+       int nofreeupl = flags & UPL_NOCOMMIT;
 
-       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 322)) | DBG_FUNC_NONE,
-                    (int)f_offset, size, pl, pl_offset, 0);
+       FSDBG(322, f_offset, size, pl, pl_offset);
+       if (pl == (upl_t)NULL)
+               panic("nfs_pagein: no upl");
 
        if (UBCINVALID(vp)) {
-#if DIAGNOSTIC
-               panic("nfs_pagein: invalid vp");
-#endif /* DIAGNOSTIC */
+               printf("nfs_pagein: invalid vnode 0x%x", (int)vp);
+               if (!nofreeupl)
+                       (void) ubc_upl_abort(pl, NULL); 
                return (EPERM);
        }
-
        UBCINFOCHECK("nfs_pagein", vp);
-       if(pl == (upl_t)NULL) {
-               panic("nfs_pagein: no upl");
-       }
 
-       cred = ubc_getcred(vp);
-       if (cred == NOCRED)
-               cred = ap->a_cred;
-
-       if (size <= 0)
+       if (size <= 0) {
+               printf("nfs_pagein: invalid size %d", size);
+               if (!nofreeupl)
+                       (void) ubc_upl_abort(pl, NULL); 
                return (EINVAL);
-
-       if (f_offset < 0 || f_offset >= np->n_size 
-                                       || (f_offset & PAGE_MASK_64)) {
-               if (!nocommit)
-                       kernel_upl_abort_range(pl, pl_offset, size, 
+       }
+       if (f_offset < 0 || f_offset >= np->n_size ||
+           (f_offset & PAGE_MASK_64)) {
+               if (!nofreeupl)
+                       ubc_upl_abort_range(pl, pl_offset, size, 
                                UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
                return (EINVAL);
        }
+       cred = ubc_getcred(vp);
+       if (cred == NOCRED)
+               cred = ap->a_cred;
 
-       auio.uio_iov = &aiov;
-       auio.uio_iovcnt = 1;
        auio.uio_offset = f_offset;
        auio.uio_segflg = UIO_SYSSPACE;
        auio.uio_rw = UIO_READ;
        auio.uio_procp = NULL;
 
-
        if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
                (void)nfs_fsinfo(nmp, vp, cred, p);
        biosize = min(vp->v_mount->mnt_stat.f_iosize, size);
@@ -4072,174 +4271,57 @@ nfs_pagein(ap)
        if (biosize & PAGE_MASK)
                panic("nfs_pagein(%x): biosize not page aligned", biosize);
 
-#if 0 /* Why bother? */
-/* DO NOT BOTHER WITH "approximately maintained cache consistency" */
-/* Does not make sense in paging paths -- Umesh*/
-       /*
-        * For nfs, cache consistency can only be maintained approximately.
-        * Although RFC1094 does not specify the criteria, the following is
-        * believed to be compatible with the reference port.
-        * For nqnfs, full cache consistency is maintained within the loop.
-        * For nfs:
-        * If the file's modify time on the server has changed since the
-        * last read rpc or you have written to the file,
-        * you may have lost data cache consistency with the
-        * server, so flush all of the file's data out of the cache.
-        * Then force a getattr rpc to ensure that you have up to date
-        * attributes.
-        * NB: This implies that cache data can be read when up to
-        * NFS_ATTRTIMEO seconds out of date. If you find that you need current
-        * attributes this could be forced by setting n_attrstamp to 0 before
-        * the VOP_GETATTR() call.
-        */
-       if ((nmp->nm_flag & NFSMNT_NQNFS) == 0) {
-               if (np->n_flag & NMODIFIED) {
-                       np->n_attrstamp = 0;
-                       error = VOP_GETATTR(vp, &vattr, cred, p);
-                       if (error) {
-                               if (!nocommit)
-                                       kernel_upl_abort_range(pl, pl_offset, 
-                                               size, 
-                                               UPL_ABORT_ERROR |
-                                               UPL_ABORT_FREE_ON_EMPTY);
-                               return (error);
-                       }
-                       np->n_mtime = vattr.va_mtime.tv_sec;
-               } else {
-                       error = VOP_GETATTR(vp, &vattr, cred, p);
-                       if (error){
-                               if (!nocommit)
-                                       kernel_upl_abort_range(pl, pl_offset, size,  
-                                               UPL_ABORT_ERROR |
-                                               UPL_ABORT_FREE_ON_EMPTY);
-                               return (error);
-                       }
-                       if (np->n_mtime != vattr.va_mtime.tv_sec) {
-                               error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
-                               if (error){
-                                       if (!nocommit)
-                                               kernel_upl_abort_range(pl, pl_offset, size, 
-                                                               UPL_ABORT_ERROR |
-                                                               UPL_ABORT_FREE_ON_EMPTY);
-                                       return (error);
-                               }
-                               np->n_mtime = vattr.va_mtime.tv_sec;
-                       }
-               }
-       }
-#endif 0 /* Why bother? */
-
-       kernel_upl_map(kernel_map, pl, &ioaddr);
+       ubc_upl_map(pl, &ioaddr);
        ioaddr += pl_offset;
        xsize = size;
 
        do {
-               uio->uio_resid = min(biosize, xsize);
-               aiov.iov_len  = uio->uio_resid;
+               iosize = min(biosize, xsize);
+               uio->uio_resid = iosize;
+               auio.uio_iov = &aiov;
+               auio.uio_iovcnt = 1;
+               aiov.iov_len  = iosize;
                aiov.iov_base = (caddr_t)ioaddr;
 
-               KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 322)) | DBG_FUNC_NONE,
-                       (int)uio->uio_offset, uio->uio_resid, ioaddr, xsize, 0);
-
-#warning nfs_pagein does not support NQNFS yet.
-#if 0 /* why bother? */
-/* NO RESOURCES TO FIX NQNFS CASE */
-/* We need to deal with this later -- Umesh */
-               /*
-                * Get a valid lease. If cached data is stale, flush it.
-                */
-               if (nmp->nm_flag & NFSMNT_NQNFS) {
-                       if (NQNFS_CKINVALID(vp, np, ND_READ)) {
-                               do {
-                                       error = nqnfs_getlease(vp, ND_READ, cred, p);
-                               } while (error == NQNFS_EXPIRED);
-                               if (error){
-                                       kernel_upl_unmap(kernel_map, pl);
-                                       if (!nocommit)
-                                               kernel_upl_abort_range(pl, pl_offset,
-                                                       size ,UPL_ABORT_ERROR |
-                                               UPL_ABORT_FREE_ON_EMPTY);
-
-                                       return (error);
-                               }
-                               if (np->n_lrev != np->n_brev ||
-                                       (np->n_flag & NQNFSNONCACHE)) {
-                                       error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
-                                       if (error) {
-                                               kernel_upl_unmap(kernel_map, pl);
-                                       if (!nocommit)
-                                               kernel_upl_abort_range(pl,
-                                                               pl_offset,size ,
-                                                               UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
-                                               return (error);
-                                       }
-                                       np->n_brev = np->n_lrev;
-                               }
-                       }
-               }
-#endif 0 /* why bother? */
-
-               if (np->n_flag & NQNFSNONCACHE) {
-                       error = nfs_readrpc(vp, uio, cred);
-                       kernel_upl_unmap(kernel_map, pl);
-
-                       if (!nocommit) {
-                               if(error) 
-                                       kernel_upl_abort_range(pl, pl_offset, size ,
-                                               UPL_ABORT_ERROR | UPL_ABORT_FREE_ON_EMPTY);
-                               else
-                                       kernel_upl_commit_range(pl, 
-                                               pl_offset, size, 
-                                               UPL_COMMIT_CLEAR_DIRTY 
-                                                  | UPL_COMMIT_FREE_ON_EMPTY,
-                                               UPL_GET_INTERNAL_PAGE_LIST(pl),
-                                               MAX_UPL_TRANSFER);
-                       }
-                       return (error);
-               }
-
+               FSDBG(322, uio->uio_offset, uio->uio_resid, ioaddr, xsize);
+#warning our nfs_pagein does not support NQNFS
                /*
                 * With UBC we get here only when the file data is not in the VM
                 * page cache, so go ahead and read in.
                 */
 #ifdef UBC_DEBUG
-               upl_ubc_alias_set(pl, ioaddr, 2);
+               upl_ubc_alias_set(pl, current_act(), 2);
 #endif /* UBC_DEBUG */
                nfsstats.pageins++;
+
                error = nfs_readrpc(vp, uio, cred);
 
                if (!error) {
-                       int zoff;
-                       int zcnt;
-
                        if (uio->uio_resid) {
                                /*
-                                * If uio_resid > 0, there is a hole in the file and
-                                * no writes after the hole have been pushed to
-                                * the server yet... or we're at the EOF
+                                * If uio_resid > 0, there is a hole in the file
+                                * and no writes after the hole have been pushed
+                                * to the server yet... or we're at the EOF
                                 * Just zero fill the rest of the valid area.
                                 */
-                               zcnt = uio->uio_resid;
-                               zoff = biosize - zcnt;
+                               int zcnt = uio->uio_resid;
+                               int zoff = iosize - zcnt;
                                bzero((char *)ioaddr + zoff, zcnt);
 
-                               KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 324)) | DBG_FUNC_NONE,
-                                       (int)uio->uio_offset, zoff, zcnt, ioaddr, 0);
-
+                               FSDBG(324, uio->uio_offset, zoff, zcnt, ioaddr);
                                uio->uio_offset += zcnt;
                        }
-                       ioaddr += biosize;      
-                       xsize  -= biosize;
+                       ioaddr += iosize;       
+                       xsize  -= iosize;
                } else
-                       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 322)) | DBG_FUNC_NONE,
-                               (int)uio->uio_offset, uio->uio_resid, error, -1, 0);
+                       FSDBG(322, uio->uio_offset, uio->uio_resid, error, -1);
 
                if (p && (vp->v_flag & VTEXT) &&
-                               (((nmp->nm_flag & NFSMNT_NQNFS) &&
-                               NQNFS_CKINVALID(vp, np, ND_READ) &&
-                               np->n_lrev != np->n_brev) ||
-                               (!(nmp->nm_flag & NFSMNT_NQNFS) &&
-                               np->n_mtime != np->n_vattr.va_mtime.tv_sec))) { 
+                   ((nmp->nm_flag & NFSMNT_NQNFS &&
+                     NQNFS_CKINVALID(vp, np, ND_READ) &&
+                     np->n_lrev != np->n_brev) ||
+                    (!(nmp->nm_flag & NFSMNT_NQNFS) &&
+                     np->n_mtime != np->n_vattr.va_mtime.tv_sec))) {
                        uprintf("Process killed due to text file modification\n");
                        psignal(p, SIGKILL);
                        p->p_flag |= P_NOSWAP;
@@ -4247,23 +4329,22 @@ nfs_pagein(ap)
 
        } while (error == 0 && xsize > 0);
 
-       kernel_upl_unmap(kernel_map, pl);
+       ubc_upl_unmap(pl);
 
-       if (!nocommit) {
+       if (!nofreeupl) {
                if (error) 
-                       kernel_upl_abort_range(pl, pl_offset, size, 
-                               UPL_ABORT_ERROR |  UPL_ABORT_FREE_ON_EMPTY);
+                       ubc_upl_abort_range(pl, pl_offset, size, 
+                                           UPL_ABORT_ERROR |
+                                           UPL_ABORT_FREE_ON_EMPTY);
                else
-                       kernel_upl_commit_range(pl, pl_offset, size,
-                               UPL_COMMIT_CLEAR_DIRTY 
-                                               | UPL_COMMIT_FREE_ON_EMPTY,
-                               UPL_GET_INTERNAL_PAGE_LIST(pl), 
-                               MAX_UPL_TRANSFER);
+                       ubc_upl_commit_range(pl, pl_offset, size,
+                                            UPL_COMMIT_CLEAR_DIRTY |
+                                            UPL_COMMIT_FREE_ON_EMPTY);
        }
-
        return (error);
 }
 
+
 /*
  * Vnode op for pageout using UPL
  * Derived from nfs_write()
@@ -4295,33 +4376,34 @@ nfs_pageout(ap)
        struct buf *bp;
        struct nfsmount *nmp = VFSTONFS(vp->v_mount);
        daddr_t lbn;
-       int bufsize;
        int n = 0, on, error = 0, iomode, must_commit, s;
        off_t off;
        vm_offset_t ioaddr;
        struct uio      auio;
        struct iovec    aiov;
        struct uio * uio = &auio;
-       int nocommit = flags & UPL_NOCOMMIT;
+       int nofreeupl = flags & UPL_NOCOMMIT;
        int iosize;
        int pgsize;
 
-       KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 323)) | DBG_FUNC_NONE,
-               (int)f_offset, size, pl, pl_offset, 0);
+       FSDBG(323, f_offset, size, pl, pl_offset);
+
+       if (pl == (upl_t)NULL)
+               panic("nfs_pageout: no upl");
 
        if (UBCINVALID(vp)) {
-#if DIAGNOSTIC
-               panic("nfs_pageout: invalid vnode");
-#endif
+               printf("nfs_pageout: invalid vnode 0x%x", (int)vp);
+               if (!nofreeupl)
+                       (void) ubc_upl_abort(pl, NULL); 
                return (EIO);
        }
        UBCINFOCHECK("nfs_pageout", vp);
 
-       if (size <= 0)
+       if (size <= 0) {
+               printf("nfs_pageout: invalid size %d", size);
+               if (!nofreeupl)
+                       (void) ubc_upl_abort(pl, NULL); 
                return (EINVAL);
-
-       if (pl == (upl_t)NULL) {
-               panic("nfs_pageout: no upl");
        }
 
        /*
@@ -4329,11 +4411,10 @@ nfs_pageout(ap)
         * will be the same size within a filesystem. nfs_writerpc will
         * still use nm_wsize when sizing the rpc's.
         */
-        biosize = min(vp->v_mount->mnt_stat.f_iosize, size);
-
-        if (biosize & PAGE_MASK)
-                panic("nfs_pageout(%x): biosize not page aligned", biosize);
+       biosize = min(vp->v_mount->mnt_stat.f_iosize, size);
 
+       if (biosize & PAGE_MASK)
+               panic("nfs_pageout(%x): biosize not page aligned", biosize);
 
        /*
         * Check to see whether the buffer is incore
@@ -4342,18 +4423,18 @@ nfs_pageout(ap)
         * vm_fault_list_request in 'getblk' before returning
         * which would block on the page busy status
         */
-        lbn = f_offset / PAGE_SIZE; /* to match the size getblk uses */
+       lbn = f_offset / PAGE_SIZE; /* to match the size getblk uses */
         
        for (iosize = size; iosize > 0; iosize -= PAGE_SIZE, lbn++) {
-
                s = splbio();
                if (bp = incore(vp, lbn)) {
+                       FSDBG(323, lbn*PAGE_SIZE, 1, bp, bp->b_flags);
                        if (ISSET(bp->b_flags, B_BUSY)) {
-                                /* don't panic incore. just tell vm we are busy */
-                               (void) kernel_upl_abort(pl, NULL); 
-                                return(EBUSY);
-                                };
-
+                               /* no panic. just tell vm we are busy */
+                               if (!nofreeupl)
+                                       (void) ubc_upl_abort(pl, NULL); 
+                               return(EBUSY);
+                       }
                        bremfree(bp);
                        SET(bp->b_flags, (B_BUSY | B_INVAL));
                        brelse(bp);
@@ -4367,25 +4448,25 @@ nfs_pageout(ap)
 
        if (np->n_flag & NWRITEERR) {
                np->n_flag &= ~NWRITEERR;
-               if (!nocommit)
-                       kernel_upl_abort_range(pl, pl_offset, size, 
-                               UPL_ABORT_FREE_ON_EMPTY);
+               if (!nofreeupl)
+                       ubc_upl_abort_range(pl, pl_offset, size,
+                                           UPL_ABORT_FREE_ON_EMPTY);
                return (np->n_error);
        }
        if ((nmp->nm_flag & (NFSMNT_NFSV3 | NFSMNT_GOTFSINFO)) == NFSMNT_NFSV3)
                (void)nfs_fsinfo(nmp, vp, cred, p);
 
        if (f_offset < 0 || f_offset >= np->n_size ||
-          (f_offset & PAGE_MASK_64) || (size & PAGE_MASK)) {
-               if (!nocommit)
-                       kernel_upl_abort_range(pl, pl_offset, size, 
-                               UPL_ABORT_FREE_ON_EMPTY);
+          f_offset & PAGE_MASK_64 || size & PAGE_MASK) {
+               if (!nofreeupl)
+                       ubc_upl_abort_range(pl, pl_offset, size,
+                                           UPL_ABORT_FREE_ON_EMPTY);
                return (EINVAL);
        }
 
-       kernel_upl_map(kernel_map, pl, &ioaddr);
+       ubc_upl_map(pl, &ioaddr);
 
-       if ((f_offset + size) > np->n_size)
+       if (f_offset + size > np->n_size)
                iosize = np->n_size - f_offset;
        else
                iosize = size;
@@ -4393,9 +4474,10 @@ nfs_pageout(ap)
        pgsize = (iosize + (PAGE_SIZE - 1)) & ~PAGE_MASK;
 
        if (size > pgsize) {
-               if (!nocommit)
-                       kernel_upl_abort_range(pl, pl_offset + pgsize, size - pgsize,
-                               UPL_ABORT_FREE_ON_EMPTY);
+               if (!nofreeupl)
+                       ubc_upl_abort_range(pl, pl_offset + pgsize,
+                                           size - pgsize,
+                                           UPL_ABORT_FREE_ON_EMPTY);
        }
        auio.uio_iov = &aiov;
        auio.uio_iovcnt = 1;
@@ -4407,139 +4489,41 @@ nfs_pageout(ap)
 
        aiov.iov_len = iosize;
        aiov.iov_base = (caddr_t)ioaddr + pl_offset;
-
        /* 
         * check for partial page and clear the
         * contents past end of the file before
         * releasing it in the VM page cache
         */
-       if ((f_offset < np->n_size) && (f_offset + size) > np->n_size) {
+       if (f_offset < np->n_size && f_offset + size > np->n_size) {
                size_t io = np->n_size - f_offset;
 
                bzero((caddr_t)(ioaddr + pl_offset + io), size - io);
 
-               KERNEL_DEBUG((FSDBG_CODE(DBG_FSRW, 321)) | DBG_FUNC_NONE,
-                       (int)np->n_size, (int)f_offset, (int)f_offset + io, size - io, 0);
+               FSDBG(321, np->n_size, f_offset, f_offset + io, size - io);
        }
 
        do {
-
-#warning nfs_pageout does not support NQNFS yet.
-#if 0 /* why bother? */
-/* NO RESOURCES TO FIX NQNFS CASE */
-/* We need to deal with this later -- Umesh */
-
-               /*
-                * Check for a valid write lease.
-                */
-               if ((nmp->nm_flag & NFSMNT_NQNFS) &&
-                   NQNFS_CKINVALID(vp, np, ND_WRITE)) {
-                       do {
-                               error = nqnfs_getlease(vp, ND_WRITE, cred, p);
-                       } while (error == NQNFS_EXPIRED);
-                       if (error) {
-                               kernel_upl_unmap(kernel_map, pl);
-                               if (!nocommit)
-                                       kernel_upl_abort_range(pl, pl_offset, size, 
-                                               UPL_ABORT_FREE_ON_EMPTY);
-                               return (error);
-                       }
-                       if (np->n_lrev != np->n_brev ||
-                           (np->n_flag & NQNFSNONCACHE)) {
-                               error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
-                               if (error) {
-                                       kernel_upl_unmap(kernel_map, pl);
-                                       if (!nocommit)
-                                               kernel_upl_abort_range(pl, 
-                                               pl_offset, size, 
-                                               UPL_ABORT_FREE_ON_EMPTY);
-                                       return (error);
-                               }
-                               np->n_brev = np->n_lrev;
-                       }
-               }
-#endif 0 /* why bother? */
-
-               if ((np->n_flag & NQNFSNONCACHE) && uio->uio_iovcnt == 1) {
-                       iomode = NFSV3WRITE_FILESYNC;
-                       error = nfs_writerpc(vp, uio, cred, &iomode, &must_commit);
-                       if (must_commit)
-                               nfs_clearcommit(vp->v_mount);
-                       kernel_upl_unmap(kernel_map, pl);
-                        
-                        /* see comments below after other nfs_writerpc and ESTALE */
-                        if (error == ESTALE) {
-                            kernel_upl_abort_range(pl, pl_offset, size, 
-                                UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY);
-                        } else {
-                            if (!nocommit) {
-                                if(error)
-                                    kernel_upl_abort_range(pl, pl_offset, size, 
-                                    UPL_ABORT_FREE_ON_EMPTY);
-                                else
-                                    kernel_upl_commit_range(pl, 
-                                        pl_offset, size, 
-                                        UPL_COMMIT_CLEAR_DIRTY | UPL_COMMIT_FREE_ON_EMPTY,
-                                        UPL_GET_INTERNAL_PAGE_LIST(pl), MAX_UPL_TRANSFER);
-                            }
-                        }
-                       return (error);
-               }
+#warning our nfs_pageout does not support NQNFS
                nfsstats.pageouts++;
                lbn = uio->uio_offset / biosize;
                on = uio->uio_offset & (biosize-1);
                n = min((unsigned)(biosize - on), uio->uio_resid);
 again:
-               bufsize = biosize;
 #if 0
-               if ((lbn + 1) * biosize > np->n_size) {
-                       bufsize = np->n_size - lbn * biosize;
+               /* (removed for UBC) */
+               bufsize = biosize;
+               if ((off_t)(lbn + 1) * biosize > np->n_size) {
+                       bufsize = np->n_size - (off_t)lbn * biosize;
                        bufsize = (bufsize + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
                }
 #endif
                vp->v_numoutput++;
-
-               np->n_flag |= NMODIFIED;
-
-#if 0 /* why bother? */
-/* NO RESOURCES TO FIX NQNFS CASE */
-/* We need to deal with this later -- Umesh */
-               /*
-                * Check for valid write lease and get one as required.
-                * In case getblk() and/or bwrite() delayed us.
-                */
-               if ((nmp->nm_flag & NFSMNT_NQNFS) &&
-                   NQNFS_CKINVALID(vp, np, ND_WRITE)) {
-                       do {
-                               error = nqnfs_getlease(vp, ND_WRITE, cred, p);
-                       } while (error == NQNFS_EXPIRED);
-                       if (error)
-                               goto cleanup;
-
-                       if (np->n_lrev != np->n_brev ||
-                           (np->n_flag & NQNFSNONCACHE)) {
-                                       error = nfs_vinvalbuf(vp, V_SAVE, cred, p, 1);
-                                       if (error) {
-                                               kernel_upl_unmap(kernel_map, pl);
-                                               if (!nocommit)
-                                                       kernel_upl_abort_range(pl, 
-                                                       pl_offset,
-                                                       size,
-                                                 UPL_ABORT_FREE_ON_EMPTY);
-
-                                               return (error);
-                                       }
-                                       np->n_brev = np->n_lrev;
-                                       goto again;
-                       }
-               }
-#endif 0 /* why bother? */
-
+               /* NMODIFIED would be set here if doing unstable writes */
                iomode = NFSV3WRITE_FILESYNC;
                error = nfs_writerpc(vp, uio, cred, &iomode, &must_commit);
                if (must_commit)
                        nfs_clearcommit(vp->v_mount);
-               vp->v_numoutput--;
+               vpwakeup(vp);
 
                if (error)
                        goto cleanup;
@@ -4553,30 +4537,70 @@ again:
        } while (uio->uio_resid > 0 && n > 0);
 
 cleanup:
-       kernel_upl_unmap(kernel_map, pl);
-       /* 
-       * EStale is special. In this case, we want vm to dump out
-       * the pages. Better yet, sever the object so we don't come
-       * back here on each page of the object to page out. For now,
-       * just dump. 
-       * XXX What about !nocommit case? Should ESTALE only be checked
-       * in that portion? - EKN
-       */
-       if (error == ESTALE) {
-            kernel_upl_abort_range(pl, pl_offset, size, 
-                UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY);
-       } else {
-            if (!nocommit) {
-                if(error)
-                    kernel_upl_abort_range(pl, pl_offset, pgsize, 
-                        UPL_ABORT_FREE_ON_EMPTY);
-                else
-                    kernel_upl_commit_range(pl, pl_offset, pgsize,
-                        UPL_COMMIT_CLEAR_DIRTY | UPL_COMMIT_FREE_ON_EMPTY,
-                    UPL_GET_INTERNAL_PAGE_LIST(pl), MAX_UPL_TRANSFER);
-            }
+       ubc_upl_unmap(pl);
+       /*
+        * We've had several different solutions on what to do when the pageout
+        * gets an error. If we don't handle it, and return an error to the 
+        * caller, vm, it will retry . This can end in endless looping 
+        * between vm and here doing retries of the same page. Doing a dump
+        * back to vm, will get it out of vm's knowledge and we lose whatever
+        * data existed. This is risky, but in some cases necessary. For
+        * example, the initial fix here was to do that for ESTALE. In that case
+        * the server is telling us that the file is no longer the same. We 
+        * would not want to keep paging out to that. We also saw some 151 
+        * errors from Auspex server and NFSv3 can return errors higher than
+        * ELAST. Those along with NFS known server errors we will "dump" from
+        * vm.  Errors we don't expect to occur, we dump and log for further
+        * analysis. Errors that could be transient, networking ones,
+        * we let vm "retry". Lastly, errors that we retry, but may have potential
+        * to storm the network, we "retrywithsleep". "sever" will be used in
+        * in the future to dump all pages of object for cases like ESTALE.
+        * All this is the basis for the states returned and first guesses on
+        * error handling. Tweaking expected as more statistics are gathered.
+        * Note, in the long run we may need another more robust solution to
+        * have some kind of persistant store when the vm cannot dump nor keep
+        * retrying as a solution, but this would be a file architectural change
+        */
+         
+       if (!nofreeupl) { /* otherwise stacked file system has to handle this */
+               if (error) {
+                       int abortflags; 
+                       short action = nfs_pageouterrorhandler(error);
+                       
+                       switch (action) {
+                               case DUMP:
+                                       abortflags = UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY;
+                                       break;
+                               case DUMPANDLOG:
+                                       abortflags = UPL_ABORT_DUMP_PAGES|UPL_ABORT_FREE_ON_EMPTY;
+                                       if (error <= ELAST &&
+                                           (errorcount[error] % 100 == 0)) 
+                                               printf("nfs_pageout: unexpected error %d. dumping vm page\n", error);
+                                       errorcount[error]++;
+                                       break;
+                               case RETRY:
+                                       abortflags = UPL_ABORT_FREE_ON_EMPTY;
+                                       break;
+                               case RETRYWITHSLEEP:
+                                       abortflags = UPL_ABORT_FREE_ON_EMPTY;
+                                       /* pri unused. PSOCK for placeholder. */
+                                       (void) tsleep(&lbolt, PSOCK,
+                                                     "nfspageout", 0);
+                                       break;
+                               case SEVER: /* not implemented */
+                               default:
+                                       printf("nfs_pageout: action %d not expected\n", action);
+                                       break;
+                       }
+                               
+                       ubc_upl_abort_range(pl, pl_offset, size, abortflags);
+                       /* return error in all cases above */
+                       
+               } else 
+                       ubc_upl_commit_range(pl, pl_offset, pgsize,
+                                            UPL_COMMIT_CLEAR_DIRTY |
+                                            UPL_COMMIT_FREE_ON_EMPTY);
        }
-
        return (error);
 }
 
@@ -4594,12 +4618,11 @@ nfs_blktooff(ap)
 
        biosize = min(vp->v_mount->mnt_stat.f_iosize, PAGE_SIZE); /* nfs_bio.c */
 
-       *ap->a_offset = (off_t)(ap->a_lblkno *  biosize);
+       *ap->a_offset = (off_t)ap->a_lblkno *  biosize;
 
        return (0);
 }
 
-/* Blktooff derives file offset given a logical block number */
 static int
 nfs_offtoblk(ap)
        struct vop_offtoblk_args /* {