diff -ur nfs.orig/nfs_node.c nfs/nfs_node.c
--- nfs.orig/nfs_node.c	2006-04-03 12:20:15.000000000 -0500
+++ nfs/nfs_node.c	2006-04-05 03:12:36.000000000 -0500
@@ -213,13 +213,8 @@
 	np = VTONFS(ap->a_vp);
 	if (prtactive && ap->a_vp->v_usecount != 0)
 		vprint("nfs_inactive: pushing active", ap->a_vp);
-	if (ap->a_vp->v_type != VDIR) {
-		sp = np->n_sillyrename;
-		np->n_sillyrename = NULL;
-	} else {
-		sp = NULL;
-	}
-	if (sp) {
+ 	sp = &np->n_sillyrename;
+	if (ap->a_vp->v_type != VDIR && sp->s_ncp != NULL) {
 		/*
 		 * We need a reference to keep the vnode from being
 		 * recycled by getnewvnode while we do the I/O
@@ -238,10 +233,13 @@
 		/*
 		 * Remove the silly file that was rename'd earlier
 		 */
-		nfs_removeit(sp);
+		cache_lock(sp->s_ncp);
+		/* XXX shouln't we lock s_ncp->nc_parent->nc_vp first? */
+		nfs_removerpc(sp->s_ncp, sp->s_cred);
+		cache_setunresolved(sp->s_ncp);
+		cache_put(sp->s_ncp);
 		crfree(sp->s_cred);
-		vrele(sp->s_dvp);
-		FREE((caddr_t)sp, M_NFSREQ);
+		sp->s_ncp = NULL;
 	}
 
 	np->n_flag &= ~(NWRITEERR | NACC | NUPD | NCHG | NLOCKED | NWANTED);
diff -ur nfs.orig/nfs_vnops.c nfs/nfs_vnops.c
--- nfs.orig/nfs_vnops.c	2006-04-03 12:20:15.000000000 -0500
+++ nfs/nfs_vnops.c	2006-04-06 00:13:00.000000000 -0500
@@ -112,9 +112,6 @@
 static int	nfsfifo_close (struct vop_close_args *);
 #define nfs_poll vop_nopoll
 static int	nfs_setattrrpc (struct vnode *,struct vattr *,struct ucred *,struct thread *);
-static	int	nfs_lookup (struct vop_old_lookup_args *);
-static	int	nfs_create (struct vop_old_create_args *);
-static	int	nfs_mknod (struct vop_old_mknod_args *);
 static	int	nfs_open (struct vop_open_args *);
 static	int	nfs_close (struct vop_close_args *);
 static	int	nfs_access (struct vop_access_args *);
@@ -123,18 +120,12 @@
 static	int	nfs_read (struct vop_read_args *);
 static	int	nfs_mmap (struct vop_mmap_args *);
 static	int	nfs_fsync (struct vop_fsync_args *);
-static	int	nfs_remove (struct vop_old_remove_args *);
-static	int	nfs_link (struct vop_old_link_args *);
-static	int	nfs_rename (struct vop_old_rename_args *);
-static	int	nfs_mkdir (struct vop_old_mkdir_args *);
-static	int	nfs_rmdir (struct vop_old_rmdir_args *);
-static	int	nfs_symlink (struct vop_old_symlink_args *);
 static	int	nfs_readdir (struct vop_readdir_args *);
 static	int	nfs_bmap (struct vop_bmap_args *);
 static	int	nfs_strategy (struct vop_strategy_args *);
 static	int	nfs_lookitup (struct vnode *, const char *, int,
 			struct ucred *, struct thread *, struct nfsnode **);
-static	int	nfs_sillyrename (struct vnode *,struct vnode *,struct componentname *);
+static	int	nfs_sillyrename (struct namecache *, struct ucred *);
 static int	nfsspec_access (struct vop_access_args *);
 static int	nfs_readlink (struct vop_readlink_args *);
 static int	nfs_print (struct vop_print_args *);
@@ -142,6 +133,15 @@
 static int	nfs_bwrite (struct vop_bwrite_args *);
 
 static	int	nfs_nresolve (struct vop_nresolve_args *);
+static	int	nfs_nlookupdotdot (struct vop_nlookupdotdot_args *);
+static	int	nfs_ncreate (struct vop_ncreate_args *);
+static	int	nfs_nmknod (struct vop_nmknod_args *);
+static	int	nfs_nremove (struct vop_nremove_args *);
+static	int	nfs_nlink (struct vop_nlink_args *);
+static	int	nfs_nrename (struct vop_nrename_args *);
+static	int	nfs_nmkdir (struct vop_nmkdir_args *);
+static	int	nfs_nrmdir (struct vop_nrmdir_args *);
+static	int	nfs_nsymlink (struct vop_nsymlink_args *);
 /*
  * Global vfs data structures for nfs
  */
@@ -152,7 +152,6 @@
 	{ &vop_bmap_desc,		(vnodeopv_entry_t) nfs_bmap },
 	{ &vop_bwrite_desc,		(vnodeopv_entry_t) nfs_bwrite },
 	{ &vop_close_desc,		(vnodeopv_entry_t) nfs_close },
-	{ &vop_old_create_desc,		(vnodeopv_entry_t) nfs_create },
 	{ &vop_fsync_desc,		(vnodeopv_entry_t) nfs_fsync },
 	{ &vop_getattr_desc,		(vnodeopv_entry_t) nfs_getattr },
 	{ &vop_getpages_desc,		(vnodeopv_entry_t) nfs_getpages },
@@ -160,11 +159,7 @@
 	{ &vop_inactive_desc,		(vnodeopv_entry_t) nfs_inactive },
 	{ &vop_islocked_desc,		(vnodeopv_entry_t) vop_stdislocked },
 	{ &vop_lease_desc,		vop_null },
-	{ &vop_old_link_desc,		(vnodeopv_entry_t) nfs_link },
 	{ &vop_lock_desc,		(vnodeopv_entry_t) vop_stdlock },
-	{ &vop_old_lookup_desc,		(vnodeopv_entry_t) nfs_lookup },
-	{ &vop_old_mkdir_desc,		(vnodeopv_entry_t) nfs_mkdir },
-	{ &vop_old_mknod_desc,		(vnodeopv_entry_t) nfs_mknod },
 	{ &vop_mmap_desc,		(vnodeopv_entry_t) nfs_mmap },
 	{ &vop_open_desc,		(vnodeopv_entry_t) nfs_open },
 	{ &vop_poll_desc,		(vnodeopv_entry_t) nfs_poll },
@@ -173,16 +168,21 @@
 	{ &vop_readdir_desc,		(vnodeopv_entry_t) nfs_readdir },
 	{ &vop_readlink_desc,		(vnodeopv_entry_t) nfs_readlink },
 	{ &vop_reclaim_desc,		(vnodeopv_entry_t) nfs_reclaim },
-	{ &vop_old_remove_desc,		(vnodeopv_entry_t) nfs_remove },
-	{ &vop_old_rename_desc,		(vnodeopv_entry_t) nfs_rename },
-	{ &vop_old_rmdir_desc,		(vnodeopv_entry_t) nfs_rmdir },
 	{ &vop_setattr_desc,		(vnodeopv_entry_t) nfs_setattr },
 	{ &vop_strategy_desc,		(vnodeopv_entry_t) nfs_strategy },
-	{ &vop_old_symlink_desc,	(vnodeopv_entry_t) nfs_symlink },
 	{ &vop_unlock_desc,		(vnodeopv_entry_t) vop_stdunlock },
 	{ &vop_write_desc,		(vnodeopv_entry_t) nfs_write },
 
 	{ &vop_nresolve_desc,		(vnodeopv_entry_t) nfs_nresolve },
+	{ &vop_nlookupdotdot_desc,	(vnodeopv_entry_t) nfs_nlookupdotdot },
+	{ &vop_ncreate_desc,		(vnodeopv_entry_t) nfs_ncreate },
+	{ &vop_nmknod_desc,		(vnodeopv_entry_t) nfs_nmknod },
+	{ &vop_nremove_desc,		(vnodeopv_entry_t) nfs_nremove },
+	{ &vop_nlink_desc,		(vnodeopv_entry_t) nfs_nlink },
+	{ &vop_nrename_desc,		(vnodeopv_entry_t) nfs_nrename },
+	{ &vop_nmkdir_desc,		(vnodeopv_entry_t) nfs_nmkdir },
+	{ &vop_nrmdir_desc,		(vnodeopv_entry_t) nfs_nrmdir },
+	{ &vop_nsymlink_desc,		(vnodeopv_entry_t) nfs_nsymlink },
 	{ NULL, NULL }
 };
 
