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. 23187d6ac0SMatt Ahrens * Copyright (c) 2011 by Delphix. All rights reserved. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/dmu_objset.h> 27fa9e4066Sahrens #include <sys/dsl_dataset.h> 28fa9e4066Sahrens #include <sys/dsl_dir.h> 2999653d4eSeschrock #include <sys/dsl_prop.h> 301d452cf5Sahrens #include <sys/dsl_synctask.h> 31fa9e4066Sahrens #include <sys/dmu_traverse.h> 32fa9e4066Sahrens #include <sys/dmu_tx.h> 33fa9e4066Sahrens #include <sys/arc.h> 34fa9e4066Sahrens #include <sys/zio.h> 35fa9e4066Sahrens #include <sys/zap.h> 36fa9e4066Sahrens #include <sys/unique.h> 37fa9e4066Sahrens #include <sys/zfs_context.h> 38cdf5b4caSmmusante #include <sys/zfs_ioctl.h> 39ecd6cf80Smarks #include <sys/spa.h> 40088f3894Sahrens #include <sys/zfs_znode.h> 41c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 42842727c2SChris Kirby #include <sys/zvol.h> 433f9d6ad7SLin Ling #include <sys/dsl_scan.h> 44cde58dbcSMatthew Ahrens #include <sys/dsl_deadlist.h> 45fa9e4066Sahrens 46745cd3c5Smaybee static char *dsl_reaper = "the grim reaper"; 47745cd3c5Smaybee 481d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 491d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 50a9799022Sck static dsl_syncfunc_t dsl_dataset_set_reservation_sync; 51e1930233Sbonwick 52cde58dbcSMatthew Ahrens #define SWITCH64(x, y) \ 53cde58dbcSMatthew Ahrens { \ 54cde58dbcSMatthew Ahrens uint64_t __tmp = (x); \ 55cde58dbcSMatthew Ahrens (x) = (y); \ 56cde58dbcSMatthew Ahrens (y) = __tmp; \ 57cde58dbcSMatthew Ahrens } 58cde58dbcSMatthew Ahrens 5955434c77Sek #define DS_REF_MAX (1ULL << 62) 60fa9e4066Sahrens 61fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 62fa9e4066Sahrens 63745cd3c5Smaybee #define DSL_DATASET_IS_DESTROYED(ds) ((ds)->ds_owner == dsl_reaper) 64745cd3c5Smaybee 65fa9e4066Sahrens 66a9799022Sck /* 67a9799022Sck * Figure out how much of this delta should be propogated to the dsl_dir 68a9799022Sck * layer. If there's a refreservation, that space has already been 69a9799022Sck * partially accounted for in our ancestors. 70a9799022Sck */ 71a9799022Sck static int64_t 72a9799022Sck parent_delta(dsl_dataset_t *ds, int64_t delta) 73a9799022Sck { 74a9799022Sck uint64_t old_bytes, new_bytes; 75a9799022Sck 76a9799022Sck if (ds->ds_reserved == 0) 77a9799022Sck return (delta); 78a9799022Sck 79a9799022Sck old_bytes = MAX(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 80a9799022Sck new_bytes = MAX(ds->ds_phys->ds_unique_bytes + delta, ds->ds_reserved); 81a9799022Sck 82a9799022Sck ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta)); 83a9799022Sck return (new_bytes - old_bytes); 84a9799022Sck } 85fa9e4066Sahrens 86fa9e4066Sahrens void 87b24ab676SJeff Bonwick dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx) 88fa9e4066Sahrens { 89b24ab676SJeff Bonwick int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp); 90fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 91fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 92a9799022Sck int64_t delta; 93fa9e4066Sahrens 943f9d6ad7SLin Ling dprintf_bp(bp, "ds=%p", ds); 95fa9e4066Sahrens 96fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 97fa9e4066Sahrens /* It could have been compressed away to nothing */ 98fa9e4066Sahrens if (BP_IS_HOLE(bp)) 99fa9e4066Sahrens return; 100fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 101fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 102fa9e4066Sahrens if (ds == NULL) { 103fa9e4066Sahrens /* 104fa9e4066Sahrens * Account for the meta-objset space in its placeholder 105fa9e4066Sahrens * dsl_dir. 106fa9e4066Sahrens */ 107fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 10874e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 109fa9e4066Sahrens used, compressed, uncompressed, tx); 110fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 111fa9e4066Sahrens return; 112fa9e4066Sahrens } 113fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1143f9d6ad7SLin Ling 11502c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 116fa9e4066Sahrens mutex_enter(&ds->ds_lock); 117a9799022Sck delta = parent_delta(ds, used); 118fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 119fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 120fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 121fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 122fa9e4066Sahrens mutex_exit(&ds->ds_lock); 12374e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, 12474e7dc98SMatthew Ahrens compressed, uncompressed, tx); 12574e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used - delta, 12674e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 12702c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 128fa9e4066Sahrens } 129fa9e4066Sahrens 130cdb0ab79Smaybee int 131b24ab676SJeff Bonwick dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx, 132b24ab676SJeff Bonwick boolean_t async) 133fa9e4066Sahrens { 134fa9e4066Sahrens if (BP_IS_HOLE(bp)) 135cdb0ab79Smaybee return (0); 136fa9e4066Sahrens 137b24ab676SJeff Bonwick ASSERT(dmu_tx_is_syncing(tx)); 138b24ab676SJeff Bonwick ASSERT(bp->blk_birth <= tx->tx_txg); 139b24ab676SJeff Bonwick 140b24ab676SJeff Bonwick int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp); 141b24ab676SJeff Bonwick int compressed = BP_GET_PSIZE(bp); 142b24ab676SJeff Bonwick int uncompressed = BP_GET_UCSIZE(bp); 143b24ab676SJeff Bonwick 144fa9e4066Sahrens ASSERT(used > 0); 145fa9e4066Sahrens if (ds == NULL) { 146fa9e4066Sahrens /* 147fa9e4066Sahrens * Account for the meta-objset space in its placeholder 148fa9e4066Sahrens * dataset. 149fa9e4066Sahrens */ 150b24ab676SJeff Bonwick dsl_free(tx->tx_pool, tx->tx_txg, bp); 151fa9e4066Sahrens 15274e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 153fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 154fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 155cdb0ab79Smaybee return (used); 156fa9e4066Sahrens } 157fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 158fa9e4066Sahrens 15974e7dc98SMatthew Ahrens ASSERT(!dsl_dataset_is_snapshot(ds)); 160fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 161fa9e4066Sahrens 162fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 163a9799022Sck int64_t delta; 164c717a561Smaybee 1653f9d6ad7SLin Ling dprintf_bp(bp, "freeing ds=%llu", ds->ds_object); 166b24ab676SJeff Bonwick dsl_free(tx->tx_pool, tx->tx_txg, bp); 167fa9e4066Sahrens 16802c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 169fa9e4066Sahrens mutex_enter(&ds->ds_lock); 170a9799022Sck ASSERT(ds->ds_phys->ds_unique_bytes >= used || 171a9799022Sck !DS_UNIQUE_IS_ACCURATE(ds)); 172a9799022Sck delta = parent_delta(ds, -used); 173fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 174fa9e4066Sahrens mutex_exit(&ds->ds_lock); 17574e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 176a9799022Sck delta, -compressed, -uncompressed, tx); 17774e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, -used - delta, 17874e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 17902c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 180fa9e4066Sahrens } else { 181fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 182b24ab676SJeff Bonwick if (async) { 183b24ab676SJeff Bonwick /* 184b24ab676SJeff Bonwick * We are here as part of zio's write done callback, 185b24ab676SJeff Bonwick * which means we're a zio interrupt thread. We can't 186cde58dbcSMatthew Ahrens * call dsl_deadlist_insert() now because it may block 187b24ab676SJeff Bonwick * waiting for I/O. Instead, put bp on the deferred 188b24ab676SJeff Bonwick * queue and let dsl_pool_sync() finish the job. 189b24ab676SJeff Bonwick */ 190cde58dbcSMatthew Ahrens bplist_append(&ds->ds_pending_deadlist, bp); 191b24ab676SJeff Bonwick } else { 192cde58dbcSMatthew Ahrens dsl_deadlist_insert(&ds->ds_deadlist, bp, tx); 193b24ab676SJeff Bonwick } 194a4611edeSahrens ASSERT3U(ds->ds_prev->ds_object, ==, 195a4611edeSahrens ds->ds_phys->ds_prev_snap_obj); 196a4611edeSahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 197fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 198a4611edeSahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 199a4611edeSahrens ds->ds_object && bp->blk_birth > 200a4611edeSahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 201a4611edeSahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 202a4611edeSahrens mutex_enter(&ds->ds_prev->ds_lock); 203a4611edeSahrens ds->ds_prev->ds_phys->ds_unique_bytes += used; 204a4611edeSahrens mutex_exit(&ds->ds_prev->ds_lock); 205fa9e4066Sahrens } 2063f9d6ad7SLin Ling if (bp->blk_birth > ds->ds_dir->dd_origin_txg) { 20774e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used, 20874e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 20974e7dc98SMatthew Ahrens } 210fa9e4066Sahrens } 211fa9e4066Sahrens mutex_enter(&ds->ds_lock); 212fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 213fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 214fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 215fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 216fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 217fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 218fa9e4066Sahrens mutex_exit(&ds->ds_lock); 219cdb0ab79Smaybee 220cdb0ab79Smaybee return (used); 221fa9e4066Sahrens } 222fa9e4066Sahrens 223ea8dc4b6Seschrock uint64_t 224ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 225fa9e4066Sahrens { 226a2eea2e1Sahrens uint64_t trysnap = 0; 227a2eea2e1Sahrens 228fa9e4066Sahrens if (ds == NULL) 229ea8dc4b6Seschrock return (0); 230fa9e4066Sahrens /* 231fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 232fa9e4066Sahrens * incorrect FALSE return, which would only result in an 233fa9e4066Sahrens * overestimation of the amount of space that an operation would 234fa9e4066Sahrens * consume, which is OK. 235fa9e4066Sahrens * 236fa9e4066Sahrens * There's also a small window where we could miss a pending 237fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 238fa9e4066Sahrens * phase. So this should only be used as a guess. 239fa9e4066Sahrens */ 240a2eea2e1Sahrens if (ds->ds_trysnap_txg > 241a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 242a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 243a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 244ea8dc4b6Seschrock } 245ea8dc4b6Seschrock 2463d692628SSanjeev Bagewadi boolean_t 247c7cd2421SGeorge Wilson dsl_dataset_block_freeable(dsl_dataset_t *ds, const blkptr_t *bp, 248c7cd2421SGeorge Wilson uint64_t blk_birth) 249ea8dc4b6Seschrock { 250c7cd2421SGeorge Wilson if (blk_birth <= dsl_dataset_prev_snap_txg(ds)) 251c7cd2421SGeorge Wilson return (B_FALSE); 252c7cd2421SGeorge Wilson 253837b568bSGeorge Wilson ddt_prefetch(dsl_dataset_get_spa(ds), bp); 254c7cd2421SGeorge Wilson 255c7cd2421SGeorge Wilson return (B_TRUE); 256fa9e4066Sahrens } 257fa9e4066Sahrens 258fa9e4066Sahrens /* ARGSUSED */ 259fa9e4066Sahrens static void 260fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 261fa9e4066Sahrens { 262fa9e4066Sahrens dsl_dataset_t *ds = dsv; 263fa9e4066Sahrens 264745cd3c5Smaybee ASSERT(ds->ds_owner == NULL || DSL_DATASET_IS_DESTROYED(ds)); 265fa9e4066Sahrens 26691ebeef5Sahrens unique_remove(ds->ds_fsid_guid); 267fa9e4066Sahrens 268503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) 269503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 270fa9e4066Sahrens 271fa9e4066Sahrens if (ds->ds_prev) { 272745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 273fa9e4066Sahrens ds->ds_prev = NULL; 274fa9e4066Sahrens } 275fa9e4066Sahrens 276cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 277cde58dbcSMatthew Ahrens if (db != NULL) { 278cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 279cde58dbcSMatthew Ahrens } else { 280cde58dbcSMatthew Ahrens ASSERT(ds->ds_deadlist.dl_dbuf == NULL); 281cde58dbcSMatthew Ahrens ASSERT(!ds->ds_deadlist.dl_oldfmt); 282cde58dbcSMatthew Ahrens } 283745cd3c5Smaybee if (ds->ds_dir) 284745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 285fa9e4066Sahrens 28691ebeef5Sahrens ASSERT(!list_link_active(&ds->ds_synced_link)); 287fa9e4066Sahrens 2885ad82045Snd mutex_destroy(&ds->ds_lock); 289f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 29091ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 291745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 292745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 2935ad82045Snd 294fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 295fa9e4066Sahrens } 296fa9e4066Sahrens 297ea8dc4b6Seschrock static int 298fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 299fa9e4066Sahrens { 300fa9e4066Sahrens dsl_dataset_phys_t *headphys; 301fa9e4066Sahrens int err; 302fa9e4066Sahrens dmu_buf_t *headdbuf; 303fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 304fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 305fa9e4066Sahrens 306fa9e4066Sahrens if (ds->ds_snapname[0]) 307ea8dc4b6Seschrock return (0); 308fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 309ea8dc4b6Seschrock return (0); 310fa9e4066Sahrens 311ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 312ea8dc4b6Seschrock FTAG, &headdbuf); 313ea8dc4b6Seschrock if (err) 314ea8dc4b6Seschrock return (err); 315fa9e4066Sahrens headphys = headdbuf->db_data; 316fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 317e7437265Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); 318ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 319ea8dc4b6Seschrock return (err); 320fa9e4066Sahrens } 321fa9e4066Sahrens 322ab04eb8eStimh static int 323745cd3c5Smaybee dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value) 324ab04eb8eStimh { 325745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 326745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 327ab04eb8eStimh matchtype_t mt; 328ab04eb8eStimh int err; 329ab04eb8eStimh 330745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 331ab04eb8eStimh mt = MT_FIRST; 332ab04eb8eStimh else 333ab04eb8eStimh mt = MT_EXACT; 334ab04eb8eStimh 335745cd3c5Smaybee err = zap_lookup_norm(mos, snapobj, name, 8, 1, 336ab04eb8eStimh value, mt, NULL, 0, NULL); 337ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 338745cd3c5Smaybee err = zap_lookup(mos, snapobj, name, 8, 1, value); 339ab04eb8eStimh return (err); 340ab04eb8eStimh } 341ab04eb8eStimh 342ab04eb8eStimh static int 343745cd3c5Smaybee dsl_dataset_snap_remove(dsl_dataset_t *ds, char *name, dmu_tx_t *tx) 344ab04eb8eStimh { 345745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 346745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 347ab04eb8eStimh matchtype_t mt; 348ab04eb8eStimh int err; 349ab04eb8eStimh 35071eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 35171eb0538SChris Kirby 352745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 353ab04eb8eStimh mt = MT_FIRST; 354ab04eb8eStimh else 355ab04eb8eStimh mt = MT_EXACT; 356ab04eb8eStimh 357745cd3c5Smaybee err = zap_remove_norm(mos, snapobj, name, mt, tx); 358ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 359745cd3c5Smaybee err = zap_remove(mos, snapobj, name, tx); 360ab04eb8eStimh return (err); 361ab04eb8eStimh } 362ab04eb8eStimh 363745cd3c5Smaybee static int 364745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag, 365745cd3c5Smaybee dsl_dataset_t **dsp) 366fa9e4066Sahrens { 367fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 368fa9e4066Sahrens dmu_buf_t *dbuf; 369fa9e4066Sahrens dsl_dataset_t *ds; 370ea8dc4b6Seschrock int err; 371a7f53a56SChris Kirby dmu_object_info_t doi; 372fa9e4066Sahrens 373fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 374fa9e4066Sahrens dsl_pool_sync_context(dp)); 375fa9e4066Sahrens 376ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 377ea8dc4b6Seschrock if (err) 378ea8dc4b6Seschrock return (err); 379a7f53a56SChris Kirby 380a7f53a56SChris Kirby /* Make sure dsobj has the correct object type. */ 381a7f53a56SChris Kirby dmu_object_info_from_db(dbuf, &doi); 382a7f53a56SChris Kirby if (doi.doi_type != DMU_OT_DSL_DATASET) 383a7f53a56SChris Kirby return (EINVAL); 384a7f53a56SChris Kirby 385fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 386fa9e4066Sahrens if (ds == NULL) { 387fa9e4066Sahrens dsl_dataset_t *winner; 388fa9e4066Sahrens 389fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 390fa9e4066Sahrens ds->ds_dbuf = dbuf; 391fa9e4066Sahrens ds->ds_object = dsobj; 392fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 393fa9e4066Sahrens 3945ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 395f4b94bdeSMatthew Ahrens mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL); 39691ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 397745cd3c5Smaybee rw_init(&ds->ds_rwlock, 0, 0, 0); 398745cd3c5Smaybee cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL); 3995ad82045Snd 400cde58dbcSMatthew Ahrens bplist_create(&ds->ds_pending_deadlist); 401cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, 402fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 403cde58dbcSMatthew Ahrens 404ea8dc4b6Seschrock if (err == 0) { 405ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 406ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 407ea8dc4b6Seschrock } 408ea8dc4b6Seschrock if (err) { 4095ad82045Snd mutex_destroy(&ds->ds_lock); 410f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 41191ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 412745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 413745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 414cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 415cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 416ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 417ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 418ea8dc4b6Seschrock return (err); 419ea8dc4b6Seschrock } 420fa9e4066Sahrens 42174e7dc98SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 422fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 423fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 424745cd3c5Smaybee err = dsl_dataset_get_ref(dp, 425745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 426745cd3c5Smaybee ds, &ds->ds_prev); 427fa9e4066Sahrens } 428842727c2SChris Kirby } else { 429842727c2SChris Kirby if (zfs_flags & ZFS_DEBUG_SNAPNAMES) 430842727c2SChris Kirby err = dsl_dataset_get_snapname(ds); 431842727c2SChris Kirby if (err == 0 && ds->ds_phys->ds_userrefs_obj != 0) { 432842727c2SChris Kirby err = zap_count( 433842727c2SChris Kirby ds->ds_dir->dd_pool->dp_meta_objset, 434842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj, 435842727c2SChris Kirby &ds->ds_userrefs); 436842727c2SChris Kirby } 437fa9e4066Sahrens } 438fa9e4066Sahrens 43974e7dc98SMatthew Ahrens if (err == 0 && !dsl_dataset_is_snapshot(ds)) { 44027345066Sck /* 44127345066Sck * In sync context, we're called with either no lock 44227345066Sck * or with the write lock. If we're not syncing, 44327345066Sck * we're always called with the read lock held. 44427345066Sck */ 445cb625fb5Sck boolean_t need_lock = 44627345066Sck !RW_WRITE_HELD(&dp->dp_config_rwlock) && 44727345066Sck dsl_pool_sync_context(dp); 448cb625fb5Sck 449cb625fb5Sck if (need_lock) 450cb625fb5Sck rw_enter(&dp->dp_config_rwlock, RW_READER); 451cb625fb5Sck 452bb0ade09Sahrens err = dsl_prop_get_ds(ds, 453cb625fb5Sck "refreservation", sizeof (uint64_t), 1, 454cb625fb5Sck &ds->ds_reserved, NULL); 455cb625fb5Sck if (err == 0) { 456bb0ade09Sahrens err = dsl_prop_get_ds(ds, 457cb625fb5Sck "refquota", sizeof (uint64_t), 1, 458cb625fb5Sck &ds->ds_quota, NULL); 459cb625fb5Sck } 460cb625fb5Sck 461cb625fb5Sck if (need_lock) 462cb625fb5Sck rw_exit(&dp->dp_config_rwlock); 463cb625fb5Sck } else { 464cb625fb5Sck ds->ds_reserved = ds->ds_quota = 0; 465cb625fb5Sck } 466cb625fb5Sck 467ea8dc4b6Seschrock if (err == 0) { 468ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 469ea8dc4b6Seschrock dsl_dataset_evict); 470ea8dc4b6Seschrock } 471ea8dc4b6Seschrock if (err || winner) { 472cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 473cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 474745cd3c5Smaybee if (ds->ds_prev) 475745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 476fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 4775ad82045Snd mutex_destroy(&ds->ds_lock); 478f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 47991ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 480745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 481745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 482fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 483ea8dc4b6Seschrock if (err) { 484ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 485ea8dc4b6Seschrock return (err); 486ea8dc4b6Seschrock } 487fa9e4066Sahrens ds = winner; 488fa9e4066Sahrens } else { 48991ebeef5Sahrens ds->ds_fsid_guid = 490fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 491fa9e4066Sahrens } 492fa9e4066Sahrens } 493fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 494fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 495088f3894Sahrens ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 || 496afc6333aSahrens spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN || 49784db2a68Sahrens dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap); 498fa9e4066Sahrens mutex_enter(&ds->ds_lock); 499745cd3c5Smaybee if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) { 500fa9e4066Sahrens mutex_exit(&ds->ds_lock); 501745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 502745cd3c5Smaybee return (ENOENT); 503fa9e4066Sahrens } 504fa9e4066Sahrens mutex_exit(&ds->ds_lock); 505ea8dc4b6Seschrock *dsp = ds; 506ea8dc4b6Seschrock return (0); 507fa9e4066Sahrens } 508fa9e4066Sahrens 509745cd3c5Smaybee static int 510745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag) 511745cd3c5Smaybee { 512745cd3c5Smaybee dsl_pool_t *dp = ds->ds_dir->dd_pool; 513745cd3c5Smaybee 514745cd3c5Smaybee /* 515745cd3c5Smaybee * In syncing context we don't want the rwlock lock: there 516745cd3c5Smaybee * may be an existing writer waiting for sync phase to 517745cd3c5Smaybee * finish. We don't need to worry about such writers, since 518745cd3c5Smaybee * sync phase is single-threaded, so the writer can't be 519745cd3c5Smaybee * doing anything while we are active. 520745cd3c5Smaybee */ 521745cd3c5Smaybee if (dsl_pool_sync_context(dp)) { 522745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 523745cd3c5Smaybee return (0); 524745cd3c5Smaybee } 525745cd3c5Smaybee 526745cd3c5Smaybee /* 527745cd3c5Smaybee * Normal users will hold the ds_rwlock as a READER until they 528745cd3c5Smaybee * are finished (i.e., call dsl_dataset_rele()). "Owners" will 529745cd3c5Smaybee * drop their READER lock after they set the ds_owner field. 530745cd3c5Smaybee * 531745cd3c5Smaybee * If the dataset is being destroyed, the destroy thread will 532745cd3c5Smaybee * obtain a WRITER lock for exclusive access after it's done its 533745cd3c5Smaybee * open-context work and then change the ds_owner to 534745cd3c5Smaybee * dsl_reaper once destruction is assured. So threads 535745cd3c5Smaybee * may block here temporarily, until the "destructability" of 536745cd3c5Smaybee * the dataset is determined. 537745cd3c5Smaybee */ 538745cd3c5Smaybee ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock)); 539745cd3c5Smaybee mutex_enter(&ds->ds_lock); 540745cd3c5Smaybee while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) { 541745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 542745cd3c5Smaybee cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock); 543745cd3c5Smaybee if (DSL_DATASET_IS_DESTROYED(ds)) { 544745cd3c5Smaybee mutex_exit(&ds->ds_lock); 545745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 546745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 547745cd3c5Smaybee return (ENOENT); 548745cd3c5Smaybee } 549620252bcSChris Kirby /* 550620252bcSChris Kirby * The dp_config_rwlock lives above the ds_lock. And 551620252bcSChris Kirby * we need to check DSL_DATASET_IS_DESTROYED() while 552620252bcSChris Kirby * holding the ds_lock, so we have to drop and reacquire 553620252bcSChris Kirby * the ds_lock here. 554620252bcSChris Kirby */ 555620252bcSChris Kirby mutex_exit(&ds->ds_lock); 556745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 557620252bcSChris Kirby mutex_enter(&ds->ds_lock); 558745cd3c5Smaybee } 559745cd3c5Smaybee mutex_exit(&ds->ds_lock); 560745cd3c5Smaybee return (0); 561745cd3c5Smaybee } 562745cd3c5Smaybee 563745cd3c5Smaybee int 564745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, 565745cd3c5Smaybee dsl_dataset_t **dsp) 566745cd3c5Smaybee { 567745cd3c5Smaybee int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp); 568745cd3c5Smaybee 569745cd3c5Smaybee if (err) 570745cd3c5Smaybee return (err); 571745cd3c5Smaybee return (dsl_dataset_hold_ref(*dsp, tag)); 572745cd3c5Smaybee } 573745cd3c5Smaybee 574745cd3c5Smaybee int 575503ad85cSMatthew Ahrens dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, boolean_t inconsistentok, 576503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 577745cd3c5Smaybee { 578503ad85cSMatthew Ahrens int err = dsl_dataset_hold_obj(dp, dsobj, tag, dsp); 579745cd3c5Smaybee if (err) 580745cd3c5Smaybee return (err); 581503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 582503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 5834f5064b7SMark J Musante *dsp = NULL; 584745cd3c5Smaybee return (EBUSY); 585745cd3c5Smaybee } 586745cd3c5Smaybee return (0); 587745cd3c5Smaybee } 588745cd3c5Smaybee 589fa9e4066Sahrens int 590745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp) 591fa9e4066Sahrens { 592fa9e4066Sahrens dsl_dir_t *dd; 593fa9e4066Sahrens dsl_pool_t *dp; 594745cd3c5Smaybee const char *snapname; 595fa9e4066Sahrens uint64_t obj; 596fa9e4066Sahrens int err = 0; 597fa9e4066Sahrens 598745cd3c5Smaybee err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname); 599ea8dc4b6Seschrock if (err) 600ea8dc4b6Seschrock return (err); 601fa9e4066Sahrens 602fa9e4066Sahrens dp = dd->dd_pool; 603fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 604fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 605745cd3c5Smaybee if (obj) 606745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, dsp); 607745cd3c5Smaybee else 608fa9e4066Sahrens err = ENOENT; 609745cd3c5Smaybee if (err) 610fa9e4066Sahrens goto out; 611fa9e4066Sahrens 612745cd3c5Smaybee err = dsl_dataset_hold_ref(*dsp, tag); 613fa9e4066Sahrens 614745cd3c5Smaybee /* we may be looking for a snapshot */ 615745cd3c5Smaybee if (err == 0 && snapname != NULL) { 616745cd3c5Smaybee dsl_dataset_t *ds = NULL; 617fa9e4066Sahrens 618745cd3c5Smaybee if (*snapname++ != '@') { 619745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 620fa9e4066Sahrens err = ENOENT; 621fa9e4066Sahrens goto out; 622fa9e4066Sahrens } 623fa9e4066Sahrens 624745cd3c5Smaybee dprintf("looking for snapshot '%s'\n", snapname); 625745cd3c5Smaybee err = dsl_dataset_snap_lookup(*dsp, snapname, &obj); 626745cd3c5Smaybee if (err == 0) 627745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, &ds); 628745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 629745cd3c5Smaybee 630745cd3c5Smaybee ASSERT3U((err == 0), ==, (ds != NULL)); 631745cd3c5Smaybee 632745cd3c5Smaybee if (ds) { 633745cd3c5Smaybee mutex_enter(&ds->ds_lock); 634745cd3c5Smaybee if (ds->ds_snapname[0] == 0) 635745cd3c5Smaybee (void) strlcpy(ds->ds_snapname, snapname, 636745cd3c5Smaybee sizeof (ds->ds_snapname)); 637745cd3c5Smaybee mutex_exit(&ds->ds_lock); 638745cd3c5Smaybee err = dsl_dataset_hold_ref(ds, tag); 639745cd3c5Smaybee *dsp = err ? NULL : ds; 640fa9e4066Sahrens } 641fa9e4066Sahrens } 642fa9e4066Sahrens out: 643fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 644fa9e4066Sahrens dsl_dir_close(dd, FTAG); 645fa9e4066Sahrens return (err); 646fa9e4066Sahrens } 647fa9e4066Sahrens 648fa9e4066Sahrens int 649503ad85cSMatthew Ahrens dsl_dataset_own(const char *name, boolean_t inconsistentok, 650503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 651fa9e4066Sahrens { 652503ad85cSMatthew Ahrens int err = dsl_dataset_hold(name, tag, dsp); 653745cd3c5Smaybee if (err) 654745cd3c5Smaybee return (err); 655503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 656503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 657745cd3c5Smaybee return (EBUSY); 658745cd3c5Smaybee } 659745cd3c5Smaybee return (0); 660fa9e4066Sahrens } 661fa9e4066Sahrens 662fa9e4066Sahrens void 663fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 664fa9e4066Sahrens { 665fa9e4066Sahrens if (ds == NULL) { 666fa9e4066Sahrens (void) strcpy(name, "mos"); 667fa9e4066Sahrens } else { 668fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 669ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 670fa9e4066Sahrens if (ds->ds_snapname[0]) { 671fa9e4066Sahrens (void) strcat(name, "@"); 672745cd3c5Smaybee /* 673745cd3c5Smaybee * We use a "recursive" mutex so that we 674745cd3c5Smaybee * can call dprintf_ds() with ds_lock held. 675745cd3c5Smaybee */ 676fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 677fa9e4066Sahrens mutex_enter(&ds->ds_lock); 678fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 679fa9e4066Sahrens mutex_exit(&ds->ds_lock); 680fa9e4066Sahrens } else { 681fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 682fa9e4066Sahrens } 683fa9e4066Sahrens } 684fa9e4066Sahrens } 685fa9e4066Sahrens } 686fa9e4066Sahrens 687b7661cccSmmusante static int 688b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 689b7661cccSmmusante { 690b7661cccSmmusante int result; 691b7661cccSmmusante 692b7661cccSmmusante if (ds == NULL) { 693b7661cccSmmusante result = 3; /* "mos" */ 694b7661cccSmmusante } else { 695b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 696b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 697b7661cccSmmusante if (ds->ds_snapname[0]) { 698b7661cccSmmusante ++result; /* adding one for the @-sign */ 699b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 700b7661cccSmmusante mutex_enter(&ds->ds_lock); 701b7661cccSmmusante result += strlen(ds->ds_snapname); 702b7661cccSmmusante mutex_exit(&ds->ds_lock); 703b7661cccSmmusante } else { 704b7661cccSmmusante result += strlen(ds->ds_snapname); 705b7661cccSmmusante } 706b7661cccSmmusante } 707b7661cccSmmusante } 708b7661cccSmmusante 709b7661cccSmmusante return (result); 710b7661cccSmmusante } 711b7661cccSmmusante 712088f3894Sahrens void 713745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag) 714fa9e4066Sahrens { 715ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 716fa9e4066Sahrens } 717fa9e4066Sahrens 7183cb34c60Sahrens void 719745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag) 7203cb34c60Sahrens { 721745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) { 722745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 723745cd3c5Smaybee } 724745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 725745cd3c5Smaybee } 726745cd3c5Smaybee 727745cd3c5Smaybee void 728503ad85cSMatthew Ahrens dsl_dataset_disown(dsl_dataset_t *ds, void *tag) 729745cd3c5Smaybee { 730503ad85cSMatthew Ahrens ASSERT((ds->ds_owner == tag && ds->ds_dbuf) || 731745cd3c5Smaybee (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL)); 732745cd3c5Smaybee 7333cb34c60Sahrens mutex_enter(&ds->ds_lock); 734745cd3c5Smaybee ds->ds_owner = NULL; 735745cd3c5Smaybee if (RW_WRITE_HELD(&ds->ds_rwlock)) { 736745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 737745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 738745cd3c5Smaybee } 7393cb34c60Sahrens mutex_exit(&ds->ds_lock); 740745cd3c5Smaybee if (ds->ds_dbuf) 741503ad85cSMatthew Ahrens dsl_dataset_drop_ref(ds, tag); 742745cd3c5Smaybee else 743cde58dbcSMatthew Ahrens dsl_dataset_evict(NULL, ds); 7443cb34c60Sahrens } 7453cb34c60Sahrens 7463cb34c60Sahrens boolean_t 747503ad85cSMatthew Ahrens dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *tag) 7483cb34c60Sahrens { 749745cd3c5Smaybee boolean_t gotit = FALSE; 750745cd3c5Smaybee 7513cb34c60Sahrens mutex_enter(&ds->ds_lock); 752745cd3c5Smaybee if (ds->ds_owner == NULL && 753745cd3c5Smaybee (!DS_IS_INCONSISTENT(ds) || inconsistentok)) { 754503ad85cSMatthew Ahrens ds->ds_owner = tag; 755745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) 756745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 757745cd3c5Smaybee gotit = TRUE; 7583cb34c60Sahrens } 7593cb34c60Sahrens mutex_exit(&ds->ds_lock); 760745cd3c5Smaybee return (gotit); 761745cd3c5Smaybee } 762745cd3c5Smaybee 763745cd3c5Smaybee void 764745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner) 765745cd3c5Smaybee { 766745cd3c5Smaybee ASSERT3P(owner, ==, ds->ds_owner); 767745cd3c5Smaybee if (!RW_WRITE_HELD(&ds->ds_rwlock)) 768745cd3c5Smaybee rw_enter(&ds->ds_rwlock, RW_WRITER); 7693cb34c60Sahrens } 7703cb34c60Sahrens 7711d452cf5Sahrens uint64_t 772088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 773ab04eb8eStimh uint64_t flags, dmu_tx_t *tx) 774fa9e4066Sahrens { 7753cb34c60Sahrens dsl_pool_t *dp = dd->dd_pool; 776fa9e4066Sahrens dmu_buf_t *dbuf; 777fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 7783cb34c60Sahrens uint64_t dsobj; 779fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 780fa9e4066Sahrens 781088f3894Sahrens if (origin == NULL) 782088f3894Sahrens origin = dp->dp_origin_snap; 783088f3894Sahrens 7843cb34c60Sahrens ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp); 7853cb34c60Sahrens ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0); 786fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 7873cb34c60Sahrens ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); 788fa9e4066Sahrens 7891649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 7901649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 791ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 792fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 793fa9e4066Sahrens dsphys = dbuf->db_data; 794745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 795fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 796ab04eb8eStimh dsphys->ds_flags = flags; 797fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 798fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 799fa9e4066Sahrens sizeof (dsphys->ds_guid)); 800fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 801ab04eb8eStimh zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP, 802ab04eb8eStimh DMU_OT_NONE, 0, tx); 803fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 804088f3894Sahrens dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg; 805a9799022Sck 806cde58dbcSMatthew Ahrens if (origin == NULL) { 807cde58dbcSMatthew Ahrens dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx); 808cde58dbcSMatthew Ahrens } else { 809cde58dbcSMatthew Ahrens dsl_dataset_t *ohds; 810cde58dbcSMatthew Ahrens 8113cb34c60Sahrens dsphys->ds_prev_snap_obj = origin->ds_object; 812fa9e4066Sahrens dsphys->ds_prev_snap_txg = 8133cb34c60Sahrens origin->ds_phys->ds_creation_txg; 814fa9e4066Sahrens dsphys->ds_used_bytes = 8153cb34c60Sahrens origin->ds_phys->ds_used_bytes; 816fa9e4066Sahrens dsphys->ds_compressed_bytes = 8173cb34c60Sahrens origin->ds_phys->ds_compressed_bytes; 818fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 8193cb34c60Sahrens origin->ds_phys->ds_uncompressed_bytes; 8203cb34c60Sahrens dsphys->ds_bp = origin->ds_phys->ds_bp; 821579ae4d5Stimh dsphys->ds_flags |= origin->ds_phys->ds_flags; 822fa9e4066Sahrens 8233cb34c60Sahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 8243cb34c60Sahrens origin->ds_phys->ds_num_children++; 825fa9e4066Sahrens 826cde58dbcSMatthew Ahrens VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 827cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ohds)); 828cde58dbcSMatthew Ahrens dsphys->ds_deadlist_obj = dsl_deadlist_clone(&ohds->ds_deadlist, 829cde58dbcSMatthew Ahrens dsphys->ds_prev_snap_txg, dsphys->ds_prev_snap_obj, tx); 830cde58dbcSMatthew Ahrens dsl_dataset_rele(ohds, FTAG); 831cde58dbcSMatthew Ahrens 832088f3894Sahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) { 833088f3894Sahrens if (origin->ds_phys->ds_next_clones_obj == 0) { 834088f3894Sahrens origin->ds_phys->ds_next_clones_obj = 835088f3894Sahrens zap_create(mos, 836088f3894Sahrens DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx); 837088f3894Sahrens } 838088f3894Sahrens VERIFY(0 == zap_add_int(mos, 839088f3894Sahrens origin->ds_phys->ds_next_clones_obj, 840088f3894Sahrens dsobj, tx)); 841088f3894Sahrens } 842088f3894Sahrens 843fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 8443cb34c60Sahrens dd->dd_phys->dd_origin_obj = origin->ds_object; 845cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 846cde58dbcSMatthew Ahrens if (origin->ds_dir->dd_phys->dd_clones == 0) { 847cde58dbcSMatthew Ahrens dmu_buf_will_dirty(origin->ds_dir->dd_dbuf, tx); 848cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_clones = 849cde58dbcSMatthew Ahrens zap_create(mos, 850cde58dbcSMatthew Ahrens DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx); 851cde58dbcSMatthew Ahrens } 852cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_add_int(mos, 853cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_clones, dsobj, tx)); 854cde58dbcSMatthew Ahrens } 855fa9e4066Sahrens } 856ab04eb8eStimh 857ab04eb8eStimh if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 858ab04eb8eStimh dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 859ab04eb8eStimh 860ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 861fa9e4066Sahrens 862fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 863fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 8643cb34c60Sahrens 8653cb34c60Sahrens return (dsobj); 8663cb34c60Sahrens } 8673cb34c60Sahrens 8683cb34c60Sahrens uint64_t 869ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname, 870ab04eb8eStimh dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx) 8713cb34c60Sahrens { 8723cb34c60Sahrens dsl_pool_t *dp = pdd->dd_pool; 8733cb34c60Sahrens uint64_t dsobj, ddobj; 8743cb34c60Sahrens dsl_dir_t *dd; 8753cb34c60Sahrens 8763cb34c60Sahrens ASSERT(lastname[0] != '@'); 8773cb34c60Sahrens 878088f3894Sahrens ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx); 8793cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 8803cb34c60Sahrens 881088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx); 8823cb34c60Sahrens 8833cb34c60Sahrens dsl_deleg_set_create_perms(dd, tx, cr); 8843cb34c60Sahrens 885fa9e4066Sahrens dsl_dir_close(dd, FTAG); 886fa9e4066Sahrens 887feaa74e4SMark Maybee /* 888feaa74e4SMark Maybee * If we are creating a clone, make sure we zero out any stale 889feaa74e4SMark Maybee * data from the origin snapshots zil header. 890feaa74e4SMark Maybee */ 891feaa74e4SMark Maybee if (origin != NULL) { 892feaa74e4SMark Maybee dsl_dataset_t *ds; 893feaa74e4SMark Maybee objset_t *os; 894feaa74e4SMark Maybee 895feaa74e4SMark Maybee VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds)); 896feaa74e4SMark Maybee VERIFY3U(0, ==, dmu_objset_from_ds(ds, &os)); 897feaa74e4SMark Maybee bzero(&os->os_zil_header, sizeof (os->os_zil_header)); 898feaa74e4SMark Maybee dsl_dataset_dirty(ds, tx); 899feaa74e4SMark Maybee dsl_dataset_rele(ds, FTAG); 900feaa74e4SMark Maybee } 901feaa74e4SMark Maybee 9021d452cf5Sahrens return (dsobj); 903fa9e4066Sahrens } 904fa9e4066Sahrens 9051d452cf5Sahrens /* 906*19b94df9SMatthew Ahrens * The snapshots must all be in the same pool. 9071d452cf5Sahrens */ 9081d452cf5Sahrens int 909*19b94df9SMatthew Ahrens dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed) 9101d452cf5Sahrens { 9111d452cf5Sahrens int err; 9121d452cf5Sahrens dsl_sync_task_t *dst; 9131d452cf5Sahrens spa_t *spa; 914*19b94df9SMatthew Ahrens nvpair_t *pair; 915*19b94df9SMatthew Ahrens dsl_sync_task_group_t *dstg; 916e5351341SMatthew Ahrens 917*19b94df9SMatthew Ahrens pair = nvlist_next_nvpair(snaps, NULL); 918*19b94df9SMatthew Ahrens if (pair == NULL) 919*19b94df9SMatthew Ahrens return (0); 920*19b94df9SMatthew Ahrens 921*19b94df9SMatthew Ahrens err = spa_open(nvpair_name(pair), &spa, FTAG); 9221d452cf5Sahrens if (err) 9231d452cf5Sahrens return (err); 924*19b94df9SMatthew Ahrens dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 9251d452cf5Sahrens 926*19b94df9SMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 927*19b94df9SMatthew Ahrens pair = nvlist_next_nvpair(snaps, pair)) { 928*19b94df9SMatthew Ahrens dsl_dataset_t *ds; 929*19b94df9SMatthew Ahrens int err; 930*19b94df9SMatthew Ahrens 931*19b94df9SMatthew Ahrens err = dsl_dataset_own(nvpair_name(pair), B_TRUE, dstg, &ds); 932*19b94df9SMatthew Ahrens if (err == 0) { 933*19b94df9SMatthew Ahrens struct dsl_ds_destroyarg *dsda; 934*19b94df9SMatthew Ahrens 935*19b94df9SMatthew Ahrens dsl_dataset_make_exclusive(ds, dstg); 936*19b94df9SMatthew Ahrens dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), 937*19b94df9SMatthew Ahrens KM_SLEEP); 938*19b94df9SMatthew Ahrens dsda->ds = ds; 939*19b94df9SMatthew Ahrens dsda->defer = defer; 940*19b94df9SMatthew Ahrens dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 941*19b94df9SMatthew Ahrens dsl_dataset_destroy_sync, dsda, dstg, 0); 942*19b94df9SMatthew Ahrens } else if (err == ENOENT) { 943*19b94df9SMatthew Ahrens err = 0; 944*19b94df9SMatthew Ahrens } else { 945*19b94df9SMatthew Ahrens (void) strcpy(failed, nvpair_name(pair)); 946*19b94df9SMatthew Ahrens break; 947*19b94df9SMatthew Ahrens } 948*19b94df9SMatthew Ahrens } 9491d452cf5Sahrens 9501d452cf5Sahrens if (err == 0) 951*19b94df9SMatthew Ahrens err = dsl_sync_task_group_wait(dstg); 9521d452cf5Sahrens 953*19b94df9SMatthew Ahrens for (dst = list_head(&dstg->dstg_tasks); dst; 954*19b94df9SMatthew Ahrens dst = list_next(&dstg->dstg_tasks, dst)) { 955842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 956842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 957842727c2SChris Kirby 958745cd3c5Smaybee /* 959745cd3c5Smaybee * Return the file system name that triggered the error 960745cd3c5Smaybee */ 9611d452cf5Sahrens if (dst->dst_err) { 962*19b94df9SMatthew Ahrens dsl_dataset_name(ds, failed); 963e1930233Sbonwick } 964842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 965*19b94df9SMatthew Ahrens dsl_dataset_disown(ds, dstg); 966842727c2SChris Kirby kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 967fa9e4066Sahrens } 968fa9e4066Sahrens 969*19b94df9SMatthew Ahrens dsl_sync_task_group_destroy(dstg); 9701d452cf5Sahrens spa_close(spa, FTAG); 971fa9e4066Sahrens return (err); 972*19b94df9SMatthew Ahrens 973fa9e4066Sahrens } 974fa9e4066Sahrens 975842727c2SChris Kirby static boolean_t 976842727c2SChris Kirby dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 977842727c2SChris Kirby { 978842727c2SChris Kirby boolean_t might_destroy = B_FALSE; 979842727c2SChris Kirby 980842727c2SChris Kirby mutex_enter(&ds->ds_lock); 981842727c2SChris Kirby if (ds->ds_phys->ds_num_children == 2 && ds->ds_userrefs == 0 && 982842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 983842727c2SChris Kirby might_destroy = B_TRUE; 984842727c2SChris Kirby mutex_exit(&ds->ds_lock); 985842727c2SChris Kirby 986842727c2SChris Kirby return (might_destroy); 987842727c2SChris Kirby } 988842727c2SChris Kirby 989842727c2SChris Kirby /* 990842727c2SChris Kirby * If we're removing a clone, and these three conditions are true: 991842727c2SChris Kirby * 1) the clone's origin has no other children 992842727c2SChris Kirby * 2) the clone's origin has no user references 993842727c2SChris Kirby * 3) the clone's origin has been marked for deferred destruction 994842727c2SChris Kirby * Then, prepare to remove the origin as part of this sync task group. 995842727c2SChris Kirby */ 996842727c2SChris Kirby static int 997842727c2SChris Kirby dsl_dataset_origin_rm_prep(struct dsl_ds_destroyarg *dsda, void *tag) 998842727c2SChris Kirby { 999842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1000842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 1001842727c2SChris Kirby 1002842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(origin)) { 1003842727c2SChris Kirby char *name; 1004842727c2SChris Kirby int namelen; 1005842727c2SChris Kirby int error; 1006842727c2SChris Kirby 1007842727c2SChris Kirby namelen = dsl_dataset_namelen(origin) + 1; 1008842727c2SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 1009842727c2SChris Kirby dsl_dataset_name(origin, name); 1010842727c2SChris Kirby #ifdef _KERNEL 1011842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 1012842727c2SChris Kirby if (error) { 1013842727c2SChris Kirby kmem_free(name, namelen); 1014842727c2SChris Kirby return (error); 1015842727c2SChris Kirby } 1016842727c2SChris Kirby #endif 1017503ad85cSMatthew Ahrens error = dsl_dataset_own(name, B_TRUE, tag, &origin); 1018842727c2SChris Kirby kmem_free(name, namelen); 1019842727c2SChris Kirby if (error) 1020842727c2SChris Kirby return (error); 1021842727c2SChris Kirby dsda->rm_origin = origin; 1022842727c2SChris Kirby dsl_dataset_make_exclusive(origin, tag); 1023842727c2SChris Kirby } 1024842727c2SChris Kirby 1025842727c2SChris Kirby return (0); 1026842727c2SChris Kirby } 1027842727c2SChris Kirby 10283cb34c60Sahrens /* 1029745cd3c5Smaybee * ds must be opened as OWNER. On return (whether successful or not), 1030745cd3c5Smaybee * ds will be closed and caller can no longer dereference it. 10313cb34c60Sahrens */ 1032fa9e4066Sahrens int 1033842727c2SChris Kirby dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) 1034fa9e4066Sahrens { 1035fa9e4066Sahrens int err; 10361d452cf5Sahrens dsl_sync_task_group_t *dstg; 10371d452cf5Sahrens objset_t *os; 1038fa9e4066Sahrens dsl_dir_t *dd; 10391d452cf5Sahrens uint64_t obj; 104092241e0bSTom Erickson struct dsl_ds_destroyarg dsda = { 0 }; 104192241e0bSTom Erickson dsl_dataset_t dummy_ds = { 0 }; 1042842727c2SChris Kirby 1043842727c2SChris Kirby dsda.ds = ds; 10441d452cf5Sahrens 10453cb34c60Sahrens if (dsl_dataset_is_snapshot(ds)) { 10461d452cf5Sahrens /* Destroying a snapshot is simpler */ 1047745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 10483baa08fcSek 1049842727c2SChris Kirby dsda.defer = defer; 10501d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 10511d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 1052842727c2SChris Kirby &dsda, tag, 0); 1053842727c2SChris Kirby ASSERT3P(dsda.rm_origin, ==, NULL); 10543cb34c60Sahrens goto out; 1055922d9a97SChris Kirby } else if (defer) { 1056922d9a97SChris Kirby err = EINVAL; 1057922d9a97SChris Kirby goto out; 10581d452cf5Sahrens } 1059fa9e4066Sahrens 10601d452cf5Sahrens dd = ds->ds_dir; 106192241e0bSTom Erickson dummy_ds.ds_dir = dd; 106292241e0bSTom Erickson dummy_ds.ds_object = ds->ds_object; 1063fa9e4066Sahrens 10641d452cf5Sahrens /* 10651d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 10661d452cf5Sahrens * case we crash while freeing the objects. 10671d452cf5Sahrens */ 10681d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 10691d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 10703cb34c60Sahrens if (err) 10713cb34c60Sahrens goto out; 10723cb34c60Sahrens 1073503ad85cSMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 10743cb34c60Sahrens if (err) 10753cb34c60Sahrens goto out; 1076fa9e4066Sahrens 10771d452cf5Sahrens /* 10781d452cf5Sahrens * remove the objects in open context, so that we won't 10791d452cf5Sahrens * have too much to do in syncing context. 10801d452cf5Sahrens */ 10816754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 10826754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 1083cdb0ab79Smaybee /* 1084cdb0ab79Smaybee * Ignore errors, if there is not enough disk space 1085cdb0ab79Smaybee * we will deal with it in dsl_dataset_destroy_sync(). 1086cdb0ab79Smaybee */ 1087cdb0ab79Smaybee (void) dmu_free_object(os, obj); 10881d452cf5Sahrens } 1089feaa74e4SMark Maybee if (err != ESRCH) 1090feaa74e4SMark Maybee goto out; 10911d452cf5Sahrens 109214843421SMatthew Ahrens /* 1093feaa74e4SMark Maybee * Only the ZIL knows how to free log blocks. 1094feaa74e4SMark Maybee */ 1095feaa74e4SMark Maybee zil_destroy(dmu_objset_zil(os), B_FALSE); 1096feaa74e4SMark Maybee 1097feaa74e4SMark Maybee /* 1098feaa74e4SMark Maybee * Sync out all in-flight IO. 109914843421SMatthew Ahrens */ 110014843421SMatthew Ahrens txg_wait_synced(dd->dd_pool, 0); 110114843421SMatthew Ahrens 110214843421SMatthew Ahrens /* 110314843421SMatthew Ahrens * If we managed to free all the objects in open 110414843421SMatthew Ahrens * context, the user space accounting should be zero. 110514843421SMatthew Ahrens */ 110614843421SMatthew Ahrens if (ds->ds_phys->ds_bp.blk_fill == 0 && 1107503ad85cSMatthew Ahrens dmu_objset_userused_enabled(os)) { 110814843421SMatthew Ahrens uint64_t count; 110914843421SMatthew Ahrens 111014843421SMatthew Ahrens ASSERT(zap_count(os, DMU_USERUSED_OBJECT, &count) != 0 || 111114843421SMatthew Ahrens count == 0); 111214843421SMatthew Ahrens ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, &count) != 0 || 111314843421SMatthew Ahrens count == 0); 111414843421SMatthew Ahrens } 111514843421SMatthew Ahrens 111668038c2cSmaybee rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 111768038c2cSmaybee err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd); 111868038c2cSmaybee rw_exit(&dd->dd_pool->dp_config_rwlock); 111968038c2cSmaybee 112068038c2cSmaybee if (err) 112168038c2cSmaybee goto out; 112268038c2cSmaybee 11231d452cf5Sahrens /* 11241d452cf5Sahrens * Blow away the dsl_dir + head dataset. 11251d452cf5Sahrens */ 1126745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 1127842727c2SChris Kirby /* 1128842727c2SChris Kirby * If we're removing a clone, we might also need to remove its 1129842727c2SChris Kirby * origin. 1130842727c2SChris Kirby */ 1131842727c2SChris Kirby do { 1132842727c2SChris Kirby dsda.need_prep = B_FALSE; 1133842727c2SChris Kirby if (dsl_dir_is_clone(dd)) { 1134842727c2SChris Kirby err = dsl_dataset_origin_rm_prep(&dsda, tag); 1135842727c2SChris Kirby if (err) { 1136842727c2SChris Kirby dsl_dir_close(dd, FTAG); 1137842727c2SChris Kirby goto out; 1138842727c2SChris Kirby } 1139842727c2SChris Kirby } 1140842727c2SChris Kirby 1141842727c2SChris Kirby dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 1142842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 1143842727c2SChris Kirby dsl_dataset_destroy_sync, &dsda, tag, 0); 1144842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dir_destroy_check, 114592241e0bSTom Erickson dsl_dir_destroy_sync, &dummy_ds, FTAG, 0); 1146842727c2SChris Kirby err = dsl_sync_task_group_wait(dstg); 1147842727c2SChris Kirby dsl_sync_task_group_destroy(dstg); 1148842727c2SChris Kirby 1149842727c2SChris Kirby /* 1150842727c2SChris Kirby * We could be racing against 'zfs release' or 'zfs destroy -d' 1151842727c2SChris Kirby * on the origin snap, in which case we can get EBUSY if we 1152842727c2SChris Kirby * needed to destroy the origin snap but were not ready to 1153842727c2SChris Kirby * do so. 1154842727c2SChris Kirby */ 1155842727c2SChris Kirby if (dsda.need_prep) { 1156842727c2SChris Kirby ASSERT(err == EBUSY); 1157842727c2SChris Kirby ASSERT(dsl_dir_is_clone(dd)); 1158842727c2SChris Kirby ASSERT(dsda.rm_origin == NULL); 1159842727c2SChris Kirby } 1160842727c2SChris Kirby } while (dsda.need_prep); 1161842727c2SChris Kirby 1162842727c2SChris Kirby if (dsda.rm_origin != NULL) 1163842727c2SChris Kirby dsl_dataset_disown(dsda.rm_origin, tag); 1164842727c2SChris Kirby 1165745cd3c5Smaybee /* if it is successful, dsl_dir_destroy_sync will close the dd */ 11663cb34c60Sahrens if (err) 11671d452cf5Sahrens dsl_dir_close(dd, FTAG); 11683cb34c60Sahrens out: 1169745cd3c5Smaybee dsl_dataset_disown(ds, tag); 1170fa9e4066Sahrens return (err); 1171fa9e4066Sahrens } 1172fa9e4066Sahrens 1173c717a561Smaybee blkptr_t * 1174c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 1175fa9e4066Sahrens { 1176c717a561Smaybee return (&ds->ds_phys->ds_bp); 1177fa9e4066Sahrens } 1178fa9e4066Sahrens 1179fa9e4066Sahrens void 1180fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 1181fa9e4066Sahrens { 1182fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1183fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 1184fa9e4066Sahrens if (ds == NULL) { 1185fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 1186fa9e4066Sahrens } else { 1187fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1188fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 1189fa9e4066Sahrens } 1190fa9e4066Sahrens } 1191fa9e4066Sahrens 1192fa9e4066Sahrens spa_t * 1193fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 1194fa9e4066Sahrens { 1195fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 1196fa9e4066Sahrens } 1197fa9e4066Sahrens 1198fa9e4066Sahrens void 1199fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 1200fa9e4066Sahrens { 1201fa9e4066Sahrens dsl_pool_t *dp; 1202fa9e4066Sahrens 1203fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 1204fa9e4066Sahrens return; 1205fa9e4066Sahrens 1206503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1207a2eea2e1Sahrens 1208a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1209a2eea2e1Sahrens panic("dirtying snapshot!"); 1210fa9e4066Sahrens 1211fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 1212fa9e4066Sahrens 1213fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 1214fa9e4066Sahrens /* up the hold count until we can be written out */ 1215fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 1216fa9e4066Sahrens } 1217fa9e4066Sahrens } 1218fa9e4066Sahrens 1219a9799022Sck /* 1220a9799022Sck * The unique space in the head dataset can be calculated by subtracting 1221a9799022Sck * the space used in the most recent snapshot, that is still being used 1222a9799022Sck * in this file system, from the space currently in use. To figure out 1223a9799022Sck * the space in the most recent snapshot still in use, we need to take 1224a9799022Sck * the total space used in the snapshot and subtract out the space that 1225a9799022Sck * has been freed up since the snapshot was taken. 1226a9799022Sck */ 1227a9799022Sck static void 1228a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds) 1229a9799022Sck { 1230a9799022Sck uint64_t mrs_used; 1231a9799022Sck uint64_t dlused, dlcomp, dluncomp; 1232a9799022Sck 12333f9d6ad7SLin Ling ASSERT(!dsl_dataset_is_snapshot(ds)); 1234a9799022Sck 1235a9799022Sck if (ds->ds_phys->ds_prev_snap_obj != 0) 1236a9799022Sck mrs_used = ds->ds_prev->ds_phys->ds_used_bytes; 1237a9799022Sck else 1238a9799022Sck mrs_used = 0; 1239a9799022Sck 1240cde58dbcSMatthew Ahrens dsl_deadlist_space(&ds->ds_deadlist, &dlused, &dlcomp, &dluncomp); 1241a9799022Sck 1242a9799022Sck ASSERT3U(dlused, <=, mrs_used); 1243a9799022Sck ds->ds_phys->ds_unique_bytes = 1244a9799022Sck ds->ds_phys->ds_used_bytes - (mrs_used - dlused); 1245a9799022Sck 12463f9d6ad7SLin Ling if (spa_version(ds->ds_dir->dd_pool->dp_spa) >= 1247a9799022Sck SPA_VERSION_UNIQUE_ACCURATE) 1248a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1249a9799022Sck } 1250a9799022Sck 1251fa9e4066Sahrens struct killarg { 125274e7dc98SMatthew Ahrens dsl_dataset_t *ds; 1253fa9e4066Sahrens dmu_tx_t *tx; 1254fa9e4066Sahrens }; 1255fa9e4066Sahrens 125674e7dc98SMatthew Ahrens /* ARGSUSED */ 1257fa9e4066Sahrens static int 12583f9d6ad7SLin Ling kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf, 1259b24ab676SJeff Bonwick const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg) 1260fa9e4066Sahrens { 1261fa9e4066Sahrens struct killarg *ka = arg; 1262b24ab676SJeff Bonwick dmu_tx_t *tx = ka->tx; 1263fa9e4066Sahrens 126488b7b0f2SMatthew Ahrens if (bp == NULL) 126588b7b0f2SMatthew Ahrens return (0); 1266fa9e4066Sahrens 1267b24ab676SJeff Bonwick if (zb->zb_level == ZB_ZIL_LEVEL) { 1268b24ab676SJeff Bonwick ASSERT(zilog != NULL); 1269ab69d62fSMatthew Ahrens /* 1270ab69d62fSMatthew Ahrens * It's a block in the intent log. It has no 1271ab69d62fSMatthew Ahrens * accounting, so just free it. 1272ab69d62fSMatthew Ahrens */ 1273b24ab676SJeff Bonwick dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp); 1274ab69d62fSMatthew Ahrens } else { 1275b24ab676SJeff Bonwick ASSERT(zilog == NULL); 1276ab69d62fSMatthew Ahrens ASSERT3U(bp->blk_birth, >, ka->ds->ds_phys->ds_prev_snap_txg); 1277b24ab676SJeff Bonwick (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE); 1278ab69d62fSMatthew Ahrens } 127974e7dc98SMatthew Ahrens 1280fa9e4066Sahrens return (0); 1281fa9e4066Sahrens } 1282fa9e4066Sahrens 1283e1930233Sbonwick /* ARGSUSED */ 1284e1930233Sbonwick static int 12851d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1286e1930233Sbonwick { 12871d452cf5Sahrens dsl_dataset_t *ds = arg1; 12883cb34c60Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 12893cb34c60Sahrens uint64_t count; 12903cb34c60Sahrens int err; 1291e1930233Sbonwick 1292e1930233Sbonwick /* 1293e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1294e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1295e1930233Sbonwick * from.) 1296e1930233Sbonwick */ 1297e1930233Sbonwick if (ds->ds_prev != NULL && 1298e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 12994aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic return (EBUSY); 1300e1930233Sbonwick 13013cb34c60Sahrens /* 13023cb34c60Sahrens * This is really a dsl_dir thing, but check it here so that 13033cb34c60Sahrens * we'll be less likely to leave this dataset inconsistent & 13043cb34c60Sahrens * nearly destroyed. 13053cb34c60Sahrens */ 13063cb34c60Sahrens err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count); 13073cb34c60Sahrens if (err) 13083cb34c60Sahrens return (err); 13093cb34c60Sahrens if (count != 0) 13103cb34c60Sahrens return (EEXIST); 13113cb34c60Sahrens 1312e1930233Sbonwick return (0); 1313e1930233Sbonwick } 1314e1930233Sbonwick 13151d452cf5Sahrens /* ARGSUSED */ 13161d452cf5Sahrens static void 13173f9d6ad7SLin Ling dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1318fa9e4066Sahrens { 13191d452cf5Sahrens dsl_dataset_t *ds = arg1; 1320ecd6cf80Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1321fa9e4066Sahrens 13221d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 13231d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 13241d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1325ecd6cf80Smarks 13263f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 13273f9d6ad7SLin Ling "dataset = %llu", ds->ds_object); 13281d452cf5Sahrens } 1329fa9e4066Sahrens 1330842727c2SChris Kirby static int 1331842727c2SChris Kirby dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag, 1332842727c2SChris Kirby dmu_tx_t *tx) 1333842727c2SChris Kirby { 1334842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1335842727c2SChris Kirby dsl_dataset_t *ds_prev = ds->ds_prev; 1336842727c2SChris Kirby 1337842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(ds_prev)) { 1338842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1339842727c2SChris Kirby 1340842727c2SChris Kirby /* 1341842727c2SChris Kirby * If we're not prepared to remove the origin, don't remove 1342842727c2SChris Kirby * the clone either. 1343842727c2SChris Kirby */ 1344842727c2SChris Kirby if (dsda->rm_origin == NULL) { 1345842727c2SChris Kirby dsda->need_prep = B_TRUE; 1346842727c2SChris Kirby return (EBUSY); 1347842727c2SChris Kirby } 1348842727c2SChris Kirby 1349842727c2SChris Kirby ndsda.ds = ds_prev; 1350842727c2SChris Kirby ndsda.is_origin_rm = B_TRUE; 1351842727c2SChris Kirby return (dsl_dataset_destroy_check(&ndsda, tag, tx)); 1352842727c2SChris Kirby } 1353842727c2SChris Kirby 1354842727c2SChris Kirby /* 1355842727c2SChris Kirby * If we're not going to remove the origin after all, 1356842727c2SChris Kirby * undo the open context setup. 1357842727c2SChris Kirby */ 1358842727c2SChris Kirby if (dsda->rm_origin != NULL) { 1359842727c2SChris Kirby dsl_dataset_disown(dsda->rm_origin, tag); 1360842727c2SChris Kirby dsda->rm_origin = NULL; 1361842727c2SChris Kirby } 1362842727c2SChris Kirby 1363842727c2SChris Kirby return (0); 1364842727c2SChris Kirby } 1365842727c2SChris Kirby 136699d5e173STim Haley /* 136799d5e173STim Haley * If you add new checks here, you may need to add 136899d5e173STim Haley * additional checks to the "temporary" case in 136999d5e173STim Haley * snapshot_check() in dmu_objset.c. 137099d5e173STim Haley */ 13711d452cf5Sahrens /* ARGSUSED */ 13723cb34c60Sahrens int 13731d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 13741d452cf5Sahrens { 1375842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1376842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1377fa9e4066Sahrens 1378745cd3c5Smaybee /* we have an owner hold, so noone else can destroy us */ 1379745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 1380745cd3c5Smaybee 1381842727c2SChris Kirby /* 1382842727c2SChris Kirby * Only allow deferred destroy on pools that support it. 1383842727c2SChris Kirby * NOTE: deferred destroy is only supported on snapshots. 1384842727c2SChris Kirby */ 1385842727c2SChris Kirby if (dsda->defer) { 1386842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 1387842727c2SChris Kirby SPA_VERSION_USERREFS) 1388842727c2SChris Kirby return (ENOTSUP); 1389842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 1390842727c2SChris Kirby return (0); 1391842727c2SChris Kirby } 1392fa9e4066Sahrens 1393fa9e4066Sahrens /* 1394fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1395fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1396fa9e4066Sahrens * from.) 1397fa9e4066Sahrens */ 1398fa9e4066Sahrens if (ds->ds_prev != NULL && 13991d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 14004aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic return (EBUSY); 1401fa9e4066Sahrens 1402fa9e4066Sahrens /* 1403fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1404fa9e4066Sahrens * them. Try again. 1405fa9e4066Sahrens */ 14061d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1407fa9e4066Sahrens return (EAGAIN); 14081d452cf5Sahrens 1409842727c2SChris Kirby if (dsl_dataset_is_snapshot(ds)) { 1410842727c2SChris Kirby /* 1411842727c2SChris Kirby * If this snapshot has an elevated user reference count, 1412842727c2SChris Kirby * we can't destroy it yet. 1413842727c2SChris Kirby */ 1414842727c2SChris Kirby if (ds->ds_userrefs > 0 && !dsda->releasing) 1415842727c2SChris Kirby return (EBUSY); 1416842727c2SChris Kirby 1417842727c2SChris Kirby mutex_enter(&ds->ds_lock); 1418842727c2SChris Kirby /* 1419842727c2SChris Kirby * Can't delete a branch point. However, if we're destroying 1420842727c2SChris Kirby * a clone and removing its origin due to it having a user 1421842727c2SChris Kirby * hold count of 0 and having been marked for deferred destroy, 1422842727c2SChris Kirby * it's OK for the origin to have a single clone. 1423842727c2SChris Kirby */ 1424842727c2SChris Kirby if (ds->ds_phys->ds_num_children > 1425842727c2SChris Kirby (dsda->is_origin_rm ? 2 : 1)) { 1426842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1427842727c2SChris Kirby return (EEXIST); 1428842727c2SChris Kirby } 1429842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1430842727c2SChris Kirby } else if (dsl_dir_is_clone(ds->ds_dir)) { 1431842727c2SChris Kirby return (dsl_dataset_origin_check(dsda, arg2, tx)); 1432842727c2SChris Kirby } 1433842727c2SChris Kirby 14341d452cf5Sahrens /* XXX we should do some i/o error checking... */ 14351d452cf5Sahrens return (0); 14361d452cf5Sahrens } 14371d452cf5Sahrens 1438745cd3c5Smaybee struct refsarg { 1439745cd3c5Smaybee kmutex_t lock; 1440745cd3c5Smaybee boolean_t gone; 1441745cd3c5Smaybee kcondvar_t cv; 1442745cd3c5Smaybee }; 1443745cd3c5Smaybee 1444745cd3c5Smaybee /* ARGSUSED */ 1445745cd3c5Smaybee static void 1446745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv) 1447745cd3c5Smaybee { 1448745cd3c5Smaybee struct refsarg *arg = argv; 1449745cd3c5Smaybee 1450745cd3c5Smaybee mutex_enter(&arg->lock); 1451745cd3c5Smaybee arg->gone = TRUE; 1452745cd3c5Smaybee cv_signal(&arg->cv); 1453745cd3c5Smaybee mutex_exit(&arg->lock); 1454745cd3c5Smaybee } 1455745cd3c5Smaybee 1456745cd3c5Smaybee static void 1457745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag) 1458745cd3c5Smaybee { 1459745cd3c5Smaybee struct refsarg arg; 1460745cd3c5Smaybee 1461745cd3c5Smaybee mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL); 1462745cd3c5Smaybee cv_init(&arg.cv, NULL, CV_DEFAULT, NULL); 1463745cd3c5Smaybee arg.gone = FALSE; 1464745cd3c5Smaybee (void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys, 1465745cd3c5Smaybee dsl_dataset_refs_gone); 1466745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 1467745cd3c5Smaybee mutex_enter(&arg.lock); 1468745cd3c5Smaybee while (!arg.gone) 1469745cd3c5Smaybee cv_wait(&arg.cv, &arg.lock); 1470745cd3c5Smaybee ASSERT(arg.gone); 1471745cd3c5Smaybee mutex_exit(&arg.lock); 1472745cd3c5Smaybee ds->ds_dbuf = NULL; 1473745cd3c5Smaybee ds->ds_phys = NULL; 1474745cd3c5Smaybee mutex_destroy(&arg.lock); 1475745cd3c5Smaybee cv_destroy(&arg.cv); 1476745cd3c5Smaybee } 1477745cd3c5Smaybee 1478c33e334fSMatthew Ahrens static void 1479c33e334fSMatthew Ahrens remove_from_next_clones(dsl_dataset_t *ds, uint64_t obj, dmu_tx_t *tx) 1480c33e334fSMatthew Ahrens { 1481c33e334fSMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1482c33e334fSMatthew Ahrens uint64_t count; 1483c33e334fSMatthew Ahrens int err; 1484c33e334fSMatthew Ahrens 1485c33e334fSMatthew Ahrens ASSERT(ds->ds_phys->ds_num_children >= 2); 1486c33e334fSMatthew Ahrens err = zap_remove_int(mos, ds->ds_phys->ds_next_clones_obj, obj, tx); 1487c33e334fSMatthew Ahrens /* 1488c33e334fSMatthew Ahrens * The err should not be ENOENT, but a bug in a previous version 1489c33e334fSMatthew Ahrens * of the code could cause upgrade_clones_cb() to not set 1490c33e334fSMatthew Ahrens * ds_next_snap_obj when it should, leading to a missing entry. 1491c33e334fSMatthew Ahrens * If we knew that the pool was created after 1492c33e334fSMatthew Ahrens * SPA_VERSION_NEXT_CLONES, we could assert that it isn't 1493c33e334fSMatthew Ahrens * ENOENT. However, at least we can check that we don't have 1494c33e334fSMatthew Ahrens * too many entries in the next_clones_obj even after failing to 1495c33e334fSMatthew Ahrens * remove this one. 1496c33e334fSMatthew Ahrens */ 1497c33e334fSMatthew Ahrens if (err != ENOENT) { 1498c33e334fSMatthew Ahrens VERIFY3U(err, ==, 0); 1499c33e334fSMatthew Ahrens } 1500c33e334fSMatthew Ahrens ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj, 1501c33e334fSMatthew Ahrens &count)); 1502c33e334fSMatthew Ahrens ASSERT3U(count, <=, ds->ds_phys->ds_num_children - 2); 1503c33e334fSMatthew Ahrens } 1504c33e334fSMatthew Ahrens 1505cde58dbcSMatthew Ahrens static void 1506cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx) 1507cde58dbcSMatthew Ahrens { 1508cde58dbcSMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1509cde58dbcSMatthew Ahrens zap_cursor_t zc; 1510cde58dbcSMatthew Ahrens zap_attribute_t za; 1511cde58dbcSMatthew Ahrens 1512cde58dbcSMatthew Ahrens /* 1513cde58dbcSMatthew Ahrens * If it is the old version, dd_clones doesn't exist so we can't 1514cde58dbcSMatthew Ahrens * find the clones, but deadlist_remove_key() is a no-op so it 1515cde58dbcSMatthew Ahrens * doesn't matter. 1516cde58dbcSMatthew Ahrens */ 1517cde58dbcSMatthew Ahrens if (ds->ds_dir->dd_phys->dd_clones == 0) 1518cde58dbcSMatthew Ahrens return; 1519cde58dbcSMatthew Ahrens 1520cde58dbcSMatthew Ahrens for (zap_cursor_init(&zc, mos, ds->ds_dir->dd_phys->dd_clones); 1521cde58dbcSMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 1522cde58dbcSMatthew Ahrens zap_cursor_advance(&zc)) { 1523cde58dbcSMatthew Ahrens dsl_dataset_t *clone; 1524cde58dbcSMatthew Ahrens 1525cde58dbcSMatthew Ahrens VERIFY3U(0, ==, dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 1526cde58dbcSMatthew Ahrens za.za_first_integer, FTAG, &clone)); 1527cde58dbcSMatthew Ahrens if (clone->ds_dir->dd_origin_txg > mintxg) { 1528cde58dbcSMatthew Ahrens dsl_deadlist_remove_key(&clone->ds_deadlist, 1529cde58dbcSMatthew Ahrens mintxg, tx); 1530cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(clone, mintxg, tx); 1531cde58dbcSMatthew Ahrens } 1532cde58dbcSMatthew Ahrens dsl_dataset_rele(clone, FTAG); 1533cde58dbcSMatthew Ahrens } 1534cde58dbcSMatthew Ahrens zap_cursor_fini(&zc); 1535cde58dbcSMatthew Ahrens } 1536cde58dbcSMatthew Ahrens 1537cde58dbcSMatthew Ahrens struct process_old_arg { 1538cde58dbcSMatthew Ahrens dsl_dataset_t *ds; 1539cde58dbcSMatthew Ahrens dsl_dataset_t *ds_prev; 1540cde58dbcSMatthew Ahrens boolean_t after_branch_point; 1541cde58dbcSMatthew Ahrens zio_t *pio; 1542cde58dbcSMatthew Ahrens uint64_t used, comp, uncomp; 1543cde58dbcSMatthew Ahrens }; 1544cde58dbcSMatthew Ahrens 1545cde58dbcSMatthew Ahrens static int 1546cde58dbcSMatthew Ahrens process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx) 1547cde58dbcSMatthew Ahrens { 1548cde58dbcSMatthew Ahrens struct process_old_arg *poa = arg; 1549cde58dbcSMatthew Ahrens dsl_pool_t *dp = poa->ds->ds_dir->dd_pool; 1550cde58dbcSMatthew Ahrens 1551cde58dbcSMatthew Ahrens if (bp->blk_birth <= poa->ds->ds_phys->ds_prev_snap_txg) { 1552cde58dbcSMatthew Ahrens dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx); 1553cde58dbcSMatthew Ahrens if (poa->ds_prev && !poa->after_branch_point && 1554cde58dbcSMatthew Ahrens bp->blk_birth > 1555cde58dbcSMatthew Ahrens poa->ds_prev->ds_phys->ds_prev_snap_txg) { 1556cde58dbcSMatthew Ahrens poa->ds_prev->ds_phys->ds_unique_bytes += 1557cde58dbcSMatthew Ahrens bp_get_dsize_sync(dp->dp_spa, bp); 1558cde58dbcSMatthew Ahrens } 1559cde58dbcSMatthew Ahrens } else { 1560cde58dbcSMatthew Ahrens poa->used += bp_get_dsize_sync(dp->dp_spa, bp); 1561cde58dbcSMatthew Ahrens poa->comp += BP_GET_PSIZE(bp); 1562cde58dbcSMatthew Ahrens poa->uncomp += BP_GET_UCSIZE(bp); 1563cde58dbcSMatthew Ahrens dsl_free_sync(poa->pio, dp, tx->tx_txg, bp); 1564cde58dbcSMatthew Ahrens } 1565cde58dbcSMatthew Ahrens return (0); 1566cde58dbcSMatthew Ahrens } 1567cde58dbcSMatthew Ahrens 1568cde58dbcSMatthew Ahrens static void 1569cde58dbcSMatthew Ahrens process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev, 1570cde58dbcSMatthew Ahrens dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx) 1571cde58dbcSMatthew Ahrens { 1572cde58dbcSMatthew Ahrens struct process_old_arg poa = { 0 }; 1573cde58dbcSMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 1574cde58dbcSMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 1575cde58dbcSMatthew Ahrens 1576cde58dbcSMatthew Ahrens ASSERT(ds->ds_deadlist.dl_oldfmt); 1577cde58dbcSMatthew Ahrens ASSERT(ds_next->ds_deadlist.dl_oldfmt); 1578cde58dbcSMatthew Ahrens 1579cde58dbcSMatthew Ahrens poa.ds = ds; 1580cde58dbcSMatthew Ahrens poa.ds_prev = ds_prev; 1581cde58dbcSMatthew Ahrens poa.after_branch_point = after_branch_point; 1582cde58dbcSMatthew Ahrens poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1583cde58dbcSMatthew Ahrens VERIFY3U(0, ==, bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj, 1584cde58dbcSMatthew Ahrens process_old_cb, &poa, tx)); 1585cde58dbcSMatthew Ahrens VERIFY3U(zio_wait(poa.pio), ==, 0); 1586cde58dbcSMatthew Ahrens ASSERT3U(poa.used, ==, ds->ds_phys->ds_unique_bytes); 1587cde58dbcSMatthew Ahrens 1588cde58dbcSMatthew Ahrens /* change snapused */ 1589cde58dbcSMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 1590cde58dbcSMatthew Ahrens -poa.used, -poa.comp, -poa.uncomp, tx); 1591cde58dbcSMatthew Ahrens 1592cde58dbcSMatthew Ahrens /* swap next's deadlist to our deadlist */ 1593cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1594cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds_next->ds_deadlist); 1595cde58dbcSMatthew Ahrens SWITCH64(ds_next->ds_phys->ds_deadlist_obj, 1596cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj); 1597cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, mos, ds->ds_phys->ds_deadlist_obj); 1598cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds_next->ds_deadlist, mos, 1599cde58dbcSMatthew Ahrens ds_next->ds_phys->ds_deadlist_obj); 1600cde58dbcSMatthew Ahrens } 1601cde58dbcSMatthew Ahrens 16023cb34c60Sahrens void 16033f9d6ad7SLin Ling dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) 16041d452cf5Sahrens { 1605842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1606842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 16071d452cf5Sahrens int err; 16081d452cf5Sahrens int after_branch_point = FALSE; 16091d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 16101d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 16111d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 161299d5e173STim Haley boolean_t wont_destroy; 16131d452cf5Sahrens uint64_t obj; 16141d452cf5Sahrens 161599d5e173STim Haley wont_destroy = (dsda->defer && 161699d5e173STim Haley (ds->ds_userrefs > 0 || ds->ds_phys->ds_num_children > 1)); 161799d5e173STim Haley 161899d5e173STim Haley ASSERT(ds->ds_owner || wont_destroy); 1619842727c2SChris Kirby ASSERT(dsda->defer || ds->ds_phys->ds_num_children <= 1); 16201d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 16211d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 16221d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 16231d452cf5Sahrens 162499d5e173STim Haley if (wont_destroy) { 1625842727c2SChris Kirby ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 162699d5e173STim Haley dmu_buf_will_dirty(ds->ds_dbuf, tx); 162799d5e173STim Haley ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY; 162899d5e173STim Haley return; 1629842727c2SChris Kirby } 1630842727c2SChris Kirby 1631745cd3c5Smaybee /* signal any waiters that this dataset is going away */ 1632745cd3c5Smaybee mutex_enter(&ds->ds_lock); 1633745cd3c5Smaybee ds->ds_owner = dsl_reaper; 1634745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 1635745cd3c5Smaybee mutex_exit(&ds->ds_lock); 1636745cd3c5Smaybee 1637a9799022Sck /* Remove our reservation */ 1638a9799022Sck if (ds->ds_reserved != 0) { 163992241e0bSTom Erickson dsl_prop_setarg_t psa; 164092241e0bSTom Erickson uint64_t value = 0; 164192241e0bSTom Erickson 164292241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refreservation", 164392241e0bSTom Erickson (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), 164492241e0bSTom Erickson &value); 164592241e0bSTom Erickson psa.psa_effective_value = 0; /* predict default value */ 164692241e0bSTom Erickson 16473f9d6ad7SLin Ling dsl_dataset_set_reservation_sync(ds, &psa, tx); 1648a9799022Sck ASSERT3U(ds->ds_reserved, ==, 0); 1649a9799022Sck } 1650a9799022Sck 16511d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 16521d452cf5Sahrens 16533f9d6ad7SLin Ling dsl_scan_ds_destroyed(ds, tx); 1654088f3894Sahrens 16551d452cf5Sahrens obj = ds->ds_object; 1656fa9e4066Sahrens 1657fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1658fa9e4066Sahrens if (ds->ds_prev) { 1659fa9e4066Sahrens ds_prev = ds->ds_prev; 1660fa9e4066Sahrens } else { 1661745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1662745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev)); 1663fa9e4066Sahrens } 1664fa9e4066Sahrens after_branch_point = 1665fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1666fa9e4066Sahrens 1667fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1668088f3894Sahrens if (after_branch_point && 1669088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj != 0) { 1670c33e334fSMatthew Ahrens remove_from_next_clones(ds_prev, obj, tx); 1671088f3894Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1672088f3894Sahrens VERIFY(0 == zap_add_int(mos, 1673088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, 1674088f3894Sahrens ds->ds_phys->ds_next_snap_obj, tx)); 1675088f3894Sahrens } 1676088f3894Sahrens } 1677fa9e4066Sahrens if (after_branch_point && 1678fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1679fa9e4066Sahrens /* This clone is toast. */ 1680fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1681fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1682842727c2SChris Kirby 1683842727c2SChris Kirby /* 1684842727c2SChris Kirby * If the clone's origin has no other clones, no 1685842727c2SChris Kirby * user holds, and has been marked for deferred 1686842727c2SChris Kirby * deletion, then we should have done the necessary 1687842727c2SChris Kirby * destroy setup for it. 1688842727c2SChris Kirby */ 1689842727c2SChris Kirby if (ds_prev->ds_phys->ds_num_children == 1 && 1690842727c2SChris Kirby ds_prev->ds_userrefs == 0 && 1691842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds_prev)) { 1692842727c2SChris Kirby ASSERT3P(dsda->rm_origin, !=, NULL); 1693842727c2SChris Kirby } else { 1694842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 1695842727c2SChris Kirby } 1696fa9e4066Sahrens } else if (!after_branch_point) { 1697fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1698fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1699fa9e4066Sahrens } 1700fa9e4066Sahrens } 1701fa9e4066Sahrens 17023f9d6ad7SLin Ling if (dsl_dataset_is_snapshot(ds)) { 1703fa9e4066Sahrens dsl_dataset_t *ds_next; 1704a9799022Sck uint64_t old_unique; 1705cde58dbcSMatthew Ahrens uint64_t used = 0, comp = 0, uncomp = 0; 1706fa9e4066Sahrens 1707745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1708745cd3c5Smaybee ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next)); 1709fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1710fa9e4066Sahrens 17113f9d6ad7SLin Ling old_unique = ds_next->ds_phys->ds_unique_bytes; 1712a9799022Sck 1713fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1714fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1715fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1716fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1717fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1718fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1719fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1720fa9e4066Sahrens 17213113f7ceSGeorge Wilson 1722cde58dbcSMatthew Ahrens if (ds_next->ds_deadlist.dl_oldfmt) { 1723cde58dbcSMatthew Ahrens process_old_deadlist(ds, ds_prev, ds_next, 1724cde58dbcSMatthew Ahrens after_branch_point, tx); 1725cde58dbcSMatthew Ahrens } else { 1726cde58dbcSMatthew Ahrens /* Adjust prev's unique space. */ 1727cde58dbcSMatthew Ahrens if (ds_prev && !after_branch_point) { 1728cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 1729cde58dbcSMatthew Ahrens ds_prev->ds_phys->ds_prev_snap_txg, 1730cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 1731cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1732cde58dbcSMatthew Ahrens ds_prev->ds_phys->ds_unique_bytes += used; 1733fa9e4066Sahrens } 173474e7dc98SMatthew Ahrens 1735cde58dbcSMatthew Ahrens /* Adjust snapused. */ 1736cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 1737cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, 1738cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1739cde58dbcSMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 1740cde58dbcSMatthew Ahrens -used, -comp, -uncomp, tx); 1741cde58dbcSMatthew Ahrens 1742cde58dbcSMatthew Ahrens /* Move blocks to be freed to pool's free list. */ 1743cde58dbcSMatthew Ahrens dsl_deadlist_move_bpobj(&ds_next->ds_deadlist, 1744cde58dbcSMatthew Ahrens &dp->dp_free_bpobj, ds->ds_phys->ds_prev_snap_txg, 1745cde58dbcSMatthew Ahrens tx); 1746cde58dbcSMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, 1747cde58dbcSMatthew Ahrens DD_USED_HEAD, used, comp, uncomp, tx); 1748cde58dbcSMatthew Ahrens dsl_dir_dirty(tx->tx_pool->dp_free_dir, tx); 1749cde58dbcSMatthew Ahrens 1750cde58dbcSMatthew Ahrens /* Merge our deadlist into next's and free it. */ 1751cde58dbcSMatthew Ahrens dsl_deadlist_merge(&ds_next->ds_deadlist, 1752cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj, tx); 1753cde58dbcSMatthew Ahrens } 1754cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1755cde58dbcSMatthew Ahrens dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx); 1756fa9e4066Sahrens 1757cde58dbcSMatthew Ahrens /* Collapse range in clone heads */ 1758cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(ds, 1759cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, tx); 1760fa9e4066Sahrens 17613f9d6ad7SLin Ling if (dsl_dataset_is_snapshot(ds_next)) { 1762cde58dbcSMatthew Ahrens dsl_dataset_t *ds_nextnext; 1763cde58dbcSMatthew Ahrens 1764fa9e4066Sahrens /* 1765fa9e4066Sahrens * Update next's unique to include blocks which 1766fa9e4066Sahrens * were previously shared by only this snapshot 1767fa9e4066Sahrens * and it. Those blocks will be born after the 1768fa9e4066Sahrens * prev snap and before this snap, and will have 1769fa9e4066Sahrens * died after the next snap and before the one 1770fa9e4066Sahrens * after that (ie. be on the snap after next's 1771fa9e4066Sahrens * deadlist). 1772fa9e4066Sahrens */ 1773745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1774745cd3c5Smaybee ds_next->ds_phys->ds_next_snap_obj, 1775cde58dbcSMatthew Ahrens FTAG, &ds_nextnext)); 1776cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_nextnext->ds_deadlist, 177774e7dc98SMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 1778cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, 1779cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1780cde58dbcSMatthew Ahrens ds_next->ds_phys->ds_unique_bytes += used; 1781cde58dbcSMatthew Ahrens dsl_dataset_rele(ds_nextnext, FTAG); 1782fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1783cde58dbcSMatthew Ahrens 1784cde58dbcSMatthew Ahrens /* Collapse range in this head. */ 1785cde58dbcSMatthew Ahrens dsl_dataset_t *hds; 1786cde58dbcSMatthew Ahrens VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 1787cde58dbcSMatthew Ahrens ds->ds_dir->dd_phys->dd_head_dataset_obj, 1788cde58dbcSMatthew Ahrens FTAG, &hds)); 1789cde58dbcSMatthew Ahrens dsl_deadlist_remove_key(&hds->ds_deadlist, 1790cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, tx); 1791cde58dbcSMatthew Ahrens dsl_dataset_rele(hds, FTAG); 1792cde58dbcSMatthew Ahrens 1793fa9e4066Sahrens } else { 1794fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1795745cd3c5Smaybee dsl_dataset_drop_ref(ds_next->ds_prev, ds_next); 1796745cd3c5Smaybee ds_next->ds_prev = NULL; 1797fa9e4066Sahrens if (ds_prev) { 1798745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1799745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 1800745cd3c5Smaybee ds_next, &ds_next->ds_prev)); 1801fa9e4066Sahrens } 1802a9799022Sck 1803a9799022Sck dsl_dataset_recalc_head_uniq(ds_next); 1804a9799022Sck 1805a9799022Sck /* 1806a9799022Sck * Reduce the amount of our unconsmed refreservation 1807a9799022Sck * being charged to our parent by the amount of 1808a9799022Sck * new unique data we have gained. 1809a9799022Sck */ 1810a9799022Sck if (old_unique < ds_next->ds_reserved) { 1811a9799022Sck int64_t mrsdelta; 1812a9799022Sck uint64_t new_unique = 1813a9799022Sck ds_next->ds_phys->ds_unique_bytes; 1814a9799022Sck 1815a9799022Sck ASSERT(old_unique <= new_unique); 1816a9799022Sck mrsdelta = MIN(new_unique - old_unique, 1817a9799022Sck ds_next->ds_reserved - old_unique); 181874e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 181974e7dc98SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 1820a9799022Sck } 1821fa9e4066Sahrens } 1822745cd3c5Smaybee dsl_dataset_rele(ds_next, FTAG); 1823fa9e4066Sahrens } else { 1824fa9e4066Sahrens /* 1825fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1826fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1827fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1828fa9e4066Sahrens * safe to ignore the deadlist contents.) 1829fa9e4066Sahrens */ 1830fa9e4066Sahrens struct killarg ka; 1831fa9e4066Sahrens 1832cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1833cde58dbcSMatthew Ahrens dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx); 1834fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1835fa9e4066Sahrens 1836fa9e4066Sahrens /* 1837fa9e4066Sahrens * Free everything that we point to (that's born after 1838fa9e4066Sahrens * the previous snapshot, if we are a clone) 1839fa9e4066Sahrens * 184074e7dc98SMatthew Ahrens * NB: this should be very quick, because we already 184174e7dc98SMatthew Ahrens * freed all the objects in open context. 1842fa9e4066Sahrens */ 184374e7dc98SMatthew Ahrens ka.ds = ds; 1844fa9e4066Sahrens ka.tx = tx; 184588b7b0f2SMatthew Ahrens err = traverse_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 184688b7b0f2SMatthew Ahrens TRAVERSE_POST, kill_blkptr, &ka); 1847fa9e4066Sahrens ASSERT3U(err, ==, 0); 18483e78c5fbSChris Kirby ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 184974e7dc98SMatthew Ahrens ds->ds_phys->ds_unique_bytes == 0); 1850ca45db41SChris Kirby 1851ca45db41SChris Kirby if (ds->ds_prev != NULL) { 1852cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 1853cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(mos, 1854cde58dbcSMatthew Ahrens ds->ds_prev->ds_dir->dd_phys->dd_clones, 1855cde58dbcSMatthew Ahrens ds->ds_object, tx)); 1856cde58dbcSMatthew Ahrens } 1857ca45db41SChris Kirby dsl_dataset_rele(ds->ds_prev, ds); 1858ca45db41SChris Kirby ds->ds_prev = ds_prev = NULL; 1859ca45db41SChris Kirby } 1860fa9e4066Sahrens } 1861fa9e4066Sahrens 18626e0cbcaaSMatthew Ahrens /* 18636e0cbcaaSMatthew Ahrens * This must be done after the dsl_traverse(), because it will 18646e0cbcaaSMatthew Ahrens * re-open the objset. 18656e0cbcaaSMatthew Ahrens */ 18666e0cbcaaSMatthew Ahrens if (ds->ds_objset) { 18676e0cbcaaSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 18686e0cbcaaSMatthew Ahrens ds->ds_objset = NULL; 18696e0cbcaaSMatthew Ahrens } 18706e0cbcaaSMatthew Ahrens 18711d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1872745cd3c5Smaybee /* Erase the link in the dir */ 18731d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 18741d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1875745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0); 1876745cd3c5Smaybee err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1877745cd3c5Smaybee ASSERT(err == 0); 1878fa9e4066Sahrens } else { 1879fa9e4066Sahrens /* remove from snapshot namespace */ 1880fa9e4066Sahrens dsl_dataset_t *ds_head; 1881745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0); 1882745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1883745cd3c5Smaybee ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head)); 18848660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1885fa9e4066Sahrens #ifdef ZFS_DEBUG 1886fa9e4066Sahrens { 1887fa9e4066Sahrens uint64_t val; 1888ab04eb8eStimh 1889745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds_head, 1890ab04eb8eStimh ds->ds_snapname, &val); 1891fa9e4066Sahrens ASSERT3U(err, ==, 0); 1892fa9e4066Sahrens ASSERT3U(val, ==, obj); 1893fa9e4066Sahrens } 1894fa9e4066Sahrens #endif 1895745cd3c5Smaybee err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx); 1896fa9e4066Sahrens ASSERT(err == 0); 1897745cd3c5Smaybee dsl_dataset_rele(ds_head, FTAG); 1898fa9e4066Sahrens } 1899fa9e4066Sahrens 1900fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1901745cd3c5Smaybee dsl_dataset_rele(ds_prev, FTAG); 1902fa9e4066Sahrens 1903990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 19043f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_DESTROY, dp->dp_spa, tx, 19053f9d6ad7SLin Ling "dataset = %llu", ds->ds_object); 1906ecd6cf80Smarks 1907088f3894Sahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 1908088f3894Sahrens uint64_t count; 1909088f3894Sahrens ASSERT(0 == zap_count(mos, 1910088f3894Sahrens ds->ds_phys->ds_next_clones_obj, &count) && count == 0); 1911088f3894Sahrens VERIFY(0 == dmu_object_free(mos, 1912088f3894Sahrens ds->ds_phys->ds_next_clones_obj, tx)); 1913088f3894Sahrens } 191474e7dc98SMatthew Ahrens if (ds->ds_phys->ds_props_obj != 0) 191574e7dc98SMatthew Ahrens VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_props_obj, tx)); 1916842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) 1917842727c2SChris Kirby VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx)); 1918745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 1919745cd3c5Smaybee ds->ds_dir = NULL; 1920745cd3c5Smaybee dsl_dataset_drain_refs(ds, tag); 19211d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1922842727c2SChris Kirby 1923842727c2SChris Kirby if (dsda->rm_origin) { 1924842727c2SChris Kirby /* 1925842727c2SChris Kirby * Remove the origin of the clone we just destroyed. 1926842727c2SChris Kirby */ 1927842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1928842727c2SChris Kirby 1929ca45db41SChris Kirby ndsda.ds = dsda->rm_origin; 19303f9d6ad7SLin Ling dsl_dataset_destroy_sync(&ndsda, tag, tx); 1931842727c2SChris Kirby } 1932fa9e4066Sahrens } 1933fa9e4066Sahrens 1934a9799022Sck static int 1935a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx) 1936a9799022Sck { 1937a9799022Sck uint64_t asize; 1938a9799022Sck 1939a9799022Sck if (!dmu_tx_is_syncing(tx)) 1940a9799022Sck return (0); 1941a9799022Sck 1942a9799022Sck /* 1943a9799022Sck * If there's an fs-only reservation, any blocks that might become 1944a9799022Sck * owned by the snapshot dataset must be accommodated by space 1945a9799022Sck * outside of the reservation. 1946a9799022Sck */ 19473f9d6ad7SLin Ling ASSERT(ds->ds_reserved == 0 || DS_UNIQUE_IS_ACCURATE(ds)); 19483f9d6ad7SLin Ling asize = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 19496e0cbcaaSMatthew Ahrens if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 1950a9799022Sck return (ENOSPC); 1951a9799022Sck 1952a9799022Sck /* 1953a9799022Sck * Propogate any reserved space for this snapshot to other 1954a9799022Sck * snapshot checks in this sync group. 1955a9799022Sck */ 1956a9799022Sck if (asize > 0) 1957a9799022Sck dsl_dir_willuse_space(ds->ds_dir, asize, tx); 1958a9799022Sck 1959a9799022Sck return (0); 1960a9799022Sck } 1961a9799022Sck 1962fa9e4066Sahrens int 19631d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1964fa9e4066Sahrens { 19653cb34c60Sahrens dsl_dataset_t *ds = arg1; 19661d452cf5Sahrens const char *snapname = arg2; 1967fa9e4066Sahrens int err; 19681d452cf5Sahrens uint64_t value; 1969fa9e4066Sahrens 19701d452cf5Sahrens /* 19711d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 19721d452cf5Sahrens * is already one, try again. 19731d452cf5Sahrens */ 19741d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 19751d452cf5Sahrens return (EAGAIN); 1976fa9e4066Sahrens 19771d452cf5Sahrens /* 19781d452cf5Sahrens * Check for conflicting name snapshot name. 19791d452cf5Sahrens */ 1980745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds, snapname, &value); 19811d452cf5Sahrens if (err == 0) 1982fa9e4066Sahrens return (EEXIST); 19831d452cf5Sahrens if (err != ENOENT) 19841d452cf5Sahrens return (err); 1985fa9e4066Sahrens 1986b7661cccSmmusante /* 1987b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 1988b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 1989b7661cccSmmusante */ 1990b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 1991b7661cccSmmusante return (ENAMETOOLONG); 1992b7661cccSmmusante 1993a9799022Sck err = dsl_dataset_snapshot_reserve_space(ds, tx); 1994a9799022Sck if (err) 1995a9799022Sck return (err); 1996a9799022Sck 19971d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 19981d452cf5Sahrens return (0); 19991d452cf5Sahrens } 2000fa9e4066Sahrens 20011d452cf5Sahrens void 20023f9d6ad7SLin Ling dsl_dataset_snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx) 20031d452cf5Sahrens { 20043cb34c60Sahrens dsl_dataset_t *ds = arg1; 20051d452cf5Sahrens const char *snapname = arg2; 20061d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 20071d452cf5Sahrens dmu_buf_t *dbuf; 20081d452cf5Sahrens dsl_dataset_phys_t *dsphys; 2009088f3894Sahrens uint64_t dsobj, crtxg; 20101d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 20111d452cf5Sahrens int err; 2012fa9e4066Sahrens 20131d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 2014fa9e4066Sahrens 2015088f3894Sahrens /* 2016088f3894Sahrens * The origin's ds_creation_txg has to be < TXG_INITIAL 2017088f3894Sahrens */ 2018088f3894Sahrens if (strcmp(snapname, ORIGIN_DIR_NAME) == 0) 2019088f3894Sahrens crtxg = 1; 2020088f3894Sahrens else 2021088f3894Sahrens crtxg = tx->tx_txg; 2022088f3894Sahrens 20231649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 20241649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 2025ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 2026fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 2027fa9e4066Sahrens dsphys = dbuf->db_data; 2028745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 20291d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 2030fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 2031fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 2032fa9e4066Sahrens sizeof (dsphys->ds_guid)); 2033fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 2034fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 2035fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 2036fa9e4066Sahrens dsphys->ds_num_children = 1; 2037fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 2038088f3894Sahrens dsphys->ds_creation_txg = crtxg; 2039fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 2040fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 2041fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 2042fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 204399653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 2044fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 2045ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 2046fa9e4066Sahrens 20471d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 20481d452cf5Sahrens if (ds->ds_prev) { 2049088f3894Sahrens uint64_t next_clones_obj = 2050088f3894Sahrens ds->ds_prev->ds_phys->ds_next_clones_obj; 20511d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 2052fa9e4066Sahrens ds->ds_object || 20531d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 20541d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 20551d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 2056fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 20571d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 20581d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 2059088f3894Sahrens } else if (next_clones_obj != 0) { 2060c33e334fSMatthew Ahrens remove_from_next_clones(ds->ds_prev, 2061c33e334fSMatthew Ahrens dsphys->ds_next_snap_obj, tx); 2062088f3894Sahrens VERIFY3U(0, ==, zap_add_int(mos, 2063088f3894Sahrens next_clones_obj, dsobj, tx)); 2064fa9e4066Sahrens } 2065fa9e4066Sahrens } 2066fa9e4066Sahrens 2067a9799022Sck /* 2068a9799022Sck * If we have a reference-reservation on this dataset, we will 2069a9799022Sck * need to increase the amount of refreservation being charged 2070a9799022Sck * since our unique space is going to zero. 2071a9799022Sck */ 2072a9799022Sck if (ds->ds_reserved) { 20733f9d6ad7SLin Ling int64_t delta; 20743f9d6ad7SLin Ling ASSERT(DS_UNIQUE_IS_ACCURATE(ds)); 20753f9d6ad7SLin Ling delta = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 207674e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, 20773f9d6ad7SLin Ling delta, 0, 0, tx); 2078a9799022Sck } 2079a9799022Sck 2080fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 2081cde58dbcSMatthew Ahrens zfs_dbgmsg("taking snapshot %s@%s/%llu; newkey=%llu", 2082cde58dbcSMatthew Ahrens ds->ds_dir->dd_myname, snapname, dsobj, 2083cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg); 2084cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj = dsl_deadlist_clone(&ds->ds_deadlist, 2085cde58dbcSMatthew Ahrens UINT64_MAX, ds->ds_phys->ds_prev_snap_obj, tx); 2086cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 2087cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, mos, ds->ds_phys->ds_deadlist_obj); 2088cde58dbcSMatthew Ahrens dsl_deadlist_add_key(&ds->ds_deadlist, 2089cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, tx); 2090cde58dbcSMatthew Ahrens 2091a4611edeSahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg); 2092fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 2093088f3894Sahrens ds->ds_phys->ds_prev_snap_txg = crtxg; 2094fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 2095a9799022Sck if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 2096a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 2097fa9e4066Sahrens 2098fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 2099fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 2100fa9e4066Sahrens ASSERT(err == 0); 2101fa9e4066Sahrens 2102fa9e4066Sahrens if (ds->ds_prev) 2103745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 2104745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 2105745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev)); 2106ecd6cf80Smarks 21073f9d6ad7SLin Ling dsl_scan_ds_snapshotted(ds, tx); 2108088f3894Sahrens 210971eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 211071eb0538SChris Kirby 21113f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_SNAPSHOT, dp->dp_spa, tx, 211240feaa91Sahrens "dataset = %llu", dsobj); 2113fa9e4066Sahrens } 2114fa9e4066Sahrens 2115fa9e4066Sahrens void 2116c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 2117fa9e4066Sahrens { 2118fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 2119503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 2120fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 2121fa9e4066Sahrens 212291ebeef5Sahrens /* 212391ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 212491ebeef5Sahrens * sync it out now. 212591ebeef5Sahrens */ 212691ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 212791ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 212891ebeef5Sahrens 2129fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 2130503ad85cSMatthew Ahrens dmu_objset_sync(ds->ds_objset, zio, tx); 2131fa9e4066Sahrens } 2132fa9e4066Sahrens 2133*19b94df9SMatthew Ahrens static void 2134*19b94df9SMatthew Ahrens get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv) 2135*19b94df9SMatthew Ahrens { 2136*19b94df9SMatthew Ahrens uint64_t count = 0; 2137*19b94df9SMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 2138*19b94df9SMatthew Ahrens zap_cursor_t zc; 2139*19b94df9SMatthew Ahrens zap_attribute_t za; 2140*19b94df9SMatthew Ahrens nvlist_t *propval; 2141*19b94df9SMatthew Ahrens nvlist_t *val; 2142*19b94df9SMatthew Ahrens 2143*19b94df9SMatthew Ahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 2144*19b94df9SMatthew Ahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2145*19b94df9SMatthew Ahrens VERIFY(nvlist_alloc(&val, NV_UNIQUE_NAME, KM_SLEEP) == 0); 2146*19b94df9SMatthew Ahrens 2147*19b94df9SMatthew Ahrens /* 2148*19b94df9SMatthew Ahrens * There may me missing entries in ds_next_clones_obj 2149*19b94df9SMatthew Ahrens * due to a bug in a previous version of the code. 2150*19b94df9SMatthew Ahrens * Only trust it if it has the right number of entries. 2151*19b94df9SMatthew Ahrens */ 2152*19b94df9SMatthew Ahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 2153*19b94df9SMatthew Ahrens ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj, 2154*19b94df9SMatthew Ahrens &count)); 2155*19b94df9SMatthew Ahrens } 2156*19b94df9SMatthew Ahrens if (count != ds->ds_phys->ds_num_children - 1) { 2157*19b94df9SMatthew Ahrens goto fail; 2158*19b94df9SMatthew Ahrens } 2159*19b94df9SMatthew Ahrens for (zap_cursor_init(&zc, mos, ds->ds_phys->ds_next_clones_obj); 2160*19b94df9SMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 2161*19b94df9SMatthew Ahrens zap_cursor_advance(&zc)) { 2162*19b94df9SMatthew Ahrens dsl_dataset_t *clone; 2163*19b94df9SMatthew Ahrens char buf[ZFS_MAXNAMELEN]; 2164*19b94df9SMatthew Ahrens if (dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 2165*19b94df9SMatthew Ahrens za.za_first_integer, FTAG, &clone) != 0) { 2166*19b94df9SMatthew Ahrens goto fail; 2167*19b94df9SMatthew Ahrens } 2168*19b94df9SMatthew Ahrens dsl_dir_name(clone->ds_dir, buf); 2169*19b94df9SMatthew Ahrens VERIFY(nvlist_add_boolean(val, buf) == 0); 2170*19b94df9SMatthew Ahrens dsl_dataset_rele(clone, FTAG); 2171*19b94df9SMatthew Ahrens } 2172*19b94df9SMatthew Ahrens zap_cursor_fini(&zc); 2173*19b94df9SMatthew Ahrens VERIFY(nvlist_add_nvlist(propval, ZPROP_VALUE, val) == 0); 2174*19b94df9SMatthew Ahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), 2175*19b94df9SMatthew Ahrens propval) == 0); 2176*19b94df9SMatthew Ahrens fail: 2177*19b94df9SMatthew Ahrens nvlist_free(val); 2178*19b94df9SMatthew Ahrens nvlist_free(propval); 2179*19b94df9SMatthew Ahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2180*19b94df9SMatthew Ahrens } 2181*19b94df9SMatthew Ahrens 2182fa9e4066Sahrens void 2183a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 2184fa9e4066Sahrens { 2185187d6ac0SMatt Ahrens uint64_t refd, avail, uobjs, aobjs, ratio; 2186a9799022Sck 2187a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 2188fa9e4066Sahrens 2189a9799022Sck dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); 2190a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); 2191a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); 2192a9799022Sck 2193a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 2194a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 2195a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 2196a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 2197a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, 2198a9799022Sck ds->ds_quota); 2199a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, 2200a9799022Sck ds->ds_reserved); 2201c5904d13Seschrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, 2202c5904d13Seschrock ds->ds_phys->ds_guid); 22031d713200SEric Schrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE, 22043f9d6ad7SLin Ling ds->ds_phys->ds_unique_bytes); 22051d713200SEric Schrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID, 22061d713200SEric Schrock ds->ds_object); 220792241e0bSTom Erickson dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, 220892241e0bSTom Erickson ds->ds_userrefs); 2209842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2210842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2211fa9e4066Sahrens 2212*19b94df9SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 2213*19b94df9SMatthew Ahrens uint64_t written, comp, uncomp; 2214*19b94df9SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 2215*19b94df9SMatthew Ahrens dsl_dataset_t *prev; 2216*19b94df9SMatthew Ahrens 2217*19b94df9SMatthew Ahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 2218*19b94df9SMatthew Ahrens int err = dsl_dataset_hold_obj(dp, 2219*19b94df9SMatthew Ahrens ds->ds_phys->ds_prev_snap_obj, FTAG, &prev); 2220*19b94df9SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 2221*19b94df9SMatthew Ahrens if (err == 0) { 2222*19b94df9SMatthew Ahrens err = dsl_dataset_space_written(prev, ds, &written, 2223*19b94df9SMatthew Ahrens &comp, &uncomp); 2224*19b94df9SMatthew Ahrens dsl_dataset_rele(prev, FTAG); 2225*19b94df9SMatthew Ahrens if (err == 0) { 2226*19b94df9SMatthew Ahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN, 2227*19b94df9SMatthew Ahrens written); 2228*19b94df9SMatthew Ahrens } 2229*19b94df9SMatthew Ahrens } 2230*19b94df9SMatthew Ahrens } 2231*19b94df9SMatthew Ahrens 2232187d6ac0SMatt Ahrens ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 2233187d6ac0SMatt Ahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 2234187d6ac0SMatt Ahrens ds->ds_phys->ds_compressed_bytes); 2235187d6ac0SMatt Ahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); 2236187d6ac0SMatt Ahrens 2237fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2238fa9e4066Sahrens /* 2239fa9e4066Sahrens * This is a snapshot; override the dd's space used with 2240a2eea2e1Sahrens * our unique space and compression ratio. 2241fa9e4066Sahrens */ 2242a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 2243a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 2244187d6ac0SMatt Ahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio); 2245*19b94df9SMatthew Ahrens 2246*19b94df9SMatthew Ahrens get_clones_stat(ds, nv); 2247fa9e4066Sahrens } 2248fa9e4066Sahrens } 2249fa9e4066Sahrens 2250a2eea2e1Sahrens void 2251a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2252a2eea2e1Sahrens { 2253a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2254a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 22553cb34c60Sahrens stat->dds_guid = ds->ds_phys->ds_guid; 2256a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2257a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 2258a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 2259ebedde84SEric Taylor } else { 2260ebedde84SEric Taylor stat->dds_is_snapshot = B_FALSE; 2261ebedde84SEric Taylor stat->dds_num_clones = 0; 2262a2eea2e1Sahrens } 2263a2eea2e1Sahrens 2264a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 22654ccbb6e7Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 2266088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 2267a2eea2e1Sahrens dsl_dataset_t *ods; 2268a2eea2e1Sahrens 2269745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool, 2270745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods)); 22713cb34c60Sahrens dsl_dataset_name(ods, stat->dds_origin); 2272745cd3c5Smaybee dsl_dataset_drop_ref(ods, FTAG); 2273ebedde84SEric Taylor } else { 2274ebedde84SEric Taylor stat->dds_origin[0] = '\0'; 2275a2eea2e1Sahrens } 22764ccbb6e7Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2277a2eea2e1Sahrens } 2278a2eea2e1Sahrens 2279a2eea2e1Sahrens uint64_t 2280a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 2281a2eea2e1Sahrens { 228291ebeef5Sahrens return (ds->ds_fsid_guid); 2283a2eea2e1Sahrens } 2284a2eea2e1Sahrens 2285a2eea2e1Sahrens void 2286a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 2287a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 2288a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 2289fa9e4066Sahrens { 2290a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 2291a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 2292a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) 2293a9799022Sck *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes; 2294a9799022Sck if (ds->ds_quota != 0) { 2295a9799022Sck /* 2296a9799022Sck * Adjust available bytes according to refquota 2297a9799022Sck */ 2298a9799022Sck if (*refdbytesp < ds->ds_quota) 2299a9799022Sck *availbytesp = MIN(*availbytesp, 2300a9799022Sck ds->ds_quota - *refdbytesp); 2301a9799022Sck else 2302a9799022Sck *availbytesp = 0; 2303a9799022Sck } 2304a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 2305a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 2306fa9e4066Sahrens } 2307fa9e4066Sahrens 2308f18faf3fSek boolean_t 2309f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 2310f18faf3fSek { 2311f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 2312f18faf3fSek 2313f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 2314f18faf3fSek dsl_pool_sync_context(dp)); 2315f18faf3fSek if (ds->ds_prev == NULL) 2316f18faf3fSek return (B_FALSE); 2317f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 23186e0cbcaaSMatthew Ahrens ds->ds_prev->ds_phys->ds_creation_txg) { 23196e0cbcaaSMatthew Ahrens objset_t *os, *os_prev; 23206e0cbcaaSMatthew Ahrens /* 23216e0cbcaaSMatthew Ahrens * It may be that only the ZIL differs, because it was 23226e0cbcaaSMatthew Ahrens * reset in the head. Don't count that as being 23236e0cbcaaSMatthew Ahrens * modified. 23246e0cbcaaSMatthew Ahrens */ 23256e0cbcaaSMatthew Ahrens if (dmu_objset_from_ds(ds, &os) != 0) 23266e0cbcaaSMatthew Ahrens return (B_TRUE); 23276e0cbcaaSMatthew Ahrens if (dmu_objset_from_ds(ds->ds_prev, &os_prev) != 0) 23286e0cbcaaSMatthew Ahrens return (B_TRUE); 23296e0cbcaaSMatthew Ahrens return (bcmp(&os->os_phys->os_meta_dnode, 23306e0cbcaaSMatthew Ahrens &os_prev->os_phys->os_meta_dnode, 23316e0cbcaaSMatthew Ahrens sizeof (os->os_phys->os_meta_dnode)) != 0); 23326e0cbcaaSMatthew Ahrens } 2333f18faf3fSek return (B_FALSE); 2334f18faf3fSek } 2335f18faf3fSek 23361d452cf5Sahrens /* ARGSUSED */ 2337fa9e4066Sahrens static int 23381d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 2339fa9e4066Sahrens { 23401d452cf5Sahrens dsl_dataset_t *ds = arg1; 23411d452cf5Sahrens char *newsnapname = arg2; 23421d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 23431d452cf5Sahrens dsl_dataset_t *hds; 2344fa9e4066Sahrens uint64_t val; 23451d452cf5Sahrens int err; 2346fa9e4066Sahrens 2347745cd3c5Smaybee err = dsl_dataset_hold_obj(dd->dd_pool, 2348745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds); 2349fa9e4066Sahrens if (err) 2350fa9e4066Sahrens return (err); 2351fa9e4066Sahrens 23521d452cf5Sahrens /* new name better not be in use */ 2353745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, newsnapname, &val); 2354745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 23551d452cf5Sahrens 23561d452cf5Sahrens if (err == 0) 23571d452cf5Sahrens err = EEXIST; 23581d452cf5Sahrens else if (err == ENOENT) 23591d452cf5Sahrens err = 0; 2360cdf5b4caSmmusante 2361cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 2362cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 2363cdf5b4caSmmusante err = ENAMETOOLONG; 2364cdf5b4caSmmusante 23651d452cf5Sahrens return (err); 23661d452cf5Sahrens } 2367fa9e4066Sahrens 23681d452cf5Sahrens static void 23693f9d6ad7SLin Ling dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx) 23701d452cf5Sahrens { 23711d452cf5Sahrens dsl_dataset_t *ds = arg1; 2372ecd6cf80Smarks const char *newsnapname = arg2; 23731d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 23741d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 23751d452cf5Sahrens dsl_dataset_t *hds; 23761d452cf5Sahrens int err; 2377fa9e4066Sahrens 23781d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 2379fa9e4066Sahrens 2380745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, 2381745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds)); 2382fa9e4066Sahrens 23831d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2384745cd3c5Smaybee err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx); 2385fa9e4066Sahrens ASSERT3U(err, ==, 0); 23861d452cf5Sahrens mutex_enter(&ds->ds_lock); 23871d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 23881d452cf5Sahrens mutex_exit(&ds->ds_lock); 23891d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 23901d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 2391fa9e4066Sahrens ASSERT3U(err, ==, 0); 2392fa9e4066Sahrens 23933f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 23943f9d6ad7SLin Ling "dataset = %llu", ds->ds_object); 2395745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 2396fa9e4066Sahrens } 2397fa9e4066Sahrens 2398f18faf3fSek struct renamesnaparg { 2399cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 2400cdf5b4caSmmusante char failed[MAXPATHLEN]; 2401cdf5b4caSmmusante char *oldsnap; 2402cdf5b4caSmmusante char *newsnap; 2403cdf5b4caSmmusante }; 2404cdf5b4caSmmusante 2405cdf5b4caSmmusante static int 2406fd136879SMatthew Ahrens dsl_snapshot_rename_one(const char *name, void *arg) 2407cdf5b4caSmmusante { 2408f18faf3fSek struct renamesnaparg *ra = arg; 2409cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 2410fd136879SMatthew Ahrens char *snapname; 2411cdf5b4caSmmusante int err; 2412cdf5b4caSmmusante 2413fd136879SMatthew Ahrens snapname = kmem_asprintf("%s@%s", name, ra->oldsnap); 2414fd136879SMatthew Ahrens (void) strlcpy(ra->failed, snapname, sizeof (ra->failed)); 2415ecd6cf80Smarks 2416ecd6cf80Smarks /* 2417ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 2418ecd6cf80Smarks * so we just pass name for both the to/from argument. 2419ecd6cf80Smarks */ 2420fd136879SMatthew Ahrens err = zfs_secpolicy_rename_perms(snapname, snapname, CRED()); 2421fd136879SMatthew Ahrens if (err != 0) { 2422fd136879SMatthew Ahrens strfree(snapname); 2423fd136879SMatthew Ahrens return (err == ENOENT ? 0 : err); 2424ecd6cf80Smarks } 2425ecd6cf80Smarks 2426745cd3c5Smaybee #ifdef _KERNEL 2427745cd3c5Smaybee /* 2428745cd3c5Smaybee * For all filesystems undergoing rename, we'll need to unmount it. 2429745cd3c5Smaybee */ 2430fd136879SMatthew Ahrens (void) zfs_unmount_snap(snapname, NULL); 2431745cd3c5Smaybee #endif 2432fd136879SMatthew Ahrens err = dsl_dataset_hold(snapname, ra->dstg, &ds); 24333f1f8012SMatthew Ahrens strfree(snapname); 24343f1f8012SMatthew Ahrens if (err != 0) 2435fd136879SMatthew Ahrens return (err == ENOENT ? 0 : err); 2436cdf5b4caSmmusante 2437cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 2438cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 2439cdf5b4caSmmusante 2440cdf5b4caSmmusante return (0); 2441cdf5b4caSmmusante } 2442cdf5b4caSmmusante 2443cdf5b4caSmmusante static int 2444cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 2445cdf5b4caSmmusante { 2446cdf5b4caSmmusante int err; 2447f18faf3fSek struct renamesnaparg *ra; 2448cdf5b4caSmmusante dsl_sync_task_t *dst; 2449cdf5b4caSmmusante spa_t *spa; 2450cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 2451fd136879SMatthew Ahrens int len = strlen(oldname) + 1; 2452cdf5b4caSmmusante 2453cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 2454cdf5b4caSmmusante cp = strchr(fsname, '@'); 2455cdf5b4caSmmusante *cp = '\0'; 2456cdf5b4caSmmusante 245740feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 2458cdf5b4caSmmusante if (err) { 2459fd136879SMatthew Ahrens kmem_free(fsname, len); 2460cdf5b4caSmmusante return (err); 2461cdf5b4caSmmusante } 2462f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 2463cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 2464cdf5b4caSmmusante 2465cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 2466cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 2467cdf5b4caSmmusante *ra->failed = '\0'; 2468cdf5b4caSmmusante 2469cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 2470cdf5b4caSmmusante DS_FIND_CHILDREN); 2471fd136879SMatthew Ahrens kmem_free(fsname, len); 2472cdf5b4caSmmusante 2473cdf5b4caSmmusante if (err == 0) { 2474cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 2475cdf5b4caSmmusante } 2476cdf5b4caSmmusante 2477cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 2478cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 2479cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 2480cdf5b4caSmmusante if (dst->dst_err) { 2481cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 2482fd136879SMatthew Ahrens (void) strlcat(ra->failed, "@", sizeof (ra->failed)); 2483fd136879SMatthew Ahrens (void) strlcat(ra->failed, ra->newsnap, 2484fd136879SMatthew Ahrens sizeof (ra->failed)); 2485cdf5b4caSmmusante } 2486745cd3c5Smaybee dsl_dataset_rele(ds, ra->dstg); 2487cdf5b4caSmmusante } 2488cdf5b4caSmmusante 2489ecd6cf80Smarks if (err) 2490fd136879SMatthew Ahrens (void) strlcpy(oldname, ra->failed, sizeof (ra->failed)); 2491cdf5b4caSmmusante 2492cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 2493f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 2494cdf5b4caSmmusante spa_close(spa, FTAG); 2495cdf5b4caSmmusante return (err); 2496cdf5b4caSmmusante } 2497cdf5b4caSmmusante 24983a5a36beSmmusante static int 2499fd136879SMatthew Ahrens dsl_valid_rename(const char *oldname, void *arg) 25003a5a36beSmmusante { 25013a5a36beSmmusante int delta = *(int *)arg; 25023a5a36beSmmusante 25033a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 25043a5a36beSmmusante return (ENAMETOOLONG); 25053a5a36beSmmusante 25063a5a36beSmmusante return (0); 25073a5a36beSmmusante } 25083a5a36beSmmusante 2509fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 2510fa9e4066Sahrens int 2511745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive) 2512fa9e4066Sahrens { 2513fa9e4066Sahrens dsl_dir_t *dd; 25141d452cf5Sahrens dsl_dataset_t *ds; 2515fa9e4066Sahrens const char *tail; 2516fa9e4066Sahrens int err; 2517fa9e4066Sahrens 25181d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 2519ea8dc4b6Seschrock if (err) 2520ea8dc4b6Seschrock return (err); 2521370c1af0SSanjeev Bagewadi 2522fa9e4066Sahrens if (tail == NULL) { 25233a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 25243a5a36beSmmusante 2525088f3894Sahrens /* if we're growing, validate child name lengths */ 25263a5a36beSmmusante if (delta > 0) 25273a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 25283a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 25293a5a36beSmmusante 2530b91a2f0bSMatthew Ahrens if (err == 0) 25313a5a36beSmmusante err = dsl_dir_rename(dd, newname); 2532fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2533fa9e4066Sahrens return (err); 2534fa9e4066Sahrens } 2535370c1af0SSanjeev Bagewadi 2536fa9e4066Sahrens if (tail[0] != '@') { 2537681d9761SEric Taylor /* the name ended in a nonexistent component */ 2538fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2539fa9e4066Sahrens return (ENOENT); 2540fa9e4066Sahrens } 2541fa9e4066Sahrens 2542fa9e4066Sahrens dsl_dir_close(dd, FTAG); 25431d452cf5Sahrens 25441d452cf5Sahrens /* new name must be snapshot in same filesystem */ 25451d452cf5Sahrens tail = strchr(newname, '@'); 25461d452cf5Sahrens if (tail == NULL) 25471d452cf5Sahrens return (EINVAL); 25481d452cf5Sahrens tail++; 25491d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 25501d452cf5Sahrens return (EXDEV); 25511d452cf5Sahrens 2552cdf5b4caSmmusante if (recursive) { 2553cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 2554cdf5b4caSmmusante } else { 2555745cd3c5Smaybee err = dsl_dataset_hold(oldname, FTAG, &ds); 2556cdf5b4caSmmusante if (err) 2557cdf5b4caSmmusante return (err); 25581d452cf5Sahrens 2559cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2560cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 2561cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 25621d452cf5Sahrens 2563745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2564cdf5b4caSmmusante } 25651d452cf5Sahrens 2566fa9e4066Sahrens return (err); 2567fa9e4066Sahrens } 256899653d4eSeschrock 2569088f3894Sahrens struct promotenode { 2570745cd3c5Smaybee list_node_t link; 2571745cd3c5Smaybee dsl_dataset_t *ds; 2572745cd3c5Smaybee }; 2573745cd3c5Smaybee 25741d452cf5Sahrens struct promotearg { 257574e7dc98SMatthew Ahrens list_t shared_snaps, origin_snaps, clone_snaps; 25763f9d6ad7SLin Ling dsl_dataset_t *origin_origin; 257774e7dc98SMatthew Ahrens uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; 2578681d9761SEric Taylor char *err_ds; 25791d452cf5Sahrens }; 25801d452cf5Sahrens 258174e7dc98SMatthew Ahrens static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep); 25823f9d6ad7SLin Ling static boolean_t snaplist_unstable(list_t *l); 258374e7dc98SMatthew Ahrens 258499653d4eSeschrock static int 25851d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 258699653d4eSeschrock { 25871d452cf5Sahrens dsl_dataset_t *hds = arg1; 25881d452cf5Sahrens struct promotearg *pa = arg2; 258974e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2590745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 2591745cd3c5Smaybee int err; 2592cde58dbcSMatthew Ahrens uint64_t unused; 25931d452cf5Sahrens 2594088f3894Sahrens /* Check that it is a real clone */ 2595088f3894Sahrens if (!dsl_dir_is_clone(hds->ds_dir)) 259699653d4eSeschrock return (EINVAL); 259799653d4eSeschrock 25981d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 25991d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 26001d452cf5Sahrens return (0); 26011d452cf5Sahrens 2602745cd3c5Smaybee if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) 2603745cd3c5Smaybee return (EXDEV); 260499653d4eSeschrock 26053cb34c60Sahrens /* compute origin's new unique space */ 260674e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 260774e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 2608cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&snap->ds->ds_deadlist, 2609cde58dbcSMatthew Ahrens origin_ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, 2610cde58dbcSMatthew Ahrens &pa->unique, &unused, &unused); 261199653d4eSeschrock 2612745cd3c5Smaybee /* 2613745cd3c5Smaybee * Walk the snapshots that we are moving 2614745cd3c5Smaybee * 261574e7dc98SMatthew Ahrens * Compute space to transfer. Consider the incremental changes 261674e7dc98SMatthew Ahrens * to used for each snapshot: 261774e7dc98SMatthew Ahrens * (my used) = (prev's used) + (blocks born) - (blocks killed) 261874e7dc98SMatthew Ahrens * So each snapshot gave birth to: 261974e7dc98SMatthew Ahrens * (blocks born) = (my used) - (prev's used) + (blocks killed) 2620745cd3c5Smaybee * So a sequence would look like: 262174e7dc98SMatthew Ahrens * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0) 2622745cd3c5Smaybee * Which simplifies to: 262374e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + k1 + k0 2624745cd3c5Smaybee * Note however, if we stop before we reach the ORIGIN we get: 262574e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + kM - uM-1 2626745cd3c5Smaybee */ 2627745cd3c5Smaybee pa->used = origin_ds->ds_phys->ds_used_bytes; 2628745cd3c5Smaybee pa->comp = origin_ds->ds_phys->ds_compressed_bytes; 2629745cd3c5Smaybee pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes; 263074e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 263174e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 263299653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 2633745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 263499653d4eSeschrock 263599653d4eSeschrock /* Check that the snapshot name does not conflict */ 263674e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2637745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); 2638681d9761SEric Taylor if (err == 0) { 2639681d9761SEric Taylor err = EEXIST; 2640681d9761SEric Taylor goto out; 2641681d9761SEric Taylor } 2642745cd3c5Smaybee if (err != ENOENT) 2643681d9761SEric Taylor goto out; 264499653d4eSeschrock 2645745cd3c5Smaybee /* The very first snapshot does not have a deadlist */ 264674e7dc98SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 264774e7dc98SMatthew Ahrens continue; 264874e7dc98SMatthew Ahrens 2649cde58dbcSMatthew Ahrens dsl_deadlist_space(&ds->ds_deadlist, 2650cde58dbcSMatthew Ahrens &dlused, &dlcomp, &dluncomp); 265174e7dc98SMatthew Ahrens pa->used += dlused; 265274e7dc98SMatthew Ahrens pa->comp += dlcomp; 265374e7dc98SMatthew Ahrens pa->uncomp += dluncomp; 265474e7dc98SMatthew Ahrens } 2655745cd3c5Smaybee 2656745cd3c5Smaybee /* 2657745cd3c5Smaybee * If we are a clone of a clone then we never reached ORIGIN, 2658745cd3c5Smaybee * so we need to subtract out the clone origin's used space. 2659745cd3c5Smaybee */ 266074e7dc98SMatthew Ahrens if (pa->origin_origin) { 266174e7dc98SMatthew Ahrens pa->used -= pa->origin_origin->ds_phys->ds_used_bytes; 266274e7dc98SMatthew Ahrens pa->comp -= pa->origin_origin->ds_phys->ds_compressed_bytes; 266374e7dc98SMatthew Ahrens pa->uncomp -= pa->origin_origin->ds_phys->ds_uncompressed_bytes; 266499653d4eSeschrock } 266599653d4eSeschrock 266699653d4eSeschrock /* Check that there is enough space here */ 266774e7dc98SMatthew Ahrens err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir, 266874e7dc98SMatthew Ahrens pa->used); 266974e7dc98SMatthew Ahrens if (err) 267074e7dc98SMatthew Ahrens return (err); 267174e7dc98SMatthew Ahrens 267274e7dc98SMatthew Ahrens /* 267374e7dc98SMatthew Ahrens * Compute the amounts of space that will be used by snapshots 267474e7dc98SMatthew Ahrens * after the promotion (for both origin and clone). For each, 267574e7dc98SMatthew Ahrens * it is the amount of space that will be on all of their 267674e7dc98SMatthew Ahrens * deadlists (that was not born before their new origin). 267774e7dc98SMatthew Ahrens */ 267874e7dc98SMatthew Ahrens if (hds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 267974e7dc98SMatthew Ahrens uint64_t space; 268074e7dc98SMatthew Ahrens 268174e7dc98SMatthew Ahrens /* 268274e7dc98SMatthew Ahrens * Note, typically this will not be a clone of a clone, 26833f9d6ad7SLin Ling * so dd_origin_txg will be < TXG_INITIAL, so 2684cde58dbcSMatthew Ahrens * these snaplist_space() -> dsl_deadlist_space_range() 268574e7dc98SMatthew Ahrens * calls will be fast because they do not have to 268674e7dc98SMatthew Ahrens * iterate over all bps. 268774e7dc98SMatthew Ahrens */ 268874e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 268974e7dc98SMatthew Ahrens err = snaplist_space(&pa->shared_snaps, 26903f9d6ad7SLin Ling snap->ds->ds_dir->dd_origin_txg, &pa->cloneusedsnap); 269174e7dc98SMatthew Ahrens if (err) 269274e7dc98SMatthew Ahrens return (err); 269374e7dc98SMatthew Ahrens 269474e7dc98SMatthew Ahrens err = snaplist_space(&pa->clone_snaps, 26953f9d6ad7SLin Ling snap->ds->ds_dir->dd_origin_txg, &space); 269674e7dc98SMatthew Ahrens if (err) 269774e7dc98SMatthew Ahrens return (err); 269874e7dc98SMatthew Ahrens pa->cloneusedsnap += space; 269974e7dc98SMatthew Ahrens } 270074e7dc98SMatthew Ahrens if (origin_ds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 270174e7dc98SMatthew Ahrens err = snaplist_space(&pa->origin_snaps, 270274e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_creation_txg, &pa->originusedsnap); 270374e7dc98SMatthew Ahrens if (err) 270474e7dc98SMatthew Ahrens return (err); 2705745cd3c5Smaybee } 27061d452cf5Sahrens 270774e7dc98SMatthew Ahrens return (0); 2708681d9761SEric Taylor out: 2709681d9761SEric Taylor pa->err_ds = snap->ds->ds_snapname; 2710681d9761SEric Taylor return (err); 27111d452cf5Sahrens } 271299653d4eSeschrock 27131d452cf5Sahrens static void 27143f9d6ad7SLin Ling dsl_dataset_promote_sync(void *arg1, void *arg2, dmu_tx_t *tx) 27151d452cf5Sahrens { 27161d452cf5Sahrens dsl_dataset_t *hds = arg1; 27171d452cf5Sahrens struct promotearg *pa = arg2; 271874e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2719745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 272074e7dc98SMatthew Ahrens dsl_dataset_t *origin_head; 27211d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 27221d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 27233cb34c60Sahrens dsl_dir_t *odd = NULL; 2724088f3894Sahrens uint64_t oldnext_obj; 272574e7dc98SMatthew Ahrens int64_t delta; 27261d452cf5Sahrens 27271d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 27281d452cf5Sahrens 272974e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 273074e7dc98SMatthew Ahrens origin_head = snap->ds; 273174e7dc98SMatthew Ahrens 27320b69c2f0Sahrens /* 27333cb34c60Sahrens * We need to explicitly open odd, since origin_ds's dd will be 27340b69c2f0Sahrens * changing. 27350b69c2f0Sahrens */ 27363cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object, 27373cb34c60Sahrens NULL, FTAG, &odd)); 273899653d4eSeschrock 2739745cd3c5Smaybee /* change origin's next snap */ 2740745cd3c5Smaybee dmu_buf_will_dirty(origin_ds->ds_dbuf, tx); 2741088f3894Sahrens oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj; 274274e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 274374e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 274474e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj = snap->ds->ds_object; 2745745cd3c5Smaybee 2746088f3894Sahrens /* change the origin's next clone */ 2747088f3894Sahrens if (origin_ds->ds_phys->ds_next_clones_obj) { 2748c33e334fSMatthew Ahrens remove_from_next_clones(origin_ds, snap->ds->ds_object, tx); 2749088f3894Sahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2750088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2751088f3894Sahrens oldnext_obj, tx)); 2752088f3894Sahrens } 2753088f3894Sahrens 2754745cd3c5Smaybee /* change origin */ 2755745cd3c5Smaybee dmu_buf_will_dirty(dd->dd_dbuf, tx); 2756745cd3c5Smaybee ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object); 2757745cd3c5Smaybee dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj; 27583f9d6ad7SLin Ling dd->dd_origin_txg = origin_head->ds_dir->dd_origin_txg; 2759745cd3c5Smaybee dmu_buf_will_dirty(odd->dd_dbuf, tx); 2760745cd3c5Smaybee odd->dd_phys->dd_origin_obj = origin_ds->ds_object; 27613f9d6ad7SLin Ling origin_head->ds_dir->dd_origin_txg = 27623f9d6ad7SLin Ling origin_ds->ds_phys->ds_creation_txg; 2763745cd3c5Smaybee 2764cde58dbcSMatthew Ahrens /* change dd_clone entries */ 2765cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 2766cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2767cde58dbcSMatthew Ahrens odd->dd_phys->dd_clones, hds->ds_object, tx)); 2768cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2769cde58dbcSMatthew Ahrens pa->origin_origin->ds_dir->dd_phys->dd_clones, 2770cde58dbcSMatthew Ahrens hds->ds_object, tx)); 2771cde58dbcSMatthew Ahrens 2772cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2773cde58dbcSMatthew Ahrens pa->origin_origin->ds_dir->dd_phys->dd_clones, 2774cde58dbcSMatthew Ahrens origin_head->ds_object, tx)); 2775cde58dbcSMatthew Ahrens if (dd->dd_phys->dd_clones == 0) { 2776cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones = zap_create(dp->dp_meta_objset, 2777cde58dbcSMatthew Ahrens DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx); 2778cde58dbcSMatthew Ahrens } 2779cde58dbcSMatthew Ahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2780cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones, origin_head->ds_object, tx)); 2781cde58dbcSMatthew Ahrens 2782cde58dbcSMatthew Ahrens } 2783cde58dbcSMatthew Ahrens 278499653d4eSeschrock /* move snapshots to this dir */ 278574e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 278674e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 2787745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 278899653d4eSeschrock 27893baa08fcSek /* unregister props as dsl_dir is changing */ 2790503ad85cSMatthew Ahrens if (ds->ds_objset) { 2791503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 2792503ad85cSMatthew Ahrens ds->ds_objset = NULL; 27933baa08fcSek } 279499653d4eSeschrock /* move snap name entry */ 279574e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 279674e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_snap_remove(origin_head, 2797745cd3c5Smaybee ds->ds_snapname, tx)); 27981d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 279999653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 280099653d4eSeschrock 8, 1, &ds->ds_object, tx)); 2801cde58dbcSMatthew Ahrens 280299653d4eSeschrock /* change containing dsl_dir */ 280399653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 28043cb34c60Sahrens ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object); 280599653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 28063cb34c60Sahrens ASSERT3P(ds->ds_dir, ==, odd); 280799653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 28081d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 280999653d4eSeschrock NULL, ds, &ds->ds_dir)); 281099653d4eSeschrock 2811cde58dbcSMatthew Ahrens /* move any clone references */ 2812cde58dbcSMatthew Ahrens if (ds->ds_phys->ds_next_clones_obj && 2813cde58dbcSMatthew Ahrens spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 2814cde58dbcSMatthew Ahrens zap_cursor_t zc; 2815cde58dbcSMatthew Ahrens zap_attribute_t za; 2816cde58dbcSMatthew Ahrens 2817cde58dbcSMatthew Ahrens for (zap_cursor_init(&zc, dp->dp_meta_objset, 2818cde58dbcSMatthew Ahrens ds->ds_phys->ds_next_clones_obj); 2819cde58dbcSMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 2820cde58dbcSMatthew Ahrens zap_cursor_advance(&zc)) { 2821cde58dbcSMatthew Ahrens dsl_dataset_t *cnds; 2822cde58dbcSMatthew Ahrens uint64_t o; 2823cde58dbcSMatthew Ahrens 2824cde58dbcSMatthew Ahrens if (za.za_first_integer == oldnext_obj) { 2825cde58dbcSMatthew Ahrens /* 2826cde58dbcSMatthew Ahrens * We've already moved the 2827cde58dbcSMatthew Ahrens * origin's reference. 2828cde58dbcSMatthew Ahrens */ 2829cde58dbcSMatthew Ahrens continue; 2830cde58dbcSMatthew Ahrens } 2831cde58dbcSMatthew Ahrens 2832cde58dbcSMatthew Ahrens VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 2833cde58dbcSMatthew Ahrens za.za_first_integer, FTAG, &cnds)); 2834cde58dbcSMatthew Ahrens o = cnds->ds_dir->dd_phys->dd_head_dataset_obj; 2835cde58dbcSMatthew Ahrens 2836cde58dbcSMatthew Ahrens VERIFY3U(zap_remove_int(dp->dp_meta_objset, 2837cde58dbcSMatthew Ahrens odd->dd_phys->dd_clones, o, tx), ==, 0); 2838cde58dbcSMatthew Ahrens VERIFY3U(zap_add_int(dp->dp_meta_objset, 2839cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones, o, tx), ==, 0); 2840cde58dbcSMatthew Ahrens dsl_dataset_rele(cnds, FTAG); 2841cde58dbcSMatthew Ahrens } 2842cde58dbcSMatthew Ahrens zap_cursor_fini(&zc); 2843cde58dbcSMatthew Ahrens } 2844cde58dbcSMatthew Ahrens 284599653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 284674e7dc98SMatthew Ahrens } 284774e7dc98SMatthew Ahrens 284874e7dc98SMatthew Ahrens /* 284974e7dc98SMatthew Ahrens * Change space accounting. 285074e7dc98SMatthew Ahrens * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either 285174e7dc98SMatthew Ahrens * both be valid, or both be 0 (resulting in delta == 0). This 285274e7dc98SMatthew Ahrens * is true for each of {clone,origin} independently. 285374e7dc98SMatthew Ahrens */ 285474e7dc98SMatthew Ahrens 285574e7dc98SMatthew Ahrens delta = pa->cloneusedsnap - 285674e7dc98SMatthew Ahrens dd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 285774e7dc98SMatthew Ahrens ASSERT3S(delta, >=, 0); 285874e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, delta); 285974e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx); 286074e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_HEAD, 286174e7dc98SMatthew Ahrens pa->used - delta, pa->comp, pa->uncomp, tx); 286274e7dc98SMatthew Ahrens 286374e7dc98SMatthew Ahrens delta = pa->originusedsnap - 286474e7dc98SMatthew Ahrens odd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 286574e7dc98SMatthew Ahrens ASSERT3S(delta, <=, 0); 286674e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, -delta); 286774e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx); 286874e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_HEAD, 286974e7dc98SMatthew Ahrens -pa->used - delta, -pa->comp, -pa->uncomp, tx); 287099653d4eSeschrock 28713cb34c60Sahrens origin_ds->ds_phys->ds_unique_bytes = pa->unique; 287299653d4eSeschrock 2873ecd6cf80Smarks /* log history record */ 28743f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 28753f9d6ad7SLin Ling "dataset = %llu", hds->ds_object); 2876ecd6cf80Smarks 28773cb34c60Sahrens dsl_dir_close(odd, FTAG); 287899653d4eSeschrock } 287999653d4eSeschrock 288074e7dc98SMatthew Ahrens static char *snaplist_tag = "snaplist"; 288174e7dc98SMatthew Ahrens /* 288274e7dc98SMatthew Ahrens * Make a list of dsl_dataset_t's for the snapshots between first_obj 288374e7dc98SMatthew Ahrens * (exclusive) and last_obj (inclusive). The list will be in reverse 288474e7dc98SMatthew Ahrens * order (last_obj will be the list_head()). If first_obj == 0, do all 288574e7dc98SMatthew Ahrens * snapshots back to this dataset's origin. 288674e7dc98SMatthew Ahrens */ 288774e7dc98SMatthew Ahrens static int 288874e7dc98SMatthew Ahrens snaplist_make(dsl_pool_t *dp, boolean_t own, 288974e7dc98SMatthew Ahrens uint64_t first_obj, uint64_t last_obj, list_t *l) 289074e7dc98SMatthew Ahrens { 289174e7dc98SMatthew Ahrens uint64_t obj = last_obj; 289274e7dc98SMatthew Ahrens 289374e7dc98SMatthew Ahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock)); 289474e7dc98SMatthew Ahrens 289574e7dc98SMatthew Ahrens list_create(l, sizeof (struct promotenode), 289674e7dc98SMatthew Ahrens offsetof(struct promotenode, link)); 289774e7dc98SMatthew Ahrens 289874e7dc98SMatthew Ahrens while (obj != first_obj) { 289974e7dc98SMatthew Ahrens dsl_dataset_t *ds; 290074e7dc98SMatthew Ahrens struct promotenode *snap; 290174e7dc98SMatthew Ahrens int err; 290274e7dc98SMatthew Ahrens 290374e7dc98SMatthew Ahrens if (own) { 290474e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, obj, 290574e7dc98SMatthew Ahrens 0, snaplist_tag, &ds); 290674e7dc98SMatthew Ahrens if (err == 0) 290774e7dc98SMatthew Ahrens dsl_dataset_make_exclusive(ds, snaplist_tag); 290874e7dc98SMatthew Ahrens } else { 290974e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, obj, snaplist_tag, &ds); 291074e7dc98SMatthew Ahrens } 291174e7dc98SMatthew Ahrens if (err == ENOENT) { 291274e7dc98SMatthew Ahrens /* lost race with snapshot destroy */ 291374e7dc98SMatthew Ahrens struct promotenode *last = list_tail(l); 291474e7dc98SMatthew Ahrens ASSERT(obj != last->ds->ds_phys->ds_prev_snap_obj); 291574e7dc98SMatthew Ahrens obj = last->ds->ds_phys->ds_prev_snap_obj; 291674e7dc98SMatthew Ahrens continue; 291774e7dc98SMatthew Ahrens } else if (err) { 291874e7dc98SMatthew Ahrens return (err); 291974e7dc98SMatthew Ahrens } 292074e7dc98SMatthew Ahrens 292174e7dc98SMatthew Ahrens if (first_obj == 0) 292274e7dc98SMatthew Ahrens first_obj = ds->ds_dir->dd_phys->dd_origin_obj; 292374e7dc98SMatthew Ahrens 292474e7dc98SMatthew Ahrens snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP); 292574e7dc98SMatthew Ahrens snap->ds = ds; 292674e7dc98SMatthew Ahrens list_insert_tail(l, snap); 292774e7dc98SMatthew Ahrens obj = ds->ds_phys->ds_prev_snap_obj; 292874e7dc98SMatthew Ahrens } 292974e7dc98SMatthew Ahrens 293074e7dc98SMatthew Ahrens return (0); 293174e7dc98SMatthew Ahrens } 293274e7dc98SMatthew Ahrens 293374e7dc98SMatthew Ahrens static int 293474e7dc98SMatthew Ahrens snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep) 293574e7dc98SMatthew Ahrens { 293674e7dc98SMatthew Ahrens struct promotenode *snap; 293774e7dc98SMatthew Ahrens 293874e7dc98SMatthew Ahrens *spacep = 0; 293974e7dc98SMatthew Ahrens for (snap = list_head(l); snap; snap = list_next(l, snap)) { 2940cde58dbcSMatthew Ahrens uint64_t used, comp, uncomp; 2941cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&snap->ds->ds_deadlist, 2942cde58dbcSMatthew Ahrens mintxg, UINT64_MAX, &used, &comp, &uncomp); 294374e7dc98SMatthew Ahrens *spacep += used; 294474e7dc98SMatthew Ahrens } 294574e7dc98SMatthew Ahrens return (0); 294674e7dc98SMatthew Ahrens } 294774e7dc98SMatthew Ahrens 294874e7dc98SMatthew Ahrens static void 294974e7dc98SMatthew Ahrens snaplist_destroy(list_t *l, boolean_t own) 295074e7dc98SMatthew Ahrens { 295174e7dc98SMatthew Ahrens struct promotenode *snap; 295274e7dc98SMatthew Ahrens 29534f5064b7SMark J Musante if (!l || !list_link_active(&l->list_head)) 295474e7dc98SMatthew Ahrens return; 295574e7dc98SMatthew Ahrens 295674e7dc98SMatthew Ahrens while ((snap = list_tail(l)) != NULL) { 295774e7dc98SMatthew Ahrens list_remove(l, snap); 295874e7dc98SMatthew Ahrens if (own) 295974e7dc98SMatthew Ahrens dsl_dataset_disown(snap->ds, snaplist_tag); 296074e7dc98SMatthew Ahrens else 296174e7dc98SMatthew Ahrens dsl_dataset_rele(snap->ds, snaplist_tag); 296274e7dc98SMatthew Ahrens kmem_free(snap, sizeof (struct promotenode)); 296374e7dc98SMatthew Ahrens } 296474e7dc98SMatthew Ahrens list_destroy(l); 296574e7dc98SMatthew Ahrens } 296674e7dc98SMatthew Ahrens 296774e7dc98SMatthew Ahrens /* 296874e7dc98SMatthew Ahrens * Promote a clone. Nomenclature note: 296974e7dc98SMatthew Ahrens * "clone" or "cds": the original clone which is being promoted 297074e7dc98SMatthew Ahrens * "origin" or "ods": the snapshot which is originally clone's origin 297174e7dc98SMatthew Ahrens * "origin head" or "ohds": the dataset which is the head 297274e7dc98SMatthew Ahrens * (filesystem/volume) for the origin 297374e7dc98SMatthew Ahrens * "origin origin": the origin of the origin's filesystem (typically 297474e7dc98SMatthew Ahrens * NULL, indicating that the clone is not a clone of a clone). 297574e7dc98SMatthew Ahrens */ 297699653d4eSeschrock int 2977681d9761SEric Taylor dsl_dataset_promote(const char *name, char *conflsnap) 297899653d4eSeschrock { 297999653d4eSeschrock dsl_dataset_t *ds; 2980745cd3c5Smaybee dsl_dir_t *dd; 2981745cd3c5Smaybee dsl_pool_t *dp; 298299653d4eSeschrock dmu_object_info_t doi; 298374e7dc98SMatthew Ahrens struct promotearg pa = { 0 }; 2984088f3894Sahrens struct promotenode *snap; 2985745cd3c5Smaybee int err; 298699653d4eSeschrock 2987745cd3c5Smaybee err = dsl_dataset_hold(name, FTAG, &ds); 298899653d4eSeschrock if (err) 298999653d4eSeschrock return (err); 2990745cd3c5Smaybee dd = ds->ds_dir; 2991745cd3c5Smaybee dp = dd->dd_pool; 299299653d4eSeschrock 2993745cd3c5Smaybee err = dmu_object_info(dp->dp_meta_objset, 299499653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 299599653d4eSeschrock if (err) { 2996745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 299799653d4eSeschrock return (err); 299899653d4eSeschrock } 299999653d4eSeschrock 300074e7dc98SMatthew Ahrens if (dsl_dataset_is_snapshot(ds) || dd->dd_phys->dd_origin_obj == 0) { 300174e7dc98SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 300274e7dc98SMatthew Ahrens return (EINVAL); 300374e7dc98SMatthew Ahrens } 300474e7dc98SMatthew Ahrens 3005745cd3c5Smaybee /* 3006745cd3c5Smaybee * We are going to inherit all the snapshots taken before our 3007745cd3c5Smaybee * origin (i.e., our new origin will be our parent's origin). 3008745cd3c5Smaybee * Take ownership of them so that we can rename them into our 3009745cd3c5Smaybee * namespace. 3010745cd3c5Smaybee */ 3011745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 3012088f3894Sahrens 301374e7dc98SMatthew Ahrens err = snaplist_make(dp, B_TRUE, 0, dd->dd_phys->dd_origin_obj, 301474e7dc98SMatthew Ahrens &pa.shared_snaps); 301574e7dc98SMatthew Ahrens if (err != 0) 301674e7dc98SMatthew Ahrens goto out; 3017088f3894Sahrens 301874e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, 0, ds->ds_object, &pa.clone_snaps); 301974e7dc98SMatthew Ahrens if (err != 0) 302074e7dc98SMatthew Ahrens goto out; 3021088f3894Sahrens 302274e7dc98SMatthew Ahrens snap = list_head(&pa.shared_snaps); 302374e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_object, ==, dd->dd_phys->dd_origin_obj); 302474e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, dd->dd_phys->dd_origin_obj, 302574e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, &pa.origin_snaps); 302674e7dc98SMatthew Ahrens if (err != 0) 302774e7dc98SMatthew Ahrens goto out; 3028088f3894Sahrens 3029cde58dbcSMatthew Ahrens if (snap->ds->ds_dir->dd_phys->dd_origin_obj != 0) { 3030cde58dbcSMatthew Ahrens err = dsl_dataset_hold_obj(dp, 303174e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_origin_obj, 3032cde58dbcSMatthew Ahrens FTAG, &pa.origin_origin); 303374e7dc98SMatthew Ahrens if (err != 0) 303474e7dc98SMatthew Ahrens goto out; 303574e7dc98SMatthew Ahrens } 3036745cd3c5Smaybee 303774e7dc98SMatthew Ahrens out: 303874e7dc98SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 3039745cd3c5Smaybee 304099653d4eSeschrock /* 304199653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 304299653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 304399653d4eSeschrock * bonus buffers. 304499653d4eSeschrock */ 304574e7dc98SMatthew Ahrens if (err == 0) { 304674e7dc98SMatthew Ahrens err = dsl_sync_task_do(dp, dsl_dataset_promote_check, 304774e7dc98SMatthew Ahrens dsl_dataset_promote_sync, ds, &pa, 3048b24ab676SJeff Bonwick 2 + 2 * doi.doi_physical_blocks_512); 3049681d9761SEric Taylor if (err && pa.err_ds && conflsnap) 3050681d9761SEric Taylor (void) strncpy(conflsnap, pa.err_ds, MAXNAMELEN); 3051745cd3c5Smaybee } 305274e7dc98SMatthew Ahrens 305374e7dc98SMatthew Ahrens snaplist_destroy(&pa.shared_snaps, B_TRUE); 305474e7dc98SMatthew Ahrens snaplist_destroy(&pa.clone_snaps, B_FALSE); 305574e7dc98SMatthew Ahrens snaplist_destroy(&pa.origin_snaps, B_FALSE); 305674e7dc98SMatthew Ahrens if (pa.origin_origin) 3057cde58dbcSMatthew Ahrens dsl_dataset_rele(pa.origin_origin, FTAG); 3058745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 305999653d4eSeschrock return (err); 306099653d4eSeschrock } 3061b1b8ab34Slling 30623cb34c60Sahrens struct cloneswaparg { 30633cb34c60Sahrens dsl_dataset_t *cds; /* clone dataset */ 30643cb34c60Sahrens dsl_dataset_t *ohds; /* origin's head dataset */ 30653cb34c60Sahrens boolean_t force; 3066a9b821a0Sck int64_t unused_refres_delta; /* change in unconsumed refreservation */ 30673cb34c60Sahrens }; 3068f18faf3fSek 3069f18faf3fSek /* ARGSUSED */ 3070f18faf3fSek static int 3071f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 3072f18faf3fSek { 30733cb34c60Sahrens struct cloneswaparg *csa = arg1; 3074f18faf3fSek 30753cb34c60Sahrens /* they should both be heads */ 30763cb34c60Sahrens if (dsl_dataset_is_snapshot(csa->cds) || 30773cb34c60Sahrens dsl_dataset_is_snapshot(csa->ohds)) 3078f18faf3fSek return (EINVAL); 3079f18faf3fSek 30803cb34c60Sahrens /* the branch point should be just before them */ 30813cb34c60Sahrens if (csa->cds->ds_prev != csa->ohds->ds_prev) 3082f18faf3fSek return (EINVAL); 3083f18faf3fSek 3084ae46e4c7SMatthew Ahrens /* cds should be the clone (unless they are unrelated) */ 3085ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev != NULL && 3086ae46e4c7SMatthew Ahrens csa->cds->ds_prev != csa->cds->ds_dir->dd_pool->dp_origin_snap && 3087ae46e4c7SMatthew Ahrens csa->ohds->ds_object != 3088ae46e4c7SMatthew Ahrens csa->cds->ds_prev->ds_phys->ds_next_snap_obj) 30893cb34c60Sahrens return (EINVAL); 3090f18faf3fSek 30913cb34c60Sahrens /* the clone should be a child of the origin */ 30923cb34c60Sahrens if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir) 30933cb34c60Sahrens return (EINVAL); 3094f18faf3fSek 30953cb34c60Sahrens /* ohds shouldn't be modified unless 'force' */ 30963cb34c60Sahrens if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) 30973cb34c60Sahrens return (ETXTBSY); 3098a9b821a0Sck 3099a9b821a0Sck /* adjust amount of any unconsumed refreservation */ 3100a9b821a0Sck csa->unused_refres_delta = 3101a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 3102a9b821a0Sck csa->ohds->ds_phys->ds_unique_bytes) - 3103a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 3104a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 3105a9b821a0Sck 3106a9b821a0Sck if (csa->unused_refres_delta > 0 && 3107a9b821a0Sck csa->unused_refres_delta > 3108a9b821a0Sck dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) 3109a9b821a0Sck return (ENOSPC); 3110a9b821a0Sck 3111c4cbca4fSChris Kirby if (csa->ohds->ds_quota != 0 && 3112c4cbca4fSChris Kirby csa->cds->ds_phys->ds_unique_bytes > csa->ohds->ds_quota) 3113c4cbca4fSChris Kirby return (EDQUOT); 3114c4cbca4fSChris Kirby 31153cb34c60Sahrens return (0); 3116f18faf3fSek } 3117f18faf3fSek 3118f18faf3fSek /* ARGSUSED */ 3119f18faf3fSek static void 31203f9d6ad7SLin Ling dsl_dataset_clone_swap_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3121f18faf3fSek { 31223cb34c60Sahrens struct cloneswaparg *csa = arg1; 31233cb34c60Sahrens dsl_pool_t *dp = csa->cds->ds_dir->dd_pool; 3124f18faf3fSek 3125a9b821a0Sck ASSERT(csa->cds->ds_reserved == 0); 3126c4cbca4fSChris Kirby ASSERT(csa->ohds->ds_quota == 0 || 3127c4cbca4fSChris Kirby csa->cds->ds_phys->ds_unique_bytes <= csa->ohds->ds_quota); 3128a9b821a0Sck 31293cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); 31303cb34c60Sahrens dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); 3131f18faf3fSek 3132503ad85cSMatthew Ahrens if (csa->cds->ds_objset != NULL) { 3133503ad85cSMatthew Ahrens dmu_objset_evict(csa->cds->ds_objset); 3134503ad85cSMatthew Ahrens csa->cds->ds_objset = NULL; 31353cb34c60Sahrens } 3136f18faf3fSek 3137503ad85cSMatthew Ahrens if (csa->ohds->ds_objset != NULL) { 3138503ad85cSMatthew Ahrens dmu_objset_evict(csa->ohds->ds_objset); 3139503ad85cSMatthew Ahrens csa->ohds->ds_objset = NULL; 31403cb34c60Sahrens } 3141f18faf3fSek 3142ae46e4c7SMatthew Ahrens /* 3143ae46e4c7SMatthew Ahrens * Reset origin's unique bytes, if it exists. 3144ae46e4c7SMatthew Ahrens */ 3145ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev) { 3146ae46e4c7SMatthew Ahrens dsl_dataset_t *origin = csa->cds->ds_prev; 3147cde58dbcSMatthew Ahrens uint64_t comp, uncomp; 3148cde58dbcSMatthew Ahrens 3149ae46e4c7SMatthew Ahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 3150cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->cds->ds_deadlist, 3151ae46e4c7SMatthew Ahrens origin->ds_phys->ds_prev_snap_txg, UINT64_MAX, 3152cde58dbcSMatthew Ahrens &origin->ds_phys->ds_unique_bytes, &comp, &uncomp); 3153ae46e4c7SMatthew Ahrens } 3154f18faf3fSek 3155f18faf3fSek /* swap blkptrs */ 3156f18faf3fSek { 3157f18faf3fSek blkptr_t tmp; 31583cb34c60Sahrens tmp = csa->ohds->ds_phys->ds_bp; 31593cb34c60Sahrens csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp; 31603cb34c60Sahrens csa->cds->ds_phys->ds_bp = tmp; 3161f18faf3fSek } 3162f18faf3fSek 3163f18faf3fSek /* set dd_*_bytes */ 3164f18faf3fSek { 3165f18faf3fSek int64_t dused, dcomp, duncomp; 3166f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 3167f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 3168f18faf3fSek 316974e7dc98SMatthew Ahrens ASSERT3U(csa->cds->ds_dir->dd_phys-> 317074e7dc98SMatthew Ahrens dd_used_breakdown[DD_USED_SNAP], ==, 0); 317174e7dc98SMatthew Ahrens 3172cde58dbcSMatthew Ahrens dsl_deadlist_space(&csa->cds->ds_deadlist, 3173cde58dbcSMatthew Ahrens &cdl_used, &cdl_comp, &cdl_uncomp); 3174cde58dbcSMatthew Ahrens dsl_deadlist_space(&csa->ohds->ds_deadlist, 3175cde58dbcSMatthew Ahrens &odl_used, &odl_comp, &odl_uncomp); 317674e7dc98SMatthew Ahrens 31773cb34c60Sahrens dused = csa->cds->ds_phys->ds_used_bytes + cdl_used - 31783cb34c60Sahrens (csa->ohds->ds_phys->ds_used_bytes + odl_used); 31793cb34c60Sahrens dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp - 31803cb34c60Sahrens (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp); 31813cb34c60Sahrens duncomp = csa->cds->ds_phys->ds_uncompressed_bytes + 31823cb34c60Sahrens cdl_uncomp - 31833cb34c60Sahrens (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 31843cb34c60Sahrens 318574e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_HEAD, 31863cb34c60Sahrens dused, dcomp, duncomp, tx); 318774e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->cds->ds_dir, DD_USED_HEAD, 31883cb34c60Sahrens -dused, -dcomp, -duncomp, tx); 318974e7dc98SMatthew Ahrens 319074e7dc98SMatthew Ahrens /* 319174e7dc98SMatthew Ahrens * The difference in the space used by snapshots is the 319274e7dc98SMatthew Ahrens * difference in snapshot space due to the head's 319374e7dc98SMatthew Ahrens * deadlist (since that's the only thing that's 319474e7dc98SMatthew Ahrens * changing that affects the snapused). 319574e7dc98SMatthew Ahrens */ 3196cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->cds->ds_deadlist, 3197cde58dbcSMatthew Ahrens csa->ohds->ds_dir->dd_origin_txg, UINT64_MAX, 3198cde58dbcSMatthew Ahrens &cdl_used, &cdl_comp, &cdl_uncomp); 3199cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->ohds->ds_deadlist, 3200cde58dbcSMatthew Ahrens csa->ohds->ds_dir->dd_origin_txg, UINT64_MAX, 3201cde58dbcSMatthew Ahrens &odl_used, &odl_comp, &odl_uncomp); 320274e7dc98SMatthew Ahrens dsl_dir_transfer_space(csa->ohds->ds_dir, cdl_used - odl_used, 320374e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 32043cb34c60Sahrens } 32053cb34c60Sahrens 3206f18faf3fSek /* swap ds_*_bytes */ 32073cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_used_bytes, 32083cb34c60Sahrens csa->cds->ds_phys->ds_used_bytes); 32093cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes, 32103cb34c60Sahrens csa->cds->ds_phys->ds_compressed_bytes); 32113cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, 32123cb34c60Sahrens csa->cds->ds_phys->ds_uncompressed_bytes); 3213a9b821a0Sck SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, 3214a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 3215a9b821a0Sck 3216a9b821a0Sck /* apply any parent delta for change in unconsumed refreservation */ 321774e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_REFRSRV, 321874e7dc98SMatthew Ahrens csa->unused_refres_delta, 0, 0, tx); 3219f18faf3fSek 3220cde58dbcSMatthew Ahrens /* 3221cde58dbcSMatthew Ahrens * Swap deadlists. 3222cde58dbcSMatthew Ahrens */ 3223cde58dbcSMatthew Ahrens dsl_deadlist_close(&csa->cds->ds_deadlist); 3224cde58dbcSMatthew Ahrens dsl_deadlist_close(&csa->ohds->ds_deadlist); 32253cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj, 32263cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj); 3227cde58dbcSMatthew Ahrens dsl_deadlist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset, 3228cde58dbcSMatthew Ahrens csa->cds->ds_phys->ds_deadlist_obj); 3229cde58dbcSMatthew Ahrens dsl_deadlist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, 3230cde58dbcSMatthew Ahrens csa->ohds->ds_phys->ds_deadlist_obj); 323188b7b0f2SMatthew Ahrens 32323f9d6ad7SLin Ling dsl_scan_ds_clone_swapped(csa->ohds, csa->cds, tx); 3233f18faf3fSek } 3234f18faf3fSek 3235f18faf3fSek /* 3236ae46e4c7SMatthew Ahrens * Swap 'clone' with its origin head datasets. Used at the end of "zfs 3237ae46e4c7SMatthew Ahrens * recv" into an existing fs to swizzle the file system to the new 3238ae46e4c7SMatthew Ahrens * version, and by "zfs rollback". Can also be used to swap two 3239ae46e4c7SMatthew Ahrens * independent head datasets if neither has any snapshots. 3240f18faf3fSek */ 3241f18faf3fSek int 32423cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, 32433cb34c60Sahrens boolean_t force) 3244f18faf3fSek { 32453cb34c60Sahrens struct cloneswaparg csa; 3246745cd3c5Smaybee int error; 3247f18faf3fSek 3248745cd3c5Smaybee ASSERT(clone->ds_owner); 3249745cd3c5Smaybee ASSERT(origin_head->ds_owner); 3250745cd3c5Smaybee retry: 325177972028SChris Kirby /* 325277972028SChris Kirby * Need exclusive access for the swap. If we're swapping these 325377972028SChris Kirby * datasets back after an error, we already hold the locks. 325477972028SChris Kirby */ 325577972028SChris Kirby if (!RW_WRITE_HELD(&clone->ds_rwlock)) 325677972028SChris Kirby rw_enter(&clone->ds_rwlock, RW_WRITER); 325777972028SChris Kirby if (!RW_WRITE_HELD(&origin_head->ds_rwlock) && 325877972028SChris Kirby !rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) { 3259745cd3c5Smaybee rw_exit(&clone->ds_rwlock); 3260745cd3c5Smaybee rw_enter(&origin_head->ds_rwlock, RW_WRITER); 3261745cd3c5Smaybee if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) { 3262745cd3c5Smaybee rw_exit(&origin_head->ds_rwlock); 3263745cd3c5Smaybee goto retry; 3264745cd3c5Smaybee } 3265745cd3c5Smaybee } 32663cb34c60Sahrens csa.cds = clone; 32673cb34c60Sahrens csa.ohds = origin_head; 32683cb34c60Sahrens csa.force = force; 3269745cd3c5Smaybee error = dsl_sync_task_do(clone->ds_dir->dd_pool, 3270f18faf3fSek dsl_dataset_clone_swap_check, 3271745cd3c5Smaybee dsl_dataset_clone_swap_sync, &csa, NULL, 9); 3272745cd3c5Smaybee return (error); 3273f18faf3fSek } 3274f18faf3fSek 3275b1b8ab34Slling /* 3276b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 3277b1b8ab34Slling * return the name of that dataset. 3278b1b8ab34Slling */ 3279b1b8ab34Slling int 3280b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 3281b1b8ab34Slling { 3282b1b8ab34Slling spa_t *spa; 3283b1b8ab34Slling dsl_pool_t *dp; 3284745cd3c5Smaybee dsl_dataset_t *ds; 3285b1b8ab34Slling int error; 3286b1b8ab34Slling 3287b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 3288b1b8ab34Slling return (error); 3289b1b8ab34Slling dp = spa_get_dsl(spa); 3290b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 3291745cd3c5Smaybee if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) { 3292745cd3c5Smaybee dsl_dataset_name(ds, buf); 3293745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3294b1b8ab34Slling } 3295b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 3296b1b8ab34Slling spa_close(spa, FTAG); 3297b1b8ab34Slling 3298745cd3c5Smaybee return (error); 3299b1b8ab34Slling } 3300a9799022Sck 3301a9799022Sck int 3302a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, 3303745cd3c5Smaybee uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv) 3304a9799022Sck { 3305a9799022Sck int error = 0; 3306a9799022Sck 3307a9799022Sck ASSERT3S(asize, >, 0); 3308a9799022Sck 33099082849eSck /* 33109082849eSck * *ref_rsrv is the portion of asize that will come from any 33119082849eSck * unconsumed refreservation space. 33129082849eSck */ 33139082849eSck *ref_rsrv = 0; 33149082849eSck 3315a9799022Sck mutex_enter(&ds->ds_lock); 3316a9799022Sck /* 3317a9799022Sck * Make a space adjustment for reserved bytes. 3318a9799022Sck */ 3319a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) { 3320a9799022Sck ASSERT3U(*used, >=, 3321a9799022Sck ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 3322a9799022Sck *used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 33239082849eSck *ref_rsrv = 33249082849eSck asize - MIN(asize, parent_delta(ds, asize + inflight)); 3325a9799022Sck } 3326a9799022Sck 3327a9799022Sck if (!check_quota || ds->ds_quota == 0) { 3328a9799022Sck mutex_exit(&ds->ds_lock); 3329a9799022Sck return (0); 3330a9799022Sck } 3331a9799022Sck /* 3332a9799022Sck * If they are requesting more space, and our current estimate 3333a9799022Sck * is over quota, they get to try again unless the actual 3334a9799022Sck * on-disk is over quota and there are no pending changes (which 3335a9799022Sck * may free up space for us). 3336a9799022Sck */ 3337a9799022Sck if (ds->ds_phys->ds_used_bytes + inflight >= ds->ds_quota) { 3338a9799022Sck if (inflight > 0 || ds->ds_phys->ds_used_bytes < ds->ds_quota) 3339a9799022Sck error = ERESTART; 3340a9799022Sck else 3341a9799022Sck error = EDQUOT; 3342a9799022Sck } 3343a9799022Sck mutex_exit(&ds->ds_lock); 3344a9799022Sck 3345a9799022Sck return (error); 3346a9799022Sck } 3347a9799022Sck 3348a9799022Sck /* ARGSUSED */ 3349a9799022Sck static int 3350a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx) 3351a9799022Sck { 3352a9799022Sck dsl_dataset_t *ds = arg1; 335392241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 335492241e0bSTom Erickson int err; 3355a9799022Sck 3356a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA) 3357a9799022Sck return (ENOTSUP); 3358a9799022Sck 335992241e0bSTom Erickson if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0) 336092241e0bSTom Erickson return (err); 336192241e0bSTom Erickson 336292241e0bSTom Erickson if (psa->psa_effective_value == 0) 3363a9799022Sck return (0); 3364a9799022Sck 336592241e0bSTom Erickson if (psa->psa_effective_value < ds->ds_phys->ds_used_bytes || 336692241e0bSTom Erickson psa->psa_effective_value < ds->ds_reserved) 3367a9799022Sck return (ENOSPC); 3368a9799022Sck 3369a9799022Sck return (0); 3370a9799022Sck } 3371a9799022Sck 33723f9d6ad7SLin Ling extern void dsl_prop_set_sync(void *, void *, dmu_tx_t *); 337392241e0bSTom Erickson 3374a9799022Sck void 33753f9d6ad7SLin Ling dsl_dataset_set_quota_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3376a9799022Sck { 3377a9799022Sck dsl_dataset_t *ds = arg1; 337892241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 337992241e0bSTom Erickson uint64_t effective_value = psa->psa_effective_value; 3380a9799022Sck 33813f9d6ad7SLin Ling dsl_prop_set_sync(ds, psa, tx); 338292241e0bSTom Erickson DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa); 3383a9799022Sck 338492241e0bSTom Erickson if (ds->ds_quota != effective_value) { 338592241e0bSTom Erickson dmu_buf_will_dirty(ds->ds_dbuf, tx); 338692241e0bSTom Erickson ds->ds_quota = effective_value; 3387a9799022Sck 33883f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_REFQUOTA, 33893f9d6ad7SLin Ling ds->ds_dir->dd_pool->dp_spa, tx, "%lld dataset = %llu ", 339092241e0bSTom Erickson (longlong_t)ds->ds_quota, ds->ds_object); 339192241e0bSTom Erickson } 3392a9799022Sck } 3393a9799022Sck 3394a9799022Sck int 339592241e0bSTom Erickson dsl_dataset_set_quota(const char *dsname, zprop_source_t source, uint64_t quota) 3396a9799022Sck { 3397a9799022Sck dsl_dataset_t *ds; 339892241e0bSTom Erickson dsl_prop_setarg_t psa; 3399a9799022Sck int err; 3400a9799022Sck 340192241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refquota", source, "a); 340292241e0bSTom Erickson 3403745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3404a9799022Sck if (err) 3405a9799022Sck return (err); 3406a9799022Sck 340792241e0bSTom Erickson /* 340892241e0bSTom Erickson * If someone removes a file, then tries to set the quota, we 340992241e0bSTom Erickson * want to make sure the file freeing takes effect. 341092241e0bSTom Erickson */ 341192241e0bSTom Erickson txg_wait_open(ds->ds_dir->dd_pool, 0); 341292241e0bSTom Erickson 341392241e0bSTom Erickson err = dsl_sync_task_do(ds->ds_dir->dd_pool, 341492241e0bSTom Erickson dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, 341592241e0bSTom Erickson ds, &psa, 0); 3416a9799022Sck 3417745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3418a9799022Sck return (err); 3419a9799022Sck } 3420a9799022Sck 3421a9799022Sck static int 3422a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx) 3423a9799022Sck { 3424a9799022Sck dsl_dataset_t *ds = arg1; 342592241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 342692241e0bSTom Erickson uint64_t effective_value; 3427a9799022Sck uint64_t unique; 342892241e0bSTom Erickson int err; 3429a9799022Sck 3430a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 3431a9799022Sck SPA_VERSION_REFRESERVATION) 3432a9799022Sck return (ENOTSUP); 3433a9799022Sck 3434a9799022Sck if (dsl_dataset_is_snapshot(ds)) 3435a9799022Sck return (EINVAL); 3436a9799022Sck 343792241e0bSTom Erickson if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0) 343892241e0bSTom Erickson return (err); 343992241e0bSTom Erickson 344092241e0bSTom Erickson effective_value = psa->psa_effective_value; 344192241e0bSTom Erickson 3442a9799022Sck /* 3443a9799022Sck * If we are doing the preliminary check in open context, the 3444a9799022Sck * space estimates may be inaccurate. 3445a9799022Sck */ 3446a9799022Sck if (!dmu_tx_is_syncing(tx)) 3447a9799022Sck return (0); 3448a9799022Sck 3449a9799022Sck mutex_enter(&ds->ds_lock); 34503f9d6ad7SLin Ling if (!DS_UNIQUE_IS_ACCURATE(ds)) 34513f9d6ad7SLin Ling dsl_dataset_recalc_head_uniq(ds); 34523f9d6ad7SLin Ling unique = ds->ds_phys->ds_unique_bytes; 3453a9799022Sck mutex_exit(&ds->ds_lock); 3454a9799022Sck 345592241e0bSTom Erickson if (MAX(unique, effective_value) > MAX(unique, ds->ds_reserved)) { 345692241e0bSTom Erickson uint64_t delta = MAX(unique, effective_value) - 3457379c004dSEric Schrock MAX(unique, ds->ds_reserved); 3458379c004dSEric Schrock 3459379c004dSEric Schrock if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 3460379c004dSEric Schrock return (ENOSPC); 3461379c004dSEric Schrock if (ds->ds_quota > 0 && 346292241e0bSTom Erickson effective_value > ds->ds_quota) 3463379c004dSEric Schrock return (ENOSPC); 3464379c004dSEric Schrock } 3465a9799022Sck 3466a9799022Sck return (0); 3467a9799022Sck } 3468a9799022Sck 3469a9799022Sck static void 34703f9d6ad7SLin Ling dsl_dataset_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3471a9799022Sck { 3472a9799022Sck dsl_dataset_t *ds = arg1; 347392241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 347492241e0bSTom Erickson uint64_t effective_value = psa->psa_effective_value; 347502c8f3f0SMatthew Ahrens uint64_t unique; 347602c8f3f0SMatthew Ahrens int64_t delta; 347702c8f3f0SMatthew Ahrens 34783f9d6ad7SLin Ling dsl_prop_set_sync(ds, psa, tx); 347992241e0bSTom Erickson DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa); 348092241e0bSTom Erickson 348102c8f3f0SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 348202c8f3f0SMatthew Ahrens 348302c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 348402c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_lock); 34853f9d6ad7SLin Ling ASSERT(DS_UNIQUE_IS_ACCURATE(ds)); 34863f9d6ad7SLin Ling unique = ds->ds_phys->ds_unique_bytes; 348792241e0bSTom Erickson delta = MAX(0, (int64_t)(effective_value - unique)) - 348802c8f3f0SMatthew Ahrens MAX(0, (int64_t)(ds->ds_reserved - unique)); 348992241e0bSTom Erickson ds->ds_reserved = effective_value; 349002c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_lock); 349102c8f3f0SMatthew Ahrens 349202c8f3f0SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx); 349302c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 3494a9799022Sck 34953f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_REFRESERV, 34963f9d6ad7SLin Ling ds->ds_dir->dd_pool->dp_spa, tx, "%lld dataset = %llu", 349792241e0bSTom Erickson (longlong_t)effective_value, ds->ds_object); 3498a9799022Sck } 3499a9799022Sck 3500a9799022Sck int 350192241e0bSTom Erickson dsl_dataset_set_reservation(const char *dsname, zprop_source_t source, 350292241e0bSTom Erickson uint64_t reservation) 3503a9799022Sck { 3504a9799022Sck dsl_dataset_t *ds; 350592241e0bSTom Erickson dsl_prop_setarg_t psa; 3506a9799022Sck int err; 3507a9799022Sck 350892241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refreservation", source, 350992241e0bSTom Erickson &reservation); 351092241e0bSTom Erickson 3511745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3512a9799022Sck if (err) 3513a9799022Sck return (err); 3514a9799022Sck 3515a9799022Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3516a9799022Sck dsl_dataset_set_reservation_check, 351792241e0bSTom Erickson dsl_dataset_set_reservation_sync, ds, &psa, 0); 351892241e0bSTom Erickson 3519745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3520a9799022Sck return (err); 3521a9799022Sck } 3522842727c2SChris Kirby 3523c99e4bdcSChris Kirby typedef struct zfs_hold_cleanup_arg { 3524a7f53a56SChris Kirby dsl_pool_t *dp; 3525a7f53a56SChris Kirby uint64_t dsobj; 3526c99e4bdcSChris Kirby char htag[MAXNAMELEN]; 3527c99e4bdcSChris Kirby } zfs_hold_cleanup_arg_t; 3528c99e4bdcSChris Kirby 3529c99e4bdcSChris Kirby static void 3530c99e4bdcSChris Kirby dsl_dataset_user_release_onexit(void *arg) 3531c99e4bdcSChris Kirby { 3532c99e4bdcSChris Kirby zfs_hold_cleanup_arg_t *ca = arg; 3533c99e4bdcSChris Kirby 3534a7f53a56SChris Kirby (void) dsl_dataset_user_release_tmp(ca->dp, ca->dsobj, ca->htag, 3535a7f53a56SChris Kirby B_TRUE); 3536c99e4bdcSChris Kirby kmem_free(ca, sizeof (zfs_hold_cleanup_arg_t)); 3537c99e4bdcSChris Kirby } 3538c99e4bdcSChris Kirby 3539a7f53a56SChris Kirby void 3540a7f53a56SChris Kirby dsl_register_onexit_hold_cleanup(dsl_dataset_t *ds, const char *htag, 3541a7f53a56SChris Kirby minor_t minor) 3542a7f53a56SChris Kirby { 3543a7f53a56SChris Kirby zfs_hold_cleanup_arg_t *ca; 3544a7f53a56SChris Kirby 3545a7f53a56SChris Kirby ca = kmem_alloc(sizeof (zfs_hold_cleanup_arg_t), KM_SLEEP); 3546a7f53a56SChris Kirby ca->dp = ds->ds_dir->dd_pool; 3547a7f53a56SChris Kirby ca->dsobj = ds->ds_object; 3548a7f53a56SChris Kirby (void) strlcpy(ca->htag, htag, sizeof (ca->htag)); 3549a7f53a56SChris Kirby VERIFY3U(0, ==, zfs_onexit_add_cb(minor, 3550a7f53a56SChris Kirby dsl_dataset_user_release_onexit, ca, NULL)); 3551a7f53a56SChris Kirby } 3552a7f53a56SChris Kirby 355315508ac0SChris Kirby /* 355499d5e173STim Haley * If you add new checks here, you may need to add 355599d5e173STim Haley * additional checks to the "temporary" case in 355699d5e173STim Haley * snapshot_check() in dmu_objset.c. 355715508ac0SChris Kirby */ 3558842727c2SChris Kirby static int 3559842727c2SChris Kirby dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx) 3560842727c2SChris Kirby { 3561842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3562ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 3563ca45db41SChris Kirby char *htag = ha->htag; 3564842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3565842727c2SChris Kirby int error = 0; 3566842727c2SChris Kirby 3567842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3568842727c2SChris Kirby return (ENOTSUP); 3569842727c2SChris Kirby 3570842727c2SChris Kirby if (!dsl_dataset_is_snapshot(ds)) 3571842727c2SChris Kirby return (EINVAL); 3572842727c2SChris Kirby 3573842727c2SChris Kirby /* tags must be unique */ 3574842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3575842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj) { 3576842727c2SChris Kirby error = zap_lookup(mos, ds->ds_phys->ds_userrefs_obj, htag, 3577842727c2SChris Kirby 8, 1, tx); 3578842727c2SChris Kirby if (error == 0) 3579842727c2SChris Kirby error = EEXIST; 3580842727c2SChris Kirby else if (error == ENOENT) 3581842727c2SChris Kirby error = 0; 3582842727c2SChris Kirby } 3583842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3584842727c2SChris Kirby 358515508ac0SChris Kirby if (error == 0 && ha->temphold && 358615508ac0SChris Kirby strlen(htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN) 358715508ac0SChris Kirby error = E2BIG; 358815508ac0SChris Kirby 3589842727c2SChris Kirby return (error); 3590842727c2SChris Kirby } 3591842727c2SChris Kirby 359299d5e173STim Haley void 35933f9d6ad7SLin Ling dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3594842727c2SChris Kirby { 3595842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3596ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 3597ca45db41SChris Kirby char *htag = ha->htag; 3598ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3599ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 360015508ac0SChris Kirby uint64_t now = gethrestime_sec(); 3601842727c2SChris Kirby uint64_t zapobj; 3602842727c2SChris Kirby 3603842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3604842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj == 0) { 3605842727c2SChris Kirby /* 3606842727c2SChris Kirby * This is the first user hold for this dataset. Create 3607842727c2SChris Kirby * the userrefs zap object. 3608842727c2SChris Kirby */ 3609842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 3610842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj = 3611842727c2SChris Kirby zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx); 3612842727c2SChris Kirby } else { 3613842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3614842727c2SChris Kirby } 3615842727c2SChris Kirby ds->ds_userrefs++; 3616842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3617842727c2SChris Kirby 3618842727c2SChris Kirby VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx)); 3619842727c2SChris Kirby 3620ca45db41SChris Kirby if (ha->temphold) { 3621ca45db41SChris Kirby VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object, 3622ca45db41SChris Kirby htag, &now, tx)); 3623ca45db41SChris Kirby } 3624ca45db41SChris Kirby 36253f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_USER_HOLD, 36263f9d6ad7SLin Ling dp->dp_spa, tx, "<%s> temp = %d dataset = %llu", htag, 3627ca45db41SChris Kirby (int)ha->temphold, ds->ds_object); 3628842727c2SChris Kirby } 3629842727c2SChris Kirby 3630842727c2SChris Kirby static int 3631fd136879SMatthew Ahrens dsl_dataset_user_hold_one(const char *dsname, void *arg) 3632842727c2SChris Kirby { 3633842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3634842727c2SChris Kirby dsl_dataset_t *ds; 3635842727c2SChris Kirby int error; 3636842727c2SChris Kirby char *name; 3637842727c2SChris Kirby 3638842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname plus terminating NULL */ 3639ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3640842727c2SChris Kirby error = dsl_dataset_hold(name, ha->dstg, &ds); 3641ae46e4c7SMatthew Ahrens strfree(name); 3642842727c2SChris Kirby if (error == 0) { 3643d7747cbcSChris Kirby ha->gotone = B_TRUE; 3644842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check, 3645ca45db41SChris Kirby dsl_dataset_user_hold_sync, ds, ha, 0); 3646842727c2SChris Kirby } else if (error == ENOENT && ha->recursive) { 3647842727c2SChris Kirby error = 0; 3648842727c2SChris Kirby } else { 3649fd136879SMatthew Ahrens (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3650842727c2SChris Kirby } 3651842727c2SChris Kirby return (error); 3652842727c2SChris Kirby } 3653842727c2SChris Kirby 3654a7f53a56SChris Kirby int 3655a7f53a56SChris Kirby dsl_dataset_user_hold_for_send(dsl_dataset_t *ds, char *htag, 3656a7f53a56SChris Kirby boolean_t temphold) 3657a7f53a56SChris Kirby { 3658a7f53a56SChris Kirby struct dsl_ds_holdarg *ha; 3659a7f53a56SChris Kirby int error; 3660a7f53a56SChris Kirby 3661a7f53a56SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3662a7f53a56SChris Kirby ha->htag = htag; 3663a7f53a56SChris Kirby ha->temphold = temphold; 3664a7f53a56SChris Kirby error = dsl_sync_task_do(ds->ds_dir->dd_pool, 3665a7f53a56SChris Kirby dsl_dataset_user_hold_check, dsl_dataset_user_hold_sync, 3666a7f53a56SChris Kirby ds, ha, 0); 3667a7f53a56SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3668a7f53a56SChris Kirby 3669a7f53a56SChris Kirby return (error); 3670a7f53a56SChris Kirby } 3671a7f53a56SChris Kirby 3672842727c2SChris Kirby int 3673842727c2SChris Kirby dsl_dataset_user_hold(char *dsname, char *snapname, char *htag, 3674c99e4bdcSChris Kirby boolean_t recursive, boolean_t temphold, int cleanup_fd) 3675842727c2SChris Kirby { 3676842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3677842727c2SChris Kirby dsl_sync_task_t *dst; 3678842727c2SChris Kirby spa_t *spa; 3679842727c2SChris Kirby int error; 3680a7f53a56SChris Kirby minor_t minor = 0; 3681a7f53a56SChris Kirby 3682a7f53a56SChris Kirby if (cleanup_fd != -1) { 3683a7f53a56SChris Kirby /* Currently we only support cleanup-on-exit of tempholds. */ 3684a7f53a56SChris Kirby if (!temphold) 3685a7f53a56SChris Kirby return (EINVAL); 3686a7f53a56SChris Kirby error = zfs_onexit_fd_hold(cleanup_fd, &minor); 3687a7f53a56SChris Kirby if (error) 3688a7f53a56SChris Kirby return (error); 3689a7f53a56SChris Kirby } 3690842727c2SChris Kirby 3691842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3692842727c2SChris Kirby 3693842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3694842727c2SChris Kirby 3695842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3696842727c2SChris Kirby if (error) { 3697842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3698a7f53a56SChris Kirby if (cleanup_fd != -1) 3699a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 3700842727c2SChris Kirby return (error); 3701842727c2SChris Kirby } 3702842727c2SChris Kirby 3703842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3704842727c2SChris Kirby ha->htag = htag; 3705842727c2SChris Kirby ha->snapname = snapname; 3706842727c2SChris Kirby ha->recursive = recursive; 3707ca45db41SChris Kirby ha->temphold = temphold; 3708c99e4bdcSChris Kirby 3709842727c2SChris Kirby if (recursive) { 3710842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_hold_one, 3711842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3712842727c2SChris Kirby } else { 3713842727c2SChris Kirby error = dsl_dataset_user_hold_one(dsname, ha); 3714842727c2SChris Kirby } 3715842727c2SChris Kirby if (error == 0) 3716842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3717842727c2SChris Kirby 3718842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3719842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3720842727c2SChris Kirby dsl_dataset_t *ds = dst->dst_arg1; 3721842727c2SChris Kirby 3722842727c2SChris Kirby if (dst->dst_err) { 3723842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3724842727c2SChris Kirby *strchr(ha->failed, '@') = '\0'; 3725a7f53a56SChris Kirby } else if (error == 0 && minor != 0 && temphold) { 3726a7f53a56SChris Kirby /* 3727a7f53a56SChris Kirby * If this hold is to be released upon process exit, 3728a7f53a56SChris Kirby * register that action now. 3729a7f53a56SChris Kirby */ 3730a7f53a56SChris Kirby dsl_register_onexit_hold_cleanup(ds, htag, minor); 3731842727c2SChris Kirby } 3732842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3733842727c2SChris Kirby } 3734842727c2SChris Kirby 3735d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3736d7747cbcSChris Kirby error = ENOENT; 3737d7747cbcSChris Kirby 3738842727c2SChris Kirby if (error) 3739fd136879SMatthew Ahrens (void) strlcpy(dsname, ha->failed, sizeof (ha->failed)); 3740842727c2SChris Kirby 3741842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3742c99e4bdcSChris Kirby 3743842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3744842727c2SChris Kirby spa_close(spa, FTAG); 3745a7f53a56SChris Kirby if (cleanup_fd != -1) 3746a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 3747842727c2SChris Kirby return (error); 3748842727c2SChris Kirby } 3749842727c2SChris Kirby 3750842727c2SChris Kirby struct dsl_ds_releasearg { 3751842727c2SChris Kirby dsl_dataset_t *ds; 3752842727c2SChris Kirby const char *htag; 3753842727c2SChris Kirby boolean_t own; /* do we own or just hold ds? */ 3754842727c2SChris Kirby }; 3755842727c2SChris Kirby 3756842727c2SChris Kirby static int 3757842727c2SChris Kirby dsl_dataset_release_might_destroy(dsl_dataset_t *ds, const char *htag, 3758842727c2SChris Kirby boolean_t *might_destroy) 3759842727c2SChris Kirby { 3760842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3761842727c2SChris Kirby uint64_t zapobj; 3762842727c2SChris Kirby uint64_t tmp; 3763842727c2SChris Kirby int error; 3764842727c2SChris Kirby 3765842727c2SChris Kirby *might_destroy = B_FALSE; 3766842727c2SChris Kirby 3767842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3768842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3769842727c2SChris Kirby if (zapobj == 0) { 3770842727c2SChris Kirby /* The tag can't possibly exist */ 3771842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3772842727c2SChris Kirby return (ESRCH); 3773842727c2SChris Kirby } 3774842727c2SChris Kirby 3775842727c2SChris Kirby /* Make sure the tag exists */ 3776842727c2SChris Kirby error = zap_lookup(mos, zapobj, htag, 8, 1, &tmp); 3777842727c2SChris Kirby if (error) { 3778842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3779842727c2SChris Kirby if (error == ENOENT) 3780842727c2SChris Kirby error = ESRCH; 3781842727c2SChris Kirby return (error); 3782842727c2SChris Kirby } 3783842727c2SChris Kirby 3784842727c2SChris Kirby if (ds->ds_userrefs == 1 && ds->ds_phys->ds_num_children == 1 && 3785842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 3786842727c2SChris Kirby *might_destroy = B_TRUE; 3787842727c2SChris Kirby 3788842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3789842727c2SChris Kirby return (0); 3790842727c2SChris Kirby } 3791842727c2SChris Kirby 3792842727c2SChris Kirby static int 3793842727c2SChris Kirby dsl_dataset_user_release_check(void *arg1, void *tag, dmu_tx_t *tx) 3794842727c2SChris Kirby { 3795842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3796842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3797842727c2SChris Kirby boolean_t might_destroy; 3798842727c2SChris Kirby int error; 3799842727c2SChris Kirby 3800842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3801842727c2SChris Kirby return (ENOTSUP); 3802842727c2SChris Kirby 3803842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ra->htag, &might_destroy); 3804842727c2SChris Kirby if (error) 3805842727c2SChris Kirby return (error); 3806842727c2SChris Kirby 3807842727c2SChris Kirby if (might_destroy) { 3808842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3809842727c2SChris Kirby 3810842727c2SChris Kirby if (dmu_tx_is_syncing(tx)) { 3811842727c2SChris Kirby /* 3812842727c2SChris Kirby * If we're not prepared to remove the snapshot, 3813842727c2SChris Kirby * we can't allow the release to happen right now. 3814842727c2SChris Kirby */ 3815842727c2SChris Kirby if (!ra->own) 3816842727c2SChris Kirby return (EBUSY); 3817842727c2SChris Kirby } 3818842727c2SChris Kirby dsda.ds = ds; 3819842727c2SChris Kirby dsda.releasing = B_TRUE; 3820842727c2SChris Kirby return (dsl_dataset_destroy_check(&dsda, tag, tx)); 3821842727c2SChris Kirby } 3822842727c2SChris Kirby 3823842727c2SChris Kirby return (0); 3824842727c2SChris Kirby } 3825842727c2SChris Kirby 3826842727c2SChris Kirby static void 38273f9d6ad7SLin Ling dsl_dataset_user_release_sync(void *arg1, void *tag, dmu_tx_t *tx) 3828842727c2SChris Kirby { 3829842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3830842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3831ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3832ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 3833842727c2SChris Kirby uint64_t zapobj; 3834842727c2SChris Kirby uint64_t dsobj = ds->ds_object; 3835842727c2SChris Kirby uint64_t refs; 3836ca45db41SChris Kirby int error; 3837842727c2SChris Kirby 3838842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3839842727c2SChris Kirby ds->ds_userrefs--; 3840842727c2SChris Kirby refs = ds->ds_userrefs; 3841842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3842ca45db41SChris Kirby error = dsl_pool_user_release(dp, ds->ds_object, ra->htag, tx); 3843ca45db41SChris Kirby VERIFY(error == 0 || error == ENOENT); 3844842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3845842727c2SChris Kirby VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx)); 3846842727c2SChris Kirby if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 && 3847842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) { 3848842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3849842727c2SChris Kirby 3850842727c2SChris Kirby ASSERT(ra->own); 3851842727c2SChris Kirby dsda.ds = ds; 3852842727c2SChris Kirby dsda.releasing = B_TRUE; 3853842727c2SChris Kirby /* We already did the destroy_check */ 38543f9d6ad7SLin Ling dsl_dataset_destroy_sync(&dsda, tag, tx); 3855842727c2SChris Kirby } 3856842727c2SChris Kirby 38573f9d6ad7SLin Ling spa_history_log_internal(LOG_DS_USER_RELEASE, 38583f9d6ad7SLin Ling dp->dp_spa, tx, "<%s> %lld dataset = %llu", 3859842727c2SChris Kirby ra->htag, (longlong_t)refs, dsobj); 3860842727c2SChris Kirby } 3861842727c2SChris Kirby 3862842727c2SChris Kirby static int 3863fd136879SMatthew Ahrens dsl_dataset_user_release_one(const char *dsname, void *arg) 3864842727c2SChris Kirby { 3865842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3866842727c2SChris Kirby struct dsl_ds_releasearg *ra; 3867842727c2SChris Kirby dsl_dataset_t *ds; 3868842727c2SChris Kirby int error; 3869842727c2SChris Kirby void *dtag = ha->dstg; 3870842727c2SChris Kirby char *name; 3871842727c2SChris Kirby boolean_t own = B_FALSE; 3872842727c2SChris Kirby boolean_t might_destroy; 3873842727c2SChris Kirby 3874842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname, plus the terminating NULL */ 3875ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3876842727c2SChris Kirby error = dsl_dataset_hold(name, dtag, &ds); 3877ae46e4c7SMatthew Ahrens strfree(name); 3878842727c2SChris Kirby if (error == ENOENT && ha->recursive) 3879842727c2SChris Kirby return (0); 3880fd136879SMatthew Ahrens (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3881842727c2SChris Kirby if (error) 3882842727c2SChris Kirby return (error); 3883842727c2SChris Kirby 3884d7747cbcSChris Kirby ha->gotone = B_TRUE; 3885d7747cbcSChris Kirby 3886842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 3887842727c2SChris Kirby 3888842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ha->htag, &might_destroy); 3889842727c2SChris Kirby if (error) { 3890842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3891842727c2SChris Kirby return (error); 3892842727c2SChris Kirby } 3893842727c2SChris Kirby 3894842727c2SChris Kirby if (might_destroy) { 3895842727c2SChris Kirby #ifdef _KERNEL 38965afc78aaSChris Kirby name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3897842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 38985afc78aaSChris Kirby strfree(name); 3899842727c2SChris Kirby if (error) { 3900842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3901842727c2SChris Kirby return (error); 3902842727c2SChris Kirby } 3903842727c2SChris Kirby #endif 3904503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(ds, B_TRUE, dtag)) { 3905842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3906842727c2SChris Kirby return (EBUSY); 3907842727c2SChris Kirby } else { 3908842727c2SChris Kirby own = B_TRUE; 3909842727c2SChris Kirby dsl_dataset_make_exclusive(ds, dtag); 3910842727c2SChris Kirby } 3911842727c2SChris Kirby } 3912842727c2SChris Kirby 3913842727c2SChris Kirby ra = kmem_alloc(sizeof (struct dsl_ds_releasearg), KM_SLEEP); 3914842727c2SChris Kirby ra->ds = ds; 3915842727c2SChris Kirby ra->htag = ha->htag; 3916842727c2SChris Kirby ra->own = own; 3917842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_release_check, 3918842727c2SChris Kirby dsl_dataset_user_release_sync, ra, dtag, 0); 3919842727c2SChris Kirby 3920842727c2SChris Kirby return (0); 3921842727c2SChris Kirby } 3922842727c2SChris Kirby 3923842727c2SChris Kirby int 3924842727c2SChris Kirby dsl_dataset_user_release(char *dsname, char *snapname, char *htag, 3925842727c2SChris Kirby boolean_t recursive) 3926842727c2SChris Kirby { 3927842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3928842727c2SChris Kirby dsl_sync_task_t *dst; 3929842727c2SChris Kirby spa_t *spa; 3930842727c2SChris Kirby int error; 3931842727c2SChris Kirby 3932620252bcSChris Kirby top: 3933842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3934842727c2SChris Kirby 3935842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3936842727c2SChris Kirby 3937842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3938842727c2SChris Kirby if (error) { 3939842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3940842727c2SChris Kirby return (error); 3941842727c2SChris Kirby } 3942842727c2SChris Kirby 3943842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3944842727c2SChris Kirby ha->htag = htag; 3945842727c2SChris Kirby ha->snapname = snapname; 3946842727c2SChris Kirby ha->recursive = recursive; 3947842727c2SChris Kirby if (recursive) { 3948842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_release_one, 3949842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3950842727c2SChris Kirby } else { 3951842727c2SChris Kirby error = dsl_dataset_user_release_one(dsname, ha); 3952842727c2SChris Kirby } 3953842727c2SChris Kirby if (error == 0) 3954842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3955842727c2SChris Kirby 3956842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3957842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3958842727c2SChris Kirby struct dsl_ds_releasearg *ra = dst->dst_arg1; 3959842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3960842727c2SChris Kirby 3961842727c2SChris Kirby if (dst->dst_err) 3962842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3963842727c2SChris Kirby 3964842727c2SChris Kirby if (ra->own) 3965842727c2SChris Kirby dsl_dataset_disown(ds, ha->dstg); 3966842727c2SChris Kirby else 3967842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3968842727c2SChris Kirby 3969842727c2SChris Kirby kmem_free(ra, sizeof (struct dsl_ds_releasearg)); 3970842727c2SChris Kirby } 3971842727c2SChris Kirby 3972d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3973d7747cbcSChris Kirby error = ENOENT; 3974d7747cbcSChris Kirby 3975620252bcSChris Kirby if (error && error != EBUSY) 3976fd136879SMatthew Ahrens (void) strlcpy(dsname, ha->failed, sizeof (ha->failed)); 3977842727c2SChris Kirby 3978842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3979842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3980842727c2SChris Kirby spa_close(spa, FTAG); 3981620252bcSChris Kirby 3982620252bcSChris Kirby /* 3983620252bcSChris Kirby * We can get EBUSY if we were racing with deferred destroy and 3984620252bcSChris Kirby * dsl_dataset_user_release_check() hadn't done the necessary 3985620252bcSChris Kirby * open context setup. We can also get EBUSY if we're racing 3986620252bcSChris Kirby * with destroy and that thread is the ds_owner. Either way 3987620252bcSChris Kirby * the busy condition should be transient, and we should retry 3988620252bcSChris Kirby * the release operation. 3989620252bcSChris Kirby */ 3990620252bcSChris Kirby if (error == EBUSY) 3991620252bcSChris Kirby goto top; 3992620252bcSChris Kirby 3993842727c2SChris Kirby return (error); 3994842727c2SChris Kirby } 3995842727c2SChris Kirby 3996ca45db41SChris Kirby /* 3997a7f53a56SChris Kirby * Called at spa_load time (with retry == B_FALSE) to release a stale 3998a7f53a56SChris Kirby * temporary user hold. Also called by the onexit code (with retry == B_TRUE). 3999ca45db41SChris Kirby */ 4000ca45db41SChris Kirby int 4001a7f53a56SChris Kirby dsl_dataset_user_release_tmp(dsl_pool_t *dp, uint64_t dsobj, char *htag, 4002a7f53a56SChris Kirby boolean_t retry) 4003ca45db41SChris Kirby { 4004ca45db41SChris Kirby dsl_dataset_t *ds; 4005ca45db41SChris Kirby char *snap; 4006ca45db41SChris Kirby char *name; 4007ca45db41SChris Kirby int namelen; 4008ca45db41SChris Kirby int error; 4009ca45db41SChris Kirby 4010a7f53a56SChris Kirby do { 4011a7f53a56SChris Kirby rw_enter(&dp->dp_config_rwlock, RW_READER); 4012a7f53a56SChris Kirby error = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds); 4013a7f53a56SChris Kirby rw_exit(&dp->dp_config_rwlock); 4014a7f53a56SChris Kirby if (error) 4015a7f53a56SChris Kirby return (error); 4016a7f53a56SChris Kirby namelen = dsl_dataset_namelen(ds)+1; 4017a7f53a56SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 4018a7f53a56SChris Kirby dsl_dataset_name(ds, name); 4019a7f53a56SChris Kirby dsl_dataset_rele(ds, FTAG); 4020ca45db41SChris Kirby 4021a7f53a56SChris Kirby snap = strchr(name, '@'); 4022a7f53a56SChris Kirby *snap = '\0'; 4023a7f53a56SChris Kirby ++snap; 4024a7f53a56SChris Kirby error = dsl_dataset_user_release(name, snap, htag, B_FALSE); 4025a7f53a56SChris Kirby kmem_free(name, namelen); 4026a7f53a56SChris Kirby 4027a7f53a56SChris Kirby /* 4028a7f53a56SChris Kirby * The object can't have been destroyed because we have a hold, 4029a7f53a56SChris Kirby * but it might have been renamed, resulting in ENOENT. Retry 4030a7f53a56SChris Kirby * if we've been requested to do so. 4031a7f53a56SChris Kirby * 4032a7f53a56SChris Kirby * It would be nice if we could use the dsobj all the way 4033a7f53a56SChris Kirby * through and avoid ENOENT entirely. But we might need to 4034a7f53a56SChris Kirby * unmount the snapshot, and there's currently no way to lookup 4035a7f53a56SChris Kirby * a vfsp using a ZFS object id. 4036a7f53a56SChris Kirby */ 4037a7f53a56SChris Kirby } while ((error == ENOENT) && retry); 4038a7f53a56SChris Kirby 4039a7f53a56SChris Kirby return (error); 4040ca45db41SChris Kirby } 4041ca45db41SChris Kirby 4042842727c2SChris Kirby int 4043842727c2SChris Kirby dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp) 4044842727c2SChris Kirby { 4045842727c2SChris Kirby dsl_dataset_t *ds; 4046842727c2SChris Kirby int err; 4047842727c2SChris Kirby 4048842727c2SChris Kirby err = dsl_dataset_hold(dsname, FTAG, &ds); 4049842727c2SChris Kirby if (err) 4050842727c2SChris Kirby return (err); 4051842727c2SChris Kirby 4052842727c2SChris Kirby VERIFY(0 == nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP)); 4053842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) { 4054842727c2SChris Kirby zap_attribute_t *za; 4055842727c2SChris Kirby zap_cursor_t zc; 4056842727c2SChris Kirby 4057842727c2SChris Kirby za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 4058842727c2SChris Kirby for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset, 4059842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj); 4060842727c2SChris Kirby zap_cursor_retrieve(&zc, za) == 0; 4061842727c2SChris Kirby zap_cursor_advance(&zc)) { 4062842727c2SChris Kirby VERIFY(0 == nvlist_add_uint64(*nvp, za->za_name, 4063842727c2SChris Kirby za->za_first_integer)); 4064842727c2SChris Kirby } 4065842727c2SChris Kirby zap_cursor_fini(&zc); 4066842727c2SChris Kirby kmem_free(za, sizeof (zap_attribute_t)); 4067842727c2SChris Kirby } 4068842727c2SChris Kirby dsl_dataset_rele(ds, FTAG); 4069842727c2SChris Kirby return (0); 4070842727c2SChris Kirby } 4071503ad85cSMatthew Ahrens 4072503ad85cSMatthew Ahrens /* 4073*19b94df9SMatthew Ahrens * Note, this function is used as the callback for dmu_objset_find(). We 4074503ad85cSMatthew Ahrens * always return 0 so that we will continue to find and process 4075503ad85cSMatthew Ahrens * inconsistent datasets, even if we encounter an error trying to 4076503ad85cSMatthew Ahrens * process one of them. 4077503ad85cSMatthew Ahrens */ 4078503ad85cSMatthew Ahrens /* ARGSUSED */ 4079503ad85cSMatthew Ahrens int 4080fd136879SMatthew Ahrens dsl_destroy_inconsistent(const char *dsname, void *arg) 4081503ad85cSMatthew Ahrens { 4082503ad85cSMatthew Ahrens dsl_dataset_t *ds; 4083503ad85cSMatthew Ahrens 4084503ad85cSMatthew Ahrens if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) { 4085503ad85cSMatthew Ahrens if (DS_IS_INCONSISTENT(ds)) 4086503ad85cSMatthew Ahrens (void) dsl_dataset_destroy(ds, FTAG, B_FALSE); 4087503ad85cSMatthew Ahrens else 4088503ad85cSMatthew Ahrens dsl_dataset_disown(ds, FTAG); 4089503ad85cSMatthew Ahrens } 4090503ad85cSMatthew Ahrens return (0); 4091503ad85cSMatthew Ahrens } 4092*19b94df9SMatthew Ahrens 4093*19b94df9SMatthew Ahrens /* 4094*19b94df9SMatthew Ahrens * Return (in *usedp) the amount of space written in new that is not 4095*19b94df9SMatthew Ahrens * present in oldsnap. New may be a snapshot or the head. Old must be 4096*19b94df9SMatthew Ahrens * a snapshot before new, in new's filesystem (or its origin). If not then 4097*19b94df9SMatthew Ahrens * fail and return EINVAL. 4098*19b94df9SMatthew Ahrens * 4099*19b94df9SMatthew Ahrens * The written space is calculated by considering two components: First, we 4100*19b94df9SMatthew Ahrens * ignore any freed space, and calculate the written as new's used space 4101*19b94df9SMatthew Ahrens * minus old's used space. Next, we add in the amount of space that was freed 4102*19b94df9SMatthew Ahrens * between the two snapshots, thus reducing new's used space relative to old's. 4103*19b94df9SMatthew Ahrens * Specifically, this is the space that was born before old->ds_creation_txg, 4104*19b94df9SMatthew Ahrens * and freed before new (ie. on new's deadlist or a previous deadlist). 4105*19b94df9SMatthew Ahrens * 4106*19b94df9SMatthew Ahrens * space freed [---------------------] 4107*19b94df9SMatthew Ahrens * snapshots ---O-------O--------O-------O------ 4108*19b94df9SMatthew Ahrens * oldsnap new 4109*19b94df9SMatthew Ahrens */ 4110*19b94df9SMatthew Ahrens int 4111*19b94df9SMatthew Ahrens dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new, 4112*19b94df9SMatthew Ahrens uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) 4113*19b94df9SMatthew Ahrens { 4114*19b94df9SMatthew Ahrens int err = 0; 4115*19b94df9SMatthew Ahrens uint64_t snapobj; 4116*19b94df9SMatthew Ahrens dsl_pool_t *dp = new->ds_dir->dd_pool; 4117*19b94df9SMatthew Ahrens 4118*19b94df9SMatthew Ahrens *usedp = 0; 4119*19b94df9SMatthew Ahrens *usedp += new->ds_phys->ds_used_bytes; 4120*19b94df9SMatthew Ahrens *usedp -= oldsnap->ds_phys->ds_used_bytes; 4121*19b94df9SMatthew Ahrens 4122*19b94df9SMatthew Ahrens *compp = 0; 4123*19b94df9SMatthew Ahrens *compp += new->ds_phys->ds_compressed_bytes; 4124*19b94df9SMatthew Ahrens *compp -= oldsnap->ds_phys->ds_compressed_bytes; 4125*19b94df9SMatthew Ahrens 4126*19b94df9SMatthew Ahrens *uncompp = 0; 4127*19b94df9SMatthew Ahrens *uncompp += new->ds_phys->ds_uncompressed_bytes; 4128*19b94df9SMatthew Ahrens *uncompp -= oldsnap->ds_phys->ds_uncompressed_bytes; 4129*19b94df9SMatthew Ahrens 4130*19b94df9SMatthew Ahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 4131*19b94df9SMatthew Ahrens snapobj = new->ds_object; 4132*19b94df9SMatthew Ahrens while (snapobj != oldsnap->ds_object) { 4133*19b94df9SMatthew Ahrens dsl_dataset_t *snap; 4134*19b94df9SMatthew Ahrens uint64_t used, comp, uncomp; 4135*19b94df9SMatthew Ahrens 4136*19b94df9SMatthew Ahrens err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snap); 4137*19b94df9SMatthew Ahrens if (err != 0) 4138*19b94df9SMatthew Ahrens break; 4139*19b94df9SMatthew Ahrens 4140*19b94df9SMatthew Ahrens if (snap->ds_phys->ds_prev_snap_txg == 4141*19b94df9SMatthew Ahrens oldsnap->ds_phys->ds_creation_txg) { 4142*19b94df9SMatthew Ahrens /* 4143*19b94df9SMatthew Ahrens * The blocks in the deadlist can not be born after 4144*19b94df9SMatthew Ahrens * ds_prev_snap_txg, so get the whole deadlist space, 4145*19b94df9SMatthew Ahrens * which is more efficient (especially for old-format 4146*19b94df9SMatthew Ahrens * deadlists). Unfortunately the deadlist code 4147*19b94df9SMatthew Ahrens * doesn't have enough information to make this 4148*19b94df9SMatthew Ahrens * optimization itself. 4149*19b94df9SMatthew Ahrens */ 4150*19b94df9SMatthew Ahrens dsl_deadlist_space(&snap->ds_deadlist, 4151*19b94df9SMatthew Ahrens &used, &comp, &uncomp); 4152*19b94df9SMatthew Ahrens } else { 4153*19b94df9SMatthew Ahrens dsl_deadlist_space_range(&snap->ds_deadlist, 4154*19b94df9SMatthew Ahrens 0, oldsnap->ds_phys->ds_creation_txg, 4155*19b94df9SMatthew Ahrens &used, &comp, &uncomp); 4156*19b94df9SMatthew Ahrens } 4157*19b94df9SMatthew Ahrens *usedp += used; 4158*19b94df9SMatthew Ahrens *compp += comp; 4159*19b94df9SMatthew Ahrens *uncompp += uncomp; 4160*19b94df9SMatthew Ahrens 4161*19b94df9SMatthew Ahrens /* 4162*19b94df9SMatthew Ahrens * If we get to the beginning of the chain of snapshots 4163*19b94df9SMatthew Ahrens * (ds_prev_snap_obj == 0) before oldsnap, then oldsnap 4164*19b94df9SMatthew Ahrens * was not a snapshot of/before new. 4165*19b94df9SMatthew Ahrens */ 4166*19b94df9SMatthew Ahrens snapobj = snap->ds_phys->ds_prev_snap_obj; 4167*19b94df9SMatthew Ahrens dsl_dataset_rele(snap, FTAG); 4168*19b94df9SMatthew Ahrens if (snapobj == 0) { 4169*19b94df9SMatthew Ahrens err = EINVAL; 4170*19b94df9SMatthew Ahrens break; 4171*19b94df9SMatthew Ahrens } 4172*19b94df9SMatthew Ahrens 4173*19b94df9SMatthew Ahrens } 4174*19b94df9SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 4175*19b94df9SMatthew Ahrens return (err); 4176*19b94df9SMatthew Ahrens } 4177*19b94df9SMatthew Ahrens 4178*19b94df9SMatthew Ahrens /* 4179*19b94df9SMatthew Ahrens * Return (in *usedp) the amount of space that will be reclaimed if firstsnap, 4180*19b94df9SMatthew Ahrens * lastsnap, and all snapshots in between are deleted. 4181*19b94df9SMatthew Ahrens * 4182*19b94df9SMatthew Ahrens * blocks that would be freed [---------------------------] 4183*19b94df9SMatthew Ahrens * snapshots ---O-------O--------O-------O--------O 4184*19b94df9SMatthew Ahrens * firstsnap lastsnap 4185*19b94df9SMatthew Ahrens * 4186*19b94df9SMatthew Ahrens * This is the set of blocks that were born after the snap before firstsnap, 4187*19b94df9SMatthew Ahrens * (birth > firstsnap->prev_snap_txg) and died before the snap after the 4188*19b94df9SMatthew Ahrens * last snap (ie, is on lastsnap->ds_next->ds_deadlist or an earlier deadlist). 4189*19b94df9SMatthew Ahrens * We calculate this by iterating over the relevant deadlists (from the snap 4190*19b94df9SMatthew Ahrens * after lastsnap, backward to the snap after firstsnap), summing up the 4191*19b94df9SMatthew Ahrens * space on the deadlist that was born after the snap before firstsnap. 4192*19b94df9SMatthew Ahrens */ 4193*19b94df9SMatthew Ahrens int 4194*19b94df9SMatthew Ahrens dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, 4195*19b94df9SMatthew Ahrens dsl_dataset_t *lastsnap, 4196*19b94df9SMatthew Ahrens uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) 4197*19b94df9SMatthew Ahrens { 4198*19b94df9SMatthew Ahrens int err = 0; 4199*19b94df9SMatthew Ahrens uint64_t snapobj; 4200*19b94df9SMatthew Ahrens dsl_pool_t *dp = firstsnap->ds_dir->dd_pool; 4201*19b94df9SMatthew Ahrens 4202*19b94df9SMatthew Ahrens ASSERT(dsl_dataset_is_snapshot(firstsnap)); 4203*19b94df9SMatthew Ahrens ASSERT(dsl_dataset_is_snapshot(lastsnap)); 4204*19b94df9SMatthew Ahrens 4205*19b94df9SMatthew Ahrens /* 4206*19b94df9SMatthew Ahrens * Check that the snapshots are in the same dsl_dir, and firstsnap 4207*19b94df9SMatthew Ahrens * is before lastsnap. 4208*19b94df9SMatthew Ahrens */ 4209*19b94df9SMatthew Ahrens if (firstsnap->ds_dir != lastsnap->ds_dir || 4210*19b94df9SMatthew Ahrens firstsnap->ds_phys->ds_creation_txg > 4211*19b94df9SMatthew Ahrens lastsnap->ds_phys->ds_creation_txg) 4212*19b94df9SMatthew Ahrens return (EINVAL); 4213*19b94df9SMatthew Ahrens 4214*19b94df9SMatthew Ahrens *usedp = *compp = *uncompp = 0; 4215*19b94df9SMatthew Ahrens 4216*19b94df9SMatthew Ahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 4217*19b94df9SMatthew Ahrens snapobj = lastsnap->ds_phys->ds_next_snap_obj; 4218*19b94df9SMatthew Ahrens while (snapobj != firstsnap->ds_object) { 4219*19b94df9SMatthew Ahrens dsl_dataset_t *ds; 4220*19b94df9SMatthew Ahrens uint64_t used, comp, uncomp; 4221*19b94df9SMatthew Ahrens 4222*19b94df9SMatthew Ahrens err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &ds); 4223*19b94df9SMatthew Ahrens if (err != 0) 4224*19b94df9SMatthew Ahrens break; 4225*19b94df9SMatthew Ahrens 4226*19b94df9SMatthew Ahrens dsl_deadlist_space_range(&ds->ds_deadlist, 4227*19b94df9SMatthew Ahrens firstsnap->ds_phys->ds_prev_snap_txg, UINT64_MAX, 4228*19b94df9SMatthew Ahrens &used, &comp, &uncomp); 4229*19b94df9SMatthew Ahrens *usedp += used; 4230*19b94df9SMatthew Ahrens *compp += comp; 4231*19b94df9SMatthew Ahrens *uncompp += uncomp; 4232*19b94df9SMatthew Ahrens 4233*19b94df9SMatthew Ahrens snapobj = ds->ds_phys->ds_prev_snap_obj; 4234*19b94df9SMatthew Ahrens ASSERT3U(snapobj, !=, 0); 4235*19b94df9SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 4236*19b94df9SMatthew Ahrens } 4237*19b94df9SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 4238*19b94df9SMatthew Ahrens return (err); 4239*19b94df9SMatthew Ahrens } 4240