[Pkg-zfsonlinux-devel] [SCM] zfs branch, upstream, updated. upstream/0.6.5.5-1-g4e820b5

Aron Xu aron at debian.org
Wed Mar 23 23:19:30 UTC 2016


The following commit has been merged in the upstream branch:
commit 4e820b5a512306a70cf272ab773087121ac40e3a
Author: Aron Xu <aron at debian.org>
Date:   Thu Mar 24 07:19:11 2016 +0800

    Imported Upstream version 0.6.5.6

diff --git a/META b/META
index ea5d644..8d4c352 100644
--- a/META
+++ b/META
@@ -1,7 +1,7 @@
 Meta:         1
 Name:         zfs
 Branch:       1.0
-Version:      0.6.5.5
+Version:      0.6.5.6
 Release:      1
 Release-Tags: relext
 License:      CDDL
diff --git a/cmd/zdb/zdb.c b/cmd/zdb/zdb.c
index 56f5670..59a0b1b 100644
--- a/cmd/zdb/zdb.c
+++ b/cmd/zdb/zdb.c
@@ -3357,8 +3357,10 @@ zdb_read_block(char *thing, spa_t *spa)
 				continue;
 
 			p = &flagstr[i + 1];
-			if (bit == ZDB_FLAG_PRINT_BLKPTR)
+			if (bit == ZDB_FLAG_PRINT_BLKPTR) {
 				blkptr_offset = strtoull(p, &p, 16);
+				i = p - &flagstr[i + 1];
+			}
 			if (*p != ':' && *p != '\0') {
 				(void) printf("***Invalid flag arg: '%s'\n", s);
 				free(dup);
diff --git a/cmd/zpool/zpool_main.c b/cmd/zpool/zpool_main.c
index aa9b21d..8f6916a 100644
--- a/cmd/zpool/zpool_main.c
+++ b/cmd/zpool/zpool_main.c
@@ -207,7 +207,7 @@ static const char *
 get_usage(zpool_help_t idx) {
 	switch (idx) {
 	case HELP_ADD:
-		return (gettext("\tadd [-fn] [-o property=value] "
+		return (gettext("\tadd [-fgLnP] [-o property=value] "
 		    "<pool> <vdev> ...\n"));
 	case HELP_ATTACH:
 		return (gettext("\tattach [-f] [-o property=value] "
@@ -237,12 +237,12 @@ get_usage(zpool_help_t idx) {
 		    "[-R root] [-F [-n]]\n"
 		    "\t    <pool | id> [newpool]\n"));
 	case HELP_IOSTAT:
-		return (gettext("\tiostat [-v] [-T d|u] [-y] [pool] ... "
+		return (gettext("\tiostat [-gLPvy] [-T d|u] [pool] ... "
 		    "[interval [count]]\n"));
 	case HELP_LABELCLEAR:
 		return (gettext("\tlabelclear [-f] <vdev>\n"));
 	case HELP_LIST:
-		return (gettext("\tlist [-Hv] [-o property[,...]] "
+		return (gettext("\tlist [-gHLPv] [-o property[,...]] "
 		    "[-T d|u] [pool] ... [interval [count]]\n"));
 	case HELP_OFFLINE:
 		return (gettext("\toffline [-t] <pool> <device> ...\n"));
@@ -258,8 +258,8 @@ get_usage(zpool_help_t idx) {
 	case HELP_SCRUB:
 		return (gettext("\tscrub [-s] <pool> ...\n"));
 	case HELP_STATUS:
-		return (gettext("\tstatus [-vxD] [-T d|u] [pool] ... [interval "
-		    "[count]]\n"));
+		return (gettext("\tstatus [-gLPvxD] [-T d|u] [pool] ... "
+		    "[interval [count]]\n"));
 	case HELP_UPGRADE:
 		return (gettext("\tupgrade\n"
 		    "\tupgrade -v\n"
@@ -272,7 +272,7 @@ get_usage(zpool_help_t idx) {
 	case HELP_SET:
 		return (gettext("\tset <property=value> <pool> \n"));
 	case HELP_SPLIT:
-		return (gettext("\tsplit [-n] [-R altroot] [-o mntopts]\n"
+		return (gettext("\tsplit [-gLnP] [-R altroot] [-o mntopts]\n"
 		    "\t    [-o property=value] <pool> <newpool> "
 		    "[<device> ...]\n"));
 	case HELP_REGUID:
@@ -371,7 +371,7 @@ usage(boolean_t requested)
 
 void
 print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
-    boolean_t print_logs)
+    boolean_t print_logs, int name_flags)
 {
 	nvlist_t **child;
 	uint_t c, children;
@@ -392,9 +392,9 @@ print_vdev_tree(zpool_handle_t *zhp, const char *name, nvlist_t *nv, int indent,
 		if ((is_log && !print_logs) || (!is_log && print_logs))
 			continue;
 
-		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+		vname = zpool_vdev_name(g_zfs, zhp, child[c], name_flags);
 		print_vdev_tree(zhp, vname, child[c], indent + 2,
-		    B_FALSE);
+		    B_FALSE, name_flags);
 		free(vname);
 	}
 }
@@ -502,12 +502,15 @@ add_prop_list_default(const char *propname, char *propval, nvlist_t **props,
 }
 
 /*
- * zpool add [-fn] [-o property=value] <pool> <vdev> ...
+ * zpool add [-fgLnP] [-o property=value] <pool> <vdev> ...
  *
  *	-f	Force addition of devices, even if they appear in use
+ *	-g	Display guid for individual vdev name.
+ *	-L	Follow links when resolving vdev path name.
  *	-n	Do not add the devices, but display the resulting layout if
  *		they were to be added.
  *	-o	Set property=value.
+ *	-P	Display full path for vdev name.
  *
  * Adds the given vdevs to 'pool'.  As with create, the bulk of this work is
  * handled by get_vdev_spec(), which constructs the nvlist needed to pass to
@@ -518,6 +521,7 @@ zpool_do_add(int argc, char **argv)
 {
 	boolean_t force = B_FALSE;
 	boolean_t dryrun = B_FALSE;
+	int name_flags = 0;
 	int c;
 	nvlist_t *nvroot;
 	char *poolname;
@@ -528,11 +532,17 @@ zpool_do_add(int argc, char **argv)
 	char *propval;
 
 	/* check options */
-	while ((c = getopt(argc, argv, "fno:")) != -1) {
+	while ((c = getopt(argc, argv, "fgLno:P")) != -1) {
 		switch (c) {
 		case 'f':
 			force = B_TRUE;
 			break;
+		case 'g':
+			name_flags |= VDEV_NAME_GUID;
+			break;
+		case 'L':
+			name_flags |= VDEV_NAME_FOLLOW_LINKS;
+			break;
 		case 'n':
 			dryrun = B_TRUE;
 			break;
@@ -549,6 +559,9 @@ zpool_do_add(int argc, char **argv)
 			    (add_prop_list(optarg, propval, &props, B_TRUE)))
 				usage(B_FALSE);
 			break;
+		case 'P':
+			name_flags |= VDEV_NAME_PATH;
+			break;
 		case '?':
 			(void) fprintf(stderr, gettext("invalid option '%c'\n"),
 			    optopt);
@@ -606,15 +619,19 @@ zpool_do_add(int argc, char **argv)
 		    "configuration:\n"), zpool_get_name(zhp));
 
 		/* print original main pool and new tree */
-		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE);
-		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE);
+		print_vdev_tree(zhp, poolname, poolnvroot, 0, B_FALSE,
+		    name_flags);
+		print_vdev_tree(zhp, NULL, nvroot, 0, B_FALSE, name_flags);
 
 		/* Do the same for the logs */
 		if (num_logs(poolnvroot) > 0) {
-			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE);
-			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE);
+			print_vdev_tree(zhp, "logs", poolnvroot, 0, B_TRUE,
+			    name_flags);
+			print_vdev_tree(zhp, NULL, nvroot, 0, B_TRUE,
+			    name_flags);
 		} else if (num_logs(nvroot) > 0) {
-			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE);
+			print_vdev_tree(zhp, "logs", nvroot, 0, B_TRUE,
+			    name_flags);
 		}
 
 		/* Do the same for the caches */
@@ -624,7 +641,7 @@ zpool_do_add(int argc, char **argv)
 			(void) printf(gettext("\tcache\n"));
 			for (c = 0; c < l2children; c++) {
 				vname = zpool_vdev_name(g_zfs, NULL,
-				    l2child[c], B_FALSE);
+				    l2child[c], name_flags);
 				(void) printf("\t  %s\n", vname);
 				free(vname);
 			}
@@ -635,7 +652,7 @@ zpool_do_add(int argc, char **argv)
 				(void) printf(gettext("\tcache\n"));
 			for (c = 0; c < l2children; c++) {
 				vname = zpool_vdev_name(g_zfs, NULL,
-				    l2child[c], B_FALSE);
+				    l2child[c], name_flags);
 				(void) printf("\t  %s\n", vname);
 				free(vname);
 			}
@@ -1082,9 +1099,9 @@ zpool_do_create(int argc, char **argv)
 		(void) printf(gettext("would create '%s' with the "
 		    "following layout:\n\n"), poolname);
 
-		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE);
+		print_vdev_tree(NULL, poolname, nvroot, 0, B_FALSE, 0);
 		if (num_logs(nvroot) > 0)
-			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE);
+			print_vdev_tree(NULL, "logs", nvroot, 0, B_TRUE, 0);
 
 		ret = 0;
 	} else {
@@ -1311,13 +1328,15 @@ zpool_do_export(int argc, char **argv)
  * name column.
  */
 static int
-max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
+max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max,
+    int name_flags)
 {
-	char *name = zpool_vdev_name(g_zfs, zhp, nv, B_TRUE);
+	char *name;
 	nvlist_t **child;
 	uint_t c, children;
 	int ret;
 
+	name = zpool_vdev_name(g_zfs, zhp, nv, name_flags | VDEV_NAME_TYPE_ID);
 	if (strlen(name) + depth > max)
 		max = strlen(name) + depth;
 
@@ -1327,7 +1346,7 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
 	    &child, &children) == 0) {
 		for (c = 0; c < children; c++)
 			if ((ret = max_width(zhp, child[c], depth + 2,
-			    max)) > max)
+			    max, name_flags)) > max)
 				max = ret;
 	}
 
@@ -1335,7 +1354,7 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
 	    &child, &children) == 0) {
 		for (c = 0; c < children; c++)
 			if ((ret = max_width(zhp, child[c], depth + 2,
-			    max)) > max)
+			    max, name_flags)) > max)
 				max = ret;
 	}
 
@@ -1343,11 +1362,10 @@ max_width(zpool_handle_t *zhp, nvlist_t *nv, int depth, int max)
 	    &child, &children) == 0) {
 		for (c = 0; c < children; c++)
 			if ((ret = max_width(zhp, child[c], depth + 2,
-			    max)) > max)
+			    max, name_flags)) > max)
 				max = ret;
 	}
 
-
 	return (max);
 }
 
@@ -1399,9 +1417,9 @@ find_spare(zpool_handle_t *zhp, void *data)
 /*
  * Print out configuration state as requested by status_callback.
  */
-void
+static void
 print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
-    int namewidth, int depth, boolean_t isspare)
+    int namewidth, int depth, boolean_t isspare, int name_flags)
 {
 	nvlist_t **child;
 	uint_t c, children;
@@ -1537,20 +1555,21 @@ print_status_config(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
 		    &ishole);
 		if (islog || ishole)
 			continue;
-		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
+		vname = zpool_vdev_name(g_zfs, zhp, child[c],
+		    name_flags | VDEV_NAME_TYPE_ID);
 		print_status_config(zhp, vname, child[c],
-		    namewidth, depth + 2, isspare);
+		    namewidth, depth + 2, isspare, name_flags);
 		free(vname);
 	}
 }
 
-
 /*
  * Print the configuration of an exported pool.  Iterate over all vdevs in the
  * pool, printing out the name and status for each one.
  */
-void
-print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
+static void
+print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth,
+    int name_flags)
 {
 	nvlist_t **child;
 	uint_t c, children;
@@ -1615,8 +1634,10 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
 		if (is_log)
 			continue;
 
-		vname = zpool_vdev_name(g_zfs, NULL, child[c], B_TRUE);
-		print_import_config(vname, child[c], namewidth, depth + 2);
+		vname = zpool_vdev_name(g_zfs, NULL, child[c],
+		    name_flags | VDEV_NAME_TYPE_ID);
+		print_import_config(vname, child[c], namewidth, depth + 2,
+		    name_flags);
 		free(vname);
 	}
 
@@ -1624,7 +1645,8 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
 	    &child, &children) == 0) {
 		(void) printf(gettext("\tcache\n"));
 		for (c = 0; c < children; c++) {
-			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
+			vname = zpool_vdev_name(g_zfs, NULL, child[c],
+			    name_flags);
 			(void) printf("\t  %s\n", vname);
 			free(vname);
 		}
@@ -1634,7 +1656,8 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
 	    &child, &children) == 0) {
 		(void) printf(gettext("\tspares\n"));
 		for (c = 0; c < children; c++) {
-			vname = zpool_vdev_name(g_zfs, NULL, child[c], B_FALSE);
+			vname = zpool_vdev_name(g_zfs, NULL, child[c],
+			    name_flags);
 			(void) printf("\t  %s\n", vname);
 			free(vname);
 		}
@@ -1650,7 +1673,8 @@ print_import_config(const char *name, nvlist_t *nv, int namewidth, int depth)
  * works because only the top level vdev is marked "is_log"
  */
 static void
-print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
+print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose,
+    int name_flags)
 {
 	uint_t c, children;
 	nvlist_t **child;
@@ -1669,12 +1693,14 @@ print_logs(zpool_handle_t *zhp, nvlist_t *nv, int namewidth, boolean_t verbose)
 		    &is_log);
 		if (!is_log)
 			continue;
-		name = zpool_vdev_name(g_zfs, zhp, child[c], B_TRUE);
+		name = zpool_vdev_name(g_zfs, zhp, child[c],
+		    name_flags | VDEV_NAME_TYPE_ID);
 		if (verbose)
 			print_status_config(zhp, name, child[c], namewidth,
-			    2, B_FALSE);
+			    2, B_FALSE, name_flags);
 		else
-			print_import_config(name, child[c], namewidth, 2);
+			print_import_config(name, child[c], namewidth, 2,
+			    name_flags);
 		free(name);
 	}
 }
@@ -1923,13 +1949,13 @@ show_import(nvlist_t *config)
 
 	(void) printf(gettext(" config:\n\n"));
 
-	namewidth = max_width(NULL, nvroot, 0, 0);
+	namewidth = max_width(NULL, nvroot, 0, 0, 0);
 	if (namewidth < 10)
 		namewidth = 10;
 
-	print_import_config(name, nvroot, namewidth, 0);
+	print_import_config(name, nvroot, namewidth, 0, 0);
 	if (num_logs(nvroot) > 0)
-		print_logs(NULL, nvroot, namewidth, B_FALSE);
+		print_logs(NULL, nvroot, namewidth, B_FALSE, 0);
 
 	if (reason == ZPOOL_STATUS_BAD_GUID_SUM) {
 		(void) printf(gettext("\n\tAdditional devices are known to "
@@ -2438,6 +2464,7 @@ error:
 
 typedef struct iostat_cbdata {
 	boolean_t cb_verbose;
+	int cb_name_flags;
 	int cb_namewidth;
 	int cb_iteration;
 	zpool_list_t *cb_list;
@@ -2560,7 +2587,8 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
 		if (ishole || islog)
 			continue;
 
-		vname = zpool_vdev_name(g_zfs, zhp, newchild[c], B_FALSE);
+		vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
+		    cb->cb_name_flags);
 		print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
 		    newchild[c], cb, depth + 2);
 		free(vname);
@@ -2581,7 +2609,7 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
 
 			if (islog) {
 				vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
-				    B_FALSE);
+				    cb->cb_name_flags);
 				print_vdev_stats(zhp, vname, oldnv ?
 				    oldchild[c] : NULL, newchild[c],
 				    cb, depth + 2);
@@ -2607,7 +2635,7 @@ print_vdev_stats(zpool_handle_t *zhp, const char *name, nvlist_t *oldnv,
 		    "-\n", cb->cb_namewidth, "cache");
 		for (c = 0; c < children; c++) {
 			vname = zpool_vdev_name(g_zfs, zhp, newchild[c],
-			    B_FALSE);
+			    cb->cb_name_flags);
 			print_vdev_stats(zhp, vname, oldnv ? oldchild[c] : NULL,
 			    newchild[c], cb, depth + 2);
 			free(vname);
@@ -2700,7 +2728,7 @@ get_namewidth(zpool_handle_t *zhp, void *data)
 			cb->cb_namewidth = strlen(zpool_get_name(zhp));
 		else
 			cb->cb_namewidth = max_width(zhp, nvroot, 0,
-			    cb->cb_namewidth);
+			    cb->cb_namewidth, cb->cb_name_flags);
 	}
 
 	/*
@@ -2800,8 +2828,11 @@ get_timestamp_arg(char c)
 }
 
 /*
- * zpool iostat [-v] [-T d|u] [pool] ... [interval [count]]
+ * zpool iostat [-gLPv] [-T d|u] [pool] ... [interval [count]]
  *
+ *	-g	Display guid for individual vdev name.
+ *	-L	Follow links when resolving vdev path name.
+ *	-P	Display full path for vdev name.
  *	-v	Display statistics for individual vdevs
  *	-T	Display a timestamp in date(1) or Unix format
  *
@@ -2821,11 +2852,23 @@ zpool_do_iostat(int argc, char **argv)
 	zpool_list_t *list;
 	boolean_t verbose = B_FALSE;
 	boolean_t omit_since_boot = B_FALSE;
-	iostat_cbdata_t cb;
+	boolean_t guid = B_FALSE;
+	boolean_t follow_links = B_FALSE;
+	boolean_t full_name = B_FALSE;
+	iostat_cbdata_t cb = { 0 };
 
 	/* check options */
-	while ((c = getopt(argc, argv, "T:vy")) != -1) {
+	while ((c = getopt(argc, argv, "gLPT:vy")) != -1) {
 		switch (c) {
+		case 'g':
+			guid = B_TRUE;
+			break;
+		case 'L':
+			follow_links = B_TRUE;
+			break;
+		case 'P':
+			full_name = B_TRUE;
+			break;
 		case 'T':
 			get_timestamp_arg(*optarg);
 			break;
@@ -2870,6 +2913,12 @@ zpool_do_iostat(int argc, char **argv)
 	 */
 	cb.cb_list = list;
 	cb.cb_verbose = verbose;
+	if (guid)
+		cb.cb_name_flags |= VDEV_NAME_GUID;
+	if (follow_links)
+		cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+	if (full_name)
+		cb.cb_name_flags |= VDEV_NAME_PATH;
 	cb.cb_iteration = 0;
 	cb.cb_namewidth = 0;
 
@@ -2953,6 +3002,7 @@ zpool_do_iostat(int argc, char **argv)
 
 typedef struct list_cbdata {
 	boolean_t	cb_verbose;
+	int		cb_name_flags;
 	int		cb_namewidth;
 	boolean_t	cb_scripted;
 	zprop_list_t	*cb_proplist;
@@ -3128,6 +3178,9 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
 	uint_t c, children;
 	char *vname;
 	boolean_t scripted = cb->cb_scripted;
+	uint64_t islog = B_FALSE;
+	boolean_t haslog = B_FALSE;
+	char *dashes = "%-*s      -      -      -         -      -      -\n";
 
 	verify(nvlist_lookup_uint64_array(nv, ZPOOL_CONFIG_VDEV_STATS,
 	    (uint64_t **)&vs, &c) == 0);
@@ -3178,24 +3231,51 @@ print_list_stats(zpool_handle_t *zhp, const char *name, nvlist_t *nv,
 		    ZPOOL_CONFIG_IS_HOLE, &ishole) == 0 && ishole)
 			continue;
 
-		vname = zpool_vdev_name(g_zfs, zhp, child[c], B_FALSE);
+		if (nvlist_lookup_uint64(child[c],
+		    ZPOOL_CONFIG_IS_LOG, &islog) == 0 && islog) {
+			haslog = B_TRUE;
+			continue;
+		}
+
+		vname = zpool_vdev_name(g_zfs, zhp, child[c],
+		    cb->cb_name_flags);
 		print_list_stats(zhp, vname, child[c], cb, depth + 2);
 		free(vname);
 	}
 
-	/*
-	 * Include level 2 ARC devices in iostat output
-	 */
+	if (haslog == B_TRUE) {
+		/* LINTED E_SEC_PRINTF_VAR_FMT */
+		(void) printf(dashes, cb->cb_namewidth, "log");
+		for (c = 0; c < children; c++) {
+			if (nvlist_lookup_uint64(child[c], ZPOOL_CONFIG_IS_LOG,
+			    &islog) != 0 || !islog)
+				continue;
+			vname = zpool_vdev_name(g_zfs, zhp, child[c],
+			    cb->cb_name_flags);
+			print_list_stats(zhp, vname, child[c], cb, depth + 2);
+			free(vname);
+		}
+	}
+
 	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_L2CACHE,
-	    &child, &children) != 0)
-		return;
+	    &child, &children) == 0 && children > 0) {
+		/* LINTED E_SEC_PRINTF_VAR_FMT */
+		(void) printf(dashes, cb->cb_namewidth, "cache");
+		for (c = 0; c < children; c++) {
+			vname = zpool_vdev_name(g_zfs, zhp, child[c],
+			    cb->cb_name_flags);
+			print_list_stats(zhp, vname, child[c], cb, depth + 2);
+			free(vname);
+		}
+	}
 
