summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorChunwei Chen <[email protected]>2016-07-14 17:31:00 -0700
committerBrian Behlendorf <[email protected]>2016-07-19 09:23:58 -0700
commit1d9b3bd8fb2b633b7523d9f39149d76e24ffb535 (patch)
tree89134ceb0c3809b4c9128da4c27d009705d1d7a2
parentb756ff2445e932a48b3a8a33ca6a0df630c8fc15 (diff)
Wait iput_async before evict_inodes to prevent race
Wait for iput_async before entering evict_inodes in generic_shutdown_super. The reason we must finish before evict_inodes is when lazytime is on, or when zfs_purgedir calls zfs_zget, iput would bump i_count from 0 to 1. This would race with the i_count check in evict_inodes. This means it could destroy the inode while we are still using it. Signed-off-by: Chunwei Chen <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #4854
-rw-r--r--module/zfs/zfs_vfsops.c18
1 files changed, 18 insertions, 0 deletions
diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c
index 3c9a8476c..2f1f44207 100644
--- a/module/zfs/zfs_vfsops.c
+++ b/module/zfs/zfs_vfsops.c
@@ -1415,6 +1415,24 @@ zfs_preumount(struct super_block *sb)
if (zsb)
zfsctl_destroy(sb->s_fs_info);
+ /*
+ * Wait for iput_async before entering evict_inodes in
+ * generic_shutdown_super. The reason we must finish before
+ * evict_inodes is when lazytime is on, or when zfs_purgedir calls
+ * zfs_zget, iput would bump i_count from 0 to 1. This would race
+ * with the i_count check in evict_inodes. This means it could
+ * destroy the inode while we are still using it.
+ *
+ * We wait for two passes. xattr directories in the first pass may
+ * add xattr entries in zfs_purgedir, so in the second pass we wait
+ * for them. We don't use taskq_wait here because it is a pool wide
+ * taskq. Other mounted filesystems can constantly do iput_async
+ * and there's no guarantee when taskq will be empty.
+ */
+ taskq_wait_outstanding(dsl_pool_iput_taskq(
+ dmu_objset_pool(zsb->z_os)), 0);
+ taskq_wait_outstanding(dsl_pool_iput_taskq(
+ dmu_objset_pool(zsb->z_os)), 0);
}
EXPORT_SYMBOL(zfs_preumount);