Add workaround about zfs vnode reclaiming deadlock by checking if we don't
ehld ZFS_MUTEX_OBJ already. If we can lock OBJ_MUTEX deffer execution of zfs_zinactive to taskq. Code was inspired by FreeBSD zfs_freebsd_reclaim. XXX. This needs to be fixed after finding final solution for vnode lifecycle.
This commit is contained in:
parent
a4ac032926
commit
afa6bc484e
@ -1949,12 +1949,6 @@ top:
|
||||
|
||||
vnevent_rmdir(vp, dvp, name, ct);
|
||||
|
||||
/*
|
||||
* Grab a lock on the directory to make sure that noone is
|
||||
* trying to add (or lookup) entries while we are removing it.
|
||||
*/
|
||||
rw_enter(&zp->z_name_lock, RW_WRITER);
|
||||
|
||||
/*
|
||||
* Grab a lock on the parent pointer to make sure we play well
|
||||
* with the treewalk and directory rename code.
|
||||
@ -4236,13 +4230,36 @@ zfs_netbsd_inactive(struct vop_inactive_args *ap)
|
||||
return (0);
|
||||
}
|
||||
|
||||
/*
|
||||
* Destroy znode from taskq thread without ZFS_OBJ_MUTEX held.
|
||||
*/
|
||||
static void
|
||||
zfs_reclaim_deferred(void *arg, int pending)
|
||||
{
|
||||
znode_t *zp = arg;
|
||||
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
|
||||
uint64_t z_id = zp->z_id;
|
||||
|
||||
/*
|
||||
* Don't allow a zfs_zget() while were trying to release this znode
|
||||
*/
|
||||
ZFS_OBJ_HOLD_ENTER(zfsvfs, z_id);
|
||||
|
||||
/* Don't need to call ZFS_OBJ_HOLD_EXIT zfs_inactive did thatfor us. */
|
||||
zfs_zinactive(zp);
|
||||
|
||||
}
|
||||
|
||||
static int
|
||||
zfs_netbsd_reclaim(struct vop_reclaim_args *ap)
|
||||
{
|
||||
vnode_t *vp = ap->a_vp;
|
||||
znode_t *zp = VTOZ(vp);
|
||||
zfsvfs_t *zfsvfs;
|
||||
int locked;
|
||||
|
||||
locked = 0;
|
||||
|
||||
ASSERT(zp != NULL);
|
||||
KASSERT(!vn_has_cached_data(vp));
|
||||
|
||||
@ -4251,13 +4268,11 @@ zfs_netbsd_reclaim(struct vop_reclaim_args *ap)
|
||||
mutex_enter(&zp->z_lock);
|
||||
ASSERT(zp->z_phys);
|
||||
|
||||
dprintf("destroying znode %p -- vnode %p -- zp->z_buf = %p\n", zp, ZTOV(zp), zp->z_dbuf);
|
||||
//cpu_Debugger();
|
||||
|
||||
rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_READER);
|
||||
// dprintf("destroying znode %p -- vnode %p -- zp->z_buf = %p\n", zp, ZTOV(zp), zp->z_dbuf);
|
||||
// rw_enter(&zfsvfs->z_teardown_inactive_lock, RW_READER);
|
||||
genfs_node_destroy(vp);
|
||||
cache_purge(vp);
|
||||
// ZTOV(zp) = NULL;
|
||||
|
||||
if (zp->z_dbuf == NULL) {
|
||||
/*
|
||||
* The fs has been unmounted, or we did a
|
||||
@ -4270,8 +4285,34 @@ zfs_netbsd_reclaim(struct vop_reclaim_args *ap)
|
||||
}
|
||||
mutex_exit(&zp->z_lock);
|
||||
|
||||
zfs_zinactive(zp);
|
||||
rw_exit(&zfsvfs->z_teardown_inactive_lock);
|
||||
mutex_enter(&zp->z_lock);
|
||||
if (!zp->z_unlinked) {
|
||||
/*
|
||||
* XXX Hack because ZFS_OBJ_MUTEX is held we can't call zfs_zinactive
|
||||
* now. I need to defer zfs_zinactive to another thread which doesn't hold this mutex.
|
||||
*/
|
||||
locked = MUTEX_HELD(ZFS_OBJ_MUTEX(zfsvfs, zp->z_id)) ? 2 :
|
||||
ZFS_OBJ_HOLD_TRYENTER(zfsvfs, zp->z_id);
|
||||
if (locked == 0) {
|
||||
/*
|
||||
* Lock can't be obtained due to deadlock possibility,
|
||||
* so defer znode destruction.
|
||||
*/
|
||||
taskq_dispatch(system_taskq, zfs_reclaim_deferred, zp, 0);
|
||||
} else {
|
||||
zfs_znode_dmu_fini(zp);
|
||||
/* Our LWP is holding ZFS_OBJ_HELD mutex but it was locked before
|
||||
zfs_zinactive was called therefore we can't release it. */
|
||||
if (locked == 1)
|
||||
ZFS_OBJ_HOLD_EXIT(zfsvfs, zp->z_id);
|
||||
zfs_znode_free(zp);
|
||||
}
|
||||
} else
|
||||
mutex_exit(&zp->z_lock);
|
||||
|
||||
ZTOV(zp) = NULL;
|
||||
vp->v_data = NULL; /* v_data must be NULL for a cleaned vnode. */
|
||||
|
||||
return (0);
|
||||
}
|
||||
|
||||
|
@ -675,7 +675,7 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz)
|
||||
}
|
||||
|
||||
dprintf("zfs_znode_alloc znode %p -- vnode %p\n", zp, vp);
|
||||
dprintf("zfs_znode_alloc Initializing genfs_node at %p\n", vp);
|
||||
dprintf("zfs_znode_alloc z_id %ld\n", zp->z_id);
|
||||
//cpu_Debugger();
|
||||
|
||||
uvm_vnp_setsize(vp, zp->z_phys->zp_size);
|
||||
@ -829,6 +829,9 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
|
||||
|
||||
pzp->zp_mode = MAKEIMODE(vap->va_type, vap->va_mode);
|
||||
if (!(flag & IS_ROOT_NODE)) {
|
||||
dprintf("zfs_mknode parent vp %p - zp %p\n", ZTOV(dzp), dzp);
|
||||
dprintf("Going to lock %p with %ld\n", ZFS_OBJ_MUTEX(zfsvfs, obj), obj);
|
||||
|
||||
ZFS_OBJ_HOLD_ENTER(zfsvfs, obj);
|
||||
*zpp = zfs_znode_alloc(zfsvfs, db, 0);
|
||||
|
||||
@ -952,7 +955,6 @@ again:
|
||||
err = ENOENT;
|
||||
} else {
|
||||
if ((vp = ZTOV(zp)) != NULL) {
|
||||
|
||||
mutex_enter(&vp->v_interlock);
|
||||
mutex_exit(&zp->z_lock);
|
||||
if (vget(vp, LK_INTERLOCK) != 0) {
|
||||
@ -1057,19 +1059,19 @@ zfs_znode_delete(znode_t *zp, dmu_tx_t *tx)
|
||||
zfs_znode_free(zp);
|
||||
}
|
||||
|
||||
/*
|
||||
* zfs_zinactive must be called with ZFS_OBJ_HOLD_ENTER held. And this lock
|
||||
* will be released in zfs_zinactive.
|
||||
*/
|
||||
void
|
||||
zfs_zinactive(znode_t *zp)
|
||||
{
|
||||
vnode_t *vp = ZTOV(zp);
|
||||
zfsvfs_t *zfsvfs = zp->z_zfsvfs;
|
||||
uint64_t z_id = zp->z_id;
|
||||
|
||||
ASSERT(zp->z_dbuf && zp->z_phys);
|
||||
|
||||
/*
|
||||
* Don't allow a zfs_zget() while were trying to release this znode
|
||||
*/
|
||||
ZFS_OBJ_HOLD_ENTER(zfsvfs, z_id);
|
||||
//printf("zfs_zinactive vp %p - zp %p\n", vp, zp);
|
||||
//printf("Going to lock %p with %ld\n", ZFS_OBJ_MUTEX(zfsvfs, z_id), z_id);
|
||||
|
||||
mutex_enter(&zp->z_lock);
|
||||
/*
|
||||
@ -1079,9 +1081,6 @@ zfs_zinactive(znode_t *zp)
|
||||
if (zp->z_unlinked) {
|
||||
mutex_exit(&zp->z_lock);
|
||||
ZFS_OBJ_HOLD_EXIT(zfsvfs, z_id);
|
||||
#ifndef __NetBSD__
|
||||
ASSERT(vp->v_count == 0);
|
||||
#endif
|
||||
zfs_rmnode(zp);
|
||||
return;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user