6377671 zfs mount -a shouldn't bother checking snapshots
authoreschrock
Mon, 30 Jan 2006 22:19:55 -0800
changeset 1356 e021b5e4aa0e
parent 1355 bfa8ad95acbb
child 1357 46e683ebd8ea
6377671 zfs mount -a shouldn't bother checking snapshots 6377673 'zfs mount -a' should discover the proper mount order 6378361 'zfs share -a' needs to avoid expensive checks during boot 6378377 zfs_get_stats() is way to expensive 6378388 zfs_for_each() iterates unnecessarily
usr/src/cmd/fs.d/nfs/share/share.c
usr/src/cmd/fs.d/nfs/svc/nfs-server
usr/src/cmd/zfs/zfs_iter.c
usr/src/cmd/zfs/zfs_main.c
usr/src/common/zfs/zfs_prop.c
usr/src/lib/libzfs/common/libzfs.h
usr/src/lib/libzfs/common/libzfs_dataset.c
usr/src/lib/libzfs/common/libzfs_impl.h
usr/src/lib/libzfs/spec/libzfs.spec
usr/src/lib/libzfs_jni/common/libzfs_jni_property.c
usr/src/uts/common/fs/zfs/dsl_dir.c
usr/src/uts/common/fs/zfs/dsl_prop.c
usr/src/uts/common/fs/zfs/sys/dmu.h
usr/src/uts/common/fs/zfs/sys/dsl_prop.h
usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h
usr/src/uts/common/fs/zfs/zfs_ioctl.c
usr/src/uts/common/fs/zfs/zvol.c
usr/src/uts/common/sys/fs/zfs.h
--- a/usr/src/cmd/fs.d/nfs/share/share.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/cmd/fs.d/nfs/share/share.c	Mon Jan 30 22:19:55 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -148,15 +148,17 @@
 	if (argc - optind > 1)
 		res = argv[optind + 1];
 
-	switch (shareable(dir)) {
-	case 0:
-		exit(RET_ERR);
-		break;
-	case 1:
-		break;
-	case 2:
-		replace = 1;
-		break;
+	if (getenv("SHARE_NOINUSE_CHECK") == NULL) {
+		switch (shareable(dir)) {
+		case 0:
+			exit(RET_ERR);
+			break;
+		case 1:
+			break;
+		case 2:
+			replace = 1;
+			break;
+		}
 	}
 
 	ex.ex_path = dir;
--- a/usr/src/cmd/fs.d/nfs/svc/nfs-server	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/cmd/fs.d/nfs/svc/nfs-server	Mon Jan 30 22:19:55 2006 -0800
@@ -21,7 +21,7 @@
 # CDDL HEADER END
 #
 #
-# Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+# Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
 # Use is subject to license terms.
 #
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
@@ -41,6 +41,16 @@
 		exit $SMF_EXIT_OK
 	fi
 
+	# Share any ZFS filesystems marked for sharing.  The environment
+	# variable prevents share(1M) from checking whether each filesystem
+	# is in use, an O(n^2) operation with no purpose at this time
+
+	if [ -x /usr/sbin/zfs ]; then
+		SHARE_NOINUSE_CHECK=1; export SHARE_NOINUSE_CHECK
+		/usr/sbin/zfs share -a
+		unset SHARE_NOINUSE_CHECK
+	fi
+
 	# If /etc/dfs/dfstab exists and has non-blank or non-commented-out
 	# lines, then run shareall to export them.
 
@@ -51,11 +61,6 @@
 		/usr/sbin/shareall -F nfs
 	fi
 
-	# Share any ZFS filesystems marked for sharing.
-
-	if [ -x /usr/sbin/zfs ]; then
-		/usr/sbin/zfs share -a
-	fi
 
 	# Start up mountd and nfsd if anything is exported.
 
--- a/usr/src/cmd/zfs/zfs_iter.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/cmd/zfs/zfs_iter.c	Mon Jan 30 22:19:55 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -91,11 +91,11 @@
 	}
 
 	/*
-	 * If 'recurse' is set, and the datasets can have datasets of the
-	 * appropriate type, then recurse over its children.
+	 * Recurse if necessary.
 	 */
 	if (cb->cb_recurse && (zfs_get_type(zhp) == ZFS_TYPE_FILESYSTEM ||
-	    (cb->cb_types & ZFS_TYPE_SNAPSHOT)))
+	    (zfs_get_type(zhp) == ZFS_TYPE_VOLUME && (cb->cb_types &
+	    ZFS_TYPE_SNAPSHOT))))
 		(void) zfs_iter_children(zhp, zfs_callback, data);
 
 	if (!dontclose)
--- a/usr/src/cmd/zfs/zfs_main.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/cmd/zfs/zfs_main.c	Mon Jan 30 22:19:55 2006 -0800
@@ -1770,6 +1770,75 @@
 	return (err != 0);
 }
 
