From cafbd2aca3fd17be78577348d9661f4142d1eb70 Mon Sep 17 00:00:00 2001 From: tuxoko Date: Tue, 1 Sep 2015 20:02:48 +0800 Subject: [PATCH] Check for RW_WRITE_HELD in zfs_inactive Before read locking z_teardown_inactive_lock, we need to check if we have already had write lock on it. Otherwise, we would deadlock on ourself when doing rollback: zfs_ioc_rollback ->zfs_suspend_fs (z_teardown_inactive_lock, RW_WRITER) ->zfs_resume_fs->zfs_rezget->zfs_iput_async->iput-> ... ->zfs_inactive (z_teardown_inactive_lock, RW_READER) Signed-off-by: Chunwei Chen Signed-off-by: Brian Behlendorf Closes #2869 --- module/zfs/zfs_vnops.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index 2292ff652..53d02a3aa 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -4096,10 +4096,16 @@ zfs_inactive(struct inode *ip) znode_t *zp = ITOZ(ip); zfs_sb_t *zsb = ITOZSB(ip); int error; + int need_unlock = 0; - rw_enter(&zsb->z_teardown_inactive_lock, RW_READER); + /* Only read lock if we haven't already write locked, e.g. rollback */ + if (!RW_WRITE_HELD(&zsb->z_teardown_inactive_lock)) { + need_unlock = 1; + rw_enter(&zsb->z_teardown_inactive_lock, RW_READER); + } if (zp->z_sa_hdl == NULL) { - rw_exit(&zsb->z_teardown_inactive_lock); + if (need_unlock) + rw_exit(&zsb->z_teardown_inactive_lock); return; } @@ -4122,7 +4128,8 @@ zfs_inactive(struct inode *ip) } zfs_zinactive(zp); - rw_exit(&zsb->z_teardown_inactive_lock); + if (need_unlock) + rw_exit(&zsb->z_teardown_inactive_lock); } EXPORT_SYMBOL(zfs_inactive);