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;