-	if (children > 0) {
-		(void) printf("%-*s      -      -      -      -      -      "
-		    "-\n", cb->cb_namewidth, "cache");
+	if (nvlist_lookup_nvlist_array(nv, ZPOOL_CONFIG_SPARES, &child,
+	    &children) == 0 && children > 0) {
+		/* LINTED E_SEC_PRINTF_VAR_FMT */
+		(void) printf(dashes, cb->cb_namewidth, "spare");
 		for (c = 0; c < children; c++) {
 			vname = zpool_vdev_name(g_zfs, zhp, child[c],
-			    B_FALSE);
+			    cb->cb_name_flags);
 			print_list_stats(zhp, vname, child[c], cb, depth + 2);
 			free(vname);
 		}
@@ -3227,13 +3307,16 @@ list_callback(zpool_handle_t *zhp, void *data)
 }
 
 /*
- * zpool list [-H] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
+ * zpool list [-gHLP] [-o prop[,prop]*] [-T d|u] [pool] ... [interval [count]]
  *
+ *	-g	Display guid for individual vdev name.
  *	-H	Scripted mode.  Don't display headers, and separate properties
  *		by a single tab.
+ *	-L	Follow links when resolving vdev path name.
  *	-o	List of properties to display.  Defaults to
  *		"name,size,allocated,free,expandsize,fragmentation,capacity,"
  *		"dedupratio,health,altroot"
+ *	-P	Display full path for vdev name.
  *	-T	Display a timestamp in date(1) or Unix format
  *
  * List all pools in the system, whether or not they're healthy.  Output space
@@ -3254,14 +3337,23 @@ zpool_do_list(int argc, char **argv)
 	boolean_t first = B_TRUE;
 
 	/* check options */
-	while ((c = getopt(argc, argv, ":Ho:T:v")) != -1) {
+	while ((c = getopt(argc, argv, ":gHLo:PT:v")) != -1) {
 		switch (c) {
+		case 'g':
+			cb.cb_name_flags |= VDEV_NAME_GUID;
+			break;
 		case 'H':
 			cb.cb_scripted = B_TRUE;
 			break;
+		case 'L':
+			cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+			break;
 		case 'o':
 			props = optarg;
 			break;
+		case 'P':
+			cb.cb_name_flags |= VDEV_NAME_PATH;
+			break;
 		case 'T':
 			get_timestamp_arg(*optarg);
 			break;
@@ -3517,13 +3609,16 @@ zpool_do_detach(int argc, char **argv)
 }
 
 /*
- * zpool split [-n] [-o prop=val] ...
+ * zpool split [-gLnP] [-o prop=val] ...
  *		[-o mntopt] ...
  *		[-R altroot] <pool> <newpool> [<device> ...]
  *
+ *	-g      Display guid for individual vdev name.
+ *	-L	Follow links when resolving vdev path name.
  *	-n	Do not split the pool, but display the resulting layout if
  *		it were to be split.
  *	-o	Set property=value, or set mount options.
+ *	-P	Display full path for vdev name.
  *	-R	Mount the split-off pool under an alternate root.
  *
  * Splits the named pool and gives it the new pool name.  Devices to be split
@@ -3547,10 +3642,17 @@ zpool_do_split(int argc, char **argv)
 
 	flags.dryrun = B_FALSE;
 	flags.import = B_FALSE;
+	flags.name_flags = 0;
 
 	/* check options */
-	while ((c = getopt(argc, argv, ":R:no:")) != -1) {
+	while ((c = getopt(argc, argv, ":gLR:no:P")) != -1) {
 		switch (c) {
+		case 'g':
+			flags.name_flags |= VDEV_NAME_GUID;
+			break;
+		case 'L':
+			flags.name_flags |= VDEV_NAME_FOLLOW_LINKS;
+			break;
 		case 'R':
 			flags.import = B_TRUE;
 			if (add_prop_list(
@@ -3578,6 +3680,9 @@ zpool_do_split(int argc, char **argv)
 				mntopts = optarg;
 			}
 			break;
+		case 'P':
+			flags.name_flags |= VDEV_NAME_PATH;
+			break;
 		case ':':
 			(void) fprintf(stderr, gettext("missing argument for "
 			    "'%c' option\n"), optopt);
@@ -3625,7 +3730,8 @@ zpool_do_split(int argc, char **argv)
 		if (flags.dryrun) {
 			(void) printf(gettext("would create '%s' with the "
 			    "following layout:\n\n"), newpool);
-			print_vdev_tree(NULL, newpool, config, 0, B_FALSE);
+			print_vdev_tree(NULL, newpool, config, 0, B_FALSE,
+			    flags.name_flags);
 		}
 		nvlist_free(config);
 	}
@@ -4031,6 +4137,7 @@ zpool_do_scrub(int argc, char **argv)
 
 typedef struct status_cbdata {
 	int		cb_count;
+	int		cb_name_flags;
 	boolean_t	cb_allpools;
 	boolean_t	cb_verbose;
 	boolean_t	cb_explain;
@@ -4187,7 +4294,7 @@ print_error_log(zpool_handle_t *zhp)
 
 static void
 print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
-    int namewidth)
+    int namewidth, int name_flags)
 {
 	uint_t i;
 	char *name;
@@ -4198,16 +4305,16 @@ print_spares(zpool_handle_t *zhp, nvlist_t **spares, uint_t nspares,
 	(void) printf(gettext("\tspares\n"));
 
 	for (i = 0; i < nspares; i++) {
-		name = zpool_vdev_name(g_zfs, zhp, spares[i], B_FALSE);
+		name = zpool_vdev_name(g_zfs, zhp, spares[i], name_flags);
 		print_status_config(zhp, name, spares[i],
-		    namewidth, 2, B_TRUE);
+		    namewidth, 2, B_TRUE, name_flags);
 		free(name);
 	}
 }
 
 static void
 print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
-    int namewidth)
+    int namewidth, int name_flags)
 {
 	uint_t i;
 	char *name;
@@ -4218,9 +4325,9 @@ print_l2cache(zpool_handle_t *zhp, nvlist_t **l2cache, uint_t nl2cache,
 	(void) printf(gettext("\tcache\n"));
 
 	for (i = 0; i < nl2cache; i++) {
-		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], B_FALSE);
+		name = zpool_vdev_name(g_zfs, zhp, l2cache[i], name_flags);
 		print_status_config(zhp, name, l2cache[i],
-		    namewidth, 2, B_FALSE);
+		    namewidth, 2, B_FALSE, name_flags);
 		free(name);
 	}
 }
@@ -4562,7 +4669,7 @@ status_callback(zpool_handle_t *zhp, void *data)
 		    ZPOOL_CONFIG_SCAN_STATS, (uint64_t **)&ps, &c);
 		print_scan_status(ps);
 
-		namewidth = max_width(zhp, nvroot, 0, 0);
+		namewidth = max_width(zhp, nvroot, 0, 0, cbp->cb_name_flags);
 		if (namewidth < 10)
 			namewidth = 10;
 
@@ -4570,17 +4677,20 @@ status_callback(zpool_handle_t *zhp, void *data)
 		(void) printf(gettext("\t%-*s  %-8s %5s %5s %5s\n"), namewidth,
 		    "NAME", "STATE", "READ", "WRITE", "CKSUM");
 		print_status_config(zhp, zpool_get_name(zhp), nvroot,
-		    namewidth, 0, B_FALSE);
+		    namewidth, 0, B_FALSE, cbp->cb_name_flags);
 
 		if (num_logs(nvroot) > 0)
-			print_logs(zhp, nvroot, namewidth, B_TRUE);
+			print_logs(zhp, nvroot, namewidth, B_TRUE,
+			    cbp->cb_name_flags);
 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_L2CACHE,
 		    &l2cache, &nl2cache) == 0)
-			print_l2cache(zhp, l2cache, nl2cache, namewidth);
+			print_l2cache(zhp, l2cache, nl2cache, namewidth,
+				cbp->cb_name_flags);
 
 		if (nvlist_lookup_nvlist_array(nvroot, ZPOOL_CONFIG_SPARES,
 		    &spares, &nspares) == 0)
-			print_spares(zhp, spares, nspares, namewidth);
+			print_spares(zhp, spares, nspares, namewidth,
+			    cbp->cb_name_flags);
 
 		if (nvlist_lookup_uint64(config, ZPOOL_CONFIG_ERRCOUNT,
 		    &nerr) == 0) {
@@ -4628,8 +4738,11 @@ status_callback(zpool_handle_t *zhp, void *data)
 }
 
 /*
- * zpool status [-vx] [-T d|u] [pool] ... [interval [count]]
+ * zpool status [-gLPvx] [-T d|u] [pool] ... [interval [count]]
  *
+ *	-g	Display guid for individual vdev name.
+ *	-L	Follow links when resolving vdev path name.
+ *	-P	Display full path for vdev name.
  *	-v	Display complete error logs
  *	-x	Display only pools with potential problems
  *	-D	Display dedup status (undocumented)
@@ -4646,8 +4759,17 @@ zpool_do_status(int argc, char **argv)
 	status_cbdata_t cb = { 0 };
 
 	/* check options */
