PSARC 2010/144 lofi(7D) in non global zones
authorJohn Levon <john.levon@sun.com>
Wed, 16 Jun 2010 10:02:44 -0700
changeset 12633 9f2cda0ed938
parent 12632 2e5ce9dbe1f9
child 12634 09fce1ed6a60
PSARC 2010/144 lofi(7D) in non global zones 6354954 lofi support in non-global zones 6942891 prof_lookup_globaldev() leaks rootdir refs 6945005 lofiadm -a /dev/lofi/1: recursive mutex enter 6946486 lofi_ioctl() shouldn't allow disk ioctl()s on /dev/lofictl
usr/src/cmd/zoneadmd/vplat.c
usr/src/cmd/zonecfg/zonecfg.c
usr/src/cmd/zonecfg/zonecfg.h
usr/src/cmd/zonecfg/zonecfg_grammar.y
usr/src/cmd/zonecfg/zonecfg_lex.l
usr/src/head/libzonecfg.h
usr/src/lib/brand/ipkg/zone/platform.xml
usr/src/lib/brand/sn1/zone/platform.xml
usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c
usr/src/lib/brand/solaris10/zone/platform.xml
usr/src/lib/libzonecfg/common/libzonecfg.c
usr/src/lib/libzonecfg/common/mapfile-vers
usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1
usr/src/uts/common/fs/autofs/auto_vfsops.c
usr/src/uts/common/fs/ctfs/ctfs_root.c
usr/src/uts/common/fs/dcfs/dc_vnops.c
usr/src/uts/common/fs/dev/sdev_profile.c
usr/src/uts/common/fs/dev/sdev_subr.c
usr/src/uts/common/fs/fd/fdops.c
usr/src/uts/common/fs/fifofs/fifosubr.c
usr/src/uts/common/fs/hsfs/hsfs_vfsops.c
usr/src/uts/common/fs/lofs/lofs_vfsops.c
usr/src/uts/common/fs/mntfs/mntvfsops.c
usr/src/uts/common/fs/namefs/namevfs.c
usr/src/uts/common/fs/nfs/nfs4_common.c
usr/src/uts/common/fs/nfs/nfs_common.c
usr/src/uts/common/fs/objfs/objfs_vfs.c
usr/src/uts/common/fs/proc/prvfsops.c
usr/src/uts/common/fs/sharefs/sharefs_vfsops.c
usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c
usr/src/uts/common/fs/sockfs/sockvfsops.c
usr/src/uts/common/fs/specfs/specvfsops.c
usr/src/uts/common/fs/tmpfs/tmp_vfsops.c
usr/src/uts/common/fs/vfs.c
usr/src/uts/common/fs/zfs/zfs_vfsops.c
usr/src/uts/common/io/lofi.c
usr/src/uts/common/os/id_space.c
usr/src/uts/common/os/policy.c
usr/src/uts/common/os/rctl.c
usr/src/uts/common/os/zone.c
usr/src/uts/common/sys/fs/sdev_impl.h
usr/src/uts/common/sys/id_space.h
usr/src/uts/common/sys/lofi.h
usr/src/uts/common/sys/policy.h
usr/src/uts/common/sys/rctl.h
usr/src/uts/common/sys/vfs.h
usr/src/uts/common/sys/zone.h
--- a/usr/src/cmd/zoneadmd/vplat.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/cmd/zoneadmd/vplat.c	Wed Jun 16 10:02:44 2010 -0700
@@ -20,8 +20,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -4109,6 +4108,25 @@
 	return (Z_OK);
 }
 
+static void
+report_prop_err(zlog_t *zlogp, const char *name, const char *value, int res)
+{
+	switch (res) {
+	case Z_TOO_BIG:
+		zerror(zlogp, B_FALSE, "%s property value is too large.", name);
+		break;
+
+	case Z_INVALID_PROPERTY:
+		zerror(zlogp, B_FALSE, "%s property value \"%s\" is not valid",
+		    name, value);
+		break;
+
+	default:
+		zerror(zlogp, B_TRUE, "fetching property %s: %d", name, res);
+		break;
+	}
+}
+
 /*
  * Sets the hostid of the new zone based on its configured value.  The zone's
  * zone_t structure must already exist in kernel memory.  'zlogp' refers to the
@@ -4119,57 +4137,81 @@
  * This function returns zero on success and a nonzero error code on failure.
  */
 static int
-setup_zone_hostid(zlog_t *zlogp, char *zone_namep, zoneid_t zoneid)
+setup_zone_hostid(zone_dochandle_t handle, zlog_t *zlogp, zoneid_t zoneid)
 {
 	int res;
-	zone_dochandle_t handle;
 	char hostidp[HW_HOSTID_LEN];
 	unsigned int hostid;
 
+	res = zonecfg_get_hostid(handle, hostidp, sizeof (hostidp));
+
+	if (res == Z_BAD_PROPERTY) {
+		return (Z_OK);
+	} else if (res != Z_OK) {
+		report_prop_err(zlogp, "hostid", hostidp, res);
+		return (res);
+	}
+
+	hostid = (unsigned int)strtoul(hostidp, NULL, 16);
+	if ((res = zone_setattr(zoneid, ZONE_ATTR_HOSTID, &hostid,
+	    sizeof (hostid))) != 0) {
+		zerror(zlogp, B_TRUE,
+		    "zone hostid is not valid: %s: %d", hostidp, res);
+		return (Z_SYSTEM);
+	}
+
+	return (res);
+}
+
+static int
+setup_zone_fs_allowed(zone_dochandle_t handle, zlog_t *zlogp, zoneid_t zoneid)
+{
+	char fsallowedp[ZONE_FS_ALLOWED_MAX];
+	int res;
+
+	res = zonecfg_get_fs_allowed(handle, fsallowedp, sizeof (fsallowedp));
+
+	if (res == Z_BAD_PROPERTY) {
+		return (Z_OK);
+	} else if (res != Z_OK) {
+		report_prop_err(zlogp, "fs-allowed", fsallowedp, res);
+		return (res);
+	}
+
+	if (zone_setattr(zoneid, ZONE_ATTR_FS_ALLOWED, &fsallowedp,
+	    sizeof (fsallowedp)) != 0) {
+		zerror(zlogp, B_TRUE,
+		    "fs-allowed couldn't be set: %s: %d", fsallowedp, res);
+		return (Z_SYSTEM);
+	}
+
+	return (res);
+}
+
+static int
+setup_zone_attrs(zlog_t *zlogp, char *zone_namep, zoneid_t zoneid)
+{
+	zone_dochandle_t handle;
+	int res = Z_OK;
+
 	if ((handle = zonecfg_init_handle()) == NULL) {
 		zerror(zlogp, B_TRUE, "getting zone configuration handle");
 		return (Z_BAD_HANDLE);
 	}
 	if ((res = zonecfg_get_snapshot_handle(zone_namep, handle)) != Z_OK) {
 		zerror(zlogp, B_FALSE, "invalid configuration");
-		zonecfg_fini_handle(handle);
-		return (res);
-	}
-
-	if ((res = zonecfg_get_hostid(handle, hostidp, sizeof (hostidp))) ==
-	    Z_OK) {
-		if (zonecfg_valid_hostid(hostidp) != Z_OK) {
-			zerror(zlogp, B_FALSE,
-			    "zone hostid is not valid: %s", hostidp);
-			zonecfg_fini_handle(handle);
-			return (Z_HOSTID_FUBAR);
-		}
-		hostid = (unsigned int)strtoul(hostidp, NULL, 16);
-		if (zone_setattr(zoneid, ZONE_ATTR_HOSTID, &hostid,
-		    sizeof (hostid)) != 0) {
-			zerror(zlogp, B_TRUE,
-			    "zone hostid is not valid: %s", hostidp);
-			zonecfg_fini_handle(handle);
-			return (Z_SYSTEM);
-		}
-	} else if (res != Z_BAD_PROPERTY) {
-		/*
-		 * Z_BAD_PROPERTY is an acceptable error value (from
-		 * zonecfg_get_hostid()) because it indicates that the zone
-		 * doesn't have a hostid.
-		 */
-		if (res == Z_TOO_BIG)
-			zerror(zlogp, B_FALSE, "hostid string in zone "
-			    "configuration is too large.");
-		else
-			zerror(zlogp, B_TRUE, "fetching zone hostid from "
-			    "configuration");
-		zonecfg_fini_handle(handle);
-		return (res);
-	}
-
+		goto out;
+	}
+
+	if ((res = setup_zone_hostid(handle, zlogp, zoneid)) != Z_OK)
+		goto out;
+
+	if ((res = setup_zone_fs_allowed(handle, zlogp, zoneid)) != Z_OK)
+		goto out;
+
+out:
 	zonecfg_fini_handle(handle);
-	return (Z_OK);
+	return (res);
 }
 
 zoneid_t
@@ -4366,7 +4408,7 @@
 		struct brand_attr attr;
 		char modname[MAXPATHLEN];
 
-		if (setup_zone_hostid(zlogp, zone_name, zoneid) != Z_OK)
+		if (setup_zone_attrs(zlogp, zone_name, zoneid) != Z_OK)
 			goto error;
 
 		if ((bh = brand_open(brand_name)) == NULL) {
--- a/usr/src/cmd/zonecfg/zonecfg.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg.c	Wed Jun 16 10:02:44 2010 -0700
@@ -183,6 +183,7 @@
 	"capped-cpu",
 	"hostid",
 	"admin",
+	"fs-allowed",
 	NULL
 };
 
@@ -227,6 +228,7 @@
 	"hostid",
 	"user",
 	"auths",
+	"fs-allowed",
 	NULL
 };
 
@@ -342,6 +344,7 @@
 	"set " ALIAS_MAXSEMIDS "=",
 	"set " ALIAS_SHARES "=",
 	"set hostid=",
+	"set fs-allowed=",
 	NULL
 };
 
@@ -373,6 +376,7 @@
 	"info cpu-shares",
 	"info hostid",
 	"info admin",
+	"info fs-allowed",
 	NULL
 };
 
@@ -1219,6 +1223,8 @@
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_HOSTID));
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
+		    pt_to_str(PT_FS_ALLOWED));
+		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_MAXLWPS));
 		(void) fprintf(fp, "\t%s\t%s\n", gettext("(global)"),
 		    pt_to_str(PT_MAXSHMMEM));
@@ -1706,6 +1712,7 @@
 	char sched[MAXNAMELEN];
 	char brand[MAXNAMELEN];
 	char hostidp[HW_HOSTID_LEN];
+	char fsallowedp[ZONE_FS_ALLOWED_MAX];
 	char *limitpriv;
 	FILE *of;
 	boolean_t autoboot;
@@ -1814,6 +1821,12 @@
 		    pt_to_str(PT_HOSTID), hostidp);
 	}
 
+	if (zonecfg_get_fs_allowed(handle, fsallowedp,
+	    sizeof (fsallowedp)) == Z_OK) {
+		(void) fprintf(of, "%s %s=%s\n", cmd_to_str(CMD_SET),
+		    pt_to_str(PT_FS_ALLOWED), fsallowedp);
+	}
+
 	if ((err = zonecfg_setipdent(handle)) != Z_OK) {
 		zone_perror(zone, err, B_FALSE);
 		goto done;
@@ -2383,7 +2396,7 @@
 	return (global_zone && (type == RT_ZONENAME || type == RT_ZONEPATH ||
 	    type == RT_AUTOBOOT || type == RT_LIMITPRIV ||
 	    type == RT_BOOTARGS || type == RT_BRAND || type == RT_SCHED ||
-	    type == RT_IPTYPE || type == RT_HOSTID));
+	    type == RT_IPTYPE || type == RT_HOSTID || type == RT_FS_ALLOWED));
 }
 
 static boolean_t
@@ -2392,7 +2405,7 @@
 	return (global_zone && (type == PT_ZONENAME || type == PT_ZONEPATH ||
 	    type == PT_AUTOBOOT || type == PT_LIMITPRIV ||
 	    type == PT_BOOTARGS || type == PT_BRAND || type == PT_SCHED ||
-	    type == PT_IPTYPE || type == PT_HOSTID));
+	    type == PT_IPTYPE || type == PT_HOSTID || type == PT_FS_ALLOWED));
 }
 
 void
@@ -3679,6 +3692,12 @@
 		else
 			need_to_commit = B_TRUE;
 		return;
+	case PT_FS_ALLOWED:
+		if ((err = zonecfg_set_fs_allowed(handle, NULL)) != Z_OK)
+			z_cmd_rt_perror(CMD_CLEAR, RT_FS_ALLOWED, err, B_TRUE);
+		else
+			need_to_commit = B_TRUE;
+		return;
 	default:
 		zone_perror(pt_to_str(type), Z_NO_PROPERTY_TYPE, B_TRUE);
 		long_usage(CMD_CLEAR, B_TRUE);
@@ -4146,6 +4165,8 @@
 			res_type = RT_SHARES;
 		} else if (prop_type == PT_HOSTID) {
 			res_type = RT_HOSTID;
+		} else if (prop_type == PT_FS_ALLOWED) {
+			res_type = RT_FS_ALLOWED;
 		} else {
 			zerr(gettext("Cannot set a resource-specific property "
 			    "from the global scope."));
@@ -4361,6 +4382,12 @@
 		}
 		need_to_commit = B_TRUE;
 		return;
+	case RT_FS_ALLOWED:
+		if ((err = zonecfg_set_fs_allowed(handle, prop_id)) != Z_OK)
+			zone_perror(zone, err, B_TRUE);
+		else
+			need_to_commit = B_TRUE;
+		return;
 	case RT_FS:
 		switch (prop_type) {
 		case PT_DIR:
@@ -4896,15 +4923,33 @@
 info_hostid(zone_dochandle_t handle, FILE *fp)
 {
 	char hostidp[HW_HOSTID_LEN];
-
-	/*
-	 * This will display "hostid: " if there isn't a hostid or an
-	 * error occurs while retrieving the hostid from the configuration
-	 * file.
-	 */
-	if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) != Z_OK)
-		hostidp[0] = '\0';
-	(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp);
+	int err;
+
+	if ((err = zonecfg_get_hostid(handle, hostidp,
+	    sizeof (hostidp))) == Z_OK) {
+		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_HOSTID), hostidp);
+	} else if (err == Z_BAD_PROPERTY) {
+		(void) fprintf(fp, "%s: \n", pt_to_str(PT_HOSTID));
+	} else {
+		zone_perror(zone, err, B_TRUE);
+	}
+}
+
+static void
+info_fs_allowed(zone_dochandle_t handle, FILE *fp)
+{
+	char fsallowedp[ZONE_FS_ALLOWED_MAX];
+	int err;
+
+	if ((err = zonecfg_get_fs_allowed(handle, fsallowedp,
+	    sizeof (fsallowedp))) == Z_OK) {
+		(void) fprintf(fp, "%s: %s\n", pt_to_str(PT_FS_ALLOWED),
+		    fsallowedp);
+	} else if (err == Z_BAD_PROPERTY) {
+		(void) fprintf(fp, "%s: \n", pt_to_str(PT_FS_ALLOWED));
+	} else {
+		zone_perror(zone, err, B_TRUE);
+	}
 }
 
 static void
@@ -5508,6 +5553,7 @@
 			info_sched(handle, fp);
 			info_iptype(handle, fp);
 			info_hostid(handle, fp);
+			info_fs_allowed(handle, fp);
 		}
 		info_aliased_rctl(handle, fp, ALIAS_MAXLWPS);
 		info_aliased_rctl(handle, fp, ALIAS_MAXSHMMEM);
@@ -5612,6 +5658,9 @@
 	case RT_ADMIN:
 		info_auth(handle, fp, cmd);
 		break;
+	case RT_FS_ALLOWED:
+		info_fs_allowed(handle, fp);
+		break;
 	default:
 		zone_perror(rt_to_str(cmd->cmd_res_type), Z_NO_RESOURCE_TYPE,
 		    B_TRUE);
@@ -5751,6 +5800,7 @@
 	char sched[MAXNAMELEN];
 	char brand[MAXNAMELEN];
 	char hostidp[HW_HOSTID_LEN];
+	char fsallowedp[ZONE_FS_ALLOWED_MAX];
 	int err, ret_val = Z_OK, arg;
 	int pset_res;
 	boolean_t save = B_FALSE;
@@ -5825,9 +5875,17 @@
 	}
 	(void) zonecfg_endipdent(handle);
 
-	if (zonecfg_get_hostid(handle, hostidp, sizeof (hostidp)) == Z_OK &&
-	    (err = zonecfg_valid_hostid(hostidp)) != Z_OK) {
-		zone_perror(zone, err, B_TRUE);
+	if (zonecfg_get_hostid(handle, hostidp,
+	    sizeof (hostidp)) == Z_INVALID_PROPERTY) {
+		zerr(gettext("%s: invalid hostid: %s"),
+		    zone, hostidp);
+		return;
+	}
+
+	if (zonecfg_get_fs_allowed(handle, fsallowedp,
+	    sizeof (fsallowedp)) == Z_INVALID_PROPERTY) {
+		zerr(gettext("%s: invalid fs-allowed: %s"),
+		    zone, fsallowedp);
 		return;
 	}
 
--- a/usr/src/cmd/zonecfg/zonecfg.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg.h	Wed Jun 16 10:02:44 2010 -0700
@@ -89,9 +89,10 @@
 #define	RT_PCAP		25
 #define	RT_HOSTID	26	/* really a property, but for info ... */
 #define	RT_ADMIN	27
+#define	RT_FS_ALLOWED	28
 
 #define	RT_MIN		RT_UNKNOWN
-#define	RT_MAX		RT_ADMIN
+#define	RT_MAX		RT_FS_ALLOWED
 
 /* property types: increment PT_MAX when expanding this list */
 #define	PT_UNKNOWN	0
@@ -133,9 +134,10 @@
 #define	PT_HOSTID	36
 #define	PT_USER		37
 #define	PT_AUTHS	38
+#define	PT_FS_ALLOWED	39
 
 #define	PT_MIN		PT_UNKNOWN
-#define	PT_MAX		PT_AUTHS
+#define	PT_MAX		PT_FS_ALLOWED
 
 #define	MAX_EQ_PROP_PAIRS	3
 
--- a/usr/src/cmd/zonecfg/zonecfg_grammar.y	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg_grammar.y	Wed Jun 16 10:02:44 2010 -0700
@@ -123,7 +123,7 @@
 %token HELP CREATE EXPORT ADD DELETE REMOVE SELECT SET INFO CANCEL END VERIFY
 %token COMMIT REVERT EXIT SEMICOLON TOKEN ZONENAME ZONEPATH AUTOBOOT POOL NET
 %token FS IPD ATTR DEVICE RCTL SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL
-%token IPTYPE HOSTID
+%token IPTYPE HOSTID FS_ALLOWED
 %token NAME MATCH PRIV LIMIT ACTION VALUE EQUAL OPEN_SQ_BRACKET CLOSE_SQ_BRACKET
 %token OPEN_PAREN CLOSE_PAREN COMMA DATASET LIMITPRIV BOOTARGS BRAND PSET PCAP
 %token MCAP NCPUS IMPORTANCE SHARES MAXLWPS MAXSHMMEM MAXSHMIDS MAXMSGIDS
@@ -136,7 +136,7 @@
     ADMIN
 %type <ival> property_name SPECIAL RAW DIR OPTIONS TYPE ADDRESS PHYSICAL NAME
     MATCH ZONENAME ZONEPATH AUTOBOOT POOL LIMITPRIV BOOTARGS VALUE PRIV LIMIT
-    ACTION BRAND SCHED IPTYPE DEFROUTER HOSTID USER AUTHS
+    ACTION BRAND SCHED IPTYPE DEFROUTER HOSTID USER AUTHS FS_ALLOWED
 %type <cmd> command
 %type <cmd> add_command ADD
 %type <cmd> cancel_command CANCEL
@@ -616,6 +616,15 @@
 		$$->cmd_res_type = RT_HOSTID;
 		$$->cmd_prop_nv_pairs = 0;
 	}
