Print this page
2882 implement libzfs_core
2883 changing "canmount" property to "on" should not always remount dataset
2900 "zfs snapshot" should be able to create multiple, arbitrary snapshots at once
Reviewed by: George Wilson <george.wilson@delphix.com>
Reviewed by: Chris Siden <christopher.siden@delphix.com>
Reviewed by: Garrett D'Amore <garrett@damore.org>
Reviewed by: Bill Pijewski <wdp@joyent.com>
Reviewed by: Dan Kruchinin <dan.kruchinin@gmail.com>

@@ -912,11 +912,12 @@
 
 /*
  * The snapshots must all be in the same pool.
  */
 int
-dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer, char *failed)
+dmu_snapshots_destroy_nvl(nvlist_t *snaps, boolean_t defer,
+    nvlist_t *errlist)
 {
         int err;
         dsl_sync_task_t *dst;
         spa_t *spa;
         nvpair_t *pair;

@@ -947,11 +948,11 @@
                         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));
+                        fnvlist_add_int32(errlist, nvpair_name(pair), err);
                         break;
                 }
         }
 
         if (err == 0)

@@ -961,14 +962,16 @@
             dst = list_next(&dstg->dstg_tasks, dst)) {
                 struct dsl_ds_destroyarg *dsda = dst->dst_arg1;
                 dsl_dataset_t *ds = dsda->ds;
 
                 /*
-                 * Return the file system name that triggered the error
+                 * Return the snapshots that triggered the error.
                  */
-                if (dst->dst_err) {
-                        dsl_dataset_name(ds, failed);
+                if (dst->dst_err != 0) {
+                        char name[ZFS_MAXNAMELEN];
+                        dsl_dataset_name(ds, name);
+                        fnvlist_add_int32(errlist, name, dst->dst_err);
                 }
                 ASSERT3P(dsda->rm_origin, ==, NULL);
                 dsl_dataset_disown(ds, dstg);
                 kmem_free(dsda, sizeof (struct dsl_ds_destroyarg));
         }

@@ -1043,11 +1046,10 @@
         dsl_sync_task_group_t *dstg;
         objset_t *os;
         dsl_dir_t *dd;
         uint64_t obj;
         struct dsl_ds_destroyarg dsda = { 0 };
-        dsl_dataset_t dummy_ds = { 0 };
 
         dsda.ds = ds;
 
         if (dsl_dataset_is_snapshot(ds)) {
                 /* Destroying a snapshot is simpler */

@@ -1063,12 +1065,10 @@
                 err = EINVAL;
                 goto out;
         }
 
         dd = ds->ds_dir;
-        dummy_ds.ds_dir = dd;
-        dummy_ds.ds_object = ds->ds_object;
 
         /*
          * Check for errors and mark this ds as inconsistent, in
          * case we crash while freeing the objects.
          */

@@ -1151,11 +1151,11 @@
 
                 dstg = dsl_sync_task_group_create(ds->ds_dir->dd_pool);
                 dsl_sync_task_create(dstg, dsl_dataset_destroy_check,
                     dsl_dataset_destroy_sync, &dsda, tag, 0);
                 dsl_sync_task_create(dstg, dsl_dir_destroy_check,
-                    dsl_dir_destroy_sync, &dummy_ds, FTAG, 0);
+                    dsl_dir_destroy_sync, dd, FTAG, 0);
                 err = dsl_sync_task_group_wait(dstg);
                 dsl_sync_task_group_destroy(dstg);
 
                 /*
                  * We could be racing against 'zfs release' or 'zfs destroy -d'

@@ -1326,18 +1326,16 @@
 /* ARGSUSED */
 static void
 dsl_dataset_destroy_begin_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 {
         dsl_dataset_t *ds = arg1;
-        dsl_pool_t *dp = ds->ds_dir->dd_pool;
 
         /* Mark it as inconsistent on-disk, in case we crash */
         dmu_buf_will_dirty(ds->ds_dbuf, tx);
         ds->ds_phys->ds_flags |= DS_FLAG_INCONSISTENT;
 
-        spa_history_log_internal(LOG_DS_DESTROY_BEGIN, dp->dp_spa, tx,
-            "dataset = %llu", ds->ds_object);
+        spa_history_log_internal_ds(ds, "destroy begin", tx, "");
 }
 
 static int
 dsl_dataset_origin_check(struct dsl_ds_destroyarg *dsda, void *tag,
     dmu_tx_t *tx)

