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 <tuxoko@gmail.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #2869
This commit is contained in:
parent
97771edaca
commit
cafbd2aca3
|
@ -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);
|
||||
|
||||
|
|
Loading…
Reference in New Issue