Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Do not hash unlinked inodes in zfs_znode_alloc #12210

Merged
merged 1 commit into from
Jun 12, 2021

Conversation

PaulZ-98
Copy link
Contributor

@PaulZ-98 PaulZ-98 commented Jun 9, 2021

Motivation and Context

Fix panic in zfs_znode_alloc

When zfs_suspend_fs is doing zrele (iput) in an async fashion, and zfs_resume_fs unlinked drain processing tries to hash an inode that is still hashed, then VERIFY3S(insert_inode_locked(ip), ==, 0 will fail, and we panic.

#9741
#11223
#11648

Description

In zfs_znode_alloc we always hash inodes. If the znode is unlinked, we do not need to hash it. This fixes the problem where zfs_suspend_fs is doing zrele (iput) in an async fashion, and zfs_resume_fs unlinked drain processing tries to hash an inode that could still be hashed, resulting in a panic.

How Has This Been Tested?

See #9741 for the reproducer code change and script. With the fix in place, the reproducer no longer produces the panic.

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)
  • Performance enhancement (non-breaking change which improves efficiency)
  • Code cleanup (non-breaking change which makes code smaller or more readable)
  • Breaking change (fix or feature that would cause existing functionality to change)
  • Library ABI change (libzfs, libzfs_core, libnvpair, libuutil and libzfsbootenv)
  • Documentation (a change to man pages or other documentation)

Checklist:

@behlendorf behlendorf added the Status: Code Review Needed Ready for review and testing label Jun 9, 2021
In zfs_znode_alloc we always hash inodes.  If the
znode is unlinked, we do not need to hash it.  This
fixes the problem where zfs_suspend_fs is doing zrele
(iput) in an async fashion, and zfs_resume_fs unlinked
drain processing will try to hash an inode that could
still be hashed, resulting in a panic.

Fixes: openzfs#9741
Fixes: openzfs#11223
Fixes: openzfs#11648

Signed-off-by: Paul Zuchowski <pzuchowski@datto.com>
Copy link
Contributor

@behlendorf behlendorf left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since you already have a test case it would be really nice to adapt it to the ZTS test suite. Aside from that, and determining what (if anything) should be done for FreeBSD, this looks good.

module/os/linux/zfs/zfs_znode.c Show resolved Hide resolved
@PaulZ-98
Copy link
Contributor Author

PaulZ-98 commented Jun 9, 2021

Since you already have a test case it would be really nice to adapt it to the ZTS test suite. Aside from that, and determining what (if anything) should be done for FreeBSD, this looks good.

To reproduce this I had to exaggerate the time it takes to do iput. Should I include that too?

--- a/module/os/linux/zfs/zfs_vnops_os.c
+++ b/module/os/linux/zfs/zfs_vnops_os.c
@@ -175,6 +175,8 @@
  *     return (error);                 // done, report error
  */
 
+unsigned long zfs_iput_delay = 0;
+
 /* ARGSUSED */
 int
 zfs_open(struct inode *ip, int mode, int flag, cred_t *cr)
@@ -367,6 +369,16 @@ zfs_write_simple(znode_t *zp, const void *data, size_t len,
        return (error);
 }
 
+static void
+iput_special(struct inode *ip)
+{
+       if (zfs_iput_delay) {
+               zfs_dbgmsg("delayed iput for %lld", ITOZ(ip)->z_id);
+               delay(4 * hz);
+       }
+       iput(ip);
+}
+
 void
 zfs_zrele_async(znode_t *zp)
 {
@@ -384,9 +396,10 @@ zfs_zrele_async(znode_t *zp)
         * For more information on the dangers of a synchronous iput, see the
         * header comment of this file.
         */
+       zfs_dbgmsg("async rele for %lld", (longlong_t)zp->z_id);
        if (!atomic_add_unless(&ip->i_count, -1, 1)) {
                VERIFY(taskq_dispatch(dsl_pool_zrele_taskq(dmu_objset_pool(os)),
-                   (task_func_t *)iput, ip, TQ_SLEEP) != TASKQID_INVALID);
+                   (task_func_t *)iput_special, ip, TQ_SLEEP) != TASKQID_INVALID);
        }
 }
 
