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/7b85aac113c9
branches:  trunk
changeset: 795873:7b85aac113c9
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 1dc107987589 -r 7b85aac113c9 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 1dc107987589 -r 7b85aac113c9 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