@@ -1658,13 +1656,17 @@
 
         if (wont_destroy) {
                 ASSERT(spa_version(dp->dp_spa) >= SPA_VERSION_USERREFS);
                 dmu_buf_will_dirty(ds->ds_dbuf, tx);
                 ds->ds_phys->ds_flags |= DS_FLAG_DEFER_DESTROY;
+                spa_history_log_internal_ds(ds, "defer_destroy", tx, "");
                 return;
         }
 
+        /* We need to log before removing it from the namespace. */
+        spa_history_log_internal_ds(ds, "destroy", tx, "");
+
         /* signal any waiters that this dataset is going away */
         mutex_enter(&ds->ds_lock);
         ds->ds_owner = dsl_reaper;
         cv_broadcast(&ds->ds_exclusive_cv);
         mutex_exit(&ds->ds_lock);

@@ -1955,12 +1957,10 @@
 
         if (ds_prev && ds->ds_prev != ds_prev)
                 dsl_dataset_rele(ds_prev, FTAG);
 
         spa_prop_clear_bootfs(dp->dp_spa, ds->ds_object, tx);
-        spa_history_log_internal(LOG_DS_DESTROY, dp->dp_spa, tx,
-            "dataset = %llu", ds->ds_object);
 
         if (ds->ds_phys->ds_next_clones_obj != 0) {
                 uint64_t count;
                 ASSERT(0 == zap_count(mos,
                     ds->ds_phys->ds_next_clones_obj, &count) && count == 0);

@@ -2004,24 +2004,23 @@
         asize = MIN(ds->ds_phys->ds_unique_bytes, ds->ds_reserved);
         if (asize > dsl_dir_space_available(ds->ds_dir, NULL, 0, TRUE))
                 return (ENOSPC);
 
         /*
-         * Propogate any reserved space for this snapshot to other
+         * Propagate any reserved space for this snapshot to other
          * snapshot checks in this sync group.
          */
         if (asize > 0)
                 dsl_dir_willuse_space(ds->ds_dir, asize, tx);
 
         return (0);
 }
 
 int
-dsl_dataset_snapshot_check(void *arg1, void *arg2, dmu_tx_t *tx)
+dsl_dataset_snapshot_check(dsl_dataset_t *ds, const char *snapname,
+    dmu_tx_t *tx)
 {
-        dsl_dataset_t *ds = arg1;
-        const char *snapname = arg2;
         int err;
         uint64_t value;
 
         /*
          * We don't allow multiple snapshots of the same txg.  If there

@@ -2029,11 +2028,11 @@
          */
         if (ds->ds_phys->ds_prev_snap_txg >= tx->tx_txg)
                 return (EAGAIN);
 
         /*
-         * Check for conflicting name snapshot name.
+         * Check for conflicting snapshot name.
          */
         err = dsl_dataset_snap_lookup(ds, snapname, &value);
         if (err == 0)
                 return (EEXIST);
         if (err != ENOENT)

@@ -2053,14 +2052,13 @@
         ds->ds_trysnap_txg = tx->tx_txg;
         return (0);
 }
 
 void
-dsl_dataset_snapshot_sync(void *arg1, void *arg2, dmu_tx_t *tx)
+dsl_dataset_snapshot_sync(dsl_dataset_t *ds, const char *snapname,
+    dmu_tx_t *tx)
 {
-        dsl_dataset_t *ds = arg1;
-        const char *snapname = arg2;
         dsl_pool_t *dp = ds->ds_dir->dd_pool;
         dmu_buf_t *dbuf;
         dsl_dataset_phys_t *dsphys;
         uint64_t dsobj, crtxg;
         objset_t *mos = dp->dp_meta_objset;

@@ -2162,12 +2160,11 @@
 
         dsl_scan_ds_snapshotted(ds, tx);
 
         dsl_dir_snap_cmtime_update(ds->ds_dir);
 
-        spa_history_log_internal(LOG_DS_SNAPSHOT, dp->dp_spa, tx,
-            "dataset = %llu", dsobj);
+        spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, "");
 }
 
 void
 dsl_dataset_sync(dsl_dataset_t *ds, zio_t *zio, dmu_tx_t *tx)
 {

@@ -2250,11 +2247,24 @@
 void
 dsl_dataset_stats(dsl_dataset_t *ds, nvlist_t *nv)
 {
         uint64_t refd, avail, uobjs, aobjs, ratio;
 
+        ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
+            (ds->ds_phys->ds_uncompressed_bytes * 100 /
+            ds->ds_phys->ds_compressed_bytes);
+
+        dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
+
+        if (dsl_dataset_is_snapshot(ds)) {
+                dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_COMPRESSRATIO, ratio);
+                dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_USED,
+                    ds->ds_phys->ds_unique_bytes);
+                get_clones_stat(ds, nv);
+        } else {
         dsl_dir_stats(ds->ds_dir, nv);
+        }
 
         dsl_dataset_space(ds, &refd, &avail, &uobjs, &aobjs);
         dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_AVAILABLE, avail);
         dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFERENCED, refd);
 

