--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c Tue Nov 08 16:22:36 2011 -0500
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c Tue Nov 08 17:01:06 2011 -0500
@@ -902,56 +902,69 @@
return (dsobj);
}
+struct destroyarg {
+ dsl_sync_task_group_t *dstg;
+ char *snapname;
+ char *failed;
+ boolean_t defer;
+};
+
+static int
+dsl_snapshot_destroy_one(const char *name, void *arg)
+{
+ struct destroyarg *da = arg;
+ dsl_dataset_t *ds;
+ int err;
+ char *dsname;
+
+ dsname = kmem_asprintf("%s@%s", name, da->snapname);
+ err = dsl_dataset_own(dsname, B_TRUE, da->dstg, &ds);
+ strfree(dsname);
+ if (err == 0) {
+ struct dsl_ds_destroyarg *dsda;
+
+ 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 (err);
+}
+
/*
- * The snapshots must all be in the same pool.
+ * Destroy 'snapname' in all descendants of 'fsname'.
*/
+#pragma weak dmu_snapshots_destroy = dsl_snapshots_destroy
int
-dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed)
+dsl_snapshots_destroy(char *fsname, char *snapname, boolean_t defer)
{
int err;
+ struct destroyarg da;
dsl_sync_task_t *dst;
spa_t *spa;
- nvpair_t *pair;
- dsl_sync_task_group_t *dstg;
-
- pair = nvlist_next_nvpair(snaps, NULL);
- if (pair == NULL)
- return (0);
-
- err = spa_open(nvpair_name(pair), &spa, FTAG);
+
+ err = spa_open(fsname, &spa, FTAG);
if (err)
return (err);
- dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
-
- for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
- pair = nvlist_next_nvpair(snaps, pair)) {
- dsl_dataset_t *ds;
- int err;
-
- 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;
- }
- }
+ da.dstg = dsl_sync_task_group_create(spa_get_dsl(spa));
+ da.snapname = snapname;
+ da.failed = fsname;
+ da.defer = defer;
+
+ err = dmu_objset_find(fsname,
+ dsl_snapshot_destroy_one, &da, DS_FIND_CHILDREN);
if (err == 0)
- err = dsl_sync_task_group_wait(dstg);
-
- for (dst = list_head(&dstg->dstg_tasks); dst;
- dst = list_next(&dstg->dstg_tasks, dst)) {
+ err = dsl_sync_task_group_wait(da.dstg);
+
+ for (dst = list_head(&da.dstg->dstg_tasks); dst;
+ dst = list_next(&da.dstg->dstg_tasks, dst)) {
struct dsl_ds_destroyarg *dsda = dst->dst_arg1;
dsl_dataset_t *ds = dsda->ds;
@@ -959,17 +972,17 @@
* Return the file system name that triggered the error
*/
if (dst->dst_err) {
- dsl_dataset_name(ds, failed);
+ dsl_dataset_name(ds, fsname);
+ *strchr(fsname, '@') = '\0';
}
ASSERT3P(dsda->rm_origin, ==, NULL);
- dsl_dataset_disown(ds, dstg);
+ dsl_dataset_disown(ds, da.dstg);
kmem_free(dsda, sizeof (struct dsl_ds_destroyarg));
}
- dsl_sync_task_group_destroy(dstg);
+ dsl_sync_task_group_destroy(da.dstg);
spa_close(spa, FTAG);
return (err);
-
}
static boolean_t
@@ -2130,55 +2143,6 @@
dmu_objset_sync(ds->ds_objset, zio, tx);
}
-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);
-}
-
void
dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
{
@@ -2209,26 +2173,6 @@
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_DEFER_DESTROY,
DS_IS_DEFER_DESTROY(ds) ? 1 : 0);
- 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);
- }
- }
- }
-
ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
(ds->ds_phys->ds_uncompressed_bytes * 100 /
ds->ds_phys->ds_compressed_bytes);
@@ -2242,8 +2186,6 @@
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
ds->ds_phys->ds_unique_bytes);
dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
-
- get_clones_stat(ds, nv);
}
}
@@ -4070,7 +4012,7 @@
}
/*
- * Note, this function is used as the callback for dmu_objset_find(). We
+ * Note, this fuction is used as the callback for dmu_objset_find(). We
* always return 0 so that we will continue to find and process
* inconsistent datasets, even if we encounter an error trying to
* process one of them.
@@ -4089,151 +4031,3 @@
}
return (0);
}
-
-/*
- * 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);
-}