mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2025-01-14 04:00:31 +03:00
dmu_objset_userquota_get_ids uses dn_bonus unsafely
The function dmu_objset_userquota_get_ids() checks and uses dn->dn_bonus outside of dn_struct_rwlock. If the dnode is being freed then the bonus dbuf may be in the process of getting evicted. In this case there is a race that may cause dmu_objset_userquota_get_ids() to access the dbuf after it has been destroyed. To prevent this, ensure that when we are using the bonus dbuf we are either holding a reference on it or have taken dn_struct_rwlock. Signed-off-by: Ned Bass <bass6@llnl.gov> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> Closes #3443
This commit is contained in:
parent
d617648c7f
commit
5f8e1e8505
@ -1314,6 +1314,7 @@ dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx)
|
|||||||
int flags = dn->dn_id_flags;
|
int flags = dn->dn_id_flags;
|
||||||
int error;
|
int error;
|
||||||
boolean_t have_spill = B_FALSE;
|
boolean_t have_spill = B_FALSE;
|
||||||
|
boolean_t have_bonus = B_FALSE;
|
||||||
|
|
||||||
if (!dmu_objset_userused_enabled(dn->dn_objset))
|
if (!dmu_objset_userused_enabled(dn->dn_objset))
|
||||||
return;
|
return;
|
||||||
@ -1325,8 +1326,21 @@ dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx)
|
|||||||
if (before && dn->dn_bonuslen != 0)
|
if (before && dn->dn_bonuslen != 0)
|
||||||
data = DN_BONUS(dn->dn_phys);
|
data = DN_BONUS(dn->dn_phys);
|
||||||
else if (!before && dn->dn_bonuslen != 0) {
|
else if (!before && dn->dn_bonuslen != 0) {
|
||||||
if (dn->dn_bonus) {
|
|
||||||
db = dn->dn_bonus;
|
db = dn->dn_bonus;
|
||||||
|
if (db != NULL) {
|
||||||
|
if (!RW_WRITE_HELD(&dn->dn_struct_rwlock)) {
|
||||||
|
have_bonus = dbuf_try_add_ref((dmu_buf_t *)db,
|
||||||
|
dn->dn_objset, dn->dn_object,
|
||||||
|
DMU_BONUS_BLKID, FTAG);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The hold will fail if the buffer is
|
||||||
|
* being evicted due to unlink, in which
|
||||||
|
* case nothing needs to be done.
|
||||||
|
*/
|
||||||
|
if (!have_bonus)
|
||||||
|
return;
|
||||||
|
}
|
||||||
mutex_enter(&db->db_mtx);
|
mutex_enter(&db->db_mtx);
|
||||||
data = dmu_objset_userquota_find_data(db, tx);
|
data = dmu_objset_userquota_find_data(db, tx);
|
||||||
} else {
|
} else {
|
||||||
@ -1401,7 +1415,7 @@ dmu_objset_userquota_get_ids(dnode_t *dn, boolean_t before, dmu_tx_t *tx)
|
|||||||
dn->dn_id_flags |= DN_ID_CHKED_BONUS;
|
dn->dn_id_flags |= DN_ID_CHKED_BONUS;
|
||||||
}
|
}
|
||||||
mutex_exit(&dn->dn_mtx);
|
mutex_exit(&dn->dn_mtx);
|
||||||
if (have_spill)
|
if (have_spill || have_bonus)
|
||||||
dmu_buf_rele((dmu_buf_t *)db, FTAG);
|
dmu_buf_rele((dmu_buf_t *)db, FTAG);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user