@@ -2295,55 +2305,37 @@
                                     written);
                         }
                 }
         }
 
-        ratio = ds->ds_phys->ds_compressed_bytes == 0 ? 100 :
-            (ds->ds_phys->ds_uncompressed_bytes * 100 /
-            ds->ds_phys->ds_compressed_bytes);
-        dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_REFRATIO, ratio);
-
-        if (ds->ds_phys->ds_next_snap_obj) {
-                /*
-                 * This is a snapshot; override the dd's space used with
-                 * our unique space and compression ratio.
-                 */
-                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);
-        }
 }
 
 void
 dsl_dataset_fast_stat(dsl_dataset_t *ds, dmu_objset_stats_t *stat)
 {
         stat->dds_creation_txg = ds->ds_phys->ds_creation_txg;
         stat->dds_inconsistent = ds->ds_phys->ds_flags & DS_FLAG_INCONSISTENT;
         stat->dds_guid = ds->ds_phys->ds_guid;
-        if (ds->ds_phys->ds_next_snap_obj) {
+        stat->dds_origin[0] = '\0';
+        if (dsl_dataset_is_snapshot(ds)) {
                 stat->dds_is_snapshot = B_TRUE;
                 stat->dds_num_clones = ds->ds_phys->ds_num_children - 1;
         } else {
                 stat->dds_is_snapshot = B_FALSE;
                 stat->dds_num_clones = 0;
-        }
 
-        /* clone origin is really a dsl_dir thing... */
         rw_enter(&ds->ds_dir->dd_pool->dp_config_rwlock, RW_READER);
         if (dsl_dir_is_clone(ds->ds_dir)) {
                 dsl_dataset_t *ods;
 
                 VERIFY(0 == dsl_dataset_get_ref(ds->ds_dir->dd_pool,
                     ds->ds_dir->dd_phys->dd_origin_obj, FTAG, &ods));
                 dsl_dataset_name(ods, stat->dds_origin);
                 dsl_dataset_drop_ref(ods, FTAG);
-        } else {
-                stat->dds_origin[0] = '\0';
         }
         rw_exit(&ds->ds_dir->dd_pool->dp_config_rwlock);
+        }
 }
 
 uint64_t
 dsl_dataset_fsid_guid(dsl_dataset_t *ds)
 {

@@ -2456,12 +2448,12 @@
         mutex_exit(&ds->ds_lock);
         err = zap_add(mos, hds->ds_phys->ds_snapnames_zapobj,
             ds->ds_snapname, 8, 1, &ds->ds_object, tx);
         ASSERT3U(err, ==, 0);
 
-        spa_history_log_internal(LOG_DS_RENAME, dd->dd_pool->dp_spa, tx,
-            "dataset = %llu", ds->ds_object);
+        spa_history_log_internal_ds(ds, "rename", tx,
+            "-> @%s", newsnapname);
         dsl_dataset_rele(hds, FTAG);
 }
 
 struct renamesnaparg {
         dsl_sync_task_group_t *dstg;

@@ -2937,12 +2929,11 @@
             -pa->used - delta, -pa->comp, -pa->uncomp, tx);
 
         origin_ds->ds_phys->ds_unique_bytes = pa->unique;
 
         /* log history record */
-        spa_history_log_internal(LOG_DS_PROMOTE, dd->dd_pool->dp_spa, tx,
-            "dataset = %llu", hds->ds_object);
+        spa_history_log_internal_ds(hds, "promote", tx, "");
 
         dsl_dir_close(odd, FTAG);
 }
 
 static char *snaplist_tag = "snaplist";

@@ -3296,10 +3287,13 @@
             csa->cds->ds_phys->ds_deadlist_obj);
         dsl_deadlist_open(&csa->ohds->ds_deadlist, dp->dp_meta_objset,
             csa->ohds->ds_phys->ds_deadlist_obj);
 
         dsl_scan_ds_clone_swapped(csa->ohds, csa->cds, tx);
