--- old/usr/src/uts/common/fs/zfs/dsl_dataset.c	Mon Aug  5 17:26:50 2019
+++ new/usr/src/uts/common/fs/zfs/dsl_dataset.c	Mon Aug  5 17:26:50 2019
@@ -46,7 +46,7 @@
 #include <sys/zfs_context.h>
 #include <sys/zfs_ioctl.h>
 #include <sys/spa.h>
-#include <sys/vdev.h>
+#include <sys/spa_impl.h>
 #include <sys/zfs_znode.h>
 #include <sys/zfs_onexit.h>
 #include <sys/zvol.h>
@@ -55,6 +55,7 @@
 #include <sys/dsl_destroy.h>
 #include <sys/dsl_userhold.h>
 #include <sys/dsl_bookmark.h>
+#include <sys/autosnap.h>
 #include <sys/dmu_send.h>
 #include <sys/zio_checksum.h>
 #include <sys/zio_compress.h>
@@ -82,15 +83,24 @@
 
 extern inline dsl_dataset_phys_t *dsl_dataset_phys(dsl_dataset_t *ds);
 
-static void dsl_dataset_set_remap_deadlist_object(dsl_dataset_t *ds,
-    uint64_t obj, dmu_tx_t *tx);
-static void dsl_dataset_unset_remap_deadlist_object(dsl_dataset_t *ds,
-    dmu_tx_t *tx);
-
 extern int spa_asize_inflation;
 
 static zil_header_t zero_zil;
 
+kmem_cache_t *zfs_ds_collector_cache = NULL;
+
+zfs_ds_collector_entry_t *
+dsl_dataset_collector_cache_alloc()
+{
+	return (kmem_cache_alloc(zfs_ds_collector_cache, KM_SLEEP));
+}
+
+void
+dsl_dataset_collector_cache_free(zfs_ds_collector_entry_t *entry)
+{
+	kmem_cache_free(zfs_ds_collector_cache, entry);
+}
+
 /*
  * Figure out how much of this delta should be propogated to the dsl_dir
  * layer.  If there's a refreservation, that space has already been
@@ -160,47 +170,6 @@
 	    DD_USED_REFRSRV, DD_USED_HEAD, tx);
 }
 
-/*
- * Called when the specified segment has been remapped, and is thus no
- * longer referenced in the head dataset.  The vdev must be indirect.
- *
- * If the segment is referenced by a snapshot, put it on the remap deadlist.
- * Otherwise, add this segment to the obsolete spacemap.
- */
-void
-dsl_dataset_block_remapped(dsl_dataset_t *ds, uint64_t vdev, uint64_t offset,
-    uint64_t size, uint64_t birth, dmu_tx_t *tx)
-{
-	spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
-
-	ASSERT(dmu_tx_is_syncing(tx));
-	ASSERT(birth <= tx->tx_txg);
-	ASSERT(!ds->ds_is_snapshot);
-
-	if (birth > dsl_dataset_phys(ds)->ds_prev_snap_txg) {
-		spa_vdev_indirect_mark_obsolete(spa, vdev, offset, size, tx);
-	} else {
-		blkptr_t fakebp;
-		dva_t *dva = &fakebp.blk_dva[0];
-
-		ASSERT(ds != NULL);
-
-		mutex_enter(&ds->ds_remap_deadlist_lock);
-		if (!dsl_dataset_remap_deadlist_exists(ds)) {
-			dsl_dataset_create_remap_deadlist(ds, tx);
-		}
-		mutex_exit(&ds->ds_remap_deadlist_lock);
-
-		BP_ZERO(&fakebp);
-		fakebp.blk_birth = birth;
-		DVA_SET_VDEV(dva, vdev);
-		DVA_SET_OFFSET(dva, offset);
-		DVA_SET_ASIZE(dva, size);
-
-		dsl_deadlist_insert(&ds->ds_remap_deadlist, &fakebp, tx);
-	}
-}
-
 int
 dsl_dataset_block_kill(dsl_dataset_t *ds, const blkptr_t *bp, dmu_tx_t *tx,
     boolean_t async)
@@ -208,6 +177,7 @@
 	int used = bp_get_dsize_sync(tx->tx_pool->dp_spa, bp);
 	int compressed = BP_GET_PSIZE(bp);
 	int uncompressed = BP_GET_UCSIZE(bp);