+typedef struct get_all_cbdata {
+	zfs_handle_t	**cb_handles;
+	size_t		cb_alloc;
+	size_t		cb_used;
+} get_all_cbdata_t;
+
+static int
+get_one_filesystem(zfs_handle_t *zhp, void *data)
+{
+	get_all_cbdata_t *cbp = data;
+
+	/*
+	 * Skip any zvols
+	 */
+	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
+		zfs_close(zhp);
+		return (0);
+	}
+
+	if (cbp->cb_alloc == cbp->cb_used) {
+		zfs_handle_t **handles;
+
+		if (cbp->cb_alloc == 0)
+			cbp->cb_alloc = 64;
+		else
+			cbp->cb_alloc *= 2;
+
+		handles = safe_malloc(cbp->cb_alloc * sizeof (void *));
+
+		if (cbp->cb_handles) {
+			bcopy(cbp->cb_handles, handles,
+			    cbp->cb_used * sizeof (void *));
+			free(cbp->cb_handles);
+		}
+
+		cbp->cb_handles = handles;
+	}
+
+	cbp->cb_handles[cbp->cb_used++] = zhp;
+
+	return (zfs_iter_filesystems(zhp, get_one_filesystem, data));
+}
+
+static void
+get_all_filesystems(zfs_handle_t ***fslist, size_t *count)
+{
+	get_all_cbdata_t cb = { 0 };
+
+	(void) zfs_iter_root(get_one_filesystem, &cb);
+
+	*fslist = cb.cb_handles;
+	*count = cb.cb_used;
+}
+
+static int
+mountpoint_compare(const void *a, const void *b)
+{
+	zfs_handle_t **za = (zfs_handle_t **)a;
+	zfs_handle_t **zb = (zfs_handle_t **)b;
+	char mounta[MAXPATHLEN];
+	char mountb[MAXPATHLEN];
+
+	verify(zfs_prop_get(*za, ZFS_PROP_MOUNTPOINT, mounta,
+	    sizeof (mounta), NULL, NULL, 0, FALSE) == 0);
+	verify(zfs_prop_get(*zb, ZFS_PROP_MOUNTPOINT, mountb,
+	    sizeof (mountb), NULL, NULL, 0, FALSE) == 0);
+
+	return (strcmp(mounta, mountb));
+}
 
 /*
  * Generic callback for sharing or mounting filesystems.  Because the code is so
@@ -1975,13 +2044,30 @@
 
 	/* check number of arguments */
 	if (do_all) {
+		zfs_handle_t **fslist = NULL;
+		size_t i, count = 0;
+
 		if (argc != 0) {
 			(void) fprintf(stderr, gettext("too many arguments\n"));
 			usage(FALSE);
 		}
 
-		ret = zfs_for_each(argc, argv, TRUE,
-		    ZFS_TYPE_FILESYSTEM, share_mount_callback, &cb);
+		get_all_filesystems(&fslist, &count);
+
+		if (count == 0)
+			return (0);
+
+		qsort(fslist, count, sizeof (void *), mountpoint_compare);
+
+		for (i = 0; i < count; i++) {
+			if ((ret = share_mount_callback(fslist[i], &cb)) != 0)
+				break;
+		}
+
+		for (i = 0; i < count; i++)
+			zfs_close(fslist[i]);
+
+		free(fslist);
 	} else if (argc == 0) {
 		struct mnttab entry;
 
--- a/usr/src/common/zfs/zfs_prop.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/common/zfs/zfs_prop.c	Mon Jan 30 22:19:55 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -212,10 +212,10 @@
 /*
  * Return the default value for the given property.
  */
-void
-zfs_prop_default_string(zfs_prop_t prop, char *buf, size_t buflen)
+const char *
+zfs_prop_default_string(zfs_prop_t prop)
 {
-	(void) strncpy(buf, zfs_prop_table[prop].pd_strdefault, buflen);
+	return (zfs_prop_table[prop].pd_strdefault);
 }
 
 uint64_t
--- a/usr/src/lib/libzfs/common/libzfs.h	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/lib/libzfs/common/libzfs.h	Mon Jan 30 22:19:55 2006 -0800
@@ -183,7 +183,7 @@
 int zfs_prop_inherit(zfs_handle_t *, zfs_prop_t);
 const char *zfs_prop_values(zfs_prop_t);
 int zfs_prop_valid_for_type(zfs_prop_t, int);
-void zfs_prop_default_string(zfs_prop_t prop, char *buf, size_t buflen);
+const char *zfs_prop_default_string(zfs_prop_t prop);
 uint64_t zfs_prop_default_numeric(zfs_prop_t);
 int zfs_prop_is_string(zfs_prop_t prop);
 const char *zfs_prop_column_name(zfs_prop_t);
@@ -201,6 +201,8 @@
 extern int zfs_iter_root(zfs_iter_f, void *);
 extern int zfs_iter_children(zfs_handle_t *, zfs_iter_f, void *);
 extern int zfs_iter_dependents(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_filesystems(zfs_handle_t *, zfs_iter_f, void *);
+extern int zfs_iter_snapshots(zfs_handle_t *, zfs_iter_f, void *);
 
 /*
  * Functions to create and destroy datasets.
--- a/usr/src/lib/libzfs/common/libzfs_dataset.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/lib/libzfs/common/libzfs_dataset.c	Mon Jan 30 22:19:55 2006 -0800
@@ -190,16 +190,24 @@
 
 	(void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 
-	/*
-	 * get the generic DMU stats and per-type (zfs, zvol) stats
-	 */
-	if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0)
-		return (-1);
+	zc.zc_config_src = (uint64_t)(uintptr_t)zfs_malloc(1024);
+	zc.zc_config_src_size = 1024;
+
+	while (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
+		if (errno == ENOMEM) {
+			zc.zc_config_src = (uint64_t)(uintptr_t)
+			    zfs_malloc(zc.zc_config_src_size);
+		} else {
+			free((void *)(uintptr_t)zc.zc_config_src);
+			return (-1);
+		}
+	}
 
 	bcopy(&zc.zc_objset_stats, &zhp->zfs_dmustats,
 	    sizeof (zc.zc_objset_stats));
 
-	bcopy(&zc.zc_zfs_stats, &zhp->zfs_zplstats, sizeof (zc.zc_zfs_stats));
+	verify(nvlist_unpack((void *)(uintptr_t)zc.zc_config_src,
+	    zc.zc_config_src_size, &zhp->zfs_props, 0) == 0);
 
 	zhp->zfs_volsize = zc.zc_volsize;
 	zhp->zfs_volblocksize = zc.zc_volblocksize;
@@ -1041,6 +1049,47 @@
 }
 
 /*
+ * True DSL properties are stored in an nvlist.  The following two functions
+ * extract them appropriately.
+ */
+static uint64_t
+getprop_uint64(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
+{
+	nvlist_t *nv;
+	uint64_t value;
+
+	if (nvlist_lookup_nvlist(zhp->zfs_props,
+	    zfs_prop_to_name(prop), &nv) == 0) {
+		verify(nvlist_lookup_uint64(nv, ZFS_PROP_VALUE, &value) == 0);
+		verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0);
+	} else {
+		value = zfs_prop_default_numeric(prop);
+		*source = "";
+	}
+
+	return (value);
+}
+
+static char *
+getprop_string(zfs_handle_t *zhp, zfs_prop_t prop, char **source)
+{
+	nvlist_t *nv;
+	char *value;
+
+	if (nvlist_lookup_nvlist(zhp->zfs_props,
+	    zfs_prop_to_name(prop), &nv) == 0) {
+		verify(nvlist_lookup_string(nv, ZFS_PROP_VALUE, &value) == 0);
+		verify(nvlist_lookup_string(nv, ZFS_PROP_SOURCE, source) == 0);
+	} else {
+		if ((value = (char *)zfs_prop_default_string(prop)) == NULL)
+			value = "";
+		*source = "";
+	}
+
+	return (value);
+}
+
+/*
  * Internal function for getting a numeric property.  Both zfs_prop_get() and
  * zfs_prop_get_int() are built using this interface.
  *
@@ -1065,8 +1114,7 @@
 
 	switch (prop) {
 	case ZFS_PROP_ATIME:
-		*source = zhp->zfs_zplstats.zs_atime_setpoint;
-		val = zhp->zfs_zplstats.zs_devices;
+		val = getprop_uint64(zhp, prop, source);
 
 		if (hasmntopt(&mnt, MNTOPT_ATIME) && !val) {
 			val = TRUE;
@@ -1077,14 +1125,13 @@
 			if (src)
 				*src = ZFS_SRC_TEMPORARY;
 		}
-		return (zhp->zfs_zplstats.zs_atime);
+		return (val);
 
 	case ZFS_PROP_AVAILABLE:
 		return (zhp->zfs_dmustats.dds_available);
 
 	case ZFS_PROP_DEVICES:
-		*source = zhp->zfs_zplstats.zs_devices_setpoint;
-		val = zhp->zfs_zplstats.zs_devices;
+		val = getprop_uint64(zhp, prop, source);
 
 		if (hasmntopt(&mnt, MNTOPT_DEVICES) && !val) {
 			val = TRUE;
@@ -1098,8 +1145,7 @@
 		return (val);
 
 	case ZFS_PROP_EXEC:
-		*source = zhp->zfs_zplstats.zs_exec_setpoint;
-		val = zhp->zfs_zplstats.zs_exec;
+		val = getprop_uint64(zhp, prop, source);
 
 		if (hasmntopt(&mnt, MNTOPT_EXEC) && !val) {
 			val = TRUE;
@@ -1113,16 +1159,13 @@
 		return (val);
 
 	case ZFS_PROP_RECORDSIZE:
-		*source = zhp->zfs_zplstats.zs_recordsize_setpoint;
-		return (zhp->zfs_zplstats.zs_recordsize);
-
 	case ZFS_PROP_COMPRESSION:
-		*source = zhp->zfs_dmustats.dds_compression_setpoint;
-		return (zhp->zfs_dmustats.dds_compression);
+	case ZFS_PROP_ZONED:
+		val = getprop_uint64(zhp, prop, source);
+		return (val);
 
 	case ZFS_PROP_READONLY:
-		*source = zhp->zfs_zplstats.zs_readonly_setpoint;
-		val = zhp->zfs_zplstats.zs_readonly;
+		val = getprop_uint64(zhp, prop, source);
 
 		if (hasmntopt(&mnt, MNTOPT_RO) && !val) {
 			val = TRUE;
@@ -1169,8 +1212,7 @@
 		return (zhp->zfs_dmustats.dds_space_refd);
 
 	case ZFS_PROP_SETUID:
-		*source = zhp->zfs_zplstats.zs_setuid_setpoint;
-		val = zhp->zfs_zplstats.zs_setuid;
+		val = getprop_uint64(zhp, prop, source);
 
 		if (hasmntopt(&mnt, MNTOPT_SETUID) && !val) {
 			val = TRUE;
@@ -1189,10 +1231,6 @@
 	case ZFS_PROP_VOLBLOCKSIZE:
 		return (zhp->zfs_volblocksize);
 
-	case ZFS_PROP_ZONED:
-		*source = zhp->zfs_dmustats.dds_zoned_setpoint;
-		return (zhp->zfs_dmustats.dds_zoned);
-
 	case ZFS_PROP_USED:
 		return (zhp->zfs_dmustats.dds_space_used);
 
@@ -1312,58 +1350,53 @@
 		break;
 
 	case ZFS_PROP_COMPRESSION:
+		val = getprop_uint64(zhp, prop, &source);
 		for (i = 0; compress_table[i].name != NULL; i++) {
-			if (compress_table[i].value ==
-			    zhp->zfs_dmustats.dds_compression)
+			if (compress_table[i].value == val)
 				break;
 		}
 		assert(compress_table[i].name != NULL);
 		(void) strlcpy(propbuf, compress_table[i].name, proplen);
-		source = zhp->zfs_dmustats.dds_compression_setpoint;
 		break;
 
 	case ZFS_PROP_CHECKSUM:
+		val = getprop_uint64(zhp, prop, &source);
 		for (i = 0; checksum_table[i].name != NULL; i++) {
-			if (checksum_table[i].value ==
-			    zhp->zfs_dmustats.dds_checksum)
+			if (checksum_table[i].value == val)
 				break;
 		}
 		assert(checksum_table[i].name != NULL);
 		(void) strlcpy(propbuf, checksum_table[i].name, proplen);
-		source = zhp->zfs_dmustats.dds_checksum_setpoint;
 		break;
 
 	case ZFS_PROP_SNAPDIR:
+		val = getprop_uint64(zhp, prop, &source);
 		for (i = 0; snapdir_table[i].name != NULL; i++) {
-			if (snapdir_table[i].value ==
-			    zhp->zfs_zplstats.zs_snapdir)
+			if (snapdir_table[i].value == val)
 				break;
 		}
 		assert(snapdir_table[i].name != NULL);
 		(void) strlcpy(propbuf, snapdir_table[i].name, proplen);
-		source = zhp->zfs_zplstats.zs_snapdir_setpoint;
 		break;
 
 	case ZFS_PROP_ACLMODE:
+		val = getprop_uint64(zhp, prop, &source);
 		for (i = 0; acl_mode_table[i].name != NULL; i++) {
-			if (acl_mode_table[i].value ==
-			    zhp->zfs_zplstats.zs_acl_mode)
+			if (acl_mode_table[i].value == val)
 				break;
 		}
 		assert(acl_mode_table[i].name != NULL);
 		(void) strlcpy(propbuf, acl_mode_table[i].name, proplen);
-		source = zhp->zfs_zplstats.zs_acl_mode_setpoint;
 		break;
 
 	case ZFS_PROP_ACLINHERIT:
+		val = getprop_uint64(zhp, prop, &source);
 		for (i = 0; acl_inherit_table[i].name != NULL; i++) {
-			if (acl_inherit_table[i].value ==
-			    zhp->zfs_zplstats.zs_acl_inherit)
+			if (acl_inherit_table[i].value == val)
 				break;
 		}
 		assert(acl_inherit_table[i].name != NULL);
 		(void) strlcpy(propbuf, acl_inherit_table[i].name, proplen);
-		source = zhp->zfs_zplstats.zs_acl_inherit_setpoint;
 		break;
 
 	case ZFS_PROP_CREATION:
@@ -1398,44 +1431,40 @@
 		 * root to any values we return.
 		 */
 		root = zhp->zfs_dmustats.dds_altroot;
