13b2aab18SMatthew Ahrens /* 23b2aab18SMatthew Ahrens * CDDL HEADER START 33b2aab18SMatthew Ahrens * 43b2aab18SMatthew Ahrens * The contents of this file are subject to the terms of the 53b2aab18SMatthew Ahrens * Common Development and Distribution License (the "License"). 63b2aab18SMatthew Ahrens * You may not use this file except in compliance with the License. 73b2aab18SMatthew Ahrens * 83b2aab18SMatthew Ahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 93b2aab18SMatthew Ahrens * or http://www.opensolaris.org/os/licensing. 103b2aab18SMatthew Ahrens * See the License for the specific language governing permissions 113b2aab18SMatthew Ahrens * and limitations under the License. 123b2aab18SMatthew Ahrens * 133b2aab18SMatthew Ahrens * When distributing Covered Code, include this CDDL HEADER in each 143b2aab18SMatthew Ahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 153b2aab18SMatthew Ahrens * If applicable, add the following below this CDDL HEADER, with the 163b2aab18SMatthew Ahrens * fields enclosed by brackets "[]" replaced with your own identifying 173b2aab18SMatthew Ahrens * information: Portions Copyright [yyyy] [name of copyright owner] 183b2aab18SMatthew Ahrens * 193b2aab18SMatthew Ahrens * CDDL HEADER END 203b2aab18SMatthew Ahrens */ 213b2aab18SMatthew Ahrens /* 223b2aab18SMatthew Ahrens * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 235cabbc6bSPrashanth Sreenivasa * Copyright (c) 2012, 2017 by Delphix. All rights reserved. 24a7a845e4SSteven Hartland * Copyright (c) 2013 Steven Hartland. All rights reserved. 25a2afb611SJerry Jelinek * Copyright (c) 2013 by Joyent, Inc. All rights reserved. 26c3d26abcSMatthew Ahrens * Copyright (c) 2014 Integros [integros.com] 273b2aab18SMatthew Ahrens */ 283b2aab18SMatthew Ahrens 293b2aab18SMatthew Ahrens #include <sys/zfs_context.h> 303b2aab18SMatthew Ahrens #include <sys/dsl_userhold.h> 313b2aab18SMatthew Ahrens #include <sys/dsl_dataset.h> 323b2aab18SMatthew Ahrens #include <sys/dsl_synctask.h> 33dfc11533SChris Williamson #include <sys/dsl_destroy.h> 343b2aab18SMatthew Ahrens #include <sys/dmu_tx.h> 353b2aab18SMatthew Ahrens #include <sys/dsl_pool.h> 363b2aab18SMatthew Ahrens #include <sys/dsl_dir.h> 373b2aab18SMatthew Ahrens #include <sys/dmu_traverse.h> 383b2aab18SMatthew Ahrens #include <sys/dsl_scan.h> 393b2aab18SMatthew Ahrens #include <sys/dmu_objset.h> 403b2aab18SMatthew Ahrens #include <sys/zap.h> 413b2aab18SMatthew Ahrens #include <sys/zfeature.h> 423b2aab18SMatthew Ahrens #include <sys/zfs_ioctl.h> 433b2aab18SMatthew Ahrens #include <sys/dsl_deleg.h> 442acef22dSMatthew Ahrens #include <sys/dmu_impl.h> 45dfc11533SChris Williamson #include <sys/zcp.h> 463b2aab18SMatthew Ahrens 4734f2f8cfSMatthew Ahrens int 483b2aab18SMatthew Ahrens dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer) 493b2aab18SMatthew Ahrens { 50bc9014e6SJustin Gibbs if (!ds->ds_is_snapshot) 51be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 523b2aab18SMatthew Ahrens 533b2aab18SMatthew Ahrens if (dsl_dataset_long_held(ds)) 54be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 553b2aab18SMatthew Ahrens 563b2aab18SMatthew Ahrens /* 573b2aab18SMatthew Ahrens * Only allow deferred destroy on pools that support it. 583b2aab18SMatthew Ahrens * NOTE: deferred destroy is only supported on snapshots. 593b2aab18SMatthew Ahrens */ 603b2aab18SMatthew Ahrens if (defer) { 613b2aab18SMatthew Ahrens if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 623b2aab18SMatthew Ahrens SPA_VERSION_USERREFS) 63be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 643b2aab18SMatthew Ahrens return (0); 653b2aab18SMatthew Ahrens } 663b2aab18SMatthew Ahrens 673b2aab18SMatthew Ahrens /* 683b2aab18SMatthew Ahrens * If this snapshot has an elevated user reference count, 693b2aab18SMatthew Ahrens * we can't destroy it yet. 703b2aab18SMatthew Ahrens */ 713b2aab18SMatthew Ahrens if (ds->ds_userrefs > 0) 72be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 733b2aab18SMatthew Ahrens 743b2aab18SMatthew Ahrens /* 753b2aab18SMatthew Ahrens * Can't delete a branch point. 763b2aab18SMatthew Ahrens */ 77c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_num_children > 1) 78be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 793b2aab18SMatthew Ahrens 803b2aab18SMatthew Ahrens return (0); 813b2aab18SMatthew Ahrens } 823b2aab18SMatthew Ahrens 83dfc11533SChris Williamson int 843b2aab18SMatthew Ahrens dsl_destroy_snapshot_check(void *arg, dmu_tx_t *tx) 853b2aab18SMatthew Ahrens { 86dfc11533SChris Williamson dsl_destroy_snapshot_arg_t *ddsa = arg; 87dfc11533SChris Williamson const char *dsname = ddsa->ddsa_name; 88dfc11533SChris Williamson boolean_t defer = ddsa->ddsa_defer; 89dfc11533SChris Williamson 903b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 913b2aab18SMatthew Ahrens int error = 0; 92dfc11533SChris Williamson dsl_dataset_t *ds; 933b2aab18SMatthew Ahrens 94dfc11533SChris Williamson error = dsl_dataset_hold(dp, dsname, FTAG, &ds); 953b2aab18SMatthew Ahrens 96dfc11533SChris Williamson /* 97dfc11533SChris Williamson * If the snapshot does not exist, silently ignore it, and 98dfc11533SChris Williamson * dsl_destroy_snapshot_sync() will be a no-op 99dfc11533SChris Williamson * (it's "already destroyed"). 100dfc11533SChris Williamson */ 101dfc11533SChris Williamson if (error == ENOENT) 102dfc11533SChris Williamson return (0); 1033b2aab18SMatthew Ahrens 104dfc11533SChris Williamson if (error == 0) { 105dfc11533SChris Williamson error = dsl_destroy_snapshot_check_impl(ds, defer); 106dfc11533SChris Williamson dsl_dataset_rele(ds, FTAG); 1073b2aab18SMatthew Ahrens } 1083b2aab18SMatthew Ahrens 109dfc11533SChris Williamson return (error); 1103b2aab18SMatthew Ahrens } 1113b2aab18SMatthew Ahrens 1123b2aab18SMatthew Ahrens struct process_old_arg { 1133b2aab18SMatthew Ahrens dsl_dataset_t *ds; 1143b2aab18SMatthew Ahrens dsl_dataset_t *ds_prev; 1153b2aab18SMatthew Ahrens boolean_t after_branch_point; 1163b2aab18SMatthew Ahrens zio_t *pio; 1173b2aab18SMatthew Ahrens uint64_t used, comp, uncomp; 1183b2aab18SMatthew Ahrens }; 1193b2aab18SMatthew Ahrens 1203b2aab18SMatthew Ahrens static int 1213b2aab18SMatthew Ahrens process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx) 1223b2aab18SMatthew Ahrens { 1233b2aab18SMatthew Ahrens struct process_old_arg *poa = arg; 1243b2aab18SMatthew Ahrens dsl_pool_t *dp = poa->ds->ds_dir->dd_pool; 1253b2aab18SMatthew Ahrens 12643466aaeSMax Grossman ASSERT(!BP_IS_HOLE(bp)); 12743466aaeSMax Grossman 128c1379625SJustin T. Gibbs if (bp->blk_birth <= dsl_dataset_phys(poa->ds)->ds_prev_snap_txg) { 1293b2aab18SMatthew Ahrens dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx); 1303b2aab18SMatthew Ahrens if (poa->ds_prev && !poa->after_branch_point && 1313b2aab18SMatthew Ahrens bp->blk_birth > 132c1379625SJustin T. Gibbs dsl_dataset_phys(poa->ds_prev)->ds_prev_snap_txg) { 133c1379625SJustin T. Gibbs dsl_dataset_phys(poa->ds_prev)->ds_unique_bytes += 1343b2aab18SMatthew Ahrens bp_get_dsize_sync(dp->dp_spa, bp); 1353b2aab18SMatthew Ahrens } 1363b2aab18SMatthew Ahrens } else { 1373b2aab18SMatthew Ahrens poa->used += bp_get_dsize_sync(dp->dp_spa, bp); 1383b2aab18SMatthew Ahrens poa->comp += BP_GET_PSIZE(bp); 1393b2aab18SMatthew Ahrens poa->uncomp += BP_GET_UCSIZE(bp); 1403b2aab18SMatthew Ahrens dsl_free_sync(poa->pio, dp, tx->tx_txg, bp); 1413b2aab18SMatthew Ahrens } 1423b2aab18SMatthew Ahrens return (0); 1433b2aab18SMatthew Ahrens } 1443b2aab18SMatthew Ahrens 1453b2aab18SMatthew Ahrens static void 1463b2aab18SMatthew Ahrens process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev, 1473b2aab18SMatthew Ahrens dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx) 1483b2aab18SMatthew Ahrens { 1493b2aab18SMatthew Ahrens struct process_old_arg poa = { 0 }; 1503b2aab18SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 1513b2aab18SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 1523b2aab18SMatthew Ahrens uint64_t deadlist_obj; 1533b2aab18SMatthew Ahrens 1543b2aab18SMatthew Ahrens ASSERT(ds->ds_deadlist.dl_oldfmt); 1553b2aab18SMatthew Ahrens ASSERT(ds_next->ds_deadlist.dl_oldfmt); 1563b2aab18SMatthew Ahrens 1573b2aab18SMatthew Ahrens poa.ds = ds; 1583b2aab18SMatthew Ahrens poa.ds_prev = ds_prev; 1593b2aab18SMatthew Ahrens poa.after_branch_point = after_branch_point; 1603b2aab18SMatthew Ahrens poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1613b2aab18SMatthew Ahrens VERIFY0(bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj, 1623b2aab18SMatthew Ahrens process_old_cb, &poa, tx)); 1633b2aab18SMatthew Ahrens VERIFY0(zio_wait(poa.pio)); 164c1379625SJustin T. Gibbs ASSERT3U(poa.used, ==, dsl_dataset_phys(ds)->ds_unique_bytes); 1653b2aab18SMatthew Ahrens 1663b2aab18SMatthew Ahrens /* change snapused */ 1673b2aab18SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 1683b2aab18SMatthew Ahrens -poa.used, -poa.comp, -poa.uncomp, tx); 1693b2aab18SMatthew Ahrens 1703b2aab18SMatthew Ahrens /* swap next's deadlist to our deadlist */ 1713b2aab18SMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1723b2aab18SMatthew Ahrens dsl_deadlist_close(&ds_next->ds_deadlist); 173c1379625SJustin T. Gibbs deadlist_obj = dsl_dataset_phys(ds)->ds_deadlist_obj; 174c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj = 175c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_deadlist_obj; 176c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_deadlist_obj = deadlist_obj; 177c1379625SJustin T. Gibbs dsl_deadlist_open(&ds->ds_deadlist, mos, 178c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj); 1793b2aab18SMatthew Ahrens dsl_deadlist_open(&ds_next->ds_deadlist, mos, 180c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_deadlist_obj); 1813b2aab18SMatthew Ahrens } 1823b2aab18SMatthew Ahrens 1833b2aab18SMatthew Ahrens static void 1843b2aab18SMatthew Ahrens dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx) 1853b2aab18SMatthew Ahrens { 1863b2aab18SMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1873b2aab18SMatthew Ahrens zap_cursor_t zc; 1883b2aab18SMatthew Ahrens zap_attribute_t za; 1893b2aab18SMatthew Ahrens 1903b2aab18SMatthew Ahrens /* 1913b2aab18SMatthew Ahrens * If it is the old version, dd_clones doesn't exist so we can't 1923b2aab18SMatthew Ahrens * find the clones, but dsl_deadlist_remove_key() is a no-op so it 1933b2aab18SMatthew Ahrens * doesn't matter. 1943b2aab18SMatthew Ahrens */ 195c1379625SJustin T. Gibbs if (dsl_dir_phys(ds->ds_dir)->dd_clones == 0) 1963b2aab18SMatthew Ahrens return; 1973b2aab18SMatthew Ahrens 198c1379625SJustin T. Gibbs for (zap_cursor_init(&zc, mos, dsl_dir_phys(ds->ds_dir)->dd_clones); 1993b2aab18SMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 2003b2aab18SMatthew Ahrens zap_cursor_advance(&zc)) { 2013b2aab18SMatthew Ahrens dsl_dataset_t *clone; 2023b2aab18SMatthew Ahrens 2033b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 2043b2aab18SMatthew Ahrens za.za_first_integer, FTAG, &clone)); 2053b2aab18SMatthew Ahrens if (clone->ds_dir->dd_origin_txg > mintxg) { 2063b2aab18SMatthew Ahrens dsl_deadlist_remove_key(&clone->ds_deadlist, 2073b2aab18SMatthew Ahrens mintxg, tx); 2085cabbc6bSPrashanth Sreenivasa if (dsl_dataset_remap_deadlist_exists(clone)) { 2095cabbc6bSPrashanth Sreenivasa dsl_deadlist_remove_key( 2105cabbc6bSPrashanth Sreenivasa &clone->ds_remap_deadlist, mintxg, tx); 2115cabbc6bSPrashanth Sreenivasa } 2123b2aab18SMatthew Ahrens dsl_dataset_remove_clones_key(clone, mintxg, tx); 2133b2aab18SMatthew Ahrens } 2143b2aab18SMatthew Ahrens dsl_dataset_rele(clone, FTAG); 2153b2aab18SMatthew Ahrens } 2163b2aab18SMatthew Ahrens zap_cursor_fini(&zc); 2173b2aab18SMatthew Ahrens } 2183b2aab18SMatthew Ahrens 2195cabbc6bSPrashanth Sreenivasa static void 2205cabbc6bSPrashanth Sreenivasa dsl_destroy_snapshot_handle_remaps(dsl_dataset_t *ds, dsl_dataset_t *ds_next, 2215cabbc6bSPrashanth Sreenivasa dmu_tx_t *tx) 2225cabbc6bSPrashanth Sreenivasa { 2235cabbc6bSPrashanth Sreenivasa dsl_pool_t *dp = ds->ds_dir->dd_pool; 2245cabbc6bSPrashanth Sreenivasa 2255cabbc6bSPrashanth Sreenivasa /* Move blocks to be obsoleted to pool's obsolete list. */ 2265cabbc6bSPrashanth Sreenivasa if (dsl_dataset_remap_deadlist_exists(ds_next)) { 2275cabbc6bSPrashanth Sreenivasa if (!bpobj_is_open(&dp->dp_obsolete_bpobj)) 2285cabbc6bSPrashanth Sreenivasa dsl_pool_create_obsolete_bpobj(dp, tx); 2295cabbc6bSPrashanth Sreenivasa 2305cabbc6bSPrashanth Sreenivasa dsl_deadlist_move_bpobj(&ds_next->ds_remap_deadlist, 2315cabbc6bSPrashanth Sreenivasa &dp->dp_obsolete_bpobj, 2325cabbc6bSPrashanth Sreenivasa dsl_dataset_phys(ds)->ds_prev_snap_txg, tx); 2335cabbc6bSPrashanth Sreenivasa } 2345cabbc6bSPrashanth Sreenivasa 2355cabbc6bSPrashanth Sreenivasa /* Merge our deadlist into next's and free it. */ 2365cabbc6bSPrashanth Sreenivasa if (dsl_dataset_remap_deadlist_exists(ds)) { 2375cabbc6bSPrashanth Sreenivasa uint64_t remap_deadlist_object = 2385cabbc6bSPrashanth Sreenivasa dsl_dataset_get_remap_deadlist_object(ds); 2395cabbc6bSPrashanth Sreenivasa ASSERT(remap_deadlist_object != 0); 2405cabbc6bSPrashanth Sreenivasa 2415cabbc6bSPrashanth Sreenivasa mutex_enter(&ds_next->ds_remap_deadlist_lock); 2425cabbc6bSPrashanth Sreenivasa if (!dsl_dataset_remap_deadlist_exists(ds_next)) 2435cabbc6bSPrashanth Sreenivasa dsl_dataset_create_remap_deadlist(ds_next, tx); 2445cabbc6bSPrashanth Sreenivasa mutex_exit(&ds_next->ds_remap_deadlist_lock); 2455cabbc6bSPrashanth Sreenivasa 2465cabbc6bSPrashanth Sreenivasa dsl_deadlist_merge(&ds_next->ds_remap_deadlist, 2475cabbc6bSPrashanth Sreenivasa remap_deadlist_object, tx); 2485cabbc6bSPrashanth Sreenivasa dsl_dataset_destroy_remap_deadlist(ds, tx); 2495cabbc6bSPrashanth Sreenivasa } 2505cabbc6bSPrashanth Sreenivasa } 2515cabbc6bSPrashanth Sreenivasa 2523b2aab18SMatthew Ahrens void 2533b2aab18SMatthew Ahrens dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx) 2543b2aab18SMatthew Ahrens { 2553b2aab18SMatthew Ahrens int err; 2563b2aab18SMatthew Ahrens int after_branch_point = FALSE; 2573b2aab18SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 2583b2aab18SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 2593b2aab18SMatthew Ahrens dsl_dataset_t *ds_prev = NULL; 2603b2aab18SMatthew Ahrens uint64_t obj; 2613b2aab18SMatthew Ahrens 2623b2aab18SMatthew Ahrens ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); 263c166b69dSPaul Dagnelie rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); 264c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg); 265c166b69dSPaul Dagnelie rrw_exit(&ds->ds_bp_rwlock, FTAG); 266e914ace2STim Schumacher ASSERT(zfs_refcount_is_zero(&ds->ds_longholds)); 2673b2aab18SMatthew Ahrens 2683b2aab18SMatthew Ahrens if (defer && 269c1379625SJustin T. Gibbs (ds->ds_userrefs > 0 || 270c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_num_children > 1)) { 2713b2aab18SMatthew Ahrens ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 2723b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 273c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_DEFER_DESTROY; 2743b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "defer_destroy", tx, ""); 2753b2aab18SMatthew Ahrens return; 2763b2aab18SMatthew Ahrens } 2773b2aab18SMatthew Ahrens 278c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1); 2793b2aab18SMatthew Ahrens 2803b2aab18SMatthew Ahrens /* We need to log before removing it from the namespace. */ 2813b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "destroy", tx, ""); 2823b2aab18SMatthew Ahrens 2833b2aab18SMatthew Ahrens dsl_scan_ds_destroyed(ds, tx); 2843b2aab18SMatthew Ahrens 2853b2aab18SMatthew Ahrens obj = ds->ds_object; 2863b2aab18SMatthew Ahrens 287ca0cc391SMatthew Ahrens for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { 288ca0cc391SMatthew Ahrens if (ds->ds_feature_inuse[f]) { 289ca0cc391SMatthew Ahrens dsl_dataset_deactivate_feature(obj, f, tx); 290ca0cc391SMatthew Ahrens ds->ds_feature_inuse[f] = B_FALSE; 291ca0cc391SMatthew Ahrens } 292b5152584SMatthew Ahrens } 293c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { 2943b2aab18SMatthew Ahrens ASSERT3P(ds->ds_prev, ==, NULL); 2953b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 296c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &ds_prev)); 2973b2aab18SMatthew Ahrens after_branch_point = 298c1379625SJustin T. Gibbs (dsl_dataset_phys(ds_prev)->ds_next_snap_obj != obj); 2993b2aab18SMatthew Ahrens 3003b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 3013b2aab18SMatthew Ahrens if (after_branch_point && 302c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)->ds_next_clones_obj != 0) { 3033b2aab18SMatthew Ahrens dsl_dataset_remove_from_next_clones(ds_prev, obj, tx); 304c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) { 3053b2aab18SMatthew Ahrens VERIFY0(zap_add_int(mos, 306c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)-> 307c1379625SJustin T. Gibbs ds_next_clones_obj, 308c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_snap_obj, 309c1379625SJustin T. Gibbs tx)); 3103b2aab18SMatthew Ahrens } 3113b2aab18SMatthew Ahrens } 3123b2aab18SMatthew Ahrens if (!after_branch_point) { 313c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)->ds_next_snap_obj = 314c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_snap_obj; 3153b2aab18SMatthew Ahrens } 3163b2aab18SMatthew Ahrens } 3173b2aab18SMatthew Ahrens 3183b2aab18SMatthew Ahrens dsl_dataset_t *ds_next; 3193b2aab18SMatthew Ahrens uint64_t old_unique; 3203b2aab18SMatthew Ahrens uint64_t used = 0, comp = 0, uncomp = 0; 3213b2aab18SMatthew Ahrens 3223b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 323c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_snap_obj, FTAG, &ds_next)); 324c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds_next)->ds_prev_snap_obj, ==, obj); 3253b2aab18SMatthew Ahrens 326c1379625SJustin T. Gibbs old_unique = dsl_dataset_phys(ds_next)->ds_unique_bytes; 3273b2aab18SMatthew Ahrens 3283b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 329c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_prev_snap_obj = 330c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_obj; 331c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_prev_snap_txg = 332c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg; 333c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, ==, 334c1379625SJustin T. Gibbs ds_prev ? dsl_dataset_phys(ds_prev)->ds_creation_txg : 0); 3353b2aab18SMatthew Ahrens 3363b2aab18SMatthew Ahrens if (ds_next->ds_deadlist.dl_oldfmt) { 3373b2aab18SMatthew Ahrens process_old_deadlist(ds, ds_prev, ds_next, 3383b2aab18SMatthew Ahrens after_branch_point, tx); 3393b2aab18SMatthew Ahrens } else { 3403b2aab18SMatthew Ahrens /* Adjust prev's unique space. */ 3413b2aab18SMatthew Ahrens if (ds_prev && !after_branch_point) { 3423b2aab18SMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 343c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)->ds_prev_snap_txg, 344c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, 3453b2aab18SMatthew Ahrens &used, &comp, &uncomp); 346c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)->ds_unique_bytes += used; 3473b2aab18SMatthew Ahrens } 3483b2aab18SMatthew Ahrens 3493b2aab18SMatthew Ahrens /* Adjust snapused. */ 3503b2aab18SMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 351c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, UINT64_MAX, 3523b2aab18SMatthew Ahrens &used, &comp, &uncomp); 3533b2aab18SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 3543b2aab18SMatthew Ahrens -used, -comp, -uncomp, tx); 3553b2aab18SMatthew Ahrens 3563b2aab18SMatthew Ahrens /* Move blocks to be freed to pool's free list. */ 3573b2aab18SMatthew Ahrens dsl_deadlist_move_bpobj(&ds_next->ds_deadlist, 358c1379625SJustin T. Gibbs &dp->dp_free_bpobj, dsl_dataset_phys(ds)->ds_prev_snap_txg, 3593b2aab18SMatthew Ahrens tx); 3603b2aab18SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, 3613b2aab18SMatthew Ahrens DD_USED_HEAD, used, comp, uncomp, tx); 3623b2aab18SMatthew Ahrens 3633b2aab18SMatthew Ahrens /* Merge our deadlist into next's and free it. */ 3643b2aab18SMatthew Ahrens dsl_deadlist_merge(&ds_next->ds_deadlist, 365c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 3663b2aab18SMatthew Ahrens } 3675cabbc6bSPrashanth Sreenivasa 3683b2aab18SMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 369c1379625SJustin T. Gibbs dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 3703b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 371c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj = 0; 3723b2aab18SMatthew Ahrens 3735cabbc6bSPrashanth Sreenivasa dsl_destroy_snapshot_handle_remaps(ds, ds_next, tx); 3745cabbc6bSPrashanth Sreenivasa 3753b2aab18SMatthew Ahrens /* Collapse range in clone heads */ 3763b2aab18SMatthew Ahrens dsl_dataset_remove_clones_key(ds, 377c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_creation_txg, tx); 3783b2aab18SMatthew Ahrens 379bc9014e6SJustin Gibbs if (ds_next->ds_is_snapshot) { 3803b2aab18SMatthew Ahrens dsl_dataset_t *ds_nextnext; 3813b2aab18SMatthew Ahrens 3823b2aab18SMatthew Ahrens /* 3833b2aab18SMatthew Ahrens * Update next's unique to include blocks which 3843b2aab18SMatthew Ahrens * were previously shared by only this snapshot 3853b2aab18SMatthew Ahrens * and it. Those blocks will be born after the 3863b2aab18SMatthew Ahrens * prev snap and before this snap, and will have 3873b2aab18SMatthew Ahrens * died after the next snap and before the one 3883b2aab18SMatthew Ahrens * after that (ie. be on the snap after next's 3893b2aab18SMatthew Ahrens * deadlist). 3903b2aab18SMatthew Ahrens */ 3913b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 392c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_next_snap_obj, 393c1379625SJustin T. Gibbs FTAG, &ds_nextnext)); 3943b2aab18SMatthew Ahrens dsl_deadlist_space_range(&ds_nextnext->ds_deadlist, 395c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, 396c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_creation_txg, 3973b2aab18SMatthew Ahrens &used, &comp, &uncomp); 398c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_unique_bytes += used; 3993b2aab18SMatthew Ahrens dsl_dataset_rele(ds_nextnext, FTAG); 4003b2aab18SMatthew Ahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 4013b2aab18SMatthew Ahrens 4023b2aab18SMatthew Ahrens /* Collapse range in this head. */ 4033b2aab18SMatthew Ahrens dsl_dataset_t *hds; 4043b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 405c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &hds)); 4063b2aab18SMatthew Ahrens dsl_deadlist_remove_key(&hds->ds_deadlist, 407c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_creation_txg, tx); 4085cabbc6bSPrashanth Sreenivasa if (dsl_dataset_remap_deadlist_exists(hds)) { 4095cabbc6bSPrashanth Sreenivasa dsl_deadlist_remove_key(&hds->ds_remap_deadlist, 4105cabbc6bSPrashanth Sreenivasa dsl_dataset_phys(ds)->ds_creation_txg, tx); 4115cabbc6bSPrashanth Sreenivasa } 4123b2aab18SMatthew Ahrens dsl_dataset_rele(hds, FTAG); 4133b2aab18SMatthew Ahrens 4143b2aab18SMatthew Ahrens } else { 4153b2aab18SMatthew Ahrens ASSERT3P(ds_next->ds_prev, ==, ds); 4163b2aab18SMatthew Ahrens dsl_dataset_rele(ds_next->ds_prev, ds_next); 4173b2aab18SMatthew Ahrens ds_next->ds_prev = NULL; 4183b2aab18SMatthew Ahrens if (ds_prev) { 4193b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 420c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_obj, 4213b2aab18SMatthew Ahrens ds_next, &ds_next->ds_prev)); 4223b2aab18SMatthew Ahrens } 4233b2aab18SMatthew Ahrens 4243b2aab18SMatthew Ahrens dsl_dataset_recalc_head_uniq(ds_next); 4253b2aab18SMatthew Ahrens 4263b2aab18SMatthew Ahrens /* 4273b2aab18SMatthew Ahrens * Reduce the amount of our unconsumed refreservation 4283b2aab18SMatthew Ahrens * being charged to our parent by the amount of 4293b2aab18SMatthew Ahrens * new unique data we have gained. 4303b2aab18SMatthew Ahrens */ 4313b2aab18SMatthew Ahrens if (old_unique < ds_next->ds_reserved) { 4323b2aab18SMatthew Ahrens int64_t mrsdelta; 4333b2aab18SMatthew Ahrens uint64_t new_unique = 434c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_unique_bytes; 4353b2aab18SMatthew Ahrens 4363b2aab18SMatthew Ahrens ASSERT(old_unique <= new_unique); 4373b2aab18SMatthew Ahrens mrsdelta = MIN(new_unique - old_unique, 4383b2aab18SMatthew Ahrens ds_next->ds_reserved - old_unique); 4393b2aab18SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 4403b2aab18SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 4413b2aab18SMatthew Ahrens } 4423b2aab18SMatthew Ahrens } 4433b2aab18SMatthew Ahrens dsl_dataset_rele(ds_next, FTAG); 4443b2aab18SMatthew Ahrens 4453b2aab18SMatthew Ahrens /* 4463b2aab18SMatthew Ahrens * This must be done after the dsl_traverse(), because it will 4473b2aab18SMatthew Ahrens * re-open the objset. 4483b2aab18SMatthew Ahrens */ 4493b2aab18SMatthew Ahrens if (ds->ds_objset) { 4503b2aab18SMatthew Ahrens dmu_objset_evict(ds->ds_objset); 4513b2aab18SMatthew Ahrens ds->ds_objset = NULL; 4523b2aab18SMatthew Ahrens } 4533b2aab18SMatthew Ahrens 4543b2aab18SMatthew Ahrens /* remove from snapshot namespace */ 4553b2aab18SMatthew Ahrens dsl_dataset_t *ds_head; 456c1379625SJustin T. Gibbs ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj == 0); 4573b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 458c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &ds_head)); 4593b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_get_snapname(ds)); 4603b2aab18SMatthew Ahrens #ifdef ZFS_DEBUG 4613b2aab18SMatthew Ahrens { 4623b2aab18SMatthew Ahrens uint64_t val; 4633b2aab18SMatthew Ahrens 4643b2aab18SMatthew Ahrens err = dsl_dataset_snap_lookup(ds_head, 4653b2aab18SMatthew Ahrens ds->ds_snapname, &val); 4663b2aab18SMatthew Ahrens ASSERT0(err); 4673b2aab18SMatthew Ahrens ASSERT3U(val, ==, obj); 4683b2aab18SMatthew Ahrens } 4693b2aab18SMatthew Ahrens #endif 470a2afb611SJerry Jelinek VERIFY0(dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx, B_TRUE)); 4713b2aab18SMatthew Ahrens dsl_dataset_rele(ds_head, FTAG); 4723b2aab18SMatthew Ahrens 4733b2aab18SMatthew Ahrens if (ds_prev != NULL) 4743b2aab18SMatthew Ahrens dsl_dataset_rele(ds_prev, FTAG); 4753b2aab18SMatthew Ahrens 4763b2aab18SMatthew Ahrens spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 4773b2aab18SMatthew Ahrens 478c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_next_clones_obj != 0) { 4793b2aab18SMatthew Ahrens uint64_t count; 4803b2aab18SMatthew Ahrens ASSERT0(zap_count(mos, 481c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_clones_obj, &count) && 482c1379625SJustin T. Gibbs count == 0); 4833b2aab18SMatthew Ahrens VERIFY0(dmu_object_free(mos, 484c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_clones_obj, tx)); 4853b2aab18SMatthew Ahrens } 486c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_props_obj != 0) 487c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_props_obj, 488c1379625SJustin T. Gibbs tx)); 489c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_userrefs_obj != 0) 490c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_userrefs_obj, 491c1379625SJustin T. Gibbs tx)); 4923b2aab18SMatthew Ahrens dsl_dir_rele(ds->ds_dir, ds); 4933b2aab18SMatthew Ahrens ds->ds_dir = NULL; 4942acef22dSMatthew Ahrens dmu_object_free_zapified(mos, obj, tx); 4953b2aab18SMatthew Ahrens } 4963b2aab18SMatthew Ahrens 497dfc11533SChris Williamson void 4983b2aab18SMatthew Ahrens dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx) 4993b2aab18SMatthew Ahrens { 500dfc11533SChris Williamson dsl_destroy_snapshot_arg_t *ddsa = arg; 501dfc11533SChris Williamson const char *dsname = ddsa->ddsa_name; 502dfc11533SChris Williamson boolean_t defer = ddsa->ddsa_defer; 5033b2aab18SMatthew Ahrens 504dfc11533SChris Williamson dsl_pool_t *dp = dmu_tx_pool(tx); 505dfc11533SChris Williamson dsl_dataset_t *ds; 5063b2aab18SMatthew Ahrens 507dfc11533SChris Williamson int error = dsl_dataset_hold(dp, dsname, FTAG, &ds); 508dfc11533SChris Williamson if (error == ENOENT) 509dfc11533SChris Williamson return; 510dfc11533SChris Williamson ASSERT0(error); 511dfc11533SChris Williamson dsl_destroy_snapshot_sync_impl(ds, defer, tx); 512dfc11533SChris Williamson dsl_dataset_rele(ds, FTAG); 5133b2aab18SMatthew Ahrens } 5143b2aab18SMatthew Ahrens 5153b2aab18SMatthew Ahrens /* 5163b2aab18SMatthew Ahrens * The semantics of this function are described in the comment above 5173b2aab18SMatthew Ahrens * lzc_destroy_snaps(). To summarize: 5183b2aab18SMatthew Ahrens * 5193b2aab18SMatthew Ahrens * The snapshots must all be in the same pool. 5203b2aab18SMatthew Ahrens * 5213b2aab18SMatthew Ahrens * Snapshots that don't exist will be silently ignored (considered to be 5223b2aab18SMatthew Ahrens * "already deleted"). 5233b2aab18SMatthew Ahrens * 5243b2aab18SMatthew Ahrens * On success, all snaps will be destroyed and this will return 0. 5253b2aab18SMatthew Ahrens * On failure, no snaps will be destroyed, the errlist will be filled in, 5263b2aab18SMatthew Ahrens * and this will return an errno. 5273b2aab18SMatthew Ahrens */ 5283b2aab18SMatthew Ahrens int 5293b2aab18SMatthew Ahrens dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer, 5303b2aab18SMatthew Ahrens nvlist_t *errlist) 5313b2aab18SMatthew Ahrens { 532dfc11533SChris Williamson if (nvlist_next_nvpair(snaps, NULL) == NULL) 5333b2aab18SMatthew Ahrens return (0); 5343b2aab18SMatthew Ahrens 535dfc11533SChris Williamson /* 536dfc11533SChris Williamson * lzc_destroy_snaps() is documented to take an nvlist whose 537ed992b0aSSerapheim Dimitropoulos * values "don't matter". We need to convert that nvlist to 538ed992b0aSSerapheim Dimitropoulos * one that we know can be converted to LUA. We also don't 539ed992b0aSSerapheim Dimitropoulos * care about any duplicate entries because the nvlist will 540ed992b0aSSerapheim Dimitropoulos * be converted to a LUA table which should take care of this. 541dfc11533SChris Williamson */ 542ed992b0aSSerapheim Dimitropoulos nvlist_t *snaps_normalized; 543ed992b0aSSerapheim Dimitropoulos VERIFY0(nvlist_alloc(&snaps_normalized, 0, KM_SLEEP)); 544dfc11533SChris Williamson for (nvpair_t *pair = nvlist_next_nvpair(snaps, NULL); 545dfc11533SChris Williamson pair != NULL; pair = nvlist_next_nvpair(snaps, pair)) { 546dfc11533SChris Williamson fnvlist_add_boolean_value(snaps_normalized, 547dfc11533SChris Williamson nvpair_name(pair), B_TRUE); 548dfc11533SChris Williamson } 549ed992b0aSSerapheim Dimitropoulos 550ed992b0aSSerapheim Dimitropoulos nvlist_t *arg; 551ed992b0aSSerapheim Dimitropoulos VERIFY0(nvlist_alloc(&arg, 0, KM_SLEEP)); 552dfc11533SChris Williamson fnvlist_add_nvlist(arg, "snaps", snaps_normalized); 553e6ab4525SMatthew Ahrens fnvlist_free(snaps_normalized); 554dfc11533SChris Williamson fnvlist_add_boolean_value(arg, "defer", defer); 555dfc11533SChris Williamson 556ed992b0aSSerapheim Dimitropoulos nvlist_t *wrapper; 557ed992b0aSSerapheim Dimitropoulos VERIFY0(nvlist_alloc(&wrapper, 0, KM_SLEEP)); 558dfc11533SChris Williamson fnvlist_add_nvlist(wrapper, ZCP_ARG_ARGLIST, arg); 559dfc11533SChris Williamson fnvlist_free(arg); 560dfc11533SChris Williamson 561dfc11533SChris Williamson const char *program = 562dfc11533SChris Williamson "arg = ...\n" 563dfc11533SChris Williamson "snaps = arg['snaps']\n" 564dfc11533SChris Williamson "defer = arg['defer']\n" 565dfc11533SChris Williamson "errors = { }\n" 566dfc11533SChris Williamson "has_errors = false\n" 567dfc11533SChris Williamson "for snap, v in pairs(snaps) do\n" 568dfc11533SChris Williamson " errno = zfs.check.destroy{snap, defer=defer}\n" 569dfc11533SChris Williamson " zfs.debug('snap: ' .. snap .. ' errno: ' .. errno)\n" 570dfc11533SChris Williamson " if errno == ENOENT then\n" 571dfc11533SChris Williamson " snaps[snap] = nil\n" 572dfc11533SChris Williamson " elseif errno ~= 0 then\n" 573dfc11533SChris Williamson " errors[snap] = errno\n" 574dfc11533SChris Williamson " has_errors = true\n" 575dfc11533SChris Williamson " end\n" 576dfc11533SChris Williamson "end\n" 577dfc11533SChris Williamson "if has_errors then\n" 578dfc11533SChris Williamson " return errors\n" 579dfc11533SChris Williamson "end\n" 580dfc11533SChris Williamson "for snap, v in pairs(snaps) do\n" 581dfc11533SChris Williamson " errno = zfs.sync.destroy{snap, defer=defer}\n" 582dfc11533SChris Williamson " assert(errno == 0)\n" 583dfc11533SChris Williamson "end\n" 584dfc11533SChris Williamson "return { }\n"; 585dfc11533SChris Williamson 586dfc11533SChris Williamson nvlist_t *result = fnvlist_alloc(); 587dfc11533SChris Williamson int error = zcp_eval(nvpair_name(nvlist_next_nvpair(snaps, NULL)), 588dfc11533SChris Williamson program, 589a3b28680SSerapheim Dimitropoulos B_TRUE, 590dfc11533SChris Williamson 0, 591dfc11533SChris Williamson zfs_lua_max_memlimit, 592ed992b0aSSerapheim Dimitropoulos nvlist_next_nvpair(wrapper, NULL), result); 593dfc11533SChris Williamson if (error != 0) { 594dfc11533SChris Williamson char *errorstr = NULL; 595dfc11533SChris Williamson (void) nvlist_lookup_string(result, ZCP_RET_ERROR, &errorstr); 596dfc11533SChris Williamson if (errorstr != NULL) { 597dfc11533SChris Williamson zfs_dbgmsg(errorstr); 598dfc11533SChris Williamson } 599dfc11533SChris Williamson return (error); 600dfc11533SChris Williamson } 601dfc11533SChris Williamson fnvlist_free(wrapper); 6023b2aab18SMatthew Ahrens 603dfc11533SChris Williamson /* 604dfc11533SChris Williamson * lzc_destroy_snaps() is documented to fill the errlist with 605dfc11533SChris Williamson * int32 values, so we need to covert the int64 values that are 606dfc11533SChris Williamson * returned from LUA. 607dfc11533SChris Williamson */ 608dfc11533SChris Williamson int rv = 0; 609dfc11533SChris Williamson nvlist_t *errlist_raw = fnvlist_lookup_nvlist(result, ZCP_RET_RETURN); 610dfc11533SChris Williamson for (nvpair_t *pair = nvlist_next_nvpair(errlist_raw, NULL); 611dfc11533SChris Williamson pair != NULL; pair = nvlist_next_nvpair(errlist_raw, pair)) { 612dfc11533SChris Williamson int32_t val = (int32_t)fnvpair_value_int64(pair); 613dfc11533SChris Williamson if (rv == 0) 614dfc11533SChris Williamson rv = val; 615dfc11533SChris Williamson fnvlist_add_int32(errlist, nvpair_name(pair), val); 616dfc11533SChris Williamson } 617dfc11533SChris Williamson fnvlist_free(result); 618dfc11533SChris Williamson return (rv); 6193b2aab18SMatthew Ahrens } 6203b2aab18SMatthew Ahrens 6213b2aab18SMatthew Ahrens int 6223b2aab18SMatthew Ahrens dsl_destroy_snapshot(const char *name, boolean_t defer) 6233b2aab18SMatthew Ahrens { 6243b2aab18SMatthew Ahrens int error; 6253b2aab18SMatthew Ahrens nvlist_t *nvl = fnvlist_alloc(); 6263b2aab18SMatthew Ahrens nvlist_t *errlist = fnvlist_alloc(); 6273b2aab18SMatthew Ahrens 6283b2aab18SMatthew Ahrens fnvlist_add_boolean(nvl, name); 6293b2aab18SMatthew Ahrens error = dsl_destroy_snapshots_nvl(nvl, defer, errlist); 6303b2aab18SMatthew Ahrens fnvlist_free(errlist); 6313b2aab18SMatthew Ahrens fnvlist_free(nvl); 6323b2aab18SMatthew Ahrens return (error); 6333b2aab18SMatthew Ahrens } 6343b2aab18SMatthew Ahrens 6353b2aab18SMatthew Ahrens struct killarg { 6363b2aab18SMatthew Ahrens dsl_dataset_t *ds; 6373b2aab18SMatthew Ahrens dmu_tx_t *tx; 6383b2aab18SMatthew Ahrens }; 6393b2aab18SMatthew Ahrens 6403b2aab18SMatthew Ahrens /* ARGSUSED */ 6413b2aab18SMatthew Ahrens static int 6423b2aab18SMatthew Ahrens kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 6437802d7bfSMatthew Ahrens const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) 6443b2aab18SMatthew Ahrens { 6453b2aab18SMatthew Ahrens struct killarg *ka = arg; 6463b2aab18SMatthew Ahrens dmu_tx_t *tx = ka->tx; 6473b2aab18SMatthew Ahrens 648a2cdcdd2SPaul Dagnelie if (bp == NULL || BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp)) 6493b2aab18SMatthew Ahrens return (0); 6503b2aab18SMatthew Ahrens 6513b2aab18SMatthew Ahrens if (zb->zb_level == ZB_ZIL_LEVEL) { 6523b2aab18SMatthew Ahrens ASSERT(zilog != NULL); 6533b2aab18SMatthew Ahrens /* 6543b2aab18SMatthew Ahrens * It's a block in the intent log. It has no 6553b2aab18SMatthew Ahrens * accounting, so just free it. 6563b2aab18SMatthew Ahrens */ 6573b2aab18SMatthew Ahrens dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp); 6583b2aab18SMatthew Ahrens } else { 6593b2aab18SMatthew Ahrens ASSERT(zilog == NULL); 660c1379625SJustin T. Gibbs ASSERT3U(bp->blk_birth, >, 661c1379625SJustin T. Gibbs dsl_dataset_phys(ka->ds)->ds_prev_snap_txg); 6623b2aab18SMatthew Ahrens (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE); 6633b2aab18SMatthew Ahrens } 6643b2aab18SMatthew Ahrens 6653b2aab18SMatthew Ahrens return (0); 6663b2aab18SMatthew Ahrens } 6673b2aab18SMatthew Ahrens 6683b2aab18SMatthew Ahrens static void 6693b2aab18SMatthew Ahrens old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx) 6703b2aab18SMatthew Ahrens { 6713b2aab18SMatthew Ahrens struct killarg ka; 6723b2aab18SMatthew Ahrens 6733b2aab18SMatthew Ahrens /* 6743b2aab18SMatthew Ahrens * Free everything that we point to (that's born after 6753b2aab18SMatthew Ahrens * the previous snapshot, if we are a clone) 6763b2aab18SMatthew Ahrens * 6773b2aab18SMatthew Ahrens * NB: this should be very quick, because we already 6783b2aab18SMatthew Ahrens * freed all the objects in open context. 6793b2aab18SMatthew Ahrens */ 6803b2aab18SMatthew Ahrens ka.ds = ds; 6813b2aab18SMatthew Ahrens ka.tx = tx; 6823b2aab18SMatthew Ahrens VERIFY0(traverse_dataset(ds, 683*eb633035STom Caputi dsl_dataset_phys(ds)->ds_prev_snap_txg, TRAVERSE_POST | 684*eb633035STom Caputi TRAVERSE_NO_DECRYPT, kill_blkptr, &ka)); 685c1379625SJustin T. Gibbs ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 686c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_unique_bytes == 0); 6873b2aab18SMatthew Ahrens } 6883b2aab18SMatthew Ahrens 6893b2aab18SMatthew Ahrens int 6903b2aab18SMatthew Ahrens dsl_destroy_head_check_impl(dsl_dataset_t *ds, int expected_holds) 6913b2aab18SMatthew Ahrens { 6923b2aab18SMatthew Ahrens int error; 6933b2aab18SMatthew Ahrens uint64_t count; 6943b2aab18SMatthew Ahrens objset_t *mos; 6953b2aab18SMatthew Ahrens 696bc9014e6SJustin Gibbs ASSERT(!ds->ds_is_snapshot); 697bc9014e6SJustin Gibbs if (ds->ds_is_snapshot) 698be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 6993b2aab18SMatthew Ahrens 700e914ace2STim Schumacher if (zfs_refcount_count(&ds->ds_longholds) != expected_holds) 701be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 7023b2aab18SMatthew Ahrens 7033b2aab18SMatthew Ahrens mos = ds->ds_dir->dd_pool->dp_meta_objset; 7043b2aab18SMatthew Ahrens 7053b2aab18SMatthew Ahrens /* 7063b2aab18SMatthew Ahrens * Can't delete a head dataset if there are snapshots of it. 7073b2aab18SMatthew Ahrens * (Except if the only snapshots are from the branch we cloned 7083b2aab18SMatthew Ahrens * from.) 7093b2aab18SMatthew Ahrens */ 7103b2aab18SMatthew Ahrens if (ds->ds_prev != NULL && 711c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj == ds->ds_object) 712be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 7133b2aab18SMatthew Ahrens 7143b2aab18SMatthew Ahrens /* 7153b2aab18SMatthew Ahrens * Can't delete if there are children of this fs. 7163b2aab18SMatthew Ahrens */ 7173b2aab18SMatthew Ahrens error = zap_count(mos, 718c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, &count); 7193b2aab18SMatthew Ahrens if (error != 0) 7203b2aab18SMatthew Ahrens return (error); 7213b2aab18SMatthew Ahrens if (count != 0) 722be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 7233b2aab18SMatthew Ahrens 7243b2aab18SMatthew Ahrens if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev) && 725c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 && 7263b2aab18SMatthew Ahrens ds->ds_prev->ds_userrefs == 0) { 7273b2aab18SMatthew Ahrens /* We need to remove the origin snapshot as well. */ 728e914ace2STim Schumacher if (!zfs_refcount_is_zero(&ds->ds_prev->ds_longholds)) 729be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 7303b2aab18SMatthew Ahrens } 7313b2aab18SMatthew Ahrens return (0); 7323b2aab18SMatthew Ahrens } 7333b2aab18SMatthew Ahrens 734dfc11533SChris Williamson int 7353b2aab18SMatthew Ahrens dsl_destroy_head_check(void *arg, dmu_tx_t *tx) 7363b2aab18SMatthew Ahrens { 7373b2aab18SMatthew Ahrens dsl_destroy_head_arg_t *ddha = arg; 7383b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 7393b2aab18SMatthew Ahrens dsl_dataset_t *ds; 7403b2aab18SMatthew Ahrens int error; 7413b2aab18SMatthew Ahrens 7423b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds); 7433b2aab18SMatthew Ahrens if (error != 0) 7443b2aab18SMatthew Ahrens return (error); 7453b2aab18SMatthew Ahrens 7463b2aab18SMatthew Ahrens error = dsl_destroy_head_check_impl(ds, 0); 7473b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 7483b2aab18SMatthew Ahrens return (error); 7493b2aab18SMatthew Ahrens } 7503b2aab18SMatthew Ahrens 7513b2aab18SMatthew Ahrens static void 7523b2aab18SMatthew Ahrens dsl_dir_destroy_sync(uint64_t ddobj, dmu_tx_t *tx) 7533b2aab18SMatthew Ahrens { 7543b2aab18SMatthew Ahrens dsl_dir_t *dd; 7553b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 7563b2aab18SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 7573b2aab18SMatthew Ahrens dd_used_t t; 7583b2aab18SMatthew Ahrens 7593b2aab18SMatthew Ahrens ASSERT(RRW_WRITE_HELD(&dmu_tx_pool(tx)->dp_config_rwlock)); 7603b2aab18SMatthew Ahrens 7613b2aab18SMatthew Ahrens VERIFY0(dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd)); 7623b2aab18SMatthew Ahrens 763c1379625SJustin T. Gibbs ASSERT0(dsl_dir_phys(dd)->dd_head_dataset_obj); 7643b2aab18SMatthew Ahrens 765a2afb611SJerry Jelinek /* 766a2afb611SJerry Jelinek * Decrement the filesystem count for all parent filesystems. 767a2afb611SJerry Jelinek * 768a2afb611SJerry Jelinek * When we receive an incremental stream into a filesystem that already 769a2afb611SJerry Jelinek * exists, a temporary clone is created. We never count this temporary 770a2afb611SJerry Jelinek * clone, whose name begins with a '%'. 771a2afb611SJerry Jelinek */ 772a2afb611SJerry Jelinek if (dd->dd_myname[0] != '%' && dd->dd_parent != NULL) 773a2afb611SJerry Jelinek dsl_fs_ss_count_adjust(dd->dd_parent, -1, 774a2afb611SJerry Jelinek DD_FIELD_FILESYSTEM_COUNT, tx); 775a2afb611SJerry Jelinek 7763b2aab18SMatthew Ahrens /* 7773b2aab18SMatthew Ahrens * Remove our reservation. The impl() routine avoids setting the 7783b2aab18SMatthew Ahrens * actual property, which would require the (already destroyed) ds. 7793b2aab18SMatthew Ahrens */ 7803b2aab18SMatthew Ahrens dsl_dir_set_reservation_sync_impl(dd, 0, tx); 7813b2aab18SMatthew Ahrens 782c1379625SJustin T. Gibbs ASSERT0(dsl_dir_phys(dd)->dd_used_bytes); 783c1379625SJustin T. Gibbs ASSERT0(dsl_dir_phys(dd)->dd_reserved); 7843b2aab18SMatthew Ahrens for (t = 0; t < DD_USED_NUM; t++) 785c1379625SJustin T. Gibbs ASSERT0(dsl_dir_phys(dd)->dd_used_breakdown[t]); 7863b2aab18SMatthew Ahrens 787*eb633035STom Caputi if (dd->dd_crypto_obj != 0) { 788*eb633035STom Caputi dsl_crypto_key_destroy_sync(dd->dd_crypto_obj, tx); 789*eb633035STom Caputi (void) spa_keystore_unload_wkey_impl(dp->dp_spa, dd->dd_object); 790*eb633035STom Caputi } 791*eb633035STom Caputi 792c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_child_dir_zapobj, tx)); 793c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_props_zapobj, tx)); 79417fb938fSMatthew Ahrens if (dsl_dir_phys(dd)->dd_clones != 0) 79517fb938fSMatthew Ahrens VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_clones, tx)); 796c1379625SJustin T. Gibbs VERIFY0(dsl_deleg_destroy(mos, dsl_dir_phys(dd)->dd_deleg_zapobj, tx)); 7973b2aab18SMatthew Ahrens VERIFY0(zap_remove(mos, 798c1379625SJustin T. Gibbs dsl_dir_phys(dd->dd_parent)->dd_child_dir_zapobj, 799c1379625SJustin T. Gibbs dd->dd_myname, tx)); 8003b2aab18SMatthew Ahrens 8013b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 8022acef22dSMatthew Ahrens dmu_object_free_zapified(mos, ddobj, tx); 8033b2aab18SMatthew Ahrens } 8043b2aab18SMatthew Ahrens 8053b2aab18SMatthew Ahrens void 8063b2aab18SMatthew Ahrens dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx) 8073b2aab18SMatthew Ahrens { 8083b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 8093b2aab18SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 8103b2aab18SMatthew Ahrens uint64_t obj, ddobj, prevobj = 0; 8113b2aab18SMatthew Ahrens boolean_t rmorigin; 8123b2aab18SMatthew Ahrens 813c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1); 8143b2aab18SMatthew Ahrens ASSERT(ds->ds_prev == NULL || 815c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj != ds->ds_object); 816c166b69dSPaul Dagnelie rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); 817c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg); 818c166b69dSPaul Dagnelie rrw_exit(&ds->ds_bp_rwlock, FTAG); 8193b2aab18SMatthew Ahrens ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); 8203b2aab18SMatthew Ahrens 8213b2aab18SMatthew Ahrens /* We need to log before removing it from the namespace. */ 8223b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "destroy", tx, ""); 8233b2aab18SMatthew Ahrens 8243b2aab18SMatthew Ahrens rmorigin = (dsl_dir_is_clone(ds->ds_dir) && 8253b2aab18SMatthew Ahrens DS_IS_DEFER_DESTROY(ds->ds_prev) && 826c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 && 8273b2aab18SMatthew Ahrens ds->ds_prev->ds_userrefs == 0); 8283b2aab18SMatthew Ahrens 8295d7b4d43SMatthew Ahrens /* Remove our reservation. */ 8303b2aab18SMatthew Ahrens if (ds->ds_reserved != 0) { 8313b2aab18SMatthew Ahrens dsl_dataset_set_refreservation_sync_impl(ds, 8323b2aab18SMatthew Ahrens (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), 8333b2aab18SMatthew Ahrens 0, tx); 8343b2aab18SMatthew Ahrens ASSERT0(ds->ds_reserved); 8353b2aab18SMatthew Ahrens } 8363b2aab18SMatthew Ahrens 837ca0cc391SMatthew Ahrens obj = ds->ds_object; 838b5152584SMatthew Ahrens 839ca0cc391SMatthew Ahrens for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { 840ca0cc391SMatthew Ahrens if (ds->ds_feature_inuse[f]) { 841ca0cc391SMatthew Ahrens dsl_dataset_deactivate_feature(obj, f, tx); 842ca0cc391SMatthew Ahrens ds->ds_feature_inuse[f] = B_FALSE; 843ca0cc391SMatthew Ahrens } 844ca0cc391SMatthew Ahrens } 8453b2aab18SMatthew Ahrens 846ca0cc391SMatthew Ahrens dsl_scan_ds_destroyed(ds, tx); 8473b2aab18SMatthew Ahrens 848c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { 8493b2aab18SMatthew Ahrens /* This is a clone */ 8503b2aab18SMatthew Ahrens ASSERT(ds->ds_prev != NULL); 851c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj, !=, 852c1379625SJustin T. Gibbs obj); 853c1379625SJustin T. Gibbs ASSERT0(dsl_dataset_phys(ds)->ds_next_snap_obj); 8543b2aab18SMatthew Ahrens 8553b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 856c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds->ds_prev)->ds_next_clones_obj != 0) { 8573b2aab18SMatthew Ahrens dsl_dataset_remove_from_next_clones(ds->ds_prev, 8583b2aab18SMatthew Ahrens obj, tx); 8593b2aab18SMatthew Ahrens } 8603b2aab18SMatthew Ahrens 861c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_num_children, >, 1); 862c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_num_children--; 8633b2aab18SMatthew Ahrens } 8643b2aab18SMatthew Ahrens 8653b2aab18SMatthew Ahrens /* 8663b2aab18SMatthew Ahrens * Destroy the deadlist. Unless it's a clone, the 8675cabbc6bSPrashanth Sreenivasa * deadlist should be empty since the dataset has no snapshots. 8685cabbc6bSPrashanth Sreenivasa * (If it's a clone, it's safe to ignore the deadlist contents 8695cabbc6bSPrashanth Sreenivasa * since they are still referenced by the origin snapshot.) 8703b2aab18SMatthew Ahrens */ 8713b2aab18SMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 872c1379625SJustin T. Gibbs dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 8733b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 874c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj = 0; 8753b2aab18SMatthew Ahrens 8765cabbc6bSPrashanth Sreenivasa if (dsl_dataset_remap_deadlist_exists(ds)) 8775cabbc6bSPrashanth Sreenivasa dsl_dataset_destroy_remap_deadlist(ds, tx); 8785cabbc6bSPrashanth Sreenivasa 8792acef22dSMatthew Ahrens objset_t *os; 8803b2aab18SMatthew Ahrens VERIFY0(dmu_objset_from_ds(ds, &os)); 8813b2aab18SMatthew Ahrens 8822acef22dSMatthew Ahrens if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) { 8833b2aab18SMatthew Ahrens old_synchronous_dataset_destroy(ds, tx); 8843b2aab18SMatthew Ahrens } else { 8853b2aab18SMatthew Ahrens /* 8863b2aab18SMatthew Ahrens * Move the bptree into the pool's list of trees to 8873b2aab18SMatthew Ahrens * clean up and update space accounting information. 8883b2aab18SMatthew Ahrens */ 8893b2aab18SMatthew Ahrens uint64_t used, comp, uncomp; 8903b2aab18SMatthew Ahrens 8913b2aab18SMatthew Ahrens zil_destroy_sync(dmu_objset_zil(os), tx); 8923b2aab18SMatthew Ahrens 8932acef22dSMatthew Ahrens if (!spa_feature_is_active(dp->dp_spa, 8942acef22dSMatthew Ahrens SPA_FEATURE_ASYNC_DESTROY)) { 8954a923759SGeorge Wilson dsl_scan_t *scn = dp->dp_scan; 8962acef22dSMatthew Ahrens spa_feature_incr(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY, 8972acef22dSMatthew Ahrens tx); 8983b2aab18SMatthew Ahrens dp->dp_bptree_obj = bptree_alloc(mos, tx); 8993b2aab18SMatthew Ahrens VERIFY0(zap_add(mos, 9003b2aab18SMatthew Ahrens DMU_POOL_DIRECTORY_OBJECT, 9013b2aab18SMatthew Ahrens DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1, 9023b2aab18SMatthew Ahrens &dp->dp_bptree_obj, tx)); 9034a923759SGeorge Wilson ASSERT(!scn->scn_async_destroying); 9044a923759SGeorge Wilson scn->scn_async_destroying = B_TRUE; 9053b2aab18SMatthew Ahrens } 9063b2aab18SMatthew Ahrens 907c1379625SJustin T. Gibbs used = dsl_dir_phys(ds->ds_dir)->dd_used_bytes; 908c1379625SJustin T. Gibbs comp = dsl_dir_phys(ds->ds_dir)->dd_compressed_bytes; 909c1379625SJustin T. Gibbs uncomp = dsl_dir_phys(ds->ds_dir)->dd_uncompressed_bytes; 9103b2aab18SMatthew Ahrens 9113b2aab18SMatthew Ahrens ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 912c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_unique_bytes == used); 9133b2aab18SMatthew Ahrens 914c166b69dSPaul Dagnelie rrw_enter(&ds->ds_bp_rwlock, RW_READER, FTAG); 9153b2aab18SMatthew Ahrens bptree_add(mos, dp->dp_bptree_obj, 916c1379625SJustin T. Gibbs &dsl_dataset_phys(ds)->ds_bp, 917c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, 9183b2aab18SMatthew Ahrens used, comp, uncomp, tx); 919c166b69dSPaul Dagnelie rrw_exit(&ds->ds_bp_rwlock, FTAG); 9203b2aab18SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 9213b2aab18SMatthew Ahrens -used, -comp, -uncomp, tx); 9223b2aab18SMatthew Ahrens dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD, 9233b2aab18SMatthew Ahrens used, comp, uncomp, tx); 9243b2aab18SMatthew Ahrens } 9253b2aab18SMatthew Ahrens 9263b2aab18SMatthew Ahrens if (ds->ds_prev != NULL) { 9273b2aab18SMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 9283b2aab18SMatthew Ahrens VERIFY0(zap_remove_int(mos, 929c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_prev->ds_dir)->dd_clones, 9303b2aab18SMatthew Ahrens ds->ds_object, tx)); 9313b2aab18SMatthew Ahrens } 9323b2aab18SMatthew Ahrens prevobj = ds->ds_prev->ds_object; 9333b2aab18SMatthew Ahrens dsl_dataset_rele(ds->ds_prev, ds); 9343b2aab18SMatthew Ahrens ds->ds_prev = NULL; 9353b2aab18SMatthew Ahrens } 9363b2aab18SMatthew Ahrens 9373b2aab18SMatthew Ahrens /* 9383b2aab18SMatthew Ahrens * This must be done after the dsl_traverse(), because it will 9393b2aab18SMatthew Ahrens * re-open the objset. 9403b2aab18SMatthew Ahrens */ 9413b2aab18SMatthew Ahrens if (ds->ds_objset) { 9423b2aab18SMatthew Ahrens dmu_objset_evict(ds->ds_objset); 9433b2aab18SMatthew Ahrens ds->ds_objset = NULL; 9443b2aab18SMatthew Ahrens } 9453b2aab18SMatthew Ahrens 9463b2aab18SMatthew Ahrens /* Erase the link in the dir */ 9473b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 948c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj = 0; 9493b2aab18SMatthew Ahrens ddobj = ds->ds_dir->dd_object; 950c1379625SJustin T. Gibbs ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj != 0); 951c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, 952c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_snapnames_zapobj, tx)); 9533b2aab18SMatthew Ahrens 95478f17100SMatthew Ahrens if (ds->ds_bookmarks != 0) { 955c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, ds->ds_bookmarks, tx)); 95678f17100SMatthew Ahrens spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx); 95778f17100SMatthew Ahrens } 95878f17100SMatthew Ahrens 9593b2aab18SMatthew Ahrens spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 9603b2aab18SMatthew Ahrens 961c1379625SJustin T. Gibbs ASSERT0(dsl_dataset_phys(ds)->ds_next_clones_obj); 962c1379625SJustin T. Gibbs ASSERT0(dsl_dataset_phys(ds)->ds_props_obj); 963c1379625SJustin T. Gibbs ASSERT0(dsl_dataset_phys(ds)->ds_userrefs_obj); 9643b2aab18SMatthew Ahrens dsl_dir_rele(ds->ds_dir, ds); 9653b2aab18SMatthew Ahrens ds->ds_dir = NULL; 9662acef22dSMatthew Ahrens dmu_object_free_zapified(mos, obj, tx); 9673b2aab18SMatthew Ahrens 9683b2aab18SMatthew Ahrens dsl_dir_destroy_sync(ddobj, tx); 9693b2aab18SMatthew Ahrens 9703b2aab18SMatthew Ahrens if (rmorigin) { 9713b2aab18SMatthew Ahrens dsl_dataset_t *prev; 9723b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, prevobj, FTAG, &prev)); 9733b2aab18SMatthew Ahrens dsl_destroy_snapshot_sync_impl(prev, B_FALSE, tx); 9743b2aab18SMatthew Ahrens dsl_dataset_rele(prev, FTAG); 9753b2aab18SMatthew Ahrens } 9763b2aab18SMatthew Ahrens } 9773b2aab18SMatthew Ahrens 978dfc11533SChris Williamson void 9793b2aab18SMatthew Ahrens dsl_destroy_head_sync(void *arg, dmu_tx_t *tx) 9803b2aab18SMatthew Ahrens { 9813b2aab18SMatthew Ahrens dsl_destroy_head_arg_t *ddha = arg; 9823b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 9833b2aab18SMatthew Ahrens dsl_dataset_t *ds; 9843b2aab18SMatthew Ahrens 9853b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds)); 9863b2aab18SMatthew Ahrens dsl_destroy_head_sync_impl(ds, tx); 9873b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 9883b2aab18SMatthew Ahrens } 9893b2aab18SMatthew Ahrens 9903b2aab18SMatthew Ahrens static void 9913b2aab18SMatthew Ahrens dsl_destroy_head_begin_sync(void *arg, dmu_tx_t *tx) 9923b2aab18SMatthew Ahrens { 9933b2aab18SMatthew Ahrens dsl_destroy_head_arg_t *ddha = arg; 9943b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 9953b2aab18SMatthew Ahrens dsl_dataset_t *ds; 9963b2aab18SMatthew Ahrens 9973b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds)); 9983b2aab18SMatthew Ahrens 9993b2aab18SMatthew Ahrens /* Mark it as inconsistent on-disk, in case we crash */ 10003b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1001c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT; 10023b2aab18SMatthew Ahrens 10033b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "destroy begin", tx, ""); 10043b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 10053b2aab18SMatthew Ahrens } 10063b2aab18SMatthew Ahrens 10073b2aab18SMatthew Ahrens int 10083b2aab18SMatthew Ahrens dsl_destroy_head(const char *name) 10093b2aab18SMatthew Ahrens { 10103b2aab18SMatthew Ahrens dsl_destroy_head_arg_t ddha; 10113b2aab18SMatthew Ahrens int error; 10123b2aab18SMatthew Ahrens spa_t *spa; 10133b2aab18SMatthew Ahrens boolean_t isenabled; 10143b2aab18SMatthew Ahrens 10153b2aab18SMatthew Ahrens #ifdef _KERNEL 10163b2aab18SMatthew Ahrens zfs_destroy_unmount_origin(name); 10173b2aab18SMatthew Ahrens #endif 10183b2aab18SMatthew Ahrens 10193b2aab18SMatthew Ahrens error = spa_open(name, &spa, FTAG); 10203b2aab18SMatthew Ahrens if (error != 0) 10213b2aab18SMatthew Ahrens return (error); 10222acef22dSMatthew Ahrens isenabled = spa_feature_is_enabled(spa, SPA_FEATURE_ASYNC_DESTROY); 10233b2aab18SMatthew Ahrens spa_close(spa, FTAG); 10243b2aab18SMatthew Ahrens 10253b2aab18SMatthew Ahrens ddha.ddha_name = name; 10263b2aab18SMatthew Ahrens 10273b2aab18SMatthew Ahrens if (!isenabled) { 10283b2aab18SMatthew Ahrens objset_t *os; 10293b2aab18SMatthew Ahrens 10303b2aab18SMatthew Ahrens error = dsl_sync_task(name, dsl_destroy_head_check, 10317d46dc6cSMatthew Ahrens dsl_destroy_head_begin_sync, &ddha, 103286714001SSerapheim Dimitropoulos 0, ZFS_SPACE_CHECK_DESTROY); 10333b2aab18SMatthew Ahrens if (error != 0) 10343b2aab18SMatthew Ahrens return (error); 10353b2aab18SMatthew Ahrens 10363b2aab18SMatthew Ahrens /* 10373b2aab18SMatthew Ahrens * Head deletion is processed in one txg on old pools; 10383b2aab18SMatthew Ahrens * remove the objects from open context so that the txg sync 10393b2aab18SMatthew Ahrens * is not too long. 10403b2aab18SMatthew Ahrens */ 1041*eb633035STom Caputi error = dmu_objset_own(name, DMU_OST_ANY, B_FALSE, B_FALSE, 1042*eb633035STom Caputi FTAG, &os); 10433b2aab18SMatthew Ahrens if (error == 0) { 10443b2aab18SMatthew Ahrens uint64_t prev_snap_txg = 1045c1379625SJustin T. Gibbs dsl_dataset_phys(dmu_objset_ds(os))-> 1046c1379625SJustin T. Gibbs ds_prev_snap_txg; 10473b2aab18SMatthew Ahrens for (uint64_t obj = 0; error == 0; 10483b2aab18SMatthew Ahrens error = dmu_object_next(os, &obj, FALSE, 10493b2aab18SMatthew Ahrens prev_snap_txg)) 1050713d6c20SMatthew Ahrens (void) dmu_free_long_object(os, obj); 10513b2aab18SMatthew Ahrens /* sync out all frees */ 10523b2aab18SMatthew Ahrens txg_wait_synced(dmu_objset_pool(os), 0); 1053*eb633035STom Caputi dmu_objset_disown(os, B_FALSE, FTAG); 10543b2aab18SMatthew Ahrens } 10553b2aab18SMatthew Ahrens } 10563b2aab18SMatthew Ahrens 10573b2aab18SMatthew Ahrens return (dsl_sync_task(name, dsl_destroy_head_check, 105886714001SSerapheim Dimitropoulos dsl_destroy_head_sync, &ddha, 0, ZFS_SPACE_CHECK_DESTROY)); 10593b2aab18SMatthew Ahrens } 10603b2aab18SMatthew Ahrens 10613b2aab18SMatthew Ahrens /* 10623b2aab18SMatthew Ahrens * Note, this function is used as the callback for dmu_objset_find(). We 10633b2aab18SMatthew Ahrens * always return 0 so that we will continue to find and process 10643b2aab18SMatthew Ahrens * inconsistent datasets, even if we encounter an error trying to 10653b2aab18SMatthew Ahrens * process one of them. 10663b2aab18SMatthew Ahrens */ 10673b2aab18SMatthew Ahrens /* ARGSUSED */ 10683b2aab18SMatthew Ahrens int 10693b2aab18SMatthew Ahrens dsl_destroy_inconsistent(const char *dsname, void *arg) 10703b2aab18SMatthew Ahrens { 10713b2aab18SMatthew Ahrens objset_t *os; 10723b2aab18SMatthew Ahrens 10733b2aab18SMatthew Ahrens if (dmu_objset_hold(dsname, FTAG, &os) == 0) { 10749c3fd121SMatthew Ahrens boolean_t need_destroy = DS_IS_INCONSISTENT(dmu_objset_ds(os)); 10759c3fd121SMatthew Ahrens 10769c3fd121SMatthew Ahrens /* 10779c3fd121SMatthew Ahrens * If the dataset is inconsistent because a resumable receive 10789c3fd121SMatthew Ahrens * has failed, then do not destroy it. 10799c3fd121SMatthew Ahrens */ 10809c3fd121SMatthew Ahrens if (dsl_dataset_has_resume_receive_state(dmu_objset_ds(os))) 10819c3fd121SMatthew Ahrens need_destroy = B_FALSE; 10829c3fd121SMatthew Ahrens 10833b2aab18SMatthew Ahrens dmu_objset_rele(os, FTAG); 10849c3fd121SMatthew Ahrens if (need_destroy) 10853b2aab18SMatthew Ahrens (void) dsl_destroy_head(dsname); 10863b2aab18SMatthew Ahrens } 10873b2aab18SMatthew Ahrens return (0); 10883b2aab18SMatthew Ahrens } 1089