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> 31fa9e4066Sahrens #include <sys/dmu_traverse.h> 32fa9e4066Sahrens #include <sys/dmu_tx.h> 33fa9e4066Sahrens #include <sys/arc.h> 34fa9e4066Sahrens #include <sys/zio.h> 35fa9e4066Sahrens #include <sys/zap.h> 36fa9e4066Sahrens #include <sys/unique.h> 37fa9e4066Sahrens #include <sys/zfs_context.h> 38fa9e4066Sahrens 39*e1930233Sbonwick static int dsl_dataset_destroy_begin_sync(dsl_dir_t *dd, 40*e1930233Sbonwick void *arg, dmu_tx_t *tx); 41*e1930233Sbonwick 42fa9e4066Sahrens #define DOS_REF_MAX (1ULL << 62) 43fa9e4066Sahrens 44fa9e4066Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 45fa9e4066Sahrens 46fa9e4066Sahrens #define BP_GET_UCSIZE(bp) \ 47fa9e4066Sahrens ((BP_GET_LEVEL(bp) > 0 || dmu_ot[BP_GET_TYPE(bp)].ot_metadata) ? \ 48fa9e4066Sahrens BP_GET_PSIZE(bp) : BP_GET_LSIZE(bp)); 49fa9e4066Sahrens 50fa9e4066Sahrens /* 51fa9e4066Sahrens * We use weighted reference counts to express the various forms of exclusion 52fa9e4066Sahrens * between different open modes. A STANDARD open is 1 point, an EXCLUSIVE open 53fa9e4066Sahrens * is DOS_REF_MAX, and a PRIMARY open is little more than half of an EXCLUSIVE. 54fa9e4066Sahrens * This makes the exclusion logic simple: the total refcnt for all opens cannot 55fa9e4066Sahrens * exceed DOS_REF_MAX. For example, EXCLUSIVE opens are exclusive because their 56fa9e4066Sahrens * weight (DOS_REF_MAX) consumes the entire refcnt space. PRIMARY opens consume 57fa9e4066Sahrens * just over half of the refcnt space, so there can't be more than one, but it 58fa9e4066Sahrens * can peacefully coexist with any number of STANDARD opens. 59fa9e4066Sahrens */ 60fa9e4066Sahrens static uint64_t ds_refcnt_weight[DS_MODE_LEVELS] = { 61fa9e4066Sahrens 0, /* DOS_MODE_NONE - invalid */ 62fa9e4066Sahrens 1, /* DOS_MODE_STANDARD - unlimited number */ 63fa9e4066Sahrens (DOS_REF_MAX >> 1) + 1, /* DOS_MODE_PRIMARY - only one of these */ 64fa9e4066Sahrens DOS_REF_MAX /* DOS_MODE_EXCLUSIVE - no other opens */ 65fa9e4066Sahrens }; 66fa9e4066Sahrens 67fa9e4066Sahrens 68fa9e4066Sahrens void 69fa9e4066Sahrens dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 70fa9e4066Sahrens { 71fa9e4066Sahrens int used = BP_GET_ASIZE(bp); 72fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 73fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 74fa9e4066Sahrens 75fa9e4066Sahrens dprintf_bp(bp, "born, ds=%p\n", ds); 76fa9e4066Sahrens 77fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 78fa9e4066Sahrens /* It could have been compressed away to nothing */ 79fa9e4066Sahrens if (BP_IS_HOLE(bp)) 80fa9e4066Sahrens return; 81fa9e4066Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 82fa9e4066Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 83fa9e4066Sahrens if (ds == NULL) { 84fa9e4066Sahrens /* 85fa9e4066Sahrens * Account for the meta-objset space in its placeholder 86fa9e4066Sahrens * dsl_dir. 87fa9e4066Sahrens */ 88fa9e4066Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 89fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 90fa9e4066Sahrens used, compressed, uncompressed, tx); 91fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 92fa9e4066Sahrens return; 93fa9e4066Sahrens } 94fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 95fa9e4066Sahrens mutex_enter(&ds->ds_lock); 96fa9e4066Sahrens ds->ds_phys->ds_used_bytes += used; 97fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 98fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 99fa9e4066Sahrens ds->ds_phys->ds_unique_bytes += used; 100fa9e4066Sahrens mutex_exit(&ds->ds_lock); 101fa9e4066Sahrens dsl_dir_diduse_space(ds->ds_dir, 102fa9e4066Sahrens used, compressed, uncompressed, tx); 103fa9e4066Sahrens } 104fa9e4066Sahrens 105fa9e4066Sahrens void 106fa9e4066Sahrens dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 107fa9e4066Sahrens { 108fa9e4066Sahrens int used = BP_GET_ASIZE(bp); 109fa9e4066Sahrens int compressed = BP_GET_PSIZE(bp); 110fa9e4066Sahrens int uncompressed = BP_GET_UCSIZE(bp); 111fa9e4066Sahrens 112fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 113fa9e4066Sahrens if (BP_IS_HOLE(bp)) 114fa9e4066Sahrens return; 115fa9e4066Sahrens 116fa9e4066Sahrens ASSERT(used > 0); 117fa9e4066Sahrens if (ds == NULL) { 118fa9e4066Sahrens /* 119fa9e4066Sahrens * Account for the meta-objset space in its placeholder 120fa9e4066Sahrens * dataset. 121fa9e4066Sahrens */ 122fa9e4066Sahrens /* XXX this can fail, what do we do when it does? */ 123fa9e4066Sahrens (void) arc_free(NULL, tx->tx_pool->dp_spa, 124fa9e4066Sahrens tx->tx_txg, bp, NULL, NULL, ARC_WAIT); 125fa9e4066Sahrens bzero(bp, sizeof (blkptr_t)); 126fa9e4066Sahrens 127fa9e4066Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 128fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 129fa9e4066Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 130fa9e4066Sahrens return; 131fa9e4066Sahrens } 132fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 133fa9e4066Sahrens 134fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 135fa9e4066Sahrens 136fa9e4066Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 137fa9e4066Sahrens dprintf_bp(bp, "freeing: %s", ""); 138fa9e4066Sahrens /* XXX check return code? */ 139fa9e4066Sahrens (void) arc_free(NULL, tx->tx_pool->dp_spa, 140fa9e4066Sahrens tx->tx_txg, bp, NULL, NULL, ARC_WAIT); 141fa9e4066Sahrens 142fa9e4066Sahrens mutex_enter(&ds->ds_lock); 143fa9e4066Sahrens /* XXX unique_bytes is not accurate for head datasets */ 144fa9e4066Sahrens /* ASSERT3U(ds->ds_phys->ds_unique_bytes, >=, used); */ 145fa9e4066Sahrens ds->ds_phys->ds_unique_bytes -= used; 146fa9e4066Sahrens mutex_exit(&ds->ds_lock); 147fa9e4066Sahrens dsl_dir_diduse_space(ds->ds_dir, 148fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 149fa9e4066Sahrens } else { 150fa9e4066Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 151ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 152fa9e4066Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 153fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 154fa9e4066Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, 155fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj); 156fa9e4066Sahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 157fa9e4066Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 158fa9e4066Sahrens ds->ds_object && 159fa9e4066Sahrens bp->blk_birth > 160fa9e4066Sahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 161fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 162fa9e4066Sahrens mutex_enter(&ds->ds_prev->ds_lock); 163fa9e4066Sahrens ds->ds_prev->ds_phys->ds_unique_bytes += 164fa9e4066Sahrens used; 165fa9e4066Sahrens mutex_exit(&ds->ds_prev->ds_lock); 166fa9e4066Sahrens } 167fa9e4066Sahrens } 168fa9e4066Sahrens } 169fa9e4066Sahrens bzero(bp, sizeof (blkptr_t)); 170fa9e4066Sahrens mutex_enter(&ds->ds_lock); 171fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 172fa9e4066Sahrens ds->ds_phys->ds_used_bytes -= used; 173fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 174fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 175fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 176fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 177fa9e4066Sahrens mutex_exit(&ds->ds_lock); 178fa9e4066Sahrens } 179fa9e4066Sahrens 180ea8dc4b6Seschrock uint64_t 181ea8dc4b6Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 182fa9e4066Sahrens { 183ea8dc4b6Seschrock uint64_t txg; 184fa9e4066Sahrens dsl_dir_t *dd; 185ea8dc4b6Seschrock 186fa9e4066Sahrens if (ds == NULL) 187ea8dc4b6Seschrock return (0); 188fa9e4066Sahrens /* 189fa9e4066Sahrens * The snapshot creation could fail, but that would cause an 190fa9e4066Sahrens * incorrect FALSE return, which would only result in an 191fa9e4066Sahrens * overestimation of the amount of space that an operation would 192fa9e4066Sahrens * consume, which is OK. 193fa9e4066Sahrens * 194fa9e4066Sahrens * There's also a small window where we could miss a pending 195fa9e4066Sahrens * snapshot, because we could set the sync task in the quiescing 196fa9e4066Sahrens * phase. So this should only be used as a guess. 197fa9e4066Sahrens */ 198fa9e4066Sahrens dd = ds->ds_dir; 199fa9e4066Sahrens mutex_enter(&dd->dd_lock); 200ea8dc4b6Seschrock if (dd->dd_sync_func == dsl_dataset_snapshot_sync) 201ea8dc4b6Seschrock txg = dd->dd_sync_txg; 202fa9e4066Sahrens else 203ea8dc4b6Seschrock txg = ds->ds_phys->ds_prev_snap_txg; 204fa9e4066Sahrens mutex_exit(&dd->dd_lock); 205ea8dc4b6Seschrock 206ea8dc4b6Seschrock return (txg); 207ea8dc4b6Seschrock } 208ea8dc4b6Seschrock 209ea8dc4b6Seschrock int 210ea8dc4b6Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 211ea8dc4b6Seschrock { 212ea8dc4b6Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 213fa9e4066Sahrens } 214fa9e4066Sahrens 215fa9e4066Sahrens /* ARGSUSED */ 216fa9e4066Sahrens static void 217fa9e4066Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 218fa9e4066Sahrens { 219fa9e4066Sahrens dsl_dataset_t *ds = dsv; 220fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 221fa9e4066Sahrens 222fa9e4066Sahrens /* open_refcount == DOS_REF_MAX when deleting */ 223fa9e4066Sahrens ASSERT(ds->ds_open_refcount == 0 || 224fa9e4066Sahrens ds->ds_open_refcount == DOS_REF_MAX); 225fa9e4066Sahrens 226fa9e4066Sahrens dprintf_ds(ds, "evicting %s\n", ""); 227fa9e4066Sahrens 228fa9e4066Sahrens unique_remove(ds->ds_phys->ds_fsid_guid); 229fa9e4066Sahrens 230fa9e4066Sahrens if (ds->ds_user_ptr != NULL) 231fa9e4066Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 232fa9e4066Sahrens 233fa9e4066Sahrens if (ds->ds_prev) { 234fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 235fa9e4066Sahrens ds->ds_prev = NULL; 236fa9e4066Sahrens } 237fa9e4066Sahrens 238fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 239fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 240fa9e4066Sahrens 241fa9e4066Sahrens if (list_link_active(&ds->ds_synced_link)) 242fa9e4066Sahrens list_remove(&dp->dp_synced_objsets, ds); 243fa9e4066Sahrens 244fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 245fa9e4066Sahrens } 246fa9e4066Sahrens 247ea8dc4b6Seschrock static int 248fa9e4066Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 249fa9e4066Sahrens { 250fa9e4066Sahrens dsl_dataset_phys_t *headphys; 251fa9e4066Sahrens int err; 252fa9e4066Sahrens dmu_buf_t *headdbuf; 253fa9e4066Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 254fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 255fa9e4066Sahrens 256fa9e4066Sahrens if (ds->ds_snapname[0]) 257ea8dc4b6Seschrock return (0); 258fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 259ea8dc4b6Seschrock return (0); 260fa9e4066Sahrens 261ea8dc4b6Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 262ea8dc4b6Seschrock FTAG, &headdbuf); 263ea8dc4b6Seschrock if (err) 264ea8dc4b6Seschrock return (err); 265fa9e4066Sahrens headphys = headdbuf->db_data; 266fa9e4066Sahrens err = zap_value_search(dp->dp_meta_objset, 267fa9e4066Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, ds->ds_snapname); 268ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 269ea8dc4b6Seschrock return (err); 270fa9e4066Sahrens } 271fa9e4066Sahrens 272ea8dc4b6Seschrock int 273fa9e4066Sahrens dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname, 274ea8dc4b6Seschrock int mode, void *tag, dsl_dataset_t **dsp) 275fa9e4066Sahrens { 276fa9e4066Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 277fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 278fa9e4066Sahrens dmu_buf_t *dbuf; 279fa9e4066Sahrens dsl_dataset_t *ds; 280ea8dc4b6Seschrock int err; 281fa9e4066Sahrens 282fa9e4066Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 283fa9e4066Sahrens dsl_pool_sync_context(dp)); 284fa9e4066Sahrens 285ea8dc4b6Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 286ea8dc4b6Seschrock if (err) 287ea8dc4b6Seschrock return (err); 288fa9e4066Sahrens ds = dmu_buf_get_user(dbuf); 289fa9e4066Sahrens if (ds == NULL) { 290fa9e4066Sahrens dsl_dataset_t *winner; 291fa9e4066Sahrens 292fa9e4066Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 293fa9e4066Sahrens ds->ds_dbuf = dbuf; 294fa9e4066Sahrens ds->ds_object = dsobj; 295fa9e4066Sahrens ds->ds_phys = dbuf->db_data; 296fa9e4066Sahrens 297ea8dc4b6Seschrock err = bplist_open(&ds->ds_deadlist, 298fa9e4066Sahrens mos, ds->ds_phys->ds_deadlist_obj); 299ea8dc4b6Seschrock if (err == 0) { 300ea8dc4b6Seschrock err = dsl_dir_open_obj(dp, 301ea8dc4b6Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 302ea8dc4b6Seschrock } 303ea8dc4b6Seschrock if (err) { 304ea8dc4b6Seschrock /* 305ea8dc4b6Seschrock * we don't really need to close the blist if we 306ea8dc4b6Seschrock * just opened it. 307ea8dc4b6Seschrock */ 308ea8dc4b6Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 309ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 310ea8dc4b6Seschrock return (err); 311ea8dc4b6Seschrock } 312fa9e4066Sahrens 313fa9e4066Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == dsobj) { 314fa9e4066Sahrens ds->ds_snapname[0] = '\0'; 315fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 316ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, 317fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 318ea8dc4b6Seschrock DS_MODE_NONE, ds, &ds->ds_prev); 319fa9e4066Sahrens } 320fa9e4066Sahrens } else { 321fa9e4066Sahrens if (snapname) { 322fa9e4066Sahrens #ifdef ZFS_DEBUG 323fa9e4066Sahrens dsl_dataset_phys_t *headphys; 324ea8dc4b6Seschrock dmu_buf_t *headdbuf; 325ea8dc4b6Seschrock err = dmu_bonus_hold(mos, 326ea8dc4b6Seschrock ds->ds_dir->dd_phys->dd_head_dataset_obj, 327ea8dc4b6Seschrock FTAG, &headdbuf); 328ea8dc4b6Seschrock if (err == 0) { 329ea8dc4b6Seschrock headphys = headdbuf->db_data; 330ea8dc4b6Seschrock uint64_t foundobj; 331ea8dc4b6Seschrock err = zap_lookup(dp->dp_meta_objset, 332ea8dc4b6Seschrock headphys->ds_snapnames_zapobj, 333ea8dc4b6Seschrock snapname, sizeof (foundobj), 1, 334ea8dc4b6Seschrock &foundobj); 335ea8dc4b6Seschrock ASSERT3U(foundobj, ==, dsobj); 336ea8dc4b6Seschrock dmu_buf_rele(headdbuf, FTAG); 337ea8dc4b6Seschrock } 338fa9e4066Sahrens #endif 339fa9e4066Sahrens (void) strcat(ds->ds_snapname, snapname); 340fa9e4066Sahrens } else if (zfs_flags & ZFS_DEBUG_SNAPNAMES) { 341ea8dc4b6Seschrock err = dsl_dataset_get_snapname(ds); 342fa9e4066Sahrens } 343fa9e4066Sahrens } 344fa9e4066Sahrens 345ea8dc4b6Seschrock if (err == 0) { 346ea8dc4b6Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 347ea8dc4b6Seschrock dsl_dataset_evict); 348ea8dc4b6Seschrock } 349ea8dc4b6Seschrock if (err || winner) { 350fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 351fa9e4066Sahrens if (ds->ds_prev) { 352fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, 353fa9e4066Sahrens DS_MODE_NONE, ds); 354fa9e4066Sahrens } 355fa9e4066Sahrens dsl_dir_close(ds->ds_dir, ds); 356fa9e4066Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 357ea8dc4b6Seschrock if (err) { 358ea8dc4b6Seschrock dmu_buf_rele(dbuf, tag); 359ea8dc4b6Seschrock return (err); 360ea8dc4b6Seschrock } 361fa9e4066Sahrens ds = winner; 362fa9e4066Sahrens } else { 363fa9e4066Sahrens uint64_t new = 364fa9e4066Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 365fa9e4066Sahrens if (new != ds->ds_phys->ds_fsid_guid) { 366fa9e4066Sahrens /* XXX it won't necessarily be synced... */ 367fa9e4066Sahrens ds->ds_phys->ds_fsid_guid = new; 368fa9e4066Sahrens } 369fa9e4066Sahrens } 370fa9e4066Sahrens } 371fa9e4066Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 372fa9e4066Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 373fa9e4066Sahrens 374fa9e4066Sahrens mutex_enter(&ds->ds_lock); 375fa9e4066Sahrens if ((DS_MODE_LEVEL(mode) == DS_MODE_PRIMARY && 376*e1930233Sbonwick ds->ds_phys->ds_inconsistent && !DS_MODE_IS_INCONSISTENT(mode)) || 377fa9e4066Sahrens (ds->ds_open_refcount + weight > DOS_REF_MAX)) { 378fa9e4066Sahrens mutex_exit(&ds->ds_lock); 379fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 380ea8dc4b6Seschrock return (EBUSY); 381fa9e4066Sahrens } 382fa9e4066Sahrens ds->ds_open_refcount += weight; 383fa9e4066Sahrens mutex_exit(&ds->ds_lock); 384fa9e4066Sahrens 385ea8dc4b6Seschrock *dsp = ds; 386ea8dc4b6Seschrock return (0); 387fa9e4066Sahrens } 388fa9e4066Sahrens 389fa9e4066Sahrens int 390fa9e4066Sahrens dsl_dataset_open_spa(spa_t *spa, const char *name, int mode, 391fa9e4066Sahrens void *tag, dsl_dataset_t **dsp) 392fa9e4066Sahrens { 393fa9e4066Sahrens dsl_dir_t *dd; 394fa9e4066Sahrens dsl_pool_t *dp; 395fa9e4066Sahrens const char *tail; 396fa9e4066Sahrens uint64_t obj; 397fa9e4066Sahrens dsl_dataset_t *ds = NULL; 398fa9e4066Sahrens int err = 0; 399fa9e4066Sahrens 400ea8dc4b6Seschrock err = dsl_dir_open_spa(spa, name, FTAG, &dd, &tail); 401ea8dc4b6Seschrock if (err) 402ea8dc4b6Seschrock return (err); 403fa9e4066Sahrens 404fa9e4066Sahrens dp = dd->dd_pool; 405fa9e4066Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 406fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 407fa9e4066Sahrens if (obj == 0) { 408fa9e4066Sahrens /* A dataset with no associated objset */ 409fa9e4066Sahrens err = ENOENT; 410fa9e4066Sahrens goto out; 411fa9e4066Sahrens } 412fa9e4066Sahrens 413fa9e4066Sahrens if (tail != NULL) { 414fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 415fa9e4066Sahrens 416ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, obj, NULL, 417ea8dc4b6Seschrock DS_MODE_NONE, tag, &ds); 418ea8dc4b6Seschrock if (err) 419ea8dc4b6Seschrock goto out; 420fa9e4066Sahrens obj = ds->ds_phys->ds_snapnames_zapobj; 421fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 422fa9e4066Sahrens ds = NULL; 423fa9e4066Sahrens 424fa9e4066Sahrens if (tail[0] != '@') { 425fa9e4066Sahrens err = ENOENT; 426fa9e4066Sahrens goto out; 427fa9e4066Sahrens } 428fa9e4066Sahrens tail++; 429fa9e4066Sahrens 430fa9e4066Sahrens /* Look for a snapshot */ 431fa9e4066Sahrens if (!DS_MODE_IS_READONLY(mode)) { 432fa9e4066Sahrens err = EROFS; 433fa9e4066Sahrens goto out; 434fa9e4066Sahrens } 435fa9e4066Sahrens dprintf("looking for snapshot '%s'\n", tail); 436fa9e4066Sahrens err = zap_lookup(mos, obj, tail, 8, 1, &obj); 437fa9e4066Sahrens if (err) 438fa9e4066Sahrens goto out; 439fa9e4066Sahrens } 440ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, obj, tail, mode, tag, &ds); 441fa9e4066Sahrens 442fa9e4066Sahrens out: 443fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 444fa9e4066Sahrens dsl_dir_close(dd, FTAG); 445fa9e4066Sahrens 446fa9e4066Sahrens ASSERT3U((err == 0), ==, (ds != NULL)); 447fa9e4066Sahrens /* ASSERT(ds == NULL || strcmp(name, ds->ds_name) == 0); */ 448fa9e4066Sahrens 449fa9e4066Sahrens *dsp = ds; 450fa9e4066Sahrens return (err); 451fa9e4066Sahrens } 452fa9e4066Sahrens 453fa9e4066Sahrens int 454fa9e4066Sahrens dsl_dataset_open(const char *name, int mode, void *tag, dsl_dataset_t **dsp) 455fa9e4066Sahrens { 456fa9e4066Sahrens return (dsl_dataset_open_spa(NULL, name, mode, tag, dsp)); 457fa9e4066Sahrens } 458fa9e4066Sahrens 459fa9e4066Sahrens void 460fa9e4066Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 461fa9e4066Sahrens { 462fa9e4066Sahrens if (ds == NULL) { 463fa9e4066Sahrens (void) strcpy(name, "mos"); 464fa9e4066Sahrens } else { 465fa9e4066Sahrens dsl_dir_name(ds->ds_dir, name); 466ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 467fa9e4066Sahrens if (ds->ds_snapname[0]) { 468fa9e4066Sahrens (void) strcat(name, "@"); 469fa9e4066Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 470fa9e4066Sahrens /* 471fa9e4066Sahrens * We use a "recursive" mutex so that we 472fa9e4066Sahrens * can call dprintf_ds() with ds_lock held. 473fa9e4066Sahrens */ 474fa9e4066Sahrens mutex_enter(&ds->ds_lock); 475fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 476fa9e4066Sahrens mutex_exit(&ds->ds_lock); 477fa9e4066Sahrens } else { 478fa9e4066Sahrens (void) strcat(name, ds->ds_snapname); 479fa9e4066Sahrens } 480fa9e4066Sahrens } 481fa9e4066Sahrens } 482fa9e4066Sahrens } 483fa9e4066Sahrens 484fa9e4066Sahrens void 485fa9e4066Sahrens dsl_dataset_close(dsl_dataset_t *ds, int mode, void *tag) 486fa9e4066Sahrens { 487fa9e4066Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 488fa9e4066Sahrens mutex_enter(&ds->ds_lock); 489fa9e4066Sahrens ASSERT3U(ds->ds_open_refcount, >=, weight); 490fa9e4066Sahrens ds->ds_open_refcount -= weight; 491fa9e4066Sahrens dprintf_ds(ds, "closing mode %u refcount now 0x%llx\n", 492fa9e4066Sahrens mode, ds->ds_open_refcount); 493fa9e4066Sahrens mutex_exit(&ds->ds_lock); 494fa9e4066Sahrens 495ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 496fa9e4066Sahrens } 497fa9e4066Sahrens 498fa9e4066Sahrens void 499fa9e4066Sahrens dsl_dataset_create_root(dsl_pool_t *dp, uint64_t *ddobjp, dmu_tx_t *tx) 500fa9e4066Sahrens { 501fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 502fa9e4066Sahrens dmu_buf_t *dbuf; 503fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 504fa9e4066Sahrens dsl_dataset_t *ds; 505fa9e4066Sahrens uint64_t dsobj; 506fa9e4066Sahrens dsl_dir_t *dd; 507fa9e4066Sahrens 508fa9e4066Sahrens dsl_dir_create_root(mos, ddobjp, tx); 509ea8dc4b6Seschrock VERIFY(0 == dsl_dir_open_obj(dp, *ddobjp, NULL, FTAG, &dd)); 510fa9e4066Sahrens 5111649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 5121649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 513ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 514fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 515fa9e4066Sahrens dsphys = dbuf->db_data; 516fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 517fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 518ea8dc4b6Seschrock unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 519fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 520fa9e4066Sahrens sizeof (dsphys->ds_guid)); 521fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 52287e5029aSahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 523fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 524fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 525fa9e4066Sahrens dsphys->ds_deadlist_obj = 526fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 527ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 528fa9e4066Sahrens 529fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 530fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 531fa9e4066Sahrens dsl_dir_close(dd, FTAG); 532fa9e4066Sahrens 533ea8dc4b6Seschrock VERIFY(0 == 534ea8dc4b6Seschrock dsl_dataset_open_obj(dp, dsobj, NULL, DS_MODE_NONE, FTAG, &ds)); 535fa9e4066Sahrens (void) dmu_objset_create_impl(dp->dp_spa, ds, DMU_OST_ZFS, tx); 536fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 537fa9e4066Sahrens } 538fa9e4066Sahrens 539fa9e4066Sahrens int 540fa9e4066Sahrens dsl_dataset_create_sync(dsl_dir_t *pds, const char *fullname, 541fa9e4066Sahrens const char *lastname, dsl_dataset_t *clone_parent, dmu_tx_t *tx) 542fa9e4066Sahrens { 543fa9e4066Sahrens int err; 544fa9e4066Sahrens dsl_pool_t *dp = pds->dd_pool; 545fa9e4066Sahrens dmu_buf_t *dbuf; 546fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 547fa9e4066Sahrens uint64_t dsobj; 548fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 549fa9e4066Sahrens dsl_dir_t *dd; 550fa9e4066Sahrens 551fa9e4066Sahrens if (clone_parent != NULL) { 552fa9e4066Sahrens /* 553fa9e4066Sahrens * You can't clone across pools. 554fa9e4066Sahrens */ 555fa9e4066Sahrens if (clone_parent->ds_dir->dd_pool != dp) 556fa9e4066Sahrens return (EXDEV); 557fa9e4066Sahrens 558fa9e4066Sahrens /* 559fa9e4066Sahrens * You can only clone snapshots, not the head datasets. 560fa9e4066Sahrens */ 561fa9e4066Sahrens if (clone_parent->ds_phys->ds_num_children == 0) 562fa9e4066Sahrens return (EINVAL); 563fa9e4066Sahrens } 564fa9e4066Sahrens 565fa9e4066Sahrens ASSERT(lastname[0] != '@'); 566fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 567fa9e4066Sahrens 568fa9e4066Sahrens err = dsl_dir_create_sync(pds, lastname, tx); 569fa9e4066Sahrens if (err) 570fa9e4066Sahrens return (err); 571ea8dc4b6Seschrock VERIFY(0 == dsl_dir_open_spa(dp->dp_spa, fullname, FTAG, &dd, NULL)); 572fa9e4066Sahrens 573fa9e4066Sahrens /* This is the point of no (unsuccessful) return */ 574fa9e4066Sahrens 5751649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 5761649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 577ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 578fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 579fa9e4066Sahrens dsphys = dbuf->db_data; 580fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 581fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 582fa9e4066Sahrens unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 583fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 584fa9e4066Sahrens sizeof (dsphys->ds_guid)); 585fa9e4066Sahrens dsphys->ds_snapnames_zapobj = 58687e5029aSahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 587fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 588fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 589fa9e4066Sahrens dsphys->ds_deadlist_obj = 590fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 591fa9e4066Sahrens if (clone_parent) { 592fa9e4066Sahrens dsphys->ds_prev_snap_obj = clone_parent->ds_object; 593fa9e4066Sahrens dsphys->ds_prev_snap_txg = 594fa9e4066Sahrens clone_parent->ds_phys->ds_creation_txg; 595fa9e4066Sahrens dsphys->ds_used_bytes = 596fa9e4066Sahrens clone_parent->ds_phys->ds_used_bytes; 597fa9e4066Sahrens dsphys->ds_compressed_bytes = 598fa9e4066Sahrens clone_parent->ds_phys->ds_compressed_bytes; 599fa9e4066Sahrens dsphys->ds_uncompressed_bytes = 600fa9e4066Sahrens clone_parent->ds_phys->ds_uncompressed_bytes; 601fa9e4066Sahrens dsphys->ds_bp = clone_parent->ds_phys->ds_bp; 602fa9e4066Sahrens 603fa9e4066Sahrens dmu_buf_will_dirty(clone_parent->ds_dbuf, tx); 604fa9e4066Sahrens clone_parent->ds_phys->ds_num_children++; 605fa9e4066Sahrens 606fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 607fa9e4066Sahrens dd->dd_phys->dd_clone_parent_obj = clone_parent->ds_object; 608fa9e4066Sahrens } 609ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 610fa9e4066Sahrens 611fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 612fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 613fa9e4066Sahrens dsl_dir_close(dd, FTAG); 614fa9e4066Sahrens 615fa9e4066Sahrens return (0); 616fa9e4066Sahrens } 617fa9e4066Sahrens 618fa9e4066Sahrens int 619fa9e4066Sahrens dsl_dataset_destroy(const char *name) 620fa9e4066Sahrens { 621fa9e4066Sahrens int err; 622fa9e4066Sahrens dsl_pool_t *dp; 623fa9e4066Sahrens dsl_dir_t *dd; 624fa9e4066Sahrens const char *tail; 625fa9e4066Sahrens 626ea8dc4b6Seschrock err = dsl_dir_open(name, FTAG, &dd, &tail); 627ea8dc4b6Seschrock if (err) 628ea8dc4b6Seschrock return (err); 629fa9e4066Sahrens 630fa9e4066Sahrens dp = dd->dd_pool; 631fa9e4066Sahrens if (tail != NULL) { 632fa9e4066Sahrens if (tail[0] != '@') { 633fa9e4066Sahrens dsl_dir_close(dd, FTAG); 634fa9e4066Sahrens return (ENOENT); 635fa9e4066Sahrens } 636fa9e4066Sahrens tail++; 637fa9e4066Sahrens /* Just blow away the snapshot */ 638fa9e4066Sahrens do { 639fa9e4066Sahrens txg_wait_synced(dp, 0); 640fa9e4066Sahrens err = dsl_dir_sync_task(dd, 641fa9e4066Sahrens dsl_dataset_destroy_sync, (void*)tail, 0); 642fa9e4066Sahrens } while (err == EAGAIN); 643fa9e4066Sahrens dsl_dir_close(dd, FTAG); 644fa9e4066Sahrens } else { 645fa9e4066Sahrens char buf[MAXNAMELEN]; 646fa9e4066Sahrens char *cp; 647*e1930233Sbonwick objset_t *os; 648*e1930233Sbonwick uint64_t obj; 649fa9e4066Sahrens dsl_dir_t *pds; 650*e1930233Sbonwick 651fa9e4066Sahrens if (dd->dd_phys->dd_parent_obj == 0) { 652fa9e4066Sahrens dsl_dir_close(dd, FTAG); 653fa9e4066Sahrens return (EINVAL); 654fa9e4066Sahrens } 655*e1930233Sbonwick 656*e1930233Sbonwick err = dmu_objset_open(name, DMU_OST_ANY, 657*e1930233Sbonwick DS_MODE_PRIMARY | DS_MODE_INCONSISTENT, &os); 658*e1930233Sbonwick if (err) { 659*e1930233Sbonwick dsl_dir_close(dd, FTAG); 660*e1930233Sbonwick return (err); 661*e1930233Sbonwick } 662*e1930233Sbonwick 663*e1930233Sbonwick /* 664*e1930233Sbonwick * Check for errors and mark this ds as inconsistent, in 665*e1930233Sbonwick * case we crash while freeing the objects. 666*e1930233Sbonwick */ 667*e1930233Sbonwick err = dsl_dir_sync_task(os->os->os_dsl_dataset->ds_dir, 668*e1930233Sbonwick dsl_dataset_destroy_begin_sync, os->os->os_dsl_dataset, 0); 669*e1930233Sbonwick if (err) { 670*e1930233Sbonwick dmu_objset_close(os); 671*e1930233Sbonwick dsl_dir_close(dd, FTAG); 672*e1930233Sbonwick return (err); 673*e1930233Sbonwick } 674*e1930233Sbonwick 675fa9e4066Sahrens /* 676*e1930233Sbonwick * remove the objects in open context, so that we won't 677*e1930233Sbonwick * have too much to do in syncing context. 678fa9e4066Sahrens */ 679*e1930233Sbonwick for (obj = 0; err == 0; 680*e1930233Sbonwick err = dmu_object_next(os, &obj, FALSE)) { 681*e1930233Sbonwick dmu_tx_t *tx = dmu_tx_create(os); 682*e1930233Sbonwick dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END); 683*e1930233Sbonwick dmu_tx_hold_bonus(tx, obj); 684*e1930233Sbonwick err = dmu_tx_assign(tx, TXG_WAIT); 685*e1930233Sbonwick if (err) { 686*e1930233Sbonwick /* 687*e1930233Sbonwick * Perhaps there is not enough disk 688*e1930233Sbonwick * space. Just deal with it from 689*e1930233Sbonwick * dsl_dataset_destroy_sync(). 690*e1930233Sbonwick */ 691*e1930233Sbonwick dmu_tx_abort(tx); 692*e1930233Sbonwick continue; 693*e1930233Sbonwick } 694*e1930233Sbonwick VERIFY(0 == dmu_object_free(os, obj, tx)); 695*e1930233Sbonwick dmu_tx_commit(tx); 696*e1930233Sbonwick } 697*e1930233Sbonwick dmu_objset_close(os); 698*e1930233Sbonwick if (err != ESRCH) { 699*e1930233Sbonwick dsl_dir_close(dd, FTAG); 700*e1930233Sbonwick return (err); 701*e1930233Sbonwick } 702*e1930233Sbonwick 703*e1930233Sbonwick /* Make sure it's not dirty before we finish destroying it. */ 704fa9e4066Sahrens txg_wait_synced(dd->dd_pool, 0); 705*e1930233Sbonwick 706fa9e4066Sahrens /* 707fa9e4066Sahrens * Blow away the dsl_dir + head dataset. 708fa9e4066Sahrens * dsl_dir_destroy_sync() will call 709fa9e4066Sahrens * dsl_dataset_destroy_sync() to destroy the head dataset. 710fa9e4066Sahrens */ 711fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 712ea8dc4b6Seschrock err = dsl_dir_open_obj(dd->dd_pool, 713ea8dc4b6Seschrock dd->dd_phys->dd_parent_obj, NULL, FTAG, &pds); 714fa9e4066Sahrens dsl_dir_close(dd, FTAG); 715fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 716ea8dc4b6Seschrock if (err) 717ea8dc4b6Seschrock return (err); 718fa9e4066Sahrens 719fa9e4066Sahrens (void) strcpy(buf, name); 720fa9e4066Sahrens cp = strrchr(buf, '/') + 1; 721fa9e4066Sahrens ASSERT(cp[0] != '\0'); 722fa9e4066Sahrens do { 723fa9e4066Sahrens txg_wait_synced(dp, 0); 724fa9e4066Sahrens err = dsl_dir_sync_task(pds, 725fa9e4066Sahrens dsl_dir_destroy_sync, cp, 0); 726fa9e4066Sahrens } while (err == EAGAIN); 727fa9e4066Sahrens dsl_dir_close(pds, FTAG); 728fa9e4066Sahrens } 729fa9e4066Sahrens 730fa9e4066Sahrens return (err); 731fa9e4066Sahrens } 732fa9e4066Sahrens 733fa9e4066Sahrens int 734fa9e4066Sahrens dsl_dataset_rollback(const char *name) 735fa9e4066Sahrens { 736fa9e4066Sahrens int err; 737fa9e4066Sahrens dsl_dir_t *dd; 738fa9e4066Sahrens const char *tail; 739fa9e4066Sahrens 740ea8dc4b6Seschrock err = dsl_dir_open(name, FTAG, &dd, &tail); 741ea8dc4b6Seschrock if (err) 742ea8dc4b6Seschrock return (err); 743fa9e4066Sahrens 744fa9e4066Sahrens if (tail != NULL) { 745fa9e4066Sahrens dsl_dir_close(dd, FTAG); 746fa9e4066Sahrens return (EINVAL); 747fa9e4066Sahrens } 748fa9e4066Sahrens do { 749fa9e4066Sahrens txg_wait_synced(dd->dd_pool, 0); 750fa9e4066Sahrens err = dsl_dir_sync_task(dd, 751fa9e4066Sahrens dsl_dataset_rollback_sync, NULL, 0); 752fa9e4066Sahrens } while (err == EAGAIN); 753fa9e4066Sahrens dsl_dir_close(dd, FTAG); 754fa9e4066Sahrens 755fa9e4066Sahrens return (err); 756fa9e4066Sahrens } 757fa9e4066Sahrens 758fa9e4066Sahrens void * 759fa9e4066Sahrens dsl_dataset_set_user_ptr(dsl_dataset_t *ds, 760fa9e4066Sahrens void *p, dsl_dataset_evict_func_t func) 761fa9e4066Sahrens { 762fa9e4066Sahrens void *old; 763fa9e4066Sahrens 764fa9e4066Sahrens mutex_enter(&ds->ds_lock); 765fa9e4066Sahrens old = ds->ds_user_ptr; 766fa9e4066Sahrens if (old == NULL) { 767fa9e4066Sahrens ds->ds_user_ptr = p; 768fa9e4066Sahrens ds->ds_user_evict_func = func; 769fa9e4066Sahrens } 770fa9e4066Sahrens mutex_exit(&ds->ds_lock); 771fa9e4066Sahrens return (old); 772fa9e4066Sahrens } 773fa9e4066Sahrens 774fa9e4066Sahrens void * 775fa9e4066Sahrens dsl_dataset_get_user_ptr(dsl_dataset_t *ds) 776fa9e4066Sahrens { 777fa9e4066Sahrens return (ds->ds_user_ptr); 778fa9e4066Sahrens } 779fa9e4066Sahrens 780fa9e4066Sahrens 781fa9e4066Sahrens void 782fa9e4066Sahrens dsl_dataset_get_blkptr(dsl_dataset_t *ds, blkptr_t *bp) 783fa9e4066Sahrens { 784fa9e4066Sahrens *bp = ds->ds_phys->ds_bp; 785fa9e4066Sahrens } 786fa9e4066Sahrens 787fa9e4066Sahrens void 788fa9e4066Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 789fa9e4066Sahrens { 790fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 791fa9e4066Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 792fa9e4066Sahrens if (ds == NULL) { 793fa9e4066Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 794fa9e4066Sahrens } else { 795fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 796fa9e4066Sahrens ds->ds_phys->ds_bp = *bp; 797fa9e4066Sahrens } 798fa9e4066Sahrens } 799fa9e4066Sahrens 800fa9e4066Sahrens spa_t * 801fa9e4066Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 802fa9e4066Sahrens { 803fa9e4066Sahrens return (ds->ds_dir->dd_pool->dp_spa); 804fa9e4066Sahrens } 805fa9e4066Sahrens 806fa9e4066Sahrens void 807fa9e4066Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 808fa9e4066Sahrens { 809fa9e4066Sahrens dsl_pool_t *dp; 810fa9e4066Sahrens 811fa9e4066Sahrens if (ds == NULL) /* this is the meta-objset */ 812fa9e4066Sahrens return; 813fa9e4066Sahrens 814fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 815fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 816fa9e4066Sahrens 817fa9e4066Sahrens dp = ds->ds_dir->dd_pool; 818fa9e4066Sahrens 819fa9e4066Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 820fa9e4066Sahrens /* up the hold count until we can be written out */ 821fa9e4066Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 822fa9e4066Sahrens } 823fa9e4066Sahrens } 824fa9e4066Sahrens 825fa9e4066Sahrens struct killarg { 826fa9e4066Sahrens uint64_t *usedp; 827fa9e4066Sahrens uint64_t *compressedp; 828fa9e4066Sahrens uint64_t *uncompressedp; 829fa9e4066Sahrens zio_t *zio; 830fa9e4066Sahrens dmu_tx_t *tx; 831fa9e4066Sahrens }; 832fa9e4066Sahrens 833fa9e4066Sahrens static int 834fa9e4066Sahrens kill_blkptr(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 835fa9e4066Sahrens { 836fa9e4066Sahrens struct killarg *ka = arg; 837fa9e4066Sahrens blkptr_t *bp = &bc->bc_blkptr; 838fa9e4066Sahrens 839fa9e4066Sahrens ASSERT3U(bc->bc_errno, ==, 0); 840fa9e4066Sahrens 841fa9e4066Sahrens /* 842fa9e4066Sahrens * Since this callback is not called concurrently, no lock is 843fa9e4066Sahrens * needed on the accounting values. 844fa9e4066Sahrens */ 845fa9e4066Sahrens *ka->usedp += BP_GET_ASIZE(bp); 846fa9e4066Sahrens *ka->compressedp += BP_GET_PSIZE(bp); 847fa9e4066Sahrens *ka->uncompressedp += BP_GET_UCSIZE(bp); 848fa9e4066Sahrens /* XXX check for EIO? */ 849fa9e4066Sahrens (void) arc_free(ka->zio, spa, ka->tx->tx_txg, bp, NULL, NULL, 850fa9e4066Sahrens ARC_NOWAIT); 851fa9e4066Sahrens return (0); 852fa9e4066Sahrens } 853fa9e4066Sahrens 854fa9e4066Sahrens /* ARGSUSED */ 855fa9e4066Sahrens int 856fa9e4066Sahrens dsl_dataset_rollback_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 857fa9e4066Sahrens { 858fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 859fa9e4066Sahrens dsl_dataset_t *ds; 860ea8dc4b6Seschrock int err; 861fa9e4066Sahrens 862fa9e4066Sahrens if (dd->dd_phys->dd_head_dataset_obj == 0) 863fa9e4066Sahrens return (EINVAL); 864ea8dc4b6Seschrock err = dsl_dataset_open_obj(dd->dd_pool, 865ea8dc4b6Seschrock dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &ds); 866ea8dc4b6Seschrock if (err) 867ea8dc4b6Seschrock return (err); 868fa9e4066Sahrens 869fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_txg == 0) { 870fa9e4066Sahrens /* 871fa9e4066Sahrens * There's no previous snapshot. I suppose we could 872fa9e4066Sahrens * roll it back to being empty (and re-initialize the 873fa9e4066Sahrens * upper (ZPL) layer). But for now there's no way to do 874fa9e4066Sahrens * this via the user interface. 875fa9e4066Sahrens */ 876fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 877fa9e4066Sahrens return (EINVAL); 878fa9e4066Sahrens } 879fa9e4066Sahrens 880fa9e4066Sahrens mutex_enter(&ds->ds_lock); 881fa9e4066Sahrens if (ds->ds_open_refcount > 0) { 882fa9e4066Sahrens mutex_exit(&ds->ds_lock); 883fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 884fa9e4066Sahrens return (EBUSY); 885fa9e4066Sahrens } 886fa9e4066Sahrens 887fa9e4066Sahrens /* 888fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 889fa9e4066Sahrens * them. Try again. 890fa9e4066Sahrens */ 891fa9e4066Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) { 892fa9e4066Sahrens mutex_exit(&ds->ds_lock); 893fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 894fa9e4066Sahrens return (EAGAIN); 895fa9e4066Sahrens } 896fa9e4066Sahrens 897fa9e4066Sahrens /* THE POINT OF NO (unsuccessful) RETURN */ 898fa9e4066Sahrens ds->ds_open_refcount = DOS_REF_MAX; 899fa9e4066Sahrens mutex_exit(&ds->ds_lock); 900fa9e4066Sahrens 901fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 902fa9e4066Sahrens 903fa9e4066Sahrens /* Zero out the deadlist. */ 904fa9e4066Sahrens dprintf("old deadlist obj = %llx\n", ds->ds_phys->ds_deadlist_obj); 905fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 906fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 907fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 908fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 909ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 910ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 911fa9e4066Sahrens dprintf("new deadlist obj = %llx\n", ds->ds_phys->ds_deadlist_obj); 912fa9e4066Sahrens 913fa9e4066Sahrens { 914fa9e4066Sahrens /* Free blkptrs that we gave birth to */ 915fa9e4066Sahrens zio_t *zio; 916fa9e4066Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 917fa9e4066Sahrens struct killarg ka; 918fa9e4066Sahrens 919fa9e4066Sahrens zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL, 920fa9e4066Sahrens ZIO_FLAG_MUSTSUCCEED); 921fa9e4066Sahrens ka.usedp = &used; 922fa9e4066Sahrens ka.compressedp = &compressed; 923fa9e4066Sahrens ka.uncompressedp = &uncompressed; 924fa9e4066Sahrens ka.zio = zio; 925fa9e4066Sahrens ka.tx = tx; 926fa9e4066Sahrens (void) traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 927fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 928fa9e4066Sahrens (void) zio_wait(zio); 929fa9e4066Sahrens 930fa9e4066Sahrens dsl_dir_diduse_space(dd, 931fa9e4066Sahrens -used, -compressed, -uncompressed, tx); 932fa9e4066Sahrens } 933fa9e4066Sahrens 934fa9e4066Sahrens /* Change our contents to that of the prev snapshot (finally!) */ 935fa9e4066Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, ds->ds_phys->ds_prev_snap_obj); 936fa9e4066Sahrens ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp; 937fa9e4066Sahrens ds->ds_phys->ds_used_bytes = ds->ds_prev->ds_phys->ds_used_bytes; 938fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes = 939fa9e4066Sahrens ds->ds_prev->ds_phys->ds_compressed_bytes; 940fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes = 941fa9e4066Sahrens ds->ds_prev->ds_phys->ds_uncompressed_bytes; 942*e1930233Sbonwick ds->ds_phys->ds_inconsistent = ds->ds_prev->ds_phys->ds_inconsistent; 943fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 944fa9e4066Sahrens 945fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 946fa9e4066Sahrens ds->ds_prev->ds_phys->ds_unique_bytes = 0; 947fa9e4066Sahrens 948fa9e4066Sahrens dprintf("new deadlist obj = %llx\n", ds->ds_phys->ds_deadlist_obj); 949fa9e4066Sahrens ds->ds_open_refcount = 0; 950fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 951fa9e4066Sahrens 952fa9e4066Sahrens return (0); 953fa9e4066Sahrens } 954fa9e4066Sahrens 955*e1930233Sbonwick /* ARGSUSED */ 956*e1930233Sbonwick static int 957*e1930233Sbonwick dsl_dataset_destroy_begin_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 958*e1930233Sbonwick { 959*e1930233Sbonwick dsl_dataset_t *ds = arg; 960*e1930233Sbonwick 961*e1930233Sbonwick /* 962*e1930233Sbonwick * Can't delete a head dataset if there are snapshots of it. 963*e1930233Sbonwick * (Except if the only snapshots are from the branch we cloned 964*e1930233Sbonwick * from.) 965*e1930233Sbonwick */ 966*e1930233Sbonwick if (ds->ds_prev != NULL && 967*e1930233Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 968*e1930233Sbonwick return (EINVAL); 969*e1930233Sbonwick 970*e1930233Sbonwick /* Mark it as inconsistent on-disk, in case we crash */ 971*e1930233Sbonwick dmu_buf_will_dirty(ds->ds_dbuf, tx); 972*e1930233Sbonwick ds->ds_phys->ds_inconsistent = TRUE; 973*e1930233Sbonwick 974*e1930233Sbonwick return (0); 975*e1930233Sbonwick } 976*e1930233Sbonwick 977fa9e4066Sahrens int 978fa9e4066Sahrens dsl_dataset_destroy_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 979fa9e4066Sahrens { 980fa9e4066Sahrens const char *snapname = arg; 981fa9e4066Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 982fa9e4066Sahrens blkptr_t bp; 983fa9e4066Sahrens zio_t *zio; 984fa9e4066Sahrens int err; 985fa9e4066Sahrens int after_branch_point = FALSE; 986fa9e4066Sahrens int drop_lock = FALSE; 987fa9e4066Sahrens dsl_pool_t *dp = dd->dd_pool; 988fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 989fa9e4066Sahrens dsl_dataset_t *ds, *ds_prev = NULL; 990fa9e4066Sahrens uint64_t obj; 991fa9e4066Sahrens 992fa9e4066Sahrens if (dd->dd_phys->dd_head_dataset_obj == 0) 993fa9e4066Sahrens return (EINVAL); 994fa9e4066Sahrens 995fa9e4066Sahrens if (!RW_WRITE_HELD(&dp->dp_config_rwlock)) { 996fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_WRITER); 997fa9e4066Sahrens drop_lock = TRUE; 998fa9e4066Sahrens } 999fa9e4066Sahrens 1000ea8dc4b6Seschrock err = dsl_dataset_open_obj(dd->dd_pool, 1001fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, 1002ea8dc4b6Seschrock snapname ? DS_MODE_NONE : DS_MODE_EXCLUSIVE, FTAG, &ds); 1003fa9e4066Sahrens 1004ea8dc4b6Seschrock if (err == 0 && snapname) { 1005fa9e4066Sahrens err = zap_lookup(mos, ds->ds_phys->ds_snapnames_zapobj, 1006fa9e4066Sahrens snapname, 8, 1, &obj); 1007fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 1008ea8dc4b6Seschrock if (err == 0) { 1009ea8dc4b6Seschrock err = dsl_dataset_open_obj(dd->dd_pool, obj, NULL, 1010ea8dc4b6Seschrock DS_MODE_EXCLUSIVE, FTAG, &ds); 1011fa9e4066Sahrens } 1012fa9e4066Sahrens } 1013ea8dc4b6Seschrock if (err) { 1014fa9e4066Sahrens if (drop_lock) 1015fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 1016ea8dc4b6Seschrock return (err); 1017fa9e4066Sahrens } 1018fa9e4066Sahrens 1019fa9e4066Sahrens obj = ds->ds_object; 1020fa9e4066Sahrens 1021fa9e4066Sahrens /* Can't delete a branch point. */ 1022fa9e4066Sahrens if (ds->ds_phys->ds_num_children > 1) { 1023fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 1024fa9e4066Sahrens if (drop_lock) 1025fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 1026fa9e4066Sahrens return (EINVAL); 1027fa9e4066Sahrens } 1028fa9e4066Sahrens 1029fa9e4066Sahrens /* 1030fa9e4066Sahrens * Can't delete a head dataset if there are snapshots of it. 1031fa9e4066Sahrens * (Except if the only snapshots are from the branch we cloned 1032fa9e4066Sahrens * from.) 1033fa9e4066Sahrens */ 1034fa9e4066Sahrens if (ds->ds_prev != NULL && 1035fa9e4066Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == obj) { 1036fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 1037fa9e4066Sahrens if (drop_lock) 1038fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 1039fa9e4066Sahrens return (EINVAL); 1040fa9e4066Sahrens } 1041fa9e4066Sahrens 1042fa9e4066Sahrens /* 1043fa9e4066Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1044fa9e4066Sahrens * them. Try again. 1045fa9e4066Sahrens */ 1046fa9e4066Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) { 1047fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 104887e5029aSahrens if (drop_lock) 104987e5029aSahrens rw_exit(&dp->dp_config_rwlock); 1050fa9e4066Sahrens return (EAGAIN); 1051fa9e4066Sahrens } 1052fa9e4066Sahrens 1053fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1054fa9e4066Sahrens if (ds->ds_prev) { 1055fa9e4066Sahrens ds_prev = ds->ds_prev; 1056fa9e4066Sahrens } else { 1057ea8dc4b6Seschrock err = dsl_dataset_open_obj(dd->dd_pool, 1058fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 1059ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_prev); 1060ea8dc4b6Seschrock if (err) { 1061ea8dc4b6Seschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 1062ea8dc4b6Seschrock if (drop_lock) 1063ea8dc4b6Seschrock rw_exit(&dp->dp_config_rwlock); 1064ea8dc4b6Seschrock return (err); 1065ea8dc4b6Seschrock } 1066fa9e4066Sahrens } 1067fa9e4066Sahrens after_branch_point = 1068fa9e4066Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1069fa9e4066Sahrens 1070fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1071fa9e4066Sahrens if (after_branch_point && 1072fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1073fa9e4066Sahrens /* This clone is toast. */ 1074fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1075fa9e4066Sahrens ds_prev->ds_phys->ds_num_children--; 1076fa9e4066Sahrens } else if (!after_branch_point) { 1077fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1078fa9e4066Sahrens ds->ds_phys->ds_next_snap_obj; 1079fa9e4066Sahrens } 1080fa9e4066Sahrens } 1081fa9e4066Sahrens 1082ea8dc4b6Seschrock /* THE POINT OF NO (unsuccessful) RETURN */ 1083ea8dc4b6Seschrock 1084fa9e4066Sahrens ASSERT3P(tx->tx_pool, ==, dd->dd_pool); 1085fa9e4066Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1086fa9e4066Sahrens 1087fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 1088fa9e4066Sahrens dsl_dataset_t *ds_next; 1089fa9e4066Sahrens uint64_t itor = 0; 1090fa9e4066Sahrens 1091fa9e4066Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 1092fa9e4066Sahrens 1093ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, 1094ea8dc4b6Seschrock ds->ds_phys->ds_next_snap_obj, NULL, 1095ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_next)); 1096fa9e4066Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1097fa9e4066Sahrens 1098fa9e4066Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1099fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1100fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj; 1101fa9e4066Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1102fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg; 1103fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1104fa9e4066Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1105fa9e4066Sahrens 1106fa9e4066Sahrens /* 1107fa9e4066Sahrens * Transfer to our deadlist (which will become next's 1108fa9e4066Sahrens * new deadlist) any entries from next's current 1109fa9e4066Sahrens * deadlist which were born before prev, and free the 1110fa9e4066Sahrens * other entries. 1111fa9e4066Sahrens * 1112fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1113fa9e4066Sahrens */ 1114fa9e4066Sahrens while (bplist_iterate(&ds_next->ds_deadlist, &itor, 1115fa9e4066Sahrens &bp) == 0) { 1116fa9e4066Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 1117ea8dc4b6Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 1118ea8dc4b6Seschrock &bp, tx)); 1119fa9e4066Sahrens if (ds_prev && !after_branch_point && 1120fa9e4066Sahrens bp.blk_birth > 1121fa9e4066Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1122fa9e4066Sahrens ds_prev->ds_phys->ds_unique_bytes += 1123fa9e4066Sahrens BP_GET_ASIZE(&bp); 1124fa9e4066Sahrens } 1125fa9e4066Sahrens } else { 1126fa9e4066Sahrens used += BP_GET_ASIZE(&bp); 1127fa9e4066Sahrens compressed += BP_GET_PSIZE(&bp); 1128fa9e4066Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1129fa9e4066Sahrens /* XXX check return value? */ 1130fa9e4066Sahrens (void) arc_free(zio, dp->dp_spa, tx->tx_txg, 1131fa9e4066Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1132fa9e4066Sahrens } 1133fa9e4066Sahrens } 1134fa9e4066Sahrens 1135fa9e4066Sahrens /* free next's deadlist */ 1136fa9e4066Sahrens bplist_close(&ds_next->ds_deadlist); 1137fa9e4066Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1138fa9e4066Sahrens 1139fa9e4066Sahrens /* set next's deadlist to our deadlist */ 1140fa9e4066Sahrens ds_next->ds_phys->ds_deadlist_obj = 1141fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj; 1142ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 1143ea8dc4b6Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1144fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1145fa9e4066Sahrens 1146fa9e4066Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1147fa9e4066Sahrens /* 1148fa9e4066Sahrens * Update next's unique to include blocks which 1149fa9e4066Sahrens * were previously shared by only this snapshot 1150fa9e4066Sahrens * and it. Those blocks will be born after the 1151fa9e4066Sahrens * prev snap and before this snap, and will have 1152fa9e4066Sahrens * died after the next snap and before the one 1153fa9e4066Sahrens * after that (ie. be on the snap after next's 1154fa9e4066Sahrens * deadlist). 1155fa9e4066Sahrens * 1156fa9e4066Sahrens * XXX we're doing this long task with the 1157fa9e4066Sahrens * config lock held 1158fa9e4066Sahrens */ 1159fa9e4066Sahrens dsl_dataset_t *ds_after_next; 1160fa9e4066Sahrens 1161ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, 1162fa9e4066Sahrens ds_next->ds_phys->ds_next_snap_obj, NULL, 1163ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_after_next)); 1164fa9e4066Sahrens itor = 0; 1165fa9e4066Sahrens while (bplist_iterate(&ds_after_next->ds_deadlist, 1166fa9e4066Sahrens &itor, &bp) == 0) { 1167fa9e4066Sahrens if (bp.blk_birth > 1168fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg && 1169fa9e4066Sahrens bp.blk_birth <= 1170fa9e4066Sahrens ds->ds_phys->ds_creation_txg) { 1171fa9e4066Sahrens ds_next->ds_phys->ds_unique_bytes += 1172fa9e4066Sahrens BP_GET_ASIZE(&bp); 1173fa9e4066Sahrens } 1174fa9e4066Sahrens } 1175fa9e4066Sahrens 1176fa9e4066Sahrens dsl_dataset_close(ds_after_next, DS_MODE_NONE, FTAG); 1177fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1178fa9e4066Sahrens } else { 1179fa9e4066Sahrens /* 1180fa9e4066Sahrens * It would be nice to update the head dataset's 1181fa9e4066Sahrens * unique. To do so we would have to traverse 1182fa9e4066Sahrens * it for blocks born after ds_prev, which is 1183fa9e4066Sahrens * pretty expensive just to maintain something 1184fa9e4066Sahrens * for debugging purposes. 1185fa9e4066Sahrens */ 1186fa9e4066Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1187fa9e4066Sahrens dsl_dataset_close(ds_next->ds_prev, DS_MODE_NONE, 1188fa9e4066Sahrens ds_next); 1189fa9e4066Sahrens if (ds_prev) { 1190ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, 1191ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, NULL, 1192ea8dc4b6Seschrock DS_MODE_NONE, ds_next, &ds_next->ds_prev)); 1193fa9e4066Sahrens } else { 1194fa9e4066Sahrens ds_next->ds_prev = NULL; 1195fa9e4066Sahrens } 1196fa9e4066Sahrens } 1197fa9e4066Sahrens dsl_dataset_close(ds_next, DS_MODE_NONE, FTAG); 1198fa9e4066Sahrens 1199fa9e4066Sahrens /* 1200fa9e4066Sahrens * NB: unique_bytes is not accurate for head objsets 1201fa9e4066Sahrens * because we don't update it when we delete the most 1202fa9e4066Sahrens * recent snapshot -- see above comment. 1203fa9e4066Sahrens */ 1204fa9e4066Sahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 1205fa9e4066Sahrens } else { 1206fa9e4066Sahrens /* 1207fa9e4066Sahrens * There's no next snapshot, so this is a head dataset. 1208fa9e4066Sahrens * Destroy the deadlist. Unless it's a clone, the 1209fa9e4066Sahrens * deadlist should be empty. (If it's a clone, it's 1210fa9e4066Sahrens * safe to ignore the deadlist contents.) 1211fa9e4066Sahrens */ 1212fa9e4066Sahrens struct killarg ka; 1213fa9e4066Sahrens 1214fa9e4066Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1215fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1216fa9e4066Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1217fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1218fa9e4066Sahrens 1219fa9e4066Sahrens /* 1220fa9e4066Sahrens * Free everything that we point to (that's born after 1221fa9e4066Sahrens * the previous snapshot, if we are a clone) 1222fa9e4066Sahrens * 1223fa9e4066Sahrens * XXX we're doing this long task with the config lock held 1224fa9e4066Sahrens */ 1225fa9e4066Sahrens ka.usedp = &used; 1226fa9e4066Sahrens ka.compressedp = &compressed; 1227fa9e4066Sahrens ka.uncompressedp = &uncompressed; 1228fa9e4066Sahrens ka.zio = zio; 1229fa9e4066Sahrens ka.tx = tx; 1230fa9e4066Sahrens err = traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 1231fa9e4066Sahrens ADVANCE_POST, kill_blkptr, &ka); 1232fa9e4066Sahrens ASSERT3U(err, ==, 0); 1233fa9e4066Sahrens } 1234fa9e4066Sahrens 1235fa9e4066Sahrens err = zio_wait(zio); 1236fa9e4066Sahrens ASSERT3U(err, ==, 0); 1237fa9e4066Sahrens 1238fa9e4066Sahrens dsl_dir_diduse_space(dd, -used, -compressed, -uncompressed, tx); 1239fa9e4066Sahrens 1240fa9e4066Sahrens if (ds->ds_phys->ds_snapnames_zapobj) { 1241fa9e4066Sahrens err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1242fa9e4066Sahrens ASSERT(err == 0); 1243fa9e4066Sahrens } 1244fa9e4066Sahrens 1245fa9e4066Sahrens if (dd->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1246fa9e4066Sahrens /* Erase the link in the dataset */ 1247fa9e4066Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 1248fa9e4066Sahrens dd->dd_phys->dd_head_dataset_obj = 0; 1249fa9e4066Sahrens /* 1250fa9e4066Sahrens * dsl_dir_sync_destroy() called us, they'll destroy 1251fa9e4066Sahrens * the dataset. 1252fa9e4066Sahrens */ 1253fa9e4066Sahrens } else { 1254fa9e4066Sahrens /* remove from snapshot namespace */ 1255fa9e4066Sahrens dsl_dataset_t *ds_head; 1256ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, 1257ea8dc4b6Seschrock dd->dd_phys->dd_head_dataset_obj, NULL, 1258ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_head)); 1259fa9e4066Sahrens #ifdef ZFS_DEBUG 1260fa9e4066Sahrens { 1261fa9e4066Sahrens uint64_t val; 1262fa9e4066Sahrens err = zap_lookup(mos, 1263fa9e4066Sahrens ds_head->ds_phys->ds_snapnames_zapobj, 1264fa9e4066Sahrens snapname, 8, 1, &val); 1265fa9e4066Sahrens ASSERT3U(err, ==, 0); 1266fa9e4066Sahrens ASSERT3U(val, ==, obj); 1267fa9e4066Sahrens } 1268fa9e4066Sahrens #endif 1269fa9e4066Sahrens err = zap_remove(mos, ds_head->ds_phys->ds_snapnames_zapobj, 1270fa9e4066Sahrens snapname, tx); 1271fa9e4066Sahrens ASSERT(err == 0); 1272fa9e4066Sahrens dsl_dataset_close(ds_head, DS_MODE_NONE, FTAG); 1273fa9e4066Sahrens } 1274fa9e4066Sahrens 1275fa9e4066Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1276fa9e4066Sahrens dsl_dataset_close(ds_prev, DS_MODE_NONE, FTAG); 1277fa9e4066Sahrens 1278fa9e4066Sahrens err = dmu_object_free(mos, obj, tx); 1279fa9e4066Sahrens ASSERT(err == 0); 1280fa9e4066Sahrens 1281fa9e4066Sahrens /* 1282fa9e4066Sahrens * Close the objset with mode NONE, thus leaving it with 1283fa9e4066Sahrens * DOS_REF_MAX set, so that noone can access it. 1284fa9e4066Sahrens */ 1285fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 1286fa9e4066Sahrens 1287fa9e4066Sahrens if (drop_lock) 1288fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 1289fa9e4066Sahrens return (0); 1290fa9e4066Sahrens } 1291fa9e4066Sahrens 1292fa9e4066Sahrens int 1293fa9e4066Sahrens dsl_dataset_snapshot_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 1294fa9e4066Sahrens { 1295fa9e4066Sahrens const char *snapname = arg; 1296fa9e4066Sahrens dsl_pool_t *dp = dd->dd_pool; 1297fa9e4066Sahrens dmu_buf_t *dbuf; 1298fa9e4066Sahrens dsl_dataset_phys_t *dsphys; 1299fa9e4066Sahrens uint64_t dsobj, value; 1300fa9e4066Sahrens objset_t *mos = dp->dp_meta_objset; 1301fa9e4066Sahrens dsl_dataset_t *ds; 1302fa9e4066Sahrens int err; 1303fa9e4066Sahrens 1304fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1305fa9e4066Sahrens 1306fa9e4066Sahrens if (dd->dd_phys->dd_head_dataset_obj == 0) 1307fa9e4066Sahrens return (EINVAL); 1308ea8dc4b6Seschrock err = dsl_dataset_open_obj(dp, dd->dd_phys->dd_head_dataset_obj, NULL, 1309ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds); 1310ea8dc4b6Seschrock if (err) 1311ea8dc4b6Seschrock return (err); 1312fa9e4066Sahrens 1313fa9e4066Sahrens err = zap_lookup(mos, ds->ds_phys->ds_snapnames_zapobj, 1314fa9e4066Sahrens snapname, 8, 1, &value); 1315fa9e4066Sahrens if (err == 0) { 1316fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 1317fa9e4066Sahrens return (EEXIST); 1318fa9e4066Sahrens } 1319fa9e4066Sahrens ASSERT(err == ENOENT); 1320fa9e4066Sahrens 1321fa9e4066Sahrens /* The point of no (unsuccessful) return */ 1322fa9e4066Sahrens 1323fa9e4066Sahrens dprintf_dd(dd, "taking snapshot %s in txg %llu\n", 1324fa9e4066Sahrens snapname, tx->tx_txg); 1325fa9e4066Sahrens 1326fa9e4066Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 1327fa9e4066Sahrens 1328fa9e4066Sahrens rw_enter(&dp->dp_config_rwlock, RW_WRITER); 1329fa9e4066Sahrens 13301649cd4bStabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 13311649cd4bStabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 1332ea8dc4b6Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1333fa9e4066Sahrens dmu_buf_will_dirty(dbuf, tx); 1334fa9e4066Sahrens dsphys = dbuf->db_data; 1335fa9e4066Sahrens dsphys->ds_dir_obj = dd->dd_object; 1336fa9e4066Sahrens dsphys->ds_fsid_guid = unique_create(); 1337fa9e4066Sahrens unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 1338fa9e4066Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1339fa9e4066Sahrens sizeof (dsphys->ds_guid)); 1340fa9e4066Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1341fa9e4066Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1342fa9e4066Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1343fa9e4066Sahrens dsphys->ds_num_children = 1; 1344fa9e4066Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1345fa9e4066Sahrens dsphys->ds_creation_txg = tx->tx_txg; 1346fa9e4066Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1347fa9e4066Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1348fa9e4066Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1349fa9e4066Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 1350*e1930233Sbonwick dsphys->ds_inconsistent = ds->ds_phys->ds_inconsistent; 1351fa9e4066Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 1352ea8dc4b6Seschrock dmu_buf_rele(dbuf, FTAG); 1353fa9e4066Sahrens 1354fa9e4066Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1355fa9e4066Sahrens dsl_dataset_t *ds_prev; 1356fa9e4066Sahrens 1357ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dp, 1358ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, NULL, 1359ea8dc4b6Seschrock DS_MODE_NONE, FTAG, &ds_prev)); 1360fa9e4066Sahrens ASSERT(ds_prev->ds_phys->ds_next_snap_obj == 1361fa9e4066Sahrens ds->ds_object || 1362fa9e4066Sahrens ds_prev->ds_phys->ds_num_children > 1); 1363fa9e4066Sahrens if (ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 1364fa9e4066Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1365fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1366fa9e4066Sahrens ds_prev->ds_phys->ds_creation_txg); 1367fa9e4066Sahrens ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1368fa9e4066Sahrens } 1369fa9e4066Sahrens dsl_dataset_close(ds_prev, DS_MODE_NONE, FTAG); 1370fa9e4066Sahrens } else { 1371fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 0); 1372fa9e4066Sahrens } 1373fa9e4066Sahrens 1374fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1375fa9e4066Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1376fa9e4066Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, dsphys->ds_creation_txg); 1377fa9e4066Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1378fa9e4066Sahrens ds->ds_phys->ds_prev_snap_txg = dsphys->ds_creation_txg; 1379fa9e4066Sahrens ds->ds_phys->ds_unique_bytes = 0; 1380fa9e4066Sahrens ds->ds_phys->ds_deadlist_obj = 1381fa9e4066Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 1382ea8dc4b6Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 1383ea8dc4b6Seschrock ds->ds_phys->ds_deadlist_obj)); 1384fa9e4066Sahrens 1385fa9e4066Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1386fa9e4066Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1387fa9e4066Sahrens snapname, 8, 1, &dsobj, tx); 1388fa9e4066Sahrens ASSERT(err == 0); 1389fa9e4066Sahrens 1390fa9e4066Sahrens if (ds->ds_prev) 1391fa9e4066Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 1392ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_open_obj(dp, 1393ea8dc4b6Seschrock ds->ds_phys->ds_prev_snap_obj, snapname, 1394ea8dc4b6Seschrock DS_MODE_NONE, ds, &ds->ds_prev)); 1395fa9e4066Sahrens 1396fa9e4066Sahrens rw_exit(&dp->dp_config_rwlock); 1397fa9e4066Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 1398fa9e4066Sahrens 1399fa9e4066Sahrens return (0); 1400fa9e4066Sahrens } 1401fa9e4066Sahrens 1402fa9e4066Sahrens void 1403fa9e4066Sahrens dsl_dataset_sync(dsl_dataset_t *ds, dmu_tx_t *tx) 1404fa9e4066Sahrens { 1405fa9e4066Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1406fa9e4066Sahrens ASSERT(ds->ds_user_ptr != NULL); 1407fa9e4066Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1408fa9e4066Sahrens 1409fa9e4066Sahrens dmu_objset_sync(ds->ds_user_ptr, tx); 1410fa9e4066Sahrens dsl_dir_dirty(ds->ds_dir, tx); 1411fa9e4066Sahrens bplist_close(&ds->ds_deadlist); 1412fa9e4066Sahrens 1413ea8dc4b6Seschrock dmu_buf_rele(ds->ds_dbuf, ds); 1414fa9e4066Sahrens } 1415fa9e4066Sahrens 1416fa9e4066Sahrens void 1417fa9e4066Sahrens dsl_dataset_stats(dsl_dataset_t *ds, dmu_objset_stats_t *dds) 1418fa9e4066Sahrens { 1419fa9e4066Sahrens /* fill in properties crap */ 1420fa9e4066Sahrens dsl_dir_stats(ds->ds_dir, dds); 1421fa9e4066Sahrens 1422fa9e4066Sahrens if (ds->ds_phys->ds_num_children != 0) { 1423fa9e4066Sahrens dds->dds_is_snapshot = TRUE; 1424fa9e4066Sahrens dds->dds_num_clones = ds->ds_phys->ds_num_children - 1; 1425fa9e4066Sahrens } 1426fa9e4066Sahrens 1427fa9e4066Sahrens dds->dds_last_txg = ds->ds_phys->ds_bp.blk_birth; 1428fa9e4066Sahrens 1429fa9e4066Sahrens dds->dds_objects_used = ds->ds_phys->ds_bp.blk_fill; 1430fa9e4066Sahrens dds->dds_objects_avail = DN_MAX_OBJECT - dds->dds_objects_used; 1431fa9e4066Sahrens 1432fa9e4066Sahrens /* We override the dataset's creation time... they should be the same */ 1433fa9e4066Sahrens dds->dds_creation_time = ds->ds_phys->ds_creation_time; 1434fa9e4066Sahrens dds->dds_creation_txg = ds->ds_phys->ds_creation_txg; 1435fa9e4066Sahrens dds->dds_space_refd = ds->ds_phys->ds_used_bytes; 1436fa9e4066Sahrens dds->dds_fsid_guid = ds->ds_phys->ds_fsid_guid; 1437fa9e4066Sahrens 1438fa9e4066Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1439fa9e4066Sahrens /* 1440fa9e4066Sahrens * This is a snapshot; override the dd's space used with 1441fa9e4066Sahrens * our unique space 1442fa9e4066Sahrens */ 1443fa9e4066Sahrens dds->dds_space_used = ds->ds_phys->ds_unique_bytes; 1444fa9e4066Sahrens dds->dds_compressed_bytes = 1445fa9e4066Sahrens ds->ds_phys->ds_compressed_bytes; 1446fa9e4066Sahrens dds->dds_uncompressed_bytes = 1447fa9e4066Sahrens ds->ds_phys->ds_uncompressed_bytes; 1448fa9e4066Sahrens } 1449fa9e4066Sahrens } 1450fa9e4066Sahrens 1451fa9e4066Sahrens dsl_pool_t * 1452fa9e4066Sahrens dsl_dataset_pool(dsl_dataset_t *ds) 1453fa9e4066Sahrens { 1454fa9e4066Sahrens return (ds->ds_dir->dd_pool); 1455fa9e4066Sahrens } 1456fa9e4066Sahrens 1457fa9e4066Sahrens struct osrenamearg { 1458fa9e4066Sahrens const char *oldname; 1459fa9e4066Sahrens const char *newname; 1460fa9e4066Sahrens }; 1461fa9e4066Sahrens 1462fa9e4066Sahrens static int 1463fa9e4066Sahrens dsl_dataset_snapshot_rename_sync(dsl_dir_t *dd, void *arg, dmu_tx_t *tx) 1464fa9e4066Sahrens { 1465fa9e4066Sahrens struct osrenamearg *ora = arg; 1466fa9e4066Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 1467fa9e4066Sahrens dsl_dir_t *nds; 1468fa9e4066Sahrens const char *tail; 1469fa9e4066Sahrens int err; 1470fa9e4066Sahrens dsl_dataset_t *snds, *fsds; 1471fa9e4066Sahrens uint64_t val; 1472fa9e4066Sahrens 1473fa9e4066Sahrens err = dsl_dataset_open_spa(dd->dd_pool->dp_spa, ora->oldname, 1474fa9e4066Sahrens DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &snds); 1475fa9e4066Sahrens if (err) 1476fa9e4066Sahrens return (err); 1477fa9e4066Sahrens 1478fa9e4066Sahrens if (snds->ds_dir != dd) { 1479fa9e4066Sahrens dsl_dataset_close(snds, DS_MODE_STANDARD, FTAG); 1480fa9e4066Sahrens return (EINVAL); 1481fa9e4066Sahrens } 1482fa9e4066Sahrens 1483fa9e4066Sahrens /* better be changing a snapshot */ 1484fa9e4066Sahrens if (snds->ds_phys->ds_next_snap_obj == 0) { 1485fa9e4066Sahrens dsl_dataset_close(snds, DS_MODE_STANDARD, FTAG); 1486fa9e4066Sahrens return (EINVAL); 1487fa9e4066Sahrens } 1488fa9e4066Sahrens 1489fa9e4066Sahrens /* new fs better exist */ 1490ea8dc4b6Seschrock err = dsl_dir_open_spa(dd->dd_pool->dp_spa, ora->newname, 1491ea8dc4b6Seschrock FTAG, &nds, &tail); 1492ea8dc4b6Seschrock if (err) { 1493fa9e4066Sahrens dsl_dataset_close(snds, DS_MODE_STANDARD, FTAG); 1494ea8dc4b6Seschrock return (err); 1495fa9e4066Sahrens } 1496fa9e4066Sahrens 1497fa9e4066Sahrens dsl_dir_close(nds, FTAG); 1498fa9e4066Sahrens 1499fa9e4066Sahrens /* new name better be in same fs */ 1500fa9e4066Sahrens if (nds != dd) { 1501fa9e4066Sahrens dsl_dataset_close(snds, DS_MODE_STANDARD, FTAG); 1502fa9e4066Sahrens return (EINVAL); 1503fa9e4066Sahrens } 1504fa9e4066Sahrens 1505fa9e4066Sahrens /* new name better be a snapshot */ 1506fa9e4066Sahrens if (tail == NULL || tail[0] != '@') { 1507fa9e4066Sahrens dsl_dataset_close(snds, DS_MODE_STANDARD, FTAG); 1508fa9e4066Sahrens return (EINVAL); 1509fa9e4066Sahrens } 1510fa9e4066Sahrens 1511fa9e4066Sahrens tail++; 1512fa9e4066Sahrens 1513ea8dc4b6Seschrock err = dsl_dataset_open_obj(dd->dd_pool, 1514ea8dc4b6Seschrock dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &fsds); 1515ea8dc4b6Seschrock if (err) { 1516ea8dc4b6Seschrock dsl_dataset_close(snds, DS_MODE_STANDARD, FTAG); 1517ea8dc4b6Seschrock return (err); 1518ea8dc4b6Seschrock } 1519fa9e4066Sahrens 1520fa9e4066Sahrens /* new name better not be in use */ 1521fa9e4066Sahrens err = zap_lookup(mos, fsds->ds_phys->ds_snapnames_zapobj, 1522fa9e4066Sahrens tail, 8, 1, &val); 1523fa9e4066Sahrens if (err != ENOENT) { 1524fa9e4066Sahrens if (err == 0) 1525fa9e4066Sahrens err = EEXIST; 1526fa9e4066Sahrens dsl_dataset_close(fsds, DS_MODE_NONE, FTAG); 1527fa9e4066Sahrens dsl_dataset_close(snds, DS_MODE_STANDARD, FTAG); 1528fa9e4066Sahrens return (EEXIST); 1529fa9e4066Sahrens } 1530fa9e4066Sahrens 1531fa9e4066Sahrens /* The point of no (unsuccessful) return */ 1532fa9e4066Sahrens 1533fa9e4066Sahrens rw_enter(&dd->dd_pool->dp_config_rwlock, RW_WRITER); 1534ea8dc4b6Seschrock VERIFY(0 == dsl_dataset_get_snapname(snds)); 1535fa9e4066Sahrens err = zap_remove(mos, fsds->ds_phys->ds_snapnames_zapobj, 1536fa9e4066Sahrens snds->ds_snapname, tx); 1537fa9e4066Sahrens ASSERT3U(err, ==, 0); 1538fa9e4066Sahrens mutex_enter(&snds->ds_lock); 1539fa9e4066Sahrens (void) strcpy(snds->ds_snapname, tail); 1540fa9e4066Sahrens mutex_exit(&snds->ds_lock); 1541fa9e4066Sahrens err = zap_add(mos, fsds->ds_phys->ds_snapnames_zapobj, 1542fa9e4066Sahrens snds->ds_snapname, 8, 1, &snds->ds_object, tx); 1543fa9e4066Sahrens ASSERT3U(err, ==, 0); 1544fa9e4066Sahrens rw_exit(&dd->dd_pool->dp_config_rwlock); 1545fa9e4066Sahrens 1546fa9e4066Sahrens dsl_dataset_close(fsds, DS_MODE_NONE, FTAG); 1547fa9e4066Sahrens dsl_dataset_close(snds, DS_MODE_STANDARD, FTAG); 1548fa9e4066Sahrens return (0); 1549fa9e4066Sahrens } 1550fa9e4066Sahrens 1551fa9e4066Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 1552fa9e4066Sahrens int 1553fa9e4066Sahrens dsl_dataset_rename(const char *osname, const char *newname) 1554fa9e4066Sahrens { 1555fa9e4066Sahrens dsl_dir_t *dd; 1556fa9e4066Sahrens const char *tail; 1557fa9e4066Sahrens struct osrenamearg ora; 1558fa9e4066Sahrens int err; 1559fa9e4066Sahrens 1560ea8dc4b6Seschrock err = dsl_dir_open(osname, FTAG, &dd, &tail); 1561ea8dc4b6Seschrock if (err) 1562ea8dc4b6Seschrock return (err); 1563fa9e4066Sahrens if (tail == NULL) { 1564fa9e4066Sahrens err = dsl_dir_sync_task(dd, 1565fa9e4066Sahrens dsl_dir_rename_sync, (void*)newname, 1<<12); 1566fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1567fa9e4066Sahrens return (err); 1568fa9e4066Sahrens } 1569fa9e4066Sahrens if (tail[0] != '@') { 1570fa9e4066Sahrens /* the name ended in a nonexistant component */ 1571fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1572fa9e4066Sahrens return (ENOENT); 1573fa9e4066Sahrens } 1574fa9e4066Sahrens 1575fa9e4066Sahrens ora.oldname = osname; 1576fa9e4066Sahrens ora.newname = newname; 1577fa9e4066Sahrens 1578fa9e4066Sahrens err = dsl_dir_sync_task(dd, 1579fa9e4066Sahrens dsl_dataset_snapshot_rename_sync, &ora, 1<<12); 1580fa9e4066Sahrens dsl_dir_close(dd, FTAG); 1581fa9e4066Sahrens return (err); 1582fa9e4066Sahrens } 1583