--- old/usr/src/cmd/zfs/zfs_main.c	Mon Aug  5 17:15:42 2019
+++ new/usr/src/cmd/zfs/zfs_main.c	Mon Aug  5 17:15:42 2019
@@ -28,7 +28,7 @@
  * Copyright (c) 2013 Steven Hartland.  All rights reserved.
  * Copyright (c) 2014 Integros [integros.com]
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
- * Copyright 2016 Nexenta Systems, Inc.
+ * Copyright 2018 Nexenta Systems, Inc.
  */
 
 #include <assert.h>
@@ -107,7 +107,6 @@
 static int zfs_do_release(int argc, char **argv);
 static int zfs_do_diff(int argc, char **argv);
 static int zfs_do_bookmark(int argc, char **argv);
-static int zfs_do_remap(int argc, char **argv);
 static int zfs_do_channel_program(int argc, char **argv);
 
 /*
@@ -155,7 +154,6 @@
 	HELP_HOLDS,
 	HELP_RELEASE,
 	HELP_DIFF,
-	HELP_REMAP,
 	HELP_BOOKMARK,
 	HELP_CHANNEL_PROGRAM,
 } zfs_help_t;
@@ -212,7 +210,6 @@
 	{ "holds",	zfs_do_holds,		HELP_HOLDS		},
 	{ "release",	zfs_do_release,		HELP_RELEASE		},
 	{ "diff",	zfs_do_diff,		HELP_DIFF		},
-	{ "remap",	zfs_do_remap,		HELP_REMAP		},
 };
 
 #define	NCOMMAND	(sizeof (command_table) / sizeof (command_table[0]))
@@ -251,7 +248,7 @@
 	case HELP_LIST:
 		return (gettext("\tlist [-Hp] [-r|-d max] [-o property[,...]] "
 		    "[-s property]...\n\t    [-S property]... [-t type[,...]] "
-		    "[filesystem|volume|snapshot] ...\n"));
+		    "[filesystem|volume|snapshot|autosnapshot] ...\n"));
 	case HELP_MOUNT:
 		return (gettext("\tmount\n"
 		    "\tmount [-vO] [-o opts] <-a | filesystem>\n"));
@@ -258,10 +255,11 @@
 	case HELP_PROMOTE:
 		return (gettext("\tpromote <clone-filesystem>\n"));
 	case HELP_RECEIVE:
-		return (gettext("\treceive [-vnsFu] <filesystem|volume|"
+		return (gettext("\treceive [-vnsFKu] <filesystem|volume|"
 		    "snapshot>\n"
-		    "\treceive [-vnsFu] [-o origin=<snapshot>] [-d | -e] "
-		    "<filesystem>\n"
+		    "\treceive [-vnsFKu] [-d |-e] [-o <property=value>]... "
+		    "[-x <property>]... [-l <filesystem|volume>] ...  "
+		    "<filesystem|volume|snapshot>\n"
 		    "\treceive -A <filesystem|volume>\n"));
 	case HELP_RENAME:
 		return (gettext("\trename [-f] <filesystem|volume|snapshot> "
@@ -271,7 +269,7 @@
 	case HELP_ROLLBACK:
 		return (gettext("\trollback [-rRf] <snapshot>\n"));
 	case HELP_SEND:
-		return (gettext("\tsend [-DnPpRvLec] [-[iI] snapshot] "
+		return (gettext("\tsend [-DnPpRvLesc] [-[iI] snapshot] "
 		    "<snapshot>\n"
 		    "\tsend [-Le] [-i snapshot|bookmark] "
 		    "<filesystem|volume|snapshot>\n"
@@ -329,8 +327,6 @@
 	case HELP_DIFF:
 		return (gettext("\tdiff [-FHt] <snapshot> "
 		    "[snapshot|filesystem]\n"));
-	case HELP_REMAP:
-		return (gettext("\tremap <filesystem | volume>\n"));
 	case HELP_BOOKMARK:
 		return (gettext("\tbookmark <snapshot> <bookmark>\n"));
 	case HELP_CHANNEL_PROGRAM:
@@ -511,6 +507,19 @@
 }
 
 /*
+ * Add parameter to the list if it's not in there already
+ */
+static void
+add_unique_option(nvlist_t *props, char *propname)
+{
+	if (nvlist_lookup_string(props, propname, NULL) != 0) {
+		if (nvlist_add_boolean(props, propname) != 0) {
+			nomem();
+		}
+	}
+}
+
+/*
  * Take a property=value argument string and add it to the given nvlist.
  * Modifies the argument inplace.
  */