+	wbc_data_t *wbc_data = spa_get_wbc_data(tx->tx_pool->dp_spa);
 
 	if (BP_IS_HOLE(bp))
 		return (0);
@@ -232,6 +202,23 @@
 		dprintf_bp(bp, "freeing ds=%llu", ds->ds_object);
 		dsl_free(tx->tx_pool, tx->tx_txg, bp);
 
+		/* update amount of data which is changed in the window */
+		mutex_enter(&wbc_data->wbc_lock);
+		if (wbc_data->wbc_isvalid &&
+		    bp->blk_birth && wbc_data->wbc_finish_txg &&
+		    bp->blk_birth <= wbc_data->wbc_finish_txg &&
+		    bp->blk_birth >= wbc_data->wbc_start_txg &&
+		    !wbc_data->wbc_purge) {
+
+			wbc_data->wbc_altered_bytes += used;
+			if (wbc_data->wbc_altered_limit &&
+			    wbc_data->wbc_altered_bytes >
+			    wbc_data->wbc_altered_limit) {
+				wbc_purge_window(tx->tx_pool->dp_spa, tx);
+			}
+		}
+		mutex_exit(&wbc_data->wbc_lock);
+
 		mutex_enter(&ds->ds_lock);
 		ASSERT(dsl_dataset_phys(ds)->ds_unique_bytes >= used ||
 		    !DS_UNIQUE_IS_ACCURATE(ds));
@@ -319,10 +306,8 @@
 	}
 
 	bplist_destroy(&ds->ds_pending_deadlist);
-	if (dsl_deadlist_is_open(&ds->ds_deadlist))
+	if (ds->ds_deadlist.dl_os != NULL)
 		dsl_deadlist_close(&ds->ds_deadlist);
-	if (dsl_deadlist_is_open(&ds->ds_remap_deadlist))
-		dsl_deadlist_close(&ds->ds_remap_deadlist);
 	if (ds->ds_dir)
 		dsl_dir_async_rele(ds->ds_dir, ds);
 
@@ -332,7 +317,6 @@
 	mutex_destroy(&ds->ds_lock);
 	mutex_destroy(&ds->ds_opening_lock);
 	mutex_destroy(&ds->ds_sendstream_lock);
-	mutex_destroy(&ds->ds_remap_deadlist_lock);
 	refcount_destroy(&ds->ds_longholds);
 	rrw_destroy(&ds->ds_bp_rwlock);
 
@@ -457,23 +441,15 @@
 		ds->ds_object = dsobj;
 		ds->ds_is_snapshot = dsl_dataset_phys(ds)->ds_num_children != 0;
 
-		err = dsl_dir_hold_obj(dp, dsl_dataset_phys(ds)->ds_dir_obj,
-		    NULL, ds, &ds->ds_dir);
-		if (err != 0) {
-			kmem_free(ds, sizeof (dsl_dataset_t));
-			dmu_buf_rele(dbuf, tag);
-			return (err);
-		}
-
 		mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL);
 		mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL);
 		mutex_init(&ds->ds_sendstream_lock, NULL, MUTEX_DEFAULT, NULL);
-		mutex_init(&ds->ds_remap_deadlist_lock,
-		    NULL, MUTEX_DEFAULT, NULL);
 		rrw_init(&ds->ds_bp_rwlock, B_FALSE);
 		refcount_create(&ds->ds_longholds);
 
 		bplist_create(&ds->ds_pending_deadlist);
+		dsl_deadlist_open(&ds->ds_deadlist,
+		    mos, dsl_dataset_phys(ds)->ds_deadlist_obj);
 
 		list_create(&ds->ds_sendstreams, sizeof (dmu_sendarg_t),
 		    offsetof(dmu_sendarg_t, dsa_link));
@@ -497,6 +473,20 @@
 			}
 		}
 