@@ -225,19 +225,8 @@
 	{ NULL, NULL }
 };
 
-static int	nfs_mknodrpc (struct vnode *dvp, struct vnode **vpp,
-				  struct componentname *cnp,
-				  struct vattr *vap);
-static int	nfs_removerpc (struct vnode *dvp, const char *name,
-				   int namelen,
-				   struct ucred *cred, struct thread *td);
-static int	nfs_renamerpc (struct vnode *fdvp, const char *fnameptr,
-				   int fnamelen, struct vnode *tdvp,
-				   const char *tnameptr, int tnamelen,
-				   struct ucred *cred, struct thread *td);
-static int	nfs_renameit (struct vnode *sdvp,
-				  struct componentname *scnp,
-				  struct sillyrename *sp);
+static int	nfs_renamerpc (struct namecache *fncp, struct namecache *tncp,
+				   struct ucred *cred);
 
 /*
  * Global variables
@@ -853,8 +842,8 @@
 }
 
 /*
- * NEW API CALL - replaces nfs_lookup().  However, we cannot remove 
- * nfs_lookup() until all remaining new api calls are implemented.
+ * nfs_nresolve { struct namecache *a_ncp,
+ *		  struct ucred *a_cred }
  *
  * Resolve a namecache entry.  This function is passed a locked ncp and
  * must call cache_setvp() on it as appropriate to resolve the entry.
@@ -872,7 +861,6 @@
 	int attrflag;
 	int fhsize;
 	int error;
-	int len;
 	int v3;
 	/******NFSM MACROS********/
 	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
@@ -892,12 +880,11 @@
 	v3 = NFS_ISV3(dvp);
 	nfsstats.lookupcache_misses++;
 	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
-	len = ncp->nc_nlen;
 	nfsm_reqhead(dvp, NFSPROC_LOOKUP,
-		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len));
+		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(ncp->nc_nlen));
 	nfsm_fhtom(dvp, v3);
-	nfsm_strtom(ncp->nc_name, len, NFS_MAXNAMLEN);
-	nfsm_request(dvp, NFSPROC_LOOKUP, td, ap->a_cred);
+	nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN);
+	nfsm_request(dvp, NFSPROC_LOOKUP, td, cred);
 	if (error) {
 		/*
 		 * Cache negatve lookups to reduce NFS traffic, but use
@@ -971,6 +958,91 @@
 }
 
 /*
+ * nfs_nlookupdotdot { struct vnode *a_dvp,
+ *		       struct vnode **a_vpp,
+ *		       struct ucred *a_cred }
+ *
+ * Lookup the vnode representing the parent directory of the specified
+ * directory vnode.  a_dvp should not be locked.  If no error occurs *a_vpp
+ * will contained the parent vnode, locked and refd, else *a_vpp will be NULL.
+ *
+ * This function is designed to aid NFS server-side operations and is
+ * used by cache_fromdvp() to create a consistent, connected namecache
+ * topology.
+ *
+ * XXX The utility of this function is questionable, since re-exporting
+ * an NFS doesn't work.
+ *
+ */
+static int
+nfs_nlookupdotdot(struct vop_nlookupdotdot_args *ap)
+{
+	struct thread *td = curthread;
+	struct nfsnode *np;
+	struct vnode *dvp;
+	struct vnode *nvp;
+	nfsfh_t *fhp;
+	int attrflag;
+	int fhsize;
+	int v3;
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
+	u_int32_t *tl;
+	int32_t t1, t2;
+	int error; /* set by nfsm_*, which may jump to nfsmout: */
+
+	*ap->a_vpp = NULL;
+
+	dvp = ap->a_dvp;
+	if ((error = vget(dvp, LK_SHARED, td)) != 0)
+		return (error);
+	if (dvp->v_type != VDIR) {
+		vput(dvp);
+		return (ENOTDIR);
+	}
+
+	v3 = NFS_ISV3(dvp);
+	nfsstats.lookupcache_misses++;
+	nfsstats.rpccnt[NFSPROC_LOOKUP]++;
+	nfsm_reqhead(dvp, NFSPROC_LOOKUP,
+		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(2));
+	nfsm_fhtom(dvp, v3);
+	nfsm_strtom("..", (u_char)2, NFS_MAXNAMLEN);
+	nfsm_request(dvp, NFSPROC_LOOKUP, td, ap->a_cred);
+	if (error) {
+		nfsm_postop_attr(dvp, attrflag, NFS_LATTR_NOSHRINK);
+		m_freem(mrep);
+		goto nfsmout;
+	}
+
+	/*
+	 * Success, get the file handle, do various checks, and load 
+	 * post-operation data from the reply packet.
+	 */
+	nfsm_getfh(fhp, fhsize, v3);
+
+	/* nfs_nget() locks and refs the vnode */
+	error = nfs_nget(dvp->v_mount, fhp, fhsize, &np);
+	if (error) {
+		m_freem(mrep);
+		goto nfsmout; /* NOTE: return error from nget */
+	}
+	nvp = NFSTOV(np);
+	if (v3) {
+		nfsm_postop_attr(nvp, attrflag, NFS_LATTR_NOSHRINK);
+		nfsm_postop_attr(dvp, attrflag, NFS_LATTR_NOSHRINK);
+	} else {
+		nfsm_loadattr(nvp, NULL);
+	}
+	*ap->a_vpp = nvp;
+	m_freem(mrep);
+nfsmout:
+	vput(dvp);
+	return (error);
+}
+
+/*
  * 'cached' nfs directory lookup
  *
  * NOTE: cannot be removed until NFS implements all the new n*() API calls.
@@ -978,6 +1050,7 @@
  * nfs_lookup(struct vnodeop_desc *a_desc, struct vnode *a_dvp,
  *	      struct vnode **a_vpp, struct componentname *a_cnp)
  */
+#if 0
 static int
 nfs_lookup(struct vop_old_lookup_args *ap)
 {
@@ -1108,7 +1181,7 @@
 	} else
 		nfsm_loadattr(newvp, (struct vattr *)0);
 #if 0
-	/* XXX MOVE TO nfs_nremove() */
+	/* XXX MOVE TO nfs_nremove().  n_ctime is used nowhere; remove it? */
 	if ((cnp->cn_flags & CNP_MAKEENTRY) &&
 	    cnp->cn_nameiop != NAMEI_DELETE) {
 		np->n_ctime = np->n_vattr.va_ctime.tv_sec; /* XXX */
@@ -1137,6 +1210,7 @@
 	}
 	return (error);
 }
