Module Name:    src
Committed By:   hannken
Date:           Thu May  8 08:21:53 UTC 2014

Modified Files:
        src/sys/kern: init_sysctl.c vfs_vnode.c
        src/sys/modules/ffs: Makefile
        src/sys/rump/fs/lib/libffs: Makefile
        src/sys/sys: mount.h param.h vnode.h
        src/sys/ufs: files.ufs
        src/sys/ufs/ext2fs: ext2fs_lookup.c ext2fs_vfsops.c
        src/sys/ufs/ffs: ffs_vfsops.c
        src/sys/ufs/mfs: mfs_vfsops.c
        src/sys/ufs/ufs: inode.h ufs_extern.h ufs_inode.c ufs_lookup.c
            ufs_vfsops.c
        src/usr.bin/vmstat: vmstat.c
Removed Files:
        src/sys/ufs/ufs: ufs_ihash.c

Log Message:
Add a global vnode cache:

- vcache_get() retrieves a referenced and initialised vnode / fs node pair.
- vcache_remove() removes a vnode / fs node pair from the cache.

On cache miss vcache_get() calls new vfs operation vfs_loadvnode() to
initialise a vnode / fs node pair.  This call is guaranteed exclusive,
no other thread will try to load this vnode / fs node pair.

Convert ufs/ext2fs, ufs/ffs and ufs/mfs to use this interface.

Remove now unused ufs/ufs_ihash

Discussed on tech-kern.

Welcome to 6.99.41


To generate a diff of this commit:
cvs rdiff -u -r1.202 -r1.203 src/sys/kern/init_sysctl.c
cvs rdiff -u -r1.35 -r1.36 src/sys/kern/vfs_vnode.c
cvs rdiff -u -r1.8 -r1.9 src/sys/modules/ffs/Makefile
cvs rdiff -u -r1.14 -r1.15 src/sys/rump/fs/lib/libffs/Makefile
cvs rdiff -u -r1.212 -r1.213 src/sys/sys/mount.h
cvs rdiff -u -r1.450 -r1.451 src/sys/sys/param.h
cvs rdiff -u -r1.246 -r1.247 src/sys/sys/vnode.h
cvs rdiff -u -r1.34 -r1.35 src/sys/ufs/files.ufs
cvs rdiff -u -r1.74 -r1.75 src/sys/ufs/ext2fs/ext2fs_lookup.c
cvs rdiff -u -r1.180 -r1.181 src/sys/ufs/ext2fs/ext2fs_vfsops.c
cvs rdiff -u -r1.297 -r1.298 src/sys/ufs/ffs/ffs_vfsops.c
cvs rdiff -u -r1.107 -r1.108 src/sys/ufs/mfs/mfs_vfsops.c
cvs rdiff -u -r1.65 -r1.66 src/sys/ufs/ufs/inode.h
cvs rdiff -u -r1.73 -r1.74 src/sys/ufs/ufs/ufs_extern.h
cvs rdiff -u -r1.32 -r0 src/sys/ufs/ufs/ufs_ihash.c
cvs rdiff -u -r1.89 -r1.90 src/sys/ufs/ufs/ufs_inode.c
cvs rdiff -u -r1.129 -r1.130 src/sys/ufs/ufs/ufs_lookup.c
cvs rdiff -u -r1.52 -r1.53 src/sys/ufs/ufs/ufs_vfsops.c
cvs rdiff -u -r1.191 -r1.192 src/usr.bin/vmstat/vmstat.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/sys/kern/init_sysctl.c
diff -u src/sys/kern/init_sysctl.c:1.202 src/sys/kern/init_sysctl.c:1.203
--- src/sys/kern/init_sysctl.c:1.202	Mon Mar 24 20:07:41 2014
+++ src/sys/kern/init_sysctl.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: init_sysctl.c,v 1.202 2014/03/24 20:07:41 christos Exp $ */
+/*	$NetBSD: init_sysctl.c,v 1.203 2014/05/08 08:21:53 hannken Exp $ */
 
 /*-
  * Copyright (c) 2003, 2007, 2008, 2009 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_sysctl.c,v 1.202 2014/03/24 20:07:41 christos Exp $");
+__KERNEL_RCSID(0, "$NetBSD: init_sysctl.c,v 1.203 2014/05/08 08:21:53 hannken Exp $");
 
 #include "opt_sysv.h"
 #include "opt_compat_netbsd.h"
@@ -854,12 +854,10 @@ sysctl_kern_maxvnodes(SYSCTLFN_ARGS)
 
 	old_vnodes = desiredvnodes;
 	desiredvnodes = new_vnodes;
-	if (new_vnodes < old_vnodes) {
-		error = vfs_drainvnodes(new_vnodes);
-		if (error) {
-			desiredvnodes = old_vnodes;
-			return (error);
-		}
+	error = vfs_drainvnodes(new_vnodes);
+	if (error) {
+		desiredvnodes = old_vnodes;
+		return (error);
 	}
 	vfs_reinit();
 	nchreinit();

Index: src/sys/kern/vfs_vnode.c
diff -u src/sys/kern/vfs_vnode.c:1.35 src/sys/kern/vfs_vnode.c:1.36
--- src/sys/kern/vfs_vnode.c:1.35	Mon Mar 24 13:42:40 2014
+++ src/sys/kern/vfs_vnode.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: vfs_vnode.c,v 1.35 2014/03/24 13:42:40 hannken Exp $	*/
+/*	$NetBSD: vfs_vnode.c,v 1.36 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -116,7 +116,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.35 2014/03/24 13:42:40 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.36 2014/05/08 08:21:53 hannken Exp $");
 
 #define _VFS_VNODE_PRIVATE
 
@@ -127,6 +127,7 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,
 #include <sys/buf.h>
 #include <sys/conf.h>
 #include <sys/device.h>
+#include <sys/hash.h>
 #include <sys/kauth.h>
 #include <sys/kmem.h>
 #include <sys/kthread.h>
@@ -147,6 +148,17 @@ __KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,
 #define	VRELEL_ASYNC_RELE	0x0001	/* Always defer to vrele thread. */
 #define	VRELEL_CHANGING_SET	0x0002	/* VI_CHANGING set by caller. */
 
+struct vcache_key {
+	struct mount *vk_mount;
+	const void *vk_key;
+	size_t vk_key_len;
+};
+struct vcache_node {
+	SLIST_ENTRY(vcache_node) vn_hash;
+	struct vnode *vn_vnode;
+	struct vcache_key vn_key;
+};
+
 u_int			numvnodes		__cacheline_aligned;
 
 static pool_cache_t	vnode_cache		__read_mostly;
@@ -169,7 +181,16 @@ static lwp_t *		vrele_lwp		__cacheline_a
 static int		vrele_pending		__cacheline_aligned;
 static int		vrele_gen		__cacheline_aligned;
 
+static struct {
+	kmutex_t	lock;
+	u_long		hashmask;
+	SLIST_HEAD(hashhead, vcache_node)	*hashtab;
+	pool_cache_t	pool;
+}			vcache			__cacheline_aligned;
+
 static int		cleanvnode(void);
+static void		vcache_init(void);
+static void		vcache_reinit(void);
 static void		vclean(vnode_t *);
 static void		vrelel(vnode_t *, int);
 static void		vdrain_thread(void *);
@@ -200,6 +221,8 @@ vfs_vnode_sysinit(void)
 	TAILQ_INIT(&vnode_hold_list);
 	TAILQ_INIT(&vrele_list);
 
