--- old/usr/src/cmd/mdb/common/modules/zfs/zfs.c	2013-04-25 16:14:55.981667551 -0600
+++ new/usr/src/cmd/mdb/common/modules/zfs/zfs.c	2013-04-25 16:14:55.991540089 -0600
@@ -521,7 +521,7 @@
 	char buf[16*1024];
 	int verbose = B_FALSE;
 	int four = B_FALSE;
-	zap_leaf_t l;
+	zap_leaf_t l = { 0 };
 	zap_leaf_phys_t *zlp = (void *)buf;
 	int i;
 
@@ -1425,8 +1425,17 @@
 	uintptr_t spa_root_vdev;
 } mdb_spa_t;
 
+struct mdb_dsl_dir_phys;
+typedef struct mdb_dsl_dir_dbuf {
+	uint8_t dddb_pad[offsetof(dmu_buf_t, db_data)];
+	uintptr_t dddb_data;
+} mdb_dsl_dir_dbuf_t;
+
 typedef struct mdb_dsl_dir {
-	uintptr_t dd_phys;
+	union {
+		dmu_buf_t *dd_dmu_db;
+		mdb_dsl_dir_dbuf_t *dd_db;
+	} dd_db_u;
 	int64_t dd_space_towrite[TXG_SIZE];
 } mdb_dsl_dir_t;
 
--- old/usr/src/lib/libzfs/common/libzfs_impl.h	2013-04-25 16:14:56.371648367 -0600
+++ new/usr/src/lib/libzfs/common/libzfs_impl.h	2013-04-25 16:14:56.381104489 -0600
@@ -27,7 +27,6 @@
 #ifndef	_LIBZFS_IMPL_H
 #define	_LIBZFS_IMPL_H
 
-#include <sys/dmu.h>
 #include <sys/fs/zfs.h>
 #include <sys/zfs_ioctl.h>
 #include <sys/spa.h>
--- old/usr/src/uts/common/fs/zfs/dbuf.c	2013-04-25 16:14:56.623170102 -0600
+++ new/usr/src/uts/common/fs/zfs/dbuf.c	2013-04-25 16:14:56.632116282 -0600
@@ -204,19 +204,137 @@
 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
@@ -236,13 +354,13 @@
 }
 
 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);
 }
 
@@ -405,36 +523,6 @@
 }
 #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.
  */
@@ -442,6 +530,9 @@
 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) {
@@ -455,9 +546,10 @@
 	} 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);
 }
 
@@ -534,7 +626,6 @@
 		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;
@@ -667,8 +758,12 @@
 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);
@@ -682,11 +777,12 @@
 		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);
 }
 
 /*
@@ -703,7 +799,7 @@
  * 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;
 
@@ -739,7 +835,7 @@
 		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);
 	}
 }
 
@@ -796,6 +892,9 @@
 	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;
@@ -849,7 +948,7 @@
 		}
 		if (refcount_count(&db->db_holds) == 0) {
 			ASSERT(db->db_buf);
-			dbuf_clear(db);
+			dbuf_clear(db, &evict_list);
 			continue;
 		}
 		/* The dbuf is referenced */
@@ -874,7 +973,7 @@
 				 * 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 */
@@ -886,8 +985,10 @@
 		}
 
 		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
@@ -996,6 +1097,9 @@
 	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));
@@ -1070,6 +1174,7 @@
 				arc_buf_thaw(db->db_buf);
 		}
 		mutex_exit(&db->db_mtx);
+		dmu_buf_destroy_user_evict_list(&evict_list);
 		return (dr);
 	}
 
@@ -1124,7 +1229,7 @@
 
 		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) {
 				/*
@@ -1137,7 +1242,7 @@
 				 * 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);
@@ -1175,6 +1280,7 @@
 	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) {
@@ -1269,6 +1375,7 @@
 	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);
@@ -1286,6 +1393,8 @@
 	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);
 
@@ -1341,12 +1450,14 @@
 		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);
 }
 
@@ -1493,7 +1604,7 @@
  *	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;
@@ -1503,7 +1614,7 @@
 	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);
@@ -1646,9 +1757,7 @@
 	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;
 
@@ -1711,6 +1820,9 @@
 {
 	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);
@@ -1721,11 +1833,12 @@
 		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);
 }
 
@@ -1826,11 +1939,14 @@
     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 */
@@ -1859,7 +1975,7 @@
 	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;
@@ -1893,10 +2009,11 @@
 	}
 
 	(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);
@@ -1996,10 +2113,13 @@
 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
@@ -2017,7 +2137,7 @@
 
 	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) {
@@ -2043,15 +2163,15 @@
 			 */
 			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));
 
@@ -2072,13 +2192,14 @@
 			 */
 			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
@@ -2088,59 +2209,6 @@
 	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)
 {
--- old/usr/src/uts/common/fs/zfs/dnode.c	2013-04-25 16:14:57.015679622 -0600
+++ new/usr/src/uts/common/fs/zfs/dnode.c	2013-04-25 16:14:57.025045793 -0600
@@ -458,8 +458,12 @@
 		dn->dn_dirtyctx_firstset = NULL;
 	}
 	if (dn->dn_bonus != NULL) {
+		list_t evict_list;
+
+		dmu_buf_create_user_evict_list(&evict_list);
 		mutex_enter(&dn->dn_bonus->db_mtx);
-		dbuf_evict(dn->dn_bonus);
+		dbuf_evict(dn->dn_bonus, &evict_list);
+		dmu_buf_destroy_user_evict_list(&evict_list);
 		dn->dn_bonus = NULL;
 	}
 	dn->dn_zio = NULL;
@@ -957,15 +961,12 @@
 }
 
 static void
-dnode_buf_pageout(dmu_buf_t *db, void *arg)
+dnode_buf_pageout(dmu_buf_user_t *dbu)
 {
-	dnode_children_t *children_dnodes = arg;
+	dnode_children_t *children_dnodes = (dnode_children_t *)dbu;
 	int i;
-	int epb = db->db_size >> DNODE_SHIFT;
-
-	ASSERT(epb == children_dnodes->dnc_count);
 
-	for (i = 0; i < epb; i++) {
+	for (i = 0; i < children_dnodes->dnc_count; i++) {
 		dnode_handle_t *dnh = &children_dnodes->dnc_children[i];
 		dnode_t *dn;
 
@@ -995,7 +996,7 @@
 		dnh->dnh_dnode = NULL;
 	}
 	kmem_free(children_dnodes, sizeof (dnode_children_t) +
-	    (epb - 1) * sizeof (dnode_handle_t));
+	    (children_dnodes->dnc_count - 1) * sizeof (dnode_handle_t));
 }
 
 /*
@@ -1075,7 +1076,7 @@
 	idx = object & (epb-1);
 
 	ASSERT(DB_DNODE(db)->dn_type == DMU_OT_DNODE);
-	children_dnodes = dmu_buf_get_user(&db->db);
+	children_dnodes = (dnode_children_t *)dmu_buf_get_user(&db->db);
 	if (children_dnodes == NULL) {
 		int i;
 		dnode_children_t *winner;
@@ -1087,8 +1088,11 @@
 			zrl_init(&dnh[i].dnh_zrlock);
 			dnh[i].dnh_dnode = NULL;
 		}
-		if (winner = dmu_buf_set_user(&db->db, children_dnodes, NULL,
-		    dnode_buf_pageout)) {
+		dmu_buf_init_user(&children_dnodes->db_evict,
+		    dnode_buf_pageout);
+		winner = (dnode_children_t *)
+		    dmu_buf_set_user(&db->db, &children_dnodes->db_evict);
+		if (winner) {
 			kmem_free(children_dnodes, sizeof (dnode_children_t) +
 			    (epb - 1) * sizeof (dnode_handle_t));
 			children_dnodes = winner;
--- old/usr/src/uts/common/fs/zfs/dnode_sync.c	2013-04-25 16:14:57.357031657 -0600
+++ new/usr/src/uts/common/fs/zfs/dnode_sync.c	2013-04-25 16:14:57.364936573 -0600
@@ -377,6 +377,9 @@
 {
 	int progress;
 	int pass = 0;
+	list_t evict_list;
+
+	dmu_buf_create_user_evict_list(&evict_list);
 
 	do {
 		dmu_buf_impl_t *db, marker;
@@ -402,11 +405,12 @@
 				mutex_exit(&db->db_mtx);
 			} else if (refcount_is_zero(&db->db_holds)) {
 				progress = TRUE;
-				dbuf_clear(db); /* exits db_mtx for us */
+				dbuf_clear(db, &evict_list); /* exits db_mtx */
 			} else {
 				mutex_exit(&db->db_mtx);
 			}