+		err = dsl_dir_hold_obj(dp,
+		    dsl_dataset_phys(ds)->ds_dir_obj, NULL, ds, &ds->ds_dir);
+		if (err != 0) {
+			mutex_destroy(&ds->ds_lock);
+			mutex_destroy(&ds->ds_opening_lock);
+			mutex_destroy(&ds->ds_sendstream_lock);
+			refcount_destroy(&ds->ds_longholds);
+			bplist_destroy(&ds->ds_pending_deadlist);
+			dsl_deadlist_close(&ds->ds_deadlist);
+			kmem_free(ds, sizeof (dsl_dataset_t));
+			dmu_buf_rele(dbuf, tag);
+			return (err);
+		}
+
 		if (!ds->ds_is_snapshot) {
 			ds->ds_snapname[0] = '\0';
 			if (dsl_dataset_phys(ds)->ds_prev_snap_obj != 0) {
@@ -537,15 +527,6 @@
 			ds->ds_reserved = ds->ds_quota = 0;
 		}
 
-		dsl_deadlist_open(&ds->ds_deadlist,
-		    mos, dsl_dataset_phys(ds)->ds_deadlist_obj);
-		uint64_t remap_deadlist_obj =
-		    dsl_dataset_get_remap_deadlist_object(ds);
-		if (remap_deadlist_obj != 0) {
-			dsl_deadlist_open(&ds->ds_remap_deadlist, mos,
-			    remap_deadlist_obj);
-		}
-
 		dmu_buf_init_user(&ds->ds_dbu, dsl_dataset_evict_sync,
 		    dsl_dataset_evict_async, &ds->ds_dbuf);
 		if (err == 0)
@@ -554,8 +535,6 @@
 		if (err != 0 || winner != NULL) {
 			bplist_destroy(&ds->ds_pending_deadlist);
 			dsl_deadlist_close(&ds->ds_deadlist);
-			if (dsl_deadlist_is_open(&ds->ds_remap_deadlist))
-				dsl_deadlist_close(&ds->ds_remap_deadlist);
 			if (ds->ds_prev)
 				dsl_dataset_rele(ds->ds_prev, ds);
 			dsl_dir_rele(ds->ds_dir, ds);
@@ -1203,6 +1182,9 @@
 	nvpair_t *pair;
 	int rv = 0;
 
+	if (ddsa->ddsa_autosnap && dmu_tx_is_syncing(tx))
+		autosnap_invalidate_list(dp, ddsa->ddsa_snaps);
+
 	/*
 	 * Pre-compute how many total new snapshots will be created for each
 	 * level in the tree and below. This is needed for validating the
@@ -1343,7 +1325,8 @@
 	dsl_dataset_phys_t *dsphys;
 	uint64_t dsobj, crtxg;
 	objset_t *mos = dp->dp_meta_objset;
-	objset_t *os;
+	objset_t *os = NULL;
+	uint64_t unique_bytes = 0;
 
 	ASSERT(RRW_WRITE_HELD(&dp->dp_config_rwlock));
 
@@ -1448,27 +1431,11 @@
 	dsl_deadlist_add_key(&ds->ds_deadlist,
 	    dsl_dataset_phys(ds)->ds_prev_snap_txg, tx);
 
-	if (dsl_dataset_remap_deadlist_exists(ds)) {
-		uint64_t remap_deadlist_obj =
-		    dsl_dataset_get_remap_deadlist_object(ds);
-		/*
-		 * Move the remap_deadlist to the snapshot.  The head
-		 * will create a new remap deadlist on demand, from
-		 * dsl_dataset_block_remapped().
-		 */
-		dsl_dataset_unset_remap_deadlist_object(ds, tx);
-		dsl_deadlist_close(&ds->ds_remap_deadlist);
-
-		dmu_object_zapify(mos, dsobj, DMU_OT_DSL_DATASET, tx);
-		VERIFY0(zap_add(mos, dsobj, DS_FIELD_REMAP_DEADLIST,
-		    sizeof (remap_deadlist_obj), 1, &remap_deadlist_obj, tx));
-	}
-
 	ASSERT3U(dsl_dataset_phys(ds)->ds_prev_snap_txg, <, tx->tx_txg);
 	dsl_dataset_phys(ds)->ds_prev_snap_obj = dsobj;
 	dsl_dataset_phys(ds)->ds_prev_snap_txg = crtxg;
+	unique_bytes = dsl_dataset_phys(ds)->ds_unique_bytes;
 	dsl_dataset_phys(ds)->ds_unique_bytes = 0;
-
 	if (spa_version(dp->dp_spa) >= SPA_VERSION_UNIQUE_ACCURATE)
 		dsl_dataset_phys(ds)->ds_flags |= DS_FLAG_UNIQUE_ACCURATE;
 
@@ -1485,6 +1452,17 @@
 	dsl_dir_snap_cmtime_update(ds->ds_dir);
 
 	spa_history_log_internal_ds(ds->ds_prev, "snapshot", tx, "");
+
+	if (autosnap_check_name(snapname)) {
+		autosnap_create_cb(spa_get_autosnap(dp->dp_spa),
+		    ds, snapname, tx->tx_txg);
+	}
+
+	if (os == NULL)
+		VERIFY0(dmu_objset_from_ds(ds, &os));
+
+	if (os->os_wbc_mode != ZFS_WBC_MODE_OFF)
+		wbc_add_bytes(dp->dp_spa, tx->tx_txg, unique_bytes);
 }
 
 void