+#endif
 
 /*
  * nfs read call.
@@ -1392,43 +1466,70 @@
 }
 
 /*
- * nfs mknod rpc
+ * nfs_nmknod { struct namecache *a_ncp,
+ *		struct vnode *a_vpp,
+ *		struct ucred *a_cred,
+ *		struct vattr *a_vap }
+ *
+ * nfs mknod vop
  * For NFS v2 this is a kludge. Use a create rpc but with the IFMT bits of the
  * mode set to specify the file type and the size field for rdev.
  */
 static int
-nfs_mknodrpc(struct vnode *dvp, struct vnode **vpp, struct componentname *cnp,
-	     struct vattr *vap)
+nfs_nmknod(struct vop_nmknod_args *ap)
 {
+	struct thread *td = curthread;
+	struct namecache *ncp = ap->a_ncp;
+	struct ucred *cred = ap->a_cred;
+	struct vattr *vap = ap->a_vap;
+	struct vnode *dvp;
 	struct nfsv2_sattr *sp;
-	u_int32_t *tl;
-	caddr_t cp;
-	int32_t t1, t2;
-	struct vnode *newvp = (struct vnode *)0;
-	struct nfsnode *np = (struct nfsnode *)0;
+	struct vnode *newvp = NULL;
+	struct nfsnode *np = NULL;
 	struct vattr vattr;
-	char *cp2;
-	caddr_t bpos, dpos;
-	int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0;
-	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+	int wccflag = NFSV3_WCCRATTR, gotvp = 0;
 	u_int32_t rdev;
-	int v3 = NFS_ISV3(dvp);
+	int v3;	
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
+	u_int32_t *tl;
+	int32_t t1, t2;
+	int error; /* set by nfsm_*, which may jump to nfsmout: */
+
+	*ap->a_vpp = NULL;
 
 	if (vap->va_type == VCHR || vap->va_type == VBLK)
 		rdev = txdr_unsigned(vap->va_rdev);
 	else if (vap->va_type == VFIFO || vap->va_type == VSOCK)
 		rdev = nfs_xdrneg1;
-	else {
+	else
 		return (EOPNOTSUPP);
+
+	KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0);
+
+	KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp);
+	dvp = ncp->nc_parent->nc_vp;
+	if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0)
+		return (error);
+
+	if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
+		vput(dvp);
+		return(EROFS);
 	}
-	if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_td)) != 0) {
+
+	if ((error = VOP_GETATTR(dvp, &vattr, td)) != 0) {
+		vput(dvp);
 		return (error);
 	}
+
+	/* nfsm functions assume that error is zero! */
+	v3 = NFS_ISV3(dvp);
 	nfsstats.rpccnt[NFSPROC_MKNOD]++;
 	nfsm_reqhead(dvp, NFSPROC_MKNOD, NFSX_FH(v3) + 4 * NFSX_UNSIGNED +
-		+ nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
+	    nfsm_rndup(ncp->nc_nlen) + NFSX_SATTR(v3));
 	nfsm_fhtom(dvp, v3);
-	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
+	nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN);
 	if (v3) {
 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 		*tl++ = vtonfsv3_type(vap->va_type);
@@ -1447,17 +1548,17 @@
 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
 	}
-	nfsm_request(dvp, NFSPROC_MKNOD, cnp->cn_td, cnp->cn_cred);
-	if (!error) {
+	nfsm_request(dvp, NFSPROC_MKNOD, td, cred);
+	if (error == 0) {
 		nfsm_mtofh(dvp, newvp, v3, gotvp);
-		if (!gotvp) {
+		if (gotvp == 0) {
 			if (newvp) {
 				vput(newvp);
-				newvp = (struct vnode *)0;
+				newvp = NULL;
 			}
-			error = nfs_lookitup(dvp, cnp->cn_nameptr,
-			    cnp->cn_namelen, cnp->cn_cred, cnp->cn_td, &np);
-			if (!error)
+			error = nfs_lookitup(dvp, ncp->nc_name, ncp->nc_nlen,
+			    cred, td, &np);
+			if (error == 0)
 				newvp = NFSTOV(np);
 		}
 	}
@@ -1469,70 +1570,85 @@
 		if (newvp)
 			vput(newvp);
 	} else {
-		*vpp = newvp;
+		cache_setunresolved(ncp);
+		cache_setvp(ncp, newvp);
+		*ap->a_vpp = newvp;
 	}
 	VTONFS(dvp)->n_flag |= NLMODIFIED;
 	if (!wccflag)
 		VTONFS(dvp)->n_attrstamp = 0;
+	vput(dvp);
 	return (error);
 }
 
-/*
- * nfs mknod vop
- * just call nfs_mknodrpc() to do the work.
- *
- * nfs_mknod(struct vnode *a_dvp, struct vnode **a_vpp,
- *	     struct componentname *a_cnp, struct vattr *a_vap)
- */
-/* ARGSUSED */
-static int
-nfs_mknod(struct vop_old_mknod_args *ap)
-{
-	return nfs_mknodrpc(ap->a_dvp, ap->a_vpp, ap->a_cnp, ap->a_vap);
-}
-
 static u_long create_verf;
 /*
- * nfs file create call
+ * nfs_ncreate { struct namecache *a_ncp,
+ *		 struct vnode **a_vpp,
+ *		 struct ucred *a_cred,
+ *		 struct vattr *a_vap }
  *
- * nfs_create(struct vnode *a_dvp, struct vnode **a_vpp,
- *	      struct componentname *a_cnp, struct vattr *a_vap)
+ * nfs file create call
  */
 static int
-nfs_create(struct vop_old_create_args *ap)
+nfs_ncreate(struct vop_ncreate_args *ap)
 {
-	struct vnode *dvp = ap->a_dvp;
+	struct thread *td = curthread;
+	struct namecache *ncp;
+	struct vnode *dvp;
+	struct ucred *cred = ap->a_cred;
 	struct vattr *vap = ap->a_vap;
-	struct componentname *cnp = ap->a_cnp;
 	struct nfsv2_sattr *sp;
+	struct nfsnode *np = NULL;
+	struct vnode *newvp = NULL;
+	int wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
+	struct vattr vattr;
+	int v3;
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
 	u_int32_t *tl;
-	caddr_t cp;
 	int32_t t1, t2;
-	struct nfsnode *np = (struct nfsnode *)0;
-	struct vnode *newvp = (struct vnode *)0;
-	caddr_t bpos, dpos, cp2;
-	int error = 0, wccflag = NFSV3_WCCRATTR, gotvp = 0, fmode = 0;
-	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-	struct vattr vattr;
-	int v3 = NFS_ISV3(dvp);
+	int error; /* set by nfsm_*, which may jump to nfsmout: */
+
+	ncp = ap->a_ncp;		/* locked namecache node */
 
 	/*
 	 * Oops, not for me..
 	 */
-	if (vap->va_type == VSOCK)
-		return (nfs_mknodrpc(dvp, ap->a_vpp, cnp, vap));
+	if (vap->va_type == VSOCK) {
+		printf("nfs_ncreate() calling nfs_mknodrpc() instead\n");
+		/*  XXX This assumes vop_ncreate_args == vop_nmknod_args */
+		return (nfs_nmknod(ap));
+	}
+
+	*ap->a_vpp = NULL;
 
-	if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_td)) != 0) {
+	KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0);
+
+	KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp);
+	dvp = ncp->nc_parent->nc_vp;
+	if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0)
+		return (error);
+
+	if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
+		vput(dvp);
+		return (EROFS);
+	}
+
+	if ((error = VOP_GETATTR(dvp, &vattr, td)) != 0) {
+		vput(dvp);
 		return (error);
 	}
 	if (vap->va_vaflags & VA_EXCLUSIVE)
 		fmode |= O_EXCL;