+	|	INFO FS_ALLOWED
+	{
+		if (($$ = alloc_cmd()) == NULL)
+			YYERROR;
+		cmd = $$;
+		$$->cmd_handler = &info_func;
+		$$->cmd_res_type = RT_FS_ALLOWED;
+		$$->cmd_prop_nv_pairs = 0;
+	}
 	|	INFO resource_type property_name EQUAL property_value
 	{
 		if (($$ = alloc_cmd()) == NULL)
@@ -962,6 +971,7 @@
 	| HOSTID	{ $$ = PT_HOSTID; }
 	| USER		{ $$ = PT_USER; }
 	| AUTHS 	{ $$ = PT_AUTHS; }
+	| FS_ALLOWED	{ $$ = PT_FS_ALLOWED; }
 
 /*
  * The grammar builds data structures from the bottom up.  Thus various
--- a/usr/src/cmd/zonecfg/zonecfg_lex.l	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/cmd/zonecfg/zonecfg_lex.l	Wed Jun 16 10:02:44 2010 -0700
@@ -281,6 +281,9 @@
 <TSTATE>auths	{ return AUTHS; }
 <CSTATE>auths	{ return AUTHS; }
 
+<TSTATE>fs-allowed	{ return FS_ALLOWED; }
+<CSTATE>fs-allowed	{ return FS_ALLOWED; }
+
 <TSTATE>=	{ return EQUAL; }
 <LSTATE>=	{ return EQUAL; }
 <CSTATE>=	{ return EQUAL; }
--- a/usr/src/head/libzonecfg.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/head/libzonecfg.h	Wed Jun 16 10:02:44 2010 -0700
@@ -100,7 +100,7 @@
 #define	Z_NO_POOL		47	/* no such pool configured */
 #define	Z_POOL_CREATE		48	/* pool create failed */
 #define	Z_POOL_BIND		49	/* pool bind failed */
-#define	Z_HOSTID_FUBAR		50	/* invalid hostid provided */
+#define	Z_INVALID_PROPERTY	50	/* invalid property value */
 
 /*
  * Warning: these are shared with the admin/install consolidation.
@@ -362,7 +362,12 @@
  */
 extern	int	zonecfg_get_hostid(zone_dochandle_t, char *, size_t);
 extern	int	zonecfg_set_hostid(zone_dochandle_t, const char *);
-extern	int	zonecfg_valid_hostid(const char *);
+
+/*
+ * Allowed FS mounts configuration.
+ */
+extern int	zonecfg_get_fs_allowed(zone_dochandle_t, char *, size_t);
+extern int	zonecfg_set_fs_allowed(zone_dochandle_t, const char *);
 
 /*
  * Device configuration and rule matching.
--- a/usr/src/lib/brand/ipkg/zone/platform.xml	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/lib/brand/ipkg/zone/platform.xml	Wed Jun 16 10:02:44 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- Use is subject to license terms.
+ Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -56,6 +55,8 @@
 	<device match="ipnet" />
 	<device match="kstat" />
 	<device match="lo0" />
+	<device match="lofictl" />
+	<device match="lofi" />
 	<device match="log" />
 	<device match="logindmux" />
 	<device match="nsmb" />
@@ -68,6 +69,7 @@
 	<device match="pts/*" />
 	<device match="random" />
 	<device match="rdsk" />
+	<device match="rlofi" />
 	<device match="rmt" />
 	<device match="sad/user" />
 	<device match="svvslo0" />
--- a/usr/src/lib/brand/sn1/zone/platform.xml	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/lib/brand/sn1/zone/platform.xml	Wed Jun 16 10:02:44 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- Use is subject to license terms.
+ Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -61,6 +60,8 @@
 	<device match="ipnet" />
 	<device match="kstat" />
 	<device match="lo0" />
+	<device match="lofictl" />
+	<device match="lofi" />
 	<device match="log" />
 	<device match="logindmux" />
 	<device match="nsmb" />
@@ -73,6 +74,7 @@
 	<device match="pts/*" />
 	<device match="random" />
 	<device match="rdsk" />
+	<device match="rlofi" />
 	<device match="rmt" />
 	<device match="sad/user" />
 	<device match="svvslo0" />
--- a/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/lib/brand/solaris10/s10_brand/common/s10_brand.c	Wed Jun 16 10:02:44 2010 -0700
@@ -56,6 +56,7 @@
 #include <sys/mntio.h>
 #include <sys/mnttab.h>
 #include <sys/attr.h>
+#include <sys/lofi.h>
 #include <atomic.h>
 #include <sys/acl.h>
 
@@ -120,6 +121,41 @@
 #define	S10_UTS_VERSION	"Generic_Virtual"
 
 /*
+ * If the ioctl fd's major doesn't match "major", then pass through the
+ * ioctl, since it is not the expected device.  major should be a
+ * pointer to a static dev_t initialized to -1, and devname should be
+ * the path of the device.
+ *
+ * Returns 1 if the ioctl was handled (in which case *err contains the
+ * error code), or 0 if it still needs handling.
+ */
+static int
+passthru_otherdev_ioctl(dev_t *majordev, const char *devname, int *err,
+    sysret_t *rval, int fdes, int cmd, intptr_t arg)
+{
+	struct stat sbuf;
+
+	if (*majordev == (dev_t)-1) {
+		if ((*err = __systemcall(rval, SYS_fstatat + 1024,
+		    AT_FDCWD, devname, &sbuf, 0) != 0) != 0)
+			goto doioctl;
+
+		*majordev = major(sbuf.st_rdev);
+	}
+
+	if ((*err = __systemcall(rval, SYS_fstatat + 1024, fdes,
+	    NULL, &sbuf, 0)) != 0)
+		goto doioctl;
+
+	if (major(sbuf.st_rdev) == *majordev)
+		return (0);
+
+doioctl:
+	*err = (__systemcall(rval, SYS_ioctl + 1024, fdes, cmd, arg));
+	return (1);
+}
+
+/*
  * Figures out the PID of init for the zone.  Also returns a boolean
  * indicating whether this process currently has that pid: if so,
  * then at this moment, we are init.
@@ -414,20 +450,10 @@
 	s10_crypto_get_function_list_t	s10_param;
 	crypto_get_function_list_t	native_param;
 	static dev_t			crypto_dev = (dev_t)-1;
-	struct stat			sbuf;
 
-	if (crypto_dev == (dev_t)-1) {
-		if ((err = __systemcall(rval, SYS_fstatat + 1024,
-		    AT_FDCWD, "/dev/crypto", &sbuf, 0)) != 0)
-			goto nonemuioctl;
-		crypto_dev = major(sbuf.st_rdev);
-	}
-	if ((err = __systemcall(rval, SYS_fstatat + 1024,
-	    fdes, NULL, &sbuf, 0)) != 0)
+	if (passthru_otherdev_ioctl(&crypto_dev, "/dev/crypto", &err,
+	    rval, fdes, cmd, arg) == 1)
 		return (err);
-	/* Each open fd of /dev/crypto gets a new minor device. */
-	if (major(sbuf.st_rdev) != crypto_dev)
-		goto nonemuioctl;
 
 	if (brand_uucopy((const void *)arg, &s10_param, sizeof (s10_param))
 	    != 0)
@@ -518,9 +544,6 @@
 	struct_assign(s10_param, native_param, fl_list.prov_hash_limit);
 
 	return (brand_uucopy(&s10_param, (void *)arg, sizeof (s10_param)));
-
-nonemuioctl:
-	return (__systemcall(rval, SYS_ioctl + 1024, fdes, cmd, arg));
 }
 
 /*
@@ -584,29 +607,72 @@
 static int
 zfs_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg)
 {
-	dev_t		zfs_dev;
-	struct stat	sbuf;
+	static dev_t zfs_dev = (dev_t)-1;
+	int err;
 
-	/*
-	 * See if the ioctl is targeting the ZFS device, /dev/zfs.
-	 * If it isn't, then s10_ioctl() mistook the ioctl for a ZFS ioctl.
-	 * In that case, we don't want to abort, so we pass it along to the
-	 * kernel.
-	 */
-	if (__systemcall(rval, SYS_fstatat + 1024, AT_FDCWD, ZFS_DEV, &sbuf, 0)
-	    != 0)
-		return (__systemcall(rval, SYS_ioctl + 1024, fdes, cmd, arg));
-	zfs_dev = major(sbuf.st_rdev);
-
-	if (__systemcall(rval, SYS_fstatat + 1024, fdes, NULL, &sbuf, 0) != 0 ||
-	    major(sbuf.st_rdev) != zfs_dev)
-		return (__systemcall(rval, SYS_ioctl + 1024, fdes, cmd, arg));
+	if (passthru_otherdev_ioctl(&zfs_dev, ZFS_DEV, &err,
+	    rval, fdes, cmd, arg) == 1)
+		return (err);
 
 	brand_abort(0, "ZFS ioctl!");
 	/*NOTREACHED*/
 	return (0);
 }
 
+struct s10_lofi_ioctl {
+	uint32_t li_minor;
+	boolean_t li_force;
+	char li_filename[MAXPATHLEN + 1];
+};
+
+static int
+lofi_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg)
+{
+	static dev_t lofi_dev = (dev_t)-1;
+	struct s10_lofi_ioctl s10_param;
+	struct lofi_ioctl native_param;
+	int err;
+
+	if (passthru_otherdev_ioctl(&lofi_dev, "/dev/lofictl", &err,
+	    rval, fdes, cmd, arg) == 1)
+		return (err);
+
+	if (brand_uucopy((const void *)arg, &s10_param,
+	    sizeof (s10_param)) != 0)
+		return (EFAULT);
+
+	/*
+	 * Somewhat weirdly, EIO is what the S10 lofi driver would
+	 * return for unrecognised cmds.
+	 */
+	if (cmd >= LOFI_CHECK_COMPRESSED)
+		return (EIO);
+
+	bzero(&native_param, sizeof (native_param));
+
+	struct_assign(native_param, s10_param, li_minor);
+	struct_assign(native_param, s10_param, li_force);
+
+	/*
+	 * Careful here, this has changed from [MAXPATHLEN + 1] to
+	 * [MAXPATHLEN].
+	 */
+	bcopy(s10_param.li_filename, native_param.li_filename,
+	    sizeof (native_param.li_filename));
+	native_param.li_filename[MAXPATHLEN - 1] = '\0';
+
+	err = __systemcall(rval, SYS_ioctl + 1024, fdes, cmd, &native_param);
+
+	struct_assign(s10_param, native_param, li_minor);
+	/* li_force is input-only */
+
+	bcopy(native_param.li_filename, s10_param.li_filename,
+	    sizeof (native_param.li_filename));
+
+	(void) brand_uucopy(&s10_param, (void *)arg, sizeof (s10_param));
+	return (err);
+}
+
 int
 s10_ioctl(sysret_t *rval, int fdes, int cmd, intptr_t arg)
 {
@@ -625,9 +691,17 @@
 		return (mntfs_ioctl(rval, fdes, cmd, arg));
 	}
 
-	if ((cmd & 0xff00) == ZFS_IOC)
+	switch (cmd & ~0xff) {
+	case ZFS_IOC:
 		return (zfs_ioctl(rval, fdes, cmd, arg));
 
+	case LOFI_IOC_BASE:
+		return (lofi_ioctl(rval, fdes, cmd, arg));
+
+	default:
+		break;
+	}
+
 	return (__systemcall(rval, SYS_ioctl + 1024, fdes, cmd, arg));
 }
 
--- a/usr/src/lib/brand/solaris10/zone/platform.xml	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/lib/brand/solaris10/zone/platform.xml	Wed Jun 16 10:02:44 2010 -0700
@@ -20,8 +20,7 @@
 
  CDDL HEADER END
 
- Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- Use is subject to license terms.
+ Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
 
  DO NOT EDIT THIS FILE.
 -->
@@ -73,6 +72,8 @@
 	<device match="ipnet" />
 	<device match="kstat" />
 	<device match="lo0" />
+	<device match="lofictl" />
+	<device match="lofi" />
 	<device match="log" />
 	<device match="logindmux" />
 	<device match="nsmb" />
@@ -85,6 +86,7 @@
 	<device match="pts/*" />
 	<device match="random" />
 	<device match="rdsk" />
+	<device match="rlofi" />
 	<device match="rmt" />
 	<device match="sad/user" />
 	<device match="svvslo0" />
--- a/usr/src/lib/libzonecfg/common/libzonecfg.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/lib/libzonecfg/common/libzonecfg.c	Wed Jun 16 10:02:44 2010 -0700
@@ -132,6 +132,7 @@
 #define	DTD_ATTR_HOSTID		(const xmlChar *) "hostid"
 #define	DTD_ATTR_USER		(const xmlChar *) "user"
 #define	DTD_ATTR_AUTHS		(const xmlChar *) "auths"
+#define	DTD_ATTR_FS_ALLOWED	(const xmlChar *) "fs-allowed"
 
 #define	DTD_ENTITY_BOOLEAN	"boolean"
 #define	DTD_ENTITY_DEVPATH	"devpath"
@@ -2384,6 +2385,113 @@
 }
 
 /*
+ * Must be a comma-separated list of alpha-numeric file system names.
+ */
+static int
+zonecfg_valid_fs_allowed(const char *fsallowedp)
+{
+	char tmp[ZONE_FS_ALLOWED_MAX];
+	char *cp = tmp;
+	char *p;
+
+	if (strlen(fsallowedp) > ZONE_FS_ALLOWED_MAX)
+		return (Z_TOO_BIG);
+
+	(void) strlcpy(tmp, fsallowedp, sizeof (tmp));
+
+	while (*cp != '\0') {
+		p = cp;
+		while (*p != '\0' && *p != ',') {
+			if (!isalnum(*p))
+				return (Z_INVALID_PROPERTY);
+			p++;
+		}
+
+		if (*p == ',') {
+			if (p == cp)
+				return (Z_INVALID_PROPERTY);
+
+			p++;
+
+			if (*p == '\0')
+				return (Z_INVALID_PROPERTY);
+		}
+
+		cp = p;
+	}
+
+	return (Z_OK);
+}
+
+int
+zonecfg_get_fs_allowed(zone_dochandle_t handle, char *bufp, size_t buflen)
+{
+	int err;
+
+	if ((err = getrootattr(handle, DTD_ATTR_FS_ALLOWED,
+	    bufp, buflen)) != Z_OK)
+		return (err);
+	if (bufp[0] == '\0')
+		return (Z_BAD_PROPERTY);
+	return (zonecfg_valid_fs_allowed(bufp));
+}
+
+int
+zonecfg_set_fs_allowed(zone_dochandle_t handle, const char *bufp)
+{
+	int err;
+
+	if (bufp == NULL || (err = zonecfg_valid_fs_allowed(bufp)) == Z_OK)
+		return (setrootattr(handle, DTD_ATTR_FS_ALLOWED, bufp));
+	return (err);
+}
+
+/*
+ * Determines if the specified string is a valid hostid string.  This function
+ * returns Z_OK if the string is a valid hostid string.  It returns Z_INVAL if
+ * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
+ * containing a hex string with more than 8 digits, and Z_INVALID_PROPERTY if
+ * the string has an invalid format.
+ */
+static int
+zonecfg_valid_hostid(const char *hostidp)
+{
+	char *currentp;
+	u_longlong_t hostidval;
+	size_t len;
+
+	if (hostidp == NULL)
+		return (Z_INVAL);
+
+	/* Empty strings and strings with whitespace are invalid. */
+	if (*hostidp == '\0')
+		return (Z_INVALID_PROPERTY);
+	for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
+		if (isspace(*currentp))
+			return (Z_INVALID_PROPERTY);
+	}
+	len = (size_t)(currentp - hostidp);
+
+	/*
+	 * The caller might pass a hostid that is larger than the maximum
+	 * unsigned 32-bit integral value.  Check for this!  Also, make sure
+	 * that the whole string is converted (this helps us find illegal
+	 * characters) and that the whole string fits within a buffer of size
+	 * HW_HOSTID_LEN.
+	 */
+	currentp = (char *)hostidp;
+	if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
+		currentp += 2;
+	hostidval = strtoull(currentp, &currentp, 16);
+	if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
+		return (Z_TOO_BIG);
+	if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
+	    currentp != hostidp + len)
+		return (Z_INVALID_PROPERTY);
+	return (Z_OK);
+}
+
+/*
  * Gets the zone hostid string stored in the specified zone configuration
  * document.  This function returns Z_OK on success.  Z_BAD_PROPERTY is returned
  * if the config file doesn't specify a hostid or if the hostid is blank.
@@ -2399,7 +2507,7 @@
 		return (err);
 	if (bufp[0] == '\0')
 		return (Z_BAD_PROPERTY);
-	return (Z_OK);
+	return (zonecfg_valid_hostid(bufp));
 }
 
 /*
@@ -2422,51 +2530,6 @@
 	return (err);
 }
 
-/*
- * Determines if the specified string is a valid hostid string.  This function
- * returns Z_OK if the string is a valid hostid string.  It returns Z_INVAL if
- * 'hostidp' is NULL, Z_TOO_BIG if 'hostidp' refers to a string buffer
- * containing a hex string with more than 8 digits, and Z_HOSTID_FUBAR if the
- * string has an invalid format.
- */
-int
-zonecfg_valid_hostid(const char *hostidp)
-{
-	char *currentp;
-	u_longlong_t hostidval;
-	size_t len;
-
-	if (hostidp == NULL)
-		return (Z_INVAL);
-
-	/* Empty strings and strings with whitespace are invalid. */
-	if (*hostidp == '\0')
-		return (Z_HOSTID_FUBAR);
-	for (currentp = (char *)hostidp; *currentp != '\0'; ++currentp) {
-		if (isspace(*currentp))
-			return (Z_HOSTID_FUBAR);
-	}
-	len = (size_t)(currentp - hostidp);
-
-	/*
-	 * The caller might pass a hostid that is larger than the maximum
-	 * unsigned 32-bit integral value.  Check for this!  Also, make sure
-	 * that the whole string is converted (this helps us find illegal
-	 * characters) and that the whole string fits within a buffer of size
-	 * HW_HOSTID_LEN.
-	 */
-	currentp = (char *)hostidp;
-	if (strncmp(hostidp, "0x", 2) == 0 || strncmp(hostidp, "0X", 2) == 0)
-		currentp += 2;
-	hostidval = strtoull(currentp, &currentp, 16);
-	if ((size_t)(currentp - hostidp) >= HW_HOSTID_LEN)
-		return (Z_TOO_BIG);
-	if (hostidval > UINT_MAX || hostidval == HW_INVALID_HOSTID ||
-	    currentp != hostidp + len)
-		return (Z_HOSTID_FUBAR);
-	return (Z_OK);
-}
-
 int
 zonecfg_lookup_dev(zone_dochandle_t handle, struct zone_devtab *tabptr)
 {
@@ -3651,8 +3714,8 @@
 		    "Could not create a temporary pool"));
 	case Z_POOL_BIND:
 		return (dgettext(TEXT_DOMAIN, "Could not bind zone to pool"));
