diff options
author | Paul Zuchowski <31706010+PaulZ-98@users.noreply.github.com> | 2021-06-11 20:00:33 -0400 |
---|---|---|
committer | Tony Hutter <hutter2@llnl.gov> | 2021-06-23 13:22:15 -0700 |
commit | bd197378e772881357249f49dc7114481d8d1645 (patch) | |
tree | c0ca76aeb47e2a183169cb53785836756811546d | |
parent | cd2bb9ca44a25cda1f7b81e7026028899743df7c (diff) |
Do not hash unlinked inodes
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
-rw-r--r-- | module/os/linux/zfs/zfs_znode.c | 15 |
1 files changed, 11 insertions, 4 deletions
diff --git a/module/os/linux/zfs/zfs_znode.c b/module/os/linux/zfs/zfs_znode.c index b33594488..9318cc459 100644 --- a/module/os/linux/zfs/zfs_znode.c +++ b/module/os/linux/zfs/zfs_znode.c @@ -610,17 +610,24 @@ zfs_znode_alloc(zfsvfs_t *zfsvfs, dmu_buf_t *db, int blksz, * number is already hashed for this super block. This can never * happen because the inode numbers map 1:1 with the object numbers. * - * The one exception is rolling back a mounted file system, but in - * this case all the active inode are unhashed during the rollback. + * Exceptions include rolling back a mounted file system, either + * from the zfs rollback or zfs recv command. + * + * Active inodes are unhashed during the rollback, but since zrele + * can happen asynchronously, we can't guarantee they've been + * unhashed. This can cause hash collisions in unlinked drain + * processing so do not hash unlinked znodes. */ - VERIFY3S(insert_inode_locked(ip), ==, 0); + if (links > 0) + VERIFY3S(insert_inode_locked(ip), ==, 0); mutex_enter(&zfsvfs->z_znodes_lock); list_insert_tail(&zfsvfs->z_all_znodes, zp); zfsvfs->z_nr_znodes++; mutex_exit(&zfsvfs->z_znodes_lock); - unlock_new_inode(ip); + if (links > 0) + unlock_new_inode(ip); return (zp); error: |