+	vcache_init();
+
 	mutex_init(&vrele_lock, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&vdrain_cv, "vdrain");
 	cv_init(&vrele_cv, "vrele");
@@ -236,10 +259,20 @@ vnalloc(struct mount *mp)
 		vp->v_mount = mp;
 		vp->v_type = VBAD;
 		vp->v_iflag = VI_MARKER;
-	} else {
-		rw_init(&vp->v_lock);
+		return vp;
 	}
 
+	mutex_enter(&vnode_free_list_lock);
+	numvnodes++;
+	if (numvnodes > desiredvnodes + desiredvnodes / 10)
+		cv_signal(&vdrain_cv);
+	mutex_exit(&vnode_free_list_lock);
+
+	rw_init(&vp->v_lock);
+	vp->v_usecount = 1;
+	vp->v_type = VNON;
+	vp->v_size = vp->v_writesize = VSIZENOTSET;
+
 	return vp;
 }
 
@@ -367,29 +400,21 @@ getnewvnode(enum vtagtype tag, struct mo
 	vp = NULL;
 
 	/* Allocate a new vnode. */
-	mutex_enter(&vnode_free_list_lock);
-	numvnodes++;
-	if (numvnodes > desiredvnodes + desiredvnodes / 10)
-		cv_signal(&vdrain_cv);
-	mutex_exit(&vnode_free_list_lock);
 	vp = vnalloc(NULL);
 
 	KASSERT(vp->v_freelisthd == NULL);
 	KASSERT(LIST_EMPTY(&vp->v_nclist));
 	KASSERT(LIST_EMPTY(&vp->v_dnclist));
+	KASSERT(vp->v_data == NULL);
 
 	/* Initialize vnode. */
-	vp->v_usecount = 1;
-	vp->v_type = VNON;
 	vp->v_tag = tag;
 	vp->v_op = vops;
-	vp->v_data = NULL;
 
 	uobj = &vp->v_uobj;
 	KASSERT(uobj->pgops == &uvm_vnodeops);
 	KASSERT(uobj->uo_npages == 0);
 	KASSERT(TAILQ_FIRST(&uobj->memq) == NULL);
-	vp->v_size = vp->v_writesize = VSIZENOTSET;
 
 	/* Share the vnode_t::v_interlock, if requested. */
 	if (slock) {
@@ -1120,6 +1145,208 @@ vgone(vnode_t *vp)
 	vrelel(vp, VRELEL_CHANGING_SET);
 }
 
+static inline uint32_t
+vcache_hash(const struct vcache_key *key)
+{
+	uint32_t hash = HASH32_BUF_INIT;
+
+	hash = hash32_buf(&key->vk_mount, sizeof(struct mount *), hash);
+	hash = hash32_buf(key->vk_key, key->vk_key_len, hash);
+	return hash;
+}
+
+static void
+vcache_init(void)
+{
+
+	vcache.pool = pool_cache_init(sizeof(struct vcache_node), 0, 0, 0,
+	    "vcachepl", NULL, IPL_NONE, NULL, NULL, NULL);
+	KASSERT(vcache.pool != NULL);
+	mutex_init(&vcache.lock, MUTEX_DEFAULT, IPL_NONE);
+	vcache.hashtab = hashinit(desiredvnodes, HASH_SLIST, true,
+	    &vcache.hashmask);
+}
+
+static void
+vcache_reinit(void)
+{
+	int i;
+	uint32_t hash;
+	u_long oldmask, newmask;
+	struct hashhead *oldtab, *newtab;
+	struct vcache_node *node;
+
+	newtab = hashinit(desiredvnodes, HASH_SLIST, true, &newmask);
+	mutex_enter(&vcache.lock);
+	oldtab = vcache.hashtab;
+	oldmask = vcache.hashmask;
+	vcache.hashtab = newtab;
+	vcache.hashmask = newmask;
+	for (i = 0; i <= oldmask; i++) {
+		while ((node = SLIST_FIRST(&oldtab[i])) != NULL) {
+			SLIST_REMOVE(&oldtab[i], node, vcache_node, vn_hash);
+			hash = vcache_hash(&node->vn_key);
+			SLIST_INSERT_HEAD(&newtab[hash & vcache.hashmask],
+			    node, vn_hash);
+		}
+	}
+	mutex_exit(&vcache.lock);
+	hashdone(oldtab, HASH_SLIST, oldmask);
+}
+
+static inline struct vcache_node *
+vcache_hash_lookup(const struct vcache_key *key, uint32_t hash)
+{
+	struct hashhead *hashp;
+	struct vcache_node *node;
+
+	KASSERT(mutex_owned(&vcache.lock));
+
+	hashp = &vcache.hashtab[hash & vcache.hashmask];
+	SLIST_FOREACH(node, hashp, vn_hash) {
+		if (key->vk_mount != node->vn_key.vk_mount)
+			continue;
+		if (key->vk_key_len != node->vn_key.vk_key_len)
+			continue;
+		if (memcmp(key->vk_key, node->vn_key.vk_key, key->vk_key_len))
+			continue;
+		return node;
+	}
+	return NULL;
+}
+
+/*
+ * Get a vnode / fs node pair by key and return it referenced through vpp.
+ */
+int
+vcache_get(struct mount *mp, const void *key, size_t key_len,
+    struct vnode **vpp)
+{
+	int error;
+	uint32_t hash;
+	const void *new_key;
+	struct vnode *vp;
+	struct vcache_key vcache_key;
+	struct vcache_node *node, *new_node;
+
+	new_key = NULL;
+	*vpp = NULL;
+
+	vcache_key.vk_mount = mp;
+	vcache_key.vk_key = key;
+	vcache_key.vk_key_len = key_len;
+	hash = vcache_hash(&vcache_key);
+
+again:
+	mutex_enter(&vcache.lock);
+	node = vcache_hash_lookup(&vcache_key, hash);
+
+	/* If found, take a reference or retry. */
+	if (__predict_true(node != NULL && node->vn_vnode != NULL)) {
+		vp = node->vn_vnode;
+		mutex_enter(vp->v_interlock);
+		mutex_exit(&vcache.lock);
+		error = vget(vp, 0);
+		if (error == ENOENT)
+			goto again;
+		if (error == 0)
+			*vpp = vp;
+		KASSERT((error != 0) == (*vpp == NULL));
+		return error;
+	}
+
+	/* If another thread loads this node, wait and retry. */
+	if (node != NULL) {
+		KASSERT(node->vn_vnode == NULL);
+		mutex_exit(&vcache.lock);
+		kpause("vcache", false, mstohz(20), NULL);
+		goto again;
+	}
+	mutex_exit(&vcache.lock);
+
+	/* Allocate and initialize a new vcache / vnode pair. */
+	error = vfs_busy(mp, NULL);
+	if (error)
+		return error;
+	new_node = pool_cache_get(vcache.pool, PR_WAITOK);
+	new_node->vn_vnode = NULL;
+	new_node->vn_key = vcache_key;
+	vp = vnalloc(NULL);
+	mutex_enter(&vcache.lock);
+	node = vcache_hash_lookup(&vcache_key, hash);
+	if (node == NULL) {
+		SLIST_INSERT_HEAD(&vcache.hashtab[hash & vcache.hashmask],
+		    new_node, vn_hash);
+		node = new_node;
+	}
+	mutex_exit(&vcache.lock);
+
+	/* If another thread beat us inserting this node, retry. */
+	if (node != new_node) {
+		pool_cache_put(vcache.pool, new_node);
+		KASSERT(vp->v_usecount == 1);
+		vp->v_usecount = 0;
+		vnfree(vp);
+		vfs_unbusy(mp, false, NULL);
+		goto again;
+	}
+
+	/* Load the fs node.  Exclusive as new_node->vn_vnode is NULL. */
+	error = VFS_LOADVNODE(mp, vp, key, key_len, &new_key);
+	if (error) {
+		mutex_enter(&vcache.lock);
+		SLIST_REMOVE(&vcache.hashtab[hash & vcache.hashmask],
+		    new_node, vcache_node, vn_hash);
+		mutex_exit(&vcache.lock);
+		pool_cache_put(vcache.pool, new_node);
+		KASSERT(vp->v_usecount == 1);
+		vp->v_usecount = 0;
+		vnfree(vp);
+		vfs_unbusy(mp, false, NULL);
+		KASSERT(*vpp == NULL);
+		return error;
+	}
+	KASSERT(new_key != NULL);
+	KASSERT(memcmp(key, new_key, key_len) == 0);
+	KASSERT(vp->v_op != NULL);
+	vfs_insmntque(vp, mp);
+	if ((mp->mnt_iflag & IMNT_MPSAFE) != 0)
+		vp->v_vflag |= VV_MPSAFE;
+	vfs_unbusy(mp, true, NULL);
+
+	/* Finished loading, finalize node. */
+	mutex_enter(&vcache.lock);
+	new_node->vn_key.vk_key = new_key;
+	new_node->vn_vnode = vp;
+	mutex_exit(&vcache.lock);
+	*vpp = vp;
+	return 0;
+}
+
+/*
+ * Remove a vnode / fs node pair from the cache.
+ */
+void
+vcache_remove(struct mount *mp, const void *key, size_t key_len)
+{
+	uint32_t hash;
+	struct vcache_key vcache_key;
+	struct vcache_node *node;
+
+	vcache_key.vk_mount = mp;
+	vcache_key.vk_key = key;
+	vcache_key.vk_key_len = key_len;
+	hash = vcache_hash(&vcache_key);
+
+	mutex_enter(&vcache.lock);
+	node = vcache_hash_lookup(&vcache_key, hash);
+	KASSERT(node != NULL);
+	SLIST_REMOVE(&vcache.hashtab[hash & vcache.hashmask],
+	    node, vcache_node, vn_hash);
+	mutex_exit(&vcache.lock);
+	pool_cache_put(vcache.pool, node);
+}
+
 /*
  * Update outstanding I/O count and do wakeup if requested.
  */
@@ -1196,6 +1423,8 @@ vfs_drainvnodes(long target)
 
 	mutex_exit(&vnode_free_list_lock);
 
+	vcache_reinit();
+
 	return 0;
 }
 