-	case Z_HOSTID_FUBAR:
-		return (dgettext(TEXT_DOMAIN, "Specified hostid is invalid"));
+	case Z_INVALID_PROPERTY:
+		return (dgettext(TEXT_DOMAIN, "Specified property is invalid"));
 	case Z_SYSTEM:
 		return (strerror(errno));
 	default:
--- a/usr/src/lib/libzonecfg/common/mapfile-vers	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/lib/libzonecfg/common/mapfile-vers	Wed Jun 16 10:02:44 2010 -0700
@@ -125,6 +125,7 @@
 	zonecfg_getdevperment;
 	zonecfg_getdsent;
 	zonecfg_getfsent;
+	zonecfg_get_fs_allowed;
 	zonecfg_get_handle;
 	zonecfg_get_hostid;
 	zonecfg_getipdent;
@@ -205,6 +206,7 @@
 	zonecfg_setdevperment;
 	zonecfg_setdsent;
 	zonecfg_setfsent;
+	zonecfg_set_fs_allowed;
 	zonecfg_set_hostid;
 	zonecfg_setipdent;
 	zonecfg_set_iptype;
@@ -224,7 +226,6 @@
 	zonecfg_valid_auths;
 	zonecfg_valid_alias_limit;
 	zonecfg_valid_fs_type;
-	zonecfg_valid_hostid;
 	zonecfg_valid_importance;
 	zonecfg_valid_memlimit;
 	zonecfg_valid_ncpus;
--- a/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/lib/libzonecfg/dtd/zonecfg.dtd.1	Wed Jun 16 10:02:44 2010 -0700
@@ -150,4 +150,5 @@
 			bootargs	CDATA ""
 			brand		CDATA ""
 			scheduling-class	CDATA ""
+			fs-allowed	CDATA ""
 			version		NMTOKEN #FIXED '1'>
--- a/usr/src/uts/common/fs/autofs/auto_vfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/autofs/auto_vfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -87,7 +87,7 @@
 	VFSDEF_VERSION,
 	"autofs",
 	autofs_init,
-	VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_STATS,
+	VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_STATS|VSW_ZMOUNT,
 	&auto_mntopts
 };
 
--- a/usr/src/uts/common/fs/ctfs/ctfs_root.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/ctfs/ctfs_root.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,12 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/modctl.h>
 #include <sys/types.h>
 #include <sys/param.h>
@@ -111,7 +108,7 @@
 	VFSDEF_VERSION,
 	"ctfs",
 	ctfs_init,
-	VSW_HASPROTO,
+	VSW_HASPROTO|VSW_ZMOUNT,
 	&ctfs_mntopts,
 };
 
@@ -241,10 +238,10 @@
 	 */
 	vfsp->vfs_bsize = DEV_BSIZE;
 	vfsp->vfs_fstype = ctfs_fstype;
-	do
+	do {
 		dev = makedevice(ctfs_major,
 		    atomic_add_32_nv(&ctfs_minor, 1) & L_MAXMIN32);
-	while (vfs_devismounted(dev));
+	} while (vfs_devismounted(dev));
 	vfs_make_fsid(&vfsp->vfs_fsid, dev, ctfs_fstype);
 	vfsp->vfs_data = data;
 	vfsp->vfs_dev = dev;
--- a/usr/src/uts/common/fs/dcfs/dc_vnops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/dcfs/dc_vnops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -20,8 +20,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -159,7 +158,7 @@
 	VFSDEF_VERSION,
 	"dcfs",
 	dcinit,
-	0,
+	VSW_ZMOUNT,
 	NULL
 };
 
--- a/usr/src/uts/common/fs/dev/sdev_profile.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/dev/sdev_profile.c	Wed Jun 16 10:02:44 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * This file implements /dev filesystem operations for non-global
  * instances. Three major entry points:
@@ -245,9 +242,6 @@
 prof_lookup_globaldev(struct sdev_node *dir, struct sdev_node *gdir,
     char *name, char *rename)
 {
-	/* global OS rootdir */
-	extern vnode_t *rootdir;
-
 	int error;
 	struct vnode *avp, *gdv, *gddv;
 	struct sdev_node *newdv;
@@ -269,7 +263,6 @@
 	/* perform a relative lookup of the global /dev instance */
 	gddv = SDEVTOV(gdir);
 	VN_HOLD(gddv);
-	VN_HOLD(rootdir);
 	error = lookuppnvp(&pn, NULL, FOLLOW, NULLVPP, &gdv,
 	    rootdir, gddv, kcred);
 	pn_free(&pn);
@@ -528,25 +521,96 @@
 	kmem_free(dbuf, dlen);
 }
 
+/*
+ * Last chance for a zone to see a node.  If our parent dir is
+ * SDEV_ZONED, then we look up the "zone" property for the node.  If the
+ * property is found and matches the current zone name, we allow it.
+ * Note that this isn't quite correct for the global zone peeking inside
+ * a zone's /dev - for that to work, we'd have to have a per-dev-mount
+ * zone ref squirreled away.
+ */
 static int
-prof_make_name(char *nm, void *arg)
+prof_zone_matched(char *name, struct sdev_node *dir)
+{
+	vnode_t *gvn = SDEVTOV(dir->sdev_origin);
+	struct pathname pn;
+	vnode_t *vn = NULL;
+	char zonename[ZONENAME_MAX];
+	int znlen = ZONENAME_MAX;
+	int ret;
+
+	ASSERT((dir->sdev_flags & SDEV_ZONED) != 0);
+
+	sdcmn_err10(("sdev_node %p is zoned, looking for %s\n",
+	    (void *)dir, name));
+
+	if (pn_get(name, UIO_SYSSPACE, &pn))
+		return (0);
+
+	VN_HOLD(gvn);
+
+	ret = lookuppnvp(&pn, NULL, FOLLOW, NULLVPP, &vn, rootdir, gvn, kcred);
+
+	pn_free(&pn);
+
+	if (ret != 0) {
+		sdcmn_err10(("prof_zone_matched: %s not found\n", name));
+		return (0);
+	}
+
+	/*
+	 * VBLK doesn't matter, and the property name is in fact treated
+	 * as a const char *.
+	 */
+	ret = e_ddi_getlongprop_buf(vn->v_rdev, VBLK, (char *)"zone",
+	    DDI_PROP_NOTPROM | DDI_PROP_DONTPASS, (caddr_t)zonename, &znlen);
+
+	VN_RELE(vn);
+
+	if (ret == DDI_PROP_NOT_FOUND) {
+		sdcmn_err10(("vnode %p: no zone prop\n", (void *)vn));
+		return (0);
+	} else if (ret != DDI_PROP_SUCCESS) {
+		sdcmn_err10(("vnode %p: zone prop error: %d\n",
+		    (void *)vn, ret));
+		return (0);
+	}
+
+	sdcmn_err10(("vnode %p zone prop: %s\n", (void *)vn, zonename));
+	return (strcmp(zonename, curproc->p_zone->zone_name) == 0);
+}
+
+static int
+prof_make_name_glob(char *nm, void *arg)
 {
 	struct sdev_node *ddv = (struct sdev_node *)arg;
 
 	if (prof_name_matched(nm, ddv))
 		prof_lookup_globaldev(ddv, ddv->sdev_origin, nm, nm);
+
+	return (WALK_DIR_CONTINUE);
+}
+
+static int
+prof_make_name_zone(char *nm, void *arg)
+{
+	struct sdev_node *ddv = (struct sdev_node *)arg;
+
+	if (prof_zone_matched(nm, ddv))
+		prof_lookup_globaldev(ddv, ddv->sdev_origin, nm, nm);
+
 	return (WALK_DIR_CONTINUE);
 }
 
 static void
-prof_make_names_glob(struct sdev_node *ddv)
+prof_make_names_walk(struct sdev_node *ddv, int (*cb)(char *, void *))
 {
 	struct sdev_node *gdir;
 
 	gdir = ddv->sdev_origin;
 	if (gdir == NULL)
 		return;
-	walk_dir(SDEVTOV(gdir), (void *)ddv, prof_make_name);
+	walk_dir(SDEVTOV(gdir), (void *)ddv, cb);
 }
 
 static void
@@ -559,11 +623,14 @@
 
 	ASSERT(RW_WRITE_HELD(&dir->sdev_contents));
 
+	if ((dir->sdev_flags & SDEV_ZONED) != 0)
+		prof_make_names_walk(dir, prof_make_name_zone);
+
 	if (nvl == NULL)
 		return;
 
 	if (dir->sdev_prof.has_glob) {
-		prof_make_names_glob(dir);
+		prof_make_names_walk(dir, prof_make_name_glob);
 		return;
 	}
 
--- a/usr/src/uts/common/fs/dev/sdev_subr.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/dev/sdev_subr.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -548,6 +547,9 @@
 	{ "ipnet", devipnet_vnodeops_tbl, NULL, &devipnet_vnodeops,
 	devipnet_validate, SDEV_DYNAMIC | SDEV_VTOR | SDEV_NO_NCACHE },
 
+	{ "lofi", NULL, NULL, NULL, NULL, SDEV_ZONED },
+	{ "rlofi", NULL, NULL, NULL, NULL, SDEV_ZONED },
+
 	{ NULL, NULL, NULL, NULL, NULL, 0}
 };
 
--- a/usr/src/uts/common/fs/fd/fdops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/fd/fdops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,12 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
 /*	  All rights reserved.  	*/
 
@@ -549,7 +546,7 @@
 	VFSDEF_VERSION,
 	"fd",
 	fdinit,
-	VSW_HASPROTO,
+	VSW_HASPROTO | VSW_ZMOUNT,
 	&fdfs_mntopts
 };
 
--- a/usr/src/uts/common/fs/fifofs/fifosubr.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/fifofs/fifosubr.c	Wed Jun 16 10:02:44 2010 -0700
@@ -21,12 +21,9 @@
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
 
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * The routines defined in this file are supporting routines for FIFOFS
  * file system type.
@@ -80,7 +77,7 @@
 	VFSDEF_VERSION,
 	"fifofs",
 	fifoinit,
-	0,
+	VSW_ZMOUNT,
 	NULL
 };
 
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,12 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 /*
  * VFS operations for High Sierra filesystem
  */
@@ -151,7 +148,7 @@
 	"hsfs",
 	hsfsinit,
 	/* We don't suppport remounting */
-	VSW_HASPROTO|VSW_STATS|VSW_CANLOFI,
+	VSW_HASPROTO|VSW_STATS|VSW_CANLOFI|VSW_ZMOUNT,
 	&hsfs_proto_opttbl
 };
 
--- a/usr/src/uts/common/fs/lofs/lofs_vfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/lofs/lofs_vfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -58,7 +58,7 @@
 	VFSDEF_VERSION,
 	"lofs",
 	lofsinit,
-	VSW_HASPROTO|VSW_STATS,
+	VSW_HASPROTO|VSW_STATS|VSW_ZMOUNT,
 	&lofs_mntopts
 };
 
--- a/usr/src/uts/common/fs/mntfs/mntvfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/mntfs/mntvfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1999, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -66,7 +65,7 @@
 	VFSDEF_VERSION,
 	"mntfs",
 	mntinit,
-	VSW_HASPROTO|VSW_STATS,
+	VSW_HASPROTO|VSW_STATS|VSW_ZMOUNT,
 	&mnt_mntopts
 };
 
--- a/usr/src/uts/common/fs/namefs/namevfs.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/namefs/namevfs.c	Wed Jun 16 10:02:44 2010 -0700
@@ -730,7 +730,7 @@
 	VFSDEF_VERSION,
 	"namefs",
 	nameinit,
-	VSW_HASPROTO,
+	VSW_HASPROTO | VSW_ZMOUNT,
 	&nm_mntopts
 };
 
--- a/usr/src/uts/common/fs/nfs/nfs4_common.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs4_common.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2003, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -49,7 +48,7 @@
 	VFSDEF_VERSION,
 	"nfs4",
 	nfs4init,
-	VSW_CANREMOUNT|VSW_NOTZONESAFE|VSW_STATS,
+	VSW_CANREMOUNT|VSW_NOTZONESAFE|VSW_STATS|VSW_ZMOUNT,
 	NULL
 };
 
--- a/usr/src/uts/common/fs/nfs/nfs_common.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/nfs/nfs_common.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*
@@ -28,8 +27,6 @@
  *		All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/errno.h>
 #include <sys/param.h>
 #include <sys/types.h>
@@ -125,7 +122,7 @@
 	VFSDEF_VERSION,
 	"nfsdyn",
 	nfsdyninit,
-	0,
+	VSW_ZMOUNT,
 	NULL
 };
 
@@ -142,7 +139,7 @@
 	VFSDEF_VERSION,
 	"nfs",
 	nfsinit,
-	VSW_CANREMOUNT|VSW_NOTZONESAFE|VSW_STATS,
+	VSW_CANREMOUNT|VSW_NOTZONESAFE|VSW_STATS|VSW_ZMOUNT,
 	NULL
 };
 
@@ -159,7 +156,7 @@
 	VFSDEF_VERSION,
 	"nfs3",
 	nfs3init,
-	VSW_CANREMOUNT|VSW_NOTZONESAFE|VSW_STATS,
+	VSW_CANREMOUNT|VSW_NOTZONESAFE|VSW_STATS|VSW_ZMOUNT,
 	NULL
 };
 
@@ -410,10 +407,10 @@
 	vfsflags = 0;
 
 	if (error = mount_root(*name ? name : "root", root_path, NFS_V4,
-				&args, &vfsflags)) {
+	    &args, &vfsflags)) {
 		if (error != EPROTONOSUPPORT) {
 			nfs_cmn_err(error, CE_WARN,
-				"Unable to mount NFS root filesystem: %m");
+			    "Unable to mount NFS root filesystem: %m");
 			sv_free(svp);
 			pn_free(&pn);
 			vfs_setops(vfsp, nfsdyn_vfsops);
@@ -432,7 +429,7 @@
 		vfsflags = 0;
 
 		if (error = mount_root(*name ? name : "root", root_path,
-						NFS_V3, &args, &vfsflags)) {
+		    NFS_V3, &args, &vfsflags)) {
 			if (error != EPROTONOSUPPORT) {
 				nfs_cmn_err(error, CE_WARN,
 				    "Unable to mount NFS root filesystem: %m");
@@ -455,8 +452,7 @@
 			vfs_setops(vfsp, nfs_vfsops);
 
 			if (error = mount_root(*name ? name : "root",
-					root_path, NFS_VERSION, &args,
-					&vfsflags)) {
+			    root_path, NFS_VERSION, &args, &vfsflags)) {
 				nfs_cmn_err(error, CE_WARN,
 				    "Unable to mount NFS root filesystem: %m");
 				sv_free(svp);
--- a/usr/src/uts/common/fs/objfs/objfs_vfs.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/objfs/objfs_vfs.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,12 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/atomic.h>
 #include <sys/cmn_err.h>
 #include <sys/errno.h>
@@ -76,7 +73,7 @@
 	VFSDEF_VERSION,
 	"objfs",
 	objfs_init,
-	VSW_HASPROTO,
+	VSW_HASPROTO | VSW_ZMOUNT,
 	&objfs_mntopts,
 };
 
--- a/usr/src/uts/common/fs/proc/prvfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/proc/prvfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,16 +19,13 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1989, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*	Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T	*/
 /*	  All Rights Reserved  	*/
 
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"	/* SVr4.0 1.25  */
-
 #include <sys/types.h>
 #include <sys/param.h>
 #include <sys/cmn_err.h>
@@ -72,7 +69,7 @@
 	VFSDEF_VERSION,
 	"proc",
 	prinit,
-	VSW_HASPROTO|VSW_STATS|VSW_XID,
+	VSW_HASPROTO|VSW_STATS|VSW_XID|VSW_ZMOUNT,
 	&proc_mntopts
 };
 
--- a/usr/src/uts/common/fs/sharefs/sharefs_vfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/sharefs/sharefs_vfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -20,12 +20,9 @@
  */
 
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/atomic.h>
 #include <sys/cmn_err.h>
 #include <sys/errno.h>
@@ -94,7 +91,7 @@
 	VFSDEF_VERSION,
 	"sharefs",
 	sharefs_init,
-	VSW_HASPROTO,
+	VSW_HASPROTO | VSW_ZMOUNT,
 	&sharefs_mntopts,
 };
 
--- a/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/smbclnt/smbfs/smbfs_vfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -33,8 +33,7 @@
  */
 
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/systm.h>
@@ -116,7 +115,7 @@
 	VFSDEF_VERSION,
 	(char *)fs_type_name,
 	smbfsinit,		/* init routine */
-	VSW_HASPROTO|VSW_NOTZONESAFE,	/* flags */
+	VSW_HASPROTO|VSW_NOTZONESAFE|VSW_ZMOUNT,	/* flags */
 	&smbfs_mntopts			/* mount options table prototype */
 };
 
--- a/usr/src/uts/common/fs/sockfs/sockvfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/sockfs/sockvfsops.c	Wed Jun 16 10:02:44 2010 -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,12 +19,9 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1995, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/t_lock.h>
 #include <sys/param.h>
@@ -59,7 +55,7 @@
 	VFSDEF_VERSION,
 	"sockfs",
 	sockinit,
-	0,
+	VSW_ZMOUNT,
 	NULL
 };
 
--- a/usr/src/uts/common/fs/specfs/specvfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/specfs/specvfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -37,8 +36,6 @@
  */
 
 
