1eda14cbcSMatt Macy /* 2eda14cbcSMatt Macy * CDDL HEADER START 3eda14cbcSMatt Macy * 4eda14cbcSMatt Macy * The contents of this file are subject to the terms of the 5eda14cbcSMatt Macy * Common Development and Distribution License (the "License"). 6eda14cbcSMatt Macy * You may not use this file except in compliance with the License. 7eda14cbcSMatt Macy * 8eda14cbcSMatt Macy * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9271171e0SMartin Matuska * or https://opensource.org/licenses/CDDL-1.0. 10eda14cbcSMatt Macy * See the License for the specific language governing permissions 11eda14cbcSMatt Macy * and limitations under the License. 12eda14cbcSMatt Macy * 13eda14cbcSMatt Macy * When distributing Covered Code, include this CDDL HEADER in each 14eda14cbcSMatt Macy * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15eda14cbcSMatt Macy * If applicable, add the following below this CDDL HEADER, with the 16eda14cbcSMatt Macy * fields enclosed by brackets "[]" replaced with your own identifying 17eda14cbcSMatt Macy * information: Portions Copyright [yyyy] [name of copyright owner] 18eda14cbcSMatt Macy * 19eda14cbcSMatt Macy * CDDL HEADER END 20eda14cbcSMatt Macy */ 21eda14cbcSMatt Macy /* 22eda14cbcSMatt Macy * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23eda14cbcSMatt Macy * Copyright (c) 2012, 2018 by Delphix. All rights reserved. 24eda14cbcSMatt Macy * Copyright (c) 2013 Steven Hartland. All rights reserved. 25eda14cbcSMatt Macy * Copyright (c) 2013 by Joyent, Inc. All rights reserved. 26eda14cbcSMatt Macy * Copyright (c) 2016 Actifio, Inc. All rights reserved. 27eda14cbcSMatt Macy */ 28eda14cbcSMatt Macy 29eda14cbcSMatt Macy #include <sys/zfs_context.h> 30eda14cbcSMatt Macy #include <sys/dsl_userhold.h> 31eda14cbcSMatt Macy #include <sys/dsl_dataset.h> 32eda14cbcSMatt Macy #include <sys/dsl_synctask.h> 33eda14cbcSMatt Macy #include <sys/dsl_destroy.h> 34eda14cbcSMatt Macy #include <sys/dsl_bookmark.h> 35eda14cbcSMatt Macy #include <sys/dmu_tx.h> 36eda14cbcSMatt Macy #include <sys/dsl_pool.h> 37eda14cbcSMatt Macy #include <sys/dsl_dir.h> 38eda14cbcSMatt Macy #include <sys/dmu_traverse.h> 39eda14cbcSMatt Macy #include <sys/dsl_scan.h> 40eda14cbcSMatt Macy #include <sys/dmu_objset.h> 41eda14cbcSMatt Macy #include <sys/zap.h> 42eda14cbcSMatt Macy #include <sys/zfeature.h> 43eda14cbcSMatt Macy #include <sys/zfs_ioctl.h> 44eda14cbcSMatt Macy #include <sys/dsl_deleg.h> 45eda14cbcSMatt Macy #include <sys/dmu_impl.h> 46eda14cbcSMatt Macy #include <sys/zvol.h> 47eda14cbcSMatt Macy #include <sys/zcp.h> 48eda14cbcSMatt Macy #include <sys/dsl_deadlist.h> 49eda14cbcSMatt Macy #include <sys/zthr.h> 50eda14cbcSMatt Macy #include <sys/spa_impl.h> 51eda14cbcSMatt Macy 5208aba0aeSMartin Matuska extern int zfs_snapshot_history_enabled; 5308aba0aeSMartin Matuska 54eda14cbcSMatt Macy int 55eda14cbcSMatt Macy dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer) 56eda14cbcSMatt Macy { 57eda14cbcSMatt Macy if (!ds->ds_is_snapshot) 58eda14cbcSMatt Macy return (SET_ERROR(EINVAL)); 59eda14cbcSMatt Macy 60eda14cbcSMatt Macy if (dsl_dataset_long_held(ds)) 61eda14cbcSMatt Macy return (SET_ERROR(EBUSY)); 62eda14cbcSMatt Macy 63eda14cbcSMatt Macy /* 64eda14cbcSMatt Macy * Only allow deferred destroy on pools that support it. 65eda14cbcSMatt Macy * NOTE: deferred destroy is only supported on snapshots. 66eda14cbcSMatt Macy */ 67eda14cbcSMatt Macy if (defer) { 68eda14cbcSMatt Macy if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 69eda14cbcSMatt Macy SPA_VERSION_USERREFS) 70eda14cbcSMatt Macy return (SET_ERROR(ENOTSUP)); 71eda14cbcSMatt Macy return (0); 72eda14cbcSMatt Macy } 73eda14cbcSMatt Macy 74eda14cbcSMatt Macy /* 75eda14cbcSMatt Macy * If this snapshot has an elevated user reference count, 76eda14cbcSMatt Macy * we can't destroy it yet. 77eda14cbcSMatt Macy */ 78eda14cbcSMatt Macy if (ds->ds_userrefs > 0) 79eda14cbcSMatt Macy return (SET_ERROR(EBUSY)); 80eda14cbcSMatt Macy 81eda14cbcSMatt Macy /* 82eda14cbcSMatt Macy * Can't delete a branch point. 83eda14cbcSMatt Macy */ 84eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_num_children > 1) 85eda14cbcSMatt Macy return (SET_ERROR(EEXIST)); 86eda14cbcSMatt Macy 87eda14cbcSMatt Macy return (0); 88eda14cbcSMatt Macy } 89eda14cbcSMatt Macy 90eda14cbcSMatt Macy int 91eda14cbcSMatt Macy dsl_destroy_snapshot_check(void *arg, dmu_tx_t *tx) 92eda14cbcSMatt Macy { 93eda14cbcSMatt Macy dsl_destroy_snapshot_arg_t *ddsa = arg; 94eda14cbcSMatt Macy const char *dsname = ddsa->ddsa_name; 95eda14cbcSMatt Macy boolean_t defer = ddsa->ddsa_defer; 96eda14cbcSMatt Macy 97eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 98eda14cbcSMatt Macy int error = 0; 99eda14cbcSMatt Macy dsl_dataset_t *ds; 100eda14cbcSMatt Macy 101eda14cbcSMatt Macy error = dsl_dataset_hold(dp, dsname, FTAG, &ds); 102eda14cbcSMatt Macy 103eda14cbcSMatt Macy /* 104eda14cbcSMatt Macy * If the snapshot does not exist, silently ignore it, and 105eda14cbcSMatt Macy * dsl_destroy_snapshot_sync() will be a no-op 106eda14cbcSMatt Macy * (it's "already destroyed"). 107eda14cbcSMatt Macy */ 108eda14cbcSMatt Macy if (error == ENOENT) 109eda14cbcSMatt Macy return (0); 110eda14cbcSMatt Macy 111eda14cbcSMatt Macy if (error == 0) { 112eda14cbcSMatt Macy error = dsl_destroy_snapshot_check_impl(ds, defer); 113eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 114eda14cbcSMatt Macy } 115eda14cbcSMatt Macy 116eda14cbcSMatt Macy return (error); 117eda14cbcSMatt Macy } 118eda14cbcSMatt Macy 119eda14cbcSMatt Macy struct process_old_arg { 120eda14cbcSMatt Macy dsl_dataset_t *ds; 121eda14cbcSMatt Macy dsl_dataset_t *ds_prev; 122eda14cbcSMatt Macy boolean_t after_branch_point; 123eda14cbcSMatt Macy zio_t *pio; 124eda14cbcSMatt Macy uint64_t used, comp, uncomp; 125eda14cbcSMatt Macy }; 126eda14cbcSMatt Macy 127eda14cbcSMatt Macy static int 128eda14cbcSMatt Macy process_old_cb(void *arg, const blkptr_t *bp, boolean_t bp_freed, dmu_tx_t *tx) 129eda14cbcSMatt Macy { 130eda14cbcSMatt Macy struct process_old_arg *poa = arg; 131eda14cbcSMatt Macy dsl_pool_t *dp = poa->ds->ds_dir->dd_pool; 132eda14cbcSMatt Macy 133eda14cbcSMatt Macy ASSERT(!BP_IS_HOLE(bp)); 134eda14cbcSMatt Macy 135783d3ff6SMartin Matuska if (BP_GET_LOGICAL_BIRTH(bp) <= 136783d3ff6SMartin Matuska dsl_dataset_phys(poa->ds)->ds_prev_snap_txg) { 137eda14cbcSMatt Macy dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, bp_freed, tx); 138eda14cbcSMatt Macy if (poa->ds_prev && !poa->after_branch_point && 139783d3ff6SMartin Matuska BP_GET_LOGICAL_BIRTH(bp) > 140eda14cbcSMatt Macy dsl_dataset_phys(poa->ds_prev)->ds_prev_snap_txg) { 141eda14cbcSMatt Macy dsl_dataset_phys(poa->ds_prev)->ds_unique_bytes += 142eda14cbcSMatt Macy bp_get_dsize_sync(dp->dp_spa, bp); 143eda14cbcSMatt Macy } 144eda14cbcSMatt Macy } else { 145eda14cbcSMatt Macy poa->used += bp_get_dsize_sync(dp->dp_spa, bp); 146eda14cbcSMatt Macy poa->comp += BP_GET_PSIZE(bp); 147eda14cbcSMatt Macy poa->uncomp += BP_GET_UCSIZE(bp); 148eda14cbcSMatt Macy dsl_free_sync(poa->pio, dp, tx->tx_txg, bp); 149eda14cbcSMatt Macy } 150eda14cbcSMatt Macy return (0); 151eda14cbcSMatt Macy } 152eda14cbcSMatt Macy 153eda14cbcSMatt Macy static void 154eda14cbcSMatt Macy process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev, 155eda14cbcSMatt Macy dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx) 156eda14cbcSMatt Macy { 157eda14cbcSMatt Macy struct process_old_arg poa = { 0 }; 158eda14cbcSMatt Macy dsl_pool_t *dp = ds->ds_dir->dd_pool; 159eda14cbcSMatt Macy objset_t *mos = dp->dp_meta_objset; 160eda14cbcSMatt Macy uint64_t deadlist_obj; 161eda14cbcSMatt Macy 162eda14cbcSMatt Macy ASSERT(ds->ds_deadlist.dl_oldfmt); 163eda14cbcSMatt Macy ASSERT(ds_next->ds_deadlist.dl_oldfmt); 164eda14cbcSMatt Macy 165eda14cbcSMatt Macy poa.ds = ds; 166eda14cbcSMatt Macy poa.ds_prev = ds_prev; 167eda14cbcSMatt Macy poa.after_branch_point = after_branch_point; 168eda14cbcSMatt Macy poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 169eda14cbcSMatt Macy VERIFY0(bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj, 170eda14cbcSMatt Macy process_old_cb, &poa, tx)); 171eda14cbcSMatt Macy VERIFY0(zio_wait(poa.pio)); 172eda14cbcSMatt Macy ASSERT3U(poa.used, ==, dsl_dataset_phys(ds)->ds_unique_bytes); 173eda14cbcSMatt Macy 174eda14cbcSMatt Macy /* change snapused */ 175eda14cbcSMatt Macy dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 176eda14cbcSMatt Macy -poa.used, -poa.comp, -poa.uncomp, tx); 177eda14cbcSMatt Macy 178eda14cbcSMatt Macy /* swap next's deadlist to our deadlist */ 179eda14cbcSMatt Macy dsl_deadlist_close(&ds->ds_deadlist); 180eda14cbcSMatt Macy dsl_deadlist_close(&ds_next->ds_deadlist); 181eda14cbcSMatt Macy deadlist_obj = dsl_dataset_phys(ds)->ds_deadlist_obj; 182eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_deadlist_obj = 183eda14cbcSMatt Macy dsl_dataset_phys(ds_next)->ds_deadlist_obj; 184eda14cbcSMatt Macy dsl_dataset_phys(ds_next)->ds_deadlist_obj = deadlist_obj; 185*17aab35aSMartin Matuska VERIFY0(dsl_deadlist_open(&ds->ds_deadlist, mos, 186*17aab35aSMartin Matuska dsl_dataset_phys(ds)->ds_deadlist_obj)); 187*17aab35aSMartin Matuska VERIFY0(dsl_deadlist_open(&ds_next->ds_deadlist, mos, 188*17aab35aSMartin Matuska dsl_dataset_phys(ds_next)->ds_deadlist_obj)); 189eda14cbcSMatt Macy } 190eda14cbcSMatt Macy 191eda14cbcSMatt Macy typedef struct remaining_clones_key { 192eda14cbcSMatt Macy dsl_dataset_t *rck_clone; 193eda14cbcSMatt Macy list_node_t rck_node; 194eda14cbcSMatt Macy } remaining_clones_key_t; 195eda14cbcSMatt Macy 196eda14cbcSMatt Macy static remaining_clones_key_t * 197eda14cbcSMatt Macy rck_alloc(dsl_dataset_t *clone) 198eda14cbcSMatt Macy { 199eda14cbcSMatt Macy remaining_clones_key_t *rck = kmem_alloc(sizeof (*rck), KM_SLEEP); 200eda14cbcSMatt Macy rck->rck_clone = clone; 201eda14cbcSMatt Macy return (rck); 202eda14cbcSMatt Macy } 203eda14cbcSMatt Macy 204eda14cbcSMatt Macy static void 205eda14cbcSMatt Macy dsl_dir_remove_clones_key_impl(dsl_dir_t *dd, uint64_t mintxg, dmu_tx_t *tx, 206a0b956f5SMartin Matuska list_t *stack, const void *tag) 207eda14cbcSMatt Macy { 208eda14cbcSMatt Macy objset_t *mos = dd->dd_pool->dp_meta_objset; 209eda14cbcSMatt Macy 210eda14cbcSMatt Macy /* 211eda14cbcSMatt Macy * If it is the old version, dd_clones doesn't exist so we can't 212eda14cbcSMatt Macy * find the clones, but dsl_deadlist_remove_key() is a no-op so it 213eda14cbcSMatt Macy * doesn't matter. 214eda14cbcSMatt Macy */ 215eda14cbcSMatt Macy if (dsl_dir_phys(dd)->dd_clones == 0) 216eda14cbcSMatt Macy return; 217eda14cbcSMatt Macy 218eda14cbcSMatt Macy zap_cursor_t *zc = kmem_alloc(sizeof (zap_cursor_t), KM_SLEEP); 2197a7741afSMartin Matuska zap_attribute_t *za = zap_attribute_alloc(); 220eda14cbcSMatt Macy 221eda14cbcSMatt Macy for (zap_cursor_init(zc, mos, dsl_dir_phys(dd)->dd_clones); 222eda14cbcSMatt Macy zap_cursor_retrieve(zc, za) == 0; 223eda14cbcSMatt Macy zap_cursor_advance(zc)) { 224eda14cbcSMatt Macy dsl_dataset_t *clone; 225eda14cbcSMatt Macy 226eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold_obj(dd->dd_pool, 227eda14cbcSMatt Macy za->za_first_integer, tag, &clone)); 228eda14cbcSMatt Macy 229eda14cbcSMatt Macy if (clone->ds_dir->dd_origin_txg > mintxg) { 230eda14cbcSMatt Macy dsl_deadlist_remove_key(&clone->ds_deadlist, 231eda14cbcSMatt Macy mintxg, tx); 232eda14cbcSMatt Macy 233eda14cbcSMatt Macy if (dsl_dataset_remap_deadlist_exists(clone)) { 234eda14cbcSMatt Macy dsl_deadlist_remove_key( 235eda14cbcSMatt Macy &clone->ds_remap_deadlist, mintxg, tx); 236eda14cbcSMatt Macy } 237eda14cbcSMatt Macy 238eda14cbcSMatt Macy list_insert_head(stack, rck_alloc(clone)); 239eda14cbcSMatt Macy } else { 240eda14cbcSMatt Macy dsl_dataset_rele(clone, tag); 241eda14cbcSMatt Macy } 242eda14cbcSMatt Macy } 243eda14cbcSMatt Macy zap_cursor_fini(zc); 244eda14cbcSMatt Macy 2457a7741afSMartin Matuska zap_attribute_free(za); 246eda14cbcSMatt Macy kmem_free(zc, sizeof (zap_cursor_t)); 247eda14cbcSMatt Macy } 248eda14cbcSMatt Macy 249eda14cbcSMatt Macy void 250eda14cbcSMatt Macy dsl_dir_remove_clones_key(dsl_dir_t *top_dd, uint64_t mintxg, dmu_tx_t *tx) 251eda14cbcSMatt Macy { 252eda14cbcSMatt Macy list_t stack; 253eda14cbcSMatt Macy 254eda14cbcSMatt Macy list_create(&stack, sizeof (remaining_clones_key_t), 255eda14cbcSMatt Macy offsetof(remaining_clones_key_t, rck_node)); 256eda14cbcSMatt Macy 257eda14cbcSMatt Macy dsl_dir_remove_clones_key_impl(top_dd, mintxg, tx, &stack, FTAG); 258eda14cbcSMatt Macy for (remaining_clones_key_t *rck = list_remove_head(&stack); 259eda14cbcSMatt Macy rck != NULL; rck = list_remove_head(&stack)) { 260eda14cbcSMatt Macy dsl_dataset_t *clone = rck->rck_clone; 261eda14cbcSMatt Macy dsl_dir_t *clone_dir = clone->ds_dir; 262eda14cbcSMatt Macy 263eda14cbcSMatt Macy kmem_free(rck, sizeof (*rck)); 264eda14cbcSMatt Macy 265eda14cbcSMatt Macy dsl_dir_remove_clones_key_impl(clone_dir, mintxg, tx, 266eda14cbcSMatt Macy &stack, FTAG); 267eda14cbcSMatt Macy dsl_dataset_rele(clone, FTAG); 268eda14cbcSMatt Macy } 269eda14cbcSMatt Macy 270eda14cbcSMatt Macy list_destroy(&stack); 271eda14cbcSMatt Macy } 272eda14cbcSMatt Macy 273eda14cbcSMatt Macy static void 274eda14cbcSMatt Macy dsl_destroy_snapshot_handle_remaps(dsl_dataset_t *ds, dsl_dataset_t *ds_next, 275eda14cbcSMatt Macy dmu_tx_t *tx) 276eda14cbcSMatt Macy { 277eda14cbcSMatt Macy dsl_pool_t *dp = ds->ds_dir->dd_pool; 278eda14cbcSMatt Macy 279eda14cbcSMatt Macy /* Move blocks to be obsoleted to pool's obsolete list. */ 280eda14cbcSMatt Macy if (dsl_dataset_remap_deadlist_exists(ds_next)) { 281eda14cbcSMatt Macy if (!bpobj_is_open(&dp->dp_obsolete_bpobj)) 282eda14cbcSMatt Macy dsl_pool_create_obsolete_bpobj(dp, tx); 283eda14cbcSMatt Macy 284eda14cbcSMatt Macy dsl_deadlist_move_bpobj(&ds_next->ds_remap_deadlist, 285eda14cbcSMatt Macy &dp->dp_obsolete_bpobj, 286eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_txg, tx); 287eda14cbcSMatt Macy } 288eda14cbcSMatt Macy 289eda14cbcSMatt Macy /* Merge our deadlist into next's and free it. */ 290eda14cbcSMatt Macy if (dsl_dataset_remap_deadlist_exists(ds)) { 291eda14cbcSMatt Macy uint64_t remap_deadlist_object = 292eda14cbcSMatt Macy dsl_dataset_get_remap_deadlist_object(ds); 293eda14cbcSMatt Macy ASSERT(remap_deadlist_object != 0); 294eda14cbcSMatt Macy 295eda14cbcSMatt Macy mutex_enter(&ds_next->ds_remap_deadlist_lock); 296eda14cbcSMatt Macy if (!dsl_dataset_remap_deadlist_exists(ds_next)) 297eda14cbcSMatt Macy dsl_dataset_create_remap_deadlist(ds_next, tx); 298eda14cbcSMatt Macy mutex_exit(&ds_next->ds_remap_deadlist_lock); 299eda14cbcSMatt Macy 300eda14cbcSMatt Macy dsl_deadlist_merge(&ds_next->ds_remap_deadlist, 301eda14cbcSMatt Macy remap_deadlist_object, tx); 302eda14cbcSMatt Macy dsl_dataset_destroy_remap_deadlist(ds, tx); 303eda14cbcSMatt Macy } 304eda14cbcSMatt Macy } 305eda14cbcSMatt Macy 306eda14cbcSMatt Macy void 307eda14cbcSMatt Macy dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx) 308eda14cbcSMatt Macy { 309eda14cbcSMatt Macy int after_branch_point = FALSE; 310eda14cbcSMatt Macy dsl_pool_t *dp = ds->ds_dir->dd_pool; 311eda14cbcSMatt Macy objset_t *mos = dp->dp_meta_objset; 312eda14cbcSMatt Macy dsl_dataset_t *ds_prev = NULL; 313eda14cbcSMatt Macy uint64_t obj; 314eda14cbcSMatt Macy 315eda14cbcSMatt Macy ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); 316eda14cbcSMatt Macy rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); 317783d3ff6SMartin Matuska ASSERT3U(BP_GET_LOGICAL_BIRTH(&dsl_dataset_phys(ds)->ds_bp), <=, 318783d3ff6SMartin Matuska tx->tx_txg); 319eda14cbcSMatt Macy rrw_exit(&ds->ds_bp_rwlock, FTAG); 320eda14cbcSMatt Macy ASSERT(zfs_refcount_is_zero(&ds->ds_longholds)); 321eda14cbcSMatt Macy 322eda14cbcSMatt Macy if (defer && 323eda14cbcSMatt Macy (ds->ds_userrefs > 0 || 324eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_num_children > 1)) { 325eda14cbcSMatt Macy ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 326eda14cbcSMatt Macy dmu_buf_will_dirty(ds->ds_dbuf, tx); 327eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_DEFER_DESTROY; 32808aba0aeSMartin Matuska if (zfs_snapshot_history_enabled) { 32908aba0aeSMartin Matuska spa_history_log_internal_ds(ds, "defer_destroy", tx, 33008aba0aeSMartin Matuska " "); 33108aba0aeSMartin Matuska } 332eda14cbcSMatt Macy return; 333eda14cbcSMatt Macy } 334eda14cbcSMatt Macy 335eda14cbcSMatt Macy ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1); 336eda14cbcSMatt Macy 33708aba0aeSMartin Matuska if (zfs_snapshot_history_enabled) { 338eda14cbcSMatt Macy /* We need to log before removing it from the namespace. */ 339eda14cbcSMatt Macy spa_history_log_internal_ds(ds, "destroy", tx, " "); 34008aba0aeSMartin Matuska } 341eda14cbcSMatt Macy 342eda14cbcSMatt Macy dsl_scan_ds_destroyed(ds, tx); 343eda14cbcSMatt Macy 344eda14cbcSMatt Macy obj = ds->ds_object; 345eda14cbcSMatt Macy 346eda14cbcSMatt Macy boolean_t book_exists = dsl_bookmark_ds_destroyed(ds, tx); 347eda14cbcSMatt Macy 348eda14cbcSMatt Macy for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { 349eda14cbcSMatt Macy if (dsl_dataset_feature_is_active(ds, f)) 350eda14cbcSMatt Macy dsl_dataset_deactivate_feature(ds, f, tx); 351eda14cbcSMatt Macy } 352eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { 353eda14cbcSMatt Macy ASSERT3P(ds->ds_prev, ==, NULL); 354eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold_obj(dp, 355eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &ds_prev)); 356eda14cbcSMatt Macy after_branch_point = 357eda14cbcSMatt Macy (dsl_dataset_phys(ds_prev)->ds_next_snap_obj != obj); 358eda14cbcSMatt Macy 359eda14cbcSMatt Macy dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 360eda14cbcSMatt Macy if (after_branch_point && 361eda14cbcSMatt Macy dsl_dataset_phys(ds_prev)->ds_next_clones_obj != 0) { 362eda14cbcSMatt Macy dsl_dataset_remove_from_next_clones(ds_prev, obj, tx); 363eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) { 364eda14cbcSMatt Macy VERIFY0(zap_add_int(mos, 365eda14cbcSMatt Macy dsl_dataset_phys(ds_prev)-> 366eda14cbcSMatt Macy ds_next_clones_obj, 367eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_next_snap_obj, 368eda14cbcSMatt Macy tx)); 369eda14cbcSMatt Macy } 370eda14cbcSMatt Macy } 371eda14cbcSMatt Macy if (!after_branch_point) { 372eda14cbcSMatt Macy dsl_dataset_phys(ds_prev)->ds_next_snap_obj = 373eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_next_snap_obj; 374eda14cbcSMatt Macy } 375eda14cbcSMatt Macy } 376eda14cbcSMatt Macy 377eda14cbcSMatt Macy dsl_dataset_t *ds_next; 378eda14cbcSMatt Macy uint64_t old_unique; 379eda14cbcSMatt Macy uint64_t used = 0, comp = 0, uncomp = 0; 380eda14cbcSMatt Macy 381eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold_obj(dp, 382eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_next_snap_obj, FTAG, &ds_next)); 383eda14cbcSMatt Macy ASSERT3U(dsl_dataset_phys(ds_next)->ds_prev_snap_obj, ==, obj); 384eda14cbcSMatt Macy 385eda14cbcSMatt Macy old_unique = dsl_dataset_phys(ds_next)->ds_unique_bytes; 386eda14cbcSMatt Macy 387eda14cbcSMatt Macy dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 388eda14cbcSMatt Macy dsl_dataset_phys(ds_next)->ds_prev_snap_obj = 389eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_obj; 390eda14cbcSMatt Macy dsl_dataset_phys(ds_next)->ds_prev_snap_txg = 391eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_txg; 392eda14cbcSMatt Macy ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, ==, 393eda14cbcSMatt Macy ds_prev ? dsl_dataset_phys(ds_prev)->ds_creation_txg : 0); 394eda14cbcSMatt Macy 395eda14cbcSMatt Macy if (ds_next->ds_deadlist.dl_oldfmt) { 396eda14cbcSMatt Macy process_old_deadlist(ds, ds_prev, ds_next, 397eda14cbcSMatt Macy after_branch_point, tx); 398eda14cbcSMatt Macy } else { 399eda14cbcSMatt Macy /* Adjust prev's unique space. */ 400eda14cbcSMatt Macy if (ds_prev && !after_branch_point) { 401eda14cbcSMatt Macy dsl_deadlist_space_range(&ds_next->ds_deadlist, 402eda14cbcSMatt Macy dsl_dataset_phys(ds_prev)->ds_prev_snap_txg, 403eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_txg, 404eda14cbcSMatt Macy &used, &comp, &uncomp); 405eda14cbcSMatt Macy dsl_dataset_phys(ds_prev)->ds_unique_bytes += used; 406eda14cbcSMatt Macy } 407eda14cbcSMatt Macy 408eda14cbcSMatt Macy /* Adjust snapused. */ 409eda14cbcSMatt Macy dsl_deadlist_space_range(&ds_next->ds_deadlist, 410eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_txg, UINT64_MAX, 411eda14cbcSMatt Macy &used, &comp, &uncomp); 412eda14cbcSMatt Macy dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 413eda14cbcSMatt Macy -used, -comp, -uncomp, tx); 414eda14cbcSMatt Macy 415eda14cbcSMatt Macy /* Move blocks to be freed to pool's free list. */ 416eda14cbcSMatt Macy dsl_deadlist_move_bpobj(&ds_next->ds_deadlist, 417eda14cbcSMatt Macy &dp->dp_free_bpobj, dsl_dataset_phys(ds)->ds_prev_snap_txg, 418eda14cbcSMatt Macy tx); 419eda14cbcSMatt Macy dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, 420eda14cbcSMatt Macy DD_USED_HEAD, used, comp, uncomp, tx); 421eda14cbcSMatt Macy 422eda14cbcSMatt Macy /* Merge our deadlist into next's and free it. */ 423eda14cbcSMatt Macy dsl_deadlist_merge(&ds_next->ds_deadlist, 424eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 425eda14cbcSMatt Macy 426eda14cbcSMatt Macy /* 427eda14cbcSMatt Macy * We are done with the deadlist tree (generated/used 428eda14cbcSMatt Macy * by dsl_deadlist_move_bpobj() and dsl_deadlist_merge()). 429eda14cbcSMatt Macy * Discard it to save memory. 430eda14cbcSMatt Macy */ 431eda14cbcSMatt Macy dsl_deadlist_discard_tree(&ds_next->ds_deadlist); 432eda14cbcSMatt Macy } 433eda14cbcSMatt Macy 434eda14cbcSMatt Macy dsl_deadlist_close(&ds->ds_deadlist); 435eda14cbcSMatt Macy dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 436eda14cbcSMatt Macy dmu_buf_will_dirty(ds->ds_dbuf, tx); 437eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_deadlist_obj = 0; 438eda14cbcSMatt Macy 439eda14cbcSMatt Macy dsl_destroy_snapshot_handle_remaps(ds, ds_next, tx); 440eda14cbcSMatt Macy 441eda14cbcSMatt Macy if (!book_exists) { 442eda14cbcSMatt Macy /* Collapse range in clone heads */ 443eda14cbcSMatt Macy dsl_dir_remove_clones_key(ds->ds_dir, 444eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_creation_txg, tx); 445eda14cbcSMatt Macy } 446eda14cbcSMatt Macy 447eda14cbcSMatt Macy if (ds_next->ds_is_snapshot) { 448eda14cbcSMatt Macy dsl_dataset_t *ds_nextnext; 449eda14cbcSMatt Macy 450eda14cbcSMatt Macy /* 451eda14cbcSMatt Macy * Update next's unique to include blocks which 452eda14cbcSMatt Macy * were previously shared by only this snapshot 453eda14cbcSMatt Macy * and it. Those blocks will be born after the 454eda14cbcSMatt Macy * prev snap and before this snap, and will have 455eda14cbcSMatt Macy * died after the next snap and before the one 456eda14cbcSMatt Macy * after that (ie. be on the snap after next's 457eda14cbcSMatt Macy * deadlist). 458eda14cbcSMatt Macy */ 459eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold_obj(dp, 460eda14cbcSMatt Macy dsl_dataset_phys(ds_next)->ds_next_snap_obj, 461eda14cbcSMatt Macy FTAG, &ds_nextnext)); 462eda14cbcSMatt Macy dsl_deadlist_space_range(&ds_nextnext->ds_deadlist, 463eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_txg, 464eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_creation_txg, 465eda14cbcSMatt Macy &used, &comp, &uncomp); 466eda14cbcSMatt Macy dsl_dataset_phys(ds_next)->ds_unique_bytes += used; 467eda14cbcSMatt Macy dsl_dataset_rele(ds_nextnext, FTAG); 468eda14cbcSMatt Macy ASSERT3P(ds_next->ds_prev, ==, NULL); 469eda14cbcSMatt Macy 470eda14cbcSMatt Macy /* Collapse range in this head. */ 471eda14cbcSMatt Macy dsl_dataset_t *hds; 472eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold_obj(dp, 473eda14cbcSMatt Macy dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, 474eda14cbcSMatt Macy FTAG, &hds)); 475eda14cbcSMatt Macy if (!book_exists) { 476eda14cbcSMatt Macy /* Collapse range in this head. */ 477eda14cbcSMatt Macy dsl_deadlist_remove_key(&hds->ds_deadlist, 478eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_creation_txg, tx); 479eda14cbcSMatt Macy } 480eda14cbcSMatt Macy if (dsl_dataset_remap_deadlist_exists(hds)) { 481eda14cbcSMatt Macy dsl_deadlist_remove_key(&hds->ds_remap_deadlist, 482eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_creation_txg, tx); 483eda14cbcSMatt Macy } 484eda14cbcSMatt Macy dsl_dataset_rele(hds, FTAG); 485eda14cbcSMatt Macy 486eda14cbcSMatt Macy } else { 487eda14cbcSMatt Macy ASSERT3P(ds_next->ds_prev, ==, ds); 488eda14cbcSMatt Macy dsl_dataset_rele(ds_next->ds_prev, ds_next); 489eda14cbcSMatt Macy ds_next->ds_prev = NULL; 490eda14cbcSMatt Macy if (ds_prev) { 491eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold_obj(dp, 492eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_obj, 493eda14cbcSMatt Macy ds_next, &ds_next->ds_prev)); 494eda14cbcSMatt Macy } 495eda14cbcSMatt Macy 496eda14cbcSMatt Macy dsl_dataset_recalc_head_uniq(ds_next); 497eda14cbcSMatt Macy 498eda14cbcSMatt Macy /* 499eda14cbcSMatt Macy * Reduce the amount of our unconsumed refreservation 500eda14cbcSMatt Macy * being charged to our parent by the amount of 501eda14cbcSMatt Macy * new unique data we have gained. 502eda14cbcSMatt Macy */ 503eda14cbcSMatt Macy if (old_unique < ds_next->ds_reserved) { 504eda14cbcSMatt Macy int64_t mrsdelta; 505eda14cbcSMatt Macy uint64_t new_unique = 506eda14cbcSMatt Macy dsl_dataset_phys(ds_next)->ds_unique_bytes; 507eda14cbcSMatt Macy 508eda14cbcSMatt Macy ASSERT(old_unique <= new_unique); 509eda14cbcSMatt Macy mrsdelta = MIN(new_unique - old_unique, 510eda14cbcSMatt Macy ds_next->ds_reserved - old_unique); 511eda14cbcSMatt Macy dsl_dir_diduse_space(ds->ds_dir, 512eda14cbcSMatt Macy DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 513eda14cbcSMatt Macy } 514eda14cbcSMatt Macy } 515eda14cbcSMatt Macy dsl_dataset_rele(ds_next, FTAG); 516eda14cbcSMatt Macy 517eda14cbcSMatt Macy /* 518eda14cbcSMatt Macy * This must be done after the dsl_traverse(), because it will 519eda14cbcSMatt Macy * re-open the objset. 520eda14cbcSMatt Macy */ 521eda14cbcSMatt Macy if (ds->ds_objset) { 522eda14cbcSMatt Macy dmu_objset_evict(ds->ds_objset); 523eda14cbcSMatt Macy ds->ds_objset = NULL; 524eda14cbcSMatt Macy } 525eda14cbcSMatt Macy 526eda14cbcSMatt Macy /* remove from snapshot namespace */ 527eda14cbcSMatt Macy dsl_dataset_t *ds_head; 528eda14cbcSMatt Macy ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj == 0); 529eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold_obj(dp, 530eda14cbcSMatt Macy dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &ds_head)); 531eda14cbcSMatt Macy VERIFY0(dsl_dataset_get_snapname(ds)); 532eda14cbcSMatt Macy #ifdef ZFS_DEBUG 533eda14cbcSMatt Macy { 534eda14cbcSMatt Macy uint64_t val; 535eda14cbcSMatt Macy int err; 536eda14cbcSMatt Macy 537eda14cbcSMatt Macy err = dsl_dataset_snap_lookup(ds_head, 538eda14cbcSMatt Macy ds->ds_snapname, &val); 539eda14cbcSMatt Macy ASSERT0(err); 540eda14cbcSMatt Macy ASSERT3U(val, ==, obj); 541eda14cbcSMatt Macy } 542eda14cbcSMatt Macy #endif 543eda14cbcSMatt Macy VERIFY0(dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx, B_TRUE)); 544eda14cbcSMatt Macy dsl_dataset_rele(ds_head, FTAG); 545eda14cbcSMatt Macy 546eda14cbcSMatt Macy if (ds_prev != NULL) 547eda14cbcSMatt Macy dsl_dataset_rele(ds_prev, FTAG); 548eda14cbcSMatt Macy 549eda14cbcSMatt Macy spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 550eda14cbcSMatt Macy 551eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_next_clones_obj != 0) { 552eda14cbcSMatt Macy uint64_t count __maybe_unused; 553eda14cbcSMatt Macy ASSERT0(zap_count(mos, 554eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_next_clones_obj, &count) && 555eda14cbcSMatt Macy count == 0); 556eda14cbcSMatt Macy VERIFY0(dmu_object_free(mos, 557eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_next_clones_obj, tx)); 558eda14cbcSMatt Macy } 559eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_props_obj != 0) 560eda14cbcSMatt Macy VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_props_obj, 561eda14cbcSMatt Macy tx)); 562eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_userrefs_obj != 0) 563eda14cbcSMatt Macy VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_userrefs_obj, 564eda14cbcSMatt Macy tx)); 565eda14cbcSMatt Macy dsl_dir_rele(ds->ds_dir, ds); 566eda14cbcSMatt Macy ds->ds_dir = NULL; 567eda14cbcSMatt Macy dmu_object_free_zapified(mos, obj, tx); 568eda14cbcSMatt Macy } 569eda14cbcSMatt Macy 570eda14cbcSMatt Macy void 571eda14cbcSMatt Macy dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx) 572eda14cbcSMatt Macy { 573eda14cbcSMatt Macy dsl_destroy_snapshot_arg_t *ddsa = arg; 574eda14cbcSMatt Macy const char *dsname = ddsa->ddsa_name; 575eda14cbcSMatt Macy boolean_t defer = ddsa->ddsa_defer; 576eda14cbcSMatt Macy 577eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 578eda14cbcSMatt Macy dsl_dataset_t *ds; 579eda14cbcSMatt Macy 580eda14cbcSMatt Macy int error = dsl_dataset_hold(dp, dsname, FTAG, &ds); 581eda14cbcSMatt Macy if (error == ENOENT) 582eda14cbcSMatt Macy return; 583eda14cbcSMatt Macy ASSERT0(error); 584eda14cbcSMatt Macy dsl_destroy_snapshot_sync_impl(ds, defer, tx); 585eda14cbcSMatt Macy zvol_remove_minors(dp->dp_spa, dsname, B_TRUE); 586eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 587eda14cbcSMatt Macy } 588eda14cbcSMatt Macy 589eda14cbcSMatt Macy /* 590eda14cbcSMatt Macy * The semantics of this function are described in the comment above 591eda14cbcSMatt Macy * lzc_destroy_snaps(). To summarize: 592eda14cbcSMatt Macy * 593eda14cbcSMatt Macy * The snapshots must all be in the same pool. 594eda14cbcSMatt Macy * 595eda14cbcSMatt Macy * Snapshots that don't exist will be silently ignored (considered to be 596eda14cbcSMatt Macy * "already deleted"). 597eda14cbcSMatt Macy * 598eda14cbcSMatt Macy * On success, all snaps will be destroyed and this will return 0. 599eda14cbcSMatt Macy * On failure, no snaps will be destroyed, the errlist will be filled in, 600eda14cbcSMatt Macy * and this will return an errno. 601eda14cbcSMatt Macy */ 602eda14cbcSMatt Macy int 603eda14cbcSMatt Macy dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer, 604eda14cbcSMatt Macy nvlist_t *errlist) 605eda14cbcSMatt Macy { 606eda14cbcSMatt Macy if (nvlist_next_nvpair(snaps, NULL) == NULL) 607eda14cbcSMatt Macy return (0); 608eda14cbcSMatt Macy 609eda14cbcSMatt Macy /* 610eda14cbcSMatt Macy * lzc_destroy_snaps() is documented to take an nvlist whose 611eda14cbcSMatt Macy * values "don't matter". We need to convert that nvlist to 612184c1b94SMartin Matuska * one that we know can be converted to LUA. 613eda14cbcSMatt Macy */ 614184c1b94SMartin Matuska nvlist_t *snaps_normalized = fnvlist_alloc(); 615eda14cbcSMatt Macy for (nvpair_t *pair = nvlist_next_nvpair(snaps, NULL); 616eda14cbcSMatt Macy pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) { 617eda14cbcSMatt Macy fnvlist_add_boolean_value(snaps_normalized, 618eda14cbcSMatt Macy nvpair_name(pair), B_TRUE); 619eda14cbcSMatt Macy } 620eda14cbcSMatt Macy 621184c1b94SMartin Matuska nvlist_t *arg = fnvlist_alloc(); 622eda14cbcSMatt Macy fnvlist_add_nvlist(arg, "snaps", snaps_normalized); 623eda14cbcSMatt Macy fnvlist_free(snaps_normalized); 624eda14cbcSMatt Macy fnvlist_add_boolean_value(arg, "defer", defer); 625eda14cbcSMatt Macy 626184c1b94SMartin Matuska nvlist_t *wrapper = fnvlist_alloc(); 627eda14cbcSMatt Macy fnvlist_add_nvlist(wrapper, ZCP_ARG_ARGLIST, arg); 628eda14cbcSMatt Macy fnvlist_free(arg); 629eda14cbcSMatt Macy 630eda14cbcSMatt Macy const char *program = 631eda14cbcSMatt Macy "arg = ...\n" 632eda14cbcSMatt Macy "snaps = arg['snaps']\n" 633eda14cbcSMatt Macy "defer = arg['defer']\n" 634eda14cbcSMatt Macy "errors = { }\n" 635eda14cbcSMatt Macy "has_errors = false\n" 636eda14cbcSMatt Macy "for snap, v in pairs(snaps) do\n" 637eda14cbcSMatt Macy " errno = zfs.check.destroy{snap, defer=defer}\n" 638eda14cbcSMatt Macy " zfs.debug('snap: ' .. snap .. ' errno: ' .. errno)\n" 639eda14cbcSMatt Macy " if errno == ENOENT then\n" 640eda14cbcSMatt Macy " snaps[snap] = nil\n" 641eda14cbcSMatt Macy " elseif errno ~= 0 then\n" 642eda14cbcSMatt Macy " errors[snap] = errno\n" 643eda14cbcSMatt Macy " has_errors = true\n" 644eda14cbcSMatt Macy " end\n" 645eda14cbcSMatt Macy "end\n" 646eda14cbcSMatt Macy "if has_errors then\n" 647eda14cbcSMatt Macy " return errors\n" 648eda14cbcSMatt Macy "end\n" 649eda14cbcSMatt Macy "for snap, v in pairs(snaps) do\n" 650eda14cbcSMatt Macy " errno = zfs.sync.destroy{snap, defer=defer}\n" 651eda14cbcSMatt Macy " assert(errno == 0)\n" 652eda14cbcSMatt Macy "end\n" 653eda14cbcSMatt Macy "return { }\n"; 654eda14cbcSMatt Macy 655eda14cbcSMatt Macy nvlist_t *result = fnvlist_alloc(); 656eda14cbcSMatt Macy int error = zcp_eval(nvpair_name(nvlist_next_nvpair(snaps, NULL)), 657eda14cbcSMatt Macy program, 658eda14cbcSMatt Macy B_TRUE, 659eda14cbcSMatt Macy 0, 660eda14cbcSMatt Macy zfs_lua_max_memlimit, 661184c1b94SMartin Matuska fnvlist_lookup_nvpair(wrapper, ZCP_ARG_ARGLIST), result); 662eda14cbcSMatt Macy if (error != 0) { 6632a58b312SMartin Matuska const char *errorstr = NULL; 664eda14cbcSMatt Macy (void) nvlist_lookup_string(result, ZCP_RET_ERROR, &errorstr); 665eda14cbcSMatt Macy if (errorstr != NULL) { 66633b8c039SMartin Matuska zfs_dbgmsg("%s", errorstr); 667eda14cbcSMatt Macy } 668eda14cbcSMatt Macy fnvlist_free(wrapper); 669eda14cbcSMatt Macy fnvlist_free(result); 670eda14cbcSMatt Macy return (error); 671eda14cbcSMatt Macy } 672eda14cbcSMatt Macy fnvlist_free(wrapper); 673eda14cbcSMatt Macy 674eda14cbcSMatt Macy /* 675eda14cbcSMatt Macy * lzc_destroy_snaps() is documented to fill the errlist with 676eda14cbcSMatt Macy * int32 values, so we need to convert the int64 values that are 677eda14cbcSMatt Macy * returned from LUA. 678eda14cbcSMatt Macy */ 679eda14cbcSMatt Macy int rv = 0; 680eda14cbcSMatt Macy nvlist_t *errlist_raw = fnvlist_lookup_nvlist(result, ZCP_RET_RETURN); 681eda14cbcSMatt Macy for (nvpair_t *pair = nvlist_next_nvpair(errlist_raw, NULL); 682eda14cbcSMatt Macy pair != NULL; pair = nvlist_next_nvpair(errlist_raw, pair)) { 683eda14cbcSMatt Macy int32_t val = (int32_t)fnvpair_value_int64(pair); 684eda14cbcSMatt Macy if (rv == 0) 685eda14cbcSMatt Macy rv = val; 686eda14cbcSMatt Macy fnvlist_add_int32(errlist, nvpair_name(pair), val); 687eda14cbcSMatt Macy } 688eda14cbcSMatt Macy fnvlist_free(result); 689eda14cbcSMatt Macy return (rv); 690eda14cbcSMatt Macy } 691eda14cbcSMatt Macy 692eda14cbcSMatt Macy int 693eda14cbcSMatt Macy dsl_destroy_snapshot(const char *name, boolean_t defer) 694eda14cbcSMatt Macy { 695eda14cbcSMatt Macy int error; 696eda14cbcSMatt Macy nvlist_t *nvl = fnvlist_alloc(); 697eda14cbcSMatt Macy nvlist_t *errlist = fnvlist_alloc(); 698eda14cbcSMatt Macy 699eda14cbcSMatt Macy fnvlist_add_boolean(nvl, name); 700eda14cbcSMatt Macy error = dsl_destroy_snapshots_nvl(nvl, defer, errlist); 701eda14cbcSMatt Macy fnvlist_free(errlist); 702eda14cbcSMatt Macy fnvlist_free(nvl); 703eda14cbcSMatt Macy return (error); 704eda14cbcSMatt Macy } 705eda14cbcSMatt Macy 706eda14cbcSMatt Macy struct killarg { 707eda14cbcSMatt Macy dsl_dataset_t *ds; 708eda14cbcSMatt Macy dmu_tx_t *tx; 709eda14cbcSMatt Macy }; 710eda14cbcSMatt Macy 711eda14cbcSMatt Macy static int 712eda14cbcSMatt Macy kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 713eda14cbcSMatt Macy const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) 714eda14cbcSMatt Macy { 715e92ffd9bSMartin Matuska (void) spa, (void) dnp; 716eda14cbcSMatt Macy struct killarg *ka = arg; 717eda14cbcSMatt Macy dmu_tx_t *tx = ka->tx; 718eda14cbcSMatt Macy 719eda14cbcSMatt Macy if (zb->zb_level == ZB_DNODE_LEVEL || BP_IS_HOLE(bp) || 720eda14cbcSMatt Macy BP_IS_EMBEDDED(bp)) 721eda14cbcSMatt Macy return (0); 722eda14cbcSMatt Macy 723eda14cbcSMatt Macy if (zb->zb_level == ZB_ZIL_LEVEL) { 724eda14cbcSMatt Macy ASSERT(zilog != NULL); 725eda14cbcSMatt Macy /* 726eda14cbcSMatt Macy * It's a block in the intent log. It has no 727eda14cbcSMatt Macy * accounting, so just free it. 728eda14cbcSMatt Macy */ 729eda14cbcSMatt Macy dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp); 730eda14cbcSMatt Macy } else { 731eda14cbcSMatt Macy ASSERT(zilog == NULL); 732783d3ff6SMartin Matuska ASSERT3U(BP_GET_LOGICAL_BIRTH(bp), >, 733eda14cbcSMatt Macy dsl_dataset_phys(ka->ds)->ds_prev_snap_txg); 734eda14cbcSMatt Macy (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE); 735eda14cbcSMatt Macy } 736eda14cbcSMatt Macy 737eda14cbcSMatt Macy return (0); 738eda14cbcSMatt Macy } 739eda14cbcSMatt Macy 740eda14cbcSMatt Macy static void 741eda14cbcSMatt Macy old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx) 742eda14cbcSMatt Macy { 743eda14cbcSMatt Macy struct killarg ka; 744eda14cbcSMatt Macy 745eda14cbcSMatt Macy spa_history_log_internal_ds(ds, "destroy", tx, 746eda14cbcSMatt Macy "(synchronous, mintxg=%llu)", 747eda14cbcSMatt Macy (long long)dsl_dataset_phys(ds)->ds_prev_snap_txg); 748eda14cbcSMatt Macy 749eda14cbcSMatt Macy /* 750eda14cbcSMatt Macy * Free everything that we point to (that's born after 751eda14cbcSMatt Macy * the previous snapshot, if we are a clone) 752eda14cbcSMatt Macy * 753eda14cbcSMatt Macy * NB: this should be very quick, because we already 754eda14cbcSMatt Macy * freed all the objects in open context. 755eda14cbcSMatt Macy */ 756eda14cbcSMatt Macy ka.ds = ds; 757eda14cbcSMatt Macy ka.tx = tx; 758eda14cbcSMatt Macy VERIFY0(traverse_dataset(ds, 759eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_txg, TRAVERSE_POST | 760eda14cbcSMatt Macy TRAVERSE_NO_DECRYPT, kill_blkptr, &ka)); 761eda14cbcSMatt Macy ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 762eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_unique_bytes == 0); 763eda14cbcSMatt Macy } 764eda14cbcSMatt Macy 765eda14cbcSMatt Macy int 766eda14cbcSMatt Macy dsl_destroy_head_check_impl(dsl_dataset_t *ds, int expected_holds) 767eda14cbcSMatt Macy { 768eda14cbcSMatt Macy int error; 769eda14cbcSMatt Macy uint64_t count; 770eda14cbcSMatt Macy objset_t *mos; 771eda14cbcSMatt Macy 772eda14cbcSMatt Macy ASSERT(!ds->ds_is_snapshot); 773eda14cbcSMatt Macy if (ds->ds_is_snapshot) 774eda14cbcSMatt Macy return (SET_ERROR(EINVAL)); 775eda14cbcSMatt Macy 776eda14cbcSMatt Macy if (zfs_refcount_count(&ds->ds_longholds) != expected_holds) 777eda14cbcSMatt Macy return (SET_ERROR(EBUSY)); 778eda14cbcSMatt Macy 779eda14cbcSMatt Macy ASSERT0(ds->ds_dir->dd_activity_waiters); 780eda14cbcSMatt Macy 781eda14cbcSMatt Macy mos = ds->ds_dir->dd_pool->dp_meta_objset; 782eda14cbcSMatt Macy 783eda14cbcSMatt Macy /* 784eda14cbcSMatt Macy * Can't delete a head dataset if there are snapshots of it. 785eda14cbcSMatt Macy * (Except if the only snapshots are from the branch we cloned 786eda14cbcSMatt Macy * from.) 787eda14cbcSMatt Macy */ 788eda14cbcSMatt Macy if (ds->ds_prev != NULL && 789eda14cbcSMatt Macy dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj == ds->ds_object) 790eda14cbcSMatt Macy return (SET_ERROR(EBUSY)); 791eda14cbcSMatt Macy 792eda14cbcSMatt Macy /* 793eda14cbcSMatt Macy * Can't delete if there are children of this fs. 794eda14cbcSMatt Macy */ 795eda14cbcSMatt Macy error = zap_count(mos, 796eda14cbcSMatt Macy dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, &count); 797eda14cbcSMatt Macy if (error != 0) 798eda14cbcSMatt Macy return (error); 799eda14cbcSMatt Macy if (count != 0) 800eda14cbcSMatt Macy return (SET_ERROR(EEXIST)); 801eda14cbcSMatt Macy 802eda14cbcSMatt Macy if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev) && 803eda14cbcSMatt Macy dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 && 804eda14cbcSMatt Macy ds->ds_prev->ds_userrefs == 0) { 805eda14cbcSMatt Macy /* We need to remove the origin snapshot as well. */ 806eda14cbcSMatt Macy if (!zfs_refcount_is_zero(&ds->ds_prev->ds_longholds)) 807eda14cbcSMatt Macy return (SET_ERROR(EBUSY)); 808eda14cbcSMatt Macy } 809eda14cbcSMatt Macy return (0); 810eda14cbcSMatt Macy } 811eda14cbcSMatt Macy 812eda14cbcSMatt Macy int 813eda14cbcSMatt Macy dsl_destroy_head_check(void *arg, dmu_tx_t *tx) 814eda14cbcSMatt Macy { 815eda14cbcSMatt Macy dsl_destroy_head_arg_t *ddha = arg; 816eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 817eda14cbcSMatt Macy dsl_dataset_t *ds; 818eda14cbcSMatt Macy int error; 819eda14cbcSMatt Macy 820eda14cbcSMatt Macy error = dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds); 821eda14cbcSMatt Macy if (error != 0) 822eda14cbcSMatt Macy return (error); 823eda14cbcSMatt Macy 824eda14cbcSMatt Macy error = dsl_destroy_head_check_impl(ds, 0); 825eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 826eda14cbcSMatt Macy return (error); 827eda14cbcSMatt Macy } 828eda14cbcSMatt Macy 829eda14cbcSMatt Macy static void 830eda14cbcSMatt Macy dsl_dir_destroy_sync(uint64_t ddobj, dmu_tx_t *tx) 831eda14cbcSMatt Macy { 832eda14cbcSMatt Macy dsl_dir_t *dd; 833eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 834eda14cbcSMatt Macy objset_t *mos = dp->dp_meta_objset; 835eda14cbcSMatt Macy dd_used_t t; 836eda14cbcSMatt Macy 837eda14cbcSMatt Macy ASSERT(RRW_WRITE_HELD(&dmu_tx_pool(tx)->dp_config_rwlock)); 838eda14cbcSMatt Macy 839eda14cbcSMatt Macy VERIFY0(dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd)); 840eda14cbcSMatt Macy 841eda14cbcSMatt Macy ASSERT0(dsl_dir_phys(dd)->dd_head_dataset_obj); 842eda14cbcSMatt Macy 843eda14cbcSMatt Macy /* Decrement the filesystem count for all parent filesystems. */ 844eda14cbcSMatt Macy if (dd->dd_parent != NULL) 845eda14cbcSMatt Macy dsl_fs_ss_count_adjust(dd->dd_parent, -1, 846eda14cbcSMatt Macy DD_FIELD_FILESYSTEM_COUNT, tx); 847eda14cbcSMatt Macy 848eda14cbcSMatt Macy /* 849eda14cbcSMatt Macy * Remove our reservation. The impl() routine avoids setting the 850eda14cbcSMatt Macy * actual property, which would require the (already destroyed) ds. 851eda14cbcSMatt Macy */ 852eda14cbcSMatt Macy dsl_dir_set_reservation_sync_impl(dd, 0, tx); 853eda14cbcSMatt Macy 854eda14cbcSMatt Macy ASSERT0(dsl_dir_phys(dd)->dd_used_bytes); 855eda14cbcSMatt Macy ASSERT0(dsl_dir_phys(dd)->dd_reserved); 856eda14cbcSMatt Macy for (t = 0; t < DD_USED_NUM; t++) 857eda14cbcSMatt Macy ASSERT0(dsl_dir_phys(dd)->dd_used_breakdown[t]); 858eda14cbcSMatt Macy 859eda14cbcSMatt Macy if (dd->dd_crypto_obj != 0) { 860eda14cbcSMatt Macy dsl_crypto_key_destroy_sync(dd->dd_crypto_obj, tx); 861eda14cbcSMatt Macy (void) spa_keystore_unload_wkey_impl(dp->dp_spa, dd->dd_object); 862eda14cbcSMatt Macy } 863eda14cbcSMatt Macy 864eda14cbcSMatt Macy VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_child_dir_zapobj, tx)); 865eda14cbcSMatt Macy VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_props_zapobj, tx)); 866eda14cbcSMatt Macy if (dsl_dir_phys(dd)->dd_clones != 0) 867eda14cbcSMatt Macy VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_clones, tx)); 868eda14cbcSMatt Macy VERIFY0(dsl_deleg_destroy(mos, dsl_dir_phys(dd)->dd_deleg_zapobj, tx)); 869eda14cbcSMatt Macy VERIFY0(zap_remove(mos, 870eda14cbcSMatt Macy dsl_dir_phys(dd->dd_parent)->dd_child_dir_zapobj, 871eda14cbcSMatt Macy dd->dd_myname, tx)); 872eda14cbcSMatt Macy 873eda14cbcSMatt Macy dsl_dir_rele(dd, FTAG); 874eda14cbcSMatt Macy dmu_object_free_zapified(mos, ddobj, tx); 875eda14cbcSMatt Macy } 876eda14cbcSMatt Macy 877eda14cbcSMatt Macy static void 878eda14cbcSMatt Macy dsl_clone_destroy_assert(dsl_dir_t *dd) 879eda14cbcSMatt Macy { 880eda14cbcSMatt Macy uint64_t used, comp, uncomp; 881eda14cbcSMatt Macy 882eda14cbcSMatt Macy ASSERT(dsl_dir_is_clone(dd)); 883eda14cbcSMatt Macy dsl_deadlist_space(&dd->dd_livelist, &used, &comp, &uncomp); 884eda14cbcSMatt Macy 885eda14cbcSMatt Macy ASSERT3U(dsl_dir_phys(dd)->dd_used_bytes, ==, used); 886eda14cbcSMatt Macy ASSERT3U(dsl_dir_phys(dd)->dd_compressed_bytes, ==, comp); 887eda14cbcSMatt Macy /* 888eda14cbcSMatt Macy * Greater than because we do not track embedded block pointers in 889eda14cbcSMatt Macy * the livelist 890eda14cbcSMatt Macy */ 891eda14cbcSMatt Macy ASSERT3U(dsl_dir_phys(dd)->dd_uncompressed_bytes, >=, uncomp); 892eda14cbcSMatt Macy 893eda14cbcSMatt Macy ASSERT(list_is_empty(&dd->dd_pending_allocs.bpl_list)); 894eda14cbcSMatt Macy ASSERT(list_is_empty(&dd->dd_pending_frees.bpl_list)); 895eda14cbcSMatt Macy } 896eda14cbcSMatt Macy 897eda14cbcSMatt Macy /* 898eda14cbcSMatt Macy * Start the delete process for a clone. Free its zil, verify the space usage 899eda14cbcSMatt Macy * and queue the blkptrs for deletion by adding the livelist to the pool-wide 900eda14cbcSMatt Macy * delete queue. 901eda14cbcSMatt Macy */ 902eda14cbcSMatt Macy static void 903eda14cbcSMatt Macy dsl_async_clone_destroy(dsl_dataset_t *ds, dmu_tx_t *tx) 904eda14cbcSMatt Macy { 905eda14cbcSMatt Macy uint64_t zap_obj, to_delete, used, comp, uncomp; 906eda14cbcSMatt Macy objset_t *os; 907eda14cbcSMatt Macy dsl_dir_t *dd = ds->ds_dir; 908eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 909eda14cbcSMatt Macy objset_t *mos = dp->dp_meta_objset; 910eda14cbcSMatt Macy spa_t *spa = dmu_tx_pool(tx)->dp_spa; 911eda14cbcSMatt Macy VERIFY0(dmu_objset_from_ds(ds, &os)); 912eda14cbcSMatt Macy 913eda14cbcSMatt Macy uint64_t mintxg = 0; 914eda14cbcSMatt Macy dsl_deadlist_entry_t *dle = dsl_deadlist_first(&dd->dd_livelist); 915eda14cbcSMatt Macy if (dle != NULL) 916eda14cbcSMatt Macy mintxg = dle->dle_mintxg; 917eda14cbcSMatt Macy 918eda14cbcSMatt Macy spa_history_log_internal_ds(ds, "destroy", tx, 919eda14cbcSMatt Macy "(livelist, mintxg=%llu)", (long long)mintxg); 920eda14cbcSMatt Macy 921eda14cbcSMatt Macy /* Check that the clone is in a correct state to be deleted */ 922eda14cbcSMatt Macy dsl_clone_destroy_assert(dd); 923eda14cbcSMatt Macy 924eda14cbcSMatt Macy /* Destroy the zil */ 925eda14cbcSMatt Macy zil_destroy_sync(dmu_objset_zil(os), tx); 926eda14cbcSMatt Macy 927eda14cbcSMatt Macy VERIFY0(zap_lookup(mos, dd->dd_object, 928eda14cbcSMatt Macy DD_FIELD_LIVELIST, sizeof (uint64_t), 1, &to_delete)); 929eda14cbcSMatt Macy /* Initialize deleted_clones entry to track livelists to cleanup */ 930eda14cbcSMatt Macy int error = zap_lookup(mos, DMU_POOL_DIRECTORY_OBJECT, 931eda14cbcSMatt Macy DMU_POOL_DELETED_CLONES, sizeof (uint64_t), 1, &zap_obj); 932eda14cbcSMatt Macy if (error == ENOENT) { 933eda14cbcSMatt Macy zap_obj = zap_create(mos, DMU_OTN_ZAP_METADATA, 934eda14cbcSMatt Macy DMU_OT_NONE, 0, tx); 935eda14cbcSMatt Macy VERIFY0(zap_add(mos, DMU_POOL_DIRECTORY_OBJECT, 936eda14cbcSMatt Macy DMU_POOL_DELETED_CLONES, sizeof (uint64_t), 1, 937eda14cbcSMatt Macy &(zap_obj), tx)); 938eda14cbcSMatt Macy spa->spa_livelists_to_delete = zap_obj; 939eda14cbcSMatt Macy } else if (error != 0) { 940eda14cbcSMatt Macy zfs_panic_recover("zfs: error %d was returned while looking " 941eda14cbcSMatt Macy "up DMU_POOL_DELETED_CLONES in the zap", error); 942eda14cbcSMatt Macy return; 943eda14cbcSMatt Macy } 944eda14cbcSMatt Macy VERIFY0(zap_add_int(mos, zap_obj, to_delete, tx)); 945eda14cbcSMatt Macy 946eda14cbcSMatt Macy /* Clone is no longer using space, now tracked by dp_free_dir */ 947eda14cbcSMatt Macy dsl_deadlist_space(&dd->dd_livelist, &used, &comp, &uncomp); 948eda14cbcSMatt Macy dsl_dir_diduse_space(dd, DD_USED_HEAD, 949eda14cbcSMatt Macy -used, -comp, -dsl_dir_phys(dd)->dd_uncompressed_bytes, 950eda14cbcSMatt Macy tx); 951eda14cbcSMatt Macy dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD, 952eda14cbcSMatt Macy used, comp, uncomp, tx); 953eda14cbcSMatt Macy dsl_dir_remove_livelist(dd, tx, B_FALSE); 954eda14cbcSMatt Macy zthr_wakeup(spa->spa_livelist_delete_zthr); 955eda14cbcSMatt Macy } 956eda14cbcSMatt Macy 957eda14cbcSMatt Macy /* 958eda14cbcSMatt Macy * Move the bptree into the pool's list of trees to clean up, update space 959eda14cbcSMatt Macy * accounting information and destroy the zil. 960eda14cbcSMatt Macy */ 961eda14cbcSMatt Macy static void 962eda14cbcSMatt Macy dsl_async_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx) 963eda14cbcSMatt Macy { 964eda14cbcSMatt Macy uint64_t used, comp, uncomp; 965eda14cbcSMatt Macy objset_t *os; 966eda14cbcSMatt Macy 967eda14cbcSMatt Macy VERIFY0(dmu_objset_from_ds(ds, &os)); 968eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 969eda14cbcSMatt Macy objset_t *mos = dp->dp_meta_objset; 970eda14cbcSMatt Macy 971eda14cbcSMatt Macy spa_history_log_internal_ds(ds, "destroy", tx, 972eda14cbcSMatt Macy "(bptree, mintxg=%llu)", 973eda14cbcSMatt Macy (long long)dsl_dataset_phys(ds)->ds_prev_snap_txg); 974eda14cbcSMatt Macy 975eda14cbcSMatt Macy zil_destroy_sync(dmu_objset_zil(os), tx); 976eda14cbcSMatt Macy 977eda14cbcSMatt Macy if (!spa_feature_is_active(dp->dp_spa, 978eda14cbcSMatt Macy SPA_FEATURE_ASYNC_DESTROY)) { 979eda14cbcSMatt Macy dsl_scan_t *scn = dp->dp_scan; 980eda14cbcSMatt Macy spa_feature_incr(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY, 981eda14cbcSMatt Macy tx); 982eda14cbcSMatt Macy dp->dp_bptree_obj = bptree_alloc(mos, tx); 983eda14cbcSMatt Macy VERIFY0(zap_add(mos, 984eda14cbcSMatt Macy DMU_POOL_DIRECTORY_OBJECT, 985eda14cbcSMatt Macy DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1, 986eda14cbcSMatt Macy &dp->dp_bptree_obj, tx)); 987eda14cbcSMatt Macy ASSERT(!scn->scn_async_destroying); 988eda14cbcSMatt Macy scn->scn_async_destroying = B_TRUE; 989eda14cbcSMatt Macy } 990eda14cbcSMatt Macy 991eda14cbcSMatt Macy used = dsl_dir_phys(ds->ds_dir)->dd_used_bytes; 992eda14cbcSMatt Macy comp = dsl_dir_phys(ds->ds_dir)->dd_compressed_bytes; 993eda14cbcSMatt Macy uncomp = dsl_dir_phys(ds->ds_dir)->dd_uncompressed_bytes; 994eda14cbcSMatt Macy 995eda14cbcSMatt Macy ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 996eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_unique_bytes == used); 997eda14cbcSMatt Macy 998eda14cbcSMatt Macy rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); 999eda14cbcSMatt Macy bptree_add(mos, dp->dp_bptree_obj, 1000eda14cbcSMatt Macy &dsl_dataset_phys(ds)->ds_bp, 1001eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_prev_snap_txg, 1002eda14cbcSMatt Macy used, comp, uncomp, tx); 1003eda14cbcSMatt Macy rrw_exit(&ds->ds_bp_rwlock, FTAG); 1004eda14cbcSMatt Macy dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 1005eda14cbcSMatt Macy -used, -comp, -uncomp, tx); 1006eda14cbcSMatt Macy dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD, 1007eda14cbcSMatt Macy used, comp, uncomp, tx); 1008eda14cbcSMatt Macy } 1009eda14cbcSMatt Macy 1010eda14cbcSMatt Macy void 1011eda14cbcSMatt Macy dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx) 1012eda14cbcSMatt Macy { 1013eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 1014eda14cbcSMatt Macy objset_t *mos = dp->dp_meta_objset; 1015eda14cbcSMatt Macy uint64_t obj, ddobj, prevobj = 0; 1016eda14cbcSMatt Macy boolean_t rmorigin; 1017eda14cbcSMatt Macy 1018eda14cbcSMatt Macy ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1); 1019eda14cbcSMatt Macy ASSERT(ds->ds_prev == NULL || 1020eda14cbcSMatt Macy dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj != ds->ds_object); 1021eda14cbcSMatt Macy rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); 1022783d3ff6SMartin Matuska ASSERT3U(BP_GET_LOGICAL_BIRTH(&dsl_dataset_phys(ds)->ds_bp), <=, 1023783d3ff6SMartin Matuska tx->tx_txg); 1024eda14cbcSMatt Macy rrw_exit(&ds->ds_bp_rwlock, FTAG); 1025eda14cbcSMatt Macy ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); 1026eda14cbcSMatt Macy 1027eda14cbcSMatt Macy dsl_dir_cancel_waiters(ds->ds_dir); 1028eda14cbcSMatt Macy 1029eda14cbcSMatt Macy rmorigin = (dsl_dir_is_clone(ds->ds_dir) && 1030eda14cbcSMatt Macy DS_IS_DEFER_DESTROY(ds->ds_prev) && 1031eda14cbcSMatt Macy dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 && 1032eda14cbcSMatt Macy ds->ds_prev->ds_userrefs == 0); 1033eda14cbcSMatt Macy 1034eda14cbcSMatt Macy /* Remove our reservation. */ 1035eda14cbcSMatt Macy if (ds->ds_reserved != 0) { 1036eda14cbcSMatt Macy dsl_dataset_set_refreservation_sync_impl(ds, 1037eda14cbcSMatt Macy (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), 1038eda14cbcSMatt Macy 0, tx); 1039eda14cbcSMatt Macy ASSERT0(ds->ds_reserved); 1040eda14cbcSMatt Macy } 1041eda14cbcSMatt Macy 1042eda14cbcSMatt Macy obj = ds->ds_object; 1043eda14cbcSMatt Macy 1044eda14cbcSMatt Macy for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { 1045eda14cbcSMatt Macy if (dsl_dataset_feature_is_active(ds, f)) 1046eda14cbcSMatt Macy dsl_dataset_deactivate_feature(ds, f, tx); 1047eda14cbcSMatt Macy } 1048eda14cbcSMatt Macy 1049eda14cbcSMatt Macy dsl_scan_ds_destroyed(ds, tx); 1050eda14cbcSMatt Macy 1051eda14cbcSMatt Macy if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { 1052eda14cbcSMatt Macy /* This is a clone */ 1053eda14cbcSMatt Macy ASSERT(ds->ds_prev != NULL); 1054eda14cbcSMatt Macy ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj, !=, 1055eda14cbcSMatt Macy obj); 1056eda14cbcSMatt Macy ASSERT0(dsl_dataset_phys(ds)->ds_next_snap_obj); 1057eda14cbcSMatt Macy 1058eda14cbcSMatt Macy dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1059eda14cbcSMatt Macy if (dsl_dataset_phys(ds->ds_prev)->ds_next_clones_obj != 0) { 1060eda14cbcSMatt Macy dsl_dataset_remove_from_next_clones(ds->ds_prev, 1061eda14cbcSMatt Macy obj, tx); 1062eda14cbcSMatt Macy } 1063eda14cbcSMatt Macy 1064eda14cbcSMatt Macy ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_num_children, >, 1); 1065eda14cbcSMatt Macy dsl_dataset_phys(ds->ds_prev)->ds_num_children--; 1066eda14cbcSMatt Macy } 1067eda14cbcSMatt Macy 1068eda14cbcSMatt Macy /* 1069eda14cbcSMatt Macy * Destroy the deadlist. Unless it's a clone, the 1070eda14cbcSMatt Macy * deadlist should be empty since the dataset has no snapshots. 1071eda14cbcSMatt Macy * (If it's a clone, it's safe to ignore the deadlist contents 1072eda14cbcSMatt Macy * since they are still referenced by the origin snapshot.) 1073eda14cbcSMatt Macy */ 1074eda14cbcSMatt Macy dsl_deadlist_close(&ds->ds_deadlist); 1075eda14cbcSMatt Macy dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 1076eda14cbcSMatt Macy dmu_buf_will_dirty(ds->ds_dbuf, tx); 1077eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_deadlist_obj = 0; 1078eda14cbcSMatt Macy 1079eda14cbcSMatt Macy if (dsl_dataset_remap_deadlist_exists(ds)) 1080eda14cbcSMatt Macy dsl_dataset_destroy_remap_deadlist(ds, tx); 1081eda14cbcSMatt Macy 1082eda14cbcSMatt Macy /* 1083eda14cbcSMatt Macy * Each destroy is responsible for both destroying (enqueuing 1084eda14cbcSMatt Macy * to be destroyed) the blkptrs comprising the dataset as well as 1085eda14cbcSMatt Macy * those belonging to the zil. 1086eda14cbcSMatt Macy */ 1087eda14cbcSMatt Macy if (dsl_deadlist_is_open(&ds->ds_dir->dd_livelist)) { 1088eda14cbcSMatt Macy dsl_async_clone_destroy(ds, tx); 1089eda14cbcSMatt Macy } else if (spa_feature_is_enabled(dp->dp_spa, 1090eda14cbcSMatt Macy SPA_FEATURE_ASYNC_DESTROY)) { 1091eda14cbcSMatt Macy dsl_async_dataset_destroy(ds, tx); 1092eda14cbcSMatt Macy } else { 1093eda14cbcSMatt Macy old_synchronous_dataset_destroy(ds, tx); 1094eda14cbcSMatt Macy } 1095eda14cbcSMatt Macy 1096eda14cbcSMatt Macy if (ds->ds_prev != NULL) { 1097eda14cbcSMatt Macy if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 1098eda14cbcSMatt Macy VERIFY0(zap_remove_int(mos, 1099eda14cbcSMatt Macy dsl_dir_phys(ds->ds_prev->ds_dir)->dd_clones, 1100eda14cbcSMatt Macy ds->ds_object, tx)); 1101eda14cbcSMatt Macy } 1102eda14cbcSMatt Macy prevobj = ds->ds_prev->ds_object; 1103eda14cbcSMatt Macy dsl_dataset_rele(ds->ds_prev, ds); 1104eda14cbcSMatt Macy ds->ds_prev = NULL; 1105eda14cbcSMatt Macy } 1106eda14cbcSMatt Macy 1107eda14cbcSMatt Macy /* 1108eda14cbcSMatt Macy * This must be done after the dsl_traverse(), because it will 1109eda14cbcSMatt Macy * re-open the objset. 1110eda14cbcSMatt Macy */ 1111eda14cbcSMatt Macy if (ds->ds_objset) { 1112eda14cbcSMatt Macy dmu_objset_evict(ds->ds_objset); 1113eda14cbcSMatt Macy ds->ds_objset = NULL; 1114eda14cbcSMatt Macy } 1115eda14cbcSMatt Macy 1116eda14cbcSMatt Macy /* Erase the link in the dir */ 1117eda14cbcSMatt Macy dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 1118eda14cbcSMatt Macy dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj = 0; 1119eda14cbcSMatt Macy ddobj = ds->ds_dir->dd_object; 1120eda14cbcSMatt Macy ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj != 0); 1121eda14cbcSMatt Macy VERIFY0(zap_destroy(mos, 1122eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_snapnames_zapobj, tx)); 1123eda14cbcSMatt Macy 1124eda14cbcSMatt Macy if (ds->ds_bookmarks_obj != 0) { 1125eda14cbcSMatt Macy void *cookie = NULL; 1126eda14cbcSMatt Macy dsl_bookmark_node_t *dbn; 1127eda14cbcSMatt Macy 1128eda14cbcSMatt Macy while ((dbn = avl_destroy_nodes(&ds->ds_bookmarks, &cookie)) != 1129eda14cbcSMatt Macy NULL) { 1130eda14cbcSMatt Macy if (dbn->dbn_phys.zbm_redaction_obj != 0) { 11312ad756a6SMartin Matuska dnode_t *rl; 11322ad756a6SMartin Matuska VERIFY0(dnode_hold(mos, 11332ad756a6SMartin Matuska dbn->dbn_phys.zbm_redaction_obj, FTAG, 11342ad756a6SMartin Matuska &rl)); 11352ad756a6SMartin Matuska if (rl->dn_have_spill) { 11362ad756a6SMartin Matuska spa_feature_decr(dmu_objset_spa(mos), 11372ad756a6SMartin Matuska SPA_FEATURE_REDACTION_LIST_SPILL, 11382ad756a6SMartin Matuska tx); 11392ad756a6SMartin Matuska } 11402ad756a6SMartin Matuska dnode_rele(rl, FTAG); 1141eda14cbcSMatt Macy VERIFY0(dmu_object_free(mos, 1142eda14cbcSMatt Macy dbn->dbn_phys.zbm_redaction_obj, tx)); 1143eda14cbcSMatt Macy spa_feature_decr(dmu_objset_spa(mos), 1144eda14cbcSMatt Macy SPA_FEATURE_REDACTION_BOOKMARKS, tx); 1145eda14cbcSMatt Macy } 1146eda14cbcSMatt Macy if (dbn->dbn_phys.zbm_flags & ZBM_FLAG_HAS_FBN) { 1147eda14cbcSMatt Macy spa_feature_decr(dmu_objset_spa(mos), 1148eda14cbcSMatt Macy SPA_FEATURE_BOOKMARK_WRITTEN, tx); 1149eda14cbcSMatt Macy } 1150eda14cbcSMatt Macy spa_strfree(dbn->dbn_name); 1151eda14cbcSMatt Macy mutex_destroy(&dbn->dbn_lock); 1152eda14cbcSMatt Macy kmem_free(dbn, sizeof (*dbn)); 1153eda14cbcSMatt Macy } 1154eda14cbcSMatt Macy avl_destroy(&ds->ds_bookmarks); 1155eda14cbcSMatt Macy VERIFY0(zap_destroy(mos, ds->ds_bookmarks_obj, tx)); 1156eda14cbcSMatt Macy spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx); 1157eda14cbcSMatt Macy } 1158eda14cbcSMatt Macy 1159eda14cbcSMatt Macy spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 1160eda14cbcSMatt Macy 1161eda14cbcSMatt Macy ASSERT0(dsl_dataset_phys(ds)->ds_next_clones_obj); 1162eda14cbcSMatt Macy ASSERT0(dsl_dataset_phys(ds)->ds_props_obj); 1163eda14cbcSMatt Macy ASSERT0(dsl_dataset_phys(ds)->ds_userrefs_obj); 1164eda14cbcSMatt Macy dsl_dir_rele(ds->ds_dir, ds); 1165eda14cbcSMatt Macy ds->ds_dir = NULL; 1166eda14cbcSMatt Macy dmu_object_free_zapified(mos, obj, tx); 1167eda14cbcSMatt Macy 1168eda14cbcSMatt Macy dsl_dir_destroy_sync(ddobj, tx); 1169eda14cbcSMatt Macy 1170eda14cbcSMatt Macy if (rmorigin) { 1171eda14cbcSMatt Macy dsl_dataset_t *prev; 1172eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold_obj(dp, prevobj, FTAG, &prev)); 1173eda14cbcSMatt Macy dsl_destroy_snapshot_sync_impl(prev, B_FALSE, tx); 1174eda14cbcSMatt Macy dsl_dataset_rele(prev, FTAG); 1175eda14cbcSMatt Macy } 1176716fd348SMartin Matuska /* Delete errlog. */ 1177716fd348SMartin Matuska if (spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_HEAD_ERRLOG)) 1178716fd348SMartin Matuska spa_delete_dataset_errlog(dp->dp_spa, ds->ds_object, tx); 1179eda14cbcSMatt Macy } 1180eda14cbcSMatt Macy 1181eda14cbcSMatt Macy void 1182eda14cbcSMatt Macy dsl_destroy_head_sync(void *arg, dmu_tx_t *tx) 1183eda14cbcSMatt Macy { 1184eda14cbcSMatt Macy dsl_destroy_head_arg_t *ddha = arg; 1185eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 1186eda14cbcSMatt Macy dsl_dataset_t *ds; 1187eda14cbcSMatt Macy 1188eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds)); 1189eda14cbcSMatt Macy dsl_destroy_head_sync_impl(ds, tx); 1190eda14cbcSMatt Macy zvol_remove_minors(dp->dp_spa, ddha->ddha_name, B_TRUE); 1191eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 1192eda14cbcSMatt Macy } 1193eda14cbcSMatt Macy 1194eda14cbcSMatt Macy static void 1195eda14cbcSMatt Macy dsl_destroy_head_begin_sync(void *arg, dmu_tx_t *tx) 1196eda14cbcSMatt Macy { 1197eda14cbcSMatt Macy dsl_destroy_head_arg_t *ddha = arg; 1198eda14cbcSMatt Macy dsl_pool_t *dp = dmu_tx_pool(tx); 1199eda14cbcSMatt Macy dsl_dataset_t *ds; 1200eda14cbcSMatt Macy 1201eda14cbcSMatt Macy VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds)); 1202eda14cbcSMatt Macy 1203eda14cbcSMatt Macy /* Mark it as inconsistent on-disk, in case we crash */ 1204eda14cbcSMatt Macy dmu_buf_will_dirty(ds->ds_dbuf, tx); 1205eda14cbcSMatt Macy dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT; 1206eda14cbcSMatt Macy 1207eda14cbcSMatt Macy spa_history_log_internal_ds(ds, "destroy begin", tx, " "); 1208eda14cbcSMatt Macy dsl_dataset_rele(ds, FTAG); 1209eda14cbcSMatt Macy } 1210eda14cbcSMatt Macy 1211eda14cbcSMatt Macy int 1212eda14cbcSMatt Macy dsl_destroy_head(const char *name) 1213eda14cbcSMatt Macy { 1214eda14cbcSMatt Macy dsl_destroy_head_arg_t ddha; 1215eda14cbcSMatt Macy int error; 1216eda14cbcSMatt Macy spa_t *spa; 1217eda14cbcSMatt Macy boolean_t isenabled; 1218eda14cbcSMatt Macy 1219eda14cbcSMatt Macy #ifdef _KERNEL 1220eda14cbcSMatt Macy zfs_destroy_unmount_origin(name); 1221eda14cbcSMatt Macy #endif 1222eda14cbcSMatt Macy 1223eda14cbcSMatt Macy error = spa_open(name, &spa, FTAG); 1224eda14cbcSMatt Macy if (error != 0) 1225eda14cbcSMatt Macy return (error); 1226eda14cbcSMatt Macy isenabled = spa_feature_is_enabled(spa, SPA_FEATURE_ASYNC_DESTROY); 1227eda14cbcSMatt Macy spa_close(spa, FTAG); 1228eda14cbcSMatt Macy 1229eda14cbcSMatt Macy ddha.ddha_name = name; 1230eda14cbcSMatt Macy 1231eda14cbcSMatt Macy if (!isenabled) { 1232eda14cbcSMatt Macy objset_t *os; 1233eda14cbcSMatt Macy 1234eda14cbcSMatt Macy error = dsl_sync_task(name, dsl_destroy_head_check, 1235eda14cbcSMatt Macy dsl_destroy_head_begin_sync, &ddha, 1236eda14cbcSMatt Macy 0, ZFS_SPACE_CHECK_DESTROY); 1237eda14cbcSMatt Macy if (error != 0) 1238eda14cbcSMatt Macy return (error); 1239eda14cbcSMatt Macy 1240eda14cbcSMatt Macy /* 1241eda14cbcSMatt Macy * Head deletion is processed in one txg on old pools; 1242eda14cbcSMatt Macy * remove the objects from open context so that the txg sync 1243eda14cbcSMatt Macy * is not too long. This optimization can only work for 1244eda14cbcSMatt Macy * encrypted datasets if the wrapping key is loaded. 1245eda14cbcSMatt Macy */ 1246eda14cbcSMatt Macy error = dmu_objset_own(name, DMU_OST_ANY, B_FALSE, B_TRUE, 1247eda14cbcSMatt Macy FTAG, &os); 1248eda14cbcSMatt Macy if (error == 0) { 1249eda14cbcSMatt Macy uint64_t prev_snap_txg = 1250eda14cbcSMatt Macy dsl_dataset_phys(dmu_objset_ds(os))-> 1251eda14cbcSMatt Macy ds_prev_snap_txg; 1252eda14cbcSMatt Macy for (uint64_t obj = 0; error == 0; 1253eda14cbcSMatt Macy error = dmu_object_next(os, &obj, FALSE, 1254eda14cbcSMatt Macy prev_snap_txg)) 1255eda14cbcSMatt Macy (void) dmu_free_long_object(os, obj); 1256eda14cbcSMatt Macy /* sync out all frees */ 1257eda14cbcSMatt Macy txg_wait_synced(dmu_objset_pool(os), 0); 1258eda14cbcSMatt Macy dmu_objset_disown(os, B_TRUE, FTAG); 1259eda14cbcSMatt Macy } 1260eda14cbcSMatt Macy } 1261eda14cbcSMatt Macy 1262eda14cbcSMatt Macy return (dsl_sync_task(name, dsl_destroy_head_check, 1263eda14cbcSMatt Macy dsl_destroy_head_sync, &ddha, 0, ZFS_SPACE_CHECK_DESTROY)); 1264eda14cbcSMatt Macy } 1265eda14cbcSMatt Macy 1266eda14cbcSMatt Macy /* 1267eda14cbcSMatt Macy * Note, this function is used as the callback for dmu_objset_find(). We 1268eda14cbcSMatt Macy * always return 0 so that we will continue to find and process 1269eda14cbcSMatt Macy * inconsistent datasets, even if we encounter an error trying to 1270eda14cbcSMatt Macy * process one of them. 1271eda14cbcSMatt Macy */ 1272eda14cbcSMatt Macy int 1273eda14cbcSMatt Macy dsl_destroy_inconsistent(const char *dsname, void *arg) 1274eda14cbcSMatt Macy { 1275e92ffd9bSMartin Matuska (void) arg; 1276eda14cbcSMatt Macy objset_t *os; 1277eda14cbcSMatt Macy 1278eda14cbcSMatt Macy if (dmu_objset_hold(dsname, FTAG, &os) == 0) { 1279eda14cbcSMatt Macy boolean_t need_destroy = DS_IS_INCONSISTENT(dmu_objset_ds(os)); 1280eda14cbcSMatt Macy 1281eda14cbcSMatt Macy /* 1282eda14cbcSMatt Macy * If the dataset is inconsistent because a resumable receive 1283eda14cbcSMatt Macy * has failed, then do not destroy it. 1284eda14cbcSMatt Macy */ 1285eda14cbcSMatt Macy if (dsl_dataset_has_resume_receive_state(dmu_objset_ds(os))) 1286eda14cbcSMatt Macy need_destroy = B_FALSE; 1287eda14cbcSMatt Macy 1288eda14cbcSMatt Macy dmu_objset_rele(os, FTAG); 1289eda14cbcSMatt Macy if (need_destroy) 1290eda14cbcSMatt Macy (void) dsl_destroy_head(dsname); 1291eda14cbcSMatt Macy } 1292eda14cbcSMatt Macy return (0); 1293eda14cbcSMatt Macy } 1294eda14cbcSMatt Macy 1295eda14cbcSMatt Macy 1296eda14cbcSMatt Macy #if defined(_KERNEL) 1297eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_destroy_head); 1298eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_destroy_head_sync_impl); 1299eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_dataset_user_hold_check_one); 1300eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_destroy_snapshot_sync_impl); 1301eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_destroy_inconsistent); 1302eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_dataset_user_release_tmp); 1303eda14cbcSMatt Macy EXPORT_SYMBOL(dsl_destroy_head_check_impl); 1304eda14cbcSMatt Macy #endif 1305