zfs: getnewvnode_reserve must be called outside of a zfs transaction
Otherwise we could run into the following deadlock. A thread has a transaction open and assigned to a transaction group. That would prevent the transaction group from be quiesced and synced. The thread is blocked in getnewvnode_reserve waiting for a vnode to a be reclaimed. vnlru thread is blocked trying to enter ZFS VOP because a filesystem is suspended by an ongoing rollback or receive operation. In its turn the operation is waiting for the current transaction group to be synced. zfs_zget is always used outside of active transactions, but zfs_mknode is always used in a transaction context. Thus, we hoist getnewvnode_reserve from zfs_mknode to its callers. While there, assert that ZFS always calls getnewvnode while having a vnode reserved. Reported by: adrian Tested by: adrian MFC after: 17 days Sponsored by: HybridCluster
This commit is contained in:
parent
f9bc6dc89c
commit
97986ccb0b
@ -951,6 +951,8 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr)
|
||||
return (SET_ERROR(EDQUOT));
|
||||
}
|
||||
|
||||
getnewvnode_reserve(1);
|
||||
|
||||
tx = dmu_tx_create(zfsvfs->z_os);
|
||||
dmu_tx_hold_sa_create(tx, acl_ids.z_aclp->z_acl_bytes +
|
||||
ZFS_SA_BASE_ATTR_SIZE);
|
||||
@ -985,6 +987,8 @@ zfs_make_xattrdir(znode_t *zp, vattr_t *vap, vnode_t **xvpp, cred_t *cr)
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
dmu_tx_commit(tx);
|
||||
|
||||
getnewvnode_drop_reserve();
|
||||
|
||||
*xvpp = ZTOV(xzp);
|
||||
|
||||
return (0);
|
||||
|
@ -1625,6 +1625,9 @@ zfs_create(vnode_t *dvp, char *name, vattr_t *vap, int excl, int mode,
|
||||
return (error);
|
||||
}
|
||||
}
|
||||
|
||||
getnewvnode_reserve(1);
|
||||
|
||||
top:
|
||||
*vpp = NULL;
|
||||
|
||||
@ -1653,6 +1656,7 @@ top:
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
if (strcmp(name, "..") == 0)
|
||||
error = SET_ERROR(EISDIR);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
@ -1721,6 +1725,7 @@ top:
|
||||
}
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
dmu_tx_abort(tx);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
@ -1787,6 +1792,7 @@ top:
|
||||
}
|
||||
}
|
||||
out:
|
||||
getnewvnode_drop_reserve();
|
||||
if (dl)
|
||||
zfs_dirent_unlock(dl);
|
||||
|
||||
@ -2130,6 +2136,9 @@ zfs_mkdir(vnode_t *dvp, char *dirname, vattr_t *vap, vnode_t **vpp, cred_t *cr,
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
|
||||
getnewvnode_reserve(1);
|
||||
|
||||
/*
|
||||
* First make sure the new directory doesn't exist.
|
||||
*
|
||||
@ -2143,6 +2152,7 @@ top:
|
||||
if (error = zfs_dirent_lock(&dl, dzp, dirname, &zp, zf,
|
||||
NULL, NULL)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
@ -2150,6 +2160,7 @@ top:
|
||||
if (error = zfs_zaccess(dzp, ACE_ADD_SUBDIRECTORY, 0, B_FALSE, cr)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
zfs_dirent_unlock(dl);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
@ -2157,6 +2168,7 @@ top:
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
zfs_dirent_unlock(dl);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (SET_ERROR(EDQUOT));
|
||||
}
|
||||
@ -2189,6 +2201,7 @@ top:
|
||||
}
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
dmu_tx_abort(tx);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
@ -2218,6 +2231,8 @@ top:
|
||||
|
||||
dmu_tx_commit(tx);
|
||||
|
||||
getnewvnode_drop_reserve();
|
||||
|
||||
zfs_dirent_unlock(dl);
|
||||
|
||||
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
|
||||
@ -4109,6 +4124,9 @@ zfs_symlink(vnode_t *dvp, vnode_t **vpp, char *name, vattr_t *vap, char *link,
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
|
||||
getnewvnode_reserve(1);
|
||||
|
||||
top:
|
||||
/*
|
||||
* Attempt to lock directory; fail if entry already exists.
|
||||
@ -4116,6 +4134,7 @@ top:
|
||||
error = zfs_dirent_lock(&dl, dzp, name, &zp, zflg, NULL, NULL);
|
||||
if (error) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
@ -4123,6 +4142,7 @@ top:
|
||||
if (error = zfs_zaccess(dzp, ACE_ADD_FILE, 0, B_FALSE, cr)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
zfs_dirent_unlock(dl);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
@ -4130,6 +4150,7 @@ top:
|
||||
if (zfs_acl_ids_overquota(zfsvfs, &acl_ids)) {
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
zfs_dirent_unlock(dl);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (SET_ERROR(EDQUOT));
|
||||
}
|
||||
@ -4157,6 +4178,7 @@ top:
|
||||
}
|
||||
zfs_acl_ids_free(&acl_ids);
|
||||
dmu_tx_abort(tx);
|
||||
getnewvnode_drop_reserve();
|
||||
ZFS_EXIT(zfsvfs);
|
||||
return (error);
|
||||
}
|
||||
@ -4195,6 +4217,8 @@ top:
|
||||
|
||||
dmu_tx_commit(tx);
|
||||
|
||||
getnewvnode_drop_reserve();
|
||||
|
||||
zfs_dirent_unlock(dl);
|
||||
|
||||
if (zfsvfs->z_os->os_sync == ZFS_SYNC_ALWAYS)
|
||||
|
@ -624,6 +624,8 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz,
|
||||
|
||||
zp = kmem_cache_alloc(znode_cache, KM_SLEEP);
|
||||
|
||||
KASSERT(td->td_vp_reserv > 0,
|
||||
("zfs_znode_alloc: getnewvnode without any vnodes reserved"));
|
||||
error = getnewvnode("zfs", zfsvfs->z_parent->z_vfs, &zfs_vnodeops, &vp);
|
||||
if (error != 0) {
|
||||
kmem_cache_free(znode_cache, zp);
|
||||
@ -830,7 +832,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
|
||||
}
|
||||
}
|
||||
|
||||
getnewvnode_reserve(1);
|
||||
ZFS_OBJ_HOLD_ENTER(zfsvfs, obj);
|
||||
VERIFY(0 == sa_buf_hold(zfsvfs->z_os, obj, NULL, &db));
|
||||
|
||||
@ -1016,7 +1017,6 @@ zfs_mknode(znode_t *dzp, vattr_t *vap, dmu_tx_t *tx, cred_t *cr,
|
||||
KASSERT(err == 0, ("insmntque() failed: error %d", err));
|
||||
}
|
||||
ZFS_OBJ_HOLD_EXIT(zfsvfs, obj);
|
||||
getnewvnode_drop_reserve();
|
||||
}
|
||||
|
||||
/*
|
||||
|
Loading…
x
Reference in New Issue
Block a user