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