-#pragma ident	"%Z%%M%	%I%	%E% SMI"
-
 #include <sys/types.h>
 #include <sys/t_lock.h>
 #include <sys/param.h>
@@ -64,7 +61,7 @@
 	VFSDEF_VERSION,
 	"specfs",
 	specinit,
-	0,
+	VSW_ZMOUNT,
 	NULL
 };
 
--- a/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/tmpfs/tmp_vfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -77,7 +76,7 @@
 	VFSDEF_VERSION,
 	"tmpfs",
 	tmpfsinit,
-	VSW_HASPROTO|VSW_STATS,
+	VSW_HASPROTO|VSW_STATS|VSW_ZMOUNT,
 	&tmpfs_proto_opttbl
 };
 
--- a/usr/src/uts/common/fs/vfs.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/vfs.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -1014,8 +1013,7 @@
 	int minor;
 	int err = 0;
 
-	if (fsname == NULL ||
-	    (vfssw = vfs_getvfssw(fsname)) == NULL)
+	if ((vfssw = vfs_getvfssw(fsname)) == NULL)
 		return (0);
 
 	if (!(vfssw->vsw_flag & VSW_CANLOFI)) {
@@ -1049,29 +1047,16 @@
 	li = kmem_zalloc(sizeof (*li), KM_SLEEP);
 	(void) strlcpy(li->li_filename, pn.pn_path, MAXPATHLEN);
 
-	/*
-	 * The lofi control node is currently exclusive-open.  We'd like
-	 * to improve this, but in the meantime, we'll loop waiting for
-	 * access.
-	 */
-	for (;;) {
-		err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE | FEXCL,
-		    kcred, &ldi_hdl, ldi_id);
-
-		if (err != EBUSY)
-			break;
-
-		if ((err = delay_sig(hz / 8)) == EINTR)
-			break;
-	}
+	err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE, kcred,
+	    &ldi_hdl, ldi_id);
 
 	if (err)
 		goto out2;
 
 	err = ldi_ioctl(ldi_hdl, LOFI_MAP_FILE, (intptr_t)li,
-	    FREAD | FWRITE | FEXCL | FKIOCTL, kcred, &minor);
-
-	(void) ldi_close(ldi_hdl, FREAD | FWRITE | FEXCL, kcred);
+	    FREAD | FWRITE | FKIOCTL, kcred, &minor);
+
+	(void) ldi_close(ldi_hdl, FREAD | FWRITE, kcred);
 
 	if (!err)
 		vfsp->vfs_lofi_minor = minor;
@@ -1104,18 +1089,16 @@
 	li->li_minor = vfsp->vfs_lofi_minor;
 	li->li_cleanup = B_TRUE;
 
-	do {
-		err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE | FEXCL,
-		    kcred, &ldi_hdl, ldi_id);
-	} while (err == EBUSY);
+	err = ldi_open_by_name("/dev/lofictl", FREAD | FWRITE, kcred,
+	    &ldi_hdl, ldi_id);
 
 	if (err)
 		goto out;
 
 	err = ldi_ioctl(ldi_hdl, LOFI_UNMAP_FILE_MINOR, (intptr_t)li,
-	    FREAD | FWRITE | FEXCL | FKIOCTL, kcred, NULL);
-
-	(void) ldi_close(ldi_hdl, FREAD | FWRITE | FEXCL, kcred);
+	    FREAD | FWRITE | FKIOCTL, kcred, NULL);
+
+	(void) ldi_close(ldi_hdl, FREAD | FWRITE, kcred);
 
 	if (!err)
 		vfsp->vfs_lofi_minor = 0;
@@ -1251,9 +1234,16 @@
 	} else {
 		if ((vswp = vfs_getvfsswbyvfsops(vfs_getops(rootvfs))) == NULL)
 			return (EINVAL);
+		fsname = vswp->vsw_name;
 	}
 	if (!VFS_INSTALLED(vswp))
 		return (EINVAL);
+
+	if ((error = secpolicy_fs_allowed_mount(fsname)) != 0)  {
+		vfs_unrefvfssw(vswp);
+		return (error);
+	}
+
 	vfsops = &vswp->vsw_vfsops;
 
 	vfs_copyopttbl(&vswp->vsw_optproto, &mnt_mntopts);
@@ -4782,7 +4772,7 @@
 	}
 }
 
-#define	LOFICTL_PATH "/devices/pseudo/lofi@0:%d"
+#define	LOFINODE_PATH "/dev/lofi/%d"
 
 /*
  * Return the vnode for the lofi node if there's a lofi mount in place.
@@ -4801,11 +4791,23 @@
 		return (-1);
 	}
 
-	strsize = snprintf(NULL, 0, LOFICTL_PATH, vfsp->vfs_lofi_minor);
+	strsize = snprintf(NULL, 0, LOFINODE_PATH, vfsp->vfs_lofi_minor);
 	path = kmem_alloc(strsize + 1, KM_SLEEP);
-	(void) snprintf(path, strsize + 1, LOFICTL_PATH, vfsp->vfs_lofi_minor);
-
-	err = lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, vpp);
+	(void) snprintf(path, strsize + 1, LOFINODE_PATH, vfsp->vfs_lofi_minor);
+
+	/*
+	 * We may be inside a zone, so we need to use the /dev path, but
+	 * it's created asynchronously, so we wait here.
+	 */
+	for (;;) {
+		err = lookupname(path, UIO_SYSSPACE, FOLLOW, NULLVPP, vpp);
+
+		if (err != ENOENT)
+			break;
+
+		if ((err = delay_sig(hz / 8)) == EINTR)
+			break;
+	}
 
 	if (err)
 		*vpp = NULL;
--- a/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/fs/zfs/zfs_vfsops.c	Wed Jun 16 10:02:44 2010 -0700
@@ -2277,7 +2277,7 @@
 	MNTTYPE_ZFS,
 	zfs_vfsinit,
 	VSW_HASPROTO|VSW_CANRWRO|VSW_CANREMOUNT|VSW_VOLATILEDEV|VSW_STATS|
-	    VSW_XID,
+	    VSW_XID|VSW_ZMOUNT,
 	&zfs_mntopts
 };
 
--- a/usr/src/uts/common/io/lofi.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/io/lofi.c	Wed Jun 16 10:02:44 2010 -0700
@@ -76,12 +76,6 @@
  *	enable direct I/O on the underlying file. Don't, because that deadlocks.
  *	I think to fix the cache-twice problem we might need filesystem support.
  *
- *	lofi on itself. The simple lock strategy (lofi_lock) precludes this
- *	because you'll be in lofi_ioctl, holding the lock when you open the
- *	file, which, if it's lofi, will grab lofi_lock. We prevent this for
- *	now, though not using ddi_soft_state(9F) would make it possible to
- *	do. Though it would still be silly.
- *
  * Interesting things to do:
  *
  *	Allow multiple files for each device. A poor-man's metadisk, basically.
@@ -129,8 +123,11 @@
 #include <sys/ddi.h>
 #include <sys/sunddi.h>
 #include <sys/zmod.h>
+#include <sys/id_space.h>
+#include <sys/mkdev.h>
 #include <sys/crypto/common.h>
 #include <sys/crypto/api.h>
+#include <sys/rctl.h>
 #include <LzmaDec.h>
 
 /*
@@ -144,6 +141,7 @@
 
 #define	NBLOCKS_PROP_NAME	"Nblocks"
 #define	SIZE_PROP_NAME		"Size"
+#define	ZONE_PROP_NAME		"zone"
 
 #define	SETUP_C_DATA(cd, buf, len) 		\
 	(cd).cd_format = CRYPTO_DATA_RAW;	\
@@ -162,6 +160,9 @@
 static dev_info_t *lofi_dip = NULL;
 static void *lofi_statep = NULL;
 static kmutex_t lofi_lock;		/* state lock */
+static id_space_t *lofi_minor_id;
+static list_t lofi_list;
+static zone_key_t lofi_zone_key;
 
 /*
  * Because lofi_taskq_nthreads limits the actual swamping of the device, the
@@ -178,7 +179,6 @@
 static int lofi_taskq_maxalloc = 104857600 / DEV_BSIZE;
 static int lofi_taskq_nthreads = 4;	/* # of taskq threads per device */
 
-uint32_t lofi_max_files = LOFI_MAX_FILES;
 const char lofi_crypto_magic[6] = LOFI_CRYPTO_MAGIC;
 
 /*
@@ -244,36 +244,16 @@
 }
 
 static int
-lofi_busy(void)
-{
-	minor_t	minor;
-
-	/*
-	 * We need to make sure no mappings exist - mod_remove won't
-	 * help because the device isn't open.
-	 */
-	mutex_enter(&lofi_lock);
-	for (minor = 1; minor <= lofi_max_files; minor++) {
-		if (ddi_get_soft_state(lofi_statep, minor) != NULL) {
-			mutex_exit(&lofi_lock);
-			return (EBUSY);
-		}
-	}
-	mutex_exit(&lofi_lock);
-	return (0);
-}
-
-static int
 is_opened(struct lofi_state *lsp)
 {
-	ASSERT(mutex_owned(&lofi_lock));
+	ASSERT(MUTEX_HELD(&lofi_lock));
 	return (lsp->ls_chr_open || lsp->ls_blk_open || lsp->ls_lyr_open_count);
 }
 
 static int
 mark_opened(struct lofi_state *lsp, int otyp)
 {
-	ASSERT(mutex_owned(&lofi_lock));
+	ASSERT(MUTEX_HELD(&lofi_lock));
 	switch (otyp) {
 	case OTYP_CHR:
 		lsp->ls_chr_open = 1;
@@ -293,7 +273,7 @@
 static void
 mark_closed(struct lofi_state *lsp, int otyp)
 {
-	ASSERT(mutex_owned(&lofi_lock));
+	ASSERT(MUTEX_HELD(&lofi_lock));
 	switch (otyp) {
 	case OTYP_CHR:
 		lsp->ls_chr_open = 0;
@@ -312,19 +292,21 @@
 static void
 lofi_free_crypto(struct lofi_state *lsp)
 {
-	ASSERT(mutex_owned(&lofi_lock));
+	ASSERT(MUTEX_HELD(&lofi_lock));
 
 	if (lsp->ls_crypto_enabled) {
 		/*
 		 * Clean up the crypto state so that it doesn't hang around
 		 * in memory after we are done with it.
 		 */
-		bzero(lsp->ls_key.ck_data,
-		    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length));
-		kmem_free(lsp->ls_key.ck_data,
-		    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length));
-		lsp->ls_key.ck_data = NULL;
-		lsp->ls_key.ck_length = 0;
+		if (lsp->ls_key.ck_data != NULL) {
+			bzero(lsp->ls_key.ck_data,
+			    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length));
+			kmem_free(lsp->ls_key.ck_data,
+			    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length));
+			lsp->ls_key.ck_data = NULL;
+			lsp->ls_key.ck_length = 0;
+		}
 
 		if (lsp->ls_mech.cm_param != NULL) {
 			kmem_free(lsp->ls_mech.cm_param,
@@ -345,52 +327,17 @@
 }
 
 static void
-lofi_free_handle(dev_t dev, minor_t minor, struct lofi_state *lsp,
-    cred_t *credp)
+lofi_destroy(struct lofi_state *lsp, cred_t *credp)
 {
-	dev_t	newdev;
-	char	namebuf[50];
-	int	i;
+	minor_t minor = getminor(lsp->ls_dev);
+	int i;
 
-	ASSERT(mutex_owned(&lofi_lock));
+	ASSERT(MUTEX_HELD(&lofi_lock));
+
+	list_remove(&lofi_list, lsp);
 
 	lofi_free_crypto(lsp);
 
-	if (lsp->ls_vp) {
-		(void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag,
-		    1, 0, credp, NULL);
-		VN_RELE(lsp->ls_vp);
-		lsp->ls_vp = NULL;
-	}
-
-	newdev = makedevice(getmajor(dev), minor);
-	(void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME);
-	(void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME);
-
-	(void) snprintf(namebuf, sizeof (namebuf), "%d", minor);
-	ddi_remove_minor_node(lofi_dip, namebuf);
-	(void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor);
-	ddi_remove_minor_node(lofi_dip, namebuf);
-
-	kmem_free(lsp->ls_filename, lsp->ls_filename_sz);
-	taskq_destroy(lsp->ls_taskq);
-	if (lsp->ls_kstat) {
-		kstat_delete(lsp->ls_kstat);
-		mutex_destroy(&lsp->ls_kstat_lock);
-	}
-
-	/*
-	 * Free cached decompressed segment data
-	 */
-	lofi_free_comp_cache(lsp);
-	list_destroy(&lsp->ls_comp_cache);
-	mutex_destroy(&lsp->ls_comp_cache_lock);
-
-	if (lsp->ls_uncomp_seg_sz > 0) {
-		kmem_free(lsp->ls_comp_index_data, lsp->ls_comp_index_data_sz);
-		lsp->ls_uncomp_seg_sz = 0;
-	}
-
 	/*
 	 * Free pre-allocated compressed buffers
 	 */
@@ -402,12 +349,93 @@
 		}
 		kmem_free(lsp->ls_comp_bufs,
 		    sizeof (struct compbuf) * lofi_taskq_nthreads);
-		mutex_destroy(&lsp->ls_comp_bufs_lock);
+	}
+
+	(void) VOP_CLOSE(lsp->ls_vp, lsp->ls_openflag,
+	    1, 0, credp, NULL);
+	VN_RELE(lsp->ls_vp);
+	if (lsp->ls_stacked_vp != lsp->ls_vp)
+		VN_RELE(lsp->ls_stacked_vp);
+
+	taskq_destroy(lsp->ls_taskq);
+
+	if (lsp->ls_kstat != NULL)
+		kstat_delete(lsp->ls_kstat);
+
+	/*
+	 * Free cached decompressed segment data
+	 */
+	lofi_free_comp_cache(lsp);
+	list_destroy(&lsp->ls_comp_cache);
+
+	if (lsp->ls_uncomp_seg_sz > 0) {
+		kmem_free(lsp->ls_comp_index_data, lsp->ls_comp_index_data_sz);
+		lsp->ls_uncomp_seg_sz = 0;
 	}
 
+	rctl_decr_lofi(lsp->ls_zone, 1);
+	zone_rele(lsp->ls_zone);
+
+	mutex_destroy(&lsp->ls_comp_cache_lock);
+	mutex_destroy(&lsp->ls_comp_bufs_lock);
+	mutex_destroy(&lsp->ls_kstat_lock);
 	mutex_destroy(&lsp->ls_vp_lock);
 
+	ASSERT(ddi_get_soft_state(lofi_statep, minor) == lsp);
 	ddi_soft_state_free(lofi_statep, minor);
+	id_free(lofi_minor_id, minor);
+}
+
+static void
+lofi_free_dev(dev_t dev)
+{
+	minor_t minor = getminor(dev);
+	char namebuf[50];
+
+	ASSERT(MUTEX_HELD(&lofi_lock));
+
+	(void) ddi_prop_remove(dev, lofi_dip, ZONE_PROP_NAME);
+	(void) ddi_prop_remove(dev, lofi_dip, SIZE_PROP_NAME);
+	(void) ddi_prop_remove(dev, lofi_dip, NBLOCKS_PROP_NAME);
+
+	(void) snprintf(namebuf, sizeof (namebuf), "%d", minor);
+	ddi_remove_minor_node(lofi_dip, namebuf);
+	(void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor);
+	ddi_remove_minor_node(lofi_dip, namebuf);
+}
+
+/*ARGSUSED*/
+static void
+lofi_zone_shutdown(zoneid_t zoneid, void *arg)
+{
+	struct lofi_state *lsp;
+	struct lofi_state *next;
+
+	mutex_enter(&lofi_lock);
+
+	for (lsp = list_head(&lofi_list); lsp != NULL; lsp = next) {
+
+		/* lofi_destroy() frees lsp */
+		next = list_next(&lofi_list, lsp);
+
+		if (lsp->ls_zone->zone_id != zoneid)
+			continue;
+
+		/*
+		 * No in-zone processes are running, but something has this
+		 * open.  It's either a global zone process, or a lofi
+		 * mount.  In either case we set ls_cleanup so the last
+		 * user destroys the device.
+		 */
+		if (is_opened(lsp)) {
+			lsp->ls_cleanup = 1;
+		} else {
+			lofi_free_dev(lsp->ls_dev);
+			lofi_destroy(lsp, kcred);
+		}
+	}
+
+	mutex_exit(&lofi_lock);
 }
 
 /*ARGSUSED*/
@@ -417,25 +445,18 @@
 	minor_t	minor;
 	struct lofi_state *lsp;
 
+	/*
+	 * lofiadm -a /dev/lofi/1 gets us here.
+	 */
+	if (mutex_owner(&lofi_lock) == curthread)
+		return (EINVAL);
+
 	mutex_enter(&lofi_lock);
+
 	minor = getminor(*devp);
+
+	/* master control device */
 	if (minor == 0) {
-		/* master control device */
-		/* must be opened exclusively */
-		if (((flag & FEXCL) != FEXCL) || (otyp != OTYP_CHR)) {
-			mutex_exit(&lofi_lock);
-			return (EINVAL);
-		}
-		lsp = ddi_get_soft_state(lofi_statep, 0);
-		if (lsp == NULL) {
-			mutex_exit(&lofi_lock);
-			return (ENXIO);
-		}
-		if (is_opened(lsp)) {
-			mutex_exit(&lofi_lock);
-			return (EBUSY);
-		}
-		(void) mark_opened(lsp, OTYP_CHR);
 		mutex_exit(&lofi_lock);
 		return (0);
 	}
@@ -475,6 +496,12 @@
 		mutex_exit(&lofi_lock);
 		return (EINVAL);
 	}
+
+	if (minor == 0) {
+		mutex_exit(&lofi_lock);
+		return (0);
+	}
+
 	mark_closed(lsp, otyp);
 
 	/*
@@ -482,9 +509,10 @@
 	 * asked for cleanup (li_cleanup), finish up if we're the last
 	 * out of the door.
 	 */
-	if (minor != 0 && !is_opened(lsp) &&
-	    (lsp->ls_cleanup || lsp->ls_vp == NULL))
-		lofi_free_handle(dev, minor, lsp, credp);
+	if (!is_opened(lsp) && (lsp->ls_cleanup || lsp->ls_vp == NULL)) {
+		lofi_free_dev(dev);
+		lofi_destroy(lsp, credp);
+	}
 
 	mutex_exit(&lofi_lock);
 	return (0);
@@ -508,7 +536,7 @@
 	void	*data;
 	size_t	datasz;
 
-	ASSERT(mutex_owned(&lsp->ls_crypto_lock));
+	ASSERT(MUTEX_HELD(&lsp->ls_crypto_lock));
 
 	if (lsp == NULL)
 		return (CRYPTO_DEVICE_ERROR);
