Remove db_state DB_NOFILL checks from syncing context

Syncing context should not depend on current state of dbuf, which
could already change several times in later transaction groups,
but rely solely on dirty record for the transaction group being
synced. Some of the checks seem already impossible, while instead
of others I think we should better check for absence of data in
the specific dirty record rather than DB_NOFILL.

Reviewed-by: Robert Evans <evansr@google.com>
Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov>
Signed-off-by:	Alexander Motin <mav@FreeBSD.org>
Sponsored by:	iXsystems, Inc.
Closes #16057
This commit is contained in:
Alexander Motin 2024-04-08 18:23:43 -04:00 committed by GitHub
parent 5e5fd0a178
commit aa5445c28b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
1 changed files with 19 additions and 25 deletions

View File

@ -4596,11 +4596,10 @@ dbuf_sync_leaf(dbuf_dirty_record_t *dr, dmu_tx_t *tx)
if (os->os_encrypted && dn->dn_object == DMU_META_DNODE_OBJECT) if (os->os_encrypted && dn->dn_object == DMU_META_DNODE_OBJECT)
dbuf_prepare_encrypted_dnode_leaf(dr); dbuf_prepare_encrypted_dnode_leaf(dr);
if (db->db_state != DB_NOFILL && if (*datap != NULL && *datap == db->db_buf &&
dn->dn_object != DMU_META_DNODE_OBJECT && dn->dn_object != DMU_META_DNODE_OBJECT &&
zfs_refcount_count(&db->db_holds) > 1 && zfs_refcount_count(&db->db_holds) > 1 &&
dr->dt.dl.dr_override_state != DR_OVERRIDDEN && dr->dt.dl.dr_override_state != DR_OVERRIDDEN) {
*datap == db->db_buf) {
/* /*
* If this buffer is currently "in use" (i.e., there * If this buffer is currently "in use" (i.e., there
* are active holds and db_data still references it), * are active holds and db_data still references it),
@ -4889,11 +4888,9 @@ dbuf_write_done(zio_t *zio, arc_buf_t *buf, void *vdb)
if (db->db_level == 0) { if (db->db_level == 0) {
ASSERT(db->db_blkid != DMU_BONUS_BLKID); ASSERT(db->db_blkid != DMU_BONUS_BLKID);
ASSERT(dr->dt.dl.dr_override_state == DR_NOT_OVERRIDDEN); ASSERT(dr->dt.dl.dr_override_state == DR_NOT_OVERRIDDEN);
if (db->db_state != DB_NOFILL) { if (dr->dt.dl.dr_data != NULL &&
if (dr->dt.dl.dr_data != NULL && dr->dt.dl.dr_data != db->db_buf) {
dr->dt.dl.dr_data != db->db_buf) { arc_buf_destroy(dr->dt.dl.dr_data, db);
arc_buf_destroy(dr->dt.dl.dr_data, db);
}
} }
} else { } else {
ASSERT(list_head(&dr->dt.di.dr_children) == NULL); ASSERT(list_head(&dr->dt.di.dr_children) == NULL);
@ -5096,21 +5093,18 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
os = dn->dn_objset; os = dn->dn_objset;
if (db->db_state != DB_NOFILL) { if (db->db_level > 0 || dn->dn_type == DMU_OT_DNODE) {
if (db->db_level > 0 || dn->dn_type == DMU_OT_DNODE) { /*
/* * Private object buffers are released here rather than in
* Private object buffers are released here rather * dbuf_dirty() since they are only modified in the syncing
* than in dbuf_dirty() since they are only modified * context and we don't want the overhead of making multiple
* in the syncing context and we don't want the * copies of the data.
* overhead of making multiple copies of the data. */
*/ if (BP_IS_HOLE(db->db_blkptr))
if (BP_IS_HOLE(db->db_blkptr)) { arc_buf_thaw(data);
arc_buf_thaw(data); else
} else { dbuf_release_bp(db);
dbuf_release_bp(db); dbuf_remap(dn, db, tx);
}
dbuf_remap(dn, db, tx);
}
} }
if (parent != dn->dn_dbuf) { if (parent != dn->dn_dbuf) {
@ -5146,7 +5140,7 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
if (db->db_blkid == DMU_SPILL_BLKID) if (db->db_blkid == DMU_SPILL_BLKID)
wp_flag = WP_SPILL; wp_flag = WP_SPILL;
wp_flag |= (db->db_state == DB_NOFILL) ? WP_NOFILL : 0; wp_flag |= (data == NULL) ? WP_NOFILL : 0;
dmu_write_policy(os, dn, db->db_level, wp_flag, &zp); dmu_write_policy(os, dn, db->db_level, wp_flag, &zp);
@ -5178,7 +5172,7 @@ dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx)
dr->dt.dl.dr_copies, dr->dt.dl.dr_nopwrite, dr->dt.dl.dr_copies, dr->dt.dl.dr_nopwrite,
dr->dt.dl.dr_brtwrite); dr->dt.dl.dr_brtwrite);
mutex_exit(&db->db_mtx); mutex_exit(&db->db_mtx);
} else if (db->db_state == DB_NOFILL) { } else if (data == NULL) {
ASSERT(zp.zp_checksum == ZIO_CHECKSUM_OFF || ASSERT(zp.zp_checksum == ZIO_CHECKSUM_OFF ||
zp.zp_checksum == ZIO_CHECKSUM_NOPARITY); zp.zp_checksum == ZIO_CHECKSUM_NOPARITY);
dr->dr_zio = zio_write(pio, os->os_spa, txg, dr->dr_zio = zio_write(pio, os->os_spa, txg,