Index: src/sys/modules/ffs/Makefile
diff -u src/sys/modules/ffs/Makefile:1.8 src/sys/modules/ffs/Makefile:1.9
--- src/sys/modules/ffs/Makefile:1.8	Thu May 10 07:51:34 2012
+++ src/sys/modules/ffs/Makefile	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.8 2012/05/10 07:51:34 riastradh Exp $
+#	$NetBSD: Makefile,v 1.9 2014/05/08 08:21:53 hannken Exp $
 
 .include "../Makefile.inc"
 
@@ -10,7 +10,7 @@ CPPFLAGS+=      -DUFS_DIRHASH -DFFS_EI -
 CWARNFLAGS.clang=	-Wno-conversion
 
 .PATH:	${S}/ufs/ufs
-SRCS=	ufs_bmap.c ufs_dirhash.c ufs_extattr.c ufs_ihash.c ufs_inode.c \
+SRCS=	ufs_bmap.c ufs_dirhash.c ufs_extattr.c ufs_inode.c \
 	ufs_lookup.c ufs_quota.c ufs_quota1.c ufs_quota2.c ufs_rename.c \
 	ufs_vfsops.c ufs_vnops.c ufs_wapbl.c quota2_subr.c
 

Index: src/sys/rump/fs/lib/libffs/Makefile
diff -u src/sys/rump/fs/lib/libffs/Makefile:1.14 src/sys/rump/fs/lib/libffs/Makefile:1.15
--- src/sys/rump/fs/lib/libffs/Makefile:1.14	Wed May  9 00:21:17 2012
+++ src/sys/rump/fs/lib/libffs/Makefile	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-#	$NetBSD: Makefile,v 1.14 2012/05/09 00:21:17 riastradh Exp $
+#	$NetBSD: Makefile,v 1.15 2014/05/08 08:21:53 hannken Exp $
 #
 
 .PATH:  ${.CURDIR}/../../../../ufs/ffs ${.CURDIR}/../../../../ufs/ufs
@@ -9,7 +9,7 @@ SRCS=	ffs_alloc.c ffs_appleufs.c ffs_bal
 	ffs_snapshot.c ffs_subr.c ffs_tables.c ffs_vfsops.c ffs_vnops.c	\
 	ffs_wapbl.c ffs_quota2.c
 
-SRCS+=	ufs_bmap.c ufs_dirhash.c ufs_extattr.c ufs_ihash.c ufs_inode.c	\
+SRCS+=	ufs_bmap.c ufs_dirhash.c ufs_extattr.c ufs_inode.c	\
 	ufs_lookup.c ufs_rename.c ufs_vfsops.c ufs_vnops.c ufs_wapbl.c \
 	ufs_quota.c ufs_quota2.c quota2_subr.c
 

Index: src/sys/sys/mount.h
diff -u src/sys/sys/mount.h:1.212 src/sys/sys/mount.h:1.213
--- src/sys/sys/mount.h:1.212	Wed Mar  5 09:37:29 2014
+++ src/sys/sys/mount.h	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mount.h,v 1.212 2014/03/05 09:37:29 hannken Exp $	*/
+/*	$NetBSD: mount.h,v 1.213 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*
  * Copyright (c) 1989, 1991, 1993
@@ -220,6 +220,8 @@ struct vfsops {
 	int	(*vfs_statvfs)	(struct mount *, struct statvfs *);
 	int	(*vfs_sync)	(struct mount *, int, struct kauth_cred *);
 	int	(*vfs_vget)	(struct mount *, ino_t, struct vnode **);
+	int	(*vfs_loadvnode) (struct mount *, struct vnode *,
+				    const void *, size_t, const void **);
 	int	(*vfs_fhtovp)	(struct mount *, struct fid *,
 				    struct vnode **);
 	int	(*vfs_vptofh)	(struct vnode *, struct fid *, size_t *);
@@ -242,6 +244,8 @@ struct vfsops {
 
 /* XXX vget is actually file system internal. */
 #define VFS_VGET(MP, INO, VPP)    (*(MP)->mnt_op->vfs_vget)(MP, INO, VPP)
+#define VFS_LOADVNODE(MP, VP, KEY, KEY_LEN, NEW_KEY) \
+	(*(MP)->mnt_op->vfs_loadvnode)(MP, VP, KEY, KEY_LEN, NEW_KEY)
 
 #define VFS_RENAMELOCK_ENTER(MP)  (*(MP)->mnt_op->vfs_renamelock_enter)(MP)
 #define VFS_RENAMELOCK_EXIT(MP)   (*(MP)->mnt_op->vfs_renamelock_exit)(MP)
@@ -281,6 +285,8 @@ int	fsname##_quotactl(struct mount *, st
 int	fsname##_statvfs(struct mount *, struct statvfs *);		\
 int	fsname##_sync(struct mount *, int, struct kauth_cred *);	\
 int	fsname##_vget(struct mount *, ino_t, struct vnode **);		\
