--- old/usr/src/lib/libzfs/common/libzfs_dataset.c	Mon Aug  5 17:16:40 2019
+++ new/usr/src/lib/libzfs/common/libzfs_dataset.c	Mon Aug  5 17:16:40 2019
@@ -21,6 +21,9 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ */
+
+/*
  * Copyright (c) 2013, Joyent, Inc. All rights reserved.
  * Copyright (c) 2011, 2016 by Delphix. All rights reserved.
  * Copyright (c) 2012 DEY Storage Systems, Inc.  All rights reserved.
@@ -28,9 +31,9 @@
  * Copyright (c) 2013 Martin Matuska. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
- * Copyright 2017 Nexenta Systems, Inc.
+ * Copyright 2018 Nexenta Systems, Inc.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>
- * Copyright 2017 RackTop Systems.
+ * Copyright 2017-2018 RackTop Systems.
  */
 
 #include <ctype.h>
@@ -64,6 +67,7 @@
 #include "zfs_prop.h"
 #include "libzfs_impl.h"
 #include "zfs_deleg.h"
+#include "zfs_errno.h"
 
 static int userquota_propname_decode(const char *propname, boolean_t zoned,
     zfs_userquota_prop_t *typep, char *domain, int domainlen, uint64_t *ridp);
@@ -442,7 +446,9 @@
 	else
 		abort();
 
-	if (zhp->zfs_dmustats.dds_is_snapshot)
+	if (zhp->zfs_dmustats.dds_is_autosnapshot)
+		zhp->zfs_type = ZFS_TYPE_AUTOSNAP;
+	else if (zhp->zfs_dmustats.dds_is_snapshot)
 		zhp->zfs_type = ZFS_TYPE_SNAPSHOT;
 	else if (zhp->zfs_dmustats.dds_type == DMU_OST_ZVOL)
 		zhp->zfs_type = ZFS_TYPE_VOLUME;
@@ -1262,7 +1268,7 @@
 			 *		global zone	    non-global zone
 			 * --------------------------------------------------
 			 * zoned=on	mountpoint (no)	    mountpoint (yes)
-			 *		sharenfs (no)	    sharenfs (no)
+			 *		sharenfs (no)	    sharenfs (yes)
 			 *		sharesmb (no)	    sharesmb (no)
 			 *
 			 * zoned=off	mountpoint (yes)	N/A
@@ -1278,14 +1284,6 @@
 					(void) zfs_error(hdl, EZFS_ZONED,
 					    errbuf);
 					goto error;
-				} else if (prop == ZFS_PROP_SHARENFS ||
-				    prop == ZFS_PROP_SHARESMB) {
-					zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
-					    "'%s' cannot be set in "
-					    "a non-global zone"), propname);
-					(void) zfs_error(hdl, EZFS_ZONED,
-					    errbuf);
-					goto error;
 				}
 			} else if (getzoneid() != GLOBAL_ZONEID) {
 				/*
@@ -1557,7 +1555,8 @@
 	case ERANGE:
 		if (prop == ZFS_PROP_COMPRESSION ||
 		    prop == ZFS_PROP_RECORDSIZE) {
-			(void) zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			(void) zfs_error_aux(hdl,
+			    dgettext(TEXT_DOMAIN,
 			    "property setting is not allowed on "
 			    "bootable datasets"));
 			(void) zfs_error(hdl, EZFS_NOTSUP, errbuf);
@@ -1580,6 +1579,19 @@
 		}
 		break;
 
+	case EKZFS_WBCCONFLICT:
+		if (prop == ZFS_PROP_WBC_MODE || prop == ZFS_PROP_DEDUP) {
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "WBC and deduplication cannot be "
+			    "active simultaneously on the "
+			    "same dataset"));
+			(void) zfs_error(hdl, EZFS_WBCNOTSUP, errbuf);
+		} else {
+			(void) zfs_standard_error(hdl, err, errbuf);
+		}
+
+		break;
+
 	case EOVERFLOW:
 		/*
 		 * This platform can't address a volume this big.
@@ -1592,7 +1604,45 @@
 #endif
 		/* FALLTHROUGH */
 	default:
-		(void) zfs_standard_error(hdl, err, errbuf);
+		if (prop != ZFS_PROP_WBC_MODE) {
+			(void) zfs_standard_error(hdl, err, errbuf);
+			break;
+		}
+
+		switch (err) {
+		case EINPROGRESS:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "WBC cannot be enabled for the dataset since "
+			    "the latter is currently in transition to "
+			    "wbc_mode = off. Try again later"));
+			(void) zfs_error(hdl, EZFS_WBCINPROGRESS, errbuf);
+			break;
+		case EALREADY:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "WBC is already in the requested (on/off) "
+			    "state, nothing to do"));
+			(void) zfs_error(hdl, EZFS_WBCALREADY, errbuf);
+			break;
+		case EKZFS_WBCNOTSUP:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "feature@wbc is not enabled or "
+			    "special device (special vdev) is not present"));
+			(void) zfs_error(hdl, EZFS_WBCNOTSUP, errbuf);
+			break;
+		case EKZFS_WBCCHILD:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "a child dataset has this property enabled"));
+			(void) zfs_error(hdl, EZFS_WBCCHILD, errbuf);
+			break;
+		case EKZFS_WBCPARENT:
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "a parent dataset has this property enabled"));
+			(void) zfs_error(hdl, EZFS_WBCPARENT, errbuf);
+			break;
+		default:
+			(void) zfs_standard_error(hdl, err, errbuf);
+			break;
+		}
 	}
 }
 
