]>
Commit | Line | Data |
---|---|---|
76a4c29a SI |
1 | From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001 |
2 | From: Rohan Puri <rohan.puri15@gmail.com> | |
3 | Date: Sat, 28 Jul 2018 18:32:12 +0530 | |
4 | Subject: [PATCH] Fix deadlock between zfs umount & snapentry_expire | |
5 | ||
6 | zfs umount -> zfsctl_destroy() takes the zfs_snapshot_lock as a | |
7 | writer and calls zfsctl_snapshot_unmount_cancel(), which waits | |
8 | for snapentry_expire() if present (when snap is automounted). | |
9 | This snapentry_expire() itself then waits for zfs_snapshot_lock | |
10 | as a reader, resulting in a deadlock. | |
11 | ||
12 | The fix is to only hold the zfs_snapshot_lock over the tree | |
13 | lookup and removal. After a successful lookup the lock can | |
14 | be dropped and zfs_snapentry_t will remain valid until the | |
15 | reference taken by the lookup is released. | |
16 | ||
17 | Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> | |
18 | Signed-off-by: Rohan Puri <rohan.puri15@gmail.com> | |
19 | Closes #7751 | |
20 | Closes #7752 | |
21 | ||
22 | (Cherry-picked from fd7265c646f40e364396af5014bbb83e809e124a) | |
f587002c SI |
23 | Signed-off-by: Stoiko Ivanov <s.ivanov@proxmox.com> |
24 | ||
76a4c29a SI |
25 | Signed-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 | ||
30 | diff --git a/module/zfs/zfs_ctldir.c b/module/zfs/zfs_ctldir.c | |
f587002c | 31 | index 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; |