summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authortuxoko <[email protected]>2015-09-01 20:02:48 +0800
committerBrian Behlendorf <[email protected]>2015-09-01 10:17:57 -0700
commitcafbd2aca3fd17be78577348d9661f4142d1eb70 (patch)
treea9f9784844d3c5d2cfbafb97e541b6b0aa57a26f
parent97771edaca2cac5905571f1355dd2b6256a306b4 (diff)
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 <[email protected]> Signed-off-by: Brian Behlendorf <[email protected]> Closes #2869
-rw-r--r--module/zfs/zfs_vnops.c13
1 files 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);