diff --git a/include/sys/dbuf.h b/include/sys/dbuf.h index da223e9bbb2e..703ba5da1c8e 100644 --- a/include/sys/dbuf.h +++ b/include/sys/dbuf.h @@ -476,6 +476,20 @@ dbuf_get_dirty_direct(dmu_buf_impl_t *db) return (list_head(&db->db_dirty_records)); } +static inline boolean_t +dbuf_dirty_is_direct_write(dbuf_dirty_record_t *dr) +{ + boolean_t ret = B_FALSE; + + if (dr != NULL && dr->dr_dbuf->db_level == 0 && + !dr->dt.dl.dr_brtwrite && + dr->dt.dl.dr_override_state == DR_OVERRIDDEN && + dr->dt.dl.dr_data == NULL) { + ret = B_TRUE; + } + return (ret); +} + #define DBUF_GET_BUFC_TYPE(_db) \ (dbuf_is_metadata(_db) ? ARC_BUFC_METADATA : ARC_BUFC_DATA) diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index a9fe1ded82ad..2b44ad6126df 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -1292,9 +1292,7 @@ dbuf_set_data(dmu_buf_impl_t *db, arc_buf_t *buf) * If there is a Direct I/O, set its data too. Then its state * will be the same as if we did a ZIL dmu_sync(). */ - if (dr_dio != NULL && db->db_level == 0 && - dr_dio->dt.dl.dr_override_state == DR_OVERRIDDEN && - dr_dio->dt.dl.dr_data == NULL) { + if (dbuf_dirty_is_direct_write(dr_dio)) { dr_dio->dt.dl.dr_data = db->db_buf; } @@ -2218,9 +2216,15 @@ dbuf_redirty(dbuf_dirty_record_t *dr) } /* * If initial dirty was via Direct I/O, may not have a dr_data. + * + * If the dirty record was associated with cloned block then + * the call above to dbuf_unoverride() will have reset + * dr->dt.dl.dr_data and it will not be NULL here. */ - if (dr->dt.dl.dr_data == NULL) + if (dr->dt.dl.dr_data == NULL) { + ASSERT3B(dbuf_dirty_is_direct_write(dr), ==, B_TRUE); dr->dt.dl.dr_data = db->db_buf; + } } } diff --git a/module/zfs/dmu_direct.c b/module/zfs/dmu_direct.c index 584ec8f33598..d618d27d18fc 100644 --- a/module/zfs/dmu_direct.c +++ b/module/zfs/dmu_direct.c @@ -194,9 +194,7 @@ dmu_write_direct(zio_t *pio, dmu_buf_impl_t *db, abd_t *data, dmu_tx_t *tx) */ mutex_enter(&db->db_mtx); dr_head = dbuf_find_dirty_eq(db, dmu_tx_get_txg(tx)); - if (dr_head && dr_head->dt.dl.dr_override_state == DR_OVERRIDDEN && - dr_head->dt.dl.dr_data == NULL && - !dr_head->dt.dl.dr_brtwrite) { + if (dbuf_dirty_is_direct_write(dr_head)) { dmu_buf_undirty(db, tx); } mutex_exit(&db->db_mtx); diff --git a/module/zfs/zfs_vnops.c b/module/zfs/zfs_vnops.c index ade2b927a3ee..2e154a1759d9 100644 --- a/module/zfs/zfs_vnops.c +++ b/module/zfs/zfs_vnops.c @@ -1172,8 +1172,7 @@ zfs_get_data(void *arg, uint64_t gen, lr_write_t *lr, char *buf, * All Direct I/O writes will have already completed and the * block pointer can be immediately stored in the log record. */ - if (dr != NULL && dr->dt.dl.dr_data == NULL && - dr->dt.dl.dr_override_state == DR_OVERRIDDEN) { + if (dbuf_dirty_is_direct_write(dr)) { lr->lr_blkptr = dr->dt.dl.dr_overridden_by; zfs_get_done(zgd, 0); return (0);