@@ -1501,6 +1479,7 @@
 		char dsname[ZFS_MAX_DATASET_NAME_LEN];
 
 		name = nvpair_name(pair);
+
 		atp = strchr(name, '@');
 		(void) strlcpy(dsname, name, atp - name + 1);
 		VERIFY0(dsl_dataset_hold(dp, dsname, FTAG, &ds));
@@ -1568,6 +1547,7 @@
 	ddsa.ddsa_props = props;
 	ddsa.ddsa_errors = errors;
 	ddsa.ddsa_cr = CRED();
+	ddsa.ddsa_autosnap = B_FALSE;
 
 	if (error == 0) {
 		error = dsl_sync_task(firstname, dsl_dataset_snapshot_check,
@@ -2202,6 +2182,19 @@
 	    dsl_get_used(ds));
 
 	if (ds->ds_is_snapshot) {
+		dsl_dataset_t *hds = NULL;
+		boolean_t modified = B_FALSE;
+
+		if (dsl_dataset_hold_obj(dp,
+		    dsl_dir_phys(ds->ds_dir)->dd_head_dataset_obj,
+		    FTAG, &hds) == 0) {
+			modified = dsl_dataset_modified_since_snap(hds, ds);
+			dsl_dataset_rele(hds, FTAG);
+		}
+
+		dsl_prop_nvlist_add_uint64(nv, ZFS_PROP_MODIFIED,
+		    modified ? 1 : 0);
+
 		get_clones_stat(ds, nv);
 	} else {
 		char buf[ZFS_MAX_DATASET_NAME_LEN];
@@ -2279,11 +2272,16 @@
 	stat->dds_inconsistent = dsl_get_inconsistent(ds);
 	stat->dds_guid = dsl_get_guid(ds);
 	stat->dds_origin[0] = '\0';
+	stat->dds_is_snapshot = B_FALSE;
+	stat->dds_is_autosnapshot = B_FALSE;
 	if (ds->ds_is_snapshot) {
-		stat->dds_is_snapshot = B_TRUE;
+		if (autosnap_is_autosnap(ds))
+			stat->dds_is_autosnapshot = B_TRUE;
+		else
+			stat->dds_is_snapshot = B_TRUE;
+
 		stat->dds_num_clones = dsl_get_numclones(ds);
 	} else {
-		stat->dds_is_snapshot = B_FALSE;
 		stat->dds_num_clones = 0;
 
 		if (dsl_dir_is_clone(ds->ds_dir)) {
@@ -2400,6 +2398,14 @@
 	dsl_dataset_t *hds;
 	int error;
 
+	/* You cannot rename an autosnapshot */
+	if (autosnap_check_name(ddrsa->ddrsa_oldsnapname))
+		return (SET_ERROR(EPERM));
+
+	/* New name cannot match the AUTOSNAP prefix */
+	if (autosnap_check_name(ddrsa->ddrsa_newsnapname))
+		return (SET_ERROR(EPERM));
+
 	error = dsl_dataset_hold(dp, ddrsa->ddrsa_fsname, FTAG, &hds);
 	if (error != 0)
 		return (error);
@@ -3342,41 +3348,6 @@
 	return (0);
 }
 
-static void
-dsl_dataset_swap_remap_deadlists(dsl_dataset_t *clone,
-    dsl_dataset_t *origin, dmu_tx_t *tx)
-{
-	uint64_t clone_remap_dl_obj, origin_remap_dl_obj;
-	dsl_pool_t *dp = dmu_tx_pool(tx);
-
-	ASSERT(dsl_pool_sync_context(dp));
-
-	clone_remap_dl_obj = dsl_dataset_get_remap_deadlist_object(clone);
-	origin_remap_dl_obj = dsl_dataset_get_remap_deadlist_object(origin);
-
-	if (clone_remap_dl_obj != 0) {
-		dsl_deadlist_close(&clone->ds_remap_deadlist);
-		dsl_dataset_unset_remap_deadlist_object(clone, tx);
-	}
-	if (origin_remap_dl_obj != 0) {
-		dsl_deadlist_close(&origin->ds_remap_deadlist);
-		dsl_dataset_unset_remap_deadlist_object(origin, tx);
-	}
-
-	if (clone_remap_dl_obj != 0) {
-		dsl_dataset_set_remap_deadlist_object(origin,
-		    clone_remap_dl_obj, tx);
-		dsl_deadlist_open(&origin->ds_remap_deadlist,
-		    dp->dp_meta_objset, clone_remap_dl_obj);
-	}
-	if (origin_remap_dl_obj != 0) {
-		dsl_dataset_set_remap_deadlist_object(clone,
-		    origin_remap_dl_obj, tx);
-		dsl_deadlist_open(&clone->ds_remap_deadlist,
-		    dp->dp_meta_objset, origin_remap_dl_obj);
-	}
-}
-
 void
 dsl_dataset_clone_swap_sync_impl(dsl_dataset_t *clone,
     dsl_dataset_t *origin_head, dmu_tx_t *tx)
@@ -3546,7 +3517,6 @@
 	    dsl_dataset_phys(clone)->ds_deadlist_obj);
 	dsl_deadlist_open(&origin_head->ds_deadlist, dp->dp_meta_objset,
 	    dsl_dataset_phys(origin_head)->ds_deadlist_obj);
-	dsl_dataset_swap_remap_deadlists(clone, origin_head, tx);
 
 	dsl_scan_ds_clone_swapped(origin_head, clone, tx);
 
@@ -4039,105 +4009,55 @@
 }
 
 boolean_t
-dsl_dataset_is_zapified(dsl_dataset_t *ds)
+dataset_name_hidden(const char *name)
 {
-	dmu_object_info_t doi;
-
-	dmu_object_info_from_db(ds->ds_dbuf, &doi);
-	return (doi.doi_type == DMU_OTN_ZAP_METADATA);
+	if (strchr(name, '$') != NULL)
+		return (B_TRUE);
+	if (strchr(name, '%') != NULL)
+		return (B_TRUE);
+	if (!INGLOBALZONE(curproc) && !zone_dataset_visible(name, NULL))
+		return (B_TRUE);
+	return (B_FALSE);
 }
 
-boolean_t
-dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds)
-{
-	return (dsl_dataset_is_zapified(ds) &&
-	    zap_contains(ds->ds_dir->dd_pool->dp_meta_objset,
-	    ds->ds_object, DS_FIELD_RESUME_TOGUID) == 0);
-}
-
 uint64_t
