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 <behlendorf1@llnl.gov>
Signed-off-by: Chris Dunlop <chris@onthe.net.au>
Closes #1988
This commit is contained in:
Brian Behlendorf 2014-01-08 10:25:42 -08:00
parent 4fcc43790c
commit fd23720ae1

View File

@ -1091,6 +1091,14 @@ zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting)
{ {
znode_t *zp; 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); rrw_enter(&zsb->z_teardown_lock, RW_WRITER, FTAG);
if (!unmounting) { if (!unmounting) {
@ -1104,14 +1112,6 @@ zfs_sb_teardown(zfs_sb_t *zsb, boolean_t unmounting)
shrink_dcache_sb(zsb->z_parent->z_sb); shrink_dcache_sb(zsb->z_parent->z_sb);
} }
/*
* 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 * Close the zil. NB: Can't close the zil while zfs_inactive
* threads are blocked as zil_close can call zfs_inactive. * threads are blocked as zil_close can call zfs_inactive.