Source-Changes-HG archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
[src/trunk]: src Add a global vnode cache:
details: https://anonhg.NetBSD.org/src/rev/3e86cc73a037
branches: trunk
changeset: 329112:3e86cc73a037
user: hannken <hannken%NetBSD.org@localhost>
date: Thu May 08 08:21:53 2014 +0000
description:
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
diffstat:
sys/kern/init_sysctl.c | 14 +-
sys/kern/vfs_vnode.c | 255 +++++++++++++++++++++++++++++++++++++--
sys/modules/ffs/Makefile | 4 +-
sys/rump/fs/lib/libffs/Makefile | 4 +-
sys/sys/mount.h | 8 +-
sys/sys/param.h | 4 +-
sys/sys/vnode.h | 4 +-
sys/ufs/ext2fs/ext2fs_lookup.c | 70 +---------
sys/ufs/ext2fs/ext2fs_vfsops.c | 101 ++++-----------
sys/ufs/ffs/ffs_vfsops.c | 109 ++++------------
sys/ufs/files.ufs | 3 +-
sys/ufs/mfs/mfs_vfsops.c | 7 +-
sys/ufs/ufs/inode.h | 3 +-
sys/ufs/ufs/ufs_extern.h | 13 +-
sys/ufs/ufs/ufs_ihash.c | 193 ------------------------------
sys/ufs/ufs/ufs_inode.c | 8 +-
sys/ufs/ufs/ufs_lookup.c | 66 +--------
sys/ufs/ufs/ufs_vfsops.c | 27 +++-
usr.bin/vmstat/vmstat.c | 8 +-
19 files changed, 382 insertions(+), 519 deletions(-)
diffs (truncated from 1531 to 300 lines):
diff -r ca8c9eb2e6ae -r 3e86cc73a037 sys/kern/init_sysctl.c
--- a/sys/kern/init_sysctl.c Thu May 08 05:59:09 2014 +0000
+++ b/sys/kern/init_sysctl.c Thu May 08 08:21:53 2014 +0000
@@ -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 @@
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();
diff -r ca8c9eb2e6ae -r 3e86cc73a037 sys/kern/vfs_vnode.c
--- a/sys/kern/vfs_vnode.c Thu May 08 05:59:09 2014 +0000
+++ b/sys/kern/vfs_vnode.c Thu May 08 08:21:53 2014 +0000
@@ -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 @@
#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 @@
#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 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 @@
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 @@
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 @@
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 @@
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. */
Home |
Main Index |
Thread Index |
Old Index