@@ -3988,6 +4001,9 @@ EXPORT_SYMBOL(zfs_map);
 /* BEGIN CSTYLED */
 module_param(zfs_delete_blocks, ulong, 0644);
 MODULE_PARM_DESC(zfs_delete_blocks, "Delete files larger than N blocks async");
+
+module_param(zfs_iput_delay, ulong, 0644);
+MODULE_PARM_DESC(zfs_iput_delay, "Delay async zrele (iput)");
 /* END CSTYLED */
 
 #endif

@behlendorf
Copy link
Contributor

Ahh, I see. Well in that case I understand why you opted not to include the test case. Given that, I'm fine with not adding the test case for this.

@behlendorf behlendorf added Status: Accepted Ready to integrate (reviewed, tested) and removed Status: Code Review Needed Ready for review and testing labels Jun 11, 2021
@behlendorf behlendorf merged commit afa7b34 into openzfs:master Jun 12, 2021
@IvanVolosyuk IvanVolosyuk mentioned this pull request Jun 13, 2021
13 tasks
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jun 15, 2021
In zfs_znode_alloc we always hash inodes.  If the
znode is unlinked, we do not need to hash it.  This
fixes the problem where zfs_suspend_fs is doing zrele
(iput) in an async fashion, and zfs_resume_fs unlinked
drain processing will try to hash an inode that could
still be hashed, resulting in a panic.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alan Somers <asomers@gmail.com>
Signed-off-by: Paul Zuchowski <pzuchowski@datto.com>
Closes openzfs#9741
Closes openzfs#11223
Closes openzfs#11648
Closes openzfs#12210
behlendorf pushed a commit that referenced this pull request Jun 16, 2021
In zfs_znode_alloc we always hash inodes.  If the
znode is unlinked, we do not need to hash it.  This
fixes the problem where zfs_suspend_fs is doing zrele
(iput) in an async fashion, and zfs_resume_fs unlinked
drain processing will try to hash an inode that could
still be hashed, resulting in a panic.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alan Somers <asomers@gmail.com>
Signed-off-by: Paul Zuchowski <pzuchowski@datto.com>
Closes #9741
Closes #11223
Closes #11648
Closes #12210
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jun 16, 2021
In zfs_znode_alloc we always hash inodes.  If the
znode is unlinked, we do not need to hash it.  This
fixes the problem where zfs_suspend_fs is doing zrele
(iput) in an async fashion, and zfs_resume_fs unlinked
drain processing will try to hash an inode that could
still be hashed, resulting in a panic.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alan Somers <asomers@gmail.com>
Signed-off-by: Paul Zuchowski <pzuchowski@datto.com>
Closes openzfs#9741
Closes openzfs#11223
Closes openzfs#11648
Closes openzfs#12210
tonyhutter pushed a commit to tonyhutter/zfs that referenced this pull request Jun 17, 2021
In zfs_znode_alloc we always hash inodes.  If the
znode is unlinked, we do not need to hash it.  This
fixes the problem where zfs_suspend_fs is doing zrele
(iput) in an async fashion, and zfs_resume_fs unlinked
drain processing will try to hash an inode that could
still be hashed, resulting in a panic.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alan Somers <asomers@gmail.com>
Signed-off-by: Paul Zuchowski <pzuchowski@datto.com>
Closes openzfs#9741
Closes openzfs#11223
Closes openzfs#11648
Closes openzfs#12210
tonyhutter pushed a commit that referenced this pull request Jun 23, 2021
In zfs_znode_alloc we always hash inodes.  If the
znode is unlinked, we do not need to hash it.  This
fixes the problem where zfs_suspend_fs is doing zrele
(iput) in an async fashion, and zfs_resume_fs unlinked
drain processing will try to hash an inode that could
still be hashed, resulting in a panic.

Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Reviewed-by: Alan Somers <asomers@gmail.com>
Signed-off-by: Paul Zuchowski <pzuchowski@datto.com>
Closes #9741
Closes #11223
Closes #11648
Closes #12210
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Status: Accepted Ready to integrate (reviewed, tested)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants