6393351 unique_* could be improved
authorahrens
Thu, 02 Aug 2007 21:23:46 -0700
changeset 4787 602d3f97842c
parent 4786 9c83486af455
child 4788 b21e6355f66f
6393351 unique_* could be improved 6553348 assertion failed: ab->b_flags & (1 << 3) at line 2572 of arc.c 6582408 ::arc should accept -k/-m/-g to print in kilo/mega/giga-bytes 6582438 should have generic reader-priority rwlock for spa_config locks 6582441 zfs_cmd_t should only be used to pass arguments to/from userland 6582456 property code is overdue for some spring cleaning 6588564 zpl unmount lock should use regular rwlock
usr/src/cmd/mdb/common/modules/zfs/zfs.c
usr/src/cmd/zdb/zdb.c
usr/src/cmd/zfs/zfs_main.c
usr/src/cmd/zpool/zpool_main.c
usr/src/common/zfs/zfs_deleg.c
usr/src/common/zfs/zfs_deleg.h
usr/src/common/zfs/zfs_prop.c
usr/src/common/zfs/zfs_prop.h
usr/src/lib/libzfs/common/libzfs.h
usr/src/lib/libzfs/common/libzfs_dataset.c
usr/src/lib/libzfs/common/libzfs_util.c
usr/src/lib/libzfs_jni/common/libzfs_jni_main.c
usr/src/lib/libzfs_jni/common/libzfs_jni_property.c
usr/src/uts/common/Makefile.files
usr/src/uts/common/fs/zfs/dmu_objset.c
usr/src/uts/common/fs/zfs/dnode_sync.c
usr/src/uts/common/fs/zfs/dsl_dataset.c
usr/src/uts/common/fs/zfs/dsl_deleg.c
usr/src/uts/common/fs/zfs/dsl_prop.c
usr/src/uts/common/fs/zfs/refcount.c
usr/src/uts/common/fs/zfs/rprwlock.c
usr/src/uts/common/fs/zfs/spa.c
usr/src/uts/common/fs/zfs/spa_config.c
usr/src/uts/common/fs/zfs/spa_misc.c
usr/src/uts/common/fs/zfs/sys/dmu.h
usr/src/uts/common/fs/zfs/sys/dmu_objset.h
usr/src/uts/common/fs/zfs/sys/dnode.h
usr/src/uts/common/fs/zfs/sys/dsl_dataset.h
usr/src/uts/common/fs/zfs/sys/dsl_deleg.h
usr/src/uts/common/fs/zfs/sys/refcount.h
usr/src/uts/common/fs/zfs/sys/rprwlock.h
usr/src/uts/common/fs/zfs/sys/spa_impl.h
usr/src/uts/common/fs/zfs/sys/unique.h
usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h
usr/src/uts/common/fs/zfs/sys/zfs_znode.h
usr/src/uts/common/fs/zfs/sys/zvol.h
usr/src/uts/common/fs/zfs/unique.c
usr/src/uts/common/fs/zfs/vdev_label.c
usr/src/uts/common/fs/zfs/zfs_ioctl.c
usr/src/uts/common/fs/zfs/zfs_vfsops.c
usr/src/uts/common/fs/zfs/zfs_vnops.c
usr/src/uts/common/fs/zfs/zvol.c
usr/src/uts/common/sys/fs/zfs.h
--- a/usr/src/cmd/mdb/common/modules/zfs/zfs.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/cmd/mdb/common/modules/zfs/zfs.c	Thu Aug 02 21:23:46 2007 -0700
@@ -770,54 +770,26 @@
 	return (DCMD_OK);
 }
 
-void
-abuf_help(void)
-{
-	mdb_printf("::abuf_find dva_word[0] dva_word[1]\n");
-}
-
 /*ARGSUSED*/
 static int
 arc_print(uintptr_t addr, uint_t flags, int argc, const mdb_arg_t *argv)
 {
 	kstat_named_t *stats;
 	GElf_Sym sym;
-	int nstats, i, j;
+	int nstats, i;
 	uint_t opt_a = FALSE;
+	uint_t opt_b = FALSE;
+	uint_t shift = 0;
+	const char *suffix;
 
-	/*
-	 * In its default mode, ::arc prints exactly what one would see with
-	 * the legacy "arc::print".  The legacy[] array tracks the order of
-	 * the legacy "arc" structure -- and whether the variable can be found
-	 * in a global variable or within the arc_stats (the default).
-	 */
-	struct {
-		const char *name;
-		const char *var;
-	} legacy[] = {
-		{ "anon",		"arc_anon" },
-		{ "mru",		"arc_mru" },
-		{ "mru_ghost",		"arc_mru_ghost" },
-		{ "mfu",		"arc_mfu" },
-		{ "mfu_ghost",		"arc_mfu_ghost" },
-		{ "size" },
-		{ "p" },
-		{ "c" },
-		{ "c_min" },
-		{ "c_max" },
-		{ "hits" },
-		{ "misses" },
-		{ "deleted" },
-		{ "recycle_miss" },
-		{ "mutex_miss" },
-		{ "evict_skip" },
-		{ "hash_elements" },
-		{ "hash_elements_max" },
-		{ "hash_collisions" },
-		{ "hash_chains" },
-		{ "hash_chain_max" },
-		{ "no_grow",		"arc_no_grow" },
-		{ NULL }
+	static const char *bytestats[] = {
+		"p", "c", "c_min", "c_max", "size", NULL
+	};
+
+	static const char *extras[] = {
+		"arc_no_grow", "arc_tempreserve",
+		"arc_meta_used", "arc_meta_limit", "arc_meta_max",
+		NULL
 	};
 
 	if (mdb_lookup_by_name("arc_stats", &sym) == -1) {
@@ -834,82 +806,85 @@
 
 	nstats = sym.st_size / sizeof (kstat_named_t);
 
-	if (mdb_getopts(argc, argv, 'a',
-	    MDB_OPT_SETBITS, TRUE, &opt_a, NULL) != argc)
+	/* NB: -a / opt_a are ignored for backwards compatability */
+	if (mdb_getopts(argc, argv,
+	    'a', MDB_OPT_SETBITS, TRUE, &opt_a,
+	    'b', MDB_OPT_SETBITS, TRUE, &opt_b,
+	    'k', MDB_OPT_SETBITS, 10, &shift,
+	    'm', MDB_OPT_SETBITS, 20, &shift,
+	    'g', MDB_OPT_SETBITS, 30, &shift,
+	    NULL) != argc)
 		return (DCMD_USAGE);
 
-	mdb_printf("{\n");
+	if (!opt_b && !shift)
+		shift = 20;
 
-	if (opt_a) {
-		for (i = 0; i < nstats; i++) {
-			mdb_printf("    %s = 0x%llx\n", stats[i].name,
-			    stats[i].value.ui64);
-		}
-
-		mdb_printf("}\n");
-		return (DCMD_OK);
+	switch (shift) {
+	case 0:
+		suffix = "B";
+		break;
+	case 10:
+		suffix = "KB";
+		break;
+	case 20:
+		suffix = "MB";
+		break;
+	case 30:
+		suffix = "GB";
+		break;
+	default:
+		suffix = "XX";
 	}
 
-	for (i = 0; legacy[i].name != NULL; i++) {
-		if (legacy[i].var != NULL) {
-			uint64_t buf;
+	for (i = 0; i < nstats; i++) {
+		int j;
+		boolean_t bytes = B_FALSE;
 
-			if (mdb_lookup_by_name(legacy[i].var, &sym) == -1) {
-				mdb_warn("failed to find '%s'", legacy[i].var);
-				return (DCMD_ERR);
-			}
-
-			if (sym.st_size != sizeof (uint64_t) &&
-			    sym.st_size != sizeof (uint32_t)) {
-				mdb_warn("expected scalar for legacy "
-				    "variable '%s'\n", legacy[i].var);
-				return (DCMD_ERR);
+		for (j = 0; bytestats[j]; j++) {
+			if (strcmp(stats[i].name, bytestats[j]) == 0) {
+				bytes = B_TRUE;
+				break;
 			}
-
-			if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) {
-				mdb_warn("couldn't read '%s'", legacy[i].var);
-				return (DCMD_ERR);
-			}
-
-			mdb_printf("    %s = ", legacy[i].name);
-
-			if (sym.st_size == sizeof (uint64_t))
-				mdb_printf("%a\n", buf);
-
-			if (sym.st_size == sizeof (uint32_t))
-				mdb_printf("%d\n", *((uint32_t *)&buf));
-
-			continue;
 		}
 
-		for (j = 0; j < nstats; j++) {
-			if (strcmp(legacy[i].name, stats[j].name) != 0)
-				continue;
-
-			mdb_printf("    %s = ", stats[j].name);
-
-			if (stats[j].value.ui64 == 0) {
-				/*
-				 * To remain completely output compatible with
-				 * the legacy arc::print, we print 0 not as
-				 * "0x0" but rather 0.
-				 */
-				mdb_printf("0\n");
-			} else {
-				mdb_printf("0x%llx\n", stats[j].value.ui64);
-			}
-
-			break;
-		}
-
-		if (j == nstats) {
-			mdb_warn("couldn't find statistic in 'arc_stats' "
-			    "for field '%s'\n", legacy[i].name);
+		if (bytes) {
+			mdb_printf("%-25s = %9llu %s\n", stats[i].name,
+			    stats[i].value.ui64 >> shift, suffix);
+		} else {
+			mdb_printf("%-25s = %9llu\n", stats[i].name,
+			    stats[i].value.ui64);
 		}
 	}
 
-	mdb_printf("}\n");
+	for (i = 0; extras[i]; i++) {
+		uint64_t buf;
+
+		if (mdb_lookup_by_name(extras[i], &sym) == -1) {
+			mdb_warn("failed to find '%s'", extras[i]);
+			return (DCMD_ERR);
+		}
+
+		if (sym.st_size != sizeof (uint64_t) &&
+		    sym.st_size != sizeof (uint32_t)) {
+			mdb_warn("expected scalar for variable '%s'\n",
+			    extras[i]);
+			return (DCMD_ERR);
+		}
 
+		if (mdb_vread(&buf, sym.st_size, sym.st_value) == -1) {
+			mdb_warn("couldn't read '%s'", extras[i]);
+			return (DCMD_ERR);
+		}
+
+		mdb_printf("%-25s = ", extras[i]);
+
+		/* NB: all the 64-bit extras happen to be byte counts */
+		if (sym.st_size == sizeof (uint64_t))
+			mdb_printf("%9llu %s\n", buf >> shift, suffix);
+
+		if (sym.st_size == sizeof (uint32_t))
+			mdb_printf("%9d\n", *((uint32_t *)&buf));
+	}
 	return (DCMD_OK);
 }
 
@@ -1035,14 +1010,6 @@
 	    0, NULL));
 }
 
-void
-vdev_help(void)
-{
-	mdb_printf("[vdev_t*]::vdev [-er]\n"
-	    "\t-> -e display vdev stats\n"
-	    "\t-> -r recursive (visit all children)\n");
-}
-
 /*
  * ::vdev
  *
@@ -1920,14 +1887,14 @@
  */
 
 static const mdb_dcmd_t dcmds[] = {
-	{ "arc", "[-a]", "print ARC variables", arc_print },
+	{ "arc", "[-bkmg]", "print ARC variables", arc_print },
 	{ "blkptr", ":", "print blkptr_t", blkptr },
 	{ "dbuf", ":", "print dmu_buf_impl_t", dbuf },
 	{ "dbuf_stats", ":", "dbuf stats", dbuf_stats },
 	{ "dbufs",
 	"\t[-O objset_t*] [-n objset_name | \"mos\"] [-o object | \"mdn\"] \n"
 	"\t[-l level] [-b blkid | \"bonus\"]",
-	"find dmu_buf_impl_t's that meet criterion", dbufs },
+	"find dmu_buf_impl_t's that match specified criteria", dbufs },
 	{ "abuf_find", "dva_word[0] dva_word[1]",
 	"find arc_buf_hdr_t of a specified DVA",
 	abuf_find },
@@ -1936,7 +1903,10 @@
 	{ "spa_verify", ":", "verify spa_t consistency", spa_verify },
 	{ "spa_space", ":[-b]", "print spa_t on-disk space usage", spa_space },
 	{ "spa_vdevs", ":", "given a spa_t, print vdev summary", spa_vdevs },
-	{ "vdev", ":[-re]", "vdev_t summary", vdev_print },
+	{ "vdev", ":[-re]\n"
+	"\t-r display recursively\n"
+	"\t-e print statistics\n",
+	"vdev_t summary", vdev_print },
 	{ "zio", ":", "zio_t summary", zio_print },
 	{ "zio_state", "?", "print out all zio_t structures on system or "
 	    "for a particular pool", zio_state },
--- a/usr/src/cmd/zdb/zdb.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/cmd/zdb/zdb.c	Thu Aug 02 21:23:46 2007 -0700
@@ -2287,6 +2287,7 @@
 
 	kernel_init(FREAD);
 	g_zfs = libzfs_init();
+	ASSERT(g_zfs != NULL);
 
 	/*
 	 * Disable vdev caching.  If we don't do this, live pool traversal
--- a/usr/src/cmd/zfs/zfs_main.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/cmd/zfs/zfs_main.c	Thu Aug 02 21:23:46 2007 -0700
@@ -380,7 +380,7 @@
 		    "PROPERTY", "EDIT", "INHERIT", "VALUES");
 
 		/* Iterate over all properties */
-		(void) zfs_prop_iter_ordered(usage_prop_cb, fp, B_FALSE);
+		(void) zfs_prop_iter_ordered(usage_prop_cb, fp);
 
 		(void) fprintf(fp, gettext("\nSizes are specified in bytes "
 		    "with standard units such as K, M, G, etc.\n"));
@@ -3829,17 +3829,6 @@
 	return (1);
 }
 
-zfs_prop_t
-propset_cb(zfs_prop_t prop, void *data)
-{
-	char *cmdname = (char *)data;
-
-	if (strcmp(cmdname, zfs_prop_to_name(prop)) == 0)
-		return (prop);
-
-	return (ZFS_PROP_CONT);
-}
-
 int
 main(int argc, char **argv)
 {
@@ -3847,8 +3836,6 @@
 	int i;
 	char *progname;
 	char *cmdname;
-	char *str;
-	boolean_t found = B_FALSE;
 
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
@@ -3927,38 +3914,11 @@
 		if (find_command_idx(cmdname, &i) == 0) {
 			current_command = &command_table[i];
 			ret = command_table[i].func(argc - 1, argv + 1);
-			found = B_TRUE;
-		}
-
-		/*
-		 * Check and see if they are doing property=value
-		 */
-		if (found == B_FALSE &&
-		    ((str = strchr(cmdname, '=')) != NULL)) {
-			*str = '\0';
-			if (zfs_prop_iter(propset_cb, cmdname,
-			    B_FALSE) != ZFS_PROP_INVAL)
-				found = B_TRUE;
-
-			if (found == B_FALSE && zfs_prop_user(cmdname))
-				found = B_TRUE;
-
-			if (found == B_TRUE &&
-			    find_command_idx("set", &i) == 0) {
-				*str = '=';
-				current_command = &command_table[i];
-				ret = command_table[i].func(argc, argv);
-			} else {
-				(void) fprintf(stderr,
-				    gettext("invalid property '%s'\n"),
-				    cmdname);
-				found = B_TRUE;
-				ret = 1;
-			}
-
-		}
-
-		if (found == B_FALSE) {
+		} else if (strchr(cmdname, '=') != NULL) {
+			verify(find_command_idx("set", &i) == 0);
+			current_command = &command_table[i];
+			ret = command_table[i].func(argc, argv);
+		} else {
 			(void) fprintf(stderr, gettext("unrecognized "
 			    "command '%s'\n"), cmdname);
 			usage(B_FALSE);
--- a/usr/src/cmd/zpool/zpool_main.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/cmd/zpool/zpool_main.c	Thu Aug 02 21:23:46 2007 -0700
@@ -343,7 +343,7 @@
 		    "PROPERTY", "VALUES");
 
 		/* Iterate over all properties */
-		(void) zpool_prop_iter(print_prop_cb, fp, B_FALSE);
+		(void) zpool_prop_iter(print_prop_cb, fp);
 	}
 
 	/*
@@ -3759,25 +3759,12 @@
 	return (1);
 }
 
-zpool_prop_t
-propset_cb(zpool_prop_t prop, void *data)
-{
-	char *cmdname = (char *)data;
-
-	if (strcmp(cmdname, zpool_prop_to_name(prop)) == 0)
-		return (prop);
-
-	return (ZFS_PROP_CONT);
-}
-
 int
 main(int argc, char **argv)
 {
 	int ret;
 	int i;
 	char *cmdname;
-	boolean_t found = B_FALSE;
-	char *str;
 
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
@@ -3820,41 +3807,20 @@
 	if (find_command_idx(cmdname, &i) == 0) {
 		current_command = &command_table[i];
 		ret = command_table[i].func(argc - 1, argv + 1);
-		found = B_TRUE;
-	}
-
-	/*
-	 * 'freeze' is a vile debugging abomination, so we treat it as such.
-	 */
-	if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
+	} else if (strchr(cmdname, '=')) {
+		verify(find_command_idx("set", &i) == 0);
+		current_command = &command_table[i];
+		ret = command_table[i].func(argc, argv);
+	} else if (strcmp(cmdname, "freeze") == 0 && argc == 3) {
+		/*
+		 * 'freeze' is a vile debugging abomination, so we treat
+		 * it as such.
+		 */
 		char buf[16384];
 		int fd = open(ZFS_DEV, O_RDWR);
 		(void) strcpy((void *)buf, argv[2]);
 		return (!!ioctl(fd, ZFS_IOC_POOL_FREEZE, buf));
-	}
-
-	/* is this a zpool property=value */
-	if (found == B_FALSE && ((str = strchr(cmdname, '=')) != NULL)) {
-		*str = '\0';
-		if (zpool_prop_iter(propset_cb, cmdname,
-		    B_FALSE) != ZFS_PROP_INVAL) {
-			if (find_command_idx("set", &i) == 0) {
-				*str = '=';
-				current_command = &command_table[i];
-				ret = command_table[i].func(argc, argv);
-				found = B_TRUE;
-			}
-		}
-
-		if (found == B_FALSE) {
-			*str = '=';
-			(void) fprintf(stderr,
-			    gettext("invalid property '%s'\n"), cmdname);
-			found = B_TRUE;
-		}
-	}
-
-	if (found == B_FALSE) {
+	} else {
 		(void) fprintf(stderr, gettext("unrecognized "
 		    "command '%s'\n"), cmdname);
 		usage(B_FALSE);
--- a/usr/src/common/zfs/zfs_deleg.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/common/zfs/zfs_deleg.c	Thu Aug 02 21:23:46 2007 -0700
@@ -37,7 +37,9 @@
 #include <libnvpair.h>
 #include <ctype.h>
 #endif
+/* XXX includes zfs_context.h, so why bother with the above? */
 #include <sys/dsl_deleg.h>
+#include "zfs_prop.h"
 #include "zfs_deleg.h"
 #include "zfs_namecheck.h"
 
@@ -57,108 +59,84 @@
 	ZFS_DELEG_PERM_SHARE,
 	ZFS_DELEG_PERM_SEND,
 	ZFS_DELEG_PERM_RECEIVE,
-	ZFS_DELEG_PERM_QUOTA,
-	ZFS_DELEG_PERM_RESERVATION,
-	ZFS_DELEG_PERM_VOLSIZE,
-	ZFS_DELEG_PERM_RECORDSIZE,
-	ZFS_DELEG_PERM_MOUNTPOINT,
-	ZFS_DELEG_PERM_SHARENFS,
-	ZFS_DELEG_PERM_CHECKSUM,
-	ZFS_DELEG_PERM_COMPRESSION,
-	ZFS_DELEG_PERM_ATIME,
-	ZFS_DELEG_PERM_DEVICES,
-	ZFS_DELEG_PERM_EXEC,
-	ZFS_DELEG_PERM_SETUID,
-	ZFS_DELEG_PERM_READONLY,
-	ZFS_DELEG_PERM_ZONED,
-	ZFS_DELEG_PERM_SNAPDIR,
-	ZFS_DELEG_PERM_ACLMODE,
-	ZFS_DELEG_PERM_ACLINHERIT,
 	ZFS_DELEG_PERM_ALLOW,
-	ZFS_DELEG_PERM_CANMOUNT,
 	ZFS_DELEG_PERM_USERPROP,
-	ZFS_DELEG_PERM_SHAREISCSI,
-	ZFS_DELEG_PERM_XATTR,
-	ZFS_DELEG_PERM_COPIES,
-	ZFS_DELEG_PERM_VERSION,
 	NULL
 };
 
-int
-zfs_deleg_type(char *name)
+static int
+zfs_valid_permission_name(const char *perm)
 {
-	return (name[0]);
+	if (zfs_deleg_canonicalize_perm(perm))
+		return (0);
+
+	return (permset_namecheck(perm, NULL, NULL));
 }
 
-static int
-zfs_valid_permission_name(char *perm)
+const char *
+zfs_deleg_canonicalize_perm(const char *perm)
 {
 	int i;
+	zfs_prop_t prop;
+
 	for (i = 0; zfs_deleg_perm_tab[i] != NULL; i++) {
 		if (strcmp(perm, zfs_deleg_perm_tab[i]) == 0)
-			return (0);
+			return (perm);
 	}
 
-	return (permset_namecheck(perm, NULL, NULL));
+	prop = zfs_name_to_prop(perm);
+	if (prop != ZFS_PROP_INVAL && zfs_prop_delegatable(prop))
+		return (zfs_prop_to_name(prop));
+	return (NULL);
+
 }
 
 static int
 zfs_validate_who(char *who)
 {
-	int error = 0;
 	char *p;
 
-	switch (zfs_deleg_type(who)) {
+	if (who[2] != ZFS_DELEG_FIELD_SEP_CHR)
+		return (-1);
+
+	switch (who[0]) {
 	case ZFS_DELEG_USER:
 	case ZFS_DELEG_GROUP:
 	case ZFS_DELEG_USER_SETS:
 	case ZFS_DELEG_GROUP_SETS:
-		if ((who[1] != 'l' || who[1] != 'd') &&
-		    (who[2] != ZFS_DELEG_FIELD_SEP_CHR)) {
-			error = -1;
-			break;
-		}
+		if (who[1] != ZFS_DELEG_LOCAL && who[1] != ZFS_DELEG_DESCENDENT)
+			return (-1);
+		for (p = &who[3]; *p; p++)
+			if (!isdigit(*p))
+				return (-1);
+		break;
 
-		for (p = &who[3]; p && *p; p++)
-			if (!isdigit(*p)) {
-				error = -1;
-			}
-		break;
 	case ZFS_DELEG_NAMED_SET:
 	case ZFS_DELEG_NAMED_SET_SETS:
-		error =  permset_namecheck(&who[3], NULL, NULL);
-		break;
+		if (who[1] != ZFS_DELEG_NA)
+			return (-1);
+		return (permset_namecheck(&who[3], NULL, NULL));
 
 	case ZFS_DELEG_CREATE:
 	case ZFS_DELEG_CREATE_SETS:
+		if (who[1] != ZFS_DELEG_NA)
+			return (-1);
+		if (who[3] != '\0')
+			return (-1);
+		break;
+
 	case ZFS_DELEG_EVERYONE:
 	case ZFS_DELEG_EVERYONE_SETS:
+		if (who[1] != ZFS_DELEG_LOCAL && who[1] != ZFS_DELEG_DESCENDENT)
+			return (-1);
 		if (who[3] != '\0')
-			error = -1;
+			return (-1);
 		break;
+
 	default:
-		error = -1;
+		return (-1);
 	}
 
-	return (error);
-}
-
-static int
-zfs_validate_iflags(char *who)
-{
-	switch (zfs_deleg_type(who)) {
-	case ZFS_DELEG_NAMED_SET:
-	case ZFS_DELEG_NAMED_SET_SETS:
-	case ZFS_DELEG_CREATE:
-	case ZFS_DELEG_CREATE_SETS:
-		if (who[1] != '-')
-			return (-1);
-		break;
-	default:
-		if (who[1] != 'l' && who[1] != 'd')
-			return (-1);
-		break;
-	}
 	return (0);
 }
 
@@ -180,9 +158,6 @@
 		if (zfs_validate_who(nvpair_name(who)))
 			return (-1);
 
-		if (zfs_validate_iflags(nvpair_name(who)))
-			return (-1);
-
 		error = nvlist_lookup_nvlist(nvp, nvpair_name(who), &perms);
 
 		if (error && error != ENOENT)
@@ -197,9 +172,8 @@
 		do {
 			error = zfs_valid_permission_name(
 			    nvpair_name(perm_name));
-			if (error) {
+			if (error)
 				return (-1);
-			}
 		} while (perm_name = nvlist_next_nvpair(perms, perm_name));
 	} while (who = nvlist_next_nvpair(nvp, who));
 	return (0);
@@ -220,7 +194,8 @@
  * data - is either a permission set name or a 64 bit uid/gid.
  */
 void
-zfs_deleg_whokey(char *attr, char type, char inheritchr, void *data)
+zfs_deleg_whokey(char *attr, zfs_deleg_who_type_t type,
+    char inheritchr, void *data)
 {
 	int len = ZFS_MAX_DELEG_NAME;
 	uint64_t *id = data;
@@ -243,8 +218,12 @@
 		(void) snprintf(attr, len, "%c-%c", type,
 		    ZFS_DELEG_FIELD_SEP_CHR);
 		break;
-	default:
+	case ZFS_DELEG_EVERYONE:
+	case ZFS_DELEG_EVERYONE_SETS:
 		(void) snprintf(attr, len, "%c%c%c", type, inheritchr,
 		    ZFS_DELEG_FIELD_SEP_CHR);
+		break;
+	default:
+		ASSERT(!"bad zfs_deleg_who_type_t");
 	}
 }