@@ -545,7 +554,7 @@
 	depth = (int)strtol(opt, &tmp, 0);
 	if (*tmp) {
 		(void) fprintf(stderr,
-		    gettext("%s is not an integer\n"), optarg);
+		    gettext("%s is not an integer\n"), opt);
 		usage(B_FALSE);
 	}
 	if (depth < 0) {
@@ -1076,7 +1085,8 @@
 	 * simply do all snap deletions and then all fs deletions,
 	 * because we must delete a clone before its origin.
 	 */
-	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT) {
+	if (zfs_get_type(zhp) == ZFS_TYPE_SNAPSHOT ||
+	    zfs_get_type(zhp) == ZFS_TYPE_AUTOSNAP) {
 		fnvlist_add_boolean(cb->cb_batchedsnaps, name);
 	} else {
 		int error = zfs_destroy_snaps_nvl(g_zfs,
@@ -1238,6 +1248,20 @@
 }
 
 static int
+unmount_callback(zfs_handle_t *zhp, void *arg)
+{
+	destroy_cbdata_t *cb = arg;
+	int err = 0;
+
+	if (zfs_is_mounted(zhp, NULL))
+		err = zfs_unmount(zhp, NULL, cb->cb_force ? MS_FORCE : 0);
+
+	zfs_close(zhp);
+
+	return (err);
+}
+
+static int
 zfs_do_destroy(int argc, char **argv)
 {
 	destroy_cbdata_t cb = { 0 };
@@ -1406,7 +1430,59 @@
 
 		cb.cb_target = zhp;
 
+		err = zfs_check_krrp(g_zfs, argv[0]);
+
 		/*
+		 * ENOTSUP means that autosnaper doesn't handle this dataset
+		 * and the basic detruction can be used.
+		 */
+		if (err != ENOTSUP) {
+			rv = 1;
+			if (!cb.cb_recurse || !cb.cb_doclones) {
+				(void) fprintf(stderr,
+				    gettext("cannot destroy '%s': "
+				    "dataset under autosnap can be destroyed "
+				    "with -R only\n"), zfs_get_name(zhp));
+			} else if (err == ECHILD) {
+				(void) fprintf(stderr,
+				    gettext("cannot destroy '%s': "
+				    "dataset has children under krrp\n"),
+				    zfs_get_name(zhp));
+			} else if (err == EBUSY) {
+				(void) fprintf(stderr,
+				    gettext("cannot destroy '%s': "
+				    "dataset is root of a krrp task\n"),
+				    zfs_get_name(zhp));
+			} else if (err && err != EUSERS) {
+				(void) fprintf(stderr,
+				    gettext("cannot destroy '%s': "
+				    "unexpected error : %d\n"),
+				    zfs_get_name(zhp), err);
+			} else {
+				/*
+				 * err == 0 || err == EUSERS means the ds can
+				 * be destroyed with atomical destroy
+				 */
+				err = zfs_iter_dependents(zhp, B_FALSE,
+				    unmount_callback, &cb);
+				if (!err) {
+					err = unmount_callback(
+					    zfs_handle_dup(zhp), &cb);
+				}
+				if (!err) {
+					err = zfs_destroy_atomically(
+					    zhp, B_TRUE);
+				}
+
+				if (!err)
+					rv = 0;
+			}
+			goto out;
+		}
+
+		err = 0;
+
+		/*
 		 * Perform an explicit check for pools before going any further.
 		 */
 		if (!cb.cb_recurse && strchr(zfs_get_name(zhp), '/') == NULL &&
@@ -2079,6 +2155,7 @@
 			 * the normal history logging that happens in main().
 			 */
 			(void) zpool_log_history(g_zfs, history_str);
+			verify(zpool_stage_history(g_zfs, history_str) == 0);
 			log_history = B_FALSE;
 		}
 		if (zfs_prop_set(zhp, "version", verstr) == 0)
@@ -3126,7 +3203,7 @@
 			while (*optarg != '\0') {
 				static char *type_subopts[] = { "filesystem",
 				    "volume", "snapshot", "snap", "bookmark",
-				    "all", NULL };
+				    "all", "autosnapshot", NULL };
 
 				switch (getsubopt(&optarg, type_subopts,
 				    &value)) {
@@ -3145,8 +3222,12 @@
 					break;
 				case 5:
 					types = ZFS_TYPE_DATASET |
-					    ZFS_TYPE_BOOKMARK;
+					    ZFS_TYPE_BOOKMARK |
+					    ZFS_TYPE_AUTOSNAP;
 					break;
+				case 6:
+					types |= ZFS_TYPE_AUTOSNAP;
+					break;
 				default:
 					(void) fprintf(stderr,
 					    gettext("invalid type '%s'\n"),
@@ -3746,7 +3827,7 @@
 	};
 
 	/* check options */
-	while ((c = getopt_long(argc, argv, ":i:I:RbDpvnPLet:c", long_options,
+	while ((c = getopt_long(argc, argv, ":i:I:RbDpvnPLest:c", long_options,
 	    NULL)) != -1) {
 		switch (c) {
 		case 'i':
@@ -3788,6 +3869,9 @@
 		case 'e':
 			flags.embed_data = B_TRUE;
 			break;
+		case 's':
+			flags.sendsize = B_TRUE;
+			break;
 		case 't':
 			resume_token = optarg;
 			break;
@@ -3862,7 +3946,17 @@
 		}
 	}
 
-	if (!flags.dryrun && isatty(STDOUT_FILENO)) {
+	if (flags.sendsize) {
+		int fd = open("/dev/null", O_WRONLY|O_LARGEFILE);
+		if (fd < 0) {
+			perror("failed to open /dev/null");
+			return (1);
+		}
+		if ((dup2(fd, STDOUT_FILENO)) < 0) {
+			perror("failed to dup2(/dev/null,STDOUT_FILENO)");
+			return (1);
+		}
+	} else if (!flags.dryrun && isatty(STDOUT_FILENO)) {
 		(void) fprintf(stderr,
 		    gettext("Error: Stream can not be written to a terminal.\n"
 		    "You must redirect standard output.\n"));
@@ -3987,21 +4081,23 @@
 zfs_do_receive(int argc, char **argv)
 {
 	int c, err = 0;
+	nvlist_t *exprops, *limitds;
 	recvflags_t flags = { 0 };
 	boolean_t abort_resumable = B_FALSE;
 
-	nvlist_t *props;
-	nvpair_t *nvp = NULL;
-
-	if (nvlist_alloc(&props, NV_UNIQUE_NAME, 0) != 0)
+	if (nvlist_alloc(&exprops, NV_UNIQUE_NAME, 0) != 0)
 		nomem();
+	if (nvlist_alloc(&limitds, NV_UNIQUE_NAME, 0) != 0)
+		nomem();
 
 	/* check options */
-	while ((c = getopt(argc, argv, ":o:denuvFsA")) != -1) {
+	while ((c = getopt(argc, argv, ":del:no:uvx:FsAK")) != -1) {
 		switch (c) {
 		case 'o':
-			if (parseprop(props, optarg) != 0)
-				return (1);
+			if (parseprop(exprops, optarg) != 0) {
+				err = 1;
+				goto recverror;
+			}
 			break;
 		case 'd':
 			flags.isprefix = B_TRUE;
@@ -4010,6 +4106,9 @@
 			flags.isprefix = B_TRUE;
 			flags.istail = B_TRUE;
 			break;
+		case 'l':
+			add_unique_option(limitds, optarg);
+			break;
 		case 'n':
 			flags.dryrun = B_TRUE;
 			break;
@@ -4019,6 +4118,9 @@
 		case 'v':
 			flags.verbose = B_TRUE;
 			break;
+		case 'x':
+			add_unique_option(exprops, optarg);
+			break;
 		case 's':
 			flags.resumable = B_TRUE;
 			break;
@@ -4028,6 +4130,9 @@
 		case 'A':
 			abort_resumable = B_TRUE;
 			break;
+		case 'K':
+			flags.keepsnap = B_TRUE;
+			break;
 		case ':':
 			(void) fprintf(stderr, gettext("missing argument for "
 			    "'%c' option\n"), optopt);
@@ -4053,13 +4158,6 @@
 		usage(B_FALSE);
 	}
 
-	while ((nvp = nvlist_next_nvpair(props, nvp))) {
-		if (strcmp(nvpair_name(nvp), "origin") != 0) {
-			(void) fprintf(stderr, gettext("invalid option"));
-			usage(B_FALSE);
-		}
-	}
-
 	if (abort_resumable) {
 		if (flags.isprefix || flags.istail || flags.dryrun ||
 		    flags.resumable || flags.nomount) {
@@ -4105,8 +4203,14 @@
 		    "You must redirect standard input.\n"));
 		return (1);
 	}
-	err = zfs_receive(g_zfs, argv[0], props, &flags, STDIN_FILENO, NULL);
 
+	err = zfs_receive(g_zfs, argv[0], &flags, STDIN_FILENO, exprops,
+	    limitds, NULL);
+
+recverror:
+	nvlist_free(exprops);
+	nvlist_free(limitds);
+
 	return (err != 0);
 }
 
@@ -4136,7 +4240,6 @@
 #define	ZFS_DELEG_PERM_RELEASE		"release"
 #define	ZFS_DELEG_PERM_DIFF		"diff"
 #define	ZFS_DELEG_PERM_BOOKMARK		"bookmark"
-#define	ZFS_DELEG_PERM_REMAP		"remap"
 
 #define	ZFS_NUM_DELEG_NOTES ZFS_DELEG_NOTE_NONE
 
@@ -4157,7 +4260,6 @@
 	{ ZFS_DELEG_PERM_SHARE, ZFS_DELEG_NOTE_SHARE },
 	{ ZFS_DELEG_PERM_SNAPSHOT, ZFS_DELEG_NOTE_SNAPSHOT },
 	{ ZFS_DELEG_PERM_BOOKMARK, ZFS_DELEG_NOTE_BOOKMARK },
-	{ ZFS_DELEG_PERM_REMAP, ZFS_DELEG_NOTE_REMAP },
 
 	{ ZFS_DELEG_PERM_GROUPQUOTA, ZFS_DELEG_NOTE_GROUPQUOTA },
 	{ ZFS_DELEG_PERM_GROUPUSED, ZFS_DELEG_NOTE_GROUPUSED },
@@ -5603,6 +5705,8 @@
 			uint64_t val = 0;
 			time_t time;
 			struct tm t;
+			char sep = scripted ? '\t' : ' ';
+			size_t sepnum = scripted ? 1 : 2;
 
 			(void) nvpair_value_uint64(nvp2, &val);
 			time = (time_t)val;
@@ -5610,13 +5714,8 @@
 			(void) strftime(tsbuf, DATETIME_BUF_LEN,
 			    gettext(STRFTIME_FMT_STR), &t);
 
-			if (scripted) {
-				(void) printf("%s\t%s\t%s\n", zname,
-				    tagname, tsbuf);
-			} else {
-				(void) printf("%-*s  %-*s  %s\n", nwidth,
-				    zname, tagwidth, tagname, tsbuf);
-			}
+			(void) printf("%-*s%*c%-*s%*c%s\n", nwidth, zname,
+			    sepnum, sep, tagwidth, tagname, sepnum, sep, tsbuf);
 		}
 	}
 }
@@ -6534,6 +6633,32 @@
 		}
 
 		/*
+		 * Initilialize libshare SA_INIT_SHARE_API_SELECTIVE here
+		 * to avoid unneccesary load/unload of the libshare API
+		 * per shared dataset downstream.
+		 */
+		if (op == OP_SHARE) {
+			zfs_handle_t **dslist = NULL;
+			size_t count = 0;
+			get_all_datasets(&dslist, &count, B_FALSE);
+
+			if (count > 0) {
+				sa_init_selective_arg_t sharearg;
+				sharearg.zhandle_arr = dslist;
+				sharearg.zhandle_len = count;
+				if ((ret = zfs_init_libshare_arg(
+				    zfs_get_handle(dslist[0]),
+				    SA_INIT_SHARE_API_SELECTIVE, &sharearg))
+				    != SA_OK) {
+					(void) fprintf(stderr, gettext(
+					    "Could not initialize libshare,"
+					    "%d"), ret);
+					return (1);
+				}
+			}
+		}
+
+		/*
 		 * Walk the AVL tree in reverse, unmounting each filesystem and
 		 * removing it from the AVL tree in the process.
 		 */
@@ -6863,7 +6988,7 @@
 
 	if (argc < 1) {
 		(void) fprintf(stderr,
-		    gettext("must provide at least one snapshot name\n"));
+		gettext("must provide at least one snapshot name\n"));
 		usage(B_FALSE);
 	}
 
@@ -6904,22 +7029,6 @@
 	return (err != 0);
 }
 
-static int
-zfs_do_remap(int argc, char **argv)
-{
-	const char *fsname;
-	int err = 0;
-	if (argc != 2) {
-		(void) fprintf(stderr, gettext("wrong number of arguments\n"));
-		usage(B_FALSE);
-	}
-
-	fsname = argv[1];
-	err = zfs_remap_indirects(g_zfs, fsname);
-
-	return (err);
-}
-
 /*
  * zfs bookmark <fs@snap> <fs#bmark>
  *
@@ -7239,6 +7348,7 @@
 	}
 
 	zfs_save_arguments(argc, argv, history_str, sizeof (history_str));
+	verify(zpool_stage_history(g_zfs, history_str) == 0);
 
 	libzfs_print_on_error(g_zfs, B_TRUE);
 