+int	fsname##_loadvnode(struct mount *, struct vnode *,		\
+		const void *, size_t, const void **);			\
 int	fsname##_fhtovp(struct mount *, struct fid *, struct vnode **);	\
 int	fsname##_vptofh(struct vnode *, struct fid *, size_t *);	\
 void	fsname##_init(void);						\

Index: src/sys/sys/param.h
diff -u src/sys/sys/param.h:1.450 src/sys/sys/param.h:1.451
--- src/sys/sys/param.h:1.450	Fri Apr  4 18:11:58 2014
+++ src/sys/sys/param.h	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: param.h,v 1.450 2014/04/04 18:11:58 christos Exp $	*/
+/*	$NetBSD: param.h,v 1.451 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*-
  * Copyright (c) 1982, 1986, 1989, 1993
@@ -63,7 +63,7 @@
  *	2.99.9		(299000900)
  */
 
-#define	__NetBSD_Version__	699004000	/* NetBSD 6.99.40 */
+#define	__NetBSD_Version__	699004100	/* NetBSD 6.99.41 */
 
 #define __NetBSD_Prereq__(M,m,p) (((((M) * 100000000) + \
     (m) * 1000000) + (p) * 100) <= __NetBSD_Version__)

Index: src/sys/sys/vnode.h
diff -u src/sys/sys/vnode.h:1.246 src/sys/sys/vnode.h:1.247
--- src/sys/sys/vnode.h:1.246	Mon Mar 24 13:42:40 2014
+++ src/sys/sys/vnode.h	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: vnode.h,v 1.246 2014/03/24 13:42:40 hannken Exp $	*/
+/*	$NetBSD: vnode.h,v 1.247 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*-
  * Copyright (c) 2008 The NetBSD Foundation, Inc.
@@ -556,6 +556,8 @@ struct vnode *
 	vnalloc(struct mount *);
 void	vnfree(struct vnode *);
 void	vremfree(struct vnode *);
+int	vcache_get(struct mount *, const void *, size_t, struct vnode **);
+void	vcache_remove(struct mount *, const void *, size_t);
 
 /* see vnsubr(9) */
 int	vn_bwrite(void *);

Index: src/sys/ufs/files.ufs
diff -u src/sys/ufs/files.ufs:1.34 src/sys/ufs/files.ufs:1.35
--- src/sys/ufs/files.ufs:1.34	Tue Mar 18 18:20:44 2014
+++ src/sys/ufs/files.ufs	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-#	$NetBSD: files.ufs,v 1.34 2014/03/18 18:20:44 riastradh Exp $
+#	$NetBSD: files.ufs,v 1.35 2014/05/08 08:21:53 hannken Exp $
 
 deffs					FFS
 deffs					EXT2FS
@@ -94,7 +94,6 @@ file	ufs/mfs/mfs_miniroot.c
 file	ufs/ufs/ufs_bmap.c		ffs | mfs | ext2fs | chfs
 file	ufs/ufs/ufs_dirhash.c		(ffs | mfs | ext2fs | chfs) & ufs_dirhash
 file	ufs/ufs/ufs_extattr.c		(ffs | mfs) & ufs_extattr
-file	ufs/ufs/ufs_ihash.c		ffs | mfs | ext2fs
 file	ufs/ufs/ufs_inode.c		ffs | mfs | ext2fs
 file	ufs/ufs/ufs_lookup.c		ffs | mfs | ext2fs | chfs
 file	ufs/ufs/ufs_quota.c		(quota | quota2) & (ffs | mfs | ext2fs | chfs)

Index: src/sys/ufs/ext2fs/ext2fs_lookup.c
diff -u src/sys/ufs/ext2fs/ext2fs_lookup.c:1.74 src/sys/ufs/ext2fs/ext2fs_lookup.c:1.75
--- src/sys/ufs/ext2fs/ext2fs_lookup.c:1.74	Fri Feb  7 15:29:23 2014
+++ src/sys/ufs/ext2fs/ext2fs_lookup.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ext2fs_lookup.c,v 1.74 2014/02/07 15:29:23 hannken Exp $	*/
+/*	$NetBSD: ext2fs_lookup.c,v 1.75 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*
  * Modified for NetBSD 1.2E
@@ -48,7 +48,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_lookup.c,v 1.74 2014/02/07 15:29:23 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_lookup.c,v 1.75 2014/05/08 08:21:53 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/systm.h>
@@ -279,8 +279,7 @@ ext2fs_lookup(void *v)
 	int numdirpasses;		/* strategy for directory search */
 	doff_t endsearch;		/* offset to end directory search */
 	doff_t prevoff;			/* prev entry dp->i_offset */
-	struct vnode *pdp;		/* saved dp during symlink work */
-	struct vnode *tdp;		/* returned by VFS_VGET */
+	struct vnode *tdp;		/* returned by vcache_get */
 	doff_t enduseful;		/* pointer past last used dir slot */
 	u_long bmask;			/* block offset mask */
 	int namlen, error;
@@ -594,11 +593,8 @@ found:
 			vref(vdp);
 			tdp = vdp;
 		} else {
-			if (flags & ISDOTDOT)
-				VOP_UNLOCK(vdp); /* race to get the inode */
-			error = VFS_VGET(vdp->v_mount, foundino, &tdp);
-			if (flags & ISDOTDOT)
-				vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
+			error = vcache_get(vdp->v_mount,
+			    &foundino, sizeof(foundino), &tdp);
 			if (error)
 				return (error);
 		}
@@ -606,10 +602,7 @@ found:
 		 * Write access to directory required to delete files.
 		 */
 		if ((error = VOP_ACCESS(vdp, VWRITE, cred)) != 0) {
-			if (dp->i_number == foundino)
-				vrele(tdp);
-			else
-				vput(tdp);
+			vrele(tdp);
 			return (error);
 		}
 		/*
@@ -623,15 +616,10 @@ found:
 			    tdp, vdp, genfs_can_sticky(cred, dp->i_uid,
 			    VTOI(tdp)->i_uid));
 			if (error) {
-				if (dp->i_number == foundino)
-					vrele(tdp);
-				else
-					vput(tdp);
+				vrele(tdp);
 				return (EPERM);
 			}
 		}
-		if (tdp != vdp)
-			VOP_UNLOCK(tdp);
 		*vpp = tdp;
 		return (0);
 	}
@@ -652,52 +640,20 @@ found:
 		 */
 		if (dp->i_number == foundino)
 			return (EISDIR);
-		if (flags & ISDOTDOT)
-			VOP_UNLOCK(vdp); /* race to get the inode */
-		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
-		if (flags & ISDOTDOT)
-			vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
+		error = vcache_get(vdp->v_mount,
+		    &foundino, sizeof(foundino), &tdp);
 		if (error)
 			return (error);
-		if (tdp != vdp)
-			VOP_UNLOCK(tdp);
 		*vpp = tdp;
 		return (0);
 	}
 
