diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c index 04fc2f7cd..02478605f 100644 --- a/module/zfs/dbuf.c +++ b/module/zfs/dbuf.c @@ -150,6 +150,7 @@ dbuf_stats_t dbuf_stats = { static boolean_t dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx); static void dbuf_write(dbuf_dirty_record_t *dr, arc_buf_t *data, dmu_tx_t *tx); +static void dbuf_sync_leaf_verify_bonus_dnode(dbuf_dirty_record_t *dr); extern inline void dmu_buf_init_user(dmu_buf_user_t *dbu, dmu_buf_evict_func_t *evict_func_sync, @@ -2210,6 +2211,30 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx) return (dr); } +static void +dbuf_undirty_bonus(dbuf_dirty_record_t *dr) +{ + dmu_buf_impl_t *db = dr->dr_dbuf; + + if (dr->dt.dl.dr_data != db->db.db_data) { + struct dnode *dn = DB_DNODE(db); + int max_bonuslen = DN_SLOTS_TO_BONUSLEN(dn->dn_num_slots); + + kmem_free(dr->dt.dl.dr_data, max_bonuslen); + arc_space_return(max_bonuslen, ARC_SPACE_BONUS); + } + db->db_data_pending = NULL; + ASSERT(list_next(&db->db_dirty_records, dr) == NULL); + list_remove(&db->db_dirty_records, dr); + if (dr->dr_dbuf->db_level != 0) { + mutex_destroy(&dr->dt.di.dr_mtx); + list_destroy(&dr->dt.di.dr_children); + } + kmem_free(dr, sizeof (dbuf_dirty_record_t)); + ASSERT3U(db->db_dirtycnt, >, 0); + db->db_dirtycnt -= 1; +} + /* * Undirty a buffer in the transaction group referenced by the given * transaction. Return whether this evicted the dbuf. @@ -3741,6 +3766,30 @@ dbuf_check_blkptr(dnode_t *dn, dmu_buf_impl_t *db) } } +static void +dbuf_sync_bonus(dbuf_dirty_record_t *dr, dmu_tx_t *tx) +{ + dmu_buf_impl_t *db = dr->dr_dbuf; + void *data = dr->dt.dl.dr_data; + + ASSERT0(db->db_level); + ASSERT(MUTEX_HELD(&db->db_mtx)); + ASSERT(DB_DNODE_HELD(db)); + ASSERT(db->db_blkid == DMU_BONUS_BLKID); + ASSERT(data != NULL); + + dnode_t *dn = DB_DNODE(db); + ASSERT3U(DN_MAX_BONUS_LEN(dn->dn_phys), <=, + DN_SLOTS_TO_BONUSLEN(dn->dn_phys->dn_extra_slots + 1)); + bcopy(data, DN_BONUS(dn->dn_phys), DN_MAX_BONUS_LEN(dn->dn_phys)); + DB_DNODE_EXIT(db); + + dbuf_sync_leaf_verify_bonus_dnode(dr); + + dbuf_undirty_bonus(dr); + dbuf_rele_and_unlock(db, (void *)(uintptr_t)tx->tx_txg, B_FALSE); +} + /* * When syncing out a blocks of dnodes, adjust the block to deal with * encryption. Normally, we make sure the block is decrypted before writing @@ -3835,7 +3884,6 @@ dbuf_sync_indirect(dbuf_dirty_record_t *dr, dmu_tx_t *tx) zio_nowait(zio); } -#ifdef ZFS_DEBUG /* * Verify that the size of the data in our bonus buffer does not exceed * its recorded size. @@ -3852,6 +3900,7 @@ dbuf_sync_indirect(dbuf_dirty_record_t *dr, dmu_tx_t *tx) static void dbuf_sync_leaf_verify_bonus_dnode(dbuf_dirty_record_t *dr) { +#ifdef ZFS_DEBUG dnode_t *dn = DB_DNODE(dr->dr_dbuf); /* @@ -3872,8 +3921,8 @@ dbuf_sync_leaf_verify_bonus_dnode(dbuf_dirty_record_t *dr) /* ensure that everything is zero after our data */ for (; datap_end < datap_max; datap_end++) ASSERT(*datap_end == 0); -} #endif +} /* * dbuf_sync_leaf() is called recursively from dbuf_sync_list() so it is @@ -3941,36 +3990,8 @@ dbuf_sync_leaf(dbuf_dirty_record_t *dr, dmu_tx_t *tx) * be called). */ if (db->db_blkid == DMU_BONUS_BLKID) { - ASSERT(*datap != NULL); - ASSERT0(db->db_level); - ASSERT3U(DN_MAX_BONUS_LEN(dn->dn_phys), <=, - DN_SLOTS_TO_BONUSLEN(dn->dn_phys->dn_extra_slots + 1)); - bcopy(*datap, DN_BONUS(dn->dn_phys), - DN_MAX_BONUS_LEN(dn->dn_phys)); - DB_DNODE_EXIT(db); - -#ifdef ZFS_DEBUG - dbuf_sync_leaf_verify_bonus_dnode(dr); -#endif - - if (*datap != db->db.db_data) { - int slots = DB_DNODE(db)->dn_num_slots; - int bonuslen = DN_SLOTS_TO_BONUSLEN(slots); - kmem_free(*datap, bonuslen); - arc_space_return(bonuslen, ARC_SPACE_BONUS); - } - db->db_data_pending = NULL; - ASSERT(list_next(&db->db_dirty_records, dr) == NULL); ASSERT(dr->dr_dbuf == db); - list_remove(&db->db_dirty_records, dr); - if (dr->dr_dbuf->db_level != 0) { - mutex_destroy(&dr->dt.di.dr_mtx); - list_destroy(&dr->dt.di.dr_children); - } - kmem_free(dr, sizeof (dbuf_dirty_record_t)); - ASSERT(db->db_dirtycnt > 0); - db->db_dirtycnt -= 1; - dbuf_rele_and_unlock(db, (void *)(uintptr_t)txg, B_FALSE); + dbuf_sync_bonus(dr, tx); return; }