-
-		if (zhp->zfs_zplstats.zs_mountpoint[0] == '\0') {
+		str = getprop_string(zhp, prop, &source);
+
+		if (str[0] == '\0') {
 			(void) snprintf(propbuf, proplen, "%s/zfs/%s",
 			    root, zhp->zfs_name);
-		} else if (zhp->zfs_zplstats.zs_mountpoint[0] == '/') {
-			const char *relpath = zhp->zfs_name +
-			    strlen(zhp->zfs_zplstats.zs_mountpoint_setpoint);
-			const char *mntpoint = zhp->zfs_zplstats.zs_mountpoint;
+		} else if (str[0] == '/') {
+			const char *relpath = zhp->zfs_name + strlen(source);
 
 			if (relpath[0] == '/')
 				relpath++;
-			if (mntpoint[1] == '\0')
-				mntpoint++;
+			if (str[1] == '\0')
+				str++;
 
 			if (relpath[0] == '\0')
 				(void) snprintf(propbuf, proplen, "%s%s",
-				    root, mntpoint);
+				    root, str);
 			else
 				(void) snprintf(propbuf, proplen, "%s%s%s%s",
-				    root, mntpoint,
-				    relpath[0] == '@' ? "" : "/",
+				    root, str, relpath[0] == '@' ? "" : "/",
 				    relpath);
 		} else {
 			/* 'legacy' or 'none' */
-			(void) strlcpy(propbuf, zhp->zfs_zplstats.zs_mountpoint,
-			    proplen);
+			(void) strlcpy(propbuf, str, proplen);
 		}
 
