]> git.proxmox.com Git - mirror_zfs.git/commitdiff
Wait iput_async before evict_inodes to prevent race
authorChunwei Chen <david.chen@osnexus.com>
Fri, 15 Jul 2016 00:31:00 +0000 (17:31 -0700)
committerBrian Behlendorf <behlendorf1@llnl.gov>
Tue, 19 Jul 2016 16:23:58 +0000 (09:23 -0700)
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 <david.chen@osnexus.com>
Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov>
Closes #4854

module/zfs/zfs_vfsops.c

index 3c9a8476c4762ba17207bbdefb4e4c04383b0bf5..2f1f44207b69ee944cb1822905f3a17dda028ee8 100644 (file)
@@ -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);