@@ -843,7 +871,7 @@
 {
 	struct lofi_comp_cache *lc;
 
-	ASSERT(mutex_owned(&lsp->ls_comp_cache_lock));
+	ASSERT(MUTEX_HELD(&lsp->ls_comp_cache_lock));
 
 	for (lc = list_head(&lsp->ls_comp_cache); lc != NULL;
 	    lc = list_next(&lsp->ls_comp_cache, lc)) {
@@ -877,7 +905,7 @@
 {
 	struct lofi_comp_cache *lc;
 
-	ASSERT(mutex_owned(&lsp->ls_comp_cache_lock));
+	ASSERT(MUTEX_HELD(&lsp->ls_comp_cache_lock));
 
 	while (lsp->ls_comp_cache_count > lofi_max_comp_cache) {
 		lc = list_remove_tail(&lsp->ls_comp_cache);
@@ -1443,14 +1471,22 @@
 
 	if (cmd != DDI_ATTACH)
 		return (DDI_FAILURE);
+
+	lofi_minor_id = id_space_create("lofi_minor_id", 1, L_MAXMIN32 + 1);
+
+	if (!lofi_minor_id)
+		return (DDI_FAILURE);
+
 	error = ddi_soft_state_zalloc(lofi_statep, 0);
 	if (error == DDI_FAILURE) {
+		id_space_destroy(lofi_minor_id);
 		return (DDI_FAILURE);
 	}
 	error = ddi_create_minor_node(dip, LOFI_CTL_NODE, S_IFCHR, 0,
 	    DDI_PSEUDO, NULL);
 	if (error == DDI_FAILURE) {
 		ddi_soft_state_free(lofi_statep, 0);
+		id_space_destroy(lofi_minor_id);
 		return (DDI_FAILURE);
 	}
 	/* driver handles kernel-issued IOCTLs */
@@ -1458,8 +1494,12 @@
 	    DDI_KERNEL_IOCTL, NULL, 0) != DDI_PROP_SUCCESS) {
 		ddi_remove_minor_node(dip, NULL);
 		ddi_soft_state_free(lofi_statep, 0);
+		id_space_destroy(lofi_minor_id);
 		return (DDI_FAILURE);
 	}
+
+	zone_key_create(&lofi_zone_key, NULL, lofi_zone_shutdown, NULL);
+
 	lofi_dip = dip;
 	ddi_report_dev(dip);
 	return (DDI_SUCCESS);
@@ -1470,12 +1510,27 @@
 {
 	if (cmd != DDI_DETACH)
 		return (DDI_FAILURE);
-	if (lofi_busy())
+
+	mutex_enter(&lofi_lock);
+
+	if (!list_is_empty(&lofi_list)) {
+		mutex_exit(&lofi_lock);
 		return (DDI_FAILURE);
+	}
+
 	lofi_dip = NULL;
 	ddi_remove_minor_node(dip, NULL);
 	ddi_prop_remove_all(dip);
+
+	mutex_exit(&lofi_lock);
+
+	if (zone_key_delete(lofi_zone_key) != 0)
+		cmn_err(CE_WARN, "failed to delete zone key");
+
 	ddi_soft_state_free(lofi_statep, 0);
+
+	id_space_destroy(lofi_minor_id);
+
 	return (DDI_SUCCESS);
 }
 
@@ -1496,30 +1551,34 @@
  * These two just simplify the rest of the ioctls that need to copyin/out
  * the lofi_ioctl structure.
  */
-struct lofi_ioctl *
-copy_in_lofi_ioctl(const struct lofi_ioctl *ulip, int flag)
+int
+copy_in_lofi_ioctl(const struct lofi_ioctl *ulip, struct lofi_ioctl **klipp,
+    int flag)
 {
 	struct lofi_ioctl *klip;
 	int	error;
 
-	klip = kmem_alloc(sizeof (struct lofi_ioctl), KM_SLEEP);
+	klip = *klipp = kmem_alloc(sizeof (struct lofi_ioctl), KM_SLEEP);
 	error = ddi_copyin(ulip, klip, sizeof (struct lofi_ioctl), flag);
-	if (error) {
-		free_lofi_ioctl(klip);
-		return (NULL);
+	if (error)
+		goto err;
+
+	/* ensure NULL termination */
+	klip->li_filename[MAXPATHLEN-1] = '\0';
+	klip->li_algorithm[MAXALGLEN-1] = '\0';
+	klip->li_cipher[CRYPTO_MAX_MECH_NAME-1] = '\0';
+	klip->li_iv_cipher[CRYPTO_MAX_MECH_NAME-1] = '\0';
+
+	if (klip->li_minor > L_MAXMIN32) {
+		error = EINVAL;
+		goto err;
 	}
 
-	/* make sure filename is always null-terminated */
-	klip->li_filename[MAXPATHLEN-1] = '\0';
+	return (0);
 
-	/* validate minor number */
-	if (klip->li_minor > lofi_max_files) {
-		free_lofi_ioctl(klip);
-		cmn_err(CE_WARN, "attempt to map more than lofi_max_files (%d)",
-		    lofi_max_files);
-		return (NULL);
-	}
-	return (klip);
+err:
+	free_lofi_ioctl(klip);
+	return (error);
 }
 
 int
@@ -1547,45 +1606,76 @@
 	return (0);
 }
 
-/*
- * Return the minor number 'filename' is mapped to, if it is.
- */
 static int
-file_to_minor(char *filename)
+lofi_access(struct lofi_state *lsp)
 {
-	minor_t	minor;
-	struct lofi_state *lsp;
-
-	ASSERT(mutex_owned(&lofi_lock));
-	for (minor = 1; minor <= lofi_max_files; minor++) {
-		lsp = ddi_get_soft_state(lofi_statep, minor);
-		if (lsp == NULL)
-			continue;
-		if (strcmp(lsp->ls_filename, filename) == 0)
-			return (minor);
-	}
-	return (0);
+	ASSERT(MUTEX_HELD(&lofi_lock));
+	if (INGLOBALZONE(curproc) || lsp->ls_zone == curproc->p_zone)
+		return (0);
+	return (EPERM);
 }
 
 /*
- * lofiadm does some validation, but since Joe Random (or crashme) could
- * do our ioctls, we need to do some validation too.
+ * Find the lofi state for the given filename. We compare by vnode to
+ * allow the global zone visibility into NGZ lofi nodes.
  */
 static int
-valid_filename(const char *filename)
+file_to_lofi_nocheck(char *filename, struct lofi_state **lspp)
 {
-	static char *blkprefix = "/dev/" LOFI_BLOCK_NAME "/";
-	static char *charprefix = "/dev/" LOFI_CHAR_NAME "/";
+	struct lofi_state *lsp;
+	vnode_t *vp = NULL;
+	int err = 0;
+
+	ASSERT(MUTEX_HELD(&lofi_lock));
+
+	if ((err = lookupname(filename, UIO_SYSSPACE, FOLLOW,
+	    NULLVPP, &vp)) != 0)
+		goto out;
+
+	if (vp->v_type == VREG) {
+		vnode_t *realvp;
+		if (VOP_REALVP(vp, &realvp, NULL) == 0) {
+			VN_HOLD(realvp);
+			VN_RELE(vp);
+			vp = realvp;
+		}
+	}
 
-	/* must be absolute path */
-	if (filename[0] != '/')
-		return (0);
-	/* must not be lofi */
-	if (strncmp(filename, blkprefix, strlen(blkprefix)) == 0)
-		return (0);
-	if (strncmp(filename, charprefix, strlen(charprefix)) == 0)
-		return (0);
-	return (1);
+	for (lsp = list_head(&lofi_list); lsp != NULL;
+	    lsp = list_next(&lofi_list, lsp)) {
+		if (lsp->ls_vp == vp) {
+			if (lspp != NULL)
+				*lspp = lsp;
+			goto out;
+		}
+	}
+
+	err = ENOENT;
+
+out:
+	if (vp != NULL)
+		VN_RELE(vp);
+	return (err);
+}
+
+/*
+ * Find the minor for the given filename, checking the zone can access
+ * it.
+ */
+static int
+file_to_lofi(char *filename, struct lofi_state **lspp)
+{
+	int err = 0;
+
+	ASSERT(MUTEX_HELD(&lofi_lock));
+
+	if ((err = file_to_lofi_nocheck(filename, lspp)) != 0)
+		return (err);
+
+	if ((err = lofi_access(*lspp)) != 0)
+		return (err);
+
+	return (0);
 }
 
 /*
@@ -1790,342 +1880,89 @@
 		    BE_64(lsp->ls_comp_seg_index[i]);
 	}
 
-	/*
-	 * Finally setup per-thread pre-allocated buffers
-	 */
-	lsp->ls_comp_bufs = kmem_zalloc(lofi_taskq_nthreads *
-	    sizeof (struct compbuf), KM_SLEEP);
-	mutex_init(&lsp->ls_comp_bufs_lock, NULL, MUTEX_DRIVER, NULL);
-
 	return (error);
 }
 
-/*
- * Check to see if the passed in signature is a valid
- * one.  If it is valid, return the index into
- * lofi_compress_table.
- *
- * Return -1 if it is invalid
- */
-static int lofi_compress_select(char *signature)
+static int
+lofi_init_crypto(struct lofi_state *lsp, struct lofi_ioctl *klip)
 {
+	struct crypto_meta chead;
+	char buf[DEV_BSIZE];
+	ssize_t	resid;
+	char *marker;
+	int error;
+	int ret;
 	int i;
 
-	for (i = 0; i < LOFI_COMPRESS_FUNCTIONS; i++) {
-		if (strcmp(lofi_compress_table[i].l_name, signature) == 0)
-			return (i);
-	}
+	if (!klip->li_crypto_enabled)
+		return (0);
 
-	return (-1);
-}
+	/*
+	 * All current algorithms have a max of 448 bits.
+	 */
+	if (klip->li_iv_len > CRYPTO_BITS2BYTES(512))
+		return (EINVAL);
 
-/*
- * map a file to a minor number. Return the minor number.
- */
-static int
-lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor,
-    int *rvalp, struct cred *credp, int ioctl_flag)
-{
-	minor_t	newminor;
-	struct lofi_state *lsp;
-	struct lofi_ioctl *klip;
-	int	error;
-	struct vnode *vp;
-	int64_t	Nblocks_prop_val;
-	int64_t	Size_prop_val;
-	int	compress_index;
-	vattr_t	vattr;
-	int	flag;
-	enum vtype v_type;
-	int zalloced = 0;
-	dev_t	newdev;
-	char	namebuf[50];
-	char	buf[DEV_BSIZE];
-	char	crybuf[DEV_BSIZE];
-	ssize_t	resid;
-	boolean_t need_vn_close = B_FALSE;
-	boolean_t keycopied = B_FALSE;
-	boolean_t need_size_update = B_FALSE;
+	if (CRYPTO_BITS2BYTES(klip->li_key_len) > sizeof (klip->li_key))
+		return (EINVAL);
+
+	lsp->ls_crypto_enabled = klip->li_crypto_enabled;
 
-	klip = copy_in_lofi_ioctl(ulip, ioctl_flag);
-	if (klip == NULL)
-		return (EFAULT);
-
-	mutex_enter(&lofi_lock);
-
-	if (!valid_filename(klip->li_filename)) {
-		error = EINVAL;
-		goto out;
-	}
-
-	if (file_to_minor(klip->li_filename) != 0) {
-		error = EBUSY;
-		goto out;
-	}
+	mutex_init(&lsp->ls_crypto_lock, NULL, MUTEX_DRIVER, NULL);
 
-	if (pickminor) {
-		/* Find a free one */
-		for (newminor = 1; newminor <= lofi_max_files; newminor++)
-			if (ddi_get_soft_state(lofi_statep, newminor) == NULL)
-				break;
-		if (newminor >= lofi_max_files) {
-			error = EAGAIN;
-			goto out;
-		}
-	} else {
-		newminor = klip->li_minor;
-		if (ddi_get_soft_state(lofi_statep, newminor) != NULL) {
-			error = EEXIST;
-			goto out;
-		}
+	lsp->ls_mech.cm_type = crypto_mech2id(klip->li_cipher);
+	if (lsp->ls_mech.cm_type == CRYPTO_MECH_INVALID) {
+		cmn_err(CE_WARN, "invalid cipher %s requested for %s",
+		    klip->li_cipher, klip->li_filename);
+		return (EINVAL);
 	}
 
-	/* make sure it's valid */
-	error = lookupname(klip->li_filename, UIO_SYSSPACE, FOLLOW,
-	    NULLVPP, &vp);
-	if (error) {
-		goto out;
-	}
-	v_type = vp->v_type;
-	VN_RELE(vp);
-	if (!V_ISLOFIABLE(v_type)) {
-		error = EINVAL;
-		goto out;
-	}
-	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
-	error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0, &vp, 0, 0);
-	if (error) {
-		/* try read-only */
-		flag &= ~FWRITE;
-		error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0,
-		    &vp, 0, 0);
-		if (error) {
-			goto out;
-		}
-	}
-	need_vn_close = B_TRUE;
+	/* this is just initialization here */
+	lsp->ls_mech.cm_param = NULL;
+	lsp->ls_mech.cm_param_len = 0;
 
-	vattr.va_mask = AT_SIZE;
-	error = VOP_GETATTR(vp, &vattr, 0, credp, NULL);
-	if (error) {
-		goto out;
-	}
-	/* the file needs to be a multiple of the block size */
-	if ((vattr.va_size % DEV_BSIZE) != 0) {
-		error = EINVAL;
-		goto out;
-	}
-	newdev = makedevice(getmajor(dev), newminor);
-	Size_prop_val = vattr.va_size;
-	if ((ddi_prop_update_int64(newdev, lofi_dip,
-	    SIZE_PROP_NAME, Size_prop_val)) != DDI_PROP_SUCCESS) {
-		error = EINVAL;
-		goto out;
-	}
-	Nblocks_prop_val = vattr.va_size / DEV_BSIZE;
-	if ((ddi_prop_update_int64(newdev, lofi_dip,
-	    NBLOCKS_PROP_NAME, Nblocks_prop_val)) != DDI_PROP_SUCCESS) {
-		error = EINVAL;
-		goto propout;
+	lsp->ls_iv_type = klip->li_iv_type;
+	lsp->ls_iv_mech.cm_type = crypto_mech2id(klip->li_iv_cipher);
+	if (lsp->ls_iv_mech.cm_type == CRYPTO_MECH_INVALID) {
+		cmn_err(CE_WARN, "invalid iv cipher %s requested"
+		    " for %s", klip->li_iv_cipher, klip->li_filename);
+		return (EINVAL);
 	}
-	error = ddi_soft_state_zalloc(lofi_statep, newminor);
-	if (error == DDI_FAILURE) {
-		error = ENOMEM;
-		goto propout;
-	}
-	zalloced = 1;
-	(void) snprintf(namebuf, sizeof (namebuf), "%d", newminor);
-	error = ddi_create_minor_node(lofi_dip, namebuf, S_IFBLK, newminor,
-	    DDI_PSEUDO, NULL);
-	if (error != DDI_SUCCESS) {
-		error = ENXIO;
-		goto propout;
-	}
-	(void) snprintf(namebuf, sizeof (namebuf), "%d,raw", newminor);
-	error = ddi_create_minor_node(lofi_dip, namebuf, S_IFCHR, newminor,
-	    DDI_PSEUDO, NULL);
-	if (error != DDI_SUCCESS) {
-		/* remove block node */
-		(void) snprintf(namebuf, sizeof (namebuf), "%d", newminor);
-		ddi_remove_minor_node(lofi_dip, namebuf);
-		error = ENXIO;
-		goto propout;
-	}
-	lsp = ddi_get_soft_state(lofi_statep, newminor);
-	lsp->ls_filename_sz = strlen(klip->li_filename) + 1;
-	lsp->ls_filename = kmem_alloc(lsp->ls_filename_sz, KM_SLEEP);
-	(void) snprintf(namebuf, sizeof (namebuf), "%s_taskq_%d",
-	    LOFI_DRIVER_NAME, newminor);
-	lsp->ls_taskq = taskq_create(namebuf, lofi_taskq_nthreads,
-	    minclsyspri, 1, lofi_taskq_maxalloc, 0);
-	lsp->ls_kstat = kstat_create(LOFI_DRIVER_NAME, newminor,
-	    NULL, "disk", KSTAT_TYPE_IO, 1, 0);
-	if (lsp->ls_kstat) {
-		mutex_init(&lsp->ls_kstat_lock, NULL, MUTEX_DRIVER, NULL);
-		lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock;
-		kstat_install(lsp->ls_kstat);
-	}
-	cv_init(&lsp->ls_vp_cv, NULL, CV_DRIVER, NULL);
-	mutex_init(&lsp->ls_vp_lock, NULL, MUTEX_DRIVER, NULL);
 
-	list_create(&lsp->ls_comp_cache, sizeof (struct lofi_comp_cache),
-	    offsetof(struct lofi_comp_cache, lc_list));
-	mutex_init(&lsp->ls_comp_cache_lock, NULL, MUTEX_DRIVER, NULL);
-
-	/*
-	 * save open mode so file can be closed properly and vnode counts
-	 * updated correctly.
-	 */
-	lsp->ls_openflag = flag;
+	/* iv mech must itself take a null iv */
+	lsp->ls_iv_mech.cm_param = NULL;
+	lsp->ls_iv_mech.cm_param_len = 0;
+	lsp->ls_iv_len = klip->li_iv_len;
 
 	/*
-	 * Try to handle stacked lofs vnodes.
+	 * Create ctx using li_cipher & the raw li_key after checking
+	 * that it isn't a weak key.
 	 */
-	if (vp->v_type == VREG) {
-		if (VOP_REALVP(vp, &lsp->ls_vp, NULL) != 0) {
-			lsp->ls_vp = vp;
-		} else {
-			/*
-			 * Even though vp was obtained via vn_open(), we
-			 * can't call vn_close() on it, since lofs will
-			 * pass the VOP_CLOSE() on down to the realvp
-			 * (which we are about to use). Hence we merely
-			 * drop the reference to the lofs vnode and hold
-			 * the realvp so things behave as if we've
-			 * opened the realvp without any interaction
-			 * with lofs.
-			 */
-			VN_HOLD(lsp->ls_vp);
-			VN_RELE(vp);
-		}
-	} else {
-		lsp->ls_vp = vp;
+	lsp->ls_key.ck_format = CRYPTO_KEY_RAW;
+	lsp->ls_key.ck_length = klip->li_key_len;
+	lsp->ls_key.ck_data = kmem_alloc(
+	    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length), KM_SLEEP);
+	bcopy(klip->li_key, lsp->ls_key.ck_data,
+	    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length));
+
+	ret = crypto_key_check(&lsp->ls_mech, &lsp->ls_key);
+	if (ret != CRYPTO_SUCCESS) {
+		cmn_err(CE_WARN, "weak key check failed for cipher "
+		    "%s on file %s (0x%x)", klip->li_cipher,
+		    klip->li_filename, ret);
+		return (EINVAL);
 	}