+	v3 = NFS_ISV3(dvp);
 again:
 	nfsstats.rpccnt[NFSPROC_CREATE]++;
 	nfsm_reqhead(dvp, NFSPROC_CREATE, NFSX_FH(v3) + 2 * NFSX_UNSIGNED +
-		nfsm_rndup(cnp->cn_namelen) + NFSX_SATTR(v3));
+		nfsm_rndup(ncp->nc_nlen) + NFSX_SATTR(v3));
 	nfsm_fhtom(dvp, v3);
-	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
+	nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN);
 	if (v3) {
 		nfsm_build(tl, u_int32_t *, NFSX_UNSIGNED);
 		if (fmode & O_EXCL) {
@@ -1558,17 +1674,17 @@
 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
 	}
-	nfsm_request(dvp, NFSPROC_CREATE, cnp->cn_td, cnp->cn_cred);
-	if (!error) {
+	nfsm_request(dvp, NFSPROC_CREATE, td, cred);
+	if (error == 0) {
 		nfsm_mtofh(dvp, newvp, v3, gotvp);
-		if (!gotvp) {
+		if (gotvp == 0) {
 			if (newvp) {
 				vput(newvp);
-				newvp = (struct vnode *)0;
+				newvp = NULL;
 			}
-			error = nfs_lookitup(dvp, cnp->cn_nameptr,
-			    cnp->cn_namelen, cnp->cn_cred, cnp->cn_td, &np);
-			if (!error)
+			error = nfs_lookitup(dvp, ncp->nc_name,
+			    ncp->nc_nlen, cred, td, &np);
+			if (error == 0)
 				newvp = NFSTOV(np);
 		}
 	}
@@ -1596,9 +1712,9 @@
 			vfs_timestamp(&vap->va_mtime);
 		if (vap->va_atime.tv_sec == VNOVAL)
 			vap->va_atime = vap->va_mtime;
-		error = nfs_setattrrpc(newvp, vap, cnp->cn_cred, cnp->cn_td);
+		error = nfs_setattrrpc(newvp, vap, cred, td);
 	}
-	if (!error) {
+	if (error == 0) {
 		/*
 		 * The new np may have enough info for access
 		 * checks, make sure rucred and wucred are
@@ -1606,18 +1722,24 @@
 		 */
 		np = VTONFS(newvp);
 		if (np->n_rucred == NULL)
-			np->n_rucred = crhold(cnp->cn_cred);
+			np->n_rucred = crhold(cred);
 		if (np->n_wucred == NULL)
-			np->n_wucred = crhold(cnp->cn_cred);
+			np->n_wucred = crhold(cred);
+		cache_setunresolved(ncp);
+		cache_setvp(ncp, newvp);
 		*ap->a_vpp = newvp;
 	}
 	VTONFS(dvp)->n_flag |= NLMODIFIED;
 	if (!wccflag)
 		VTONFS(dvp)->n_attrstamp = 0;
+	vput(dvp);
 	return (error);
 }
 
 /*
+ * nfs_nremove { struct namecache *a_ncp,
+ *		 struct ucred *a_cred }
+ *
  * nfs file remove call
  * To try and make nfs semantics closer to ufs semantics, a file that has
  * other processes using the vnode is renamed instead of removed and then
@@ -1627,83 +1749,88 @@
  *	     call nfs_sillyrename() to set it up
  *     else
  *	  do the remove rpc
- *
- * nfs_remove(struct vnodeop_desc *a_desc, struct vnode *a_dvp,
- *	      struct vnode *a_vp, struct componentname *a_cnp)
  */
 static int
-nfs_remove(struct vop_old_remove_args *ap)
+nfs_nremove(struct vop_nremove_args *ap)
 {
-	struct vnode *vp = ap->a_vp;
-	struct vnode *dvp = ap->a_dvp;
-	struct componentname *cnp = ap->a_cnp;
-	struct nfsnode *np = VTONFS(vp);
+	struct thread *td = curthread;
+	struct namecache *ncp;
+	struct ucred *cred;
+	struct vnode *dvp, *vp;
 	int error = 0;
 	struct vattr vattr;
 
-#ifndef DIAGNOSTIC
-	if (vp->v_usecount < 1)
-		panic("nfs_remove: bad v_usecount");
-#endif
-	if (vp->v_type == VDIR)
-		error = EPERM;
-	else if (vp->v_usecount == 1 || (np->n_sillyrename &&
-	    VOP_GETATTR(vp, &vattr, cnp->cn_td) == 0 &&
+	ncp = ap->a_ncp;		/* locked namecache node */
+	cred = ap->a_cred;
+
+	vp = ncp->nc_vp;
+		
+	KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0);
+
+	KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp);
+	dvp = ncp->nc_parent->nc_vp;
+	if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0)
+		return (error);
+
+	if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
+		vput(dvp);
+		return (EROFS);
+	}
+
+	if (vp->v_usecount == 0 || (VTONFS(vp)->n_sillyrename.s_ncp != NULL &&
+	    VOP_GETATTR(vp, &vattr, td) == 0 &&
 	    vattr.va_nlink > 1)) {
 		/*
 		 * throw away biocache buffers, mainly to avoid
 		 * unnecessary delayed writes later.
 		 */
-		error = nfs_vinvalbuf(vp, 0, cnp->cn_td, 1);
+		error = nfs_vinvalbuf(vp, 0, td, 1);
 		/* Do the rpc */
-		if (error != EINTR)
-			error = nfs_removerpc(dvp, cnp->cn_nameptr,
-				cnp->cn_namelen, cnp->cn_cred, cnp->cn_td);
-		/*
-		 * Kludge City: If the first reply to the remove rpc is lost..
-		 *   the reply to the retransmitted request will be ENOENT
-		 *   since the file was in fact removed
-		 *   Therefore, we cheat and return success.
-		 */
-		if (error == ENOENT)
-			error = 0;
-	} else if (!np->n_sillyrename) {
-		error = nfs_sillyrename(dvp, vp, cnp);
+		if (error != EINTR) {
+			error = nfs_removerpc(ncp, cred);
+			if (error == 0)
+				cache_setunresolved(ncp);			
+		}
+	} else if (VTONFS(vp)->n_sillyrename.s_ncp == NULL) {
+		error = nfs_sillyrename(ncp, cred);
 	}
-	np->n_attrstamp = 0;
+	/*
+	 * Kludge City: If the first reply to the remove rpc is lost..
+	 *   the reply to the retransmitted request will be ENOENT
+	 *   since the file was in fact removed
+	 *   Therefore, we cheat and return success.
+	 */
+	if (error == ENOENT && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM)
+		error = 0;
+	vput(dvp);
 	return (error);
 }
 
 /*
- * nfs file remove rpc called from nfs_inactive
+ * Nfs remove rpc, called from nfs_nremove() and nfs_inactive().
  */
 int