-	/*
-	 * Step through the translation in the name.  We do not `vput' the
-	 * directory because we may need it again if a symbolic link
-	 * is relative to the current directory.  Instead we save it
-	 * unlocked as "pdp".  We must get the target inode before unlocking
-	 * the directory to insure that the inode will not be removed
-	 * before we get it.  We prevent deadlock by always fetching
-	 * inodes from the root, moving down the directory tree. Thus
-	 * when following backward pointers ".." we must unlock the
-	 * parent directory before getting the requested directory.
-	 * There is a potential race condition here if both the current
-	 * and parent directories are removed before the VFS_VGET for the
-	 * inode associated with ".." returns.  We hope that this occurs
-	 * infrequently since we cannot avoid this race condition without
-	 * implementing a sophisticated deadlock detection algorithm.
-	 * Note also that this simple deadlock detection scheme will not
-	 * work if the file system has any hard links other than ".."
-	 * that point backwards in the directory structure.
-	 */
-	pdp = vdp;
-	if (flags & ISDOTDOT) {
-		VOP_UNLOCK(pdp);	/* race to get the inode */
-		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
-		vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
-		if (error) {
-			return (error);
-		}
-		*vpp = tdp;
-	} else if (dp->i_number == foundino) {
+	if (dp->i_number == foundino) {
 		vref(vdp);	/* we want ourself, ie "." */
 		*vpp = vdp;
 	} else {
-		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
+		error = vcache_get(vdp->v_mount,
+		    &foundino, sizeof(foundino), &tdp);
 		if (error)
 			return (error);
 		*vpp = tdp;
@@ -707,8 +663,6 @@ found:
 	 * Insert name into cache if appropriate.
 	 */
 	cache_enter(vdp, *vpp, cnp->cn_nameptr, cnp->cn_namelen, cnp->cn_flags);
-	if (*vpp != vdp)
-		VOP_UNLOCK(*vpp);
 	return 0;
 }
 

Index: src/sys/ufs/ext2fs/ext2fs_vfsops.c
diff -u src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.180 src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.181
--- src/sys/ufs/ext2fs/ext2fs_vfsops.c:1.180	Wed Apr 16 18:55:19 2014
+++ src/sys/ufs/ext2fs/ext2fs_vfsops.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ext2fs_vfsops.c,v 1.180 2014/04/16 18:55:19 maxv Exp $	*/
+/*	$NetBSD: ext2fs_vfsops.c,v 1.181 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*
  * Copyright (c) 1989, 1991, 1993, 1994
@@ -60,7 +60,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.180 2014/04/16 18:55:19 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ext2fs_vfsops.c,v 1.181 2014/05/08 08:21:53 hannken Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -130,7 +130,8 @@ struct vfsops ext2fs_vfsops = {
 	.vfs_quotactl = ufs_quotactl,
 	.vfs_statvfs = ext2fs_statvfs,
 	.vfs_sync = ext2fs_sync,
-	.vfs_vget = ext2fs_vget,
+	.vfs_vget = ufs_vget,
+	.vfs_loadvnode = ext2fs_loadvnode,
 	.vfs_fhtovp = ext2fs_fhtovp,
 	.vfs_vptofh = ext2fs_vptofh,
 	.vfs_init = ext2fs_init,
@@ -943,84 +944,52 @@ ext2fs_sync(struct mount *mp, int waitfo
 }
 
 /*
- * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it
- * in from disk.  If it is in core, wait for the lock bit to clear, then
- * return the inode locked.  Detection and handling of mount points must be
- * done by the calling routine.
+ * Read an inode from disk and initialize this vnode / inode pair.
+ * Caller assures no other thread will try to load this inode.
  */
 int
-ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
+ext2fs_loadvnode(struct mount *mp, struct vnode *vp,
+    const void *key, size_t key_len, const void **new_key)
 {
+	ino_t ino;
 	struct m_ext2fs *fs;
 	struct inode *ip;
 	struct ufsmount *ump;
 	struct buf *bp;
-	struct vnode *vp;
 	dev_t dev;
 	int error;
 	void *cp;
 
+	KASSERT(key_len == sizeof(ino));
+	memcpy(&ino, key, key_len);
 	ump = VFSTOUFS(mp);
 	dev = ump->um_dev;
-retry:
-	if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL)
-		return (0);
-
-	/* Allocate a new vnode/inode. */
-	error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, NULL, &vp);
-	if (error) {
-		*vpp = NULL;
-		return (error);
-	}
-	ip = pool_get(&ext2fs_inode_pool, PR_WAITOK);
-
-	mutex_enter(&ufs_hashlock);
-	if ((*vpp = ufs_ihashget(dev, ino, 0)) != NULL) {
-		mutex_exit(&ufs_hashlock);
-		ungetnewvnode(vp);
-		pool_put(&ext2fs_inode_pool, ip);
-		goto retry;
-	}
+	fs = ump->um_e2fs;
 
-	vp->v_vflag |= VV_LOCKSWORK;
+	/* Read in the disk contents for the inode, copy into the inode. */
+	error = bread(ump->um_devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ino)),
+	    (int)fs->e2fs_bsize, NOCRED, 0, &bp);
+	if (error)
+		return error;
 
+	/* Allocate and initialize inode. */
+	ip = pool_get(&ext2fs_inode_pool, PR_WAITOK);
 	memset(ip, 0, sizeof(struct inode));
+	vp->v_tag = VT_EXT2FS;
+	vp->v_op = ext2fs_vnodeop_p;
+	vp->v_vflag |= VV_LOCKSWORK;
 	vp->v_data = ip;
 	ip->i_vnode = vp;
 	ip->i_ump = ump;
-	ip->i_e2fs = fs = ump->um_e2fs;
+	ip->i_e2fs = fs;
 	ip->i_dev = dev;
 	ip->i_number = ino;
 	ip->i_e2fs_last_lblk = 0;
 	ip->i_e2fs_last_blk = 0;
-	genfs_node_init(vp, &ext2fs_genfsops);
-
-	/*
-	 * Put it onto its hash chain and lock it so that other requests for
-	 * this inode will block if they arrive while we are sleeping waiting
-	 * for old data structures to be purged or for the contents of the
-	 * disk portion of this inode to be read.
-	 */
-
-	ufs_ihashins(ip);
-	mutex_exit(&ufs_hashlock);
 
-	/* Read in the disk contents for the inode, copy into the inode. */
-	error = bread(ump->um_devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ino)),
-	    (int)fs->e2fs_bsize, NOCRED, 0, &bp);
-	if (error) {
-
-		/*
-		 * The inode does not contain anything useful, so it would
-		 * be misleading to leave it on its hash chain. With mode
-		 * still zero, it will be unlinked and returned to the free
-		 * list by vput().
-		 */
+	/* Initialize genfs node. */
+	genfs_node_init(vp, &ext2fs_genfsops);
 
-		vput(vp);
-		*vpp = NULL;
-		return (error);
-	}
 	cp = (char *)bp->b_data + (ino_to_fsbo(fs, ino) * EXT2_DINODE_SIZE(fs));
 	ip->i_din.e2fs_din = pool_get(&ext2fs_dinode_pool, PR_WAITOK);
 	e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din);
@@ -1035,20 +1004,10 @@ retry:
 		memset(ip->i_e2fs_blocks, 0, sizeof(ip->i_e2fs_blocks));
 	}
 
-	/*
-	 * Initialize the vnode from the inode, check for aliases.
-	 */
-
-	error = ext2fs_vinit(mp, ext2fs_specop_p, ext2fs_fifoop_p, &vp);
-	if (error) {
-		vput(vp);
-		*vpp = NULL;
-		return (error);
-	}
-	/*
-	 * Finish inode initialization now that aliasing has been resolved.
-	 */
+	/* Initialize the vnode from the inode. */
+	ext2fs_vinit(mp, ext2fs_specop_p, ext2fs_fifoop_p, &vp);
 
