Print this page
3752 want more verifiable dbuf user eviction
Submitted by: Justin Gibbs <justing@spectralogic.com>
Submitted by: Will Andrews <willa@spectralogic.com>
@@ -202,23 +202,141 @@
}
static arc_evict_func_t dbuf_do_evict;
static void
-dbuf_evict_user(dmu_buf_impl_t *db)
+dbuf_verify_user(dmu_buf_impl_t *db, boolean_t evicting)
+{
+#ifdef ZFS_DEBUG
+
+ if (db->db_level != 0)
+ ASSERT(db->db_user == NULL);
+
+ if (db->db_user == NULL)
+ return;
+
+ /* Clients must resolve a dbuf before attaching user data. */
+ ASSERT(db->db.db_data != NULL && db->db_state == DB_CACHED);
+ /*
+ * We can't check the hold count here, because they are modified
+ * independently of the dbuf mutex. But it would be nice to ensure
+ * that the user has the appropriate number.
+ */
+#endif
+}
+
+/*
+ * Evict the dbuf's user, either immediately, or use a provided queue.
+ *
+ * Call dmu_buf_process_user_evicts or dmu_buf_destroy_user_evict_list
+ * on the list when finished generating it.
+ *
+ * NOTE: If db->db_immediate_evict is FALSE, evict_list_p must be provided.
+ * NOTE: See dmu_buf_user_t about how this process works.
+ */
+static void
+dbuf_evict_user(dmu_buf_impl_t *db, list_t *evict_list_p)
{
ASSERT(MUTEX_HELD(&db->db_mtx));
+ ASSERT(evict_list_p != NULL);
+ dbuf_verify_user(db, /*evicting*/B_TRUE);
- if (db->db_level != 0 || db->db_evict_func == NULL)
+ if (db->db_user == NULL)
return;
- if (db->db_user_data_ptr_ptr)
- *db->db_user_data_ptr_ptr = db->db.db_data;
- db->db_evict_func(&db->db, db->db_user_ptr);
- db->db_user_ptr = NULL;
- db->db_user_data_ptr_ptr = NULL;
- db->db_evict_func = NULL;
+ ASSERT(!list_link_active(&db->db_user->evict_queue_link));
+ list_insert_head(evict_list_p, db->db_user);
+ db->db_user = NULL;
+}
+
+/*
+ * Replace the current user of the dbuf. Requires that the caller knows who
+ * the old user is. Returns the old user, which may not necessarily be
+ * the same old_user provided by the caller.
+ */
+dmu_buf_user_t *
+dmu_buf_replace_user(dmu_buf_t *db_fake, dmu_buf_user_t *old_user,
+ dmu_buf_user_t *new_user)
+{
+ dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+ mutex_enter(&db->db_mtx);
+ dbuf_verify_user(db, /*evicting*/B_FALSE);
+ if (db->db_user == old_user)
+ db->db_user = new_user;
+ else
+ old_user = db->db_user;
+ dbuf_verify_user(db, /*evicting*/B_FALSE);
+ mutex_exit(&db->db_mtx);
+
+ return (old_user);
+}
+
+/*
+ * Set the user eviction data for the DMU beturns NULL on success,
+ * or the existing user if another user currently owns the buffer.
+ */
+dmu_buf_user_t *
+dmu_buf_set_user(dmu_buf_t *db_fake, dmu_buf_user_t *user)
+{
+ return (dmu_buf_replace_user(db_fake, NULL, user));
+}
+
+dmu_buf_user_t *
+dmu_buf_set_user_ie(dmu_buf_t *db_fake, dmu_buf_user_t *user)
+{
+ dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+ db->db_immediate_evict = TRUE;
+ return (dmu_buf_set_user(db_fake, user));
+}
+
+/*
+ * Remove the user eviction data for the DMU buffer.
+ */
+dmu_buf_user_t *
+dmu_buf_remove_user(dmu_buf_t *db_fake, dmu_buf_user_t *user)
+{
+ return (dmu_buf_replace_user(db_fake, user, NULL));
+}
+
+/*
+ * Returns the db_user set with dmu_buf_update_user(), or NULL if not set.
+ */
+dmu_buf_user_t *
+dmu_buf_get_user(dmu_buf_t *db_fake)
+{
+ dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
+
+ dbuf_verify_user(db, /*evicting*/B_FALSE);
+ return (db->db_user);
+}
+
+static void
+dbuf_clear_data(dmu_buf_impl_t *db, list_t *evict_list_p)
+{
+ ASSERT(MUTEX_HELD(&db->db_mtx));
+ ASSERT(db->db_buf == NULL || !arc_has_callback(db->db_buf));
+ dbuf_evict_user(db, evict_list_p);
+ db->db_buf = NULL;
+ db->db.db_data = NULL;
+ if (db->db_state != DB_NOFILL)
+ db->db_state = DB_UNCACHED;
+}
+
+static void
+dbuf_set_data(dmu_buf_impl_t *db, arc_buf_t *buf)
+{
+ ASSERT(MUTEX_HELD(&db->db_mtx));
+ ASSERT(db->db_buf == NULL || !arc_has_callback(db->db_buf));
+ ASSERT(buf != NULL);
+
+ db->db_buf = buf;
+ ASSERT(buf->b_data != NULL);
+ db->db.db_data = buf->b_data;
+ if (!arc_released(buf))
+ arc_set_callback(buf, dbuf_do_evict, db);
}
boolean_t
dbuf_is_metadata(dmu_buf_impl_t *db)
{
@@ -234,17 +352,17 @@
return (is_metadata);
}
}
void
-dbuf_evict(dmu_buf_impl_t *db)
+dbuf_evict(dmu_buf_impl_t *db, list_t *evict_list_p)
{
ASSERT(MUTEX_HELD(&db->db_mtx));
ASSERT(db->db_buf == NULL);
ASSERT(db->db_data_pending == NULL);
- dbuf_clear(db);
+ dbuf_clear(db, evict_list_p);
dbuf_destroy(db);
}
void
dbuf_init(void)
@@ -403,47 +521,20 @@
}
DB_DNODE_EXIT(db);
}
#endif
-static void
-dbuf_update_data(dmu_buf_impl_t *db)
-{
- ASSERT(MUTEX_HELD(&db->db_mtx));
- if (db->db_level == 0 && db->db_user_data_ptr_ptr) {
- ASSERT(!refcount_is_zero(&db->db_holds));
- *db->db_user_data_ptr_ptr = db->db.db_data;
- }
-}
-
-static void
-dbuf_set_data(dmu_buf_impl_t *db, arc_buf_t *buf)
-{
- ASSERT(MUTEX_HELD(&db->db_mtx));
- ASSERT(db->db_buf == NULL || !arc_has_callback(db->db_buf));
- db->db_buf = buf;
- if (buf != NULL) {
- ASSERT(buf->b_data != NULL);
- db->db.db_data = buf->b_data;
- if (!arc_released(buf))
- arc_set_callback(buf, dbuf_do_evict, db);
- dbuf_update_data(db);
- } else {
- dbuf_evict_user(db);
- db->db.db_data = NULL;
- if (db->db_state != DB_NOFILL)
- db->db_state = DB_UNCACHED;
- }
-}
-
/*
* Loan out an arc_buf for read. Return the loaned arc_buf.
*/
arc_buf_t *
dbuf_loan_arcbuf(dmu_buf_impl_t *db)
{
arc_buf_t *abuf;
+ list_t evict_list;
+
+ dmu_buf_create_user_evict_list(&evict_list);
mutex_enter(&db->db_mtx);
if (arc_released(db->db_buf) || refcount_count(&db->db_holds) > 1) {
int blksz = db->db.db_size;
spa_t *spa;
@@ -453,13 +544,14 @@
abuf = arc_loan_buf(spa, blksz);
bcopy(db->db.db_data, abuf->b_data, blksz);
} else {
abuf = db->db_buf;
arc_loan_inuse_buf(abuf, db);
- dbuf_set_data(db, NULL);
+ dbuf_clear_data(db, &evict_list);
mutex_exit(&db->db_mtx);
}
+ dmu_buf_destroy_user_evict_list(&evict_list);
return (abuf);
}
uint64_t
dbuf_whichblock(dnode_t *dn, uint64_t offset)
@@ -532,11 +624,10 @@
if (bonuslen < DN_MAX_BONUSLEN)
bzero(db->db.db_data, DN_MAX_BONUSLEN);
if (bonuslen)
bcopy(DN_BONUS(dn->dn_phys), db->db.db_data, bonuslen);
DB_DNODE_EXIT(db);
- dbuf_update_data(db);
db->db_state = DB_CACHED;
mutex_exit(&db->db_mtx);
return;
}
@@ -665,12 +756,16 @@
}
static void
dbuf_noread(dmu_buf_impl_t *db)
{
+ list_t evict_list;
+
ASSERT(!refcount_is_zero(&db->db_holds));
ASSERT(db->db_blkid != DMU_BONUS_BLKID);
+ dmu_buf_create_user_evict_list(&evict_list);
+
mutex_enter(&db->db_mtx);
while (db->db_state == DB_READ || db->db_state == DB_FILL)
cv_wait(&db->db_changed, &db->db_mtx);
if (db->db_state == DB_UNCACHED) {
arc_buf_contents_t type = DBUF_GET_BUFC_TYPE(db);
@@ -680,15 +775,16 @@
ASSERT(db->db.db_data == NULL);
DB_GET_SPA(&spa, db);
dbuf_set_data(db, arc_buf_alloc(spa, db->db.db_size, db, type));
db->db_state = DB_FILL;
} else if (db->db_state == DB_NOFILL) {
- dbuf_set_data(db, NULL);
+ dbuf_clear_data(db, &evict_list);
} else {
ASSERT3U(db->db_state, ==, DB_CACHED);
}
mutex_exit(&db->db_mtx);
+ dmu_buf_destroy_user_evict_list(&evict_list);
}
/*
* This is our just-in-time copy function. It makes a copy of
* buffers, that have been modified in a previous transaction
@@ -701,11 +797,11 @@
* Note that when we are called from dbuf_free_range() we do
* not put a hold on the buffer, we just traverse the active
* dbuf list for the dnode.
*/
static void
-dbuf_fix_old_data(dmu_buf_impl_t *db, uint64_t txg)
+dbuf_fix_old_data(dmu_buf_impl_t *db, uint64_t txg, list_t *evict_list_p)
{
dbuf_dirty_record_t *dr = db->db_last_dirty;
ASSERT(MUTEX_HELD(&db->db_mtx));
ASSERT(db->db.db_data != NULL);
@@ -737,11 +833,11 @@
DB_GET_SPA(&spa, db);
dr->dt.dl.dr_data = arc_buf_alloc(spa, size, db, type);
bcopy(db->db.db_data, dr->dt.dl.dr_data->b_data, size);
} else {
- dbuf_set_data(db, NULL);
+ dbuf_clear_data(db, evict_list_p);
}
}
void
dbuf_unoverride(dbuf_dirty_record_t *dr)
@@ -794,10 +890,13 @@
dmu_buf_impl_t *db, *db_next;
uint64_t txg = tx->tx_txg;
int epbs = dn->dn_indblkshift - SPA_BLKPTRSHIFT;
uint64_t first_l1 = start >> epbs;
uint64_t last_l1 = end >> epbs;
+ list_t evict_list;
+
+ dmu_buf_create_user_evict_list(&evict_list);
if (end > dn->dn_maxblkid && (end != DMU_SPILL_BLKID)) {
end = dn->dn_maxblkid;
last_l1 = end >> epbs;
}
@@ -847,11 +946,11 @@
mutex_exit(&db->db_mtx);
continue;
}
if (refcount_count(&db->db_holds) == 0) {
ASSERT(db->db_buf);
- dbuf_clear(db);
+ dbuf_clear(db, &evict_list);
continue;
}
/* The dbuf is referenced */
if (db->db_last_dirty != NULL) {
@@ -872,11 +971,11 @@
* This dbuf is not dirty in the open context.
* Either uncache it (if its not referenced in
* the open context) or reset its contents to
* empty.
*/
- dbuf_fix_old_data(db, txg);
+ dbuf_fix_old_data(db, txg, &evict_list);
}
}
/* clear the contents if its cached */
if (db->db_state == DB_CACHED) {
ASSERT(db->db.db_data != NULL);
@@ -884,12 +983,14 @@
bzero(db->db.db_data, db->db.db_size);
arc_buf_freeze(db->db_buf);
}
mutex_exit(&db->db_mtx);
+ dmu_buf_process_user_evicts(&evict_list);
}
mutex_exit(&dn->dn_dbufs_mtx);
+ dmu_buf_destroy_user_evict_list(&evict_list);
}
static int
dbuf_block_freeable(dmu_buf_impl_t *db)
{
@@ -994,10 +1095,13 @@
objset_t *os;
dbuf_dirty_record_t **drp, *dr;
int drop_struct_lock = FALSE;
boolean_t do_free_accounting = B_FALSE;
int txgoff = tx->tx_txg & TXG_MASK;
+ list_t evict_list;
+
+ dmu_buf_create_user_evict_list(&evict_list);
ASSERT(tx->tx_txg != 0);
ASSERT(!refcount_is_zero(&db->db_holds));
DMU_TX_DIRTY_BUF(tx, db);
@@ -1068,10 +1172,11 @@
if (db->db.db_object != DMU_META_DNODE_OBJECT &&
db->db_state != DB_NOFILL)
arc_buf_thaw(db->db_buf);
}
mutex_exit(&db->db_mtx);
+ dmu_buf_destroy_user_evict_list(&evict_list);
return (dr);
}
/*
* Only valid if not already dirty.
@@ -1122,11 +1227,11 @@
if (db->db_level == 0) {
void *data_old = db->db_buf;
if (db->db_state != DB_NOFILL) {
if (db->db_blkid == DMU_BONUS_BLKID) {
- dbuf_fix_old_data(db, tx->tx_txg);
+ dbuf_fix_old_data(db, tx->tx_txg, &evict_list);
data_old = db->db.db_data;
} else if (db->db.db_object != DMU_META_DNODE_OBJECT) {
/*
* Release the data buffer from the cache so
* that we can modify it without impacting
@@ -1135,11 +1240,11 @@
* private objects are not released until the
* syncing state (since they are only modified
* then).
*/
arc_release(db->db_buf, db);
- dbuf_fix_old_data(db, tx->tx_txg);
+ dbuf_fix_old_data(db, tx->tx_txg, &evict_list);
data_old = db->db_buf;
}
ASSERT(data_old != NULL);
}
dr->dt.dl.dr_data = data_old;
@@ -1173,10 +1278,11 @@
dbuf_add_ref(db, (void *)(uintptr_t)tx->tx_txg);
db->db_dirtycnt += 1;
ASSERT3U(db->db_dirtycnt, <=, 3);
mutex_exit(&db->db_mtx);
+ dmu_buf_destroy_user_evict_list(&evict_list);
if (db->db_blkid == DMU_BONUS_BLKID ||
db->db_blkid == DMU_SPILL_BLKID) {
mutex_enter(&dn->dn_mtx);
ASSERT(!list_link_active(&dr->dr_dirty_node));
@@ -1267,10 +1373,11 @@
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;
+ list_t evict_list;
ASSERT(txg != 0);
ASSERT(db->db_blkid != DMU_BONUS_BLKID);
ASSERT0(db->db_level);
ASSERT(MUTEX_HELD(&db->db_mtx));
@@ -1284,10 +1391,12 @@
if (dr == NULL || dr->dr_txg < txg)
return (B_FALSE);
ASSERT(dr->dr_txg == txg);
ASSERT(dr->dr_dbuf == db);
+ dmu_buf_create_user_evict_list(&evict_list);
+
DB_DNODE_ENTER(db);
dn = DB_DNODE(db);
/*
* Note: This code will probably work even if there are concurrent
@@ -1339,16 +1448,18 @@
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_set_data(db, NULL);
+ dbuf_clear_data(db, &evict_list);
VERIFY(arc_buf_remove_ref(buf, db));
- dbuf_evict(db);
+ dbuf_evict(db, &evict_list);
+ dmu_buf_destroy_user_evict_list(&evict_list);
return (B_TRUE);
}
+ dmu_buf_destroy_user_evict_list(&evict_list);
return (B_FALSE);
}
#pragma weak dmu_buf_will_dirty = dbuf_will_dirty
void
@@ -1491,21 +1602,21 @@
* Sometimes, though, we will get a mix of these two:
* DMU: dbuf_clear()->arc_buf_evict()
* ARC: dbuf_do_evict()->dbuf_destroy()
*/
void
-dbuf_clear(dmu_buf_impl_t *db)
+dbuf_clear(dmu_buf_impl_t *db, list_t *evict_list_p)
{
dnode_t *dn;
dmu_buf_impl_t *parent = db->db_parent;
dmu_buf_impl_t *dndb;
int dbuf_gone = FALSE;
ASSERT(MUTEX_HELD(&db->db_mtx));
ASSERT(refcount_is_zero(&db->db_holds));
- dbuf_evict_user(db);
+ dbuf_evict_user(db, evict_list_p);
if (db->db_state == DB_CACHED) {
ASSERT(db->db.db_data != NULL);
if (db->db_blkid == DMU_BONUS_BLKID) {
zio_buf_free(db->db.db_data, DN_MAX_BONUSLEN);
@@ -1644,13 +1755,11 @@
db->db_dirtycnt = 0;
db->db_dnode_handle = dn->dn_handle;
db->db_parent = parent;
db->db_blkptr = blkptr;
- db->db_user_ptr = NULL;
- db->db_user_data_ptr_ptr = NULL;
- db->db_evict_func = NULL;
+ db->db_user = NULL;
db->db_immediate_evict = 0;
db->db_freed_in_flight = 0;
if (blkid == DMU_BONUS_BLKID) {
ASSERT3P(parent, ==, dn->dn_dbuf);
@@ -1709,25 +1818,29 @@
static int
dbuf_do_evict(void *private)
{
arc_buf_t *buf = private;
dmu_buf_impl_t *db = buf->b_private;
+ list_t evict_list;
+
+ dmu_buf_create_user_evict_list(&evict_list);
if (!MUTEX_HELD(&db->db_mtx))
mutex_enter(&db->db_mtx);
ASSERT(refcount_is_zero(&db->db_holds));
if (db->db_state != DB_EVICTING) {
ASSERT(db->db_state == DB_CACHED);
DBUF_VERIFY(db);
db->db_buf = NULL;
- dbuf_evict(db);
+ dbuf_evict(db, &evict_list);
} else {
mutex_exit(&db->db_mtx);
dbuf_destroy(db);
}
+ dmu_buf_destroy_user_evict_list(&evict_list);
return (0);
}
static void
dbuf_destroy(dmu_buf_impl_t *db)
@@ -1824,15 +1937,18 @@
int
dbuf_hold_impl(dnode_t *dn, uint8_t level, uint64_t blkid, int fail_sparse,
void *tag, dmu_buf_impl_t **dbp)
{
dmu_buf_impl_t *db, *parent = NULL;
+ list_t evict_list;
ASSERT(blkid != DMU_BONUS_BLKID);
ASSERT(RW_LOCK_HELD(&dn->dn_struct_rwlock));
ASSERT3U(dn->dn_nlevels, >, level);
+ dmu_buf_create_user_evict_list(&evict_list);
+
*dbp = NULL;
top:
/* dbuf_find() returns with db_mtx held */
db = dbuf_find(dn, level, blkid);
@@ -1857,11 +1973,11 @@
}
if (db->db_buf && refcount_is_zero(&db->db_holds)) {
arc_buf_add_ref(db->db_buf, db);
if (db->db_buf->b_data == NULL) {
- dbuf_clear(db);
+ dbuf_clear(db, &evict_list);
if (parent) {
dbuf_rele(parent, NULL);
parent = NULL;
}
goto top;
@@ -1891,14 +2007,15 @@
db->db.db_size);
}
}
(void) refcount_add(&db->db_holds, tag);
- dbuf_update_data(db);
DBUF_VERIFY(db);
mutex_exit(&db->db_mtx);
+ dmu_buf_destroy_user_evict_list(&evict_list);
+
/* NOTE: we can't rele the parent until after we drop the db_mtx */
if (parent)
dbuf_rele(parent, NULL);
ASSERT3P(DB_DNODE(db), ==, dn);
@@ -1994,14 +2111,17 @@
*/
void
dbuf_rele_and_unlock(dmu_buf_impl_t *db, void *tag)
{
int64_t holds;
+ list_t evict_list;
ASSERT(MUTEX_HELD(&db->db_mtx));
DBUF_VERIFY(db);
+ dmu_buf_create_user_evict_list(&evict_list);
+
/*
* Remove the reference to the dbuf before removing its hold on the
* dnode so we can guarantee in dnode_move() that a referenced bonus
* buffer has a corresponding dnode hold.
*/
@@ -2015,11 +2135,11 @@
if (db->db_buf && holds == (db->db_level == 0 ? db->db_dirtycnt : 0))
arc_buf_freeze(db->db_buf);
if (holds == db->db_dirtycnt &&
db->db_level == 0 && db->db_immediate_evict)
- dbuf_evict_user(db);
+ dbuf_evict_user(db, &evict_list);
if (holds == 0) {
if (db->db_blkid == DMU_BONUS_BLKID) {
mutex_exit(&db->db_mtx);
@@ -2041,19 +2161,19 @@
* This is a special case: we never associated this
* dbuf with any data allocated from the ARC.
*/
ASSERT(db->db_state == DB_UNCACHED ||
db->db_state == DB_NOFILL);
- dbuf_evict(db);
+ dbuf_evict(db, &evict_list);
} else if (arc_released(db->db_buf)) {
arc_buf_t *buf = db->db_buf;
/*
* This dbuf has anonymous data associated with it.
*/
- dbuf_set_data(db, NULL);
+ dbuf_clear_data(db, &evict_list);
VERIFY(arc_buf_remove_ref(buf, db));
- dbuf_evict(db);
+ dbuf_evict(db, &evict_list);
} else {
VERIFY(!arc_buf_remove_ref(db->db_buf, db));
/*
* A dbuf will be eligible for eviction if either the
@@ -2070,79 +2190,27 @@
* block on-disk. If so, then we simply evict
* ourselves.
*/
if (!DBUF_IS_CACHEABLE(db) ||
arc_buf_eviction_needed(db->db_buf))
- dbuf_clear(db);
+ dbuf_clear(db, &evict_list);
else
mutex_exit(&db->db_mtx);
}
} else {
mutex_exit(&db->db_mtx);
}
+ dmu_buf_destroy_user_evict_list(&evict_list);
}
#pragma weak dmu_buf_refcount = dbuf_refcount
uint64_t
dbuf_refcount(dmu_buf_impl_t *db)
{
return (refcount_count(&db->db_holds));
}
-void *
-dmu_buf_set_user(dmu_buf_t *db_fake, void *user_ptr, void *user_data_ptr_ptr,
- dmu_buf_evict_func_t *evict_func)
-{
- return (dmu_buf_update_user(db_fake, NULL, user_ptr,
- user_data_ptr_ptr, evict_func));
-}
-
-void *
-dmu_buf_set_user_ie(dmu_buf_t *db_fake, void *user_ptr, void *user_data_ptr_ptr,
- dmu_buf_evict_func_t *evict_func)
-{
- dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
-
- db->db_immediate_evict = TRUE;
- return (dmu_buf_update_user(db_fake, NULL, user_ptr,
- user_data_ptr_ptr, evict_func));
-}
-
-void *
-dmu_buf_update_user(dmu_buf_t *db_fake, void *old_user_ptr, void *user_ptr,
- void *user_data_ptr_ptr, dmu_buf_evict_func_t *evict_func)
-{
- dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
- ASSERT(db->db_level == 0);
-
- ASSERT((user_ptr == NULL) == (evict_func == NULL));
-
- mutex_enter(&db->db_mtx);
-
- if (db->db_user_ptr == old_user_ptr) {
- db->db_user_ptr = user_ptr;
- db->db_user_data_ptr_ptr = user_data_ptr_ptr;
- db->db_evict_func = evict_func;
-
- dbuf_update_data(db);
- } else {
- old_user_ptr = db->db_user_ptr;
- }
-
- mutex_exit(&db->db_mtx);
- return (old_user_ptr);
-}
-
-void *
-dmu_buf_get_user(dmu_buf_t *db_fake)
-{
- dmu_buf_impl_t *db = (dmu_buf_impl_t *)db_fake;
- ASSERT(!refcount_is_zero(&db->db_holds));
-
- return (db->db_user_ptr);
-}
-
boolean_t
dmu_buf_freeable(dmu_buf_t *dbuf)
{
boolean_t res = B_FALSE;
dmu_buf_impl_t *db = (dmu_buf_impl_t *)dbuf;