6957090 ddt_zap_prefetch() induces deadlock, panic
authorGeorge Wilson <George.Wilson@Sun.COM>
Tue, 08 Jun 2010 13:36:53 -0700
changeset 12587 16aef3d16470
parent 12586 b118bbd65be9
child 12588 1cb8fb936e1f
6957090 ddt_zap_prefetch() induces deadlock, panic 6958874 bpobj_close() tries to dereference a NULL bpo_dbuf
usr/src/uts/common/fs/zfs/bpobj.c
usr/src/uts/common/fs/zfs/dbuf.c
usr/src/uts/common/fs/zfs/ddt.c
usr/src/uts/common/fs/zfs/dsl_dataset.c
--- a/usr/src/uts/common/fs/zfs/bpobj.c	Tue Jun 08 12:32:02 2010 -0700
+++ b/usr/src/uts/common/fs/zfs/bpobj.c	Tue Jun 08 13:36:53 2010 -0700
@@ -113,16 +113,15 @@
 	ASSERT3U(doi.doi_type, ==, DMU_OT_BPOBJ);
 	ASSERT3U(doi.doi_bonus_type, ==, DMU_OT_BPOBJ_HDR);
 
+	err = dmu_bonus_hold(os, object, bpo, &bpo->bpo_dbuf);
+	if (err)
+		return (err);
+
 	bpo->bpo_os = os;
 	bpo->bpo_object = object;
 	bpo->bpo_epb = doi.doi_data_block_size >> SPA_BLKPTRSHIFT;
 	bpo->bpo_havecomp = (doi.doi_bonus_size > BPOBJ_SIZE_V0);
 	bpo->bpo_havesubobj = (doi.doi_bonus_size > BPOBJ_SIZE_V1);
-
-	err = dmu_bonus_hold(bpo->bpo_os,
-	    bpo->bpo_object, bpo, &bpo->bpo_dbuf);
-	if (err)
-		return (err);
 	bpo->bpo_phys = bpo->bpo_dbuf->db_data;
 	return (0);
 }
@@ -140,6 +139,7 @@
 	bpo->bpo_dbuf = NULL;
 	bpo->bpo_phys = NULL;
 	bpo->bpo_cached_dbuf = NULL;
+	bpo->bpo_object = 0;
 
 	mutex_destroy(&bpo->bpo_lock);
 }
--- a/usr/src/uts/common/fs/zfs/dbuf.c	Tue Jun 08 12:32:02 2010 -0700
+++ b/usr/src/uts/common/fs/zfs/dbuf.c	Tue Jun 08 13:36:53 2010 -0700
@@ -865,10 +865,15 @@
 	else if (db->db_blkptr)
 		birth_txg = db->db_blkptr->blk_birth;
 
-	/* If we don't exist or are in a snapshot, we can't be freed */
+	/*
+	 * If we don't exist or are in a snapshot, we can't be freed.
+	 * Don't pass the bp to dsl_dataset_block_freeable() since we
+	 * are holding the db_mtx lock and might deadlock if we are
+	 * prefetching a dedup-ed block.
+	 */
 	if (birth_txg)
 		return (ds == NULL ||
-		    dsl_dataset_block_freeable(ds, db->db_blkptr, birth_txg));
+		    dsl_dataset_block_freeable(ds, NULL, birth_txg));
 	else
 		return (FALSE);
 }
@@ -1145,6 +1150,7 @@
 		 * db_blkptr, but since this is just a guess,
 		 * it's OK if we get an odd answer.
 		 */
+		ddt_prefetch(os->os_spa, bp);
 		dnode_willuse_space(dn, -willfree, tx);
 	}
 
--- a/usr/src/uts/common/fs/zfs/ddt.c	Tue Jun 08 12:32:02 2010 -0700
+++ b/usr/src/uts/common/fs/zfs/ddt.c	Tue Jun 08 13:36:53 2010 -0700
@@ -36,6 +36,11 @@
 #include <sys/zio_compress.h>
 #include <sys/dsl_scan.h>
 
+/*
+ * Enable/disable prefetching of dedup-ed blocks which are going to be freed.
+ */
+int zfs_dedup_prefetch = 1;
+
 static const ddt_ops_t *ddt_ops[DDT_TYPES] = {
 	&ddt_zap_ops,
 };
@@ -730,7 +735,7 @@
 	ddt_t *ddt;
 	ddt_entry_t dde;
 
-	if (!BP_GET_DEDUP(bp))
+	if (!zfs_dedup_prefetch || bp == NULL || !BP_GET_DEDUP(bp))
 		return;
 
 	/*
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c	Tue Jun 08 12:32:02 2010 -0700
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c	Tue Jun 08 13:36:53 2010 -0700
@@ -42,11 +42,6 @@
 #include <sys/dsl_scan.h>
 #include <sys/dsl_deadlist.h>
 
-/*
- * Enable/disable prefetching of dedup-ed blocks which are going to be freed.
- */
-int zfs_dedup_prefetch = 1;
-
 static char *dsl_reaper = "the grim reaper";
 
 static dsl_checkfunc_t dsl_dataset_destroy_begin_check;
@@ -254,8 +249,7 @@
 	if (blk_birth <= dsl_dataset_prev_snap_txg(ds))
 		return (B_FALSE);
 
-	if (zfs_dedup_prefetch && bp && BP_GET_DEDUP(bp))
-		ddt_prefetch(dsl_dataset_get_spa(ds), bp);
+	ddt_prefetch(dsl_dataset_get_spa(ds), bp);
 
 	return (B_TRUE);
 }