--- a/usr/src/common/zfs/zfs_deleg.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/common/zfs/zfs_deleg.h	Thu Aug 02 21:23:46 2007 -0700
@@ -47,11 +47,11 @@
 #define	ZFS_DELEG_NA		'-'
 
 extern char *zfs_deleg_perm_tab[];
-int zfs_deleg_type(char *attr);
 
 int zfs_deleg_verify_nvlist(nvlist_t *nvlist);
-void zfs_deleg_whokey(char *attr, char type,
+void zfs_deleg_whokey(char *attr, zfs_deleg_who_type_t type,
     char checkflag, void *data);
+const char *zfs_deleg_canonicalize_perm(const char *perm);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/common/zfs/zfs_prop.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/common/zfs/zfs_prop.c	Thu Aug 02 21:23:46 2007 -0700
@@ -25,28 +25,6 @@
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
-/*
- * Master property table.
- *
- * This table keeps track of all the properties supported by ZFS, and their
- * various attributes.  Not all of these are needed by the kernel, and several
- * are only used by a single libzfs client.  But having them here centralizes
- * all property information in one location.
- *
- * 	name		The human-readable string representing this property
- * 	proptype	Basic type (string, boolean, number)
- * 	default		Default value for the property.  Sadly, C only allows
- * 			you to initialize the first member of a union, so we
- * 			have two default members for each property.
- * 	attr		Attributes (readonly, inheritable) for the property
- * 	types		Valid dataset types to which this applies
- * 	values		String describing acceptable values for the property
- * 	colname		The column header for 'zfs list'
- *	colfmt		The column formatting for 'zfs list'
- *
- * This table must match the order of property types in libzfs.h.
- */
-
 #include <sys/zio.h>
 #include <sys/spa.h>
 #include <sys/zfs_acl.h>
@@ -66,156 +44,280 @@
 #endif
 
 typedef enum {
-	prop_default,
-	prop_readonly,
-	prop_inherit
+	PROP_DEFAULT,
+	PROP_READONLY,
+	PROP_INHERIT
 } prop_attr_t;
 
+typedef struct zfs_index {
+	const char *name;
+	uint64_t index;
+} zfs_index_t;
+
 typedef struct {
-	const char	*pd_name;
-	zfs_proptype_t	pd_proptype;
-	uint64_t	pd_numdefault;
-	const char	*pd_strdefault;
-	prop_attr_t	pd_attr;
-	int		pd_types;
-	const char	*pd_values;
-	const char	*pd_colname;
-	boolean_t	pd_rightalign;
-	boolean_t	pd_visible;
-	const char	*pd_perm;
+	const char *pd_name;		/* human-readable property name */
+	zfs_proptype_t pd_proptype;	/* string, boolean, index, number */
+	const char *pd_strdefault;	/* default for strings */
+	uint64_t pd_numdefault;		/* for boolean / index / number */
+	prop_attr_t pd_attr;		/* default, readonly, inherit */
+	int pd_types;			/* bitfield of valid dataset types */
+					/* fs | vol | snap; or pool */
+	const char *pd_values;		/* string telling acceptable values */
+	const char *pd_colname;		/* column header for "zfs list" */
+	boolean_t pd_rightalign;	/* column alignment for "zfs list" */
+	boolean_t pd_visible;		/* do we list this property with the */
+					/* "zfs get" help message */
+	const zfs_index_t *pd_table;	/* for index properties, a table */
+					/* defining the possible values */
 } prop_desc_t;
 
-static prop_desc_t zfs_prop_table[] = {
-	{ "type",	prop_type_string,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE", B_TRUE,
-	    B_TRUE, ZFS_DELEG_PERM_NONE },
-	{ "creation",	prop_type_number,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_ANY, "<date>", "CREATION", B_FALSE, B_TRUE,
-	    ZFS_DELEG_PERM_NONE },
-	{ "used",	prop_type_number,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_ANY, "<size>",	"USED", B_TRUE, B_TRUE,
-	    ZFS_DELEG_PERM_NONE },
-	{ "available",	prop_type_number,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size>", "AVAIL", B_TRUE,
-	    B_TRUE, ZFS_DELEG_PERM_NONE },
-	{ "referenced",	prop_type_number,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_ANY,
-	    "<size>", "REFER", B_TRUE, B_TRUE, ZFS_DELEG_PERM_NONE },
-	{ "compressratio", prop_type_number,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_ANY, "<1.00x or higher if compressed>", "RATIO", B_TRUE,
-	    B_TRUE, ZFS_DELEG_PERM_NONE },
-	{ "mounted",	prop_type_boolean,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED", B_TRUE, B_TRUE,
-	    ZFS_DELEG_PERM_NONE },
-	{ "origin",	prop_type_string,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN",
-	    B_FALSE, B_TRUE, ZFS_DELEG_PERM_NONE },
-	{ "quota",	prop_type_number,	0,	NULL,	prop_default,
-	    ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA", B_TRUE, B_TRUE,
-	    ZFS_DELEG_PERM_QUOTA },
-	{ "reservation", prop_type_number,	0,	NULL,	prop_default,
+static prop_desc_t zfs_prop_table[ZFS_NUM_PROPS];
+
+static void
+register_impl(zfs_prop_t prop, const char *name, zfs_proptype_t type,
+    uint64_t numdefault, const char *strdefault, prop_attr_t attr,
+    int objset_types, const char *values, const char *colname,
+    boolean_t rightalign, boolean_t visible, const zfs_index_t *table)
+{
+	prop_desc_t *pd = &zfs_prop_table[prop];
+
+	ASSERT(pd->pd_name == NULL || pd->pd_name == name);
+
+	pd->pd_name = name;
+	pd->pd_proptype = type;
+	pd->pd_numdefault = numdefault;
+	pd->pd_strdefault = strdefault;
+	pd->pd_attr = attr;
+	pd->pd_types = objset_types;
+	pd->pd_values = values;
+	pd->pd_colname = colname;
+	pd->pd_rightalign = rightalign;
+	pd->pd_visible = visible;
+	pd->pd_table = table;
+}
+
+static void
+register_string(zfs_prop_t prop, const char *name, const char *def,
+    prop_attr_t attr, int objset_types, const char *values,
+    const char *colname)
+{
+	register_impl(prop, name, PROP_TYPE_STRING, 0, def, attr,
+	    objset_types, values, colname, B_FALSE, B_TRUE, NULL);
+
+}
+
+static void
+register_number(zfs_prop_t prop, const char *name, uint64_t def,
+    prop_attr_t attr, int objset_types, const char *values, const char *colname)
+{
+	register_impl(prop, name, PROP_TYPE_NUMBER, def, NULL, attr,
+	    objset_types, values, colname, B_TRUE, B_TRUE, NULL);
+}
+
+static void
+register_boolean(zfs_prop_t prop, const char *name, uint64_t def,
+    prop_attr_t attr, int objset_types, const char *values, const char *colname)
+{
+	register_impl(prop, name, PROP_TYPE_BOOLEAN, def, NULL, attr,
+	    objset_types, values, colname, B_TRUE, B_TRUE, NULL);
+}
+
+static void
+register_index(zfs_prop_t prop, const char *name, uint64_t def,
+    int objset_types, const char *values, const char *colname,
+    const zfs_index_t *table)
+{
+	register_impl(prop, name, PROP_TYPE_INDEX, def, NULL, PROP_INHERIT,
+	    objset_types, values, colname, B_TRUE, B_TRUE, table);
+}
+
+static void
+register_hidden(zfs_prop_t prop, const char *name, zfs_proptype_t type,
+    prop_attr_t attr, int objset_types, const char *colname)
+{
+	register_impl(prop, name, type, 0, NULL, attr,
+	    objset_types, NULL, colname, B_FALSE, B_FALSE, NULL);
+}
+
+void
+zfs_prop_init(void)
+{
+	static zfs_index_t checksum_table[] = {
+		{ "on",		ZIO_CHECKSUM_ON },
+		{ "off",	ZIO_CHECKSUM_OFF },
+		{ "fletcher2",	ZIO_CHECKSUM_FLETCHER_2 },
+		{ "fletcher4",	ZIO_CHECKSUM_FLETCHER_4 },
+		{ "sha256",	ZIO_CHECKSUM_SHA256 },
+		{ NULL }
+	};
+
+	static zfs_index_t compress_table[] = {
+		{ "on",		ZIO_COMPRESS_ON },
+		{ "off",	ZIO_COMPRESS_OFF },
+		{ "lzjb",	ZIO_COMPRESS_LZJB },
+		{ "gzip",	ZIO_COMPRESS_GZIP_6 },	/* gzip default */
+		{ "gzip-1",	ZIO_COMPRESS_GZIP_1 },
+		{ "gzip-2",	ZIO_COMPRESS_GZIP_2 },
+		{ "gzip-3",	ZIO_COMPRESS_GZIP_3 },
+		{ "gzip-4",	ZIO_COMPRESS_GZIP_4 },
+		{ "gzip-5",	ZIO_COMPRESS_GZIP_5 },
+		{ "gzip-6",	ZIO_COMPRESS_GZIP_6 },
+		{ "gzip-7",	ZIO_COMPRESS_GZIP_7 },
+		{ "gzip-8",	ZIO_COMPRESS_GZIP_8 },
+		{ "gzip-9",	ZIO_COMPRESS_GZIP_9 },
+		{ NULL }
+	};
+
+	static zfs_index_t snapdir_table[] = {
+		{ "hidden",	ZFS_SNAPDIR_HIDDEN },
+		{ "visible",	ZFS_SNAPDIR_VISIBLE },
+		{ NULL }
+	};
+
+	static zfs_index_t acl_mode_table[] = {
+		{ "discard",	ZFS_ACL_DISCARD },
+		{ "groupmask",	ZFS_ACL_GROUPMASK },
+		{ "passthrough", ZFS_ACL_PASSTHROUGH },
+		{ NULL }
+	};
+
+	static zfs_index_t acl_inherit_table[] = {
+		{ "discard",	ZFS_ACL_DISCARD },
+		{ "noallow",	ZFS_ACL_NOALLOW },
+		{ "secure",	ZFS_ACL_SECURE },
+		{ "passthrough", ZFS_ACL_PASSTHROUGH },
+		{ NULL }
+	};
+
+	static zfs_index_t copies_table[] = {
+		{ "1",		1 },
+		{ "2",		2 },
+		{ "3",		3 },
+		{ NULL }
+	};
+
+	static zfs_index_t version_table[] = {
+		{ "1",		1 },
+		{ "2",		2 },
+		{ "current",	ZPL_VERSION },
+		{ NULL }
+	};
+
+	/* inherit index properties */
+	register_index(ZFS_PROP_CHECKSUM, "checksum", ZIO_CHECKSUM_DEFAULT,
 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
-	    "<size> | none", "RESERV", B_TRUE, B_TRUE,
-	    ZFS_DELEG_PERM_RESERVATION },
-	{ "volsize",	prop_type_number,	0,	NULL,	prop_default,
-	    ZFS_TYPE_VOLUME, "<size>", "VOLSIZE", B_TRUE, B_TRUE,
-	    ZFS_DELEG_PERM_VOLSIZE },
-	{ "volblocksize", prop_type_number,	8192,	NULL,	prop_readonly,
-	    ZFS_TYPE_VOLUME, "512 to 128k, power of 2",	"VOLBLOCK", B_TRUE,
-	    B_TRUE, ZFS_DELEG_PERM_NONE },
-	{ "recordsize",	prop_type_number,	SPA_MAXBLOCKSIZE,	NULL,
-	    prop_inherit,
-	    ZFS_TYPE_FILESYSTEM,
-	    "512 to 128k, power of 2", "RECSIZE", B_TRUE, B_TRUE,
-	    ZFS_DELEG_PERM_RECORDSIZE },
-	{ "mountpoint",	prop_type_string,	0,	"/",	prop_inherit,
+	    "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM",
+	    checksum_table);
+	register_index(ZFS_PROP_COMPRESSION, "compression",
+	    ZIO_COMPRESS_DEFAULT, ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+	    "on | off | lzjb | gzip | gzip-[1-9]", "COMPRESS", compress_table);
+	register_index(ZFS_PROP_SNAPDIR, "snapdir", ZFS_SNAPDIR_HIDDEN,
+	    ZFS_TYPE_FILESYSTEM, "hidden | visible", "SNAPDIR", snapdir_table);
+	register_index(ZFS_PROP_ACLMODE, "aclmode", ZFS_ACL_GROUPMASK,
+	    ZFS_TYPE_FILESYSTEM, "discard | groupmask | passthrough", "ACLMODE",
+	    acl_mode_table);
+	register_index(ZFS_PROP_ACLINHERIT, "aclinherit", ZFS_ACL_SECURE,
 	    ZFS_TYPE_FILESYSTEM,
-	    "<path> | legacy | none", "MOUNTPOINT", B_FALSE, B_TRUE,
-	    ZFS_DELEG_PERM_MOUNTPOINT },
-	{ "sharenfs",	prop_type_string,	0,	"off",	prop_inherit,
-	    ZFS_TYPE_FILESYSTEM,
-	    "on | off | share(1M) options", "SHARENFS", B_FALSE, B_TRUE,
-	    ZFS_DELEG_PERM_SHARENFS },
-	{ "checksum",	prop_type_index,	ZIO_CHECKSUM_DEFAULT,	"on",
-	    prop_inherit,	ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
-	    "on | off | fletcher2 | fletcher4 | sha256", "CHECKSUM", B_TRUE,
-	    B_TRUE, ZFS_DELEG_PERM_CHECKSUM },
-	{ "compression", prop_type_index,	ZIO_COMPRESS_DEFAULT,	"off",
-	    prop_inherit,	ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
-	    "on | off | lzjb | gzip | gzip-[1-9]", "COMPRESS", B_TRUE, B_TRUE,
-	    ZFS_DELEG_PERM_COMPRESSION },
-	{ "atime",	prop_type_boolean,	1,	NULL,	prop_inherit,
-	    ZFS_TYPE_FILESYSTEM,
-	    "on | off", "ATIME", B_TRUE, B_TRUE, ZFS_DELEG_PERM_ATIME },
-	{ "devices",	prop_type_boolean,	1,	NULL,	prop_inherit,
+	    "discard | noallow | secure | passthrough", "ACLINHERIT",
+	    acl_inherit_table);
+	register_index(ZFS_PROP_COPIES, "copies", 1,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
+	    "1 | 2 | 3", "COPIES", copies_table);
+	register_index(ZFS_PROP_VERSION, "version", 0,
 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
-	    "on | off", "DEVICES", B_TRUE, B_TRUE, ZFS_DELEG_PERM_DEVICES },
-	{ "exec",	prop_type_boolean,	1,	NULL,	prop_inherit,
-	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
-	    "on | off", "EXEC", B_TRUE, B_TRUE, ZFS_DELEG_PERM_EXEC },
-	{ "setuid",	prop_type_boolean,	1,	NULL,	prop_inherit,
-	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "SETUID",
-	    B_TRUE, B_TRUE, ZFS_DELEG_PERM_SETUID },
-	{ "readonly",	prop_type_boolean,	0,	NULL,	prop_inherit,
+	    "1 | 2 | current", "VERSION", version_table);
+
+	/* string properties */
+	register_string(ZFS_PROP_ORIGIN, "origin", NULL, PROP_READONLY,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<snapshot>", "ORIGIN");
+	register_string(ZPOOL_PROP_BOOTFS, "bootfs", NULL, PROP_DEFAULT,
+	    ZFS_TYPE_POOL, "<filesystem>", "BOOTFS");
+	register_string(ZFS_PROP_MOUNTPOINT, "mountpoint", "/", PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM, "<path> | legacy | none", "MOUNTPOINT");
+	register_string(ZFS_PROP_SHARENFS, "sharenfs", "off", PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM, "on | off | share(1M) options", "SHARENFS");
+	register_string(ZFS_PROP_SHAREISCSI, "shareiscsi", "off", PROP_INHERIT,
+	    ZFS_TYPE_ANY, "on | off | type=<type>", "SHAREISCSI");
+	register_string(ZFS_PROP_TYPE, "type", NULL, PROP_READONLY,
+	    ZFS_TYPE_ANY, "filesystem | volume | snapshot", "TYPE");
+
+	/* readonly number properties */
+	register_number(ZFS_PROP_USED, "used", 0, PROP_READONLY,
+	    ZFS_TYPE_ANY, "<size>", "USED");
+	register_number(ZFS_PROP_AVAILABLE, "available", 0, PROP_READONLY,
 	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
-	    "on | off", "RDONLY", B_TRUE, B_TRUE, ZFS_DELEG_PERM_READONLY },
-	{ "zoned",	prop_type_boolean,	0,	NULL,	prop_inherit,
-	    ZFS_TYPE_FILESYSTEM,
-	    "on | off", "ZONED", B_TRUE, B_TRUE, ZFS_DELEG_PERM_ZONED },
-	{ "snapdir",	prop_type_index,	ZFS_SNAPDIR_HIDDEN, "hidden",
-	    prop_inherit,
-	    ZFS_TYPE_FILESYSTEM,
-	    "hidden | visible", "SNAPDIR", B_TRUE, B_TRUE,
-	    ZFS_DELEG_PERM_SNAPDIR },
-	{ "aclmode", prop_type_index,	ZFS_ACL_GROUPMASK, "groupmask",
-	    prop_inherit, ZFS_TYPE_FILESYSTEM,
-	    "discard | groupmask | passthrough", "ACLMODE", B_TRUE,
-	    B_TRUE, ZFS_DELEG_PERM_ACLMODE },
-	{ "aclinherit", prop_type_index,	ZFS_ACL_SECURE,	"secure",
-	    prop_inherit, ZFS_TYPE_FILESYSTEM,
-	    "discard | noallow | secure | passthrough", "ACLINHERIT", B_TRUE,
-	    B_TRUE, ZFS_DELEG_PERM_ACLINHERIT },
-	{ "createtxg",	prop_type_number,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_ANY, NULL, NULL, B_FALSE, B_FALSE, ZFS_DELEG_PERM_NONE },
-	{ "name",	prop_type_string,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_ANY, NULL, "NAME", B_FALSE, B_FALSE, ZFS_DELEG_PERM_NONE },
-	{ "canmount",	prop_type_boolean,	1,	NULL,	prop_default,
-	    ZFS_TYPE_FILESYSTEM,
-	    "on | off", "CANMOUNT", B_TRUE, B_TRUE, ZFS_DELEG_PERM_CANMOUNT },
-	{ "shareiscsi",	prop_type_string,	0,	"off",	prop_inherit,
-	    ZFS_TYPE_ANY,
-	    "on | off | type=<type>", "SHAREISCSI", B_FALSE, B_TRUE,
-	    ZFS_DELEG_PERM_SHAREISCSI },
-	{ "iscsioptions", prop_type_string,	0,	NULL,	prop_inherit,
-	    ZFS_TYPE_VOLUME, NULL, "ISCSIOPTIONS", B_FALSE, B_FALSE,
-	    ZFS_DELEG_PERM_NONE },
-	{ "xattr",	prop_type_boolean,	1,	NULL,	prop_inherit,
-	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT,
-	    "on | off", "XATTR", B_TRUE, B_TRUE, ZFS_DELEG_PERM_XATTR },
-	{ "numclones", prop_type_number,	0,	NULL,	prop_readonly,
-	    ZFS_TYPE_SNAPSHOT, NULL, NULL, B_FALSE, B_FALSE,
-	    ZFS_DELEG_PERM_NONE },
-	{ "copies",	prop_type_index,	1,	"1",	prop_inherit,
-	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME,
-	    "1 | 2 | 3", "COPIES", B_TRUE, B_TRUE, ZFS_DELEG_PERM_COPIES },
-	{ "bootfs", prop_type_string,	0,	NULL,	prop_default,
-	    ZFS_TYPE_POOL, "<filesystem>", "BOOTFS", B_FALSE,
-	    B_TRUE, ZFS_DELEG_PERM_NONE },
-	{ "autoreplace", prop_type_boolean,	0,	NULL, prop_default,
-	    ZFS_TYPE_POOL, "on | off", "REPLACE", B_FALSE, B_TRUE,
-	    ZFS_DELEG_PERM_NONE },
-	{ "delegation", prop_type_boolean,	1,	NULL,	prop_default,
-	    ZFS_TYPE_POOL, "on | off", "DELEGATION", B_TRUE,
-	    B_TRUE, ZFS_DELEG_PERM_NONE },
-	{ "version",	prop_type_index,	0,	NULL,	prop_default,
-	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "1 | 2 | current",
-	    "VERSION", B_TRUE, B_TRUE, ZFS_DELEG_PERM_VERSION },
-};
+	    "<size>", "AVAIL");
+	register_number(ZFS_PROP_REFERENCED, "referenced", 0, PROP_READONLY,
+	    ZFS_TYPE_ANY, "<size>", "REFER");
+	register_number(ZFS_PROP_COMPRESSRATIO, "compressratio", 0,
+	    PROP_READONLY, ZFS_TYPE_ANY,
+	    "<1.00x or higher if compressed>", "RATIO");
+	register_number(ZFS_PROP_VOLBLOCKSIZE, "volblocksize", 8192,
+	    PROP_READONLY,
+	    ZFS_TYPE_VOLUME, "512 to 128k, power of 2",	"VOLBLOCK");
+
+	/* default number properties */
+	register_number(ZFS_PROP_QUOTA, "quota", 0, PROP_DEFAULT,
+	    ZFS_TYPE_FILESYSTEM, "<size> | none", "QUOTA");
+	register_number(ZFS_PROP_RESERVATION, "reservation", 0, PROP_DEFAULT,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "<size> | none", "RESERV");
+	register_number(ZFS_PROP_VOLSIZE, "volsize", 0, PROP_DEFAULT,
+	    ZFS_TYPE_VOLUME, "<size>", "VOLSIZE");
+
+	/* inherit number properties */
+	register_number(ZFS_PROP_RECORDSIZE, "recordsize", SPA_MAXBLOCKSIZE,
+	    PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM, "512 to 128k, power of 2", "RECSIZE");
+
+	/* readonly boolean properties */
+	register_boolean(ZFS_PROP_MOUNTED, "mounted", 0, PROP_READONLY,
+	    ZFS_TYPE_FILESYSTEM, "yes | no | -", "MOUNTED");
+
+	/* default boolean properties */
+	register_boolean(ZFS_PROP_CANMOUNT, "canmount", 1, PROP_DEFAULT,
+	    ZFS_TYPE_FILESYSTEM, "on | off", "CANMOUNT");
+	register_boolean(ZPOOL_PROP_DELEGATION, "delegation", 1, PROP_DEFAULT,
+	    ZFS_TYPE_POOL, "on | off", "DELEGATION");
+	register_boolean(ZPOOL_PROP_AUTOREPLACE, "autoreplace", 0, PROP_DEFAULT,
+	    ZFS_TYPE_POOL, "on | off", "REPLACE");
 
-#define	ZFS_PROP_COUNT	((sizeof (zfs_prop_table))/(sizeof (prop_desc_t)))
+	/* inherit boolean properties */
+	register_boolean(ZFS_PROP_ATIME, "atime", 1, PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM, "on | off", "ATIME");
+	register_boolean(ZFS_PROP_DEVICES, "devices", 1, PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "DEVICES");
+	register_boolean(ZFS_PROP_EXEC, "exec", 1, PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "EXEC");
+	register_boolean(ZFS_PROP_SETUID, "setuid", 1, PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "SETUID");
+	register_boolean(ZFS_PROP_READONLY, "readonly", 0, PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_VOLUME, "on | off", "RDONLY");
+	register_boolean(ZFS_PROP_ZONED, "zoned", 0, PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM, "on | off", "ZONED");
+	register_boolean(ZFS_PROP_XATTR, "xattr", 1, PROP_INHERIT,
+	    ZFS_TYPE_FILESYSTEM | ZFS_TYPE_SNAPSHOT, "on | off", "XATTR");
+
+	/* hidden properties */
+	register_hidden(ZFS_PROP_CREATETXG, "createtxg", PROP_TYPE_NUMBER,
+	    PROP_READONLY, ZFS_TYPE_ANY, NULL);
+	register_hidden(ZFS_PROP_NUMCLONES, "numclones", PROP_TYPE_NUMBER,
+	    PROP_READONLY, ZFS_TYPE_SNAPSHOT, NULL);
+	register_hidden(ZFS_PROP_NAME, "name", PROP_TYPE_STRING,
+	    PROP_READONLY, ZFS_TYPE_ANY, "NAME");
+	register_hidden(ZFS_PROP_ISCSIOPTIONS, "iscsioptions", PROP_TYPE_STRING,
+	    PROP_INHERIT, ZFS_TYPE_VOLUME, "ISCSIOPTIONS");
+	register_hidden(ZPOOL_PROP_NAME, "zpoolname", PROP_TYPE_STRING,
+	    PROP_READONLY, ZFS_TYPE_POOL, NULL);
+
+	/* oddball properties */
+	register_impl(ZFS_PROP_CREATION, "creation", PROP_TYPE_NUMBER, 0, NULL,
+	    PROP_READONLY, ZFS_TYPE_ANY,
+	    "<date>", "CREATION", B_FALSE, B_TRUE, NULL);
+}
+
 
 /*
- * Returns TRUE if the property applies to the given dataset types.
+ * Returns TRUE if the property applies to any of the given dataset types.
  */
 int
 zfs_prop_valid_for_type(zfs_prop_t prop, int types)
@@ -240,28 +342,21 @@
  * zfs_prop_table[]
  */
 static int
-zfs_prop_compare(const void *p1, const void *p2)
+zfs_prop_compare(const void *arg1, const void *arg2)
 {
-	int i, j;
-	prop_attr_t iattr, jattr;
-
-	i = *((int *)p1);
-	j = *((int *)p2);
-
-	iattr = zfs_prop_table[i].pd_attr;
-	jattr = zfs_prop_table[j].pd_attr;
+	const zfs_prop_t *p1 = arg1;
+	const zfs_prop_t *p2 = arg2;
+	boolean_t p1ro, p2ro;
 
-	/* first, sort by whether the property is readonly or not */
-	if (iattr != prop_readonly &&
-	    jattr == prop_readonly)
-		return (1);
-	if (iattr == prop_readonly &&
-	    jattr != prop_readonly)
-		return (-1);
+	p1ro = (zfs_prop_table[*p1].pd_attr == PROP_READONLY);
+	p2ro = (zfs_prop_table[*p2].pd_attr == PROP_READONLY);
 
-	/* otherwise, sort by the property name */
-	return (strcmp(zfs_prop_table[i].pd_name,
-	    zfs_prop_table[j].pd_name));
+	if (p1ro == p2ro) {
+		return (strcmp(zfs_prop_table[*p1].pd_name,
+		    zfs_prop_table[*p2].pd_name));
+	}
+
+	return (p1ro ? -1 : 1);
 }
 
 /*
@@ -275,19 +370,18 @@
     boolean_t show_all, boolean_t ordered)
 {
 	int i;
-	int order[ZFS_PROP_COUNT];
+	zfs_prop_t order[ZFS_NUM_PROPS];
 
-	for (int j = 0; j < ZFS_PROP_COUNT; j++) {
+	for (int j = 0; j < ZFS_NUM_PROPS; j++)
 		order[j] = j;
-	}
 
 
 	if (ordered) {
-		qsort((void *)order, ZFS_PROP_COUNT, sizeof (zfs_prop_t),
+		qsort((void *)order, ZFS_NUM_PROPS, sizeof (zfs_prop_t),
 		    zfs_prop_compare);
 	}
 
-	for (i = 0; i < ZFS_PROP_COUNT; i++) {
+	for (i = 0; i < ZFS_NUM_PROPS; i++) {
 		if (zfs_prop_valid_for_type(order[i], type) &&
 		    (zfs_prop_is_visible(order[i]) || show_all)) {
 			if (func(order[i], cb) != ZFS_PROP_CONT)
@@ -298,23 +392,21 @@
 }
 
 zfs_prop_t
-zfs_prop_iter(zfs_prop_f func, void *cb, boolean_t show_all)
+zfs_prop_iter(zfs_prop_f func, void *cb)
 {
-	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, show_all,
-	    B_FALSE));
+	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, B_FALSE, B_FALSE));
 }
 
 zfs_prop_t
-zfs_prop_iter_ordered(zfs_prop_f func, void *cb, boolean_t show_all)
+zfs_prop_iter_ordered(zfs_prop_f func, void *cb)
 {
-	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, show_all,
-	    B_TRUE));
+	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_ANY, B_FALSE, B_TRUE));
 }
 
 zpool_prop_t
-zpool_prop_iter(zpool_prop_f func, void *cb, boolean_t show_all)
+zpool_prop_iter(zpool_prop_f func, void *cb)
 {
-	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_POOL, show_all,
+	return (zfs_prop_iter_common(func, cb, ZFS_TYPE_POOL, B_FALSE,
 	    B_FALSE));
 }
 
@@ -337,9 +429,7 @@
 #ifndef _KERNEL
 	const char *colname = zfs_prop_table[prop].pd_colname;
 	int c;
-#endif
 
-#ifndef _KERNEL
 	if (colname == NULL)
 		return (B_FALSE);
 #endif
@@ -367,9 +457,8 @@
 {
 	const char *propname = cb_data;
 
-	if (propname_match(propname, prop, strlen(propname))) {
+	if (propname_match(propname, prop, strlen(propname)))
 		return (prop);
-	}
 
 	return (ZFS_PROP_CONT);
 }
@@ -405,10 +494,11 @@
 	return (zfs_name_to_prop_common(propname, ZFS_TYPE_POOL));
 }
 
-const char *
-zfs_prop_perm(zfs_prop_t prop)
+boolean_t
+zfs_prop_delegatable(zfs_prop_t prop)
 {
-	return (zfs_prop_table[prop].pd_perm);
+	prop_desc_t *pd = &zfs_prop_table[prop];
+	return (pd->pd_attr != PROP_READONLY && pd->pd_types != ZFS_TYPE_POOL);
 }
 
 /*
@@ -480,7 +570,7 @@
 int
 zfs_prop_readonly(zfs_prop_t prop)
 {
-	return (zfs_prop_table[prop].pd_attr == prop_readonly);
+	return (zfs_prop_table[prop].pd_attr == PROP_READONLY);
 }
 
 /*
@@ -509,96 +599,7 @@
 int
 zfs_prop_inheritable(zfs_prop_t prop)
 {
-	return (zfs_prop_table[prop].pd_attr == prop_inherit);
-}
-
-typedef struct zfs_index {
-	const char *name;
-	uint64_t index;
-} zfs_index_t;
-
-static zfs_index_t checksum_table[] = {
-	{ "on",		ZIO_CHECKSUM_ON },
-	{ "off",	ZIO_CHECKSUM_OFF },
-	{ "fletcher2",	ZIO_CHECKSUM_FLETCHER_2 },
-	{ "fletcher4",	ZIO_CHECKSUM_FLETCHER_4 },
-	{ "sha256",	ZIO_CHECKSUM_SHA256 },
-	{ NULL }
-};
-
-static zfs_index_t compress_table[] = {
-	{ "on",		ZIO_COMPRESS_ON },
-	{ "off",	ZIO_COMPRESS_OFF },
-	{ "lzjb",	ZIO_COMPRESS_LZJB },
-	{ "gzip",	ZIO_COMPRESS_GZIP_6 },	/* the default gzip level */
-	{ "gzip-1",	ZIO_COMPRESS_GZIP_1 },
-	{ "gzip-2",	ZIO_COMPRESS_GZIP_2 },
-	{ "gzip-3",	ZIO_COMPRESS_GZIP_3 },
-	{ "gzip-4",	ZIO_COMPRESS_GZIP_4 },
-	{ "gzip-5",	ZIO_COMPRESS_GZIP_5 },
-	{ "gzip-6",	ZIO_COMPRESS_GZIP_6 },
-	{ "gzip-7",	ZIO_COMPRESS_GZIP_7 },
-	{ "gzip-8",	ZIO_COMPRESS_GZIP_8 },
-	{ "gzip-9",	ZIO_COMPRESS_GZIP_9 },
-	{ NULL }
-};
-
-static zfs_index_t snapdir_table[] = {
-	{ "hidden",	ZFS_SNAPDIR_HIDDEN },
-	{ "visible",	ZFS_SNAPDIR_VISIBLE },
-	{ NULL }
-};
-
-static zfs_index_t acl_mode_table[] = {
-	{ "discard",	ZFS_ACL_DISCARD },
-	{ "groupmask",	ZFS_ACL_GROUPMASK },
-	{ "passthrough", ZFS_ACL_PASSTHROUGH },
-	{ NULL }
-};
-
-static zfs_index_t acl_inherit_table[] = {
-	{ "discard",	ZFS_ACL_DISCARD },
-	{ "noallow",	ZFS_ACL_NOALLOW },
-	{ "secure",	ZFS_ACL_SECURE },
-	{ "passthrough", ZFS_ACL_PASSTHROUGH },
-	{ NULL }
-};
-
-static zfs_index_t copies_table[] = {
-	{ "1",	1 },
-	{ "2",	2 },
-	{ "3",	3 },
-	{ NULL }
-};
-
-static zfs_index_t version_table[] = {
-	{ "1",		1 },
-	{ "2",		2 },
-	{ "current",	ZPL_VERSION },
-	{ NULL }
-};
-
-static zfs_index_t *
-zfs_prop_index_table(zfs_prop_t prop)
-{
-	switch (prop) {
-	case ZFS_PROP_CHECKSUM:
-		return (checksum_table);
-	case ZFS_PROP_COMPRESSION:
-		return (compress_table);
-	case ZFS_PROP_SNAPDIR:
-		return (snapdir_table);
-	case ZFS_PROP_ACLMODE:
-		return (acl_mode_table);
-	case ZFS_PROP_ACLINHERIT:
-		return (acl_inherit_table);
-	case ZFS_PROP_COPIES:
-		return (copies_table);
-	case ZFS_PROP_VERSION:
-		return (version_table);
-	default:
-		return (NULL);
-	}
+	return (zfs_prop_table[prop].pd_attr == PROP_INHERIT);
 }
 
 /*
@@ -608,10 +609,10 @@
 int
 zfs_prop_string_to_index(zfs_prop_t prop, const char *string, uint64_t *index)
 {
-	zfs_index_t *table;
+	const zfs_index_t *table;
 	int i;
 
-	if ((table = zfs_prop_index_table(prop)) == NULL)
+	if ((table = zfs_prop_table[prop].pd_table) == NULL)
 		return (-1);
 
 	for (i = 0; table[i].name != NULL; i++) {
@@ -627,10 +628,10 @@
 int
 zfs_prop_index_to_string(zfs_prop_t prop, uint64_t index, const char **string)
 {
-	zfs_index_t *table;
+	const zfs_index_t *table;
 	int i;
 
-	if ((table = zfs_prop_index_table(prop)) == NULL)
+	if ((table = zfs_prop_table[prop].pd_table) == NULL)
 		return (-1);
 
 	for (i = 0; table[i].name != NULL; i++) {
@@ -679,8 +680,8 @@
 int
 zfs_prop_is_string(zfs_prop_t prop)
 {
-	return (zfs_prop_table[prop].pd_proptype == prop_type_string ||
-	    zfs_prop_table[prop].pd_proptype == prop_type_index);
+	return (zfs_prop_table[prop].pd_proptype == PROP_TYPE_STRING ||
+	    zfs_prop_table[prop].pd_proptype == PROP_TYPE_INDEX);
 }
 
 /*
@@ -711,7 +712,7 @@
 zfs_prop_width(zfs_prop_t prop, boolean_t *fixed)
 {
 	prop_desc_t *pd = &zfs_prop_table[prop];
-	zfs_index_t *idx;
+	const zfs_index_t *idx;
 	size_t ret;
 	int i;
 
@@ -727,7 +728,7 @@
 	 * any possible value.
 	 */
 	switch (pd->pd_proptype) {
-	case prop_type_number:
+	case PROP_TYPE_NUMBER:
 		/*
 		 * The maximum length of a human-readable number is 5 characters
 		 * ("20.4M", for example).
@@ -741,7 +742,7 @@
 		if (prop == ZFS_PROP_CREATION)
 			*fixed = B_FALSE;
 		break;
-	case prop_type_boolean:
+	case PROP_TYPE_BOOLEAN:
 		/*
 		 * The maximum length of a boolean value is 3 characters, for
 		 * "off".
@@ -749,15 +750,15 @@
 		if (ret < 3)
 			ret = 3;
 		break;
-	case prop_type_index:
-		idx = zfs_prop_index_table(prop);
+	case PROP_TYPE_INDEX:
+		idx = zfs_prop_table[prop].pd_table;
 		for (i = 0; idx[i].name != NULL; i++) {
 			if (strlen(idx[i].name) > ret)
 				ret = strlen(idx[i].name);
 		}
 		break;
 
-	case prop_type_string:
+	case PROP_TYPE_STRING:
 		*fixed = B_FALSE;
 		break;
 	}
--- a/usr/src/common/zfs/zfs_prop.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/common/zfs/zfs_prop.h	Thu Aug 02 21:23:46 2007 -0700
@@ -40,15 +40,17 @@
  * in the kernel, but the string value in userland.
  */
 typedef enum {
-	prop_type_number,	/* numeric value */
-	prop_type_string,	/* string value */
-	prop_type_boolean,	/* boolean value */
-	prop_type_index		/* numeric value indexed by string */
+	PROP_TYPE_NUMBER,	/* numeric value */
+	PROP_TYPE_STRING,	/* string value */
+	PROP_TYPE_BOOLEAN,	/* boolean value */
+	PROP_TYPE_INDEX		/* numeric value indexed by string */
 } zfs_proptype_t;
 
 zfs_proptype_t zfs_prop_get_type(zfs_prop_t);
 zfs_proptype_t zpool_prop_get_type(zpool_prop_t);
 size_t zfs_prop_width(zfs_prop_t, boolean_t *);
+boolean_t zfs_prop_delegatable(zfs_prop_t prop);
+void zfs_prop_init(void);
 
 #ifdef	__cplusplus
 }
--- a/usr/src/lib/libzfs/common/libzfs.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/lib/libzfs/common/libzfs.h	Thu Aug 02 21:23:46 2007 -0700
@@ -107,7 +107,6 @@
 	EZFS_BADWHO,		/* invalid permission who */
 	EZFS_BADPERM,		/* invalid permission */
 	EZFS_BADPERMSET,	/* invalid permission set name */
-	EZFS_PERMSET_CIRCULAR,	/* circular dependency on permset */
 	EZFS_NODELEGATION,	/* delegated administration is disabled */
 	EZFS_PERMRDONLY,	/* pemissions are readonly */
 	EZFS_UNKNOWN
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c	Thu Aug 02 21:23:46 2007 -0700
@@ -839,14 +839,14 @@
 		 */
 		strval = NULL;
 		switch (zfs_prop_get_type(prop)) {
-		case prop_type_boolean:
+		case PROP_TYPE_BOOLEAN:
 			if (prop_parse_boolean(hdl, elem, &intval) != 0) {
 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 				goto error;
 			}
 			break;
 
-		case prop_type_string:
+		case PROP_TYPE_STRING:
 			if (nvpair_type(elem) != DATA_TYPE_STRING) {
 				zfs_error_aux(hdl, dgettext(TEXT_DOMAIN,
 				    "'%s' must be a string"),
@@ -863,14 +863,14 @@
 			}
 			break;
 
-		case prop_type_number:
+		case PROP_TYPE_NUMBER:
 			if (prop_parse_number(hdl, elem, prop, &intval) != 0) {
 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 				goto error;
 			}
 			break;
 
-		case prop_type_index:
+		case PROP_TYPE_INDEX:
 			if (prop_parse_index(hdl, elem, prop, &intval) != 0) {
 				(void) zfs_error(hdl, EZFS_BADPROP, errbuf);
 				goto error;
@@ -1312,21 +1312,12 @@
 	nvlist_t *perms_nvp = NULL;
 	nvlist_t *sets_nvp = NULL;
 	char errbuf[1024];
-	char *who_tok;
+	char *who_tok, *perm;
 	int error;
 
 	*nvp = NULL;
 
 	if (perms) {
-		/* Make sure permission string doesn't have an '=' sign in it */
-		if (strchr(perms, '=') != NULL) {
-			(void) snprintf(errbuf, sizeof (errbuf),
-			    dgettext(TEXT_DOMAIN,
-			    "permissions can't contain equal sign : '%s'"),
-			    perms);
-			return (zfs_error(zhp->zfs_hdl, EZFS_BADPERM, errbuf));
-		}
-
 		if ((error = nvlist_alloc(&perms_nvp,
 		    NV_UNIQUE_NAME, 0)) != 0) {
 			return (1);
@@ -1351,6 +1342,12 @@
 		char what;
 
 		if ((error = permset_namecheck(whostr, &why, &what)) != 0) {
+			nvlist_free(who_nvp);
+			if (perms_nvp)
+				nvlist_free(perms_nvp);
+			if (sets_nvp)
+				nvlist_free(sets_nvp);
+
 			switch (why) {
 			case NAME_ERR_NO_AT:
 				zfs_error_aux(zhp->zfs_hdl,
@@ -1368,74 +1365,28 @@
 	 * The first nvlist perms_nvp will have normal permissions and the
 	 * other sets_nvp will have only permssion set names in it.
 	 */
-
-
-	while (perms && *perms != '\0') {
-		char *value;
-		char *perm_name;
-		nvlist_t *update_nvp;
-		int  perm_num;
-		char canonical_name[64];
-		char *canonicalp = canonical_name;
-
-
-		update_nvp = perms_nvp;
-
-		perm_num = getsubopt(&perms, zfs_deleg_perm_tab, &value);
-		if (perm_num == -1) {
-			zfs_prop_t prop;
-
-			prop = zfs_name_to_prop(value);
-			if (prop != ZFS_PROP_INVAL) {
-				(void) snprintf(canonical_name,
-				    sizeof (canonical_name), "%s",
-				    zfs_prop_to_name(prop));
-				perm_num = getsubopt(&canonicalp,
-				    zfs_deleg_perm_tab, &value);
-			}
+	for (perm = strtok(perms, ","); perm; perm = strtok(NULL, ",")) {
+		const char *perm_canonical = zfs_deleg_canonicalize_perm(perm);
+
+		if (perm_canonical) {
+			verify(nvlist_add_boolean(perms_nvp,
+			    perm_canonical) == 0);
+		} else if (perm[0] == '@') {
+			verify(nvlist_add_boolean(sets_nvp, perm) == 0);
+		} else {
+			nvlist_free(who_nvp);
+			nvlist_free(perms_nvp);
+			nvlist_free(sets_nvp);
+			return (zfs_error(zhp->zfs_hdl, EZFS_BADPERM, perm));
 		}
-		if (perm_num != -1) {
-			perm_name = zfs_deleg_perm_tab[perm_num];
-		} else {  /* check and see if permission is a named set */
-			if (value[0] == '@') {
-
-				/*
-				 * make sure permssion set isn't defined
-				 * in terms of itself. ie.
-				 * @set1 = create,destroy,@set1
-				 */
-				if (who_type == ZFS_DELEG_NAMED_SET &&
-				    strcmp(value, whostr) == 0) {
-					nvlist_free(who_nvp);
-					nvlist_free(perms_nvp);
-					if (sets_nvp)
-						nvlist_free(sets_nvp);
-					(void) snprintf(errbuf,
-					    sizeof (errbuf),
-					    dgettext(TEXT_DOMAIN,
-					    "Invalid permission %s"), value);
-					return (zfs_error(zhp->zfs_hdl,
-					    EZFS_PERMSET_CIRCULAR, errbuf));
-				}
-				update_nvp = sets_nvp;
-				perm_name = value;
-			} else {
-				nvlist_free(who_nvp);
-				nvlist_free(perms_nvp);
-				if (sets_nvp)
-					nvlist_free(sets_nvp);
-				return (zfs_error(zhp->zfs_hdl,
-				    EZFS_BADPERM, value));
-			}
-		}
-		verify(nvlist_add_boolean(update_nvp, perm_name) == 0);
 	}
 
 	if (whostr && who_type != ZFS_DELEG_CREATE) {
 		who_tok = strtok(whostr, ",");
 		if (who_tok == NULL) {
 			nvlist_free(who_nvp);
-			nvlist_free(perms_nvp);
+			if (perms_nvp)
+				nvlist_free(perms_nvp);
 			if (sets_nvp)
 				nvlist_free(sets_nvp);
 			(void) snprintf(errbuf, sizeof (errbuf),
@@ -1455,7 +1406,8 @@
 		    &who_id);
 		if (error) {
 			nvlist_free(who_nvp);
-			nvlist_free(perms_nvp);
+			if (perms_nvp)
+				nvlist_free(perms_nvp);
 			if (sets_nvp)
 				nvlist_free(sets_nvp);
 			(void) snprintf(errbuf, sizeof (errbuf),
@@ -1468,7 +1420,6 @@
 		/*
 		 * add entries for both local and descendent when required
 		 */
-
 		zfs_perms_add_who_nvlist(who_nvp, who_id, who_tok,
 		    perms_nvp, sets_nvp, who_type, inherit);
 
@@ -2321,13 +2272,13 @@
 
 	default:
 		switch (zfs_prop_get_type(prop)) {
-		case prop_type_number:
-		case prop_type_boolean:
-		case prop_type_index:
+		case PROP_TYPE_NUMBER:
+		case PROP_TYPE_BOOLEAN:
+		case PROP_TYPE_INDEX:
 			*val = getprop_uint64(zhp, prop, source);
 			break;
 
-		case prop_type_string:
+		case PROP_TYPE_STRING:
 		default:
 			zfs_error_aux(zhp->zfs_hdl, dgettext(TEXT_DOMAIN,
 			    "cannot get non-numeric property"));
@@ -2536,7 +2487,7 @@
 
 	default:
 		switch (zfs_prop_get_type(prop)) {
-		case prop_type_number:
+		case PROP_TYPE_NUMBER:
 			if (get_numeric_property(zhp, prop, src,
 			    &source, &val) != 0)
 				return (-1);
@@ -2547,12 +2498,12 @@
 				zfs_nicenum(val, propbuf, proplen);
 			break;
 
-		case prop_type_string:
+		case PROP_TYPE_STRING:
 			(void) strlcpy(propbuf,
 			    getprop_string(zhp, prop, &source), proplen);
 			break;
 
-		case prop_type_boolean:
+		case PROP_TYPE_BOOLEAN:
 			if (get_numeric_property(zhp, prop, src,
 			    &source, &val) != 0)
 				return (-1);
@@ -2560,7 +2511,7 @@
 
 			break;
 
-		case prop_type_index:
+		case PROP_TYPE_INDEX:
 			val = getprop_uint64(zhp, prop, &source);
 			if (zfs_prop_index_to_string(prop, val,
 			    &strval) != 0)
--- a/usr/src/lib/libzfs/common/libzfs_util.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/lib/libzfs/common/libzfs_util.c	Thu Aug 02 21:23:46 2007 -0700
@@ -44,6 +44,7 @@
 #include <libzfs.h>
 
 #include "libzfs_impl.h"
+#include "zfs_prop.h"
 
 int
 libzfs_errno(libzfs_handle_t *hdl)
@@ -186,9 +187,6 @@
 		return (dgettext(TEXT_DOMAIN, "invalid permission"));
 	case EZFS_BADPERMSET:
 		return (dgettext(TEXT_DOMAIN, "invalid permission set name"));
-	case EZFS_PERMSET_CIRCULAR:
-		return (dgettext(TEXT_DOMAIN,
-		    "Cannot define a permission set in terms of itself"));
 	case EZFS_NODELEGATION:
 		return (dgettext(TEXT_DOMAIN, "delegated administration is "
 		    "disabled on pool"));
@@ -556,6 +554,8 @@
 
 	hdl->libzfs_sharetab = fopen("/etc/dfs/sharetab", "r");
 
+	zfs_prop_init();
+
 	return (hdl);
 }
 
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_main.c	Thu Aug 02 21:23:46 2007 -0700
@@ -176,14 +176,13 @@
 
 	/* Verify that object is Pool, not some other Dataset */
 	if (pool != NULL) {
-	    jclass class = (*env)->FindClass(
-		env, ZFSJNI_PACKAGE_DATA "Pool");
+		jclass class = (*env)->FindClass(
+		    env, ZFSJNI_PACKAGE_DATA "Pool");
 
-	    jboolean is_pool = (*env)->IsInstanceOf(env, pool, class);
+		jboolean is_pool = (*env)->IsInstanceOf(env, pool, class);
 
-	    if (is_pool != JNI_TRUE) {
-		pool = NULL;
-	    }
+		if (is_pool != JNI_TRUE)
+			pool = NULL;
 	}
 
 	return (pool);
@@ -570,7 +569,7 @@
 			map_data.env = env;
 			map_data.type = mappings[i].type;
 			map_data.list = list;
-			(void) zfs_prop_iter(mapping_cb, &map_data, B_FALSE);
+			(void) zfs_prop_iter(mapping_cb, &map_data);
 			break;
 		}
 	}
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c	Thu Aug 02 21:23:46 2007 -0700
@@ -172,21 +172,19 @@
 	jobject propValue = NULL;
 
 	if (convert_str != NULL) {
-	    char propbuf[ZFS_MAXPROPLEN];
-	    int result = zfs_prop_get(zhp, prop, propbuf,
-		sizeof (propbuf), &srctype, source, sizeof (source), 1);
+		char propbuf[ZFS_MAXPROPLEN];
+		int result = zfs_prop_get(zhp, prop, propbuf,
+		    sizeof (propbuf), &srctype, source, sizeof (source), 1);
 
-	    if (result == 0) {
-		propValue = convert_str(env, propbuf);
-	    }
+		if (result == 0)
+			propValue = convert_str(env, propbuf);
 	} else {
-	    uint64_t value;
-	    int result = zfs_prop_get_numeric(
-		zhp, prop, &value, &srctype, source, sizeof (source));
+		uint64_t value;
+		int result = zfs_prop_get_numeric(
+		    zhp, prop, &value, &srctype, source, sizeof (source));
 
-	    if (result == 0) {
-		propValue = convert_uint64(env, value);
-	    }
+		if (result == 0)
+			propValue = convert_uint64(env, value);
 	}
 
 	if (propValue != NULL) {
@@ -267,21 +265,19 @@
 	jobject propValue = NULL;
 
 	if (convert_str != NULL) {
-	    char propbuf[ZFS_MAXPROPLEN];
-	    int result = zfs_prop_get(zhp, prop, propbuf,
-		sizeof (propbuf), &srctype, source, sizeof (source), 1);
+		char propbuf[ZFS_MAXPROPLEN];
+		int result = zfs_prop_get(zhp, prop, propbuf,
+		    sizeof (propbuf), &srctype, source, sizeof (source), 1);
 
-	    if (result == 0) {
-		propValue = convert_str(env, propbuf);
-	    }
+		if (result == 0)
+			propValue = convert_str(env, propbuf);
 	} else {
-	    uint64_t value;
-	    int result = zfs_prop_get_numeric(
-		zhp, prop, &value, &srctype, source, sizeof (source));
+		uint64_t value;
+		int result = zfs_prop_get_numeric(
+		    zhp, prop, &value, &srctype, source, sizeof (source));
 
-	    if (result == 0) {
-		propValue = convert_uint64(env, value);
-	    }
+		if (result == 0)
+			propValue = convert_uint64(env, value);
 	}
 
 	if (propValue != NULL) {
@@ -520,10 +516,12 @@
 
 	for (i = 0; props_custom[i].prop != ZFS_PROP_INVAL; i++) {
 		if (prop == props_custom[i].prop) {
-		    return create_default_ObjectProperty(env,
-			props_custom[i].prop, props_custom[i].convert_str,
-			props_custom[i].convert_uint64,
-			props_custom[i].propClass, props_custom[i].valueClass);
+			return create_default_ObjectProperty(env,
+			    props_custom[i].prop,
+			    props_custom[i].convert_str,
+			    props_custom[i].convert_uint64,
+			    props_custom[i].propClass,
+			    props_custom[i].valueClass);
 		}
 	}
 
@@ -546,8 +544,7 @@
 {
 	zfs_prop_t prop;
 
-	prop = zfs_prop_iter(zjni_get_property_from_name_cb, (void *)name,
-	    B_FALSE);
+	prop = zfs_prop_iter(zjni_get_property_from_name_cb, (void *)name);
 	return (prop == ZFS_PROP_CONT ? ZFS_PROP_INVAL : prop);
 }
 
--- a/usr/src/uts/common/Makefile.files	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/Makefile.files	Thu Aug 02 21:23:46 2007 -0700
@@ -940,6 +940,7 @@
 	lzjb.o			\
 	metaslab.o		\
 	refcount.o		\
+	rprwlock.o		\
 	sha256.o		\
 	spa.o			\
 	spa_config.o		\
--- a/usr/src/uts/common/fs/zfs/dmu_objset.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dmu_objset.c	Thu Aug 02 21:23:46 2007 -0700
@@ -149,9 +149,11 @@
 dmu_objset_open_impl(spa_t *spa, dsl_dataset_t *ds, blkptr_t *bp,
     objset_impl_t **osip)
 {
-	objset_impl_t *winner, *osi;
+	objset_impl_t *osi;
 	int i, err, checksum;
 
+	ASSERT(ds == NULL || MUTEX_HELD(&ds->ds_opening_lock));
+
 	osi = kmem_zalloc(sizeof (objset_impl_t), KM_SLEEP);
 	osi->os.os = osi;
 	osi->os_dsl_dataset = ds;
@@ -245,12 +247,13 @@
 	osi->os_meta_dnode = dnode_special_open(osi,
 	    &osi->os_phys->os_meta_dnode, DMU_META_DNODE_OBJECT);
 
-	if (ds != NULL) {
-		winner = dsl_dataset_set_user_ptr(ds, osi, dmu_objset_evict);
-		if (winner) {
-			dmu_objset_evict(ds, osi);
-			osi = winner;
-		}
+	/*
+	 * We should be the only thread trying to do this because we
+	 * have ds_opening_lock
+	 */
+	if (ds) {
+		VERIFY(NULL == dsl_dataset_set_user_ptr(ds, osi,
+		    dmu_objset_evict));
 	}
 
 	*osip = osi;
@@ -274,6 +277,7 @@
 		return (err);
 	}
 
+	mutex_enter(&ds->ds_opening_lock);
 	osi = dsl_dataset_get_user_ptr(ds);
 	if (osi == NULL) {
 		err = dmu_objset_open_impl(dsl_dataset_get_spa(ds),
@@ -284,6 +288,7 @@
 			return (err);
 		}
 	}
+	mutex_exit(&ds->ds_opening_lock);
 
 	os->os = osi;
 	os->os_mode = mode;
@@ -304,7 +309,7 @@
 }
 
 int
-dmu_objset_evict_dbufs(objset_t *os, int try)
+dmu_objset_evict_dbufs(objset_t *os, boolean_t try)
 {
 	objset_impl_t *osi = os->os;
 	dnode_t *dn;
@@ -402,7 +407,11 @@
 	dnode_t *mdn;
 
 	ASSERT(dmu_tx_is_syncing(tx));
+	if (ds)
+		mutex_enter(&ds->ds_opening_lock);
 	VERIFY(0 == dmu_objset_open_impl(spa, ds, bp, &osi));
+	if (ds)
+		mutex_exit(&ds->ds_opening_lock);
 	mdn = osi->os_meta_dnode;
 
 	dnode_allocate(mdn, DMU_OT_DNODE, 1 << DNODE_BLOCK_SHIFT,
@@ -802,9 +811,10 @@
 	zb.zb_object = 0;
 	zb.zb_level = -1;
 	zb.zb_blkid = 0;
-	if (BP_IS_OLDER(os->os_rootbp, tx->tx_txg))
+	if (BP_IS_OLDER(os->os_rootbp, tx->tx_txg)) {
 		dsl_dataset_block_kill(os->os_dsl_dataset,
 		    os->os_rootbp, pio, tx);
+	}
 	zio = arc_write(pio, os->os_spa, os->os_md_checksum,
 	    os->os_md_compress,
 	    dmu_get_replication_level(os, &zb, DMU_OT_OBJSET),
--- a/usr/src/uts/common/fs/zfs/dnode_sync.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dnode_sync.c	Thu Aug 02 21:23:46 2007 -0700
@@ -350,7 +350,7 @@
  * Try to kick all the dnodes dbufs out of the cache...
  */
 int
-dnode_evict_dbufs(dnode_t *dn, int try)
+dnode_evict_dbufs(dnode_t *dn, boolean_t try)
 {
 	int progress;
 	int pass = 0;
--- a/usr/src/uts/common/fs/zfs/dsl_dataset.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dsl_dataset.c	Thu Aug 02 21:23:46 2007 -0700
@@ -218,7 +218,6 @@
 dsl_dataset_evict(dmu_buf_t *db, void *dsv)
 {
 	dsl_dataset_t *ds = dsv;
-	dsl_pool_t *dp = ds->ds_dir->dd_pool;
 
 	/* open_refcount == DS_REF_MAX when deleting */
 	ASSERT(ds->ds_open_refcount == 0 ||
@@ -226,7 +225,7 @@
 
 	dprintf_ds(ds, "evicting %s\n", "");
 
-	unique_remove(ds->ds_phys->ds_fsid_guid);
+	unique_remove(ds->ds_fsid_guid);
 
 	if (ds->ds_user_ptr != NULL)
 		ds->ds_user_evict_func(ds, ds->ds_user_ptr);
@@ -239,10 +238,10 @@
 	bplist_close(&ds->ds_deadlist);
 	dsl_dir_close(ds->ds_dir, ds);
 
-	if (list_link_active(&ds->ds_synced_link))
-		list_remove(&dp->dp_synced_objsets, ds);
+	ASSERT(!list_link_active(&ds->ds_synced_link));
 
 	mutex_destroy(&ds->ds_lock);
+	mutex_destroy(&ds->ds_opening_lock);
 	mutex_destroy(&ds->ds_deadlist.bpl_lock);
 
 	kmem_free(ds, sizeof (dsl_dataset_t));
@@ -299,6 +298,7 @@
 		ds->ds_phys = dbuf->db_data;
 
 		mutex_init(&ds->ds_lock, NULL, MUTEX_DEFAULT, NULL);
+		mutex_init(&ds->ds_opening_lock, NULL, MUTEX_DEFAULT, NULL);
 		mutex_init(&ds->ds_deadlist.bpl_lock, NULL, MUTEX_DEFAULT,
 		    NULL);
 
@@ -314,6 +314,7 @@
 			 * just opened it.
 			 */
 			mutex_destroy(&ds->ds_lock);
+			mutex_destroy(&ds->ds_opening_lock);
 			mutex_destroy(&ds->ds_deadlist.bpl_lock);
 			kmem_free(ds, sizeof (dsl_dataset_t));
 			dmu_buf_rele(dbuf, tag);
@@ -364,6 +365,7 @@
 			}
 			dsl_dir_close(ds->ds_dir, ds);
 			mutex_destroy(&ds->ds_lock);
+			mutex_destroy(&ds->ds_opening_lock);
 			mutex_destroy(&ds->ds_deadlist.bpl_lock);
 			kmem_free(ds, sizeof (dsl_dataset_t));
 			if (err) {
@@ -372,12 +374,8 @@
 			}
 			ds = winner;
 		} else {
-			uint64_t new =
+			ds->ds_fsid_guid =
 			    unique_insert(ds->ds_phys->ds_fsid_guid);
-			if (new != ds->ds_phys->ds_fsid_guid) {
-				/* XXX it won't necessarily be synced... */
-				ds->ds_phys->ds_fsid_guid = new;
-			}
 		}
 	}
 	ASSERT3P(ds->ds_dbuf, ==, dbuf);
@@ -554,7 +552,6 @@
 	dsphys = dbuf->db_data;
 	dsphys->ds_dir_obj = dd->dd_object;
 	dsphys->ds_fsid_guid = unique_create();
-	unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
 	(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
 	    sizeof (dsphys->ds_guid));
 	dsphys->ds_snapnames_zapobj =
@@ -603,7 +600,6 @@
 	dsphys = dbuf->db_data;
 	dsphys->ds_dir_obj = dd->dd_object;
 	dsphys->ds_fsid_guid = unique_create();
-	unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
 	(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
 	    sizeof (dsphys->ds_guid));
 	dsphys->ds_snapnames_zapobj =
@@ -1390,7 +1386,6 @@
 	dsphys = dbuf->db_data;
 	dsphys->ds_dir_obj = ds->ds_dir->dd_object;
 	dsphys->ds_fsid_guid = unique_create();
-	unique_remove(dsphys->ds_fsid_guid); /* it isn't open yet */
 	(void) random_get_pseudo_bytes((void*)&dsphys->ds_guid,
 	    sizeof (dsphys->ds_guid));
 	dsphys->ds_prev_snap_obj = ds->ds_phys->ds_prev_snap_obj;
@@ -1453,9 +1448,15 @@
 	ASSERT(ds->ds_user_ptr != NULL);
 	ASSERT(ds->ds_phys->ds_next_snap_obj == 0);
 
+	/*
+	 * in case we had to change ds_fsid_guid when we opened it,
+	 * sync it out now.
+	 */
+	dmu_buf_will_dirty(ds->ds_dbuf, tx);
+	ds->ds_phys->ds_fsid_guid = ds->ds_fsid_guid;
+
 	dsl_dir_dirty(ds->ds_dir, tx);
 	dmu_objset_sync(ds->ds_user_ptr, zio, tx);
-	/* Unneeded? bplist_close(&ds->ds_deadlist); */
 }
 
 void
@@ -1511,7 +1512,7 @@
 uint64_t
 dsl_dataset_fsid_guid(dsl_dataset_t *ds)
 {
-	return (ds->ds_phys->ds_fsid_guid);
+	return (ds->ds_fsid_guid);
 }
 
 void
--- a/usr/src/uts/common/fs/zfs/dsl_deleg.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dsl_deleg.c	Thu Aug 02 21:23:46 2007 -0700
@@ -89,17 +89,16 @@
 /*
  * Validate that user is allowed to delegate specified permissions.
  *
- * In order to delegate "create" you must have create"
+ * In order to delegate "create" you must have "create"
  * and "allow".
  */
 int
 dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr)
 {
 	nvpair_t *whopair = NULL;
-	int error = 0;
+	int error;
 
-	if ((error = dsl_deleg_access(ddname,
-	    ZFS_DELEG_PERM_ALLOW, cr)) != 0)
+	if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
 		return (error);
 
 	while (whopair = nvlist_next_nvpair(nvp, whopair)) {
@@ -114,12 +113,11 @@
 			if (strcmp(perm, ZFS_DELEG_PERM_ALLOW) == 0)
 				return (EPERM);
 
-			if ((error = dsl_deleg_access(ddname,
-			    perm, cr)) != 0)
+			if ((error = dsl_deleg_access(ddname, perm, cr)) != 0)
 				return (error);
 		}
 	}
-	return (error);
+	return (0);
 }
 
 /*
@@ -132,25 +130,23 @@
 {
 	nvpair_t *whopair = NULL;
 	int error;
+	char idstr[32];
 
-	if ((error = dsl_deleg_access(ddname,
-	    ZFS_DELEG_PERM_ALLOW, cr)) != 0)
+	if ((error = dsl_deleg_access(ddname, ZFS_DELEG_PERM_ALLOW, cr)) != 0)
 		return (error);
 
+	(void) snprintf(idstr, sizeof (idstr), "%lld",
+	    (longlong_t)crgetuid(cr));
+
 	while (whopair = nvlist_next_nvpair(nvp, whopair)) {
 		zfs_deleg_who_type_t type = nvpair_name(whopair)[0];
-		char idstr[32];
 
 		if (type != ZFS_DELEG_USER &&
 		    type != ZFS_DELEG_USER_SETS)
 			return (EPERM);
 
-		(void) snprintf(idstr, sizeof (idstr), "%lld",
-		    (longlong_t)crgetuid(cr));
 		if (strcmp(idstr, &nvpair_name(whopair)[3]) != 0)
 			return (EPERM);
-
-		continue;
 	}
 	return (0);
 }
@@ -184,6 +180,7 @@
 		uint64_t jumpobj;
 
 		if (nvpair_value_nvlist(whopair, &perms) != 0) {
+			ASSERT(pa->p_unset);
 			if (zap_lookup(mos, zapobj, whokey, 8,
 			    1, &jumpobj) == 0) {
 				(void) zap_remove(mos, zapobj, whokey, tx);
@@ -201,7 +198,7 @@
 			 * If object doesn't exist and we are removing
 			 * it, then just continue to next item in nvlist
 			 */
-			if (pa->p_unset == 1)
+			if (pa->p_unset)
 				continue;
 			jumpobj = zap_create(mos, DMU_OT_DSL_PERMS,
 			    DMU_OT_NONE, 0, tx);
@@ -359,8 +356,8 @@
  */
 typedef struct perm_set {
 	avl_node_t	p_node;
+	boolean_t	p_matched;
 	char		p_setname[ZFS_MAX_DELEG_NAME];
-	boolean_t	p_matched;
 } perm_set_t;
 
 static int
@@ -408,7 +405,7 @@
  * check a specified user/group for a requested permission
  */
 static int
-dsl_check_user_access(objset_t *os, uint64_t zapobj, const char *perm,
+dsl_check_user_access(objset_t *mos, uint64_t zapobj, const char *perm,
     int checkflag, cred_t *cr)
 {
 	const	gid_t *gids;
@@ -418,19 +415,19 @@
 
 	/* check for user */
 	id = crgetuid(cr);
-	if (dsl_check_access(os, zapobj,
+	if (dsl_check_access(mos, zapobj,
 	    ZFS_DELEG_USER, checkflag, &id, perm) == 0)
 		return (0);
 
 	/* check for users primary group */
 	id = crgetgid(cr);
-	if (dsl_check_access(os, zapobj,
+	if (dsl_check_access(mos, zapobj,
 	    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
 		return (0);
 
 	/* check for everyone entry */
 	id = -1;
-	if (dsl_check_access(os, zapobj,
+	if (dsl_check_access(mos, zapobj,
 	    ZFS_DELEG_EVERYONE, checkflag, &id, perm) == 0)
 		return (0);
 
@@ -439,7 +436,7 @@
 	gids = crgetgroups(cr);
 	for (i = 0; i != ngids; i++) {
 		id = gids[i];
-		if (dsl_check_access(os, zapobj,
+		if (dsl_check_access(mos, zapobj,
 		    ZFS_DELEG_GROUP, checkflag, &id, perm) == 0)
 			return (0);
 	}
@@ -581,11 +578,6 @@
 			    zfs_prop_to_name(ZFS_PROP_ZONED),
 			    8, 1, &zoned, NULL) != 0)
 				break;
-
-			/*
-			 * if zoned property isn't set then break
-			 * out and return EPERM.
-			 */
 			if (!zoned)
 				break;
 		}
@@ -595,12 +587,10 @@
 			continue;
 
 		dsl_load_user_sets(mos, zapobj, &permsets, checkflag, cr);
-		setnode = avl_first(&permsets);
 again:
 		expanded = B_FALSE;
 		for (setnode = avl_first(&permsets); setnode;
 		    setnode = AVL_NEXT(&permsets, setnode)) {
-
 			if (setnode->p_matched == B_TRUE)
 				continue;
 
@@ -636,10 +626,8 @@
 	dsl_dir_close(startdd, FTAG);
 
 	cookie = NULL;
-	while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL) {
-		/* These sets were used but never defined! */
+	while ((setnode = avl_destroy_nodes(&permsets, &cookie)) != NULL)
 		kmem_free(setnode, sizeof (perm_set_t));
-	}
 
 	return (error);
 }
@@ -649,12 +637,11 @@
  */
 
 static void
-copy_create_perms(objset_t *mos, uint64_t pzapobj, dsl_dir_t *dd,
+copy_create_perms(dsl_dir_t *dd, uint64_t pzapobj,
     boolean_t dosets, uint64_t uid, dmu_tx_t *tx)
 {
-	int error;
+	objset_t *mos = dd->dd_pool->dp_meta_objset;
 	uint64_t jumpobj, pjumpobj;
-	uint64_t zero = 0;
 	uint64_t zapobj = dd->dd_phys->dd_deleg_zapobj;
 	zap_cursor_t zc;
 	zap_attribute_t za;
@@ -663,20 +650,18 @@
 	zfs_deleg_whokey(whokey,
 	    dosets ? ZFS_DELEG_CREATE_SETS : ZFS_DELEG_CREATE,
 	    ZFS_DELEG_LOCAL, NULL);
-	error = zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj);
-	if (error != 0)
+	if (zap_lookup(mos, pzapobj, whokey, 8, 1, &pjumpobj) != 0)
 		return;
 
-	zfs_deleg_whokey(whokey,
-	    dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
-	    ZFS_DELEG_LOCAL, &uid);
-
 	if (zapobj == 0) {
 		dmu_buf_will_dirty(dd->dd_dbuf, tx);
 		zapobj = dd->dd_phys->dd_deleg_zapobj = zap_create(mos,
 		    DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
 	}
 
+	zfs_deleg_whokey(whokey,
+	    dosets ? ZFS_DELEG_USER_SETS : ZFS_DELEG_USER,
+	    ZFS_DELEG_LOCAL, &uid);
 	if (zap_lookup(mos, zapobj, whokey, 8, 1, &jumpobj) == ENOENT) {
 		jumpobj = zap_create(mos, DMU_OT_DSL_PERMS, DMU_OT_NONE, 0, tx);
 		VERIFY(zap_add(mos, zapobj, whokey, 8, 1, &jumpobj, tx) == 0);
@@ -685,6 +670,7 @@
 	for (zap_cursor_init(&zc, mos, pjumpobj);
 	    zap_cursor_retrieve(&zc, &za) == 0;
 	    zap_cursor_advance(&zc)) {
+		uint64_t zero = 0;
 		ASSERT(za.za_integer_length == 8 && za.za_num_integers == 1);
 
 		VERIFY(zap_update(mos, jumpobj, za.za_name,
@@ -700,20 +686,20 @@
 dsl_deleg_set_create_perms(dsl_dir_t *sdd, dmu_tx_t *tx, cred_t *cr)
 {
 	dsl_dir_t *dd;
-	objset_t *mos = sdd->dd_pool->dp_meta_objset;
+	uint64_t uid = crgetuid(cr);
 
 	if (spa_version(dmu_objset_spa(sdd->dd_pool->dp_meta_objset)) <
 	    ZFS_VERSION_DELEGATED_PERMS)
 		return;
 
 	for (dd = sdd->dd_parent; dd != NULL; dd = dd->dd_parent) {
-		uint64_t pobj = dd->dd_phys->dd_deleg_zapobj;
+		uint64_t pzapobj = dd->dd_phys->dd_deleg_zapobj;
 
-		if (pobj == 0)
+		if (pzapobj == 0)
 			continue;
 
-		copy_create_perms(mos, pobj, sdd, B_FALSE, crgetuid(cr), tx);
-		copy_create_perms(mos, pobj, sdd, B_TRUE, crgetuid(cr), tx);
+		copy_create_perms(sdd, pzapobj, B_FALSE, uid, tx);
+		copy_create_perms(sdd, pzapobj, B_TRUE, uid, tx);
 	}
 }
 
--- a/usr/src/uts/common/fs/zfs/dsl_prop.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/dsl_prop.c	Thu Aug 02 21:23:46 2007 -0700
@@ -48,7 +48,7 @@
 	    zfs_prop_readonly(prop))
 		return (ENOENT);
 
-	if (zfs_prop_get_type(prop) == prop_type_string) {
+	if (zfs_prop_get_type(prop) == PROP_TYPE_STRING) {
 		if (intsz != 1)
 			return (EOVERFLOW);
 		(void) strncpy(buf, zfs_prop_default_string(prop), numint);
--- a/usr/src/uts/common/fs/zfs/refcount.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/refcount.c	Thu Aug 02 21:23:46 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -61,11 +60,13 @@
 void
 refcount_create(refcount_t *rc)
 {
+	mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL);
 	list_create(&rc->rc_list, sizeof (reference_t),
 	    offsetof(reference_t, ref_link));
 	list_create(&rc->rc_removed, sizeof (reference_t),
 	    offsetof(reference_t, ref_link));
-	mutex_init(&rc->rc_mtx, NULL, MUTEX_DEFAULT, NULL);
+	rc->rc_count = 0;
+	rc->rc_removed_count = 0;
 }
 
 void
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/zfs/rprwlock.c	Thu Aug 02 21:23:46 2007 -0700
@@ -0,0 +1,118 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/zfs_context.h>
+#include <sys/refcount.h>
+#include <sys/rprwlock.h>
+
+void
+rprw_init(rprwlock_t *rwl)
+{
+	mutex_init(&rwl->rw_lock, NULL, MUTEX_DEFAULT, NULL);
+	rwl->rw_writer = NULL;
+	cv_init(&rwl->rw_cv, NULL, CV_DEFAULT, NULL);
+	refcount_create(&rwl->rw_count);
+}
+
+void
+rprw_destroy(rprwlock_t *rwl)
+{
+	mutex_destroy(&rwl->rw_lock);
+	ASSERT(rwl->rw_writer == NULL);
+	cv_destroy(&rwl->rw_cv);
+	refcount_destroy(&rwl->rw_count);
+}
+
+void
+rprw_enter_read(rprwlock_t *rwl, void *tag)
+{
+	mutex_enter(&rwl->rw_lock);
+
+	if (rwl->rw_writer != curthread) {
+		while (rwl->rw_writer != NULL)
+			cv_wait(&rwl->rw_cv, &rwl->rw_lock);
+	}
+
+	(void) refcount_add(&rwl->rw_count, tag);
+
+	mutex_exit(&rwl->rw_lock);
+}
+
+void
+rprw_enter_write(rprwlock_t *rwl, void *tag)
+{
+	mutex_enter(&rwl->rw_lock);
+
+	if (rwl->rw_writer != curthread) {
+		while (!refcount_is_zero(&rwl->rw_count))
+			cv_wait(&rwl->rw_cv, &rwl->rw_lock);
+		rwl->rw_writer = curthread;
+	}
+
+	(void) refcount_add(&rwl->rw_count, tag);
+
+	mutex_exit(&rwl->rw_lock);
+}
+
+void
+rprw_enter(rprwlock_t *rwl, krw_t rw, void *tag)
+{
+	if (rw == RW_READER)
+		rprw_enter_read(rwl, tag);
+	else
+		rprw_enter_write(rwl, tag);
+}
+
+void
+rprw_exit(rprwlock_t *rwl, void *tag)
+{
+	mutex_enter(&rwl->rw_lock);
+
+	ASSERT(!refcount_is_zero(&rwl->rw_count));
+	ASSERT(rwl->rw_writer == NULL || curthread == rwl->rw_writer);
+	if (refcount_remove(&rwl->rw_count, tag) == 0) {
+		cv_broadcast(&rwl->rw_cv);
+		rwl->rw_writer = NULL;  /* OK in either case */
+	}
+
+	mutex_exit(&rwl->rw_lock);
+}
+
+boolean_t
+rprw_held(rprwlock_t *rwl, krw_t rw)
+{
+	boolean_t held;
+
+	mutex_enter(&rwl->rw_lock);
+	if (rw == RW_WRITER)
+		held = (rwl->rw_writer == curthread);
+	else
+		held = !rwl->rw_writer && !refcount_is_zero(&rwl->rw_count);
+	mutex_exit(&rwl->rw_lock);
+
+	return (held);
+}
--- a/usr/src/uts/common/fs/zfs/spa.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/spa.c	Thu Aug 02 21:23:46 2007 -0700
@@ -132,12 +132,13 @@
 
 	rw_init(&spa->spa_traverse_lock, NULL, RW_DEFAULT, NULL);
 
+	rprw_init(&spa->spa_config_lock);
+
 	mutex_init(&spa->spa_async_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&spa->spa_config_cache_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&spa->spa_scrub_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&spa->spa_errlog_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&spa->spa_errlist_lock, NULL, MUTEX_DEFAULT, NULL);
-	mutex_init(&spa->spa_config_lock.scl_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&spa->spa_sync_bplist.bpl_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&spa->spa_history_lock, NULL, MUTEX_DEFAULT, NULL);
 	mutex_init(&spa->spa_props_lock, NULL, MUTEX_DEFAULT, NULL);
--- a/usr/src/uts/common/fs/zfs/spa_config.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/spa_config.c	Thu Aug 02 21:23:46 2007 -0700
@@ -270,7 +270,8 @@
 	vdev_t *rvd = spa->spa_root_vdev;
 	unsigned long hostid = 0;
 
-	ASSERT(spa_config_held(spa, RW_READER));
+	ASSERT(spa_config_held(spa, RW_READER) ||
+	    spa_config_held(spa, RW_WRITER));
 
 	if (vd == NULL)
 		vd = rvd;
--- a/usr/src/uts/common/fs/zfs/spa_misc.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/spa_misc.c	Thu Aug 02 21:23:46 2007 -0700
@@ -45,6 +45,7 @@
 #include <sys/dsl_prop.h>
 #include <sys/fs/zfs.h>
 #include <sys/metaslab_impl.h>
+#include "zfs_prop.h"
 
 /*
  * SPA locking
@@ -76,11 +77,10 @@
  *	some references in the DMU.  Internally we check against SPA_MINREF, but
  *	present the image of a zero/non-zero value to consumers.
  *
- * spa_config_lock (per-spa crazy rwlock)
+ * spa_config_lock (per-spa read-priority rwlock)
  *
- *	This SPA special is a recursive rwlock, capable of being acquired from
- *	asynchronous threads.  It has protects the spa_t from config changes,
- *	and must be held in the following circumstances:
+ *	This protects the spa_t from config changes, and must be held in
+ *	the following circumstances:
  *
  *		- RW_READER to perform I/O to the spa
  *		- RW_WRITER to change the vdev config
@@ -257,7 +257,7 @@
 	spa->spa_final_txg = UINT64_MAX;
 
 	refcount_create(&spa->spa_refcount);
-	refcount_create(&spa->spa_config_lock.scl_count);
+	rprw_init(&spa->spa_config_lock);
 
 	avl_add(&spa_namespace_avl, spa);
 
@@ -298,10 +298,10 @@
 	spa_config_set(spa, NULL);
 
 	refcount_destroy(&spa->spa_refcount);
-	refcount_destroy(&spa->spa_config_lock.scl_count);
+
+	rprw_destroy(&spa->spa_config_lock);
 
 	mutex_destroy(&spa->spa_sync_bplist.bpl_lock);
-	mutex_destroy(&spa->spa_config_lock.scl_lock);
 	mutex_destroy(&spa->spa_errlist_lock);
 	mutex_destroy(&spa->spa_errlog_lock);
 	mutex_destroy(&spa->spa_scrub_lock);
@@ -518,79 +518,22 @@
  * SPA config locking
  * ==========================================================================
  */
-
-/*
- * Acquire the config lock.  The config lock is a special rwlock that allows for
- * recursive enters.  Because these enters come from the same thread as well as
- * asynchronous threads working on behalf of the owner, we must unilaterally
- * allow all reads access as long at least one reader is held (even if a write
- * is requested).  This has the side effect of write starvation, but write locks
- * are extremely rare, and a solution to this problem would be significantly
- * more complex (if even possible).
- *
- * We would like to assert that the namespace lock isn't held, but this is a
- * valid use during create.
- */
 void
 spa_config_enter(spa_t *spa, krw_t rw, void *tag)
 {
-	spa_config_lock_t *scl = &spa->spa_config_lock;
-
-	mutex_enter(&scl->scl_lock);
-
-	if (scl->scl_writer != curthread) {
-		if (rw == RW_READER) {
-			while (scl->scl_writer != NULL)
-				cv_wait(&scl->scl_cv, &scl->scl_lock);
-		} else {
-			while (scl->scl_writer != NULL ||
-			    !refcount_is_zero(&scl->scl_count))
-				cv_wait(&scl->scl_cv, &scl->scl_lock);
-			scl->scl_writer = curthread;
-		}
-	}
-
-	(void) refcount_add(&scl->scl_count, tag);
-
-	mutex_exit(&scl->scl_lock);
+	rprw_enter(&spa->spa_config_lock, rw, tag);
 }
 
-/*
- * Release the spa config lock, notifying any waiters in the process.
- */
 void
 spa_config_exit(spa_t *spa, void *tag)
 {
-	spa_config_lock_t *scl = &spa->spa_config_lock;
-
-	mutex_enter(&scl->scl_lock);
-
-	ASSERT(!refcount_is_zero(&scl->scl_count));
-	if (refcount_remove(&scl->scl_count, tag) == 0) {
-		cv_broadcast(&scl->scl_cv);
-		scl->scl_writer = NULL;  /* OK in either case */
-	}
-
-	mutex_exit(&scl->scl_lock);
+	rprw_exit(&spa->spa_config_lock, tag);
 }
 
-/*
- * Returns true if the config lock is held in the given manner.
- */
 boolean_t
 spa_config_held(spa_t *spa, krw_t rw)
 {
-	spa_config_lock_t *scl = &spa->spa_config_lock;
-	boolean_t held;
-
-	mutex_enter(&scl->scl_lock);
-	if (rw == RW_WRITER)
-		held = (scl->scl_writer == curthread);
-	else
-		held = !refcount_is_zero(&scl->scl_count);
-	mutex_exit(&scl->scl_lock);
-
-	return (held);
+	return (rprw_held(&spa->spa_config_lock, rw));
 }
 
 /*
@@ -1105,6 +1048,7 @@
 	zio_init();
 	dmu_init();
 	zil_init();
+	zfs_prop_init();
 	spa_config_load();
 }
 
@@ -1116,6 +1060,7 @@
 	zil_fini();
 	dmu_fini();
 	zio_fini();
+	unique_fini();
 	refcount_fini();
 
 	avl_destroy(&spa_namespace_avl);
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h	Thu Aug 02 21:23:46 2007 -0700
@@ -157,7 +157,7 @@
 int dmu_objset_open(const char *name, dmu_objset_type_t type, int mode,
     objset_t **osp);
 void dmu_objset_close(objset_t *os);
-int dmu_objset_evict_dbufs(objset_t *os, int try);
+int dmu_objset_evict_dbufs(objset_t *os, boolean_t try);
 int dmu_objset_create(const char *name, dmu_objset_type_t type,
     objset_t *clone_parent,
     void (*func)(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx), void *arg);
--- a/usr/src/uts/common/fs/zfs/sys/dmu_objset.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dmu_objset.h	Thu Aug 02 21:23:46 2007 -0700
@@ -108,7 +108,7 @@
 int dmu_objset_find(char *name, int func(char *, void *), void *arg,
     int flags);
 void dmu_objset_byteswap(void *buf, size_t size);
-int dmu_objset_evict_dbufs(objset_t *os, int try);
+int dmu_objset_evict_dbufs(objset_t *os, boolean_t try);
 
 /* called from dsl */
 void dmu_objset_sync(objset_impl_t *os, zio_t *zio, dmu_tx_t *tx);
--- a/usr/src/uts/common/fs/zfs/sys/dnode.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dnode.h	Thu Aug 02 21:23:46 2007 -0700
@@ -226,7 +226,7 @@
 void dnode_fini(void);
 int dnode_next_offset(dnode_t *dn, boolean_t hole, uint64_t *off, int minlvl,
     uint64_t blkfill, uint64_t txg);
-int dnode_evict_dbufs(dnode_t *dn, int try);
+int dnode_evict_dbufs(dnode_t *dn, boolean_t try);
 
 #ifdef ZFS_DEBUG
 
--- a/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_dataset.h	Thu Aug 02 21:23:46 2007 -0700
@@ -87,6 +87,7 @@
 	dsl_dataset_phys_t *ds_phys;
 	dmu_buf_t *ds_dbuf;
 	uint64_t ds_object;
+	uint64_t ds_fsid_guid;
 
 	/* only used in syncing context: */
 	struct dsl_dataset *ds_prev; /* only valid for non-snapshots */
@@ -110,6 +111,9 @@
 	/* no locking; only for making guesses */
 	uint64_t ds_trysnap_txg;
 
+	/* for objset_open() */
+	kmutex_t ds_opening_lock;
+
 	/* Protected by ds_lock; keep at end of struct for better locality */
 	char ds_snapname[MAXNAMELEN];
 } dsl_dataset_t;
--- a/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_deleg.h	Thu Aug 02 21:23:46 2007 -0700
@@ -23,8 +23,8 @@
  * Use is subject to license terms.
  */
 
-#ifndef	_SYS_DSL_PERMS_H
-#define	_SYS_DSL_PERMS_H
+#ifndef	_SYS_DSL_DELEG_H
+#define	_SYS_DSL_DELEG_H
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
@@ -48,30 +48,13 @@
 #define	ZFS_DELEG_PERM_SHARE		"share"
 #define	ZFS_DELEG_PERM_SEND		"send"
 #define	ZFS_DELEG_PERM_RECEIVE		"receive"
-#define	ZFS_DELEG_PERM_QUOTA		"quota"
-#define	ZFS_DELEG_PERM_RESERVATION	"reservation"
-#define	ZFS_DELEG_PERM_VOLSIZE		"volsize"
-#define	ZFS_DELEG_PERM_RECORDSIZE	"recordsize"
-#define	ZFS_DELEG_PERM_MOUNTPOINT	"mountpoint"
-#define	ZFS_DELEG_PERM_SHARENFS		"sharenfs"
-#define	ZFS_DELEG_PERM_CHECKSUM		"checksum"
-#define	ZFS_DELEG_PERM_COMPRESSION	"compression"
-#define	ZFS_DELEG_PERM_ATIME		"atime"
-#define	ZFS_DELEG_PERM_DEVICES		"devices"
-#define	ZFS_DELEG_PERM_EXEC		"exec"
-#define	ZFS_DELEG_PERM_SETUID		"setuid"
-#define	ZFS_DELEG_PERM_READONLY		"readonly"
-#define	ZFS_DELEG_PERM_ZONED		"zoned"
-#define	ZFS_DELEG_PERM_SNAPDIR		"snapdir"
-#define	ZFS_DELEG_PERM_ACLMODE		"aclmode"
-#define	ZFS_DELEG_PERM_ACLINHERIT	"aclinherit"
 #define	ZFS_DELEG_PERM_ALLOW		"allow"
-#define	ZFS_DELEG_PERM_CANMOUNT		"canmount"
 #define	ZFS_DELEG_PERM_USERPROP		"userprop"
-#define	ZFS_DELEG_PERM_SHAREISCSI	"shareiscsi"
-#define	ZFS_DELEG_PERM_XATTR		"xattr"
-#define	ZFS_DELEG_PERM_COPIES		"copies"
-#define	ZFS_DELEG_PERM_VERSION		"version"
+
+/*
+ * Note: the names of properties that are marked delegatable are also
+ * valid delegated permissions
+ */
 
 int dsl_deleg_get(const char *ddname, nvlist_t **nvp);
 int dsl_deleg_set(const char *ddname, nvlist_t *nvp, boolean_t unset);
@@ -80,10 +63,10 @@
 int dsl_deleg_can_allow(char *ddname, nvlist_t *nvp, cred_t *cr);
 int dsl_deleg_can_unallow(char *ddname, nvlist_t *nvp, cred_t *cr);
 int dsl_deleg_destroy(objset_t *os, uint64_t zapobj, dmu_tx_t *tx);
-boolean_t dsl_delegation_on(objset_t  *os);
+boolean_t dsl_delegation_on(objset_t *os);
 
 #ifdef	__cplusplus
 }
 #endif
 
-#endif	/* _SYS_DSL_PERMS_H */
+#endif	/* _SYS_DSL_DELEG_H */
--- a/usr/src/uts/common/fs/zfs/sys/refcount.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/refcount.h	Thu Aug 02 21:23:46 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -59,7 +59,7 @@
 	int64_t rc_removed_count;
 } refcount_t;
 
-/* Note: refcount_t should be initialized to zero before use. */
+/* Note: refcount_t must be initialized with refcount_create() */
 
 void refcount_create(refcount_t *rc);
 void refcount_destroy(refcount_t *rc);
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/uts/common/fs/zfs/sys/rprwlock.h	Thu Aug 02 21:23:46 2007 -0700
@@ -0,0 +1,61 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Use is subject to license terms.
+ */
+
+#ifndef	_SYS_RPRWLOCK_H
+#define	_SYS_RPRWLOCK_H
+
+#pragma ident	"%Z%%M%	%I%	%E% SMI"
+
+#include <sys/inttypes.h>
+#include <sys/list.h>
+#include <sys/zfs_context.h>
+#include <sys/refcount.h>
+
+#ifdef	__cplusplus
+extern "C" {
+#endif
+
+typedef struct rprwlock {
+	kmutex_t	rw_lock;
+	kthread_t	*rw_writer;
+	kcondvar_t	rw_cv;
+	refcount_t	rw_count;
+} rprwlock_t;
+
+void rprw_init(rprwlock_t *rwl);
+void rprw_destroy(rprwlock_t *rwl);
+void rprw_enter_read(rprwlock_t *rwl, void *tag);
+void rprw_enter_write(rprwlock_t *rwl, void *tag);
+void rprw_enter(rprwlock_t *rwl, krw_t rw, void *tag);
+void rprw_exit(rprwlock_t *rwl, void *tag);
+boolean_t rprw_held(rprwlock_t *rwl, krw_t rw);
+#define	RPRW_READ_HELD(x)	rprw_held(x, RW_READER)
+#define	RPRW_WRITE_HELD(x)	rprw_held(x, RW_WRITER)
+
+#ifdef	__cplusplus
+}
+#endif
+
+#endif /* _SYS_RPRWLOCK_H */
--- a/usr/src/uts/common/fs/zfs/sys/spa_impl.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/spa_impl.h	Thu Aug 02 21:23:46 2007 -0700
@@ -37,19 +37,13 @@
 #include <sys/zfs_context.h>
 #include <sys/avl.h>
 #include <sys/refcount.h>
+#include <sys/rprwlock.h>
 #include <sys/bplist.h>
 
 #ifdef	__cplusplus
 extern "C" {
 #endif
 
-typedef struct spa_config_lock {
-	kmutex_t	scl_lock;
-	refcount_t	scl_count;
-	kthread_t	*scl_writer;
-	kcondvar_t	scl_cv;
-} spa_config_lock_t;
-
 typedef struct spa_error_entry {
 	zbookmark_t	se_bookmark;
 	char		*se_name;
@@ -152,11 +146,12 @@
 	uint64_t	spa_bootfs;		/* default boot filesystem */
 	boolean_t	spa_delegation;		/* delegation on/off */
 	/*
-	 * spa_refcnt must be the last element because it changes size based on
-	 * compilation options.  In order for the MDB module to function
-	 * correctly, the other fields must remain in the same location.
+	 * spa_refcnt & spa_config_lock must be the last elements
+	 * because refcount_t changes size based on compilation options.
+	 * In order for the MDB module to function correctly, the other
+	 * fields must remain in the same location.
 	 */
-	spa_config_lock_t spa_config_lock;	/* configuration changes */
+	rprwlock_t	spa_config_lock;	/* configuration changes */
 	refcount_t	spa_refcount;		/* number of opens */
 };
 
--- a/usr/src/uts/common/fs/zfs/sys/unique.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/unique.h	Thu Aug 02 21:23:46 2007 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -39,8 +38,12 @@
 #define	UNIQUE_BITS	56
 
 void unique_init(void);
+void unique_fini(void);
 
-/* Return a new unique value. */
+/*
+ * Return a new unique value (which will not be uniquified against until
+ * it is unique_insert()-ed.
+ */
 uint64_t unique_create(void);
 
 /* Return a unique value, which equals the one passed in if possible. */
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h	Thu Aug 02 21:23:46 2007 -0700
@@ -133,8 +133,6 @@
 	uint64_t	zc_nvlist_dst;	/* really (char *) */
 	uint64_t	zc_nvlist_dst_size;
 	uint64_t	zc_cookie;
-	uint64_t	zc_cred;
-	uint64_t	zc_dev;
 	uint64_t	zc_objset_type;
 	uint64_t	zc_perm_action;
 	uint64_t 	zc_history;	/* really (char *) */
--- a/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_vfsops.h	Thu Aug 02 21:23:46 2007 -0700
@@ -52,10 +52,9 @@
 	uint_t		z_acl_mode;	/* acl chmod/mode behavior */
 	uint_t		z_acl_inherit;	/* acl inheritance behavior */
 	boolean_t	z_atime;	/* enable atimes mount option */
-	boolean_t	z_unmounted1;	/* unmounted phase 1 */
-	boolean_t	z_unmounted2;	/* unmounted phase 2 */
-	uint32_t	z_op_cnt;	/* vnode/vfs operations ref count */
-	krwlock_t	z_um_lock;	/* rw lock for umount phase 2 */
+	boolean_t	z_unmounted;	/* unmounted */
+	krwlock_t	z_unmount_lock;
+	krwlock_t	z_unmount_inactive_lock;
 	list_t		z_all_znodes;	/* all vnodes in the fs */
 	kmutex_t	z_znodes_lock;	/* lock for z_all_znodes */
 	vnode_t		*z_ctldir;	/* .zfs directory pointer */
--- a/usr/src/uts/common/fs/zfs/sys/zfs_znode.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_znode.h	Thu Aug 02 21:23:46 2007 -0700
@@ -192,13 +192,15 @@
  */
 #define	ZFS_ENTER(zfsvfs) \
 	{ \
-		atomic_add_32(&(zfsvfs)->z_op_cnt, 1); \
-		if ((zfsvfs)->z_unmounted1) { \
+		if (rw_tryenter(&(zfsvfs)->z_unmount_lock, RW_READER) == 0) \
+			return (EIO); \
+		if ((zfsvfs)->z_unmounted) { \
 			ZFS_EXIT(zfsvfs); \
 			return (EIO); \
 		} \
 	}
-#define	ZFS_EXIT(zfsvfs) atomic_add_32(&(zfsvfs)->z_op_cnt, -1)
+
+#define	ZFS_EXIT(zfsvfs) rw_exit(&(zfsvfs)->z_unmount_lock)
 
 /*
  * Macros for dealing with dmu_buf_hold
--- a/usr/src/uts/common/fs/zfs/sys/zvol.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/sys/zvol.h	Thu Aug 02 21:23:46 2007 -0700
@@ -40,9 +40,9 @@
 extern int zvol_check_volblocksize(uint64_t volblocksize);
 extern int zvol_get_stats(objset_t *os, nvlist_t *nv);
 extern void zvol_create_cb(objset_t *os, void *arg, cred_t *cr, dmu_tx_t *tx);
-extern int zvol_create_minor(const char *, dev_t);
+extern int zvol_create_minor(const char *, major_t);
 extern int zvol_remove_minor(const char *);
-extern int zvol_set_volsize(const char *, dev_t, uint64_t);
+extern int zvol_set_volsize(const char *, major_t, uint64_t);
 extern int zvol_set_volblocksize(const char *, uint64_t);
 
 extern int zvol_open(dev_t *devp, int flag, int otyp, cred_t *cr);
--- a/usr/src/uts/common/fs/zfs/unique.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/unique.c	Thu Aug 02 21:23:46 2007 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -30,7 +30,7 @@
 #include <sys/unique.h>
 
 static avl_tree_t unique_avl;
-static kmutex_t unique_mtx;	/* Lock never initialized. */
+static kmutex_t unique_mtx;
 
 typedef struct unique {
 	avl_node_t un_link;
@@ -57,12 +57,22 @@
 {
 	avl_create(&unique_avl, unique_compare,
 	    sizeof (unique_t), offsetof(unique_t, un_link));
+	mutex_init(&unique_mtx, NULL, MUTEX_DEFAULT, NULL);
+}
+
+void
+unique_fini(void)
+{
+	avl_destroy(&unique_avl);
+	mutex_destroy(&unique_mtx);
 }
 
 uint64_t
 unique_create(void)
 {
-	return (unique_insert(0));
+	uint64_t value = unique_insert(0);
+	unique_remove(value);
+	return (value);
 }
 
 uint64_t
--- a/usr/src/uts/common/fs/zfs/vdev_label.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/vdev_label.c	Thu Aug 02 21:23:46 2007 -0700
@@ -318,7 +318,8 @@
 	zio_t *zio;
 	int l;
 
-	ASSERT(spa_config_held(spa, RW_READER));
+	ASSERT(spa_config_held(spa, RW_READER) ||
+	    spa_config_held(spa, RW_WRITER));
 
 	if (vdev_is_dead(vd))
 		return (NULL);
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Thu Aug 02 21:23:46 2007 -0700
@@ -280,7 +280,7 @@
 		break;
 	}
 
-	return (zfs_secpolicy_write_perms(name, zfs_prop_perm(prop), cr));
+	return (zfs_secpolicy_write_perms(name, zfs_prop_to_name(prop), cr));
 }
 
 int
@@ -1175,7 +1175,7 @@
 }
 
 static int
-zfs_set_prop_nvlist(const char *name, dev_t dev, cred_t *cr, nvlist_t *nvl)
+zfs_set_prop_nvlist(const char *name, nvlist_t *nvl)
 {
 	nvpair_t *elem;
 	int error;
@@ -1200,13 +1200,13 @@
 				return (EINVAL);
 
 			error = zfs_secpolicy_write_perms(name,
-			    ZFS_DELEG_PERM_USERPROP, cr);
+			    ZFS_DELEG_PERM_USERPROP, CRED());
 			if (error)
 				return (error);
 			continue;
 		}
 
-		if ((error = zfs_secpolicy_setprop(name, prop, cr)) != 0)
+		if ((error = zfs_secpolicy_setprop(name, prop, CRED())) != 0)
 			return (error);
 
 		/*
@@ -1285,7 +1285,8 @@
 
 		case ZFS_PROP_VOLSIZE:
 			if ((error = nvpair_value_uint64(elem, &intval)) != 0 ||
-			    (error = zvol_set_volsize(name, dev, intval)) != 0)
+			    (error = zvol_set_volsize(name,
+			    ddi_driver_major(zfs_dip), intval)) != 0)
 				return (error);
 			break;
 
@@ -1304,7 +1305,7 @@
 		default:
 			if (nvpair_type(elem) == DATA_TYPE_STRING) {
 				if (zfs_prop_get_type(prop) !=
-				    prop_type_string)
+				    PROP_TYPE_STRING)
 					return (EINVAL);
 				VERIFY(nvpair_value_string(elem, &strval) == 0);
 				if ((error = dsl_prop_set(name,
@@ -1317,15 +1318,15 @@
 				VERIFY(nvpair_value_uint64(elem, &intval) == 0);
 
 				switch (zfs_prop_get_type(prop)) {
-				case prop_type_number:
+				case PROP_TYPE_NUMBER:
 					break;
-				case prop_type_boolean:
+				case PROP_TYPE_BOOLEAN:
 					if (intval > 1)
 						return (EINVAL);
 					break;
-				case prop_type_string:
+				case PROP_TYPE_STRING:
 					return (EINVAL);
-				case prop_type_index:
+				case PROP_TYPE_INDEX:
 					if (zfs_prop_index_to_string(prop,
 					    intval, &unused) != 0)
 						return (EINVAL);
@@ -1366,13 +1367,12 @@
 			if (!zfs_prop_user(zc->zc_value))
 				return (EINVAL);
 			error = zfs_secpolicy_write_perms(zc->zc_name,
-			    ZFS_DELEG_PERM_USERPROP,
-			    (cred_t *)(uintptr_t)zc->zc_cred);
+			    ZFS_DELEG_PERM_USERPROP, CRED());
 		} else {
 			if (!zfs_prop_inheritable(prop))
 				return (EINVAL);
 			error = zfs_secpolicy_setprop(zc->zc_name,
-			    prop, (cred_t *)(uintptr_t)zc->zc_cred);
+			    prop, CRED());
 		}
 		if (error)
 			return (error);
@@ -1383,8 +1383,7 @@
 	if ((error = get_nvlist(zc, &nvl)) != 0)
 		return (error);
 
-	error = zfs_set_prop_nvlist(zc->zc_name, zc->zc_dev,
-	    (cred_t *)(uintptr_t)zc->zc_cred, nvl);
+	error = zfs_set_prop_nvlist(zc->zc_name, nvl);
 
 	nvlist_free(nvl);
 	return (error);
@@ -1555,7 +1554,7 @@
 	}
 	nvlist_free(nvp);
 	error = dsl_deleg_access(zc->zc_name,
-	    ZFS_DELEG_PERM_SHAREISCSI, usercred);
+	    zfs_prop_to_name(ZFS_PROP_SHAREISCSI), usercred);
 	crfree(usercred);
 	return (error);
 }
@@ -1565,7 +1564,6 @@
 {
 	int error;
 	nvlist_t *fsaclnv = NULL;
-	cred_t *cr;
 
 	if ((error = get_nvlist(zc, &fsaclnv)) != 0)
 		return (error);
@@ -1584,13 +1582,15 @@
 	 * the nvlist(s)
 	 */
 
-	cr = (cred_t *)(uintptr_t)zc->zc_cred;
-	error = secpolicy_zfs(cr);
+	error = secpolicy_zfs(CRED());
 	if (error) {
-		if (zc->zc_perm_action == B_FALSE)
-			error = dsl_deleg_can_allow(zc->zc_name, fsaclnv, cr);
-		else
-			error = dsl_deleg_can_unallow(zc->zc_name, fsaclnv, cr);
+		if (zc->zc_perm_action == B_FALSE) {
+			error = dsl_deleg_can_allow(zc->zc_name,
+			    fsaclnv, CRED());
+		} else {
+			error = dsl_deleg_can_unallow(zc->zc_name,
+			    fsaclnv, CRED());
+		}
 	}
 
 	if (error == 0)
@@ -1617,7 +1617,7 @@
 static int
 zfs_ioc_create_minor(zfs_cmd_t *zc)
 {
-	return (zvol_create_minor(zc->zc_name, zc->zc_dev));
+	return (zvol_create_minor(zc->zc_name, ddi_driver_major(zfs_dip)));
 }
 
 static int
@@ -1766,9 +1766,7 @@
 	 * It would be nice to do this atomically.
 	 */
 	if (error == 0) {
-		if ((error = zfs_set_prop_nvlist(zc->zc_name,
-		    zc->zc_dev, (cred_t *)(uintptr_t)zc->zc_cred,
-		    nvprops)) != 0)
+		if ((error = zfs_set_prop_nvlist(zc->zc_name, nvprops)) != 0)
 			(void) dmu_objset_destroy(zc->zc_name);
 	}
 
@@ -2185,6 +2183,7 @@
 		return (zvol_ioctl(dev, cmd, arg, flag, cr, rvalp));
 
 	vec = cmd - ZFS_IOC;
+	ASSERT3U(getmajor(dev), ==, ddi_driver_major(zfs_dip));
 
 	if (vec >= sizeof (zfs_ioc_vec) / sizeof (zfs_ioc_vec[0]))
 		return (EINVAL);
@@ -2193,11 +2192,8 @@
 
 	error = xcopyin((void *)arg, zc, sizeof (zfs_cmd_t));
 
-	if (error == 0) {
-		zc->zc_cred = (uintptr_t)cr;
-		zc->zc_dev = dev;
+	if (error == 0)
 		error = zfs_ioc_vec[vec].zvec_secpolicy(zc, cr);
-	}
 
 	/*
 	 * Ensure that all pool/dataset names are valid before we pass down to
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Thu Aug 02 21:23:46 2007 -0700
@@ -73,7 +73,6 @@
 static int zfs_statvfs(vfs_t *vfsp, struct statvfs64 *statp);
 static int zfs_vget(vfs_t *vfsp, vnode_t **vpp, fid_t *fidp);
 static void zfs_freevfs(vfs_t *vfsp);
-static void zfs_objset_close(zfsvfs_t *zfsvfs);
 
 static const fs_operation_def_t zfs_vfsops_template[] = {
 	VFSNAME_MOUNT,		{ .vfs_mount = zfs_mount },
@@ -526,7 +525,8 @@
 	mutex_init(&zfsvfs->z_znodes_lock, NULL, MUTEX_DEFAULT, NULL);
 	list_create(&zfsvfs->z_all_znodes, sizeof (znode_t),
 	    offsetof(znode_t, z_link_node));
-	rw_init(&zfsvfs->z_um_lock, NULL, RW_DEFAULT, NULL);
+	rw_init(&zfsvfs->z_unmount_lock, NULL, RW_DEFAULT, NULL);
+	rw_init(&zfsvfs->z_unmount_inactive_lock, NULL, RW_DEFAULT, NULL);
 
 	/* Initialize the generic filesystem structure. */
 	vfsp->vfs_bcount = 0;
@@ -1009,6 +1009,8 @@
 zfs_umount(vfs_t *vfsp, int fflag, cred_t *cr)
 {
 	zfsvfs_t *zfsvfs = vfsp->vfs_data;
+	objset_t *os = zfsvfs->z_os;
+	znode_t	*zp, *nextzp;
 	int ret;
 
 	ret = secpolicy_fs_unmount(cr, vfsp);
@@ -1036,58 +1038,102 @@
 		return (ret);
 	}
 
-	if (fflag & MS_FORCE) {
-		vfsp->vfs_flag |= VFS_UNMOUNTED;
-		zfsvfs->z_unmounted1 = B_TRUE;
-
-		/*
-		 * Ensure that z_unmounted1 reaches global visibility
-		 * before z_op_cnt.
-		 */
-		membar_producer();
-
+	if (!(fflag & MS_FORCE)) {
 		/*
-		 * Wait for all zfs threads to leave zfs.
-		 * Grabbing a rwlock as reader in all vops and
-		 * as writer here doesn't work because it too easy to get
-		 * multiple reader enters as zfs can re-enter itself.
-		 * This can lead to deadlock if there is an intervening
-		 * rw_enter as writer.
-		 * So a file system threads ref count (z_op_cnt) is used.
-		 * A polling loop on z_op_cnt may seem inefficient, but
-		 * - this saves all threads on exit from having to grab a
-		 *   mutex in order to cv_signal
-		 * - only occurs on forced unmount in the rare case when
-		 *   there are outstanding threads within the file system.
+		 * Check the number of active vnodes in the file system.
+		 * Our count is maintained in the vfs structure, but the
+		 * number is off by 1 to indicate a hold on the vfs
+		 * structure itself.
+		 *
+		 * The '.zfs' directory maintains a reference of its
+		 * own, and any active references underneath are
+		 * reflected in the vnode count.
 		 */
-		while (zfsvfs->z_op_cnt) {
-			delay(1);
-		}
-
-		zfs_objset_close(zfsvfs);
-
-		return (0);
-	}
-	/*
-	 * Check the number of active vnodes in the file system.
-	 * Our count is maintained in the vfs structure, but the number
-	 * is off by 1 to indicate a hold on the vfs structure itself.
-	 *
-	 * The '.zfs' directory maintains a reference of its own, and any active
-	 * references underneath are reflected in the vnode count.
-	 */
-	if (zfsvfs->z_ctldir == NULL) {
-		if (vfsp->vfs_count > 1)
-			return (EBUSY);
-	} else {
-		if (vfsp->vfs_count > 2 ||
-		    (zfsvfs->z_ctldir->v_count > 1 && !(fflag & MS_FORCE))) {
-			return (EBUSY);
+		if (zfsvfs->z_ctldir == NULL) {
+			if (vfsp->vfs_count > 1)
+				return (EBUSY);
+		} else {
+			if (vfsp->vfs_count > 2 ||
+			    zfsvfs->z_ctldir->v_count > 1) {
+				return (EBUSY);
+			}
 		}
 	}
 
 	vfsp->vfs_flag |= VFS_UNMOUNTED;
-	zfs_objset_close(zfsvfs);
+
+	rw_enter(&zfsvfs->z_unmount_lock, RW_WRITER);
+	rw_enter(&zfsvfs->z_unmount_inactive_lock, RW_WRITER);
+
+	/*
+	 * At this point there are no vops active, and any new vops will
+	 * fail with EIO since we have z_unmount_lock for writer (only
+	 * relavent for forced unmount).
+	 *
+	 * Release all holds on dbufs.
+	 * Note, the dmu can still callback via znode_pageout_func()
+	 * which can zfs_znode_free() the znode.  So we lock
+	 * z_all_znodes; search the list for a held dbuf; drop the lock
+	 * (we know zp can't disappear if we hold a dbuf lock) then
+	 * regrab the lock and restart.
+	 */
+	mutex_enter(&zfsvfs->z_znodes_lock);
+	for (zp = list_head(&zfsvfs->z_all_znodes); zp; zp = nextzp) {
+		nextzp = list_next(&zfsvfs->z_all_znodes, zp);
+		if (zp->z_dbuf_held) {
+			/* dbufs should only be held when force unmounting */
+			zp->z_dbuf_held = 0;
+			mutex_exit(&zfsvfs->z_znodes_lock);
+			dmu_buf_rele(zp->z_dbuf, NULL);
+			/* Start again */
+			mutex_enter(&zfsvfs->z_znodes_lock);
+			nextzp = list_head(&zfsvfs->z_all_znodes);
+		}
+	}
+	mutex_exit(&zfsvfs->z_znodes_lock);
+
+	/*
+	 * Set the unmounted flag and let new vops unblock.
+	 * zfs_inactive will have the unmounted behavior, and all other
+	 * vops will fail with EIO.
+	 */
+	zfsvfs->z_unmounted = B_TRUE;
+	rw_exit(&zfsvfs->z_unmount_lock);
+	rw_exit(&zfsvfs->z_unmount_inactive_lock);
+
+	/*
+	 * Unregister properties.
+	 */
+	if (!dmu_objset_is_snapshot(os))
+		zfs_unregister_callbacks(zfsvfs);
+
+	/*
+	 * Close the zil. NB: Can't close the zil while zfs_inactive
+	 * threads are blocked as zil_close can call zfs_inactive.
+	 */
+	if (zfsvfs->z_log) {
+		zil_close(zfsvfs->z_log);
+		zfsvfs->z_log = NULL;
+	}
+
+	/*
+	 * Evict all dbufs so that cached znodes will be freed
+	 */
+	if (dmu_objset_evict_dbufs(os, B_TRUE)) {
+		txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0);
+		(void) dmu_objset_evict_dbufs(os, B_FALSE);
+	}
+
+	/*
+	 * Finally close the objset
+	 */
+	dmu_objset_close(os);
+
+	/*
+	 * We can now safely destroy the '.zfs' directory node.
+	 */
+	if (zfsvfs->z_ctldir != NULL)
+		zfsctl_destroy(zfsvfs);
 
 	return (0);
 }
@@ -1177,92 +1223,13 @@
 }
 
 static void
-zfs_objset_close(zfsvfs_t *zfsvfs)
-{
-	znode_t		*zp, *nextzp;
-	objset_t	*os = zfsvfs->z_os;
-
-	/*
-	 * For forced unmount, at this point all vops except zfs_inactive
-	 * are erroring EIO. We need to now suspend zfs_inactive threads
-	 * while we are freeing dbufs before switching zfs_inactive
-	 * to use behaviour without a objset.
-	 */
-	rw_enter(&zfsvfs->z_um_lock, RW_WRITER);
-
-	/*
-	 * Release all holds on dbufs
-	 * Note, although we have stopped all other vop threads and
-	 * zfs_inactive(), the dmu can callback via znode_pageout_func()
-	 * which can zfs_znode_free() the znode.
-	 * So we lock z_all_znodes; search the list for a held
-	 * dbuf; drop the lock (we know zp can't disappear if we hold
-	 * a dbuf lock; then regrab the lock and restart.
-	 */
-	mutex_enter(&zfsvfs->z_znodes_lock);
-	for (zp = list_head(&zfsvfs->z_all_znodes); zp; zp = nextzp) {
-		nextzp = list_next(&zfsvfs->z_all_znodes, zp);
-		if (zp->z_dbuf_held) {
-			/* dbufs should only be held when force unmounting */
-			zp->z_dbuf_held = 0;
-			mutex_exit(&zfsvfs->z_znodes_lock);
-			dmu_buf_rele(zp->z_dbuf, NULL);
-			/* Start again */
-			mutex_enter(&zfsvfs->z_znodes_lock);
-			nextzp = list_head(&zfsvfs->z_all_znodes);
-		}
-	}
-	mutex_exit(&zfsvfs->z_znodes_lock);
-
-	/*
-	 * Unregister properties.
-	 */
-	if (!dmu_objset_is_snapshot(os))
-		zfs_unregister_callbacks(zfsvfs);
-
-	/*
-	 * Switch zfs_inactive to behaviour without an objset.
-	 * It just tosses cached pages and frees the znode & vnode.
-	 * Then re-enable zfs_inactive threads in that new behaviour.
-	 */
-	zfsvfs->z_unmounted2 = B_TRUE;
-	rw_exit(&zfsvfs->z_um_lock); /* re-enable any zfs_inactive threads */
-
-	/*
-	 * Close the zil. Can't close the zil while zfs_inactive
-	 * threads are blocked as zil_close can call zfs_inactive.
-	 */
-	if (zfsvfs->z_log) {
-		zil_close(zfsvfs->z_log);
-		zfsvfs->z_log = NULL;
-	}
-
-	/*
-	 * Evict all dbufs so that cached znodes will be freed
-	 */
-	if (dmu_objset_evict_dbufs(os, 1)) {
-		txg_wait_synced(dmu_objset_pool(zfsvfs->z_os), 0);
-		(void) dmu_objset_evict_dbufs(os, 0);
-	}
-
-	/*
-	 * Finally close the objset
-	 */
-	dmu_objset_close(os);
-
-	/*
-	 * We can now safely destroy the '.zfs' directory node.
-	 */
-	if (zfsvfs->z_ctldir != NULL)
-		zfsctl_destroy(zfsvfs);
-
-}
-
-static void
 zfs_freevfs(vfs_t *vfsp)
 {
 	zfsvfs_t *zfsvfs = vfsp->vfs_data;
 
+	mutex_destroy(&zfsvfs->z_znodes_lock);
+	rw_destroy(&zfsvfs->z_unmount_lock);
+	rw_destroy(&zfsvfs->z_unmount_inactive_lock);
 	kmem_free(zfsvfs, sizeof (zfsvfs_t));
 
 	atomic_add_32(&zfs_active_fs_count, -1);
--- a/usr/src/uts/common/fs/zfs/zfs_vnops.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_vnops.c	Thu Aug 02 21:23:46 2007 -0700
@@ -3005,8 +3005,8 @@
 	zfsvfs_t *zfsvfs = zp->z_zfsvfs;
 	int error;
 
-	rw_enter(&zfsvfs->z_um_lock, RW_READER);
-	if (zfsvfs->z_unmounted2) {
+	rw_enter(&zfsvfs->z_unmount_inactive_lock, RW_READER);
+	if (zfsvfs->z_unmounted) {
 		ASSERT(zp->z_dbuf_held == 0);
 
 		if (vn_has_cached_data(vp)) {
@@ -3022,7 +3022,7 @@
 		} else {
 			mutex_exit(&zp->z_lock);
 		}
-		rw_exit(&zfsvfs->z_um_lock);
+		rw_exit(&zfsvfs->z_unmount_inactive_lock);
 		VFS_RELE(zfsvfs->z_vfs);
 		return;
 	}
@@ -3053,7 +3053,7 @@
 	}
 
 	zfs_zinactive(zp);
-	rw_exit(&zfsvfs->z_um_lock);
+	rw_exit(&zfsvfs->z_unmount_inactive_lock);
 }
 
 /*
--- a/usr/src/uts/common/fs/zfs/zvol.c	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/fs/zfs/zvol.c	Thu Aug 02 21:23:46 2007 -0700
@@ -114,9 +114,9 @@
 static int zvol_get_data(void *arg, lr_write_t *lr, char *buf, zio_t *zio);
 
 static void
-zvol_size_changed(zvol_state_t *zv, dev_t dev)
+zvol_size_changed(zvol_state_t *zv, major_t maj)
 {
-	dev = makedevice(getmajor(dev), zv->zv_minor);
+	dev_t dev = makedevice(maj, zv->zv_minor);
 
 	VERIFY(ddi_prop_update_int64(dev, zfs_dip,
 	    "Size", zv->zv_volsize) == DDI_SUCCESS);
@@ -315,7 +315,7 @@
  * Create a minor node for the specified volume.
  */
 int
-zvol_create_minor(const char *name, dev_t dev)
+zvol_create_minor(const char *name, major_t maj)
 {
 	zvol_state_t *zv;
 	objset_t *os;
@@ -452,7 +452,7 @@
 
 	zil_replay(os, zv, &zv->zv_txg_assign, zvol_replay_vector);
 
-	zvol_size_changed(zv, dev);
+	zvol_size_changed(zv, maj);
 
 	/* XXX this should handle the possible i/o error */
 	VERIFY(dsl_prop_register(dmu_objset_ds(zv->zv_objset),
@@ -512,7 +512,7 @@
 }
 
 int
-zvol_set_volsize(const char *name, dev_t dev, uint64_t volsize)
+zvol_set_volsize(const char *name, major_t maj, uint64_t volsize)
 {
 	zvol_state_t *zv;
 	dmu_tx_t *tx;
@@ -559,7 +559,7 @@
 
 	if (error == 0) {
 		zv->zv_volsize = volsize;
-		zvol_size_changed(zv, dev);
+		zvol_size_changed(zv, maj);
 	}
 
 	mutex_exit(&zvol_state_lock);
--- a/usr/src/uts/common/sys/fs/zfs.h	Thu Aug 02 19:52:58 2007 -0700
+++ b/usr/src/uts/common/sys/fs/zfs.h	Thu Aug 02 21:23:46 2007 -0700
@@ -98,7 +98,8 @@
 	ZPOOL_PROP_AUTOREPLACE,
 	ZPOOL_PROP_DELEGATION,
 	ZFS_PROP_VERSION,
-	ZPOOL_PROP_NAME			/* XXX must be last! */
+	ZPOOL_PROP_NAME,
+	ZFS_NUM_PROPS
 } zfs_prop_t;
 
 typedef zfs_prop_t zpool_prop_t;
@@ -160,16 +161,15 @@
 int zfs_prop_string_to_index(zfs_prop_t, const char *, uint64_t *);
 int zfs_prop_index_to_string(zfs_prop_t, uint64_t, const char **);
 uint64_t zpool_prop_default_numeric(zpool_prop_t);
-const char *zfs_prop_perm(zfs_prop_t);
 
 /*
  * Property Iterator
  */
 typedef zfs_prop_t (*zfs_prop_f)(zfs_prop_t, void *);
 typedef zpool_prop_t (*zpool_prop_f)(zpool_prop_t, void *);
-extern zfs_prop_t zfs_prop_iter(zfs_prop_f, void *, boolean_t);
-extern zfs_prop_t zfs_prop_iter_ordered(zfs_prop_f, void *, boolean_t);
-extern zpool_prop_t zpool_prop_iter(zpool_prop_f, void *, boolean_t);
+extern zfs_prop_t zfs_prop_iter(zfs_prop_f, void *);
+extern zfs_prop_t zfs_prop_iter_ordered(zfs_prop_f, void *);
+extern zpool_prop_t zpool_prop_iter(zpool_prop_f, void *);
 
 /*
  * On-disk version number.