-	while ((c = getopt(argc, argv, "vxDT:")) != -1) {
+	while ((c = getopt(argc, argv, "gLPvxDT:")) != -1) {
 		switch (c) {
+		case 'g':
+			cb.cb_name_flags |= VDEV_NAME_GUID;
+			break;
+		case 'L':
+			cb.cb_name_flags |= VDEV_NAME_FOLLOW_LINKS;
+			break;
+		case 'P':
+			cb.cb_name_flags |= VDEV_NAME_PATH;
+			break;
 		case 'v':
 			cb.cb_verbose = B_TRUE;
 			break;
diff --git a/configure b/configure
index 28e1c2d..d56482b 100755
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.68 for zfs 0.6.5.5.
+# Generated by GNU Autoconf 2.68 for zfs 0.6.5.6.
 #
 #
 # Copyright (C) 1992, 1993, 1994, 1995, 1996, 1998, 1999, 2000, 2001,
@@ -567,8 +567,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='zfs'
 PACKAGE_TARNAME='zfs'
-PACKAGE_VERSION='0.6.5.5'
-PACKAGE_STRING='zfs 0.6.5.5'
+PACKAGE_VERSION='0.6.5.6'
+PACKAGE_STRING='zfs 0.6.5.6'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
@@ -1401,7 +1401,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures zfs 0.6.5.5 to adapt to many kinds of systems.
+\`configure' configures zfs 0.6.5.6 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1472,7 +1472,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of zfs 0.6.5.5:";;
+     short | recursive ) echo "Configuration of zfs 0.6.5.6:";;
    esac
   cat <<\_ACEOF
 
@@ -1607,7 +1607,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-zfs configure 0.6.5.5
+zfs configure 0.6.5.6
 generated by GNU Autoconf 2.68
 
 Copyright (C) 2010 Free Software Foundation, Inc.
@@ -1972,7 +1972,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by zfs $as_me 0.6.5.5, which was
+It was created by zfs $as_me 0.6.5.6, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   $ $0 $@
@@ -3099,7 +3099,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='zfs'
- VERSION='0.6.5.5'
+ VERSION='0.6.5.6'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -32326,7 +32326,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by zfs $as_me 0.6.5.5, which was
+This file was extended by zfs $as_me 0.6.5.6, which was
 generated by GNU Autoconf 2.68.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -32392,7 +32392,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-zfs config.status 0.6.5.5
+zfs config.status 0.6.5.6
 configured by $0, generated by GNU Autoconf 2.68,
   with options \\"\$ac_cs_config\\"
 
diff --git a/include/libzfs.h b/include/libzfs.h
index db8ee71..26847e0 100644
--- a/include/libzfs.h
+++ b/include/libzfs.h
@@ -248,6 +248,7 @@ typedef struct splitflags {
 
 	/* after splitting, import the pool */
 	int import : 1;
+	int name_flags;
 } splitflags_t;
 
 /*
@@ -406,8 +407,15 @@ struct zfs_cmd;
 
 extern const char *zfs_history_event_names[];
 
+typedef enum {
+	VDEV_NAME_PATH		= 1 << 0,
+	VDEV_NAME_GUID		= 1 << 1,
+	VDEV_NAME_FOLLOW_LINKS	= 1 << 2,
+	VDEV_NAME_TYPE_ID	= 1 << 3,
+} vdev_name_t;
+
 extern char *zpool_vdev_name(libzfs_handle_t *, zpool_handle_t *, nvlist_t *,
-    boolean_t verbose);
+    int name_flags);
 extern int zpool_upgrade(zpool_handle_t *, uint64_t);
 extern int zpool_get_history(zpool_handle_t *, nvlist_t **);
 extern int zpool_history_unpack(char *, uint64_t, uint64_t *,
diff --git a/include/sys/spa_impl.h b/include/sys/spa_impl.h
index 0b49c71..5176eb8 100644
--- a/include/sys/spa_impl.h
+++ b/include/sys/spa_impl.h
@@ -23,6 +23,7 @@
  * Copyright (c) 2011, 2015 by Delphix. All rights reserved.
  * Copyright 2011 Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #ifndef _SYS_SPA_IMPL_H
@@ -252,6 +253,7 @@ struct spa {
 	uint64_t	spa_deadman_synctime;	/* deadman expiration timer */
 	uint64_t	spa_errata;		/* errata issues detected */
 	spa_stats_t	spa_stats;		/* assorted spa statistics */
+	taskq_t		*spa_zvol_taskq;	/* Taskq for minor managment */
 
 	/*
 	 * spa_refcount & spa_config_lock must be the last elements
diff --git a/include/sys/zvol.h b/include/sys/zvol.h
index 898e235..c3e386f 100644
--- a/include/sys/zvol.h
+++ b/include/sys/zvol.h
@@ -21,6 +21,7 @@
 
 /*
  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #ifndef	_SYS_ZVOL_H
@@ -31,24 +32,22 @@
 #define	ZVOL_OBJ		1ULL
 #define	ZVOL_ZAP_OBJ		2ULL
 
-#ifdef _KERNEL
+extern void zvol_create_minors(spa_t *spa, const char *name, boolean_t async);
+extern void zvol_remove_minors(spa_t *spa, const char *name, boolean_t async);
+extern void zvol_rename_minors(spa_t *spa, const char *oldname,
+    const char *newname, boolean_t async);
 
+#ifdef _KERNEL
 extern int zvol_check_volsize(uint64_t volsize, uint64_t blocksize);
 extern int zvol_check_volblocksize(const char *name, uint64_t volblocksize);
 extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
 extern boolean_t zvol_is_zvol(const char *);
 extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
-extern int zvol_create_minor(const char *name);
-extern int zvol_create_minors(const char *name);
-extern int zvol_remove_minor(const char *name);
-extern void zvol_remove_minors(const char *name);
-extern void zvol_rename_minors(const char *oldname, const char *newname);
 extern int zvol_set_volsize(const char *, uint64_t);
 extern int zvol_set_volblocksize(const char *, uint64_t);
-extern int zvol_set_snapdev(const char *, uint64_t);
+extern int zvol_set_snapdev(const char *, zprop_source_t, uint64_t);
 
 extern int zvol_init(void);
 extern void zvol_fini(void);
-
 #endif /* _KERNEL */
 #endif /* _SYS_ZVOL_H */
diff --git a/lib/libefi/rdwr_efi.c b/lib/libefi/rdwr_efi.c
index 785cfe6..06d4dd6 100644
--- a/lib/libefi/rdwr_efi.c
+++ b/lib/libefi/rdwr_efi.c
@@ -88,7 +88,7 @@ struct dk_map2  default_vtoc_map[NDKMAP] = {
 #if defined(_SUNOS_VTOC_16)
 
 #if defined(i386) || defined(__amd64) || defined(__arm) || \
-    defined(__powerpc) || defined(__sparc)
+    defined(__powerpc) || defined(__sparc) || defined(__s390__)
 	{	V_BOOT,		V_UNMNT	},		/* i - 8 */
 	{	V_ALTSCTR,	0	},		/* j - 9 */
 
diff --git a/lib/libspl/include/sys/isa_defs.h b/lib/libspl/include/sys/isa_defs.h
index 60c6a3b..61f4cd9 100644
--- a/lib/libspl/include/sys/isa_defs.h
+++ b/lib/libspl/include/sys/isa_defs.h
@@ -157,7 +157,22 @@ extern "C" {
 #endif
 #endif
 
-#else /* Currently x86_64, i386, arm, powerpc, and sparc are supported */
+/* s390 arch specific defines */
+#elif defined(__s390__)
+#if defined(__s390x__)
+#if !defined(_LP64)
+#define	_LP64
+#endif
+#else
+#if !defined(_ILP32)
+#define	_ILP32
+#endif
+#endif
+
+#define	_BIG_ENDIAN
+#define	_SUNOS_VTOC_16
+
+#else /* Currently x86_64, i386, arm, powerpc, s390, and sparc are supported */
 #error "Unsupported ISA type"
 #endif
 
diff --git a/lib/libzfs/libzfs.pc b/lib/libzfs/libzfs.pc
index ee1c6c6..349ba8f 100644
--- a/lib/libzfs/libzfs.pc
+++ b/lib/libzfs/libzfs.pc
@@ -5,7 +5,7 @@ includedir=${prefix}/include
 
 Name: libzfs
 Description: LibZFS library
-Version: 0.6.5.5
+Version: 0.6.5.6
 URL: http://zfsonlinux.org
 Requires: libzfs_core
 Cflags: -I${includedir}/libzfs -I${includedir}/libspl
diff --git a/lib/libzfs/libzfs_core.pc b/lib/libzfs/libzfs_core.pc
index 04fea8e..b7ec4a4 100644
--- a/lib/libzfs/libzfs_core.pc
+++ b/lib/libzfs/libzfs_core.pc
@@ -5,7 +5,7 @@ includedir=${prefix}/include
 
 Name: libzfs_core
 Description: LibZFS core library
-Version: 0.6.5.5
+Version: 0.6.5.6
 URL: http://zfsonlinux.org
 Cflags: -I${includedir}/libzfs -I${includedir}/libspl
 Libs: -L${libdir} -lzfs_core
diff --git a/lib/libzfs/libzfs_pool.c b/lib/libzfs/libzfs_pool.c
index a730a94..456015e 100644
--- a/lib/libzfs/libzfs_pool.c
+++ b/lib/libzfs/libzfs_pool.c
@@ -1378,8 +1378,7 @@ zpool_add(zpool_handle_t *zhp, nvlist_t *nvroot)
 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 				    "device '%s' contains an EFI label and "
 				    "cannot be used on root pools."),
-				    zpool_vdev_name(hdl, NULL, spares[s],
-				    B_FALSE));
+				    zpool_vdev_name(hdl, NULL, spares[s], 0));
 				return (zfs_error(hdl, EZFS_POOL_NOTSUP, msg));
 			}
 		}
@@ -1700,7 +1699,7 @@ print_vdev_tree(libzfs_handle_t *hdl, const char *name, nvlist_t *nv,
 		return;
 
 	for (c = 0; c < children; c++) {
-		vname = zpool_vdev_name(hdl, NULL, child[c], B_TRUE);
+		vname = zpool_vdev_name(hdl, NULL, child[c], VDEV_NAME_TYPE_ID);
 		print_vdev_tree(hdl, vname, child[c], indent + 2);
 		free(vname);
 	}
@@ -2688,7 +2687,7 @@ zpool_vdev_attach(zpool_handle_t *zhp,
 	verify(nvlist_lookup_nvlist(zpool_get_config(zhp, NULL),
 	    ZPOOL_CONFIG_VDEV_TREE, &config_root) == 0);
 
-	if ((newname = zpool_vdev_name(NULL, NULL, child[0], B_FALSE)) == NULL)
+	if ((newname = zpool_vdev_name(NULL, NULL, child[0], 0)) == NULL)
 		return (-1);
 
 	/*
@@ -2879,11 +2878,11 @@ find_vdev_entry(zpool_handle_t *zhp, nvlist_t **mchild, uint_t mchildren,
 	for (mc = 0; mc < mchildren; mc++) {
 		uint_t sc;
 		char *mpath = zpool_vdev_name(zhp->zpool_hdl, zhp,
-		    mchild[mc], B_FALSE);
+		    mchild[mc], 0);
 
 		for (sc = 0; sc < schildren; sc++) {
 			char *spath = zpool_vdev_name(zhp->zpool_hdl, zhp,
-			    schild[sc], B_FALSE);
+			    schild[sc], 0);
 			boolean_t result = (strcmp(mpath, spath) == 0);
 
 			free(spath);
@@ -3424,21 +3423,34 @@ strip_partition(libzfs_handle_t *hdl, char *path)
  */
 char *
 zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
-    boolean_t verbose)
+    int name_flags)
 {
-	char *path, *devid, *type;
+	char *path, *devid, *type, *env;
 	uint64_t value;
 	char buf[PATH_BUF_LEN];
 	char tmpbuf[PATH_BUF_LEN];
 	vdev_stat_t *vs;
 	uint_t vsc;
 
-	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT,
-	    &value) == 0) {
-		verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID,
-		    &value) == 0);
-		(void) snprintf(buf, sizeof (buf), "%llu",
-		    (u_longlong_t)value);
+	env = getenv("ZPOOL_VDEV_NAME_PATH");
+	if (env && (strtoul(env, NULL, 0) > 0 ||
+	    !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+		name_flags |= VDEV_NAME_PATH;
+
+	env = getenv("ZPOOL_VDEV_NAME_GUID");
+	if (env && (strtoul(env, NULL, 0) > 0 ||
+	    !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+		name_flags |= VDEV_NAME_GUID;
+
+	env = getenv("ZPOOL_VDEV_NAME_FOLLOW_LINKS");
+	if (env && (strtoul(env, NULL, 0) > 0 ||
+	    !strncasecmp(env, "YES", 3) || !strncasecmp(env, "ON", 2)))
+		name_flags |= VDEV_NAME_FOLLOW_LINKS;
+
+	if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_NOT_PRESENT, &value) == 0 ||
+	    name_flags & VDEV_NAME_GUID) {
+		nvlist_lookup_uint64(nv, ZPOOL_CONFIG_GUID, &value);
+		(void) snprintf(buf, sizeof (buf), "%llu", (u_longlong_t)value);
 		path = buf;
 	} else if (nvlist_lookup_string(nv, ZPOOL_CONFIG_PATH, &path) == 0) {
 		/*
@@ -3479,11 +3491,21 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
 				devid_str_free(newdevid);
 		}
 
+		if (name_flags & VDEV_NAME_FOLLOW_LINKS) {
+			char *rp = realpath(path, NULL);
+			if (rp) {
+				strlcpy(buf, rp, sizeof (buf));
+				path = buf;
+				free(rp);
+			}
+		}
+
 		/*
 		 * For a block device only use the name.
 		 */
 		verify(nvlist_lookup_string(nv, ZPOOL_CONFIG_TYPE, &type) == 0);
-		if (strcmp(type, VDEV_TYPE_DISK) == 0) {
+		if ((strcmp(type, VDEV_TYPE_DISK) == 0) &&
+		    !(name_flags & VDEV_NAME_PATH)) {
 			path = strrchr(path, '/');
 			path++;
 		}
@@ -3491,8 +3513,8 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
 		/*
 		 * Remove the partition from the path it this is a whole disk.
 		 */
-		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK,
-		    &value) == 0 && value) {
+		if (nvlist_lookup_uint64(nv, ZPOOL_CONFIG_WHOLE_DISK, &value)
+		    == 0 && value && !(name_flags & VDEV_NAME_PATH)) {
 			return (strip_partition(hdl, path));
 		}
 	} else {
@@ -3514,7 +3536,7 @@ zpool_vdev_name(libzfs_handle_t *hdl, zpool_handle_t *zhp, nvlist_t *nv,
 		 * We identify each top-level vdev by using a <type-id>
 		 * naming convention.
 		 */
-		if (verbose) {
+		if (name_flags & VDEV_NAME_TYPE_ID) {
 			uint64_t id;
 
 			verify(nvlist_lookup_uint64(nv, ZPOOL_CONFIG_ID,
diff --git a/lib/libzfs/libzfs_util.c b/lib/libzfs/libzfs_util.c
index 678eead..ccace2d 100644
--- a/lib/libzfs/libzfs_util.c
+++ b/lib/libzfs/libzfs_util.c
@@ -1024,16 +1024,18 @@ zfs_strcmp_pathname(char *name, char *cmp, int wholedisk)
 	int path_len, cmp_len;
 	char path_name[MAXPATHLEN];
 	char cmp_name[MAXPATHLEN];
-	char *dir;
+	char *dir, *dup;
 
 	/* Strip redundant slashes if one exists due to ZPOOL_IMPORT_PATH */
 	memset(cmp_name, 0, MAXPATHLEN);
-	dir = strtok(cmp, "/");
+	dup = strdup(cmp);
+	dir = strtok(dup, "/");
 	while (dir) {
 		strcat(cmp_name, "/");
 		strcat(cmp_name, dir);
 		dir = strtok(NULL, "/");
 	}
+	free(dup);
 
 	if (name[0] != '/')
 		return (zfs_strcmp_shortname(name, cmp_name, wholedisk));
diff --git a/lib/libzpool/kernel.c b/lib/libzpool/kernel.c
index a451026..f1ce8b3 100644
--- a/lib/libzpool/kernel.c
+++ b/lib/libzpool/kernel.c
@@ -20,6 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include <assert.h>
@@ -1322,3 +1323,24 @@ spl_fstrans_check(void)
 {
 	return (0);
 }
+
+void
+zvol_create_minors(spa_t *spa, const char *name, boolean_t async)
+{
+}
+
+void
+zvol_remove_minor(spa_t *spa, const char *name, boolean_t async)
+{
+}
+
+void
+zvol_remove_minors(spa_t *spa, const char *name, boolean_t async)
+{
+}
+
+void
+zvol_rename_minors(spa_t *spa, const char *oldname, const char *newname,
+    boolean_t async)
+{
+}
diff --git a/man/man8/zpool.8 b/man/man8/zpool.8
index 062b5ae..bd7d694 100644
--- a/man/man8/zpool.8
+++ b/man/man8/zpool.8
@@ -26,7 +26,7 @@ zpool \- configures ZFS storage pools
 
 .LP
 .nf
-\fBzpool add\fR [\fB-fn\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIvdev\fR ...
+\fBzpool add\fR [\fB-fgLnP\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIvdev\fR ...
 .fi
 
 .LP
@@ -94,7 +94,7 @@ zpool \- configures ZFS storage pools
 
 .LP
 .nf
-\fBzpool iostat\fR [\fB-T\fR d | u ] [\fB-v\fR] [\fB-y\fR] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]]
+\fBzpool iostat\fR [\fB-T\fR d | u ] [\fB-gLPvy\fR] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]]
 .fi
 
 .LP
@@ -104,7 +104,7 @@ zpool \- configures ZFS storage pools
 
 .LP
 .nf
-\fBzpool list\fR [\fB-T\fR d | u ] [\fB-Hv\fR] [\fB-o\fR \fIproperty\fR[,...]] [\fIpool\fR] ...
+\fBzpool list\fR [\fB-T\fR d | u ] [\fB-HgLPv\fR] [\fB-o\fR \fIproperty\fR[,...]] [\fIpool\fR] ...
      [\fIinterval\fR[\fIcount\fR]]
 .fi
 
@@ -150,12 +150,12 @@ zpool \- configures ZFS storage pools
 
 .LP
 .nf
-\fBzpool split\fR [\fB-n\fR] [\fB-R\fR \fIaltroot\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fInewpool\fR [\fIdevice\fR ...]
+\fBzpool split\fR [\fB-gLnP\fR] [\fB-R\fR \fIaltroot\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fInewpool\fR [\fIdevice\fR ...]
 .fi
 
 .LP
 .nf
-\fBzpool status\fR [\fB-xvD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]]
+\fBzpool status\fR [\fB-gLPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]]
 .fi
 
 .LP
@@ -836,7 +836,7 @@ Displays a help message.
 .ne 2
 .mk
 .na
-\fB\fBzpool add\fR [\fB-fn\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIvdev\fR ...\fR
+\fB\fBzpool add\fR [\fB-fgLnP\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fIvdev\fR ...\fR
 .ad
 .sp .6
 .RS 4n
@@ -856,6 +856,28 @@ Forces use of \fBvdev\fRs, even if they appear in use or specify a conflicting r
 .ne 2
 .mk
 .na
+\fB\fB-g\fR\fR
+.ad
+.RS 6n
+.rt
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 6n
+.rt
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
 \fB\fB-n\fR\fR
 .ad
 .RS 6n
@@ -867,6 +889,17 @@ Displays the configuration that would be used without actually adding the \fBvde
 .ne 2
 .mk
 .na
+\fB\fB-P\fR\fR
+.ad
+.RS 6n
+.rt
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
 \fB\fB-o\fR \fIproperty=value\fR
 .ad
 .sp .6
@@ -1608,7 +1641,7 @@ Allows a pool to import when there is a missing log device.
 .ne 2
 .mk
 .na
-\fB\fBzpool iostat\fR [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-v\fR] [\fB-y\fR] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]]\fR
+\fB\fBzpool iostat\fR [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-gLPvy\fR] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]]\fR
 .ad
 .sp .6
 .RS 4n
@@ -1630,6 +1663,39 @@ Specify \fBu\fR for a printed representation of the internal representation of t
 .ne 2
 .mk
 .na
+\fB\fB-g\fR\fR
+.ad
+.RS 12n
+.rt
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 12n
+.rt
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-P\fR\fR
+.ad
+.RS 12n
+.rt
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
 \fB\fB-v\fR\fR
 .ad
 .RS 12n
@@ -1676,7 +1742,7 @@ Treat exported or foreign devices as inactive.
 .ne 2
 .mk
 .na
-\fB\fBzpool list\fR [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-Hv\fR] [\fB-o\fR \fIprops\fR[,...]] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]]\fR
+\fB\fBzpool list\fR [\fB-T\fR \fBd\fR | \fBu\fR] [\fB-HgLPv\fR] [\fB-o\fR \fIprops\fR[,...]] [\fIpool\fR] ... [\fIinterval\fR[\fIcount\fR]]\fR
 .ad
 .sp .6
 .RS 4n
@@ -1692,6 +1758,39 @@ Lists the given pools along with a health status and space usage. If no \fIpools
 Scripted mode. Do not display headers, and separate fields by a single tab instead of arbitrary space.
 .RE
 
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-g\fR\fR
+.ad
+.RS 12n
+.rt
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 12n
+.rt
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-P\fR\fR
+.ad
+.RS 12n
+.rt
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
 .ne 2
 .mk
 .na
@@ -1886,7 +1985,7 @@ Sets the given property on the specified pool. See the "Properties" section for
 .ne 2
 .mk
 .na
-\fBzpool split\fR [\fB-n\fR] [\fB-R\fR \fIaltroot\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fInewpool\fR [\fIdevice\fR ...]
+\fBzpool split\fR [\fB-gLnP\fR] [\fB-R\fR \fIaltroot\fR] [\fB-o\fR \fIproperty=value\fR] \fIpool\fR \fInewpool\fR [\fIdevice\fR ...]
 .ad
 .sp .6
 .RS 4n
@@ -1898,6 +1997,28 @@ The optional \fIdevice\fR specification causes the specified device(s) to be inc
 .ne 2
 .mk
 .na
+\fB\fB-g\fR\fR
+.ad
+.RS 6n
+.rt
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used in place of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 6n
+.rt
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
 \fB\fB-n\fR \fR
 .ad
 .sp .6
@@ -1909,6 +2030,17 @@ Do dry run, do not actually perform the split. Print out the expected configurat
 .ne 2
 .mk
 .na
+\fB\fB-P\fR\fR
+.ad
+.RS 6n
+.rt
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
 \fB\fB-R\fR \fIaltroot\fR \fR
 .ad
 .sp .6
@@ -1933,22 +2065,45 @@ Sets the specified property for \fInewpool\fR. See the “Properties” section
 .ne 2
 .mk
 .na
-\fBzpool status\fR [\fB-xvD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]]
+\fBzpool status\fR [\fB-gLPvxD\fR] [\fB-T\fR d | u] [\fIpool\fR] ... [\fIinterval\fR [\fIcount\fR]]
 .ad
 .sp .6
 .RS 4n
 Displays the detailed health status for the given pools. If no \fIpool\fR is specified, then the status of each pool in the system is displayed. For more information on pool and device health, see the "Device Failure and Recovery" section.
 .sp
 If a scrub or resilver is in progress, this command reports the percentage done and the estimated time to completion. Both of these are only approximate, because the amount of data in the pool and the other workloads on the system can change.
+
 .sp
 .ne 2
 .mk
 .na
-\fB\fB-x\fR\fR
+\fB\fB-g\fR\fR
 .ad
 .RS 12n
-.rt  
-Only display status for pools that are exhibiting errors or are otherwise unavailable. Warnings about pools not using the latest on-disk format will not be included.
+.rt
+Display vdev GUIDs instead of the normal device names. These GUIDs can be used innplace of device names for the zpool detach/offline/remove/replace commands.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-L\fR\fR
+.ad
+.RS 12n
+.rt
+Display real paths for vdevs resolving all symbolic links. This can be used to look up the current block device name regardless of the /dev/disk/ path used to open it.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
+\fB\fB-P\fR\fR
+.ad
+.RS 12n
+.rt
+Display full paths for vdevs instead of only the last component of the path.  This can be used in conjunction with the \fB-L\fR flag.
 .RE
 
 .sp
@@ -1966,6 +2121,17 @@ Displays verbose data error information, printing out a complete list of all dat
 .ne 2
 .mk
 .na
+\fB\fB-x\fR\fR
+.ad
+.RS 12n
+.rt
+Only display status for pools that are exhibiting errors or are otherwise unavailable. Warnings about pools not using the latest on-disk format will not be included.
+.RE
+
+.sp
+.ne 2
+.mk
+.na
 \fB\fB-D\fR\fR
 .ad
 .RS 12n
@@ -2401,6 +2567,17 @@ Cause \fBzpool\fR to dump core on exit for the purposes of running \fB::findleak
 .B "ZPOOL_IMPORT_PATH"
 The search path for devices or files to use with the pool. This is a colon-separated list of directories in which \fBzpool\fR looks for device nodes and files.
 Similar to the \fB-d\fR option in \fIzpool import\fR.
+.TP
+.B "ZPOOL_VDEV_NAME_GUID"
+Cause \fBzpool\fR subcommands to output vdev guids by default.  This behavior
+is identical to the \fBzpool status -g\fR command line option.
+.TP
+.B "ZPOOL_VDEV_NAME_FOLLOW_LINKS"
+Cause \fBzpool\fR subcommands to follow links for vdev names by default.  This behavior is identical to the \fBzpool status -L\fR command line option.
+.TP
+.B "ZPOOL_VDEV_NAME_PATH"
+Cause \fBzpool\fR subcommands to output full vdev path names by default.  This
+behavior is identical to the \fBzpool status -p\fR command line option.
 
 .SH SEE ALSO
 .sp
diff --git a/module/avl/zavl.mod.c b/module/avl/zavl.mod.c
new file mode 100644
index 0000000..062c559
--- /dev/null
+++ b/module/avl/zavl.mod.c
@@ -0,0 +1,32 @@
+#include <linux/module.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+struct module __this_module
+__attribute__((section(".gnu.linkonce.this_module"))) = {
+ .name = KBUILD_MODNAME,
+ .init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+ .exit = cleanup_module,
+#endif
+ .arch = MODULE_ARCH_INIT,
+};
+
+static const struct modversion_info ____versions[]
+__used
+__attribute__((section("__versions"))) = {
+	{ 0x51198477, "module_layout" },
+	{ 0xbc32eee7, "spl_panic" },
+	{ 0xe52592a, "panic" },
+	{ 0xb4390f9a, "mcount" },
+};
+
+static const char __module_depends[]
+__used
+__attribute__((section(".modinfo"))) =
+"depends=spl";
+
+
+MODULE_INFO(srcversion, "C188A8AF7758C6D5506AE88");
diff --git a/module/nvpair/znvpair.mod.c b/module/nvpair/znvpair.mod.c
new file mode 100644
index 0000000..9c37d77
--- /dev/null
+++ b/module/nvpair/znvpair.mod.c
@@ -0,0 +1,42 @@
+#include <linux/module.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+struct module __this_module
+__attribute__((section(".gnu.linkonce.this_module"))) = {
+ .name = KBUILD_MODNAME,
+ .init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+ .exit = cleanup_module,
+#endif
+ .arch = MODULE_ARCH_INIT,
+};
+
+static const struct modversion_info ____versions[]
+__used
+__attribute__((section("__versions"))) = {
+	{ 0x51198477, "module_layout" },
+	{ 0x349cba85, "strchr" },
+	{ 0x25ec1b28, "strlen" },
+	{ 0xab140103, "spl_kmem_alloc" },
+	{ 0xbc32eee7, "spl_panic" },
+	{ 0xe2d5255a, "strcmp" },
+	{ 0xde0bdcff, "memset" },
+	{ 0xb4390f9a, "mcount" },
+	{ 0x85abc85f, "strncmp" },
+	{ 0xdae80439, "spl_vmem_alloc" },
+	{ 0x82fe53e1, "ddi_strtol" },
+	{ 0xddd4a3d3, "xdrmem_create" },
+	{ 0xa3a5be95, "memmove" },
+	{ 0x80c3f220, "spl_kmem_free" },
+};
+
+static const char __module_depends[]
+__used
+__attribute__((section(".modinfo"))) =
+"depends=spl";
+
+
+MODULE_INFO(srcversion, "3BD67F56FE7BC46673DD6A6");
diff --git a/module/unicode/zunicode.mod.c b/module/unicode/zunicode.mod.c
new file mode 100644
index 0000000..88cda5e
--- /dev/null
+++ b/module/unicode/zunicode.mod.c
@@ -0,0 +1,34 @@
+#include <linux/module.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+struct module __this_module
+__attribute__((section(".gnu.linkonce.this_module"))) = {
+ .name = KBUILD_MODNAME,
+ .init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+ .exit = cleanup_module,
+#endif
+ .arch = MODULE_ARCH_INIT,
+};
+
+static const struct modversion_info ____versions[]
+__used
+__attribute__((section("__versions"))) = {
+	{ 0x51198477, "module_layout" },
+	{ 0x25ec1b28, "strlen" },
+	{ 0xe2d5255a, "strcmp" },
+	{ 0xb4390f9a, "mcount" },
+	{ 0x85abc85f, "strncmp" },
+	{ 0xf0fdf6cb, "__stack_chk_fail" },
+};
+
+static const char __module_depends[]
+__used
+__attribute__((section(".modinfo"))) =
+"depends=";
+
+
+MODULE_INFO(srcversion, "5DC8CE3A830A36341CDAF7F");
diff --git a/module/zcommon/zcommon.mod.c b/module/zcommon/zcommon.mod.c
new file mode 100644
index 0000000..465d241
--- /dev/null
+++ b/module/zcommon/zcommon.mod.c
@@ -0,0 +1,54 @@
+#include <linux/module.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+struct module __this_module
+__attribute__((section(".gnu.linkonce.this_module"))) = {
+ .name = KBUILD_MODNAME,
+ .init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+ .exit = cleanup_module,
+#endif
+ .arch = MODULE_ARCH_INIT,
+};
+
+static const struct modversion_info ____versions[]
+__used
+__attribute__((section("__versions"))) = {
+	{ 0x51198477, "module_layout" },
+	{ 0x4c4fef19, "kernel_stack" },
+	{ 0x25ec1b28, "strlen" },
+	{ 0xab140103, "spl_kmem_alloc" },
+	{ 0x167e7f9d, "__get_user_1" },
+	{ 0xbc32eee7, "spl_panic" },
+	{ 0xe2d5255a, "strcmp" },
+	{ 0x4f8b5ddb, "_copy_to_user" },
+	{ 0xee8843fa, "nvpair_value_uint64" },
+	{ 0x11089ac7, "_ctype" },
+	{ 0xa1c76e0a, "_cond_resched" },
+	{ 0xb4390f9a, "mcount" },
+	{ 0x85abc85f, "strncmp" },
+	{ 0x9ca95a0e, "sort" },
+	{ 0xd42a96fa, "nvpair_name" },
+	{ 0x1bfac311, "nvlist_lookup_nvlist" },
+	{ 0x5d6e0bba, "nvlist_lookup_uint64" },
+	{ 0xd0920999, "nvpair_value_uint32" },
+	{ 0x29c88b11, "nvlist_next_nvpair" },
+	{ 0x82027a4c, "cmn_err" },
+	{ 0x50720c5f, "snprintf" },
+	{ 0xec1cce40, "nvlist_lookup_nvlist_array" },
+	{ 0xa3a5be95, "memmove" },
+	{ 0x80c3f220, "spl_kmem_free" },
+	{ 0x4f6b400b, "_copy_from_user" },
+	{ 0xa66a6969, "nvpair_value_nvlist" },
+};
+
+static const char __module_depends[]
+__used
+__attribute__((section(".modinfo"))) =
+"depends=spl,znvpair";
+
+
+MODULE_INFO(srcversion, "D94B05FC2B3769899B59647");
diff --git a/module/zfs/dmu_object.c b/module/zfs/dmu_object.c
index c0e8d7b..177162f 100644
--- a/module/zfs/dmu_object.c
+++ b/module/zfs/dmu_object.c
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2013, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2013, 2015 by Delphix. All rights reserved.
  * Copyright 2014 HybridCluster. All rights reserved.
  */
 
@@ -50,6 +50,12 @@ dmu_object_alloc(objset_t *os, dmu_object_type_t ot, int blocksize,
 		 * reasonably sparse (at most 1/4 full).  Look from the
 		 * beginning once, but after that keep looking from here.
 		 * If we can't find one, just keep going from here.
+		 *
+		 * Note that dmu_traverse depends on the behavior that we use
+		 * multiple blocks of the dnode object before going back to
+		 * reuse objects.  Any change to this algorithm should preserve
+		 * that property or find another solution to the issues
+		 * described in traverse_visitbp.
 		 */
 		if (P2PHASE(object, L2_dnode_count) == 0) {
 			uint64_t offset = restarted ? object << DNODE_SHIFT : 0;
diff --git a/module/zfs/dmu_objset.c b/module/zfs/dmu_objset.c
index 779b3bb..f2d492e 100644
--- a/module/zfs/dmu_objset.c
+++ b/module/zfs/dmu_objset.c
@@ -26,6 +26,7 @@
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
  * Copyright (c) 2015 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2015, STRATO AG, Inc. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 /* Portions Copyright 2010 Robert Milkowski */
@@ -900,6 +901,8 @@ dmu_objset_create_sync(void *arg, dmu_tx_t *tx)
 	}
 
 	spa_history_log_internal_ds(ds, "create", tx, "");
+	zvol_create_minors(dp->dp_spa, doca->doca_name, B_TRUE);
+
 	dsl_dataset_rele(ds, FTAG);
 	dsl_dir_rele(pdd, FTAG);
 }
@@ -993,6 +996,7 @@ dmu_objset_clone_sync(void *arg, dmu_tx_t *tx)
 	dsl_dataset_name(origin, namebuf);
 	spa_history_log_internal_ds(ds, "clone", tx,
 	    "origin=%s (%llu)", namebuf, origin->ds_object);
+	zvol_create_minors(dp->dp_spa, doca->doca_clone, B_TRUE);
 	dsl_dataset_rele(ds, FTAG);
 	dsl_dataset_rele(origin, FTAG);
 	dsl_dir_rele(pdd, FTAG);
diff --git a/module/zfs/dmu_send.c b/module/zfs/dmu_send.c
index b2d844e..6a349c6 100644
--- a/module/zfs/dmu_send.c
+++ b/module/zfs/dmu_send.c
@@ -24,6 +24,7 @@
  * Copyright 2011 Nexenta Systems, Inc. All rights reserved.
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright (c) 2011, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include <sys/dmu.h>
@@ -53,6 +54,7 @@
 #include <sys/blkptr.h>
 #include <sys/dsl_bookmark.h>
 #include <sys/zfeature.h>
+#include <sys/zvol.h>
 
 /* Set this tunable to TRUE to replace corrupt data with 0x2f5baddb10c */
 int zfs_send_corrupt_data = B_FALSE;
@@ -2162,6 +2164,7 @@ dmu_recv_end_sync(void *arg, dmu_tx_t *tx)
 		dsl_dataset_phys(ds)->ds_flags &= ~DS_FLAG_INCONSISTENT;
 	}
 	drc->drc_newsnapobj = dsl_dataset_phys(drc->drc_ds)->ds_prev_snap_obj;
+	zvol_create_minors(dp->dp_spa, drc->drc_tofs, B_TRUE);
 	/*
 	 * Release the hold from dmu_recv_begin.  This must be done before
 	 * we return to open context, so that when we free the dataset's dnode,
diff --git a/module/zfs/dmu_traverse.c b/module/zfs/dmu_traverse.c
index 12d099b..cdb29b6 100644
--- a/module/zfs/dmu_traverse.c
+++ b/module/zfs/dmu_traverse.c
@@ -20,7 +20,7 @@
  */
 /*
  * Copyright (c) 2005, 2010, Oracle and/or its affiliates. All rights reserved.
- * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
+ * Copyright (c) 2012, 2016 by Delphix. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -61,6 +61,7 @@ typedef struct traverse_data {
 	uint64_t td_hole_birth_enabled_txg;
 	blkptr_cb_t *td_func;
 	void *td_arg;
+	boolean_t td_realloc_possible;
 } traverse_data_t;
 
 static int traverse_dnode(traverse_data_t *td, const dnode_phys_t *dnp,
@@ -228,18 +229,30 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
 
 	if (bp->blk_birth == 0) {
 		/*
-		 * Since this block has a birth time of 0 it must be a
-		 * hole created before the SPA_FEATURE_HOLE_BIRTH
-		 * feature was enabled.  If SPA_FEATURE_HOLE_BIRTH
-		 * was enabled before the min_txg for this traveral we
-		 * know the hole must have been created before the
-		 * min_txg for this traveral, so we can skip it. If
-		 * SPA_FEATURE_HOLE_BIRTH was enabled after the min_txg
-		 * for this traveral we cannot tell if the hole was
-		 * created before or after the min_txg for this
-		 * traversal, so we cannot skip it.
+		 * Since this block has a birth time of 0 it must be one of
+		 * two things: a hole created before the
+		 * SPA_FEATURE_HOLE_BIRTH feature was enabled, or a hole
+		 * which has always been a hole in an object.
+		 *
+		 * If a file is written sparsely, then the unwritten parts of
+		 * the file were "always holes" -- that is, they have been
+		 * holes since this object was allocated.  However, we (and
+		 * our callers) can not necessarily tell when an object was
+		 * allocated.  Therefore, if it's possible that this object
+		 * was freed and then its object number reused, we need to
+		 * visit all the holes with birth==0.
+		 *
+		 * If it isn't possible that the object number was reused,
+		 * then if SPA_FEATURE_HOLE_BIRTH was enabled before we wrote
+		 * all the blocks we will visit as part of this traversal,
+		 * then this hole must have always existed, so we can skip
+		 * it.  We visit blocks born after (exclusive) td_min_txg.
+		 *
+		 * Note that the meta-dnode cannot be reallocated.
 		 */
-		if (td->td_hole_birth_enabled_txg < td->td_min_txg)
+		if ((!td->td_realloc_possible ||
+			zb->zb_object == DMU_META_DNODE_OBJECT) &&
+			td->td_hole_birth_enabled_txg <= td->td_min_txg)
 			return (0);
 	} else if (bp->blk_birth <= td->td_min_txg) {
 		return (0);
@@ -347,6 +360,15 @@ traverse_visitbp(traverse_data_t *td, const dnode_phys_t *dnp,
 
 		prefetch_dnode_metadata(td, mdnp, zb->zb_objset,
 		    DMU_META_DNODE_OBJECT);
+		/*
+		 * See the block comment above for the goal of this variable.
+		 * If the maxblkid of the meta-dnode is 0, then we know that
+		 * we've never had more than DNODES_PER_BLOCK objects in the
+		 * dataset, which means we can't have reused any object ids.
+		 */
+		if (osp->os_meta_dnode.dn_maxblkid == 0)
+			td->td_realloc_possible = B_FALSE;
+
 		if (arc_buf_size(buf) >= sizeof (objset_phys_t)) {
 			prefetch_dnode_metadata(td, gdnp, zb->zb_objset,
 			    DMU_GROUPUSED_OBJECT);
@@ -530,12 +552,13 @@ traverse_impl(spa_t *spa, dsl_dataset_t *ds, uint64_t objset, blkptr_t *rootbp,
 	td->td_pfd = pd;
 	td->td_flags = flags;
 	td->td_paused = B_FALSE;
+	td->td_realloc_possible = (txg_start == 0 ? B_FALSE : B_TRUE);
 
 	if (spa_feature_is_active(spa, SPA_FEATURE_HOLE_BIRTH)) {
 		VERIFY(spa_feature_enabled_txg(spa,
 		    SPA_FEATURE_HOLE_BIRTH, &td->td_hole_birth_enabled_txg));
 	} else {
-		td->td_hole_birth_enabled_txg = 0;
+		td->td_hole_birth_enabled_txg = UINT64_MAX;
 	}
 
 	pd->pd_flags = flags;
diff --git a/module/zfs/dsl_dataset.c b/module/zfs/dsl_dataset.c
index 2168f28..a063885 100644
--- a/module/zfs/dsl_dataset.c
+++ b/module/zfs/dsl_dataset.c
@@ -24,6 +24,7 @@
  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 RackTop Systems.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include <sys/dmu_objset.h>
@@ -1376,6 +1377,7 @@ dsl_dataset_snapshot_sync(void *arg, dmu_tx_t *tx)
 			dsl_props_set_sync_impl(ds->ds_prev,
 			    ZPROP_SRC_LOCAL, ddsa->ddsa_props, tx);
 		}
+		zvol_create_minors(dp->dp_spa, nvpair_name(pair), B_TRUE);
 		dsl_dataset_rele(ds, FTAG);
 	}
 }
@@ -1450,16 +1452,6 @@ dsl_dataset_snapshot(nvlist_t *snaps, nvlist_t *props, nvlist_t *errors)
 		fnvlist_free(suspended);
 	}
 
-#ifdef _KERNEL
-	if (error == 0) {
-		for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
-		    pair = nvlist_next_nvpair(snaps, pair)) {
-			char *snapname = nvpair_name(pair);
-			zvol_create_minors(snapname);
-		}
-	}
-#endif
-
 	return (error);
 }
 
@@ -1870,6 +1862,8 @@ dsl_dataset_rename_snapshot_sync_impl(dsl_pool_t *dp,
 	VERIFY0(zap_add(dp->dp_meta_objset,
 	    dsl_dataset_phys(hds)->ds_snapnames_zapobj,
 	    ds->ds_snapname, 8, 1, &ds->ds_object, tx));
+	zvol_rename_minors(dp->dp_spa, ddrsa->ddrsa_oldsnapname,
+	    ddrsa->ddrsa_newsnapname, B_TRUE);
 
 	dsl_dataset_rele(ds, FTAG);
 	return (0);
@@ -1898,11 +1892,6 @@ int
 dsl_dataset_rename_snapshot(const char *fsname,
     const char *oldsnapname, const char *newsnapname, boolean_t recursive)
 {
-#ifdef _KERNEL
-	char *oldname, *newname;
-#endif
-	int error;
-
 	dsl_dataset_rename_snapshot_arg_t ddrsa;
 
 	ddrsa.ddrsa_fsname = fsname;
@@ -1910,22 +1899,9 @@ dsl_dataset_rename_snapshot(const char *fsname,
 	ddrsa.ddrsa_newsnapname = newsnapname;
 	ddrsa.ddrsa_recursive = recursive;
 
-	error = dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
+	return (dsl_sync_task(fsname, dsl_dataset_rename_snapshot_check,
 	    dsl_dataset_rename_snapshot_sync, &ddrsa,
-	    1, ZFS_SPACE_CHECK_RESERVED);
-
-	if (error)
-	    return (SET_ERROR(error));
-
-#ifdef _KERNEL
-	oldname = kmem_asprintf("%s@%s", fsname, oldsnapname);
-	newname = kmem_asprintf("%s@%s", fsname, newsnapname);
-	zvol_rename_minors(oldname, newname);
-	strfree(newname);
-	strfree(oldname);
-#endif
-
-	return (0);
+	    1, ZFS_SPACE_CHECK_RESERVED));
 }
 
 /*
diff --git a/module/zfs/dsl_destroy.c b/module/zfs/dsl_destroy.c
index 0e2238f..34d076e 100644
--- a/module/zfs/dsl_destroy.c
+++ b/module/zfs/dsl_destroy.c
@@ -23,6 +23,7 @@
  * Copyright (c) 2012, 2014 by Delphix. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2013 by Joyent, Inc. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include <sys/zfs_context.h>
@@ -40,6 +41,7 @@
 #include <sys/zfs_ioctl.h>
 #include <sys/dsl_deleg.h>
 #include <sys/dmu_impl.h>
+#include <sys/zvol.h>
 
 typedef struct dmu_snapshots_destroy_arg {
 	nvlist_t *dsda_snaps;
@@ -243,9 +245,6 @@ dsl_dataset_remove_clones_key(dsl_dataset_t *ds, uint64_t mintxg, dmu_tx_t *tx)
 void
 dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
 {
-#ifdef ZFS_DEBUG
-	int err;
-#endif
 	int after_branch_point = FALSE;
 	dsl_pool_t *dp = ds->ds_dir->dd_pool;
 	objset_t *mos = dp->dp_meta_objset;
@@ -438,6 +437,7 @@ dsl_destroy_snapshot_sync_impl(dsl_dataset_t *ds, boolean_t defer, dmu_tx_t *tx)
 #ifdef ZFS_DEBUG
 	{
 		uint64_t val;
+		int err;
 
 		err = dsl_dataset_snap_lookup(ds_head,
 		    ds->ds_snapname, &val);
@@ -487,6 +487,7 @@ dsl_destroy_snapshot_sync(void *arg, dmu_tx_t *tx)
 		VERIFY0(dsl_dataset_hold(dp, nvpair_name(pair), FTAG, &ds));
 
 		dsl_destroy_snapshot_sync_impl(ds, dsda->dsda_defer, tx);
+		zvol_remove_minors(dp->dp_spa, nvpair_name(pair), B_TRUE);
 		dsl_dataset_rele(ds, FTAG);
 	}
 }
@@ -881,6 +882,7 @@ dsl_destroy_head_sync(void *arg, dmu_tx_t *tx)
 
 	VERIFY0(dsl_dataset_hold(dp, ddha->ddha_name, FTAG, &ds));
 	dsl_destroy_head_sync_impl(ds, tx);
+	zvol_remove_minors(dp->dp_spa, ddha->ddha_name, B_TRUE);
 	dsl_dataset_rele(ds, FTAG);
 }
 
diff --git a/module/zfs/dsl_dir.c b/module/zfs/dsl_dir.c
index ba6c244..762e2e5 100644
--- a/module/zfs/dsl_dir.c
+++ b/module/zfs/dsl_dir.c
@@ -24,6 +24,7 @@
  * Copyright (c) 2013 Martin Matuska. All rights reserved.
  * Copyright (c) 2014 Joyent, Inc. All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include <sys/dmu.h>
@@ -1913,9 +1914,8 @@ dsl_dir_rename_sync(void *arg, dmu_tx_t *tx)
 	VERIFY0(zap_add(mos, dsl_dir_phys(newparent)->dd_child_dir_zapobj,
 	    dd->dd_myname, 8, 1, &dd->dd_object, tx));
 
-#ifdef _KERNEL
-	zvol_rename_minors(ddra->ddra_oldname, ddra->ddra_newname);
-#endif
+	zvol_rename_minors(dp->dp_spa, ddra->ddra_oldname,
+	    ddra->ddra_newname, B_TRUE);
 
 	dsl_prop_notify_all(dd);
 
diff --git a/module/zfs/spa.c b/module/zfs/spa.c
index b4831a7..4468cdf 100644
--- a/module/zfs/spa.c
+++ b/module/zfs/spa.c
@@ -24,6 +24,7 @@
  * Copyright (c) 2013 by Delphix. All rights reserved.
  * Copyright (c) 2013, 2014, Nexenta Systems, Inc.  All rights reserved.
  * Copyright (c) 2014 Spectra Logic Corporation, All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 /*
@@ -1131,6 +1132,24 @@ spa_activate(spa_t *spa, int mode)
 	avl_create(&spa->spa_errlist_last,
 	    spa_error_entry_compare, sizeof (spa_error_entry_t),
 	    offsetof(spa_error_entry_t, se_avl));
+
+	/*
+	 * This taskq is used to perform zvol-minor-related tasks
+	 * asynchronously. This has several advantages, including easy
+	 * resolution of various deadlocks (zfsonlinux bug #3681).
+	 *
+	 * The taskq must be single threaded to ensure tasks are always
+	 * processed in the order in which they were dispatched.
+	 *
+	 * A taskq per pool allows one to keep the pools independent.
+	 * This way if one pool is suspended, it will not impact another.
+	 *
+	 * The preferred location to dispatch a zvol minor task is a sync
+	 * task. In this context, there is easy access to the spa_t and minimal
+	 * error handling is required because the sync task must succeed.
+	 */
+	spa->spa_zvol_taskq = taskq_create("z_zvol", 1, defclsyspri,
+	    1, INT_MAX, 0);
 }
 
 /*
@@ -1149,6 +1168,11 @@ spa_deactivate(spa_t *spa)
 
 	spa_evicting_os_wait(spa);
 
+	if (spa->spa_zvol_taskq) {
+		taskq_destroy(spa->spa_zvol_taskq);
+		spa->spa_zvol_taskq = NULL;
+	}
+
 	txg_list_destroy(&spa->spa_vdev_txg_list);
 
 	list_destroy(&spa->spa_config_dirty_list);
@@ -3083,10 +3107,8 @@ spa_open_common(const char *pool, spa_t **spapp, void *tag, nvlist_t *nvpolicy,
 		mutex_exit(&spa_namespace_lock);
 	}
 
-#ifdef _KERNEL
 	if (firstopen)
-		zvol_create_minors(spa->spa_name);
-#endif
+		zvol_create_minors(spa, spa_name(spa), B_TRUE);
 
 	*spapp = spa;
 
@@ -4206,10 +4228,7 @@ spa_import(char *pool, nvlist_t *config, nvlist_t *props, uint64_t flags)
 
 	mutex_exit(&spa_namespace_lock);
 	spa_history_log_version(spa, "import");
-
-#ifdef _KERNEL
-	zvol_create_minors(pool);
-#endif
+	zvol_create_minors(spa, pool, B_TRUE);
 
 	return (0);
 }
@@ -4344,6 +4363,10 @@ spa_export_common(char *pool, int new_state, nvlist_t **oldconfig,
 	spa_open_ref(spa, FTAG);
 	mutex_exit(&spa_namespace_lock);
 	spa_async_suspend(spa);
+	if (spa->spa_zvol_taskq) {
+		zvol_remove_minors(spa, spa_name(spa), B_TRUE);
+		taskq_wait(spa->spa_zvol_taskq);
+	}
 	mutex_enter(&spa_namespace_lock);
 	spa_close(spa, FTAG);
 
diff --git a/module/zfs/zfs.mod.c b/module/zfs/zfs.mod.c
new file mode 100644
index 0000000..9e0b227
--- /dev/null
+++ b/module/zfs/zfs.mod.c
@@ -0,0 +1,474 @@
+#include <linux/module.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+struct module __this_module
+__attribute__((section(".gnu.linkonce.this_module"))) = {
+ .name = KBUILD_MODNAME,
+ .init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+ .exit = cleanup_module,
+#endif
+ .arch = MODULE_ARCH_INIT,
+};
+
+static const struct modversion_info ____versions[]
+__used
+__attribute__((section("__versions"))) = {
+	{ 0x51198477, "module_layout" },
+	{ 0xdd4acab1, "vn_fsync" },
+	{ 0x9937746a, "d_path" },
+	{ 0x13be9977, "nvlist_add_boolean_array" },
+	{ 0x9a1dfd65, "strpbrk" },
+	{ 0xb7d1325e, "nvlist_add_int32" },
+	{ 0x6cc650a4, "zfs_prop_get_type" },
+	{ 0x6ae12453, "__kstat_install" },
+	{ 0x1c90ea0e, "nvlist_add_int64" },
+	{ 0x36198a4d, "nvpair_value_string" },
+	{ 0x405c1144, "get_seconds" },
+	{ 0x8d8996ce, "z_uncompress" },
+	{ 0x4c327173, "alloc_disk" },
+	{ 0x34eccc79, "generic_getxattr" },
+	{ 0x8b484c4c, "fnvlist_lookup_nvpair" },
+	{ 0xcf47e212, "fnvlist_add_int32" },
+	{ 0x26b64321, "call_usermodehelper_setfns" },
+	{ 0xf5893abf, "up_read" },
+	{ 0x8f20556d, "blk_cleanup_queue" },
+	{ 0xaada9d55, "zfs_prop_init" },
+	{ 0xb41ea00a, "nvlist_add_uint8_array" },
+	{ 0xeae36f92, "blk_queue_io_opt" },
+	{ 0xdc89486b, "zfs_name_to_prop" },
+	{ 0xdb347c7a, "call_usermodehelper_exec" },
+	{ 0x3a3b4efc, "generic_file_llseek" },
+	{ 0xda48c2e6, "__mark_inode_dirty" },
+	{ 0xd4bf55ff, "u8_validate" },
+	{ 0x3228f0a3, "d_invalidate" },
+	{ 0x21b5a134, "__set_page_dirty_nobuffers" },
+	{ 0xf2f1ef64, "fnvlist_alloc" },
+	{ 0xadaabe1b, "pv_lock_ops" },
+	{ 0x349cba85, "strchr" },
+	{ 0x9191a98c, "nvlist_add_uint32_array" },
+	{ 0xce291afa, "bio_alloc" },
+	{ 0x150ddbd2, "kstat_runq_enter" },
+	{ 0x370dbc79, "__remove_inode_hash" },
+	{ 0x2fe3ab3e, "get_gendisk" },
+	{ 0x3ec8886f, "param_ops_int" },
+	{ 0x1403a15e, "taskq_member" },
+	{ 0xb0364551, "zio_arena" },
+	{ 0xf5dea0d6, "nvpair_value_int64_array" },
+	{ 0x25ec1b28, "strlen" },
+	{ 0xd0ee38b8, "schedule_timeout_uninterruptible" },
+	{ 0x8205f265, "crhold" },
+	{ 0x3a9b6fb9, "blk_unregister_region" },
+	{ 0xb37f3106, "d_set_d_op" },
+	{ 0xaaf57193, "blk_queue_max_hw_sectors" },
+	{ 0x1efe1f66, "vn_close" },
+	{ 0xa6867664, "filemap_write_and_wait_range" },
+	{ 0x4ff1c9bc, "populate_rootfs_wait" },
+	{ 0x16916efb, "nvlist_prev_nvpair" },
+	{ 0x19295e53, "taskq_create" },
+	{ 0x1ba29031, "zfs_component_namecheck" },
+	{ 0xffc19dde, "elevator_change" },
+	{ 0x89a7204c, "kill_anon_super" },
+	{ 0x3f38bd50, "crgetruid" },
+	{ 0x6a4152d5, "nvlist_add_uint64" },
+	{ 0x6363ef50, "fnvlist_pack_free" },
+	{ 0xd0799edd, "posix_acl_to_xattr" },
+	{ 0xd14a7eb5, "vn_getattr" },
+	{ 0xed8dac48, "nvlist_pack" },
+	{ 0xbd100793, "cpu_online_mask" },
+	{ 0x79aa04a2, "get_random_bytes" },
+	{ 0x67053080, "current_kernel_time" },
+	{ 0xf4f0a175, "avl_nearest" },
+	{ 0xab140103, "spl_kmem_alloc" },
+	{ 0x5d16cdc5, "nvlist_exists" },
+	{ 0xd0bd878, "seq_puts" },
+	{ 0x80c478fd, "rootdir" },
+	{ 0xa850554e, "vn_seek" },
+	{ 0x73a78bc4, "downgrade_write" },
+	{ 0xcb98e344, "truncate_inode_pages_range" },
+	{ 0x2e93154b, "generic_file_open" },
+	{ 0xacf4d843, "match_strdup" },
+	{ 0xffff91e3, "taskq_init_ent" },
+	{ 0x3f69d73b, "test_set_page_writeback" },
+	{ 0xefc4da17, "kobj_close_file" },
+	{ 0xcf24ceff, "nvlist_remove" },
+	{ 0xcd69282b, "__lock_page" },
+	{ 0xb54533f7, "usecs_to_jiffies" },
+	{ 0x581b3ff3, "zpool_prop_get_type" },
+	{ 0xa483a8c3, "zfs_prop_to_name" },
+	{ 0x63bdf5f0, "crgetngroups" },
+	{ 0xf7fb002a, "kobj_get_filesize" },
+	{ 0xd6f70ea0, "nvlist_empty" },
+	{ 0x187c0510, "nvpair_value_int64" },
+	{ 0x21a7d814, "seq_printf" },
+	{ 0xac095684, "zfs_prop_inheritable" },
+	{ 0xb6c2717d, "fnvlist_lookup_uint64" },
+	{ 0x44e9a829, "match_token" },
+	{ 0x582829a0, "avl_last" },
+	{ 0xf4e84391, "nvlist_add_nvlist" },
+	{ 0xb205e7ee, "nvpair_value_uint16_array" },
+	{ 0x8e4c2658, "crgetgroups" },
+	{ 0x7cb40d78, "avl_insert_here" },
+	{ 0xf3e29ae0, "zpool_prop_to_name" },
+	{ 0x64913468, "nvpair_value_uint8_array" },
+	{ 0x305105e, "end_writeback" },
+	{ 0xba2adaf, "mutex_unlock" },
+	{ 0x407478e1, "nvpair_value_uint32_array" },
+	{ 0x85df9b6c, "strsep" },
+	{ 0xccc94e8, "nvlist_lookup_string" },
+	{ 0x4704f678, "vn_rdwr" },
+	{ 0xb05ef89e, "fnvlist_add_uint64" },
+	{ 0x80336cc4, "generic_read_dir" },
+	{ 0x1083f24f, "zfs_prop_valid_for_type" },
+	{ 0x5be9e34a, "zfs_prop_setonce" },
+	{ 0x76e8f609, "igrab" },
+	{ 0x76ad2c09, "fnvlist_size" },
+	{ 0x58b765b9, "pool_namecheck" },
+	{ 0x47c7b0d2, "cpu_number" },
+	{ 0x75fb8325, "generic_setxattr" },
+	{ 0xafe82e10, "strcspn" },
+	{ 0x3b251083, "mount_nodev" },
+	{ 0x84000109, "path_get" },
+	{ 0xa5894c2a, "redirty_page_for_writepage" },
+	{ 0x91715312, "sprintf" },
+	{ 0x8eb0a41f, "tsd_destroy" },
+	{ 0xb8e71471, "spl_kmem_cache_free" },
+	{ 0xbc32eee7, "spl_panic" },
+	{ 0xcc13e034, "nv_alloc_init" },
+	{ 0x50ea1952, "nvlist_add_int16_array" },
+	{ 0x7d11c268, "jiffies" },
+	{ 0x6ccdbacb, "lookup_bdev" },
+	{ 0x6fba9cae, "truncate_setsize" },
+	{ 0x31eb4278, "mutex_trylock" },
+	{ 0x57a6ccd0, "down_read" },
+	{ 0xe2d5255a, "strcmp" },
+	{ 0x35225ea3, "down_write_trylock" },
+	{ 0xb3d0550d, "end_page_writeback" },
+	{ 0x8a4cbe5a, "cv_timedwait_hires" },
+	{ 0xde9360ba, "totalram_pages" },
+	{ 0xaa65a555, "kmem_asprintf" },
+	{ 0x42585bc5, "nvlist_add_string_array" },
+	{ 0x1d06c4ac, "u8_strcmp" },
+	{ 0xd416eac3, "nvlist_xalloc" },
+	{ 0xcfb24408, "nvpair_value_int32" },
+	{ 0x786ba98a, "crgetuid" },
+	{ 0xf2cb0b79, "uio_prefaultpages" },
+	{ 0xba3e2d71, "zone_get_hostid" },
+	{ 0xd1bf81d6, "invalidate_bdev" },
+	{ 0x6395be94, "__init_waitqueue_head" },
+	{ 0x4f8b5ddb, "_copy_to_user" },
+	{ 0x3c7cdc13, "avl_remove" },
+	{ 0x528f1f4e, "nvpair_value_int8_array" },
+	{ 0xe24d3a97, "jiffies_64" },
+	{ 0xee8843fa, "nvpair_value_uint64" },
+	{ 0xc98d2e5d, "blk_queue_max_segments" },
+	{ 0x106b6ba8, "taskq_destroy" },
+	{ 0x6d0aba34, "wait_for_completion" },
+	{ 0x72aa82c6, "param_ops_charp" },
+	{ 0xb11fa1ce, "strlcat" },
+	{ 0x45fe0d68, "inode_owner_or_capable" },
+	{ 0x114258fb, "misc_register" },
+	{ 0x7023fd74, "zfs_spa_version_map" },
+	{ 0x66cb0ee2, "nvpair_value_uint64_array" },
+	{ 0xaba3870c, "kern_path" },
+	{ 0xde0bdcff, "memset" },
+	{ 0x8b78128, "spl_kmem_cache_destroy" },
+	{ 0xbd256438, "nvlist_lookup_nvpair" },
+	{ 0x81c1c2b2, "vmem_size" },
+	{ 0xbc9dddde, "taskq_wait_id" },
+	{ 0x4f6584e1, "vn_getf" },
+	{ 0x516b8b85, "nvlist_add_int8_array" },
+	{ 0x79a0ecea, "d_add_ci" },
+	{ 0xc810362f, "strdup" },
+	{ 0x852e6c79, "blk_alloc_queue" },
+	{ 0x26cd2d80, "fnvlist_num_pairs" },
+	{ 0x22c35c6c, "fnvpair_value_nvlist" },
+	{ 0xe9ba039d, "avl_destroy" },
+	{ 0x11089ac7, "_ctype" },
+	{ 0xd9977d8, "fletcher_4_incremental_native" },
+	{ 0x8f64aa4, "_raw_spin_unlock_irqrestore" },
+	{ 0x69371301, "current_task" },
+	{ 0x143fcac6, "__cv_signal" },
+	{ 0x7b6047b1, "avl_numnodes" },
+	{ 0x6127b911, "kstat_waitq_exit" },
+	{ 0x882c1dc4, "check_disk_change" },
+	{ 0x2d004b80, "current_fs_time" },
+	{ 0x87ebeb76, "__mutex_init" },
+	{ 0x27e1a049, "printk" },
+	{ 0xeba677bd, "posix_acl_chmod" },
+	{ 0x30da4fbf, "fnvlist_free" },
+	{ 0xe6b9d3c4, "find_lock_page" },
+	{ 0xeb69fdd8, "d_obtain_alias" },
+	{ 0x2fa5a500, "memcmp" },
+	{ 0x90cc07c8, "blk_queue_max_discard_sectors" },
+	{ 0x9d9024f7, "del_gendisk" },
+	{ 0x68a9f991, "nvlist_add_uint16_array" },
+	{ 0xa4cec62, "nv_fixed_ops" },
+	{ 0x6a36f138, "zpool_prop_feature" },
+	{ 0xd04b4649, "crgetfsgid" },
+	{ 0xf2048734, "bio_add_page" },
+	{ 0xe8856dea, "nvlist_remove_nvpair" },
+	{ 0x35b9d4a6, "nvlist_add_nvlist_array" },
+	{ 0x75a78768, "nvlist_alloc" },
+	{ 0xa26a953e, "fletcher_2_byteswap" },
+	{ 0x27655c15, "zfs_allocatable_devs" },
+	{ 0xf7eb91ff, "d_alloc_root" },
+	{ 0xe52592a, "panic" },
+	{ 0xe2fd64d6, "nvpair_value_hrtime" },
+	{ 0xa1c76e0a, "_cond_resched" },
+	{ 0xb940ee11, "taskq_wait" },
+	{ 0x7ec9bfbc, "strncpy" },
+	{ 0x70f7c090, "__kstat_set_raw_ops" },
+	{ 0xb4390f9a, "mcount" },
+	{ 0x422932ac, "nvlist_lookup_int32" },
+	{ 0x9e5f923c, "blkdev_get_by_path" },
+	{ 0x5da5c9c6, "security_inode_init_security" },
+	{ 0x8b19c37b, "check_disk_size_change" },
+	{ 0x11edcd4c, "blk_register_region" },
+	{ 0x85abc85f, "strncmp" },
+	{ 0x672144bd, "strlcpy" },
+	{ 0xbf8ba54a, "vprintk" },
+	{ 0xafe1db9d, "mutex_lock" },
+	{ 0xe5318fa0, "write_cache_pages" },
+	{ 0xa340453c, "system_taskq" },
+	{ 0x13401075, "taskq_dispatch" },
+	{ 0xc8f88566, "nvpair_value_uint16" },
+	{ 0x9f1dd1aa, "avl_insert" },
+	{ 0x732cbdd2, "avl_is_empty" },
+	{ 0xcb99edb0, "posix_acl_equiv_mode" },
+	{ 0x5bb6ad4b, "spl_vmem_zalloc" },
+	{ 0x71a50dbc, "register_blkdev" },
+	{ 0x9b4571df, "nvpair_value_int32_array" },
+	{ 0x79cca7cb, "uioskip" },
+	{ 0x30cc3621, "insert_inode_locked" },
+	{ 0xb3db5628, "avl_create" },
+	{ 0xafa476dd, "nvpair_value_int8" },
+	{ 0x90782bf3, "nvlist_add_string" },
+	{ 0x13f6f973, "wait_on_page_bit" },
+	{ 0x5559ab10, "zfs_deleg_whokey" },
+	{ 0x4223cbc0, "uiocopy" },
+	{ 0x7a82be45, "unlock_page" },
+	{ 0x3b4ceb4a, "up_write" },
+	{ 0x5318e74d, "shrink_dcache_sb" },
+	{ 0x1ebbfffd, "ddi_copyout" },
+	{ 0xe6e3b875, "down_write" },
+	{ 0xcc762837, "kstat_waitq_enter" },
+	{ 0x52252d43, "get_disk" },
+	{ 0x6d601403, "crgetgid" },
+	{ 0x64623de, "kmem_vasprintf" },
+	{ 0x618628e6, "avl_destroy_nodes" },
+	{ 0xd16645b6, "fnvlist_add_nvlist" },
+	{ 0x89f2142a, "nvpair_value_nvlist_array" },
+	{ 0xdb9e2c22, "posix_acl_create" },
+	{ 0xd42a96fa, "nvpair_name" },
+	{ 0x52778ec7, "vcmn_err" },
+	{ 0x7c0a143, "bio_endio" },
+	{ 0x920ca817, "bio_put" },
+	{ 0xf41bf8b5, "generic_removexattr" },
+	{ 0x1b7b5809, "__cv_broadcast" },
+	{ 0x3323ccb1, "tsd_get" },
+	{ 0xfcb16c49, "mark_page_accessed" },
+	{ 0x180d429, "nvlist_add_int64_array" },
+	{ 0x53bddca5, "taskq_dispatch_ent" },
+	{ 0x61651be, "strcat" },
+	{ 0x27277915, "vm_stat" },
+	{ 0xd1346eaa, "avl_first" },
+	{ 0x5cbae8f4, "crgetfsuid" },
+	{ 0x1bc61496, "nvpair_value_int16_array" },
+	{ 0xb5a459dc, "unregister_blkdev" },
+	{ 0x24208ad1, "__cv_wait_io" },
+	{ 0xb428a99c, "zfs_deleg_verify_nvlist" },
+	{ 0x87b743ea, "inode_init_once" },
+	{ 0x1bfac311, "nvlist_lookup_nvlist" },
+	{ 0x7479525e, "fnvlist_add_uint64_array" },
+	{ 0x9d9f80c4, "nvlist_free" },
+	{ 0x5eb99327, "simple_getattr" },
+	{ 0x50c5246d, "nvlist_add_uint8" },
+	{ 0x5d6e0bba, "nvlist_lookup_uint64" },
+	{ 0xaeefe7de, "submit_bio" },
+	{ 0xc6cbbc89, "capable" },
+	{ 0x31eaf145, "init_task" },
+	{ 0xb1c3a01a, "oops_in_progress" },
+	{ 0x9f984513, "strrchr" },
+	{ 0x351c2576, "z_compress_level" },
+	{ 0x901bfc1a, "ilookup" },
+	{ 0x81376bfd, "vn_remove" },
+	{ 0xb0030d43, "blkdev_put" },
+	{ 0xc50bab05, "unregister_shrinker" },
+	{ 0xe8adb6d8, "nvpair_value_boolean_value" },
+	{ 0x81483072, "nvlist_add_uint16" },
+	{ 0x9e3e7c5, "simple_dir_operations" },
+	{ 0xeaa8f57, "generic_file_mmap" },
+	{ 0x12a38747, "usleep_range" },
+	{ 0x6ae07d22, "__cv_wait" },
+	{ 0x17980bc5, "crfree" },
+	{ 0x34fdc162, "nvlist_unpack" },
+	{ 0x62dbf439, "blk_queue_make_request" },
+	{  0x1e77f, "nvlist_add_int32_array" },
+	{ 0x1ef1f75f, "posix_acl_valid" },
+	{ 0xaeab70e4, "zfs_prop_default_numeric" },
+	{ 0xfce9b49e, "uiomove" },
+	{ 0xc54a86a3, "blk_queue_physical_block_size" },
+	{ 0x10006f1f, "nvlist_lookup_nv_alloc" },
+	{ 0xf7b48661, "vn_set_pwd" },
+	{ 0xcb59902f, "nvlist_lookup_byte_array" },
+	{ 0xf0fdf6cb, "__stack_chk_fail" },
+	{ 0xb9249d16, "cpu_possible_mask" },
+	{ 0x3bd1b1f6, "msecs_to_jiffies" },
+	{ 0xfe56e2a4, "nvpair_value_int16" },
+	{ 0xcc8e80f8, "kstat_runq_exit" },
+	{ 0x1000e51, "schedule" },
+	{ 0x958b84e3, "tsd_create" },
+	{ 0x667ba081, "spl_kmem_cache_create" },
+	{ 0x20173f35, "taskq_wait_outstanding" },
+	{ 0x5295f485, "posix_acl_from_xattr" },
+	{ 0x85261be0, "__kstat_create" },
+	{ 0xaebbec7c, "kobj_read_file" },
+	{ 0x5b2da8a8, "put_disk" },
+	{ 0xffa90716, "unlock_new_inode" },
+	{ 0x2bbdb1d2, "nvlist_add_uint32" },
+	{ 0x6da84db2, "deactivate_super" },
+	{ 0x7274e02f, "bdi_setup_and_register" },
+	{ 0x447bea0b, "fnvpair_value_uint64" },
+	{ 0x2e36ff5c, "nvlist_remove_all" },
+	{ 0x6dc38171, "fnvlist_add_boolean" },
+	{ 0xd94959c7, "fletcher_4_native" },
+	{ 0x5e95b1cd, "current_umask" },
+	{ 0xb948e867, "zfs_prop_userquota" },
+	{ 0xd0920999, "nvpair_value_uint32" },
+	{ 0xc5ca5da8, "nvlist_merge" },
+	{ 0xdae80439, "spl_vmem_alloc" },
+	{ 0xdeea79ca, "nvlist_add_int8" },
+	{ 0xd22ed5e2, "spl_kmem_cache_alloc" },
+	{ 0x6b63f55e, "heap_arena" },
+	{ 0x1e60b5ba, "clear_page_dirty_for_io" },
+	{ 0xc6956d59, "inode_change_ok" },
+	{ 0xa3a77c69, "down_read_trylock" },
+	{ 0x65f3602b, "vn_releasef" },
+	{ 0x82384b7, "path_put" },
+	{ 0x4b88e0e9, "zpool_get_rewind_policy" },
+	{ 0x360e492b, "__cv_init" },
+	{ 0xd52bf1ce, "_raw_spin_lock" },
+	{ 0x2168361b, "fnvlist_add_nvlist_array" },
+	{ 0xff3980bf, "read_cache_pages" },
+	{ 0xb6445021, "zpool_prop_init" },
+	{ 0x9327f5ce, "_raw_spin_lock_irqsave" },
+	{ 0xe9167510, "fnvpair_value_string" },
+	{ 0xe52947e7, "__phys_addr" },
+	{ 0x7521d525, "fnvlist_lookup_string" },
+	{ 0x1b8f1d1e, "strfree" },
+	{ 0x9e7bdafa, "register_filesystem" },
+	{ 0xdafb8f63, "zpool_name_to_prop" },
+	{ 0x29c88b11, "nvlist_next_nvpair" },
+	{ 0x10f2eb76, "vsnprintf" },
+	{ 0x443890f9, "u8_textprep_str" },
+	{ 0x659a64d0, "call_usermodehelper_setup" },
+	{ 0x16d71b69, "__cv_wait_sig" },
+	{ 0x88163724, "zfs_prop_user" },
+	{ 0x2c0fbe10, "vn_open" },
+	{ 0xa456b044, "zfs_prop_readonly" },
+	{ 0x82027a4c, "cmn_err" },
+	{ 0xff40513c, "avl_find" },
+	{ 0xc43ab895, "nvlist_add_boolean_value" },
+	{ 0xe6990065, "fletcher_4_incremental_byteswap" },
+	{ 0x506746b6, "getrawmonotonic" },
+	{ 0x2e99f25f, "__cv_timedwait_sig" },
+	{ 0x8dfdd77d, "fnvpair_value_int32" },
+	{ 0x4c82bcb5, "nvlist_add_byte" },
+	{ 0x5c5fd5f1, "iput" },
+	{ 0xa0ed48c9, "fnvlist_lookup_nvlist" },
+	{ 0x6db955bf, "nvpair_type" },
+	{ 0xd2c3d1c4, "ddi_copyin" },
+	{ 0x1285cb78, "tsd_set" },
+	{ 0x3896a905, "__thread_exit" },
+	{ 0x37a0cba, "kfree" },
+	{ 0x531d58c3, "zpool_prop_index_to_string" },
+	{ 0xd234c7f7, "nvlist_add_nvpair" },
+	{ 0x236c8c64, "memcpy" },
+	{ 0x3799704a, "spl_kmem_cache_set_move" },
+	{ 0x5ecf6f91, "vn_mode_to_vtype" },
+	{ 0xea8a6c75, "param_ops_long" },
+	{ 0xe3e12c4f, "d_splice_alias" },
+	{ 0x9518b623, "register_shrinker" },
+	{ 0xe1f620de, "add_disk" },
+	{ 0x4b2cb038, "zfs_prop_index_to_string" },
+	{ 0xd1c1752d, "zfs_zpl_version_map" },
+	{ 0x434773c9, "avl_walk" },
+	{ 0xf715d7e4, "fletcher_4_byteswap" },
+	{ 0x86f43149, "zfs_userquota_prop_prefixes" },
+	{ 0xf68905fd, "ddi_strtoull" },
+	{ 0x45dd41aa, "generic_readlink" },
+	{ 0xa2fb3ea8, "put_page" },
+	{ 0x5aa48f01, "bdi_destroy" },
+	{ 0x4cbbd171, "__bitmap_weight" },
+	{ 0x4b69abe5, "nvpair_value_byte" },
+	{ 0x6811efbd, "nvlist_size" },
+	{ 0xd7e6464c, "fletcher_2_native" },
+	{ 0x3d6d97a2, "ioctl_by_bdev" },
+	{ 0x670fde39, "fnvlist_pack" },
+	{ 0x5cc844b3, "unregister_filesystem" },
+	{ 0x6cfc93ad, "init_special_inode" },
+	{ 0x9f46de9, "kobj_open_file" },
+	{ 0x4e7a84e6, "avl_add" },
+	{ 0x185936d6, "groupmember" },
+	{ 0x4ea06afa, "nvlist_add_byte_array" },
+	{ 0x4b06d2e7, "complete" },
+	{ 0x50720c5f, "snprintf" },
+	{ 0x3a1aa9fb, "bdget" },
+	{ 0x7be1c89e, "blk_queue_max_segment_size" },
+	{ 0xd433d2cb, "__kstat_delete" },
+	{ 0xa3de192d, "fnvlist_add_string" },
+	{ 0x504be4f9, "nvlist_add_int16" },
+	{ 0xec1cce40, "nvlist_lookup_nvlist_array" },
+	{ 0x4ccb2dda, "new_inode" },
+	{ 0xa3a5be95, "memmove" },
+	{ 0x43c69f9a, "zpool_prop_default_numeric" },
+	{ 0xae5d807c, "vmalloc_to_page" },
+	{ 0x80c3f220, "spl_kmem_free" },
+	{ 0x8eb2664d, "fnvlist_remove_nvpair" },
+	{ 0x6edb75cf, "follow_down_one" },
+	{ 0x7466fa85, "spl_kmem_cache_reap_now" },
+	{ 0xaa9db9bb, "nvlist_add_uint64_array" },
+	{ 0xf473f2ff, "blkdev_get" },
+	{ 0xc236e29a, "zfs_prop_default_string" },
+	{ 0xbaa28806, "simple_dir_inode_operations" },
+	{ 0x1500ba78, "__thread_create" },
+	{ 0x778a305, "spl_vmem_free" },
+	{ 0x4f6b400b, "_copy_from_user" },
+	{ 0xb3e56341, "taskq_cancel_id" },
+	{ 0xa2c56c31, "param_ops_ulong" },
+	{ 0xfad8deb5, "nv_alloc_fini" },
+	{ 0xc3fe87c8, "param_ops_uint" },
+	{ 0x19471135, "bdget_disk" },
+	{ 0xa66a6969, "nvpair_value_nvlist" },
+	{ 0xdfb0b5e5, "misc_deregister" },
+	{ 0xf91d3b5a, "nvlist_dup" },
+	{ 0x62c31a0, "bdput" },
+	{ 0x9c679abb, "d_instantiate" },
+	{ 0x2a6e6109, "__init_rwsem" },
+	{ 0xec031267, "taskq_dispatch_delay" },
+	{ 0x2821e0b2, "nvlist_lookup_uint64_array" },
+	{ 0x85524b8b, "p0" },
+	{ 0x59fe72f0, "__cv_destroy" },
+	{ 0x38dbd03a, "dataset_namecheck" },
+	{ 0x5fb4b61d, "fnvlist_dup" },
+	{ 0x8b50312f, "generic_fillattr" },
+	{ 0x2e1cae5a, "vn_openat" },
+	{ 0xe914e41e, "strcpy" },
+	{ 0xda6b5415, "set_disk_ro" },
+	{ 0x9dcb88fc, "spl_kmem_zalloc" },
+	{ 0x75907276, "kmem_debugging" },
+	{ 0xc3ff0fa1, "nvpair_value_uint8" },
+	{ 0xdb7958d9, "taskq_empty_ent" },
+};
+
+static const char __module_depends[]
+__used
+__attribute__((section(".modinfo"))) =
+"depends=spl,znvpair,zcommon,zunicode,zavl";
+
+
+MODULE_INFO(srcversion, "6D4A581C24AFCEC615C1511");
diff --git a/module/zfs/zfs_ioctl.c b/module/zfs/zfs_ioctl.c
index d026e92..12d2750 100644
--- a/module/zfs/zfs_ioctl.c
+++ b/module/zfs/zfs_ioctl.c
@@ -30,6 +30,7 @@
  * Copyright (c) 2013 by Saso Kiselkov. All rights reserved.
  * Copyright (c) 2013 Steven Hartland. All rights reserved.
  * Copyright (c) 2014, Nexenta Systems, Inc. All rights reserved.
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 /*
@@ -1500,8 +1501,7 @@ zfs_ioc_pool_destroy(zfs_cmd_t *zc)
 	int error;
 	zfs_log_history(zc);
 	error = spa_destroy(zc->zc_name);
-	if (error == 0)
-		zvol_remove_minors(zc->zc_name);
+
 	return (error);
 }
 
@@ -1553,8 +1553,7 @@ zfs_ioc_pool_export(zfs_cmd_t *zc)
 
 	zfs_log_history(zc);
 	error = spa_export(zc->zc_name, NULL, force, hardforce);
-	if (error == 0)
-		zvol_remove_minors(zc->zc_name);
+
 	return (error);
 }
 
@@ -2395,7 +2394,7 @@ zfs_prop_set_special(const char *dsname, zprop_source_t source,
 		err = zvol_set_volsize(dsname, intval);
 		break;
 	case ZFS_PROP_SNAPDEV:
-		err = zvol_set_snapdev(dsname, intval);
+		err = zvol_set_snapdev(dsname, source, intval);
 		break;
 	case ZFS_PROP_VERSION:
 	{
@@ -3189,12 +3188,6 @@ zfs_ioc_create(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
 		if (error != 0)
 			(void) dsl_destroy_head(fsname);
 	}
-
-#ifdef _KERNEL
-	if (error == 0 && type == DMU_OST_ZVOL)
-		zvol_create_minors(fsname);
-#endif
-
 	return (error);
 }
 
@@ -3237,12 +3230,6 @@ zfs_ioc_clone(const char *fsname, nvlist_t *innvl, nvlist_t *outnvl)
 		if (error != 0)
 			(void) dsl_destroy_head(fsname);
 	}
-
-#ifdef _KERNEL
-	if (error == 0)
-		zvol_create_minors(fsname);
-#endif
-
 	return (error);
 }
 
@@ -3305,11 +3292,6 @@ zfs_ioc_snapshot(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
 
 	error = dsl_dataset_snapshot(snaps, props, outnvl);
 
-#ifdef _KERNEL
-	if (error == 0)
-		zvol_create_minors(poolname);
-#endif
-
 	return (error);
 }
 
@@ -3435,7 +3417,6 @@ zfs_ioc_destroy_snaps(const char *poolname, nvlist_t *innvl, nvlist_t *outnvl)
 	for (pair = nvlist_next_nvpair(snaps, NULL); pair != NULL;
 	    pair = nvlist_next_nvpair(snaps, pair)) {
 		(void) zfs_unmount_snap(nvpair_name(pair));
-		(void) zvol_remove_minor(nvpair_name(pair));
 	}
 
 	return (dsl_destroy_snapshots_nvl(snaps, defer, outnvl));
@@ -3561,8 +3542,7 @@ zfs_ioc_destroy(zfs_cmd_t *zc)
 		err = dsl_destroy_snapshot(zc->zc_name, zc->zc_defer_destroy);
 	else
 		err = dsl_destroy_head(zc->zc_name);
-	if (zc->zc_objset_type == DMU_OST_ZVOL && err == 0)
-		(void) zvol_remove_minor(zc->zc_name);
+
 	return (err);
 }
 
@@ -4128,11 +4108,6 @@ zfs_ioc_recv(zfs_cmd_t *zc)
 	}
 #endif
 
-#ifdef _KERNEL
-	if (error == 0)
-		zvol_create_minors(tofs);
-#endif
-
 	/*
 	 * On error, restore the original props.
 	 */
@@ -6018,16 +5993,16 @@ _init(void)
 		return (error);
 	}
 
+	if ((error = -zvol_init()) != 0)
+		return (error);
+
 	spa_init(FREAD | FWRITE);
 	zfs_init();
 
-	if ((error = -zvol_init()) != 0)
-		goto out1;
-
 	zfs_ioctl_init();
 
 	if ((error = zfs_attach()) != 0)
-		goto out2;
+		goto out;
 
 	tsd_create(&zfs_fsyncer_key, NULL);
 	tsd_create(&rrw_tsd_key, rrw_tsd_destroy);
@@ -6043,11 +6018,10 @@ _init(void)
 
 	return (0);
 
-out2:
-	(void) zvol_fini();
-out1:
+out:
 	zfs_fini();
 	spa_fini();
+	(void) zvol_fini();
 	printk(KERN_NOTICE "ZFS: Failed to Load ZFS Filesystem v%s-%s%s"
 	    ", rc = %d\n", ZFS_META_VERSION, ZFS_META_RELEASE,
 	    ZFS_DEBUG_STR, error);
@@ -6059,9 +6033,9 @@ static void __exit
 _fini(void)
 {
 	zfs_detach();
-	zvol_fini();
 	zfs_fini();
 	spa_fini();
+	zvol_fini();
 
 	tsd_destroy(&zfs_fsyncer_key);
 	tsd_destroy(&rrw_tsd_key);
diff --git a/module/zfs/zpl_inode.c b/module/zfs/zpl_inode.c
index bd0d512..cbdab7d 100644
--- a/module/zfs/zpl_inode.c
+++ b/module/zfs/zpl_inode.c
@@ -31,6 +31,7 @@
 #include <sys/dmu_objset.h>
 #include <sys/vfs.h>
 #include <sys/zpl.h>
+#include <sys/file.h>
 
 
 static struct dentry *
@@ -44,13 +45,26 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 	struct inode *ip;
 	int error;
 	fstrans_cookie_t cookie;
+	pathname_t *ppn = NULL;
+	pathname_t pn;
+	int zfs_flags = 0;
+	zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
 
 	if (dlen(dentry) > ZFS_MAXNAMELEN)
 		return (ERR_PTR(-ENAMETOOLONG));
 
 	crhold(cr);
 	cookie = spl_fstrans_mark();
-	error = -zfs_lookup(dir, dname(dentry), &ip, 0, cr, NULL, NULL);
+
+	/* If we are a case insensitive fs, we need the real name */
+	if (zsb->z_case == ZFS_CASE_INSENSITIVE) {
+		zfs_flags = FIGNORECASE;
+		pn.pn_bufsize = ZFS_MAXNAMELEN;
+		pn.pn_buf = kmem_zalloc(ZFS_MAXNAMELEN, KM_SLEEP);
+		ppn = &pn;
+	}
+
+	error = -zfs_lookup(dir, dname(dentry), &ip, zfs_flags, cr, NULL, ppn);
 	spl_fstrans_unmark(cookie);
 	ASSERT3S(error, <=, 0);
 	crfree(cr);
@@ -63,13 +77,39 @@ zpl_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
 	spin_unlock(&dentry->d_lock);
 
 	if (error) {
+		/*
+		 * If we have a case sensitive fs, we do not want to
+		 * insert negative entries, so return NULL for ENOENT.
+		 * Fall through if the error is not ENOENT. Also free memory.
+		 */
+		if (ppn) {
+			kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
+			if (error == -ENOENT)
+				return (NULL);
+		}
+
 		if (error == -ENOENT)
 			return (d_splice_alias(NULL, dentry));
 		else
 			return (ERR_PTR(error));
 	}
 
-	return (d_splice_alias(ip, dentry));
+	/*
+	 * If we are case insensitive, call the correct function
+	 * to install the name.
+	 */
+	if (ppn) {
+		struct dentry *new_dentry;
+		struct qstr ci_name;
+
+		ci_name.name = pn.pn_buf;
+		ci_name.len = strlen(pn.pn_buf);
+		new_dentry = d_add_ci(dentry, ip, &ci_name);
+		kmem_free(pn.pn_buf, ZFS_MAXNAMELEN);
+		return (new_dentry);
+	} else {
+		return (d_splice_alias(ip, dentry));
+	}
 }
 
 void
@@ -177,10 +217,19 @@ zpl_unlink(struct inode *dir, struct dentry *dentry)
 	cred_t *cr = CRED();
 	int error;
 	fstrans_cookie_t cookie;
+	zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
 
 	crhold(cr);
 	cookie = spl_fstrans_mark();
 	error = -zfs_remove(dir, dname(dentry), cr);
+
+	/*
+	 * For a CI FS we must invalidate the dentry to prevent the
+	 * creation of negative entries.
+	 */
+	if (error == 0 && zsb->z_case == ZFS_CASE_INSENSITIVE)
+		d_invalidate(dentry);
+
 	spl_fstrans_unmark(cookie);
 	crfree(cr);
 	ASSERT3S(error, <=, 0);
@@ -228,10 +277,19 @@ zpl_rmdir(struct inode * dir, struct dentry *dentry)
 	cred_t *cr = CRED();
 	int error;
 	fstrans_cookie_t cookie;
+	zfs_sb_t *zsb = dentry->d_sb->s_fs_info;
 
 	crhold(cr);
 	cookie = spl_fstrans_mark();
 	error = -zfs_rmdir(dir, dname(dentry), NULL, cr, 0);
+
+	/*
+	 * For a CI FS we must invalidate the dentry to prevent the
+	 * creation of negative entries.
+	 */
+	if (error == 0 && zsb->z_case == ZFS_CASE_INSENSITIVE)
+		d_invalidate(dentry);
+
 	spl_fstrans_unmark(cookie);
 	crfree(cr);
 	ASSERT3S(error, <=, 0);
diff --git a/module/zfs/zvol.c b/module/zfs/zvol.c
index 613b47e..a7a79e6 100644
--- a/module/zfs/zvol.c
+++ b/module/zfs/zvol.c
@@ -33,18 +33,23 @@
  *
  * Volumes are persistent through reboot and module load.  No user command
  * needs to be run before opening and using a device.
+ *
+ * Copyright (c) 2016 Actifio, Inc. All rights reserved.
  */
 
 #include <sys/dbuf.h>
 #include <sys/dmu_traverse.h>
 #include <sys/dsl_dataset.h>
 #include <sys/dsl_prop.h>
+#include <sys/dsl_dir.h>
 #include <sys/zap.h>
 #include <sys/zfeature.h>
 #include <sys/zil_impl.h>
+#include <sys/dmu_tx.h>
 #include <sys/zio.h>
 #include <sys/zfs_rlock.h>
 #include <sys/zfs_znode.h>
+#include <sys/spa_impl.h>
 #include <sys/zvol.h>
 #include <linux/blkdev_compat.h>
 
@@ -78,6 +83,23 @@ typedef struct zvol_state {
 	list_node_t		zv_next;	/* next zvol_state_t linkage */
 } zvol_state_t;
 
+typedef enum {
+	ZVOL_ASYNC_CREATE_MINORS,
+	ZVOL_ASYNC_REMOVE_MINORS,
+	ZVOL_ASYNC_RENAME_MINORS,
+	ZVOL_ASYNC_SET_SNAPDEV,
+	ZVOL_ASYNC_MAX
+} zvol_async_op_t;
+
+typedef struct {
+	zvol_async_op_t op;
+	char pool[MAXNAMELEN];
+	char name1[MAXNAMELEN];
+	char name2[MAXNAMELEN];
+	zprop_source_t source;
+	uint64_t snapdev;
+} zvol_task_t;
+
 #define	ZVOL_RDONLY	0x1
 
 /*
@@ -599,6 +621,8 @@ zvol_write(struct bio *bio)
 	dmu_tx_t *tx;
 	rl_t *rl;
 
+	ASSERT(zv && zv->zv_open_count > 0);
+
 	if (bio->bi_rw & VDEV_REQ_FLUSH)
 		zil_commit(zv->zv_zilog, ZVOL_OBJ);
 
@@ -647,6 +671,8 @@ zvol_discard(struct bio *bio)
 	int error;
 	rl_t *rl;
 
+	ASSERT(zv && zv->zv_open_count > 0);
+
 	if (end > zv->zv_volsize)
 		return (SET_ERROR(EIO));
 
@@ -691,10 +717,11 @@ zvol_read(struct bio *bio)
 	int error;
 	rl_t *rl;
 
+	ASSERT(zv && zv->zv_open_count > 0);
+
 	if (len == 0)
 		return (0);
 
-
 	rl = zfs_range_lock(&zv->zv_znode, offset, len, RL_READER);
 
 	error = dmu_read_bio(zv->zv_objset, ZVOL_OBJ, bio);
@@ -874,54 +901,27 @@ zvol_first_open(zvol_state_t *zv)
 {
 	objset_t *os;
 	uint64_t volsize;
-	int locked = 0;
 	int error;
 	uint64_t ro;
 
-	/*
-	 * In all other cases the spa_namespace_lock is taken before the
-	 * bdev->bd_mutex lock.  But in this case the Linux __blkdev_get()
-	 * function calls fops->open() with the bdev->bd_mutex lock held.
-	 *
-	 * To avoid a potential lock inversion deadlock we preemptively
-	 * try to take the spa_namespace_lock().  Normally it will not
-	 * be contended and this is safe because spa_open_common() handles
-	 * the case where the caller already holds the spa_namespace_lock.
-	 *
-	 * When it is contended we risk a lock inversion if we were to
-	 * block waiting for the lock.  Luckily, the __blkdev_get()
-	 * function allows us to return -ERESTARTSYS which will result in
-	 * bdev->bd_mutex being dropped, reacquired, and fops->open() being
-	 * called again.  This process can be repeated safely until both
-	 * locks are acquired.
-	 */
-	if (!mutex_owned(&spa_namespace_lock)) {
-		locked = mutex_tryenter(&spa_namespace_lock);
-		if (!locked)
-			return (-SET_ERROR(ERESTARTSYS));
-	}
-
-	error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
-	if (error)
-		goto out_mutex;
-
 	/* lie and say we're read-only */
 	error = dmu_objset_own(zv->zv_name, DMU_OST_ZVOL, 1, zvol_tag, &os);
 	if (error)
-		goto out_mutex;
+		return (SET_ERROR(-error));
+
+	zv->zv_objset = os;
+
+	error = dsl_prop_get_integer(zv->zv_name, "readonly", &ro, NULL);
+	if (error)
+		goto out_owned;
 
 	error = zap_lookup(os, ZVOL_ZAP_OBJ, "size", 8, 1, &volsize);
-	if (error) {
-		dmu_objset_disown(os, zvol_tag);
-		goto out_mutex;
-	}
+	if (error)
+		goto out_owned;
 
-	zv->zv_objset = os;
 	error = dmu_bonus_hold(os, ZVOL_OBJ, zvol_tag, &zv->zv_dbuf);
-	if (error) {
-		dmu_objset_disown(os, zvol_tag);
-		goto out_mutex;
-	}
+	if (error)
+		goto out_owned;
 
 	set_capacity(zv->zv_disk, volsize >> 9);
 	zv->zv_volsize = volsize;
@@ -936,9 +936,11 @@ zvol_first_open(zvol_state_t *zv)
 		zv->zv_flags &= ~ZVOL_RDONLY;
 	}
 
-out_mutex:
-	if (locked)
-		mutex_exit(&spa_namespace_lock);
+out_owned:
+	if (error) {
+		dmu_objset_disown(os, zvol_tag);
+		zv->zv_objset = NULL;
+	}
 
 	return (SET_ERROR(-error));
 }
@@ -967,12 +969,12 @@ zvol_last_close(zvol_state_t *zv)
 static int
 zvol_open(struct block_device *bdev, fmode_t flag)
 {
-	zvol_state_t *zv = bdev->bd_disk->private_data;
+	zvol_state_t *zv;
 	int error = 0, drop_mutex = 0;
 
 	/*
 	 * If the caller is already holding the mutex do not take it
-	 * again, this will happen as part of zvol_create_minor().
+	 * again, this will happen as part of zvol_create_minor_impl().
 	 * Once add_disk() is called the device is live and the kernel
 	 * will attempt to open it to read the partition information.
 	 */
@@ -981,7 +983,17 @@ zvol_open(struct block_device *bdev, fmode_t flag)
 		drop_mutex = 1;
 	}
 
-	ASSERT3P(zv, !=, NULL);
+	/*
+	 * Obtain a copy of private_data under the lock to make sure
+	 * that either the result of zvol_freeg() setting
+	 * bdev->bd_disk->private_data to NULL is observed, or zvol_free()
+	 * is not called on this zv because of the positive zv_open_count.
+	 */
+	zv = bdev->bd_disk->private_data;
+	if (zv == NULL) {
+		error = -ENXIO;
+		goto out_mutex;
+	}
 
 	if (zv->zv_open_count == 0) {
 		error = zvol_first_open(zv);
@@ -996,6 +1008,8 @@ zvol_open(struct block_device *bdev, fmode_t flag)
 
 	zv->zv_open_count++;
 
+	check_disk_change(bdev);
+
 out_open_count:
 	if (zv->zv_open_count == 0)
 		zvol_last_close(zv);
@@ -1004,8 +1018,6 @@ out_mutex:
 	if (drop_mutex)
 		mutex_exit(&zvol_state_lock);
 
-	check_disk_change(bdev);
-
 	return (SET_ERROR(error));
 }
 
@@ -1019,16 +1031,16 @@ zvol_release(struct gendisk *disk, fmode_t mode)
 	zvol_state_t *zv = disk->private_data;
 	int drop_mutex = 0;
 
+	ASSERT(zv && zv->zv_open_count > 0);
+
 	if (!mutex_owned(&zvol_state_lock)) {
 		mutex_enter(&zvol_state_lock);
 		drop_mutex = 1;
 	}
 
-	if (zv->zv_open_count > 0) {
-		zv->zv_open_count--;
-		if (zv->zv_open_count == 0)
-			zvol_last_close(zv);
-	}
+	zv->zv_open_count--;
+	if (zv->zv_open_count == 0)
+		zvol_last_close(zv);
 
 	if (drop_mutex)
 		mutex_exit(&zvol_state_lock);
@@ -1045,8 +1057,7 @@ zvol_ioctl(struct block_device *bdev, fmode_t mode,
 	zvol_state_t *zv = bdev->bd_disk->private_data;
 	int error = 0;
 
-	if (zv == NULL)
-		return (SET_ERROR(-ENXIO));
+	ASSERT(zv && zv->zv_open_count > 0);
 
 	switch (cmd) {
 	case BLKFLSBUF:
@@ -1080,6 +1091,8 @@ static int zvol_media_changed(struct gendisk *disk)
 {
 	zvol_state_t *zv = disk->private_data;
 
+	ASSERT(zv && zv->zv_open_count > 0);
+
 	return (zv->zv_changed);
 }
 
@@ -1087,6 +1100,8 @@ static int zvol_revalidate_disk(struct gendisk *disk)
 {
 	zvol_state_t *zv = disk->private_data;
 
+	ASSERT(zv && zv->zv_open_count > 0);
+
 	zv->zv_changed = 0;
 	set_capacity(zv->zv_disk, zv->zv_volsize >> 9);
 
@@ -1103,7 +1118,11 @@ static int
 zvol_getgeo(struct block_device *bdev, struct hd_geometry *geo)
 {
 	zvol_state_t *zv = bdev->bd_disk->private_data;
-	sector_t sectors = get_capacity(zv->zv_disk);
+	sector_t sectors;
+
+	ASSERT(zv && zv->zv_open_count > 0);
+
+	sectors = get_capacity(zv->zv_disk);
 
 	if (sectors > 2048) {
 		geo->heads = 16;
@@ -1260,9 +1279,14 @@ out_kmem:
 static void
 zvol_free(zvol_state_t *zv)
 {
+	ASSERT(MUTEX_HELD(&zvol_state_lock));
+	ASSERT(zv->zv_open_count == 0);
+
 	avl_destroy(&zv->zv_znode.z_range_avl);
 	mutex_destroy(&zv->zv_znode.z_range_lock);
 
+	zv->zv_disk->private_data = NULL;
+
 	del_gendisk(zv->zv_disk);
 	blk_cleanup_queue(zv->zv_queue);
 	put_disk(zv->zv_disk);
@@ -1270,31 +1294,13 @@ zvol_free(zvol_state_t *zv)
 	kmem_free(zv, sizeof (zvol_state_t));
 }
 
+/*
+ * Create a block device minor node and setup the linkage between it
+ * and the specified volume.  Once this function returns the block
+ * device is live and ready for use.
+ */
 static int
-__zvol_snapdev_hidden(const char *name)
-{
-	uint64_t snapdev;
-	char *parent;
-	char *atp;
-	int error = 0;
-
-	parent = kmem_alloc(MAXPATHLEN, KM_SLEEP);
-	(void) strlcpy(parent, name, MAXPATHLEN);
-
-	if ((atp = strrchr(parent, '@')) != NULL) {
-		*atp = '\0';
-		error = dsl_prop_get_integer(parent, "snapdev", &snapdev, NULL);
-		if ((error == 0) && (snapdev == ZFS_SNAPDEV_HIDDEN))
-			error = SET_ERROR(ENODEV);
-	}
-
-	kmem_free(parent, MAXPATHLEN);
-
-	return (SET_ERROR(error));
-}
-
-static int
-__zvol_create_minor(const char *name, boolean_t ignore_snapdev)
+zvol_create_minor_impl(const char *name)
 {
 	zvol_state_t *zv;
 	objset_t *os;
@@ -1304,7 +1310,7 @@ __zvol_create_minor(const char *name, boolean_t ignore_snapdev)
 	unsigned minor = 0;
 	int error = 0;
 
-	ASSERT(MUTEX_HELD(&zvol_state_lock));
+	mutex_enter(&zvol_state_lock);
 
 	zv = zvol_find_by_name(name);
 	if (zv) {
@@ -1312,12 +1318,6 @@ __zvol_create_minor(const char *name, boolean_t ignore_snapdev)
 		goto out;
 	}
 
-	if (ignore_snapdev == B_FALSE) {
-		error = __zvol_snapdev_hidden(name);
-		if (error)
-			goto out;
-	}
-
 	doi = kmem_alloc(sizeof (dmu_object_info_t), KM_SLEEP);
 
 	error = dmu_objset_own(name, DMU_OST_ZVOL, B_TRUE, zvol_tag, &os);
@@ -1395,69 +1395,26 @@ out:
 
 	if (error == 0) {
 		zvol_insert(zv);
+		/*
+		 * Drop the lock to prevent deadlock with sys_open() ->
+		 * zvol_open(), which first takes bd_disk->bd_mutex and then
+		 * takes zvol_state_lock, whereas this code path first takes
+		 * zvol_state_lock, and then takes bd_disk->bd_mutex.
+		 */
+		mutex_exit(&zvol_state_lock);
 		add_disk(zv->zv_disk);
+	} else {
+		mutex_exit(&zvol_state_lock);
 	}
 
 	return (SET_ERROR(error));
 }
 
 /*
- * Create a block device minor node and setup the linkage between it
- * and the specified volume.  Once this function returns the block
- * device is live and ready for use.
- */
-int
-zvol_create_minor(const char *name)
-{
-	int error;
-
-	mutex_enter(&zvol_state_lock);
-	error = __zvol_create_minor(name, B_FALSE);
-	mutex_exit(&zvol_state_lock);
-
-	return (SET_ERROR(error));
-}
-
-static int
-__zvol_remove_minor(const char *name)
-{
-	zvol_state_t *zv;
-
-	ASSERT(MUTEX_HELD(&zvol_state_lock));
-
-	zv = zvol_find_by_name(name);
-	if (zv == NULL)
-		return (SET_ERROR(ENXIO));
-
-	if (zv->zv_open_count > 0)
-		return (SET_ERROR(EBUSY));
-
-	zvol_remove(zv);
-	zvol_free(zv);
-
-	return (0);
-}
-
-/*
- * Remove a block device minor node for the specified volume.
- */
-int
-zvol_remove_minor(const char *name)
-{
-	int error;
-
-	mutex_enter(&zvol_state_lock);
-	error = __zvol_remove_minor(name);
-	mutex_exit(&zvol_state_lock);
-
-	return (SET_ERROR(error));
-}
-
-/*
  * Rename a block device minor mode for the specified volume.
  */
 static void
-__zvol_rename_minor(zvol_state_t *zv, const char *newname)
+zvol_rename_minor(zvol_state_t *zv, const char *newname)
 {
 	int readonly = get_disk_ro(zv->zv_disk);
 
@@ -1477,25 +1434,124 @@ __zvol_rename_minor(zvol_state_t *zv, const char *newname)
 	set_disk_ro(zv->zv_disk, readonly);
 }
 
+
+/*
+ * Mask errors to continue dmu_objset_find() traversal
+ */
+static int
+zvol_create_snap_minor_cb(const char *dsname, void *arg)
+{
+	const char *name = (const char *)arg;
+
+	ASSERT0(MUTEX_HELD(&spa_namespace_lock));
+
+	/* skip the designated dataset */
+	if (name && strcmp(dsname, name) == 0)
+		return (0);
+
+	/* at this point, the dsname should name a snapshot */
+	if (strchr(dsname, '@') == 0) {
+		dprintf("zvol_create_snap_minor_cb(): "
+			"%s is not a shapshot name\n", dsname);
+	} else {
+		(void) zvol_create_minor_impl(dsname);
+	}
+
+	return (0);
+}
+
+/*
+ * Mask errors to continue dmu_objset_find() traversal
+ */
 static int
 zvol_create_minors_cb(const char *dsname, void *arg)
 {
-	(void) zvol_create_minor(dsname);
+	uint64_t snapdev;
+	int error;
+
+	ASSERT0(MUTEX_HELD(&spa_namespace_lock));
+
+	error = dsl_prop_get_integer(dsname, "snapdev", &snapdev, NULL);
+	if (error)
+		return (0);
+
+	/*
+	 * Given the name and the 'snapdev' property, create device minor nodes
+	 * with the linkages to zvols/snapshots as needed.
+	 * If the name represents a zvol, create a minor node for the zvol, then
+	 * check if its snapshots are 'visible', and if so, iterate over the
+	 * snapshots and create device minor nodes for those.
+	 */
+	if (strchr(dsname, '@') == 0) {
+		/* create minor for the 'dsname' explicitly */
+		error = zvol_create_minor_impl(dsname);
+		if ((error == 0 || error == EEXIST) &&
+		    (snapdev == ZFS_SNAPDEV_VISIBLE)) {
+			fstrans_cookie_t cookie = spl_fstrans_mark();
+			/*
+			 * traverse snapshots only, do not traverse children,
+			 * and skip the 'dsname'
+			 */
+			error = dmu_objset_find((char *)dsname,
+			    zvol_create_snap_minor_cb, (void *)dsname,
+			    DS_FIND_SNAPSHOTS);
+			spl_fstrans_unmark(cookie);
+		}
+	} else {
+		dprintf("zvol_create_minors_cb(): %s is not a zvol name\n",
+			dsname);
+	}
 
 	return (0);
 }
 
 /*
- * Create minors for specified dataset including children and snapshots.
+ * Create minors for the specified dataset, including children and snapshots.
+ * Pay attention to the 'snapdev' property and iterate over the snapshots
+ * only if they are 'visible'. This approach allows one to assure that the
+ * snapshot metadata is read from disk only if it is needed.
+ *
+ * The name can represent a dataset to be recursively scanned for zvols and
+ * their snapshots, or a single zvol snapshot. If the name represents a
+ * dataset, the scan is performed in two nested stages:
+ * - scan the dataset for zvols, and
+ * - for each zvol, create a minor node, then check if the zvol's snapshots
+ *   are 'visible', and only then iterate over the snapshots if needed
+ *
+ * If the name represents a snapshot, a check is perfromed if the snapshot is
+ * 'visible' (which also verifies that the parent is a zvol), and if so,
+ * a minor node for that snapshot is created.
  */
-int
-zvol_create_minors(const char *name)
+static int
+zvol_create_minors_impl(const char *name)
 {
 	int error = 0;
+	fstrans_cookie_t cookie;
+	char *atp, *parent;
+
+	if (zvol_inhibit_dev)
+		return (0);
+
+	parent = kmem_alloc(MAXPATHLEN, KM_SLEEP);
+	(void) strlcpy(parent, name, MAXPATHLEN);
+
+	if ((atp = strrchr(parent, '@')) != NULL) {
+		uint64_t snapdev;
+
+		*atp = '\0';
+		error = dsl_prop_get_integer(parent, "snapdev",
+		    &snapdev, NULL);
+
+		if (error == 0 && snapdev == ZFS_SNAPDEV_VISIBLE)
+			error = zvol_create_minor_impl(name);
+	} else {
+		cookie = spl_fstrans_mark();
+		error = dmu_objset_find(parent, zvol_create_minors_cb,
+		    NULL, DS_FIND_CHILDREN);
+		spl_fstrans_unmark(cookie);
+	}
 
-	if (!zvol_inhibit_dev)
-		error = dmu_objset_find((char *)name, zvol_create_minors_cb,
-		    NULL, DS_FIND_CHILDREN | DS_FIND_SNAPSHOTS);
+	kmem_free(parent, MAXPATHLEN);
 
 	return (SET_ERROR(error));
 }
@@ -1503,8 +1559,8 @@ zvol_create_minors(const char *name)
 /*
  * Remove minors for specified dataset including children and snapshots.
  */
-void
-zvol_remove_minors(const char *name)
+static void
+zvol_remove_minors_impl(const char *name)
 {
 	zvol_state_t *zv, *zv_next;
 	int namelen = ((name) ? strlen(name) : 0);
@@ -1519,9 +1575,45 @@ zvol_remove_minors(const char *name)
 
 		if (name == NULL || strcmp(zv->zv_name, name) == 0 ||
 		    (strncmp(zv->zv_name, name, namelen) == 0 &&
-		    zv->zv_name[namelen] == '/')) {
+		    (zv->zv_name[namelen] == '/' ||
+		    zv->zv_name[namelen] == '@'))) {
+
+			/* If in use, leave alone */
+			if (zv->zv_open_count > 0)
+				continue;
+
+			zvol_remove(zv);
+			zvol_free(zv);
+		}
+	}
+
+	mutex_exit(&zvol_state_lock);
+}
+
+/* Remove minor for this specific snapshot only */
+static void
+zvol_remove_minor_impl(const char *name)
+{
+	zvol_state_t *zv, *zv_next;
+
+	if (zvol_inhibit_dev)
+		return;
+
+	if (strchr(name, '@') == NULL)
+		return;
+
+	mutex_enter(&zvol_state_lock);
+
+	for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
+		zv_next = list_next(&zvol_state_list, zv);
+
+		if (strcmp(zv->zv_name, name) == 0) {
+			/* If in use, leave alone */
+			if (zv->zv_open_count > 0)
+				continue;
 			zvol_remove(zv);
 			zvol_free(zv);
+			break;
 		}
 	}
 
@@ -1531,8 +1623,8 @@ zvol_remove_minors(const char *name)
 /*
  * Rename minors for specified dataset including children and snapshots.
  */
-void
-zvol_rename_minors(const char *oldname, const char *newname)
+static void
+zvol_rename_minors_impl(const char *oldname, const char *newname)
 {
 	zvol_state_t *zv, *zv_next;
 	int oldnamelen, newnamelen;
@@ -1550,15 +1642,19 @@ zvol_rename_minors(const char *oldname, const char *newname)
 	for (zv = list_head(&zvol_state_list); zv != NULL; zv = zv_next) {
 		zv_next = list_next(&zvol_state_list, zv);
 
+		/* If in use, leave alone */
+		if (zv->zv_open_count > 0)
+			continue;
+
 		if (strcmp(zv->zv_name, oldname) == 0) {
-			__zvol_rename_minor(zv, newname);
+			zvol_rename_minor(zv, newname);
 		} else if (strncmp(zv->zv_name, oldname, oldnamelen) == 0 &&
 		    (zv->zv_name[oldnamelen] == '/' ||
 		    zv->zv_name[oldnamelen] == '@')) {
 			snprintf(name, MAXNAMELEN, "%s%c%s", newname,
 			    zv->zv_name[oldnamelen],
 			    zv->zv_name + oldnamelen + 1);
-			__zvol_rename_minor(zv, name);
+			zvol_rename_minor(zv, name);
 		}
 	}
 
@@ -1567,33 +1663,227 @@ zvol_rename_minors(const char *oldname, const char *newname)
 	kmem_free(name, MAXNAMELEN);
 }
 
+typedef struct zvol_snapdev_cb_arg {
+	uint64_t snapdev;
+} zvol_snapdev_cb_arg_t;
+
 static int
-snapdev_snapshot_changed_cb(const char *dsname, void *arg) {
-	uint64_t snapdev = *(uint64_t *) arg;
+zvol_set_snapdev_cb(const char *dsname, void *param) {
+	zvol_snapdev_cb_arg_t *arg = param;
 
 	if (strchr(dsname, '@') == NULL)
 		return (0);
 
-	switch (snapdev) {
+	switch (arg->snapdev) {
 		case ZFS_SNAPDEV_VISIBLE:
-			mutex_enter(&zvol_state_lock);
-			(void) __zvol_create_minor(dsname, B_TRUE);
-			mutex_exit(&zvol_state_lock);
+			(void) zvol_create_minor_impl(dsname);
 			break;
 		case ZFS_SNAPDEV_HIDDEN:
-			(void) zvol_remove_minor(dsname);
+			(void) zvol_remove_minor_impl(dsname);
 			break;
 	}
 
 	return (0);
 }
 
+static void
+zvol_set_snapdev_impl(char *name, uint64_t snapdev)
+{
+	zvol_snapdev_cb_arg_t arg = {snapdev};
+	fstrans_cookie_t cookie = spl_fstrans_mark();
+	/*
+	 * The zvol_set_snapdev_sync() sets snapdev appropriately
+	 * in the dataset hierarchy. Here, we only scan snapshots.
+	 */
+	dmu_objset_find(name, zvol_set_snapdev_cb, &arg, DS_FIND_SNAPSHOTS);
+	spl_fstrans_unmark(cookie);
+}
+
+static zvol_task_t *
+zvol_task_alloc(zvol_async_op_t op, const char *name1, const char *name2,
+    uint64_t snapdev)
+{
+	zvol_task_t *task;
+	char *delim;
+
+	/* Never allow tasks on hidden names. */
+	if (name1[0] == '$')
+		return (NULL);
+
+	task = kmem_zalloc(sizeof (zvol_task_t), KM_SLEEP);
+	task->op = op;
+	task->snapdev = snapdev;
+	delim = strchr(name1, '/');
+	strlcpy(task->pool, name1, delim ? (delim - name1 + 1) : MAXNAMELEN);
+
+	strlcpy(task->name1, name1, MAXNAMELEN);
+	if (name2 != NULL)
+		strlcpy(task->name2, name2, MAXNAMELEN);
+
+	return (task);
+}
+
+static void
+zvol_task_free(zvol_task_t *task)
+{
+	kmem_free(task, sizeof (zvol_task_t));
+}
+
+/*
+ * The worker thread function performed asynchronously.
+ */
+static void
+zvol_task_cb(void *param)
+{
+	zvol_task_t *task = (zvol_task_t *)param;
+
+	switch (task->op) {
+	case ZVOL_ASYNC_CREATE_MINORS:
+		(void) zvol_create_minors_impl(task->name1);
+		break;
+	case ZVOL_ASYNC_REMOVE_MINORS:
+		zvol_remove_minors_impl(task->name1);
+		break;
+	case ZVOL_ASYNC_RENAME_MINORS:
+		zvol_rename_minors_impl(task->name1, task->name2);
+		break;
+	case ZVOL_ASYNC_SET_SNAPDEV:
+		zvol_set_snapdev_impl(task->name1, task->snapdev);
+		break;
+	default:
+		VERIFY(0);
+		break;
+	}
+
+	zvol_task_free(task);
+}
+
+typedef struct zvol_set_snapdev_arg {
+	const char *zsda_name;
+	uint64_t zsda_value;
+	zprop_source_t zsda_source;
+	dmu_tx_t *zsda_tx;
+} zvol_set_snapdev_arg_t;
+
+/*
+ * Sanity check the dataset for safe use by the sync task.  No additional
+ * conditions are imposed.
+ */
+static int
+zvol_set_snapdev_check(void *arg, dmu_tx_t *tx)
+{
+	zvol_set_snapdev_arg_t *zsda = arg;
+	dsl_pool_t *dp = dmu_tx_pool(tx);
+	dsl_dir_t *dd;
+	int error;
+
+	error = dsl_dir_hold(dp, zsda->zsda_name, FTAG, &dd, NULL);
+	if (error != 0)
+		return (error);
+
+	dsl_dir_rele(dd, FTAG);
+
+	return (error);
+}
+
+static int
+zvol_set_snapdev_sync_cb(dsl_pool_t *dp, dsl_dataset_t *ds, void *arg)
+{
+	zvol_set_snapdev_arg_t *zsda = arg;
+	char dsname[MAXNAMELEN];
+	zvol_task_t *task;
+
+	dsl_dataset_name(ds, dsname);
+	dsl_prop_set_sync_impl(ds, zfs_prop_to_name(ZFS_PROP_SNAPDEV),
+	    zsda->zsda_source, sizeof (zsda->zsda_value), 1,
+	    &zsda->zsda_value, zsda->zsda_tx);
+
+	task = zvol_task_alloc(ZVOL_ASYNC_SET_SNAPDEV, dsname,
+	    NULL, zsda->zsda_value);
+	if (task == NULL)
+		return (0);
+
+	(void) taskq_dispatch(dp->dp_spa->spa_zvol_taskq, zvol_task_cb,
+		task, TQ_SLEEP);
+	return (0);
+}
+
+/*
+ * Traverse all child snapshot datasets and apply snapdev appropriately.
+ */
+static void
+zvol_set_snapdev_sync(void *arg, dmu_tx_t *tx)
+{
+	zvol_set_snapdev_arg_t *zsda = arg;
+	dsl_pool_t *dp = dmu_tx_pool(tx);
+	dsl_dir_t *dd;
+
+	VERIFY0(dsl_dir_hold(dp, zsda->zsda_name, FTAG, &dd, NULL));
+	zsda->zsda_tx = tx;
+
+	dmu_objset_find_dp(dp, dd->dd_object, zvol_set_snapdev_sync_cb,
+	    zsda, DS_FIND_CHILDREN);
+
+	dsl_dir_rele(dd, FTAG);
+}
+
 int
-zvol_set_snapdev(const char *dsname, uint64_t snapdev) {
-	(void) dmu_objset_find((char *) dsname, snapdev_snapshot_changed_cb,
-		&snapdev, DS_FIND_SNAPSHOTS | DS_FIND_CHILDREN);
-	/* caller should continue to modify snapdev property */
-	return (-1);
+zvol_set_snapdev(const char *ddname, zprop_source_t source, uint64_t snapdev)
+{
+	zvol_set_snapdev_arg_t zsda;
+
+	zsda.zsda_name = ddname;
+	zsda.zsda_source = source;
+	zsda.zsda_value = snapdev;
+
+	return (dsl_sync_task(ddname, zvol_set_snapdev_check,
+	    zvol_set_snapdev_sync, &zsda, 0, ZFS_SPACE_CHECK_NONE));
+}
+
+void
+zvol_create_minors(spa_t *spa, const char *name, boolean_t async)
+{
+	zvol_task_t *task;
+	taskqid_t id;
+
+	task = zvol_task_alloc(ZVOL_ASYNC_CREATE_MINORS, name, NULL, ~0ULL);
+	if (task == NULL)
+		return;
+
+	id = taskq_dispatch(spa->spa_zvol_taskq, zvol_task_cb, task, TQ_SLEEP);
+	if ((async == B_FALSE) && (id != 0))
+		taskq_wait_id(spa->spa_zvol_taskq, id);
+}
+
+void
+zvol_remove_minors(spa_t *spa, const char *name, boolean_t async)
+{
+	zvol_task_t *task;
+	taskqid_t id;
+
+	task = zvol_task_alloc(ZVOL_ASYNC_REMOVE_MINORS, name, NULL, ~0ULL);
+	if (task == NULL)
+		return;
+
+	id = taskq_dispatch(spa->spa_zvol_taskq, zvol_task_cb, task, TQ_SLEEP);
+	if ((async == B_FALSE) && (id != 0))
+		taskq_wait_id(spa->spa_zvol_taskq, id);
+}
+
+void
+zvol_rename_minors(spa_t *spa, const char *name1, const char *name2,
+    boolean_t async)
+{
+	zvol_task_t *task;
+	taskqid_t id;
+
+	task = zvol_task_alloc(ZVOL_ASYNC_RENAME_MINORS, name1, name2, ~0ULL);
+	if (task == NULL)
+		return;
+
+	id = taskq_dispatch(spa->spa_zvol_taskq, zvol_task_cb, task, TQ_SLEEP);
+	if ((async == B_FALSE) && (id != 0))
+		taskq_wait_id(spa->spa_zvol_taskq, id);
 }
 
 int
@@ -1603,7 +1893,6 @@ zvol_init(void)
 
 	list_create(&zvol_state_list, sizeof (zvol_state_t),
 	    offsetof(zvol_state_t, zv_next));
-
 	mutex_init(&zvol_state_lock, NULL, MUTEX_DEFAULT, NULL);
 
 	error = register_blkdev(zvol_major, ZVOL_DRIVER);
@@ -1627,11 +1916,13 @@ out:
 void
 zvol_fini(void)
 {
-	zvol_remove_minors(NULL);
+	zvol_remove_minors_impl(NULL);
+
 	blk_unregister_region(MKDEV(zvol_major, 0), 1UL << MINORBITS);
 	unregister_blkdev(zvol_major, ZVOL_DRIVER);
-	mutex_destroy(&zvol_state_lock);
+
 	list_destroy(&zvol_state_list);
+	mutex_destroy(&zvol_state_lock);
 }
 
 module_param(zvol_inhibit_dev, uint, 0644);
diff --git a/module/zpios/zpios.mod.c b/module/zpios/zpios.mod.c
new file mode 100644
index 0000000..bc848b5
--- /dev/null
+++ b/module/zpios/zpios.mod.c
@@ -0,0 +1,88 @@
+#include <linux/module.h>
+#include <linux/vermagic.h>
+#include <linux/compiler.h>
+
+MODULE_INFO(vermagic, VERMAGIC_STRING);
+
+struct module __this_module
+__attribute__((section(".gnu.linkonce.this_module"))) = {
+ .name = KBUILD_MODNAME,
+ .init = init_module,
+#ifdef CONFIG_MODULE_UNLOAD
+ .exit = cleanup_module,
+#endif
+ .arch = MODULE_ARCH_INIT,
+};
+
+static const struct modversion_info ____versions[]
+__used
+__attribute__((section("__versions"))) = {
+	{ 0x51198477, "module_layout" },
+	{ 0x3a8fb147, "dmu_tx_hold_free" },
+	{ 0x6b85513b, "dmu_objset_create" },
+	{ 0x4d73bbca, "dmu_object_set_blocksize" },
+	{ 0x26b64321, "call_usermodehelper_setfns" },
+	{ 0xdb347c7a, "call_usermodehelper_exec" },
+	{ 0xadaabe1b, "pv_lock_ops" },
+	{ 0xbf479b07, "dmu_tx_abort" },
+	{ 0x4ff1c9bc, "populate_rootfs_wait" },
+	{ 0xc8b57c27, "autoremove_wake_function" },
+	{ 0x79aa04a2, "get_random_bytes" },
+	{ 0x67053080, "current_kernel_time" },
+	{ 0x71642c98, "dmu_tx_wait" },
+	{ 0xab140103, "spl_kmem_alloc" },
+	{ 0xba2adaf, "mutex_unlock" },
+	{ 0xd3b65d9d, "kthread_create_on_node" },
+	{ 0xbc32eee7, "spl_panic" },
+	{ 0x4040455, "dmu_tx_commit" },
+	{ 0x6395be94, "__init_waitqueue_head" },
+	{ 0x4f8b5ddb, "_copy_to_user" },
+	{ 0x114258fb, "misc_register" },
+	{ 0xde0bdcff, "memset" },
+	{ 0x69371301, "current_task" },
+	{ 0x87ebeb76, "__mutex_init" },
+	{ 0x27e1a049, "printk" },
+	{ 0x4ebec927, "kthread_stop" },
+	{ 0x81034537, "dmu_objset_disown" },
+	{ 0xa1c76e0a, "_cond_resched" },
+	{ 0x7ec9bfbc, "strncpy" },
+	{ 0xb4390f9a, "mcount" },
+	{ 0xafe1db9d, "mutex_lock" },
+	{ 0x5bb6ad4b, "spl_vmem_zalloc" },
+	{ 0x6357a5a8, "dmu_write" },
+	{ 0x952664c5, "do_exit" },
+	{ 0x7da403ec, "dsl_destroy_head" },
+	{ 0x699a8466, "dmu_objset_own" },
+	{ 0x8c51c50b, "dmu_object_free" },
+	{ 0xf0fdf6cb, "__stack_chk_fail" },
+	{ 0xd62c833f, "schedule_timeout" },
+	{ 0x1000e51, "schedule" },
+	{ 0x252f790a, "dmu_object_alloc" },
+	{ 0xdae80439, "spl_vmem_alloc" },
+	{ 0xcfa37f55, "wake_up_process" },
+	{ 0xcd992a36, "dmu_tx_create" },
+	{ 0xd52bf1ce, "_raw_spin_lock" },
+	{ 0xcf21d241, "__wake_up" },
+	{ 0x659a64d0, "call_usermodehelper_setup" },
+	{ 0x236c8c64, "memcpy" },
+	{ 0x5c8b5ce8, "prepare_to_wait" },
+	{ 0xfa66f77c, "finish_wait" },
+	{ 0xf005a1c7, "dmu_tx_assign" },
+	{ 0x50720c5f, "snprintf" },
+	{ 0x80c3f220, "spl_kmem_free" },
+	{ 0xe55595ee, "dmu_read" },
+	{ 0x778a305, "spl_vmem_free" },
+	{ 0x4f6b400b, "_copy_from_user" },
+	{ 0x2482e688, "vsprintf" },
+	{ 0xdfb0b5e5, "misc_deregister" },
+	{ 0xa296a969, "dmu_tx_hold_write" },
+	{ 0x9dcb88fc, "spl_kmem_zalloc" },
+};
+
+static const char __module_depends[]
+__used
+__attribute__((section(".modinfo"))) =
+"depends=zfs,spl";
+
+
+MODULE_INFO(srcversion, "6224A8554C1154556C8A26B");
diff --git a/rpm/generic/zfs-kmod.spec.in b/rpm/generic/zfs-kmod.spec.in
index 48d9f4f..3840604 100644
--- a/rpm/generic/zfs-kmod.spec.in
+++ b/rpm/generic/zfs-kmod.spec.in
@@ -186,6 +186,18 @@ chmod u+x ${RPM_BUILD_ROOT}%{kmodinstdir_prefix}/*/extra/*/*/*
 rm -rf $RPM_BUILD_ROOT
 
 %changelog
+* Tue Mar 22 2016 Ned Bass <bass6 at llnl.gov> - 0.6.5.6-1
+- Remove artificial architecture restrictions in packaging
+- Add support for s390[x] zfsonlinux/zfs#4425
+- Handle negative dentries in case insensitive filesystem zfsonlinux/zfs#4243
+- Fix casesensitivity=insensitive deadlock zfsonlinux/zfs#4136
+- Correctly parse zdb -R flag arguments zfsonlinux/zfs#4304
+- Fix lock order inversion with zvol_open() zfsonlinux/zfs#3681
+- Add support for asynchronous zvol minor operations zfsonlinux/zfs#2217
+- Make zvol minor functionality more robust zfsonlinux/zfs#4344
+- Prevent zpool_find_vdev() from truncating vdev path zfsonlinux/zfs#4312
+- Add -gLP to zpool subcommands for alt vdev names zfsonlinux/zfs#4341
+- Fix zpool list -v output for spares and log devices zfsonlinux/zfs#4313
 * Wed Mar 9 2016 Ned Bass <bass6 at llnl.gov> - 0.6.5.5-1
 - Linux 4.5 compatibility zfsonlinux/zfs#4228
 - Create working debuginfo packages on Red Hat zfsonlinux/zfs#4224
diff --git a/rpm/generic/zfs.spec.in b/rpm/generic/zfs.spec.in
index 41419e6..55289df 100644
--- a/rpm/generic/zfs.spec.in
+++ b/rpm/generic/zfs.spec.in
@@ -69,11 +69,6 @@ License:        @ZFS_META_LICENSE@
 URL:            http://zfsonlinux.org/
 Source0:        %{name}-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-ExclusiveArch:  i386 i686 x86_64
-
-# May build but untested on ppc/ppc64
-ExcludeArch:    ppc ppc64
-
 Requires:       spl = %{version}
 Requires:       libzpool2 = %{version}
 Requires:       libnvpair1 = %{version}
@@ -332,6 +327,18 @@ exit 0
 %endif
 
 %changelog
+* Tue Mar 22 2016 Ned Bass <bass6 at llnl.gov> - 0.6.5.6-1
+- Remove artificial architecture restrictions in packaging
+- Add support for s390[x] zfsonlinux/zfs#4425
+- Handle negative dentries in case insensitive filesystem zfsonlinux/zfs#4243
+- Fix casesensitivity=insensitive deadlock zfsonlinux/zfs#4136
+- Correctly parse zdb -R flag arguments zfsonlinux/zfs#4304
+- Fix lock order inversion with zvol_open() zfsonlinux/zfs#3681
+- Add support for asynchronous zvol minor operations zfsonlinux/zfs#2217
+- Make zvol minor functionality more robust zfsonlinux/zfs#4344
+- Prevent zpool_find_vdev() from truncating vdev path zfsonlinux/zfs#4312
+- Add -gLP to zpool subcommands for alt vdev names zfsonlinux/zfs#4341
+- Fix zpool list -v output for spares and log devices zfsonlinux/zfs#4313
 * Wed Mar 9 2016 Ned Bass <bass6 at llnl.gov> - 0.6.5.5-1
 - Linux 4.5 compatibility zfsonlinux/zfs#4228
 - Create working debuginfo packages on Red Hat zfsonlinux/zfs#4224
diff --git a/rpm/redhat/zfs.spec.in b/rpm/redhat/zfs.spec.in
index 41419e6..55289df 100644
--- a/rpm/redhat/zfs.spec.in
+++ b/rpm/redhat/zfs.spec.in
@@ -69,11 +69,6 @@ License:        @ZFS_META_LICENSE@
 URL:            http://zfsonlinux.org/
 Source0:        %{name}-%{version}.tar.gz
 BuildRoot:      %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n)
-ExclusiveArch:  i386 i686 x86_64
-
-# May build but untested on ppc/ppc64
-ExcludeArch:    ppc ppc64
-
 Requires:       spl = %{version}
 Requires:       libzpool2 = %{version}
 Requires:       libnvpair1 = %{version}
@@ -332,6 +327,18 @@ exit 0
 %endif
 
 %changelog
+* Tue Mar 22 2016 Ned Bass <bass6 at llnl.gov> - 0.6.5.6-1
+- Remove artificial architecture restrictions in packaging
+- Add support for s390[x] zfsonlinux/zfs#4425
+- Handle negative dentries in case insensitive filesystem zfsonlinux/zfs#4243
+- Fix casesensitivity=insensitive deadlock zfsonlinux/zfs#4136
+- Correctly parse zdb -R flag arguments zfsonlinux/zfs#4304
+- Fix lock order inversion with zvol_open() zfsonlinux/zfs#3681
+- Add support for asynchronous zvol minor operations zfsonlinux/zfs#2217
+- Make zvol minor functionality more robust zfsonlinux/zfs#4344
+- Prevent zpool_find_vdev() from truncating vdev path zfsonlinux/zfs#4312
+- Add -gLP to zpool subcommands for alt vdev names zfsonlinux/zfs#4341
+- Fix zpool list -v output for spares and log devices zfsonlinux/zfs#4313
 * Wed Mar 9 2016 Ned Bass <bass6 at llnl.gov> - 0.6.5.5-1
 - Linux 4.5 compatibility zfsonlinux/zfs#4228
 - Create working debuginfo packages on Red Hat zfsonlinux/zfs#4224
diff --git a/scripts/zconfig.sh b/scripts/zconfig.sh
index 45ccf62..1908dc1 100755
--- a/scripts/zconfig.sh
+++ b/scripts/zconfig.sh
@@ -217,15 +217,26 @@ test_3() {
 	zconfig_zvol_device_stat 10 ${POOL_NAME} ${FULL_ZVOL_NAME} \
 	    ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 11
 
+	# Toggle the snapdev and observe snapshot device links toggled
+	${ZFS} set snapdev=hidden ${FULL_ZVOL_NAME} || fail 12
+	
+	zconfig_zvol_device_stat 7 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+	    "invalid" ${FULL_CLONE_NAME} || fail 13
+
+	${ZFS} set snapdev=visible ${FULL_ZVOL_NAME} || fail 14
+
+	zconfig_zvol_device_stat 10 ${POOL_NAME} ${FULL_ZVOL_NAME} \
+	    ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 15
+
 	# Destroy the pool and consequently the devices
-	${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 12
+	${ZPOOL_CREATE_SH} -p ${POOL_NAME} -c lo-raidz2 -d || fail 16
 
 	# verify the devices were removed
 	zconfig_zvol_device_stat 0 ${POOL_NAME} ${FULL_ZVOL_NAME} \
-	    ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 13
+	    ${FULL_SNAP_NAME} ${FULL_CLONE_NAME} || fail 17
 
-	${ZFS_SH} -u || fail 14
-	rm -f ${TMP_CACHE} || fail 15
+	${ZFS_SH} -u || fail 18
+	rm -f ${TMP_CACHE} || fail 19
 
 	pass
 }

-- 
OpenZFS on Linux



More information about the Pkg-zfsonlinux-devel mailing list