-nfs_removeit(struct sillyrename *sp)
-{
-	return (nfs_removerpc(sp->s_dvp, sp->s_name, sp->s_namlen,
-		sp->s_cred, NULL));
-}
-
-/*
- * Nfs remove rpc, called from nfs_remove() and nfs_removeit().
- */
-static int
-nfs_removerpc(struct vnode *dvp, const char *name, int namelen,
-	      struct ucred *cred, struct thread *td)
+nfs_removerpc(struct namecache *ncp, struct ucred *cred)
 {
+	struct thread *td = curthread;
+	struct vnode *dvp;
+	int wccflag = NFSV3_WCCRATTR;
+	int v3;
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
 	u_int32_t *tl;
-	caddr_t cp;
 	int32_t t1, t2;
-	caddr_t bpos, dpos, cp2;
-	int error = 0, wccflag = NFSV3_WCCRATTR;
-	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-	int v3 = NFS_ISV3(dvp);
+	int error = 0; /* set by nfsm_*, which may jump to nfsmout: */
 
+	dvp = ncp->nc_parent->nc_vp;	/* locked directory vnode */
+	
+	v3 = NFS_ISV3(dvp);
 	nfsstats.rpccnt[NFSPROC_REMOVE]++;
 	nfsm_reqhead(dvp, NFSPROC_REMOVE,
-		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(namelen));
+		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(ncp->nc_nlen));
 	nfsm_fhtom(dvp, v3);
-	nfsm_strtom(name, namelen, NFS_MAXNAMLEN);
+	nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN);
 	nfsm_request(dvp, NFSPROC_REMOVE, td, cred);
 	if (v3)
 		nfsm_wcc_data(dvp, wccflag);
@@ -1716,23 +1843,47 @@
 }
 
 /*
- * nfs file rename call
+ * nfs_nrename { struct namecache *a_fncp,
+ *		 struct namecache *a_tncp,
+ *		 struct ucred *a_cred }
  *
- * nfs_rename(struct vnode *a_fdvp, struct vnode *a_fvp,
- *	      struct componentname *a_fcnp, struct vnode *a_tdvp,
- *	      struct vnode *a_tvp, struct componentname *a_tcnp)
+ * nfs file rename call
  */
 static int
-nfs_rename(struct vop_old_rename_args *ap)
-{
-	struct vnode *fvp = ap->a_fvp;
-	struct vnode *tvp = ap->a_tvp;
-	struct vnode *fdvp = ap->a_fdvp;
-	struct vnode *tdvp = ap->a_tdvp;
-	struct componentname *tcnp = ap->a_tcnp;
-	struct componentname *fcnp = ap->a_fcnp;
+nfs_nrename(struct vop_nrename_args *ap)
+{
+	struct thread *td = curthread;
+	struct namecache *fncp, *tncp;
+	struct ucred *cred;
+	struct vnode *fdvp, *fvp, *tdvp, *tvp;
 	int error;
 
+	fncp = ap->a_fncp;
+	tncp = ap->a_tncp;
+	cred = ap->a_cred;
+
+	fvp = fncp->nc_vp;
+	tvp = tncp->nc_vp;
+
+	KKASSERT((fncp->nc_flag & NCF_MOUNTPT) == 0);
+	KKASSERT((tncp->nc_flag & NCF_MOUNTPT) == 0);
+
+	KKASSERT(fncp->nc_parent && fncp->nc_parent->nc_vp);
+	fdvp = fncp->nc_parent->nc_vp;
+	vref(fdvp);
+
+	KKASSERT(tncp->nc_parent && tncp->nc_parent->nc_vp);
+	tdvp = tncp->nc_parent->nc_vp;
+	if ((error = vget(tdvp, LK_EXCLUSIVE, td)) != 0) {
+		vrele(fdvp);
+		return (error);
+	}
+
+	if (fdvp->v_mount->mnt_flag & MNT_RDONLY) {
+		error = EROFS;
+		goto out;
+	}
+
 	/* Check for cross-device rename */
 	if ((fvp->v_mount != tdvp->v_mount) ||
 	    (tvp && (fvp->v_mount != tvp->v_mount))) {
@@ -1749,84 +1900,64 @@
 	 * often.
 	 */
 
-	VOP_FSYNC(fvp, MNT_WAIT, fcnp->cn_td);
-	if (tvp)
-	    VOP_FSYNC(tvp, MNT_WAIT, tcnp->cn_td);
+	VOP_FSYNC(fvp, MNT_WAIT, td);
+	if (tvp) {
+		VOP_FSYNC(tvp, MNT_WAIT, td);
 
-	/*
-	 * 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.
-	 *
-	 * We do not attempt to do any namecache purges in this old API
-	 * routine.  The new API compat functions have access to the actual
-	 * namecache structures and will do it for us.
-	 */
-	if (tvp && tvp->v_usecount > 1 && !VTONFS(tvp)->n_sillyrename &&
-		tvp->v_type != VDIR && !nfs_sillyrename(tdvp, tvp, tcnp)) {
-		vput(tvp);
-		tvp = NULL;
-	} else if (tvp) {
-		;
+		/*
+		 * If the tvp is in use, sillyrename it before doing the
+		 * rename of the new file over it.
+		 *
+		 * XXX Can't sillyrename a directory.
+		 */
+		if (tvp->v_usecount > 0 && tvp->v_type != VDIR)
+			error = nfs_sillyrename(tncp, cred);
 	}
 
-	error = nfs_renamerpc(fdvp, fcnp->cn_nameptr, fcnp->cn_namelen,
-		tdvp, tcnp->cn_nameptr, tcnp->cn_namelen, tcnp->cn_cred,
-		tcnp->cn_td);
+	if (error == 0)
+		error = nfs_renamerpc(fncp, tncp, cred);
 
-out:
-	if (tdvp == tvp)
-		vrele(tdvp);
-	else
-		vput(tdvp);
-	if (tvp)
-		vput(tvp);
-	vrele(fdvp);
-	vrele(fvp);
 	/*
 	 * Kludge: Map ENOENT => 0 assuming that it is a reply to a retry.
 	 */
-	if (error == ENOENT)
+	if (error == ENOENT && VFSTONFS(tvp->v_mount)->nm_sotype == SOCK_DGRAM)
 		error = 0;
+out:
+	vput(tdvp);
+	vrele(fdvp);
 	return (error);
 }
 
 /*
- * nfs file rename rpc called from nfs_remove() above
- */
-static int
-nfs_renameit(struct vnode *sdvp, struct componentname *scnp,
-	     struct sillyrename *sp)
-{
-	return (nfs_renamerpc(sdvp, scnp->cn_nameptr, scnp->cn_namelen,
-		sdvp, sp->s_name, sp->s_namlen, scnp->cn_cred, scnp->cn_td));
-}
-
-/*
- * Do an nfs rename rpc. Called from nfs_rename() and nfs_renameit().
+ * Do an nfs rename rpc. Called from nfs_nrename() and nfs_inactive().
  */
 static int
-nfs_renamerpc(struct vnode *fdvp, const char *fnameptr, int fnamelen,
-	      struct vnode *tdvp, const char *tnameptr, int tnamelen,
-	      struct ucred *cred, struct thread *td)
+nfs_renamerpc(struct namecache *fncp, struct namecache *tncp,
+	      struct ucred *cred)
 {
+	struct thread *td = curthread;
+	struct vnode *fdvp, *tdvp, *vp;
+	int fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
+	int v3;
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
 	u_int32_t *tl;
-	caddr_t cp;
 	int32_t t1, t2;
-	caddr_t bpos, dpos, cp2;
-	int error = 0, fwccflag = NFSV3_WCCRATTR, twccflag = NFSV3_WCCRATTR;
-	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-	int v3 = NFS_ISV3(fdvp);
+	int error = 0; /* set by nfsm_*, which may jump to nfsmout: */
+
+	fdvp = fncp->nc_parent->nc_vp;	/* locked source directory vnode */
+	tdvp = tncp->nc_parent->nc_vp;	/* locked target directory vnode */
 
+	v3 = NFS_ISV3(fdvp);
 	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(fncp->nc_nlen) +
+		nfsm_rndup(tncp->nc_nlen));
 	nfsm_fhtom(fdvp, v3);
-	nfsm_strtom(fnameptr, fnamelen, NFS_MAXNAMLEN);
+	nfsm_strtom(fncp->nc_name, fncp->nc_nlen, NFS_MAXNAMLEN);
 	nfsm_fhtom(tdvp, v3);
-	nfsm_strtom(tnameptr, tnamelen, NFS_MAXNAMLEN);
+	nfsm_strtom(tncp->nc_name, tncp->nc_nlen, NFS_MAXNAMLEN);
 	nfsm_request(fdvp, NFSPROC_RENAME, td, cred);
 	if (v3) {
 		nfsm_wcc_data(fdvp, fwccflag);
@@ -1840,30 +1971,56 @@
 		VTONFS(fdvp)->n_attrstamp = 0;
 	if (!twccflag)
 		VTONFS(tdvp)->n_attrstamp = 0;
+	if (error == 0) {
+		vp = fncp->nc_vp;
+		vref(vp);
+		cache_rename(fncp, tncp);
+		cache_setvp(tncp, vp);
+		vrele(vp);
+	}
 	return (error);
 }
 
 /*
+ * nfs_nlink { struct namecache *a_ncp,
+ *	       struct vnode *a_vp,
+ *	       struct ucred *a_cred }
+ *
  * nfs hard link create call
  *
- * nfs_link(struct vnode *a_tdvp, struct vnode *a_vp,
- *	    struct componentname *a_cnp)
+ * The passed vp is locked and represents the source.
+ * The passed ncp is locked and represents the target to create.
  */
 static int
-nfs_link(struct vop_old_link_args *ap)
+nfs_nlink(struct vop_nlink_args *ap)
 {
+	struct thread *td = curthread;
+	struct namecache *ncp;
+	struct vnode *dvp;
 	struct vnode *vp = ap->a_vp;
-	struct vnode *tdvp = ap->a_tdvp;
-	struct componentname *cnp = ap->a_cnp;
+	struct ucred *cred = ap->a_cred;
+	int wccflag = NFSV3_WCCRATTR, attrflag = 0;
+	int v3;
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
 	u_int32_t *tl;
-	caddr_t cp;
 	int32_t t1, t2;
-	caddr_t bpos, dpos, cp2;
-	int error = 0, wccflag = NFSV3_WCCRATTR, attrflag = 0;
-	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-	int v3;
+	int error; /* set by nfsm_*, which may jump to nfsmout: */
 
-	if (vp->v_mount != tdvp->v_mount) {
+	ncp = ap->a_ncp;		/* locked namecache node */
+
+	KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp);
+	dvp = ncp->nc_parent->nc_vp;
+	if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0)
+		return (error);
+
+	if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
+		vput(dvp);
+		return (EROFS);
+	}
+	if (vp->v_mount != dvp->v_mount) {
+		vput(dvp);
 		return (EXDEV);
 	}
 
@@ -1872,64 +2029,92 @@
 	 * doesn't get "out of sync" with the server.
 	 * XXX There should be a better way!
 	 */
-	VOP_FSYNC(vp, MNT_WAIT, cnp->cn_td);
+	VOP_FSYNC(vp, MNT_WAIT, td);
 
 	v3 = NFS_ISV3(vp);
 	nfsstats.rpccnt[NFSPROC_LINK]++;
 	nfsm_reqhead(vp, NFSPROC_LINK,
-		NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
+		NFSX_FH(v3)*2 + NFSX_UNSIGNED + nfsm_rndup(ncp->nc_nlen));
 	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_td, cnp->cn_cred);
+	nfsm_fhtom(dvp, v3);
+	nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN);
+	nfsm_request(vp, NFSPROC_LINK, td, cred);
 	if (v3) {
 		nfsm_postop_attr(vp, attrflag, NFS_LATTR_NOSHRINK);
-		nfsm_wcc_data(tdvp, wccflag);
+		nfsm_wcc_data(dvp, wccflag);
 	}
 	m_freem(mrep);
 nfsmout:
