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 247*503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) 248*503ad85cSMatthew 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 324745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 325ab04eb8eStimh mt = MT_FIRST; 326ab04eb8eStimh else 327ab04eb8eStimh mt = MT_EXACT; 328ab04eb8eStimh 329745cd3c5Smaybee err = zap_remove_norm(mos, snapobj, name, mt, tx); 330ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 331745cd3c5Smaybee err = zap_remove(mos, snapobj, name, tx); 332ab04eb8eStimh return (err); 333ab04eb8eStimh } 334ab04eb8eStimh 335745cd3c5Smaybee static int 336745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag, 337745cd3c5Smaybee dsl_dataset_t **dsp) 338fa9e4066Sahrens { 339fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 340fa9e4066Sahrens dmu_buf_t *dbuf; 341fa9e4066Sahrens dsl_dataset_t *ds; 342ea8dc4b6Seschrock int err; 343fa9e4066Sahrens 344fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 345fa9e4066Sahrens dsl_pool_sync_context(dp)); 346fa9e4066Sahrens 347ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 348ea8dc4b6Seschrock if (err) 349ea8dc4b6Seschrock return (err); 350fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 351fa9e4066Sahrens if (ds == NULL) { 352fa9e4066Sahrens dsl_dataset_t *winner; 353fa9e4066Sahrens 354fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 355fa9e4066Sahrens ds->ds_dbuf = dbuf; 356fa9e4066Sahrens ds->ds_object = dsobj; 357fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 358fa9e4066Sahrens 3595ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 360f4b94bdeSMatthew Ahrens mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL); 36191ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 3625ad82045Snd mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT, 3635ad82045Snd NULL); 364745cd3c5Smaybee rw_init(&ds->ds_rwlock, 0, 0, 0); 365745cd3c5Smaybee cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL); 3665ad82045Snd 367ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 368fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 369ea8dc4b6Seschrock if (err == 0) { 370ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 371ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 372ea8dc4b6Seschrock } 373ea8dc4b6Seschrock if (err) { 374ea8dc4b6Seschrock /* 375ea8dc4b6Seschrock * we don't really need to close the blist if we 376ea8dc4b6Seschrock * just opened it. 377ea8dc4b6Seschrock */ 3785ad82045Snd mutex_destroy(&ds->ds_lock); 379f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 38091ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 3815ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 382745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 383745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 384ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 385ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 386ea8dc4b6Seschrock return (err); 387ea8dc4b6Seschrock } 388fa9e4066Sahrens 38974e7dc98SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 390fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 391fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 392745cd3c5Smaybee err = dsl_dataset_get_ref(dp, 393745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 394745cd3c5Smaybee ds, &ds->ds_prev); 395fa9e4066Sahrens } 39674e7dc98SMatthew Ahrens 39774e7dc98SMatthew Ahrens if (err == 0 && dsl_dir_is_clone(ds->ds_dir)) { 39874e7dc98SMatthew Ahrens dsl_dataset_t *origin; 39974e7dc98SMatthew Ahrens 40074e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, 40174e7dc98SMatthew Ahrens ds->ds_dir->dd_phys->dd_origin_obj, 40274e7dc98SMatthew Ahrens FTAG, &origin); 40374e7dc98SMatthew Ahrens if (err == 0) { 40474e7dc98SMatthew Ahrens ds->ds_origin_txg = 40574e7dc98SMatthew Ahrens origin->ds_phys->ds_creation_txg; 40674e7dc98SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 40774e7dc98SMatthew Ahrens } 40874e7dc98SMatthew Ahrens } 409842727c2SChris Kirby } else { 410842727c2SChris Kirby if (zfs_flags & ZFS_DEBUG_SNAPNAMES) 411842727c2SChris Kirby err = dsl_dataset_get_snapname(ds); 412842727c2SChris Kirby if (err == 0 && ds->ds_phys->ds_userrefs_obj != 0) { 413842727c2SChris Kirby err = zap_count( 414842727c2SChris Kirby ds->ds_dir->dd_pool->dp_meta_objset, 415842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj, 416842727c2SChris Kirby &ds->ds_userrefs); 417842727c2SChris Kirby } 418fa9e4066Sahrens } 419fa9e4066Sahrens 42074e7dc98SMatthew Ahrens if (err == 0 && !dsl_dataset_is_snapshot(ds)) { 42127345066Sck /* 42227345066Sck * In sync context, we're called with either no lock 42327345066Sck * or with the write lock. If we're not syncing, 42427345066Sck * we're always called with the read lock held. 42527345066Sck */ 426cb625fb5Sck boolean_t need_lock = 42727345066Sck !RW_WRITE_HELD(&dp->dp_config_rwlock) && 42827345066Sck dsl_pool_sync_context(dp); 429cb625fb5Sck 430cb625fb5Sck if (need_lock) 431cb625fb5Sck rw_enter(&dp->dp_config_rwlock, RW_READER); 432cb625fb5Sck 433bb0ade09Sahrens err = dsl_prop_get_ds(ds, 434cb625fb5Sck "refreservation", sizeof (uint64_t), 1, 435cb625fb5Sck &ds->ds_reserved, NULL); 436cb625fb5Sck if (err == 0) { 437bb0ade09Sahrens err = dsl_prop_get_ds(ds, 438cb625fb5Sck "refquota", sizeof (uint64_t), 1, 439cb625fb5Sck &ds->ds_quota, NULL); 440cb625fb5Sck } 441cb625fb5Sck 442cb625fb5Sck if (need_lock) 443cb625fb5Sck rw_exit(&dp->dp_config_rwlock); 444cb625fb5Sck } else { 445cb625fb5Sck ds->ds_reserved = ds->ds_quota = 0; 446cb625fb5Sck } 447cb625fb5Sck 448ea8dc4b6Seschrock if (err == 0) { 449ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 450ea8dc4b6Seschrock dsl_dataset_evict); 451ea8dc4b6Seschrock } 452ea8dc4b6Seschrock if (err || winner) { 453fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 454745cd3c5Smaybee if (ds->ds_prev) 455745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 456fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 4575ad82045Snd mutex_destroy(&ds->ds_lock); 458f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 45991ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 4605ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 461745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 462745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 463fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 464ea8dc4b6Seschrock if (err) { 465ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 466ea8dc4b6Seschrock return (err); 467ea8dc4b6Seschrock } 468fa9e4066Sahrens ds = winner; 469fa9e4066Sahrens } else { 47091ebeef5Sahrens ds->ds_fsid_guid = 471fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 472fa9e4066Sahrens } 473fa9e4066Sahrens } 474fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 475fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 476088f3894Sahrens ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 || 477afc6333aSahrens spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN || 47884db2a68Sahrens dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap); 479fa9e4066Sahrens mutex_enter(&ds->ds_lock); 480745cd3c5Smaybee if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) { 481fa9e4066Sahrens mutex_exit(&ds->ds_lock); 482745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 483745cd3c5Smaybee return (ENOENT); 484fa9e4066Sahrens } 485fa9e4066Sahrens mutex_exit(&ds->ds_lock); 486ea8dc4b6Seschrock *dsp = ds; 487ea8dc4b6Seschrock return (0); 488fa9e4066Sahrens } 489fa9e4066Sahrens 490745cd3c5Smaybee static int 491745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag) 492745cd3c5Smaybee { 493745cd3c5Smaybee dsl_pool_t *dp = ds->ds_dir->dd_pool; 494745cd3c5Smaybee 495745cd3c5Smaybee /* 496745cd3c5Smaybee * In syncing context we don't want the rwlock lock: there 497745cd3c5Smaybee * may be an existing writer waiting for sync phase to 498745cd3c5Smaybee * finish. We don't need to worry about such writers, since 499745cd3c5Smaybee * sync phase is single-threaded, so the writer can't be 500745cd3c5Smaybee * doing anything while we are active. 501745cd3c5Smaybee */ 502745cd3c5Smaybee if (dsl_pool_sync_context(dp)) { 503745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 504745cd3c5Smaybee return (0); 505745cd3c5Smaybee } 506745cd3c5Smaybee 507745cd3c5Smaybee /* 508745cd3c5Smaybee * Normal users will hold the ds_rwlock as a READER until they 509745cd3c5Smaybee * are finished (i.e., call dsl_dataset_rele()). "Owners" will 510745cd3c5Smaybee * drop their READER lock after they set the ds_owner field. 511745cd3c5Smaybee * 512745cd3c5Smaybee * If the dataset is being destroyed, the destroy thread will 513745cd3c5Smaybee * obtain a WRITER lock for exclusive access after it's done its 514745cd3c5Smaybee * open-context work and then change the ds_owner to 515745cd3c5Smaybee * dsl_reaper once destruction is assured. So threads 516745cd3c5Smaybee * may block here temporarily, until the "destructability" of 517745cd3c5Smaybee * the dataset is determined. 518745cd3c5Smaybee */ 519745cd3c5Smaybee ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock)); 520745cd3c5Smaybee mutex_enter(&ds->ds_lock); 521745cd3c5Smaybee while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) { 522745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 523745cd3c5Smaybee cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock); 524745cd3c5Smaybee if (DSL_DATASET_IS_DESTROYED(ds)) { 525745cd3c5Smaybee mutex_exit(&ds->ds_lock); 526745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 527745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 528745cd3c5Smaybee return (ENOENT); 529745cd3c5Smaybee } 530745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 531745cd3c5Smaybee } 532745cd3c5Smaybee mutex_exit(&ds->ds_lock); 533745cd3c5Smaybee return (0); 534745cd3c5Smaybee } 535745cd3c5Smaybee 536745cd3c5Smaybee int 537745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, 538745cd3c5Smaybee dsl_dataset_t **dsp) 539745cd3c5Smaybee { 540745cd3c5Smaybee int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp); 541745cd3c5Smaybee 542745cd3c5Smaybee if (err) 543745cd3c5Smaybee return (err); 544745cd3c5Smaybee return (dsl_dataset_hold_ref(*dsp, tag)); 545745cd3c5Smaybee } 546745cd3c5Smaybee 547745cd3c5Smaybee int 548*503ad85cSMatthew Ahrens dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, boolean_t inconsistentok, 549*503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 550745cd3c5Smaybee { 551*503ad85cSMatthew Ahrens int err = dsl_dataset_hold_obj(dp, dsobj, tag, dsp); 552745cd3c5Smaybee if (err) 553745cd3c5Smaybee return (err); 554*503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 555*503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 5564f5064b7SMark J Musante *dsp = NULL; 557745cd3c5Smaybee return (EBUSY); 558745cd3c5Smaybee } 559745cd3c5Smaybee return (0); 560745cd3c5Smaybee } 561745cd3c5Smaybee 562fa9e4066Sahrens int 563745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp) 564fa9e4066Sahrens { 565fa9e4066Sahrens dsl_dir_t *dd; 566fa9e4066Sahrens dsl_pool_t *dp; 567745cd3c5Smaybee const char *snapname; 568fa9e4066Sahrens uint64_t obj; 569fa9e4066Sahrens int err = 0; 570fa9e4066Sahrens 571745cd3c5Smaybee err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname); 572ea8dc4b6Seschrock if (err) 573ea8dc4b6Seschrock return (err); 574fa9e4066Sahrens 575fa9e4066Sahrens dp = dd->dd_pool; 576fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 577fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 578745cd3c5Smaybee if (obj) 579745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, dsp); 580745cd3c5Smaybee else 581fa9e4066Sahrens err = ENOENT; 582745cd3c5Smaybee if (err) 583fa9e4066Sahrens goto out; 584fa9e4066Sahrens 585745cd3c5Smaybee err = dsl_dataset_hold_ref(*dsp, tag); 586fa9e4066Sahrens 587745cd3c5Smaybee /* we may be looking for a snapshot */ 588745cd3c5Smaybee if (err == 0 && snapname != NULL) { 589745cd3c5Smaybee dsl_dataset_t *ds = NULL; 590fa9e4066Sahrens 591745cd3c5Smaybee if (*snapname++ != '@') { 592745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 593fa9e4066Sahrens err = ENOENT; 594fa9e4066Sahrens goto out; 595fa9e4066Sahrens } 596fa9e4066Sahrens 597745cd3c5Smaybee dprintf("looking for snapshot '%s'\n", snapname); 598745cd3c5Smaybee err = dsl_dataset_snap_lookup(*dsp, snapname, &obj); 599745cd3c5Smaybee if (err == 0) 600745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, &ds); 601745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 602745cd3c5Smaybee 603745cd3c5Smaybee ASSERT3U((err == 0), ==, (ds != NULL)); 604745cd3c5Smaybee 605745cd3c5Smaybee if (ds) { 606745cd3c5Smaybee mutex_enter(&ds->ds_lock); 607745cd3c5Smaybee if (ds->ds_snapname[0] == 0) 608745cd3c5Smaybee (void) strlcpy(ds->ds_snapname, snapname, 609745cd3c5Smaybee sizeof (ds->ds_snapname)); 610745cd3c5Smaybee mutex_exit(&ds->ds_lock); 611745cd3c5Smaybee err = dsl_dataset_hold_ref(ds, tag); 612745cd3c5Smaybee *dsp = err ? NULL : ds; 613fa9e4066Sahrens } 614fa9e4066Sahrens } 615fa9e4066Sahrens out: 616fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 617fa9e4066Sahrens dsl_dir_close(dd, FTAG); 618fa9e4066Sahrens return (err); 619fa9e4066Sahrens } 620fa9e4066Sahrens 621fa9e4066Sahrens int 622*503ad85cSMatthew Ahrens dsl_dataset_own(const char *name, boolean_t inconsistentok, 623*503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 624fa9e4066Sahrens { 625*503ad85cSMatthew Ahrens int err = dsl_dataset_hold(name, tag, dsp); 626745cd3c5Smaybee if (err) 627745cd3c5Smaybee return (err); 628*503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 629*503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 630745cd3c5Smaybee return (EBUSY); 631745cd3c5Smaybee } 632745cd3c5Smaybee return (0); 633fa9e4066Sahrens } 634fa9e4066Sahrens 635fa9e4066Sahrens void 636fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 637fa9e4066Sahrens { 638fa9e4066Sahrens if (ds == NULL) { 639fa9e4066Sahrens (void) strcpy(name, "mos"); 640fa9e4066Sahrens } else { 641fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 642ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 643fa9e4066Sahrens if (ds->ds_snapname[0]) { 644fa9e4066Sahrens (void) strcat(name, "@"); 645745cd3c5Smaybee /* 646745cd3c5Smaybee * We use a "recursive" mutex so that we 647745cd3c5Smaybee * can call dprintf_ds() with ds_lock held. 648745cd3c5Smaybee */ 649fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 650fa9e4066Sahrens mutex_enter(&ds->ds_lock); 651fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 652fa9e4066Sahrens mutex_exit(&ds->ds_lock); 653fa9e4066Sahrens } else { 654fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 655fa9e4066Sahrens } 656fa9e4066Sahrens } 657fa9e4066Sahrens } 658fa9e4066Sahrens } 659fa9e4066Sahrens 660b7661cccSmmusante static int 661b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 662b7661cccSmmusante { 663b7661cccSmmusante int result; 664b7661cccSmmusante 665b7661cccSmmusante if (ds == NULL) { 666b7661cccSmmusante result = 3; /* "mos" */ 667b7661cccSmmusante } else { 668b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 669b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 670b7661cccSmmusante if (ds->ds_snapname[0]) { 671b7661cccSmmusante ++result; /* adding one for the @-sign */ 672b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 673b7661cccSmmusante mutex_enter(&ds->ds_lock); 674b7661cccSmmusante result += strlen(ds->ds_snapname); 675b7661cccSmmusante mutex_exit(&ds->ds_lock); 676b7661cccSmmusante } else { 677b7661cccSmmusante result += strlen(ds->ds_snapname); 678b7661cccSmmusante } 679b7661cccSmmusante } 680b7661cccSmmusante } 681b7661cccSmmusante 682b7661cccSmmusante return (result); 683b7661cccSmmusante } 684b7661cccSmmusante 685088f3894Sahrens void 686745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag) 687fa9e4066Sahrens { 688ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 689fa9e4066Sahrens } 690fa9e4066Sahrens 6913cb34c60Sahrens void 692745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag) 6933cb34c60Sahrens { 694745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) { 695745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 696745cd3c5Smaybee } 697745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 698745cd3c5Smaybee } 699745cd3c5Smaybee 700745cd3c5Smaybee void 701*503ad85cSMatthew Ahrens dsl_dataset_disown(dsl_dataset_t *ds, void *tag) 702745cd3c5Smaybee { 703*503ad85cSMatthew Ahrens ASSERT((ds->ds_owner == tag && ds->ds_dbuf) || 704745cd3c5Smaybee (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL)); 705745cd3c5Smaybee 7063cb34c60Sahrens mutex_enter(&ds->ds_lock); 707745cd3c5Smaybee ds->ds_owner = NULL; 708745cd3c5Smaybee if (RW_WRITE_HELD(&ds->ds_rwlock)) { 709745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 710745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 711745cd3c5Smaybee } 7123cb34c60Sahrens mutex_exit(&ds->ds_lock); 713745cd3c5Smaybee if (ds->ds_dbuf) 714*503ad85cSMatthew Ahrens dsl_dataset_drop_ref(ds, tag); 715745cd3c5Smaybee else 716745cd3c5Smaybee dsl_dataset_evict(ds->ds_dbuf, ds); 7173cb34c60Sahrens } 7183cb34c60Sahrens 7193cb34c60Sahrens boolean_t 720*503ad85cSMatthew Ahrens dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *tag) 7213cb34c60Sahrens { 722745cd3c5Smaybee boolean_t gotit = FALSE; 723745cd3c5Smaybee 7243cb34c60Sahrens mutex_enter(&ds->ds_lock); 725745cd3c5Smaybee if (ds->ds_owner == NULL && 726745cd3c5Smaybee (!DS_IS_INCONSISTENT(ds) || inconsistentok)) { 727*503ad85cSMatthew Ahrens ds->ds_owner = tag; 728745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) 729745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 730745cd3c5Smaybee gotit = TRUE; 7313cb34c60Sahrens } 7323cb34c60Sahrens mutex_exit(&ds->ds_lock); 733745cd3c5Smaybee return (gotit); 734745cd3c5Smaybee } 735745cd3c5Smaybee 736745cd3c5Smaybee void 737745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner) 738745cd3c5Smaybee { 739745cd3c5Smaybee ASSERT3P(owner, ==, ds->ds_owner); 740745cd3c5Smaybee if (!RW_WRITE_HELD(&ds->ds_rwlock)) 741745cd3c5Smaybee rw_enter(&ds->ds_rwlock, RW_WRITER); 7423cb34c60Sahrens } 7433cb34c60Sahrens 7441d452cf5Sahrens uint64_t 745088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 746ab04eb8eStimh uint64_t flags, dmu_tx_t *tx) 747fa9e4066Sahrens { 7483cb34c60Sahrens dsl_pool_t *dp = dd->dd_pool; 749fa9e4066Sahrens dmu_buf_t *dbuf; 750fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 7513cb34c60Sahrens uint64_t dsobj; 752fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 753fa9e4066Sahrens 754088f3894Sahrens if (origin == NULL) 755088f3894Sahrens origin = dp->dp_origin_snap; 756088f3894Sahrens 7573cb34c60Sahrens ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp); 7583cb34c60Sahrens ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0); 759fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 7603cb34c60Sahrens ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); 761fa9e4066Sahrens 7621649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 7631649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 764ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 765fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 766fa9e4066Sahrens dsphys = dbuf->db_data; 767745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 768fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 769ab04eb8eStimh dsphys->ds_flags = flags; 770fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 771fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 772fa9e4066Sahrens sizeof (dsphys->ds_guid)); 773fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 774ab04eb8eStimh zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP, 775ab04eb8eStimh DMU_OT_NONE, 0, tx); 776fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 777088f3894Sahrens dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg; 778fa9e4066Sahrens dsphys->ds_deadlist_obj = 779fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 780a9799022Sck 7813cb34c60Sahrens if (origin) { 7823cb34c60Sahrens dsphys->ds_prev_snap_obj = origin->ds_object; 783fa9e4066Sahrens dsphys->ds_prev_snap_txg = 7843cb34c60Sahrens origin->ds_phys->ds_creation_txg; 785fa9e4066Sahrens dsphys->ds_used_bytes = 7863cb34c60Sahrens origin->ds_phys->ds_used_bytes; 787fa9e4066Sahrens dsphys->ds_compressed_bytes = 7883cb34c60Sahrens origin->ds_phys->ds_compressed_bytes; 789fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 7903cb34c60Sahrens origin->ds_phys->ds_uncompressed_bytes; 7913cb34c60Sahrens dsphys->ds_bp = origin->ds_phys->ds_bp; 792579ae4d5Stimh dsphys->ds_flags |= origin->ds_phys->ds_flags; 793fa9e4066Sahrens 7943cb34c60Sahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 7953cb34c60Sahrens origin->ds_phys->ds_num_children++; 796fa9e4066Sahrens 797088f3894Sahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) { 798088f3894Sahrens if (origin->ds_phys->ds_next_clones_obj == 0) { 799088f3894Sahrens origin->ds_phys->ds_next_clones_obj = 800088f3894Sahrens zap_create(mos, 801088f3894Sahrens DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx); 802088f3894Sahrens } 803088f3894Sahrens VERIFY(0 == zap_add_int(mos, 804088f3894Sahrens origin->ds_phys->ds_next_clones_obj, 805088f3894Sahrens dsobj, tx)); 806088f3894Sahrens } 807088f3894Sahrens 808fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 8093cb34c60Sahrens dd->dd_phys->dd_origin_obj = origin->ds_object; 810fa9e4066Sahrens } 811ab04eb8eStimh 812ab04eb8eStimh if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 813ab04eb8eStimh dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 814ab04eb8eStimh 815ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 816fa9e4066Sahrens 817fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 818fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 8193cb34c60Sahrens 8203cb34c60Sahrens return (dsobj); 8213cb34c60Sahrens } 8223cb34c60Sahrens 8233cb34c60Sahrens uint64_t 824ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname, 825ab04eb8eStimh dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx) 8263cb34c60Sahrens { 8273cb34c60Sahrens dsl_pool_t *dp = pdd->dd_pool; 8283cb34c60Sahrens uint64_t dsobj, ddobj; 8293cb34c60Sahrens dsl_dir_t *dd; 8303cb34c60Sahrens 8313cb34c60Sahrens ASSERT(lastname[0] != '@'); 8323cb34c60Sahrens 833088f3894Sahrens ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx); 8343cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 8353cb34c60Sahrens 836088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx); 8373cb34c60Sahrens 8383cb34c60Sahrens dsl_deleg_set_create_perms(dd, tx, cr); 8393cb34c60Sahrens 840fa9e4066Sahrens dsl_dir_close(dd, FTAG); 841fa9e4066Sahrens 8421d452cf5Sahrens return (dsobj); 843fa9e4066Sahrens } 844fa9e4066Sahrens 8451d452cf5Sahrens struct destroyarg { 8461d452cf5Sahrens dsl_sync_task_group_t *dstg; 8471d452cf5Sahrens char *snapname; 8481d452cf5Sahrens char *failed; 849842727c2SChris Kirby boolean_t defer; 8501d452cf5Sahrens }; 8511d452cf5Sahrens 8521d452cf5Sahrens static int 8531d452cf5Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 854fa9e4066Sahrens { 8551d452cf5Sahrens struct destroyarg *da = arg; 8561d452cf5Sahrens dsl_dataset_t *ds; 857fa9e4066Sahrens int err; 858842727c2SChris Kirby char *dsname; 859842727c2SChris Kirby 860ae46e4c7SMatthew Ahrens dsname = kmem_asprintf("%s@%s", name, da->snapname); 861*503ad85cSMatthew Ahrens err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds); 862ae46e4c7SMatthew Ahrens strfree(dsname); 863745cd3c5Smaybee if (err == 0) { 864842727c2SChris Kirby struct dsl_ds_destroyarg *dsda; 865842727c2SChris Kirby 866745cd3c5Smaybee dsl_dataset_make_exclusive(ds, da->dstg); 867*503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) { 868*503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 869*503ad85cSMatthew Ahrens ds->ds_objset = NULL; 8703baa08fcSek } 871842727c2SChris Kirby dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP); 872842727c2SChris Kirby dsda->ds = ds; 873842727c2SChris Kirby dsda->defer = da->defer; 874745cd3c5Smaybee dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 875842727c2SChris Kirby dsl_dataset_destroy_sync, dsda, da->dstg, 0); 876745cd3c5Smaybee } else if (err == ENOENT) { 877745cd3c5Smaybee err = 0; 878745cd3c5Smaybee } else { 8791d452cf5Sahrens (void) strcpy(da->failed, name); 8801d452cf5Sahrens } 881745cd3c5Smaybee return (err); 8821d452cf5Sahrens } 88331fd60d3Sahrens 8841d452cf5Sahrens /* 8851d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 8861d452cf5Sahrens */ 8871d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 8881d452cf5Sahrens int 889842727c2SChris Kirby dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer) 8901d452cf5Sahrens { 8911d452cf5Sahrens int err; 8921d452cf5Sahrens struct destroyarg da; 8931d452cf5Sahrens dsl_sync_task_t *dst; 8941d452cf5Sahrens spa_t *spa; 8951d452cf5Sahrens 89640feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 8971d452cf5Sahrens if (err) 8981d452cf5Sahrens return (err); 8991d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 9001d452cf5Sahrens da.snapname = snapname; 9011d452cf5Sahrens da.failed = fsname; 902842727c2SChris Kirby da.defer = defer; 9031d452cf5Sahrens 9041d452cf5Sahrens err = dmu_objset_find(fsname, 9050b69c2f0Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 9061d452cf5Sahrens 9071d452cf5Sahrens if (err == 0) 9081d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 9091d452cf5Sahrens 9101d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 9111d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 912842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 913842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 914842727c2SChris Kirby 915745cd3c5Smaybee /* 916745cd3c5Smaybee * Return the file system name that triggered the error 917745cd3c5Smaybee */ 9181d452cf5Sahrens if (dst->dst_err) { 9191d452cf5Sahrens dsl_dataset_name(ds, fsname); 92040feaa91Sahrens *strchr(fsname, '@') = '\0'; 921e1930233Sbonwick } 922842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 923745cd3c5Smaybee dsl_dataset_disown(ds, da.dstg); 924842727c2SChris Kirby kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 925fa9e4066Sahrens } 926fa9e4066Sahrens 9271d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 9281d452cf5Sahrens spa_close(spa, FTAG); 929fa9e4066Sahrens return (err); 930fa9e4066Sahrens } 931fa9e4066Sahrens 932842727c2SChris Kirby static boolean_t 933842727c2SChris Kirby dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 934842727c2SChris Kirby { 935842727c2SChris Kirby boolean_t might_destroy = B_FALSE; 936842727c2SChris Kirby 937842727c2SChris Kirby mutex_enter(&ds->ds_lock); 938842727c2SChris Kirby if (ds->ds_phys->ds_num_children == 2 && ds->ds_userrefs == 0 && 939842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 940842727c2SChris Kirby might_destroy = B_TRUE; 941842727c2SChris Kirby mutex_exit(&ds->ds_lock); 942842727c2SChris Kirby 943842727c2SChris Kirby return (might_destroy); 944842727c2SChris Kirby } 945842727c2SChris Kirby 946842727c2SChris Kirby #ifdef _KERNEL 947842727c2SChris Kirby static int 948842727c2SChris Kirby dsl_dataset_zvol_cleanup(dsl_dataset_t *ds, const char *name) 949842727c2SChris Kirby { 950842727c2SChris Kirby int error; 951842727c2SChris Kirby objset_t *os; 952842727c2SChris Kirby 953*503ad85cSMatthew Ahrens error = dmu_objset_from_ds(ds, &os); 954842727c2SChris Kirby if (error) 955842727c2SChris Kirby return (error); 956842727c2SChris Kirby 957842727c2SChris Kirby if (dmu_objset_type(os) == DMU_OST_ZVOL) 958842727c2SChris Kirby error = zvol_remove_minor(name); 959842727c2SChris Kirby 960842727c2SChris Kirby return (error); 961842727c2SChris Kirby } 962842727c2SChris Kirby #endif 963842727c2SChris Kirby 964842727c2SChris Kirby /* 965842727c2SChris Kirby * If we're removing a clone, and these three conditions are true: 966842727c2SChris Kirby * 1) the clone's origin has no other children 967842727c2SChris Kirby * 2) the clone's origin has no user references 968842727c2SChris Kirby * 3) the clone's origin has been marked for deferred destruction 969842727c2SChris Kirby * Then, prepare to remove the origin as part of this sync task group. 970842727c2SChris Kirby */ 971842727c2SChris Kirby static int 972842727c2SChris Kirby dsl_dataset_origin_rm_prep(struct dsl_ds_destroyarg *dsda, void *tag) 973842727c2SChris Kirby { 974842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 975842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 976842727c2SChris Kirby 977842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(origin)) { 978842727c2SChris Kirby char *name; 979842727c2SChris Kirby int namelen; 980842727c2SChris Kirby int error; 981842727c2SChris Kirby 982842727c2SChris Kirby namelen = dsl_dataset_namelen(origin) + 1; 983842727c2SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 984842727c2SChris Kirby dsl_dataset_name(origin, name); 985842727c2SChris Kirby #ifdef _KERNEL 986842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 987842727c2SChris Kirby if (error) { 988842727c2SChris Kirby kmem_free(name, namelen); 989842727c2SChris Kirby return (error); 990842727c2SChris Kirby } 991842727c2SChris Kirby error = dsl_dataset_zvol_cleanup(origin, name); 992842727c2SChris Kirby if (error) { 993842727c2SChris Kirby kmem_free(name, namelen); 994842727c2SChris Kirby return (error); 995842727c2SChris Kirby } 996842727c2SChris Kirby #endif 997*503ad85cSMatthew Ahrens error = dsl_dataset_own(name, B_TRUE, tag, &origin); 998842727c2SChris Kirby kmem_free(name, namelen); 999842727c2SChris Kirby if (error) 1000842727c2SChris Kirby return (error); 1001842727c2SChris Kirby dsda->rm_origin = origin; 1002842727c2SChris Kirby dsl_dataset_make_exclusive(origin, tag); 1003842727c2SChris Kirby } 1004842727c2SChris Kirby 1005842727c2SChris Kirby return (0); 1006842727c2SChris Kirby } 1007842727c2SChris Kirby 10083cb34c60Sahrens /* 1009745cd3c5Smaybee * ds must be opened as OWNER. On return (whether successful or not), 1010745cd3c5Smaybee * ds will be closed and caller can no longer dereference it. 10113cb34c60Sahrens */ 1012fa9e4066Sahrens int 1013842727c2SChris Kirby dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) 1014fa9e4066Sahrens { 1015fa9e4066Sahrens int err; 10161d452cf5Sahrens dsl_sync_task_group_t *dstg; 10171d452cf5Sahrens objset_t *os; 1018fa9e4066Sahrens dsl_dir_t *dd; 10191d452cf5Sahrens uint64_t obj; 1020842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 1021842727c2SChris Kirby 1022842727c2SChris Kirby dsda.ds = ds; 10231d452cf5Sahrens 10243cb34c60Sahrens if (dsl_dataset_is_snapshot(ds)) { 10251d452cf5Sahrens /* Destroying a snapshot is simpler */ 1026745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 10273baa08fcSek 1028*503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) { 1029*503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 1030*503ad85cSMatthew Ahrens ds->ds_objset = NULL; 10313baa08fcSek } 1032842727c2SChris Kirby /* NOTE: defer is always B_FALSE for non-snapshots */ 1033842727c2SChris Kirby dsda.defer = defer; 10341d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 10351d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 1036842727c2SChris Kirby &dsda, tag, 0); 1037842727c2SChris Kirby ASSERT3P(dsda.rm_origin, ==, NULL); 10383cb34c60Sahrens goto out; 10391d452cf5Sahrens } 1040fa9e4066Sahrens 10411d452cf5Sahrens dd = ds->ds_dir; 1042fa9e4066Sahrens 10431d452cf5Sahrens /* 10441d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 10451d452cf5Sahrens * case we crash while freeing the objects. 10461d452cf5Sahrens */ 10471d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 10481d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 10493cb34c60Sahrens if (err) 10503cb34c60Sahrens goto out; 10513cb34c60Sahrens 1052*503ad85cSMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 10533cb34c60Sahrens if (err) 10543cb34c60Sahrens goto out; 1055fa9e4066Sahrens 10561d452cf5Sahrens /* 10571d452cf5Sahrens * remove the objects in open context, so that we won't 10581d452cf5Sahrens * have too much to do in syncing context. 10591d452cf5Sahrens */ 10606754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 10616754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 1062cdb0ab79Smaybee /* 1063cdb0ab79Smaybee * Ignore errors, if there is not enough disk space 1064cdb0ab79Smaybee * we will deal with it in dsl_dataset_destroy_sync(). 1065cdb0ab79Smaybee */ 1066cdb0ab79Smaybee (void) dmu_free_object(os, obj); 10671d452cf5Sahrens } 10681d452cf5Sahrens 106914843421SMatthew Ahrens /* 107014843421SMatthew Ahrens * We need to sync out all in-flight IO before we try to evict 107114843421SMatthew Ahrens * (the dataset evict func is trying to clear the cached entries 107214843421SMatthew Ahrens * for this dataset in the ARC). 107314843421SMatthew Ahrens */ 107414843421SMatthew Ahrens txg_wait_synced(dd->dd_pool, 0); 107514843421SMatthew Ahrens 107614843421SMatthew Ahrens /* 107714843421SMatthew Ahrens * If we managed to free all the objects in open 107814843421SMatthew Ahrens * context, the user space accounting should be zero. 107914843421SMatthew Ahrens */ 108014843421SMatthew Ahrens if (ds->ds_phys->ds_bp.blk_fill == 0 && 1081*503ad85cSMatthew Ahrens dmu_objset_userused_enabled(os)) { 108214843421SMatthew Ahrens uint64_t count; 108314843421SMatthew Ahrens 108414843421SMatthew Ahrens ASSERT(zap_count(os, DMU_USERUSED_OBJECT, &count) != 0 || 108514843421SMatthew Ahrens count == 0); 108614843421SMatthew Ahrens ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, &count) != 0 || 108714843421SMatthew Ahrens count == 0); 108814843421SMatthew Ahrens } 108914843421SMatthew Ahrens 10901d452cf5Sahrens if (err != ESRCH) 10913cb34c60Sahrens goto out; 10921d452cf5Sahrens 109368038c2cSmaybee rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 109468038c2cSmaybee err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd); 109568038c2cSmaybee rw_exit(&dd->dd_pool->dp_config_rwlock); 109668038c2cSmaybee 109768038c2cSmaybee if (err) 109868038c2cSmaybee goto out; 109968038c2cSmaybee 1100*503ad85cSMatthew Ahrens if (ds->ds_objset) { 1101745cd3c5Smaybee /* 1102745cd3c5Smaybee * We need to sync out all in-flight IO before we try 1103745cd3c5Smaybee * to evict (the dataset evict func is trying to clear 1104745cd3c5Smaybee * the cached entries for this dataset in the ARC). 1105745cd3c5Smaybee */ 1106745cd3c5Smaybee txg_wait_synced(dd->dd_pool, 0); 11071d452cf5Sahrens } 11081d452cf5Sahrens 11091d452cf5Sahrens /* 11101d452cf5Sahrens * Blow away the dsl_dir + head dataset. 11111d452cf5Sahrens */ 1112745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 1113*503ad85cSMatthew Ahrens if (ds->ds_objset) { 1114*503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 1115*503ad85cSMatthew Ahrens ds->ds_objset = NULL; 111668038c2cSmaybee } 1117842727c2SChris Kirby 1118842727c2SChris Kirby /* 1119842727c2SChris Kirby * If we're removing a clone, we might also need to remove its 1120842727c2SChris Kirby * origin. 1121842727c2SChris Kirby */ 1122842727c2SChris Kirby do { 1123842727c2SChris Kirby dsda.need_prep = B_FALSE; 1124842727c2SChris Kirby if (dsl_dir_is_clone(dd)) { 1125842727c2SChris Kirby err = dsl_dataset_origin_rm_prep(&dsda, tag); 1126842727c2SChris Kirby if (err) { 1127842727c2SChris Kirby dsl_dir_close(dd, FTAG); 1128842727c2SChris Kirby goto out; 1129842727c2SChris Kirby } 1130842727c2SChris Kirby } 1131842727c2SChris Kirby 1132842727c2SChris Kirby dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 1133842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 1134842727c2SChris Kirby dsl_dataset_destroy_sync, &dsda, tag, 0); 1135842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dir_destroy_check, 1136842727c2SChris Kirby dsl_dir_destroy_sync, dd, FTAG, 0); 1137842727c2SChris Kirby err = dsl_sync_task_group_wait(dstg); 1138842727c2SChris Kirby dsl_sync_task_group_destroy(dstg); 1139842727c2SChris Kirby 1140842727c2SChris Kirby /* 1141842727c2SChris Kirby * We could be racing against 'zfs release' or 'zfs destroy -d' 1142842727c2SChris Kirby * on the origin snap, in which case we can get EBUSY if we 1143842727c2SChris Kirby * needed to destroy the origin snap but were not ready to 1144842727c2SChris Kirby * do so. 1145842727c2SChris Kirby */ 1146842727c2SChris Kirby if (dsda.need_prep) { 1147842727c2SChris Kirby ASSERT(err == EBUSY); 1148842727c2SChris Kirby ASSERT(dsl_dir_is_clone(dd)); 1149842727c2SChris Kirby ASSERT(dsda.rm_origin == NULL); 1150842727c2SChris Kirby } 1151842727c2SChris Kirby } while (dsda.need_prep); 1152842727c2SChris Kirby 1153842727c2SChris Kirby if (dsda.rm_origin != NULL) 1154842727c2SChris Kirby dsl_dataset_disown(dsda.rm_origin, tag); 1155842727c2SChris Kirby 1156745cd3c5Smaybee /* if it is successful, dsl_dir_destroy_sync will close the dd */ 11573cb34c60Sahrens if (err) 11581d452cf5Sahrens dsl_dir_close(dd, FTAG); 11593cb34c60Sahrens out: 1160745cd3c5Smaybee dsl_dataset_disown(ds, tag); 1161fa9e4066Sahrens return (err); 1162fa9e4066Sahrens } 1163fa9e4066Sahrens 1164c717a561Smaybee blkptr_t * 1165c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 1166fa9e4066Sahrens { 1167c717a561Smaybee return (&ds->ds_phys->ds_bp); 1168fa9e4066Sahrens } 1169fa9e4066Sahrens 1170fa9e4066Sahrens void 1171fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 1172fa9e4066Sahrens { 1173fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1174fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 1175fa9e4066Sahrens if (ds == NULL) { 1176fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 1177fa9e4066Sahrens } else { 1178fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1179fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 1180fa9e4066Sahrens } 1181fa9e4066Sahrens } 1182fa9e4066Sahrens 1183fa9e4066Sahrens spa_t * 1184fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 1185fa9e4066Sahrens { 1186fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 1187fa9e4066Sahrens } 1188fa9e4066Sahrens 1189fa9e4066Sahrens void 1190fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 1191fa9e4066Sahrens { 1192fa9e4066Sahrens dsl_pool_t *dp; 1193fa9e4066Sahrens 1194fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 1195fa9e4066Sahrens return; 1196fa9e4066Sahrens 1197*503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1198a2eea2e1Sahrens 1199a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1200a2eea2e1Sahrens panic("dirtying snapshot!"); 1201fa9e4066Sahrens 1202fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 1203fa9e4066Sahrens 1204fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 1205fa9e4066Sahrens /* up the hold count until we can be written out */ 1206fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 1207fa9e4066Sahrens } 1208fa9e4066Sahrens } 1209fa9e4066Sahrens 1210a9799022Sck /* 1211a9799022Sck * The unique space in the head dataset can be calculated by subtracting 1212a9799022Sck * the space used in the most recent snapshot, that is still being used 1213a9799022Sck * in this file system, from the space currently in use. To figure out 1214a9799022Sck * the space in the most recent snapshot still in use, we need to take 1215a9799022Sck * the total space used in the snapshot and subtract out the space that 1216a9799022Sck * has been freed up since the snapshot was taken. 1217a9799022Sck */ 1218a9799022Sck static void 1219a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds) 1220a9799022Sck { 1221a9799022Sck uint64_t mrs_used; 1222a9799022Sck uint64_t dlused, dlcomp, dluncomp; 1223a9799022Sck 1224a9799022Sck ASSERT(ds->ds_object == ds->ds_dir->dd_phys->dd_head_dataset_obj); 1225a9799022Sck 1226a9799022Sck if (ds->ds_phys->ds_prev_snap_obj != 0) 1227a9799022Sck mrs_used = ds->ds_prev->ds_phys->ds_used_bytes; 1228a9799022Sck else 1229a9799022Sck mrs_used = 0; 1230a9799022Sck 1231a9799022Sck VERIFY(0 == bplist_space(&ds->ds_deadlist, &dlused, &dlcomp, 1232a9799022Sck &dluncomp)); 1233a9799022Sck 1234a9799022Sck ASSERT3U(dlused, <=, mrs_used); 1235a9799022Sck ds->ds_phys->ds_unique_bytes = 1236a9799022Sck ds->ds_phys->ds_used_bytes - (mrs_used - dlused); 1237a9799022Sck 1238a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && 1239a9799022Sck spa_version(ds->ds_dir->dd_pool->dp_spa) >= 1240a9799022Sck SPA_VERSION_UNIQUE_ACCURATE) 1241a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1242a9799022Sck } 1243a9799022Sck 1244a9799022Sck static uint64_t 1245a9799022Sck dsl_dataset_unique(dsl_dataset_t *ds) 1246a9799022Sck { 1247a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && !dsl_dataset_is_snapshot(ds)) 1248a9799022Sck dsl_dataset_recalc_head_uniq(ds); 1249a9799022Sck 1250a9799022Sck return (ds->ds_phys->ds_unique_bytes); 1251a9799022Sck } 1252a9799022Sck 1253fa9e4066Sahrens struct killarg { 125474e7dc98SMatthew Ahrens dsl_dataset_t *ds; 1255fa9e4066Sahrens zio_t *zio; 1256fa9e4066Sahrens dmu_tx_t *tx; 1257fa9e4066Sahrens }; 1258fa9e4066Sahrens 125974e7dc98SMatthew Ahrens /* ARGSUSED */ 1260fa9e4066Sahrens static int 126188b7b0f2SMatthew Ahrens kill_blkptr(spa_t *spa, blkptr_t *bp, const zbookmark_t *zb, 126288b7b0f2SMatthew Ahrens const dnode_phys_t *dnp, void *arg) 1263fa9e4066Sahrens { 1264fa9e4066Sahrens struct killarg *ka = arg; 1265fa9e4066Sahrens 126688b7b0f2SMatthew Ahrens if (bp == NULL) 126788b7b0f2SMatthew Ahrens return (0); 1268fa9e4066Sahrens 1269ab69d62fSMatthew Ahrens if ((zb->zb_level == -1ULL && zb->zb_blkid != 0) || 1270ab69d62fSMatthew Ahrens (zb->zb_object != 0 && dnp == NULL)) { 1271ab69d62fSMatthew Ahrens /* 1272ab69d62fSMatthew Ahrens * It's a block in the intent log. It has no 1273ab69d62fSMatthew Ahrens * accounting, so just free it. 1274ab69d62fSMatthew Ahrens */ 1275ab69d62fSMatthew Ahrens VERIFY3U(0, ==, dsl_free(ka->zio, ka->tx->tx_pool, 1276ab69d62fSMatthew Ahrens ka->tx->tx_txg, bp, NULL, NULL, ARC_NOWAIT)); 1277ab69d62fSMatthew Ahrens } else { 1278ab69d62fSMatthew Ahrens ASSERT3U(bp->blk_birth, >, ka->ds->ds_phys->ds_prev_snap_txg); 1279ab69d62fSMatthew Ahrens (void) dsl_dataset_block_kill(ka->ds, bp, ka->zio, ka->tx); 1280ab69d62fSMatthew Ahrens } 128174e7dc98SMatthew Ahrens 1282fa9e4066Sahrens return (0); 1283fa9e4066Sahrens } 1284fa9e4066Sahrens 1285e1930233Sbonwick /* ARGSUSED */ 1286e1930233Sbonwick static int 12871d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1288e1930233Sbonwick { 12891d452cf5Sahrens dsl_dataset_t *ds = arg1; 12903cb34c60Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 12913cb34c60Sahrens uint64_t count; 12923cb34c60Sahrens int err; 1293e1930233Sbonwick 1294e1930233Sbonwick /* 1295e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1296e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1297e1930233Sbonwick * from.) 1298e1930233Sbonwick */ 1299e1930233Sbonwick if (ds->ds_prev != NULL && 1300e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1301e1930233Sbonwick return (EINVAL); 1302e1930233Sbonwick 13033cb34c60Sahrens /* 13043cb34c60Sahrens * This is really a dsl_dir thing, but check it here so that 13053cb34c60Sahrens * we'll be less likely to leave this dataset inconsistent & 13063cb34c60Sahrens * nearly destroyed. 13073cb34c60Sahrens */ 13083cb34c60Sahrens err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count); 13093cb34c60Sahrens if (err) 13103cb34c60Sahrens return (err); 13113cb34c60Sahrens if (count != 0) 13123cb34c60Sahrens return (EEXIST); 13133cb34c60Sahrens 1314e1930233Sbonwick return (0); 1315e1930233Sbonwick } 1316e1930233Sbonwick 13171d452cf5Sahrens /* ARGSUSED */ 13181d452cf5Sahrens static void 1319ecd6cf80Smarks dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 1320fa9e4066Sahrens { 13211d452cf5Sahrens dsl_dataset_t *ds = arg1; 1322ecd6cf80Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1323fa9e4066Sahrens 13241d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 13251d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 13261d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1327ecd6cf80Smarks 1328ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 1329ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 13301d452cf5Sahrens } 1331fa9e4066Sahrens 1332842727c2SChris Kirby static int 1333842727c2SChris Kirby dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag, 1334842727c2SChris Kirby dmu_tx_t *tx) 1335842727c2SChris Kirby { 1336842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1337842727c2SChris Kirby dsl_dataset_t *ds_prev = ds->ds_prev; 1338842727c2SChris Kirby 1339842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(ds_prev)) { 1340842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1341842727c2SChris Kirby 1342842727c2SChris Kirby /* 1343842727c2SChris Kirby * If we're not prepared to remove the origin, don't remove 1344842727c2SChris Kirby * the clone either. 1345842727c2SChris Kirby */ 1346842727c2SChris Kirby if (dsda->rm_origin == NULL) { 1347842727c2SChris Kirby dsda->need_prep = B_TRUE; 1348842727c2SChris Kirby return (EBUSY); 1349842727c2SChris Kirby } 1350842727c2SChris Kirby 1351842727c2SChris Kirby ndsda.ds = ds_prev; 1352842727c2SChris Kirby ndsda.is_origin_rm = B_TRUE; 1353842727c2SChris Kirby return (dsl_dataset_destroy_check(&ndsda, tag, tx)); 1354842727c2SChris Kirby } 1355842727c2SChris Kirby 1356842727c2SChris Kirby /* 1357842727c2SChris Kirby * If we're not going to remove the origin after all, 1358842727c2SChris Kirby * undo the open context setup. 1359842727c2SChris Kirby */ 1360842727c2SChris Kirby if (dsda->rm_origin != NULL) { 1361842727c2SChris Kirby dsl_dataset_disown(dsda->rm_origin, tag); 1362842727c2SChris Kirby dsda->rm_origin = NULL; 1363842727c2SChris Kirby } 1364842727c2SChris Kirby 1365842727c2SChris Kirby return (0); 1366842727c2SChris Kirby } 1367842727c2SChris Kirby 13681d452cf5Sahrens /* ARGSUSED */ 13693cb34c60Sahrens int 13701d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 13711d452cf5Sahrens { 1372842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1373842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1374fa9e4066Sahrens 1375745cd3c5Smaybee /* we have an owner hold, so noone else can destroy us */ 1376745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 1377745cd3c5Smaybee 1378842727c2SChris Kirby /* 1379842727c2SChris Kirby * Only allow deferred destroy on pools that support it. 1380842727c2SChris Kirby * NOTE: deferred destroy is only supported on snapshots. 1381842727c2SChris Kirby */ 1382842727c2SChris Kirby if (dsda->defer) { 1383842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 1384842727c2SChris Kirby SPA_VERSION_USERREFS) 1385842727c2SChris Kirby return (ENOTSUP); 1386842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 1387842727c2SChris Kirby return (0); 1388842727c2SChris Kirby } 1389fa9e4066Sahrens 1390fa9e4066Sahrens /* 1391fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1392fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1393fa9e4066Sahrens * from.) 1394fa9e4066Sahrens */ 1395fa9e4066Sahrens if (ds->ds_prev != NULL && 13961d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1397fa9e4066Sahrens return (EINVAL); 1398fa9e4066Sahrens 1399fa9e4066Sahrens /* 1400fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1401fa9e4066Sahrens * them. Try again. 1402fa9e4066Sahrens */ 14031d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1404fa9e4066Sahrens return (EAGAIN); 14051d452cf5Sahrens 1406842727c2SChris Kirby if (dsl_dataset_is_snapshot(ds)) { 1407842727c2SChris Kirby /* 1408842727c2SChris Kirby * If this snapshot has an elevated user reference count, 1409842727c2SChris Kirby * we can't destroy it yet. 1410842727c2SChris Kirby */ 1411842727c2SChris Kirby if (ds->ds_userrefs > 0 && !dsda->releasing) 1412842727c2SChris Kirby return (EBUSY); 1413842727c2SChris Kirby 1414842727c2SChris Kirby mutex_enter(&ds->ds_lock); 1415842727c2SChris Kirby /* 1416842727c2SChris Kirby * Can't delete a branch point. However, if we're destroying 1417842727c2SChris Kirby * a clone and removing its origin due to it having a user 1418842727c2SChris Kirby * hold count of 0 and having been marked for deferred destroy, 1419842727c2SChris Kirby * it's OK for the origin to have a single clone. 1420842727c2SChris Kirby */ 1421842727c2SChris Kirby if (ds->ds_phys->ds_num_children > 1422842727c2SChris Kirby (dsda->is_origin_rm ? 2 : 1)) { 1423842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1424842727c2SChris Kirby return (EEXIST); 1425842727c2SChris Kirby } 1426842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1427842727c2SChris Kirby } else if (dsl_dir_is_clone(ds->ds_dir)) { 1428842727c2SChris Kirby return (dsl_dataset_origin_check(dsda, arg2, tx)); 1429842727c2SChris Kirby } 1430842727c2SChris Kirby 14311d452cf5Sahrens /* XXX we should do some i/o error checking... */ 14321d452cf5Sahrens return (0); 14331d452cf5Sahrens } 14341d452cf5Sahrens 1435745cd3c5Smaybee struct refsarg { 1436745cd3c5Smaybee kmutex_t lock; 1437745cd3c5Smaybee boolean_t gone; 1438745cd3c5Smaybee kcondvar_t cv; 1439745cd3c5Smaybee }; 1440745cd3c5Smaybee 1441745cd3c5Smaybee /* ARGSUSED */ 1442745cd3c5Smaybee static void 1443745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv) 1444745cd3c5Smaybee { 1445745cd3c5Smaybee struct refsarg *arg = argv; 1446745cd3c5Smaybee 1447745cd3c5Smaybee mutex_enter(&arg->lock); 1448745cd3c5Smaybee arg->gone = TRUE; 1449745cd3c5Smaybee cv_signal(&arg->cv); 1450745cd3c5Smaybee mutex_exit(&arg->lock); 1451745cd3c5Smaybee } 1452745cd3c5Smaybee 1453745cd3c5Smaybee static void 1454745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag) 1455745cd3c5Smaybee { 1456745cd3c5Smaybee struct refsarg arg; 1457745cd3c5Smaybee 1458745cd3c5Smaybee mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL); 1459745cd3c5Smaybee cv_init(&arg.cv, NULL, CV_DEFAULT, NULL); 1460745cd3c5Smaybee arg.gone = FALSE; 1461745cd3c5Smaybee (void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys, 1462745cd3c5Smaybee dsl_dataset_refs_gone); 1463745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 1464745cd3c5Smaybee mutex_enter(&arg.lock); 1465745cd3c5Smaybee while (!arg.gone) 1466745cd3c5Smaybee cv_wait(&arg.cv, &arg.lock); 1467745cd3c5Smaybee ASSERT(arg.gone); 1468745cd3c5Smaybee mutex_exit(&arg.lock); 1469745cd3c5Smaybee ds->ds_dbuf = NULL; 1470745cd3c5Smaybee ds->ds_phys = NULL; 1471745cd3c5Smaybee mutex_destroy(&arg.lock); 1472745cd3c5Smaybee cv_destroy(&arg.cv); 1473745cd3c5Smaybee } 1474745cd3c5Smaybee 14753cb34c60Sahrens void 1476ecd6cf80Smarks dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 14771d452cf5Sahrens { 1478842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1479842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 14801d452cf5Sahrens zio_t *zio; 14811d452cf5Sahrens int err; 14821d452cf5Sahrens int after_branch_point = FALSE; 14831d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 14841d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 14851d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 14861d452cf5Sahrens uint64_t obj; 14871d452cf5Sahrens 1488745cd3c5Smaybee ASSERT(ds->ds_owner); 1489842727c2SChris Kirby ASSERT(dsda->defer || ds->ds_phys->ds_num_children <= 1); 14901d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 14911d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 14921d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 14931d452cf5Sahrens 1494842727c2SChris Kirby if (dsda->defer) { 1495842727c2SChris Kirby ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 1496842727c2SChris Kirby if (ds->ds_userrefs > 0 || ds->ds_phys->ds_num_children > 1) { 1497842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 1498842727c2SChris Kirby ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY; 1499842727c2SChris Kirby return; 1500842727c2SChris Kirby } 1501842727c2SChris Kirby } 1502842727c2SChris Kirby 1503745cd3c5Smaybee /* signal any waiters that this dataset is going away */ 1504745cd3c5Smaybee mutex_enter(&ds->ds_lock); 1505745cd3c5Smaybee ds->ds_owner = dsl_reaper; 1506745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 1507745cd3c5Smaybee mutex_exit(&ds->ds_lock); 1508745cd3c5Smaybee 1509a9799022Sck /* Remove our reservation */ 1510a9799022Sck if (ds->ds_reserved != 0) { 1511a9799022Sck uint64_t val = 0; 1512a9799022Sck dsl_dataset_set_reservation_sync(ds, &val, cr, tx); 1513a9799022Sck ASSERT3U(ds->ds_reserved, ==, 0); 1514a9799022Sck } 1515a9799022Sck 15161d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 15171d452cf5Sahrens 1518088f3894Sahrens dsl_pool_ds_destroyed(ds, tx); 1519088f3894Sahrens 15201d452cf5Sahrens obj = ds->ds_object; 1521fa9e4066Sahrens 1522fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1523fa9e4066Sahrens if (ds->ds_prev) { 1524fa9e4066Sahrens ds_prev = ds->ds_prev; 1525fa9e4066Sahrens } else { 1526745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1527745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev)); 1528fa9e4066Sahrens } 1529fa9e4066Sahrens after_branch_point = 1530fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1531fa9e4066Sahrens 1532fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1533088f3894Sahrens if (after_branch_point && 1534088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj != 0) { 153514843421SMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(mos, 1536088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, obj, tx)); 1537088f3894Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1538088f3894Sahrens VERIFY(0 == zap_add_int(mos, 1539088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, 1540088f3894Sahrens ds->ds_phys->ds_next_snap_obj, tx)); 1541088f3894Sahrens } 1542088f3894Sahrens } 1543fa9e4066Sahrens if (after_branch_point && 1544fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1545fa9e4066Sahrens /* This clone is toast. */ 1546fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1547fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1548842727c2SChris Kirby 1549842727c2SChris Kirby /* 1550842727c2SChris Kirby * If the clone's origin has no other clones, no 1551842727c2SChris Kirby * user holds, and has been marked for deferred 1552842727c2SChris Kirby * deletion, then we should have done the necessary 1553842727c2SChris Kirby * destroy setup for it. 1554842727c2SChris Kirby */ 1555842727c2SChris Kirby if (ds_prev->ds_phys->ds_num_children == 1 && 1556842727c2SChris Kirby ds_prev->ds_userrefs == 0 && 1557842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds_prev)) { 1558842727c2SChris Kirby ASSERT3P(dsda->rm_origin, !=, NULL); 1559842727c2SChris Kirby } else { 1560842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 1561842727c2SChris Kirby } 1562fa9e4066Sahrens } else if (!after_branch_point) { 1563fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1564fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1565fa9e4066Sahrens } 1566fa9e4066Sahrens } 1567fa9e4066Sahrens 1568fa9e4066Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1569fa9e4066Sahrens 1570fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 15711d452cf5Sahrens blkptr_t bp; 1572fa9e4066Sahrens dsl_dataset_t *ds_next; 1573fa9e4066Sahrens uint64_t itor = 0; 1574a9799022Sck uint64_t old_unique; 157574e7dc98SMatthew Ahrens int64_t used = 0, compressed = 0, uncompressed = 0; 1576fa9e4066Sahrens 1577745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1578745cd3c5Smaybee ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next)); 1579fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1580fa9e4066Sahrens 1581a9799022Sck old_unique = dsl_dataset_unique(ds_next); 1582a9799022Sck 1583fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1584fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1585fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1586fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1587fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1588fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1589fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1590fa9e4066Sahrens 1591fa9e4066Sahrens /* 1592fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1593fa9e4066Sahrens * new deadlist) any entries from next's current 1594fa9e4066Sahrens * deadlist which were born before prev, and free the 1595fa9e4066Sahrens * other entries. 1596fa9e4066Sahrens * 1597fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1598fa9e4066Sahrens */ 1599745cd3c5Smaybee while (bplist_iterate(&ds_next->ds_deadlist, &itor, &bp) == 0) { 1600fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1601ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1602ea8dc4b6Seschrock &bp, tx)); 1603fa9e4066Sahrens if (ds_prev && !after_branch_point && 1604fa9e4066Sahrens bp.blk_birth > 1605fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1606fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 160799653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1608fa9e4066Sahrens } 1609fa9e4066Sahrens } else { 161099653d4eSeschrock used += bp_get_dasize(dp->dp_spa, &bp); 1611fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1612fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1613fa9e4066Sahrens /* XXX check return value? */ 1614088f3894Sahrens (void) dsl_free(zio, dp, tx->tx_txg, 1615fa9e4066Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1616fa9e4066Sahrens } 1617fa9e4066Sahrens } 1618fa9e4066Sahrens 161974e7dc98SMatthew Ahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 162074e7dc98SMatthew Ahrens 162174e7dc98SMatthew Ahrens /* change snapused */ 162274e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 162374e7dc98SMatthew Ahrens -used, -compressed, -uncompressed, tx); 162474e7dc98SMatthew Ahrens 1625fa9e4066Sahrens /* free next's deadlist */ 1626fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1627fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1628fa9e4066Sahrens 1629fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1630745cd3c5Smaybee bplist_close(&ds->ds_deadlist); 1631fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1632fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1633ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1634ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1635fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1636fa9e4066Sahrens 1637fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1638fa9e4066Sahrens /* 1639fa9e4066Sahrens * Update next's unique to include blocks which 1640fa9e4066Sahrens * were previously shared by only this snapshot 1641fa9e4066Sahrens * and it. Those blocks will be born after the 1642fa9e4066Sahrens * prev snap and before this snap, and will have 1643fa9e4066Sahrens * died after the next snap and before the one 1644fa9e4066Sahrens * after that (ie. be on the snap after next's 1645fa9e4066Sahrens * deadlist). 1646fa9e4066Sahrens * 1647fa9e4066Sahrens * XXX we're doing this long task with the 1648fa9e4066Sahrens * config lock held 1649fa9e4066Sahrens */ 1650fa9e4066Sahrens dsl_dataset_t *ds_after_next; 165174e7dc98SMatthew Ahrens uint64_t space; 1652fa9e4066Sahrens 1653745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1654745cd3c5Smaybee ds_next->ds_phys->ds_next_snap_obj, 1655745cd3c5Smaybee FTAG, &ds_after_next)); 165674e7dc98SMatthew Ahrens 165774e7dc98SMatthew Ahrens VERIFY(0 == 165874e7dc98SMatthew Ahrens bplist_space_birthrange(&ds_after_next->ds_deadlist, 165974e7dc98SMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 166074e7dc98SMatthew Ahrens ds->ds_phys->ds_creation_txg, &space)); 166174e7dc98SMatthew Ahrens ds_next->ds_phys->ds_unique_bytes += space; 1662fa9e4066Sahrens 1663745cd3c5Smaybee dsl_dataset_rele(ds_after_next, FTAG); 1664fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1665fa9e4066Sahrens } else { 1666fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1667745cd3c5Smaybee dsl_dataset_drop_ref(ds_next->ds_prev, ds_next); 1668745cd3c5Smaybee ds_next->ds_prev = NULL; 1669fa9e4066Sahrens if (ds_prev) { 1670745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1671745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 1672745cd3c5Smaybee ds_next, &ds_next->ds_prev)); 1673fa9e4066Sahrens } 1674a9799022Sck 1675a9799022Sck dsl_dataset_recalc_head_uniq(ds_next); 1676a9799022Sck 1677a9799022Sck /* 1678a9799022Sck * Reduce the amount of our unconsmed refreservation 1679a9799022Sck * being charged to our parent by the amount of 1680a9799022Sck * new unique data we have gained. 1681a9799022Sck */ 1682a9799022Sck if (old_unique < ds_next->ds_reserved) { 1683a9799022Sck int64_t mrsdelta; 1684a9799022Sck uint64_t new_unique = 1685a9799022Sck ds_next->ds_phys->ds_unique_bytes; 1686a9799022Sck 1687a9799022Sck ASSERT(old_unique <= new_unique); 1688a9799022Sck mrsdelta = MIN(new_unique - old_unique, 1689a9799022Sck ds_next->ds_reserved - old_unique); 169074e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 169174e7dc98SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 1692a9799022Sck } 1693fa9e4066Sahrens } 1694745cd3c5Smaybee dsl_dataset_rele(ds_next, FTAG); 1695fa9e4066Sahrens } else { 1696fa9e4066Sahrens /* 1697fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1698fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1699fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1700fa9e4066Sahrens * safe to ignore the deadlist contents.) 1701fa9e4066Sahrens */ 1702fa9e4066Sahrens struct killarg ka; 1703fa9e4066Sahrens 1704fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1705fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1706fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1707fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1708fa9e4066Sahrens 1709fa9e4066Sahrens /* 1710fa9e4066Sahrens * Free everything that we point to (that's born after 1711fa9e4066Sahrens * the previous snapshot, if we are a clone) 1712fa9e4066Sahrens * 171374e7dc98SMatthew Ahrens * NB: this should be very quick, because we already 171474e7dc98SMatthew Ahrens * freed all the objects in open context. 1715fa9e4066Sahrens */ 171674e7dc98SMatthew Ahrens ka.ds = ds; 1717fa9e4066Sahrens ka.zio = zio; 1718fa9e4066Sahrens ka.tx = tx; 171988b7b0f2SMatthew Ahrens err = traverse_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 172088b7b0f2SMatthew Ahrens TRAVERSE_POST, kill_blkptr, &ka); 1721fa9e4066Sahrens ASSERT3U(err, ==, 0); 17223e78c5fbSChris Kirby ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 172374e7dc98SMatthew Ahrens ds->ds_phys->ds_unique_bytes == 0); 1724fa9e4066Sahrens } 1725fa9e4066Sahrens 1726fa9e4066Sahrens err = zio_wait(zio); 1727fa9e4066Sahrens ASSERT3U(err, ==, 0); 1728fa9e4066Sahrens 17291d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1730745cd3c5Smaybee /* Erase the link in the dir */ 17311d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 17321d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1733745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0); 1734745cd3c5Smaybee err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1735745cd3c5Smaybee ASSERT(err == 0); 1736fa9e4066Sahrens } else { 1737fa9e4066Sahrens /* remove from snapshot namespace */ 1738fa9e4066Sahrens dsl_dataset_t *ds_head; 1739745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0); 1740745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1741745cd3c5Smaybee ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head)); 17428660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1743fa9e4066Sahrens #ifdef ZFS_DEBUG 1744fa9e4066Sahrens { 1745fa9e4066Sahrens uint64_t val; 1746ab04eb8eStimh 1747745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds_head, 1748ab04eb8eStimh ds->ds_snapname, &val); 1749fa9e4066Sahrens ASSERT3U(err, ==, 0); 1750fa9e4066Sahrens ASSERT3U(val, ==, obj); 1751fa9e4066Sahrens } 1752fa9e4066Sahrens #endif 1753745cd3c5Smaybee err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx); 1754fa9e4066Sahrens ASSERT(err == 0); 1755745cd3c5Smaybee dsl_dataset_rele(ds_head, FTAG); 1756fa9e4066Sahrens } 1757fa9e4066Sahrens 1758fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1759745cd3c5Smaybee dsl_dataset_rele(ds_prev, FTAG); 1760fa9e4066Sahrens 1761990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 1762ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx, 1763ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 1764ecd6cf80Smarks 1765088f3894Sahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 1766088f3894Sahrens uint64_t count; 1767088f3894Sahrens ASSERT(0 == zap_count(mos, 1768088f3894Sahrens ds->ds_phys->ds_next_clones_obj, &count) && count == 0); 1769088f3894Sahrens VERIFY(0 == dmu_object_free(mos, 1770088f3894Sahrens ds->ds_phys->ds_next_clones_obj, tx)); 1771088f3894Sahrens } 177274e7dc98SMatthew Ahrens if (ds->ds_phys->ds_props_obj != 0) 177374e7dc98SMatthew Ahrens VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_props_obj, tx)); 1774842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) 1775842727c2SChris Kirby VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx)); 1776745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 1777745cd3c5Smaybee ds->ds_dir = NULL; 1778745cd3c5Smaybee dsl_dataset_drain_refs(ds, tag); 17791d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1780842727c2SChris Kirby 1781842727c2SChris Kirby if (dsda->rm_origin) { 1782842727c2SChris Kirby /* 1783842727c2SChris Kirby * Remove the origin of the clone we just destroyed. 1784842727c2SChris Kirby */ 1785842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 1786842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1787842727c2SChris Kirby 1788842727c2SChris Kirby ASSERT3P(origin, ==, dsda->rm_origin); 1789*503ad85cSMatthew Ahrens if (origin->ds_objset) { 1790*503ad85cSMatthew Ahrens dmu_objset_evict(origin->ds_objset); 1791*503ad85cSMatthew Ahrens origin->ds_objset = NULL; 1792842727c2SChris Kirby } 1793842727c2SChris Kirby 1794*503ad85cSMatthew Ahrens dsl_dataset_rele(ds->ds_prev, ds); 1795842727c2SChris Kirby ds->ds_prev = NULL; 1796842727c2SChris Kirby 1797842727c2SChris Kirby ndsda.ds = origin; 1798842727c2SChris Kirby dsl_dataset_destroy_sync(&ndsda, tag, cr, tx); 1799842727c2SChris Kirby } 1800fa9e4066Sahrens } 1801fa9e4066Sahrens 1802a9799022Sck static int 1803a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx) 1804a9799022Sck { 1805a9799022Sck uint64_t asize; 1806a9799022Sck 1807a9799022Sck if (!dmu_tx_is_syncing(tx)) 1808a9799022Sck return (0); 1809a9799022Sck 1810a9799022Sck /* 1811a9799022Sck * If there's an fs-only reservation, any blocks that might become 1812a9799022Sck * owned by the snapshot dataset must be accommodated by space 1813a9799022Sck * outside of the reservation. 1814a9799022Sck */ 1815a9799022Sck asize = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 1816a9799022Sck if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, FALSE)) 1817a9799022Sck return (ENOSPC); 1818a9799022Sck 1819a9799022Sck /* 1820a9799022Sck * Propogate any reserved space for this snapshot to other 1821a9799022Sck * snapshot checks in this sync group. 1822a9799022Sck */ 1823a9799022Sck if (asize > 0) 1824a9799022Sck dsl_dir_willuse_space(ds->ds_dir, asize, tx); 1825a9799022Sck 1826a9799022Sck return (0); 1827a9799022Sck } 1828a9799022Sck 18291d452cf5Sahrens /* ARGSUSED */ 1830fa9e4066Sahrens int 18311d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1832fa9e4066Sahrens { 18333cb34c60Sahrens dsl_dataset_t *ds = arg1; 18341d452cf5Sahrens const char *snapname = arg2; 1835fa9e4066Sahrens int err; 18361d452cf5Sahrens uint64_t value; 1837fa9e4066Sahrens 18381d452cf5Sahrens /* 18391d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 18401d452cf5Sahrens * is already one, try again. 18411d452cf5Sahrens */ 18421d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 18431d452cf5Sahrens return (EAGAIN); 1844fa9e4066Sahrens 18451d452cf5Sahrens /* 18461d452cf5Sahrens * Check for conflicting name snapshot name. 18471d452cf5Sahrens */ 1848745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds, snapname, &value); 18491d452cf5Sahrens if (err == 0) 1850fa9e4066Sahrens return (EEXIST); 18511d452cf5Sahrens if (err != ENOENT) 18521d452cf5Sahrens return (err); 1853fa9e4066Sahrens 1854b7661cccSmmusante /* 1855b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 1856b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 1857b7661cccSmmusante */ 1858b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 1859b7661cccSmmusante return (ENAMETOOLONG); 1860b7661cccSmmusante 1861a9799022Sck err = dsl_dataset_snapshot_reserve_space(ds, tx); 1862a9799022Sck if (err) 1863a9799022Sck return (err); 1864a9799022Sck 18651d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 18661d452cf5Sahrens return (0); 18671d452cf5Sahrens } 1868fa9e4066Sahrens 18691d452cf5Sahrens void 1870ecd6cf80Smarks dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 18711d452cf5Sahrens { 18723cb34c60Sahrens dsl_dataset_t *ds = arg1; 18731d452cf5Sahrens const char *snapname = arg2; 18741d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 18751d452cf5Sahrens dmu_buf_t *dbuf; 18761d452cf5Sahrens dsl_dataset_phys_t *dsphys; 1877088f3894Sahrens uint64_t dsobj, crtxg; 18781d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 18791d452cf5Sahrens int err; 1880fa9e4066Sahrens 18811d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1882fa9e4066Sahrens 1883088f3894Sahrens /* 1884088f3894Sahrens * The origin's ds_creation_txg has to be < TXG_INITIAL 1885088f3894Sahrens */ 1886088f3894Sahrens if (strcmp(snapname, ORIGIN_DIR_NAME) == 0) 1887088f3894Sahrens crtxg = 1; 1888088f3894Sahrens else 1889088f3894Sahrens crtxg = tx->tx_txg; 1890088f3894Sahrens 18911649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 18921649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 1893ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1894fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 1895fa9e4066Sahrens dsphys = dbuf->db_data; 1896745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 18971d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 1898fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 1899fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1900fa9e4066Sahrens sizeof (dsphys->ds_guid)); 1901fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1902fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1903fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1904fa9e4066Sahrens dsphys->ds_num_children = 1; 1905fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1906088f3894Sahrens dsphys->ds_creation_txg = crtxg; 1907fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1908fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1909fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1910fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 191199653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 1912fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 1913ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 1914fa9e4066Sahrens 19151d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 19161d452cf5Sahrens if (ds->ds_prev) { 1917088f3894Sahrens uint64_t next_clones_obj = 1918088f3894Sahrens ds->ds_prev->ds_phys->ds_next_clones_obj; 19191d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 1920fa9e4066Sahrens ds->ds_object || 19211d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 19221d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 19231d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1924fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 19251d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 19261d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1927088f3894Sahrens } else if (next_clones_obj != 0) { 1928088f3894Sahrens VERIFY3U(0, ==, zap_remove_int(mos, 1929088f3894Sahrens next_clones_obj, dsphys->ds_next_snap_obj, tx)); 1930088f3894Sahrens VERIFY3U(0, ==, zap_add_int(mos, 1931088f3894Sahrens next_clones_obj, dsobj, tx)); 1932fa9e4066Sahrens } 1933fa9e4066Sahrens } 1934fa9e4066Sahrens 1935a9799022Sck /* 1936a9799022Sck * If we have a reference-reservation on this dataset, we will 1937a9799022Sck * need to increase the amount of refreservation being charged 1938a9799022Sck * since our unique space is going to zero. 1939a9799022Sck */ 1940a9799022Sck if (ds->ds_reserved) { 1941a9799022Sck int64_t add = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 194274e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, 194374e7dc98SMatthew Ahrens add, 0, 0, tx); 1944a9799022Sck } 1945a9799022Sck 1946fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1947fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1948a4611edeSahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg); 1949fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1950088f3894Sahrens ds->ds_phys->ds_prev_snap_txg = crtxg; 1951fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1952a9799022Sck if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 1953a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1954fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1955fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1956ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1957ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1958fa9e4066Sahrens 1959fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1960fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1961fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 1962fa9e4066Sahrens ASSERT(err == 0); 1963fa9e4066Sahrens 1964fa9e4066Sahrens if (ds->ds_prev) 1965745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 1966745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1967745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev)); 1968ecd6cf80Smarks 1969088f3894Sahrens dsl_pool_ds_snapshotted(ds, tx); 1970088f3894Sahrens 1971ecd6cf80Smarks spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr, 197240feaa91Sahrens "dataset = %llu", dsobj); 1973fa9e4066Sahrens } 1974fa9e4066Sahrens 1975fa9e4066Sahrens void 1976c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 1977fa9e4066Sahrens { 1978fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1979*503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1980fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1981fa9e4066Sahrens 198291ebeef5Sahrens /* 198391ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 198491ebeef5Sahrens * sync it out now. 198591ebeef5Sahrens */ 198691ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 198791ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 198891ebeef5Sahrens 1989fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 1990*503ad85cSMatthew Ahrens dmu_objset_sync(ds->ds_objset, zio, tx); 1991fa9e4066Sahrens } 1992fa9e4066Sahrens 1993fa9e4066Sahrens void 1994a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 1995fa9e4066Sahrens { 1996a9799022Sck uint64_t refd, avail, uobjs, aobjs; 1997a9799022Sck 1998a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 1999fa9e4066Sahrens 2000a9799022Sck dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); 2001a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); 2002a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); 2003a9799022Sck 2004a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 2005a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 2006a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 2007a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 2008a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, 2009a9799022Sck ds->ds_quota); 2010a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, 2011a9799022Sck ds->ds_reserved); 2012c5904d13Seschrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, 2013c5904d13Seschrock ds->ds_phys->ds_guid); 2014842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, ds->ds_userrefs); 2015842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2016842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2017fa9e4066Sahrens 2018fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2019fa9e4066Sahrens /* 2020fa9e4066Sahrens * This is a snapshot; override the dd's space used with 2021a2eea2e1Sahrens * our unique space and compression ratio. 2022fa9e4066Sahrens */ 2023a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 2024a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 2025a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 2026a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 2027a2eea2e1Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 2028a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes)); 2029fa9e4066Sahrens } 2030fa9e4066Sahrens } 2031fa9e4066Sahrens 2032a2eea2e1Sahrens void 2033a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2034a2eea2e1Sahrens { 2035a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2036a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 20373cb34c60Sahrens stat->dds_guid = ds->ds_phys->ds_guid; 2038a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2039a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 2040a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 2041ebedde84SEric Taylor } else { 2042ebedde84SEric Taylor stat->dds_is_snapshot = B_FALSE; 2043ebedde84SEric Taylor stat->dds_num_clones = 0; 2044a2eea2e1Sahrens } 2045a2eea2e1Sahrens 2046a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 20474ccbb6e7Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 2048088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 2049a2eea2e1Sahrens dsl_dataset_t *ods; 2050a2eea2e1Sahrens 2051745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool, 2052745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods)); 20533cb34c60Sahrens dsl_dataset_name(ods, stat->dds_origin); 2054745cd3c5Smaybee dsl_dataset_drop_ref(ods, FTAG); 2055ebedde84SEric Taylor } else { 2056ebedde84SEric Taylor stat->dds_origin[0] = '\0'; 2057a2eea2e1Sahrens } 20584ccbb6e7Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2059a2eea2e1Sahrens } 2060a2eea2e1Sahrens 2061a2eea2e1Sahrens uint64_t 2062a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 2063a2eea2e1Sahrens { 206491ebeef5Sahrens return (ds->ds_fsid_guid); 2065a2eea2e1Sahrens } 2066a2eea2e1Sahrens 2067a2eea2e1Sahrens void 2068a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 2069a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 2070a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 2071fa9e4066Sahrens { 2072a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 2073a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 2074a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) 2075a9799022Sck *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes; 2076a9799022Sck if (ds->ds_quota != 0) { 2077a9799022Sck /* 2078a9799022Sck * Adjust available bytes according to refquota 2079a9799022Sck */ 2080a9799022Sck if (*refdbytesp < ds->ds_quota) 2081a9799022Sck *availbytesp = MIN(*availbytesp, 2082a9799022Sck ds->ds_quota - *refdbytesp); 2083a9799022Sck else 2084a9799022Sck *availbytesp = 0; 2085a9799022Sck } 2086a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 2087a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 2088fa9e4066Sahrens } 2089fa9e4066Sahrens 2090f18faf3fSek boolean_t 2091f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 2092f18faf3fSek { 2093f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 2094f18faf3fSek 2095f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 2096f18faf3fSek dsl_pool_sync_context(dp)); 2097f18faf3fSek if (ds->ds_prev == NULL) 2098f18faf3fSek return (B_FALSE); 2099f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 2100f18faf3fSek ds->ds_prev->ds_phys->ds_creation_txg) 2101f18faf3fSek return (B_TRUE); 2102f18faf3fSek return (B_FALSE); 2103f18faf3fSek } 2104f18faf3fSek 21051d452cf5Sahrens /* ARGSUSED */ 2106fa9e4066Sahrens static int 21071d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 2108fa9e4066Sahrens { 21091d452cf5Sahrens dsl_dataset_t *ds = arg1; 21101d452cf5Sahrens char *newsnapname = arg2; 21111d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 21121d452cf5Sahrens dsl_dataset_t *hds; 2113fa9e4066Sahrens uint64_t val; 21141d452cf5Sahrens int err; 2115fa9e4066Sahrens 2116745cd3c5Smaybee err = dsl_dataset_hold_obj(dd->dd_pool, 2117745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds); 2118fa9e4066Sahrens if (err) 2119fa9e4066Sahrens return (err); 2120fa9e4066Sahrens 21211d452cf5Sahrens /* new name better not be in use */ 2122745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, newsnapname, &val); 2123745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 21241d452cf5Sahrens 21251d452cf5Sahrens if (err == 0) 21261d452cf5Sahrens err = EEXIST; 21271d452cf5Sahrens else if (err == ENOENT) 21281d452cf5Sahrens err = 0; 2129cdf5b4caSmmusante 2130cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 2131cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 2132cdf5b4caSmmusante err = ENAMETOOLONG; 2133cdf5b4caSmmusante 21341d452cf5Sahrens return (err); 21351d452cf5Sahrens } 2136fa9e4066Sahrens 21371d452cf5Sahrens static void 2138ecd6cf80Smarks dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, 2139ecd6cf80Smarks cred_t *cr, dmu_tx_t *tx) 21401d452cf5Sahrens { 21411d452cf5Sahrens dsl_dataset_t *ds = arg1; 2142ecd6cf80Smarks const char *newsnapname = arg2; 21431d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 21441d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 21451d452cf5Sahrens dsl_dataset_t *hds; 21461d452cf5Sahrens int err; 2147fa9e4066Sahrens 21481d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 2149fa9e4066Sahrens 2150745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, 2151745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds)); 2152fa9e4066Sahrens 21531d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2154745cd3c5Smaybee err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx); 2155fa9e4066Sahrens ASSERT3U(err, ==, 0); 21561d452cf5Sahrens mutex_enter(&ds->ds_lock); 21571d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 21581d452cf5Sahrens mutex_exit(&ds->ds_lock); 21591d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 21601d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 2161fa9e4066Sahrens ASSERT3U(err, ==, 0); 2162fa9e4066Sahrens 2163ecd6cf80Smarks spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 2164ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 2165745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 2166fa9e4066Sahrens } 2167fa9e4066Sahrens 2168f18faf3fSek struct renamesnaparg { 2169cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 2170cdf5b4caSmmusante char failed[MAXPATHLEN]; 2171cdf5b4caSmmusante char *oldsnap; 2172cdf5b4caSmmusante char *newsnap; 2173cdf5b4caSmmusante }; 2174cdf5b4caSmmusante 2175cdf5b4caSmmusante static int 2176cdf5b4caSmmusante dsl_snapshot_rename_one(char *name, void *arg) 2177cdf5b4caSmmusante { 2178f18faf3fSek struct renamesnaparg *ra = arg; 2179cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 2180cdf5b4caSmmusante char *cp; 2181cdf5b4caSmmusante int err; 2182cdf5b4caSmmusante 2183cdf5b4caSmmusante cp = name + strlen(name); 2184cdf5b4caSmmusante *cp = '@'; 2185cdf5b4caSmmusante (void) strcpy(cp + 1, ra->oldsnap); 2186ecd6cf80Smarks 2187ecd6cf80Smarks /* 2188ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 2189ecd6cf80Smarks * so we just pass name for both the to/from argument. 2190ecd6cf80Smarks */ 2191a0dc2951SMatthew Ahrens err = zfs_secpolicy_rename_perms(name, name, CRED()); 2192a0dc2951SMatthew Ahrens if (err == ENOENT) { 2193a0dc2951SMatthew Ahrens return (0); 2194a0dc2951SMatthew Ahrens } else if (err) { 2195ecd6cf80Smarks (void) strcpy(ra->failed, name); 2196ecd6cf80Smarks return (err); 2197ecd6cf80Smarks } 2198ecd6cf80Smarks 2199745cd3c5Smaybee #ifdef _KERNEL 2200745cd3c5Smaybee /* 2201745cd3c5Smaybee * For all filesystems undergoing rename, we'll need to unmount it. 2202745cd3c5Smaybee */ 2203745cd3c5Smaybee (void) zfs_unmount_snap(name, NULL); 2204745cd3c5Smaybee #endif 2205745cd3c5Smaybee err = dsl_dataset_hold(name, ra->dstg, &ds); 2206745cd3c5Smaybee *cp = '\0'; 2207cdf5b4caSmmusante if (err == ENOENT) { 2208cdf5b4caSmmusante return (0); 2209745cd3c5Smaybee } else if (err) { 2210cdf5b4caSmmusante (void) strcpy(ra->failed, name); 2211cdf5b4caSmmusante return (err); 2212cdf5b4caSmmusante } 2213cdf5b4caSmmusante 2214cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 2215cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 2216cdf5b4caSmmusante 2217cdf5b4caSmmusante return (0); 2218cdf5b4caSmmusante } 2219cdf5b4caSmmusante 2220cdf5b4caSmmusante static int 2221cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 2222cdf5b4caSmmusante { 2223cdf5b4caSmmusante int err; 2224f18faf3fSek struct renamesnaparg *ra; 2225cdf5b4caSmmusante dsl_sync_task_t *dst; 2226cdf5b4caSmmusante spa_t *spa; 2227cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 2228cdf5b4caSmmusante int len = strlen(oldname); 2229cdf5b4caSmmusante 2230cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 2231cdf5b4caSmmusante cp = strchr(fsname, '@'); 2232cdf5b4caSmmusante *cp = '\0'; 2233cdf5b4caSmmusante 223440feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 2235cdf5b4caSmmusante if (err) { 2236cdf5b4caSmmusante kmem_free(fsname, len + 1); 2237cdf5b4caSmmusante return (err); 2238cdf5b4caSmmusante } 2239f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 2240cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 2241cdf5b4caSmmusante 2242cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 2243cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 2244cdf5b4caSmmusante *ra->failed = '\0'; 2245cdf5b4caSmmusante 2246cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 2247cdf5b4caSmmusante DS_FIND_CHILDREN); 2248cdf5b4caSmmusante kmem_free(fsname, len + 1); 2249cdf5b4caSmmusante 2250cdf5b4caSmmusante if (err == 0) { 2251cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 2252cdf5b4caSmmusante } 2253cdf5b4caSmmusante 2254cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 2255cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 2256cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 2257cdf5b4caSmmusante if (dst->dst_err) { 2258cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 22592572aa4eSmmusante (void) strcat(ra->failed, "@"); 22602572aa4eSmmusante (void) strcat(ra->failed, ra->newsnap); 2261cdf5b4caSmmusante } 2262745cd3c5Smaybee dsl_dataset_rele(ds, ra->dstg); 2263cdf5b4caSmmusante } 2264cdf5b4caSmmusante 2265ecd6cf80Smarks if (err) 2266ecd6cf80Smarks (void) strcpy(oldname, ra->failed); 2267cdf5b4caSmmusante 2268cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 2269f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 2270cdf5b4caSmmusante spa_close(spa, FTAG); 2271cdf5b4caSmmusante return (err); 2272cdf5b4caSmmusante } 2273cdf5b4caSmmusante 22743a5a36beSmmusante static int 22753a5a36beSmmusante dsl_valid_rename(char *oldname, void *arg) 22763a5a36beSmmusante { 22773a5a36beSmmusante int delta = *(int *)arg; 22783a5a36beSmmusante 22793a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 22803a5a36beSmmusante return (ENAMETOOLONG); 22813a5a36beSmmusante 22823a5a36beSmmusante return (0); 22833a5a36beSmmusante } 22843a5a36beSmmusante 2285fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 2286fa9e4066Sahrens int 2287745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive) 2288fa9e4066Sahrens { 2289fa9e4066Sahrens dsl_dir_t *dd; 22901d452cf5Sahrens dsl_dataset_t *ds; 2291fa9e4066Sahrens const char *tail; 2292fa9e4066Sahrens int err; 2293fa9e4066Sahrens 22941d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 2295ea8dc4b6Seschrock if (err) 2296ea8dc4b6Seschrock return (err); 22971db42183SEric Taylor /* 22981db42183SEric Taylor * If there are more than 2 references there may be holds 22991db42183SEric Taylor * hanging around that haven't been cleared out yet. 23001db42183SEric Taylor */ 23011db42183SEric Taylor if (dmu_buf_refcount(dd->dd_dbuf) > 2) 23021db42183SEric Taylor txg_wait_synced(dd->dd_pool, 0); 2303fa9e4066Sahrens if (tail == NULL) { 23043a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 23053a5a36beSmmusante 2306088f3894Sahrens /* if we're growing, validate child name lengths */ 23073a5a36beSmmusante if (delta > 0) 23083a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 23093a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 23103a5a36beSmmusante 23113a5a36beSmmusante if (!err) 23123a5a36beSmmusante err = dsl_dir_rename(dd, newname); 2313fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2314fa9e4066Sahrens return (err); 2315fa9e4066Sahrens } 2316fa9e4066Sahrens if (tail[0] != '@') { 2317fa9e4066Sahrens /* the name ended in a nonexistant component */ 2318fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2319fa9e4066Sahrens return (ENOENT); 2320fa9e4066Sahrens } 2321fa9e4066Sahrens 2322fa9e4066Sahrens dsl_dir_close(dd, FTAG); 23231d452cf5Sahrens 23241d452cf5Sahrens /* new name must be snapshot in same filesystem */ 23251d452cf5Sahrens tail = strchr(newname, '@'); 23261d452cf5Sahrens if (tail == NULL) 23271d452cf5Sahrens return (EINVAL); 23281d452cf5Sahrens tail++; 23291d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 23301d452cf5Sahrens return (EXDEV); 23311d452cf5Sahrens 2332cdf5b4caSmmusante if (recursive) { 2333cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 2334cdf5b4caSmmusante } else { 2335745cd3c5Smaybee err = dsl_dataset_hold(oldname, FTAG, &ds); 2336cdf5b4caSmmusante if (err) 2337cdf5b4caSmmusante return (err); 23381d452cf5Sahrens 2339cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2340cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 2341cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 23421d452cf5Sahrens 2343745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2344cdf5b4caSmmusante } 23451d452cf5Sahrens 2346fa9e4066Sahrens return (err); 2347fa9e4066Sahrens } 234899653d4eSeschrock 2349088f3894Sahrens struct promotenode { 2350745cd3c5Smaybee list_node_t link; 2351745cd3c5Smaybee dsl_dataset_t *ds; 2352745cd3c5Smaybee }; 2353745cd3c5Smaybee 23541d452cf5Sahrens struct promotearg { 235574e7dc98SMatthew Ahrens list_t shared_snaps, origin_snaps, clone_snaps; 235674e7dc98SMatthew Ahrens dsl_dataset_t *origin_origin, *origin_head; 235774e7dc98SMatthew Ahrens uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; 23581d452cf5Sahrens }; 23591d452cf5Sahrens 236074e7dc98SMatthew Ahrens static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep); 236174e7dc98SMatthew Ahrens 2362ecd6cf80Smarks /* ARGSUSED */ 236399653d4eSeschrock static int 23641d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 236599653d4eSeschrock { 23661d452cf5Sahrens dsl_dataset_t *hds = arg1; 23671d452cf5Sahrens struct promotearg *pa = arg2; 236874e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2369745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 2370745cd3c5Smaybee int err; 23711d452cf5Sahrens 2372088f3894Sahrens /* Check that it is a real clone */ 2373088f3894Sahrens if (!dsl_dir_is_clone(hds->ds_dir)) 237499653d4eSeschrock return (EINVAL); 237599653d4eSeschrock 23761d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 23771d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 23781d452cf5Sahrens return (0); 23791d452cf5Sahrens 2380745cd3c5Smaybee if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) 2381745cd3c5Smaybee return (EXDEV); 238299653d4eSeschrock 23833cb34c60Sahrens /* compute origin's new unique space */ 238474e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 238574e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 238674e7dc98SMatthew Ahrens err = bplist_space_birthrange(&snap->ds->ds_deadlist, 238774e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, &pa->unique); 238874e7dc98SMatthew Ahrens if (err) 2389745cd3c5Smaybee return (err); 239099653d4eSeschrock 2391745cd3c5Smaybee /* 2392745cd3c5Smaybee * Walk the snapshots that we are moving 2393745cd3c5Smaybee * 239474e7dc98SMatthew Ahrens * Compute space to transfer. Consider the incremental changes 239574e7dc98SMatthew Ahrens * to used for each snapshot: 239674e7dc98SMatthew Ahrens * (my used) = (prev's used) + (blocks born) - (blocks killed) 239774e7dc98SMatthew Ahrens * So each snapshot gave birth to: 239874e7dc98SMatthew Ahrens * (blocks born) = (my used) - (prev's used) + (blocks killed) 2399745cd3c5Smaybee * So a sequence would look like: 240074e7dc98SMatthew Ahrens * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0) 2401745cd3c5Smaybee * Which simplifies to: 240274e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + k1 + k0 2403745cd3c5Smaybee * Note however, if we stop before we reach the ORIGIN we get: 240474e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + kM - uM-1 2405745cd3c5Smaybee */ 2406745cd3c5Smaybee pa->used = origin_ds->ds_phys->ds_used_bytes; 2407745cd3c5Smaybee pa->comp = origin_ds->ds_phys->ds_compressed_bytes; 2408745cd3c5Smaybee pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes; 240974e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 241074e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 241199653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 2412745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 241399653d4eSeschrock 241499653d4eSeschrock /* Check that the snapshot name does not conflict */ 241574e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2416745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); 2417745cd3c5Smaybee if (err == 0) 241874e7dc98SMatthew Ahrens return (EEXIST); 2419745cd3c5Smaybee if (err != ENOENT) 242074e7dc98SMatthew Ahrens return (err); 242199653d4eSeschrock 2422745cd3c5Smaybee /* The very first snapshot does not have a deadlist */ 242374e7dc98SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 242474e7dc98SMatthew Ahrens continue; 242574e7dc98SMatthew Ahrens 242674e7dc98SMatthew Ahrens if (err = bplist_space(&ds->ds_deadlist, 242774e7dc98SMatthew Ahrens &dlused, &dlcomp, &dluncomp)) 242874e7dc98SMatthew Ahrens return (err); 242974e7dc98SMatthew Ahrens pa->used += dlused; 243074e7dc98SMatthew Ahrens pa->comp += dlcomp; 243174e7dc98SMatthew Ahrens pa->uncomp += dluncomp; 243274e7dc98SMatthew Ahrens } 2433745cd3c5Smaybee 2434745cd3c5Smaybee /* 2435745cd3c5Smaybee * If we are a clone of a clone then we never reached ORIGIN, 2436745cd3c5Smaybee * so we need to subtract out the clone origin's used space. 2437745cd3c5Smaybee */ 243874e7dc98SMatthew Ahrens if (pa->origin_origin) { 243974e7dc98SMatthew Ahrens pa->used -= pa->origin_origin->ds_phys->ds_used_bytes; 244074e7dc98SMatthew Ahrens pa->comp -= pa->origin_origin->ds_phys->ds_compressed_bytes; 244174e7dc98SMatthew Ahrens pa->uncomp -= pa->origin_origin->ds_phys->ds_uncompressed_bytes; 244299653d4eSeschrock } 244399653d4eSeschrock 244499653d4eSeschrock /* Check that there is enough space here */ 244574e7dc98SMatthew Ahrens err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir, 244674e7dc98SMatthew Ahrens pa->used); 244774e7dc98SMatthew Ahrens if (err) 244874e7dc98SMatthew Ahrens return (err); 244974e7dc98SMatthew Ahrens 245074e7dc98SMatthew Ahrens /* 245174e7dc98SMatthew Ahrens * Compute the amounts of space that will be used by snapshots 245274e7dc98SMatthew Ahrens * after the promotion (for both origin and clone). For each, 245374e7dc98SMatthew Ahrens * it is the amount of space that will be on all of their 245474e7dc98SMatthew Ahrens * deadlists (that was not born before their new origin). 245574e7dc98SMatthew Ahrens */ 245674e7dc98SMatthew Ahrens if (hds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 245774e7dc98SMatthew Ahrens uint64_t space; 245874e7dc98SMatthew Ahrens 245974e7dc98SMatthew Ahrens /* 246074e7dc98SMatthew Ahrens * Note, typically this will not be a clone of a clone, 246174e7dc98SMatthew Ahrens * so snap->ds->ds_origin_txg will be < TXG_INITIAL, so 246274e7dc98SMatthew Ahrens * these snaplist_space() -> bplist_space_birthrange() 246374e7dc98SMatthew Ahrens * calls will be fast because they do not have to 246474e7dc98SMatthew Ahrens * iterate over all bps. 246574e7dc98SMatthew Ahrens */ 246674e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 246774e7dc98SMatthew Ahrens err = snaplist_space(&pa->shared_snaps, 246874e7dc98SMatthew Ahrens snap->ds->ds_origin_txg, &pa->cloneusedsnap); 246974e7dc98SMatthew Ahrens if (err) 247074e7dc98SMatthew Ahrens return (err); 247174e7dc98SMatthew Ahrens 247274e7dc98SMatthew Ahrens err = snaplist_space(&pa->clone_snaps, 247374e7dc98SMatthew Ahrens snap->ds->ds_origin_txg, &space); 247474e7dc98SMatthew Ahrens if (err) 247574e7dc98SMatthew Ahrens return (err); 247674e7dc98SMatthew Ahrens pa->cloneusedsnap += space; 247774e7dc98SMatthew Ahrens } 247874e7dc98SMatthew Ahrens if (origin_ds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 247974e7dc98SMatthew Ahrens err = snaplist_space(&pa->origin_snaps, 248074e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_creation_txg, &pa->originusedsnap); 248174e7dc98SMatthew Ahrens if (err) 248274e7dc98SMatthew Ahrens return (err); 2483745cd3c5Smaybee } 24841d452cf5Sahrens 248574e7dc98SMatthew Ahrens return (0); 24861d452cf5Sahrens } 248799653d4eSeschrock 24881d452cf5Sahrens static void 2489ecd6cf80Smarks dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 24901d452cf5Sahrens { 24911d452cf5Sahrens dsl_dataset_t *hds = arg1; 24921d452cf5Sahrens struct promotearg *pa = arg2; 249374e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2494745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 249574e7dc98SMatthew Ahrens dsl_dataset_t *origin_head; 24961d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 24971d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 24983cb34c60Sahrens dsl_dir_t *odd = NULL; 2499088f3894Sahrens uint64_t oldnext_obj; 250074e7dc98SMatthew Ahrens int64_t delta; 25011d452cf5Sahrens 25021d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 25031d452cf5Sahrens 250474e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 250574e7dc98SMatthew Ahrens origin_head = snap->ds; 250674e7dc98SMatthew Ahrens 25070b69c2f0Sahrens /* 25083cb34c60Sahrens * We need to explicitly open odd, since origin_ds's dd will be 25090b69c2f0Sahrens * changing. 25100b69c2f0Sahrens */ 25113cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object, 25123cb34c60Sahrens NULL, FTAG, &odd)); 251399653d4eSeschrock 2514745cd3c5Smaybee /* change origin's next snap */ 2515745cd3c5Smaybee dmu_buf_will_dirty(origin_ds->ds_dbuf, tx); 2516088f3894Sahrens oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj; 251774e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 251874e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 251974e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj = snap->ds->ds_object; 2520745cd3c5Smaybee 2521088f3894Sahrens /* change the origin's next clone */ 2522088f3894Sahrens if (origin_ds->ds_phys->ds_next_clones_obj) { 2523088f3894Sahrens VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2524088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 252574e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj, tx)); 2526088f3894Sahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2527088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2528088f3894Sahrens oldnext_obj, tx)); 2529088f3894Sahrens } 2530088f3894Sahrens 2531745cd3c5Smaybee /* change origin */ 2532745cd3c5Smaybee dmu_buf_will_dirty(dd->dd_dbuf, tx); 2533745cd3c5Smaybee ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object); 2534745cd3c5Smaybee dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj; 253574e7dc98SMatthew Ahrens hds->ds_origin_txg = origin_head->ds_origin_txg; 2536745cd3c5Smaybee dmu_buf_will_dirty(odd->dd_dbuf, tx); 2537745cd3c5Smaybee odd->dd_phys->dd_origin_obj = origin_ds->ds_object; 253874e7dc98SMatthew Ahrens origin_head->ds_origin_txg = origin_ds->ds_phys->ds_creation_txg; 2539745cd3c5Smaybee 254099653d4eSeschrock /* move snapshots to this dir */ 254174e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 254274e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 2543745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 254499653d4eSeschrock 25453baa08fcSek /* unregister props as dsl_dir is changing */ 2546*503ad85cSMatthew Ahrens if (ds->ds_objset) { 2547*503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 2548*503ad85cSMatthew Ahrens ds->ds_objset = NULL; 25493baa08fcSek } 255099653d4eSeschrock /* move snap name entry */ 255174e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 255274e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_snap_remove(origin_head, 2553745cd3c5Smaybee ds->ds_snapname, tx)); 25541d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 255599653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 255699653d4eSeschrock 8, 1, &ds->ds_object, tx)); 255799653d4eSeschrock /* change containing dsl_dir */ 255899653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 25593cb34c60Sahrens ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object); 256099653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 25613cb34c60Sahrens ASSERT3P(ds->ds_dir, ==, odd); 256299653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 25631d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 256499653d4eSeschrock NULL, ds, &ds->ds_dir)); 256599653d4eSeschrock 256699653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 256774e7dc98SMatthew Ahrens } 256874e7dc98SMatthew Ahrens 256974e7dc98SMatthew Ahrens /* 257074e7dc98SMatthew Ahrens * Change space accounting. 257174e7dc98SMatthew Ahrens * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either 257274e7dc98SMatthew Ahrens * both be valid, or both be 0 (resulting in delta == 0). This 257374e7dc98SMatthew Ahrens * is true for each of {clone,origin} independently. 257474e7dc98SMatthew Ahrens */ 257574e7dc98SMatthew Ahrens 257674e7dc98SMatthew Ahrens delta = pa->cloneusedsnap - 257774e7dc98SMatthew Ahrens dd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 257874e7dc98SMatthew Ahrens ASSERT3S(delta, >=, 0); 257974e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, delta); 258074e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx); 258174e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_HEAD, 258274e7dc98SMatthew Ahrens pa->used - delta, pa->comp, pa->uncomp, tx); 258374e7dc98SMatthew Ahrens 258474e7dc98SMatthew Ahrens delta = pa->originusedsnap - 258574e7dc98SMatthew Ahrens odd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 258674e7dc98SMatthew Ahrens ASSERT3S(delta, <=, 0); 258774e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, -delta); 258874e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx); 258974e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_HEAD, 259074e7dc98SMatthew Ahrens -pa->used - delta, -pa->comp, -pa->uncomp, tx); 259199653d4eSeschrock 25923cb34c60Sahrens origin_ds->ds_phys->ds_unique_bytes = pa->unique; 259399653d4eSeschrock 2594ecd6cf80Smarks /* log history record */ 2595ecd6cf80Smarks spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 2596745cd3c5Smaybee cr, "dataset = %llu", hds->ds_object); 2597ecd6cf80Smarks 25983cb34c60Sahrens dsl_dir_close(odd, FTAG); 259999653d4eSeschrock } 260099653d4eSeschrock 260174e7dc98SMatthew Ahrens static char *snaplist_tag = "snaplist"; 260274e7dc98SMatthew Ahrens /* 260374e7dc98SMatthew Ahrens * Make a list of dsl_dataset_t's for the snapshots between first_obj 260474e7dc98SMatthew Ahrens * (exclusive) and last_obj (inclusive). The list will be in reverse 260574e7dc98SMatthew Ahrens * order (last_obj will be the list_head()). If first_obj == 0, do all 260674e7dc98SMatthew Ahrens * snapshots back to this dataset's origin. 260774e7dc98SMatthew Ahrens */ 260874e7dc98SMatthew Ahrens static int 260974e7dc98SMatthew Ahrens snaplist_make(dsl_pool_t *dp, boolean_t own, 261074e7dc98SMatthew Ahrens uint64_t first_obj, uint64_t last_obj, list_t *l) 261174e7dc98SMatthew Ahrens { 261274e7dc98SMatthew Ahrens uint64_t obj = last_obj; 261374e7dc98SMatthew Ahrens 261474e7dc98SMatthew Ahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock)); 261574e7dc98SMatthew Ahrens 261674e7dc98SMatthew Ahrens list_create(l, sizeof (struct promotenode), 261774e7dc98SMatthew Ahrens offsetof(struct promotenode, link)); 261874e7dc98SMatthew Ahrens 261974e7dc98SMatthew Ahrens while (obj != first_obj) { 262074e7dc98SMatthew Ahrens dsl_dataset_t *ds; 262174e7dc98SMatthew Ahrens struct promotenode *snap; 262274e7dc98SMatthew Ahrens int err; 262374e7dc98SMatthew Ahrens 262474e7dc98SMatthew Ahrens if (own) { 262574e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, obj, 262674e7dc98SMatthew Ahrens 0, snaplist_tag, &ds); 262774e7dc98SMatthew Ahrens if (err == 0) 262874e7dc98SMatthew Ahrens dsl_dataset_make_exclusive(ds, snaplist_tag); 262974e7dc98SMatthew Ahrens } else { 263074e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, obj, snaplist_tag, &ds); 263174e7dc98SMatthew Ahrens } 263274e7dc98SMatthew Ahrens if (err == ENOENT) { 263374e7dc98SMatthew Ahrens /* lost race with snapshot destroy */ 263474e7dc98SMatthew Ahrens struct promotenode *last = list_tail(l); 263574e7dc98SMatthew Ahrens ASSERT(obj != last->ds->ds_phys->ds_prev_snap_obj); 263674e7dc98SMatthew Ahrens obj = last->ds->ds_phys->ds_prev_snap_obj; 263774e7dc98SMatthew Ahrens continue; 263874e7dc98SMatthew Ahrens } else if (err) { 263974e7dc98SMatthew Ahrens return (err); 264074e7dc98SMatthew Ahrens } 264174e7dc98SMatthew Ahrens 264274e7dc98SMatthew Ahrens if (first_obj == 0) 264374e7dc98SMatthew Ahrens first_obj = ds->ds_dir->dd_phys->dd_origin_obj; 264474e7dc98SMatthew Ahrens 264574e7dc98SMatthew Ahrens snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP); 264674e7dc98SMatthew Ahrens snap->ds = ds; 264774e7dc98SMatthew Ahrens list_insert_tail(l, snap); 264874e7dc98SMatthew Ahrens obj = ds->ds_phys->ds_prev_snap_obj; 264974e7dc98SMatthew Ahrens } 265074e7dc98SMatthew Ahrens 265174e7dc98SMatthew Ahrens return (0); 265274e7dc98SMatthew Ahrens } 265374e7dc98SMatthew Ahrens 265474e7dc98SMatthew Ahrens static int 265574e7dc98SMatthew Ahrens snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep) 265674e7dc98SMatthew Ahrens { 265774e7dc98SMatthew Ahrens struct promotenode *snap; 265874e7dc98SMatthew Ahrens 265974e7dc98SMatthew Ahrens *spacep = 0; 266074e7dc98SMatthew Ahrens for (snap = list_head(l); snap; snap = list_next(l, snap)) { 266174e7dc98SMatthew Ahrens uint64_t used; 266274e7dc98SMatthew Ahrens int err = bplist_space_birthrange(&snap->ds->ds_deadlist, 266374e7dc98SMatthew Ahrens mintxg, UINT64_MAX, &used); 266474e7dc98SMatthew Ahrens if (err) 266574e7dc98SMatthew Ahrens return (err); 266674e7dc98SMatthew Ahrens *spacep += used; 266774e7dc98SMatthew Ahrens } 266874e7dc98SMatthew Ahrens return (0); 266974e7dc98SMatthew Ahrens } 267074e7dc98SMatthew Ahrens 267174e7dc98SMatthew Ahrens static void 267274e7dc98SMatthew Ahrens snaplist_destroy(list_t *l, boolean_t own) 267374e7dc98SMatthew Ahrens { 267474e7dc98SMatthew Ahrens struct promotenode *snap; 267574e7dc98SMatthew Ahrens 26764f5064b7SMark J Musante if (!l || !list_link_active(&l->list_head)) 267774e7dc98SMatthew Ahrens return; 267874e7dc98SMatthew Ahrens 267974e7dc98SMatthew Ahrens while ((snap = list_tail(l)) != NULL) { 268074e7dc98SMatthew Ahrens list_remove(l, snap); 268174e7dc98SMatthew Ahrens if (own) 268274e7dc98SMatthew Ahrens dsl_dataset_disown(snap->ds, snaplist_tag); 268374e7dc98SMatthew Ahrens else 268474e7dc98SMatthew Ahrens dsl_dataset_rele(snap->ds, snaplist_tag); 268574e7dc98SMatthew Ahrens kmem_free(snap, sizeof (struct promotenode)); 268674e7dc98SMatthew Ahrens } 268774e7dc98SMatthew Ahrens list_destroy(l); 268874e7dc98SMatthew Ahrens } 268974e7dc98SMatthew Ahrens 269074e7dc98SMatthew Ahrens /* 269174e7dc98SMatthew Ahrens * Promote a clone. Nomenclature note: 269274e7dc98SMatthew Ahrens * "clone" or "cds": the original clone which is being promoted 269374e7dc98SMatthew Ahrens * "origin" or "ods": the snapshot which is originally clone's origin 269474e7dc98SMatthew Ahrens * "origin head" or "ohds": the dataset which is the head 269574e7dc98SMatthew Ahrens * (filesystem/volume) for the origin 269674e7dc98SMatthew Ahrens * "origin origin": the origin of the origin's filesystem (typically 269774e7dc98SMatthew Ahrens * NULL, indicating that the clone is not a clone of a clone). 269874e7dc98SMatthew Ahrens */ 269999653d4eSeschrock int 270099653d4eSeschrock dsl_dataset_promote(const char *name) 270199653d4eSeschrock { 270299653d4eSeschrock dsl_dataset_t *ds; 2703745cd3c5Smaybee dsl_dir_t *dd; 2704745cd3c5Smaybee dsl_pool_t *dp; 270599653d4eSeschrock dmu_object_info_t doi; 270674e7dc98SMatthew Ahrens struct promotearg pa = { 0 }; 2707088f3894Sahrens struct promotenode *snap; 2708745cd3c5Smaybee int err; 270999653d4eSeschrock 2710745cd3c5Smaybee err = dsl_dataset_hold(name, FTAG, &ds); 271199653d4eSeschrock if (err) 271299653d4eSeschrock return (err); 2713745cd3c5Smaybee dd = ds->ds_dir; 2714745cd3c5Smaybee dp = dd->dd_pool; 271599653d4eSeschrock 2716745cd3c5Smaybee err = dmu_object_info(dp->dp_meta_objset, 271799653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 271899653d4eSeschrock if (err) { 2719745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 272099653d4eSeschrock return (err); 272199653d4eSeschrock } 272299653d4eSeschrock 272374e7dc98SMatthew Ahrens if (dsl_dataset_is_snapshot(ds) || dd->dd_phys->dd_origin_obj == 0) { 272474e7dc98SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 272574e7dc98SMatthew Ahrens return (EINVAL); 272674e7dc98SMatthew Ahrens } 272774e7dc98SMatthew Ahrens 2728745cd3c5Smaybee /* 2729745cd3c5Smaybee * We are going to inherit all the snapshots taken before our 2730745cd3c5Smaybee * origin (i.e., our new origin will be our parent's origin). 2731745cd3c5Smaybee * Take ownership of them so that we can rename them into our 2732745cd3c5Smaybee * namespace. 2733745cd3c5Smaybee */ 2734745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 2735088f3894Sahrens 273674e7dc98SMatthew Ahrens err = snaplist_make(dp, B_TRUE, 0, dd->dd_phys->dd_origin_obj, 273774e7dc98SMatthew Ahrens &pa.shared_snaps); 273874e7dc98SMatthew Ahrens if (err != 0) 273974e7dc98SMatthew Ahrens goto out; 2740088f3894Sahrens 274174e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, 0, ds->ds_object, &pa.clone_snaps); 274274e7dc98SMatthew Ahrens if (err != 0) 274374e7dc98SMatthew Ahrens goto out; 2744088f3894Sahrens 274574e7dc98SMatthew Ahrens snap = list_head(&pa.shared_snaps); 274674e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_object, ==, dd->dd_phys->dd_origin_obj); 274774e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, dd->dd_phys->dd_origin_obj, 274874e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, &pa.origin_snaps); 274974e7dc98SMatthew Ahrens if (err != 0) 275074e7dc98SMatthew Ahrens goto out; 2751088f3894Sahrens 275274e7dc98SMatthew Ahrens if (dsl_dir_is_clone(snap->ds->ds_dir)) { 275374e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, 275474e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_origin_obj, 275574e7dc98SMatthew Ahrens 0, FTAG, &pa.origin_origin); 275674e7dc98SMatthew Ahrens if (err != 0) 275774e7dc98SMatthew Ahrens goto out; 275874e7dc98SMatthew Ahrens } 2759745cd3c5Smaybee 276074e7dc98SMatthew Ahrens out: 276174e7dc98SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 2762745cd3c5Smaybee 276399653d4eSeschrock /* 276499653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 276599653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 276699653d4eSeschrock * bonus buffers. 276799653d4eSeschrock */ 276874e7dc98SMatthew Ahrens if (err == 0) { 276974e7dc98SMatthew Ahrens err = dsl_sync_task_do(dp, dsl_dataset_promote_check, 277074e7dc98SMatthew Ahrens dsl_dataset_promote_sync, ds, &pa, 277174e7dc98SMatthew Ahrens 2 + 2 * doi.doi_physical_blks); 2772745cd3c5Smaybee } 277374e7dc98SMatthew Ahrens 277474e7dc98SMatthew Ahrens snaplist_destroy(&pa.shared_snaps, B_TRUE); 277574e7dc98SMatthew Ahrens snaplist_destroy(&pa.clone_snaps, B_FALSE); 277674e7dc98SMatthew Ahrens snaplist_destroy(&pa.origin_snaps, B_FALSE); 277774e7dc98SMatthew Ahrens if (pa.origin_origin) 277874e7dc98SMatthew Ahrens dsl_dataset_disown(pa.origin_origin, FTAG); 2779745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 278099653d4eSeschrock return (err); 278199653d4eSeschrock } 2782b1b8ab34Slling 27833cb34c60Sahrens struct cloneswaparg { 27843cb34c60Sahrens dsl_dataset_t *cds; /* clone dataset */ 27853cb34c60Sahrens dsl_dataset_t *ohds; /* origin's head dataset */ 27863cb34c60Sahrens boolean_t force; 2787a9b821a0Sck int64_t unused_refres_delta; /* change in unconsumed refreservation */ 27883cb34c60Sahrens }; 2789f18faf3fSek 2790f18faf3fSek /* ARGSUSED */ 2791f18faf3fSek static int 2792f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 2793f18faf3fSek { 27943cb34c60Sahrens struct cloneswaparg *csa = arg1; 2795f18faf3fSek 27963cb34c60Sahrens /* they should both be heads */ 27973cb34c60Sahrens if (dsl_dataset_is_snapshot(csa->cds) || 27983cb34c60Sahrens dsl_dataset_is_snapshot(csa->ohds)) 2799f18faf3fSek return (EINVAL); 2800f18faf3fSek 28013cb34c60Sahrens /* the branch point should be just before them */ 28023cb34c60Sahrens if (csa->cds->ds_prev != csa->ohds->ds_prev) 2803f18faf3fSek return (EINVAL); 2804f18faf3fSek 2805ae46e4c7SMatthew Ahrens /* cds should be the clone (unless they are unrelated) */ 2806ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev != NULL && 2807ae46e4c7SMatthew Ahrens csa->cds->ds_prev != csa->cds->ds_dir->dd_pool->dp_origin_snap && 2808ae46e4c7SMatthew Ahrens csa->ohds->ds_object != 2809ae46e4c7SMatthew Ahrens csa->cds->ds_prev->ds_phys->ds_next_snap_obj) 28103cb34c60Sahrens return (EINVAL); 2811f18faf3fSek 28123cb34c60Sahrens /* the clone should be a child of the origin */ 28133cb34c60Sahrens if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir) 28143cb34c60Sahrens return (EINVAL); 2815f18faf3fSek 28163cb34c60Sahrens /* ohds shouldn't be modified unless 'force' */ 28173cb34c60Sahrens if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) 28183cb34c60Sahrens return (ETXTBSY); 2819a9b821a0Sck 2820a9b821a0Sck /* adjust amount of any unconsumed refreservation */ 2821a9b821a0Sck csa->unused_refres_delta = 2822a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 2823a9b821a0Sck csa->ohds->ds_phys->ds_unique_bytes) - 2824a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 2825a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 2826a9b821a0Sck 2827a9b821a0Sck if (csa->unused_refres_delta > 0 && 2828a9b821a0Sck csa->unused_refres_delta > 2829a9b821a0Sck dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) 2830a9b821a0Sck return (ENOSPC); 2831a9b821a0Sck 28323cb34c60Sahrens return (0); 2833f18faf3fSek } 2834f18faf3fSek 2835f18faf3fSek /* ARGSUSED */ 2836f18faf3fSek static void 2837f18faf3fSek dsl_dataset_clone_swap_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 2838f18faf3fSek { 28393cb34c60Sahrens struct cloneswaparg *csa = arg1; 28403cb34c60Sahrens dsl_pool_t *dp = csa->cds->ds_dir->dd_pool; 2841f18faf3fSek 2842a9b821a0Sck ASSERT(csa->cds->ds_reserved == 0); 2843a9b821a0Sck ASSERT(csa->cds->ds_quota == csa->ohds->ds_quota); 2844a9b821a0Sck 28453cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); 28463cb34c60Sahrens dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); 2847f18faf3fSek 2848*503ad85cSMatthew Ahrens if (csa->cds->ds_objset != NULL) { 2849*503ad85cSMatthew Ahrens dmu_objset_evict(csa->cds->ds_objset); 2850*503ad85cSMatthew Ahrens csa->cds->ds_objset = NULL; 28513cb34c60Sahrens } 2852f18faf3fSek 2853*503ad85cSMatthew Ahrens if (csa->ohds->ds_objset != NULL) { 2854*503ad85cSMatthew Ahrens dmu_objset_evict(csa->ohds->ds_objset); 2855*503ad85cSMatthew Ahrens csa->ohds->ds_objset = NULL; 28563cb34c60Sahrens } 2857f18faf3fSek 2858ae46e4c7SMatthew Ahrens /* 2859ae46e4c7SMatthew Ahrens * Reset origin's unique bytes, if it exists. 2860ae46e4c7SMatthew Ahrens */ 2861ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev) { 2862ae46e4c7SMatthew Ahrens dsl_dataset_t *origin = csa->cds->ds_prev; 2863ae46e4c7SMatthew Ahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 2864ae46e4c7SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->cds->ds_deadlist, 2865ae46e4c7SMatthew Ahrens origin->ds_phys->ds_prev_snap_txg, UINT64_MAX, 2866ae46e4c7SMatthew Ahrens &origin->ds_phys->ds_unique_bytes)); 2867ae46e4c7SMatthew Ahrens } 2868f18faf3fSek 2869f18faf3fSek /* swap blkptrs */ 2870f18faf3fSek { 2871f18faf3fSek blkptr_t tmp; 28723cb34c60Sahrens tmp = csa->ohds->ds_phys->ds_bp; 28733cb34c60Sahrens csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp; 28743cb34c60Sahrens csa->cds->ds_phys->ds_bp = tmp; 2875f18faf3fSek } 2876f18faf3fSek 2877f18faf3fSek /* set dd_*_bytes */ 2878f18faf3fSek { 2879f18faf3fSek int64_t dused, dcomp, duncomp; 2880f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 2881f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 2882f18faf3fSek 288374e7dc98SMatthew Ahrens ASSERT3U(csa->cds->ds_dir->dd_phys-> 288474e7dc98SMatthew Ahrens dd_used_breakdown[DD_USED_SNAP], ==, 0); 288574e7dc98SMatthew Ahrens 28863cb34c60Sahrens VERIFY(0 == bplist_space(&csa->cds->ds_deadlist, &cdl_used, 2887f18faf3fSek &cdl_comp, &cdl_uncomp)); 28883cb34c60Sahrens VERIFY(0 == bplist_space(&csa->ohds->ds_deadlist, &odl_used, 2889f18faf3fSek &odl_comp, &odl_uncomp)); 289074e7dc98SMatthew Ahrens 28913cb34c60Sahrens dused = csa->cds->ds_phys->ds_used_bytes + cdl_used - 28923cb34c60Sahrens (csa->ohds->ds_phys->ds_used_bytes + odl_used); 28933cb34c60Sahrens dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp - 28943cb34c60Sahrens (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp); 28953cb34c60Sahrens duncomp = csa->cds->ds_phys->ds_uncompressed_bytes + 28963cb34c60Sahrens cdl_uncomp - 28973cb34c60Sahrens (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 28983cb34c60Sahrens 289974e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_HEAD, 29003cb34c60Sahrens dused, dcomp, duncomp, tx); 290174e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->cds->ds_dir, DD_USED_HEAD, 29023cb34c60Sahrens -dused, -dcomp, -duncomp, tx); 290374e7dc98SMatthew Ahrens 290474e7dc98SMatthew Ahrens /* 290574e7dc98SMatthew Ahrens * The difference in the space used by snapshots is the 290674e7dc98SMatthew Ahrens * difference in snapshot space due to the head's 290774e7dc98SMatthew Ahrens * deadlist (since that's the only thing that's 290874e7dc98SMatthew Ahrens * changing that affects the snapused). 290974e7dc98SMatthew Ahrens */ 291074e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->cds->ds_deadlist, 291174e7dc98SMatthew Ahrens csa->ohds->ds_origin_txg, UINT64_MAX, &cdl_used)); 291274e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->ohds->ds_deadlist, 291374e7dc98SMatthew Ahrens csa->ohds->ds_origin_txg, UINT64_MAX, &odl_used)); 291474e7dc98SMatthew Ahrens dsl_dir_transfer_space(csa->ohds->ds_dir, cdl_used - odl_used, 291574e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 29163cb34c60Sahrens } 29173cb34c60Sahrens 29183cb34c60Sahrens #define SWITCH64(x, y) \ 29193cb34c60Sahrens { \ 29203cb34c60Sahrens uint64_t __tmp = (x); \ 29213cb34c60Sahrens (x) = (y); \ 29223cb34c60Sahrens (y) = __tmp; \ 2923f18faf3fSek } 2924f18faf3fSek 2925f18faf3fSek /* swap ds_*_bytes */ 29263cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_used_bytes, 29273cb34c60Sahrens csa->cds->ds_phys->ds_used_bytes); 29283cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes, 29293cb34c60Sahrens csa->cds->ds_phys->ds_compressed_bytes); 29303cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, 29313cb34c60Sahrens csa->cds->ds_phys->ds_uncompressed_bytes); 2932a9b821a0Sck SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, 2933a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 2934a9b821a0Sck 2935a9b821a0Sck /* apply any parent delta for change in unconsumed refreservation */ 293674e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_REFRSRV, 293774e7dc98SMatthew Ahrens csa->unused_refres_delta, 0, 0, tx); 2938f18faf3fSek 2939f18faf3fSek /* swap deadlists */ 29403cb34c60Sahrens bplist_close(&csa->cds->ds_deadlist); 29413cb34c60Sahrens bplist_close(&csa->ohds->ds_deadlist); 29423cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj, 29433cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj); 29443cb34c60Sahrens VERIFY(0 == bplist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset, 29453cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj)); 29463cb34c60Sahrens VERIFY(0 == bplist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, 29473cb34c60Sahrens csa->ohds->ds_phys->ds_deadlist_obj)); 294888b7b0f2SMatthew Ahrens 294988b7b0f2SMatthew Ahrens dsl_pool_ds_clone_swapped(csa->ohds, csa->cds, tx); 2950f18faf3fSek } 2951f18faf3fSek 2952f18faf3fSek /* 2953ae46e4c7SMatthew Ahrens * Swap 'clone' with its origin head datasets. Used at the end of "zfs 2954ae46e4c7SMatthew Ahrens * recv" into an existing fs to swizzle the file system to the new 2955ae46e4c7SMatthew Ahrens * version, and by "zfs rollback". Can also be used to swap two 2956ae46e4c7SMatthew Ahrens * independent head datasets if neither has any snapshots. 2957f18faf3fSek */ 2958f18faf3fSek int 29593cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, 29603cb34c60Sahrens boolean_t force) 2961f18faf3fSek { 29623cb34c60Sahrens struct cloneswaparg csa; 2963745cd3c5Smaybee int error; 2964f18faf3fSek 2965745cd3c5Smaybee ASSERT(clone->ds_owner); 2966745cd3c5Smaybee ASSERT(origin_head->ds_owner); 2967745cd3c5Smaybee retry: 2968745cd3c5Smaybee /* Need exclusive access for the swap */ 2969745cd3c5Smaybee rw_enter(&clone->ds_rwlock, RW_WRITER); 2970745cd3c5Smaybee if (!rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) { 2971745cd3c5Smaybee rw_exit(&clone->ds_rwlock); 2972745cd3c5Smaybee rw_enter(&origin_head->ds_rwlock, RW_WRITER); 2973745cd3c5Smaybee if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) { 2974745cd3c5Smaybee rw_exit(&origin_head->ds_rwlock); 2975745cd3c5Smaybee goto retry; 2976745cd3c5Smaybee } 2977745cd3c5Smaybee } 29783cb34c60Sahrens csa.cds = clone; 29793cb34c60Sahrens csa.ohds = origin_head; 29803cb34c60Sahrens csa.force = force; 2981745cd3c5Smaybee error = dsl_sync_task_do(clone->ds_dir->dd_pool, 2982f18faf3fSek dsl_dataset_clone_swap_check, 2983745cd3c5Smaybee dsl_dataset_clone_swap_sync, &csa, NULL, 9); 2984745cd3c5Smaybee return (error); 2985f18faf3fSek } 2986f18faf3fSek 2987b1b8ab34Slling /* 2988b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 2989b1b8ab34Slling * return the name of that dataset. 2990b1b8ab34Slling */ 2991b1b8ab34Slling int 2992b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 2993b1b8ab34Slling { 2994b1b8ab34Slling spa_t *spa; 2995b1b8ab34Slling dsl_pool_t *dp; 2996745cd3c5Smaybee dsl_dataset_t *ds; 2997b1b8ab34Slling int error; 2998b1b8ab34Slling 2999b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 3000b1b8ab34Slling return (error); 3001b1b8ab34Slling dp = spa_get_dsl(spa); 3002b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 3003745cd3c5Smaybee if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) { 3004745cd3c5Smaybee dsl_dataset_name(ds, buf); 3005745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3006b1b8ab34Slling } 3007b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 3008b1b8ab34Slling spa_close(spa, FTAG); 3009b1b8ab34Slling 3010745cd3c5Smaybee return (error); 3011b1b8ab34Slling } 3012a9799022Sck 3013a9799022Sck int 3014a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, 3015745cd3c5Smaybee uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv) 3016a9799022Sck { 3017a9799022Sck int error = 0; 3018a9799022Sck 3019a9799022Sck ASSERT3S(asize, >, 0); 3020a9799022Sck 30219082849eSck /* 30229082849eSck * *ref_rsrv is the portion of asize that will come from any 30239082849eSck * unconsumed refreservation space. 30249082849eSck */ 30259082849eSck *ref_rsrv = 0; 30269082849eSck 3027a9799022Sck mutex_enter(&ds->ds_lock); 3028a9799022Sck /* 3029a9799022Sck * Make a space adjustment for reserved bytes. 3030a9799022Sck */ 3031a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) { 3032a9799022Sck ASSERT3U(*used, >=, 3033a9799022Sck ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 3034a9799022Sck *used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 30359082849eSck *ref_rsrv = 30369082849eSck asize - MIN(asize, parent_delta(ds, asize + inflight)); 3037a9799022Sck } 3038a9799022Sck 3039a9799022Sck if (!check_quota || ds->ds_quota == 0) { 3040a9799022Sck mutex_exit(&ds->ds_lock); 3041a9799022Sck return (0); 3042a9799022Sck } 3043a9799022Sck /* 3044a9799022Sck * If they are requesting more space, and our current estimate 3045a9799022Sck * is over quota, they get to try again unless the actual 3046a9799022Sck * on-disk is over quota and there are no pending changes (which 3047a9799022Sck * may free up space for us). 3048a9799022Sck */ 3049a9799022Sck if (ds->ds_phys->ds_used_bytes + inflight >= ds->ds_quota) { 3050a9799022Sck if (inflight > 0 || ds->ds_phys->ds_used_bytes < ds->ds_quota) 3051a9799022Sck error = ERESTART; 3052a9799022Sck else 3053a9799022Sck error = EDQUOT; 3054a9799022Sck } 3055a9799022Sck mutex_exit(&ds->ds_lock); 3056a9799022Sck 3057a9799022Sck return (error); 3058a9799022Sck } 3059a9799022Sck 3060a9799022Sck /* ARGSUSED */ 3061a9799022Sck static int 3062a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx) 3063a9799022Sck { 3064a9799022Sck dsl_dataset_t *ds = arg1; 3065a9799022Sck uint64_t *quotap = arg2; 3066a9799022Sck uint64_t new_quota = *quotap; 3067a9799022Sck 3068a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA) 3069a9799022Sck return (ENOTSUP); 3070a9799022Sck 3071a9799022Sck if (new_quota == 0) 3072a9799022Sck return (0); 3073a9799022Sck 3074a9799022Sck if (new_quota < ds->ds_phys->ds_used_bytes || 3075a9799022Sck new_quota < ds->ds_reserved) 3076a9799022Sck return (ENOSPC); 3077a9799022Sck 3078a9799022Sck return (0); 3079a9799022Sck } 3080a9799022Sck 3081a9799022Sck /* ARGSUSED */ 3082a9799022Sck void 3083a9799022Sck dsl_dataset_set_quota_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3084a9799022Sck { 3085a9799022Sck dsl_dataset_t *ds = arg1; 3086a9799022Sck uint64_t *quotap = arg2; 3087a9799022Sck uint64_t new_quota = *quotap; 3088a9799022Sck 3089a9799022Sck dmu_buf_will_dirty(ds->ds_dbuf, tx); 3090a9799022Sck 3091a9799022Sck ds->ds_quota = new_quota; 3092a9799022Sck 3093842727c2SChris Kirby dsl_dir_prop_set_uint64_sync(ds->ds_dir, "refquota", new_quota, cr, tx); 3094a9799022Sck 3095a9799022Sck spa_history_internal_log(LOG_DS_REFQUOTA, ds->ds_dir->dd_pool->dp_spa, 3096a9799022Sck tx, cr, "%lld dataset = %llu ", 3097745cd3c5Smaybee (longlong_t)new_quota, ds->ds_object); 3098a9799022Sck } 3099a9799022Sck 3100a9799022Sck int 3101a9799022Sck dsl_dataset_set_quota(const char *dsname, uint64_t quota) 3102a9799022Sck { 3103a9799022Sck dsl_dataset_t *ds; 3104a9799022Sck int err; 3105a9799022Sck 3106745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3107a9799022Sck if (err) 3108a9799022Sck return (err); 3109a9799022Sck 3110a9b821a0Sck if (quota != ds->ds_quota) { 3111a9b821a0Sck /* 3112a9b821a0Sck * If someone removes a file, then tries to set the quota, we 3113a9b821a0Sck * want to make sure the file freeing takes effect. 3114a9b821a0Sck */ 3115a9b821a0Sck txg_wait_open(ds->ds_dir->dd_pool, 0); 3116a9799022Sck 3117a9b821a0Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3118a9b821a0Sck dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, 3119a9b821a0Sck ds, "a, 0); 3120a9b821a0Sck } 3121745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3122a9799022Sck return (err); 3123a9799022Sck } 3124a9799022Sck 3125a9799022Sck static int 3126a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx) 3127a9799022Sck { 3128a9799022Sck dsl_dataset_t *ds = arg1; 3129a9799022Sck uint64_t *reservationp = arg2; 3130a9799022Sck uint64_t new_reservation = *reservationp; 3131a9799022Sck uint64_t unique; 3132a9799022Sck 3133a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 3134a9799022Sck SPA_VERSION_REFRESERVATION) 3135a9799022Sck return (ENOTSUP); 3136a9799022Sck 3137a9799022Sck if (dsl_dataset_is_snapshot(ds)) 3138a9799022Sck return (EINVAL); 3139a9799022Sck 3140a9799022Sck /* 3141a9799022Sck * If we are doing the preliminary check in open context, the 3142a9799022Sck * space estimates may be inaccurate. 3143a9799022Sck */ 3144a9799022Sck if (!dmu_tx_is_syncing(tx)) 3145a9799022Sck return (0); 3146a9799022Sck 3147a9799022Sck mutex_enter(&ds->ds_lock); 3148a9799022Sck unique = dsl_dataset_unique(ds); 3149a9799022Sck mutex_exit(&ds->ds_lock); 3150a9799022Sck 3151379c004dSEric Schrock if (MAX(unique, new_reservation) > MAX(unique, ds->ds_reserved)) { 3152379c004dSEric Schrock uint64_t delta = MAX(unique, new_reservation) - 3153379c004dSEric Schrock MAX(unique, ds->ds_reserved); 3154379c004dSEric Schrock 3155379c004dSEric Schrock if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 3156379c004dSEric Schrock return (ENOSPC); 3157379c004dSEric Schrock if (ds->ds_quota > 0 && 3158379c004dSEric Schrock new_reservation > ds->ds_quota) 3159379c004dSEric Schrock return (ENOSPC); 3160379c004dSEric Schrock } 3161a9799022Sck 3162a9799022Sck return (0); 3163a9799022Sck } 3164a9799022Sck 3165a9799022Sck /* ARGSUSED */ 3166a9799022Sck static void 3167a9799022Sck dsl_dataset_set_reservation_sync(void *arg1, void *arg2, cred_t *cr, 3168a9799022Sck dmu_tx_t *tx) 3169a9799022Sck { 3170a9799022Sck dsl_dataset_t *ds = arg1; 3171a9799022Sck uint64_t *reservationp = arg2; 3172a9799022Sck uint64_t new_reservation = *reservationp; 317302c8f3f0SMatthew Ahrens uint64_t unique; 317402c8f3f0SMatthew Ahrens int64_t delta; 317502c8f3f0SMatthew Ahrens 317602c8f3f0SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 317702c8f3f0SMatthew Ahrens 317802c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 317902c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_lock); 318002c8f3f0SMatthew Ahrens unique = dsl_dataset_unique(ds); 318102c8f3f0SMatthew Ahrens delta = MAX(0, (int64_t)(new_reservation - unique)) - 318202c8f3f0SMatthew Ahrens MAX(0, (int64_t)(ds->ds_reserved - unique)); 318302c8f3f0SMatthew Ahrens ds->ds_reserved = new_reservation; 318402c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_lock); 318502c8f3f0SMatthew Ahrens 318602c8f3f0SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx); 318702c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 3188842727c2SChris Kirby dsl_dir_prop_set_uint64_sync(ds->ds_dir, "refreservation", 318902c8f3f0SMatthew Ahrens new_reservation, cr, tx); 3190a9799022Sck 319102c8f3f0SMatthew Ahrens spa_history_internal_log(LOG_DS_REFRESERV, 319202c8f3f0SMatthew Ahrens ds->ds_dir->dd_pool->dp_spa, tx, cr, "%lld dataset = %llu", 319302c8f3f0SMatthew Ahrens (longlong_t)new_reservation, ds->ds_object); 3194a9799022Sck } 3195a9799022Sck 3196a9799022Sck int 3197a9799022Sck dsl_dataset_set_reservation(const char *dsname, uint64_t reservation) 3198a9799022Sck { 3199a9799022Sck dsl_dataset_t *ds; 3200a9799022Sck int err; 3201a9799022Sck 3202745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3203a9799022Sck if (err) 3204a9799022Sck return (err); 3205a9799022Sck 3206a9799022Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3207a9799022Sck dsl_dataset_set_reservation_check, 3208a9799022Sck dsl_dataset_set_reservation_sync, ds, &reservation, 0); 3209745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3210a9799022Sck return (err); 3211a9799022Sck } 3212842727c2SChris Kirby 3213842727c2SChris Kirby static int 3214842727c2SChris Kirby dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx) 3215842727c2SChris Kirby { 3216842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3217842727c2SChris Kirby char *htag = arg2; 3218842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3219842727c2SChris Kirby int error = 0; 3220842727c2SChris Kirby 3221842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3222842727c2SChris Kirby return (ENOTSUP); 3223842727c2SChris Kirby 3224842727c2SChris Kirby if (!dsl_dataset_is_snapshot(ds)) 3225842727c2SChris Kirby return (EINVAL); 3226842727c2SChris Kirby 3227842727c2SChris Kirby if (strlen(htag) >= ZAP_MAXNAMELEN) 3228842727c2SChris Kirby return (ENAMETOOLONG); 3229842727c2SChris Kirby 3230842727c2SChris Kirby /* tags must be unique */ 3231842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3232842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj) { 3233842727c2SChris Kirby error = zap_lookup(mos, ds->ds_phys->ds_userrefs_obj, htag, 3234842727c2SChris Kirby 8, 1, tx); 3235842727c2SChris Kirby if (error == 0) 3236842727c2SChris Kirby error = EEXIST; 3237842727c2SChris Kirby else if (error == ENOENT) 3238842727c2SChris Kirby error = 0; 3239842727c2SChris Kirby } 3240842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3241842727c2SChris Kirby 3242842727c2SChris Kirby return (error); 3243842727c2SChris Kirby } 3244842727c2SChris Kirby 3245842727c2SChris Kirby static void 3246842727c2SChris Kirby dsl_dataset_user_hold_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3247842727c2SChris Kirby { 3248842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3249842727c2SChris Kirby char *htag = arg2; 3250842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3251842727c2SChris Kirby time_t now = gethrestime_sec(); 3252842727c2SChris Kirby uint64_t zapobj; 3253842727c2SChris Kirby 3254842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3255842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj == 0) { 3256842727c2SChris Kirby /* 3257842727c2SChris Kirby * This is the first user hold for this dataset. Create 3258842727c2SChris Kirby * the userrefs zap object. 3259842727c2SChris Kirby */ 3260842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 3261842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj = 3262842727c2SChris Kirby zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx); 3263842727c2SChris Kirby } else { 3264842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3265842727c2SChris Kirby } 3266842727c2SChris Kirby ds->ds_userrefs++; 3267842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3268842727c2SChris Kirby 3269842727c2SChris Kirby VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx)); 3270842727c2SChris Kirby 3271842727c2SChris Kirby spa_history_internal_log(LOG_DS_USER_HOLD, 3272842727c2SChris Kirby ds->ds_dir->dd_pool->dp_spa, tx, cr, "<%s> dataset = %llu", 3273842727c2SChris Kirby htag, ds->ds_object); 3274842727c2SChris Kirby } 3275842727c2SChris Kirby 3276842727c2SChris Kirby struct dsl_ds_holdarg { 3277842727c2SChris Kirby dsl_sync_task_group_t *dstg; 3278842727c2SChris Kirby char *htag; 3279842727c2SChris Kirby char *snapname; 3280842727c2SChris Kirby boolean_t recursive; 3281d7747cbcSChris Kirby boolean_t gotone; 3282842727c2SChris Kirby char failed[MAXPATHLEN]; 3283842727c2SChris Kirby }; 3284842727c2SChris Kirby 3285842727c2SChris Kirby static int 3286842727c2SChris Kirby dsl_dataset_user_hold_one(char *dsname, void *arg) 3287842727c2SChris Kirby { 3288842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3289842727c2SChris Kirby dsl_dataset_t *ds; 3290842727c2SChris Kirby int error; 3291842727c2SChris Kirby char *name; 3292842727c2SChris Kirby 3293842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname plus terminating NULL */ 3294ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3295842727c2SChris Kirby error = dsl_dataset_hold(name, ha->dstg, &ds); 3296ae46e4c7SMatthew Ahrens strfree(name); 3297842727c2SChris Kirby if (error == 0) { 3298d7747cbcSChris Kirby ha->gotone = B_TRUE; 3299842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check, 3300842727c2SChris Kirby dsl_dataset_user_hold_sync, ds, ha->htag, 0); 3301842727c2SChris Kirby } else if (error == ENOENT && ha->recursive) { 3302842727c2SChris Kirby error = 0; 3303842727c2SChris Kirby } else { 3304842727c2SChris Kirby (void) strcpy(ha->failed, dsname); 3305842727c2SChris Kirby } 3306842727c2SChris Kirby return (error); 3307842727c2SChris Kirby } 3308842727c2SChris Kirby 3309842727c2SChris Kirby int 3310842727c2SChris Kirby dsl_dataset_user_hold(char *dsname, char *snapname, char *htag, 3311842727c2SChris Kirby boolean_t recursive) 3312842727c2SChris Kirby { 3313842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3314842727c2SChris Kirby dsl_sync_task_t *dst; 3315842727c2SChris Kirby spa_t *spa; 3316842727c2SChris Kirby int error; 3317842727c2SChris Kirby 3318842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3319842727c2SChris Kirby 3320842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3321842727c2SChris Kirby 3322842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3323842727c2SChris Kirby if (error) { 3324842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3325842727c2SChris Kirby return (error); 3326842727c2SChris Kirby } 3327842727c2SChris Kirby 3328842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3329842727c2SChris Kirby ha->htag = htag; 3330842727c2SChris Kirby ha->snapname = snapname; 3331842727c2SChris Kirby ha->recursive = recursive; 3332842727c2SChris Kirby if (recursive) { 3333842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_hold_one, 3334842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3335842727c2SChris Kirby } else { 3336842727c2SChris Kirby error = dsl_dataset_user_hold_one(dsname, ha); 3337842727c2SChris Kirby } 3338842727c2SChris Kirby if (error == 0) 3339842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3340842727c2SChris Kirby 3341842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3342842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3343842727c2SChris Kirby dsl_dataset_t *ds = dst->dst_arg1; 3344842727c2SChris Kirby 3345842727c2SChris Kirby if (dst->dst_err) { 3346842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3347842727c2SChris Kirby *strchr(ha->failed, '@') = '\0'; 3348842727c2SChris Kirby } 3349842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3350842727c2SChris Kirby } 3351842727c2SChris Kirby 3352d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3353d7747cbcSChris Kirby error = ENOENT; 3354d7747cbcSChris Kirby 3355842727c2SChris Kirby if (error) 3356842727c2SChris Kirby (void) strcpy(dsname, ha->failed); 3357842727c2SChris Kirby 3358842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3359842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3360842727c2SChris Kirby spa_close(spa, FTAG); 3361842727c2SChris Kirby return (error); 3362842727c2SChris Kirby } 3363842727c2SChris Kirby 3364842727c2SChris Kirby struct dsl_ds_releasearg { 3365842727c2SChris Kirby dsl_dataset_t *ds; 3366842727c2SChris Kirby const char *htag; 3367842727c2SChris Kirby boolean_t own; /* do we own or just hold ds? */ 3368842727c2SChris Kirby }; 3369842727c2SChris Kirby 3370842727c2SChris Kirby static int 3371842727c2SChris Kirby dsl_dataset_release_might_destroy(dsl_dataset_t *ds, const char *htag, 3372842727c2SChris Kirby boolean_t *might_destroy) 3373842727c2SChris Kirby { 3374842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3375842727c2SChris Kirby uint64_t zapobj; 3376842727c2SChris Kirby uint64_t tmp; 3377842727c2SChris Kirby int error; 3378842727c2SChris Kirby 3379842727c2SChris Kirby *might_destroy = B_FALSE; 3380842727c2SChris Kirby 3381842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3382842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3383842727c2SChris Kirby if (zapobj == 0) { 3384842727c2SChris Kirby /* The tag can't possibly exist */ 3385842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3386842727c2SChris Kirby return (ESRCH); 3387842727c2SChris Kirby } 3388842727c2SChris Kirby 3389842727c2SChris Kirby /* Make sure the tag exists */ 3390842727c2SChris Kirby error = zap_lookup(mos, zapobj, htag, 8, 1, &tmp); 3391842727c2SChris Kirby if (error) { 3392842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3393842727c2SChris Kirby if (error == ENOENT) 3394842727c2SChris Kirby error = ESRCH; 3395842727c2SChris Kirby return (error); 3396842727c2SChris Kirby } 3397842727c2SChris Kirby 3398842727c2SChris Kirby if (ds->ds_userrefs == 1 && ds->ds_phys->ds_num_children == 1 && 3399842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 3400842727c2SChris Kirby *might_destroy = B_TRUE; 3401842727c2SChris Kirby 3402842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3403842727c2SChris Kirby return (0); 3404842727c2SChris Kirby } 3405842727c2SChris Kirby 3406842727c2SChris Kirby static int 3407842727c2SChris Kirby dsl_dataset_user_release_check(void *arg1, void *tag, dmu_tx_t *tx) 3408842727c2SChris Kirby { 3409842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3410842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3411842727c2SChris Kirby boolean_t might_destroy; 3412842727c2SChris Kirby int error; 3413842727c2SChris Kirby 3414842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3415842727c2SChris Kirby return (ENOTSUP); 3416842727c2SChris Kirby 3417842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ra->htag, &might_destroy); 3418842727c2SChris Kirby if (error) 3419842727c2SChris Kirby return (error); 3420842727c2SChris Kirby 3421842727c2SChris Kirby if (might_destroy) { 3422842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3423842727c2SChris Kirby 3424842727c2SChris Kirby if (dmu_tx_is_syncing(tx)) { 3425842727c2SChris Kirby /* 3426842727c2SChris Kirby * If we're not prepared to remove the snapshot, 3427842727c2SChris Kirby * we can't allow the release to happen right now. 3428842727c2SChris Kirby */ 3429842727c2SChris Kirby if (!ra->own) 3430842727c2SChris Kirby return (EBUSY); 3431*503ad85cSMatthew Ahrens if (ds->ds_objset) { 3432*503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 3433*503ad85cSMatthew Ahrens ds->ds_objset = NULL; 3434842727c2SChris Kirby } 3435842727c2SChris Kirby } 3436842727c2SChris Kirby dsda.ds = ds; 3437842727c2SChris Kirby dsda.releasing = B_TRUE; 3438842727c2SChris Kirby return (dsl_dataset_destroy_check(&dsda, tag, tx)); 3439842727c2SChris Kirby } 3440842727c2SChris Kirby 3441842727c2SChris Kirby return (0); 3442842727c2SChris Kirby } 3443842727c2SChris Kirby 3444842727c2SChris Kirby static void 3445842727c2SChris Kirby dsl_dataset_user_release_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 3446842727c2SChris Kirby { 3447842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3448842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3449842727c2SChris Kirby spa_t *spa = ds->ds_dir->dd_pool->dp_spa; 3450842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3451842727c2SChris Kirby uint64_t zapobj; 3452842727c2SChris Kirby uint64_t dsobj = ds->ds_object; 3453842727c2SChris Kirby uint64_t refs; 3454842727c2SChris Kirby 3455842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3456842727c2SChris Kirby ds->ds_userrefs--; 3457842727c2SChris Kirby refs = ds->ds_userrefs; 3458842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3459842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3460842727c2SChris Kirby VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx)); 3461842727c2SChris Kirby if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 && 3462842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) { 3463842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3464842727c2SChris Kirby 3465842727c2SChris Kirby ASSERT(ra->own); 3466842727c2SChris Kirby dsda.ds = ds; 3467842727c2SChris Kirby dsda.releasing = B_TRUE; 3468842727c2SChris Kirby /* We already did the destroy_check */ 3469842727c2SChris Kirby dsl_dataset_destroy_sync(&dsda, tag, cr, tx); 3470842727c2SChris Kirby } 3471842727c2SChris Kirby 3472842727c2SChris Kirby spa_history_internal_log(LOG_DS_USER_RELEASE, 3473842727c2SChris Kirby spa, tx, cr, "<%s> %lld dataset = %llu", 3474842727c2SChris Kirby ra->htag, (longlong_t)refs, dsobj); 3475842727c2SChris Kirby } 3476842727c2SChris Kirby 3477842727c2SChris Kirby static int 3478842727c2SChris Kirby dsl_dataset_user_release_one(char *dsname, void *arg) 3479842727c2SChris Kirby { 3480842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3481842727c2SChris Kirby struct dsl_ds_releasearg *ra; 3482842727c2SChris Kirby dsl_dataset_t *ds; 3483842727c2SChris Kirby int error; 3484842727c2SChris Kirby void *dtag = ha->dstg; 3485842727c2SChris Kirby char *name; 3486842727c2SChris Kirby boolean_t own = B_FALSE; 3487842727c2SChris Kirby boolean_t might_destroy; 3488842727c2SChris Kirby 3489842727c2SChris Kirby if (strlen(ha->htag) >= ZAP_MAXNAMELEN) 3490842727c2SChris Kirby return (ENAMETOOLONG); 3491842727c2SChris Kirby 3492842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname, plus the terminating NULL */ 3493ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3494842727c2SChris Kirby error = dsl_dataset_hold(name, dtag, &ds); 3495ae46e4c7SMatthew Ahrens strfree(name); 3496842727c2SChris Kirby if (error == ENOENT && ha->recursive) 3497842727c2SChris Kirby return (0); 3498842727c2SChris Kirby (void) strcpy(ha->failed, dsname); 3499842727c2SChris Kirby if (error) 3500842727c2SChris Kirby return (error); 3501842727c2SChris Kirby 3502d7747cbcSChris Kirby ha->gotone = B_TRUE; 3503d7747cbcSChris Kirby 3504842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 3505842727c2SChris Kirby 3506842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ha->htag, &might_destroy); 3507842727c2SChris Kirby if (error) { 3508842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3509842727c2SChris Kirby return (error); 3510842727c2SChris Kirby } 3511842727c2SChris Kirby 3512842727c2SChris Kirby if (might_destroy) { 3513842727c2SChris Kirby #ifdef _KERNEL 3514842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 3515842727c2SChris Kirby if (error) { 3516842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3517842727c2SChris Kirby return (error); 3518842727c2SChris Kirby } 3519842727c2SChris Kirby error = dsl_dataset_zvol_cleanup(ds, name); 3520842727c2SChris Kirby if (error) { 3521842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3522842727c2SChris Kirby return (error); 3523842727c2SChris Kirby } 3524842727c2SChris Kirby #endif 3525*503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(ds, B_TRUE, dtag)) { 3526842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3527842727c2SChris Kirby return (EBUSY); 3528842727c2SChris Kirby } else { 3529842727c2SChris Kirby own = B_TRUE; 3530842727c2SChris Kirby dsl_dataset_make_exclusive(ds, dtag); 3531842727c2SChris Kirby } 3532842727c2SChris Kirby } 3533842727c2SChris Kirby 3534842727c2SChris Kirby ra = kmem_alloc(sizeof (struct dsl_ds_releasearg), KM_SLEEP); 3535842727c2SChris Kirby ra->ds = ds; 3536842727c2SChris Kirby ra->htag = ha->htag; 3537842727c2SChris Kirby ra->own = own; 3538842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_release_check, 3539842727c2SChris Kirby dsl_dataset_user_release_sync, ra, dtag, 0); 3540842727c2SChris Kirby 3541842727c2SChris Kirby return (0); 3542842727c2SChris Kirby } 3543842727c2SChris Kirby 3544842727c2SChris Kirby int 3545842727c2SChris Kirby dsl_dataset_user_release(char *dsname, char *snapname, char *htag, 3546842727c2SChris Kirby boolean_t recursive) 3547842727c2SChris Kirby { 3548842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3549842727c2SChris Kirby dsl_sync_task_t *dst; 3550842727c2SChris Kirby spa_t *spa; 3551842727c2SChris Kirby int error; 3552842727c2SChris Kirby 3553842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3554842727c2SChris Kirby 3555842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3556842727c2SChris Kirby 3557842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3558842727c2SChris Kirby if (error) { 3559842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3560842727c2SChris Kirby return (error); 3561842727c2SChris Kirby } 3562842727c2SChris Kirby 3563842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3564842727c2SChris Kirby ha->htag = htag; 3565842727c2SChris Kirby ha->snapname = snapname; 3566842727c2SChris Kirby ha->recursive = recursive; 3567842727c2SChris Kirby if (recursive) { 3568842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_release_one, 3569842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3570842727c2SChris Kirby } else { 3571842727c2SChris Kirby error = dsl_dataset_user_release_one(dsname, ha); 3572842727c2SChris Kirby } 3573842727c2SChris Kirby if (error == 0) 3574842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3575842727c2SChris Kirby 3576842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3577842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3578842727c2SChris Kirby struct dsl_ds_releasearg *ra = dst->dst_arg1; 3579842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3580842727c2SChris Kirby 3581842727c2SChris Kirby if (dst->dst_err) 3582842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3583842727c2SChris Kirby 3584842727c2SChris Kirby if (ra->own) 3585842727c2SChris Kirby dsl_dataset_disown(ds, ha->dstg); 3586842727c2SChris Kirby else 3587842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3588842727c2SChris Kirby 3589842727c2SChris Kirby kmem_free(ra, sizeof (struct dsl_ds_releasearg)); 3590842727c2SChris Kirby } 3591842727c2SChris Kirby 3592d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3593d7747cbcSChris Kirby error = ENOENT; 3594d7747cbcSChris Kirby 3595842727c2SChris Kirby if (error) 3596842727c2SChris Kirby (void) strcpy(dsname, ha->failed); 3597842727c2SChris Kirby 3598842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3599842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3600842727c2SChris Kirby spa_close(spa, FTAG); 3601842727c2SChris Kirby return (error); 3602842727c2SChris Kirby } 3603842727c2SChris Kirby 3604842727c2SChris Kirby int 3605842727c2SChris Kirby dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp) 3606842727c2SChris Kirby { 3607842727c2SChris Kirby dsl_dataset_t *ds; 3608842727c2SChris Kirby int err; 3609842727c2SChris Kirby 3610842727c2SChris Kirby err = dsl_dataset_hold(dsname, FTAG, &ds); 3611842727c2SChris Kirby if (err) 3612842727c2SChris Kirby return (err); 3613842727c2SChris Kirby 3614842727c2SChris Kirby VERIFY(0 == nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP)); 3615842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) { 3616842727c2SChris Kirby zap_attribute_t *za; 3617842727c2SChris Kirby zap_cursor_t zc; 3618842727c2SChris Kirby 3619842727c2SChris Kirby za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 3620842727c2SChris Kirby for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset, 3621842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj); 3622842727c2SChris Kirby zap_cursor_retrieve(&zc, za) == 0; 3623842727c2SChris Kirby zap_cursor_advance(&zc)) { 3624842727c2SChris Kirby VERIFY(0 == nvlist_add_uint64(*nvp, za->za_name, 3625842727c2SChris Kirby za->za_first_integer)); 3626842727c2SChris Kirby } 3627842727c2SChris Kirby zap_cursor_fini(&zc); 3628842727c2SChris Kirby kmem_free(za, sizeof (zap_attribute_t)); 3629842727c2SChris Kirby } 3630842727c2SChris Kirby dsl_dataset_rele(ds, FTAG); 3631842727c2SChris Kirby return (0); 3632842727c2SChris Kirby } 3633*503ad85cSMatthew Ahrens 3634*503ad85cSMatthew Ahrens /* 3635*503ad85cSMatthew Ahrens * Note, this fuction is used as the callback for dmu_objset_find(). We 3636*503ad85cSMatthew Ahrens * always return 0 so that we will continue to find and process 3637*503ad85cSMatthew Ahrens * inconsistent datasets, even if we encounter an error trying to 3638*503ad85cSMatthew Ahrens * process one of them. 3639*503ad85cSMatthew Ahrens */ 3640*503ad85cSMatthew Ahrens /* ARGSUSED */ 3641*503ad85cSMatthew Ahrens int 3642*503ad85cSMatthew Ahrens dsl_destroy_inconsistent(char *dsname, void *arg) 3643*503ad85cSMatthew Ahrens { 3644*503ad85cSMatthew Ahrens dsl_dataset_t *ds; 3645*503ad85cSMatthew Ahrens 3646*503ad85cSMatthew Ahrens if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) { 3647*503ad85cSMatthew Ahrens if (DS_IS_INCONSISTENT(ds)) 3648*503ad85cSMatthew Ahrens (void) dsl_dataset_destroy(ds, FTAG, B_FALSE); 3649*503ad85cSMatthew Ahrens else 3650*503ad85cSMatthew Ahrens dsl_dataset_disown(ds, FTAG); 3651*503ad85cSMatthew Ahrens } 3652*503ad85cSMatthew Ahrens return (0); 3653*503ad85cSMatthew Ahrens } 3654