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> 40fa9e4066Sahrens 411d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 421d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 431d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_rollback_check; 441d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_rollback_sync; 451d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_check; 461d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_sync; 47e1930233Sbonwick 4855434c77Sek #define DS_REF_MAX (1ULL << 62) 49fa9e4066Sahrens 50fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 51fa9e4066Sahrens 52fa9e4066Sahrens /* 53fa9e4066Sahrens * We use weighted reference counts to express the various forms of exclusion 54fa9e4066Sahrens * between different open modes. A STANDARD open is 1 point, an EXCLUSIVE open 5555434c77Sek * is DS_REF_MAX, and a PRIMARY open is little more than half of an EXCLUSIVE. 56fa9e4066Sahrens * This makes the exclusion logic simple: the total refcnt for all opens cannot 5755434c77Sek * exceed DS_REF_MAX. For example, EXCLUSIVE opens are exclusive because their 5855434c77Sek * weight (DS_REF_MAX) consumes the entire refcnt space. PRIMARY opens consume 59fa9e4066Sahrens * just over half of the refcnt space, so there can't be more than one, but it 60fa9e4066Sahrens * can peacefully coexist with any number of STANDARD opens. 61fa9e4066Sahrens */ 62fa9e4066Sahrens static uint64_t ds_refcnt_weight[DS_MODE_LEVELS] = { 6355434c77Sek 0, /* DS_MODE_NONE - invalid */ 6455434c77Sek 1, /* DS_MODE_STANDARD - unlimited number */ 6555434c77Sek (DS_REF_MAX >> 1) + 1, /* DS_MODE_PRIMARY - only one of these */ 6655434c77Sek DS_REF_MAX /* DS_MODE_EXCLUSIVE - no other opens */ 67fa9e4066Sahrens }; 68fa9e4066Sahrens 69fa9e4066Sahrens 70fa9e4066Sahrens void 71fa9e4066Sahrens dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 72fa9e4066Sahrens { 7399653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 74fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 75fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 76fa9e4066Sahrens 77fa9e4066Sahrens dprintf_bp(bp, "born, ds=%p\n", ds); 78fa9e4066Sahrens 79fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 80fa9e4066Sahrens /* It could have been compressed away to nothing */ 81fa9e4066Sahrens if (BP_IS_HOLE(bp)) 82fa9e4066Sahrens return; 83fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 84fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 85fa9e4066Sahrens if (ds == NULL) { 86fa9e4066Sahrens /* 87fa9e4066Sahrens * Account for the meta-objset space in its placeholder 88fa9e4066Sahrens * dsl_dir. 89fa9e4066Sahrens */ 90fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 91fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 92fa9e4066Sahrens used, compressed, uncompressed, tx); 93fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 94fa9e4066Sahrens return; 95fa9e4066Sahrens } 96fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 97fa9e4066Sahrens mutex_enter(&ds->ds_lock); 98fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 99fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 100fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 101fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 102fa9e4066Sahrens mutex_exit(&ds->ds_lock); 103fa9e4066Sahrens dsl_dir_diduse_space(ds->ds_dir, 104fa9e4066Sahrens used, compressed, uncompressed, tx); 105fa9e4066Sahrens } 106fa9e4066Sahrens 107fa9e4066Sahrens void 108*c717a561Smaybee dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, zio_t *pio, 109*c717a561Smaybee dmu_tx_t *tx) 110fa9e4066Sahrens { 11199653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 112fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 113fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 114fa9e4066Sahrens 115fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 116*c717a561Smaybee /* No block pointer => nothing to free */ 117fa9e4066Sahrens if (BP_IS_HOLE(bp)) 118fa9e4066Sahrens return; 119fa9e4066Sahrens 120fa9e4066Sahrens ASSERT(used > 0); 121fa9e4066Sahrens if (ds == NULL) { 122*c717a561Smaybee int err; 123fa9e4066Sahrens /* 124fa9e4066Sahrens * Account for the meta-objset space in its placeholder 125fa9e4066Sahrens * dataset. 126fa9e4066Sahrens */ 127*c717a561Smaybee err = arc_free(pio, tx->tx_pool->dp_spa, 128*c717a561Smaybee tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); 129*c717a561Smaybee ASSERT(err == 0); 130fa9e4066Sahrens 131fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 132fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 133fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 134fa9e4066Sahrens return; 135fa9e4066Sahrens } 136fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 137fa9e4066Sahrens 138fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 139fa9e4066Sahrens 140fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 141*c717a561Smaybee int err; 142*c717a561Smaybee 143fa9e4066Sahrens dprintf_bp(bp, "freeing: %s", ""); 144*c717a561Smaybee err = arc_free(pio, tx->tx_pool->dp_spa, 145*c717a561Smaybee tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); 146*c717a561Smaybee ASSERT(err == 0); 147fa9e4066Sahrens 148fa9e4066Sahrens mutex_enter(&ds->ds_lock); 149fa9e4066Sahrens /* XXX unique_bytes is not accurate for head datasets */ 150fa9e4066Sahrens /* ASSERT3U(ds->ds_phys->ds_unique_bytes, >=, used); */ 151fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 152fa9e4066Sahrens mutex_exit(&ds->ds_lock); 153fa9e4066Sahrens dsl_dir_diduse_space(ds->ds_dir, 154fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 155fa9e4066Sahrens } else { 156fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 157ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 158fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 159fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 160fa9e4066Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, 161fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj); 162fa9e4066Sahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 163fa9e4066Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 16499653d4eSeschrock ds->ds_object && bp->blk_birth > 165fa9e4066Sahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 166fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 167fa9e4066Sahrens mutex_enter(&ds->ds_prev->ds_lock); 168fa9e4066Sahrens ds->ds_prev->ds_phys->ds_unique_bytes += 169fa9e4066Sahrens used; 170fa9e4066Sahrens mutex_exit(&ds->ds_prev->ds_lock); 171fa9e4066Sahrens } 172fa9e4066Sahrens } 173fa9e4066Sahrens } 174fa9e4066Sahrens mutex_enter(&ds->ds_lock); 175fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 176fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 177fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 178fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 179fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 180fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 181fa9e4066Sahrens mutex_exit(&ds->ds_lock); 182fa9e4066Sahrens } 183fa9e4066Sahrens 184ea8dc4b6Seschrock uint64_t 185ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 186fa9e4066Sahrens { 187a2eea2e1Sahrens uint64_t trysnap = 0; 188a2eea2e1Sahrens 189fa9e4066Sahrens if (ds == NULL) 190ea8dc4b6Seschrock return (0); 191fa9e4066Sahrens /* 192fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 193fa9e4066Sahrens * incorrect FALSE return, which would only result in an 194fa9e4066Sahrens * overestimation of the amount of space that an operation would 195fa9e4066Sahrens * consume, which is OK. 196fa9e4066Sahrens * 197fa9e4066Sahrens * There's also a small window where we could miss a pending 198fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 199fa9e4066Sahrens * phase. So this should only be used as a guess. 200fa9e4066Sahrens */ 201a2eea2e1Sahrens if (ds->ds_trysnap_txg > 202a2eea2e1Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 203a2eea2e1Sahrens trysnap = ds->ds_trysnap_txg; 204a2eea2e1Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 205ea8dc4b6Seschrock } 206ea8dc4b6Seschrock 207ea8dc4b6Seschrock int 208ea8dc4b6Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 209ea8dc4b6Seschrock { 210ea8dc4b6Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 211fa9e4066Sahrens } 212fa9e4066Sahrens 213fa9e4066Sahrens /* ARGSUSED */ 214fa9e4066Sahrens static void 215fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 216fa9e4066Sahrens { 217fa9e4066Sahrens dsl_dataset_t *ds = dsv; 218fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 219fa9e4066Sahrens 22055434c77Sek /* open_refcount == DS_REF_MAX when deleting */ 221fa9e4066Sahrens ASSERT(ds->ds_open_refcount == 0 || 22255434c77Sek ds->ds_open_refcount == DS_REF_MAX); 223fa9e4066Sahrens 224fa9e4066Sahrens dprintf_ds(ds, "evicting %s\n", ""); 225fa9e4066Sahrens 226fa9e4066Sahrens unique_remove(ds->ds_phys->ds_fsid_guid); 227fa9e4066Sahrens 228fa9e4066Sahrens if (ds->ds_user_ptr != NULL) 229fa9e4066Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 230fa9e4066Sahrens 231fa9e4066Sahrens if (ds->ds_prev) { 232fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 233fa9e4066Sahrens ds->ds_prev = NULL; 234fa9e4066Sahrens } 235fa9e4066Sahrens 236fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 237fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 238fa9e4066Sahrens 239fa9e4066Sahrens if (list_link_active(&ds->ds_synced_link)) 240fa9e4066Sahrens list_remove(&dp->dp_synced_objsets, ds); 241fa9e4066Sahrens 2425ad82045Snd mutex_destroy(&ds->ds_lock); 2435ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 2445ad82045Snd 245fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 246fa9e4066Sahrens } 247fa9e4066Sahrens 248ea8dc4b6Seschrock static int 249fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 250fa9e4066Sahrens { 251fa9e4066Sahrens dsl_dataset_phys_t *headphys; 252fa9e4066Sahrens int err; 253fa9e4066Sahrens dmu_buf_t *headdbuf; 254fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 255fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 256fa9e4066Sahrens 257fa9e4066Sahrens if (ds->ds_snapname[0]) 258ea8dc4b6Seschrock return (0); 259fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 260ea8dc4b6Seschrock return (0); 261fa9e4066Sahrens 262ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 263ea8dc4b6Seschrock FTAG, &headdbuf); 264ea8dc4b6Seschrock if (err) 265ea8dc4b6Seschrock return (err); 266fa9e4066Sahrens headphys = headdbuf->db_data; 267fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 268fa9e4066Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, ds->ds_snapname); 269ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 270ea8dc4b6Seschrock return (err); 271fa9e4066Sahrens } 272fa9e4066Sahrens 273ea8dc4b6Seschrock int 274fa9e4066Sahrens dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname, 275ea8dc4b6Seschrock int mode, void *tag, dsl_dataset_t **dsp) 276fa9e4066Sahrens { 277fa9e4066Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 278fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 279fa9e4066Sahrens dmu_buf_t *dbuf; 280fa9e4066Sahrens dsl_dataset_t *ds; 281ea8dc4b6Seschrock int err; 282fa9e4066Sahrens 283fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 284fa9e4066Sahrens dsl_pool_sync_context(dp)); 285fa9e4066Sahrens 286ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 287ea8dc4b6Seschrock if (err) 288ea8dc4b6Seschrock return (err); 289fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 290fa9e4066Sahrens if (ds == NULL) { 291fa9e4066Sahrens dsl_dataset_t *winner; 292fa9e4066Sahrens 293fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 294fa9e4066Sahrens ds->ds_dbuf = dbuf; 295fa9e4066Sahrens ds->ds_object = dsobj; 296fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 297fa9e4066Sahrens 2985ad82045Snd mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 2995ad82045Snd mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT, 3005ad82045Snd NULL); 3015ad82045Snd 302ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 303fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 304ea8dc4b6Seschrock if (err == 0) { 305ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 306ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 307ea8dc4b6Seschrock } 308ea8dc4b6Seschrock if (err) { 309ea8dc4b6Seschrock /* 310ea8dc4b6Seschrock * we don't really need to close the blist if we 311ea8dc4b6Seschrock * just opened it. 312ea8dc4b6Seschrock */ 3135ad82045Snd mutex_destroy(&ds->ds_lock); 3145ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 315ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 316ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 317ea8dc4b6Seschrock return (err); 318ea8dc4b6Seschrock } 319fa9e4066Sahrens 320fa9e4066Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == dsobj) { 321fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 322fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 323ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, 324fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 325ea8dc4b6Seschrock DS_MODE_NONE, ds, &ds->ds_prev); 326fa9e4066Sahrens } 327fa9e4066Sahrens } else { 328fa9e4066Sahrens if (snapname) { 329fa9e4066Sahrens #ifdef ZFS_DEBUG 330fa9e4066Sahrens dsl_dataset_phys_t *headphys; 331ea8dc4b6Seschrock dmu_buf_t *headdbuf; 332ea8dc4b6Seschrock err = dmu_bonus_hold(mos, 333ea8dc4b6Seschrock ds->ds_dir->dd_phys->dd_head_dataset_obj, 334ea8dc4b6Seschrock FTAG, &headdbuf); 335ea8dc4b6Seschrock if (err == 0) { 336ea8dc4b6Seschrock headphys = headdbuf->db_data; 337ea8dc4b6Seschrock uint64_t foundobj; 338ea8dc4b6Seschrock err = zap_lookup(dp->dp_meta_objset, 339ea8dc4b6Seschrock headphys->ds_snapnames_zapobj, 340ea8dc4b6Seschrock snapname, sizeof (foundobj), 1, 341ea8dc4b6Seschrock &foundobj); 342ea8dc4b6Seschrock ASSERT3U(foundobj, ==, dsobj); 343ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 344ea8dc4b6Seschrock } 345fa9e4066Sahrens #endif 346fa9e4066Sahrens (void) strcat(ds->ds_snapname, snapname); 347fa9e4066Sahrens } else if (zfs_flags & ZFS_DEBUG_SNAPNAMES) { 348ea8dc4b6Seschrock err = dsl_dataset_get_snapname(ds); 349fa9e4066Sahrens } 350fa9e4066Sahrens } 351fa9e4066Sahrens 352ea8dc4b6Seschrock if (err == 0) { 353ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 354ea8dc4b6Seschrock dsl_dataset_evict); 355ea8dc4b6Seschrock } 356ea8dc4b6Seschrock if (err || winner) { 357fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 358fa9e4066Sahrens if (ds->ds_prev) { 359fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, 360fa9e4066Sahrens DS_MODE_NONE, ds); 361fa9e4066Sahrens } 362fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 3635ad82045Snd mutex_destroy(&ds->ds_lock); 3645ad82045Snd mutex_destroy(&ds->ds_deadlist.bpl_lock); 365fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 366ea8dc4b6Seschrock if (err) { 367ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 368ea8dc4b6Seschrock return (err); 369ea8dc4b6Seschrock } 370fa9e4066Sahrens ds = winner; 371fa9e4066Sahrens } else { 372fa9e4066Sahrens uint64_t new = 373fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 374fa9e4066Sahrens if (new != ds->ds_phys->ds_fsid_guid) { 375fa9e4066Sahrens /* XXX it won't necessarily be synced... */ 376fa9e4066Sahrens ds->ds_phys->ds_fsid_guid = new; 377fa9e4066Sahrens } 378fa9e4066Sahrens } 379fa9e4066Sahrens } 380fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 381fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 382fa9e4066Sahrens 383fa9e4066Sahrens mutex_enter(&ds->ds_lock); 384fa9e4066Sahrens if ((DS_MODE_LEVEL(mode) == DS_MODE_PRIMARY && 38599653d4eSeschrock (ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) && 38699653d4eSeschrock !DS_MODE_IS_INCONSISTENT(mode)) || 38755434c77Sek (ds->ds_open_refcount + weight > DS_REF_MAX)) { 388fa9e4066Sahrens mutex_exit(&ds->ds_lock); 389fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 390ea8dc4b6Seschrock return (EBUSY); 391fa9e4066Sahrens } 392fa9e4066Sahrens ds->ds_open_refcount += weight; 393fa9e4066Sahrens mutex_exit(&ds->ds_lock); 394fa9e4066Sahrens 395ea8dc4b6Seschrock *dsp = ds; 396ea8dc4b6Seschrock return (0); 397fa9e4066Sahrens } 398fa9e4066Sahrens 399fa9e4066Sahrens int 400fa9e4066Sahrens dsl_dataset_open_spa(spa_t *spa, const char *name, int mode, 401fa9e4066Sahrens void *tag, dsl_dataset_t **dsp) 402fa9e4066Sahrens { 403fa9e4066Sahrens dsl_dir_t *dd; 404fa9e4066Sahrens dsl_pool_t *dp; 405fa9e4066Sahrens const char *tail; 406fa9e4066Sahrens uint64_t obj; 407fa9e4066Sahrens dsl_dataset_t *ds = NULL; 408fa9e4066Sahrens int err = 0; 409fa9e4066Sahrens 410ea8dc4b6Seschrock err = dsl_dir_open_spa(spa, name, FTAG, &dd, &tail); 411ea8dc4b6Seschrock if (err) 412ea8dc4b6Seschrock return (err); 413fa9e4066Sahrens 414fa9e4066Sahrens dp = dd->dd_pool; 415fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 416fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 417fa9e4066Sahrens if (obj == 0) { 418fa9e4066Sahrens /* A dataset with no associated objset */ 419fa9e4066Sahrens err = ENOENT; 420fa9e4066Sahrens goto out; 421fa9e4066Sahrens } 422fa9e4066Sahrens 423fa9e4066Sahrens if (tail != NULL) { 424fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 425fa9e4066Sahrens 426ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, obj, NULL, 427ea8dc4b6Seschrock DS_MODE_NONE, tag, &ds); 428ea8dc4b6Seschrock if (err) 429ea8dc4b6Seschrock goto out; 430fa9e4066Sahrens obj = ds->ds_phys->ds_snapnames_zapobj; 431fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 432fa9e4066Sahrens ds = NULL; 433fa9e4066Sahrens 434fa9e4066Sahrens if (tail[0] != '@') { 435fa9e4066Sahrens err = ENOENT; 436fa9e4066Sahrens goto out; 437fa9e4066Sahrens } 438fa9e4066Sahrens tail++; 439fa9e4066Sahrens 440fa9e4066Sahrens /* Look for a snapshot */ 441fa9e4066Sahrens if (!DS_MODE_IS_READONLY(mode)) { 442fa9e4066Sahrens err = EROFS; 443fa9e4066Sahrens goto out; 444fa9e4066Sahrens } 445fa9e4066Sahrens dprintf("looking for snapshot '%s'\n", tail); 446fa9e4066Sahrens err = zap_lookup(mos, obj, tail, 8, 1, &obj); 447fa9e4066Sahrens if (err) 448fa9e4066Sahrens goto out; 449fa9e4066Sahrens } 450ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, obj, tail, mode, tag, &ds); 451fa9e4066Sahrens 452fa9e4066Sahrens out: 453fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 454fa9e4066Sahrens dsl_dir_close(dd, FTAG); 455fa9e4066Sahrens 456fa9e4066Sahrens ASSERT3U((err == 0), ==, (ds != NULL)); 457fa9e4066Sahrens /* ASSERT(ds == NULL || strcmp(name, ds->ds_name) == 0); */ 458fa9e4066Sahrens 459fa9e4066Sahrens *dsp = ds; 460fa9e4066Sahrens return (err); 461fa9e4066Sahrens } 462fa9e4066Sahrens 463fa9e4066Sahrens int 464fa9e4066Sahrens dsl_dataset_open(const char *name, int mode, void *tag, dsl_dataset_t **dsp) 465fa9e4066Sahrens { 466fa9e4066Sahrens return (dsl_dataset_open_spa(NULL, name, mode, tag, dsp)); 467fa9e4066Sahrens } 468fa9e4066Sahrens 469fa9e4066Sahrens void 470fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 471fa9e4066Sahrens { 472fa9e4066Sahrens if (ds == NULL) { 473fa9e4066Sahrens (void) strcpy(name, "mos"); 474fa9e4066Sahrens } else { 475fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 476ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 477fa9e4066Sahrens if (ds->ds_snapname[0]) { 478fa9e4066Sahrens (void) strcat(name, "@"); 479fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 480fa9e4066Sahrens /* 481fa9e4066Sahrens * We use a "recursive" mutex so that we 482fa9e4066Sahrens * can call dprintf_ds() with ds_lock held. 483fa9e4066Sahrens */ 484fa9e4066Sahrens mutex_enter(&ds->ds_lock); 485fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 486fa9e4066Sahrens mutex_exit(&ds->ds_lock); 487fa9e4066Sahrens } else { 488fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 489fa9e4066Sahrens } 490fa9e4066Sahrens } 491fa9e4066Sahrens } 492fa9e4066Sahrens } 493fa9e4066Sahrens 494fa9e4066Sahrens void 495fa9e4066Sahrens dsl_dataset_close(dsl_dataset_t *ds, int mode, void *tag) 496fa9e4066Sahrens { 497fa9e4066Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 498fa9e4066Sahrens mutex_enter(&ds->ds_lock); 499fa9e4066Sahrens ASSERT3U(ds->ds_open_refcount, >=, weight); 500fa9e4066Sahrens ds->ds_open_refcount -= weight; 501fa9e4066Sahrens dprintf_ds(ds, "closing mode %u refcount now 0x%llx\n", 502fa9e4066Sahrens mode, ds->ds_open_refcount); 503fa9e4066Sahrens mutex_exit(&ds->ds_lock); 504fa9e4066Sahrens 505ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 506fa9e4066Sahrens } 507fa9e4066Sahrens 508fa9e4066Sahrens void 509fa9e4066Sahrens dsl_dataset_create_root(dsl_pool_t *dp, uint64_t *ddobjp, dmu_tx_t *tx) 510fa9e4066Sahrens { 511fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 512fa9e4066Sahrens dmu_buf_t *dbuf; 513fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 514fa9e4066Sahrens dsl_dataset_t *ds; 515fa9e4066Sahrens uint64_t dsobj; 516fa9e4066Sahrens dsl_dir_t *dd; 517fa9e4066Sahrens 518fa9e4066Sahrens dsl_dir_create_root(mos, ddobjp, tx); 519ea8dc4b6Seschrock VERIFY(0 == dsl_dir_open_obj(dp, *ddobjp, NULL, FTAG, &dd)); 520fa9e4066Sahrens 5211649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 5221649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 523ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 524fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 525fa9e4066Sahrens dsphys = dbuf->db_data; 526fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 527fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 528ea8dc4b6Seschrock unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 529fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 530fa9e4066Sahrens sizeof (dsphys->ds_guid)); 531fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 53287e5029aSahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 533fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 534fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 535fa9e4066Sahrens dsphys->ds_deadlist_obj = 536fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 537ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 538fa9e4066Sahrens 539fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 540fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 541fa9e4066Sahrens dsl_dir_close(dd, FTAG); 542fa9e4066Sahrens 543ea8dc4b6Seschrock VERIFY(0 == 544ea8dc4b6Seschrock dsl_dataset_open_obj(dp, dsobj, NULL, DS_MODE_NONE, FTAG, &ds)); 545*c717a561Smaybee (void) dmu_objset_create_impl(dp->dp_spa, ds, 546*c717a561Smaybee &ds->ds_phys->ds_bp, DMU_OST_ZFS, tx); 547fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 548fa9e4066Sahrens } 549fa9e4066Sahrens 5501d452cf5Sahrens uint64_t 5511d452cf5Sahrens dsl_dataset_create_sync(dsl_dir_t *pdd, 552fa9e4066Sahrens const char *lastname, dsl_dataset_t *clone_parent, dmu_tx_t *tx) 553fa9e4066Sahrens { 5541d452cf5Sahrens dsl_pool_t *dp = pdd->dd_pool; 555fa9e4066Sahrens dmu_buf_t *dbuf; 556fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 5571d452cf5Sahrens uint64_t dsobj, ddobj; 558fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 559fa9e4066Sahrens dsl_dir_t *dd; 560fa9e4066Sahrens 5611d452cf5Sahrens ASSERT(clone_parent == NULL || clone_parent->ds_dir->dd_pool == dp); 5621d452cf5Sahrens ASSERT(clone_parent == NULL || 5631d452cf5Sahrens clone_parent->ds_phys->ds_num_children > 0); 564fa9e4066Sahrens ASSERT(lastname[0] != '@'); 565fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 566fa9e4066Sahrens 5671d452cf5Sahrens ddobj = dsl_dir_create_sync(pdd, lastname, tx); 5681d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 569fa9e4066Sahrens 5701649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 5711649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 572ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 573fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 574fa9e4066Sahrens dsphys = dbuf->db_data; 575fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 576fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 577fa9e4066Sahrens unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 578fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 579fa9e4066Sahrens sizeof (dsphys->ds_guid)); 580fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 58187e5029aSahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 582fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 583fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 584fa9e4066Sahrens dsphys->ds_deadlist_obj = 585fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 586fa9e4066Sahrens if (clone_parent) { 587fa9e4066Sahrens dsphys->ds_prev_snap_obj = clone_parent->ds_object; 588fa9e4066Sahrens dsphys->ds_prev_snap_txg = 589fa9e4066Sahrens clone_parent->ds_phys->ds_creation_txg; 590fa9e4066Sahrens dsphys->ds_used_bytes = 591fa9e4066Sahrens clone_parent->ds_phys->ds_used_bytes; 592fa9e4066Sahrens dsphys->ds_compressed_bytes = 593fa9e4066Sahrens clone_parent->ds_phys->ds_compressed_bytes; 594fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 595fa9e4066Sahrens clone_parent->ds_phys->ds_uncompressed_bytes; 596fa9e4066Sahrens dsphys->ds_bp = clone_parent->ds_phys->ds_bp; 597fa9e4066Sahrens 598fa9e4066Sahrens dmu_buf_will_dirty(clone_parent->ds_dbuf, tx); 599fa9e4066Sahrens clone_parent->ds_phys->ds_num_children++; 600fa9e4066Sahrens 601fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 602fa9e4066Sahrens dd->dd_phys->dd_clone_parent_obj = clone_parent->ds_object; 603fa9e4066Sahrens } 604ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 605fa9e4066Sahrens 606fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 607fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 608fa9e4066Sahrens dsl_dir_close(dd, FTAG); 609fa9e4066Sahrens 6101d452cf5Sahrens return (dsobj); 611fa9e4066Sahrens } 612fa9e4066Sahrens 6131d452cf5Sahrens struct destroyarg { 6141d452cf5Sahrens dsl_sync_task_group_t *dstg; 6151d452cf5Sahrens char *snapname; 6161d452cf5Sahrens void *tag; 6171d452cf5Sahrens char *failed; 6181d452cf5Sahrens }; 6191d452cf5Sahrens 6201d452cf5Sahrens static int 6211d452cf5Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 622fa9e4066Sahrens { 6231d452cf5Sahrens struct destroyarg *da = arg; 6241d452cf5Sahrens dsl_dataset_t *ds; 6251d452cf5Sahrens char *cp; 626fa9e4066Sahrens int err; 627fa9e4066Sahrens 6281d452cf5Sahrens (void) strcat(name, "@"); 6291d452cf5Sahrens (void) strcat(name, da->snapname); 6301d452cf5Sahrens err = dsl_dataset_open(name, 6311d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 6321d452cf5Sahrens da->tag, &ds); 6331d452cf5Sahrens cp = strchr(name, '@'); 6341d452cf5Sahrens *cp = '\0'; 6351d452cf5Sahrens if (err == ENOENT) 6361d452cf5Sahrens return (0); 6371d452cf5Sahrens if (err) { 6381d452cf5Sahrens (void) strcpy(da->failed, name); 639ea8dc4b6Seschrock return (err); 6401d452cf5Sahrens } 641fa9e4066Sahrens 6421d452cf5Sahrens dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 6431d452cf5Sahrens dsl_dataset_destroy_sync, ds, da->tag, 0); 6441d452cf5Sahrens return (0); 6451d452cf5Sahrens } 64631fd60d3Sahrens 6471d452cf5Sahrens /* 6481d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 6491d452cf5Sahrens */ 6501d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 6511d452cf5Sahrens int 6521d452cf5Sahrens dsl_snapshots_destroy(char *fsname, char *snapname) 6531d452cf5Sahrens { 6541d452cf5Sahrens int err; 6551d452cf5Sahrens struct destroyarg da; 6561d452cf5Sahrens dsl_sync_task_t *dst; 6571d452cf5Sahrens spa_t *spa; 6581d452cf5Sahrens char *cp; 6591d452cf5Sahrens 6601d452cf5Sahrens cp = strchr(fsname, '/'); 6611d452cf5Sahrens if (cp) { 6621d452cf5Sahrens *cp = '\0'; 6631d452cf5Sahrens err = spa_open(fsname, &spa, FTAG); 6641d452cf5Sahrens *cp = '/'; 6651d452cf5Sahrens } else { 6661d452cf5Sahrens err = spa_open(fsname, &spa, FTAG); 6671d452cf5Sahrens } 6681d452cf5Sahrens if (err) 6691d452cf5Sahrens return (err); 6701d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 6711d452cf5Sahrens da.snapname = snapname; 6721d452cf5Sahrens da.tag = FTAG; 6731d452cf5Sahrens da.failed = fsname; 6741d452cf5Sahrens 6751d452cf5Sahrens err = dmu_objset_find(fsname, 6760b69c2f0Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 6771d452cf5Sahrens 6781d452cf5Sahrens if (err == 0) 6791d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 6801d452cf5Sahrens 6811d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 6821d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 6831d452cf5Sahrens dsl_dataset_t *ds = dst->dst_arg1; 6841d452cf5Sahrens if (dst->dst_err) { 6851d452cf5Sahrens dsl_dataset_name(ds, fsname); 6861d452cf5Sahrens cp = strchr(fsname, '@'); 6871d452cf5Sahrens *cp = '\0'; 688e1930233Sbonwick } 689fa9e4066Sahrens /* 6901d452cf5Sahrens * If it was successful, destroy_sync would have 6911d452cf5Sahrens * closed the ds 692fa9e4066Sahrens */ 693ea8dc4b6Seschrock if (err) 6941d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 695fa9e4066Sahrens } 696fa9e4066Sahrens 6971d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 6981d452cf5Sahrens spa_close(spa, FTAG); 699fa9e4066Sahrens return (err); 700fa9e4066Sahrens } 701fa9e4066Sahrens 702fa9e4066Sahrens int 7031d452cf5Sahrens dsl_dataset_destroy(const char *name) 704fa9e4066Sahrens { 705fa9e4066Sahrens int err; 7061d452cf5Sahrens dsl_sync_task_group_t *dstg; 7071d452cf5Sahrens objset_t *os; 7081d452cf5Sahrens dsl_dataset_t *ds; 709fa9e4066Sahrens dsl_dir_t *dd; 7101d452cf5Sahrens uint64_t obj; 7111d452cf5Sahrens 7121d452cf5Sahrens if (strchr(name, '@')) { 7131d452cf5Sahrens /* Destroying a snapshot is simpler */ 7141d452cf5Sahrens err = dsl_dataset_open(name, 7151d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 7161d452cf5Sahrens FTAG, &ds); 7171d452cf5Sahrens if (err) 7181d452cf5Sahrens return (err); 7191d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 7201d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 7211d452cf5Sahrens ds, FTAG, 0); 7221d452cf5Sahrens if (err) 7231d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 7241d452cf5Sahrens return (err); 7251d452cf5Sahrens } 726fa9e4066Sahrens 7271d452cf5Sahrens err = dmu_objset_open(name, DMU_OST_ANY, 7281d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, &os); 729ea8dc4b6Seschrock if (err) 730ea8dc4b6Seschrock return (err); 7311d452cf5Sahrens ds = os->os->os_dsl_dataset; 7321d452cf5Sahrens dd = ds->ds_dir; 733fa9e4066Sahrens 7341d452cf5Sahrens /* 7351d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 7361d452cf5Sahrens * case we crash while freeing the objects. 7371d452cf5Sahrens */ 7381d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 7391d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 7401d452cf5Sahrens if (err) { 7411d452cf5Sahrens dmu_objset_close(os); 7421d452cf5Sahrens return (err); 743fa9e4066Sahrens } 744fa9e4066Sahrens 7451d452cf5Sahrens /* 7461d452cf5Sahrens * remove the objects in open context, so that we won't 7471d452cf5Sahrens * have too much to do in syncing context. 7481d452cf5Sahrens */ 7496754306eSahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 7506754306eSahrens ds->ds_phys->ds_prev_snap_txg)) { 7511d452cf5Sahrens dmu_tx_t *tx = dmu_tx_create(os); 7521d452cf5Sahrens dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END); 7531d452cf5Sahrens dmu_tx_hold_bonus(tx, obj); 7541d452cf5Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 7551d452cf5Sahrens if (err) { 7561d452cf5Sahrens /* 7571d452cf5Sahrens * Perhaps there is not enough disk 7581d452cf5Sahrens * space. Just deal with it from 7591d452cf5Sahrens * dsl_dataset_destroy_sync(). 7601d452cf5Sahrens */ 7611d452cf5Sahrens dmu_tx_abort(tx); 7621d452cf5Sahrens continue; 7631d452cf5Sahrens } 7641d452cf5Sahrens VERIFY(0 == dmu_object_free(os, obj, tx)); 7651d452cf5Sahrens dmu_tx_commit(tx); 7661d452cf5Sahrens } 7671d452cf5Sahrens /* Make sure it's not dirty before we finish destroying it. */ 7681d452cf5Sahrens txg_wait_synced(dd->dd_pool, 0); 7691d452cf5Sahrens 7701d452cf5Sahrens dmu_objset_close(os); 7711d452cf5Sahrens if (err != ESRCH) 7721d452cf5Sahrens return (err); 7731d452cf5Sahrens 7741d452cf5Sahrens err = dsl_dataset_open(name, 7751d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 7761d452cf5Sahrens FTAG, &ds); 7771d452cf5Sahrens if (err) 7781d452cf5Sahrens return (err); 7791d452cf5Sahrens 7801d452cf5Sahrens err = dsl_dir_open(name, FTAG, &dd, NULL); 7811d452cf5Sahrens if (err) { 7821d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 7831d452cf5Sahrens return (err); 7841d452cf5Sahrens } 7851d452cf5Sahrens 7861d452cf5Sahrens /* 7871d452cf5Sahrens * Blow away the dsl_dir + head dataset. 7881d452cf5Sahrens */ 7891d452cf5Sahrens dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 7901d452cf5Sahrens dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 7911d452cf5Sahrens dsl_dataset_destroy_sync, ds, FTAG, 0); 7921d452cf5Sahrens dsl_sync_task_create(dstg, dsl_dir_destroy_check, 7931d452cf5Sahrens dsl_dir_destroy_sync, dd, FTAG, 0); 7941d452cf5Sahrens err = dsl_sync_task_group_wait(dstg); 7951d452cf5Sahrens dsl_sync_task_group_destroy(dstg); 7961d452cf5Sahrens /* if it is successful, *destroy_sync will close the ds+dd */ 7971d452cf5Sahrens if (err) { 7981d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 7991d452cf5Sahrens dsl_dir_close(dd, FTAG); 8001d452cf5Sahrens } 801fa9e4066Sahrens return (err); 802fa9e4066Sahrens } 803fa9e4066Sahrens 8041d452cf5Sahrens int 8051d452cf5Sahrens dsl_dataset_rollback(dsl_dataset_t *ds) 8061d452cf5Sahrens { 80755434c77Sek ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX); 8081d452cf5Sahrens return (dsl_sync_task_do(ds->ds_dir->dd_pool, 8091d452cf5Sahrens dsl_dataset_rollback_check, dsl_dataset_rollback_sync, 8101d452cf5Sahrens ds, NULL, 0)); 8111d452cf5Sahrens } 8121d452cf5Sahrens 813fa9e4066Sahrens void * 814fa9e4066Sahrens dsl_dataset_set_user_ptr(dsl_dataset_t *ds, 815fa9e4066Sahrens void *p, dsl_dataset_evict_func_t func) 816fa9e4066Sahrens { 817fa9e4066Sahrens void *old; 818fa9e4066Sahrens 819fa9e4066Sahrens mutex_enter(&ds->ds_lock); 820fa9e4066Sahrens old = ds->ds_user_ptr; 821fa9e4066Sahrens if (old == NULL) { 822fa9e4066Sahrens ds->ds_user_ptr = p; 823fa9e4066Sahrens ds->ds_user_evict_func = func; 824fa9e4066Sahrens } 825fa9e4066Sahrens mutex_exit(&ds->ds_lock); 826fa9e4066Sahrens return (old); 827fa9e4066Sahrens } 828fa9e4066Sahrens 829fa9e4066Sahrens void * 830fa9e4066Sahrens dsl_dataset_get_user_ptr(dsl_dataset_t *ds) 831fa9e4066Sahrens { 832fa9e4066Sahrens return (ds->ds_user_ptr); 833fa9e4066Sahrens } 834fa9e4066Sahrens 835fa9e4066Sahrens 836*c717a561Smaybee blkptr_t * 837*c717a561Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 838fa9e4066Sahrens { 839*c717a561Smaybee return (&ds->ds_phys->ds_bp); 840fa9e4066Sahrens } 841fa9e4066Sahrens 842fa9e4066Sahrens void 843fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 844fa9e4066Sahrens { 845fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 846fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 847fa9e4066Sahrens if (ds == NULL) { 848fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 849fa9e4066Sahrens } else { 850fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 851fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 852fa9e4066Sahrens } 853fa9e4066Sahrens } 854fa9e4066Sahrens 855fa9e4066Sahrens spa_t * 856fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 857fa9e4066Sahrens { 858fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 859fa9e4066Sahrens } 860fa9e4066Sahrens 861fa9e4066Sahrens void 862fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 863fa9e4066Sahrens { 864fa9e4066Sahrens dsl_pool_t *dp; 865fa9e4066Sahrens 866fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 867fa9e4066Sahrens return; 868fa9e4066Sahrens 869fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 870a2eea2e1Sahrens 871a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 872a2eea2e1Sahrens panic("dirtying snapshot!"); 873fa9e4066Sahrens 874fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 875fa9e4066Sahrens 876fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 877fa9e4066Sahrens /* up the hold count until we can be written out */ 878fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 879fa9e4066Sahrens } 880fa9e4066Sahrens } 881fa9e4066Sahrens 882fa9e4066Sahrens struct killarg { 883fa9e4066Sahrens uint64_t *usedp; 884fa9e4066Sahrens uint64_t *compressedp; 885fa9e4066Sahrens uint64_t *uncompressedp; 886fa9e4066Sahrens zio_t *zio; 887fa9e4066Sahrens dmu_tx_t *tx; 888fa9e4066Sahrens }; 889fa9e4066Sahrens 890fa9e4066Sahrens static int 891fa9e4066Sahrens kill_blkptr(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 892fa9e4066Sahrens { 893fa9e4066Sahrens struct killarg *ka = arg; 894fa9e4066Sahrens blkptr_t *bp = &bc->bc_blkptr; 895fa9e4066Sahrens 896fa9e4066Sahrens ASSERT3U(bc->bc_errno, ==, 0); 897fa9e4066Sahrens 898fa9e4066Sahrens /* 899fa9e4066Sahrens * Since this callback is not called concurrently, no lock is 900fa9e4066Sahrens * needed on the accounting values. 901fa9e4066Sahrens */ 90299653d4eSeschrock *ka->usedp += bp_get_dasize(spa, bp); 903fa9e4066Sahrens *ka->compressedp += BP_GET_PSIZE(bp); 904fa9e4066Sahrens *ka->uncompressedp += BP_GET_UCSIZE(bp); 905fa9e4066Sahrens /* XXX check for EIO? */ 906fa9e4066Sahrens (void) arc_free(ka->zio, spa, ka->tx->tx_txg, bp, NULL, NULL, 907fa9e4066Sahrens ARC_NOWAIT); 908fa9e4066Sahrens return (0); 909fa9e4066Sahrens } 910fa9e4066Sahrens 911fa9e4066Sahrens /* ARGSUSED */ 9121d452cf5Sahrens static int 9131d452cf5Sahrens dsl_dataset_rollback_check(void *arg1, void *arg2, dmu_tx_t *tx) 914fa9e4066Sahrens { 9151d452cf5Sahrens dsl_dataset_t *ds = arg1; 916fa9e4066Sahrens 9171d452cf5Sahrens /* 9181d452cf5Sahrens * There must be a previous snapshot. I suppose we could roll 9191d452cf5Sahrens * it back to being empty (and re-initialize the upper (ZPL) 9201d452cf5Sahrens * layer). But for now there's no way to do this via the user 9211d452cf5Sahrens * interface. 9221d452cf5Sahrens */ 9231d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg == 0) 924fa9e4066Sahrens return (EINVAL); 925fa9e4066Sahrens 9261d452cf5Sahrens /* 9271d452cf5Sahrens * This must not be a snapshot. 9281d452cf5Sahrens */ 9291d452cf5Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 930fa9e4066Sahrens return (EINVAL); 931fa9e4066Sahrens 932fa9e4066Sahrens /* 933fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 934fa9e4066Sahrens * them. Try again. 935fa9e4066Sahrens */ 9361d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 937fa9e4066Sahrens return (EAGAIN); 938fa9e4066Sahrens 9391d452cf5Sahrens return (0); 9401d452cf5Sahrens } 9411d452cf5Sahrens 9421d452cf5Sahrens /* ARGSUSED */ 9431d452cf5Sahrens static void 9441d452cf5Sahrens dsl_dataset_rollback_sync(void *arg1, void *arg2, dmu_tx_t *tx) 9451d452cf5Sahrens { 9461d452cf5Sahrens dsl_dataset_t *ds = arg1; 9471d452cf5Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 948fa9e4066Sahrens 949fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 950fa9e4066Sahrens 951fa9e4066Sahrens /* Zero out the deadlist. */ 952fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 953fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 954fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 955fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 956ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 957ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 958fa9e4066Sahrens 959fa9e4066Sahrens { 960fa9e4066Sahrens /* Free blkptrs that we gave birth to */ 961fa9e4066Sahrens zio_t *zio; 962fa9e4066Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 963fa9e4066Sahrens struct killarg ka; 964fa9e4066Sahrens 965fa9e4066Sahrens zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL, 966fa9e4066Sahrens ZIO_FLAG_MUSTSUCCEED); 967fa9e4066Sahrens ka.usedp = &used; 968fa9e4066Sahrens ka.compressedp = &compressed; 969fa9e4066Sahrens ka.uncompressedp = &uncompressed; 970fa9e4066Sahrens ka.zio = zio; 971fa9e4066Sahrens ka.tx = tx; 972fa9e4066Sahrens (void) traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 973fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 974fa9e4066Sahrens (void) zio_wait(zio); 975fa9e4066Sahrens 9761d452cf5Sahrens dsl_dir_diduse_space(ds->ds_dir, 977fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 978fa9e4066Sahrens } 979fa9e4066Sahrens 9801d452cf5Sahrens /* Change our contents to that of the prev snapshot */ 981fa9e4066Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, ds->ds_phys->ds_prev_snap_obj); 982fa9e4066Sahrens ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp; 983fa9e4066Sahrens ds->ds_phys->ds_used_bytes = ds->ds_prev->ds_phys->ds_used_bytes; 984fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes = 985fa9e4066Sahrens ds->ds_prev->ds_phys->ds_compressed_bytes; 986fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes = 987fa9e4066Sahrens ds->ds_prev->ds_phys->ds_uncompressed_bytes; 98899653d4eSeschrock ds->ds_phys->ds_flags = ds->ds_prev->ds_phys->ds_flags; 989fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 990fa9e4066Sahrens 99185edac42Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 99285edac42Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 99385edac42Sahrens ds->ds_prev->ds_phys->ds_unique_bytes = 0; 99485edac42Sahrens } 995fa9e4066Sahrens } 996fa9e4066Sahrens 997e1930233Sbonwick /* ARGSUSED */ 998e1930233Sbonwick static int 9991d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 1000e1930233Sbonwick { 10011d452cf5Sahrens dsl_dataset_t *ds = arg1; 1002e1930233Sbonwick 1003e1930233Sbonwick /* 1004e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 1005e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 1006e1930233Sbonwick * from.) 1007e1930233Sbonwick */ 1008e1930233Sbonwick if (ds->ds_prev != NULL && 1009e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1010e1930233Sbonwick return (EINVAL); 1011e1930233Sbonwick 1012e1930233Sbonwick return (0); 1013e1930233Sbonwick } 1014e1930233Sbonwick 10151d452cf5Sahrens /* ARGSUSED */ 10161d452cf5Sahrens static void 10171d452cf5Sahrens dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1018fa9e4066Sahrens { 10191d452cf5Sahrens dsl_dataset_t *ds = arg1; 1020fa9e4066Sahrens 10211d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 10221d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 10231d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 10241d452cf5Sahrens } 1025fa9e4066Sahrens 10261d452cf5Sahrens /* ARGSUSED */ 10271d452cf5Sahrens static int 10281d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 10291d452cf5Sahrens { 10301d452cf5Sahrens dsl_dataset_t *ds = arg1; 1031fa9e4066Sahrens 1032fa9e4066Sahrens /* Can't delete a branch point. */ 10331d452cf5Sahrens if (ds->ds_phys->ds_num_children > 1) 10341d452cf5Sahrens return (EEXIST); 1035fa9e4066Sahrens 1036fa9e4066Sahrens /* 1037fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1038fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1039fa9e4066Sahrens * from.) 1040fa9e4066Sahrens */ 1041fa9e4066Sahrens if (ds->ds_prev != NULL && 10421d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1043fa9e4066Sahrens return (EINVAL); 1044fa9e4066Sahrens 1045fa9e4066Sahrens /* 1046fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1047fa9e4066Sahrens * them. Try again. 1048fa9e4066Sahrens */ 10491d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1050fa9e4066Sahrens return (EAGAIN); 10511d452cf5Sahrens 10521d452cf5Sahrens /* XXX we should do some i/o error checking... */ 10531d452cf5Sahrens return (0); 10541d452cf5Sahrens } 10551d452cf5Sahrens 10561d452cf5Sahrens static void 10571d452cf5Sahrens dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) 10581d452cf5Sahrens { 10591d452cf5Sahrens dsl_dataset_t *ds = arg1; 10601d452cf5Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 10611d452cf5Sahrens zio_t *zio; 10621d452cf5Sahrens int err; 10631d452cf5Sahrens int after_branch_point = FALSE; 10641d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 10651d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 10661d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 10671d452cf5Sahrens uint64_t obj; 10681d452cf5Sahrens 106955434c77Sek ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX); 10701d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_num_children, <=, 1); 10711d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 10721d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 10731d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 10741d452cf5Sahrens 10751d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 10761d452cf5Sahrens 10771d452cf5Sahrens obj = ds->ds_object; 1078fa9e4066Sahrens 1079fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1080fa9e4066Sahrens if (ds->ds_prev) { 1081fa9e4066Sahrens ds_prev = ds->ds_prev; 1082fa9e4066Sahrens } else { 10831d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1084fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 10851d452cf5Sahrens DS_MODE_NONE, FTAG, &ds_prev)); 1086fa9e4066Sahrens } 1087fa9e4066Sahrens after_branch_point = 1088fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1089fa9e4066Sahrens 1090fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1091fa9e4066Sahrens if (after_branch_point && 1092fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1093fa9e4066Sahrens /* This clone is toast. */ 1094fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1095fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1096fa9e4066Sahrens } else if (!after_branch_point) { 1097fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1098fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1099fa9e4066Sahrens } 1100fa9e4066Sahrens } 1101fa9e4066Sahrens 1102fa9e4066Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1103fa9e4066Sahrens 1104fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 11051d452cf5Sahrens blkptr_t bp; 1106fa9e4066Sahrens dsl_dataset_t *ds_next; 1107fa9e4066Sahrens uint64_t itor = 0; 1108fa9e4066Sahrens 1109fa9e4066Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 1110fa9e4066Sahrens 11111d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1112ea8dc4b6Seschrock ds->ds_phys->ds_next_snap_obj, NULL, 1113ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_next)); 1114fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1115fa9e4066Sahrens 1116fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1117fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1118fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1119fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1120fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1121fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1122fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1123fa9e4066Sahrens 1124fa9e4066Sahrens /* 1125fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1126fa9e4066Sahrens * new deadlist) any entries from next's current 1127fa9e4066Sahrens * deadlist which were born before prev, and free the 1128fa9e4066Sahrens * other entries. 1129fa9e4066Sahrens * 1130fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1131fa9e4066Sahrens */ 1132fa9e4066Sahrens while (bplist_iterate(&ds_next->ds_deadlist, &itor, 1133fa9e4066Sahrens &bp) == 0) { 1134fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1135ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1136ea8dc4b6Seschrock &bp, tx)); 1137fa9e4066Sahrens if (ds_prev && !after_branch_point && 1138fa9e4066Sahrens bp.blk_birth > 1139fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1140fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 114199653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1142fa9e4066Sahrens } 1143fa9e4066Sahrens } else { 114499653d4eSeschrock used += bp_get_dasize(dp->dp_spa, &bp); 1145fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1146fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1147fa9e4066Sahrens /* XXX check return value? */ 1148fa9e4066Sahrens (void) arc_free(zio, dp->dp_spa, tx->tx_txg, 1149fa9e4066Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1150fa9e4066Sahrens } 1151fa9e4066Sahrens } 1152fa9e4066Sahrens 1153fa9e4066Sahrens /* free next's deadlist */ 1154fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1155fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1156fa9e4066Sahrens 1157fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1158fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1159fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1160ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1161ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1162fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1163fa9e4066Sahrens 1164fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1165fa9e4066Sahrens /* 1166fa9e4066Sahrens * Update next's unique to include blocks which 1167fa9e4066Sahrens * were previously shared by only this snapshot 1168fa9e4066Sahrens * and it. Those blocks will be born after the 1169fa9e4066Sahrens * prev snap and before this snap, and will have 1170fa9e4066Sahrens * died after the next snap and before the one 1171fa9e4066Sahrens * after that (ie. be on the snap after next's 1172fa9e4066Sahrens * deadlist). 1173fa9e4066Sahrens * 1174fa9e4066Sahrens * XXX we're doing this long task with the 1175fa9e4066Sahrens * config lock held 1176fa9e4066Sahrens */ 1177fa9e4066Sahrens dsl_dataset_t *ds_after_next; 1178fa9e4066Sahrens 11791d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1180fa9e4066Sahrens ds_next->ds_phys->ds_next_snap_obj, NULL, 1181ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_after_next)); 1182fa9e4066Sahrens itor = 0; 1183fa9e4066Sahrens while (bplist_iterate(&ds_after_next->ds_deadlist, 1184fa9e4066Sahrens &itor, &bp) == 0) { 1185fa9e4066Sahrens if (bp.blk_birth > 1186fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg && 1187fa9e4066Sahrens bp.blk_birth <= 1188fa9e4066Sahrens ds->ds_phys->ds_creation_txg) { 1189fa9e4066Sahrens ds_next->ds_phys->ds_unique_bytes += 119099653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1191fa9e4066Sahrens } 1192fa9e4066Sahrens } 1193fa9e4066Sahrens 1194fa9e4066Sahrens dsl_dataset_close(ds_after_next, DS_MODE_NONE, FTAG); 1195fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1196fa9e4066Sahrens } else { 1197fa9e4066Sahrens /* 1198fa9e4066Sahrens * It would be nice to update the head dataset's 1199fa9e4066Sahrens * unique. To do so we would have to traverse 1200fa9e4066Sahrens * it for blocks born after ds_prev, which is 1201fa9e4066Sahrens * pretty expensive just to maintain something 1202fa9e4066Sahrens * for debugging purposes. 1203fa9e4066Sahrens */ 1204fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1205fa9e4066Sahrens dsl_dataset_close(ds_next->ds_prev, DS_MODE_NONE, 1206fa9e4066Sahrens ds_next); 1207fa9e4066Sahrens if (ds_prev) { 12081d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1209ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, NULL, 1210ea8dc4b6Seschrock DS_MODE_NONE, ds_next, &ds_next->ds_prev)); 1211fa9e4066Sahrens } else { 1212fa9e4066Sahrens ds_next->ds_prev = NULL; 1213fa9e4066Sahrens } 1214fa9e4066Sahrens } 1215fa9e4066Sahrens dsl_dataset_close(ds_next, DS_MODE_NONE, FTAG); 1216fa9e4066Sahrens 1217fa9e4066Sahrens /* 1218fa9e4066Sahrens * NB: unique_bytes is not accurate for head objsets 1219fa9e4066Sahrens * because we don't update it when we delete the most 1220fa9e4066Sahrens * recent snapshot -- see above comment. 1221fa9e4066Sahrens */ 1222fa9e4066Sahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 1223fa9e4066Sahrens } else { 1224fa9e4066Sahrens /* 1225fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1226fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1227fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1228fa9e4066Sahrens * safe to ignore the deadlist contents.) 1229fa9e4066Sahrens */ 1230fa9e4066Sahrens struct killarg ka; 1231fa9e4066Sahrens 1232fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1233fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1234fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1235fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1236fa9e4066Sahrens 1237fa9e4066Sahrens /* 1238fa9e4066Sahrens * Free everything that we point to (that's born after 1239fa9e4066Sahrens * the previous snapshot, if we are a clone) 1240fa9e4066Sahrens * 1241fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1242fa9e4066Sahrens */ 1243fa9e4066Sahrens ka.usedp = &used; 1244fa9e4066Sahrens ka.compressedp = &compressed; 1245fa9e4066Sahrens ka.uncompressedp = &uncompressed; 1246fa9e4066Sahrens ka.zio = zio; 1247fa9e4066Sahrens ka.tx = tx; 1248fa9e4066Sahrens err = traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 1249fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 1250fa9e4066Sahrens ASSERT3U(err, ==, 0); 1251fa9e4066Sahrens } 1252fa9e4066Sahrens 1253fa9e4066Sahrens err = zio_wait(zio); 1254fa9e4066Sahrens ASSERT3U(err, ==, 0); 1255fa9e4066Sahrens 12561d452cf5Sahrens dsl_dir_diduse_space(ds->ds_dir, -used, -compressed, -uncompressed, tx); 1257fa9e4066Sahrens 1258fa9e4066Sahrens if (ds->ds_phys->ds_snapnames_zapobj) { 1259fa9e4066Sahrens err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1260fa9e4066Sahrens ASSERT(err == 0); 1261fa9e4066Sahrens } 1262fa9e4066Sahrens 12631d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1264fa9e4066Sahrens /* Erase the link in the dataset */ 12651d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 12661d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1267fa9e4066Sahrens /* 1268fa9e4066Sahrens * dsl_dir_sync_destroy() called us, they'll destroy 1269fa9e4066Sahrens * the dataset. 1270fa9e4066Sahrens */ 1271fa9e4066Sahrens } else { 1272fa9e4066Sahrens /* remove from snapshot namespace */ 1273fa9e4066Sahrens dsl_dataset_t *ds_head; 12741d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 12751d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj, NULL, 1276ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_head)); 12778660574dSahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1278fa9e4066Sahrens #ifdef ZFS_DEBUG 1279fa9e4066Sahrens { 1280fa9e4066Sahrens uint64_t val; 1281fa9e4066Sahrens err = zap_lookup(mos, 1282fa9e4066Sahrens ds_head->ds_phys->ds_snapnames_zapobj, 12831d452cf5Sahrens ds->ds_snapname, 8, 1, &val); 1284fa9e4066Sahrens ASSERT3U(err, ==, 0); 1285fa9e4066Sahrens ASSERT3U(val, ==, obj); 1286fa9e4066Sahrens } 1287fa9e4066Sahrens #endif 1288fa9e4066Sahrens err = zap_remove(mos, ds_head->ds_phys->ds_snapnames_zapobj, 12891d452cf5Sahrens ds->ds_snapname, tx); 1290fa9e4066Sahrens ASSERT(err == 0); 1291fa9e4066Sahrens dsl_dataset_close(ds_head, DS_MODE_NONE, FTAG); 1292fa9e4066Sahrens } 1293fa9e4066Sahrens 1294fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1295fa9e4066Sahrens dsl_dataset_close(ds_prev, DS_MODE_NONE, FTAG); 1296fa9e4066Sahrens 12971d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, tag); 12981d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1299fa9e4066Sahrens } 1300fa9e4066Sahrens 13011d452cf5Sahrens /* ARGSUSED */ 1302fa9e4066Sahrens int 13031d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1304fa9e4066Sahrens { 13051d452cf5Sahrens objset_t *os = arg1; 13061d452cf5Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 13071d452cf5Sahrens const char *snapname = arg2; 13081d452cf5Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1309fa9e4066Sahrens int err; 13101d452cf5Sahrens uint64_t value; 1311fa9e4066Sahrens 13121d452cf5Sahrens /* 13131d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 13141d452cf5Sahrens * is already one, try again. 13151d452cf5Sahrens */ 13161d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 13171d452cf5Sahrens return (EAGAIN); 1318fa9e4066Sahrens 13191d452cf5Sahrens /* 13201d452cf5Sahrens * Check for conflicting name snapshot name. 13211d452cf5Sahrens */ 1322fa9e4066Sahrens err = zap_lookup(mos, ds->ds_phys->ds_snapnames_zapobj, 1323fa9e4066Sahrens snapname, 8, 1, &value); 13241d452cf5Sahrens if (err == 0) 1325fa9e4066Sahrens return (EEXIST); 13261d452cf5Sahrens if (err != ENOENT) 13271d452cf5Sahrens return (err); 1328fa9e4066Sahrens 13291d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 13301d452cf5Sahrens return (0); 13311d452cf5Sahrens } 1332fa9e4066Sahrens 13331d452cf5Sahrens void 13341d452cf5Sahrens dsl_dataset_snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx) 13351d452cf5Sahrens { 13361d452cf5Sahrens objset_t *os = arg1; 13371d452cf5Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 13381d452cf5Sahrens const char *snapname = arg2; 13391d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 13401d452cf5Sahrens dmu_buf_t *dbuf; 13411d452cf5Sahrens dsl_dataset_phys_t *dsphys; 13421d452cf5Sahrens uint64_t dsobj; 13431d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 13441d452cf5Sahrens int err; 1345fa9e4066Sahrens 1346fa9e4066Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 13471d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1348fa9e4066Sahrens 13491649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 13501649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 1351ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1352fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 1353fa9e4066Sahrens dsphys = dbuf->db_data; 13541d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 1355fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 1356fa9e4066Sahrens unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 1357fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1358fa9e4066Sahrens sizeof (dsphys->ds_guid)); 1359fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1360fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1361fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1362fa9e4066Sahrens dsphys->ds_num_children = 1; 1363fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1364fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 1365fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1366fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1367fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1368fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 136999653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 1370fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 1371ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 1372fa9e4066Sahrens 13731d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 13741d452cf5Sahrens if (ds->ds_prev) { 13751d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 1376fa9e4066Sahrens ds->ds_object || 13771d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 13781d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 13791d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1380fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 13811d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 13821d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1383fa9e4066Sahrens } 1384fa9e4066Sahrens } 1385fa9e4066Sahrens 1386fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1387fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1388fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, dsphys->ds_creation_txg); 1389fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1390fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg = dsphys->ds_creation_txg; 1391fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1392fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1393fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1394ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1395ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1396fa9e4066Sahrens 1397fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1398fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1399fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 1400fa9e4066Sahrens ASSERT(err == 0); 1401fa9e4066Sahrens 1402fa9e4066Sahrens if (ds->ds_prev) 1403fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 1404ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dp, 1405ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, snapname, 1406ea8dc4b6Seschrock DS_MODE_NONE, ds, &ds->ds_prev)); 1407fa9e4066Sahrens } 1408fa9e4066Sahrens 1409fa9e4066Sahrens void 1410*c717a561Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 1411fa9e4066Sahrens { 1412fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1413fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 1414fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1415fa9e4066Sahrens 1416fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 1417*c717a561Smaybee dmu_objset_sync(ds->ds_user_ptr, zio, tx); 1418*c717a561Smaybee /* Unneeded? bplist_close(&ds->ds_deadlist); */ 1419fa9e4066Sahrens } 1420fa9e4066Sahrens 1421fa9e4066Sahrens void 1422a2eea2e1Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 1423fa9e4066Sahrens { 1424a2eea2e1Sahrens dsl_dir_stats(ds->ds_dir, nv); 1425fa9e4066Sahrens 1426a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 1427a2eea2e1Sahrens ds->ds_phys->ds_creation_time); 1428a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 1429a2eea2e1Sahrens ds->ds_phys->ds_creation_txg); 1430a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, 1431a2eea2e1Sahrens ds->ds_phys->ds_used_bytes); 1432fa9e4066Sahrens 1433fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1434fa9e4066Sahrens /* 1435fa9e4066Sahrens * This is a snapshot; override the dd's space used with 1436a2eea2e1Sahrens * our unique space and compression ratio. 1437fa9e4066Sahrens */ 1438a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 1439a2eea2e1Sahrens ds->ds_phys->ds_unique_bytes); 1440a2eea2e1Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 1441a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 1442a2eea2e1Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 1443a2eea2e1Sahrens ds->ds_phys->ds_compressed_bytes)); 1444fa9e4066Sahrens } 1445fa9e4066Sahrens } 1446fa9e4066Sahrens 1447a2eea2e1Sahrens void 1448a2eea2e1Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 1449a2eea2e1Sahrens { 1450a2eea2e1Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 1451a2eea2e1Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 1452a2eea2e1Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1453a2eea2e1Sahrens stat->dds_is_snapshot = B_TRUE; 1454a2eea2e1Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 1455a2eea2e1Sahrens } 1456a2eea2e1Sahrens 1457a2eea2e1Sahrens /* clone origin is really a dsl_dir thing... */ 1458a2eea2e1Sahrens if (ds->ds_dir->dd_phys->dd_clone_parent_obj) { 1459a2eea2e1Sahrens dsl_dataset_t *ods; 1460a2eea2e1Sahrens 1461a2eea2e1Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 1462a2eea2e1Sahrens VERIFY(0 == dsl_dataset_open_obj(ds->ds_dir->dd_pool, 1463a2eea2e1Sahrens ds->ds_dir->dd_phys->dd_clone_parent_obj, 1464a2eea2e1Sahrens NULL, DS_MODE_NONE, FTAG, &ods)); 1465a2eea2e1Sahrens dsl_dataset_name(ods, stat->dds_clone_of); 1466a2eea2e1Sahrens dsl_dataset_close(ods, DS_MODE_NONE, FTAG); 1467a2eea2e1Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 1468a2eea2e1Sahrens } 1469a2eea2e1Sahrens } 1470a2eea2e1Sahrens 1471a2eea2e1Sahrens uint64_t 1472a2eea2e1Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 1473a2eea2e1Sahrens { 1474a2eea2e1Sahrens return (ds->ds_phys->ds_fsid_guid); 1475a2eea2e1Sahrens } 1476a2eea2e1Sahrens 1477a2eea2e1Sahrens void 1478a2eea2e1Sahrens dsl_dataset_space(dsl_dataset_t *ds, 1479a2eea2e1Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 1480a2eea2e1Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 1481fa9e4066Sahrens { 1482a2eea2e1Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 1483a2eea2e1Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 1484a2eea2e1Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 1485a2eea2e1Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 1486fa9e4066Sahrens } 1487fa9e4066Sahrens 14881d452cf5Sahrens /* ARGSUSED */ 1489fa9e4066Sahrens static int 14901d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 1491fa9e4066Sahrens { 14921d452cf5Sahrens dsl_dataset_t *ds = arg1; 14931d452cf5Sahrens char *newsnapname = arg2; 14941d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 1495fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 14961d452cf5Sahrens dsl_dataset_t *hds; 1497fa9e4066Sahrens uint64_t val; 14981d452cf5Sahrens int err; 1499fa9e4066Sahrens 15001d452cf5Sahrens err = dsl_dataset_open_obj(dd->dd_pool, 15011d452cf5Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds); 1502fa9e4066Sahrens if (err) 1503fa9e4066Sahrens return (err); 1504fa9e4066Sahrens 15051d452cf5Sahrens /* new name better not be in use */ 15061d452cf5Sahrens err = zap_lookup(mos, hds->ds_phys->ds_snapnames_zapobj, 15071d452cf5Sahrens newsnapname, 8, 1, &val); 15081d452cf5Sahrens dsl_dataset_close(hds, DS_MODE_NONE, FTAG); 15091d452cf5Sahrens 15101d452cf5Sahrens if (err == 0) 15111d452cf5Sahrens err = EEXIST; 15121d452cf5Sahrens else if (err == ENOENT) 15131d452cf5Sahrens err = 0; 15141d452cf5Sahrens return (err); 15151d452cf5Sahrens } 1516fa9e4066Sahrens 15171d452cf5Sahrens static void 15181d452cf5Sahrens dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx) 15191d452cf5Sahrens { 15201d452cf5Sahrens dsl_dataset_t *ds = arg1; 15211d452cf5Sahrens char *newsnapname = arg2; 15221d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 15231d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 15241d452cf5Sahrens dsl_dataset_t *hds; 15251d452cf5Sahrens int err; 1526fa9e4066Sahrens 15271d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 1528fa9e4066Sahrens 15291d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, 15301d452cf5Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds)); 1531fa9e4066Sahrens 15321d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 15331d452cf5Sahrens err = zap_remove(mos, hds->ds_phys->ds_snapnames_zapobj, 15341d452cf5Sahrens ds->ds_snapname, tx); 1535fa9e4066Sahrens ASSERT3U(err, ==, 0); 15361d452cf5Sahrens mutex_enter(&ds->ds_lock); 15371d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 15381d452cf5Sahrens mutex_exit(&ds->ds_lock); 15391d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 15401d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 1541fa9e4066Sahrens ASSERT3U(err, ==, 0); 1542fa9e4066Sahrens 15431d452cf5Sahrens dsl_dataset_close(hds, DS_MODE_NONE, FTAG); 1544fa9e4066Sahrens } 1545fa9e4066Sahrens 1546fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 1547fa9e4066Sahrens int 15481d452cf5Sahrens dsl_dataset_rename(const char *oldname, const char *newname) 1549fa9e4066Sahrens { 1550fa9e4066Sahrens dsl_dir_t *dd; 15511d452cf5Sahrens dsl_dataset_t *ds; 1552fa9e4066Sahrens const char *tail; 1553fa9e4066Sahrens int err; 1554fa9e4066Sahrens 15551d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 1556ea8dc4b6Seschrock if (err) 1557ea8dc4b6Seschrock return (err); 1558fa9e4066Sahrens if (tail == NULL) { 15591d452cf5Sahrens err = dsl_dir_rename(dd, newname); 1560fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1561fa9e4066Sahrens return (err); 1562fa9e4066Sahrens } 1563fa9e4066Sahrens if (tail[0] != '@') { 1564fa9e4066Sahrens /* the name ended in a nonexistant component */ 1565fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1566fa9e4066Sahrens return (ENOENT); 1567fa9e4066Sahrens } 1568fa9e4066Sahrens 1569fa9e4066Sahrens dsl_dir_close(dd, FTAG); 15701d452cf5Sahrens 15711d452cf5Sahrens /* new name must be snapshot in same filesystem */ 15721d452cf5Sahrens tail = strchr(newname, '@'); 15731d452cf5Sahrens if (tail == NULL) 15741d452cf5Sahrens return (EINVAL); 15751d452cf5Sahrens tail++; 15761d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 15771d452cf5Sahrens return (EXDEV); 15781d452cf5Sahrens 15791d452cf5Sahrens err = dsl_dataset_open(oldname, 15801d452cf5Sahrens DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &ds); 15811d452cf5Sahrens if (err) 15821d452cf5Sahrens return (err); 15831d452cf5Sahrens 15841d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 15851d452cf5Sahrens dsl_dataset_snapshot_rename_check, 15861d452cf5Sahrens dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 15871d452cf5Sahrens 15881d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG); 15891d452cf5Sahrens 1590fa9e4066Sahrens return (err); 1591fa9e4066Sahrens } 159299653d4eSeschrock 15931d452cf5Sahrens struct promotearg { 15941d452cf5Sahrens uint64_t used, comp, uncomp, unique; 15951d452cf5Sahrens uint64_t newnext_obj, snapnames_obj; 15961d452cf5Sahrens }; 15971d452cf5Sahrens 159899653d4eSeschrock static int 15991d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 160099653d4eSeschrock { 16011d452cf5Sahrens dsl_dataset_t *hds = arg1; 16021d452cf5Sahrens struct promotearg *pa = arg2; 16031d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 16041d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 160599653d4eSeschrock dsl_dir_t *pdd = NULL; 160699653d4eSeschrock dsl_dataset_t *ds = NULL; 160799653d4eSeschrock dsl_dataset_t *pivot_ds = NULL; 160899653d4eSeschrock dsl_dataset_t *newnext_ds = NULL; 160999653d4eSeschrock int err; 161099653d4eSeschrock char *name = NULL; 16111d452cf5Sahrens uint64_t itor = 0; 161299653d4eSeschrock blkptr_t bp; 161399653d4eSeschrock 16141d452cf5Sahrens bzero(pa, sizeof (*pa)); 16151d452cf5Sahrens 161699653d4eSeschrock /* Check that it is a clone */ 161799653d4eSeschrock if (dd->dd_phys->dd_clone_parent_obj == 0) 161899653d4eSeschrock return (EINVAL); 161999653d4eSeschrock 16201d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 16211d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 16221d452cf5Sahrens return (0); 16231d452cf5Sahrens 16241d452cf5Sahrens if (err = dsl_dataset_open_obj(dp, 162599653d4eSeschrock dd->dd_phys->dd_clone_parent_obj, 162699653d4eSeschrock NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)) 162799653d4eSeschrock goto out; 162899653d4eSeschrock pdd = pivot_ds->ds_dir; 16291d452cf5Sahrens 16301d452cf5Sahrens { 16311d452cf5Sahrens dsl_dataset_t *phds; 16321d452cf5Sahrens if (err = dsl_dataset_open_obj(dd->dd_pool, 16331d452cf5Sahrens pdd->dd_phys->dd_head_dataset_obj, 16341d452cf5Sahrens NULL, DS_MODE_NONE, FTAG, &phds)) 16351d452cf5Sahrens goto out; 16361d452cf5Sahrens pa->snapnames_obj = phds->ds_phys->ds_snapnames_zapobj; 16371d452cf5Sahrens dsl_dataset_close(phds, DS_MODE_NONE, FTAG); 16381d452cf5Sahrens } 163999653d4eSeschrock 164099653d4eSeschrock if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) { 164199653d4eSeschrock err = EXDEV; 164299653d4eSeschrock goto out; 164399653d4eSeschrock } 164499653d4eSeschrock 164599653d4eSeschrock /* find pivot point's new next ds */ 164699653d4eSeschrock VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, hds->ds_object, 164799653d4eSeschrock NULL, DS_MODE_NONE, FTAG, &newnext_ds)); 164899653d4eSeschrock while (newnext_ds->ds_phys->ds_prev_snap_obj != pivot_ds->ds_object) { 164999653d4eSeschrock dsl_dataset_t *prev; 165099653d4eSeschrock 165199653d4eSeschrock if (err = dsl_dataset_open_obj(dd->dd_pool, 16521d452cf5Sahrens newnext_ds->ds_phys->ds_prev_snap_obj, 16531d452cf5Sahrens NULL, DS_MODE_NONE, FTAG, &prev)) 165499653d4eSeschrock goto out; 165599653d4eSeschrock dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); 165699653d4eSeschrock newnext_ds = prev; 165799653d4eSeschrock } 16581d452cf5Sahrens pa->newnext_obj = newnext_ds->ds_object; 165999653d4eSeschrock 166099653d4eSeschrock /* compute pivot point's new unique space */ 166199653d4eSeschrock while ((err = bplist_iterate(&newnext_ds->ds_deadlist, 166299653d4eSeschrock &itor, &bp)) == 0) { 166399653d4eSeschrock if (bp.blk_birth > pivot_ds->ds_phys->ds_prev_snap_txg) 16641d452cf5Sahrens pa->unique += bp_get_dasize(dd->dd_pool->dp_spa, &bp); 166599653d4eSeschrock } 166699653d4eSeschrock if (err != ENOENT) 166799653d4eSeschrock goto out; 166899653d4eSeschrock 166999653d4eSeschrock /* Walk the snapshots that we are moving */ 167099653d4eSeschrock name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 167199653d4eSeschrock ds = pivot_ds; 167299653d4eSeschrock /* CONSTCOND */ 167399653d4eSeschrock while (TRUE) { 167499653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 167599653d4eSeschrock dsl_dataset_t *prev; 167699653d4eSeschrock 167799653d4eSeschrock /* Check that the snapshot name does not conflict */ 167899653d4eSeschrock dsl_dataset_name(ds, name); 167999653d4eSeschrock err = zap_lookup(dd->dd_pool->dp_meta_objset, 168099653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 168199653d4eSeschrock 8, 1, &val); 168299653d4eSeschrock if (err != ENOENT) { 168399653d4eSeschrock if (err == 0) 168499653d4eSeschrock err = EEXIST; 168599653d4eSeschrock goto out; 168699653d4eSeschrock } 168799653d4eSeschrock 168899653d4eSeschrock /* 168999653d4eSeschrock * compute space to transfer. Each snapshot gave birth to: 169099653d4eSeschrock * (my used) - (prev's used) + (deadlist's used) 169199653d4eSeschrock */ 16921d452cf5Sahrens pa->used += ds->ds_phys->ds_used_bytes; 16931d452cf5Sahrens pa->comp += ds->ds_phys->ds_compressed_bytes; 16941d452cf5Sahrens pa->uncomp += ds->ds_phys->ds_uncompressed_bytes; 169599653d4eSeschrock 169699653d4eSeschrock /* If we reach the first snapshot, we're done. */ 169799653d4eSeschrock if (ds->ds_phys->ds_prev_snap_obj == 0) 169899653d4eSeschrock break; 169999653d4eSeschrock 170099653d4eSeschrock if (err = bplist_space(&ds->ds_deadlist, 170199653d4eSeschrock &dlused, &dlcomp, &dluncomp)) 170299653d4eSeschrock goto out; 170399653d4eSeschrock if (err = dsl_dataset_open_obj(dd->dd_pool, 170499653d4eSeschrock ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, 170599653d4eSeschrock FTAG, &prev)) 170699653d4eSeschrock goto out; 17071d452cf5Sahrens pa->used += dlused - prev->ds_phys->ds_used_bytes; 17081d452cf5Sahrens pa->comp += dlcomp - prev->ds_phys->ds_compressed_bytes; 17091d452cf5Sahrens pa->uncomp += dluncomp - prev->ds_phys->ds_uncompressed_bytes; 171099653d4eSeschrock 171199653d4eSeschrock /* 171299653d4eSeschrock * We could be a clone of a clone. If we reach our 171399653d4eSeschrock * parent's branch point, we're done. 171499653d4eSeschrock */ 171599653d4eSeschrock if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { 171699653d4eSeschrock dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); 171799653d4eSeschrock break; 171899653d4eSeschrock } 171999653d4eSeschrock if (ds != pivot_ds) 172099653d4eSeschrock dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 172199653d4eSeschrock ds = prev; 172299653d4eSeschrock } 172399653d4eSeschrock 172499653d4eSeschrock /* Check that there is enough space here */ 17251d452cf5Sahrens err = dsl_dir_transfer_possible(pdd, dd, pa->used); 17261d452cf5Sahrens 17271d452cf5Sahrens out: 17281d452cf5Sahrens if (ds && ds != pivot_ds) 17291d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 17301d452cf5Sahrens if (pivot_ds) 17311d452cf5Sahrens dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); 17321d452cf5Sahrens if (newnext_ds) 17331d452cf5Sahrens dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); 17341d452cf5Sahrens if (name) 17351d452cf5Sahrens kmem_free(name, MAXPATHLEN); 17361d452cf5Sahrens return (err); 17371d452cf5Sahrens } 173899653d4eSeschrock 17391d452cf5Sahrens static void 17401d452cf5Sahrens dsl_dataset_promote_sync(void *arg1, void *arg2, dmu_tx_t *tx) 17411d452cf5Sahrens { 17421d452cf5Sahrens dsl_dataset_t *hds = arg1; 17431d452cf5Sahrens struct promotearg *pa = arg2; 17441d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 17451d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 17461d452cf5Sahrens dsl_dir_t *pdd = NULL; 17471d452cf5Sahrens dsl_dataset_t *ds, *pivot_ds; 17481d452cf5Sahrens char *name; 17491d452cf5Sahrens 17501d452cf5Sahrens ASSERT(dd->dd_phys->dd_clone_parent_obj != 0); 17511d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 17521d452cf5Sahrens 17531d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 17541d452cf5Sahrens dd->dd_phys->dd_clone_parent_obj, 17551d452cf5Sahrens NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)); 17560b69c2f0Sahrens /* 17570b69c2f0Sahrens * We need to explicitly open pdd, since pivot_ds's pdd will be 17580b69c2f0Sahrens * changing. 17590b69c2f0Sahrens */ 17600b69c2f0Sahrens VERIFY(0 == dsl_dir_open_obj(dp, pivot_ds->ds_dir->dd_object, 17610b69c2f0Sahrens NULL, FTAG, &pdd)); 176299653d4eSeschrock 176399653d4eSeschrock /* move snapshots to this dir */ 17641d452cf5Sahrens name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 176599653d4eSeschrock ds = pivot_ds; 176699653d4eSeschrock /* CONSTCOND */ 176799653d4eSeschrock while (TRUE) { 176899653d4eSeschrock dsl_dataset_t *prev; 176999653d4eSeschrock 177099653d4eSeschrock /* move snap name entry */ 177199653d4eSeschrock dsl_dataset_name(ds, name); 17721d452cf5Sahrens VERIFY(0 == zap_remove(dp->dp_meta_objset, 17731d452cf5Sahrens pa->snapnames_obj, ds->ds_snapname, tx)); 17741d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 177599653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 177699653d4eSeschrock 8, 1, &ds->ds_object, tx)); 177799653d4eSeschrock 177899653d4eSeschrock /* change containing dsl_dir */ 177999653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 178099653d4eSeschrock ASSERT3U(ds->ds_phys->ds_dir_obj, ==, pdd->dd_object); 178199653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 178299653d4eSeschrock ASSERT3P(ds->ds_dir, ==, pdd); 178399653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 17841d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 178599653d4eSeschrock NULL, ds, &ds->ds_dir)); 178699653d4eSeschrock 178799653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 178899653d4eSeschrock 178999653d4eSeschrock if (ds->ds_phys->ds_prev_snap_obj == 0) 179099653d4eSeschrock break; 179199653d4eSeschrock 17921d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 179399653d4eSeschrock ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, 179499653d4eSeschrock FTAG, &prev)); 179599653d4eSeschrock 179699653d4eSeschrock if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { 179799653d4eSeschrock dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); 179899653d4eSeschrock break; 179999653d4eSeschrock } 180099653d4eSeschrock if (ds != pivot_ds) 180199653d4eSeschrock dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 180299653d4eSeschrock ds = prev; 180399653d4eSeschrock } 18041d452cf5Sahrens if (ds != pivot_ds) 18051d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 180699653d4eSeschrock 180799653d4eSeschrock /* change pivot point's next snap */ 180899653d4eSeschrock dmu_buf_will_dirty(pivot_ds->ds_dbuf, tx); 18091d452cf5Sahrens pivot_ds->ds_phys->ds_next_snap_obj = pa->newnext_obj; 181099653d4eSeschrock 181199653d4eSeschrock /* change clone_parent-age */ 181299653d4eSeschrock dmu_buf_will_dirty(dd->dd_dbuf, tx); 181399653d4eSeschrock ASSERT3U(dd->dd_phys->dd_clone_parent_obj, ==, pivot_ds->ds_object); 181499653d4eSeschrock dd->dd_phys->dd_clone_parent_obj = pdd->dd_phys->dd_clone_parent_obj; 181599653d4eSeschrock dmu_buf_will_dirty(pdd->dd_dbuf, tx); 181699653d4eSeschrock pdd->dd_phys->dd_clone_parent_obj = pivot_ds->ds_object; 181799653d4eSeschrock 181899653d4eSeschrock /* change space accounting */ 18191d452cf5Sahrens dsl_dir_diduse_space(pdd, -pa->used, -pa->comp, -pa->uncomp, tx); 18201d452cf5Sahrens dsl_dir_diduse_space(dd, pa->used, pa->comp, pa->uncomp, tx); 18211d452cf5Sahrens pivot_ds->ds_phys->ds_unique_bytes = pa->unique; 182299653d4eSeschrock 18230b69c2f0Sahrens dsl_dir_close(pdd, FTAG); 18241d452cf5Sahrens dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); 18251d452cf5Sahrens kmem_free(name, MAXPATHLEN); 182699653d4eSeschrock } 182799653d4eSeschrock 182899653d4eSeschrock int 182999653d4eSeschrock dsl_dataset_promote(const char *name) 183099653d4eSeschrock { 183199653d4eSeschrock dsl_dataset_t *ds; 183299653d4eSeschrock int err; 183399653d4eSeschrock dmu_object_info_t doi; 18341d452cf5Sahrens struct promotearg pa; 183599653d4eSeschrock 183699653d4eSeschrock err = dsl_dataset_open(name, DS_MODE_NONE, FTAG, &ds); 183799653d4eSeschrock if (err) 183899653d4eSeschrock return (err); 183999653d4eSeschrock 184099653d4eSeschrock err = dmu_object_info(ds->ds_dir->dd_pool->dp_meta_objset, 184199653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 184299653d4eSeschrock if (err) { 184399653d4eSeschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 184499653d4eSeschrock return (err); 184599653d4eSeschrock } 184699653d4eSeschrock 184799653d4eSeschrock /* 184899653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 184999653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 185099653d4eSeschrock * bonus buffers. 185199653d4eSeschrock */ 18521d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 18531d452cf5Sahrens dsl_dataset_promote_check, 18541d452cf5Sahrens dsl_dataset_promote_sync, ds, &pa, 2 + 2 * doi.doi_physical_blks); 185599653d4eSeschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 185699653d4eSeschrock return (err); 185799653d4eSeschrock } 1858