Source-Changes-HG archive

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

[src/trunk]: src/sys Use vnode state to replace VI_MARKER, VI_CHANGING, VI_XL...



details:   https://anonhg.NetBSD.org/src/rev/23d49bbe673c
branches:  trunk
changeset: 345430:23d49bbe673c
user:      hannken <hannken%NetBSD.org@localhost>
date:      Thu May 26 11:09:55 2016 +0000

description:
Use vnode state to replace VI_MARKER, VI_CHANGING, VI_XLOCK and VI_CLEAN.

Presented on tech-kern@

diffstat:

 sys/kern/vfs_vnode.c |  359 +++++++++++++++++++++++---------------------------
 sys/sys/vnode.h      |   15 +-
 2 files changed, 164 insertions(+), 210 deletions(-)

diffs (truncated from 897 to 300 lines):

diff -r f96e3ae9ff1f -r 23d49bbe673c sys/kern/vfs_vnode.c
--- a/sys/kern/vfs_vnode.c      Thu May 26 11:08:44 2016 +0000
+++ b/sys/kern/vfs_vnode.c      Thu May 26 11:09:55 2016 +0000
@@ -1,4 +1,4 @@
-/*     $NetBSD: vfs_vnode.c,v 1.51 2016/05/26 11:08:44 hannken Exp $   */
+/*     $NetBSD: vfs_vnode.c,v 1.52 2016/05/26 11:09:55 hannken Exp $   */
 
 /*-
  * Copyright (c) 1997-2011 The NetBSD Foundation, Inc.
@@ -92,6 +92,49 @@
  *     or cleaned via vclean(9), which calls VOP_RECLAIM(9) to disassociate
  *     underlying file system from the vnode, and finally destroyed.
  *
+ * Vnode state
+ *
+ *     Vnode is always in one of six states:
+ *     - MARKER        This is a marker vnode to help list traversal.  It
+ *                     will never change its state.
+ *     - LOADING       Vnode is associating underlying file system and not
+ *                     yet ready to use.
+ *     - ACTIVE        Vnode has associated underlying file system and is
+ *                     ready to use.
+ *     - BLOCKED       Vnode is active but cannot get new references.
+ *     - RECLAIMING    Vnode is disassociating from the underlying file
+ *                     system.
+ *     - RECLAIMED     Vnode has disassociated from underlying file system
+ *                     and is dead.
+ *
+ *     Valid state changes are:
+ *     LOADING -> ACTIVE
+ *                     Vnode has been initialised in vcache_get() or
+ *                     vcache_new() and is ready to use.
+ *     ACTIVE -> RECLAIMING
+ *                     Vnode starts disassociation from underlying file
+ *                     system in vclean().
+ *     RECLAIMING -> RECLAIMED
+ *                     Vnode finished disassociation from underlying file
+ *                     system in vclean().
+ *     ACTIVE -> BLOCKED
+ *                     Either vcache_rekey*() is changing the vnode key or
+ *                     vrelel() is about to call VOP_INACTIVE().
+ *     BLOCKED -> ACTIVE
+ *                     The block condition is over.
+ *     LOADING -> RECLAIMED
+ *                     Either vcache_get() or vcache_new() failed to
+ *                     associate the underlying file system or vcache_rekey*()
+ *                     drops a vnode used as placeholder.
+ *
+ *     Of these states LOADING, BLOCKED and RECLAIMING are intermediate
+ *     and it is possible to wait for state change.
+ *
+ *     State is protected with v_interlock with one exception:
+ *     to change from LOADING both v_interlock and vcache.lock must be held
+ *     so it is possible to check "state == LOADING" without holding
+ *     v_interlock.  See vcache_get() for details.
+ *
  * Reference counting
  *
  *     Vnode is considered active, if reference count (vnode_t::v_usecount)
@@ -109,14 +152,10 @@
  *     Changing the usecount from a non-zero value to a non-zero value can
  *     safely be done using atomic operations, without the interlock held.
  *
- *     Note: if VI_CLEAN is set, vnode_t::v_interlock will be released while
- *     mntvnode_lock is still held.
- *
- *     See PR 41374.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.51 2016/05/26 11:08:44 hannken Exp $");
+__KERNEL_RCSID(0, "$NetBSD: vfs_vnode.c,v 1.52 2016/05/26 11:09:55 hannken Exp $");
 
 #define _VFS_VNODE_PRIVATE
 
@@ -146,7 +185,6 @@
 
 /* Flags to vrelel. */
 #define        VRELEL_ASYNC_RELE       0x0001  /* Always defer to vrele thread. */
