aboutsummaryrefslogtreecommitdiffstats
path: root/module/zfs/dbuf.c
diff options
context:
space:
mode:
Diffstat (limited to 'module/zfs/dbuf.c')
-rw-r--r--module/zfs/dbuf.c30
1 files changed, 30 insertions, 0 deletions
diff --git a/module/zfs/dbuf.c b/module/zfs/dbuf.c
index 4d347b6f4..0518205f9 100644
--- a/module/zfs/dbuf.c
+++ b/module/zfs/dbuf.c
@@ -3286,6 +3286,13 @@ dbuf_hold_impl_arg(struct dbuf_hold_arg *dh)
*(dh->dh_dbp) = NULL;
+ /* If the pool has been created, verify the tx_sync_lock is not held */
+ spa_t *spa = dh->dh_dn->dn_objset->os_spa;
+ dsl_pool_t *dp = spa->spa_dsl_pool;
+ if (dp != NULL) {
+ ASSERT(!MUTEX_HELD(&dp->dp_tx.tx_sync_lock));
+ }
+
/* dbuf_find() returns with db_mtx held */
dh->dh_db = dbuf_find(dh->dh_dn->dn_objset, dh->dh_dn->dn_object,
dh->dh_level, dh->dh_blkid);
@@ -4480,6 +4487,29 @@ dbuf_remap_impl(dnode_t *dn, blkptr_t *bp, krwlock_t *rw, dmu_tx_t *tx)
if (spa_remap_blkptr(spa, &bp_copy, dbuf_remap_impl_callback,
&drica)) {
/*
+ * If the blkptr being remapped is tracked by a livelist,
+ * then we need to make sure the livelist reflects the update.
+ * First, cancel out the old blkptr by appending a 'FREE'
+ * entry. Next, add an 'ALLOC' to track the new version. This
+ * way we avoid trying to free an inaccurate blkptr at delete.
+ * Note that embedded blkptrs are not tracked in livelists.
+ */
+ if (dn->dn_objset != spa_meta_objset(spa)) {
+ dsl_dataset_t *ds = dmu_objset_ds(dn->dn_objset);
+ if (dsl_deadlist_is_open(&ds->ds_dir->dd_livelist) &&
+ bp->blk_birth > ds->ds_dir->dd_origin_txg) {
+ ASSERT(!BP_IS_EMBEDDED(bp));
+ ASSERT(dsl_dir_is_clone(ds->ds_dir));
+ ASSERT(spa_feature_is_enabled(spa,
+ SPA_FEATURE_LIVELIST));
+ bplist_append(&ds->ds_dir->dd_pending_frees,
+ bp);
+ bplist_append(&ds->ds_dir->dd_pending_allocs,
+ &bp_copy);
+ }
+ }
+
+ /*
* The db_rwlock prevents dbuf_read_impl() from
* dereferencing the BP while we are changing it. To
* avoid lock contention, only grab it when we are actually