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. 23*ca0cc391SMatthew Ahrens * Copyright (c) 2012, 2015 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. 263b2aab18SMatthew Ahrens */ 273b2aab18SMatthew Ahrens 283b2aab18SMatthew Ahrens #include <sys/zfs_context.h> 293b2aab18SMatthew Ahrens #include <sys/dsl_userhold.h> 303b2aab18SMatthew Ahrens #include <sys/dsl_dataset.h> 313b2aab18SMatthew Ahrens #include <sys/dsl_synctask.h> 323b2aab18SMatthew Ahrens #include <sys/dmu_tx.h> 333b2aab18SMatthew Ahrens #include <sys/dsl_pool.h> 343b2aab18SMatthew Ahrens #include <sys/dsl_dir.h> 353b2aab18SMatthew Ahrens #include <sys/dmu_traverse.h> 363b2aab18SMatthew Ahrens #include <sys/dsl_scan.h> 373b2aab18SMatthew Ahrens #include <sys/dmu_objset.h> 383b2aab18SMatthew Ahrens #include <sys/zap.h> 393b2aab18SMatthew Ahrens #include <sys/zfeature.h> 403b2aab18SMatthew Ahrens #include <sys/zfs_ioctl.h> 413b2aab18SMatthew Ahrens #include <sys/dsl_deleg.h> 422acef22dSMatthew Ahrens #include <sys/dmu_impl.h> 433b2aab18SMatthew Ahrens 443b2aab18SMatthew Ahrens typedef struct dmu_snapshots_destroy_arg { 453b2aab18SMatthew Ahrens nvlist_t *dsda_snaps; 463b2aab18SMatthew Ahrens nvlist_t *dsda_successful_snaps; 473b2aab18SMatthew Ahrens boolean_t dsda_defer; 483b2aab18SMatthew Ahrens nvlist_t *dsda_errlist; 493b2aab18SMatthew Ahrens } dmu_snapshots_destroy_arg_t; 503b2aab18SMatthew Ahrens 5134f2f8cfSMatthew Ahrens int 523b2aab18SMatthew Ahrens dsl_destroy_snapshot_check_impl(dsl_dataset_t *ds, boolean_t defer) 533b2aab18SMatthew Ahrens { 54bc9014e6SJustin Gibbs if (!ds->ds_is_snapshot) 55be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 563b2aab18SMatthew Ahrens 573b2aab18SMatthew Ahrens if (dsl_dataset_long_held(ds)) 58be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 593b2aab18SMatthew Ahrens 603b2aab18SMatthew Ahrens /* 613b2aab18SMatthew Ahrens * Only allow deferred destroy on pools that support it. 623b2aab18SMatthew Ahrens * NOTE: deferred destroy is only supported on snapshots. 633b2aab18SMatthew Ahrens */ 643b2aab18SMatthew Ahrens if (defer) { 653b2aab18SMatthew Ahrens if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 663b2aab18SMatthew Ahrens SPA_VERSION_USERREFS) 67be6fd75aSMatthew Ahrens return (SET_ERROR(ENOTSUP)); 683b2aab18SMatthew Ahrens return (0); 693b2aab18SMatthew Ahrens } 703b2aab18SMatthew Ahrens 713b2aab18SMatthew Ahrens /* 723b2aab18SMatthew Ahrens * If this snapshot has an elevated user reference count, 733b2aab18SMatthew Ahrens * we can't destroy it yet. 743b2aab18SMatthew Ahrens */ 753b2aab18SMatthew Ahrens if (ds->ds_userrefs > 0) 76be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 773b2aab18SMatthew Ahrens 783b2aab18SMatthew Ahrens /* 793b2aab18SMatthew Ahrens * Can't delete a branch point. 803b2aab18SMatthew Ahrens */ 81c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_num_children > 1) 82be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 833b2aab18SMatthew Ahrens 843b2aab18SMatthew Ahrens return (0); 853b2aab18SMatthew Ahrens } 863b2aab18SMatthew Ahrens 873b2aab18SMatthew Ahrens static int 883b2aab18SMatthew Ahrens dsl_destroy_snapshot_check(void *arg, dmu_tx_t *tx) 893b2aab18SMatthew Ahrens { 903b2aab18SMatthew Ahrens dmu_snapshots_destroy_arg_t *dsda = arg; 913b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 923b2aab18SMatthew Ahrens nvpair_t *pair; 933b2aab18SMatthew Ahrens int error = 0; 943b2aab18SMatthew Ahrens 953b2aab18SMatthew Ahrens if (!dmu_tx_is_syncing(tx)) 963b2aab18SMatthew Ahrens return (0); 973b2aab18SMatthew Ahrens 983b2aab18SMatthew Ahrens for (pair = nvlist_next_nvpair(dsda->dsda_snaps, NULL); 993b2aab18SMatthew Ahrens pair != NULL; pair = nvlist_next_nvpair(dsda->dsda_snaps, pair)) { 1003b2aab18SMatthew Ahrens dsl_dataset_t *ds; 1013b2aab18SMatthew Ahrens 1023b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, nvpair_name(pair), 1033b2aab18SMatthew Ahrens FTAG, &ds); 1043b2aab18SMatthew Ahrens 1053b2aab18SMatthew Ahrens /* 1063b2aab18SMatthew Ahrens * If the snapshot does not exist, silently ignore it 1073b2aab18SMatthew Ahrens * (it's "already destroyed"). 1083b2aab18SMatthew Ahrens */ 1093b2aab18SMatthew Ahrens if (error == ENOENT) 1103b2aab18SMatthew Ahrens continue; 1113b2aab18SMatthew Ahrens 1123b2aab18SMatthew Ahrens if (error == 0) { 1133b2aab18SMatthew Ahrens error = dsl_destroy_snapshot_check_impl(ds, 1143b2aab18SMatthew Ahrens dsda->dsda_defer); 1153b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 1163b2aab18SMatthew Ahrens } 1173b2aab18SMatthew Ahrens 1183b2aab18SMatthew Ahrens if (error == 0) { 1193b2aab18SMatthew Ahrens fnvlist_add_boolean(dsda->dsda_successful_snaps, 1203b2aab18SMatthew Ahrens nvpair_name(pair)); 1213b2aab18SMatthew Ahrens } else { 1223b2aab18SMatthew Ahrens fnvlist_add_int32(dsda->dsda_errlist, 1233b2aab18SMatthew Ahrens nvpair_name(pair), error); 1243b2aab18SMatthew Ahrens } 1253b2aab18SMatthew Ahrens } 1263b2aab18SMatthew Ahrens 1273b2aab18SMatthew Ahrens pair = nvlist_next_nvpair(dsda->dsda_errlist, NULL); 1283b2aab18SMatthew Ahrens if (pair != NULL) 1293b2aab18SMatthew Ahrens return (fnvpair_value_int32(pair)); 130a7a845e4SSteven Hartland 1313b2aab18SMatthew Ahrens return (0); 1323b2aab18SMatthew Ahrens } 1333b2aab18SMatthew Ahrens 1343b2aab18SMatthew Ahrens struct process_old_arg { 1353b2aab18SMatthew Ahrens dsl_dataset_t *ds; 1363b2aab18SMatthew Ahrens dsl_dataset_t *ds_prev; 1373b2aab18SMatthew Ahrens boolean_t after_branch_point; 1383b2aab18SMatthew Ahrens zio_t *pio; 1393b2aab18SMatthew Ahrens uint64_t used, comp, uncomp; 1403b2aab18SMatthew Ahrens }; 1413b2aab18SMatthew Ahrens 1423b2aab18SMatthew Ahrens static int 1433b2aab18SMatthew Ahrens process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx) 1443b2aab18SMatthew Ahrens { 1453b2aab18SMatthew Ahrens struct process_old_arg *poa = arg; 1463b2aab18SMatthew Ahrens dsl_pool_t *dp = poa->ds->ds_dir->dd_pool; 1473b2aab18SMatthew Ahrens 14843466aaeSMax Grossman ASSERT(!BP_IS_HOLE(bp)); 14943466aaeSMax Grossman 150c1379625SJustin T. Gibbs if (bp->blk_birth <= dsl_dataset_phys(poa->ds)->ds_prev_snap_txg) { 1513b2aab18SMatthew Ahrens dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx); 1523b2aab18SMatthew Ahrens if (poa->ds_prev && !poa->after_branch_point && 1533b2aab18SMatthew Ahrens bp->blk_birth > 154c1379625SJustin T. Gibbs dsl_dataset_phys(poa->ds_prev)->ds_prev_snap_txg) { 155c1379625SJustin T. Gibbs dsl_dataset_phys(poa->ds_prev)->ds_unique_bytes += 1563b2aab18SMatthew Ahrens bp_get_dsize_sync(dp->dp_spa, bp); 1573b2aab18SMatthew Ahrens } 1583b2aab18SMatthew Ahrens } else { 1593b2aab18SMatthew Ahrens poa->used += bp_get_dsize_sync(dp->dp_spa, bp); 1603b2aab18SMatthew Ahrens poa->comp += BP_GET_PSIZE(bp); 1613b2aab18SMatthew Ahrens poa->uncomp += BP_GET_UCSIZE(bp); 1623b2aab18SMatthew Ahrens dsl_free_sync(poa->pio, dp, tx->tx_txg, bp); 1633b2aab18SMatthew Ahrens } 1643b2aab18SMatthew Ahrens return (0); 1653b2aab18SMatthew Ahrens } 1663b2aab18SMatthew Ahrens 1673b2aab18SMatthew Ahrens static void 1683b2aab18SMatthew Ahrens process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev, 1693b2aab18SMatthew Ahrens dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx) 1703b2aab18SMatthew Ahrens { 1713b2aab18SMatthew Ahrens struct process_old_arg poa = { 0 }; 1723b2aab18SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 1733b2aab18SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 1743b2aab18SMatthew Ahrens uint64_t deadlist_obj; 1753b2aab18SMatthew Ahrens 1763b2aab18SMatthew Ahrens ASSERT(ds->ds_deadlist.dl_oldfmt); 1773b2aab18SMatthew Ahrens ASSERT(ds_next->ds_deadlist.dl_oldfmt); 1783b2aab18SMatthew Ahrens 1793b2aab18SMatthew Ahrens poa.ds = ds; 1803b2aab18SMatthew Ahrens poa.ds_prev = ds_prev; 1813b2aab18SMatthew Ahrens poa.after_branch_point = after_branch_point; 1823b2aab18SMatthew Ahrens poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1833b2aab18SMatthew Ahrens VERIFY0(bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj, 1843b2aab18SMatthew Ahrens process_old_cb, &poa, tx)); 1853b2aab18SMatthew Ahrens VERIFY0(zio_wait(poa.pio)); 186c1379625SJustin T. Gibbs ASSERT3U(poa.used, ==, dsl_dataset_phys(ds)->ds_unique_bytes); 1873b2aab18SMatthew Ahrens 1883b2aab18SMatthew Ahrens /* change snapused */ 1893b2aab18SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 1903b2aab18SMatthew Ahrens -poa.used, -poa.comp, -poa.uncomp, tx); 1913b2aab18SMatthew Ahrens 1923b2aab18SMatthew Ahrens /* swap next's deadlist to our deadlist */ 1933b2aab18SMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1943b2aab18SMatthew Ahrens dsl_deadlist_close(&ds_next->ds_deadlist); 195c1379625SJustin T. Gibbs deadlist_obj = dsl_dataset_phys(ds)->ds_deadlist_obj; 196c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj = 197c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_deadlist_obj; 198c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_deadlist_obj = deadlist_obj; 199c1379625SJustin T. Gibbs dsl_deadlist_open(&ds->ds_deadlist, mos, 200c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj); 2013b2aab18SMatthew Ahrens dsl_deadlist_open(&ds_next->ds_deadlist, mos, 202c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_deadlist_obj); 2033b2aab18SMatthew Ahrens } 2043b2aab18SMatthew Ahrens 2053b2aab18SMatthew Ahrens static void 2063b2aab18SMatthew Ahrens dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx) 2073b2aab18SMatthew Ahrens { 2083b2aab18SMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 2093b2aab18SMatthew Ahrens zap_cursor_t zc; 2103b2aab18SMatthew Ahrens zap_attribute_t za; 2113b2aab18SMatthew Ahrens 2123b2aab18SMatthew Ahrens /* 2133b2aab18SMatthew Ahrens * If it is the old version, dd_clones doesn't exist so we can't 2143b2aab18SMatthew Ahrens * find the clones, but dsl_deadlist_remove_key() is a no-op so it 2153b2aab18SMatthew Ahrens * doesn't matter. 2163b2aab18SMatthew Ahrens */ 217c1379625SJustin T. Gibbs if (dsl_dir_phys(ds->ds_dir)->dd_clones == 0) 2183b2aab18SMatthew Ahrens return; 2193b2aab18SMatthew Ahrens 220c1379625SJustin T. Gibbs for (zap_cursor_init(&zc, mos, dsl_dir_phys(ds->ds_dir)->dd_clones); 2213b2aab18SMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 2223b2aab18SMatthew Ahrens zap_cursor_advance(&zc)) { 2233b2aab18SMatthew Ahrens dsl_dataset_t *clone; 2243b2aab18SMatthew Ahrens 2253b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 2263b2aab18SMatthew Ahrens za.za_first_integer, FTAG, &clone)); 2273b2aab18SMatthew Ahrens if (clone->ds_dir->dd_origin_txg > mintxg) { 2283b2aab18SMatthew Ahrens dsl_deadlist_remove_key(&clone->ds_deadlist, 2293b2aab18SMatthew Ahrens mintxg, tx); 2303b2aab18SMatthew Ahrens dsl_dataset_remove_clones_key(clone, mintxg, tx); 2313b2aab18SMatthew Ahrens } 2323b2aab18SMatthew Ahrens dsl_dataset_rele(clone, FTAG); 2333b2aab18SMatthew Ahrens } 2343b2aab18SMatthew Ahrens zap_cursor_fini(&zc); 2353b2aab18SMatthew Ahrens } 2363b2aab18SMatthew Ahrens 2373b2aab18SMatthew Ahrens void 2383b2aab18SMatthew Ahrens dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx) 2393b2aab18SMatthew Ahrens { 2403b2aab18SMatthew Ahrens int err; 2413b2aab18SMatthew Ahrens int after_branch_point = FALSE; 2423b2aab18SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 2433b2aab18SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 2443b2aab18SMatthew Ahrens dsl_dataset_t *ds_prev = NULL; 2453b2aab18SMatthew Ahrens uint64_t obj; 2463b2aab18SMatthew Ahrens 2473b2aab18SMatthew Ahrens ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); 248c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg); 2493b2aab18SMatthew Ahrens ASSERT(refcount_is_zero(&ds->ds_longholds)); 2503b2aab18SMatthew Ahrens 2513b2aab18SMatthew Ahrens if (defer && 252c1379625SJustin T. Gibbs (ds->ds_userrefs > 0 || 253c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_num_children > 1)) { 2543b2aab18SMatthew Ahrens ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 2553b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 256c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_DEFER_DESTROY; 2573b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "defer_destroy", tx, ""); 2583b2aab18SMatthew Ahrens return; 2593b2aab18SMatthew Ahrens } 2603b2aab18SMatthew Ahrens 261c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1); 2623b2aab18SMatthew Ahrens 2633b2aab18SMatthew Ahrens /* We need to log before removing it from the namespace. */ 2643b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "destroy", tx, ""); 2653b2aab18SMatthew Ahrens 2663b2aab18SMatthew Ahrens dsl_scan_ds_destroyed(ds, tx); 2673b2aab18SMatthew Ahrens 2683b2aab18SMatthew Ahrens obj = ds->ds_object; 2693b2aab18SMatthew Ahrens 270*ca0cc391SMatthew Ahrens for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { 271*ca0cc391SMatthew Ahrens if (ds->ds_feature_inuse[f]) { 272*ca0cc391SMatthew Ahrens dsl_dataset_deactivate_feature(obj, f, tx); 273*ca0cc391SMatthew Ahrens ds->ds_feature_inuse[f] = B_FALSE; 274*ca0cc391SMatthew Ahrens } 275b5152584SMatthew Ahrens } 276c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { 2773b2aab18SMatthew Ahrens ASSERT3P(ds->ds_prev, ==, NULL); 2783b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 279c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_obj, FTAG, &ds_prev)); 2803b2aab18SMatthew Ahrens after_branch_point = 281c1379625SJustin T. Gibbs (dsl_dataset_phys(ds_prev)->ds_next_snap_obj != obj); 2823b2aab18SMatthew Ahrens 2833b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 2843b2aab18SMatthew Ahrens if (after_branch_point && 285c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)->ds_next_clones_obj != 0) { 2863b2aab18SMatthew Ahrens dsl_dataset_remove_from_next_clones(ds_prev, obj, tx); 287c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_next_snap_obj != 0) { 2883b2aab18SMatthew Ahrens VERIFY0(zap_add_int(mos, 289c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)-> 290c1379625SJustin T. Gibbs ds_next_clones_obj, 291c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_snap_obj, 292c1379625SJustin T. Gibbs tx)); 2933b2aab18SMatthew Ahrens } 2943b2aab18SMatthew Ahrens } 2953b2aab18SMatthew Ahrens if (!after_branch_point) { 296c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)->ds_next_snap_obj = 297c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_snap_obj; 2983b2aab18SMatthew Ahrens } 2993b2aab18SMatthew Ahrens } 3003b2aab18SMatthew Ahrens 3013b2aab18SMatthew Ahrens dsl_dataset_t *ds_next; 3023b2aab18SMatthew Ahrens uint64_t old_unique; 3033b2aab18SMatthew Ahrens uint64_t used = 0, comp = 0, uncomp = 0; 3043b2aab18SMatthew Ahrens 3053b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 306c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_snap_obj, FTAG, &ds_next)); 307c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds_next)->ds_prev_snap_obj, ==, obj); 3083b2aab18SMatthew Ahrens 309c1379625SJustin T. Gibbs old_unique = dsl_dataset_phys(ds_next)->ds_unique_bytes; 3103b2aab18SMatthew Ahrens 3113b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 312c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_prev_snap_obj = 313c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_obj; 314c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_prev_snap_txg = 315c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg; 316c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, ==, 317c1379625SJustin T. Gibbs ds_prev ? dsl_dataset_phys(ds_prev)->ds_creation_txg : 0); 3183b2aab18SMatthew Ahrens 3193b2aab18SMatthew Ahrens if (ds_next->ds_deadlist.dl_oldfmt) { 3203b2aab18SMatthew Ahrens process_old_deadlist(ds, ds_prev, ds_next, 3213b2aab18SMatthew Ahrens after_branch_point, tx); 3223b2aab18SMatthew Ahrens } else { 3233b2aab18SMatthew Ahrens /* Adjust prev's unique space. */ 3243b2aab18SMatthew Ahrens if (ds_prev && !after_branch_point) { 3253b2aab18SMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 326c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)->ds_prev_snap_txg, 327c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, 3283b2aab18SMatthew Ahrens &used, &comp, &uncomp); 329c1379625SJustin T. Gibbs dsl_dataset_phys(ds_prev)->ds_unique_bytes += used; 3303b2aab18SMatthew Ahrens } 3313b2aab18SMatthew Ahrens 3323b2aab18SMatthew Ahrens /* Adjust snapused. */ 3333b2aab18SMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 334c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, UINT64_MAX, 3353b2aab18SMatthew Ahrens &used, &comp, &uncomp); 3363b2aab18SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 3373b2aab18SMatthew Ahrens -used, -comp, -uncomp, tx); 3383b2aab18SMatthew Ahrens 3393b2aab18SMatthew Ahrens /* Move blocks to be freed to pool's free list. */ 3403b2aab18SMatthew Ahrens dsl_deadlist_move_bpobj(&ds_next->ds_deadlist, 341c1379625SJustin T. Gibbs &dp->dp_free_bpobj, dsl_dataset_phys(ds)->ds_prev_snap_txg, 3423b2aab18SMatthew Ahrens tx); 3433b2aab18SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, 3443b2aab18SMatthew Ahrens DD_USED_HEAD, used, comp, uncomp, tx); 3453b2aab18SMatthew Ahrens 3463b2aab18SMatthew Ahrens /* Merge our deadlist into next's and free it. */ 3473b2aab18SMatthew Ahrens dsl_deadlist_merge(&ds_next->ds_deadlist, 348c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 3493b2aab18SMatthew Ahrens } 3503b2aab18SMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 351c1379625SJustin T. Gibbs dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 3523b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 353c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj = 0; 3543b2aab18SMatthew Ahrens 3553b2aab18SMatthew Ahrens /* Collapse range in clone heads */ 3563b2aab18SMatthew Ahrens dsl_dataset_remove_clones_key(ds, 357c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_creation_txg, tx); 3583b2aab18SMatthew Ahrens 359bc9014e6SJustin Gibbs if (ds_next->ds_is_snapshot) { 3603b2aab18SMatthew Ahrens dsl_dataset_t *ds_nextnext; 3613b2aab18SMatthew Ahrens 3623b2aab18SMatthew Ahrens /* 3633b2aab18SMatthew Ahrens * Update next's unique to include blocks which 3643b2aab18SMatthew Ahrens * were previously shared by only this snapshot 3653b2aab18SMatthew Ahrens * and it. Those blocks will be born after the 3663b2aab18SMatthew Ahrens * prev snap and before this snap, and will have 3673b2aab18SMatthew Ahrens * died after the next snap and before the one 3683b2aab18SMatthew Ahrens * after that (ie. be on the snap after next's 3693b2aab18SMatthew Ahrens * deadlist). 3703b2aab18SMatthew Ahrens */ 3713b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 372c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_next_snap_obj, 373c1379625SJustin T. Gibbs FTAG, &ds_nextnext)); 3743b2aab18SMatthew Ahrens dsl_deadlist_space_range(&ds_nextnext->ds_deadlist, 375c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, 376c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_creation_txg, 3773b2aab18SMatthew Ahrens &used, &comp, &uncomp); 378c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_unique_bytes += used; 3793b2aab18SMatthew Ahrens dsl_dataset_rele(ds_nextnext, FTAG); 3803b2aab18SMatthew Ahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 3813b2aab18SMatthew Ahrens 3823b2aab18SMatthew Ahrens /* Collapse range in this head. */ 3833b2aab18SMatthew Ahrens dsl_dataset_t *hds; 3843b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 385c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &hds)); 3863b2aab18SMatthew Ahrens dsl_deadlist_remove_key(&hds->ds_deadlist, 387c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_creation_txg, tx); 3883b2aab18SMatthew Ahrens dsl_dataset_rele(hds, FTAG); 3893b2aab18SMatthew Ahrens 3903b2aab18SMatthew Ahrens } else { 3913b2aab18SMatthew Ahrens ASSERT3P(ds_next->ds_prev, ==, ds); 3923b2aab18SMatthew Ahrens dsl_dataset_rele(ds_next->ds_prev, ds_next); 3933b2aab18SMatthew Ahrens ds_next->ds_prev = NULL; 3943b2aab18SMatthew Ahrens if (ds_prev) { 3953b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 396c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_obj, 3973b2aab18SMatthew Ahrens ds_next, &ds_next->ds_prev)); 3983b2aab18SMatthew Ahrens } 3993b2aab18SMatthew Ahrens 4003b2aab18SMatthew Ahrens dsl_dataset_recalc_head_uniq(ds_next); 4013b2aab18SMatthew Ahrens 4023b2aab18SMatthew Ahrens /* 4033b2aab18SMatthew Ahrens * Reduce the amount of our unconsumed refreservation 4043b2aab18SMatthew Ahrens * being charged to our parent by the amount of 4053b2aab18SMatthew Ahrens * new unique data we have gained. 4063b2aab18SMatthew Ahrens */ 4073b2aab18SMatthew Ahrens if (old_unique < ds_next->ds_reserved) { 4083b2aab18SMatthew Ahrens int64_t mrsdelta; 4093b2aab18SMatthew Ahrens uint64_t new_unique = 410c1379625SJustin T. Gibbs dsl_dataset_phys(ds_next)->ds_unique_bytes; 4113b2aab18SMatthew Ahrens 4123b2aab18SMatthew Ahrens ASSERT(old_unique <= new_unique); 4133b2aab18SMatthew Ahrens mrsdelta = MIN(new_unique - old_unique, 4143b2aab18SMatthew Ahrens ds_next->ds_reserved - old_unique); 4153b2aab18SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 4163b2aab18SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 4173b2aab18SMatthew Ahrens } 4183b2aab18SMatthew Ahrens } 4193b2aab18SMatthew Ahrens dsl_dataset_rele(ds_next, FTAG); 4203b2aab18SMatthew Ahrens 4213b2aab18SMatthew Ahrens /* 4223b2aab18SMatthew Ahrens * This must be done after the dsl_traverse(), because it will 4233b2aab18SMatthew Ahrens * re-open the objset. 4243b2aab18SMatthew Ahrens */ 4253b2aab18SMatthew Ahrens if (ds->ds_objset) { 4263b2aab18SMatthew Ahrens dmu_objset_evict(ds->ds_objset); 4273b2aab18SMatthew Ahrens ds->ds_objset = NULL; 4283b2aab18SMatthew Ahrens } 4293b2aab18SMatthew Ahrens 4303b2aab18SMatthew Ahrens /* remove from snapshot namespace */ 4313b2aab18SMatthew Ahrens dsl_dataset_t *ds_head; 432c1379625SJustin T. Gibbs ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj == 0); 4333b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, 434c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj, FTAG, &ds_head)); 4353b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_get_snapname(ds)); 4363b2aab18SMatthew Ahrens #ifdef ZFS_DEBUG 4373b2aab18SMatthew Ahrens { 4383b2aab18SMatthew Ahrens uint64_t val; 4393b2aab18SMatthew Ahrens 4403b2aab18SMatthew Ahrens err = dsl_dataset_snap_lookup(ds_head, 4413b2aab18SMatthew Ahrens ds->ds_snapname, &val); 4423b2aab18SMatthew Ahrens ASSERT0(err); 4433b2aab18SMatthew Ahrens ASSERT3U(val, ==, obj); 4443b2aab18SMatthew Ahrens } 4453b2aab18SMatthew Ahrens #endif 446a2afb611SJerry Jelinek VERIFY0(dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx, B_TRUE)); 4473b2aab18SMatthew Ahrens dsl_dataset_rele(ds_head, FTAG); 4483b2aab18SMatthew Ahrens 4493b2aab18SMatthew Ahrens if (ds_prev != NULL) 4503b2aab18SMatthew Ahrens dsl_dataset_rele(ds_prev, FTAG); 4513b2aab18SMatthew Ahrens 4523b2aab18SMatthew Ahrens spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 4533b2aab18SMatthew Ahrens 454c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_next_clones_obj != 0) { 4553b2aab18SMatthew Ahrens uint64_t count; 4563b2aab18SMatthew Ahrens ASSERT0(zap_count(mos, 457c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_clones_obj, &count) && 458c1379625SJustin T. Gibbs count == 0); 4593b2aab18SMatthew Ahrens VERIFY0(dmu_object_free(mos, 460c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_next_clones_obj, tx)); 4613b2aab18SMatthew Ahrens } 462c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_props_obj != 0) 463c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_props_obj, 464c1379625SJustin T. Gibbs tx)); 465c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_userrefs_obj != 0) 466c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, dsl_dataset_phys(ds)->ds_userrefs_obj, 467c1379625SJustin T. Gibbs tx)); 4683b2aab18SMatthew Ahrens dsl_dir_rele(ds->ds_dir, ds); 4693b2aab18SMatthew Ahrens ds->ds_dir = NULL; 4702acef22dSMatthew Ahrens dmu_object_free_zapified(mos, obj, tx); 4713b2aab18SMatthew Ahrens } 4723b2aab18SMatthew Ahrens 4733b2aab18SMatthew Ahrens static void 4743b2aab18SMatthew Ahrens dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx) 4753b2aab18SMatthew Ahrens { 4763b2aab18SMatthew Ahrens dmu_snapshots_destroy_arg_t *dsda = arg; 4773b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 4783b2aab18SMatthew Ahrens nvpair_t *pair; 4793b2aab18SMatthew Ahrens 4803b2aab18SMatthew Ahrens for (pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, NULL); 4813b2aab18SMatthew Ahrens pair != NULL; 4823b2aab18SMatthew Ahrens pair = nvlist_next_nvpair(dsda->dsda_successful_snaps, pair)) { 4833b2aab18SMatthew Ahrens dsl_dataset_t *ds; 4843b2aab18SMatthew Ahrens 4853b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds)); 4863b2aab18SMatthew Ahrens 4873b2aab18SMatthew Ahrens dsl_destroy_snapshot_sync_impl(ds, dsda->dsda_defer, tx); 4883b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 4893b2aab18SMatthew Ahrens } 4903b2aab18SMatthew Ahrens } 4913b2aab18SMatthew Ahrens 4923b2aab18SMatthew Ahrens /* 4933b2aab18SMatthew Ahrens * The semantics of this function are described in the comment above 4943b2aab18SMatthew Ahrens * lzc_destroy_snaps(). To summarize: 4953b2aab18SMatthew Ahrens * 4963b2aab18SMatthew Ahrens * The snapshots must all be in the same pool. 4973b2aab18SMatthew Ahrens * 4983b2aab18SMatthew Ahrens * Snapshots that don't exist will be silently ignored (considered to be 4993b2aab18SMatthew Ahrens * "already deleted"). 5003b2aab18SMatthew Ahrens * 5013b2aab18SMatthew Ahrens * On success, all snaps will be destroyed and this will return 0. 5023b2aab18SMatthew Ahrens * On failure, no snaps will be destroyed, the errlist will be filled in, 5033b2aab18SMatthew Ahrens * and this will return an errno. 5043b2aab18SMatthew Ahrens */ 5053b2aab18SMatthew Ahrens int 5063b2aab18SMatthew Ahrens dsl_destroy_snapshots_nvl(nvlist_t *snaps, boolean_t defer, 5073b2aab18SMatthew Ahrens nvlist_t *errlist) 5083b2aab18SMatthew Ahrens { 5093b2aab18SMatthew Ahrens dmu_snapshots_destroy_arg_t dsda; 5103b2aab18SMatthew Ahrens int error; 5113b2aab18SMatthew Ahrens nvpair_t *pair; 5123b2aab18SMatthew Ahrens 5133b2aab18SMatthew Ahrens pair = nvlist_next_nvpair(snaps, NULL); 5143b2aab18SMatthew Ahrens if (pair == NULL) 5153b2aab18SMatthew Ahrens return (0); 5163b2aab18SMatthew Ahrens 5173b2aab18SMatthew Ahrens dsda.dsda_snaps = snaps; 5183b2aab18SMatthew Ahrens dsda.dsda_successful_snaps = fnvlist_alloc(); 5193b2aab18SMatthew Ahrens dsda.dsda_defer = defer; 5203b2aab18SMatthew Ahrens dsda.dsda_errlist = errlist; 5213b2aab18SMatthew Ahrens 5223b2aab18SMatthew Ahrens error = dsl_sync_task(nvpair_name(pair), 5233b2aab18SMatthew Ahrens dsl_destroy_snapshot_check, dsl_destroy_snapshot_sync, 5247d46dc6cSMatthew Ahrens &dsda, 0, ZFS_SPACE_CHECK_NONE); 5253b2aab18SMatthew Ahrens fnvlist_free(dsda.dsda_successful_snaps); 5263b2aab18SMatthew Ahrens 5273b2aab18SMatthew Ahrens return (error); 5283b2aab18SMatthew Ahrens } 5293b2aab18SMatthew Ahrens 5303b2aab18SMatthew Ahrens int 5313b2aab18SMatthew Ahrens dsl_destroy_snapshot(const char *name, boolean_t defer) 5323b2aab18SMatthew Ahrens { 5333b2aab18SMatthew Ahrens int error; 5343b2aab18SMatthew Ahrens nvlist_t *nvl = fnvlist_alloc(); 5353b2aab18SMatthew Ahrens nvlist_t *errlist = fnvlist_alloc(); 5363b2aab18SMatthew Ahrens 5373b2aab18SMatthew Ahrens fnvlist_add_boolean(nvl, name); 5383b2aab18SMatthew Ahrens error = dsl_destroy_snapshots_nvl(nvl, defer, errlist); 5393b2aab18SMatthew Ahrens fnvlist_free(errlist); 5403b2aab18SMatthew Ahrens fnvlist_free(nvl); 5413b2aab18SMatthew Ahrens return (error); 5423b2aab18SMatthew Ahrens } 5433b2aab18SMatthew Ahrens 5443b2aab18SMatthew Ahrens struct killarg { 5453b2aab18SMatthew Ahrens dsl_dataset_t *ds; 5463b2aab18SMatthew Ahrens dmu_tx_t *tx; 5473b2aab18SMatthew Ahrens }; 5483b2aab18SMatthew Ahrens 5493b2aab18SMatthew Ahrens /* ARGSUSED */ 5503b2aab18SMatthew Ahrens static int 5513b2aab18SMatthew Ahrens kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 5527802d7bfSMatthew Ahrens const zbookmark_phys_t *zb, const dnode_phys_t *dnp, void *arg) 5533b2aab18SMatthew Ahrens { 5543b2aab18SMatthew Ahrens struct killarg *ka = arg; 5553b2aab18SMatthew Ahrens dmu_tx_t *tx = ka->tx; 5563b2aab18SMatthew Ahrens 557a2cdcdd2SPaul Dagnelie if (bp == NULL || BP_IS_HOLE(bp) || BP_IS_EMBEDDED(bp)) 5583b2aab18SMatthew Ahrens return (0); 5593b2aab18SMatthew Ahrens 5603b2aab18SMatthew Ahrens if (zb->zb_level == ZB_ZIL_LEVEL) { 5613b2aab18SMatthew Ahrens ASSERT(zilog != NULL); 5623b2aab18SMatthew Ahrens /* 5633b2aab18SMatthew Ahrens * It's a block in the intent log. It has no 5643b2aab18SMatthew Ahrens * accounting, so just free it. 5653b2aab18SMatthew Ahrens */ 5663b2aab18SMatthew Ahrens dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp); 5673b2aab18SMatthew Ahrens } else { 5683b2aab18SMatthew Ahrens ASSERT(zilog == NULL); 569c1379625SJustin T. Gibbs ASSERT3U(bp->blk_birth, >, 570c1379625SJustin T. Gibbs dsl_dataset_phys(ka->ds)->ds_prev_snap_txg); 5713b2aab18SMatthew Ahrens (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE); 5723b2aab18SMatthew Ahrens } 5733b2aab18SMatthew Ahrens 5743b2aab18SMatthew Ahrens return (0); 5753b2aab18SMatthew Ahrens } 5763b2aab18SMatthew Ahrens 5773b2aab18SMatthew Ahrens static void 5783b2aab18SMatthew Ahrens old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx) 5793b2aab18SMatthew Ahrens { 5803b2aab18SMatthew Ahrens struct killarg ka; 5813b2aab18SMatthew Ahrens 5823b2aab18SMatthew Ahrens /* 5833b2aab18SMatthew Ahrens * Free everything that we point to (that's born after 5843b2aab18SMatthew Ahrens * the previous snapshot, if we are a clone) 5853b2aab18SMatthew Ahrens * 5863b2aab18SMatthew Ahrens * NB: this should be very quick, because we already 5873b2aab18SMatthew Ahrens * freed all the objects in open context. 5883b2aab18SMatthew Ahrens */ 5893b2aab18SMatthew Ahrens ka.ds = ds; 5903b2aab18SMatthew Ahrens ka.tx = tx; 5913b2aab18SMatthew Ahrens VERIFY0(traverse_dataset(ds, 592c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, TRAVERSE_POST, 5933b2aab18SMatthew Ahrens kill_blkptr, &ka)); 594c1379625SJustin T. Gibbs ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 595c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_unique_bytes == 0); 5963b2aab18SMatthew Ahrens } 5973b2aab18SMatthew Ahrens 5983b2aab18SMatthew Ahrens typedef struct dsl_destroy_head_arg { 5993b2aab18SMatthew Ahrens const char *ddha_name; 6003b2aab18SMatthew Ahrens } dsl_destroy_head_arg_t; 6013b2aab18SMatthew Ahrens 6023b2aab18SMatthew Ahrens int 6033b2aab18SMatthew Ahrens dsl_destroy_head_check_impl(dsl_dataset_t *ds, int expected_holds) 6043b2aab18SMatthew Ahrens { 6053b2aab18SMatthew Ahrens int error; 6063b2aab18SMatthew Ahrens uint64_t count; 6073b2aab18SMatthew Ahrens objset_t *mos; 6083b2aab18SMatthew Ahrens 609bc9014e6SJustin Gibbs ASSERT(!ds->ds_is_snapshot); 610bc9014e6SJustin Gibbs if (ds->ds_is_snapshot) 611be6fd75aSMatthew Ahrens return (SET_ERROR(EINVAL)); 6123b2aab18SMatthew Ahrens 6133b2aab18SMatthew Ahrens if (refcount_count(&ds->ds_longholds) != expected_holds) 614be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 6153b2aab18SMatthew Ahrens 6163b2aab18SMatthew Ahrens mos = ds->ds_dir->dd_pool->dp_meta_objset; 6173b2aab18SMatthew Ahrens 6183b2aab18SMatthew Ahrens /* 6193b2aab18SMatthew Ahrens * Can't delete a head dataset if there are snapshots of it. 6203b2aab18SMatthew Ahrens * (Except if the only snapshots are from the branch we cloned 6213b2aab18SMatthew Ahrens * from.) 6223b2aab18SMatthew Ahrens */ 6233b2aab18SMatthew Ahrens if (ds->ds_prev != NULL && 624c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj == ds->ds_object) 625be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 6263b2aab18SMatthew Ahrens 6273b2aab18SMatthew Ahrens /* 6283b2aab18SMatthew Ahrens * Can't delete if there are children of this fs. 6293b2aab18SMatthew Ahrens */ 6303b2aab18SMatthew Ahrens error = zap_count(mos, 631c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_dir)->dd_child_dir_zapobj, &count); 6323b2aab18SMatthew Ahrens if (error != 0) 6333b2aab18SMatthew Ahrens return (error); 6343b2aab18SMatthew Ahrens if (count != 0) 635be6fd75aSMatthew Ahrens return (SET_ERROR(EEXIST)); 6363b2aab18SMatthew Ahrens 6373b2aab18SMatthew Ahrens if (dsl_dir_is_clone(ds->ds_dir) && DS_IS_DEFER_DESTROY(ds->ds_prev) && 638c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 && 6393b2aab18SMatthew Ahrens ds->ds_prev->ds_userrefs == 0) { 6403b2aab18SMatthew Ahrens /* We need to remove the origin snapshot as well. */ 6413b2aab18SMatthew Ahrens if (!refcount_is_zero(&ds->ds_prev->ds_longholds)) 642be6fd75aSMatthew Ahrens return (SET_ERROR(EBUSY)); 6433b2aab18SMatthew Ahrens } 6443b2aab18SMatthew Ahrens return (0); 6453b2aab18SMatthew Ahrens } 6463b2aab18SMatthew Ahrens 6473b2aab18SMatthew Ahrens static int 6483b2aab18SMatthew Ahrens dsl_destroy_head_check(void *arg, dmu_tx_t *tx) 6493b2aab18SMatthew Ahrens { 6503b2aab18SMatthew Ahrens dsl_destroy_head_arg_t *ddha = arg; 6513b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 6523b2aab18SMatthew Ahrens dsl_dataset_t *ds; 6533b2aab18SMatthew Ahrens int error; 6543b2aab18SMatthew Ahrens 6553b2aab18SMatthew Ahrens error = dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds); 6563b2aab18SMatthew Ahrens if (error != 0) 6573b2aab18SMatthew Ahrens return (error); 6583b2aab18SMatthew Ahrens 6593b2aab18SMatthew Ahrens error = dsl_destroy_head_check_impl(ds, 0); 6603b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 6613b2aab18SMatthew Ahrens return (error); 6623b2aab18SMatthew Ahrens } 6633b2aab18SMatthew Ahrens 6643b2aab18SMatthew Ahrens static void 6653b2aab18SMatthew Ahrens dsl_dir_destroy_sync(uint64_t ddobj, dmu_tx_t *tx) 6663b2aab18SMatthew Ahrens { 6673b2aab18SMatthew Ahrens dsl_dir_t *dd; 6683b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 6693b2aab18SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 6703b2aab18SMatthew Ahrens dd_used_t t; 6713b2aab18SMatthew Ahrens 6723b2aab18SMatthew Ahrens ASSERT(RRW_WRITE_HELD(&dmu_tx_pool(tx)->dp_config_rwlock)); 6733b2aab18SMatthew Ahrens 6743b2aab18SMatthew Ahrens VERIFY0(dsl_dir_hold_obj(dp, ddobj, NULL, FTAG, &dd)); 6753b2aab18SMatthew Ahrens 676c1379625SJustin T. Gibbs ASSERT0(dsl_dir_phys(dd)->dd_head_dataset_obj); 6773b2aab18SMatthew Ahrens 678a2afb611SJerry Jelinek /* 679a2afb611SJerry Jelinek * Decrement the filesystem count for all parent filesystems. 680a2afb611SJerry Jelinek * 681a2afb611SJerry Jelinek * When we receive an incremental stream into a filesystem that already 682a2afb611SJerry Jelinek * exists, a temporary clone is created. We never count this temporary 683a2afb611SJerry Jelinek * clone, whose name begins with a '%'. 684a2afb611SJerry Jelinek */ 685a2afb611SJerry Jelinek if (dd->dd_myname[0] != '%' && dd->dd_parent != NULL) 686a2afb611SJerry Jelinek dsl_fs_ss_count_adjust(dd->dd_parent, -1, 687a2afb611SJerry Jelinek DD_FIELD_FILESYSTEM_COUNT, tx); 688a2afb611SJerry Jelinek 6893b2aab18SMatthew Ahrens /* 6903b2aab18SMatthew Ahrens * Remove our reservation. The impl() routine avoids setting the 6913b2aab18SMatthew Ahrens * actual property, which would require the (already destroyed) ds. 6923b2aab18SMatthew Ahrens */ 6933b2aab18SMatthew Ahrens dsl_dir_set_reservation_sync_impl(dd, 0, tx); 6943b2aab18SMatthew Ahrens 695c1379625SJustin T. Gibbs ASSERT0(dsl_dir_phys(dd)->dd_used_bytes); 696c1379625SJustin T. Gibbs ASSERT0(dsl_dir_phys(dd)->dd_reserved); 6973b2aab18SMatthew Ahrens for (t = 0; t < DD_USED_NUM; t++) 698c1379625SJustin T. Gibbs ASSERT0(dsl_dir_phys(dd)->dd_used_breakdown[t]); 6993b2aab18SMatthew Ahrens 700c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_child_dir_zapobj, tx)); 701c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, dsl_dir_phys(dd)->dd_props_zapobj, tx)); 702c1379625SJustin T. Gibbs VERIFY0(dsl_deleg_destroy(mos, dsl_dir_phys(dd)->dd_deleg_zapobj, tx)); 7033b2aab18SMatthew Ahrens VERIFY0(zap_remove(mos, 704c1379625SJustin T. Gibbs dsl_dir_phys(dd->dd_parent)->dd_child_dir_zapobj, 705c1379625SJustin T. Gibbs dd->dd_myname, tx)); 7063b2aab18SMatthew Ahrens 7073b2aab18SMatthew Ahrens dsl_dir_rele(dd, FTAG); 7082acef22dSMatthew Ahrens dmu_object_free_zapified(mos, ddobj, tx); 7093b2aab18SMatthew Ahrens } 7103b2aab18SMatthew Ahrens 7113b2aab18SMatthew Ahrens void 7123b2aab18SMatthew Ahrens dsl_destroy_head_sync_impl(dsl_dataset_t *ds, dmu_tx_t *tx) 7133b2aab18SMatthew Ahrens { 7143b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 7153b2aab18SMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 7163b2aab18SMatthew Ahrens uint64_t obj, ddobj, prevobj = 0; 7173b2aab18SMatthew Ahrens boolean_t rmorigin; 7183b2aab18SMatthew Ahrens 719c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_num_children, <=, 1); 7203b2aab18SMatthew Ahrens ASSERT(ds->ds_prev == NULL || 721c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj != ds->ds_object); 722c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds)->ds_bp.blk_birth, <=, tx->tx_txg); 7233b2aab18SMatthew Ahrens ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock)); 7243b2aab18SMatthew Ahrens 7253b2aab18SMatthew Ahrens /* We need to log before removing it from the namespace. */ 7263b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "destroy", tx, ""); 7273b2aab18SMatthew Ahrens 7283b2aab18SMatthew Ahrens rmorigin = (dsl_dir_is_clone(ds->ds_dir) && 7293b2aab18SMatthew Ahrens DS_IS_DEFER_DESTROY(ds->ds_prev) && 730c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_num_children == 2 && 7313b2aab18SMatthew Ahrens ds->ds_prev->ds_userrefs == 0); 7323b2aab18SMatthew Ahrens 7335d7b4d43SMatthew Ahrens /* Remove our reservation. */ 7343b2aab18SMatthew Ahrens if (ds->ds_reserved != 0) { 7353b2aab18SMatthew Ahrens dsl_dataset_set_refreservation_sync_impl(ds, 7363b2aab18SMatthew Ahrens (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), 7373b2aab18SMatthew Ahrens 0, tx); 7383b2aab18SMatthew Ahrens ASSERT0(ds->ds_reserved); 7393b2aab18SMatthew Ahrens } 7403b2aab18SMatthew Ahrens 741*ca0cc391SMatthew Ahrens obj = ds->ds_object; 742b5152584SMatthew Ahrens 743*ca0cc391SMatthew Ahrens for (spa_feature_t f = 0; f < SPA_FEATURES; f++) { 744*ca0cc391SMatthew Ahrens if (ds->ds_feature_inuse[f]) { 745*ca0cc391SMatthew Ahrens dsl_dataset_deactivate_feature(obj, f, tx); 746*ca0cc391SMatthew Ahrens ds->ds_feature_inuse[f] = B_FALSE; 747*ca0cc391SMatthew Ahrens } 748*ca0cc391SMatthew Ahrens } 7493b2aab18SMatthew Ahrens 750*ca0cc391SMatthew Ahrens dsl_scan_ds_destroyed(ds, tx); 7513b2aab18SMatthew Ahrens 752c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) { 7533b2aab18SMatthew Ahrens /* This is a clone */ 7543b2aab18SMatthew Ahrens ASSERT(ds->ds_prev != NULL); 755c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_next_snap_obj, !=, 756c1379625SJustin T. Gibbs obj); 757c1379625SJustin T. Gibbs ASSERT0(dsl_dataset_phys(ds)->ds_next_snap_obj); 7583b2aab18SMatthew Ahrens 7593b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 760c1379625SJustin T. Gibbs if (dsl_dataset_phys(ds->ds_prev)->ds_next_clones_obj != 0) { 7613b2aab18SMatthew Ahrens dsl_dataset_remove_from_next_clones(ds->ds_prev, 7623b2aab18SMatthew Ahrens obj, tx); 7633b2aab18SMatthew Ahrens } 7643b2aab18SMatthew Ahrens 765c1379625SJustin T. Gibbs ASSERT3U(dsl_dataset_phys(ds->ds_prev)->ds_num_children, >, 1); 766c1379625SJustin T. Gibbs dsl_dataset_phys(ds->ds_prev)->ds_num_children--; 7673b2aab18SMatthew Ahrens } 7683b2aab18SMatthew Ahrens 7693b2aab18SMatthew Ahrens /* 7703b2aab18SMatthew Ahrens * Destroy the deadlist. Unless it's a clone, the 7713b2aab18SMatthew Ahrens * deadlist should be empty. (If it's a clone, it's 7723b2aab18SMatthew Ahrens * safe to ignore the deadlist contents.) 7733b2aab18SMatthew Ahrens */ 7743b2aab18SMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 775c1379625SJustin T. Gibbs dsl_deadlist_free(mos, dsl_dataset_phys(ds)->ds_deadlist_obj, tx); 7763b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 777c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_deadlist_obj = 0; 7783b2aab18SMatthew Ahrens 7792acef22dSMatthew Ahrens objset_t *os; 7803b2aab18SMatthew Ahrens VERIFY0(dmu_objset_from_ds(ds, &os)); 7813b2aab18SMatthew Ahrens 7822acef22dSMatthew Ahrens if (!spa_feature_is_enabled(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY)) { 7833b2aab18SMatthew Ahrens old_synchronous_dataset_destroy(ds, tx); 7843b2aab18SMatthew Ahrens } else { 7853b2aab18SMatthew Ahrens /* 7863b2aab18SMatthew Ahrens * Move the bptree into the pool's list of trees to 7873b2aab18SMatthew Ahrens * clean up and update space accounting information. 7883b2aab18SMatthew Ahrens */ 7893b2aab18SMatthew Ahrens uint64_t used, comp, uncomp; 7903b2aab18SMatthew Ahrens 7913b2aab18SMatthew Ahrens zil_destroy_sync(dmu_objset_zil(os), tx); 7923b2aab18SMatthew Ahrens 7932acef22dSMatthew Ahrens if (!spa_feature_is_active(dp->dp_spa, 7942acef22dSMatthew Ahrens SPA_FEATURE_ASYNC_DESTROY)) { 7954a923759SGeorge Wilson dsl_scan_t *scn = dp->dp_scan; 7962acef22dSMatthew Ahrens spa_feature_incr(dp->dp_spa, SPA_FEATURE_ASYNC_DESTROY, 7972acef22dSMatthew Ahrens tx); 7983b2aab18SMatthew Ahrens dp->dp_bptree_obj = bptree_alloc(mos, tx); 7993b2aab18SMatthew Ahrens VERIFY0(zap_add(mos, 8003b2aab18SMatthew Ahrens DMU_POOL_DIRECTORY_OBJECT, 8013b2aab18SMatthew Ahrens DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1, 8023b2aab18SMatthew Ahrens &dp->dp_bptree_obj, tx)); 8034a923759SGeorge Wilson ASSERT(!scn->scn_async_destroying); 8044a923759SGeorge Wilson scn->scn_async_destroying = B_TRUE; 8053b2aab18SMatthew Ahrens } 8063b2aab18SMatthew Ahrens 807c1379625SJustin T. Gibbs used = dsl_dir_phys(ds->ds_dir)->dd_used_bytes; 808c1379625SJustin T. Gibbs comp = dsl_dir_phys(ds->ds_dir)->dd_compressed_bytes; 809c1379625SJustin T. Gibbs uncomp = dsl_dir_phys(ds->ds_dir)->dd_uncompressed_bytes; 8103b2aab18SMatthew Ahrens 8113b2aab18SMatthew Ahrens ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 812c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_unique_bytes == used); 8133b2aab18SMatthew Ahrens 8143b2aab18SMatthew Ahrens bptree_add(mos, dp->dp_bptree_obj, 815c1379625SJustin T. Gibbs &dsl_dataset_phys(ds)->ds_bp, 816c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_prev_snap_txg, 8173b2aab18SMatthew Ahrens used, comp, uncomp, tx); 8183b2aab18SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 8193b2aab18SMatthew Ahrens -used, -comp, -uncomp, tx); 8203b2aab18SMatthew Ahrens dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD, 8213b2aab18SMatthew Ahrens used, comp, uncomp, tx); 8223b2aab18SMatthew Ahrens } 8233b2aab18SMatthew Ahrens 8243b2aab18SMatthew Ahrens if (ds->ds_prev != NULL) { 8253b2aab18SMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 8263b2aab18SMatthew Ahrens VERIFY0(zap_remove_int(mos, 827c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_prev->ds_dir)->dd_clones, 8283b2aab18SMatthew Ahrens ds->ds_object, tx)); 8293b2aab18SMatthew Ahrens } 8303b2aab18SMatthew Ahrens prevobj = ds->ds_prev->ds_object; 8313b2aab18SMatthew Ahrens dsl_dataset_rele(ds->ds_prev, ds); 8323b2aab18SMatthew Ahrens ds->ds_prev = NULL; 8333b2aab18SMatthew Ahrens } 8343b2aab18SMatthew Ahrens 8353b2aab18SMatthew Ahrens /* 8363b2aab18SMatthew Ahrens * This must be done after the dsl_traverse(), because it will 8373b2aab18SMatthew Ahrens * re-open the objset. 8383b2aab18SMatthew Ahrens */ 8393b2aab18SMatthew Ahrens if (ds->ds_objset) { 8403b2aab18SMatthew Ahrens dmu_objset_evict(ds->ds_objset); 8413b2aab18SMatthew Ahrens ds->ds_objset = NULL; 8423b2aab18SMatthew Ahrens } 8433b2aab18SMatthew Ahrens 8443b2aab18SMatthew Ahrens /* Erase the link in the dir */ 8453b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 846c1379625SJustin T. Gibbs dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj = 0; 8473b2aab18SMatthew Ahrens ddobj = ds->ds_dir->dd_object; 848c1379625SJustin T. Gibbs ASSERT(dsl_dataset_phys(ds)->ds_snapnames_zapobj != 0); 849c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, 850c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_snapnames_zapobj, tx)); 8513b2aab18SMatthew Ahrens 85278f17100SMatthew Ahrens if (ds->ds_bookmarks != 0) { 853c1379625SJustin T. Gibbs VERIFY0(zap_destroy(mos, ds->ds_bookmarks, tx)); 85478f17100SMatthew Ahrens spa_feature_decr(dp->dp_spa, SPA_FEATURE_BOOKMARKS, tx); 85578f17100SMatthew Ahrens } 85678f17100SMatthew Ahrens 8573b2aab18SMatthew Ahrens spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 8583b2aab18SMatthew Ahrens 859c1379625SJustin T. Gibbs ASSERT0(dsl_dataset_phys(ds)->ds_next_clones_obj); 860c1379625SJustin T. Gibbs ASSERT0(dsl_dataset_phys(ds)->ds_props_obj); 861c1379625SJustin T. Gibbs ASSERT0(dsl_dataset_phys(ds)->ds_userrefs_obj); 8623b2aab18SMatthew Ahrens dsl_dir_rele(ds->ds_dir, ds); 8633b2aab18SMatthew Ahrens ds->ds_dir = NULL; 8642acef22dSMatthew Ahrens dmu_object_free_zapified(mos, obj, tx); 8653b2aab18SMatthew Ahrens 8663b2aab18SMatthew Ahrens dsl_dir_destroy_sync(ddobj, tx); 8673b2aab18SMatthew Ahrens 8683b2aab18SMatthew Ahrens if (rmorigin) { 8693b2aab18SMatthew Ahrens dsl_dataset_t *prev; 8703b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold_obj(dp, prevobj, FTAG, &prev)); 8713b2aab18SMatthew Ahrens dsl_destroy_snapshot_sync_impl(prev, B_FALSE, tx); 8723b2aab18SMatthew Ahrens dsl_dataset_rele(prev, FTAG); 8733b2aab18SMatthew Ahrens } 8743b2aab18SMatthew Ahrens } 8753b2aab18SMatthew Ahrens 8763b2aab18SMatthew Ahrens static void 8773b2aab18SMatthew Ahrens dsl_destroy_head_sync(void *arg, dmu_tx_t *tx) 8783b2aab18SMatthew Ahrens { 8793b2aab18SMatthew Ahrens dsl_destroy_head_arg_t *ddha = arg; 8803b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 8813b2aab18SMatthew Ahrens dsl_dataset_t *ds; 8823b2aab18SMatthew Ahrens 8833b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds)); 8843b2aab18SMatthew Ahrens dsl_destroy_head_sync_impl(ds, tx); 8853b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 8863b2aab18SMatthew Ahrens } 8873b2aab18SMatthew Ahrens 8883b2aab18SMatthew Ahrens static void 8893b2aab18SMatthew Ahrens dsl_destroy_head_begin_sync(void *arg, dmu_tx_t *tx) 8903b2aab18SMatthew Ahrens { 8913b2aab18SMatthew Ahrens dsl_destroy_head_arg_t *ddha = arg; 8923b2aab18SMatthew Ahrens dsl_pool_t *dp = dmu_tx_pool(tx); 8933b2aab18SMatthew Ahrens dsl_dataset_t *ds; 8943b2aab18SMatthew Ahrens 8953b2aab18SMatthew Ahrens VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds)); 8963b2aab18SMatthew Ahrens 8973b2aab18SMatthew Ahrens /* Mark it as inconsistent on-disk, in case we crash */ 8983b2aab18SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 899c1379625SJustin T. Gibbs dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_INCONSISTENT; 9003b2aab18SMatthew Ahrens 9013b2aab18SMatthew Ahrens spa_history_log_internal_ds(ds, "destroy begin", tx, ""); 9023b2aab18SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 9033b2aab18SMatthew Ahrens } 9043b2aab18SMatthew Ahrens 9053b2aab18SMatthew Ahrens int 9063b2aab18SMatthew Ahrens dsl_destroy_head(const char *name) 9073b2aab18SMatthew Ahrens { 9083b2aab18SMatthew Ahrens dsl_destroy_head_arg_t ddha; 9093b2aab18SMatthew Ahrens int error; 9103b2aab18SMatthew Ahrens spa_t *spa; 9113b2aab18SMatthew Ahrens boolean_t isenabled; 9123b2aab18SMatthew Ahrens 9133b2aab18SMatthew Ahrens #ifdef _KERNEL 9143b2aab18SMatthew Ahrens zfs_destroy_unmount_origin(name); 9153b2aab18SMatthew Ahrens #endif 9163b2aab18SMatthew Ahrens 9173b2aab18SMatthew Ahrens error = spa_open(name, &spa, FTAG); 9183b2aab18SMatthew Ahrens if (error != 0) 9193b2aab18SMatthew Ahrens return (error); 9202acef22dSMatthew Ahrens isenabled = spa_feature_is_enabled(spa, SPA_FEATURE_ASYNC_DESTROY); 9213b2aab18SMatthew Ahrens spa_close(spa, FTAG); 9223b2aab18SMatthew Ahrens 9233b2aab18SMatthew Ahrens ddha.ddha_name = name; 9243b2aab18SMatthew Ahrens 9253b2aab18SMatthew Ahrens if (!isenabled) { 9263b2aab18SMatthew Ahrens objset_t *os; 9273b2aab18SMatthew Ahrens 9283b2aab18SMatthew Ahrens error = dsl_sync_task(name, dsl_destroy_head_check, 9297d46dc6cSMatthew Ahrens dsl_destroy_head_begin_sync, &ddha, 9307d46dc6cSMatthew Ahrens 0, ZFS_SPACE_CHECK_NONE); 9313b2aab18SMatthew Ahrens if (error != 0) 9323b2aab18SMatthew Ahrens return (error); 9333b2aab18SMatthew Ahrens 9343b2aab18SMatthew Ahrens /* 9353b2aab18SMatthew Ahrens * Head deletion is processed in one txg on old pools; 9363b2aab18SMatthew Ahrens * remove the objects from open context so that the txg sync 9373b2aab18SMatthew Ahrens * is not too long. 9383b2aab18SMatthew Ahrens */ 9393b2aab18SMatthew Ahrens error = dmu_objset_own(name, DMU_OST_ANY, B_FALSE, FTAG, &os); 9403b2aab18SMatthew Ahrens if (error == 0) { 9413b2aab18SMatthew Ahrens uint64_t prev_snap_txg = 942c1379625SJustin T. Gibbs dsl_dataset_phys(dmu_objset_ds(os))-> 943c1379625SJustin T. Gibbs ds_prev_snap_txg; 9443b2aab18SMatthew Ahrens for (uint64_t obj = 0; error == 0; 9453b2aab18SMatthew Ahrens error = dmu_object_next(os, &obj, FALSE, 9463b2aab18SMatthew Ahrens prev_snap_txg)) 947713d6c20SMatthew Ahrens (void) dmu_free_long_object(os, obj); 9483b2aab18SMatthew Ahrens /* sync out all frees */ 9493b2aab18SMatthew Ahrens txg_wait_synced(dmu_objset_pool(os), 0); 9503b2aab18SMatthew Ahrens dmu_objset_disown(os, FTAG); 9513b2aab18SMatthew Ahrens } 9523b2aab18SMatthew Ahrens } 9533b2aab18SMatthew Ahrens 9543b2aab18SMatthew Ahrens return (dsl_sync_task(name, dsl_destroy_head_check, 9557d46dc6cSMatthew Ahrens dsl_destroy_head_sync, &ddha, 0, ZFS_SPACE_CHECK_NONE)); 9563b2aab18SMatthew Ahrens } 9573b2aab18SMatthew Ahrens 9583b2aab18SMatthew Ahrens /* 9593b2aab18SMatthew Ahrens * Note, this function is used as the callback for dmu_objset_find(). We 9603b2aab18SMatthew Ahrens * always return 0 so that we will continue to find and process 9613b2aab18SMatthew Ahrens * inconsistent datasets, even if we encounter an error trying to 9623b2aab18SMatthew Ahrens * process one of them. 9633b2aab18SMatthew Ahrens */ 9643b2aab18SMatthew Ahrens /* ARGSUSED */ 9653b2aab18SMatthew Ahrens int 9663b2aab18SMatthew Ahrens dsl_destroy_inconsistent(const char *dsname, void *arg) 9673b2aab18SMatthew Ahrens { 9683b2aab18SMatthew Ahrens objset_t *os; 9693b2aab18SMatthew Ahrens 9703b2aab18SMatthew Ahrens if (dmu_objset_hold(dsname, FTAG, &os) == 0) { 9713b2aab18SMatthew Ahrens boolean_t inconsistent = DS_IS_INCONSISTENT(dmu_objset_ds(os)); 9723b2aab18SMatthew Ahrens dmu_objset_rele(os, FTAG); 9733b2aab18SMatthew Ahrens if (inconsistent) 9743b2aab18SMatthew Ahrens (void) dsl_destroy_head(dsname); 9753b2aab18SMatthew Ahrens } 9763b2aab18SMatthew Ahrens return (0); 9773b2aab18SMatthew Ahrens } 978