More aggressively assert that db_mtx protects db.db_data

db.db_mtx must be held any time that db.db_data is accessed.  All of
these functions do have the lock held by a parent; add assertions to
ensure that it stays that way.

See https://github.com/openzfs/zfs/discussions/17118

* Refactor dbuf_read_bonus to make it obvious why db_rwlock isn't
required.

* Refactor dbuf_hold_copy to eliminate the db_rwlock
Copy data into the newly allocated buffer before assigning it to the db.
That way, there will be no need to take db->db_rwlock.

* Refactor dbuf_read_hole
In the case of an indirect hole, initialize the newly allocated buffer
before assigning it to the dmu_buf_impl_t.

Sponsored by:	ConnectWise
Signed-off-by: Alan Somers <asomers@gmail.com>
Closes #17209
This commit is contained in:
Alan Somers 2025-05-09 07:02:26 -06:00 committed by GitHub
parent 1a8f5ad3b0
commit c17bdc4914
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 26 additions and 18 deletions

View File

@ -1410,6 +1410,7 @@ dbuf_read_done(zio_t *zio, const zbookmark_phys_t *zb, const blkptr_t *bp,
static int static int
dbuf_read_bonus(dmu_buf_impl_t *db, dnode_t *dn) dbuf_read_bonus(dmu_buf_impl_t *db, dnode_t *dn)
{ {
void* db_data;
int bonuslen, max_bonuslen; int bonuslen, max_bonuslen;
bonuslen = MIN(dn->dn_bonuslen, dn->dn_phys->dn_bonuslen); bonuslen = MIN(dn->dn_bonuslen, dn->dn_phys->dn_bonuslen);
@ -1417,21 +1418,22 @@ dbuf_read_bonus(dmu_buf_impl_t *db, dnode_t *dn)
ASSERT(MUTEX_HELD(&db->db_mtx)); ASSERT(MUTEX_HELD(&db->db_mtx));
ASSERT(DB_DNODE_HELD(db)); ASSERT(DB_DNODE_HELD(db));
ASSERT3U(bonuslen, <=, db->db.db_size); ASSERT3U(bonuslen, <=, db->db.db_size);
db->db.db_data = kmem_alloc(max_bonuslen, KM_SLEEP); db_data = kmem_alloc(max_bonuslen, KM_SLEEP);
arc_space_consume(max_bonuslen, ARC_SPACE_BONUS); arc_space_consume(max_bonuslen, ARC_SPACE_BONUS);
if (bonuslen < max_bonuslen) if (bonuslen < max_bonuslen)
memset(db->db.db_data, 0, max_bonuslen); memset(db_data, 0, max_bonuslen);
if (bonuslen) if (bonuslen)
memcpy(db->db.db_data, DN_BONUS(dn->dn_phys), bonuslen); memcpy(db_data, DN_BONUS(dn->dn_phys), bonuslen);
db->db.db_data = db_data;
db->db_state = DB_CACHED; db->db_state = DB_CACHED;
DTRACE_SET_STATE(db, "bonus buffer filled"); DTRACE_SET_STATE(db, "bonus buffer filled");
return (0); return (0);
} }
static void static void
dbuf_handle_indirect_hole(dmu_buf_impl_t *db, dnode_t *dn, blkptr_t *dbbp) dbuf_handle_indirect_hole(void *data, dnode_t *dn, blkptr_t *dbbp)
{ {
blkptr_t *bps = db->db.db_data; blkptr_t *bps = data;
uint32_t indbs = 1ULL << dn->dn_indblkshift; uint32_t indbs = 1ULL << dn->dn_indblkshift;
int n_bps = indbs >> SPA_BLKPTRSHIFT; int n_bps = indbs >> SPA_BLKPTRSHIFT;
@ -1456,6 +1458,7 @@ static int
dbuf_read_hole(dmu_buf_impl_t *db, dnode_t *dn, blkptr_t *bp) dbuf_read_hole(dmu_buf_impl_t *db, dnode_t *dn, blkptr_t *bp)
{ {
ASSERT(MUTEX_HELD(&db->db_mtx)); ASSERT(MUTEX_HELD(&db->db_mtx));
arc_buf_t *db_data;
int is_hole = bp == NULL || BP_IS_HOLE(bp); int is_hole = bp == NULL || BP_IS_HOLE(bp);
/* /*
@ -1468,13 +1471,14 @@ dbuf_read_hole(dmu_buf_impl_t *db, dnode_t *dn, blkptr_t *bp)
is_hole = dnode_block_freed(dn, db->db_blkid) || BP_IS_HOLE(bp); is_hole = dnode_block_freed(dn, db->db_blkid) || BP_IS_HOLE(bp);
if (is_hole) { if (is_hole) {
dbuf_set_data(db, dbuf_alloc_arcbuf(db)); db_data = dbuf_alloc_arcbuf(db);
memset(db->db.db_data, 0, db->db.db_size); memset(db_data->b_data, 0, db->db.db_size);
if (bp != NULL && db->db_level > 0 && BP_IS_HOLE(bp) && if (bp != NULL && db->db_level > 0 && BP_IS_HOLE(bp) &&
BP_GET_LOGICAL_BIRTH(bp) != 0) { BP_GET_LOGICAL_BIRTH(bp) != 0) {
dbuf_handle_indirect_hole(db, dn, bp); dbuf_handle_indirect_hole(db_data->b_data, dn, bp);
} }
dbuf_set_data(db, db_data);
db->db_state = DB_CACHED; db->db_state = DB_CACHED;
DTRACE_SET_STATE(db, "hole read satisfied"); DTRACE_SET_STATE(db, "hole read satisfied");
return (0); return (0);
@ -2493,6 +2497,7 @@ dbuf_undirty_bonus(dbuf_dirty_record_t *dr)
{ {
dmu_buf_impl_t *db = dr->dr_dbuf; dmu_buf_impl_t *db = dr->dr_dbuf;
ASSERT(MUTEX_HELD(&db->db_mtx));
if (dr->dt.dl.dr_data != db->db.db_data) { if (dr->dt.dl.dr_data != db->db.db_data) {
struct dnode *dn = dr->dr_dnode; struct dnode *dn = dr->dr_dnode;
int max_bonuslen = DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots); int max_bonuslen = DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots);
@ -3827,6 +3832,7 @@ dbuf_hold_copy(dnode_t *dn, dmu_buf_impl_t *db)
{ {
dbuf_dirty_record_t *dr = db->db_data_pending; dbuf_dirty_record_t *dr = db->db_data_pending;
arc_buf_t *data = dr->dt.dl.dr_data; arc_buf_t *data = dr->dt.dl.dr_data;
arc_buf_t *db_data;
enum zio_compress compress_type = arc_get_compression(data); enum zio_compress compress_type = arc_get_compression(data);
uint8_t complevel = arc_get_complevel(data); uint8_t complevel = arc_get_complevel(data);
@ -3837,22 +3843,21 @@ dbuf_hold_copy(dnode_t *dn, dmu_buf_impl_t *db)
uint8_t mac[ZIO_DATA_MAC_LEN]; uint8_t mac[ZIO_DATA_MAC_LEN];
arc_get_raw_params(data, &byteorder, salt, iv, mac); arc_get_raw_params(data, &byteorder, salt, iv, mac);
dbuf_set_data(db, arc_alloc_raw_buf(dn->dn_objset->os_spa, db, db_data = arc_alloc_raw_buf(dn->dn_objset->os_spa, db,
dmu_objset_id(dn->dn_objset), byteorder, salt, iv, mac, dmu_objset_id(dn->dn_objset), byteorder, salt, iv, mac,
dn->dn_type, arc_buf_size(data), arc_buf_lsize(data), dn->dn_type, arc_buf_size(data), arc_buf_lsize(data),
compress_type, complevel)); compress_type, complevel);
} else if (compress_type != ZIO_COMPRESS_OFF) { } else if (compress_type != ZIO_COMPRESS_OFF) {
dbuf_set_data(db, arc_alloc_compressed_buf( db_data = arc_alloc_compressed_buf(
dn->dn_objset->os_spa, db, arc_buf_size(data), dn->dn_objset->os_spa, db, arc_buf_size(data),
arc_buf_lsize(data), compress_type, complevel)); arc_buf_lsize(data), compress_type, complevel);
} else { } else {
dbuf_set_data(db, arc_alloc_buf(dn->dn_objset->os_spa, db, db_data = arc_alloc_buf(dn->dn_objset->os_spa, db,
DBUF_GET_BUFC_TYPE(db), db->db.db_size)); DBUF_GET_BUFC_TYPE(db), db->db.db_size);
} }
memcpy(db_data->b_data, data->b_data, arc_buf_size(data));
rw_enter(&db->db_rwlock, RW_WRITER); dbuf_set_data(db, db_data);
memcpy(db->db.db_data, data->b_data, arc_buf_size(data));
rw_exit(&db->db_rwlock);
} }
/* /*
@ -3913,6 +3918,7 @@ dbuf_hold_impl(dnode_t *dn, uint8_t level, uint64_t blkid,
if (db->db_buf != NULL) { if (db->db_buf != NULL) {
arc_buf_access(db->db_buf); arc_buf_access(db->db_buf);
ASSERT(MUTEX_HELD(&db->db_mtx));
ASSERT3P(db->db.db_data, ==, db->db_buf->b_data); ASSERT3P(db->db.db_data, ==, db->db_buf->b_data);
} }

View File

@ -2272,8 +2272,10 @@ dmu_objset_userquota_find_data(dmu_buf_impl_t *db, dmu_tx_t *tx)
dbuf_dirty_record_t *dr; dbuf_dirty_record_t *dr;
void *data; void *data;
if (db->db_dirtycnt == 0) if (db->db_dirtycnt == 0) {
ASSERT(MUTEX_HELD(&db->db_mtx));
return (db->db.db_data); /* Nothing is changing */ return (db->db.db_data); /* Nothing is changing */
}
dr = dbuf_find_dirty_eq(db, tx->tx_txg); dr = dbuf_find_dirty_eq(db, tx->tx_txg);