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 /* 229082849eSck * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 23fa9e4066Sahrens * Use is subject to license terms. 24fa9e4066Sahrens */ 25fa9e4066Sahrens 26fa9e4066Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27fa9e4066Sahrens 28fa9e4066Sahrens #include <sys/dmu_objset.h> 29fa9e4066Sahrens #include <sys/dsl_dataset.h> 30fa9e4066Sahrens #include <sys/dsl_dir.h> 3199653d4eSeschrock #include <sys/dsl_prop.h> 321d452cf5Sahrens #include <sys/dsl_synctask.h> 33fa9e4066Sahrens #include <sys/dmu_traverse.h> 34fa9e4066Sahrens #include <sys/dmu_tx.h> 35fa9e4066Sahrens #include <sys/arc.h> 36fa9e4066Sahrens #include <sys/zio.h> 37fa9e4066Sahrens #include <sys/zap.h> 38fa9e4066Sahrens #include <sys/unique.h> 39fa9e4066Sahrens #include <sys/zfs_context.h> 40cdf5b4caSmmusante #include <sys/zfs_ioctl.h> 41ecd6cf80Smarks #include <sys/spa.h> 42*088f3894Sahrens #include <sys/zfs_znode.h> 43ecd6cf80Smarks #include <sys/sunddi.h> 44fa9e4066Sahrens 45745cd3c5Smaybee static char *dsl_reaper = "the grim reaper"; 46745cd3c5Smaybee 471d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 481d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 491d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_rollback_check; 501d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_rollback_sync; 51a9799022Sck static dsl_syncfunc_t dsl_dataset_set_reservation_sync; 52e1930233Sbonwick 5355434c77Sek #define DS_REF_MAX (1ULL << 62) 54fa9e4066Sahrens 55fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 56fa9e4066Sahrens 57745cd3c5Smaybee #define DSL_DATASET_IS_DESTROYED(ds) ((ds)->ds_owner == dsl_reaper) 58745cd3c5Smaybee 59fa9e4066Sahrens 60a9799022Sck /* 61a9799022Sck * Figure out how much of this delta should be propogated to the dsl_dir 62a9799022Sck * layer. If there's a refreservation, that space has already been 63a9799022Sck * partially accounted for in our ancestors. 64a9799022Sck */ 65a9799022Sck static int64_t 66a9799022Sck parent_delta(dsl_dataset_t *ds, int64_t delta) 67a9799022Sck { 68a9799022Sck uint64_t old_bytes, new_bytes; 69a9799022Sck 70a9799022Sck if (ds->ds_reserved == 0) 71a9799022Sck return (delta); 72a9799022Sck 73a9799022Sck old_bytes = MAX(ds->ds_phys->ds_unique_bytes, ds->ds_reserved); 74a9799022Sck new_bytes = MAX(ds->ds_phys->ds_unique_bytes + delta, ds->ds_reserved); 75a9799022Sck 76a9799022Sck ASSERT3U(ABS((int64_t)(new_bytes - old_bytes)), <=, ABS(delta)); 77a9799022Sck return (new_bytes - old_bytes); 78a9799022Sck } 79fa9e4066Sahrens 80fa9e4066Sahrens void 81fa9e4066Sahrens dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 82fa9e4066Sahrens { 8399653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 84fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 85fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 86a9799022Sck int64_t delta; 87fa9e4066Sahrens 88fa9e4066Sahrens dprintf_bp(bp, "born, ds=%p\n", ds); 89fa9e4066Sahrens 90fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 91fa9e4066Sahrens /* It could have been compressed away to nothing */ 92fa9e4066Sahrens if (BP_IS_HOLE(bp)) 93fa9e4066Sahrens return; 94fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 95fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 96fa9e4066Sahrens if (ds == NULL) { 97fa9e4066Sahrens /* 98fa9e4066Sahrens * Account for the meta-objset space in its placeholder 99fa9e4066Sahrens * dsl_dir. 100fa9e4066Sahrens */ 101fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 102fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 103fa9e4066Sahrens used, compressed, uncompressed, tx); 104fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 105fa9e4066Sahrens return; 106fa9e4066Sahrens } 107fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 108fa9e4066Sahrens mutex_enter(&ds->ds_lock); 109a9799022Sck delta = parent_delta(ds, used); 110fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 111fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 112fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 113fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 114fa9e4066Sahrens mutex_exit(&ds->ds_lock); 115a9799022Sck dsl_dir_diduse_space(ds->ds_dir, delta, compressed, uncompressed, tx); 116fa9e4066Sahrens } 117fa9e4066Sahrens 118cdb0ab79Smaybee int 119c717a561Smaybee dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, zio_t *pio, 120c717a561Smaybee dmu_tx_t *tx) 121fa9e4066Sahrens { 12299653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 123fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 124fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 125fa9e4066Sahrens 126fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 127c717a561Smaybee /* No block pointer => nothing to free */ 128fa9e4066Sahrens if (BP_IS_HOLE(bp)) 129cdb0ab79Smaybee return (0); 130fa9e4066Sahrens 131fa9e4066Sahrens ASSERT(used > 0); 132fa9e4066Sahrens if (ds == NULL) { 133c717a561Smaybee int err; 134fa9e4066Sahrens /* 135fa9e4066Sahrens * Account for the meta-objset space in its placeholder 136fa9e4066Sahrens * dataset. 137fa9e4066Sahrens */ 138*088f3894Sahrens err = dsl_free(pio, tx->tx_pool, 139c717a561Smaybee tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); 140c717a561Smaybee ASSERT(err == 0); 141fa9e4066Sahrens 142fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 143fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 144fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 145cdb0ab79Smaybee return (used); 146fa9e4066Sahrens } 147fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 148fa9e4066Sahrens 149fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 150fa9e4066Sahrens 151fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 152c717a561Smaybee int err; 153a9799022Sck int64_t delta; 154c717a561Smaybee 155fa9e4066Sahrens dprintf_bp(bp, "freeing: %s", ""); 156*088f3894Sahrens err = dsl_free(pio, tx->tx_pool, 157c717a561Smaybee tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); 158c717a561Smaybee ASSERT(err == 0); 159fa9e4066Sahrens 160fa9e4066Sahrens mutex_enter(&ds->ds_lock); 161a9799022Sck ASSERT(ds->ds_phys->ds_unique_bytes >= used || 162a9799022Sck !DS_UNIQUE_IS_ACCURATE(ds)); 163a9799022Sck delta = parent_delta(ds, -used); 164fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 165fa9e4066Sahrens mutex_exit(&ds->ds_lock); 166fa9e4066Sahrens dsl_dir_diduse_space(ds->ds_dir, 167a9799022Sck delta, -compressed, -uncompressed, tx); 168fa9e4066Sahrens } else { 169fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 170ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 171a4611edeSahrens ASSERT3U(ds->ds_prev->ds_object, ==, 172a4611edeSahrens ds->ds_phys->ds_prev_snap_obj); 173a4611edeSahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 174fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 175a4611edeSahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 176a4611edeSahrens ds->ds_object && bp->blk_birth > 177a4611edeSahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 178a4611edeSahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 179a4611edeSahrens mutex_enter(&ds->ds_prev->ds_lock); 180a4611edeSahrens ds->ds_prev->ds_phys->ds_unique_bytes += used; 181a4611edeSahrens mutex_exit(&ds->ds_prev->ds_lock); 182fa9e4066Sahrens } 183fa9e4066Sahrens } 184fa9e4066Sahrens mutex_enter(&ds->ds_lock); 185fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 186fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 187fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 188fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 189fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 190fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 191fa9e4066Sahrens mutex_exit(&ds->ds_lock); 192cdb0ab79Smaybee 193cdb0ab79Smaybee return (used); 194fa9e4066Sahrens } 195fa9e4066Sahrens 196ea8dc4b6Seschrock uint64_t 197ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 198fa9e4066Sahrens { 199a2eea2e1Sahrens uint64_t trysnap = 0; 200a2eea2e1Sahrens 201fa9e4066Sahrens if (ds == NULL) 202ea8dc4b6Seschrock return (0); 203fa9e4066Sahrens /* 204fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 205fa9e4066Sahrens * incorrect FALSE return, which would only result in an 206fa9e4066Sahrens * overestimation of the amount of space that an operation would 207fa9e4066Sahrens * consume, which is OK. 208fa9e4066Sahrens * 209fa9e4066Sahrens * There's also a small window where we could miss a pending 210fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 211fa9e4066Sahrens * phase. So this should only be used as a guess. 212fa9e4066Sahrens */ 213a2eea2e1Sahrens if (ds->ds_trysnap_txg > 214a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 215a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 216a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 217ea8dc4b6Seschrock } 218ea8dc4b6Seschrock 219ea8dc4b6Seschrock int 220ea8dc4b6Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 221ea8dc4b6Seschrock { 222ea8dc4b6Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 223fa9e4066Sahrens } 224fa9e4066Sahrens 225fa9e4066Sahrens /* ARGSUSED */ 226fa9e4066Sahrens static void 227fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 228fa9e4066Sahrens { 229fa9e4066Sahrens dsl_dataset_t *ds = dsv; 230fa9e4066Sahrens 231745cd3c5Smaybee ASSERT(ds->ds_owner == NULL || DSL_DATASET_IS_DESTROYED(ds)); 232fa9e4066Sahrens 233fa9e4066Sahrens dprintf_ds(ds, "evicting %s\n", ""); 234fa9e4066Sahrens 23591ebeef5Sahrens unique_remove(ds->ds_fsid_guid); 236fa9e4066Sahrens 237fa9e4066Sahrens if (ds->ds_user_ptr != NULL) 238fa9e4066Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 239fa9e4066Sahrens 240fa9e4066Sahrens if (ds->ds_prev) { 241745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 242fa9e4066Sahrens ds->ds_prev = NULL; 243fa9e4066Sahrens } 244fa9e4066Sahrens 245fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 246745cd3c5Smaybee if (ds->ds_dir) 247745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 248fa9e4066Sahrens 24991ebeef5Sahrens ASSERT(!list_link_active(&ds->ds_synced_link)); 250fa9e4066Sahrens 2515ad82045Snd mutex_destroy(&ds->ds_lock); 25291ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 2535ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 254745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 255745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 2565ad82045Snd 257fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 258fa9e4066Sahrens } 259fa9e4066Sahrens 260ea8dc4b6Seschrock static int 261fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 262fa9e4066Sahrens { 263fa9e4066Sahrens dsl_dataset_phys_t *headphys; 264fa9e4066Sahrens int err; 265fa9e4066Sahrens dmu_buf_t *headdbuf; 266fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 267fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 268fa9e4066Sahrens 269fa9e4066Sahrens if (ds->ds_snapname[0]) 270ea8dc4b6Seschrock return (0); 271fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 272ea8dc4b6Seschrock return (0); 273fa9e4066Sahrens 274ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 275ea8dc4b6Seschrock FTAG, &headdbuf); 276ea8dc4b6Seschrock if (err) 277ea8dc4b6Seschrock return (err); 278fa9e4066Sahrens headphys = headdbuf->db_data; 279fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 280e7437265Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); 281ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 282ea8dc4b6Seschrock return (err); 283fa9e4066Sahrens } 284fa9e4066Sahrens 285ab04eb8eStimh static int 286745cd3c5Smaybee dsl_dataset_snap_lookup(dsl_dataset_t *ds, const char *name, uint64_t *value) 287ab04eb8eStimh { 288745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 289745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 290ab04eb8eStimh matchtype_t mt; 291ab04eb8eStimh int err; 292ab04eb8eStimh 293745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 294ab04eb8eStimh mt = MT_FIRST; 295ab04eb8eStimh else 296ab04eb8eStimh mt = MT_EXACT; 297ab04eb8eStimh 298745cd3c5Smaybee err = zap_lookup_norm(mos, snapobj, name, 8, 1, 299ab04eb8eStimh value, mt, NULL, 0, NULL); 300ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 301745cd3c5Smaybee err = zap_lookup(mos, snapobj, name, 8, 1, value); 302ab04eb8eStimh return (err); 303ab04eb8eStimh } 304ab04eb8eStimh 305ab04eb8eStimh static int 306745cd3c5Smaybee dsl_dataset_snap_remove(dsl_dataset_t *ds, char *name, dmu_tx_t *tx) 307ab04eb8eStimh { 308745cd3c5Smaybee objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 309745cd3c5Smaybee uint64_t snapobj = ds->ds_phys->ds_snapnames_zapobj; 310ab04eb8eStimh matchtype_t mt; 311ab04eb8eStimh int err; 312ab04eb8eStimh 313745cd3c5Smaybee if (ds->ds_phys->ds_flags & DS_FLAG_CI_DATASET) 314ab04eb8eStimh mt = MT_FIRST; 315ab04eb8eStimh else 316ab04eb8eStimh mt = MT_EXACT; 317ab04eb8eStimh 318745cd3c5Smaybee err = zap_remove_norm(mos, snapobj, name, mt, tx); 319ab04eb8eStimh if (err == ENOTSUP && mt == MT_FIRST) 320745cd3c5Smaybee err = zap_remove(mos, snapobj, name, tx); 321ab04eb8eStimh return (err); 322ab04eb8eStimh } 323ab04eb8eStimh 324745cd3c5Smaybee static int 325745cd3c5Smaybee dsl_dataset_get_ref(dsl_pool_t *dp, uint64_t dsobj, void *tag, 326745cd3c5Smaybee dsl_dataset_t **dsp) 327fa9e4066Sahrens { 328fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 329fa9e4066Sahrens dmu_buf_t *dbuf; 330fa9e4066Sahrens dsl_dataset_t *ds; 331ea8dc4b6Seschrock int err; 332fa9e4066Sahrens 333fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 334fa9e4066Sahrens dsl_pool_sync_context(dp)); 335fa9e4066Sahrens 336ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 337ea8dc4b6Seschrock if (err) 338ea8dc4b6Seschrock return (err); 339fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 340fa9e4066Sahrens if (ds == NULL) { 341fa9e4066Sahrens dsl_dataset_t *winner; 342fa9e4066Sahrens 343fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 344fa9e4066Sahrens ds->ds_dbuf = dbuf; 345fa9e4066Sahrens ds->ds_object = dsobj; 346fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 347fa9e4066Sahrens 3485ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 34991ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 3505ad82045Snd mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT, 3515ad82045Snd NULL); 352745cd3c5Smaybee rw_init(&ds->ds_rwlock, 0, 0, 0); 353745cd3c5Smaybee cv_init(&ds->ds_exclusive_cv, NULL, CV_DEFAULT, NULL); 3545ad82045Snd 355ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 356fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 357ea8dc4b6Seschrock if (err == 0) { 358ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 359ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 360ea8dc4b6Seschrock } 361ea8dc4b6Seschrock if (err) { 362ea8dc4b6Seschrock /* 363ea8dc4b6Seschrock * we don't really need to close the blist if we 364ea8dc4b6Seschrock * just opened it. 365ea8dc4b6Seschrock */ 3665ad82045Snd mutex_destroy(&ds->ds_lock); 36791ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 3685ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 369745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 370745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 371ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 372ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 373ea8dc4b6Seschrock return (err); 374ea8dc4b6Seschrock } 375fa9e4066Sahrens 376fa9e4066Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == dsobj) { 377fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 378fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 379745cd3c5Smaybee err = dsl_dataset_get_ref(dp, 380745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 381745cd3c5Smaybee ds, &ds->ds_prev); 382fa9e4066Sahrens } 383745cd3c5Smaybee } else if (zfs_flags & ZFS_DEBUG_SNAPNAMES) { 384745cd3c5Smaybee err = dsl_dataset_get_snapname(ds); 385fa9e4066Sahrens } 386fa9e4066Sahrens 387cb625fb5Sck if (!dsl_dataset_is_snapshot(ds)) { 38827345066Sck /* 38927345066Sck * In sync context, we're called with either no lock 39027345066Sck * or with the write lock. If we're not syncing, 39127345066Sck * we're always called with the read lock held. 39227345066Sck */ 393cb625fb5Sck boolean_t need_lock = 39427345066Sck !RW_WRITE_HELD(&dp->dp_config_rwlock) && 39527345066Sck dsl_pool_sync_context(dp); 396cb625fb5Sck 397cb625fb5Sck if (need_lock) 398cb625fb5Sck rw_enter(&dp->dp_config_rwlock, RW_READER); 399cb625fb5Sck 400cb625fb5Sck err = dsl_prop_get_ds_locked(ds->ds_dir, 401cb625fb5Sck "refreservation", sizeof (uint64_t), 1, 402cb625fb5Sck &ds->ds_reserved, NULL); 403cb625fb5Sck if (err == 0) { 404cb625fb5Sck err = dsl_prop_get_ds_locked(ds->ds_dir, 405cb625fb5Sck "refquota", sizeof (uint64_t), 1, 406cb625fb5Sck &ds->ds_quota, NULL); 407cb625fb5Sck } 408cb625fb5Sck 409cb625fb5Sck if (need_lock) 410cb625fb5Sck rw_exit(&dp->dp_config_rwlock); 411cb625fb5Sck } else { 412cb625fb5Sck ds->ds_reserved = ds->ds_quota = 0; 413cb625fb5Sck } 414cb625fb5Sck 415ea8dc4b6Seschrock if (err == 0) { 416ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 417ea8dc4b6Seschrock dsl_dataset_evict); 418ea8dc4b6Seschrock } 419ea8dc4b6Seschrock if (err || winner) { 420fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 421745cd3c5Smaybee if (ds->ds_prev) 422745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 423fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 4245ad82045Snd mutex_destroy(&ds->ds_lock); 42591ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 4265ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 427745cd3c5Smaybee rw_destroy(&ds->ds_rwlock); 428745cd3c5Smaybee cv_destroy(&ds->ds_exclusive_cv); 429fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 430ea8dc4b6Seschrock if (err) { 431ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 432ea8dc4b6Seschrock return (err); 433ea8dc4b6Seschrock } 434fa9e4066Sahrens ds = winner; 435fa9e4066Sahrens } else { 43691ebeef5Sahrens ds->ds_fsid_guid = 437fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 438fa9e4066Sahrens } 439fa9e4066Sahrens } 440fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 441fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 442*088f3894Sahrens ASSERT(ds->ds_phys->ds_prev_snap_obj != 0 || 443*088f3894Sahrens dp->dp_origin_snap == NULL || ds == dp->dp_origin_snap); 444fa9e4066Sahrens mutex_enter(&ds->ds_lock); 445745cd3c5Smaybee if (!dsl_pool_sync_context(dp) && DSL_DATASET_IS_DESTROYED(ds)) { 446fa9e4066Sahrens mutex_exit(&ds->ds_lock); 447745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 448745cd3c5Smaybee return (ENOENT); 449fa9e4066Sahrens } 450fa9e4066Sahrens mutex_exit(&ds->ds_lock); 451ea8dc4b6Seschrock *dsp = ds; 452ea8dc4b6Seschrock return (0); 453fa9e4066Sahrens } 454fa9e4066Sahrens 455745cd3c5Smaybee static int 456745cd3c5Smaybee dsl_dataset_hold_ref(dsl_dataset_t *ds, void *tag) 457745cd3c5Smaybee { 458745cd3c5Smaybee dsl_pool_t *dp = ds->ds_dir->dd_pool; 459745cd3c5Smaybee 460745cd3c5Smaybee /* 461745cd3c5Smaybee * In syncing context we don't want the rwlock lock: there 462745cd3c5Smaybee * may be an existing writer waiting for sync phase to 463745cd3c5Smaybee * finish. We don't need to worry about such writers, since 464745cd3c5Smaybee * sync phase is single-threaded, so the writer can't be 465745cd3c5Smaybee * doing anything while we are active. 466745cd3c5Smaybee */ 467745cd3c5Smaybee if (dsl_pool_sync_context(dp)) { 468745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 469745cd3c5Smaybee return (0); 470745cd3c5Smaybee } 471745cd3c5Smaybee 472745cd3c5Smaybee /* 473745cd3c5Smaybee * Normal users will hold the ds_rwlock as a READER until they 474745cd3c5Smaybee * are finished (i.e., call dsl_dataset_rele()). "Owners" will 475745cd3c5Smaybee * drop their READER lock after they set the ds_owner field. 476745cd3c5Smaybee * 477745cd3c5Smaybee * If the dataset is being destroyed, the destroy thread will 478745cd3c5Smaybee * obtain a WRITER lock for exclusive access after it's done its 479745cd3c5Smaybee * open-context work and then change the ds_owner to 480745cd3c5Smaybee * dsl_reaper once destruction is assured. So threads 481745cd3c5Smaybee * may block here temporarily, until the "destructability" of 482745cd3c5Smaybee * the dataset is determined. 483745cd3c5Smaybee */ 484745cd3c5Smaybee ASSERT(!RW_WRITE_HELD(&dp->dp_config_rwlock)); 485745cd3c5Smaybee mutex_enter(&ds->ds_lock); 486745cd3c5Smaybee while (!rw_tryenter(&ds->ds_rwlock, RW_READER)) { 487745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 488745cd3c5Smaybee cv_wait(&ds->ds_exclusive_cv, &ds->ds_lock); 489745cd3c5Smaybee if (DSL_DATASET_IS_DESTROYED(ds)) { 490745cd3c5Smaybee mutex_exit(&ds->ds_lock); 491745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 492745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 493745cd3c5Smaybee return (ENOENT); 494745cd3c5Smaybee } 495745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 496745cd3c5Smaybee } 497745cd3c5Smaybee mutex_exit(&ds->ds_lock); 498745cd3c5Smaybee return (0); 499745cd3c5Smaybee } 500745cd3c5Smaybee 501745cd3c5Smaybee int 502745cd3c5Smaybee dsl_dataset_hold_obj(dsl_pool_t *dp, uint64_t dsobj, void *tag, 503745cd3c5Smaybee dsl_dataset_t **dsp) 504745cd3c5Smaybee { 505745cd3c5Smaybee int err = dsl_dataset_get_ref(dp, dsobj, tag, dsp); 506745cd3c5Smaybee 507745cd3c5Smaybee if (err) 508745cd3c5Smaybee return (err); 509745cd3c5Smaybee return (dsl_dataset_hold_ref(*dsp, tag)); 510745cd3c5Smaybee } 511745cd3c5Smaybee 512745cd3c5Smaybee int 513745cd3c5Smaybee dsl_dataset_own_obj(dsl_pool_t *dp, uint64_t dsobj, int flags, void *owner, 514745cd3c5Smaybee dsl_dataset_t **dsp) 515745cd3c5Smaybee { 516745cd3c5Smaybee int err = dsl_dataset_hold_obj(dp, dsobj, owner, dsp); 517745cd3c5Smaybee 518745cd3c5Smaybee ASSERT(DS_MODE_TYPE(flags) != DS_MODE_USER); 519745cd3c5Smaybee 520745cd3c5Smaybee if (err) 521745cd3c5Smaybee return (err); 522745cd3c5Smaybee if (!dsl_dataset_tryown(*dsp, DS_MODE_IS_INCONSISTENT(flags), owner)) { 523745cd3c5Smaybee dsl_dataset_rele(*dsp, owner); 524745cd3c5Smaybee return (EBUSY); 525745cd3c5Smaybee } 526745cd3c5Smaybee return (0); 527745cd3c5Smaybee } 528745cd3c5Smaybee 529fa9e4066Sahrens int 530745cd3c5Smaybee dsl_dataset_hold(const char *name, void *tag, dsl_dataset_t **dsp) 531fa9e4066Sahrens { 532fa9e4066Sahrens dsl_dir_t *dd; 533fa9e4066Sahrens dsl_pool_t *dp; 534745cd3c5Smaybee const char *snapname; 535fa9e4066Sahrens uint64_t obj; 536fa9e4066Sahrens int err = 0; 537fa9e4066Sahrens 538745cd3c5Smaybee err = dsl_dir_open_spa(NULL, name, FTAG, &dd, &snapname); 539ea8dc4b6Seschrock if (err) 540ea8dc4b6Seschrock return (err); 541fa9e4066Sahrens 542fa9e4066Sahrens dp = dd->dd_pool; 543fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 544fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 545745cd3c5Smaybee if (obj) 546745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, dsp); 547745cd3c5Smaybee else 548fa9e4066Sahrens err = ENOENT; 549745cd3c5Smaybee if (err) 550fa9e4066Sahrens goto out; 551fa9e4066Sahrens 552745cd3c5Smaybee err = dsl_dataset_hold_ref(*dsp, tag); 553fa9e4066Sahrens 554745cd3c5Smaybee /* we may be looking for a snapshot */ 555745cd3c5Smaybee if (err == 0 && snapname != NULL) { 556745cd3c5Smaybee dsl_dataset_t *ds = NULL; 557fa9e4066Sahrens 558745cd3c5Smaybee if (*snapname++ != '@') { 559745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 560fa9e4066Sahrens err = ENOENT; 561fa9e4066Sahrens goto out; 562fa9e4066Sahrens } 563fa9e4066Sahrens 564745cd3c5Smaybee dprintf("looking for snapshot '%s'\n", snapname); 565745cd3c5Smaybee err = dsl_dataset_snap_lookup(*dsp, snapname, &obj); 566745cd3c5Smaybee if (err == 0) 567745cd3c5Smaybee err = dsl_dataset_get_ref(dp, obj, tag, &ds); 568745cd3c5Smaybee dsl_dataset_rele(*dsp, tag); 569745cd3c5Smaybee 570745cd3c5Smaybee ASSERT3U((err == 0), ==, (ds != NULL)); 571745cd3c5Smaybee 572745cd3c5Smaybee if (ds) { 573745cd3c5Smaybee mutex_enter(&ds->ds_lock); 574745cd3c5Smaybee if (ds->ds_snapname[0] == 0) 575745cd3c5Smaybee (void) strlcpy(ds->ds_snapname, snapname, 576745cd3c5Smaybee sizeof (ds->ds_snapname)); 577745cd3c5Smaybee mutex_exit(&ds->ds_lock); 578745cd3c5Smaybee err = dsl_dataset_hold_ref(ds, tag); 579745cd3c5Smaybee *dsp = err ? NULL : ds; 580fa9e4066Sahrens } 581fa9e4066Sahrens } 582fa9e4066Sahrens out: 583fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 584fa9e4066Sahrens dsl_dir_close(dd, FTAG); 585fa9e4066Sahrens return (err); 586fa9e4066Sahrens } 587fa9e4066Sahrens 588fa9e4066Sahrens int 589745cd3c5Smaybee dsl_dataset_own(const char *name, int flags, void *owner, dsl_dataset_t **dsp) 590fa9e4066Sahrens { 591745cd3c5Smaybee int err = dsl_dataset_hold(name, owner, dsp); 592745cd3c5Smaybee if (err) 593745cd3c5Smaybee return (err); 594745cd3c5Smaybee if ((*dsp)->ds_phys->ds_num_children > 0 && 595745cd3c5Smaybee !DS_MODE_IS_READONLY(flags)) { 596745cd3c5Smaybee dsl_dataset_rele(*dsp, owner); 597745cd3c5Smaybee return (EROFS); 598745cd3c5Smaybee } 599745cd3c5Smaybee if (!dsl_dataset_tryown(*dsp, DS_MODE_IS_INCONSISTENT(flags), owner)) { 600745cd3c5Smaybee dsl_dataset_rele(*dsp, owner); 601745cd3c5Smaybee return (EBUSY); 602745cd3c5Smaybee } 603745cd3c5Smaybee return (0); 604fa9e4066Sahrens } 605fa9e4066Sahrens 606fa9e4066Sahrens void 607fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 608fa9e4066Sahrens { 609fa9e4066Sahrens if (ds == NULL) { 610fa9e4066Sahrens (void) strcpy(name, "mos"); 611fa9e4066Sahrens } else { 612fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 613ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 614fa9e4066Sahrens if (ds->ds_snapname[0]) { 615fa9e4066Sahrens (void) strcat(name, "@"); 616745cd3c5Smaybee /* 617745cd3c5Smaybee * We use a "recursive" mutex so that we 618745cd3c5Smaybee * can call dprintf_ds() with ds_lock held. 619745cd3c5Smaybee */ 620fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 621fa9e4066Sahrens mutex_enter(&ds->ds_lock); 622fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 623fa9e4066Sahrens mutex_exit(&ds->ds_lock); 624fa9e4066Sahrens } else { 625fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 626fa9e4066Sahrens } 627fa9e4066Sahrens } 628fa9e4066Sahrens } 629fa9e4066Sahrens } 630fa9e4066Sahrens 631b7661cccSmmusante static int 632b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 633b7661cccSmmusante { 634b7661cccSmmusante int result; 635b7661cccSmmusante 636b7661cccSmmusante if (ds == NULL) { 637b7661cccSmmusante result = 3; /* "mos" */ 638b7661cccSmmusante } else { 639b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 640b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 641b7661cccSmmusante if (ds->ds_snapname[0]) { 642b7661cccSmmusante ++result; /* adding one for the @-sign */ 643b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 644b7661cccSmmusante mutex_enter(&ds->ds_lock); 645b7661cccSmmusante result += strlen(ds->ds_snapname); 646b7661cccSmmusante mutex_exit(&ds->ds_lock); 647b7661cccSmmusante } else { 648b7661cccSmmusante result += strlen(ds->ds_snapname); 649b7661cccSmmusante } 650b7661cccSmmusante } 651b7661cccSmmusante } 652b7661cccSmmusante 653b7661cccSmmusante return (result); 654b7661cccSmmusante } 655b7661cccSmmusante 656*088f3894Sahrens void 657745cd3c5Smaybee dsl_dataset_drop_ref(dsl_dataset_t *ds, void *tag) 658fa9e4066Sahrens { 659ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 660fa9e4066Sahrens } 661fa9e4066Sahrens 6623cb34c60Sahrens void 663745cd3c5Smaybee dsl_dataset_rele(dsl_dataset_t *ds, void *tag) 6643cb34c60Sahrens { 665745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) { 666745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 667745cd3c5Smaybee } 668745cd3c5Smaybee dsl_dataset_drop_ref(ds, tag); 669745cd3c5Smaybee } 670745cd3c5Smaybee 671745cd3c5Smaybee void 672745cd3c5Smaybee dsl_dataset_disown(dsl_dataset_t *ds, void *owner) 673745cd3c5Smaybee { 674745cd3c5Smaybee ASSERT((ds->ds_owner == owner && ds->ds_dbuf) || 675745cd3c5Smaybee (DSL_DATASET_IS_DESTROYED(ds) && ds->ds_dbuf == NULL)); 676745cd3c5Smaybee 6773cb34c60Sahrens mutex_enter(&ds->ds_lock); 678745cd3c5Smaybee ds->ds_owner = NULL; 679745cd3c5Smaybee if (RW_WRITE_HELD(&ds->ds_rwlock)) { 680745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 681745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 682745cd3c5Smaybee } 6833cb34c60Sahrens mutex_exit(&ds->ds_lock); 684745cd3c5Smaybee if (ds->ds_dbuf) 685745cd3c5Smaybee dsl_dataset_drop_ref(ds, owner); 686745cd3c5Smaybee else 687745cd3c5Smaybee dsl_dataset_evict(ds->ds_dbuf, ds); 6883cb34c60Sahrens } 6893cb34c60Sahrens 6903cb34c60Sahrens boolean_t 691745cd3c5Smaybee dsl_dataset_tryown(dsl_dataset_t *ds, boolean_t inconsistentok, void *owner) 6923cb34c60Sahrens { 693745cd3c5Smaybee boolean_t gotit = FALSE; 694745cd3c5Smaybee 6953cb34c60Sahrens mutex_enter(&ds->ds_lock); 696745cd3c5Smaybee if (ds->ds_owner == NULL && 697745cd3c5Smaybee (!DS_IS_INCONSISTENT(ds) || inconsistentok)) { 698745cd3c5Smaybee ds->ds_owner = owner; 699745cd3c5Smaybee if (!dsl_pool_sync_context(ds->ds_dir->dd_pool)) 700745cd3c5Smaybee rw_exit(&ds->ds_rwlock); 701745cd3c5Smaybee gotit = TRUE; 7023cb34c60Sahrens } 7033cb34c60Sahrens mutex_exit(&ds->ds_lock); 704745cd3c5Smaybee return (gotit); 705745cd3c5Smaybee } 706745cd3c5Smaybee 707745cd3c5Smaybee void 708745cd3c5Smaybee dsl_dataset_make_exclusive(dsl_dataset_t *ds, void *owner) 709745cd3c5Smaybee { 710745cd3c5Smaybee ASSERT3P(owner, ==, ds->ds_owner); 711745cd3c5Smaybee if (!RW_WRITE_HELD(&ds->ds_rwlock)) 712745cd3c5Smaybee rw_enter(&ds->ds_rwlock, RW_WRITER); 7133cb34c60Sahrens } 7143cb34c60Sahrens 7151d452cf5Sahrens uint64_t 716*088f3894Sahrens dsl_dataset_create_sync_dd(dsl_dir_t *dd, dsl_dataset_t *origin, 717ab04eb8eStimh uint64_t flags, dmu_tx_t *tx) 718fa9e4066Sahrens { 7193cb34c60Sahrens dsl_pool_t *dp = dd->dd_pool; 720fa9e4066Sahrens dmu_buf_t *dbuf; 721fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 7223cb34c60Sahrens uint64_t dsobj; 723fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 724fa9e4066Sahrens 725*088f3894Sahrens if (origin == NULL) 726*088f3894Sahrens origin = dp->dp_origin_snap; 727*088f3894Sahrens 7283cb34c60Sahrens ASSERT(origin == NULL || origin->ds_dir->dd_pool == dp); 7293cb34c60Sahrens ASSERT(origin == NULL || origin->ds_phys->ds_num_children > 0); 730fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 7313cb34c60Sahrens ASSERT(dd->dd_phys->dd_head_dataset_obj == 0); 732fa9e4066Sahrens 7331649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 7341649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 735ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 736fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 737fa9e4066Sahrens dsphys = dbuf->db_data; 738745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 739fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 740ab04eb8eStimh dsphys->ds_flags = flags; 741fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 742fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 743fa9e4066Sahrens sizeof (dsphys->ds_guid)); 744fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 745ab04eb8eStimh zap_create_norm(mos, U8_TEXTPREP_TOUPPER, DMU_OT_DSL_DS_SNAP_MAP, 746ab04eb8eStimh DMU_OT_NONE, 0, tx); 747fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 748*088f3894Sahrens dsphys->ds_creation_txg = tx->tx_txg == TXG_INITIAL ? 1 : tx->tx_txg; 749fa9e4066Sahrens dsphys->ds_deadlist_obj = 750fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 751a9799022Sck 7523cb34c60Sahrens if (origin) { 7533cb34c60Sahrens dsphys->ds_prev_snap_obj = origin->ds_object; 754fa9e4066Sahrens dsphys->ds_prev_snap_txg = 7553cb34c60Sahrens origin->ds_phys->ds_creation_txg; 756fa9e4066Sahrens dsphys->ds_used_bytes = 7573cb34c60Sahrens origin->ds_phys->ds_used_bytes; 758fa9e4066Sahrens dsphys->ds_compressed_bytes = 7593cb34c60Sahrens origin->ds_phys->ds_compressed_bytes; 760fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 7613cb34c60Sahrens origin->ds_phys->ds_uncompressed_bytes; 7623cb34c60Sahrens dsphys->ds_bp = origin->ds_phys->ds_bp; 763579ae4d5Stimh dsphys->ds_flags |= origin->ds_phys->ds_flags; 764fa9e4066Sahrens 7653cb34c60Sahrens dmu_buf_will_dirty(origin->ds_dbuf, tx); 7663cb34c60Sahrens origin->ds_phys->ds_num_children++; 767fa9e4066Sahrens 768*088f3894Sahrens if (spa_version(dp->dp_spa) >= SPA_VERSION_NEXT_CLONES) { 769*088f3894Sahrens if (origin->ds_phys->ds_next_clones_obj == 0) { 770*088f3894Sahrens origin->ds_phys->ds_next_clones_obj = 771*088f3894Sahrens zap_create(mos, 772*088f3894Sahrens DMU_OT_NEXT_CLONES, DMU_OT_NONE, 0, tx); 773*088f3894Sahrens } 774*088f3894Sahrens VERIFY(0 == zap_add_int(mos, 775*088f3894Sahrens origin->ds_phys->ds_next_clones_obj, 776*088f3894Sahrens dsobj, tx)); 777*088f3894Sahrens } 778*088f3894Sahrens 779fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 7803cb34c60Sahrens dd->dd_phys->dd_origin_obj = origin->ds_object; 781fa9e4066Sahrens } 782ab04eb8eStimh 783ab04eb8eStimh if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 784ab04eb8eStimh dsphys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 785ab04eb8eStimh 786ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 787fa9e4066Sahrens 788fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 789fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 7903cb34c60Sahrens 7913cb34c60Sahrens return (dsobj); 7923cb34c60Sahrens } 7933cb34c60Sahrens 7943cb34c60Sahrens uint64_t 795ab04eb8eStimh dsl_dataset_create_sync(dsl_dir_t *pdd, const char *lastname, 796ab04eb8eStimh dsl_dataset_t *origin, uint64_t flags, cred_t *cr, dmu_tx_t *tx) 7973cb34c60Sahrens { 7983cb34c60Sahrens dsl_pool_t *dp = pdd->dd_pool; 7993cb34c60Sahrens uint64_t dsobj, ddobj; 8003cb34c60Sahrens dsl_dir_t *dd; 8013cb34c60Sahrens 8023cb34c60Sahrens ASSERT(lastname[0] != '@'); 8033cb34c60Sahrens 804*088f3894Sahrens ddobj = dsl_dir_create_sync(dp, pdd, lastname, tx); 8053cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 8063cb34c60Sahrens 807*088f3894Sahrens dsobj = dsl_dataset_create_sync_dd(dd, origin, flags, tx); 8083cb34c60Sahrens 8093cb34c60Sahrens dsl_deleg_set_create_perms(dd, tx, cr); 8103cb34c60Sahrens 811fa9e4066Sahrens dsl_dir_close(dd, FTAG); 812fa9e4066Sahrens 8131d452cf5Sahrens return (dsobj); 814fa9e4066Sahrens } 815fa9e4066Sahrens 8161d452cf5Sahrens struct destroyarg { 8171d452cf5Sahrens dsl_sync_task_group_t *dstg; 8181d452cf5Sahrens char *snapname; 8191d452cf5Sahrens char *failed; 8201d452cf5Sahrens }; 8211d452cf5Sahrens 8221d452cf5Sahrens static int 8231d452cf5Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 824fa9e4066Sahrens { 8251d452cf5Sahrens struct destroyarg *da = arg; 8261d452cf5Sahrens dsl_dataset_t *ds; 8271d452cf5Sahrens char *cp; 828fa9e4066Sahrens int err; 829fa9e4066Sahrens 8301d452cf5Sahrens (void) strcat(name, "@"); 8311d452cf5Sahrens (void) strcat(name, da->snapname); 832745cd3c5Smaybee err = dsl_dataset_own(name, DS_MODE_READONLY | DS_MODE_INCONSISTENT, 833cdf5b4caSmmusante da->dstg, &ds); 8341d452cf5Sahrens cp = strchr(name, '@'); 8351d452cf5Sahrens *cp = '\0'; 836745cd3c5Smaybee if (err == 0) { 837745cd3c5Smaybee dsl_dataset_make_exclusive(ds, da->dstg); 838745cd3c5Smaybee dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 839745cd3c5Smaybee dsl_dataset_destroy_sync, ds, da->dstg, 0); 840745cd3c5Smaybee } else if (err == ENOENT) { 841745cd3c5Smaybee err = 0; 842745cd3c5Smaybee } else { 8431d452cf5Sahrens (void) strcpy(da->failed, name); 8441d452cf5Sahrens } 845745cd3c5Smaybee return (err); 8461d452cf5Sahrens } 84731fd60d3Sahrens 8481d452cf5Sahrens /* 8491d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 8501d452cf5Sahrens */ 8511d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 8521d452cf5Sahrens int 8531d452cf5Sahrens dsl_snapshots_destroy(char *fsname, char *snapname) 8541d452cf5Sahrens { 8551d452cf5Sahrens int err; 8561d452cf5Sahrens struct destroyarg da; 8571d452cf5Sahrens dsl_sync_task_t *dst; 8581d452cf5Sahrens spa_t *spa; 8591d452cf5Sahrens 86040feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 8611d452cf5Sahrens if (err) 8621d452cf5Sahrens return (err); 8631d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 8641d452cf5Sahrens da.snapname = snapname; 8651d452cf5Sahrens da.failed = fsname; 8661d452cf5Sahrens 8671d452cf5Sahrens err = dmu_objset_find(fsname, 8680b69c2f0Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 8691d452cf5Sahrens 8701d452cf5Sahrens if (err == 0) 8711d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 8721d452cf5Sahrens 8731d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 8741d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 8751d452cf5Sahrens dsl_dataset_t *ds = dst->dst_arg1; 876745cd3c5Smaybee /* 877745cd3c5Smaybee * Return the file system name that triggered the error 878745cd3c5Smaybee */ 8791d452cf5Sahrens if (dst->dst_err) { 8801d452cf5Sahrens dsl_dataset_name(ds, fsname); 88140feaa91Sahrens *strchr(fsname, '@') = '\0'; 882e1930233Sbonwick } 883745cd3c5Smaybee dsl_dataset_disown(ds, da.dstg); 884fa9e4066Sahrens } 885fa9e4066Sahrens 8861d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 8871d452cf5Sahrens spa_close(spa, FTAG); 888fa9e4066Sahrens return (err); 889fa9e4066Sahrens } 890fa9e4066Sahrens 8913cb34c60Sahrens /* 892745cd3c5Smaybee * ds must be opened as OWNER. On return (whether successful or not), 893745cd3c5Smaybee * ds will be closed and caller can no longer dereference it. 8943cb34c60Sahrens */ 895fa9e4066Sahrens int 8963cb34c60Sahrens dsl_dataset_destroy(dsl_dataset_t *ds, void *tag) 897fa9e4066Sahrens { 898fa9e4066Sahrens int err; 8991d452cf5Sahrens dsl_sync_task_group_t *dstg; 9001d452cf5Sahrens objset_t *os; 901fa9e4066Sahrens dsl_dir_t *dd; 9021d452cf5Sahrens uint64_t obj; 9031d452cf5Sahrens 9043cb34c60Sahrens if (dsl_dataset_is_snapshot(ds)) { 9051d452cf5Sahrens /* Destroying a snapshot is simpler */ 906745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 9071d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 9081d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 9093cb34c60Sahrens ds, tag, 0); 9103cb34c60Sahrens goto out; 9111d452cf5Sahrens } 912fa9e4066Sahrens 9131d452cf5Sahrens dd = ds->ds_dir; 914fa9e4066Sahrens 9151d452cf5Sahrens /* 9161d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 9171d452cf5Sahrens * case we crash while freeing the objects. 9181d452cf5Sahrens */ 9191d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 9201d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 9213cb34c60Sahrens if (err) 9223cb34c60Sahrens goto out; 9233cb34c60Sahrens 9243cb34c60Sahrens err = dmu_objset_open_ds(ds, DMU_OST_ANY, &os); 9253cb34c60Sahrens if (err) 9263cb34c60Sahrens goto out; 927fa9e4066Sahrens 9281d452cf5Sahrens /* 9291d452cf5Sahrens * remove the objects in open context, so that we won't 9301d452cf5Sahrens * have too much to do in syncing context. 9311d452cf5Sahrens */ 9326754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 9336754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 934cdb0ab79Smaybee /* 935cdb0ab79Smaybee * Ignore errors, if there is not enough disk space 936cdb0ab79Smaybee * we will deal with it in dsl_dataset_destroy_sync(). 937cdb0ab79Smaybee */ 938cdb0ab79Smaybee (void) dmu_free_object(os, obj); 9391d452cf5Sahrens } 9401d452cf5Sahrens 9411d452cf5Sahrens dmu_objset_close(os); 9421d452cf5Sahrens if (err != ESRCH) 9433cb34c60Sahrens goto out; 9441d452cf5Sahrens 94568038c2cSmaybee rw_enter(&dd->dd_pool->dp_config_rwlock, RW_READER); 94668038c2cSmaybee err = dsl_dir_open_obj(dd->dd_pool, dd->dd_object, NULL, FTAG, &dd); 94768038c2cSmaybee rw_exit(&dd->dd_pool->dp_config_rwlock); 94868038c2cSmaybee 94968038c2cSmaybee if (err) 95068038c2cSmaybee goto out; 95168038c2cSmaybee 9523cb34c60Sahrens if (ds->ds_user_ptr) { 953745cd3c5Smaybee /* 954745cd3c5Smaybee * We need to sync out all in-flight IO before we try 955745cd3c5Smaybee * to evict (the dataset evict func is trying to clear 956745cd3c5Smaybee * the cached entries for this dataset in the ARC). 957745cd3c5Smaybee */ 958745cd3c5Smaybee txg_wait_synced(dd->dd_pool, 0); 9591d452cf5Sahrens } 9601d452cf5Sahrens 9611d452cf5Sahrens /* 9621d452cf5Sahrens * Blow away the dsl_dir + head dataset. 9631d452cf5Sahrens */ 964745cd3c5Smaybee dsl_dataset_make_exclusive(ds, tag); 96568038c2cSmaybee if (ds->ds_user_ptr) { 96668038c2cSmaybee ds->ds_user_evict_func(ds, ds->ds_user_ptr); 96768038c2cSmaybee ds->ds_user_ptr = NULL; 96868038c2cSmaybee } 9691d452cf5Sahrens dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 9701d452cf5Sahrens dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 9713cb34c60Sahrens dsl_dataset_destroy_sync, ds, tag, 0); 9721d452cf5Sahrens dsl_sync_task_create(dstg, dsl_dir_destroy_check, 9731d452cf5Sahrens dsl_dir_destroy_sync, dd, FTAG, 0); 9741d452cf5Sahrens err = dsl_sync_task_group_wait(dstg); 9751d452cf5Sahrens dsl_sync_task_group_destroy(dstg); 976745cd3c5Smaybee /* if it is successful, dsl_dir_destroy_sync will close the dd */ 9773cb34c60Sahrens if (err) 9781d452cf5Sahrens dsl_dir_close(dd, FTAG); 9793cb34c60Sahrens out: 980745cd3c5Smaybee dsl_dataset_disown(ds, tag); 981fa9e4066Sahrens return (err); 982fa9e4066Sahrens } 983fa9e4066Sahrens 9841d452cf5Sahrens int 9853cb34c60Sahrens dsl_dataset_rollback(dsl_dataset_t *ds, dmu_objset_type_t ost) 9861d452cf5Sahrens { 987745cd3c5Smaybee ASSERT(ds->ds_owner); 9883cb34c60Sahrens 9891d452cf5Sahrens return (dsl_sync_task_do(ds->ds_dir->dd_pool, 9901d452cf5Sahrens dsl_dataset_rollback_check, dsl_dataset_rollback_sync, 9913cb34c60Sahrens ds, &ost, 0)); 9921d452cf5Sahrens } 9931d452cf5Sahrens 994fa9e4066Sahrens void * 995fa9e4066Sahrens dsl_dataset_set_user_ptr(dsl_dataset_t *ds, 996fa9e4066Sahrens void *p, dsl_dataset_evict_func_t func) 997fa9e4066Sahrens { 998fa9e4066Sahrens void *old; 999fa9e4066Sahrens 1000fa9e4066Sahrens mutex_enter(&ds->ds_lock); 1001fa9e4066Sahrens old = ds->ds_user_ptr; 1002fa9e4066Sahrens if (old == NULL) { 1003fa9e4066Sahrens ds->ds_user_ptr = p; 1004fa9e4066Sahrens ds->ds_user_evict_func = func; 1005fa9e4066Sahrens } 1006fa9e4066Sahrens mutex_exit(&ds->ds_lock); 1007fa9e4066Sahrens return (old); 1008fa9e4066Sahrens } 1009fa9e4066Sahrens 1010fa9e4066Sahrens void * 1011fa9e4066Sahrens dsl_dataset_get_user_ptr(dsl_dataset_t *ds) 1012fa9e4066Sahrens { 1013fa9e4066Sahrens return (ds->ds_user_ptr); 1014fa9e4066Sahrens } 1015fa9e4066Sahrens 1016fa9e4066Sahrens 1017c717a561Smaybee blkptr_t * 1018c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 1019fa9e4066Sahrens { 1020c717a561Smaybee return (&ds->ds_phys->ds_bp); 1021fa9e4066Sahrens } 1022fa9e4066Sahrens 1023fa9e4066Sahrens void 1024fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 1025fa9e4066Sahrens { 1026fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1027fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 1028fa9e4066Sahrens if (ds == NULL) { 1029fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 1030fa9e4066Sahrens } else { 1031fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1032fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 1033fa9e4066Sahrens } 1034fa9e4066Sahrens } 1035fa9e4066Sahrens 1036fa9e4066Sahrens spa_t * 1037fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 1038fa9e4066Sahrens { 1039fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 1040fa9e4066Sahrens } 1041fa9e4066Sahrens 1042fa9e4066Sahrens void 1043fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 1044fa9e4066Sahrens { 1045fa9e4066Sahrens dsl_pool_t *dp; 1046fa9e4066Sahrens 1047fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 1048fa9e4066Sahrens return; 1049fa9e4066Sahrens 1050fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 1051a2eea2e1Sahrens 1052a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1053a2eea2e1Sahrens panic("dirtying snapshot!"); 1054fa9e4066Sahrens 1055fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 1056fa9e4066Sahrens 1057fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 1058fa9e4066Sahrens /* up the hold count until we can be written out */ 1059fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 1060fa9e4066Sahrens } 1061fa9e4066Sahrens } 1062fa9e4066Sahrens 1063a9799022Sck /* 1064a9799022Sck * The unique space in the head dataset can be calculated by subtracting 1065a9799022Sck * the space used in the most recent snapshot, that is still being used 1066a9799022Sck * in this file system, from the space currently in use. To figure out 1067a9799022Sck * the space in the most recent snapshot still in use, we need to take 1068a9799022Sck * the total space used in the snapshot and subtract out the space that 1069a9799022Sck * has been freed up since the snapshot was taken. 1070a9799022Sck */ 1071a9799022Sck static void 1072a9799022Sck dsl_dataset_recalc_head_uniq(dsl_dataset_t *ds) 1073a9799022Sck { 1074a9799022Sck uint64_t mrs_used; 1075a9799022Sck uint64_t dlused, dlcomp, dluncomp; 1076a9799022Sck 1077a9799022Sck ASSERT(ds->ds_object == ds->ds_dir->dd_phys->dd_head_dataset_obj); 1078a9799022Sck 1079a9799022Sck if (ds->ds_phys->ds_prev_snap_obj != 0) 1080a9799022Sck mrs_used = ds->ds_prev->ds_phys->ds_used_bytes; 1081a9799022Sck else 1082a9799022Sck mrs_used = 0; 1083a9799022Sck 1084a9799022Sck VERIFY(0 == bplist_space(&ds->ds_deadlist, &dlused, &dlcomp, 1085a9799022Sck &dluncomp)); 1086a9799022Sck 1087a9799022Sck ASSERT3U(dlused, <=, mrs_used); 1088a9799022Sck ds->ds_phys->ds_unique_bytes = 1089a9799022Sck ds->ds_phys->ds_used_bytes - (mrs_used - dlused); 1090a9799022Sck 1091a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && 1092a9799022Sck spa_version(ds->ds_dir->dd_pool->dp_spa) >= 1093a9799022Sck SPA_VERSION_UNIQUE_ACCURATE) 1094a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1095a9799022Sck } 1096a9799022Sck 1097a9799022Sck static uint64_t 1098a9799022Sck dsl_dataset_unique(dsl_dataset_t *ds) 1099a9799022Sck { 1100a9799022Sck if (!DS_UNIQUE_IS_ACCURATE(ds) && !dsl_dataset_is_snapshot(ds)) 1101a9799022Sck dsl_dataset_recalc_head_uniq(ds); 1102a9799022Sck 1103a9799022Sck return (ds->ds_phys->ds_unique_bytes); 1104a9799022Sck } 1105a9799022Sck 1106fa9e4066Sahrens struct killarg { 1107a9799022Sck int64_t *usedp; 1108a9799022Sck int64_t *compressedp; 1109a9799022Sck int64_t *uncompressedp; 1110fa9e4066Sahrens zio_t *zio; 1111fa9e4066Sahrens dmu_tx_t *tx; 1112fa9e4066Sahrens }; 1113fa9e4066Sahrens 1114fa9e4066Sahrens static int 1115fa9e4066Sahrens kill_blkptr(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 1116fa9e4066Sahrens { 1117fa9e4066Sahrens struct killarg *ka = arg; 1118fa9e4066Sahrens blkptr_t *bp = &bc->bc_blkptr; 1119fa9e4066Sahrens 1120fa9e4066Sahrens ASSERT3U(bc->bc_errno, ==, 0); 1121fa9e4066Sahrens 1122fa9e4066Sahrens /* 1123fa9e4066Sahrens * Since this callback is not called concurrently, no lock is 1124fa9e4066Sahrens * needed on the accounting values. 1125fa9e4066Sahrens */ 112699653d4eSeschrock *ka->usedp += bp_get_dasize(spa, bp); 1127fa9e4066Sahrens *ka->compressedp += BP_GET_PSIZE(bp); 1128fa9e4066Sahrens *ka->uncompressedp += BP_GET_UCSIZE(bp); 1129fa9e4066Sahrens /* XXX check for EIO? */ 1130*088f3894Sahrens (void) dsl_free(ka->zio, spa_get_dsl(spa), ka->tx->tx_txg, 1131*088f3894Sahrens bp, NULL, NULL, ARC_NOWAIT); 1132fa9e4066Sahrens return (0); 1133fa9e4066Sahrens } 1134fa9e4066Sahrens 1135fa9e4066Sahrens /* ARGSUSED */ 11361d452cf5Sahrens static int 11371d452cf5Sahrens dsl_dataset_rollback_check(void *arg1, void *arg2, dmu_tx_t *tx) 1138fa9e4066Sahrens { 11391d452cf5Sahrens dsl_dataset_t *ds = arg1; 11403cb34c60Sahrens dmu_objset_type_t *ost = arg2; 1141fa9e4066Sahrens 11421d452cf5Sahrens /* 11433cb34c60Sahrens * We can only roll back to emptyness if it is a ZPL objset. 11441d452cf5Sahrens */ 11453cb34c60Sahrens if (*ost != DMU_OST_ZFS && ds->ds_phys->ds_prev_snap_txg == 0) 1146fa9e4066Sahrens return (EINVAL); 1147fa9e4066Sahrens 11481d452cf5Sahrens /* 11491d452cf5Sahrens * This must not be a snapshot. 11501d452cf5Sahrens */ 11511d452cf5Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 1152fa9e4066Sahrens return (EINVAL); 1153fa9e4066Sahrens 1154fa9e4066Sahrens /* 1155fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1156fa9e4066Sahrens * them. Try again. 1157fa9e4066Sahrens */ 11581d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1159fa9e4066Sahrens return (EAGAIN); 1160fa9e4066Sahrens 11611d452cf5Sahrens return (0); 11621d452cf5Sahrens } 11631d452cf5Sahrens 11641d452cf5Sahrens /* ARGSUSED */ 11651d452cf5Sahrens static void 1166ecd6cf80Smarks dsl_dataset_rollback_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 11671d452cf5Sahrens { 11681d452cf5Sahrens dsl_dataset_t *ds = arg1; 11693cb34c60Sahrens dmu_objset_type_t *ost = arg2; 11701d452cf5Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1171fa9e4066Sahrens 1172fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1173fa9e4066Sahrens 117486ccc033Sperrin /* 117586ccc033Sperrin * Before the roll back destroy the zil. 117686ccc033Sperrin */ 117786ccc033Sperrin if (ds->ds_user_ptr != NULL) { 117886ccc033Sperrin zil_rollback_destroy( 117986ccc033Sperrin ((objset_impl_t *)ds->ds_user_ptr)->os_zil, tx); 11803cb34c60Sahrens 11813cb34c60Sahrens /* 11823cb34c60Sahrens * We need to make sure that the objset_impl_t is reopened after 11833cb34c60Sahrens * we do the rollback, otherwise it will have the wrong 11843cb34c60Sahrens * objset_phys_t. Normally this would happen when this 1185745cd3c5Smaybee * dataset-open is closed, thus causing the 11863cb34c60Sahrens * dataset to be immediately evicted. But when doing "zfs recv 11873cb34c60Sahrens * -F", we reopen the objset before that, so that there is no 11883cb34c60Sahrens * window where the dataset is closed and inconsistent. 11893cb34c60Sahrens */ 11903cb34c60Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 11913cb34c60Sahrens ds->ds_user_ptr = NULL; 119286ccc033Sperrin } 11933a8a1de4Sperrin 1194fa9e4066Sahrens /* Zero out the deadlist. */ 1195fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1196fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1197fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1198fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1199ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1200ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1201fa9e4066Sahrens 1202fa9e4066Sahrens { 1203fa9e4066Sahrens /* Free blkptrs that we gave birth to */ 1204fa9e4066Sahrens zio_t *zio; 1205a9799022Sck int64_t used = 0, compressed = 0, uncompressed = 0; 1206fa9e4066Sahrens struct killarg ka; 1207d9b87188Sck int64_t delta; 1208fa9e4066Sahrens 1209fa9e4066Sahrens zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL, 1210fa9e4066Sahrens ZIO_FLAG_MUSTSUCCEED); 1211fa9e4066Sahrens ka.usedp = &used; 1212fa9e4066Sahrens ka.compressedp = &compressed; 1213fa9e4066Sahrens ka.uncompressedp = &uncompressed; 1214fa9e4066Sahrens ka.zio = zio; 1215fa9e4066Sahrens ka.tx = tx; 1216fa9e4066Sahrens (void) traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 1217fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 1218fa9e4066Sahrens (void) zio_wait(zio); 1219fa9e4066Sahrens 1220d9b87188Sck /* only deduct space beyond any refreservation */ 1221d9b87188Sck delta = parent_delta(ds, -used); 12221d452cf5Sahrens dsl_dir_diduse_space(ds->ds_dir, 1223d9b87188Sck delta, -compressed, -uncompressed, tx); 1224fa9e4066Sahrens } 1225fa9e4066Sahrens 1226*088f3894Sahrens if (ds->ds_prev && ds->ds_prev != ds->ds_dir->dd_pool->dp_origin_snap) { 12273cb34c60Sahrens /* Change our contents to that of the prev snapshot */ 12283cb34c60Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, 12293cb34c60Sahrens ds->ds_phys->ds_prev_snap_obj); 12303cb34c60Sahrens ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp; 12313cb34c60Sahrens ds->ds_phys->ds_used_bytes = 12323cb34c60Sahrens ds->ds_prev->ds_phys->ds_used_bytes; 12333cb34c60Sahrens ds->ds_phys->ds_compressed_bytes = 12343cb34c60Sahrens ds->ds_prev->ds_phys->ds_compressed_bytes; 12353cb34c60Sahrens ds->ds_phys->ds_uncompressed_bytes = 12363cb34c60Sahrens ds->ds_prev->ds_phys->ds_uncompressed_bytes; 12373cb34c60Sahrens ds->ds_phys->ds_flags = ds->ds_prev->ds_phys->ds_flags; 12383cb34c60Sahrens ds->ds_phys->ds_unique_bytes = 0; 1239fa9e4066Sahrens 12403cb34c60Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 12413cb34c60Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 12423cb34c60Sahrens ds->ds_prev->ds_phys->ds_unique_bytes = 0; 12433cb34c60Sahrens } 12443cb34c60Sahrens } else { 1245*088f3894Sahrens objset_impl_t *osi; 1246*088f3894Sahrens 12473cb34c60Sahrens /* Zero out our contents, recreate objset */ 12483cb34c60Sahrens bzero(&ds->ds_phys->ds_bp, sizeof (blkptr_t)); 12493cb34c60Sahrens ds->ds_phys->ds_used_bytes = 0; 12503cb34c60Sahrens ds->ds_phys->ds_compressed_bytes = 0; 12513cb34c60Sahrens ds->ds_phys->ds_uncompressed_bytes = 0; 12523cb34c60Sahrens ds->ds_phys->ds_flags = 0; 12533cb34c60Sahrens ds->ds_phys->ds_unique_bytes = 0; 1254*088f3894Sahrens osi = dmu_objset_create_impl(ds->ds_dir->dd_pool->dp_spa, ds, 12553cb34c60Sahrens &ds->ds_phys->ds_bp, *ost, tx); 1256*088f3894Sahrens #ifdef _KERNEL 1257*088f3894Sahrens zfs_create_fs(&osi->os, kcred, NULL, tx); 1258*088f3894Sahrens #endif 125985edac42Sahrens } 1260ecd6cf80Smarks 1261ecd6cf80Smarks spa_history_internal_log(LOG_DS_ROLLBACK, ds->ds_dir->dd_pool->dp_spa, 1262ecd6cf80Smarks tx, cr, "dataset = %llu", ds->ds_object); 1263fa9e4066Sahrens } 1264fa9e4066Sahrens 1265e1930233Sbonwick /* ARGSUSED */ 1266e1930233Sbonwick static int 12671d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1268e1930233Sbonwick { 12691d452cf5Sahrens dsl_dataset_t *ds = arg1; 12703cb34c60Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 12713cb34c60Sahrens uint64_t count; 12723cb34c60Sahrens int err; 1273e1930233Sbonwick 1274e1930233Sbonwick /* 1275e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1276e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1277e1930233Sbonwick * from.) 1278e1930233Sbonwick */ 1279e1930233Sbonwick if (ds->ds_prev != NULL && 1280e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1281e1930233Sbonwick return (EINVAL); 1282e1930233Sbonwick 12833cb34c60Sahrens /* 12843cb34c60Sahrens * This is really a dsl_dir thing, but check it here so that 12853cb34c60Sahrens * we'll be less likely to leave this dataset inconsistent & 12863cb34c60Sahrens * nearly destroyed. 12873cb34c60Sahrens */ 12883cb34c60Sahrens err = zap_count(mos, ds->ds_dir->dd_phys->dd_child_dir_zapobj, &count); 12893cb34c60Sahrens if (err) 12903cb34c60Sahrens return (err); 12913cb34c60Sahrens if (count != 0) 12923cb34c60Sahrens return (EEXIST); 12933cb34c60Sahrens 1294e1930233Sbonwick return (0); 1295e1930233Sbonwick } 1296e1930233Sbonwick 12971d452cf5Sahrens /* ARGSUSED */ 12981d452cf5Sahrens static void 1299ecd6cf80Smarks dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 1300fa9e4066Sahrens { 13011d452cf5Sahrens dsl_dataset_t *ds = arg1; 1302ecd6cf80Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1303fa9e4066Sahrens 13041d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 13051d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 13061d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1307ecd6cf80Smarks 1308ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 1309ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 13101d452cf5Sahrens } 1311fa9e4066Sahrens 13121d452cf5Sahrens /* ARGSUSED */ 13133cb34c60Sahrens int 13141d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 13151d452cf5Sahrens { 13161d452cf5Sahrens dsl_dataset_t *ds = arg1; 1317fa9e4066Sahrens 1318745cd3c5Smaybee /* we have an owner hold, so noone else can destroy us */ 1319745cd3c5Smaybee ASSERT(!DSL_DATASET_IS_DESTROYED(ds)); 1320745cd3c5Smaybee 1321fa9e4066Sahrens /* Can't delete a branch point. */ 13221d452cf5Sahrens if (ds->ds_phys->ds_num_children > 1) 13231d452cf5Sahrens return (EEXIST); 1324fa9e4066Sahrens 1325fa9e4066Sahrens /* 1326fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1327fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1328fa9e4066Sahrens * from.) 1329fa9e4066Sahrens */ 1330fa9e4066Sahrens if (ds->ds_prev != NULL && 13311d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1332fa9e4066Sahrens return (EINVAL); 1333fa9e4066Sahrens 1334fa9e4066Sahrens /* 1335fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1336fa9e4066Sahrens * them. Try again. 1337fa9e4066Sahrens */ 13381d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1339fa9e4066Sahrens return (EAGAIN); 13401d452cf5Sahrens 13411d452cf5Sahrens /* XXX we should do some i/o error checking... */ 13421d452cf5Sahrens return (0); 13431d452cf5Sahrens } 13441d452cf5Sahrens 1345745cd3c5Smaybee struct refsarg { 1346745cd3c5Smaybee kmutex_t lock; 1347745cd3c5Smaybee boolean_t gone; 1348745cd3c5Smaybee kcondvar_t cv; 1349745cd3c5Smaybee }; 1350745cd3c5Smaybee 1351745cd3c5Smaybee /* ARGSUSED */ 1352745cd3c5Smaybee static void 1353745cd3c5Smaybee dsl_dataset_refs_gone(dmu_buf_t *db, void *argv) 1354745cd3c5Smaybee { 1355745cd3c5Smaybee struct refsarg *arg = argv; 1356745cd3c5Smaybee 1357745cd3c5Smaybee mutex_enter(&arg->lock); 1358745cd3c5Smaybee arg->gone = TRUE; 1359745cd3c5Smaybee cv_signal(&arg->cv); 1360745cd3c5Smaybee mutex_exit(&arg->lock); 1361745cd3c5Smaybee } 1362745cd3c5Smaybee 1363745cd3c5Smaybee static void 1364745cd3c5Smaybee dsl_dataset_drain_refs(dsl_dataset_t *ds, void *tag) 1365745cd3c5Smaybee { 1366745cd3c5Smaybee struct refsarg arg; 1367745cd3c5Smaybee 1368745cd3c5Smaybee mutex_init(&arg.lock, NULL, MUTEX_DEFAULT, NULL); 1369745cd3c5Smaybee cv_init(&arg.cv, NULL, CV_DEFAULT, NULL); 1370745cd3c5Smaybee arg.gone = FALSE; 1371745cd3c5Smaybee (void) dmu_buf_update_user(ds->ds_dbuf, ds, &arg, &ds->ds_phys, 1372745cd3c5Smaybee dsl_dataset_refs_gone); 1373745cd3c5Smaybee dmu_buf_rele(ds->ds_dbuf, tag); 1374745cd3c5Smaybee mutex_enter(&arg.lock); 1375745cd3c5Smaybee while (!arg.gone) 1376745cd3c5Smaybee cv_wait(&arg.cv, &arg.lock); 1377745cd3c5Smaybee ASSERT(arg.gone); 1378745cd3c5Smaybee mutex_exit(&arg.lock); 1379745cd3c5Smaybee ds->ds_dbuf = NULL; 1380745cd3c5Smaybee ds->ds_phys = NULL; 1381745cd3c5Smaybee mutex_destroy(&arg.lock); 1382745cd3c5Smaybee cv_destroy(&arg.cv); 1383745cd3c5Smaybee } 1384745cd3c5Smaybee 13853cb34c60Sahrens void 1386ecd6cf80Smarks dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 13871d452cf5Sahrens { 13881d452cf5Sahrens dsl_dataset_t *ds = arg1; 1389a9799022Sck int64_t used = 0, compressed = 0, uncompressed = 0; 13901d452cf5Sahrens zio_t *zio; 13911d452cf5Sahrens int err; 13921d452cf5Sahrens int after_branch_point = FALSE; 13931d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 13941d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 13951d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 13961d452cf5Sahrens uint64_t obj; 13971d452cf5Sahrens 1398745cd3c5Smaybee ASSERT(ds->ds_owner); 13991d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_num_children, <=, 1); 14001d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 14011d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 14021d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 14031d452cf5Sahrens 1404745cd3c5Smaybee /* signal any waiters that this dataset is going away */ 1405745cd3c5Smaybee mutex_enter(&ds->ds_lock); 1406745cd3c5Smaybee ds->ds_owner = dsl_reaper; 1407745cd3c5Smaybee cv_broadcast(&ds->ds_exclusive_cv); 1408745cd3c5Smaybee mutex_exit(&ds->ds_lock); 1409745cd3c5Smaybee 1410a9799022Sck /* Remove our reservation */ 1411a9799022Sck if (ds->ds_reserved != 0) { 1412a9799022Sck uint64_t val = 0; 1413a9799022Sck dsl_dataset_set_reservation_sync(ds, &val, cr, tx); 1414a9799022Sck ASSERT3U(ds->ds_reserved, ==, 0); 1415a9799022Sck } 1416a9799022Sck 14171d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 14181d452cf5Sahrens 1419*088f3894Sahrens dsl_pool_ds_destroyed(ds, tx); 1420*088f3894Sahrens 14211d452cf5Sahrens obj = ds->ds_object; 1422fa9e4066Sahrens 1423fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1424fa9e4066Sahrens if (ds->ds_prev) { 1425fa9e4066Sahrens ds_prev = ds->ds_prev; 1426fa9e4066Sahrens } else { 1427745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1428745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, FTAG, &ds_prev)); 1429fa9e4066Sahrens } 1430fa9e4066Sahrens after_branch_point = 1431fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1432fa9e4066Sahrens 1433fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1434*088f3894Sahrens if (after_branch_point && 1435*088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj != 0) { 1436*088f3894Sahrens VERIFY(0 == zap_remove_int(mos, 1437*088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, obj, tx)); 1438*088f3894Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1439*088f3894Sahrens VERIFY(0 == zap_add_int(mos, 1440*088f3894Sahrens ds_prev->ds_phys->ds_next_clones_obj, 1441*088f3894Sahrens ds->ds_phys->ds_next_snap_obj, tx)); 1442*088f3894Sahrens } 1443*088f3894Sahrens } 1444fa9e4066Sahrens if (after_branch_point && 1445fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1446fa9e4066Sahrens /* This clone is toast. */ 1447fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1448fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1449fa9e4066Sahrens } else if (!after_branch_point) { 1450fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1451fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1452fa9e4066Sahrens } 1453fa9e4066Sahrens } 1454fa9e4066Sahrens 1455fa9e4066Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1456fa9e4066Sahrens 1457fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 14581d452cf5Sahrens blkptr_t bp; 1459fa9e4066Sahrens dsl_dataset_t *ds_next; 1460fa9e4066Sahrens uint64_t itor = 0; 1461a9799022Sck uint64_t old_unique; 1462fa9e4066Sahrens 1463745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1464745cd3c5Smaybee ds->ds_phys->ds_next_snap_obj, FTAG, &ds_next)); 1465fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1466fa9e4066Sahrens 1467a9799022Sck old_unique = dsl_dataset_unique(ds_next); 1468a9799022Sck 1469fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1470fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1471fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1472fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1473fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1474fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1475fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1476fa9e4066Sahrens 1477fa9e4066Sahrens /* 1478fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1479fa9e4066Sahrens * new deadlist) any entries from next's current 1480fa9e4066Sahrens * deadlist which were born before prev, and free the 1481fa9e4066Sahrens * other entries. 1482fa9e4066Sahrens * 1483fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1484fa9e4066Sahrens */ 1485745cd3c5Smaybee while (bplist_iterate(&ds_next->ds_deadlist, &itor, &bp) == 0) { 1486fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1487ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1488ea8dc4b6Seschrock &bp, tx)); 1489fa9e4066Sahrens if (ds_prev && !after_branch_point && 1490fa9e4066Sahrens bp.blk_birth > 1491fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1492fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 149399653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1494fa9e4066Sahrens } 1495fa9e4066Sahrens } else { 149699653d4eSeschrock used += bp_get_dasize(dp->dp_spa, &bp); 1497fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1498fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1499fa9e4066Sahrens /* XXX check return value? */ 1500*088f3894Sahrens (void) dsl_free(zio, dp, tx->tx_txg, 1501fa9e4066Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1502fa9e4066Sahrens } 1503fa9e4066Sahrens } 1504fa9e4066Sahrens 1505fa9e4066Sahrens /* free next's deadlist */ 1506fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1507fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1508fa9e4066Sahrens 1509fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1510745cd3c5Smaybee bplist_close(&ds->ds_deadlist); 1511fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1512fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1513ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1514ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1515fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1516fa9e4066Sahrens 1517fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1518fa9e4066Sahrens /* 1519fa9e4066Sahrens * Update next's unique to include blocks which 1520fa9e4066Sahrens * were previously shared by only this snapshot 1521fa9e4066Sahrens * and it. Those blocks will be born after the 1522fa9e4066Sahrens * prev snap and before this snap, and will have 1523fa9e4066Sahrens * died after the next snap and before the one 1524fa9e4066Sahrens * after that (ie. be on the snap after next's 1525fa9e4066Sahrens * deadlist). 1526fa9e4066Sahrens * 1527fa9e4066Sahrens * XXX we're doing this long task with the 1528fa9e4066Sahrens * config lock held 1529fa9e4066Sahrens */ 1530fa9e4066Sahrens dsl_dataset_t *ds_after_next; 1531fa9e4066Sahrens 1532745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1533745cd3c5Smaybee ds_next->ds_phys->ds_next_snap_obj, 1534745cd3c5Smaybee FTAG, &ds_after_next)); 1535fa9e4066Sahrens itor = 0; 1536fa9e4066Sahrens while (bplist_iterate(&ds_after_next->ds_deadlist, 1537fa9e4066Sahrens &itor, &bp) == 0) { 1538fa9e4066Sahrens if (bp.blk_birth > 1539fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg && 1540fa9e4066Sahrens bp.blk_birth <= 1541fa9e4066Sahrens ds->ds_phys->ds_creation_txg) { 1542fa9e4066Sahrens ds_next->ds_phys->ds_unique_bytes += 154399653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1544fa9e4066Sahrens } 1545fa9e4066Sahrens } 1546fa9e4066Sahrens 1547745cd3c5Smaybee dsl_dataset_rele(ds_after_next, FTAG); 1548fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1549fa9e4066Sahrens } else { 1550fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1551745cd3c5Smaybee dsl_dataset_drop_ref(ds_next->ds_prev, ds_next); 1552745cd3c5Smaybee ds_next->ds_prev = NULL; 1553fa9e4066Sahrens if (ds_prev) { 1554745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1555745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, 1556745cd3c5Smaybee ds_next, &ds_next->ds_prev)); 1557fa9e4066Sahrens } 1558a9799022Sck 1559a9799022Sck dsl_dataset_recalc_head_uniq(ds_next); 1560a9799022Sck 1561a9799022Sck /* 1562a9799022Sck * Reduce the amount of our unconsmed refreservation 1563a9799022Sck * being charged to our parent by the amount of 1564a9799022Sck * new unique data we have gained. 1565a9799022Sck */ 1566a9799022Sck if (old_unique < ds_next->ds_reserved) { 1567a9799022Sck int64_t mrsdelta; 1568a9799022Sck uint64_t new_unique = 1569a9799022Sck ds_next->ds_phys->ds_unique_bytes; 1570a9799022Sck 1571a9799022Sck ASSERT(old_unique <= new_unique); 1572a9799022Sck mrsdelta = MIN(new_unique - old_unique, 1573a9799022Sck ds_next->ds_reserved - old_unique); 1574a9799022Sck dsl_dir_diduse_space(ds->ds_dir, -mrsdelta, 1575a9799022Sck 0, 0, tx); 1576a9799022Sck } 1577fa9e4066Sahrens } 1578745cd3c5Smaybee dsl_dataset_rele(ds_next, FTAG); 1579fa9e4066Sahrens 1580fa9e4066Sahrens /* 1581a9799022Sck * NB: unique_bytes might not be accurate for the head objset. 1582a9799022Sck * Before SPA_VERSION 9, we didn't update its value when we 1583a9799022Sck * deleted the most recent snapshot. 1584fa9e4066Sahrens */ 1585fa9e4066Sahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 1586fa9e4066Sahrens } else { 1587fa9e4066Sahrens /* 1588fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1589fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1590fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1591fa9e4066Sahrens * safe to ignore the deadlist contents.) 1592fa9e4066Sahrens */ 1593fa9e4066Sahrens struct killarg ka; 1594fa9e4066Sahrens 1595fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1596fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1597fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1598fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1599fa9e4066Sahrens 1600fa9e4066Sahrens /* 1601fa9e4066Sahrens * Free everything that we point to (that's born after 1602fa9e4066Sahrens * the previous snapshot, if we are a clone) 1603fa9e4066Sahrens * 1604fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1605fa9e4066Sahrens */ 1606fa9e4066Sahrens ka.usedp = &used; 1607fa9e4066Sahrens ka.compressedp = &compressed; 1608fa9e4066Sahrens ka.uncompressedp = &uncompressed; 1609fa9e4066Sahrens ka.zio = zio; 1610fa9e4066Sahrens ka.tx = tx; 1611fa9e4066Sahrens err = traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 1612fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 1613fa9e4066Sahrens ASSERT3U(err, ==, 0); 1614a9799022Sck ASSERT(spa_version(dp->dp_spa) < 1615a9799022Sck SPA_VERSION_UNIQUE_ACCURATE || 1616a9799022Sck used == ds->ds_phys->ds_unique_bytes); 1617fa9e4066Sahrens } 1618fa9e4066Sahrens 1619fa9e4066Sahrens err = zio_wait(zio); 1620fa9e4066Sahrens ASSERT3U(err, ==, 0); 1621fa9e4066Sahrens 16221d452cf5Sahrens dsl_dir_diduse_space(ds->ds_dir, -used, -compressed, -uncompressed, tx); 1623fa9e4066Sahrens 16241d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1625745cd3c5Smaybee /* Erase the link in the dir */ 16261d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 16271d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1628745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj != 0); 1629745cd3c5Smaybee err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1630745cd3c5Smaybee ASSERT(err == 0); 1631fa9e4066Sahrens } else { 1632fa9e4066Sahrens /* remove from snapshot namespace */ 1633fa9e4066Sahrens dsl_dataset_t *ds_head; 1634745cd3c5Smaybee ASSERT(ds->ds_phys->ds_snapnames_zapobj == 0); 1635745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dp, 1636745cd3c5Smaybee ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &ds_head)); 16378660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1638fa9e4066Sahrens #ifdef ZFS_DEBUG 1639fa9e4066Sahrens { 1640fa9e4066Sahrens uint64_t val; 1641ab04eb8eStimh 1642745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds_head, 1643ab04eb8eStimh ds->ds_snapname, &val); 1644fa9e4066Sahrens ASSERT3U(err, ==, 0); 1645fa9e4066Sahrens ASSERT3U(val, ==, obj); 1646fa9e4066Sahrens } 1647fa9e4066Sahrens #endif 1648745cd3c5Smaybee err = dsl_dataset_snap_remove(ds_head, ds->ds_snapname, tx); 1649fa9e4066Sahrens ASSERT(err == 0); 1650745cd3c5Smaybee dsl_dataset_rele(ds_head, FTAG); 1651fa9e4066Sahrens } 1652fa9e4066Sahrens 1653fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1654745cd3c5Smaybee dsl_dataset_rele(ds_prev, FTAG); 1655fa9e4066Sahrens 1656990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 1657ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx, 1658ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 1659ecd6cf80Smarks 1660*088f3894Sahrens if (ds->ds_phys->ds_next_clones_obj != 0) { 1661*088f3894Sahrens uint64_t count; 1662*088f3894Sahrens ASSERT(0 == zap_count(mos, 1663*088f3894Sahrens ds->ds_phys->ds_next_clones_obj, &count) && count == 0); 1664*088f3894Sahrens VERIFY(0 == dmu_object_free(mos, 1665*088f3894Sahrens ds->ds_phys->ds_next_clones_obj, tx)); 1666*088f3894Sahrens } 1667745cd3c5Smaybee dsl_dir_close(ds->ds_dir, ds); 1668745cd3c5Smaybee ds->ds_dir = NULL; 1669745cd3c5Smaybee dsl_dataset_drain_refs(ds, tag); 16701d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1671fa9e4066Sahrens } 1672fa9e4066Sahrens 1673a9799022Sck static int 1674a9799022Sck dsl_dataset_snapshot_reserve_space(dsl_dataset_t *ds, dmu_tx_t *tx) 1675a9799022Sck { 1676a9799022Sck uint64_t asize; 1677a9799022Sck 1678a9799022Sck if (!dmu_tx_is_syncing(tx)) 1679a9799022Sck return (0); 1680a9799022Sck 1681a9799022Sck /* 1682a9799022Sck * If there's an fs-only reservation, any blocks that might become 1683a9799022Sck * owned by the snapshot dataset must be accommodated by space 1684a9799022Sck * outside of the reservation. 1685a9799022Sck */ 1686a9799022Sck asize = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 1687a9799022Sck if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, FALSE)) 1688a9799022Sck return (ENOSPC); 1689a9799022Sck 1690a9799022Sck /* 1691a9799022Sck * Propogate any reserved space for this snapshot to other 1692a9799022Sck * snapshot checks in this sync group. 1693a9799022Sck */ 1694a9799022Sck if (asize > 0) 1695a9799022Sck dsl_dir_willuse_space(ds->ds_dir, asize, tx); 1696a9799022Sck 1697a9799022Sck return (0); 1698a9799022Sck } 1699a9799022Sck 17001d452cf5Sahrens /* ARGSUSED */ 1701fa9e4066Sahrens int 17021d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1703fa9e4066Sahrens { 17043cb34c60Sahrens dsl_dataset_t *ds = arg1; 17051d452cf5Sahrens const char *snapname = arg2; 1706fa9e4066Sahrens int err; 17071d452cf5Sahrens uint64_t value; 1708fa9e4066Sahrens 17091d452cf5Sahrens /* 17101d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 17111d452cf5Sahrens * is already one, try again. 17121d452cf5Sahrens */ 17131d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 17141d452cf5Sahrens return (EAGAIN); 1715fa9e4066Sahrens 17161d452cf5Sahrens /* 17171d452cf5Sahrens * Check for conflicting name snapshot name. 17181d452cf5Sahrens */ 1719745cd3c5Smaybee err = dsl_dataset_snap_lookup(ds, snapname, &value); 17201d452cf5Sahrens if (err == 0) 1721fa9e4066Sahrens return (EEXIST); 17221d452cf5Sahrens if (err != ENOENT) 17231d452cf5Sahrens return (err); 1724fa9e4066Sahrens 1725b7661cccSmmusante /* 1726b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 1727b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 1728b7661cccSmmusante */ 1729b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 1730b7661cccSmmusante return (ENAMETOOLONG); 1731b7661cccSmmusante 1732a9799022Sck err = dsl_dataset_snapshot_reserve_space(ds, tx); 1733a9799022Sck if (err) 1734a9799022Sck return (err); 1735a9799022Sck 17361d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 17371d452cf5Sahrens return (0); 17381d452cf5Sahrens } 1739fa9e4066Sahrens 17401d452cf5Sahrens void 1741ecd6cf80Smarks dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 17421d452cf5Sahrens { 17433cb34c60Sahrens dsl_dataset_t *ds = arg1; 17441d452cf5Sahrens const char *snapname = arg2; 17451d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 17461d452cf5Sahrens dmu_buf_t *dbuf; 17471d452cf5Sahrens dsl_dataset_phys_t *dsphys; 1748*088f3894Sahrens uint64_t dsobj, crtxg; 17491d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 17501d452cf5Sahrens int err; 1751fa9e4066Sahrens 17521d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1753fa9e4066Sahrens 1754*088f3894Sahrens /* 1755*088f3894Sahrens * The origin's ds_creation_txg has to be < TXG_INITIAL 1756*088f3894Sahrens */ 1757*088f3894Sahrens if (strcmp(snapname, ORIGIN_DIR_NAME) == 0) 1758*088f3894Sahrens crtxg = 1; 1759*088f3894Sahrens else 1760*088f3894Sahrens crtxg = tx->tx_txg; 1761*088f3894Sahrens 17621649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 17631649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 1764ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1765fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 1766fa9e4066Sahrens dsphys = dbuf->db_data; 1767745cd3c5Smaybee bzero(dsphys, sizeof (dsl_dataset_phys_t)); 17681d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 1769fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 1770fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1771fa9e4066Sahrens sizeof (dsphys->ds_guid)); 1772fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1773fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1774fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1775fa9e4066Sahrens dsphys->ds_num_children = 1; 1776fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1777*088f3894Sahrens dsphys->ds_creation_txg = crtxg; 1778fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1779fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1780fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1781fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 178299653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 1783fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 1784ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 1785fa9e4066Sahrens 17861d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 17871d452cf5Sahrens if (ds->ds_prev) { 1788*088f3894Sahrens uint64_t next_clones_obj = 1789*088f3894Sahrens ds->ds_prev->ds_phys->ds_next_clones_obj; 17901d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 1791fa9e4066Sahrens ds->ds_object || 17921d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 17931d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 17941d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1795fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 17961d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 17971d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1798*088f3894Sahrens } else if (next_clones_obj != 0) { 1799*088f3894Sahrens VERIFY3U(0, ==, zap_remove_int(mos, 1800*088f3894Sahrens next_clones_obj, dsphys->ds_next_snap_obj, tx)); 1801*088f3894Sahrens VERIFY3U(0, ==, zap_add_int(mos, 1802*088f3894Sahrens next_clones_obj, dsobj, tx)); 1803fa9e4066Sahrens } 1804fa9e4066Sahrens } 1805fa9e4066Sahrens 1806a9799022Sck /* 1807a9799022Sck * If we have a reference-reservation on this dataset, we will 1808a9799022Sck * need to increase the amount of refreservation being charged 1809a9799022Sck * since our unique space is going to zero. 1810a9799022Sck */ 1811a9799022Sck if (ds->ds_reserved) { 1812a9799022Sck int64_t add = MIN(dsl_dataset_unique(ds), ds->ds_reserved); 1813a9799022Sck dsl_dir_diduse_space(ds->ds_dir, add, 0, 0, tx); 1814a9799022Sck } 1815a9799022Sck 1816fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1817fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1818a4611edeSahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, tx->tx_txg); 1819fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1820*088f3894Sahrens ds->ds_phys->ds_prev_snap_txg = crtxg; 1821fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1822a9799022Sck if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE) 1823a9799022Sck ds->ds_phys->ds_flags |= DS_FLAG_UNIQUE_ACCURATE; 1824fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1825fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1826ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1827ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1828fa9e4066Sahrens 1829fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1830fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1831fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 1832fa9e4066Sahrens ASSERT(err == 0); 1833fa9e4066Sahrens 1834fa9e4066Sahrens if (ds->ds_prev) 1835745cd3c5Smaybee dsl_dataset_drop_ref(ds->ds_prev, ds); 1836745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(dp, 1837745cd3c5Smaybee ds->ds_phys->ds_prev_snap_obj, ds, &ds->ds_prev)); 1838ecd6cf80Smarks 1839*088f3894Sahrens dsl_pool_ds_snapshotted(ds, tx); 1840*088f3894Sahrens 1841ecd6cf80Smarks spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr, 184240feaa91Sahrens "dataset = %llu", dsobj); 1843fa9e4066Sahrens } 1844fa9e4066Sahrens 1845fa9e4066Sahrens void 1846c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 1847fa9e4066Sahrens { 1848fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1849fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 1850fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1851fa9e4066Sahrens 185291ebeef5Sahrens /* 185391ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 185491ebeef5Sahrens * sync it out now. 185591ebeef5Sahrens */ 185691ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 185791ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 185891ebeef5Sahrens 1859fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 1860c717a561Smaybee dmu_objset_sync(ds->ds_user_ptr, zio, tx); 1861fa9e4066Sahrens } 1862fa9e4066Sahrens 1863fa9e4066Sahrens void 1864a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 1865fa9e4066Sahrens { 1866a9799022Sck uint64_t refd, avail, uobjs, aobjs; 1867a9799022Sck 1868a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 1869fa9e4066Sahrens 1870a9799022Sck dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs); 1871a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail); 1872a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd); 1873a9799022Sck 1874a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 1875a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 1876a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 1877a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 1878a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFQUOTA, 1879a9799022Sck ds->ds_quota); 1880a9799022Sck dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRESERVATION, 1881a9799022Sck ds->ds_reserved); 1882c5904d13Seschrock dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_GUID, 1883c5904d13Seschrock ds->ds_phys->ds_guid); 1884fa9e4066Sahrens 1885fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1886fa9e4066Sahrens /* 1887fa9e4066Sahrens * This is a snapshot; override the dd's space used with 1888a2eea2e1Sahrens * our unique space and compression ratio. 1889fa9e4066Sahrens */ 1890a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 1891a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 1892a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 1893a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 1894a2eea2e1Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 1895a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes)); 1896fa9e4066Sahrens } 1897fa9e4066Sahrens } 1898fa9e4066Sahrens 1899a2eea2e1Sahrens void 1900a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 1901a2eea2e1Sahrens { 1902a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 1903a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 19043cb34c60Sahrens stat->dds_guid = ds->ds_phys->ds_guid; 1905a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1906a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 1907a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 1908a2eea2e1Sahrens } 1909a2eea2e1Sahrens 1910a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 19114ccbb6e7Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 1912*088f3894Sahrens if (dsl_dir_is_clone(ds->ds_dir)) { 1913a2eea2e1Sahrens dsl_dataset_t *ods; 1914a2eea2e1Sahrens 1915745cd3c5Smaybee VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool, 1916745cd3c5Smaybee ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods)); 19173cb34c60Sahrens dsl_dataset_name(ods, stat->dds_origin); 1918745cd3c5Smaybee dsl_dataset_drop_ref(ods, FTAG); 1919a2eea2e1Sahrens } 19204ccbb6e7Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 1921a2eea2e1Sahrens } 1922a2eea2e1Sahrens 1923a2eea2e1Sahrens uint64_t 1924a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 1925a2eea2e1Sahrens { 192691ebeef5Sahrens return (ds->ds_fsid_guid); 1927a2eea2e1Sahrens } 1928a2eea2e1Sahrens 1929a2eea2e1Sahrens void 1930a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 1931a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 1932a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 1933fa9e4066Sahrens { 1934a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 1935a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 1936a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) 1937a9799022Sck *availbytesp += ds->ds_reserved - ds->ds_phys->ds_unique_bytes; 1938a9799022Sck if (ds->ds_quota != 0) { 1939a9799022Sck /* 1940a9799022Sck * Adjust available bytes according to refquota 1941a9799022Sck */ 1942a9799022Sck if (*refdbytesp < ds->ds_quota) 1943a9799022Sck *availbytesp = MIN(*availbytesp, 1944a9799022Sck ds->ds_quota - *refdbytesp); 1945a9799022Sck else 1946a9799022Sck *availbytesp = 0; 1947a9799022Sck } 1948a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 1949a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 1950fa9e4066Sahrens } 1951fa9e4066Sahrens 1952f18faf3fSek boolean_t 1953f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 1954f18faf3fSek { 1955f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 1956f18faf3fSek 1957f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 1958f18faf3fSek dsl_pool_sync_context(dp)); 1959f18faf3fSek if (ds->ds_prev == NULL) 1960f18faf3fSek return (B_FALSE); 1961f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 1962f18faf3fSek ds->ds_prev->ds_phys->ds_creation_txg) 1963f18faf3fSek return (B_TRUE); 1964f18faf3fSek return (B_FALSE); 1965f18faf3fSek } 1966f18faf3fSek 19671d452cf5Sahrens /* ARGSUSED */ 1968fa9e4066Sahrens static int 19691d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 1970fa9e4066Sahrens { 19711d452cf5Sahrens dsl_dataset_t *ds = arg1; 19721d452cf5Sahrens char *newsnapname = arg2; 19731d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 19741d452cf5Sahrens dsl_dataset_t *hds; 1975fa9e4066Sahrens uint64_t val; 19761d452cf5Sahrens int err; 1977fa9e4066Sahrens 1978745cd3c5Smaybee err = dsl_dataset_hold_obj(dd->dd_pool, 1979745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds); 1980fa9e4066Sahrens if (err) 1981fa9e4066Sahrens return (err); 1982fa9e4066Sahrens 19831d452cf5Sahrens /* new name better not be in use */ 1984745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, newsnapname, &val); 1985745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 19861d452cf5Sahrens 19871d452cf5Sahrens if (err == 0) 19881d452cf5Sahrens err = EEXIST; 19891d452cf5Sahrens else if (err == ENOENT) 19901d452cf5Sahrens err = 0; 1991cdf5b4caSmmusante 1992cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 1993cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 1994cdf5b4caSmmusante err = ENAMETOOLONG; 1995cdf5b4caSmmusante 19961d452cf5Sahrens return (err); 19971d452cf5Sahrens } 1998fa9e4066Sahrens 19991d452cf5Sahrens static void 2000ecd6cf80Smarks dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, 2001ecd6cf80Smarks cred_t *cr, dmu_tx_t *tx) 20021d452cf5Sahrens { 20031d452cf5Sahrens dsl_dataset_t *ds = arg1; 2004ecd6cf80Smarks const char *newsnapname = arg2; 20051d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 20061d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 20071d452cf5Sahrens dsl_dataset_t *hds; 20081d452cf5Sahrens int err; 2009fa9e4066Sahrens 20101d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 2011fa9e4066Sahrens 2012745cd3c5Smaybee VERIFY(0 == dsl_dataset_hold_obj(dd->dd_pool, 2013745cd3c5Smaybee dd->dd_phys->dd_head_dataset_obj, FTAG, &hds)); 2014fa9e4066Sahrens 20151d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 2016745cd3c5Smaybee err = dsl_dataset_snap_remove(hds, ds->ds_snapname, tx); 2017fa9e4066Sahrens ASSERT3U(err, ==, 0); 20181d452cf5Sahrens mutex_enter(&ds->ds_lock); 20191d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 20201d452cf5Sahrens mutex_exit(&ds->ds_lock); 20211d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 20221d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 2023fa9e4066Sahrens ASSERT3U(err, ==, 0); 2024fa9e4066Sahrens 2025ecd6cf80Smarks spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 2026ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 2027745cd3c5Smaybee dsl_dataset_rele(hds, FTAG); 2028fa9e4066Sahrens } 2029fa9e4066Sahrens 2030f18faf3fSek struct renamesnaparg { 2031cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 2032cdf5b4caSmmusante char failed[MAXPATHLEN]; 2033cdf5b4caSmmusante char *oldsnap; 2034cdf5b4caSmmusante char *newsnap; 2035cdf5b4caSmmusante }; 2036cdf5b4caSmmusante 2037cdf5b4caSmmusante static int 2038cdf5b4caSmmusante dsl_snapshot_rename_one(char *name, void *arg) 2039cdf5b4caSmmusante { 2040f18faf3fSek struct renamesnaparg *ra = arg; 2041cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 2042cdf5b4caSmmusante char *cp; 2043cdf5b4caSmmusante int err; 2044cdf5b4caSmmusante 2045cdf5b4caSmmusante cp = name + strlen(name); 2046cdf5b4caSmmusante *cp = '@'; 2047cdf5b4caSmmusante (void) strcpy(cp + 1, ra->oldsnap); 2048ecd6cf80Smarks 2049ecd6cf80Smarks /* 2050ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 2051ecd6cf80Smarks * so we just pass name for both the to/from argument. 2052ecd6cf80Smarks */ 2053ecd6cf80Smarks if (err = zfs_secpolicy_rename_perms(name, name, CRED())) { 2054ecd6cf80Smarks (void) strcpy(ra->failed, name); 2055ecd6cf80Smarks return (err); 2056ecd6cf80Smarks } 2057ecd6cf80Smarks 2058745cd3c5Smaybee #ifdef _KERNEL 2059745cd3c5Smaybee /* 2060745cd3c5Smaybee * For all filesystems undergoing rename, we'll need to unmount it. 2061745cd3c5Smaybee */ 2062745cd3c5Smaybee (void) zfs_unmount_snap(name, NULL); 2063745cd3c5Smaybee #endif 2064745cd3c5Smaybee err = dsl_dataset_hold(name, ra->dstg, &ds); 2065745cd3c5Smaybee *cp = '\0'; 2066cdf5b4caSmmusante if (err == ENOENT) { 2067cdf5b4caSmmusante return (0); 2068745cd3c5Smaybee } else if (err) { 2069cdf5b4caSmmusante (void) strcpy(ra->failed, name); 2070cdf5b4caSmmusante return (err); 2071cdf5b4caSmmusante } 2072cdf5b4caSmmusante 2073cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 2074cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 2075cdf5b4caSmmusante 2076cdf5b4caSmmusante return (0); 2077cdf5b4caSmmusante } 2078cdf5b4caSmmusante 2079cdf5b4caSmmusante static int 2080cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 2081cdf5b4caSmmusante { 2082cdf5b4caSmmusante int err; 2083f18faf3fSek struct renamesnaparg *ra; 2084cdf5b4caSmmusante dsl_sync_task_t *dst; 2085cdf5b4caSmmusante spa_t *spa; 2086cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 2087cdf5b4caSmmusante int len = strlen(oldname); 2088cdf5b4caSmmusante 2089cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 2090cdf5b4caSmmusante cp = strchr(fsname, '@'); 2091cdf5b4caSmmusante *cp = '\0'; 2092cdf5b4caSmmusante 209340feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 2094cdf5b4caSmmusante if (err) { 2095cdf5b4caSmmusante kmem_free(fsname, len + 1); 2096cdf5b4caSmmusante return (err); 2097cdf5b4caSmmusante } 2098f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 2099cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 2100cdf5b4caSmmusante 2101cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 2102cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 2103cdf5b4caSmmusante *ra->failed = '\0'; 2104cdf5b4caSmmusante 2105cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 2106cdf5b4caSmmusante DS_FIND_CHILDREN); 2107cdf5b4caSmmusante kmem_free(fsname, len + 1); 2108cdf5b4caSmmusante 2109cdf5b4caSmmusante if (err == 0) { 2110cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 2111cdf5b4caSmmusante } 2112cdf5b4caSmmusante 2113cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 2114cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 2115cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 2116cdf5b4caSmmusante if (dst->dst_err) { 2117cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 21182572aa4eSmmusante (void) strcat(ra->failed, "@"); 21192572aa4eSmmusante (void) strcat(ra->failed, ra->newsnap); 2120cdf5b4caSmmusante } 2121745cd3c5Smaybee dsl_dataset_rele(ds, ra->dstg); 2122cdf5b4caSmmusante } 2123cdf5b4caSmmusante 2124ecd6cf80Smarks if (err) 2125ecd6cf80Smarks (void) strcpy(oldname, ra->failed); 2126cdf5b4caSmmusante 2127cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 2128f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 2129cdf5b4caSmmusante spa_close(spa, FTAG); 2130cdf5b4caSmmusante return (err); 2131cdf5b4caSmmusante } 2132cdf5b4caSmmusante 21333a5a36beSmmusante static int 21343a5a36beSmmusante dsl_valid_rename(char *oldname, void *arg) 21353a5a36beSmmusante { 21363a5a36beSmmusante int delta = *(int *)arg; 21373a5a36beSmmusante 21383a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 21393a5a36beSmmusante return (ENAMETOOLONG); 21403a5a36beSmmusante 21413a5a36beSmmusante return (0); 21423a5a36beSmmusante } 21433a5a36beSmmusante 2144fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 2145fa9e4066Sahrens int 2146745cd3c5Smaybee dsl_dataset_rename(char *oldname, const char *newname, boolean_t recursive) 2147fa9e4066Sahrens { 2148fa9e4066Sahrens dsl_dir_t *dd; 21491d452cf5Sahrens dsl_dataset_t *ds; 2150fa9e4066Sahrens const char *tail; 2151fa9e4066Sahrens int err; 2152fa9e4066Sahrens 21531d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 2154ea8dc4b6Seschrock if (err) 2155ea8dc4b6Seschrock return (err); 2156fa9e4066Sahrens if (tail == NULL) { 21573a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 21583a5a36beSmmusante 2159*088f3894Sahrens /* if we're growing, validate child name lengths */ 21603a5a36beSmmusante if (delta > 0) 21613a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 21623a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 21633a5a36beSmmusante 21643a5a36beSmmusante if (!err) 21653a5a36beSmmusante err = dsl_dir_rename(dd, newname); 2166fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2167fa9e4066Sahrens return (err); 2168fa9e4066Sahrens } 2169fa9e4066Sahrens if (tail[0] != '@') { 2170fa9e4066Sahrens /* the name ended in a nonexistant component */ 2171fa9e4066Sahrens dsl_dir_close(dd, FTAG); 2172fa9e4066Sahrens return (ENOENT); 2173fa9e4066Sahrens } 2174fa9e4066Sahrens 2175fa9e4066Sahrens dsl_dir_close(dd, FTAG); 21761d452cf5Sahrens 21771d452cf5Sahrens /* new name must be snapshot in same filesystem */ 21781d452cf5Sahrens tail = strchr(newname, '@'); 21791d452cf5Sahrens if (tail == NULL) 21801d452cf5Sahrens return (EINVAL); 21811d452cf5Sahrens tail++; 21821d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 21831d452cf5Sahrens return (EXDEV); 21841d452cf5Sahrens 2185cdf5b4caSmmusante if (recursive) { 2186cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 2187cdf5b4caSmmusante } else { 2188745cd3c5Smaybee err = dsl_dataset_hold(oldname, FTAG, &ds); 2189cdf5b4caSmmusante if (err) 2190cdf5b4caSmmusante return (err); 21911d452cf5Sahrens 2192cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2193cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 2194cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 21951d452cf5Sahrens 2196745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2197cdf5b4caSmmusante } 21981d452cf5Sahrens 2199fa9e4066Sahrens return (err); 2200fa9e4066Sahrens } 220199653d4eSeschrock 2202*088f3894Sahrens struct promotenode { 2203745cd3c5Smaybee list_node_t link; 2204745cd3c5Smaybee dsl_dataset_t *ds; 2205745cd3c5Smaybee }; 2206745cd3c5Smaybee 22071d452cf5Sahrens struct promotearg { 2208745cd3c5Smaybee list_t snap_list; 2209745cd3c5Smaybee dsl_dataset_t *clone_origin, *old_head; 22101d452cf5Sahrens uint64_t used, comp, uncomp, unique; 2211745cd3c5Smaybee uint64_t newnext_obj; 22121d452cf5Sahrens }; 22131d452cf5Sahrens 2214ecd6cf80Smarks /* ARGSUSED */ 221599653d4eSeschrock static int 22161d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 221799653d4eSeschrock { 22181d452cf5Sahrens dsl_dataset_t *hds = arg1; 22191d452cf5Sahrens struct promotearg *pa = arg2; 2220*088f3894Sahrens struct promotenode *snap = list_head(&pa->snap_list); 22211d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 2222745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 2223745cd3c5Smaybee dsl_dataset_t *newnext_ds; 2224745cd3c5Smaybee char *name; 22251d452cf5Sahrens uint64_t itor = 0; 222699653d4eSeschrock blkptr_t bp; 2227745cd3c5Smaybee int err; 22281d452cf5Sahrens 2229*088f3894Sahrens /* Check that it is a real clone */ 2230*088f3894Sahrens if (!dsl_dir_is_clone(hds->ds_dir)) 223199653d4eSeschrock return (EINVAL); 223299653d4eSeschrock 22331d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 22341d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 22351d452cf5Sahrens return (0); 22361d452cf5Sahrens 2237745cd3c5Smaybee if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) 2238745cd3c5Smaybee return (EXDEV); 223999653d4eSeschrock 22403cb34c60Sahrens /* find origin's new next ds */ 2241745cd3c5Smaybee newnext_ds = hds; 22423cb34c60Sahrens while (newnext_ds->ds_phys->ds_prev_snap_obj != origin_ds->ds_object) { 224399653d4eSeschrock dsl_dataset_t *prev; 224499653d4eSeschrock 2245745cd3c5Smaybee err = dsl_dataset_hold_obj(dp, 2246745cd3c5Smaybee newnext_ds->ds_phys->ds_prev_snap_obj, FTAG, &prev); 2247745cd3c5Smaybee if (newnext_ds != hds) 2248745cd3c5Smaybee dsl_dataset_rele(newnext_ds, FTAG); 2249745cd3c5Smaybee if (err) 2250745cd3c5Smaybee return (err); 225199653d4eSeschrock newnext_ds = prev; 225299653d4eSeschrock } 22531d452cf5Sahrens pa->newnext_obj = newnext_ds->ds_object; 225499653d4eSeschrock 22553cb34c60Sahrens /* compute origin's new unique space */ 2256745cd3c5Smaybee pa->unique = 0; 225799653d4eSeschrock while ((err = bplist_iterate(&newnext_ds->ds_deadlist, 225899653d4eSeschrock &itor, &bp)) == 0) { 22593cb34c60Sahrens if (bp.blk_birth > origin_ds->ds_phys->ds_prev_snap_txg) 2260745cd3c5Smaybee pa->unique += bp_get_dasize(dp->dp_spa, &bp); 226199653d4eSeschrock } 2262745cd3c5Smaybee if (newnext_ds != hds) 2263745cd3c5Smaybee dsl_dataset_rele(newnext_ds, FTAG); 226499653d4eSeschrock if (err != ENOENT) 2265745cd3c5Smaybee return (err); 226699653d4eSeschrock 226799653d4eSeschrock name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2268745cd3c5Smaybee 2269745cd3c5Smaybee /* 2270745cd3c5Smaybee * Walk the snapshots that we are moving 2271745cd3c5Smaybee * 2272745cd3c5Smaybee * Compute space to transfer. Each snapshot gave birth to: 2273745cd3c5Smaybee * (my used) - (prev's used) + (deadlist's used) 2274745cd3c5Smaybee * So a sequence would look like: 2275745cd3c5Smaybee * uN - u(N-1) + dN + ... + u1 - u0 + d1 + u0 - 0 + d0 2276745cd3c5Smaybee * Which simplifies to: 2277745cd3c5Smaybee * uN + dN + ... + d1 + d0 2278745cd3c5Smaybee * Note however, if we stop before we reach the ORIGIN we get: 2279745cd3c5Smaybee * uN + dN + ... + dM - uM-1 2280745cd3c5Smaybee */ 2281745cd3c5Smaybee pa->used = origin_ds->ds_phys->ds_used_bytes; 2282745cd3c5Smaybee pa->comp = origin_ds->ds_phys->ds_compressed_bytes; 2283745cd3c5Smaybee pa->uncomp = origin_ds->ds_phys->ds_uncompressed_bytes; 2284745cd3c5Smaybee do { 228599653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 2286745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 228799653d4eSeschrock 228899653d4eSeschrock /* Check that the snapshot name does not conflict */ 228999653d4eSeschrock dsl_dataset_name(ds, name); 2290745cd3c5Smaybee err = dsl_dataset_snap_lookup(hds, ds->ds_snapname, &val); 2291745cd3c5Smaybee if (err == 0) 2292745cd3c5Smaybee err = EEXIST; 2293745cd3c5Smaybee if (err != ENOENT) 229499653d4eSeschrock break; 2295745cd3c5Smaybee err = 0; 229699653d4eSeschrock 2297745cd3c5Smaybee /* The very first snapshot does not have a deadlist */ 2298745cd3c5Smaybee if (ds->ds_phys->ds_prev_snap_obj != 0) { 2299745cd3c5Smaybee if (err = bplist_space(&ds->ds_deadlist, 2300745cd3c5Smaybee &dlused, &dlcomp, &dluncomp)) 2301745cd3c5Smaybee break; 2302745cd3c5Smaybee pa->used += dlused; 2303745cd3c5Smaybee pa->comp += dlcomp; 2304745cd3c5Smaybee pa->uncomp += dluncomp; 230599653d4eSeschrock } 2306745cd3c5Smaybee } while (snap = list_next(&pa->snap_list, snap)); 2307745cd3c5Smaybee 2308745cd3c5Smaybee /* 2309745cd3c5Smaybee * If we are a clone of a clone then we never reached ORIGIN, 2310745cd3c5Smaybee * so we need to subtract out the clone origin's used space. 2311745cd3c5Smaybee */ 2312745cd3c5Smaybee if (pa->clone_origin) { 2313745cd3c5Smaybee pa->used -= pa->clone_origin->ds_phys->ds_used_bytes; 2314745cd3c5Smaybee pa->comp -= pa->clone_origin->ds_phys->ds_compressed_bytes; 2315745cd3c5Smaybee pa->uncomp -= pa->clone_origin->ds_phys->ds_uncompressed_bytes; 231699653d4eSeschrock } 231799653d4eSeschrock 2318745cd3c5Smaybee kmem_free(name, MAXPATHLEN); 2319745cd3c5Smaybee 232099653d4eSeschrock /* Check that there is enough space here */ 2321745cd3c5Smaybee if (err == 0) { 2322745cd3c5Smaybee dsl_dir_t *odd = origin_ds->ds_dir; 2323745cd3c5Smaybee err = dsl_dir_transfer_possible(odd, hds->ds_dir, pa->used); 2324745cd3c5Smaybee } 23251d452cf5Sahrens 23261d452cf5Sahrens return (err); 23271d452cf5Sahrens } 232899653d4eSeschrock 23291d452cf5Sahrens static void 2330ecd6cf80Smarks dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 23311d452cf5Sahrens { 23321d452cf5Sahrens dsl_dataset_t *hds = arg1; 23331d452cf5Sahrens struct promotearg *pa = arg2; 2334*088f3894Sahrens struct promotenode *snap = list_head(&pa->snap_list); 2335745cd3c5Smaybee dsl_dataset_t *origin_ds = snap->ds; 23361d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 23371d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 23383cb34c60Sahrens dsl_dir_t *odd = NULL; 23391d452cf5Sahrens char *name; 2340*088f3894Sahrens uint64_t oldnext_obj; 23411d452cf5Sahrens 23421d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 23431d452cf5Sahrens 23440b69c2f0Sahrens /* 23453cb34c60Sahrens * We need to explicitly open odd, since origin_ds's dd will be 23460b69c2f0Sahrens * changing. 23470b69c2f0Sahrens */ 23483cb34c60Sahrens VERIFY(0 == dsl_dir_open_obj(dp, origin_ds->ds_dir->dd_object, 23493cb34c60Sahrens NULL, FTAG, &odd)); 235099653d4eSeschrock 2351745cd3c5Smaybee /* change origin's next snap */ 2352745cd3c5Smaybee dmu_buf_will_dirty(origin_ds->ds_dbuf, tx); 2353*088f3894Sahrens oldnext_obj = origin_ds->ds_phys->ds_next_snap_obj; 2354745cd3c5Smaybee origin_ds->ds_phys->ds_next_snap_obj = pa->newnext_obj; 2355745cd3c5Smaybee 2356*088f3894Sahrens /* change the origin's next clone */ 2357*088f3894Sahrens if (origin_ds->ds_phys->ds_next_clones_obj) { 2358*088f3894Sahrens VERIFY3U(0, ==, zap_remove_int(dp->dp_meta_objset, 2359*088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2360*088f3894Sahrens pa->newnext_obj, tx)); 2361*088f3894Sahrens VERIFY3U(0, ==, zap_add_int(dp->dp_meta_objset, 2362*088f3894Sahrens origin_ds->ds_phys->ds_next_clones_obj, 2363*088f3894Sahrens oldnext_obj, tx)); 2364*088f3894Sahrens } 2365*088f3894Sahrens 2366745cd3c5Smaybee /* change origin */ 2367745cd3c5Smaybee dmu_buf_will_dirty(dd->dd_dbuf, tx); 2368745cd3c5Smaybee ASSERT3U(dd->dd_phys->dd_origin_obj, ==, origin_ds->ds_object); 2369745cd3c5Smaybee dd->dd_phys->dd_origin_obj = odd->dd_phys->dd_origin_obj; 2370745cd3c5Smaybee dmu_buf_will_dirty(odd->dd_dbuf, tx); 2371745cd3c5Smaybee odd->dd_phys->dd_origin_obj = origin_ds->ds_object; 2372745cd3c5Smaybee 237399653d4eSeschrock /* move snapshots to this dir */ 23741d452cf5Sahrens name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 2375745cd3c5Smaybee do { 2376745cd3c5Smaybee dsl_dataset_t *ds = snap->ds; 237799653d4eSeschrock 237899653d4eSeschrock /* move snap name entry */ 237999653d4eSeschrock dsl_dataset_name(ds, name); 2380745cd3c5Smaybee VERIFY(0 == dsl_dataset_snap_remove(pa->old_head, 2381745cd3c5Smaybee ds->ds_snapname, tx)); 23821d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 238399653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 238499653d4eSeschrock 8, 1, &ds->ds_object, tx)); 238599653d4eSeschrock 238699653d4eSeschrock /* change containing dsl_dir */ 238799653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 23883cb34c60Sahrens ASSERT3U(ds->ds_phys->ds_dir_obj, ==, odd->dd_object); 238999653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 23903cb34c60Sahrens ASSERT3P(ds->ds_dir, ==, odd); 239199653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 23921d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 239399653d4eSeschrock NULL, ds, &ds->ds_dir)); 239499653d4eSeschrock 239599653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 2396745cd3c5Smaybee } while (snap = list_next(&pa->snap_list, snap)); 239799653d4eSeschrock 239899653d4eSeschrock /* change space accounting */ 23993cb34c60Sahrens dsl_dir_diduse_space(odd, -pa->used, -pa->comp, -pa->uncomp, tx); 24001d452cf5Sahrens dsl_dir_diduse_space(dd, pa->used, pa->comp, pa->uncomp, tx); 24013cb34c60Sahrens origin_ds->ds_phys->ds_unique_bytes = pa->unique; 240299653d4eSeschrock 2403ecd6cf80Smarks /* log history record */ 2404ecd6cf80Smarks spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 2405745cd3c5Smaybee cr, "dataset = %llu", hds->ds_object); 2406ecd6cf80Smarks 24073cb34c60Sahrens dsl_dir_close(odd, FTAG); 24081d452cf5Sahrens kmem_free(name, MAXPATHLEN); 240999653d4eSeschrock } 241099653d4eSeschrock 241199653d4eSeschrock int 241299653d4eSeschrock dsl_dataset_promote(const char *name) 241399653d4eSeschrock { 241499653d4eSeschrock dsl_dataset_t *ds; 2415745cd3c5Smaybee dsl_dir_t *dd; 2416745cd3c5Smaybee dsl_pool_t *dp; 241799653d4eSeschrock dmu_object_info_t doi; 24181d452cf5Sahrens struct promotearg pa; 2419*088f3894Sahrens struct promotenode *snap; 2420745cd3c5Smaybee uint64_t snap_obj; 2421745cd3c5Smaybee uint64_t last_snap = 0; 2422745cd3c5Smaybee int err; 242399653d4eSeschrock 2424745cd3c5Smaybee err = dsl_dataset_hold(name, FTAG, &ds); 242599653d4eSeschrock if (err) 242699653d4eSeschrock return (err); 2427745cd3c5Smaybee dd = ds->ds_dir; 2428745cd3c5Smaybee dp = dd->dd_pool; 242999653d4eSeschrock 2430745cd3c5Smaybee err = dmu_object_info(dp->dp_meta_objset, 243199653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 243299653d4eSeschrock if (err) { 2433745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 243499653d4eSeschrock return (err); 243599653d4eSeschrock } 243699653d4eSeschrock 2437745cd3c5Smaybee /* 2438745cd3c5Smaybee * We are going to inherit all the snapshots taken before our 2439745cd3c5Smaybee * origin (i.e., our new origin will be our parent's origin). 2440745cd3c5Smaybee * Take ownership of them so that we can rename them into our 2441745cd3c5Smaybee * namespace. 2442745cd3c5Smaybee */ 2443745cd3c5Smaybee pa.clone_origin = NULL; 2444745cd3c5Smaybee list_create(&pa.snap_list, 2445*088f3894Sahrens sizeof (struct promotenode), offsetof(struct promotenode, link)); 2446745cd3c5Smaybee rw_enter(&dp->dp_config_rwlock, RW_READER); 2447745cd3c5Smaybee ASSERT(dd->dd_phys->dd_origin_obj != 0); 2448745cd3c5Smaybee snap_obj = dd->dd_phys->dd_origin_obj; 2449745cd3c5Smaybee while (snap_obj) { 2450*088f3894Sahrens dsl_dataset_t *snapds; 2451*088f3894Sahrens 2452*088f3894Sahrens /* 2453*088f3894Sahrens * NB: this would be handled by the below check for 2454*088f3894Sahrens * clone of a clone, but then we'd always own_obj() the 2455*088f3894Sahrens * $ORIGIN, thus causing unnecessary EBUSYs. We don't 2456*088f3894Sahrens * need to set pa.clone_origin because the $ORIGIN has 2457*088f3894Sahrens * no data to account for. 2458*088f3894Sahrens */ 2459*088f3894Sahrens if (dp->dp_origin_snap && 2460*088f3894Sahrens snap_obj == dp->dp_origin_snap->ds_object) 2461*088f3894Sahrens break; 2462*088f3894Sahrens 2463*088f3894Sahrens err = dsl_dataset_own_obj(dp, snap_obj, 0, FTAG, &snapds); 2464745cd3c5Smaybee if (err == ENOENT) { 2465745cd3c5Smaybee /* lost race with snapshot destroy */ 2466*088f3894Sahrens struct promotenode *last = list_tail(&pa.snap_list); 2467745cd3c5Smaybee ASSERT(snap_obj != last->ds->ds_phys->ds_prev_snap_obj); 2468745cd3c5Smaybee snap_obj = last->ds->ds_phys->ds_prev_snap_obj; 2469745cd3c5Smaybee continue; 2470745cd3c5Smaybee } else if (err) { 2471745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 2472745cd3c5Smaybee goto out; 2473745cd3c5Smaybee } 2474*088f3894Sahrens 2475745cd3c5Smaybee /* 2476745cd3c5Smaybee * We could be a clone of a clone. If we reach our 2477745cd3c5Smaybee * parent's branch point, we're done. 2478745cd3c5Smaybee */ 2479745cd3c5Smaybee if (last_snap && 2480*088f3894Sahrens snapds->ds_phys->ds_next_snap_obj != last_snap) { 2481*088f3894Sahrens pa.clone_origin = snapds; 2482*088f3894Sahrens break; 2483745cd3c5Smaybee } 2484*088f3894Sahrens 2485*088f3894Sahrens snap = kmem_alloc(sizeof (struct promotenode), KM_SLEEP); 2486*088f3894Sahrens snap->ds = snapds; 2487*088f3894Sahrens list_insert_tail(&pa.snap_list, snap); 2488*088f3894Sahrens last_snap = snap_obj; 2489*088f3894Sahrens snap_obj = snap->ds->ds_phys->ds_prev_snap_obj; 2490745cd3c5Smaybee } 2491745cd3c5Smaybee snap = list_head(&pa.snap_list); 2492745cd3c5Smaybee ASSERT(snap != NULL); 2493745cd3c5Smaybee err = dsl_dataset_hold_obj(dp, 2494745cd3c5Smaybee snap->ds->ds_dir->dd_phys->dd_head_dataset_obj, FTAG, &pa.old_head); 2495745cd3c5Smaybee rw_exit(&dp->dp_config_rwlock); 2496745cd3c5Smaybee 2497745cd3c5Smaybee if (err) 2498745cd3c5Smaybee goto out; 2499745cd3c5Smaybee 250099653d4eSeschrock /* 250199653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 250299653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 250399653d4eSeschrock * bonus buffers. 250499653d4eSeschrock */ 2505745cd3c5Smaybee err = dsl_sync_task_do(dp, dsl_dataset_promote_check, 25061d452cf5Sahrens dsl_dataset_promote_sync, ds, &pa, 2 + 2 * doi.doi_physical_blks); 2507745cd3c5Smaybee 2508745cd3c5Smaybee dsl_dataset_rele(pa.old_head, FTAG); 2509745cd3c5Smaybee out: 2510745cd3c5Smaybee while ((snap = list_tail(&pa.snap_list)) != NULL) { 2511745cd3c5Smaybee list_remove(&pa.snap_list, snap); 2512745cd3c5Smaybee dsl_dataset_disown(snap->ds, FTAG); 2513*088f3894Sahrens kmem_free(snap, sizeof (struct promotenode)); 2514745cd3c5Smaybee } 2515745cd3c5Smaybee list_destroy(&pa.snap_list); 2516745cd3c5Smaybee if (pa.clone_origin) 2517745cd3c5Smaybee dsl_dataset_disown(pa.clone_origin, FTAG); 2518745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 251999653d4eSeschrock return (err); 252099653d4eSeschrock } 2521b1b8ab34Slling 25223cb34c60Sahrens struct cloneswaparg { 25233cb34c60Sahrens dsl_dataset_t *cds; /* clone dataset */ 25243cb34c60Sahrens dsl_dataset_t *ohds; /* origin's head dataset */ 25253cb34c60Sahrens boolean_t force; 2526a9b821a0Sck int64_t unused_refres_delta; /* change in unconsumed refreservation */ 25273cb34c60Sahrens }; 2528f18faf3fSek 2529f18faf3fSek /* ARGSUSED */ 2530f18faf3fSek static int 2531f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 2532f18faf3fSek { 25333cb34c60Sahrens struct cloneswaparg *csa = arg1; 2534f18faf3fSek 25353cb34c60Sahrens /* they should both be heads */ 25363cb34c60Sahrens if (dsl_dataset_is_snapshot(csa->cds) || 25373cb34c60Sahrens dsl_dataset_is_snapshot(csa->ohds)) 2538f18faf3fSek return (EINVAL); 2539f18faf3fSek 25403cb34c60Sahrens /* the branch point should be just before them */ 25413cb34c60Sahrens if (csa->cds->ds_prev != csa->ohds->ds_prev) 2542f18faf3fSek return (EINVAL); 2543f18faf3fSek 25443cb34c60Sahrens /* cds should be the clone */ 25453cb34c60Sahrens if (csa->cds->ds_prev->ds_phys->ds_next_snap_obj != 25463cb34c60Sahrens csa->ohds->ds_object) 25473cb34c60Sahrens return (EINVAL); 2548f18faf3fSek 25493cb34c60Sahrens /* the clone should be a child of the origin */ 25503cb34c60Sahrens if (csa->cds->ds_dir->dd_parent != csa->ohds->ds_dir) 25513cb34c60Sahrens return (EINVAL); 2552f18faf3fSek 25533cb34c60Sahrens /* ohds shouldn't be modified unless 'force' */ 25543cb34c60Sahrens if (!csa->force && dsl_dataset_modified_since_lastsnap(csa->ohds)) 25553cb34c60Sahrens return (ETXTBSY); 2556a9b821a0Sck 2557a9b821a0Sck /* adjust amount of any unconsumed refreservation */ 2558a9b821a0Sck csa->unused_refres_delta = 2559a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 2560a9b821a0Sck csa->ohds->ds_phys->ds_unique_bytes) - 2561a9b821a0Sck (int64_t)MIN(csa->ohds->ds_reserved, 2562a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 2563a9b821a0Sck 2564a9b821a0Sck if (csa->unused_refres_delta > 0 && 2565a9b821a0Sck csa->unused_refres_delta > 2566a9b821a0Sck dsl_dir_space_available(csa->ohds->ds_dir, NULL, 0, TRUE)) 2567a9b821a0Sck return (ENOSPC); 2568a9b821a0Sck 25693cb34c60Sahrens return (0); 2570f18faf3fSek } 2571f18faf3fSek 2572f18faf3fSek /* ARGSUSED */ 2573f18faf3fSek static void 2574f18faf3fSek dsl_dataset_clone_swap_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 2575f18faf3fSek { 25763cb34c60Sahrens struct cloneswaparg *csa = arg1; 25773cb34c60Sahrens dsl_pool_t *dp = csa->cds->ds_dir->dd_pool; 2578f18faf3fSek uint64_t itor = 0; 2579f18faf3fSek blkptr_t bp; 2580f18faf3fSek uint64_t unique = 0; 2581f18faf3fSek int err; 2582f18faf3fSek 2583a9b821a0Sck ASSERT(csa->cds->ds_reserved == 0); 2584a9b821a0Sck ASSERT(csa->cds->ds_quota == csa->ohds->ds_quota); 2585a9b821a0Sck 25863cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_dbuf, tx); 25873cb34c60Sahrens dmu_buf_will_dirty(csa->ohds->ds_dbuf, tx); 25883cb34c60Sahrens dmu_buf_will_dirty(csa->cds->ds_prev->ds_dbuf, tx); 2589f18faf3fSek 25903cb34c60Sahrens if (csa->cds->ds_user_ptr != NULL) { 25913cb34c60Sahrens csa->cds->ds_user_evict_func(csa->cds, csa->cds->ds_user_ptr); 25923cb34c60Sahrens csa->cds->ds_user_ptr = NULL; 25933cb34c60Sahrens } 2594f18faf3fSek 25953cb34c60Sahrens if (csa->ohds->ds_user_ptr != NULL) { 25963cb34c60Sahrens csa->ohds->ds_user_evict_func(csa->ohds, 25973cb34c60Sahrens csa->ohds->ds_user_ptr); 25983cb34c60Sahrens csa->ohds->ds_user_ptr = NULL; 25993cb34c60Sahrens } 2600f18faf3fSek 2601f18faf3fSek /* compute unique space */ 26023cb34c60Sahrens while ((err = bplist_iterate(&csa->cds->ds_deadlist, 26033cb34c60Sahrens &itor, &bp)) == 0) { 26043cb34c60Sahrens if (bp.blk_birth > csa->cds->ds_prev->ds_phys->ds_prev_snap_txg) 26053cb34c60Sahrens unique += bp_get_dasize(dp->dp_spa, &bp); 2606f18faf3fSek } 2607f18faf3fSek VERIFY(err == ENOENT); 2608f18faf3fSek 2609f18faf3fSek /* reset origin's unique bytes */ 26103cb34c60Sahrens csa->cds->ds_prev->ds_phys->ds_unique_bytes = unique; 2611f18faf3fSek 2612f18faf3fSek /* swap blkptrs */ 2613f18faf3fSek { 2614f18faf3fSek blkptr_t tmp; 26153cb34c60Sahrens tmp = csa->ohds->ds_phys->ds_bp; 26163cb34c60Sahrens csa->ohds->ds_phys->ds_bp = csa->cds->ds_phys->ds_bp; 26173cb34c60Sahrens csa->cds->ds_phys->ds_bp = tmp; 2618f18faf3fSek } 2619f18faf3fSek 2620f18faf3fSek /* set dd_*_bytes */ 2621f18faf3fSek { 2622f18faf3fSek int64_t dused, dcomp, duncomp; 2623f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 2624f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 2625f18faf3fSek 26263cb34c60Sahrens VERIFY(0 == bplist_space(&csa->cds->ds_deadlist, &cdl_used, 2627f18faf3fSek &cdl_comp, &cdl_uncomp)); 26283cb34c60Sahrens VERIFY(0 == bplist_space(&csa->ohds->ds_deadlist, &odl_used, 2629f18faf3fSek &odl_comp, &odl_uncomp)); 26303cb34c60Sahrens dused = csa->cds->ds_phys->ds_used_bytes + cdl_used - 26313cb34c60Sahrens (csa->ohds->ds_phys->ds_used_bytes + odl_used); 26323cb34c60Sahrens dcomp = csa->cds->ds_phys->ds_compressed_bytes + cdl_comp - 26333cb34c60Sahrens (csa->ohds->ds_phys->ds_compressed_bytes + odl_comp); 26343cb34c60Sahrens duncomp = csa->cds->ds_phys->ds_uncompressed_bytes + 26353cb34c60Sahrens cdl_uncomp - 26363cb34c60Sahrens (csa->ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 26373cb34c60Sahrens 26383cb34c60Sahrens dsl_dir_diduse_space(csa->ohds->ds_dir, 26393cb34c60Sahrens dused, dcomp, duncomp, tx); 26403cb34c60Sahrens dsl_dir_diduse_space(csa->cds->ds_dir, 26413cb34c60Sahrens -dused, -dcomp, -duncomp, tx); 26423cb34c60Sahrens } 26433cb34c60Sahrens 26443cb34c60Sahrens #define SWITCH64(x, y) \ 26453cb34c60Sahrens { \ 26463cb34c60Sahrens uint64_t __tmp = (x); \ 26473cb34c60Sahrens (x) = (y); \ 26483cb34c60Sahrens (y) = __tmp; \ 2649f18faf3fSek } 2650f18faf3fSek 2651f18faf3fSek /* swap ds_*_bytes */ 26523cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_used_bytes, 26533cb34c60Sahrens csa->cds->ds_phys->ds_used_bytes); 26543cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_compressed_bytes, 26553cb34c60Sahrens csa->cds->ds_phys->ds_compressed_bytes); 26563cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_uncompressed_bytes, 26573cb34c60Sahrens csa->cds->ds_phys->ds_uncompressed_bytes); 2658a9b821a0Sck SWITCH64(csa->ohds->ds_phys->ds_unique_bytes, 2659a9b821a0Sck csa->cds->ds_phys->ds_unique_bytes); 2660a9b821a0Sck 2661a9b821a0Sck /* apply any parent delta for change in unconsumed refreservation */ 2662a9b821a0Sck dsl_dir_diduse_space(csa->ohds->ds_dir, csa->unused_refres_delta, 2663a9b821a0Sck 0, 0, tx); 2664f18faf3fSek 2665f18faf3fSek /* swap deadlists */ 26663cb34c60Sahrens bplist_close(&csa->cds->ds_deadlist); 26673cb34c60Sahrens bplist_close(&csa->ohds->ds_deadlist); 26683cb34c60Sahrens SWITCH64(csa->ohds->ds_phys->ds_deadlist_obj, 26693cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj); 26703cb34c60Sahrens VERIFY(0 == bplist_open(&csa->cds->ds_deadlist, dp->dp_meta_objset, 26713cb34c60Sahrens csa->cds->ds_phys->ds_deadlist_obj)); 26723cb34c60Sahrens VERIFY(0 == bplist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset, 26733cb34c60Sahrens csa->ohds->ds_phys->ds_deadlist_obj)); 2674f18faf3fSek } 2675f18faf3fSek 2676f18faf3fSek /* 2677745cd3c5Smaybee * Swap 'clone' with its origin head file system. Used at the end 2678745cd3c5Smaybee * of "online recv" to swizzle the file system to the new version. 2679f18faf3fSek */ 2680f18faf3fSek int 26813cb34c60Sahrens dsl_dataset_clone_swap(dsl_dataset_t *clone, dsl_dataset_t *origin_head, 26823cb34c60Sahrens boolean_t force) 2683f18faf3fSek { 26843cb34c60Sahrens struct cloneswaparg csa; 2685745cd3c5Smaybee int error; 2686f18faf3fSek 2687745cd3c5Smaybee ASSERT(clone->ds_owner); 2688745cd3c5Smaybee ASSERT(origin_head->ds_owner); 2689745cd3c5Smaybee retry: 2690745cd3c5Smaybee /* Need exclusive access for the swap */ 2691745cd3c5Smaybee rw_enter(&clone->ds_rwlock, RW_WRITER); 2692745cd3c5Smaybee if (!rw_tryenter(&origin_head->ds_rwlock, RW_WRITER)) { 2693745cd3c5Smaybee rw_exit(&clone->ds_rwlock); 2694745cd3c5Smaybee rw_enter(&origin_head->ds_rwlock, RW_WRITER); 2695745cd3c5Smaybee if (!rw_tryenter(&clone->ds_rwlock, RW_WRITER)) { 2696745cd3c5Smaybee rw_exit(&origin_head->ds_rwlock); 2697745cd3c5Smaybee goto retry; 2698745cd3c5Smaybee } 2699745cd3c5Smaybee } 27003cb34c60Sahrens csa.cds = clone; 27013cb34c60Sahrens csa.ohds = origin_head; 27023cb34c60Sahrens csa.force = force; 2703745cd3c5Smaybee error = dsl_sync_task_do(clone->ds_dir->dd_pool, 2704f18faf3fSek dsl_dataset_clone_swap_check, 2705745cd3c5Smaybee dsl_dataset_clone_swap_sync, &csa, NULL, 9); 2706745cd3c5Smaybee return (error); 2707f18faf3fSek } 2708f18faf3fSek 2709b1b8ab34Slling /* 2710b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 2711b1b8ab34Slling * return the name of that dataset. 2712b1b8ab34Slling */ 2713b1b8ab34Slling int 2714b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 2715b1b8ab34Slling { 2716b1b8ab34Slling spa_t *spa; 2717b1b8ab34Slling dsl_pool_t *dp; 2718745cd3c5Smaybee dsl_dataset_t *ds; 2719b1b8ab34Slling int error; 2720b1b8ab34Slling 2721b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 2722b1b8ab34Slling return (error); 2723b1b8ab34Slling dp = spa_get_dsl(spa); 2724b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 2725745cd3c5Smaybee if ((error = dsl_dataset_hold_obj(dp, obj, FTAG, &ds)) == 0) { 2726745cd3c5Smaybee dsl_dataset_name(ds, buf); 2727745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2728b1b8ab34Slling } 2729b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 2730b1b8ab34Slling spa_close(spa, FTAG); 2731b1b8ab34Slling 2732745cd3c5Smaybee return (error); 2733b1b8ab34Slling } 2734a9799022Sck 2735a9799022Sck int 2736a9799022Sck dsl_dataset_check_quota(dsl_dataset_t *ds, boolean_t check_quota, 2737745cd3c5Smaybee uint64_t asize, uint64_t inflight, uint64_t *used, uint64_t *ref_rsrv) 2738a9799022Sck { 2739a9799022Sck int error = 0; 2740a9799022Sck 2741a9799022Sck ASSERT3S(asize, >, 0); 2742a9799022Sck 27439082849eSck /* 27449082849eSck * *ref_rsrv is the portion of asize that will come from any 27459082849eSck * unconsumed refreservation space. 27469082849eSck */ 27479082849eSck *ref_rsrv = 0; 27489082849eSck 2749a9799022Sck mutex_enter(&ds->ds_lock); 2750a9799022Sck /* 2751a9799022Sck * Make a space adjustment for reserved bytes. 2752a9799022Sck */ 2753a9799022Sck if (ds->ds_reserved > ds->ds_phys->ds_unique_bytes) { 2754a9799022Sck ASSERT3U(*used, >=, 2755a9799022Sck ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 2756a9799022Sck *used -= (ds->ds_reserved - ds->ds_phys->ds_unique_bytes); 27579082849eSck *ref_rsrv = 27589082849eSck asize - MIN(asize, parent_delta(ds, asize + inflight)); 2759a9799022Sck } 2760a9799022Sck 2761a9799022Sck if (!check_quota || ds->ds_quota == 0) { 2762a9799022Sck mutex_exit(&ds->ds_lock); 2763a9799022Sck return (0); 2764a9799022Sck } 2765a9799022Sck /* 2766a9799022Sck * If they are requesting more space, and our current estimate 2767a9799022Sck * is over quota, they get to try again unless the actual 2768a9799022Sck * on-disk is over quota and there are no pending changes (which 2769a9799022Sck * may free up space for us). 2770a9799022Sck */ 2771a9799022Sck if (ds->ds_phys->ds_used_bytes + inflight >= ds->ds_quota) { 2772a9799022Sck if (inflight > 0 || ds->ds_phys->ds_used_bytes < ds->ds_quota) 2773a9799022Sck error = ERESTART; 2774a9799022Sck else 2775a9799022Sck error = EDQUOT; 2776a9799022Sck } 2777a9799022Sck mutex_exit(&ds->ds_lock); 2778a9799022Sck 2779a9799022Sck return (error); 2780a9799022Sck } 2781a9799022Sck 2782a9799022Sck /* ARGSUSED */ 2783a9799022Sck static int 2784a9799022Sck dsl_dataset_set_quota_check(void *arg1, void *arg2, dmu_tx_t *tx) 2785a9799022Sck { 2786a9799022Sck dsl_dataset_t *ds = arg1; 2787a9799022Sck uint64_t *quotap = arg2; 2788a9799022Sck uint64_t new_quota = *quotap; 2789a9799022Sck 2790a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_REFQUOTA) 2791a9799022Sck return (ENOTSUP); 2792a9799022Sck 2793a9799022Sck if (new_quota == 0) 2794a9799022Sck return (0); 2795a9799022Sck 2796a9799022Sck if (new_quota < ds->ds_phys->ds_used_bytes || 2797a9799022Sck new_quota < ds->ds_reserved) 2798a9799022Sck return (ENOSPC); 2799a9799022Sck 2800a9799022Sck return (0); 2801a9799022Sck } 2802a9799022Sck 2803a9799022Sck /* ARGSUSED */ 2804a9799022Sck void 2805a9799022Sck dsl_dataset_set_quota_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 2806a9799022Sck { 2807a9799022Sck dsl_dataset_t *ds = arg1; 2808a9799022Sck uint64_t *quotap = arg2; 2809a9799022Sck uint64_t new_quota = *quotap; 2810a9799022Sck 2811a9799022Sck dmu_buf_will_dirty(ds->ds_dbuf, tx); 2812a9799022Sck 2813a9799022Sck ds->ds_quota = new_quota; 2814a9799022Sck 2815a9799022Sck dsl_prop_set_uint64_sync(ds->ds_dir, "refquota", new_quota, cr, tx); 2816a9799022Sck 2817a9799022Sck spa_history_internal_log(LOG_DS_REFQUOTA, ds->ds_dir->dd_pool->dp_spa, 2818a9799022Sck tx, cr, "%lld dataset = %llu ", 2819745cd3c5Smaybee (longlong_t)new_quota, ds->ds_object); 2820a9799022Sck } 2821a9799022Sck 2822a9799022Sck int 2823a9799022Sck dsl_dataset_set_quota(const char *dsname, uint64_t quota) 2824a9799022Sck { 2825a9799022Sck dsl_dataset_t *ds; 2826a9799022Sck int err; 2827a9799022Sck 2828745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 2829a9799022Sck if (err) 2830a9799022Sck return (err); 2831a9799022Sck 2832a9b821a0Sck if (quota != ds->ds_quota) { 2833a9b821a0Sck /* 2834a9b821a0Sck * If someone removes a file, then tries to set the quota, we 2835a9b821a0Sck * want to make sure the file freeing takes effect. 2836a9b821a0Sck */ 2837a9b821a0Sck txg_wait_open(ds->ds_dir->dd_pool, 0); 2838a9799022Sck 2839a9b821a0Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2840a9b821a0Sck dsl_dataset_set_quota_check, dsl_dataset_set_quota_sync, 2841a9b821a0Sck ds, "a, 0); 2842a9b821a0Sck } 2843745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2844a9799022Sck return (err); 2845a9799022Sck } 2846a9799022Sck 2847a9799022Sck static int 2848a9799022Sck dsl_dataset_set_reservation_check(void *arg1, void *arg2, dmu_tx_t *tx) 2849a9799022Sck { 2850a9799022Sck dsl_dataset_t *ds = arg1; 2851a9799022Sck uint64_t *reservationp = arg2; 2852a9799022Sck uint64_t new_reservation = *reservationp; 2853a9799022Sck int64_t delta; 2854a9799022Sck uint64_t unique; 2855a9799022Sck 2856a9799022Sck if (new_reservation > INT64_MAX) 2857a9799022Sck return (EOVERFLOW); 2858a9799022Sck 2859a9799022Sck if (spa_version(ds->ds_dir->dd_pool->dp_spa) < 2860a9799022Sck SPA_VERSION_REFRESERVATION) 2861a9799022Sck return (ENOTSUP); 2862a9799022Sck 2863a9799022Sck if (dsl_dataset_is_snapshot(ds)) 2864a9799022Sck return (EINVAL); 2865a9799022Sck 2866a9799022Sck /* 2867a9799022Sck * If we are doing the preliminary check in open context, the 2868a9799022Sck * space estimates may be inaccurate. 2869a9799022Sck */ 2870a9799022Sck if (!dmu_tx_is_syncing(tx)) 2871a9799022Sck return (0); 2872a9799022Sck 2873a9799022Sck mutex_enter(&ds->ds_lock); 2874a9799022Sck unique = dsl_dataset_unique(ds); 2875a9799022Sck delta = MAX(unique, new_reservation) - MAX(unique, ds->ds_reserved); 2876a9799022Sck mutex_exit(&ds->ds_lock); 2877a9799022Sck 2878a9799022Sck if (delta > 0 && 2879a9799022Sck delta > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE)) 2880a9799022Sck return (ENOSPC); 2881a9799022Sck if (delta > 0 && ds->ds_quota > 0 && 2882a9799022Sck new_reservation > ds->ds_quota) 2883a9799022Sck return (ENOSPC); 2884a9799022Sck 2885a9799022Sck return (0); 2886a9799022Sck } 2887a9799022Sck 2888a9799022Sck /* ARGSUSED */ 2889a9799022Sck static void 2890a9799022Sck dsl_dataset_set_reservation_sync(void *arg1, void *arg2, cred_t *cr, 2891a9799022Sck dmu_tx_t *tx) 2892a9799022Sck { 2893a9799022Sck dsl_dataset_t *ds = arg1; 2894a9799022Sck uint64_t *reservationp = arg2; 2895a9799022Sck uint64_t new_reservation = *reservationp; 2896a9799022Sck uint64_t unique; 2897a9799022Sck int64_t delta; 2898a9799022Sck 2899a9799022Sck dmu_buf_will_dirty(ds->ds_dbuf, tx); 2900a9799022Sck 2901a9799022Sck mutex_enter(&ds->ds_lock); 2902a9799022Sck unique = dsl_dataset_unique(ds); 2903a9799022Sck delta = MAX(0, (int64_t)(new_reservation - unique)) - 2904a9799022Sck MAX(0, (int64_t)(ds->ds_reserved - unique)); 2905a9799022Sck ds->ds_reserved = new_reservation; 2906a9799022Sck mutex_exit(&ds->ds_lock); 2907a9799022Sck 2908a9799022Sck dsl_prop_set_uint64_sync(ds->ds_dir, "refreservation", 2909a9799022Sck new_reservation, cr, tx); 2910a9799022Sck 2911a9799022Sck dsl_dir_diduse_space(ds->ds_dir, delta, 0, 0, tx); 2912a9799022Sck 2913a9799022Sck spa_history_internal_log(LOG_DS_REFRESERV, 2914a9799022Sck ds->ds_dir->dd_pool->dp_spa, tx, cr, "%lld dataset = %llu", 2915a9799022Sck (longlong_t)new_reservation, 2916a9799022Sck ds->ds_dir->dd_phys->dd_head_dataset_obj); 2917a9799022Sck } 2918a9799022Sck 2919a9799022Sck int 2920a9799022Sck dsl_dataset_set_reservation(const char *dsname, uint64_t reservation) 2921a9799022Sck { 2922a9799022Sck dsl_dataset_t *ds; 2923a9799022Sck int err; 2924a9799022Sck 2925745cd3c5Smaybee err = dsl_dataset_hold(dsname, FTAG, &ds); 2926a9799022Sck if (err) 2927a9799022Sck return (err); 2928a9799022Sck 2929a9799022Sck err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2930a9799022Sck dsl_dataset_set_reservation_check, 2931a9799022Sck dsl_dataset_set_reservation_sync, ds, &reservation, 0); 2932745cd3c5Smaybee dsl_dataset_rele(ds, FTAG); 2933a9799022Sck return (err); 2934a9799022Sck } 2935