-
+			ASSERT(MUTEX_NOT_HELD(&db->db_mtx));
+			dmu_buf_process_user_evicts(&evict_list);
 		}
 		list_remove(&dn->dn_dbufs, &marker);
 		/*
@@ -426,10 +430,11 @@
 	rw_enter(&dn->dn_struct_rwlock, RW_WRITER);
 	if (dn->dn_bonus && refcount_is_zero(&dn->dn_bonus->db_holds)) {
 		mutex_enter(&dn->dn_bonus->db_mtx);
-		dbuf_evict(dn->dn_bonus);
+		dbuf_evict(dn->dn_bonus, &evict_list);
 		dn->dn_bonus = NULL;
 	}
 	rw_exit(&dn->dn_struct_rwlock);
+	dmu_buf_destroy_user_evict_list(&evict_list);
 }
 
 static void
--- old/usr/src/uts/common/fs/zfs/dsl_dataset.c	2013-04-25 16:14:57.630703834 -0600
+++ new/usr/src/uts/common/fs/zfs/dsl_dataset.c	2013-04-25 16:14:57.639030209 -0600
@@ -241,12 +241,13 @@
 
 /* ARGSUSED */
 static void
-dsl_dataset_evict(dmu_buf_t *db, void *dsv)
+dsl_dataset_evict_impl(dsl_dataset_t *ds, boolean_t evict_deadlist)
 {
-	dsl_dataset_t *ds = dsv;
 
 	ASSERT(ds->ds_owner == NULL);
 
+	ds->ds_dbuf = NULL;
+
 	unique_remove(ds->ds_fsid_guid);
 
 	if (ds->ds_objset != NULL)
@@ -258,7 +259,7 @@
 	}
 
 	bplist_destroy(&ds->ds_pending_deadlist);
-	if (ds->ds_phys->ds_deadlist_obj != 0)
+	if (evict_deadlist)
 		dsl_deadlist_close(&ds->ds_deadlist);
 	if (ds->ds_dir)
 		dsl_dir_rele(ds->ds_dir, ds);
@@ -272,6 +273,13 @@
 	kmem_free(ds, sizeof (dsl_dataset_t));
 }
 
+/* ARGSUSED */
+static void
+dsl_dataset_evict(dmu_buf_user_t *dbu)
+{
+	dsl_dataset_evict_impl((dsl_dataset_t *)dbu, B_TRUE);
+}
+
 int
 dsl_dataset_get_snapname(dsl_dataset_t *ds)
 {
@@ -359,14 +367,13 @@
 	if (doi.doi_type != DMU_OT_DSL_DATASET)
 		return (SET_ERROR(EINVAL));
 
-	ds = dmu_buf_get_user(dbuf);
+	ds = (dsl_dataset_t *)dmu_buf_get_user(dbuf);
 	if (ds == NULL) {
 		dsl_dataset_t *winner = NULL;
 
 		ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP);
 		ds->ds_dbuf = dbuf;
 		ds->ds_object = dsobj;
-		ds->ds_phys = dbuf->db_data;
 
 		mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL);
 		mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL);
@@ -426,8 +433,12 @@
 			ds->ds_reserved = ds->ds_quota = 0;
 		}
 