-	VTONFS(tdvp)->n_flag |= NLMODIFIED;
+	VTONFS(dvp)->n_flag |= NLMODIFIED;
 	if (!attrflag)
 		VTONFS(vp)->n_attrstamp = 0;
 	if (!wccflag)
-		VTONFS(tdvp)->n_attrstamp = 0;
+		VTONFS(dvp)->n_attrstamp = 0;
 	/*
 	 * Kludge: Map EEXIST => 0 assuming that it is a reply to a retry.
 	 */
-	if (error == EEXIST)
+	if (error == EEXIST && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM)
 		error = 0;
+	if (error == 0) {
+		cache_setunresolved(ncp);
+		cache_setvp(ncp, vp);
+	}
+	vput(dvp);
 	return (error);
 }
 
 /*
+ * nfs_nsymlink { struct namecache *a_ncp,
+ *		  struct vnode **a_vpp,
+ *		  struct ucred *a_cred,
+ *		  struct vattr *a_vap,
+ *		  char *a_target }
+ *
  * nfs symbolic link create call
  *
- * nfs_symlink(struct vnode *a_dvp, struct vnode **a_vpp,
- *		struct componentname *a_cnp, struct vattr *a_vap,
- *		char *a_target)
+ * The passed ncp is locked and represents the symlink to create, while
+ * a_target represents the target of the symlink.  On success, the vnode of
+ * the new symlink is returned in a_vpp; NULL on failure.
  */
 static int
-nfs_symlink(struct vop_old_symlink_args *ap)
+nfs_nsymlink(struct vop_nsymlink_args *ap)
 {
-	struct vnode *dvp = ap->a_dvp;
+	struct thread *td = curthread;
+	struct namecache *ncp;
+	struct vnode *dvp;
+	struct ucred *cred = ap->a_cred;
 	struct vattr *vap = ap->a_vap;
-	struct componentname *cnp = ap->a_cnp;
 	struct nfsv2_sattr *sp;
+	int slen, wccflag = NFSV3_WCCRATTR, gotvp = 0;
+	struct vnode *newvp = NULL;
+	int v3;
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
 	u_int32_t *tl;
-	caddr_t cp;
 	int32_t t1, t2;
-	caddr_t bpos, dpos, cp2;
-	int slen, error = 0, wccflag = NFSV3_WCCRATTR, gotvp;
-	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-	struct vnode *newvp = (struct vnode *)0;
-	int v3 = NFS_ISV3(dvp);
+	int error; /* set by nfsm_*, which may jump to nfsmout: */
 
+	*ap->a_vpp = NULL;
+	ncp = ap->a_ncp;		/* locked namecache node */
+
+	KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp);
+	dvp = ncp->nc_parent->nc_vp;
+	if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0)
+		return(error);
+
+	if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
+		vput(dvp);
+		return(EROFS);
+	}
+
+	v3 = NFS_ISV3(dvp);
 	nfsstats.rpccnt[NFSPROC_SYMLINK]++;
 	slen = strlen(ap->a_target);
 	nfsm_reqhead(dvp, NFSPROC_SYMLINK, NFSX_FH(v3) + 2*NFSX_UNSIGNED +
-	    nfsm_rndup(cnp->cn_namelen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
+	    nfsm_rndup(ncp->nc_nlen) + nfsm_rndup(slen) + NFSX_SATTR(v3));
 	nfsm_fhtom(dvp, v3);
-	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
+	nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN);
 	if (v3) {
 		nfsm_v3attrbuild(vap, FALSE);
 	}
