summaryrefslogtreecommitdiffstats
path: root/module/zfs/zfs_vfsops.c
diff options
context:
space:
mode:
authorBrian Behlendorf <[email protected]>2014-01-08 10:25:42 -0800
committerBrian Behlendorf <[email protected]>2014-01-09 15:54:08 -0800
commitfd23720ae14dca926800ae70e6c8f4b4f82efc08 (patch)
tree3acde6613c84ed21c324f155445f36f0b0891639 /module/zfs/zfs_vfsops.c
parent4fcc43790c872139a2e318ebe4100e8404f841c0 (diff)
Drain iput taskq outside z_teardown_lock
It's unsafe to drain the iput taskq while holding the z_teardown_lock as a writer. This is because when the last reference on an inode is dropped it may still have pages which need to be written to disk. This will be done through zpl_writepages which will acquire the z_teardown_lock as a reader in ZFS_ENTER. Therefore, if we're holding the lock as a writer in zfs_sb_teardown the unmount will deadlock. Signed-off-by: Brian Behlendorf <[email protected]> Signed-off-by: Chris Dunlop <[email protected]> Closes #1988
Diffstat (limited to 'module/zfs/zfs_vfsops.c')
-rw-r--r--module/zfs/zfs_vfsops.c16
1 files changed, 8 insertions, 8 deletions
diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c
index c64854d7b..f331a36ea 100644
--- a/module/zfs/zfs_vfsops.c
+++ b/module/zfs/zfs_vfsops.c
@@ -1091,6 +1091,14 @@ zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting)
{
znode_t *zp;
+ /*
+ * If someone has not already unmounted this file system,
+ * drain the iput_taskq to ensure all active references to the
+ * zfs_sb_t have been handled only then can it be safely destroyed.
+ */
+ if (zsb->z_os)
+ taskq_wait(dsl_pool_iput_taskq(dmu_objset_pool(zsb->z_os)));
+
rrw_enter(&zsb->z_teardown_lock, RW_WRITER, FTAG);
if (!unmounting) {
@@ -1105,14 +1113,6 @@ zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting)
}
/*
- * If someone has not already unmounted this file system,
- * drain the iput_taskq to ensure all active references to the
- * zfs_sb_t have been handled only then can it be safely destroyed.
- */
- if (zsb->z_os)
- taskq_wait(dsl_pool_iput_taskq(dmu_objset_pool(zsb->z_os)));
-
- /*
* Close the zil. NB: Can't close the zil while zfs_inactive
* threads are blocked as zil_close can call zfs_inactive.
*/