-	lsp->ls_vp_size = vattr.va_size;
-	(void) strcpy(lsp->ls_filename, klip->li_filename);
-	if (rvalp)
-		*rvalp = (int)newminor;
-	klip->li_minor = newminor;
+
+	error = vn_rdwr(UIO_READ, lsp->ls_vp, buf, DEV_BSIZE,
+	    CRYOFF, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
+	if (error != 0)
+		return (error);
 
 	/*
-	 * Initialize crypto details for encrypted lofi
+	 * This is the case where the header in the lofi image is already
+	 * initialized to indicate it is encrypted.
 	 */
-	if (klip->li_crypto_enabled) {
-		int ret;
-
-		mutex_init(&lsp->ls_crypto_lock, NULL, MUTEX_DRIVER, NULL);
-
-		lsp->ls_mech.cm_type = crypto_mech2id(klip->li_cipher);
-		if (lsp->ls_mech.cm_type == CRYPTO_MECH_INVALID) {
-			cmn_err(CE_WARN, "invalid cipher %s requested for %s",
-			    klip->li_cipher, lsp->ls_filename);
-			error = EINVAL;
-			goto propout;
-		}
-
-		/* this is just initialization here */
-		lsp->ls_mech.cm_param = NULL;
-		lsp->ls_mech.cm_param_len = 0;
-
-		lsp->ls_iv_type = klip->li_iv_type;
-		lsp->ls_iv_mech.cm_type = crypto_mech2id(klip->li_iv_cipher);
-		if (lsp->ls_iv_mech.cm_type == CRYPTO_MECH_INVALID) {
-			cmn_err(CE_WARN, "invalid iv cipher %s requested"
-			    " for %s", klip->li_iv_cipher, lsp->ls_filename);
-			error = EINVAL;
-			goto propout;
-		}
-
-		/* iv mech must itself take a null iv */
-		lsp->ls_iv_mech.cm_param = NULL;
-		lsp->ls_iv_mech.cm_param_len = 0;
-		lsp->ls_iv_len = klip->li_iv_len;
-
-		/*
-		 * Create ctx using li_cipher & the raw li_key after checking
-		 * that it isn't a weak key.
-		 */
-		lsp->ls_key.ck_format = CRYPTO_KEY_RAW;
-		lsp->ls_key.ck_length = klip->li_key_len;
-		lsp->ls_key.ck_data = kmem_alloc(
-		    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length), KM_SLEEP);
-		bcopy(klip->li_key, lsp->ls_key.ck_data,
-		    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length));
-		keycopied = B_TRUE;
-
-		ret = crypto_key_check(&lsp->ls_mech, &lsp->ls_key);
-		if (ret != CRYPTO_SUCCESS) {
-			error = EINVAL;
-			cmn_err(CE_WARN, "weak key check failed for cipher "
-			    "%s on file %s (0x%x)", klip->li_cipher,
-			    lsp->ls_filename, ret);
-			goto propout;
-		}
-	}
-	lsp->ls_crypto_enabled = klip->li_crypto_enabled;
-
-	/*
-	 * Read the file signature to check if it is compressed or encrypted.
-	 * Crypto signature is in a different location; both areas should
-	 * read to keep compression and encryption mutually exclusive.
-	 */
-	if (lsp->ls_crypto_enabled) {
-		error = vn_rdwr(UIO_READ, lsp->ls_vp, crybuf, DEV_BSIZE,
-		    CRYOFF, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
-		if (error != 0)
-			goto propout;
-	}
-	error = vn_rdwr(UIO_READ, lsp->ls_vp, buf, DEV_BSIZE, 0, UIO_SYSSPACE,
-	    0, RLIM64_INFINITY, kcred, &resid);
-	if (error != 0)
-		goto propout;
-
-	/* initialize these variables for all lofi files */
-	lsp->ls_comp_bufs = NULL;
-	lsp->ls_uncomp_seg_sz = 0;
-	lsp->ls_vp_comp_size = lsp->ls_vp_size;
-	lsp->ls_comp_algorithm[0] = '\0';
-
-	/* encrypted lofi reads/writes shifted by crypto metadata size */
-	lsp->ls_crypto_offset = 0;
-
-	/* this is a compressed lofi */
-	if ((compress_index = lofi_compress_select(buf)) != -1) {
-
-		/* compression and encryption are mutually exclusive */
-		if (klip->li_crypto_enabled) {
-			error = ENOTSUP;
-			goto propout;
-		}
-
-		/* initialize compression info for compressed lofi */
-		lsp->ls_comp_algorithm_index = compress_index;
-		(void) strlcpy(lsp->ls_comp_algorithm,
-		    lofi_compress_table[compress_index].l_name,
-		    sizeof (lsp->ls_comp_algorithm));
-
-		error = lofi_map_compressed_file(lsp, buf);
-		if (error != 0)
-			goto propout;
-		need_size_update = B_TRUE;
-
-	/* this is an encrypted lofi */
-	} else if (strncmp(crybuf, lofi_crypto_magic,
-	    sizeof (lofi_crypto_magic)) == 0) {
-
-		char *marker = crybuf;
-
-		/*
-		 * This is the case where the header in the lofi image is
-		 * already initialized to indicate it is encrypted.
-		 * There is another case (see below) where encryption is
-		 * requested but the lofi image has never been used yet,
-		 * so the header needs to be written with encryption magic.
-		 */
-
-		/* indicate this must be an encrypted lofi due to magic */
-		klip->li_crypto_enabled = B_TRUE;
-
+	if (strncmp(buf, lofi_crypto_magic, sizeof (lofi_crypto_magic)) == 0) {
 		/*
 		 * The encryption header information is laid out this way:
 		 *	6 bytes:	hex "CFLOFI"
@@ -2135,6 +1972,8 @@
 		 *	more...		not implemented yet
 		 */
 
+		marker = buf;
+
 		/* copy the magic */
 		bcopy(marker, lsp->ls_crypto.magic,
 		    sizeof (lsp->ls_crypto.magic));
@@ -2160,106 +1999,326 @@
 		/* and ignore the rest until it is implemented */
 
 		lsp->ls_crypto_offset = lsp->ls_crypto.data_sector * DEV_BSIZE;
-		need_size_update = B_TRUE;
-
-	/* neither compressed nor encrypted, BUT could be new encrypted lofi */
-	} else if (klip->li_crypto_enabled) {
-
-		/*
-		 * This is the case where encryption was requested but the
-		 * appears to be entirely blank where the encryption header
-		 * would have been in the lofi image.  If it is blank,
-		 * assume it is a brand new lofi image and initialize the
-		 * header area with encryption magic and current version
-		 * header data.  If it is not blank, that's an error.
-		 */
-		int	i;
-		char	*marker;
-		struct crypto_meta	chead;
-
-		for (i = 0; i < sizeof (struct crypto_meta); i++)
-			if (crybuf[i] != '\0')
-				break;
-		if (i != sizeof (struct crypto_meta)) {
-			error = EINVAL;
-			goto propout;
-		}
-
-		/* nothing there, initialize as encrypted lofi */
-		marker = crybuf;
-		bcopy(lofi_crypto_magic, marker, sizeof (lofi_crypto_magic));
-		marker += sizeof (lofi_crypto_magic);
-		chead.version = htons(LOFI_CRYPTO_VERSION);
-		bcopy(&(chead.version), marker, sizeof (chead.version));
-		marker += sizeof (chead.version);
-		marker += sizeof (chead.reserved1);
-		chead.data_sector = htonl(LOFI_CRYPTO_DATA_SECTOR);
-		bcopy(&(chead.data_sector), marker, sizeof (chead.data_sector));
-
-		/* write the header */
-		error = vn_rdwr(UIO_WRITE, lsp->ls_vp, crybuf, DEV_BSIZE,
-		    CRYOFF, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
-		if (error != 0)
-			goto propout;
-
-		/* fix things up so it looks like we read this info */
-		bcopy(lofi_crypto_magic, lsp->ls_crypto.magic,
-		    sizeof (lofi_crypto_magic));
-		lsp->ls_crypto.version = LOFI_CRYPTO_VERSION;
-		lsp->ls_crypto.data_sector = LOFI_CRYPTO_DATA_SECTOR;
-
-		lsp->ls_crypto_offset = lsp->ls_crypto.data_sector * DEV_BSIZE;
-		need_size_update = B_TRUE;
+		return (0);
 	}
 
 	/*
-	 * Either lsp->ls_vp_size or lsp->ls_crypto_offset changed;
-	 * for encrypted lofi, advertise that it is somewhat shorter
-	 * due to embedded crypto metadata section
+	 * We've requested encryption, but no magic was found, so it must be
+	 * a new image.
 	 */
-	if (need_size_update) {
-		/* update DDI properties */
-		Size_prop_val = lsp->ls_vp_size - lsp->ls_crypto_offset;
-		if ((ddi_prop_update_int64(newdev, lofi_dip, SIZE_PROP_NAME,
-		    Size_prop_val)) != DDI_PROP_SUCCESS) {
-			error = EINVAL;
-			goto propout;
+
+	for (i = 0; i < sizeof (struct crypto_meta); i++) {
+		if (buf[i] != '\0')
+			return (EINVAL);
+	}
+
+	marker = buf;
+	bcopy(lofi_crypto_magic, marker, sizeof (lofi_crypto_magic));
+	marker += sizeof (lofi_crypto_magic);
+	chead.version = htons(LOFI_CRYPTO_VERSION);
+	bcopy(&(chead.version), marker, sizeof (chead.version));
+	marker += sizeof (chead.version);
+	marker += sizeof (chead.reserved1);
+	chead.data_sector = htonl(LOFI_CRYPTO_DATA_SECTOR);
+	bcopy(&(chead.data_sector), marker, sizeof (chead.data_sector));
+
+	/* write the header */
+	error = vn_rdwr(UIO_WRITE, lsp->ls_vp, buf, DEV_BSIZE,
+	    CRYOFF, UIO_SYSSPACE, 0, RLIM64_INFINITY, kcred, &resid);
+	if (error != 0)
+		return (error);
+
+	/* fix things up so it looks like we read this info */
+	bcopy(lofi_crypto_magic, lsp->ls_crypto.magic,
+	    sizeof (lofi_crypto_magic));
+	lsp->ls_crypto.version = LOFI_CRYPTO_VERSION;
+	lsp->ls_crypto.data_sector = LOFI_CRYPTO_DATA_SECTOR;
+	lsp->ls_crypto_offset = lsp->ls_crypto.data_sector * DEV_BSIZE;
+	return (0);
+}
+
+/*
+ * Check to see if the passed in signature is a valid one.  If it is
+ * valid, return the index into lofi_compress_table.
+ *
+ * Return -1 if it is invalid
+ */
+static int
+lofi_compress_select(const char *signature)
+{
+	int i;
+
+	for (i = 0; i < LOFI_COMPRESS_FUNCTIONS; i++) {
+		if (strcmp(lofi_compress_table[i].l_name, signature) == 0)
+			return (i);
+	}
+
+	return (-1);
+}
+
+static int
+lofi_init_compress(struct lofi_state *lsp)
+{
+	char buf[DEV_BSIZE];
+	int compress_index;
+	ssize_t	resid;
+	int error;
+
+	error = vn_rdwr(UIO_READ, lsp->ls_vp, buf, DEV_BSIZE, 0, UIO_SYSSPACE,
+	    0, RLIM64_INFINITY, kcred, &resid);
+
+	if (error != 0)
+		return (error);
+
+	if ((compress_index = lofi_compress_select(buf)) == -1)
+		return (0);
+
+	/* compression and encryption are mutually exclusive */
+	if (lsp->ls_crypto_enabled)
+		return (ENOTSUP);
+
+	/* initialize compression info for compressed lofi */
+	lsp->ls_comp_algorithm_index = compress_index;
+	(void) strlcpy(lsp->ls_comp_algorithm,
+	    lofi_compress_table[compress_index].l_name,
+	    sizeof (lsp->ls_comp_algorithm));
+
+	/* Finally setup per-thread pre-allocated buffers */
+	lsp->ls_comp_bufs = kmem_zalloc(lofi_taskq_nthreads *
+	    sizeof (struct compbuf), KM_SLEEP);
+
+	return (lofi_map_compressed_file(lsp, buf));
+}
+
+/*
+ * map a file to a minor number. Return the minor number.
+ */
+static int
+lofi_map_file(dev_t dev, struct lofi_ioctl *ulip, int pickminor,
+    int *rvalp, struct cred *credp, int ioctl_flag)
+{
+	minor_t	minor = (minor_t)-1;
+	struct lofi_state *lsp = NULL;
+	struct lofi_ioctl *klip;
+	int	error;
+	struct vnode *vp = NULL;
+	vattr_t	vattr;
+	int	flag;
+	dev_t	newdev;
+	char	namebuf[50];
+
+	error = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag);
+	if (error != 0)
+		return (error);
+
+	mutex_enter(&lofi_lock);
+
+	mutex_enter(&curproc->p_lock);
+	if ((error = rctl_incr_lofi(curproc, curproc->p_zone, 1)) != 0) {
+		mutex_exit(&curproc->p_lock);
+		mutex_exit(&lofi_lock);
+		free_lofi_ioctl(klip);
+		return (error);
+	}
+	mutex_exit(&curproc->p_lock);
+
+	if (file_to_lofi_nocheck(klip->li_filename, NULL) == 0) {
+		error = EBUSY;
+		goto err;
+	}
+
+	if (pickminor) {
+		minor = (minor_t)id_allocff_nosleep(lofi_minor_id);
+		if (minor == (minor_t)-1) {
+			error = EAGAIN;
+			goto err;
 		}
-		Nblocks_prop_val =
-		    (lsp->ls_vp_size - lsp->ls_crypto_offset) / DEV_BSIZE;
-		if ((ddi_prop_update_int64(newdev, lofi_dip, NBLOCKS_PROP_NAME,
-		    Nblocks_prop_val)) != DDI_PROP_SUCCESS) {
-			error = EINVAL;
-			goto propout;
+	} else {
+		if (ddi_get_soft_state(lofi_statep, klip->li_minor) != NULL) {
+			error = EEXIST;
+			goto err;
+		}
+
+		minor = (minor_t)
+		    id_alloc_specific_nosleep(lofi_minor_id, klip->li_minor);
+		ASSERT(minor != (minor_t)-1);
+	}
+
+	flag = FREAD | FWRITE | FOFFMAX | FEXCL;
+	error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0, &vp, 0, 0);
+	if (error) {
+		/* try read-only */
+		flag &= ~FWRITE;
+		error = vn_open(klip->li_filename, UIO_SYSSPACE, flag, 0,
+		    &vp, 0, 0);
+		if (error)
+			goto err;
+	}
+
+	if (!V_ISLOFIABLE(vp->v_type)) {
+		error = EINVAL;
+		goto err;
+	}
+
+	vattr.va_mask = AT_SIZE;
+	error = VOP_GETATTR(vp, &vattr, 0, credp, NULL);
+	if (error)
+		goto err;
+
+	/* the file needs to be a multiple of the block size */
+	if ((vattr.va_size % DEV_BSIZE) != 0) {
+		error = EINVAL;
+		goto err;
+	}
+
+	/* lsp alloc+init */
+
+	error = ddi_soft_state_zalloc(lofi_statep, minor);
+	if (error == DDI_FAILURE) {
+		error = ENOMEM;
+		goto err;
+	}
+
+	lsp = ddi_get_soft_state(lofi_statep, minor);
+	list_insert_tail(&lofi_list, lsp);
+
+	newdev = makedevice(getmajor(dev), minor);
+	lsp->ls_dev = newdev;
+	lsp->ls_zone = zone_find_by_id(getzoneid());
+	ASSERT(lsp->ls_zone != NULL);
+	lsp->ls_uncomp_seg_sz = 0;
+	lsp->ls_comp_algorithm[0] = '\0';
+	lsp->ls_crypto_offset = 0;
+
+	cv_init(&lsp->ls_vp_cv, NULL, CV_DRIVER, NULL);
+	mutex_init(&lsp->ls_comp_cache_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&lsp->ls_comp_bufs_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&lsp->ls_kstat_lock, NULL, MUTEX_DRIVER, NULL);
+	mutex_init(&lsp->ls_vp_lock, NULL, MUTEX_DRIVER, NULL);
+
+	(void) snprintf(namebuf, sizeof (namebuf), "%s_taskq_%d",
+	    LOFI_DRIVER_NAME, minor);
+	lsp->ls_taskq = taskq_create_proc(namebuf, lofi_taskq_nthreads,
+	    minclsyspri, 1, lofi_taskq_maxalloc, curzone->zone_zsched, 0);
+
+	list_create(&lsp->ls_comp_cache, sizeof (struct lofi_comp_cache),
+	    offsetof(struct lofi_comp_cache, lc_list));
+
+	/*
+	 * save open mode so file can be closed properly and vnode counts
+	 * updated correctly.
+	 */
+	lsp->ls_openflag = flag;
+
+	lsp->ls_vp = vp;
+	lsp->ls_stacked_vp = vp;
+	/*
+	 * Try to handle stacked lofs vnodes.
+	 */
+	if (vp->v_type == VREG) {
+		vnode_t *realvp;
+
+		if (VOP_REALVP(vp, &realvp, NULL) == 0) {
+			/*
+			 * We need to use the realvp for uniqueness
+			 * checking, but keep the stacked vp for
+			 * LOFI_GET_FILENAME display.
+			 */
+			VN_HOLD(realvp);
+			lsp->ls_vp = realvp;
 		}
 	}
 
+	lsp->ls_vp_size = vattr.va_size;
+	lsp->ls_vp_comp_size = lsp->ls_vp_size;
+
+	lsp->ls_kstat = kstat_create_zone(LOFI_DRIVER_NAME, minor,
+	    NULL, "disk", KSTAT_TYPE_IO, 1, 0, getzoneid());
+
+	if (lsp->ls_kstat == NULL) {
+		error = ENOMEM;
+		goto err;
+	}
+
+	lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock;
+	kstat_zone_add(lsp->ls_kstat, GLOBAL_ZONEID);
+
+	if ((error = lofi_init_crypto(lsp, klip)) != 0)
+		goto err;
+
+	if ((error = lofi_init_compress(lsp)) != 0)
+		goto err;
+
 	fake_disk_geometry(lsp);
+
+	/* create minor nodes */
+
+	(void) snprintf(namebuf, sizeof (namebuf), "%d", minor);
+	error = ddi_create_minor_node(lofi_dip, namebuf, S_IFBLK, minor,
+	    DDI_PSEUDO, NULL);
+	if (error != DDI_SUCCESS) {
+		error = ENXIO;
+		goto err;
+	}
+
+	(void) snprintf(namebuf, sizeof (namebuf), "%d,raw", minor);
+	error = ddi_create_minor_node(lofi_dip, namebuf, S_IFCHR, minor,
+	    DDI_PSEUDO, NULL);
+	if (error != DDI_SUCCESS) {
+		/* remove block node */
+		(void) snprintf(namebuf, sizeof (namebuf), "%d", minor);
+		ddi_remove_minor_node(lofi_dip, namebuf);
+		error = ENXIO;
+		goto err;
+	}
+
+	/* create DDI properties */
+
+	if ((ddi_prop_update_int64(newdev, lofi_dip, SIZE_PROP_NAME,
+	    lsp->ls_vp_size - lsp->ls_crypto_offset)) != DDI_PROP_SUCCESS) {
+		error = EINVAL;
+		goto nodeerr;
+	}
+
+	if ((ddi_prop_update_int64(newdev, lofi_dip, NBLOCKS_PROP_NAME,
+	    (lsp->ls_vp_size - lsp->ls_crypto_offset) / DEV_BSIZE))
+	    != DDI_PROP_SUCCESS) {
+		error = EINVAL;
+		goto nodeerr;
+	}
+
+	if (ddi_prop_update_string(newdev, lofi_dip, ZONE_PROP_NAME,
+	    (char *)curproc->p_zone->zone_name) != DDI_PROP_SUCCESS) {
+		error = EINVAL;
+		goto nodeerr;
+	}
+
+	kstat_install(lsp->ls_kstat);
+
 	mutex_exit(&lofi_lock);
+
+	if (rvalp)
+		*rvalp = (int)minor;
+	klip->li_minor = minor;
 	(void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
 	free_lofi_ioctl(klip);
 	return (0);
 
-propout:
-	if (keycopied) {
-		bzero(lsp->ls_key.ck_data,
-		    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length));
-		kmem_free(lsp->ls_key.ck_data,
-		    CRYPTO_BITS2BYTES(lsp->ls_key.ck_length));
-		lsp->ls_key.ck_data = NULL;
-		lsp->ls_key.ck_length = 0;
-	}
+nodeerr:
+	lofi_free_dev(newdev);
+err:
+	if (lsp != NULL) {
+		lofi_destroy(lsp, credp);
+	} else {
+		if (vp != NULL) {
+			(void) VOP_CLOSE(vp, flag, 1, 0, credp, NULL);
+			VN_RELE(vp);
+		}
 
-	if (zalloced)
-		ddi_soft_state_free(lofi_statep, newminor);
+		if (minor != (minor_t)-1)
+			id_free(lofi_minor_id, minor);
 
-	(void) ddi_prop_remove(newdev, lofi_dip, SIZE_PROP_NAME);
-	(void) ddi_prop_remove(newdev, lofi_dip, NBLOCKS_PROP_NAME);
-
-out:
-	if (need_vn_close) {
-		(void) VOP_CLOSE(vp, flag, 1, 0, credp, NULL);
-		VN_RELE(vp);
+		rctl_decr_lofi(curproc->p_zone, 1);
 	}
 
 	mutex_exit(&lofi_lock);
@@ -2276,29 +2335,33 @@
 {
 	struct lofi_state *lsp;
 	struct lofi_ioctl *klip;
-	minor_t	minor;
+	int err;
 
-	klip = copy_in_lofi_ioctl(ulip, ioctl_flag);
-	if (klip == NULL)
-		return (EFAULT);
+	err = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag);
+	if (err != 0)
+		return (err);
 
 	mutex_enter(&lofi_lock);
 	if (byfilename) {
-		minor = file_to_minor(klip->li_filename);
+		if ((err = file_to_lofi(klip->li_filename, &lsp)) != 0) {
+			mutex_exit(&lofi_lock);
+			return (err);
+		}
+	} else if (klip->li_minor == 0) {
+		mutex_exit(&lofi_lock);
+		free_lofi_ioctl(klip);
+		return (ENXIO);
 	} else {
-		minor = klip->li_minor;
+		lsp = ddi_get_soft_state(lofi_statep, klip->li_minor);
 	}
-	if (minor == 0) {
+
+	if (lsp == NULL || lsp->ls_vp == NULL || lofi_access(lsp) != 0) {
 		mutex_exit(&lofi_lock);
 		free_lofi_ioctl(klip);
 		return (ENXIO);
 	}
-	lsp = ddi_get_soft_state(lofi_statep, minor);
-	if (lsp == NULL || lsp->ls_vp == NULL) {
-		mutex_exit(&lofi_lock);
-		free_lofi_ioctl(klip);
-		return (ENXIO);
-	}
+
+	klip->li_minor = getminor(lsp->ls_dev);
 
 	/*
 	 * If it's still held open, we'll do one of three things:
@@ -2331,13 +2394,8 @@
 			while (lsp->ls_vp_iocount > 0)
 				cv_wait(&lsp->ls_vp_cv, &lsp->ls_vp_lock);
 			mutex_exit(&lsp->ls_vp_lock);
-			lofi_free_handle(dev, minor, lsp, credp);
 
-			klip->li_minor = minor;
-			mutex_exit(&lofi_lock);
-			(void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
-			free_lofi_ioctl(klip);
-			return (0);
+			goto out;
 		} else if (klip->li_cleanup) {
 			lsp->ls_cleanup = 1;
 			mutex_exit(&lofi_lock);
@@ -2350,9 +2408,10 @@
 		return (EBUSY);
 	}
 
-	lofi_free_handle(dev, minor, lsp, credp);
+out:
+	lofi_free_dev(dev);
+	lofi_destroy(lsp, credp);
 
-	klip->li_minor = minor;
 	mutex_exit(&lofi_lock);
 	(void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
 	free_lofi_ioctl(klip);
@@ -2368,31 +2427,39 @@
 lofi_get_info(dev_t dev, struct lofi_ioctl *ulip, int which,
     struct cred *credp, int ioctl_flag)
 {
+	struct lofi_ioctl *klip;
 	struct lofi_state *lsp;
-	struct lofi_ioctl *klip;
 	int	error;
-	minor_t	minor;
 
-	klip = copy_in_lofi_ioctl(ulip, ioctl_flag);
-	if (klip == NULL)
-		return (EFAULT);
+	error = copy_in_lofi_ioctl(ulip, &klip, ioctl_flag);
+	if (error != 0)
+		return (error);
 
 	switch (which) {
 	case LOFI_GET_FILENAME:
-		minor = klip->li_minor;
-		if (minor == 0) {
+		if (klip->li_minor == 0) {
 			free_lofi_ioctl(klip);
 			return (EINVAL);
 		}
 
 		mutex_enter(&lofi_lock);
-		lsp = ddi_get_soft_state(lofi_statep, minor);
-		if (lsp == NULL) {
+		lsp = ddi_get_soft_state(lofi_statep, klip->li_minor);
+		if (lsp == NULL || lofi_access(lsp) != 0) {
 			mutex_exit(&lofi_lock);
 			free_lofi_ioctl(klip);
 			return (ENXIO);
 		}
-		(void) strcpy(klip->li_filename, lsp->ls_filename);
+
+		/*
+		 * This may fail if, for example, we're trying to look
+		 * up a zoned NFS path from the global zone.
+		 */
+		if (vnodetopath(NULL, lsp->ls_stacked_vp, klip->li_filename,
+		    sizeof (klip->li_filename), CRED()) != 0) {
+			(void) strlcpy(klip->li_filename, "?",
+			    sizeof (klip->li_filename));
+		}
+
 		(void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm,
 		    sizeof (klip->li_algorithm));
 		klip->li_crypto_enabled = lsp->ls_crypto_enabled;
@@ -2402,35 +2469,29 @@
 		return (error);
 	case LOFI_GET_MINOR:
 		mutex_enter(&lofi_lock);
-		klip->li_minor = file_to_minor(klip->li_filename);
-		/* caller should not depend on klip->li_crypto_enabled here */
+		error = file_to_lofi(klip->li_filename, &lsp);
+		if (error == 0)
+			klip->li_minor = getminor(lsp->ls_dev);
 		mutex_exit(&lofi_lock);
-		if (klip->li_minor == 0) {
-			free_lofi_ioctl(klip);
-			return (ENOENT);
-		}
-		error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
+
+		if (error == 0)
+			error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
+
 		free_lofi_ioctl(klip);
 		return (error);
 	case LOFI_CHECK_COMPRESSED:
 		mutex_enter(&lofi_lock);
-		klip->li_minor = file_to_minor(klip->li_filename);
-		mutex_exit(&lofi_lock);
-		if (klip->li_minor == 0) {
-			free_lofi_ioctl(klip);
-			return (ENOENT);
-		}
-		mutex_enter(&lofi_lock);
-		lsp = ddi_get_soft_state(lofi_statep, klip->li_minor);
-		if (lsp == NULL) {
+		error = file_to_lofi(klip->li_filename, &lsp);
+		if (error != 0) {
 			mutex_exit(&lofi_lock);
 			free_lofi_ioctl(klip);
-			return (ENXIO);
+			return (error);
 		}
-		ASSERT(strcmp(klip->li_filename, lsp->ls_filename) == 0);
 
+		klip->li_minor = getminor(lsp->ls_dev);
 		(void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm,
 		    sizeof (klip->li_algorithm));
+
 		mutex_exit(&lofi_lock);
 		error = copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
 		free_lofi_ioctl(klip);
@@ -2439,7 +2500,6 @@
 		free_lofi_ioctl(klip);
 		return (EINVAL);
 	}
-
 }
 
 static int
@@ -2484,17 +2544,41 @@
 		case LOFI_GET_MINOR:
 			return (lofi_get_info(dev, lip, LOFI_GET_MINOR,
 			    credp, flag));
+
+		/*
+		 * This API made limited sense when this value was fixed
+		 * at LOFI_MAX_FILES.  However, its use to iterate
+		 * across all possible devices in lofiadm means we don't
+		 * want to return L_MAXMIN32, but the highest
+		 * *allocated* minor.
+		 */
 		case LOFI_GET_MAXMINOR:
-			error = ddi_copyout(&lofi_max_files, &lip->li_minor,
-			    sizeof (lofi_max_files), flag);
+			minor = 0;
+
+			mutex_enter(&lofi_lock);
+
+			for (lsp = list_head(&lofi_list); lsp != NULL;
+			    lsp = list_next(&lofi_list, lsp)) {
+				if (lofi_access(lsp) != 0)
+					continue;
+
+				if (getminor(lsp->ls_dev) > minor)
+					minor = getminor(lsp->ls_dev);
+			}
+
+			mutex_exit(&lofi_lock);
+
+			error = ddi_copyout(&minor, &lip->li_minor,
+			    sizeof (minor), flag);
 			if (error)
 				return (EFAULT);
 			return (0);
+
 		case LOFI_CHECK_COMPRESSED:
 			return (lofi_get_info(dev, lip, LOFI_CHECK_COMPRESSED,
 			    credp, flag));
 		default:
-			break;
+			return (EINVAL);
 		}
 	}
 
@@ -2644,16 +2728,21 @@
 {
 	int error;
 
+	list_create(&lofi_list, sizeof (struct lofi_state),
+	    offsetof(struct lofi_state, ls_list));
+
 	error = ddi_soft_state_init(&lofi_statep,
 	    sizeof (struct lofi_state), 0);
 	if (error)
 		return (error);
 
 	mutex_init(&lofi_lock, NULL, MUTEX_DRIVER, NULL);
+
 	error = mod_install(&modlinkage);
 	if (error) {
 		mutex_destroy(&lofi_lock);
 		ddi_soft_state_fini(&lofi_statep);
+		list_destroy(&lofi_list);
 	}
 
 	return (error);
@@ -2664,8 +2753,14 @@
 {
 	int	error;
 
-	if (lofi_busy())
+	mutex_enter(&lofi_lock);
+
+	if (!list_is_empty(&lofi_list)) {
+		mutex_exit(&lofi_lock);
 		return (EBUSY);
+	}
+
+	mutex_exit(&lofi_lock);
 
 	error = mod_remove(&modlinkage);
 	if (error)
@@ -2673,6 +2768,7 @@
 
 	mutex_destroy(&lofi_lock);
 	ddi_soft_state_fini(&lofi_statep);
+	list_destroy(&lofi_list);
 
 	return (error);
 }
--- a/usr/src/uts/common/os/id_space.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/os/id_space.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/types.h>
@@ -47,7 +46,7 @@
  *   As an ID space is designed for representing a range of id_t's, there
  *   is a preexisting maximal range: [0, MAXUID].  ID space requests outside
  *   that range will fail on a DEBUG kernel.  The id_allocff*() functions
- *   return the first available id, and should be used when there is benifit
+ *   return the first available id, and should be used when there is benefit
  *   to having a compact allocated range.
  *
  *   (Presently, the id_space_t abstraction supports only direct allocations; ID
@@ -56,6 +55,9 @@
  *   arrives.)
  */
 
+#define	ID_TO_ADDR(id) ((void *)(uintptr_t)(id + 1))
+#define	ADDR_TO_ID(addr) ((id_t)((uintptr_t)addr - 1))
+
 /*
  * Create an arena to represent the range [low, high).
  * Caller must be in a context in which VM_SLEEP is legal.
@@ -66,7 +68,7 @@
 	ASSERT(low >= 0);
 	ASSERT(low < high);
 
-	return (vmem_create(name, (void *)(uintptr_t)(low + 1), high - low, 1,
+	return (vmem_create(name, ID_TO_ADDR(low), high - low, 1,
 	    NULL, NULL, NULL, 0, VM_SLEEP | VMC_IDENTIFIER));
 }
 
@@ -83,8 +85,7 @@
 void
 id_space_extend(id_space_t *isp, id_t low, id_t high)
 {
-	(void) vmem_add(isp,
-	    (void *)(uintptr_t)(low + 1), high - low, VM_SLEEP);
+	(void) vmem_add(isp, ID_TO_ADDR(low), high - low, VM_SLEEP);
 }
 
 /*
@@ -94,8 +95,7 @@
 id_t
 id_alloc(id_space_t *isp)
 {
-	return ((id_t)(uintptr_t)
-	    vmem_alloc(isp, 1, VM_SLEEP | VM_NEXTFIT) - 1);
+	return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_SLEEP | VM_NEXTFIT)));
 }
 
 /*
@@ -106,8 +106,7 @@
 id_t
 id_alloc_nosleep(id_space_t *isp)
 {
-	return ((id_t)(uintptr_t)
-	    vmem_alloc(isp, 1, VM_NOSLEEP | VM_NEXTFIT) - 1);
+	return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_NOSLEEP | VM_NEXTFIT)));
 }
 
 /*
@@ -117,8 +116,7 @@
 id_t
 id_allocff(id_space_t *isp)
 {
-	return ((id_t)(uintptr_t)
-	    vmem_alloc(isp, 1, VM_SLEEP | VM_FIRSTFIT) - 1);
+	return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_SLEEP | VM_FIRSTFIT)));
 }
 
 /*
@@ -129,8 +127,25 @@
 id_t
 id_allocff_nosleep(id_space_t *isp)
 {
-	return ((id_t)(uintptr_t)
-	    vmem_alloc(isp, 1, VM_NOSLEEP | VM_FIRSTFIT) - 1);
+	return (ADDR_TO_ID(vmem_alloc(isp, 1, VM_NOSLEEP | VM_FIRSTFIT)));
+}
+
+/*
+ * Allocate a specific identifier if possible, returning the id if
+ * successful, or -1 on failure.
+ */
+id_t
+id_alloc_specific_nosleep(id_space_t *isp, id_t id)
+{
+	void *minaddr = ID_TO_ADDR(id);
+	void *maxaddr = ID_TO_ADDR(id + 1);
+
+	/*
+	 * Note that even though we're vmem_free()ing this later, it
+	 * should be OK, since there's no quantum cache.
+	 */
+	return (ADDR_TO_ID(vmem_xalloc(isp, 1, 1, 0, 0,
+	    minaddr, maxaddr, VM_NOSLEEP)));
 }
 
 /*
@@ -140,5 +155,5 @@
 void
 id_free(id_space_t *isp, id_t id)
 {
-	vmem_free(isp, (void *)(uintptr_t)(id + 1), 1);
+	vmem_free(isp, ID_TO_ADDR(id), 1);
 }
--- a/usr/src/uts/common/os/policy.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/os/policy.c	Wed Jun 16 10:02:44 2010 -0700
@@ -755,6 +755,48 @@
 
 }
 
+int
+secpolicy_fs_allowed_mount(const char *fsname)
+{
+	struct vfssw *vswp;
+	const char *p;
+	size_t len;
+
+	ASSERT(fsname != NULL);
+	ASSERT(fsname[0] != '\0');
+
+	if (INGLOBALZONE(curproc))
+		return (0);
+
+	vswp = vfs_getvfssw(fsname);
+	if (vswp == NULL)
+		return (ENOENT);
+
+	if ((vswp->vsw_flag & VSW_ZMOUNT) != 0) {
+		vfs_unrefvfssw(vswp);
+		return (0);
+	}
+
+	vfs_unrefvfssw(vswp);
+
+	p = curzone->zone_fs_allowed;
+	len = strlen(fsname);
+
+	while (p != NULL && *p != '\0') {
+		if (strncmp(p, fsname, len) == 0) {
+			char c = *(p + len);
+			if (c == '\0' || c == ',')
+				return (0);
+		}
+
+		/* skip to beyond the next comma */
+		if ((p = strchr(p, ',')) != NULL)
+			p++;
+	}
+
+	return (EPERM);
+}
+
 extern vnode_t *rootvp;
 extern vfs_t *rootvfs;
 
--- a/usr/src/uts/common/os/rctl.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/os/rctl.c	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #include <sys/atomic.h>
@@ -3058,6 +3057,64 @@
 }
 
 /*
+ * rctl_incr_lofi(proc_t *, zone_t *, size_t)
+ *
+ * Overview
+ *   Increments the number of lofi devices for the zone.
+ *
+ * Return values
+ *   0 on success.  EAGAIN if increment fails due an rctl value
+ *   on the zone.
+ *
+ * Callers context
+ *   p_lock held on specified proc.
+ */
+int
+rctl_incr_lofi(proc_t *proc, zone_t *zone, size_t incr)
+{
+	rctl_entity_p_t e;
+
+	ASSERT(MUTEX_HELD(&proc->p_lock));
+	ASSERT(incr > 0);
+
+	e.rcep_p.zone = zone;
+	e.rcep_t = RCENTITY_ZONE;
+
+	mutex_enter(&zone->zone_rctl_lock);
+
+	/* Check for overflow */
+	if ((zone->zone_max_lofi + incr) < zone->zone_max_lofi) {
+		mutex_exit(&zone->zone_rctl_lock);
+		return (EAGAIN);
+	}
+	if ((zone->zone_max_lofi + incr) > zone->zone_max_lofi_ctl) {
+		if (rctl_test_entity(rc_zone_max_lofi, zone->zone_rctls,
+		    proc, &e, incr, 0) & RCT_DENY) {
+			mutex_exit(&zone->zone_rctl_lock);
+			return (EAGAIN);
+		}
+	}
+	zone->zone_max_lofi += incr;
+	mutex_exit(&zone->zone_rctl_lock);
+	return (0);
+}
+
+/*
+ * rctl_decr_lofi(zone_t *, size_t)
+ *
+ * Overview
+ *   Decrements the number of lofi devices for the zone.
+ */
+void
+rctl_decr_lofi(zone_t *zone, size_t decr)
+{
+	mutex_enter(&zone->zone_rctl_lock);
+	ASSERT(zone->zone_max_lofi >= decr);
+	zone->zone_max_lofi -= decr;
+	mutex_exit(&zone->zone_rctl_lock);
+}
+
+/*
  * Create resource kstat
  */
 static kstat_t *
--- a/usr/src/uts/common/os/zone.c	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/os/zone.c	Wed Jun 16 10:02:44 2010 -0700
@@ -159,6 +159,8 @@
  *	 related to the zone.max-lwps rctl.
  *   zone_mem_lock: This is a per-zone lock used to protect the fields
  *	 related to the zone.max-locked-memory and zone.max-swap rctls.
+ *   zone_rctl_lock: This is a per-zone lock used to protect other rctls,
+ *       currently just max_lofi
  *   zsd_key_lock: This is a global lock protecting the key state for ZSD.
  *   zone_deathrow_lock: This is a global lock protecting the "deathrow"
  *       list (a list of zones in the ZONE_IS_DEAD state).
@@ -340,6 +342,7 @@
 rctl_hndl_t rc_zone_cpu_shares;
 rctl_hndl_t rc_zone_locked_mem;
 rctl_hndl_t rc_zone_max_swap;
+rctl_hndl_t rc_zone_max_lofi;
 rctl_hndl_t rc_zone_cpu_cap;
 rctl_hndl_t rc_zone_nlwps;
 rctl_hndl_t rc_zone_shmmax;
@@ -1584,6 +1587,57 @@
 	zone_max_swap_test
 };
 
+/*ARGSUSED*/
+static rctl_qty_t
+zone_max_lofi_usage(rctl_t *rctl, struct proc *p)
+{
+	rctl_qty_t q;
+	zone_t *z = p->p_zone;
+
+	ASSERT(MUTEX_HELD(&p->p_lock));
+	mutex_enter(&z->zone_rctl_lock);
+	q = z->zone_max_lofi;
+	mutex_exit(&z->zone_rctl_lock);
+	return (q);
+}
+
+/*ARGSUSED*/
+static int
+zone_max_lofi_test(rctl_t *r, proc_t *p, rctl_entity_p_t *e,
+    rctl_val_t *rcntl, rctl_qty_t incr, uint_t flags)
+{
+	rctl_qty_t q;
+	zone_t *z;
+
+	z = e->rcep_p.zone;
+	ASSERT(MUTEX_HELD(&p->p_lock));
+	ASSERT(MUTEX_HELD(&z->zone_rctl_lock));
+	q = z->zone_max_lofi;
+	if (q + incr > rcntl->rcv_value)
+		return (1);
+	return (0);
+}
+
+/*ARGSUSED*/
+static int
+zone_max_lofi_set(rctl_t *rctl, struct proc *p, rctl_entity_p_t *e,
+    rctl_qty_t nv)
+{
+	ASSERT(MUTEX_HELD(&p->p_lock));
+	ASSERT(e->rcep_t == RCENTITY_ZONE);
+	if (e->rcep_p.zone == NULL)
+		return (0);
+	e->rcep_p.zone->zone_max_lofi_ctl = nv;
+	return (0);
+}
+
+static rctl_ops_t zone_max_lofi_ops = {
+	rcop_no_action,
+	zone_max_lofi_usage,
+	zone_max_lofi_set,
+	zone_max_lofi_test
+};
+
 /*
  * Helper function to brand the zone with a unique ID.
  */
