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 /* 221db42183SEric Taylor * Copyright 2009 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #include <sys/dmu_objset.h> 27fa9e4066Sahrens #include <sys/dsl_dataset.h> 28fa9e4066Sahrens #include <sys/dsl_dir.h> 2999653d4eSeschrock #include <sys/dsl_prop.h> 301d452cf5Sahrens #include <sys/dsl_synctask.h> 31fa9e4066Sahrens #include <sys/dmu_traverse.h> 32fa9e4066Sahrens #include <sys/dmu_tx.h> 33fa9e4066Sahrens #include <sys/arc.h> 34fa9e4066Sahrens #include <sys/zio.h> 35fa9e4066Sahrens #include <sys/zap.h> 36fa9e4066Sahrens #include <sys/unique.h> 37fa9e4066Sahrens #include <sys/zfs_context.h> 38cdf5b4caSmmusante #include <sys/zfs_ioctl.h> 39ecd6cf80Smarks #include <sys/spa.h> 40088f3894Sahrens #include <sys/zfs_znode.h> 41ecd6cf80Smarks #include <sys/sunddi.h> 42842727c2SChris Kirby #include <sys/zvol.h> 43fa9e4066Sahrens 44745cd3c5Smaybee static char *dsl_reaper = "the grim reaper"; 45745cd3c5Smaybee 461d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 471d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 48a9799022Sck static dsl_syncfunc_t dsl_dataset_set_reservation_sync; 49e1930233Sbonwick 5055434c77Sek #define DS_REF_MAX (1ULL << 62) 51fa9e4066Sahrens 52fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 53fa9e4066Sahrens 54745cd3c5Smaybee #define DSL_DATASET_IS_DESTROYED(ds) ((ds)->ds_owner == dsl_reaper) 55745cd3c5Smaybee 56fa9e4066Sahrens 57a9799022Sck /* 58a9799022Sck * Figure out how much of this delta should be propogated to the dsl_dir 59a9799022Sck * layer. If there's a refreservation, that space has already been 60a9799022Sck * partially accounted for in our ancestors. 61a9799022Sck */ 62a9799022Sck static int64_t 63a9799022Sck parent_delta(dsl_dataset_t *ds, int64_t delta) 64a9799022Sck { 65a9799022Sck uint64_t old_bytes, new_bytes; 66a9799022Sck 67a9799022Sck if (ds->ds_reserved == 0) 68a9799022Sck return (delta); 69a9799022Sck 70a9799022Sck old_bytes = MAX(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 71a9799022Sck new_bytes = MAX(ds->ds_phys->ds_unique_bytes + delta, ds->ds_reserved); 72a9799022Sck 73a9799022Sck ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta)); 74a9799022Sck return (new_bytes - old_bytes); 75a9799022Sck } 76fa9e4066Sahrens 77fa9e4066Sahrens void 78fa9e4066Sahrens dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 79fa9e4066Sahrens { 8099653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 81fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 82fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 83a9799022Sck int64_t delta; 84fa9e4066Sahrens 85fa9e4066Sahrens dprintf_bp(bp, "born, ds=%p\n", ds); 86fa9e4066Sahrens 87fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 88fa9e4066Sahrens /* It could have been compressed away to nothing */ 89fa9e4066Sahrens if (BP_IS_HOLE(bp)) 90fa9e4066Sahrens return; 91fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 92fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 93fa9e4066Sahrens if (ds == NULL) { 94fa9e4066Sahrens /* 95fa9e4066Sahrens * Account for the meta-objset space in its placeholder 96fa9e4066Sahrens * dsl_dir. 97fa9e4066Sahrens */ 98fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 9974e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 100fa9e4066Sahrens used, compressed, uncompressed, tx); 101fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 102fa9e4066Sahrens return; 103fa9e4066Sahrens } 104fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 10502c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 106fa9e4066Sahrens mutex_enter(&ds->ds_lock); 107a9799022Sck delta = parent_delta(ds, used); 108fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 109fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 110fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 111fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 112fa9e4066Sahrens mutex_exit(&ds->ds_lock); 11374e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, 11474e7dc98SMatthew Ahrens compressed, uncompressed, tx); 11574e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used - delta, 11674e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 11702c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 118fa9e4066Sahrens } 119fa9e4066Sahrens 120cdb0ab79Smaybee int 121c717a561Smaybee dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, zio_t *pio, 122c717a561Smaybee dmu_tx_t *tx) 123fa9e4066Sahrens { 12499653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 125fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 126fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 127fa9e4066Sahrens 128e14bb325SJeff Bonwick ASSERT(pio != NULL); 129fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 130c717a561Smaybee /* No block pointer => nothing to free */ 131fa9e4066Sahrens if (BP_IS_HOLE(bp)) 132cdb0ab79Smaybee return (0); 133fa9e4066Sahrens 134fa9e4066Sahrens ASSERT(used > 0); 135fa9e4066Sahrens if (ds == NULL) { 136c717a561Smaybee int err; 137fa9e4066Sahrens /* 138fa9e4066Sahrens * Account for the meta-objset space in its placeholder 139fa9e4066Sahrens * dataset. 140fa9e4066Sahrens */ 141088f3894Sahrens err = dsl_free(pio, tx->tx_pool, 142e14bb325SJeff Bonwick tx->tx_txg, bp, NULL, NULL, ARC_NOWAIT); 143c717a561Smaybee ASSERT(err == 0); 144fa9e4066Sahrens 14574e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 146fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 147fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 148cdb0ab79Smaybee return (used); 149fa9e4066Sahrens } 150fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 151fa9e4066Sahrens 15274e7dc98SMatthew Ahrens ASSERT(!dsl_dataset_is_snapshot(ds)); 153fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 154fa9e4066Sahrens 155fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 156c717a561Smaybee int err; 157a9799022Sck int64_t delta; 158c717a561Smaybee 159fa9e4066Sahrens dprintf_bp(bp, "freeing: %s", ""); 160088f3894Sahrens err = dsl_free(pio, tx->tx_pool, 161e14bb325SJeff Bonwick tx->tx_txg, bp, NULL, NULL, ARC_NOWAIT); 162c717a561Smaybee ASSERT(err == 0); 163fa9e4066Sahrens 16402c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 165fa9e4066Sahrens mutex_enter(&ds->ds_lock); 166a9799022Sck ASSERT(ds->ds_phys->ds_unique_bytes >= used || 167a9799022Sck !DS_UNIQUE_IS_ACCURATE(ds)); 168a9799022Sck delta = parent_delta(ds, -used); 169fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 170fa9e4066Sahrens mutex_exit(&ds->ds_lock); 17174e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 172a9799022Sck delta, -compressed, -uncompressed, tx); 17374e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, -used - delta, 17474e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 17502c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 176fa9e4066Sahrens } else { 177fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 178ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 179a4611edeSahrens ASSERT3U(ds->ds_prev->ds_object, ==, 180a4611edeSahrens ds->ds_phys->ds_prev_snap_obj); 181a4611edeSahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 182fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 183a4611edeSahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 184a4611edeSahrens ds->ds_object && bp->blk_birth > 185a4611edeSahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 186a4611edeSahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 187a4611edeSahrens mutex_enter(&ds->ds_prev->ds_lock); 188a4611edeSahrens ds->ds_prev->ds_phys->ds_unique_bytes += used; 189a4611edeSahrens mutex_exit(&ds->ds_prev->ds_lock); 190fa9e4066Sahrens } 19174e7dc98SMatthew Ahrens if (bp->blk_birth > ds->ds_origin_txg) { 19274e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used, 19374e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 19474e7dc98SMatthew Ahrens } 195fa9e4066Sahrens } 196fa9e4066Sahrens mutex_enter(&ds->ds_lock); 197fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 198fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 199fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 200fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 201fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 202fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 203fa9e4066Sahrens mutex_exit(&ds->ds_lock); 204cdb0ab79Smaybee 205cdb0ab79Smaybee return (used); 206fa9e4066Sahrens } 207fa9e4066Sahrens 208ea8dc4b6Seschrock uint64_t 209ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 210fa9e4066Sahrens { 211a2eea2e1Sahrens uint64_t trysnap = 0; 212a2eea2e1Sahrens 213fa9e4066Sahrens if (ds == NULL) 214ea8dc4b6Seschrock return (0); 215fa9e4066Sahrens /* 216fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 217fa9e4066Sahrens * incorrect FALSE return, which would only result in an 218fa9e4066Sahrens * overestimation of the amount of space that an operation would 219fa9e4066Sahrens * consume, which is OK. 220fa9e4066Sahrens * 221fa9e4066Sahrens * There's also a small window where we could miss a pending 222fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 223fa9e4066Sahrens * phase. So this should only be used as a guess. 224fa9e4066Sahrens */ 225a2eea2e1Sahrens if (ds->ds_trysnap_txg > 226a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 227a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 228a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 229ea8dc4b6Seschrock } 230ea8dc4b6Seschrock 2313d692628SSanjeev Bagewadi boolean_t 232ea8dc4b6Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 233ea8dc4b6Seschrock { 234ea8dc4b6Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 235fa9e4066Sahrens } 236fa9e4066Sahrens 237fa9e4066Sahrens /* ARGSUSED */ 238fa9e4066Sahrens static void 239fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 240fa9e4066Sahrens { 241fa9e4066Sahrens dsl_dataset_t *ds = dsv; 242fa9e4066Sahrens 243745cd3c5Smaybee ASSERT(ds->ds_owner == NULL || DSL_DATASET_IS_DESTROYED(ds)); 244fa9e4066Sahrens 24591ebeef5Sahrens unique_remove(ds->ds_fsid_guid); 246fa9e4066Sahrens 247503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) 248503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 249fa9e4066Sahrens 250fa9e4066Sahrens if (ds->ds_prev) { 251745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 252fa9e4066Sahrens ds->ds_prev = NULL; 253fa9e4066Sahrens } 254fa9e4066Sahrens 255fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 256745cd3c5Smaybee if (ds->ds_dir) 257745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 258fa9e4066Sahrens 25991ebeef5Sahrens ASSERT(!list_link_active(&ds->ds_synced_link)); 260fa9e4066Sahrens 2615ad82045Snd mutex_destroy(&ds->ds_lock); 262f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 26391ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 2645ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 265745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 266745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 2675ad82045Snd 268fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 269fa9e4066Sahrens } 270fa9e4066Sahrens 271ea8dc4b6Seschrock static int 272fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 273fa9e4066Sahrens { 274fa9e4066Sahrens dsl_dataset_phys_t *headphys; 275fa9e4066Sahrens int err; 276fa9e4066Sahrens dmu_buf_t *headdbuf; 277fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 278fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 279fa9e4066Sahrens 280fa9e4066Sahrens if (ds->ds_snapname[0]) 281ea8dc4b6Seschrock return (0); 282fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 283ea8dc4b6Seschrock return (0); 284fa9e4066Sahrens 285ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 286ea8dc4b6Seschrock FTAG, &headdbuf); 287ea8dc4b6Seschrock if (err) 288ea8dc4b6Seschrock return (err); 289fa9e4066Sahrens headphys = headdbuf->db_data; 290fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 291e7437265Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); 292ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 293ea8dc4b6Seschrock return (err); 294fa9e4066Sahrens } 295fa9e4066Sahrens 296ab04eb8eStimh static int 297745cd3c5Smaybee dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value) 298ab04eb8eStimh { 299745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 300745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 301ab04eb8eStimh matchtype_t mt; 302ab04eb8eStimh int err; 303ab04eb8eStimh 304745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 305ab04eb8eStimh mt = MT_FIRST; 306ab04eb8eStimh else 307ab04eb8eStimh mt = MT_EXACT; 308ab04eb8eStimh 309745cd3c5Smaybee err = zap_lookup_norm(mos, snapobj, name, 8, 1, 310ab04eb8eStimh value, mt, NULL, 0, NULL); 311ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 312745cd3c5Smaybee err = zap_lookup(mos, snapobj, name, 8, 1, value); 313ab04eb8eStimh return (err); 314ab04eb8eStimh } 315ab04eb8eStimh 316ab04eb8eStimh static int 317745cd3c5Smaybee dsl_dataset_snap_remove(dsl_dataset_t *ds, char *name, dmu_tx_t *tx) 318ab04eb8eStimh { 319745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 320745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 321ab04eb8eStimh matchtype_t mt; 322ab04eb8eStimh int err; 323ab04eb8eStimh 324*71eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 325*71eb0538SChris Kirby 326745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 327ab04eb8eStimh mt = MT_FIRST; 328ab04eb8eStimh else 329ab04eb8eStimh mt = MT_EXACT; 330ab04eb8eStimh 331745cd3c5Smaybee err = zap_remove_norm(mos, snapobj, name, mt, tx); 332ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 333745cd3c5Smaybee err = zap_remove(mos, snapobj, name, tx); 334ab04eb8eStimh return (err); 335ab04eb8eStimh } 336ab04eb8eStimh 337745cd3c5Smaybee static int 338745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag, 339745cd3c5Smaybee dsl_dataset_t **dsp) 340fa9e4066Sahrens { 341fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 342fa9e4066Sahrens dmu_buf_t *dbuf; 343fa9e4066Sahrens dsl_dataset_t *ds; 344ea8dc4b6Seschrock int err; 345fa9e4066Sahrens 346fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 347fa9e4066Sahrens dsl_pool_sync_context(dp)); 348fa9e4066Sahrens 349ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 350ea8dc4b6Seschrock if (err) 351ea8dc4b6Seschrock return (err); 352fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 353fa9e4066Sahrens if (ds == NULL) { 354fa9e4066Sahrens dsl_dataset_t *winner; 355fa9e4066Sahrens 356fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 357fa9e4066Sahrens ds->ds_dbuf = dbuf; 358fa9e4066Sahrens ds->ds_object = dsobj; 359fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 360fa9e4066Sahrens 3615ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 362f4b94bdeSMatthew Ahrens mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL); 36391ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 3645ad82045Snd mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT, 3655ad82045Snd NULL); 366745cd3c5Smaybee rw_init(&ds->ds_rwlock, 0, 0, 0); 367745cd3c5Smaybee cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL); 3685ad82045Snd 369ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 370fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 371ea8dc4b6Seschrock if (err == 0) { 372ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 373ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 374ea8dc4b6Seschrock } 375ea8dc4b6Seschrock if (err) { 376ea8dc4b6Seschrock /* 377ea8dc4b6Seschrock * we don't really need to close the blist if we 378ea8dc4b6Seschrock * just opened it. 379ea8dc4b6Seschrock */ 3805ad82045Snd mutex_destroy(&ds->ds_lock); 381f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 38291ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 3835ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 384745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 385745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 386ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 387ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 388ea8dc4b6Seschrock return (err); 389ea8dc4b6Seschrock } 390fa9e4066Sahrens 39174e7dc98SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 392fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 393fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 394745cd3c5Smaybee err = dsl_dataset_get_ref(dp, 395745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 396745cd3c5Smaybee ds, &ds->ds_prev); 397fa9e4066Sahrens } 39874e7dc98SMatthew Ahrens 39974e7dc98SMatthew Ahrens if (err == 0 && dsl_dir_is_clone(ds->ds_dir)) { 40074e7dc98SMatthew Ahrens dsl_dataset_t *origin; 40174e7dc98SMatthew Ahrens 40274e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, 40374e7dc98SMatthew Ahrens ds->ds_dir->dd_phys->dd_origin_obj, 40474e7dc98SMatthew Ahrens FTAG, &origin); 40574e7dc98SMatthew Ahrens if (err == 0) { 40674e7dc98SMatthew Ahrens ds->ds_origin_txg = 40774e7dc98SMatthew Ahrens origin->ds_phys->ds_creation_txg; 40874e7dc98SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 40974e7dc98SMatthew Ahrens } 41074e7dc98SMatthew Ahrens } 411842727c2SChris Kirby } else { 412842727c2SChris Kirby if (zfs_flags & ZFS_DEBUG_SNAPNAMES) 413842727c2SChris Kirby err = dsl_dataset_get_snapname(ds); 414842727c2SChris Kirby if (err == 0 && ds->ds_phys->ds_userrefs_obj != 0) { 415842727c2SChris Kirby err = zap_count( 416842727c2SChris Kirby ds->ds_dir->dd_pool->dp_meta_objset, 417842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj, 418842727c2SChris Kirby &ds->ds_userrefs); 419842727c2SChris Kirby } 420fa9e4066Sahrens } 421fa9e4066Sahrens 42274e7dc98SMatthew Ahrens if (err == 0 && !dsl_dataset_is_snapshot(ds)) { 42327345066Sck /* 42427345066Sck * In sync context, we're called with either no lock 42527345066Sck * or with the write lock. If we're not syncing, 42627345066Sck * we're always called with the read lock held. 42727345066Sck */ 428cb625fb5Sck boolean_t need_lock = 42927345066Sck !RW_WRITE_HELD(&dp->dp_config_rwlock) && 43027345066Sck dsl_pool_sync_context(dp); 431cb625fb5Sck 432cb625fb5Sck if (need_lock) 433cb625fb5Sck rw_enter(&dp->dp_config_rwlock, RW_READER); 434cb625fb5Sck 435bb0ade09Sahrens err = dsl_prop_get_ds(ds, 436cb625fb5Sck "refreservation", sizeof (uint64_t), 1, 437cb625fb5Sck &ds->ds_reserved, NULL); 438cb625fb5Sck if (err == 0) { 439bb0ade09Sahrens err = dsl_prop_get_ds(ds, 440cb625fb5Sck "refquota", sizeof (uint64_t), 1, 441cb625fb5Sck &ds->ds_quota, NULL); 442cb625fb5Sck } 443cb625fb5Sck 444cb625fb5Sck if (need_lock) 445cb625fb5Sck rw_exit(&dp->dp_config_rwlock); 446cb625fb5Sck } else { 447cb625fb5Sck ds->ds_reserved = ds->ds_quota = 0; 448cb625fb5Sck } 449cb625fb5Sck 450ea8dc4b6Seschrock if (err == 0) { 451ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 452ea8dc4b6Seschrock dsl_dataset_evict); 453ea8dc4b6Seschrock } 454ea8dc4b6Seschrock if (err || winner) { 455fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 456745cd3c5Smaybee if (ds->ds_prev) 457745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 458fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 4595ad82045Snd mutex_destroy(&ds->ds_lock); 460f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 46191ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 4625ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 463745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 464745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 465fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 466ea8dc4b6Seschrock if (err) { 467ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 468ea8dc4b6Seschrock return (err); 469ea8dc4b6Seschrock } 470fa9e4066Sahrens ds = winner; 471fa9e4066Sahrens } else { 47291ebeef5Sahrens ds->ds_fsid_guid = 473fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 474fa9e4066Sahrens } 475fa9e4066Sahrens } 476fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 477fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 478088f3894Sahrens ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 || 479afc6333aSahrens spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN || 48084db2a68Sahrens dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap); 481fa9e4066Sahrens mutex_enter(&ds->ds_lock); 482745cd3c5Smaybee if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) { 483fa9e4066Sahrens mutex_exit(&ds->ds_lock); 484745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 485745cd3c5Smaybee return (ENOENT); 486fa9e4066Sahrens } 487fa9e4066Sahrens mutex_exit(&ds->ds_lock); 488ea8dc4b6Seschrock *dsp = ds; 489ea8dc4b6Seschrock return (0); 490fa9e4066Sahrens } 491fa9e4066Sahrens 492745cd3c5Smaybee static int 493745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag) 494745cd3c5Smaybee { 495745cd3c5Smaybee dsl_pool_t *dp = ds->ds_dir->dd_pool; 496745cd3c5Smaybee 497745cd3c5Smaybee /* 498745cd3c5Smaybee * In syncing context we don't want the rwlock lock: there 499745cd3c5Smaybee * may be an existing writer waiting for sync phase to 500745cd3c5Smaybee * finish. We don't need to worry about such writers, since 501745cd3c5Smaybee * sync phase is single-threaded, so the writer can't be 502745cd3c5Smaybee * doing anything while we are active. 503745cd3c5Smaybee */ 504745cd3c5Smaybee if (dsl_pool_sync_context(dp)) { 505745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 506745cd3c5Smaybee return (0); 507745cd3c5Smaybee } 508745cd3c5Smaybee 509745cd3c5Smaybee /* 510745cd3c5Smaybee * Normal users will hold the ds_rwlock as a READER until they 511745cd3c5Smaybee * are finished (i.e., call dsl_dataset_rele()). "Owners" will 512745cd3c5Smaybee * drop their READER lock after they set the ds_owner field. 513745cd3c5Smaybee * 514745cd3c5Smaybee * If the dataset is being destroyed, the destroy thread will 515745cd3c5Smaybee * obtain a WRITER lock for exclusive access after it's done its 516745cd3c5Smaybee * open-context work and then change the ds_owner to 517745cd3c5Smaybee * dsl_reaper once destruction is assured. So threads 518745cd3c5Smaybee * may block here temporarily, until the "destructability" of 519745cd3c5Smaybee * the dataset is determined. 520745cd3c5Smaybee */ 521745cd3c5Smaybee ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock)); 522745cd3c5Smaybee mutex_enter(&ds->ds_lock); 523745cd3c5Smaybee while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) { 524745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 525745cd3c5Smaybee cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock); 526745cd3c5Smaybee if (DSL_DATASET_IS_DESTROYED(ds)) { 527745cd3c5Smaybee mutex_exit(&ds->ds_lock); 528745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 529745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 530745cd3c5Smaybee return (ENOENT); 531745cd3c5Smaybee } 532745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 533745cd3c5Smaybee } 534745cd3c5Smaybee mutex_exit(&ds->ds_lock); 535745cd3c5Smaybee return (0); 536745cd3c5Smaybee } 537745cd3c5Smaybee 538745cd3c5Smaybee int 539745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, 540745cd3c5Smaybee dsl_dataset_t **dsp) 541745cd3c5Smaybee { 542745cd3c5Smaybee int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp); 543745cd3c5Smaybee 544745cd3c5Smaybee if (err) 545745cd3c5Smaybee return (err); 546745cd3c5Smaybee return (dsl_dataset_hold_ref(*dsp, tag)); 547745cd3c5Smaybee } 548745cd3c5Smaybee 549745cd3c5Smaybee int 550503ad85cSMatthew Ahrens dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, boolean_t inconsistentok, 551503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 552745cd3c5Smaybee { 553503ad85cSMatthew Ahrens int err = dsl_dataset_hold_obj(dp, dsobj, tag, dsp); 554745cd3c5Smaybee if (err) 555745cd3c5Smaybee return (err); 556503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 557503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 5584f5064b7SMark J Musante *dsp = NULL; 559745cd3c5Smaybee return (EBUSY); 560745cd3c5Smaybee } 561745cd3c5Smaybee return (0); 562745cd3c5Smaybee } 563745cd3c5Smaybee 564fa9e4066Sahrens int 565745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp) 566fa9e4066Sahrens { 567fa9e4066Sahrens dsl_dir_t *dd; 568fa9e4066Sahrens dsl_pool_t *dp; 569745cd3c5Smaybee const char *snapname; 570fa9e4066Sahrens uint64_t obj; 571fa9e4066Sahrens int err = 0; 572fa9e4066Sahrens 573745cd3c5Smaybee err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname); 574ea8dc4b6Seschrock if (err) 575ea8dc4b6Seschrock return (err); 576fa9e4066Sahrens 577fa9e4066Sahrens dp = dd->dd_pool; 578fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 579fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 580745cd3c5Smaybee if (obj) 581745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, dsp); 582745cd3c5Smaybee else 583fa9e4066Sahrens err = ENOENT; 584745cd3c5Smaybee if (err) 585fa9e4066Sahrens goto out; 586fa9e4066Sahrens 587745cd3c5Smaybee err = dsl_dataset_hold_ref(*dsp, tag); 588fa9e4066Sahrens 589745cd3c5Smaybee /* we may be looking for a snapshot */ 590745cd3c5Smaybee if (err == 0 && snapname != NULL) { 591745cd3c5Smaybee dsl_dataset_t *ds = NULL; 592fa9e4066Sahrens 593745cd3c5Smaybee if (*snapname++ != '@') { 594745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 595fa9e4066Sahrens err = ENOENT; 596fa9e4066Sahrens goto out; 597fa9e4066Sahrens } 598fa9e4066Sahrens 599745cd3c5Smaybee dprintf("looking for snapshot '%s'\n", snapname); 600745cd3c5Smaybee err = dsl_dataset_snap_lookup(*dsp, snapname, &obj); 601745cd3c5Smaybee if (err == 0) 602745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, &ds); 603745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 604745cd3c5Smaybee 605745cd3c5Smaybee ASSERT3U((err == 0), ==, (ds != NULL)); 606745cd3c5Smaybee 607745cd3c5Smaybee if (ds) { 608745cd3c5Smaybee mutex_enter(&ds->ds_lock); 609745cd3c5Smaybee if (ds->ds_snapname[0] == 0) 610745cd3c5Smaybee (void) strlcpy(ds->ds_snapname, snapname, 611745cd3c5Smaybee sizeof (ds->ds_snapname)); 612745cd3c5Smaybee mutex_exit(&ds->ds_lock); 613745cd3c5Smaybee err = dsl_dataset_hold_ref(ds, tag); 614745cd3c5Smaybee *dsp = err ? NULL : ds; 615fa9e4066Sahrens } 616fa9e4066Sahrens } 617fa9e4066Sahrens out: 618fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 619fa9e4066Sahrens dsl_dir_close(dd, FTAG); 620fa9e4066Sahrens return (err); 621fa9e4066Sahrens } 622fa9e4066Sahrens 623fa9e4066Sahrens int 624503ad85cSMatthew Ahrens dsl_dataset_own(const char *name, boolean_t inconsistentok, 625503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 626fa9e4066Sahrens { 627503ad85cSMatthew Ahrens int err = dsl_dataset_hold(name, tag, dsp); 628745cd3c5Smaybee if (err) 629745cd3c5Smaybee return (err); 630503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 631503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 632745cd3c5Smaybee return (EBUSY); 633745cd3c5Smaybee } 634745cd3c5Smaybee return (0); 635fa9e4066Sahrens } 636fa9e4066Sahrens 637fa9e4066Sahrens void 638fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 639fa9e4066Sahrens { 640fa9e4066Sahrens if (ds == NULL) { 641fa9e4066Sahrens (void) strcpy(name, "mos"); 642fa9e4066Sahrens } else { 643fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 644ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 645fa9e4066Sahrens if (ds->ds_snapname[0]) { 646fa9e4066Sahrens (void) strcat(name, "@"); 647745cd3c5Smaybee /* 648745cd3c5Smaybee * We use a "recursive" mutex so that we 649745cd3c5Smaybee * can call dprintf_ds() with ds_lock held. 650745cd3c5Smaybee */ 651fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 652fa9e4066Sahrens mutex_enter(&ds->ds_lock); 653fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 654fa9e4066Sahrens mutex_exit(&ds->ds_lock); 655fa9e4066Sahrens } else { 656fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 657fa9e4066Sahrens } 658fa9e4066Sahrens } 659fa9e4066Sahrens } 660fa9e4066Sahrens } 661fa9e4066Sahrens 662b7661cccSmmusante static int 663b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 664b7661cccSmmusante { 665b7661cccSmmusante int result; 666b7661cccSmmusante 667b7661cccSmmusante if (ds == NULL) { 668b7661cccSmmusante result = 3; /* "mos" */ 669b7661cccSmmusante } else { 670b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 671b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 672b7661cccSmmusante if (ds->ds_snapname[0]) { 673b7661cccSmmusante ++result; /* adding one for the @-sign */ 674b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 675b7661cccSmmusante mutex_enter(&ds->ds_lock); 676b7661cccSmmusante result += strlen(ds->ds_snapname); 677b7661cccSmmusante mutex_exit(&ds->ds_lock); 678b7661cccSmmusante } else { 679b7661cccSmmusante result += strlen(ds->ds_snapname); 680b7661cccSmmusante } 681b7661cccSmmusante } 682b7661cccSmmusante } 683b7661cccSmmusante 684b7661cccSmmusante return (result); 685b7661cccSmmusante } 686b7661cccSmmusante 687088f3894Sahrens void 688745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag) 689fa9e4066Sahrens { 690ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 691fa9e4066Sahrens } 692fa9e4066Sahrens 6933cb34c60Sahrens void 694745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag) 6953cb34c60Sahrens { 696745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) { 697745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 698745cd3c5Smaybee } 699745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 700745cd3c5Smaybee } 701745cd3c5Smaybee 702745cd3c5Smaybee void 703503ad85cSMatthew Ahrens dsl_dataset_disown(dsl_dataset_t *ds, void *tag) 704745cd3c5Smaybee { 705503ad85cSMatthew Ahrens ASSERT((ds->ds_owner == tag && ds->ds_dbuf) || 706745cd3c5Smaybee (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL)); 707745cd3c5Smaybee 7083cb34c60Sahrens mutex_enter(&ds->ds_lock); 709745cd3c5Smaybee ds->ds_owner = NULL; 710745cd3c5Smaybee if (RW_WRITE_HELD(&ds->ds_rwlock)) { 711745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 712745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 713745cd3c5Smaybee } 7143cb34c60Sahrens mutex_exit(&ds->ds_lock); 715745cd3c5Smaybee if (ds->ds_dbuf) 716503ad85cSMatthew Ahrens dsl_dataset_drop_ref(ds, tag); 717745cd3c5Smaybee else 718745cd3c5Smaybee dsl_dataset_evict(ds->ds_dbuf, ds); 7193cb34c60Sahrens } 7203cb34c60Sahrens 7213cb34c60Sahrens boolean_t 722503ad85cSMatthew Ahrens dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *tag) 7233cb34c60Sahrens { 724745cd3c5Smaybee boolean_t gotit = FALSE; 725745cd3c5Smaybee 7263cb34c60Sahrens mutex_enter(&ds->ds_lock); 727745cd3c5Smaybee if (ds->ds_owner == NULL && 728745cd3c5Smaybee (!DS_IS_INCONSISTENT(ds) || inconsistentok)) { 729503ad85cSMatthew Ahrens ds->ds_owner = tag; 730745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) 731745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 732745cd3c5Smaybee gotit = TRUE; 7333cb34c60Sahrens } 7343cb34c60Sahrens mutex_exit(&ds->ds_lock); 735745cd3c5Smaybee return (gotit); 736745cd3c5Smaybee } 737745cd3c5Smaybee 738745cd3c5Smaybee void 739745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner) 740745cd3c5Smaybee { 741745cd3c5Smaybee ASSERT3P(owner, ==, ds->ds_owner); 742745cd3c5Smaybee if (!RW_WRITE_HELD(&ds->ds_rwlock)) 743745cd3c5Smaybee rw_enter(&ds->ds_rwlock, RW_WRITER); 7443cb34c60Sahrens } 7453cb34c60Sahrens 7461d452cf5Sahrens uint64_t 747088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 748ab04eb8eStimh uint64_t flags, dmu_tx_t *tx) 749fa9e4066Sahrens { 7503cb34c60Sahrens dsl_pool_t *dp = dd->dd_pool; 751fa9e4066Sahrens dmu_buf_t *dbuf; 752fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 7533cb34c60Sahrens uint64_t dsobj; 754fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 755fa9e4066Sahrens 756088f3894Sahrens if (origin == NULL) 757088f3894Sahrens origin = dp->dp_origin_snap; 758088f3894Sahrens 7593cb34c60Sahrens ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp); 7603cb34c60Sahrens ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0); 761fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 7623cb34c60Sahrens ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); 763fa9e4066Sahrens 7641649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 7651649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 766ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 767fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 768fa9e4066Sahrens dsphys = dbuf->db_data; 769745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 770fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 771ab04eb8eStimh dsphys->ds_flags = flags; 772fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 773fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 774fa9e4066Sahrens sizeof (dsphys->ds_guid)); 775fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 776ab04eb8eStimh zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP, 777ab04eb8eStimh DMU_OT_NONE, 0, tx); 778fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 779088f3894Sahrens dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg; 780fa9e4066Sahrens dsphys->ds_deadlist_obj = 781fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 782a9799022Sck 7833cb34c60Sahrens if (origin) { 7843cb34c60Sahrens dsphys->ds_prev_snap_obj = origin->ds_object; 785fa9e4066Sahrens dsphys->ds_prev_snap_txg = 7863cb34c60Sahrens origin->ds_phys->ds_creation_txg; 787fa9e4066Sahrens dsphys->ds_used_bytes = 7883cb34c60Sahrens origin->ds_phys->ds_used_bytes; 789fa9e4066Sahrens dsphys->ds_compressed_bytes = 7903cb34c60Sahrens origin->ds_phys->ds_compressed_bytes; 791fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 7923cb34c60Sahrens origin->ds_phys->ds_uncompressed_bytes; 7933cb34c60Sahrens dsphys->ds_bp = origin->ds_phys->ds_bp; 794579ae4d5Stimh dsphys->ds_flags |= origin->ds_phys->ds_flags; 795fa9e4066Sahrens 7963cb34c60Sahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 7973cb34c60Sahrens origin->ds_phys->ds_num_children++; 798fa9e4066Sahrens 799088f3894Sahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) { 800088f3894Sahrens if (origin->ds_phys->ds_next_clones_obj == 0) { 801088f3894Sahrens origin->ds_phys->ds_next_clones_obj = 802088f3894Sahrens zap_create(mos, 803088f3894Sahrens DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx); 804088f3894Sahrens } 805088f3894Sahrens VERIFY(0 == zap_add_int(mos, 806088f3894Sahrens origin->ds_phys->ds_next_clones_obj, 807088f3894Sahrens dsobj, tx)); 808088f3894Sahrens } 809088f3894Sahrens 810fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 8113cb34c60Sahrens dd->dd_phys->dd_origin_obj = origin->ds_object; 812fa9e4066Sahrens } 813ab04eb8eStimh 814ab04eb8eStimh if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 815ab04eb8eStimh dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 816ab04eb8eStimh 817ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 818fa9e4066Sahrens 819fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 820fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 8213cb34c60Sahrens 8223cb34c60Sahrens return (dsobj); 8233cb34c60Sahrens } 8243cb34c60Sahrens 8253cb34c60Sahrens uint64_t 826ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname, 827ab04eb8eStimh dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx) 8283cb34c60Sahrens { 8293cb34c60Sahrens dsl_pool_t *dp = pdd->dd_pool; 8303cb34c60Sahrens uint64_t dsobj, ddobj; 8313cb34c60Sahrens dsl_dir_t *dd; 8323cb34c60Sahrens 8333cb34c60Sahrens ASSERT(lastname[0] != '@'); 8343cb34c60Sahrens 835088f3894Sahrens ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx); 8363cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 8373cb34c60Sahrens 838088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx); 8393cb34c60Sahrens 8403cb34c60Sahrens dsl_deleg_set_create_perms(dd, tx, cr); 8413cb34c60Sahrens 842fa9e4066Sahrens dsl_dir_close(dd, FTAG); 843fa9e4066Sahrens 8441d452cf5Sahrens return (dsobj); 845fa9e4066Sahrens } 846fa9e4066Sahrens 8471d452cf5Sahrens struct destroyarg { 8481d452cf5Sahrens dsl_sync_task_group_t *dstg; 8491d452cf5Sahrens char *snapname; 8501d452cf5Sahrens char *failed; 851842727c2SChris Kirby boolean_t defer; 8521d452cf5Sahrens }; 8531d452cf5Sahrens 8541d452cf5Sahrens static int 8551d452cf5Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 856fa9e4066Sahrens { 8571d452cf5Sahrens struct destroyarg *da = arg; 8581d452cf5Sahrens dsl_dataset_t *ds; 859fa9e4066Sahrens int err; 860842727c2SChris Kirby char *dsname; 861842727c2SChris Kirby 862ae46e4c7SMatthew Ahrens dsname = kmem_asprintf("%s@%s", name, da->snapname); 863503ad85cSMatthew Ahrens err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds); 864ae46e4c7SMatthew Ahrens strfree(dsname); 865745cd3c5Smaybee if (err == 0) { 866842727c2SChris Kirby struct dsl_ds_destroyarg *dsda; 867842727c2SChris Kirby 868745cd3c5Smaybee dsl_dataset_make_exclusive(ds, da->dstg); 869503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) { 870503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 871503ad85cSMatthew Ahrens ds->ds_objset = NULL; 8723baa08fcSek } 873842727c2SChris Kirby dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP); 874842727c2SChris Kirby dsda->ds = ds; 875842727c2SChris Kirby dsda->defer = da->defer; 876745cd3c5Smaybee dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 877842727c2SChris Kirby dsl_dataset_destroy_sync, dsda, da->dstg, 0); 878745cd3c5Smaybee } else if (err == ENOENT) { 879745cd3c5Smaybee err = 0; 880745cd3c5Smaybee } else { 8811d452cf5Sahrens (void) strcpy(da->failed, name); 8821d452cf5Sahrens } 883745cd3c5Smaybee return (err); 8841d452cf5Sahrens } 88531fd60d3Sahrens 8861d452cf5Sahrens /* 8871d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 8881d452cf5Sahrens */ 8891d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 8901d452cf5Sahrens int 891842727c2SChris Kirby dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer) 8921d452cf5Sahrens { 8931d452cf5Sahrens int err; 8941d452cf5Sahrens struct destroyarg da; 8951d452cf5Sahrens dsl_sync_task_t *dst; 8961d452cf5Sahrens spa_t *spa; 8971d452cf5Sahrens 89840feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 8991d452cf5Sahrens if (err) 9001d452cf5Sahrens return (err); 9011d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 9021d452cf5Sahrens da.snapname = snapname; 9031d452cf5Sahrens da.failed = fsname; 904842727c2SChris Kirby da.defer = defer; 9051d452cf5Sahrens 9061d452cf5Sahrens err = dmu_objset_find(fsname, 9070b69c2f0Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 9081d452cf5Sahrens 9091d452cf5Sahrens if (err == 0) 9101d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 9111d452cf5Sahrens 9121d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 9131d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 914842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 915842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 916842727c2SChris Kirby 917745cd3c5Smaybee /* 918745cd3c5Smaybee * Return the file system name that triggered the error 919745cd3c5Smaybee */ 9201d452cf5Sahrens if (dst->dst_err) { 9211d452cf5Sahrens dsl_dataset_name(ds, fsname); 92240feaa91Sahrens *strchr(fsname, '@') = '\0'; 923e1930233Sbonwick } 924842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 925745cd3c5Smaybee dsl_dataset_disown(ds, da.dstg); 926842727c2SChris Kirby kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 927fa9e4066Sahrens } 928fa9e4066Sahrens 9291d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 9301d452cf5Sahrens spa_close(spa, FTAG); 931fa9e4066Sahrens return (err); 932fa9e4066Sahrens } 933fa9e4066Sahrens 934842727c2SChris Kirby static boolean_t 935842727c2SChris Kirby dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 936842727c2SChris Kirby { 937842727c2SChris Kirby boolean_t might_destroy = B_FALSE; 938842727c2SChris Kirby 939842727c2SChris Kirby mutex_enter(&ds->ds_lock); 940842727c2SChris Kirby if (ds->ds_phys->ds_num_children == 2 && ds->ds_userrefs == 0 && 941842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 942842727c2SChris Kirby might_destroy = B_TRUE; 943842727c2SChris Kirby mutex_exit(&ds->ds_lock); 944842727c2SChris Kirby 945842727c2SChris Kirby return (might_destroy); 946842727c2SChris Kirby } 947842727c2SChris Kirby 948842727c2SChris Kirby #ifdef _KERNEL 949842727c2SChris Kirby static int 950842727c2SChris Kirby dsl_dataset_zvol_cleanup(dsl_dataset_t *ds, const char *name) 951842727c2SChris Kirby { 952842727c2SChris Kirby int error; 953842727c2SChris Kirby objset_t *os; 954842727c2SChris Kirby 955503ad85cSMatthew Ahrens error = dmu_objset_from_ds(ds, &os); 956842727c2SChris Kirby if (error) 957842727c2SChris Kirby return (error); 958842727c2SChris Kirby 959842727c2SChris Kirby if (dmu_objset_type(os) == DMU_OST_ZVOL) 960842727c2SChris Kirby error = zvol_remove_minor(name); 961842727c2SChris Kirby 962842727c2SChris Kirby return (error); 963842727c2SChris Kirby } 964842727c2SChris Kirby #endif 965842727c2SChris Kirby 966842727c2SChris Kirby /* 967842727c2SChris Kirby * If we're removing a clone, and these three conditions are true: 968842727c2SChris Kirby * 1) the clone's origin has no other children 969842727c2SChris Kirby * 2) the clone's origin has no user references 970842727c2SChris Kirby * 3) the clone's origin has been marked for deferred destruction 971842727c2SChris Kirby * Then, prepare to remove the origin as part of this sync task group. 972842727c2SChris Kirby */ 973842727c2SChris Kirby static int 974842727c2SChris Kirby dsl_dataset_origin_rm_prep(struct dsl_ds_destroyarg *dsda, void *tag) 975842727c2SChris Kirby { 976842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 977842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 978842727c2SChris Kirby 979842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(origin)) { 980842727c2SChris Kirby char *name; 981842727c2SChris Kirby int namelen; 982842727c2SChris Kirby int error; 983842727c2SChris Kirby 984842727c2SChris Kirby namelen = dsl_dataset_namelen(origin) + 1; 985842727c2SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 986842727c2SChris Kirby dsl_dataset_name(origin, name); 987842727c2SChris Kirby #ifdef _KERNEL 988842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 989842727c2SChris Kirby if (error) { 990842727c2SChris Kirby kmem_free(name, namelen); 991842727c2SChris Kirby return (error); 992842727c2SChris Kirby } 993842727c2SChris Kirby error = dsl_dataset_zvol_cleanup(origin, name); 994842727c2SChris Kirby if (error) { 995842727c2SChris Kirby kmem_free(name, namelen); 996842727c2SChris Kirby return (error); 997842727c2SChris Kirby } 998842727c2SChris Kirby #endif 999503ad85cSMatthew Ahrens error = dsl_dataset_own(name, B_TRUE, tag, &origin); 1000842727c2SChris Kirby kmem_free(name, namelen); 1001842727c2SChris Kirby if (error) 1002842727c2SChris Kirby return (error); 1003842727c2SChris Kirby dsda->rm_origin = origin; 1004842727c2SChris Kirby dsl_dataset_make_exclusive(origin, tag); 1005ca45db41SChris Kirby 1006ca45db41SChris Kirby if (origin->ds_objset != NULL) { 1007ca45db41SChris Kirby dmu_objset_evict(origin->ds_objset); 1008ca45db41SChris Kirby origin->ds_objset = NULL; 1009ca45db41SChris Kirby } 1010842727c2SChris Kirby } 1011842727c2SChris Kirby 1012842727c2SChris Kirby return (0); 1013842727c2SChris Kirby } 1014842727c2SChris Kirby 10153cb34c60Sahrens /* 1016745cd3c5Smaybee * ds must be opened as OWNER. On return (whether successful or not), 1017745cd3c5Smaybee * ds will be closed and caller can no longer dereference it. 10183cb34c60Sahrens */ 1019fa9e4066Sahrens int 1020842727c2SChris Kirby dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) 1021fa9e4066Sahrens { 1022fa9e4066Sahrens int err; 10231d452cf5Sahrens dsl_sync_task_group_t *dstg; 10241d452cf5Sahrens objset_t *os; 1025fa9e4066Sahrens dsl_dir_t *dd; 10261d452cf5Sahrens uint64_t obj; 1027842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 1028842727c2SChris Kirby 1029842727c2SChris Kirby dsda.ds = ds; 10301d452cf5Sahrens 10313cb34c60Sahrens if (dsl_dataset_is_snapshot(ds)) { 10321d452cf5Sahrens /* Destroying a snapshot is simpler */ 1033745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 10343baa08fcSek 1035503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) { 1036503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 1037503ad85cSMatthew Ahrens ds->ds_objset = NULL; 10383baa08fcSek } 1039842727c2SChris Kirby /* NOTE: defer is always B_FALSE for non-snapshots */ 1040842727c2SChris Kirby dsda.defer = defer; 10411d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 10421d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 1043842727c2SChris Kirby &dsda, tag, 0); 1044842727c2SChris Kirby ASSERT3P(dsda.rm_origin, ==, NULL); 10453cb34c60Sahrens goto out; 10461d452cf5Sahrens } 1047fa9e4066Sahrens 10481d452cf5Sahrens dd = ds->ds_dir; 1049fa9e4066Sahrens 10501d452cf5Sahrens /* 10511d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 10521d452cf5Sahrens * case we crash while freeing the objects. 10531d452cf5Sahrens */ 10541d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 10551d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 10563cb34c60Sahrens if (err) 10573cb34c60Sahrens goto out; 10583cb34c60Sahrens 1059503ad85cSMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 10603cb34c60Sahrens if (err) 10613cb34c60Sahrens goto out; 1062fa9e4066Sahrens 10631d452cf5Sahrens /* 10641d452cf5Sahrens * remove the objects in open context, so that we won't 10651d452cf5Sahrens * have too much to do in syncing context. 10661d452cf5Sahrens */ 10676754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 10686754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 1069cdb0ab79Smaybee /* 1070cdb0ab79Smaybee * Ignore errors, if there is not enough disk space 1071cdb0ab79Smaybee * we will deal with it in dsl_dataset_destroy_sync(). 1072cdb0ab79Smaybee */ 1073cdb0ab79Smaybee (void) dmu_free_object(os, obj); 10741d452cf5Sahrens } 10751d452cf5Sahrens 107614843421SMatthew Ahrens /* 107714843421SMatthew Ahrens * We need to sync out all in-flight IO before we try to evict 107814843421SMatthew Ahrens * (the dataset evict func is trying to clear the cached entries 107914843421SMatthew Ahrens * for this dataset in the ARC). 108014843421SMatthew Ahrens */ 108114843421SMatthew Ahrens txg_wait_synced(dd->dd_pool, 0); 108214843421SMatthew Ahrens 108314843421SMatthew Ahrens /* 108414843421SMatthew Ahrens * If we managed to free all the objects in open 108514843421SMatthew Ahrens * context, the user space accounting should be zero. 108614843421SMatthew Ahrens */ 108714843421SMatthew Ahrens if (ds->ds_phys->ds_bp.blk_fill == 0 && 1088503ad85cSMatthew Ahrens dmu_objset_userused_enabled(os)) { 108914843421SMatthew Ahrens uint64_t count; 109014843421SMatthew Ahrens 109114843421SMatthew Ahrens ASSERT(zap_count(os, DMU_USERUSED_OBJECT, &count) != 0 || 109214843421SMatthew Ahrens count == 0); 109314843421SMatthew Ahrens ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, &count) != 0 || 109414843421SMatthew Ahrens count == 0); 109514843421SMatthew Ahrens } 109614843421SMatthew Ahrens 10971d452cf5Sahrens if (err != ESRCH) 10983cb34c60Sahrens goto out; 10991d452cf5Sahrens 110068038c2cSmaybee rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 110168038c2cSmaybee err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd); 110268038c2cSmaybee rw_exit(&dd->dd_pool->dp_config_rwlock); 110368038c2cSmaybee 110468038c2cSmaybee if (err) 110568038c2cSmaybee goto out; 110668038c2cSmaybee 1107503ad85cSMatthew Ahrens if (ds->ds_objset) { 1108745cd3c5Smaybee /* 1109745cd3c5Smaybee * We need to sync out all in-flight IO before we try 1110745cd3c5Smaybee * to evict (the dataset evict func is trying to clear 1111745cd3c5Smaybee * the cached entries for this dataset in the ARC). 1112745cd3c5Smaybee */ 1113745cd3c5Smaybee txg_wait_synced(dd->dd_pool, 0); 11141d452cf5Sahrens } 11151d452cf5Sahrens 11161d452cf5Sahrens /* 11171d452cf5Sahrens * Blow away the dsl_dir + head dataset. 11181d452cf5Sahrens */ 1119745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 1120503ad85cSMatthew Ahrens if (ds->ds_objset) { 1121503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 1122503ad85cSMatthew Ahrens ds->ds_objset = NULL; 112368038c2cSmaybee } 1124842727c2SChris Kirby 1125842727c2SChris Kirby /* 1126842727c2SChris Kirby * If we're removing a clone, we might also need to remove its 1127842727c2SChris Kirby * origin. 1128842727c2SChris Kirby */ 1129842727c2SChris Kirby do { 1130842727c2SChris Kirby dsda.need_prep = B_FALSE; 1131842727c2SChris Kirby if (dsl_dir_is_clone(dd)) { 1132842727c2SChris Kirby err = dsl_dataset_origin_rm_prep(&dsda, tag); 1133842727c2SChris Kirby if (err) { 1134842727c2SChris Kirby dsl_dir_close(dd, FTAG); 1135842727c2SChris Kirby goto out; 1136842727c2SChris Kirby } 1137842727c2SChris Kirby } 1138842727c2SChris Kirby 1139842727c2SChris Kirby dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 1140842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 1141842727c2SChris Kirby dsl_dataset_destroy_sync, &dsda, tag, 0); 1142842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dir_destroy_check, 1143842727c2SChris Kirby dsl_dir_destroy_sync, dd, FTAG, 0); 1144842727c2SChris Kirby err = dsl_sync_task_group_wait(dstg); 1145842727c2SChris Kirby dsl_sync_task_group_destroy(dstg); 1146842727c2SChris Kirby 1147842727c2SChris Kirby /* 1148842727c2SChris Kirby * We could be racing against 'zfs release' or 'zfs destroy -d' 1149842727c2SChris Kirby * on the origin snap, in which case we can get EBUSY if we 1150842727c2SChris Kirby * needed to destroy the origin snap but were not ready to 1151842727c2SChris Kirby * do so. 1152842727c2SChris Kirby */ 1153842727c2SChris Kirby if (dsda.need_prep) { 1154842727c2SChris Kirby ASSERT(err == EBUSY); 1155842727c2SChris Kirby ASSERT(dsl_dir_is_clone(dd)); 1156842727c2SChris Kirby ASSERT(dsda.rm_origin == NULL); 1157842727c2SChris Kirby } 1158842727c2SChris Kirby } while (dsda.need_prep); 1159842727c2SChris Kirby 1160842727c2SChris Kirby if (dsda.rm_origin != NULL) 1161842727c2SChris Kirby dsl_dataset_disown(dsda.rm_origin, tag); 1162842727c2SChris Kirby 1163745cd3c5Smaybee /* if it is successful, dsl_dir_destroy_sync will close the dd */ 11643cb34c60Sahrens if (err) 11651d452cf5Sahrens dsl_dir_close(dd, FTAG); 11663cb34c60Sahrens out: 1167745cd3c5Smaybee dsl_dataset_disown(ds, tag); 1168fa9e4066Sahrens return (err); 1169fa9e4066Sahrens } 1170fa9e4066Sahrens 1171c717a561Smaybee blkptr_t * 1172c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 1173fa9e4066Sahrens { 1174c717a561Smaybee return (&ds->ds_phys->ds_bp); 1175fa9e4066Sahrens } 1176fa9e4066Sahrens 1177fa9e4066Sahrens void 1178fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 1179fa9e4066Sahrens { 1180fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1181fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 1182fa9e4066Sahrens if (ds == NULL) { 1183fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 1184fa9e4066Sahrens } else { 1185fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1186fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 1187fa9e4066Sahrens } 1188fa9e4066Sahrens } 1189fa9e4066Sahrens 1190fa9e4066Sahrens spa_t * 1191fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 1192fa9e4066Sahrens { 1193fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 1194fa9e4066Sahrens } 1195fa9e4066Sahrens 1196fa9e4066Sahrens void 1197fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 1198fa9e4066Sahrens { 1199fa9e4066Sahrens dsl_pool_t *dp; 1200fa9e4066Sahrens 1201fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 1202fa9e4066Sahrens return; 1203fa9e4066Sahrens 1204503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1205a2eea2e1Sahrens 1206a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1207a2eea2e1Sahrens panic("dirtying snapshot!"); 1208fa9e4066Sahrens 1209fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 1210fa9e4066Sahrens 1211fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 1212fa9e4066Sahrens /* up the hold count until we can be written out */ 1213fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 1214fa9e4066Sahrens } 1215fa9e4066Sahrens } 1216fa9e4066Sahrens 1217a9799022Sck /* 1218a9799022Sck * The unique space in the head dataset can be calculated by subtracting 1219a9799022Sck * the space used in the most recent snapshot, that is still being used 1220a9799022Sck * in this file system, from the space currently in use. To figure out 1221a9799022Sck * the space in the most recent snapshot still in use, we need to take 1222a9799022Sck * the total space used in the snapshot and subtract out the space that 1223a9799022Sck * has been freed up since the snapshot was taken. 1224a9799022Sck */ 1225a9799022Sck static void 1226a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds) 1227a9799022Sck { 1228a9799022Sck uint64_t mrs_used; 1229a9799022Sck uint64_t dlused, dlcomp, dluncomp; 1230a9799022Sck 1231a9799022Sck ASSERT(ds->ds_object == ds->ds_dir->dd_phys->dd_head_dataset_obj); 1232a9799022Sck 1233a9799022Sck if (ds->ds_phys->ds_prev_snap_obj != 0) 1234a9799022Sck mrs_used = ds->ds_prev->ds_phys->ds_used_bytes; 1235a9799022Sck else 1236a9799022Sck mrs_used = 0; 1237a9799022Sck 1238a9799022Sck VERIFY(0 == bplist_space(&ds->ds_deadlist, &dlused, &dlcomp, 1239a9799022Sck &dluncomp)); 1240a9799022Sck 1241a9799022Sck ASSERT3U(dlused, <=, mrs_used); 1242a9799022Sck ds->ds_phys->ds_unique_bytes = 1243a9799022Sck ds->ds_phys->ds_used_bytes - (mrs_used - dlused); 1244a9799022Sck 1245a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && 1246a9799022Sck spa_version(ds->ds_dir->dd_pool->dp_spa) >= 1247a9799022Sck SPA_VERSION_UNIQUE_ACCURATE) 1248a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1249a9799022Sck } 1250a9799022Sck 1251a9799022Sck static uint64_t 1252a9799022Sck dsl_dataset_unique(dsl_dataset_t *ds) 1253a9799022Sck { 1254a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && !dsl_dataset_is_snapshot(ds)) 1255a9799022Sck dsl_dataset_recalc_head_uniq(ds); 1256a9799022Sck 1257a9799022Sck return (ds->ds_phys->ds_unique_bytes); 1258a9799022Sck } 1259a9799022Sck 1260fa9e4066Sahrens struct killarg { 126174e7dc98SMatthew Ahrens dsl_dataset_t *ds; 1262fa9e4066Sahrens zio_t *zio; 1263fa9e4066Sahrens dmu_tx_t *tx; 1264fa9e4066Sahrens }; 1265fa9e4066Sahrens 126674e7dc98SMatthew Ahrens /* ARGSUSED */ 1267fa9e4066Sahrens static int 126888b7b0f2SMatthew Ahrens kill_blkptr(spa_t *spa, blkptr_t *bp, const zbookmark_t *zb, 126988b7b0f2SMatthew Ahrens const dnode_phys_t *dnp, void *arg) 1270fa9e4066Sahrens { 1271fa9e4066Sahrens struct killarg *ka = arg; 1272fa9e4066Sahrens 127388b7b0f2SMatthew Ahrens if (bp == NULL) 127488b7b0f2SMatthew Ahrens return (0); 1275fa9e4066Sahrens 1276ab69d62fSMatthew Ahrens if ((zb->zb_level == -1ULL && zb->zb_blkid != 0) || 1277ab69d62fSMatthew Ahrens (zb->zb_object != 0 && dnp == NULL)) { 1278ab69d62fSMatthew Ahrens /* 1279ab69d62fSMatthew Ahrens * It's a block in the intent log. It has no 1280ab69d62fSMatthew Ahrens * accounting, so just free it. 1281ab69d62fSMatthew Ahrens */ 1282ab69d62fSMatthew Ahrens VERIFY3U(0, ==, dsl_free(ka->zio, ka->tx->tx_pool, 1283ab69d62fSMatthew Ahrens ka->tx->tx_txg, bp, NULL, NULL, ARC_NOWAIT)); 1284ab69d62fSMatthew Ahrens } else { 1285ab69d62fSMatthew Ahrens ASSERT3U(bp->blk_birth, >, ka->ds->ds_phys->ds_prev_snap_txg); 1286ab69d62fSMatthew Ahrens (void) dsl_dataset_block_kill(ka->ds, bp, ka->zio, ka->tx); 1287ab69d62fSMatthew Ahrens } 128874e7dc98SMatthew Ahrens 1289fa9e4066Sahrens return (0); 1290fa9e4066Sahrens } 1291fa9e4066Sahrens 1292e1930233Sbonwick /* ARGSUSED */ 1293e1930233Sbonwick static int 12941d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1295e1930233Sbonwick { 12961d452cf5Sahrens dsl_dataset_t *ds = arg1; 12973cb34c60Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 12983cb34c60Sahrens uint64_t count; 12993cb34c60Sahrens int err; 1300e1930233Sbonwick 1301e1930233Sbonwick /* 1302e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1303e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1304e1930233Sbonwick * from.) 1305e1930233Sbonwick */ 1306e1930233Sbonwick if (ds->ds_prev != NULL && 1307e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1308e1930233Sbonwick return (EINVAL); 1309e1930233Sbonwick 13103cb34c60Sahrens /* 13113cb34c60Sahrens * This is really a dsl_dir thing, but check it here so that 13123cb34c60Sahrens * we'll be less likely to leave this dataset inconsistent & 13133cb34c60Sahrens * nearly destroyed. 13143cb34c60Sahrens */ 13153cb34c60Sahrens err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count); 13163cb34c60Sahrens if (err) 13173cb34c60Sahrens return (err); 13183cb34c60Sahrens if (count != 0) 13193cb34c60Sahrens return (EEXIST); 13203cb34c60Sahrens 1321e1930233Sbonwick return (0); 1322e1930233Sbonwick } 1323e1930233Sbonwick 13241d452cf5Sahrens /* ARGSUSED */ 13251d452cf5Sahrens static void 1326ecd6cf80Smarks dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 1327fa9e4066Sahrens { 13281d452cf5Sahrens dsl_dataset_t *ds = arg1; 1329ecd6cf80Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1330fa9e4066Sahrens 13311d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 13321d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 13331d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1334ecd6cf80Smarks 1335ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 1336ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 13371d452cf5Sahrens } 1338fa9e4066Sahrens 1339842727c2SChris Kirby static int 1340842727c2SChris Kirby dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag, 1341842727c2SChris Kirby dmu_tx_t *tx) 1342842727c2SChris Kirby { 1343842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1344842727c2SChris Kirby dsl_dataset_t *ds_prev = ds->ds_prev; 1345842727c2SChris Kirby 1346842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(ds_prev)) { 1347842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1348842727c2SChris Kirby 1349842727c2SChris Kirby /* 1350842727c2SChris Kirby * If we're not prepared to remove the origin, don't remove 1351842727c2SChris Kirby * the clone either. 1352842727c2SChris Kirby */ 1353842727c2SChris Kirby if (dsda->rm_origin == NULL) { 1354842727c2SChris Kirby dsda->need_prep = B_TRUE; 1355842727c2SChris Kirby return (EBUSY); 1356842727c2SChris Kirby } 1357842727c2SChris Kirby 1358842727c2SChris Kirby ndsda.ds = ds_prev; 1359842727c2SChris Kirby ndsda.is_origin_rm = B_TRUE; 1360842727c2SChris Kirby return (dsl_dataset_destroy_check(&ndsda, tag, tx)); 1361842727c2SChris Kirby } 1362842727c2SChris Kirby 1363842727c2SChris Kirby /* 1364842727c2SChris Kirby * If we're not going to remove the origin after all, 1365842727c2SChris Kirby * undo the open context setup. 1366842727c2SChris Kirby */ 1367842727c2SChris Kirby if (dsda->rm_origin != NULL) { 1368842727c2SChris Kirby dsl_dataset_disown(dsda->rm_origin, tag); 1369842727c2SChris Kirby dsda->rm_origin = NULL; 1370842727c2SChris Kirby } 1371842727c2SChris Kirby 1372842727c2SChris Kirby return (0); 1373842727c2SChris Kirby } 1374842727c2SChris Kirby 13751d452cf5Sahrens /* ARGSUSED */ 13763cb34c60Sahrens int 13771d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 13781d452cf5Sahrens { 1379842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1380842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1381fa9e4066Sahrens 1382745cd3c5Smaybee /* we have an owner hold, so noone else can destroy us */ 1383745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 1384745cd3c5Smaybee 1385842727c2SChris Kirby /* 1386842727c2SChris Kirby * Only allow deferred destroy on pools that support it. 1387842727c2SChris Kirby * NOTE: deferred destroy is only supported on snapshots. 1388842727c2SChris Kirby */ 1389842727c2SChris Kirby if (dsda->defer) { 1390842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 1391842727c2SChris Kirby SPA_VERSION_USERREFS) 1392842727c2SChris Kirby return (ENOTSUP); 1393842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 1394842727c2SChris Kirby return (0); 1395842727c2SChris Kirby } 1396fa9e4066Sahrens 1397fa9e4066Sahrens /* 1398fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1399fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1400fa9e4066Sahrens * from.) 1401fa9e4066Sahrens */ 1402fa9e4066Sahrens if (ds->ds_prev != NULL && 14031d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1404fa9e4066Sahrens return (EINVAL); 1405fa9e4066Sahrens 1406fa9e4066Sahrens /* 1407fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1408fa9e4066Sahrens * them. Try again. 1409fa9e4066Sahrens */ 14101d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1411fa9e4066Sahrens return (EAGAIN); 14121d452cf5Sahrens 1413842727c2SChris Kirby if (dsl_dataset_is_snapshot(ds)) { 1414842727c2SChris Kirby /* 1415842727c2SChris Kirby * If this snapshot has an elevated user reference count, 1416842727c2SChris Kirby * we can't destroy it yet. 1417842727c2SChris Kirby */ 1418842727c2SChris Kirby if (ds->ds_userrefs > 0 && !dsda->releasing) 1419842727c2SChris Kirby return (EBUSY); 1420842727c2SChris Kirby 1421842727c2SChris Kirby mutex_enter(&ds->ds_lock); 1422842727c2SChris Kirby /* 1423842727c2SChris Kirby * Can't delete a branch point. However, if we're destroying 1424842727c2SChris Kirby * a clone and removing its origin due to it having a user 1425842727c2SChris Kirby * hold count of 0 and having been marked for deferred destroy, 1426842727c2SChris Kirby * it's OK for the origin to have a single clone. 1427842727c2SChris Kirby */ 1428842727c2SChris Kirby if (ds->ds_phys->ds_num_children > 1429842727c2SChris Kirby (dsda->is_origin_rm ? 2 : 1)) { 1430842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1431842727c2SChris Kirby return (EEXIST); 1432842727c2SChris Kirby } 1433842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1434842727c2SChris Kirby } else if (dsl_dir_is_clone(ds->ds_dir)) { 1435842727c2SChris Kirby return (dsl_dataset_origin_check(dsda, arg2, tx)); 1436842727c2SChris Kirby } 1437842727c2SChris Kirby 14381d452cf5Sahrens /* XXX we should do some i/o error checking... */ 14391d452cf5Sahrens return (0); 14401d452cf5Sahrens } 14411d452cf5Sahrens 1442745cd3c5Smaybee struct refsarg { 1443745cd3c5Smaybee kmutex_t lock; 1444745cd3c5Smaybee boolean_t gone; 1445745cd3c5Smaybee kcondvar_t cv; 1446745cd3c5Smaybee }; 1447745cd3c5Smaybee 1448745cd3c5Smaybee /* ARGSUSED */ 1449745cd3c5Smaybee static void 1450745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv) 1451745cd3c5Smaybee { 1452745cd3c5Smaybee struct refsarg *arg = argv; 1453745cd3c5Smaybee 1454745cd3c5Smaybee mutex_enter(&arg->lock); 1455745cd3c5Smaybee arg->gone = TRUE; 1456745cd3c5Smaybee cv_signal(&arg->cv); 1457745cd3c5Smaybee mutex_exit(&arg->lock); 1458745cd3c5Smaybee } 1459745cd3c5Smaybee 1460745cd3c5Smaybee static void 1461745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag) 1462745cd3c5Smaybee { 1463745cd3c5Smaybee struct refsarg arg; 1464745cd3c5Smaybee 1465745cd3c5Smaybee mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL); 1466745cd3c5Smaybee cv_init(&arg.cv, NULL, CV_DEFAULT, NULL); 1467745cd3c5Smaybee arg.gone = FALSE; 1468745cd3c5Smaybee (void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys, 1469745cd3c5Smaybee dsl_dataset_refs_gone); 1470745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 1471745cd3c5Smaybee mutex_enter(&arg.lock); 1472745cd3c5Smaybee while (!arg.gone) 1473745cd3c5Smaybee cv_wait(&arg.cv, &arg.lock); 1474745cd3c5Smaybee ASSERT(arg.gone); 1475745cd3c5Smaybee mutex_exit(&arg.lock); 1476745cd3c5Smaybee ds->ds_dbuf = NULL; 1477745cd3c5Smaybee ds->ds_phys = NULL; 1478745cd3c5Smaybee mutex_destroy(&arg.lock); 1479745cd3c5Smaybee cv_destroy(&arg.cv); 1480745cd3c5Smaybee } 1481745cd3c5Smaybee 14823cb34c60Sahrens void 1483ecd6cf80Smarks dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 14841d452cf5Sahrens { 1485842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1486842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 14871d452cf5Sahrens zio_t *zio; 14881d452cf5Sahrens int err; 14891d452cf5Sahrens int after_branch_point = FALSE; 14901d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 14911d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 14921d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 14931d452cf5Sahrens uint64_t obj; 14941d452cf5Sahrens 1495745cd3c5Smaybee ASSERT(ds->ds_owner); 1496842727c2SChris Kirby ASSERT(dsda->defer || ds->ds_phys->ds_num_children <= 1); 14971d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 14981d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 14991d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 15001d452cf5Sahrens 1501842727c2SChris Kirby if (dsda->defer) { 1502842727c2SChris Kirby ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 1503842727c2SChris Kirby if (ds->ds_userrefs > 0 || ds->ds_phys->ds_num_children > 1) { 1504842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 1505842727c2SChris Kirby ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY; 1506842727c2SChris Kirby return; 1507842727c2SChris Kirby } 1508842727c2SChris Kirby } 1509842727c2SChris Kirby 1510745cd3c5Smaybee /* signal any waiters that this dataset is going away */ 1511745cd3c5Smaybee mutex_enter(&ds->ds_lock); 1512745cd3c5Smaybee ds->ds_owner = dsl_reaper; 1513745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 1514745cd3c5Smaybee mutex_exit(&ds->ds_lock); 1515745cd3c5Smaybee 1516a9799022Sck /* Remove our reservation */ 1517a9799022Sck if (ds->ds_reserved != 0) { 1518a9799022Sck uint64_t val = 0; 1519a9799022Sck dsl_dataset_set_reservation_sync(ds, &val, cr, tx); 1520a9799022Sck ASSERT3U(ds->ds_reserved, ==, 0); 1521a9799022Sck } 1522a9799022Sck 15231d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 15241d452cf5Sahrens 1525088f3894Sahrens dsl_pool_ds_destroyed(ds, tx); 1526088f3894Sahrens 15271d452cf5Sahrens obj = ds->ds_object; 1528fa9e4066Sahrens 1529fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1530fa9e4066Sahrens if (ds->ds_prev) { 1531fa9e4066Sahrens ds_prev = ds->ds_prev; 1532fa9e4066Sahrens } else { 1533745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1534745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev)); 1535fa9e4066Sahrens } 1536fa9e4066Sahrens after_branch_point = 1537fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1538fa9e4066Sahrens 1539fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1540088f3894Sahrens if (after_branch_point && 1541088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj != 0) { 154214843421SMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(mos, 1543088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, obj, tx)); 1544088f3894Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1545088f3894Sahrens VERIFY(0 == zap_add_int(mos, 1546088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, 1547088f3894Sahrens ds->ds_phys->ds_next_snap_obj, tx)); 1548088f3894Sahrens } 1549088f3894Sahrens } 1550fa9e4066Sahrens if (after_branch_point && 1551fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1552fa9e4066Sahrens /* This clone is toast. */ 1553fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1554fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1555842727c2SChris Kirby 1556842727c2SChris Kirby /* 1557842727c2SChris Kirby * If the clone's origin has no other clones, no 1558842727c2SChris Kirby * user holds, and has been marked for deferred 1559842727c2SChris Kirby * deletion, then we should have done the necessary 1560842727c2SChris Kirby * destroy setup for it. 1561842727c2SChris Kirby */ 1562842727c2SChris Kirby if (ds_prev->ds_phys->ds_num_children == 1 && 1563842727c2SChris Kirby ds_prev->ds_userrefs == 0 && 1564842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds_prev)) { 1565842727c2SChris Kirby ASSERT3P(dsda->rm_origin, !=, NULL); 1566842727c2SChris Kirby } else { 1567842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 1568842727c2SChris Kirby } 1569fa9e4066Sahrens } else if (!after_branch_point) { 1570fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1571fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1572fa9e4066Sahrens } 1573fa9e4066Sahrens } 1574fa9e4066Sahrens 1575fa9e4066Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1576fa9e4066Sahrens 1577fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 15781d452cf5Sahrens blkptr_t bp; 1579fa9e4066Sahrens dsl_dataset_t *ds_next; 1580fa9e4066Sahrens uint64_t itor = 0; 1581a9799022Sck uint64_t old_unique; 158274e7dc98SMatthew Ahrens int64_t used = 0, compressed = 0, uncompressed = 0; 1583fa9e4066Sahrens 1584745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1585745cd3c5Smaybee ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next)); 1586fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1587fa9e4066Sahrens 1588a9799022Sck old_unique = dsl_dataset_unique(ds_next); 1589a9799022Sck 1590fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1591fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1592fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1593fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1594fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1595fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1596fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1597fa9e4066Sahrens 1598fa9e4066Sahrens /* 1599fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1600fa9e4066Sahrens * new deadlist) any entries from next's current 1601fa9e4066Sahrens * deadlist which were born before prev, and free the 1602fa9e4066Sahrens * other entries. 1603fa9e4066Sahrens * 1604fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1605fa9e4066Sahrens */ 1606745cd3c5Smaybee while (bplist_iterate(&ds_next->ds_deadlist, &itor, &bp) == 0) { 1607fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1608ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1609ea8dc4b6Seschrock &bp, tx)); 1610fa9e4066Sahrens if (ds_prev && !after_branch_point && 1611fa9e4066Sahrens bp.blk_birth > 1612fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1613fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 161499653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1615fa9e4066Sahrens } 1616fa9e4066Sahrens } else { 161799653d4eSeschrock used += bp_get_dasize(dp->dp_spa, &bp); 1618fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1619fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1620fa9e4066Sahrens /* XXX check return value? */ 1621088f3894Sahrens (void) dsl_free(zio, dp, tx->tx_txg, 1622fa9e4066Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1623fa9e4066Sahrens } 1624fa9e4066Sahrens } 1625fa9e4066Sahrens 162674e7dc98SMatthew Ahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 162774e7dc98SMatthew Ahrens 162874e7dc98SMatthew Ahrens /* change snapused */ 162974e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 163074e7dc98SMatthew Ahrens -used, -compressed, -uncompressed, tx); 163174e7dc98SMatthew Ahrens 1632fa9e4066Sahrens /* free next's deadlist */ 1633fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1634fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1635fa9e4066Sahrens 1636fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1637745cd3c5Smaybee bplist_close(&ds->ds_deadlist); 1638fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1639fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1640ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1641ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1642fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1643fa9e4066Sahrens 1644fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1645fa9e4066Sahrens /* 1646fa9e4066Sahrens * Update next's unique to include blocks which 1647fa9e4066Sahrens * were previously shared by only this snapshot 1648fa9e4066Sahrens * and it. Those blocks will be born after the 1649fa9e4066Sahrens * prev snap and before this snap, and will have 1650fa9e4066Sahrens * died after the next snap and before the one 1651fa9e4066Sahrens * after that (ie. be on the snap after next's 1652fa9e4066Sahrens * deadlist). 1653fa9e4066Sahrens * 1654fa9e4066Sahrens * XXX we're doing this long task with the 1655fa9e4066Sahrens * config lock held 1656fa9e4066Sahrens */ 1657fa9e4066Sahrens dsl_dataset_t *ds_after_next; 165874e7dc98SMatthew Ahrens uint64_t space; 1659fa9e4066Sahrens 1660745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1661745cd3c5Smaybee ds_next->ds_phys->ds_next_snap_obj, 1662745cd3c5Smaybee FTAG, &ds_after_next)); 166374e7dc98SMatthew Ahrens 166474e7dc98SMatthew Ahrens VERIFY(0 == 166574e7dc98SMatthew Ahrens bplist_space_birthrange(&ds_after_next->ds_deadlist, 166674e7dc98SMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 166774e7dc98SMatthew Ahrens ds->ds_phys->ds_creation_txg, &space)); 166874e7dc98SMatthew Ahrens ds_next->ds_phys->ds_unique_bytes += space; 1669fa9e4066Sahrens 1670745cd3c5Smaybee dsl_dataset_rele(ds_after_next, FTAG); 1671fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1672fa9e4066Sahrens } else { 1673fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1674745cd3c5Smaybee dsl_dataset_drop_ref(ds_next->ds_prev, ds_next); 1675745cd3c5Smaybee ds_next->ds_prev = NULL; 1676fa9e4066Sahrens if (ds_prev) { 1677745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1678745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 1679745cd3c5Smaybee ds_next, &ds_next->ds_prev)); 1680fa9e4066Sahrens } 1681a9799022Sck 1682a9799022Sck dsl_dataset_recalc_head_uniq(ds_next); 1683a9799022Sck 1684a9799022Sck /* 1685a9799022Sck * Reduce the amount of our unconsmed refreservation 1686a9799022Sck * being charged to our parent by the amount of 1687a9799022Sck * new unique data we have gained. 1688a9799022Sck */ 1689a9799022Sck if (old_unique < ds_next->ds_reserved) { 1690a9799022Sck int64_t mrsdelta; 1691a9799022Sck uint64_t new_unique = 1692a9799022Sck ds_next->ds_phys->ds_unique_bytes; 1693a9799022Sck 1694a9799022Sck ASSERT(old_unique <= new_unique); 1695a9799022Sck mrsdelta = MIN(new_unique - old_unique, 1696a9799022Sck ds_next->ds_reserved - old_unique); 169774e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 169874e7dc98SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 1699a9799022Sck } 1700fa9e4066Sahrens } 1701745cd3c5Smaybee dsl_dataset_rele(ds_next, FTAG); 1702fa9e4066Sahrens } else { 1703fa9e4066Sahrens /* 1704fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1705fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1706fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1707fa9e4066Sahrens * safe to ignore the deadlist contents.) 1708fa9e4066Sahrens */ 1709fa9e4066Sahrens struct killarg ka; 1710fa9e4066Sahrens 1711fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1712fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1713fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1714fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1715fa9e4066Sahrens 1716fa9e4066Sahrens /* 1717fa9e4066Sahrens * Free everything that we point to (that's born after 1718fa9e4066Sahrens * the previous snapshot, if we are a clone) 1719fa9e4066Sahrens * 172074e7dc98SMatthew Ahrens * NB: this should be very quick, because we already 172174e7dc98SMatthew Ahrens * freed all the objects in open context. 1722fa9e4066Sahrens */ 172374e7dc98SMatthew Ahrens ka.ds = ds; 1724fa9e4066Sahrens ka.zio = zio; 1725fa9e4066Sahrens ka.tx = tx; 172688b7b0f2SMatthew Ahrens err = traverse_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 172788b7b0f2SMatthew Ahrens TRAVERSE_POST, kill_blkptr, &ka); 1728fa9e4066Sahrens ASSERT3U(err, ==, 0); 17293e78c5fbSChris Kirby ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 173074e7dc98SMatthew Ahrens ds->ds_phys->ds_unique_bytes == 0); 1731ca45db41SChris Kirby 1732ca45db41SChris Kirby if (ds->ds_prev != NULL) { 1733ca45db41SChris Kirby dsl_dataset_rele(ds->ds_prev, ds); 1734ca45db41SChris Kirby ds->ds_prev = ds_prev = NULL; 1735ca45db41SChris Kirby } 1736fa9e4066Sahrens } 1737fa9e4066Sahrens 1738fa9e4066Sahrens err = zio_wait(zio); 1739fa9e4066Sahrens ASSERT3U(err, ==, 0); 1740fa9e4066Sahrens 17411d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1742745cd3c5Smaybee /* Erase the link in the dir */ 17431d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 17441d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1745745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0); 1746745cd3c5Smaybee err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1747745cd3c5Smaybee ASSERT(err == 0); 1748fa9e4066Sahrens } else { 1749fa9e4066Sahrens /* remove from snapshot namespace */ 1750fa9e4066Sahrens dsl_dataset_t *ds_head; 1751745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0); 1752745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1753745cd3c5Smaybee ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head)); 17548660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1755fa9e4066Sahrens #ifdef ZFS_DEBUG 1756fa9e4066Sahrens { 1757fa9e4066Sahrens uint64_t val; 1758ab04eb8eStimh 1759745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds_head, 1760ab04eb8eStimh ds->ds_snapname, &val); 1761fa9e4066Sahrens ASSERT3U(err, ==, 0); 1762fa9e4066Sahrens ASSERT3U(val, ==, obj); 1763fa9e4066Sahrens } 1764fa9e4066Sahrens #endif 1765745cd3c5Smaybee err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx); 1766fa9e4066Sahrens ASSERT(err == 0); 1767745cd3c5Smaybee dsl_dataset_rele(ds_head, FTAG); 1768fa9e4066Sahrens } 1769fa9e4066Sahrens 1770fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1771745cd3c5Smaybee dsl_dataset_rele(ds_prev, FTAG); 1772fa9e4066Sahrens 1773990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 1774ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx, 1775ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 1776ecd6cf80Smarks 1777088f3894Sahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 1778088f3894Sahrens uint64_t count; 1779088f3894Sahrens ASSERT(0 == zap_count(mos, 1780088f3894Sahrens ds->ds_phys->ds_next_clones_obj, &count) && count == 0); 1781088f3894Sahrens VERIFY(0 == dmu_object_free(mos, 1782088f3894Sahrens ds->ds_phys->ds_next_clones_obj, tx)); 1783088f3894Sahrens } 178474e7dc98SMatthew Ahrens if (ds->ds_phys->ds_props_obj != 0) 178574e7dc98SMatthew Ahrens VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_props_obj, tx)); 1786842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) 1787842727c2SChris Kirby VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx)); 1788745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 1789745cd3c5Smaybee ds->ds_dir = NULL; 1790745cd3c5Smaybee dsl_dataset_drain_refs(ds, tag); 17911d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1792842727c2SChris Kirby 1793842727c2SChris Kirby if (dsda->rm_origin) { 1794842727c2SChris Kirby /* 1795842727c2SChris Kirby * Remove the origin of the clone we just destroyed. 1796842727c2SChris Kirby */ 1797842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1798842727c2SChris Kirby 1799ca45db41SChris Kirby ndsda.ds = dsda->rm_origin; 1800842727c2SChris Kirby dsl_dataset_destroy_sync(&ndsda, tag, cr, tx); 1801842727c2SChris Kirby } 1802fa9e4066Sahrens } 1803fa9e4066Sahrens 1804a9799022Sck static int 1805a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx) 1806a9799022Sck { 1807a9799022Sck uint64_t asize; 1808a9799022Sck 1809a9799022Sck if (!dmu_tx_is_syncing(tx)) 1810a9799022Sck return (0); 1811a9799022Sck 1812a9799022Sck /* 1813a9799022Sck * If there's an fs-only reservation, any blocks that might become 1814a9799022Sck * owned by the snapshot dataset must be accommodated by space 1815a9799022Sck * outside of the reservation. 1816a9799022Sck */ 1817a9799022Sck asize = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 1818a9799022Sck if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, FALSE)) 1819a9799022Sck return (ENOSPC); 1820a9799022Sck 1821a9799022Sck /* 1822a9799022Sck * Propogate any reserved space for this snapshot to other 1823a9799022Sck * snapshot checks in this sync group. 1824a9799022Sck */ 1825a9799022Sck if (asize > 0) 1826a9799022Sck dsl_dir_willuse_space(ds->ds_dir, asize, tx); 1827a9799022Sck 1828a9799022Sck return (0); 1829a9799022Sck } 1830a9799022Sck 18311d452cf5Sahrens /* ARGSUSED */ 1832fa9e4066Sahrens int 18331d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1834fa9e4066Sahrens { 18353cb34c60Sahrens dsl_dataset_t *ds = arg1; 18361d452cf5Sahrens const char *snapname = arg2; 1837fa9e4066Sahrens int err; 18381d452cf5Sahrens uint64_t value; 1839fa9e4066Sahrens 18401d452cf5Sahrens /* 18411d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 18421d452cf5Sahrens * is already one, try again. 18431d452cf5Sahrens */ 18441d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 18451d452cf5Sahrens return (EAGAIN); 1846fa9e4066Sahrens 18471d452cf5Sahrens /* 18481d452cf5Sahrens * Check for conflicting name snapshot name. 18491d452cf5Sahrens */ 1850745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds, snapname, &value); 18511d452cf5Sahrens if (err == 0) 1852fa9e4066Sahrens return (EEXIST); 18531d452cf5Sahrens if (err != ENOENT) 18541d452cf5Sahrens return (err); 1855fa9e4066Sahrens 1856b7661cccSmmusante /* 1857b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 1858b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 1859b7661cccSmmusante */ 1860b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 1861b7661cccSmmusante return (ENAMETOOLONG); 1862b7661cccSmmusante 1863a9799022Sck err = dsl_dataset_snapshot_reserve_space(ds, tx); 1864a9799022Sck if (err) 1865a9799022Sck return (err); 1866a9799022Sck 18671d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 18681d452cf5Sahrens return (0); 18691d452cf5Sahrens } 1870fa9e4066Sahrens 18711d452cf5Sahrens void 1872ecd6cf80Smarks dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 18731d452cf5Sahrens { 18743cb34c60Sahrens dsl_dataset_t *ds = arg1; 18751d452cf5Sahrens const char *snapname = arg2; 18761d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 18771d452cf5Sahrens dmu_buf_t *dbuf; 18781d452cf5Sahrens dsl_dataset_phys_t *dsphys; 1879088f3894Sahrens uint64_t dsobj, crtxg; 18801d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 18811d452cf5Sahrens int err; 1882fa9e4066Sahrens 18831d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1884fa9e4066Sahrens 1885088f3894Sahrens /* 1886088f3894Sahrens * The origin's ds_creation_txg has to be < TXG_INITIAL 1887088f3894Sahrens */ 1888088f3894Sahrens if (strcmp(snapname, ORIGIN_DIR_NAME) == 0) 1889088f3894Sahrens crtxg = 1; 1890088f3894Sahrens else 1891088f3894Sahrens crtxg = tx->tx_txg; 1892088f3894Sahrens 18931649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 18941649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 1895ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1896fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 1897fa9e4066Sahrens dsphys = dbuf->db_data; 1898745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 18991d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 1900fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 1901fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1902fa9e4066Sahrens sizeof (dsphys->ds_guid)); 1903fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1904fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1905fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1906fa9e4066Sahrens dsphys->ds_num_children = 1; 1907fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1908088f3894Sahrens dsphys->ds_creation_txg = crtxg; 1909fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1910fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1911fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1912fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 191399653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 1914fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 1915ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 1916fa9e4066Sahrens 19171d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 19181d452cf5Sahrens if (ds->ds_prev) { 1919088f3894Sahrens uint64_t next_clones_obj = 1920088f3894Sahrens ds->ds_prev->ds_phys->ds_next_clones_obj; 19211d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 1922fa9e4066Sahrens ds->ds_object || 19231d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 19241d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 19251d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1926fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 19271d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 19281d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1929088f3894Sahrens } else if (next_clones_obj != 0) { 1930088f3894Sahrens VERIFY3U(0, ==, zap_remove_int(mos, 1931088f3894Sahrens next_clones_obj, dsphys->ds_next_snap_obj, tx)); 1932088f3894Sahrens VERIFY3U(0, ==, zap_add_int(mos, 1933088f3894Sahrens next_clones_obj, dsobj, tx)); 1934fa9e4066Sahrens } 1935fa9e4066Sahrens } 1936fa9e4066Sahrens 1937a9799022Sck /* 1938a9799022Sck * If we have a reference-reservation on this dataset, we will 1939a9799022Sck * need to increase the amount of refreservation being charged 1940a9799022Sck * since our unique space is going to zero. 1941a9799022Sck */ 1942a9799022Sck if (ds->ds_reserved) { 1943a9799022Sck int64_t add = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 194474e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, 194574e7dc98SMatthew Ahrens add, 0, 0, tx); 1946a9799022Sck } 1947a9799022Sck 1948fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1949fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1950a4611edeSahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg); 1951fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1952088f3894Sahrens ds->ds_phys->ds_prev_snap_txg = crtxg; 1953fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1954a9799022Sck if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 1955a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1956fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1957fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1958ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1959ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1960fa9e4066Sahrens 1961fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1962fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1963fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 1964fa9e4066Sahrens ASSERT(err == 0); 1965fa9e4066Sahrens 1966fa9e4066Sahrens if (ds->ds_prev) 1967745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 1968745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1969745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev)); 1970ecd6cf80Smarks 1971088f3894Sahrens dsl_pool_ds_snapshotted(ds, tx); 1972088f3894Sahrens 1973*71eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 1974*71eb0538SChris Kirby 1975ecd6cf80Smarks spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr, 197640feaa91Sahrens "dataset = %llu", dsobj); 1977fa9e4066Sahrens } 1978fa9e4066Sahrens 1979fa9e4066Sahrens void 1980c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 1981fa9e4066Sahrens { 1982fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1983503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1984fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1985fa9e4066Sahrens 198691ebeef5Sahrens /* 198791ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 198891ebeef5Sahrens * sync it out now. 198991ebeef5Sahrens */ 199091ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 199191ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 199291ebeef5Sahrens 1993fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 1994503ad85cSMatthew Ahrens dmu_objset_sync(ds->ds_objset, zio, tx); 1995fa9e4066Sahrens } 1996fa9e4066Sahrens 1997fa9e4066Sahrens void 1998a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 1999fa9e4066Sahrens { 2000a9799022Sck uint64_t refd, avail, uobjs, aobjs; 2001a9799022Sck 2002a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 2003fa9e4066Sahrens 2004a9799022Sck dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); 2005a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); 2006a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); 2007a9799022Sck 2008a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 2009a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 2010a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 2011a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 2012a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, 2013a9799022Sck ds->ds_quota); 2014a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, 2015a9799022Sck ds->ds_reserved); 2016c5904d13Seschrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, 2017c5904d13Seschrock ds->ds_phys->ds_guid); 2018842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, ds->ds_userrefs); 2019842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2020842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2021fa9e4066Sahrens 2022fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2023fa9e4066Sahrens /* 2024fa9e4066Sahrens * This is a snapshot; override the dd's space used with 2025a2eea2e1Sahrens * our unique space and compression ratio. 2026fa9e4066Sahrens */ 2027a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 2028a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 2029a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 2030a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 2031a2eea2e1Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 2032a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes)); 2033fa9e4066Sahrens } 2034fa9e4066Sahrens } 2035fa9e4066Sahrens 2036a2eea2e1Sahrens void 2037a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2038a2eea2e1Sahrens { 2039a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2040a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 20413cb34c60Sahrens stat->dds_guid = ds->ds_phys->ds_guid; 2042a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2043a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 2044a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 2045ebedde84SEric Taylor } else { 2046ebedde84SEric Taylor stat->dds_is_snapshot = B_FALSE; 2047ebedde84SEric Taylor stat->dds_num_clones = 0; 2048a2eea2e1Sahrens } 2049a2eea2e1Sahrens 2050a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 20514ccbb6e7Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 2052088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 2053a2eea2e1Sahrens dsl_dataset_t *ods; 2054a2eea2e1Sahrens 2055745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool, 2056745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods)); 20573cb34c60Sahrens dsl_dataset_name(ods, stat->dds_origin); 2058745cd3c5Smaybee dsl_dataset_drop_ref(ods, FTAG); 2059ebedde84SEric Taylor } else { 2060ebedde84SEric Taylor stat->dds_origin[0] = '\0'; 2061a2eea2e1Sahrens } 20624ccbb6e7Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2063a2eea2e1Sahrens } 2064a2eea2e1Sahrens 2065a2eea2e1Sahrens uint64_t 2066a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 2067a2eea2e1Sahrens { 206891ebeef5Sahrens return (ds->ds_fsid_guid); 2069a2eea2e1Sahrens } 2070a2eea2e1Sahrens 2071a2eea2e1Sahrens void 2072a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 2073a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 2074a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 2075fa9e4066Sahrens { 2076a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 2077a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 2078a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) 2079a9799022Sck *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes; 2080a9799022Sck if (ds->ds_quota != 0) { 2081a9799022Sck /* 2082a9799022Sck * Adjust available bytes according to refquota 2083a9799022Sck */ 2084a9799022Sck if (*refdbytesp < ds->ds_quota) 2085a9799022Sck *availbytesp = MIN(*availbytesp, 2086a9799022Sck ds->ds_quota - *refdbytesp); 2087a9799022Sck else 2088a9799022Sck *availbytesp = 0; 2089a9799022Sck } 2090a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 2091a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 2092fa9e4066Sahrens } 2093fa9e4066Sahrens 2094f18faf3fSek boolean_t 2095f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 2096f18faf3fSek { 2097f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 2098f18faf3fSek 2099f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 2100f18faf3fSek dsl_pool_sync_context(dp)); 2101f18faf3fSek if (ds->ds_prev == NULL) 2102f18faf3fSek return (B_FALSE); 2103f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 2104f18faf3fSek ds->ds_prev->ds_phys->ds_creation_txg) 2105f18faf3fSek return (B_TRUE); 2106f18faf3fSek return (B_FALSE); 2107f18faf3fSek } 2108f18faf3fSek 21091d452cf5Sahrens /* ARGSUSED */ 2110fa9e4066Sahrens static int 21111d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 2112fa9e4066Sahrens { 21131d452cf5Sahrens dsl_dataset_t *ds = arg1; 21141d452cf5Sahrens char *newsnapname = arg2; 21151d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 21161d452cf5Sahrens dsl_dataset_t *hds; 2117fa9e4066Sahrens uint64_t val; 21181d452cf5Sahrens int err; 2119fa9e4066Sahrens 2120745cd3c5Smaybee err = dsl_dataset_hold_obj(dd->dd_pool, 2121745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds); 2122fa9e4066Sahrens if (err) 2123fa9e4066Sahrens return (err); 2124fa9e4066Sahrens 21251d452cf5Sahrens /* new name better not be in use */ 2126745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, newsnapname, &val); 2127745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 21281d452cf5Sahrens 21291d452cf5Sahrens if (err == 0) 21301d452cf5Sahrens err = EEXIST; 21311d452cf5Sahrens else if (err == ENOENT) 21321d452cf5Sahrens err = 0; 2133cdf5b4caSmmusante 2134cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 2135cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 2136cdf5b4caSmmusante err = ENAMETOOLONG; 2137cdf5b4caSmmusante 21381d452cf5Sahrens return (err); 21391d452cf5Sahrens } 2140fa9e4066Sahrens 21411d452cf5Sahrens static void 2142ecd6cf80Smarks dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, 2143ecd6cf80Smarks cred_t *cr, dmu_tx_t *tx) 21441d452cf5Sahrens { 21451d452cf5Sahrens dsl_dataset_t *ds = arg1; 2146ecd6cf80Smarks const char *newsnapname = arg2; 21471d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 21481d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 21491d452cf5Sahrens dsl_dataset_t *hds; 21501d452cf5Sahrens int err; 2151fa9e4066Sahrens 21521d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 2153fa9e4066Sahrens 2154745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, 2155745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds)); 2156fa9e4066Sahrens 21571d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2158745cd3c5Smaybee err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx); 2159fa9e4066Sahrens ASSERT3U(err, ==, 0); 21601d452cf5Sahrens mutex_enter(&ds->ds_lock); 21611d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 21621d452cf5Sahrens mutex_exit(&ds->ds_lock); 21631d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 21641d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 2165fa9e4066Sahrens ASSERT3U(err, ==, 0); 2166fa9e4066Sahrens 2167ecd6cf80Smarks spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 2168ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 2169745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 2170fa9e4066Sahrens } 2171fa9e4066Sahrens 2172f18faf3fSek struct renamesnaparg { 2173cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 2174cdf5b4caSmmusante char failed[MAXPATHLEN]; 2175cdf5b4caSmmusante char *oldsnap; 2176cdf5b4caSmmusante char *newsnap; 2177cdf5b4caSmmusante }; 2178cdf5b4caSmmusante 2179cdf5b4caSmmusante static int 2180cdf5b4caSmmusante dsl_snapshot_rename_one(char *name, void *arg) 2181cdf5b4caSmmusante { 2182f18faf3fSek struct renamesnaparg *ra = arg; 2183cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 2184cdf5b4caSmmusante char *cp; 2185cdf5b4caSmmusante int err; 2186cdf5b4caSmmusante 2187cdf5b4caSmmusante cp = name + strlen(name); 2188cdf5b4caSmmusante *cp = '@'; 2189cdf5b4caSmmusante (void) strcpy(cp + 1, ra->oldsnap); 2190ecd6cf80Smarks 2191ecd6cf80Smarks /* 2192ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 2193ecd6cf80Smarks * so we just pass name for both the to/from argument. 2194ecd6cf80Smarks */ 2195a0dc2951SMatthew Ahrens err = zfs_secpolicy_rename_perms(name, name, CRED()); 2196a0dc2951SMatthew Ahrens if (err == ENOENT) { 2197a0dc2951SMatthew Ahrens return (0); 2198a0dc2951SMatthew Ahrens } else if (err) { 2199ecd6cf80Smarks (void) strcpy(ra->failed, name); 2200ecd6cf80Smarks return (err); 2201ecd6cf80Smarks } 2202ecd6cf80Smarks 2203745cd3c5Smaybee #ifdef _KERNEL 2204745cd3c5Smaybee /* 2205745cd3c5Smaybee * For all filesystems undergoing rename, we'll need to unmount it. 2206745cd3c5Smaybee */ 2207745cd3c5Smaybee (void) zfs_unmount_snap(name, NULL); 2208745cd3c5Smaybee #endif 2209745cd3c5Smaybee err = dsl_dataset_hold(name, ra->dstg, &ds); 2210745cd3c5Smaybee *cp = '\0'; 2211cdf5b4caSmmusante if (err == ENOENT) { 2212cdf5b4caSmmusante return (0); 2213745cd3c5Smaybee } else if (err) { 2214cdf5b4caSmmusante (void) strcpy(ra->failed, name); 2215cdf5b4caSmmusante return (err); 2216cdf5b4caSmmusante } 2217cdf5b4caSmmusante 2218cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 2219cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 2220cdf5b4caSmmusante 2221cdf5b4caSmmusante return (0); 2222cdf5b4caSmmusante } 2223cdf5b4caSmmusante 2224cdf5b4caSmmusante static int 2225cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 2226cdf5b4caSmmusante { 2227cdf5b4caSmmusante int err; 2228f18faf3fSek struct renamesnaparg *ra; 2229cdf5b4caSmmusante dsl_sync_task_t *dst; 2230cdf5b4caSmmusante spa_t *spa; 2231cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 2232cdf5b4caSmmusante int len = strlen(oldname); 2233cdf5b4caSmmusante 2234cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 2235cdf5b4caSmmusante cp = strchr(fsname, '@'); 2236cdf5b4caSmmusante *cp = '\0'; 2237cdf5b4caSmmusante 223840feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 2239cdf5b4caSmmusante if (err) { 2240cdf5b4caSmmusante kmem_free(fsname, len + 1); 2241cdf5b4caSmmusante return (err); 2242cdf5b4caSmmusante } 2243f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 2244cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 2245cdf5b4caSmmusante 2246cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 2247cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 2248cdf5b4caSmmusante *ra->failed = '\0'; 2249cdf5b4caSmmusante 2250cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 2251cdf5b4caSmmusante DS_FIND_CHILDREN); 2252cdf5b4caSmmusante kmem_free(fsname, len + 1); 2253cdf5b4caSmmusante 2254cdf5b4caSmmusante if (err == 0) { 2255cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 2256cdf5b4caSmmusante } 2257cdf5b4caSmmusante 2258cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 2259cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 2260cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 2261cdf5b4caSmmusante if (dst->dst_err) { 2262cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 22632572aa4eSmmusante (void) strcat(ra->failed, "@"); 22642572aa4eSmmusante (void) strcat(ra->failed, ra->newsnap); 2265cdf5b4caSmmusante } 2266745cd3c5Smaybee dsl_dataset_rele(ds, ra->dstg); 2267cdf5b4caSmmusante } 2268cdf5b4caSmmusante 2269ecd6cf80Smarks if (err) 2270ecd6cf80Smarks (void) strcpy(oldname, ra->failed); 2271cdf5b4caSmmusante 2272cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 2273f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 2274cdf5b4caSmmusante spa_close(spa, FTAG); 2275cdf5b4caSmmusante return (err); 2276cdf5b4caSmmusante } 2277cdf5b4caSmmusante 22783a5a36beSmmusante static int 22793a5a36beSmmusante dsl_valid_rename(char *oldname, void *arg) 22803a5a36beSmmusante { 22813a5a36beSmmusante int delta = *(int *)arg; 22823a5a36beSmmusante 22833a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 22843a5a36beSmmusante return (ENAMETOOLONG); 22853a5a36beSmmusante 22863a5a36beSmmusante return (0); 22873a5a36beSmmusante } 22883a5a36beSmmusante 2289fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 2290fa9e4066Sahrens int 2291745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive) 2292fa9e4066Sahrens { 2293fa9e4066Sahrens dsl_dir_t *dd; 22941d452cf5Sahrens dsl_dataset_t *ds; 2295fa9e4066Sahrens const char *tail; 2296fa9e4066Sahrens int err; 2297fa9e4066Sahrens 22981d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 2299ea8dc4b6Seschrock if (err) 2300ea8dc4b6Seschrock return (err); 23011db42183SEric Taylor /* 23021db42183SEric Taylor * If there are more than 2 references there may be holds 23031db42183SEric Taylor * hanging around that haven't been cleared out yet. 23041db42183SEric Taylor */ 23051db42183SEric Taylor if (dmu_buf_refcount(dd->dd_dbuf) > 2) 23061db42183SEric Taylor txg_wait_synced(dd->dd_pool, 0); 2307fa9e4066Sahrens if (tail == NULL) { 23083a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 23093a5a36beSmmusante 2310088f3894Sahrens /* if we're growing, validate child name lengths */ 23113a5a36beSmmusante if (delta > 0) 23123a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 23133a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 23143a5a36beSmmusante 23153a5a36beSmmusante if (!err) 23163a5a36beSmmusante err = dsl_dir_rename(dd, newname); 2317fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2318fa9e4066Sahrens return (err); 2319fa9e4066Sahrens } 2320fa9e4066Sahrens if (tail[0] != '@') { 2321fa9e4066Sahrens /* the name ended in a nonexistant component */ 2322fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2323fa9e4066Sahrens return (ENOENT); 2324fa9e4066Sahrens } 2325fa9e4066Sahrens 2326fa9e4066Sahrens dsl_dir_close(dd, FTAG); 23271d452cf5Sahrens 23281d452cf5Sahrens /* new name must be snapshot in same filesystem */ 23291d452cf5Sahrens tail = strchr(newname, '@'); 23301d452cf5Sahrens if (tail == NULL) 23311d452cf5Sahrens return (EINVAL); 23321d452cf5Sahrens tail++; 23331d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 23341d452cf5Sahrens return (EXDEV); 23351d452cf5Sahrens 2336cdf5b4caSmmusante if (recursive) { 2337cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 2338cdf5b4caSmmusante } else { 2339745cd3c5Smaybee err = dsl_dataset_hold(oldname, FTAG, &ds); 2340cdf5b4caSmmusante if (err) 2341cdf5b4caSmmusante return (err); 23421d452cf5Sahrens 2343cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2344cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 2345cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 23461d452cf5Sahrens 2347745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2348cdf5b4caSmmusante } 23491d452cf5Sahrens 2350fa9e4066Sahrens return (err); 2351fa9e4066Sahrens } 235299653d4eSeschrock 2353088f3894Sahrens struct promotenode { 2354745cd3c5Smaybee list_node_t link; 2355745cd3c5Smaybee dsl_dataset_t *ds; 2356745cd3c5Smaybee }; 2357745cd3c5Smaybee 23581d452cf5Sahrens struct promotearg { 235974e7dc98SMatthew Ahrens list_t shared_snaps, origin_snaps, clone_snaps; 236074e7dc98SMatthew Ahrens dsl_dataset_t *origin_origin, *origin_head; 236174e7dc98SMatthew Ahrens uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; 23621d452cf5Sahrens }; 23631d452cf5Sahrens 236474e7dc98SMatthew Ahrens static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep); 236574e7dc98SMatthew Ahrens 2366ecd6cf80Smarks /* ARGSUSED */ 236799653d4eSeschrock static int 23681d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 236999653d4eSeschrock { 23701d452cf5Sahrens dsl_dataset_t *hds = arg1; 23711d452cf5Sahrens struct promotearg *pa = arg2; 237274e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2373745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 2374745cd3c5Smaybee int err; 23751d452cf5Sahrens 2376088f3894Sahrens /* Check that it is a real clone */ 2377088f3894Sahrens if (!dsl_dir_is_clone(hds->ds_dir)) 237899653d4eSeschrock return (EINVAL); 237999653d4eSeschrock 23801d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 23811d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 23821d452cf5Sahrens return (0); 23831d452cf5Sahrens 2384745cd3c5Smaybee if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) 2385745cd3c5Smaybee return (EXDEV); 238699653d4eSeschrock 23873cb34c60Sahrens /* compute origin's new unique space */ 238874e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 238974e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 239074e7dc98SMatthew Ahrens err = bplist_space_birthrange(&snap->ds->ds_deadlist, 239174e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, &pa->unique); 239274e7dc98SMatthew Ahrens if (err) 2393745cd3c5Smaybee return (err); 239499653d4eSeschrock 2395745cd3c5Smaybee /* 2396745cd3c5Smaybee * Walk the snapshots that we are moving 2397745cd3c5Smaybee * 239874e7dc98SMatthew Ahrens * Compute space to transfer. Consider the incremental changes 239974e7dc98SMatthew Ahrens * to used for each snapshot: 240074e7dc98SMatthew Ahrens * (my used) = (prev's used) + (blocks born) - (blocks killed) 240174e7dc98SMatthew Ahrens * So each snapshot gave birth to: 240274e7dc98SMatthew Ahrens * (blocks born) = (my used) - (prev's used) + (blocks killed) 2403745cd3c5Smaybee * So a sequence would look like: 240474e7dc98SMatthew Ahrens * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0) 2405745cd3c5Smaybee * Which simplifies to: 240674e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + k1 + k0 2407745cd3c5Smaybee * Note however, if we stop before we reach the ORIGIN we get: 240874e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + kM - uM-1 2409745cd3c5Smaybee */ 2410745cd3c5Smaybee pa->used = origin_ds->ds_phys->ds_used_bytes; 2411745cd3c5Smaybee pa->comp = origin_ds->ds_phys->ds_compressed_bytes; 2412745cd3c5Smaybee pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes; 241374e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 241474e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 241599653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 2416745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 241799653d4eSeschrock 241899653d4eSeschrock /* Check that the snapshot name does not conflict */ 241974e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2420745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); 2421745cd3c5Smaybee if (err == 0) 242274e7dc98SMatthew Ahrens return (EEXIST); 2423745cd3c5Smaybee if (err != ENOENT) 242474e7dc98SMatthew Ahrens return (err); 242599653d4eSeschrock 2426745cd3c5Smaybee /* The very first snapshot does not have a deadlist */ 242774e7dc98SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 242874e7dc98SMatthew Ahrens continue; 242974e7dc98SMatthew Ahrens 243074e7dc98SMatthew Ahrens if (err = bplist_space(&ds->ds_deadlist, 243174e7dc98SMatthew Ahrens &dlused, &dlcomp, &dluncomp)) 243274e7dc98SMatthew Ahrens return (err); 243374e7dc98SMatthew Ahrens pa->used += dlused; 243474e7dc98SMatthew Ahrens pa->comp += dlcomp; 243574e7dc98SMatthew Ahrens pa->uncomp += dluncomp; 243674e7dc98SMatthew Ahrens } 2437745cd3c5Smaybee 2438745cd3c5Smaybee /* 2439745cd3c5Smaybee * If we are a clone of a clone then we never reached ORIGIN, 2440745cd3c5Smaybee * so we need to subtract out the clone origin's used space. 2441745cd3c5Smaybee */ 244274e7dc98SMatthew Ahrens if (pa->origin_origin) { 244374e7dc98SMatthew Ahrens pa->used -= pa->origin_origin->ds_phys->ds_used_bytes; 244474e7dc98SMatthew Ahrens pa->comp -= pa->origin_origin->ds_phys->ds_compressed_bytes; 244574e7dc98SMatthew Ahrens pa->uncomp -= pa->origin_origin->ds_phys->ds_uncompressed_bytes; 244699653d4eSeschrock } 244799653d4eSeschrock 244899653d4eSeschrock /* Check that there is enough space here */ 244974e7dc98SMatthew Ahrens err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir, 245074e7dc98SMatthew Ahrens pa->used); 245174e7dc98SMatthew Ahrens if (err) 245274e7dc98SMatthew Ahrens return (err); 245374e7dc98SMatthew Ahrens 245474e7dc98SMatthew Ahrens /* 245574e7dc98SMatthew Ahrens * Compute the amounts of space that will be used by snapshots 245674e7dc98SMatthew Ahrens * after the promotion (for both origin and clone). For each, 245774e7dc98SMatthew Ahrens * it is the amount of space that will be on all of their 245874e7dc98SMatthew Ahrens * deadlists (that was not born before their new origin). 245974e7dc98SMatthew Ahrens */ 246074e7dc98SMatthew Ahrens if (hds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 246174e7dc98SMatthew Ahrens uint64_t space; 246274e7dc98SMatthew Ahrens 246374e7dc98SMatthew Ahrens /* 246474e7dc98SMatthew Ahrens * Note, typically this will not be a clone of a clone, 246574e7dc98SMatthew Ahrens * so snap->ds->ds_origin_txg will be < TXG_INITIAL, so 246674e7dc98SMatthew Ahrens * these snaplist_space() -> bplist_space_birthrange() 246774e7dc98SMatthew Ahrens * calls will be fast because they do not have to 246874e7dc98SMatthew Ahrens * iterate over all bps. 246974e7dc98SMatthew Ahrens */ 247074e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 247174e7dc98SMatthew Ahrens err = snaplist_space(&pa->shared_snaps, 247274e7dc98SMatthew Ahrens snap->ds->ds_origin_txg, &pa->cloneusedsnap); 247374e7dc98SMatthew Ahrens if (err) 247474e7dc98SMatthew Ahrens return (err); 247574e7dc98SMatthew Ahrens 247674e7dc98SMatthew Ahrens err = snaplist_space(&pa->clone_snaps, 247774e7dc98SMatthew Ahrens snap->ds->ds_origin_txg, &space); 247874e7dc98SMatthew Ahrens if (err) 247974e7dc98SMatthew Ahrens return (err); 248074e7dc98SMatthew Ahrens pa->cloneusedsnap += space; 248174e7dc98SMatthew Ahrens } 248274e7dc98SMatthew Ahrens if (origin_ds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 248374e7dc98SMatthew Ahrens err = snaplist_space(&pa->origin_snaps, 248474e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_creation_txg, &pa->originusedsnap); 248574e7dc98SMatthew Ahrens if (err) 248674e7dc98SMatthew Ahrens return (err); 2487745cd3c5Smaybee } 24881d452cf5Sahrens 248974e7dc98SMatthew Ahrens return (0); 24901d452cf5Sahrens } 249199653d4eSeschrock 24921d452cf5Sahrens static void 2493ecd6cf80Smarks dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 24941d452cf5Sahrens { 24951d452cf5Sahrens dsl_dataset_t *hds = arg1; 24961d452cf5Sahrens struct promotearg *pa = arg2; 249774e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2498745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 249974e7dc98SMatthew Ahrens dsl_dataset_t *origin_head; 25001d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 25011d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 25023cb34c60Sahrens dsl_dir_t *odd = NULL; 2503088f3894Sahrens uint64_t oldnext_obj; 250474e7dc98SMatthew Ahrens int64_t delta; 25051d452cf5Sahrens 25061d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 25071d452cf5Sahrens 250874e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 250974e7dc98SMatthew Ahrens origin_head = snap->ds; 251074e7dc98SMatthew Ahrens 25110b69c2f0Sahrens /* 25123cb34c60Sahrens * We need to explicitly open odd, since origin_ds's dd will be 25130b69c2f0Sahrens * changing. 25140b69c2f0Sahrens */ 25153cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object, 25163cb34c60Sahrens NULL, FTAG, &odd)); 251799653d4eSeschrock 2518745cd3c5Smaybee /* change origin's next snap */ 2519745cd3c5Smaybee dmu_buf_will_dirty(origin_ds->ds_dbuf, tx); 2520088f3894Sahrens oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj; 252174e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 252274e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 252374e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj = snap->ds->ds_object; 2524745cd3c5Smaybee 2525088f3894Sahrens /* change the origin's next clone */ 2526088f3894Sahrens if (origin_ds->ds_phys->ds_next_clones_obj) { 2527088f3894Sahrens VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2528088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 252974e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj, tx)); 2530088f3894Sahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2531088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2532088f3894Sahrens oldnext_obj, tx)); 2533088f3894Sahrens } 2534088f3894Sahrens 2535745cd3c5Smaybee /* change origin */ 2536745cd3c5Smaybee dmu_buf_will_dirty(dd->dd_dbuf, tx); 2537745cd3c5Smaybee ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object); 2538745cd3c5Smaybee dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj; 253974e7dc98SMatthew Ahrens hds->ds_origin_txg = origin_head->ds_origin_txg; 2540745cd3c5Smaybee dmu_buf_will_dirty(odd->dd_dbuf, tx); 2541745cd3c5Smaybee odd->dd_phys->dd_origin_obj = origin_ds->ds_object; 254274e7dc98SMatthew Ahrens origin_head->ds_origin_txg = origin_ds->ds_phys->ds_creation_txg; 2543745cd3c5Smaybee 254499653d4eSeschrock /* move snapshots to this dir */ 254574e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 254674e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 2547745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 254899653d4eSeschrock 25493baa08fcSek /* unregister props as dsl_dir is changing */ 2550503ad85cSMatthew Ahrens if (ds->ds_objset) { 2551503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 2552503ad85cSMatthew Ahrens ds->ds_objset = NULL; 25533baa08fcSek } 255499653d4eSeschrock /* move snap name entry */ 255574e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 255674e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_snap_remove(origin_head, 2557745cd3c5Smaybee ds->ds_snapname, tx)); 25581d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 255999653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 256099653d4eSeschrock 8, 1, &ds->ds_object, tx)); 256199653d4eSeschrock /* change containing dsl_dir */ 256299653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 25633cb34c60Sahrens ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object); 256499653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 25653cb34c60Sahrens ASSERT3P(ds->ds_dir, ==, odd); 256699653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 25671d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 256899653d4eSeschrock NULL, ds, &ds->ds_dir)); 256999653d4eSeschrock 257099653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 257174e7dc98SMatthew Ahrens } 257274e7dc98SMatthew Ahrens 257374e7dc98SMatthew Ahrens /* 257474e7dc98SMatthew Ahrens * Change space accounting. 257574e7dc98SMatthew Ahrens * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either 257674e7dc98SMatthew Ahrens * both be valid, or both be 0 (resulting in delta == 0). This 257774e7dc98SMatthew Ahrens * is true for each of {clone,origin} independently. 257874e7dc98SMatthew Ahrens */ 257974e7dc98SMatthew Ahrens 258074e7dc98SMatthew Ahrens delta = pa->cloneusedsnap - 258174e7dc98SMatthew Ahrens dd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 258274e7dc98SMatthew Ahrens ASSERT3S(delta, >=, 0); 258374e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, delta); 258474e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx); 258574e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_HEAD, 258674e7dc98SMatthew Ahrens pa->used - delta, pa->comp, pa->uncomp, tx); 258774e7dc98SMatthew Ahrens 258874e7dc98SMatthew Ahrens delta = pa->originusedsnap - 258974e7dc98SMatthew Ahrens odd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 259074e7dc98SMatthew Ahrens ASSERT3S(delta, <=, 0); 259174e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, -delta); 259274e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx); 259374e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_HEAD, 259474e7dc98SMatthew Ahrens -pa->used - delta, -pa->comp, -pa->uncomp, tx); 259599653d4eSeschrock 25963cb34c60Sahrens origin_ds->ds_phys->ds_unique_bytes = pa->unique; 259799653d4eSeschrock 2598ecd6cf80Smarks /* log history record */ 2599ecd6cf80Smarks spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 2600745cd3c5Smaybee cr, "dataset = %llu", hds->ds_object); 2601ecd6cf80Smarks 26023cb34c60Sahrens dsl_dir_close(odd, FTAG); 260399653d4eSeschrock } 260499653d4eSeschrock 260574e7dc98SMatthew Ahrens static char *snaplist_tag = "snaplist"; 260674e7dc98SMatthew Ahrens /* 260774e7dc98SMatthew Ahrens * Make a list of dsl_dataset_t's for the snapshots between first_obj 260874e7dc98SMatthew Ahrens * (exclusive) and last_obj (inclusive). The list will be in reverse 260974e7dc98SMatthew Ahrens * order (last_obj will be the list_head()). If first_obj == 0, do all 261074e7dc98SMatthew Ahrens * snapshots back to this dataset's origin. 261174e7dc98SMatthew Ahrens */ 261274e7dc98SMatthew Ahrens static int 261374e7dc98SMatthew Ahrens snaplist_make(dsl_pool_t *dp, boolean_t own, 261474e7dc98SMatthew Ahrens uint64_t first_obj, uint64_t last_obj, list_t *l) 261574e7dc98SMatthew Ahrens { 261674e7dc98SMatthew Ahrens uint64_t obj = last_obj; 261774e7dc98SMatthew Ahrens 261874e7dc98SMatthew Ahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock)); 261974e7dc98SMatthew Ahrens 262074e7dc98SMatthew Ahrens list_create(l, sizeof (struct promotenode), 262174e7dc98SMatthew Ahrens offsetof(struct promotenode, link)); 262274e7dc98SMatthew Ahrens 262374e7dc98SMatthew Ahrens while (obj != first_obj) { 262474e7dc98SMatthew Ahrens dsl_dataset_t *ds; 262574e7dc98SMatthew Ahrens struct promotenode *snap; 262674e7dc98SMatthew Ahrens int err; 262774e7dc98SMatthew Ahrens 262874e7dc98SMatthew Ahrens if (own) { 262974e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, obj, 263074e7dc98SMatthew Ahrens 0, snaplist_tag, &ds); 263174e7dc98SMatthew Ahrens if (err == 0) 263274e7dc98SMatthew Ahrens dsl_dataset_make_exclusive(ds, snaplist_tag); 263374e7dc98SMatthew Ahrens } else { 263474e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, obj, snaplist_tag, &ds); 263574e7dc98SMatthew Ahrens } 263674e7dc98SMatthew Ahrens if (err == ENOENT) { 263774e7dc98SMatthew Ahrens /* lost race with snapshot destroy */ 263874e7dc98SMatthew Ahrens struct promotenode *last = list_tail(l); 263974e7dc98SMatthew Ahrens ASSERT(obj != last->ds->ds_phys->ds_prev_snap_obj); 264074e7dc98SMatthew Ahrens obj = last->ds->ds_phys->ds_prev_snap_obj; 264174e7dc98SMatthew Ahrens continue; 264274e7dc98SMatthew Ahrens } else if (err) { 264374e7dc98SMatthew Ahrens return (err); 264474e7dc98SMatthew Ahrens } 264574e7dc98SMatthew Ahrens 264674e7dc98SMatthew Ahrens if (first_obj == 0) 264774e7dc98SMatthew Ahrens first_obj = ds->ds_dir->dd_phys->dd_origin_obj; 264874e7dc98SMatthew Ahrens 264974e7dc98SMatthew Ahrens snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP); 265074e7dc98SMatthew Ahrens snap->ds = ds; 265174e7dc98SMatthew Ahrens list_insert_tail(l, snap); 265274e7dc98SMatthew Ahrens obj = ds->ds_phys->ds_prev_snap_obj; 265374e7dc98SMatthew Ahrens } 265474e7dc98SMatthew Ahrens 265574e7dc98SMatthew Ahrens return (0); 265674e7dc98SMatthew Ahrens } 265774e7dc98SMatthew Ahrens 265874e7dc98SMatthew Ahrens static int 265974e7dc98SMatthew Ahrens snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep) 266074e7dc98SMatthew Ahrens { 266174e7dc98SMatthew Ahrens struct promotenode *snap; 266274e7dc98SMatthew Ahrens 266374e7dc98SMatthew Ahrens *spacep = 0; 266474e7dc98SMatthew Ahrens for (snap = list_head(l); snap; snap = list_next(l, snap)) { 266574e7dc98SMatthew Ahrens uint64_t used; 266674e7dc98SMatthew Ahrens int err = bplist_space_birthrange(&snap->ds->ds_deadlist, 266774e7dc98SMatthew Ahrens mintxg, UINT64_MAX, &used); 266874e7dc98SMatthew Ahrens if (err) 266974e7dc98SMatthew Ahrens return (err); 267074e7dc98SMatthew Ahrens *spacep += used; 267174e7dc98SMatthew Ahrens } 267274e7dc98SMatthew Ahrens return (0); 267374e7dc98SMatthew Ahrens } 267474e7dc98SMatthew Ahrens 267574e7dc98SMatthew Ahrens static void 267674e7dc98SMatthew Ahrens snaplist_destroy(list_t *l, boolean_t own) 267774e7dc98SMatthew Ahrens { 267874e7dc98SMatthew Ahrens struct promotenode *snap; 267974e7dc98SMatthew Ahrens 26804f5064b7SMark J Musante if (!l || !list_link_active(&l->list_head)) 268174e7dc98SMatthew Ahrens return; 268274e7dc98SMatthew Ahrens 268374e7dc98SMatthew Ahrens while ((snap = list_tail(l)) != NULL) { 268474e7dc98SMatthew Ahrens list_remove(l, snap); 268574e7dc98SMatthew Ahrens if (own) 268674e7dc98SMatthew Ahrens dsl_dataset_disown(snap->ds, snaplist_tag); 268774e7dc98SMatthew Ahrens else 268874e7dc98SMatthew Ahrens dsl_dataset_rele(snap->ds, snaplist_tag); 268974e7dc98SMatthew Ahrens kmem_free(snap, sizeof (struct promotenode)); 269074e7dc98SMatthew Ahrens } 269174e7dc98SMatthew Ahrens list_destroy(l); 269274e7dc98SMatthew Ahrens } 269374e7dc98SMatthew Ahrens 269474e7dc98SMatthew Ahrens /* 269574e7dc98SMatthew Ahrens * Promote a clone. Nomenclature note: 269674e7dc98SMatthew Ahrens * "clone" or "cds": the original clone which is being promoted 269774e7dc98SMatthew Ahrens * "origin" or "ods": the snapshot which is originally clone's origin 269874e7dc98SMatthew Ahrens * "origin head" or "ohds": the dataset which is the head 269974e7dc98SMatthew Ahrens * (filesystem/volume) for the origin 270074e7dc98SMatthew Ahrens * "origin origin": the origin of the origin's filesystem (typically 270174e7dc98SMatthew Ahrens * NULL, indicating that the clone is not a clone of a clone). 270274e7dc98SMatthew Ahrens */ 270399653d4eSeschrock int 270499653d4eSeschrock dsl_dataset_promote(const char *name) 270599653d4eSeschrock { 270699653d4eSeschrock dsl_dataset_t *ds; 2707745cd3c5Smaybee dsl_dir_t *dd; 2708745cd3c5Smaybee dsl_pool_t *dp; 270999653d4eSeschrock dmu_object_info_t doi; 271074e7dc98SMatthew Ahrens struct promotearg pa = { 0 }; 2711088f3894Sahrens struct promotenode *snap; 2712745cd3c5Smaybee int err; 271399653d4eSeschrock 2714745cd3c5Smaybee err = dsl_dataset_hold(name, FTAG, &ds); 271599653d4eSeschrock if (err) 271699653d4eSeschrock return (err); 2717745cd3c5Smaybee dd = ds->ds_dir; 2718745cd3c5Smaybee dp = dd->dd_pool; 271999653d4eSeschrock 2720745cd3c5Smaybee err = dmu_object_info(dp->dp_meta_objset, 272199653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 272299653d4eSeschrock if (err) { 2723745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 272499653d4eSeschrock return (err); 272599653d4eSeschrock } 272699653d4eSeschrock 272774e7dc98SMatthew Ahrens if (dsl_dataset_is_snapshot(ds) || dd->dd_phys->dd_origin_obj == 0) { 272874e7dc98SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 272974e7dc98SMatthew Ahrens return (EINVAL); 273074e7dc98SMatthew Ahrens } 273174e7dc98SMatthew Ahrens 2732745cd3c5Smaybee /* 2733745cd3c5Smaybee * We are going to inherit all the snapshots taken before our 2734745cd3c5Smaybee * origin (i.e., our new origin will be our parent's origin). 2735745cd3c5Smaybee * Take ownership of them so that we can rename them into our 2736745cd3c5Smaybee * namespace. 2737745cd3c5Smaybee */ 2738745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 2739088f3894Sahrens 274074e7dc98SMatthew Ahrens err = snaplist_make(dp, B_TRUE, 0, dd->dd_phys->dd_origin_obj, 274174e7dc98SMatthew Ahrens &pa.shared_snaps); 274274e7dc98SMatthew Ahrens if (err != 0) 274374e7dc98SMatthew Ahrens goto out; 2744088f3894Sahrens 274574e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, 0, ds->ds_object, &pa.clone_snaps); 274674e7dc98SMatthew Ahrens if (err != 0) 274774e7dc98SMatthew Ahrens goto out; 2748088f3894Sahrens 274974e7dc98SMatthew Ahrens snap = list_head(&pa.shared_snaps); 275074e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_object, ==, dd->dd_phys->dd_origin_obj); 275174e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, dd->dd_phys->dd_origin_obj, 275274e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, &pa.origin_snaps); 275374e7dc98SMatthew Ahrens if (err != 0) 275474e7dc98SMatthew Ahrens goto out; 2755088f3894Sahrens 275674e7dc98SMatthew Ahrens if (dsl_dir_is_clone(snap->ds->ds_dir)) { 275774e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, 275874e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_origin_obj, 275974e7dc98SMatthew Ahrens 0, FTAG, &pa.origin_origin); 276074e7dc98SMatthew Ahrens if (err != 0) 276174e7dc98SMatthew Ahrens goto out; 276274e7dc98SMatthew Ahrens } 2763745cd3c5Smaybee 276474e7dc98SMatthew Ahrens out: 276574e7dc98SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 2766745cd3c5Smaybee 276799653d4eSeschrock /* 276899653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 276999653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 277099653d4eSeschrock * bonus buffers. 277199653d4eSeschrock */ 277274e7dc98SMatthew Ahrens if (err == 0) { 277374e7dc98SMatthew Ahrens err = dsl_sync_task_do(dp, dsl_dataset_promote_check, 277474e7dc98SMatthew Ahrens dsl_dataset_promote_sync, ds, &pa, 277574e7dc98SMatthew Ahrens 2 + 2 * doi.doi_physical_blks); 2776745cd3c5Smaybee } 277774e7dc98SMatthew Ahrens 277874e7dc98SMatthew Ahrens snaplist_destroy(&pa.shared_snaps, B_TRUE); 277974e7dc98SMatthew Ahrens snaplist_destroy(&pa.clone_snaps, B_FALSE); 278074e7dc98SMatthew Ahrens snaplist_destroy(&pa.origin_snaps, B_FALSE); 278174e7dc98SMatthew Ahrens if (pa.origin_origin) 278274e7dc98SMatthew Ahrens dsl_dataset_disown(pa.origin_origin, FTAG); 2783745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 278499653d4eSeschrock return (err); 278599653d4eSeschrock } 2786b1b8ab34Slling 27873cb34c60Sahrens struct cloneswaparg { 27883cb34c60Sahrens dsl_dataset_t *cds; /* clone dataset */ 27893cb34c60Sahrens dsl_dataset_t *ohds; /* origin's head dataset */ 27903cb34c60Sahrens boolean_t force; 2791a9b821a0Sck int64_t unused_refres_delta; /* change in unconsumed refreservation */ 27923cb34c60Sahrens }; 2793f18faf3fSek 2794f18faf3fSek /* ARGSUSED */ 2795f18faf3fSek static int 2796f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 2797f18faf3fSek { 27983cb34c60Sahrens struct cloneswaparg *csa = arg1; 2799f18faf3fSek 28003cb34c60Sahrens /* they should both be heads */ 28013cb34c60Sahrens if (dsl_dataset_is_snapshot(csa->cds) || 28023cb34c60Sahrens dsl_dataset_is_snapshot(csa->ohds)) 2803f18faf3fSek return (EINVAL); 2804f18faf3fSek 28053cb34c60Sahrens /* the branch point should be just before them */ 28063cb34c60Sahrens if (csa->cds->ds_prev != csa->ohds->ds_prev) 2807f18faf3fSek return (EINVAL); 2808f18faf3fSek 2809ae46e4c7SMatthew Ahrens /* cds should be the clone (unless they are unrelated) */ 2810ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev != NULL && 2811ae46e4c7SMatthew Ahrens csa->cds->ds_prev != csa->cds->ds_dir->dd_pool->dp_origin_snap && 2812ae46e4c7SMatthew Ahrens csa->ohds->ds_object != 2813ae46e4c7SMatthew Ahrens csa->cds->ds_prev->ds_phys->ds_next_snap_obj) 28143cb34c60Sahrens return (EINVAL); 2815f18faf3fSek 28163cb34c60Sahrens /* the clone should be a child of the origin */ 28173cb34c60Sahrens if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir) 28183cb34c60Sahrens return (EINVAL); 2819f18faf3fSek 28203cb34c60Sahrens /* ohds shouldn't be modified unless 'force' */ 28213cb34c60Sahrens if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) 28223cb34c60Sahrens return (ETXTBSY); 2823a9b821a0Sck 2824a9b821a0Sck /* adjust amount of any unconsumed refreservation */ 2825a9b821a0Sck csa->unused_refres_delta = 2826a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 2827a9b821a0Sck csa->ohds->ds_phys->ds_unique_bytes) - 2828a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 2829a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 2830a9b821a0Sck 2831a9b821a0Sck if (csa->unused_refres_delta > 0 && 2832a9b821a0Sck csa->unused_refres_delta > 2833a9b821a0Sck dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) 2834a9b821a0Sck return (ENOSPC); 2835a9b821a0Sck 28363cb34c60Sahrens return (0); 2837f18faf3fSek } 2838f18faf3fSek 2839f18faf3fSek /* ARGSUSED */ 2840f18faf3fSek static void 2841f18faf3fSek dsl_dataset_clone_swap_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 2842f18faf3fSek { 28433cb34c60Sahrens struct cloneswaparg *csa = arg1; 28443cb34c60Sahrens dsl_pool_t *dp = csa->cds->ds_dir->dd_pool; 2845f18faf3fSek 2846a9b821a0Sck ASSERT(csa->cds->ds_reserved == 0); 2847a9b821a0Sck ASSERT(csa->cds->ds_quota == csa->ohds->ds_quota); 2848a9b821a0Sck 28493cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); 28503cb34c60Sahrens dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); 2851f18faf3fSek 2852503ad85cSMatthew Ahrens if (csa->cds->ds_objset != NULL) { 2853503ad85cSMatthew Ahrens dmu_objset_evict(csa->cds->ds_objset); 2854503ad85cSMatthew Ahrens csa->cds->ds_objset = NULL; 28553cb34c60Sahrens } 2856f18faf3fSek 2857503ad85cSMatthew Ahrens if (csa->ohds->ds_objset != NULL) { 2858503ad85cSMatthew Ahrens dmu_objset_evict(csa->ohds->ds_objset); 2859503ad85cSMatthew Ahrens csa->ohds->ds_objset = NULL; 28603cb34c60Sahrens } 2861f18faf3fSek 2862ae46e4c7SMatthew Ahrens /* 2863ae46e4c7SMatthew Ahrens * Reset origin's unique bytes, if it exists. 2864ae46e4c7SMatthew Ahrens */ 2865ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev) { 2866ae46e4c7SMatthew Ahrens dsl_dataset_t *origin = csa->cds->ds_prev; 2867ae46e4c7SMatthew Ahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 2868ae46e4c7SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->cds->ds_deadlist, 2869ae46e4c7SMatthew Ahrens origin->ds_phys->ds_prev_snap_txg, UINT64_MAX, 2870ae46e4c7SMatthew Ahrens &origin->ds_phys->ds_unique_bytes)); 2871ae46e4c7SMatthew Ahrens } 2872f18faf3fSek 2873f18faf3fSek /* swap blkptrs */ 2874f18faf3fSek { 2875f18faf3fSek blkptr_t tmp; 28763cb34c60Sahrens tmp = csa->ohds->ds_phys->ds_bp; 28773cb34c60Sahrens csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp; 28783cb34c60Sahrens csa->cds->ds_phys->ds_bp = tmp; 2879f18faf3fSek } 2880f18faf3fSek 2881f18faf3fSek /* set dd_*_bytes */ 2882f18faf3fSek { 2883f18faf3fSek int64_t dused, dcomp, duncomp; 2884f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 2885f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 2886f18faf3fSek 288774e7dc98SMatthew Ahrens ASSERT3U(csa->cds->ds_dir->dd_phys-> 288874e7dc98SMatthew Ahrens dd_used_breakdown[DD_USED_SNAP], ==, 0); 288974e7dc98SMatthew Ahrens 28903cb34c60Sahrens VERIFY(0 == bplist_space(&csa->cds->ds_deadlist, &cdl_used, 2891f18faf3fSek &cdl_comp, &cdl_uncomp)); 28923cb34c60Sahrens VERIFY(0 == bplist_space(&csa->ohds->ds_deadlist, &odl_used, 2893f18faf3fSek &odl_comp, &odl_uncomp)); 289474e7dc98SMatthew Ahrens 28953cb34c60Sahrens dused = csa->cds->ds_phys->ds_used_bytes + cdl_used - 28963cb34c60Sahrens (csa->ohds->ds_phys->ds_used_bytes + odl_used); 28973cb34c60Sahrens dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp - 28983cb34c60Sahrens (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp); 28993cb34c60Sahrens duncomp = csa->cds->ds_phys->ds_uncompressed_bytes + 29003cb34c60Sahrens cdl_uncomp - 29013cb34c60Sahrens (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 29023cb34c60Sahrens 290374e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_HEAD, 29043cb34c60Sahrens dused, dcomp, duncomp, tx); 290574e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->cds->ds_dir, DD_USED_HEAD, 29063cb34c60Sahrens -dused, -dcomp, -duncomp, tx); 290774e7dc98SMatthew Ahrens 290874e7dc98SMatthew Ahrens /* 290974e7dc98SMatthew Ahrens * The difference in the space used by snapshots is the 291074e7dc98SMatthew Ahrens * difference in snapshot space due to the head's 291174e7dc98SMatthew Ahrens * deadlist (since that's the only thing that's 291274e7dc98SMatthew Ahrens * changing that affects the snapused). 291374e7dc98SMatthew Ahrens */ 291474e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->cds->ds_deadlist, 291574e7dc98SMatthew Ahrens csa->ohds->ds_origin_txg, UINT64_MAX, &cdl_used)); 291674e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->ohds->ds_deadlist, 291774e7dc98SMatthew Ahrens csa->ohds->ds_origin_txg, UINT64_MAX, &odl_used)); 291874e7dc98SMatthew Ahrens dsl_dir_transfer_space(csa->ohds->ds_dir, cdl_used - odl_used, 291974e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 29203cb34c60Sahrens } 29213cb34c60Sahrens 29223cb34c60Sahrens #define SWITCH64(x, y) \ 29233cb34c60Sahrens { \ 29243cb34c60Sahrens uint64_t __tmp = (x); \ 29253cb34c60Sahrens (x) = (y); \ 29263cb34c60Sahrens (y) = __tmp; \ 2927f18faf3fSek } 2928f18faf3fSek 2929f18faf3fSek /* swap ds_*_bytes */ 29303cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_used_bytes, 29313cb34c60Sahrens csa->cds->ds_phys->ds_used_bytes); 29323cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes, 29333cb34c60Sahrens csa->cds->ds_phys->ds_compressed_bytes); 29343cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, 29353cb34c60Sahrens csa->cds->ds_phys->ds_uncompressed_bytes); 2936a9b821a0Sck SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, 2937a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 2938a9b821a0Sck 2939a9b821a0Sck /* apply any parent delta for change in unconsumed refreservation */ 294074e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_REFRSRV, 294174e7dc98SMatthew Ahrens csa->unused_refres_delta, 0, 0, tx); 2942f18faf3fSek 2943f18faf3fSek /* swap deadlists */ 29443cb34c60Sahrens bplist_close(&csa->cds->ds_deadlist); 29453cb34c60Sahrens bplist_close(&csa->ohds->ds_deadlist); 29463cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj, 29473cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj); 29483cb34c60Sahrens VERIFY(0 == bplist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset, 29493cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj)); 29503cb34c60Sahrens VERIFY(0 == bplist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, 29513cb34c60Sahrens csa->ohds->ds_phys->ds_deadlist_obj)); 295288b7b0f2SMatthew Ahrens 295388b7b0f2SMatthew Ahrens dsl_pool_ds_clone_swapped(csa->ohds, csa->cds, tx); 2954f18faf3fSek } 2955f18faf3fSek 2956f18faf3fSek /* 2957ae46e4c7SMatthew Ahrens * Swap 'clone' with its origin head datasets. Used at the end of "zfs 2958ae46e4c7SMatthew Ahrens * recv" into an existing fs to swizzle the file system to the new 2959ae46e4c7SMatthew Ahrens * version, and by "zfs rollback". Can also be used to swap two 2960ae46e4c7SMatthew Ahrens * independent head datasets if neither has any snapshots. 2961f18faf3fSek */ 2962f18faf3fSek int 29633cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, 29643cb34c60Sahrens boolean_t force) 2965f18faf3fSek { 29663cb34c60Sahrens struct cloneswaparg csa; 2967745cd3c5Smaybee int error; 2968f18faf3fSek 2969745cd3c5Smaybee ASSERT(clone->ds_owner); 2970745cd3c5Smaybee ASSERT(origin_head->ds_owner); 2971745cd3c5Smaybee retry: 2972745cd3c5Smaybee /* Need exclusive access for the swap */ 2973745cd3c5Smaybee rw_enter(&clone->ds_rwlock, RW_WRITER); 2974745cd3c5Smaybee if (!rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) { 2975745cd3c5Smaybee rw_exit(&clone->ds_rwlock); 2976745cd3c5Smaybee rw_enter(&origin_head->ds_rwlock, RW_WRITER); 2977745cd3c5Smaybee if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) { 2978745cd3c5Smaybee rw_exit(&origin_head->ds_rwlock); 2979745cd3c5Smaybee goto retry; 2980745cd3c5Smaybee } 2981745cd3c5Smaybee } 29823cb34c60Sahrens csa.cds = clone; 29833cb34c60Sahrens csa.ohds = origin_head; 29843cb34c60Sahrens csa.force = force; 2985745cd3c5Smaybee error = dsl_sync_task_do(clone->ds_dir->dd_pool, 2986f18faf3fSek dsl_dataset_clone_swap_check, 2987745cd3c5Smaybee dsl_dataset_clone_swap_sync, &csa, NULL, 9); 2988745cd3c5Smaybee return (error); 2989f18faf3fSek } 2990f18faf3fSek 2991b1b8ab34Slling /* 2992b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 2993b1b8ab34Slling * return the name of that dataset. 2994b1b8ab34Slling */ 2995b1b8ab34Slling int 2996b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 2997b1b8ab34Slling { 2998b1b8ab34Slling spa_t *spa; 2999b1b8ab34Slling dsl_pool_t *dp; 3000745cd3c5Smaybee dsl_dataset_t *ds; 3001b1b8ab34Slling int error; 3002b1b8ab34Slling 3003b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 3004b1b8ab34Slling return (error); 3005b1b8ab34Slling dp = spa_get_dsl(spa); 3006b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 3007745cd3c5Smaybee if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) { 3008745cd3c5Smaybee dsl_dataset_name(ds, buf); 3009745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3010b1b8ab34Slling } 3011b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 3012b1b8ab34Slling spa_close(spa, FTAG); 3013b1b8ab34Slling 3014745cd3c5Smaybee return (error); 3015b1b8ab34Slling } 3016a9799022Sck 3017a9799022Sck int 3018a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, 3019745cd3c5Smaybee uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv) 3020a9799022Sck { 3021a9799022Sck int error = 0; 3022a9799022Sck 3023a9799022Sck ASSERT3S(asize, >, 0); 3024a9799022Sck 30259082849eSck /* 30269082849eSck * *ref_rsrv is the portion of asize that will come from any 30279082849eSck * unconsumed refreservation space. 30289082849eSck */ 30299082849eSck *ref_rsrv = 0; 30309082849eSck 3031a9799022Sck mutex_enter(&ds->ds_lock); 3032a9799022Sck /* 3033a9799022Sck * Make a space adjustment for reserved bytes. 3034a9799022Sck */ 3035a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) { 3036a9799022Sck ASSERT3U(*used, >=, 3037a9799022Sck ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 3038a9799022Sck *used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 30399082849eSck *ref_rsrv = 30409082849eSck asize - MIN(asize, parent_delta(ds, asize + inflight)); 3041a9799022Sck } 3042a9799022Sck 3043a9799022Sck if (!check_quota || ds->ds_quota == 0) { 3044a9799022Sck mutex_exit(&ds->ds_lock); 3045a9799022Sck return (0); 3046a9799022Sck } 3047a9799022Sck /* 3048a9799022Sck * If they are requesting more space, and our current estimate 3049a9799022Sck * is over quota, they get to try again unless the actual 3050a9799022Sck * on-disk is over quota and there are no pending changes (which 3051a9799022Sck * may free up space for us). 3052a9799022Sck */ 3053a9799022Sck if (ds->ds_phys->ds_used_bytes + inflight >= ds->ds_quota) { 3054a9799022Sck if (inflight > 0 || ds->ds_phys->ds_used_bytes < ds->ds_quota) 3055a9799022Sck error = ERESTART; 3056a9799022Sck else 3057a9799022Sck error = EDQUOT; 3058a9799022Sck } 3059a9799022Sck mutex_exit(&ds->ds_lock); 3060a9799022Sck 3061a9799022Sck return (error); 3062a9799022Sck } 3063a9799022Sck 3064a9799022Sck /* ARGSUSED */ 3065a9799022Sck static int 3066a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx) 3067a9799022Sck { 3068a9799022Sck dsl_dataset_t *ds = arg1; 3069a9799022Sck uint64_t *quotap = arg2; 3070a9799022Sck uint64_t new_quota = *quotap; 3071a9799022Sck 3072a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA) 3073a9799022Sck return (ENOTSUP); 3074a9799022Sck 3075a9799022Sck if (new_quota == 0) 3076a9799022Sck return (0); 3077a9799022Sck 3078a9799022Sck if (new_quota < ds->ds_phys->ds_used_bytes || 3079a9799022Sck new_quota < ds->ds_reserved) 3080a9799022Sck return (ENOSPC); 3081a9799022Sck 3082a9799022Sck return (0); 3083a9799022Sck } 3084a9799022Sck 3085a9799022Sck /* ARGSUSED */ 3086a9799022Sck void 3087a9799022Sck dsl_dataset_set_quota_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3088a9799022Sck { 3089a9799022Sck dsl_dataset_t *ds = arg1; 3090a9799022Sck uint64_t *quotap = arg2; 3091a9799022Sck uint64_t new_quota = *quotap; 3092a9799022Sck 3093a9799022Sck dmu_buf_will_dirty(ds->ds_dbuf, tx); 3094a9799022Sck 3095a9799022Sck ds->ds_quota = new_quota; 3096a9799022Sck 3097842727c2SChris Kirby dsl_dir_prop_set_uint64_sync(ds->ds_dir, "refquota", new_quota, cr, tx); 3098a9799022Sck 3099a9799022Sck spa_history_internal_log(LOG_DS_REFQUOTA, ds->ds_dir->dd_pool->dp_spa, 3100a9799022Sck tx, cr, "%lld dataset = %llu ", 3101745cd3c5Smaybee (longlong_t)new_quota, ds->ds_object); 3102a9799022Sck } 3103a9799022Sck 3104a9799022Sck int 3105a9799022Sck dsl_dataset_set_quota(const char *dsname, uint64_t quota) 3106a9799022Sck { 3107a9799022Sck dsl_dataset_t *ds; 3108a9799022Sck int err; 3109a9799022Sck 3110745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3111a9799022Sck if (err) 3112a9799022Sck return (err); 3113a9799022Sck 3114a9b821a0Sck if (quota != ds->ds_quota) { 3115a9b821a0Sck /* 3116a9b821a0Sck * If someone removes a file, then tries to set the quota, we 3117a9b821a0Sck * want to make sure the file freeing takes effect. 3118a9b821a0Sck */ 3119a9b821a0Sck txg_wait_open(ds->ds_dir->dd_pool, 0); 3120a9799022Sck 3121a9b821a0Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3122a9b821a0Sck dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, 3123a9b821a0Sck ds, "a, 0); 3124a9b821a0Sck } 3125745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3126a9799022Sck return (err); 3127a9799022Sck } 3128a9799022Sck 3129a9799022Sck static int 3130a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx) 3131a9799022Sck { 3132a9799022Sck dsl_dataset_t *ds = arg1; 3133a9799022Sck uint64_t *reservationp = arg2; 3134a9799022Sck uint64_t new_reservation = *reservationp; 3135a9799022Sck uint64_t unique; 3136a9799022Sck 3137a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 3138a9799022Sck SPA_VERSION_REFRESERVATION) 3139a9799022Sck return (ENOTSUP); 3140a9799022Sck 3141a9799022Sck if (dsl_dataset_is_snapshot(ds)) 3142a9799022Sck return (EINVAL); 3143a9799022Sck 3144a9799022Sck /* 3145a9799022Sck * If we are doing the preliminary check in open context, the 3146a9799022Sck * space estimates may be inaccurate. 3147a9799022Sck */ 3148a9799022Sck if (!dmu_tx_is_syncing(tx)) 3149a9799022Sck return (0); 3150a9799022Sck 3151a9799022Sck mutex_enter(&ds->ds_lock); 3152a9799022Sck unique = dsl_dataset_unique(ds); 3153a9799022Sck mutex_exit(&ds->ds_lock); 3154a9799022Sck 3155379c004dSEric Schrock if (MAX(unique, new_reservation) > MAX(unique, ds->ds_reserved)) { 3156379c004dSEric Schrock uint64_t delta = MAX(unique, new_reservation) - 3157379c004dSEric Schrock MAX(unique, ds->ds_reserved); 3158379c004dSEric Schrock 3159379c004dSEric Schrock if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 3160379c004dSEric Schrock return (ENOSPC); 3161379c004dSEric Schrock if (ds->ds_quota > 0 && 3162379c004dSEric Schrock new_reservation > ds->ds_quota) 3163379c004dSEric Schrock return (ENOSPC); 3164379c004dSEric Schrock } 3165a9799022Sck 3166a9799022Sck return (0); 3167a9799022Sck } 3168a9799022Sck 3169a9799022Sck /* ARGSUSED */ 3170a9799022Sck static void 3171a9799022Sck dsl_dataset_set_reservation_sync(void *arg1, void *arg2, cred_t *cr, 3172a9799022Sck dmu_tx_t *tx) 3173a9799022Sck { 3174a9799022Sck dsl_dataset_t *ds = arg1; 3175a9799022Sck uint64_t *reservationp = arg2; 3176a9799022Sck uint64_t new_reservation = *reservationp; 317702c8f3f0SMatthew Ahrens uint64_t unique; 317802c8f3f0SMatthew Ahrens int64_t delta; 317902c8f3f0SMatthew Ahrens 318002c8f3f0SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 318102c8f3f0SMatthew Ahrens 318202c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 318302c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_lock); 318402c8f3f0SMatthew Ahrens unique = dsl_dataset_unique(ds); 318502c8f3f0SMatthew Ahrens delta = MAX(0, (int64_t)(new_reservation - unique)) - 318602c8f3f0SMatthew Ahrens MAX(0, (int64_t)(ds->ds_reserved - unique)); 318702c8f3f0SMatthew Ahrens ds->ds_reserved = new_reservation; 318802c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_lock); 318902c8f3f0SMatthew Ahrens 319002c8f3f0SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx); 319102c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 3192842727c2SChris Kirby dsl_dir_prop_set_uint64_sync(ds->ds_dir, "refreservation", 319302c8f3f0SMatthew Ahrens new_reservation, cr, tx); 3194a9799022Sck 319502c8f3f0SMatthew Ahrens spa_history_internal_log(LOG_DS_REFRESERV, 319602c8f3f0SMatthew Ahrens ds->ds_dir->dd_pool->dp_spa, tx, cr, "%lld dataset = %llu", 319702c8f3f0SMatthew Ahrens (longlong_t)new_reservation, ds->ds_object); 3198a9799022Sck } 3199a9799022Sck 3200a9799022Sck int 3201a9799022Sck dsl_dataset_set_reservation(const char *dsname, uint64_t reservation) 3202a9799022Sck { 3203a9799022Sck dsl_dataset_t *ds; 3204a9799022Sck int err; 3205a9799022Sck 3206745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3207a9799022Sck if (err) 3208a9799022Sck return (err); 3209a9799022Sck 3210a9799022Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3211a9799022Sck dsl_dataset_set_reservation_check, 3212a9799022Sck dsl_dataset_set_reservation_sync, ds, &reservation, 0); 3213745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3214a9799022Sck return (err); 3215a9799022Sck } 3216842727c2SChris Kirby 3217ca45db41SChris Kirby struct dsl_ds_holdarg { 3218ca45db41SChris Kirby dsl_sync_task_group_t *dstg; 3219ca45db41SChris Kirby char *htag; 3220ca45db41SChris Kirby char *snapname; 3221ca45db41SChris Kirby boolean_t recursive; 3222ca45db41SChris Kirby boolean_t gotone; 3223ca45db41SChris Kirby boolean_t temphold; 3224ca45db41SChris Kirby char failed[MAXPATHLEN]; 3225ca45db41SChris Kirby }; 3226ca45db41SChris Kirby 3227842727c2SChris Kirby static int 3228842727c2SChris Kirby dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx) 3229842727c2SChris Kirby { 3230842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3231ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 3232ca45db41SChris Kirby char *htag = ha->htag; 3233842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3234842727c2SChris Kirby int error = 0; 3235842727c2SChris Kirby 3236842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3237842727c2SChris Kirby return (ENOTSUP); 3238842727c2SChris Kirby 3239842727c2SChris Kirby if (!dsl_dataset_is_snapshot(ds)) 3240842727c2SChris Kirby return (EINVAL); 3241842727c2SChris Kirby 3242842727c2SChris Kirby /* tags must be unique */ 3243842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3244842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj) { 3245842727c2SChris Kirby error = zap_lookup(mos, ds->ds_phys->ds_userrefs_obj, htag, 3246842727c2SChris Kirby 8, 1, tx); 3247842727c2SChris Kirby if (error == 0) 3248842727c2SChris Kirby error = EEXIST; 3249842727c2SChris Kirby else if (error == ENOENT) 3250842727c2SChris Kirby error = 0; 3251842727c2SChris Kirby } 3252842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3253842727c2SChris Kirby 3254842727c2SChris Kirby return (error); 3255842727c2SChris Kirby } 3256842727c2SChris Kirby 3257842727c2SChris Kirby static void 3258842727c2SChris Kirby dsl_dataset_user_hold_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3259842727c2SChris Kirby { 3260842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3261ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 3262ca45db41SChris Kirby char *htag = ha->htag; 3263ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3264ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 3265842727c2SChris Kirby time_t now = gethrestime_sec(); 3266842727c2SChris Kirby uint64_t zapobj; 3267842727c2SChris Kirby 3268842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3269842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj == 0) { 3270842727c2SChris Kirby /* 3271842727c2SChris Kirby * This is the first user hold for this dataset. Create 3272842727c2SChris Kirby * the userrefs zap object. 3273842727c2SChris Kirby */ 3274842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 3275842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj = 3276842727c2SChris Kirby zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx); 3277842727c2SChris Kirby } else { 3278842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3279842727c2SChris Kirby } 3280842727c2SChris Kirby ds->ds_userrefs++; 3281842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3282842727c2SChris Kirby 3283842727c2SChris Kirby VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx)); 3284842727c2SChris Kirby 3285ca45db41SChris Kirby if (ha->temphold) { 3286ca45db41SChris Kirby VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object, 3287ca45db41SChris Kirby htag, &now, tx)); 3288ca45db41SChris Kirby } 3289ca45db41SChris Kirby 3290842727c2SChris Kirby spa_history_internal_log(LOG_DS_USER_HOLD, 3291ca45db41SChris Kirby dp->dp_spa, tx, cr, "<%s> temp = %d dataset = %llu", htag, 3292ca45db41SChris Kirby (int)ha->temphold, ds->ds_object); 3293842727c2SChris Kirby } 3294842727c2SChris Kirby 3295842727c2SChris Kirby static int 3296842727c2SChris Kirby dsl_dataset_user_hold_one(char *dsname, void *arg) 3297842727c2SChris Kirby { 3298842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3299842727c2SChris Kirby dsl_dataset_t *ds; 3300842727c2SChris Kirby int error; 3301842727c2SChris Kirby char *name; 3302842727c2SChris Kirby 3303842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname plus terminating NULL */ 3304ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3305842727c2SChris Kirby error = dsl_dataset_hold(name, ha->dstg, &ds); 3306ae46e4c7SMatthew Ahrens strfree(name); 3307842727c2SChris Kirby if (error == 0) { 3308d7747cbcSChris Kirby ha->gotone = B_TRUE; 3309842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check, 3310ca45db41SChris Kirby dsl_dataset_user_hold_sync, ds, ha, 0); 3311842727c2SChris Kirby } else if (error == ENOENT && ha->recursive) { 3312842727c2SChris Kirby error = 0; 3313842727c2SChris Kirby } else { 3314842727c2SChris Kirby (void) strcpy(ha->failed, dsname); 3315842727c2SChris Kirby } 3316842727c2SChris Kirby return (error); 3317842727c2SChris Kirby } 3318842727c2SChris Kirby 3319842727c2SChris Kirby int 3320842727c2SChris Kirby dsl_dataset_user_hold(char *dsname, char *snapname, char *htag, 3321ca45db41SChris Kirby boolean_t recursive, boolean_t temphold) 3322842727c2SChris Kirby { 3323842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3324842727c2SChris Kirby dsl_sync_task_t *dst; 3325842727c2SChris Kirby spa_t *spa; 3326842727c2SChris Kirby int error; 3327842727c2SChris Kirby 3328842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3329842727c2SChris Kirby 3330842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3331842727c2SChris Kirby 3332842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3333842727c2SChris Kirby if (error) { 3334842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3335842727c2SChris Kirby return (error); 3336842727c2SChris Kirby } 3337842727c2SChris Kirby 3338842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3339842727c2SChris Kirby ha->htag = htag; 3340842727c2SChris Kirby ha->snapname = snapname; 3341842727c2SChris Kirby ha->recursive = recursive; 3342ca45db41SChris Kirby ha->temphold = temphold; 3343842727c2SChris Kirby if (recursive) { 3344842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_hold_one, 3345842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3346842727c2SChris Kirby } else { 3347842727c2SChris Kirby error = dsl_dataset_user_hold_one(dsname, ha); 3348842727c2SChris Kirby } 3349842727c2SChris Kirby if (error == 0) 3350842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3351842727c2SChris Kirby 3352842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3353842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3354842727c2SChris Kirby dsl_dataset_t *ds = dst->dst_arg1; 3355842727c2SChris Kirby 3356842727c2SChris Kirby if (dst->dst_err) { 3357842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3358842727c2SChris Kirby *strchr(ha->failed, '@') = '\0'; 3359842727c2SChris Kirby } 3360842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3361842727c2SChris Kirby } 3362842727c2SChris Kirby 3363d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3364d7747cbcSChris Kirby error = ENOENT; 3365d7747cbcSChris Kirby 3366842727c2SChris Kirby if (error) 3367842727c2SChris Kirby (void) strcpy(dsname, ha->failed); 3368842727c2SChris Kirby 3369842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3370842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3371842727c2SChris Kirby spa_close(spa, FTAG); 3372842727c2SChris Kirby return (error); 3373842727c2SChris Kirby } 3374842727c2SChris Kirby 3375842727c2SChris Kirby struct dsl_ds_releasearg { 3376842727c2SChris Kirby dsl_dataset_t *ds; 3377842727c2SChris Kirby const char *htag; 3378842727c2SChris Kirby boolean_t own; /* do we own or just hold ds? */ 3379842727c2SChris Kirby }; 3380842727c2SChris Kirby 3381842727c2SChris Kirby static int 3382842727c2SChris Kirby dsl_dataset_release_might_destroy(dsl_dataset_t *ds, const char *htag, 3383842727c2SChris Kirby boolean_t *might_destroy) 3384842727c2SChris Kirby { 3385842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3386842727c2SChris Kirby uint64_t zapobj; 3387842727c2SChris Kirby uint64_t tmp; 3388842727c2SChris Kirby int error; 3389842727c2SChris Kirby 3390842727c2SChris Kirby *might_destroy = B_FALSE; 3391842727c2SChris Kirby 3392842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3393842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3394842727c2SChris Kirby if (zapobj == 0) { 3395842727c2SChris Kirby /* The tag can't possibly exist */ 3396842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3397842727c2SChris Kirby return (ESRCH); 3398842727c2SChris Kirby } 3399842727c2SChris Kirby 3400842727c2SChris Kirby /* Make sure the tag exists */ 3401842727c2SChris Kirby error = zap_lookup(mos, zapobj, htag, 8, 1, &tmp); 3402842727c2SChris Kirby if (error) { 3403842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3404842727c2SChris Kirby if (error == ENOENT) 3405842727c2SChris Kirby error = ESRCH; 3406842727c2SChris Kirby return (error); 3407842727c2SChris Kirby } 3408842727c2SChris Kirby 3409842727c2SChris Kirby if (ds->ds_userrefs == 1 && ds->ds_phys->ds_num_children == 1 && 3410842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 3411842727c2SChris Kirby *might_destroy = B_TRUE; 3412842727c2SChris Kirby 3413842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3414842727c2SChris Kirby return (0); 3415842727c2SChris Kirby } 3416842727c2SChris Kirby 3417842727c2SChris Kirby static int 3418842727c2SChris Kirby dsl_dataset_user_release_check(void *arg1, void *tag, dmu_tx_t *tx) 3419842727c2SChris Kirby { 3420842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3421842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3422842727c2SChris Kirby boolean_t might_destroy; 3423842727c2SChris Kirby int error; 3424842727c2SChris Kirby 3425842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3426842727c2SChris Kirby return (ENOTSUP); 3427842727c2SChris Kirby 3428842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ra->htag, &might_destroy); 3429842727c2SChris Kirby if (error) 3430842727c2SChris Kirby return (error); 3431842727c2SChris Kirby 3432842727c2SChris Kirby if (might_destroy) { 3433842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3434842727c2SChris Kirby 3435842727c2SChris Kirby if (dmu_tx_is_syncing(tx)) { 3436842727c2SChris Kirby /* 3437842727c2SChris Kirby * If we're not prepared to remove the snapshot, 3438842727c2SChris Kirby * we can't allow the release to happen right now. 3439842727c2SChris Kirby */ 3440842727c2SChris Kirby if (!ra->own) 3441842727c2SChris Kirby return (EBUSY); 3442503ad85cSMatthew Ahrens if (ds->ds_objset) { 3443503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 3444503ad85cSMatthew Ahrens ds->ds_objset = NULL; 3445842727c2SChris Kirby } 3446842727c2SChris Kirby } 3447842727c2SChris Kirby dsda.ds = ds; 3448842727c2SChris Kirby dsda.releasing = B_TRUE; 3449842727c2SChris Kirby return (dsl_dataset_destroy_check(&dsda, tag, tx)); 3450842727c2SChris Kirby } 3451842727c2SChris Kirby 3452842727c2SChris Kirby return (0); 3453842727c2SChris Kirby } 3454842727c2SChris Kirby 3455842727c2SChris Kirby static void 3456842727c2SChris Kirby dsl_dataset_user_release_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 3457842727c2SChris Kirby { 3458842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3459842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3460ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3461ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 3462842727c2SChris Kirby uint64_t zapobj; 3463842727c2SChris Kirby uint64_t dsobj = ds->ds_object; 3464842727c2SChris Kirby uint64_t refs; 3465ca45db41SChris Kirby int error; 3466842727c2SChris Kirby 3467842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3468842727c2SChris Kirby ds->ds_userrefs--; 3469842727c2SChris Kirby refs = ds->ds_userrefs; 3470842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3471ca45db41SChris Kirby error = dsl_pool_user_release(dp, ds->ds_object, ra->htag, tx); 3472ca45db41SChris Kirby VERIFY(error == 0 || error == ENOENT); 3473842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3474842727c2SChris Kirby VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx)); 3475842727c2SChris Kirby if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 && 3476842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) { 3477842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3478842727c2SChris Kirby 3479842727c2SChris Kirby ASSERT(ra->own); 3480842727c2SChris Kirby dsda.ds = ds; 3481842727c2SChris Kirby dsda.releasing = B_TRUE; 3482842727c2SChris Kirby /* We already did the destroy_check */ 3483842727c2SChris Kirby dsl_dataset_destroy_sync(&dsda, tag, cr, tx); 3484842727c2SChris Kirby } 3485842727c2SChris Kirby 3486842727c2SChris Kirby spa_history_internal_log(LOG_DS_USER_RELEASE, 3487ca45db41SChris Kirby dp->dp_spa, tx, cr, "<%s> %lld dataset = %llu", 3488842727c2SChris Kirby ra->htag, (longlong_t)refs, dsobj); 3489842727c2SChris Kirby } 3490842727c2SChris Kirby 3491842727c2SChris Kirby static int 3492842727c2SChris Kirby dsl_dataset_user_release_one(char *dsname, void *arg) 3493842727c2SChris Kirby { 3494842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3495842727c2SChris Kirby struct dsl_ds_releasearg *ra; 3496842727c2SChris Kirby dsl_dataset_t *ds; 3497842727c2SChris Kirby int error; 3498842727c2SChris Kirby void *dtag = ha->dstg; 3499842727c2SChris Kirby char *name; 3500842727c2SChris Kirby boolean_t own = B_FALSE; 3501842727c2SChris Kirby boolean_t might_destroy; 3502842727c2SChris Kirby 3503842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname, plus the terminating NULL */ 3504ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3505842727c2SChris Kirby error = dsl_dataset_hold(name, dtag, &ds); 3506ae46e4c7SMatthew Ahrens strfree(name); 3507842727c2SChris Kirby if (error == ENOENT && ha->recursive) 3508842727c2SChris Kirby return (0); 3509842727c2SChris Kirby (void) strcpy(ha->failed, dsname); 3510842727c2SChris Kirby if (error) 3511842727c2SChris Kirby return (error); 3512842727c2SChris Kirby 3513d7747cbcSChris Kirby ha->gotone = B_TRUE; 3514d7747cbcSChris Kirby 3515842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 3516842727c2SChris Kirby 3517842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ha->htag, &might_destroy); 3518842727c2SChris Kirby if (error) { 3519842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3520842727c2SChris Kirby return (error); 3521842727c2SChris Kirby } 3522842727c2SChris Kirby 3523842727c2SChris Kirby if (might_destroy) { 3524842727c2SChris Kirby #ifdef _KERNEL 3525842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 3526842727c2SChris Kirby if (error) { 3527842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3528842727c2SChris Kirby return (error); 3529842727c2SChris Kirby } 3530842727c2SChris Kirby error = dsl_dataset_zvol_cleanup(ds, name); 3531842727c2SChris Kirby if (error) { 3532842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3533842727c2SChris Kirby return (error); 3534842727c2SChris Kirby } 3535842727c2SChris Kirby #endif 3536503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(ds, B_TRUE, dtag)) { 3537842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3538842727c2SChris Kirby return (EBUSY); 3539842727c2SChris Kirby } else { 3540842727c2SChris Kirby own = B_TRUE; 3541842727c2SChris Kirby dsl_dataset_make_exclusive(ds, dtag); 3542842727c2SChris Kirby } 3543842727c2SChris Kirby } 3544842727c2SChris Kirby 3545842727c2SChris Kirby ra = kmem_alloc(sizeof (struct dsl_ds_releasearg), KM_SLEEP); 3546842727c2SChris Kirby ra->ds = ds; 3547842727c2SChris Kirby ra->htag = ha->htag; 3548842727c2SChris Kirby ra->own = own; 3549842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_release_check, 3550842727c2SChris Kirby dsl_dataset_user_release_sync, ra, dtag, 0); 3551842727c2SChris Kirby 3552842727c2SChris Kirby return (0); 3553842727c2SChris Kirby } 3554842727c2SChris Kirby 3555842727c2SChris Kirby int 3556842727c2SChris Kirby dsl_dataset_user_release(char *dsname, char *snapname, char *htag, 3557842727c2SChris Kirby boolean_t recursive) 3558842727c2SChris Kirby { 3559842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3560842727c2SChris Kirby dsl_sync_task_t *dst; 3561842727c2SChris Kirby spa_t *spa; 3562842727c2SChris Kirby int error; 3563842727c2SChris Kirby 3564842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3565842727c2SChris Kirby 3566842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3567842727c2SChris Kirby 3568842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3569842727c2SChris Kirby if (error) { 3570842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3571842727c2SChris Kirby return (error); 3572842727c2SChris Kirby } 3573842727c2SChris Kirby 3574842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3575842727c2SChris Kirby ha->htag = htag; 3576842727c2SChris Kirby ha->snapname = snapname; 3577842727c2SChris Kirby ha->recursive = recursive; 3578842727c2SChris Kirby if (recursive) { 3579842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_release_one, 3580842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3581842727c2SChris Kirby } else { 3582842727c2SChris Kirby error = dsl_dataset_user_release_one(dsname, ha); 3583842727c2SChris Kirby } 3584842727c2SChris Kirby if (error == 0) 3585842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3586842727c2SChris Kirby 3587842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3588842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3589842727c2SChris Kirby struct dsl_ds_releasearg *ra = dst->dst_arg1; 3590842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3591842727c2SChris Kirby 3592842727c2SChris Kirby if (dst->dst_err) 3593842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3594842727c2SChris Kirby 3595842727c2SChris Kirby if (ra->own) 3596842727c2SChris Kirby dsl_dataset_disown(ds, ha->dstg); 3597842727c2SChris Kirby else 3598842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3599842727c2SChris Kirby 3600842727c2SChris Kirby kmem_free(ra, sizeof (struct dsl_ds_releasearg)); 3601842727c2SChris Kirby } 3602842727c2SChris Kirby 3603d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3604d7747cbcSChris Kirby error = ENOENT; 3605d7747cbcSChris Kirby 3606842727c2SChris Kirby if (error) 3607842727c2SChris Kirby (void) strcpy(dsname, ha->failed); 3608842727c2SChris Kirby 3609842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3610842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3611842727c2SChris Kirby spa_close(spa, FTAG); 3612842727c2SChris Kirby return (error); 3613842727c2SChris Kirby } 3614842727c2SChris Kirby 3615ca45db41SChris Kirby /* 3616ca45db41SChris Kirby * Called at spa_load time to release a stale temporary user hold. 3617ca45db41SChris Kirby */ 3618ca45db41SChris Kirby int 3619ca45db41SChris Kirby dsl_dataset_user_release_tmp(dsl_pool_t *dp, uint64_t dsobj, char *htag) 3620ca45db41SChris Kirby { 3621ca45db41SChris Kirby dsl_dataset_t *ds; 3622ca45db41SChris Kirby char *snap; 3623ca45db41SChris Kirby char *name; 3624ca45db41SChris Kirby int namelen; 3625ca45db41SChris Kirby int error; 3626ca45db41SChris Kirby 3627ca45db41SChris Kirby rw_enter(&dp->dp_config_rwlock, RW_READER); 3628ca45db41SChris Kirby error = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds); 3629ca45db41SChris Kirby rw_exit(&dp->dp_config_rwlock); 3630ca45db41SChris Kirby if (error) 3631ca45db41SChris Kirby return (error); 3632ca45db41SChris Kirby namelen = dsl_dataset_namelen(ds)+1; 3633ca45db41SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 3634ca45db41SChris Kirby dsl_dataset_name(ds, name); 3635ca45db41SChris Kirby dsl_dataset_rele(ds, FTAG); 3636ca45db41SChris Kirby 3637ca45db41SChris Kirby snap = strchr(name, '@'); 3638ca45db41SChris Kirby *snap = '\0'; 3639ca45db41SChris Kirby ++snap; 3640ca45db41SChris Kirby return (dsl_dataset_user_release(name, snap, htag, B_FALSE)); 3641ca45db41SChris Kirby } 3642ca45db41SChris Kirby 3643842727c2SChris Kirby int 3644842727c2SChris Kirby dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp) 3645842727c2SChris Kirby { 3646842727c2SChris Kirby dsl_dataset_t *ds; 3647842727c2SChris Kirby int err; 3648842727c2SChris Kirby 3649842727c2SChris Kirby err = dsl_dataset_hold(dsname, FTAG, &ds); 3650842727c2SChris Kirby if (err) 3651842727c2SChris Kirby return (err); 3652842727c2SChris Kirby 3653842727c2SChris Kirby VERIFY(0 == nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP)); 3654842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) { 3655842727c2SChris Kirby zap_attribute_t *za; 3656842727c2SChris Kirby zap_cursor_t zc; 3657842727c2SChris Kirby 3658842727c2SChris Kirby za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 3659842727c2SChris Kirby for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset, 3660842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj); 3661842727c2SChris Kirby zap_cursor_retrieve(&zc, za) == 0; 3662842727c2SChris Kirby zap_cursor_advance(&zc)) { 3663842727c2SChris Kirby VERIFY(0 == nvlist_add_uint64(*nvp, za->za_name, 3664842727c2SChris Kirby za->za_first_integer)); 3665842727c2SChris Kirby } 3666842727c2SChris Kirby zap_cursor_fini(&zc); 3667842727c2SChris Kirby kmem_free(za, sizeof (zap_attribute_t)); 3668842727c2SChris Kirby } 3669842727c2SChris Kirby dsl_dataset_rele(ds, FTAG); 3670842727c2SChris Kirby return (0); 3671842727c2SChris Kirby } 3672503ad85cSMatthew Ahrens 3673503ad85cSMatthew Ahrens /* 3674503ad85cSMatthew Ahrens * Note, this fuction is used as the callback for dmu_objset_find(). We 3675503ad85cSMatthew Ahrens * always return 0 so that we will continue to find and process 3676503ad85cSMatthew Ahrens * inconsistent datasets, even if we encounter an error trying to 3677503ad85cSMatthew Ahrens * process one of them. 3678503ad85cSMatthew Ahrens */ 3679503ad85cSMatthew Ahrens /* ARGSUSED */ 3680503ad85cSMatthew Ahrens int 3681503ad85cSMatthew Ahrens dsl_destroy_inconsistent(char *dsname, void *arg) 3682503ad85cSMatthew Ahrens { 3683503ad85cSMatthew Ahrens dsl_dataset_t *ds; 3684503ad85cSMatthew Ahrens 3685503ad85cSMatthew Ahrens if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) { 3686503ad85cSMatthew Ahrens if (DS_IS_INCONSISTENT(ds)) 3687503ad85cSMatthew Ahrens (void) dsl_dataset_destroy(ds, FTAG, B_FALSE); 3688503ad85cSMatthew Ahrens else 3689503ad85cSMatthew Ahrens dsl_dataset_disown(ds, FTAG); 3690503ad85cSMatthew Ahrens } 3691503ad85cSMatthew Ahrens return (0); 3692503ad85cSMatthew Ahrens } 3693