1789Sahrens /* 2789Sahrens * CDDL HEADER START 3789Sahrens * 4789Sahrens * The contents of this file are subject to the terms of the 51544Seschrock * Common Development and Distribution License (the "License"). 61544Seschrock * You may not use this file except in compliance with the License. 7789Sahrens * 8789Sahrens * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 9789Sahrens * or http://www.opensolaris.org/os/licensing. 10789Sahrens * See the License for the specific language governing permissions 11789Sahrens * and limitations under the License. 12789Sahrens * 13789Sahrens * When distributing Covered Code, include this CDDL HEADER in each 14789Sahrens * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 15789Sahrens * If applicable, add the following below this CDDL HEADER, with the 16789Sahrens * fields enclosed by brackets "[]" replaced with your own identifying 17789Sahrens * information: Portions Copyright [yyyy] [name of copyright owner] 18789Sahrens * 19789Sahrens * CDDL HEADER END 20789Sahrens */ 21789Sahrens /* 223444Sek110237 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 23789Sahrens * Use is subject to license terms. 24789Sahrens */ 25789Sahrens 26789Sahrens #pragma ident "%Z%%M% %I% %E% SMI" 27789Sahrens 28789Sahrens #include <sys/dmu_objset.h> 29789Sahrens #include <sys/dsl_dataset.h> 30789Sahrens #include <sys/dsl_dir.h> 312082Seschrock #include <sys/dsl_prop.h> 322199Sahrens #include <sys/dsl_synctask.h> 33789Sahrens #include <sys/dmu_traverse.h> 34789Sahrens #include <sys/dmu_tx.h> 35789Sahrens #include <sys/arc.h> 36789Sahrens #include <sys/zio.h> 37789Sahrens #include <sys/zap.h> 38789Sahrens #include <sys/unique.h> 39789Sahrens #include <sys/zfs_context.h> 404007Smmusante #include <sys/zfs_ioctl.h> 414543Smarks #include <sys/spa.h> 424543Smarks #include <sys/sunddi.h> 43789Sahrens 442199Sahrens static dsl_checkfunc_t dsl_dataset_destroy_begin_check; 452199Sahrens static dsl_syncfunc_t dsl_dataset_destroy_begin_sync; 462199Sahrens static dsl_checkfunc_t dsl_dataset_rollback_check; 472199Sahrens static dsl_syncfunc_t dsl_dataset_rollback_sync; 482199Sahrens static dsl_checkfunc_t dsl_dataset_destroy_check; 492199Sahrens static dsl_syncfunc_t dsl_dataset_destroy_sync; 501731Sbonwick 513444Sek110237 #define DS_REF_MAX (1ULL << 62) 52789Sahrens 53789Sahrens #define DSL_DEADLIST_BLOCKSIZE SPA_MAXBLOCKSIZE 54789Sahrens 55789Sahrens /* 56789Sahrens * We use weighted reference counts to express the various forms of exclusion 57789Sahrens * between different open modes. A STANDARD open is 1 point, an EXCLUSIVE open 583444Sek110237 * is DS_REF_MAX, and a PRIMARY open is little more than half of an EXCLUSIVE. 59789Sahrens * This makes the exclusion logic simple: the total refcnt for all opens cannot 603444Sek110237 * exceed DS_REF_MAX. For example, EXCLUSIVE opens are exclusive because their 613444Sek110237 * weight (DS_REF_MAX) consumes the entire refcnt space. PRIMARY opens consume 62789Sahrens * just over half of the refcnt space, so there can't be more than one, but it 63789Sahrens * can peacefully coexist with any number of STANDARD opens. 64789Sahrens */ 65789Sahrens static uint64_t ds_refcnt_weight[DS_MODE_LEVELS] = { 663444Sek110237 0, /* DS_MODE_NONE - invalid */ 673444Sek110237 1, /* DS_MODE_STANDARD - unlimited number */ 683444Sek110237 (DS_REF_MAX >> 1) + 1, /* DS_MODE_PRIMARY - only one of these */ 693444Sek110237 DS_REF_MAX /* DS_MODE_EXCLUSIVE - no other opens */ 70789Sahrens }; 71789Sahrens 72789Sahrens 73789Sahrens void 74789Sahrens dsl_dataset_block_born(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 75789Sahrens { 762082Seschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 77789Sahrens int compressed = BP_GET_PSIZE(bp); 78789Sahrens int uncompressed = BP_GET_UCSIZE(bp); 79789Sahrens 80789Sahrens dprintf_bp(bp, "born, ds=%p\n", ds); 81789Sahrens 82789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 83789Sahrens /* It could have been compressed away to nothing */ 84789Sahrens if (BP_IS_HOLE(bp)) 85789Sahrens return; 86789Sahrens ASSERT(BP_GET_TYPE(bp) != DMU_OT_NONE); 87789Sahrens ASSERT3U(BP_GET_TYPE(bp), <, DMU_OT_NUMTYPES); 88789Sahrens if (ds == NULL) { 89789Sahrens /* 90789Sahrens * Account for the meta-objset space in its placeholder 91789Sahrens * dsl_dir. 92789Sahrens */ 93789Sahrens ASSERT3U(compressed, ==, uncompressed); /* it's all metadata */ 94789Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 95789Sahrens used, compressed, uncompressed, tx); 96789Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 97789Sahrens return; 98789Sahrens } 99789Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 100789Sahrens mutex_enter(&ds->ds_lock); 101789Sahrens ds->ds_phys->ds_used_bytes += used; 102789Sahrens ds->ds_phys->ds_compressed_bytes += compressed; 103789Sahrens ds->ds_phys->ds_uncompressed_bytes += uncompressed; 104789Sahrens ds->ds_phys->ds_unique_bytes += used; 105789Sahrens mutex_exit(&ds->ds_lock); 106789Sahrens dsl_dir_diduse_space(ds->ds_dir, 107789Sahrens used, compressed, uncompressed, tx); 108789Sahrens } 109789Sahrens 110789Sahrens void 1113547Smaybee dsl_dataset_block_kill(dsl_dataset_t *ds, blkptr_t *bp, zio_t *pio, 1123547Smaybee dmu_tx_t *tx) 113789Sahrens { 1142082Seschrock int used = bp_get_dasize(tx->tx_pool->dp_spa, bp); 115789Sahrens int compressed = BP_GET_PSIZE(bp); 116789Sahrens int uncompressed = BP_GET_UCSIZE(bp); 117789Sahrens 118789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1193547Smaybee /* No block pointer => nothing to free */ 120789Sahrens if (BP_IS_HOLE(bp)) 121789Sahrens return; 122789Sahrens 123789Sahrens ASSERT(used > 0); 124789Sahrens if (ds == NULL) { 1253547Smaybee int err; 126789Sahrens /* 127789Sahrens * Account for the meta-objset space in its placeholder 128789Sahrens * dataset. 129789Sahrens */ 1303547Smaybee err = arc_free(pio, tx->tx_pool->dp_spa, 1313547Smaybee tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); 1323547Smaybee ASSERT(err == 0); 133789Sahrens 134789Sahrens dsl_dir_diduse_space(tx->tx_pool->dp_mos_dir, 135789Sahrens -used, -compressed, -uncompressed, tx); 136789Sahrens dsl_dir_dirty(tx->tx_pool->dp_mos_dir, tx); 137789Sahrens return; 138789Sahrens } 139789Sahrens ASSERT3P(tx->tx_pool, ==, ds->ds_dir->dd_pool); 140789Sahrens 141789Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 142789Sahrens 143789Sahrens if (bp->blk_birth > ds->ds_phys->ds_prev_snap_txg) { 1443547Smaybee int err; 1453547Smaybee 146789Sahrens dprintf_bp(bp, "freeing: %s", ""); 1473547Smaybee err = arc_free(pio, tx->tx_pool->dp_spa, 1483547Smaybee tx->tx_txg, bp, NULL, NULL, pio ? ARC_NOWAIT: ARC_WAIT); 1493547Smaybee ASSERT(err == 0); 150789Sahrens 151789Sahrens mutex_enter(&ds->ds_lock); 152789Sahrens /* XXX unique_bytes is not accurate for head datasets */ 153789Sahrens /* ASSERT3U(ds->ds_phys->ds_unique_bytes, >=, used); */ 154789Sahrens ds->ds_phys->ds_unique_bytes -= used; 155789Sahrens mutex_exit(&ds->ds_lock); 156789Sahrens dsl_dir_diduse_space(ds->ds_dir, 157789Sahrens -used, -compressed, -uncompressed, tx); 158789Sahrens } else { 159789Sahrens dprintf_bp(bp, "putting on dead list: %s", ""); 1601544Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, bp, tx)); 161789Sahrens /* if (bp->blk_birth > prev prev snap txg) prev unique += bs */ 162789Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 163789Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, 164789Sahrens ds->ds_phys->ds_prev_snap_obj); 165789Sahrens ASSERT(ds->ds_prev->ds_phys->ds_num_children > 0); 166789Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == 1672082Seschrock ds->ds_object && bp->blk_birth > 168789Sahrens ds->ds_prev->ds_phys->ds_prev_snap_txg) { 169789Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 170789Sahrens mutex_enter(&ds->ds_prev->ds_lock); 171789Sahrens ds->ds_prev->ds_phys->ds_unique_bytes += 172789Sahrens used; 173789Sahrens mutex_exit(&ds->ds_prev->ds_lock); 174789Sahrens } 175789Sahrens } 176789Sahrens } 177789Sahrens mutex_enter(&ds->ds_lock); 178789Sahrens ASSERT3U(ds->ds_phys->ds_used_bytes, >=, used); 179789Sahrens ds->ds_phys->ds_used_bytes -= used; 180789Sahrens ASSERT3U(ds->ds_phys->ds_compressed_bytes, >=, compressed); 181789Sahrens ds->ds_phys->ds_compressed_bytes -= compressed; 182789Sahrens ASSERT3U(ds->ds_phys->ds_uncompressed_bytes, >=, uncompressed); 183789Sahrens ds->ds_phys->ds_uncompressed_bytes -= uncompressed; 184789Sahrens mutex_exit(&ds->ds_lock); 185789Sahrens } 186789Sahrens 1871544Seschrock uint64_t 1881544Seschrock dsl_dataset_prev_snap_txg(dsl_dataset_t *ds) 189789Sahrens { 1902885Sahrens uint64_t trysnap = 0; 1912885Sahrens 192789Sahrens if (ds == NULL) 1931544Seschrock return (0); 194789Sahrens /* 195789Sahrens * The snapshot creation could fail, but that would cause an 196789Sahrens * incorrect FALSE return, which would only result in an 197789Sahrens * overestimation of the amount of space that an operation would 198789Sahrens * consume, which is OK. 199789Sahrens * 200789Sahrens * There's also a small window where we could miss a pending 201789Sahrens * snapshot, because we could set the sync task in the quiescing 202789Sahrens * phase. So this should only be used as a guess. 203789Sahrens */ 2042885Sahrens if (ds->ds_trysnap_txg > 2052885Sahrens spa_last_synced_txg(ds->ds_dir->dd_pool->dp_spa)) 2062885Sahrens trysnap = ds->ds_trysnap_txg; 2072885Sahrens return (MAX(ds->ds_phys->ds_prev_snap_txg, trysnap)); 2081544Seschrock } 2091544Seschrock 2101544Seschrock int 2111544Seschrock dsl_dataset_block_freeable(dsl_dataset_t *ds, uint64_t blk_birth) 2121544Seschrock { 2131544Seschrock return (blk_birth > dsl_dataset_prev_snap_txg(ds)); 214789Sahrens } 215789Sahrens 216789Sahrens /* ARGSUSED */ 217789Sahrens static void 218789Sahrens dsl_dataset_evict(dmu_buf_t *db, void *dsv) 219789Sahrens { 220789Sahrens dsl_dataset_t *ds = dsv; 221789Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 222789Sahrens 2233444Sek110237 /* open_refcount == DS_REF_MAX when deleting */ 224789Sahrens ASSERT(ds->ds_open_refcount == 0 || 2253444Sek110237 ds->ds_open_refcount == DS_REF_MAX); 226789Sahrens 227789Sahrens dprintf_ds(ds, "evicting %s\n", ""); 228789Sahrens 229789Sahrens unique_remove(ds->ds_phys->ds_fsid_guid); 230789Sahrens 231789Sahrens if (ds->ds_user_ptr != NULL) 232789Sahrens ds->ds_user_evict_func(ds, ds->ds_user_ptr); 233789Sahrens 234789Sahrens if (ds->ds_prev) { 235789Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 236789Sahrens ds->ds_prev = NULL; 237789Sahrens } 238789Sahrens 239789Sahrens bplist_close(&ds->ds_deadlist); 240789Sahrens dsl_dir_close(ds->ds_dir, ds); 241789Sahrens 242789Sahrens if (list_link_active(&ds->ds_synced_link)) 243789Sahrens list_remove(&dp->dp_synced_objsets, ds); 244789Sahrens 2452856Snd150628 mutex_destroy(&ds->ds_lock); 2462856Snd150628 mutex_destroy(&ds->ds_deadlist.bpl_lock); 2472856Snd150628 248789Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 249789Sahrens } 250789Sahrens 2511544Seschrock static int 252789Sahrens dsl_dataset_get_snapname(dsl_dataset_t *ds) 253789Sahrens { 254789Sahrens dsl_dataset_phys_t *headphys; 255789Sahrens int err; 256789Sahrens dmu_buf_t *headdbuf; 257789Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 258789Sahrens objset_t *mos = dp->dp_meta_objset; 259789Sahrens 260789Sahrens if (ds->ds_snapname[0]) 2611544Seschrock return (0); 262789Sahrens if (ds->ds_phys->ds_next_snap_obj == 0) 2631544Seschrock return (0); 264789Sahrens 2651544Seschrock err = dmu_bonus_hold(mos, ds->ds_dir->dd_phys->dd_head_dataset_obj, 2661544Seschrock FTAG, &headdbuf); 2671544Seschrock if (err) 2681544Seschrock return (err); 269789Sahrens headphys = headdbuf->db_data; 270789Sahrens err = zap_value_search(dp->dp_meta_objset, 2714577Sahrens headphys->ds_snapnames_zapobj, ds->ds_object, 0, ds->ds_snapname); 2721544Seschrock dmu_buf_rele(headdbuf, FTAG); 2731544Seschrock return (err); 274789Sahrens } 275789Sahrens 2761544Seschrock int 277789Sahrens dsl_dataset_open_obj(dsl_pool_t *dp, uint64_t dsobj, const char *snapname, 2781544Seschrock int mode, void *tag, dsl_dataset_t **dsp) 279789Sahrens { 280789Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 281789Sahrens objset_t *mos = dp->dp_meta_objset; 282789Sahrens dmu_buf_t *dbuf; 283789Sahrens dsl_dataset_t *ds; 2841544Seschrock int err; 285789Sahrens 286789Sahrens ASSERT(RW_LOCK_HELD(&dp->dp_config_rwlock) || 287789Sahrens dsl_pool_sync_context(dp)); 288789Sahrens 2891544Seschrock err = dmu_bonus_hold(mos, dsobj, tag, &dbuf); 2901544Seschrock if (err) 2911544Seschrock return (err); 292789Sahrens ds = dmu_buf_get_user(dbuf); 293789Sahrens if (ds == NULL) { 294789Sahrens dsl_dataset_t *winner; 295789Sahrens 296789Sahrens ds = kmem_zalloc(sizeof (dsl_dataset_t), KM_SLEEP); 297789Sahrens ds->ds_dbuf = dbuf; 298789Sahrens ds->ds_object = dsobj; 299789Sahrens ds->ds_phys = dbuf->db_data; 300789Sahrens 3012856Snd150628 mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL); 3022856Snd150628 mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT, 3032856Snd150628 NULL); 3042856Snd150628 3051544Seschrock err = bplist_open(&ds->ds_deadlist, 306789Sahrens mos, ds->ds_phys->ds_deadlist_obj); 3071544Seschrock if (err == 0) { 3081544Seschrock err = dsl_dir_open_obj(dp, 3091544Seschrock ds->ds_phys->ds_dir_obj, NULL, ds, &ds->ds_dir); 3101544Seschrock } 3111544Seschrock if (err) { 3121544Seschrock /* 3131544Seschrock * we don't really need to close the blist if we 3141544Seschrock * just opened it. 3151544Seschrock */ 3162856Snd150628 mutex_destroy(&ds->ds_lock); 3172856Snd150628 mutex_destroy(&ds->ds_deadlist.bpl_lock); 3181544Seschrock kmem_free(ds, sizeof (dsl_dataset_t)); 3191544Seschrock dmu_buf_rele(dbuf, tag); 3201544Seschrock return (err); 3211544Seschrock } 322789Sahrens 323789Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == dsobj) { 324789Sahrens ds->ds_snapname[0] = '\0'; 325789Sahrens if (ds->ds_phys->ds_prev_snap_obj) { 3261544Seschrock err = dsl_dataset_open_obj(dp, 327789Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 3281544Seschrock DS_MODE_NONE, ds, &ds->ds_prev); 329789Sahrens } 330789Sahrens } else { 331789Sahrens if (snapname) { 332789Sahrens #ifdef ZFS_DEBUG 333789Sahrens dsl_dataset_phys_t *headphys; 3341544Seschrock dmu_buf_t *headdbuf; 3351544Seschrock err = dmu_bonus_hold(mos, 3361544Seschrock ds->ds_dir->dd_phys->dd_head_dataset_obj, 3371544Seschrock FTAG, &headdbuf); 3381544Seschrock if (err == 0) { 3391544Seschrock headphys = headdbuf->db_data; 3401544Seschrock uint64_t foundobj; 3411544Seschrock err = zap_lookup(dp->dp_meta_objset, 3421544Seschrock headphys->ds_snapnames_zapobj, 3431544Seschrock snapname, sizeof (foundobj), 1, 3441544Seschrock &foundobj); 3451544Seschrock ASSERT3U(foundobj, ==, dsobj); 3461544Seschrock dmu_buf_rele(headdbuf, FTAG); 3471544Seschrock } 348789Sahrens #endif 349789Sahrens (void) strcat(ds->ds_snapname, snapname); 350789Sahrens } else if (zfs_flags & ZFS_DEBUG_SNAPNAMES) { 3511544Seschrock err = dsl_dataset_get_snapname(ds); 352789Sahrens } 353789Sahrens } 354789Sahrens 3551544Seschrock if (err == 0) { 3561544Seschrock winner = dmu_buf_set_user_ie(dbuf, ds, &ds->ds_phys, 3571544Seschrock dsl_dataset_evict); 3581544Seschrock } 3591544Seschrock if (err || winner) { 360789Sahrens bplist_close(&ds->ds_deadlist); 361789Sahrens if (ds->ds_prev) { 362789Sahrens dsl_dataset_close(ds->ds_prev, 363789Sahrens DS_MODE_NONE, ds); 364789Sahrens } 365789Sahrens dsl_dir_close(ds->ds_dir, ds); 3662856Snd150628 mutex_destroy(&ds->ds_lock); 3672856Snd150628 mutex_destroy(&ds->ds_deadlist.bpl_lock); 368789Sahrens kmem_free(ds, sizeof (dsl_dataset_t)); 3691544Seschrock if (err) { 3701544Seschrock dmu_buf_rele(dbuf, tag); 3711544Seschrock return (err); 3721544Seschrock } 373789Sahrens ds = winner; 374789Sahrens } else { 375789Sahrens uint64_t new = 376789Sahrens unique_insert(ds->ds_phys->ds_fsid_guid); 377789Sahrens if (new != ds->ds_phys->ds_fsid_guid) { 378789Sahrens /* XXX it won't necessarily be synced... */ 379789Sahrens ds->ds_phys->ds_fsid_guid = new; 380789Sahrens } 381789Sahrens } 382789Sahrens } 383789Sahrens ASSERT3P(ds->ds_dbuf, ==, dbuf); 384789Sahrens ASSERT3P(ds->ds_phys, ==, dbuf->db_data); 385789Sahrens 386789Sahrens mutex_enter(&ds->ds_lock); 387789Sahrens if ((DS_MODE_LEVEL(mode) == DS_MODE_PRIMARY && 3882082Seschrock (ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT) && 3892082Seschrock !DS_MODE_IS_INCONSISTENT(mode)) || 3903444Sek110237 (ds->ds_open_refcount + weight > DS_REF_MAX)) { 391789Sahrens mutex_exit(&ds->ds_lock); 392789Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 3931544Seschrock return (EBUSY); 394789Sahrens } 395789Sahrens ds->ds_open_refcount += weight; 396789Sahrens mutex_exit(&ds->ds_lock); 397789Sahrens 3981544Seschrock *dsp = ds; 3991544Seschrock return (0); 400789Sahrens } 401789Sahrens 402789Sahrens int 403789Sahrens dsl_dataset_open_spa(spa_t *spa, const char *name, int mode, 404789Sahrens void *tag, dsl_dataset_t **dsp) 405789Sahrens { 406789Sahrens dsl_dir_t *dd; 407789Sahrens dsl_pool_t *dp; 408789Sahrens const char *tail; 409789Sahrens uint64_t obj; 410789Sahrens dsl_dataset_t *ds = NULL; 411789Sahrens int err = 0; 412789Sahrens 4131544Seschrock err = dsl_dir_open_spa(spa, name, FTAG, &dd, &tail); 4141544Seschrock if (err) 4151544Seschrock return (err); 416789Sahrens 417789Sahrens dp = dd->dd_pool; 418789Sahrens obj = dd->dd_phys->dd_head_dataset_obj; 419789Sahrens rw_enter(&dp->dp_config_rwlock, RW_READER); 420789Sahrens if (obj == 0) { 421789Sahrens /* A dataset with no associated objset */ 422789Sahrens err = ENOENT; 423789Sahrens goto out; 424789Sahrens } 425789Sahrens 426789Sahrens if (tail != NULL) { 427789Sahrens objset_t *mos = dp->dp_meta_objset; 428789Sahrens 4291544Seschrock err = dsl_dataset_open_obj(dp, obj, NULL, 4301544Seschrock DS_MODE_NONE, tag, &ds); 4311544Seschrock if (err) 4321544Seschrock goto out; 433789Sahrens obj = ds->ds_phys->ds_snapnames_zapobj; 434789Sahrens dsl_dataset_close(ds, DS_MODE_NONE, tag); 435789Sahrens ds = NULL; 436789Sahrens 437789Sahrens if (tail[0] != '@') { 438789Sahrens err = ENOENT; 439789Sahrens goto out; 440789Sahrens } 441789Sahrens tail++; 442789Sahrens 443789Sahrens /* Look for a snapshot */ 444789Sahrens if (!DS_MODE_IS_READONLY(mode)) { 445789Sahrens err = EROFS; 446789Sahrens goto out; 447789Sahrens } 448789Sahrens dprintf("looking for snapshot '%s'\n", tail); 449789Sahrens err = zap_lookup(mos, obj, tail, 8, 1, &obj); 450789Sahrens if (err) 451789Sahrens goto out; 452789Sahrens } 4531544Seschrock err = dsl_dataset_open_obj(dp, obj, tail, mode, tag, &ds); 454789Sahrens 455789Sahrens out: 456789Sahrens rw_exit(&dp->dp_config_rwlock); 457789Sahrens dsl_dir_close(dd, FTAG); 458789Sahrens 459789Sahrens ASSERT3U((err == 0), ==, (ds != NULL)); 460789Sahrens /* ASSERT(ds == NULL || strcmp(name, ds->ds_name) == 0); */ 461789Sahrens 462789Sahrens *dsp = ds; 463789Sahrens return (err); 464789Sahrens } 465789Sahrens 466789Sahrens int 467789Sahrens dsl_dataset_open(const char *name, int mode, void *tag, dsl_dataset_t **dsp) 468789Sahrens { 469789Sahrens return (dsl_dataset_open_spa(NULL, name, mode, tag, dsp)); 470789Sahrens } 471789Sahrens 472789Sahrens void 473789Sahrens dsl_dataset_name(dsl_dataset_t *ds, char *name) 474789Sahrens { 475789Sahrens if (ds == NULL) { 476789Sahrens (void) strcpy(name, "mos"); 477789Sahrens } else { 478789Sahrens dsl_dir_name(ds->ds_dir, name); 4791544Seschrock VERIFY(0 == dsl_dataset_get_snapname(ds)); 480789Sahrens if (ds->ds_snapname[0]) { 481789Sahrens (void) strcat(name, "@"); 482789Sahrens if (!MUTEX_HELD(&ds->ds_lock)) { 483789Sahrens /* 484789Sahrens * We use a "recursive" mutex so that we 485789Sahrens * can call dprintf_ds() with ds_lock held. 486789Sahrens */ 487789Sahrens mutex_enter(&ds->ds_lock); 488789Sahrens (void) strcat(name, ds->ds_snapname); 489789Sahrens mutex_exit(&ds->ds_lock); 490789Sahrens } else { 491789Sahrens (void) strcat(name, ds->ds_snapname); 492789Sahrens } 493789Sahrens } 494789Sahrens } 495789Sahrens } 496789Sahrens 4973978Smmusante static int 4983978Smmusante dsl_dataset_namelen(dsl_dataset_t *ds) 4993978Smmusante { 5003978Smmusante int result; 5013978Smmusante 5023978Smmusante if (ds == NULL) { 5033978Smmusante result = 3; /* "mos" */ 5043978Smmusante } else { 5053978Smmusante result = dsl_dir_namelen(ds->ds_dir); 5063978Smmusante VERIFY(0 == dsl_dataset_get_snapname(ds)); 5073978Smmusante if (ds->ds_snapname[0]) { 5083978Smmusante ++result; /* adding one for the @-sign */ 5093978Smmusante if (!MUTEX_HELD(&ds->ds_lock)) { 5103978Smmusante /* see dsl_datset_name */ 5113978Smmusante mutex_enter(&ds->ds_lock); 5123978Smmusante result += strlen(ds->ds_snapname); 5133978Smmusante mutex_exit(&ds->ds_lock); 5143978Smmusante } else { 5153978Smmusante result += strlen(ds->ds_snapname); 5163978Smmusante } 5173978Smmusante } 5183978Smmusante } 5193978Smmusante 5203978Smmusante return (result); 5213978Smmusante } 5223978Smmusante 523789Sahrens void 524789Sahrens dsl_dataset_close(dsl_dataset_t *ds, int mode, void *tag) 525789Sahrens { 526789Sahrens uint64_t weight = ds_refcnt_weight[DS_MODE_LEVEL(mode)]; 527789Sahrens mutex_enter(&ds->ds_lock); 528789Sahrens ASSERT3U(ds->ds_open_refcount, >=, weight); 529789Sahrens ds->ds_open_refcount -= weight; 530789Sahrens dprintf_ds(ds, "closing mode %u refcount now 0x%llx\n", 531789Sahrens mode, ds->ds_open_refcount); 532789Sahrens mutex_exit(&ds->ds_lock); 533789Sahrens 5341544Seschrock dmu_buf_rele(ds->ds_dbuf, tag); 535789Sahrens } 536789Sahrens 537789Sahrens void 538789Sahrens dsl_dataset_create_root(dsl_pool_t *dp, uint64_t *ddobjp, dmu_tx_t *tx) 539789Sahrens { 540789Sahrens objset_t *mos = dp->dp_meta_objset; 541789Sahrens dmu_buf_t *dbuf; 542789Sahrens dsl_dataset_phys_t *dsphys; 543789Sahrens dsl_dataset_t *ds; 544789Sahrens uint64_t dsobj; 545789Sahrens dsl_dir_t *dd; 546789Sahrens 547789Sahrens dsl_dir_create_root(mos, ddobjp, tx); 5481544Seschrock VERIFY(0 == dsl_dir_open_obj(dp, *ddobjp, NULL, FTAG, &dd)); 549789Sahrens 550928Stabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 551928Stabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 5521544Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 553789Sahrens dmu_buf_will_dirty(dbuf, tx); 554789Sahrens dsphys = dbuf->db_data; 555789Sahrens dsphys->ds_dir_obj = dd->dd_object; 556789Sahrens dsphys->ds_fsid_guid = unique_create(); 5571544Seschrock unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 558789Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 559789Sahrens sizeof (dsphys->ds_guid)); 560789Sahrens dsphys->ds_snapnames_zapobj = 561885Sahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 562789Sahrens dsphys->ds_creation_time = gethrestime_sec(); 563789Sahrens dsphys->ds_creation_txg = tx->tx_txg; 564789Sahrens dsphys->ds_deadlist_obj = 565789Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 5661544Seschrock dmu_buf_rele(dbuf, FTAG); 567789Sahrens 568789Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 569789Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 570789Sahrens dsl_dir_close(dd, FTAG); 571789Sahrens 5721544Seschrock VERIFY(0 == 5731544Seschrock dsl_dataset_open_obj(dp, dsobj, NULL, DS_MODE_NONE, FTAG, &ds)); 5743547Smaybee (void) dmu_objset_create_impl(dp->dp_spa, ds, 5753547Smaybee &ds->ds_phys->ds_bp, DMU_OST_ZFS, tx); 576789Sahrens dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 577789Sahrens } 578789Sahrens 5792199Sahrens uint64_t 5802199Sahrens dsl_dataset_create_sync(dsl_dir_t *pdd, 581789Sahrens const char *lastname, dsl_dataset_t *clone_parent, dmu_tx_t *tx) 582789Sahrens { 5832199Sahrens dsl_pool_t *dp = pdd->dd_pool; 584789Sahrens dmu_buf_t *dbuf; 585789Sahrens dsl_dataset_phys_t *dsphys; 5862199Sahrens uint64_t dsobj, ddobj; 587789Sahrens objset_t *mos = dp->dp_meta_objset; 588789Sahrens dsl_dir_t *dd; 589789Sahrens 5902199Sahrens ASSERT(clone_parent == NULL || clone_parent->ds_dir->dd_pool == dp); 5912199Sahrens ASSERT(clone_parent == NULL || 5922199Sahrens clone_parent->ds_phys->ds_num_children > 0); 593789Sahrens ASSERT(lastname[0] != '@'); 594789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 595789Sahrens 5962199Sahrens ddobj = dsl_dir_create_sync(pdd, lastname, tx); 5972199Sahrens VERIFY(0 == dsl_dir_open_obj(dp, ddobj, lastname, FTAG, &dd)); 598789Sahrens 599928Stabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 600928Stabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 6011544Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 602789Sahrens dmu_buf_will_dirty(dbuf, tx); 603789Sahrens dsphys = dbuf->db_data; 604789Sahrens dsphys->ds_dir_obj = dd->dd_object; 605789Sahrens dsphys->ds_fsid_guid = unique_create(); 606789Sahrens unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 607789Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 608789Sahrens sizeof (dsphys->ds_guid)); 609789Sahrens dsphys->ds_snapnames_zapobj = 610885Sahrens zap_create(mos, DMU_OT_DSL_DS_SNAP_MAP, DMU_OT_NONE, 0, tx); 611789Sahrens dsphys->ds_creation_time = gethrestime_sec(); 612789Sahrens dsphys->ds_creation_txg = tx->tx_txg; 613789Sahrens dsphys->ds_deadlist_obj = 614789Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 615789Sahrens if (clone_parent) { 616789Sahrens dsphys->ds_prev_snap_obj = clone_parent->ds_object; 617789Sahrens dsphys->ds_prev_snap_txg = 618789Sahrens clone_parent->ds_phys->ds_creation_txg; 619789Sahrens dsphys->ds_used_bytes = 620789Sahrens clone_parent->ds_phys->ds_used_bytes; 621789Sahrens dsphys->ds_compressed_bytes = 622789Sahrens clone_parent->ds_phys->ds_compressed_bytes; 623789Sahrens dsphys->ds_uncompressed_bytes = 624789Sahrens clone_parent->ds_phys->ds_uncompressed_bytes; 625789Sahrens dsphys->ds_bp = clone_parent->ds_phys->ds_bp; 626789Sahrens 627789Sahrens dmu_buf_will_dirty(clone_parent->ds_dbuf, tx); 628789Sahrens clone_parent->ds_phys->ds_num_children++; 629789Sahrens 630789Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 631789Sahrens dd->dd_phys->dd_clone_parent_obj = clone_parent->ds_object; 632789Sahrens } 6331544Seschrock dmu_buf_rele(dbuf, FTAG); 634789Sahrens 635789Sahrens dmu_buf_will_dirty(dd->dd_dbuf, tx); 636789Sahrens dd->dd_phys->dd_head_dataset_obj = dsobj; 637789Sahrens dsl_dir_close(dd, FTAG); 638789Sahrens 6392199Sahrens return (dsobj); 6402199Sahrens } 6412199Sahrens 6422199Sahrens struct destroyarg { 6432199Sahrens dsl_sync_task_group_t *dstg; 6442199Sahrens char *snapname; 6452199Sahrens char *failed; 6462199Sahrens }; 6472199Sahrens 6482199Sahrens static int 6492199Sahrens dsl_snapshot_destroy_one(char *name, void *arg) 6502199Sahrens { 6512199Sahrens struct destroyarg *da = arg; 6522199Sahrens dsl_dataset_t *ds; 6532199Sahrens char *cp; 6542199Sahrens int err; 6552199Sahrens 6562199Sahrens (void) strcat(name, "@"); 6572199Sahrens (void) strcat(name, da->snapname); 6582199Sahrens err = dsl_dataset_open(name, 6592199Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 6604007Smmusante da->dstg, &ds); 6612199Sahrens cp = strchr(name, '@'); 6622199Sahrens *cp = '\0'; 6632199Sahrens if (err == ENOENT) 6642199Sahrens return (0); 6652199Sahrens if (err) { 6662199Sahrens (void) strcpy(da->failed, name); 6672199Sahrens return (err); 6682199Sahrens } 6692199Sahrens 6702199Sahrens dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check, 6714007Smmusante dsl_dataset_destroy_sync, ds, da->dstg, 0); 672789Sahrens return (0); 673789Sahrens } 674789Sahrens 6752199Sahrens /* 6762199Sahrens * Destroy 'snapname' in all descendants of 'fsname'. 6772199Sahrens */ 6782199Sahrens #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy 6792199Sahrens int 6802199Sahrens dsl_snapshots_destroy(char *fsname, char *snapname) 6812199Sahrens { 6822199Sahrens int err; 6832199Sahrens struct destroyarg da; 6842199Sahrens dsl_sync_task_t *dst; 6852199Sahrens spa_t *spa; 6862199Sahrens 687*4603Sahrens err = spa_open(fsname, &spa, FTAG); 6882199Sahrens if (err) 6892199Sahrens return (err); 6902199Sahrens da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 6912199Sahrens da.snapname = snapname; 6922199Sahrens da.failed = fsname; 6932199Sahrens 6942199Sahrens err = dmu_objset_find(fsname, 6952417Sahrens dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN); 6962199Sahrens 6972199Sahrens if (err == 0) 6982199Sahrens err = dsl_sync_task_group_wait(da.dstg); 6992199Sahrens 7002199Sahrens for (dst = list_head(&da.dstg->dstg_tasks); dst; 7012199Sahrens dst = list_next(&da.dstg->dstg_tasks, dst)) { 7022199Sahrens dsl_dataset_t *ds = dst->dst_arg1; 7032199Sahrens if (dst->dst_err) { 7042199Sahrens dsl_dataset_name(ds, fsname); 705*4603Sahrens *strchr(fsname, '@') = '\0'; 7062199Sahrens } 7072199Sahrens /* 7082199Sahrens * If it was successful, destroy_sync would have 7092199Sahrens * closed the ds 7102199Sahrens */ 7112199Sahrens if (err) 7124007Smmusante dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, da.dstg); 7132199Sahrens } 7142199Sahrens 7152199Sahrens dsl_sync_task_group_destroy(da.dstg); 7162199Sahrens spa_close(spa, FTAG); 7172199Sahrens return (err); 7182199Sahrens } 7192199Sahrens 720789Sahrens int 721789Sahrens dsl_dataset_destroy(const char *name) 722789Sahrens { 723789Sahrens int err; 7242199Sahrens dsl_sync_task_group_t *dstg; 7252199Sahrens objset_t *os; 7262199Sahrens dsl_dataset_t *ds; 727789Sahrens dsl_dir_t *dd; 7282199Sahrens uint64_t obj; 7292199Sahrens 7302199Sahrens if (strchr(name, '@')) { 7312199Sahrens /* Destroying a snapshot is simpler */ 7322199Sahrens err = dsl_dataset_open(name, 7332199Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 7342199Sahrens FTAG, &ds); 7352199Sahrens if (err) 7362199Sahrens return (err); 7372199Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 7382199Sahrens dsl_dataset_destroy_check, dsl_dataset_destroy_sync, 7392199Sahrens ds, FTAG, 0); 7402199Sahrens if (err) 7412199Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 7422199Sahrens return (err); 7432199Sahrens } 7442199Sahrens 7452199Sahrens err = dmu_objset_open(name, DMU_OST_ANY, 7462199Sahrens DS_MODE_EXCLUSIVE | DS_MODE_INCONSISTENT, &os); 7472199Sahrens if (err) 7482199Sahrens return (err); 7492199Sahrens ds = os->os->os_dsl_dataset; 7502199Sahrens dd = ds->ds_dir; 751789Sahrens 7522199Sahrens /* 7532199Sahrens * Check for errors and mark this ds as inconsistent, in 7542199Sahrens * case we crash while freeing the objects. 7552199Sahrens */ 7562199Sahrens err = dsl_sync_task_do(dd->dd_pool, dsl_dataset_destroy_begin_check, 7572199Sahrens dsl_dataset_destroy_begin_sync, ds, NULL, 0); 7582199Sahrens if (err) { 7592199Sahrens dmu_objset_close(os); 7602199Sahrens return (err); 7612199Sahrens } 7622199Sahrens 7632199Sahrens /* 7642199Sahrens * remove the objects in open context, so that we won't 7652199Sahrens * have too much to do in syncing context. 7662199Sahrens */ 7673025Sahrens for (obj = 0; err == 0; err = dmu_object_next(os, &obj, FALSE, 7683025Sahrens ds->ds_phys->ds_prev_snap_txg)) { 7692199Sahrens dmu_tx_t *tx = dmu_tx_create(os); 7702199Sahrens dmu_tx_hold_free(tx, obj, 0, DMU_OBJECT_END); 7712199Sahrens dmu_tx_hold_bonus(tx, obj); 7722199Sahrens err = dmu_tx_assign(tx, TXG_WAIT); 7732199Sahrens if (err) { 7742199Sahrens /* 7752199Sahrens * Perhaps there is not enough disk 7762199Sahrens * space. Just deal with it from 7772199Sahrens * dsl_dataset_destroy_sync(). 7782199Sahrens */ 7792199Sahrens dmu_tx_abort(tx); 7802199Sahrens continue; 7812199Sahrens } 7822199Sahrens VERIFY(0 == dmu_object_free(os, obj, tx)); 7832199Sahrens dmu_tx_commit(tx); 7842199Sahrens } 7852199Sahrens /* Make sure it's not dirty before we finish destroying it. */ 7862199Sahrens txg_wait_synced(dd->dd_pool, 0); 7872199Sahrens 7882199Sahrens dmu_objset_close(os); 7892199Sahrens if (err != ESRCH) 7902199Sahrens return (err); 7912199Sahrens 7922199Sahrens err = dsl_dataset_open(name, 7932199Sahrens DS_MODE_EXCLUSIVE | DS_MODE_READONLY | DS_MODE_INCONSISTENT, 7942199Sahrens FTAG, &ds); 7951544Seschrock if (err) 7961544Seschrock return (err); 797789Sahrens 7982199Sahrens err = dsl_dir_open(name, FTAG, &dd, NULL); 7992199Sahrens if (err) { 8002199Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 8012199Sahrens return (err); 802789Sahrens } 803789Sahrens 8042199Sahrens /* 8052199Sahrens * Blow away the dsl_dir + head dataset. 8062199Sahrens */ 8072199Sahrens dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool); 8082199Sahrens dsl_sync_task_create(dstg, dsl_dataset_destroy_check, 8092199Sahrens dsl_dataset_destroy_sync, ds, FTAG, 0); 8102199Sahrens dsl_sync_task_create(dstg, dsl_dir_destroy_check, 8112199Sahrens dsl_dir_destroy_sync, dd, FTAG, 0); 8122199Sahrens err = dsl_sync_task_group_wait(dstg); 8132199Sahrens dsl_sync_task_group_destroy(dstg); 8142199Sahrens /* if it is successful, *destroy_sync will close the ds+dd */ 8152199Sahrens if (err) { 8162199Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 8172199Sahrens dsl_dir_close(dd, FTAG); 8182199Sahrens } 819789Sahrens return (err); 820789Sahrens } 821789Sahrens 822789Sahrens int 8232199Sahrens dsl_dataset_rollback(dsl_dataset_t *ds) 824789Sahrens { 8253444Sek110237 ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX); 8262199Sahrens return (dsl_sync_task_do(ds->ds_dir->dd_pool, 8272199Sahrens dsl_dataset_rollback_check, dsl_dataset_rollback_sync, 8282199Sahrens ds, NULL, 0)); 829789Sahrens } 830789Sahrens 831789Sahrens void * 832789Sahrens dsl_dataset_set_user_ptr(dsl_dataset_t *ds, 833789Sahrens void *p, dsl_dataset_evict_func_t func) 834789Sahrens { 835789Sahrens void *old; 836789Sahrens 837789Sahrens mutex_enter(&ds->ds_lock); 838789Sahrens old = ds->ds_user_ptr; 839789Sahrens if (old == NULL) { 840789Sahrens ds->ds_user_ptr = p; 841789Sahrens ds->ds_user_evict_func = func; 842789Sahrens } 843789Sahrens mutex_exit(&ds->ds_lock); 844789Sahrens return (old); 845789Sahrens } 846789Sahrens 847789Sahrens void * 848789Sahrens dsl_dataset_get_user_ptr(dsl_dataset_t *ds) 849789Sahrens { 850789Sahrens return (ds->ds_user_ptr); 851789Sahrens } 852789Sahrens 853789Sahrens 8543547Smaybee blkptr_t * 8553547Smaybee dsl_dataset_get_blkptr(dsl_dataset_t *ds) 856789Sahrens { 8573547Smaybee return (&ds->ds_phys->ds_bp); 858789Sahrens } 859789Sahrens 860789Sahrens void 861789Sahrens dsl_dataset_set_blkptr(dsl_dataset_t *ds, blkptr_t *bp, dmu_tx_t *tx) 862789Sahrens { 863789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 864789Sahrens /* If it's the meta-objset, set dp_meta_rootbp */ 865789Sahrens if (ds == NULL) { 866789Sahrens tx->tx_pool->dp_meta_rootbp = *bp; 867789Sahrens } else { 868789Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 869789Sahrens ds->ds_phys->ds_bp = *bp; 870789Sahrens } 871789Sahrens } 872789Sahrens 873789Sahrens spa_t * 874789Sahrens dsl_dataset_get_spa(dsl_dataset_t *ds) 875789Sahrens { 876789Sahrens return (ds->ds_dir->dd_pool->dp_spa); 877789Sahrens } 878789Sahrens 879789Sahrens void 880789Sahrens dsl_dataset_dirty(dsl_dataset_t *ds, dmu_tx_t *tx) 881789Sahrens { 882789Sahrens dsl_pool_t *dp; 883789Sahrens 884789Sahrens if (ds == NULL) /* this is the meta-objset */ 885789Sahrens return; 886789Sahrens 887789Sahrens ASSERT(ds->ds_user_ptr != NULL); 8882885Sahrens 8892885Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 8902885Sahrens panic("dirtying snapshot!"); 891789Sahrens 892789Sahrens dp = ds->ds_dir->dd_pool; 893789Sahrens 894789Sahrens if (txg_list_add(&dp->dp_dirty_datasets, ds, tx->tx_txg) == 0) { 895789Sahrens /* up the hold count until we can be written out */ 896789Sahrens dmu_buf_add_ref(ds->ds_dbuf, ds); 897789Sahrens } 898789Sahrens } 899789Sahrens 900789Sahrens struct killarg { 901789Sahrens uint64_t *usedp; 902789Sahrens uint64_t *compressedp; 903789Sahrens uint64_t *uncompressedp; 904789Sahrens zio_t *zio; 905789Sahrens dmu_tx_t *tx; 906789Sahrens }; 907789Sahrens 908789Sahrens static int 909789Sahrens kill_blkptr(traverse_blk_cache_t *bc, spa_t *spa, void *arg) 910789Sahrens { 911789Sahrens struct killarg *ka = arg; 912789Sahrens blkptr_t *bp = &bc->bc_blkptr; 913789Sahrens 914789Sahrens ASSERT3U(bc->bc_errno, ==, 0); 915789Sahrens 916789Sahrens /* 917789Sahrens * Since this callback is not called concurrently, no lock is 918789Sahrens * needed on the accounting values. 919789Sahrens */ 9202082Seschrock *ka->usedp += bp_get_dasize(spa, bp); 921789Sahrens *ka->compressedp += BP_GET_PSIZE(bp); 922789Sahrens *ka->uncompressedp += BP_GET_UCSIZE(bp); 923789Sahrens /* XXX check for EIO? */ 924789Sahrens (void) arc_free(ka->zio, spa, ka->tx->tx_txg, bp, NULL, NULL, 925789Sahrens ARC_NOWAIT); 926789Sahrens return (0); 927789Sahrens } 928789Sahrens 929789Sahrens /* ARGSUSED */ 9302199Sahrens static int 9312199Sahrens dsl_dataset_rollback_check(void *arg1, void *arg2, dmu_tx_t *tx) 932789Sahrens { 9332199Sahrens dsl_dataset_t *ds = arg1; 934789Sahrens 9352199Sahrens /* 9362199Sahrens * There must be a previous snapshot. I suppose we could roll 9372199Sahrens * it back to being empty (and re-initialize the upper (ZPL) 9382199Sahrens * layer). But for now there's no way to do this via the user 9392199Sahrens * interface. 9402199Sahrens */ 9412199Sahrens if (ds->ds_phys->ds_prev_snap_txg == 0) 942789Sahrens return (EINVAL); 943789Sahrens 9442199Sahrens /* 9452199Sahrens * This must not be a snapshot. 9462199Sahrens */ 9472199Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) 9482199Sahrens return (EINVAL); 949789Sahrens 950789Sahrens /* 951789Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 952789Sahrens * them. Try again. 953789Sahrens */ 9542199Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 955789Sahrens return (EAGAIN); 9562199Sahrens 9572199Sahrens return (0); 9582199Sahrens } 959789Sahrens 9602199Sahrens /* ARGSUSED */ 9612199Sahrens static void 9624543Smarks dsl_dataset_rollback_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 9632199Sahrens { 9642199Sahrens dsl_dataset_t *ds = arg1; 9652199Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 966789Sahrens 967789Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 968789Sahrens 969789Sahrens /* Zero out the deadlist. */ 970789Sahrens bplist_close(&ds->ds_deadlist); 971789Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 972789Sahrens ds->ds_phys->ds_deadlist_obj = 973789Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 9741544Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 9751544Seschrock ds->ds_phys->ds_deadlist_obj)); 976789Sahrens 977789Sahrens { 978789Sahrens /* Free blkptrs that we gave birth to */ 979789Sahrens zio_t *zio; 980789Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 981789Sahrens struct killarg ka; 982789Sahrens 983789Sahrens zio = zio_root(tx->tx_pool->dp_spa, NULL, NULL, 984789Sahrens ZIO_FLAG_MUSTSUCCEED); 985789Sahrens ka.usedp = &used; 986789Sahrens ka.compressedp = &compressed; 987789Sahrens ka.uncompressedp = &uncompressed; 988789Sahrens ka.zio = zio; 989789Sahrens ka.tx = tx; 990789Sahrens (void) traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 991789Sahrens ADVANCE_POST, kill_blkptr, &ka); 992789Sahrens (void) zio_wait(zio); 993789Sahrens 9942199Sahrens dsl_dir_diduse_space(ds->ds_dir, 995789Sahrens -used, -compressed, -uncompressed, tx); 996789Sahrens } 997789Sahrens 9982199Sahrens /* Change our contents to that of the prev snapshot */ 999789Sahrens ASSERT3U(ds->ds_prev->ds_object, ==, ds->ds_phys->ds_prev_snap_obj); 1000789Sahrens ds->ds_phys->ds_bp = ds->ds_prev->ds_phys->ds_bp; 1001789Sahrens ds->ds_phys->ds_used_bytes = ds->ds_prev->ds_phys->ds_used_bytes; 1002789Sahrens ds->ds_phys->ds_compressed_bytes = 1003789Sahrens ds->ds_prev->ds_phys->ds_compressed_bytes; 1004789Sahrens ds->ds_phys->ds_uncompressed_bytes = 1005789Sahrens ds->ds_prev->ds_phys->ds_uncompressed_bytes; 10062082Seschrock ds->ds_phys->ds_flags = ds->ds_prev->ds_phys->ds_flags; 1007789Sahrens ds->ds_phys->ds_unique_bytes = 0; 1008789Sahrens 10092532Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 10102532Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 10112532Sahrens ds->ds_prev->ds_phys->ds_unique_bytes = 0; 10122532Sahrens } 10134543Smarks 10144543Smarks spa_history_internal_log(LOG_DS_ROLLBACK, ds->ds_dir->dd_pool->dp_spa, 10154543Smarks tx, cr, "dataset = %llu", ds->ds_object); 1016789Sahrens } 1017789Sahrens 10181731Sbonwick /* ARGSUSED */ 10191731Sbonwick static int 10202199Sahrens dsl_dataset_destroy_begin_check(void *arg1, void *arg2, dmu_tx_t *tx) 10211731Sbonwick { 10222199Sahrens dsl_dataset_t *ds = arg1; 10231731Sbonwick 10241731Sbonwick /* 10251731Sbonwick * Can't delete a head dataset if there are snapshots of it. 10261731Sbonwick * (Except if the only snapshots are from the branch we cloned 10271731Sbonwick * from.) 10281731Sbonwick */ 10291731Sbonwick if (ds->ds_prev != NULL && 10301731Sbonwick ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 10311731Sbonwick return (EINVAL); 10321731Sbonwick 10331731Sbonwick return (0); 10341731Sbonwick } 10351731Sbonwick 10362199Sahrens /* ARGSUSED */ 10372199Sahrens static void 10384543Smarks dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 1039789Sahrens { 10402199Sahrens dsl_dataset_t *ds = arg1; 10414543Smarks dsl_pool_t *dp = ds->ds_dir->dd_pool; 1042789Sahrens 10432199Sahrens /* Mark it as inconsistent on-disk, in case we crash */ 10442199Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 10452199Sahrens ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT; 10464543Smarks 10474543Smarks spa_history_internal_log(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx, 10484543Smarks cr, "dataset = %llu", ds->ds_object); 10492199Sahrens } 1050789Sahrens 10512199Sahrens /* ARGSUSED */ 10522199Sahrens static int 10532199Sahrens dsl_dataset_destroy_check(void *arg1, void *arg2, dmu_tx_t *tx) 10542199Sahrens { 10552199Sahrens dsl_dataset_t *ds = arg1; 1056789Sahrens 1057789Sahrens /* Can't delete a branch point. */ 10582199Sahrens if (ds->ds_phys->ds_num_children > 1) 10592199Sahrens return (EEXIST); 1060789Sahrens 1061789Sahrens /* 1062789Sahrens * Can't delete a head dataset if there are snapshots of it. 1063789Sahrens * (Except if the only snapshots are from the branch we cloned 1064789Sahrens * from.) 1065789Sahrens */ 1066789Sahrens if (ds->ds_prev != NULL && 10672199Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) 1068789Sahrens return (EINVAL); 1069789Sahrens 1070789Sahrens /* 1071789Sahrens * If we made changes this txg, traverse_dsl_dataset won't find 1072789Sahrens * them. Try again. 1073789Sahrens */ 10742199Sahrens if (ds->ds_phys->ds_bp.blk_birth >= tx->tx_txg) 1075789Sahrens return (EAGAIN); 10762199Sahrens 10772199Sahrens /* XXX we should do some i/o error checking... */ 10782199Sahrens return (0); 10792199Sahrens } 10802199Sahrens 10812199Sahrens static void 10824543Smarks dsl_dataset_destroy_sync(void *arg1, void *tag, cred_t *cr, dmu_tx_t *tx) 10832199Sahrens { 10842199Sahrens dsl_dataset_t *ds = arg1; 10852199Sahrens uint64_t used = 0, compressed = 0, uncompressed = 0; 10862199Sahrens zio_t *zio; 10872199Sahrens int err; 10882199Sahrens int after_branch_point = FALSE; 10892199Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 10902199Sahrens objset_t *mos = dp->dp_meta_objset; 10912199Sahrens dsl_dataset_t *ds_prev = NULL; 10922199Sahrens uint64_t obj; 10932199Sahrens 10943444Sek110237 ASSERT3U(ds->ds_open_refcount, ==, DS_REF_MAX); 10952199Sahrens ASSERT3U(ds->ds_phys->ds_num_children, <=, 1); 10962199Sahrens ASSERT(ds->ds_prev == NULL || 10972199Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj != ds->ds_object); 10982199Sahrens ASSERT3U(ds->ds_phys->ds_bp.blk_birth, <=, tx->tx_txg); 10992199Sahrens 11002199Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 11012199Sahrens 11022199Sahrens obj = ds->ds_object; 1103789Sahrens 1104789Sahrens if (ds->ds_phys->ds_prev_snap_obj != 0) { 1105789Sahrens if (ds->ds_prev) { 1106789Sahrens ds_prev = ds->ds_prev; 1107789Sahrens } else { 11082199Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1109789Sahrens ds->ds_phys->ds_prev_snap_obj, NULL, 11102199Sahrens DS_MODE_NONE, FTAG, &ds_prev)); 1111789Sahrens } 1112789Sahrens after_branch_point = 1113789Sahrens (ds_prev->ds_phys->ds_next_snap_obj != obj); 1114789Sahrens 1115789Sahrens dmu_buf_will_dirty(ds_prev->ds_dbuf, tx); 1116789Sahrens if (after_branch_point && 1117789Sahrens ds->ds_phys->ds_next_snap_obj == 0) { 1118789Sahrens /* This clone is toast. */ 1119789Sahrens ASSERT(ds_prev->ds_phys->ds_num_children > 1); 1120789Sahrens ds_prev->ds_phys->ds_num_children--; 1121789Sahrens } else if (!after_branch_point) { 1122789Sahrens ds_prev->ds_phys->ds_next_snap_obj = 1123789Sahrens ds->ds_phys->ds_next_snap_obj; 1124789Sahrens } 1125789Sahrens } 1126789Sahrens 1127789Sahrens zio = zio_root(dp->dp_spa, NULL, NULL, ZIO_FLAG_MUSTSUCCEED); 1128789Sahrens 1129789Sahrens if (ds->ds_phys->ds_next_snap_obj != 0) { 11302199Sahrens blkptr_t bp; 1131789Sahrens dsl_dataset_t *ds_next; 1132789Sahrens uint64_t itor = 0; 1133789Sahrens 1134789Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 1135789Sahrens 11362199Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 11371544Seschrock ds->ds_phys->ds_next_snap_obj, NULL, 11381544Seschrock DS_MODE_NONE, FTAG, &ds_next)); 1139789Sahrens ASSERT3U(ds_next->ds_phys->ds_prev_snap_obj, ==, obj); 1140789Sahrens 1141789Sahrens dmu_buf_will_dirty(ds_next->ds_dbuf, tx); 1142789Sahrens ds_next->ds_phys->ds_prev_snap_obj = 1143789Sahrens ds->ds_phys->ds_prev_snap_obj; 1144789Sahrens ds_next->ds_phys->ds_prev_snap_txg = 1145789Sahrens ds->ds_phys->ds_prev_snap_txg; 1146789Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 1147789Sahrens ds_prev ? ds_prev->ds_phys->ds_creation_txg : 0); 1148789Sahrens 1149789Sahrens /* 1150789Sahrens * Transfer to our deadlist (which will become next's 1151789Sahrens * new deadlist) any entries from next's current 1152789Sahrens * deadlist which were born before prev, and free the 1153789Sahrens * other entries. 1154789Sahrens * 1155789Sahrens * XXX we're doing this long task with the config lock held 1156789Sahrens */ 1157789Sahrens while (bplist_iterate(&ds_next->ds_deadlist, &itor, 1158789Sahrens &bp) == 0) { 1159789Sahrens if (bp.blk_birth <= ds->ds_phys->ds_prev_snap_txg) { 11601544Seschrock VERIFY(0 == bplist_enqueue(&ds->ds_deadlist, 11611544Seschrock &bp, tx)); 1162789Sahrens if (ds_prev && !after_branch_point && 1163789Sahrens bp.blk_birth > 1164789Sahrens ds_prev->ds_phys->ds_prev_snap_txg) { 1165789Sahrens ds_prev->ds_phys->ds_unique_bytes += 11662082Seschrock bp_get_dasize(dp->dp_spa, &bp); 1167789Sahrens } 1168789Sahrens } else { 11692082Seschrock used += bp_get_dasize(dp->dp_spa, &bp); 1170789Sahrens compressed += BP_GET_PSIZE(&bp); 1171789Sahrens uncompressed += BP_GET_UCSIZE(&bp); 1172789Sahrens /* XXX check return value? */ 1173789Sahrens (void) arc_free(zio, dp->dp_spa, tx->tx_txg, 1174789Sahrens &bp, NULL, NULL, ARC_NOWAIT); 1175789Sahrens } 1176789Sahrens } 1177789Sahrens 1178789Sahrens /* free next's deadlist */ 1179789Sahrens bplist_close(&ds_next->ds_deadlist); 1180789Sahrens bplist_destroy(mos, ds_next->ds_phys->ds_deadlist_obj, tx); 1181789Sahrens 1182789Sahrens /* set next's deadlist to our deadlist */ 1183789Sahrens ds_next->ds_phys->ds_deadlist_obj = 1184789Sahrens ds->ds_phys->ds_deadlist_obj; 11851544Seschrock VERIFY(0 == bplist_open(&ds_next->ds_deadlist, mos, 11861544Seschrock ds_next->ds_phys->ds_deadlist_obj)); 1187789Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1188789Sahrens 1189789Sahrens if (ds_next->ds_phys->ds_next_snap_obj != 0) { 1190789Sahrens /* 1191789Sahrens * Update next's unique to include blocks which 1192789Sahrens * were previously shared by only this snapshot 1193789Sahrens * and it. Those blocks will be born after the 1194789Sahrens * prev snap and before this snap, and will have 1195789Sahrens * died after the next snap and before the one 1196789Sahrens * after that (ie. be on the snap after next's 1197789Sahrens * deadlist). 1198789Sahrens * 1199789Sahrens * XXX we're doing this long task with the 1200789Sahrens * config lock held 1201789Sahrens */ 1202789Sahrens dsl_dataset_t *ds_after_next; 1203789Sahrens 12042199Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 1205789Sahrens ds_next->ds_phys->ds_next_snap_obj, NULL, 12061544Seschrock DS_MODE_NONE, FTAG, &ds_after_next)); 1207789Sahrens itor = 0; 1208789Sahrens while (bplist_iterate(&ds_after_next->ds_deadlist, 1209789Sahrens &itor, &bp) == 0) { 1210789Sahrens if (bp.blk_birth > 1211789Sahrens ds->ds_phys->ds_prev_snap_txg && 1212789Sahrens bp.blk_birth <= 1213789Sahrens ds->ds_phys->ds_creation_txg) { 1214789Sahrens ds_next->ds_phys->ds_unique_bytes += 12152082Seschrock bp_get_dasize(dp->dp_spa, &bp); 1216789Sahrens } 1217789Sahrens } 1218789Sahrens 1219789Sahrens dsl_dataset_close(ds_after_next, DS_MODE_NONE, FTAG); 1220789Sahrens ASSERT3P(ds_next->ds_prev, ==, NULL); 1221789Sahrens } else { 1222789Sahrens /* 1223789Sahrens * It would be nice to update the head dataset's 1224789Sahrens * unique. To do so we would have to traverse 1225789Sahrens * it for blocks born after ds_prev, which is 1226789Sahrens * pretty expensive just to maintain something 1227789Sahrens * for debugging purposes. 1228789Sahrens */ 1229789Sahrens ASSERT3P(ds_next->ds_prev, ==, ds); 1230789Sahrens dsl_dataset_close(ds_next->ds_prev, DS_MODE_NONE, 1231789Sahrens ds_next); 1232789Sahrens if (ds_prev) { 12332199Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 12341544Seschrock ds->ds_phys->ds_prev_snap_obj, NULL, 12351544Seschrock DS_MODE_NONE, ds_next, &ds_next->ds_prev)); 1236789Sahrens } else { 1237789Sahrens ds_next->ds_prev = NULL; 1238789Sahrens } 1239789Sahrens } 1240789Sahrens dsl_dataset_close(ds_next, DS_MODE_NONE, FTAG); 1241789Sahrens 1242789Sahrens /* 1243789Sahrens * NB: unique_bytes is not accurate for head objsets 1244789Sahrens * because we don't update it when we delete the most 1245789Sahrens * recent snapshot -- see above comment. 1246789Sahrens */ 1247789Sahrens ASSERT3U(used, ==, ds->ds_phys->ds_unique_bytes); 1248789Sahrens } else { 1249789Sahrens /* 1250789Sahrens * There's no next snapshot, so this is a head dataset. 1251789Sahrens * Destroy the deadlist. Unless it's a clone, the 1252789Sahrens * deadlist should be empty. (If it's a clone, it's 1253789Sahrens * safe to ignore the deadlist contents.) 1254789Sahrens */ 1255789Sahrens struct killarg ka; 1256789Sahrens 1257789Sahrens ASSERT(after_branch_point || bplist_empty(&ds->ds_deadlist)); 1258789Sahrens bplist_close(&ds->ds_deadlist); 1259789Sahrens bplist_destroy(mos, ds->ds_phys->ds_deadlist_obj, tx); 1260789Sahrens ds->ds_phys->ds_deadlist_obj = 0; 1261789Sahrens 1262789Sahrens /* 1263789Sahrens * Free everything that we point to (that's born after 1264789Sahrens * the previous snapshot, if we are a clone) 1265789Sahrens * 1266789Sahrens * XXX we're doing this long task with the config lock held 1267789Sahrens */ 1268789Sahrens ka.usedp = &used; 1269789Sahrens ka.compressedp = &compressed; 1270789Sahrens ka.uncompressedp = &uncompressed; 1271789Sahrens ka.zio = zio; 1272789Sahrens ka.tx = tx; 1273789Sahrens err = traverse_dsl_dataset(ds, ds->ds_phys->ds_prev_snap_txg, 1274789Sahrens ADVANCE_POST, kill_blkptr, &ka); 1275789Sahrens ASSERT3U(err, ==, 0); 1276789Sahrens } 1277789Sahrens 1278789Sahrens err = zio_wait(zio); 1279789Sahrens ASSERT3U(err, ==, 0); 1280789Sahrens 12812199Sahrens dsl_dir_diduse_space(ds->ds_dir, -used, -compressed, -uncompressed, tx); 1282789Sahrens 1283789Sahrens if (ds->ds_phys->ds_snapnames_zapobj) { 1284789Sahrens err = zap_destroy(mos, ds->ds_phys->ds_snapnames_zapobj, tx); 1285789Sahrens ASSERT(err == 0); 1286789Sahrens } 1287789Sahrens 12882199Sahrens if (ds->ds_dir->dd_phys->dd_head_dataset_obj == ds->ds_object) { 1289789Sahrens /* Erase the link in the dataset */ 12902199Sahrens dmu_buf_will_dirty(ds->ds_dir->dd_dbuf, tx); 12912199Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj = 0; 1292789Sahrens /* 1293789Sahrens * dsl_dir_sync_destroy() called us, they'll destroy 1294789Sahrens * the dataset. 1295789Sahrens */ 1296789Sahrens } else { 1297789Sahrens /* remove from snapshot namespace */ 1298789Sahrens dsl_dataset_t *ds_head; 12992199Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 13002199Sahrens ds->ds_dir->dd_phys->dd_head_dataset_obj, NULL, 13011544Seschrock DS_MODE_NONE, FTAG, &ds_head)); 13022207Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 1303789Sahrens #ifdef ZFS_DEBUG 1304789Sahrens { 1305789Sahrens uint64_t val; 1306789Sahrens err = zap_lookup(mos, 1307789Sahrens ds_head->ds_phys->ds_snapnames_zapobj, 13082199Sahrens ds->ds_snapname, 8, 1, &val); 1309789Sahrens ASSERT3U(err, ==, 0); 1310789Sahrens ASSERT3U(val, ==, obj); 1311789Sahrens } 1312789Sahrens #endif 1313789Sahrens err = zap_remove(mos, ds_head->ds_phys->ds_snapnames_zapobj, 13142199Sahrens ds->ds_snapname, tx); 1315789Sahrens ASSERT(err == 0); 1316789Sahrens dsl_dataset_close(ds_head, DS_MODE_NONE, FTAG); 1317789Sahrens } 1318789Sahrens 1319789Sahrens if (ds_prev && ds->ds_prev != ds_prev) 1320789Sahrens dsl_dataset_close(ds_prev, DS_MODE_NONE, FTAG); 1321789Sahrens 13223912Slling spa_clear_bootfs(dp->dp_spa, ds->ds_object, tx); 13234543Smarks spa_history_internal_log(LOG_DS_DESTROY, dp->dp_spa, tx, 13244543Smarks cr, "dataset = %llu", ds->ds_object); 13254543Smarks 13262199Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, tag); 13272199Sahrens VERIFY(0 == dmu_object_free(mos, obj, tx)); 13283912Slling 13292199Sahrens } 13302199Sahrens 13312199Sahrens /* ARGSUSED */ 13322199Sahrens int 13332199Sahrens dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx) 13342199Sahrens { 13352199Sahrens objset_t *os = arg1; 13362199Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 13372199Sahrens const char *snapname = arg2; 13382199Sahrens objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset; 13392199Sahrens int err; 13402199Sahrens uint64_t value; 1341789Sahrens 1342789Sahrens /* 13432199Sahrens * We don't allow multiple snapshots of the same txg. If there 13442199Sahrens * is already one, try again. 13452199Sahrens */ 13462199Sahrens if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg) 13472199Sahrens return (EAGAIN); 13482199Sahrens 13492199Sahrens /* 13502199Sahrens * Check for conflicting name snapshot name. 1351789Sahrens */ 13522199Sahrens err = zap_lookup(mos, ds->ds_phys->ds_snapnames_zapobj, 13532199Sahrens snapname, 8, 1, &value); 13542199Sahrens if (err == 0) 13552199Sahrens return (EEXIST); 13562199Sahrens if (err != ENOENT) 13572199Sahrens return (err); 1358789Sahrens 13593978Smmusante /* 13603978Smmusante * Check that the dataset's name is not too long. Name consists 13613978Smmusante * of the dataset's length + 1 for the @-sign + snapshot name's length 13623978Smmusante */ 13633978Smmusante if (dsl_dataset_namelen(ds) + 1 + strlen(snapname) >= MAXNAMELEN) 13643978Smmusante return (ENAMETOOLONG); 13653978Smmusante 13662199Sahrens ds->ds_trysnap_txg = tx->tx_txg; 1367789Sahrens return (0); 1368789Sahrens } 1369789Sahrens 13702199Sahrens void 13714543Smarks dsl_dataset_snapshot_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 1372789Sahrens { 13732199Sahrens objset_t *os = arg1; 13742199Sahrens dsl_dataset_t *ds = os->os->os_dsl_dataset; 13752199Sahrens const char *snapname = arg2; 13762199Sahrens dsl_pool_t *dp = ds->ds_dir->dd_pool; 1377789Sahrens dmu_buf_t *dbuf; 1378789Sahrens dsl_dataset_phys_t *dsphys; 13792199Sahrens uint64_t dsobj; 1380789Sahrens objset_t *mos = dp->dp_meta_objset; 1381789Sahrens int err; 1382789Sahrens 1383789Sahrens spa_scrub_restart(dp->dp_spa, tx->tx_txg); 13842199Sahrens ASSERT(RW_WRITE_HELD(&dp->dp_config_rwlock)); 1385789Sahrens 1386928Stabriz dsobj = dmu_object_alloc(mos, DMU_OT_DSL_DATASET, 0, 1387928Stabriz DMU_OT_DSL_DATASET, sizeof (dsl_dataset_phys_t), tx); 13881544Seschrock VERIFY(0 == dmu_bonus_hold(mos, dsobj, FTAG, &dbuf)); 1389789Sahrens dmu_buf_will_dirty(dbuf, tx); 1390789Sahrens dsphys = dbuf->db_data; 13912199Sahrens dsphys->ds_dir_obj = ds->ds_dir->dd_object; 1392789Sahrens dsphys->ds_fsid_guid = unique_create(); 1393789Sahrens unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */ 1394789Sahrens (void) random_get_pseudo_bytes((void*)&dsphys->ds_guid, 1395789Sahrens sizeof (dsphys->ds_guid)); 1396789Sahrens dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj; 1397789Sahrens dsphys->ds_prev_snap_txg = ds->ds_phys->ds_prev_snap_txg; 1398789Sahrens dsphys->ds_next_snap_obj = ds->ds_object; 1399789Sahrens dsphys->ds_num_children = 1; 1400789Sahrens dsphys->ds_creation_time = gethrestime_sec(); 1401789Sahrens dsphys->ds_creation_txg = tx->tx_txg; 1402789Sahrens dsphys->ds_deadlist_obj = ds->ds_phys->ds_deadlist_obj; 1403789Sahrens dsphys->ds_used_bytes = ds->ds_phys->ds_used_bytes; 1404789Sahrens dsphys->ds_compressed_bytes = ds->ds_phys->ds_compressed_bytes; 1405789Sahrens dsphys->ds_uncompressed_bytes = ds->ds_phys->ds_uncompressed_bytes; 14062082Seschrock dsphys->ds_flags = ds->ds_phys->ds_flags; 1407789Sahrens dsphys->ds_bp = ds->ds_phys->ds_bp; 14081544Seschrock dmu_buf_rele(dbuf, FTAG); 1409789Sahrens 14102199Sahrens ASSERT3U(ds->ds_prev != 0, ==, ds->ds_phys->ds_prev_snap_obj != 0); 14112199Sahrens if (ds->ds_prev) { 14122199Sahrens ASSERT(ds->ds_prev->ds_phys->ds_next_snap_obj == 1413789Sahrens ds->ds_object || 14142199Sahrens ds->ds_prev->ds_phys->ds_num_children > 1); 14152199Sahrens if (ds->ds_prev->ds_phys->ds_next_snap_obj == ds->ds_object) { 14162199Sahrens dmu_buf_will_dirty(ds->ds_prev->ds_dbuf, tx); 1417789Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, ==, 14182199Sahrens ds->ds_prev->ds_phys->ds_creation_txg); 14192199Sahrens ds->ds_prev->ds_phys->ds_next_snap_obj = dsobj; 1420789Sahrens } 1421789Sahrens } 1422789Sahrens 1423789Sahrens bplist_close(&ds->ds_deadlist); 1424789Sahrens dmu_buf_will_dirty(ds->ds_dbuf, tx); 1425789Sahrens ASSERT3U(ds->ds_phys->ds_prev_snap_txg, <, dsphys->ds_creation_txg); 1426789Sahrens ds->ds_phys->ds_prev_snap_obj = dsobj; 1427789Sahrens ds->ds_phys->ds_prev_snap_txg = dsphys->ds_creation_txg; 1428789Sahrens ds->ds_phys->ds_unique_bytes = 0; 1429789Sahrens ds->ds_phys->ds_deadlist_obj = 1430789Sahrens bplist_create(mos, DSL_DEADLIST_BLOCKSIZE, tx); 14311544Seschrock VERIFY(0 == bplist_open(&ds->ds_deadlist, mos, 14321544Seschrock ds->ds_phys->ds_deadlist_obj)); 1433789Sahrens 1434789Sahrens dprintf("snap '%s' -> obj %llu\n", snapname, dsobj); 1435789Sahrens err = zap_add(mos, ds->ds_phys->ds_snapnames_zapobj, 1436789Sahrens snapname, 8, 1, &dsobj, tx); 1437789Sahrens ASSERT(err == 0); 1438789Sahrens 1439789Sahrens if (ds->ds_prev) 1440789Sahrens dsl_dataset_close(ds->ds_prev, DS_MODE_NONE, ds); 14411544Seschrock VERIFY(0 == dsl_dataset_open_obj(dp, 14421544Seschrock ds->ds_phys->ds_prev_snap_obj, snapname, 14431544Seschrock DS_MODE_NONE, ds, &ds->ds_prev)); 14444543Smarks 14454543Smarks spa_history_internal_log(LOG_DS_SNAPSHOT, dp->dp_spa, tx, cr, 1446*4603Sahrens "dataset = %llu", dsobj); 1447789Sahrens } 1448789Sahrens 1449789Sahrens void 14503547Smaybee dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx) 1451789Sahrens { 1452789Sahrens ASSERT(dmu_tx_is_syncing(tx)); 1453789Sahrens ASSERT(ds->ds_user_ptr != NULL); 1454789Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj == 0); 1455789Sahrens 1456789Sahrens dsl_dir_dirty(ds->ds_dir, tx); 14573547Smaybee dmu_objset_sync(ds->ds_user_ptr, zio, tx); 14583547Smaybee /* Unneeded? bplist_close(&ds->ds_deadlist); */ 1459789Sahrens } 1460789Sahrens 1461789Sahrens void 14622885Sahrens dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv) 1463789Sahrens { 14642885Sahrens dsl_dir_stats(ds->ds_dir, nv); 1465789Sahrens 14662885Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATION, 14672885Sahrens ds->ds_phys->ds_creation_time); 14682885Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_CREATETXG, 14692885Sahrens ds->ds_phys->ds_creation_txg); 14702885Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, 14712885Sahrens ds->ds_phys->ds_used_bytes); 1472789Sahrens 1473789Sahrens if (ds->ds_phys->ds_next_snap_obj) { 1474789Sahrens /* 1475789Sahrens * This is a snapshot; override the dd's space used with 14762885Sahrens * our unique space and compression ratio. 1477789Sahrens */ 14782885Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED, 14792885Sahrens ds->ds_phys->ds_unique_bytes); 14802885Sahrens dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, 14812885Sahrens ds->ds_phys->ds_compressed_bytes == 0 ? 100 : 14822885Sahrens (ds->ds_phys->ds_uncompressed_bytes * 100 / 14832885Sahrens ds->ds_phys->ds_compressed_bytes)); 1484789Sahrens } 1485789Sahrens } 1486789Sahrens 14872885Sahrens void 14882885Sahrens dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat) 1489789Sahrens { 14902885Sahrens stat->dds_creation_txg = ds->ds_phys->ds_creation_txg; 14912885Sahrens stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT; 14922885Sahrens if (ds->ds_phys->ds_next_snap_obj) { 14932885Sahrens stat->dds_is_snapshot = B_TRUE; 14942885Sahrens stat->dds_num_clones = ds->ds_phys->ds_num_children - 1; 14952885Sahrens } 14962885Sahrens 14972885Sahrens /* clone origin is really a dsl_dir thing... */ 14982885Sahrens if (ds->ds_dir->dd_phys->dd_clone_parent_obj) { 14992885Sahrens dsl_dataset_t *ods; 15002885Sahrens 15012885Sahrens rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER); 15022885Sahrens VERIFY(0 == dsl_dataset_open_obj(ds->ds_dir->dd_pool, 15032885Sahrens ds->ds_dir->dd_phys->dd_clone_parent_obj, 15042885Sahrens NULL, DS_MODE_NONE, FTAG, &ods)); 15052885Sahrens dsl_dataset_name(ods, stat->dds_clone_of); 15062885Sahrens dsl_dataset_close(ods, DS_MODE_NONE, FTAG); 15072885Sahrens rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock); 15082885Sahrens } 15092885Sahrens } 15102885Sahrens 15112885Sahrens uint64_t 15122885Sahrens dsl_dataset_fsid_guid(dsl_dataset_t *ds) 15132885Sahrens { 15142885Sahrens return (ds->ds_phys->ds_fsid_guid); 15152885Sahrens } 15162885Sahrens 15172885Sahrens void 15182885Sahrens dsl_dataset_space(dsl_dataset_t *ds, 15192885Sahrens uint64_t *refdbytesp, uint64_t *availbytesp, 15202885Sahrens uint64_t *usedobjsp, uint64_t *availobjsp) 15212885Sahrens { 15222885Sahrens *refdbytesp = ds->ds_phys->ds_used_bytes; 15232885Sahrens *availbytesp = dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE); 15242885Sahrens *usedobjsp = ds->ds_phys->ds_bp.blk_fill; 15252885Sahrens *availobjsp = DN_MAX_OBJECT - *usedobjsp; 1526789Sahrens } 1527789Sahrens 15282199Sahrens /* ARGSUSED */ 1529789Sahrens static int 15302199Sahrens dsl_dataset_snapshot_rename_check(void *arg1, void *arg2, dmu_tx_t *tx) 1531789Sahrens { 15322199Sahrens dsl_dataset_t *ds = arg1; 15332199Sahrens char *newsnapname = arg2; 15342199Sahrens dsl_dir_t *dd = ds->ds_dir; 1535789Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 15362199Sahrens dsl_dataset_t *hds; 15372199Sahrens uint64_t val; 1538789Sahrens int err; 1539789Sahrens 15402199Sahrens err = dsl_dataset_open_obj(dd->dd_pool, 15412199Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds); 1542789Sahrens if (err) 1543789Sahrens return (err); 1544789Sahrens 15452199Sahrens /* new name better not be in use */ 15462199Sahrens err = zap_lookup(mos, hds->ds_phys->ds_snapnames_zapobj, 15472199Sahrens newsnapname, 8, 1, &val); 15482199Sahrens dsl_dataset_close(hds, DS_MODE_NONE, FTAG); 1549789Sahrens 15502199Sahrens if (err == 0) 15512199Sahrens err = EEXIST; 15522199Sahrens else if (err == ENOENT) 15532199Sahrens err = 0; 15544007Smmusante 15554007Smmusante /* dataset name + 1 for the "@" + the new snapshot name must fit */ 15564007Smmusante if (dsl_dir_namelen(ds->ds_dir) + 1 + strlen(newsnapname) >= MAXNAMELEN) 15574007Smmusante err = ENAMETOOLONG; 15584007Smmusante 15592199Sahrens return (err); 15602199Sahrens } 1561789Sahrens 15622199Sahrens static void 15634543Smarks dsl_dataset_snapshot_rename_sync(void *arg1, void *arg2, 15644543Smarks cred_t *cr, dmu_tx_t *tx) 15652199Sahrens { 15662199Sahrens dsl_dataset_t *ds = arg1; 15674543Smarks const char *newsnapname = arg2; 15682199Sahrens dsl_dir_t *dd = ds->ds_dir; 15692199Sahrens objset_t *mos = dd->dd_pool->dp_meta_objset; 15702199Sahrens dsl_dataset_t *hds; 15712199Sahrens int err; 1572789Sahrens 15732199Sahrens ASSERT(ds->ds_phys->ds_next_snap_obj != 0); 1574789Sahrens 15752199Sahrens VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, 15762199Sahrens dd->dd_phys->dd_head_dataset_obj, NULL, DS_MODE_NONE, FTAG, &hds)); 1577789Sahrens 15782199Sahrens VERIFY(0 == dsl_dataset_get_snapname(ds)); 15792199Sahrens err = zap_remove(mos, hds->ds_phys->ds_snapnames_zapobj, 15802199Sahrens ds->ds_snapname, tx); 1581789Sahrens ASSERT3U(err, ==, 0); 15822199Sahrens mutex_enter(&ds->ds_lock); 15832199Sahrens (void) strcpy(ds->ds_snapname, newsnapname); 15842199Sahrens mutex_exit(&ds->ds_lock); 15852199Sahrens err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj, 15862199Sahrens ds->ds_snapname, 8, 1, &ds->ds_object, tx); 1587789Sahrens ASSERT3U(err, ==, 0); 1588789Sahrens 15894543Smarks spa_history_internal_log(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx, 15904543Smarks cr, "dataset = %llu", ds->ds_object); 15912199Sahrens dsl_dataset_close(hds, DS_MODE_NONE, FTAG); 1592789Sahrens } 1593789Sahrens 15944007Smmusante struct renamearg { 15954007Smmusante dsl_sync_task_group_t *dstg; 15964007Smmusante char failed[MAXPATHLEN]; 15974007Smmusante char *oldsnap; 15984007Smmusante char *newsnap; 15994007Smmusante }; 16004007Smmusante 16014007Smmusante static int 16024007Smmusante dsl_snapshot_rename_one(char *name, void *arg) 16034007Smmusante { 16044007Smmusante struct renamearg *ra = arg; 16054007Smmusante dsl_dataset_t *ds = NULL; 16064007Smmusante char *cp; 16074007Smmusante int err; 16084007Smmusante 16094007Smmusante cp = name + strlen(name); 16104007Smmusante *cp = '@'; 16114007Smmusante (void) strcpy(cp + 1, ra->oldsnap); 16124543Smarks 16134543Smarks /* 16144543Smarks * For recursive snapshot renames the parent won't be changing 16154543Smarks * so we just pass name for both the to/from argument. 16164543Smarks */ 16174543Smarks if (err = zfs_secpolicy_rename_perms(name, name, CRED())) { 16184543Smarks (void) strcpy(ra->failed, name); 16194543Smarks return (err); 16204543Smarks } 16214543Smarks 16224007Smmusante err = dsl_dataset_open(name, DS_MODE_READONLY | DS_MODE_STANDARD, 16234007Smmusante ra->dstg, &ds); 16244007Smmusante if (err == ENOENT) { 16254007Smmusante *cp = '\0'; 16264007Smmusante return (0); 16274007Smmusante } 16284007Smmusante if (err) { 16294007Smmusante (void) strcpy(ra->failed, name); 16304007Smmusante *cp = '\0'; 16314007Smmusante dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg); 16324007Smmusante return (err); 16334007Smmusante } 16344007Smmusante 16354007Smmusante #ifdef _KERNEL 16364007Smmusante /* for all filesystems undergoing rename, we'll need to unmount it */ 16374007Smmusante (void) zfs_unmount_snap(name, NULL); 16384007Smmusante #endif 16394007Smmusante 16404007Smmusante *cp = '\0'; 16414007Smmusante 16424007Smmusante dsl_sync_task_create(ra->dstg, dsl_dataset_snapshot_rename_check, 16434007Smmusante dsl_dataset_snapshot_rename_sync, ds, ra->newsnap, 0); 16444007Smmusante 16454007Smmusante return (0); 16464007Smmusante } 16474007Smmusante 16484007Smmusante static int 16494007Smmusante dsl_recursive_rename(char *oldname, const char *newname) 16504007Smmusante { 16514007Smmusante int err; 16524007Smmusante struct renamearg *ra; 16534007Smmusante dsl_sync_task_t *dst; 16544007Smmusante spa_t *spa; 16554007Smmusante char *cp, *fsname = spa_strdup(oldname); 16564007Smmusante int len = strlen(oldname); 16574007Smmusante 16584007Smmusante /* truncate the snapshot name to get the fsname */ 16594007Smmusante cp = strchr(fsname, '@'); 16604007Smmusante *cp = '\0'; 16614007Smmusante 1662*4603Sahrens err = spa_open(fsname, &spa, FTAG); 16634007Smmusante if (err) { 16644007Smmusante kmem_free(fsname, len + 1); 16654007Smmusante return (err); 16664007Smmusante } 16674007Smmusante ra = kmem_alloc(sizeof (struct renamearg), KM_SLEEP); 16684007Smmusante ra->dstg = dsl_sync_task_group_create(spa_get_dsl(spa)); 16694007Smmusante 16704007Smmusante ra->oldsnap = strchr(oldname, '@') + 1; 16714007Smmusante ra->newsnap = strchr(newname, '@') + 1; 16724007Smmusante *ra->failed = '\0'; 16734007Smmusante 16744007Smmusante err = dmu_objset_find(fsname, dsl_snapshot_rename_one, ra, 16754007Smmusante DS_FIND_CHILDREN); 16764007Smmusante kmem_free(fsname, len + 1); 16774007Smmusante 16784007Smmusante if (err == 0) { 16794007Smmusante err = dsl_sync_task_group_wait(ra->dstg); 16804007Smmusante } 16814007Smmusante 16824007Smmusante for (dst = list_head(&ra->dstg->dstg_tasks); dst; 16834007Smmusante dst = list_next(&ra->dstg->dstg_tasks, dst)) { 16844007Smmusante dsl_dataset_t *ds = dst->dst_arg1; 16854007Smmusante if (dst->dst_err) { 16864007Smmusante dsl_dir_name(ds->ds_dir, ra->failed); 16874009Smmusante (void) strcat(ra->failed, "@"); 16884009Smmusante (void) strcat(ra->failed, ra->newsnap); 16894007Smmusante } 16904007Smmusante dsl_dataset_close(ds, DS_MODE_STANDARD, ra->dstg); 16914007Smmusante } 16924007Smmusante 16934543Smarks if (err) 16944543Smarks (void) strcpy(oldname, ra->failed); 16954007Smmusante 16964007Smmusante dsl_sync_task_group_destroy(ra->dstg); 16974007Smmusante kmem_free(ra, sizeof (struct renamearg)); 16984007Smmusante spa_close(spa, FTAG); 16994007Smmusante return (err); 17004007Smmusante } 17014007Smmusante 17024569Smmusante static int 17034569Smmusante dsl_valid_rename(char *oldname, void *arg) 17044569Smmusante { 17054569Smmusante int delta = *(int *)arg; 17064569Smmusante 17074569Smmusante if (strlen(oldname) + delta >= MAXNAMELEN) 17084569Smmusante return (ENAMETOOLONG); 17094569Smmusante 17104569Smmusante return (0); 17114569Smmusante } 17124569Smmusante 1713789Sahrens #pragma weak dmu_objset_rename = dsl_dataset_rename 1714789Sahrens int 17154007Smmusante dsl_dataset_rename(char *oldname, const char *newname, 17164007Smmusante boolean_t recursive) 1717789Sahrens { 1718789Sahrens dsl_dir_t *dd; 17192199Sahrens dsl_dataset_t *ds; 1720789Sahrens const char *tail; 1721789Sahrens int err; 1722789Sahrens 17232199Sahrens err = dsl_dir_open(oldname, FTAG, &dd, &tail); 17241544Seschrock if (err) 17251544Seschrock return (err); 1726789Sahrens if (tail == NULL) { 17274569Smmusante int delta = strlen(newname) - strlen(oldname); 17284569Smmusante 17294569Smmusante /* if we're growing, validate child size lengths */ 17304569Smmusante if (delta > 0) 17314569Smmusante err = dmu_objset_find(oldname, dsl_valid_rename, 17324569Smmusante &delta, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS); 17334569Smmusante 17344569Smmusante if (!err) 17354569Smmusante err = dsl_dir_rename(dd, newname); 1736789Sahrens dsl_dir_close(dd, FTAG); 1737789Sahrens return (err); 1738789Sahrens } 1739789Sahrens if (tail[0] != '@') { 1740789Sahrens /* the name ended in a nonexistant component */ 1741789Sahrens dsl_dir_close(dd, FTAG); 1742789Sahrens return (ENOENT); 1743789Sahrens } 1744789Sahrens 17452199Sahrens dsl_dir_close(dd, FTAG); 17462199Sahrens 17472199Sahrens /* new name must be snapshot in same filesystem */ 17482199Sahrens tail = strchr(newname, '@'); 17492199Sahrens if (tail == NULL) 17502199Sahrens return (EINVAL); 17512199Sahrens tail++; 17522199Sahrens if (strncmp(oldname, newname, tail - newname) != 0) 17532199Sahrens return (EXDEV); 1754789Sahrens 17554007Smmusante if (recursive) { 17564007Smmusante err = dsl_recursive_rename(oldname, newname); 17574007Smmusante } else { 17584007Smmusante err = dsl_dataset_open(oldname, 17594007Smmusante DS_MODE_READONLY | DS_MODE_STANDARD, FTAG, &ds); 17604007Smmusante if (err) 17614007Smmusante return (err); 17622199Sahrens 17634007Smmusante err = dsl_sync_task_do(ds->ds_dir->dd_pool, 17644007Smmusante dsl_dataset_snapshot_rename_check, 17654007Smmusante dsl_dataset_snapshot_rename_sync, ds, (char *)tail, 1); 17662199Sahrens 17674007Smmusante dsl_dataset_close(ds, DS_MODE_STANDARD, FTAG); 17684007Smmusante } 17692199Sahrens 1770789Sahrens return (err); 1771789Sahrens } 17722082Seschrock 17732199Sahrens struct promotearg { 17742199Sahrens uint64_t used, comp, uncomp, unique; 17752199Sahrens uint64_t newnext_obj, snapnames_obj; 17762199Sahrens }; 17772199Sahrens 17784543Smarks /* ARGSUSED */ 17792082Seschrock static int 17802199Sahrens dsl_dataset_promote_check(void *arg1, void *arg2, dmu_tx_t *tx) 17812082Seschrock { 17822199Sahrens dsl_dataset_t *hds = arg1; 17832199Sahrens struct promotearg *pa = arg2; 17842199Sahrens dsl_dir_t *dd = hds->ds_dir; 17852199Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 17862082Seschrock dsl_dir_t *pdd = NULL; 17872082Seschrock dsl_dataset_t *ds = NULL; 17882082Seschrock dsl_dataset_t *pivot_ds = NULL; 17892082Seschrock dsl_dataset_t *newnext_ds = NULL; 17902082Seschrock int err; 17912082Seschrock char *name = NULL; 17922199Sahrens uint64_t itor = 0; 17932082Seschrock blkptr_t bp; 17942082Seschrock 17952199Sahrens bzero(pa, sizeof (*pa)); 17962199Sahrens 17972082Seschrock /* Check that it is a clone */ 17982082Seschrock if (dd->dd_phys->dd_clone_parent_obj == 0) 17992082Seschrock return (EINVAL); 18002082Seschrock 18012199Sahrens /* Since this is so expensive, don't do the preliminary check */ 18022199Sahrens if (!dmu_tx_is_syncing(tx)) 18032199Sahrens return (0); 18042199Sahrens 18052199Sahrens if (err = dsl_dataset_open_obj(dp, 18062082Seschrock dd->dd_phys->dd_clone_parent_obj, 18072082Seschrock NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)) 18082082Seschrock goto out; 18092082Seschrock pdd = pivot_ds->ds_dir; 18102199Sahrens 18112199Sahrens { 18122199Sahrens dsl_dataset_t *phds; 18132199Sahrens if (err = dsl_dataset_open_obj(dd->dd_pool, 18142199Sahrens pdd->dd_phys->dd_head_dataset_obj, 18152199Sahrens NULL, DS_MODE_NONE, FTAG, &phds)) 18162199Sahrens goto out; 18172199Sahrens pa->snapnames_obj = phds->ds_phys->ds_snapnames_zapobj; 18182199Sahrens dsl_dataset_close(phds, DS_MODE_NONE, FTAG); 18192199Sahrens } 18202082Seschrock 18212082Seschrock if (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE) { 18222082Seschrock err = EXDEV; 18232082Seschrock goto out; 18242082Seschrock } 18252082Seschrock 18262082Seschrock /* find pivot point's new next ds */ 18272082Seschrock VERIFY(0 == dsl_dataset_open_obj(dd->dd_pool, hds->ds_object, 18282082Seschrock NULL, DS_MODE_NONE, FTAG, &newnext_ds)); 18292082Seschrock while (newnext_ds->ds_phys->ds_prev_snap_obj != pivot_ds->ds_object) { 18302082Seschrock dsl_dataset_t *prev; 18312082Seschrock 18322082Seschrock if (err = dsl_dataset_open_obj(dd->dd_pool, 18332199Sahrens newnext_ds->ds_phys->ds_prev_snap_obj, 18342199Sahrens NULL, DS_MODE_NONE, FTAG, &prev)) 18352082Seschrock goto out; 18362082Seschrock dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); 18372082Seschrock newnext_ds = prev; 18382082Seschrock } 18392199Sahrens pa->newnext_obj = newnext_ds->ds_object; 18402082Seschrock 18412082Seschrock /* compute pivot point's new unique space */ 18422082Seschrock while ((err = bplist_iterate(&newnext_ds->ds_deadlist, 18432082Seschrock &itor, &bp)) == 0) { 18442082Seschrock if (bp.blk_birth > pivot_ds->ds_phys->ds_prev_snap_txg) 18452199Sahrens pa->unique += bp_get_dasize(dd->dd_pool->dp_spa, &bp); 18462082Seschrock } 18472082Seschrock if (err != ENOENT) 18482082Seschrock goto out; 18492082Seschrock 18502082Seschrock /* Walk the snapshots that we are moving */ 18512082Seschrock name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 18522082Seschrock ds = pivot_ds; 18532082Seschrock /* CONSTCOND */ 18542082Seschrock while (TRUE) { 18552082Seschrock uint64_t val, dlused, dlcomp, dluncomp; 18562082Seschrock dsl_dataset_t *prev; 18572082Seschrock 18582082Seschrock /* Check that the snapshot name does not conflict */ 18592082Seschrock dsl_dataset_name(ds, name); 18602082Seschrock err = zap_lookup(dd->dd_pool->dp_meta_objset, 18612082Seschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 18622082Seschrock 8, 1, &val); 18632082Seschrock if (err != ENOENT) { 18642082Seschrock if (err == 0) 18652082Seschrock err = EEXIST; 18662082Seschrock goto out; 18672082Seschrock } 18682082Seschrock 18692082Seschrock /* 18702082Seschrock * compute space to transfer. Each snapshot gave birth to: 18712082Seschrock * (my used) - (prev's used) + (deadlist's used) 18722082Seschrock */ 18732199Sahrens pa->used += ds->ds_phys->ds_used_bytes; 18742199Sahrens pa->comp += ds->ds_phys->ds_compressed_bytes; 18752199Sahrens pa->uncomp += ds->ds_phys->ds_uncompressed_bytes; 18762082Seschrock 18772082Seschrock /* If we reach the first snapshot, we're done. */ 18782082Seschrock if (ds->ds_phys->ds_prev_snap_obj == 0) 18792082Seschrock break; 18802082Seschrock 18812082Seschrock if (err = bplist_space(&ds->ds_deadlist, 18822082Seschrock &dlused, &dlcomp, &dluncomp)) 18832082Seschrock goto out; 18842082Seschrock if (err = dsl_dataset_open_obj(dd->dd_pool, 18852082Seschrock ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, 18862082Seschrock FTAG, &prev)) 18872082Seschrock goto out; 18882199Sahrens pa->used += dlused - prev->ds_phys->ds_used_bytes; 18892199Sahrens pa->comp += dlcomp - prev->ds_phys->ds_compressed_bytes; 18902199Sahrens pa->uncomp += dluncomp - prev->ds_phys->ds_uncompressed_bytes; 18912082Seschrock 18922082Seschrock /* 18932082Seschrock * We could be a clone of a clone. If we reach our 18942082Seschrock * parent's branch point, we're done. 18952082Seschrock */ 18962082Seschrock if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { 18972082Seschrock dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); 18982082Seschrock break; 18992082Seschrock } 19002082Seschrock if (ds != pivot_ds) 19012082Seschrock dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 19022082Seschrock ds = prev; 19032082Seschrock } 19042082Seschrock 19052082Seschrock /* Check that there is enough space here */ 19062199Sahrens err = dsl_dir_transfer_possible(pdd, dd, pa->used); 19072199Sahrens 19082199Sahrens out: 19092199Sahrens if (ds && ds != pivot_ds) 19102199Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 19112199Sahrens if (pivot_ds) 19122199Sahrens dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); 19132199Sahrens if (newnext_ds) 19142199Sahrens dsl_dataset_close(newnext_ds, DS_MODE_NONE, FTAG); 19152199Sahrens if (name) 19162199Sahrens kmem_free(name, MAXPATHLEN); 19172199Sahrens return (err); 19182199Sahrens } 19192082Seschrock 19202199Sahrens static void 19214543Smarks dsl_dataset_promote_sync(void *arg1, void *arg2, cred_t *cr, dmu_tx_t *tx) 19222199Sahrens { 19232199Sahrens dsl_dataset_t *hds = arg1; 19242199Sahrens struct promotearg *pa = arg2; 19252199Sahrens dsl_dir_t *dd = hds->ds_dir; 19262199Sahrens dsl_pool_t *dp = hds->ds_dir->dd_pool; 19272199Sahrens dsl_dir_t *pdd = NULL; 19282199Sahrens dsl_dataset_t *ds, *pivot_ds; 19292199Sahrens char *name; 19302199Sahrens 19312199Sahrens ASSERT(dd->dd_phys->dd_clone_parent_obj != 0); 19322199Sahrens ASSERT(0 == (hds->ds_phys->ds_flags & DS_FLAG_NOPROMOTE)); 19332199Sahrens 19342199Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 19352199Sahrens dd->dd_phys->dd_clone_parent_obj, 19362199Sahrens NULL, DS_MODE_EXCLUSIVE, FTAG, &pivot_ds)); 19372417Sahrens /* 19382417Sahrens * We need to explicitly open pdd, since pivot_ds's pdd will be 19392417Sahrens * changing. 19402417Sahrens */ 19412417Sahrens VERIFY(0 == dsl_dir_open_obj(dp, pivot_ds->ds_dir->dd_object, 19422417Sahrens NULL, FTAG, &pdd)); 19432082Seschrock 19442082Seschrock /* move snapshots to this dir */ 19452199Sahrens name = kmem_alloc(MAXPATHLEN, KM_SLEEP); 19462082Seschrock ds = pivot_ds; 19472082Seschrock /* CONSTCOND */ 19482082Seschrock while (TRUE) { 19492082Seschrock dsl_dataset_t *prev; 19502082Seschrock 19512082Seschrock /* move snap name entry */ 19522082Seschrock dsl_dataset_name(ds, name); 19532199Sahrens VERIFY(0 == zap_remove(dp->dp_meta_objset, 19542199Sahrens pa->snapnames_obj, ds->ds_snapname, tx)); 19552199Sahrens VERIFY(0 == zap_add(dp->dp_meta_objset, 19562082Seschrock hds->ds_phys->ds_snapnames_zapobj, ds->ds_snapname, 19572082Seschrock 8, 1, &ds->ds_object, tx)); 19582082Seschrock 19592082Seschrock /* change containing dsl_dir */ 19602082Seschrock dmu_buf_will_dirty(ds->ds_dbuf, tx); 19612082Seschrock ASSERT3U(ds->ds_phys->ds_dir_obj, ==, pdd->dd_object); 19622082Seschrock ds->ds_phys->ds_dir_obj = dd->dd_object; 19632082Seschrock ASSERT3P(ds->ds_dir, ==, pdd); 19642082Seschrock dsl_dir_close(ds->ds_dir, ds); 19652199Sahrens VERIFY(0 == dsl_dir_open_obj(dp, dd->dd_object, 19662082Seschrock NULL, ds, &ds->ds_dir)); 19672082Seschrock 19682082Seschrock ASSERT3U(dsl_prop_numcb(ds), ==, 0); 19692082Seschrock 19702082Seschrock if (ds->ds_phys->ds_prev_snap_obj == 0) 19712082Seschrock break; 19722082Seschrock 19732199Sahrens VERIFY(0 == dsl_dataset_open_obj(dp, 19742082Seschrock ds->ds_phys->ds_prev_snap_obj, NULL, DS_MODE_EXCLUSIVE, 19752082Seschrock FTAG, &prev)); 19762082Seschrock 19772082Seschrock if (prev->ds_phys->ds_next_snap_obj != ds->ds_object) { 19782082Seschrock dsl_dataset_close(prev, DS_MODE_EXCLUSIVE, FTAG); 19792082Seschrock break; 19802082Seschrock } 19812082Seschrock if (ds != pivot_ds) 19822082Seschrock dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 19832082Seschrock ds = prev; 19842082Seschrock } 19852199Sahrens if (ds != pivot_ds) 19862199Sahrens dsl_dataset_close(ds, DS_MODE_EXCLUSIVE, FTAG); 19872082Seschrock 19882082Seschrock /* change pivot point's next snap */ 19892082Seschrock dmu_buf_will_dirty(pivot_ds->ds_dbuf, tx); 19902199Sahrens pivot_ds->ds_phys->ds_next_snap_obj = pa->newnext_obj; 19912082Seschrock 19922082Seschrock /* change clone_parent-age */ 19932082Seschrock dmu_buf_will_dirty(dd->dd_dbuf, tx); 19942082Seschrock ASSERT3U(dd->dd_phys->dd_clone_parent_obj, ==, pivot_ds->ds_object); 19952082Seschrock dd->dd_phys->dd_clone_parent_obj = pdd->dd_phys->dd_clone_parent_obj; 19962082Seschrock dmu_buf_will_dirty(pdd->dd_dbuf, tx); 19972082Seschrock pdd->dd_phys->dd_clone_parent_obj = pivot_ds->ds_object; 19982082Seschrock 19992082Seschrock /* change space accounting */ 20002199Sahrens dsl_dir_diduse_space(pdd, -pa->used, -pa->comp, -pa->uncomp, tx); 20012199Sahrens dsl_dir_diduse_space(dd, pa->used, pa->comp, pa->uncomp, tx); 20022199Sahrens pivot_ds->ds_phys->ds_unique_bytes = pa->unique; 20032082Seschrock 20044543Smarks /* log history record */ 20054543Smarks spa_history_internal_log(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx, 20064543Smarks cr, "dataset = %llu", ds->ds_object); 20074543Smarks 20082417Sahrens dsl_dir_close(pdd, FTAG); 20092199Sahrens dsl_dataset_close(pivot_ds, DS_MODE_EXCLUSIVE, FTAG); 20102199Sahrens kmem_free(name, MAXPATHLEN); 20112082Seschrock } 20122082Seschrock 20132082Seschrock int 20142082Seschrock dsl_dataset_promote(const char *name) 20152082Seschrock { 20162082Seschrock dsl_dataset_t *ds; 20172082Seschrock int err; 20182082Seschrock dmu_object_info_t doi; 20192199Sahrens struct promotearg pa; 20202082Seschrock 20212082Seschrock err = dsl_dataset_open(name, DS_MODE_NONE, FTAG, &ds); 20222082Seschrock if (err) 20232082Seschrock return (err); 20242082Seschrock 20252082Seschrock err = dmu_object_info(ds->ds_dir->dd_pool->dp_meta_objset, 20262082Seschrock ds->ds_phys->ds_snapnames_zapobj, &doi); 20272082Seschrock if (err) { 20282082Seschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 20292082Seschrock return (err); 20302082Seschrock } 20312082Seschrock 20322082Seschrock /* 20332082Seschrock * Add in 128x the snapnames zapobj size, since we will be moving 20342082Seschrock * a bunch of snapnames to the promoted ds, and dirtying their 20352082Seschrock * bonus buffers. 20362082Seschrock */ 20372199Sahrens err = dsl_sync_task_do(ds->ds_dir->dd_pool, 20382199Sahrens dsl_dataset_promote_check, 20392199Sahrens dsl_dataset_promote_sync, ds, &pa, 2 + 2 * doi.doi_physical_blks); 20402082Seschrock dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 20412082Seschrock return (err); 20422082Seschrock } 20433912Slling 20443912Slling /* 20453912Slling * Given a pool name and a dataset object number in that pool, 20463912Slling * return the name of that dataset. 20473912Slling */ 20483912Slling int 20493912Slling dsl_dsobj_to_dsname(char *pname, uint64_t obj, char *buf) 20503912Slling { 20513912Slling spa_t *spa; 20523912Slling dsl_pool_t *dp; 20533912Slling dsl_dataset_t *ds = NULL; 20543912Slling int error; 20553912Slling 20563912Slling if ((error = spa_open(pname, &spa, FTAG)) != 0) 20573912Slling return (error); 20583912Slling dp = spa_get_dsl(spa); 20593912Slling rw_enter(&dp->dp_config_rwlock, RW_READER); 20603912Slling if ((error = dsl_dataset_open_obj(dp, obj, 20613912Slling NULL, DS_MODE_NONE, FTAG, &ds)) != 0) { 20623912Slling rw_exit(&dp->dp_config_rwlock); 20633912Slling spa_close(spa, FTAG); 20643912Slling return (error); 20653912Slling } 20663912Slling dsl_dataset_name(ds, buf); 20673912Slling dsl_dataset_close(ds, DS_MODE_NONE, FTAG); 20683912Slling rw_exit(&dp->dp_config_rwlock); 20693912Slling spa_close(spa, FTAG); 20703912Slling 20713912Slling return (0); 20723912Slling } 2073