-#define        VRELEL_CHANGING_SET     0x0002  /* VI_CHANGING set by caller. */
 
 enum vcache_state {
        VN_MARKER,      /* Stable, used as marker. Will not change. */
@@ -162,10 +200,9 @@
        size_t vk_key_len;
 };
 struct vcache_node {
-       struct vnode vn_data;
+       struct vnode vn_vnode;
        enum vcache_state vn_state;
        SLIST_ENTRY(vcache_node) vn_hash;
-       struct vnode *vn_vnode;
        struct vcache_key vn_key;
 };
 
@@ -211,7 +248,6 @@
 static void            vrele_thread(void *);
 static void            vnpanic(vnode_t *, const char *, ...)
     __printflike(2, 3);
-static void            vwait(vnode_t *, int);
 
 /* Routines having to do with the management of the vnode table. */
 extern struct mount    *dead_rootmount;
@@ -253,7 +289,7 @@
 #define VSTATE_ASSERT(vp, state) \
        vstate_assert((vp), (state), __func__, __LINE__)
 
-static void __unused
+static void
 vstate_assert(vnode_t *vp, enum vcache_state state, const char *func, int line)
 {
        struct vcache_node *node = VP_TO_VN(vp);
@@ -266,7 +302,7 @@
            vstate_name(node->vn_state), vstate_name(state), func, line);
 }
 
-static enum vcache_state __unused
+static enum vcache_state
 vstate_assert_get(vnode_t *vp, const char *func, int line)
 {
        struct vcache_node *node = VP_TO_VN(vp);
@@ -279,7 +315,7 @@
        return node->vn_state;
 }
 
-static void __unused
+static void
 vstate_assert_wait_stable(vnode_t *vp, const char *func, int line)
 {
        struct vcache_node *node = VP_TO_VN(vp);
@@ -297,7 +333,7 @@
                    vstate_name(node->vn_state), func, line);
 }
 
-static void __unused
+static void
 vstate_assert_change(vnode_t *vp, enum vcache_state from, enum vcache_state to,
     const char *func, int line)
 {
@@ -334,7 +370,7 @@
        vstate_wait_stable((vp))
 #define VSTATE_ASSERT(vp, state)
 
-static void __unused
+static void
 vstate_wait_stable(vnode_t *vp)
 {
        struct vcache_node *node = VP_TO_VN(vp);
@@ -343,7 +379,7 @@
                cv_wait(&vp->v_cv, vp->v_interlock);
 }
 
-static void __unused
+static void
 vstate_change(vnode_t *vp, enum vcache_state from, enum vcache_state to)
 {
        struct vcache_node *node = VP_TO_VN(vp);
@@ -399,7 +435,7 @@
        uvm_obj_init(&vp->v_uobj, &uvm_vnodeops, true, 0);
        vp->v_mount = mp;
        vp->v_type = VBAD;
-       vp->v_iflag = VI_MARKER;
+       node->vn_state = VN_MARKER;
 
        return vp;
 }
@@ -413,7 +449,7 @@
        struct vcache_node *node;
 
        node = VP_TO_VN(vp);
-       KASSERT(ISSET(vp->v_iflag, VI_MARKER));
+       KASSERT(node->vn_state == VN_MARKER);
        uvm_obj_destroy(&vp->v_uobj, true);
        pool_cache_put(vcache.pool, node);
 }
@@ -425,7 +461,7 @@
 vnis_marker(vnode_t *vp)
 {
 
-       return (ISSET(vp->v_iflag, VI_MARKER));
+       return (VP_TO_VN(vp)->vn_state == VN_MARKER);
 }
 
 /*
@@ -452,7 +488,6 @@
                 * lists.
                 */
                KASSERT(vp->v_usecount == 0);
-               KASSERT((vp->v_iflag & VI_CLEAN) == 0);
                KASSERT(vp->v_freelisthd == listhd);
 
                if (vn_lock(vp, LK_EXCLUSIVE | LK_NOWAIT) != 0)
