--- old/usr/src/cmd/zpool/zpool_vdev.c	Mon Aug  5 17:15:44 2019
+++ new/usr/src/cmd/zpool/zpool_vdev.c	Mon Aug  5 17:15:44 2019
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright 2013 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  * Copyright 2016 Igor Kozhukhov <ikozhukhov@gmail.com>.
  */
@@ -387,7 +388,7 @@
  * 	xxx		Shorthand for /dev/dsk/xxx
  */
 static nvlist_t *
-make_leaf_vdev(const char *arg, uint64_t is_log)
+make_leaf_vdev(const char *arg, uint64_t is_log, uint64_t is_special)
 {
 	char path[MAXPATHLEN];
 	struct stat64 statbuf;
@@ -471,6 +472,8 @@
 	verify(nvlist_add_string(vdev, ZPOOL_CONFIG_PATH, path) == 0);
 	verify(nvlist_add_string(vdev, ZPOOL_CONFIG_TYPE, type) == 0);
 	verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+	verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_IS_SPECIAL,
+	    is_special) == 0);
 	if (strcmp(type, VDEV_TYPE_DISK) == 0)
 		verify(nvlist_add_uint64(vdev, ZPOOL_CONFIG_WHOLE_DISK,
 		    (uint64_t)wholedisk) == 0);
@@ -628,11 +631,9 @@
 
 				/*
 				 * If this is a replacing or spare vdev, then
-				 * get the real first child of the vdev: do this
-				 * in a loop because replacing and spare vdevs
-				 * can be nested.
+				 * get the real first child of the vdev.
 				 */
-				while (strcmp(childtype,
+				if (strcmp(childtype,
 				    VDEV_TYPE_REPLACING) == 0 ||
 				    strcmp(childtype, VDEV_TYPE_SPARE) == 0) {
 					nvlist_t **rchild;
@@ -1183,6 +1184,12 @@
 		return (VDEV_TYPE_L2CACHE);
 	}
 
+	if (strcmp(type, "special") == 0) {
+		if (mindev != NULL)
+			*mindev = 1;
+		return (VDEV_TYPE_SPECIAL);
+	}
+
 	return (NULL);
 }
 
@@ -1197,9 +1204,10 @@
 {
 	nvlist_t *nvroot, *nv, **top, **spares, **l2cache;
 	int t, toplevels, mindev, maxdev, nspares, nlogs, nl2cache;
+	int nspecial = 0;
 	const char *type;
-	uint64_t is_log;
-	boolean_t seen_logs;
+	boolean_t is_log, seen_logs;
+	boolean_t is_special, seen_special;
 
 	top = NULL;
 	toplevels = 0;
@@ -1210,6 +1218,8 @@
 	nl2cache = 0;
 	is_log = B_FALSE;
 	seen_logs = B_FALSE;
+	is_special = B_FALSE;
+	seen_special = B_FALSE;
 
 	while (argc > 0) {
 		nv = NULL;
@@ -1231,6 +1241,7 @@
 					return (NULL);
 				}
 				is_log = B_FALSE;
+				is_special = B_FALSE;
 			}
 
 			if (strcmp(type, VDEV_TYPE_LOG) == 0) {
@@ -1243,6 +1254,7 @@
 				}
 				seen_logs = B_TRUE;
 				is_log = B_TRUE;
+				is_special = B_FALSE;
 				argc--;
 				argv++;
 				/*
@@ -1261,8 +1273,29 @@
 					return (NULL);
 				}
 				is_log = B_FALSE;
+				is_special = B_FALSE;
 			}
 
+			if (strcmp(type, VDEV_TYPE_SPECIAL) == 0) {
+				if (seen_special) {
+					(void) fprintf(stderr,
+					    gettext("invalid vdev "
+					    "specification: 'special' can be "
+					    "specified only once\n"));
+					return (NULL);
+				}
+				seen_special = B_TRUE;
+				is_log = B_FALSE;
+				is_special = B_TRUE;
+				argc--;
+				argv++;
+				/*
+				 * A special is not a real grouping device.
+				 * We just set is_special and continue.
+				 */
+				continue;
+			}
+
 			if (is_log) {
 				if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
 					(void) fprintf(stderr,
@@ -1274,6 +1307,17 @@
 				nlogs++;
 			}
 
+			if (is_special) {
+				if (strcmp(type, VDEV_TYPE_MIRROR) != 0) {
+					(void) fprintf(stderr,
+					    gettext("invalid vdev "
+					    "specification: unsupported "
+					    "'special' device: %s\n"), type);
+					return (NULL);
+				}
+				nspecial++;
+			}
+
 			for (c = 1; c < argc; c++) {
 				if (is_grouping(argv[c], NULL, NULL) != NULL)
 					break;
@@ -1282,8 +1326,9 @@
 				    children * sizeof (nvlist_t *));
 				if (child == NULL)
 					zpool_no_memory();
-				if ((nv = make_leaf_vdev(argv[c], B_FALSE))
-				    == NULL)
+				if ((nv = make_leaf_vdev(argv[c],
+				    (uint64_t)B_FALSE,
+				    (uint64_t)B_FALSE)) == NULL)
 					return (NULL);
 				child[children - 1] = nv;
 			}
@@ -1319,7 +1364,11 @@
 				verify(nvlist_add_string(nv, ZPOOL_CONFIG_TYPE,
 				    type) == 0);
 				verify(nvlist_add_uint64(nv,
-				    ZPOOL_CONFIG_IS_LOG, is_log) == 0);
+				    ZPOOL_CONFIG_IS_LOG,
+				    (uint64_t)is_log) == 0);
+				verify(nvlist_add_uint64(nv,
+				    ZPOOL_CONFIG_IS_SPECIAL,
+				    (uint64_t)is_special) == 0);
 				if (strcmp(type, VDEV_TYPE_RAIDZ) == 0) {
 					verify(nvlist_add_uint64(nv,
 					    ZPOOL_CONFIG_NPARITY,
@@ -1338,10 +1387,13 @@
 			 * We have a device.  Pass off to make_leaf_vdev() to
 			 * construct the appropriate nvlist describing the vdev.
 			 */
-			if ((nv = make_leaf_vdev(argv[0], is_log)) == NULL)
+			if ((nv = make_leaf_vdev(argv[0], (uint64_t)is_log,
+			    (uint64_t)is_special)) == NULL)
 				return (NULL);
 			if (is_log)
 				nlogs++;
+			if (is_special)
+				nspecial++;
 			argc--;
 			argv++;
 		}
@@ -1359,6 +1411,12 @@
 		    "specified\n"));
 		return (NULL);
 	}
+
+	if (seen_special && nspecial == 0) {
+		(void) fprintf(stderr, gettext("invalid vdev specification: "
+		    "special requires at least 1 device\n"));
+		return (NULL);
+	}
 
 	if (seen_logs && nlogs == 0) {
 		(void) fprintf(stderr, gettext("invalid vdev specification: "
