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 /* 2255434c77Sek * Copyright 2007 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> 42ecd6cf80Smarks #include <sys/sunddi.h> 43fa9e4066Sahrens 441d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 451d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 461d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_rollback_check; 471d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_rollback_sync; 481d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_check; 491d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_sync; 50e1930233Sbonwick 5155434c77Sek #define DS_REF_MAX (1ULL << 62) 52fa9e4066Sahrens 53fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 54fa9e4066Sahrens 55fa9e4066Sahrens /* 56fa9e4066Sahrens * We use weighted reference counts to express the various forms of exclusion 57fa9e4066Sahrens * between different open modes. A STANDARD open is 1 point, an EXCLUSIVE open 5855434c77Sek * is DS_REF_MAX, and a PRIMARY open is little more than half of an EXCLUSIVE. 59fa9e4066Sahrens * This makes the exclusion logic simple: the total refcnt for all opens cannot 6055434c77Sek * exceed DS_REF_MAX. For example, EXCLUSIVE opens are exclusive because their 6155434c77Sek * weight (DS_REF_MAX) consumes the entire refcnt space. PRIMARY opens consume 62fa9e4066Sahrens * just over half of the refcnt space, so there can't be more than one, but it 63fa9e4066Sahrens * can peacefully coexist with any number of STANDARD opens. 64fa9e4066Sahrens */ 65fa9e4066Sahrens static uint64_t ds_refcnt_weight[DS_MODE_LEVELS] = { 6655434c77Sek 0, /* DS_MODE_NONE - invalid */ 6755434c77Sek 1, /* DS_MODE_STANDARD - unlimited number */ 6855434c77Sek (DS_REF_MAX >> 1) + 1, /* DS_MODE_PRIMARY - only one of these */ 6955434c77Sek DS_REF_MAX /* DS_MODE_EXCLUSIVE - no other opens */ 70fa9e4066Sahrens }; 71fa9e4066Sahrens 72fa9e4066Sahrens 73fa9e4066Sahrens void 74fa9e4066Sahrens dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 75fa9e4066Sahrens { 7699653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 77fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 78fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 79fa9e4066Sahrens 80fa9e4066Sahrens dprintf_bp(bp, "born, ds=%p\n", ds); 81fa9e4066Sahrens 82fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 83fa9e4066Sahrens /* It could have been compressed away to nothing */ 84fa9e4066Sahrens if (BP_IS_HOLE(bp)) 85fa9e4066Sahrens return; 86fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 87fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 88fa9e4066Sahrens if (ds == NULL) { 89fa9e4066Sahrens /* 90fa9e4066Sahrens * Account for the meta-objset space in its placeholder 91fa9e4066Sahrens * dsl_dir. 92fa9e4066Sahrens */ 93fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 94fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 95fa9e4066Sahrens used, compressed, uncompressed, tx); 96fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 97fa9e4066Sahrens return; 98fa9e4066Sahrens } 99fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 100fa9e4066Sahrens mutex_enter(&ds->ds_lock); 101fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 102fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 103fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 104fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 105fa9e4066Sahrens mutex_exit(&ds->ds_lock); 106fa9e4066Sahrens dsl_dir_diduse_space(ds->ds_dir, 107fa9e4066Sahrens used, compressed, uncompressed, tx); 108fa9e4066Sahrens } 109fa9e4066Sahrens 110fa9e4066Sahrens void 111c717a561Smaybee dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, zio_t *pio, 112c717a561Smaybee dmu_tx_t *tx) 113fa9e4066Sahrens { 11499653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 115fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 116fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 117fa9e4066Sahrens 118fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 119c717a561Smaybee /* No block pointer => nothing to free */ 120fa9e4066Sahrens if (BP_IS_HOLE(bp)) 121fa9e4066Sahrens return; 122fa9e4066Sahrens 123fa9e4066Sahrens ASSERT(used > 0); 124fa9e4066Sahrens if (ds == NULL) { 125c717a561Smaybee int err; 126fa9e4066Sahrens /* 127fa9e4066Sahrens * Account for the meta-objset space in its placeholder 128fa9e4066Sahrens * dataset. 129fa9e4066Sahrens */ 130c717a561Smaybee err = arc_free(pio, tx->tx_pool->dp_spa, 131c717a561Smaybee tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); 132c717a561Smaybee ASSERT(err == 0); 133fa9e4066Sahrens 134fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 135fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 136fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 137fa9e4066Sahrens return; 138fa9e4066Sahrens } 139fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 140fa9e4066Sahrens 141fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 142fa9e4066Sahrens 143fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 144c717a561Smaybee int err; 145c717a561Smaybee 146fa9e4066Sahrens dprintf_bp(bp, "freeing: %s", ""); 147c717a561Smaybee err = arc_free(pio, tx->tx_pool->dp_spa, 148c717a561Smaybee tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); 149c717a561Smaybee ASSERT(err == 0); 150fa9e4066Sahrens 151fa9e4066Sahrens mutex_enter(&ds->ds_lock); 152fa9e4066Sahrens /* XXX unique_bytes is not accurate for head datasets */ 153fa9e4066Sahrens /* ASSERT3U(ds->ds_phys->ds_unique_bytes, >=, used); */ 154fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 155fa9e4066Sahrens mutex_exit(&ds->ds_lock); 156fa9e4066Sahrens dsl_dir_diduse_space(ds->ds_dir, 157fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 158fa9e4066Sahrens } else { 159fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 160ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 161fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 162fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 163fa9e4066Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, 164fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj); 165fa9e4066Sahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 166fa9e4066Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 16799653d4eSeschrock ds->ds_object && bp->blk_birth > 168fa9e4066Sahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 169fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 170fa9e4066Sahrens mutex_enter(&ds->ds_prev->ds_lock); 171fa9e4066Sahrens ds->ds_prev->ds_phys->ds_unique_bytes += 172fa9e4066Sahrens used; 173fa9e4066Sahrens mutex_exit(&ds->ds_prev->ds_lock); 174fa9e4066Sahrens } 175fa9e4066Sahrens } 176fa9e4066Sahrens } 177fa9e4066Sahrens mutex_enter(&ds->ds_lock); 178fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 179fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 180fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 181fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 182fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 183fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 184fa9e4066Sahrens mutex_exit(&ds->ds_lock); 185fa9e4066Sahrens } 186fa9e4066Sahrens 187ea8dc4b6Seschrock uint64_t 188ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 189fa9e4066Sahrens { 190a2eea2e1Sahrens uint64_t trysnap = 0; 191a2eea2e1Sahrens 192fa9e4066Sahrens if (ds == NULL) 193ea8dc4b6Seschrock return (0); 194fa9e4066Sahrens /* 195fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 196fa9e4066Sahrens * incorrect FALSE return, which would only result in an 197fa9e4066Sahrens * overestimation of the amount of space that an operation would 198fa9e4066Sahrens * consume, which is OK. 199fa9e4066Sahrens * 200fa9e4066Sahrens * There's also a small window where we could miss a pending 201fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 202fa9e4066Sahrens * phase. So this should only be used as a guess. 203fa9e4066Sahrens */ 204a2eea2e1Sahrens if (ds->ds_trysnap_txg > 205a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 206a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 207a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 208ea8dc4b6Seschrock } 209ea8dc4b6Seschrock 210ea8dc4b6Seschrock int 211ea8dc4b6Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 212ea8dc4b6Seschrock { 213ea8dc4b6Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 214fa9e4066Sahrens } 215fa9e4066Sahrens 216fa9e4066Sahrens /* ARGSUSED */ 217fa9e4066Sahrens static void 218fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 219fa9e4066Sahrens { 220fa9e4066Sahrens dsl_dataset_t *ds = dsv; 221fa9e4066Sahrens 22255434c77Sek /* open_refcount == DS_REF_MAX when deleting */ 223fa9e4066Sahrens ASSERT(ds->ds_open_refcount == 0 || 22455434c77Sek ds->ds_open_refcount == DS_REF_MAX); 225fa9e4066Sahrens 226fa9e4066Sahrens dprintf_ds(ds, "evicting %s\n", ""); 227fa9e4066Sahrens 22891ebeef5Sahrens unique_remove(ds->ds_fsid_guid); 229fa9e4066Sahrens 230fa9e4066Sahrens if (ds->ds_user_ptr != NULL) 231fa9e4066Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 232fa9e4066Sahrens 233fa9e4066Sahrens if (ds->ds_prev) { 234fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 235fa9e4066Sahrens ds->ds_prev = NULL; 236fa9e4066Sahrens } 237fa9e4066Sahrens 238fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 239fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 240fa9e4066Sahrens 24191ebeef5Sahrens ASSERT(!list_link_active(&ds->ds_synced_link)); 242fa9e4066Sahrens 2435ad82045Snd mutex_destroy(&ds->ds_lock); 24491ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 2455ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 2465ad82045Snd 247fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 248fa9e4066Sahrens } 249fa9e4066Sahrens 250ea8dc4b6Seschrock static int 251fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 252fa9e4066Sahrens { 253fa9e4066Sahrens dsl_dataset_phys_t *headphys; 254fa9e4066Sahrens int err; 255fa9e4066Sahrens dmu_buf_t *headdbuf; 256fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 257fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 258fa9e4066Sahrens 259fa9e4066Sahrens if (ds->ds_snapname[0]) 260ea8dc4b6Seschrock return (0); 261fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 262ea8dc4b6Seschrock return (0); 263fa9e4066Sahrens 264ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 265ea8dc4b6Seschrock FTAG, &headdbuf); 266ea8dc4b6Seschrock if (err) 267ea8dc4b6Seschrock return (err); 268fa9e4066Sahrens headphys = headdbuf->db_data; 269fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 270e7437265Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); 271ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 272ea8dc4b6Seschrock return (err); 273fa9e4066Sahrens } 274fa9e4066Sahrens 275ea8dc4b6Seschrock int 276fa9e4066Sahrens dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname, 277ea8dc4b6Seschrock int mode, void *tag, dsl_dataset_t **dsp) 278fa9e4066Sahrens { 279fa9e4066Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 280fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 281fa9e4066Sahrens dmu_buf_t *dbuf; 282fa9e4066Sahrens dsl_dataset_t *ds; 283ea8dc4b6Seschrock int err; 284fa9e4066Sahrens 285fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 286fa9e4066Sahrens dsl_pool_sync_context(dp)); 287fa9e4066Sahrens 288ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 289ea8dc4b6Seschrock if (err) 290ea8dc4b6Seschrock return (err); 291fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 292fa9e4066Sahrens if (ds == NULL) { 293fa9e4066Sahrens dsl_dataset_t *winner; 294fa9e4066Sahrens 295fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 296fa9e4066Sahrens ds->ds_dbuf = dbuf; 297fa9e4066Sahrens ds->ds_object = dsobj; 298fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 299fa9e4066Sahrens 3005ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 30191ebeef5Sahrens mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL); 3025ad82045Snd mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT, 3035ad82045Snd NULL); 3045ad82045Snd 305ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 306fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 307ea8dc4b6Seschrock if (err == 0) { 308ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 309ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 310ea8dc4b6Seschrock } 311ea8dc4b6Seschrock if (err) { 312ea8dc4b6Seschrock /* 313ea8dc4b6Seschrock * we don't really need to close the blist if we 314ea8dc4b6Seschrock * just opened it. 315ea8dc4b6Seschrock */ 3165ad82045Snd mutex_destroy(&ds->ds_lock); 31791ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 3185ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 319ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 320ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 321ea8dc4b6Seschrock return (err); 322ea8dc4b6Seschrock } 323fa9e4066Sahrens 324fa9e4066Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == dsobj) { 325fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 326fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 327ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, 328fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 329ea8dc4b6Seschrock DS_MODE_NONE, ds, &ds->ds_prev); 330fa9e4066Sahrens } 331fa9e4066Sahrens } else { 332fa9e4066Sahrens if (snapname) { 333fa9e4066Sahrens #ifdef ZFS_DEBUG 334fa9e4066Sahrens dsl_dataset_phys_t *headphys; 335ea8dc4b6Seschrock dmu_buf_t *headdbuf; 336ea8dc4b6Seschrock err = dmu_bonus_hold(mos, 337ea8dc4b6Seschrock ds->ds_dir->dd_phys->dd_head_dataset_obj, 338ea8dc4b6Seschrock FTAG, &headdbuf); 339ea8dc4b6Seschrock if (err == 0) { 340ea8dc4b6Seschrock headphys = headdbuf->db_data; 341ea8dc4b6Seschrock uint64_t foundobj; 342ea8dc4b6Seschrock err = zap_lookup(dp->dp_meta_objset, 343ea8dc4b6Seschrock headphys->ds_snapnames_zapobj, 344ea8dc4b6Seschrock snapname, sizeof (foundobj), 1, 345ea8dc4b6Seschrock &foundobj); 346ea8dc4b6Seschrock ASSERT3U(foundobj, ==, dsobj); 347ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 348ea8dc4b6Seschrock } 349fa9e4066Sahrens #endif 350fa9e4066Sahrens (void) strcat(ds->ds_snapname, snapname); 351fa9e4066Sahrens } else if (zfs_flags & ZFS_DEBUG_SNAPNAMES) { 352ea8dc4b6Seschrock err = dsl_dataset_get_snapname(ds); 353fa9e4066Sahrens } 354fa9e4066Sahrens } 355fa9e4066Sahrens 356ea8dc4b6Seschrock if (err == 0) { 357ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 358ea8dc4b6Seschrock dsl_dataset_evict); 359ea8dc4b6Seschrock } 360ea8dc4b6Seschrock if (err || winner) { 361fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 362fa9e4066Sahrens if (ds->ds_prev) { 363fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, 364fa9e4066Sahrens DS_MODE_NONE, ds); 365fa9e4066Sahrens } 366fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 3675ad82045Snd mutex_destroy(&ds->ds_lock); 36891ebeef5Sahrens mutex_destroy(&ds->ds_opening_lock); 3695ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 370fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 371ea8dc4b6Seschrock if (err) { 372ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 373ea8dc4b6Seschrock return (err); 374ea8dc4b6Seschrock } 375fa9e4066Sahrens ds = winner; 376fa9e4066Sahrens } else { 37791ebeef5Sahrens ds->ds_fsid_guid = 378fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 379fa9e4066Sahrens } 380fa9e4066Sahrens } 381fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 382fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 383fa9e4066Sahrens 384fa9e4066Sahrens mutex_enter(&ds->ds_lock); 385fa9e4066Sahrens if ((DS_MODE_LEVEL(mode) == DS_MODE_PRIMARY && 38699653d4eSeschrock (ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) && 38799653d4eSeschrock !DS_MODE_IS_INCONSISTENT(mode)) || 38855434c77Sek (ds->ds_open_refcount + weight > DS_REF_MAX)) { 389fa9e4066Sahrens mutex_exit(&ds->ds_lock); 390fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 391ea8dc4b6Seschrock return (EBUSY); 392fa9e4066Sahrens } 393fa9e4066Sahrens ds->ds_open_refcount += weight; 394fa9e4066Sahrens mutex_exit(&ds->ds_lock); 395fa9e4066Sahrens 396ea8dc4b6Seschrock *dsp = ds; 397ea8dc4b6Seschrock return (0); 398fa9e4066Sahrens } 399fa9e4066Sahrens 400fa9e4066Sahrens int 401fa9e4066Sahrens dsl_dataset_open_spa(spa_t *spa, const char *name, int mode, 402fa9e4066Sahrens void *tag, dsl_dataset_t **dsp) 403fa9e4066Sahrens { 404fa9e4066Sahrens dsl_dir_t *dd; 405fa9e4066Sahrens dsl_pool_t *dp; 406fa9e4066Sahrens const char *tail; 407fa9e4066Sahrens uint64_t obj; 408fa9e4066Sahrens dsl_dataset_t *ds = NULL; 409fa9e4066Sahrens int err = 0; 410fa9e4066Sahrens 411ea8dc4b6Seschrock err = dsl_dir_open_spa(spa, name, FTAG, &dd, &tail); 412ea8dc4b6Seschrock if (err) 413ea8dc4b6Seschrock return (err); 414fa9e4066Sahrens 415fa9e4066Sahrens dp = dd->dd_pool; 416fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 417fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 418fa9e4066Sahrens if (obj == 0) { 419fa9e4066Sahrens /* A dataset with no associated objset */ 420fa9e4066Sahrens err = ENOENT; 421fa9e4066Sahrens goto out; 422fa9e4066Sahrens } 423fa9e4066Sahrens 424fa9e4066Sahrens if (tail != NULL) { 425fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 426fa9e4066Sahrens 427ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, obj, NULL, 428ea8dc4b6Seschrock DS_MODE_NONE, tag, &ds); 429ea8dc4b6Seschrock if (err) 430ea8dc4b6Seschrock goto out; 431fa9e4066Sahrens obj = ds->ds_phys->ds_snapnames_zapobj; 432fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 433fa9e4066Sahrens ds = NULL; 434fa9e4066Sahrens 435fa9e4066Sahrens if (tail[0] != '@') { 436fa9e4066Sahrens err = ENOENT; 437fa9e4066Sahrens goto out; 438fa9e4066Sahrens } 439fa9e4066Sahrens tail++; 440fa9e4066Sahrens 441fa9e4066Sahrens /* Look for a snapshot */ 442fa9e4066Sahrens if (!DS_MODE_IS_READONLY(mode)) { 443fa9e4066Sahrens err = EROFS; 444fa9e4066Sahrens goto out; 445fa9e4066Sahrens } 446fa9e4066Sahrens dprintf("looking for snapshot '%s'\n", tail); 447fa9e4066Sahrens err = zap_lookup(mos, obj, tail, 8, 1, &obj); 448fa9e4066Sahrens if (err) 449fa9e4066Sahrens goto out; 450fa9e4066Sahrens } 451ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, obj, tail, mode, tag, &ds); 452fa9e4066Sahrens 453fa9e4066Sahrens out: 454fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 455fa9e4066Sahrens dsl_dir_close(dd, FTAG); 456fa9e4066Sahrens 457fa9e4066Sahrens ASSERT3U((err == 0), ==, (ds != NULL)); 458fa9e4066Sahrens /* ASSERT(ds == NULL || strcmp(name, ds->ds_name) == 0); */ 459fa9e4066Sahrens 460fa9e4066Sahrens *dsp = ds; 461fa9e4066Sahrens return (err); 462fa9e4066Sahrens } 463fa9e4066Sahrens 464fa9e4066Sahrens int 465fa9e4066Sahrens dsl_dataset_open(const char *name, int mode, void *tag, dsl_dataset_t **dsp) 466fa9e4066Sahrens { 467fa9e4066Sahrens return (dsl_dataset_open_spa(NULL, name, mode, tag, dsp)); 468fa9e4066Sahrens } 469fa9e4066Sahrens 470fa9e4066Sahrens void 471fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 472fa9e4066Sahrens { 473fa9e4066Sahrens if (ds == NULL) { 474fa9e4066Sahrens (void) strcpy(name, "mos"); 475fa9e4066Sahrens } else { 476fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 477ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 478fa9e4066Sahrens if (ds->ds_snapname[0]) { 479fa9e4066Sahrens (void) strcat(name, "@"); 480fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 481fa9e4066Sahrens /* 482fa9e4066Sahrens * We use a "recursive" mutex so that we 483fa9e4066Sahrens * can call dprintf_ds() with ds_lock held. 484fa9e4066Sahrens */ 485fa9e4066Sahrens mutex_enter(&ds->ds_lock); 486fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 487fa9e4066Sahrens mutex_exit(&ds->ds_lock); 488fa9e4066Sahrens } else { 489fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 490fa9e4066Sahrens } 491fa9e4066Sahrens } 492fa9e4066Sahrens } 493fa9e4066Sahrens } 494fa9e4066Sahrens 495b7661cccSmmusante static int 496b7661cccSmmusante dsl_dataset_namelen(dsl_dataset_t *ds) 497b7661cccSmmusante { 498b7661cccSmmusante int result; 499b7661cccSmmusante 500b7661cccSmmusante if (ds == NULL) { 501b7661cccSmmusante result = 3; /* "mos" */ 502b7661cccSmmusante } else { 503b7661cccSmmusante result = dsl_dir_namelen(ds->ds_dir); 504b7661cccSmmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 505b7661cccSmmusante if (ds->ds_snapname[0]) { 506b7661cccSmmusante ++result; /* adding one for the @-sign */ 507b7661cccSmmusante if (!MUTEX_HELD(&ds->ds_lock)) { 508b7661cccSmmusante /* see dsl_datset_name */ 509b7661cccSmmusante mutex_enter(&ds->ds_lock); 510b7661cccSmmusante result += strlen(ds->ds_snapname); 511b7661cccSmmusante mutex_exit(&ds->ds_lock); 512b7661cccSmmusante } else { 513b7661cccSmmusante result += strlen(ds->ds_snapname); 514b7661cccSmmusante } 515b7661cccSmmusante } 516b7661cccSmmusante } 517b7661cccSmmusante 518b7661cccSmmusante return (result); 519b7661cccSmmusante } 520b7661cccSmmusante 521fa9e4066Sahrens void 522fa9e4066Sahrens dsl_dataset_close(dsl_dataset_t *ds, int mode, void *tag) 523fa9e4066Sahrens { 524fa9e4066Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 525fa9e4066Sahrens mutex_enter(&ds->ds_lock); 526fa9e4066Sahrens ASSERT3U(ds->ds_open_refcount, >=, weight); 527fa9e4066Sahrens ds->ds_open_refcount -= weight; 528fa9e4066Sahrens dprintf_ds(ds, "closing mode %u refcount now 0x%llx\n", 529fa9e4066Sahrens mode, ds->ds_open_refcount); 530fa9e4066Sahrens mutex_exit(&ds->ds_lock); 531fa9e4066Sahrens 532ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 533fa9e4066Sahrens } 534fa9e4066Sahrens 535fa9e4066Sahrens void 536fa9e4066Sahrens dsl_dataset_create_root(dsl_pool_t *dp, uint64_t *ddobjp, dmu_tx_t *tx) 537fa9e4066Sahrens { 538fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 539fa9e4066Sahrens dmu_buf_t *dbuf; 540fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 541fa9e4066Sahrens dsl_dataset_t *ds; 542fa9e4066Sahrens uint64_t dsobj; 543fa9e4066Sahrens dsl_dir_t *dd; 544fa9e4066Sahrens 545fa9e4066Sahrens dsl_dir_create_root(mos, ddobjp, tx); 546ea8dc4b6Seschrock VERIFY(0 == dsl_dir_open_obj(dp, *ddobjp, NULL, FTAG, &dd)); 547fa9e4066Sahrens 5481649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 5491649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 550ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 551fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 552fa9e4066Sahrens dsphys = dbuf->db_data; 553fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 554fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 555fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 556fa9e4066Sahrens sizeof (dsphys->ds_guid)); 557fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 55887e5029aSahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 559fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 560fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 561fa9e4066Sahrens dsphys->ds_deadlist_obj = 562fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 563ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 564fa9e4066Sahrens 565fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 566fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 567fa9e4066Sahrens dsl_dir_close(dd, FTAG); 568fa9e4066Sahrens 569ea8dc4b6Seschrock VERIFY(0 == 570ea8dc4b6Seschrock dsl_dataset_open_obj(dp, dsobj, NULL, DS_MODE_NONE, FTAG, &ds)); 571c717a561Smaybee (void) dmu_objset_create_impl(dp->dp_spa, ds, 572c717a561Smaybee &ds->ds_phys->ds_bp, DMU_OST_ZFS, tx); 573fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 574fa9e4066Sahrens } 575fa9e4066Sahrens 5761d452cf5Sahrens uint64_t 5771d452cf5Sahrens dsl_dataset_create_sync(dsl_dir_t *pdd, 578fa9e4066Sahrens const char *lastname, dsl_dataset_t *clone_parent, dmu_tx_t *tx) 579fa9e4066Sahrens { 5801d452cf5Sahrens dsl_pool_t *dp = pdd->dd_pool; 581fa9e4066Sahrens dmu_buf_t *dbuf; 582fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 5831d452cf5Sahrens uint64_t dsobj, ddobj; 584fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 585fa9e4066Sahrens dsl_dir_t *dd; 586fa9e4066Sahrens 5871d452cf5Sahrens ASSERT(clone_parent == NULL || clone_parent->ds_dir->dd_pool == dp); 5881d452cf5Sahrens ASSERT(clone_parent == NULL || 5891d452cf5Sahrens clone_parent->ds_phys->ds_num_children > 0); 590fa9e4066Sahrens ASSERT(lastname[0] != '@'); 591fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 592fa9e4066Sahrens 5931d452cf5Sahrens ddobj = dsl_dir_create_sync(pdd, lastname, tx); 5941d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 595fa9e4066Sahrens 5961649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 5971649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 598ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 599fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 600fa9e4066Sahrens dsphys = dbuf->db_data; 601fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 602fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 603fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 604fa9e4066Sahrens sizeof (dsphys->ds_guid)); 605fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 60687e5029aSahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 607fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 608fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 609fa9e4066Sahrens dsphys->ds_deadlist_obj = 610fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 611fa9e4066Sahrens if (clone_parent) { 612fa9e4066Sahrens dsphys->ds_prev_snap_obj = clone_parent->ds_object; 613fa9e4066Sahrens dsphys->ds_prev_snap_txg = 614fa9e4066Sahrens clone_parent->ds_phys->ds_creation_txg; 615fa9e4066Sahrens dsphys->ds_used_bytes = 616fa9e4066Sahrens clone_parent->ds_phys->ds_used_bytes; 617fa9e4066Sahrens dsphys->ds_compressed_bytes = 618fa9e4066Sahrens clone_parent->ds_phys->ds_compressed_bytes; 619fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 620fa9e4066Sahrens clone_parent->ds_phys->ds_uncompressed_bytes; 621fa9e4066Sahrens dsphys->ds_bp = clone_parent->ds_phys->ds_bp; 622fa9e4066Sahrens 623fa9e4066Sahrens dmu_buf_will_dirty(clone_parent->ds_dbuf, tx); 624fa9e4066Sahrens clone_parent->ds_phys->ds_num_children++; 625fa9e4066Sahrens 626fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 627fa9e4066Sahrens dd->dd_phys->dd_clone_parent_obj = clone_parent->ds_object; 628fa9e4066Sahrens } 629ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 630fa9e4066Sahrens 631fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 632fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 633fa9e4066Sahrens dsl_dir_close(dd, FTAG); 634fa9e4066Sahrens 6351d452cf5Sahrens return (dsobj); 636fa9e4066Sahrens } 637fa9e4066Sahrens 6381d452cf5Sahrens struct destroyarg { 6391d452cf5Sahrens dsl_sync_task_group_t *dstg; 6401d452cf5Sahrens char *snapname; 6411d452cf5Sahrens char *failed; 6421d452cf5Sahrens }; 6431d452cf5Sahrens 6441d452cf5Sahrens static int 6451d452cf5Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 646fa9e4066Sahrens { 6471d452cf5Sahrens struct destroyarg *da = arg; 6481d452cf5Sahrens dsl_dataset_t *ds; 6491d452cf5Sahrens char *cp; 650fa9e4066Sahrens int err; 651fa9e4066Sahrens 6521d452cf5Sahrens (void) strcat(name, "@"); 6531d452cf5Sahrens (void) strcat(name, da->snapname); 6541d452cf5Sahrens err = dsl_dataset_open(name, 6551d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 656cdf5b4caSmmusante da->dstg, &ds); 6571d452cf5Sahrens cp = strchr(name, '@'); 6581d452cf5Sahrens *cp = '\0'; 6591d452cf5Sahrens if (err == ENOENT) 6601d452cf5Sahrens return (0); 6611d452cf5Sahrens if (err) { 6621d452cf5Sahrens (void) strcpy(da->failed, name); 663ea8dc4b6Seschrock return (err); 6641d452cf5Sahrens } 665fa9e4066Sahrens 6661d452cf5Sahrens dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 667cdf5b4caSmmusante dsl_dataset_destroy_sync, ds, da->dstg, 0); 6681d452cf5Sahrens return (0); 6691d452cf5Sahrens } 67031fd60d3Sahrens 6711d452cf5Sahrens /* 6721d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 6731d452cf5Sahrens */ 6741d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 6751d452cf5Sahrens int 6761d452cf5Sahrens dsl_snapshots_destroy(char *fsname, char *snapname) 6771d452cf5Sahrens { 6781d452cf5Sahrens int err; 6791d452cf5Sahrens struct destroyarg da; 6801d452cf5Sahrens dsl_sync_task_t *dst; 6811d452cf5Sahrens spa_t *spa; 6821d452cf5Sahrens 68340feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 6841d452cf5Sahrens if (err) 6851d452cf5Sahrens return (err); 6861d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 6871d452cf5Sahrens da.snapname = snapname; 6881d452cf5Sahrens da.failed = fsname; 6891d452cf5Sahrens 6901d452cf5Sahrens err = dmu_objset_find(fsname, 6910b69c2f0Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 6921d452cf5Sahrens 6931d452cf5Sahrens if (err == 0) 6941d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 6951d452cf5Sahrens 6961d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 6971d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 6981d452cf5Sahrens dsl_dataset_t *ds = dst->dst_arg1; 6991d452cf5Sahrens if (dst->dst_err) { 7001d452cf5Sahrens dsl_dataset_name(ds, fsname); 70140feaa91Sahrens *strchr(fsname, '@') = '\0'; 702e1930233Sbonwick } 703fa9e4066Sahrens /* 7041d452cf5Sahrens * If it was successful, destroy_sync would have 7051d452cf5Sahrens * closed the ds 706fa9e4066Sahrens */ 707ea8dc4b6Seschrock if (err) 708cdf5b4caSmmusante dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, da.dstg); 709fa9e4066Sahrens } 710fa9e4066Sahrens 7111d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 7121d452cf5Sahrens spa_close(spa, FTAG); 713fa9e4066Sahrens return (err); 714fa9e4066Sahrens } 715fa9e4066Sahrens 716fa9e4066Sahrens int 7171d452cf5Sahrens dsl_dataset_destroy(const char *name) 718fa9e4066Sahrens { 719fa9e4066Sahrens int err; 7201d452cf5Sahrens dsl_sync_task_group_t *dstg; 7211d452cf5Sahrens objset_t *os; 7221d452cf5Sahrens dsl_dataset_t *ds; 723fa9e4066Sahrens dsl_dir_t *dd; 7241d452cf5Sahrens uint64_t obj; 7251d452cf5Sahrens 7261d452cf5Sahrens if (strchr(name, '@')) { 7271d452cf5Sahrens /* Destroying a snapshot is simpler */ 7281d452cf5Sahrens err = dsl_dataset_open(name, 7291d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 7301d452cf5Sahrens FTAG, &ds); 7311d452cf5Sahrens if (err) 7321d452cf5Sahrens return (err); 7331d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 7341d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 7351d452cf5Sahrens ds, FTAG, 0); 7361d452cf5Sahrens if (err) 7371d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 7381d452cf5Sahrens return (err); 7391d452cf5Sahrens } 740fa9e4066Sahrens 7411d452cf5Sahrens err = dmu_objset_open(name, DMU_OST_ANY, 7421d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, &os); 743ea8dc4b6Seschrock if (err) 744ea8dc4b6Seschrock return (err); 7451d452cf5Sahrens ds = os->os->os_dsl_dataset; 7461d452cf5Sahrens dd = ds->ds_dir; 747fa9e4066Sahrens 7481d452cf5Sahrens /* 7491d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 7501d452cf5Sahrens * case we crash while freeing the objects. 7511d452cf5Sahrens */ 7521d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 7531d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 7541d452cf5Sahrens if (err) { 7551d452cf5Sahrens dmu_objset_close(os); 7561d452cf5Sahrens return (err); 757fa9e4066Sahrens } 758fa9e4066Sahrens 7591d452cf5Sahrens /* 7601d452cf5Sahrens * remove the objects in open context, so that we won't 7611d452cf5Sahrens * have too much to do in syncing context. 7621d452cf5Sahrens */ 7636754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 7646754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 7651d452cf5Sahrens dmu_tx_t *tx = dmu_tx_create(os); 7661d452cf5Sahrens dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END); 7671d452cf5Sahrens dmu_tx_hold_bonus(tx, obj); 7681d452cf5Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 7691d452cf5Sahrens if (err) { 7701d452cf5Sahrens /* 7711d452cf5Sahrens * Perhaps there is not enough disk 7721d452cf5Sahrens * space. Just deal with it from 7731d452cf5Sahrens * dsl_dataset_destroy_sync(). 7741d452cf5Sahrens */ 7751d452cf5Sahrens dmu_tx_abort(tx); 7761d452cf5Sahrens continue; 7771d452cf5Sahrens } 7781d452cf5Sahrens VERIFY(0 == dmu_object_free(os, obj, tx)); 7791d452cf5Sahrens dmu_tx_commit(tx); 7801d452cf5Sahrens } 7811d452cf5Sahrens /* Make sure it's not dirty before we finish destroying it. */ 7821d452cf5Sahrens txg_wait_synced(dd->dd_pool, 0); 7831d452cf5Sahrens 7841d452cf5Sahrens dmu_objset_close(os); 7851d452cf5Sahrens if (err != ESRCH) 7861d452cf5Sahrens return (err); 7871d452cf5Sahrens 7881d452cf5Sahrens err = dsl_dataset_open(name, 7891d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 7901d452cf5Sahrens FTAG, &ds); 7911d452cf5Sahrens if (err) 7921d452cf5Sahrens return (err); 7931d452cf5Sahrens 7941d452cf5Sahrens err = dsl_dir_open(name, FTAG, &dd, NULL); 7951d452cf5Sahrens if (err) { 7961d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 7971d452cf5Sahrens return (err); 7981d452cf5Sahrens } 7991d452cf5Sahrens 8001d452cf5Sahrens /* 8011d452cf5Sahrens * Blow away the dsl_dir + head dataset. 8021d452cf5Sahrens */ 8031d452cf5Sahrens dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 8041d452cf5Sahrens dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 8051d452cf5Sahrens dsl_dataset_destroy_sync, ds, FTAG, 0); 8061d452cf5Sahrens dsl_sync_task_create(dstg, dsl_dir_destroy_check, 8071d452cf5Sahrens dsl_dir_destroy_sync, dd, FTAG, 0); 8081d452cf5Sahrens err = dsl_sync_task_group_wait(dstg); 8091d452cf5Sahrens dsl_sync_task_group_destroy(dstg); 8101d452cf5Sahrens /* if it is successful, *destroy_sync will close the ds+dd */ 8111d452cf5Sahrens if (err) { 8121d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 8131d452cf5Sahrens dsl_dir_close(dd, FTAG); 8141d452cf5Sahrens } 815fa9e4066Sahrens return (err); 816fa9e4066Sahrens } 817fa9e4066Sahrens 8181d452cf5Sahrens int 8191d452cf5Sahrens dsl_dataset_rollback(dsl_dataset_t *ds) 8201d452cf5Sahrens { 82155434c77Sek ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX); 8221d452cf5Sahrens return (dsl_sync_task_do(ds->ds_dir->dd_pool, 8231d452cf5Sahrens dsl_dataset_rollback_check, dsl_dataset_rollback_sync, 8241d452cf5Sahrens ds, NULL, 0)); 8251d452cf5Sahrens } 8261d452cf5Sahrens 827fa9e4066Sahrens void * 828fa9e4066Sahrens dsl_dataset_set_user_ptr(dsl_dataset_t *ds, 829fa9e4066Sahrens void *p, dsl_dataset_evict_func_t func) 830fa9e4066Sahrens { 831fa9e4066Sahrens void *old; 832fa9e4066Sahrens 833fa9e4066Sahrens mutex_enter(&ds->ds_lock); 834fa9e4066Sahrens old = ds->ds_user_ptr; 835fa9e4066Sahrens if (old == NULL) { 836fa9e4066Sahrens ds->ds_user_ptr = p; 837fa9e4066Sahrens ds->ds_user_evict_func = func; 838fa9e4066Sahrens } 839fa9e4066Sahrens mutex_exit(&ds->ds_lock); 840fa9e4066Sahrens return (old); 841fa9e4066Sahrens } 842fa9e4066Sahrens 843fa9e4066Sahrens void * 844fa9e4066Sahrens dsl_dataset_get_user_ptr(dsl_dataset_t *ds) 845fa9e4066Sahrens { 846fa9e4066Sahrens return (ds->ds_user_ptr); 847fa9e4066Sahrens } 848fa9e4066Sahrens 849fa9e4066Sahrens 850c717a561Smaybee blkptr_t * 851c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 852fa9e4066Sahrens { 853c717a561Smaybee return (&ds->ds_phys->ds_bp); 854fa9e4066Sahrens } 855fa9e4066Sahrens 856fa9e4066Sahrens void 857fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 858fa9e4066Sahrens { 859fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 860fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 861fa9e4066Sahrens if (ds == NULL) { 862fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 863fa9e4066Sahrens } else { 864fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 865fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 866fa9e4066Sahrens } 867fa9e4066Sahrens } 868fa9e4066Sahrens 869fa9e4066Sahrens spa_t * 870fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 871fa9e4066Sahrens { 872fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 873fa9e4066Sahrens } 874fa9e4066Sahrens 875fa9e4066Sahrens void 876fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 877fa9e4066Sahrens { 878fa9e4066Sahrens dsl_pool_t *dp; 879fa9e4066Sahrens 880fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 881fa9e4066Sahrens return; 882fa9e4066Sahrens 883fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 884a2eea2e1Sahrens 885a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 886a2eea2e1Sahrens panic("dirtying snapshot!"); 887fa9e4066Sahrens 888fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 889fa9e4066Sahrens 890fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 891fa9e4066Sahrens /* up the hold count until we can be written out */ 892fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 893fa9e4066Sahrens } 894fa9e4066Sahrens } 895fa9e4066Sahrens 896fa9e4066Sahrens struct killarg { 897fa9e4066Sahrens uint64_t *usedp; 898fa9e4066Sahrens uint64_t *compressedp; 899fa9e4066Sahrens uint64_t *uncompressedp; 900fa9e4066Sahrens zio_t *zio; 901fa9e4066Sahrens dmu_tx_t *tx; 902fa9e4066Sahrens }; 903fa9e4066Sahrens 904fa9e4066Sahrens static int 905fa9e4066Sahrens kill_blkptr(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 906fa9e4066Sahrens { 907fa9e4066Sahrens struct killarg *ka = arg; 908fa9e4066Sahrens blkptr_t *bp = &bc->bc_blkptr; 909fa9e4066Sahrens 910fa9e4066Sahrens ASSERT3U(bc->bc_errno, ==, 0); 911fa9e4066Sahrens 912fa9e4066Sahrens /* 913fa9e4066Sahrens * Since this callback is not called concurrently, no lock is 914fa9e4066Sahrens * needed on the accounting values. 915fa9e4066Sahrens */ 91699653d4eSeschrock *ka->usedp += bp_get_dasize(spa, bp); 917fa9e4066Sahrens *ka->compressedp += BP_GET_PSIZE(bp); 918fa9e4066Sahrens *ka->uncompressedp += BP_GET_UCSIZE(bp); 919fa9e4066Sahrens /* XXX check for EIO? */ 920fa9e4066Sahrens (void) arc_free(ka->zio, spa, ka->tx->tx_txg, bp, NULL, NULL, 921fa9e4066Sahrens ARC_NOWAIT); 922fa9e4066Sahrens return (0); 923fa9e4066Sahrens } 924fa9e4066Sahrens 925fa9e4066Sahrens /* ARGSUSED */ 9261d452cf5Sahrens static int 9271d452cf5Sahrens dsl_dataset_rollback_check(void *arg1, void *arg2, dmu_tx_t *tx) 928fa9e4066Sahrens { 9291d452cf5Sahrens dsl_dataset_t *ds = arg1; 930fa9e4066Sahrens 9311d452cf5Sahrens /* 9321d452cf5Sahrens * There must be a previous snapshot. I suppose we could roll 9331d452cf5Sahrens * it back to being empty (and re-initialize the upper (ZPL) 9341d452cf5Sahrens * layer). But for now there's no way to do this via the user 9351d452cf5Sahrens * interface. 9361d452cf5Sahrens */ 9371d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg == 0) 938fa9e4066Sahrens return (EINVAL); 939fa9e4066Sahrens 9401d452cf5Sahrens /* 9411d452cf5Sahrens * This must not be a snapshot. 9421d452cf5Sahrens */ 9431d452cf5Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 944fa9e4066Sahrens return (EINVAL); 945fa9e4066Sahrens 946fa9e4066Sahrens /* 947fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 948fa9e4066Sahrens * them. Try again. 949fa9e4066Sahrens */ 9501d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 951fa9e4066Sahrens return (EAGAIN); 952fa9e4066Sahrens 9531d452cf5Sahrens return (0); 9541d452cf5Sahrens } 9551d452cf5Sahrens 9561d452cf5Sahrens /* ARGSUSED */ 9571d452cf5Sahrens static void 958ecd6cf80Smarks dsl_dataset_rollback_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 9591d452cf5Sahrens { 9601d452cf5Sahrens dsl_dataset_t *ds = arg1; 9611d452cf5Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 962fa9e4066Sahrens 963fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 964fa9e4066Sahrens 96586ccc033Sperrin /* 96686ccc033Sperrin * Before the roll back destroy the zil. 96786ccc033Sperrin * Note, ds_user_ptr can be null if we are doing a "zfs receive -F" 96886ccc033Sperrin */ 96986ccc033Sperrin if (ds->ds_user_ptr != NULL) { 97086ccc033Sperrin zil_rollback_destroy( 97186ccc033Sperrin ((objset_impl_t *)ds->ds_user_ptr)->os_zil, tx); 97286ccc033Sperrin } 9733a8a1de4Sperrin 974fa9e4066Sahrens /* Zero out the deadlist. */ 975fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 976fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 977fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 978fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 979ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 980ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 981fa9e4066Sahrens 982fa9e4066Sahrens { 983fa9e4066Sahrens /* Free blkptrs that we gave birth to */ 984fa9e4066Sahrens zio_t *zio; 985fa9e4066Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 986fa9e4066Sahrens struct killarg ka; 987fa9e4066Sahrens 988fa9e4066Sahrens zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL, 989fa9e4066Sahrens ZIO_FLAG_MUSTSUCCEED); 990fa9e4066Sahrens ka.usedp = &used; 991fa9e4066Sahrens ka.compressedp = &compressed; 992fa9e4066Sahrens ka.uncompressedp = &uncompressed; 993fa9e4066Sahrens ka.zio = zio; 994fa9e4066Sahrens ka.tx = tx; 995fa9e4066Sahrens (void) traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 996fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 997fa9e4066Sahrens (void) zio_wait(zio); 998fa9e4066Sahrens 9991d452cf5Sahrens dsl_dir_diduse_space(ds->ds_dir, 1000fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 1001fa9e4066Sahrens } 1002fa9e4066Sahrens 10031d452cf5Sahrens /* Change our contents to that of the prev snapshot */ 1004fa9e4066Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, ds->ds_phys->ds_prev_snap_obj); 1005fa9e4066Sahrens ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp; 1006fa9e4066Sahrens ds->ds_phys->ds_used_bytes = ds->ds_prev->ds_phys->ds_used_bytes; 1007fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes = 1008fa9e4066Sahrens ds->ds_prev->ds_phys->ds_compressed_bytes; 1009fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes = 1010fa9e4066Sahrens ds->ds_prev->ds_phys->ds_uncompressed_bytes; 101199653d4eSeschrock ds->ds_phys->ds_flags = ds->ds_prev->ds_phys->ds_flags; 1012fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1013fa9e4066Sahrens 101485edac42Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 101585edac42Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 101685edac42Sahrens ds->ds_prev->ds_phys->ds_unique_bytes = 0; 101785edac42Sahrens } 1018ecd6cf80Smarks 1019ecd6cf80Smarks spa_history_internal_log(LOG_DS_ROLLBACK, ds->ds_dir->dd_pool->dp_spa, 1020ecd6cf80Smarks tx, cr, "dataset = %llu", ds->ds_object); 1021fa9e4066Sahrens } 1022fa9e4066Sahrens 1023e1930233Sbonwick /* ARGSUSED */ 1024e1930233Sbonwick static int 10251d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1026e1930233Sbonwick { 10271d452cf5Sahrens dsl_dataset_t *ds = arg1; 1028e1930233Sbonwick 1029e1930233Sbonwick /* 1030e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1031e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1032e1930233Sbonwick * from.) 1033e1930233Sbonwick */ 1034e1930233Sbonwick if (ds->ds_prev != NULL && 1035e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1036e1930233Sbonwick return (EINVAL); 1037e1930233Sbonwick 1038e1930233Sbonwick return (0); 1039e1930233Sbonwick } 1040e1930233Sbonwick 10411d452cf5Sahrens /* ARGSUSED */ 10421d452cf5Sahrens static void 1043ecd6cf80Smarks dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 1044fa9e4066Sahrens { 10451d452cf5Sahrens dsl_dataset_t *ds = arg1; 1046ecd6cf80Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1047fa9e4066Sahrens 10481d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 10491d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 10501d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1051ecd6cf80Smarks 1052ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 1053ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 10541d452cf5Sahrens } 1055fa9e4066Sahrens 10561d452cf5Sahrens /* ARGSUSED */ 10571d452cf5Sahrens static int 10581d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 10591d452cf5Sahrens { 10601d452cf5Sahrens dsl_dataset_t *ds = arg1; 1061fa9e4066Sahrens 1062fa9e4066Sahrens /* Can't delete a branch point. */ 10631d452cf5Sahrens if (ds->ds_phys->ds_num_children > 1) 10641d452cf5Sahrens return (EEXIST); 1065fa9e4066Sahrens 1066fa9e4066Sahrens /* 1067fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1068fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1069fa9e4066Sahrens * from.) 1070fa9e4066Sahrens */ 1071fa9e4066Sahrens if (ds->ds_prev != NULL && 10721d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1073fa9e4066Sahrens return (EINVAL); 1074fa9e4066Sahrens 1075fa9e4066Sahrens /* 1076fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1077fa9e4066Sahrens * them. Try again. 1078fa9e4066Sahrens */ 10791d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1080fa9e4066Sahrens return (EAGAIN); 10811d452cf5Sahrens 10821d452cf5Sahrens /* XXX we should do some i/o error checking... */ 10831d452cf5Sahrens return (0); 10841d452cf5Sahrens } 10851d452cf5Sahrens 10861d452cf5Sahrens static void 1087ecd6cf80Smarks dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 10881d452cf5Sahrens { 10891d452cf5Sahrens dsl_dataset_t *ds = arg1; 10901d452cf5Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 10911d452cf5Sahrens zio_t *zio; 10921d452cf5Sahrens int err; 10931d452cf5Sahrens int after_branch_point = FALSE; 10941d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 10951d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 10961d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 10971d452cf5Sahrens uint64_t obj; 10981d452cf5Sahrens 109955434c77Sek ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX); 11001d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_num_children, <=, 1); 11011d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 11021d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 11031d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 11041d452cf5Sahrens 11051d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 11061d452cf5Sahrens 11071d452cf5Sahrens obj = ds->ds_object; 1108fa9e4066Sahrens 1109fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1110fa9e4066Sahrens if (ds->ds_prev) { 1111fa9e4066Sahrens ds_prev = ds->ds_prev; 1112fa9e4066Sahrens } else { 11131d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1114fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 11151d452cf5Sahrens DS_MODE_NONE, FTAG, &ds_prev)); 1116fa9e4066Sahrens } 1117fa9e4066Sahrens after_branch_point = 1118fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1119fa9e4066Sahrens 1120fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1121fa9e4066Sahrens if (after_branch_point && 1122fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1123fa9e4066Sahrens /* This clone is toast. */ 1124fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1125fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1126fa9e4066Sahrens } else if (!after_branch_point) { 1127fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1128fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1129fa9e4066Sahrens } 1130fa9e4066Sahrens } 1131fa9e4066Sahrens 1132fa9e4066Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1133fa9e4066Sahrens 1134fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 11351d452cf5Sahrens blkptr_t bp; 1136fa9e4066Sahrens dsl_dataset_t *ds_next; 1137fa9e4066Sahrens uint64_t itor = 0; 1138fa9e4066Sahrens 1139fa9e4066Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 1140fa9e4066Sahrens 11411d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1142ea8dc4b6Seschrock ds->ds_phys->ds_next_snap_obj, NULL, 1143ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_next)); 1144fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1145fa9e4066Sahrens 1146fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1147fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1148fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1149fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1150fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1151fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1152fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1153fa9e4066Sahrens 1154fa9e4066Sahrens /* 1155fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1156fa9e4066Sahrens * new deadlist) any entries from next's current 1157fa9e4066Sahrens * deadlist which were born before prev, and free the 1158fa9e4066Sahrens * other entries. 1159fa9e4066Sahrens * 1160fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1161fa9e4066Sahrens */ 1162fa9e4066Sahrens while (bplist_iterate(&ds_next->ds_deadlist, &itor, 1163fa9e4066Sahrens &bp) == 0) { 1164fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1165ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1166ea8dc4b6Seschrock &bp, tx)); 1167fa9e4066Sahrens if (ds_prev && !after_branch_point && 1168fa9e4066Sahrens bp.blk_birth > 1169fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1170fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 117199653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1172fa9e4066Sahrens } 1173fa9e4066Sahrens } else { 117499653d4eSeschrock used += bp_get_dasize(dp->dp_spa, &bp); 1175fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1176fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1177fa9e4066Sahrens /* XXX check return value? */ 1178fa9e4066Sahrens (void) arc_free(zio, dp->dp_spa, tx->tx_txg, 1179fa9e4066Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1180fa9e4066Sahrens } 1181fa9e4066Sahrens } 1182fa9e4066Sahrens 1183fa9e4066Sahrens /* free next's deadlist */ 1184fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1185fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1186fa9e4066Sahrens 1187fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1188fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1189fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1190ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1191ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1192fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1193fa9e4066Sahrens 1194fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1195fa9e4066Sahrens /* 1196fa9e4066Sahrens * Update next's unique to include blocks which 1197fa9e4066Sahrens * were previously shared by only this snapshot 1198fa9e4066Sahrens * and it. Those blocks will be born after the 1199fa9e4066Sahrens * prev snap and before this snap, and will have 1200fa9e4066Sahrens * died after the next snap and before the one 1201fa9e4066Sahrens * after that (ie. be on the snap after next's 1202fa9e4066Sahrens * deadlist). 1203fa9e4066Sahrens * 1204fa9e4066Sahrens * XXX we're doing this long task with the 1205fa9e4066Sahrens * config lock held 1206fa9e4066Sahrens */ 1207fa9e4066Sahrens dsl_dataset_t *ds_after_next; 1208fa9e4066Sahrens 12091d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1210fa9e4066Sahrens ds_next->ds_phys->ds_next_snap_obj, NULL, 1211ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_after_next)); 1212fa9e4066Sahrens itor = 0; 1213fa9e4066Sahrens while (bplist_iterate(&ds_after_next->ds_deadlist, 1214fa9e4066Sahrens &itor, &bp) == 0) { 1215fa9e4066Sahrens if (bp.blk_birth > 1216fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg && 1217fa9e4066Sahrens bp.blk_birth <= 1218fa9e4066Sahrens ds->ds_phys->ds_creation_txg) { 1219fa9e4066Sahrens ds_next->ds_phys->ds_unique_bytes += 122099653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1221fa9e4066Sahrens } 1222fa9e4066Sahrens } 1223fa9e4066Sahrens 1224fa9e4066Sahrens dsl_dataset_close(ds_after_next, DS_MODE_NONE, FTAG); 1225fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1226fa9e4066Sahrens } else { 1227fa9e4066Sahrens /* 1228fa9e4066Sahrens * It would be nice to update the head dataset's 1229fa9e4066Sahrens * unique. To do so we would have to traverse 1230fa9e4066Sahrens * it for blocks born after ds_prev, which is 1231fa9e4066Sahrens * pretty expensive just to maintain something 1232fa9e4066Sahrens * for debugging purposes. 1233fa9e4066Sahrens */ 1234fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1235fa9e4066Sahrens dsl_dataset_close(ds_next->ds_prev, DS_MODE_NONE, 1236fa9e4066Sahrens ds_next); 1237fa9e4066Sahrens if (ds_prev) { 12381d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1239ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, NULL, 1240ea8dc4b6Seschrock DS_MODE_NONE, ds_next, &ds_next->ds_prev)); 1241fa9e4066Sahrens } else { 1242fa9e4066Sahrens ds_next->ds_prev = NULL; 1243fa9e4066Sahrens } 1244fa9e4066Sahrens } 1245fa9e4066Sahrens dsl_dataset_close(ds_next, DS_MODE_NONE, FTAG); 1246fa9e4066Sahrens 1247fa9e4066Sahrens /* 1248fa9e4066Sahrens * NB: unique_bytes is not accurate for head objsets 1249fa9e4066Sahrens * because we don't update it when we delete the most 1250fa9e4066Sahrens * recent snapshot -- see above comment. 1251fa9e4066Sahrens */ 1252fa9e4066Sahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 1253fa9e4066Sahrens } else { 1254fa9e4066Sahrens /* 1255fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1256fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1257fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1258fa9e4066Sahrens * safe to ignore the deadlist contents.) 1259fa9e4066Sahrens */ 1260fa9e4066Sahrens struct killarg ka; 1261fa9e4066Sahrens 1262fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1263fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1264fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1265fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1266fa9e4066Sahrens 1267fa9e4066Sahrens /* 1268fa9e4066Sahrens * Free everything that we point to (that's born after 1269fa9e4066Sahrens * the previous snapshot, if we are a clone) 1270fa9e4066Sahrens * 1271fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1272fa9e4066Sahrens */ 1273fa9e4066Sahrens ka.usedp = &used; 1274fa9e4066Sahrens ka.compressedp = &compressed; 1275fa9e4066Sahrens ka.uncompressedp = &uncompressed; 1276fa9e4066Sahrens ka.zio = zio; 1277fa9e4066Sahrens ka.tx = tx; 1278fa9e4066Sahrens err = traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 1279fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 1280fa9e4066Sahrens ASSERT3U(err, ==, 0); 1281fa9e4066Sahrens } 1282fa9e4066Sahrens 1283fa9e4066Sahrens err = zio_wait(zio); 1284fa9e4066Sahrens ASSERT3U(err, ==, 0); 1285fa9e4066Sahrens 12861d452cf5Sahrens dsl_dir_diduse_space(ds->ds_dir, -used, -compressed, -uncompressed, tx); 1287fa9e4066Sahrens 1288fa9e4066Sahrens if (ds->ds_phys->ds_snapnames_zapobj) { 1289fa9e4066Sahrens err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1290fa9e4066Sahrens ASSERT(err == 0); 1291fa9e4066Sahrens } 1292fa9e4066Sahrens 12931d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1294fa9e4066Sahrens /* Erase the link in the dataset */ 12951d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 12961d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1297fa9e4066Sahrens /* 1298fa9e4066Sahrens * dsl_dir_sync_destroy() called us, they'll destroy 1299fa9e4066Sahrens * the dataset. 1300fa9e4066Sahrens */ 1301fa9e4066Sahrens } else { 1302fa9e4066Sahrens /* remove from snapshot namespace */ 1303fa9e4066Sahrens dsl_dataset_t *ds_head; 13041d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 13051d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj, NULL, 1306ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_head)); 13078660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1308fa9e4066Sahrens #ifdef ZFS_DEBUG 1309fa9e4066Sahrens { 1310fa9e4066Sahrens uint64_t val; 1311fa9e4066Sahrens err = zap_lookup(mos, 1312fa9e4066Sahrens ds_head->ds_phys->ds_snapnames_zapobj, 13131d452cf5Sahrens ds->ds_snapname, 8, 1, &val); 1314fa9e4066Sahrens ASSERT3U(err, ==, 0); 1315fa9e4066Sahrens ASSERT3U(val, ==, obj); 1316fa9e4066Sahrens } 1317fa9e4066Sahrens #endif 1318fa9e4066Sahrens err = zap_remove(mos, ds_head->ds_phys->ds_snapnames_zapobj, 13191d452cf5Sahrens ds->ds_snapname, tx); 1320fa9e4066Sahrens ASSERT(err == 0); 1321fa9e4066Sahrens dsl_dataset_close(ds_head, DS_MODE_NONE, FTAG); 1322fa9e4066Sahrens } 1323fa9e4066Sahrens 1324fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1325fa9e4066Sahrens dsl_dataset_close(ds_prev, DS_MODE_NONE, FTAG); 1326fa9e4066Sahrens 1327990b4856Slling spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 1328ecd6cf80Smarks spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx, 1329ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 1330ecd6cf80Smarks 13311d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, tag); 13321d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1333b1b8ab34Slling 1334fa9e4066Sahrens } 1335fa9e4066Sahrens 13361d452cf5Sahrens /* ARGSUSED */ 1337fa9e4066Sahrens int 13381d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1339fa9e4066Sahrens { 13401d452cf5Sahrens objset_t *os = arg1; 13411d452cf5Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 13421d452cf5Sahrens const char *snapname = arg2; 13431d452cf5Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1344fa9e4066Sahrens int err; 13451d452cf5Sahrens uint64_t value; 1346fa9e4066Sahrens 13471d452cf5Sahrens /* 13481d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 13491d452cf5Sahrens * is already one, try again. 13501d452cf5Sahrens */ 13511d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 13521d452cf5Sahrens return (EAGAIN); 1353fa9e4066Sahrens 13541d452cf5Sahrens /* 13551d452cf5Sahrens * Check for conflicting name snapshot name. 13561d452cf5Sahrens */ 1357fa9e4066Sahrens err = zap_lookup(mos, ds->ds_phys->ds_snapnames_zapobj, 1358fa9e4066Sahrens snapname, 8, 1, &value); 13591d452cf5Sahrens if (err == 0) 1360fa9e4066Sahrens return (EEXIST); 13611d452cf5Sahrens if (err != ENOENT) 13621d452cf5Sahrens return (err); 1363fa9e4066Sahrens 1364b7661cccSmmusante /* 1365b7661cccSmmusante * Check that the dataset's name is not too long. Name consists 1366b7661cccSmmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 1367b7661cccSmmusante */ 1368b7661cccSmmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 1369b7661cccSmmusante return (ENAMETOOLONG); 1370b7661cccSmmusante 13711d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 13721d452cf5Sahrens return (0); 13731d452cf5Sahrens } 1374fa9e4066Sahrens 13751d452cf5Sahrens void 1376ecd6cf80Smarks dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 13771d452cf5Sahrens { 13781d452cf5Sahrens objset_t *os = arg1; 13791d452cf5Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 13801d452cf5Sahrens const char *snapname = arg2; 13811d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 13821d452cf5Sahrens dmu_buf_t *dbuf; 13831d452cf5Sahrens dsl_dataset_phys_t *dsphys; 13841d452cf5Sahrens uint64_t dsobj; 13851d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 13861d452cf5Sahrens int err; 1387fa9e4066Sahrens 1388fa9e4066Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 13891d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1390fa9e4066Sahrens 13911649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 13921649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 1393ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1394fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 1395fa9e4066Sahrens dsphys = dbuf->db_data; 13961d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 1397fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 1398fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1399fa9e4066Sahrens sizeof (dsphys->ds_guid)); 1400fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1401fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1402fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1403fa9e4066Sahrens dsphys->ds_num_children = 1; 1404fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1405fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 1406fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1407fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1408fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1409fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 141099653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 1411fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 1412ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 1413fa9e4066Sahrens 14141d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 14151d452cf5Sahrens if (ds->ds_prev) { 14161d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 1417fa9e4066Sahrens ds->ds_object || 14181d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 14191d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 14201d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1421fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 14221d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 14231d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1424fa9e4066Sahrens } 1425fa9e4066Sahrens } 1426fa9e4066Sahrens 1427fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1428fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1429fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, dsphys->ds_creation_txg); 1430fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1431fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg = dsphys->ds_creation_txg; 1432fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1433fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1434fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1435ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1436ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1437fa9e4066Sahrens 1438fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1439fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1440fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 1441fa9e4066Sahrens ASSERT(err == 0); 1442fa9e4066Sahrens 1443fa9e4066Sahrens if (ds->ds_prev) 1444fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 1445ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dp, 1446ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, snapname, 1447ea8dc4b6Seschrock DS_MODE_NONE, ds, &ds->ds_prev)); 1448ecd6cf80Smarks 1449ecd6cf80Smarks spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr, 145040feaa91Sahrens "dataset = %llu", dsobj); 1451fa9e4066Sahrens } 1452fa9e4066Sahrens 1453fa9e4066Sahrens void 1454c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 1455fa9e4066Sahrens { 1456fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1457fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 1458fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1459fa9e4066Sahrens 146091ebeef5Sahrens /* 146191ebeef5Sahrens * in case we had to change ds_fsid_guid when we opened it, 146291ebeef5Sahrens * sync it out now. 146391ebeef5Sahrens */ 146491ebeef5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 146591ebeef5Sahrens ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid; 146691ebeef5Sahrens 1467fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 1468c717a561Smaybee dmu_objset_sync(ds->ds_user_ptr, zio, tx); 1469fa9e4066Sahrens } 1470fa9e4066Sahrens 1471fa9e4066Sahrens void 1472a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 1473fa9e4066Sahrens { 1474a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 1475fa9e4066Sahrens 1476a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 1477a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 1478a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 1479a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 1480a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, 1481a2eea2e1Sahrens ds->ds_phys->ds_used_bytes); 1482fa9e4066Sahrens 1483fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1484fa9e4066Sahrens /* 1485fa9e4066Sahrens * This is a snapshot; override the dd's space used with 1486a2eea2e1Sahrens * our unique space and compression ratio. 1487fa9e4066Sahrens */ 1488a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 1489a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 1490a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 1491a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 1492a2eea2e1Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 1493a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes)); 1494fa9e4066Sahrens } 1495fa9e4066Sahrens } 1496fa9e4066Sahrens 1497a2eea2e1Sahrens void 1498a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 1499a2eea2e1Sahrens { 1500a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 1501a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 1502a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1503a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 1504a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 1505a2eea2e1Sahrens } 1506a2eea2e1Sahrens 1507a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 1508a2eea2e1Sahrens if (ds->ds_dir->dd_phys->dd_clone_parent_obj) { 1509a2eea2e1Sahrens dsl_dataset_t *ods; 1510a2eea2e1Sahrens 1511a2eea2e1Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 1512a2eea2e1Sahrens VERIFY(0 == dsl_dataset_open_obj(ds->ds_dir->dd_pool, 1513a2eea2e1Sahrens ds->ds_dir->dd_phys->dd_clone_parent_obj, 1514a2eea2e1Sahrens NULL, DS_MODE_NONE, FTAG, &ods)); 1515a2eea2e1Sahrens dsl_dataset_name(ods, stat->dds_clone_of); 1516a2eea2e1Sahrens dsl_dataset_close(ods, DS_MODE_NONE, FTAG); 1517a2eea2e1Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 1518a2eea2e1Sahrens } 1519a2eea2e1Sahrens } 1520a2eea2e1Sahrens 1521a2eea2e1Sahrens uint64_t 1522a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 1523a2eea2e1Sahrens { 152491ebeef5Sahrens return (ds->ds_fsid_guid); 1525a2eea2e1Sahrens } 1526a2eea2e1Sahrens 1527a2eea2e1Sahrens void 1528a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 1529a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 1530a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 1531fa9e4066Sahrens { 1532a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 1533a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 1534a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 1535a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 1536fa9e4066Sahrens } 1537fa9e4066Sahrens 1538*f18faf3fSek boolean_t 1539*f18faf3fSek dsl_dataset_modified_since_lastsnap(dsl_dataset_t *ds) 1540*f18faf3fSek { 1541*f18faf3fSek dsl_pool_t *dp = ds->ds_dir->dd_pool; 1542*f18faf3fSek 1543*f18faf3fSek ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 1544*f18faf3fSek dsl_pool_sync_context(dp)); 1545*f18faf3fSek if (ds->ds_prev == NULL) 1546*f18faf3fSek return (B_FALSE); 1547*f18faf3fSek if (ds->ds_phys->ds_bp.blk_birth > 1548*f18faf3fSek ds->ds_prev->ds_phys->ds_creation_txg) 1549*f18faf3fSek return (B_TRUE); 1550*f18faf3fSek return (B_FALSE); 1551*f18faf3fSek } 1552*f18faf3fSek 15531d452cf5Sahrens /* ARGSUSED */ 1554fa9e4066Sahrens static int 15551d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 1556fa9e4066Sahrens { 15571d452cf5Sahrens dsl_dataset_t *ds = arg1; 15581d452cf5Sahrens char *newsnapname = arg2; 15591d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 1560fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 15611d452cf5Sahrens dsl_dataset_t *hds; 1562fa9e4066Sahrens uint64_t val; 15631d452cf5Sahrens int err; 1564fa9e4066Sahrens 15651d452cf5Sahrens err = dsl_dataset_open_obj(dd->dd_pool, 15661d452cf5Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds); 1567fa9e4066Sahrens if (err) 1568fa9e4066Sahrens return (err); 1569fa9e4066Sahrens 15701d452cf5Sahrens /* new name better not be in use */ 15711d452cf5Sahrens err = zap_lookup(mos, hds->ds_phys->ds_snapnames_zapobj, 15721d452cf5Sahrens newsnapname, 8, 1, &val); 15731d452cf5Sahrens dsl_dataset_close(hds, DS_MODE_NONE, FTAG); 15741d452cf5Sahrens 15751d452cf5Sahrens if (err == 0) 15761d452cf5Sahrens err = EEXIST; 15771d452cf5Sahrens else if (err == ENOENT) 15781d452cf5Sahrens err = 0; 1579cdf5b4caSmmusante 1580cdf5b4caSmmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 1581cdf5b4caSmmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 1582cdf5b4caSmmusante err = ENAMETOOLONG; 1583cdf5b4caSmmusante 15841d452cf5Sahrens return (err); 15851d452cf5Sahrens } 1586fa9e4066Sahrens 15871d452cf5Sahrens static void 1588ecd6cf80Smarks dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, 1589ecd6cf80Smarks cred_t *cr, dmu_tx_t *tx) 15901d452cf5Sahrens { 15911d452cf5Sahrens dsl_dataset_t *ds = arg1; 1592ecd6cf80Smarks const char *newsnapname = arg2; 15931d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 15941d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 15951d452cf5Sahrens dsl_dataset_t *hds; 15961d452cf5Sahrens int err; 1597fa9e4066Sahrens 15981d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 1599fa9e4066Sahrens 16001d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, 16011d452cf5Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds)); 1602fa9e4066Sahrens 16031d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 16041d452cf5Sahrens err = zap_remove(mos, hds->ds_phys->ds_snapnames_zapobj, 16051d452cf5Sahrens ds->ds_snapname, tx); 1606fa9e4066Sahrens ASSERT3U(err, ==, 0); 16071d452cf5Sahrens mutex_enter(&ds->ds_lock); 16081d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 16091d452cf5Sahrens mutex_exit(&ds->ds_lock); 16101d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 16111d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 1612fa9e4066Sahrens ASSERT3U(err, ==, 0); 1613fa9e4066Sahrens 1614ecd6cf80Smarks spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 1615ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 16161d452cf5Sahrens dsl_dataset_close(hds, DS_MODE_NONE, FTAG); 1617fa9e4066Sahrens } 1618fa9e4066Sahrens 1619*f18faf3fSek struct renamesnaparg { 1620cdf5b4caSmmusante dsl_sync_task_group_t *dstg; 1621cdf5b4caSmmusante char failed[MAXPATHLEN]; 1622cdf5b4caSmmusante char *oldsnap; 1623cdf5b4caSmmusante char *newsnap; 1624cdf5b4caSmmusante }; 1625cdf5b4caSmmusante 1626cdf5b4caSmmusante static int 1627cdf5b4caSmmusante dsl_snapshot_rename_one(char *name, void *arg) 1628cdf5b4caSmmusante { 1629*f18faf3fSek struct renamesnaparg *ra = arg; 1630cdf5b4caSmmusante dsl_dataset_t *ds = NULL; 1631cdf5b4caSmmusante char *cp; 1632cdf5b4caSmmusante int err; 1633cdf5b4caSmmusante 1634cdf5b4caSmmusante cp = name + strlen(name); 1635cdf5b4caSmmusante *cp = '@'; 1636cdf5b4caSmmusante (void) strcpy(cp + 1, ra->oldsnap); 1637ecd6cf80Smarks 1638ecd6cf80Smarks /* 1639ecd6cf80Smarks * For recursive snapshot renames the parent won't be changing 1640ecd6cf80Smarks * so we just pass name for both the to/from argument. 1641ecd6cf80Smarks */ 1642ecd6cf80Smarks if (err = zfs_secpolicy_rename_perms(name, name, CRED())) { 1643ecd6cf80Smarks (void) strcpy(ra->failed, name); 1644ecd6cf80Smarks return (err); 1645ecd6cf80Smarks } 1646ecd6cf80Smarks 1647cdf5b4caSmmusante err = dsl_dataset_open(name, DS_MODE_READONLY | DS_MODE_STANDARD, 1648cdf5b4caSmmusante ra->dstg, &ds); 1649cdf5b4caSmmusante if (err == ENOENT) { 1650cdf5b4caSmmusante *cp = '\0'; 1651cdf5b4caSmmusante return (0); 1652cdf5b4caSmmusante } 1653cdf5b4caSmmusante if (err) { 1654cdf5b4caSmmusante (void) strcpy(ra->failed, name); 1655cdf5b4caSmmusante *cp = '\0'; 1656cdf5b4caSmmusante dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg); 1657cdf5b4caSmmusante return (err); 1658cdf5b4caSmmusante } 1659cdf5b4caSmmusante 1660cdf5b4caSmmusante #ifdef _KERNEL 1661cdf5b4caSmmusante /* for all filesystems undergoing rename, we'll need to unmount it */ 1662cdf5b4caSmmusante (void) zfs_unmount_snap(name, NULL); 1663cdf5b4caSmmusante #endif 1664cdf5b4caSmmusante 1665cdf5b4caSmmusante *cp = '\0'; 1666cdf5b4caSmmusante 1667cdf5b4caSmmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 1668cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 1669cdf5b4caSmmusante 1670cdf5b4caSmmusante return (0); 1671cdf5b4caSmmusante } 1672cdf5b4caSmmusante 1673cdf5b4caSmmusante static int 1674cdf5b4caSmmusante dsl_recursive_rename(char *oldname, const char *newname) 1675cdf5b4caSmmusante { 1676cdf5b4caSmmusante int err; 1677*f18faf3fSek struct renamesnaparg *ra; 1678cdf5b4caSmmusante dsl_sync_task_t *dst; 1679cdf5b4caSmmusante spa_t *spa; 1680cdf5b4caSmmusante char *cp, *fsname = spa_strdup(oldname); 1681cdf5b4caSmmusante int len = strlen(oldname); 1682cdf5b4caSmmusante 1683cdf5b4caSmmusante /* truncate the snapshot name to get the fsname */ 1684cdf5b4caSmmusante cp = strchr(fsname, '@'); 1685cdf5b4caSmmusante *cp = '\0'; 1686cdf5b4caSmmusante 168740feaa91Sahrens err = spa_open(fsname, &spa, FTAG); 1688cdf5b4caSmmusante if (err) { 1689cdf5b4caSmmusante kmem_free(fsname, len + 1); 1690cdf5b4caSmmusante return (err); 1691cdf5b4caSmmusante } 1692*f18faf3fSek ra = kmem_alloc(sizeof (struct renamesnaparg), KM_SLEEP); 1693cdf5b4caSmmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 1694cdf5b4caSmmusante 1695cdf5b4caSmmusante ra->oldsnap = strchr(oldname, '@') + 1; 1696cdf5b4caSmmusante ra->newsnap = strchr(newname, '@') + 1; 1697cdf5b4caSmmusante *ra->failed = '\0'; 1698cdf5b4caSmmusante 1699cdf5b4caSmmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 1700cdf5b4caSmmusante DS_FIND_CHILDREN); 1701cdf5b4caSmmusante kmem_free(fsname, len + 1); 1702cdf5b4caSmmusante 1703cdf5b4caSmmusante if (err == 0) { 1704cdf5b4caSmmusante err = dsl_sync_task_group_wait(ra->dstg); 1705cdf5b4caSmmusante } 1706cdf5b4caSmmusante 1707cdf5b4caSmmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 1708cdf5b4caSmmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 1709cdf5b4caSmmusante dsl_dataset_t *ds = dst->dst_arg1; 1710cdf5b4caSmmusante if (dst->dst_err) { 1711cdf5b4caSmmusante dsl_dir_name(ds->ds_dir, ra->failed); 17122572aa4eSmmusante (void) strcat(ra->failed, "@"); 17132572aa4eSmmusante (void) strcat(ra->failed, ra->newsnap); 1714cdf5b4caSmmusante } 1715cdf5b4caSmmusante dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg); 1716cdf5b4caSmmusante } 1717cdf5b4caSmmusante 1718ecd6cf80Smarks if (err) 1719ecd6cf80Smarks (void) strcpy(oldname, ra->failed); 1720cdf5b4caSmmusante 1721cdf5b4caSmmusante dsl_sync_task_group_destroy(ra->dstg); 1722*f18faf3fSek kmem_free(ra, sizeof (struct renamesnaparg)); 1723cdf5b4caSmmusante spa_close(spa, FTAG); 1724cdf5b4caSmmusante return (err); 1725cdf5b4caSmmusante } 1726cdf5b4caSmmusante 17273a5a36beSmmusante static int 17283a5a36beSmmusante dsl_valid_rename(char *oldname, void *arg) 17293a5a36beSmmusante { 17303a5a36beSmmusante int delta = *(int *)arg; 17313a5a36beSmmusante 17323a5a36beSmmusante if (strlen(oldname) + delta >= MAXNAMELEN) 17333a5a36beSmmusante return (ENAMETOOLONG); 17343a5a36beSmmusante 17353a5a36beSmmusante return (0); 17363a5a36beSmmusante } 17373a5a36beSmmusante 1738fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 1739fa9e4066Sahrens int 1740cdf5b4caSmmusante dsl_dataset_rename(char *oldname, const char *newname, 1741cdf5b4caSmmusante boolean_t recursive) 1742fa9e4066Sahrens { 1743fa9e4066Sahrens dsl_dir_t *dd; 17441d452cf5Sahrens dsl_dataset_t *ds; 1745fa9e4066Sahrens const char *tail; 1746fa9e4066Sahrens int err; 1747fa9e4066Sahrens 17481d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 1749ea8dc4b6Seschrock if (err) 1750ea8dc4b6Seschrock return (err); 1751fa9e4066Sahrens if (tail == NULL) { 17523a5a36beSmmusante int delta = strlen(newname) - strlen(oldname); 17533a5a36beSmmusante 17543a5a36beSmmusante /* if we're growing, validate child size lengths */ 17553a5a36beSmmusante if (delta > 0) 17563a5a36beSmmusante err = dmu_objset_find(oldname, dsl_valid_rename, 17573a5a36beSmmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 17583a5a36beSmmusante 17593a5a36beSmmusante if (!err) 17603a5a36beSmmusante err = dsl_dir_rename(dd, newname); 1761fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1762fa9e4066Sahrens return (err); 1763fa9e4066Sahrens } 1764fa9e4066Sahrens if (tail[0] != '@') { 1765fa9e4066Sahrens /* the name ended in a nonexistant component */ 1766fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1767fa9e4066Sahrens return (ENOENT); 1768fa9e4066Sahrens } 1769fa9e4066Sahrens 1770fa9e4066Sahrens dsl_dir_close(dd, FTAG); 17711d452cf5Sahrens 17721d452cf5Sahrens /* new name must be snapshot in same filesystem */ 17731d452cf5Sahrens tail = strchr(newname, '@'); 17741d452cf5Sahrens if (tail == NULL) 17751d452cf5Sahrens return (EINVAL); 17761d452cf5Sahrens tail++; 17771d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 17781d452cf5Sahrens return (EXDEV); 17791d452cf5Sahrens 1780cdf5b4caSmmusante if (recursive) { 1781cdf5b4caSmmusante err = dsl_recursive_rename(oldname, newname); 1782cdf5b4caSmmusante } else { 1783cdf5b4caSmmusante err = dsl_dataset_open(oldname, 1784cdf5b4caSmmusante DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &ds); 1785cdf5b4caSmmusante if (err) 1786cdf5b4caSmmusante return (err); 17871d452cf5Sahrens 1788cdf5b4caSmmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 1789cdf5b4caSmmusante dsl_dataset_snapshot_rename_check, 1790cdf5b4caSmmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 17911d452cf5Sahrens 1792cdf5b4caSmmusante dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG); 1793cdf5b4caSmmusante } 17941d452cf5Sahrens 1795fa9e4066Sahrens return (err); 1796fa9e4066Sahrens } 179799653d4eSeschrock 17981d452cf5Sahrens struct promotearg { 17991d452cf5Sahrens uint64_t used, comp, uncomp, unique; 18001d452cf5Sahrens uint64_t newnext_obj, snapnames_obj; 18011d452cf5Sahrens }; 18021d452cf5Sahrens 1803ecd6cf80Smarks /* ARGSUSED */ 180499653d4eSeschrock static int 18051d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 180699653d4eSeschrock { 18071d452cf5Sahrens dsl_dataset_t *hds = arg1; 18081d452cf5Sahrens struct promotearg *pa = arg2; 18091d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 18101d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 181199653d4eSeschrock dsl_dir_t *pdd = NULL; 181299653d4eSeschrock dsl_dataset_t *ds = NULL; 181399653d4eSeschrock dsl_dataset_t *pivot_ds = NULL; 181499653d4eSeschrock dsl_dataset_t *newnext_ds = NULL; 181599653d4eSeschrock int err; 181699653d4eSeschrock char *name = NULL; 18171d452cf5Sahrens uint64_t itor = 0; 181899653d4eSeschrock blkptr_t bp; 181999653d4eSeschrock 18201d452cf5Sahrens bzero(pa, sizeof (*pa)); 18211d452cf5Sahrens 182299653d4eSeschrock /* Check that it is a clone */ 182399653d4eSeschrock if (dd->dd_phys->dd_clone_parent_obj == 0) 182499653d4eSeschrock return (EINVAL); 182599653d4eSeschrock 18261d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 18271d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 18281d452cf5Sahrens return (0); 18291d452cf5Sahrens 18301d452cf5Sahrens if (err = dsl_dataset_open_obj(dp, 183199653d4eSeschrock dd->dd_phys->dd_clone_parent_obj, 183299653d4eSeschrock NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)) 183399653d4eSeschrock goto out; 183499653d4eSeschrock pdd = pivot_ds->ds_dir; 18351d452cf5Sahrens 18361d452cf5Sahrens { 18371d452cf5Sahrens dsl_dataset_t *phds; 18381d452cf5Sahrens if (err = dsl_dataset_open_obj(dd->dd_pool, 18391d452cf5Sahrens pdd->dd_phys->dd_head_dataset_obj, 18401d452cf5Sahrens NULL, DS_MODE_NONE, FTAG, &phds)) 18411d452cf5Sahrens goto out; 18421d452cf5Sahrens pa->snapnames_obj = phds->ds_phys->ds_snapnames_zapobj; 18431d452cf5Sahrens dsl_dataset_close(phds, DS_MODE_NONE, FTAG); 18441d452cf5Sahrens } 184599653d4eSeschrock 184699653d4eSeschrock if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) { 184799653d4eSeschrock err = EXDEV; 184899653d4eSeschrock goto out; 184999653d4eSeschrock } 185099653d4eSeschrock 185199653d4eSeschrock /* find pivot point's new next ds */ 185299653d4eSeschrock VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, hds->ds_object, 185399653d4eSeschrock NULL, DS_MODE_NONE, FTAG, &newnext_ds)); 185499653d4eSeschrock while (newnext_ds->ds_phys->ds_prev_snap_obj != pivot_ds->ds_object) { 185599653d4eSeschrock dsl_dataset_t *prev; 185699653d4eSeschrock 185799653d4eSeschrock if (err = dsl_dataset_open_obj(dd->dd_pool, 18581d452cf5Sahrens newnext_ds->ds_phys->ds_prev_snap_obj, 18591d452cf5Sahrens NULL, DS_MODE_NONE, FTAG, &prev)) 186099653d4eSeschrock goto out; 186199653d4eSeschrock dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); 186299653d4eSeschrock newnext_ds = prev; 186399653d4eSeschrock } 18641d452cf5Sahrens pa->newnext_obj = newnext_ds->ds_object; 186599653d4eSeschrock 186699653d4eSeschrock /* compute pivot point's new unique space */ 186799653d4eSeschrock while ((err = bplist_iterate(&newnext_ds->ds_deadlist, 186899653d4eSeschrock &itor, &bp)) == 0) { 186999653d4eSeschrock if (bp.blk_birth > pivot_ds->ds_phys->ds_prev_snap_txg) 18701d452cf5Sahrens pa->unique += bp_get_dasize(dd->dd_pool->dp_spa, &bp); 187199653d4eSeschrock } 187299653d4eSeschrock if (err != ENOENT) 187399653d4eSeschrock goto out; 187499653d4eSeschrock 187599653d4eSeschrock /* Walk the snapshots that we are moving */ 187699653d4eSeschrock name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 187799653d4eSeschrock ds = pivot_ds; 187899653d4eSeschrock /* CONSTCOND */ 187999653d4eSeschrock while (TRUE) { 188099653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 188199653d4eSeschrock dsl_dataset_t *prev; 188299653d4eSeschrock 188399653d4eSeschrock /* Check that the snapshot name does not conflict */ 188499653d4eSeschrock dsl_dataset_name(ds, name); 188599653d4eSeschrock err = zap_lookup(dd->dd_pool->dp_meta_objset, 188699653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 188799653d4eSeschrock 8, 1, &val); 188899653d4eSeschrock if (err != ENOENT) { 188999653d4eSeschrock if (err == 0) 189099653d4eSeschrock err = EEXIST; 189199653d4eSeschrock goto out; 189299653d4eSeschrock } 189399653d4eSeschrock 189499653d4eSeschrock /* 189599653d4eSeschrock * compute space to transfer. Each snapshot gave birth to: 189699653d4eSeschrock * (my used) - (prev's used) + (deadlist's used) 189799653d4eSeschrock */ 18981d452cf5Sahrens pa->used += ds->ds_phys->ds_used_bytes; 18991d452cf5Sahrens pa->comp += ds->ds_phys->ds_compressed_bytes; 19001d452cf5Sahrens pa->uncomp += ds->ds_phys->ds_uncompressed_bytes; 190199653d4eSeschrock 190299653d4eSeschrock /* If we reach the first snapshot, we're done. */ 190399653d4eSeschrock if (ds->ds_phys->ds_prev_snap_obj == 0) 190499653d4eSeschrock break; 190599653d4eSeschrock 190699653d4eSeschrock if (err = bplist_space(&ds->ds_deadlist, 190799653d4eSeschrock &dlused, &dlcomp, &dluncomp)) 190899653d4eSeschrock goto out; 190999653d4eSeschrock if (err = dsl_dataset_open_obj(dd->dd_pool, 191099653d4eSeschrock ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, 191199653d4eSeschrock FTAG, &prev)) 191299653d4eSeschrock goto out; 19131d452cf5Sahrens pa->used += dlused - prev->ds_phys->ds_used_bytes; 19141d452cf5Sahrens pa->comp += dlcomp - prev->ds_phys->ds_compressed_bytes; 19151d452cf5Sahrens pa->uncomp += dluncomp - prev->ds_phys->ds_uncompressed_bytes; 191699653d4eSeschrock 191799653d4eSeschrock /* 191899653d4eSeschrock * We could be a clone of a clone. If we reach our 191999653d4eSeschrock * parent's branch point, we're done. 192099653d4eSeschrock */ 192199653d4eSeschrock if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { 192299653d4eSeschrock dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); 192399653d4eSeschrock break; 192499653d4eSeschrock } 192599653d4eSeschrock if (ds != pivot_ds) 192699653d4eSeschrock dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 192799653d4eSeschrock ds = prev; 192899653d4eSeschrock } 192999653d4eSeschrock 193099653d4eSeschrock /* Check that there is enough space here */ 19311d452cf5Sahrens err = dsl_dir_transfer_possible(pdd, dd, pa->used); 19321d452cf5Sahrens 19331d452cf5Sahrens out: 19341d452cf5Sahrens if (ds && ds != pivot_ds) 19351d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 19361d452cf5Sahrens if (pivot_ds) 19371d452cf5Sahrens dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); 19381d452cf5Sahrens if (newnext_ds) 19391d452cf5Sahrens dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); 19401d452cf5Sahrens if (name) 19411d452cf5Sahrens kmem_free(name, MAXPATHLEN); 19421d452cf5Sahrens return (err); 19431d452cf5Sahrens } 194499653d4eSeschrock 19451d452cf5Sahrens static void 1946ecd6cf80Smarks dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 19471d452cf5Sahrens { 19481d452cf5Sahrens dsl_dataset_t *hds = arg1; 19491d452cf5Sahrens struct promotearg *pa = arg2; 19501d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 19511d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 19521d452cf5Sahrens dsl_dir_t *pdd = NULL; 19531d452cf5Sahrens dsl_dataset_t *ds, *pivot_ds; 19541d452cf5Sahrens char *name; 19551d452cf5Sahrens 19561d452cf5Sahrens ASSERT(dd->dd_phys->dd_clone_parent_obj != 0); 19571d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 19581d452cf5Sahrens 19591d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 19601d452cf5Sahrens dd->dd_phys->dd_clone_parent_obj, 19611d452cf5Sahrens NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)); 19620b69c2f0Sahrens /* 19630b69c2f0Sahrens * We need to explicitly open pdd, since pivot_ds's pdd will be 19640b69c2f0Sahrens * changing. 19650b69c2f0Sahrens */ 19660b69c2f0Sahrens VERIFY(0 == dsl_dir_open_obj(dp, pivot_ds->ds_dir->dd_object, 19670b69c2f0Sahrens NULL, FTAG, &pdd)); 196899653d4eSeschrock 196999653d4eSeschrock /* move snapshots to this dir */ 19701d452cf5Sahrens name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 197199653d4eSeschrock ds = pivot_ds; 197299653d4eSeschrock /* CONSTCOND */ 197399653d4eSeschrock while (TRUE) { 197499653d4eSeschrock dsl_dataset_t *prev; 197599653d4eSeschrock 197699653d4eSeschrock /* move snap name entry */ 197799653d4eSeschrock dsl_dataset_name(ds, name); 19781d452cf5Sahrens VERIFY(0 == zap_remove(dp->dp_meta_objset, 19791d452cf5Sahrens pa->snapnames_obj, ds->ds_snapname, tx)); 19801d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 198199653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 198299653d4eSeschrock 8, 1, &ds->ds_object, tx)); 198399653d4eSeschrock 198499653d4eSeschrock /* change containing dsl_dir */ 198599653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 198699653d4eSeschrock ASSERT3U(ds->ds_phys->ds_dir_obj, ==, pdd->dd_object); 198799653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 198899653d4eSeschrock ASSERT3P(ds->ds_dir, ==, pdd); 198999653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 19901d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 199199653d4eSeschrock NULL, ds, &ds->ds_dir)); 199299653d4eSeschrock 199399653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 199499653d4eSeschrock 199599653d4eSeschrock if (ds->ds_phys->ds_prev_snap_obj == 0) 199699653d4eSeschrock break; 199799653d4eSeschrock 19981d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 199999653d4eSeschrock ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, 200099653d4eSeschrock FTAG, &prev)); 200199653d4eSeschrock 200299653d4eSeschrock if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { 200399653d4eSeschrock dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); 200499653d4eSeschrock break; 200599653d4eSeschrock } 200699653d4eSeschrock if (ds != pivot_ds) 200799653d4eSeschrock dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 200899653d4eSeschrock ds = prev; 200999653d4eSeschrock } 20101d452cf5Sahrens if (ds != pivot_ds) 20111d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 201299653d4eSeschrock 201399653d4eSeschrock /* change pivot point's next snap */ 201499653d4eSeschrock dmu_buf_will_dirty(pivot_ds->ds_dbuf, tx); 20151d452cf5Sahrens pivot_ds->ds_phys->ds_next_snap_obj = pa->newnext_obj; 201699653d4eSeschrock 201799653d4eSeschrock /* change clone_parent-age */ 201899653d4eSeschrock dmu_buf_will_dirty(dd->dd_dbuf, tx); 201999653d4eSeschrock ASSERT3U(dd->dd_phys->dd_clone_parent_obj, ==, pivot_ds->ds_object); 202099653d4eSeschrock dd->dd_phys->dd_clone_parent_obj = pdd->dd_phys->dd_clone_parent_obj; 202199653d4eSeschrock dmu_buf_will_dirty(pdd->dd_dbuf, tx); 202299653d4eSeschrock pdd->dd_phys->dd_clone_parent_obj = pivot_ds->ds_object; 202399653d4eSeschrock 202499653d4eSeschrock /* change space accounting */ 20251d452cf5Sahrens dsl_dir_diduse_space(pdd, -pa->used, -pa->comp, -pa->uncomp, tx); 20261d452cf5Sahrens dsl_dir_diduse_space(dd, pa->used, pa->comp, pa->uncomp, tx); 20271d452cf5Sahrens pivot_ds->ds_phys->ds_unique_bytes = pa->unique; 202899653d4eSeschrock 2029ecd6cf80Smarks /* log history record */ 2030ecd6cf80Smarks spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 2031ecd6cf80Smarks cr, "dataset = %llu", ds->ds_object); 2032ecd6cf80Smarks 20330b69c2f0Sahrens dsl_dir_close(pdd, FTAG); 20341d452cf5Sahrens dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); 20351d452cf5Sahrens kmem_free(name, MAXPATHLEN); 203699653d4eSeschrock } 203799653d4eSeschrock 203899653d4eSeschrock int 203999653d4eSeschrock dsl_dataset_promote(const char *name) 204099653d4eSeschrock { 204199653d4eSeschrock dsl_dataset_t *ds; 204299653d4eSeschrock int err; 204399653d4eSeschrock dmu_object_info_t doi; 20441d452cf5Sahrens struct promotearg pa; 204599653d4eSeschrock 204699653d4eSeschrock err = dsl_dataset_open(name, DS_MODE_NONE, FTAG, &ds); 204799653d4eSeschrock if (err) 204899653d4eSeschrock return (err); 204999653d4eSeschrock 205099653d4eSeschrock err = dmu_object_info(ds->ds_dir->dd_pool->dp_meta_objset, 205199653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 205299653d4eSeschrock if (err) { 205399653d4eSeschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 205499653d4eSeschrock return (err); 205599653d4eSeschrock } 205699653d4eSeschrock 205799653d4eSeschrock /* 205899653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 205999653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 206099653d4eSeschrock * bonus buffers. 206199653d4eSeschrock */ 20621d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 20631d452cf5Sahrens dsl_dataset_promote_check, 20641d452cf5Sahrens dsl_dataset_promote_sync, ds, &pa, 2 + 2 * doi.doi_physical_blks); 206599653d4eSeschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 206699653d4eSeschrock return (err); 206799653d4eSeschrock } 2068b1b8ab34Slling 2069*f18faf3fSek #define SWITCH64(x, y) \ 2070*f18faf3fSek { \ 2071*f18faf3fSek uint64_t __tmp = (x); \ 2072*f18faf3fSek (x) = (y); \ 2073*f18faf3fSek (y) = __tmp; \ 2074*f18faf3fSek } 2075*f18faf3fSek 2076*f18faf3fSek /* ARGSUSED */ 2077*f18faf3fSek static int 2078*f18faf3fSek dsl_dataset_clone_swap_check(void *arg1, void *arg2, dmu_tx_t *tx) 2079*f18faf3fSek { 2080*f18faf3fSek dsl_dataset_t *cds = arg1; /* clone to become new head */ 2081*f18faf3fSek boolean_t *forcep = arg2; 2082*f18faf3fSek dsl_dir_t *cdd = cds->ds_dir; 2083*f18faf3fSek dsl_pool_t *dp = cds->ds_dir->dd_pool; 2084*f18faf3fSek dsl_dataset_t *ods; /* the snapshot cds is cloned off of */ 2085*f18faf3fSek dsl_dataset_t *ohds = NULL; 2086*f18faf3fSek dsl_dir_t *odd; 2087*f18faf3fSek int err; 2088*f18faf3fSek 2089*f18faf3fSek /* check that it is a clone */ 2090*f18faf3fSek if (cdd->dd_phys->dd_clone_parent_obj == 0) 2091*f18faf3fSek return (EINVAL); 2092*f18faf3fSek 2093*f18faf3fSek /* check that cds is not a snapshot */ 2094*f18faf3fSek if (dsl_dataset_is_snapshot(cds)) 2095*f18faf3fSek return (EINVAL); 2096*f18faf3fSek 2097*f18faf3fSek /* open the origin */ 2098*f18faf3fSek if (err = dsl_dataset_open_obj(dp, cdd->dd_phys->dd_clone_parent_obj, 2099*f18faf3fSek NULL, DS_MODE_STANDARD | DS_MODE_READONLY, FTAG, &ods)) 2100*f18faf3fSek return (err); 2101*f18faf3fSek odd = ods->ds_dir; 2102*f18faf3fSek 2103*f18faf3fSek /* make sure the clone is descendant of origin */ 2104*f18faf3fSek if (cdd->dd_parent != odd) { 2105*f18faf3fSek err = EINVAL; 2106*f18faf3fSek goto out; 2107*f18faf3fSek } 2108*f18faf3fSek 2109*f18faf3fSek /* check that there are no snapshots after the origin */ 2110*f18faf3fSek if (cds->ds_phys->ds_prev_snap_obj != ods->ds_object || 2111*f18faf3fSek ods->ds_phys->ds_next_snap_obj != 2112*f18faf3fSek odd->dd_phys->dd_head_dataset_obj) { 2113*f18faf3fSek err = EINVAL; 2114*f18faf3fSek goto out; 2115*f18faf3fSek } 2116*f18faf3fSek 2117*f18faf3fSek /* 2118*f18faf3fSek * Verify origin head dataset hasn't been modified or 2119*f18faf3fSek * 'force' has been passed down. 2120*f18faf3fSek */ 2121*f18faf3fSek if (!(*forcep) && 2122*f18faf3fSek (err = dsl_dataset_open_obj(cdd->dd_pool, 2123*f18faf3fSek odd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_EXCLUSIVE, 2124*f18faf3fSek FTAG, &ohds)) == 0) { 2125*f18faf3fSek if (dsl_dataset_modified_since_lastsnap(ohds)) 2126*f18faf3fSek err = ETXTBSY; 2127*f18faf3fSek dsl_dataset_close(ohds, DS_MODE_EXCLUSIVE, FTAG); 2128*f18faf3fSek } 2129*f18faf3fSek out: 2130*f18faf3fSek dsl_dataset_close(ods, DS_MODE_STANDARD, FTAG); 2131*f18faf3fSek return (err); 2132*f18faf3fSek } 2133*f18faf3fSek 2134*f18faf3fSek /* ARGSUSED */ 2135*f18faf3fSek static void 2136*f18faf3fSek dsl_dataset_clone_swap_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 2137*f18faf3fSek { 2138*f18faf3fSek dsl_dataset_t *cds = arg1; /* clone to become new head */ 2139*f18faf3fSek dsl_dir_t *cdd = cds->ds_dir; 2140*f18faf3fSek dsl_pool_t *dp = cds->ds_dir->dd_pool; 2141*f18faf3fSek dsl_dataset_t *ods, *ohds; 2142*f18faf3fSek dsl_dir_t *odd; 2143*f18faf3fSek uint64_t itor = 0; 2144*f18faf3fSek blkptr_t bp; 2145*f18faf3fSek uint64_t unique = 0; 2146*f18faf3fSek int err; 2147*f18faf3fSek 2148*f18faf3fSek ASSERT(cdd->dd_phys->dd_clone_parent_obj != 0); 2149*f18faf3fSek ASSERT(dsl_dataset_is_snapshot(cds) == 0); 2150*f18faf3fSek 2151*f18faf3fSek /* open the origin */ 2152*f18faf3fSek VERIFY(0 == dsl_dataset_open_obj(dp, cdd->dd_phys->dd_clone_parent_obj, 2153*f18faf3fSek NULL, DS_MODE_STANDARD | DS_MODE_READONLY, FTAG, &ods)); 2154*f18faf3fSek odd = ods->ds_dir; 2155*f18faf3fSek ASSERT(cds->ds_phys->ds_prev_snap_obj == ods->ds_object); 2156*f18faf3fSek ASSERT(ods->ds_phys->ds_next_snap_obj == 2157*f18faf3fSek odd->dd_phys->dd_head_dataset_obj); 2158*f18faf3fSek 2159*f18faf3fSek /* open the origin head */ 2160*f18faf3fSek VERIFY(0 == dsl_dataset_open_obj(cdd->dd_pool, 2161*f18faf3fSek odd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_EXCLUSIVE, 2162*f18faf3fSek FTAG, &ohds)); 2163*f18faf3fSek ASSERT(odd == ohds->ds_dir); 2164*f18faf3fSek 2165*f18faf3fSek dmu_buf_will_dirty(cds->ds_dbuf, tx); 2166*f18faf3fSek dmu_buf_will_dirty(ohds->ds_dbuf, tx); 2167*f18faf3fSek dmu_buf_will_dirty(ods->ds_dbuf, tx); 2168*f18faf3fSek 2169*f18faf3fSek /* compute unique space */ 2170*f18faf3fSek while ((err = bplist_iterate(&cds->ds_deadlist, &itor, &bp)) == 0) { 2171*f18faf3fSek if (bp.blk_birth > ods->ds_phys->ds_prev_snap_txg) 2172*f18faf3fSek unique += bp_get_dasize(cdd->dd_pool->dp_spa, &bp); 2173*f18faf3fSek } 2174*f18faf3fSek VERIFY(err == ENOENT); 2175*f18faf3fSek 2176*f18faf3fSek /* reset origin's unique bytes */ 2177*f18faf3fSek ods->ds_phys->ds_unique_bytes = unique; 2178*f18faf3fSek 2179*f18faf3fSek /* swap blkptrs */ 2180*f18faf3fSek { 2181*f18faf3fSek blkptr_t tmp; 2182*f18faf3fSek tmp = ohds->ds_phys->ds_bp; 2183*f18faf3fSek ohds->ds_phys->ds_bp = cds->ds_phys->ds_bp; 2184*f18faf3fSek cds->ds_phys->ds_bp = tmp; 2185*f18faf3fSek } 2186*f18faf3fSek 2187*f18faf3fSek /* set dd_*_bytes */ 2188*f18faf3fSek { 2189*f18faf3fSek int64_t dused, dcomp, duncomp; 2190*f18faf3fSek uint64_t cdl_used, cdl_comp, cdl_uncomp; 2191*f18faf3fSek uint64_t odl_used, odl_comp, odl_uncomp; 2192*f18faf3fSek 2193*f18faf3fSek VERIFY(0 == bplist_space(&cds->ds_deadlist, &cdl_used, 2194*f18faf3fSek &cdl_comp, &cdl_uncomp)); 2195*f18faf3fSek VERIFY(0 == bplist_space(&ohds->ds_deadlist, &odl_used, 2196*f18faf3fSek &odl_comp, &odl_uncomp)); 2197*f18faf3fSek dused = cds->ds_phys->ds_used_bytes + cdl_used - 2198*f18faf3fSek (ohds->ds_phys->ds_used_bytes + odl_used); 2199*f18faf3fSek dcomp = cds->ds_phys->ds_compressed_bytes + cdl_comp - 2200*f18faf3fSek (ohds->ds_phys->ds_compressed_bytes + odl_comp); 2201*f18faf3fSek duncomp = cds->ds_phys->ds_uncompressed_bytes + cdl_uncomp - 2202*f18faf3fSek (ohds->ds_phys->ds_uncompressed_bytes + odl_uncomp); 2203*f18faf3fSek 2204*f18faf3fSek dsl_dir_diduse_space(odd, dused, dcomp, duncomp, tx); 2205*f18faf3fSek dsl_dir_diduse_space(cdd, -dused, -dcomp, -duncomp, tx); 2206*f18faf3fSek } 2207*f18faf3fSek 2208*f18faf3fSek /* swap ds_*_bytes */ 2209*f18faf3fSek SWITCH64(ohds->ds_phys->ds_used_bytes, cds->ds_phys->ds_used_bytes); 2210*f18faf3fSek SWITCH64(ohds->ds_phys->ds_compressed_bytes, 2211*f18faf3fSek cds->ds_phys->ds_compressed_bytes); 2212*f18faf3fSek SWITCH64(ohds->ds_phys->ds_uncompressed_bytes, 2213*f18faf3fSek cds->ds_phys->ds_uncompressed_bytes); 2214*f18faf3fSek 2215*f18faf3fSek /* swap deadlists */ 2216*f18faf3fSek bplist_close(&cds->ds_deadlist); 2217*f18faf3fSek bplist_close(&ohds->ds_deadlist); 2218*f18faf3fSek SWITCH64(ohds->ds_phys->ds_deadlist_obj, cds->ds_phys->ds_deadlist_obj); 2219*f18faf3fSek VERIFY(0 == bplist_open(&cds->ds_deadlist, dp->dp_meta_objset, 2220*f18faf3fSek cds->ds_phys->ds_deadlist_obj)); 2221*f18faf3fSek VERIFY(0 == bplist_open(&ohds->ds_deadlist, dp->dp_meta_objset, 2222*f18faf3fSek ohds->ds_phys->ds_deadlist_obj)); 2223*f18faf3fSek 2224*f18faf3fSek dsl_dataset_close(ohds, DS_MODE_EXCLUSIVE, FTAG); 2225*f18faf3fSek dsl_dataset_close(ods, DS_MODE_STANDARD, FTAG); 2226*f18faf3fSek } 2227*f18faf3fSek 2228*f18faf3fSek /* 2229*f18faf3fSek * Swap the clone "cosname" with its origin head file system. 2230*f18faf3fSek */ 2231*f18faf3fSek int 2232*f18faf3fSek dsl_dataset_clone_swap(const char *cosname, boolean_t force) 2233*f18faf3fSek { 2234*f18faf3fSek dsl_dataset_t *ds; 2235*f18faf3fSek int err; 2236*f18faf3fSek 2237*f18faf3fSek err = dsl_dataset_open(cosname, 2238*f18faf3fSek DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, FTAG, &ds); 2239*f18faf3fSek if (err) 2240*f18faf3fSek return (err); 2241*f18faf3fSek 2242*f18faf3fSek err = dsl_sync_task_do(ds->ds_dir->dd_pool, 2243*f18faf3fSek dsl_dataset_clone_swap_check, 2244*f18faf3fSek dsl_dataset_clone_swap_sync, ds, &force, 9); 2245*f18faf3fSek dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 2246*f18faf3fSek return (err); 2247*f18faf3fSek } 2248*f18faf3fSek 2249b1b8ab34Slling /* 2250b1b8ab34Slling * Given a pool name and a dataset object number in that pool, 2251b1b8ab34Slling * return the name of that dataset. 2252b1b8ab34Slling */ 2253b1b8ab34Slling int 2254b1b8ab34Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 2255b1b8ab34Slling { 2256b1b8ab34Slling spa_t *spa; 2257b1b8ab34Slling dsl_pool_t *dp; 2258b1b8ab34Slling dsl_dataset_t *ds = NULL; 2259b1b8ab34Slling int error; 2260b1b8ab34Slling 2261b1b8ab34Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 2262b1b8ab34Slling return (error); 2263b1b8ab34Slling dp = spa_get_dsl(spa); 2264b1b8ab34Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 2265b1b8ab34Slling if ((error = dsl_dataset_open_obj(dp, obj, 2266b1b8ab34Slling NULL, DS_MODE_NONE, FTAG, &ds)) != 0) { 2267b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 2268b1b8ab34Slling spa_close(spa, FTAG); 2269b1b8ab34Slling return (error); 2270b1b8ab34Slling } 2271b1b8ab34Slling dsl_dataset_name(ds, buf); 2272b1b8ab34Slling dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 2273b1b8ab34Slling rw_exit(&dp->dp_config_rwlock); 2274b1b8ab34Slling spa_close(spa, FTAG); 2275b1b8ab34Slling 2276b1b8ab34Slling return (0); 2277b1b8ab34Slling } 2278