mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2024-12-26 19:19:32 +03:00
Fix zfs_putpage() lock inversion
There exists a lock inversions involving the zfs range lock and the individual page writeback bits which can result in a deadlock. To prevent this we must always manipulate the writeback bit while holding the range lock. The exact deadlock is as follows: ------ Process A ------ ------ Process B ------ zpl_writepages zpl_fallocate write_cache_pages zpl_fallocate_common zpl_putpage zfs_space zfs_putpage (set bit) zfs_freesp zfs_range_lock (wait on lock) zfs_free_range (take lock) [has not yet initiated I/O, truncate_inode_pages_range the bit will not be cleared] wait_on_page_writeback (wait on bit) Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Signed-off-by: Tim Chase <tim@chase2k.com> Signed-off-by: Richard Yao <richard.yao@clusterhq.com> Issue #2976
This commit is contained in:
parent
2d9d57b0fb
commit
74328ee18f
@ -3899,14 +3899,13 @@ zfs_putpage(struct inode *ip, struct page *pp, struct writeback_control *wbc)
|
|||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
rl = zfs_range_lock(zp, pgoff, pglen, RL_WRITER);
|
||||||
|
|
||||||
set_page_writeback(pp);
|
set_page_writeback(pp);
|
||||||
unlock_page(pp);
|
unlock_page(pp);
|
||||||
|
|
||||||
rl = zfs_range_lock(zp, pgoff, pglen, RL_WRITER);
|
|
||||||
tx = dmu_tx_create(zsb->z_os);
|
tx = dmu_tx_create(zsb->z_os);
|
||||||
|
|
||||||
dmu_tx_hold_write(tx, zp->z_id, pgoff, pglen);
|
dmu_tx_hold_write(tx, zp->z_id, pgoff, pglen);
|
||||||
|
|
||||||
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
dmu_tx_hold_sa(tx, zp->z_sa_hdl, B_FALSE);
|
||||||
zfs_sa_upgrade_txholds(tx, zp);
|
zfs_sa_upgrade_txholds(tx, zp);
|
||||||
err = dmu_tx_assign(tx, TXG_NOWAIT);
|
err = dmu_tx_assign(tx, TXG_NOWAIT);
|
||||||
|
Loading…
Reference in New Issue
Block a user