+
+        spa_history_log_internal_ds(csa->cds, "clone swap", tx,
+            "parent=%s", csa->ohds->ds_dir->dd_myname);
 }
 
 /*
  * Swap 'clone' with its origin head datasets.  Used at the end of "zfs
  * recv" into an existing fs to swizzle the file system to the new

@@ -3452,13 +3446,12 @@
 
         if (ds->ds_quota != effective_value) {
                 dmu_buf_will_dirty(ds->ds_dbuf, tx);
                 ds->ds_quota = effective_value;
 
-                spa_history_log_internal(LOG_DS_REFQUOTA,
-                    ds->ds_dir->dd_pool->dp_spa, tx, "%lld dataset = %llu ",
-                    (longlong_t)ds->ds_quota, ds->ds_object);
+                spa_history_log_internal_ds(ds, "set refquota", tx,
+                    "refquota=%lld", (longlong_t)ds->ds_quota);
         }
 }
 
 int
 dsl_dataset_set_quota(const char *dsname, zprop_source_t source, uint64_t quota)

@@ -3559,13 +3552,12 @@
         mutex_exit(&ds->ds_lock);
 
         dsl_dir_diduse_space(ds->ds_dir, DD_USED_REFRSRV, delta, 0, 0, tx);
         mutex_exit(&ds->ds_dir->dd_lock);
 
-        spa_history_log_internal(LOG_DS_REFRESERV,
-            ds->ds_dir->dd_pool->dp_spa, tx, "%lld dataset = %llu",
-            (longlong_t)effective_value, ds->ds_object);
+        spa_history_log_internal_ds(ds, "set refreservation", tx,
+            "refreservation=%lld", (longlong_t)effective_value);
 }
 
 int
 dsl_dataset_set_reservation(const char *dsname, zprop_source_t source,
     uint64_t reservation)

@@ -3627,11 +3619,11 @@
 static int
 dsl_dataset_user_hold_check(void *arg1, void *arg2, dmu_tx_t *tx)
 {
         dsl_dataset_t *ds = arg1;
         struct dsl_ds_holdarg *ha = arg2;
-        char *htag = ha->htag;
+        const char *htag = ha->htag;
         objset_t *mos = ds->ds_dir->dd_pool->dp_meta_objset;
         int error = 0;
 
         if (spa_version(ds->ds_dir->dd_pool->dp_spa) < SPA_VERSION_USERREFS)
                 return (ENOTSUP);

@@ -3661,11 +3653,11 @@
 void
 dsl_dataset_user_hold_sync(void *arg1, void *arg2, dmu_tx_t *tx)
 {
         dsl_dataset_t *ds = arg1;
         struct dsl_ds_holdarg *ha = arg2;
-        char *htag = ha->htag;
+        const char *htag = ha->htag;
         dsl_pool_t *dp = ds->ds_dir->dd_pool;
         objset_t *mos = dp->dp_meta_objset;
         uint64_t now = gethrestime_sec();
         uint64_t zapobj;
 

@@ -3689,13 +3681,13 @@
         if (ha->temphold) {
                 VERIFY(0 == dsl_pool_user_hold(dp, ds->ds_object,
                     htag, &now, tx));
         }
 
-        spa_history_log_internal(LOG_DS_USER_HOLD,
-            dp->dp_spa, tx, "<%s> temp = %d dataset = %llu", htag,
-            (int)ha->temphold, ds->ds_object);
+        spa_history_log_internal_ds(ds, "hold", tx,
+            "tag = %s temp = %d holds now = %llu",
+            htag, (int)ha->temphold, ds->ds_userrefs);
 }
 
 static int
 dsl_dataset_user_hold_one(const char *dsname, void *arg)
 {

@@ -3898,11 +3890,10 @@
         struct dsl_ds_releasearg *ra = arg1;
         dsl_dataset_t *ds = ra->ds;
         dsl_pool_t *dp = ds->ds_dir->dd_pool;
         objset_t *mos = dp->dp_meta_objset;
         uint64_t zapobj;
-        uint64_t dsobj = ds->ds_object;
         uint64_t refs;
         int error;
 
         mutex_enter(&ds->ds_lock);
         ds->ds_userrefs--;

@@ -3921,13 +3912,12 @@
                 dsda.releasing = B_TRUE;
                 /* We already did the destroy_check */
                 dsl_dataset_destroy_sync(&dsda, tag, tx);
         }
 
-        spa_history_log_internal(LOG_DS_USER_RELEASE,
-            dp->dp_spa, tx, "<%s> %lld dataset = %llu",
-            ra->htag, (longlong_t)refs, dsobj);
+        spa_history_log_internal_ds(ds, "release", tx,
+            "tag = %s refs now = %lld", ra->htag, (longlong_t)refs);
 }
 
 static int
 dsl_dataset_user_release_one(const char *dsname, void *arg)
 {