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 /* 22ea8dc4b6Seschrock * Copyright 2006 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> 32*1d452cf5Sahrens #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 41*1d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 42*1d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 43*1d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_rollback_check; 44*1d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_rollback_sync; 45*1d452cf5Sahrens static dsl_checkfunc_t dsl_dataset_destroy_check; 46*1d452cf5Sahrens static dsl_syncfunc_t dsl_dataset_destroy_sync; 47e1930233Sbonwick 48fa9e4066Sahrens #define DOS_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 55fa9e4066Sahrens * is DOS_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 57fa9e4066Sahrens * exceed DOS_REF_MAX. For example, EXCLUSIVE opens are exclusive because their 58fa9e4066Sahrens * weight (DOS_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] = { 63fa9e4066Sahrens 0, /* DOS_MODE_NONE - invalid */ 64fa9e4066Sahrens 1, /* DOS_MODE_STANDARD - unlimited number */ 65fa9e4066Sahrens (DOS_REF_MAX >> 1) + 1, /* DOS_MODE_PRIMARY - only one of these */ 66fa9e4066Sahrens DOS_REF_MAX /* DOS_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 108fa9e4066Sahrens dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 109fa9e4066Sahrens { 11099653d4eSeschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 111fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 112fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 113fa9e4066Sahrens 114fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 115fa9e4066Sahrens if (BP_IS_HOLE(bp)) 116fa9e4066Sahrens return; 117fa9e4066Sahrens 118fa9e4066Sahrens ASSERT(used > 0); 119fa9e4066Sahrens if (ds == NULL) { 120fa9e4066Sahrens /* 121fa9e4066Sahrens * Account for the meta-objset space in its placeholder 122fa9e4066Sahrens * dataset. 123fa9e4066Sahrens */ 124fa9e4066Sahrens /* XXX this can fail, what do we do when it does? */ 125fa9e4066Sahrens (void) arc_free(NULL, tx->tx_pool->dp_spa, 126fa9e4066Sahrens tx->tx_txg, bp, NULL, NULL, ARC_WAIT); 127fa9e4066Sahrens bzero(bp, sizeof (blkptr_t)); 128fa9e4066Sahrens 129fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 130fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 131fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 132fa9e4066Sahrens return; 133fa9e4066Sahrens } 134fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 135fa9e4066Sahrens 136fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 137fa9e4066Sahrens 138fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 139fa9e4066Sahrens dprintf_bp(bp, "freeing: %s", ""); 140fa9e4066Sahrens /* XXX check return code? */ 141fa9e4066Sahrens (void) arc_free(NULL, tx->tx_pool->dp_spa, 142fa9e4066Sahrens tx->tx_txg, bp, NULL, NULL, ARC_WAIT); 143fa9e4066Sahrens 144fa9e4066Sahrens mutex_enter(&ds->ds_lock); 145fa9e4066Sahrens /* XXX unique_bytes is not accurate for head datasets */ 146fa9e4066Sahrens /* ASSERT3U(ds->ds_phys->ds_unique_bytes, >=, used); */ 147fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 148fa9e4066Sahrens mutex_exit(&ds->ds_lock); 149fa9e4066Sahrens dsl_dir_diduse_space(ds->ds_dir, 150fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 151fa9e4066Sahrens } else { 152fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 153ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 154fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 155fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 156fa9e4066Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, 157fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj); 158fa9e4066Sahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 159fa9e4066Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 16099653d4eSeschrock ds->ds_object && bp->blk_birth > 161fa9e4066Sahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 162fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 163fa9e4066Sahrens mutex_enter(&ds->ds_prev->ds_lock); 164fa9e4066Sahrens ds->ds_prev->ds_phys->ds_unique_bytes += 165fa9e4066Sahrens used; 166fa9e4066Sahrens mutex_exit(&ds->ds_prev->ds_lock); 167fa9e4066Sahrens } 168fa9e4066Sahrens } 169fa9e4066Sahrens } 170fa9e4066Sahrens bzero(bp, sizeof (blkptr_t)); 171fa9e4066Sahrens mutex_enter(&ds->ds_lock); 172fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 173fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 174fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 175fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 176fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 177fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 178fa9e4066Sahrens mutex_exit(&ds->ds_lock); 179fa9e4066Sahrens } 180fa9e4066Sahrens 181ea8dc4b6Seschrock uint64_t 182ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 183fa9e4066Sahrens { 184fa9e4066Sahrens if (ds == NULL) 185ea8dc4b6Seschrock return (0); 186fa9e4066Sahrens /* 187fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 188fa9e4066Sahrens * incorrect FALSE return, which would only result in an 189fa9e4066Sahrens * overestimation of the amount of space that an operation would 190fa9e4066Sahrens * consume, which is OK. 191fa9e4066Sahrens * 192fa9e4066Sahrens * There's also a small window where we could miss a pending 193fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 194fa9e4066Sahrens * phase. So this should only be used as a guess. 195fa9e4066Sahrens */ 196*1d452cf5Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, ds->ds_trysnap_txg)); 197ea8dc4b6Seschrock } 198ea8dc4b6Seschrock 199ea8dc4b6Seschrock int 200ea8dc4b6Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 201ea8dc4b6Seschrock { 202ea8dc4b6Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 203fa9e4066Sahrens } 204fa9e4066Sahrens 205fa9e4066Sahrens /* ARGSUSED */ 206fa9e4066Sahrens static void 207fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 208fa9e4066Sahrens { 209fa9e4066Sahrens dsl_dataset_t *ds = dsv; 210fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 211fa9e4066Sahrens 212fa9e4066Sahrens /* open_refcount == DOS_REF_MAX when deleting */ 213fa9e4066Sahrens ASSERT(ds->ds_open_refcount == 0 || 214fa9e4066Sahrens ds->ds_open_refcount == DOS_REF_MAX); 215fa9e4066Sahrens 216fa9e4066Sahrens dprintf_ds(ds, "evicting %s\n", ""); 217fa9e4066Sahrens 218fa9e4066Sahrens unique_remove(ds->ds_phys->ds_fsid_guid); 219fa9e4066Sahrens 220fa9e4066Sahrens if (ds->ds_user_ptr != NULL) 221fa9e4066Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 222fa9e4066Sahrens 223fa9e4066Sahrens if (ds->ds_prev) { 224fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 225fa9e4066Sahrens ds->ds_prev = NULL; 226fa9e4066Sahrens } 227fa9e4066Sahrens 228fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 229fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 230fa9e4066Sahrens 231fa9e4066Sahrens if (list_link_active(&ds->ds_synced_link)) 232fa9e4066Sahrens list_remove(&dp->dp_synced_objsets, ds); 233fa9e4066Sahrens 234fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 235fa9e4066Sahrens } 236fa9e4066Sahrens 237ea8dc4b6Seschrock static int 238fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 239fa9e4066Sahrens { 240fa9e4066Sahrens dsl_dataset_phys_t *headphys; 241fa9e4066Sahrens int err; 242fa9e4066Sahrens dmu_buf_t *headdbuf; 243fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 244fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 245fa9e4066Sahrens 246fa9e4066Sahrens if (ds->ds_snapname[0]) 247ea8dc4b6Seschrock return (0); 248fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 249ea8dc4b6Seschrock return (0); 250fa9e4066Sahrens 251ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 252ea8dc4b6Seschrock FTAG, &headdbuf); 253ea8dc4b6Seschrock if (err) 254ea8dc4b6Seschrock return (err); 255fa9e4066Sahrens headphys = headdbuf->db_data; 256fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 257fa9e4066Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, ds->ds_snapname); 258ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 259ea8dc4b6Seschrock return (err); 260fa9e4066Sahrens } 261fa9e4066Sahrens 262ea8dc4b6Seschrock int 263fa9e4066Sahrens dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname, 264ea8dc4b6Seschrock int mode, void *tag, dsl_dataset_t **dsp) 265fa9e4066Sahrens { 266fa9e4066Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 267fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 268fa9e4066Sahrens dmu_buf_t *dbuf; 269fa9e4066Sahrens dsl_dataset_t *ds; 270ea8dc4b6Seschrock int err; 271fa9e4066Sahrens 272fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 273fa9e4066Sahrens dsl_pool_sync_context(dp)); 274fa9e4066Sahrens 275ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 276ea8dc4b6Seschrock if (err) 277ea8dc4b6Seschrock return (err); 278fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 279fa9e4066Sahrens if (ds == NULL) { 280fa9e4066Sahrens dsl_dataset_t *winner; 281fa9e4066Sahrens 282fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 283fa9e4066Sahrens ds->ds_dbuf = dbuf; 284fa9e4066Sahrens ds->ds_object = dsobj; 285fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 286fa9e4066Sahrens 287ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 288fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 289ea8dc4b6Seschrock if (err == 0) { 290ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 291ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 292ea8dc4b6Seschrock } 293ea8dc4b6Seschrock if (err) { 294ea8dc4b6Seschrock /* 295ea8dc4b6Seschrock * we don't really need to close the blist if we 296ea8dc4b6Seschrock * just opened it. 297ea8dc4b6Seschrock */ 298ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 299ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 300ea8dc4b6Seschrock return (err); 301ea8dc4b6Seschrock } 302fa9e4066Sahrens 303fa9e4066Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == dsobj) { 304fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 305fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 306ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, 307fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 308ea8dc4b6Seschrock DS_MODE_NONE, ds, &ds->ds_prev); 309fa9e4066Sahrens } 310fa9e4066Sahrens } else { 311fa9e4066Sahrens if (snapname) { 312fa9e4066Sahrens #ifdef ZFS_DEBUG 313fa9e4066Sahrens dsl_dataset_phys_t *headphys; 314ea8dc4b6Seschrock dmu_buf_t *headdbuf; 315ea8dc4b6Seschrock err = dmu_bonus_hold(mos, 316ea8dc4b6Seschrock ds->ds_dir->dd_phys->dd_head_dataset_obj, 317ea8dc4b6Seschrock FTAG, &headdbuf); 318ea8dc4b6Seschrock if (err == 0) { 319ea8dc4b6Seschrock headphys = headdbuf->db_data; 320ea8dc4b6Seschrock uint64_t foundobj; 321ea8dc4b6Seschrock err = zap_lookup(dp->dp_meta_objset, 322ea8dc4b6Seschrock headphys->ds_snapnames_zapobj, 323ea8dc4b6Seschrock snapname, sizeof (foundobj), 1, 324ea8dc4b6Seschrock &foundobj); 325ea8dc4b6Seschrock ASSERT3U(foundobj, ==, dsobj); 326ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 327ea8dc4b6Seschrock } 328fa9e4066Sahrens #endif 329fa9e4066Sahrens (void) strcat(ds->ds_snapname, snapname); 330fa9e4066Sahrens } else if (zfs_flags & ZFS_DEBUG_SNAPNAMES) { 331ea8dc4b6Seschrock err = dsl_dataset_get_snapname(ds); 332fa9e4066Sahrens } 333fa9e4066Sahrens } 334fa9e4066Sahrens 335ea8dc4b6Seschrock if (err == 0) { 336ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 337ea8dc4b6Seschrock dsl_dataset_evict); 338ea8dc4b6Seschrock } 339ea8dc4b6Seschrock if (err || winner) { 340fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 341fa9e4066Sahrens if (ds->ds_prev) { 342fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, 343fa9e4066Sahrens DS_MODE_NONE, ds); 344fa9e4066Sahrens } 345fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 346fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 347ea8dc4b6Seschrock if (err) { 348ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 349ea8dc4b6Seschrock return (err); 350ea8dc4b6Seschrock } 351fa9e4066Sahrens ds = winner; 352fa9e4066Sahrens } else { 353fa9e4066Sahrens uint64_t new = 354fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 355fa9e4066Sahrens if (new != ds->ds_phys->ds_fsid_guid) { 356fa9e4066Sahrens /* XXX it won't necessarily be synced... */ 357fa9e4066Sahrens ds->ds_phys->ds_fsid_guid = new; 358fa9e4066Sahrens } 359fa9e4066Sahrens } 360fa9e4066Sahrens } 361fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 362fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 363fa9e4066Sahrens 364fa9e4066Sahrens mutex_enter(&ds->ds_lock); 365fa9e4066Sahrens if ((DS_MODE_LEVEL(mode) == DS_MODE_PRIMARY && 36699653d4eSeschrock (ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) && 36799653d4eSeschrock !DS_MODE_IS_INCONSISTENT(mode)) || 368fa9e4066Sahrens (ds->ds_open_refcount + weight > DOS_REF_MAX)) { 369fa9e4066Sahrens mutex_exit(&ds->ds_lock); 370fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 371ea8dc4b6Seschrock return (EBUSY); 372fa9e4066Sahrens } 373fa9e4066Sahrens ds->ds_open_refcount += weight; 374fa9e4066Sahrens mutex_exit(&ds->ds_lock); 375fa9e4066Sahrens 376ea8dc4b6Seschrock *dsp = ds; 377ea8dc4b6Seschrock return (0); 378fa9e4066Sahrens } 379fa9e4066Sahrens 380fa9e4066Sahrens int 381fa9e4066Sahrens dsl_dataset_open_spa(spa_t *spa, const char *name, int mode, 382fa9e4066Sahrens void *tag, dsl_dataset_t **dsp) 383fa9e4066Sahrens { 384fa9e4066Sahrens dsl_dir_t *dd; 385fa9e4066Sahrens dsl_pool_t *dp; 386fa9e4066Sahrens const char *tail; 387fa9e4066Sahrens uint64_t obj; 388fa9e4066Sahrens dsl_dataset_t *ds = NULL; 389fa9e4066Sahrens int err = 0; 390fa9e4066Sahrens 391ea8dc4b6Seschrock err = dsl_dir_open_spa(spa, name, FTAG, &dd, &tail); 392ea8dc4b6Seschrock if (err) 393ea8dc4b6Seschrock return (err); 394fa9e4066Sahrens 395fa9e4066Sahrens dp = dd->dd_pool; 396fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 397fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 398fa9e4066Sahrens if (obj == 0) { 399fa9e4066Sahrens /* A dataset with no associated objset */ 400fa9e4066Sahrens err = ENOENT; 401fa9e4066Sahrens goto out; 402fa9e4066Sahrens } 403fa9e4066Sahrens 404fa9e4066Sahrens if (tail != NULL) { 405fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 406fa9e4066Sahrens 407ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, obj, NULL, 408ea8dc4b6Seschrock DS_MODE_NONE, tag, &ds); 409ea8dc4b6Seschrock if (err) 410ea8dc4b6Seschrock goto out; 411fa9e4066Sahrens obj = ds->ds_phys->ds_snapnames_zapobj; 412fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 413fa9e4066Sahrens ds = NULL; 414fa9e4066Sahrens 415fa9e4066Sahrens if (tail[0] != '@') { 416fa9e4066Sahrens err = ENOENT; 417fa9e4066Sahrens goto out; 418fa9e4066Sahrens } 419fa9e4066Sahrens tail++; 420fa9e4066Sahrens 421fa9e4066Sahrens /* Look for a snapshot */ 422fa9e4066Sahrens if (!DS_MODE_IS_READONLY(mode)) { 423fa9e4066Sahrens err = EROFS; 424fa9e4066Sahrens goto out; 425fa9e4066Sahrens } 426fa9e4066Sahrens dprintf("looking for snapshot '%s'\n", tail); 427fa9e4066Sahrens err = zap_lookup(mos, obj, tail, 8, 1, &obj); 428fa9e4066Sahrens if (err) 429fa9e4066Sahrens goto out; 430fa9e4066Sahrens } 431ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, obj, tail, mode, tag, &ds); 432fa9e4066Sahrens 433fa9e4066Sahrens out: 434fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 435fa9e4066Sahrens dsl_dir_close(dd, FTAG); 436fa9e4066Sahrens 437fa9e4066Sahrens ASSERT3U((err == 0), ==, (ds != NULL)); 438fa9e4066Sahrens /* ASSERT(ds == NULL || strcmp(name, ds->ds_name) == 0); */ 439fa9e4066Sahrens 440fa9e4066Sahrens *dsp = ds; 441fa9e4066Sahrens return (err); 442fa9e4066Sahrens } 443fa9e4066Sahrens 444fa9e4066Sahrens int 445fa9e4066Sahrens dsl_dataset_open(const char *name, int mode, void *tag, dsl_dataset_t **dsp) 446fa9e4066Sahrens { 447fa9e4066Sahrens return (dsl_dataset_open_spa(NULL, name, mode, tag, dsp)); 448fa9e4066Sahrens } 449fa9e4066Sahrens 450fa9e4066Sahrens void 451fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 452fa9e4066Sahrens { 453fa9e4066Sahrens if (ds == NULL) { 454fa9e4066Sahrens (void) strcpy(name, "mos"); 455fa9e4066Sahrens } else { 456fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 457ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 458fa9e4066Sahrens if (ds->ds_snapname[0]) { 459fa9e4066Sahrens (void) strcat(name, "@"); 460fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 461fa9e4066Sahrens /* 462fa9e4066Sahrens * We use a "recursive" mutex so that we 463fa9e4066Sahrens * can call dprintf_ds() with ds_lock held. 464fa9e4066Sahrens */ 465fa9e4066Sahrens mutex_enter(&ds->ds_lock); 466fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 467fa9e4066Sahrens mutex_exit(&ds->ds_lock); 468fa9e4066Sahrens } else { 469fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 470fa9e4066Sahrens } 471fa9e4066Sahrens } 472fa9e4066Sahrens } 473fa9e4066Sahrens } 474fa9e4066Sahrens 475fa9e4066Sahrens void 476fa9e4066Sahrens dsl_dataset_close(dsl_dataset_t *ds, int mode, void *tag) 477fa9e4066Sahrens { 478fa9e4066Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 479fa9e4066Sahrens mutex_enter(&ds->ds_lock); 480fa9e4066Sahrens ASSERT3U(ds->ds_open_refcount, >=, weight); 481fa9e4066Sahrens ds->ds_open_refcount -= weight; 482fa9e4066Sahrens dprintf_ds(ds, "closing mode %u refcount now 0x%llx\n", 483fa9e4066Sahrens mode, ds->ds_open_refcount); 484fa9e4066Sahrens mutex_exit(&ds->ds_lock); 485fa9e4066Sahrens 486ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 487fa9e4066Sahrens } 488fa9e4066Sahrens 489fa9e4066Sahrens void 490fa9e4066Sahrens dsl_dataset_create_root(dsl_pool_t *dp, uint64_t *ddobjp, dmu_tx_t *tx) 491fa9e4066Sahrens { 492fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 493fa9e4066Sahrens dmu_buf_t *dbuf; 494fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 495fa9e4066Sahrens dsl_dataset_t *ds; 496fa9e4066Sahrens uint64_t dsobj; 497fa9e4066Sahrens dsl_dir_t *dd; 498fa9e4066Sahrens 499fa9e4066Sahrens dsl_dir_create_root(mos, ddobjp, tx); 500ea8dc4b6Seschrock VERIFY(0 == dsl_dir_open_obj(dp, *ddobjp, NULL, FTAG, &dd)); 501fa9e4066Sahrens 5021649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 5031649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 504ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 505fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 506fa9e4066Sahrens dsphys = dbuf->db_data; 507fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 508fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 509ea8dc4b6Seschrock unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 510fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 511fa9e4066Sahrens sizeof (dsphys->ds_guid)); 512fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 51387e5029aSahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 514fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 515fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 516fa9e4066Sahrens dsphys->ds_deadlist_obj = 517fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 518ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 519fa9e4066Sahrens 520fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 521fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 522fa9e4066Sahrens dsl_dir_close(dd, FTAG); 523fa9e4066Sahrens 524ea8dc4b6Seschrock VERIFY(0 == 525ea8dc4b6Seschrock dsl_dataset_open_obj(dp, dsobj, NULL, DS_MODE_NONE, FTAG, &ds)); 526fa9e4066Sahrens (void) dmu_objset_create_impl(dp->dp_spa, ds, DMU_OST_ZFS, tx); 527fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 528fa9e4066Sahrens } 529fa9e4066Sahrens 530*1d452cf5Sahrens uint64_t 531*1d452cf5Sahrens dsl_dataset_create_sync(dsl_dir_t *pdd, 532fa9e4066Sahrens const char *lastname, dsl_dataset_t *clone_parent, dmu_tx_t *tx) 533fa9e4066Sahrens { 534*1d452cf5Sahrens dsl_pool_t *dp = pdd->dd_pool; 535fa9e4066Sahrens dmu_buf_t *dbuf; 536fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 537*1d452cf5Sahrens uint64_t dsobj, ddobj; 538fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 539fa9e4066Sahrens dsl_dir_t *dd; 540fa9e4066Sahrens 541*1d452cf5Sahrens ASSERT(clone_parent == NULL || clone_parent->ds_dir->dd_pool == dp); 542*1d452cf5Sahrens ASSERT(clone_parent == NULL || 543*1d452cf5Sahrens clone_parent->ds_phys->ds_num_children > 0); 544fa9e4066Sahrens ASSERT(lastname[0] != '@'); 545fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 546fa9e4066Sahrens 547*1d452cf5Sahrens ddobj = dsl_dir_create_sync(pdd, lastname, tx); 548*1d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 549fa9e4066Sahrens 5501649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 5511649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 552ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 553fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 554fa9e4066Sahrens dsphys = dbuf->db_data; 555fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 556fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 557fa9e4066Sahrens unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 558fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 559fa9e4066Sahrens sizeof (dsphys->ds_guid)); 560fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 56187e5029aSahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 562fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 563fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 564fa9e4066Sahrens dsphys->ds_deadlist_obj = 565fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 566fa9e4066Sahrens if (clone_parent) { 567fa9e4066Sahrens dsphys->ds_prev_snap_obj = clone_parent->ds_object; 568fa9e4066Sahrens dsphys->ds_prev_snap_txg = 569fa9e4066Sahrens clone_parent->ds_phys->ds_creation_txg; 570fa9e4066Sahrens dsphys->ds_used_bytes = 571fa9e4066Sahrens clone_parent->ds_phys->ds_used_bytes; 572fa9e4066Sahrens dsphys->ds_compressed_bytes = 573fa9e4066Sahrens clone_parent->ds_phys->ds_compressed_bytes; 574fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 575fa9e4066Sahrens clone_parent->ds_phys->ds_uncompressed_bytes; 576fa9e4066Sahrens dsphys->ds_bp = clone_parent->ds_phys->ds_bp; 577fa9e4066Sahrens 578fa9e4066Sahrens dmu_buf_will_dirty(clone_parent->ds_dbuf, tx); 579fa9e4066Sahrens clone_parent->ds_phys->ds_num_children++; 580fa9e4066Sahrens 581fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 582fa9e4066Sahrens dd->dd_phys->dd_clone_parent_obj = clone_parent->ds_object; 583fa9e4066Sahrens } 584ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 585fa9e4066Sahrens 586fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 587fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 588fa9e4066Sahrens dsl_dir_close(dd, FTAG); 589fa9e4066Sahrens 590*1d452cf5Sahrens return (dsobj); 591fa9e4066Sahrens } 592fa9e4066Sahrens 593*1d452cf5Sahrens struct destroyarg { 594*1d452cf5Sahrens dsl_sync_task_group_t *dstg; 595*1d452cf5Sahrens char *snapname; 596*1d452cf5Sahrens void *tag; 597*1d452cf5Sahrens char *failed; 598*1d452cf5Sahrens }; 599*1d452cf5Sahrens 600*1d452cf5Sahrens static int 601*1d452cf5Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 602fa9e4066Sahrens { 603*1d452cf5Sahrens struct destroyarg *da = arg; 604*1d452cf5Sahrens dsl_dataset_t *ds; 605*1d452cf5Sahrens char *cp; 606fa9e4066Sahrens int err; 607fa9e4066Sahrens 608*1d452cf5Sahrens (void) strcat(name, "@"); 609*1d452cf5Sahrens (void) strcat(name, da->snapname); 610*1d452cf5Sahrens err = dsl_dataset_open(name, 611*1d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 612*1d452cf5Sahrens da->tag, &ds); 613*1d452cf5Sahrens cp = strchr(name, '@'); 614*1d452cf5Sahrens *cp = '\0'; 615*1d452cf5Sahrens if (err == ENOENT) 616*1d452cf5Sahrens return (0); 617*1d452cf5Sahrens if (err) { 618*1d452cf5Sahrens (void) strcpy(da->failed, name); 619ea8dc4b6Seschrock return (err); 620*1d452cf5Sahrens } 621fa9e4066Sahrens 622*1d452cf5Sahrens dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 623*1d452cf5Sahrens dsl_dataset_destroy_sync, ds, da->tag, 0); 624*1d452cf5Sahrens return (0); 625*1d452cf5Sahrens } 62631fd60d3Sahrens 627*1d452cf5Sahrens /* 628*1d452cf5Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 629*1d452cf5Sahrens */ 630*1d452cf5Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 631*1d452cf5Sahrens int 632*1d452cf5Sahrens dsl_snapshots_destroy(char *fsname, char *snapname) 633*1d452cf5Sahrens { 634*1d452cf5Sahrens int err; 635*1d452cf5Sahrens struct destroyarg da; 636*1d452cf5Sahrens dsl_sync_task_t *dst; 637*1d452cf5Sahrens spa_t *spa; 638*1d452cf5Sahrens char *cp; 639*1d452cf5Sahrens 640*1d452cf5Sahrens cp = strchr(fsname, '/'); 641*1d452cf5Sahrens if (cp) { 642*1d452cf5Sahrens *cp = '\0'; 643*1d452cf5Sahrens err = spa_open(fsname, &spa, FTAG); 644*1d452cf5Sahrens *cp = '/'; 645*1d452cf5Sahrens } else { 646*1d452cf5Sahrens err = spa_open(fsname, &spa, FTAG); 647*1d452cf5Sahrens } 648*1d452cf5Sahrens if (err) 649*1d452cf5Sahrens return (err); 650*1d452cf5Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 651*1d452cf5Sahrens da.snapname = snapname; 652*1d452cf5Sahrens da.tag = FTAG; 653*1d452cf5Sahrens da.failed = fsname; 654*1d452cf5Sahrens 655*1d452cf5Sahrens err = dmu_objset_find(fsname, 656*1d452cf5Sahrens dsl_snapshot_destroy_one, &da, 0); 657*1d452cf5Sahrens 658*1d452cf5Sahrens if (err == 0) 659*1d452cf5Sahrens err = dsl_sync_task_group_wait(da.dstg); 660*1d452cf5Sahrens 661*1d452cf5Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 662*1d452cf5Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 663*1d452cf5Sahrens dsl_dataset_t *ds = dst->dst_arg1; 664*1d452cf5Sahrens if (dst->dst_err) { 665*1d452cf5Sahrens dsl_dataset_name(ds, fsname); 666*1d452cf5Sahrens cp = strchr(fsname, '@'); 667*1d452cf5Sahrens *cp = '\0'; 668e1930233Sbonwick } 669fa9e4066Sahrens /* 670*1d452cf5Sahrens * If it was successful, destroy_sync would have 671*1d452cf5Sahrens * closed the ds 672fa9e4066Sahrens */ 673ea8dc4b6Seschrock if (err) 674*1d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 675fa9e4066Sahrens } 676fa9e4066Sahrens 677*1d452cf5Sahrens dsl_sync_task_group_destroy(da.dstg); 678*1d452cf5Sahrens spa_close(spa, FTAG); 679fa9e4066Sahrens return (err); 680fa9e4066Sahrens } 681fa9e4066Sahrens 682fa9e4066Sahrens int 683*1d452cf5Sahrens dsl_dataset_destroy(const char *name) 684fa9e4066Sahrens { 685fa9e4066Sahrens int err; 686*1d452cf5Sahrens dsl_sync_task_group_t *dstg; 687*1d452cf5Sahrens objset_t *os; 688*1d452cf5Sahrens dsl_dataset_t *ds; 689fa9e4066Sahrens dsl_dir_t *dd; 690*1d452cf5Sahrens uint64_t obj; 691*1d452cf5Sahrens 692*1d452cf5Sahrens if (strchr(name, '@')) { 693*1d452cf5Sahrens /* Destroying a snapshot is simpler */ 694*1d452cf5Sahrens err = dsl_dataset_open(name, 695*1d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 696*1d452cf5Sahrens FTAG, &ds); 697*1d452cf5Sahrens if (err) 698*1d452cf5Sahrens return (err); 699*1d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 700*1d452cf5Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 701*1d452cf5Sahrens ds, FTAG, 0); 702*1d452cf5Sahrens if (err) 703*1d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 704*1d452cf5Sahrens return (err); 705*1d452cf5Sahrens } 706fa9e4066Sahrens 707*1d452cf5Sahrens err = dmu_objset_open(name, DMU_OST_ANY, 708*1d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, &os); 709ea8dc4b6Seschrock if (err) 710ea8dc4b6Seschrock return (err); 711*1d452cf5Sahrens ds = os->os->os_dsl_dataset; 712*1d452cf5Sahrens dd = ds->ds_dir; 713fa9e4066Sahrens 714*1d452cf5Sahrens /* 715*1d452cf5Sahrens * Check for errors and mark this ds as inconsistent, in 716*1d452cf5Sahrens * case we crash while freeing the objects. 717*1d452cf5Sahrens */ 718*1d452cf5Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 719*1d452cf5Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 720*1d452cf5Sahrens if (err) { 721*1d452cf5Sahrens dmu_objset_close(os); 722*1d452cf5Sahrens return (err); 723fa9e4066Sahrens } 724fa9e4066Sahrens 725*1d452cf5Sahrens /* 726*1d452cf5Sahrens * remove the objects in open context, so that we won't 727*1d452cf5Sahrens * have too much to do in syncing context. 728*1d452cf5Sahrens */ 729*1d452cf5Sahrens for (obj = 0; err == 0; 730*1d452cf5Sahrens err = dmu_object_next(os, &obj, FALSE)) { 731*1d452cf5Sahrens dmu_tx_t *tx = dmu_tx_create(os); 732*1d452cf5Sahrens dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END); 733*1d452cf5Sahrens dmu_tx_hold_bonus(tx, obj); 734*1d452cf5Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 735*1d452cf5Sahrens if (err) { 736*1d452cf5Sahrens /* 737*1d452cf5Sahrens * Perhaps there is not enough disk 738*1d452cf5Sahrens * space. Just deal with it from 739*1d452cf5Sahrens * dsl_dataset_destroy_sync(). 740*1d452cf5Sahrens */ 741*1d452cf5Sahrens dmu_tx_abort(tx); 742*1d452cf5Sahrens continue; 743*1d452cf5Sahrens } 744*1d452cf5Sahrens VERIFY(0 == dmu_object_free(os, obj, tx)); 745*1d452cf5Sahrens dmu_tx_commit(tx); 746*1d452cf5Sahrens } 747*1d452cf5Sahrens /* Make sure it's not dirty before we finish destroying it. */ 748*1d452cf5Sahrens txg_wait_synced(dd->dd_pool, 0); 749*1d452cf5Sahrens 750*1d452cf5Sahrens dmu_objset_close(os); 751*1d452cf5Sahrens if (err != ESRCH) 752*1d452cf5Sahrens return (err); 753*1d452cf5Sahrens 754*1d452cf5Sahrens err = dsl_dataset_open(name, 755*1d452cf5Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 756*1d452cf5Sahrens FTAG, &ds); 757*1d452cf5Sahrens if (err) 758*1d452cf5Sahrens return (err); 759*1d452cf5Sahrens 760*1d452cf5Sahrens err = dsl_dir_open(name, FTAG, &dd, NULL); 761*1d452cf5Sahrens if (err) { 762*1d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 763*1d452cf5Sahrens return (err); 764*1d452cf5Sahrens } 765*1d452cf5Sahrens 766*1d452cf5Sahrens /* 767*1d452cf5Sahrens * Blow away the dsl_dir + head dataset. 768*1d452cf5Sahrens */ 769*1d452cf5Sahrens dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 770*1d452cf5Sahrens dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 771*1d452cf5Sahrens dsl_dataset_destroy_sync, ds, FTAG, 0); 772*1d452cf5Sahrens dsl_sync_task_create(dstg, dsl_dir_destroy_check, 773*1d452cf5Sahrens dsl_dir_destroy_sync, dd, FTAG, 0); 774*1d452cf5Sahrens err = dsl_sync_task_group_wait(dstg); 775*1d452cf5Sahrens dsl_sync_task_group_destroy(dstg); 776*1d452cf5Sahrens /* if it is successful, *destroy_sync will close the ds+dd */ 777*1d452cf5Sahrens if (err) { 778*1d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 779*1d452cf5Sahrens dsl_dir_close(dd, FTAG); 780*1d452cf5Sahrens } 781fa9e4066Sahrens return (err); 782fa9e4066Sahrens } 783fa9e4066Sahrens 784*1d452cf5Sahrens int 785*1d452cf5Sahrens dsl_dataset_rollback(dsl_dataset_t *ds) 786*1d452cf5Sahrens { 787*1d452cf5Sahrens ASSERT3U(ds->ds_open_refcount, ==, DOS_REF_MAX); 788*1d452cf5Sahrens return (dsl_sync_task_do(ds->ds_dir->dd_pool, 789*1d452cf5Sahrens dsl_dataset_rollback_check, dsl_dataset_rollback_sync, 790*1d452cf5Sahrens ds, NULL, 0)); 791*1d452cf5Sahrens } 792*1d452cf5Sahrens 793fa9e4066Sahrens void * 794fa9e4066Sahrens dsl_dataset_set_user_ptr(dsl_dataset_t *ds, 795fa9e4066Sahrens void *p, dsl_dataset_evict_func_t func) 796fa9e4066Sahrens { 797fa9e4066Sahrens void *old; 798fa9e4066Sahrens 799fa9e4066Sahrens mutex_enter(&ds->ds_lock); 800fa9e4066Sahrens old = ds->ds_user_ptr; 801fa9e4066Sahrens if (old == NULL) { 802fa9e4066Sahrens ds->ds_user_ptr = p; 803fa9e4066Sahrens ds->ds_user_evict_func = func; 804fa9e4066Sahrens } 805fa9e4066Sahrens mutex_exit(&ds->ds_lock); 806fa9e4066Sahrens return (old); 807fa9e4066Sahrens } 808fa9e4066Sahrens 809fa9e4066Sahrens void * 810fa9e4066Sahrens dsl_dataset_get_user_ptr(dsl_dataset_t *ds) 811fa9e4066Sahrens { 812fa9e4066Sahrens return (ds->ds_user_ptr); 813fa9e4066Sahrens } 814fa9e4066Sahrens 815fa9e4066Sahrens 816fa9e4066Sahrens void 817fa9e4066Sahrens dsl_dataset_get_blkptr(dsl_dataset_t *ds, blkptr_t *bp) 818fa9e4066Sahrens { 819fa9e4066Sahrens *bp = ds->ds_phys->ds_bp; 820fa9e4066Sahrens } 821fa9e4066Sahrens 822fa9e4066Sahrens void 823fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 824fa9e4066Sahrens { 825fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 826fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 827fa9e4066Sahrens if (ds == NULL) { 828fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 829fa9e4066Sahrens } else { 830fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 831fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 832fa9e4066Sahrens } 833fa9e4066Sahrens } 834fa9e4066Sahrens 835fa9e4066Sahrens spa_t * 836fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 837fa9e4066Sahrens { 838fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 839fa9e4066Sahrens } 840fa9e4066Sahrens 841fa9e4066Sahrens void 842fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 843fa9e4066Sahrens { 844fa9e4066Sahrens dsl_pool_t *dp; 845fa9e4066Sahrens 846fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 847fa9e4066Sahrens return; 848fa9e4066Sahrens 849fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 850fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 851fa9e4066Sahrens 852fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 853fa9e4066Sahrens 854fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 855fa9e4066Sahrens /* up the hold count until we can be written out */ 856fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 857fa9e4066Sahrens } 858fa9e4066Sahrens } 859fa9e4066Sahrens 860fa9e4066Sahrens struct killarg { 861fa9e4066Sahrens uint64_t *usedp; 862fa9e4066Sahrens uint64_t *compressedp; 863fa9e4066Sahrens uint64_t *uncompressedp; 864fa9e4066Sahrens zio_t *zio; 865fa9e4066Sahrens dmu_tx_t *tx; 866fa9e4066Sahrens }; 867fa9e4066Sahrens 868fa9e4066Sahrens static int 869fa9e4066Sahrens kill_blkptr(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 870fa9e4066Sahrens { 871fa9e4066Sahrens struct killarg *ka = arg; 872fa9e4066Sahrens blkptr_t *bp = &bc->bc_blkptr; 873fa9e4066Sahrens 874fa9e4066Sahrens ASSERT3U(bc->bc_errno, ==, 0); 875fa9e4066Sahrens 876fa9e4066Sahrens /* 877fa9e4066Sahrens * Since this callback is not called concurrently, no lock is 878fa9e4066Sahrens * needed on the accounting values. 879fa9e4066Sahrens */ 88099653d4eSeschrock *ka->usedp += bp_get_dasize(spa, bp); 881fa9e4066Sahrens *ka->compressedp += BP_GET_PSIZE(bp); 882fa9e4066Sahrens *ka->uncompressedp += BP_GET_UCSIZE(bp); 883fa9e4066Sahrens /* XXX check for EIO? */ 884fa9e4066Sahrens (void) arc_free(ka->zio, spa, ka->tx->tx_txg, bp, NULL, NULL, 885fa9e4066Sahrens ARC_NOWAIT); 886fa9e4066Sahrens return (0); 887fa9e4066Sahrens } 888fa9e4066Sahrens 889fa9e4066Sahrens /* ARGSUSED */ 890*1d452cf5Sahrens static int 891*1d452cf5Sahrens dsl_dataset_rollback_check(void *arg1, void *arg2, dmu_tx_t *tx) 892fa9e4066Sahrens { 893*1d452cf5Sahrens dsl_dataset_t *ds = arg1; 894fa9e4066Sahrens 895*1d452cf5Sahrens /* 896*1d452cf5Sahrens * There must be a previous snapshot. I suppose we could roll 897*1d452cf5Sahrens * it back to being empty (and re-initialize the upper (ZPL) 898*1d452cf5Sahrens * layer). But for now there's no way to do this via the user 899*1d452cf5Sahrens * interface. 900*1d452cf5Sahrens */ 901*1d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg == 0) 902fa9e4066Sahrens return (EINVAL); 903fa9e4066Sahrens 904*1d452cf5Sahrens /* 905*1d452cf5Sahrens * This must not be a snapshot. 906*1d452cf5Sahrens */ 907*1d452cf5Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 908fa9e4066Sahrens return (EINVAL); 909fa9e4066Sahrens 910fa9e4066Sahrens /* 911fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 912fa9e4066Sahrens * them. Try again. 913fa9e4066Sahrens */ 914*1d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 915fa9e4066Sahrens return (EAGAIN); 916fa9e4066Sahrens 917*1d452cf5Sahrens return (0); 918*1d452cf5Sahrens } 919*1d452cf5Sahrens 920*1d452cf5Sahrens /* ARGSUSED */ 921*1d452cf5Sahrens static void 922*1d452cf5Sahrens dsl_dataset_rollback_sync(void *arg1, void *arg2, dmu_tx_t *tx) 923*1d452cf5Sahrens { 924*1d452cf5Sahrens dsl_dataset_t *ds = arg1; 925*1d452cf5Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 926fa9e4066Sahrens 927fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 928fa9e4066Sahrens 929fa9e4066Sahrens /* Zero out the deadlist. */ 930fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 931fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 932fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 933fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 934ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 935ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 936fa9e4066Sahrens 937fa9e4066Sahrens { 938fa9e4066Sahrens /* Free blkptrs that we gave birth to */ 939fa9e4066Sahrens zio_t *zio; 940fa9e4066Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 941fa9e4066Sahrens struct killarg ka; 942fa9e4066Sahrens 943fa9e4066Sahrens zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL, 944fa9e4066Sahrens ZIO_FLAG_MUSTSUCCEED); 945fa9e4066Sahrens ka.usedp = &used; 946fa9e4066Sahrens ka.compressedp = &compressed; 947fa9e4066Sahrens ka.uncompressedp = &uncompressed; 948fa9e4066Sahrens ka.zio = zio; 949fa9e4066Sahrens ka.tx = tx; 950fa9e4066Sahrens (void) traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 951fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 952fa9e4066Sahrens (void) zio_wait(zio); 953fa9e4066Sahrens 954*1d452cf5Sahrens dsl_dir_diduse_space(ds->ds_dir, 955fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 956fa9e4066Sahrens } 957fa9e4066Sahrens 958*1d452cf5Sahrens /* Change our contents to that of the prev snapshot */ 959fa9e4066Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, ds->ds_phys->ds_prev_snap_obj); 960fa9e4066Sahrens ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp; 961fa9e4066Sahrens ds->ds_phys->ds_used_bytes = ds->ds_prev->ds_phys->ds_used_bytes; 962fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes = 963fa9e4066Sahrens ds->ds_prev->ds_phys->ds_compressed_bytes; 964fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes = 965fa9e4066Sahrens ds->ds_prev->ds_phys->ds_uncompressed_bytes; 96699653d4eSeschrock ds->ds_phys->ds_flags = ds->ds_prev->ds_phys->ds_flags; 967fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 968fa9e4066Sahrens 969fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 970fa9e4066Sahrens ds->ds_prev->ds_phys->ds_unique_bytes = 0; 971fa9e4066Sahrens } 972fa9e4066Sahrens 973e1930233Sbonwick /* ARGSUSED */ 974e1930233Sbonwick static int 975*1d452cf5Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 976e1930233Sbonwick { 977*1d452cf5Sahrens dsl_dataset_t *ds = arg1; 978e1930233Sbonwick 979e1930233Sbonwick /* 980e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 981e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 982e1930233Sbonwick * from.) 983e1930233Sbonwick */ 984e1930233Sbonwick if (ds->ds_prev != NULL && 985e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 986e1930233Sbonwick return (EINVAL); 987e1930233Sbonwick 988e1930233Sbonwick return (0); 989e1930233Sbonwick } 990e1930233Sbonwick 991*1d452cf5Sahrens /* ARGSUSED */ 992*1d452cf5Sahrens static void 993*1d452cf5Sahrens dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx) 994fa9e4066Sahrens { 995*1d452cf5Sahrens dsl_dataset_t *ds = arg1; 996fa9e4066Sahrens 997*1d452cf5Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 998*1d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 999*1d452cf5Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 1000*1d452cf5Sahrens } 1001fa9e4066Sahrens 1002*1d452cf5Sahrens /* ARGSUSED */ 1003*1d452cf5Sahrens static int 1004*1d452cf5Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 1005*1d452cf5Sahrens { 1006*1d452cf5Sahrens dsl_dataset_t *ds = arg1; 1007fa9e4066Sahrens 1008fa9e4066Sahrens /* Can't delete a branch point. */ 1009*1d452cf5Sahrens if (ds->ds_phys->ds_num_children > 1) 1010*1d452cf5Sahrens return (EEXIST); 1011fa9e4066Sahrens 1012fa9e4066Sahrens /* 1013fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1014fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1015fa9e4066Sahrens * from.) 1016fa9e4066Sahrens */ 1017fa9e4066Sahrens if (ds->ds_prev != NULL && 1018*1d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1019fa9e4066Sahrens return (EINVAL); 1020fa9e4066Sahrens 1021fa9e4066Sahrens /* 1022fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1023fa9e4066Sahrens * them. Try again. 1024fa9e4066Sahrens */ 1025*1d452cf5Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1026fa9e4066Sahrens return (EAGAIN); 1027*1d452cf5Sahrens 1028*1d452cf5Sahrens /* XXX we should do some i/o error checking... */ 1029*1d452cf5Sahrens return (0); 1030*1d452cf5Sahrens } 1031*1d452cf5Sahrens 1032*1d452cf5Sahrens static void 1033*1d452cf5Sahrens dsl_dataset_destroy_sync(void *arg1, void *tag, dmu_tx_t *tx) 1034*1d452cf5Sahrens { 1035*1d452cf5Sahrens dsl_dataset_t *ds = arg1; 1036*1d452cf5Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 1037*1d452cf5Sahrens zio_t *zio; 1038*1d452cf5Sahrens int err; 1039*1d452cf5Sahrens int after_branch_point = FALSE; 1040*1d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 1041*1d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 1042*1d452cf5Sahrens dsl_dataset_t *ds_prev = NULL; 1043*1d452cf5Sahrens uint64_t obj; 1044*1d452cf5Sahrens 1045*1d452cf5Sahrens ASSERT3U(ds->ds_open_refcount, ==, DOS_REF_MAX); 1046*1d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_num_children, <=, 1); 1047*1d452cf5Sahrens ASSERT(ds->ds_prev == NULL || 1048*1d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 1049*1d452cf5Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 1050*1d452cf5Sahrens 1051*1d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1052*1d452cf5Sahrens 1053*1d452cf5Sahrens obj = ds->ds_object; 1054fa9e4066Sahrens 1055fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1056fa9e4066Sahrens if (ds->ds_prev) { 1057fa9e4066Sahrens ds_prev = ds->ds_prev; 1058fa9e4066Sahrens } else { 1059*1d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1060fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 1061*1d452cf5Sahrens DS_MODE_NONE, FTAG, &ds_prev)); 1062fa9e4066Sahrens } 1063fa9e4066Sahrens after_branch_point = 1064fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1065fa9e4066Sahrens 1066fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1067fa9e4066Sahrens if (after_branch_point && 1068fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1069fa9e4066Sahrens /* This clone is toast. */ 1070fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1071fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1072fa9e4066Sahrens } else if (!after_branch_point) { 1073fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1074fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1075fa9e4066Sahrens } 1076fa9e4066Sahrens } 1077fa9e4066Sahrens 1078fa9e4066Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1079fa9e4066Sahrens 1080fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1081*1d452cf5Sahrens blkptr_t bp; 1082fa9e4066Sahrens dsl_dataset_t *ds_next; 1083fa9e4066Sahrens uint64_t itor = 0; 1084fa9e4066Sahrens 1085fa9e4066Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 1086fa9e4066Sahrens 1087*1d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1088ea8dc4b6Seschrock ds->ds_phys->ds_next_snap_obj, NULL, 1089ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_next)); 1090fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1091fa9e4066Sahrens 1092fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1093fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1094fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1095fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1096fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1097fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1098fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1099fa9e4066Sahrens 1100fa9e4066Sahrens /* 1101fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1102fa9e4066Sahrens * new deadlist) any entries from next's current 1103fa9e4066Sahrens * deadlist which were born before prev, and free the 1104fa9e4066Sahrens * other entries. 1105fa9e4066Sahrens * 1106fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1107fa9e4066Sahrens */ 1108fa9e4066Sahrens while (bplist_iterate(&ds_next->ds_deadlist, &itor, 1109fa9e4066Sahrens &bp) == 0) { 1110fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1111ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1112ea8dc4b6Seschrock &bp, tx)); 1113fa9e4066Sahrens if (ds_prev && !after_branch_point && 1114fa9e4066Sahrens bp.blk_birth > 1115fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1116fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 111799653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1118fa9e4066Sahrens } 1119fa9e4066Sahrens } else { 112099653d4eSeschrock used += bp_get_dasize(dp->dp_spa, &bp); 1121fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1122fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1123fa9e4066Sahrens /* XXX check return value? */ 1124fa9e4066Sahrens (void) arc_free(zio, dp->dp_spa, tx->tx_txg, 1125fa9e4066Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1126fa9e4066Sahrens } 1127fa9e4066Sahrens } 1128fa9e4066Sahrens 1129fa9e4066Sahrens /* free next's deadlist */ 1130fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1131fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1132fa9e4066Sahrens 1133fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1134fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1135fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1136ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1137ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1138fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1139fa9e4066Sahrens 1140fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1141fa9e4066Sahrens /* 1142fa9e4066Sahrens * Update next's unique to include blocks which 1143fa9e4066Sahrens * were previously shared by only this snapshot 1144fa9e4066Sahrens * and it. Those blocks will be born after the 1145fa9e4066Sahrens * prev snap and before this snap, and will have 1146fa9e4066Sahrens * died after the next snap and before the one 1147fa9e4066Sahrens * after that (ie. be on the snap after next's 1148fa9e4066Sahrens * deadlist). 1149fa9e4066Sahrens * 1150fa9e4066Sahrens * XXX we're doing this long task with the 1151fa9e4066Sahrens * config lock held 1152fa9e4066Sahrens */ 1153fa9e4066Sahrens dsl_dataset_t *ds_after_next; 1154fa9e4066Sahrens 1155*1d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1156fa9e4066Sahrens ds_next->ds_phys->ds_next_snap_obj, NULL, 1157ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_after_next)); 1158fa9e4066Sahrens itor = 0; 1159fa9e4066Sahrens while (bplist_iterate(&ds_after_next->ds_deadlist, 1160fa9e4066Sahrens &itor, &bp) == 0) { 1161fa9e4066Sahrens if (bp.blk_birth > 1162fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg && 1163fa9e4066Sahrens bp.blk_birth <= 1164fa9e4066Sahrens ds->ds_phys->ds_creation_txg) { 1165fa9e4066Sahrens ds_next->ds_phys->ds_unique_bytes += 116699653d4eSeschrock bp_get_dasize(dp->dp_spa, &bp); 1167fa9e4066Sahrens } 1168fa9e4066Sahrens } 1169fa9e4066Sahrens 1170fa9e4066Sahrens dsl_dataset_close(ds_after_next, DS_MODE_NONE, FTAG); 1171fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1172fa9e4066Sahrens } else { 1173fa9e4066Sahrens /* 1174fa9e4066Sahrens * It would be nice to update the head dataset's 1175fa9e4066Sahrens * unique. To do so we would have to traverse 1176fa9e4066Sahrens * it for blocks born after ds_prev, which is 1177fa9e4066Sahrens * pretty expensive just to maintain something 1178fa9e4066Sahrens * for debugging purposes. 1179fa9e4066Sahrens */ 1180fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1181fa9e4066Sahrens dsl_dataset_close(ds_next->ds_prev, DS_MODE_NONE, 1182fa9e4066Sahrens ds_next); 1183fa9e4066Sahrens if (ds_prev) { 1184*1d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1185ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, NULL, 1186ea8dc4b6Seschrock DS_MODE_NONE, ds_next, &ds_next->ds_prev)); 1187fa9e4066Sahrens } else { 1188fa9e4066Sahrens ds_next->ds_prev = NULL; 1189fa9e4066Sahrens } 1190fa9e4066Sahrens } 1191fa9e4066Sahrens dsl_dataset_close(ds_next, DS_MODE_NONE, FTAG); 1192fa9e4066Sahrens 1193fa9e4066Sahrens /* 1194fa9e4066Sahrens * NB: unique_bytes is not accurate for head objsets 1195fa9e4066Sahrens * because we don't update it when we delete the most 1196fa9e4066Sahrens * recent snapshot -- see above comment. 1197fa9e4066Sahrens */ 1198fa9e4066Sahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 1199fa9e4066Sahrens } else { 1200fa9e4066Sahrens /* 1201fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1202fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1203fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1204fa9e4066Sahrens * safe to ignore the deadlist contents.) 1205fa9e4066Sahrens */ 1206fa9e4066Sahrens struct killarg ka; 1207fa9e4066Sahrens 1208fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1209fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1210fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1211fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1212fa9e4066Sahrens 1213fa9e4066Sahrens /* 1214fa9e4066Sahrens * Free everything that we point to (that's born after 1215fa9e4066Sahrens * the previous snapshot, if we are a clone) 1216fa9e4066Sahrens * 1217fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1218fa9e4066Sahrens */ 1219fa9e4066Sahrens ka.usedp = &used; 1220fa9e4066Sahrens ka.compressedp = &compressed; 1221fa9e4066Sahrens ka.uncompressedp = &uncompressed; 1222fa9e4066Sahrens ka.zio = zio; 1223fa9e4066Sahrens ka.tx = tx; 1224fa9e4066Sahrens err = traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 1225fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 1226fa9e4066Sahrens ASSERT3U(err, ==, 0); 1227fa9e4066Sahrens } 1228fa9e4066Sahrens 1229fa9e4066Sahrens err = zio_wait(zio); 1230fa9e4066Sahrens ASSERT3U(err, ==, 0); 1231fa9e4066Sahrens 1232*1d452cf5Sahrens dsl_dir_diduse_space(ds->ds_dir, -used, -compressed, -uncompressed, tx); 1233fa9e4066Sahrens 1234fa9e4066Sahrens if (ds->ds_phys->ds_snapnames_zapobj) { 1235fa9e4066Sahrens err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1236fa9e4066Sahrens ASSERT(err == 0); 1237fa9e4066Sahrens } 1238fa9e4066Sahrens 1239*1d452cf5Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1240fa9e4066Sahrens /* Erase the link in the dataset */ 1241*1d452cf5Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 1242*1d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1243fa9e4066Sahrens /* 1244fa9e4066Sahrens * dsl_dir_sync_destroy() called us, they'll destroy 1245fa9e4066Sahrens * the dataset. 1246fa9e4066Sahrens */ 1247fa9e4066Sahrens } else { 1248fa9e4066Sahrens /* remove from snapshot namespace */ 1249fa9e4066Sahrens dsl_dataset_t *ds_head; 1250*1d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1251*1d452cf5Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj, NULL, 1252ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_head)); 1253fa9e4066Sahrens #ifdef ZFS_DEBUG 1254fa9e4066Sahrens { 1255fa9e4066Sahrens uint64_t val; 1256fa9e4066Sahrens err = zap_lookup(mos, 1257fa9e4066Sahrens ds_head->ds_phys->ds_snapnames_zapobj, 1258*1d452cf5Sahrens ds->ds_snapname, 8, 1, &val); 1259fa9e4066Sahrens ASSERT3U(err, ==, 0); 1260fa9e4066Sahrens ASSERT3U(val, ==, obj); 1261fa9e4066Sahrens } 1262fa9e4066Sahrens #endif 1263fa9e4066Sahrens err = zap_remove(mos, ds_head->ds_phys->ds_snapnames_zapobj, 1264*1d452cf5Sahrens ds->ds_snapname, tx); 1265fa9e4066Sahrens ASSERT(err == 0); 1266fa9e4066Sahrens dsl_dataset_close(ds_head, DS_MODE_NONE, FTAG); 1267fa9e4066Sahrens } 1268fa9e4066Sahrens 1269fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1270fa9e4066Sahrens dsl_dataset_close(ds_prev, DS_MODE_NONE, FTAG); 1271fa9e4066Sahrens 1272*1d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, tag); 1273*1d452cf5Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 1274fa9e4066Sahrens } 1275fa9e4066Sahrens 1276*1d452cf5Sahrens /* ARGSUSED */ 1277fa9e4066Sahrens int 1278*1d452cf5Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 1279fa9e4066Sahrens { 1280*1d452cf5Sahrens objset_t *os = arg1; 1281*1d452cf5Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 1282*1d452cf5Sahrens const char *snapname = arg2; 1283*1d452cf5Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 1284fa9e4066Sahrens int err; 1285*1d452cf5Sahrens uint64_t value; 1286fa9e4066Sahrens 1287*1d452cf5Sahrens /* 1288*1d452cf5Sahrens * We don't allow multiple snapshots of the same txg. If there 1289*1d452cf5Sahrens * is already one, try again. 1290*1d452cf5Sahrens */ 1291*1d452cf5Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 1292*1d452cf5Sahrens return (EAGAIN); 1293fa9e4066Sahrens 1294*1d452cf5Sahrens /* 1295*1d452cf5Sahrens * Check for conflicting name snapshot name. 1296*1d452cf5Sahrens */ 1297fa9e4066Sahrens err = zap_lookup(mos, ds->ds_phys->ds_snapnames_zapobj, 1298fa9e4066Sahrens snapname, 8, 1, &value); 1299*1d452cf5Sahrens if (err == 0) 1300fa9e4066Sahrens return (EEXIST); 1301*1d452cf5Sahrens if (err != ENOENT) 1302*1d452cf5Sahrens return (err); 1303fa9e4066Sahrens 1304*1d452cf5Sahrens ds->ds_trysnap_txg = tx->tx_txg; 1305*1d452cf5Sahrens return (0); 1306*1d452cf5Sahrens } 1307fa9e4066Sahrens 1308*1d452cf5Sahrens void 1309*1d452cf5Sahrens dsl_dataset_snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1310*1d452cf5Sahrens { 1311*1d452cf5Sahrens objset_t *os = arg1; 1312*1d452cf5Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 1313*1d452cf5Sahrens const char *snapname = arg2; 1314*1d452cf5Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 1315*1d452cf5Sahrens dmu_buf_t *dbuf; 1316*1d452cf5Sahrens dsl_dataset_phys_t *dsphys; 1317*1d452cf5Sahrens uint64_t dsobj; 1318*1d452cf5Sahrens objset_t *mos = dp->dp_meta_objset; 1319*1d452cf5Sahrens int err; 1320fa9e4066Sahrens 1321fa9e4066Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 1322*1d452cf5Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1323fa9e4066Sahrens 13241649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 13251649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 1326ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1327fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 1328fa9e4066Sahrens dsphys = dbuf->db_data; 1329*1d452cf5Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 1330fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 1331fa9e4066Sahrens unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 1332fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1333fa9e4066Sahrens sizeof (dsphys->ds_guid)); 1334fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1335fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1336fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1337fa9e4066Sahrens dsphys->ds_num_children = 1; 1338fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1339fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 1340fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1341fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1342fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1343fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 134499653d4eSeschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 1345fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 1346ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 1347fa9e4066Sahrens 1348*1d452cf5Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 1349*1d452cf5Sahrens if (ds->ds_prev) { 1350*1d452cf5Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 1351fa9e4066Sahrens ds->ds_object || 1352*1d452cf5Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 1353*1d452cf5Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 1354*1d452cf5Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1355fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1356*1d452cf5Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 1357*1d452cf5Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1358fa9e4066Sahrens } 1359fa9e4066Sahrens } 1360fa9e4066Sahrens 1361fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1362fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1363fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, dsphys->ds_creation_txg); 1364fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1365fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg = dsphys->ds_creation_txg; 1366fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1367fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1368fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1369ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1370ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1371fa9e4066Sahrens 1372fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1373fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1374fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 1375fa9e4066Sahrens ASSERT(err == 0); 1376fa9e4066Sahrens 1377fa9e4066Sahrens if (ds->ds_prev) 1378fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 1379ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dp, 1380ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, snapname, 1381ea8dc4b6Seschrock DS_MODE_NONE, ds, &ds->ds_prev)); 1382fa9e4066Sahrens } 1383fa9e4066Sahrens 1384fa9e4066Sahrens void 1385fa9e4066Sahrens dsl_dataset_sync(dsl_dataset_t *ds, dmu_tx_t *tx) 1386fa9e4066Sahrens { 1387fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1388fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 1389fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1390fa9e4066Sahrens 1391fa9e4066Sahrens dmu_objset_sync(ds->ds_user_ptr, tx); 1392fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 1393fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1394fa9e4066Sahrens 1395ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, ds); 1396fa9e4066Sahrens } 1397fa9e4066Sahrens 1398fa9e4066Sahrens void 1399fa9e4066Sahrens dsl_dataset_stats(dsl_dataset_t *ds, dmu_objset_stats_t *dds) 1400fa9e4066Sahrens { 1401fa9e4066Sahrens /* fill in properties crap */ 1402fa9e4066Sahrens dsl_dir_stats(ds->ds_dir, dds); 1403fa9e4066Sahrens 1404fa9e4066Sahrens if (ds->ds_phys->ds_num_children != 0) { 1405fa9e4066Sahrens dds->dds_is_snapshot = TRUE; 1406fa9e4066Sahrens dds->dds_num_clones = ds->ds_phys->ds_num_children - 1; 1407fa9e4066Sahrens } 1408fa9e4066Sahrens 140999653d4eSeschrock dds->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 1410fa9e4066Sahrens dds->dds_last_txg = ds->ds_phys->ds_bp.blk_birth; 1411fa9e4066Sahrens 1412fa9e4066Sahrens dds->dds_objects_used = ds->ds_phys->ds_bp.blk_fill; 1413fa9e4066Sahrens dds->dds_objects_avail = DN_MAX_OBJECT - dds->dds_objects_used; 1414fa9e4066Sahrens 1415fa9e4066Sahrens /* We override the dataset's creation time... they should be the same */ 1416fa9e4066Sahrens dds->dds_creation_time = ds->ds_phys->ds_creation_time; 1417fa9e4066Sahrens dds->dds_creation_txg = ds->ds_phys->ds_creation_txg; 1418fa9e4066Sahrens dds->dds_space_refd = ds->ds_phys->ds_used_bytes; 1419fa9e4066Sahrens dds->dds_fsid_guid = ds->ds_phys->ds_fsid_guid; 1420fa9e4066Sahrens 1421fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1422fa9e4066Sahrens /* 1423fa9e4066Sahrens * This is a snapshot; override the dd's space used with 1424fa9e4066Sahrens * our unique space 1425fa9e4066Sahrens */ 1426fa9e4066Sahrens dds->dds_space_used = ds->ds_phys->ds_unique_bytes; 1427fa9e4066Sahrens dds->dds_compressed_bytes = 1428fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes; 1429fa9e4066Sahrens dds->dds_uncompressed_bytes = 1430fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes; 1431fa9e4066Sahrens } 1432fa9e4066Sahrens } 1433fa9e4066Sahrens 1434fa9e4066Sahrens dsl_pool_t * 1435fa9e4066Sahrens dsl_dataset_pool(dsl_dataset_t *ds) 1436fa9e4066Sahrens { 1437fa9e4066Sahrens return (ds->ds_dir->dd_pool); 1438fa9e4066Sahrens } 1439fa9e4066Sahrens 1440*1d452cf5Sahrens /* ARGSUSED */ 1441fa9e4066Sahrens static int 1442*1d452cf5Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 1443fa9e4066Sahrens { 1444*1d452cf5Sahrens dsl_dataset_t *ds = arg1; 1445*1d452cf5Sahrens char *newsnapname = arg2; 1446*1d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 1447fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 1448*1d452cf5Sahrens dsl_dataset_t *hds; 1449fa9e4066Sahrens uint64_t val; 1450*1d452cf5Sahrens int err; 1451fa9e4066Sahrens 1452*1d452cf5Sahrens err = dsl_dataset_open_obj(dd->dd_pool, 1453*1d452cf5Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds); 1454fa9e4066Sahrens if (err) 1455fa9e4066Sahrens return (err); 1456fa9e4066Sahrens 1457*1d452cf5Sahrens /* new name better not be in use */ 1458*1d452cf5Sahrens err = zap_lookup(mos, hds->ds_phys->ds_snapnames_zapobj, 1459*1d452cf5Sahrens newsnapname, 8, 1, &val); 1460*1d452cf5Sahrens dsl_dataset_close(hds, DS_MODE_NONE, FTAG); 1461*1d452cf5Sahrens 1462*1d452cf5Sahrens if (err == 0) 1463*1d452cf5Sahrens err = EEXIST; 1464*1d452cf5Sahrens else if (err == ENOENT) 1465*1d452cf5Sahrens err = 0; 1466*1d452cf5Sahrens return (err); 1467*1d452cf5Sahrens } 1468fa9e4066Sahrens 1469*1d452cf5Sahrens static void 1470*1d452cf5Sahrens dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1471*1d452cf5Sahrens { 1472*1d452cf5Sahrens dsl_dataset_t *ds = arg1; 1473*1d452cf5Sahrens char *newsnapname = arg2; 1474*1d452cf5Sahrens dsl_dir_t *dd = ds->ds_dir; 1475*1d452cf5Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 1476*1d452cf5Sahrens dsl_dataset_t *hds; 1477*1d452cf5Sahrens int err; 1478fa9e4066Sahrens 1479*1d452cf5Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 1480fa9e4066Sahrens 1481*1d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, 1482*1d452cf5Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds)); 1483fa9e4066Sahrens 1484*1d452cf5Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1485*1d452cf5Sahrens err = zap_remove(mos, hds->ds_phys->ds_snapnames_zapobj, 1486*1d452cf5Sahrens ds->ds_snapname, tx); 1487fa9e4066Sahrens ASSERT3U(err, ==, 0); 1488*1d452cf5Sahrens mutex_enter(&ds->ds_lock); 1489*1d452cf5Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 1490*1d452cf5Sahrens mutex_exit(&ds->ds_lock); 1491*1d452cf5Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 1492*1d452cf5Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 1493fa9e4066Sahrens ASSERT3U(err, ==, 0); 1494fa9e4066Sahrens 1495*1d452cf5Sahrens dsl_dataset_close(hds, DS_MODE_NONE, FTAG); 1496fa9e4066Sahrens } 1497fa9e4066Sahrens 1498fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 1499fa9e4066Sahrens int 1500*1d452cf5Sahrens dsl_dataset_rename(const char *oldname, const char *newname) 1501fa9e4066Sahrens { 1502fa9e4066Sahrens dsl_dir_t *dd; 1503*1d452cf5Sahrens dsl_dataset_t *ds; 1504fa9e4066Sahrens const char *tail; 1505fa9e4066Sahrens int err; 1506fa9e4066Sahrens 1507*1d452cf5Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 1508ea8dc4b6Seschrock if (err) 1509ea8dc4b6Seschrock return (err); 1510fa9e4066Sahrens if (tail == NULL) { 1511*1d452cf5Sahrens err = dsl_dir_rename(dd, newname); 1512fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1513fa9e4066Sahrens return (err); 1514fa9e4066Sahrens } 1515fa9e4066Sahrens if (tail[0] != '@') { 1516fa9e4066Sahrens /* the name ended in a nonexistant component */ 1517fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1518fa9e4066Sahrens return (ENOENT); 1519fa9e4066Sahrens } 1520fa9e4066Sahrens 1521fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1522*1d452cf5Sahrens 1523*1d452cf5Sahrens /* new name must be snapshot in same filesystem */ 1524*1d452cf5Sahrens tail = strchr(newname, '@'); 1525*1d452cf5Sahrens if (tail == NULL) 1526*1d452cf5Sahrens return (EINVAL); 1527*1d452cf5Sahrens tail++; 1528*1d452cf5Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 1529*1d452cf5Sahrens return (EXDEV); 1530*1d452cf5Sahrens 1531*1d452cf5Sahrens err = dsl_dataset_open(oldname, 1532*1d452cf5Sahrens DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &ds); 1533*1d452cf5Sahrens if (err) 1534*1d452cf5Sahrens return (err); 1535*1d452cf5Sahrens 1536*1d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 1537*1d452cf5Sahrens dsl_dataset_snapshot_rename_check, 1538*1d452cf5Sahrens dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 1539*1d452cf5Sahrens 1540*1d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG); 1541*1d452cf5Sahrens 1542fa9e4066Sahrens return (err); 1543fa9e4066Sahrens } 154499653d4eSeschrock 1545*1d452cf5Sahrens struct promotearg { 1546*1d452cf5Sahrens uint64_t used, comp, uncomp, unique; 1547*1d452cf5Sahrens uint64_t newnext_obj, snapnames_obj; 1548*1d452cf5Sahrens }; 1549*1d452cf5Sahrens 155099653d4eSeschrock static int 1551*1d452cf5Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 155299653d4eSeschrock { 1553*1d452cf5Sahrens dsl_dataset_t *hds = arg1; 1554*1d452cf5Sahrens struct promotearg *pa = arg2; 1555*1d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 1556*1d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 155799653d4eSeschrock dsl_dir_t *pdd = NULL; 155899653d4eSeschrock dsl_dataset_t *ds = NULL; 155999653d4eSeschrock dsl_dataset_t *pivot_ds = NULL; 156099653d4eSeschrock dsl_dataset_t *newnext_ds = NULL; 156199653d4eSeschrock int err; 156299653d4eSeschrock char *name = NULL; 1563*1d452cf5Sahrens uint64_t itor = 0; 156499653d4eSeschrock blkptr_t bp; 156599653d4eSeschrock 1566*1d452cf5Sahrens bzero(pa, sizeof (*pa)); 1567*1d452cf5Sahrens 156899653d4eSeschrock /* Check that it is a clone */ 156999653d4eSeschrock if (dd->dd_phys->dd_clone_parent_obj == 0) 157099653d4eSeschrock return (EINVAL); 157199653d4eSeschrock 1572*1d452cf5Sahrens /* Since this is so expensive, don't do the preliminary check */ 1573*1d452cf5Sahrens if (!dmu_tx_is_syncing(tx)) 1574*1d452cf5Sahrens return (0); 1575*1d452cf5Sahrens 1576*1d452cf5Sahrens if (err = dsl_dataset_open_obj(dp, 157799653d4eSeschrock dd->dd_phys->dd_clone_parent_obj, 157899653d4eSeschrock NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)) 157999653d4eSeschrock goto out; 158099653d4eSeschrock pdd = pivot_ds->ds_dir; 1581*1d452cf5Sahrens 1582*1d452cf5Sahrens { 1583*1d452cf5Sahrens dsl_dataset_t *phds; 1584*1d452cf5Sahrens if (err = dsl_dataset_open_obj(dd->dd_pool, 1585*1d452cf5Sahrens pdd->dd_phys->dd_head_dataset_obj, 1586*1d452cf5Sahrens NULL, DS_MODE_NONE, FTAG, &phds)) 1587*1d452cf5Sahrens goto out; 1588*1d452cf5Sahrens pa->snapnames_obj = phds->ds_phys->ds_snapnames_zapobj; 1589*1d452cf5Sahrens dsl_dataset_close(phds, DS_MODE_NONE, FTAG); 1590*1d452cf5Sahrens } 159199653d4eSeschrock 159299653d4eSeschrock if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) { 159399653d4eSeschrock err = EXDEV; 159499653d4eSeschrock goto out; 159599653d4eSeschrock } 159699653d4eSeschrock 159799653d4eSeschrock /* find pivot point's new next ds */ 159899653d4eSeschrock VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, hds->ds_object, 159999653d4eSeschrock NULL, DS_MODE_NONE, FTAG, &newnext_ds)); 160099653d4eSeschrock while (newnext_ds->ds_phys->ds_prev_snap_obj != pivot_ds->ds_object) { 160199653d4eSeschrock dsl_dataset_t *prev; 160299653d4eSeschrock 160399653d4eSeschrock if (err = dsl_dataset_open_obj(dd->dd_pool, 1604*1d452cf5Sahrens newnext_ds->ds_phys->ds_prev_snap_obj, 1605*1d452cf5Sahrens NULL, DS_MODE_NONE, FTAG, &prev)) 160699653d4eSeschrock goto out; 160799653d4eSeschrock dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); 160899653d4eSeschrock newnext_ds = prev; 160999653d4eSeschrock } 1610*1d452cf5Sahrens pa->newnext_obj = newnext_ds->ds_object; 161199653d4eSeschrock 161299653d4eSeschrock /* compute pivot point's new unique space */ 161399653d4eSeschrock while ((err = bplist_iterate(&newnext_ds->ds_deadlist, 161499653d4eSeschrock &itor, &bp)) == 0) { 161599653d4eSeschrock if (bp.blk_birth > pivot_ds->ds_phys->ds_prev_snap_txg) 1616*1d452cf5Sahrens pa->unique += bp_get_dasize(dd->dd_pool->dp_spa, &bp); 161799653d4eSeschrock } 161899653d4eSeschrock if (err != ENOENT) 161999653d4eSeschrock goto out; 162099653d4eSeschrock 162199653d4eSeschrock /* Walk the snapshots that we are moving */ 162299653d4eSeschrock name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 162399653d4eSeschrock ds = pivot_ds; 162499653d4eSeschrock /* CONSTCOND */ 162599653d4eSeschrock while (TRUE) { 162699653d4eSeschrock uint64_t val, dlused, dlcomp, dluncomp; 162799653d4eSeschrock dsl_dataset_t *prev; 162899653d4eSeschrock 162999653d4eSeschrock /* Check that the snapshot name does not conflict */ 163099653d4eSeschrock dsl_dataset_name(ds, name); 163199653d4eSeschrock err = zap_lookup(dd->dd_pool->dp_meta_objset, 163299653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 163399653d4eSeschrock 8, 1, &val); 163499653d4eSeschrock if (err != ENOENT) { 163599653d4eSeschrock if (err == 0) 163699653d4eSeschrock err = EEXIST; 163799653d4eSeschrock goto out; 163899653d4eSeschrock } 163999653d4eSeschrock 164099653d4eSeschrock /* 164199653d4eSeschrock * compute space to transfer. Each snapshot gave birth to: 164299653d4eSeschrock * (my used) - (prev's used) + (deadlist's used) 164399653d4eSeschrock */ 1644*1d452cf5Sahrens pa->used += ds->ds_phys->ds_used_bytes; 1645*1d452cf5Sahrens pa->comp += ds->ds_phys->ds_compressed_bytes; 1646*1d452cf5Sahrens pa->uncomp += ds->ds_phys->ds_uncompressed_bytes; 164799653d4eSeschrock 164899653d4eSeschrock /* If we reach the first snapshot, we're done. */ 164999653d4eSeschrock if (ds->ds_phys->ds_prev_snap_obj == 0) 165099653d4eSeschrock break; 165199653d4eSeschrock 165299653d4eSeschrock if (err = bplist_space(&ds->ds_deadlist, 165399653d4eSeschrock &dlused, &dlcomp, &dluncomp)) 165499653d4eSeschrock goto out; 165599653d4eSeschrock if (err = dsl_dataset_open_obj(dd->dd_pool, 165699653d4eSeschrock ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, 165799653d4eSeschrock FTAG, &prev)) 165899653d4eSeschrock goto out; 1659*1d452cf5Sahrens pa->used += dlused - prev->ds_phys->ds_used_bytes; 1660*1d452cf5Sahrens pa->comp += dlcomp - prev->ds_phys->ds_compressed_bytes; 1661*1d452cf5Sahrens pa->uncomp += dluncomp - prev->ds_phys->ds_uncompressed_bytes; 166299653d4eSeschrock 166399653d4eSeschrock /* 166499653d4eSeschrock * We could be a clone of a clone. If we reach our 166599653d4eSeschrock * parent's branch point, we're done. 166699653d4eSeschrock */ 166799653d4eSeschrock if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { 166899653d4eSeschrock dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); 166999653d4eSeschrock break; 167099653d4eSeschrock } 167199653d4eSeschrock if (ds != pivot_ds) 167299653d4eSeschrock dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 167399653d4eSeschrock ds = prev; 167499653d4eSeschrock } 167599653d4eSeschrock 167699653d4eSeschrock /* Check that there is enough space here */ 1677*1d452cf5Sahrens err = dsl_dir_transfer_possible(pdd, dd, pa->used); 1678*1d452cf5Sahrens 1679*1d452cf5Sahrens out: 1680*1d452cf5Sahrens if (ds && ds != pivot_ds) 1681*1d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 1682*1d452cf5Sahrens if (pivot_ds) 1683*1d452cf5Sahrens dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); 1684*1d452cf5Sahrens if (newnext_ds) 1685*1d452cf5Sahrens dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); 1686*1d452cf5Sahrens if (name) 1687*1d452cf5Sahrens kmem_free(name, MAXPATHLEN); 1688*1d452cf5Sahrens return (err); 1689*1d452cf5Sahrens } 169099653d4eSeschrock 1691*1d452cf5Sahrens static void 1692*1d452cf5Sahrens dsl_dataset_promote_sync(void *arg1, void *arg2, dmu_tx_t *tx) 1693*1d452cf5Sahrens { 1694*1d452cf5Sahrens dsl_dataset_t *hds = arg1; 1695*1d452cf5Sahrens struct promotearg *pa = arg2; 1696*1d452cf5Sahrens dsl_dir_t *dd = hds->ds_dir; 1697*1d452cf5Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 1698*1d452cf5Sahrens dsl_dir_t *pdd = NULL; 1699*1d452cf5Sahrens dsl_dataset_t *ds, *pivot_ds; 1700*1d452cf5Sahrens char *name; 1701*1d452cf5Sahrens 1702*1d452cf5Sahrens ASSERT(dd->dd_phys->dd_clone_parent_obj != 0); 1703*1d452cf5Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 1704*1d452cf5Sahrens 1705*1d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1706*1d452cf5Sahrens dd->dd_phys->dd_clone_parent_obj, 1707*1d452cf5Sahrens NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)); 1708*1d452cf5Sahrens pdd = pivot_ds->ds_dir; 170999653d4eSeschrock 171099653d4eSeschrock /* move snapshots to this dir */ 1711*1d452cf5Sahrens name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 171299653d4eSeschrock ds = pivot_ds; 171399653d4eSeschrock /* CONSTCOND */ 171499653d4eSeschrock while (TRUE) { 171599653d4eSeschrock dsl_dataset_t *prev; 171699653d4eSeschrock 171799653d4eSeschrock /* move snap name entry */ 171899653d4eSeschrock dsl_dataset_name(ds, name); 1719*1d452cf5Sahrens VERIFY(0 == zap_remove(dp->dp_meta_objset, 1720*1d452cf5Sahrens pa->snapnames_obj, ds->ds_snapname, tx)); 1721*1d452cf5Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 172299653d4eSeschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 172399653d4eSeschrock 8, 1, &ds->ds_object, tx)); 172499653d4eSeschrock 172599653d4eSeschrock /* change containing dsl_dir */ 172699653d4eSeschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 172799653d4eSeschrock ASSERT3U(ds->ds_phys->ds_dir_obj, ==, pdd->dd_object); 172899653d4eSeschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 172999653d4eSeschrock ASSERT3P(ds->ds_dir, ==, pdd); 173099653d4eSeschrock dsl_dir_close(ds->ds_dir, ds); 1731*1d452cf5Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 173299653d4eSeschrock NULL, ds, &ds->ds_dir)); 173399653d4eSeschrock 173499653d4eSeschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 173599653d4eSeschrock 173699653d4eSeschrock if (ds->ds_phys->ds_prev_snap_obj == 0) 173799653d4eSeschrock break; 173899653d4eSeschrock 1739*1d452cf5Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 174099653d4eSeschrock ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, 174199653d4eSeschrock FTAG, &prev)); 174299653d4eSeschrock 174399653d4eSeschrock if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { 174499653d4eSeschrock dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); 174599653d4eSeschrock break; 174699653d4eSeschrock } 174799653d4eSeschrock if (ds != pivot_ds) 174899653d4eSeschrock dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 174999653d4eSeschrock ds = prev; 175099653d4eSeschrock } 1751*1d452cf5Sahrens if (ds != pivot_ds) 1752*1d452cf5Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 175399653d4eSeschrock 175499653d4eSeschrock /* change pivot point's next snap */ 175599653d4eSeschrock dmu_buf_will_dirty(pivot_ds->ds_dbuf, tx); 1756*1d452cf5Sahrens pivot_ds->ds_phys->ds_next_snap_obj = pa->newnext_obj; 175799653d4eSeschrock 175899653d4eSeschrock /* change clone_parent-age */ 175999653d4eSeschrock dmu_buf_will_dirty(dd->dd_dbuf, tx); 176099653d4eSeschrock ASSERT3U(dd->dd_phys->dd_clone_parent_obj, ==, pivot_ds->ds_object); 176199653d4eSeschrock dd->dd_phys->dd_clone_parent_obj = pdd->dd_phys->dd_clone_parent_obj; 176299653d4eSeschrock dmu_buf_will_dirty(pdd->dd_dbuf, tx); 176399653d4eSeschrock pdd->dd_phys->dd_clone_parent_obj = pivot_ds->ds_object; 176499653d4eSeschrock 176599653d4eSeschrock /* change space accounting */ 1766*1d452cf5Sahrens dsl_dir_diduse_space(pdd, -pa->used, -pa->comp, -pa->uncomp, tx); 1767*1d452cf5Sahrens dsl_dir_diduse_space(dd, pa->used, pa->comp, pa->uncomp, tx); 1768*1d452cf5Sahrens pivot_ds->ds_phys->ds_unique_bytes = pa->unique; 176999653d4eSeschrock 1770*1d452cf5Sahrens dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); 1771*1d452cf5Sahrens kmem_free(name, MAXPATHLEN); 177299653d4eSeschrock } 177399653d4eSeschrock 177499653d4eSeschrock int 177599653d4eSeschrock dsl_dataset_promote(const char *name) 177699653d4eSeschrock { 177799653d4eSeschrock dsl_dataset_t *ds; 177899653d4eSeschrock int err; 177999653d4eSeschrock dmu_object_info_t doi; 1780*1d452cf5Sahrens struct promotearg pa; 178199653d4eSeschrock 178299653d4eSeschrock err = dsl_dataset_open(name, DS_MODE_NONE, FTAG, &ds); 178399653d4eSeschrock if (err) 178499653d4eSeschrock return (err); 178599653d4eSeschrock 178699653d4eSeschrock err = dmu_object_info(ds->ds_dir->dd_pool->dp_meta_objset, 178799653d4eSeschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 178899653d4eSeschrock if (err) { 178999653d4eSeschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 179099653d4eSeschrock return (err); 179199653d4eSeschrock } 179299653d4eSeschrock 179399653d4eSeschrock /* 179499653d4eSeschrock * Add in 128x the snapnames zapobj size, since we will be moving 179599653d4eSeschrock * a bunch of snapnames to the promoted ds, and dirtying their 179699653d4eSeschrock * bonus buffers. 179799653d4eSeschrock */ 1798*1d452cf5Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 1799*1d452cf5Sahrens dsl_dataset_promote_check, 1800*1d452cf5Sahrens dsl_dataset_promote_sync, ds, &pa, 2 + 2 * doi.doi_physical_blks); 180199653d4eSeschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 180299653d4eSeschrock return (err); 180399653d4eSeschrock } 1804