@@ -1951,7 +2136,7 @@
 	 * a file handle that can be converted into newvp without having
 	 * to do an extra lookup rpc.
 	 */
-	nfsm_request(dvp, NFSPROC_SYMLINK, cnp->cn_td, cnp->cn_cred);
+	nfsm_request(dvp, NFSPROC_SYMLINK, td, cred);
 	if (v3) {
 		if (error == 0)
 			nfsm_mtofh(dvp, newvp, v3, gotvp);
@@ -1969,7 +2154,7 @@
 	 * If we get an EEXIST error, silently convert it to no-error
 	 * in case of an NFS retry.
 	 */
-	if (error == EEXIST)
+	if (error == EEXIST && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM)
 		error = 0;
 
 	/*
@@ -1981,58 +2166,81 @@
 	if (error == 0 && newvp == NULL) {
 		struct nfsnode *np = NULL;
 
-		error = nfs_lookitup(dvp, cnp->cn_nameptr, cnp->cn_namelen,
-		    cnp->cn_cred, cnp->cn_td, &np);
-		if (!error)
+		error = nfs_lookitup(dvp, ncp->nc_name, ncp->nc_nlen,
+		    cred, td, &np);
+		if (error == 0)
 			newvp = NFSTOV(np);
 	}
 	if (error) {
 		if (newvp)
 			vput(newvp);
 	} else {
-		*ap->a_vpp = newvp;
+		cache_setunresolved(ncp);
+		cache_setvp(ncp, newvp);
+		*ap->a_vpp = newvp;	/* referenced locked vnode */
 	}
 	VTONFS(dvp)->n_flag |= NLMODIFIED;
 	if (!wccflag)
 		VTONFS(dvp)->n_attrstamp = 0;
+	vput(dvp);
 	return (error);
 }
 
 /*
- * nfs make dir call
+ * nfs_nmkdir { struct namecache *a_ncp,
+ *		struct vnode **a_vpp,
+ *		struct ucred *a_cred,
+ *		struct vattr *a_vap }
  *
- * nfs_mkdir(struct vnode *a_dvp, struct vnode **a_vpp,
- *	     struct componentname *a_cnp, struct vattr *a_vap)
+ * nfs make dir call
  */
 static int
-nfs_mkdir(struct vop_old_mkdir_args *ap)
+nfs_nmkdir(struct vop_nmkdir_args *ap)
 {
-	struct vnode *dvp = ap->a_dvp;
+	struct thread *td = curthread;
+	struct namecache *ncp;
+	struct vnode *dvp;
+	struct ucred *cred = ap->a_cred;
 	struct vattr *vap = ap->a_vap;
-	struct componentname *cnp = ap->a_cnp;
 	struct nfsv2_sattr *sp;
-	u_int32_t *tl;
-	caddr_t cp;
-	int32_t t1, t2;
 	int len;
-	struct nfsnode *np = (struct nfsnode *)0;
-	struct vnode *newvp = (struct vnode *)0;
-	caddr_t bpos, dpos, cp2;
-	int error = 0, wccflag = NFSV3_WCCRATTR;
-	int gotvp = 0;
-	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
+	struct nfsnode *np = NULL;
+	struct vnode *newvp = NULL;
+	int gotvp = 0, wccflag = NFSV3_WCCRATTR;
 	struct vattr vattr;
-	int v3 = NFS_ISV3(dvp);
+	int v3;
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
+	u_int32_t *tl;
+	int32_t t1, t2;
+	int error; /* set by nfsm_*, which may jump to nfsmout: */
+
+	*ap->a_vpp = NULL;
+	ncp = ap->a_ncp;		/* locked namecache node */
 
-	if ((error = VOP_GETATTR(dvp, &vattr, cnp->cn_td)) != 0) {
+	KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp);	
+	dvp = ncp->nc_parent->nc_vp;
+	if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0)
+		return(error);
+
+	if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
+		vput(dvp);
+		return(EROFS);
+	}
+
+	if ((error = VOP_GETATTR(dvp, &vattr, td)) != 0) {
+		vput(dvp);
 		return (error);
 	}
-	len = cnp->cn_namelen;
+
+	len = ncp->nc_nlen;
+	v3 = NFS_ISV3(dvp);
 	nfsstats.rpccnt[NFSPROC_MKDIR]++;
 	nfsm_reqhead(dvp, NFSPROC_MKDIR,
-	  NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
+	    NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(len) + NFSX_SATTR(v3));
 	nfsm_fhtom(dvp, v3);
-	nfsm_strtom(cnp->cn_nameptr, len, NFS_MAXNAMLEN);
+	nfsm_strtom(ncp->nc_name, len, NFS_MAXNAMLEN);
 	if (v3) {
 		nfsm_v3attrbuild(vap, FALSE);
 	} else {
@@ -2044,8 +2252,8 @@
 		txdr_nfsv2time(&vap->va_atime, &sp->sa_atime);
 		txdr_nfsv2time(&vap->va_mtime, &sp->sa_mtime);
 	}
-	nfsm_request(dvp, NFSPROC_MKDIR, cnp->cn_td, cnp->cn_cred);
-	if (!error)
+	nfsm_request(dvp, NFSPROC_MKDIR, td, cred);
+	if (error == 0)
 		nfsm_mtofh(dvp, newvp, v3, gotvp);
 	if (v3)
 		nfsm_wcc_data(dvp, wccflag);
@@ -2058,14 +2266,15 @@
 	 * Kludge: Map EEXIST => 0 assuming that you have a reply to a retry
 	 * if we can succeed in looking up the directory.
 	 */
