dbuf: Set dr_data when unoverriding after clone

Block cloning normally creates dirty record without dr_data.  But if
the block is read after cloning, it is moved into DB_CACHED state and
receives the data buffer.  If after that we call dbuf_unoverride()
to convert the dirty record into normal write, we should give it the
data buffer from dbuf and release one.

Reviewed-by: Kay Pedersen <mail@mkwg.de>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by: Alexander Motin <mav@FreeBSD.org>
Sponsored by: iXsystems, Inc.
Closes #15654
Closes #15656
This commit is contained in:
Alexander Motin 2023-12-12 15:59:24 -05:00 committed by Brian Behlendorf
parent a701548eb4
commit 9c40ae0219

View File

@ -1904,7 +1904,6 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
dmu_buf_impl_t *db = dr->dr_dbuf; dmu_buf_impl_t *db = dr->dr_dbuf;
blkptr_t *bp = &dr->dt.dl.dr_overridden_by; blkptr_t *bp = &dr->dt.dl.dr_overridden_by;
uint64_t txg = dr->dr_txg; uint64_t txg = dr->dr_txg;
boolean_t release;
ASSERT(MUTEX_HELD(&db->db_mtx)); ASSERT(MUTEX_HELD(&db->db_mtx));
/* /*
@ -1925,7 +1924,10 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
if (!BP_IS_HOLE(bp) && !dr->dt.dl.dr_nopwrite) if (!BP_IS_HOLE(bp) && !dr->dt.dl.dr_nopwrite)
zio_free(db->db_objset->os_spa, txg, bp); zio_free(db->db_objset->os_spa, txg, bp);
release = !dr->dt.dl.dr_brtwrite; if (dr->dt.dl.dr_brtwrite) {
ASSERT0(dr->dt.dl.dr_data);
dr->dt.dl.dr_data = db->db_buf;
}
dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN; dr->dt.dl.dr_override_state = DR_NOT_OVERRIDDEN;
dr->dt.dl.dr_nopwrite = B_FALSE; dr->dt.dl.dr_nopwrite = B_FALSE;
dr->dt.dl.dr_brtwrite = B_FALSE; dr->dt.dl.dr_brtwrite = B_FALSE;
@ -1939,7 +1941,7 @@ dbuf_unoverride(dbuf_dirty_record_t *dr)
* the buf thawed to save the effort of freezing & * the buf thawed to save the effort of freezing &
* immediately re-thawing it. * immediately re-thawing it.
*/ */
if (release) if (dr->dt.dl.dr_data)
arc_release(dr->dt.dl.dr_data, db); arc_release(dr->dt.dl.dr_data, db);
} }