-dsl_dataset_get_remap_deadlist_object(dsl_dataset_t *ds)
+dsl_dataset_creation_txg(const char *name)
 {
-	uint64_t remap_deadlist_obj;
+	dsl_pool_t *dp;
+	dsl_dataset_t *ds;
 	int err;
+	uint64_t ret = UINT64_MAX;
 
-	if (!dsl_dataset_is_zapified(ds))
-		return (0);
+	err = dsl_pool_hold(name, FTAG, &dp);
 
-	err = zap_lookup(ds->ds_dir->dd_pool->dp_meta_objset, ds->ds_object,
-	    DS_FIELD_REMAP_DEADLIST, sizeof (remap_deadlist_obj), 1,
-	    &remap_deadlist_obj);
+	if (err)
+		return (ret);
 
-	if (err != 0) {
-		VERIFY3S(err, ==, ENOENT);
-		return (0);
+	err = dsl_dataset_hold(dp, name, FTAG, &ds);
+
+	if (!err) {
+		ret = dsl_dataset_phys(ds)->ds_creation_txg;
+		dsl_dataset_rele(ds, FTAG);
 	}
 
-	ASSERT(remap_deadlist_obj != 0);
-	return (remap_deadlist_obj);
+	dsl_pool_rele(dp, FTAG);
+
+	return (ret);
 }
 
 boolean_t
-dsl_dataset_remap_deadlist_exists(dsl_dataset_t *ds)
+dsl_dataset_is_zapified(dsl_dataset_t *ds)
 {
-	EQUIV(dsl_deadlist_is_open(&ds->ds_remap_deadlist),
-	    dsl_dataset_get_remap_deadlist_object(ds) != 0);
-	return (dsl_deadlist_is_open(&ds->ds_remap_deadlist));
-}
+	dmu_object_info_t doi;
 
-static void
-dsl_dataset_set_remap_deadlist_object(dsl_dataset_t *ds, uint64_t obj,
-    dmu_tx_t *tx)
-{
-	ASSERT(obj != 0);
-	dsl_dataset_zapify(ds, tx);
-	VERIFY0(zap_add(ds->ds_dir->dd_pool->dp_meta_objset, ds->ds_object,
-	    DS_FIELD_REMAP_DEADLIST, sizeof (obj), 1, &obj, tx));
+	dmu_object_info_from_db(ds->ds_dbuf, &doi);
+	return (doi.doi_type == DMU_OTN_ZAP_METADATA);
 }
 
-static void
-dsl_dataset_unset_remap_deadlist_object(dsl_dataset_t *ds, dmu_tx_t *tx)
+boolean_t
+dsl_dataset_has_resume_receive_state(dsl_dataset_t *ds)
 {
-	VERIFY0(zap_remove(ds->ds_dir->dd_pool->dp_meta_objset,
-	    ds->ds_object, DS_FIELD_REMAP_DEADLIST, tx));
-}
-
-void
-dsl_dataset_destroy_remap_deadlist(dsl_dataset_t *ds, dmu_tx_t *tx)
-{
-	uint64_t remap_deadlist_object;
-	spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
-
-	ASSERT(dmu_tx_is_syncing(tx));
-	ASSERT(dsl_dataset_remap_deadlist_exists(ds));
-
-	remap_deadlist_object = ds->ds_remap_deadlist.dl_object;
-	dsl_deadlist_close(&ds->ds_remap_deadlist);
-	dsl_deadlist_free(spa_meta_objset(spa), remap_deadlist_object, tx);
-	dsl_dataset_unset_remap_deadlist_object(ds, tx);
-	spa_feature_decr(spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
-}
-
-void
-dsl_dataset_create_remap_deadlist(dsl_dataset_t *ds, dmu_tx_t *tx)
-{
-	uint64_t remap_deadlist_obj;
-	spa_t *spa = ds->ds_dir->dd_pool->dp_spa;
-
-	ASSERT(dmu_tx_is_syncing(tx));
-	ASSERT(MUTEX_HELD(&ds->ds_remap_deadlist_lock));
-	/*
-	 * Currently we only create remap deadlists when there are indirect
-	 * vdevs with referenced mappings.
-	 */
-	ASSERT(spa_feature_is_active(spa, SPA_FEATURE_DEVICE_REMOVAL));
-
-	remap_deadlist_obj = dsl_deadlist_clone(
-	    &ds->ds_deadlist, UINT64_MAX,
-	    dsl_dataset_phys(ds)->ds_prev_snap_obj, tx);
-	dsl_dataset_set_remap_deadlist_object(ds,
-	    remap_deadlist_obj, tx);
-	dsl_deadlist_open(&ds->ds_remap_deadlist, spa_meta_objset(spa),
-	    remap_deadlist_obj);
-	spa_feature_incr(spa, SPA_FEATURE_OBSOLETE_COUNTS, tx);
+	return (dsl_dataset_is_zapified(ds) &&
+	    zap_contains(ds->ds_dir->dd_pool->dp_meta_objset,
+	    ds->ds_object, DS_FIELD_RESUME_TOGUID) == 0);
 }