+	/* Finish inode initialization. */
 	ip->i_devvp = ump->um_devvp;
 	vref(ip->i_devvp);
 
@@ -1065,8 +1024,8 @@ retry:
 			ip->i_flag |= IN_MODIFIED;
 	}
 	uvm_vnp_setsize(vp, ext2fs_size(ip));
-	*vpp = vp;
-	return (0);
+	*new_key = &ip->i_number;
+	return 0;
 }
 
 /*

Index: src/sys/ufs/ffs/ffs_vfsops.c
diff -u src/sys/ufs/ffs/ffs_vfsops.c:1.297 src/sys/ufs/ffs/ffs_vfsops.c:1.298
--- src/sys/ufs/ffs/ffs_vfsops.c:1.297	Wed Apr 16 18:55:19 2014
+++ src/sys/ufs/ffs/ffs_vfsops.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ffs_vfsops.c,v 1.297 2014/04/16 18:55:19 maxv Exp $	*/
+/*	$NetBSD: ffs_vfsops.c,v 1.298 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*-
  * Copyright (c) 2008, 2009 The NetBSD Foundation, Inc.
@@ -61,7 +61,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.297 2014/04/16 18:55:19 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ffs_vfsops.c,v 1.298 2014/05/08 08:21:53 hannken Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -141,7 +141,8 @@ struct vfsops ffs_vfsops = {
 	.vfs_quotactl = ufs_quotactl,
 	.vfs_statvfs = ffs_statvfs,
 	.vfs_sync = ffs_sync,
-	.vfs_vget = ffs_vget,
+	.vfs_vget = ufs_vget,
+	.vfs_loadvnode = ffs_loadvnode,
 	.vfs_fhtovp = ffs_fhtovp,
 	.vfs_vptofh = ffs_vptofh,
 	.vfs_init = ffs_init,
@@ -1725,99 +1726,52 @@ ffs_sync(struct mount *mp, int waitfor, 
 }
 
 /*
- * Look up a FFS dinode number to find its incore vnode, otherwise read it
- * in from disk.  If it is in core, wait for the lock bit to clear, then
- * return the inode locked.  Detection and handling of mount points must be
- * done by the calling routine.
+ * Read an inode from disk and initialize this vnode / inode pair.
+ * Caller assures no other thread will try to load this inode.
  */
 int
-ffs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
+ffs_loadvnode(struct mount *mp, struct vnode *vp,
+    const void *key, size_t key_len, const void **new_key)
 {
+	ino_t ino;
 	struct fs *fs;
 	struct inode *ip;
 	struct ufsmount *ump;
 	struct buf *bp;
-	struct vnode *vp;
 	dev_t dev;
 	int error;
 
+	KASSERT(key_len == sizeof(ino));
+	memcpy(&ino, key, key_len);
 	ump = VFSTOUFS(mp);
 	dev = ump->um_dev;
+	fs = ump->um_fs;
 
- retry:
-	if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL)
-		return (0);
+	/* Read in the disk contents for the inode. */
+	error = bread(ump->um_devvp, FFS_FSBTODB(fs, ino_to_fsba(fs, ino)),
+		      (int)fs->fs_bsize, NOCRED, 0, &bp);
+	if (error)
+		return error;
 
-	/* Allocate a new vnode/inode. */
-	error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, NULL, &vp);
-	if (error) {
-		*vpp = NULL;
-		return (error);
-	}
+	/* Allocate and initialize inode. */
 	ip = pool_cache_get(ffs_inode_cache, PR_WAITOK);
-
-	/*
-	 * If someone beat us to it, put back the freshly allocated
-	 * vnode/inode pair and retry.
-	 */
-	mutex_enter(&ufs_hashlock);
-	if (ufs_ihashget(dev, ino, 0) != NULL) {
-		mutex_exit(&ufs_hashlock);
-		ungetnewvnode(vp);
-		pool_cache_put(ffs_inode_cache, ip);
-		goto retry;
-	}
-
-	vp->v_vflag |= VV_LOCKSWORK;
-
-	/*
-	 * XXX MFS ends up here, too, to allocate an inode.  Should we
-	 * XXX create another pool for MFS inodes?
-	 */
-
 	memset(ip, 0, sizeof(struct inode));
+	vp->v_tag = VT_UFS;
+	vp->v_op = ffs_vnodeop_p;
+	vp->v_vflag |= VV_LOCKSWORK;
 	vp->v_data = ip;
 	ip->i_vnode = vp;
 	ip->i_ump = ump;
-	ip->i_fs = fs = ump->um_fs;
+	ip->i_fs = fs;
 	ip->i_dev = dev;
 	ip->i_number = ino;
 #if defined(QUOTA) || defined(QUOTA2)
 	ufsquota_init(ip);
 #endif
 
-	/*
-	 * Initialize genfs node, we might proceed to destroy it in
-	 * error branches.
-	 */
+	/* Initialize genfs node. */
 	genfs_node_init(vp, &ffs_genfsops);
 
-	/*
-	 * Put it onto its hash chain and lock it so that other requests for
-	 * this inode will block if they arrive while we are sleeping waiting
-	 * for old data structures to be purged or for the contents of the
-	 * disk portion of this inode to be read.
-	 */
-
-	ufs_ihashins(ip);
-	mutex_exit(&ufs_hashlock);
-
-	/* Read in the disk contents for the inode, copy into the inode. */
-	error = bread(ump->um_devvp, FFS_FSBTODB(fs, ino_to_fsba(fs, ino)),
-		      (int)fs->fs_bsize, NOCRED, 0, &bp);
-	if (error) {
-
-		/*
-		 * The inode does not contain anything useful, so it would
-		 * be misleading to leave it on its hash chain. With mode
-		 * still zero, it will be unlinked and returned to the free
-		 * list by vput().
-		 */
-
-		vput(vp);
-		*vpp = NULL;
-		return (error);
-	}
 	if (ip->i_ump->um_fstype == UFS1)
 		ip->i_din.ffs1_din = pool_cache_get(ffs_dinode1_cache,
 		    PR_WAITOK);
@@ -1827,17 +1781,10 @@ ffs_vget(struct mount *mp, ino_t ino, st
 	ffs_load_inode(bp, ip, fs, ino);
 	brelse(bp, 0);
 
-	/*
-	 * Initialize the vnode from the inode, check for aliases.
-	 * Note that the underlying vnode may have changed.
-	 */
-
+	/* Initialize the vnode from the inode. */
 	ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp);
 
-	/*
-	 * Finish inode initialization now that aliasing has been resolved.
-	 */
-
+	/* Finish inode initialization.  */
 	ip->i_devvp = ump->um_devvp;
 	vref(ip->i_devvp);
 
@@ -1851,8 +1798,8 @@ ffs_vget(struct mount *mp, ino_t ino, st
 		ip->i_gid = ip->i_ffs1_ogid;			/* XXX */
 	}							/* XXX */
 	uvm_vnp_setsize(vp, ip->i_size);
