FreeBSD/sys/cddl/contrib/opensolaris/uts/common/fs/zfs/dbuf.c
/*
 * Undirty a buffer in the transaction group referenced by the given
 * transaction.  Return whether this evicted the dbuf.
 */
Undirty a buffer in the transaction group referenced by the given
transaction.  Return whether this evicted the dbuf.
Undirty a buffer in the transaction group referenced by the given transaction . Return whether this evicted the dbuf .
static boolean_t
dbuf_undirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
{
	dnode_t *dn;
	uint64_t txg = tx->tx_txg;
	dbuf_dirty_record_t *dr, **drp;
	ASSERT(txg != 0);
	ASSERT(db->db_objset ==
	    dmu_objset_pool(db->db_objset)->dp_meta_objset ||
	    txg != spa_syncing_txg(dmu_objset_spa(db->db_objset)));
	ASSERT(db->db_blkid != DMU_BONUS_BLKID);
	ASSERT0(db->db_level);
	ASSERT(MUTEX_HELD(&db->db_mtx));
	for (drp = &db->db_last_dirty; (dr = *drp) != NULL; drp = &dr->dr_next)
		if (dr->dr_txg <= txg)
			break;
	if (dr == NULL || dr->dr_txg < txg)
		return (B_FALSE);
	ASSERT(dr->dr_txg == txg);
	ASSERT(dr->dr_dbuf == db);
	DB_DNODE_ENTER(db);
	dn = DB_DNODE(db);
	dprintf_dbuf(db, "size=%llx\n", (u_longlong_t)db->db.db_size);
	ASSERT(db->db.db_size != 0);
	dsl_pool_undirty_space(dmu_objset_pool(dn->dn_objset),
	    dr->dr_accounted, txg);
	*drp = dr->dr_next;
	if (dr->dr_parent) {
		mutex_enter(&dr->dr_parent->dt.di.dr_mtx);
		list_remove(&dr->dr_parent->dt.di.dr_children, dr);
		mutex_exit(&dr->dr_parent->dt.di.dr_mtx);
	} else if (db->db_blkid == DMU_SPILL_BLKID ||
	    db->db_level + 1 == dn->dn_nlevels) {
		ASSERT(db->db_blkptr == NULL || db->db_parent == dn->dn_dbuf);
		mutex_enter(&dn->dn_mtx);
		list_remove(&dn->dn_dirty_records[txg & TXG_MASK], dr);
		mutex_exit(&dn->dn_mtx);
	}
	DB_DNODE_EXIT(db);
	if (db->db_state != DB_NOFILL) {
		dbuf_unoverride(dr);
		ASSERT(db->db_buf != NULL);
		ASSERT(dr->dt.dl.dr_data != NULL);
		if (dr->dt.dl.dr_data != db->db_buf)
			VERIFY(arc_buf_remove_ref(dr->dt.dl.dr_data, db));
	}
	kmem_free(dr, sizeof (dbuf_dirty_record_t));
	ASSERT(db->db_dirtycnt > 0);
	db->db_dirtycnt -= 1;
	if (refcount_remove(&db->db_holds, (void *)(uintptr_t)txg) == 0) {
		arc_buf_t *buf = db->db_buf;
		ASSERT(db->db_state == DB_NOFILL || arc_released(buf));
		dbuf_clear_data(db);
		VERIFY(arc_buf_remove_ref(buf, db));
		dbuf_evict(db);
		return (B_TRUE);
	}
	return (B_FALSE);
}
static boolean_t dbuf_undirty ( dmu_buf_impl_t * db , dmu_tx_t * tx ) { dnode_t * dn ; uint64_t txg = tx -> tx_txg ; dbuf_dirty_record_t * dr , * * drp ; ASSERT ( txg != 0 ) ; ASSERT ( db -> db_objset == dmu_objset_pool ( db -> db_objset ) -> dp_meta_objset || txg != spa_syncing_txg ( dmu_objset_spa ( db -> db_objset ) ) ) ; ASSERT ( db -> db_blkid != DMU_BONUS_BLKID ) ; ASSERT0 ( db -> db_level ) ; ASSERT ( MUTEX_HELD ( & db -> db_mtx ) ) ; for ( drp = & db -> db_last_dirty ; ( dr = * drp ) != NULL ; drp = & dr -> dr_next ) if ( dr -> dr_txg <= txg ) break ; if ( dr == NULL || dr -> dr_txg < txg ) return ( B_FALSE ) ; ASSERT ( dr -> dr_txg == txg ) ; ASSERT ( dr -> dr_dbuf == db ) ; DB_DNODE_ENTER ( db ) ; dn = DB_DNODE ( db ) ; dprintf_dbuf ( db , " \n " , ( u_longlong_t ) db -> db . db_size ) ; ASSERT ( db -> db . db_size != 0 ) ; dsl_pool_undirty_space ( dmu_objset_pool ( dn -> dn_objset ) , dr -> dr_accounted , txg ) ; * drp = dr -> dr_next ; if ( dr -> dr_parent ) { mutex_enter ( & dr -> dr_parent -> dt . di . dr_mtx ) ; list_remove ( & dr -> dr_parent -> dt . di . dr_children , dr ) ; mutex_exit ( & dr -> dr_parent -> dt . di . dr_mtx ) ; } else if ( db -> db_blkid == DMU_SPILL_BLKID || db -> db_level + 1 == dn -> dn_nlevels ) { ASSERT ( db -> db_blkptr == NULL || db -> db_parent == dn -> dn_dbuf ) ; mutex_enter ( & dn -> dn_mtx ) ; list_remove ( & dn -> dn_dirty_records [ txg & TXG_MASK ] , dr ) ; mutex_exit ( & dn -> dn_mtx ) ; } DB_DNODE_EXIT ( db ) ; if ( db -> db_state != DB_NOFILL ) { dbuf_unoverride ( dr ) ; ASSERT ( db -> db_buf != NULL ) ; ASSERT ( dr -> dt . dl . dr_data != NULL ) ; if ( dr -> dt . dl . dr_data != db -> db_buf ) VERIFY ( arc_buf_remove_ref ( dr -> dt . dl . dr_data , db ) ) ; } kmem_free ( dr , sizeof ( dbuf_dirty_record_t ) ) ; ASSERT ( db -> db_dirtycnt > 0 ) ; db -> db_dirtycnt -= 1 ; if ( refcount_remove ( & db -> db_holds , ( void * ) ( uintptr_t ) txg ) == 0 ) { arc_buf_t * buf = db -> db_buf ; ASSERT ( db -> db_state == DB_NOFILL || arc_released ( buf ) ) ; dbuf_clear_data ( db ) ; VERIFY ( arc_buf_remove_ref ( buf , db ) ) ; dbuf_evict ( db ) ; return ( B_TRUE ) ; } return ( B_FALSE ) ; }
Undirty a buffer in the transaction group referenced by the given
 transaction.
Undirty a buffer in the transaction group referenced by the given transaction .
/*
	 * Due to our use of dn_nlevels below, this can only be called
	 * in open context, unless we are operating on the MOS.
	 * From syncing context, dn_nlevels may be different from the
	 * dn_nlevels used when dbuf was dirtied.
	 */ /*
	 * If this buffer is not dirty, we're done.
	 */ /*
	 * Note that there are three places in dbuf_dirty()
	 * where this dirty record may be put on a list.
	 * Make sure to do a list_remove corresponding to
	 * every one of those list_insert calls.
	 */