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. 23ad135b5dSChristopher Siden * Copyright (c) 2012 by Delphix. All rights reserved. 244e3c9f44SBill Pijewski * Copyright (c) 2012, Joyent, Inc. All rights reserved. 25fa9e4066Sahrens */ 26fa9e4066Sahrens 27fa9e4066Sahrens #include <sys/dmu_objset.h> 28fa9e4066Sahrens #include <sys/dsl_dataset.h> 29fa9e4066Sahrens #include <sys/dsl_dir.h> 3099653d4eSeschrock #include <sys/dsl_prop.h> 311d452cf5Sahrens #include <sys/dsl_synctask.h> 32fa9e4066Sahrens #include <sys/dmu_traverse.h> 334e3c9f44SBill Pijewski #include <sys/dmu_impl.h> 34fa9e4066Sahrens #include <sys/dmu_tx.h> 35fa9e4066Sahrens #include <sys/arc.h> 36fa9e4066Sahrens #include <sys/zio.h> 37fa9e4066Sahrens #include <sys/zap.h> 38ad135b5dSChristopher Siden #include <sys/zfeature.h> 39fa9e4066Sahrens #include <sys/unique.h> 40fa9e4066Sahrens #include <sys/zfs_context.h> 41cdf5b4caSmmusante #include <sys/zfs_ioctl.h> 42ecd6cf80Smarks #include <sys/spa.h> 43088f3894Sahrens #include <sys/zfs_znode.h> 44c99e4bdcSChris Kirby #include <sys/zfs_onexit.h> 45842727c2SChris Kirby #include <sys/zvol.h> 463f9d6ad7SLin Ling #include <sys/dsl_scan.h> 47cde58dbcSMatthew Ahrens #include <sys/dsl_deadlist.h> 48fa9e4066Sahrens 49745cd3c5Smaybee static char *dsl_reaper = "the grim reaper"; 50745cd3c5Smaybee 511d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 521d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 53a9799022Sck static dsl_syncfunc_t dsl_dataset_set_reservation_sync; 54e1930233Sbonwick 55cde58dbcSMatthew Ahrens #define SWITCH64(x, y) \ 56cde58dbcSMatthew Ahrens { \ 57cde58dbcSMatthew Ahrens uint64_t __tmp = (x); \ 58cde58dbcSMatthew Ahrens (x) = (y); \ 59cde58dbcSMatthew Ahrens (y) = __tmp; \ 60cde58dbcSMatthew Ahrens } 61cde58dbcSMatthew Ahrens 6255434c77Sek #define DS_REF_MAX (1ULL << 62) 63fa9e4066Sahrens 64fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 65fa9e4066Sahrens 66745cd3c5Smaybee #define DSL_DATASET_IS_DESTROYED(ds) ((ds)->ds_owner == dsl_reaper) 67745cd3c5Smaybee 68fa9e4066Sahrens 69a9799022Sck /* 70a9799022Sck * Figure out how much of this delta should be propogated to the dsl_dir 71a9799022Sck * layer. If there's a refreservation, that space has already been 72a9799022Sck * partially accounted for in our ancestors. 73a9799022Sck */ 74a9799022Sck static int64_t 75a9799022Sck parent_delta(dsl_dataset_t *ds, int64_t delta) 76a9799022Sck { 77a9799022Sck uint64_t old_bytes, new_bytes; 78a9799022Sck 79a9799022Sck if (ds->ds_reserved == 0) 80a9799022Sck return (delta); 81a9799022Sck 82a9799022Sck old_bytes = MAX(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 83a9799022Sck new_bytes = MAX(ds->ds_phys->ds_unique_bytes + delta, ds->ds_reserved); 84a9799022Sck 85a9799022Sck ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta)); 86a9799022Sck return (new_bytes - old_bytes); 87a9799022Sck } 88fa9e4066Sahrens 89fa9e4066Sahrens void 90b24ab676SJeff Bonwick dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx) 91fa9e4066Sahrens { 92b24ab676SJeff Bonwick int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp); 93fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 94fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 95a9799022Sck int64_t delta; 96fa9e4066Sahrens 973f9d6ad7SLin Ling dprintf_bp(bp, "ds=%p", ds); 98fa9e4066Sahrens 99fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 100fa9e4066Sahrens /* It could have been compressed away to nothing */ 101fa9e4066Sahrens if (BP_IS_HOLE(bp)) 102fa9e4066Sahrens return; 103fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 104ad135b5dSChristopher Siden ASSERT(DMU_OT_IS_VALID(BP_GET_TYPE(bp))); 105fa9e4066Sahrens if (ds == NULL) { 106*ce636f8bSMatthew Ahrens dsl_pool_mos_diduse_space(tx->tx_pool, 107*ce636f8bSMatthew Ahrens used, compressed, uncompressed); 108fa9e4066Sahrens return; 109fa9e4066Sahrens } 110fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1113f9d6ad7SLin Ling 11202c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 113fa9e4066Sahrens mutex_enter(&ds->ds_lock); 114a9799022Sck delta = parent_delta(ds, used); 115ad135b5dSChristopher Siden ds->ds_phys->ds_referenced_bytes += used; 116fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 117fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 118fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 119fa9e4066Sahrens mutex_exit(&ds->ds_lock); 12074e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, 12174e7dc98SMatthew Ahrens compressed, uncompressed, tx); 12274e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used - delta, 12374e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 12402c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 125fa9e4066Sahrens } 126fa9e4066Sahrens 127cdb0ab79Smaybee int 128b24ab676SJeff Bonwick dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx, 129b24ab676SJeff Bonwick boolean_t async) 130fa9e4066Sahrens { 131fa9e4066Sahrens if (BP_IS_HOLE(bp)) 132cdb0ab79Smaybee return (0); 133fa9e4066Sahrens 134b24ab676SJeff Bonwick ASSERT(dmu_tx_is_syncing(tx)); 135b24ab676SJeff Bonwick ASSERT(bp->blk_birth <= tx->tx_txg); 136b24ab676SJeff Bonwick 137b24ab676SJeff Bonwick int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp); 138b24ab676SJeff Bonwick int compressed = BP_GET_PSIZE(bp); 139b24ab676SJeff Bonwick int uncompressed = BP_GET_UCSIZE(bp); 140b24ab676SJeff Bonwick 141fa9e4066Sahrens ASSERT(used > 0); 142fa9e4066Sahrens if (ds == NULL) { 143b24ab676SJeff Bonwick dsl_free(tx->tx_pool, tx->tx_txg, bp); 144*ce636f8bSMatthew Ahrens dsl_pool_mos_diduse_space(tx->tx_pool, 145*ce636f8bSMatthew Ahrens -used, -compressed, -uncompressed); 146cdb0ab79Smaybee return (used); 147fa9e4066Sahrens } 148fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 149fa9e4066Sahrens 15074e7dc98SMatthew Ahrens ASSERT(!dsl_dataset_is_snapshot(ds)); 151fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 152fa9e4066Sahrens 153fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 154a9799022Sck int64_t delta; 155c717a561Smaybee 1563f9d6ad7SLin Ling dprintf_bp(bp, "freeing ds=%llu", ds->ds_object); 157b24ab676SJeff Bonwick dsl_free(tx->tx_pool, tx->tx_txg, bp); 158fa9e4066Sahrens 15902c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 160fa9e4066Sahrens mutex_enter(&ds->ds_lock); 161a9799022Sck ASSERT(ds->ds_phys->ds_unique_bytes >= used || 162a9799022Sck !DS_UNIQUE_IS_ACCURATE(ds)); 163a9799022Sck delta = parent_delta(ds, -used); 164fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 165fa9e4066Sahrens mutex_exit(&ds->ds_lock); 16674e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 167a9799022Sck delta, -compressed, -uncompressed, tx); 16874e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, -used - delta, 16974e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 17002c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 171fa9e4066Sahrens } else { 172fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 173b24ab676SJeff Bonwick if (async) { 174b24ab676SJeff Bonwick /* 175b24ab676SJeff Bonwick * We are here as part of zio's write done callback, 176b24ab676SJeff Bonwick * which means we're a zio interrupt thread. We can't 177cde58dbcSMatthew Ahrens * call dsl_deadlist_insert() now because it may block 178b24ab676SJeff Bonwick * waiting for I/O. Instead, put bp on the deferred 179b24ab676SJeff Bonwick * queue and let dsl_pool_sync() finish the job. 180b24ab676SJeff Bonwick */ 181cde58dbcSMatthew Ahrens bplist_append(&ds->ds_pending_deadlist, bp); 182b24ab676SJeff Bonwick } else { 183cde58dbcSMatthew Ahrens dsl_deadlist_insert(&ds->ds_deadlist, bp, tx); 184b24ab676SJeff Bonwick } 185a4611edeSahrens ASSERT3U(ds->ds_prev->ds_object, ==, 186a4611edeSahrens ds->ds_phys->ds_prev_snap_obj); 187a4611edeSahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 188fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 189a4611edeSahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 190a4611edeSahrens ds->ds_object && bp->blk_birth > 191a4611edeSahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 192a4611edeSahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 193a4611edeSahrens mutex_enter(&ds->ds_prev->ds_lock); 194a4611edeSahrens ds->ds_prev->ds_phys->ds_unique_bytes += used; 195a4611edeSahrens mutex_exit(&ds->ds_prev->ds_lock); 196fa9e4066Sahrens } 1973f9d6ad7SLin Ling if (bp->blk_birth > ds->ds_dir->dd_origin_txg) { 19874e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used, 19974e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 20074e7dc98SMatthew Ahrens } 201fa9e4066Sahrens } 202fa9e4066Sahrens mutex_enter(&ds->ds_lock); 203ad135b5dSChristopher Siden ASSERT3U(ds->ds_phys->ds_referenced_bytes, >=, used); 204ad135b5dSChristopher Siden ds->ds_phys->ds_referenced_bytes -= used; 205fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 206fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 207fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 208fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 209fa9e4066Sahrens mutex_exit(&ds->ds_lock); 210cdb0ab79Smaybee 211cdb0ab79Smaybee return (used); 212fa9e4066Sahrens } 213fa9e4066Sahrens 214ea8dc4b6Seschrock uint64_t 215ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 216fa9e4066Sahrens { 217a2eea2e1Sahrens uint64_t trysnap = 0; 218a2eea2e1Sahrens 219fa9e4066Sahrens if (ds == NULL) 220ea8dc4b6Seschrock return (0); 221fa9e4066Sahrens /* 222fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 223fa9e4066Sahrens * incorrect FALSE return, which would only result in an 224fa9e4066Sahrens * overestimation of the amount of space that an operation would 225fa9e4066Sahrens * consume, which is OK. 226fa9e4066Sahrens * 227fa9e4066Sahrens * There's also a small window where we could miss a pending 228fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 229fa9e4066Sahrens * phase. So this should only be used as a guess. 230fa9e4066Sahrens */ 231a2eea2e1Sahrens if (ds->ds_trysnap_txg > 232a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 233a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 234a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 235ea8dc4b6Seschrock } 236ea8dc4b6Seschrock 2373d692628SSanjeev Bagewadi boolean_t 238c7cd2421SGeorge Wilson dsl_dataset_block_freeable(dsl_dataset_t *ds, const blkptr_t *bp, 239c7cd2421SGeorge Wilson uint64_t blk_birth) 240ea8dc4b6Seschrock { 241c7cd2421SGeorge Wilson if (blk_birth <= dsl_dataset_prev_snap_txg(ds)) 242c7cd2421SGeorge Wilson return (B_FALSE); 243c7cd2421SGeorge Wilson 244837b568bSGeorge Wilson ddt_prefetch(dsl_dataset_get_spa(ds), bp); 245c7cd2421SGeorge Wilson 246c7cd2421SGeorge Wilson return (B_TRUE); 247fa9e4066Sahrens } 248fa9e4066Sahrens 249fa9e4066Sahrens /* ARGSUSED */ 250fa9e4066Sahrens static void 251fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 252fa9e4066Sahrens { 253fa9e4066Sahrens dsl_dataset_t *ds = dsv; 254fa9e4066Sahrens 255745cd3c5Smaybee ASSERT(ds->ds_owner == NULL || DSL_DATASET_IS_DESTROYED(ds)); 256fa9e4066Sahrens 25791ebeef5Sahrens unique_remove(ds->ds_fsid_guid); 258fa9e4066Sahrens 259503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) 260503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 261fa9e4066Sahrens 262fa9e4066Sahrens if (ds->ds_prev) { 263745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 264fa9e4066Sahrens ds->ds_prev = NULL; 265fa9e4066Sahrens } 266fa9e4066Sahrens 267cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 268cde58dbcSMatthew Ahrens if (db != NULL) { 269cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 270cde58dbcSMatthew Ahrens } else { 271cde58dbcSMatthew Ahrens ASSERT(ds->ds_deadlist.dl_dbuf == NULL); 272cde58dbcSMatthew Ahrens ASSERT(!ds->ds_deadlist.dl_oldfmt); 273cde58dbcSMatthew Ahrens } 274745cd3c5Smaybee if (ds->ds_dir) 275745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 276fa9e4066Sahrens 27791ebeef5Sahrens ASSERT(!list_link_active(&ds->ds_synced_link)); 278fa9e4066Sahrens 2795ad82045Snd mutex_destroy(&ds->ds_lock); 280f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 28191ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 282745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 283745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 2845ad82045Snd 285fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 286fa9e4066Sahrens } 287fa9e4066Sahrens 288ea8dc4b6Seschrock static int 289fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 290fa9e4066Sahrens { 291fa9e4066Sahrens dsl_dataset_phys_t *headphys; 292fa9e4066Sahrens int err; 293fa9e4066Sahrens dmu_buf_t *headdbuf; 294fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 295fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 296fa9e4066Sahrens 297fa9e4066Sahrens if (ds->ds_snapname[0]) 298ea8dc4b6Seschrock return (0); 299fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 300ea8dc4b6Seschrock return (0); 301fa9e4066Sahrens 302ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 303ea8dc4b6Seschrock FTAG, &headdbuf); 304ea8dc4b6Seschrock if (err) 305ea8dc4b6Seschrock return (err); 306fa9e4066Sahrens headphys = headdbuf->db_data; 307fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 308e7437265Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); 309ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 310ea8dc4b6Seschrock return (err); 311fa9e4066Sahrens } 312fa9e4066Sahrens 313ab04eb8eStimh static int 314745cd3c5Smaybee dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value) 315ab04eb8eStimh { 316745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 317745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 318ab04eb8eStimh matchtype_t mt; 319ab04eb8eStimh int err; 320ab04eb8eStimh 321745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 322ab04eb8eStimh mt = MT_FIRST; 323ab04eb8eStimh else 324ab04eb8eStimh mt = MT_EXACT; 325ab04eb8eStimh 326745cd3c5Smaybee err = zap_lookup_norm(mos, snapobj, name, 8, 1, 327ab04eb8eStimh value, mt, NULL, 0, NULL); 328ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 329745cd3c5Smaybee err = zap_lookup(mos, snapobj, name, 8, 1, value); 330ab04eb8eStimh return (err); 331ab04eb8eStimh } 332ab04eb8eStimh 333ab04eb8eStimh static int 334745cd3c5Smaybee dsl_dataset_snap_remove(dsl_dataset_t *ds, char *name, dmu_tx_t *tx) 335ab04eb8eStimh { 336745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 337745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 338ab04eb8eStimh matchtype_t mt; 339ab04eb8eStimh int err; 340ab04eb8eStimh 34171eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 34271eb0538SChris Kirby 343745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 344ab04eb8eStimh mt = MT_FIRST; 345ab04eb8eStimh else 346ab04eb8eStimh mt = MT_EXACT; 347ab04eb8eStimh 348745cd3c5Smaybee err = zap_remove_norm(mos, snapobj, name, mt, tx); 349ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 350745cd3c5Smaybee err = zap_remove(mos, snapobj, name, tx); 351ab04eb8eStimh return (err); 352ab04eb8eStimh } 353ab04eb8eStimh 354745cd3c5Smaybee static int 355745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag, 356745cd3c5Smaybee dsl_dataset_t **dsp) 357fa9e4066Sahrens { 358fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 359fa9e4066Sahrens dmu_buf_t *dbuf; 360fa9e4066Sahrens dsl_dataset_t *ds; 361ea8dc4b6Seschrock int err; 362a7f53a56SChris Kirby dmu_object_info_t doi; 363fa9e4066Sahrens 364fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 365fa9e4066Sahrens dsl_pool_sync_context(dp)); 366fa9e4066Sahrens 367ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 368ea8dc4b6Seschrock if (err) 369ea8dc4b6Seschrock return (err); 370a7f53a56SChris Kirby 371a7f53a56SChris Kirby /* Make sure dsobj has the correct object type. */ 372a7f53a56SChris Kirby dmu_object_info_from_db(dbuf, &doi); 373a7f53a56SChris Kirby if (doi.doi_type != DMU_OT_DSL_DATASET) 374a7f53a56SChris Kirby return (EINVAL); 375a7f53a56SChris Kirby 376fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 377fa9e4066Sahrens if (ds == NULL) { 378fa9e4066Sahrens dsl_dataset_t *winner; 379fa9e4066Sahrens 380fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 381fa9e4066Sahrens ds->ds_dbuf = dbuf; 382fa9e4066Sahrens ds->ds_object = dsobj; 383fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 384fa9e4066Sahrens 3855ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 386f4b94bdeSMatthew Ahrens mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL); 38791ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 3884e3c9f44SBill Pijewski mutex_init(&ds->ds_sendstream_lock, NULL, MUTEX_DEFAULT, NULL); 3894e3c9f44SBill Pijewski 390745cd3c5Smaybee rw_init(&ds->ds_rwlock, 0, 0, 0); 391745cd3c5Smaybee cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL); 3925ad82045Snd 393cde58dbcSMatthew Ahrens bplist_create(&ds->ds_pending_deadlist); 394cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, 395fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 396cde58dbcSMatthew Ahrens 3974e3c9f44SBill Pijewski list_create(&ds->ds_sendstreams, sizeof (dmu_sendarg_t), 3984e3c9f44SBill Pijewski offsetof(dmu_sendarg_t, dsa_link)); 3994e3c9f44SBill Pijewski 400ea8dc4b6Seschrock if (err == 0) { 401ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 402ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 403ea8dc4b6Seschrock } 404ea8dc4b6Seschrock if (err) { 4055ad82045Snd mutex_destroy(&ds->ds_lock); 406f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 40791ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 408745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 409745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 410cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 411cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 412ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 413ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 414ea8dc4b6Seschrock return (err); 415ea8dc4b6Seschrock } 416fa9e4066Sahrens 41774e7dc98SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 418fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 419fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 420745cd3c5Smaybee err = dsl_dataset_get_ref(dp, 421745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 422745cd3c5Smaybee ds, &ds->ds_prev); 423fa9e4066Sahrens } 424842727c2SChris Kirby } else { 425842727c2SChris Kirby if (zfs_flags & ZFS_DEBUG_SNAPNAMES) 426842727c2SChris Kirby err = dsl_dataset_get_snapname(ds); 427842727c2SChris Kirby if (err == 0 && ds->ds_phys->ds_userrefs_obj != 0) { 428842727c2SChris Kirby err = zap_count( 429842727c2SChris Kirby ds->ds_dir->dd_pool->dp_meta_objset, 430842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj, 431842727c2SChris Kirby &ds->ds_userrefs); 432842727c2SChris Kirby } 433fa9e4066Sahrens } 434fa9e4066Sahrens 43574e7dc98SMatthew Ahrens if (err == 0 && !dsl_dataset_is_snapshot(ds)) { 43627345066Sck /* 43727345066Sck * In sync context, we're called with either no lock 43827345066Sck * or with the write lock. If we're not syncing, 43927345066Sck * we're always called with the read lock held. 44027345066Sck */ 441cb625fb5Sck boolean_t need_lock = 44227345066Sck !RW_WRITE_HELD(&dp->dp_config_rwlock) && 44327345066Sck dsl_pool_sync_context(dp); 444cb625fb5Sck 445cb625fb5Sck if (need_lock) 446cb625fb5Sck rw_enter(&dp->dp_config_rwlock, RW_READER); 447cb625fb5Sck 448bb0ade09Sahrens err = dsl_prop_get_ds(ds, 449cb625fb5Sck "refreservation", sizeof (uint64_t), 1, 450cb625fb5Sck &ds->ds_reserved, NULL); 451cb625fb5Sck if (err == 0) { 452bb0ade09Sahrens err = dsl_prop_get_ds(ds, 453cb625fb5Sck "refquota", sizeof (uint64_t), 1, 454cb625fb5Sck &ds->ds_quota, NULL); 455cb625fb5Sck } 456cb625fb5Sck 457cb625fb5Sck if (need_lock) 458cb625fb5Sck rw_exit(&dp->dp_config_rwlock); 459cb625fb5Sck } else { 460cb625fb5Sck ds->ds_reserved = ds->ds_quota = 0; 461cb625fb5Sck } 462cb625fb5Sck 463ea8dc4b6Seschrock if (err == 0) { 464ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 465ea8dc4b6Seschrock dsl_dataset_evict); 466ea8dc4b6Seschrock } 467ea8dc4b6Seschrock if (err || winner) { 468cde58dbcSMatthew Ahrens bplist_destroy(&ds->ds_pending_deadlist); 469cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 470745cd3c5Smaybee if (ds->ds_prev) 471745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 472fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 4735ad82045Snd mutex_destroy(&ds->ds_lock); 474f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 47591ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 476745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 477745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 478fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 479ea8dc4b6Seschrock if (err) { 480ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 481ea8dc4b6Seschrock return (err); 482ea8dc4b6Seschrock } 483fa9e4066Sahrens ds = winner; 484fa9e4066Sahrens } else { 48591ebeef5Sahrens ds->ds_fsid_guid = 486fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 487fa9e4066Sahrens } 488fa9e4066Sahrens } 489fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 490fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 491088f3894Sahrens ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 || 492afc6333aSahrens spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN || 49384db2a68Sahrens dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap); 494fa9e4066Sahrens mutex_enter(&ds->ds_lock); 495745cd3c5Smaybee if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) { 496fa9e4066Sahrens mutex_exit(&ds->ds_lock); 497745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 498745cd3c5Smaybee return (ENOENT); 499fa9e4066Sahrens } 500fa9e4066Sahrens mutex_exit(&ds->ds_lock); 501ea8dc4b6Seschrock *dsp = ds; 502ea8dc4b6Seschrock return (0); 503fa9e4066Sahrens } 504fa9e4066Sahrens 505745cd3c5Smaybee static int 506745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag) 507745cd3c5Smaybee { 508745cd3c5Smaybee dsl_pool_t *dp = ds->ds_dir->dd_pool; 509745cd3c5Smaybee 510745cd3c5Smaybee /* 511745cd3c5Smaybee * In syncing context we don't want the rwlock lock: there 512745cd3c5Smaybee * may be an existing writer waiting for sync phase to 513745cd3c5Smaybee * finish. We don't need to worry about such writers, since 514745cd3c5Smaybee * sync phase is single-threaded, so the writer can't be 515745cd3c5Smaybee * doing anything while we are active. 516745cd3c5Smaybee */ 517745cd3c5Smaybee if (dsl_pool_sync_context(dp)) { 518745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 519745cd3c5Smaybee return (0); 520745cd3c5Smaybee } 521745cd3c5Smaybee 522745cd3c5Smaybee /* 523745cd3c5Smaybee * Normal users will hold the ds_rwlock as a READER until they 524745cd3c5Smaybee * are finished (i.e., call dsl_dataset_rele()). "Owners" will 525745cd3c5Smaybee * drop their READER lock after they set the ds_owner field. 526745cd3c5Smaybee * 527745cd3c5Smaybee * If the dataset is being destroyed, the destroy thread will 528745cd3c5Smaybee * obtain a WRITER lock for exclusive access after it's done its 529745cd3c5Smaybee * open-context work and then change the ds_owner to 530745cd3c5Smaybee * dsl_reaper once destruction is assured. So threads 531745cd3c5Smaybee * may block here temporarily, until the "destructability" of 532745cd3c5Smaybee * the dataset is determined. 533745cd3c5Smaybee */ 534745cd3c5Smaybee ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock)); 535745cd3c5Smaybee mutex_enter(&ds->ds_lock); 536745cd3c5Smaybee while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) { 537745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 538745cd3c5Smaybee cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock); 539745cd3c5Smaybee if (DSL_DATASET_IS_DESTROYED(ds)) { 540745cd3c5Smaybee mutex_exit(&ds->ds_lock); 541745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 542745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 543745cd3c5Smaybee return (ENOENT); 544745cd3c5Smaybee } 545620252bcSChris Kirby /* 546620252bcSChris Kirby * The dp_config_rwlock lives above the ds_lock. And 547620252bcSChris Kirby * we need to check DSL_DATASET_IS_DESTROYED() while 548620252bcSChris Kirby * holding the ds_lock, so we have to drop and reacquire 549620252bcSChris Kirby * the ds_lock here. 550620252bcSChris Kirby */ 551620252bcSChris Kirby mutex_exit(&ds->ds_lock); 552745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 553620252bcSChris Kirby mutex_enter(&ds->ds_lock); 554745cd3c5Smaybee } 555745cd3c5Smaybee mutex_exit(&ds->ds_lock); 556745cd3c5Smaybee return (0); 557745cd3c5Smaybee } 558745cd3c5Smaybee 559745cd3c5Smaybee int 560745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, 561745cd3c5Smaybee dsl_dataset_t **dsp) 562745cd3c5Smaybee { 563745cd3c5Smaybee int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp); 564745cd3c5Smaybee 565745cd3c5Smaybee if (err) 566745cd3c5Smaybee return (err); 567745cd3c5Smaybee return (dsl_dataset_hold_ref(*dsp, tag)); 568745cd3c5Smaybee } 569745cd3c5Smaybee 570745cd3c5Smaybee int 571503ad85cSMatthew Ahrens dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, boolean_t inconsistentok, 572503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 573745cd3c5Smaybee { 574503ad85cSMatthew Ahrens int err = dsl_dataset_hold_obj(dp, dsobj, tag, dsp); 575745cd3c5Smaybee if (err) 576745cd3c5Smaybee return (err); 577503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 578503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 5794f5064b7SMark J Musante *dsp = NULL; 580745cd3c5Smaybee return (EBUSY); 581745cd3c5Smaybee } 582745cd3c5Smaybee return (0); 583745cd3c5Smaybee } 584745cd3c5Smaybee 585fa9e4066Sahrens int 586745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp) 587fa9e4066Sahrens { 588fa9e4066Sahrens dsl_dir_t *dd; 589fa9e4066Sahrens dsl_pool_t *dp; 590745cd3c5Smaybee const char *snapname; 591fa9e4066Sahrens uint64_t obj; 592fa9e4066Sahrens int err = 0; 593fa9e4066Sahrens 594745cd3c5Smaybee err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname); 595ea8dc4b6Seschrock if (err) 596ea8dc4b6Seschrock return (err); 597fa9e4066Sahrens 598fa9e4066Sahrens dp = dd->dd_pool; 599fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 600fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 601745cd3c5Smaybee if (obj) 602745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, dsp); 603745cd3c5Smaybee else 604fa9e4066Sahrens err = ENOENT; 605745cd3c5Smaybee if (err) 606fa9e4066Sahrens goto out; 607fa9e4066Sahrens 608745cd3c5Smaybee err = dsl_dataset_hold_ref(*dsp, tag); 609fa9e4066Sahrens 610745cd3c5Smaybee /* we may be looking for a snapshot */ 611745cd3c5Smaybee if (err == 0 && snapname != NULL) { 612745cd3c5Smaybee dsl_dataset_t *ds = NULL; 613fa9e4066Sahrens 614745cd3c5Smaybee if (*snapname++ != '@') { 615745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 616fa9e4066Sahrens err = ENOENT; 617fa9e4066Sahrens goto out; 618fa9e4066Sahrens } 619fa9e4066Sahrens 620745cd3c5Smaybee dprintf("looking for snapshot '%s'\n", snapname); 621745cd3c5Smaybee err = dsl_dataset_snap_lookup(*dsp, snapname, &obj); 622745cd3c5Smaybee if (err == 0) 623745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, &ds); 624745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 625745cd3c5Smaybee 626745cd3c5Smaybee ASSERT3U((err == 0), ==, (ds != NULL)); 627745cd3c5Smaybee 628745cd3c5Smaybee if (ds) { 629745cd3c5Smaybee mutex_enter(&ds->ds_lock); 630745cd3c5Smaybee if (ds->ds_snapname[0] == 0) 631745cd3c5Smaybee (void) strlcpy(ds->ds_snapname, snapname, 632745cd3c5Smaybee sizeof (ds->ds_snapname)); 633745cd3c5Smaybee mutex_exit(&ds->ds_lock); 634745cd3c5Smaybee err = dsl_dataset_hold_ref(ds, tag); 635745cd3c5Smaybee *dsp = err ? NULL : ds; 636fa9e4066Sahrens } 637fa9e4066Sahrens } 638fa9e4066Sahrens out: 639fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 640fa9e4066Sahrens dsl_dir_close(dd, FTAG); 641fa9e4066Sahrens return (err); 642fa9e4066Sahrens } 643fa9e4066Sahrens 644fa9e4066Sahrens int 645503ad85cSMatthew Ahrens dsl_dataset_own(const char *name, boolean_t inconsistentok, 646503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 647fa9e4066Sahrens { 648503ad85cSMatthew Ahrens int err = dsl_dataset_hold(name, tag, dsp); 649745cd3c5Smaybee if (err) 650745cd3c5Smaybee return (err); 651503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 652503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 653745cd3c5Smaybee return (EBUSY); 654745cd3c5Smaybee } 655745cd3c5Smaybee return (0); 656fa9e4066Sahrens } 657fa9e4066Sahrens 658fa9e4066Sahrens void 659fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 660fa9e4066Sahrens { 661fa9e4066Sahrens if (ds == NULL) { 662fa9e4066Sahrens (void) strcpy(name, "mos"); 663fa9e4066Sahrens } else { 664fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 665ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 666fa9e4066Sahrens if (ds->ds_snapname[0]) { 667fa9e4066Sahrens (void) strcat(name, "@"); 668745cd3c5Smaybee /* 669745cd3c5Smaybee * We use a "recursive" mutex so that we 670745cd3c5Smaybee * can call dprintf_ds() with ds_lock held. 671745cd3c5Smaybee */ 672fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 673fa9e4066Sahrens mutex_enter(&ds->ds_lock); 674fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 675fa9e4066Sahrens mutex_exit(&ds->ds_lock); 676fa9e4066Sahrens } else { 677fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 678fa9e4066Sahrens } 679fa9e4066Sahrens } 680fa9e4066Sahrens } 681fa9e4066Sahrens } 682fa9e4066Sahrens 683b7661cccSmmusante static int 684b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 685b7661cccSmmusante { 686b7661cccSmmusante int result; 687b7661cccSmmusante 688b7661cccSmmusante if (ds == NULL) { 689b7661cccSmmusante result = 3; /* "mos" */ 690b7661cccSmmusante } else { 691b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 692b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 693b7661cccSmmusante if (ds->ds_snapname[0]) { 694b7661cccSmmusante ++result; /* adding one for the @-sign */ 695b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 696b7661cccSmmusante mutex_enter(&ds->ds_lock); 697b7661cccSmmusante result += strlen(ds->ds_snapname); 698b7661cccSmmusante mutex_exit(&ds->ds_lock); 699b7661cccSmmusante } else { 700b7661cccSmmusante result += strlen(ds->ds_snapname); 701b7661cccSmmusante } 702b7661cccSmmusante } 703b7661cccSmmusante } 704b7661cccSmmusante 705b7661cccSmmusante return (result); 706b7661cccSmmusante } 707b7661cccSmmusante 708088f3894Sahrens void 709745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag) 710fa9e4066Sahrens { 711ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 712fa9e4066Sahrens } 713fa9e4066Sahrens 7143cb34c60Sahrens void 715745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag) 7163cb34c60Sahrens { 717745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) { 718745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 719745cd3c5Smaybee } 720745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 721745cd3c5Smaybee } 722745cd3c5Smaybee 723745cd3c5Smaybee void 724503ad85cSMatthew Ahrens dsl_dataset_disown(dsl_dataset_t *ds, void *tag) 725745cd3c5Smaybee { 726503ad85cSMatthew Ahrens ASSERT((ds->ds_owner == tag && ds->ds_dbuf) || 727745cd3c5Smaybee (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL)); 728745cd3c5Smaybee 7293cb34c60Sahrens mutex_enter(&ds->ds_lock); 730745cd3c5Smaybee ds->ds_owner = NULL; 731745cd3c5Smaybee if (RW_WRITE_HELD(&ds->ds_rwlock)) { 732745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 733745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 734745cd3c5Smaybee } 7353cb34c60Sahrens mutex_exit(&ds->ds_lock); 736745cd3c5Smaybee if (ds->ds_dbuf) 737503ad85cSMatthew Ahrens dsl_dataset_drop_ref(ds, tag); 738745cd3c5Smaybee else 739cde58dbcSMatthew Ahrens dsl_dataset_evict(NULL, ds); 7403cb34c60Sahrens } 7413cb34c60Sahrens 7423cb34c60Sahrens boolean_t 743503ad85cSMatthew Ahrens dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *tag) 7443cb34c60Sahrens { 745745cd3c5Smaybee boolean_t gotit = FALSE; 746745cd3c5Smaybee 7473cb34c60Sahrens mutex_enter(&ds->ds_lock); 748745cd3c5Smaybee if (ds->ds_owner == NULL && 749745cd3c5Smaybee (!DS_IS_INCONSISTENT(ds) || inconsistentok)) { 750503ad85cSMatthew Ahrens ds->ds_owner = tag; 751745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) 752745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 753745cd3c5Smaybee gotit = TRUE; 7543cb34c60Sahrens } 7553cb34c60Sahrens mutex_exit(&ds->ds_lock); 756745cd3c5Smaybee return (gotit); 757745cd3c5Smaybee } 758745cd3c5Smaybee 759745cd3c5Smaybee void 760745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner) 761745cd3c5Smaybee { 762745cd3c5Smaybee ASSERT3P(owner, ==, ds->ds_owner); 763745cd3c5Smaybee if (!RW_WRITE_HELD(&ds->ds_rwlock)) 764745cd3c5Smaybee rw_enter(&ds->ds_rwlock, RW_WRITER); 7653cb34c60Sahrens } 7663cb34c60Sahrens 7671d452cf5Sahrens uint64_t 768088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 769ab04eb8eStimh uint64_t flags, dmu_tx_t *tx) 770fa9e4066Sahrens { 7713cb34c60Sahrens dsl_pool_t *dp = dd->dd_pool; 772fa9e4066Sahrens dmu_buf_t *dbuf; 773fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 7743cb34c60Sahrens uint64_t dsobj; 775fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 776fa9e4066Sahrens 777088f3894Sahrens if (origin == NULL) 778088f3894Sahrens origin = dp->dp_origin_snap; 779088f3894Sahrens 7803cb34c60Sahrens ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp); 7813cb34c60Sahrens ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0); 782fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 7833cb34c60Sahrens ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); 784fa9e4066Sahrens 7851649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 7861649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 787ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 788fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 789fa9e4066Sahrens dsphys = dbuf->db_data; 790745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 791fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 792ab04eb8eStimh dsphys->ds_flags = flags; 793fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 794fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 795fa9e4066Sahrens sizeof (dsphys->ds_guid)); 796fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 797ab04eb8eStimh zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP, 798ab04eb8eStimh DMU_OT_NONE, 0, tx); 799fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 800088f3894Sahrens dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg; 801a9799022Sck 802cde58dbcSMatthew Ahrens if (origin == NULL) { 803cde58dbcSMatthew Ahrens dsphys->ds_deadlist_obj = dsl_deadlist_alloc(mos, tx); 804cde58dbcSMatthew Ahrens } else { 805cde58dbcSMatthew Ahrens dsl_dataset_t *ohds; 806cde58dbcSMatthew Ahrens 8073cb34c60Sahrens dsphys->ds_prev_snap_obj = origin->ds_object; 808fa9e4066Sahrens dsphys->ds_prev_snap_txg = 8093cb34c60Sahrens origin->ds_phys->ds_creation_txg; 810ad135b5dSChristopher Siden dsphys->ds_referenced_bytes = 811ad135b5dSChristopher Siden origin->ds_phys->ds_referenced_bytes; 812fa9e4066Sahrens dsphys->ds_compressed_bytes = 8133cb34c60Sahrens origin->ds_phys->ds_compressed_bytes; 814fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 8153cb34c60Sahrens origin->ds_phys->ds_uncompressed_bytes; 8163cb34c60Sahrens dsphys->ds_bp = origin->ds_phys->ds_bp; 817579ae4d5Stimh dsphys->ds_flags |= origin->ds_phys->ds_flags; 818fa9e4066Sahrens 8193cb34c60Sahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 8203cb34c60Sahrens origin->ds_phys->ds_num_children++; 821fa9e4066Sahrens 822b420f3adSRichard Lowe VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 823cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ohds)); 824cde58dbcSMatthew Ahrens dsphys->ds_deadlist_obj = dsl_deadlist_clone(&ohds->ds_deadlist, 825cde58dbcSMatthew Ahrens dsphys->ds_prev_snap_txg, dsphys->ds_prev_snap_obj, tx); 826cde58dbcSMatthew Ahrens dsl_dataset_rele(ohds, FTAG); 827cde58dbcSMatthew Ahrens 828088f3894Sahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) { 829088f3894Sahrens if (origin->ds_phys->ds_next_clones_obj == 0) { 830088f3894Sahrens origin->ds_phys->ds_next_clones_obj = 831088f3894Sahrens zap_create(mos, 832088f3894Sahrens DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx); 833088f3894Sahrens } 834088f3894Sahrens VERIFY(0 == zap_add_int(mos, 835088f3894Sahrens origin->ds_phys->ds_next_clones_obj, 836088f3894Sahrens dsobj, tx)); 837088f3894Sahrens } 838088f3894Sahrens 839fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 8403cb34c60Sahrens dd->dd_phys->dd_origin_obj = origin->ds_object; 841cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 842cde58dbcSMatthew Ahrens if (origin->ds_dir->dd_phys->dd_clones == 0) { 843cde58dbcSMatthew Ahrens dmu_buf_will_dirty(origin->ds_dir->dd_dbuf, tx); 844cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_clones = 845cde58dbcSMatthew Ahrens zap_create(mos, 846cde58dbcSMatthew Ahrens DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx); 847cde58dbcSMatthew Ahrens } 848b420f3adSRichard Lowe VERIFY3U(0, ==, zap_add_int(mos, 849cde58dbcSMatthew Ahrens origin->ds_dir->dd_phys->dd_clones, dsobj, tx)); 850cde58dbcSMatthew Ahrens } 851fa9e4066Sahrens } 852ab04eb8eStimh 853ab04eb8eStimh if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 854ab04eb8eStimh dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 855ab04eb8eStimh 856ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 857fa9e4066Sahrens 858fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 859fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 8603cb34c60Sahrens 8613cb34c60Sahrens return (dsobj); 8623cb34c60Sahrens } 8633cb34c60Sahrens 8643cb34c60Sahrens uint64_t 865ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname, 866ab04eb8eStimh dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx) 8673cb34c60Sahrens { 8683cb34c60Sahrens dsl_pool_t *dp = pdd->dd_pool; 8693cb34c60Sahrens uint64_t dsobj, ddobj; 8703cb34c60Sahrens dsl_dir_t *dd; 8713cb34c60Sahrens 8723cb34c60Sahrens ASSERT(lastname[0] != '@'); 8733cb34c60Sahrens 874088f3894Sahrens ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx); 8753cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 8763cb34c60Sahrens 877088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx); 8783cb34c60Sahrens 8793cb34c60Sahrens dsl_deleg_set_create_perms(dd, tx, cr); 8803cb34c60Sahrens 881fa9e4066Sahrens dsl_dir_close(dd, FTAG); 882fa9e4066Sahrens 883feaa74e4SMark Maybee /* 884feaa74e4SMark Maybee * If we are creating a clone, make sure we zero out any stale 885feaa74e4SMark Maybee * data from the origin snapshots zil header. 886feaa74e4SMark Maybee */ 887feaa74e4SMark Maybee if (origin != NULL) { 888feaa74e4SMark Maybee dsl_dataset_t *ds; 889feaa74e4SMark Maybee objset_t *os; 890feaa74e4SMark Maybee 891b420f3adSRichard Lowe VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds)); 892b420f3adSRichard Lowe VERIFY3U(0, ==, dmu_objset_from_ds(ds, &os)); 893feaa74e4SMark Maybee bzero(&os->os_zil_header, sizeof (os->os_zil_header)); 894feaa74e4SMark Maybee dsl_dataset_dirty(ds, tx); 895feaa74e4SMark Maybee dsl_dataset_rele(ds, FTAG); 896feaa74e4SMark Maybee } 897feaa74e4SMark Maybee 8981d452cf5Sahrens return (dsobj); 899fa9e4066Sahrens } 900fa9e4066Sahrens 9011d452cf5Sahrens /* 90219b94df9SMatthew Ahrens * The snapshots must all be in the same pool. 9031d452cf5Sahrens */ 9041d452cf5Sahrens int 9054445fffbSMatthew Ahrens dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, 9064445fffbSMatthew Ahrens nvlist_t *errlist) 9071d452cf5Sahrens { 9081d452cf5Sahrens int err; 9091d452cf5Sahrens dsl_sync_task_t *dst; 9101d452cf5Sahrens spa_t *spa; 91119b94df9SMatthew Ahrens nvpair_t *pair; 91219b94df9SMatthew Ahrens dsl_sync_task_group_t *dstg; 913e5351341SMatthew Ahrens 91419b94df9SMatthew Ahrens pair = nvlist_next_nvpair(snaps, NULL); 91519b94df9SMatthew Ahrens if (pair == NULL) 91619b94df9SMatthew Ahrens return (0); 91719b94df9SMatthew Ahrens 91819b94df9SMatthew Ahrens err = spa_open(nvpair_name(pair), &spa, FTAG); 9191d452cf5Sahrens if (err) 9201d452cf5Sahrens return (err); 92119b94df9SMatthew Ahrens dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 9221d452cf5Sahrens 92319b94df9SMatthew Ahrens for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL; 92419b94df9SMatthew Ahrens pair = nvlist_next_nvpair(snaps, pair)) { 92519b94df9SMatthew Ahrens dsl_dataset_t *ds; 92619b94df9SMatthew Ahrens 92719b94df9SMatthew Ahrens err = dsl_dataset_own(nvpair_name(pair), B_TRUE, dstg, &ds); 92819b94df9SMatthew Ahrens if (err == 0) { 92919b94df9SMatthew Ahrens struct dsl_ds_destroyarg *dsda; 93019b94df9SMatthew Ahrens 93119b94df9SMatthew Ahrens dsl_dataset_make_exclusive(ds, dstg); 93219b94df9SMatthew Ahrens dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), 93319b94df9SMatthew Ahrens KM_SLEEP); 93419b94df9SMatthew Ahrens dsda->ds = ds; 93519b94df9SMatthew Ahrens dsda->defer = defer; 93619b94df9SMatthew Ahrens dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 93719b94df9SMatthew Ahrens dsl_dataset_destroy_sync, dsda, dstg, 0); 93819b94df9SMatthew Ahrens } else if (err == ENOENT) { 93919b94df9SMatthew Ahrens err = 0; 94019b94df9SMatthew Ahrens } else { 9414445fffbSMatthew Ahrens fnvlist_add_int32(errlist, nvpair_name(pair), err); 94219b94df9SMatthew Ahrens break; 94319b94df9SMatthew Ahrens } 94419b94df9SMatthew Ahrens } 9451d452cf5Sahrens 9461d452cf5Sahrens if (err == 0) 94719b94df9SMatthew Ahrens err = dsl_sync_task_group_wait(dstg); 9481d452cf5Sahrens 94919b94df9SMatthew Ahrens for (dst = list_head(&dstg->dstg_tasks); dst; 95019b94df9SMatthew Ahrens dst = list_next(&dstg->dstg_tasks, dst)) { 951842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 952842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 953842727c2SChris Kirby 954745cd3c5Smaybee /* 9554445fffbSMatthew Ahrens * Return the snapshots that triggered the error. 956745cd3c5Smaybee */ 9574445fffbSMatthew Ahrens if (dst->dst_err != 0) { 9584445fffbSMatthew Ahrens char name[ZFS_MAXNAMELEN]; 9594445fffbSMatthew Ahrens dsl_dataset_name(ds, name); 9604445fffbSMatthew Ahrens fnvlist_add_int32(errlist, name, dst->dst_err); 961e1930233Sbonwick } 962842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 96319b94df9SMatthew Ahrens dsl_dataset_disown(ds, dstg); 964842727c2SChris Kirby kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 965fa9e4066Sahrens } 966fa9e4066Sahrens 96719b94df9SMatthew Ahrens dsl_sync_task_group_destroy(dstg); 9681d452cf5Sahrens spa_close(spa, FTAG); 969fa9e4066Sahrens return (err); 97019b94df9SMatthew Ahrens 971fa9e4066Sahrens } 972fa9e4066Sahrens 973842727c2SChris Kirby static boolean_t 974842727c2SChris Kirby dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 975842727c2SChris Kirby { 976842727c2SChris Kirby boolean_t might_destroy = B_FALSE; 977842727c2SChris Kirby 978842727c2SChris Kirby mutex_enter(&ds->ds_lock); 979842727c2SChris Kirby if (ds->ds_phys->ds_num_children == 2 && ds->ds_userrefs == 0 && 980842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 981842727c2SChris Kirby might_destroy = B_TRUE; 982842727c2SChris Kirby mutex_exit(&ds->ds_lock); 983842727c2SChris Kirby 984842727c2SChris Kirby return (might_destroy); 985842727c2SChris Kirby } 986842727c2SChris Kirby 987842727c2SChris Kirby /* 988842727c2SChris Kirby * If we're removing a clone, and these three conditions are true: 989842727c2SChris Kirby * 1) the clone's origin has no other children 990842727c2SChris Kirby * 2) the clone's origin has no user references 991842727c2SChris Kirby * 3) the clone's origin has been marked for deferred destruction 992842727c2SChris Kirby * Then, prepare to remove the origin as part of this sync task group. 993842727c2SChris Kirby */ 994842727c2SChris Kirby static int 995842727c2SChris Kirby dsl_dataset_origin_rm_prep(struct dsl_ds_destroyarg *dsda, void *tag) 996842727c2SChris Kirby { 997842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 998842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 999842727c2SChris Kirby 1000842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(origin)) { 1001842727c2SChris Kirby char *name; 1002842727c2SChris Kirby int namelen; 1003842727c2SChris Kirby int error; 1004842727c2SChris Kirby 1005842727c2SChris Kirby namelen = dsl_dataset_namelen(origin) + 1; 1006842727c2SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 1007842727c2SChris Kirby dsl_dataset_name(origin, name); 1008842727c2SChris Kirby #ifdef _KERNEL 1009842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 1010842727c2SChris Kirby if (error) { 1011842727c2SChris Kirby kmem_free(name, namelen); 1012842727c2SChris Kirby return (error); 1013842727c2SChris Kirby } 1014842727c2SChris Kirby #endif 1015503ad85cSMatthew Ahrens error = dsl_dataset_own(name, B_TRUE, tag, &origin); 1016842727c2SChris Kirby kmem_free(name, namelen); 1017842727c2SChris Kirby if (error) 1018842727c2SChris Kirby return (error); 1019842727c2SChris Kirby dsda->rm_origin = origin; 1020842727c2SChris Kirby dsl_dataset_make_exclusive(origin, tag); 1021842727c2SChris Kirby } 1022842727c2SChris Kirby 1023842727c2SChris Kirby return (0); 1024842727c2SChris Kirby } 1025842727c2SChris Kirby 10263cb34c60Sahrens /* 1027745cd3c5Smaybee * ds must be opened as OWNER. On return (whether successful or not), 1028745cd3c5Smaybee * ds will be closed and caller can no longer dereference it. 10293cb34c60Sahrens */ 1030fa9e4066Sahrens int 1031842727c2SChris Kirby dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) 1032fa9e4066Sahrens { 1033fa9e4066Sahrens int err; 10341d452cf5Sahrens dsl_sync_task_group_t *dstg; 10351d452cf5Sahrens objset_t *os; 1036fa9e4066Sahrens dsl_dir_t *dd; 10371d452cf5Sahrens uint64_t obj; 103892241e0bSTom Erickson struct dsl_ds_destroyarg dsda = { 0 }; 1039842727c2SChris Kirby 1040842727c2SChris Kirby dsda.ds = ds; 10411d452cf5Sahrens 10423cb34c60Sahrens if (dsl_dataset_is_snapshot(ds)) { 10431d452cf5Sahrens /* Destroying a snapshot is simpler */ 1044745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 10453baa08fcSek 1046842727c2SChris Kirby dsda.defer = defer; 10471d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 10481d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 1049842727c2SChris Kirby &dsda, tag, 0); 1050842727c2SChris Kirby ASSERT3P(dsda.rm_origin, ==, NULL); 10513cb34c60Sahrens goto out; 1052922d9a97SChris Kirby } else if (defer) { 1053922d9a97SChris Kirby err = EINVAL; 1054922d9a97SChris Kirby goto out; 10551d452cf5Sahrens } 1056fa9e4066Sahrens 10571d452cf5Sahrens dd = ds->ds_dir; 1058fa9e4066Sahrens 1059ad135b5dSChristopher Siden if (!spa_feature_is_enabled(dsl_dataset_get_spa(ds), 1060ad135b5dSChristopher Siden &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY])) { 1061*ce636f8bSMatthew Ahrens /* 1062*ce636f8bSMatthew Ahrens * Check for errors and mark this ds as inconsistent, in 1063*ce636f8bSMatthew Ahrens * case we crash while freeing the objects. 1064*ce636f8bSMatthew Ahrens */ 1065*ce636f8bSMatthew Ahrens err = dsl_sync_task_do(dd->dd_pool, 1066*ce636f8bSMatthew Ahrens dsl_dataset_destroy_begin_check, 1067*ce636f8bSMatthew Ahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 1068*ce636f8bSMatthew Ahrens if (err) 1069*ce636f8bSMatthew Ahrens goto out; 1070*ce636f8bSMatthew Ahrens 1071*ce636f8bSMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 1072*ce636f8bSMatthew Ahrens if (err) 1073*ce636f8bSMatthew Ahrens goto out; 1074*ce636f8bSMatthew Ahrens 1075*ce636f8bSMatthew Ahrens /* 1076*ce636f8bSMatthew Ahrens * Remove all objects while in the open context so that 1077*ce636f8bSMatthew Ahrens * there is less work to do in the syncing context. 1078*ce636f8bSMatthew Ahrens */ 1079ad135b5dSChristopher Siden for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 1080ad135b5dSChristopher Siden ds->ds_phys->ds_prev_snap_txg)) { 1081ad135b5dSChristopher Siden /* 1082ad135b5dSChristopher Siden * Ignore errors, if there is not enough disk space 1083ad135b5dSChristopher Siden * we will deal with it in dsl_dataset_destroy_sync(). 1084ad135b5dSChristopher Siden */ 1085ad135b5dSChristopher Siden (void) dmu_free_object(os, obj); 1086ad135b5dSChristopher Siden } 1087ad135b5dSChristopher Siden if (err != ESRCH) 1088ad135b5dSChristopher Siden goto out; 1089feaa74e4SMark Maybee 1090*ce636f8bSMatthew Ahrens /* 1091*ce636f8bSMatthew Ahrens * Sync out all in-flight IO. 1092*ce636f8bSMatthew Ahrens */ 1093*ce636f8bSMatthew Ahrens txg_wait_synced(dd->dd_pool, 0); 109414843421SMatthew Ahrens 1095*ce636f8bSMatthew Ahrens /* 1096*ce636f8bSMatthew Ahrens * If we managed to free all the objects in open 1097*ce636f8bSMatthew Ahrens * context, the user space accounting should be zero. 1098*ce636f8bSMatthew Ahrens */ 1099*ce636f8bSMatthew Ahrens if (ds->ds_phys->ds_bp.blk_fill == 0 && 1100*ce636f8bSMatthew Ahrens dmu_objset_userused_enabled(os)) { 1101*ce636f8bSMatthew Ahrens uint64_t count; 1102*ce636f8bSMatthew Ahrens 1103*ce636f8bSMatthew Ahrens ASSERT(zap_count(os, DMU_USERUSED_OBJECT, 1104*ce636f8bSMatthew Ahrens &count) != 0 || count == 0); 1105*ce636f8bSMatthew Ahrens ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, 1106*ce636f8bSMatthew Ahrens &count) != 0 || count == 0); 1107*ce636f8bSMatthew Ahrens } 110814843421SMatthew Ahrens } 110914843421SMatthew Ahrens 111068038c2cSmaybee rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 111168038c2cSmaybee err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd); 111268038c2cSmaybee rw_exit(&dd->dd_pool->dp_config_rwlock); 111368038c2cSmaybee 111468038c2cSmaybee if (err) 111568038c2cSmaybee goto out; 111668038c2cSmaybee 11171d452cf5Sahrens /* 11181d452cf5Sahrens * Blow away the dsl_dir + head dataset. 11191d452cf5Sahrens */ 1120745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 1121842727c2SChris Kirby /* 1122842727c2SChris Kirby * If we're removing a clone, we might also need to remove its 1123842727c2SChris Kirby * origin. 1124842727c2SChris Kirby */ 1125842727c2SChris Kirby do { 1126842727c2SChris Kirby dsda.need_prep = B_FALSE; 1127842727c2SChris Kirby if (dsl_dir_is_clone(dd)) { 1128842727c2SChris Kirby err = dsl_dataset_origin_rm_prep(&dsda, tag); 1129842727c2SChris Kirby if (err) { 1130842727c2SChris Kirby dsl_dir_close(dd, FTAG); 1131842727c2SChris Kirby goto out; 1132842727c2SChris Kirby } 1133842727c2SChris Kirby } 1134842727c2SChris Kirby 1135842727c2SChris Kirby dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 1136842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 1137842727c2SChris Kirby dsl_dataset_destroy_sync, &dsda, tag, 0); 1138842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dir_destroy_check, 11394445fffbSMatthew Ahrens dsl_dir_destroy_sync, dd, FTAG, 0); 1140842727c2SChris Kirby err = dsl_sync_task_group_wait(dstg); 1141842727c2SChris Kirby dsl_sync_task_group_destroy(dstg); 1142842727c2SChris Kirby 1143842727c2SChris Kirby /* 1144842727c2SChris Kirby * We could be racing against 'zfs release' or 'zfs destroy -d' 1145842727c2SChris Kirby * on the origin snap, in which case we can get EBUSY if we 1146842727c2SChris Kirby * needed to destroy the origin snap but were not ready to 1147842727c2SChris Kirby * do so. 1148842727c2SChris Kirby */ 1149842727c2SChris Kirby if (dsda.need_prep) { 1150842727c2SChris Kirby ASSERT(err == EBUSY); 1151842727c2SChris Kirby ASSERT(dsl_dir_is_clone(dd)); 1152842727c2SChris Kirby ASSERT(dsda.rm_origin == NULL); 1153842727c2SChris Kirby } 1154842727c2SChris Kirby } while (dsda.need_prep); 1155842727c2SChris Kirby 1156842727c2SChris Kirby if (dsda.rm_origin != NULL) 1157842727c2SChris Kirby dsl_dataset_disown(dsda.rm_origin, tag); 1158842727c2SChris Kirby 1159745cd3c5Smaybee /* if it is successful, dsl_dir_destroy_sync will close the dd */ 11603cb34c60Sahrens if (err) 11611d452cf5Sahrens dsl_dir_close(dd, FTAG); 11623cb34c60Sahrens out: 1163745cd3c5Smaybee dsl_dataset_disown(ds, tag); 1164fa9e4066Sahrens return (err); 1165fa9e4066Sahrens } 1166fa9e4066Sahrens 1167c717a561Smaybee blkptr_t * 1168c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 1169fa9e4066Sahrens { 1170c717a561Smaybee return (&ds->ds_phys->ds_bp); 1171fa9e4066Sahrens } 1172fa9e4066Sahrens 1173fa9e4066Sahrens void 1174fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 1175fa9e4066Sahrens { 1176fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1177fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 1178fa9e4066Sahrens if (ds == NULL) { 1179fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 1180fa9e4066Sahrens } else { 1181fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1182fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 1183fa9e4066Sahrens } 1184fa9e4066Sahrens } 1185fa9e4066Sahrens 1186fa9e4066Sahrens spa_t * 1187fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 1188fa9e4066Sahrens { 1189fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 1190fa9e4066Sahrens } 1191fa9e4066Sahrens 1192fa9e4066Sahrens void 1193fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 1194fa9e4066Sahrens { 1195fa9e4066Sahrens dsl_pool_t *dp; 1196fa9e4066Sahrens 1197fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 1198fa9e4066Sahrens return; 1199fa9e4066Sahrens 1200503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1201a2eea2e1Sahrens 1202a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1203a2eea2e1Sahrens panic("dirtying snapshot!"); 1204fa9e4066Sahrens 1205fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 1206fa9e4066Sahrens 1207fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 1208fa9e4066Sahrens /* up the hold count until we can be written out */ 1209fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 1210fa9e4066Sahrens } 1211fa9e4066Sahrens } 1212fa9e4066Sahrens 1213a9799022Sck /* 1214a9799022Sck * The unique space in the head dataset can be calculated by subtracting 1215a9799022Sck * the space used in the most recent snapshot, that is still being used 1216a9799022Sck * in this file system, from the space currently in use. To figure out 1217a9799022Sck * the space in the most recent snapshot still in use, we need to take 1218a9799022Sck * the total space used in the snapshot and subtract out the space that 1219a9799022Sck * has been freed up since the snapshot was taken. 1220a9799022Sck */ 1221a9799022Sck static void 1222a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds) 1223a9799022Sck { 1224a9799022Sck uint64_t mrs_used; 1225a9799022Sck uint64_t dlused, dlcomp, dluncomp; 1226a9799022Sck 12273f9d6ad7SLin Ling ASSERT(!dsl_dataset_is_snapshot(ds)); 1228a9799022Sck 1229a9799022Sck if (ds->ds_phys->ds_prev_snap_obj != 0) 1230ad135b5dSChristopher Siden mrs_used = ds->ds_prev->ds_phys->ds_referenced_bytes; 1231a9799022Sck else 1232a9799022Sck mrs_used = 0; 1233a9799022Sck 1234cde58dbcSMatthew Ahrens dsl_deadlist_space(&ds->ds_deadlist, &dlused, &dlcomp, &dluncomp); 1235a9799022Sck 1236a9799022Sck ASSERT3U(dlused, <=, mrs_used); 1237a9799022Sck ds->ds_phys->ds_unique_bytes = 1238ad135b5dSChristopher Siden ds->ds_phys->ds_referenced_bytes - (mrs_used - dlused); 1239a9799022Sck 12403f9d6ad7SLin Ling if (spa_version(ds->ds_dir->dd_pool->dp_spa) >= 1241a9799022Sck SPA_VERSION_UNIQUE_ACCURATE) 1242a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1243a9799022Sck } 1244a9799022Sck 1245fa9e4066Sahrens struct killarg { 124674e7dc98SMatthew Ahrens dsl_dataset_t *ds; 1247fa9e4066Sahrens dmu_tx_t *tx; 1248fa9e4066Sahrens }; 1249fa9e4066Sahrens 125074e7dc98SMatthew Ahrens /* ARGSUSED */ 1251fa9e4066Sahrens static int 12523f9d6ad7SLin Ling kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, arc_buf_t *pbuf, 1253b24ab676SJeff Bonwick const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg) 1254fa9e4066Sahrens { 1255fa9e4066Sahrens struct killarg *ka = arg; 1256b24ab676SJeff Bonwick dmu_tx_t *tx = ka->tx; 1257fa9e4066Sahrens 125888b7b0f2SMatthew Ahrens if (bp == NULL) 125988b7b0f2SMatthew Ahrens return (0); 1260fa9e4066Sahrens 1261b24ab676SJeff Bonwick if (zb->zb_level == ZB_ZIL_LEVEL) { 1262b24ab676SJeff Bonwick ASSERT(zilog != NULL); 1263ab69d62fSMatthew Ahrens /* 1264ab69d62fSMatthew Ahrens * It's a block in the intent log. It has no 1265ab69d62fSMatthew Ahrens * accounting, so just free it. 1266ab69d62fSMatthew Ahrens */ 1267b24ab676SJeff Bonwick dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp); 1268ab69d62fSMatthew Ahrens } else { 1269b24ab676SJeff Bonwick ASSERT(zilog == NULL); 1270ab69d62fSMatthew Ahrens ASSERT3U(bp->blk_birth, >, ka->ds->ds_phys->ds_prev_snap_txg); 1271b24ab676SJeff Bonwick (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE); 1272ab69d62fSMatthew Ahrens } 127374e7dc98SMatthew Ahrens 1274fa9e4066Sahrens return (0); 1275fa9e4066Sahrens } 1276fa9e4066Sahrens 1277e1930233Sbonwick /* ARGSUSED */ 1278e1930233Sbonwick static int 12791d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1280e1930233Sbonwick { 12811d452cf5Sahrens dsl_dataset_t *ds = arg1; 12823cb34c60Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 12833cb34c60Sahrens uint64_t count; 12843cb34c60Sahrens int err; 1285e1930233Sbonwick 1286e1930233Sbonwick /* 1287e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1288e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1289e1930233Sbonwick * from.) 1290e1930233Sbonwick */ 1291e1930233Sbonwick if (ds->ds_prev != NULL && 1292e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 12934aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic return (EBUSY); 1294e1930233Sbonwick 12953cb34c60Sahrens /* 12963cb34c60Sahrens * This is really a dsl_dir thing, but check it here so that 12973cb34c60Sahrens * we'll be less likely to leave this dataset inconsistent & 12983cb34c60Sahrens * nearly destroyed. 12993cb34c60Sahrens */ 13003cb34c60Sahrens err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count); 13013cb34c60Sahrens if (err) 13023cb34c60Sahrens return (err); 13033cb34c60Sahrens if (count != 0) 13043cb34c60Sahrens return (EEXIST); 13053cb34c60Sahrens 1306e1930233Sbonwick return (0); 1307e1930233Sbonwick } 1308e1930233Sbonwick 13091d452cf5Sahrens /* ARGSUSED */ 13101d452cf5Sahrens static void 13113f9d6ad7SLin Ling dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1312fa9e4066Sahrens { 13131d452cf5Sahrens dsl_dataset_t *ds = arg1; 1314fa9e4066Sahrens 13151d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 13161d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 13171d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1318ecd6cf80Smarks 13194445fffbSMatthew Ahrens spa_history_log_internal_ds(ds, "destroy begin", tx, ""); 13201d452cf5Sahrens } 1321fa9e4066Sahrens 1322842727c2SChris Kirby static int 1323842727c2SChris Kirby dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag, 1324842727c2SChris Kirby dmu_tx_t *tx) 1325842727c2SChris Kirby { 1326842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1327842727c2SChris Kirby dsl_dataset_t *ds_prev = ds->ds_prev; 1328842727c2SChris Kirby 1329842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(ds_prev)) { 1330842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1331842727c2SChris Kirby 1332842727c2SChris Kirby /* 1333842727c2SChris Kirby * If we're not prepared to remove the origin, don't remove 1334842727c2SChris Kirby * the clone either. 1335842727c2SChris Kirby */ 1336842727c2SChris Kirby if (dsda->rm_origin == NULL) { 1337842727c2SChris Kirby dsda->need_prep = B_TRUE; 1338842727c2SChris Kirby return (EBUSY); 1339842727c2SChris Kirby } 1340842727c2SChris Kirby 1341842727c2SChris Kirby ndsda.ds = ds_prev; 1342842727c2SChris Kirby ndsda.is_origin_rm = B_TRUE; 1343842727c2SChris Kirby return (dsl_dataset_destroy_check(&ndsda, tag, tx)); 1344842727c2SChris Kirby } 1345842727c2SChris Kirby 1346842727c2SChris Kirby /* 1347842727c2SChris Kirby * If we're not going to remove the origin after all, 1348842727c2SChris Kirby * undo the open context setup. 1349842727c2SChris Kirby */ 1350842727c2SChris Kirby if (dsda->rm_origin != NULL) { 1351842727c2SChris Kirby dsl_dataset_disown(dsda->rm_origin, tag); 1352842727c2SChris Kirby dsda->rm_origin = NULL; 1353842727c2SChris Kirby } 1354842727c2SChris Kirby 1355842727c2SChris Kirby return (0); 1356842727c2SChris Kirby } 1357842727c2SChris Kirby 135899d5e173STim Haley /* 135999d5e173STim Haley * If you add new checks here, you may need to add 136099d5e173STim Haley * additional checks to the "temporary" case in 136199d5e173STim Haley * snapshot_check() in dmu_objset.c. 136299d5e173STim Haley */ 13631d452cf5Sahrens /* ARGSUSED */ 13643cb34c60Sahrens int 13651d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 13661d452cf5Sahrens { 1367842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1368842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1369fa9e4066Sahrens 1370745cd3c5Smaybee /* we have an owner hold, so noone else can destroy us */ 1371745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 1372745cd3c5Smaybee 1373842727c2SChris Kirby /* 1374842727c2SChris Kirby * Only allow deferred destroy on pools that support it. 1375842727c2SChris Kirby * NOTE: deferred destroy is only supported on snapshots. 1376842727c2SChris Kirby */ 1377842727c2SChris Kirby if (dsda->defer) { 1378842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 1379842727c2SChris Kirby SPA_VERSION_USERREFS) 1380842727c2SChris Kirby return (ENOTSUP); 1381842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 1382842727c2SChris Kirby return (0); 1383842727c2SChris Kirby } 1384fa9e4066Sahrens 1385fa9e4066Sahrens /* 1386fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1387fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1388fa9e4066Sahrens * from.) 1389fa9e4066Sahrens */ 1390fa9e4066Sahrens if (ds->ds_prev != NULL && 13911d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 13924aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic return (EBUSY); 1393fa9e4066Sahrens 1394fa9e4066Sahrens /* 1395fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1396fa9e4066Sahrens * them. Try again. 1397fa9e4066Sahrens */ 13981d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1399fa9e4066Sahrens return (EAGAIN); 14001d452cf5Sahrens 1401842727c2SChris Kirby if (dsl_dataset_is_snapshot(ds)) { 1402842727c2SChris Kirby /* 1403842727c2SChris Kirby * If this snapshot has an elevated user reference count, 1404842727c2SChris Kirby * we can't destroy it yet. 1405842727c2SChris Kirby */ 1406842727c2SChris Kirby if (ds->ds_userrefs > 0 && !dsda->releasing) 1407842727c2SChris Kirby return (EBUSY); 1408842727c2SChris Kirby 1409842727c2SChris Kirby mutex_enter(&ds->ds_lock); 1410842727c2SChris Kirby /* 1411842727c2SChris Kirby * Can't delete a branch point. However, if we're destroying 1412842727c2SChris Kirby * a clone and removing its origin due to it having a user 1413842727c2SChris Kirby * hold count of 0 and having been marked for deferred destroy, 1414842727c2SChris Kirby * it's OK for the origin to have a single clone. 1415842727c2SChris Kirby */ 1416842727c2SChris Kirby if (ds->ds_phys->ds_num_children > 1417842727c2SChris Kirby (dsda->is_origin_rm ? 2 : 1)) { 1418842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1419842727c2SChris Kirby return (EEXIST); 1420842727c2SChris Kirby } 1421842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1422842727c2SChris Kirby } else if (dsl_dir_is_clone(ds->ds_dir)) { 1423842727c2SChris Kirby return (dsl_dataset_origin_check(dsda, arg2, tx)); 1424842727c2SChris Kirby } 1425842727c2SChris Kirby 14261d452cf5Sahrens /* XXX we should do some i/o error checking... */ 14271d452cf5Sahrens return (0); 14281d452cf5Sahrens } 14291d452cf5Sahrens 1430745cd3c5Smaybee struct refsarg { 1431745cd3c5Smaybee kmutex_t lock; 1432745cd3c5Smaybee boolean_t gone; 1433745cd3c5Smaybee kcondvar_t cv; 1434745cd3c5Smaybee }; 1435745cd3c5Smaybee 1436745cd3c5Smaybee /* ARGSUSED */ 1437745cd3c5Smaybee static void 1438745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv) 1439745cd3c5Smaybee { 1440745cd3c5Smaybee struct refsarg *arg = argv; 1441745cd3c5Smaybee 1442745cd3c5Smaybee mutex_enter(&arg->lock); 1443745cd3c5Smaybee arg->gone = TRUE; 1444745cd3c5Smaybee cv_signal(&arg->cv); 1445745cd3c5Smaybee mutex_exit(&arg->lock); 1446745cd3c5Smaybee } 1447745cd3c5Smaybee 1448745cd3c5Smaybee static void 1449745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag) 1450745cd3c5Smaybee { 1451745cd3c5Smaybee struct refsarg arg; 1452745cd3c5Smaybee 1453745cd3c5Smaybee mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL); 1454745cd3c5Smaybee cv_init(&arg.cv, NULL, CV_DEFAULT, NULL); 1455745cd3c5Smaybee arg.gone = FALSE; 1456745cd3c5Smaybee (void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys, 1457745cd3c5Smaybee dsl_dataset_refs_gone); 1458745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 1459745cd3c5Smaybee mutex_enter(&arg.lock); 1460745cd3c5Smaybee while (!arg.gone) 1461745cd3c5Smaybee cv_wait(&arg.cv, &arg.lock); 1462745cd3c5Smaybee ASSERT(arg.gone); 1463745cd3c5Smaybee mutex_exit(&arg.lock); 1464745cd3c5Smaybee ds->ds_dbuf = NULL; 1465745cd3c5Smaybee ds->ds_phys = NULL; 1466745cd3c5Smaybee mutex_destroy(&arg.lock); 1467745cd3c5Smaybee cv_destroy(&arg.cv); 1468745cd3c5Smaybee } 1469745cd3c5Smaybee 1470c33e334fSMatthew Ahrens static void 1471c33e334fSMatthew Ahrens remove_from_next_clones(dsl_dataset_t *ds, uint64_t obj, dmu_tx_t *tx) 1472c33e334fSMatthew Ahrens { 1473c33e334fSMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1474c33e334fSMatthew Ahrens uint64_t count; 1475c33e334fSMatthew Ahrens int err; 1476c33e334fSMatthew Ahrens 1477c33e334fSMatthew Ahrens ASSERT(ds->ds_phys->ds_num_children >= 2); 1478c33e334fSMatthew Ahrens err = zap_remove_int(mos, ds->ds_phys->ds_next_clones_obj, obj, tx); 1479c33e334fSMatthew Ahrens /* 1480c33e334fSMatthew Ahrens * The err should not be ENOENT, but a bug in a previous version 1481c33e334fSMatthew Ahrens * of the code could cause upgrade_clones_cb() to not set 1482c33e334fSMatthew Ahrens * ds_next_snap_obj when it should, leading to a missing entry. 1483c33e334fSMatthew Ahrens * If we knew that the pool was created after 1484c33e334fSMatthew Ahrens * SPA_VERSION_NEXT_CLONES, we could assert that it isn't 1485c33e334fSMatthew Ahrens * ENOENT. However, at least we can check that we don't have 1486c33e334fSMatthew Ahrens * too many entries in the next_clones_obj even after failing to 1487c33e334fSMatthew Ahrens * remove this one. 1488c33e334fSMatthew Ahrens */ 1489c33e334fSMatthew Ahrens if (err != ENOENT) { 1490b420f3adSRichard Lowe VERIFY3U(err, ==, 0); 1491c33e334fSMatthew Ahrens } 1492b420f3adSRichard Lowe ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj, 1493b420f3adSRichard Lowe &count)); 1494c33e334fSMatthew Ahrens ASSERT3U(count, <=, ds->ds_phys->ds_num_children - 2); 1495c33e334fSMatthew Ahrens } 1496c33e334fSMatthew Ahrens 1497cde58dbcSMatthew Ahrens static void 1498cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx) 1499cde58dbcSMatthew Ahrens { 1500cde58dbcSMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1501cde58dbcSMatthew Ahrens zap_cursor_t zc; 1502cde58dbcSMatthew Ahrens zap_attribute_t za; 1503cde58dbcSMatthew Ahrens 1504cde58dbcSMatthew Ahrens /* 1505cde58dbcSMatthew Ahrens * If it is the old version, dd_clones doesn't exist so we can't 1506cde58dbcSMatthew Ahrens * find the clones, but deadlist_remove_key() is a no-op so it 1507cde58dbcSMatthew Ahrens * doesn't matter. 1508cde58dbcSMatthew Ahrens */ 1509cde58dbcSMatthew Ahrens if (ds->ds_dir->dd_phys->dd_clones == 0) 1510cde58dbcSMatthew Ahrens return; 1511cde58dbcSMatthew Ahrens 1512cde58dbcSMatthew Ahrens for (zap_cursor_init(&zc, mos, ds->ds_dir->dd_phys->dd_clones); 1513cde58dbcSMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 1514cde58dbcSMatthew Ahrens zap_cursor_advance(&zc)) { 1515cde58dbcSMatthew Ahrens dsl_dataset_t *clone; 1516cde58dbcSMatthew Ahrens 1517b420f3adSRichard Lowe VERIFY3U(0, ==, dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 1518cde58dbcSMatthew Ahrens za.za_first_integer, FTAG, &clone)); 1519cde58dbcSMatthew Ahrens if (clone->ds_dir->dd_origin_txg > mintxg) { 1520cde58dbcSMatthew Ahrens dsl_deadlist_remove_key(&clone->ds_deadlist, 1521cde58dbcSMatthew Ahrens mintxg, tx); 1522cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(clone, mintxg, tx); 1523cde58dbcSMatthew Ahrens } 1524cde58dbcSMatthew Ahrens dsl_dataset_rele(clone, FTAG); 1525cde58dbcSMatthew Ahrens } 1526cde58dbcSMatthew Ahrens zap_cursor_fini(&zc); 1527cde58dbcSMatthew Ahrens } 1528cde58dbcSMatthew Ahrens 1529cde58dbcSMatthew Ahrens struct process_old_arg { 1530cde58dbcSMatthew Ahrens dsl_dataset_t *ds; 1531cde58dbcSMatthew Ahrens dsl_dataset_t *ds_prev; 1532cde58dbcSMatthew Ahrens boolean_t after_branch_point; 1533cde58dbcSMatthew Ahrens zio_t *pio; 1534cde58dbcSMatthew Ahrens uint64_t used, comp, uncomp; 1535cde58dbcSMatthew Ahrens }; 1536cde58dbcSMatthew Ahrens 1537cde58dbcSMatthew Ahrens static int 1538cde58dbcSMatthew Ahrens process_old_cb(void *arg, const blkptr_t *bp, dmu_tx_t *tx) 1539cde58dbcSMatthew Ahrens { 1540cde58dbcSMatthew Ahrens struct process_old_arg *poa = arg; 1541cde58dbcSMatthew Ahrens dsl_pool_t *dp = poa->ds->ds_dir->dd_pool; 1542cde58dbcSMatthew Ahrens 1543cde58dbcSMatthew Ahrens if (bp->blk_birth <= poa->ds->ds_phys->ds_prev_snap_txg) { 1544cde58dbcSMatthew Ahrens dsl_deadlist_insert(&poa->ds->ds_deadlist, bp, tx); 1545cde58dbcSMatthew Ahrens if (poa->ds_prev && !poa->after_branch_point && 1546cde58dbcSMatthew Ahrens bp->blk_birth > 1547cde58dbcSMatthew Ahrens poa->ds_prev->ds_phys->ds_prev_snap_txg) { 1548cde58dbcSMatthew Ahrens poa->ds_prev->ds_phys->ds_unique_bytes += 1549cde58dbcSMatthew Ahrens bp_get_dsize_sync(dp->dp_spa, bp); 1550cde58dbcSMatthew Ahrens } 1551cde58dbcSMatthew Ahrens } else { 1552cde58dbcSMatthew Ahrens poa->used += bp_get_dsize_sync(dp->dp_spa, bp); 1553cde58dbcSMatthew Ahrens poa->comp += BP_GET_PSIZE(bp); 1554cde58dbcSMatthew Ahrens poa->uncomp += BP_GET_UCSIZE(bp); 1555cde58dbcSMatthew Ahrens dsl_free_sync(poa->pio, dp, tx->tx_txg, bp); 1556cde58dbcSMatthew Ahrens } 1557cde58dbcSMatthew Ahrens return (0); 1558cde58dbcSMatthew Ahrens } 1559cde58dbcSMatthew Ahrens 1560cde58dbcSMatthew Ahrens static void 1561cde58dbcSMatthew Ahrens process_old_deadlist(dsl_dataset_t *ds, dsl_dataset_t *ds_prev, 1562cde58dbcSMatthew Ahrens dsl_dataset_t *ds_next, boolean_t after_branch_point, dmu_tx_t *tx) 1563cde58dbcSMatthew Ahrens { 1564cde58dbcSMatthew Ahrens struct process_old_arg poa = { 0 }; 1565cde58dbcSMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 1566cde58dbcSMatthew Ahrens objset_t *mos = dp->dp_meta_objset; 1567cde58dbcSMatthew Ahrens 1568cde58dbcSMatthew Ahrens ASSERT(ds->ds_deadlist.dl_oldfmt); 1569cde58dbcSMatthew Ahrens ASSERT(ds_next->ds_deadlist.dl_oldfmt); 1570cde58dbcSMatthew Ahrens 1571cde58dbcSMatthew Ahrens poa.ds = ds; 1572cde58dbcSMatthew Ahrens poa.ds_prev = ds_prev; 1573cde58dbcSMatthew Ahrens poa.after_branch_point = after_branch_point; 1574cde58dbcSMatthew Ahrens poa.pio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1575b420f3adSRichard Lowe VERIFY3U(0, ==, bpobj_iterate(&ds_next->ds_deadlist.dl_bpobj, 1576cde58dbcSMatthew Ahrens process_old_cb, &poa, tx)); 1577b420f3adSRichard Lowe VERIFY3U(zio_wait(poa.pio), ==, 0); 1578cde58dbcSMatthew Ahrens ASSERT3U(poa.used, ==, ds->ds_phys->ds_unique_bytes); 1579cde58dbcSMatthew Ahrens 1580cde58dbcSMatthew Ahrens /* change snapused */ 1581cde58dbcSMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 1582cde58dbcSMatthew Ahrens -poa.used, -poa.comp, -poa.uncomp, tx); 1583cde58dbcSMatthew Ahrens 1584cde58dbcSMatthew Ahrens /* swap next's deadlist to our deadlist */ 1585cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1586cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds_next->ds_deadlist); 1587cde58dbcSMatthew Ahrens SWITCH64(ds_next->ds_phys->ds_deadlist_obj, 1588cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj); 1589cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, mos, ds->ds_phys->ds_deadlist_obj); 1590cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds_next->ds_deadlist, mos, 1591cde58dbcSMatthew Ahrens ds_next->ds_phys->ds_deadlist_obj); 1592cde58dbcSMatthew Ahrens } 1593cde58dbcSMatthew Ahrens 1594ad135b5dSChristopher Siden static int 1595ad135b5dSChristopher Siden old_synchronous_dataset_destroy(dsl_dataset_t *ds, dmu_tx_t *tx) 1596ad135b5dSChristopher Siden { 1597ad135b5dSChristopher Siden int err; 1598ad135b5dSChristopher Siden struct killarg ka; 1599ad135b5dSChristopher Siden 1600ad135b5dSChristopher Siden /* 1601ad135b5dSChristopher Siden * Free everything that we point to (that's born after 1602ad135b5dSChristopher Siden * the previous snapshot, if we are a clone) 1603ad135b5dSChristopher Siden * 1604ad135b5dSChristopher Siden * NB: this should be very quick, because we already 1605ad135b5dSChristopher Siden * freed all the objects in open context. 1606ad135b5dSChristopher Siden */ 1607ad135b5dSChristopher Siden ka.ds = ds; 1608ad135b5dSChristopher Siden ka.tx = tx; 1609ad135b5dSChristopher Siden err = traverse_dataset(ds, 1610ad135b5dSChristopher Siden ds->ds_phys->ds_prev_snap_txg, TRAVERSE_POST, 1611ad135b5dSChristopher Siden kill_blkptr, &ka); 1612b420f3adSRichard Lowe ASSERT3U(err, ==, 0); 1613ad135b5dSChristopher Siden ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || ds->ds_phys->ds_unique_bytes == 0); 1614ad135b5dSChristopher Siden 1615ad135b5dSChristopher Siden return (err); 1616ad135b5dSChristopher Siden } 1617ad135b5dSChristopher Siden 16183cb34c60Sahrens void 16193f9d6ad7SLin Ling dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) 16201d452cf5Sahrens { 1621842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1622842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 16231d452cf5Sahrens int err; 16241d452cf5Sahrens int after_branch_point = FALSE; 16251d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 16261d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 16271d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 162899d5e173STim Haley boolean_t wont_destroy; 16291d452cf5Sahrens uint64_t obj; 16301d452cf5Sahrens 163199d5e173STim Haley wont_destroy = (dsda->defer && 163299d5e173STim Haley (ds->ds_userrefs > 0 || ds->ds_phys->ds_num_children > 1)); 163399d5e173STim Haley 163499d5e173STim Haley ASSERT(ds->ds_owner || wont_destroy); 1635842727c2SChris Kirby ASSERT(dsda->defer || ds->ds_phys->ds_num_children <= 1); 16361d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 16371d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 16381d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 16391d452cf5Sahrens 164099d5e173STim Haley if (wont_destroy) { 1641842727c2SChris Kirby ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 164299d5e173STim Haley dmu_buf_will_dirty(ds->ds_dbuf, tx); 164399d5e173STim Haley ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY; 16444445fffbSMatthew Ahrens spa_history_log_internal_ds(ds, "defer_destroy", tx, ""); 164599d5e173STim Haley return; 1646842727c2SChris Kirby } 1647842727c2SChris Kirby 16484445fffbSMatthew Ahrens /* We need to log before removing it from the namespace. */ 16494445fffbSMatthew Ahrens spa_history_log_internal_ds(ds, "destroy", tx, ""); 16504445fffbSMatthew Ahrens 1651745cd3c5Smaybee /* signal any waiters that this dataset is going away */ 1652745cd3c5Smaybee mutex_enter(&ds->ds_lock); 1653745cd3c5Smaybee ds->ds_owner = dsl_reaper; 1654745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 1655745cd3c5Smaybee mutex_exit(&ds->ds_lock); 1656745cd3c5Smaybee 1657a9799022Sck /* Remove our reservation */ 1658a9799022Sck if (ds->ds_reserved != 0) { 165992241e0bSTom Erickson dsl_prop_setarg_t psa; 166092241e0bSTom Erickson uint64_t value = 0; 166192241e0bSTom Erickson 166292241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refreservation", 166392241e0bSTom Erickson (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), 166492241e0bSTom Erickson &value); 166592241e0bSTom Erickson psa.psa_effective_value = 0; /* predict default value */ 166692241e0bSTom Erickson 16673f9d6ad7SLin Ling dsl_dataset_set_reservation_sync(ds, &psa, tx); 1668b420f3adSRichard Lowe ASSERT3U(ds->ds_reserved, ==, 0); 1669a9799022Sck } 1670a9799022Sck 16711d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 16721d452cf5Sahrens 16733f9d6ad7SLin Ling dsl_scan_ds_destroyed(ds, tx); 1674088f3894Sahrens 16751d452cf5Sahrens obj = ds->ds_object; 1676fa9e4066Sahrens 1677fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1678fa9e4066Sahrens if (ds->ds_prev) { 1679fa9e4066Sahrens ds_prev = ds->ds_prev; 1680fa9e4066Sahrens } else { 1681745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1682745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev)); 1683fa9e4066Sahrens } 1684fa9e4066Sahrens after_branch_point = 1685fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1686fa9e4066Sahrens 1687fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1688088f3894Sahrens if (after_branch_point && 1689088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj != 0) { 1690c33e334fSMatthew Ahrens remove_from_next_clones(ds_prev, obj, tx); 1691088f3894Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1692088f3894Sahrens VERIFY(0 == zap_add_int(mos, 1693088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, 1694088f3894Sahrens ds->ds_phys->ds_next_snap_obj, tx)); 1695088f3894Sahrens } 1696088f3894Sahrens } 1697fa9e4066Sahrens if (after_branch_point && 1698fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1699fa9e4066Sahrens /* This clone is toast. */ 1700fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1701fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1702842727c2SChris Kirby 1703842727c2SChris Kirby /* 1704842727c2SChris Kirby * If the clone's origin has no other clones, no 1705842727c2SChris Kirby * user holds, and has been marked for deferred 1706842727c2SChris Kirby * deletion, then we should have done the necessary 1707842727c2SChris Kirby * destroy setup for it. 1708842727c2SChris Kirby */ 1709842727c2SChris Kirby if (ds_prev->ds_phys->ds_num_children == 1 && 1710842727c2SChris Kirby ds_prev->ds_userrefs == 0 && 1711842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds_prev)) { 1712842727c2SChris Kirby ASSERT3P(dsda->rm_origin, !=, NULL); 1713842727c2SChris Kirby } else { 1714842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 1715842727c2SChris Kirby } 1716fa9e4066Sahrens } else if (!after_branch_point) { 1717fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1718fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1719fa9e4066Sahrens } 1720fa9e4066Sahrens } 1721fa9e4066Sahrens 17223f9d6ad7SLin Ling if (dsl_dataset_is_snapshot(ds)) { 1723fa9e4066Sahrens dsl_dataset_t *ds_next; 1724a9799022Sck uint64_t old_unique; 1725cde58dbcSMatthew Ahrens uint64_t used = 0, comp = 0, uncomp = 0; 1726fa9e4066Sahrens 1727745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1728745cd3c5Smaybee ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next)); 1729fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1730fa9e4066Sahrens 17313f9d6ad7SLin Ling old_unique = ds_next->ds_phys->ds_unique_bytes; 1732a9799022Sck 1733fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1734fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1735fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1736fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1737fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1738fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1739fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1740fa9e4066Sahrens 17413113f7ceSGeorge Wilson 1742cde58dbcSMatthew Ahrens if (ds_next->ds_deadlist.dl_oldfmt) { 1743cde58dbcSMatthew Ahrens process_old_deadlist(ds, ds_prev, ds_next, 1744cde58dbcSMatthew Ahrens after_branch_point, tx); 1745cde58dbcSMatthew Ahrens } else { 1746cde58dbcSMatthew Ahrens /* Adjust prev's unique space. */ 1747cde58dbcSMatthew Ahrens if (ds_prev && !after_branch_point) { 1748cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 1749cde58dbcSMatthew Ahrens ds_prev->ds_phys->ds_prev_snap_txg, 1750cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 1751cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1752cde58dbcSMatthew Ahrens ds_prev->ds_phys->ds_unique_bytes += used; 1753fa9e4066Sahrens } 175474e7dc98SMatthew Ahrens 1755cde58dbcSMatthew Ahrens /* Adjust snapused. */ 1756cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_next->ds_deadlist, 1757cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, 1758cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1759cde58dbcSMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 1760cde58dbcSMatthew Ahrens -used, -comp, -uncomp, tx); 1761cde58dbcSMatthew Ahrens 1762cde58dbcSMatthew Ahrens /* Move blocks to be freed to pool's free list. */ 1763cde58dbcSMatthew Ahrens dsl_deadlist_move_bpobj(&ds_next->ds_deadlist, 1764cde58dbcSMatthew Ahrens &dp->dp_free_bpobj, ds->ds_phys->ds_prev_snap_txg, 1765cde58dbcSMatthew Ahrens tx); 1766cde58dbcSMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_free_dir, 1767cde58dbcSMatthew Ahrens DD_USED_HEAD, used, comp, uncomp, tx); 1768cde58dbcSMatthew Ahrens 1769cde58dbcSMatthew Ahrens /* Merge our deadlist into next's and free it. */ 1770cde58dbcSMatthew Ahrens dsl_deadlist_merge(&ds_next->ds_deadlist, 1771cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj, tx); 1772cde58dbcSMatthew Ahrens } 1773cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1774cde58dbcSMatthew Ahrens dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx); 1775fa9e4066Sahrens 1776cde58dbcSMatthew Ahrens /* Collapse range in clone heads */ 1777cde58dbcSMatthew Ahrens dsl_dataset_remove_clones_key(ds, 1778cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, tx); 1779fa9e4066Sahrens 17803f9d6ad7SLin Ling if (dsl_dataset_is_snapshot(ds_next)) { 1781cde58dbcSMatthew Ahrens dsl_dataset_t *ds_nextnext; 1782cde58dbcSMatthew Ahrens 1783fa9e4066Sahrens /* 1784fa9e4066Sahrens * Update next's unique to include blocks which 1785fa9e4066Sahrens * were previously shared by only this snapshot 1786fa9e4066Sahrens * and it. Those blocks will be born after the 1787fa9e4066Sahrens * prev snap and before this snap, and will have 1788fa9e4066Sahrens * died after the next snap and before the one 1789fa9e4066Sahrens * after that (ie. be on the snap after next's 1790fa9e4066Sahrens * deadlist). 1791fa9e4066Sahrens */ 1792745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1793745cd3c5Smaybee ds_next->ds_phys->ds_next_snap_obj, 1794cde58dbcSMatthew Ahrens FTAG, &ds_nextnext)); 1795cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&ds_nextnext->ds_deadlist, 179674e7dc98SMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 1797cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, 1798cde58dbcSMatthew Ahrens &used, &comp, &uncomp); 1799cde58dbcSMatthew Ahrens ds_next->ds_phys->ds_unique_bytes += used; 1800cde58dbcSMatthew Ahrens dsl_dataset_rele(ds_nextnext, FTAG); 1801fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1802cde58dbcSMatthew Ahrens 1803cde58dbcSMatthew Ahrens /* Collapse range in this head. */ 1804cde58dbcSMatthew Ahrens dsl_dataset_t *hds; 1805b420f3adSRichard Lowe VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 1806cde58dbcSMatthew Ahrens ds->ds_dir->dd_phys->dd_head_dataset_obj, 1807cde58dbcSMatthew Ahrens FTAG, &hds)); 1808cde58dbcSMatthew Ahrens dsl_deadlist_remove_key(&hds->ds_deadlist, 1809cde58dbcSMatthew Ahrens ds->ds_phys->ds_creation_txg, tx); 1810cde58dbcSMatthew Ahrens dsl_dataset_rele(hds, FTAG); 1811cde58dbcSMatthew Ahrens 1812fa9e4066Sahrens } else { 1813fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1814745cd3c5Smaybee dsl_dataset_drop_ref(ds_next->ds_prev, ds_next); 1815745cd3c5Smaybee ds_next->ds_prev = NULL; 1816fa9e4066Sahrens if (ds_prev) { 1817745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1818745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 1819745cd3c5Smaybee ds_next, &ds_next->ds_prev)); 1820fa9e4066Sahrens } 1821a9799022Sck 1822a9799022Sck dsl_dataset_recalc_head_uniq(ds_next); 1823a9799022Sck 1824a9799022Sck /* 1825a9799022Sck * Reduce the amount of our unconsmed refreservation 1826a9799022Sck * being charged to our parent by the amount of 1827a9799022Sck * new unique data we have gained. 1828a9799022Sck */ 1829a9799022Sck if (old_unique < ds_next->ds_reserved) { 1830a9799022Sck int64_t mrsdelta; 1831a9799022Sck uint64_t new_unique = 1832a9799022Sck ds_next->ds_phys->ds_unique_bytes; 1833a9799022Sck 1834a9799022Sck ASSERT(old_unique <= new_unique); 1835a9799022Sck mrsdelta = MIN(new_unique - old_unique, 1836a9799022Sck ds_next->ds_reserved - old_unique); 183774e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 183874e7dc98SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 1839a9799022Sck } 1840fa9e4066Sahrens } 1841745cd3c5Smaybee dsl_dataset_rele(ds_next, FTAG); 1842fa9e4066Sahrens } else { 1843ad135b5dSChristopher Siden zfeature_info_t *async_destroy = 1844ad135b5dSChristopher Siden &spa_feature_table[SPA_FEATURE_ASYNC_DESTROY]; 1845*ce636f8bSMatthew Ahrens objset_t *os; 1846ad135b5dSChristopher Siden 1847fa9e4066Sahrens /* 1848fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1849fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1850fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1851fa9e4066Sahrens * safe to ignore the deadlist contents.) 1852fa9e4066Sahrens */ 1853cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 1854cde58dbcSMatthew Ahrens dsl_deadlist_free(mos, ds->ds_phys->ds_deadlist_obj, tx); 1855fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1856fa9e4066Sahrens 1857*ce636f8bSMatthew Ahrens VERIFY3U(0, ==, dmu_objset_from_ds(ds, &os)); 1858*ce636f8bSMatthew Ahrens 1859ad135b5dSChristopher Siden if (!spa_feature_is_enabled(dp->dp_spa, async_destroy)) { 1860ad135b5dSChristopher Siden err = old_synchronous_dataset_destroy(ds, tx); 1861ad135b5dSChristopher Siden } else { 1862ad135b5dSChristopher Siden /* 1863ad135b5dSChristopher Siden * Move the bptree into the pool's list of trees to 1864ad135b5dSChristopher Siden * clean up and update space accounting information. 1865ad135b5dSChristopher Siden */ 1866ad135b5dSChristopher Siden uint64_t used, comp, uncomp; 1867ad135b5dSChristopher Siden 1868*ce636f8bSMatthew Ahrens zil_destroy_sync(dmu_objset_zil(os), tx); 1869*ce636f8bSMatthew Ahrens 1870ad135b5dSChristopher Siden if (!spa_feature_is_active(dp->dp_spa, async_destroy)) { 1871ad135b5dSChristopher Siden spa_feature_incr(dp->dp_spa, async_destroy, tx); 1872*ce636f8bSMatthew Ahrens dp->dp_bptree_obj = bptree_alloc(mos, tx); 1873*ce636f8bSMatthew Ahrens VERIFY(zap_add(mos, 1874ad135b5dSChristopher Siden DMU_POOL_DIRECTORY_OBJECT, 1875ad135b5dSChristopher Siden DMU_POOL_BPTREE_OBJ, sizeof (uint64_t), 1, 1876ad135b5dSChristopher Siden &dp->dp_bptree_obj, tx) == 0); 1877ad135b5dSChristopher Siden } 1878ad135b5dSChristopher Siden 1879ad135b5dSChristopher Siden used = ds->ds_dir->dd_phys->dd_used_bytes; 1880ad135b5dSChristopher Siden comp = ds->ds_dir->dd_phys->dd_compressed_bytes; 1881ad135b5dSChristopher Siden uncomp = ds->ds_dir->dd_phys->dd_uncompressed_bytes; 1882ad135b5dSChristopher Siden 1883ad135b5dSChristopher Siden ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 1884ad135b5dSChristopher Siden ds->ds_phys->ds_unique_bytes == used); 1885ad135b5dSChristopher Siden 1886*ce636f8bSMatthew Ahrens bptree_add(mos, dp->dp_bptree_obj, 1887ad135b5dSChristopher Siden &ds->ds_phys->ds_bp, ds->ds_phys->ds_prev_snap_txg, 1888ad135b5dSChristopher Siden used, comp, uncomp, tx); 1889ad135b5dSChristopher Siden dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 1890ad135b5dSChristopher Siden -used, -comp, -uncomp, tx); 1891ad135b5dSChristopher Siden dsl_dir_diduse_space(dp->dp_free_dir, DD_USED_HEAD, 1892ad135b5dSChristopher Siden used, comp, uncomp, tx); 1893ad135b5dSChristopher Siden } 1894ca45db41SChris Kirby 1895ca45db41SChris Kirby if (ds->ds_prev != NULL) { 1896cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 1897b420f3adSRichard Lowe VERIFY3U(0, ==, zap_remove_int(mos, 1898cde58dbcSMatthew Ahrens ds->ds_prev->ds_dir->dd_phys->dd_clones, 1899cde58dbcSMatthew Ahrens ds->ds_object, tx)); 1900cde58dbcSMatthew Ahrens } 1901ca45db41SChris Kirby dsl_dataset_rele(ds->ds_prev, ds); 1902ca45db41SChris Kirby ds->ds_prev = ds_prev = NULL; 1903ca45db41SChris Kirby } 1904fa9e4066Sahrens } 1905fa9e4066Sahrens 19066e0cbcaaSMatthew Ahrens /* 19076e0cbcaaSMatthew Ahrens * This must be done after the dsl_traverse(), because it will 19086e0cbcaaSMatthew Ahrens * re-open the objset. 19096e0cbcaaSMatthew Ahrens */ 19106e0cbcaaSMatthew Ahrens if (ds->ds_objset) { 19116e0cbcaaSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 19126e0cbcaaSMatthew Ahrens ds->ds_objset = NULL; 19136e0cbcaaSMatthew Ahrens } 19146e0cbcaaSMatthew Ahrens 19151d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1916745cd3c5Smaybee /* Erase the link in the dir */ 19171d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 19181d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1919745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0); 1920745cd3c5Smaybee err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1921745cd3c5Smaybee ASSERT(err == 0); 1922fa9e4066Sahrens } else { 1923fa9e4066Sahrens /* remove from snapshot namespace */ 1924fa9e4066Sahrens dsl_dataset_t *ds_head; 1925745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0); 1926745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1927745cd3c5Smaybee ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head)); 19288660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1929fa9e4066Sahrens #ifdef ZFS_DEBUG 1930fa9e4066Sahrens { 1931fa9e4066Sahrens uint64_t val; 1932ab04eb8eStimh 1933745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds_head, 1934ab04eb8eStimh ds->ds_snapname, &val); 1935b420f3adSRichard Lowe ASSERT3U(err, ==, 0); 1936fa9e4066Sahrens ASSERT3U(val, ==, obj); 1937fa9e4066Sahrens } 1938fa9e4066Sahrens #endif 1939745cd3c5Smaybee err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx); 1940fa9e4066Sahrens ASSERT(err == 0); 1941745cd3c5Smaybee dsl_dataset_rele(ds_head, FTAG); 1942fa9e4066Sahrens } 1943fa9e4066Sahrens 1944fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1945745cd3c5Smaybee dsl_dataset_rele(ds_prev, FTAG); 1946fa9e4066Sahrens 1947990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 1948ecd6cf80Smarks 1949088f3894Sahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 1950088f3894Sahrens uint64_t count; 1951088f3894Sahrens ASSERT(0 == zap_count(mos, 1952088f3894Sahrens ds->ds_phys->ds_next_clones_obj, &count) && count == 0); 1953088f3894Sahrens VERIFY(0 == dmu_object_free(mos, 1954088f3894Sahrens ds->ds_phys->ds_next_clones_obj, tx)); 1955088f3894Sahrens } 195674e7dc98SMatthew Ahrens if (ds->ds_phys->ds_props_obj != 0) 195774e7dc98SMatthew Ahrens VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_props_obj, tx)); 1958842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) 1959842727c2SChris Kirby VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx)); 1960745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 1961745cd3c5Smaybee ds->ds_dir = NULL; 1962745cd3c5Smaybee dsl_dataset_drain_refs(ds, tag); 19631d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1964842727c2SChris Kirby 1965842727c2SChris Kirby if (dsda->rm_origin) { 1966842727c2SChris Kirby /* 1967842727c2SChris Kirby * Remove the origin of the clone we just destroyed. 1968842727c2SChris Kirby */ 1969842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1970842727c2SChris Kirby 1971ca45db41SChris Kirby ndsda.ds = dsda->rm_origin; 19723f9d6ad7SLin Ling dsl_dataset_destroy_sync(&ndsda, tag, tx); 1973842727c2SChris Kirby } 1974fa9e4066Sahrens } 1975fa9e4066Sahrens 1976a9799022Sck static int 1977a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx) 1978a9799022Sck { 1979a9799022Sck uint64_t asize; 1980a9799022Sck 1981a9799022Sck if (!dmu_tx_is_syncing(tx)) 1982a9799022Sck return (0); 1983a9799022Sck 1984a9799022Sck /* 1985a9799022Sck * If there's an fs-only reservation, any blocks that might become 1986a9799022Sck * owned by the snapshot dataset must be accommodated by space 1987a9799022Sck * outside of the reservation. 1988a9799022Sck */ 19893f9d6ad7SLin Ling ASSERT(ds->ds_reserved == 0 || DS_UNIQUE_IS_ACCURATE(ds)); 19903f9d6ad7SLin Ling asize = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 19916e0cbcaaSMatthew Ahrens if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 1992a9799022Sck return (ENOSPC); 1993a9799022Sck 1994a9799022Sck /* 19954445fffbSMatthew Ahrens * Propagate any reserved space for this snapshot to other 1996a9799022Sck * snapshot checks in this sync group. 1997a9799022Sck */ 1998a9799022Sck if (asize > 0) 1999a9799022Sck dsl_dir_willuse_space(ds->ds_dir, asize, tx); 2000a9799022Sck 2001a9799022Sck return (0); 2002a9799022Sck } 2003a9799022Sck 2004fa9e4066Sahrens int 20054445fffbSMatthew Ahrens dsl_dataset_snapshot_check(dsl_dataset_t *ds, const char *snapname, 20064445fffbSMatthew Ahrens dmu_tx_t *tx) 2007fa9e4066Sahrens { 2008fa9e4066Sahrens int err; 20091d452cf5Sahrens uint64_t value; 2010fa9e4066Sahrens 20111d452cf5Sahrens /* 20121d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 20131d452cf5Sahrens * is already one, try again. 20141d452cf5Sahrens */ 20151d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 20161d452cf5Sahrens return (EAGAIN); 2017fa9e4066Sahrens 20181d452cf5Sahrens /* 20194445fffbSMatthew Ahrens * Check for conflicting snapshot name. 20201d452cf5Sahrens */ 2021745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds, snapname, &value); 20221d452cf5Sahrens if (err == 0) 2023fa9e4066Sahrens return (EEXIST); 20241d452cf5Sahrens if (err != ENOENT) 20251d452cf5Sahrens return (err); 2026fa9e4066Sahrens 2027b7661cccSmmusante /* 2028b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 2029b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 2030b7661cccSmmusante */ 2031b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 2032b7661cccSmmusante return (ENAMETOOLONG); 2033b7661cccSmmusante 2034a9799022Sck err = dsl_dataset_snapshot_reserve_space(ds, tx); 2035a9799022Sck if (err) 2036a9799022Sck return (err); 2037a9799022Sck 20381d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 20391d452cf5Sahrens return (0); 20401d452cf5Sahrens } 2041fa9e4066Sahrens 20421d452cf5Sahrens void 20434445fffbSMatthew Ahrens dsl_dataset_snapshot_sync(dsl_dataset_t *ds, const char *snapname, 20444445fffbSMatthew Ahrens dmu_tx_t *tx) 20451d452cf5Sahrens { 20461d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 20471d452cf5Sahrens dmu_buf_t *dbuf; 20481d452cf5Sahrens dsl_dataset_phys_t *dsphys; 2049088f3894Sahrens uint64_t dsobj, crtxg; 20501d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 20511d452cf5Sahrens int err; 2052fa9e4066Sahrens 20531d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 2054fa9e4066Sahrens 2055088f3894Sahrens /* 2056088f3894Sahrens * The origin's ds_creation_txg has to be < TXG_INITIAL 2057088f3894Sahrens */ 2058088f3894Sahrens if (strcmp(snapname, ORIGIN_DIR_NAME) == 0) 2059088f3894Sahrens crtxg = 1; 2060088f3894Sahrens else 2061088f3894Sahrens crtxg = tx->tx_txg; 2062088f3894Sahrens 20631649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 20641649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 2065ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 2066fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 2067fa9e4066Sahrens dsphys = dbuf->db_data; 2068745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 20691d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 2070fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 2071fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 2072fa9e4066Sahrens sizeof (dsphys->ds_guid)); 2073fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 2074fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 2075fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 2076fa9e4066Sahrens dsphys->ds_num_children = 1; 2077fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 2078088f3894Sahrens dsphys->ds_creation_txg = crtxg; 2079fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 2080ad135b5dSChristopher Siden dsphys->ds_referenced_bytes = ds->ds_phys->ds_referenced_bytes; 2081fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 2082fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 208399653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 2084fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 2085ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 2086fa9e4066Sahrens 20871d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 20881d452cf5Sahrens if (ds->ds_prev) { 2089088f3894Sahrens uint64_t next_clones_obj = 2090088f3894Sahrens ds->ds_prev->ds_phys->ds_next_clones_obj; 20911d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 2092fa9e4066Sahrens ds->ds_object || 20931d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 20941d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 20951d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 2096fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 20971d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 20981d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 2099088f3894Sahrens } else if (next_clones_obj != 0) { 2100c33e334fSMatthew Ahrens remove_from_next_clones(ds->ds_prev, 2101c33e334fSMatthew Ahrens dsphys->ds_next_snap_obj, tx); 2102b420f3adSRichard Lowe VERIFY3U(0, ==, zap_add_int(mos, 2103088f3894Sahrens next_clones_obj, dsobj, tx)); 2104fa9e4066Sahrens } 2105fa9e4066Sahrens } 2106fa9e4066Sahrens 2107a9799022Sck /* 2108a9799022Sck * If we have a reference-reservation on this dataset, we will 2109a9799022Sck * need to increase the amount of refreservation being charged 2110a9799022Sck * since our unique space is going to zero. 2111a9799022Sck */ 2112a9799022Sck if (ds->ds_reserved) { 21133f9d6ad7SLin Ling int64_t delta; 21143f9d6ad7SLin Ling ASSERT(DS_UNIQUE_IS_ACCURATE(ds)); 21153f9d6ad7SLin Ling delta = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 211674e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, 21173f9d6ad7SLin Ling delta, 0, 0, tx); 2118a9799022Sck } 2119a9799022Sck 2120fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 2121cde58dbcSMatthew Ahrens zfs_dbgmsg("taking snapshot %s@%s/%llu; newkey=%llu", 2122cde58dbcSMatthew Ahrens ds->ds_dir->dd_myname, snapname, dsobj, 2123cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg); 2124cde58dbcSMatthew Ahrens ds->ds_phys->ds_deadlist_obj = dsl_deadlist_clone(&ds->ds_deadlist, 2125cde58dbcSMatthew Ahrens UINT64_MAX, ds->ds_phys->ds_prev_snap_obj, tx); 2126cde58dbcSMatthew Ahrens dsl_deadlist_close(&ds->ds_deadlist); 2127cde58dbcSMatthew Ahrens dsl_deadlist_open(&ds->ds_deadlist, mos, ds->ds_phys->ds_deadlist_obj); 2128cde58dbcSMatthew Ahrens dsl_deadlist_add_key(&ds->ds_deadlist, 2129cde58dbcSMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, tx); 2130cde58dbcSMatthew Ahrens 2131a4611edeSahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg); 2132fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 2133088f3894Sahrens ds->ds_phys->ds_prev_snap_txg = crtxg; 2134fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 2135a9799022Sck if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 2136a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 2137fa9e4066Sahrens 2138fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 2139fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 2140fa9e4066Sahrens ASSERT(err == 0); 2141fa9e4066Sahrens 2142fa9e4066Sahrens if (ds->ds_prev) 2143745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 2144745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 2145745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev)); 2146ecd6cf80Smarks 21473f9d6ad7SLin Ling dsl_scan_ds_snapshotted(ds, tx); 2148088f3894Sahrens 214971eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 215071eb0538SChris Kirby 21514445fffbSMatthew Ahrens spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, ""); 2152fa9e4066Sahrens } 2153fa9e4066Sahrens 2154fa9e4066Sahrens void 2155c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 2156fa9e4066Sahrens { 2157fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 2158503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 2159fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 2160fa9e4066Sahrens 216191ebeef5Sahrens /* 216291ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 216391ebeef5Sahrens * sync it out now. 216491ebeef5Sahrens */ 216591ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 216691ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 216791ebeef5Sahrens 2168503ad85cSMatthew Ahrens dmu_objset_sync(ds->ds_objset, zio, tx); 2169fa9e4066Sahrens } 2170fa9e4066Sahrens 217119b94df9SMatthew Ahrens static void 217219b94df9SMatthew Ahrens get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv) 217319b94df9SMatthew Ahrens { 217419b94df9SMatthew Ahrens uint64_t count = 0; 217519b94df9SMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 217619b94df9SMatthew Ahrens zap_cursor_t zc; 217719b94df9SMatthew Ahrens zap_attribute_t za; 217819b94df9SMatthew Ahrens nvlist_t *propval; 217919b94df9SMatthew Ahrens nvlist_t *val; 218019b94df9SMatthew Ahrens 218119b94df9SMatthew Ahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 218219b94df9SMatthew Ahrens VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0); 218319b94df9SMatthew Ahrens VERIFY(nvlist_alloc(&val, NV_UNIQUE_NAME, KM_SLEEP) == 0); 218419b94df9SMatthew Ahrens 218519b94df9SMatthew Ahrens /* 218619b94df9SMatthew Ahrens * There may me missing entries in ds_next_clones_obj 218719b94df9SMatthew Ahrens * due to a bug in a previous version of the code. 218819b94df9SMatthew Ahrens * Only trust it if it has the right number of entries. 218919b94df9SMatthew Ahrens */ 219019b94df9SMatthew Ahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 2191b420f3adSRichard Lowe ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj, 219219b94df9SMatthew Ahrens &count)); 219319b94df9SMatthew Ahrens } 219419b94df9SMatthew Ahrens if (count != ds->ds_phys->ds_num_children - 1) { 219519b94df9SMatthew Ahrens goto fail; 219619b94df9SMatthew Ahrens } 219719b94df9SMatthew Ahrens for (zap_cursor_init(&zc, mos, ds->ds_phys->ds_next_clones_obj); 219819b94df9SMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 219919b94df9SMatthew Ahrens zap_cursor_advance(&zc)) { 220019b94df9SMatthew Ahrens dsl_dataset_t *clone; 220119b94df9SMatthew Ahrens char buf[ZFS_MAXNAMELEN]; 2202ad135b5dSChristopher Siden /* 2203ad135b5dSChristopher Siden * Even though we hold the dp_config_rwlock, the dataset 2204ad135b5dSChristopher Siden * may fail to open, returning ENOENT. If there is a 2205ad135b5dSChristopher Siden * thread concurrently attempting to destroy this 2206ad135b5dSChristopher Siden * dataset, it will have the ds_rwlock held for 2207ad135b5dSChristopher Siden * RW_WRITER. Our call to dsl_dataset_hold_obj() -> 2208ad135b5dSChristopher Siden * dsl_dataset_hold_ref() will fail its 2209ad135b5dSChristopher Siden * rw_tryenter(&ds->ds_rwlock, RW_READER), drop the 2210ad135b5dSChristopher Siden * dp_config_rwlock, and wait for the destroy progress 2211ad135b5dSChristopher Siden * and signal ds_exclusive_cv. If the destroy was 2212ad135b5dSChristopher Siden * successful, we will see that 2213ad135b5dSChristopher Siden * DSL_DATASET_IS_DESTROYED(), and return ENOENT. 2214ad135b5dSChristopher Siden */ 221519b94df9SMatthew Ahrens if (dsl_dataset_hold_obj(ds->ds_dir->dd_pool, 2216ad135b5dSChristopher Siden za.za_first_integer, FTAG, &clone) != 0) 2217ad135b5dSChristopher Siden continue; 221819b94df9SMatthew Ahrens dsl_dir_name(clone->ds_dir, buf); 221919b94df9SMatthew Ahrens VERIFY(nvlist_add_boolean(val, buf) == 0); 222019b94df9SMatthew Ahrens dsl_dataset_rele(clone, FTAG); 222119b94df9SMatthew Ahrens } 222219b94df9SMatthew Ahrens zap_cursor_fini(&zc); 222319b94df9SMatthew Ahrens VERIFY(nvlist_add_nvlist(propval, ZPROP_VALUE, val) == 0); 222419b94df9SMatthew Ahrens VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES), 222519b94df9SMatthew Ahrens propval) == 0); 222619b94df9SMatthew Ahrens fail: 222719b94df9SMatthew Ahrens nvlist_free(val); 222819b94df9SMatthew Ahrens nvlist_free(propval); 222919b94df9SMatthew Ahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 223019b94df9SMatthew Ahrens } 223119b94df9SMatthew Ahrens 2232fa9e4066Sahrens void 2233a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 2234fa9e4066Sahrens { 2235187d6ac0SMatt Ahrens uint64_t refd, avail, uobjs, aobjs, ratio; 2236a9799022Sck 22374445fffbSMatthew Ahrens ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 22384445fffbSMatthew Ahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 22394445fffbSMatthew Ahrens ds->ds_phys->ds_compressed_bytes); 22404445fffbSMatthew Ahrens 22414445fffbSMatthew Ahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio); 22424445fffbSMatthew Ahrens 22434445fffbSMatthew Ahrens if (dsl_dataset_is_snapshot(ds)) { 22444445fffbSMatthew Ahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio); 22454445fffbSMatthew Ahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 22464445fffbSMatthew Ahrens ds->ds_phys->ds_unique_bytes); 22474445fffbSMatthew Ahrens get_clones_stat(ds, nv); 22484445fffbSMatthew Ahrens } else { 22494445fffbSMatthew Ahrens dsl_dir_stats(ds->ds_dir, nv); 22504445fffbSMatthew Ahrens } 2251fa9e4066Sahrens 2252a9799022Sck dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); 2253a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); 2254a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); 2255a9799022Sck 2256a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 2257a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 2258a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 2259a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 2260a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, 2261a9799022Sck ds->ds_quota); 2262a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, 2263a9799022Sck ds->ds_reserved); 2264c5904d13Seschrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, 2265c5904d13Seschrock ds->ds_phys->ds_guid); 22661d713200SEric Schrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE, 22673f9d6ad7SLin Ling ds->ds_phys->ds_unique_bytes); 22681d713200SEric Schrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID, 22691d713200SEric Schrock ds->ds_object); 227092241e0bSTom Erickson dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, 227192241e0bSTom Erickson ds->ds_userrefs); 2272842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2273842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2274fa9e4066Sahrens 227519b94df9SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 227619b94df9SMatthew Ahrens uint64_t written, comp, uncomp; 227719b94df9SMatthew Ahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 227819b94df9SMatthew Ahrens dsl_dataset_t *prev; 227919b94df9SMatthew Ahrens 228019b94df9SMatthew Ahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 228119b94df9SMatthew Ahrens int err = dsl_dataset_hold_obj(dp, 228219b94df9SMatthew Ahrens ds->ds_phys->ds_prev_snap_obj, FTAG, &prev); 228319b94df9SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 228419b94df9SMatthew Ahrens if (err == 0) { 228519b94df9SMatthew Ahrens err = dsl_dataset_space_written(prev, ds, &written, 228619b94df9SMatthew Ahrens &comp, &uncomp); 228719b94df9SMatthew Ahrens dsl_dataset_rele(prev, FTAG); 228819b94df9SMatthew Ahrens if (err == 0) { 228919b94df9SMatthew Ahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN, 229019b94df9SMatthew Ahrens written); 229119b94df9SMatthew Ahrens } 229219b94df9SMatthew Ahrens } 229319b94df9SMatthew Ahrens } 229419b94df9SMatthew Ahrens 2295fa9e4066Sahrens } 2296fa9e4066Sahrens 2297a2eea2e1Sahrens void 2298a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2299a2eea2e1Sahrens { 2300a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2301a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 23023cb34c60Sahrens stat->dds_guid = ds->ds_phys->ds_guid; 23034445fffbSMatthew Ahrens stat->dds_origin[0] = '\0'; 23044445fffbSMatthew Ahrens if (dsl_dataset_is_snapshot(ds)) { 2305a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 2306a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 2307ebedde84SEric Taylor } else { 2308ebedde84SEric Taylor stat->dds_is_snapshot = B_FALSE; 2309ebedde84SEric Taylor stat->dds_num_clones = 0; 2310a2eea2e1Sahrens 23114445fffbSMatthew Ahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 23124445fffbSMatthew Ahrens if (dsl_dir_is_clone(ds->ds_dir)) { 23134445fffbSMatthew Ahrens dsl_dataset_t *ods; 2314a2eea2e1Sahrens 23154445fffbSMatthew Ahrens VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool, 23164445fffbSMatthew Ahrens ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods)); 23174445fffbSMatthew Ahrens dsl_dataset_name(ods, stat->dds_origin); 23184445fffbSMatthew Ahrens dsl_dataset_drop_ref(ods, FTAG); 23194445fffbSMatthew Ahrens } 23204445fffbSMatthew Ahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2321a2eea2e1Sahrens } 2322a2eea2e1Sahrens } 2323a2eea2e1Sahrens 2324a2eea2e1Sahrens uint64_t 2325a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 2326a2eea2e1Sahrens { 232791ebeef5Sahrens return (ds->ds_fsid_guid); 2328a2eea2e1Sahrens } 2329a2eea2e1Sahrens 2330a2eea2e1Sahrens void 2331a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 2332a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 2333a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 2334fa9e4066Sahrens { 2335ad135b5dSChristopher Siden *refdbytesp = ds->ds_phys->ds_referenced_bytes; 2336a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 2337a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) 2338a9799022Sck *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes; 2339a9799022Sck if (ds->ds_quota != 0) { 2340a9799022Sck /* 2341a9799022Sck * Adjust available bytes according to refquota 2342a9799022Sck */ 2343a9799022Sck if (*refdbytesp < ds->ds_quota) 2344a9799022Sck *availbytesp = MIN(*availbytesp, 2345a9799022Sck ds->ds_quota - *refdbytesp); 2346a9799022Sck else 2347a9799022Sck *availbytesp = 0; 2348a9799022Sck } 2349a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 2350a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 2351fa9e4066Sahrens } 2352fa9e4066Sahrens 2353f18faf3fSek boolean_t 2354f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 2355f18faf3fSek { 2356f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 2357f18faf3fSek 2358f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 2359f18faf3fSek dsl_pool_sync_context(dp)); 2360f18faf3fSek if (ds->ds_prev == NULL) 2361f18faf3fSek return (B_FALSE); 2362f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 23636e0cbcaaSMatthew Ahrens ds->ds_prev->ds_phys->ds_creation_txg) { 23646e0cbcaaSMatthew Ahrens objset_t *os, *os_prev; 23656e0cbcaaSMatthew Ahrens /* 23666e0cbcaaSMatthew Ahrens * It may be that only the ZIL differs, because it was 23676e0cbcaaSMatthew Ahrens * reset in the head. Don't count that as being 23686e0cbcaaSMatthew Ahrens * modified. 23696e0cbcaaSMatthew Ahrens */ 23706e0cbcaaSMatthew Ahrens if (dmu_objset_from_ds(ds, &os) != 0) 23716e0cbcaaSMatthew Ahrens return (B_TRUE); 23726e0cbcaaSMatthew Ahrens if (dmu_objset_from_ds(ds->ds_prev, &os_prev) != 0) 23736e0cbcaaSMatthew Ahrens return (B_TRUE); 23746e0cbcaaSMatthew Ahrens return (bcmp(&os->os_phys->os_meta_dnode, 23756e0cbcaaSMatthew Ahrens &os_prev->os_phys->os_meta_dnode, 23766e0cbcaaSMatthew Ahrens sizeof (os->os_phys->os_meta_dnode)) != 0); 23776e0cbcaaSMatthew Ahrens } 2378f18faf3fSek return (B_FALSE); 2379f18faf3fSek } 2380f18faf3fSek 23811d452cf5Sahrens /* ARGSUSED */ 2382fa9e4066Sahrens static int 23831d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 2384fa9e4066Sahrens { 23851d452cf5Sahrens dsl_dataset_t *ds = arg1; 23861d452cf5Sahrens char *newsnapname = arg2; 23871d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 23881d452cf5Sahrens dsl_dataset_t *hds; 2389fa9e4066Sahrens uint64_t val; 23901d452cf5Sahrens int err; 2391fa9e4066Sahrens 2392745cd3c5Smaybee err = dsl_dataset_hold_obj(dd->dd_pool, 2393745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds); 2394fa9e4066Sahrens if (err) 2395fa9e4066Sahrens return (err); 2396fa9e4066Sahrens 23971d452cf5Sahrens /* new name better not be in use */ 2398745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, newsnapname, &val); 2399745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 24001d452cf5Sahrens 24011d452cf5Sahrens if (err == 0) 24021d452cf5Sahrens err = EEXIST; 24031d452cf5Sahrens else if (err == ENOENT) 24041d452cf5Sahrens err = 0; 2405cdf5b4caSmmusante 2406cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 2407cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 2408cdf5b4caSmmusante err = ENAMETOOLONG; 2409cdf5b4caSmmusante 24101d452cf5Sahrens return (err); 24111d452cf5Sahrens } 2412fa9e4066Sahrens 24131d452cf5Sahrens static void 24143f9d6ad7SLin Ling dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx) 24151d452cf5Sahrens { 24161d452cf5Sahrens dsl_dataset_t *ds = arg1; 2417ecd6cf80Smarks const char *newsnapname = arg2; 24181d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 24191d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 24201d452cf5Sahrens dsl_dataset_t *hds; 24211d452cf5Sahrens int err; 2422fa9e4066Sahrens 24231d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 2424fa9e4066Sahrens 2425745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, 2426745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds)); 2427fa9e4066Sahrens 24281d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2429745cd3c5Smaybee err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx); 2430b420f3adSRichard Lowe ASSERT3U(err, ==, 0); 24311d452cf5Sahrens mutex_enter(&ds->ds_lock); 24321d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 24331d452cf5Sahrens mutex_exit(&ds->ds_lock); 24341d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 24351d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 2436b420f3adSRichard Lowe ASSERT3U(err, ==, 0); 2437fa9e4066Sahrens 24384445fffbSMatthew Ahrens spa_history_log_internal_ds(ds, "rename", tx, 24394445fffbSMatthew Ahrens "-> @%s", newsnapname); 2440745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 2441fa9e4066Sahrens } 2442fa9e4066Sahrens 2443f18faf3fSek struct renamesnaparg { 2444cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 2445cdf5b4caSmmusante char failed[MAXPATHLEN]; 2446cdf5b4caSmmusante char *oldsnap; 2447cdf5b4caSmmusante char *newsnap; 2448cdf5b4caSmmusante }; 2449cdf5b4caSmmusante 2450cdf5b4caSmmusante static int 2451fd136879SMatthew Ahrens dsl_snapshot_rename_one(const char *name, void *arg) 2452cdf5b4caSmmusante { 2453f18faf3fSek struct renamesnaparg *ra = arg; 2454cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 2455fd136879SMatthew Ahrens char *snapname; 2456cdf5b4caSmmusante int err; 2457cdf5b4caSmmusante 2458fd136879SMatthew Ahrens snapname = kmem_asprintf("%s@%s", name, ra->oldsnap); 2459fd136879SMatthew Ahrens (void) strlcpy(ra->failed, snapname, sizeof (ra->failed)); 2460ecd6cf80Smarks 2461ecd6cf80Smarks /* 2462ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 2463ecd6cf80Smarks * so we just pass name for both the to/from argument. 2464ecd6cf80Smarks */ 2465fd136879SMatthew Ahrens err = zfs_secpolicy_rename_perms(snapname, snapname, CRED()); 2466fd136879SMatthew Ahrens if (err != 0) { 2467fd136879SMatthew Ahrens strfree(snapname); 2468fd136879SMatthew Ahrens return (err == ENOENT ? 0 : err); 2469ecd6cf80Smarks } 2470ecd6cf80Smarks 2471745cd3c5Smaybee #ifdef _KERNEL 2472745cd3c5Smaybee /* 2473745cd3c5Smaybee * For all filesystems undergoing rename, we'll need to unmount it. 2474745cd3c5Smaybee */ 2475fd136879SMatthew Ahrens (void) zfs_unmount_snap(snapname, NULL); 2476745cd3c5Smaybee #endif 2477fd136879SMatthew Ahrens err = dsl_dataset_hold(snapname, ra->dstg, &ds); 24783f1f8012SMatthew Ahrens strfree(snapname); 24793f1f8012SMatthew Ahrens if (err != 0) 2480fd136879SMatthew Ahrens return (err == ENOENT ? 0 : err); 2481cdf5b4caSmmusante 2482cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 2483cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 2484cdf5b4caSmmusante 2485cdf5b4caSmmusante return (0); 2486cdf5b4caSmmusante } 2487cdf5b4caSmmusante 2488cdf5b4caSmmusante static int 2489cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 2490cdf5b4caSmmusante { 2491cdf5b4caSmmusante int err; 2492f18faf3fSek struct renamesnaparg *ra; 2493cdf5b4caSmmusante dsl_sync_task_t *dst; 2494cdf5b4caSmmusante spa_t *spa; 2495cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 2496fd136879SMatthew Ahrens int len = strlen(oldname) + 1; 2497cdf5b4caSmmusante 2498cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 2499cdf5b4caSmmusante cp = strchr(fsname, '@'); 2500cdf5b4caSmmusante *cp = '\0'; 2501cdf5b4caSmmusante 250240feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 2503cdf5b4caSmmusante if (err) { 2504fd136879SMatthew Ahrens kmem_free(fsname, len); 2505cdf5b4caSmmusante return (err); 2506cdf5b4caSmmusante } 2507f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 2508cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 2509cdf5b4caSmmusante 2510cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 2511cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 2512cdf5b4caSmmusante *ra->failed = '\0'; 2513cdf5b4caSmmusante 2514cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 2515cdf5b4caSmmusante DS_FIND_CHILDREN); 2516fd136879SMatthew Ahrens kmem_free(fsname, len); 2517cdf5b4caSmmusante 2518cdf5b4caSmmusante if (err == 0) { 2519cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 2520cdf5b4caSmmusante } 2521cdf5b4caSmmusante 2522cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 2523cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 2524cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 2525cdf5b4caSmmusante if (dst->dst_err) { 2526cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 2527fd136879SMatthew Ahrens (void) strlcat(ra->failed, "@", sizeof (ra->failed)); 2528fd136879SMatthew Ahrens (void) strlcat(ra->failed, ra->newsnap, 2529fd136879SMatthew Ahrens sizeof (ra->failed)); 2530cdf5b4caSmmusante } 2531745cd3c5Smaybee dsl_dataset_rele(ds, ra->dstg); 2532cdf5b4caSmmusante } 2533cdf5b4caSmmusante 2534ecd6cf80Smarks if (err) 2535fd136879SMatthew Ahrens (void) strlcpy(oldname, ra->failed, sizeof (ra->failed)); 2536cdf5b4caSmmusante 2537cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 2538f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 2539cdf5b4caSmmusante spa_close(spa, FTAG); 2540cdf5b4caSmmusante return (err); 2541cdf5b4caSmmusante } 2542cdf5b4caSmmusante 25433a5a36beSmmusante static int 2544fd136879SMatthew Ahrens dsl_valid_rename(const char *oldname, void *arg) 25453a5a36beSmmusante { 25463a5a36beSmmusante int delta = *(int *)arg; 25473a5a36beSmmusante 25483a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 25493a5a36beSmmusante return (ENAMETOOLONG); 25503a5a36beSmmusante 25513a5a36beSmmusante return (0); 25523a5a36beSmmusante } 25533a5a36beSmmusante 2554fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 2555fa9e4066Sahrens int 2556745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive) 2557fa9e4066Sahrens { 2558fa9e4066Sahrens dsl_dir_t *dd; 25591d452cf5Sahrens dsl_dataset_t *ds; 2560fa9e4066Sahrens const char *tail; 2561fa9e4066Sahrens int err; 2562fa9e4066Sahrens 25631d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 2564ea8dc4b6Seschrock if (err) 2565ea8dc4b6Seschrock return (err); 2566370c1af0SSanjeev Bagewadi 2567fa9e4066Sahrens if (tail == NULL) { 25683a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 25693a5a36beSmmusante 2570088f3894Sahrens /* if we're growing, validate child name lengths */ 25713a5a36beSmmusante if (delta > 0) 25723a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 25733a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 25743a5a36beSmmusante 2575b91a2f0bSMatthew Ahrens if (err == 0) 25763a5a36beSmmusante err = dsl_dir_rename(dd, newname); 2577fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2578fa9e4066Sahrens return (err); 2579fa9e4066Sahrens } 2580370c1af0SSanjeev Bagewadi 2581fa9e4066Sahrens if (tail[0] != '@') { 2582681d9761SEric Taylor /* the name ended in a nonexistent component */ 2583fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2584fa9e4066Sahrens return (ENOENT); 2585fa9e4066Sahrens } 2586fa9e4066Sahrens 2587fa9e4066Sahrens dsl_dir_close(dd, FTAG); 25881d452cf5Sahrens 25891d452cf5Sahrens /* new name must be snapshot in same filesystem */ 25901d452cf5Sahrens tail = strchr(newname, '@'); 25911d452cf5Sahrens if (tail == NULL) 25921d452cf5Sahrens return (EINVAL); 25931d452cf5Sahrens tail++; 25941d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 25951d452cf5Sahrens return (EXDEV); 25961d452cf5Sahrens 2597cdf5b4caSmmusante if (recursive) { 2598cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 2599cdf5b4caSmmusante } else { 2600745cd3c5Smaybee err = dsl_dataset_hold(oldname, FTAG, &ds); 2601cdf5b4caSmmusante if (err) 2602cdf5b4caSmmusante return (err); 26031d452cf5Sahrens 2604cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2605cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 2606cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 26071d452cf5Sahrens 2608745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2609cdf5b4caSmmusante } 26101d452cf5Sahrens 2611fa9e4066Sahrens return (err); 2612fa9e4066Sahrens } 261399653d4eSeschrock 2614088f3894Sahrens struct promotenode { 2615745cd3c5Smaybee list_node_t link; 2616745cd3c5Smaybee dsl_dataset_t *ds; 2617745cd3c5Smaybee }; 2618745cd3c5Smaybee 26191d452cf5Sahrens struct promotearg { 262074e7dc98SMatthew Ahrens list_t shared_snaps, origin_snaps, clone_snaps; 26213f9d6ad7SLin Ling dsl_dataset_t *origin_origin; 262274e7dc98SMatthew Ahrens uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; 2623681d9761SEric Taylor char *err_ds; 26241d452cf5Sahrens }; 26251d452cf5Sahrens 262674e7dc98SMatthew Ahrens static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep); 26273f9d6ad7SLin Ling static boolean_t snaplist_unstable(list_t *l); 262874e7dc98SMatthew Ahrens 262999653d4eSeschrock static int 26301d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 263199653d4eSeschrock { 26321d452cf5Sahrens dsl_dataset_t *hds = arg1; 26331d452cf5Sahrens struct promotearg *pa = arg2; 263474e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2635745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 2636745cd3c5Smaybee int err; 2637cde58dbcSMatthew Ahrens uint64_t unused; 26381d452cf5Sahrens 2639088f3894Sahrens /* Check that it is a real clone */ 2640088f3894Sahrens if (!dsl_dir_is_clone(hds->ds_dir)) 264199653d4eSeschrock return (EINVAL); 264299653d4eSeschrock 26431d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 26441d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 26451d452cf5Sahrens return (0); 26461d452cf5Sahrens 2647745cd3c5Smaybee if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) 2648745cd3c5Smaybee return (EXDEV); 264999653d4eSeschrock 26503cb34c60Sahrens /* compute origin's new unique space */ 265174e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 265274e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 2653cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&snap->ds->ds_deadlist, 2654cde58dbcSMatthew Ahrens origin_ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, 2655cde58dbcSMatthew Ahrens &pa->unique, &unused, &unused); 265699653d4eSeschrock 2657745cd3c5Smaybee /* 2658745cd3c5Smaybee * Walk the snapshots that we are moving 2659745cd3c5Smaybee * 266074e7dc98SMatthew Ahrens * Compute space to transfer. Consider the incremental changes 266174e7dc98SMatthew Ahrens * to used for each snapshot: 266274e7dc98SMatthew Ahrens * (my used) = (prev's used) + (blocks born) - (blocks killed) 266374e7dc98SMatthew Ahrens * So each snapshot gave birth to: 266474e7dc98SMatthew Ahrens * (blocks born) = (my used) - (prev's used) + (blocks killed) 2665745cd3c5Smaybee * So a sequence would look like: 266674e7dc98SMatthew Ahrens * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0) 2667745cd3c5Smaybee * Which simplifies to: 266874e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + k1 + k0 2669745cd3c5Smaybee * Note however, if we stop before we reach the ORIGIN we get: 267074e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + kM - uM-1 2671745cd3c5Smaybee */ 2672ad135b5dSChristopher Siden pa->used = origin_ds->ds_phys->ds_referenced_bytes; 2673745cd3c5Smaybee pa->comp = origin_ds->ds_phys->ds_compressed_bytes; 2674745cd3c5Smaybee pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes; 267574e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 267674e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 267799653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 2678745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 267999653d4eSeschrock 268099653d4eSeschrock /* Check that the snapshot name does not conflict */ 268174e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2682745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); 2683681d9761SEric Taylor if (err == 0) { 2684681d9761SEric Taylor err = EEXIST; 2685681d9761SEric Taylor goto out; 2686681d9761SEric Taylor } 2687745cd3c5Smaybee if (err != ENOENT) 2688681d9761SEric Taylor goto out; 268999653d4eSeschrock 2690745cd3c5Smaybee /* The very first snapshot does not have a deadlist */ 269174e7dc98SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 269274e7dc98SMatthew Ahrens continue; 269374e7dc98SMatthew Ahrens 2694cde58dbcSMatthew Ahrens dsl_deadlist_space(&ds->ds_deadlist, 2695cde58dbcSMatthew Ahrens &dlused, &dlcomp, &dluncomp); 269674e7dc98SMatthew Ahrens pa->used += dlused; 269774e7dc98SMatthew Ahrens pa->comp += dlcomp; 269874e7dc98SMatthew Ahrens pa->uncomp += dluncomp; 269974e7dc98SMatthew Ahrens } 2700745cd3c5Smaybee 2701745cd3c5Smaybee /* 2702745cd3c5Smaybee * If we are a clone of a clone then we never reached ORIGIN, 2703745cd3c5Smaybee * so we need to subtract out the clone origin's used space. 2704745cd3c5Smaybee */ 270574e7dc98SMatthew Ahrens if (pa->origin_origin) { 2706ad135b5dSChristopher Siden pa->used -= pa->origin_origin->ds_phys->ds_referenced_bytes; 270774e7dc98SMatthew Ahrens pa->comp -= pa->origin_origin->ds_phys->ds_compressed_bytes; 270874e7dc98SMatthew Ahrens pa->uncomp -= pa->origin_origin->ds_phys->ds_uncompressed_bytes; 270999653d4eSeschrock } 271099653d4eSeschrock 271199653d4eSeschrock /* Check that there is enough space here */ 271274e7dc98SMatthew Ahrens err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir, 271374e7dc98SMatthew Ahrens pa->used); 271474e7dc98SMatthew Ahrens if (err) 271574e7dc98SMatthew Ahrens return (err); 271674e7dc98SMatthew Ahrens 271774e7dc98SMatthew Ahrens /* 271874e7dc98SMatthew Ahrens * Compute the amounts of space that will be used by snapshots 271974e7dc98SMatthew Ahrens * after the promotion (for both origin and clone). For each, 272074e7dc98SMatthew Ahrens * it is the amount of space that will be on all of their 272174e7dc98SMatthew Ahrens * deadlists (that was not born before their new origin). 272274e7dc98SMatthew Ahrens */ 272374e7dc98SMatthew Ahrens if (hds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 272474e7dc98SMatthew Ahrens uint64_t space; 272574e7dc98SMatthew Ahrens 272674e7dc98SMatthew Ahrens /* 272774e7dc98SMatthew Ahrens * Note, typically this will not be a clone of a clone, 27283f9d6ad7SLin Ling * so dd_origin_txg will be < TXG_INITIAL, so 2729cde58dbcSMatthew Ahrens * these snaplist_space() -> dsl_deadlist_space_range() 273074e7dc98SMatthew Ahrens * calls will be fast because they do not have to 273174e7dc98SMatthew Ahrens * iterate over all bps. 273274e7dc98SMatthew Ahrens */ 273374e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 273474e7dc98SMatthew Ahrens err = snaplist_space(&pa->shared_snaps, 27353f9d6ad7SLin Ling snap->ds->ds_dir->dd_origin_txg, &pa->cloneusedsnap); 273674e7dc98SMatthew Ahrens if (err) 273774e7dc98SMatthew Ahrens return (err); 273874e7dc98SMatthew Ahrens 273974e7dc98SMatthew Ahrens err = snaplist_space(&pa->clone_snaps, 27403f9d6ad7SLin Ling snap->ds->ds_dir->dd_origin_txg, &space); 274174e7dc98SMatthew Ahrens if (err) 274274e7dc98SMatthew Ahrens return (err); 274374e7dc98SMatthew Ahrens pa->cloneusedsnap += space; 274474e7dc98SMatthew Ahrens } 274574e7dc98SMatthew Ahrens if (origin_ds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 274674e7dc98SMatthew Ahrens err = snaplist_space(&pa->origin_snaps, 274774e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_creation_txg, &pa->originusedsnap); 274874e7dc98SMatthew Ahrens if (err) 274974e7dc98SMatthew Ahrens return (err); 2750745cd3c5Smaybee } 27511d452cf5Sahrens 275274e7dc98SMatthew Ahrens return (0); 2753681d9761SEric Taylor out: 2754681d9761SEric Taylor pa->err_ds = snap->ds->ds_snapname; 2755681d9761SEric Taylor return (err); 27561d452cf5Sahrens } 275799653d4eSeschrock 27581d452cf5Sahrens static void 27593f9d6ad7SLin Ling dsl_dataset_promote_sync(void *arg1, void *arg2, dmu_tx_t *tx) 27601d452cf5Sahrens { 27611d452cf5Sahrens dsl_dataset_t *hds = arg1; 27621d452cf5Sahrens struct promotearg *pa = arg2; 276374e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2764745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 276574e7dc98SMatthew Ahrens dsl_dataset_t *origin_head; 27661d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 27671d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 27683cb34c60Sahrens dsl_dir_t *odd = NULL; 2769088f3894Sahrens uint64_t oldnext_obj; 277074e7dc98SMatthew Ahrens int64_t delta; 27711d452cf5Sahrens 27721d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 27731d452cf5Sahrens 277474e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 277574e7dc98SMatthew Ahrens origin_head = snap->ds; 277674e7dc98SMatthew Ahrens 27770b69c2f0Sahrens /* 27783cb34c60Sahrens * We need to explicitly open odd, since origin_ds's dd will be 27790b69c2f0Sahrens * changing. 27800b69c2f0Sahrens */ 27813cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object, 27823cb34c60Sahrens NULL, FTAG, &odd)); 278399653d4eSeschrock 2784745cd3c5Smaybee /* change origin's next snap */ 2785745cd3c5Smaybee dmu_buf_will_dirty(origin_ds->ds_dbuf, tx); 2786088f3894Sahrens oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj; 278774e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 278874e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 278974e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj = snap->ds->ds_object; 2790745cd3c5Smaybee 2791088f3894Sahrens /* change the origin's next clone */ 2792088f3894Sahrens if (origin_ds->ds_phys->ds_next_clones_obj) { 2793c33e334fSMatthew Ahrens remove_from_next_clones(origin_ds, snap->ds->ds_object, tx); 2794b420f3adSRichard Lowe VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2795088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2796088f3894Sahrens oldnext_obj, tx)); 2797088f3894Sahrens } 2798088f3894Sahrens 2799745cd3c5Smaybee /* change origin */ 2800745cd3c5Smaybee dmu_buf_will_dirty(dd->dd_dbuf, tx); 2801745cd3c5Smaybee ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object); 2802745cd3c5Smaybee dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj; 28033f9d6ad7SLin Ling dd->dd_origin_txg = origin_head->ds_dir->dd_origin_txg; 2804745cd3c5Smaybee dmu_buf_will_dirty(odd->dd_dbuf, tx); 2805745cd3c5Smaybee odd->dd_phys->dd_origin_obj = origin_ds->ds_object; 28063f9d6ad7SLin Ling origin_head->ds_dir->dd_origin_txg = 28073f9d6ad7SLin Ling origin_ds->ds_phys->ds_creation_txg; 2808745cd3c5Smaybee 2809cde58dbcSMatthew Ahrens /* change dd_clone entries */ 2810cde58dbcSMatthew Ahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 2811b420f3adSRichard Lowe VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2812cde58dbcSMatthew Ahrens odd->dd_phys->dd_clones, hds->ds_object, tx)); 2813b420f3adSRichard Lowe VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2814cde58dbcSMatthew Ahrens pa->origin_origin->ds_dir->dd_phys->dd_clones, 2815cde58dbcSMatthew Ahrens hds->ds_object, tx)); 2816cde58dbcSMatthew Ahrens 2817b420f3adSRichard Lowe VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2818cde58dbcSMatthew Ahrens pa->origin_origin->ds_dir->dd_phys->dd_clones, 2819cde58dbcSMatthew Ahrens origin_head->ds_object, tx)); 2820cde58dbcSMatthew Ahrens if (dd->dd_phys->dd_clones == 0) { 2821cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones = zap_create(dp->dp_meta_objset, 2822cde58dbcSMatthew Ahrens DMU_OT_DSL_CLONES, DMU_OT_NONE, 0, tx); 2823cde58dbcSMatthew Ahrens } 2824b420f3adSRichard Lowe VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2825cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones, origin_head->ds_object, tx)); 2826cde58dbcSMatthew Ahrens 2827cde58dbcSMatthew Ahrens } 2828cde58dbcSMatthew Ahrens 282999653d4eSeschrock /* move snapshots to this dir */ 283074e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 283174e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 2832745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 283399653d4eSeschrock 28343baa08fcSek /* unregister props as dsl_dir is changing */ 2835503ad85cSMatthew Ahrens if (ds->ds_objset) { 2836503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 2837503ad85cSMatthew Ahrens ds->ds_objset = NULL; 28383baa08fcSek } 283999653d4eSeschrock /* move snap name entry */ 284074e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 284174e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_snap_remove(origin_head, 2842745cd3c5Smaybee ds->ds_snapname, tx)); 28431d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 284499653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 284599653d4eSeschrock 8, 1, &ds->ds_object, tx)); 2846cde58dbcSMatthew Ahrens 284799653d4eSeschrock /* change containing dsl_dir */ 284899653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 28493cb34c60Sahrens ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object); 285099653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 28513cb34c60Sahrens ASSERT3P(ds->ds_dir, ==, odd); 285299653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 28531d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 285499653d4eSeschrock NULL, ds, &ds->ds_dir)); 285599653d4eSeschrock 2856cde58dbcSMatthew Ahrens /* move any clone references */ 2857cde58dbcSMatthew Ahrens if (ds->ds_phys->ds_next_clones_obj && 2858cde58dbcSMatthew Ahrens spa_version(dp->dp_spa) >= SPA_VERSION_DIR_CLONES) { 2859cde58dbcSMatthew Ahrens zap_cursor_t zc; 2860cde58dbcSMatthew Ahrens zap_attribute_t za; 2861cde58dbcSMatthew Ahrens 2862cde58dbcSMatthew Ahrens for (zap_cursor_init(&zc, dp->dp_meta_objset, 2863cde58dbcSMatthew Ahrens ds->ds_phys->ds_next_clones_obj); 2864cde58dbcSMatthew Ahrens zap_cursor_retrieve(&zc, &za) == 0; 2865cde58dbcSMatthew Ahrens zap_cursor_advance(&zc)) { 2866cde58dbcSMatthew Ahrens dsl_dataset_t *cnds; 2867cde58dbcSMatthew Ahrens uint64_t o; 2868cde58dbcSMatthew Ahrens 2869cde58dbcSMatthew Ahrens if (za.za_first_integer == oldnext_obj) { 2870cde58dbcSMatthew Ahrens /* 2871cde58dbcSMatthew Ahrens * We've already moved the 2872cde58dbcSMatthew Ahrens * origin's reference. 2873cde58dbcSMatthew Ahrens */ 2874cde58dbcSMatthew Ahrens continue; 2875cde58dbcSMatthew Ahrens } 2876cde58dbcSMatthew Ahrens 2877b420f3adSRichard Lowe VERIFY3U(0, ==, dsl_dataset_hold_obj(dp, 2878cde58dbcSMatthew Ahrens za.za_first_integer, FTAG, &cnds)); 2879cde58dbcSMatthew Ahrens o = cnds->ds_dir->dd_phys->dd_head_dataset_obj; 2880cde58dbcSMatthew Ahrens 2881cde58dbcSMatthew Ahrens VERIFY3U(zap_remove_int(dp->dp_meta_objset, 2882cde58dbcSMatthew Ahrens odd->dd_phys->dd_clones, o, tx), ==, 0); 2883cde58dbcSMatthew Ahrens VERIFY3U(zap_add_int(dp->dp_meta_objset, 2884cde58dbcSMatthew Ahrens dd->dd_phys->dd_clones, o, tx), ==, 0); 2885cde58dbcSMatthew Ahrens dsl_dataset_rele(cnds, FTAG); 2886cde58dbcSMatthew Ahrens } 2887cde58dbcSMatthew Ahrens zap_cursor_fini(&zc); 2888cde58dbcSMatthew Ahrens } 2889cde58dbcSMatthew Ahrens 2890b420f3adSRichard Lowe ASSERT3U(dsl_prop_numcb(ds), ==, 0); 289174e7dc98SMatthew Ahrens } 289274e7dc98SMatthew Ahrens 289374e7dc98SMatthew Ahrens /* 289474e7dc98SMatthew Ahrens * Change space accounting. 289574e7dc98SMatthew Ahrens * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either 289674e7dc98SMatthew Ahrens * both be valid, or both be 0 (resulting in delta == 0). This 289774e7dc98SMatthew Ahrens * is true for each of {clone,origin} independently. 289874e7dc98SMatthew Ahrens */ 289974e7dc98SMatthew Ahrens 290074e7dc98SMatthew Ahrens delta = pa->cloneusedsnap - 290174e7dc98SMatthew Ahrens dd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 290274e7dc98SMatthew Ahrens ASSERT3S(delta, >=, 0); 290374e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, delta); 290474e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx); 290574e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_HEAD, 290674e7dc98SMatthew Ahrens pa->used - delta, pa->comp, pa->uncomp, tx); 290774e7dc98SMatthew Ahrens 290874e7dc98SMatthew Ahrens delta = pa->originusedsnap - 290974e7dc98SMatthew Ahrens odd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 291074e7dc98SMatthew Ahrens ASSERT3S(delta, <=, 0); 291174e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, -delta); 291274e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx); 291374e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_HEAD, 291474e7dc98SMatthew Ahrens -pa->used - delta, -pa->comp, -pa->uncomp, tx); 291599653d4eSeschrock 29163cb34c60Sahrens origin_ds->ds_phys->ds_unique_bytes = pa->unique; 291799653d4eSeschrock 2918ecd6cf80Smarks /* log history record */ 29194445fffbSMatthew Ahrens spa_history_log_internal_ds(hds, "promote", tx, ""); 2920ecd6cf80Smarks 29213cb34c60Sahrens dsl_dir_close(odd, FTAG); 292299653d4eSeschrock } 292399653d4eSeschrock 292474e7dc98SMatthew Ahrens static char *snaplist_tag = "snaplist"; 292574e7dc98SMatthew Ahrens /* 292674e7dc98SMatthew Ahrens * Make a list of dsl_dataset_t's for the snapshots between first_obj 292774e7dc98SMatthew Ahrens * (exclusive) and last_obj (inclusive). The list will be in reverse 292874e7dc98SMatthew Ahrens * order (last_obj will be the list_head()). If first_obj == 0, do all 292974e7dc98SMatthew Ahrens * snapshots back to this dataset's origin. 293074e7dc98SMatthew Ahrens */ 293174e7dc98SMatthew Ahrens static int 293274e7dc98SMatthew Ahrens snaplist_make(dsl_pool_t *dp, boolean_t own, 293374e7dc98SMatthew Ahrens uint64_t first_obj, uint64_t last_obj, list_t *l) 293474e7dc98SMatthew Ahrens { 293574e7dc98SMatthew Ahrens uint64_t obj = last_obj; 293674e7dc98SMatthew Ahrens 293774e7dc98SMatthew Ahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock)); 293874e7dc98SMatthew Ahrens 293974e7dc98SMatthew Ahrens list_create(l, sizeof (struct promotenode), 294074e7dc98SMatthew Ahrens offsetof(struct promotenode, link)); 294174e7dc98SMatthew Ahrens 294274e7dc98SMatthew Ahrens while (obj != first_obj) { 294374e7dc98SMatthew Ahrens dsl_dataset_t *ds; 294474e7dc98SMatthew Ahrens struct promotenode *snap; 294574e7dc98SMatthew Ahrens int err; 294674e7dc98SMatthew Ahrens 294774e7dc98SMatthew Ahrens if (own) { 294874e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, obj, 294974e7dc98SMatthew Ahrens 0, snaplist_tag, &ds); 295074e7dc98SMatthew Ahrens if (err == 0) 295174e7dc98SMatthew Ahrens dsl_dataset_make_exclusive(ds, snaplist_tag); 295274e7dc98SMatthew Ahrens } else { 295374e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, obj, snaplist_tag, &ds); 295474e7dc98SMatthew Ahrens } 295574e7dc98SMatthew Ahrens if (err == ENOENT) { 295674e7dc98SMatthew Ahrens /* lost race with snapshot destroy */ 295774e7dc98SMatthew Ahrens struct promotenode *last = list_tail(l); 295874e7dc98SMatthew Ahrens ASSERT(obj != last->ds->ds_phys->ds_prev_snap_obj); 295974e7dc98SMatthew Ahrens obj = last->ds->ds_phys->ds_prev_snap_obj; 296074e7dc98SMatthew Ahrens continue; 296174e7dc98SMatthew Ahrens } else if (err) { 296274e7dc98SMatthew Ahrens return (err); 296374e7dc98SMatthew Ahrens } 296474e7dc98SMatthew Ahrens 296574e7dc98SMatthew Ahrens if (first_obj == 0) 296674e7dc98SMatthew Ahrens first_obj = ds->ds_dir->dd_phys->dd_origin_obj; 296774e7dc98SMatthew Ahrens 296874e7dc98SMatthew Ahrens snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP); 296974e7dc98SMatthew Ahrens snap->ds = ds; 297074e7dc98SMatthew Ahrens list_insert_tail(l, snap); 297174e7dc98SMatthew Ahrens obj = ds->ds_phys->ds_prev_snap_obj; 297274e7dc98SMatthew Ahrens } 297374e7dc98SMatthew Ahrens 297474e7dc98SMatthew Ahrens return (0); 297574e7dc98SMatthew Ahrens } 297674e7dc98SMatthew Ahrens 297774e7dc98SMatthew Ahrens static int 297874e7dc98SMatthew Ahrens snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep) 297974e7dc98SMatthew Ahrens { 298074e7dc98SMatthew Ahrens struct promotenode *snap; 298174e7dc98SMatthew Ahrens 298274e7dc98SMatthew Ahrens *spacep = 0; 298374e7dc98SMatthew Ahrens for (snap = list_head(l); snap; snap = list_next(l, snap)) { 2984cde58dbcSMatthew Ahrens uint64_t used, comp, uncomp; 2985cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&snap->ds->ds_deadlist, 2986cde58dbcSMatthew Ahrens mintxg, UINT64_MAX, &used, &comp, &uncomp); 298774e7dc98SMatthew Ahrens *spacep += used; 298874e7dc98SMatthew Ahrens } 298974e7dc98SMatthew Ahrens return (0); 299074e7dc98SMatthew Ahrens } 299174e7dc98SMatthew Ahrens 299274e7dc98SMatthew Ahrens static void 299374e7dc98SMatthew Ahrens snaplist_destroy(list_t *l, boolean_t own) 299474e7dc98SMatthew Ahrens { 299574e7dc98SMatthew Ahrens struct promotenode *snap; 299674e7dc98SMatthew Ahrens 29974f5064b7SMark J Musante if (!l || !list_link_active(&l->list_head)) 299874e7dc98SMatthew Ahrens return; 299974e7dc98SMatthew Ahrens 300074e7dc98SMatthew Ahrens while ((snap = list_tail(l)) != NULL) { 300174e7dc98SMatthew Ahrens list_remove(l, snap); 300274e7dc98SMatthew Ahrens if (own) 300374e7dc98SMatthew Ahrens dsl_dataset_disown(snap->ds, snaplist_tag); 300474e7dc98SMatthew Ahrens else 300574e7dc98SMatthew Ahrens dsl_dataset_rele(snap->ds, snaplist_tag); 300674e7dc98SMatthew Ahrens kmem_free(snap, sizeof (struct promotenode)); 300774e7dc98SMatthew Ahrens } 300874e7dc98SMatthew Ahrens list_destroy(l); 300974e7dc98SMatthew Ahrens } 301074e7dc98SMatthew Ahrens 301174e7dc98SMatthew Ahrens /* 301274e7dc98SMatthew Ahrens * Promote a clone. Nomenclature note: 301374e7dc98SMatthew Ahrens * "clone" or "cds": the original clone which is being promoted 301474e7dc98SMatthew Ahrens * "origin" or "ods": the snapshot which is originally clone's origin 301574e7dc98SMatthew Ahrens * "origin head" or "ohds": the dataset which is the head 301674e7dc98SMatthew Ahrens * (filesystem/volume) for the origin 301774e7dc98SMatthew Ahrens * "origin origin": the origin of the origin's filesystem (typically 301874e7dc98SMatthew Ahrens * NULL, indicating that the clone is not a clone of a clone). 301974e7dc98SMatthew Ahrens */ 302099653d4eSeschrock int 3021681d9761SEric Taylor dsl_dataset_promote(const char *name, char *conflsnap) 302299653d4eSeschrock { 302399653d4eSeschrock dsl_dataset_t *ds; 3024745cd3c5Smaybee dsl_dir_t *dd; 3025745cd3c5Smaybee dsl_pool_t *dp; 302699653d4eSeschrock dmu_object_info_t doi; 302774e7dc98SMatthew Ahrens struct promotearg pa = { 0 }; 3028088f3894Sahrens struct promotenode *snap; 3029745cd3c5Smaybee int err; 303099653d4eSeschrock 3031745cd3c5Smaybee err = dsl_dataset_hold(name, FTAG, &ds); 303299653d4eSeschrock if (err) 303399653d4eSeschrock return (err); 3034745cd3c5Smaybee dd = ds->ds_dir; 3035745cd3c5Smaybee dp = dd->dd_pool; 303699653d4eSeschrock 3037745cd3c5Smaybee err = dmu_object_info(dp->dp_meta_objset, 303899653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 303999653d4eSeschrock if (err) { 3040745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 304199653d4eSeschrock return (err); 304299653d4eSeschrock } 304399653d4eSeschrock 304474e7dc98SMatthew Ahrens if (dsl_dataset_is_snapshot(ds) || dd->dd_phys->dd_origin_obj == 0) { 304574e7dc98SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 304674e7dc98SMatthew Ahrens return (EINVAL); 304774e7dc98SMatthew Ahrens } 304874e7dc98SMatthew Ahrens 3049745cd3c5Smaybee /* 3050745cd3c5Smaybee * We are going to inherit all the snapshots taken before our 3051745cd3c5Smaybee * origin (i.e., our new origin will be our parent's origin). 3052745cd3c5Smaybee * Take ownership of them so that we can rename them into our 3053745cd3c5Smaybee * namespace. 3054745cd3c5Smaybee */ 3055745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 3056088f3894Sahrens 305774e7dc98SMatthew Ahrens err = snaplist_make(dp, B_TRUE, 0, dd->dd_phys->dd_origin_obj, 305874e7dc98SMatthew Ahrens &pa.shared_snaps); 305974e7dc98SMatthew Ahrens if (err != 0) 306074e7dc98SMatthew Ahrens goto out; 3061088f3894Sahrens 306274e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, 0, ds->ds_object, &pa.clone_snaps); 306374e7dc98SMatthew Ahrens if (err != 0) 306474e7dc98SMatthew Ahrens goto out; 3065088f3894Sahrens 306674e7dc98SMatthew Ahrens snap = list_head(&pa.shared_snaps); 306774e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_object, ==, dd->dd_phys->dd_origin_obj); 306874e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, dd->dd_phys->dd_origin_obj, 306974e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, &pa.origin_snaps); 307074e7dc98SMatthew Ahrens if (err != 0) 307174e7dc98SMatthew Ahrens goto out; 3072088f3894Sahrens 3073cde58dbcSMatthew Ahrens if (snap->ds->ds_dir->dd_phys->dd_origin_obj != 0) { 3074cde58dbcSMatthew Ahrens err = dsl_dataset_hold_obj(dp, 307574e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_origin_obj, 3076cde58dbcSMatthew Ahrens FTAG, &pa.origin_origin); 307774e7dc98SMatthew Ahrens if (err != 0) 307874e7dc98SMatthew Ahrens goto out; 307974e7dc98SMatthew Ahrens } 3080745cd3c5Smaybee 308174e7dc98SMatthew Ahrens out: 308274e7dc98SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 3083745cd3c5Smaybee 308499653d4eSeschrock /* 308599653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 308699653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 308799653d4eSeschrock * bonus buffers. 308899653d4eSeschrock */ 308974e7dc98SMatthew Ahrens if (err == 0) { 309074e7dc98SMatthew Ahrens err = dsl_sync_task_do(dp, dsl_dataset_promote_check, 309174e7dc98SMatthew Ahrens dsl_dataset_promote_sync, ds, &pa, 3092b24ab676SJeff Bonwick 2 + 2 * doi.doi_physical_blocks_512); 3093681d9761SEric Taylor if (err && pa.err_ds && conflsnap) 3094681d9761SEric Taylor (void) strncpy(conflsnap, pa.err_ds, MAXNAMELEN); 3095745cd3c5Smaybee } 309674e7dc98SMatthew Ahrens 309774e7dc98SMatthew Ahrens snaplist_destroy(&pa.shared_snaps, B_TRUE); 309874e7dc98SMatthew Ahrens snaplist_destroy(&pa.clone_snaps, B_FALSE); 309974e7dc98SMatthew Ahrens snaplist_destroy(&pa.origin_snaps, B_FALSE); 310074e7dc98SMatthew Ahrens if (pa.origin_origin) 3101cde58dbcSMatthew Ahrens dsl_dataset_rele(pa.origin_origin, FTAG); 3102745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 310399653d4eSeschrock return (err); 310499653d4eSeschrock } 3105b1b8ab34Slling 31063cb34c60Sahrens struct cloneswaparg { 31073cb34c60Sahrens dsl_dataset_t *cds; /* clone dataset */ 31083cb34c60Sahrens dsl_dataset_t *ohds; /* origin's head dataset */ 31093cb34c60Sahrens boolean_t force; 3110a9b821a0Sck int64_t unused_refres_delta; /* change in unconsumed refreservation */ 31113cb34c60Sahrens }; 3112f18faf3fSek 3113f18faf3fSek /* ARGSUSED */ 3114f18faf3fSek static int 3115f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 3116f18faf3fSek { 31173cb34c60Sahrens struct cloneswaparg *csa = arg1; 3118f18faf3fSek 31193cb34c60Sahrens /* they should both be heads */ 31203cb34c60Sahrens if (dsl_dataset_is_snapshot(csa->cds) || 31213cb34c60Sahrens dsl_dataset_is_snapshot(csa->ohds)) 3122f18faf3fSek return (EINVAL); 3123f18faf3fSek 31243cb34c60Sahrens /* the branch point should be just before them */ 31253cb34c60Sahrens if (csa->cds->ds_prev != csa->ohds->ds_prev) 3126f18faf3fSek return (EINVAL); 3127f18faf3fSek 3128ae46e4c7SMatthew Ahrens /* cds should be the clone (unless they are unrelated) */ 3129ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev != NULL && 3130ae46e4c7SMatthew Ahrens csa->cds->ds_prev != csa->cds->ds_dir->dd_pool->dp_origin_snap && 3131ae46e4c7SMatthew Ahrens csa->ohds->ds_object != 3132ae46e4c7SMatthew Ahrens csa->cds->ds_prev->ds_phys->ds_next_snap_obj) 31333cb34c60Sahrens return (EINVAL); 3134f18faf3fSek 31353cb34c60Sahrens /* the clone should be a child of the origin */ 31363cb34c60Sahrens if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir) 31373cb34c60Sahrens return (EINVAL); 3138f18faf3fSek 31393cb34c60Sahrens /* ohds shouldn't be modified unless 'force' */ 31403cb34c60Sahrens if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) 31413cb34c60Sahrens return (ETXTBSY); 3142a9b821a0Sck 3143a9b821a0Sck /* adjust amount of any unconsumed refreservation */ 3144a9b821a0Sck csa->unused_refres_delta = 3145a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 3146a9b821a0Sck csa->ohds->ds_phys->ds_unique_bytes) - 3147a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 3148a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 3149a9b821a0Sck 3150a9b821a0Sck if (csa->unused_refres_delta > 0 && 3151a9b821a0Sck csa->unused_refres_delta > 3152a9b821a0Sck dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) 3153a9b821a0Sck return (ENOSPC); 3154a9b821a0Sck 3155c4cbca4fSChris Kirby if (csa->ohds->ds_quota != 0 && 3156c4cbca4fSChris Kirby csa->cds->ds_phys->ds_unique_bytes > csa->ohds->ds_quota) 3157c4cbca4fSChris Kirby return (EDQUOT); 3158c4cbca4fSChris Kirby 31593cb34c60Sahrens return (0); 3160f18faf3fSek } 3161f18faf3fSek 3162f18faf3fSek /* ARGSUSED */ 3163f18faf3fSek static void 31643f9d6ad7SLin Ling dsl_dataset_clone_swap_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3165f18faf3fSek { 31663cb34c60Sahrens struct cloneswaparg *csa = arg1; 31673cb34c60Sahrens dsl_pool_t *dp = csa->cds->ds_dir->dd_pool; 3168f18faf3fSek 3169a9b821a0Sck ASSERT(csa->cds->ds_reserved == 0); 3170c4cbca4fSChris Kirby ASSERT(csa->ohds->ds_quota == 0 || 3171c4cbca4fSChris Kirby csa->cds->ds_phys->ds_unique_bytes <= csa->ohds->ds_quota); 3172a9b821a0Sck 31733cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); 31743cb34c60Sahrens dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); 3175f18faf3fSek 3176503ad85cSMatthew Ahrens if (csa->cds->ds_objset != NULL) { 3177503ad85cSMatthew Ahrens dmu_objset_evict(csa->cds->ds_objset); 3178503ad85cSMatthew Ahrens csa->cds->ds_objset = NULL; 31793cb34c60Sahrens } 3180f18faf3fSek 3181503ad85cSMatthew Ahrens if (csa->ohds->ds_objset != NULL) { 3182503ad85cSMatthew Ahrens dmu_objset_evict(csa->ohds->ds_objset); 3183503ad85cSMatthew Ahrens csa->ohds->ds_objset = NULL; 31843cb34c60Sahrens } 3185f18faf3fSek 3186ae46e4c7SMatthew Ahrens /* 3187ae46e4c7SMatthew Ahrens * Reset origin's unique bytes, if it exists. 3188ae46e4c7SMatthew Ahrens */ 3189ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev) { 3190ae46e4c7SMatthew Ahrens dsl_dataset_t *origin = csa->cds->ds_prev; 3191cde58dbcSMatthew Ahrens uint64_t comp, uncomp; 3192cde58dbcSMatthew Ahrens 3193ae46e4c7SMatthew Ahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 3194cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->cds->ds_deadlist, 3195ae46e4c7SMatthew Ahrens origin->ds_phys->ds_prev_snap_txg, UINT64_MAX, 3196cde58dbcSMatthew Ahrens &origin->ds_phys->ds_unique_bytes, &comp, &uncomp); 3197ae46e4c7SMatthew Ahrens } 3198f18faf3fSek 3199f18faf3fSek /* swap blkptrs */ 3200f18faf3fSek { 3201f18faf3fSek blkptr_t tmp; 32023cb34c60Sahrens tmp = csa->ohds->ds_phys->ds_bp; 32033cb34c60Sahrens csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp; 32043cb34c60Sahrens csa->cds->ds_phys->ds_bp = tmp; 3205f18faf3fSek } 3206f18faf3fSek 3207f18faf3fSek /* set dd_*_bytes */ 3208f18faf3fSek { 3209f18faf3fSek int64_t dused, dcomp, duncomp; 3210f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 3211f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 3212f18faf3fSek 321374e7dc98SMatthew Ahrens ASSERT3U(csa->cds->ds_dir->dd_phys-> 321474e7dc98SMatthew Ahrens dd_used_breakdown[DD_USED_SNAP], ==, 0); 321574e7dc98SMatthew Ahrens 3216cde58dbcSMatthew Ahrens dsl_deadlist_space(&csa->cds->ds_deadlist, 3217cde58dbcSMatthew Ahrens &cdl_used, &cdl_comp, &cdl_uncomp); 3218cde58dbcSMatthew Ahrens dsl_deadlist_space(&csa->ohds->ds_deadlist, 3219cde58dbcSMatthew Ahrens &odl_used, &odl_comp, &odl_uncomp); 322074e7dc98SMatthew Ahrens 3221ad135b5dSChristopher Siden dused = csa->cds->ds_phys->ds_referenced_bytes + cdl_used - 3222ad135b5dSChristopher Siden (csa->ohds->ds_phys->ds_referenced_bytes + odl_used); 32233cb34c60Sahrens dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp - 32243cb34c60Sahrens (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp); 32253cb34c60Sahrens duncomp = csa->cds->ds_phys->ds_uncompressed_bytes + 32263cb34c60Sahrens cdl_uncomp - 32273cb34c60Sahrens (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 32283cb34c60Sahrens 322974e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_HEAD, 32303cb34c60Sahrens dused, dcomp, duncomp, tx); 323174e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->cds->ds_dir, DD_USED_HEAD, 32323cb34c60Sahrens -dused, -dcomp, -duncomp, tx); 323374e7dc98SMatthew Ahrens 323474e7dc98SMatthew Ahrens /* 323574e7dc98SMatthew Ahrens * The difference in the space used by snapshots is the 323674e7dc98SMatthew Ahrens * difference in snapshot space due to the head's 323774e7dc98SMatthew Ahrens * deadlist (since that's the only thing that's 323874e7dc98SMatthew Ahrens * changing that affects the snapused). 323974e7dc98SMatthew Ahrens */ 3240cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->cds->ds_deadlist, 3241cde58dbcSMatthew Ahrens csa->ohds->ds_dir->dd_origin_txg, UINT64_MAX, 3242cde58dbcSMatthew Ahrens &cdl_used, &cdl_comp, &cdl_uncomp); 3243cde58dbcSMatthew Ahrens dsl_deadlist_space_range(&csa->ohds->ds_deadlist, 3244cde58dbcSMatthew Ahrens csa->ohds->ds_dir->dd_origin_txg, UINT64_MAX, 3245cde58dbcSMatthew Ahrens &odl_used, &odl_comp, &odl_uncomp); 324674e7dc98SMatthew Ahrens dsl_dir_transfer_space(csa->ohds->ds_dir, cdl_used - odl_used, 324774e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 32483cb34c60Sahrens } 32493cb34c60Sahrens 3250f18faf3fSek /* swap ds_*_bytes */ 3251ad135b5dSChristopher Siden SWITCH64(csa->ohds->ds_phys->ds_referenced_bytes, 3252ad135b5dSChristopher Siden csa->cds->ds_phys->ds_referenced_bytes); 32533cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes, 32543cb34c60Sahrens csa->cds->ds_phys->ds_compressed_bytes); 32553cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, 32563cb34c60Sahrens csa->cds->ds_phys->ds_uncompressed_bytes); 3257a9b821a0Sck SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, 3258a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 3259a9b821a0Sck 3260a9b821a0Sck /* apply any parent delta for change in unconsumed refreservation */ 326174e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_REFRSRV, 326274e7dc98SMatthew Ahrens csa->unused_refres_delta, 0, 0, tx); 3263f18faf3fSek 3264cde58dbcSMatthew Ahrens /* 3265cde58dbcSMatthew Ahrens * Swap deadlists. 3266cde58dbcSMatthew Ahrens */ 3267cde58dbcSMatthew Ahrens dsl_deadlist_close(&csa->cds->ds_deadlist); 3268cde58dbcSMatthew Ahrens dsl_deadlist_close(&csa->ohds->ds_deadlist); 32693cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj, 32703cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj); 3271cde58dbcSMatthew Ahrens dsl_deadlist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset, 3272cde58dbcSMatthew Ahrens csa->cds->ds_phys->ds_deadlist_obj); 3273cde58dbcSMatthew Ahrens dsl_deadlist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, 3274cde58dbcSMatthew Ahrens csa->ohds->ds_phys->ds_deadlist_obj); 327588b7b0f2SMatthew Ahrens 32763f9d6ad7SLin Ling dsl_scan_ds_clone_swapped(csa->ohds, csa->cds, tx); 32774445fffbSMatthew Ahrens 32784445fffbSMatthew Ahrens spa_history_log_internal_ds(csa->cds, "clone swap", tx, 32794445fffbSMatthew Ahrens "parent=%s", csa->ohds->ds_dir->dd_myname); 3280f18faf3fSek } 3281f18faf3fSek 3282f18faf3fSek /* 3283ae46e4c7SMatthew Ahrens * Swap 'clone' with its origin head datasets. Used at the end of "zfs 3284ae46e4c7SMatthew Ahrens * recv" into an existing fs to swizzle the file system to the new 3285ae46e4c7SMatthew Ahrens * version, and by "zfs rollback". Can also be used to swap two 3286ae46e4c7SMatthew Ahrens * independent head datasets if neither has any snapshots. 3287f18faf3fSek */ 3288f18faf3fSek int 32893cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, 32903cb34c60Sahrens boolean_t force) 3291f18faf3fSek { 32923cb34c60Sahrens struct cloneswaparg csa; 3293745cd3c5Smaybee int error; 3294f18faf3fSek 3295745cd3c5Smaybee ASSERT(clone->ds_owner); 3296745cd3c5Smaybee ASSERT(origin_head->ds_owner); 3297745cd3c5Smaybee retry: 329877972028SChris Kirby /* 329977972028SChris Kirby * Need exclusive access for the swap. If we're swapping these 330077972028SChris Kirby * datasets back after an error, we already hold the locks. 330177972028SChris Kirby */ 330277972028SChris Kirby if (!RW_WRITE_HELD(&clone->ds_rwlock)) 330377972028SChris Kirby rw_enter(&clone->ds_rwlock, RW_WRITER); 330477972028SChris Kirby if (!RW_WRITE_HELD(&origin_head->ds_rwlock) && 330577972028SChris Kirby !rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) { 3306745cd3c5Smaybee rw_exit(&clone->ds_rwlock); 3307745cd3c5Smaybee rw_enter(&origin_head->ds_rwlock, RW_WRITER); 3308745cd3c5Smaybee if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) { 3309745cd3c5Smaybee rw_exit(&origin_head->ds_rwlock); 3310745cd3c5Smaybee goto retry; 3311745cd3c5Smaybee } 3312745cd3c5Smaybee } 33133cb34c60Sahrens csa.cds = clone; 33143cb34c60Sahrens csa.ohds = origin_head; 33153cb34c60Sahrens csa.force = force; 3316745cd3c5Smaybee error = dsl_sync_task_do(clone->ds_dir->dd_pool, 3317f18faf3fSek dsl_dataset_clone_swap_check, 3318745cd3c5Smaybee dsl_dataset_clone_swap_sync, &csa, NULL, 9); 3319745cd3c5Smaybee return (error); 3320f18faf3fSek } 3321f18faf3fSek 3322b1b8ab34Slling /* 3323b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 3324b1b8ab34Slling * return the name of that dataset. 3325b1b8ab34Slling */ 3326b1b8ab34Slling int 3327b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 3328b1b8ab34Slling { 3329b1b8ab34Slling spa_t *spa; 3330b1b8ab34Slling dsl_pool_t *dp; 3331745cd3c5Smaybee dsl_dataset_t *ds; 3332b1b8ab34Slling int error; 3333b1b8ab34Slling 3334b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 3335b1b8ab34Slling return (error); 3336b1b8ab34Slling dp = spa_get_dsl(spa); 3337b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 3338745cd3c5Smaybee if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) { 3339745cd3c5Smaybee dsl_dataset_name(ds, buf); 3340745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3341b1b8ab34Slling } 3342b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 3343b1b8ab34Slling spa_close(spa, FTAG); 3344b1b8ab34Slling 3345745cd3c5Smaybee return (error); 3346b1b8ab34Slling } 3347a9799022Sck 3348a9799022Sck int 3349a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, 3350745cd3c5Smaybee uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv) 3351a9799022Sck { 3352a9799022Sck int error = 0; 3353a9799022Sck 3354a9799022Sck ASSERT3S(asize, >, 0); 3355a9799022Sck 33569082849eSck /* 33579082849eSck * *ref_rsrv is the portion of asize that will come from any 33589082849eSck * unconsumed refreservation space. 33599082849eSck */ 33609082849eSck *ref_rsrv = 0; 33619082849eSck 3362a9799022Sck mutex_enter(&ds->ds_lock); 3363a9799022Sck /* 3364a9799022Sck * Make a space adjustment for reserved bytes. 3365a9799022Sck */ 3366a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) { 3367a9799022Sck ASSERT3U(*used, >=, 3368a9799022Sck ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 3369a9799022Sck *used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 33709082849eSck *ref_rsrv = 33719082849eSck asize - MIN(asize, parent_delta(ds, asize + inflight)); 3372a9799022Sck } 3373a9799022Sck 3374a9799022Sck if (!check_quota || ds->ds_quota == 0) { 3375a9799022Sck mutex_exit(&ds->ds_lock); 3376a9799022Sck return (0); 3377a9799022Sck } 3378a9799022Sck /* 3379a9799022Sck * If they are requesting more space, and our current estimate 3380a9799022Sck * is over quota, they get to try again unless the actual 3381a9799022Sck * on-disk is over quota and there are no pending changes (which 3382a9799022Sck * may free up space for us). 3383a9799022Sck */ 3384ad135b5dSChristopher Siden if (ds->ds_phys->ds_referenced_bytes + inflight >= ds->ds_quota) { 3385ad135b5dSChristopher Siden if (inflight > 0 || 3386ad135b5dSChristopher Siden ds->ds_phys->ds_referenced_bytes < ds->ds_quota) 3387a9799022Sck error = ERESTART; 3388a9799022Sck else 3389a9799022Sck error = EDQUOT; 3390a9799022Sck } 3391a9799022Sck mutex_exit(&ds->ds_lock); 3392a9799022Sck 3393a9799022Sck return (error); 3394a9799022Sck } 3395a9799022Sck 3396a9799022Sck /* ARGSUSED */ 3397a9799022Sck static int 3398a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx) 3399a9799022Sck { 3400a9799022Sck dsl_dataset_t *ds = arg1; 340192241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 340292241e0bSTom Erickson int err; 3403a9799022Sck 3404a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA) 3405a9799022Sck return (ENOTSUP); 3406a9799022Sck 340792241e0bSTom Erickson if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0) 340892241e0bSTom Erickson return (err); 340992241e0bSTom Erickson 341092241e0bSTom Erickson if (psa->psa_effective_value == 0) 3411a9799022Sck return (0); 3412a9799022Sck 3413ad135b5dSChristopher Siden if (psa->psa_effective_value < ds->ds_phys->ds_referenced_bytes || 341492241e0bSTom Erickson psa->psa_effective_value < ds->ds_reserved) 3415a9799022Sck return (ENOSPC); 3416a9799022Sck 3417a9799022Sck return (0); 3418a9799022Sck } 3419a9799022Sck 34203f9d6ad7SLin Ling extern void dsl_prop_set_sync(void *, void *, dmu_tx_t *); 342192241e0bSTom Erickson 3422a9799022Sck void 34233f9d6ad7SLin Ling dsl_dataset_set_quota_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3424a9799022Sck { 3425a9799022Sck dsl_dataset_t *ds = arg1; 342692241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 342792241e0bSTom Erickson uint64_t effective_value = psa->psa_effective_value; 3428a9799022Sck 34293f9d6ad7SLin Ling dsl_prop_set_sync(ds, psa, tx); 343092241e0bSTom Erickson DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa); 3431a9799022Sck 343292241e0bSTom Erickson if (ds->ds_quota != effective_value) { 343392241e0bSTom Erickson dmu_buf_will_dirty(ds->ds_dbuf, tx); 343492241e0bSTom Erickson ds->ds_quota = effective_value; 3435a9799022Sck 34364445fffbSMatthew Ahrens spa_history_log_internal_ds(ds, "set refquota", tx, 34374445fffbSMatthew Ahrens "refquota=%lld", (longlong_t)ds->ds_quota); 343892241e0bSTom Erickson } 3439a9799022Sck } 3440a9799022Sck 3441a9799022Sck int 344292241e0bSTom Erickson dsl_dataset_set_quota(const char *dsname, zprop_source_t source, uint64_t quota) 3443a9799022Sck { 3444a9799022Sck dsl_dataset_t *ds; 344592241e0bSTom Erickson dsl_prop_setarg_t psa; 3446a9799022Sck int err; 3447a9799022Sck 344892241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refquota", source, "a); 344992241e0bSTom Erickson 3450745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3451a9799022Sck if (err) 3452a9799022Sck return (err); 3453a9799022Sck 345492241e0bSTom Erickson /* 345592241e0bSTom Erickson * If someone removes a file, then tries to set the quota, we 345692241e0bSTom Erickson * want to make sure the file freeing takes effect. 345792241e0bSTom Erickson */ 345892241e0bSTom Erickson txg_wait_open(ds->ds_dir->dd_pool, 0); 345992241e0bSTom Erickson 346092241e0bSTom Erickson err = dsl_sync_task_do(ds->ds_dir->dd_pool, 346192241e0bSTom Erickson dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, 346292241e0bSTom Erickson ds, &psa, 0); 3463a9799022Sck 3464745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3465a9799022Sck return (err); 3466a9799022Sck } 3467a9799022Sck 3468a9799022Sck static int 3469a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx) 3470a9799022Sck { 3471a9799022Sck dsl_dataset_t *ds = arg1; 347292241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 347392241e0bSTom Erickson uint64_t effective_value; 3474a9799022Sck uint64_t unique; 347592241e0bSTom Erickson int err; 3476a9799022Sck 3477a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 3478a9799022Sck SPA_VERSION_REFRESERVATION) 3479a9799022Sck return (ENOTSUP); 3480a9799022Sck 3481a9799022Sck if (dsl_dataset_is_snapshot(ds)) 3482a9799022Sck return (EINVAL); 3483a9799022Sck 348492241e0bSTom Erickson if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0) 348592241e0bSTom Erickson return (err); 348692241e0bSTom Erickson 348792241e0bSTom Erickson effective_value = psa->psa_effective_value; 348892241e0bSTom Erickson 3489a9799022Sck /* 3490a9799022Sck * If we are doing the preliminary check in open context, the 3491a9799022Sck * space estimates may be inaccurate. 3492a9799022Sck */ 3493a9799022Sck if (!dmu_tx_is_syncing(tx)) 3494a9799022Sck return (0); 3495a9799022Sck 3496a9799022Sck mutex_enter(&ds->ds_lock); 34973f9d6ad7SLin Ling if (!DS_UNIQUE_IS_ACCURATE(ds)) 34983f9d6ad7SLin Ling dsl_dataset_recalc_head_uniq(ds); 34993f9d6ad7SLin Ling unique = ds->ds_phys->ds_unique_bytes; 3500a9799022Sck mutex_exit(&ds->ds_lock); 3501a9799022Sck 350292241e0bSTom Erickson if (MAX(unique, effective_value) > MAX(unique, ds->ds_reserved)) { 350392241e0bSTom Erickson uint64_t delta = MAX(unique, effective_value) - 3504379c004dSEric Schrock MAX(unique, ds->ds_reserved); 3505379c004dSEric Schrock 3506379c004dSEric Schrock if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 3507379c004dSEric Schrock return (ENOSPC); 3508379c004dSEric Schrock if (ds->ds_quota > 0 && 350992241e0bSTom Erickson effective_value > ds->ds_quota) 3510379c004dSEric Schrock return (ENOSPC); 3511379c004dSEric Schrock } 3512a9799022Sck 3513a9799022Sck return (0); 3514a9799022Sck } 3515a9799022Sck 3516a9799022Sck static void 35173f9d6ad7SLin Ling dsl_dataset_set_reservation_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3518a9799022Sck { 3519a9799022Sck dsl_dataset_t *ds = arg1; 352092241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 352192241e0bSTom Erickson uint64_t effective_value = psa->psa_effective_value; 352202c8f3f0SMatthew Ahrens uint64_t unique; 352302c8f3f0SMatthew Ahrens int64_t delta; 352402c8f3f0SMatthew Ahrens 35253f9d6ad7SLin Ling dsl_prop_set_sync(ds, psa, tx); 352692241e0bSTom Erickson DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa); 352792241e0bSTom Erickson 352802c8f3f0SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 352902c8f3f0SMatthew Ahrens 353002c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 353102c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_lock); 35323f9d6ad7SLin Ling ASSERT(DS_UNIQUE_IS_ACCURATE(ds)); 35333f9d6ad7SLin Ling unique = ds->ds_phys->ds_unique_bytes; 353492241e0bSTom Erickson delta = MAX(0, (int64_t)(effective_value - unique)) - 353502c8f3f0SMatthew Ahrens MAX(0, (int64_t)(ds->ds_reserved - unique)); 353692241e0bSTom Erickson ds->ds_reserved = effective_value; 353702c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_lock); 353802c8f3f0SMatthew Ahrens 353902c8f3f0SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx); 354002c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 3541a9799022Sck 35424445fffbSMatthew Ahrens spa_history_log_internal_ds(ds, "set refreservation", tx, 35434445fffbSMatthew Ahrens "refreservation=%lld", (longlong_t)effective_value); 3544a9799022Sck } 3545a9799022Sck 3546a9799022Sck int 354792241e0bSTom Erickson dsl_dataset_set_reservation(const char *dsname, zprop_source_t source, 354892241e0bSTom Erickson uint64_t reservation) 3549a9799022Sck { 3550a9799022Sck dsl_dataset_t *ds; 355192241e0bSTom Erickson dsl_prop_setarg_t psa; 3552a9799022Sck int err; 3553a9799022Sck 355492241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refreservation", source, 355592241e0bSTom Erickson &reservation); 355692241e0bSTom Erickson 3557745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3558a9799022Sck if (err) 3559a9799022Sck return (err); 3560a9799022Sck 3561a9799022Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3562a9799022Sck dsl_dataset_set_reservation_check, 356392241e0bSTom Erickson dsl_dataset_set_reservation_sync, ds, &psa, 0); 356492241e0bSTom Erickson 3565745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3566a9799022Sck return (err); 3567a9799022Sck } 3568842727c2SChris Kirby 3569c99e4bdcSChris Kirby typedef struct zfs_hold_cleanup_arg { 3570a7f53a56SChris Kirby dsl_pool_t *dp; 3571a7f53a56SChris Kirby uint64_t dsobj; 3572c99e4bdcSChris Kirby char htag[MAXNAMELEN]; 3573c99e4bdcSChris Kirby } zfs_hold_cleanup_arg_t; 3574c99e4bdcSChris Kirby 3575c99e4bdcSChris Kirby static void 3576c99e4bdcSChris Kirby dsl_dataset_user_release_onexit(void *arg) 3577c99e4bdcSChris Kirby { 3578c99e4bdcSChris Kirby zfs_hold_cleanup_arg_t *ca = arg; 3579c99e4bdcSChris Kirby 3580a7f53a56SChris Kirby (void) dsl_dataset_user_release_tmp(ca->dp, ca->dsobj, ca->htag, 3581a7f53a56SChris Kirby B_TRUE); 3582c99e4bdcSChris Kirby kmem_free(ca, sizeof (zfs_hold_cleanup_arg_t)); 3583c99e4bdcSChris Kirby } 3584c99e4bdcSChris Kirby 3585a7f53a56SChris Kirby void 3586a7f53a56SChris Kirby dsl_register_onexit_hold_cleanup(dsl_dataset_t *ds, const char *htag, 3587a7f53a56SChris Kirby minor_t minor) 3588a7f53a56SChris Kirby { 3589a7f53a56SChris Kirby zfs_hold_cleanup_arg_t *ca; 3590a7f53a56SChris Kirby 3591a7f53a56SChris Kirby ca = kmem_alloc(sizeof (zfs_hold_cleanup_arg_t), KM_SLEEP); 3592a7f53a56SChris Kirby ca->dp = ds->ds_dir->dd_pool; 3593a7f53a56SChris Kirby ca->dsobj = ds->ds_object; 3594a7f53a56SChris Kirby (void) strlcpy(ca->htag, htag, sizeof (ca->htag)); 3595b420f3adSRichard Lowe VERIFY3U(0, ==, zfs_onexit_add_cb(minor, 3596a7f53a56SChris Kirby dsl_dataset_user_release_onexit, ca, NULL)); 3597a7f53a56SChris Kirby } 3598a7f53a56SChris Kirby 359915508ac0SChris Kirby /* 360099d5e173STim Haley * If you add new checks here, you may need to add 360199d5e173STim Haley * additional checks to the "temporary" case in 360299d5e173STim Haley * snapshot_check() in dmu_objset.c. 360315508ac0SChris Kirby */ 3604842727c2SChris Kirby static int 3605842727c2SChris Kirby dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx) 3606842727c2SChris Kirby { 3607842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3608ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 36094445fffbSMatthew Ahrens const char *htag = ha->htag; 3610842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3611842727c2SChris Kirby int error = 0; 3612842727c2SChris Kirby 3613842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3614842727c2SChris Kirby return (ENOTSUP); 3615842727c2SChris Kirby 3616842727c2SChris Kirby if (!dsl_dataset_is_snapshot(ds)) 3617842727c2SChris Kirby return (EINVAL); 3618842727c2SChris Kirby 3619842727c2SChris Kirby /* tags must be unique */ 3620842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3621842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj) { 3622842727c2SChris Kirby error = zap_lookup(mos, ds->ds_phys->ds_userrefs_obj, htag, 3623842727c2SChris Kirby 8, 1, tx); 3624842727c2SChris Kirby if (error == 0) 3625842727c2SChris Kirby error = EEXIST; 3626842727c2SChris Kirby else if (error == ENOENT) 3627842727c2SChris Kirby error = 0; 3628842727c2SChris Kirby } 3629842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3630842727c2SChris Kirby 363115508ac0SChris Kirby if (error == 0 && ha->temphold && 363215508ac0SChris Kirby strlen(htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN) 363315508ac0SChris Kirby error = E2BIG; 363415508ac0SChris Kirby 3635842727c2SChris Kirby return (error); 3636842727c2SChris Kirby } 3637842727c2SChris Kirby 363899d5e173STim Haley void 36393f9d6ad7SLin Ling dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx) 3640842727c2SChris Kirby { 3641842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3642ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 36434445fffbSMatthew Ahrens const char *htag = ha->htag; 3644ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3645ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 364615508ac0SChris Kirby uint64_t now = gethrestime_sec(); 3647842727c2SChris Kirby uint64_t zapobj; 3648842727c2SChris Kirby 3649842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3650842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj == 0) { 3651842727c2SChris Kirby /* 3652842727c2SChris Kirby * This is the first user hold for this dataset. Create 3653842727c2SChris Kirby * the userrefs zap object. 3654842727c2SChris Kirby */ 3655842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 3656842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj = 3657842727c2SChris Kirby zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx); 3658842727c2SChris Kirby } else { 3659842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3660842727c2SChris Kirby } 3661842727c2SChris Kirby ds->ds_userrefs++; 3662842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3663842727c2SChris Kirby 3664842727c2SChris Kirby VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx)); 3665842727c2SChris Kirby 3666ca45db41SChris Kirby if (ha->temphold) { 3667ca45db41SChris Kirby VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object, 3668ca45db41SChris Kirby htag, &now, tx)); 3669ca45db41SChris Kirby } 3670ca45db41SChris Kirby 36714445fffbSMatthew Ahrens spa_history_log_internal_ds(ds, "hold", tx, 36724445fffbSMatthew Ahrens "tag = %s temp = %d holds now = %llu", 36734445fffbSMatthew Ahrens htag, (int)ha->temphold, ds->ds_userrefs); 3674842727c2SChris Kirby } 3675842727c2SChris Kirby 3676842727c2SChris Kirby static int 3677fd136879SMatthew Ahrens dsl_dataset_user_hold_one(const char *dsname, void *arg) 3678842727c2SChris Kirby { 3679842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3680842727c2SChris Kirby dsl_dataset_t *ds; 3681842727c2SChris Kirby int error; 3682842727c2SChris Kirby char *name; 3683842727c2SChris Kirby 3684842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname plus terminating NULL */ 3685ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3686842727c2SChris Kirby error = dsl_dataset_hold(name, ha->dstg, &ds); 3687ae46e4c7SMatthew Ahrens strfree(name); 3688842727c2SChris Kirby if (error == 0) { 3689d7747cbcSChris Kirby ha->gotone = B_TRUE; 3690842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check, 3691ca45db41SChris Kirby dsl_dataset_user_hold_sync, ds, ha, 0); 3692842727c2SChris Kirby } else if (error == ENOENT && ha->recursive) { 3693842727c2SChris Kirby error = 0; 3694842727c2SChris Kirby } else { 3695fd136879SMatthew Ahrens (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3696842727c2SChris Kirby } 3697842727c2SChris Kirby return (error); 3698842727c2SChris Kirby } 3699842727c2SChris Kirby 3700a7f53a56SChris Kirby int 3701a7f53a56SChris Kirby dsl_dataset_user_hold_for_send(dsl_dataset_t *ds, char *htag, 3702a7f53a56SChris Kirby boolean_t temphold) 3703a7f53a56SChris Kirby { 3704a7f53a56SChris Kirby struct dsl_ds_holdarg *ha; 3705a7f53a56SChris Kirby int error; 3706a7f53a56SChris Kirby 3707a7f53a56SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3708a7f53a56SChris Kirby ha->htag = htag; 3709a7f53a56SChris Kirby ha->temphold = temphold; 3710a7f53a56SChris Kirby error = dsl_sync_task_do(ds->ds_dir->dd_pool, 3711a7f53a56SChris Kirby dsl_dataset_user_hold_check, dsl_dataset_user_hold_sync, 3712a7f53a56SChris Kirby ds, ha, 0); 3713a7f53a56SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3714a7f53a56SChris Kirby 3715a7f53a56SChris Kirby return (error); 3716a7f53a56SChris Kirby } 3717a7f53a56SChris Kirby 3718842727c2SChris Kirby int 3719842727c2SChris Kirby dsl_dataset_user_hold(char *dsname, char *snapname, char *htag, 3720c99e4bdcSChris Kirby boolean_t recursive, boolean_t temphold, int cleanup_fd) 3721842727c2SChris Kirby { 3722842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3723842727c2SChris Kirby dsl_sync_task_t *dst; 3724842727c2SChris Kirby spa_t *spa; 3725842727c2SChris Kirby int error; 3726a7f53a56SChris Kirby minor_t minor = 0; 3727a7f53a56SChris Kirby 3728a7f53a56SChris Kirby if (cleanup_fd != -1) { 3729a7f53a56SChris Kirby /* Currently we only support cleanup-on-exit of tempholds. */ 3730a7f53a56SChris Kirby if (!temphold) 3731a7f53a56SChris Kirby return (EINVAL); 3732a7f53a56SChris Kirby error = zfs_onexit_fd_hold(cleanup_fd, &minor); 3733a7f53a56SChris Kirby if (error) 3734a7f53a56SChris Kirby return (error); 3735a7f53a56SChris Kirby } 3736842727c2SChris Kirby 3737842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3738842727c2SChris Kirby 3739842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3740842727c2SChris Kirby 3741842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3742842727c2SChris Kirby if (error) { 3743842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3744a7f53a56SChris Kirby if (cleanup_fd != -1) 3745a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 3746842727c2SChris Kirby return (error); 3747842727c2SChris Kirby } 3748842727c2SChris Kirby 3749842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3750842727c2SChris Kirby ha->htag = htag; 3751842727c2SChris Kirby ha->snapname = snapname; 3752842727c2SChris Kirby ha->recursive = recursive; 3753ca45db41SChris Kirby ha->temphold = temphold; 3754c99e4bdcSChris Kirby 3755842727c2SChris Kirby if (recursive) { 3756842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_hold_one, 3757842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3758842727c2SChris Kirby } else { 3759842727c2SChris Kirby error = dsl_dataset_user_hold_one(dsname, ha); 3760842727c2SChris Kirby } 3761842727c2SChris Kirby if (error == 0) 3762842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3763842727c2SChris Kirby 3764842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3765842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3766842727c2SChris Kirby dsl_dataset_t *ds = dst->dst_arg1; 3767842727c2SChris Kirby 3768842727c2SChris Kirby if (dst->dst_err) { 3769842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3770842727c2SChris Kirby *strchr(ha->failed, '@') = '\0'; 3771a7f53a56SChris Kirby } else if (error == 0 && minor != 0 && temphold) { 3772a7f53a56SChris Kirby /* 3773a7f53a56SChris Kirby * If this hold is to be released upon process exit, 3774a7f53a56SChris Kirby * register that action now. 3775a7f53a56SChris Kirby */ 3776a7f53a56SChris Kirby dsl_register_onexit_hold_cleanup(ds, htag, minor); 3777842727c2SChris Kirby } 3778842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3779842727c2SChris Kirby } 3780842727c2SChris Kirby 3781d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3782d7747cbcSChris Kirby error = ENOENT; 3783d7747cbcSChris Kirby 3784842727c2SChris Kirby if (error) 3785fd136879SMatthew Ahrens (void) strlcpy(dsname, ha->failed, sizeof (ha->failed)); 3786842727c2SChris Kirby 3787842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3788c99e4bdcSChris Kirby 3789842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3790842727c2SChris Kirby spa_close(spa, FTAG); 3791a7f53a56SChris Kirby if (cleanup_fd != -1) 3792a7f53a56SChris Kirby zfs_onexit_fd_rele(cleanup_fd); 3793842727c2SChris Kirby return (error); 3794842727c2SChris Kirby } 3795842727c2SChris Kirby 3796842727c2SChris Kirby struct dsl_ds_releasearg { 3797842727c2SChris Kirby dsl_dataset_t *ds; 3798842727c2SChris Kirby const char *htag; 3799842727c2SChris Kirby boolean_t own; /* do we own or just hold ds? */ 3800842727c2SChris Kirby }; 3801842727c2SChris Kirby 3802842727c2SChris Kirby static int 3803842727c2SChris Kirby dsl_dataset_release_might_destroy(dsl_dataset_t *ds, const char *htag, 3804842727c2SChris Kirby boolean_t *might_destroy) 3805842727c2SChris Kirby { 3806842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3807842727c2SChris Kirby uint64_t zapobj; 3808842727c2SChris Kirby uint64_t tmp; 3809842727c2SChris Kirby int error; 3810842727c2SChris Kirby 3811842727c2SChris Kirby *might_destroy = B_FALSE; 3812842727c2SChris Kirby 3813842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3814842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3815842727c2SChris Kirby if (zapobj == 0) { 3816842727c2SChris Kirby /* The tag can't possibly exist */ 3817842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3818842727c2SChris Kirby return (ESRCH); 3819842727c2SChris Kirby } 3820842727c2SChris Kirby 3821842727c2SChris Kirby /* Make sure the tag exists */ 3822842727c2SChris Kirby error = zap_lookup(mos, zapobj, htag, 8, 1, &tmp); 3823842727c2SChris Kirby if (error) { 3824842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3825842727c2SChris Kirby if (error == ENOENT) 3826842727c2SChris Kirby error = ESRCH; 3827842727c2SChris Kirby return (error); 3828842727c2SChris Kirby } 3829842727c2SChris Kirby 3830842727c2SChris Kirby if (ds->ds_userrefs == 1 && ds->ds_phys->ds_num_children == 1 && 3831842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 3832842727c2SChris Kirby *might_destroy = B_TRUE; 3833842727c2SChris Kirby 3834842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3835842727c2SChris Kirby return (0); 3836842727c2SChris Kirby } 3837842727c2SChris Kirby 3838842727c2SChris Kirby static int 3839842727c2SChris Kirby dsl_dataset_user_release_check(void *arg1, void *tag, dmu_tx_t *tx) 3840842727c2SChris Kirby { 3841842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3842842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3843842727c2SChris Kirby boolean_t might_destroy; 3844842727c2SChris Kirby int error; 3845842727c2SChris Kirby 3846842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3847842727c2SChris Kirby return (ENOTSUP); 3848842727c2SChris Kirby 3849842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ra->htag, &might_destroy); 3850842727c2SChris Kirby if (error) 3851842727c2SChris Kirby return (error); 3852842727c2SChris Kirby 3853842727c2SChris Kirby if (might_destroy) { 3854842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3855842727c2SChris Kirby 3856842727c2SChris Kirby if (dmu_tx_is_syncing(tx)) { 3857842727c2SChris Kirby /* 3858842727c2SChris Kirby * If we're not prepared to remove the snapshot, 3859842727c2SChris Kirby * we can't allow the release to happen right now. 3860842727c2SChris Kirby */ 3861842727c2SChris Kirby if (!ra->own) 3862842727c2SChris Kirby return (EBUSY); 3863842727c2SChris Kirby } 3864842727c2SChris Kirby dsda.ds = ds; 3865842727c2SChris Kirby dsda.releasing = B_TRUE; 3866842727c2SChris Kirby return (dsl_dataset_destroy_check(&dsda, tag, tx)); 3867842727c2SChris Kirby } 3868842727c2SChris Kirby 3869842727c2SChris Kirby return (0); 3870842727c2SChris Kirby } 3871842727c2SChris Kirby 3872842727c2SChris Kirby static void 38733f9d6ad7SLin Ling dsl_dataset_user_release_sync(void *arg1, void *tag, dmu_tx_t *tx) 3874842727c2SChris Kirby { 3875842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3876842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3877ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3878ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 3879842727c2SChris Kirby uint64_t zapobj; 3880842727c2SChris Kirby uint64_t refs; 3881ca45db41SChris Kirby int error; 3882842727c2SChris Kirby 3883842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3884842727c2SChris Kirby ds->ds_userrefs--; 3885842727c2SChris Kirby refs = ds->ds_userrefs; 3886842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3887ca45db41SChris Kirby error = dsl_pool_user_release(dp, ds->ds_object, ra->htag, tx); 3888ca45db41SChris Kirby VERIFY(error == 0 || error == ENOENT); 3889842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3890842727c2SChris Kirby VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx)); 3891347eec8eSChristopher Siden 3892347eec8eSChristopher Siden spa_history_log_internal_ds(ds, "release", tx, 3893347eec8eSChristopher Siden "tag = %s refs now = %lld", ra->htag, (longlong_t)refs); 3894347eec8eSChristopher Siden 3895842727c2SChris Kirby if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 && 3896842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) { 3897842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3898842727c2SChris Kirby 3899842727c2SChris Kirby ASSERT(ra->own); 3900842727c2SChris Kirby dsda.ds = ds; 3901842727c2SChris Kirby dsda.releasing = B_TRUE; 3902842727c2SChris Kirby /* We already did the destroy_check */ 39033f9d6ad7SLin Ling dsl_dataset_destroy_sync(&dsda, tag, tx); 3904842727c2SChris Kirby } 3905842727c2SChris Kirby } 3906842727c2SChris Kirby 3907842727c2SChris Kirby static int 3908fd136879SMatthew Ahrens dsl_dataset_user_release_one(const char *dsname, void *arg) 3909842727c2SChris Kirby { 3910842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3911842727c2SChris Kirby struct dsl_ds_releasearg *ra; 3912842727c2SChris Kirby dsl_dataset_t *ds; 3913842727c2SChris Kirby int error; 3914842727c2SChris Kirby void *dtag = ha->dstg; 3915842727c2SChris Kirby char *name; 3916842727c2SChris Kirby boolean_t own = B_FALSE; 3917842727c2SChris Kirby boolean_t might_destroy; 3918842727c2SChris Kirby 3919842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname, plus the terminating NULL */ 3920ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3921842727c2SChris Kirby error = dsl_dataset_hold(name, dtag, &ds); 3922ae46e4c7SMatthew Ahrens strfree(name); 3923842727c2SChris Kirby if (error == ENOENT && ha->recursive) 3924842727c2SChris Kirby return (0); 3925fd136879SMatthew Ahrens (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3926842727c2SChris Kirby if (error) 3927842727c2SChris Kirby return (error); 3928842727c2SChris Kirby 3929d7747cbcSChris Kirby ha->gotone = B_TRUE; 3930d7747cbcSChris Kirby 3931842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 3932842727c2SChris Kirby 3933842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ha->htag, &might_destroy); 3934842727c2SChris Kirby if (error) { 3935842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3936842727c2SChris Kirby return (error); 3937842727c2SChris Kirby } 3938842727c2SChris Kirby 3939842727c2SChris Kirby if (might_destroy) { 3940842727c2SChris Kirby #ifdef _KERNEL 39415afc78aaSChris Kirby name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3942842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 39435afc78aaSChris Kirby strfree(name); 3944842727c2SChris Kirby if (error) { 3945842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3946842727c2SChris Kirby return (error); 3947842727c2SChris Kirby } 3948842727c2SChris Kirby #endif 3949503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(ds, B_TRUE, dtag)) { 3950842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3951842727c2SChris Kirby return (EBUSY); 3952842727c2SChris Kirby } else { 3953842727c2SChris Kirby own = B_TRUE; 3954842727c2SChris Kirby dsl_dataset_make_exclusive(ds, dtag); 3955842727c2SChris Kirby } 3956842727c2SChris Kirby } 3957842727c2SChris Kirby 3958842727c2SChris Kirby ra = kmem_alloc(sizeof (struct dsl_ds_releasearg), KM_SLEEP); 3959842727c2SChris Kirby ra->ds = ds; 3960842727c2SChris Kirby ra->htag = ha->htag; 3961842727c2SChris Kirby ra->own = own; 3962842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_release_check, 3963842727c2SChris Kirby dsl_dataset_user_release_sync, ra, dtag, 0); 3964842727c2SChris Kirby 3965842727c2SChris Kirby return (0); 3966842727c2SChris Kirby } 3967842727c2SChris Kirby 3968842727c2SChris Kirby int 3969842727c2SChris Kirby dsl_dataset_user_release(char *dsname, char *snapname, char *htag, 3970842727c2SChris Kirby boolean_t recursive) 3971842727c2SChris Kirby { 3972842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3973842727c2SChris Kirby dsl_sync_task_t *dst; 3974842727c2SChris Kirby spa_t *spa; 3975842727c2SChris Kirby int error; 3976842727c2SChris Kirby 3977620252bcSChris Kirby top: 3978842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3979842727c2SChris Kirby 3980842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3981842727c2SChris Kirby 3982842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3983842727c2SChris Kirby if (error) { 3984842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3985842727c2SChris Kirby return (error); 3986842727c2SChris Kirby } 3987842727c2SChris Kirby 3988842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3989842727c2SChris Kirby ha->htag = htag; 3990842727c2SChris Kirby ha->snapname = snapname; 3991842727c2SChris Kirby ha->recursive = recursive; 3992842727c2SChris Kirby if (recursive) { 3993842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_release_one, 3994842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3995842727c2SChris Kirby } else { 3996842727c2SChris Kirby error = dsl_dataset_user_release_one(dsname, ha); 3997842727c2SChris Kirby } 3998842727c2SChris Kirby if (error == 0) 3999842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 4000842727c2SChris Kirby 4001842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 4002842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 4003842727c2SChris Kirby struct dsl_ds_releasearg *ra = dst->dst_arg1; 4004842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 4005842727c2SChris Kirby 4006842727c2SChris Kirby if (dst->dst_err) 4007842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 4008842727c2SChris Kirby 4009842727c2SChris Kirby if (ra->own) 4010842727c2SChris Kirby dsl_dataset_disown(ds, ha->dstg); 4011842727c2SChris Kirby else 4012842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 4013842727c2SChris Kirby 4014842727c2SChris Kirby kmem_free(ra, sizeof (struct dsl_ds_releasearg)); 4015842727c2SChris Kirby } 4016842727c2SChris Kirby 4017d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 4018d7747cbcSChris Kirby error = ENOENT; 4019d7747cbcSChris Kirby 4020620252bcSChris Kirby if (error && error != EBUSY) 4021fd136879SMatthew Ahrens (void) strlcpy(dsname, ha->failed, sizeof (ha->failed)); 4022842727c2SChris Kirby 4023842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 4024842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 4025842727c2SChris Kirby spa_close(spa, FTAG); 4026620252bcSChris Kirby 4027620252bcSChris Kirby /* 4028620252bcSChris Kirby * We can get EBUSY if we were racing with deferred destroy and 4029620252bcSChris Kirby * dsl_dataset_user_release_check() hadn't done the necessary 4030620252bcSChris Kirby * open context setup. We can also get EBUSY if we're racing 4031620252bcSChris Kirby * with destroy and that thread is the ds_owner. Either way 4032620252bcSChris Kirby * the busy condition should be transient, and we should retry 4033620252bcSChris Kirby * the release operation. 4034620252bcSChris Kirby */ 4035620252bcSChris Kirby if (error == EBUSY) 4036620252bcSChris Kirby goto top; 4037620252bcSChris Kirby 4038842727c2SChris Kirby return (error); 4039842727c2SChris Kirby } 4040842727c2SChris Kirby 4041ca45db41SChris Kirby /* 4042a7f53a56SChris Kirby * Called at spa_load time (with retry == B_FALSE) to release a stale 4043a7f53a56SChris Kirby * temporary user hold. Also called by the onexit code (with retry == B_TRUE). 4044ca45db41SChris Kirby */ 4045ca45db41SChris Kirby int 4046a7f53a56SChris Kirby dsl_dataset_user_release_tmp(dsl_pool_t *dp, uint64_t dsobj, char *htag, 4047a7f53a56SChris Kirby boolean_t retry) 4048ca45db41SChris Kirby { 4049ca45db41SChris Kirby dsl_dataset_t *ds; 4050ca45db41SChris Kirby char *snap; 4051ca45db41SChris Kirby char *name; 4052ca45db41SChris Kirby int namelen; 4053ca45db41SChris Kirby int error; 4054ca45db41SChris Kirby 4055a7f53a56SChris Kirby do { 4056a7f53a56SChris Kirby rw_enter(&dp->dp_config_rwlock, RW_READER); 4057a7f53a56SChris Kirby error = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds); 4058a7f53a56SChris Kirby rw_exit(&dp->dp_config_rwlock); 4059a7f53a56SChris Kirby if (error) 4060a7f53a56SChris Kirby return (error); 4061a7f53a56SChris Kirby namelen = dsl_dataset_namelen(ds)+1; 4062a7f53a56SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 4063a7f53a56SChris Kirby dsl_dataset_name(ds, name); 4064a7f53a56SChris Kirby dsl_dataset_rele(ds, FTAG); 4065ca45db41SChris Kirby 4066a7f53a56SChris Kirby snap = strchr(name, '@'); 4067a7f53a56SChris Kirby *snap = '\0'; 4068a7f53a56SChris Kirby ++snap; 4069a7f53a56SChris Kirby error = dsl_dataset_user_release(name, snap, htag, B_FALSE); 4070a7f53a56SChris Kirby kmem_free(name, namelen); 4071a7f53a56SChris Kirby 4072a7f53a56SChris Kirby /* 4073a7f53a56SChris Kirby * The object can't have been destroyed because we have a hold, 4074a7f53a56SChris Kirby * but it might have been renamed, resulting in ENOENT. Retry 4075a7f53a56SChris Kirby * if we've been requested to do so. 4076a7f53a56SChris Kirby * 4077a7f53a56SChris Kirby * It would be nice if we could use the dsobj all the way 4078a7f53a56SChris Kirby * through and avoid ENOENT entirely. But we might need to 4079a7f53a56SChris Kirby * unmount the snapshot, and there's currently no way to lookup 4080a7f53a56SChris Kirby * a vfsp using a ZFS object id. 4081a7f53a56SChris Kirby */ 4082a7f53a56SChris Kirby } while ((error == ENOENT) && retry); 4083a7f53a56SChris Kirby 4084a7f53a56SChris Kirby return (error); 4085ca45db41SChris Kirby } 4086ca45db41SChris Kirby 4087842727c2SChris Kirby int 4088842727c2SChris Kirby dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp) 4089842727c2SChris Kirby { 4090842727c2SChris Kirby dsl_dataset_t *ds; 4091842727c2SChris Kirby int err; 4092842727c2SChris Kirby 4093842727c2SChris Kirby err = dsl_dataset_hold(dsname, FTAG, &ds); 4094842727c2SChris Kirby if (err) 4095842727c2SChris Kirby return (err); 4096842727c2SChris Kirby 4097842727c2SChris Kirby VERIFY(0 == nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP)); 4098842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) { 4099842727c2SChris Kirby zap_attribute_t *za; 4100842727c2SChris Kirby zap_cursor_t zc; 4101842727c2SChris Kirby 4102842727c2SChris Kirby za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 4103842727c2SChris Kirby for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset, 4104842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj); 4105842727c2SChris Kirby zap_cursor_retrieve(&zc, za) == 0; 4106842727c2SChris Kirby zap_cursor_advance(&zc)) { 4107842727c2SChris Kirby VERIFY(0 == nvlist_add_uint64(*nvp, za->za_name, 4108842727c2SChris Kirby za->za_first_integer)); 4109842727c2SChris Kirby } 4110842727c2SChris Kirby zap_cursor_fini(&zc); 4111842727c2SChris Kirby kmem_free(za, sizeof (zap_attribute_t)); 4112842727c2SChris Kirby } 4113842727c2SChris Kirby dsl_dataset_rele(ds, FTAG); 4114842727c2SChris Kirby return (0); 4115842727c2SChris Kirby } 4116503ad85cSMatthew Ahrens 4117503ad85cSMatthew Ahrens /* 411819b94df9SMatthew Ahrens * Note, this function is used as the callback for dmu_objset_find(). We 4119503ad85cSMatthew Ahrens * always return 0 so that we will continue to find and process 4120503ad85cSMatthew Ahrens * inconsistent datasets, even if we encounter an error trying to 4121503ad85cSMatthew Ahrens * process one of them. 4122503ad85cSMatthew Ahrens */ 4123503ad85cSMatthew Ahrens /* ARGSUSED */ 4124503ad85cSMatthew Ahrens int 4125fd136879SMatthew Ahrens dsl_destroy_inconsistent(const char *dsname, void *arg) 4126503ad85cSMatthew Ahrens { 4127503ad85cSMatthew Ahrens dsl_dataset_t *ds; 4128503ad85cSMatthew Ahrens 4129503ad85cSMatthew Ahrens if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) { 4130503ad85cSMatthew Ahrens if (DS_IS_INCONSISTENT(ds)) 4131503ad85cSMatthew Ahrens (void) dsl_dataset_destroy(ds, FTAG, B_FALSE); 4132503ad85cSMatthew Ahrens else 4133503ad85cSMatthew Ahrens dsl_dataset_disown(ds, FTAG); 4134503ad85cSMatthew Ahrens } 4135503ad85cSMatthew Ahrens return (0); 4136503ad85cSMatthew Ahrens } 413719b94df9SMatthew Ahrens 413819b94df9SMatthew Ahrens /* 413919b94df9SMatthew Ahrens * Return (in *usedp) the amount of space written in new that is not 414019b94df9SMatthew Ahrens * present in oldsnap. New may be a snapshot or the head. Old must be 414119b94df9SMatthew Ahrens * a snapshot before new, in new's filesystem (or its origin). If not then 414219b94df9SMatthew Ahrens * fail and return EINVAL. 414319b94df9SMatthew Ahrens * 414419b94df9SMatthew Ahrens * The written space is calculated by considering two components: First, we 414519b94df9SMatthew Ahrens * ignore any freed space, and calculate the written as new's used space 414619b94df9SMatthew Ahrens * minus old's used space. Next, we add in the amount of space that was freed 414719b94df9SMatthew Ahrens * between the two snapshots, thus reducing new's used space relative to old's. 414819b94df9SMatthew Ahrens * Specifically, this is the space that was born before old->ds_creation_txg, 414919b94df9SMatthew Ahrens * and freed before new (ie. on new's deadlist or a previous deadlist). 415019b94df9SMatthew Ahrens * 415119b94df9SMatthew Ahrens * space freed [---------------------] 415219b94df9SMatthew Ahrens * snapshots ---O-------O--------O-------O------ 415319b94df9SMatthew Ahrens * oldsnap new 415419b94df9SMatthew Ahrens */ 415519b94df9SMatthew Ahrens int 415619b94df9SMatthew Ahrens dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new, 415719b94df9SMatthew Ahrens uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) 415819b94df9SMatthew Ahrens { 415919b94df9SMatthew Ahrens int err = 0; 416019b94df9SMatthew Ahrens uint64_t snapobj; 416119b94df9SMatthew Ahrens dsl_pool_t *dp = new->ds_dir->dd_pool; 416219b94df9SMatthew Ahrens 416319b94df9SMatthew Ahrens *usedp = 0; 4164ad135b5dSChristopher Siden *usedp += new->ds_phys->ds_referenced_bytes; 4165ad135b5dSChristopher Siden *usedp -= oldsnap->ds_phys->ds_referenced_bytes; 416619b94df9SMatthew Ahrens 416719b94df9SMatthew Ahrens *compp = 0; 416819b94df9SMatthew Ahrens *compp += new->ds_phys->ds_compressed_bytes; 416919b94df9SMatthew Ahrens *compp -= oldsnap->ds_phys->ds_compressed_bytes; 417019b94df9SMatthew Ahrens 417119b94df9SMatthew Ahrens *uncompp = 0; 417219b94df9SMatthew Ahrens *uncompp += new->ds_phys->ds_uncompressed_bytes; 417319b94df9SMatthew Ahrens *uncompp -= oldsnap->ds_phys->ds_uncompressed_bytes; 417419b94df9SMatthew Ahrens 417519b94df9SMatthew Ahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 417619b94df9SMatthew Ahrens snapobj = new->ds_object; 417719b94df9SMatthew Ahrens while (snapobj != oldsnap->ds_object) { 417819b94df9SMatthew Ahrens dsl_dataset_t *snap; 417919b94df9SMatthew Ahrens uint64_t used, comp, uncomp; 418019b94df9SMatthew Ahrens 4181ad135b5dSChristopher Siden if (snapobj == new->ds_object) { 4182ad135b5dSChristopher Siden snap = new; 4183ad135b5dSChristopher Siden } else { 4184ad135b5dSChristopher Siden err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snap); 4185ad135b5dSChristopher Siden if (err != 0) 4186ad135b5dSChristopher Siden break; 4187ad135b5dSChristopher Siden } 418819b94df9SMatthew Ahrens 418919b94df9SMatthew Ahrens if (snap->ds_phys->ds_prev_snap_txg == 419019b94df9SMatthew Ahrens oldsnap->ds_phys->ds_creation_txg) { 419119b94df9SMatthew Ahrens /* 419219b94df9SMatthew Ahrens * The blocks in the deadlist can not be born after 419319b94df9SMatthew Ahrens * ds_prev_snap_txg, so get the whole deadlist space, 419419b94df9SMatthew Ahrens * which is more efficient (especially for old-format 419519b94df9SMatthew Ahrens * deadlists). Unfortunately the deadlist code 419619b94df9SMatthew Ahrens * doesn't have enough information to make this 419719b94df9SMatthew Ahrens * optimization itself. 419819b94df9SMatthew Ahrens */ 419919b94df9SMatthew Ahrens dsl_deadlist_space(&snap->ds_deadlist, 420019b94df9SMatthew Ahrens &used, &comp, &uncomp); 420119b94df9SMatthew Ahrens } else { 420219b94df9SMatthew Ahrens dsl_deadlist_space_range(&snap->ds_deadlist, 420319b94df9SMatthew Ahrens 0, oldsnap->ds_phys->ds_creation_txg, 420419b94df9SMatthew Ahrens &used, &comp, &uncomp); 420519b94df9SMatthew Ahrens } 420619b94df9SMatthew Ahrens *usedp += used; 420719b94df9SMatthew Ahrens *compp += comp; 420819b94df9SMatthew Ahrens *uncompp += uncomp; 420919b94df9SMatthew Ahrens 421019b94df9SMatthew Ahrens /* 421119b94df9SMatthew Ahrens * If we get to the beginning of the chain of snapshots 421219b94df9SMatthew Ahrens * (ds_prev_snap_obj == 0) before oldsnap, then oldsnap 421319b94df9SMatthew Ahrens * was not a snapshot of/before new. 421419b94df9SMatthew Ahrens */ 421519b94df9SMatthew Ahrens snapobj = snap->ds_phys->ds_prev_snap_obj; 4216ad135b5dSChristopher Siden if (snap != new) 4217ad135b5dSChristopher Siden dsl_dataset_rele(snap, FTAG); 421819b94df9SMatthew Ahrens if (snapobj == 0) { 421919b94df9SMatthew Ahrens err = EINVAL; 422019b94df9SMatthew Ahrens break; 422119b94df9SMatthew Ahrens } 422219b94df9SMatthew Ahrens 422319b94df9SMatthew Ahrens } 422419b94df9SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 422519b94df9SMatthew Ahrens return (err); 422619b94df9SMatthew Ahrens } 422719b94df9SMatthew Ahrens 422819b94df9SMatthew Ahrens /* 422919b94df9SMatthew Ahrens * Return (in *usedp) the amount of space that will be reclaimed if firstsnap, 423019b94df9SMatthew Ahrens * lastsnap, and all snapshots in between are deleted. 423119b94df9SMatthew Ahrens * 423219b94df9SMatthew Ahrens * blocks that would be freed [---------------------------] 423319b94df9SMatthew Ahrens * snapshots ---O-------O--------O-------O--------O 423419b94df9SMatthew Ahrens * firstsnap lastsnap 423519b94df9SMatthew Ahrens * 423619b94df9SMatthew Ahrens * This is the set of blocks that were born after the snap before firstsnap, 423719b94df9SMatthew Ahrens * (birth > firstsnap->prev_snap_txg) and died before the snap after the 423819b94df9SMatthew Ahrens * last snap (ie, is on lastsnap->ds_next->ds_deadlist or an earlier deadlist). 423919b94df9SMatthew Ahrens * We calculate this by iterating over the relevant deadlists (from the snap 424019b94df9SMatthew Ahrens * after lastsnap, backward to the snap after firstsnap), summing up the 424119b94df9SMatthew Ahrens * space on the deadlist that was born after the snap before firstsnap. 424219b94df9SMatthew Ahrens */ 424319b94df9SMatthew Ahrens int 424419b94df9SMatthew Ahrens dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap, 424519b94df9SMatthew Ahrens dsl_dataset_t *lastsnap, 424619b94df9SMatthew Ahrens uint64_t *usedp, uint64_t *compp, uint64_t *uncompp) 424719b94df9SMatthew Ahrens { 424819b94df9SMatthew Ahrens int err = 0; 424919b94df9SMatthew Ahrens uint64_t snapobj; 425019b94df9SMatthew Ahrens dsl_pool_t *dp = firstsnap->ds_dir->dd_pool; 425119b94df9SMatthew Ahrens 425219b94df9SMatthew Ahrens ASSERT(dsl_dataset_is_snapshot(firstsnap)); 425319b94df9SMatthew Ahrens ASSERT(dsl_dataset_is_snapshot(lastsnap)); 425419b94df9SMatthew Ahrens 425519b94df9SMatthew Ahrens /* 425619b94df9SMatthew Ahrens * Check that the snapshots are in the same dsl_dir, and firstsnap 425719b94df9SMatthew Ahrens * is before lastsnap. 425819b94df9SMatthew Ahrens */ 425919b94df9SMatthew Ahrens if (firstsnap->ds_dir != lastsnap->ds_dir || 426019b94df9SMatthew Ahrens firstsnap->ds_phys->ds_creation_txg > 426119b94df9SMatthew Ahrens lastsnap->ds_phys->ds_creation_txg) 426219b94df9SMatthew Ahrens return (EINVAL); 426319b94df9SMatthew Ahrens 426419b94df9SMatthew Ahrens *usedp = *compp = *uncompp = 0; 426519b94df9SMatthew Ahrens 426619b94df9SMatthew Ahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 426719b94df9SMatthew Ahrens snapobj = lastsnap->ds_phys->ds_next_snap_obj; 426819b94df9SMatthew Ahrens while (snapobj != firstsnap->ds_object) { 426919b94df9SMatthew Ahrens dsl_dataset_t *ds; 427019b94df9SMatthew Ahrens uint64_t used, comp, uncomp; 427119b94df9SMatthew Ahrens 427219b94df9SMatthew Ahrens err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &ds); 427319b94df9SMatthew Ahrens if (err != 0) 427419b94df9SMatthew Ahrens break; 427519b94df9SMatthew Ahrens 427619b94df9SMatthew Ahrens dsl_deadlist_space_range(&ds->ds_deadlist, 427719b94df9SMatthew Ahrens firstsnap->ds_phys->ds_prev_snap_txg, UINT64_MAX, 427819b94df9SMatthew Ahrens &used, &comp, &uncomp); 427919b94df9SMatthew Ahrens *usedp += used; 428019b94df9SMatthew Ahrens *compp += comp; 428119b94df9SMatthew Ahrens *uncompp += uncomp; 428219b94df9SMatthew Ahrens 428319b94df9SMatthew Ahrens snapobj = ds->ds_phys->ds_prev_snap_obj; 428419b94df9SMatthew Ahrens ASSERT3U(snapobj, !=, 0); 428519b94df9SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 428619b94df9SMatthew Ahrens } 428719b94df9SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 428819b94df9SMatthew Ahrens return (err); 428919b94df9SMatthew Ahrens } 4290