@@ -461,7 +496,6 @@
                        VOP_UNLOCK(vp);
                        continue;
                }
-               KASSERT((vp->v_iflag & VI_XLOCK) == 0);
                mp = vp->v_mount;
                if (fstrans_start_nowait(mp, FSTRANS_SHARED) != 0) {
                        mutex_exit(vp->v_interlock);
@@ -493,10 +527,8 @@
         * before doing this.
         */
        vp->v_usecount = 1;
-       KASSERT((vp->v_iflag & VI_CHANGING) == 0);
-       vp->v_iflag |= VI_CHANGING;
        vclean(vp);
-       vrelel(vp, VRELEL_CHANGING_SET);
+       vrelel(vp, 0);
        fstrans_done(mp);
 
        return 0;
@@ -552,21 +584,22 @@
 
 /*
  * vget: get a particular vnode from the free list, increment its reference
- * count and lock it.
+ * count and return it.
  *
- * => Should be called with v_interlock held.
+ * => Must be called with v_interlock held.
  *
- * If VI_CHANGING is set, the vnode may be eliminated in vgone()/vclean().
+ * If state is VN_RECLAIMING, the vnode may be eliminated in vgone()/vclean().
  * In that case, we cannot grab the vnode, so the process is awakened when
  * the transition is completed, and an error returned to indicate that the
  * vnode is no longer usable.
+ *
+ * If state is VN_LOADING or VN_BLOCKED, wait until the vnode enters a
+ * stable state (VN_ACTIVE or VN_RECLAIMED).
  */
 int
 vget(vnode_t *vp, int flags, bool waitok)
 {
-       int error = 0;
 
-       KASSERT((vp->v_iflag & VI_MARKER) == 0);
        KASSERT(mutex_owned(vp->v_interlock));
        KASSERT((flags & ~LK_NOWAIT) == 0);
        KASSERT(waitok == ((flags & LK_NOWAIT) == 0));
@@ -587,24 +620,24 @@
         * for the change to complete and take care not to return
         * a clean vnode.
         */
-       if ((vp->v_iflag & VI_CHANGING) != 0) {
-               if ((flags & LK_NOWAIT) != 0) {
-                       vrelel(vp, 0);
-                       return EBUSY;
-               }
-               vwait(vp, VI_CHANGING);
-               if ((vp->v_iflag & VI_CLEAN) != 0) {
-                       vrelel(vp, 0);
-                       return ENOENT;
-               }
+       if (! ISSET(flags, LK_NOWAIT))
+               VSTATE_WAIT_STABLE(vp);
+       if (VSTATE_GET(vp) == VN_RECLAIMED) {
+               vrelel(vp, 0);
+               return ENOENT;
+       } else if (VSTATE_GET(vp) != VN_ACTIVE) {
+               KASSERT(ISSET(flags, LK_NOWAIT));
+               vrelel(vp, 0);
+               return EBUSY;
        }
 
        /*
         * Ok, we got it in good shape.
         */
-       KASSERT((vp->v_iflag & VI_CLEAN) == 0);
+       VSTATE_ASSERT(vp, VN_ACTIVE);
        mutex_exit(vp->v_interlock);
-       return error;
+
+       return 0;
 }
 
 /*
@@ -614,8 +647,6 @@
 vput(vnode_t *vp)
 {
 
-       KASSERT((vp->v_iflag & VI_MARKER) == 0);
-
        VOP_UNLOCK(vp);
        vrele(vp);
 }
@@ -652,11 +683,10 @@
        int error;
 
        KASSERT(mutex_owned(vp->v_interlock));
-       KASSERT((vp->v_iflag & VI_MARKER) == 0);
        KASSERT(vp->v_freelisthd == NULL);
 
        if (__predict_false(vp->v_op == dead_vnodeop_p &&
-           (vp->v_iflag & (VI_CLEAN|VI_XLOCK)) == 0)) {
+           VSTATE_GET(vp) != VN_RECLAIMED)) {
                vnpanic(vp, "dead but not clean");
        }
 
@@ -665,11 +695,6 @@



Home | Main Index | Thread Index | Old Index