From: Stoiko Ivanov Date: Fri, 3 Aug 2018 09:51:15 +0000 (+0200) Subject: Cherry-pick fix for deadlock umount/snapentry_expire X-Git-Tag: zfs-2.0.6-bullseye~146 X-Git-Url: https://git.proxmox.com/?p=zfsonlinux.git;a=commitdiff_plain;h=76a4c29ab509065af029b9a18b0dfc92c63d79a3 Cherry-pick fix for deadlock umount/snapentry_expire Signed-off-by: Stoiko Ivanov --- diff --git a/zfs-patches/0005-Fix-deadlock-between-zfs-umount-snapentry_expire.patch b/zfs-patches/0005-Fix-deadlock-between-zfs-umount-snapentry_expire.patch new file mode 100644 index 0000000..5c090d3 --- /dev/null +++ b/zfs-patches/0005-Fix-deadlock-between-zfs-umount-snapentry_expire.patch @@ -0,0 +1,59 @@ +From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 +From: Rohan Puri +Date: Sat, 28 Jul 2018 18:32:12 +0530 +Subject: [PATCH] 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 +Signed-off-by: Rohan Puri +Closes #7751 +Closes #7752 + +(Cherry-picked from fd7265c646f40e364396af5014bbb83e809e124a) +Signed-off-by: Stoiko Ivanov +--- + module/zfs/zfs_ctldir.c | 11 +++++------ + 1 file changed, 5 insertions(+), 6 deletions(-) + +diff --git a/module/zfs/zfs_ctldir.c b/module/zfs/zfs_ctldir.c +index 3b5fb196..14af55c4 100644 +--- a/module/zfs/zfs_ctldir.c ++++ b/module/zfs/zfs_ctldir.c +@@ -358,8 +358,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); +@@ -570,13 +568,14 @@ zfsctl_destroy(zfsvfs_t *zfsvfs) + uint64_t objsetid = dmu_objset_id(zfsvfs->z_os); + + rw_enter(&zfs_snapshot_lock, RW_WRITER); +- if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid)) +- != NULL) { +- zfsctl_snapshot_unmount_cancel(se); ++ se = zfsctl_snapshot_find_by_objsetid(spa, objsetid); ++ if (se != NULL) + zfsctl_snapshot_remove(se); ++ rw_exit(&zfs_snapshot_lock); ++ if (se != NULL) { ++ zfsctl_snapshot_unmount_cancel(se); + zfsctl_snapshot_rele(se); + } +- rw_exit(&zfs_snapshot_lock); + } else if (zfsvfs->z_ctldir) { + iput(zfsvfs->z_ctldir); + zfsvfs->z_ctldir = NULL; diff --git a/zfs-patches/series b/zfs-patches/series index 815e5cd..5d154db 100644 --- a/zfs-patches/series +++ b/zfs-patches/series @@ -2,3 +2,4 @@ 0002-import-with-d-dev-disk-by-id-in-scan-service.patch 0003-always-load-ZFS-module-on-boot.patch 0004-Fix-zpl_mount-deadlock.patch +0005-Fix-deadlock-between-zfs-umount-snapentry_expire.patch