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> 42*842727c2SChris 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; 481d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_rollback_check; 491d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_rollback_sync; 50a9799022Sck static dsl_syncfunc_t dsl_dataset_set_reservation_sync; 51e1930233Sbonwick 5255434c77Sek #define DS_REF_MAX (1ULL << 62) 53fa9e4066Sahrens 54fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 55fa9e4066Sahrens 56745cd3c5Smaybee #define DSL_DATASET_IS_DESTROYED(ds) ((ds)->ds_owner == dsl_reaper) 57745cd3c5Smaybee 58fa9e4066Sahrens 59a9799022Sck /* 60a9799022Sck * Figure out how much of this delta should be propogated to the dsl_dir 61a9799022Sck * layer. If there's a refreservation, that space has already been 62a9799022Sck * partially accounted for in our ancestors. 63a9799022Sck */ 64a9799022Sck static int64_t 65a9799022Sck parent_delta(dsl_dataset_t *ds, int64_t delta) 66a9799022Sck { 67a9799022Sck uint64_t old_bytes, new_bytes; 68a9799022Sck 69a9799022Sck if (ds->ds_reserved == 0) 70a9799022Sck return (delta); 71a9799022Sck 72a9799022Sck old_bytes = MAX(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 73a9799022Sck new_bytes = MAX(ds->ds_phys->ds_unique_bytes + delta, ds->ds_reserved); 74a9799022Sck 75a9799022Sck ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta)); 76a9799022Sck return (new_bytes - old_bytes); 77a9799022Sck } 78fa9e4066Sahrens 79fa9e4066Sahrens void 80fa9e4066Sahrens dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 81fa9e4066Sahrens { 8299653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 83fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 84fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 85a9799022Sck int64_t delta; 86fa9e4066Sahrens 87fa9e4066Sahrens dprintf_bp(bp, "born, ds=%p\n", ds); 88fa9e4066Sahrens 89fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 90fa9e4066Sahrens /* It could have been compressed away to nothing */ 91fa9e4066Sahrens if (BP_IS_HOLE(bp)) 92fa9e4066Sahrens return; 93fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 94fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 95fa9e4066Sahrens if (ds == NULL) { 96fa9e4066Sahrens /* 97fa9e4066Sahrens * Account for the meta-objset space in its placeholder 98fa9e4066Sahrens * dsl_dir. 99fa9e4066Sahrens */ 100fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 10174e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 102fa9e4066Sahrens used, compressed, uncompressed, tx); 103fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 104fa9e4066Sahrens return; 105fa9e4066Sahrens } 106fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 10702c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 108fa9e4066Sahrens mutex_enter(&ds->ds_lock); 109a9799022Sck delta = parent_delta(ds, used); 110fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 111fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 112fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 113fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 114fa9e4066Sahrens mutex_exit(&ds->ds_lock); 11574e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, 11674e7dc98SMatthew Ahrens compressed, uncompressed, tx); 11774e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used - delta, 11874e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 11902c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 120fa9e4066Sahrens } 121fa9e4066Sahrens 122cdb0ab79Smaybee int 123c717a561Smaybee dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, zio_t *pio, 124c717a561Smaybee dmu_tx_t *tx) 125fa9e4066Sahrens { 12699653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 127fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 128fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 129fa9e4066Sahrens 130e14bb325SJeff Bonwick ASSERT(pio != NULL); 131fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 132c717a561Smaybee /* No block pointer => nothing to free */ 133fa9e4066Sahrens if (BP_IS_HOLE(bp)) 134cdb0ab79Smaybee return (0); 135fa9e4066Sahrens 136fa9e4066Sahrens ASSERT(used > 0); 137fa9e4066Sahrens if (ds == NULL) { 138c717a561Smaybee int err; 139fa9e4066Sahrens /* 140fa9e4066Sahrens * Account for the meta-objset space in its placeholder 141fa9e4066Sahrens * dataset. 142fa9e4066Sahrens */ 143088f3894Sahrens err = dsl_free(pio, tx->tx_pool, 144e14bb325SJeff Bonwick tx->tx_txg, bp, NULL, NULL, ARC_NOWAIT); 145c717a561Smaybee ASSERT(err == 0); 146fa9e4066Sahrens 14774e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 148fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 149fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 150cdb0ab79Smaybee return (used); 151fa9e4066Sahrens } 152fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 153fa9e4066Sahrens 15474e7dc98SMatthew Ahrens ASSERT(!dsl_dataset_is_snapshot(ds)); 155fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 156fa9e4066Sahrens 157fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 158c717a561Smaybee int err; 159a9799022Sck int64_t delta; 160c717a561Smaybee 161fa9e4066Sahrens dprintf_bp(bp, "freeing: %s", ""); 162088f3894Sahrens err = dsl_free(pio, tx->tx_pool, 163e14bb325SJeff Bonwick tx->tx_txg, bp, NULL, NULL, ARC_NOWAIT); 164c717a561Smaybee ASSERT(err == 0); 165fa9e4066Sahrens 16602c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 167fa9e4066Sahrens mutex_enter(&ds->ds_lock); 168a9799022Sck ASSERT(ds->ds_phys->ds_unique_bytes >= used || 169a9799022Sck !DS_UNIQUE_IS_ACCURATE(ds)); 170a9799022Sck delta = parent_delta(ds, -used); 171fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 172fa9e4066Sahrens mutex_exit(&ds->ds_lock); 17374e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 174a9799022Sck delta, -compressed, -uncompressed, tx); 17574e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, -used - delta, 17674e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 17702c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 178fa9e4066Sahrens } else { 179fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 180ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 181a4611edeSahrens ASSERT3U(ds->ds_prev->ds_object, ==, 182a4611edeSahrens ds->ds_phys->ds_prev_snap_obj); 183a4611edeSahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 184fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 185a4611edeSahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 186a4611edeSahrens ds->ds_object && bp->blk_birth > 187a4611edeSahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 188a4611edeSahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 189a4611edeSahrens mutex_enter(&ds->ds_prev->ds_lock); 190a4611edeSahrens ds->ds_prev->ds_phys->ds_unique_bytes += used; 191a4611edeSahrens mutex_exit(&ds->ds_prev->ds_lock); 192fa9e4066Sahrens } 19374e7dc98SMatthew Ahrens if (bp->blk_birth > ds->ds_origin_txg) { 19474e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used, 19574e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 19674e7dc98SMatthew Ahrens } 197fa9e4066Sahrens } 198fa9e4066Sahrens mutex_enter(&ds->ds_lock); 199fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 200fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 201fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 202fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 203fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 204fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 205fa9e4066Sahrens mutex_exit(&ds->ds_lock); 206cdb0ab79Smaybee 207cdb0ab79Smaybee return (used); 208fa9e4066Sahrens } 209fa9e4066Sahrens 210ea8dc4b6Seschrock uint64_t 211ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 212fa9e4066Sahrens { 213a2eea2e1Sahrens uint64_t trysnap = 0; 214a2eea2e1Sahrens 215fa9e4066Sahrens if (ds == NULL) 216ea8dc4b6Seschrock return (0); 217fa9e4066Sahrens /* 218fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 219fa9e4066Sahrens * incorrect FALSE return, which would only result in an 220fa9e4066Sahrens * overestimation of the amount of space that an operation would 221fa9e4066Sahrens * consume, which is OK. 222fa9e4066Sahrens * 223fa9e4066Sahrens * There's also a small window where we could miss a pending 224fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 225fa9e4066Sahrens * phase. So this should only be used as a guess. 226fa9e4066Sahrens */ 227a2eea2e1Sahrens if (ds->ds_trysnap_txg > 228a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 229a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 230a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 231ea8dc4b6Seschrock } 232ea8dc4b6Seschrock 2333d692628SSanjeev Bagewadi boolean_t 234ea8dc4b6Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 235ea8dc4b6Seschrock { 236ea8dc4b6Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 237fa9e4066Sahrens } 238fa9e4066Sahrens 239fa9e4066Sahrens /* ARGSUSED */ 240fa9e4066Sahrens static void 241fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 242fa9e4066Sahrens { 243fa9e4066Sahrens dsl_dataset_t *ds = dsv; 244fa9e4066Sahrens 245745cd3c5Smaybee ASSERT(ds->ds_owner == NULL || DSL_DATASET_IS_DESTROYED(ds)); 246fa9e4066Sahrens 247fa9e4066Sahrens dprintf_ds(ds, "evicting %s\n", ""); 248fa9e4066Sahrens 24991ebeef5Sahrens unique_remove(ds->ds_fsid_guid); 250fa9e4066Sahrens 251fa9e4066Sahrens if (ds->ds_user_ptr != NULL) 252fa9e4066Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 253fa9e4066Sahrens 254fa9e4066Sahrens if (ds->ds_prev) { 255745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 256fa9e4066Sahrens ds->ds_prev = NULL; 257fa9e4066Sahrens } 258fa9e4066Sahrens 259fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 260745cd3c5Smaybee if (ds->ds_dir) 261745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 262fa9e4066Sahrens 26391ebeef5Sahrens ASSERT(!list_link_active(&ds->ds_synced_link)); 264fa9e4066Sahrens 2655ad82045Snd mutex_destroy(&ds->ds_lock); 266f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 26791ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 2685ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 269745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 270745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 2715ad82045Snd 272fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 273fa9e4066Sahrens } 274fa9e4066Sahrens 275ea8dc4b6Seschrock static int 276fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 277fa9e4066Sahrens { 278fa9e4066Sahrens dsl_dataset_phys_t *headphys; 279fa9e4066Sahrens int err; 280fa9e4066Sahrens dmu_buf_t *headdbuf; 281fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 282fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 283fa9e4066Sahrens 284fa9e4066Sahrens if (ds->ds_snapname[0]) 285ea8dc4b6Seschrock return (0); 286fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 287ea8dc4b6Seschrock return (0); 288fa9e4066Sahrens 289ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 290ea8dc4b6Seschrock FTAG, &headdbuf); 291ea8dc4b6Seschrock if (err) 292ea8dc4b6Seschrock return (err); 293fa9e4066Sahrens headphys = headdbuf->db_data; 294fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 295e7437265Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); 296ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 297ea8dc4b6Seschrock return (err); 298fa9e4066Sahrens } 299fa9e4066Sahrens 300ab04eb8eStimh static int 301745cd3c5Smaybee dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value) 302ab04eb8eStimh { 303745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 304745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 305ab04eb8eStimh matchtype_t mt; 306ab04eb8eStimh int err; 307ab04eb8eStimh 308745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 309ab04eb8eStimh mt = MT_FIRST; 310ab04eb8eStimh else 311ab04eb8eStimh mt = MT_EXACT; 312ab04eb8eStimh 313745cd3c5Smaybee err = zap_lookup_norm(mos, snapobj, name, 8, 1, 314ab04eb8eStimh value, mt, NULL, 0, NULL); 315ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 316745cd3c5Smaybee err = zap_lookup(mos, snapobj, name, 8, 1, value); 317ab04eb8eStimh return (err); 318ab04eb8eStimh } 319ab04eb8eStimh 320ab04eb8eStimh static int 321745cd3c5Smaybee dsl_dataset_snap_remove(dsl_dataset_t *ds, char *name, dmu_tx_t *tx) 322ab04eb8eStimh { 323745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 324745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 325ab04eb8eStimh matchtype_t mt; 326ab04eb8eStimh int err; 327ab04eb8eStimh 328745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 329ab04eb8eStimh mt = MT_FIRST; 330ab04eb8eStimh else 331ab04eb8eStimh mt = MT_EXACT; 332ab04eb8eStimh 333745cd3c5Smaybee err = zap_remove_norm(mos, snapobj, name, mt, tx); 334ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 335745cd3c5Smaybee err = zap_remove(mos, snapobj, name, tx); 336ab04eb8eStimh return (err); 337ab04eb8eStimh } 338ab04eb8eStimh 339745cd3c5Smaybee static int 340745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag, 341745cd3c5Smaybee dsl_dataset_t **dsp) 342fa9e4066Sahrens { 343fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 344fa9e4066Sahrens dmu_buf_t *dbuf; 345fa9e4066Sahrens dsl_dataset_t *ds; 346ea8dc4b6Seschrock int err; 347fa9e4066Sahrens 348fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 349fa9e4066Sahrens dsl_pool_sync_context(dp)); 350fa9e4066Sahrens 351ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 352ea8dc4b6Seschrock if (err) 353ea8dc4b6Seschrock return (err); 354fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 355fa9e4066Sahrens if (ds == NULL) { 356fa9e4066Sahrens dsl_dataset_t *winner; 357fa9e4066Sahrens 358fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 359fa9e4066Sahrens ds->ds_dbuf = dbuf; 360fa9e4066Sahrens ds->ds_object = dsobj; 361fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 362fa9e4066Sahrens 3635ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 364f4b94bdeSMatthew Ahrens mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL); 36591ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 3665ad82045Snd mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT, 3675ad82045Snd NULL); 368745cd3c5Smaybee rw_init(&ds->ds_rwlock, 0, 0, 0); 369745cd3c5Smaybee cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL); 3705ad82045Snd 371ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 372fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 373ea8dc4b6Seschrock if (err == 0) { 374ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 375ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 376ea8dc4b6Seschrock } 377ea8dc4b6Seschrock if (err) { 378ea8dc4b6Seschrock /* 379ea8dc4b6Seschrock * we don't really need to close the blist if we 380ea8dc4b6Seschrock * just opened it. 381ea8dc4b6Seschrock */ 3825ad82045Snd mutex_destroy(&ds->ds_lock); 383f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 38491ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 3855ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 386745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 387745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 388ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 389ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 390ea8dc4b6Seschrock return (err); 391ea8dc4b6Seschrock } 392fa9e4066Sahrens 39374e7dc98SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 394fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 395fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 396745cd3c5Smaybee err = dsl_dataset_get_ref(dp, 397745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 398745cd3c5Smaybee ds, &ds->ds_prev); 399fa9e4066Sahrens } 40074e7dc98SMatthew Ahrens 40174e7dc98SMatthew Ahrens if (err == 0 && dsl_dir_is_clone(ds->ds_dir)) { 40274e7dc98SMatthew Ahrens dsl_dataset_t *origin; 40374e7dc98SMatthew Ahrens 40474e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, 40574e7dc98SMatthew Ahrens ds->ds_dir->dd_phys->dd_origin_obj, 40674e7dc98SMatthew Ahrens FTAG, &origin); 40774e7dc98SMatthew Ahrens if (err == 0) { 40874e7dc98SMatthew Ahrens ds->ds_origin_txg = 40974e7dc98SMatthew Ahrens origin->ds_phys->ds_creation_txg; 41074e7dc98SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 41174e7dc98SMatthew Ahrens } 41274e7dc98SMatthew Ahrens } 413*842727c2SChris Kirby } else { 414*842727c2SChris Kirby if (zfs_flags & ZFS_DEBUG_SNAPNAMES) 415*842727c2SChris Kirby err = dsl_dataset_get_snapname(ds); 416*842727c2SChris Kirby if (err == 0 && ds->ds_phys->ds_userrefs_obj != 0) { 417*842727c2SChris Kirby err = zap_count( 418*842727c2SChris Kirby ds->ds_dir->dd_pool->dp_meta_objset, 419*842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj, 420*842727c2SChris Kirby &ds->ds_userrefs); 421*842727c2SChris Kirby } 422fa9e4066Sahrens } 423fa9e4066Sahrens 42474e7dc98SMatthew Ahrens if (err == 0 && !dsl_dataset_is_snapshot(ds)) { 42527345066Sck /* 42627345066Sck * In sync context, we're called with either no lock 42727345066Sck * or with the write lock. If we're not syncing, 42827345066Sck * we're always called with the read lock held. 42927345066Sck */ 430cb625fb5Sck boolean_t need_lock = 43127345066Sck !RW_WRITE_HELD(&dp->dp_config_rwlock) && 43227345066Sck dsl_pool_sync_context(dp); 433cb625fb5Sck 434cb625fb5Sck if (need_lock) 435cb625fb5Sck rw_enter(&dp->dp_config_rwlock, RW_READER); 436cb625fb5Sck 437bb0ade09Sahrens err = dsl_prop_get_ds(ds, 438cb625fb5Sck "refreservation", sizeof (uint64_t), 1, 439cb625fb5Sck &ds->ds_reserved, NULL); 440cb625fb5Sck if (err == 0) { 441bb0ade09Sahrens err = dsl_prop_get_ds(ds, 442cb625fb5Sck "refquota", sizeof (uint64_t), 1, 443cb625fb5Sck &ds->ds_quota, NULL); 444cb625fb5Sck } 445cb625fb5Sck 446cb625fb5Sck if (need_lock) 447cb625fb5Sck rw_exit(&dp->dp_config_rwlock); 448cb625fb5Sck } else { 449cb625fb5Sck ds->ds_reserved = ds->ds_quota = 0; 450cb625fb5Sck } 451cb625fb5Sck 452ea8dc4b6Seschrock if (err == 0) { 453ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 454ea8dc4b6Seschrock dsl_dataset_evict); 455ea8dc4b6Seschrock } 456ea8dc4b6Seschrock if (err || winner) { 457fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 458745cd3c5Smaybee if (ds->ds_prev) 459745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 460fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 4615ad82045Snd mutex_destroy(&ds->ds_lock); 462f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 46391ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 4645ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 465745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 466745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 467fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 468ea8dc4b6Seschrock if (err) { 469ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 470ea8dc4b6Seschrock return (err); 471ea8dc4b6Seschrock } 472fa9e4066Sahrens ds = winner; 473fa9e4066Sahrens } else { 47491ebeef5Sahrens ds->ds_fsid_guid = 475fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 476fa9e4066Sahrens } 477fa9e4066Sahrens } 478fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 479fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 480088f3894Sahrens ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 || 481afc6333aSahrens spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN || 48284db2a68Sahrens dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap); 483fa9e4066Sahrens mutex_enter(&ds->ds_lock); 484745cd3c5Smaybee if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) { 485fa9e4066Sahrens mutex_exit(&ds->ds_lock); 486745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 487745cd3c5Smaybee return (ENOENT); 488fa9e4066Sahrens } 489fa9e4066Sahrens mutex_exit(&ds->ds_lock); 490ea8dc4b6Seschrock *dsp = ds; 491ea8dc4b6Seschrock return (0); 492fa9e4066Sahrens } 493fa9e4066Sahrens 494745cd3c5Smaybee static int 495745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag) 496745cd3c5Smaybee { 497745cd3c5Smaybee dsl_pool_t *dp = ds->ds_dir->dd_pool; 498745cd3c5Smaybee 499745cd3c5Smaybee /* 500745cd3c5Smaybee * In syncing context we don't want the rwlock lock: there 501745cd3c5Smaybee * may be an existing writer waiting for sync phase to 502745cd3c5Smaybee * finish. We don't need to worry about such writers, since 503745cd3c5Smaybee * sync phase is single-threaded, so the writer can't be 504745cd3c5Smaybee * doing anything while we are active. 505745cd3c5Smaybee */ 506745cd3c5Smaybee if (dsl_pool_sync_context(dp)) { 507745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 508745cd3c5Smaybee return (0); 509745cd3c5Smaybee } 510745cd3c5Smaybee 511745cd3c5Smaybee /* 512745cd3c5Smaybee * Normal users will hold the ds_rwlock as a READER until they 513745cd3c5Smaybee * are finished (i.e., call dsl_dataset_rele()). "Owners" will 514745cd3c5Smaybee * drop their READER lock after they set the ds_owner field. 515745cd3c5Smaybee * 516745cd3c5Smaybee * If the dataset is being destroyed, the destroy thread will 517745cd3c5Smaybee * obtain a WRITER lock for exclusive access after it's done its 518745cd3c5Smaybee * open-context work and then change the ds_owner to 519745cd3c5Smaybee * dsl_reaper once destruction is assured. So threads 520745cd3c5Smaybee * may block here temporarily, until the "destructability" of 521745cd3c5Smaybee * the dataset is determined. 522745cd3c5Smaybee */ 523745cd3c5Smaybee ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock)); 524745cd3c5Smaybee mutex_enter(&ds->ds_lock); 525745cd3c5Smaybee while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) { 526745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 527745cd3c5Smaybee cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock); 528745cd3c5Smaybee if (DSL_DATASET_IS_DESTROYED(ds)) { 529745cd3c5Smaybee mutex_exit(&ds->ds_lock); 530745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 531745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 532745cd3c5Smaybee return (ENOENT); 533745cd3c5Smaybee } 534745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 535745cd3c5Smaybee } 536745cd3c5Smaybee mutex_exit(&ds->ds_lock); 537745cd3c5Smaybee return (0); 538745cd3c5Smaybee } 539745cd3c5Smaybee 540745cd3c5Smaybee int 541745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, 542745cd3c5Smaybee dsl_dataset_t **dsp) 543745cd3c5Smaybee { 544745cd3c5Smaybee int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp); 545745cd3c5Smaybee 546745cd3c5Smaybee if (err) 547745cd3c5Smaybee return (err); 548745cd3c5Smaybee return (dsl_dataset_hold_ref(*dsp, tag)); 549745cd3c5Smaybee } 550745cd3c5Smaybee 551745cd3c5Smaybee int 552745cd3c5Smaybee dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, int flags, void *owner, 553745cd3c5Smaybee dsl_dataset_t **dsp) 554745cd3c5Smaybee { 555745cd3c5Smaybee int err = dsl_dataset_hold_obj(dp, dsobj, owner, dsp); 556745cd3c5Smaybee 557745cd3c5Smaybee ASSERT(DS_MODE_TYPE(flags) != DS_MODE_USER); 558745cd3c5Smaybee 559745cd3c5Smaybee if (err) 560745cd3c5Smaybee return (err); 561745cd3c5Smaybee if (!dsl_dataset_tryown(*dsp, DS_MODE_IS_INCONSISTENT(flags), owner)) { 562745cd3c5Smaybee dsl_dataset_rele(*dsp, owner); 5634f5064b7SMark J Musante *dsp = NULL; 564745cd3c5Smaybee return (EBUSY); 565745cd3c5Smaybee } 566745cd3c5Smaybee return (0); 567745cd3c5Smaybee } 568745cd3c5Smaybee 569fa9e4066Sahrens int 570745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp) 571fa9e4066Sahrens { 572fa9e4066Sahrens dsl_dir_t *dd; 573fa9e4066Sahrens dsl_pool_t *dp; 574745cd3c5Smaybee const char *snapname; 575fa9e4066Sahrens uint64_t obj; 576fa9e4066Sahrens int err = 0; 577fa9e4066Sahrens 578745cd3c5Smaybee err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname); 579ea8dc4b6Seschrock if (err) 580ea8dc4b6Seschrock return (err); 581fa9e4066Sahrens 582fa9e4066Sahrens dp = dd->dd_pool; 583fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 584fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 585745cd3c5Smaybee if (obj) 586745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, dsp); 587745cd3c5Smaybee else 588fa9e4066Sahrens err = ENOENT; 589745cd3c5Smaybee if (err) 590fa9e4066Sahrens goto out; 591fa9e4066Sahrens 592745cd3c5Smaybee err = dsl_dataset_hold_ref(*dsp, tag); 593fa9e4066Sahrens 594745cd3c5Smaybee /* we may be looking for a snapshot */ 595745cd3c5Smaybee if (err == 0 && snapname != NULL) { 596745cd3c5Smaybee dsl_dataset_t *ds = NULL; 597fa9e4066Sahrens 598745cd3c5Smaybee if (*snapname++ != '@') { 599745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 600fa9e4066Sahrens err = ENOENT; 601fa9e4066Sahrens goto out; 602fa9e4066Sahrens } 603fa9e4066Sahrens 604745cd3c5Smaybee dprintf("looking for snapshot '%s'\n", snapname); 605745cd3c5Smaybee err = dsl_dataset_snap_lookup(*dsp, snapname, &obj); 606745cd3c5Smaybee if (err == 0) 607745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, &ds); 608745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 609745cd3c5Smaybee 610745cd3c5Smaybee ASSERT3U((err == 0), ==, (ds != NULL)); 611745cd3c5Smaybee 612745cd3c5Smaybee if (ds) { 613745cd3c5Smaybee mutex_enter(&ds->ds_lock); 614745cd3c5Smaybee if (ds->ds_snapname[0] == 0) 615745cd3c5Smaybee (void) strlcpy(ds->ds_snapname, snapname, 616745cd3c5Smaybee sizeof (ds->ds_snapname)); 617745cd3c5Smaybee mutex_exit(&ds->ds_lock); 618745cd3c5Smaybee err = dsl_dataset_hold_ref(ds, tag); 619745cd3c5Smaybee *dsp = err ? NULL : ds; 620fa9e4066Sahrens } 621fa9e4066Sahrens } 622fa9e4066Sahrens out: 623fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 624fa9e4066Sahrens dsl_dir_close(dd, FTAG); 625fa9e4066Sahrens return (err); 626fa9e4066Sahrens } 627fa9e4066Sahrens 628fa9e4066Sahrens int 629745cd3c5Smaybee dsl_dataset_own(const char *name, int flags, void *owner, dsl_dataset_t **dsp) 630fa9e4066Sahrens { 631745cd3c5Smaybee int err = dsl_dataset_hold(name, owner, dsp); 632745cd3c5Smaybee if (err) 633745cd3c5Smaybee return (err); 634745cd3c5Smaybee if ((*dsp)->ds_phys->ds_num_children > 0 && 635745cd3c5Smaybee !DS_MODE_IS_READONLY(flags)) { 636745cd3c5Smaybee dsl_dataset_rele(*dsp, owner); 637745cd3c5Smaybee return (EROFS); 638745cd3c5Smaybee } 639745cd3c5Smaybee if (!dsl_dataset_tryown(*dsp, DS_MODE_IS_INCONSISTENT(flags), owner)) { 640745cd3c5Smaybee dsl_dataset_rele(*dsp, owner); 641745cd3c5Smaybee return (EBUSY); 642745cd3c5Smaybee } 643745cd3c5Smaybee return (0); 644fa9e4066Sahrens } 645fa9e4066Sahrens 646fa9e4066Sahrens void 647fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 648fa9e4066Sahrens { 649fa9e4066Sahrens if (ds == NULL) { 650fa9e4066Sahrens (void) strcpy(name, "mos"); 651fa9e4066Sahrens } else { 652fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 653ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 654fa9e4066Sahrens if (ds->ds_snapname[0]) { 655fa9e4066Sahrens (void) strcat(name, "@"); 656745cd3c5Smaybee /* 657745cd3c5Smaybee * We use a "recursive" mutex so that we 658745cd3c5Smaybee * can call dprintf_ds() with ds_lock held. 659745cd3c5Smaybee */ 660fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 661fa9e4066Sahrens mutex_enter(&ds->ds_lock); 662fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 663fa9e4066Sahrens mutex_exit(&ds->ds_lock); 664fa9e4066Sahrens } else { 665fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 666fa9e4066Sahrens } 667fa9e4066Sahrens } 668fa9e4066Sahrens } 669fa9e4066Sahrens } 670fa9e4066Sahrens 671b7661cccSmmusante static int 672b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 673b7661cccSmmusante { 674b7661cccSmmusante int result; 675b7661cccSmmusante 676b7661cccSmmusante if (ds == NULL) { 677b7661cccSmmusante result = 3; /* "mos" */ 678b7661cccSmmusante } else { 679b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 680b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 681b7661cccSmmusante if (ds->ds_snapname[0]) { 682b7661cccSmmusante ++result; /* adding one for the @-sign */ 683b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 684b7661cccSmmusante mutex_enter(&ds->ds_lock); 685b7661cccSmmusante result += strlen(ds->ds_snapname); 686b7661cccSmmusante mutex_exit(&ds->ds_lock); 687b7661cccSmmusante } else { 688b7661cccSmmusante result += strlen(ds->ds_snapname); 689b7661cccSmmusante } 690b7661cccSmmusante } 691b7661cccSmmusante } 692b7661cccSmmusante 693b7661cccSmmusante return (result); 694b7661cccSmmusante } 695b7661cccSmmusante 696088f3894Sahrens void 697745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag) 698fa9e4066Sahrens { 699ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 700fa9e4066Sahrens } 701fa9e4066Sahrens 7023cb34c60Sahrens void 703745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag) 7043cb34c60Sahrens { 705745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) { 706745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 707745cd3c5Smaybee } 708745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 709745cd3c5Smaybee } 710745cd3c5Smaybee 711745cd3c5Smaybee void 712745cd3c5Smaybee dsl_dataset_disown(dsl_dataset_t *ds, void *owner) 713745cd3c5Smaybee { 714745cd3c5Smaybee ASSERT((ds->ds_owner == owner && ds->ds_dbuf) || 715745cd3c5Smaybee (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL)); 716745cd3c5Smaybee 7173cb34c60Sahrens mutex_enter(&ds->ds_lock); 718745cd3c5Smaybee ds->ds_owner = NULL; 719745cd3c5Smaybee if (RW_WRITE_HELD(&ds->ds_rwlock)) { 720745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 721745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 722745cd3c5Smaybee } 7233cb34c60Sahrens mutex_exit(&ds->ds_lock); 724745cd3c5Smaybee if (ds->ds_dbuf) 725745cd3c5Smaybee dsl_dataset_drop_ref(ds, owner); 726745cd3c5Smaybee else 727745cd3c5Smaybee dsl_dataset_evict(ds->ds_dbuf, ds); 7283cb34c60Sahrens } 7293cb34c60Sahrens 7303cb34c60Sahrens boolean_t 731745cd3c5Smaybee dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *owner) 7323cb34c60Sahrens { 733745cd3c5Smaybee boolean_t gotit = FALSE; 734745cd3c5Smaybee 7353cb34c60Sahrens mutex_enter(&ds->ds_lock); 736745cd3c5Smaybee if (ds->ds_owner == NULL && 737745cd3c5Smaybee (!DS_IS_INCONSISTENT(ds) || inconsistentok)) { 738745cd3c5Smaybee ds->ds_owner = owner; 739745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) 740745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 741745cd3c5Smaybee gotit = TRUE; 7423cb34c60Sahrens } 7433cb34c60Sahrens mutex_exit(&ds->ds_lock); 744745cd3c5Smaybee return (gotit); 745745cd3c5Smaybee } 746745cd3c5Smaybee 747745cd3c5Smaybee void 748745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner) 749745cd3c5Smaybee { 750745cd3c5Smaybee ASSERT3P(owner, ==, ds->ds_owner); 751745cd3c5Smaybee if (!RW_WRITE_HELD(&ds->ds_rwlock)) 752745cd3c5Smaybee rw_enter(&ds->ds_rwlock, RW_WRITER); 7533cb34c60Sahrens } 7543cb34c60Sahrens 7551d452cf5Sahrens uint64_t 756088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 757ab04eb8eStimh uint64_t flags, dmu_tx_t *tx) 758fa9e4066Sahrens { 7593cb34c60Sahrens dsl_pool_t *dp = dd->dd_pool; 760fa9e4066Sahrens dmu_buf_t *dbuf; 761fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 7623cb34c60Sahrens uint64_t dsobj; 763fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 764fa9e4066Sahrens 765088f3894Sahrens if (origin == NULL) 766088f3894Sahrens origin = dp->dp_origin_snap; 767088f3894Sahrens 7683cb34c60Sahrens ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp); 7693cb34c60Sahrens ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0); 770fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 7713cb34c60Sahrens ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); 772fa9e4066Sahrens 7731649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 7741649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 775ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 776fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 777fa9e4066Sahrens dsphys = dbuf->db_data; 778745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 779fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 780ab04eb8eStimh dsphys->ds_flags = flags; 781fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 782fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 783fa9e4066Sahrens sizeof (dsphys->ds_guid)); 784fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 785ab04eb8eStimh zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP, 786ab04eb8eStimh DMU_OT_NONE, 0, tx); 787fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 788088f3894Sahrens dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg; 789fa9e4066Sahrens dsphys->ds_deadlist_obj = 790fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 791a9799022Sck 7923cb34c60Sahrens if (origin) { 7933cb34c60Sahrens dsphys->ds_prev_snap_obj = origin->ds_object; 794fa9e4066Sahrens dsphys->ds_prev_snap_txg = 7953cb34c60Sahrens origin->ds_phys->ds_creation_txg; 796fa9e4066Sahrens dsphys->ds_used_bytes = 7973cb34c60Sahrens origin->ds_phys->ds_used_bytes; 798fa9e4066Sahrens dsphys->ds_compressed_bytes = 7993cb34c60Sahrens origin->ds_phys->ds_compressed_bytes; 800fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 8013cb34c60Sahrens origin->ds_phys->ds_uncompressed_bytes; 8023cb34c60Sahrens dsphys->ds_bp = origin->ds_phys->ds_bp; 803579ae4d5Stimh dsphys->ds_flags |= origin->ds_phys->ds_flags; 804fa9e4066Sahrens 8053cb34c60Sahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 8063cb34c60Sahrens origin->ds_phys->ds_num_children++; 807fa9e4066Sahrens 808088f3894Sahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) { 809088f3894Sahrens if (origin->ds_phys->ds_next_clones_obj == 0) { 810088f3894Sahrens origin->ds_phys->ds_next_clones_obj = 811088f3894Sahrens zap_create(mos, 812088f3894Sahrens DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx); 813088f3894Sahrens } 814088f3894Sahrens VERIFY(0 == zap_add_int(mos, 815088f3894Sahrens origin->ds_phys->ds_next_clones_obj, 816088f3894Sahrens dsobj, tx)); 817088f3894Sahrens } 818088f3894Sahrens 819fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 8203cb34c60Sahrens dd->dd_phys->dd_origin_obj = origin->ds_object; 821fa9e4066Sahrens } 822ab04eb8eStimh 823ab04eb8eStimh if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 824ab04eb8eStimh dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 825ab04eb8eStimh 826ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 827fa9e4066Sahrens 828fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 829fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 8303cb34c60Sahrens 8313cb34c60Sahrens return (dsobj); 8323cb34c60Sahrens } 8333cb34c60Sahrens 8343cb34c60Sahrens uint64_t 835ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname, 836ab04eb8eStimh dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx) 8373cb34c60Sahrens { 8383cb34c60Sahrens dsl_pool_t *dp = pdd->dd_pool; 8393cb34c60Sahrens uint64_t dsobj, ddobj; 8403cb34c60Sahrens dsl_dir_t *dd; 8413cb34c60Sahrens 8423cb34c60Sahrens ASSERT(lastname[0] != '@'); 8433cb34c60Sahrens 844088f3894Sahrens ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx); 8453cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 8463cb34c60Sahrens 847088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx); 8483cb34c60Sahrens 8493cb34c60Sahrens dsl_deleg_set_create_perms(dd, tx, cr); 8503cb34c60Sahrens 851fa9e4066Sahrens dsl_dir_close(dd, FTAG); 852fa9e4066Sahrens 8531d452cf5Sahrens return (dsobj); 854fa9e4066Sahrens } 855fa9e4066Sahrens 8561d452cf5Sahrens struct destroyarg { 8571d452cf5Sahrens dsl_sync_task_group_t *dstg; 8581d452cf5Sahrens char *snapname; 8591d452cf5Sahrens char *failed; 860*842727c2SChris Kirby boolean_t defer; 8611d452cf5Sahrens }; 8621d452cf5Sahrens 8631d452cf5Sahrens static int 8641d452cf5Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 865fa9e4066Sahrens { 8661d452cf5Sahrens struct destroyarg *da = arg; 8671d452cf5Sahrens dsl_dataset_t *ds; 868fa9e4066Sahrens int err; 869*842727c2SChris Kirby char *dsname; 870*842727c2SChris Kirby size_t buflen; 871*842727c2SChris Kirby 872*842727c2SChris Kirby /* alloc a buffer to hold name@snapname, plus the terminating NULL */ 873*842727c2SChris Kirby buflen = strlen(name) + strlen(da->snapname) + 2; 874*842727c2SChris Kirby dsname = kmem_alloc(buflen, KM_SLEEP); 875*842727c2SChris Kirby (void) snprintf(dsname, buflen, "%s@%s", name, da->snapname); 876*842727c2SChris Kirby err = dsl_dataset_own(dsname, DS_MODE_READONLY | DS_MODE_INCONSISTENT, 877cdf5b4caSmmusante da->dstg, &ds); 878*842727c2SChris Kirby kmem_free(dsname, buflen); 879745cd3c5Smaybee if (err == 0) { 880*842727c2SChris Kirby struct dsl_ds_destroyarg *dsda; 881*842727c2SChris Kirby 882745cd3c5Smaybee dsl_dataset_make_exclusive(ds, da->dstg); 8833baa08fcSek if (ds->ds_user_ptr) { 8843baa08fcSek ds->ds_user_evict_func(ds, ds->ds_user_ptr); 8853baa08fcSek ds->ds_user_ptr = NULL; 8863baa08fcSek } 887*842727c2SChris Kirby dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP); 888*842727c2SChris Kirby dsda->ds = ds; 889*842727c2SChris Kirby dsda->defer = da->defer; 890745cd3c5Smaybee dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 891*842727c2SChris Kirby dsl_dataset_destroy_sync, dsda, da->dstg, 0); 892745cd3c5Smaybee } else if (err == ENOENT) { 893745cd3c5Smaybee err = 0; 894745cd3c5Smaybee } else { 8951d452cf5Sahrens (void) strcpy(da->failed, name); 8961d452cf5Sahrens } 897745cd3c5Smaybee return (err); 8981d452cf5Sahrens } 89931fd60d3Sahrens 9001d452cf5Sahrens /* 9011d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 9021d452cf5Sahrens */ 9031d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 9041d452cf5Sahrens int 905*842727c2SChris Kirby dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer) 9061d452cf5Sahrens { 9071d452cf5Sahrens int err; 9081d452cf5Sahrens struct destroyarg da; 9091d452cf5Sahrens dsl_sync_task_t *dst; 9101d452cf5Sahrens spa_t *spa; 9111d452cf5Sahrens 91240feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 9131d452cf5Sahrens if (err) 9141d452cf5Sahrens return (err); 9151d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 9161d452cf5Sahrens da.snapname = snapname; 9171d452cf5Sahrens da.failed = fsname; 918*842727c2SChris Kirby da.defer = defer; 9191d452cf5Sahrens 9201d452cf5Sahrens err = dmu_objset_find(fsname, 9210b69c2f0Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 9221d452cf5Sahrens 9231d452cf5Sahrens if (err == 0) 9241d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 9251d452cf5Sahrens 9261d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 9271d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 928*842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 929*842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 930*842727c2SChris Kirby 931745cd3c5Smaybee /* 932745cd3c5Smaybee * Return the file system name that triggered the error 933745cd3c5Smaybee */ 9341d452cf5Sahrens if (dst->dst_err) { 9351d452cf5Sahrens dsl_dataset_name(ds, fsname); 93640feaa91Sahrens *strchr(fsname, '@') = '\0'; 937e1930233Sbonwick } 938*842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 939745cd3c5Smaybee dsl_dataset_disown(ds, da.dstg); 940*842727c2SChris Kirby kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 941fa9e4066Sahrens } 942fa9e4066Sahrens 9431d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 9441d452cf5Sahrens spa_close(spa, FTAG); 945fa9e4066Sahrens return (err); 946fa9e4066Sahrens } 947fa9e4066Sahrens 948*842727c2SChris Kirby static boolean_t 949*842727c2SChris Kirby dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 950*842727c2SChris Kirby { 951*842727c2SChris Kirby boolean_t might_destroy = B_FALSE; 952*842727c2SChris Kirby 953*842727c2SChris Kirby mutex_enter(&ds->ds_lock); 954*842727c2SChris Kirby if (ds->ds_phys->ds_num_children == 2 && ds->ds_userrefs == 0 && 955*842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 956*842727c2SChris Kirby might_destroy = B_TRUE; 957*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 958*842727c2SChris Kirby 959*842727c2SChris Kirby return (might_destroy); 960*842727c2SChris Kirby } 961*842727c2SChris Kirby 962*842727c2SChris Kirby #ifdef _KERNEL 963*842727c2SChris Kirby static int 964*842727c2SChris Kirby dsl_dataset_zvol_cleanup(dsl_dataset_t *ds, const char *name) 965*842727c2SChris Kirby { 966*842727c2SChris Kirby int error; 967*842727c2SChris Kirby objset_t *os; 968*842727c2SChris Kirby 969*842727c2SChris Kirby error = dmu_objset_open_ds(ds, DMU_OST_ANY, &os); 970*842727c2SChris Kirby if (error) 971*842727c2SChris Kirby return (error); 972*842727c2SChris Kirby 973*842727c2SChris Kirby if (dmu_objset_type(os) == DMU_OST_ZVOL) 974*842727c2SChris Kirby error = zvol_remove_minor(name); 975*842727c2SChris Kirby dmu_objset_close(os); 976*842727c2SChris Kirby 977*842727c2SChris Kirby return (error); 978*842727c2SChris Kirby } 979*842727c2SChris Kirby #endif 980*842727c2SChris Kirby 981*842727c2SChris Kirby /* 982*842727c2SChris Kirby * If we're removing a clone, and these three conditions are true: 983*842727c2SChris Kirby * 1) the clone's origin has no other children 984*842727c2SChris Kirby * 2) the clone's origin has no user references 985*842727c2SChris Kirby * 3) the clone's origin has been marked for deferred destruction 986*842727c2SChris Kirby * Then, prepare to remove the origin as part of this sync task group. 987*842727c2SChris Kirby */ 988*842727c2SChris Kirby static int 989*842727c2SChris Kirby dsl_dataset_origin_rm_prep(struct dsl_ds_destroyarg *dsda, void *tag) 990*842727c2SChris Kirby { 991*842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 992*842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 993*842727c2SChris Kirby 994*842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(origin)) { 995*842727c2SChris Kirby char *name; 996*842727c2SChris Kirby int namelen; 997*842727c2SChris Kirby int error; 998*842727c2SChris Kirby 999*842727c2SChris Kirby namelen = dsl_dataset_namelen(origin) + 1; 1000*842727c2SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 1001*842727c2SChris Kirby dsl_dataset_name(origin, name); 1002*842727c2SChris Kirby #ifdef _KERNEL 1003*842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 1004*842727c2SChris Kirby if (error) { 1005*842727c2SChris Kirby kmem_free(name, namelen); 1006*842727c2SChris Kirby return (error); 1007*842727c2SChris Kirby } 1008*842727c2SChris Kirby error = dsl_dataset_zvol_cleanup(origin, name); 1009*842727c2SChris Kirby if (error) { 1010*842727c2SChris Kirby kmem_free(name, namelen); 1011*842727c2SChris Kirby return (error); 1012*842727c2SChris Kirby } 1013*842727c2SChris Kirby #endif 1014*842727c2SChris Kirby error = dsl_dataset_own(name, 1015*842727c2SChris Kirby DS_MODE_READONLY | DS_MODE_INCONSISTENT, 1016*842727c2SChris Kirby tag, &origin); 1017*842727c2SChris Kirby kmem_free(name, namelen); 1018*842727c2SChris Kirby if (error) 1019*842727c2SChris Kirby return (error); 1020*842727c2SChris Kirby dsda->rm_origin = origin; 1021*842727c2SChris Kirby dsl_dataset_make_exclusive(origin, tag); 1022*842727c2SChris Kirby } 1023*842727c2SChris Kirby 1024*842727c2SChris Kirby return (0); 1025*842727c2SChris Kirby } 1026*842727c2SChris Kirby 10273cb34c60Sahrens /* 1028745cd3c5Smaybee * ds must be opened as OWNER. On return (whether successful or not), 1029745cd3c5Smaybee * ds will be closed and caller can no longer dereference it. 10303cb34c60Sahrens */ 1031fa9e4066Sahrens int 1032*842727c2SChris Kirby dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) 1033fa9e4066Sahrens { 1034fa9e4066Sahrens int err; 10351d452cf5Sahrens dsl_sync_task_group_t *dstg; 10361d452cf5Sahrens objset_t *os; 1037fa9e4066Sahrens dsl_dir_t *dd; 10381d452cf5Sahrens uint64_t obj; 1039*842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 1040*842727c2SChris Kirby 1041*842727c2SChris Kirby dsda.ds = ds; 10421d452cf5Sahrens 10433cb34c60Sahrens if (dsl_dataset_is_snapshot(ds)) { 10441d452cf5Sahrens /* Destroying a snapshot is simpler */ 1045745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 10463baa08fcSek 10473baa08fcSek if (ds->ds_user_ptr) { 10483baa08fcSek ds->ds_user_evict_func(ds, ds->ds_user_ptr); 10493baa08fcSek ds->ds_user_ptr = NULL; 10503baa08fcSek } 1051*842727c2SChris Kirby /* NOTE: defer is always B_FALSE for non-snapshots */ 1052*842727c2SChris Kirby dsda.defer = defer; 10531d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 10541d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 1055*842727c2SChris Kirby &dsda, tag, 0); 1056*842727c2SChris Kirby ASSERT3P(dsda.rm_origin, ==, NULL); 10573cb34c60Sahrens goto out; 10581d452cf5Sahrens } 1059fa9e4066Sahrens 10601d452cf5Sahrens dd = ds->ds_dir; 1061fa9e4066Sahrens 10621d452cf5Sahrens /* 10631d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 10641d452cf5Sahrens * case we crash while freeing the objects. 10651d452cf5Sahrens */ 10661d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 10671d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 10683cb34c60Sahrens if (err) 10693cb34c60Sahrens goto out; 10703cb34c60Sahrens 10713cb34c60Sahrens err = dmu_objset_open_ds(ds, DMU_OST_ANY, &os); 10723cb34c60Sahrens if (err) 10733cb34c60Sahrens goto out; 1074fa9e4066Sahrens 10751d452cf5Sahrens /* 10761d452cf5Sahrens * remove the objects in open context, so that we won't 10771d452cf5Sahrens * have too much to do in syncing context. 10781d452cf5Sahrens */ 10796754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 10806754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 1081cdb0ab79Smaybee /* 1082cdb0ab79Smaybee * Ignore errors, if there is not enough disk space 1083cdb0ab79Smaybee * we will deal with it in dsl_dataset_destroy_sync(). 1084cdb0ab79Smaybee */ 1085cdb0ab79Smaybee (void) dmu_free_object(os, obj); 10861d452cf5Sahrens } 10871d452cf5Sahrens 108814843421SMatthew Ahrens /* 108914843421SMatthew Ahrens * We need to sync out all in-flight IO before we try to evict 109014843421SMatthew Ahrens * (the dataset evict func is trying to clear the cached entries 109114843421SMatthew Ahrens * for this dataset in the ARC). 109214843421SMatthew Ahrens */ 109314843421SMatthew Ahrens txg_wait_synced(dd->dd_pool, 0); 109414843421SMatthew Ahrens 109514843421SMatthew Ahrens /* 109614843421SMatthew Ahrens * If we managed to free all the objects in open 109714843421SMatthew Ahrens * context, the user space accounting should be zero. 109814843421SMatthew Ahrens */ 109914843421SMatthew Ahrens if (ds->ds_phys->ds_bp.blk_fill == 0 && 110014843421SMatthew Ahrens dmu_objset_userused_enabled(os->os)) { 110114843421SMatthew Ahrens uint64_t count; 110214843421SMatthew Ahrens 110314843421SMatthew Ahrens ASSERT(zap_count(os, DMU_USERUSED_OBJECT, &count) != 0 || 110414843421SMatthew Ahrens count == 0); 110514843421SMatthew Ahrens ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, &count) != 0 || 110614843421SMatthew Ahrens count == 0); 110714843421SMatthew Ahrens } 110814843421SMatthew Ahrens 11091d452cf5Sahrens dmu_objset_close(os); 11101d452cf5Sahrens if (err != ESRCH) 11113cb34c60Sahrens goto out; 11121d452cf5Sahrens 111368038c2cSmaybee rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 111468038c2cSmaybee err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd); 111568038c2cSmaybee rw_exit(&dd->dd_pool->dp_config_rwlock); 111668038c2cSmaybee 111768038c2cSmaybee if (err) 111868038c2cSmaybee goto out; 111968038c2cSmaybee 11203cb34c60Sahrens if (ds->ds_user_ptr) { 1121745cd3c5Smaybee /* 1122745cd3c5Smaybee * We need to sync out all in-flight IO before we try 1123745cd3c5Smaybee * to evict (the dataset evict func is trying to clear 1124745cd3c5Smaybee * the cached entries for this dataset in the ARC). 1125745cd3c5Smaybee */ 1126745cd3c5Smaybee txg_wait_synced(dd->dd_pool, 0); 11271d452cf5Sahrens } 11281d452cf5Sahrens 11291d452cf5Sahrens /* 11301d452cf5Sahrens * Blow away the dsl_dir + head dataset. 11311d452cf5Sahrens */ 1132745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 113368038c2cSmaybee if (ds->ds_user_ptr) { 113468038c2cSmaybee ds->ds_user_evict_func(ds, ds->ds_user_ptr); 113568038c2cSmaybee ds->ds_user_ptr = NULL; 113668038c2cSmaybee } 1137*842727c2SChris Kirby 1138*842727c2SChris Kirby /* 1139*842727c2SChris Kirby * If we're removing a clone, we might also need to remove its 1140*842727c2SChris Kirby * origin. 1141*842727c2SChris Kirby */ 1142*842727c2SChris Kirby do { 1143*842727c2SChris Kirby dsda.need_prep = B_FALSE; 1144*842727c2SChris Kirby if (dsl_dir_is_clone(dd)) { 1145*842727c2SChris Kirby err = dsl_dataset_origin_rm_prep(&dsda, tag); 1146*842727c2SChris Kirby if (err) { 1147*842727c2SChris Kirby dsl_dir_close(dd, FTAG); 1148*842727c2SChris Kirby goto out; 1149*842727c2SChris Kirby } 1150*842727c2SChris Kirby } 1151*842727c2SChris Kirby 1152*842727c2SChris Kirby dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 1153*842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 1154*842727c2SChris Kirby dsl_dataset_destroy_sync, &dsda, tag, 0); 1155*842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dir_destroy_check, 1156*842727c2SChris Kirby dsl_dir_destroy_sync, dd, FTAG, 0); 1157*842727c2SChris Kirby err = dsl_sync_task_group_wait(dstg); 1158*842727c2SChris Kirby dsl_sync_task_group_destroy(dstg); 1159*842727c2SChris Kirby 1160*842727c2SChris Kirby /* 1161*842727c2SChris Kirby * We could be racing against 'zfs release' or 'zfs destroy -d' 1162*842727c2SChris Kirby * on the origin snap, in which case we can get EBUSY if we 1163*842727c2SChris Kirby * needed to destroy the origin snap but were not ready to 1164*842727c2SChris Kirby * do so. 1165*842727c2SChris Kirby */ 1166*842727c2SChris Kirby if (dsda.need_prep) { 1167*842727c2SChris Kirby ASSERT(err == EBUSY); 1168*842727c2SChris Kirby ASSERT(dsl_dir_is_clone(dd)); 1169*842727c2SChris Kirby ASSERT(dsda.rm_origin == NULL); 1170*842727c2SChris Kirby } 1171*842727c2SChris Kirby } while (dsda.need_prep); 1172*842727c2SChris Kirby 1173*842727c2SChris Kirby if (dsda.rm_origin != NULL) 1174*842727c2SChris Kirby dsl_dataset_disown(dsda.rm_origin, tag); 1175*842727c2SChris Kirby 1176745cd3c5Smaybee /* if it is successful, dsl_dir_destroy_sync will close the dd */ 11773cb34c60Sahrens if (err) 11781d452cf5Sahrens dsl_dir_close(dd, FTAG); 11793cb34c60Sahrens out: 1180745cd3c5Smaybee dsl_dataset_disown(ds, tag); 1181fa9e4066Sahrens return (err); 1182fa9e4066Sahrens } 1183fa9e4066Sahrens 11841d452cf5Sahrens int 11853cb34c60Sahrens dsl_dataset_rollback(dsl_dataset_t *ds, dmu_objset_type_t ost) 11861d452cf5Sahrens { 11871c8564a7SMark Maybee int err; 11881c8564a7SMark Maybee 1189745cd3c5Smaybee ASSERT(ds->ds_owner); 11903cb34c60Sahrens 11911c8564a7SMark Maybee dsl_dataset_make_exclusive(ds, ds->ds_owner); 11921c8564a7SMark Maybee err = dsl_sync_task_do(ds->ds_dir->dd_pool, 11931d452cf5Sahrens dsl_dataset_rollback_check, dsl_dataset_rollback_sync, 11941c8564a7SMark Maybee ds, &ost, 0); 11951c8564a7SMark Maybee /* drop exclusive access */ 11961c8564a7SMark Maybee mutex_enter(&ds->ds_lock); 11971c8564a7SMark Maybee rw_exit(&ds->ds_rwlock); 11981c8564a7SMark Maybee cv_broadcast(&ds->ds_exclusive_cv); 11991c8564a7SMark Maybee mutex_exit(&ds->ds_lock); 12001c8564a7SMark Maybee return (err); 12011d452cf5Sahrens } 12021d452cf5Sahrens 1203fa9e4066Sahrens void * 1204fa9e4066Sahrens dsl_dataset_set_user_ptr(dsl_dataset_t *ds, 1205fa9e4066Sahrens void *p, dsl_dataset_evict_func_t func) 1206fa9e4066Sahrens { 1207fa9e4066Sahrens void *old; 1208fa9e4066Sahrens 1209fa9e4066Sahrens mutex_enter(&ds->ds_lock); 1210fa9e4066Sahrens old = ds->ds_user_ptr; 1211fa9e4066Sahrens if (old == NULL) { 1212fa9e4066Sahrens ds->ds_user_ptr = p; 1213fa9e4066Sahrens ds->ds_user_evict_func = func; 1214fa9e4066Sahrens } 1215fa9e4066Sahrens mutex_exit(&ds->ds_lock); 1216fa9e4066Sahrens return (old); 1217fa9e4066Sahrens } 1218fa9e4066Sahrens 1219fa9e4066Sahrens void * 1220fa9e4066Sahrens dsl_dataset_get_user_ptr(dsl_dataset_t *ds) 1221fa9e4066Sahrens { 1222fa9e4066Sahrens return (ds->ds_user_ptr); 1223fa9e4066Sahrens } 1224fa9e4066Sahrens 1225c717a561Smaybee blkptr_t * 1226c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 1227fa9e4066Sahrens { 1228c717a561Smaybee return (&ds->ds_phys->ds_bp); 1229fa9e4066Sahrens } 1230fa9e4066Sahrens 1231fa9e4066Sahrens void 1232fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 1233fa9e4066Sahrens { 1234fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1235fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 1236fa9e4066Sahrens if (ds == NULL) { 1237fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 1238fa9e4066Sahrens } else { 1239fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1240fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 1241fa9e4066Sahrens } 1242fa9e4066Sahrens } 1243fa9e4066Sahrens 1244fa9e4066Sahrens spa_t * 1245fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 1246fa9e4066Sahrens { 1247fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 1248fa9e4066Sahrens } 1249fa9e4066Sahrens 1250fa9e4066Sahrens void 1251fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 1252fa9e4066Sahrens { 1253fa9e4066Sahrens dsl_pool_t *dp; 1254fa9e4066Sahrens 1255fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 1256fa9e4066Sahrens return; 1257fa9e4066Sahrens 1258fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 1259a2eea2e1Sahrens 1260a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1261a2eea2e1Sahrens panic("dirtying snapshot!"); 1262fa9e4066Sahrens 1263fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 1264fa9e4066Sahrens 1265fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 1266fa9e4066Sahrens /* up the hold count until we can be written out */ 1267fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 1268fa9e4066Sahrens } 1269fa9e4066Sahrens } 1270fa9e4066Sahrens 1271a9799022Sck /* 1272a9799022Sck * The unique space in the head dataset can be calculated by subtracting 1273a9799022Sck * the space used in the most recent snapshot, that is still being used 1274a9799022Sck * in this file system, from the space currently in use. To figure out 1275a9799022Sck * the space in the most recent snapshot still in use, we need to take 1276a9799022Sck * the total space used in the snapshot and subtract out the space that 1277a9799022Sck * has been freed up since the snapshot was taken. 1278a9799022Sck */ 1279a9799022Sck static void 1280a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds) 1281a9799022Sck { 1282a9799022Sck uint64_t mrs_used; 1283a9799022Sck uint64_t dlused, dlcomp, dluncomp; 1284a9799022Sck 1285a9799022Sck ASSERT(ds->ds_object == ds->ds_dir->dd_phys->dd_head_dataset_obj); 1286a9799022Sck 1287a9799022Sck if (ds->ds_phys->ds_prev_snap_obj != 0) 1288a9799022Sck mrs_used = ds->ds_prev->ds_phys->ds_used_bytes; 1289a9799022Sck else 1290a9799022Sck mrs_used = 0; 1291a9799022Sck 1292a9799022Sck VERIFY(0 == bplist_space(&ds->ds_deadlist, &dlused, &dlcomp, 1293a9799022Sck &dluncomp)); 1294a9799022Sck 1295a9799022Sck ASSERT3U(dlused, <=, mrs_used); 1296a9799022Sck ds->ds_phys->ds_unique_bytes = 1297a9799022Sck ds->ds_phys->ds_used_bytes - (mrs_used - dlused); 1298a9799022Sck 1299a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && 1300a9799022Sck spa_version(ds->ds_dir->dd_pool->dp_spa) >= 1301a9799022Sck SPA_VERSION_UNIQUE_ACCURATE) 1302a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1303a9799022Sck } 1304a9799022Sck 1305a9799022Sck static uint64_t 1306a9799022Sck dsl_dataset_unique(dsl_dataset_t *ds) 1307a9799022Sck { 1308a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && !dsl_dataset_is_snapshot(ds)) 1309a9799022Sck dsl_dataset_recalc_head_uniq(ds); 1310a9799022Sck 1311a9799022Sck return (ds->ds_phys->ds_unique_bytes); 1312a9799022Sck } 1313a9799022Sck 1314fa9e4066Sahrens struct killarg { 131574e7dc98SMatthew Ahrens dsl_dataset_t *ds; 1316fa9e4066Sahrens zio_t *zio; 1317fa9e4066Sahrens dmu_tx_t *tx; 1318fa9e4066Sahrens }; 1319fa9e4066Sahrens 132074e7dc98SMatthew Ahrens /* ARGSUSED */ 1321fa9e4066Sahrens static int 132288b7b0f2SMatthew Ahrens kill_blkptr(spa_t *spa, blkptr_t *bp, const zbookmark_t *zb, 132388b7b0f2SMatthew Ahrens const dnode_phys_t *dnp, void *arg) 1324fa9e4066Sahrens { 1325fa9e4066Sahrens struct killarg *ka = arg; 1326fa9e4066Sahrens 132788b7b0f2SMatthew Ahrens if (bp == NULL) 132888b7b0f2SMatthew Ahrens return (0); 1329fa9e4066Sahrens 1330ab69d62fSMatthew Ahrens if ((zb->zb_level == -1ULL && zb->zb_blkid != 0) || 1331ab69d62fSMatthew Ahrens (zb->zb_object != 0 && dnp == NULL)) { 1332ab69d62fSMatthew Ahrens /* 1333ab69d62fSMatthew Ahrens * It's a block in the intent log. It has no 1334ab69d62fSMatthew Ahrens * accounting, so just free it. 1335ab69d62fSMatthew Ahrens */ 1336ab69d62fSMatthew Ahrens VERIFY3U(0, ==, dsl_free(ka->zio, ka->tx->tx_pool, 1337ab69d62fSMatthew Ahrens ka->tx->tx_txg, bp, NULL, NULL, ARC_NOWAIT)); 1338ab69d62fSMatthew Ahrens } else { 1339ab69d62fSMatthew Ahrens ASSERT3U(bp->blk_birth, >, ka->ds->ds_phys->ds_prev_snap_txg); 1340ab69d62fSMatthew Ahrens (void) dsl_dataset_block_kill(ka->ds, bp, ka->zio, ka->tx); 1341ab69d62fSMatthew Ahrens } 134274e7dc98SMatthew Ahrens 1343fa9e4066Sahrens return (0); 1344fa9e4066Sahrens } 1345fa9e4066Sahrens 1346fa9e4066Sahrens /* ARGSUSED */ 13471d452cf5Sahrens static int 13481d452cf5Sahrens dsl_dataset_rollback_check(void *arg1, void *arg2, dmu_tx_t *tx) 1349fa9e4066Sahrens { 13501d452cf5Sahrens dsl_dataset_t *ds = arg1; 13513cb34c60Sahrens dmu_objset_type_t *ost = arg2; 1352fa9e4066Sahrens 13531d452cf5Sahrens /* 13543cb34c60Sahrens * We can only roll back to emptyness if it is a ZPL objset. 13551d452cf5Sahrens */ 1356e3053a4bSEric Taylor if (*ost != DMU_OST_ZFS && 1357e3053a4bSEric Taylor ds->ds_phys->ds_prev_snap_txg < TXG_INITIAL) 1358fa9e4066Sahrens return (EINVAL); 1359fa9e4066Sahrens 13601d452cf5Sahrens /* 13611d452cf5Sahrens * This must not be a snapshot. 13621d452cf5Sahrens */ 13631d452cf5Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1364fa9e4066Sahrens return (EINVAL); 1365fa9e4066Sahrens 1366fa9e4066Sahrens /* 136788b7b0f2SMatthew Ahrens * If we made changes this txg, traverse_dataset won't find 1368fa9e4066Sahrens * them. Try again. 1369fa9e4066Sahrens */ 13701d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1371fa9e4066Sahrens return (EAGAIN); 1372fa9e4066Sahrens 13731d452cf5Sahrens return (0); 13741d452cf5Sahrens } 13751d452cf5Sahrens 13761d452cf5Sahrens /* ARGSUSED */ 13771d452cf5Sahrens static void 1378ecd6cf80Smarks dsl_dataset_rollback_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 13791d452cf5Sahrens { 13801d452cf5Sahrens dsl_dataset_t *ds = arg1; 13813cb34c60Sahrens dmu_objset_type_t *ost = arg2; 13821d452cf5Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1383fa9e4066Sahrens 1384fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1385fa9e4066Sahrens 138686ccc033Sperrin if (ds->ds_user_ptr != NULL) { 13873cb34c60Sahrens /* 13883cb34c60Sahrens * We need to make sure that the objset_impl_t is reopened after 13893cb34c60Sahrens * we do the rollback, otherwise it will have the wrong 13903cb34c60Sahrens * objset_phys_t. Normally this would happen when this 1391745cd3c5Smaybee * dataset-open is closed, thus causing the 13923cb34c60Sahrens * dataset to be immediately evicted. But when doing "zfs recv 13933cb34c60Sahrens * -F", we reopen the objset before that, so that there is no 13943cb34c60Sahrens * window where the dataset is closed and inconsistent. 13953cb34c60Sahrens */ 13963cb34c60Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 13973cb34c60Sahrens ds->ds_user_ptr = NULL; 139886ccc033Sperrin } 13993a8a1de4Sperrin 140074e7dc98SMatthew Ahrens /* Transfer space that was freed since last snap back to the head. */ 140174e7dc98SMatthew Ahrens { 140274e7dc98SMatthew Ahrens uint64_t used; 140374e7dc98SMatthew Ahrens 140474e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&ds->ds_deadlist, 140574e7dc98SMatthew Ahrens ds->ds_origin_txg, UINT64_MAX, &used)); 140674e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used, 140774e7dc98SMatthew Ahrens DD_USED_SNAP, DD_USED_HEAD, tx); 140874e7dc98SMatthew Ahrens } 140974e7dc98SMatthew Ahrens 1410fa9e4066Sahrens /* Zero out the deadlist. */ 1411fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1412fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1413fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1414fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1415ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1416ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1417fa9e4066Sahrens 1418fa9e4066Sahrens { 1419ab69d62fSMatthew Ahrens /* 1420ab69d62fSMatthew Ahrens * Free blkptrs that we gave birth to - this covers 1421ab69d62fSMatthew Ahrens * claimed but not played log blocks too. 1422ab69d62fSMatthew Ahrens */ 1423fa9e4066Sahrens zio_t *zio; 1424fa9e4066Sahrens struct killarg ka; 1425fa9e4066Sahrens 1426fa9e4066Sahrens zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL, 1427fa9e4066Sahrens ZIO_FLAG_MUSTSUCCEED); 142874e7dc98SMatthew Ahrens ka.ds = ds; 1429fa9e4066Sahrens ka.zio = zio; 1430fa9e4066Sahrens ka.tx = tx; 143188b7b0f2SMatthew Ahrens (void) traverse_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 143288b7b0f2SMatthew Ahrens TRAVERSE_POST, kill_blkptr, &ka); 1433fa9e4066Sahrens (void) zio_wait(zio); 1434fa9e4066Sahrens } 1435fa9e4066Sahrens 14363e78c5fbSChris Kirby ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || ds->ds_phys->ds_unique_bytes == 0); 143774e7dc98SMatthew Ahrens 1438088f3894Sahrens if (ds->ds_prev && ds->ds_prev != ds->ds_dir->dd_pool->dp_origin_snap) { 14393cb34c60Sahrens /* Change our contents to that of the prev snapshot */ 144074e7dc98SMatthew Ahrens 14413cb34c60Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, 14423cb34c60Sahrens ds->ds_phys->ds_prev_snap_obj); 144374e7dc98SMatthew Ahrens ASSERT3U(ds->ds_phys->ds_used_bytes, <=, 144474e7dc98SMatthew Ahrens ds->ds_prev->ds_phys->ds_used_bytes); 144574e7dc98SMatthew Ahrens 14463cb34c60Sahrens ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp; 14473cb34c60Sahrens ds->ds_phys->ds_used_bytes = 14483cb34c60Sahrens ds->ds_prev->ds_phys->ds_used_bytes; 14493cb34c60Sahrens ds->ds_phys->ds_compressed_bytes = 14503cb34c60Sahrens ds->ds_prev->ds_phys->ds_compressed_bytes; 14513cb34c60Sahrens ds->ds_phys->ds_uncompressed_bytes = 14523cb34c60Sahrens ds->ds_prev->ds_phys->ds_uncompressed_bytes; 14533cb34c60Sahrens ds->ds_phys->ds_flags = ds->ds_prev->ds_phys->ds_flags; 1454fa9e4066Sahrens 14553cb34c60Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 14563cb34c60Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 14573cb34c60Sahrens ds->ds_prev->ds_phys->ds_unique_bytes = 0; 14583cb34c60Sahrens } 14593cb34c60Sahrens } else { 1460088f3894Sahrens objset_impl_t *osi; 1461088f3894Sahrens 1462e3053a4bSEric Taylor ASSERT(*ost != DMU_OST_ZVOL); 146374e7dc98SMatthew Ahrens ASSERT3U(ds->ds_phys->ds_used_bytes, ==, 0); 146474e7dc98SMatthew Ahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, ==, 0); 146574e7dc98SMatthew Ahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, ==, 0); 146674e7dc98SMatthew Ahrens 14673cb34c60Sahrens bzero(&ds->ds_phys->ds_bp, sizeof (blkptr_t)); 14683cb34c60Sahrens ds->ds_phys->ds_flags = 0; 14693cb34c60Sahrens ds->ds_phys->ds_unique_bytes = 0; 147074e7dc98SMatthew Ahrens if (spa_version(ds->ds_dir->dd_pool->dp_spa) >= 147174e7dc98SMatthew Ahrens SPA_VERSION_UNIQUE_ACCURATE) 147274e7dc98SMatthew Ahrens ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 147374e7dc98SMatthew Ahrens 1474088f3894Sahrens osi = dmu_objset_create_impl(ds->ds_dir->dd_pool->dp_spa, ds, 14753cb34c60Sahrens &ds->ds_phys->ds_bp, *ost, tx); 1476088f3894Sahrens #ifdef _KERNEL 1477088f3894Sahrens zfs_create_fs(&osi->os, kcred, NULL, tx); 1478088f3894Sahrens #endif 147985edac42Sahrens } 1480ecd6cf80Smarks 1481ecd6cf80Smarks spa_history_internal_log(LOG_DS_ROLLBACK, ds->ds_dir->dd_pool->dp_spa, 1482ecd6cf80Smarks tx, cr, "dataset = %llu", ds->ds_object); 1483fa9e4066Sahrens } 1484fa9e4066Sahrens 1485e1930233Sbonwick /* ARGSUSED */ 1486e1930233Sbonwick static int 14871d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1488e1930233Sbonwick { 14891d452cf5Sahrens dsl_dataset_t *ds = arg1; 14903cb34c60Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 14913cb34c60Sahrens uint64_t count; 14923cb34c60Sahrens int err; 1493e1930233Sbonwick 1494e1930233Sbonwick /* 1495e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1496e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1497e1930233Sbonwick * from.) 1498e1930233Sbonwick */ 1499e1930233Sbonwick if (ds->ds_prev != NULL && 1500e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1501e1930233Sbonwick return (EINVAL); 1502e1930233Sbonwick 15033cb34c60Sahrens /* 15043cb34c60Sahrens * This is really a dsl_dir thing, but check it here so that 15053cb34c60Sahrens * we'll be less likely to leave this dataset inconsistent & 15063cb34c60Sahrens * nearly destroyed. 15073cb34c60Sahrens */ 15083cb34c60Sahrens err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count); 15093cb34c60Sahrens if (err) 15103cb34c60Sahrens return (err); 15113cb34c60Sahrens if (count != 0) 15123cb34c60Sahrens return (EEXIST); 15133cb34c60Sahrens 1514e1930233Sbonwick return (0); 1515e1930233Sbonwick } 1516e1930233Sbonwick 15171d452cf5Sahrens /* ARGSUSED */ 15181d452cf5Sahrens static void 1519ecd6cf80Smarks dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 1520fa9e4066Sahrens { 15211d452cf5Sahrens dsl_dataset_t *ds = arg1; 1522ecd6cf80Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1523fa9e4066Sahrens 15241d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 15251d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 15261d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1527ecd6cf80Smarks 1528ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 1529ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 15301d452cf5Sahrens } 1531fa9e4066Sahrens 1532*842727c2SChris Kirby static int 1533*842727c2SChris Kirby dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag, 1534*842727c2SChris Kirby dmu_tx_t *tx) 1535*842727c2SChris Kirby { 1536*842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1537*842727c2SChris Kirby dsl_dataset_t *ds_prev = ds->ds_prev; 1538*842727c2SChris Kirby 1539*842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(ds_prev)) { 1540*842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1541*842727c2SChris Kirby 1542*842727c2SChris Kirby /* 1543*842727c2SChris Kirby * If we're not prepared to remove the origin, don't remove 1544*842727c2SChris Kirby * the clone either. 1545*842727c2SChris Kirby */ 1546*842727c2SChris Kirby if (dsda->rm_origin == NULL) { 1547*842727c2SChris Kirby dsda->need_prep = B_TRUE; 1548*842727c2SChris Kirby return (EBUSY); 1549*842727c2SChris Kirby } 1550*842727c2SChris Kirby 1551*842727c2SChris Kirby ndsda.ds = ds_prev; 1552*842727c2SChris Kirby ndsda.is_origin_rm = B_TRUE; 1553*842727c2SChris Kirby return (dsl_dataset_destroy_check(&ndsda, tag, tx)); 1554*842727c2SChris Kirby } 1555*842727c2SChris Kirby 1556*842727c2SChris Kirby /* 1557*842727c2SChris Kirby * If we're not going to remove the origin after all, 1558*842727c2SChris Kirby * undo the open context setup. 1559*842727c2SChris Kirby */ 1560*842727c2SChris Kirby if (dsda->rm_origin != NULL) { 1561*842727c2SChris Kirby dsl_dataset_disown(dsda->rm_origin, tag); 1562*842727c2SChris Kirby dsda->rm_origin = NULL; 1563*842727c2SChris Kirby } 1564*842727c2SChris Kirby 1565*842727c2SChris Kirby return (0); 1566*842727c2SChris Kirby } 1567*842727c2SChris Kirby 15681d452cf5Sahrens /* ARGSUSED */ 15693cb34c60Sahrens int 15701d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 15711d452cf5Sahrens { 1572*842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1573*842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1574fa9e4066Sahrens 1575745cd3c5Smaybee /* we have an owner hold, so noone else can destroy us */ 1576745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 1577745cd3c5Smaybee 1578*842727c2SChris Kirby /* 1579*842727c2SChris Kirby * Only allow deferred destroy on pools that support it. 1580*842727c2SChris Kirby * NOTE: deferred destroy is only supported on snapshots. 1581*842727c2SChris Kirby */ 1582*842727c2SChris Kirby if (dsda->defer) { 1583*842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 1584*842727c2SChris Kirby SPA_VERSION_USERREFS) 1585*842727c2SChris Kirby return (ENOTSUP); 1586*842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 1587*842727c2SChris Kirby return (0); 1588*842727c2SChris Kirby } 1589fa9e4066Sahrens 1590fa9e4066Sahrens /* 1591fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1592fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1593fa9e4066Sahrens * from.) 1594fa9e4066Sahrens */ 1595fa9e4066Sahrens if (ds->ds_prev != NULL && 15961d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1597fa9e4066Sahrens return (EINVAL); 1598fa9e4066Sahrens 1599fa9e4066Sahrens /* 1600fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1601fa9e4066Sahrens * them. Try again. 1602fa9e4066Sahrens */ 16031d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1604fa9e4066Sahrens return (EAGAIN); 16051d452cf5Sahrens 1606*842727c2SChris Kirby if (dsl_dataset_is_snapshot(ds)) { 1607*842727c2SChris Kirby /* 1608*842727c2SChris Kirby * If this snapshot has an elevated user reference count, 1609*842727c2SChris Kirby * we can't destroy it yet. 1610*842727c2SChris Kirby */ 1611*842727c2SChris Kirby if (ds->ds_userrefs > 0 && !dsda->releasing) 1612*842727c2SChris Kirby return (EBUSY); 1613*842727c2SChris Kirby 1614*842727c2SChris Kirby mutex_enter(&ds->ds_lock); 1615*842727c2SChris Kirby /* 1616*842727c2SChris Kirby * Can't delete a branch point. However, if we're destroying 1617*842727c2SChris Kirby * a clone and removing its origin due to it having a user 1618*842727c2SChris Kirby * hold count of 0 and having been marked for deferred destroy, 1619*842727c2SChris Kirby * it's OK for the origin to have a single clone. 1620*842727c2SChris Kirby */ 1621*842727c2SChris Kirby if (ds->ds_phys->ds_num_children > 1622*842727c2SChris Kirby (dsda->is_origin_rm ? 2 : 1)) { 1623*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1624*842727c2SChris Kirby return (EEXIST); 1625*842727c2SChris Kirby } 1626*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1627*842727c2SChris Kirby } else if (dsl_dir_is_clone(ds->ds_dir)) { 1628*842727c2SChris Kirby return (dsl_dataset_origin_check(dsda, arg2, tx)); 1629*842727c2SChris Kirby } 1630*842727c2SChris Kirby 16311d452cf5Sahrens /* XXX we should do some i/o error checking... */ 16321d452cf5Sahrens return (0); 16331d452cf5Sahrens } 16341d452cf5Sahrens 1635745cd3c5Smaybee struct refsarg { 1636745cd3c5Smaybee kmutex_t lock; 1637745cd3c5Smaybee boolean_t gone; 1638745cd3c5Smaybee kcondvar_t cv; 1639745cd3c5Smaybee }; 1640745cd3c5Smaybee 1641745cd3c5Smaybee /* ARGSUSED */ 1642745cd3c5Smaybee static void 1643745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv) 1644745cd3c5Smaybee { 1645745cd3c5Smaybee struct refsarg *arg = argv; 1646745cd3c5Smaybee 1647745cd3c5Smaybee mutex_enter(&arg->lock); 1648745cd3c5Smaybee arg->gone = TRUE; 1649745cd3c5Smaybee cv_signal(&arg->cv); 1650745cd3c5Smaybee mutex_exit(&arg->lock); 1651745cd3c5Smaybee } 1652745cd3c5Smaybee 1653745cd3c5Smaybee static void 1654745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag) 1655745cd3c5Smaybee { 1656745cd3c5Smaybee struct refsarg arg; 1657745cd3c5Smaybee 1658745cd3c5Smaybee mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL); 1659745cd3c5Smaybee cv_init(&arg.cv, NULL, CV_DEFAULT, NULL); 1660745cd3c5Smaybee arg.gone = FALSE; 1661745cd3c5Smaybee (void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys, 1662745cd3c5Smaybee dsl_dataset_refs_gone); 1663745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 1664745cd3c5Smaybee mutex_enter(&arg.lock); 1665745cd3c5Smaybee while (!arg.gone) 1666745cd3c5Smaybee cv_wait(&arg.cv, &arg.lock); 1667745cd3c5Smaybee ASSERT(arg.gone); 1668745cd3c5Smaybee mutex_exit(&arg.lock); 1669745cd3c5Smaybee ds->ds_dbuf = NULL; 1670745cd3c5Smaybee ds->ds_phys = NULL; 1671745cd3c5Smaybee mutex_destroy(&arg.lock); 1672745cd3c5Smaybee cv_destroy(&arg.cv); 1673745cd3c5Smaybee } 1674745cd3c5Smaybee 16753cb34c60Sahrens void 1676ecd6cf80Smarks dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 16771d452cf5Sahrens { 1678*842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1679*842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 16801d452cf5Sahrens zio_t *zio; 16811d452cf5Sahrens int err; 16821d452cf5Sahrens int after_branch_point = FALSE; 16831d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 16841d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 16851d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 16861d452cf5Sahrens uint64_t obj; 16871d452cf5Sahrens 1688745cd3c5Smaybee ASSERT(ds->ds_owner); 1689*842727c2SChris Kirby ASSERT(dsda->defer || ds->ds_phys->ds_num_children <= 1); 16901d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 16911d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 16921d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 16931d452cf5Sahrens 1694*842727c2SChris Kirby if (dsda->defer) { 1695*842727c2SChris Kirby ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 1696*842727c2SChris Kirby if (ds->ds_userrefs > 0 || ds->ds_phys->ds_num_children > 1) { 1697*842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 1698*842727c2SChris Kirby ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY; 1699*842727c2SChris Kirby return; 1700*842727c2SChris Kirby } 1701*842727c2SChris Kirby } 1702*842727c2SChris Kirby 1703745cd3c5Smaybee /* signal any waiters that this dataset is going away */ 1704745cd3c5Smaybee mutex_enter(&ds->ds_lock); 1705745cd3c5Smaybee ds->ds_owner = dsl_reaper; 1706745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 1707745cd3c5Smaybee mutex_exit(&ds->ds_lock); 1708745cd3c5Smaybee 1709a9799022Sck /* Remove our reservation */ 1710a9799022Sck if (ds->ds_reserved != 0) { 1711a9799022Sck uint64_t val = 0; 1712a9799022Sck dsl_dataset_set_reservation_sync(ds, &val, cr, tx); 1713a9799022Sck ASSERT3U(ds->ds_reserved, ==, 0); 1714a9799022Sck } 1715a9799022Sck 17161d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 17171d452cf5Sahrens 1718088f3894Sahrens dsl_pool_ds_destroyed(ds, tx); 1719088f3894Sahrens 17201d452cf5Sahrens obj = ds->ds_object; 1721fa9e4066Sahrens 1722fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1723fa9e4066Sahrens if (ds->ds_prev) { 1724fa9e4066Sahrens ds_prev = ds->ds_prev; 1725fa9e4066Sahrens } else { 1726745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1727745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev)); 1728fa9e4066Sahrens } 1729fa9e4066Sahrens after_branch_point = 1730fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1731fa9e4066Sahrens 1732fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1733088f3894Sahrens if (after_branch_point && 1734088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj != 0) { 173514843421SMatthew Ahrens VERIFY3U(0, ==, zap_remove_int(mos, 1736088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, obj, tx)); 1737088f3894Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1738088f3894Sahrens VERIFY(0 == zap_add_int(mos, 1739088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, 1740088f3894Sahrens ds->ds_phys->ds_next_snap_obj, tx)); 1741088f3894Sahrens } 1742088f3894Sahrens } 1743fa9e4066Sahrens if (after_branch_point && 1744fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1745fa9e4066Sahrens /* This clone is toast. */ 1746fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1747fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1748*842727c2SChris Kirby 1749*842727c2SChris Kirby /* 1750*842727c2SChris Kirby * If the clone's origin has no other clones, no 1751*842727c2SChris Kirby * user holds, and has been marked for deferred 1752*842727c2SChris Kirby * deletion, then we should have done the necessary 1753*842727c2SChris Kirby * destroy setup for it. 1754*842727c2SChris Kirby */ 1755*842727c2SChris Kirby if (ds_prev->ds_phys->ds_num_children == 1 && 1756*842727c2SChris Kirby ds_prev->ds_userrefs == 0 && 1757*842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds_prev)) { 1758*842727c2SChris Kirby ASSERT3P(dsda->rm_origin, !=, NULL); 1759*842727c2SChris Kirby } else { 1760*842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 1761*842727c2SChris Kirby } 1762fa9e4066Sahrens } else if (!after_branch_point) { 1763fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1764fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1765fa9e4066Sahrens } 1766fa9e4066Sahrens } 1767fa9e4066Sahrens 1768fa9e4066Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1769fa9e4066Sahrens 1770fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 17711d452cf5Sahrens blkptr_t bp; 1772fa9e4066Sahrens dsl_dataset_t *ds_next; 1773fa9e4066Sahrens uint64_t itor = 0; 1774a9799022Sck uint64_t old_unique; 177574e7dc98SMatthew Ahrens int64_t used = 0, compressed = 0, uncompressed = 0; 1776fa9e4066Sahrens 1777745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1778745cd3c5Smaybee ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next)); 1779fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1780fa9e4066Sahrens 1781a9799022Sck old_unique = dsl_dataset_unique(ds_next); 1782a9799022Sck 1783fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1784fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1785fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1786fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1787fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1788fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1789fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1790fa9e4066Sahrens 1791fa9e4066Sahrens /* 1792fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1793fa9e4066Sahrens * new deadlist) any entries from next's current 1794fa9e4066Sahrens * deadlist which were born before prev, and free the 1795fa9e4066Sahrens * other entries. 1796fa9e4066Sahrens * 1797fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1798fa9e4066Sahrens */ 1799745cd3c5Smaybee while (bplist_iterate(&ds_next->ds_deadlist, &itor, &bp) == 0) { 1800fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1801ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1802ea8dc4b6Seschrock &bp, tx)); 1803fa9e4066Sahrens if (ds_prev && !after_branch_point && 1804fa9e4066Sahrens bp.blk_birth > 1805fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1806fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 180799653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1808fa9e4066Sahrens } 1809fa9e4066Sahrens } else { 181099653d4eSeschrock used += bp_get_dasize(dp->dp_spa, &bp); 1811fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1812fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1813fa9e4066Sahrens /* XXX check return value? */ 1814088f3894Sahrens (void) dsl_free(zio, dp, tx->tx_txg, 1815fa9e4066Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1816fa9e4066Sahrens } 1817fa9e4066Sahrens } 1818fa9e4066Sahrens 181974e7dc98SMatthew Ahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 182074e7dc98SMatthew Ahrens 182174e7dc98SMatthew Ahrens /* change snapused */ 182274e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 182374e7dc98SMatthew Ahrens -used, -compressed, -uncompressed, tx); 182474e7dc98SMatthew Ahrens 1825fa9e4066Sahrens /* free next's deadlist */ 1826fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1827fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1828fa9e4066Sahrens 1829fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1830745cd3c5Smaybee bplist_close(&ds->ds_deadlist); 1831fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1832fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1833ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1834ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1835fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1836fa9e4066Sahrens 1837fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1838fa9e4066Sahrens /* 1839fa9e4066Sahrens * Update next's unique to include blocks which 1840fa9e4066Sahrens * were previously shared by only this snapshot 1841fa9e4066Sahrens * and it. Those blocks will be born after the 1842fa9e4066Sahrens * prev snap and before this snap, and will have 1843fa9e4066Sahrens * died after the next snap and before the one 1844fa9e4066Sahrens * after that (ie. be on the snap after next's 1845fa9e4066Sahrens * deadlist). 1846fa9e4066Sahrens * 1847fa9e4066Sahrens * XXX we're doing this long task with the 1848fa9e4066Sahrens * config lock held 1849fa9e4066Sahrens */ 1850fa9e4066Sahrens dsl_dataset_t *ds_after_next; 185174e7dc98SMatthew Ahrens uint64_t space; 1852fa9e4066Sahrens 1853745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1854745cd3c5Smaybee ds_next->ds_phys->ds_next_snap_obj, 1855745cd3c5Smaybee FTAG, &ds_after_next)); 185674e7dc98SMatthew Ahrens 185774e7dc98SMatthew Ahrens VERIFY(0 == 185874e7dc98SMatthew Ahrens bplist_space_birthrange(&ds_after_next->ds_deadlist, 185974e7dc98SMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 186074e7dc98SMatthew Ahrens ds->ds_phys->ds_creation_txg, &space)); 186174e7dc98SMatthew Ahrens ds_next->ds_phys->ds_unique_bytes += space; 1862fa9e4066Sahrens 1863745cd3c5Smaybee dsl_dataset_rele(ds_after_next, FTAG); 1864fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1865fa9e4066Sahrens } else { 1866fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1867745cd3c5Smaybee dsl_dataset_drop_ref(ds_next->ds_prev, ds_next); 1868745cd3c5Smaybee ds_next->ds_prev = NULL; 1869fa9e4066Sahrens if (ds_prev) { 1870745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1871745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 1872745cd3c5Smaybee ds_next, &ds_next->ds_prev)); 1873fa9e4066Sahrens } 1874a9799022Sck 1875a9799022Sck dsl_dataset_recalc_head_uniq(ds_next); 1876a9799022Sck 1877a9799022Sck /* 1878a9799022Sck * Reduce the amount of our unconsmed refreservation 1879a9799022Sck * being charged to our parent by the amount of 1880a9799022Sck * new unique data we have gained. 1881a9799022Sck */ 1882a9799022Sck if (old_unique < ds_next->ds_reserved) { 1883a9799022Sck int64_t mrsdelta; 1884a9799022Sck uint64_t new_unique = 1885a9799022Sck ds_next->ds_phys->ds_unique_bytes; 1886a9799022Sck 1887a9799022Sck ASSERT(old_unique <= new_unique); 1888a9799022Sck mrsdelta = MIN(new_unique - old_unique, 1889a9799022Sck ds_next->ds_reserved - old_unique); 189074e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 189174e7dc98SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 1892a9799022Sck } 1893fa9e4066Sahrens } 1894745cd3c5Smaybee dsl_dataset_rele(ds_next, FTAG); 1895fa9e4066Sahrens } else { 1896fa9e4066Sahrens /* 1897fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1898fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1899fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1900fa9e4066Sahrens * safe to ignore the deadlist contents.) 1901fa9e4066Sahrens */ 1902fa9e4066Sahrens struct killarg ka; 1903fa9e4066Sahrens 1904fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1905fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1906fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1907fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1908fa9e4066Sahrens 1909fa9e4066Sahrens /* 1910fa9e4066Sahrens * Free everything that we point to (that's born after 1911fa9e4066Sahrens * the previous snapshot, if we are a clone) 1912fa9e4066Sahrens * 191374e7dc98SMatthew Ahrens * NB: this should be very quick, because we already 191474e7dc98SMatthew Ahrens * freed all the objects in open context. 1915fa9e4066Sahrens */ 191674e7dc98SMatthew Ahrens ka.ds = ds; 1917fa9e4066Sahrens ka.zio = zio; 1918fa9e4066Sahrens ka.tx = tx; 191988b7b0f2SMatthew Ahrens err = traverse_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 192088b7b0f2SMatthew Ahrens TRAVERSE_POST, kill_blkptr, &ka); 1921fa9e4066Sahrens ASSERT3U(err, ==, 0); 19223e78c5fbSChris Kirby ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 192374e7dc98SMatthew Ahrens ds->ds_phys->ds_unique_bytes == 0); 1924fa9e4066Sahrens } 1925fa9e4066Sahrens 1926fa9e4066Sahrens err = zio_wait(zio); 1927fa9e4066Sahrens ASSERT3U(err, ==, 0); 1928fa9e4066Sahrens 19291d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1930745cd3c5Smaybee /* Erase the link in the dir */ 19311d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 19321d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1933745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0); 1934745cd3c5Smaybee err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1935745cd3c5Smaybee ASSERT(err == 0); 1936fa9e4066Sahrens } else { 1937fa9e4066Sahrens /* remove from snapshot namespace */ 1938fa9e4066Sahrens dsl_dataset_t *ds_head; 1939745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0); 1940745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1941745cd3c5Smaybee ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head)); 19428660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1943fa9e4066Sahrens #ifdef ZFS_DEBUG 1944fa9e4066Sahrens { 1945fa9e4066Sahrens uint64_t val; 1946ab04eb8eStimh 1947745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds_head, 1948ab04eb8eStimh ds->ds_snapname, &val); 1949fa9e4066Sahrens ASSERT3U(err, ==, 0); 1950fa9e4066Sahrens ASSERT3U(val, ==, obj); 1951fa9e4066Sahrens } 1952fa9e4066Sahrens #endif 1953745cd3c5Smaybee err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx); 1954fa9e4066Sahrens ASSERT(err == 0); 1955745cd3c5Smaybee dsl_dataset_rele(ds_head, FTAG); 1956fa9e4066Sahrens } 1957fa9e4066Sahrens 1958fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1959745cd3c5Smaybee dsl_dataset_rele(ds_prev, FTAG); 1960fa9e4066Sahrens 1961990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 1962ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx, 1963ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 1964ecd6cf80Smarks 1965088f3894Sahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 1966088f3894Sahrens uint64_t count; 1967088f3894Sahrens ASSERT(0 == zap_count(mos, 1968088f3894Sahrens ds->ds_phys->ds_next_clones_obj, &count) && count == 0); 1969088f3894Sahrens VERIFY(0 == dmu_object_free(mos, 1970088f3894Sahrens ds->ds_phys->ds_next_clones_obj, tx)); 1971088f3894Sahrens } 197274e7dc98SMatthew Ahrens if (ds->ds_phys->ds_props_obj != 0) 197374e7dc98SMatthew Ahrens VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_props_obj, tx)); 1974*842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) 1975*842727c2SChris Kirby VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx)); 1976745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 1977745cd3c5Smaybee ds->ds_dir = NULL; 1978745cd3c5Smaybee dsl_dataset_drain_refs(ds, tag); 19791d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1980*842727c2SChris Kirby 1981*842727c2SChris Kirby if (dsda->rm_origin) { 1982*842727c2SChris Kirby /* 1983*842727c2SChris Kirby * Remove the origin of the clone we just destroyed. 1984*842727c2SChris Kirby */ 1985*842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 1986*842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1987*842727c2SChris Kirby 1988*842727c2SChris Kirby ASSERT3P(origin, ==, dsda->rm_origin); 1989*842727c2SChris Kirby if (origin->ds_user_ptr) { 1990*842727c2SChris Kirby origin->ds_user_evict_func(origin, origin->ds_user_ptr); 1991*842727c2SChris Kirby origin->ds_user_ptr = NULL; 1992*842727c2SChris Kirby } 1993*842727c2SChris Kirby 1994*842727c2SChris Kirby dsl_dataset_rele(origin, tag); 1995*842727c2SChris Kirby ds->ds_prev = NULL; 1996*842727c2SChris Kirby 1997*842727c2SChris Kirby ndsda.ds = origin; 1998*842727c2SChris Kirby dsl_dataset_destroy_sync(&ndsda, tag, cr, tx); 1999*842727c2SChris Kirby } 2000fa9e4066Sahrens } 2001fa9e4066Sahrens 2002a9799022Sck static int 2003a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx) 2004a9799022Sck { 2005a9799022Sck uint64_t asize; 2006a9799022Sck 2007a9799022Sck if (!dmu_tx_is_syncing(tx)) 2008a9799022Sck return (0); 2009a9799022Sck 2010a9799022Sck /* 2011a9799022Sck * If there's an fs-only reservation, any blocks that might become 2012a9799022Sck * owned by the snapshot dataset must be accommodated by space 2013a9799022Sck * outside of the reservation. 2014a9799022Sck */ 2015a9799022Sck asize = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 2016a9799022Sck if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, FALSE)) 2017a9799022Sck return (ENOSPC); 2018a9799022Sck 2019a9799022Sck /* 2020a9799022Sck * Propogate any reserved space for this snapshot to other 2021a9799022Sck * snapshot checks in this sync group. 2022a9799022Sck */ 2023a9799022Sck if (asize > 0) 2024a9799022Sck dsl_dir_willuse_space(ds->ds_dir, asize, tx); 2025a9799022Sck 2026a9799022Sck return (0); 2027a9799022Sck } 2028a9799022Sck 20291d452cf5Sahrens /* ARGSUSED */ 2030fa9e4066Sahrens int 20311d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 2032fa9e4066Sahrens { 20333cb34c60Sahrens dsl_dataset_t *ds = arg1; 20341d452cf5Sahrens const char *snapname = arg2; 2035fa9e4066Sahrens int err; 20361d452cf5Sahrens uint64_t value; 2037fa9e4066Sahrens 20381d452cf5Sahrens /* 20391d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 20401d452cf5Sahrens * is already one, try again. 20411d452cf5Sahrens */ 20421d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 20431d452cf5Sahrens return (EAGAIN); 2044fa9e4066Sahrens 20451d452cf5Sahrens /* 20461d452cf5Sahrens * Check for conflicting name snapshot name. 20471d452cf5Sahrens */ 2048745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds, snapname, &value); 20491d452cf5Sahrens if (err == 0) 2050fa9e4066Sahrens return (EEXIST); 20511d452cf5Sahrens if (err != ENOENT) 20521d452cf5Sahrens return (err); 2053fa9e4066Sahrens 2054b7661cccSmmusante /* 2055b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 2056b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 2057b7661cccSmmusante */ 2058b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 2059b7661cccSmmusante return (ENAMETOOLONG); 2060b7661cccSmmusante 2061a9799022Sck err = dsl_dataset_snapshot_reserve_space(ds, tx); 2062a9799022Sck if (err) 2063a9799022Sck return (err); 2064a9799022Sck 20651d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 20661d452cf5Sahrens return (0); 20671d452cf5Sahrens } 2068fa9e4066Sahrens 20691d452cf5Sahrens void 2070ecd6cf80Smarks dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 20711d452cf5Sahrens { 20723cb34c60Sahrens dsl_dataset_t *ds = arg1; 20731d452cf5Sahrens const char *snapname = arg2; 20741d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 20751d452cf5Sahrens dmu_buf_t *dbuf; 20761d452cf5Sahrens dsl_dataset_phys_t *dsphys; 2077088f3894Sahrens uint64_t dsobj, crtxg; 20781d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 20791d452cf5Sahrens int err; 2080fa9e4066Sahrens 20811d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 2082fa9e4066Sahrens 2083088f3894Sahrens /* 2084088f3894Sahrens * The origin's ds_creation_txg has to be < TXG_INITIAL 2085088f3894Sahrens */ 2086088f3894Sahrens if (strcmp(snapname, ORIGIN_DIR_NAME) == 0) 2087088f3894Sahrens crtxg = 1; 2088088f3894Sahrens else 2089088f3894Sahrens crtxg = tx->tx_txg; 2090088f3894Sahrens 20911649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 20921649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 2093ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 2094fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 2095fa9e4066Sahrens dsphys = dbuf->db_data; 2096745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 20971d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 2098fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 2099fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 2100fa9e4066Sahrens sizeof (dsphys->ds_guid)); 2101fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 2102fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 2103fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 2104fa9e4066Sahrens dsphys->ds_num_children = 1; 2105fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 2106088f3894Sahrens dsphys->ds_creation_txg = crtxg; 2107fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 2108fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 2109fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 2110fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 211199653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 2112fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 2113ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 2114fa9e4066Sahrens 21151d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 21161d452cf5Sahrens if (ds->ds_prev) { 2117088f3894Sahrens uint64_t next_clones_obj = 2118088f3894Sahrens ds->ds_prev->ds_phys->ds_next_clones_obj; 21191d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 2120fa9e4066Sahrens ds->ds_object || 21211d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 21221d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 21231d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 2124fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 21251d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 21261d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 2127088f3894Sahrens } else if (next_clones_obj != 0) { 2128088f3894Sahrens VERIFY3U(0, ==, zap_remove_int(mos, 2129088f3894Sahrens next_clones_obj, dsphys->ds_next_snap_obj, tx)); 2130088f3894Sahrens VERIFY3U(0, ==, zap_add_int(mos, 2131088f3894Sahrens next_clones_obj, dsobj, tx)); 2132fa9e4066Sahrens } 2133fa9e4066Sahrens } 2134fa9e4066Sahrens 2135a9799022Sck /* 2136a9799022Sck * If we have a reference-reservation on this dataset, we will 2137a9799022Sck * need to increase the amount of refreservation being charged 2138a9799022Sck * since our unique space is going to zero. 2139a9799022Sck */ 2140a9799022Sck if (ds->ds_reserved) { 2141a9799022Sck int64_t add = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 214274e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, 214374e7dc98SMatthew Ahrens add, 0, 0, tx); 2144a9799022Sck } 2145a9799022Sck 2146fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 2147fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 2148a4611edeSahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg); 2149fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 2150088f3894Sahrens ds->ds_phys->ds_prev_snap_txg = crtxg; 2151fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 2152a9799022Sck if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 2153a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 2154fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 2155fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 2156ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 2157ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 2158fa9e4066Sahrens 2159fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 2160fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 2161fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 2162fa9e4066Sahrens ASSERT(err == 0); 2163fa9e4066Sahrens 2164fa9e4066Sahrens if (ds->ds_prev) 2165745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 2166745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 2167745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev)); 2168ecd6cf80Smarks 2169088f3894Sahrens dsl_pool_ds_snapshotted(ds, tx); 2170088f3894Sahrens 2171ecd6cf80Smarks spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr, 217240feaa91Sahrens "dataset = %llu", dsobj); 2173fa9e4066Sahrens } 2174fa9e4066Sahrens 2175fa9e4066Sahrens void 2176c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 2177fa9e4066Sahrens { 2178fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 2179fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 2180fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 2181fa9e4066Sahrens 218291ebeef5Sahrens /* 218391ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 218491ebeef5Sahrens * sync it out now. 218591ebeef5Sahrens */ 218691ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 218791ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 218891ebeef5Sahrens 2189fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 2190c717a561Smaybee dmu_objset_sync(ds->ds_user_ptr, zio, tx); 2191fa9e4066Sahrens } 2192fa9e4066Sahrens 2193fa9e4066Sahrens void 2194a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 2195fa9e4066Sahrens { 2196a9799022Sck uint64_t refd, avail, uobjs, aobjs; 2197a9799022Sck 2198a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 2199fa9e4066Sahrens 2200a9799022Sck dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); 2201a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); 2202a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); 2203a9799022Sck 2204a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 2205a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 2206a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 2207a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 2208a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, 2209a9799022Sck ds->ds_quota); 2210a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, 2211a9799022Sck ds->ds_reserved); 2212c5904d13Seschrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, 2213c5904d13Seschrock ds->ds_phys->ds_guid); 2214*842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, ds->ds_userrefs); 2215*842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2216*842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2217fa9e4066Sahrens 2218fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2219fa9e4066Sahrens /* 2220fa9e4066Sahrens * This is a snapshot; override the dd's space used with 2221a2eea2e1Sahrens * our unique space and compression ratio. 2222fa9e4066Sahrens */ 2223a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 2224a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 2225a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 2226a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 2227a2eea2e1Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 2228a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes)); 2229fa9e4066Sahrens } 2230fa9e4066Sahrens } 2231fa9e4066Sahrens 2232a2eea2e1Sahrens void 2233a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2234a2eea2e1Sahrens { 2235a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2236a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 22373cb34c60Sahrens stat->dds_guid = ds->ds_phys->ds_guid; 2238a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2239a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 2240a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 2241ebedde84SEric Taylor } else { 2242ebedde84SEric Taylor stat->dds_is_snapshot = B_FALSE; 2243ebedde84SEric Taylor stat->dds_num_clones = 0; 2244a2eea2e1Sahrens } 2245a2eea2e1Sahrens 2246a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 22474ccbb6e7Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 2248088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 2249a2eea2e1Sahrens dsl_dataset_t *ods; 2250a2eea2e1Sahrens 2251745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool, 2252745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods)); 22533cb34c60Sahrens dsl_dataset_name(ods, stat->dds_origin); 2254745cd3c5Smaybee dsl_dataset_drop_ref(ods, FTAG); 2255ebedde84SEric Taylor } else { 2256ebedde84SEric Taylor stat->dds_origin[0] = '\0'; 2257a2eea2e1Sahrens } 22584ccbb6e7Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2259a2eea2e1Sahrens } 2260a2eea2e1Sahrens 2261a2eea2e1Sahrens uint64_t 2262a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 2263a2eea2e1Sahrens { 226491ebeef5Sahrens return (ds->ds_fsid_guid); 2265a2eea2e1Sahrens } 2266a2eea2e1Sahrens 2267a2eea2e1Sahrens void 2268a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 2269a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 2270a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 2271fa9e4066Sahrens { 2272a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 2273a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 2274a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) 2275a9799022Sck *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes; 2276a9799022Sck if (ds->ds_quota != 0) { 2277a9799022Sck /* 2278a9799022Sck * Adjust available bytes according to refquota 2279a9799022Sck */ 2280a9799022Sck if (*refdbytesp < ds->ds_quota) 2281a9799022Sck *availbytesp = MIN(*availbytesp, 2282a9799022Sck ds->ds_quota - *refdbytesp); 2283a9799022Sck else 2284a9799022Sck *availbytesp = 0; 2285a9799022Sck } 2286a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 2287a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 2288fa9e4066Sahrens } 2289fa9e4066Sahrens 2290f18faf3fSek boolean_t 2291f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 2292f18faf3fSek { 2293f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 2294f18faf3fSek 2295f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 2296f18faf3fSek dsl_pool_sync_context(dp)); 2297f18faf3fSek if (ds->ds_prev == NULL) 2298f18faf3fSek return (B_FALSE); 2299f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 2300f18faf3fSek ds->ds_prev->ds_phys->ds_creation_txg) 2301f18faf3fSek return (B_TRUE); 2302f18faf3fSek return (B_FALSE); 2303f18faf3fSek } 2304f18faf3fSek 23051d452cf5Sahrens /* ARGSUSED */ 2306fa9e4066Sahrens static int 23071d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 2308fa9e4066Sahrens { 23091d452cf5Sahrens dsl_dataset_t *ds = arg1; 23101d452cf5Sahrens char *newsnapname = arg2; 23111d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 23121d452cf5Sahrens dsl_dataset_t *hds; 2313fa9e4066Sahrens uint64_t val; 23141d452cf5Sahrens int err; 2315fa9e4066Sahrens 2316745cd3c5Smaybee err = dsl_dataset_hold_obj(dd->dd_pool, 2317745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds); 2318fa9e4066Sahrens if (err) 2319fa9e4066Sahrens return (err); 2320fa9e4066Sahrens 23211d452cf5Sahrens /* new name better not be in use */ 2322745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, newsnapname, &val); 2323745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 23241d452cf5Sahrens 23251d452cf5Sahrens if (err == 0) 23261d452cf5Sahrens err = EEXIST; 23271d452cf5Sahrens else if (err == ENOENT) 23281d452cf5Sahrens err = 0; 2329cdf5b4caSmmusante 2330cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 2331cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 2332cdf5b4caSmmusante err = ENAMETOOLONG; 2333cdf5b4caSmmusante 23341d452cf5Sahrens return (err); 23351d452cf5Sahrens } 2336fa9e4066Sahrens 23371d452cf5Sahrens static void 2338ecd6cf80Smarks dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, 2339ecd6cf80Smarks cred_t *cr, dmu_tx_t *tx) 23401d452cf5Sahrens { 23411d452cf5Sahrens dsl_dataset_t *ds = arg1; 2342ecd6cf80Smarks const char *newsnapname = arg2; 23431d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 23441d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 23451d452cf5Sahrens dsl_dataset_t *hds; 23461d452cf5Sahrens int err; 2347fa9e4066Sahrens 23481d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 2349fa9e4066Sahrens 2350745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, 2351745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds)); 2352fa9e4066Sahrens 23531d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2354745cd3c5Smaybee err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx); 2355fa9e4066Sahrens ASSERT3U(err, ==, 0); 23561d452cf5Sahrens mutex_enter(&ds->ds_lock); 23571d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 23581d452cf5Sahrens mutex_exit(&ds->ds_lock); 23591d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 23601d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 2361fa9e4066Sahrens ASSERT3U(err, ==, 0); 2362fa9e4066Sahrens 2363ecd6cf80Smarks spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 2364ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 2365745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 2366fa9e4066Sahrens } 2367fa9e4066Sahrens 2368f18faf3fSek struct renamesnaparg { 2369cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 2370cdf5b4caSmmusante char failed[MAXPATHLEN]; 2371cdf5b4caSmmusante char *oldsnap; 2372cdf5b4caSmmusante char *newsnap; 2373cdf5b4caSmmusante }; 2374cdf5b4caSmmusante 2375cdf5b4caSmmusante static int 2376cdf5b4caSmmusante dsl_snapshot_rename_one(char *name, void *arg) 2377cdf5b4caSmmusante { 2378f18faf3fSek struct renamesnaparg *ra = arg; 2379cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 2380cdf5b4caSmmusante char *cp; 2381cdf5b4caSmmusante int err; 2382cdf5b4caSmmusante 2383cdf5b4caSmmusante cp = name + strlen(name); 2384cdf5b4caSmmusante *cp = '@'; 2385cdf5b4caSmmusante (void) strcpy(cp + 1, ra->oldsnap); 2386ecd6cf80Smarks 2387ecd6cf80Smarks /* 2388ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 2389ecd6cf80Smarks * so we just pass name for both the to/from argument. 2390ecd6cf80Smarks */ 2391a0dc2951SMatthew Ahrens err = zfs_secpolicy_rename_perms(name, name, CRED()); 2392a0dc2951SMatthew Ahrens if (err == ENOENT) { 2393a0dc2951SMatthew Ahrens return (0); 2394a0dc2951SMatthew Ahrens } else if (err) { 2395ecd6cf80Smarks (void) strcpy(ra->failed, name); 2396ecd6cf80Smarks return (err); 2397ecd6cf80Smarks } 2398ecd6cf80Smarks 2399745cd3c5Smaybee #ifdef _KERNEL 2400745cd3c5Smaybee /* 2401745cd3c5Smaybee * For all filesystems undergoing rename, we'll need to unmount it. 2402745cd3c5Smaybee */ 2403745cd3c5Smaybee (void) zfs_unmount_snap(name, NULL); 2404745cd3c5Smaybee #endif 2405745cd3c5Smaybee err = dsl_dataset_hold(name, ra->dstg, &ds); 2406745cd3c5Smaybee *cp = '\0'; 2407cdf5b4caSmmusante if (err == ENOENT) { 2408cdf5b4caSmmusante return (0); 2409745cd3c5Smaybee } else if (err) { 2410cdf5b4caSmmusante (void) strcpy(ra->failed, name); 2411cdf5b4caSmmusante return (err); 2412cdf5b4caSmmusante } 2413cdf5b4caSmmusante 2414cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 2415cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 2416cdf5b4caSmmusante 2417cdf5b4caSmmusante return (0); 2418cdf5b4caSmmusante } 2419cdf5b4caSmmusante 2420cdf5b4caSmmusante static int 2421cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 2422cdf5b4caSmmusante { 2423cdf5b4caSmmusante int err; 2424f18faf3fSek struct renamesnaparg *ra; 2425cdf5b4caSmmusante dsl_sync_task_t *dst; 2426cdf5b4caSmmusante spa_t *spa; 2427cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 2428cdf5b4caSmmusante int len = strlen(oldname); 2429cdf5b4caSmmusante 2430cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 2431cdf5b4caSmmusante cp = strchr(fsname, '@'); 2432cdf5b4caSmmusante *cp = '\0'; 2433cdf5b4caSmmusante 243440feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 2435cdf5b4caSmmusante if (err) { 2436cdf5b4caSmmusante kmem_free(fsname, len + 1); 2437cdf5b4caSmmusante return (err); 2438cdf5b4caSmmusante } 2439f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 2440cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 2441cdf5b4caSmmusante 2442cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 2443cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 2444cdf5b4caSmmusante *ra->failed = '\0'; 2445cdf5b4caSmmusante 2446cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 2447cdf5b4caSmmusante DS_FIND_CHILDREN); 2448cdf5b4caSmmusante kmem_free(fsname, len + 1); 2449cdf5b4caSmmusante 2450cdf5b4caSmmusante if (err == 0) { 2451cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 2452cdf5b4caSmmusante } 2453cdf5b4caSmmusante 2454cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 2455cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 2456cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 2457cdf5b4caSmmusante if (dst->dst_err) { 2458cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 24592572aa4eSmmusante (void) strcat(ra->failed, "@"); 24602572aa4eSmmusante (void) strcat(ra->failed, ra->newsnap); 2461cdf5b4caSmmusante } 2462745cd3c5Smaybee dsl_dataset_rele(ds, ra->dstg); 2463cdf5b4caSmmusante } 2464cdf5b4caSmmusante 2465ecd6cf80Smarks if (err) 2466ecd6cf80Smarks (void) strcpy(oldname, ra->failed); 2467cdf5b4caSmmusante 2468cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 2469f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 2470cdf5b4caSmmusante spa_close(spa, FTAG); 2471cdf5b4caSmmusante return (err); 2472cdf5b4caSmmusante } 2473cdf5b4caSmmusante 24743a5a36beSmmusante static int 24753a5a36beSmmusante dsl_valid_rename(char *oldname, void *arg) 24763a5a36beSmmusante { 24773a5a36beSmmusante int delta = *(int *)arg; 24783a5a36beSmmusante 24793a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 24803a5a36beSmmusante return (ENAMETOOLONG); 24813a5a36beSmmusante 24823a5a36beSmmusante return (0); 24833a5a36beSmmusante } 24843a5a36beSmmusante 2485fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 2486fa9e4066Sahrens int 2487745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive) 2488fa9e4066Sahrens { 2489fa9e4066Sahrens dsl_dir_t *dd; 24901d452cf5Sahrens dsl_dataset_t *ds; 2491fa9e4066Sahrens const char *tail; 2492fa9e4066Sahrens int err; 2493fa9e4066Sahrens 24941d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 2495ea8dc4b6Seschrock if (err) 2496ea8dc4b6Seschrock return (err); 24971db42183SEric Taylor /* 24981db42183SEric Taylor * If there are more than 2 references there may be holds 24991db42183SEric Taylor * hanging around that haven't been cleared out yet. 25001db42183SEric Taylor */ 25011db42183SEric Taylor if (dmu_buf_refcount(dd->dd_dbuf) > 2) 25021db42183SEric Taylor txg_wait_synced(dd->dd_pool, 0); 2503fa9e4066Sahrens if (tail == NULL) { 25043a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 25053a5a36beSmmusante 2506088f3894Sahrens /* if we're growing, validate child name lengths */ 25073a5a36beSmmusante if (delta > 0) 25083a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 25093a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 25103a5a36beSmmusante 25113a5a36beSmmusante if (!err) 25123a5a36beSmmusante err = dsl_dir_rename(dd, newname); 2513fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2514fa9e4066Sahrens return (err); 2515fa9e4066Sahrens } 2516fa9e4066Sahrens if (tail[0] != '@') { 2517fa9e4066Sahrens /* the name ended in a nonexistant component */ 2518fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2519fa9e4066Sahrens return (ENOENT); 2520fa9e4066Sahrens } 2521fa9e4066Sahrens 2522fa9e4066Sahrens dsl_dir_close(dd, FTAG); 25231d452cf5Sahrens 25241d452cf5Sahrens /* new name must be snapshot in same filesystem */ 25251d452cf5Sahrens tail = strchr(newname, '@'); 25261d452cf5Sahrens if (tail == NULL) 25271d452cf5Sahrens return (EINVAL); 25281d452cf5Sahrens tail++; 25291d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 25301d452cf5Sahrens return (EXDEV); 25311d452cf5Sahrens 2532cdf5b4caSmmusante if (recursive) { 2533cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 2534cdf5b4caSmmusante } else { 2535745cd3c5Smaybee err = dsl_dataset_hold(oldname, FTAG, &ds); 2536cdf5b4caSmmusante if (err) 2537cdf5b4caSmmusante return (err); 25381d452cf5Sahrens 2539cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2540cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 2541cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 25421d452cf5Sahrens 2543745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2544cdf5b4caSmmusante } 25451d452cf5Sahrens 2546fa9e4066Sahrens return (err); 2547fa9e4066Sahrens } 254899653d4eSeschrock 2549088f3894Sahrens struct promotenode { 2550745cd3c5Smaybee list_node_t link; 2551745cd3c5Smaybee dsl_dataset_t *ds; 2552745cd3c5Smaybee }; 2553745cd3c5Smaybee 25541d452cf5Sahrens struct promotearg { 255574e7dc98SMatthew Ahrens list_t shared_snaps, origin_snaps, clone_snaps; 255674e7dc98SMatthew Ahrens dsl_dataset_t *origin_origin, *origin_head; 255774e7dc98SMatthew Ahrens uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; 25581d452cf5Sahrens }; 25591d452cf5Sahrens 256074e7dc98SMatthew Ahrens static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep); 256174e7dc98SMatthew Ahrens 2562ecd6cf80Smarks /* ARGSUSED */ 256399653d4eSeschrock static int 25641d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 256599653d4eSeschrock { 25661d452cf5Sahrens dsl_dataset_t *hds = arg1; 25671d452cf5Sahrens struct promotearg *pa = arg2; 256874e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2569745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 2570745cd3c5Smaybee int err; 25711d452cf5Sahrens 2572088f3894Sahrens /* Check that it is a real clone */ 2573088f3894Sahrens if (!dsl_dir_is_clone(hds->ds_dir)) 257499653d4eSeschrock return (EINVAL); 257599653d4eSeschrock 25761d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 25771d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 25781d452cf5Sahrens return (0); 25791d452cf5Sahrens 2580745cd3c5Smaybee if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) 2581745cd3c5Smaybee return (EXDEV); 258299653d4eSeschrock 25833cb34c60Sahrens /* compute origin's new unique space */ 258474e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 258574e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 258674e7dc98SMatthew Ahrens err = bplist_space_birthrange(&snap->ds->ds_deadlist, 258774e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, &pa->unique); 258874e7dc98SMatthew Ahrens if (err) 2589745cd3c5Smaybee return (err); 259099653d4eSeschrock 2591745cd3c5Smaybee /* 2592745cd3c5Smaybee * Walk the snapshots that we are moving 2593745cd3c5Smaybee * 259474e7dc98SMatthew Ahrens * Compute space to transfer. Consider the incremental changes 259574e7dc98SMatthew Ahrens * to used for each snapshot: 259674e7dc98SMatthew Ahrens * (my used) = (prev's used) + (blocks born) - (blocks killed) 259774e7dc98SMatthew Ahrens * So each snapshot gave birth to: 259874e7dc98SMatthew Ahrens * (blocks born) = (my used) - (prev's used) + (blocks killed) 2599745cd3c5Smaybee * So a sequence would look like: 260074e7dc98SMatthew Ahrens * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0) 2601745cd3c5Smaybee * Which simplifies to: 260274e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + k1 + k0 2603745cd3c5Smaybee * Note however, if we stop before we reach the ORIGIN we get: 260474e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + kM - uM-1 2605745cd3c5Smaybee */ 2606745cd3c5Smaybee pa->used = origin_ds->ds_phys->ds_used_bytes; 2607745cd3c5Smaybee pa->comp = origin_ds->ds_phys->ds_compressed_bytes; 2608745cd3c5Smaybee pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes; 260974e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 261074e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 261199653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 2612745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 261399653d4eSeschrock 261499653d4eSeschrock /* Check that the snapshot name does not conflict */ 261574e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2616745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); 2617745cd3c5Smaybee if (err == 0) 261874e7dc98SMatthew Ahrens return (EEXIST); 2619745cd3c5Smaybee if (err != ENOENT) 262074e7dc98SMatthew Ahrens return (err); 262199653d4eSeschrock 2622745cd3c5Smaybee /* The very first snapshot does not have a deadlist */ 262374e7dc98SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 262474e7dc98SMatthew Ahrens continue; 262574e7dc98SMatthew Ahrens 262674e7dc98SMatthew Ahrens if (err = bplist_space(&ds->ds_deadlist, 262774e7dc98SMatthew Ahrens &dlused, &dlcomp, &dluncomp)) 262874e7dc98SMatthew Ahrens return (err); 262974e7dc98SMatthew Ahrens pa->used += dlused; 263074e7dc98SMatthew Ahrens pa->comp += dlcomp; 263174e7dc98SMatthew Ahrens pa->uncomp += dluncomp; 263274e7dc98SMatthew Ahrens } 2633745cd3c5Smaybee 2634745cd3c5Smaybee /* 2635745cd3c5Smaybee * If we are a clone of a clone then we never reached ORIGIN, 2636745cd3c5Smaybee * so we need to subtract out the clone origin's used space. 2637745cd3c5Smaybee */ 263874e7dc98SMatthew Ahrens if (pa->origin_origin) { 263974e7dc98SMatthew Ahrens pa->used -= pa->origin_origin->ds_phys->ds_used_bytes; 264074e7dc98SMatthew Ahrens pa->comp -= pa->origin_origin->ds_phys->ds_compressed_bytes; 264174e7dc98SMatthew Ahrens pa->uncomp -= pa->origin_origin->ds_phys->ds_uncompressed_bytes; 264299653d4eSeschrock } 264399653d4eSeschrock 264499653d4eSeschrock /* Check that there is enough space here */ 264574e7dc98SMatthew Ahrens err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir, 264674e7dc98SMatthew Ahrens pa->used); 264774e7dc98SMatthew Ahrens if (err) 264874e7dc98SMatthew Ahrens return (err); 264974e7dc98SMatthew Ahrens 265074e7dc98SMatthew Ahrens /* 265174e7dc98SMatthew Ahrens * Compute the amounts of space that will be used by snapshots 265274e7dc98SMatthew Ahrens * after the promotion (for both origin and clone). For each, 265374e7dc98SMatthew Ahrens * it is the amount of space that will be on all of their 265474e7dc98SMatthew Ahrens * deadlists (that was not born before their new origin). 265574e7dc98SMatthew Ahrens */ 265674e7dc98SMatthew Ahrens if (hds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 265774e7dc98SMatthew Ahrens uint64_t space; 265874e7dc98SMatthew Ahrens 265974e7dc98SMatthew Ahrens /* 266074e7dc98SMatthew Ahrens * Note, typically this will not be a clone of a clone, 266174e7dc98SMatthew Ahrens * so snap->ds->ds_origin_txg will be < TXG_INITIAL, so 266274e7dc98SMatthew Ahrens * these snaplist_space() -> bplist_space_birthrange() 266374e7dc98SMatthew Ahrens * calls will be fast because they do not have to 266474e7dc98SMatthew Ahrens * iterate over all bps. 266574e7dc98SMatthew Ahrens */ 266674e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 266774e7dc98SMatthew Ahrens err = snaplist_space(&pa->shared_snaps, 266874e7dc98SMatthew Ahrens snap->ds->ds_origin_txg, &pa->cloneusedsnap); 266974e7dc98SMatthew Ahrens if (err) 267074e7dc98SMatthew Ahrens return (err); 267174e7dc98SMatthew Ahrens 267274e7dc98SMatthew Ahrens err = snaplist_space(&pa->clone_snaps, 267374e7dc98SMatthew Ahrens snap->ds->ds_origin_txg, &space); 267474e7dc98SMatthew Ahrens if (err) 267574e7dc98SMatthew Ahrens return (err); 267674e7dc98SMatthew Ahrens pa->cloneusedsnap += space; 267774e7dc98SMatthew Ahrens } 267874e7dc98SMatthew Ahrens if (origin_ds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 267974e7dc98SMatthew Ahrens err = snaplist_space(&pa->origin_snaps, 268074e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_creation_txg, &pa->originusedsnap); 268174e7dc98SMatthew Ahrens if (err) 268274e7dc98SMatthew Ahrens return (err); 2683745cd3c5Smaybee } 26841d452cf5Sahrens 268574e7dc98SMatthew Ahrens return (0); 26861d452cf5Sahrens } 268799653d4eSeschrock 26881d452cf5Sahrens static void 2689ecd6cf80Smarks dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 26901d452cf5Sahrens { 26911d452cf5Sahrens dsl_dataset_t *hds = arg1; 26921d452cf5Sahrens struct promotearg *pa = arg2; 269374e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2694745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 269574e7dc98SMatthew Ahrens dsl_dataset_t *origin_head; 26961d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 26971d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 26983cb34c60Sahrens dsl_dir_t *odd = NULL; 2699088f3894Sahrens uint64_t oldnext_obj; 270074e7dc98SMatthew Ahrens int64_t delta; 27011d452cf5Sahrens 27021d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 27031d452cf5Sahrens 270474e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 270574e7dc98SMatthew Ahrens origin_head = snap->ds; 270674e7dc98SMatthew Ahrens 27070b69c2f0Sahrens /* 27083cb34c60Sahrens * We need to explicitly open odd, since origin_ds's dd will be 27090b69c2f0Sahrens * changing. 27100b69c2f0Sahrens */ 27113cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object, 27123cb34c60Sahrens NULL, FTAG, &odd)); 271399653d4eSeschrock 2714745cd3c5Smaybee /* change origin's next snap */ 2715745cd3c5Smaybee dmu_buf_will_dirty(origin_ds->ds_dbuf, tx); 2716088f3894Sahrens oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj; 271774e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 271874e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 271974e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj = snap->ds->ds_object; 2720745cd3c5Smaybee 2721088f3894Sahrens /* change the origin's next clone */ 2722088f3894Sahrens if (origin_ds->ds_phys->ds_next_clones_obj) { 2723088f3894Sahrens VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2724088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 272574e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj, tx)); 2726088f3894Sahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2727088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2728088f3894Sahrens oldnext_obj, tx)); 2729088f3894Sahrens } 2730088f3894Sahrens 2731745cd3c5Smaybee /* change origin */ 2732745cd3c5Smaybee dmu_buf_will_dirty(dd->dd_dbuf, tx); 2733745cd3c5Smaybee ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object); 2734745cd3c5Smaybee dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj; 273574e7dc98SMatthew Ahrens hds->ds_origin_txg = origin_head->ds_origin_txg; 2736745cd3c5Smaybee dmu_buf_will_dirty(odd->dd_dbuf, tx); 2737745cd3c5Smaybee odd->dd_phys->dd_origin_obj = origin_ds->ds_object; 273874e7dc98SMatthew Ahrens origin_head->ds_origin_txg = origin_ds->ds_phys->ds_creation_txg; 2739745cd3c5Smaybee 274099653d4eSeschrock /* move snapshots to this dir */ 274174e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 274274e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 2743745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 274499653d4eSeschrock 27453baa08fcSek /* unregister props as dsl_dir is changing */ 27463baa08fcSek if (ds->ds_user_ptr) { 27473baa08fcSek ds->ds_user_evict_func(ds, ds->ds_user_ptr); 27483baa08fcSek ds->ds_user_ptr = NULL; 27493baa08fcSek } 275099653d4eSeschrock /* move snap name entry */ 275174e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 275274e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_snap_remove(origin_head, 2753745cd3c5Smaybee ds->ds_snapname, tx)); 27541d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 275599653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 275699653d4eSeschrock 8, 1, &ds->ds_object, tx)); 275799653d4eSeschrock /* change containing dsl_dir */ 275899653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 27593cb34c60Sahrens ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object); 276099653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 27613cb34c60Sahrens ASSERT3P(ds->ds_dir, ==, odd); 276299653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 27631d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 276499653d4eSeschrock NULL, ds, &ds->ds_dir)); 276599653d4eSeschrock 276699653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 276774e7dc98SMatthew Ahrens } 276874e7dc98SMatthew Ahrens 276974e7dc98SMatthew Ahrens /* 277074e7dc98SMatthew Ahrens * Change space accounting. 277174e7dc98SMatthew Ahrens * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either 277274e7dc98SMatthew Ahrens * both be valid, or both be 0 (resulting in delta == 0). This 277374e7dc98SMatthew Ahrens * is true for each of {clone,origin} independently. 277474e7dc98SMatthew Ahrens */ 277574e7dc98SMatthew Ahrens 277674e7dc98SMatthew Ahrens delta = pa->cloneusedsnap - 277774e7dc98SMatthew Ahrens dd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 277874e7dc98SMatthew Ahrens ASSERT3S(delta, >=, 0); 277974e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, delta); 278074e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx); 278174e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_HEAD, 278274e7dc98SMatthew Ahrens pa->used - delta, pa->comp, pa->uncomp, tx); 278374e7dc98SMatthew Ahrens 278474e7dc98SMatthew Ahrens delta = pa->originusedsnap - 278574e7dc98SMatthew Ahrens odd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 278674e7dc98SMatthew Ahrens ASSERT3S(delta, <=, 0); 278774e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, -delta); 278874e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx); 278974e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_HEAD, 279074e7dc98SMatthew Ahrens -pa->used - delta, -pa->comp, -pa->uncomp, tx); 279199653d4eSeschrock 27923cb34c60Sahrens origin_ds->ds_phys->ds_unique_bytes = pa->unique; 279399653d4eSeschrock 2794ecd6cf80Smarks /* log history record */ 2795ecd6cf80Smarks spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 2796745cd3c5Smaybee cr, "dataset = %llu", hds->ds_object); 2797ecd6cf80Smarks 27983cb34c60Sahrens dsl_dir_close(odd, FTAG); 279999653d4eSeschrock } 280099653d4eSeschrock 280174e7dc98SMatthew Ahrens static char *snaplist_tag = "snaplist"; 280274e7dc98SMatthew Ahrens /* 280374e7dc98SMatthew Ahrens * Make a list of dsl_dataset_t's for the snapshots between first_obj 280474e7dc98SMatthew Ahrens * (exclusive) and last_obj (inclusive). The list will be in reverse 280574e7dc98SMatthew Ahrens * order (last_obj will be the list_head()). If first_obj == 0, do all 280674e7dc98SMatthew Ahrens * snapshots back to this dataset's origin. 280774e7dc98SMatthew Ahrens */ 280874e7dc98SMatthew Ahrens static int 280974e7dc98SMatthew Ahrens snaplist_make(dsl_pool_t *dp, boolean_t own, 281074e7dc98SMatthew Ahrens uint64_t first_obj, uint64_t last_obj, list_t *l) 281174e7dc98SMatthew Ahrens { 281274e7dc98SMatthew Ahrens uint64_t obj = last_obj; 281374e7dc98SMatthew Ahrens 281474e7dc98SMatthew Ahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock)); 281574e7dc98SMatthew Ahrens 281674e7dc98SMatthew Ahrens list_create(l, sizeof (struct promotenode), 281774e7dc98SMatthew Ahrens offsetof(struct promotenode, link)); 281874e7dc98SMatthew Ahrens 281974e7dc98SMatthew Ahrens while (obj != first_obj) { 282074e7dc98SMatthew Ahrens dsl_dataset_t *ds; 282174e7dc98SMatthew Ahrens struct promotenode *snap; 282274e7dc98SMatthew Ahrens int err; 282374e7dc98SMatthew Ahrens 282474e7dc98SMatthew Ahrens if (own) { 282574e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, obj, 282674e7dc98SMatthew Ahrens 0, snaplist_tag, &ds); 282774e7dc98SMatthew Ahrens if (err == 0) 282874e7dc98SMatthew Ahrens dsl_dataset_make_exclusive(ds, snaplist_tag); 282974e7dc98SMatthew Ahrens } else { 283074e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, obj, snaplist_tag, &ds); 283174e7dc98SMatthew Ahrens } 283274e7dc98SMatthew Ahrens if (err == ENOENT) { 283374e7dc98SMatthew Ahrens /* lost race with snapshot destroy */ 283474e7dc98SMatthew Ahrens struct promotenode *last = list_tail(l); 283574e7dc98SMatthew Ahrens ASSERT(obj != last->ds->ds_phys->ds_prev_snap_obj); 283674e7dc98SMatthew Ahrens obj = last->ds->ds_phys->ds_prev_snap_obj; 283774e7dc98SMatthew Ahrens continue; 283874e7dc98SMatthew Ahrens } else if (err) { 283974e7dc98SMatthew Ahrens return (err); 284074e7dc98SMatthew Ahrens } 284174e7dc98SMatthew Ahrens 284274e7dc98SMatthew Ahrens if (first_obj == 0) 284374e7dc98SMatthew Ahrens first_obj = ds->ds_dir->dd_phys->dd_origin_obj; 284474e7dc98SMatthew Ahrens 284574e7dc98SMatthew Ahrens snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP); 284674e7dc98SMatthew Ahrens snap->ds = ds; 284774e7dc98SMatthew Ahrens list_insert_tail(l, snap); 284874e7dc98SMatthew Ahrens obj = ds->ds_phys->ds_prev_snap_obj; 284974e7dc98SMatthew Ahrens } 285074e7dc98SMatthew Ahrens 285174e7dc98SMatthew Ahrens return (0); 285274e7dc98SMatthew Ahrens } 285374e7dc98SMatthew Ahrens 285474e7dc98SMatthew Ahrens static int 285574e7dc98SMatthew Ahrens snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep) 285674e7dc98SMatthew Ahrens { 285774e7dc98SMatthew Ahrens struct promotenode *snap; 285874e7dc98SMatthew Ahrens 285974e7dc98SMatthew Ahrens *spacep = 0; 286074e7dc98SMatthew Ahrens for (snap = list_head(l); snap; snap = list_next(l, snap)) { 286174e7dc98SMatthew Ahrens uint64_t used; 286274e7dc98SMatthew Ahrens int err = bplist_space_birthrange(&snap->ds->ds_deadlist, 286374e7dc98SMatthew Ahrens mintxg, UINT64_MAX, &used); 286474e7dc98SMatthew Ahrens if (err) 286574e7dc98SMatthew Ahrens return (err); 286674e7dc98SMatthew Ahrens *spacep += used; 286774e7dc98SMatthew Ahrens } 286874e7dc98SMatthew Ahrens return (0); 286974e7dc98SMatthew Ahrens } 287074e7dc98SMatthew Ahrens 287174e7dc98SMatthew Ahrens static void 287274e7dc98SMatthew Ahrens snaplist_destroy(list_t *l, boolean_t own) 287374e7dc98SMatthew Ahrens { 287474e7dc98SMatthew Ahrens struct promotenode *snap; 287574e7dc98SMatthew Ahrens 28764f5064b7SMark J Musante if (!l || !list_link_active(&l->list_head)) 287774e7dc98SMatthew Ahrens return; 287874e7dc98SMatthew Ahrens 287974e7dc98SMatthew Ahrens while ((snap = list_tail(l)) != NULL) { 288074e7dc98SMatthew Ahrens list_remove(l, snap); 288174e7dc98SMatthew Ahrens if (own) 288274e7dc98SMatthew Ahrens dsl_dataset_disown(snap->ds, snaplist_tag); 288374e7dc98SMatthew Ahrens else 288474e7dc98SMatthew Ahrens dsl_dataset_rele(snap->ds, snaplist_tag); 288574e7dc98SMatthew Ahrens kmem_free(snap, sizeof (struct promotenode)); 288674e7dc98SMatthew Ahrens } 288774e7dc98SMatthew Ahrens list_destroy(l); 288874e7dc98SMatthew Ahrens } 288974e7dc98SMatthew Ahrens 289074e7dc98SMatthew Ahrens /* 289174e7dc98SMatthew Ahrens * Promote a clone. Nomenclature note: 289274e7dc98SMatthew Ahrens * "clone" or "cds": the original clone which is being promoted 289374e7dc98SMatthew Ahrens * "origin" or "ods": the snapshot which is originally clone's origin 289474e7dc98SMatthew Ahrens * "origin head" or "ohds": the dataset which is the head 289574e7dc98SMatthew Ahrens * (filesystem/volume) for the origin 289674e7dc98SMatthew Ahrens * "origin origin": the origin of the origin's filesystem (typically 289774e7dc98SMatthew Ahrens * NULL, indicating that the clone is not a clone of a clone). 289874e7dc98SMatthew Ahrens */ 289999653d4eSeschrock int 290099653d4eSeschrock dsl_dataset_promote(const char *name) 290199653d4eSeschrock { 290299653d4eSeschrock dsl_dataset_t *ds; 2903745cd3c5Smaybee dsl_dir_t *dd; 2904745cd3c5Smaybee dsl_pool_t *dp; 290599653d4eSeschrock dmu_object_info_t doi; 290674e7dc98SMatthew Ahrens struct promotearg pa = { 0 }; 2907088f3894Sahrens struct promotenode *snap; 2908745cd3c5Smaybee int err; 290999653d4eSeschrock 2910745cd3c5Smaybee err = dsl_dataset_hold(name, FTAG, &ds); 291199653d4eSeschrock if (err) 291299653d4eSeschrock return (err); 2913745cd3c5Smaybee dd = ds->ds_dir; 2914745cd3c5Smaybee dp = dd->dd_pool; 291599653d4eSeschrock 2916745cd3c5Smaybee err = dmu_object_info(dp->dp_meta_objset, 291799653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 291899653d4eSeschrock if (err) { 2919745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 292099653d4eSeschrock return (err); 292199653d4eSeschrock } 292299653d4eSeschrock 292374e7dc98SMatthew Ahrens if (dsl_dataset_is_snapshot(ds) || dd->dd_phys->dd_origin_obj == 0) { 292474e7dc98SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 292574e7dc98SMatthew Ahrens return (EINVAL); 292674e7dc98SMatthew Ahrens } 292774e7dc98SMatthew Ahrens 2928745cd3c5Smaybee /* 2929745cd3c5Smaybee * We are going to inherit all the snapshots taken before our 2930745cd3c5Smaybee * origin (i.e., our new origin will be our parent's origin). 2931745cd3c5Smaybee * Take ownership of them so that we can rename them into our 2932745cd3c5Smaybee * namespace. 2933745cd3c5Smaybee */ 2934745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 2935088f3894Sahrens 293674e7dc98SMatthew Ahrens err = snaplist_make(dp, B_TRUE, 0, dd->dd_phys->dd_origin_obj, 293774e7dc98SMatthew Ahrens &pa.shared_snaps); 293874e7dc98SMatthew Ahrens if (err != 0) 293974e7dc98SMatthew Ahrens goto out; 2940088f3894Sahrens 294174e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, 0, ds->ds_object, &pa.clone_snaps); 294274e7dc98SMatthew Ahrens if (err != 0) 294374e7dc98SMatthew Ahrens goto out; 2944088f3894Sahrens 294574e7dc98SMatthew Ahrens snap = list_head(&pa.shared_snaps); 294674e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_object, ==, dd->dd_phys->dd_origin_obj); 294774e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, dd->dd_phys->dd_origin_obj, 294874e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, &pa.origin_snaps); 294974e7dc98SMatthew Ahrens if (err != 0) 295074e7dc98SMatthew Ahrens goto out; 2951088f3894Sahrens 295274e7dc98SMatthew Ahrens if (dsl_dir_is_clone(snap->ds->ds_dir)) { 295374e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, 295474e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_origin_obj, 295574e7dc98SMatthew Ahrens 0, FTAG, &pa.origin_origin); 295674e7dc98SMatthew Ahrens if (err != 0) 295774e7dc98SMatthew Ahrens goto out; 295874e7dc98SMatthew Ahrens } 2959745cd3c5Smaybee 296074e7dc98SMatthew Ahrens out: 296174e7dc98SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 2962745cd3c5Smaybee 296399653d4eSeschrock /* 296499653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 296599653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 296699653d4eSeschrock * bonus buffers. 296799653d4eSeschrock */ 296874e7dc98SMatthew Ahrens if (err == 0) { 296974e7dc98SMatthew Ahrens err = dsl_sync_task_do(dp, dsl_dataset_promote_check, 297074e7dc98SMatthew Ahrens dsl_dataset_promote_sync, ds, &pa, 297174e7dc98SMatthew Ahrens 2 + 2 * doi.doi_physical_blks); 2972745cd3c5Smaybee } 297374e7dc98SMatthew Ahrens 297474e7dc98SMatthew Ahrens snaplist_destroy(&pa.shared_snaps, B_TRUE); 297574e7dc98SMatthew Ahrens snaplist_destroy(&pa.clone_snaps, B_FALSE); 297674e7dc98SMatthew Ahrens snaplist_destroy(&pa.origin_snaps, B_FALSE); 297774e7dc98SMatthew Ahrens if (pa.origin_origin) 297874e7dc98SMatthew Ahrens dsl_dataset_disown(pa.origin_origin, FTAG); 2979745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 298099653d4eSeschrock return (err); 298199653d4eSeschrock } 2982b1b8ab34Slling 29833cb34c60Sahrens struct cloneswaparg { 29843cb34c60Sahrens dsl_dataset_t *cds; /* clone dataset */ 29853cb34c60Sahrens dsl_dataset_t *ohds; /* origin's head dataset */ 29863cb34c60Sahrens boolean_t force; 2987a9b821a0Sck int64_t unused_refres_delta; /* change in unconsumed refreservation */ 29883cb34c60Sahrens }; 2989f18faf3fSek 2990f18faf3fSek /* ARGSUSED */ 2991f18faf3fSek static int 2992f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 2993f18faf3fSek { 29943cb34c60Sahrens struct cloneswaparg *csa = arg1; 2995f18faf3fSek 29963cb34c60Sahrens /* they should both be heads */ 29973cb34c60Sahrens if (dsl_dataset_is_snapshot(csa->cds) || 29983cb34c60Sahrens dsl_dataset_is_snapshot(csa->ohds)) 2999f18faf3fSek return (EINVAL); 3000f18faf3fSek 30013cb34c60Sahrens /* the branch point should be just before them */ 30023cb34c60Sahrens if (csa->cds->ds_prev != csa->ohds->ds_prev) 3003f18faf3fSek return (EINVAL); 3004f18faf3fSek 30053cb34c60Sahrens /* cds should be the clone */ 30063cb34c60Sahrens if (csa->cds->ds_prev->ds_phys->ds_next_snap_obj != 30073cb34c60Sahrens csa->ohds->ds_object) 30083cb34c60Sahrens return (EINVAL); 3009f18faf3fSek 30103cb34c60Sahrens /* the clone should be a child of the origin */ 30113cb34c60Sahrens if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir) 30123cb34c60Sahrens return (EINVAL); 3013f18faf3fSek 30143cb34c60Sahrens /* ohds shouldn't be modified unless 'force' */ 30153cb34c60Sahrens if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) 30163cb34c60Sahrens return (ETXTBSY); 3017a9b821a0Sck 3018a9b821a0Sck /* adjust amount of any unconsumed refreservation */ 3019a9b821a0Sck csa->unused_refres_delta = 3020a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 3021a9b821a0Sck csa->ohds->ds_phys->ds_unique_bytes) - 3022a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 3023a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 3024a9b821a0Sck 3025a9b821a0Sck if (csa->unused_refres_delta > 0 && 3026a9b821a0Sck csa->unused_refres_delta > 3027a9b821a0Sck dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) 3028a9b821a0Sck return (ENOSPC); 3029a9b821a0Sck 30303cb34c60Sahrens return (0); 3031f18faf3fSek } 3032f18faf3fSek 3033f18faf3fSek /* ARGSUSED */ 3034f18faf3fSek static void 3035f18faf3fSek dsl_dataset_clone_swap_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3036f18faf3fSek { 30373cb34c60Sahrens struct cloneswaparg *csa = arg1; 30383cb34c60Sahrens dsl_pool_t *dp = csa->cds->ds_dir->dd_pool; 3039f18faf3fSek 3040a9b821a0Sck ASSERT(csa->cds->ds_reserved == 0); 3041a9b821a0Sck ASSERT(csa->cds->ds_quota == csa->ohds->ds_quota); 3042a9b821a0Sck 30433cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); 30443cb34c60Sahrens dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); 30453cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_prev->ds_dbuf, tx); 3046f18faf3fSek 30473cb34c60Sahrens if (csa->cds->ds_user_ptr != NULL) { 30483cb34c60Sahrens csa->cds->ds_user_evict_func(csa->cds, csa->cds->ds_user_ptr); 30493cb34c60Sahrens csa->cds->ds_user_ptr = NULL; 30503cb34c60Sahrens } 3051f18faf3fSek 30523cb34c60Sahrens if (csa->ohds->ds_user_ptr != NULL) { 30533cb34c60Sahrens csa->ohds->ds_user_evict_func(csa->ohds, 30543cb34c60Sahrens csa->ohds->ds_user_ptr); 30553cb34c60Sahrens csa->ohds->ds_user_ptr = NULL; 30563cb34c60Sahrens } 3057f18faf3fSek 3058f18faf3fSek /* reset origin's unique bytes */ 305974e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->cds->ds_deadlist, 306074e7dc98SMatthew Ahrens csa->cds->ds_prev->ds_phys->ds_prev_snap_txg, UINT64_MAX, 306174e7dc98SMatthew Ahrens &csa->cds->ds_prev->ds_phys->ds_unique_bytes)); 3062f18faf3fSek 3063f18faf3fSek /* swap blkptrs */ 3064f18faf3fSek { 3065f18faf3fSek blkptr_t tmp; 30663cb34c60Sahrens tmp = csa->ohds->ds_phys->ds_bp; 30673cb34c60Sahrens csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp; 30683cb34c60Sahrens csa->cds->ds_phys->ds_bp = tmp; 3069f18faf3fSek } 3070f18faf3fSek 3071f18faf3fSek /* set dd_*_bytes */ 3072f18faf3fSek { 3073f18faf3fSek int64_t dused, dcomp, duncomp; 3074f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 3075f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 3076f18faf3fSek 307774e7dc98SMatthew Ahrens ASSERT3U(csa->cds->ds_dir->dd_phys-> 307874e7dc98SMatthew Ahrens dd_used_breakdown[DD_USED_SNAP], ==, 0); 307974e7dc98SMatthew Ahrens 30803cb34c60Sahrens VERIFY(0 == bplist_space(&csa->cds->ds_deadlist, &cdl_used, 3081f18faf3fSek &cdl_comp, &cdl_uncomp)); 30823cb34c60Sahrens VERIFY(0 == bplist_space(&csa->ohds->ds_deadlist, &odl_used, 3083f18faf3fSek &odl_comp, &odl_uncomp)); 308474e7dc98SMatthew Ahrens 30853cb34c60Sahrens dused = csa->cds->ds_phys->ds_used_bytes + cdl_used - 30863cb34c60Sahrens (csa->ohds->ds_phys->ds_used_bytes + odl_used); 30873cb34c60Sahrens dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp - 30883cb34c60Sahrens (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp); 30893cb34c60Sahrens duncomp = csa->cds->ds_phys->ds_uncompressed_bytes + 30903cb34c60Sahrens cdl_uncomp - 30913cb34c60Sahrens (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 30923cb34c60Sahrens 309374e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_HEAD, 30943cb34c60Sahrens dused, dcomp, duncomp, tx); 309574e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->cds->ds_dir, DD_USED_HEAD, 30963cb34c60Sahrens -dused, -dcomp, -duncomp, tx); 309774e7dc98SMatthew Ahrens 309874e7dc98SMatthew Ahrens /* 309974e7dc98SMatthew Ahrens * The difference in the space used by snapshots is the 310074e7dc98SMatthew Ahrens * difference in snapshot space due to the head's 310174e7dc98SMatthew Ahrens * deadlist (since that's the only thing that's 310274e7dc98SMatthew Ahrens * changing that affects the snapused). 310374e7dc98SMatthew Ahrens */ 310474e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->cds->ds_deadlist, 310574e7dc98SMatthew Ahrens csa->ohds->ds_origin_txg, UINT64_MAX, &cdl_used)); 310674e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->ohds->ds_deadlist, 310774e7dc98SMatthew Ahrens csa->ohds->ds_origin_txg, UINT64_MAX, &odl_used)); 310874e7dc98SMatthew Ahrens dsl_dir_transfer_space(csa->ohds->ds_dir, cdl_used - odl_used, 310974e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 31103cb34c60Sahrens } 31113cb34c60Sahrens 31123cb34c60Sahrens #define SWITCH64(x, y) \ 31133cb34c60Sahrens { \ 31143cb34c60Sahrens uint64_t __tmp = (x); \ 31153cb34c60Sahrens (x) = (y); \ 31163cb34c60Sahrens (y) = __tmp; \ 3117f18faf3fSek } 3118f18faf3fSek 3119f18faf3fSek /* swap ds_*_bytes */ 31203cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_used_bytes, 31213cb34c60Sahrens csa->cds->ds_phys->ds_used_bytes); 31223cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes, 31233cb34c60Sahrens csa->cds->ds_phys->ds_compressed_bytes); 31243cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, 31253cb34c60Sahrens csa->cds->ds_phys->ds_uncompressed_bytes); 3126a9b821a0Sck SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, 3127a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 3128a9b821a0Sck 3129a9b821a0Sck /* apply any parent delta for change in unconsumed refreservation */ 313074e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_REFRSRV, 313174e7dc98SMatthew Ahrens csa->unused_refres_delta, 0, 0, tx); 3132f18faf3fSek 3133f18faf3fSek /* swap deadlists */ 31343cb34c60Sahrens bplist_close(&csa->cds->ds_deadlist); 31353cb34c60Sahrens bplist_close(&csa->ohds->ds_deadlist); 31363cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj, 31373cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj); 31383cb34c60Sahrens VERIFY(0 == bplist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset, 31393cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj)); 31403cb34c60Sahrens VERIFY(0 == bplist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, 31413cb34c60Sahrens csa->ohds->ds_phys->ds_deadlist_obj)); 314288b7b0f2SMatthew Ahrens 314388b7b0f2SMatthew Ahrens dsl_pool_ds_clone_swapped(csa->ohds, csa->cds, tx); 3144f18faf3fSek } 3145f18faf3fSek 3146f18faf3fSek /* 3147745cd3c5Smaybee * Swap 'clone' with its origin head file system. Used at the end 3148745cd3c5Smaybee * of "online recv" to swizzle the file system to the new version. 3149f18faf3fSek */ 3150f18faf3fSek int 31513cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, 31523cb34c60Sahrens boolean_t force) 3153f18faf3fSek { 31543cb34c60Sahrens struct cloneswaparg csa; 3155745cd3c5Smaybee int error; 3156f18faf3fSek 3157745cd3c5Smaybee ASSERT(clone->ds_owner); 3158745cd3c5Smaybee ASSERT(origin_head->ds_owner); 3159745cd3c5Smaybee retry: 3160745cd3c5Smaybee /* Need exclusive access for the swap */ 3161745cd3c5Smaybee rw_enter(&clone->ds_rwlock, RW_WRITER); 3162745cd3c5Smaybee if (!rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) { 3163745cd3c5Smaybee rw_exit(&clone->ds_rwlock); 3164745cd3c5Smaybee rw_enter(&origin_head->ds_rwlock, RW_WRITER); 3165745cd3c5Smaybee if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) { 3166745cd3c5Smaybee rw_exit(&origin_head->ds_rwlock); 3167745cd3c5Smaybee goto retry; 3168745cd3c5Smaybee } 3169745cd3c5Smaybee } 31703cb34c60Sahrens csa.cds = clone; 31713cb34c60Sahrens csa.ohds = origin_head; 31723cb34c60Sahrens csa.force = force; 3173745cd3c5Smaybee error = dsl_sync_task_do(clone->ds_dir->dd_pool, 3174f18faf3fSek dsl_dataset_clone_swap_check, 3175745cd3c5Smaybee dsl_dataset_clone_swap_sync, &csa, NULL, 9); 3176745cd3c5Smaybee return (error); 3177f18faf3fSek } 3178f18faf3fSek 3179b1b8ab34Slling /* 3180b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 3181b1b8ab34Slling * return the name of that dataset. 3182b1b8ab34Slling */ 3183b1b8ab34Slling int 3184b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 3185b1b8ab34Slling { 3186b1b8ab34Slling spa_t *spa; 3187b1b8ab34Slling dsl_pool_t *dp; 3188745cd3c5Smaybee dsl_dataset_t *ds; 3189b1b8ab34Slling int error; 3190b1b8ab34Slling 3191b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 3192b1b8ab34Slling return (error); 3193b1b8ab34Slling dp = spa_get_dsl(spa); 3194b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 3195745cd3c5Smaybee if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) { 3196745cd3c5Smaybee dsl_dataset_name(ds, buf); 3197745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3198b1b8ab34Slling } 3199b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 3200b1b8ab34Slling spa_close(spa, FTAG); 3201b1b8ab34Slling 3202745cd3c5Smaybee return (error); 3203b1b8ab34Slling } 3204a9799022Sck 3205a9799022Sck int 3206a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, 3207745cd3c5Smaybee uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv) 3208a9799022Sck { 3209a9799022Sck int error = 0; 3210a9799022Sck 3211a9799022Sck ASSERT3S(asize, >, 0); 3212a9799022Sck 32139082849eSck /* 32149082849eSck * *ref_rsrv is the portion of asize that will come from any 32159082849eSck * unconsumed refreservation space. 32169082849eSck */ 32179082849eSck *ref_rsrv = 0; 32189082849eSck 3219a9799022Sck mutex_enter(&ds->ds_lock); 3220a9799022Sck /* 3221a9799022Sck * Make a space adjustment for reserved bytes. 3222a9799022Sck */ 3223a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) { 3224a9799022Sck ASSERT3U(*used, >=, 3225a9799022Sck ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 3226a9799022Sck *used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 32279082849eSck *ref_rsrv = 32289082849eSck asize - MIN(asize, parent_delta(ds, asize + inflight)); 3229a9799022Sck } 3230a9799022Sck 3231a9799022Sck if (!check_quota || ds->ds_quota == 0) { 3232a9799022Sck mutex_exit(&ds->ds_lock); 3233a9799022Sck return (0); 3234a9799022Sck } 3235a9799022Sck /* 3236a9799022Sck * If they are requesting more space, and our current estimate 3237a9799022Sck * is over quota, they get to try again unless the actual 3238a9799022Sck * on-disk is over quota and there are no pending changes (which 3239a9799022Sck * may free up space for us). 3240a9799022Sck */ 3241a9799022Sck if (ds->ds_phys->ds_used_bytes + inflight >= ds->ds_quota) { 3242a9799022Sck if (inflight > 0 || ds->ds_phys->ds_used_bytes < ds->ds_quota) 3243a9799022Sck error = ERESTART; 3244a9799022Sck else 3245a9799022Sck error = EDQUOT; 3246a9799022Sck } 3247a9799022Sck mutex_exit(&ds->ds_lock); 3248a9799022Sck 3249a9799022Sck return (error); 3250a9799022Sck } 3251a9799022Sck 3252a9799022Sck /* ARGSUSED */ 3253a9799022Sck static int 3254a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx) 3255a9799022Sck { 3256a9799022Sck dsl_dataset_t *ds = arg1; 3257a9799022Sck uint64_t *quotap = arg2; 3258a9799022Sck uint64_t new_quota = *quotap; 3259a9799022Sck 3260a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA) 3261a9799022Sck return (ENOTSUP); 3262a9799022Sck 3263a9799022Sck if (new_quota == 0) 3264a9799022Sck return (0); 3265a9799022Sck 3266a9799022Sck if (new_quota < ds->ds_phys->ds_used_bytes || 3267a9799022Sck new_quota < ds->ds_reserved) 3268a9799022Sck return (ENOSPC); 3269a9799022Sck 3270a9799022Sck return (0); 3271a9799022Sck } 3272a9799022Sck 3273a9799022Sck /* ARGSUSED */ 3274a9799022Sck void 3275a9799022Sck dsl_dataset_set_quota_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3276a9799022Sck { 3277a9799022Sck dsl_dataset_t *ds = arg1; 3278a9799022Sck uint64_t *quotap = arg2; 3279a9799022Sck uint64_t new_quota = *quotap; 3280a9799022Sck 3281a9799022Sck dmu_buf_will_dirty(ds->ds_dbuf, tx); 3282a9799022Sck 3283a9799022Sck ds->ds_quota = new_quota; 3284a9799022Sck 3285*842727c2SChris Kirby dsl_dir_prop_set_uint64_sync(ds->ds_dir, "refquota", new_quota, cr, tx); 3286a9799022Sck 3287a9799022Sck spa_history_internal_log(LOG_DS_REFQUOTA, ds->ds_dir->dd_pool->dp_spa, 3288a9799022Sck tx, cr, "%lld dataset = %llu ", 3289745cd3c5Smaybee (longlong_t)new_quota, ds->ds_object); 3290a9799022Sck } 3291a9799022Sck 3292a9799022Sck int 3293a9799022Sck dsl_dataset_set_quota(const char *dsname, uint64_t quota) 3294a9799022Sck { 3295a9799022Sck dsl_dataset_t *ds; 3296a9799022Sck int err; 3297a9799022Sck 3298745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3299a9799022Sck if (err) 3300a9799022Sck return (err); 3301a9799022Sck 3302a9b821a0Sck if (quota != ds->ds_quota) { 3303a9b821a0Sck /* 3304a9b821a0Sck * If someone removes a file, then tries to set the quota, we 3305a9b821a0Sck * want to make sure the file freeing takes effect. 3306a9b821a0Sck */ 3307a9b821a0Sck txg_wait_open(ds->ds_dir->dd_pool, 0); 3308a9799022Sck 3309a9b821a0Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3310a9b821a0Sck dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, 3311a9b821a0Sck ds, "a, 0); 3312a9b821a0Sck } 3313745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3314a9799022Sck return (err); 3315a9799022Sck } 3316a9799022Sck 3317a9799022Sck static int 3318a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx) 3319a9799022Sck { 3320a9799022Sck dsl_dataset_t *ds = arg1; 3321a9799022Sck uint64_t *reservationp = arg2; 3322a9799022Sck uint64_t new_reservation = *reservationp; 3323a9799022Sck uint64_t unique; 3324a9799022Sck 3325a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 3326a9799022Sck SPA_VERSION_REFRESERVATION) 3327a9799022Sck return (ENOTSUP); 3328a9799022Sck 3329a9799022Sck if (dsl_dataset_is_snapshot(ds)) 3330a9799022Sck return (EINVAL); 3331a9799022Sck 3332a9799022Sck /* 3333a9799022Sck * If we are doing the preliminary check in open context, the 3334a9799022Sck * space estimates may be inaccurate. 3335a9799022Sck */ 3336a9799022Sck if (!dmu_tx_is_syncing(tx)) 3337a9799022Sck return (0); 3338a9799022Sck 3339a9799022Sck mutex_enter(&ds->ds_lock); 3340a9799022Sck unique = dsl_dataset_unique(ds); 3341a9799022Sck mutex_exit(&ds->ds_lock); 3342a9799022Sck 3343379c004dSEric Schrock if (MAX(unique, new_reservation) > MAX(unique, ds->ds_reserved)) { 3344379c004dSEric Schrock uint64_t delta = MAX(unique, new_reservation) - 3345379c004dSEric Schrock MAX(unique, ds->ds_reserved); 3346379c004dSEric Schrock 3347379c004dSEric Schrock if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 3348379c004dSEric Schrock return (ENOSPC); 3349379c004dSEric Schrock if (ds->ds_quota > 0 && 3350379c004dSEric Schrock new_reservation > ds->ds_quota) 3351379c004dSEric Schrock return (ENOSPC); 3352379c004dSEric Schrock } 3353a9799022Sck 3354a9799022Sck return (0); 3355a9799022Sck } 3356a9799022Sck 3357a9799022Sck /* ARGSUSED */ 3358a9799022Sck static void 3359a9799022Sck dsl_dataset_set_reservation_sync(void *arg1, void *arg2, cred_t *cr, 3360a9799022Sck dmu_tx_t *tx) 3361a9799022Sck { 3362a9799022Sck dsl_dataset_t *ds = arg1; 3363a9799022Sck uint64_t *reservationp = arg2; 3364a9799022Sck uint64_t new_reservation = *reservationp; 336502c8f3f0SMatthew Ahrens uint64_t unique; 336602c8f3f0SMatthew Ahrens int64_t delta; 336702c8f3f0SMatthew Ahrens 336802c8f3f0SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 336902c8f3f0SMatthew Ahrens 337002c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 337102c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_lock); 337202c8f3f0SMatthew Ahrens unique = dsl_dataset_unique(ds); 337302c8f3f0SMatthew Ahrens delta = MAX(0, (int64_t)(new_reservation - unique)) - 337402c8f3f0SMatthew Ahrens MAX(0, (int64_t)(ds->ds_reserved - unique)); 337502c8f3f0SMatthew Ahrens ds->ds_reserved = new_reservation; 337602c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_lock); 337702c8f3f0SMatthew Ahrens 337802c8f3f0SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx); 337902c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 3380*842727c2SChris Kirby dsl_dir_prop_set_uint64_sync(ds->ds_dir, "refreservation", 338102c8f3f0SMatthew Ahrens new_reservation, cr, tx); 3382a9799022Sck 338302c8f3f0SMatthew Ahrens spa_history_internal_log(LOG_DS_REFRESERV, 338402c8f3f0SMatthew Ahrens ds->ds_dir->dd_pool->dp_spa, tx, cr, "%lld dataset = %llu", 338502c8f3f0SMatthew Ahrens (longlong_t)new_reservation, ds->ds_object); 3386a9799022Sck } 3387a9799022Sck 3388a9799022Sck int 3389a9799022Sck dsl_dataset_set_reservation(const char *dsname, uint64_t reservation) 3390a9799022Sck { 3391a9799022Sck dsl_dataset_t *ds; 3392a9799022Sck int err; 3393a9799022Sck 3394745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3395a9799022Sck if (err) 3396a9799022Sck return (err); 3397a9799022Sck 3398a9799022Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3399a9799022Sck dsl_dataset_set_reservation_check, 3400a9799022Sck dsl_dataset_set_reservation_sync, ds, &reservation, 0); 3401745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3402a9799022Sck return (err); 3403a9799022Sck } 3404*842727c2SChris Kirby 3405*842727c2SChris Kirby static int 3406*842727c2SChris Kirby dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx) 3407*842727c2SChris Kirby { 3408*842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3409*842727c2SChris Kirby char *htag = arg2; 3410*842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3411*842727c2SChris Kirby int error = 0; 3412*842727c2SChris Kirby 3413*842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3414*842727c2SChris Kirby return (ENOTSUP); 3415*842727c2SChris Kirby 3416*842727c2SChris Kirby if (!dsl_dataset_is_snapshot(ds)) 3417*842727c2SChris Kirby return (EINVAL); 3418*842727c2SChris Kirby 3419*842727c2SChris Kirby if (strlen(htag) >= ZAP_MAXNAMELEN) 3420*842727c2SChris Kirby return (ENAMETOOLONG); 3421*842727c2SChris Kirby 3422*842727c2SChris Kirby /* tags must be unique */ 3423*842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3424*842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj) { 3425*842727c2SChris Kirby error = zap_lookup(mos, ds->ds_phys->ds_userrefs_obj, htag, 3426*842727c2SChris Kirby 8, 1, tx); 3427*842727c2SChris Kirby if (error == 0) 3428*842727c2SChris Kirby error = EEXIST; 3429*842727c2SChris Kirby else if (error == ENOENT) 3430*842727c2SChris Kirby error = 0; 3431*842727c2SChris Kirby } 3432*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3433*842727c2SChris Kirby 3434*842727c2SChris Kirby return (error); 3435*842727c2SChris Kirby } 3436*842727c2SChris Kirby 3437*842727c2SChris Kirby static void 3438*842727c2SChris Kirby dsl_dataset_user_hold_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3439*842727c2SChris Kirby { 3440*842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3441*842727c2SChris Kirby char *htag = arg2; 3442*842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3443*842727c2SChris Kirby time_t now = gethrestime_sec(); 3444*842727c2SChris Kirby uint64_t zapobj; 3445*842727c2SChris Kirby 3446*842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3447*842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj == 0) { 3448*842727c2SChris Kirby /* 3449*842727c2SChris Kirby * This is the first user hold for this dataset. Create 3450*842727c2SChris Kirby * the userrefs zap object. 3451*842727c2SChris Kirby */ 3452*842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 3453*842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj = 3454*842727c2SChris Kirby zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx); 3455*842727c2SChris Kirby } else { 3456*842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3457*842727c2SChris Kirby } 3458*842727c2SChris Kirby ds->ds_userrefs++; 3459*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3460*842727c2SChris Kirby 3461*842727c2SChris Kirby VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx)); 3462*842727c2SChris Kirby 3463*842727c2SChris Kirby spa_history_internal_log(LOG_DS_USER_HOLD, 3464*842727c2SChris Kirby ds->ds_dir->dd_pool->dp_spa, tx, cr, "<%s> dataset = %llu", 3465*842727c2SChris Kirby htag, ds->ds_object); 3466*842727c2SChris Kirby } 3467*842727c2SChris Kirby 3468*842727c2SChris Kirby struct dsl_ds_holdarg { 3469*842727c2SChris Kirby dsl_sync_task_group_t *dstg; 3470*842727c2SChris Kirby char *htag; 3471*842727c2SChris Kirby char *snapname; 3472*842727c2SChris Kirby boolean_t recursive; 3473*842727c2SChris Kirby char failed[MAXPATHLEN]; 3474*842727c2SChris Kirby }; 3475*842727c2SChris Kirby 3476*842727c2SChris Kirby static int 3477*842727c2SChris Kirby dsl_dataset_user_hold_one(char *dsname, void *arg) 3478*842727c2SChris Kirby { 3479*842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3480*842727c2SChris Kirby dsl_dataset_t *ds; 3481*842727c2SChris Kirby int error; 3482*842727c2SChris Kirby char *name; 3483*842727c2SChris Kirby size_t buflen; 3484*842727c2SChris Kirby 3485*842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname plus terminating NULL */ 3486*842727c2SChris Kirby buflen = strlen(dsname) + strlen(ha->snapname) + 2; 3487*842727c2SChris Kirby name = kmem_alloc(buflen, KM_SLEEP); 3488*842727c2SChris Kirby (void) snprintf(name, buflen, "%s@%s", dsname, ha->snapname); 3489*842727c2SChris Kirby error = dsl_dataset_hold(name, ha->dstg, &ds); 3490*842727c2SChris Kirby kmem_free(name, buflen); 3491*842727c2SChris Kirby if (error == 0) { 3492*842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check, 3493*842727c2SChris Kirby dsl_dataset_user_hold_sync, ds, ha->htag, 0); 3494*842727c2SChris Kirby } else if (error == ENOENT && ha->recursive) { 3495*842727c2SChris Kirby error = 0; 3496*842727c2SChris Kirby } else { 3497*842727c2SChris Kirby (void) strcpy(ha->failed, dsname); 3498*842727c2SChris Kirby } 3499*842727c2SChris Kirby return (error); 3500*842727c2SChris Kirby } 3501*842727c2SChris Kirby 3502*842727c2SChris Kirby int 3503*842727c2SChris Kirby dsl_dataset_user_hold(char *dsname, char *snapname, char *htag, 3504*842727c2SChris Kirby boolean_t recursive) 3505*842727c2SChris Kirby { 3506*842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3507*842727c2SChris Kirby dsl_sync_task_t *dst; 3508*842727c2SChris Kirby spa_t *spa; 3509*842727c2SChris Kirby int error; 3510*842727c2SChris Kirby 3511*842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3512*842727c2SChris Kirby 3513*842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3514*842727c2SChris Kirby 3515*842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3516*842727c2SChris Kirby if (error) { 3517*842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3518*842727c2SChris Kirby return (error); 3519*842727c2SChris Kirby } 3520*842727c2SChris Kirby 3521*842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3522*842727c2SChris Kirby ha->htag = htag; 3523*842727c2SChris Kirby ha->snapname = snapname; 3524*842727c2SChris Kirby ha->recursive = recursive; 3525*842727c2SChris Kirby if (recursive) { 3526*842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_hold_one, 3527*842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3528*842727c2SChris Kirby } else { 3529*842727c2SChris Kirby error = dsl_dataset_user_hold_one(dsname, ha); 3530*842727c2SChris Kirby } 3531*842727c2SChris Kirby if (error == 0) 3532*842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3533*842727c2SChris Kirby 3534*842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3535*842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3536*842727c2SChris Kirby dsl_dataset_t *ds = dst->dst_arg1; 3537*842727c2SChris Kirby 3538*842727c2SChris Kirby if (dst->dst_err) { 3539*842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3540*842727c2SChris Kirby *strchr(ha->failed, '@') = '\0'; 3541*842727c2SChris Kirby } 3542*842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3543*842727c2SChris Kirby } 3544*842727c2SChris Kirby 3545*842727c2SChris Kirby if (error) 3546*842727c2SChris Kirby (void) strcpy(dsname, ha->failed); 3547*842727c2SChris Kirby 3548*842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3549*842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3550*842727c2SChris Kirby spa_close(spa, FTAG); 3551*842727c2SChris Kirby return (error); 3552*842727c2SChris Kirby } 3553*842727c2SChris Kirby 3554*842727c2SChris Kirby struct dsl_ds_releasearg { 3555*842727c2SChris Kirby dsl_dataset_t *ds; 3556*842727c2SChris Kirby const char *htag; 3557*842727c2SChris Kirby boolean_t own; /* do we own or just hold ds? */ 3558*842727c2SChris Kirby }; 3559*842727c2SChris Kirby 3560*842727c2SChris Kirby static int 3561*842727c2SChris Kirby dsl_dataset_release_might_destroy(dsl_dataset_t *ds, const char *htag, 3562*842727c2SChris Kirby boolean_t *might_destroy) 3563*842727c2SChris Kirby { 3564*842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3565*842727c2SChris Kirby uint64_t zapobj; 3566*842727c2SChris Kirby uint64_t tmp; 3567*842727c2SChris Kirby int error; 3568*842727c2SChris Kirby 3569*842727c2SChris Kirby *might_destroy = B_FALSE; 3570*842727c2SChris Kirby 3571*842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3572*842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3573*842727c2SChris Kirby if (zapobj == 0) { 3574*842727c2SChris Kirby /* The tag can't possibly exist */ 3575*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3576*842727c2SChris Kirby return (ESRCH); 3577*842727c2SChris Kirby } 3578*842727c2SChris Kirby 3579*842727c2SChris Kirby /* Make sure the tag exists */ 3580*842727c2SChris Kirby error = zap_lookup(mos, zapobj, htag, 8, 1, &tmp); 3581*842727c2SChris Kirby if (error) { 3582*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3583*842727c2SChris Kirby if (error == ENOENT) 3584*842727c2SChris Kirby error = ESRCH; 3585*842727c2SChris Kirby return (error); 3586*842727c2SChris Kirby } 3587*842727c2SChris Kirby 3588*842727c2SChris Kirby if (ds->ds_userrefs == 1 && ds->ds_phys->ds_num_children == 1 && 3589*842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 3590*842727c2SChris Kirby *might_destroy = B_TRUE; 3591*842727c2SChris Kirby 3592*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3593*842727c2SChris Kirby return (0); 3594*842727c2SChris Kirby } 3595*842727c2SChris Kirby 3596*842727c2SChris Kirby static int 3597*842727c2SChris Kirby dsl_dataset_user_release_check(void *arg1, void *tag, dmu_tx_t *tx) 3598*842727c2SChris Kirby { 3599*842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3600*842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3601*842727c2SChris Kirby boolean_t might_destroy; 3602*842727c2SChris Kirby int error; 3603*842727c2SChris Kirby 3604*842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3605*842727c2SChris Kirby return (ENOTSUP); 3606*842727c2SChris Kirby 3607*842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ra->htag, &might_destroy); 3608*842727c2SChris Kirby if (error) 3609*842727c2SChris Kirby return (error); 3610*842727c2SChris Kirby 3611*842727c2SChris Kirby if (might_destroy) { 3612*842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3613*842727c2SChris Kirby 3614*842727c2SChris Kirby if (dmu_tx_is_syncing(tx)) { 3615*842727c2SChris Kirby /* 3616*842727c2SChris Kirby * If we're not prepared to remove the snapshot, 3617*842727c2SChris Kirby * we can't allow the release to happen right now. 3618*842727c2SChris Kirby */ 3619*842727c2SChris Kirby if (!ra->own) 3620*842727c2SChris Kirby return (EBUSY); 3621*842727c2SChris Kirby if (ds->ds_user_ptr) { 3622*842727c2SChris Kirby ds->ds_user_evict_func(ds, ds->ds_user_ptr); 3623*842727c2SChris Kirby ds->ds_user_ptr = NULL; 3624*842727c2SChris Kirby } 3625*842727c2SChris Kirby } 3626*842727c2SChris Kirby dsda.ds = ds; 3627*842727c2SChris Kirby dsda.releasing = B_TRUE; 3628*842727c2SChris Kirby return (dsl_dataset_destroy_check(&dsda, tag, tx)); 3629*842727c2SChris Kirby } 3630*842727c2SChris Kirby 3631*842727c2SChris Kirby return (0); 3632*842727c2SChris Kirby } 3633*842727c2SChris Kirby 3634*842727c2SChris Kirby static void 3635*842727c2SChris Kirby dsl_dataset_user_release_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 3636*842727c2SChris Kirby { 3637*842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3638*842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3639*842727c2SChris Kirby spa_t *spa = ds->ds_dir->dd_pool->dp_spa; 3640*842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3641*842727c2SChris Kirby uint64_t zapobj; 3642*842727c2SChris Kirby uint64_t dsobj = ds->ds_object; 3643*842727c2SChris Kirby uint64_t refs; 3644*842727c2SChris Kirby 3645*842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3646*842727c2SChris Kirby ds->ds_userrefs--; 3647*842727c2SChris Kirby refs = ds->ds_userrefs; 3648*842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3649*842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3650*842727c2SChris Kirby VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx)); 3651*842727c2SChris Kirby if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 && 3652*842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) { 3653*842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3654*842727c2SChris Kirby 3655*842727c2SChris Kirby ASSERT(ra->own); 3656*842727c2SChris Kirby dsda.ds = ds; 3657*842727c2SChris Kirby dsda.releasing = B_TRUE; 3658*842727c2SChris Kirby /* We already did the destroy_check */ 3659*842727c2SChris Kirby dsl_dataset_destroy_sync(&dsda, tag, cr, tx); 3660*842727c2SChris Kirby } 3661*842727c2SChris Kirby 3662*842727c2SChris Kirby spa_history_internal_log(LOG_DS_USER_RELEASE, 3663*842727c2SChris Kirby spa, tx, cr, "<%s> %lld dataset = %llu", 3664*842727c2SChris Kirby ra->htag, (longlong_t)refs, dsobj); 3665*842727c2SChris Kirby } 3666*842727c2SChris Kirby 3667*842727c2SChris Kirby static int 3668*842727c2SChris Kirby dsl_dataset_user_release_one(char *dsname, void *arg) 3669*842727c2SChris Kirby { 3670*842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3671*842727c2SChris Kirby struct dsl_ds_releasearg *ra; 3672*842727c2SChris Kirby dsl_dataset_t *ds; 3673*842727c2SChris Kirby int error; 3674*842727c2SChris Kirby void *dtag = ha->dstg; 3675*842727c2SChris Kirby char *name; 3676*842727c2SChris Kirby size_t buflen; 3677*842727c2SChris Kirby boolean_t own = B_FALSE; 3678*842727c2SChris Kirby boolean_t might_destroy; 3679*842727c2SChris Kirby 3680*842727c2SChris Kirby if (strlen(ha->htag) >= ZAP_MAXNAMELEN) 3681*842727c2SChris Kirby return (ENAMETOOLONG); 3682*842727c2SChris Kirby 3683*842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname, plus the terminating NULL */ 3684*842727c2SChris Kirby buflen = strlen(dsname) + strlen(ha->snapname) + 2; 3685*842727c2SChris Kirby name = kmem_alloc(buflen, KM_SLEEP); 3686*842727c2SChris Kirby (void) snprintf(name, buflen, "%s@%s", dsname, ha->snapname); 3687*842727c2SChris Kirby error = dsl_dataset_hold(name, dtag, &ds); 3688*842727c2SChris Kirby kmem_free(name, buflen); 3689*842727c2SChris Kirby if (error == ENOENT && ha->recursive) 3690*842727c2SChris Kirby return (0); 3691*842727c2SChris Kirby (void) strcpy(ha->failed, dsname); 3692*842727c2SChris Kirby if (error) 3693*842727c2SChris Kirby return (error); 3694*842727c2SChris Kirby 3695*842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 3696*842727c2SChris Kirby 3697*842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ha->htag, &might_destroy); 3698*842727c2SChris Kirby if (error) { 3699*842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3700*842727c2SChris Kirby return (error); 3701*842727c2SChris Kirby } 3702*842727c2SChris Kirby 3703*842727c2SChris Kirby if (might_destroy) { 3704*842727c2SChris Kirby #ifdef _KERNEL 3705*842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 3706*842727c2SChris Kirby if (error) { 3707*842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3708*842727c2SChris Kirby return (error); 3709*842727c2SChris Kirby } 3710*842727c2SChris Kirby error = dsl_dataset_zvol_cleanup(ds, name); 3711*842727c2SChris Kirby if (error) { 3712*842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3713*842727c2SChris Kirby return (error); 3714*842727c2SChris Kirby } 3715*842727c2SChris Kirby #endif 3716*842727c2SChris Kirby if (!dsl_dataset_tryown(ds, 3717*842727c2SChris Kirby DS_MODE_READONLY | DS_MODE_INCONSISTENT, dtag)) { 3718*842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3719*842727c2SChris Kirby return (EBUSY); 3720*842727c2SChris Kirby } else { 3721*842727c2SChris Kirby own = B_TRUE; 3722*842727c2SChris Kirby dsl_dataset_make_exclusive(ds, dtag); 3723*842727c2SChris Kirby } 3724*842727c2SChris Kirby } 3725*842727c2SChris Kirby 3726*842727c2SChris Kirby ra = kmem_alloc(sizeof (struct dsl_ds_releasearg), KM_SLEEP); 3727*842727c2SChris Kirby ra->ds = ds; 3728*842727c2SChris Kirby ra->htag = ha->htag; 3729*842727c2SChris Kirby ra->own = own; 3730*842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_release_check, 3731*842727c2SChris Kirby dsl_dataset_user_release_sync, ra, dtag, 0); 3732*842727c2SChris Kirby 3733*842727c2SChris Kirby return (0); 3734*842727c2SChris Kirby } 3735*842727c2SChris Kirby 3736*842727c2SChris Kirby int 3737*842727c2SChris Kirby dsl_dataset_user_release(char *dsname, char *snapname, char *htag, 3738*842727c2SChris Kirby boolean_t recursive) 3739*842727c2SChris Kirby { 3740*842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3741*842727c2SChris Kirby dsl_sync_task_t *dst; 3742*842727c2SChris Kirby spa_t *spa; 3743*842727c2SChris Kirby int error; 3744*842727c2SChris Kirby 3745*842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3746*842727c2SChris Kirby 3747*842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3748*842727c2SChris Kirby 3749*842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3750*842727c2SChris Kirby if (error) { 3751*842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3752*842727c2SChris Kirby return (error); 3753*842727c2SChris Kirby } 3754*842727c2SChris Kirby 3755*842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3756*842727c2SChris Kirby ha->htag = htag; 3757*842727c2SChris Kirby ha->snapname = snapname; 3758*842727c2SChris Kirby ha->recursive = recursive; 3759*842727c2SChris Kirby if (recursive) { 3760*842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_release_one, 3761*842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3762*842727c2SChris Kirby } else { 3763*842727c2SChris Kirby error = dsl_dataset_user_release_one(dsname, ha); 3764*842727c2SChris Kirby } 3765*842727c2SChris Kirby if (error == 0) 3766*842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3767*842727c2SChris Kirby 3768*842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3769*842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3770*842727c2SChris Kirby struct dsl_ds_releasearg *ra = dst->dst_arg1; 3771*842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3772*842727c2SChris Kirby 3773*842727c2SChris Kirby if (dst->dst_err) 3774*842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3775*842727c2SChris Kirby 3776*842727c2SChris Kirby if (ra->own) 3777*842727c2SChris Kirby dsl_dataset_disown(ds, ha->dstg); 3778*842727c2SChris Kirby else 3779*842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3780*842727c2SChris Kirby 3781*842727c2SChris Kirby kmem_free(ra, sizeof (struct dsl_ds_releasearg)); 3782*842727c2SChris Kirby } 3783*842727c2SChris Kirby 3784*842727c2SChris Kirby if (error) 3785*842727c2SChris Kirby (void) strcpy(dsname, ha->failed); 3786*842727c2SChris Kirby 3787*842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3788*842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3789*842727c2SChris Kirby spa_close(spa, FTAG); 3790*842727c2SChris Kirby return (error); 3791*842727c2SChris Kirby } 3792*842727c2SChris Kirby 3793*842727c2SChris Kirby int 3794*842727c2SChris Kirby dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp) 3795*842727c2SChris Kirby { 3796*842727c2SChris Kirby dsl_dataset_t *ds; 3797*842727c2SChris Kirby int err; 3798*842727c2SChris Kirby 3799*842727c2SChris Kirby err = dsl_dataset_hold(dsname, FTAG, &ds); 3800*842727c2SChris Kirby if (err) 3801*842727c2SChris Kirby return (err); 3802*842727c2SChris Kirby 3803*842727c2SChris Kirby VERIFY(0 == nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP)); 3804*842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) { 3805*842727c2SChris Kirby zap_attribute_t *za; 3806*842727c2SChris Kirby zap_cursor_t zc; 3807*842727c2SChris Kirby 3808*842727c2SChris Kirby za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 3809*842727c2SChris Kirby for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset, 3810*842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj); 3811*842727c2SChris Kirby zap_cursor_retrieve(&zc, za) == 0; 3812*842727c2SChris Kirby zap_cursor_advance(&zc)) { 3813*842727c2SChris Kirby VERIFY(0 == nvlist_add_uint64(*nvp, za->za_name, 3814*842727c2SChris Kirby za->za_first_integer)); 3815*842727c2SChris Kirby } 3816*842727c2SChris Kirby zap_cursor_fini(&zc); 3817*842727c2SChris Kirby kmem_free(za, sizeof (zap_attribute_t)); 3818*842727c2SChris Kirby } 3819*842727c2SChris Kirby dsl_dataset_rele(ds, FTAG); 3820*842727c2SChris Kirby return (0); 3821*842727c2SChris Kirby } 3822