OpenZFS 7086 - ztest attempts dva_get_dsize_sync on an embedded blockpointer
In dbuf_dirty(), we need to grab the dn_struct_rwlock before looking at the db_blkptr, to prevent it from being changed by syncing context. Reviewed by: Prakash Surya <prakash.surya@delphix.com> Reviewed by: George Wilson <george.wilson@delphix.com> Signed-off-by: Brian Behlendorf <behlendorf1@llnl.gov> OpenZFS-issue: https://www.illumos.org/issues/7086 OpenZFS-commit: https://github.com/openzfs/openzfs/commit/98fa317 Closes #5039
This commit is contained in:
parent
c40db193a5
commit
98ace739bd
@ -1468,7 +1468,20 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
|
|||||||
dnode_setdirty(dn, tx);
|
dnode_setdirty(dn, tx);
|
||||||
DB_DNODE_EXIT(db);
|
DB_DNODE_EXIT(db);
|
||||||
return (dr);
|
return (dr);
|
||||||
} else if (do_free_accounting) {
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The dn_struct_rwlock prevents db_blkptr from changing
|
||||||
|
* due to a write from syncing context completing
|
||||||
|
* while we are running, so we want to acquire it before
|
||||||
|
* looking at db_blkptr.
|
||||||
|
*/
|
||||||
|
if (!RW_WRITE_HELD(&dn->dn_struct_rwlock)) {
|
||||||
|
rw_enter(&dn->dn_struct_rwlock, RW_READER);
|
||||||
|
drop_struct_lock = TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (do_free_accounting) {
|
||||||
blkptr_t *bp = db->db_blkptr;
|
blkptr_t *bp = db->db_blkptr;
|
||||||
int64_t willfree = (bp && !BP_IS_HOLE(bp)) ?
|
int64_t willfree = (bp && !BP_IS_HOLE(bp)) ?
|
||||||
bp_get_dsize(os->os_spa, bp) : db->db.db_size;
|
bp_get_dsize(os->os_spa, bp) : db->db.db_size;
|
||||||
@ -1484,11 +1497,6 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
|
|||||||
dnode_willuse_space(dn, -willfree, tx);
|
dnode_willuse_space(dn, -willfree, tx);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!RW_WRITE_HELD(&dn->dn_struct_rwlock)) {
|
|
||||||
rw_enter(&dn->dn_struct_rwlock, RW_READER);
|
|
||||||
drop_struct_lock = TRUE;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (db->db_level == 0) {
|
if (db->db_level == 0) {
|
||||||
dnode_new_blkid(dn, db->db_blkid, tx, drop_struct_lock);
|
dnode_new_blkid(dn, db->db_blkid, tx, drop_struct_lock);
|
||||||
ASSERT(dn->dn_maxblkid >= db->db_blkid);
|
ASSERT(dn->dn_maxblkid >= db->db_blkid);
|
||||||
|
Loading…
Reference in New Issue
Block a user