summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaul Zuchowski <31706010+PaulZ-98@users.noreply.github.com>2021-06-11 20:00:33 -0400
committerTony Hutter <hutter2@llnl.gov>2021-06-23 13:22:15 -0700
commitbd197378e772881357249f49dc7114481d8d1645 (patch)
treec0ca76aeb47e2a183169cb53785836756811546d
parentcd2bb9ca44a25cda1f7b81e7026028899743df7c (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.c15
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: