From b53d1774086c3d69bc96d2b3f06ba6b7b4ff700e Mon Sep 17 00:00:00 2001 From: Chunwei Chen Date: Thu, 14 Jul 2016 17:31:00 -0700 Subject: [PATCH] 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 Signed-off-by: Brian Behlendorf Closes #4854 --- module/zfs/zfs_vfsops.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/module/zfs/zfs_vfsops.c b/module/zfs/zfs_vfsops.c index e1887c2d9045..0cf9815c9ef4 100644 --- a/module/zfs/zfs_vfsops.c +++ b/module/zfs/zfs_vfsops.c @@ -1476,6 +1476,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);