Source-Changes-HG archive

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]

[src/trunk]: src/sys/kern Change vrelel() to defer the test for a reclaimed v...



details:   https://anonhg.NetBSD.org/src/rev/5f6d50cc63d0
branches:  trunk
changeset: 352400:5f6d50cc63d0
user:      hannken <hannken%NetBSD.org@localhost>
date:      Thu Mar 30 09:14:59 2017 +0000

description:
Change vrelel() to defer the test for a reclaimed vnode until
we hold both the interlock and the vnode lock.

Add a common operation to deallocate a vnode in state LOADING.

diffstat:

 sys/kern/vfs_vnode.c |  147 ++++++++++++++++++++++++--------------------------
 1 files changed, 71 insertions(+), 76 deletions(-)

diffs (253 lines):

diff -r 7fd71a6f0086 -r 5f6d50cc63d0 sys/kern/vfs_vnode.c
--- a/sys/kern/vfs_vnode.c      Thu Mar 30 09:14:08 2017 +0000
+++ b/sys/kern/vfs_vnode.c      Thu Mar 30 09:14:59 2017 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_vnode.c,v 1.78 2017/03/30 09:14:08 hannken Exp $   */
+/*     $NetBSD: vfs_vnode.c,v 1.79 2017/03/30 09:14:59 hannken Exp $   */
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -156,7 +156,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.78 2017/03/30 09:14:08 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.79 2017/03/30 09:14:59 hannken Exp $");
 
 #include <sys/param.h>
 #include <sys/kernel.h>
@@ -212,6 +212,7 @@
 static void            lru_requeue(vnode_t *, vnodelst_t *);
 static vnodelst_t *    lru_which(vnode_t *);
 static vnode_impl_t *  vcache_alloc(void);
+static void            vcache_dealloc(vnode_impl_t *);
 static void            vcache_free(vnode_impl_t *);
 static void            vcache_init(void);
 static void            vcache_reinit(void);
