Changeset View
Changeset View
Standalone View
Standalone View
sys/kern/vfs_subr.c
Show First 20 Lines • Show All 1,755 Lines • ▼ Show 20 Lines | freevnode(struct vnode *vp) | ||||
* The vnode will be returned to the zone where it will | * The vnode will be returned to the zone where it will | ||||
* normally remain until it is needed for another vnode. We | * normally remain until it is needed for another vnode. We | ||||
* need to cleanup (or verify that the cleanup has already | * need to cleanup (or verify that the cleanup has already | ||||
* been done) any residual data left from its current use | * been done) any residual data left from its current use | ||||
* so as not to contaminate the freshly allocated vnode. | * so as not to contaminate the freshly allocated vnode. | ||||
*/ | */ | ||||
CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, vp); | CTR2(KTR_VFS, "%s: destroying the vnode %p", __func__, vp); | ||||
bo = &vp->v_bufobj; | bo = &vp->v_bufobj; | ||||
VNPASS(vp->v_seqc_users == 0, vp); | |||||
VNASSERT(vp->v_data == NULL, vp, ("cleaned vnode isn't")); | VNASSERT(vp->v_data == NULL, vp, ("cleaned vnode isn't")); | ||||
VNPASS(vp->v_holdcnt == VHOLD_NO_SMR, vp); | VNPASS(vp->v_holdcnt == VHOLD_NO_SMR, vp); | ||||
VNASSERT(vp->v_usecount == 0, vp, ("Non-zero use count")); | VNASSERT(vp->v_usecount == 0, vp, ("Non-zero use count")); | ||||
VNASSERT(vp->v_writecount == 0, vp, ("Non-zero write count")); | VNASSERT(vp->v_writecount == 0, vp, ("Non-zero write count")); | ||||
VNASSERT(bo->bo_numoutput == 0, vp, ("Clean vnode has pending I/O's")); | VNASSERT(bo->bo_numoutput == 0, vp, ("Clean vnode has pending I/O's")); | ||||
VNASSERT(bo->bo_clean.bv_cnt == 0, vp, ("cleanbufcnt not 0")); | VNASSERT(bo->bo_clean.bv_cnt == 0, vp, ("cleanbufcnt not 0")); | ||||
VNASSERT(pctrie_is_empty(&bo->bo_clean.bv_root), vp, | VNASSERT(pctrie_is_empty(&bo->bo_clean.bv_root), vp, | ||||
("clean blk trie not empty")); | ("clean blk trie not empty")); | ||||
▲ Show 20 Lines • Show All 2,222 Lines • ▼ Show 20 Lines | vgonel(struct vnode *vp) | ||||
CTR2(KTR_VFS, "%s: vp %p", __func__, vp); | CTR2(KTR_VFS, "%s: vp %p", __func__, vp); | ||||
td = curthread; | td = curthread; | ||||
/* | /* | ||||
* Don't vgonel if we're already doomed. | * Don't vgonel if we're already doomed. | ||||
*/ | */ | ||||
if (vp->v_irflag & VIRF_DOOMED) | if (vp->v_irflag & VIRF_DOOMED) | ||||
return; | return; | ||||
vn_seqc_write_begin_locked(vp); | |||||
vunlazy_gone(vp); | vunlazy_gone(vp); | ||||
vp->v_irflag |= VIRF_DOOMED; | vp->v_irflag |= VIRF_DOOMED; | ||||
/* | /* | ||||
* Check to see if the vnode is in use. If so, we have to call | * Check to see if the vnode is in use. If so, we have to call | ||||
* VOP_CLOSE() and VOP_INACTIVE(). | * VOP_CLOSE() and VOP_INACTIVE(). | ||||
*/ | */ | ||||
active = vp->v_usecount > 0; | active = vp->v_usecount > 0; | ||||
▲ Show 20 Lines • Show All 86 Lines • ▼ Show 20 Lines | vgonel(struct vnode *vp) | ||||
/* | /* | ||||
* Done with purge, reset to the standard lock and invalidate | * Done with purge, reset to the standard lock and invalidate | ||||
* the vnode. | * the vnode. | ||||
*/ | */ | ||||
VI_LOCK(vp); | VI_LOCK(vp); | ||||
vp->v_vnlock = &vp->v_lock; | vp->v_vnlock = &vp->v_lock; | ||||
vp->v_op = &dead_vnodeops; | vp->v_op = &dead_vnodeops; | ||||
vp->v_type = VBAD; | vp->v_type = VBAD; | ||||
vn_seqc_write_end_locked(vp); | |||||
kib: Does it make sense to end seqc_write for reclaimed vnode ?
IMO it should be not, to avoid any… | |||||
} | } | ||||
/* | /* | ||||
* Calculate the total number of references to a special device. | * Calculate the total number of references to a special device. | ||||
*/ | */ | ||||
int | int | ||||
vcount(struct vnode *vp) | vcount(struct vnode *vp) | ||||
{ | { | ||||
Show All 24 Lines | vn_printf(struct vnode *vp, const char *fmt, ...) | ||||
u_int holdcnt; | u_int holdcnt; | ||||
va_start(ap, fmt); | va_start(ap, fmt); | ||||
vprintf(fmt, ap); | vprintf(fmt, ap); | ||||
va_end(ap); | va_end(ap); | ||||
printf("%p: ", (void *)vp); | printf("%p: ", (void *)vp); | ||||
printf("type %s\n", typename[vp->v_type]); | printf("type %s\n", typename[vp->v_type]); | ||||
holdcnt = atomic_load_int(&vp->v_holdcnt); | holdcnt = atomic_load_int(&vp->v_holdcnt); | ||||
printf(" usecount %d, writecount %d, refcount %d", | printf(" usecount %d, writecount %d, refcount %d seqc users %d", | ||||
vp->v_usecount, vp->v_writecount, holdcnt & ~VHOLD_ALL_FLAGS); | vp->v_usecount, vp->v_writecount, holdcnt & ~VHOLD_ALL_FLAGS, | ||||
vp->v_seqc_users); | |||||
switch (vp->v_type) { | switch (vp->v_type) { | ||||
case VDIR: | case VDIR: | ||||
printf(" mountedhere %p\n", vp->v_mountedhere); | printf(" mountedhere %p\n", vp->v_mountedhere); | ||||
break; | break; | ||||
case VCHR: | case VCHR: | ||||
printf(" rdev %p\n", vp->v_rdev); | printf(" rdev %p\n", vp->v_rdev); | ||||
break; | break; | ||||
case VSOCK: | case VSOCK: | ||||
▲ Show 20 Lines • Show All 1,330 Lines • ▼ Show 20 Lines | #ifdef DEBUG_VFS_LOCKS | ||||
if (a->a_tvp == NULL || a->a_tvp->v_vnlock != a->a_fvp->v_vnlock) | if (a->a_tvp == NULL || a->a_tvp->v_vnlock != a->a_fvp->v_vnlock) | ||||
ASSERT_VOP_UNLOCKED(a->a_fvp, "vop_rename: fvp locked"); | ASSERT_VOP_UNLOCKED(a->a_fvp, "vop_rename: fvp locked"); | ||||
/* Check the target. */ | /* Check the target. */ | ||||
if (a->a_tvp) | if (a->a_tvp) | ||||
ASSERT_VOP_LOCKED(a->a_tvp, "vop_rename: tvp not locked"); | ASSERT_VOP_LOCKED(a->a_tvp, "vop_rename: tvp not locked"); | ||||
ASSERT_VOP_LOCKED(a->a_tdvp, "vop_rename: tdvp not locked"); | ASSERT_VOP_LOCKED(a->a_tdvp, "vop_rename: tdvp not locked"); | ||||
#endif | #endif | ||||
/* | |||||
* It may be tempting to add vn_seqc_write_begin/end calls here and | |||||
* in vop_rename_post but that's not going to work out since some | |||||
* filesystems relookup vnodes mid-rename. This is probably a bug. | |||||
* | |||||
* For now filesystems are expected to do the relevant calls after they | |||||
* decide what vnodes to operate on. | |||||
*/ | |||||
if (a->a_tdvp != a->a_fdvp) | if (a->a_tdvp != a->a_fdvp) | ||||
vhold(a->a_fdvp); | vhold(a->a_fdvp); | ||||
if (a->a_tvp != a->a_fvp) | if (a->a_tvp != a->a_fvp) | ||||
vhold(a->a_fvp); | vhold(a->a_fvp); | ||||
vhold(a->a_tdvp); | vhold(a->a_tdvp); | ||||
if (a->a_tvp) | if (a->a_tvp) | ||||
vhold(a->a_tvp); | vhold(a->a_tvp); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 65 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct vop_need_inactive_args *a = ap; | struct vop_need_inactive_args *a = ap; | ||||
ASSERT_VI_LOCKED(a->a_vp, "VOP_NEED_INACTIVE"); | ASSERT_VI_LOCKED(a->a_vp, "VOP_NEED_INACTIVE"); | ||||
} | } | ||||
#endif | #endif | ||||
void | void | ||||
vop_create_pre(void *ap) | |||||
{ | |||||
struct vop_create_args *a; | |||||
struct vnode *dvp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vn_seqc_write_begin(dvp); | |||||
} | |||||
void | |||||
vop_create_post(void *ap, int rc) | vop_create_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_create_args *a = ap; | struct vop_create_args *a; | ||||
struct vnode *dvp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vn_seqc_write_end(dvp); | |||||
if (!rc) | if (!rc) | ||||
VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); | VFS_KNOTE_LOCKED(dvp, NOTE_WRITE); | ||||
} | } | ||||
void | void | ||||
vop_deleteextattr_pre(void *ap) | |||||
{ | |||||
struct vop_deleteextattr_args *a; | |||||
struct vnode *vp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_begin(vp); | |||||
} | |||||
void | |||||
vop_deleteextattr_post(void *ap, int rc) | vop_deleteextattr_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_deleteextattr_args *a = ap; | struct vop_deleteextattr_args *a; | ||||
struct vnode *vp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_end(vp); | |||||
if (!rc) | if (!rc) | ||||
VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); | VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); | ||||
} | } | ||||
void | void | ||||
vop_link_pre(void *ap) | |||||
{ | |||||
struct vop_link_args *a; | |||||
struct vnode *vp, *tdvp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
tdvp = a->a_tdvp; | |||||
vn_seqc_write_begin(vp); | |||||
Not Done Inline ActionsI think that bloking l/l for vp (not tdvp) is not needed. kib: I think that bloking l/l for vp (not tdvp) is not needed. | |||||
vn_seqc_write_begin(tdvp); | |||||
} | |||||
void | |||||
vop_link_post(void *ap, int rc) | vop_link_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_link_args *a = ap; | struct vop_link_args *a; | ||||
struct vnode *vp, *tdvp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
tdvp = a->a_tdvp; | |||||
vn_seqc_write_end(vp); | |||||
vn_seqc_write_end(tdvp); | |||||
if (!rc) { | if (!rc) { | ||||
VFS_KNOTE_LOCKED(a->a_vp, NOTE_LINK); | VFS_KNOTE_LOCKED(vp, NOTE_LINK); | ||||
VFS_KNOTE_LOCKED(a->a_tdvp, NOTE_WRITE); | VFS_KNOTE_LOCKED(tdvp, NOTE_WRITE); | ||||
} | } | ||||
} | } | ||||
void | void | ||||
vop_mkdir_pre(void *ap) | |||||
{ | |||||
struct vop_mkdir_args *a; | |||||
struct vnode *dvp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vn_seqc_write_begin(dvp); | |||||
} | |||||
void | |||||
vop_mkdir_post(void *ap, int rc) | vop_mkdir_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_mkdir_args *a = ap; | struct vop_mkdir_args *a; | ||||
struct vnode *dvp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vn_seqc_write_end(dvp); | |||||
if (!rc) | if (!rc) | ||||
VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE | NOTE_LINK); | VFS_KNOTE_LOCKED(dvp, NOTE_WRITE | NOTE_LINK); | ||||
} | } | ||||
void | void | ||||
vop_mknod_pre(void *ap) | |||||
{ | |||||
struct vop_mknod_args *a; | |||||
struct vnode *dvp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vn_seqc_write_begin(dvp); | |||||
} | |||||
void | |||||
vop_mknod_post(void *ap, int rc) | vop_mknod_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_mknod_args *a = ap; | struct vop_mknod_args *a; | ||||
struct vnode *dvp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vn_seqc_write_end(dvp); | |||||
if (!rc) | if (!rc) | ||||
VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); | VFS_KNOTE_LOCKED(dvp, NOTE_WRITE); | ||||
} | } | ||||
void | void | ||||
vop_reclaim_post(void *ap, int rc) | vop_reclaim_post(void *ap, int rc) | ||||
kibUnsubmitted Not Done Inline ActionsAssert that the vnode in seqc_write ? kib: Assert that the vnode in seqc_write ? | |||||
{ | { | ||||
struct vop_reclaim_args *a = ap; | struct vop_reclaim_args *a = ap; | ||||
if (!rc) | if (!rc) | ||||
VFS_KNOTE_LOCKED(a->a_vp, NOTE_REVOKE); | VFS_KNOTE_LOCKED(a->a_vp, NOTE_REVOKE); | ||||
} | } | ||||
void | void | ||||
vop_remove_pre(void *ap) | |||||
{ | |||||
struct vop_remove_args *a; | |||||
struct vnode *dvp, *vp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_begin(dvp); | |||||
vn_seqc_write_begin(vp); | |||||
} | |||||
void | |||||
vop_remove_post(void *ap, int rc) | vop_remove_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_remove_args *a = ap; | struct vop_remove_args *a; | ||||
struct vnode *dvp, *vp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_end(dvp); | |||||
vn_seqc_write_end(vp); | |||||
if (!rc) { | if (!rc) { | ||||
VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); | VFS_KNOTE_LOCKED(dvp, NOTE_WRITE); | ||||
VFS_KNOTE_LOCKED(a->a_vp, NOTE_DELETE); | VFS_KNOTE_LOCKED(vp, NOTE_DELETE); | ||||
} | } | ||||
} | } | ||||
void | void | ||||
vop_rename_post(void *ap, int rc) | vop_rename_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_rename_args *a = ap; | struct vop_rename_args *a = ap; | ||||
long hint; | long hint; | ||||
Show All 26 Lines | vop_rename_post(void *ap, int rc) | ||||
if (a->a_tvp != a->a_fvp) | if (a->a_tvp != a->a_fvp) | ||||
vdrop(a->a_fvp); | vdrop(a->a_fvp); | ||||
vdrop(a->a_tdvp); | vdrop(a->a_tdvp); | ||||
if (a->a_tvp) | if (a->a_tvp) | ||||
vdrop(a->a_tvp); | vdrop(a->a_tvp); | ||||
} | } | ||||
void | void | ||||
vop_rmdir_pre(void *ap) | |||||
{ | |||||
struct vop_rmdir_args *a; | |||||
struct vnode *dvp, *vp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_begin(dvp); | |||||
vn_seqc_write_begin(vp); | |||||
} | |||||
void | |||||
vop_rmdir_post(void *ap, int rc) | vop_rmdir_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_rmdir_args *a = ap; | struct vop_rmdir_args *a; | ||||
struct vnode *dvp, *vp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_end(dvp); | |||||
vn_seqc_write_end(vp); | |||||
if (!rc) { | if (!rc) { | ||||
VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE | NOTE_LINK); | VFS_KNOTE_LOCKED(dvp, NOTE_WRITE | NOTE_LINK); | ||||
VFS_KNOTE_LOCKED(a->a_vp, NOTE_DELETE); | VFS_KNOTE_LOCKED(vp, NOTE_DELETE); | ||||
} | } | ||||
} | } | ||||
void | void | ||||
vop_setattr_pre(void *ap) | |||||
{ | |||||
struct vop_setattr_args *a; | |||||
struct vnode *vp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_begin(vp); | |||||
} | |||||
void | |||||
vop_setattr_post(void *ap, int rc) | vop_setattr_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_setattr_args *a = ap; | struct vop_setattr_args *a; | ||||
struct vnode *vp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_end(vp); | |||||
if (!rc) | if (!rc) | ||||
VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); | VFS_KNOTE_LOCKED(vp, NOTE_ATTRIB); | ||||
} | } | ||||
void | void | ||||
vop_setacl_pre(void *ap) | |||||
{ | |||||
struct vop_setacl_args *a; | |||||
struct vnode *vp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_begin(vp); | |||||
} | |||||
void | |||||
vop_setacl_post(void *ap, int rc __unused) | |||||
{ | |||||
struct vop_setacl_args *a; | |||||
struct vnode *vp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_end(vp); | |||||
} | |||||
void | |||||
vop_setextattr_pre(void *ap) | |||||
{ | |||||
struct vop_setextattr_args *a; | |||||
struct vnode *vp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_begin(vp); | |||||
} | |||||
void | |||||
vop_setextattr_post(void *ap, int rc) | vop_setextattr_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_setextattr_args *a = ap; | struct vop_setextattr_args *a; | ||||
struct vnode *vp; | |||||
a = ap; | |||||
vp = a->a_vp; | |||||
vn_seqc_write_end(vp); | |||||
if (!rc) | if (!rc) | ||||
VFS_KNOTE_LOCKED(a->a_vp, NOTE_ATTRIB); | VFS_KNOTE_LOCKED(vp, NOTE_ATTRIB); | ||||
} | } | ||||
void | void | ||||
vop_symlink_pre(void *ap) | |||||
{ | |||||
struct vop_symlink_args *a; | |||||
struct vnode *dvp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vn_seqc_write_begin(dvp); | |||||
} | |||||
void | |||||
vop_symlink_post(void *ap, int rc) | vop_symlink_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_symlink_args *a = ap; | struct vop_symlink_args *a; | ||||
struct vnode *dvp; | |||||
a = ap; | |||||
dvp = a->a_dvp; | |||||
vn_seqc_write_end(dvp); | |||||
if (!rc) | if (!rc) | ||||
VFS_KNOTE_LOCKED(a->a_dvp, NOTE_WRITE); | VFS_KNOTE_LOCKED(dvp, NOTE_WRITE); | ||||
} | } | ||||
void | void | ||||
vop_open_post(void *ap, int rc) | vop_open_post(void *ap, int rc) | ||||
{ | { | ||||
struct vop_open_args *a = ap; | struct vop_open_args *a = ap; | ||||
if (!rc) | if (!rc) | ||||
▲ Show 20 Lines • Show All 536 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
struct vnode *vp; | struct vnode *vp; | ||||
/* | /* | ||||
* ops > 0 guarantees there is nobody who can see this vnode | * ops > 0 guarantees there is nobody who can see this vnode | ||||
*/ | */ | ||||
MPASS(mp->mnt_vfs_ops > 0); | MPASS(mp->mnt_vfs_ops > 0); | ||||
vp = mp->mnt_rootvnode; | vp = mp->mnt_rootvnode; | ||||
if (vp != NULL) | |||||
vn_seqc_write_begin(vp); | |||||
mp->mnt_rootvnode = NULL; | mp->mnt_rootvnode = NULL; | ||||
return (vp); | return (vp); | ||||
} | } | ||||
void | void | ||||
vfs_cache_root_set(struct mount *mp, struct vnode *vp) | vfs_cache_root_set(struct mount *mp, struct vnode *vp) | ||||
{ | { | ||||
▲ Show 20 Lines • Show All 279 Lines • ▼ Show 20 Lines | |||||
{ | { | ||||
if ((cnp->cn_flags & NOEXECCHECK) != 0) { | if ((cnp->cn_flags & NOEXECCHECK) != 0) { | ||||
cnp->cn_flags &= ~NOEXECCHECK; | cnp->cn_flags &= ~NOEXECCHECK; | ||||
return (0); | return (0); | ||||
} | } | ||||
return (VOP_ACCESS(vp, VEXEC, cnp->cn_cred, cnp->cn_thread)); | return (VOP_ACCESS(vp, VEXEC, cnp->cn_cred, cnp->cn_thread)); | ||||
} | |||||
void | |||||
vn_seqc_write_begin_locked(struct vnode *vp) | |||||
{ | |||||
ASSERT_VI_LOCKED(vp, __func__); | |||||
VNPASS(vp->v_holdcnt > 0, vp); | |||||
VNPASS(vp->v_seqc_users >= 0, vp); | |||||
vp->v_seqc_users++; | |||||
if (vp->v_seqc_users == 1) | |||||
seqc_sleepable_write_begin(&vp->v_seqc); | |||||
} | |||||
void | |||||
vn_seqc_write_begin(struct vnode *vp) | |||||
{ | |||||
VI_LOCK(vp); | |||||
vn_seqc_write_begin_locked(vp); | |||||
VI_UNLOCK(vp); | |||||
} | |||||
void | |||||
vn_seqc_write_end_locked(struct vnode *vp) | |||||
{ | |||||
ASSERT_VI_LOCKED(vp, __func__); | |||||
VNPASS(vp->v_holdcnt > 0, vp); | |||||
VNPASS(vp->v_seqc_users > 0, vp); | |||||
vp->v_seqc_users--; | |||||
if (vp->v_seqc_users == 0) | |||||
seqc_sleepable_write_end(&vp->v_seqc); | |||||
} | |||||
void | |||||
vn_seqc_write_end(struct vnode *vp) | |||||
{ | |||||
VI_LOCK(vp); | |||||
vn_seqc_write_end_locked(vp); | |||||
VI_UNLOCK(vp); | |||||
} | } |
Does it make sense to end seqc_write for reclaimed vnode ?
IMO it should be not, to avoid any possibility for it to participate in a new lookup.
You might need to indeed end the seqc_write in the vnode destructor.