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> 41842727c2SChris Kirby #include <sys/zvol.h> 42fa9e4066Sahrens 43745cd3c5Smaybee static char *dsl_reaper = "the grim reaper"; 44745cd3c5Smaybee 451d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 461d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 47a9799022Sck static dsl_syncfunc_t dsl_dataset_set_reservation_sync; 48e1930233Sbonwick 4955434c77Sek #define DS_REF_MAX (1ULL << 62) 50fa9e4066Sahrens 51fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 52fa9e4066Sahrens 53745cd3c5Smaybee #define DSL_DATASET_IS_DESTROYED(ds) ((ds)->ds_owner == dsl_reaper) 54745cd3c5Smaybee 55fa9e4066Sahrens 56a9799022Sck /* 57a9799022Sck * Figure out how much of this delta should be propogated to the dsl_dir 58a9799022Sck * layer. If there's a refreservation, that space has already been 59a9799022Sck * partially accounted for in our ancestors. 60a9799022Sck */ 61a9799022Sck static int64_t 62a9799022Sck parent_delta(dsl_dataset_t *ds, int64_t delta) 63a9799022Sck { 64a9799022Sck uint64_t old_bytes, new_bytes; 65a9799022Sck 66a9799022Sck if (ds->ds_reserved == 0) 67a9799022Sck return (delta); 68a9799022Sck 69a9799022Sck old_bytes = MAX(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 70a9799022Sck new_bytes = MAX(ds->ds_phys->ds_unique_bytes + delta, ds->ds_reserved); 71a9799022Sck 72a9799022Sck ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta)); 73a9799022Sck return (new_bytes - old_bytes); 74a9799022Sck } 75fa9e4066Sahrens 76fa9e4066Sahrens void 77b24ab676SJeff Bonwick dsl_dataset_block_born(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx) 78fa9e4066Sahrens { 79b24ab676SJeff Bonwick int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp); 80fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 81fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 82a9799022Sck int64_t delta; 83fa9e4066Sahrens 84fa9e4066Sahrens dprintf_bp(bp, "born, ds=%p\n", ds); 85fa9e4066Sahrens 86fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 87fa9e4066Sahrens /* It could have been compressed away to nothing */ 88fa9e4066Sahrens if (BP_IS_HOLE(bp)) 89fa9e4066Sahrens return; 90fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 91fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 92fa9e4066Sahrens if (ds == NULL) { 93fa9e4066Sahrens /* 94fa9e4066Sahrens * Account for the meta-objset space in its placeholder 95fa9e4066Sahrens * dsl_dir. 96fa9e4066Sahrens */ 97fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 9874e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 99fa9e4066Sahrens used, compressed, uncompressed, tx); 100fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 101fa9e4066Sahrens return; 102fa9e4066Sahrens } 103fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 10402c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 105fa9e4066Sahrens mutex_enter(&ds->ds_lock); 106a9799022Sck delta = parent_delta(ds, used); 107fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 108fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 109fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 110fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 111fa9e4066Sahrens mutex_exit(&ds->ds_lock); 11274e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, delta, 11374e7dc98SMatthew Ahrens compressed, uncompressed, tx); 11474e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used - delta, 11574e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 11602c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 117fa9e4066Sahrens } 118fa9e4066Sahrens 119cdb0ab79Smaybee int 120b24ab676SJeff Bonwick dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx, 121b24ab676SJeff Bonwick boolean_t async) 122fa9e4066Sahrens { 123fa9e4066Sahrens if (BP_IS_HOLE(bp)) 124cdb0ab79Smaybee return (0); 125fa9e4066Sahrens 126b24ab676SJeff Bonwick ASSERT(dmu_tx_is_syncing(tx)); 127b24ab676SJeff Bonwick ASSERT(bp->blk_birth <= tx->tx_txg); 128b24ab676SJeff Bonwick 129b24ab676SJeff Bonwick int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp); 130b24ab676SJeff Bonwick int compressed = BP_GET_PSIZE(bp); 131b24ab676SJeff Bonwick int uncompressed = BP_GET_UCSIZE(bp); 132b24ab676SJeff Bonwick 133fa9e4066Sahrens ASSERT(used > 0); 134fa9e4066Sahrens if (ds == NULL) { 135fa9e4066Sahrens /* 136fa9e4066Sahrens * Account for the meta-objset space in its placeholder 137fa9e4066Sahrens * dataset. 138fa9e4066Sahrens */ 139b24ab676SJeff Bonwick dsl_free(tx->tx_pool, tx->tx_txg, bp); 140fa9e4066Sahrens 14174e7dc98SMatthew Ahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, DD_USED_HEAD, 142fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 143fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 144cdb0ab79Smaybee return (used); 145fa9e4066Sahrens } 146fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 147fa9e4066Sahrens 14874e7dc98SMatthew Ahrens ASSERT(!dsl_dataset_is_snapshot(ds)); 149fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 150fa9e4066Sahrens 151fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 152a9799022Sck int64_t delta; 153c717a561Smaybee 154fa9e4066Sahrens dprintf_bp(bp, "freeing: %s", ""); 155b24ab676SJeff Bonwick dsl_free(tx->tx_pool, tx->tx_txg, bp); 156fa9e4066Sahrens 15702c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 158fa9e4066Sahrens mutex_enter(&ds->ds_lock); 159a9799022Sck ASSERT(ds->ds_phys->ds_unique_bytes >= used || 160a9799022Sck !DS_UNIQUE_IS_ACCURATE(ds)); 161a9799022Sck delta = parent_delta(ds, -used); 162fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 163fa9e4066Sahrens mutex_exit(&ds->ds_lock); 16474e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_HEAD, 165a9799022Sck delta, -compressed, -uncompressed, tx); 16674e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, -used - delta, 16774e7dc98SMatthew Ahrens DD_USED_REFRSRV, DD_USED_HEAD, tx); 16802c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 169fa9e4066Sahrens } else { 170fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 171b24ab676SJeff Bonwick if (async) { 172b24ab676SJeff Bonwick /* 173b24ab676SJeff Bonwick * We are here as part of zio's write done callback, 174b24ab676SJeff Bonwick * which means we're a zio interrupt thread. We can't 175b24ab676SJeff Bonwick * call bplist_enqueue() now because it may block 176b24ab676SJeff Bonwick * waiting for I/O. Instead, put bp on the deferred 177b24ab676SJeff Bonwick * queue and let dsl_pool_sync() finish the job. 178b24ab676SJeff Bonwick */ 179b24ab676SJeff Bonwick bplist_enqueue_deferred(&ds->ds_deadlist, bp); 180b24ab676SJeff Bonwick } else { 181b24ab676SJeff Bonwick VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 182b24ab676SJeff Bonwick } 183a4611edeSahrens ASSERT3U(ds->ds_prev->ds_object, ==, 184a4611edeSahrens ds->ds_phys->ds_prev_snap_obj); 185a4611edeSahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 186fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 187a4611edeSahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 188a4611edeSahrens ds->ds_object && bp->blk_birth > 189a4611edeSahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 190a4611edeSahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 191a4611edeSahrens mutex_enter(&ds->ds_prev->ds_lock); 192a4611edeSahrens ds->ds_prev->ds_phys->ds_unique_bytes += used; 193a4611edeSahrens mutex_exit(&ds->ds_prev->ds_lock); 194fa9e4066Sahrens } 19574e7dc98SMatthew Ahrens if (bp->blk_birth > ds->ds_origin_txg) { 19674e7dc98SMatthew Ahrens dsl_dir_transfer_space(ds->ds_dir, used, 19774e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 19874e7dc98SMatthew Ahrens } 199fa9e4066Sahrens } 200fa9e4066Sahrens mutex_enter(&ds->ds_lock); 201fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 202fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 203fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 204fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 205fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 206fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 207fa9e4066Sahrens mutex_exit(&ds->ds_lock); 208cdb0ab79Smaybee 209cdb0ab79Smaybee return (used); 210fa9e4066Sahrens } 211fa9e4066Sahrens 212ea8dc4b6Seschrock uint64_t 213ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 214fa9e4066Sahrens { 215a2eea2e1Sahrens uint64_t trysnap = 0; 216a2eea2e1Sahrens 217fa9e4066Sahrens if (ds == NULL) 218ea8dc4b6Seschrock return (0); 219fa9e4066Sahrens /* 220fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 221fa9e4066Sahrens * incorrect FALSE return, which would only result in an 222fa9e4066Sahrens * overestimation of the amount of space that an operation would 223fa9e4066Sahrens * consume, which is OK. 224fa9e4066Sahrens * 225fa9e4066Sahrens * There's also a small window where we could miss a pending 226fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 227fa9e4066Sahrens * phase. So this should only be used as a guess. 228fa9e4066Sahrens */ 229a2eea2e1Sahrens if (ds->ds_trysnap_txg > 230a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 231a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 232a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 233ea8dc4b6Seschrock } 234ea8dc4b6Seschrock 2353d692628SSanjeev Bagewadi boolean_t 236ea8dc4b6Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 237ea8dc4b6Seschrock { 238ea8dc4b6Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 239fa9e4066Sahrens } 240fa9e4066Sahrens 241fa9e4066Sahrens /* ARGSUSED */ 242fa9e4066Sahrens static void 243fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 244fa9e4066Sahrens { 245fa9e4066Sahrens dsl_dataset_t *ds = dsv; 246fa9e4066Sahrens 247745cd3c5Smaybee ASSERT(ds->ds_owner == NULL || DSL_DATASET_IS_DESTROYED(ds)); 248fa9e4066Sahrens 24991ebeef5Sahrens unique_remove(ds->ds_fsid_guid); 250fa9e4066Sahrens 251503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) 252503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 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); 268745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 269745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 270b24ab676SJeff Bonwick bplist_fini(&ds->ds_deadlist); 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 32871eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 32971eb0538SChris Kirby 330745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 331ab04eb8eStimh mt = MT_FIRST; 332ab04eb8eStimh else 333ab04eb8eStimh mt = MT_EXACT; 334ab04eb8eStimh 335745cd3c5Smaybee err = zap_remove_norm(mos, snapobj, name, mt, tx); 336ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 337745cd3c5Smaybee err = zap_remove(mos, snapobj, name, tx); 338ab04eb8eStimh return (err); 339ab04eb8eStimh } 340ab04eb8eStimh 341745cd3c5Smaybee static int 342745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag, 343745cd3c5Smaybee dsl_dataset_t **dsp) 344fa9e4066Sahrens { 345fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 346fa9e4066Sahrens dmu_buf_t *dbuf; 347fa9e4066Sahrens dsl_dataset_t *ds; 348ea8dc4b6Seschrock int err; 349fa9e4066Sahrens 350fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 351fa9e4066Sahrens dsl_pool_sync_context(dp)); 352fa9e4066Sahrens 353ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 354ea8dc4b6Seschrock if (err) 355ea8dc4b6Seschrock return (err); 356fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 357fa9e4066Sahrens if (ds == NULL) { 358fa9e4066Sahrens dsl_dataset_t *winner; 359fa9e4066Sahrens 360fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 361fa9e4066Sahrens ds->ds_dbuf = dbuf; 362fa9e4066Sahrens ds->ds_object = dsobj; 363fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 364fa9e4066Sahrens 3655ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 366f4b94bdeSMatthew Ahrens mutex_init(&ds->ds_recvlock, NULL, MUTEX_DEFAULT, NULL); 36791ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 368745cd3c5Smaybee rw_init(&ds->ds_rwlock, 0, 0, 0); 369745cd3c5Smaybee cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL); 370b24ab676SJeff Bonwick bplist_init(&ds->ds_deadlist); 3715ad82045Snd 372ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 373fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 374ea8dc4b6Seschrock if (err == 0) { 375ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 376ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 377ea8dc4b6Seschrock } 378ea8dc4b6Seschrock if (err) { 379ea8dc4b6Seschrock /* 380ea8dc4b6Seschrock * we don't really need to close the blist if we 381ea8dc4b6Seschrock * just opened it. 382ea8dc4b6Seschrock */ 3835ad82045Snd mutex_destroy(&ds->ds_lock); 384f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 38591ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 386745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 387745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 388b24ab676SJeff Bonwick bplist_fini(&ds->ds_deadlist); 389ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 390ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 391ea8dc4b6Seschrock return (err); 392ea8dc4b6Seschrock } 393fa9e4066Sahrens 39474e7dc98SMatthew Ahrens if (!dsl_dataset_is_snapshot(ds)) { 395fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 396fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 397745cd3c5Smaybee err = dsl_dataset_get_ref(dp, 398745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 399745cd3c5Smaybee ds, &ds->ds_prev); 400fa9e4066Sahrens } 40174e7dc98SMatthew Ahrens 40274e7dc98SMatthew Ahrens if (err == 0 && dsl_dir_is_clone(ds->ds_dir)) { 40374e7dc98SMatthew Ahrens dsl_dataset_t *origin; 40474e7dc98SMatthew Ahrens 40574e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, 40674e7dc98SMatthew Ahrens ds->ds_dir->dd_phys->dd_origin_obj, 40774e7dc98SMatthew Ahrens FTAG, &origin); 40874e7dc98SMatthew Ahrens if (err == 0) { 40974e7dc98SMatthew Ahrens ds->ds_origin_txg = 41074e7dc98SMatthew Ahrens origin->ds_phys->ds_creation_txg; 41174e7dc98SMatthew Ahrens dsl_dataset_rele(origin, FTAG); 41274e7dc98SMatthew Ahrens } 41374e7dc98SMatthew Ahrens } 414842727c2SChris Kirby } else { 415842727c2SChris Kirby if (zfs_flags & ZFS_DEBUG_SNAPNAMES) 416842727c2SChris Kirby err = dsl_dataset_get_snapname(ds); 417842727c2SChris Kirby if (err == 0 && ds->ds_phys->ds_userrefs_obj != 0) { 418842727c2SChris Kirby err = zap_count( 419842727c2SChris Kirby ds->ds_dir->dd_pool->dp_meta_objset, 420842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj, 421842727c2SChris Kirby &ds->ds_userrefs); 422842727c2SChris Kirby } 423fa9e4066Sahrens } 424fa9e4066Sahrens 42574e7dc98SMatthew Ahrens if (err == 0 && !dsl_dataset_is_snapshot(ds)) { 42627345066Sck /* 42727345066Sck * In sync context, we're called with either no lock 42827345066Sck * or with the write lock. If we're not syncing, 42927345066Sck * we're always called with the read lock held. 43027345066Sck */ 431cb625fb5Sck boolean_t need_lock = 43227345066Sck !RW_WRITE_HELD(&dp->dp_config_rwlock) && 43327345066Sck dsl_pool_sync_context(dp); 434cb625fb5Sck 435cb625fb5Sck if (need_lock) 436cb625fb5Sck rw_enter(&dp->dp_config_rwlock, RW_READER); 437cb625fb5Sck 438bb0ade09Sahrens err = dsl_prop_get_ds(ds, 439cb625fb5Sck "refreservation", sizeof (uint64_t), 1, 440cb625fb5Sck &ds->ds_reserved, NULL); 441cb625fb5Sck if (err == 0) { 442bb0ade09Sahrens err = dsl_prop_get_ds(ds, 443cb625fb5Sck "refquota", sizeof (uint64_t), 1, 444cb625fb5Sck &ds->ds_quota, NULL); 445cb625fb5Sck } 446cb625fb5Sck 447cb625fb5Sck if (need_lock) 448cb625fb5Sck rw_exit(&dp->dp_config_rwlock); 449cb625fb5Sck } else { 450cb625fb5Sck ds->ds_reserved = ds->ds_quota = 0; 451cb625fb5Sck } 452cb625fb5Sck 453ea8dc4b6Seschrock if (err == 0) { 454ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 455ea8dc4b6Seschrock dsl_dataset_evict); 456ea8dc4b6Seschrock } 457ea8dc4b6Seschrock if (err || winner) { 458fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 459745cd3c5Smaybee if (ds->ds_prev) 460745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 461fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 4625ad82045Snd mutex_destroy(&ds->ds_lock); 463f4b94bdeSMatthew Ahrens mutex_destroy(&ds->ds_recvlock); 46491ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 465745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 466745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 467b24ab676SJeff Bonwick bplist_fini(&ds->ds_deadlist); 468fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 469ea8dc4b6Seschrock if (err) { 470ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 471ea8dc4b6Seschrock return (err); 472ea8dc4b6Seschrock } 473fa9e4066Sahrens ds = winner; 474fa9e4066Sahrens } else { 47591ebeef5Sahrens ds->ds_fsid_guid = 476fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 477fa9e4066Sahrens } 478fa9e4066Sahrens } 479fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 480fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 481088f3894Sahrens ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 || 482afc6333aSahrens spa_version(dp->dp_spa) < SPA_VERSION_ORIGIN || 48384db2a68Sahrens dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap); 484fa9e4066Sahrens mutex_enter(&ds->ds_lock); 485745cd3c5Smaybee if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) { 486fa9e4066Sahrens mutex_exit(&ds->ds_lock); 487745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 488745cd3c5Smaybee return (ENOENT); 489fa9e4066Sahrens } 490fa9e4066Sahrens mutex_exit(&ds->ds_lock); 491ea8dc4b6Seschrock *dsp = ds; 492ea8dc4b6Seschrock return (0); 493fa9e4066Sahrens } 494fa9e4066Sahrens 495745cd3c5Smaybee static int 496745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag) 497745cd3c5Smaybee { 498745cd3c5Smaybee dsl_pool_t *dp = ds->ds_dir->dd_pool; 499745cd3c5Smaybee 500745cd3c5Smaybee /* 501745cd3c5Smaybee * In syncing context we don't want the rwlock lock: there 502745cd3c5Smaybee * may be an existing writer waiting for sync phase to 503745cd3c5Smaybee * finish. We don't need to worry about such writers, since 504745cd3c5Smaybee * sync phase is single-threaded, so the writer can't be 505745cd3c5Smaybee * doing anything while we are active. 506745cd3c5Smaybee */ 507745cd3c5Smaybee if (dsl_pool_sync_context(dp)) { 508745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 509745cd3c5Smaybee return (0); 510745cd3c5Smaybee } 511745cd3c5Smaybee 512745cd3c5Smaybee /* 513745cd3c5Smaybee * Normal users will hold the ds_rwlock as a READER until they 514745cd3c5Smaybee * are finished (i.e., call dsl_dataset_rele()). "Owners" will 515745cd3c5Smaybee * drop their READER lock after they set the ds_owner field. 516745cd3c5Smaybee * 517745cd3c5Smaybee * If the dataset is being destroyed, the destroy thread will 518745cd3c5Smaybee * obtain a WRITER lock for exclusive access after it's done its 519745cd3c5Smaybee * open-context work and then change the ds_owner to 520745cd3c5Smaybee * dsl_reaper once destruction is assured. So threads 521745cd3c5Smaybee * may block here temporarily, until the "destructability" of 522745cd3c5Smaybee * the dataset is determined. 523745cd3c5Smaybee */ 524745cd3c5Smaybee ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock)); 525745cd3c5Smaybee mutex_enter(&ds->ds_lock); 526745cd3c5Smaybee while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) { 527745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 528745cd3c5Smaybee cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock); 529745cd3c5Smaybee if (DSL_DATASET_IS_DESTROYED(ds)) { 530745cd3c5Smaybee mutex_exit(&ds->ds_lock); 531745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 532745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 533745cd3c5Smaybee return (ENOENT); 534745cd3c5Smaybee } 535745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 536745cd3c5Smaybee } 537745cd3c5Smaybee mutex_exit(&ds->ds_lock); 538745cd3c5Smaybee return (0); 539745cd3c5Smaybee } 540745cd3c5Smaybee 541745cd3c5Smaybee int 542745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, 543745cd3c5Smaybee dsl_dataset_t **dsp) 544745cd3c5Smaybee { 545745cd3c5Smaybee int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp); 546745cd3c5Smaybee 547745cd3c5Smaybee if (err) 548745cd3c5Smaybee return (err); 549745cd3c5Smaybee return (dsl_dataset_hold_ref(*dsp, tag)); 550745cd3c5Smaybee } 551745cd3c5Smaybee 552745cd3c5Smaybee int 553503ad85cSMatthew Ahrens dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, boolean_t inconsistentok, 554503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 555745cd3c5Smaybee { 556503ad85cSMatthew Ahrens int err = dsl_dataset_hold_obj(dp, dsobj, tag, dsp); 557745cd3c5Smaybee if (err) 558745cd3c5Smaybee return (err); 559503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 560503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 5614f5064b7SMark J Musante *dsp = NULL; 562745cd3c5Smaybee return (EBUSY); 563745cd3c5Smaybee } 564745cd3c5Smaybee return (0); 565745cd3c5Smaybee } 566745cd3c5Smaybee 567fa9e4066Sahrens int 568745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp) 569fa9e4066Sahrens { 570fa9e4066Sahrens dsl_dir_t *dd; 571fa9e4066Sahrens dsl_pool_t *dp; 572745cd3c5Smaybee const char *snapname; 573fa9e4066Sahrens uint64_t obj; 574fa9e4066Sahrens int err = 0; 575fa9e4066Sahrens 576745cd3c5Smaybee err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname); 577ea8dc4b6Seschrock if (err) 578ea8dc4b6Seschrock return (err); 579fa9e4066Sahrens 580fa9e4066Sahrens dp = dd->dd_pool; 581fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 582fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 583745cd3c5Smaybee if (obj) 584745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, dsp); 585745cd3c5Smaybee else 586fa9e4066Sahrens err = ENOENT; 587745cd3c5Smaybee if (err) 588fa9e4066Sahrens goto out; 589fa9e4066Sahrens 590745cd3c5Smaybee err = dsl_dataset_hold_ref(*dsp, tag); 591fa9e4066Sahrens 592745cd3c5Smaybee /* we may be looking for a snapshot */ 593745cd3c5Smaybee if (err == 0 && snapname != NULL) { 594745cd3c5Smaybee dsl_dataset_t *ds = NULL; 595fa9e4066Sahrens 596745cd3c5Smaybee if (*snapname++ != '@') { 597745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 598fa9e4066Sahrens err = ENOENT; 599fa9e4066Sahrens goto out; 600fa9e4066Sahrens } 601fa9e4066Sahrens 602745cd3c5Smaybee dprintf("looking for snapshot '%s'\n", snapname); 603745cd3c5Smaybee err = dsl_dataset_snap_lookup(*dsp, snapname, &obj); 604745cd3c5Smaybee if (err == 0) 605745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, &ds); 606745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 607745cd3c5Smaybee 608745cd3c5Smaybee ASSERT3U((err == 0), ==, (ds != NULL)); 609745cd3c5Smaybee 610745cd3c5Smaybee if (ds) { 611745cd3c5Smaybee mutex_enter(&ds->ds_lock); 612745cd3c5Smaybee if (ds->ds_snapname[0] == 0) 613745cd3c5Smaybee (void) strlcpy(ds->ds_snapname, snapname, 614745cd3c5Smaybee sizeof (ds->ds_snapname)); 615745cd3c5Smaybee mutex_exit(&ds->ds_lock); 616745cd3c5Smaybee err = dsl_dataset_hold_ref(ds, tag); 617745cd3c5Smaybee *dsp = err ? NULL : ds; 618fa9e4066Sahrens } 619fa9e4066Sahrens } 620fa9e4066Sahrens out: 621fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 622fa9e4066Sahrens dsl_dir_close(dd, FTAG); 623fa9e4066Sahrens return (err); 624fa9e4066Sahrens } 625fa9e4066Sahrens 626fa9e4066Sahrens int 627503ad85cSMatthew Ahrens dsl_dataset_own(const char *name, boolean_t inconsistentok, 628503ad85cSMatthew Ahrens void *tag, dsl_dataset_t **dsp) 629fa9e4066Sahrens { 630503ad85cSMatthew Ahrens int err = dsl_dataset_hold(name, tag, dsp); 631745cd3c5Smaybee if (err) 632745cd3c5Smaybee return (err); 633503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(*dsp, inconsistentok, tag)) { 634503ad85cSMatthew Ahrens dsl_dataset_rele(*dsp, tag); 635745cd3c5Smaybee return (EBUSY); 636745cd3c5Smaybee } 637745cd3c5Smaybee return (0); 638fa9e4066Sahrens } 639fa9e4066Sahrens 640fa9e4066Sahrens void 641fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 642fa9e4066Sahrens { 643fa9e4066Sahrens if (ds == NULL) { 644fa9e4066Sahrens (void) strcpy(name, "mos"); 645fa9e4066Sahrens } else { 646fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 647ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 648fa9e4066Sahrens if (ds->ds_snapname[0]) { 649fa9e4066Sahrens (void) strcat(name, "@"); 650745cd3c5Smaybee /* 651745cd3c5Smaybee * We use a "recursive" mutex so that we 652745cd3c5Smaybee * can call dprintf_ds() with ds_lock held. 653745cd3c5Smaybee */ 654fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 655fa9e4066Sahrens mutex_enter(&ds->ds_lock); 656fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 657fa9e4066Sahrens mutex_exit(&ds->ds_lock); 658fa9e4066Sahrens } else { 659fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 660fa9e4066Sahrens } 661fa9e4066Sahrens } 662fa9e4066Sahrens } 663fa9e4066Sahrens } 664fa9e4066Sahrens 665b7661cccSmmusante static int 666b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 667b7661cccSmmusante { 668b7661cccSmmusante int result; 669b7661cccSmmusante 670b7661cccSmmusante if (ds == NULL) { 671b7661cccSmmusante result = 3; /* "mos" */ 672b7661cccSmmusante } else { 673b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 674b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 675b7661cccSmmusante if (ds->ds_snapname[0]) { 676b7661cccSmmusante ++result; /* adding one for the @-sign */ 677b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 678b7661cccSmmusante mutex_enter(&ds->ds_lock); 679b7661cccSmmusante result += strlen(ds->ds_snapname); 680b7661cccSmmusante mutex_exit(&ds->ds_lock); 681b7661cccSmmusante } else { 682b7661cccSmmusante result += strlen(ds->ds_snapname); 683b7661cccSmmusante } 684b7661cccSmmusante } 685b7661cccSmmusante } 686b7661cccSmmusante 687b7661cccSmmusante return (result); 688b7661cccSmmusante } 689b7661cccSmmusante 690088f3894Sahrens void 691745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag) 692fa9e4066Sahrens { 693ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 694fa9e4066Sahrens } 695fa9e4066Sahrens 6963cb34c60Sahrens void 697745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag) 6983cb34c60Sahrens { 699745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) { 700745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 701745cd3c5Smaybee } 702745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 703745cd3c5Smaybee } 704745cd3c5Smaybee 705745cd3c5Smaybee void 706503ad85cSMatthew Ahrens dsl_dataset_disown(dsl_dataset_t *ds, void *tag) 707745cd3c5Smaybee { 708503ad85cSMatthew Ahrens ASSERT((ds->ds_owner == tag && ds->ds_dbuf) || 709745cd3c5Smaybee (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL)); 710745cd3c5Smaybee 7113cb34c60Sahrens mutex_enter(&ds->ds_lock); 712745cd3c5Smaybee ds->ds_owner = NULL; 713745cd3c5Smaybee if (RW_WRITE_HELD(&ds->ds_rwlock)) { 714745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 715745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 716745cd3c5Smaybee } 7173cb34c60Sahrens mutex_exit(&ds->ds_lock); 718745cd3c5Smaybee if (ds->ds_dbuf) 719503ad85cSMatthew Ahrens dsl_dataset_drop_ref(ds, tag); 720745cd3c5Smaybee else 721745cd3c5Smaybee dsl_dataset_evict(ds->ds_dbuf, ds); 7223cb34c60Sahrens } 7233cb34c60Sahrens 7243cb34c60Sahrens boolean_t 725503ad85cSMatthew Ahrens dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *tag) 7263cb34c60Sahrens { 727745cd3c5Smaybee boolean_t gotit = FALSE; 728745cd3c5Smaybee 7293cb34c60Sahrens mutex_enter(&ds->ds_lock); 730745cd3c5Smaybee if (ds->ds_owner == NULL && 731745cd3c5Smaybee (!DS_IS_INCONSISTENT(ds) || inconsistentok)) { 732503ad85cSMatthew Ahrens ds->ds_owner = tag; 733745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) 734745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 735745cd3c5Smaybee gotit = TRUE; 7363cb34c60Sahrens } 7373cb34c60Sahrens mutex_exit(&ds->ds_lock); 738745cd3c5Smaybee return (gotit); 739745cd3c5Smaybee } 740745cd3c5Smaybee 741745cd3c5Smaybee void 742745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner) 743745cd3c5Smaybee { 744745cd3c5Smaybee ASSERT3P(owner, ==, ds->ds_owner); 745745cd3c5Smaybee if (!RW_WRITE_HELD(&ds->ds_rwlock)) 746745cd3c5Smaybee rw_enter(&ds->ds_rwlock, RW_WRITER); 7473cb34c60Sahrens } 7483cb34c60Sahrens 7491d452cf5Sahrens uint64_t 750088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 751ab04eb8eStimh uint64_t flags, dmu_tx_t *tx) 752fa9e4066Sahrens { 7533cb34c60Sahrens dsl_pool_t *dp = dd->dd_pool; 754fa9e4066Sahrens dmu_buf_t *dbuf; 755fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 7563cb34c60Sahrens uint64_t dsobj; 757fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 758fa9e4066Sahrens 759088f3894Sahrens if (origin == NULL) 760088f3894Sahrens origin = dp->dp_origin_snap; 761088f3894Sahrens 7623cb34c60Sahrens ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp); 7633cb34c60Sahrens ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0); 764fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 7653cb34c60Sahrens ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); 766fa9e4066Sahrens 7671649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 7681649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 769ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 770fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 771fa9e4066Sahrens dsphys = dbuf->db_data; 772745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 773fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 774ab04eb8eStimh dsphys->ds_flags = flags; 775fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 776fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 777fa9e4066Sahrens sizeof (dsphys->ds_guid)); 778fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 779ab04eb8eStimh zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP, 780ab04eb8eStimh DMU_OT_NONE, 0, tx); 781fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 782088f3894Sahrens dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg; 783fa9e4066Sahrens dsphys->ds_deadlist_obj = 784fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 785a9799022Sck 7863cb34c60Sahrens if (origin) { 7873cb34c60Sahrens dsphys->ds_prev_snap_obj = origin->ds_object; 788fa9e4066Sahrens dsphys->ds_prev_snap_txg = 7893cb34c60Sahrens origin->ds_phys->ds_creation_txg; 790fa9e4066Sahrens dsphys->ds_used_bytes = 7913cb34c60Sahrens origin->ds_phys->ds_used_bytes; 792fa9e4066Sahrens dsphys->ds_compressed_bytes = 7933cb34c60Sahrens origin->ds_phys->ds_compressed_bytes; 794fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 7953cb34c60Sahrens origin->ds_phys->ds_uncompressed_bytes; 7963cb34c60Sahrens dsphys->ds_bp = origin->ds_phys->ds_bp; 797579ae4d5Stimh dsphys->ds_flags |= origin->ds_phys->ds_flags; 798fa9e4066Sahrens 7993cb34c60Sahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 8003cb34c60Sahrens origin->ds_phys->ds_num_children++; 801fa9e4066Sahrens 802088f3894Sahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) { 803088f3894Sahrens if (origin->ds_phys->ds_next_clones_obj == 0) { 804088f3894Sahrens origin->ds_phys->ds_next_clones_obj = 805088f3894Sahrens zap_create(mos, 806088f3894Sahrens DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx); 807088f3894Sahrens } 808088f3894Sahrens VERIFY(0 == zap_add_int(mos, 809088f3894Sahrens origin->ds_phys->ds_next_clones_obj, 810088f3894Sahrens dsobj, tx)); 811088f3894Sahrens } 812088f3894Sahrens 813fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 8143cb34c60Sahrens dd->dd_phys->dd_origin_obj = origin->ds_object; 815fa9e4066Sahrens } 816ab04eb8eStimh 817ab04eb8eStimh if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 818ab04eb8eStimh dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 819ab04eb8eStimh 820ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 821fa9e4066Sahrens 822fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 823fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 8243cb34c60Sahrens 8253cb34c60Sahrens return (dsobj); 8263cb34c60Sahrens } 8273cb34c60Sahrens 8283cb34c60Sahrens uint64_t 829ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname, 830ab04eb8eStimh dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx) 8313cb34c60Sahrens { 8323cb34c60Sahrens dsl_pool_t *dp = pdd->dd_pool; 8333cb34c60Sahrens uint64_t dsobj, ddobj; 8343cb34c60Sahrens dsl_dir_t *dd; 8353cb34c60Sahrens 8363cb34c60Sahrens ASSERT(lastname[0] != '@'); 8373cb34c60Sahrens 838088f3894Sahrens ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx); 8393cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 8403cb34c60Sahrens 841088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx); 8423cb34c60Sahrens 8433cb34c60Sahrens dsl_deleg_set_create_perms(dd, tx, cr); 8443cb34c60Sahrens 845fa9e4066Sahrens dsl_dir_close(dd, FTAG); 846fa9e4066Sahrens 8471d452cf5Sahrens return (dsobj); 848fa9e4066Sahrens } 849fa9e4066Sahrens 8501d452cf5Sahrens struct destroyarg { 8511d452cf5Sahrens dsl_sync_task_group_t *dstg; 8521d452cf5Sahrens char *snapname; 8531d452cf5Sahrens char *failed; 854842727c2SChris Kirby boolean_t defer; 8551d452cf5Sahrens }; 8561d452cf5Sahrens 8571d452cf5Sahrens static int 8581d452cf5Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 859fa9e4066Sahrens { 8601d452cf5Sahrens struct destroyarg *da = arg; 8611d452cf5Sahrens dsl_dataset_t *ds; 862fa9e4066Sahrens int err; 863842727c2SChris Kirby char *dsname; 864842727c2SChris Kirby 865ae46e4c7SMatthew Ahrens dsname = kmem_asprintf("%s@%s", name, da->snapname); 866503ad85cSMatthew Ahrens err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds); 867ae46e4c7SMatthew Ahrens strfree(dsname); 868745cd3c5Smaybee if (err == 0) { 869842727c2SChris Kirby struct dsl_ds_destroyarg *dsda; 870842727c2SChris Kirby 871745cd3c5Smaybee dsl_dataset_make_exclusive(ds, da->dstg); 872503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) { 873503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 874503ad85cSMatthew Ahrens ds->ds_objset = NULL; 8753baa08fcSek } 876842727c2SChris Kirby dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP); 877842727c2SChris Kirby dsda->ds = ds; 878842727c2SChris Kirby dsda->defer = da->defer; 879745cd3c5Smaybee dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 880842727c2SChris Kirby dsl_dataset_destroy_sync, dsda, da->dstg, 0); 881745cd3c5Smaybee } else if (err == ENOENT) { 882745cd3c5Smaybee err = 0; 883745cd3c5Smaybee } else { 8841d452cf5Sahrens (void) strcpy(da->failed, name); 8851d452cf5Sahrens } 886745cd3c5Smaybee return (err); 8871d452cf5Sahrens } 88831fd60d3Sahrens 8891d452cf5Sahrens /* 8901d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 8911d452cf5Sahrens */ 8921d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 8931d452cf5Sahrens int 894842727c2SChris Kirby dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer) 8951d452cf5Sahrens { 8961d452cf5Sahrens int err; 8971d452cf5Sahrens struct destroyarg da; 8981d452cf5Sahrens dsl_sync_task_t *dst; 8991d452cf5Sahrens spa_t *spa; 9001d452cf5Sahrens 90140feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 9021d452cf5Sahrens if (err) 9031d452cf5Sahrens return (err); 9041d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 9051d452cf5Sahrens da.snapname = snapname; 9061d452cf5Sahrens da.failed = fsname; 907842727c2SChris Kirby da.defer = defer; 9081d452cf5Sahrens 9091d452cf5Sahrens err = dmu_objset_find(fsname, 9100b69c2f0Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 9111d452cf5Sahrens 9121d452cf5Sahrens if (err == 0) 9131d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 9141d452cf5Sahrens 9151d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 9161d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 917842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = dst->dst_arg1; 918842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 919842727c2SChris Kirby 920745cd3c5Smaybee /* 921745cd3c5Smaybee * Return the file system name that triggered the error 922745cd3c5Smaybee */ 9231d452cf5Sahrens if (dst->dst_err) { 9241d452cf5Sahrens dsl_dataset_name(ds, fsname); 92540feaa91Sahrens *strchr(fsname, '@') = '\0'; 926e1930233Sbonwick } 927842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 928745cd3c5Smaybee dsl_dataset_disown(ds, da.dstg); 929842727c2SChris Kirby kmem_free(dsda, sizeof (struct dsl_ds_destroyarg)); 930fa9e4066Sahrens } 931fa9e4066Sahrens 9321d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 9331d452cf5Sahrens spa_close(spa, FTAG); 934fa9e4066Sahrens return (err); 935fa9e4066Sahrens } 936fa9e4066Sahrens 937842727c2SChris Kirby static boolean_t 938842727c2SChris Kirby dsl_dataset_might_destroy_origin(dsl_dataset_t *ds) 939842727c2SChris Kirby { 940842727c2SChris Kirby boolean_t might_destroy = B_FALSE; 941842727c2SChris Kirby 942842727c2SChris Kirby mutex_enter(&ds->ds_lock); 943842727c2SChris Kirby if (ds->ds_phys->ds_num_children == 2 && ds->ds_userrefs == 0 && 944842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 945842727c2SChris Kirby might_destroy = B_TRUE; 946842727c2SChris Kirby mutex_exit(&ds->ds_lock); 947842727c2SChris Kirby 948842727c2SChris Kirby return (might_destroy); 949842727c2SChris Kirby } 950842727c2SChris Kirby 951842727c2SChris Kirby /* 952842727c2SChris Kirby * If we're removing a clone, and these three conditions are true: 953842727c2SChris Kirby * 1) the clone's origin has no other children 954842727c2SChris Kirby * 2) the clone's origin has no user references 955842727c2SChris Kirby * 3) the clone's origin has been marked for deferred destruction 956842727c2SChris Kirby * Then, prepare to remove the origin as part of this sync task group. 957842727c2SChris Kirby */ 958842727c2SChris Kirby static int 959842727c2SChris Kirby dsl_dataset_origin_rm_prep(struct dsl_ds_destroyarg *dsda, void *tag) 960842727c2SChris Kirby { 961842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 962842727c2SChris Kirby dsl_dataset_t *origin = ds->ds_prev; 963842727c2SChris Kirby 964842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(origin)) { 965842727c2SChris Kirby char *name; 966842727c2SChris Kirby int namelen; 967842727c2SChris Kirby int error; 968842727c2SChris Kirby 969842727c2SChris Kirby namelen = dsl_dataset_namelen(origin) + 1; 970842727c2SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 971842727c2SChris Kirby dsl_dataset_name(origin, name); 972842727c2SChris Kirby #ifdef _KERNEL 973842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 974842727c2SChris Kirby if (error) { 975842727c2SChris Kirby kmem_free(name, namelen); 976842727c2SChris Kirby return (error); 977842727c2SChris Kirby } 978842727c2SChris Kirby #endif 979503ad85cSMatthew Ahrens error = dsl_dataset_own(name, B_TRUE, tag, &origin); 980842727c2SChris Kirby kmem_free(name, namelen); 981842727c2SChris Kirby if (error) 982842727c2SChris Kirby return (error); 983842727c2SChris Kirby dsda->rm_origin = origin; 984842727c2SChris Kirby dsl_dataset_make_exclusive(origin, tag); 985ca45db41SChris Kirby 986ca45db41SChris Kirby if (origin->ds_objset != NULL) { 987ca45db41SChris Kirby dmu_objset_evict(origin->ds_objset); 988ca45db41SChris Kirby origin->ds_objset = NULL; 989ca45db41SChris Kirby } 990842727c2SChris Kirby } 991842727c2SChris Kirby 992842727c2SChris Kirby return (0); 993842727c2SChris Kirby } 994842727c2SChris Kirby 9953cb34c60Sahrens /* 996745cd3c5Smaybee * ds must be opened as OWNER. On return (whether successful or not), 997745cd3c5Smaybee * ds will be closed and caller can no longer dereference it. 9983cb34c60Sahrens */ 999fa9e4066Sahrens int 1000842727c2SChris Kirby dsl_dataset_destroy(dsl_dataset_t *ds, void *tag, boolean_t defer) 1001fa9e4066Sahrens { 1002fa9e4066Sahrens int err; 10031d452cf5Sahrens dsl_sync_task_group_t *dstg; 10041d452cf5Sahrens objset_t *os; 1005fa9e4066Sahrens dsl_dir_t *dd; 10061d452cf5Sahrens uint64_t obj; 1007*92241e0bSTom Erickson struct dsl_ds_destroyarg dsda = { 0 }; 1008*92241e0bSTom Erickson dsl_dataset_t dummy_ds = { 0 }; 1009842727c2SChris Kirby 1010842727c2SChris Kirby dsda.ds = ds; 10111d452cf5Sahrens 10123cb34c60Sahrens if (dsl_dataset_is_snapshot(ds)) { 10131d452cf5Sahrens /* Destroying a snapshot is simpler */ 1014745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 10153baa08fcSek 1016503ad85cSMatthew Ahrens if (ds->ds_objset != NULL) { 1017503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 1018503ad85cSMatthew Ahrens ds->ds_objset = NULL; 10193baa08fcSek } 1020842727c2SChris Kirby dsda.defer = defer; 10211d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 10221d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 1023842727c2SChris Kirby &dsda, tag, 0); 1024842727c2SChris Kirby ASSERT3P(dsda.rm_origin, ==, NULL); 10253cb34c60Sahrens goto out; 1026922d9a97SChris Kirby } else if (defer) { 1027922d9a97SChris Kirby err = EINVAL; 1028922d9a97SChris Kirby goto out; 10291d452cf5Sahrens } 1030fa9e4066Sahrens 10311d452cf5Sahrens dd = ds->ds_dir; 1032*92241e0bSTom Erickson dummy_ds.ds_dir = dd; 1033*92241e0bSTom Erickson dummy_ds.ds_object = ds->ds_object; 1034fa9e4066Sahrens 10351d452cf5Sahrens /* 10361d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 10371d452cf5Sahrens * case we crash while freeing the objects. 10381d452cf5Sahrens */ 10391d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 10401d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 10413cb34c60Sahrens if (err) 10423cb34c60Sahrens goto out; 10433cb34c60Sahrens 1044503ad85cSMatthew Ahrens err = dmu_objset_from_ds(ds, &os); 10453cb34c60Sahrens if (err) 10463cb34c60Sahrens goto out; 1047fa9e4066Sahrens 10481d452cf5Sahrens /* 10491d452cf5Sahrens * remove the objects in open context, so that we won't 10501d452cf5Sahrens * have too much to do in syncing context. 10511d452cf5Sahrens */ 10526754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 10536754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 1054cdb0ab79Smaybee /* 1055cdb0ab79Smaybee * Ignore errors, if there is not enough disk space 1056cdb0ab79Smaybee * we will deal with it in dsl_dataset_destroy_sync(). 1057cdb0ab79Smaybee */ 1058cdb0ab79Smaybee (void) dmu_free_object(os, obj); 10591d452cf5Sahrens } 10601d452cf5Sahrens 106114843421SMatthew Ahrens /* 106214843421SMatthew Ahrens * We need to sync out all in-flight IO before we try to evict 106314843421SMatthew Ahrens * (the dataset evict func is trying to clear the cached entries 106414843421SMatthew Ahrens * for this dataset in the ARC). 106514843421SMatthew Ahrens */ 106614843421SMatthew Ahrens txg_wait_synced(dd->dd_pool, 0); 106714843421SMatthew Ahrens 106814843421SMatthew Ahrens /* 106914843421SMatthew Ahrens * If we managed to free all the objects in open 107014843421SMatthew Ahrens * context, the user space accounting should be zero. 107114843421SMatthew Ahrens */ 107214843421SMatthew Ahrens if (ds->ds_phys->ds_bp.blk_fill == 0 && 1073503ad85cSMatthew Ahrens dmu_objset_userused_enabled(os)) { 107414843421SMatthew Ahrens uint64_t count; 107514843421SMatthew Ahrens 107614843421SMatthew Ahrens ASSERT(zap_count(os, DMU_USERUSED_OBJECT, &count) != 0 || 107714843421SMatthew Ahrens count == 0); 107814843421SMatthew Ahrens ASSERT(zap_count(os, DMU_GROUPUSED_OBJECT, &count) != 0 || 107914843421SMatthew Ahrens count == 0); 108014843421SMatthew Ahrens } 108114843421SMatthew Ahrens 10821d452cf5Sahrens if (err != ESRCH) 10833cb34c60Sahrens goto out; 10841d452cf5Sahrens 108568038c2cSmaybee rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 108668038c2cSmaybee err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd); 108768038c2cSmaybee rw_exit(&dd->dd_pool->dp_config_rwlock); 108868038c2cSmaybee 108968038c2cSmaybee if (err) 109068038c2cSmaybee goto out; 109168038c2cSmaybee 1092503ad85cSMatthew Ahrens if (ds->ds_objset) { 1093745cd3c5Smaybee /* 1094745cd3c5Smaybee * We need to sync out all in-flight IO before we try 1095745cd3c5Smaybee * to evict (the dataset evict func is trying to clear 1096745cd3c5Smaybee * the cached entries for this dataset in the ARC). 1097745cd3c5Smaybee */ 1098745cd3c5Smaybee txg_wait_synced(dd->dd_pool, 0); 10991d452cf5Sahrens } 11001d452cf5Sahrens 11011d452cf5Sahrens /* 11021d452cf5Sahrens * Blow away the dsl_dir + head dataset. 11031d452cf5Sahrens */ 1104745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 1105503ad85cSMatthew Ahrens if (ds->ds_objset) { 1106503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 1107503ad85cSMatthew Ahrens ds->ds_objset = NULL; 110868038c2cSmaybee } 1109842727c2SChris Kirby 1110842727c2SChris Kirby /* 1111842727c2SChris Kirby * If we're removing a clone, we might also need to remove its 1112842727c2SChris Kirby * origin. 1113842727c2SChris Kirby */ 1114842727c2SChris Kirby do { 1115842727c2SChris Kirby dsda.need_prep = B_FALSE; 1116842727c2SChris Kirby if (dsl_dir_is_clone(dd)) { 1117842727c2SChris Kirby err = dsl_dataset_origin_rm_prep(&dsda, tag); 1118842727c2SChris Kirby if (err) { 1119842727c2SChris Kirby dsl_dir_close(dd, FTAG); 1120842727c2SChris Kirby goto out; 1121842727c2SChris Kirby } 1122842727c2SChris Kirby } 1123842727c2SChris Kirby 1124842727c2SChris Kirby dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 1125842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 1126842727c2SChris Kirby dsl_dataset_destroy_sync, &dsda, tag, 0); 1127842727c2SChris Kirby dsl_sync_task_create(dstg, dsl_dir_destroy_check, 1128*92241e0bSTom Erickson dsl_dir_destroy_sync, &dummy_ds, FTAG, 0); 1129842727c2SChris Kirby err = dsl_sync_task_group_wait(dstg); 1130842727c2SChris Kirby dsl_sync_task_group_destroy(dstg); 1131842727c2SChris Kirby 1132842727c2SChris Kirby /* 1133842727c2SChris Kirby * We could be racing against 'zfs release' or 'zfs destroy -d' 1134842727c2SChris Kirby * on the origin snap, in which case we can get EBUSY if we 1135842727c2SChris Kirby * needed to destroy the origin snap but were not ready to 1136842727c2SChris Kirby * do so. 1137842727c2SChris Kirby */ 1138842727c2SChris Kirby if (dsda.need_prep) { 1139842727c2SChris Kirby ASSERT(err == EBUSY); 1140842727c2SChris Kirby ASSERT(dsl_dir_is_clone(dd)); 1141842727c2SChris Kirby ASSERT(dsda.rm_origin == NULL); 1142842727c2SChris Kirby } 1143842727c2SChris Kirby } while (dsda.need_prep); 1144842727c2SChris Kirby 1145842727c2SChris Kirby if (dsda.rm_origin != NULL) 1146842727c2SChris Kirby dsl_dataset_disown(dsda.rm_origin, tag); 1147842727c2SChris Kirby 1148745cd3c5Smaybee /* if it is successful, dsl_dir_destroy_sync will close the dd */ 11493cb34c60Sahrens if (err) 11501d452cf5Sahrens dsl_dir_close(dd, FTAG); 11513cb34c60Sahrens out: 1152745cd3c5Smaybee dsl_dataset_disown(ds, tag); 1153fa9e4066Sahrens return (err); 1154fa9e4066Sahrens } 1155fa9e4066Sahrens 1156c717a561Smaybee blkptr_t * 1157c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 1158fa9e4066Sahrens { 1159c717a561Smaybee return (&ds->ds_phys->ds_bp); 1160fa9e4066Sahrens } 1161fa9e4066Sahrens 1162fa9e4066Sahrens void 1163fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 1164fa9e4066Sahrens { 1165fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1166fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 1167fa9e4066Sahrens if (ds == NULL) { 1168fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 1169fa9e4066Sahrens } else { 1170fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1171fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 1172fa9e4066Sahrens } 1173fa9e4066Sahrens } 1174fa9e4066Sahrens 1175fa9e4066Sahrens spa_t * 1176fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 1177fa9e4066Sahrens { 1178fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 1179fa9e4066Sahrens } 1180fa9e4066Sahrens 1181fa9e4066Sahrens void 1182fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 1183fa9e4066Sahrens { 1184fa9e4066Sahrens dsl_pool_t *dp; 1185fa9e4066Sahrens 1186fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 1187fa9e4066Sahrens return; 1188fa9e4066Sahrens 1189503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1190a2eea2e1Sahrens 1191a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1192a2eea2e1Sahrens panic("dirtying snapshot!"); 1193fa9e4066Sahrens 1194fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 1195fa9e4066Sahrens 1196fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 1197fa9e4066Sahrens /* up the hold count until we can be written out */ 1198fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 1199fa9e4066Sahrens } 1200fa9e4066Sahrens } 1201fa9e4066Sahrens 1202a9799022Sck /* 1203a9799022Sck * The unique space in the head dataset can be calculated by subtracting 1204a9799022Sck * the space used in the most recent snapshot, that is still being used 1205a9799022Sck * in this file system, from the space currently in use. To figure out 1206a9799022Sck * the space in the most recent snapshot still in use, we need to take 1207a9799022Sck * the total space used in the snapshot and subtract out the space that 1208a9799022Sck * has been freed up since the snapshot was taken. 1209a9799022Sck */ 1210a9799022Sck static void 1211a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds) 1212a9799022Sck { 1213a9799022Sck uint64_t mrs_used; 1214a9799022Sck uint64_t dlused, dlcomp, dluncomp; 1215a9799022Sck 1216a9799022Sck ASSERT(ds->ds_object == ds->ds_dir->dd_phys->dd_head_dataset_obj); 1217a9799022Sck 1218a9799022Sck if (ds->ds_phys->ds_prev_snap_obj != 0) 1219a9799022Sck mrs_used = ds->ds_prev->ds_phys->ds_used_bytes; 1220a9799022Sck else 1221a9799022Sck mrs_used = 0; 1222a9799022Sck 1223a9799022Sck VERIFY(0 == bplist_space(&ds->ds_deadlist, &dlused, &dlcomp, 1224a9799022Sck &dluncomp)); 1225a9799022Sck 1226a9799022Sck ASSERT3U(dlused, <=, mrs_used); 1227a9799022Sck ds->ds_phys->ds_unique_bytes = 1228a9799022Sck ds->ds_phys->ds_used_bytes - (mrs_used - dlused); 1229a9799022Sck 1230a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && 1231a9799022Sck spa_version(ds->ds_dir->dd_pool->dp_spa) >= 1232a9799022Sck SPA_VERSION_UNIQUE_ACCURATE) 1233a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1234a9799022Sck } 1235a9799022Sck 1236a9799022Sck static uint64_t 1237a9799022Sck dsl_dataset_unique(dsl_dataset_t *ds) 1238a9799022Sck { 1239a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && !dsl_dataset_is_snapshot(ds)) 1240a9799022Sck dsl_dataset_recalc_head_uniq(ds); 1241a9799022Sck 1242a9799022Sck return (ds->ds_phys->ds_unique_bytes); 1243a9799022Sck } 1244a9799022Sck 1245fa9e4066Sahrens struct killarg { 124674e7dc98SMatthew Ahrens dsl_dataset_t *ds; 1247fa9e4066Sahrens dmu_tx_t *tx; 1248fa9e4066Sahrens }; 1249fa9e4066Sahrens 125074e7dc98SMatthew Ahrens /* ARGSUSED */ 1251fa9e4066Sahrens static int 1252b24ab676SJeff Bonwick kill_blkptr(spa_t *spa, zilog_t *zilog, const blkptr_t *bp, 1253b24ab676SJeff Bonwick const zbookmark_t *zb, const dnode_phys_t *dnp, void *arg) 1254fa9e4066Sahrens { 1255fa9e4066Sahrens struct killarg *ka = arg; 1256b24ab676SJeff Bonwick dmu_tx_t *tx = ka->tx; 1257fa9e4066Sahrens 125888b7b0f2SMatthew Ahrens if (bp == NULL) 125988b7b0f2SMatthew Ahrens return (0); 1260fa9e4066Sahrens 1261b24ab676SJeff Bonwick if (zb->zb_level == ZB_ZIL_LEVEL) { 1262b24ab676SJeff Bonwick ASSERT(zilog != NULL); 1263ab69d62fSMatthew Ahrens /* 1264ab69d62fSMatthew Ahrens * It's a block in the intent log. It has no 1265ab69d62fSMatthew Ahrens * accounting, so just free it. 1266ab69d62fSMatthew Ahrens */ 1267b24ab676SJeff Bonwick dsl_free(ka->tx->tx_pool, ka->tx->tx_txg, bp); 1268ab69d62fSMatthew Ahrens } else { 1269b24ab676SJeff Bonwick ASSERT(zilog == NULL); 1270ab69d62fSMatthew Ahrens ASSERT3U(bp->blk_birth, >, ka->ds->ds_phys->ds_prev_snap_txg); 1271b24ab676SJeff Bonwick (void) dsl_dataset_block_kill(ka->ds, bp, tx, B_FALSE); 1272ab69d62fSMatthew Ahrens } 127374e7dc98SMatthew Ahrens 1274fa9e4066Sahrens return (0); 1275fa9e4066Sahrens } 1276fa9e4066Sahrens 1277e1930233Sbonwick /* ARGSUSED */ 1278e1930233Sbonwick static int 12791d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1280e1930233Sbonwick { 12811d452cf5Sahrens dsl_dataset_t *ds = arg1; 12823cb34c60Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 12833cb34c60Sahrens uint64_t count; 12843cb34c60Sahrens int err; 1285e1930233Sbonwick 1286e1930233Sbonwick /* 1287e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1288e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1289e1930233Sbonwick * from.) 1290e1930233Sbonwick */ 1291e1930233Sbonwick if (ds->ds_prev != NULL && 1292e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 12934aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic return (EBUSY); 1294e1930233Sbonwick 12953cb34c60Sahrens /* 12963cb34c60Sahrens * This is really a dsl_dir thing, but check it here so that 12973cb34c60Sahrens * we'll be less likely to leave this dataset inconsistent & 12983cb34c60Sahrens * nearly destroyed. 12993cb34c60Sahrens */ 13003cb34c60Sahrens err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count); 13013cb34c60Sahrens if (err) 13023cb34c60Sahrens return (err); 13033cb34c60Sahrens if (count != 0) 13043cb34c60Sahrens return (EEXIST); 13053cb34c60Sahrens 1306e1930233Sbonwick return (0); 1307e1930233Sbonwick } 1308e1930233Sbonwick 13091d452cf5Sahrens /* ARGSUSED */ 13101d452cf5Sahrens static void 1311ecd6cf80Smarks dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 1312fa9e4066Sahrens { 13131d452cf5Sahrens dsl_dataset_t *ds = arg1; 1314ecd6cf80Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1315fa9e4066Sahrens 13161d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 13171d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 13181d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1319ecd6cf80Smarks 1320ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 1321ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 13221d452cf5Sahrens } 1323fa9e4066Sahrens 1324842727c2SChris Kirby static int 1325842727c2SChris Kirby dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag, 1326842727c2SChris Kirby dmu_tx_t *tx) 1327842727c2SChris Kirby { 1328842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1329842727c2SChris Kirby dsl_dataset_t *ds_prev = ds->ds_prev; 1330842727c2SChris Kirby 1331842727c2SChris Kirby if (dsl_dataset_might_destroy_origin(ds_prev)) { 1332842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1333842727c2SChris Kirby 1334842727c2SChris Kirby /* 1335842727c2SChris Kirby * If we're not prepared to remove the origin, don't remove 1336842727c2SChris Kirby * the clone either. 1337842727c2SChris Kirby */ 1338842727c2SChris Kirby if (dsda->rm_origin == NULL) { 1339842727c2SChris Kirby dsda->need_prep = B_TRUE; 1340842727c2SChris Kirby return (EBUSY); 1341842727c2SChris Kirby } 1342842727c2SChris Kirby 1343842727c2SChris Kirby ndsda.ds = ds_prev; 1344842727c2SChris Kirby ndsda.is_origin_rm = B_TRUE; 1345842727c2SChris Kirby return (dsl_dataset_destroy_check(&ndsda, tag, tx)); 1346842727c2SChris Kirby } 1347842727c2SChris Kirby 1348842727c2SChris Kirby /* 1349842727c2SChris Kirby * If we're not going to remove the origin after all, 1350842727c2SChris Kirby * undo the open context setup. 1351842727c2SChris Kirby */ 1352842727c2SChris Kirby if (dsda->rm_origin != NULL) { 1353842727c2SChris Kirby dsl_dataset_disown(dsda->rm_origin, tag); 1354842727c2SChris Kirby dsda->rm_origin = NULL; 1355842727c2SChris Kirby } 1356842727c2SChris Kirby 1357842727c2SChris Kirby return (0); 1358842727c2SChris Kirby } 1359842727c2SChris Kirby 13601d452cf5Sahrens /* ARGSUSED */ 13613cb34c60Sahrens int 13621d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 13631d452cf5Sahrens { 1364842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1365842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 1366fa9e4066Sahrens 1367745cd3c5Smaybee /* we have an owner hold, so noone else can destroy us */ 1368745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 1369745cd3c5Smaybee 1370842727c2SChris Kirby /* 1371842727c2SChris Kirby * Only allow deferred destroy on pools that support it. 1372842727c2SChris Kirby * NOTE: deferred destroy is only supported on snapshots. 1373842727c2SChris Kirby */ 1374842727c2SChris Kirby if (dsda->defer) { 1375842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 1376842727c2SChris Kirby SPA_VERSION_USERREFS) 1377842727c2SChris Kirby return (ENOTSUP); 1378842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 1379842727c2SChris Kirby return (0); 1380842727c2SChris Kirby } 1381fa9e4066Sahrens 1382fa9e4066Sahrens /* 1383fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1384fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1385fa9e4066Sahrens * from.) 1386fa9e4066Sahrens */ 1387fa9e4066Sahrens if (ds->ds_prev != NULL && 13881d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 13894aed9999Svitezslav batrla - Sun Microsystems - Prague Czech Republic return (EBUSY); 1390fa9e4066Sahrens 1391fa9e4066Sahrens /* 1392fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1393fa9e4066Sahrens * them. Try again. 1394fa9e4066Sahrens */ 13951d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1396fa9e4066Sahrens return (EAGAIN); 13971d452cf5Sahrens 1398842727c2SChris Kirby if (dsl_dataset_is_snapshot(ds)) { 1399842727c2SChris Kirby /* 1400842727c2SChris Kirby * If this snapshot has an elevated user reference count, 1401842727c2SChris Kirby * we can't destroy it yet. 1402842727c2SChris Kirby */ 1403842727c2SChris Kirby if (ds->ds_userrefs > 0 && !dsda->releasing) 1404842727c2SChris Kirby return (EBUSY); 1405842727c2SChris Kirby 1406842727c2SChris Kirby mutex_enter(&ds->ds_lock); 1407842727c2SChris Kirby /* 1408842727c2SChris Kirby * Can't delete a branch point. However, if we're destroying 1409842727c2SChris Kirby * a clone and removing its origin due to it having a user 1410842727c2SChris Kirby * hold count of 0 and having been marked for deferred destroy, 1411842727c2SChris Kirby * it's OK for the origin to have a single clone. 1412842727c2SChris Kirby */ 1413842727c2SChris Kirby if (ds->ds_phys->ds_num_children > 1414842727c2SChris Kirby (dsda->is_origin_rm ? 2 : 1)) { 1415842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1416842727c2SChris Kirby return (EEXIST); 1417842727c2SChris Kirby } 1418842727c2SChris Kirby mutex_exit(&ds->ds_lock); 1419842727c2SChris Kirby } else if (dsl_dir_is_clone(ds->ds_dir)) { 1420842727c2SChris Kirby return (dsl_dataset_origin_check(dsda, arg2, tx)); 1421842727c2SChris Kirby } 1422842727c2SChris Kirby 14231d452cf5Sahrens /* XXX we should do some i/o error checking... */ 14241d452cf5Sahrens return (0); 14251d452cf5Sahrens } 14261d452cf5Sahrens 1427745cd3c5Smaybee struct refsarg { 1428745cd3c5Smaybee kmutex_t lock; 1429745cd3c5Smaybee boolean_t gone; 1430745cd3c5Smaybee kcondvar_t cv; 1431745cd3c5Smaybee }; 1432745cd3c5Smaybee 1433745cd3c5Smaybee /* ARGSUSED */ 1434745cd3c5Smaybee static void 1435745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv) 1436745cd3c5Smaybee { 1437745cd3c5Smaybee struct refsarg *arg = argv; 1438745cd3c5Smaybee 1439745cd3c5Smaybee mutex_enter(&arg->lock); 1440745cd3c5Smaybee arg->gone = TRUE; 1441745cd3c5Smaybee cv_signal(&arg->cv); 1442745cd3c5Smaybee mutex_exit(&arg->lock); 1443745cd3c5Smaybee } 1444745cd3c5Smaybee 1445745cd3c5Smaybee static void 1446745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag) 1447745cd3c5Smaybee { 1448745cd3c5Smaybee struct refsarg arg; 1449745cd3c5Smaybee 1450745cd3c5Smaybee mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL); 1451745cd3c5Smaybee cv_init(&arg.cv, NULL, CV_DEFAULT, NULL); 1452745cd3c5Smaybee arg.gone = FALSE; 1453745cd3c5Smaybee (void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys, 1454745cd3c5Smaybee dsl_dataset_refs_gone); 1455745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 1456745cd3c5Smaybee mutex_enter(&arg.lock); 1457745cd3c5Smaybee while (!arg.gone) 1458745cd3c5Smaybee cv_wait(&arg.cv, &arg.lock); 1459745cd3c5Smaybee ASSERT(arg.gone); 1460745cd3c5Smaybee mutex_exit(&arg.lock); 1461745cd3c5Smaybee ds->ds_dbuf = NULL; 1462745cd3c5Smaybee ds->ds_phys = NULL; 1463745cd3c5Smaybee mutex_destroy(&arg.lock); 1464745cd3c5Smaybee cv_destroy(&arg.cv); 1465745cd3c5Smaybee } 1466745cd3c5Smaybee 1467c33e334fSMatthew Ahrens static void 1468c33e334fSMatthew Ahrens remove_from_next_clones(dsl_dataset_t *ds, uint64_t obj, dmu_tx_t *tx) 1469c33e334fSMatthew Ahrens { 1470c33e334fSMatthew Ahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1471c33e334fSMatthew Ahrens uint64_t count; 1472c33e334fSMatthew Ahrens int err; 1473c33e334fSMatthew Ahrens 1474c33e334fSMatthew Ahrens ASSERT(ds->ds_phys->ds_num_children >= 2); 1475c33e334fSMatthew Ahrens err = zap_remove_int(mos, ds->ds_phys->ds_next_clones_obj, obj, tx); 1476c33e334fSMatthew Ahrens /* 1477c33e334fSMatthew Ahrens * The err should not be ENOENT, but a bug in a previous version 1478c33e334fSMatthew Ahrens * of the code could cause upgrade_clones_cb() to not set 1479c33e334fSMatthew Ahrens * ds_next_snap_obj when it should, leading to a missing entry. 1480c33e334fSMatthew Ahrens * If we knew that the pool was created after 1481c33e334fSMatthew Ahrens * SPA_VERSION_NEXT_CLONES, we could assert that it isn't 1482c33e334fSMatthew Ahrens * ENOENT. However, at least we can check that we don't have 1483c33e334fSMatthew Ahrens * too many entries in the next_clones_obj even after failing to 1484c33e334fSMatthew Ahrens * remove this one. 1485c33e334fSMatthew Ahrens */ 1486c33e334fSMatthew Ahrens if (err != ENOENT) { 1487c33e334fSMatthew Ahrens VERIFY3U(err, ==, 0); 1488c33e334fSMatthew Ahrens } 1489c33e334fSMatthew Ahrens ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj, 1490c33e334fSMatthew Ahrens &count)); 1491c33e334fSMatthew Ahrens ASSERT3U(count, <=, ds->ds_phys->ds_num_children - 2); 1492c33e334fSMatthew Ahrens } 1493c33e334fSMatthew Ahrens 14943cb34c60Sahrens void 1495ecd6cf80Smarks dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 14961d452cf5Sahrens { 1497842727c2SChris Kirby struct dsl_ds_destroyarg *dsda = arg1; 1498842727c2SChris Kirby dsl_dataset_t *ds = dsda->ds; 14991d452cf5Sahrens int err; 15001d452cf5Sahrens int after_branch_point = FALSE; 15011d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 15021d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 15031d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 15041d452cf5Sahrens uint64_t obj; 15051d452cf5Sahrens 1506745cd3c5Smaybee ASSERT(ds->ds_owner); 1507842727c2SChris Kirby ASSERT(dsda->defer || ds->ds_phys->ds_num_children <= 1); 15081d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 15091d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 15101d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 15111d452cf5Sahrens 1512842727c2SChris Kirby if (dsda->defer) { 1513842727c2SChris Kirby ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS); 1514842727c2SChris Kirby if (ds->ds_userrefs > 0 || ds->ds_phys->ds_num_children > 1) { 1515842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 1516842727c2SChris Kirby ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY; 1517842727c2SChris Kirby return; 1518842727c2SChris Kirby } 1519842727c2SChris Kirby } 1520842727c2SChris Kirby 1521745cd3c5Smaybee /* signal any waiters that this dataset is going away */ 1522745cd3c5Smaybee mutex_enter(&ds->ds_lock); 1523745cd3c5Smaybee ds->ds_owner = dsl_reaper; 1524745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 1525745cd3c5Smaybee mutex_exit(&ds->ds_lock); 1526745cd3c5Smaybee 1527a9799022Sck /* Remove our reservation */ 1528a9799022Sck if (ds->ds_reserved != 0) { 1529*92241e0bSTom Erickson dsl_prop_setarg_t psa; 1530*92241e0bSTom Erickson uint64_t value = 0; 1531*92241e0bSTom Erickson 1532*92241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refreservation", 1533*92241e0bSTom Erickson (ZPROP_SRC_NONE | ZPROP_SRC_LOCAL | ZPROP_SRC_RECEIVED), 1534*92241e0bSTom Erickson &value); 1535*92241e0bSTom Erickson psa.psa_effective_value = 0; /* predict default value */ 1536*92241e0bSTom Erickson 1537*92241e0bSTom Erickson dsl_dataset_set_reservation_sync(ds, &psa, cr, tx); 1538a9799022Sck ASSERT3U(ds->ds_reserved, ==, 0); 1539a9799022Sck } 1540a9799022Sck 15411d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 15421d452cf5Sahrens 1543088f3894Sahrens dsl_pool_ds_destroyed(ds, tx); 1544088f3894Sahrens 15451d452cf5Sahrens obj = ds->ds_object; 1546fa9e4066Sahrens 1547fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1548fa9e4066Sahrens if (ds->ds_prev) { 1549fa9e4066Sahrens ds_prev = ds->ds_prev; 1550fa9e4066Sahrens } else { 1551745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1552745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev)); 1553fa9e4066Sahrens } 1554fa9e4066Sahrens after_branch_point = 1555fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1556fa9e4066Sahrens 1557fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1558088f3894Sahrens if (after_branch_point && 1559088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj != 0) { 1560c33e334fSMatthew Ahrens remove_from_next_clones(ds_prev, obj, tx); 1561088f3894Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1562088f3894Sahrens VERIFY(0 == zap_add_int(mos, 1563088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, 1564088f3894Sahrens ds->ds_phys->ds_next_snap_obj, tx)); 1565088f3894Sahrens } 1566088f3894Sahrens } 1567fa9e4066Sahrens if (after_branch_point && 1568fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1569fa9e4066Sahrens /* This clone is toast. */ 1570fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1571fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1572842727c2SChris Kirby 1573842727c2SChris Kirby /* 1574842727c2SChris Kirby * If the clone's origin has no other clones, no 1575842727c2SChris Kirby * user holds, and has been marked for deferred 1576842727c2SChris Kirby * deletion, then we should have done the necessary 1577842727c2SChris Kirby * destroy setup for it. 1578842727c2SChris Kirby */ 1579842727c2SChris Kirby if (ds_prev->ds_phys->ds_num_children == 1 && 1580842727c2SChris Kirby ds_prev->ds_userrefs == 0 && 1581842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds_prev)) { 1582842727c2SChris Kirby ASSERT3P(dsda->rm_origin, !=, NULL); 1583842727c2SChris Kirby } else { 1584842727c2SChris Kirby ASSERT3P(dsda->rm_origin, ==, NULL); 1585842727c2SChris Kirby } 1586fa9e4066Sahrens } else if (!after_branch_point) { 1587fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1588fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1589fa9e4066Sahrens } 1590fa9e4066Sahrens } 1591fa9e4066Sahrens 1592fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 15931d452cf5Sahrens blkptr_t bp; 1594fa9e4066Sahrens dsl_dataset_t *ds_next; 1595fa9e4066Sahrens uint64_t itor = 0; 1596a9799022Sck uint64_t old_unique; 159774e7dc98SMatthew Ahrens int64_t used = 0, compressed = 0, uncompressed = 0; 1598fa9e4066Sahrens 1599745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1600745cd3c5Smaybee ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next)); 1601fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1602fa9e4066Sahrens 1603a9799022Sck old_unique = dsl_dataset_unique(ds_next); 1604a9799022Sck 1605fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1606fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1607fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1608fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1609fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1610fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1611fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1612fa9e4066Sahrens 1613fa9e4066Sahrens /* 1614fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1615fa9e4066Sahrens * new deadlist) any entries from next's current 1616fa9e4066Sahrens * deadlist which were born before prev, and free the 1617fa9e4066Sahrens * other entries. 1618fa9e4066Sahrens * 1619fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1620fa9e4066Sahrens */ 1621745cd3c5Smaybee while (bplist_iterate(&ds_next->ds_deadlist, &itor, &bp) == 0) { 1622fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1623ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1624ea8dc4b6Seschrock &bp, tx)); 1625fa9e4066Sahrens if (ds_prev && !after_branch_point && 1626fa9e4066Sahrens bp.blk_birth > 1627fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1628fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 1629b24ab676SJeff Bonwick bp_get_dsize_sync(dp->dp_spa, &bp); 1630fa9e4066Sahrens } 1631fa9e4066Sahrens } else { 1632b24ab676SJeff Bonwick used += bp_get_dsize_sync(dp->dp_spa, &bp); 1633fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1634fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1635b24ab676SJeff Bonwick dsl_free(dp, tx->tx_txg, &bp); 1636fa9e4066Sahrens } 1637fa9e4066Sahrens } 1638fa9e4066Sahrens 163974e7dc98SMatthew Ahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 164074e7dc98SMatthew Ahrens 164174e7dc98SMatthew Ahrens /* change snapused */ 164274e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_SNAP, 164374e7dc98SMatthew Ahrens -used, -compressed, -uncompressed, tx); 164474e7dc98SMatthew Ahrens 1645fa9e4066Sahrens /* free next's deadlist */ 1646fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1647fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1648fa9e4066Sahrens 1649fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1650745cd3c5Smaybee bplist_close(&ds->ds_deadlist); 1651fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1652fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1653ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1654ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1655fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1656fa9e4066Sahrens 1657fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1658fa9e4066Sahrens /* 1659fa9e4066Sahrens * Update next's unique to include blocks which 1660fa9e4066Sahrens * were previously shared by only this snapshot 1661fa9e4066Sahrens * and it. Those blocks will be born after the 1662fa9e4066Sahrens * prev snap and before this snap, and will have 1663fa9e4066Sahrens * died after the next snap and before the one 1664fa9e4066Sahrens * after that (ie. be on the snap after next's 1665fa9e4066Sahrens * deadlist). 1666fa9e4066Sahrens * 1667fa9e4066Sahrens * XXX we're doing this long task with the 1668fa9e4066Sahrens * config lock held 1669fa9e4066Sahrens */ 1670fa9e4066Sahrens dsl_dataset_t *ds_after_next; 167174e7dc98SMatthew Ahrens uint64_t space; 1672fa9e4066Sahrens 1673745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1674745cd3c5Smaybee ds_next->ds_phys->ds_next_snap_obj, 1675745cd3c5Smaybee FTAG, &ds_after_next)); 167674e7dc98SMatthew Ahrens 167774e7dc98SMatthew Ahrens VERIFY(0 == 167874e7dc98SMatthew Ahrens bplist_space_birthrange(&ds_after_next->ds_deadlist, 167974e7dc98SMatthew Ahrens ds->ds_phys->ds_prev_snap_txg, 168074e7dc98SMatthew Ahrens ds->ds_phys->ds_creation_txg, &space)); 168174e7dc98SMatthew Ahrens ds_next->ds_phys->ds_unique_bytes += space; 1682fa9e4066Sahrens 1683745cd3c5Smaybee dsl_dataset_rele(ds_after_next, FTAG); 1684fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1685fa9e4066Sahrens } else { 1686fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1687745cd3c5Smaybee dsl_dataset_drop_ref(ds_next->ds_prev, ds_next); 1688745cd3c5Smaybee ds_next->ds_prev = NULL; 1689fa9e4066Sahrens if (ds_prev) { 1690745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1691745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 1692745cd3c5Smaybee ds_next, &ds_next->ds_prev)); 1693fa9e4066Sahrens } 1694a9799022Sck 1695a9799022Sck dsl_dataset_recalc_head_uniq(ds_next); 1696a9799022Sck 1697a9799022Sck /* 1698a9799022Sck * Reduce the amount of our unconsmed refreservation 1699a9799022Sck * being charged to our parent by the amount of 1700a9799022Sck * new unique data we have gained. 1701a9799022Sck */ 1702a9799022Sck if (old_unique < ds_next->ds_reserved) { 1703a9799022Sck int64_t mrsdelta; 1704a9799022Sck uint64_t new_unique = 1705a9799022Sck ds_next->ds_phys->ds_unique_bytes; 1706a9799022Sck 1707a9799022Sck ASSERT(old_unique <= new_unique); 1708a9799022Sck mrsdelta = MIN(new_unique - old_unique, 1709a9799022Sck ds_next->ds_reserved - old_unique); 171074e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, 171174e7dc98SMatthew Ahrens DD_USED_REFRSRV, -mrsdelta, 0, 0, tx); 1712a9799022Sck } 1713fa9e4066Sahrens } 1714745cd3c5Smaybee dsl_dataset_rele(ds_next, FTAG); 1715fa9e4066Sahrens } else { 1716fa9e4066Sahrens /* 1717fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1718fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1719fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1720fa9e4066Sahrens * safe to ignore the deadlist contents.) 1721fa9e4066Sahrens */ 1722fa9e4066Sahrens struct killarg ka; 1723fa9e4066Sahrens 1724fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1725fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1726fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1727fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1728fa9e4066Sahrens 1729fa9e4066Sahrens /* 1730fa9e4066Sahrens * Free everything that we point to (that's born after 1731fa9e4066Sahrens * the previous snapshot, if we are a clone) 1732fa9e4066Sahrens * 173374e7dc98SMatthew Ahrens * NB: this should be very quick, because we already 173474e7dc98SMatthew Ahrens * freed all the objects in open context. 1735fa9e4066Sahrens */ 173674e7dc98SMatthew Ahrens ka.ds = ds; 1737fa9e4066Sahrens ka.tx = tx; 173888b7b0f2SMatthew Ahrens err = traverse_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 173988b7b0f2SMatthew Ahrens TRAVERSE_POST, kill_blkptr, &ka); 1740fa9e4066Sahrens ASSERT3U(err, ==, 0); 17413e78c5fbSChris Kirby ASSERT(!DS_UNIQUE_IS_ACCURATE(ds) || 174274e7dc98SMatthew Ahrens ds->ds_phys->ds_unique_bytes == 0); 1743ca45db41SChris Kirby 1744ca45db41SChris Kirby if (ds->ds_prev != NULL) { 1745ca45db41SChris Kirby dsl_dataset_rele(ds->ds_prev, ds); 1746ca45db41SChris Kirby ds->ds_prev = ds_prev = NULL; 1747ca45db41SChris Kirby } 1748fa9e4066Sahrens } 1749fa9e4066Sahrens 17501d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1751745cd3c5Smaybee /* Erase the link in the dir */ 17521d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 17531d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1754745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0); 1755745cd3c5Smaybee err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1756745cd3c5Smaybee ASSERT(err == 0); 1757fa9e4066Sahrens } else { 1758fa9e4066Sahrens /* remove from snapshot namespace */ 1759fa9e4066Sahrens dsl_dataset_t *ds_head; 1760745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0); 1761745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1762745cd3c5Smaybee ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head)); 17638660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1764fa9e4066Sahrens #ifdef ZFS_DEBUG 1765fa9e4066Sahrens { 1766fa9e4066Sahrens uint64_t val; 1767ab04eb8eStimh 1768745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds_head, 1769ab04eb8eStimh ds->ds_snapname, &val); 1770fa9e4066Sahrens ASSERT3U(err, ==, 0); 1771fa9e4066Sahrens ASSERT3U(val, ==, obj); 1772fa9e4066Sahrens } 1773fa9e4066Sahrens #endif 1774745cd3c5Smaybee err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx); 1775fa9e4066Sahrens ASSERT(err == 0); 1776745cd3c5Smaybee dsl_dataset_rele(ds_head, FTAG); 1777fa9e4066Sahrens } 1778fa9e4066Sahrens 1779fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1780745cd3c5Smaybee dsl_dataset_rele(ds_prev, FTAG); 1781fa9e4066Sahrens 1782990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 1783ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx, 1784ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 1785ecd6cf80Smarks 1786088f3894Sahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 1787088f3894Sahrens uint64_t count; 1788088f3894Sahrens ASSERT(0 == zap_count(mos, 1789088f3894Sahrens ds->ds_phys->ds_next_clones_obj, &count) && count == 0); 1790088f3894Sahrens VERIFY(0 == dmu_object_free(mos, 1791088f3894Sahrens ds->ds_phys->ds_next_clones_obj, tx)); 1792088f3894Sahrens } 179374e7dc98SMatthew Ahrens if (ds->ds_phys->ds_props_obj != 0) 179474e7dc98SMatthew Ahrens VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_props_obj, tx)); 1795842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) 1796842727c2SChris Kirby VERIFY(0 == zap_destroy(mos, ds->ds_phys->ds_userrefs_obj, tx)); 1797745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 1798745cd3c5Smaybee ds->ds_dir = NULL; 1799745cd3c5Smaybee dsl_dataset_drain_refs(ds, tag); 18001d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1801842727c2SChris Kirby 1802842727c2SChris Kirby if (dsda->rm_origin) { 1803842727c2SChris Kirby /* 1804842727c2SChris Kirby * Remove the origin of the clone we just destroyed. 1805842727c2SChris Kirby */ 1806842727c2SChris Kirby struct dsl_ds_destroyarg ndsda = {0}; 1807842727c2SChris Kirby 1808ca45db41SChris Kirby ndsda.ds = dsda->rm_origin; 1809842727c2SChris Kirby dsl_dataset_destroy_sync(&ndsda, tag, cr, tx); 1810842727c2SChris Kirby } 1811fa9e4066Sahrens } 1812fa9e4066Sahrens 1813a9799022Sck static int 1814a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx) 1815a9799022Sck { 1816a9799022Sck uint64_t asize; 1817a9799022Sck 1818a9799022Sck if (!dmu_tx_is_syncing(tx)) 1819a9799022Sck return (0); 1820a9799022Sck 1821a9799022Sck /* 1822a9799022Sck * If there's an fs-only reservation, any blocks that might become 1823a9799022Sck * owned by the snapshot dataset must be accommodated by space 1824a9799022Sck * outside of the reservation. 1825a9799022Sck */ 1826a9799022Sck asize = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 1827a9799022Sck if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, FALSE)) 1828a9799022Sck return (ENOSPC); 1829a9799022Sck 1830a9799022Sck /* 1831a9799022Sck * Propogate any reserved space for this snapshot to other 1832a9799022Sck * snapshot checks in this sync group. 1833a9799022Sck */ 1834a9799022Sck if (asize > 0) 1835a9799022Sck dsl_dir_willuse_space(ds->ds_dir, asize, tx); 1836a9799022Sck 1837a9799022Sck return (0); 1838a9799022Sck } 1839a9799022Sck 18401d452cf5Sahrens /* ARGSUSED */ 1841fa9e4066Sahrens int 18421d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1843fa9e4066Sahrens { 18443cb34c60Sahrens dsl_dataset_t *ds = arg1; 18451d452cf5Sahrens const char *snapname = arg2; 1846fa9e4066Sahrens int err; 18471d452cf5Sahrens uint64_t value; 1848fa9e4066Sahrens 18491d452cf5Sahrens /* 18501d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 18511d452cf5Sahrens * is already one, try again. 18521d452cf5Sahrens */ 18531d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 18541d452cf5Sahrens return (EAGAIN); 1855fa9e4066Sahrens 18561d452cf5Sahrens /* 18571d452cf5Sahrens * Check for conflicting name snapshot name. 18581d452cf5Sahrens */ 1859745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds, snapname, &value); 18601d452cf5Sahrens if (err == 0) 1861fa9e4066Sahrens return (EEXIST); 18621d452cf5Sahrens if (err != ENOENT) 18631d452cf5Sahrens return (err); 1864fa9e4066Sahrens 1865b7661cccSmmusante /* 1866b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 1867b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 1868b7661cccSmmusante */ 1869b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 1870b7661cccSmmusante return (ENAMETOOLONG); 1871b7661cccSmmusante 1872a9799022Sck err = dsl_dataset_snapshot_reserve_space(ds, tx); 1873a9799022Sck if (err) 1874a9799022Sck return (err); 1875a9799022Sck 18761d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 18771d452cf5Sahrens return (0); 18781d452cf5Sahrens } 1879fa9e4066Sahrens 18801d452cf5Sahrens void 1881ecd6cf80Smarks dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 18821d452cf5Sahrens { 18833cb34c60Sahrens dsl_dataset_t *ds = arg1; 18841d452cf5Sahrens const char *snapname = arg2; 18851d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 18861d452cf5Sahrens dmu_buf_t *dbuf; 18871d452cf5Sahrens dsl_dataset_phys_t *dsphys; 1888088f3894Sahrens uint64_t dsobj, crtxg; 18891d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 18901d452cf5Sahrens int err; 1891fa9e4066Sahrens 18921d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1893fa9e4066Sahrens 1894088f3894Sahrens /* 1895088f3894Sahrens * The origin's ds_creation_txg has to be < TXG_INITIAL 1896088f3894Sahrens */ 1897088f3894Sahrens if (strcmp(snapname, ORIGIN_DIR_NAME) == 0) 1898088f3894Sahrens crtxg = 1; 1899088f3894Sahrens else 1900088f3894Sahrens crtxg = tx->tx_txg; 1901088f3894Sahrens 19021649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 19031649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 1904ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1905fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 1906fa9e4066Sahrens dsphys = dbuf->db_data; 1907745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 19081d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 1909fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 1910fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1911fa9e4066Sahrens sizeof (dsphys->ds_guid)); 1912fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1913fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1914fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1915fa9e4066Sahrens dsphys->ds_num_children = 1; 1916fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1917088f3894Sahrens dsphys->ds_creation_txg = crtxg; 1918fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1919fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1920fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1921fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 192299653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 1923fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 1924ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 1925fa9e4066Sahrens 19261d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 19271d452cf5Sahrens if (ds->ds_prev) { 1928088f3894Sahrens uint64_t next_clones_obj = 1929088f3894Sahrens ds->ds_prev->ds_phys->ds_next_clones_obj; 19301d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 1931fa9e4066Sahrens ds->ds_object || 19321d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 19331d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 19341d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1935fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 19361d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 19371d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1938088f3894Sahrens } else if (next_clones_obj != 0) { 1939c33e334fSMatthew Ahrens remove_from_next_clones(ds->ds_prev, 1940c33e334fSMatthew Ahrens dsphys->ds_next_snap_obj, tx); 1941088f3894Sahrens VERIFY3U(0, ==, zap_add_int(mos, 1942088f3894Sahrens next_clones_obj, dsobj, tx)); 1943fa9e4066Sahrens } 1944fa9e4066Sahrens } 1945fa9e4066Sahrens 1946a9799022Sck /* 1947a9799022Sck * If we have a reference-reservation on this dataset, we will 1948a9799022Sck * need to increase the amount of refreservation being charged 1949a9799022Sck * since our unique space is going to zero. 1950a9799022Sck */ 1951a9799022Sck if (ds->ds_reserved) { 1952a9799022Sck int64_t add = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 195374e7dc98SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, 195474e7dc98SMatthew Ahrens add, 0, 0, tx); 1955a9799022Sck } 1956a9799022Sck 1957fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1958fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1959a4611edeSahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg); 1960fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1961088f3894Sahrens ds->ds_phys->ds_prev_snap_txg = crtxg; 1962fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1963a9799022Sck if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 1964a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1965fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1966fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1967ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1968ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1969fa9e4066Sahrens 1970fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1971fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1972fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 1973fa9e4066Sahrens ASSERT(err == 0); 1974fa9e4066Sahrens 1975fa9e4066Sahrens if (ds->ds_prev) 1976745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 1977745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1978745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev)); 1979ecd6cf80Smarks 1980088f3894Sahrens dsl_pool_ds_snapshotted(ds, tx); 1981088f3894Sahrens 198271eb0538SChris Kirby dsl_dir_snap_cmtime_update(ds->ds_dir); 198371eb0538SChris Kirby 1984ecd6cf80Smarks spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr, 198540feaa91Sahrens "dataset = %llu", dsobj); 1986fa9e4066Sahrens } 1987fa9e4066Sahrens 1988fa9e4066Sahrens void 1989c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 1990fa9e4066Sahrens { 1991fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1992503ad85cSMatthew Ahrens ASSERT(ds->ds_objset != NULL); 1993fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1994fa9e4066Sahrens 199591ebeef5Sahrens /* 199691ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 199791ebeef5Sahrens * sync it out now. 199891ebeef5Sahrens */ 199991ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 200091ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 200191ebeef5Sahrens 2002fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 2003503ad85cSMatthew Ahrens dmu_objset_sync(ds->ds_objset, zio, tx); 2004fa9e4066Sahrens } 2005fa9e4066Sahrens 2006fa9e4066Sahrens void 2007a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 2008fa9e4066Sahrens { 2009a9799022Sck uint64_t refd, avail, uobjs, aobjs; 2010a9799022Sck 2011a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 2012fa9e4066Sahrens 2013a9799022Sck dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); 2014a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); 2015a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); 2016a9799022Sck 2017a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 2018a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 2019a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 2020a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 2021a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, 2022a9799022Sck ds->ds_quota); 2023a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, 2024a9799022Sck ds->ds_reserved); 2025c5904d13Seschrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, 2026c5904d13Seschrock ds->ds_phys->ds_guid); 20271d713200SEric Schrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_UNIQUE, 20281d713200SEric Schrock dsl_dataset_unique(ds)); 20291d713200SEric Schrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_OBJSETID, 20301d713200SEric Schrock ds->ds_object); 2031*92241e0bSTom Erickson dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USERREFS, 2032*92241e0bSTom Erickson ds->ds_userrefs); 2033842727c2SChris Kirby dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY, 2034842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds) ? 1 : 0); 2035fa9e4066Sahrens 2036fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2037fa9e4066Sahrens /* 2038fa9e4066Sahrens * This is a snapshot; override the dd's space used with 2039a2eea2e1Sahrens * our unique space and compression ratio. 2040fa9e4066Sahrens */ 2041a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 2042a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 2043a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 2044a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 2045a2eea2e1Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 2046a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes)); 2047fa9e4066Sahrens } 2048fa9e4066Sahrens } 2049fa9e4066Sahrens 2050a2eea2e1Sahrens void 2051a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 2052a2eea2e1Sahrens { 2053a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 2054a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 20553cb34c60Sahrens stat->dds_guid = ds->ds_phys->ds_guid; 2056a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 2057a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 2058a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 2059ebedde84SEric Taylor } else { 2060ebedde84SEric Taylor stat->dds_is_snapshot = B_FALSE; 2061ebedde84SEric Taylor stat->dds_num_clones = 0; 2062a2eea2e1Sahrens } 2063a2eea2e1Sahrens 2064a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 20654ccbb6e7Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 2066088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 2067a2eea2e1Sahrens dsl_dataset_t *ods; 2068a2eea2e1Sahrens 2069745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool, 2070745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods)); 20713cb34c60Sahrens dsl_dataset_name(ods, stat->dds_origin); 2072745cd3c5Smaybee dsl_dataset_drop_ref(ods, FTAG); 2073ebedde84SEric Taylor } else { 2074ebedde84SEric Taylor stat->dds_origin[0] = '\0'; 2075a2eea2e1Sahrens } 20764ccbb6e7Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 2077a2eea2e1Sahrens } 2078a2eea2e1Sahrens 2079a2eea2e1Sahrens uint64_t 2080a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 2081a2eea2e1Sahrens { 208291ebeef5Sahrens return (ds->ds_fsid_guid); 2083a2eea2e1Sahrens } 2084a2eea2e1Sahrens 2085a2eea2e1Sahrens void 2086a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 2087a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 2088a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 2089fa9e4066Sahrens { 2090a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 2091a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 2092a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) 2093a9799022Sck *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes; 2094a9799022Sck if (ds->ds_quota != 0) { 2095a9799022Sck /* 2096a9799022Sck * Adjust available bytes according to refquota 2097a9799022Sck */ 2098a9799022Sck if (*refdbytesp < ds->ds_quota) 2099a9799022Sck *availbytesp = MIN(*availbytesp, 2100a9799022Sck ds->ds_quota - *refdbytesp); 2101a9799022Sck else 2102a9799022Sck *availbytesp = 0; 2103a9799022Sck } 2104a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 2105a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 2106fa9e4066Sahrens } 2107fa9e4066Sahrens 2108f18faf3fSek boolean_t 2109f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 2110f18faf3fSek { 2111f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 2112f18faf3fSek 2113f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 2114f18faf3fSek dsl_pool_sync_context(dp)); 2115f18faf3fSek if (ds->ds_prev == NULL) 2116f18faf3fSek return (B_FALSE); 2117f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 2118f18faf3fSek ds->ds_prev->ds_phys->ds_creation_txg) 2119f18faf3fSek return (B_TRUE); 2120f18faf3fSek return (B_FALSE); 2121f18faf3fSek } 2122f18faf3fSek 21231d452cf5Sahrens /* ARGSUSED */ 2124fa9e4066Sahrens static int 21251d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 2126fa9e4066Sahrens { 21271d452cf5Sahrens dsl_dataset_t *ds = arg1; 21281d452cf5Sahrens char *newsnapname = arg2; 21291d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 21301d452cf5Sahrens dsl_dataset_t *hds; 2131fa9e4066Sahrens uint64_t val; 21321d452cf5Sahrens int err; 2133fa9e4066Sahrens 2134745cd3c5Smaybee err = dsl_dataset_hold_obj(dd->dd_pool, 2135745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds); 2136fa9e4066Sahrens if (err) 2137fa9e4066Sahrens return (err); 2138fa9e4066Sahrens 21391d452cf5Sahrens /* new name better not be in use */ 2140745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, newsnapname, &val); 2141745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 21421d452cf5Sahrens 21431d452cf5Sahrens if (err == 0) 21441d452cf5Sahrens err = EEXIST; 21451d452cf5Sahrens else if (err == ENOENT) 21461d452cf5Sahrens err = 0; 2147cdf5b4caSmmusante 2148cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 2149cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 2150cdf5b4caSmmusante err = ENAMETOOLONG; 2151cdf5b4caSmmusante 21521d452cf5Sahrens return (err); 21531d452cf5Sahrens } 2154fa9e4066Sahrens 21551d452cf5Sahrens static void 2156ecd6cf80Smarks dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, 2157ecd6cf80Smarks cred_t *cr, dmu_tx_t *tx) 21581d452cf5Sahrens { 21591d452cf5Sahrens dsl_dataset_t *ds = arg1; 2160ecd6cf80Smarks const char *newsnapname = arg2; 21611d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 21621d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 21631d452cf5Sahrens dsl_dataset_t *hds; 21641d452cf5Sahrens int err; 2165fa9e4066Sahrens 21661d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 2167fa9e4066Sahrens 2168745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, 2169745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds)); 2170fa9e4066Sahrens 21711d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2172745cd3c5Smaybee err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx); 2173fa9e4066Sahrens ASSERT3U(err, ==, 0); 21741d452cf5Sahrens mutex_enter(&ds->ds_lock); 21751d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 21761d452cf5Sahrens mutex_exit(&ds->ds_lock); 21771d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 21781d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 2179fa9e4066Sahrens ASSERT3U(err, ==, 0); 2180fa9e4066Sahrens 2181ecd6cf80Smarks spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 2182ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 2183745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 2184fa9e4066Sahrens } 2185fa9e4066Sahrens 2186f18faf3fSek struct renamesnaparg { 2187cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 2188cdf5b4caSmmusante char failed[MAXPATHLEN]; 2189cdf5b4caSmmusante char *oldsnap; 2190cdf5b4caSmmusante char *newsnap; 2191cdf5b4caSmmusante }; 2192cdf5b4caSmmusante 2193cdf5b4caSmmusante static int 2194cdf5b4caSmmusante dsl_snapshot_rename_one(char *name, void *arg) 2195cdf5b4caSmmusante { 2196f18faf3fSek struct renamesnaparg *ra = arg; 2197cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 2198cdf5b4caSmmusante char *cp; 2199cdf5b4caSmmusante int err; 2200cdf5b4caSmmusante 2201cdf5b4caSmmusante cp = name + strlen(name); 2202cdf5b4caSmmusante *cp = '@'; 2203cdf5b4caSmmusante (void) strcpy(cp + 1, ra->oldsnap); 2204ecd6cf80Smarks 2205ecd6cf80Smarks /* 2206ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 2207ecd6cf80Smarks * so we just pass name for both the to/from argument. 2208ecd6cf80Smarks */ 2209a0dc2951SMatthew Ahrens err = zfs_secpolicy_rename_perms(name, name, CRED()); 2210a0dc2951SMatthew Ahrens if (err == ENOENT) { 2211a0dc2951SMatthew Ahrens return (0); 2212a0dc2951SMatthew Ahrens } else if (err) { 2213ecd6cf80Smarks (void) strcpy(ra->failed, name); 2214ecd6cf80Smarks return (err); 2215ecd6cf80Smarks } 2216ecd6cf80Smarks 2217745cd3c5Smaybee #ifdef _KERNEL 2218745cd3c5Smaybee /* 2219745cd3c5Smaybee * For all filesystems undergoing rename, we'll need to unmount it. 2220745cd3c5Smaybee */ 2221745cd3c5Smaybee (void) zfs_unmount_snap(name, NULL); 2222745cd3c5Smaybee #endif 2223745cd3c5Smaybee err = dsl_dataset_hold(name, ra->dstg, &ds); 2224745cd3c5Smaybee *cp = '\0'; 2225cdf5b4caSmmusante if (err == ENOENT) { 2226cdf5b4caSmmusante return (0); 2227745cd3c5Smaybee } else if (err) { 2228cdf5b4caSmmusante (void) strcpy(ra->failed, name); 2229cdf5b4caSmmusante return (err); 2230cdf5b4caSmmusante } 2231cdf5b4caSmmusante 2232cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 2233cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 2234cdf5b4caSmmusante 2235cdf5b4caSmmusante return (0); 2236cdf5b4caSmmusante } 2237cdf5b4caSmmusante 2238cdf5b4caSmmusante static int 2239cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 2240cdf5b4caSmmusante { 2241cdf5b4caSmmusante int err; 2242f18faf3fSek struct renamesnaparg *ra; 2243cdf5b4caSmmusante dsl_sync_task_t *dst; 2244cdf5b4caSmmusante spa_t *spa; 2245cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 2246cdf5b4caSmmusante int len = strlen(oldname); 2247cdf5b4caSmmusante 2248cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 2249cdf5b4caSmmusante cp = strchr(fsname, '@'); 2250cdf5b4caSmmusante *cp = '\0'; 2251cdf5b4caSmmusante 225240feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 2253cdf5b4caSmmusante if (err) { 2254cdf5b4caSmmusante kmem_free(fsname, len + 1); 2255cdf5b4caSmmusante return (err); 2256cdf5b4caSmmusante } 2257f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 2258cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 2259cdf5b4caSmmusante 2260cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 2261cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 2262cdf5b4caSmmusante *ra->failed = '\0'; 2263cdf5b4caSmmusante 2264cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 2265cdf5b4caSmmusante DS_FIND_CHILDREN); 2266cdf5b4caSmmusante kmem_free(fsname, len + 1); 2267cdf5b4caSmmusante 2268cdf5b4caSmmusante if (err == 0) { 2269cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 2270cdf5b4caSmmusante } 2271cdf5b4caSmmusante 2272cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 2273cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 2274cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 2275cdf5b4caSmmusante if (dst->dst_err) { 2276cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 22772572aa4eSmmusante (void) strcat(ra->failed, "@"); 22782572aa4eSmmusante (void) strcat(ra->failed, ra->newsnap); 2279cdf5b4caSmmusante } 2280745cd3c5Smaybee dsl_dataset_rele(ds, ra->dstg); 2281cdf5b4caSmmusante } 2282cdf5b4caSmmusante 2283ecd6cf80Smarks if (err) 2284ecd6cf80Smarks (void) strcpy(oldname, ra->failed); 2285cdf5b4caSmmusante 2286cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 2287f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 2288cdf5b4caSmmusante spa_close(spa, FTAG); 2289cdf5b4caSmmusante return (err); 2290cdf5b4caSmmusante } 2291cdf5b4caSmmusante 22923a5a36beSmmusante static int 22933a5a36beSmmusante dsl_valid_rename(char *oldname, void *arg) 22943a5a36beSmmusante { 22953a5a36beSmmusante int delta = *(int *)arg; 22963a5a36beSmmusante 22973a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 22983a5a36beSmmusante return (ENAMETOOLONG); 22993a5a36beSmmusante 23003a5a36beSmmusante return (0); 23013a5a36beSmmusante } 23023a5a36beSmmusante 2303fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 2304fa9e4066Sahrens int 2305745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive) 2306fa9e4066Sahrens { 2307fa9e4066Sahrens dsl_dir_t *dd; 23081d452cf5Sahrens dsl_dataset_t *ds; 2309fa9e4066Sahrens const char *tail; 2310fa9e4066Sahrens int err; 2311fa9e4066Sahrens 23121d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 2313ea8dc4b6Seschrock if (err) 2314ea8dc4b6Seschrock return (err); 23151db42183SEric Taylor /* 23161db42183SEric Taylor * If there are more than 2 references there may be holds 23171db42183SEric Taylor * hanging around that haven't been cleared out yet. 23181db42183SEric Taylor */ 23191db42183SEric Taylor if (dmu_buf_refcount(dd->dd_dbuf) > 2) 23201db42183SEric Taylor txg_wait_synced(dd->dd_pool, 0); 2321fa9e4066Sahrens if (tail == NULL) { 23223a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 23233a5a36beSmmusante 2324088f3894Sahrens /* if we're growing, validate child name lengths */ 23253a5a36beSmmusante if (delta > 0) 23263a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 23273a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 23283a5a36beSmmusante 23293a5a36beSmmusante if (!err) 23303a5a36beSmmusante err = dsl_dir_rename(dd, newname); 2331fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2332fa9e4066Sahrens return (err); 2333fa9e4066Sahrens } 2334fa9e4066Sahrens if (tail[0] != '@') { 2335681d9761SEric Taylor /* the name ended in a nonexistent component */ 2336fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2337fa9e4066Sahrens return (ENOENT); 2338fa9e4066Sahrens } 2339fa9e4066Sahrens 2340fa9e4066Sahrens dsl_dir_close(dd, FTAG); 23411d452cf5Sahrens 23421d452cf5Sahrens /* new name must be snapshot in same filesystem */ 23431d452cf5Sahrens tail = strchr(newname, '@'); 23441d452cf5Sahrens if (tail == NULL) 23451d452cf5Sahrens return (EINVAL); 23461d452cf5Sahrens tail++; 23471d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 23481d452cf5Sahrens return (EXDEV); 23491d452cf5Sahrens 2350cdf5b4caSmmusante if (recursive) { 2351cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 2352cdf5b4caSmmusante } else { 2353745cd3c5Smaybee err = dsl_dataset_hold(oldname, FTAG, &ds); 2354cdf5b4caSmmusante if (err) 2355cdf5b4caSmmusante return (err); 23561d452cf5Sahrens 2357cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2358cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 2359cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 23601d452cf5Sahrens 2361745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2362cdf5b4caSmmusante } 23631d452cf5Sahrens 2364fa9e4066Sahrens return (err); 2365fa9e4066Sahrens } 236699653d4eSeschrock 2367088f3894Sahrens struct promotenode { 2368745cd3c5Smaybee list_node_t link; 2369745cd3c5Smaybee dsl_dataset_t *ds; 2370745cd3c5Smaybee }; 2371745cd3c5Smaybee 23721d452cf5Sahrens struct promotearg { 237374e7dc98SMatthew Ahrens list_t shared_snaps, origin_snaps, clone_snaps; 237474e7dc98SMatthew Ahrens dsl_dataset_t *origin_origin, *origin_head; 237574e7dc98SMatthew Ahrens uint64_t used, comp, uncomp, unique, cloneusedsnap, originusedsnap; 2376681d9761SEric Taylor char *err_ds; 23771d452cf5Sahrens }; 23781d452cf5Sahrens 237974e7dc98SMatthew Ahrens static int snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep); 238074e7dc98SMatthew Ahrens 2381ecd6cf80Smarks /* ARGSUSED */ 238299653d4eSeschrock static int 23831d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 238499653d4eSeschrock { 23851d452cf5Sahrens dsl_dataset_t *hds = arg1; 23861d452cf5Sahrens struct promotearg *pa = arg2; 238774e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2388745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 2389745cd3c5Smaybee int err; 23901d452cf5Sahrens 2391088f3894Sahrens /* Check that it is a real clone */ 2392088f3894Sahrens if (!dsl_dir_is_clone(hds->ds_dir)) 239399653d4eSeschrock return (EINVAL); 239499653d4eSeschrock 23951d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 23961d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 23971d452cf5Sahrens return (0); 23981d452cf5Sahrens 2399745cd3c5Smaybee if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) 2400745cd3c5Smaybee return (EXDEV); 240199653d4eSeschrock 24023cb34c60Sahrens /* compute origin's new unique space */ 240374e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 240474e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 240574e7dc98SMatthew Ahrens err = bplist_space_birthrange(&snap->ds->ds_deadlist, 240674e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_prev_snap_txg, UINT64_MAX, &pa->unique); 240774e7dc98SMatthew Ahrens if (err) 2408745cd3c5Smaybee return (err); 240999653d4eSeschrock 2410745cd3c5Smaybee /* 2411745cd3c5Smaybee * Walk the snapshots that we are moving 2412745cd3c5Smaybee * 241374e7dc98SMatthew Ahrens * Compute space to transfer. Consider the incremental changes 241474e7dc98SMatthew Ahrens * to used for each snapshot: 241574e7dc98SMatthew Ahrens * (my used) = (prev's used) + (blocks born) - (blocks killed) 241674e7dc98SMatthew Ahrens * So each snapshot gave birth to: 241774e7dc98SMatthew Ahrens * (blocks born) = (my used) - (prev's used) + (blocks killed) 2418745cd3c5Smaybee * So a sequence would look like: 241974e7dc98SMatthew Ahrens * (uN - u(N-1) + kN) + ... + (u1 - u0 + k1) + (u0 - 0 + k0) 2420745cd3c5Smaybee * Which simplifies to: 242174e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + k1 + k0 2422745cd3c5Smaybee * Note however, if we stop before we reach the ORIGIN we get: 242374e7dc98SMatthew Ahrens * uN + kN + kN-1 + ... + kM - uM-1 2424745cd3c5Smaybee */ 2425745cd3c5Smaybee pa->used = origin_ds->ds_phys->ds_used_bytes; 2426745cd3c5Smaybee pa->comp = origin_ds->ds_phys->ds_compressed_bytes; 2427745cd3c5Smaybee pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes; 242874e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 242974e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 243099653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 2431745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 243299653d4eSeschrock 243399653d4eSeschrock /* Check that the snapshot name does not conflict */ 243474e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2435745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); 2436681d9761SEric Taylor if (err == 0) { 2437681d9761SEric Taylor err = EEXIST; 2438681d9761SEric Taylor goto out; 2439681d9761SEric Taylor } 2440745cd3c5Smaybee if (err != ENOENT) 2441681d9761SEric Taylor goto out; 244299653d4eSeschrock 2443745cd3c5Smaybee /* The very first snapshot does not have a deadlist */ 244474e7dc98SMatthew Ahrens if (ds->ds_phys->ds_prev_snap_obj == 0) 244574e7dc98SMatthew Ahrens continue; 244674e7dc98SMatthew Ahrens 244774e7dc98SMatthew Ahrens if (err = bplist_space(&ds->ds_deadlist, 244874e7dc98SMatthew Ahrens &dlused, &dlcomp, &dluncomp)) 2449681d9761SEric Taylor goto out; 245074e7dc98SMatthew Ahrens pa->used += dlused; 245174e7dc98SMatthew Ahrens pa->comp += dlcomp; 245274e7dc98SMatthew Ahrens pa->uncomp += dluncomp; 245374e7dc98SMatthew Ahrens } 2454745cd3c5Smaybee 2455745cd3c5Smaybee /* 2456745cd3c5Smaybee * If we are a clone of a clone then we never reached ORIGIN, 2457745cd3c5Smaybee * so we need to subtract out the clone origin's used space. 2458745cd3c5Smaybee */ 245974e7dc98SMatthew Ahrens if (pa->origin_origin) { 246074e7dc98SMatthew Ahrens pa->used -= pa->origin_origin->ds_phys->ds_used_bytes; 246174e7dc98SMatthew Ahrens pa->comp -= pa->origin_origin->ds_phys->ds_compressed_bytes; 246274e7dc98SMatthew Ahrens pa->uncomp -= pa->origin_origin->ds_phys->ds_uncompressed_bytes; 246399653d4eSeschrock } 246499653d4eSeschrock 246599653d4eSeschrock /* Check that there is enough space here */ 246674e7dc98SMatthew Ahrens err = dsl_dir_transfer_possible(origin_ds->ds_dir, hds->ds_dir, 246774e7dc98SMatthew Ahrens pa->used); 246874e7dc98SMatthew Ahrens if (err) 246974e7dc98SMatthew Ahrens return (err); 247074e7dc98SMatthew Ahrens 247174e7dc98SMatthew Ahrens /* 247274e7dc98SMatthew Ahrens * Compute the amounts of space that will be used by snapshots 247374e7dc98SMatthew Ahrens * after the promotion (for both origin and clone). For each, 247474e7dc98SMatthew Ahrens * it is the amount of space that will be on all of their 247574e7dc98SMatthew Ahrens * deadlists (that was not born before their new origin). 247674e7dc98SMatthew Ahrens */ 247774e7dc98SMatthew Ahrens if (hds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 247874e7dc98SMatthew Ahrens uint64_t space; 247974e7dc98SMatthew Ahrens 248074e7dc98SMatthew Ahrens /* 248174e7dc98SMatthew Ahrens * Note, typically this will not be a clone of a clone, 248274e7dc98SMatthew Ahrens * so snap->ds->ds_origin_txg will be < TXG_INITIAL, so 248374e7dc98SMatthew Ahrens * these snaplist_space() -> bplist_space_birthrange() 248474e7dc98SMatthew Ahrens * calls will be fast because they do not have to 248574e7dc98SMatthew Ahrens * iterate over all bps. 248674e7dc98SMatthew Ahrens */ 248774e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 248874e7dc98SMatthew Ahrens err = snaplist_space(&pa->shared_snaps, 248974e7dc98SMatthew Ahrens snap->ds->ds_origin_txg, &pa->cloneusedsnap); 249074e7dc98SMatthew Ahrens if (err) 249174e7dc98SMatthew Ahrens return (err); 249274e7dc98SMatthew Ahrens 249374e7dc98SMatthew Ahrens err = snaplist_space(&pa->clone_snaps, 249474e7dc98SMatthew Ahrens snap->ds->ds_origin_txg, &space); 249574e7dc98SMatthew Ahrens if (err) 249674e7dc98SMatthew Ahrens return (err); 249774e7dc98SMatthew Ahrens pa->cloneusedsnap += space; 249874e7dc98SMatthew Ahrens } 249974e7dc98SMatthew Ahrens if (origin_ds->ds_dir->dd_phys->dd_flags & DD_FLAG_USED_BREAKDOWN) { 250074e7dc98SMatthew Ahrens err = snaplist_space(&pa->origin_snaps, 250174e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_creation_txg, &pa->originusedsnap); 250274e7dc98SMatthew Ahrens if (err) 250374e7dc98SMatthew Ahrens return (err); 2504745cd3c5Smaybee } 25051d452cf5Sahrens 250674e7dc98SMatthew Ahrens return (0); 2507681d9761SEric Taylor out: 2508681d9761SEric Taylor pa->err_ds = snap->ds->ds_snapname; 2509681d9761SEric Taylor return (err); 25101d452cf5Sahrens } 251199653d4eSeschrock 25121d452cf5Sahrens static void 2513ecd6cf80Smarks dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 25141d452cf5Sahrens { 25151d452cf5Sahrens dsl_dataset_t *hds = arg1; 25161d452cf5Sahrens struct promotearg *pa = arg2; 251774e7dc98SMatthew Ahrens struct promotenode *snap = list_head(&pa->shared_snaps); 2518745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 251974e7dc98SMatthew Ahrens dsl_dataset_t *origin_head; 25201d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 25211d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 25223cb34c60Sahrens dsl_dir_t *odd = NULL; 2523088f3894Sahrens uint64_t oldnext_obj; 252474e7dc98SMatthew Ahrens int64_t delta; 25251d452cf5Sahrens 25261d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 25271d452cf5Sahrens 252874e7dc98SMatthew Ahrens snap = list_head(&pa->origin_snaps); 252974e7dc98SMatthew Ahrens origin_head = snap->ds; 253074e7dc98SMatthew Ahrens 25310b69c2f0Sahrens /* 25323cb34c60Sahrens * We need to explicitly open odd, since origin_ds's dd will be 25330b69c2f0Sahrens * changing. 25340b69c2f0Sahrens */ 25353cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object, 25363cb34c60Sahrens NULL, FTAG, &odd)); 253799653d4eSeschrock 2538745cd3c5Smaybee /* change origin's next snap */ 2539745cd3c5Smaybee dmu_buf_will_dirty(origin_ds->ds_dbuf, tx); 2540088f3894Sahrens oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj; 254174e7dc98SMatthew Ahrens snap = list_tail(&pa->clone_snaps); 254274e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_phys->ds_prev_snap_obj, ==, origin_ds->ds_object); 254374e7dc98SMatthew Ahrens origin_ds->ds_phys->ds_next_snap_obj = snap->ds->ds_object; 2544745cd3c5Smaybee 2545088f3894Sahrens /* change the origin's next clone */ 2546088f3894Sahrens if (origin_ds->ds_phys->ds_next_clones_obj) { 2547c33e334fSMatthew Ahrens remove_from_next_clones(origin_ds, snap->ds->ds_object, tx); 2548088f3894Sahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2549088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2550088f3894Sahrens oldnext_obj, tx)); 2551088f3894Sahrens } 2552088f3894Sahrens 2553745cd3c5Smaybee /* change origin */ 2554745cd3c5Smaybee dmu_buf_will_dirty(dd->dd_dbuf, tx); 2555745cd3c5Smaybee ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object); 2556745cd3c5Smaybee dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj; 255774e7dc98SMatthew Ahrens hds->ds_origin_txg = origin_head->ds_origin_txg; 2558745cd3c5Smaybee dmu_buf_will_dirty(odd->dd_dbuf, tx); 2559745cd3c5Smaybee odd->dd_phys->dd_origin_obj = origin_ds->ds_object; 256074e7dc98SMatthew Ahrens origin_head->ds_origin_txg = origin_ds->ds_phys->ds_creation_txg; 2561745cd3c5Smaybee 256299653d4eSeschrock /* move snapshots to this dir */ 256374e7dc98SMatthew Ahrens for (snap = list_head(&pa->shared_snaps); snap; 256474e7dc98SMatthew Ahrens snap = list_next(&pa->shared_snaps, snap)) { 2565745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 256699653d4eSeschrock 25673baa08fcSek /* unregister props as dsl_dir is changing */ 2568503ad85cSMatthew Ahrens if (ds->ds_objset) { 2569503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 2570503ad85cSMatthew Ahrens ds->ds_objset = NULL; 25713baa08fcSek } 257299653d4eSeschrock /* move snap name entry */ 257374e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 257474e7dc98SMatthew Ahrens VERIFY(0 == dsl_dataset_snap_remove(origin_head, 2575745cd3c5Smaybee ds->ds_snapname, tx)); 25761d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 257799653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 257899653d4eSeschrock 8, 1, &ds->ds_object, tx)); 257999653d4eSeschrock /* change containing dsl_dir */ 258099653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 25813cb34c60Sahrens ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object); 258299653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 25833cb34c60Sahrens ASSERT3P(ds->ds_dir, ==, odd); 258499653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 25851d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 258699653d4eSeschrock NULL, ds, &ds->ds_dir)); 258799653d4eSeschrock 258899653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 258974e7dc98SMatthew Ahrens } 259074e7dc98SMatthew Ahrens 259174e7dc98SMatthew Ahrens /* 259274e7dc98SMatthew Ahrens * Change space accounting. 259374e7dc98SMatthew Ahrens * Note, pa->*usedsnap and dd_used_breakdown[SNAP] will either 259474e7dc98SMatthew Ahrens * both be valid, or both be 0 (resulting in delta == 0). This 259574e7dc98SMatthew Ahrens * is true for each of {clone,origin} independently. 259674e7dc98SMatthew Ahrens */ 259774e7dc98SMatthew Ahrens 259874e7dc98SMatthew Ahrens delta = pa->cloneusedsnap - 259974e7dc98SMatthew Ahrens dd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 260074e7dc98SMatthew Ahrens ASSERT3S(delta, >=, 0); 260174e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, delta); 260274e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_SNAP, delta, 0, 0, tx); 260374e7dc98SMatthew Ahrens dsl_dir_diduse_space(dd, DD_USED_HEAD, 260474e7dc98SMatthew Ahrens pa->used - delta, pa->comp, pa->uncomp, tx); 260574e7dc98SMatthew Ahrens 260674e7dc98SMatthew Ahrens delta = pa->originusedsnap - 260774e7dc98SMatthew Ahrens odd->dd_phys->dd_used_breakdown[DD_USED_SNAP]; 260874e7dc98SMatthew Ahrens ASSERT3S(delta, <=, 0); 260974e7dc98SMatthew Ahrens ASSERT3U(pa->used, >=, -delta); 261074e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_SNAP, delta, 0, 0, tx); 261174e7dc98SMatthew Ahrens dsl_dir_diduse_space(odd, DD_USED_HEAD, 261274e7dc98SMatthew Ahrens -pa->used - delta, -pa->comp, -pa->uncomp, tx); 261399653d4eSeschrock 26143cb34c60Sahrens origin_ds->ds_phys->ds_unique_bytes = pa->unique; 261599653d4eSeschrock 2616ecd6cf80Smarks /* log history record */ 2617ecd6cf80Smarks spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 2618745cd3c5Smaybee cr, "dataset = %llu", hds->ds_object); 2619ecd6cf80Smarks 26203cb34c60Sahrens dsl_dir_close(odd, FTAG); 262199653d4eSeschrock } 262299653d4eSeschrock 262374e7dc98SMatthew Ahrens static char *snaplist_tag = "snaplist"; 262474e7dc98SMatthew Ahrens /* 262574e7dc98SMatthew Ahrens * Make a list of dsl_dataset_t's for the snapshots between first_obj 262674e7dc98SMatthew Ahrens * (exclusive) and last_obj (inclusive). The list will be in reverse 262774e7dc98SMatthew Ahrens * order (last_obj will be the list_head()). If first_obj == 0, do all 262874e7dc98SMatthew Ahrens * snapshots back to this dataset's origin. 262974e7dc98SMatthew Ahrens */ 263074e7dc98SMatthew Ahrens static int 263174e7dc98SMatthew Ahrens snaplist_make(dsl_pool_t *dp, boolean_t own, 263274e7dc98SMatthew Ahrens uint64_t first_obj, uint64_t last_obj, list_t *l) 263374e7dc98SMatthew Ahrens { 263474e7dc98SMatthew Ahrens uint64_t obj = last_obj; 263574e7dc98SMatthew Ahrens 263674e7dc98SMatthew Ahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock)); 263774e7dc98SMatthew Ahrens 263874e7dc98SMatthew Ahrens list_create(l, sizeof (struct promotenode), 263974e7dc98SMatthew Ahrens offsetof(struct promotenode, link)); 264074e7dc98SMatthew Ahrens 264174e7dc98SMatthew Ahrens while (obj != first_obj) { 264274e7dc98SMatthew Ahrens dsl_dataset_t *ds; 264374e7dc98SMatthew Ahrens struct promotenode *snap; 264474e7dc98SMatthew Ahrens int err; 264574e7dc98SMatthew Ahrens 264674e7dc98SMatthew Ahrens if (own) { 264774e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, obj, 264874e7dc98SMatthew Ahrens 0, snaplist_tag, &ds); 264974e7dc98SMatthew Ahrens if (err == 0) 265074e7dc98SMatthew Ahrens dsl_dataset_make_exclusive(ds, snaplist_tag); 265174e7dc98SMatthew Ahrens } else { 265274e7dc98SMatthew Ahrens err = dsl_dataset_hold_obj(dp, obj, snaplist_tag, &ds); 265374e7dc98SMatthew Ahrens } 265474e7dc98SMatthew Ahrens if (err == ENOENT) { 265574e7dc98SMatthew Ahrens /* lost race with snapshot destroy */ 265674e7dc98SMatthew Ahrens struct promotenode *last = list_tail(l); 265774e7dc98SMatthew Ahrens ASSERT(obj != last->ds->ds_phys->ds_prev_snap_obj); 265874e7dc98SMatthew Ahrens obj = last->ds->ds_phys->ds_prev_snap_obj; 265974e7dc98SMatthew Ahrens continue; 266074e7dc98SMatthew Ahrens } else if (err) { 266174e7dc98SMatthew Ahrens return (err); 266274e7dc98SMatthew Ahrens } 266374e7dc98SMatthew Ahrens 266474e7dc98SMatthew Ahrens if (first_obj == 0) 266574e7dc98SMatthew Ahrens first_obj = ds->ds_dir->dd_phys->dd_origin_obj; 266674e7dc98SMatthew Ahrens 266774e7dc98SMatthew Ahrens snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP); 266874e7dc98SMatthew Ahrens snap->ds = ds; 266974e7dc98SMatthew Ahrens list_insert_tail(l, snap); 267074e7dc98SMatthew Ahrens obj = ds->ds_phys->ds_prev_snap_obj; 267174e7dc98SMatthew Ahrens } 267274e7dc98SMatthew Ahrens 267374e7dc98SMatthew Ahrens return (0); 267474e7dc98SMatthew Ahrens } 267574e7dc98SMatthew Ahrens 267674e7dc98SMatthew Ahrens static int 267774e7dc98SMatthew Ahrens snaplist_space(list_t *l, uint64_t mintxg, uint64_t *spacep) 267874e7dc98SMatthew Ahrens { 267974e7dc98SMatthew Ahrens struct promotenode *snap; 268074e7dc98SMatthew Ahrens 268174e7dc98SMatthew Ahrens *spacep = 0; 268274e7dc98SMatthew Ahrens for (snap = list_head(l); snap; snap = list_next(l, snap)) { 268374e7dc98SMatthew Ahrens uint64_t used; 268474e7dc98SMatthew Ahrens int err = bplist_space_birthrange(&snap->ds->ds_deadlist, 268574e7dc98SMatthew Ahrens mintxg, UINT64_MAX, &used); 268674e7dc98SMatthew Ahrens if (err) 268774e7dc98SMatthew Ahrens return (err); 268874e7dc98SMatthew Ahrens *spacep += used; 268974e7dc98SMatthew Ahrens } 269074e7dc98SMatthew Ahrens return (0); 269174e7dc98SMatthew Ahrens } 269274e7dc98SMatthew Ahrens 269374e7dc98SMatthew Ahrens static void 269474e7dc98SMatthew Ahrens snaplist_destroy(list_t *l, boolean_t own) 269574e7dc98SMatthew Ahrens { 269674e7dc98SMatthew Ahrens struct promotenode *snap; 269774e7dc98SMatthew Ahrens 26984f5064b7SMark J Musante if (!l || !list_link_active(&l->list_head)) 269974e7dc98SMatthew Ahrens return; 270074e7dc98SMatthew Ahrens 270174e7dc98SMatthew Ahrens while ((snap = list_tail(l)) != NULL) { 270274e7dc98SMatthew Ahrens list_remove(l, snap); 270374e7dc98SMatthew Ahrens if (own) 270474e7dc98SMatthew Ahrens dsl_dataset_disown(snap->ds, snaplist_tag); 270574e7dc98SMatthew Ahrens else 270674e7dc98SMatthew Ahrens dsl_dataset_rele(snap->ds, snaplist_tag); 270774e7dc98SMatthew Ahrens kmem_free(snap, sizeof (struct promotenode)); 270874e7dc98SMatthew Ahrens } 270974e7dc98SMatthew Ahrens list_destroy(l); 271074e7dc98SMatthew Ahrens } 271174e7dc98SMatthew Ahrens 271274e7dc98SMatthew Ahrens /* 271374e7dc98SMatthew Ahrens * Promote a clone. Nomenclature note: 271474e7dc98SMatthew Ahrens * "clone" or "cds": the original clone which is being promoted 271574e7dc98SMatthew Ahrens * "origin" or "ods": the snapshot which is originally clone's origin 271674e7dc98SMatthew Ahrens * "origin head" or "ohds": the dataset which is the head 271774e7dc98SMatthew Ahrens * (filesystem/volume) for the origin 271874e7dc98SMatthew Ahrens * "origin origin": the origin of the origin's filesystem (typically 271974e7dc98SMatthew Ahrens * NULL, indicating that the clone is not a clone of a clone). 272074e7dc98SMatthew Ahrens */ 272199653d4eSeschrock int 2722681d9761SEric Taylor dsl_dataset_promote(const char *name, char *conflsnap) 272399653d4eSeschrock { 272499653d4eSeschrock dsl_dataset_t *ds; 2725745cd3c5Smaybee dsl_dir_t *dd; 2726745cd3c5Smaybee dsl_pool_t *dp; 272799653d4eSeschrock dmu_object_info_t doi; 272874e7dc98SMatthew Ahrens struct promotearg pa = { 0 }; 2729088f3894Sahrens struct promotenode *snap; 2730745cd3c5Smaybee int err; 273199653d4eSeschrock 2732745cd3c5Smaybee err = dsl_dataset_hold(name, FTAG, &ds); 273399653d4eSeschrock if (err) 273499653d4eSeschrock return (err); 2735745cd3c5Smaybee dd = ds->ds_dir; 2736745cd3c5Smaybee dp = dd->dd_pool; 273799653d4eSeschrock 2738745cd3c5Smaybee err = dmu_object_info(dp->dp_meta_objset, 273999653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 274099653d4eSeschrock if (err) { 2741745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 274299653d4eSeschrock return (err); 274399653d4eSeschrock } 274499653d4eSeschrock 274574e7dc98SMatthew Ahrens if (dsl_dataset_is_snapshot(ds) || dd->dd_phys->dd_origin_obj == 0) { 274674e7dc98SMatthew Ahrens dsl_dataset_rele(ds, FTAG); 274774e7dc98SMatthew Ahrens return (EINVAL); 274874e7dc98SMatthew Ahrens } 274974e7dc98SMatthew Ahrens 2750745cd3c5Smaybee /* 2751745cd3c5Smaybee * We are going to inherit all the snapshots taken before our 2752745cd3c5Smaybee * origin (i.e., our new origin will be our parent's origin). 2753745cd3c5Smaybee * Take ownership of them so that we can rename them into our 2754745cd3c5Smaybee * namespace. 2755745cd3c5Smaybee */ 2756745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 2757088f3894Sahrens 275874e7dc98SMatthew Ahrens err = snaplist_make(dp, B_TRUE, 0, dd->dd_phys->dd_origin_obj, 275974e7dc98SMatthew Ahrens &pa.shared_snaps); 276074e7dc98SMatthew Ahrens if (err != 0) 276174e7dc98SMatthew Ahrens goto out; 2762088f3894Sahrens 276374e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, 0, ds->ds_object, &pa.clone_snaps); 276474e7dc98SMatthew Ahrens if (err != 0) 276574e7dc98SMatthew Ahrens goto out; 2766088f3894Sahrens 276774e7dc98SMatthew Ahrens snap = list_head(&pa.shared_snaps); 276874e7dc98SMatthew Ahrens ASSERT3U(snap->ds->ds_object, ==, dd->dd_phys->dd_origin_obj); 276974e7dc98SMatthew Ahrens err = snaplist_make(dp, B_FALSE, dd->dd_phys->dd_origin_obj, 277074e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, &pa.origin_snaps); 277174e7dc98SMatthew Ahrens if (err != 0) 277274e7dc98SMatthew Ahrens goto out; 2773088f3894Sahrens 277474e7dc98SMatthew Ahrens if (dsl_dir_is_clone(snap->ds->ds_dir)) { 277574e7dc98SMatthew Ahrens err = dsl_dataset_own_obj(dp, 277674e7dc98SMatthew Ahrens snap->ds->ds_dir->dd_phys->dd_origin_obj, 277774e7dc98SMatthew Ahrens 0, FTAG, &pa.origin_origin); 277874e7dc98SMatthew Ahrens if (err != 0) 277974e7dc98SMatthew Ahrens goto out; 278074e7dc98SMatthew Ahrens } 2781745cd3c5Smaybee 278274e7dc98SMatthew Ahrens out: 278374e7dc98SMatthew Ahrens rw_exit(&dp->dp_config_rwlock); 2784745cd3c5Smaybee 278599653d4eSeschrock /* 278699653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 278799653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 278899653d4eSeschrock * bonus buffers. 278999653d4eSeschrock */ 279074e7dc98SMatthew Ahrens if (err == 0) { 279174e7dc98SMatthew Ahrens err = dsl_sync_task_do(dp, dsl_dataset_promote_check, 279274e7dc98SMatthew Ahrens dsl_dataset_promote_sync, ds, &pa, 2793b24ab676SJeff Bonwick 2 + 2 * doi.doi_physical_blocks_512); 2794681d9761SEric Taylor if (err && pa.err_ds && conflsnap) 2795681d9761SEric Taylor (void) strncpy(conflsnap, pa.err_ds, MAXNAMELEN); 2796745cd3c5Smaybee } 279774e7dc98SMatthew Ahrens 279874e7dc98SMatthew Ahrens snaplist_destroy(&pa.shared_snaps, B_TRUE); 279974e7dc98SMatthew Ahrens snaplist_destroy(&pa.clone_snaps, B_FALSE); 280074e7dc98SMatthew Ahrens snaplist_destroy(&pa.origin_snaps, B_FALSE); 280174e7dc98SMatthew Ahrens if (pa.origin_origin) 280274e7dc98SMatthew Ahrens dsl_dataset_disown(pa.origin_origin, FTAG); 2803745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 280499653d4eSeschrock return (err); 280599653d4eSeschrock } 2806b1b8ab34Slling 28073cb34c60Sahrens struct cloneswaparg { 28083cb34c60Sahrens dsl_dataset_t *cds; /* clone dataset */ 28093cb34c60Sahrens dsl_dataset_t *ohds; /* origin's head dataset */ 28103cb34c60Sahrens boolean_t force; 2811a9b821a0Sck int64_t unused_refres_delta; /* change in unconsumed refreservation */ 28123cb34c60Sahrens }; 2813f18faf3fSek 2814f18faf3fSek /* ARGSUSED */ 2815f18faf3fSek static int 2816f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 2817f18faf3fSek { 28183cb34c60Sahrens struct cloneswaparg *csa = arg1; 2819f18faf3fSek 28203cb34c60Sahrens /* they should both be heads */ 28213cb34c60Sahrens if (dsl_dataset_is_snapshot(csa->cds) || 28223cb34c60Sahrens dsl_dataset_is_snapshot(csa->ohds)) 2823f18faf3fSek return (EINVAL); 2824f18faf3fSek 28253cb34c60Sahrens /* the branch point should be just before them */ 28263cb34c60Sahrens if (csa->cds->ds_prev != csa->ohds->ds_prev) 2827f18faf3fSek return (EINVAL); 2828f18faf3fSek 2829ae46e4c7SMatthew Ahrens /* cds should be the clone (unless they are unrelated) */ 2830ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev != NULL && 2831ae46e4c7SMatthew Ahrens csa->cds->ds_prev != csa->cds->ds_dir->dd_pool->dp_origin_snap && 2832ae46e4c7SMatthew Ahrens csa->ohds->ds_object != 2833ae46e4c7SMatthew Ahrens csa->cds->ds_prev->ds_phys->ds_next_snap_obj) 28343cb34c60Sahrens return (EINVAL); 2835f18faf3fSek 28363cb34c60Sahrens /* the clone should be a child of the origin */ 28373cb34c60Sahrens if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir) 28383cb34c60Sahrens return (EINVAL); 2839f18faf3fSek 28403cb34c60Sahrens /* ohds shouldn't be modified unless 'force' */ 28413cb34c60Sahrens if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) 28423cb34c60Sahrens return (ETXTBSY); 2843a9b821a0Sck 2844a9b821a0Sck /* adjust amount of any unconsumed refreservation */ 2845a9b821a0Sck csa->unused_refres_delta = 2846a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 2847a9b821a0Sck csa->ohds->ds_phys->ds_unique_bytes) - 2848a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 2849a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 2850a9b821a0Sck 2851a9b821a0Sck if (csa->unused_refres_delta > 0 && 2852a9b821a0Sck csa->unused_refres_delta > 2853a9b821a0Sck dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) 2854a9b821a0Sck return (ENOSPC); 2855a9b821a0Sck 2856c4cbca4fSChris Kirby if (csa->ohds->ds_quota != 0 && 2857c4cbca4fSChris Kirby csa->cds->ds_phys->ds_unique_bytes > csa->ohds->ds_quota) 2858c4cbca4fSChris Kirby return (EDQUOT); 2859c4cbca4fSChris Kirby 28603cb34c60Sahrens return (0); 2861f18faf3fSek } 2862f18faf3fSek 2863f18faf3fSek /* ARGSUSED */ 2864f18faf3fSek static void 2865f18faf3fSek dsl_dataset_clone_swap_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 2866f18faf3fSek { 28673cb34c60Sahrens struct cloneswaparg *csa = arg1; 28683cb34c60Sahrens dsl_pool_t *dp = csa->cds->ds_dir->dd_pool; 2869f18faf3fSek 2870a9b821a0Sck ASSERT(csa->cds->ds_reserved == 0); 2871c4cbca4fSChris Kirby ASSERT(csa->ohds->ds_quota == 0 || 2872c4cbca4fSChris Kirby csa->cds->ds_phys->ds_unique_bytes <= csa->ohds->ds_quota); 2873a9b821a0Sck 28743cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); 28753cb34c60Sahrens dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); 2876f18faf3fSek 2877503ad85cSMatthew Ahrens if (csa->cds->ds_objset != NULL) { 2878503ad85cSMatthew Ahrens dmu_objset_evict(csa->cds->ds_objset); 2879503ad85cSMatthew Ahrens csa->cds->ds_objset = NULL; 28803cb34c60Sahrens } 2881f18faf3fSek 2882503ad85cSMatthew Ahrens if (csa->ohds->ds_objset != NULL) { 2883503ad85cSMatthew Ahrens dmu_objset_evict(csa->ohds->ds_objset); 2884503ad85cSMatthew Ahrens csa->ohds->ds_objset = NULL; 28853cb34c60Sahrens } 2886f18faf3fSek 2887ae46e4c7SMatthew Ahrens /* 2888ae46e4c7SMatthew Ahrens * Reset origin's unique bytes, if it exists. 2889ae46e4c7SMatthew Ahrens */ 2890ae46e4c7SMatthew Ahrens if (csa->cds->ds_prev) { 2891ae46e4c7SMatthew Ahrens dsl_dataset_t *origin = csa->cds->ds_prev; 2892ae46e4c7SMatthew Ahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 2893ae46e4c7SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->cds->ds_deadlist, 2894ae46e4c7SMatthew Ahrens origin->ds_phys->ds_prev_snap_txg, UINT64_MAX, 2895ae46e4c7SMatthew Ahrens &origin->ds_phys->ds_unique_bytes)); 2896ae46e4c7SMatthew Ahrens } 2897f18faf3fSek 2898f18faf3fSek /* swap blkptrs */ 2899f18faf3fSek { 2900f18faf3fSek blkptr_t tmp; 29013cb34c60Sahrens tmp = csa->ohds->ds_phys->ds_bp; 29023cb34c60Sahrens csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp; 29033cb34c60Sahrens csa->cds->ds_phys->ds_bp = tmp; 2904f18faf3fSek } 2905f18faf3fSek 2906f18faf3fSek /* set dd_*_bytes */ 2907f18faf3fSek { 2908f18faf3fSek int64_t dused, dcomp, duncomp; 2909f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 2910f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 2911f18faf3fSek 291274e7dc98SMatthew Ahrens ASSERT3U(csa->cds->ds_dir->dd_phys-> 291374e7dc98SMatthew Ahrens dd_used_breakdown[DD_USED_SNAP], ==, 0); 291474e7dc98SMatthew Ahrens 29153cb34c60Sahrens VERIFY(0 == bplist_space(&csa->cds->ds_deadlist, &cdl_used, 2916f18faf3fSek &cdl_comp, &cdl_uncomp)); 29173cb34c60Sahrens VERIFY(0 == bplist_space(&csa->ohds->ds_deadlist, &odl_used, 2918f18faf3fSek &odl_comp, &odl_uncomp)); 291974e7dc98SMatthew Ahrens 29203cb34c60Sahrens dused = csa->cds->ds_phys->ds_used_bytes + cdl_used - 29213cb34c60Sahrens (csa->ohds->ds_phys->ds_used_bytes + odl_used); 29223cb34c60Sahrens dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp - 29233cb34c60Sahrens (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp); 29243cb34c60Sahrens duncomp = csa->cds->ds_phys->ds_uncompressed_bytes + 29253cb34c60Sahrens cdl_uncomp - 29263cb34c60Sahrens (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 29273cb34c60Sahrens 292874e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_HEAD, 29293cb34c60Sahrens dused, dcomp, duncomp, tx); 293074e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->cds->ds_dir, DD_USED_HEAD, 29313cb34c60Sahrens -dused, -dcomp, -duncomp, tx); 293274e7dc98SMatthew Ahrens 293374e7dc98SMatthew Ahrens /* 293474e7dc98SMatthew Ahrens * The difference in the space used by snapshots is the 293574e7dc98SMatthew Ahrens * difference in snapshot space due to the head's 293674e7dc98SMatthew Ahrens * deadlist (since that's the only thing that's 293774e7dc98SMatthew Ahrens * changing that affects the snapused). 293874e7dc98SMatthew Ahrens */ 293974e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->cds->ds_deadlist, 294074e7dc98SMatthew Ahrens csa->ohds->ds_origin_txg, UINT64_MAX, &cdl_used)); 294174e7dc98SMatthew Ahrens VERIFY(0 == bplist_space_birthrange(&csa->ohds->ds_deadlist, 294274e7dc98SMatthew Ahrens csa->ohds->ds_origin_txg, UINT64_MAX, &odl_used)); 294374e7dc98SMatthew Ahrens dsl_dir_transfer_space(csa->ohds->ds_dir, cdl_used - odl_used, 294474e7dc98SMatthew Ahrens DD_USED_HEAD, DD_USED_SNAP, tx); 29453cb34c60Sahrens } 29463cb34c60Sahrens 29473cb34c60Sahrens #define SWITCH64(x, y) \ 29483cb34c60Sahrens { \ 29493cb34c60Sahrens uint64_t __tmp = (x); \ 29503cb34c60Sahrens (x) = (y); \ 29513cb34c60Sahrens (y) = __tmp; \ 2952f18faf3fSek } 2953f18faf3fSek 2954f18faf3fSek /* swap ds_*_bytes */ 29553cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_used_bytes, 29563cb34c60Sahrens csa->cds->ds_phys->ds_used_bytes); 29573cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes, 29583cb34c60Sahrens csa->cds->ds_phys->ds_compressed_bytes); 29593cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, 29603cb34c60Sahrens csa->cds->ds_phys->ds_uncompressed_bytes); 2961a9b821a0Sck SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, 2962a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 2963a9b821a0Sck 2964a9b821a0Sck /* apply any parent delta for change in unconsumed refreservation */ 296574e7dc98SMatthew Ahrens dsl_dir_diduse_space(csa->ohds->ds_dir, DD_USED_REFRSRV, 296674e7dc98SMatthew Ahrens csa->unused_refres_delta, 0, 0, tx); 2967f18faf3fSek 2968f18faf3fSek /* swap deadlists */ 29693cb34c60Sahrens bplist_close(&csa->cds->ds_deadlist); 29703cb34c60Sahrens bplist_close(&csa->ohds->ds_deadlist); 29713cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj, 29723cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj); 29733cb34c60Sahrens VERIFY(0 == bplist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset, 29743cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj)); 29753cb34c60Sahrens VERIFY(0 == bplist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, 29763cb34c60Sahrens csa->ohds->ds_phys->ds_deadlist_obj)); 297788b7b0f2SMatthew Ahrens 297888b7b0f2SMatthew Ahrens dsl_pool_ds_clone_swapped(csa->ohds, csa->cds, tx); 2979f18faf3fSek } 2980f18faf3fSek 2981f18faf3fSek /* 2982ae46e4c7SMatthew Ahrens * Swap 'clone' with its origin head datasets. Used at the end of "zfs 2983ae46e4c7SMatthew Ahrens * recv" into an existing fs to swizzle the file system to the new 2984ae46e4c7SMatthew Ahrens * version, and by "zfs rollback". Can also be used to swap two 2985ae46e4c7SMatthew Ahrens * independent head datasets if neither has any snapshots. 2986f18faf3fSek */ 2987f18faf3fSek int 29883cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, 29893cb34c60Sahrens boolean_t force) 2990f18faf3fSek { 29913cb34c60Sahrens struct cloneswaparg csa; 2992745cd3c5Smaybee int error; 2993f18faf3fSek 2994745cd3c5Smaybee ASSERT(clone->ds_owner); 2995745cd3c5Smaybee ASSERT(origin_head->ds_owner); 2996745cd3c5Smaybee retry: 2997745cd3c5Smaybee /* Need exclusive access for the swap */ 2998745cd3c5Smaybee rw_enter(&clone->ds_rwlock, RW_WRITER); 2999745cd3c5Smaybee if (!rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) { 3000745cd3c5Smaybee rw_exit(&clone->ds_rwlock); 3001745cd3c5Smaybee rw_enter(&origin_head->ds_rwlock, RW_WRITER); 3002745cd3c5Smaybee if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) { 3003745cd3c5Smaybee rw_exit(&origin_head->ds_rwlock); 3004745cd3c5Smaybee goto retry; 3005745cd3c5Smaybee } 3006745cd3c5Smaybee } 30073cb34c60Sahrens csa.cds = clone; 30083cb34c60Sahrens csa.ohds = origin_head; 30093cb34c60Sahrens csa.force = force; 3010745cd3c5Smaybee error = dsl_sync_task_do(clone->ds_dir->dd_pool, 3011f18faf3fSek dsl_dataset_clone_swap_check, 3012745cd3c5Smaybee dsl_dataset_clone_swap_sync, &csa, NULL, 9); 3013745cd3c5Smaybee return (error); 3014f18faf3fSek } 3015f18faf3fSek 3016b1b8ab34Slling /* 3017b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 3018b1b8ab34Slling * return the name of that dataset. 3019b1b8ab34Slling */ 3020b1b8ab34Slling int 3021b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 3022b1b8ab34Slling { 3023b1b8ab34Slling spa_t *spa; 3024b1b8ab34Slling dsl_pool_t *dp; 3025745cd3c5Smaybee dsl_dataset_t *ds; 3026b1b8ab34Slling int error; 3027b1b8ab34Slling 3028b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 3029b1b8ab34Slling return (error); 3030b1b8ab34Slling dp = spa_get_dsl(spa); 3031b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 3032745cd3c5Smaybee if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) { 3033745cd3c5Smaybee dsl_dataset_name(ds, buf); 3034745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3035b1b8ab34Slling } 3036b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 3037b1b8ab34Slling spa_close(spa, FTAG); 3038b1b8ab34Slling 3039745cd3c5Smaybee return (error); 3040b1b8ab34Slling } 3041a9799022Sck 3042a9799022Sck int 3043a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, 3044745cd3c5Smaybee uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv) 3045a9799022Sck { 3046a9799022Sck int error = 0; 3047a9799022Sck 3048a9799022Sck ASSERT3S(asize, >, 0); 3049a9799022Sck 30509082849eSck /* 30519082849eSck * *ref_rsrv is the portion of asize that will come from any 30529082849eSck * unconsumed refreservation space. 30539082849eSck */ 30549082849eSck *ref_rsrv = 0; 30559082849eSck 3056a9799022Sck mutex_enter(&ds->ds_lock); 3057a9799022Sck /* 3058a9799022Sck * Make a space adjustment for reserved bytes. 3059a9799022Sck */ 3060a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) { 3061a9799022Sck ASSERT3U(*used, >=, 3062a9799022Sck ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 3063a9799022Sck *used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 30649082849eSck *ref_rsrv = 30659082849eSck asize - MIN(asize, parent_delta(ds, asize + inflight)); 3066a9799022Sck } 3067a9799022Sck 3068a9799022Sck if (!check_quota || ds->ds_quota == 0) { 3069a9799022Sck mutex_exit(&ds->ds_lock); 3070a9799022Sck return (0); 3071a9799022Sck } 3072a9799022Sck /* 3073a9799022Sck * If they are requesting more space, and our current estimate 3074a9799022Sck * is over quota, they get to try again unless the actual 3075a9799022Sck * on-disk is over quota and there are no pending changes (which 3076a9799022Sck * may free up space for us). 3077a9799022Sck */ 3078a9799022Sck if (ds->ds_phys->ds_used_bytes + inflight >= ds->ds_quota) { 3079a9799022Sck if (inflight > 0 || ds->ds_phys->ds_used_bytes < ds->ds_quota) 3080a9799022Sck error = ERESTART; 3081a9799022Sck else 3082a9799022Sck error = EDQUOT; 3083a9799022Sck } 3084a9799022Sck mutex_exit(&ds->ds_lock); 3085a9799022Sck 3086a9799022Sck return (error); 3087a9799022Sck } 3088a9799022Sck 3089a9799022Sck /* ARGSUSED */ 3090a9799022Sck static int 3091a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx) 3092a9799022Sck { 3093a9799022Sck dsl_dataset_t *ds = arg1; 3094*92241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 3095*92241e0bSTom Erickson int err; 3096a9799022Sck 3097a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA) 3098a9799022Sck return (ENOTSUP); 3099a9799022Sck 3100*92241e0bSTom Erickson if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0) 3101*92241e0bSTom Erickson return (err); 3102*92241e0bSTom Erickson 3103*92241e0bSTom Erickson if (psa->psa_effective_value == 0) 3104a9799022Sck return (0); 3105a9799022Sck 3106*92241e0bSTom Erickson if (psa->psa_effective_value < ds->ds_phys->ds_used_bytes || 3107*92241e0bSTom Erickson psa->psa_effective_value < ds->ds_reserved) 3108a9799022Sck return (ENOSPC); 3109a9799022Sck 3110a9799022Sck return (0); 3111a9799022Sck } 3112a9799022Sck 3113*92241e0bSTom Erickson extern void dsl_prop_set_sync(void *, void *, cred_t *, dmu_tx_t *); 3114*92241e0bSTom Erickson 3115a9799022Sck void 3116a9799022Sck dsl_dataset_set_quota_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3117a9799022Sck { 3118a9799022Sck dsl_dataset_t *ds = arg1; 3119*92241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 3120*92241e0bSTom Erickson uint64_t effective_value = psa->psa_effective_value; 3121a9799022Sck 3122*92241e0bSTom Erickson dsl_prop_set_sync(ds, psa, cr, tx); 3123*92241e0bSTom Erickson DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa); 3124a9799022Sck 3125*92241e0bSTom Erickson if (ds->ds_quota != effective_value) { 3126*92241e0bSTom Erickson dmu_buf_will_dirty(ds->ds_dbuf, tx); 3127*92241e0bSTom Erickson ds->ds_quota = effective_value; 3128a9799022Sck 3129*92241e0bSTom Erickson spa_history_internal_log(LOG_DS_REFQUOTA, 3130*92241e0bSTom Erickson ds->ds_dir->dd_pool->dp_spa, tx, cr, "%lld dataset = %llu ", 3131*92241e0bSTom Erickson (longlong_t)ds->ds_quota, ds->ds_object); 3132*92241e0bSTom Erickson } 3133a9799022Sck } 3134a9799022Sck 3135a9799022Sck int 3136*92241e0bSTom Erickson dsl_dataset_set_quota(const char *dsname, zprop_source_t source, uint64_t quota) 3137a9799022Sck { 3138a9799022Sck dsl_dataset_t *ds; 3139*92241e0bSTom Erickson dsl_prop_setarg_t psa; 3140a9799022Sck int err; 3141a9799022Sck 3142*92241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refquota", source, "a); 3143*92241e0bSTom Erickson 3144745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3145a9799022Sck if (err) 3146a9799022Sck return (err); 3147a9799022Sck 3148*92241e0bSTom Erickson /* 3149*92241e0bSTom Erickson * If someone removes a file, then tries to set the quota, we 3150*92241e0bSTom Erickson * want to make sure the file freeing takes effect. 3151*92241e0bSTom Erickson */ 3152*92241e0bSTom Erickson txg_wait_open(ds->ds_dir->dd_pool, 0); 3153*92241e0bSTom Erickson 3154*92241e0bSTom Erickson err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3155*92241e0bSTom Erickson dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, 3156*92241e0bSTom Erickson ds, &psa, 0); 3157a9799022Sck 3158745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3159a9799022Sck return (err); 3160a9799022Sck } 3161a9799022Sck 3162a9799022Sck static int 3163a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx) 3164a9799022Sck { 3165a9799022Sck dsl_dataset_t *ds = arg1; 3166*92241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 3167*92241e0bSTom Erickson uint64_t effective_value; 3168a9799022Sck uint64_t unique; 3169*92241e0bSTom Erickson int err; 3170a9799022Sck 3171a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 3172a9799022Sck SPA_VERSION_REFRESERVATION) 3173a9799022Sck return (ENOTSUP); 3174a9799022Sck 3175a9799022Sck if (dsl_dataset_is_snapshot(ds)) 3176a9799022Sck return (EINVAL); 3177a9799022Sck 3178*92241e0bSTom Erickson if ((err = dsl_prop_predict_sync(ds->ds_dir, psa)) != 0) 3179*92241e0bSTom Erickson return (err); 3180*92241e0bSTom Erickson 3181*92241e0bSTom Erickson effective_value = psa->psa_effective_value; 3182*92241e0bSTom Erickson 3183a9799022Sck /* 3184a9799022Sck * If we are doing the preliminary check in open context, the 3185a9799022Sck * space estimates may be inaccurate. 3186a9799022Sck */ 3187a9799022Sck if (!dmu_tx_is_syncing(tx)) 3188a9799022Sck return (0); 3189a9799022Sck 3190a9799022Sck mutex_enter(&ds->ds_lock); 3191a9799022Sck unique = dsl_dataset_unique(ds); 3192a9799022Sck mutex_exit(&ds->ds_lock); 3193a9799022Sck 3194*92241e0bSTom Erickson if (MAX(unique, effective_value) > MAX(unique, ds->ds_reserved)) { 3195*92241e0bSTom Erickson uint64_t delta = MAX(unique, effective_value) - 3196379c004dSEric Schrock MAX(unique, ds->ds_reserved); 3197379c004dSEric Schrock 3198379c004dSEric Schrock if (delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 3199379c004dSEric Schrock return (ENOSPC); 3200379c004dSEric Schrock if (ds->ds_quota > 0 && 3201*92241e0bSTom Erickson effective_value > ds->ds_quota) 3202379c004dSEric Schrock return (ENOSPC); 3203379c004dSEric Schrock } 3204a9799022Sck 3205a9799022Sck return (0); 3206a9799022Sck } 3207a9799022Sck 3208a9799022Sck /* ARGSUSED */ 3209a9799022Sck static void 3210a9799022Sck dsl_dataset_set_reservation_sync(void *arg1, void *arg2, cred_t *cr, 3211a9799022Sck dmu_tx_t *tx) 3212a9799022Sck { 3213a9799022Sck dsl_dataset_t *ds = arg1; 3214*92241e0bSTom Erickson dsl_prop_setarg_t *psa = arg2; 3215*92241e0bSTom Erickson uint64_t effective_value = psa->psa_effective_value; 321602c8f3f0SMatthew Ahrens uint64_t unique; 321702c8f3f0SMatthew Ahrens int64_t delta; 321802c8f3f0SMatthew Ahrens 3219*92241e0bSTom Erickson dsl_prop_set_sync(ds, psa, cr, tx); 3220*92241e0bSTom Erickson DSL_PROP_CHECK_PREDICTION(ds->ds_dir, psa); 3221*92241e0bSTom Erickson 322202c8f3f0SMatthew Ahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 322302c8f3f0SMatthew Ahrens 322402c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_dir->dd_lock); 322502c8f3f0SMatthew Ahrens mutex_enter(&ds->ds_lock); 322602c8f3f0SMatthew Ahrens unique = dsl_dataset_unique(ds); 3227*92241e0bSTom Erickson delta = MAX(0, (int64_t)(effective_value - unique)) - 322802c8f3f0SMatthew Ahrens MAX(0, (int64_t)(ds->ds_reserved - unique)); 3229*92241e0bSTom Erickson ds->ds_reserved = effective_value; 323002c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_lock); 323102c8f3f0SMatthew Ahrens 323202c8f3f0SMatthew Ahrens dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx); 323302c8f3f0SMatthew Ahrens mutex_exit(&ds->ds_dir->dd_lock); 3234a9799022Sck 323502c8f3f0SMatthew Ahrens spa_history_internal_log(LOG_DS_REFRESERV, 323602c8f3f0SMatthew Ahrens ds->ds_dir->dd_pool->dp_spa, tx, cr, "%lld dataset = %llu", 3237*92241e0bSTom Erickson (longlong_t)effective_value, ds->ds_object); 3238a9799022Sck } 3239a9799022Sck 3240a9799022Sck int 3241*92241e0bSTom Erickson dsl_dataset_set_reservation(const char *dsname, zprop_source_t source, 3242*92241e0bSTom Erickson uint64_t reservation) 3243a9799022Sck { 3244a9799022Sck dsl_dataset_t *ds; 3245*92241e0bSTom Erickson dsl_prop_setarg_t psa; 3246a9799022Sck int err; 3247a9799022Sck 3248*92241e0bSTom Erickson dsl_prop_setarg_init_uint64(&psa, "refreservation", source, 3249*92241e0bSTom Erickson &reservation); 3250*92241e0bSTom Erickson 3251745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 3252a9799022Sck if (err) 3253a9799022Sck return (err); 3254a9799022Sck 3255a9799022Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 3256a9799022Sck dsl_dataset_set_reservation_check, 3257*92241e0bSTom Erickson dsl_dataset_set_reservation_sync, ds, &psa, 0); 3258*92241e0bSTom Erickson 3259745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 3260a9799022Sck return (err); 3261a9799022Sck } 3262842727c2SChris Kirby 3263ca45db41SChris Kirby struct dsl_ds_holdarg { 3264ca45db41SChris Kirby dsl_sync_task_group_t *dstg; 3265ca45db41SChris Kirby char *htag; 3266ca45db41SChris Kirby char *snapname; 3267ca45db41SChris Kirby boolean_t recursive; 3268ca45db41SChris Kirby boolean_t gotone; 3269ca45db41SChris Kirby boolean_t temphold; 3270ca45db41SChris Kirby char failed[MAXPATHLEN]; 3271ca45db41SChris Kirby }; 3272ca45db41SChris Kirby 327315508ac0SChris Kirby /* 327415508ac0SChris Kirby * The max length of a temporary tag prefix is the number of hex digits 327515508ac0SChris Kirby * required to express UINT64_MAX plus one for the hyphen. 327615508ac0SChris Kirby */ 327715508ac0SChris Kirby #define MAX_TAG_PREFIX_LEN 17 327815508ac0SChris Kirby 3279842727c2SChris Kirby static int 3280842727c2SChris Kirby dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx) 3281842727c2SChris Kirby { 3282842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3283ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 3284ca45db41SChris Kirby char *htag = ha->htag; 3285842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3286842727c2SChris Kirby int error = 0; 3287842727c2SChris Kirby 3288842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3289842727c2SChris Kirby return (ENOTSUP); 3290842727c2SChris Kirby 3291842727c2SChris Kirby if (!dsl_dataset_is_snapshot(ds)) 3292842727c2SChris Kirby return (EINVAL); 3293842727c2SChris Kirby 3294842727c2SChris Kirby /* tags must be unique */ 3295842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3296842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj) { 3297842727c2SChris Kirby error = zap_lookup(mos, ds->ds_phys->ds_userrefs_obj, htag, 3298842727c2SChris Kirby 8, 1, tx); 3299842727c2SChris Kirby if (error == 0) 3300842727c2SChris Kirby error = EEXIST; 3301842727c2SChris Kirby else if (error == ENOENT) 3302842727c2SChris Kirby error = 0; 3303842727c2SChris Kirby } 3304842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3305842727c2SChris Kirby 330615508ac0SChris Kirby if (error == 0 && ha->temphold && 330715508ac0SChris Kirby strlen(htag) + MAX_TAG_PREFIX_LEN >= MAXNAMELEN) 330815508ac0SChris Kirby error = E2BIG; 330915508ac0SChris Kirby 3310842727c2SChris Kirby return (error); 3311842727c2SChris Kirby } 3312842727c2SChris Kirby 3313842727c2SChris Kirby static void 3314842727c2SChris Kirby dsl_dataset_user_hold_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 3315842727c2SChris Kirby { 3316842727c2SChris Kirby dsl_dataset_t *ds = arg1; 3317ca45db41SChris Kirby struct dsl_ds_holdarg *ha = arg2; 3318ca45db41SChris Kirby char *htag = ha->htag; 3319ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3320ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 332115508ac0SChris Kirby uint64_t now = gethrestime_sec(); 3322842727c2SChris Kirby uint64_t zapobj; 3323842727c2SChris Kirby 3324842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3325842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj == 0) { 3326842727c2SChris Kirby /* 3327842727c2SChris Kirby * This is the first user hold for this dataset. Create 3328842727c2SChris Kirby * the userrefs zap object. 3329842727c2SChris Kirby */ 3330842727c2SChris Kirby dmu_buf_will_dirty(ds->ds_dbuf, tx); 3331842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj = 3332842727c2SChris Kirby zap_create(mos, DMU_OT_USERREFS, DMU_OT_NONE, 0, tx); 3333842727c2SChris Kirby } else { 3334842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3335842727c2SChris Kirby } 3336842727c2SChris Kirby ds->ds_userrefs++; 3337842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3338842727c2SChris Kirby 3339842727c2SChris Kirby VERIFY(0 == zap_add(mos, zapobj, htag, 8, 1, &now, tx)); 3340842727c2SChris Kirby 3341ca45db41SChris Kirby if (ha->temphold) { 3342ca45db41SChris Kirby VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object, 3343ca45db41SChris Kirby htag, &now, tx)); 3344ca45db41SChris Kirby } 3345ca45db41SChris Kirby 3346842727c2SChris Kirby spa_history_internal_log(LOG_DS_USER_HOLD, 3347ca45db41SChris Kirby dp->dp_spa, tx, cr, "<%s> temp = %d dataset = %llu", htag, 3348ca45db41SChris Kirby (int)ha->temphold, ds->ds_object); 3349842727c2SChris Kirby } 3350842727c2SChris Kirby 3351842727c2SChris Kirby static int 3352842727c2SChris Kirby dsl_dataset_user_hold_one(char *dsname, void *arg) 3353842727c2SChris Kirby { 3354842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3355842727c2SChris Kirby dsl_dataset_t *ds; 3356842727c2SChris Kirby int error; 3357842727c2SChris Kirby char *name; 3358842727c2SChris Kirby 3359842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname plus terminating NULL */ 3360ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3361842727c2SChris Kirby error = dsl_dataset_hold(name, ha->dstg, &ds); 3362ae46e4c7SMatthew Ahrens strfree(name); 3363842727c2SChris Kirby if (error == 0) { 3364d7747cbcSChris Kirby ha->gotone = B_TRUE; 3365842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_hold_check, 3366ca45db41SChris Kirby dsl_dataset_user_hold_sync, ds, ha, 0); 3367842727c2SChris Kirby } else if (error == ENOENT && ha->recursive) { 3368842727c2SChris Kirby error = 0; 3369842727c2SChris Kirby } else { 3370842727c2SChris Kirby (void) strcpy(ha->failed, dsname); 3371842727c2SChris Kirby } 3372842727c2SChris Kirby return (error); 3373842727c2SChris Kirby } 3374842727c2SChris Kirby 3375842727c2SChris Kirby int 3376842727c2SChris Kirby dsl_dataset_user_hold(char *dsname, char *snapname, char *htag, 3377ca45db41SChris Kirby boolean_t recursive, boolean_t temphold) 3378842727c2SChris Kirby { 3379842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3380842727c2SChris Kirby dsl_sync_task_t *dst; 3381842727c2SChris Kirby spa_t *spa; 3382842727c2SChris Kirby int error; 3383842727c2SChris Kirby 3384842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3385842727c2SChris Kirby 3386842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3387842727c2SChris Kirby 3388842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3389842727c2SChris Kirby if (error) { 3390842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3391842727c2SChris Kirby return (error); 3392842727c2SChris Kirby } 3393842727c2SChris Kirby 3394842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3395842727c2SChris Kirby ha->htag = htag; 3396842727c2SChris Kirby ha->snapname = snapname; 3397842727c2SChris Kirby ha->recursive = recursive; 3398ca45db41SChris Kirby ha->temphold = temphold; 3399842727c2SChris Kirby if (recursive) { 3400842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_hold_one, 3401842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3402842727c2SChris Kirby } else { 3403842727c2SChris Kirby error = dsl_dataset_user_hold_one(dsname, ha); 3404842727c2SChris Kirby } 3405842727c2SChris Kirby if (error == 0) 3406842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3407842727c2SChris Kirby 3408842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3409842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3410842727c2SChris Kirby dsl_dataset_t *ds = dst->dst_arg1; 3411842727c2SChris Kirby 3412842727c2SChris Kirby if (dst->dst_err) { 3413842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3414842727c2SChris Kirby *strchr(ha->failed, '@') = '\0'; 3415842727c2SChris Kirby } 3416842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3417842727c2SChris Kirby } 3418842727c2SChris Kirby 3419d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3420d7747cbcSChris Kirby error = ENOENT; 3421d7747cbcSChris Kirby 3422842727c2SChris Kirby if (error) 3423842727c2SChris Kirby (void) strcpy(dsname, ha->failed); 3424842727c2SChris Kirby 3425842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3426842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3427842727c2SChris Kirby spa_close(spa, FTAG); 3428842727c2SChris Kirby return (error); 3429842727c2SChris Kirby } 3430842727c2SChris Kirby 3431842727c2SChris Kirby struct dsl_ds_releasearg { 3432842727c2SChris Kirby dsl_dataset_t *ds; 3433842727c2SChris Kirby const char *htag; 3434842727c2SChris Kirby boolean_t own; /* do we own or just hold ds? */ 3435842727c2SChris Kirby }; 3436842727c2SChris Kirby 3437842727c2SChris Kirby static int 3438842727c2SChris Kirby dsl_dataset_release_might_destroy(dsl_dataset_t *ds, const char *htag, 3439842727c2SChris Kirby boolean_t *might_destroy) 3440842727c2SChris Kirby { 3441842727c2SChris Kirby objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 3442842727c2SChris Kirby uint64_t zapobj; 3443842727c2SChris Kirby uint64_t tmp; 3444842727c2SChris Kirby int error; 3445842727c2SChris Kirby 3446842727c2SChris Kirby *might_destroy = B_FALSE; 3447842727c2SChris Kirby 3448842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3449842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3450842727c2SChris Kirby if (zapobj == 0) { 3451842727c2SChris Kirby /* The tag can't possibly exist */ 3452842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3453842727c2SChris Kirby return (ESRCH); 3454842727c2SChris Kirby } 3455842727c2SChris Kirby 3456842727c2SChris Kirby /* Make sure the tag exists */ 3457842727c2SChris Kirby error = zap_lookup(mos, zapobj, htag, 8, 1, &tmp); 3458842727c2SChris Kirby if (error) { 3459842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3460842727c2SChris Kirby if (error == ENOENT) 3461842727c2SChris Kirby error = ESRCH; 3462842727c2SChris Kirby return (error); 3463842727c2SChris Kirby } 3464842727c2SChris Kirby 3465842727c2SChris Kirby if (ds->ds_userrefs == 1 && ds->ds_phys->ds_num_children == 1 && 3466842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) 3467842727c2SChris Kirby *might_destroy = B_TRUE; 3468842727c2SChris Kirby 3469842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3470842727c2SChris Kirby return (0); 3471842727c2SChris Kirby } 3472842727c2SChris Kirby 3473842727c2SChris Kirby static int 3474842727c2SChris Kirby dsl_dataset_user_release_check(void *arg1, void *tag, dmu_tx_t *tx) 3475842727c2SChris Kirby { 3476842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3477842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3478842727c2SChris Kirby boolean_t might_destroy; 3479842727c2SChris Kirby int error; 3480842727c2SChris Kirby 3481842727c2SChris Kirby if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS) 3482842727c2SChris Kirby return (ENOTSUP); 3483842727c2SChris Kirby 3484842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ra->htag, &might_destroy); 3485842727c2SChris Kirby if (error) 3486842727c2SChris Kirby return (error); 3487842727c2SChris Kirby 3488842727c2SChris Kirby if (might_destroy) { 3489842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3490842727c2SChris Kirby 3491842727c2SChris Kirby if (dmu_tx_is_syncing(tx)) { 3492842727c2SChris Kirby /* 3493842727c2SChris Kirby * If we're not prepared to remove the snapshot, 3494842727c2SChris Kirby * we can't allow the release to happen right now. 3495842727c2SChris Kirby */ 3496842727c2SChris Kirby if (!ra->own) 3497842727c2SChris Kirby return (EBUSY); 3498503ad85cSMatthew Ahrens if (ds->ds_objset) { 3499503ad85cSMatthew Ahrens dmu_objset_evict(ds->ds_objset); 3500503ad85cSMatthew Ahrens ds->ds_objset = NULL; 3501842727c2SChris Kirby } 3502842727c2SChris Kirby } 3503842727c2SChris Kirby dsda.ds = ds; 3504842727c2SChris Kirby dsda.releasing = B_TRUE; 3505842727c2SChris Kirby return (dsl_dataset_destroy_check(&dsda, tag, tx)); 3506842727c2SChris Kirby } 3507842727c2SChris Kirby 3508842727c2SChris Kirby return (0); 3509842727c2SChris Kirby } 3510842727c2SChris Kirby 3511842727c2SChris Kirby static void 3512842727c2SChris Kirby dsl_dataset_user_release_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 3513842727c2SChris Kirby { 3514842727c2SChris Kirby struct dsl_ds_releasearg *ra = arg1; 3515842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3516ca45db41SChris Kirby dsl_pool_t *dp = ds->ds_dir->dd_pool; 3517ca45db41SChris Kirby objset_t *mos = dp->dp_meta_objset; 3518842727c2SChris Kirby uint64_t zapobj; 3519842727c2SChris Kirby uint64_t dsobj = ds->ds_object; 3520842727c2SChris Kirby uint64_t refs; 3521ca45db41SChris Kirby int error; 3522842727c2SChris Kirby 3523842727c2SChris Kirby mutex_enter(&ds->ds_lock); 3524842727c2SChris Kirby ds->ds_userrefs--; 3525842727c2SChris Kirby refs = ds->ds_userrefs; 3526842727c2SChris Kirby mutex_exit(&ds->ds_lock); 3527ca45db41SChris Kirby error = dsl_pool_user_release(dp, ds->ds_object, ra->htag, tx); 3528ca45db41SChris Kirby VERIFY(error == 0 || error == ENOENT); 3529842727c2SChris Kirby zapobj = ds->ds_phys->ds_userrefs_obj; 3530842727c2SChris Kirby VERIFY(0 == zap_remove(mos, zapobj, ra->htag, tx)); 3531842727c2SChris Kirby if (ds->ds_userrefs == 0 && ds->ds_phys->ds_num_children == 1 && 3532842727c2SChris Kirby DS_IS_DEFER_DESTROY(ds)) { 3533842727c2SChris Kirby struct dsl_ds_destroyarg dsda = {0}; 3534842727c2SChris Kirby 3535842727c2SChris Kirby ASSERT(ra->own); 3536842727c2SChris Kirby dsda.ds = ds; 3537842727c2SChris Kirby dsda.releasing = B_TRUE; 3538842727c2SChris Kirby /* We already did the destroy_check */ 3539842727c2SChris Kirby dsl_dataset_destroy_sync(&dsda, tag, cr, tx); 3540842727c2SChris Kirby } 3541842727c2SChris Kirby 3542842727c2SChris Kirby spa_history_internal_log(LOG_DS_USER_RELEASE, 3543ca45db41SChris Kirby dp->dp_spa, tx, cr, "<%s> %lld dataset = %llu", 3544842727c2SChris Kirby ra->htag, (longlong_t)refs, dsobj); 3545842727c2SChris Kirby } 3546842727c2SChris Kirby 3547842727c2SChris Kirby static int 3548842727c2SChris Kirby dsl_dataset_user_release_one(char *dsname, void *arg) 3549842727c2SChris Kirby { 3550842727c2SChris Kirby struct dsl_ds_holdarg *ha = arg; 3551842727c2SChris Kirby struct dsl_ds_releasearg *ra; 3552842727c2SChris Kirby dsl_dataset_t *ds; 3553842727c2SChris Kirby int error; 3554842727c2SChris Kirby void *dtag = ha->dstg; 3555842727c2SChris Kirby char *name; 3556842727c2SChris Kirby boolean_t own = B_FALSE; 3557842727c2SChris Kirby boolean_t might_destroy; 3558842727c2SChris Kirby 3559842727c2SChris Kirby /* alloc a buffer to hold dsname@snapname, plus the terminating NULL */ 3560ae46e4c7SMatthew Ahrens name = kmem_asprintf("%s@%s", dsname, ha->snapname); 3561842727c2SChris Kirby error = dsl_dataset_hold(name, dtag, &ds); 3562ae46e4c7SMatthew Ahrens strfree(name); 3563842727c2SChris Kirby if (error == ENOENT && ha->recursive) 3564842727c2SChris Kirby return (0); 3565842727c2SChris Kirby (void) strcpy(ha->failed, dsname); 3566842727c2SChris Kirby if (error) 3567842727c2SChris Kirby return (error); 3568842727c2SChris Kirby 3569d7747cbcSChris Kirby ha->gotone = B_TRUE; 3570d7747cbcSChris Kirby 3571842727c2SChris Kirby ASSERT(dsl_dataset_is_snapshot(ds)); 3572842727c2SChris Kirby 3573842727c2SChris Kirby error = dsl_dataset_release_might_destroy(ds, ha->htag, &might_destroy); 3574842727c2SChris Kirby if (error) { 3575842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3576842727c2SChris Kirby return (error); 3577842727c2SChris Kirby } 3578842727c2SChris Kirby 3579842727c2SChris Kirby if (might_destroy) { 3580842727c2SChris Kirby #ifdef _KERNEL 3581842727c2SChris Kirby error = zfs_unmount_snap(name, NULL); 3582842727c2SChris Kirby if (error) { 3583842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3584842727c2SChris Kirby return (error); 3585842727c2SChris Kirby } 3586842727c2SChris Kirby #endif 3587503ad85cSMatthew Ahrens if (!dsl_dataset_tryown(ds, B_TRUE, dtag)) { 3588842727c2SChris Kirby dsl_dataset_rele(ds, dtag); 3589842727c2SChris Kirby return (EBUSY); 3590842727c2SChris Kirby } else { 3591842727c2SChris Kirby own = B_TRUE; 3592842727c2SChris Kirby dsl_dataset_make_exclusive(ds, dtag); 3593842727c2SChris Kirby } 3594842727c2SChris Kirby } 3595842727c2SChris Kirby 3596842727c2SChris Kirby ra = kmem_alloc(sizeof (struct dsl_ds_releasearg), KM_SLEEP); 3597842727c2SChris Kirby ra->ds = ds; 3598842727c2SChris Kirby ra->htag = ha->htag; 3599842727c2SChris Kirby ra->own = own; 3600842727c2SChris Kirby dsl_sync_task_create(ha->dstg, dsl_dataset_user_release_check, 3601842727c2SChris Kirby dsl_dataset_user_release_sync, ra, dtag, 0); 3602842727c2SChris Kirby 3603842727c2SChris Kirby return (0); 3604842727c2SChris Kirby } 3605842727c2SChris Kirby 3606842727c2SChris Kirby int 3607842727c2SChris Kirby dsl_dataset_user_release(char *dsname, char *snapname, char *htag, 3608842727c2SChris Kirby boolean_t recursive) 3609842727c2SChris Kirby { 3610842727c2SChris Kirby struct dsl_ds_holdarg *ha; 3611842727c2SChris Kirby dsl_sync_task_t *dst; 3612842727c2SChris Kirby spa_t *spa; 3613842727c2SChris Kirby int error; 3614842727c2SChris Kirby 3615842727c2SChris Kirby ha = kmem_zalloc(sizeof (struct dsl_ds_holdarg), KM_SLEEP); 3616842727c2SChris Kirby 3617842727c2SChris Kirby (void) strlcpy(ha->failed, dsname, sizeof (ha->failed)); 3618842727c2SChris Kirby 3619842727c2SChris Kirby error = spa_open(dsname, &spa, FTAG); 3620842727c2SChris Kirby if (error) { 3621842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3622842727c2SChris Kirby return (error); 3623842727c2SChris Kirby } 3624842727c2SChris Kirby 3625842727c2SChris Kirby ha->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 3626842727c2SChris Kirby ha->htag = htag; 3627842727c2SChris Kirby ha->snapname = snapname; 3628842727c2SChris Kirby ha->recursive = recursive; 3629842727c2SChris Kirby if (recursive) { 3630842727c2SChris Kirby error = dmu_objset_find(dsname, dsl_dataset_user_release_one, 3631842727c2SChris Kirby ha, DS_FIND_CHILDREN); 3632842727c2SChris Kirby } else { 3633842727c2SChris Kirby error = dsl_dataset_user_release_one(dsname, ha); 3634842727c2SChris Kirby } 3635842727c2SChris Kirby if (error == 0) 3636842727c2SChris Kirby error = dsl_sync_task_group_wait(ha->dstg); 3637842727c2SChris Kirby 3638842727c2SChris Kirby for (dst = list_head(&ha->dstg->dstg_tasks); dst; 3639842727c2SChris Kirby dst = list_next(&ha->dstg->dstg_tasks, dst)) { 3640842727c2SChris Kirby struct dsl_ds_releasearg *ra = dst->dst_arg1; 3641842727c2SChris Kirby dsl_dataset_t *ds = ra->ds; 3642842727c2SChris Kirby 3643842727c2SChris Kirby if (dst->dst_err) 3644842727c2SChris Kirby dsl_dataset_name(ds, ha->failed); 3645842727c2SChris Kirby 3646842727c2SChris Kirby if (ra->own) 3647842727c2SChris Kirby dsl_dataset_disown(ds, ha->dstg); 3648842727c2SChris Kirby else 3649842727c2SChris Kirby dsl_dataset_rele(ds, ha->dstg); 3650842727c2SChris Kirby 3651842727c2SChris Kirby kmem_free(ra, sizeof (struct dsl_ds_releasearg)); 3652842727c2SChris Kirby } 3653842727c2SChris Kirby 3654d7747cbcSChris Kirby if (error == 0 && recursive && !ha->gotone) 3655d7747cbcSChris Kirby error = ENOENT; 3656d7747cbcSChris Kirby 3657842727c2SChris Kirby if (error) 3658842727c2SChris Kirby (void) strcpy(dsname, ha->failed); 3659842727c2SChris Kirby 3660842727c2SChris Kirby dsl_sync_task_group_destroy(ha->dstg); 3661842727c2SChris Kirby kmem_free(ha, sizeof (struct dsl_ds_holdarg)); 3662842727c2SChris Kirby spa_close(spa, FTAG); 3663842727c2SChris Kirby return (error); 3664842727c2SChris Kirby } 3665842727c2SChris Kirby 3666ca45db41SChris Kirby /* 3667ca45db41SChris Kirby * Called at spa_load time to release a stale temporary user hold. 3668ca45db41SChris Kirby */ 3669ca45db41SChris Kirby int 3670ca45db41SChris Kirby dsl_dataset_user_release_tmp(dsl_pool_t *dp, uint64_t dsobj, char *htag) 3671ca45db41SChris Kirby { 3672ca45db41SChris Kirby dsl_dataset_t *ds; 3673ca45db41SChris Kirby char *snap; 3674ca45db41SChris Kirby char *name; 3675ca45db41SChris Kirby int namelen; 3676ca45db41SChris Kirby int error; 3677ca45db41SChris Kirby 3678ca45db41SChris Kirby rw_enter(&dp->dp_config_rwlock, RW_READER); 3679ca45db41SChris Kirby error = dsl_dataset_hold_obj(dp, dsobj, FTAG, &ds); 3680ca45db41SChris Kirby rw_exit(&dp->dp_config_rwlock); 3681ca45db41SChris Kirby if (error) 3682ca45db41SChris Kirby return (error); 3683ca45db41SChris Kirby namelen = dsl_dataset_namelen(ds)+1; 3684ca45db41SChris Kirby name = kmem_alloc(namelen, KM_SLEEP); 3685ca45db41SChris Kirby dsl_dataset_name(ds, name); 3686ca45db41SChris Kirby dsl_dataset_rele(ds, FTAG); 3687ca45db41SChris Kirby 3688ca45db41SChris Kirby snap = strchr(name, '@'); 3689ca45db41SChris Kirby *snap = '\0'; 3690ca45db41SChris Kirby ++snap; 3691ca45db41SChris Kirby return (dsl_dataset_user_release(name, snap, htag, B_FALSE)); 3692ca45db41SChris Kirby } 3693ca45db41SChris Kirby 3694842727c2SChris Kirby int 3695842727c2SChris Kirby dsl_dataset_get_holds(const char *dsname, nvlist_t **nvp) 3696842727c2SChris Kirby { 3697842727c2SChris Kirby dsl_dataset_t *ds; 3698842727c2SChris Kirby int err; 3699842727c2SChris Kirby 3700842727c2SChris Kirby err = dsl_dataset_hold(dsname, FTAG, &ds); 3701842727c2SChris Kirby if (err) 3702842727c2SChris Kirby return (err); 3703842727c2SChris Kirby 3704842727c2SChris Kirby VERIFY(0 == nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP)); 3705842727c2SChris Kirby if (ds->ds_phys->ds_userrefs_obj != 0) { 3706842727c2SChris Kirby zap_attribute_t *za; 3707842727c2SChris Kirby zap_cursor_t zc; 3708842727c2SChris Kirby 3709842727c2SChris Kirby za = kmem_alloc(sizeof (zap_attribute_t), KM_SLEEP); 3710842727c2SChris Kirby for (zap_cursor_init(&zc, ds->ds_dir->dd_pool->dp_meta_objset, 3711842727c2SChris Kirby ds->ds_phys->ds_userrefs_obj); 3712842727c2SChris Kirby zap_cursor_retrieve(&zc, za) == 0; 3713842727c2SChris Kirby zap_cursor_advance(&zc)) { 3714842727c2SChris Kirby VERIFY(0 == nvlist_add_uint64(*nvp, za->za_name, 3715842727c2SChris Kirby za->za_first_integer)); 3716842727c2SChris Kirby } 3717842727c2SChris Kirby zap_cursor_fini(&zc); 3718842727c2SChris Kirby kmem_free(za, sizeof (zap_attribute_t)); 3719842727c2SChris Kirby } 3720842727c2SChris Kirby dsl_dataset_rele(ds, FTAG); 3721842727c2SChris Kirby return (0); 3722842727c2SChris Kirby } 3723503ad85cSMatthew Ahrens 3724503ad85cSMatthew Ahrens /* 3725503ad85cSMatthew Ahrens * Note, this fuction is used as the callback for dmu_objset_find(). We 3726503ad85cSMatthew Ahrens * always return 0 so that we will continue to find and process 3727503ad85cSMatthew Ahrens * inconsistent datasets, even if we encounter an error trying to 3728503ad85cSMatthew Ahrens * process one of them. 3729503ad85cSMatthew Ahrens */ 3730503ad85cSMatthew Ahrens /* ARGSUSED */ 3731503ad85cSMatthew Ahrens int 3732503ad85cSMatthew Ahrens dsl_destroy_inconsistent(char *dsname, void *arg) 3733503ad85cSMatthew Ahrens { 3734503ad85cSMatthew Ahrens dsl_dataset_t *ds; 3735503ad85cSMatthew Ahrens 3736503ad85cSMatthew Ahrens if (dsl_dataset_own(dsname, B_TRUE, FTAG, &ds) == 0) { 3737503ad85cSMatthew Ahrens if (DS_IS_INCONSISTENT(ds)) 3738503ad85cSMatthew Ahrens (void) dsl_dataset_destroy(ds, FTAG, B_FALSE); 3739503ad85cSMatthew Ahrens else 3740503ad85cSMatthew Ahrens dsl_dataset_disown(ds, FTAG); 3741503ad85cSMatthew Ahrens } 3742503ad85cSMatthew Ahrens return (0); 3743503ad85cSMatthew Ahrens } 3744