@@ -662,6 +663,8 @@
 static void
 vrelel(vnode_t *vp, int flags)
 {
+       const bool async = ((flags & VRELEL_ASYNC_RELE) != 0);
+       const bool force = ((flags & VRELEL_FORCE_RELE) != 0);
        bool recycle, defer;
        int error;
 
@@ -692,62 +695,48 @@
 #endif
 
        /*
+        * First try to get the vnode locked for VOP_INACTIVE().
+        * Defer vnode release to vdrain_thread if caller requests
+        * it explicitly, is the pagedaemon or the lock failed.
+        */
+       if ((curlwp == uvm.pagedaemon_lwp) || async) {
+               defer = true;
+       } else {
+               mutex_exit(vp->v_interlock);
+               error = vn_lock(vp,
+                   LK_EXCLUSIVE | LK_RETRY | (force ? 0 : LK_NOWAIT));
+               defer = (error != 0);
+               mutex_enter(vp->v_interlock);
+       }
+       KASSERT(mutex_owned(vp->v_interlock));
+       KASSERT(! (force && defer));
+       if (defer) {
+               /*
+                * Defer reclaim to the kthread; it's not safe to
+                * clean it here.  We donate it our last reference.
+                */
+               lru_requeue(vp, &lru_vrele_list);
+               mutex_exit(vp->v_interlock);
+               return;
+       }
+
+       /*
+        * If the node got another reference while we
+        * released the interlock, don't try to inactivate it yet.
+        */
+       if (__predict_false(vtryrele(vp))) {
+               VOP_UNLOCK(vp);
+               mutex_exit(vp->v_interlock);
+               return;
+       }
+
+       /*
         * If not clean, deactivate the vnode, but preserve
         * our reference across the call to VOP_INACTIVE().
         */
-       if (VSTATE_GET(vp) != VS_RECLAIMED) {
-               recycle = false;
-
-               /*
-                * XXX This ugly block can be largely eliminated if
-                * locking is pushed down into the file systems.
-                *
-                * Defer vnode release to vdrain_thread if caller
-                * requests it explicitly or is the pagedaemon.
-                */
-               if ((curlwp == uvm.pagedaemon_lwp) ||
-                   (flags & VRELEL_ASYNC_RELE) != 0) {
-                       defer = true;
-               } else if ((flags & VRELEL_FORCE_RELE) != 0) {
-                       /*
-                        * We have to try harder.
-                        */
-                       mutex_exit(vp->v_interlock);
-                       error = vn_lock(vp, LK_EXCLUSIVE | LK_RETRY);
-                       KASSERTMSG((error == 0), "vn_lock failed: %d", error);
-                       mutex_enter(vp->v_interlock);
-                       defer = false;
-               } else {
-                       /* If we can't acquire the lock, then defer. */
-                       mutex_exit(vp->v_interlock);
-                       error = vn_lock(vp,
-                           LK_EXCLUSIVE | LK_RETRY | LK_NOWAIT);
-                       defer = (error != 0);
-                       mutex_enter(vp->v_interlock);
-               }
-
-               KASSERT(mutex_owned(vp->v_interlock));
-               KASSERT(! ((flags & VRELEL_FORCE_RELE) != 0 && defer));
-
-               if (defer) {
-                       /*
-                        * Defer reclaim to the kthread; it's not safe to
-                        * clean it here.  We donate it our last reference.
-                        */
-                       lru_requeue(vp, &lru_vrele_list);
-                       mutex_exit(vp->v_interlock);
-                       return;
-               }
-
-               /*
-                * If the node got another reference while we
-                * released the interlock, don't try to inactivate it yet.
-                */
-               if (__predict_false(vtryrele(vp))) {
-                       VOP_UNLOCK(vp);
-                       mutex_exit(vp->v_interlock);
-                       return;
-               }
+       if (VSTATE_GET(vp) == VS_RECLAIMED) {
+               VOP_UNLOCK(vp);
+       } else {
                VSTATE_CHANGE(vp, VS_ACTIVE, VS_BLOCKED);
                mutex_exit(vp->v_interlock);
 
@@ -759,6 +748,7 @@
                 *
                 * Note that VOP_INACTIVE() will drop the vnode lock.
                 */
+               recycle = false;
                VOP_INACTIVE(vp, &recycle);
                if (recycle) {
                        /* vcache_reclaim() below will drop the lock. */
@@ -1097,6 +1087,26 @@
 }
 
 /*
+ * Deallocate a vcache node in state VS_LOADING.
+ *
+ * vcache_lock held on entry and released on return.
+ */
+static void
+vcache_dealloc(vnode_impl_t *vip)
+{
+       vnode_t *vp;
+
+       KASSERT(mutex_owned(&vcache_lock));
+
+       vp = VIMPL_TO_VNODE(vip);
+       mutex_enter(vp->v_interlock);
+       vp->v_op = dead_vnodeop_p;
+       VSTATE_CHANGE(vp, VS_LOADING, VS_RECLAIMED);
+       mutex_exit(&vcache_lock);
+       vrelel(vp, 0);
+}
+
+/*
  * Free an unused, unreferenced vcache node.
  * v_interlock locked on entry.
  */
@@ -1260,10 +1270,7 @@
 
        /* If another thread beat us inserting this node, retry. */
        if (vip != new_vip) {
-               mutex_enter(vp->v_interlock);
-               VSTATE_CHANGE(vp, VS_LOADING, VS_RECLAIMED);
-               mutex_exit(&vcache_lock);
-               vrelel(vp, 0);
+               vcache_dealloc(new_vip);
                vfs_unbusy(mp, false, NULL);
                goto again;
        }
@@ -1275,10 +1282,7 @@
                mutex_enter(&vcache_lock);
                SLIST_REMOVE(&vcache_hashtab[hash & vcache_hashmask],
                    new_vip, vnode_impl, vi_hash);
-               mutex_enter(vp->v_interlock);
-               VSTATE_CHANGE(vp, VS_LOADING, VS_RECLAIMED);
-               mutex_exit(&vcache_lock);
-               vrelel(vp, 0);
+               vcache_dealloc(new_vip);
                vfs_unbusy(mp, false, NULL);
                KASSERT(*vpp == NULL);
                return error;
@@ -1329,10 +1333,7 @@
            &vip->vi_key.vk_key_len, &vip->vi_key.vk_key);
        if (error) {
                mutex_enter(&vcache_lock);
-               mutex_enter(vp->v_interlock);
-               VSTATE_CHANGE(vp, VS_LOADING, VS_RECLAIMED);
-               mutex_exit(&vcache_lock);
-               vrelel(vp, 0);
+               vcache_dealloc(vip);
                vfs_unbusy(mp, false, NULL);
                KASSERT(*vpp == NULL);
                return error;
@@ -1381,7 +1382,6 @@
        uint32_t old_hash, new_hash;
        struct vcache_key old_vcache_key, new_vcache_key;
        vnode_impl_t *vip, *new_vip;
-       struct vnode *new_vp;
 
        old_vcache_key.vk_mount = mp;
        old_vcache_key.vk_key = old_key;
@@ -1395,16 +1395,12 @@
 
        new_vip = vcache_alloc();
        new_vip->vi_key = new_vcache_key;
-       new_vp = VIMPL_TO_VNODE(new_vip);
 
        /* Insert locked new node used as placeholder. */
        mutex_enter(&vcache_lock);
        vip = vcache_hash_lookup(&new_vcache_key, new_hash);
        if (vip != NULL) {
-               mutex_enter(new_vp->v_interlock);
-               VSTATE_CHANGE(new_vp, VS_LOADING, VS_RECLAIMED);
-               mutex_exit(&vcache_lock);
-               vrelel(new_vp, 0);
+               vcache_dealloc(new_vip);
                return EEXIST;
        }
        SLIST_INSERT_HEAD(&vcache_hashtab[new_hash & vcache_hashmask],
@@ -1456,6 +1452,7 @@
        new_vp = VIMPL_TO_VNODE(new_vip);
        mutex_enter(new_vp->v_interlock);
        VSTATE_ASSERT(VIMPL_TO_VNODE(new_vip), VS_LOADING);
+       mutex_exit(new_vp->v_interlock);
 
        /* Rekey old node and put it onto its new hashlist. */
        vip->vi_key = new_vcache_key;
@@ -1469,9 +1466,7 @@
        /* Remove new node used as placeholder. */
        SLIST_REMOVE(&vcache_hashtab[new_hash & vcache_hashmask],
            new_vip, vnode_impl, vi_hash);
-       VSTATE_CHANGE(new_vp, VS_LOADING, VS_RECLAIMED);
-       mutex_exit(&vcache_lock);
-       vrelel(new_vp, 0);
+       vcache_dealloc(new_vip);
 }
 
 /*



Home | Main Index | Thread Index | Old Index