Fix deadlock between zfs umount & snapentry_expire
zfs umount -> zfsctl_destroy() takes the zfs_snapshot_lock as a writer and calls zfsctl_snapshot_unmount_cancel(), which waits for snapentry_expire() if present (when snap is automounted). This snapentry_expire() itself then waits for zfs_snapshot_lock as a reader, resulting in a deadlock. The fix is to only hold the zfs_snapshot_lock over the tree lookup and removal. After a successful lookup the lock can be dropped and zfs_snapentry_t will remain valid until the reference taken by the lookup is released. Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Rohan Puri <rohan.puri15@gmail.com> Closes #7751 Closes #7752
This commit is contained in:
parent
492f64e941
commit
fd7265c646
|
@ -355,8 +355,6 @@ snapentry_expire(void *data)
|
||||||
static void
|
static void
|
||||||
zfsctl_snapshot_unmount_cancel(zfs_snapentry_t *se)
|
zfsctl_snapshot_unmount_cancel(zfs_snapentry_t *se)
|
||||||
{
|
{
|
||||||
ASSERT(RW_LOCK_HELD(&zfs_snapshot_lock));
|
|
||||||
|
|
||||||
if (taskq_cancel_id(system_delay_taskq, se->se_taskqid) == 0) {
|
if (taskq_cancel_id(system_delay_taskq, se->se_taskqid) == 0) {
|
||||||
se->se_taskqid = TASKQID_INVALID;
|
se->se_taskqid = TASKQID_INVALID;
|
||||||
zfsctl_snapshot_rele(se);
|
zfsctl_snapshot_rele(se);
|
||||||
|
@ -567,13 +565,14 @@ zfsctl_destroy(zfsvfs_t *zfsvfs)
|
||||||
uint64_t objsetid = dmu_objset_id(zfsvfs->z_os);
|
uint64_t objsetid = dmu_objset_id(zfsvfs->z_os);
|
||||||
|
|
||||||
rw_enter(&zfs_snapshot_lock, RW_WRITER);
|
rw_enter(&zfs_snapshot_lock, RW_WRITER);
|
||||||
if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid))
|
se = zfsctl_snapshot_find_by_objsetid(spa, objsetid);
|
||||||
!= NULL) {
|
if (se != NULL)
|
||||||
zfsctl_snapshot_unmount_cancel(se);
|
|
||||||
zfsctl_snapshot_remove(se);
|
zfsctl_snapshot_remove(se);
|
||||||
|
rw_exit(&zfs_snapshot_lock);
|
||||||
|
if (se != NULL) {
|
||||||
|
zfsctl_snapshot_unmount_cancel(se);
|
||||||
zfsctl_snapshot_rele(se);
|
zfsctl_snapshot_rele(se);
|
||||||
}
|
}
|
||||||
rw_exit(&zfs_snapshot_lock);
|
|
||||||
} else if (zfsvfs->z_ctldir) {
|
} else if (zfsvfs->z_ctldir) {
|
||||||
iput(zfsvfs->z_ctldir);
|
iput(zfsvfs->z_ctldir);
|
||||||
zfsvfs->z_ctldir = NULL;
|
zfsvfs->z_ctldir = NULL;
|
||||||
|
|
Loading…
Reference in New Issue