@@ -1732,6 +1786,8 @@
 	zone0.zone_locked_mem_ctl = UINT64_MAX;
 	ASSERT(zone0.zone_max_swap == 0);
 	zone0.zone_max_swap_ctl = UINT64_MAX;
+	zone0.zone_max_lofi = 0;
+	zone0.zone_max_lofi_ctl = UINT64_MAX;
 	zone0.zone_shmmax = 0;
 	zone0.zone_ipc.ipcq_shmmni = 0;
 	zone0.zone_ipc.ipcq_semmni = 0;
@@ -1740,6 +1796,7 @@
 	zone0.zone_nodename = utsname.nodename;
 	zone0.zone_domain = srpc_domain;
 	zone0.zone_hostid = HW_INVALID_HOSTID;
+	zone0.zone_fs_allowed = NULL;
 	zone0.zone_ref = 1;
 	zone0.zone_id = GLOBAL_ZONEID;
 	zone0.zone_status = ZONE_IS_RUNNING;
@@ -1902,6 +1959,11 @@
 	    RCTL_GLOBAL_DENY_ALWAYS, UINT64_MAX, UINT64_MAX,
 	    &zone_max_swap_ops);
 
+	rc_zone_max_lofi = rctl_register("zone.max-lofi",
+	    RCENTITY_ZONE, RCTL_GLOBAL_NOBASIC | RCTL_GLOBAL_COUNT |
+	    RCTL_GLOBAL_DENY_ALWAYS, UINT64_MAX, UINT64_MAX,
+	    &zone_max_lofi_ops);
+
 	/*
 	 * Initialize the ``global zone''.
 	 */
@@ -2040,9 +2102,11 @@
 	if (zone->zone_rctls != NULL)
 		rctl_set_free(zone->zone_rctls);
 	if (zone->zone_bootargs != NULL)
-		kmem_free(zone->zone_bootargs, strlen(zone->zone_bootargs) + 1);
+		strfree(zone->zone_bootargs);
 	if (zone->zone_initname != NULL)
-		kmem_free(zone->zone_initname, strlen(zone->zone_initname) + 1);
+		strfree(zone->zone_initname);
+	if (zone->zone_fs_allowed != NULL)
+		strfree(zone->zone_fs_allowed);
 	if (zone->zone_pfexecd != NULL)
 		klpd_freelist(&zone->zone_pfexecd);
 	id_free(zoneid_space, zone->zone_id);
@@ -2104,21 +2168,20 @@
 static int
 zone_set_bootargs(zone_t *zone, const char *zone_bootargs)
 {
-	char *bootargs = kmem_zalloc(BOOTARGS_MAX, KM_SLEEP);
+	char *buf = kmem_zalloc(BOOTARGS_MAX, KM_SLEEP);
 	int err = 0;
 
 	ASSERT(zone != global_zone);
-	if ((err = copyinstr(zone_bootargs, bootargs, BOOTARGS_MAX, NULL)) != 0)
+	if ((err = copyinstr(zone_bootargs, buf, BOOTARGS_MAX, NULL)) != 0)
 		goto done;	/* EFAULT or ENAMETOOLONG */
 
 	if (zone->zone_bootargs != NULL)
-		kmem_free(zone->zone_bootargs, strlen(zone->zone_bootargs) + 1);
-
-	zone->zone_bootargs = kmem_alloc(strlen(bootargs) + 1, KM_SLEEP);
-	(void) strcpy(zone->zone_bootargs, bootargs);
+		strfree(zone->zone_bootargs);
+
+	zone->zone_bootargs = strdup(buf);
 
 done:
-	kmem_free(bootargs, BOOTARGS_MAX);
+	kmem_free(buf, BOOTARGS_MAX);
 	return (err);
 }
 
@@ -2164,6 +2227,27 @@
 }
 
 static int
+zone_set_fs_allowed(zone_t *zone, const char *zone_fs_allowed)
+{
+	char *buf = kmem_zalloc(ZONE_FS_ALLOWED_MAX, KM_SLEEP);
+	int err = 0;
+
+	ASSERT(zone != global_zone);
+	if ((err = copyinstr(zone_fs_allowed, buf,
+	    ZONE_FS_ALLOWED_MAX, NULL)) != 0)
+		goto done;
+
+	if (zone->zone_fs_allowed != NULL)
+		strfree(zone->zone_fs_allowed);
+
+	zone->zone_fs_allowed = strdup(buf);
+
+done:
+	kmem_free(buf, ZONE_FS_ALLOWED_MAX);
+	return (err);
+}
+
+static int
 zone_set_initname(zone_t *zone, const char *zone_initname)
 {
 	char initname[INITNAME_SZ];
@@ -2175,7 +2259,7 @@
 		return (err);	/* EFAULT or ENAMETOOLONG */
 
 	if (zone->zone_initname != NULL)
-		kmem_free(zone->zone_initname, strlen(zone->zone_initname) + 1);
+		strfree(zone->zone_initname);
 
 	zone->zone_initname = kmem_alloc(strlen(initname) + 1, KM_SLEEP);
 	(void) strcpy(zone->zone_initname, initname);
@@ -3856,6 +3940,7 @@
 	zone->zone_ipc.ipcq_semmni = 0;
 	zone->zone_ipc.ipcq_msgmni = 0;
 	zone->zone_bootargs = NULL;
+	zone->zone_fs_allowed = NULL;
 	zone->zone_initname =
 	    kmem_alloc(strlen(zone_default_initname) + 1, KM_SLEEP);
 	(void) strcpy(zone->zone_initname, zone_default_initname);
@@ -3865,6 +3950,8 @@
 	zone->zone_locked_mem_ctl = UINT64_MAX;
 	zone->zone_max_swap = 0;
 	zone->zone_max_swap_ctl = UINT64_MAX;
+	zone->zone_max_lofi = 0;
+	zone->zone_max_lofi_ctl = UINT64_MAX;
 	zone0.zone_lockedmem_kstat = NULL;
 	zone0.zone_swapresv_kstat = NULL;
 
@@ -4790,6 +4877,20 @@
 			error = EINVAL;
 		}
 		break;
+	case ZONE_ATTR_FS_ALLOWED:
+		if (zone->zone_fs_allowed == NULL)
+			outstr = "";
+		else
+			outstr = zone->zone_fs_allowed;
+		size = strlen(outstr) + 1;
+		if (bufsize > size)
+			bufsize = size;
+		if (buf != NULL) {
+			err = copyoutstr(outstr, buf, bufsize, NULL);
+			if (err != 0 && err != ENAMETOOLONG)
+				error = EFAULT;
+		}
+		break;
 	default:
 		if ((attr >= ZONE_ATTR_BRAND_ATTRS) && ZONE_IS_BRANDED(zone)) {
 			size = bufsize;
@@ -4853,6 +4954,9 @@
 	case ZONE_ATTR_BRAND:
 		err = zone_set_brand(zone, (const char *)buf);
 		break;
+	case ZONE_ATTR_FS_ALLOWED:
+		err = zone_set_fs_allowed(zone, (const char *)buf);
+		break;
 	case ZONE_ATTR_PHYS_MCAP:
 		err = zone_set_phys_mcap(zone, (const uint64_t *)buf);
 		break;
--- a/usr/src/uts/common/sys/fs/sdev_impl.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/sys/fs/sdev_impl.h	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef _SYS_SDEV_IMPL_H
@@ -230,6 +229,7 @@
 #define	SDEV_ATTR_INVALID	0x0080	/* invalid node attributes, */
 					/* need update */
 #define	SDEV_SUBDIR		0x0100	/* match all subdirs under here */
+#define	SDEV_ZONED		0x0200  /* zoned subdir */
 
 /* sdev_lookup_flags */
 #define	SDEV_LOOKUP	0x0001	/* node creation in progress */
--- a/usr/src/uts/common/sys/id_space.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/sys/id_space.h	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_ID_SPACE_H
@@ -46,6 +45,7 @@
 id_t id_alloc_nosleep(id_space_t *);
 id_t id_allocff(id_space_t *);
 id_t id_allocff_nosleep(id_space_t *);
+id_t id_alloc_specific_nosleep(id_space_t *, id_t);
 void id_free(id_space_t *, id_t);
 
 #endif /* _KERNEL */
--- a/usr/src/uts/common/sys/lofi.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/sys/lofi.h	Wed Jun 16 10:02:44 2010 -0700
@@ -34,6 +34,7 @@
 #include <sys/vnode.h>
 #include <sys/list.h>
 #include <sys/crypto/api.h>
+#include <sys/zone.h>
 
 #ifdef	__cplusplus
 extern "C" {
@@ -176,15 +177,6 @@
 	uint64_t	lc_index;		/* segment index */
 };
 
-/*
- * We limit the maximum number of active lofi devices to 128, which seems very
- * large. You can tune this by changing lofi_max_files in /etc/system.
- * If you change it dynamically, which you probably shouldn't do, make sure
- * to only _increase_ it.
- */
-#define	LOFI_MAX_FILES	128
-extern uint32_t lofi_max_files;
-
 #define	V_ISLOFIABLE(vtype) \
 	((vtype == VREG) || (vtype == VBLK) || (vtype == VCHR))
 
@@ -219,9 +211,8 @@
 };
 
 struct lofi_state {
-	char		*ls_filename;	/* filename to open */
-	size_t		ls_filename_sz;
-	struct vnode	*ls_vp;		/* open vnode */
+	vnode_t		*ls_vp;		/* open real vnode */
+	vnode_t		*ls_stacked_vp;	/* open vnode */
 	kmutex_t	ls_vp_lock;	/* protects ls_vp */
 	kcondvar_t	ls_vp_cv;	/* signal changes to ls_vp */
 	uint32_t	ls_vp_iocount;	/* # pending I/O requests */
@@ -238,6 +229,9 @@
 	struct dk_geom	ls_dkg;
 	struct vtoc	ls_vtoc;
 	struct dk_cinfo	ls_ci;
+	zone_t 		*ls_zone;
+	list_node_t	ls_list;	/* all lofis */
+	dev_t		ls_dev;		/* this node's dev_t */
 
 	/* the following fields are required for compression support */
 	int		ls_comp_algorithm_index; /* idx into compress_table */
--- a/usr/src/uts/common/sys/policy.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/sys/policy.h	Wed Jun 16 10:02:44 2010 -0700
@@ -89,12 +89,13 @@
 int secpolicy_dispadm(const cred_t *);
 int secpolicy_error_inject(const cred_t *);
 int secpolicy_excl_open(const cred_t *);
-int secpolicy_fs_mount(cred_t *, vnode_t *, struct vfs *);
-int secpolicy_fs_unmount(cred_t *, struct vfs *);
+int secpolicy_fs_allowed_mount(const char *);
 int secpolicy_fs_config(const cred_t *, const struct vfs *);
 int secpolicy_fs_linkdir(const cred_t *, const struct vfs *);
 int secpolicy_fs_minfree(const cred_t *, const struct vfs *);
+int secpolicy_fs_mount(cred_t *, vnode_t *, struct vfs *);
 int secpolicy_fs_quota(const cred_t *, const struct vfs *);
+int secpolicy_fs_unmount(cred_t *, struct vfs *);
 int secpolicy_idmap(const cred_t *);
 int secpolicy_ip(const cred_t *, int, boolean_t);
 int secpolicy_ip_config(const cred_t *, boolean_t);
--- a/usr/src/uts/common/sys/rctl.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/sys/rctl.h	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 #ifndef	_SYS_RCTL_H
@@ -337,6 +336,9 @@
 int rctl_incr_swap(struct proc *, struct zone *, size_t);
 void rctl_decr_swap(struct zone *, size_t);
 
+int rctl_incr_lofi(struct proc *, struct zone *, size_t);
+void rctl_decr_lofi(struct zone *, size_t);
+
 struct kstat *rctl_kstat_create_zone(struct zone *, char *, uchar_t, uint_t,
     uchar_t);
 
--- a/usr/src/uts/common/sys/vfs.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/sys/vfs.h	Wed Jun 16 10:02:44 2010 -0700
@@ -19,8 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
- * Use is subject to license terms.
+ * Copyright (c) 1988, 2010, Oracle and/or its affiliates. All rights reserved.
  */
 
 /*	Copyright (c) 1983, 1984, 1985, 1986, 1987, 1988, 1989 AT&T	*/
@@ -439,6 +438,7 @@
 #define	VSW_STATS	0x20	/* file system can collect stats */
 #define	VSW_XID		0x40	/* file system supports extended ids */
 #define	VSW_CANLOFI	0x80	/* file system supports lofi mounts */
+#define	VSW_ZMOUNT	0x100	/* file system always allowed in a zone */
 
 #define	VSW_INSTALLED	0x8000	/* this vsw is associated with a file system */
 
--- a/usr/src/uts/common/sys/zone.h	Wed Jun 16 07:19:49 2010 -0700
+++ b/usr/src/uts/common/sys/zone.h	Wed Jun 16 10:02:44 2010 -0700
@@ -96,10 +96,13 @@
 #define	ZONE_ATTR_SCHED_CLASS	13
 #define	ZONE_ATTR_FLAGS		14
 #define	ZONE_ATTR_HOSTID	15
+#define	ZONE_ATTR_FS_ALLOWED	16
 
 /* Start of the brand-specific attribute namespace */
 #define	ZONE_ATTR_BRAND_ATTRS	32768
 
+#define	ZONE_FS_ALLOWED_MAX	1024
+
 #define	ZONE_EVENT_CHANNEL	"com.sun:zones:status"
 #define	ZONE_EVENT_STATUS_CLASS	"status"
 #define	ZONE_EVENT_STATUS_SUBCLASS	"change"
@@ -379,6 +382,11 @@
 	rctl_qty_t	zone_max_swap_ctl;	/* current swap limit. */
 						/* Protected by */
 						/* zone_rctls->rcs_lock */
+	kmutex_t	zone_rctl_lock;	/* protects zone_max_lofi */
+	rctl_qty_t	zone_max_lofi; /* lofi devs for zone */
+	rctl_qty_t	zone_max_lofi_ctl;	/* current lofi limit. */
+						/* Protected by */
+						/* zone_rctls->rcs_lock */
 	list_t		zone_zsd;	/* list of Zone-Specific Data values */
 	kcondvar_t	zone_cv;	/* used to signal state changes */
 	struct proc	*zone_zsched;	/* Dummy kernel "zsched" process */
@@ -443,6 +451,8 @@
 	krwlock_t	zone_mntfs_db_lock;
 
 	struct klpd_reg		*zone_pfexecd;
+
+	char		*zone_fs_allowed;
 } zone_t;
 
 /*
@@ -664,6 +674,7 @@
 
 extern rctl_hndl_t rc_zone_locked_mem;
 extern rctl_hndl_t rc_zone_max_swap;
+extern rctl_hndl_t rc_zone_max_lofi;
 
 #endif	/* _KERNEL */