]> git.proxmox.com Git - zfsonlinux.git/blame - zfs-patches/0004-Fix-deadlock-between-zfs-umount-snapentry_expire.patch
update/rebase to spl-0.7.12 with patches from ZOL
[zfsonlinux.git] / zfs-patches / 0004-Fix-deadlock-between-zfs-umount-snapentry_expire.patch
CommitLineData
76a4c29a
SI
1From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
2From: Rohan Puri <rohan.puri15@gmail.com>
3Date: Sat, 28 Jul 2018 18:32:12 +0530
4Subject: [PATCH] Fix deadlock between zfs umount & snapentry_expire
5
6zfs umount -> zfsctl_destroy() takes the zfs_snapshot_lock as a
7writer and calls zfsctl_snapshot_unmount_cancel(), which waits
8for snapentry_expire() if present (when snap is automounted).
9This snapentry_expire() itself then waits for zfs_snapshot_lock
10as a reader, resulting in a deadlock.
11
12The fix is to only hold the zfs_snapshot_lock over the tree
13lookup and removal. After a successful lookup the lock can
14be dropped and zfs_snapentry_t will remain valid until the
15reference taken by the lookup is released.
16
17Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
18Signed-off-by: Rohan Puri <rohan.puri15@gmail.com>
19Closes #7751
20Closes #7752
21
22(Cherry-picked from fd7265c646f40e364396af5014bbb83e809e124a)
f587002c
SI
23Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
24
76a4c29a
SI
25Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com>
26---
27 module/zfs/zfs_ctldir.c | 11 +++++------
28 1 file changed, 5 insertions(+), 6 deletions(-)
29
30diff --git a/module/zfs/zfs_ctldir.c b/module/zfs/zfs_ctldir.c
f587002c 31index 98897fe6..0ab5b4f0 100644
76a4c29a
SI
32--- a/module/zfs/zfs_ctldir.c
33+++ b/module/zfs/zfs_ctldir.c
34@@ -358,8 +358,6 @@ snapentry_expire(void *data)
35 static void
36 zfsctl_snapshot_unmount_cancel(zfs_snapentry_t *se)
37 {
38- ASSERT(RW_LOCK_HELD(&zfs_snapshot_lock));
39-
40 if (taskq_cancel_id(system_delay_taskq, se->se_taskqid) == 0) {
41 se->se_taskqid = TASKQID_INVALID;
42 zfsctl_snapshot_rele(se);
43@@ -570,13 +568,14 @@ zfsctl_destroy(zfsvfs_t *zfsvfs)
44 uint64_t objsetid = dmu_objset_id(zfsvfs->z_os);
45
46 rw_enter(&zfs_snapshot_lock, RW_WRITER);
47- if ((se = zfsctl_snapshot_find_by_objsetid(spa, objsetid))
48- != NULL) {
49- zfsctl_snapshot_unmount_cancel(se);
50+ se = zfsctl_snapshot_find_by_objsetid(spa, objsetid);
51+ if (se != NULL)
52 zfsctl_snapshot_remove(se);
53+ rw_exit(&zfs_snapshot_lock);
54+ if (se != NULL) {
55+ zfsctl_snapshot_unmount_cancel(se);
56 zfsctl_snapshot_rele(se);
57 }
58- rw_exit(&zfs_snapshot_lock);
59 } else if (zfsvfs->z_ctldir) {
60 iput(zfsvfs->z_ctldir);
61 zfsvfs->z_ctldir = NULL;