-		source = zhp->zfs_zplstats.zs_mountpoint_setpoint;
 		break;
 
 	case ZFS_PROP_SHARENFS:
-		(void) strlcpy(propbuf, zhp->zfs_zplstats.zs_sharenfs, proplen);
-		source = zhp->zfs_zplstats.zs_sharenfs_setpoint;
+		(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
+		    proplen);
 		break;
 
 	case ZFS_PROP_ORIGIN:
-		(void) strlcpy(propbuf, zhp->zfs_dmustats.dds_clone_of,
+		(void) strlcpy(propbuf, getprop_string(zhp, prop, &source),
 		    proplen);
 		/*
 		 * If there is no parent at all, return failure to indicate that
@@ -1580,10 +1609,10 @@
 }
 
 /*
- * Iterate over all children, datasets and snapshots.
+ * Iterate over all child filesystems
  */
 int
-zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+zfs_iter_filesystems(zfs_handle_t *zhp, zfs_iter_f func, void *data)
 {
 	zfs_cmd_t zc = { 0 };
 	zfs_handle_t *nzhp;
@@ -1617,7 +1646,18 @@
 	if (errno != ESRCH && errno != ENOENT)
 		zfs_baderror(errno);
 
-	bzero(&zc, sizeof (zc));
+	return (0);
+}
+
+/*
+ * Iterate over all snapshots
+ */
+int
+zfs_iter_snapshots(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+	zfs_cmd_t zc = { 0 };
+	zfs_handle_t *nzhp;
+	int ret;
 
 	for ((void) strlcpy(zc.zc_name, zhp->zfs_name, sizeof (zc.zc_name));
 	    ioctl(zfs_fd, ZFS_IOC_SNAPSHOT_LIST_NEXT, &zc) == 0;
@@ -1642,6 +1682,20 @@
 }
 
 /*
+ * Iterate over all children, snapshots and filesystems
+ */
+int
+zfs_iter_children(zfs_handle_t *zhp, zfs_iter_f func, void *data)
+{
+	int ret;
+
+	if ((ret = zfs_iter_filesystems(zhp, func, data)) != 0)
+		return (ret);
+
+	return (zfs_iter_snapshots(zhp, func, data));
+}
+
+/*
  * Given a complete name, return just the portion that refers to the parent.
  * Can return NULL if this is a pool.
  */
@@ -1668,6 +1722,7 @@
 	zfs_cmd_t zc = { 0 };
 	char parent[ZFS_MAXNAMELEN];
 	char *slash;
+	zfs_handle_t *zhp;
 
 	/* get parent, and check to see if this is just a pool */
 	if (parent_name(path, parent, sizeof (parent)) != 0) {
@@ -1692,8 +1747,7 @@
 	}
 
 	/* check to see if the parent dataset exists */
-	(void) strlcpy(zc.zc_name, parent, sizeof (zc.zc_name));
-	if (ioctl(zfs_fd, ZFS_IOC_OBJSET_STATS, &zc) != 0) {
+	if ((zhp = make_dataset_handle(parent)) == NULL) {
 		switch (errno) {
 		case ENOENT:
 			zfs_error(dgettext(TEXT_DOMAIN,
@@ -1706,20 +1760,24 @@
 	}
 
 	/* we are in a non-global zone, but parent is in the global zone */
-	if (getzoneid() != GLOBAL_ZONEID && !zc.zc_objset_stats.dds_zoned) {
+	if (getzoneid() != GLOBAL_ZONEID &&
+	    zfs_prop_get_int(zhp, ZFS_PROP_ZONED)) {
 		zfs_error(dgettext(TEXT_DOMAIN,
 		    "cannot create '%s': permission denied"), path);
+		zfs_close(zhp);
 		return (-1);
 	}
 
 	/* make sure parent is a filesystem */
-	if (zc.zc_objset_stats.dds_type != DMU_OST_ZFS) {
+	if (zfs_get_type(zhp) != ZFS_TYPE_FILESYSTEM) {
 		zfs_error(dgettext(TEXT_DOMAIN,
 		    "cannot create '%s': parent is not a filesystem"),
 		    path);
+		zfs_close(zhp);
 		return (-1);
 	}
 
+	zfs_close(zhp);
 	return (0);
 }
 
--- a/usr/src/lib/libzfs/common/libzfs_impl.h	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/lib/libzfs/common/libzfs_impl.h	Mon Jan 30 22:19:55 2006 -0800
@@ -45,7 +45,7 @@
 	char zfs_name[ZFS_MAXNAMELEN];
 	zfs_type_t zfs_type;
 	dmu_objset_stats_t zfs_dmustats;
-	zfs_stats_t zfs_zplstats;
+	nvlist_t *zfs_props;
 	uint64_t zfs_volsize;
 	uint64_t zfs_volblocksize;
 	char *zfs_mntopts;
--- a/usr/src/lib/libzfs/spec/libzfs.spec	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/lib/libzfs/spec/libzfs.spec	Mon Jan 30 22:19:55 2006 -0800
@@ -80,10 +80,18 @@
 version SUNWprivate_1.1
 end
 
+function zfs_iter_filesystems
+version SUNWprivate_1.1
+end
+
 function zfs_iter_root
 version SUNWprivate_1.1
 end
 
+function zfs_iter_snapshots
+version SUNWprivate_1.1
+end
+
 function zfs_mount
 version SUNWprivate_1.1
 end
--- a/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/lib/libzfs_jni/common/libzfs_jni_property.c	Mon Jan 30 22:19:55 2006 -0800
@@ -333,9 +333,7 @@
 		jobject propValue;
 
 		if (convert_str != NULL) {
-			char propbuf[ZFS_MAXPROPLEN];
-			zfs_prop_default_string(
-			    prop, propbuf, sizeof (propbuf));
+			char *propbuf = (char *)zfs_prop_default_string(prop);
 			propValue = convert_str(env, propbuf);
 		} else {
 			uint64_t value = zfs_prop_default_numeric(prop);
@@ -406,9 +404,7 @@
 		jobject propValue;
 
 		if (convert_str != NULL) {
-			char propbuf[ZFS_MAXPROPLEN];
-			zfs_prop_default_string(
-			    prop, propbuf, sizeof (propbuf));
+			char *propbuf = (char *)zfs_prop_default_string(prop);
 			propValue = convert_str(env, propbuf);
 		} else {
 			uint64_t value = zfs_prop_default_numeric(prop);
--- a/usr/src/uts/common/fs/zfs/dsl_dir.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/dsl_dir.c	Mon Jan 30 22:19:55 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -557,15 +557,6 @@
 		rw_exit(&dd->dd_pool->dp_config_rwlock);
 	}
 
-	VERIFY(dsl_prop_get_ds_integer(dd, "checksum",
-	    &dds->dds_checksum, dds->dds_checksum_setpoint) == 0);
-
-	VERIFY(dsl_prop_get_ds_integer(dd, "compression",
-	    &dds->dds_compression, dds->dds_compression_setpoint) == 0);
-
-	VERIFY(dsl_prop_get_ds_integer(dd, "zoned",
-	    &dds->dds_zoned, dds->dds_zoned_setpoint) == 0);
-
 	spa_altroot(dd->dd_pool->dp_spa, dds->dds_altroot,
 	    sizeof (dds->dds_altroot));
 }
--- a/usr/src/uts/common/fs/zfs/dsl_prop.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/dsl_prop.c	Mon Jan 30 22:19:55 2006 -0800
@@ -20,13 +20,14 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
 #pragma ident	"%Z%%M%	%I%	%E% SMI"
 
 #include <sys/dmu.h>
+#include <sys/dmu_objset.h>
 #include <sys/dmu_tx.h>
 #include <sys/dsl_dataset.h>
 #include <sys/dsl_dir.h>
@@ -50,7 +51,7 @@
 	if (zfs_prop_get_type(prop) == prop_type_string) {
 		if (intsz != 1)
 			return (EOVERFLOW);
-		zfs_prop_default_string(prop, buf, numint);
+		(void) strncpy(buf, zfs_prop_default_string(prop), numint);
 	} else {
 		if (intsz != 8 || numint < 1)
 			return (EOVERFLOW);
@@ -366,3 +367,103 @@
 
 	return (err);
 }
+
+/*
+ * Iterate over all properties for this dataset and return them in an nvlist.
+ */
+int
+dsl_prop_get_all(objset_t *os, nvlist_t **nvp)
+{
+	dsl_dataset_t *ds = os->os->os_dsl_dataset;
+	dsl_dir_t *dd, *parent;
+	int err = 0;
+	dsl_pool_t *dp;
+	objset_t *mos;
+	zap_cursor_t zc;
+	zap_attribute_t za;
+	char setpoint[MAXNAMELEN];
+	char *tmp;
+	nvlist_t *prop;
+
+	if (dsl_dataset_is_snapshot(ds)) {
+		VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+		return (0);
+	}
+
+	dd = ds->ds_dir;
+
+	VERIFY(nvlist_alloc(nvp, NV_UNIQUE_NAME, KM_SLEEP) == 0);
+
+	dp = dd->dd_pool;
+	mos = dp->dp_meta_objset;
+
+	rw_enter(&dp->dp_config_rwlock, RW_READER);
+	while (dd != NULL) {
+		dsl_dir_name(dd, setpoint);
+
+		for (zap_cursor_init(&zc, mos, dd->dd_phys->dd_props_zapobj);
+		    (err = zap_cursor_retrieve(&zc, &za)) == 0;
+		    zap_cursor_advance(&zc)) {
+			if (nvlist_lookup_nvlist(*nvp, za.za_name, &prop) == 0)
+				continue;
+
+			VERIFY(nvlist_alloc(&prop, NV_UNIQUE_NAME,
+			    KM_SLEEP) == 0);
+			if (za.za_integer_length == 1) {
+				/*
+				 * String property
+				 */
+
+				tmp = kmem_alloc(za.za_num_integers, KM_SLEEP);
+				err = zap_lookup(mos,
+				    dd->dd_phys->dd_props_zapobj,
+				    za.za_name, 1, za.za_num_integers,
+				    tmp);
+				if (err != 0) {
+					kmem_free(tmp, za.za_num_integers);
+					break;
+				}
+				VERIFY(nvlist_add_string(prop,
+				    ZFS_PROP_VALUE, tmp) == 0);
+				kmem_free(tmp, za.za_num_integers);
+			} else {
+				/*
+				 * Integer property
+				 */
+				ASSERT(za.za_integer_length == 8);
+				(void) nvlist_add_uint64(prop, ZFS_PROP_VALUE,
+				    za.za_first_integer);
+			}
+
+			VERIFY(nvlist_add_string(prop,
+			    ZFS_PROP_SOURCE, setpoint) == 0);
+			VERIFY(nvlist_add_nvlist(*nvp, za.za_name,
+			    prop) == 0);
+			nvlist_free(prop);
+		}
+		zap_cursor_fini(&zc);
+
+		if (err != ENOENT) {
+			if (dd != ds->ds_dir)
+				dsl_dir_close(dd, FTAG);
+			break;
+		} else {
+			err = 0;
+		}
+
+		/*
+		 * Continue to parent.
+		 */
+		if (dd->dd_phys->dd_parent_obj == 0)
+			parent = NULL;
+		else
+			parent = dsl_dir_open_obj(dp,
+			    dd->dd_phys->dd_parent_obj, NULL, FTAG);
+		if (dd != ds->ds_dir)
+			dsl_dir_close(dd, FTAG);
+		dd = parent;
+	}
+	rw_exit(&dp->dp_config_rwlock);
+
+	return (err);
+}
--- a/usr/src/uts/common/fs/zfs/sys/dmu.h	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/sys/dmu.h	Mon Jan 30 22:19:55 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -553,14 +553,8 @@
 	uint64_t dds_available;
 
 	/*
-	 * Various properties.
+	 * Miscellaneous
 	 */
-	uint64_t dds_compression;
-	uint64_t dds_checksum;
-	uint64_t dds_zoned;
-	char dds_compression_setpoint[MAXNAMELEN];
-	char dds_checksum_setpoint[MAXNAMELEN];
-	char dds_zoned_setpoint[MAXNAMELEN];
 	char dds_altroot[MAXPATHLEN];
 
 	/* The following are for debugging purposes only */
--- a/usr/src/uts/common/fs/zfs/sys/dsl_prop.h	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/sys/dsl_prop.h	Mon Jan 30 22:19:55 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -64,6 +64,7 @@
     uint64_t *valuep, char *setpoint);
 int dsl_prop_get_ds_integer(dsl_dir_t *dd, const char *propname,
     uint64_t *valuep, char *setpoint);
+int dsl_prop_get_all(objset_t *os, nvlist_t **nvp);
 
 int dsl_prop_set(const char *ddname, const char *propname,
     int intsz, int numints, const void *buf);
--- a/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/sys/zfs_ioctl.h	Mon Jan 30 22:19:55 2006 -0800
@@ -42,31 +42,6 @@
 #define	ZFS_SNAPDIR_HIDDEN		0
 #define	ZFS_SNAPDIR_VISIBLE		1
 
-typedef struct zfs_stats {
-	uint64_t	zs_atime;
-	uint64_t	zs_recordsize;
-	uint64_t	zs_readonly;
-	uint64_t	zs_devices;
-	uint64_t	zs_exec;
-	uint64_t	zs_setuid;
-	uint64_t	zs_snapdir;
-	uint64_t	zs_acl_mode;
-	uint64_t	zs_acl_inherit;
-	char		zs_mountpoint[MAXPATHLEN];
-	char		zs_atime_setpoint[MAXNAMELEN];
-	char		zs_recordsize_setpoint[MAXNAMELEN];
-	char		zs_readonly_setpoint[MAXNAMELEN];
-	char		zs_devices_setpoint[MAXNAMELEN];
-	char		zs_setuid_setpoint[MAXNAMELEN];
-	char		zs_exec_setpoint[MAXNAMELEN];
-	char		zs_mountpoint_setpoint[MAXNAMELEN];
-	char		zs_sharenfs[MAXPATHLEN];
-	char		zs_sharenfs_setpoint[MAXNAMELEN];
-	char		zs_snapdir_setpoint[MAXNAMELEN];
-	char		zs_acl_mode_setpoint[MAXNAMELEN];
-	char		zs_acl_inherit_setpoint[MAXNAMELEN];
-} zfs_stats_t;
-
 #define	DMU_BACKUP_VERSION (1ULL)
 #define	DMU_BACKUP_MAGIC 0x2F5bacbacULL
 
@@ -141,7 +116,6 @@
 	uint64_t	zc_volsize;
 	uint64_t	zc_volblocksize;
 	uint64_t	zc_objset_type;
-	zfs_stats_t	zc_zfs_stats;
 	dmu_object_info_t zc_object_info;
 	dmu_objset_stats_t zc_objset_stats;
 	struct drr_begin zc_begin_record;
--- a/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/zfs_ioctl.c	Mon Jan 30 22:19:55 2006 -0800
@@ -640,46 +640,13 @@
 
 
 static int
-zfs_get_stats(zfs_cmd_t *zc)
-{
-	char *name = zc->zc_name;
-	zfs_stats_t *zs = &zc->zc_zfs_stats;
-	int error;
-
-	bzero(zs, sizeof (zfs_stats_t));
-
-	if ((error = dsl_prop_get_integer(name, "atime",
-	    &zs->zs_atime, zs->zs_atime_setpoint)) != 0 ||
-	    (error = dsl_prop_get_integer(name, "recordsize",
-	    &zs->zs_recordsize, zs->zs_recordsize_setpoint)) != 0 ||
-	    (error = dsl_prop_get_integer(name, "readonly",
-	    &zs->zs_readonly, zs->zs_readonly_setpoint)) != 0 ||
-	    (error = dsl_prop_get_integer(name, "devices",
-	    &zs->zs_devices, zs->zs_devices_setpoint)) != 0 ||
-	    (error = dsl_prop_get_integer(name, "setuid",
-	    &zs->zs_setuid, zs->zs_setuid_setpoint)) != 0 ||
-	    (error = dsl_prop_get_integer(name, "exec",
-	    &zs->zs_exec, zs->zs_exec_setpoint)) != 0 ||
-	    (error = dsl_prop_get_string(name, "mountpoint", zs->zs_mountpoint,
-	    sizeof (zs->zs_mountpoint), zs->zs_mountpoint_setpoint)) != 0 ||
-	    (error = dsl_prop_get_string(name, "sharenfs", zs->zs_sharenfs,
-	    sizeof (zs->zs_sharenfs), zs->zs_sharenfs_setpoint)) != 0 ||
-	    (error = dsl_prop_get_integer(name, "aclmode",
-	    &zs->zs_acl_mode, zs->zs_acl_mode_setpoint)) != 0 ||
-	    (error = dsl_prop_get_integer(name, "snapdir",
-	    &zs->zs_snapdir, zs->zs_snapdir_setpoint)) != 0 ||
-	    (error = dsl_prop_get_integer(name, "aclinherit",
-	    &zs->zs_acl_inherit, zs->zs_acl_inherit_setpoint)) != 0)
-		return (error);
-
-	return (0);
-}
-
-static int
 zfs_ioc_objset_stats(zfs_cmd_t *zc)
 {
 	objset_t *os = NULL;
 	int error;
+	nvlist_t *nv;
+	size_t sz;
+	char *buf;
 
 retry:
 	error = dmu_objset_open(zc->zc_name, DMU_OST_ANY,
@@ -701,16 +668,25 @@
 
 	dmu_objset_stats(os, &zc->zc_objset_stats);
 
-	switch (zc->zc_objset_stats.dds_type) {
+	if (zc->zc_config_src != NULL &&
+	    (error = dsl_prop_get_all(os, &nv)) == 0) {
+		VERIFY(nvlist_size(nv, &sz, NV_ENCODE_NATIVE) == 0);
+		if (sz > zc->zc_config_src_size) {
+			zc->zc_config_src_size = sz;
+			error = ENOMEM;
+		} else {
+			buf = kmem_alloc(sz, KM_SLEEP);
+			VERIFY(nvlist_pack(nv, &buf, &sz,
+			    NV_ENCODE_NATIVE, 0) == 0);
+			error = xcopyout(buf,
+			    (void *)(uintptr_t)zc->zc_config_src, sz);
+			kmem_free(buf, sz);
+		}
+		nvlist_free(nv);
+	}
 
-	case DMU_OST_ZFS:
-		error = zfs_get_stats(zc);
-		break;
-
-	case DMU_OST_ZVOL:
+	if (!error && zc->zc_objset_stats.dds_type == DMU_OST_ZVOL)
 		error = zvol_get_stats(zc, os);
-		break;
-	}
 
 	dmu_objset_close(os);
 	return (error);
--- a/usr/src/uts/common/fs/zfs/zvol.c	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/uts/common/fs/zfs/zvol.c	Mon Jan 30 22:19:55 2006 -0800
@@ -20,7 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -165,10 +165,6 @@
 	if (error == 0)
 		zc->zc_volblocksize = doi.doi_data_block_size;
 
-	error = dsl_prop_get_integer(zc->zc_name, "readonly",
-			&zc->zc_zfs_stats.zs_readonly,
-			zc->zc_zfs_stats.zs_readonly_setpoint);
-
 	return (error);
 }
 
--- a/usr/src/uts/common/sys/fs/zfs.h	Mon Jan 30 21:43:33 2006 -0800
+++ b/usr/src/uts/common/sys/fs/zfs.h	Mon Jan 30 22:19:55 2006 -0800
@@ -96,12 +96,15 @@
 
 #define	ZFS_NPROP_VISIBLE	ZFS_PROP_CREATETXG
 
+#define	ZFS_PROP_VALUE		"value"
+#define	ZFS_PROP_SOURCE		"source"
+
 /*
  * The following functions are shared between libzfs and the kernel.
  */
 zfs_prop_t zfs_name_to_prop(const char *);
 int zfs_prop_readonly(zfs_prop_t);
-void zfs_prop_default_string(zfs_prop_t, char *, size_t);
+const char *zfs_prop_default_string(zfs_prop_t);
 uint64_t zfs_prop_default_numeric(zfs_prop_t);
 
 /*