diff --git a/sys/vfs/tmpfs/tmpfs.h b/sys/vfs/tmpfs/tmpfs.h
index 7e8a7e6..2a4d76e 100644
--- a/sys/vfs/tmpfs/tmpfs.h
+++ b/sys/vfs/tmpfs/tmpfs.h
@@ -63,6 +63,10 @@ MALLOC_DECLARE(M_TMPFSMNT);
  */
 struct tmpfs_dirent {
 	TAILQ_ENTRY(tmpfs_dirent)	td_entries;
+	TAILQ_ENTRY(tmpfs_dirent)	td_hash;
+	int				td_hashq;
+	int				td_namelenq;
+	char				*td_hashname;
 
 	/* Length of the name stored in this directory entry.  This avoids
 	 * the need to recalculate it every time the name is used. */
@@ -91,6 +95,17 @@ struct tmpfs_dirent {
  * importantly, to remove redundancy. */
 TAILQ_HEAD(tmpfs_dir, tmpfs_dirent);
 
+#define TH_HASH			(64)
+
+struct tmpfs_hdir {
+	/* Head of a tail-queue that links the contents of
+	 * the directory together.  See above for a
+	 * description of its contents. */
+	struct tmpfs_dir	th_dirhead;
+
+	struct tmpfs_dir	th_hash[TH_HASH];
+};
+
 /* Each entry in a directory has a cookie that identifies it.  Cookies
  * supersede offsets within directories because, given how tmpfs stores
  * directories in memory, there is no such thing as an offset.  (Emulating
@@ -252,10 +267,7 @@ struct tmpfs_node {
 			 * this property identifies the root node. */
 			struct tmpfs_node *	tn_parent;
 
-			/* Head of a tail-queue that links the contents of
-			 * the directory together.  See above for a
-			 * description of its contents. */
-			struct tmpfs_dir	tn_dirhead;
+			struct tmpfs_hdir	tn_hdirhead;
 
 			/* Number and pointer of the first directory entry
 			 * returned by the readdir operation if it were
diff --git a/sys/vfs/tmpfs/tmpfs_subr.c b/sys/vfs/tmpfs/tmpfs_subr.c
index 14e70b9..9c77220 100644
--- a/sys/vfs/tmpfs/tmpfs_subr.c
+++ b/sys/vfs/tmpfs/tmpfs_subr.c
@@ -1,5 +1,7 @@
 /*	$NetBSD: tmpfs_subr.c,v 1.35 2007/07/09 21:10:50 ad Exp $	*/
 
+#include <string.h>
+#include <stdlib.h>
 /*-
  * Copyright (c) 2005 The NetBSD Foundation, Inc.
  * All rights reserved.
@@ -44,6 +46,7 @@
 #include <sys/systm.h>
 #include <sys/vnode.h>
 #include <sys/vmmeter.h>
+#include <sys/fnv_hash.h>
 
 #include <vm/vm.h>
 #include <vm/vm_object.h>
@@ -55,6 +58,21 @@
 #include <vfs/tmpfs/tmpfs_vnops.h>
 
 static ino_t tmpfs_fetch_ino(struct tmpfs_mount *);
+int tmpfs_dirhash(char *, uint16_t);
+/* --------------------------------------------------------------------- */
+int
+tmpfs_dirhash(char *name, uint16_t namelen)
+{
+	uint32_t hash;
+	char *c;
+	int len;
+
+	c = index(name, '\0');
+	len = min(namelen, c - name);
+	hash = fnv_32_buf(name, len, FNV1_32_INIT);
+
+	return (hash & (TH_HASH - 1));
+}
 
 /* --------------------------------------------------------------------- */
 
@@ -88,6 +106,7 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type,
 	struct tmpfs_node *nnode;
 	struct timespec ts;
 	udev_t rdev;
+	int i;
 
 	/* If the root directory of the 'tmp' file system is not yet
 	 * allocated, this must be the request to do it. */
@@ -129,7 +148,10 @@ tmpfs_alloc_node(struct tmpfs_mount *tmp, enum vtype type,
 		break;
 
 	case VDIR:
-		TAILQ_INIT(&nnode->tn_dir.tn_dirhead);
+		TAILQ_INIT(&nnode->tn_dir.tn_hdirhead.th_dirhead);
+		for (i = 0; i < TH_HASH; i++)
+			TAILQ_INIT(&nnode->tn_dir.tn_hdirhead.th_hash[i]);
+
 		KKASSERT(parent != nnode);
 		KKASSERT(IMPLIES(parent == NULL, tmp->tm_root == NULL));
 		nnode->tn_dir.tn_parent = parent;
@@ -327,6 +349,8 @@ tmpfs_alloc_dirent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
 	bcopy(name, nde->td_name, len);
 	nde->td_name[len] = '\0';
 
+	nde->td_namelenq = -1;
+	nde->td_hashq = -65;
 	nde->td_node = node;
 
 	TMPFS_NODE_LOCK(node);
@@ -593,6 +617,7 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
 	 * insert the new node into the directory, an operation that
 	 * cannot fail. */
 	tmpfs_dir_attach(dnode, de);
+	KKASSERT(de->td_hashq == tmpfs_dirhash(de->td_name, de->td_namelen));
 	TMPFS_NODE_UNLOCK(node);
 
 	return error;
@@ -608,8 +633,17 @@ tmpfs_alloc_file(struct vnode *dvp, struct vnode **vpp, struct vattr *vap,
 void
 tmpfs_dir_attach(struct tmpfs_node *dnode, struct tmpfs_dirent *de)
 {
+	int i;
+
 	TMPFS_NODE_LOCK(dnode);
-	TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_dirhead, de, td_entries);
+
+	i = tmpfs_dirhash(de->td_name, de->td_namelen);
+
+	TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_hdirhead.th_dirhead, de, td_entries);
+	TAILQ_INSERT_TAIL(&dnode->tn_dir.tn_hdirhead.th_hash[i], de, td_hash);
+	de->td_hashq = i;
+	de->td_hashname = strndup(de->td_name, de->td_namelen);
+	de->td_namelenq = de->td_namelen;
 
 	TMPFS_ASSERT_ELOCKED(dnode);
 	dnode->tn_size += sizeof(struct tmpfs_dirent);
@@ -628,12 +662,20 @@ tmpfs_dir_attach(struct tmpfs_node *dnode, struct tmpfs_dirent *de)
 void
 tmpfs_dir_detach(struct tmpfs_node *dnode, struct tmpfs_dirent *de)
 {
+	int i;
+
 	TMPFS_NODE_LOCK(dnode);
+
+	i = tmpfs_dirhash(de->td_name, de->td_namelen);
+
 	if (dnode->tn_dir.tn_readdir_lastp == de) {
 		dnode->tn_dir.tn_readdir_lastn = 0;
 		dnode->tn_dir.tn_readdir_lastp = NULL;
 	}
-	TAILQ_REMOVE(&dnode->tn_dir.tn_dirhead, de, td_entries);
+	TAILQ_REMOVE(&dnode->tn_dir.tn_hdirhead.th_dirhead, de, td_entries);
+	TAILQ_REMOVE(&dnode->tn_dir.tn_hdirhead.th_hash[i], de, td_hash);
+	de->td_hashq = -i;
+	de->td_namelenq = -2;
 
 	TMPFS_ASSERT_ELOCKED(dnode);
 	dnode->tn_size -= sizeof(struct tmpfs_dirent);
@@ -654,16 +696,19 @@ tmpfs_dir_detach(struct tmpfs_node *dnode, struct tmpfs_dirent *de)
  */
 struct tmpfs_dirent *
 tmpfs_dir_lookup(struct tmpfs_node *node, struct tmpfs_node *f,
-    struct namecache *ncp)
+		 struct namecache *ncp)
 {
 	struct tmpfs_dirent *de;
 	int len = ncp->nc_nlen;
+	int i;
 
 	TMPFS_VALIDATE_DIR(node);
 
-	TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) {
-		if (f != NULL && de->td_node != f)
-		    continue;
+	i = tmpfs_dirhash(ncp->nc_name, len);
+
+	TAILQ_FOREACH(de, &node->tn_dir.tn_hdirhead.th_hash[i], td_hash) {
+		if (f != NULL && de->td_node != f) 
+			continue;
 		if (len == de->td_namelen) {
 			if (!memcmp(ncp->nc_name, de->td_name, len))
 				break;
@@ -760,7 +805,7 @@ tmpfs_dir_getdotdotdent(struct tmpfs_mount *tmp, struct tmpfs_node *node,
 		if (error == 0) {
 			struct tmpfs_dirent *de;
 
-			de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
+			de = TAILQ_FIRST(&node->tn_dir.tn_hdirhead.th_dirhead);
 			if (de == NULL)
 				uio->uio_offset = TMPFS_DIRCOOKIE_EOF;
 			else
@@ -790,7 +835,7 @@ tmpfs_dir_lookupbycookie(struct tmpfs_node *node, off_t cookie)
 		return node->tn_dir.tn_readdir_lastp;
 	}
 
-	TAILQ_FOREACH(de, &node->tn_dir.tn_dirhead, td_entries) {
+	TAILQ_FOREACH(de, &node->tn_dir.tn_hdirhead.th_dirhead, td_entries) {
 		if (tmpfs_dircookie(de) == cookie) {
 			break;
 		}
diff --git a/sys/vfs/tmpfs/tmpfs_vfsops.c b/sys/vfs/tmpfs/tmpfs_vfsops.c
index 4aa5eb1..6090b56 100644
--- a/sys/vfs/tmpfs/tmpfs_vfsops.c
+++ b/sys/vfs/tmpfs/tmpfs_vfsops.c
@@ -351,8 +351,8 @@ tmpfs_unmount(struct mount *mp, int mntflags)
 		if (node->tn_type == VDIR) {
 			struct tmpfs_dirent *de;
 
-			while (!TAILQ_EMPTY(&node->tn_dir.tn_dirhead)) {
-				de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
+			while (!TAILQ_EMPTY(&node->tn_dir.tn_hdirhead.th_dirhead)) {
+				de = TAILQ_FIRST(&node->tn_dir.tn_hdirhead.th_dirhead);
 				tmpfs_dir_detach(node, de);
 				tmpfs_free_dirent(tmp, de);
 				node->tn_size -= sizeof(struct tmpfs_dirent);
diff --git a/sys/vfs/tmpfs/tmpfs_vnops.c b/sys/vfs/tmpfs/tmpfs_vnops.c
index 990a1ce..4bf5894 100644
--- a/sys/vfs/tmpfs/tmpfs_vnops.c
+++ b/sys/vfs/tmpfs/tmpfs_vnops.c
@@ -66,6 +66,7 @@ MALLOC_DECLARE(M_TMPFS);
 
 static void tmpfs_strategy_done(struct bio *bio);
 
+		extern int tmpfs_dirhash(char *, uint16_t);
 static __inline
 void
 tmpfs_knote(struct vnode *vp, int flags)
@@ -895,6 +896,7 @@ tmpfs_nlink(struct vop_nlink_args *v)
 
 	/* Insert the new directory entry into the appropriate directory. */
 	tmpfs_dir_attach(dnode, de);
+        KKASSERT(de->td_hashq == tmpfs_dirhash(de->td_name, de->td_namelen));
 
 	/* vp link count has changed, so update node times. */
 
@@ -1039,17 +1041,17 @@ tmpfs_nrename(struct vop_nrename_args *v)
 	 */
 	if (fdnode != tdnode)
 		tmpfs_dir_detach(fdnode, de);
+	else {
+		int i = tmpfs_dirhash(de->td_name, de->td_namelen);
+		TAILQ_REMOVE(&fdnode->tn_dir.tn_hdirhead.th_hash[i], de, 
+			     td_hash);
+	}
 
 	/*
 	 * Handle any name change.  Swap with newname, we will
 	 * deallocate it at the end.
 	 */
 	if (newname != NULL) {
-#if 0
-		TMPFS_NODE_LOCK(fnode);
-		fnode->tn_status |= TMPFS_NODE_CHANGED;
-		TMPFS_NODE_UNLOCK(fnode);
-#endif
 		oldname = de->td_name;
 		de->td_name = newname;
 		de->td_namelen = (uint16_t)tncp->nc_nlen;
@@ -1082,9 +1084,13 @@ tmpfs_nrename(struct vop_nrename_args *v)
 		}
 		tmpfs_dir_attach(tdnode, de);
 	} else {
+		int i = tmpfs_dirhash(de->td_name, de->td_namelen);
 		TMPFS_NODE_LOCK(tdnode);
 		tdnode->tn_status |= TMPFS_NODE_MODIFIED;
 		TMPFS_NODE_UNLOCK(tdnode);
+		TAILQ_INSERT_TAIL(&tdnode->tn_dir.tn_hdirhead.th_hash[i], de, 
+				  td_hash);
+
 	}
 
 	/*
@@ -1213,6 +1219,27 @@ tmpfs_nrmdir(struct vop_nrmdir_args *v)
 	/* Get the directory entry associated with node (vp).  This was
 	 * filled by tmpfs_lookup while looking up the entry. */
 	de = tmpfs_dir_lookup(dnode, node, ncp);
+
+/* VS */
+	if (de == NULL) {
+		int i = tmpfs_dirhash(ncp->nc_name, ncp->nc_nlen);
+		struct tmpfs_dirent *tde;
+
+		tde = NULL;
+		TAILQ_FOREACH(tde, &dnode->tn_dir.tn_hdirhead.th_dirhead, td_entries) {
+			if (ncp->nc_nlen == tde->td_namelen) {
+				if (memcmp(ncp->nc_name, tde->td_name, ncp->nc_nlen) == 0)	
+					break;
+			}
+		} 
+
+		kprintf("warning: lookup mismatch, unexpected! %.*s name in %p dir, %p expnode\n", 
+			ncp->nc_nlen, ncp->nc_name, dnode, node);
+		kprintf("hash chain %d in dir %p\n", i, dnode);
+		kprintf("hand-find-de: %p %d hashq hname %s\n", tde, tde->td_hashq, tde->td_hashname);
+	}
+/* !VS */
+
 	KKASSERT(TMPFS_DIRENT_MATCHES(de,
 	    ncp->nc_name,
 	    ncp->nc_nlen));
@@ -1368,7 +1395,7 @@ outok:
 				off = TMPFS_DIRCOOKIE_DOTDOT;
 			} else {
 				if (off == TMPFS_DIRCOOKIE_DOTDOT) {
-					de = TAILQ_FIRST(&node->tn_dir.tn_dirhead);
+					de = TAILQ_FIRST(&node->tn_dir.tn_hdirhead.th_dirhead);
 				} else if (de != NULL) {
 					de = TAILQ_NEXT(de, td_entries);
 				} else {
