summaryrefslogtreecommitdiff
path: root/usr/src/uts/common
diff options
context:
space:
mode:
authorGeorge Wilson <George.Wilson@Sun.COM>2010-06-08 13:36:53 -0700
committerGeorge Wilson <George.Wilson@Sun.COM>2010-06-08 13:36:53 -0700
commit837b568b3a2559f8c9b9403f95104271a85d129e (patch)
treeb177cd759870ba9b56f725e788af0e4a286daa8b /usr/src/uts/common
parent44ecc5327ab4ce0750dcca2a17e05566bf2812e2 (diff)
downloadillumos-joyent-837b568b3a2559f8c9b9403f95104271a85d129e.tar.gz
6957090 ddt_zap_prefetch() induces deadlock, panic
6958874 bpobj_close() tries to dereference a NULL bpo_dbuf
Diffstat (limited to 'usr/src/uts/common')
-rw-r--r--usr/src/uts/common/fs/zfs/bpobj.c10
-rw-r--r--usr/src/uts/common/fs/zfs/dbuf.c10
-rw-r--r--usr/src/uts/common/fs/zfs/ddt.c7
-rw-r--r--usr/src/uts/common/fs/zfs/dsl_dataset.c8
4 files changed, 20 insertions, 15 deletions
diff --git a/usr/src/uts/common/fs/zfs/bpobj.c b/usr/src/uts/common/fs/zfs/bpobj.c
index d69a1a7f47..a50d7cfe43 100644
--- a/usr/src/uts/common/fs/zfs/bpobj.c
+++ b/usr/src/uts/common/fs/zfs/bpobj.c
@@ -113,16 +113,15 @@ bpobj_open(bpobj_t *bpo, objset_t *os, uint64_t object)
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 @@ bpobj_close(bpobj_t *bpo)
bpo->bpo_dbuf = NULL;
bpo->bpo_phys = NULL;
bpo->bpo_cached_dbuf = NULL;
+ bpo->bpo_object = 0;
mutex_destroy(&bpo->bpo_lock);
}
diff --git a/usr/src/uts/common/fs/zfs/dbuf.c b/usr/src/uts/common/fs/zfs/dbuf.c
index 42ae439972..f3388e1360 100644
--- a/usr/src/uts/common/fs/zfs/dbuf.c
+++ b/usr/src/uts/common/fs/zfs/dbuf.c
@@ -865,10 +865,15 @@ dbuf_block_freeable(dmu_buf_impl_t *db)
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 @@ dbuf_dirty(dmu_buf_impl_t *db, dmu_tx_t *tx)
* 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);
}
diff --git a/usr/src/uts/common/fs/zfs/ddt.c b/usr/src/uts/common/fs/zfs/ddt.c
index 926b4df9a5..89e360d0ef 100644
--- a/usr/src/uts/common/fs/zfs/ddt.c
+++ b/usr/src/uts/common/fs/zfs/ddt.c
@@ -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_prefetch(spa_t *spa, const blkptr_t *bp)
ddt_t *ddt;
ddt_entry_t dde;
- if (!BP_GET_DEDUP(bp))
+ if (!zfs_dedup_prefetch || bp == NULL || !BP_GET_DEDUP(bp))
return;
/*
diff --git a/usr/src/uts/common/fs/zfs/dsl_dataset.c b/usr/src/uts/common/fs/zfs/dsl_dataset.c
index fef0f5385d..f1a5776935 100644
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c
@@ -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 @@ dsl_dataset_block_freeable(dsl_dataset_t *ds, const blkptr_t *bp,
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);
}