Deleted Added
full compact
25a26
> * Portions Copyright 2011 Martin Matuska <mm@FreeBSd.org>
910a912,913
> #ifdef __FreeBSD__
> /* FreeBSD ioctl compat begin */
912,915c915,916
< dsl_sync_task_group_t *dstg;
< char *snapname;
< char *failed;
< boolean_t defer;
---
> nvlist_t *nvl;
> const char *snapname;
919c920
< dsl_snapshot_destroy_one(const char *name, void *arg)
---
> dsl_check_snap_cb(const char *name, void *arg)
923d923
< int err;
927,930c927
< err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds);
< strfree(dsname);
< if (err == 0) {
< struct dsl_ds_destroyarg *dsda;
---
> VERIFY(nvlist_add_boolean(da->nvl, dsname) == 0);
932,942c929,945
< dsl_dataset_make_exclusive(ds, da->dstg);
< dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg), KM_SLEEP);
< dsda->ds = ds;
< dsda->defer = da->defer;
< dsl_sync_task_create(da->dstg, dsl_dataset_destroy_check,
< dsl_dataset_destroy_sync, dsda, da->dstg, 0);
< } else if (err == ENOENT) {
< err = 0;
< } else {
< (void) strcpy(da->failed, name);
< }
---
> return (0);
> }
>
> int
> dmu_get_recursive_snaps_nvl(const char *fsname, const char *snapname,
> nvlist_t *snaps)
> {
> struct destroyarg *da;
> int err;
>
> da = kmem_zalloc(sizeof (struct destroyarg), KM_SLEEP);
> da->nvl = snaps;
> da->snapname = snapname;
> err = dmu_objset_find(fsname, dsl_check_snap_cb, da,
> DS_FIND_CHILDREN);
> kmem_free(da, sizeof (struct destroyarg));
>
944a948,949
> /* FreeBSD ioctl compat end */
> #endif /* __FreeBSD__ */
947c952
< * Destroy 'snapname' in all descendants of 'fsname'.
---
> * The snapshots must all be in the same pool.
949d953
< #pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy
951c955
< dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer)
---
> dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed)
954d957
< struct destroyarg da;
956a960,961
> nvpair_t *pair;
> dsl_sync_task_group_t *dstg;
958c963,967
< err = spa_open(fsname, &spa, FTAG);
---
> pair = nvlist_next_nvpair(snaps, NULL);
> if (pair == NULL)
> return (0);
>
> err = spa_open(nvpair_name(pair), &spa, FTAG);
961,964c970
< da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
< da.snapname = snapname;
< da.failed = fsname;
< da.defer = defer;
---
> dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
966,967c972,975
< err = dmu_objset_find(fsname,
< dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN);
---
> for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
> pair = nvlist_next_nvpair(snaps, pair)) {
> dsl_dataset_t *ds;
> int err;
968a977,995
> err = dsl_dataset_own(nvpair_name(pair), B_TRUE, dstg, &ds);
> if (err == 0) {
> struct dsl_ds_destroyarg *dsda;
>
> dsl_dataset_make_exclusive(ds, dstg);
> dsda = kmem_zalloc(sizeof (struct dsl_ds_destroyarg),
> KM_SLEEP);
> dsda->ds = ds;
> dsda->defer = defer;
> dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
> dsl_dataset_destroy_sync, dsda, dstg, 0);
> } else if (err == ENOENT) {
> err = 0;
> } else {
> (void) strcpy(failed, nvpair_name(pair));
> break;
> }
> }
>
970c997
< err = dsl_sync_task_group_wait(da.dstg);
---
> err = dsl_sync_task_group_wait(dstg);
972,973c999,1000
< for (dst = list_head(&da.dstg->dstg_tasks); dst;
< dst = list_next(&da.dstg->dstg_tasks, dst)) {
---
> for (dst = list_head(&dstg->dstg_tasks); dst;
> dst = list_next(&dstg->dstg_tasks, dst)) {
981,982c1008
< dsl_dataset_name(ds, fsname);
< *strchr(fsname, '@') = '\0';
---
> dsl_dataset_name(ds, failed);
985c1011
< dsl_dataset_disown(ds, da.dstg);
---
> dsl_dataset_disown(ds, dstg);
989c1015
< dsl_sync_task_group_destroy(da.dstg);
---
> dsl_sync_task_group_destroy(dstg);
991a1018
>
2152a2180,2228
> static void
> get_clones_stat(dsl_dataset_t *ds, nvlist_t *nv)
> {
> uint64_t count = 0;
> objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
> zap_cursor_t zc;
> zap_attribute_t za;
> nvlist_t *propval;
> nvlist_t *val;
>
> rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
> VERIFY(nvlist_alloc(&propval, NV_UNIQUE_NAME, KM_SLEEP) == 0);
> VERIFY(nvlist_alloc(&val, NV_UNIQUE_NAME, KM_SLEEP) == 0);
>
> /*
> * There may me missing entries in ds_next_clones_obj
> * due to a bug in a previous version of the code.
> * Only trust it if it has the right number of entries.
> */
> if (ds->ds_phys->ds_next_clones_obj != 0) {
> ASSERT3U(0, ==, zap_count(mos, ds->ds_phys->ds_next_clones_obj,
> &count));
> }
> if (count != ds->ds_phys->ds_num_children - 1) {
> goto fail;
> }
> for (zap_cursor_init(&zc, mos, ds->ds_phys->ds_next_clones_obj);
> zap_cursor_retrieve(&zc, &za) == 0;
> zap_cursor_advance(&zc)) {
> dsl_dataset_t *clone;
> char buf[ZFS_MAXNAMELEN];
> if (dsl_dataset_hold_obj(ds->ds_dir->dd_pool,
> za.za_first_integer, FTAG, &clone) != 0) {
> goto fail;
> }
> dsl_dir_name(clone->ds_dir, buf);
> VERIFY(nvlist_add_boolean(val, buf) == 0);
> dsl_dataset_rele(clone, FTAG);
> }
> zap_cursor_fini(&zc);
> VERIFY(nvlist_add_nvlist(propval, ZPROP_VALUE, val) == 0);
> VERIFY(nvlist_add_nvlist(nv, zfs_prop_to_name(ZFS_PROP_CLONES),
> propval) == 0);
> fail:
> nvlist_free(val);
> nvlist_free(propval);
> rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
> }
>
2182a2259,2278
> if (ds->ds_phys->ds_prev_snap_obj != 0) {
> uint64_t written, comp, uncomp;
> dsl_pool_t *dp = ds->ds_dir->dd_pool;
> dsl_dataset_t *prev;
>
> rw_enter(&dp->dp_config_rwlock, RW_READER);
> int err = dsl_dataset_hold_obj(dp,
> ds->ds_phys->ds_prev_snap_obj, FTAG, &prev);
> rw_exit(&dp->dp_config_rwlock);
> if (err == 0) {
> err = dsl_dataset_space_written(prev, ds, &written,
> &comp, &uncomp);
> dsl_dataset_rele(prev, FTAG);
> if (err == 0) {
> dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_WRITTEN,
> written);
> }
> }
> }
>
2195a2292,2293
>
> get_clones_stat(ds, nv);
4028c4126
< * Note, this fuction is used as the callback for dmu_objset_find(). We
---
> * Note, this function is used as the callback for dmu_objset_find(). We
4046a4145,4292
>
> /*
> * Return (in *usedp) the amount of space written in new that is not
> * present in oldsnap. New may be a snapshot or the head. Old must be
> * a snapshot before new, in new's filesystem (or its origin). If not then
> * fail and return EINVAL.
> *
> * The written space is calculated by considering two components: First, we
> * ignore any freed space, and calculate the written as new's used space
> * minus old's used space. Next, we add in the amount of space that was freed
> * between the two snapshots, thus reducing new's used space relative to old's.
> * Specifically, this is the space that was born before old->ds_creation_txg,
> * and freed before new (ie. on new's deadlist or a previous deadlist).
> *
> * space freed [---------------------]
> * snapshots ---O-------O--------O-------O------
> * oldsnap new
> */
> int
> dsl_dataset_space_written(dsl_dataset_t *oldsnap, dsl_dataset_t *new,
> uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
> {
> int err = 0;
> uint64_t snapobj;
> dsl_pool_t *dp = new->ds_dir->dd_pool;
>
> *usedp = 0;
> *usedp += new->ds_phys->ds_used_bytes;
> *usedp -= oldsnap->ds_phys->ds_used_bytes;
>
> *compp = 0;
> *compp += new->ds_phys->ds_compressed_bytes;
> *compp -= oldsnap->ds_phys->ds_compressed_bytes;
>
> *uncompp = 0;
> *uncompp += new->ds_phys->ds_uncompressed_bytes;
> *uncompp -= oldsnap->ds_phys->ds_uncompressed_bytes;
>
> rw_enter(&dp->dp_config_rwlock, RW_READER);
> snapobj = new->ds_object;
> while (snapobj != oldsnap->ds_object) {
> dsl_dataset_t *snap;
> uint64_t used, comp, uncomp;
>
> err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &snap);
> if (err != 0)
> break;
>
> if (snap->ds_phys->ds_prev_snap_txg ==
> oldsnap->ds_phys->ds_creation_txg) {
> /*
> * The blocks in the deadlist can not be born after
> * ds_prev_snap_txg, so get the whole deadlist space,
> * which is more efficient (especially for old-format
> * deadlists). Unfortunately the deadlist code
> * doesn't have enough information to make this
> * optimization itself.
> */
> dsl_deadlist_space(&snap->ds_deadlist,
> &used, &comp, &uncomp);
> } else {
> dsl_deadlist_space_range(&snap->ds_deadlist,
> 0, oldsnap->ds_phys->ds_creation_txg,
> &used, &comp, &uncomp);
> }
> *usedp += used;
> *compp += comp;
> *uncompp += uncomp;
>
> /*
> * If we get to the beginning of the chain of snapshots
> * (ds_prev_snap_obj == 0) before oldsnap, then oldsnap
> * was not a snapshot of/before new.
> */
> snapobj = snap->ds_phys->ds_prev_snap_obj;
> dsl_dataset_rele(snap, FTAG);
> if (snapobj == 0) {
> err = EINVAL;
> break;
> }
>
> }
> rw_exit(&dp->dp_config_rwlock);
> return (err);
> }
>
> /*
> * Return (in *usedp) the amount of space that will be reclaimed if firstsnap,
> * lastsnap, and all snapshots in between are deleted.
> *
> * blocks that would be freed [---------------------------]
> * snapshots ---O-------O--------O-------O--------O
> * firstsnap lastsnap
> *
> * This is the set of blocks that were born after the snap before firstsnap,
> * (birth > firstsnap->prev_snap_txg) and died before the snap after the
> * last snap (ie, is on lastsnap->ds_next->ds_deadlist or an earlier deadlist).
> * We calculate this by iterating over the relevant deadlists (from the snap
> * after lastsnap, backward to the snap after firstsnap), summing up the
> * space on the deadlist that was born after the snap before firstsnap.
> */
> int
> dsl_dataset_space_wouldfree(dsl_dataset_t *firstsnap,
> dsl_dataset_t *lastsnap,
> uint64_t *usedp, uint64_t *compp, uint64_t *uncompp)
> {
> int err = 0;
> uint64_t snapobj;
> dsl_pool_t *dp = firstsnap->ds_dir->dd_pool;
>
> ASSERT(dsl_dataset_is_snapshot(firstsnap));
> ASSERT(dsl_dataset_is_snapshot(lastsnap));
>
> /*
> * Check that the snapshots are in the same dsl_dir, and firstsnap
> * is before lastsnap.
> */
> if (firstsnap->ds_dir != lastsnap->ds_dir ||
> firstsnap->ds_phys->ds_creation_txg >
> lastsnap->ds_phys->ds_creation_txg)
> return (EINVAL);
>
> *usedp = *compp = *uncompp = 0;
>
> rw_enter(&dp->dp_config_rwlock, RW_READER);
> snapobj = lastsnap->ds_phys->ds_next_snap_obj;
> while (snapobj != firstsnap->ds_object) {
> dsl_dataset_t *ds;
> uint64_t used, comp, uncomp;
>
> err = dsl_dataset_hold_obj(dp, snapobj, FTAG, &ds);
> if (err != 0)
> break;
>
> dsl_deadlist_space_range(&ds->ds_deadlist,
> firstsnap->ds_phys->ds_prev_snap_txg, UINT64_MAX,
> &used, &comp, &uncomp);
> *usedp += used;
> *compp += comp;
> *uncompp += uncomp;
>
> snapobj = ds->ds_phys->ds_prev_snap_obj;
> ASSERT3U(snapobj, !=, 0);
> dsl_dataset_rele(ds, FTAG);
> }
> rw_exit(&dp->dp_config_rwlock);
> return (err);
> }