@@ -1726,13 +1776,18 @@
 	ret = zfs_ioctl(hdl, ZFS_IOC_SET_PROP, &zc);
 
 	if (ret != 0) {
+		if (zc.zc_nvlist_dst_filled == B_FALSE) {
+			(void) zfs_standard_error(hdl, errno, errbuf);
+			goto error;
+		}
+
 		/* Get the list of unset properties back and report them. */
 		nvlist_t *errorprops = NULL;
 		if (zcmd_read_dst_nvlist(hdl, &zc, &errorprops) != 0)
 			goto error;
-		for (nvpair_t *elem = nvlist_next_nvpair(nvl, NULL);
+		for (nvpair_t *elem = nvlist_next_nvpair(errorprops, NULL);
 		    elem != NULL;
-		    elem = nvlist_next_nvpair(nvl, elem)) {
+		    elem = nvlist_next_nvpair(errorprops, elem)) {
 			zfs_prop_t prop = zfs_name_to_prop(nvpair_name(elem));
 			zfs_setprop_error(hdl, prop, errno, errbuf);
 		}
@@ -1834,6 +1889,14 @@
 		return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
 
 	/*
+	 * This property is inheritable by nature,
+	 * but user can do only "set" operation,
+	 * because "inherit" does not make sence
+	 */
+	if (prop == ZFS_PROP_WBC_MODE)
+		return (zfs_error(hdl, EZFS_PROPNONINHERIT, errbuf));
+
+	/*
 	 * Check to see if the value applies to this type
 	 */
 	if (!zfs_prop_valid_for_type(prop, zhp->zfs_type))
@@ -2075,6 +2138,7 @@
 	case ZFS_PROP_SNAPSHOT_LIMIT:
 	case ZFS_PROP_FILESYSTEM_COUNT:
 	case ZFS_PROP_SNAPSHOT_COUNT:
+	case ZFS_PROP_RATE_LIMIT:
 		*val = getprop_uint64(zhp, prop, source);
 
 		if (*source == NULL) {
@@ -2553,6 +2617,7 @@
 	case ZFS_PROP_SNAPSHOT_LIMIT:
 	case ZFS_PROP_FILESYSTEM_COUNT:
 	case ZFS_PROP_SNAPSHOT_COUNT:
+	case ZFS_PROP_RATE_LIMIT:
 
 		if (get_numeric_property(zhp, prop, src, &source, &val) != 0)
 			return (-1);
@@ -2596,6 +2661,9 @@
 		case ZFS_TYPE_SNAPSHOT:
 			str = "snapshot";
 			break;
+		case ZFS_TYPE_AUTOSNAP:
+			str = "autosnap";
+			break;
 		case ZFS_TYPE_BOOKMARK:
 			str = "bookmark";
 			break;
@@ -2682,6 +2750,23 @@
 		zcp_check(zhp, prop, val, NULL);
 		break;
 
+	case ZFS_PROP_MODIFIED:
+		/*
+		 * For a snapshot the "modified" pseudo-property is set to
+		 * "yes" if parent filesystem/zvol differs from the snapshot.
+		 * Even though it's a boolean value, the typical
+		 * values of "on" and "off" don't make sense, so we translate
+		 * to "yes" and "no".
+		 */
+		if (get_numeric_property(zhp, ZFS_PROP_MODIFIED,
+		    src, &source, &val) != 0)
+			return (-1);
+		if (val != 0)
+			(void) strlcpy(propbuf, "yes", proplen);
+		else
+			(void) strlcpy(propbuf, "no", proplen);
+		break;
+
 	default:
 		switch (zfs_prop_get_type(prop)) {
 		case PROP_TYPE_NUMBER:
@@ -3142,7 +3227,7 @@
  * 'zoned' property, which is used to validate property settings when creating
  * new datasets.
  */
-static int
+int
 check_parents(libzfs_handle_t *hdl, const char *path, uint64_t *zoned,
     boolean_t accept_ancestor, int *prefixlen)
 {
@@ -3454,6 +3539,8 @@
 	/* create the dataset */
 	ret = lzc_create(path, ost, props);
 	nvlist_free(props);
+	if (ret == 0)
+		libzfs_log_event(hdl, path);
 
 	/* check for failure */
 	if (ret != 0) {
@@ -3498,6 +3585,64 @@
 	return (0);
 }
 
+int
+zfs_check_krrp(libzfs_handle_t *hdl, const char *name)
+{
+	zfs_cmd_t zc = { 0 };
+	int err;
+
+	(void) strncpy(zc.zc_name, name, ZFS_MAX_DATASET_NAME_LEN);
+	zc.zc_name[ZFS_MAX_DATASET_NAME_LEN - 1] = '\0';
+
+	(void) zfs_ioctl(hdl, ZFS_IOC_CHECK_KRRP, &zc);
+	err = errno;
+
+	free((void *)(uintptr_t)zc.zc_nvlist_dst);
+
+	return (err);
+}
+
+int
+zfs_destroy_atomically(zfs_handle_t *zhp, boolean_t defer)
+{
+	zfs_cmd_t zc = { 0 };
+
+	if (zhp->zfs_type == ZFS_TYPE_BOOKMARK) {
+		nvlist_t *nv = fnvlist_alloc();
+		fnvlist_add_boolean(nv, zhp->zfs_name);
+		int error = lzc_destroy_bookmarks(nv, NULL);
+		fnvlist_free(nv);
+		if (error != 0) {
+			return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
+			    dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+			    zhp->zfs_name));
+		}
+		return (0);
+	}
+
+	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
+
+	if (ZFS_IS_VOLUME(zhp)) {
+		zc.zc_objset_type = DMU_OST_ZVOL;
+	} else {
+		zc.zc_objset_type = DMU_OST_ZFS;
+	}
+
+	zc.zc_defer_destroy = defer;
+	zc.zc_guid = B_TRUE;
+	if (zfs_ioctl(zhp->zfs_hdl, ZFS_IOC_DESTROY, &zc) != 0 &&
+	    errno != ENOENT) {
+		return (zfs_standard_error_fmt(zhp->zfs_hdl, errno,
+		    dgettext(TEXT_DOMAIN, "cannot destroy '%s'"),
+		    zhp->zfs_name));
+	}
+
+	remove_mountpoint(zhp);
+
+	return (0);
+
+}
+
 /*
  * Destroys the given dataset.  The caller must make sure that the filesystem
  * isn't mounted, and that there are no active dependents. If the file system
@@ -3596,9 +3741,15 @@
 zfs_destroy_snaps_nvl(libzfs_handle_t *hdl, nvlist_t *snaps, boolean_t defer)
 {
 	int ret;
+	nvpair_t *elem;
 	nvlist_t *errlist = NULL;
 
 	ret = lzc_destroy_snaps(snaps, defer, &errlist);
+	if (ret == 0) {
+		for (elem = nvlist_next_nvpair(snaps, NULL); elem != NULL;
+		    elem = nvlist_next_nvpair(snaps, elem))
+			libzfs_log_event(hdl, nvpair_name(elem));
+	}
 
 	if (ret == 0) {
 		nvlist_free(errlist);
@@ -3678,6 +3829,8 @@
 
 	ret = lzc_clone(target, zhp->zfs_name, props);
 	nvlist_free(props);
+	if (ret == 0)
+		libzfs_log_event(hdl, target);
 
 	if (ret != 0) {
 		switch (errno) {
@@ -3737,9 +3890,6 @@
 		return (zfs_error(hdl, EZFS_BADTYPE, errbuf));
 	}
 
-	if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
-		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
-
 	ret = lzc_promote(zhp->zfs_name, snapname, sizeof (snapname));
 
 	if (ret != 0) {
@@ -3783,24 +3933,6 @@
 	return (rv);
 }
 
-int
-zfs_remap_indirects(libzfs_handle_t *hdl, const char *fs)
-{
-	int err;
-	char errbuf[1024];
-
-	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
-	    "cannot remap filesystem '%s' "), fs);
-
-	err = lzc_remap(fs);
-
-	if (err != 0) {
-		(void) zfs_standard_error(hdl, err, errbuf);
-	}
-
-	return (err);
-}
-
 /*
  * Creates snapshots.  The keys in the snaps nvlist are the snapshots to be
  * created.
@@ -3849,6 +3981,11 @@
 	zpool_close(zpool_hdl);
 
 	ret = lzc_snapshot(snaps, props, &errors);
+	if (ret == 0) {
+		for (elem = nvlist_next_nvpair(snaps, NULL); elem != NULL;
+		    elem = nvlist_next_nvpair(snaps, elem))
+			libzfs_log_event(hdl, nvpair_name(elem));
+	}
 
 	if (ret != 0) {
 		boolean_t printed = B_FALSE;
@@ -4097,9 +4234,11 @@
 	(void) snprintf(errbuf, sizeof (errbuf), dgettext(TEXT_DOMAIN,
 	    "cannot rename to '%s'"), target);
 
-	/* make sure source name is valid */
-	if (!zfs_validate_name(hdl, zhp->zfs_name, zhp->zfs_type, B_TRUE))
-		return (zfs_error(hdl, EZFS_INVALIDNAME, errbuf));
+	if (zhp->zfs_type == ZFS_TYPE_AUTOSNAP) {
+			zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
+			    "autosnapshots cannot be renamed"));
+			return (zfs_error(hdl, EZFS_PERM, errbuf));
+	}
 
 	/*
 	 * Make sure the target name is valid
@@ -4709,6 +4848,8 @@
 		fnvlist_free(torelease);
 	}
 
+	fnvlist_free(existing_holds);
+
 	if (ha->recursive)
 		rv = zfs_iter_filesystems(zhp, zfs_release_one, ha);
 	zfs_close(zhp);
