1fa9e4066Sahrens /* 2fa9e4066Sahrens * CDDL HEADER START 3fa9e4066Sahrens * 4fa9e4066Sahrens * The contents of this file are subject to the terms of the 5ea8dc4b6Seschrock * Common Development and Distribution License (the "License"). 6ea8dc4b6Seschrock * You may not use this file except in compliance with the License. 7fa9e4066Sahrens * 8fa9e4066Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9fa9e4066Sahrens * or http://www.opensolaris.org/os/licensing. 10fa9e4066Sahrens * See the License for the specific language governing permissions 11fa9e4066Sahrens * and limitations under the License. 12fa9e4066Sahrens * 13fa9e4066Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14fa9e4066Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15fa9e4066Sahrens * If applicable, add the following below this CDDL HEADER, with the 16fa9e4066Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17fa9e4066Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18fa9e4066Sahrens * 19fa9e4066Sahrens * CDDL HEADER END 20fa9e4066Sahrens */ 21fa9e4066Sahrens /* 225afc78aaSChris Kirby * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved. 23fa9e4066Sahrens */ 24fa9e4066Sahrens 25fa9e4066Sahrens #include <sys/dmu_objset.h> 26fa9e4066Sahrens #include <sys/dsl_dataset.h> 27fa9e4066Sahrens #include <sys/dsl_dir.h> 2899653d4eSeschrock #include <sys/dsl_prop.h> 291d452cf5Sahrens #include <sys/dsl_synctask.h> 30fa9e4066Sahrens #include <sys/dmu_traverse.h> 31fa9e4066Sahrens #include <sys/dmu_tx.h> 32fa9e4066Sahrens #include <sys/arc.h> 33fa9e4066Sahrens #include <sys/zio.h> 34fa9e4066Sahrens #include <sys/zap.h> 35fa9e4066Sahrens #include <sys/unique.h> 36fa9e4066Sahrens #include <sys/zfs_context.h> 37cdf5b4caSmmusante #include <sys/zfs_ioctl.h> 38ecd6cf80Smarks #include <sys/spa.h> 39088f3894Sahrens #include <sys/zfs_znode.h> 40c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 41842727c2SChris Kirby #include <sys/zvol.h> 423f9d6ad7SLin Ling #include <sys/dsl_scan.h> 43cde58dbcSMatthew Ahrens #include <sys/dsl_deadlist.h> 44fa9e4066Sahrens 45745cd3c5Smaybee static char *dsl_reaper = "the grim reaper"; 46745cd3c5Smaybee 471d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 481d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 49a9799022Sck static dsl_syncfunc_t dsl_dataset_set_reservation_sync; 50e1930233Sbonwick 51cde58dbcSMatthew Ahrens #define SWITCH64(x, y) \ 52cde58dbcSMatthew Ahrens { \ 53cde58dbcSMatthew Ahrens uint64_t __tmp = (x); \ 54cde58dbcSMatthew Ahrens (x) = (y); \ 55cde58dbcSMatthew Ahrens (y) = __tmp; \ 56cde58dbcSMatthew Ahrens } 57cde58dbcSMatthew Ahrens 5855434c77Sek #define DS_REF_MAX (1ULL << 62) 59fa9e4066Sahrens 60fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 61fa9e4066Sahrens 62745cd3c5Smaybee #define DSL_DATASET_IS_DESTROYED(ds) ((ds)->ds_owner == dsl_reaper) 63745cd3c5Smaybee 64fa9e4066Sahrens 65a9799022Sck /* 66a9799022Sck * Figure out how much of this delta should be propogated to the dsl_dir 67a9799022Sck * layer. If there's a refreservation, that space has already been 68a9799022Sck * partially accounted for in our ancestors. 69a9799022Sck */ 70a9799022Sck static int64_t 71a9799022Sck parent_delta(dsl_dataset_t *ds, int64_t delta) 72a9799022Sck { 73a9799022Sck uint64_t old_bytes, new_bytes; 74a9799022Sck 75a9799022Sck if (ds->ds_reserved == 0) 76a9799022Sck return (delta); 77a9799022Sck 78a9799022Sck old_bytes = MAX(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 79a9799022Sck new_bytes = MAX(ds->ds_phys->ds_unique_bytes + delta, ds->ds_reserved); 80a9799022Sck 81a9799022Sck ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta)); 82a9799022Sck return (new_bytes - old_bytes); 83a9799022Sck } 84fa9e4066Sahrens 85fa9e4066Sahrens void 86b24ab676SJeff Bonwick dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx) 87fa9e4066Sahrens { 88b24ab676SJeff Bonwick int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp); 89fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 90fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 91a9799022Sck int64_t delta; 92fa9e4066Sahrens 933f9d6ad7SLin Ling dprintf_bp(bp, "ds=%p", ds); 94fa9e4066Sahrens 95fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 96fa9e4066Sahrens /* It could have been compressed away to nothing */ 97fa9e4066Sahrens if (BP_IS_HOLE(bp)) 98fa9e4066Sahrens return; 99fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 100fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 101fa9e4066Sahrens if (ds == NULL) { 102fa9e4066Sahrens /* 103fa9e4066Sahrens * Account for the meta-objset space in its placeholder 104fa9e4066Sahrens * dsl_dir. 105fa9e4066Sahrens */ 106fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 10774e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 108fa9e4066Sahrens used, compressed, uncompressed, tx); 109fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 110fa9e4066Sahrens return; 111fa9e4066Sahrens } 112fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1133f9d6ad7SLin Ling 11402c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 115fa9e4066Sahrens mutex_enter(&ds->ds_lock); 116a9799022Sck delta = parent_delta(ds, used); 117fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 118fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 119fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 120fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 121fa9e4066Sahrens mutex_exit(&ds->ds_lock); 12274e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, 12374e7dc98SMatthew Ahrens compressed, uncompressed, tx); 12474e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used - delta, 12574e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 12602c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 127fa9e4066Sahrens } 128fa9e4066Sahrens 129cdb0ab79Smaybee int 130b24ab676SJeff Bonwick dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx, 131b24ab676SJeff Bonwick boolean_t async) 132fa9e4066Sahrens { 133fa9e4066Sahrens if (BP_IS_HOLE(bp)) 134cdb0ab79Smaybee return (0); 135fa9e4066Sahrens 136b24ab676SJeff Bonwick ASSERT(dmu_tx_is_syncing(tx)); 137b24ab676SJeff Bonwick ASSERT(bp->blk_birth <= tx->tx_txg); 138b24ab676SJeff Bonwick 139b24ab676SJeff Bonwick int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp); 140b24ab676SJeff Bonwick int compressed = BP_GET_PSIZE(bp); 141b24ab676SJeff Bonwick int uncompressed = BP_GET_UCSIZE(bp); 142b24ab676SJeff Bonwick 143fa9e4066Sahrens ASSERT(used > 0); 144fa9e4066Sahrens if (ds == NULL) { 145fa9e4066Sahrens /* 146fa9e4066Sahrens * Account for the meta-objset space in its placeholder 147fa9e4066Sahrens * dataset. 148fa9e4066Sahrens */ 149b24ab676SJeff Bonwick dsl_free(tx->tx_pool, tx->tx_txg, bp); 150fa9e4066Sahrens 15174e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 152fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 153fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 154cdb0ab79Smaybee return (used); 155fa9e4066Sahrens } 156fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 157fa9e4066Sahrens 15874e7dc98SMatthew Ahrens ASSERT(!dsl_dataset_is_snapshot(ds)); 159fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 160fa9e4066Sahrens 161fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 162a9799022Sck int64_t delta; 163c717a561Smaybee 1643f9d6ad7SLin Ling dprintf_bp(bp, "freeing ds=%llu", ds->ds_object); 165b24ab676SJeff Bonwick dsl_free(tx->tx_pool, tx->tx_txg, bp); 166fa9e4066Sahrens 16702c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 168fa9e4066Sahrens mutex_enter(&ds->ds_lock); 169a9799022Sck ASSERT(ds->ds_phys->ds_unique_bytes >= used || 170a9799022Sck !DS_UNIQUE_IS_ACCURATE(ds)); 171a9799022Sck delta = parent_delta(ds, -used); 172fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 173fa9e4066Sahrens mutex_exit(&ds->ds_lock); 17474e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 175a9799022Sck delta, -compressed, -uncompressed, tx); 17674e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, -used - delta, 17774e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 17802c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 179fa9e4066Sahrens } else { 180fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 181b24ab676SJeff Bonwick if (async) { 182b24ab676SJeff Bonwick /* 183b24ab676SJeff Bonwick * We are here as part of zio's write done callback, 184b24ab676SJeff Bonwick * which means we're a zio interrupt thread. We can't 185cde58dbcSMatthew Ahrens * call dsl_deadlist_insert() now because it may block 186b24ab676SJeff Bonwick * waiting for I/O. Instead, put bp on the deferred 187b24ab676SJeff Bonwick * queue and let dsl_pool_sync() finish the job. 188b24ab676SJeff Bonwick */ 189cde58dbcSMatthew Ahrens bplist_append(&ds->ds_pending_deadlist, bp); 190b24ab676SJeff Bonwick } else { 191cde58dbcSMatthew Ahrens dsl_deadlist_insert(&ds->ds_deadlist, bp, tx); 192b24ab676SJeff Bonwick } 193a4611edeSahrens ASSERT3U(ds->ds_prev->ds_object, ==, 194a4611edeSahrens ds->ds_phys->ds_prev_snap_obj); 195a4611edeSahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 196fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 197a4611edeSahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 198a4611edeSahrens ds->ds_object && bp->blk_birth > 199a4611edeSahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 200a4611edeSahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 201a4611edeSahrens mutex_enter(&ds->ds_prev->ds_lock); 202a4611edeSahrens ds->ds_prev->ds_phys->ds_unique_bytes += used; 203a4611edeSahrens mutex_exit(&ds->ds_prev->ds_lock); 204fa9e4066Sahrens } 2053f9d6ad7SLin Ling if (bp->blk_birth > ds->ds_dir->dd_origin_txg) { 20674e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used, 20774e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 20874e7dc98SMatthew Ahrens } 209fa9e4066Sahrens } 210fa9e4066Sahrens mutex_enter(&ds->ds_lock); 211fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 212fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 213fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 214fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 215fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 216fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 217fa9e4066Sahrens mutex_exit(&ds->ds_lock); 218cdb0ab79Smaybee 219cdb0ab79Smaybee return (used); 220fa9e4066Sahrens } 221fa9e4066Sahrens 222ea8dc4b6Seschrock uint64_t 223ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 224fa9e4066Sahrens { 225a2eea2e1Sahrens uint64_t trysnap = 0; 226a2eea2e1Sahrens 227fa9e4066Sahrens if (ds == NULL) 228ea8dc4b6Seschrock return (0); 229fa9e4066Sahrens /* 230fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 231fa9e4066Sahrens * incorrect FALSE return, which would only result in an 232fa9e4066Sahrens * overestimation of the amount of space that an operation would 233fa9e4066Sahrens * consume, which is OK. 234fa9e4066Sahrens * 235fa9e4066Sahrens * There's also a small window where we could miss a pending 236fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 237fa9e4066Sahrens * phase. So this should only be used as a guess. 238fa9e4066Sahrens */ 239a2eea2e1Sahrens if (ds->ds_trysnap_txg > 240a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 241a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 242a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 243ea8dc4b6Seschrock } 244ea8dc4b6Seschrock 2453d692628SSanjeev Bagewadi boolean_t 246c7cd2421SGeorge Wilson dsl_dataset_block_freeable(dsl_dataset_t *ds, const blkptr_t *bp, 247c7cd2421SGeorge Wilson uint64_t blk_birth) 248ea8dc4b6Seschrock { 249c7cd2421SGeorge Wilson if (blk_birth <= dsl_dataset_prev_snap_txg(ds)) 250c7cd2421SGeorge Wilson return (B_FALSE); 251c7cd2421SGeorge Wilson 252837b568bSGeorge Wilson ddt_prefetch(dsl_dataset_get_spa(ds), bp); 253c7cd2421SGeorge Wilson 254c7cd2421SGeorge Wilson return (B_TRUE); 255fa9e4066Sahrens } 256fa9e4066Sahrens 257fa9e4066Sahrens /* ARGSUSED */ 258fa9e4066Sahrens static void 259fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 260fa9e4066Sahrens { 261fa9e4066Sahrens dsl_dataset_t *ds = dsv; 262fa9e4066Sahrens 263745cd3c5Smaybee ASSERT(ds->ds_owner == NULL || DSL_DATASET_IS_DESTROYED(ds)); 264fa9e4066Sahrens 26591ebeef5Sahrens unique_remove(ds->ds_fsid_guid); 266fa9e4066Sahrens 267503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) 268503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 269fa9e4066Sahrens 270fa9e4066Sahrens if (ds->ds_prev) { 271745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 272fa9e4066Sahrens ds->ds_prev = NULL; 273fa9e4066Sahrens } 274fa9e4066Sahrens 275cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 276cde58dbcSMatthew Ahrens if (db != NULL) { 277cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 278cde58dbcSMatthew Ahrens } else { 279cde58dbcSMatthew Ahrens ASSERT(ds->ds_deadlist.dl_dbuf == NULL); 280cde58dbcSMatthew Ahrens ASSERT(!ds->ds_deadlist.dl_oldfmt); 281cde58dbcSMatthew Ahrens } 282745cd3c5Smaybee if (ds->ds_dir) 283745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 284fa9e4066Sahrens 28591ebeef5Sahrens ASSERT(!list_link_active(&ds->ds_synced_link)); 286fa9e4066Sahrens 2875ad82045Snd mutex_destroy(&ds->ds_lock); 288f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 28991ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 290745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 291745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 2925ad82045Snd 293fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 294fa9e4066Sahrens } 295fa9e4066Sahrens 296ea8dc4b6Seschrock static int 297fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 298fa9e4066Sahrens { 299fa9e4066Sahrens dsl_dataset_phys_t *headphys; 300fa9e4066Sahrens int err; 301fa9e4066Sahrens dmu_buf_t *headdbuf; 302fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 303fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 304fa9e4066Sahrens 305fa9e4066Sahrens if (ds->ds_snapname[0]) 306ea8dc4b6Seschrock return (0); 307fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 308ea8dc4b6Seschrock return (0); 309fa9e4066Sahrens 310ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 311ea8dc4b6Seschrock FTAG, &headdbuf); 312ea8dc4b6Seschrock if (err) 313ea8dc4b6Seschrock return (err); 314fa9e4066Sahrens headphys = headdbuf->db_data; 315fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 316e7437265Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); 317ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 318ea8dc4b6Seschrock return (err); 319fa9e4066Sahrens } 320fa9e4066Sahrens 321ab04eb8eStimh static int 322745cd3c5Smaybee dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value) 323ab04eb8eStimh { 324745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 325745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 326ab04eb8eStimh matchtype_t mt; 327ab04eb8eStimh int err; 328ab04eb8eStimh 329745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 330ab04eb8eStimh mt = MT_FIRST; 331ab04eb8eStimh else 332ab04eb8eStimh mt = MT_EXACT; 333ab04eb8eStimh 334745cd3c5Smaybee err = zap_lookup_norm(mos, snapobj, name, 8, 1, 335ab04eb8eStimh value, mt, NULL, 0, NULL); 336ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 337745cd3c5Smaybee err = zap_lookup(mos, snapobj, name, 8, 1, value); 338ab04eb8eStimh return (err); 339ab04eb8eStimh } 340ab04eb8eStimh 341ab04eb8eStimh static int 342745cd3c5Smaybee dsl_dataset_snap_remove(dsl_dataset_t *ds, char *name, dmu_tx_t *tx) 343ab04eb8eStimh { 344745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 345745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 346ab04eb8eStimh matchtype_t mt; 347ab04eb8eStimh int err; 348ab04eb8eStimh 34971eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 35071eb0538SChris Kirby 351745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 352ab04eb8eStimh mt = MT_FIRST; 353ab04eb8eStimh else 354ab04eb8eStimh mt = MT_EXACT; 355ab04eb8eStimh 356745cd3c5Smaybee err = zap_remove_norm(mos, snapobj, name, mt, tx); 357ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 358745cd3c5Smaybee err = zap_remove(mos, snapobj, name, tx); 359ab04eb8eStimh return (err); 360ab04eb8eStimh } 361ab04eb8eStimh 362745cd3c5Smaybee static int 363745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag, 364745cd3c5Smaybee dsl_dataset_t **dsp) 365fa9e4066Sahrens { 366fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 367fa9e4066Sahrens dmu_buf_t *dbuf; 368fa9e4066Sahrens dsl_dataset_t *ds; 369ea8dc4b6Seschrock int err; 370*a7f53a56SChris Kirby dmu_object_info_t doi; 371fa9e4066Sahrens 372fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 373fa9e4066Sahrens dsl_pool_sync_context(dp)); 374fa9e4066Sahrens 375ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 376ea8dc4b6Seschrock if (err) 377ea8dc4b6Seschrock return (err); 378*a7f53a56SChris Kirby 379*a7f53a56SChris Kirby /* Make sure dsobj has the correct object type. */ 380*a7f53a56SChris Kirby dmu_object_info_from_db(dbuf, &doi); 381*a7f53a56SChris Kirby if (doi.doi_type != DMU_OT_DSL_DATASET) 382*a7f53a56SChris Kirby return (EINVAL); 383*a7f53a56SChris Kirby 384fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 385fa9e4066Sahrens if (ds == NULL) { 386fa9e4066Sahrens dsl_dataset_t *winner; 387fa9e4066Sahrens 388fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 389fa9e4066Sahrens ds->ds_dbuf = dbuf; 390fa9e4066Sahrens ds->ds_object = dsobj; 391fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 392fa9e4066Sahrens 3935ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 394f4b94bdeSMatthew Ahrens mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL); 39591ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 396745cd3c5Smaybee rw_init(&ds->ds_rwlock, 0, 0, 0); 397745cd3c5Smaybee cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL); 3985ad82045Snd 399cde58dbcSMatthew Ahrens bplist_create(&ds->ds_pending_deadlist); 400cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, 401fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 402cde58dbcSMatthew Ahrens 403ea8dc4b6Seschrock if (err == 0) { 404ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 405ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 406ea8dc4b6Seschrock } 407ea8dc4b6Seschrock if (err) { 4085ad82045Snd mutex_destroy(&ds->ds_lock); 409f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 41091ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 411745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 412745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 413cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 414cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 415ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 416ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 417ea8dc4b6Seschrock return (err); 418ea8dc4b6Seschrock } 419fa9e4066Sahrens 42074e7dc98SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 421fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 422fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 423745cd3c5Smaybee err = dsl_dataset_get_ref(dp, 424745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 425745cd3c5Smaybee ds, &ds->ds_prev); 426fa9e4066Sahrens } 427842727c2SChris Kirby } else { 428842727c2SChris Kirby if (zfs_flags & ZFS_DEBUG_SNAPNAMES) 429842727c2SChris Kirby err = dsl_dataset_get_snapname(ds); 430842727c2SChris Kirby if (err == 0 && ds->ds_phys->ds_userrefs_obj != 0) { 431842727c2SChris Kirby err = zap_count( 432842727c2SChris Kirby ds->ds_dir->dd_pool->dp_meta_objset, 433842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj, 434842727c2SChris Kirby &ds->ds_userrefs); 435842727c2SChris Kirby } 436fa9e4066Sahrens } 437fa9e4066Sahrens 43874e7dc98SMatthew Ahrens if (err == 0 && !dsl_dataset_is_snapshot(ds)) { 43927345066Sck /* 44027345066Sck * In sync context, we're called with either no lock 44127345066Sck * or with the write lock. If we're not syncing, 44227345066Sck * we're always called with the read lock held. 44327345066Sck */ 444cb625fb5Sck boolean_t need_lock = 44527345066Sck !RW_WRITE_HELD(&dp->dp_config_rwlock) && 44627345066Sck dsl_pool_sync_context(dp); 447cb625fb5Sck 448cb625fb5Sck if (need_lock) 449cb625fb5Sck rw_enter(&dp->dp_config_rwlock, RW_READER); 450cb625fb5Sck 451bb0ade09Sahrens err = dsl_prop_get_ds(ds, 452cb625fb5Sck "refreservation", sizeof (uint64_t), 1, 453cb625fb5Sck &ds->ds_reserved, NULL); 454cb625fb5Sck if (err == 0) { 455bb0ade09Sahrens err = dsl_prop_get_ds(ds, 456cb625fb5Sck "refquota", sizeof (uint64_t), 1, 457cb625fb5Sck &ds->ds_quota, NULL); 458cb625fb5Sck } 459cb625fb5Sck 460cb625fb5Sck if (need_lock) 461cb625fb5Sck rw_exit(&dp->dp_config_rwlock); 462cb625fb5Sck } else { 463cb625fb5Sck ds->ds_reserved = ds->ds_quota = 0; 464cb625fb5Sck } 465cb625fb5Sck 466ea8dc4b6Seschrock if (err == 0) { 467ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 468ea8dc4b6Seschrock dsl_dataset_evict); 469ea8dc4b6Seschrock } 470ea8dc4b6Seschrock if (err || winner) { 471cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 472cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 473745cd3c5Smaybee if (ds->ds_prev) 474745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 475fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 4765ad82045Snd mutex_destroy(&ds->ds_lock); 477f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 47891ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 479745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 480745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 481fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 482ea8dc4b6Seschrock if (err) { 483ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 484ea8dc4b6Seschrock return (err); 485ea8dc4b6Seschrock } 486fa9e4066Sahrens ds = winner; 487fa9e4066Sahrens } else { 48891ebeef5Sahrens ds->ds_fsid_guid = 489fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 490fa9e4066Sahrens } 491fa9e4066Sahrens } 492fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 493fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 494088f3894Sahrens ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 || 495afc6333aSahrens spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN || 49684db2a68Sahrens dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap); 497fa9e4066Sahrens mutex_enter(&ds->ds_lock); 498745cd3c5Smaybee if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) { 499fa9e4066Sahrens mutex_exit(&ds->ds_lock); 500745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 501745cd3c5Smaybee return (ENOENT); 502fa9e4066Sahrens } 503fa9e4066Sahrens mutex_exit(&ds->ds_lock); 504ea8dc4b6Seschrock *dsp = ds; 505ea8dc4b6Seschrock return (0); 506fa9e4066Sahrens } 507fa9e4066Sahrens 508745cd3c5Smaybee static int 509745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag) 510745cd3c5Smaybee { 511745cd3c5Smaybee dsl_pool_t *dp = ds->ds_dir->dd_pool; 512745cd3c5Smaybee 513745cd3c5Smaybee /* 514745cd3c5Smaybee * In syncing context we don't want the rwlock lock: there 515745cd3c5Smaybee * may be an existing writer waiting for sync phase to 516745cd3c5Smaybee * finish. We don't need to worry about such writers, since 517745cd3c5Smaybee * sync phase is single-threaded, so the writer can't be 518745cd3c5Smaybee * doing anything while we are active. 519745cd3c5Smaybee */ 520745cd3c5Smaybee if (dsl_pool_sync_context(dp)) { 521745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 522745cd3c5Smaybee return (0); 523745cd3c5Smaybee } 524745cd3c5Smaybee 525745cd3c5Smaybee /* 526745cd3c5Smaybee * Normal users will hold the ds_rwlock as a READER until they 527745cd3c5Smaybee * are finished (i.e., call dsl_dataset_rele()). "Owners" will 528745cd3c5Smaybee * drop their READER lock after they set the ds_owner field. 529745cd3c5Smaybee * 530745cd3c5Smaybee * If the dataset is being destroyed, the destroy thread will 531745cd3c5Smaybee * obtain a WRITER lock for exclusive access after it's done its 532745cd3c5Smaybee * open-context work and then change the ds_owner to 533745cd3c5Smaybee * dsl_reaper once destruction is assured. So threads 534745cd3c5Smaybee * may block here temporarily, until the "destructability" of 535745cd3c5Smaybee * the dataset is determined. 536745cd3c5Smaybee */ 537745cd3c5Smaybee ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock)); 538745cd3c5Smaybee mutex_enter(&ds->ds_lock); 539745cd3c5Smaybee while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) { 540745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 541745cd3c5Smaybee cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock); 542745cd3c5Smaybee if (DSL_DATASET_IS_DESTROYED(ds)) { 543745cd3c5Smaybee mutex_exit(&ds->ds_lock); 544745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 545745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 546745cd3c5Smaybee return (ENOENT); 547745cd3c5Smaybee } 548620252bcSChris Kirby /* 549620252bcSChris Kirby * The dp_config_rwlock lives above the ds_lock. And 550620252bcSChris Kirby * we need to check DSL_DATASET_IS_DESTROYED() while 551620252bcSChris Kirby * holding the ds_lock, so we have to drop and reacquire 552620252bcSChris Kirby * the ds_lock here. 553620252bcSChris Kirby */ 554620252bcSChris Kirby mutex_exit(&ds->ds_lock); 555745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 556620252bcSChris Kirby mutex_enter(&ds->ds_lock); 557745cd3c5Smaybee } 558745cd3c5Smaybee mutex_exit(&ds->ds_lock); 559745cd3c5Smaybee return (0); 560745cd3c5Smaybee } 561745cd3c5Smaybee 562745cd3c5Smaybee int 563745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, 564745cd3c5Smaybee dsl_dataset_t **dsp) 565745cd3c5Smaybee { 566745cd3c5Smaybee int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp); 567745cd3c5Smaybee 568745cd3c5Smaybee if (err) 569745cd3c5Smaybee return (err); 570745cd3c5Smaybee return (dsl_dataset_hold_ref(*dsp, tag)); 571745cd3c5Smaybee } 572745cd3c5Smaybee 573745cd3c5Smaybee int 574503ad85cSMatthew Ahrens dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, boolean_t inconsistentok, 575503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 576745cd3c5Smaybee { 577503ad85cSMatthew Ahrens int err = dsl_dataset_hold_obj(dp, dsobj, tag, dsp); 578745cd3c5Smaybee if (err) 579745cd3c5Smaybee return (err); 580503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 581503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 5824f5064b7SMark J Musante *dsp = NULL; 583745cd3c5Smaybee return (EBUSY); 584745cd3c5Smaybee } 585745cd3c5Smaybee return (0); 586745cd3c5Smaybee } 587745cd3c5Smaybee 588fa9e4066Sahrens int 589745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp) 590fa9e4066Sahrens { 591fa9e4066Sahrens dsl_dir_t *dd; 592fa9e4066Sahrens dsl_pool_t *dp; 593745cd3c5Smaybee const char *snapname; 594fa9e4066Sahrens uint64_t obj; 595fa9e4066Sahrens int err = 0; 596fa9e4066Sahrens 597745cd3c5Smaybee err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname); 598ea8dc4b6Seschrock if (err) 599ea8dc4b6Seschrock return (err); 600fa9e4066Sahrens 601fa9e4066Sahrens dp = dd->dd_pool; 602fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 603fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 604745cd3c5Smaybee if (obj) 605745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, dsp); 606745cd3c5Smaybee else 607fa9e4066Sahrens err = ENOENT; 608745cd3c5Smaybee if (err) 609fa9e4066Sahrens goto out; 610fa9e4066Sahrens 611745cd3c5Smaybee err = dsl_dataset_hold_ref(*dsp, tag); 612fa9e4066Sahrens 613745cd3c5Smaybee /* we may be looking for a snapshot */ 614745cd3c5Smaybee if (err == 0 && snapname != NULL) { 615745cd3c5Smaybee dsl_dataset_t *ds = NULL; 616fa9e4066Sahrens 617745cd3c5Smaybee if (*snapname++ != '@') { 618745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 619fa9e4066Sahrens err = ENOENT; 620fa9e4066Sahrens goto out; 621fa9e4066Sahrens } 622fa9e4066Sahrens 623745cd3c5Smaybee dprintf("looking for snapshot '%s'\n", snapname); 624745cd3c5Smaybee err = dsl_dataset_snap_lookup(*dsp, snapname, &obj); 625745cd3c5Smaybee if (err == 0) 626745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, &ds); 627745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 628745cd3c5Smaybee 629745cd3c5Smaybee ASSERT3U((err == 0), ==, (ds != NULL)); 630745cd3c5Smaybee 631745cd3c5Smaybee if (ds) { 632745cd3c5Smaybee mutex_enter(&ds->ds_lock); 633745cd3c5Smaybee if (ds->ds_snapname[0] == 0) 634745cd3c5Smaybee (void) strlcpy(ds->ds_snapname, snapname, 635745cd3c5Smaybee sizeof (ds->ds_snapname)); 636745cd3c5Smaybee mutex_exit(&ds->ds_lock); 637745cd3c5Smaybee err = dsl_dataset_hold_ref(ds, tag); 638745cd3c5Smaybee *dsp = err ? NULL : ds; 639fa9e4066Sahrens } 640fa9e4066Sahrens } 641fa9e4066Sahrens out: 642fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 643fa9e4066Sahrens dsl_dir_close(dd, FTAG); 644fa9e4066Sahrens return (err); 645fa9e4066Sahrens } 646fa9e4066Sahrens 647fa9e4066Sahrens int 648503ad85cSMatthew Ahrens dsl_dataset_own(const char *name, boolean_t inconsistentok, 649503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 650fa9e4066Sahrens { 651503ad85cSMatthew Ahrens int err = dsl_dataset_hold(name, tag, dsp); 652745cd3c5Smaybee if (err) 653745cd3c5Smaybee return (err); 654503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 655503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 656745cd3c5Smaybee return (EBUSY); 657745cd3c5Smaybee } 658745cd3c5Smaybee return (0); 659fa9e4066Sahrens } 660fa9e4066Sahrens 661fa9e4066Sahrens void 662fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 663fa9e4066Sahrens { 664fa9e4066Sahrens if (ds == NULL) { 665fa9e4066Sahrens (void) strcpy(name, "mos"); 666fa9e4066Sahrens } else { 667fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 668ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 669fa9e4066Sahrens if (ds->ds_snapname[0]) { 670fa9e4066Sahrens (void) strcat(name, "@"); 671745cd3c5Smaybee /* 672745cd3c5Smaybee * We use a "recursive" mutex so that we 673745cd3c5Smaybee * can call dprintf_ds() with ds_lock held. 674745cd3c5Smaybee */ 675fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 676fa9e4066Sahrens mutex_enter(&ds->ds_lock); 677fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 678fa9e4066Sahrens mutex_exit(&ds->ds_lock); 679fa9e4066Sahrens } else { 680fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 681fa9e4066Sahrens } 682fa9e4066Sahrens } 683fa9e4066Sahrens } 684fa9e4066Sahrens } 685fa9e4066Sahrens 686b7661cccSmmusante static int 687b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 688b7661cccSmmusante { 689b7661cccSmmusante int result; 690b7661cccSmmusante 691b7661cccSmmusante if (ds == NULL) { 692b7661cccSmmusante result = 3; /* "mos" */ 693b7661cccSmmusante } else { 694b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 695b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 696b7661cccSmmusante if (ds->ds_snapname[0]) { 697b7661cccSmmusante ++result; /* adding one for the @-sign */ 698b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 699b7661cccSmmusante mutex_enter(&ds->ds_lock); 700b7661cccSmmusante result += strlen(ds->ds_snapname); 701b7661cccSmmusante mutex_exit(&ds->ds_lock); 702b7661cccSmmusante } else { 703b7661cccSmmusante result += strlen(ds->ds_snapname); 704b7661cccSmmusante } 705b7661cccSmmusante } 706b7661cccSmmusante } 707b7661cccSmmusante 708b7661cccSmmusante return (result); 709b7661cccSmmusante } 710b7661cccSmmusante 711088f3894Sahrens void 712745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag) 713fa9e4066Sahrens { 714ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 715fa9e4066Sahrens } 716fa9e4066Sahrens 7173cb34c60Sahrens void 718745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag) 7193cb34c60Sahrens { 720745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) { 721745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 722745cd3c5Smaybee } 723745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 724745cd3c5Smaybee } 725745cd3c5Smaybee 726745cd3c5Smaybee void 727503ad85cSMatthew Ahrens dsl_dataset_disown(dsl_dataset_t *ds, void *tag) 728745cd3c5Smaybee { 729503ad85cSMatthew Ahrens ASSERT((ds->ds_owner == tag && ds->ds_dbuf) || 730745cd3c5Smaybee (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL)); 731745cd3c5Smaybee 7323cb34c60Sahrens mutex_enter(&ds->ds_lock); 733745cd3c5Smaybee ds->ds_owner = NULL; 734745cd3c5Smaybee if (RW_WRITE_HELD(&ds->ds_rwlock)) { 735745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 736745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 737745cd3c5Smaybee } 7383cb34c60Sahrens mutex_exit(&ds->ds_lock); 739745cd3c5Smaybee if (ds->ds_dbuf) 740503ad85cSMatthew Ahrens dsl_dataset_drop_ref(ds, tag); 741745cd3c5Smaybee else 742cde58dbcSMatthew Ahrens dsl_dataset_evict(NULL, ds); 7433cb34c60Sahrens } 7443cb34c60Sahrens 7453cb34c60Sahrens boolean_t 746503ad85cSMatthew Ahrens dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *tag) 7473cb34c60Sahrens { 748745cd3c5Smaybee boolean_t gotit = FALSE; 749745cd3c5Smaybee 7503cb34c60Sahrens mutex_enter(&ds->ds_lock); 751745cd3c5Smaybee if (ds->ds_owner == NULL && 752745cd3c5Smaybee (!DS_IS_INCONSISTENT(ds) || inconsistentok)) { 753503ad85cSMatthew Ahrens ds->ds_owner = tag; 754745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) 755745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 756745cd3c5Smaybee gotit = TRUE; 7573cb34c60Sahrens } 7583cb34c60Sahrens mutex_exit(&ds->ds_lock); 759745cd3c5Smaybee return (gotit); 760745cd3c5Smaybee } 761745cd3c5Smaybee 762745cd3c5Smaybee void 763745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner) 764745cd3c5Smaybee { 765745cd3c5Smaybee ASSERT3P(owner, ==, ds->ds_owner); 766745cd3c5Smaybee if (!RW_WRITE_HELD(&ds->ds_rwlock)) 767745cd3c5Smaybee rw_enter(&ds->ds_rwlock, RW_WRITER); 7683cb34c60Sahrens } 7693cb34c60Sahrens 7701d452cf5Sahrens uint64_t 771088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 772ab04eb8eStimh uint64_t flags, dmu_tx_t *tx) 773fa9e4066Sahrens { 7743cb34c60Sahrens dsl_pool_t *dp = dd->dd_pool; 775fa9e4066Sahrens dmu_buf_t *dbuf; 776fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 7773cb34c60Sahrens uint64_t dsobj; 778fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 779fa9e4066Sahrens 780088f3894Sahrens if (origin == NULL) 781088f3894Sahrens origin = dp->dp_origin_snap; 782088f3894Sahrens 7833cb34c60Sahrens ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp); 7843cb34c60Sahrens ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0); 785fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 7863cb34c60Sahrens ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); 787fa9e4066Sahrens 7881649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 7891649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 790ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 791fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 792fa9e4066Sahrens dsphys = dbuf->db_data; 793745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 794fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 795ab04eb8eStimh dsphys->ds_flags = flags; 796fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 797fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 798fa9e4066Sahrens sizeof (dsphys->ds_guid)); 799fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 800ab04eb8eStimh zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP, 801ab04eb8eStimh DMU_OT_NONE, 0, tx); 802fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 803088f3894Sahrens dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg; 804a9799022Sck 805cde58dbcSMatthew Ahrens if (origin == NULL) { 806cde58dbcSMatthew Ahrens dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx); 807cde58dbcSMatthew Ahrens } else { 808cde58dbcSMatthew Ahrens dsl_dataset_t *ohds; 809cde58dbcSMatthew Ahrens 8103cb34c60Sahrens dsphys->ds_prev_snap_obj = origin->ds_object; 811fa9e4066Sahrens dsphys->ds_prev_snap_txg = 8123cb34c60Sahrens origin->ds_phys->ds_creation_txg; 813fa9e4066Sahrens dsphys->ds_used_bytes = 8143cb34c60Sahrens origin->ds_phys->ds_used_bytes; 815fa9e4066Sahrens dsphys->ds_compressed_bytes = 8163cb34c60Sahrens origin->ds_phys->ds_compressed_bytes; 817fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 8183cb34c60Sahrens origin->ds_phys->ds_uncompressed_bytes; 8193cb34c60Sahrens dsphys->ds_bp = origin->ds_phys->ds_bp; 820579ae4d5Stimh dsphys->ds_flags |= origin->ds_phys->ds_flags; 821fa9e4066Sahrens 8223cb34c60Sahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 8233cb34c60Sahrens origin->ds_phys->ds_num_children++; 824fa9e4066Sahrens 825cde58dbcSMatthew Ahrens VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 826cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ohds)); 827cde58dbcSMatthew Ahrens dsphys->ds_deadlist_obj = dsl_deadlist_clone(&ohds->ds_deadlist, 828cde58dbcSMatthew Ahrens dsphys->ds_prev_snap_txg, dsphys->ds_prev_snap_obj, tx); 829cde58dbcSMatthew Ahrens dsl_dataset_rele(ohds, FTAG); 830cde58dbcSMatthew Ahrens 831088f3894Sahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) { 832088f3894Sahrens if (origin->ds_phys->ds_next_clones_obj == 0) { 833088f3894Sahrens origin->ds_phys->ds_next_clones_obj = 834088f3894Sahrens zap_create(mos, 835088f3894Sahrens DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx); 836088f3894Sahrens } 837088f3894Sahrens VERIFY(0 == zap_add_int(mos, 838088f3894Sahrens origin->ds_phys->ds_next_clones_obj, 839088f3894Sahrens dsobj, tx)); 840088f3894Sahrens } 841088f3894Sahrens 842fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 8433cb34c60Sahrens dd->dd_phys->dd_origin_obj = origin->ds_object; 844cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 845cde58dbcSMatthew Ahrens if (origin->ds_dir->dd_phys->dd_clones == 0) { 846cde58dbcSMatthew Ahrens dmu_buf_will_dirty(origin->ds_dir->dd_dbuf, tx); 847cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_clones = 848cde58dbcSMatthew Ahrens zap_create(mos, 849cde58dbcSMatthew Ahrens DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx); 850cde58dbcSMatthew Ahrens } 851cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_add_int(mos, 852cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_clones, dsobj, tx)); 853cde58dbcSMatthew Ahrens } 854fa9e4066Sahrens } 855ab04eb8eStimh 856ab04eb8eStimh if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 857ab04eb8eStimh dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 858ab04eb8eStimh 859ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 860fa9e4066Sahrens 861fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 862fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 8633cb34c60Sahrens 8643cb34c60Sahrens return (dsobj); 8653cb34c60Sahrens } 8663cb34c60Sahrens 8673cb34c60Sahrens uint64_t 868ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname, 869ab04eb8eStimh dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx) 8703cb34c60Sahrens { 8713cb34c60Sahrens dsl_pool_t *dp = pdd->dd_pool; 8723cb34c60Sahrens uint64_t dsobj, ddobj; 8733cb34c60Sahrens dsl_dir_t *dd; 8743cb34c60Sahrens 8753cb34c60Sahrens ASSERT(lastname[0] != '@'); 8763cb34c60Sahrens 877088f3894Sahrens ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx); 8783cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 8793cb34c60Sahrens 880088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx); 8813cb34c60Sahrens 8823cb34c60Sahrens dsl_deleg_set_create_perms(dd, tx, cr); 8833cb34c60Sahrens 884fa9e4066Sahrens dsl_dir_close(dd, FTAG); 885fa9e4066Sahrens 8861d452cf5Sahrens return (dsobj); 887fa9e4066Sahrens } 888fa9e4066Sahrens 8891d452cf5Sahrens struct destroyarg { 8901d452cf5Sahrens dsl_sync_task_group_t *dstg; 8911d452cf5Sahrens char *snapname; 8921d452cf5Sahrens char *failed; 893842727c2SChris Kirby boolean_t defer; 8941d452cf5Sahrens }; 8951d452cf5Sahrens 8961d452cf5Sahrens static int 897fd136879SMatthew Ahrens dsl_snapshot_destroy_one(const char *name, void *arg) 898fa9e4066Sahrens { 8991d452cf5Sahrens struct destroyarg *da = arg; 9001d452cf5Sahrens dsl_dataset_t *ds; 901fa9e4066Sahrens int err; 902842727c2SChris Kirby char *dsname; 903842727c2SChris Kirby 904ae46e4c7SMatthew Ahrens dsname = kmem_asprintf("%s@%s", name, da->snapname); 905503ad85cSMatthew Ahrens err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds); 906ae46e4c7SMatthew Ahrens strfree(dsname); 907745cd3c5Smaybee if (err == 0) { 908842727c2SChris Kirby struct dsl_ds_destroyarg *dsda; 909842727c2SChris Kirby 910745cd3c5Smaybee dsl_dataset_make_exclusive(ds, da->dstg); 911842727c2SChris Kirby dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP); 912842727c2SChris Kirby dsda->ds = ds; 913842727c2SChris Kirby dsda->defer = da->defer; 914745cd3c5Smaybee dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 915842727c2SChris Kirby dsl_dataset_destroy_sync, dsda, da->dstg, 0); 916745cd3c5Smaybee } else if (err == ENOENT) { 917745cd3c5Smaybee err = 0; 918745cd3c5Smaybee } else { 9191d452cf5Sahrens (void) strcpy(da->failed, name); 9201d452cf5Sahrens } 921745cd3c5Smaybee return (err); 9221d452cf5Sahrens } 92331fd60d3Sahrens 9241d452cf5Sahrens /* 9251d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 9261d452cf5Sahrens */ 9271d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 9281d452cf5Sahrens int 929842727c2SChris Kirby dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer) 9301d452cf5Sahrens { 9311d452cf5Sahrens int err; 9321d452cf5Sahrens struct destroyarg da; 9331d452cf5Sahrens dsl_sync_task_t *dst; 9341d452cf5Sahrens spa_t *spa; 9351d452cf5Sahrens 93640feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 9371d452cf5Sahrens if (err) 9381d452cf5Sahrens return (err); 9391d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 9401d452cf5Sahrens da.snapname = snapname; 9411d452cf5Sahrens da.failed = fsname; 942842727c2SChris Kirby da.defer = defer; 9431d452cf5Sahrens 9441d452cf5Sahrens err = dmu_objset_find(fsname, 9450b69c2f0Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 9461d452cf5Sahrens 9471d452cf5Sahrens if (err == 0) 9481d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 9491d452cf5Sahrens 9501d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 9511d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 952842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 953842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 954842727c2SChris Kirby 955745cd3c5Smaybee /* 956745cd3c5Smaybee * Return the file system name that triggered the error 957745cd3c5Smaybee */ 9581d452cf5Sahrens if (dst->dst_err) { 9591d452cf5Sahrens dsl_dataset_name(ds, fsname); 96040feaa91Sahrens *strchr(fsname, '@') = '\0'; 961e1930233Sbonwick } 962842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 963745cd3c5Smaybee dsl_dataset_disown(ds, da.dstg); 964842727c2SChris Kirby kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 965fa9e4066Sahrens } 966fa9e4066Sahrens 9671d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 9681d452cf5Sahrens spa_close(spa, FTAG); 969fa9e4066Sahrens return (err); 970fa9e4066Sahrens } 971fa9e4066Sahrens 972842727c2SChris Kirby static boolean_t 973842727c2SChris Kirby dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 974842727c2SChris Kirby { 975842727c2SChris Kirby boolean_t might_destroy = B_FALSE; 976842727c2SChris Kirby 977842727c2SChris Kirby mutex_enter(&ds->ds_lock); 978842727c2SChris Kirby if (ds->ds_phys->ds_num_children == 2 && ds->ds_userrefs == 0 && 979842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 980842727c2SChris Kirby might_destroy = B_TRUE; 981842727c2SChris Kirby mutex_exit(&ds->ds_lock); 982842727c2SChris Kirby 983842727c2SChris Kirby return (might_destroy); 984842727c2SChris Kirby } 985842727c2SChris Kirby 986842727c2SChris Kirby /* 987842727c2SChris Kirby * If we're removing a clone, and these three conditions are true: 988842727c2SChris Kirby * 1) the clone's origin has no other children 989842727c2SChris Kirby * 2) the clone's origin has no user references 990842727c2SChris Kirby * 3) the clone's origin has been marked for deferred destruction 991842727c2SChris Kirby * Then, prepare to remove the origin as part of this sync task group. 992842727c2SChris Kirby */ 993842727c2SChris Kirby static int 994842727c2SChris Kirby dsl_dataset_origin_rm_prep(struct dsl_ds_destroyarg *dsda, void *tag) 995842727c2SChris Kirby { 996842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 997842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 998842727c2SChris Kirby 999842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(origin)) { 1000842727c2SChris Kirby char *name; 1001842727c2SChris Kirby int namelen; 1002842727c2SChris Kirby int error; 1003842727c2SChris Kirby 1004842727c2SChris Kirby namelen = dsl_dataset_namelen(origin) + 1; 1005842727c2SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 1006842727c2SChris Kirby dsl_dataset_name(origin, name); 1007842727c2SChris Kirby #ifdef _KERNEL 1008842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 1009842727c2SChris Kirby if (error) { 1010842727c2SChris Kirby kmem_free(name, namelen); 1011842727c2SChris Kirby return (error); 1012842727c2SChris Kirby } 1013842727c2SChris Kirby #endif 1014503ad85cSMatthew Ahrens error = dsl_dataset_own(name, B_TRUE, tag, &origin); 1015842727c2SChris Kirby kmem_free(name, namelen); 1016842727c2SChris Kirby if (error) 1017842727c2SChris Kirby return (error); 1018842727c2SChris Kirby dsda->rm_origin = origin; 1019842727c2SChris Kirby dsl_dataset_make_exclusive(origin, tag); 1020842727c2SChris Kirby } 1021842727c2SChris Kirby 1022842727c2SChris Kirby return (0); 1023842727c2SChris Kirby } 1024842727c2SChris Kirby 10253cb34c60Sahrens /* 1026745cd3c5Smaybee * ds must be opened as OWNER. On return (whether successful or not), 1027745cd3c5Smaybee * ds will be closed and caller can no longer dereference it. 10283cb34c60Sahrens */ 1029fa9e4066Sahrens int 1030842727c2SChris Kirby dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) 1031fa9e4066Sahrens { 1032fa9e4066Sahrens int err; 10331d452cf5Sahrens dsl_sync_task_group_t *dstg; 10341d452cf5Sahrens objset_t *os; 1035fa9e4066Sahrens dsl_dir_t *dd; 10361d452cf5Sahrens uint64_t obj; 103792241e0bSTom Erickson struct dsl_ds_destroyarg dsda = { 0 }; 103892241e0bSTom Erickson dsl_dataset_t dummy_ds = { 0 }; 1039842727c2SChris Kirby 1040842727c2SChris Kirby dsda.ds = ds; 10411d452cf5Sahrens 10423cb34c60Sahrens if (dsl_dataset_is_snapshot(ds)) { 10431d452cf5Sahrens /* Destroying a snapshot is simpler */ 1044745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 10453baa08fcSek 1046842727c2SChris Kirby dsda.defer = defer; 10471d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 10481d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 1049842727c2SChris Kirby &dsda, tag, 0); 1050842727c2SChris Kirby ASSERT3P(dsda.rm_origin, ==, NULL); 10513cb34c60Sahrens goto out; 1052922d9a97SChris Kirby } else if (defer) { 1053922d9a97SChris Kirby err = EINVAL; 1054922d9a97SChris Kirby goto out; 10551d452cf5Sahrens } 1056fa9e4066Sahrens 10571d452cf5Sahrens dd = ds->ds_dir; 105892241e0bSTom Erickson dummy_ds.ds_dir = dd; 105992241e0bSTom Erickson dummy_ds.ds_object = ds->ds_object; 1060fa9e4066Sahrens 10611d452cf5Sahrens /* 10621d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 10631d452cf5Sahrens * case we crash while freeing the objects. 10641d452cf5Sahrens */ 10651d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 10661d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 10673cb34c60Sahrens if (err) 10683cb34c60Sahrens goto out; 10693cb34c60Sahrens 1070503ad85cSMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 10713cb34c60Sahrens if (err) 10723cb34c60Sahrens goto out; 1073fa9e4066Sahrens 10741d452cf5Sahrens /* 10751d452cf5Sahrens * remove the objects in open context, so that we won't 10761d452cf5Sahrens * have too much to do in syncing context. 10771d452cf5Sahrens */ 10786754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 10796754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 1080cdb0ab79Smaybee /* 1081cdb0ab79Smaybee * Ignore errors, if there is not enough disk space 1082cdb0ab79Smaybee * we will deal with it in dsl_dataset_destroy_sync(). 1083cdb0ab79Smaybee */ 1084cdb0ab79Smaybee (void) dmu_free_object(os, obj); 10851d452cf5Sahrens } 10861d452cf5Sahrens 108714843421SMatthew Ahrens /* 108814843421SMatthew Ahrens * We need to sync out all in-flight IO before we try to evict 108914843421SMatthew Ahrens * (the dataset evict func is trying to clear the cached entries 109014843421SMatthew Ahrens * for this dataset in the ARC). 109114843421SMatthew Ahrens */ 109214843421SMatthew Ahrens txg_wait_synced(dd->dd_pool, 0); 109314843421SMatthew Ahrens 109414843421SMatthew Ahrens /* 109514843421SMatthew Ahrens * If we managed to free all the objects in open 109614843421SMatthew Ahrens * context, the user space accounting should be zero. 109714843421SMatthew Ahrens */ 109814843421SMatthew Ahrens if (ds->ds_phys->ds_bp.blk_fill == 0 && 1099503ad85cSMatthew Ahrens dmu_objset_userused_enabled(os)) { 110014843421SMatthew Ahrens uint64_t count; 110114843421SMatthew Ahrens 110214843421SMatthew Ahrens ASSERT(zap_count(os, DMU_USERUSED_OBJECT, &count) != 0 || 110314843421SMatthew Ahrens count == 0); 110414843421SMatthew Ahrens ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, &count) != 0 || 110514843421SMatthew Ahrens count == 0); 110614843421SMatthew Ahrens } 110714843421SMatthew Ahrens 11081d452cf5Sahrens if (err != ESRCH) 11093cb34c60Sahrens goto out; 11101d452cf5Sahrens 111168038c2cSmaybee rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 111268038c2cSmaybee err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd); 111368038c2cSmaybee rw_exit(&dd->dd_pool->dp_config_rwlock); 111468038c2cSmaybee 111568038c2cSmaybee if (err) 111668038c2cSmaybee goto out; 111768038c2cSmaybee 11181d452cf5Sahrens /* 11191d452cf5Sahrens * Blow away the dsl_dir + head dataset. 11201d452cf5Sahrens */ 1121745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 1122842727c2SChris Kirby /* 1123842727c2SChris Kirby * If we're removing a clone, we might also need to remove its 1124842727c2SChris Kirby * origin. 1125842727c2SChris Kirby */ 1126842727c2SChris Kirby do { 1127842727c2SChris Kirby dsda.need_prep = B_FALSE; 1128842727c2SChris Kirby if (dsl_dir_is_clone(dd)) { 1129842727c2SChris Kirby err = dsl_dataset_origin_rm_prep(&dsda, tag); 1130842727c2SChris Kirby if (err) { 1131842727c2SChris Kirby dsl_dir_close(dd, FTAG); 1132842727c2SChris Kirby goto out; 1133842727c2SChris Kirby } 1134842727c2SChris Kirby } 1135842727c2SChris Kirby 1136842727c2SChris Kirby dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 1137842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 1138842727c2SChris Kirby dsl_dataset_destroy_sync, &dsda, tag, 0); 1139842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dir_destroy_check, 114092241e0bSTom Erickson dsl_dir_destroy_sync, &dummy_ds, FTAG, 0); 1141842727c2SChris Kirby err = dsl_sync_task_group_wait(dstg); 1142842727c2SChris Kirby dsl_sync_task_group_destroy(dstg); 1143842727c2SChris Kirby 1144842727c2SChris Kirby /* 1145842727c2SChris Kirby * We could be racing against 'zfs release' or 'zfs destroy -d' 1146842727c2SChris Kirby * on the origin snap, in which case we can get EBUSY if we 1147842727c2SChris Kirby * needed to destroy the origin snap but were not ready to 1148842727c2SChris Kirby * do so. 1149842727c2SChris Kirby */ 1150842727c2SChris Kirby if (dsda.need_prep) { 1151842727c2SChris Kirby ASSERT(err == EBUSY); 1152842727c2SChris Kirby ASSERT(dsl_dir_is_clone(dd)); 1153842727c2SChris Kirby ASSERT(dsda.rm_origin == NULL); 1154842727c2SChris Kirby } 1155842727c2SChris Kirby } while (dsda.need_prep); 1156842727c2SChris Kirby 1157842727c2SChris Kirby if (dsda.rm_origin != NULL) 1158842727c2SChris Kirby dsl_dataset_disown(dsda.rm_origin, tag); 1159842727c2SChris Kirby 1160745cd3c5Smaybee /* if it is successful, dsl_dir_destroy_sync will close the dd */ 11613cb34c60Sahrens if (err) 11621d452cf5Sahrens dsl_dir_close(dd, FTAG); 11633cb34c60Sahrens out: 1164745cd3c5Smaybee dsl_dataset_disown(ds, tag); 1165fa9e4066Sahrens return (err); 1166fa9e4066Sahrens } 1167fa9e4066Sahrens 1168c717a561Smaybee blkptr_t * 1169c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 1170fa9e4066Sahrens { 1171c717a561Smaybee return (&ds->ds_phys->ds_bp); 1172fa9e4066Sahrens } 1173fa9e4066Sahrens 1174fa9e4066Sahrens void 1175fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 1176fa9e4066Sahrens { 1177fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1178fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 1179fa9e4066Sahrens if (ds == NULL) { 1180fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 1181fa9e4066Sahrens } else { 1182fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1183fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 1184fa9e4066Sahrens } 1185fa9e4066Sahrens } 1186fa9e4066Sahrens 1187fa9e4066Sahrens spa_t * 1188fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 1189fa9e4066Sahrens { 1190fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 1191fa9e4066Sahrens } 1192fa9e4066Sahrens 1193fa9e4066Sahrens void 1194fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 1195fa9e4066Sahrens { 1196fa9e4066Sahrens dsl_pool_t *dp; 1197fa9e4066Sahrens 1198fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 1199fa9e4066Sahrens return; 1200fa9e4066Sahrens 1201503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1202a2eea2e1Sahrens 1203a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1204a2eea2e1Sahrens panic("dirtying snapshot!"); 1205fa9e4066Sahrens 1206fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 1207fa9e4066Sahrens 1208fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 1209fa9e4066Sahrens /* up the hold count until we can be written out */ 1210fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 1211fa9e4066Sahrens } 1212fa9e4066Sahrens } 1213fa9e4066Sahrens 1214a9799022Sck /* 1215a9799022Sck * The unique space in the head dataset can be calculated by subtracting 1216a9799022Sck * the space used in the most recent snapshot, that is still being used 1217a9799022Sck * in this file system, from the space currently in use. To figure out 1218a9799022Sck * the space in the most recent snapshot still in use, we need to take 1219a9799022Sck * the total space used in the snapshot and subtract out the space that 1220a9799022Sck * has been freed up since the snapshot was taken. 1221a9799022Sck */ 1222a9799022Sck static void 1223a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds) 1224a9799022Sck { 1225a9799022Sck uint64_t mrs_used; 1226a9799022Sck uint64_t dlused, dlcomp, dluncomp; 1227a9799022Sck 12283f9d6ad7SLin Ling ASSERT(!dsl_dataset_is_snapshot(ds)); 1229a9799022Sck 1230a9799022Sck if (ds->ds_phys->ds_prev_snap_obj != 0) 1231a9799022Sck mrs_used = ds->ds_prev->ds_phys->ds_used_bytes; 1232a9799022Sck else 1233a9799022Sck mrs_used = 0; 1234a9799022Sck 1235cde58dbcSMatthew Ahrens dsl_deadlist_space(&ds->ds_deadlist, &dlused, &dlcomp, &dluncomp); 1236a9799022Sck 1237a9799022Sck ASSERT3U(dlused, <=, mrs_used); 1238a9799022Sck ds->ds_phys->ds_unique_bytes = 1239a9799022Sck ds->ds_phys->ds_used_bytes - (mrs_used - dlused); 1240a9799022Sck 12413f9d6ad7SLin Ling if (spa_version(ds->ds_dir->dd_pool->dp_spa) >= 1242a9799022Sck SPA_VERSION_UNIQUE_ACCURATE) 1243a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1244a9799022Sck } 1245a9799022Sck 1246fa9e4066Sahrens struct killarg { 124774e7dc98SMatthew Ahrens dsl_dataset_t *ds; 1248fa9e4066Sahrens dmu_tx_t *tx; 1249fa9e4066Sahrens }; 1250fa9e4066Sahrens 125174e7dc98SMatthew Ahrens /* ARGSUSED */ 1252fa9e4066Sahrens static int 12533f9d6ad7SLin Ling kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf, 1254b24ab676SJeff Bonwick const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg) 1255fa9e4066Sahrens { 1256fa9e4066Sahrens struct killarg *ka = arg; 1257b24ab676SJeff Bonwick dmu_tx_t *tx = ka->tx; 1258fa9e4066Sahrens 125988b7b0f2SMatthew Ahrens if (bp == NULL) 126088b7b0f2SMatthew Ahrens return (0); 1261fa9e4066Sahrens 1262b24ab676SJeff Bonwick if (zb->zb_level == ZB_ZIL_LEVEL) { 1263b24ab676SJeff Bonwick ASSERT(zilog != NULL); 1264ab69d62fSMatthew Ahrens /* 1265ab69d62fSMatthew Ahrens * It's a block in the intent log. It has no 1266ab69d62fSMatthew Ahrens * accounting, so just free it. 1267ab69d62fSMatthew Ahrens */ 1268b24ab676SJeff Bonwick dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp); 1269ab69d62fSMatthew Ahrens } else { 1270b24ab676SJeff Bonwick ASSERT(zilog == NULL); 1271ab69d62fSMatthew Ahrens ASSERT3U(bp->blk_birth, >, ka->ds->ds_phys->ds_prev_snap_txg); 1272b24ab676SJeff Bonwick (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE); 1273ab69d62fSMatthew Ahrens } 127474e7dc98SMatthew Ahrens 1275fa9e4066Sahrens return (0); 1276fa9e4066Sahrens } 1277fa9e4066Sahrens 1278e1930233Sbonwick /* ARGSUSED */ 1279e1930233Sbonwick static int 12801d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1281e1930233Sbonwick { 12821d452cf5Sahrens dsl_dataset_t *ds = arg1; 12833cb34c60Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 12843cb34c60Sahrens uint64_t count; 12853cb34c60Sahrens int err; 1286e1930233Sbonwick 1287e1930233Sbonwick /* 1288e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1289e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1290e1930233Sbonwick * from.) 1291e1930233Sbonwick */ 1292e1930233Sbonwick if (ds->ds_prev != NULL && 1293e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 12944aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic return (EBUSY); 1295e1930233Sbonwick 12963cb34c60Sahrens /* 12973cb34c60Sahrens * This is really a dsl_dir thing, but check it here so that 12983cb34c60Sahrens * we'll be less likely to leave this dataset inconsistent & 12993cb34c60Sahrens * nearly destroyed. 13003cb34c60Sahrens */ 13013cb34c60Sahrens err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count); 13023cb34c60Sahrens if (err) 13033cb34c60Sahrens return (err); 13043cb34c60Sahrens if (count != 0) 13053cb34c60Sahrens return (EEXIST); 13063cb34c60Sahrens 1307e1930233Sbonwick return (0); 1308e1930233Sbonwick } 1309e1930233Sbonwick 13101d452cf5Sahrens /* ARGSUSED */ 13111d452cf5Sahrens static void 13123f9d6ad7SLin Ling dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1313fa9e4066Sahrens { 13141d452cf5Sahrens dsl_dataset_t *ds = arg1; 1315ecd6cf80Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1316fa9e4066Sahrens 13171d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 13181d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 13191d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1320ecd6cf80Smarks 13213f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 13223f9d6ad7SLin Ling "dataset = %llu", ds->ds_object); 13231d452cf5Sahrens } 1324fa9e4066Sahrens 1325842727c2SChris Kirby static int 1326842727c2SChris Kirby dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag, 1327842727c2SChris Kirby dmu_tx_t *tx) 1328842727c2SChris Kirby { 1329842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1330842727c2SChris Kirby dsl_dataset_t *ds_prev = ds->ds_prev; 1331842727c2SChris Kirby 1332842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(ds_prev)) { 1333842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1334842727c2SChris Kirby 1335842727c2SChris Kirby /* 1336842727c2SChris Kirby * If we're not prepared to remove the origin, don't remove 1337842727c2SChris Kirby * the clone either. 1338842727c2SChris Kirby */ 1339842727c2SChris Kirby if (dsda->rm_origin == NULL) { 1340842727c2SChris Kirby dsda->need_prep = B_TRUE; 1341842727c2SChris Kirby return (EBUSY); 1342842727c2SChris Kirby } 1343842727c2SChris Kirby 1344842727c2SChris Kirby ndsda.ds = ds_prev; 1345842727c2SChris Kirby ndsda.is_origin_rm = B_TRUE; 1346842727c2SChris Kirby return (dsl_dataset_destroy_check(&ndsda, tag, tx)); 1347842727c2SChris Kirby } 1348842727c2SChris Kirby 1349842727c2SChris Kirby /* 1350842727c2SChris Kirby * If we're not going to remove the origin after all, 1351842727c2SChris Kirby * undo the open context setup. 1352842727c2SChris Kirby */ 1353842727c2SChris Kirby if (dsda->rm_origin != NULL) { 1354842727c2SChris Kirby dsl_dataset_disown(dsda->rm_origin, tag); 1355842727c2SChris Kirby dsda->rm_origin = NULL; 1356842727c2SChris Kirby } 1357842727c2SChris Kirby 1358842727c2SChris Kirby return (0); 1359842727c2SChris Kirby } 1360842727c2SChris Kirby 13611d452cf5Sahrens /* ARGSUSED */ 13623cb34c60Sahrens int 13631d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 13641d452cf5Sahrens { 1365842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1366842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1367fa9e4066Sahrens 1368745cd3c5Smaybee /* we have an owner hold, so noone else can destroy us */ 1369745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 1370745cd3c5Smaybee 1371842727c2SChris Kirby /* 1372842727c2SChris Kirby * Only allow deferred destroy on pools that support it. 1373842727c2SChris Kirby * NOTE: deferred destroy is only supported on snapshots. 1374842727c2SChris Kirby */ 1375842727c2SChris Kirby if (dsda->defer) { 1376842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 1377842727c2SChris Kirby SPA_VERSION_USERREFS) 1378842727c2SChris Kirby return (ENOTSUP); 1379842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 1380842727c2SChris Kirby return (0); 1381842727c2SChris Kirby } 1382fa9e4066Sahrens 1383fa9e4066Sahrens /* 1384fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1385fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1386fa9e4066Sahrens * from.) 1387fa9e4066Sahrens */ 1388fa9e4066Sahrens if (ds->ds_prev != NULL && 13891d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 13904aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic return (EBUSY); 1391fa9e4066Sahrens 1392fa9e4066Sahrens /* 1393fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1394fa9e4066Sahrens * them. Try again. 1395fa9e4066Sahrens */ 13961d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1397fa9e4066Sahrens return (EAGAIN); 13981d452cf5Sahrens 1399842727c2SChris Kirby if (dsl_dataset_is_snapshot(ds)) { 1400842727c2SChris Kirby /* 1401842727c2SChris Kirby * If this snapshot has an elevated user reference count, 1402842727c2SChris Kirby * we can't destroy it yet. 1403842727c2SChris Kirby */ 1404842727c2SChris Kirby if (ds->ds_userrefs > 0 && !dsda->releasing) 1405842727c2SChris Kirby return (EBUSY); 1406842727c2SChris Kirby 1407842727c2SChris Kirby mutex_enter(&ds->ds_lock); 1408842727c2SChris Kirby /* 1409842727c2SChris Kirby * Can't delete a branch point. However, if we're destroying 1410842727c2SChris Kirby * a clone and removing its origin due to it having a user 1411842727c2SChris Kirby * hold count of 0 and having been marked for deferred destroy, 1412842727c2SChris Kirby * it's OK for the origin to have a single clone. 1413842727c2SChris Kirby */ 1414842727c2SChris Kirby if (ds->ds_phys->ds_num_children > 1415842727c2SChris Kirby (dsda->is_origin_rm ? 2 : 1)) { 1416842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1417842727c2SChris Kirby return (EEXIST); 1418842727c2SChris Kirby } 1419842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1420842727c2SChris Kirby } else if (dsl_dir_is_clone(ds->ds_dir)) { 1421842727c2SChris Kirby return (dsl_dataset_origin_check(dsda, arg2, tx)); 1422842727c2SChris Kirby } 1423842727c2SChris Kirby 14241d452cf5Sahrens /* XXX we should do some i/o error checking... */ 14251d452cf5Sahrens return (0); 14261d452cf5Sahrens } 14271d452cf5Sahrens 1428745cd3c5Smaybee struct refsarg { 1429745cd3c5Smaybee kmutex_t lock; 1430745cd3c5Smaybee boolean_t gone; 1431745cd3c5Smaybee kcondvar_t cv; 1432745cd3c5Smaybee }; 1433745cd3c5Smaybee 1434745cd3c5Smaybee /* ARGSUSED */ 1435745cd3c5Smaybee static void 1436745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv) 1437745cd3c5Smaybee { 1438745cd3c5Smaybee struct refsarg *arg = argv; 1439745cd3c5Smaybee 1440745cd3c5Smaybee mutex_enter(&arg->lock); 1441745cd3c5Smaybee arg->gone = TRUE; 1442745cd3c5Smaybee cv_signal(&arg->cv); 1443745cd3c5Smaybee mutex_exit(&arg->lock); 1444745cd3c5Smaybee } 1445745cd3c5Smaybee 1446745cd3c5Smaybee static void 1447745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag) 1448745cd3c5Smaybee { 1449745cd3c5Smaybee struct refsarg arg; 1450745cd3c5Smaybee 1451745cd3c5Smaybee mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL); 1452745cd3c5Smaybee cv_init(&arg.cv, NULL, CV_DEFAULT, NULL); 1453745cd3c5Smaybee arg.gone = FALSE; 1454745cd3c5Smaybee (void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys, 1455745cd3c5Smaybee dsl_dataset_refs_gone); 1456745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 1457745cd3c5Smaybee mutex_enter(&arg.lock); 1458745cd3c5Smaybee while (!arg.gone) 1459745cd3c5Smaybee cv_wait(&arg.cv, &arg.lock); 1460745cd3c5Smaybee ASSERT(arg.gone); 1461745cd3c5Smaybee mutex_exit(&arg.lock); 1462745cd3c5Smaybee ds->ds_dbuf = NULL; 1463745cd3c5Smaybee ds->ds_phys = NULL; 1464745cd3c5Smaybee mutex_destroy(&arg.lock); 1465745cd3c5Smaybee cv_destroy(&arg.cv); 1466745cd3c5Smaybee } 1467745cd3c5Smaybee 1468c33e334fSMatthew Ahrens static void 1469c33e334fSMatthew Ahrens remove_from_next_clones(dsl_dataset_t *ds, uint64_t obj, dmu_tx_t *tx) 1470c33e334fSMatthew Ahrens { 1471c33e334fSMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1472c33e334fSMatthew Ahrens uint64_t count; 1473c33e334fSMatthew Ahrens int err; 1474c33e334fSMatthew Ahrens 1475c33e334fSMatthew Ahrens ASSERT(ds->ds_phys->ds_num_children >= 2); 1476c33e334fSMatthew Ahrens err = zap_remove_int(mos, ds->ds_phys->ds_next_clones_obj, obj, tx); 1477c33e334fSMatthew Ahrens /* 1478c33e334fSMatthew Ahrens * The err should not be ENOENT, but a bug in a previous version 1479c33e334fSMatthew Ahrens * of the code could cause upgrade_clones_cb() to not set 1480c33e334fSMatthew Ahrens * ds_next_snap_obj when it should, leading to a missing entry. 1481c33e334fSMatthew Ahrens * If we knew that the pool was created after 1482c33e334fSMatthew Ahrens * SPA_VERSION_NEXT_CLONES, we could assert that it isn't 1483c33e334fSMatthew Ahrens * ENOENT. However, at least we can check that we don't have 1484c33e334fSMatthew Ahrens * too many entries in the next_clones_obj even after failing to 1485c33e334fSMatthew Ahrens * remove this one. 1486c33e334fSMatthew Ahrens */ 1487c33e334fSMatthew Ahrens if (err != ENOENT) { 1488c33e334fSMatthew Ahrens VERIFY3U(err, ==, 0); 1489c33e334fSMatthew Ahrens } 1490c33e334fSMatthew Ahrens ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj, 1491c33e334fSMatthew Ahrens &count)); 1492c33e334fSMatthew Ahrens ASSERT3U(count, <=, ds->ds_phys->ds_num_children - 2); 1493c33e334fSMatthew Ahrens } 1494c33e334fSMatthew Ahrens 1495cde58dbcSMatthew Ahrens static void 1496cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx) 1497cde58dbcSMatthew Ahrens { 1498cde58dbcSMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1499cde58dbcSMatthew Ahrens zap_cursor_t zc; 1500cde58dbcSMatthew Ahrens zap_attribute_t za; 1501cde58dbcSMatthew Ahrens 1502cde58dbcSMatthew Ahrens /* 1503cde58dbcSMatthew Ahrens * If it is the old version, dd_clones doesn't exist so we can't 1504cde58dbcSMatthew Ahrens * find the clones, but deadlist_remove_key() is a no-op so it 1505cde58dbcSMatthew Ahrens * doesn't matter. 1506cde58dbcSMatthew Ahrens */ 1507cde58dbcSMatthew Ahrens if (ds->ds_dir->dd_phys->dd_clones == 0) 1508cde58dbcSMatthew Ahrens return; 1509cde58dbcSMatthew Ahrens 1510cde58dbcSMatthew Ahrens for (zap_cursor_init(&zc, mos, ds->ds_dir->dd_phys->dd_clones); 1511cde58dbcSMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 1512cde58dbcSMatthew Ahrens zap_cursor_advance(&zc)) { 1513cde58dbcSMatthew Ahrens dsl_dataset_t *clone; 1514cde58dbcSMatthew Ahrens 1515cde58dbcSMatthew Ahrens VERIFY3U(0, ==, dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 1516cde58dbcSMatthew Ahrens za.za_first_integer, FTAG, &clone)); 1517cde58dbcSMatthew Ahrens if (clone->ds_dir->dd_origin_txg > mintxg) { 1518cde58dbcSMatthew Ahrens dsl_deadlist_remove_key(&clone->ds_deadlist, 1519cde58dbcSMatthew Ahrens mintxg, tx); 1520cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(clone, mintxg, tx); 1521cde58dbcSMatthew Ahrens } 1522cde58dbcSMatthew Ahrens dsl_dataset_rele(clone, FTAG); 1523cde58dbcSMatthew Ahrens } 1524cde58dbcSMatthew Ahrens zap_cursor_fini(&zc); 1525cde58dbcSMatthew Ahrens } 1526cde58dbcSMatthew Ahrens 1527cde58dbcSMatthew Ahrens struct process_old_arg { 1528cde58dbcSMatthew Ahrens dsl_dataset_t *ds; 1529cde58dbcSMatthew Ahrens dsl_dataset_t *ds_prev; 1530cde58dbcSMatthew Ahrens boolean_t after_branch_point; 1531cde58dbcSMatthew Ahrens zio_t *pio; 1532cde58dbcSMatthew Ahrens uint64_t used, comp, uncomp; 1533cde58dbcSMatthew Ahrens }; 1534cde58dbcSMatthew Ahrens 1535cde58dbcSMatthew Ahrens static int 1536cde58dbcSMatthew Ahrens process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx) 1537cde58dbcSMatthew Ahrens { 1538cde58dbcSMatthew Ahrens struct process_old_arg *poa = arg; 1539cde58dbcSMatthew Ahrens dsl_pool_t *dp = poa->ds->ds_dir->dd_pool; 1540cde58dbcSMatthew Ahrens 1541cde58dbcSMatthew Ahrens if (bp->blk_birth <= poa->ds->ds_phys->ds_prev_snap_txg) { 1542cde58dbcSMatthew Ahrens dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx); 1543cde58dbcSMatthew Ahrens if (poa->ds_prev && !poa->after_branch_point && 1544cde58dbcSMatthew Ahrens bp->blk_birth > 1545cde58dbcSMatthew Ahrens poa->ds_prev->ds_phys->ds_prev_snap_txg) { 1546cde58dbcSMatthew Ahrens poa->ds_prev->ds_phys->ds_unique_bytes += 1547cde58dbcSMatthew Ahrens bp_get_dsize_sync(dp->dp_spa, bp); 1548cde58dbcSMatthew Ahrens } 1549cde58dbcSMatthew Ahrens } else { 1550cde58dbcSMatthew Ahrens poa->used += bp_get_dsize_sync(dp->dp_spa, bp); 1551cde58dbcSMatthew Ahrens poa->comp += BP_GET_PSIZE(bp); 1552cde58dbcSMatthew Ahrens poa->uncomp += BP_GET_UCSIZE(bp); 1553cde58dbcSMatthew Ahrens dsl_free_sync(poa->pio, dp, tx->tx_txg, bp); 1554cde58dbcSMatthew Ahrens } 1555cde58dbcSMatthew Ahrens return (0); 1556cde58dbcSMatthew Ahrens } 1557cde58dbcSMatthew Ahrens 1558cde58dbcSMatthew Ahrens static void 1559cde58dbcSMatthew Ahrens process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev, 1560cde58dbcSMatthew Ahrens dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx) 1561cde58dbcSMatthew Ahrens { 1562cde58dbcSMatthew Ahrens struct process_old_arg poa = { 0 }; 1563cde58dbcSMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 1564cde58dbcSMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 1565cde58dbcSMatthew Ahrens 1566cde58dbcSMatthew Ahrens ASSERT(ds->ds_deadlist.dl_oldfmt); 1567cde58dbcSMatthew Ahrens ASSERT(ds_next->ds_deadlist.dl_oldfmt); 1568cde58dbcSMatthew Ahrens 1569cde58dbcSMatthew Ahrens poa.ds = ds; 1570cde58dbcSMatthew Ahrens poa.ds_prev = ds_prev; 1571cde58dbcSMatthew Ahrens poa.after_branch_point = after_branch_point; 1572cde58dbcSMatthew Ahrens poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1573cde58dbcSMatthew Ahrens VERIFY3U(0, ==, bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj, 1574cde58dbcSMatthew Ahrens process_old_cb, &poa, tx)); 1575cde58dbcSMatthew Ahrens VERIFY3U(zio_wait(poa.pio), ==, 0); 1576cde58dbcSMatthew Ahrens ASSERT3U(poa.used, ==, ds->ds_phys->ds_unique_bytes); 1577cde58dbcSMatthew Ahrens 1578cde58dbcSMatthew Ahrens /* change snapused */ 1579cde58dbcSMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 1580cde58dbcSMatthew Ahrens -poa.used, -poa.comp, -poa.uncomp, tx); 1581cde58dbcSMatthew Ahrens 1582cde58dbcSMatthew Ahrens /* swap next's deadlist to our deadlist */ 1583cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1584cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds_next->ds_deadlist); 1585cde58dbcSMatthew Ahrens SWITCH64(ds_next->ds_phys->ds_deadlist_obj, 1586cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj); 1587cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, mos, ds->ds_phys->ds_deadlist_obj); 1588cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds_next->ds_deadlist, mos, 1589cde58dbcSMatthew Ahrens ds_next->ds_phys->ds_deadlist_obj); 1590cde58dbcSMatthew Ahrens } 1591cde58dbcSMatthew Ahrens 15923cb34c60Sahrens void 15933f9d6ad7SLin Ling dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) 15941d452cf5Sahrens { 1595842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1596842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 15971d452cf5Sahrens int err; 15981d452cf5Sahrens int after_branch_point = FALSE; 15991d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 16001d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 16011d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 16021d452cf5Sahrens uint64_t obj; 16031d452cf5Sahrens 1604745cd3c5Smaybee ASSERT(ds->ds_owner); 1605842727c2SChris Kirby ASSERT(dsda->defer || ds->ds_phys->ds_num_children <= 1); 16061d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 16071d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 16081d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 16091d452cf5Sahrens 1610842727c2SChris Kirby if (dsda->defer) { 1611842727c2SChris Kirby ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 1612842727c2SChris Kirby if (ds->ds_userrefs > 0 || ds->ds_phys->ds_num_children > 1) { 1613842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 1614842727c2SChris Kirby ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY; 1615842727c2SChris Kirby return; 1616842727c2SChris Kirby } 1617842727c2SChris Kirby } 1618842727c2SChris Kirby 1619745cd3c5Smaybee /* signal any waiters that this dataset is going away */ 1620745cd3c5Smaybee mutex_enter(&ds->ds_lock); 1621745cd3c5Smaybee ds->ds_owner = dsl_reaper; 1622745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 1623745cd3c5Smaybee mutex_exit(&ds->ds_lock); 1624745cd3c5Smaybee 16253f9d6ad7SLin Ling if (ds->ds_objset) { 16263f9d6ad7SLin Ling dmu_objset_evict(ds->ds_objset); 16273f9d6ad7SLin Ling ds->ds_objset = NULL; 16283f9d6ad7SLin Ling } 16293f9d6ad7SLin Ling 1630a9799022Sck /* Remove our reservation */ 1631a9799022Sck if (ds->ds_reserved != 0) { 163292241e0bSTom Erickson dsl_prop_setarg_t psa; 163392241e0bSTom Erickson uint64_t value = 0; 163492241e0bSTom Erickson 163592241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refreservation", 163692241e0bSTom Erickson (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), 163792241e0bSTom Erickson &value); 163892241e0bSTom Erickson psa.psa_effective_value = 0; /* predict default value */ 163992241e0bSTom Erickson 16403f9d6ad7SLin Ling dsl_dataset_set_reservation_sync(ds, &psa, tx); 1641a9799022Sck ASSERT3U(ds->ds_reserved, ==, 0); 1642a9799022Sck } 1643a9799022Sck 16441d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 16451d452cf5Sahrens 16463f9d6ad7SLin Ling dsl_scan_ds_destroyed(ds, tx); 1647088f3894Sahrens 16481d452cf5Sahrens obj = ds->ds_object; 1649fa9e4066Sahrens 1650fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1651fa9e4066Sahrens if (ds->ds_prev) { 1652fa9e4066Sahrens ds_prev = ds->ds_prev; 1653fa9e4066Sahrens } else { 1654745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1655745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev)); 1656fa9e4066Sahrens } 1657fa9e4066Sahrens after_branch_point = 1658fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1659fa9e4066Sahrens 1660fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1661088f3894Sahrens if (after_branch_point && 1662088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj != 0) { 1663c33e334fSMatthew Ahrens remove_from_next_clones(ds_prev, obj, tx); 1664088f3894Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1665088f3894Sahrens VERIFY(0 == zap_add_int(mos, 1666088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, 1667088f3894Sahrens ds->ds_phys->ds_next_snap_obj, tx)); 1668088f3894Sahrens } 1669088f3894Sahrens } 1670fa9e4066Sahrens if (after_branch_point && 1671fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1672fa9e4066Sahrens /* This clone is toast. */ 1673fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1674fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1675842727c2SChris Kirby 1676842727c2SChris Kirby /* 1677842727c2SChris Kirby * If the clone's origin has no other clones, no 1678842727c2SChris Kirby * user holds, and has been marked for deferred 1679842727c2SChris Kirby * deletion, then we should have done the necessary 1680842727c2SChris Kirby * destroy setup for it. 1681842727c2SChris Kirby */ 1682842727c2SChris Kirby if (ds_prev->ds_phys->ds_num_children == 1 && 1683842727c2SChris Kirby ds_prev->ds_userrefs == 0 && 1684842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds_prev)) { 1685842727c2SChris Kirby ASSERT3P(dsda->rm_origin, !=, NULL); 1686842727c2SChris Kirby } else { 1687842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 1688842727c2SChris Kirby } 1689fa9e4066Sahrens } else if (!after_branch_point) { 1690fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1691fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1692fa9e4066Sahrens } 1693fa9e4066Sahrens } 1694fa9e4066Sahrens 16953f9d6ad7SLin Ling if (dsl_dataset_is_snapshot(ds)) { 1696fa9e4066Sahrens dsl_dataset_t *ds_next; 1697a9799022Sck uint64_t old_unique; 1698cde58dbcSMatthew Ahrens uint64_t used = 0, comp = 0, uncomp = 0; 1699fa9e4066Sahrens 1700745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1701745cd3c5Smaybee ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next)); 1702fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1703fa9e4066Sahrens 17043f9d6ad7SLin Ling old_unique = ds_next->ds_phys->ds_unique_bytes; 1705a9799022Sck 1706fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1707fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1708fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1709fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1710fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1711fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1712fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1713fa9e4066Sahrens 17143113f7ceSGeorge Wilson 1715cde58dbcSMatthew Ahrens if (ds_next->ds_deadlist.dl_oldfmt) { 1716cde58dbcSMatthew Ahrens process_old_deadlist(ds, ds_prev, ds_next, 1717cde58dbcSMatthew Ahrens after_branch_point, tx); 1718cde58dbcSMatthew Ahrens } else { 1719cde58dbcSMatthew Ahrens /* Adjust prev's unique space. */ 1720cde58dbcSMatthew Ahrens if (ds_prev && !after_branch_point) { 1721cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 1722cde58dbcSMatthew Ahrens ds_prev->ds_phys->ds_prev_snap_txg, 1723cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 1724cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1725cde58dbcSMatthew Ahrens ds_prev->ds_phys->ds_unique_bytes += used; 1726fa9e4066Sahrens } 172774e7dc98SMatthew Ahrens 1728cde58dbcSMatthew Ahrens /* Adjust snapused. */ 1729cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 1730cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, 1731cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1732cde58dbcSMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 1733cde58dbcSMatthew Ahrens -used, -comp, -uncomp, tx); 1734cde58dbcSMatthew Ahrens 1735cde58dbcSMatthew Ahrens /* Move blocks to be freed to pool's free list. */ 1736cde58dbcSMatthew Ahrens dsl_deadlist_move_bpobj(&ds_next->ds_deadlist, 1737cde58dbcSMatthew Ahrens &dp->dp_free_bpobj, ds->ds_phys->ds_prev_snap_txg, 1738cde58dbcSMatthew Ahrens tx); 1739cde58dbcSMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, 1740cde58dbcSMatthew Ahrens DD_USED_HEAD, used, comp, uncomp, tx); 1741cde58dbcSMatthew Ahrens dsl_dir_dirty(tx->tx_pool->dp_free_dir, tx); 1742cde58dbcSMatthew Ahrens 1743cde58dbcSMatthew Ahrens /* Merge our deadlist into next's and free it. */ 1744cde58dbcSMatthew Ahrens dsl_deadlist_merge(&ds_next->ds_deadlist, 1745cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj, tx); 1746cde58dbcSMatthew Ahrens } 1747cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1748cde58dbcSMatthew Ahrens dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx); 1749fa9e4066Sahrens 1750cde58dbcSMatthew Ahrens /* Collapse range in clone heads */ 1751cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(ds, 1752cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, tx); 1753fa9e4066Sahrens 17543f9d6ad7SLin Ling if (dsl_dataset_is_snapshot(ds_next)) { 1755cde58dbcSMatthew Ahrens dsl_dataset_t *ds_nextnext; 1756cde58dbcSMatthew Ahrens 1757fa9e4066Sahrens /* 1758fa9e4066Sahrens * Update next's unique to include blocks which 1759fa9e4066Sahrens * were previously shared by only this snapshot 1760fa9e4066Sahrens * and it. Those blocks will be born after the 1761fa9e4066Sahrens * prev snap and before this snap, and will have 1762fa9e4066Sahrens * died after the next snap and before the one 1763fa9e4066Sahrens * after that (ie. be on the snap after next's 1764fa9e4066Sahrens * deadlist). 1765fa9e4066Sahrens */ 1766745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1767745cd3c5Smaybee ds_next->ds_phys->ds_next_snap_obj, 1768cde58dbcSMatthew Ahrens FTAG, &ds_nextnext)); 1769cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_nextnext->ds_deadlist, 177074e7dc98SMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 1771cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, 1772cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1773cde58dbcSMatthew Ahrens ds_next->ds_phys->ds_unique_bytes += used; 1774cde58dbcSMatthew Ahrens dsl_dataset_rele(ds_nextnext, FTAG); 1775fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1776cde58dbcSMatthew Ahrens 1777cde58dbcSMatthew Ahrens /* Collapse range in this head. */ 1778cde58dbcSMatthew Ahrens dsl_dataset_t *hds; 1779cde58dbcSMatthew Ahrens VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 1780cde58dbcSMatthew Ahrens ds->ds_dir->dd_phys->dd_head_dataset_obj, 1781cde58dbcSMatthew Ahrens FTAG, &hds)); 1782cde58dbcSMatthew Ahrens dsl_deadlist_remove_key(&hds->ds_deadlist, 1783cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, tx); 1784cde58dbcSMatthew Ahrens dsl_dataset_rele(hds, FTAG); 1785cde58dbcSMatthew Ahrens 1786fa9e4066Sahrens } else { 1787fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1788745cd3c5Smaybee dsl_dataset_drop_ref(ds_next->ds_prev, ds_next); 1789745cd3c5Smaybee ds_next->ds_prev = NULL; 1790fa9e4066Sahrens if (ds_prev) { 1791745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1792745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 1793745cd3c5Smaybee ds_next, &ds_next->ds_prev)); 1794fa9e4066Sahrens } 1795a9799022Sck 1796a9799022Sck dsl_dataset_recalc_head_uniq(ds_next); 1797a9799022Sck 1798a9799022Sck /* 1799a9799022Sck * Reduce the amount of our unconsmed refreservation 1800a9799022Sck * being charged to our parent by the amount of 1801a9799022Sck * new unique data we have gained. 1802a9799022Sck */ 1803a9799022Sck if (old_unique < ds_next->ds_reserved) { 1804a9799022Sck int64_t mrsdelta; 1805a9799022Sck uint64_t new_unique = 1806a9799022Sck ds_next->ds_phys->ds_unique_bytes; 1807a9799022Sck 1808a9799022Sck ASSERT(old_unique <= new_unique); 1809a9799022Sck mrsdelta = MIN(new_unique - old_unique, 1810a9799022Sck ds_next->ds_reserved - old_unique); 181174e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 181274e7dc98SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 1813a9799022Sck } 1814fa9e4066Sahrens } 1815745cd3c5Smaybee dsl_dataset_rele(ds_next, FTAG); 1816fa9e4066Sahrens } else { 1817fa9e4066Sahrens /* 1818fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1819fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1820fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1821fa9e4066Sahrens * safe to ignore the deadlist contents.) 1822fa9e4066Sahrens */ 1823fa9e4066Sahrens struct killarg ka; 1824fa9e4066Sahrens 1825cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1826cde58dbcSMatthew Ahrens dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx); 1827fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1828fa9e4066Sahrens 1829fa9e4066Sahrens /* 1830fa9e4066Sahrens * Free everything that we point to (that's born after 1831fa9e4066Sahrens * the previous snapshot, if we are a clone) 1832fa9e4066Sahrens * 183374e7dc98SMatthew Ahrens * NB: this should be very quick, because we already 183474e7dc98SMatthew Ahrens * freed all the objects in open context. 1835fa9e4066Sahrens */ 183674e7dc98SMatthew Ahrens ka.ds = ds; 1837fa9e4066Sahrens ka.tx = tx; 183888b7b0f2SMatthew Ahrens err = traverse_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 183988b7b0f2SMatthew Ahrens TRAVERSE_POST, kill_blkptr, &ka); 1840fa9e4066Sahrens ASSERT3U(err, ==, 0); 18413e78c5fbSChris Kirby ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 184274e7dc98SMatthew Ahrens ds->ds_phys->ds_unique_bytes == 0); 1843ca45db41SChris Kirby 1844ca45db41SChris Kirby if (ds->ds_prev != NULL) { 1845cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 1846cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(mos, 1847cde58dbcSMatthew Ahrens ds->ds_prev->ds_dir->dd_phys->dd_clones, 1848cde58dbcSMatthew Ahrens ds->ds_object, tx)); 1849cde58dbcSMatthew Ahrens } 1850ca45db41SChris Kirby dsl_dataset_rele(ds->ds_prev, ds); 1851ca45db41SChris Kirby ds->ds_prev = ds_prev = NULL; 1852ca45db41SChris Kirby } 1853fa9e4066Sahrens } 1854fa9e4066Sahrens 18551d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1856745cd3c5Smaybee /* Erase the link in the dir */ 18571d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 18581d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1859745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0); 1860745cd3c5Smaybee err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1861745cd3c5Smaybee ASSERT(err == 0); 1862fa9e4066Sahrens } else { 1863fa9e4066Sahrens /* remove from snapshot namespace */ 1864fa9e4066Sahrens dsl_dataset_t *ds_head; 1865745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0); 1866745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1867745cd3c5Smaybee ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head)); 18688660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1869fa9e4066Sahrens #ifdef ZFS_DEBUG 1870fa9e4066Sahrens { 1871fa9e4066Sahrens uint64_t val; 1872ab04eb8eStimh 1873745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds_head, 1874ab04eb8eStimh ds->ds_snapname, &val); 1875fa9e4066Sahrens ASSERT3U(err, ==, 0); 1876fa9e4066Sahrens ASSERT3U(val, ==, obj); 1877fa9e4066Sahrens } 1878fa9e4066Sahrens #endif 1879745cd3c5Smaybee err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx); 1880fa9e4066Sahrens ASSERT(err == 0); 1881745cd3c5Smaybee dsl_dataset_rele(ds_head, FTAG); 1882fa9e4066Sahrens } 1883fa9e4066Sahrens 1884fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1885745cd3c5Smaybee dsl_dataset_rele(ds_prev, FTAG); 1886fa9e4066Sahrens 1887990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 18883f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_DESTROY, dp->dp_spa, tx, 18893f9d6ad7SLin Ling "dataset = %llu", ds->ds_object); 1890ecd6cf80Smarks 1891088f3894Sahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 1892088f3894Sahrens uint64_t count; 1893088f3894Sahrens ASSERT(0 == zap_count(mos, 1894088f3894Sahrens ds->ds_phys->ds_next_clones_obj, &count) && count == 0); 1895088f3894Sahrens VERIFY(0 == dmu_object_free(mos, 1896088f3894Sahrens ds->ds_phys->ds_next_clones_obj, tx)); 1897088f3894Sahrens } 189874e7dc98SMatthew Ahrens if (ds->ds_phys->ds_props_obj != 0) 189974e7dc98SMatthew Ahrens VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_props_obj, tx)); 1900842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) 1901842727c2SChris Kirby VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx)); 1902745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 1903745cd3c5Smaybee ds->ds_dir = NULL; 1904745cd3c5Smaybee dsl_dataset_drain_refs(ds, tag); 19051d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1906842727c2SChris Kirby 1907842727c2SChris Kirby if (dsda->rm_origin) { 1908842727c2SChris Kirby /* 1909842727c2SChris Kirby * Remove the origin of the clone we just destroyed. 1910842727c2SChris Kirby */ 1911842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1912842727c2SChris Kirby 1913ca45db41SChris Kirby ndsda.ds = dsda->rm_origin; 19143f9d6ad7SLin Ling dsl_dataset_destroy_sync(&ndsda, tag, tx); 1915842727c2SChris Kirby } 1916fa9e4066Sahrens } 1917fa9e4066Sahrens 1918a9799022Sck static int 1919a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx) 1920a9799022Sck { 1921a9799022Sck uint64_t asize; 1922a9799022Sck 1923a9799022Sck if (!dmu_tx_is_syncing(tx)) 1924a9799022Sck return (0); 1925a9799022Sck 1926a9799022Sck /* 1927a9799022Sck * If there's an fs-only reservation, any blocks that might become 1928a9799022Sck * owned by the snapshot dataset must be accommodated by space 1929a9799022Sck * outside of the reservation. 1930a9799022Sck */ 19313f9d6ad7SLin Ling ASSERT(ds->ds_reserved == 0 || DS_UNIQUE_IS_ACCURATE(ds)); 19323f9d6ad7SLin Ling asize = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 1933a9799022Sck if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, FALSE)) 1934a9799022Sck return (ENOSPC); 1935a9799022Sck 1936a9799022Sck /* 1937a9799022Sck * Propogate any reserved space for this snapshot to other 1938a9799022Sck * snapshot checks in this sync group. 1939a9799022Sck */ 1940a9799022Sck if (asize > 0) 1941a9799022Sck dsl_dir_willuse_space(ds->ds_dir, asize, tx); 1942a9799022Sck 1943a9799022Sck return (0); 1944a9799022Sck } 1945a9799022Sck 1946fa9e4066Sahrens int 19471d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1948fa9e4066Sahrens { 19493cb34c60Sahrens dsl_dataset_t *ds = arg1; 19501d452cf5Sahrens const char *snapname = arg2; 1951fa9e4066Sahrens int err; 19521d452cf5Sahrens uint64_t value; 1953fa9e4066Sahrens 19541d452cf5Sahrens /* 19551d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 19561d452cf5Sahrens * is already one, try again. 19571d452cf5Sahrens */ 19581d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 19591d452cf5Sahrens return (EAGAIN); 1960fa9e4066Sahrens 19611d452cf5Sahrens /* 19621d452cf5Sahrens * Check for conflicting name snapshot name. 19631d452cf5Sahrens */ 1964745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds, snapname, &value); 19651d452cf5Sahrens if (err == 0) 1966fa9e4066Sahrens return (EEXIST); 19671d452cf5Sahrens if (err != ENOENT) 19681d452cf5Sahrens return (err); 1969fa9e4066Sahrens 1970b7661cccSmmusante /* 1971b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 1972b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 1973b7661cccSmmusante */ 1974b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 1975b7661cccSmmusante return (ENAMETOOLONG); 1976b7661cccSmmusante 1977a9799022Sck err = dsl_dataset_snapshot_reserve_space(ds, tx); 1978a9799022Sck if (err) 1979a9799022Sck return (err); 1980a9799022Sck 19811d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 19821d452cf5Sahrens return (0); 19831d452cf5Sahrens } 1984fa9e4066Sahrens 19851d452cf5Sahrens void 19863f9d6ad7SLin Ling dsl_dataset_snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx) 19871d452cf5Sahrens { 19883cb34c60Sahrens dsl_dataset_t *ds = arg1; 19891d452cf5Sahrens const char *snapname = arg2; 19901d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 19911d452cf5Sahrens dmu_buf_t *dbuf; 19921d452cf5Sahrens dsl_dataset_phys_t *dsphys; 1993088f3894Sahrens uint64_t dsobj, crtxg; 19941d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 19951d452cf5Sahrens int err; 1996fa9e4066Sahrens 19971d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1998fa9e4066Sahrens 1999088f3894Sahrens /* 2000088f3894Sahrens * The origin's ds_creation_txg has to be < TXG_INITIAL 2001088f3894Sahrens */ 2002088f3894Sahrens if (strcmp(snapname, ORIGIN_DIR_NAME) == 0) 2003088f3894Sahrens crtxg = 1; 2004088f3894Sahrens else 2005088f3894Sahrens crtxg = tx->tx_txg; 2006088f3894Sahrens 20071649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 20081649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 2009ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 2010fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 2011fa9e4066Sahrens dsphys = dbuf->db_data; 2012745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 20131d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 2014fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 2015fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 2016fa9e4066Sahrens sizeof (dsphys->ds_guid)); 2017fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 2018fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 2019fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 2020fa9e4066Sahrens dsphys->ds_num_children = 1; 2021fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 2022088f3894Sahrens dsphys->ds_creation_txg = crtxg; 2023fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 2024fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 2025fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 2026fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 202799653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 2028fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 2029ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 2030fa9e4066Sahrens 20311d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 20321d452cf5Sahrens if (ds->ds_prev) { 2033088f3894Sahrens uint64_t next_clones_obj = 2034088f3894Sahrens ds->ds_prev->ds_phys->ds_next_clones_obj; 20351d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 2036fa9e4066Sahrens ds->ds_object || 20371d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 20381d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 20391d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 2040fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 20411d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 20421d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 2043088f3894Sahrens } else if (next_clones_obj != 0) { 2044c33e334fSMatthew Ahrens remove_from_next_clones(ds->ds_prev, 2045c33e334fSMatthew Ahrens dsphys->ds_next_snap_obj, tx); 2046088f3894Sahrens VERIFY3U(0, ==, zap_add_int(mos, 2047088f3894Sahrens next_clones_obj, dsobj, tx)); 2048fa9e4066Sahrens } 2049fa9e4066Sahrens } 2050fa9e4066Sahrens 2051a9799022Sck /* 2052a9799022Sck * If we have a reference-reservation on this dataset, we will 2053a9799022Sck * need to increase the amount of refreservation being charged 2054a9799022Sck * since our unique space is going to zero. 2055a9799022Sck */ 2056a9799022Sck if (ds->ds_reserved) { 20573f9d6ad7SLin Ling int64_t delta; 20583f9d6ad7SLin Ling ASSERT(DS_UNIQUE_IS_ACCURATE(ds)); 20593f9d6ad7SLin Ling delta = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 206074e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, 20613f9d6ad7SLin Ling delta, 0, 0, tx); 2062a9799022Sck } 2063a9799022Sck 2064fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 2065cde58dbcSMatthew Ahrens zfs_dbgmsg("taking snapshot %s@%s/%llu; newkey=%llu", 2066cde58dbcSMatthew Ahrens ds->ds_dir->dd_myname, snapname, dsobj, 2067cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg); 2068cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj = dsl_deadlist_clone(&ds->ds_deadlist, 2069cde58dbcSMatthew Ahrens UINT64_MAX, ds->ds_phys->ds_prev_snap_obj, tx); 2070cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 2071cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, mos, ds->ds_phys->ds_deadlist_obj); 2072cde58dbcSMatthew Ahrens dsl_deadlist_add_key(&ds->ds_deadlist, 2073cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, tx); 2074cde58dbcSMatthew Ahrens 2075a4611edeSahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg); 2076fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 2077088f3894Sahrens ds->ds_phys->ds_prev_snap_txg = crtxg; 2078fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 2079a9799022Sck if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 2080a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 2081fa9e4066Sahrens 2082fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 2083fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 2084fa9e4066Sahrens ASSERT(err == 0); 2085fa9e4066Sahrens 2086fa9e4066Sahrens if (ds->ds_prev) 2087745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 2088745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 2089745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev)); 2090ecd6cf80Smarks 20913f9d6ad7SLin Ling dsl_scan_ds_snapshotted(ds, tx); 2092088f3894Sahrens 209371eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 209471eb0538SChris Kirby 20953f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_SNAPSHOT, dp->dp_spa, tx, 209640feaa91Sahrens "dataset = %llu", dsobj); 2097fa9e4066Sahrens } 2098fa9e4066Sahrens 2099fa9e4066Sahrens void 2100c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 2101fa9e4066Sahrens { 2102fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 2103503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 2104fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 2105fa9e4066Sahrens 210691ebeef5Sahrens /* 210791ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 210891ebeef5Sahrens * sync it out now. 210991ebeef5Sahrens */ 211091ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 211191ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 211291ebeef5Sahrens 2113fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 2114503ad85cSMatthew Ahrens dmu_objset_sync(ds->ds_objset, zio, tx); 2115fa9e4066Sahrens } 2116fa9e4066Sahrens 2117fa9e4066Sahrens void 2118a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 2119fa9e4066Sahrens { 2120a9799022Sck uint64_t refd, avail, uobjs, aobjs; 2121a9799022Sck 2122a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 2123fa9e4066Sahrens 2124a9799022Sck dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); 2125a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); 2126a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); 2127a9799022Sck 2128a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 2129a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 2130a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 2131a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 2132a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, 2133a9799022Sck ds->ds_quota); 2134a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, 2135a9799022Sck ds->ds_reserved); 2136c5904d13Seschrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, 2137c5904d13Seschrock ds->ds_phys->ds_guid); 21381d713200SEric Schrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE, 21393f9d6ad7SLin Ling ds->ds_phys->ds_unique_bytes); 21401d713200SEric Schrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID, 21411d713200SEric Schrock ds->ds_object); 214292241e0bSTom Erickson dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, 214392241e0bSTom Erickson ds->ds_userrefs); 2144842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2145842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2146fa9e4066Sahrens 2147fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2148fa9e4066Sahrens /* 2149fa9e4066Sahrens * This is a snapshot; override the dd's space used with 2150a2eea2e1Sahrens * our unique space and compression ratio. 2151fa9e4066Sahrens */ 2152a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 2153a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 2154a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 2155a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 2156a2eea2e1Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 2157a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes)); 2158fa9e4066Sahrens } 2159fa9e4066Sahrens } 2160fa9e4066Sahrens 2161a2eea2e1Sahrens void 2162a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2163a2eea2e1Sahrens { 2164a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2165a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 21663cb34c60Sahrens stat->dds_guid = ds->ds_phys->ds_guid; 2167a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2168a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 2169a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 2170ebedde84SEric Taylor } else { 2171ebedde84SEric Taylor stat->dds_is_snapshot = B_FALSE; 2172ebedde84SEric Taylor stat->dds_num_clones = 0; 2173a2eea2e1Sahrens } 2174a2eea2e1Sahrens 2175a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 21764ccbb6e7Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 2177088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 2178a2eea2e1Sahrens dsl_dataset_t *ods; 2179a2eea2e1Sahrens 2180745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool, 2181745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods)); 21823cb34c60Sahrens dsl_dataset_name(ods, stat->dds_origin); 2183745cd3c5Smaybee dsl_dataset_drop_ref(ods, FTAG); 2184ebedde84SEric Taylor } else { 2185ebedde84SEric Taylor stat->dds_origin[0] = '\0'; 2186a2eea2e1Sahrens } 21874ccbb6e7Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2188a2eea2e1Sahrens } 2189a2eea2e1Sahrens 2190a2eea2e1Sahrens uint64_t 2191a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 2192a2eea2e1Sahrens { 219391ebeef5Sahrens return (ds->ds_fsid_guid); 2194a2eea2e1Sahrens } 2195a2eea2e1Sahrens 2196a2eea2e1Sahrens void 2197a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 2198a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 2199a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 2200fa9e4066Sahrens { 2201a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 2202a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 2203a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) 2204a9799022Sck *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes; 2205a9799022Sck if (ds->ds_quota != 0) { 2206a9799022Sck /* 2207a9799022Sck * Adjust available bytes according to refquota 2208a9799022Sck */ 2209a9799022Sck if (*refdbytesp < ds->ds_quota) 2210a9799022Sck *availbytesp = MIN(*availbytesp, 2211a9799022Sck ds->ds_quota - *refdbytesp); 2212a9799022Sck else 2213a9799022Sck *availbytesp = 0; 2214a9799022Sck } 2215a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 2216a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 2217fa9e4066Sahrens } 2218fa9e4066Sahrens 2219f18faf3fSek boolean_t 2220f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 2221f18faf3fSek { 2222f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 2223f18faf3fSek 2224f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 2225f18faf3fSek dsl_pool_sync_context(dp)); 2226f18faf3fSek if (ds->ds_prev == NULL) 2227f18faf3fSek return (B_FALSE); 2228f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 2229f18faf3fSek ds->ds_prev->ds_phys->ds_creation_txg) 2230f18faf3fSek return (B_TRUE); 2231f18faf3fSek return (B_FALSE); 2232f18faf3fSek } 2233f18faf3fSek 22341d452cf5Sahrens /* ARGSUSED */ 2235fa9e4066Sahrens static int 22361d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 2237fa9e4066Sahrens { 22381d452cf5Sahrens dsl_dataset_t *ds = arg1; 22391d452cf5Sahrens char *newsnapname = arg2; 22401d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 22411d452cf5Sahrens dsl_dataset_t *hds; 2242fa9e4066Sahrens uint64_t val; 22431d452cf5Sahrens int err; 2244fa9e4066Sahrens 2245745cd3c5Smaybee err = dsl_dataset_hold_obj(dd->dd_pool, 2246745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds); 2247fa9e4066Sahrens if (err) 2248fa9e4066Sahrens return (err); 2249fa9e4066Sahrens 22501d452cf5Sahrens /* new name better not be in use */ 2251745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, newsnapname, &val); 2252745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 22531d452cf5Sahrens 22541d452cf5Sahrens if (err == 0) 22551d452cf5Sahrens err = EEXIST; 22561d452cf5Sahrens else if (err == ENOENT) 22571d452cf5Sahrens err = 0; 2258cdf5b4caSmmusante 2259cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 2260cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 2261cdf5b4caSmmusante err = ENAMETOOLONG; 2262cdf5b4caSmmusante 22631d452cf5Sahrens return (err); 22641d452cf5Sahrens } 2265fa9e4066Sahrens 22661d452cf5Sahrens static void 22673f9d6ad7SLin Ling dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx) 22681d452cf5Sahrens { 22691d452cf5Sahrens dsl_dataset_t *ds = arg1; 2270ecd6cf80Smarks const char *newsnapname = arg2; 22711d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 22721d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 22731d452cf5Sahrens dsl_dataset_t *hds; 22741d452cf5Sahrens int err; 2275fa9e4066Sahrens 22761d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 2277fa9e4066Sahrens 2278745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, 2279745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds)); 2280fa9e4066Sahrens 22811d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2282745cd3c5Smaybee err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx); 2283fa9e4066Sahrens ASSERT3U(err, ==, 0); 22841d452cf5Sahrens mutex_enter(&ds->ds_lock); 22851d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 22861d452cf5Sahrens mutex_exit(&ds->ds_lock); 22871d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 22881d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 2289fa9e4066Sahrens ASSERT3U(err, ==, 0); 2290fa9e4066Sahrens 22913f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 22923f9d6ad7SLin Ling "dataset = %llu", ds->ds_object); 2293745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 2294fa9e4066Sahrens } 2295fa9e4066Sahrens 2296f18faf3fSek struct renamesnaparg { 2297cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 2298cdf5b4caSmmusante char failed[MAXPATHLEN]; 2299cdf5b4caSmmusante char *oldsnap; 2300cdf5b4caSmmusante char *newsnap; 2301cdf5b4caSmmusante }; 2302cdf5b4caSmmusante 2303cdf5b4caSmmusante static int 2304fd136879SMatthew Ahrens dsl_snapshot_rename_one(const char *name, void *arg) 2305cdf5b4caSmmusante { 2306f18faf3fSek struct renamesnaparg *ra = arg; 2307cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 2308fd136879SMatthew Ahrens char *snapname; 2309cdf5b4caSmmusante int err; 2310cdf5b4caSmmusante 2311fd136879SMatthew Ahrens snapname = kmem_asprintf("%s@%s", name, ra->oldsnap); 2312fd136879SMatthew Ahrens (void) strlcpy(ra->failed, snapname, sizeof (ra->failed)); 2313ecd6cf80Smarks 2314ecd6cf80Smarks /* 2315ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 2316ecd6cf80Smarks * so we just pass name for both the to/from argument. 2317ecd6cf80Smarks */ 2318fd136879SMatthew Ahrens err = zfs_secpolicy_rename_perms(snapname, snapname, CRED()); 2319fd136879SMatthew Ahrens if (err != 0) { 2320fd136879SMatthew Ahrens strfree(snapname); 2321fd136879SMatthew Ahrens return (err == ENOENT ? 0 : err); 2322ecd6cf80Smarks } 2323ecd6cf80Smarks 2324745cd3c5Smaybee #ifdef _KERNEL 2325745cd3c5Smaybee /* 2326745cd3c5Smaybee * For all filesystems undergoing rename, we'll need to unmount it. 2327745cd3c5Smaybee */ 2328fd136879SMatthew Ahrens (void) zfs_unmount_snap(snapname, NULL); 2329745cd3c5Smaybee #endif 2330fd136879SMatthew Ahrens err = dsl_dataset_hold(snapname, ra->dstg, &ds); 23313f1f8012SMatthew Ahrens strfree(snapname); 23323f1f8012SMatthew Ahrens if (err != 0) 2333fd136879SMatthew Ahrens return (err == ENOENT ? 0 : err); 2334cdf5b4caSmmusante 2335cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 2336cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 2337cdf5b4caSmmusante 2338cdf5b4caSmmusante return (0); 2339cdf5b4caSmmusante } 2340cdf5b4caSmmusante 2341cdf5b4caSmmusante static int 2342cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 2343cdf5b4caSmmusante { 2344cdf5b4caSmmusante int err; 2345f18faf3fSek struct renamesnaparg *ra; 2346cdf5b4caSmmusante dsl_sync_task_t *dst; 2347cdf5b4caSmmusante spa_t *spa; 2348cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 2349fd136879SMatthew Ahrens int len = strlen(oldname) + 1; 2350cdf5b4caSmmusante 2351cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 2352cdf5b4caSmmusante cp = strchr(fsname, '@'); 2353cdf5b4caSmmusante *cp = '\0'; 2354cdf5b4caSmmusante 235540feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 2356cdf5b4caSmmusante if (err) { 2357fd136879SMatthew Ahrens kmem_free(fsname, len); 2358cdf5b4caSmmusante return (err); 2359cdf5b4caSmmusante } 2360f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 2361cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 2362cdf5b4caSmmusante 2363cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 2364cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 2365cdf5b4caSmmusante *ra->failed = '\0'; 2366cdf5b4caSmmusante 2367cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 2368cdf5b4caSmmusante DS_FIND_CHILDREN); 2369fd136879SMatthew Ahrens kmem_free(fsname, len); 2370cdf5b4caSmmusante 2371cdf5b4caSmmusante if (err == 0) { 2372cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 2373cdf5b4caSmmusante } 2374cdf5b4caSmmusante 2375cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 2376cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 2377cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 2378cdf5b4caSmmusante if (dst->dst_err) { 2379cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 2380fd136879SMatthew Ahrens (void) strlcat(ra->failed, "@", sizeof (ra->failed)); 2381fd136879SMatthew Ahrens (void) strlcat(ra->failed, ra->newsnap, 2382fd136879SMatthew Ahrens sizeof (ra->failed)); 2383cdf5b4caSmmusante } 2384745cd3c5Smaybee dsl_dataset_rele(ds, ra->dstg); 2385cdf5b4caSmmusante } 2386cdf5b4caSmmusante 2387ecd6cf80Smarks if (err) 2388fd136879SMatthew Ahrens (void) strlcpy(oldname, ra->failed, sizeof (ra->failed)); 2389cdf5b4caSmmusante 2390cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 2391f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 2392cdf5b4caSmmusante spa_close(spa, FTAG); 2393cdf5b4caSmmusante return (err); 2394cdf5b4caSmmusante } 2395cdf5b4caSmmusante 23963a5a36beSmmusante static int 2397fd136879SMatthew Ahrens dsl_valid_rename(const char *oldname, void *arg) 23983a5a36beSmmusante { 23993a5a36beSmmusante int delta = *(int *)arg; 24003a5a36beSmmusante 24013a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 24023a5a36beSmmusante return (ENAMETOOLONG); 24033a5a36beSmmusante 24043a5a36beSmmusante return (0); 24053a5a36beSmmusante } 24063a5a36beSmmusante 2407fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 2408fa9e4066Sahrens int 2409745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive) 2410fa9e4066Sahrens { 2411fa9e4066Sahrens dsl_dir_t *dd; 24121d452cf5Sahrens dsl_dataset_t *ds; 2413fa9e4066Sahrens const char *tail; 2414fa9e4066Sahrens int err; 2415fa9e4066Sahrens 24161d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 2417ea8dc4b6Seschrock if (err) 2418ea8dc4b6Seschrock return (err); 2419370c1af0SSanjeev Bagewadi 2420fa9e4066Sahrens if (tail == NULL) { 24213a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 24223a5a36beSmmusante 2423088f3894Sahrens /* if we're growing, validate child name lengths */ 24243a5a36beSmmusante if (delta > 0) 24253a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 24263a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 24273a5a36beSmmusante 2428b91a2f0bSMatthew Ahrens if (err == 0) 24293a5a36beSmmusante err = dsl_dir_rename(dd, newname); 2430fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2431fa9e4066Sahrens return (err); 2432fa9e4066Sahrens } 2433370c1af0SSanjeev Bagewadi 2434fa9e4066Sahrens if (tail[0] != '@') { 2435681d9761SEric Taylor /* the name ended in a nonexistent component */ 2436fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2437fa9e4066Sahrens return (ENOENT); 2438fa9e4066Sahrens } 2439fa9e4066Sahrens 2440fa9e4066Sahrens dsl_dir_close(dd, FTAG); 24411d452cf5Sahrens 24421d452cf5Sahrens /* new name must be snapshot in same filesystem */ 24431d452cf5Sahrens tail = strchr(newname, '@'); 24441d452cf5Sahrens if (tail == NULL) 24451d452cf5Sahrens return (EINVAL); 24461d452cf5Sahrens tail++; 24471d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 24481d452cf5Sahrens return (EXDEV); 24491d452cf5Sahrens 2450cdf5b4caSmmusante if (recursive) { 2451cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 2452cdf5b4caSmmusante } else { 2453745cd3c5Smaybee err = dsl_dataset_hold(oldname, FTAG, &ds); 2454cdf5b4caSmmusante if (err) 2455cdf5b4caSmmusante return (err); 24561d452cf5Sahrens 2457cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2458cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 2459cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 24601d452cf5Sahrens 2461745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2462cdf5b4caSmmusante } 24631d452cf5Sahrens 2464fa9e4066Sahrens return (err); 2465fa9e4066Sahrens } 246699653d4eSeschrock 2467088f3894Sahrens struct promotenode { 2468745cd3c5Smaybee list_node_t link; 2469745cd3c5Smaybee dsl_dataset_t *ds; 2470745cd3c5Smaybee }; 2471745cd3c5Smaybee 24721d452cf5Sahrens struct promotearg { 247374e7dc98SMatthew Ahrens list_t shared_snaps, origin_snaps, clone_snaps; 24743f9d6ad7SLin Ling dsl_dataset_t *origin_origin; 247574e7dc98SMatthew Ahrens uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; 2476681d9761SEric Taylor char *err_ds; 24771d452cf5Sahrens }; 24781d452cf5Sahrens 247974e7dc98SMatthew Ahrens static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep); 24803f9d6ad7SLin Ling static boolean_t snaplist_unstable(list_t *l); 248174e7dc98SMatthew Ahrens 248299653d4eSeschrock static int 24831d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 248499653d4eSeschrock { 24851d452cf5Sahrens dsl_dataset_t *hds = arg1; 24861d452cf5Sahrens struct promotearg *pa = arg2; 248774e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2488745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 2489745cd3c5Smaybee int err; 2490cde58dbcSMatthew Ahrens uint64_t unused; 24911d452cf5Sahrens 2492088f3894Sahrens /* Check that it is a real clone */ 2493088f3894Sahrens if (!dsl_dir_is_clone(hds->ds_dir)) 249499653d4eSeschrock return (EINVAL); 249599653d4eSeschrock 24961d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 24971d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 24981d452cf5Sahrens return (0); 24991d452cf5Sahrens 2500745cd3c5Smaybee if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) 2501745cd3c5Smaybee return (EXDEV); 250299653d4eSeschrock 25033cb34c60Sahrens /* compute origin's new unique space */ 250474e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 250574e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 2506cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&snap->ds->ds_deadlist, 2507cde58dbcSMatthew Ahrens origin_ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, 2508cde58dbcSMatthew Ahrens &pa->unique, &unused, &unused); 250999653d4eSeschrock 2510745cd3c5Smaybee /* 2511745cd3c5Smaybee * Walk the snapshots that we are moving 2512745cd3c5Smaybee * 251374e7dc98SMatthew Ahrens * Compute space to transfer. Consider the incremental changes 251474e7dc98SMatthew Ahrens * to used for each snapshot: 251574e7dc98SMatthew Ahrens * (my used) = (prev's used) + (blocks born) - (blocks killed) 251674e7dc98SMatthew Ahrens * So each snapshot gave birth to: 251774e7dc98SMatthew Ahrens * (blocks born) = (my used) - (prev's used) + (blocks killed) 2518745cd3c5Smaybee * So a sequence would look like: 251974e7dc98SMatthew Ahrens * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0) 2520745cd3c5Smaybee * Which simplifies to: 252174e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + k1 + k0 2522745cd3c5Smaybee * Note however, if we stop before we reach the ORIGIN we get: 252374e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + kM - uM-1 2524745cd3c5Smaybee */ 2525745cd3c5Smaybee pa->used = origin_ds->ds_phys->ds_used_bytes; 2526745cd3c5Smaybee pa->comp = origin_ds->ds_phys->ds_compressed_bytes; 2527745cd3c5Smaybee pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes; 252874e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 252974e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 253099653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 2531745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 253299653d4eSeschrock 253399653d4eSeschrock /* Check that the snapshot name does not conflict */ 253474e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2535745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); 2536681d9761SEric Taylor if (err == 0) { 2537681d9761SEric Taylor err = EEXIST; 2538681d9761SEric Taylor goto out; 2539681d9761SEric Taylor } 2540745cd3c5Smaybee if (err != ENOENT) 2541681d9761SEric Taylor goto out; 254299653d4eSeschrock 2543745cd3c5Smaybee /* The very first snapshot does not have a deadlist */ 254474e7dc98SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 254574e7dc98SMatthew Ahrens continue; 254674e7dc98SMatthew Ahrens 2547cde58dbcSMatthew Ahrens dsl_deadlist_space(&ds->ds_deadlist, 2548cde58dbcSMatthew Ahrens &dlused, &dlcomp, &dluncomp); 254974e7dc98SMatthew Ahrens pa->used += dlused; 255074e7dc98SMatthew Ahrens pa->comp += dlcomp; 255174e7dc98SMatthew Ahrens pa->uncomp += dluncomp; 255274e7dc98SMatthew Ahrens } 2553745cd3c5Smaybee 2554745cd3c5Smaybee /* 2555745cd3c5Smaybee * If we are a clone of a clone then we never reached ORIGIN, 2556745cd3c5Smaybee * so we need to subtract out the clone origin's used space. 2557745cd3c5Smaybee */ 255874e7dc98SMatthew Ahrens if (pa->origin_origin) { 255974e7dc98SMatthew Ahrens pa->used -= pa->origin_origin->ds_phys->ds_used_bytes; 256074e7dc98SMatthew Ahrens pa->comp -= pa->origin_origin->ds_phys->ds_compressed_bytes; 256174e7dc98SMatthew Ahrens pa->uncomp -= pa->origin_origin->ds_phys->ds_uncompressed_bytes; 256299653d4eSeschrock } 256399653d4eSeschrock 256499653d4eSeschrock /* Check that there is enough space here */ 256574e7dc98SMatthew Ahrens err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir, 256674e7dc98SMatthew Ahrens pa->used); 256774e7dc98SMatthew Ahrens if (err) 256874e7dc98SMatthew Ahrens return (err); 256974e7dc98SMatthew Ahrens 257074e7dc98SMatthew Ahrens /* 257174e7dc98SMatthew Ahrens * Compute the amounts of space that will be used by snapshots 257274e7dc98SMatthew Ahrens * after the promotion (for both origin and clone). For each, 257374e7dc98SMatthew Ahrens * it is the amount of space that will be on all of their 257474e7dc98SMatthew Ahrens * deadlists (that was not born before their new origin). 257574e7dc98SMatthew Ahrens */ 257674e7dc98SMatthew Ahrens if (hds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 257774e7dc98SMatthew Ahrens uint64_t space; 257874e7dc98SMatthew Ahrens 257974e7dc98SMatthew Ahrens /* 258074e7dc98SMatthew Ahrens * Note, typically this will not be a clone of a clone, 25813f9d6ad7SLin Ling * so dd_origin_txg will be < TXG_INITIAL, so 2582cde58dbcSMatthew Ahrens * these snaplist_space() -> dsl_deadlist_space_range() 258374e7dc98SMatthew Ahrens * calls will be fast because they do not have to 258474e7dc98SMatthew Ahrens * iterate over all bps. 258574e7dc98SMatthew Ahrens */ 258674e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 258774e7dc98SMatthew Ahrens err = snaplist_space(&pa->shared_snaps, 25883f9d6ad7SLin Ling snap->ds->ds_dir->dd_origin_txg, &pa->cloneusedsnap); 258974e7dc98SMatthew Ahrens if (err) 259074e7dc98SMatthew Ahrens return (err); 259174e7dc98SMatthew Ahrens 259274e7dc98SMatthew Ahrens err = snaplist_space(&pa->clone_snaps, 25933f9d6ad7SLin Ling snap->ds->ds_dir->dd_origin_txg, &space); 259474e7dc98SMatthew Ahrens if (err) 259574e7dc98SMatthew Ahrens return (err); 259674e7dc98SMatthew Ahrens pa->cloneusedsnap += space; 259774e7dc98SMatthew Ahrens } 259874e7dc98SMatthew Ahrens if (origin_ds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 259974e7dc98SMatthew Ahrens err = snaplist_space(&pa->origin_snaps, 260074e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_creation_txg, &pa->originusedsnap); 260174e7dc98SMatthew Ahrens if (err) 260274e7dc98SMatthew Ahrens return (err); 2603745cd3c5Smaybee } 26041d452cf5Sahrens 260574e7dc98SMatthew Ahrens return (0); 2606681d9761SEric Taylor out: 2607681d9761SEric Taylor pa->err_ds = snap->ds->ds_snapname; 2608681d9761SEric Taylor return (err); 26091d452cf5Sahrens } 261099653d4eSeschrock 26111d452cf5Sahrens static void 26123f9d6ad7SLin Ling dsl_dataset_promote_sync(void *arg1, void *arg2, dmu_tx_t *tx) 26131d452cf5Sahrens { 26141d452cf5Sahrens dsl_dataset_t *hds = arg1; 26151d452cf5Sahrens struct promotearg *pa = arg2; 261674e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2617745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 261874e7dc98SMatthew Ahrens dsl_dataset_t *origin_head; 26191d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 26201d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 26213cb34c60Sahrens dsl_dir_t *odd = NULL; 2622088f3894Sahrens uint64_t oldnext_obj; 262374e7dc98SMatthew Ahrens int64_t delta; 26241d452cf5Sahrens 26251d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 26261d452cf5Sahrens 262774e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 262874e7dc98SMatthew Ahrens origin_head = snap->ds; 262974e7dc98SMatthew Ahrens 26300b69c2f0Sahrens /* 26313cb34c60Sahrens * We need to explicitly open odd, since origin_ds's dd will be 26320b69c2f0Sahrens * changing. 26330b69c2f0Sahrens */ 26343cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object, 26353cb34c60Sahrens NULL, FTAG, &odd)); 263699653d4eSeschrock 2637745cd3c5Smaybee /* change origin's next snap */ 2638745cd3c5Smaybee dmu_buf_will_dirty(origin_ds->ds_dbuf, tx); 2639088f3894Sahrens oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj; 264074e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 264174e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 264274e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj = snap->ds->ds_object; 2643745cd3c5Smaybee 2644088f3894Sahrens /* change the origin's next clone */ 2645088f3894Sahrens if (origin_ds->ds_phys->ds_next_clones_obj) { 2646c33e334fSMatthew Ahrens remove_from_next_clones(origin_ds, snap->ds->ds_object, tx); 2647088f3894Sahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2648088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2649088f3894Sahrens oldnext_obj, tx)); 2650088f3894Sahrens } 2651088f3894Sahrens 2652745cd3c5Smaybee /* change origin */ 2653745cd3c5Smaybee dmu_buf_will_dirty(dd->dd_dbuf, tx); 2654745cd3c5Smaybee ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object); 2655745cd3c5Smaybee dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj; 26563f9d6ad7SLin Ling dd->dd_origin_txg = origin_head->ds_dir->dd_origin_txg; 2657745cd3c5Smaybee dmu_buf_will_dirty(odd->dd_dbuf, tx); 2658745cd3c5Smaybee odd->dd_phys->dd_origin_obj = origin_ds->ds_object; 26593f9d6ad7SLin Ling origin_head->ds_dir->dd_origin_txg = 26603f9d6ad7SLin Ling origin_ds->ds_phys->ds_creation_txg; 2661745cd3c5Smaybee 2662cde58dbcSMatthew Ahrens /* change dd_clone entries */ 2663cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 2664cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2665cde58dbcSMatthew Ahrens odd->dd_phys->dd_clones, hds->ds_object, tx)); 2666cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2667cde58dbcSMatthew Ahrens pa->origin_origin->ds_dir->dd_phys->dd_clones, 2668cde58dbcSMatthew Ahrens hds->ds_object, tx)); 2669cde58dbcSMatthew Ahrens 2670cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2671cde58dbcSMatthew Ahrens pa->origin_origin->ds_dir->dd_phys->dd_clones, 2672cde58dbcSMatthew Ahrens origin_head->ds_object, tx)); 2673cde58dbcSMatthew Ahrens if (dd->dd_phys->dd_clones == 0) { 2674cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones = zap_create(dp->dp_meta_objset, 2675cde58dbcSMatthew Ahrens DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx); 2676cde58dbcSMatthew Ahrens } 2677cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2678cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones, origin_head->ds_object, tx)); 2679cde58dbcSMatthew Ahrens 2680cde58dbcSMatthew Ahrens } 2681cde58dbcSMatthew Ahrens 268299653d4eSeschrock /* move snapshots to this dir */ 268374e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 268474e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 2685745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 268699653d4eSeschrock 26873baa08fcSek /* unregister props as dsl_dir is changing */ 2688503ad85cSMatthew Ahrens if (ds->ds_objset) { 2689503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 2690503ad85cSMatthew Ahrens ds->ds_objset = NULL; 26913baa08fcSek } 269299653d4eSeschrock /* move snap name entry */ 269374e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 269474e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_snap_remove(origin_head, 2695745cd3c5Smaybee ds->ds_snapname, tx)); 26961d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 269799653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 269899653d4eSeschrock 8, 1, &ds->ds_object, tx)); 2699cde58dbcSMatthew Ahrens 270099653d4eSeschrock /* change containing dsl_dir */ 270199653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 27023cb34c60Sahrens ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object); 270399653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 27043cb34c60Sahrens ASSERT3P(ds->ds_dir, ==, odd); 270599653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 27061d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 270799653d4eSeschrock NULL, ds, &ds->ds_dir)); 270899653d4eSeschrock 2709cde58dbcSMatthew Ahrens /* move any clone references */ 2710cde58dbcSMatthew Ahrens if (ds->ds_phys->ds_next_clones_obj && 2711cde58dbcSMatthew Ahrens spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 2712cde58dbcSMatthew Ahrens zap_cursor_t zc; 2713cde58dbcSMatthew Ahrens zap_attribute_t za; 2714cde58dbcSMatthew Ahrens 2715cde58dbcSMatthew Ahrens for (zap_cursor_init(&zc, dp->dp_meta_objset, 2716cde58dbcSMatthew Ahrens ds->ds_phys->ds_next_clones_obj); 2717cde58dbcSMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 2718cde58dbcSMatthew Ahrens zap_cursor_advance(&zc)) { 2719cde58dbcSMatthew Ahrens dsl_dataset_t *cnds; 2720cde58dbcSMatthew Ahrens uint64_t o; 2721cde58dbcSMatthew Ahrens 2722cde58dbcSMatthew Ahrens if (za.za_first_integer == oldnext_obj) { 2723cde58dbcSMatthew Ahrens /* 2724cde58dbcSMatthew Ahrens * We've already moved the 2725cde58dbcSMatthew Ahrens * origin's reference. 2726cde58dbcSMatthew Ahrens */ 2727cde58dbcSMatthew Ahrens continue; 2728cde58dbcSMatthew Ahrens } 2729cde58dbcSMatthew Ahrens 2730cde58dbcSMatthew Ahrens VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 2731cde58dbcSMatthew Ahrens za.za_first_integer, FTAG, &cnds)); 2732cde58dbcSMatthew Ahrens o = cnds->ds_dir->dd_phys->dd_head_dataset_obj; 2733cde58dbcSMatthew Ahrens 2734cde58dbcSMatthew Ahrens VERIFY3U(zap_remove_int(dp->dp_meta_objset, 2735cde58dbcSMatthew Ahrens odd->dd_phys->dd_clones, o, tx), ==, 0); 2736cde58dbcSMatthew Ahrens VERIFY3U(zap_add_int(dp->dp_meta_objset, 2737cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones, o, tx), ==, 0); 2738cde58dbcSMatthew Ahrens dsl_dataset_rele(cnds, FTAG); 2739cde58dbcSMatthew Ahrens } 2740cde58dbcSMatthew Ahrens zap_cursor_fini(&zc); 2741cde58dbcSMatthew Ahrens } 2742cde58dbcSMatthew Ahrens 274399653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 274474e7dc98SMatthew Ahrens } 274574e7dc98SMatthew Ahrens 274674e7dc98SMatthew Ahrens /* 274774e7dc98SMatthew Ahrens * Change space accounting. 274874e7dc98SMatthew Ahrens * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either 274974e7dc98SMatthew Ahrens * both be valid, or both be 0 (resulting in delta == 0). This 275074e7dc98SMatthew Ahrens * is true for each of {clone,origin} independently. 275174e7dc98SMatthew Ahrens */ 275274e7dc98SMatthew Ahrens 275374e7dc98SMatthew Ahrens delta = pa->cloneusedsnap - 275474e7dc98SMatthew Ahrens dd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 275574e7dc98SMatthew Ahrens ASSERT3S(delta, >=, 0); 275674e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, delta); 275774e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx); 275874e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_HEAD, 275974e7dc98SMatthew Ahrens pa->used - delta, pa->comp, pa->uncomp, tx); 276074e7dc98SMatthew Ahrens 276174e7dc98SMatthew Ahrens delta = pa->originusedsnap - 276274e7dc98SMatthew Ahrens odd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 276374e7dc98SMatthew Ahrens ASSERT3S(delta, <=, 0); 276474e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, -delta); 276574e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx); 276674e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_HEAD, 276774e7dc98SMatthew Ahrens -pa->used - delta, -pa->comp, -pa->uncomp, tx); 276899653d4eSeschrock 27693cb34c60Sahrens origin_ds->ds_phys->ds_unique_bytes = pa->unique; 277099653d4eSeschrock 2771ecd6cf80Smarks /* log history record */ 27723f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 27733f9d6ad7SLin Ling "dataset = %llu", hds->ds_object); 2774ecd6cf80Smarks 27753cb34c60Sahrens dsl_dir_close(odd, FTAG); 277699653d4eSeschrock } 277799653d4eSeschrock 277874e7dc98SMatthew Ahrens static char *snaplist_tag = "snaplist"; 277974e7dc98SMatthew Ahrens /* 278074e7dc98SMatthew Ahrens * Make a list of dsl_dataset_t's for the snapshots between first_obj 278174e7dc98SMatthew Ahrens * (exclusive) and last_obj (inclusive). The list will be in reverse 278274e7dc98SMatthew Ahrens * order (last_obj will be the list_head()). If first_obj == 0, do all 278374e7dc98SMatthew Ahrens * snapshots back to this dataset's origin. 278474e7dc98SMatthew Ahrens */ 278574e7dc98SMatthew Ahrens static int 278674e7dc98SMatthew Ahrens snaplist_make(dsl_pool_t *dp, boolean_t own, 278774e7dc98SMatthew Ahrens uint64_t first_obj, uint64_t last_obj, list_t *l) 278874e7dc98SMatthew Ahrens { 278974e7dc98SMatthew Ahrens uint64_t obj = last_obj; 279074e7dc98SMatthew Ahrens 279174e7dc98SMatthew Ahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock)); 279274e7dc98SMatthew Ahrens 279374e7dc98SMatthew Ahrens list_create(l, sizeof (struct promotenode), 279474e7dc98SMatthew Ahrens offsetof(struct promotenode, link)); 279574e7dc98SMatthew Ahrens 279674e7dc98SMatthew Ahrens while (obj != first_obj) { 279774e7dc98SMatthew Ahrens dsl_dataset_t *ds; 279874e7dc98SMatthew Ahrens struct promotenode *snap; 279974e7dc98SMatthew Ahrens int err; 280074e7dc98SMatthew Ahrens 280174e7dc98SMatthew Ahrens if (own) { 280274e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, obj, 280374e7dc98SMatthew Ahrens 0, snaplist_tag, &ds); 280474e7dc98SMatthew Ahrens if (err == 0) 280574e7dc98SMatthew Ahrens dsl_dataset_make_exclusive(ds, snaplist_tag); 280674e7dc98SMatthew Ahrens } else { 280774e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, obj, snaplist_tag, &ds); 280874e7dc98SMatthew Ahrens } 280974e7dc98SMatthew Ahrens if (err == ENOENT) { 281074e7dc98SMatthew Ahrens /* lost race with snapshot destroy */ 281174e7dc98SMatthew Ahrens struct promotenode *last = list_tail(l); 281274e7dc98SMatthew Ahrens ASSERT(obj != last->ds->ds_phys->ds_prev_snap_obj); 281374e7dc98SMatthew Ahrens obj = last->ds->ds_phys->ds_prev_snap_obj; 281474e7dc98SMatthew Ahrens continue; 281574e7dc98SMatthew Ahrens } else if (err) { 281674e7dc98SMatthew Ahrens return (err); 281774e7dc98SMatthew Ahrens } 281874e7dc98SMatthew Ahrens 281974e7dc98SMatthew Ahrens if (first_obj == 0) 282074e7dc98SMatthew Ahrens first_obj = ds->ds_dir->dd_phys->dd_origin_obj; 282174e7dc98SMatthew Ahrens 282274e7dc98SMatthew Ahrens snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP); 282374e7dc98SMatthew Ahrens snap->ds = ds; 282474e7dc98SMatthew Ahrens list_insert_tail(l, snap); 282574e7dc98SMatthew Ahrens obj = ds->ds_phys->ds_prev_snap_obj; 282674e7dc98SMatthew Ahrens } 282774e7dc98SMatthew Ahrens 282874e7dc98SMatthew Ahrens return (0); 282974e7dc98SMatthew Ahrens } 283074e7dc98SMatthew Ahrens 283174e7dc98SMatthew Ahrens static int 283274e7dc98SMatthew Ahrens snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep) 283374e7dc98SMatthew Ahrens { 283474e7dc98SMatthew Ahrens struct promotenode *snap; 283574e7dc98SMatthew Ahrens 283674e7dc98SMatthew Ahrens *spacep = 0; 283774e7dc98SMatthew Ahrens for (snap = list_head(l); snap; snap = list_next(l, snap)) { 2838cde58dbcSMatthew Ahrens uint64_t used, comp, uncomp; 2839cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&snap->ds->ds_deadlist, 2840cde58dbcSMatthew Ahrens mintxg, UINT64_MAX, &used, &comp, &uncomp); 284174e7dc98SMatthew Ahrens *spacep += used; 284274e7dc98SMatthew Ahrens } 284374e7dc98SMatthew Ahrens return (0); 284474e7dc98SMatthew Ahrens } 284574e7dc98SMatthew Ahrens 284674e7dc98SMatthew Ahrens static void 284774e7dc98SMatthew Ahrens snaplist_destroy(list_t *l, boolean_t own) 284874e7dc98SMatthew Ahrens { 284974e7dc98SMatthew Ahrens struct promotenode *snap; 285074e7dc98SMatthew Ahrens 28514f5064b7SMark J Musante if (!l || !list_link_active(&l->list_head)) 285274e7dc98SMatthew Ahrens return; 285374e7dc98SMatthew Ahrens 285474e7dc98SMatthew Ahrens while ((snap = list_tail(l)) != NULL) { 285574e7dc98SMatthew Ahrens list_remove(l, snap); 285674e7dc98SMatthew Ahrens if (own) 285774e7dc98SMatthew Ahrens dsl_dataset_disown(snap->ds, snaplist_tag); 285874e7dc98SMatthew Ahrens else 285974e7dc98SMatthew Ahrens dsl_dataset_rele(snap->ds, snaplist_tag); 286074e7dc98SMatthew Ahrens kmem_free(snap, sizeof (struct promotenode)); 286174e7dc98SMatthew Ahrens } 286274e7dc98SMatthew Ahrens list_destroy(l); 286374e7dc98SMatthew Ahrens } 286474e7dc98SMatthew Ahrens 286574e7dc98SMatthew Ahrens /* 286674e7dc98SMatthew Ahrens * Promote a clone. Nomenclature note: 286774e7dc98SMatthew Ahrens * "clone" or "cds": the original clone which is being promoted 286874e7dc98SMatthew Ahrens * "origin" or "ods": the snapshot which is originally clone's origin 286974e7dc98SMatthew Ahrens * "origin head" or "ohds": the dataset which is the head 287074e7dc98SMatthew Ahrens * (filesystem/volume) for the origin 287174e7dc98SMatthew Ahrens * "origin origin": the origin of the origin's filesystem (typically 287274e7dc98SMatthew Ahrens * NULL, indicating that the clone is not a clone of a clone). 287374e7dc98SMatthew Ahrens */ 287499653d4eSeschrock int 2875681d9761SEric Taylor dsl_dataset_promote(const char *name, char *conflsnap) 287699653d4eSeschrock { 287799653d4eSeschrock dsl_dataset_t *ds; 2878745cd3c5Smaybee dsl_dir_t *dd; 2879745cd3c5Smaybee dsl_pool_t *dp; 288099653d4eSeschrock dmu_object_info_t doi; 288174e7dc98SMatthew Ahrens struct promotearg pa = { 0 }; 2882088f3894Sahrens struct promotenode *snap; 2883745cd3c5Smaybee int err; 288499653d4eSeschrock 2885745cd3c5Smaybee err = dsl_dataset_hold(name, FTAG, &ds); 288699653d4eSeschrock if (err) 288799653d4eSeschrock return (err); 2888745cd3c5Smaybee dd = ds->ds_dir; 2889745cd3c5Smaybee dp = dd->dd_pool; 289099653d4eSeschrock 2891745cd3c5Smaybee err = dmu_object_info(dp->dp_meta_objset, 289299653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 289399653d4eSeschrock if (err) { 2894745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 289599653d4eSeschrock return (err); 289699653d4eSeschrock } 289799653d4eSeschrock 289874e7dc98SMatthew Ahrens if (dsl_dataset_is_snapshot(ds) || dd->dd_phys->dd_origin_obj == 0) { 289974e7dc98SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 290074e7dc98SMatthew Ahrens return (EINVAL); 290174e7dc98SMatthew Ahrens } 290274e7dc98SMatthew Ahrens 2903745cd3c5Smaybee /* 2904745cd3c5Smaybee * We are going to inherit all the snapshots taken before our 2905745cd3c5Smaybee * origin (i.e., our new origin will be our parent's origin). 2906745cd3c5Smaybee * Take ownership of them so that we can rename them into our 2907745cd3c5Smaybee * namespace. 2908745cd3c5Smaybee */ 2909745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 2910088f3894Sahrens 291174e7dc98SMatthew Ahrens err = snaplist_make(dp, B_TRUE, 0, dd->dd_phys->dd_origin_obj, 291274e7dc98SMatthew Ahrens &pa.shared_snaps); 291374e7dc98SMatthew Ahrens if (err != 0) 291474e7dc98SMatthew Ahrens goto out; 2915088f3894Sahrens 291674e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, 0, ds->ds_object, &pa.clone_snaps); 291774e7dc98SMatthew Ahrens if (err != 0) 291874e7dc98SMatthew Ahrens goto out; 2919088f3894Sahrens 292074e7dc98SMatthew Ahrens snap = list_head(&pa.shared_snaps); 292174e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_object, ==, dd->dd_phys->dd_origin_obj); 292274e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, dd->dd_phys->dd_origin_obj, 292374e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, &pa.origin_snaps); 292474e7dc98SMatthew Ahrens if (err != 0) 292574e7dc98SMatthew Ahrens goto out; 2926088f3894Sahrens 2927cde58dbcSMatthew Ahrens if (snap->ds->ds_dir->dd_phys->dd_origin_obj != 0) { 2928cde58dbcSMatthew Ahrens err = dsl_dataset_hold_obj(dp, 292974e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_origin_obj, 2930cde58dbcSMatthew Ahrens FTAG, &pa.origin_origin); 293174e7dc98SMatthew Ahrens if (err != 0) 293274e7dc98SMatthew Ahrens goto out; 293374e7dc98SMatthew Ahrens } 2934745cd3c5Smaybee 293574e7dc98SMatthew Ahrens out: 293674e7dc98SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 2937745cd3c5Smaybee 293899653d4eSeschrock /* 293999653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 294099653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 294199653d4eSeschrock * bonus buffers. 294299653d4eSeschrock */ 294374e7dc98SMatthew Ahrens if (err == 0) { 294474e7dc98SMatthew Ahrens err = dsl_sync_task_do(dp, dsl_dataset_promote_check, 294574e7dc98SMatthew Ahrens dsl_dataset_promote_sync, ds, &pa, 2946b24ab676SJeff Bonwick 2 + 2 * doi.doi_physical_blocks_512); 2947681d9761SEric Taylor if (err && pa.err_ds && conflsnap) 2948681d9761SEric Taylor (void) strncpy(conflsnap, pa.err_ds, MAXNAMELEN); 2949745cd3c5Smaybee } 295074e7dc98SMatthew Ahrens 295174e7dc98SMatthew Ahrens snaplist_destroy(&pa.shared_snaps, B_TRUE); 295274e7dc98SMatthew Ahrens snaplist_destroy(&pa.clone_snaps, B_FALSE); 295374e7dc98SMatthew Ahrens snaplist_destroy(&pa.origin_snaps, B_FALSE); 295474e7dc98SMatthew Ahrens if (pa.origin_origin) 2955cde58dbcSMatthew Ahrens dsl_dataset_rele(pa.origin_origin, FTAG); 2956745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 295799653d4eSeschrock return (err); 295899653d4eSeschrock } 2959b1b8ab34Slling 29603cb34c60Sahrens struct cloneswaparg { 29613cb34c60Sahrens dsl_dataset_t *cds; /* clone dataset */ 29623cb34c60Sahrens dsl_dataset_t *ohds; /* origin's head dataset */ 29633cb34c60Sahrens boolean_t force; 2964a9b821a0Sck int64_t unused_refres_delta; /* change in unconsumed refreservation */ 29653cb34c60Sahrens }; 2966f18faf3fSek 2967f18faf3fSek /* ARGSUSED */ 2968f18faf3fSek static int 2969f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 2970f18faf3fSek { 29713cb34c60Sahrens struct cloneswaparg *csa = arg1; 2972f18faf3fSek 29733cb34c60Sahrens /* they should both be heads */ 29743cb34c60Sahrens if (dsl_dataset_is_snapshot(csa->cds) || 29753cb34c60Sahrens dsl_dataset_is_snapshot(csa->ohds)) 2976f18faf3fSek return (EINVAL); 2977f18faf3fSek 29783cb34c60Sahrens /* the branch point should be just before them */ 29793cb34c60Sahrens if (csa->cds->ds_prev != csa->ohds->ds_prev) 2980f18faf3fSek return (EINVAL); 2981f18faf3fSek 2982ae46e4c7SMatthew Ahrens /* cds should be the clone (unless they are unrelated) */ 2983ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev != NULL && 2984ae46e4c7SMatthew Ahrens csa->cds->ds_prev != csa->cds->ds_dir->dd_pool->dp_origin_snap && 2985ae46e4c7SMatthew Ahrens csa->ohds->ds_object != 2986ae46e4c7SMatthew Ahrens csa->cds->ds_prev->ds_phys->ds_next_snap_obj) 29873cb34c60Sahrens return (EINVAL); 2988f18faf3fSek 29893cb34c60Sahrens /* the clone should be a child of the origin */ 29903cb34c60Sahrens if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir) 29913cb34c60Sahrens return (EINVAL); 2992f18faf3fSek 29933cb34c60Sahrens /* ohds shouldn't be modified unless 'force' */ 29943cb34c60Sahrens if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) 29953cb34c60Sahrens return (ETXTBSY); 2996a9b821a0Sck 2997a9b821a0Sck /* adjust amount of any unconsumed refreservation */ 2998a9b821a0Sck csa->unused_refres_delta = 2999a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 3000a9b821a0Sck csa->ohds->ds_phys->ds_unique_bytes) - 3001a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 3002a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 3003a9b821a0Sck 3004a9b821a0Sck if (csa->unused_refres_delta > 0 && 3005a9b821a0Sck csa->unused_refres_delta > 3006a9b821a0Sck dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) 3007a9b821a0Sck return (ENOSPC); 3008a9b821a0Sck 3009c4cbca4fSChris Kirby if (csa->ohds->ds_quota != 0 && 3010c4cbca4fSChris Kirby csa->cds->ds_phys->ds_unique_bytes > csa->ohds->ds_quota) 3011c4cbca4fSChris Kirby return (EDQUOT); 3012c4cbca4fSChris Kirby 30133cb34c60Sahrens return (0); 3014f18faf3fSek } 3015f18faf3fSek 3016f18faf3fSek /* ARGSUSED */ 3017f18faf3fSek static void 30183f9d6ad7SLin Ling dsl_dataset_clone_swap_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3019f18faf3fSek { 30203cb34c60Sahrens struct cloneswaparg *csa = arg1; 30213cb34c60Sahrens dsl_pool_t *dp = csa->cds->ds_dir->dd_pool; 3022f18faf3fSek 3023a9b821a0Sck ASSERT(csa->cds->ds_reserved == 0); 3024c4cbca4fSChris Kirby ASSERT(csa->ohds->ds_quota == 0 || 3025c4cbca4fSChris Kirby csa->cds->ds_phys->ds_unique_bytes <= csa->ohds->ds_quota); 3026a9b821a0Sck 30273cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); 30283cb34c60Sahrens dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); 3029f18faf3fSek 3030503ad85cSMatthew Ahrens if (csa->cds->ds_objset != NULL) { 3031503ad85cSMatthew Ahrens dmu_objset_evict(csa->cds->ds_objset); 3032503ad85cSMatthew Ahrens csa->cds->ds_objset = NULL; 30333cb34c60Sahrens } 3034f18faf3fSek 3035503ad85cSMatthew Ahrens if (csa->ohds->ds_objset != NULL) { 3036503ad85cSMatthew Ahrens dmu_objset_evict(csa->ohds->ds_objset); 3037503ad85cSMatthew Ahrens csa->ohds->ds_objset = NULL; 30383cb34c60Sahrens } 3039f18faf3fSek 3040ae46e4c7SMatthew Ahrens /* 3041ae46e4c7SMatthew Ahrens * Reset origin's unique bytes, if it exists. 3042ae46e4c7SMatthew Ahrens */ 3043ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev) { 3044ae46e4c7SMatthew Ahrens dsl_dataset_t *origin = csa->cds->ds_prev; 3045cde58dbcSMatthew Ahrens uint64_t comp, uncomp; 3046cde58dbcSMatthew Ahrens 3047ae46e4c7SMatthew Ahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 3048cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->cds->ds_deadlist, 3049ae46e4c7SMatthew Ahrens origin->ds_phys->ds_prev_snap_txg, UINT64_MAX, 3050cde58dbcSMatthew Ahrens &origin->ds_phys->ds_unique_bytes, &comp, &uncomp); 3051ae46e4c7SMatthew Ahrens } 3052f18faf3fSek 3053f18faf3fSek /* swap blkptrs */ 3054f18faf3fSek { 3055f18faf3fSek blkptr_t tmp; 30563cb34c60Sahrens tmp = csa->ohds->ds_phys->ds_bp; 30573cb34c60Sahrens csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp; 30583cb34c60Sahrens csa->cds->ds_phys->ds_bp = tmp; 3059f18faf3fSek } 3060f18faf3fSek 3061f18faf3fSek /* set dd_*_bytes */ 3062f18faf3fSek { 3063f18faf3fSek int64_t dused, dcomp, duncomp; 3064f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 3065f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 3066f18faf3fSek 306774e7dc98SMatthew Ahrens ASSERT3U(csa->cds->ds_dir->dd_phys-> 306874e7dc98SMatthew Ahrens dd_used_breakdown[DD_USED_SNAP], ==, 0); 306974e7dc98SMatthew Ahrens 3070cde58dbcSMatthew Ahrens dsl_deadlist_space(&csa->cds->ds_deadlist, 3071cde58dbcSMatthew Ahrens &cdl_used, &cdl_comp, &cdl_uncomp); 3072cde58dbcSMatthew Ahrens dsl_deadlist_space(&csa->ohds->ds_deadlist, 3073cde58dbcSMatthew Ahrens &odl_used, &odl_comp, &odl_uncomp); 307474e7dc98SMatthew Ahrens 30753cb34c60Sahrens dused = csa->cds->ds_phys->ds_used_bytes + cdl_used - 30763cb34c60Sahrens (csa->ohds->ds_phys->ds_used_bytes + odl_used); 30773cb34c60Sahrens dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp - 30783cb34c60Sahrens (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp); 30793cb34c60Sahrens duncomp = csa->cds->ds_phys->ds_uncompressed_bytes + 30803cb34c60Sahrens cdl_uncomp - 30813cb34c60Sahrens (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 30823cb34c60Sahrens 308374e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_HEAD, 30843cb34c60Sahrens dused, dcomp, duncomp, tx); 308574e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->cds->ds_dir, DD_USED_HEAD, 30863cb34c60Sahrens -dused, -dcomp, -duncomp, tx); 308774e7dc98SMatthew Ahrens 308874e7dc98SMatthew Ahrens /* 308974e7dc98SMatthew Ahrens * The difference in the space used by snapshots is the 309074e7dc98SMatthew Ahrens * difference in snapshot space due to the head's 309174e7dc98SMatthew Ahrens * deadlist (since that's the only thing that's 309274e7dc98SMatthew Ahrens * changing that affects the snapused). 309374e7dc98SMatthew Ahrens */ 3094cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->cds->ds_deadlist, 3095cde58dbcSMatthew Ahrens csa->ohds->ds_dir->dd_origin_txg, UINT64_MAX, 3096cde58dbcSMatthew Ahrens &cdl_used, &cdl_comp, &cdl_uncomp); 3097cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->ohds->ds_deadlist, 3098cde58dbcSMatthew Ahrens csa->ohds->ds_dir->dd_origin_txg, UINT64_MAX, 3099cde58dbcSMatthew Ahrens &odl_used, &odl_comp, &odl_uncomp); 310074e7dc98SMatthew Ahrens dsl_dir_transfer_space(csa->ohds->ds_dir, cdl_used - odl_used, 310174e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 31023cb34c60Sahrens } 31033cb34c60Sahrens 3104f18faf3fSek /* swap ds_*_bytes */ 31053cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_used_bytes, 31063cb34c60Sahrens csa->cds->ds_phys->ds_used_bytes); 31073cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes, 31083cb34c60Sahrens csa->cds->ds_phys->ds_compressed_bytes); 31093cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, 31103cb34c60Sahrens csa->cds->ds_phys->ds_uncompressed_bytes); 3111a9b821a0Sck SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, 3112a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 3113a9b821a0Sck 3114a9b821a0Sck /* apply any parent delta for change in unconsumed refreservation */ 311574e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_REFRSRV, 311674e7dc98SMatthew Ahrens csa->unused_refres_delta, 0, 0, tx); 3117f18faf3fSek 3118cde58dbcSMatthew Ahrens /* 3119cde58dbcSMatthew Ahrens * Swap deadlists. 3120cde58dbcSMatthew Ahrens */ 3121cde58dbcSMatthew Ahrens dsl_deadlist_close(&csa->cds->ds_deadlist); 3122cde58dbcSMatthew Ahrens dsl_deadlist_close(&csa->ohds->ds_deadlist); 31233cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj, 31243cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj); 3125cde58dbcSMatthew Ahrens dsl_deadlist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset, 3126cde58dbcSMatthew Ahrens csa->cds->ds_phys->ds_deadlist_obj); 3127cde58dbcSMatthew Ahrens dsl_deadlist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, 3128cde58dbcSMatthew Ahrens csa->ohds->ds_phys->ds_deadlist_obj); 312988b7b0f2SMatthew Ahrens 31303f9d6ad7SLin Ling dsl_scan_ds_clone_swapped(csa->ohds, csa->cds, tx); 3131f18faf3fSek } 3132f18faf3fSek 3133f18faf3fSek /* 3134ae46e4c7SMatthew Ahrens * Swap 'clone' with its origin head datasets. Used at the end of "zfs 3135ae46e4c7SMatthew Ahrens * recv" into an existing fs to swizzle the file system to the new 3136ae46e4c7SMatthew Ahrens * version, and by "zfs rollback". Can also be used to swap two 3137ae46e4c7SMatthew Ahrens * independent head datasets if neither has any snapshots. 3138f18faf3fSek */ 3139f18faf3fSek int 31403cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, 31413cb34c60Sahrens boolean_t force) 3142f18faf3fSek { 31433cb34c60Sahrens struct cloneswaparg csa; 3144745cd3c5Smaybee int error; 3145f18faf3fSek 3146745cd3c5Smaybee ASSERT(clone->ds_owner); 3147745cd3c5Smaybee ASSERT(origin_head->ds_owner); 3148745cd3c5Smaybee retry: 314977972028SChris Kirby /* 315077972028SChris Kirby * Need exclusive access for the swap. If we're swapping these 315177972028SChris Kirby * datasets back after an error, we already hold the locks. 315277972028SChris Kirby */ 315377972028SChris Kirby if (!RW_WRITE_HELD(&clone->ds_rwlock)) 315477972028SChris Kirby rw_enter(&clone->ds_rwlock, RW_WRITER); 315577972028SChris Kirby if (!RW_WRITE_HELD(&origin_head->ds_rwlock) && 315677972028SChris Kirby !rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) { 3157745cd3c5Smaybee rw_exit(&clone->ds_rwlock); 3158745cd3c5Smaybee rw_enter(&origin_head->ds_rwlock, RW_WRITER); 3159745cd3c5Smaybee if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) { 3160745cd3c5Smaybee rw_exit(&origin_head->ds_rwlock); 3161745cd3c5Smaybee goto retry; 3162745cd3c5Smaybee } 3163745cd3c5Smaybee } 31643cb34c60Sahrens csa.cds = clone; 31653cb34c60Sahrens csa.ohds = origin_head; 31663cb34c60Sahrens csa.force = force; 3167745cd3c5Smaybee error = dsl_sync_task_do(clone->ds_dir->dd_pool, 3168f18faf3fSek dsl_dataset_clone_swap_check, 3169745cd3c5Smaybee dsl_dataset_clone_swap_sync, &csa, NULL, 9); 3170745cd3c5Smaybee return (error); 3171f18faf3fSek } 3172f18faf3fSek 3173b1b8ab34Slling /* 3174b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 3175b1b8ab34Slling * return the name of that dataset. 3176b1b8ab34Slling */ 3177b1b8ab34Slling int 3178b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 3179b1b8ab34Slling { 3180b1b8ab34Slling spa_t *spa; 3181b1b8ab34Slling dsl_pool_t *dp; 3182745cd3c5Smaybee dsl_dataset_t *ds; 3183b1b8ab34Slling int error; 3184b1b8ab34Slling 3185b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 3186b1b8ab34Slling return (error); 3187b1b8ab34Slling dp = spa_get_dsl(spa); 3188b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 3189745cd3c5Smaybee if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) { 3190745cd3c5Smaybee dsl_dataset_name(ds, buf); 3191745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3192b1b8ab34Slling } 3193b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 3194b1b8ab34Slling spa_close(spa, FTAG); 3195b1b8ab34Slling 3196745cd3c5Smaybee return (error); 3197b1b8ab34Slling } 3198a9799022Sck 3199a9799022Sck int 3200a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, 3201745cd3c5Smaybee uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv) 3202a9799022Sck { 3203a9799022Sck int error = 0; 3204a9799022Sck 3205a9799022Sck ASSERT3S(asize, >, 0); 3206a9799022Sck 32079082849eSck /* 32089082849eSck * *ref_rsrv is the portion of asize that will come from any 32099082849eSck * unconsumed refreservation space. 32109082849eSck */ 32119082849eSck *ref_rsrv = 0; 32129082849eSck 3213a9799022Sck mutex_enter(&ds->ds_lock); 3214a9799022Sck /* 3215a9799022Sck * Make a space adjustment for reserved bytes. 3216a9799022Sck */ 3217a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) { 3218a9799022Sck ASSERT3U(*used, >=, 3219a9799022Sck ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 3220a9799022Sck *used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 32219082849eSck *ref_rsrv = 32229082849eSck asize - MIN(asize, parent_delta(ds, asize + inflight)); 3223a9799022Sck } 3224a9799022Sck 3225a9799022Sck if (!check_quota || ds->ds_quota == 0) { 3226a9799022Sck mutex_exit(&ds->ds_lock); 3227a9799022Sck return (0); 3228a9799022Sck } 3229a9799022Sck /* 3230a9799022Sck * If they are requesting more space, and our current estimate 3231a9799022Sck * is over quota, they get to try again unless the actual 3232a9799022Sck * on-disk is over quota and there are no pending changes (which 3233a9799022Sck * may free up space for us). 3234a9799022Sck */ 3235a9799022Sck if (ds->ds_phys->ds_used_bytes + inflight >= ds->ds_quota) { 3236a9799022Sck if (inflight > 0 || ds->ds_phys->ds_used_bytes < ds->ds_quota) 3237a9799022Sck error = ERESTART; 3238a9799022Sck else 3239a9799022Sck error = EDQUOT; 3240a9799022Sck } 3241a9799022Sck mutex_exit(&ds->ds_lock); 3242a9799022Sck 3243a9799022Sck return (error); 3244a9799022Sck } 3245a9799022Sck 3246a9799022Sck /* ARGSUSED */ 3247a9799022Sck static int 3248a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx) 3249a9799022Sck { 3250a9799022Sck dsl_dataset_t *ds = arg1; 325192241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 325292241e0bSTom Erickson int err; 3253a9799022Sck 3254a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA) 3255a9799022Sck return (ENOTSUP); 3256a9799022Sck 325792241e0bSTom Erickson if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0) 325892241e0bSTom Erickson return (err); 325992241e0bSTom Erickson 326092241e0bSTom Erickson if (psa->psa_effective_value == 0) 3261a9799022Sck return (0); 3262a9799022Sck 326392241e0bSTom Erickson if (psa->psa_effective_value < ds->ds_phys->ds_used_bytes || 326492241e0bSTom Erickson psa->psa_effective_value < ds->ds_reserved) 3265a9799022Sck return (ENOSPC); 3266a9799022Sck 3267a9799022Sck return (0); 3268a9799022Sck } 3269a9799022Sck 32703f9d6ad7SLin Ling extern void dsl_prop_set_sync(void *, void *, dmu_tx_t *); 327192241e0bSTom Erickson 3272a9799022Sck void 32733f9d6ad7SLin Ling dsl_dataset_set_quota_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3274a9799022Sck { 3275a9799022Sck dsl_dataset_t *ds = arg1; 327692241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 327792241e0bSTom Erickson uint64_t effective_value = psa->psa_effective_value; 3278a9799022Sck 32793f9d6ad7SLin Ling dsl_prop_set_sync(ds, psa, tx); 328092241e0bSTom Erickson DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa); 3281a9799022Sck 328292241e0bSTom Erickson if (ds->ds_quota != effective_value) { 328392241e0bSTom Erickson dmu_buf_will_dirty(ds->ds_dbuf, tx); 328492241e0bSTom Erickson ds->ds_quota = effective_value; 3285a9799022Sck 32863f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_REFQUOTA, 32873f9d6ad7SLin Ling ds->ds_dir->dd_pool->dp_spa, tx, "%lld dataset = %llu ", 328892241e0bSTom Erickson (longlong_t)ds->ds_quota, ds->ds_object); 328992241e0bSTom Erickson } 3290a9799022Sck } 3291a9799022Sck 3292a9799022Sck int 329392241e0bSTom Erickson dsl_dataset_set_quota(const char *dsname, zprop_source_t source, uint64_t quota) 3294a9799022Sck { 3295a9799022Sck dsl_dataset_t *ds; 329692241e0bSTom Erickson dsl_prop_setarg_t psa; 3297a9799022Sck int err; 3298a9799022Sck 329992241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refquota", source, "a); 330092241e0bSTom Erickson 3301745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3302a9799022Sck if (err) 3303a9799022Sck return (err); 3304a9799022Sck 330592241e0bSTom Erickson /* 330692241e0bSTom Erickson * If someone removes a file, then tries to set the quota, we 330792241e0bSTom Erickson * want to make sure the file freeing takes effect. 330892241e0bSTom Erickson */ 330992241e0bSTom Erickson txg_wait_open(ds->ds_dir->dd_pool, 0); 331092241e0bSTom Erickson 331192241e0bSTom Erickson err = dsl_sync_task_do(ds->ds_dir->dd_pool, 331292241e0bSTom Erickson dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, 331392241e0bSTom Erickson ds, &psa, 0); 3314a9799022Sck 3315745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3316a9799022Sck return (err); 3317a9799022Sck } 3318a9799022Sck 3319a9799022Sck static int 3320a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx) 3321a9799022Sck { 3322a9799022Sck dsl_dataset_t *ds = arg1; 332392241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 332492241e0bSTom Erickson uint64_t effective_value; 3325a9799022Sck uint64_t unique; 332692241e0bSTom Erickson int err; 3327a9799022Sck 3328a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 3329a9799022Sck SPA_VERSION_REFRESERVATION) 3330a9799022Sck return (ENOTSUP); 3331a9799022Sck 3332a9799022Sck if (dsl_dataset_is_snapshot(ds)) 3333a9799022Sck return (EINVAL); 3334a9799022Sck 333592241e0bSTom Erickson if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0) 333692241e0bSTom Erickson return (err); 333792241e0bSTom Erickson 333892241e0bSTom Erickson effective_value = psa->psa_effective_value; 333992241e0bSTom Erickson 3340a9799022Sck /* 3341a9799022Sck * If we are doing the preliminary check in open context, the 3342a9799022Sck * space estimates may be inaccurate. 3343a9799022Sck */ 3344a9799022Sck if (!dmu_tx_is_syncing(tx)) 3345a9799022Sck return (0); 3346a9799022Sck 3347a9799022Sck mutex_enter(&ds->ds_lock); 33483f9d6ad7SLin Ling if (!DS_UNIQUE_IS_ACCURATE(ds)) 33493f9d6ad7SLin Ling dsl_dataset_recalc_head_uniq(ds); 33503f9d6ad7SLin Ling unique = ds->ds_phys->ds_unique_bytes; 3351a9799022Sck mutex_exit(&ds->ds_lock); 3352a9799022Sck 335392241e0bSTom Erickson if (MAX(unique, effective_value) > MAX(unique, ds->ds_reserved)) { 335492241e0bSTom Erickson uint64_t delta = MAX(unique, effective_value) - 3355379c004dSEric Schrock MAX(unique, ds->ds_reserved); 3356379c004dSEric Schrock 3357379c004dSEric Schrock if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 3358379c004dSEric Schrock return (ENOSPC); 3359379c004dSEric Schrock if (ds->ds_quota > 0 && 336092241e0bSTom Erickson effective_value > ds->ds_quota) 3361379c004dSEric Schrock return (ENOSPC); 3362379c004dSEric Schrock } 3363a9799022Sck 3364a9799022Sck return (0); 3365a9799022Sck } 3366a9799022Sck 3367a9799022Sck static void 33683f9d6ad7SLin Ling dsl_dataset_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3369a9799022Sck { 3370a9799022Sck dsl_dataset_t *ds = arg1; 337192241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 337292241e0bSTom Erickson uint64_t effective_value = psa->psa_effective_value; 337302c8f3f0SMatthew Ahrens uint64_t unique; 337402c8f3f0SMatthew Ahrens int64_t delta; 337502c8f3f0SMatthew Ahrens 33763f9d6ad7SLin Ling dsl_prop_set_sync(ds, psa, tx); 337792241e0bSTom Erickson DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa); 337892241e0bSTom Erickson 337902c8f3f0SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 338002c8f3f0SMatthew Ahrens 338102c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 338202c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_lock); 33833f9d6ad7SLin Ling ASSERT(DS_UNIQUE_IS_ACCURATE(ds)); 33843f9d6ad7SLin Ling unique = ds->ds_phys->ds_unique_bytes; 338592241e0bSTom Erickson delta = MAX(0, (int64_t)(effective_value - unique)) - 338602c8f3f0SMatthew Ahrens MAX(0, (int64_t)(ds->ds_reserved - unique)); 338792241e0bSTom Erickson ds->ds_reserved = effective_value; 338802c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_lock); 338902c8f3f0SMatthew Ahrens 339002c8f3f0SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx); 339102c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 3392a9799022Sck 33933f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_REFRESERV, 33943f9d6ad7SLin Ling ds->ds_dir->dd_pool->dp_spa, tx, "%lld dataset = %llu", 339592241e0bSTom Erickson (longlong_t)effective_value, ds->ds_object); 3396a9799022Sck } 3397a9799022Sck 3398a9799022Sck int 339992241e0bSTom Erickson dsl_dataset_set_reservation(const char *dsname, zprop_source_t source, 340092241e0bSTom Erickson uint64_t reservation) 3401a9799022Sck { 3402a9799022Sck dsl_dataset_t *ds; 340392241e0bSTom Erickson dsl_prop_setarg_t psa; 3404a9799022Sck int err; 3405a9799022Sck 340692241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refreservation", source, 340792241e0bSTom Erickson &reservation); 340892241e0bSTom Erickson 3409745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3410a9799022Sck if (err) 3411a9799022Sck return (err); 3412a9799022Sck 3413a9799022Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3414a9799022Sck dsl_dataset_set_reservation_check, 341592241e0bSTom Erickson dsl_dataset_set_reservation_sync, ds, &psa, 0); 341692241e0bSTom Erickson 3417745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3418a9799022Sck return (err); 3419a9799022Sck } 3420842727c2SChris Kirby 3421ca45db41SChris Kirby struct dsl_ds_holdarg { 3422ca45db41SChris Kirby dsl_sync_task_group_t *dstg; 3423ca45db41SChris Kirby char *htag; 3424ca45db41SChris Kirby char *snapname; 3425ca45db41SChris Kirby boolean_t recursive; 3426ca45db41SChris Kirby boolean_t gotone; 3427ca45db41SChris Kirby boolean_t temphold; 3428ca45db41SChris Kirby char failed[MAXPATHLEN]; 3429ca45db41SChris Kirby }; 3430ca45db41SChris Kirby 3431c99e4bdcSChris Kirby typedef struct zfs_hold_cleanup_arg { 3432*a7f53a56SChris Kirby dsl_pool_t *dp; 3433*a7f53a56SChris Kirby uint64_t dsobj; 3434c99e4bdcSChris Kirby char htag[MAXNAMELEN]; 3435c99e4bdcSChris Kirby } zfs_hold_cleanup_arg_t; 3436c99e4bdcSChris Kirby 3437c99e4bdcSChris Kirby static void 3438c99e4bdcSChris Kirby dsl_dataset_user_release_onexit(void *arg) 3439c99e4bdcSChris Kirby { 3440c99e4bdcSChris Kirby zfs_hold_cleanup_arg_t *ca = arg; 3441c99e4bdcSChris Kirby 3442*a7f53a56SChris Kirby (void) dsl_dataset_user_release_tmp(ca->dp, ca->dsobj, ca->htag, 3443*a7f53a56SChris Kirby B_TRUE); 3444c99e4bdcSChris Kirby kmem_free(ca, sizeof (zfs_hold_cleanup_arg_t)); 3445c99e4bdcSChris Kirby } 3446c99e4bdcSChris Kirby 3447*a7f53a56SChris Kirby void 3448*a7f53a56SChris Kirby dsl_register_onexit_hold_cleanup(dsl_dataset_t *ds, const char *htag, 3449*a7f53a56SChris Kirby minor_t minor) 3450*a7f53a56SChris Kirby { 3451*a7f53a56SChris Kirby zfs_hold_cleanup_arg_t *ca; 3452*a7f53a56SChris Kirby 3453*a7f53a56SChris Kirby ca = kmem_alloc(sizeof (zfs_hold_cleanup_arg_t), KM_SLEEP); 3454*a7f53a56SChris Kirby ca->dp = ds->ds_dir->dd_pool; 3455*a7f53a56SChris Kirby ca->dsobj = ds->ds_object; 3456*a7f53a56SChris Kirby (void) strlcpy(ca->htag, htag, sizeof (ca->htag)); 3457*a7f53a56SChris Kirby VERIFY3U(0, ==, zfs_onexit_add_cb(minor, 3458*a7f53a56SChris Kirby dsl_dataset_user_release_onexit, ca, NULL)); 3459*a7f53a56SChris Kirby } 3460*a7f53a56SChris Kirby 346115508ac0SChris Kirby /* 346215508ac0SChris Kirby * The max length of a temporary tag prefix is the number of hex digits 346315508ac0SChris Kirby * required to express UINT64_MAX plus one for the hyphen. 346415508ac0SChris Kirby */ 346515508ac0SChris Kirby #define MAX_TAG_PREFIX_LEN 17 346615508ac0SChris Kirby 3467842727c2SChris Kirby static int 3468842727c2SChris Kirby dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx) 3469842727c2SChris Kirby { 3470842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3471ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 3472ca45db41SChris Kirby char *htag = ha->htag; 3473842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3474842727c2SChris Kirby int error = 0; 3475842727c2SChris Kirby 3476842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3477842727c2SChris Kirby return (ENOTSUP); 3478842727c2SChris Kirby 3479842727c2SChris Kirby if (!dsl_dataset_is_snapshot(ds)) 3480842727c2SChris Kirby return (EINVAL); 3481842727c2SChris Kirby 3482842727c2SChris Kirby /* tags must be unique */ 3483842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3484842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj) { 3485842727c2SChris Kirby error = zap_lookup(mos, ds->ds_phys->ds_userrefs_obj, htag, 3486842727c2SChris Kirby 8, 1, tx); 3487842727c2SChris Kirby if (error == 0) 3488842727c2SChris Kirby error = EEXIST; 3489842727c2SChris Kirby else if (error == ENOENT) 3490842727c2SChris Kirby error = 0; 3491842727c2SChris Kirby } 3492842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3493842727c2SChris Kirby 349415508ac0SChris Kirby if (error == 0 && ha->temphold && 349515508ac0SChris Kirby strlen(htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN) 349615508ac0SChris Kirby error = E2BIG; 349715508ac0SChris Kirby 3498842727c2SChris Kirby return (error); 3499842727c2SChris Kirby } 3500842727c2SChris Kirby 3501842727c2SChris Kirby static void 35023f9d6ad7SLin Ling dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3503842727c2SChris Kirby { 3504842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3505ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 3506ca45db41SChris Kirby char *htag = ha->htag; 3507ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3508ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 350915508ac0SChris Kirby uint64_t now = gethrestime_sec(); 3510842727c2SChris Kirby uint64_t zapobj; 3511842727c2SChris Kirby 3512842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3513842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj == 0) { 3514842727c2SChris Kirby /* 3515842727c2SChris Kirby * This is the first user hold for this dataset. Create 3516842727c2SChris Kirby * the userrefs zap object. 3517842727c2SChris Kirby */ 3518842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 3519842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj = 3520842727c2SChris Kirby zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx); 3521842727c2SChris Kirby } else { 3522842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3523842727c2SChris Kirby } 3524842727c2SChris Kirby ds->ds_userrefs++; 3525842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3526842727c2SChris Kirby 3527842727c2SChris Kirby VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx)); 3528842727c2SChris Kirby 3529ca45db41SChris Kirby if (ha->temphold) { 3530ca45db41SChris Kirby VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object, 3531ca45db41SChris Kirby htag, &now, tx)); 3532ca45db41SChris Kirby } 3533ca45db41SChris Kirby 35343f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_USER_HOLD, 35353f9d6ad7SLin Ling dp->dp_spa, tx, "<%s> temp = %d dataset = %llu", htag, 3536ca45db41SChris Kirby (int)ha->temphold, ds->ds_object); 3537842727c2SChris Kirby } 3538842727c2SChris Kirby 3539842727c2SChris Kirby static int 3540fd136879SMatthew Ahrens dsl_dataset_user_hold_one(const char *dsname, void *arg) 3541842727c2SChris Kirby { 3542842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3543842727c2SChris Kirby dsl_dataset_t *ds; 3544842727c2SChris Kirby int error; 3545842727c2SChris Kirby char *name; 3546842727c2SChris Kirby 3547842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname plus terminating NULL */ 3548ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3549842727c2SChris Kirby error = dsl_dataset_hold(name, ha->dstg, &ds); 3550ae46e4c7SMatthew Ahrens strfree(name); 3551842727c2SChris Kirby if (error == 0) { 3552d7747cbcSChris Kirby ha->gotone = B_TRUE; 3553842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check, 3554ca45db41SChris Kirby dsl_dataset_user_hold_sync, ds, ha, 0); 3555842727c2SChris Kirby } else if (error == ENOENT && ha->recursive) { 3556842727c2SChris Kirby error = 0; 3557842727c2SChris Kirby } else { 3558fd136879SMatthew Ahrens (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3559842727c2SChris Kirby } 3560842727c2SChris Kirby return (error); 3561842727c2SChris Kirby } 3562842727c2SChris Kirby 3563*a7f53a56SChris Kirby int 3564*a7f53a56SChris Kirby dsl_dataset_user_hold_for_send(dsl_dataset_t *ds, char *htag, 3565*a7f53a56SChris Kirby boolean_t temphold) 3566*a7f53a56SChris Kirby { 3567*a7f53a56SChris Kirby struct dsl_ds_holdarg *ha; 3568*a7f53a56SChris Kirby int error; 3569*a7f53a56SChris Kirby 3570*a7f53a56SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3571*a7f53a56SChris Kirby ha->htag = htag; 3572*a7f53a56SChris Kirby ha->temphold = temphold; 3573*a7f53a56SChris Kirby error = dsl_sync_task_do(ds->ds_dir->dd_pool, 3574*a7f53a56SChris Kirby dsl_dataset_user_hold_check, dsl_dataset_user_hold_sync, 3575*a7f53a56SChris Kirby ds, ha, 0); 3576*a7f53a56SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3577*a7f53a56SChris Kirby 3578*a7f53a56SChris Kirby return (error); 3579*a7f53a56SChris Kirby } 3580*a7f53a56SChris Kirby 3581842727c2SChris Kirby int 3582842727c2SChris Kirby dsl_dataset_user_hold(char *dsname, char *snapname, char *htag, 3583c99e4bdcSChris Kirby boolean_t recursive, boolean_t temphold, int cleanup_fd) 3584842727c2SChris Kirby { 3585842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3586842727c2SChris Kirby dsl_sync_task_t *dst; 3587842727c2SChris Kirby spa_t *spa; 3588842727c2SChris Kirby int error; 3589*a7f53a56SChris Kirby minor_t minor = 0; 3590*a7f53a56SChris Kirby 3591*a7f53a56SChris Kirby if (cleanup_fd != -1) { 3592*a7f53a56SChris Kirby /* Currently we only support cleanup-on-exit of tempholds. */ 3593*a7f53a56SChris Kirby if (!temphold) 3594*a7f53a56SChris Kirby return (EINVAL); 3595*a7f53a56SChris Kirby error = zfs_onexit_fd_hold(cleanup_fd, &minor); 3596*a7f53a56SChris Kirby if (error) 3597*a7f53a56SChris Kirby return (error); 3598*a7f53a56SChris Kirby } 3599842727c2SChris Kirby 3600842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3601842727c2SChris Kirby 3602842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3603842727c2SChris Kirby 3604842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3605842727c2SChris Kirby if (error) { 3606842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3607*a7f53a56SChris Kirby if (cleanup_fd != -1) 3608*a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 3609842727c2SChris Kirby return (error); 3610842727c2SChris Kirby } 3611842727c2SChris Kirby 3612842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3613842727c2SChris Kirby ha->htag = htag; 3614842727c2SChris Kirby ha->snapname = snapname; 3615842727c2SChris Kirby ha->recursive = recursive; 3616ca45db41SChris Kirby ha->temphold = temphold; 3617c99e4bdcSChris Kirby 3618842727c2SChris Kirby if (recursive) { 3619842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_hold_one, 3620842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3621842727c2SChris Kirby } else { 3622842727c2SChris Kirby error = dsl_dataset_user_hold_one(dsname, ha); 3623842727c2SChris Kirby } 3624842727c2SChris Kirby if (error == 0) 3625842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3626842727c2SChris Kirby 3627842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3628842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3629842727c2SChris Kirby dsl_dataset_t *ds = dst->dst_arg1; 3630842727c2SChris Kirby 3631842727c2SChris Kirby if (dst->dst_err) { 3632842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3633842727c2SChris Kirby *strchr(ha->failed, '@') = '\0'; 3634*a7f53a56SChris Kirby } else if (error == 0 && minor != 0 && temphold) { 3635*a7f53a56SChris Kirby /* 3636*a7f53a56SChris Kirby * If this hold is to be released upon process exit, 3637*a7f53a56SChris Kirby * register that action now. 3638*a7f53a56SChris Kirby */ 3639*a7f53a56SChris Kirby dsl_register_onexit_hold_cleanup(ds, htag, minor); 3640842727c2SChris Kirby } 3641842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3642842727c2SChris Kirby } 3643842727c2SChris Kirby 3644d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3645d7747cbcSChris Kirby error = ENOENT; 3646d7747cbcSChris Kirby 3647842727c2SChris Kirby if (error) 3648fd136879SMatthew Ahrens (void) strlcpy(dsname, ha->failed, sizeof (ha->failed)); 3649842727c2SChris Kirby 3650842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3651c99e4bdcSChris Kirby 3652842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3653842727c2SChris Kirby spa_close(spa, FTAG); 3654*a7f53a56SChris Kirby if (cleanup_fd != -1) 3655*a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 3656842727c2SChris Kirby return (error); 3657842727c2SChris Kirby } 3658842727c2SChris Kirby 3659842727c2SChris Kirby struct dsl_ds_releasearg { 3660842727c2SChris Kirby dsl_dataset_t *ds; 3661842727c2SChris Kirby const char *htag; 3662842727c2SChris Kirby boolean_t own; /* do we own or just hold ds? */ 3663842727c2SChris Kirby }; 3664842727c2SChris Kirby 3665842727c2SChris Kirby static int 3666842727c2SChris Kirby dsl_dataset_release_might_destroy(dsl_dataset_t *ds, const char *htag, 3667842727c2SChris Kirby boolean_t *might_destroy) 3668842727c2SChris Kirby { 3669842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3670842727c2SChris Kirby uint64_t zapobj; 3671842727c2SChris Kirby uint64_t tmp; 3672842727c2SChris Kirby int error; 3673842727c2SChris Kirby 3674842727c2SChris Kirby *might_destroy = B_FALSE; 3675842727c2SChris Kirby 3676842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3677842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3678842727c2SChris Kirby if (zapobj == 0) { 3679842727c2SChris Kirby /* The tag can't possibly exist */ 3680842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3681842727c2SChris Kirby return (ESRCH); 3682842727c2SChris Kirby } 3683842727c2SChris Kirby 3684842727c2SChris Kirby /* Make sure the tag exists */ 3685842727c2SChris Kirby error = zap_lookup(mos, zapobj, htag, 8, 1, &tmp); 3686842727c2SChris Kirby if (error) { 3687842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3688842727c2SChris Kirby if (error == ENOENT) 3689842727c2SChris Kirby error = ESRCH; 3690842727c2SChris Kirby return (error); 3691842727c2SChris Kirby } 3692842727c2SChris Kirby 3693842727c2SChris Kirby if (ds->ds_userrefs == 1 && ds->ds_phys->ds_num_children == 1 && 3694842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 3695842727c2SChris Kirby *might_destroy = B_TRUE; 3696842727c2SChris Kirby 3697842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3698842727c2SChris Kirby return (0); 3699842727c2SChris Kirby } 3700842727c2SChris Kirby 3701842727c2SChris Kirby static int 3702842727c2SChris Kirby dsl_dataset_user_release_check(void *arg1, void *tag, dmu_tx_t *tx) 3703842727c2SChris Kirby { 3704842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3705842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3706842727c2SChris Kirby boolean_t might_destroy; 3707842727c2SChris Kirby int error; 3708842727c2SChris Kirby 3709842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3710842727c2SChris Kirby return (ENOTSUP); 3711842727c2SChris Kirby 3712842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ra->htag, &might_destroy); 3713842727c2SChris Kirby if (error) 3714842727c2SChris Kirby return (error); 3715842727c2SChris Kirby 3716842727c2SChris Kirby if (might_destroy) { 3717842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3718842727c2SChris Kirby 3719842727c2SChris Kirby if (dmu_tx_is_syncing(tx)) { 3720842727c2SChris Kirby /* 3721842727c2SChris Kirby * If we're not prepared to remove the snapshot, 3722842727c2SChris Kirby * we can't allow the release to happen right now. 3723842727c2SChris Kirby */ 3724842727c2SChris Kirby if (!ra->own) 3725842727c2SChris Kirby return (EBUSY); 3726842727c2SChris Kirby } 3727842727c2SChris Kirby dsda.ds = ds; 3728842727c2SChris Kirby dsda.releasing = B_TRUE; 3729842727c2SChris Kirby return (dsl_dataset_destroy_check(&dsda, tag, tx)); 3730842727c2SChris Kirby } 3731842727c2SChris Kirby 3732842727c2SChris Kirby return (0); 3733842727c2SChris Kirby } 3734842727c2SChris Kirby 3735842727c2SChris Kirby static void 37363f9d6ad7SLin Ling dsl_dataset_user_release_sync(void *arg1, void *tag, dmu_tx_t *tx) 3737842727c2SChris Kirby { 3738842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3739842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3740ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3741ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 3742842727c2SChris Kirby uint64_t zapobj; 3743842727c2SChris Kirby uint64_t dsobj = ds->ds_object; 3744842727c2SChris Kirby uint64_t refs; 3745ca45db41SChris Kirby int error; 3746842727c2SChris Kirby 3747842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3748842727c2SChris Kirby ds->ds_userrefs--; 3749842727c2SChris Kirby refs = ds->ds_userrefs; 3750842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3751ca45db41SChris Kirby error = dsl_pool_user_release(dp, ds->ds_object, ra->htag, tx); 3752ca45db41SChris Kirby VERIFY(error == 0 || error == ENOENT); 3753842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3754842727c2SChris Kirby VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx)); 3755842727c2SChris Kirby if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 && 3756842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) { 3757842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3758842727c2SChris Kirby 3759842727c2SChris Kirby ASSERT(ra->own); 3760842727c2SChris Kirby dsda.ds = ds; 3761842727c2SChris Kirby dsda.releasing = B_TRUE; 3762842727c2SChris Kirby /* We already did the destroy_check */ 37633f9d6ad7SLin Ling dsl_dataset_destroy_sync(&dsda, tag, tx); 3764842727c2SChris Kirby } 3765842727c2SChris Kirby 37663f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_USER_RELEASE, 37673f9d6ad7SLin Ling dp->dp_spa, tx, "<%s> %lld dataset = %llu", 3768842727c2SChris Kirby ra->htag, (longlong_t)refs, dsobj); 3769842727c2SChris Kirby } 3770842727c2SChris Kirby 3771842727c2SChris Kirby static int 3772fd136879SMatthew Ahrens dsl_dataset_user_release_one(const char *dsname, void *arg) 3773842727c2SChris Kirby { 3774842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3775842727c2SChris Kirby struct dsl_ds_releasearg *ra; 3776842727c2SChris Kirby dsl_dataset_t *ds; 3777842727c2SChris Kirby int error; 3778842727c2SChris Kirby void *dtag = ha->dstg; 3779842727c2SChris Kirby char *name; 3780842727c2SChris Kirby boolean_t own = B_FALSE; 3781842727c2SChris Kirby boolean_t might_destroy; 3782842727c2SChris Kirby 3783842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname, plus the terminating NULL */ 3784ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3785842727c2SChris Kirby error = dsl_dataset_hold(name, dtag, &ds); 3786ae46e4c7SMatthew Ahrens strfree(name); 3787842727c2SChris Kirby if (error == ENOENT && ha->recursive) 3788842727c2SChris Kirby return (0); 3789fd136879SMatthew Ahrens (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3790842727c2SChris Kirby if (error) 3791842727c2SChris Kirby return (error); 3792842727c2SChris Kirby 3793d7747cbcSChris Kirby ha->gotone = B_TRUE; 3794d7747cbcSChris Kirby 3795842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 3796842727c2SChris Kirby 3797842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ha->htag, &might_destroy); 3798842727c2SChris Kirby if (error) { 3799842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3800842727c2SChris Kirby return (error); 3801842727c2SChris Kirby } 3802842727c2SChris Kirby 3803842727c2SChris Kirby if (might_destroy) { 3804842727c2SChris Kirby #ifdef _KERNEL 38055afc78aaSChris Kirby name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3806842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 38075afc78aaSChris Kirby strfree(name); 3808842727c2SChris Kirby if (error) { 3809842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3810842727c2SChris Kirby return (error); 3811842727c2SChris Kirby } 3812842727c2SChris Kirby #endif 3813503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(ds, B_TRUE, dtag)) { 3814842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3815842727c2SChris Kirby return (EBUSY); 3816842727c2SChris Kirby } else { 3817842727c2SChris Kirby own = B_TRUE; 3818842727c2SChris Kirby dsl_dataset_make_exclusive(ds, dtag); 3819842727c2SChris Kirby } 3820842727c2SChris Kirby } 3821842727c2SChris Kirby 3822842727c2SChris Kirby ra = kmem_alloc(sizeof (struct dsl_ds_releasearg), KM_SLEEP); 3823842727c2SChris Kirby ra->ds = ds; 3824842727c2SChris Kirby ra->htag = ha->htag; 3825842727c2SChris Kirby ra->own = own; 3826842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_release_check, 3827842727c2SChris Kirby dsl_dataset_user_release_sync, ra, dtag, 0); 3828842727c2SChris Kirby 3829842727c2SChris Kirby return (0); 3830842727c2SChris Kirby } 3831842727c2SChris Kirby 3832842727c2SChris Kirby int 3833842727c2SChris Kirby dsl_dataset_user_release(char *dsname, char *snapname, char *htag, 3834842727c2SChris Kirby boolean_t recursive) 3835842727c2SChris Kirby { 3836842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3837842727c2SChris Kirby dsl_sync_task_t *dst; 3838842727c2SChris Kirby spa_t *spa; 3839842727c2SChris Kirby int error; 3840842727c2SChris Kirby 3841620252bcSChris Kirby top: 3842842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3843842727c2SChris Kirby 3844842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3845842727c2SChris Kirby 3846842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3847842727c2SChris Kirby if (error) { 3848842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3849842727c2SChris Kirby return (error); 3850842727c2SChris Kirby } 3851842727c2SChris Kirby 3852842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3853842727c2SChris Kirby ha->htag = htag; 3854842727c2SChris Kirby ha->snapname = snapname; 3855842727c2SChris Kirby ha->recursive = recursive; 3856842727c2SChris Kirby if (recursive) { 3857842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_release_one, 3858842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3859842727c2SChris Kirby } else { 3860842727c2SChris Kirby error = dsl_dataset_user_release_one(dsname, ha); 3861842727c2SChris Kirby } 3862842727c2SChris Kirby if (error == 0) 3863842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3864842727c2SChris Kirby 3865842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3866842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3867842727c2SChris Kirby struct dsl_ds_releasearg *ra = dst->dst_arg1; 3868842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3869842727c2SChris Kirby 3870842727c2SChris Kirby if (dst->dst_err) 3871842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3872842727c2SChris Kirby 3873842727c2SChris Kirby if (ra->own) 3874842727c2SChris Kirby dsl_dataset_disown(ds, ha->dstg); 3875842727c2SChris Kirby else 3876842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3877842727c2SChris Kirby 3878842727c2SChris Kirby kmem_free(ra, sizeof (struct dsl_ds_releasearg)); 3879842727c2SChris Kirby } 3880842727c2SChris Kirby 3881d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3882d7747cbcSChris Kirby error = ENOENT; 3883d7747cbcSChris Kirby 3884620252bcSChris Kirby if (error && error != EBUSY) 3885fd136879SMatthew Ahrens (void) strlcpy(dsname, ha->failed, sizeof (ha->failed)); 3886842727c2SChris Kirby 3887842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3888842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3889842727c2SChris Kirby spa_close(spa, FTAG); 3890620252bcSChris Kirby 3891620252bcSChris Kirby /* 3892620252bcSChris Kirby * We can get EBUSY if we were racing with deferred destroy and 3893620252bcSChris Kirby * dsl_dataset_user_release_check() hadn't done the necessary 3894620252bcSChris Kirby * open context setup. We can also get EBUSY if we're racing 3895620252bcSChris Kirby * with destroy and that thread is the ds_owner. Either way 3896620252bcSChris Kirby * the busy condition should be transient, and we should retry 3897620252bcSChris Kirby * the release operation. 3898620252bcSChris Kirby */ 3899620252bcSChris Kirby if (error == EBUSY) 3900620252bcSChris Kirby goto top; 3901620252bcSChris Kirby 3902842727c2SChris Kirby return (error); 3903842727c2SChris Kirby } 3904842727c2SChris Kirby 3905ca45db41SChris Kirby /* 3906*a7f53a56SChris Kirby * Called at spa_load time (with retry == B_FALSE) to release a stale 3907*a7f53a56SChris Kirby * temporary user hold. Also called by the onexit code (with retry == B_TRUE). 3908ca45db41SChris Kirby */ 3909ca45db41SChris Kirby int 3910*a7f53a56SChris Kirby dsl_dataset_user_release_tmp(dsl_pool_t *dp, uint64_t dsobj, char *htag, 3911*a7f53a56SChris Kirby boolean_t retry) 3912ca45db41SChris Kirby { 3913ca45db41SChris Kirby dsl_dataset_t *ds; 3914ca45db41SChris Kirby char *snap; 3915ca45db41SChris Kirby char *name; 3916ca45db41SChris Kirby int namelen; 3917ca45db41SChris Kirby int error; 3918ca45db41SChris Kirby 3919*a7f53a56SChris Kirby do { 3920*a7f53a56SChris Kirby rw_enter(&dp->dp_config_rwlock, RW_READER); 3921*a7f53a56SChris Kirby error = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds); 3922*a7f53a56SChris Kirby rw_exit(&dp->dp_config_rwlock); 3923*a7f53a56SChris Kirby if (error) 3924*a7f53a56SChris Kirby return (error); 3925*a7f53a56SChris Kirby namelen = dsl_dataset_namelen(ds)+1; 3926*a7f53a56SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 3927*a7f53a56SChris Kirby dsl_dataset_name(ds, name); 3928*a7f53a56SChris Kirby dsl_dataset_rele(ds, FTAG); 3929ca45db41SChris Kirby 3930*a7f53a56SChris Kirby snap = strchr(name, '@'); 3931*a7f53a56SChris Kirby *snap = '\0'; 3932*a7f53a56SChris Kirby ++snap; 3933*a7f53a56SChris Kirby error = dsl_dataset_user_release(name, snap, htag, B_FALSE); 3934*a7f53a56SChris Kirby kmem_free(name, namelen); 3935*a7f53a56SChris Kirby 3936*a7f53a56SChris Kirby /* 3937*a7f53a56SChris Kirby * The object can't have been destroyed because we have a hold, 3938*a7f53a56SChris Kirby * but it might have been renamed, resulting in ENOENT. Retry 3939*a7f53a56SChris Kirby * if we've been requested to do so. 3940*a7f53a56SChris Kirby * 3941*a7f53a56SChris Kirby * It would be nice if we could use the dsobj all the way 3942*a7f53a56SChris Kirby * through and avoid ENOENT entirely. But we might need to 3943*a7f53a56SChris Kirby * unmount the snapshot, and there's currently no way to lookup 3944*a7f53a56SChris Kirby * a vfsp using a ZFS object id. 3945*a7f53a56SChris Kirby */ 3946*a7f53a56SChris Kirby } while ((error == ENOENT) && retry); 3947*a7f53a56SChris Kirby 3948*a7f53a56SChris Kirby return (error); 3949ca45db41SChris Kirby } 3950ca45db41SChris Kirby 3951842727c2SChris Kirby int 3952842727c2SChris Kirby dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp) 3953842727c2SChris Kirby { 3954842727c2SChris Kirby dsl_dataset_t *ds; 3955842727c2SChris Kirby int err; 3956842727c2SChris Kirby 3957842727c2SChris Kirby err = dsl_dataset_hold(dsname, FTAG, &ds); 3958842727c2SChris Kirby if (err) 3959842727c2SChris Kirby return (err); 3960842727c2SChris Kirby 3961842727c2SChris Kirby VERIFY(0 == nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP)); 3962842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) { 3963842727c2SChris Kirby zap_attribute_t *za; 3964842727c2SChris Kirby zap_cursor_t zc; 3965842727c2SChris Kirby 3966842727c2SChris Kirby za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 3967842727c2SChris Kirby for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset, 3968842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj); 3969842727c2SChris Kirby zap_cursor_retrieve(&zc, za) == 0; 3970842727c2SChris Kirby zap_cursor_advance(&zc)) { 3971842727c2SChris Kirby VERIFY(0 == nvlist_add_uint64(*nvp, za->za_name, 3972842727c2SChris Kirby za->za_first_integer)); 3973842727c2SChris Kirby } 3974842727c2SChris Kirby zap_cursor_fini(&zc); 3975842727c2SChris Kirby kmem_free(za, sizeof (zap_attribute_t)); 3976842727c2SChris Kirby } 3977842727c2SChris Kirby dsl_dataset_rele(ds, FTAG); 3978842727c2SChris Kirby return (0); 3979842727c2SChris Kirby } 3980503ad85cSMatthew Ahrens 3981503ad85cSMatthew Ahrens /* 3982503ad85cSMatthew Ahrens * Note, this fuction is used as the callback for dmu_objset_find(). We 3983503ad85cSMatthew Ahrens * always return 0 so that we will continue to find and process 3984503ad85cSMatthew Ahrens * inconsistent datasets, even if we encounter an error trying to 3985503ad85cSMatthew Ahrens * process one of them. 3986503ad85cSMatthew Ahrens */ 3987503ad85cSMatthew Ahrens /* ARGSUSED */ 3988503ad85cSMatthew Ahrens int 3989fd136879SMatthew Ahrens dsl_destroy_inconsistent(const char *dsname, void *arg) 3990503ad85cSMatthew Ahrens { 3991503ad85cSMatthew Ahrens dsl_dataset_t *ds; 3992503ad85cSMatthew Ahrens 3993503ad85cSMatthew Ahrens if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) { 3994503ad85cSMatthew Ahrens if (DS_IS_INCONSISTENT(ds)) 3995503ad85cSMatthew Ahrens (void) dsl_dataset_destroy(ds, FTAG, B_FALSE); 3996503ad85cSMatthew Ahrens else 3997503ad85cSMatthew Ahrens dsl_dataset_disown(ds, FTAG); 3998503ad85cSMatthew Ahrens } 3999503ad85cSMatthew Ahrens return (0); 4000503ad85cSMatthew Ahrens } 4001