-		if (err != 0 || (winner = dmu_buf_set_user_ie(dbuf, ds,
-		    &ds->ds_phys, dsl_dataset_evict)) != NULL) {
+		dmu_buf_init_user(&ds->db_evict, dsl_dataset_evict);
+		if (err == 0)
+			winner = (dsl_dataset_t *)
+			    dmu_buf_set_user_ie(dbuf, &ds->db_evict);
+
+		if (err || winner) {
 			bplist_destroy(&ds->ds_pending_deadlist);
 			dsl_deadlist_close(&ds->ds_deadlist);
 			if (ds->ds_prev)
@@ -632,7 +643,7 @@
 	if (ds->ds_dbuf != NULL)
 		dsl_dataset_rele(ds, tag);
 	else
-		dsl_dataset_evict(NULL, ds);
+		dsl_dataset_evict_impl(ds, B_FALSE);
 }
 
 boolean_t
--- old/usr/src/uts/common/fs/zfs/dsl_dir.c	2013-04-25 16:14:58.024604093 -0600
+++ new/usr/src/uts/common/fs/zfs/dsl_dir.c	2013-04-25 16:14:58.033443344 -0600
@@ -43,12 +43,14 @@
 
 /* ARGSUSED */
 static void
-dsl_dir_evict(dmu_buf_t *db, void *arg)
+dsl_dir_evict(dmu_buf_user_t *dbu)
 {
-	dsl_dir_t *dd = arg;
+	dsl_dir_t *dd = (dsl_dir_t *)dbu;
 	dsl_pool_t *dp = dd->dd_pool;
 	int t;
 
+	dd->dd_dbuf = NULL;
+
 	for (t = 0; t < TXG_SIZE; t++) {
 		ASSERT(!txg_list_member(&dp->dp_dirty_dirs, dd, t));
 		ASSERT(dd->dd_tempreserved[t] == 0);
@@ -82,7 +84,7 @@
 	err = dmu_bonus_hold(dp->dp_meta_objset, ddobj, tag, &dbuf);
 	if (err != 0)
 		return (err);
-	dd = dmu_buf_get_user(dbuf);
+	dd = (dsl_dir_t *)dmu_buf_get_user(dbuf);
 #ifdef ZFS_DEBUG
 	{
 		dmu_object_info_t doi;
@@ -98,7 +100,6 @@
 		dd->dd_object = ddobj;
 		dd->dd_dbuf = dbuf;
 		dd->dd_pool = dp;
-		dd->dd_phys = dbuf->db_data;
 		mutex_init(&dd->dd_lock, NULL, MUTEX_DEFAULT, NULL);
 
 		list_create(&dd->dd_prop_cbs, sizeof (dsl_prop_cb_record_t),
@@ -151,8 +152,8 @@
 			dmu_buf_rele(origin_bonus, FTAG);
 		}
 
-		winner = dmu_buf_set_user_ie(dbuf, dd, &dd->dd_phys,
-		    dsl_dir_evict);
+		dmu_buf_init_user(&dd->db_evict, dsl_dir_evict);
+		winner = (dsl_dir_t *)dmu_buf_set_user_ie(dbuf, &dd->db_evict);
 		if (winner) {
 			if (dd->dd_parent)
 				dsl_dir_rele(dd->dd_parent, dd);
--- old/usr/src/uts/common/fs/zfs/dsl_prop.c	2013-04-25 16:14:58.328465911 -0600
+++ new/usr/src/uts/common/fs/zfs/dsl_prop.c	2013-04-25 16:14:58.338021349 -0600
@@ -167,8 +167,8 @@
 
 	ASSERT(dsl_pool_config_held(ds->ds_dir->dd_pool));
 	inheritable = (prop == ZPROP_INVAL || zfs_prop_inheritable(prop));
-	snapshot = (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds));
-	zapobj = (ds->ds_phys == NULL ? 0 : ds->ds_phys->ds_props_obj);
+	snapshot = (DS_HAS_PHYS(ds) && dsl_dataset_is_snapshot(ds));
+	zapobj = (DS_HAS_PHYS(ds) ? ds->ds_phys->ds_props_obj : 0);
 
 	if (zapobj != 0) {
 		objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
@@ -543,7 +543,7 @@
 
 	isint = (dodefault(propname, 8, 1, &intval) == 0);
 
-	if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
+	if (DS_HAS_PHYS(ds) && dsl_dataset_is_snapshot(ds)) {
 		ASSERT(version >= SPA_VERSION_SNAP_PROPS);
 		if (ds->ds_phys->ds_props_obj == 0) {
 			dmu_buf_will_dirty(ds->ds_dbuf, tx);
@@ -644,7 +644,7 @@
 	if (isint) {
 		VERIFY0(dsl_prop_get_int_ds(ds, propname, &intval));
 
-		if (ds->ds_phys != NULL && dsl_dataset_is_snapshot(ds)) {
+		if (DS_HAS_PHYS(ds) && dsl_dataset_is_snapshot(ds)) {
 			dsl_prop_cb_record_t *cbr;
 			/*
 			 * It's a snapshot; nothing can inherit this
--- old/usr/src/uts/common/fs/zfs/sa.c	2013-04-25 16:14:58.617138545 -0600
+++ new/usr/src/uts/common/fs/zfs/sa.c	2013-04-25 16:14:58.626201866 -0600
@@ -1299,9 +1299,9 @@
 
 /*ARGSUSED*/
 void
-sa_evict(dmu_buf_t *db, void *sap)
+sa_evict(dmu_buf_user_t *dbu)
 {
-	panic("evicting sa dbuf %p\n", (void *)db);
+	panic("evicting sa dbuf\n");
 }
 
 static void
@@ -1340,9 +1340,10 @@
 void
 sa_handle_destroy(sa_handle_t *hdl)
 {
+	dmu_buf_t *db = hdl->sa_bonus;
+
 	mutex_enter(&hdl->sa_lock);
-	(void) dmu_buf_update_user((dmu_buf_t *)hdl->sa_bonus, hdl,
-	    NULL, NULL, NULL);
+	(void) dmu_buf_remove_user(db, &hdl->db_evict);
 
 	if (hdl->sa_bonus_tab) {
 		sa_idx_tab_rele(hdl->sa_os, hdl->sa_bonus_tab);
@@ -1368,7 +1369,7 @@
 {
 	int error = 0;
 	dmu_object_info_t doi;
-	sa_handle_t *handle;
+	sa_handle_t *handle = NULL;
 
 #ifdef ZFS_DEBUG
 	dmu_object_info_from_db(db, &doi);
@@ -1378,9 +1379,13 @@
 	/* find handle, if it exists */
 	/* if one doesn't exist then create a new one, and initialize it */
 
-	handle = (hdl_type == SA_HDL_SHARED) ? dmu_buf_get_user(db) : NULL;
+	if (hdl_type == SA_HDL_SHARED)
+		handle = (sa_handle_t *)dmu_buf_get_user(db);
+
 	if (handle == NULL) {
-		sa_handle_t *newhandle;
+		sa_handle_t *winner = NULL;
+
+		bzero(&handle->db_evict, sizeof(dmu_buf_user_t));
 		handle = kmem_cache_alloc(sa_cache, KM_SLEEP);
 		handle->sa_userp = userp;
 		handle->sa_bonus = db;
@@ -1388,13 +1393,14 @@
 		handle->sa_spill = NULL;
 
 		error = sa_build_index(handle, SA_BONUS);
-		newhandle = (hdl_type == SA_HDL_SHARED) ?
-		    dmu_buf_set_user_ie(db, handle,
-		    NULL, sa_evict) : NULL;
-
-		if (newhandle != NULL) {
+		if (hdl_type == SA_HDL_SHARED) {
+			dmu_buf_init_user(&handle->db_evict, sa_evict);
+			winner = (sa_handle_t *)
+			    dmu_buf_set_user_ie(db, &handle->db_evict);
+		}
+		if (winner != NULL) {
 			kmem_cache_free(sa_cache, handle);
-			handle = newhandle;
+			handle = winner;
 		}
 	}
 	*handlepp = handle;
@@ -1907,8 +1913,12 @@
 void
 sa_update_user(sa_handle_t *newhdl, sa_handle_t *oldhdl)
 {
-	(void) dmu_buf_update_user((dmu_buf_t *)newhdl->sa_bonus,
-	    oldhdl, newhdl, NULL, sa_evict);
+	dmu_buf_user_t *new_user = &newhdl->db_evict;
+	dmu_buf_user_t *old_user = &oldhdl->db_evict;
+
+	dmu_buf_init_user(new_user, sa_evict);
+	VERIFY(dmu_buf_replace_user(newhdl->sa_bonus, old_user,
+	    new_user) == old_user);
 	oldhdl->sa_bonus = NULL;
 }
 
--- old/usr/src/uts/common/fs/zfs/sys/dbuf.h	2013-04-25 16:14:58.941342553 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/dbuf.h	2013-04-25 16:14:58.949658803 -0600
@@ -217,10 +217,8 @@
 
 	/* Data which is unique to data (leaf) blocks: */
 
-	/* stuff we store for the user (see dmu_buf_set_user) */
-	void *db_user_ptr;
-	void **db_user_data_ptr_ptr;
-	dmu_buf_evict_func_t *db_evict_func;
+	/* User callback information.  See dmu_buf_set_user(). */
+	dmu_buf_user_t *db_user;
 
 	uint8_t db_immediate_evict;
 	uint8_t db_freed_in_flight;
@@ -273,8 +271,8 @@
 dbuf_dirty_record_t *dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx);
 arc_buf_t *dbuf_loan_arcbuf(dmu_buf_impl_t *db);
 
-void dbuf_clear(dmu_buf_impl_t *db);
-void dbuf_evict(dmu_buf_impl_t *db);
+void dbuf_clear(dmu_buf_impl_t *db, list_t *evict_list_p);
+void dbuf_evict(dmu_buf_impl_t *db, list_t *evict_list_p);
 
 void dbuf_setdirty(dmu_buf_impl_t *db, dmu_tx_t *tx);
 void dbuf_unoverride(dbuf_dirty_record_t *dr);
--- old/usr/src/uts/common/fs/zfs/sys/dmu.h	2013-04-25 16:14:59.196027710 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/dmu.h	2013-04-25 16:14:59.204210963 -0600
@@ -39,6 +39,7 @@
  * dmu_spa.h.
  */
 
+#include <sys/zfs_context.h>
 #include <sys/inttypes.h>
 #include <sys/types.h>
 #include <sys/param.h>
@@ -281,8 +282,6 @@
 	void *db_data;			/* data in buffer */
 } dmu_buf_t;
 
-typedef void dmu_buf_evict_func_t(struct dmu_buf *db, void *user_ptr);
-
 /*
  * The names of zap entries in the DIRECTORY_OBJECT of the MOS.
  */
@@ -460,42 +459,104 @@
     uint64_t length, int read, void *tag, int *numbufsp, dmu_buf_t ***dbpp);
 void dmu_buf_rele_array(dmu_buf_t **, int numbufs, void *tag);
 
-/*
- * Returns NULL on success, or the existing user ptr if it's already
- * been set.
- *
- * user_ptr is for use by the user and can be obtained via dmu_buf_get_user().
- *
- * user_data_ptr_ptr should be NULL, or a pointer to a pointer which
- * will be set to db->db_data when you are allowed to access it.  Note
- * that db->db_data (the pointer) can change when you do dmu_buf_read(),
- * dmu_buf_tryupgrade(), dmu_buf_will_dirty(), or dmu_buf_will_fill().
- * *user_data_ptr_ptr will be set to the new value when it changes.
- *
- * If non-NULL, pageout func will be called when this buffer is being
- * excised from the cache, so that you can clean up the data structure
- * pointed to by user_ptr.
- *
- * dmu_evict_user() will call the pageout func for all buffers in a
- * objset with a given pageout func.
- */
-void *dmu_buf_set_user(dmu_buf_t *db, void *user_ptr, void *user_data_ptr_ptr,
-    dmu_buf_evict_func_t *pageout_func);
-/*
- * set_user_ie is the same as set_user, but request immediate eviction
- * when hold count goes to zero.
- */
-void *dmu_buf_set_user_ie(dmu_buf_t *db, void *user_ptr,
-    void *user_data_ptr_ptr, dmu_buf_evict_func_t *pageout_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 *pageout_func);
-void dmu_evict_user(objset_t *os, dmu_buf_evict_func_t *func);
+struct dmu_buf_user;
+
+typedef void dmu_buf_evict_func_t(struct dmu_buf_user *);
 
 /*
- * Returns the user_ptr set with dmu_buf_set_user(), or NULL if not set.
+ * The DMU buffer user object is used to allow private data to be
+ * associated with a dbuf for the duration of its lifetime.  This private
+ * data must include a dmu_buf_user_t as its first object, which is passed
+ * into the DMU user data API and can be attached to a dbuf.  Clients can
+ * regain access to their private data structure with a cast.
+ *
+ * DMU buffer users can be notified via a callback when their associated
+ * dbuf has been evicted.  This is typically used to free the user's
+ * private data.  The eviction callback is executed without the dbuf
+ * mutex held or any other type of mechanism to guarantee that the
+ * dbuf is still available.  For this reason, users must assume the dbuf
+ * has already been freed and not reference the dbuf from the callback
+ * context.
+ *
+ * Users requestion "immediate eviction" are notified as soon as the dbuf
+ * is only referenced by dirty records (dirties == holds).  Otherwise the
+ * eviction callback occurs after the last reference to the dbuf is dropped.    
+ *
+ * Eviction Callback Processing
+ * ============================
+ * In any context where a dbuf reference drop may trigger an eviction, an       
+ * eviction queue object must be provided.  This queue must then be
+ * processed while not holding any dbuf locks.  In this way, the user can       
+ * perform any work needed in their eviction function without fear of
+ * lock order reversals.
+ *
+ * Implementation Note
+ * ============================
+ * Some users will occasionally want to map a structure directly onto the
+ * backing dbuf.  Using an union with an name alias macro to access these
+ * overlays reduces the ugliness of code that accesses them.  Initial work on
+ * user objects involved using a macro that took the user object as an
+ * argument to access the fields, which resulted in hundreds of lines of
+ * needless diffs and wasn't any easier to read.
  */
-void *dmu_buf_get_user(dmu_buf_t *db);
+typedef struct dmu_buf_user {
+	/*
+	 * This instance's link in the eviction queue.  Set when the buffer
+	 * has evicted and the callback needs to be called.
+	 */
+	list_node_t evict_queue_link;
+	/** This instance's eviction function pointer. */
+	dmu_buf_evict_func_t *evict_func;
+} dmu_buf_user_t;
+
+/*
+ * Initialize the given dmu_buf_user_t instance with the eviction function
+ * evict_func, to be called when the user is evicted.
+ *
+ * NOTE: This function should only be called once on a given object.  To
+ *       help enforce this, dbu should already be zeroed on entry.
+ */
+static inline void
+dmu_buf_init_user(dmu_buf_user_t *dbu, dmu_buf_evict_func_t *evict_func)
+{
+	ASSERT(dbu->evict_func == NULL);
+	ASSERT(!list_link_active(&dbu->evict_queue_link));
+	dbu->evict_func = evict_func;
+}
+
+static inline void
+dmu_buf_create_user_evict_list(list_t *evict_list_p)
+{
+	list_create(evict_list_p, sizeof(dmu_buf_user_t),
+	    offsetof(dmu_buf_user_t, evict_queue_link));
+}
+
+static inline void
+dmu_buf_process_user_evicts(list_t *evict_list_p)
+{
+	dmu_buf_user_t *dbu, *next;
+
+	for (dbu = (dmu_buf_user_t *)list_head(evict_list_p); dbu != NULL;
+	    dbu = next) {
+		next = (dmu_buf_user_t *)list_next(evict_list_p, dbu);
+		list_remove(evict_list_p, dbu);
+		dbu->evict_func(dbu);
+	}
+}
+
+static inline void
+dmu_buf_destroy_user_evict_list(list_t *evict_list_p)
+{
+	dmu_buf_process_user_evicts(evict_list_p);
+	list_destroy(evict_list_p);
+}
+
+dmu_buf_user_t *dmu_buf_set_user(dmu_buf_t *db, dmu_buf_user_t *user);
+dmu_buf_user_t *dmu_buf_set_user_ie(dmu_buf_t *db, dmu_buf_user_t *user);
+dmu_buf_user_t *dmu_buf_replace_user(dmu_buf_t *db,
+    dmu_buf_user_t *old_user, dmu_buf_user_t *new_user);
+dmu_buf_user_t *dmu_buf_remove_user(dmu_buf_t *db, dmu_buf_user_t *user);
+dmu_buf_user_t *dmu_buf_get_user(dmu_buf_t *db);
 
 /*
  * Returns the blkptr associated with this dbuf, or NULL if not set.
--- old/usr/src/uts/common/fs/zfs/sys/dmu_impl.h	2013-04-25 16:14:59.477415724 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/dmu_impl.h	2013-04-25 16:14:59.486454341 -0600
@@ -32,6 +32,7 @@
 #include <sys/dnode.h>
 #include <sys/zfs_context.h>
 #include <sys/zfs_ioctl.h>
+#include <sys/dmu.h>
 
 #ifdef	__cplusplus
 extern "C" {
--- old/usr/src/uts/common/fs/zfs/sys/dnode.h	2013-04-25 16:14:59.731202826 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/dnode.h	2013-04-25 16:14:59.740603124 -0600
@@ -242,6 +242,7 @@
 } dnode_handle_t;
 
 typedef struct dnode_children {
+	dmu_buf_user_t db_evict;	/* User evict data */
 	size_t dnc_count;		/* number of children */
 	dnode_handle_t dnc_children[1];	/* sized dynamically */
 } dnode_children_t;
--- old/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h	2013-04-25 16:14:59.989844958 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h	2013-04-25 16:14:59.997993068 -0600
@@ -45,6 +45,9 @@
 struct dsl_dir;
 struct dsl_pool;
 
+#define	DS_HAS_PHYS(ds)	\
+	((ds)->ds_dbuf != NULL && (ds)->ds_dbuf->db_data != NULL)
+
 #define	DS_FLAG_INCONSISTENT	(1ULL<<0)
 #define	DS_IS_INCONSISTENT(ds)	\
 	((ds)->ds_phys->ds_flags & DS_FLAG_INCONSISTENT)
@@ -111,11 +114,20 @@
 	uint64_t ds_pad[5]; /* pad out to 320 bytes for good measure */
 } dsl_dataset_phys_t;
 
+typedef struct dsl_dataset_dbuf {
+	uint8_t dsdb_pad[offsetof(dmu_buf_t, db_data)];
+	dsl_dataset_phys_t *dsdb_data;
+} dsl_dataset_dbuf_t;
+
 typedef struct dsl_dataset {
+	dmu_buf_user_t db_evict;
+
 	/* Immutable: */
 	struct dsl_dir *ds_dir;
-	dsl_dataset_phys_t *ds_phys;
-	dmu_buf_t *ds_dbuf;
+	union {
+		dmu_buf_t *ds_dmu_db;
+		dsl_dataset_dbuf_t *ds_db;
+	} ds_db_u;
 	uint64_t ds_object;
 	uint64_t ds_fsid_guid;
 
@@ -163,6 +175,19 @@
 	char ds_snapname[MAXNAMELEN];
 } dsl_dataset_t;
 
+/* See sys/dmu.h:dmu_buf_user_t for why we have these. */
+#define	ds_dbuf ds_db_u.ds_dmu_db
+#define	ds_phys ds_db_u.ds_db->dsdb_data
+
+struct dsl_ds_destroyarg {
+	dsl_dataset_t *ds;		/* ds to destroy */
+	dsl_dataset_t *rm_origin;	/* also remove our origin? */
+	boolean_t is_origin_rm;		/* set if removing origin snap */
+	boolean_t defer;		/* destroy -d requested? */
+	boolean_t releasing;		/* destroying due to release? */
+	boolean_t need_prep;		/* do we need to retry due to EBUSY? */
+};
+
 /*
  * The max length of a temporary tag prefix is the number of hex digits
  * required to express UINT64_MAX plus one for the hyphen.
--- old/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h	2013-04-25 16:15:00.246986558 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h	2013-04-25 16:15:00.255050119 -0600
@@ -26,9 +26,9 @@
 #ifndef	_SYS_DSL_DELEG_H
 #define	_SYS_DSL_DELEG_H
 
+#include <sys/zfs_context.h>
 #include <sys/dmu.h>
 #include <sys/dsl_pool.h>
-#include <sys/zfs_context.h>
 
 #ifdef	__cplusplus
 extern "C" {
--- old/usr/src/uts/common/fs/zfs/sys/dsl_dir.h	2013-04-25 16:15:00.491590189 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/dsl_dir.h	2013-04-25 16:15:00.500256424 -0600
@@ -74,11 +74,20 @@
 	uint64_t dd_pad[13]; /* pad out to 256 bytes for good measure */
 } dsl_dir_phys_t;
 
+typedef struct dsl_dir_dbuf {
+	uint8_t dddb_pad[offsetof(dmu_buf_t, db_data)];
+	dsl_dir_phys_t *dddb_data;
+} dsl_dir_dbuf_t;
+
 struct dsl_dir {
+	dmu_buf_user_t db_evict;
+
 	/* These are immutable; no lock needed: */
 	uint64_t dd_object;
-	dsl_dir_phys_t *dd_phys;
-	dmu_buf_t *dd_dbuf;
+	union {
+		dmu_buf_t *dd_dmu_db;
+		dsl_dir_dbuf_t *dd_db;
+	} dd_db_u;
 	dsl_pool_t *dd_pool;
 
 	/* protected by lock on pool's dp_dirty_dirs list */
@@ -102,6 +111,10 @@
 	char dd_myname[MAXNAMELEN];
 };
 
+/* See sys/dmu.h:dmu_buf_user_t for why we have these. */
+#define	dd_dbuf dd_db_u.dd_dmu_db
+#define	dd_phys dd_db_u.dd_db->dddb_data
+
 void dsl_dir_rele(dsl_dir_t *dd, void *tag);
 int dsl_dir_hold(dsl_pool_t *dp, const char *name, void *tag,
     dsl_dir_t **, const char **tail);
--- old/usr/src/uts/common/fs/zfs/sys/sa_impl.h	2013-04-25 16:15:00.741888519 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/sa_impl.h	2013-04-25 16:15:00.750394137 -0600
@@ -209,6 +209,7 @@
  */
 
 struct sa_handle {
+	dmu_buf_user_t	db_evict;
 	kmutex_t	sa_lock;
 	dmu_buf_t	*sa_bonus;
 	dmu_buf_t	*sa_spill;
--- old/usr/src/uts/common/fs/zfs/sys/zap_impl.h	2013-04-25 16:15:00.993718846 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/zap_impl.h	2013-04-25 16:15:01.002055106 -0600
@@ -62,6 +62,11 @@
 	/* actually variable size depending on block size */
 } mzap_phys_t;
 
+typedef struct mzap_dbuf {
+	uint8_t mzdb_pad[offsetof(dmu_buf_t, db_data)];
+	mzap_phys_t *mzdb_data;
+} mzap_dbuf_t;
+
 typedef struct mzap_ent {
 	avl_node_t mze_node;
 	int mze_chunkid;
@@ -70,7 +75,7 @@
 } mzap_ent_t;
 
 #define	MZE_PHYS(zap, mze) \
-	(&(zap)->zap_m.zap_phys->mz_chunk[(mze)->mze_chunkid])
+	(&(zap)->zap_m_phys->mz_chunk[(mze)->mze_chunkid])
 
 /*
  * The (fat) zap is stored in one object. It is an array of
@@ -104,7 +109,7 @@
  * word number (1<<ZAP_EMBEDDED_PTRTBL_SHIFT(zap)).
  */
 #define	ZAP_EMBEDDED_PTRTBL_ENT(zap, idx) \
-	((uint64_t *)(zap)->zap_f.zap_phys) \
+	((uint64_t *)(zap)->zap_f_phys) \
 	[(idx) + (1<<ZAP_EMBEDDED_PTRTBL_SHIFT(zap))]
 
 /*
@@ -139,27 +144,31 @@
 
 typedef struct zap_table_phys zap_table_phys_t;
 
+typedef struct fzap_dbuf {
+	uint8_t fzdb_pad[offsetof(dmu_buf_t, db_data)];
+	zap_phys_t *fzdb_data;
+} fzap_dbuf_t;
+
 typedef struct zap {
+	dmu_buf_user_t db_evict;
 	objset_t *zap_objset;
 	uint64_t zap_object;
-	struct dmu_buf *zap_dbuf;
+	union {
+		dmu_buf_t *zap_dmu_db;
+		mzap_dbuf_t *mzap_db;
+		fzap_dbuf_t *fzap_db;
+	} zap_db_u;
 	krwlock_t zap_rwlock;
 	boolean_t zap_ismicro;
 	int zap_normflags;
 	uint64_t zap_salt;
 	union {
 		struct {
-			zap_phys_t *zap_phys;
-
-			/*
-			 * zap_num_entries_mtx protects
-			 * zap_num_entries
-			 */
+			/* protects zap_num_entries */
 			kmutex_t zap_num_entries_mtx;
 			int zap_block_shift;
 		} zap_fat;
 		struct {
-			mzap_phys_t *zap_phys;
 			int16_t zap_num_entries;
 			int16_t zap_num_chunks;
 			int16_t zap_alloc_next;
@@ -168,6 +177,13 @@
 	} zap_u;
 } zap_t;
 
+/* See sys/dmu.h:dmu_buf_user_t for why we have these. */
+#define	zap_dbuf	zap_db_u.zap_dmu_db
+#define	zap_f		zap_u.zap_fat
+#define	zap_m		zap_u.zap_micro
+#define	zap_f_phys	zap_db_u.fzap_db->fzdb_data
+#define	zap_m_phys	zap_db_u.mzap_db->mzdb_data
+
 typedef struct zap_name {
 	zap_t *zn_zap;
 	int zn_key_intlen;
@@ -180,14 +196,11 @@
 	char zn_normbuf[ZAP_MAXNAMELEN];
 } zap_name_t;
 
-#define	zap_f	zap_u.zap_fat
-#define	zap_m	zap_u.zap_micro
-
 boolean_t zap_match(zap_name_t *zn, const char *matchname);
 int zap_lockdir(objset_t *os, uint64_t obj, dmu_tx_t *tx,
     krw_t lti, boolean_t fatreader, boolean_t adding, zap_t **zapp);
 void zap_unlockdir(zap_t *zap);
-void zap_evict(dmu_buf_t *db, void *vmzap);
+void zap_evict(dmu_buf_user_t *dbu);
 zap_name_t *zap_name_alloc(zap_t *zap, const char *key, matchtype_t mt);
 void zap_name_free(zap_name_t *zn);
 int zap_hashbits(zap_t *zap);
--- old/usr/src/uts/common/fs/zfs/sys/zap_leaf.h	2013-04-25 16:15:01.248543914 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/zap_leaf.h	2013-04-25 16:15:01.256834143 -0600
@@ -127,6 +127,11 @@
 	uint16_t l_hash[1];
 } zap_leaf_phys_t;
 
+typedef struct zap_leaf_dbuf {
+	uint8_t zldb_pad[offsetof(dmu_buf_t, db_data)];
+	zap_leaf_phys_t *zldb_data;
+} zap_leaf_dbuf_t;
+
 typedef union zap_leaf_chunk {
 	struct zap_leaf_entry {
 		uint8_t le_type; 		/* always ZAP_CHUNK_ENTRY */
@@ -152,13 +157,18 @@
 } zap_leaf_chunk_t;
 
 typedef struct zap_leaf {
+	dmu_buf_user_t db_evict;
 	krwlock_t l_rwlock;
 	uint64_t l_blkid;		/* 1<<ZAP_BLOCK_SHIFT byte block off */
 	int l_bs;			/* block size shift */
-	dmu_buf_t *l_dbuf;
-	zap_leaf_phys_t *l_phys;
+	union {
+		dmu_buf_t *l_dmu_db;
+		zap_leaf_dbuf_t *l_db;
+	} zl_db_u;
 } zap_leaf_t;
 
+#define	l_dbuf zl_db_u.l_dmu_db
+#define	l_phys zl_db_u.l_db->zldb_data
 
 typedef struct zap_entry_handle {
 	/* below is set by zap_leaf.c and is public to zap.c */
--- old/usr/src/uts/common/fs/zfs/sys/zfs_context.h	2013-04-25 16:15:01.501461913 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/zfs_context.h	2013-04-25 16:15:01.509574178 -0600
@@ -35,6 +35,9 @@
 extern "C" {
 #endif
 
+#ifndef _KERNEL
+#include <stddef.h>
+#endif
 #include <sys/note.h>
 #include <sys/types.h>
 #include <sys/t_lock.h>
--- old/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h	2013-04-25 16:15:01.751448961 -0600
+++ new/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h	2013-04-25 16:15:01.759514840 -0600
@@ -26,6 +26,9 @@
 #ifndef	_SYS_ZFS_IOCTL_H
 #define	_SYS_ZFS_IOCTL_H
 
+#ifndef _KERNEL
+#include <stddef.h>
+#endif
 #include <sys/cred.h>
 #include <sys/dmu.h>
 #include <sys/zio.h>
--- old/usr/src/uts/common/fs/zfs/zap.c	2013-04-25 16:15:02.011972939 -0600
+++ new/usr/src/uts/common/fs/zfs/zap.c	2013-04-25 16:15:02.021192603 -0600
@@ -50,10 +50,8 @@
 
 int fzap_default_block_shift = 14; /* 16k blocksize */
 
-static void zap_leaf_pageout(dmu_buf_t *db, void *vl);
 static uint64_t zap_allocate_blocks(zap_t *zap, int nblocks);
 
-
 void
 fzap_byteswap(void *vbuf, size_t size)
 {
@@ -80,13 +78,12 @@
 	ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
 	zap->zap_ismicro = FALSE;
 
-	(void) dmu_buf_update_user(zap->zap_dbuf, zap, zap,
-	    &zap->zap_f.zap_phys, zap_evict);
+	zap->db_evict.evict_func = zap_evict;
 
 	mutex_init(&zap->zap_f.zap_num_entries_mtx, 0, 0, 0);
 	zap->zap_f.zap_block_shift = highbit(zap->zap_dbuf->db_size) - 1;
 
-	zp = zap->zap_f.zap_phys;
+	zp = zap->zap_f_phys;
 	/*
 	 * explicitly zero it since it might be coming from an
 	 * initialized microzap
@@ -117,7 +114,6 @@
 
 	l = kmem_zalloc(sizeof (zap_leaf_t), KM_SLEEP);
 	l->l_dbuf = db;
-	l->l_phys = db->db_data;
 
 	zap_leaf_init(l, zp->zap_normflags != 0);
 
@@ -324,10 +320,10 @@
 	 * If we are within 2 bits of running out, stop growing, since
 	 * this is already an aberrant condition.
 	 */
-	if (zap->zap_f.zap_phys->zap_ptrtbl.zt_shift >= zap_hashbits(zap) - 2)
+	if (zap->zap_f_phys->zap_ptrtbl.zt_shift >= zap_hashbits(zap) - 2)
 		return (SET_ERROR(ENOSPC));
 
-	if (zap->zap_f.zap_phys->zap_ptrtbl.zt_numblks == 0) {
+	if (zap->zap_f_phys->zap_ptrtbl.zt_numblks == 0) {
 		/*
 		 * We are outgrowing the "embedded" ptrtbl (the one
 		 * stored in the header block).  Give it its own entire
@@ -337,9 +333,9 @@
 		dmu_buf_t *db_new;
 		int err;
 
-		ASSERT3U(zap->zap_f.zap_phys->zap_ptrtbl.zt_shift, ==,
+		ASSERT3U(zap->zap_f_phys->zap_ptrtbl.zt_shift, ==,
 		    ZAP_EMBEDDED_PTRTBL_SHIFT(zap));
-		ASSERT0(zap->zap_f.zap_phys->zap_ptrtbl.zt_blk);
+		ASSERT0(zap->zap_f_phys->zap_ptrtbl.zt_blk);
 
 		newblk = zap_allocate_blocks(zap, 1);
 		err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
@@ -352,17 +348,17 @@
 		    db_new->db_data, 1 << ZAP_EMBEDDED_PTRTBL_SHIFT(zap));
 		dmu_buf_rele(db_new, FTAG);
 
-		zap->zap_f.zap_phys->zap_ptrtbl.zt_blk = newblk;
-		zap->zap_f.zap_phys->zap_ptrtbl.zt_numblks = 1;
-		zap->zap_f.zap_phys->zap_ptrtbl.zt_shift++;
+		zap->zap_f_phys->zap_ptrtbl.zt_blk = newblk;
+		zap->zap_f_phys->zap_ptrtbl.zt_numblks = 1;
+		zap->zap_f_phys->zap_ptrtbl.zt_shift++;
 
-		ASSERT3U(1ULL << zap->zap_f.zap_phys->zap_ptrtbl.zt_shift, ==,
-		    zap->zap_f.zap_phys->zap_ptrtbl.zt_numblks <<
+		ASSERT3U(1ULL << zap->zap_f_phys->zap_ptrtbl.zt_shift, ==,
+		    zap->zap_f_phys->zap_ptrtbl.zt_numblks <<
 		    (FZAP_BLOCK_SHIFT(zap)-3));
 
 		return (0);
 	} else {
-		return (zap_table_grow(zap, &zap->zap_f.zap_phys->zap_ptrtbl,
+		return (zap_table_grow(zap, &zap->zap_f_phys->zap_ptrtbl,
 		    zap_ptrtbl_transfer, tx));
 	}
 }
@@ -372,8 +368,8 @@
 {
 	dmu_buf_will_dirty(zap->zap_dbuf, tx);
 	mutex_enter(&zap->zap_f.zap_num_entries_mtx);
-	ASSERT(delta > 0 || zap->zap_f.zap_phys->zap_num_entries >= -delta);
-	zap->zap_f.zap_phys->zap_num_entries += delta;
+	ASSERT(delta > 0 || zap->zap_f_phys->zap_num_entries >= -delta);
+	zap->zap_f_phys->zap_num_entries += delta;
 	mutex_exit(&zap->zap_f.zap_num_entries_mtx);
 }
 
@@ -382,11 +378,20 @@
 {
 	uint64_t newblk;
 	ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
-	newblk = zap->zap_f.zap_phys->zap_freeblk;
-	zap->zap_f.zap_phys->zap_freeblk += nblocks;
+	newblk = zap->zap_f_phys->zap_freeblk;
+	zap->zap_f_phys->zap_freeblk += nblocks;
 	return (newblk);
 }
 
+static void
+zap_leaf_pageout(dmu_buf_user_t *dbu)
+{
+	zap_leaf_t *l = (zap_leaf_t *)dbu;
+
+	rw_destroy(&l->l_rwlock);
+	kmem_free(l, sizeof (zap_leaf_t));
+}
+
 static zap_leaf_t *
 zap_create_leaf(zap_t *zap, dmu_tx_t *tx)
 {
@@ -399,18 +404,18 @@
 	rw_enter(&l->l_rwlock, RW_WRITER);
 	l->l_blkid = zap_allocate_blocks(zap, 1);
 	l->l_dbuf = NULL;
-	l->l_phys = NULL;
 
 	VERIFY(0 == dmu_buf_hold(zap->zap_objset, zap->zap_object,
 	    l->l_blkid << FZAP_BLOCK_SHIFT(zap), NULL, &l->l_dbuf,
 	    DMU_READ_NO_PREFETCH));
-	winner = dmu_buf_set_user(l->l_dbuf, l, &l->l_phys, zap_leaf_pageout);
+	dmu_buf_init_user(&l->db_evict, zap_leaf_pageout);
+	winner = (zap_leaf_t *)dmu_buf_set_user(l->l_dbuf, &l->db_evict);
 	ASSERT(winner == NULL);
 	dmu_buf_will_dirty(l->l_dbuf, tx);
 
 	zap_leaf_init(l, zap->zap_normflags != 0);
 
-	zap->zap_f.zap_phys->zap_num_leafs++;
+	zap->zap_f_phys->zap_num_leafs++;
 
 	return (l);
 }
@@ -420,7 +425,7 @@
 {
 	ASSERT(!zap->zap_ismicro);
 	mutex_enter(&zap->zap_f.zap_num_entries_mtx); /* unnecessary */
-	*count = zap->zap_f.zap_phys->zap_num_entries;
+	*count = zap->zap_f_phys->zap_num_entries;
 	mutex_exit(&zap->zap_f.zap_num_entries_mtx);
 	return (0);
 }
@@ -436,16 +441,6 @@
 	dmu_buf_rele(l->l_dbuf, NULL);
 }
 
-_NOTE(ARGSUSED(0))
-static void
-zap_leaf_pageout(dmu_buf_t *db, void *vl)
-{
-	zap_leaf_t *l = vl;
-
-	rw_destroy(&l->l_rwlock);
-	kmem_free(l, sizeof (zap_leaf_t));
-}
-
 static zap_leaf_t *
 zap_open_leaf(uint64_t blkid, dmu_buf_t *db)
 {
@@ -459,14 +454,14 @@
 	l->l_blkid = blkid;
 	l->l_bs = highbit(db->db_size)-1;
 	l->l_dbuf = db;
-	l->l_phys = NULL;
 
-	winner = dmu_buf_set_user(db, l, &l->l_phys, zap_leaf_pageout);
+	dmu_buf_init_user(&l->db_evict, zap_leaf_pageout);
+	winner = (zap_leaf_t *)dmu_buf_set_user(db, &l->db_evict);
 
 	rw_exit(&l->l_rwlock);
 	if (winner != NULL) {
 		/* someone else set it first */
-		zap_leaf_pageout(NULL, l);
+		zap_leaf_pageout(&l->db_evict);
 		l = winner;
 	}
 
@@ -515,7 +510,7 @@
 	ASSERT3U(db->db_size, ==, 1 << bs);
 	ASSERT(blkid != 0);
 
-	l = dmu_buf_get_user(db);
+	l = (zap_leaf_t *)dmu_buf_get_user(db);
 
 	if (l == NULL)
 		l = zap_open_leaf(blkid, db);
@@ -542,13 +537,13 @@
 {
 	ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
 
-	if (zap->zap_f.zap_phys->zap_ptrtbl.zt_numblks == 0) {
+	if (zap->zap_f_phys->zap_ptrtbl.zt_numblks == 0) {
 		ASSERT3U(idx, <,
-		    (1ULL << zap->zap_f.zap_phys->zap_ptrtbl.zt_shift));
+		    (1ULL << zap->zap_f_phys->zap_ptrtbl.zt_shift));
 		*valp = ZAP_EMBEDDED_PTRTBL_ENT(zap, idx);
 		return (0);
 	} else {
-		return (zap_table_load(zap, &zap->zap_f.zap_phys->zap_ptrtbl,
+		return (zap_table_load(zap, &zap->zap_f_phys->zap_ptrtbl,
 		    idx, valp));
 	}
 }
@@ -559,11 +554,11 @@
 	ASSERT(tx != NULL);
 	ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
 
-	if (zap->zap_f.zap_phys->zap_ptrtbl.zt_blk == 0) {
+	if (zap->zap_f_phys->zap_ptrtbl.zt_blk == 0) {
 		ZAP_EMBEDDED_PTRTBL_ENT(zap, idx) = blk;
 		return (0);
 	} else {
-		return (zap_table_store(zap, &zap->zap_f.zap_phys->zap_ptrtbl,
+		return (zap_table_store(zap, &zap->zap_f_phys->zap_ptrtbl,
 		    idx, blk, tx));
 	}
 }
@@ -575,9 +570,9 @@
 	int err;
 
 	ASSERT(zap->zap_dbuf == NULL ||
-	    zap->zap_f.zap_phys == zap->zap_dbuf->db_data);
-	ASSERT3U(zap->zap_f.zap_phys->zap_magic, ==, ZAP_MAGIC);
-	idx = ZAP_HASH_IDX(h, zap->zap_f.zap_phys->zap_ptrtbl.zt_shift);
+	    zap->zap_f_phys == zap->zap_dbuf->db_data);
+	ASSERT3U(zap->zap_f_phys->zap_magic, ==, ZAP_MAGIC);
+	idx = ZAP_HASH_IDX(h, zap->zap_f_phys->zap_ptrtbl.zt_shift);
 	err = zap_idx_to_blk(zap, idx, &blk);
 	if (err != 0)
 		return (err);
@@ -598,14 +593,14 @@
 	uint64_t sibling;
 	int old_prefix_len = l->l_phys->l_hdr.lh_prefix_len;
 
-	ASSERT3U(old_prefix_len, <=, zap->zap_f.zap_phys->zap_ptrtbl.zt_shift);
+	ASSERT3U(old_prefix_len, <=, zap->zap_f_phys->zap_ptrtbl.zt_shift);
 	ASSERT(RW_LOCK_HELD(&zap->zap_rwlock));
 
 	ASSERT3U(ZAP_HASH_IDX(hash, old_prefix_len), ==,
 	    l->l_phys->l_hdr.lh_prefix);
 
 	if (zap_tryupgradedir(zap, tx) == 0 ||
-	    old_prefix_len == zap->zap_f.zap_phys->zap_ptrtbl.zt_shift) {
+	    old_prefix_len == zap->zap_f_phys->zap_ptrtbl.zt_shift) {
 		/* We failed to upgrade, or need to grow the pointer table */
 		objset_t *os = zap->zap_objset;
 		uint64_t object = zap->zap_object;
@@ -620,7 +615,7 @@
 		ASSERT(!zap->zap_ismicro);
 
 		while (old_prefix_len ==
-		    zap->zap_f.zap_phys->zap_ptrtbl.zt_shift) {
+		    zap->zap_f_phys->zap_ptrtbl.zt_shift) {
 			err = zap_grow_ptrtbl(zap, tx);
 			if (err)
 				return (err);
@@ -637,11 +632,11 @@
 		}
 	}
 	ASSERT(RW_WRITE_HELD(&zap->zap_rwlock));
-	ASSERT3U(old_prefix_len, <, zap->zap_f.zap_phys->zap_ptrtbl.zt_shift);
+	ASSERT3U(old_prefix_len, <, zap->zap_f_phys->zap_ptrtbl.zt_shift);
 	ASSERT3U(ZAP_HASH_IDX(hash, old_prefix_len), ==,
 	    l->l_phys->l_hdr.lh_prefix);
 
-	prefix_diff = zap->zap_f.zap_phys->zap_ptrtbl.zt_shift -
+	prefix_diff = zap->zap_f_phys->zap_ptrtbl.zt_shift -
 	    (old_prefix_len + 1);
 	sibling = (ZAP_HASH_IDX(hash, old_prefix_len + 1) | 1) << prefix_diff;
 
@@ -679,13 +674,13 @@
 zap_put_leaf_maybe_grow_ptrtbl(zap_name_t *zn, zap_leaf_t *l, dmu_tx_t *tx)
 {
 	zap_t *zap = zn->zn_zap;
-	int shift = zap->zap_f.zap_phys->zap_ptrtbl.zt_shift;
+	int shift = zap->zap_f_phys->zap_ptrtbl.zt_shift;
 	int leaffull = (l->l_phys->l_hdr.lh_prefix_len == shift &&
 	    l->l_phys->l_hdr.lh_nfree < ZAP_LEAF_LOW_WATER);
 
 	zap_put_leaf(l);
 
-	if (leaffull || zap->zap_f.zap_phys->zap_ptrtbl.zt_nextblk) {
+	if (leaffull || zap->zap_f_phys->zap_ptrtbl.zt_nextblk) {
 		int err;
 
 		/*
@@ -705,7 +700,7 @@
 		}
 
 		/* could have finished growing while our locks were down */
-		if (zap->zap_f.zap_phys->zap_ptrtbl.zt_shift == shift)
+		if (zap->zap_f_phys->zap_ptrtbl.zt_shift == shift)
 			(void) zap_grow_ptrtbl(zap, tx);
 	}
 }
@@ -936,7 +931,7 @@
 	int bs;
 
 	idx = ZAP_HASH_IDX(zn->zn_hash,
-	    zap->zap_f.zap_phys->zap_ptrtbl.zt_shift);
+	    zap->zap_f_phys->zap_ptrtbl.zt_shift);
 	if (zap_idx_to_blk(zap, idx, &blk) != 0)
 		return;
 	bs = FZAP_BLOCK_SHIFT(zap);
@@ -1276,25 +1271,25 @@
 	/*
 	 * Set zap_phys_t fields
 	 */
-	zs->zs_num_leafs = zap->zap_f.zap_phys->zap_num_leafs;
-	zs->zs_num_entries = zap->zap_f.zap_phys->zap_num_entries;
-	zs->zs_num_blocks = zap->zap_f.zap_phys->zap_freeblk;
-	zs->zs_block_type = zap->zap_f.zap_phys->zap_block_type;
-	zs->zs_magic = zap->zap_f.zap_phys->zap_magic;
-	zs->zs_salt = zap->zap_f.zap_phys->zap_salt;
+	zs->zs_num_leafs = zap->zap_f_phys->zap_num_leafs;
+	zs->zs_num_entries = zap->zap_f_phys->zap_num_entries;
+	zs->zs_num_blocks = zap->zap_f_phys->zap_freeblk;
+	zs->zs_block_type = zap->zap_f_phys->zap_block_type;
+	zs->zs_magic = zap->zap_f_phys->zap_magic;
+	zs->zs_salt = zap->zap_f_phys->zap_salt;
 
 	/*
 	 * Set zap_ptrtbl fields
 	 */
-	zs->zs_ptrtbl_len = 1ULL << zap->zap_f.zap_phys->zap_ptrtbl.zt_shift;
-	zs->zs_ptrtbl_nextblk = zap->zap_f.zap_phys->zap_ptrtbl.zt_nextblk;
+	zs->zs_ptrtbl_len = 1ULL << zap->zap_f_phys->zap_ptrtbl.zt_shift;
+	zs->zs_ptrtbl_nextblk = zap->zap_f_phys->zap_ptrtbl.zt_nextblk;
 	zs->zs_ptrtbl_blks_copied =
-	    zap->zap_f.zap_phys->zap_ptrtbl.zt_blks_copied;
-	zs->zs_ptrtbl_zt_blk = zap->zap_f.zap_phys->zap_ptrtbl.zt_blk;
-	zs->zs_ptrtbl_zt_numblks = zap->zap_f.zap_phys->zap_ptrtbl.zt_numblks;
-	zs->zs_ptrtbl_zt_shift = zap->zap_f.zap_phys->zap_ptrtbl.zt_shift;
+	    zap->zap_f_phys->zap_ptrtbl.zt_blks_copied;
+	zs->zs_ptrtbl_zt_blk = zap->zap_f_phys->zap_ptrtbl.zt_blk;
+	zs->zs_ptrtbl_zt_numblks = zap->zap_f_phys->zap_ptrtbl.zt_numblks;
+	zs->zs_ptrtbl_zt_shift = zap->zap_f_phys->zap_ptrtbl.zt_shift;
 
-	if (zap->zap_f.zap_phys->zap_ptrtbl.zt_numblks == 0) {
+	if (zap->zap_f_phys->zap_ptrtbl.zt_numblks == 0) {
 		/* the ptrtbl is entirely in the header block. */
 		zap_stats_ptrtbl(zap, &ZAP_EMBEDDED_PTRTBL_ENT(zap, 0),
 		    1 << ZAP_EMBEDDED_PTRTBL_SHIFT(zap), zs);
@@ -1302,16 +1297,16 @@
 		int b;
 
 		dmu_prefetch(zap->zap_objset, zap->zap_object,
-		    zap->zap_f.zap_phys->zap_ptrtbl.zt_blk << bs,
-		    zap->zap_f.zap_phys->zap_ptrtbl.zt_numblks << bs);
+		    zap->zap_f_phys->zap_ptrtbl.zt_blk << bs,
+		    zap->zap_f_phys->zap_ptrtbl.zt_numblks << bs);
 
-		for (b = 0; b < zap->zap_f.zap_phys->zap_ptrtbl.zt_numblks;
+		for (b = 0; b < zap->zap_f_phys->zap_ptrtbl.zt_numblks;
 		    b++) {
 			dmu_buf_t *db;
 			int err;
 
 			err = dmu_buf_hold(zap->zap_objset, zap->zap_object,
-			    (zap->zap_f.zap_phys->zap_ptrtbl.zt_blk + b) << bs,
+			    (zap->zap_f_phys->zap_ptrtbl.zt_blk + b) << bs,
 			    FTAG, &db, DMU_READ_NO_PREFETCH);
 			if (err == 0) {
 				zap_stats_ptrtbl(zap, db->db_data,
@@ -1348,7 +1343,7 @@
 	 *   could extend the table.
 	 */
 	if (add) {
-		if (zap->zap_f.zap_phys->zap_ptrtbl.zt_blk == 0)
+		if (zap->zap_f_phys->zap_ptrtbl.zt_blk == 0)
 			*towrite += zap->zap_dbuf->db_size;
 		else
 			*towrite += (zap->zap_dbuf->db_size * 3);
--- old/usr/src/uts/common/fs/zfs/zap_leaf.c	2013-04-25 16:15:02.326387568 -0600
+++ new/usr/src/uts/common/fs/zfs/zap_leaf.c	2013-04-25 16:15:02.334630603 -0600
@@ -104,9 +104,9 @@
 zap_leaf_byteswap(zap_leaf_phys_t *buf, int size)
 {
 	int i;
-	zap_leaf_t l;
+	zap_leaf_t l = { 0 };
+
 	l.l_bs = highbit(size)-1;
-	l.l_phys = buf;
 
 	buf->l_hdr.lh_block_type = 	BSWAP_64(buf->l_hdr.lh_block_type);
 	buf->l_hdr.lh_prefix = 		BSWAP_64(buf->l_hdr.lh_prefix);
@@ -832,7 +832,7 @@
 {
 	int i, n;
 
-	n = zap->zap_f.zap_phys->zap_ptrtbl.zt_shift -
+	n = zap->zap_f_phys->zap_ptrtbl.zt_shift -
 	    l->l_phys->l_hdr.lh_prefix_len;
 	n = MIN(n, ZAP_HISTOGRAM_SIZE-1);
 	zs->zs_leafs_with_2n_pointers[n]++;
--- old/usr/src/uts/common/fs/zfs/zap_micro.c	2013-04-25 16:15:02.602530194 -0600
+++ new/usr/src/uts/common/fs/zfs/zap_micro.c	2013-04-25 16:15:02.611514785 -0600
@@ -45,7 +45,7 @@
 {
 	if (zap->zap_ismicro)
 		return (0);
-	return (zap->zap_u.zap_fat.zap_phys->zap_flags);
+	return (zap->zap_f_phys->zap_flags);
 }
 
 int
@@ -384,7 +384,8 @@
 	 * it, because zap_lockdir() checks zap_ismicro without the lock
 	 * held.
 	 */
-	winner = dmu_buf_set_user(db, zap, &zap->zap_m.zap_phys, zap_evict);
+	dmu_buf_init_user(&zap->db_evict, zap_evict);
+	winner = (zap_t *)dmu_buf_set_user(db, &zap->db_evict);
 
 	if (winner != NULL) {
 		rw_exit(&zap->zap_rwlock);
@@ -396,15 +397,15 @@
 	}
 
 	if (zap->zap_ismicro) {
-		zap->zap_salt = zap->zap_m.zap_phys->mz_salt;
-		zap->zap_normflags = zap->zap_m.zap_phys->mz_normflags;
+		zap->zap_salt = zap->zap_m_phys->mz_salt;
+		zap->zap_normflags = zap->zap_m_phys->mz_normflags;
 		zap->zap_m.zap_num_chunks = db->db_size / MZAP_ENT_LEN - 1;
 		avl_create(&zap->zap_m.zap_avl, mze_compare,
 		    sizeof (mzap_ent_t), offsetof(mzap_ent_t, mze_node));
 
 		for (i = 0; i < zap->zap_m.zap_num_chunks; i++) {
 			mzap_ent_phys_t *mze =
-			    &zap->zap_m.zap_phys->mz_chunk[i];
+			    &zap->zap_m_phys->mz_chunk[i];
 			if (mze->mze_name[0]) {
 				zap_name_t *zn;
 
@@ -416,8 +417,8 @@
 			}
 		}
 	} else {
-		zap->zap_salt = zap->zap_f.zap_phys->zap_salt;
-		zap->zap_normflags = zap->zap_f.zap_phys->zap_normflags;
+		zap->zap_salt = zap->zap_f_phys->zap_salt;
+		zap->zap_normflags = zap->zap_f_phys->zap_normflags;
 
 		ASSERT3U(sizeof (struct zap_leaf_header), ==,
 		    2*ZAP_LEAF_CHUNKSIZE);
@@ -427,7 +428,7 @@
 		 * other members.
 		 */
 		ASSERT3P(&ZAP_EMBEDDED_PTRTBL_ENT(zap, 0), >,
-		    &zap->zap_f.zap_phys->zap_salt);
+		    &zap->zap_f_phys->zap_salt);
 
 		/*
 		 * The embedded pointer table should end at the end of
@@ -435,7 +436,7 @@
 		 */
 		ASSERT3U((uintptr_t)&ZAP_EMBEDDED_PTRTBL_ENT(zap,
 		    1<<ZAP_EMBEDDED_PTRTBL_SHIFT(zap)) -
-		    (uintptr_t)zap->zap_f.zap_phys, ==,
+		    (uintptr_t)zap->zap_f_phys, ==,
 		    zap->zap_dbuf->db_size);
 	}
 	rw_exit(&zap->zap_rwlock);
@@ -465,7 +466,7 @@
 	}
 #endif
 
-	zap = dmu_buf_get_user(db);
+	zap = (zap_t *)dmu_buf_get_user(db);
 	if (zap == NULL)
 		zap = mzap_open(os, obj, db);
 
@@ -676,11 +677,10 @@
 	return (dmu_object_free(os, zapobj, tx));
 }
 
-_NOTE(ARGSUSED(0))
 void
-zap_evict(dmu_buf_t *db, void *vzap)
+zap_evict(dmu_buf_user_t *dbu)
 {
-	zap_t *zap = vzap;
+	zap_t *zap = (zap_t *)dbu;
 
 	rw_destroy(&zap->zap_rwlock);
 
@@ -938,7 +938,7 @@
 
 #ifdef ZFS_DEBUG
 	for (i = 0; i < zap->zap_m.zap_num_chunks; i++) {
-		mzap_ent_phys_t *mze = &zap->zap_m.zap_phys->mz_chunk[i];
+		mzap_ent_phys_t *mze = &zap->zap_m_phys->mz_chunk[i];
 		ASSERT(strcmp(zn->zn_key_orig, mze->mze_name) != 0);
 	}
 #endif
@@ -949,7 +949,7 @@
 
 again:
 	for (i = start; i < zap->zap_m.zap_num_chunks; i++) {
-		mzap_ent_phys_t *mze = &zap->zap_m.zap_phys->mz_chunk[i];
+		mzap_ent_phys_t *mze = &zap->zap_m_phys->mz_chunk[i];
 		if (mze->mze_name[0] == 0) {
 			mze->mze_value = value;
 			mze->mze_cd = cd;
@@ -1150,7 +1150,7 @@
 			err = SET_ERROR(ENOENT);
 		} else {
 			zap->zap_m.zap_num_entries--;
-			bzero(&zap->zap_m.zap_phys->mz_chunk[mze->mze_chunkid],
+			bzero(&zap->zap_m_phys->mz_chunk[mze->mze_chunkid],
 			    sizeof (mzap_ent_phys_t));
 			mze_remove(zap, mze);
 		}
--- old/usr/src/uts/common/fs/zfs/zfs_sa.c	2013-04-25 16:15:02.920482881 -0600
+++ new/usr/src/uts/common/fs/zfs/zfs_sa.c	2013-04-25 16:15:02.930257276 -0600
@@ -22,6 +22,7 @@
  * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
+#include <sys/zfs_context.h>
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/vnode.h>
--- old/usr/src/uts/common/fs/zfs/zfs_znode.c	2013-04-25 16:15:03.178520782 -0600
+++ new/usr/src/uts/common/fs/zfs/zfs_znode.c	2013-04-25 16:15:03.187793353 -0600
@@ -1130,7 +1130,7 @@
 		return (SET_ERROR(EINVAL));
 	}
 
-	hdl = dmu_buf_get_user(db);
+	hdl = (sa_handle_t *)dmu_buf_get_user(db);
 	if (hdl != NULL) {
 		zp  = sa_get_userdata(hdl);
 
