mirror of
https://git.proxmox.com/git/mirror_zfs.git
synced 2026-05-26 04:07:45 +03:00
Fast Clone Deletion
Deleting a clone requires finding blocks are clone-only, not shared with the snapshot. This was done by traversing the entire block tree which results in a large performance penalty for sparsely written clones. This is new method keeps track of clone blocks when they are modified in a "Livelist" so that, when it’s time to delete, the clone-specific blocks are already at hand. We see performance improvements because now deletion work is proportional to the number of clone-modified blocks, not the size of the original dataset. Reviewed-by: Sean Eric Fagan <sef@ixsystems.com> Reviewed-by: Matt Ahrens <matt@delphix.com> Reviewed-by: Brian Behlendorf <behlendorf1@llnl.gov> Reviewed-by: Serapheim Dimitropoulos <serapheim@delphix.com> Signed-off-by: Sara Hartse <sara.hartse@delphix.com> Closes #8416
This commit is contained in:
committed by
Brian Behlendorf
parent
d274ac5460
commit
37f03da8ba
@@ -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);
|
||||
@@ -4479,6 +4486,29 @@ dbuf_remap_impl(dnode_t *dn, blkptr_t *bp, krwlock_t *rw, dmu_tx_t *tx)
|
||||
drica.drica_tx = 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
|
||||
|
||||
Reference in New Issue
Block a user