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