-	*vpp = vp;
-	return (0);
+	*new_key = &ip->i_number;
+	return 0;
 }
 
 /*

Index: src/sys/ufs/mfs/mfs_vfsops.c
diff -u src/sys/ufs/mfs/mfs_vfsops.c:1.107 src/sys/ufs/mfs/mfs_vfsops.c:1.108
--- src/sys/ufs/mfs/mfs_vfsops.c:1.107	Wed Apr 16 18:55:19 2014
+++ src/sys/ufs/mfs/mfs_vfsops.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: mfs_vfsops.c,v 1.107 2014/04/16 18:55:19 maxv Exp $	*/
+/*	$NetBSD: mfs_vfsops.c,v 1.108 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*
  * Copyright (c) 1989, 1990, 1993, 1994
@@ -32,7 +32,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: mfs_vfsops.c,v 1.107 2014/04/16 18:55:19 maxv Exp $");
+__KERNEL_RCSID(0, "$NetBSD: mfs_vfsops.c,v 1.108 2014/05/08 08:21:53 hannken Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_compat_netbsd.h"
@@ -99,7 +99,8 @@ struct vfsops mfs_vfsops = {
 	.vfs_quotactl = ufs_quotactl,
 	.vfs_statvfs = mfs_statvfs,
 	.vfs_sync = ffs_sync,
-	.vfs_vget = ffs_vget,
+	.vfs_vget = ufs_vget,
+	.vfs_loadvnode = ffs_loadvnode,
 	.vfs_fhtovp = ffs_fhtovp,
 	.vfs_vptofh = ffs_vptofh,
 	.vfs_init = mfs_init,

Index: src/sys/ufs/ufs/inode.h
diff -u src/sys/ufs/ufs/inode.h:1.65 src/sys/ufs/ufs/inode.h:1.66
--- src/sys/ufs/ufs/inode.h:1.65	Sun Jun  9 17:55:46 2013
+++ src/sys/ufs/ufs/inode.h	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: inode.h,v 1.65 2013/06/09 17:55:46 dholland Exp $	*/
+/*	$NetBSD: inode.h,v 1.66 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*
  * Copyright (c) 1982, 1989, 1993
@@ -93,7 +93,6 @@ struct lfs_inode_ext;
  */
 struct inode {
 	struct genfs_node i_gnode;
-	LIST_ENTRY(inode) i_hash;/* Hash chain. */
 	TAILQ_ENTRY(inode) i_nextsnap; /* snapshot file list. */
 	struct	vnode *i_vnode;	/* Vnode associated with this inode. */
 	struct  ufsmount *i_ump; /* Mount point associated with this inode. */

Index: src/sys/ufs/ufs/ufs_extern.h
diff -u src/sys/ufs/ufs/ufs_extern.h:1.73 src/sys/ufs/ufs/ufs_extern.h:1.74
--- src/sys/ufs/ufs/ufs_extern.h:1.73	Sun Jun 16 13:33:30 2013
+++ src/sys/ufs/ufs/ufs_extern.h	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_extern.h,v 1.73 2013/06/16 13:33:30 hannken Exp $	*/
+/*	$NetBSD: ufs_extern.h,v 1.74 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*-
  * Copyright (c) 1991, 1993, 1994
@@ -108,15 +108,6 @@ int	ufs_bmaparray(struct vnode *, daddr_
 		      int *, int *, ufs_issequential_callback_t);
 int	ufs_getlbns(struct vnode *, daddr_t, struct indir *, int *);
 
-/* ufs_ihash.c */
-void	ufs_ihashinit(void);
-void	ufs_ihashreinit(void);
-void	ufs_ihashdone(void);
-struct vnode *ufs_ihashlookup(dev_t, ino_t);
-struct vnode *ufs_ihashget(dev_t, ino_t, int);
-void	ufs_ihashins(struct inode *);
-void	ufs_ihashrem(struct inode *);
-
 /* ufs_inode.c */
 int	ufs_reclaim(struct vnode *);
 int	ufs_balloc_range(struct vnode *, off_t, off_t, kauth_cred_t, int);
@@ -188,6 +179,7 @@ void	ufs_reinit(void);
 void	ufs_done(void);
 int	ufs_start(struct mount *, int);
 int	ufs_root(struct mount *, struct vnode **);
+int	ufs_vget(struct mount *, ino_t, struct vnode **);
 int	ufs_quotactl(struct mount *, struct quotactl_args *);
 int	ufs_fhtovp(struct mount *, struct ufid *, struct vnode **);
 
@@ -201,7 +193,6 @@ void	ufs_gop_markupdate(struct vnode *, 
 
 __END_DECLS
 
-extern kmutex_t ufs_ihash_lock;
 extern kmutex_t ufs_hashlock;
 
 #endif /* !_UFS_UFS_EXTERN_H_ */

Index: src/sys/ufs/ufs/ufs_inode.c
diff -u src/sys/ufs/ufs/ufs_inode.c:1.89 src/sys/ufs/ufs/ufs_inode.c:1.90
--- src/sys/ufs/ufs/ufs_inode.c:1.89	Tue Jan 22 09:39:18 2013
+++ src/sys/ufs/ufs/ufs_inode.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_inode.c,v 1.89 2013/01/22 09:39:18 dholland Exp $	*/
+/*	$NetBSD: ufs_inode.c,v 1.90 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*
  * Copyright (c) 1991, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,v 1.89 2013/01/22 09:39:18 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_inode.c,v 1.90 2014/05/08 08:21:53 hannken Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -191,9 +191,9 @@ ufs_reclaim(struct vnode *vp)
 	UFS_UPDATE(vp, NULL, NULL, UPDATE_CLOSE);
 
 	/*
-	 * Remove the inode from its hash chain.
+	 * Remove the inode from the vnode cache.
 	 */
-	ufs_ihashrem(ip);
+	vcache_remove(vp->v_mount, &ip->i_number, sizeof(ip->i_number));
 
 	if (ip->i_devvp) {
 		vrele(ip->i_devvp);

Index: src/sys/ufs/ufs/ufs_lookup.c
diff -u src/sys/ufs/ufs/ufs_lookup.c:1.129 src/sys/ufs/ufs/ufs_lookup.c:1.130
--- src/sys/ufs/ufs/ufs_lookup.c:1.129	Fri Feb  7 15:29:23 2014
+++ src/sys/ufs/ufs/ufs_lookup.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_lookup.c,v 1.129 2014/02/07 15:29:23 hannken Exp $	*/
+/*	$NetBSD: ufs_lookup.c,v 1.130 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*
  * Copyright (c) 1989, 1993
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.129 2014/02/07 15:29:23 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_lookup.c,v 1.130 2014/05/08 08:21:53 hannken Exp $");
 
 #ifdef _KERNEL_OPT
 #include "opt_ffs.h"
@@ -137,8 +137,7 @@ ufs_lookup(void *v)
 	int numdirpasses;		/* strategy for directory search */
 	doff_t endsearch;		/* offset to end directory search */
 	doff_t prevoff;			/* previous value of ulr_offset */
-	struct vnode *pdp;		/* saved dp during symlink work */
-	struct vnode *tdp;		/* returned by VFS_VGET */
+	struct vnode *tdp;		/* returned by vcache_get */
 	doff_t enduseful;		/* pointer past last used dir slot.
 					   used for directory truncation. */
 	u_long bmask;			/* block offset mask */
@@ -566,11 +565,8 @@ found:
 			vref(vdp);
 			tdp = vdp;
 		} else {
-			if (flags & ISDOTDOT)
-				VOP_UNLOCK(vdp); /* race to get the inode */
-			error = VFS_VGET(vdp->v_mount, foundino, &tdp);
-			if (flags & ISDOTDOT)
-				vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
+			error = vcache_get(vdp->v_mount,
+			    &foundino, sizeof(foundino), &tdp);
 			if (error)
 				goto out;
 		}
@@ -579,10 +575,7 @@ found:
 		 */
 		error = VOP_ACCESS(vdp, VWRITE, cred);
 		if (error) {
-			if (dp->i_number == foundino)
-				vrele(tdp);
-			else
-				vput(tdp);
+			vrele(tdp);
 			goto out;
 		}
 		/*
@@ -596,10 +589,7 @@ found:
 			    tdp, vdp, genfs_can_sticky(cred, dp->i_uid,
 			    VTOI(tdp)->i_uid));
 			if (error) {
-				if (dp->i_number == foundino)
-					vrele(tdp);
-				else
-					vput(tdp);
+				vrele(tdp);
 				error = EPERM;
 				goto out;
 			}
@@ -627,11 +617,8 @@ found:
 			error = EISDIR;
 			goto out;
 		}
-		if (flags & ISDOTDOT)
-			VOP_UNLOCK(vdp); /* race to get the inode */
-		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
-		if (flags & ISDOTDOT)
-			vn_lock(vdp, LK_EXCLUSIVE | LK_RETRY);
+		error = vcache_get(vdp->v_mount,
+		    &foundino, sizeof(foundino), &tdp);
 		if (error)
 			goto out;
 		*vpp = tdp;
@@ -639,39 +626,12 @@ found:
 		goto out;
 	}
 
-	/*
-	 * Step through the translation in the name.  We do not `vput' the
-	 * directory because we may need it again if a symbolic link
-	 * is relative to the current directory.  Instead we save it
-	 * unlocked as "pdp".  We must get the target inode before unlocking
-	 * the directory to insure that the inode will not be removed
-	 * before we get it.  We prevent deadlock by always fetching
-	 * inodes from the root, moving down the directory tree. Thus
-	 * when following backward pointers ".." we must unlock the
-	 * parent directory before getting the requested directory.
-	 * There is a potential race condition here if both the current
-	 * and parent directories are removed before the VFS_VGET for the
-	 * inode associated with ".." returns.  We hope that this occurs
-	 * infrequently since we cannot avoid this race condition without
-	 * implementing a sophisticated deadlock detection algorithm.
-	 * Note also that this simple deadlock detection scheme will not
-	 * work if the file system has any hard links other than ".."
-	 * that point backwards in the directory structure.
-	 */
-	pdp = vdp;
-	if (flags & ISDOTDOT) {
-		VOP_UNLOCK(pdp);	/* race to get the inode */
-		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
-		vn_lock(pdp, LK_EXCLUSIVE | LK_RETRY);
-		if (error) {
-			goto out;
-		}
-		*vpp = tdp;
-	} else if (dp->i_number == foundino) {
+	if (dp->i_number == foundino) {
 		vref(vdp);	/* we want ourself, ie "." */
 		*vpp = vdp;
 	} else {
-		error = VFS_VGET(vdp->v_mount, foundino, &tdp);
+		error = vcache_get(vdp->v_mount,
+		    &foundino, sizeof(foundino), &tdp);
 		if (error)
 			goto out;
 		*vpp = tdp;
@@ -684,8 +644,6 @@ found:
 	error = 0;
 
 out:
-	if (error == 0 && *vpp != vdp)
-		VOP_UNLOCK(*vpp);
 	fstrans_done(vdp->v_mount);
 	return error;
 }

Index: src/sys/ufs/ufs/ufs_vfsops.c
diff -u src/sys/ufs/ufs/ufs_vfsops.c:1.52 src/sys/ufs/ufs/ufs_vfsops.c:1.53
--- src/sys/ufs/ufs/ufs_vfsops.c:1.52	Tue Jan 22 09:39:18 2013
+++ src/sys/ufs/ufs/ufs_vfsops.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/*	$NetBSD: ufs_vfsops.c,v 1.52 2013/01/22 09:39:18 dholland Exp $	*/
+/*	$NetBSD: ufs_vfsops.c,v 1.53 2014/05/08 08:21:53 hannken Exp $	*/
 
 /*
  * Copyright (c) 1991, 1993, 1994
@@ -37,7 +37,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ufs_vfsops.c,v 1.52 2013/01/22 09:39:18 dholland Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ufs_vfsops.c,v 1.53 2014/05/08 08:21:53 hannken Exp $");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ffs.h"
@@ -97,6 +97,26 @@ ufs_root(struct mount *mp, struct vnode 
 }
 
 /*
+ * Look up and return a vnode/inode pair by inode number.
+ */
+int
+ufs_vget(struct mount *mp, ino_t ino, struct vnode **vpp)
+{
+	int error;
+
+	error = vcache_get(mp, &ino, sizeof(ino), vpp);
+	if (error)
+		return error;
+	error = vn_lock(*vpp, LK_EXCLUSIVE);
+	if (error) {
+		vrele(*vpp);
+		*vpp = NULL;
+		return error;
+	}
+	return 0;
+}
+
+/*
  * Do operations associated with quotas
  */
 int
@@ -245,7 +265,6 @@ ufs_init(void)
 	ufs_direct_cache = pool_cache_init(sizeof(struct direct), 0, 0, 0,
 	    "ufsdir", NULL, IPL_NONE, NULL, NULL, NULL);
 
-	ufs_ihashinit();
 #if defined(QUOTA) || defined(QUOTA2)
 	dqinit();
 #endif
@@ -260,7 +279,6 @@ ufs_init(void)
 void
 ufs_reinit(void)
 {
-	ufs_ihashreinit();
 #if defined(QUOTA) || defined(QUOTA2)
 	dqreinit();
 #endif
@@ -275,7 +293,6 @@ ufs_done(void)
 	if (--ufs_initcount > 0)
 		return;
 
-	ufs_ihashdone();
 #if defined(QUOTA) || defined(QUOTA2)
 	dqdone();
 #endif

Index: src/usr.bin/vmstat/vmstat.c
diff -u src/usr.bin/vmstat/vmstat.c:1.191 src/usr.bin/vmstat/vmstat.c:1.192
--- src/usr.bin/vmstat/vmstat.c:1.191	Wed Feb 19 20:42:14 2014
+++ src/usr.bin/vmstat/vmstat.c	Thu May  8 08:21:53 2014
@@ -1,4 +1,4 @@
-/* $NetBSD: vmstat.c,v 1.191 2014/02/19 20:42:14 dsl Exp $ */
+/* $NetBSD: vmstat.c,v 1.192 2014/05/08 08:21:53 hannken Exp $ */
 
 /*-
  * Copyright (c) 1998, 2000, 2001, 2007 The NetBSD Foundation, Inc.
@@ -70,7 +70,7 @@ __COPYRIGHT("@(#) Copyright (c) 1980, 19
 #if 0
 static char sccsid[] = "@(#)vmstat.c	8.2 (Berkeley) 3/1/95";
 #else
-__RCSID("$NetBSD: vmstat.c,v 1.191 2014/02/19 20:42:14 dsl Exp $");
+__RCSID("$NetBSD: vmstat.c,v 1.192 2014/05/08 08:21:53 hannken Exp $");
 #endif
 #endif /* not lint */
 
@@ -1470,10 +1470,6 @@ struct kernel_hash {
 		X_BUFHASH, X_BUFHASHTBL,
 		HASH_LIST, offsetof(struct buf, b_hash)
 	}, {
-		"inode cache (ihash)",
-		X_IHASH, X_IHASHTBL,
-		HASH_LIST, offsetof(struct inode, i_hash)
-	}, {
 		"ipv4 address -> interface hash",
 		X_IFADDRHASH, X_IFADDRHASHTBL,
 		HASH_LIST, offsetof(struct in_ifaddr, ia_hash),

Reply via email to