Skip to content

Commit

Permalink
Fix deadlock between zfs umount & snapentry_expire
Browse files Browse the repository at this point in the history
zfs umount -> zfsctl_destroy() takes zfs_snapshot_lock WRITER &
calls zfsctl_snapshot_unmount_cancel() which waits for
snapentry_expire() if present(only when snap is automounted).
This snapentry_expire() itself then waits for zfs_snapshot_lock
READER, resulting in a deadlock.

Fix is, in zfsctl_destroy() do avl_tree lookup & removal with
WRITER zfs_snapshot_lock & leave this lock before
zfsctl_snapshot_unmount_cancel() call, since the validity of se
is protected by se->se_refcount.
Also remove the corresponding lock assertion from
zfsctl_snapshot_unmount_cancel() too.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Rohan Puri <rohan.puri15@gmail.com>
Closes openzfs#7751
  • Loading branch information
rohan-puri committed Aug 1, 2018
1 parent fb7307b commit 8e4d086
Showing 1 changed file with 4 additions and 4 deletions.
8 changes: 4 additions & 4 deletions module/zfs/zfs_ctldir.c
Original file line number Diff line number Diff line change
Expand Up @@ -355,8 +355,6 @@ snapentry_expire(void *data)
static void
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) {
se->se_taskqid = TASKQID_INVALID;
zfsctl_snapshot_rele(se);
Expand Down Expand Up @@ -569,11 +567,13 @@ zfsctl_destroy(zfsvfs_t *zfsvfs)
rw_enter(&zfs_snapshot_lock, RW_WRITER);
if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid))
!= NULL) {
zfsctl_snapshot_unmount_cancel(se);
zfsctl_snapshot_remove(se);
zfsctl_snapshot_rele(se);
}
rw_exit(&zfs_snapshot_lock);
if (se) {
zfsctl_snapshot_unmount_cancel(se);
zfsctl_snapshot_rele(se);
}
} else if (zfsvfs->z_ctldir) {
iput(zfsvfs->z_ctldir);
zfsvfs->z_ctldir = NULL;
Expand Down

0 comments on commit 8e4d086

Please sign in to comment.