-	if (error == EEXIST || (!error && !gotvp)) {
+	if (error == EEXIST && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM)
+		error = 0;
+	if (error == 0 && gotvp == 0) {
 		if (newvp) {
-			vrele(newvp);
-			newvp = (struct vnode *)0;
+			vput(newvp);
+			newvp = NULL;
 		}
-		error = nfs_lookitup(dvp, cnp->cn_nameptr, len, cnp->cn_cred,
-			cnp->cn_td, &np);
-		if (!error) {
+		error = nfs_lookitup(dvp, ncp->nc_name, len, cred, td, &np);
+		if (error == 0) {
 			newvp = NFSTOV(np);
 			if (newvp->v_type != VDIR)
 				error = EEXIST;
@@ -2073,40 +2282,60 @@
 	}
 	if (error) {
 		if (newvp)
-			vrele(newvp);
-	} else
-		*ap->a_vpp = newvp;
+			vput(newvp);
+	} else {
+		cache_setunresolved(ncp);
+		cache_setvp(ncp, newvp);
+		*ap->a_vpp = newvp;	/* referenced locked vnode */
+	}
+	vput(dvp);
 	return (error);
 }
 
 /*
- * nfs remove directory call
+ * nfs_nrmdir { struct namecache *a_ncp,
+ *		struct ucred *a_cred }
  *
- * nfs_rmdir(struct vnode *a_dvp, struct vnode *a_vp,
- *	     struct componentname *a_cnp)
+ * nfs remove directory call
  */
 static int
-nfs_rmdir(struct vop_old_rmdir_args *ap)
+nfs_nrmdir(struct vop_nrmdir_args *ap)
 {
-	struct vnode *vp = ap->a_vp;
-	struct vnode *dvp = ap->a_dvp;
-	struct componentname *cnp = ap->a_cnp;
+	struct thread *td = curthread;
+	struct namecache *ncp;
+	struct vnode *dvp;
+	struct ucred *cred = ap->a_cred;
+	int wccflag = NFSV3_WCCRATTR;
+	int v3;
+	/******NFSM MACROS********/
+	struct mbuf *mb, *mrep, *mreq, *mb2, *md;
+	caddr_t bpos, dpos, cp, cp2;
 	u_int32_t *tl;
-	caddr_t cp;
 	int32_t t1, t2;
-	caddr_t bpos, dpos, cp2;
-	int error = 0, wccflag = NFSV3_WCCRATTR;
-	struct mbuf *mreq, *mrep, *md, *mb, *mb2;
-	int v3 = NFS_ISV3(dvp);
+	int error; /* set by nfsm_*, which may jump to nfsmout: */
 
-	if (dvp == vp)
-		return (EINVAL);
+	ncp = ap->a_ncp;		/* locked namecache node */
+
+	KKASSERT((ncp->nc_flag & NCF_MOUNTPT) == 0);
+
+	KKASSERT(ncp->nc_parent && ncp->nc_parent->nc_vp);
+	dvp = ncp->nc_parent->nc_vp;
+
+	if ((error = vget(dvp, LK_EXCLUSIVE, td)) != 0)
+		return (error);
+
+	if (dvp->v_mount->mnt_flag & MNT_RDONLY) {
+		vput(dvp);
+		return (EROFS);
+	}
+
+	v3 = NFS_ISV3(dvp);
 	nfsstats.rpccnt[NFSPROC_RMDIR]++;
 	nfsm_reqhead(dvp, NFSPROC_RMDIR,
-		NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(cnp->cn_namelen));
+	    NFSX_FH(v3) + NFSX_UNSIGNED + nfsm_rndup(ncp->nc_nlen));
 	nfsm_fhtom(dvp, v3);
-	nfsm_strtom(cnp->cn_nameptr, cnp->cn_namelen, NFS_MAXNAMLEN);
-	nfsm_request(dvp, NFSPROC_RMDIR, cnp->cn_td, cnp->cn_cred);
+	nfsm_strtom(ncp->nc_name, ncp->nc_nlen, NFS_MAXNAMLEN);
+	nfsm_request(dvp, NFSPROC_RMDIR, td, cred);
 	if (v3)
 		nfsm_wcc_data(dvp, wccflag);
 	m_freem(mrep);
@@ -2117,8 +2346,11 @@
 	/*
 	 * Kludge: Map ENOENT => 0 assuming that you have a reply to a retry.
 	 */
-	if (error == ENOENT)
+	if (error == ENOENT && VFSTONFS(dvp->v_mount)->nm_sotype == SOCK_DGRAM)
 		error = 0;
+	if (error == 0)
+		cache_inval(ncp, CINV_DESTROY);
+	vput(dvp);
 	return (error);
 }
 
@@ -2659,52 +2891,53 @@
  * nfs_rename() completes, but...
  */
 static int
-nfs_sillyrename(struct vnode *dvp, struct vnode *vp, struct componentname *cnp)
+nfs_sillyrename(struct namecache *ncp, struct ucred *cred)
 {
-	struct sillyrename *sp;
+	struct thread *td = curthread;
+	struct nlcomponent snlc;
+	struct namecache *sncp;
+	struct vnode *vp, *dvp;
 	struct nfsnode *np;
+	struct sillyrename *sp;
+	char sname[20];
 	int error;
 
-	/*
-	 * We previously purged dvp instead of vp.  I don't know why, it
-	 * completely destroys performance.  We can't do it anyway with the
-	 * new VFS API since we would be breaking the namecache topology.
-	 */
-	cache_purge(vp);	/* XXX */
-	np = VTONFS(vp);
+	vp = ncp->nc_vp;
 #ifndef DIAGNOSTIC
 	if (vp->v_type == VDIR)
 		panic("nfs: sillyrename dir");
 #endif
-	MALLOC(sp, struct sillyrename *, sizeof (struct sillyrename),
-		M_NFSREQ, M_WAITOK);
-	sp->s_cred = crdup(cnp->cn_cred);
-	sp->s_dvp = dvp;
-	vref(dvp);
 
 	/* Fudge together a funny name */
-	sp->s_namlen = sprintf(sp->s_name, ".nfsA%08x4.4", (int)cnp->cn_td);
+	snlc.nlc_namelen = sprintf(sname, ".nfsA%08x4.4", (int)td);
+	snlc.nlc_nameptr = sname;
+	for (;;) {
+		sncp = cache_nlookup(ncp->nc_parent, &snlc);
+		error = cache_resolve(sncp, cred);
+		if (error == ENOENT)
+			break;
+		cache_put(sncp);
+		if (++sname[4] > 'z')
+			return (EINVAL); /* XXX remove the file instead? */
+	}
 
-	/* Try lookitups until we get one that isn't there */
-	while (nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
-		cnp->cn_td, (struct nfsnode **)0) == 0) {
-		sp->s_name[4]++;
-		if (sp->s_name[4] > 'z') {
-			error = EINVAL;
-			goto bad;
+	error = nfs_renamerpc(ncp, sncp, cred);
+	if (error == 0) {
+		dvp = ncp->nc_parent->nc_vp;	/* locked directory vnode */
+		np = VTONFS(vp);
+
+		error = nfs_lookitup(dvp, sncp->nc_name, sncp->nc_nlen, cred,
+				     td, &np);
+		if (error == 0) {
+			sp = &(VTONFS(vp)->n_sillyrename);
+			sp->s_ncp = sncp;
+			sp->s_cred = crdup(cred);
+			cache_unlock(sncp);
+			return (error);
 		}
 	}
-	error = nfs_renameit(dvp, cnp, sp);
-	if (error)
-		goto bad;
-	error = nfs_lookitup(dvp, sp->s_name, sp->s_namlen, sp->s_cred,
-		cnp->cn_td, &np);
-	np->n_sillyrename = sp;
-	return (0);
-bad:
-	vrele(sp->s_dvp);
-	crfree(sp->s_cred);
-	free((caddr_t)sp, M_NFSREQ);
+	cache_setunresolved(sncp);
+	cache_put(sncp);
 	return (error);
 }
 
diff -ur nfs.orig/nfsnode.h nfs/nfsnode.h
--- nfs.orig/nfsnode.h	2006-04-03 12:20:15.000000000 -0500
+++ nfs/nfsnode.h	2006-04-03 13:18:49.000000000 -0500
@@ -53,12 +53,11 @@
  * can be removed by nfs_inactive()
  */
 struct sillyrename {
-	struct	ucred *s_cred;
-	struct	vnode *s_dvp;
-	long	s_namlen;
-	char	s_name[20];
+	struct  namecache *s_ncp;
+	struct  ucred *s_cred;
 };
 
+
 /*
  * Entries of directories in the buffer cache.
  */
@@ -134,7 +133,7 @@
 		off_t		nd_direof;	/* Dir. EOF offset cache */
 	} n_un2;
 	union {
-		struct sillyrename *nf_silly;	/* Ptr to silly rename struct */
+		struct sillyrename nf_silly;	/* silly rename struct */
 		LIST_HEAD(, nfsdmap) nd_cook;	/* cookies */
 	} n_un3;
 	short			n_fhsize;	/* size in bytes, of fh */
@@ -232,7 +231,7 @@
 int	nfs_flush (struct vnode *, int, struct thread *, int);
 
 /* other stuff */
-int	nfs_removeit (struct sillyrename *);
+int	nfs_removerpc (struct namecache *ncp, struct ucred *cred);
 int	nfs_nget (struct mount *,nfsfh_t *,int,struct nfsnode **);
 nfsuint64 *nfs_getcookie (struct nfsnode *, off_t, int);
 void	nfs_invaldir (struct vnode *);
