changeset 6734:d16dda992d39

PSARC/2008/290 lofi mount 6384817 Need persistent lofi based mounts and direct mount(1m) support for lofi
author johnlev
date Tue, 27 May 2008 18:25:14 -0700
parents 1db40e194d28
children ba4d622bb38a
files usr/src/cmd/devfsadm/devfsadm.c usr/src/cmd/fs.d/fslib.c usr/src/cmd/fs.d/ufs/fsck/main.c usr/src/cmd/lofiadm/main.c usr/src/cmd/zoneadm/zoneadm.c usr/src/cmd/zoneadmd/vplat.c usr/src/uts/common/fs/hsfs/hsfs_vfsops.c usr/src/uts/common/fs/pcfs/pc_vfsops.c usr/src/uts/common/fs/udfs/udf_vfsops.c usr/src/uts/common/fs/ufs/ufs_vfsops.c usr/src/uts/common/fs/vfs.c usr/src/uts/common/io/lofi.c usr/src/uts/common/sys/lofi.h usr/src/uts/common/sys/vfs.h
diffstat 14 files changed, 699 insertions(+), 324 deletions(-) [+]
line wrap: on
line diff
--- a/usr/src/cmd/devfsadm/devfsadm.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/cmd/devfsadm/devfsadm.c	Tue May 27 18:25:14 2008 -0700
@@ -8467,10 +8467,16 @@
 	if (dev_name)
 		free(dev_name);
 
-	if (dev_name_lookup_err)
-		err_print(DEV_NAME_LOOKUP_FAILED, node_path);
-	else
+	if (dev_name_lookup_err) {
+		/*
+		 * If a lofi mount fails, the /devices node may well have
+		 * disappeared by the time we run, so let's not complain.
+		 */
+		if (strcmp(subclass, ESC_LOFI) != 0)
+			err_print(DEV_NAME_LOOKUP_FAILED, node_path);
+	} else {
 		err_print(BUILD_EVENT_ATTR_FAILED, (err) ? strerror(err) : "");
+	}
 	return (NULL);
 }
 
--- a/usr/src/cmd/fs.d/fslib.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/cmd/fs.d/fslib.c	Tue May 27 18:25:14 2008 -0700
@@ -2,9 +2,8 @@
  * CDDL HEADER START
  *
  * The contents of this file are subject to the terms of the
- * Common Development and Distribution License, Version 1.0 only
- * (the "License").  You may not use this file except in compliance
- * with the License.
+ * Common Development and Distribution License (the "License").
+ * You may not use this file except in compliance with the License.
  *
  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
  * or http://www.opensolaris.org/os/licensing.
@@ -20,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -174,7 +173,7 @@
 
 	resetmnttab(mfp);
 	while ((ret = getextmntent(mfp, &mnt, sizeof (struct extmnttab)))
-		!= -1) {
+	    != -1) {
 		mntlist_t	*mp;
 
 		if (ret != 0)		/* bad entry */
@@ -216,19 +215,19 @@
 			 * match if and only if both are equal.
 			 */
 			if ((strcmp(ml->mntl_mnt->mnt_mountp,
-					mntin->mnt_mountp) == 0) &&
+			    mntin->mnt_mountp) == 0) &&
 			    (strcmp(ml->mntl_mnt->mnt_special,
-					mntin->mnt_special) == 0))
+			    mntin->mnt_special) == 0))
 				delete = ml;
 		} else if (mntin->mnt_mountp) {
 			if (strcmp(ml->mntl_mnt->mnt_mountp,
-					mntin->mnt_mountp) == 0)
+			    mntin->mnt_mountp) == 0)
 				delete = ml;
 		} else if (mntin->mnt_special) {
 			if (strcmp(ml->mntl_mnt->mnt_special,
-					mntin->mnt_special) == 0)
+			    mntin->mnt_special) == 0)
 				delete = ml;
-	    }
+		}
 	}
 	return (delete);
 }
@@ -309,7 +308,7 @@
 
 	while (*requested_opts != '\0') {
 		(void) getsubopt(&requested_opts, empty_opt_vector,
-			&option_ptr);
+		    &option_ptr);
 
 		/*
 		 * Truncate any "=<value>" string from the end of
@@ -322,6 +321,14 @@
 			continue;
 
 		/*
+		 * Whilst we don't need this option to perform a lofi
+		 * mount, let's not be mendacious enough to complain
+		 * about it.
+		 */
+		if (strcmp(option_ptr, "loop") == 0)
+			continue;
+
+		/*
 		 * Search for the requested option in the list of options
 		 * actually supported.
 		 */
@@ -344,7 +351,7 @@
 
 		while (*actual_opt_hold != '\0') {
 			(void) getsubopt(&actual_opt_hold, empty_opt_vector,
-				&actopt);
+			    &actopt);
 
 			/* Truncate the "=<value>", if any. */
 			if ((equalptr = strchr(actopt, '=')) != NULL)
@@ -428,10 +435,10 @@
 
 	for (;;) {
 		if (zone_list(ids, &numzones) < 0) {
-			    perror("unable to retrieve list of zones");
-			    if (ids != NULL)
-				    free(ids);
-			    return (NULL);
+			perror("unable to retrieve list of zones");
+			if (ids != NULL)
+				free(ids);
+			return (NULL);
 		}
 		if (numzones <= oldnumzones)
 			break;
--- a/usr/src/cmd/fs.d/ufs/fsck/main.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/cmd/fs.d/ufs/fsck/main.c	Tue May 27 18:25:14 2008 -0700
@@ -696,7 +696,8 @@
 	int found_magic[MAGIC_LIMIT];
 	int magic_cnt;
 	int is_magic = 0;
-	int is_block;
+	int is_block = 0;
+	int is_file = 0;
 
 	(void) memset((void *)found_magic, 0, sizeof (found_magic));
 
@@ -706,22 +707,12 @@
 		exit(EXNOSTAT);
 	}
 
-	if ((stbd.st_mode & S_IFMT) == S_IFBLK) {
+	if (S_ISBLK(stbd.st_mode)) {
 		is_block = 1;
-	} else if ((stbd.st_mode & S_IFMT) == S_IFCHR) {
+	} else if (S_ISCHR(stbd.st_mode)) {
 		is_block = 0;
-	} else {
-		/*
-		 * In !mflag mode, we allow checking the contents
-		 * of a file.  Since this is intended primarily for
-		 * speeding up boot-time checks and allowing for a
-		 * file complicates the ok-input tests, we'll disallow
-		 * that option.
-		 */
-		(void) fprintf(stderr,
-		    "ufs fsck: sanity check failed: "
-		    "%s not block or character device\n", filename);
-		exit(EXNOSTAT);
+	} else if (S_ISREG(stbd.st_mode)) {
+		is_file = 1;
 	}
 
 	/*
@@ -729,7 +720,7 @@
 	 * silently on failures. The whole point of this is to be tolerant
 	 * of the magic file systems being already mounted.
 	 */
-	if ((vfstab = fopen(VFSTAB, "r")) != 0) {
+	if (!is_file && (vfstab = fopen(VFSTAB, "r")) != NULL) {
 		for (magic_cnt = 0; magic_cnt < MAGIC_LIMIT; magic_cnt++) {
 			if (magic_cnt == MAGIC_NONE)
 				continue;
--- a/usr/src/cmd/lofiadm/main.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/cmd/lofiadm/main.c	Tue May 27 18:25:14 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -304,6 +304,8 @@
 	struct lofi_ioctl li;
 
 	li.li_force = force;
+	li.li_cleanup = B_FALSE;
+
 	if (devicename == NULL) {
 		/* delete by filename */
 		(void) strlcpy(li.li_filename, filename,
--- a/usr/src/cmd/zoneadm/zoneadm.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/cmd/zoneadm/zoneadm.c	Tue May 27 18:25:14 2008 -0700
@@ -2437,7 +2437,7 @@
 static int
 verify_fs_special(struct zone_fstab *fstab)
 {
-	struct stat st;
+	struct stat64 st;
 
 	/*
 	 * This validation is really intended for standard zone administration.
@@ -2450,7 +2450,7 @@
 	if (strcmp(fstab->zone_fs_type, MNTTYPE_ZFS) == 0)
 		return (verify_fs_zfs(fstab));
 
-	if (stat(fstab->zone_fs_special, &st) != 0) {
+	if (stat64(fstab->zone_fs_special, &st) != 0) {
 		(void) fprintf(stderr, gettext("could not verify fs "
 		    "%s: could not access %s: %s\n"), fstab->zone_fs_dir,
 		    fstab->zone_fs_special, strerror(errno));
@@ -2474,6 +2474,17 @@
 }
 
 static int
+isregfile(const char *path)
+{
+	struct stat64 st;
+
+	if (stat64(path, &st) == -1)
+		return (-1);
+
+	return (S_ISREG(st.st_mode));
+}
+
+static int
 verify_filesystems(zone_dochandle_t handle)
 {
 	int return_code = Z_OK;
@@ -2529,8 +2540,10 @@
 			goto next_fs;
 		}
 		/*
-		 * Verify /usr/lib/fs/<fstype>/fsck exists iff zone_fs_raw is
-		 * set.
+		 * If zone_fs_raw is set, verify that there's an fsck
+		 * binary for it.  If zone_fs_raw is not set, and it's
+		 * not a regular file (lofi mount), and there's an fsck
+		 * binary for it, complain.
 		 */
 		if (snprintf(cmdbuf, sizeof (cmdbuf), "/usr/lib/fs/%s/fsck",
 		    fstab.zone_fs_type) > sizeof (cmdbuf)) {
@@ -2540,14 +2553,6 @@
 			return_code = Z_ERR;
 			goto next_fs;
 		}
-		if (fstab.zone_fs_raw[0] == '\0' && stat(cmdbuf, &st) == 0) {
-			(void) fprintf(stderr, gettext("could not verify fs "
-			    "%s: must specify 'raw' device for %s "
-			    "file systems\n"),
-			    fstab.zone_fs_dir, fstab.zone_fs_type);
-			return_code = Z_ERR;
-			goto next_fs;
-		}
 		if (fstab.zone_fs_raw[0] != '\0' &&
 		    (stat(cmdbuf, &st) != 0 || !S_ISREG(st.st_mode))) {
 			(void) fprintf(stderr, gettext("cannot verify fs %s: "
@@ -2556,6 +2561,15 @@
 			    fstab.zone_fs_dir, fstab.zone_fs_type);
 			return_code = Z_ERR;
 			goto next_fs;
+		} else if (fstab.zone_fs_raw[0] == '\0' &&
+		    stat(cmdbuf, &st) == 0 &&
+		    isregfile(fstab.zone_fs_special) != 1) {
+			(void) fprintf(stderr, gettext("could not verify fs "
+			    "%s: must specify 'raw' device for %s "
+			    "file systems\n"),
+			    fstab.zone_fs_dir, fstab.zone_fs_type);
+			return_code = Z_ERR;
+			goto next_fs;
 		}
 
 		/* Verify fs_special. */
--- a/usr/src/cmd/zoneadmd/vplat.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/cmd/zoneadmd/vplat.c	Tue May 27 18:25:14 2008 -0700
@@ -803,6 +803,17 @@
 }
 
 static int
+isregfile(const char *path)
+{
+	struct stat64 st;
+
+	if (stat64(path, &st) == -1)
+		return (-1);
+
+	return (S_ISREG(st.st_mode));
+}
+
+static int
 dofsck(zlog_t *zlogp, const char *fstype, const char *rawdev)
 {
 	char cmdbuf[MAXPATHLEN];
@@ -819,6 +830,13 @@
 		return (-1);
 	}
 
+	/*
+	 * If it doesn't exist, that's OK: we verified this previously
+	 * in zoneadm.
+	 */
+	if (isregfile(cmdbuf) == -1)
+		return (0);
+
 	argv[0] = "fsck";
 	argv[1] = "-m";
 	argv[2] = (char *)rawdev;
@@ -1260,8 +1278,12 @@
 	 * Run 'fsck -m' if there's a device to fsck.
 	 */
 	if (fsptr->zone_fs_raw[0] != '\0' &&
-	    dofsck(zlogp, fsptr->zone_fs_type, fsptr->zone_fs_raw) != 0)
+	    dofsck(zlogp, fsptr->zone_fs_type, fsptr->zone_fs_raw) != 0) {
 		return (-1);
+	} else if (isregfile(fsptr->zone_fs_special) == 1 &&
+	    dofsck(zlogp, fsptr->zone_fs_type, fsptr->zone_fs_special) != 0) {
+		return (-1);
+	}
 
 	/*
 	 * Build up mount option string.
--- a/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/uts/common/fs/hsfs/hsfs_vfsops.c	Tue May 27 18:25:14 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -1343,40 +1343,57 @@
     cred_t *cr)
 {
 	int error;
-	struct vnode *vp;
+	struct vnode *svp = NULL;
+	struct vnode *lvp = NULL;
+	struct vnode *bvp;
 	struct vattr vap;
 	dev_t dev;
+	enum uio_seg fromspace = (flags & MS_SYSSPACE) ?
+	    UIO_SYSSPACE : UIO_USERSPACE;
 
 	/*
-	 * Get the device to be mounted
+	 * Look up the device/file to be mounted.
 	 */
-	error = lookupname(fspec, (flags & MS_SYSSPACE) ?
-	    UIO_SYSSPACE : UIO_USERSPACE, FOLLOW, NULLVPP, &vp);
+	error = lookupname(fspec, fromspace, FOLLOW, NULLVPP, &svp);
 	if (error) {
-		if (error == ENOENT) {
-			return (ENODEV);	/* needs translation */
-		}
-		return (error);
-	}
-	if (vp->v_type != VBLK) {
-		VN_RELE(vp);
-		return (ENOTBLK);
-	}
-	/*
-	 * Can we read from the device?
-	 */
-	if ((error = VOP_ACCESS(vp, VREAD, 0, cr, NULL)) != 0 ||
-	    (error = secpolicy_spec_open(cr, vp, FREAD)) != 0) {
-		VN_RELE(vp);
-		return (error);
+		if (error == ENOENT)
+			error = ENODEV;
+		goto out;
 	}
 
+	error = vfs_get_lofi(vfsp, &lvp);
+
+	if (error > 0) {
+		if (error == ENOENT)
+			error = ENODEV;
+		goto out;
+	} else if (error == 0) {
+		bvp = lvp;
+	} else {
+		bvp = svp;
+
+		if (bvp->v_type != VBLK) {
+			error = ENOTBLK;
+			goto out;
+		}
+
+		if ((error = secpolicy_spec_open(cr, bvp, FREAD)) != 0)
+			goto out;
+	}
+
+	/*
+	 * Can we read from the device/file ?
+	 */
+	if ((error = VOP_ACCESS(svp, VREAD, 0, cr, NULL)) != 0)
+		goto out;
+
 	vap.va_mask = AT_MODE;		/* get protection mode */
-	(void) VOP_GETATTR(vp, &vap, 0, CRED(), NULL);
+	(void) VOP_GETATTR(bvp, &vap, 0, CRED(), NULL);
 	*mode = vap.va_mode;
 
-	dev = *pdev = vp->v_rdev;
-	VN_RELE(vp);
+	dev = *pdev = bvp->v_rdev;
+
+	error = EBUSY;
 
 	/*
 	 * Ensure that this device isn't already mounted,
@@ -1385,14 +1402,23 @@
 	 */
 	if ((flags & MS_NOCHECK) == 0) {
 		if (vfs_devmounting(dev, vfsp))
-			return (EBUSY);
+			goto out;
 		if (vfs_devismounted(dev) && !(flags & MS_REMOUNT))
-			return (EBUSY);
+			goto out;
 	}
 
-	if (getmajor(*pdev) >= devcnt)
-		return (ENXIO);
-	return (0);
+	if (getmajor(*pdev) >= devcnt) {
+		error = ENXIO;
+		goto out;
+	}
+
+	error = 0;
+out:
+	if (svp != NULL)
+		VN_RELE(svp);
+	if (lvp != NULL)
+		VN_RELE(lvp);
+	return (error);
 }
 
 static void
--- a/usr/src/uts/common/fs/pcfs/pc_vfsops.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/uts/common/fs/pcfs/pc_vfsops.c	Tue May 27 18:25:14 2008 -0700
@@ -293,7 +293,8 @@
 {
 	struct pathname special;
 	char *c;
-	struct vnode *bvp;
+	struct vnode *svp = NULL;
+	struct vnode *lvp = NULL;
 	int oflag, aflag;
 	int error;
 
@@ -307,7 +308,7 @@
 	*dos_ldrive = -1;
 
 	if (error =
-	    lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &bvp)) {
+	    lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW, NULLVPP, &svp)) {
 		/*
 		 * If there's no device node, the name specified most likely
 		 * maps to a PCFS-style "partition specifier" to select a
@@ -384,7 +385,7 @@
 
 
 		error = lookupname(special.pn_path, UIO_SYSSPACE, FOLLOW,
-		    NULLVPP, &bvp);
+		    NULLVPP, &svp);
 	} else {
 		*dos_ldrive = UNPARTITIONED_DRIVE;
 	}
@@ -395,8 +396,6 @@
 
 	ASSERT(*dos_ldrive >= UNPARTITIONED_DRIVE);
 
-	*xdev = bvp->v_rdev;
-
 	/*
 	 * Verify caller's permission to open the device special file.
 	 */
@@ -409,20 +408,38 @@
 		aflag = VREAD | VWRITE;
 	}
 
-	if (bvp->v_type != VBLK)
-		error = ENOTBLK;
-	else if (getmajor(*xdev) >= devcnt)
-		error = ENXIO;
+	error = vfs_get_lofi(vfsp, &lvp);
 
-	if ((error != 0) ||
-	    (error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
-	    (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
-		VN_RELE(bvp);
-		return (error);
+	if (error > 0) {
+		if (error == ENOENT)
+			error = ENODEV;
+		goto out;
+	} else if (error == 0) {
+		*xdev = lvp->v_rdev;
+	} else {
+		*xdev = svp->v_rdev;
+
+		if (svp->v_type != VBLK)
+			error = ENOTBLK;
+
+		if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0)
+			goto out;
 	}
 
-	VN_RELE(bvp);
-	return (0);
+	if (getmajor(*xdev) >= devcnt) {
+		error = ENXIO;
+		goto out;
+	}
+
+	if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0)
+		goto out;
+
+out:
+	if (svp != NULL)
+		VN_RELE(svp);
+	if (lvp != NULL)
+		VN_RELE(lvp);
+	return (error);
 }
 
 static int
--- a/usr/src/uts/common/fs/udfs/udf_vfsops.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/uts/common/fs/udfs/udf_vfsops.c	Tue May 27 18:25:14 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -91,22 +91,22 @@
 
 extern kmutex_t ud_sync_busy;
 static int32_t ud_mountfs(struct vfs *,
-	enum whymountroot, dev_t, char *, struct cred *, int32_t);
+    enum whymountroot, dev_t, char *, struct cred *, int32_t);
 static struct udf_vfs *ud_validate_and_fill_superblock(dev_t,
-			int32_t, uint32_t);
+    int32_t, uint32_t);
 void ud_destroy_fsp(struct udf_vfs *);
 void ud_convert_to_superblock(struct udf_vfs *,
-	struct log_vol_int_desc *);
+    struct log_vol_int_desc *);
 void ud_update_superblock(struct vfs *);
 int32_t ud_get_last_block(dev_t, daddr_t *);
 static int32_t ud_val_get_vat(struct udf_vfs *,
-	dev_t, daddr_t, struct ud_map *);
+    dev_t, daddr_t, struct ud_map *);
 int32_t ud_read_sparing_tbls(struct udf_vfs *,
-	dev_t, struct ud_map *, struct pmap_typ2 *);
+    dev_t, struct ud_map *, struct pmap_typ2 *);
 uint32_t ud_get_lbsize(dev_t, uint32_t *);
 
 static int32_t udf_mount(struct vfs *,
-	struct vnode *, struct mounta *, struct cred *);
+    struct vnode *, struct mounta *, struct cred *);
 static int32_t udf_unmount(struct vfs *, int, struct cred *);
 static int32_t udf_root(struct vfs *, struct vnode **);
 static int32_t udf_statvfs(struct vfs *, struct statvfs64 *);
@@ -183,7 +183,8 @@
 	struct mounta *uap, struct cred *cr)
 {
 	dev_t dev;
-	struct vnode *bvp;
+	struct vnode *lvp = NULL;
+	struct vnode *svp = NULL;
 	struct pathname dpn;
 	int32_t error;
 	enum whymountroot why;
@@ -202,9 +203,9 @@
 	mutex_enter(&mvp->v_lock);
 	if ((uap->flags & MS_REMOUNT) == 0 &&
 	    (uap->flags & MS_OVERLAY) == 0 &&
-		(mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
-			mutex_exit(&mvp->v_lock);
-			return (EBUSY);
+	    (mvp->v_count != 1 || (mvp->v_flag & VROOT))) {
+		mutex_exit(&mvp->v_lock);
+		return (EBUSY);
 	}
 	mutex_exit(&mvp->v_lock);
 
@@ -213,18 +214,30 @@
 	}
 
 	/*
-	 * Resolve path name of special file being mounted.
+	 * Resolve path name of the file being mounted.
 	 */
 	if (error = lookupname(uap->spec, UIO_USERSPACE, FOLLOW, NULLVPP,
-	    &bvp)) {
+	    &svp)) {
 		pn_free(&dpn);
 		return (error);
 	}
-	if (bvp->v_type != VBLK) {
-		error = ENOTBLK;
+
+	error = vfs_get_lofi(vfsp, &lvp);
+
+	if (error > 0) {
+		if (error == ENOENT)
+			error = ENODEV;
 		goto out;
+	} else if (error == 0) {
+		dev = lvp->v_rdev;
+	} else {
+		dev = svp->v_rdev;
+
+		if (svp->v_type != VBLK) {
+			error = ENOTBLK;
+			goto out;
+		}
 	}
-	dev = bvp->v_rdev;
 
 	/*
 	 * Ensure that this device isn't already mounted,
@@ -282,19 +295,23 @@
 		oflag = FREAD | FWRITE;
 		aflag = VREAD | VWRITE;
 	}
-	if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
-	    (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
+
+	if (lvp == NULL &&
+	    (error = secpolicy_spec_open(cr, svp, oflag)) != 0)
 		goto out;
-	}
+
+	if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0)
+		goto out;
 
 	/*
 	 * Mount the filesystem.
 	 */
 	error = ud_mountfs(vfsp, why, dev, dpn.pn_path, cr, 0);
 out:
-	VN_RELE(bvp);
+	VN_RELE(svp);
+	if (lvp != NULL)
+		VN_RELE(lvp);
 	pn_free(&dpn);
-
 	return (error);
 }
 
@@ -436,15 +453,13 @@
 	 * 38(over head each dent) + MAXNAMLEN / 2 + inode_size(==block size)
 	 */
 	sp->f_ffree = sp->f_favail =
-		(sp->f_bavail * sp->f_bsize) / (146 + sp->f_bsize);
+	    (sp->f_bavail * sp->f_bsize) / (146 + sp->f_bsize);
 
 	/*
 	 * The total number of inodes is
 	 * the sum of files + directories + free inodes
 	 */
-	sp->f_files = sp->f_ffree +
-			udf_vfsp->udf_nfiles +
-			udf_vfsp->udf_ndirs;
+	sp->f_files = sp->f_ffree + udf_vfsp->udf_nfiles + udf_vfsp->udf_ndirs;
 	(void) cmpldev(&d32, vfsp->vfs_dev);
 	sp->f_fsid = d32;
 	(void) strcpy(sp->f_basetype, vfssw[vfsp->vfs_fstype].vsw_name);
@@ -495,14 +510,14 @@
 
 	udfid = (struct udf_fid *)fidp;
 	if ((error = ud_iget(vfsp, udfid->udfid_prn,
-		udfid->udfid_icb_lbn, &ip, NULL, CRED())) != 0) {
+	    udfid->udfid_icb_lbn, &ip, NULL, CRED())) != 0) {
 		*vpp = NULL;
 		return (error);
 	}
 
 	rw_enter(&ip->i_contents, RW_READER);
 	if ((udfid->udfid_uinq_lo != (ip->i_uniqid & 0xffffffff)) ||
-			(udfid->udfid_prn != ip->i_icb_prn)) {
+	    (udfid->udfid_prn != ip->i_icb_prn)) {
 		rw_exit(&ip->i_contents);
 		VN_RELE(ITOV(ip));
 		*vpp = NULL;
@@ -555,7 +570,7 @@
 		(void) dnlc_purge_vfsp(vfsp, 0);
 		vp = common_specvp(vp);
 		(void) VOP_PUTPAGE(vp, (offset_t)0,
-			(uint32_t)0, B_INVAL, CRED(), NULL);
+		    (uint32_t)0, B_INVAL, CRED(), NULL);
 		binval(vfsp->vfs_dev);
 
 		ovflags = vfsp->vfs_flag;
@@ -566,7 +581,7 @@
 		ud_update(0);
 		vp = ((struct udf_vfs *)vfsp->vfs_data)->udf_devvp;
 		(void) VOP_CLOSE(vp, FREAD|FWRITE, 1,
-					(offset_t)0, CRED(), NULL);
+		    (offset_t)0, CRED(), NULL);
 		return (0);
 	}
 
@@ -589,7 +604,7 @@
 
 	if (why == ROOT_INIT) {
 		vfs_add((struct vnode *)0, vfsp,
-			(vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0);
+		    (vfsp->vfs_flag & VFS_RDONLY) ? MS_RDONLY : 0);
 	}
 	vfs_unlock(vfsp);
 	return (0);
@@ -678,7 +693,7 @@
 		if (udf_vfsp->udf_flags & UDF_FL_RDONLY) {
 			(void) dnlc_purge_vfsp(vfsp, 0);
 			(void) VOP_PUTPAGE(devvp, (offset_t)0, (uint_t)0,
-					B_INVAL, CRED(), NULL);
+			    B_INVAL, CRED(), NULL);
 			(void) ud_iflush(vfsp);
 			bflush(dev);
 			binval(dev);
@@ -689,7 +704,7 @@
 		 * disallow mount of any highier version
 		 */
 		if ((udf_vfsp->udf_miread > UDF_150) ||
-			(udf_vfsp->udf_miwrite > UDF_150)) {
+		    (udf_vfsp->udf_miwrite > UDF_150)) {
 			error = EINVAL;
 			goto remountout;
 		}
@@ -715,8 +730,8 @@
 		 * mount in rw mode
 		 */
 		tpt = ud_bread(vfsp->vfs_dev,
-			udf_vfsp->udf_iseq_loc << udf_vfsp->udf_l2d_shift,
-			udf_vfsp->udf_iseq_len);
+		    udf_vfsp->udf_iseq_loc << udf_vfsp->udf_l2d_shift,
+		    udf_vfsp->udf_iseq_len);
 		if (tpt->b_flags & B_ERROR) {
 			error = EIO;
 			goto remountout;
@@ -735,7 +750,7 @@
 				lvid = (struct log_vol_int_desc *)ttag;
 
 				if (SWAP_32(lvid->lvid_int_type) !=
-					LOG_VOL_CLOSE_INT) {
+				    LOG_VOL_CLOSE_INT) {
 					error = EINVAL;
 					goto remountout;
 				}
@@ -744,7 +759,7 @@
 				 * Copy new data to old data
 				 */
 				bcopy(udf_vfsp->udf_iseq->b_un.b_addr,
-				tpt->b_un.b_addr, udf_vfsp->udf_iseq_len);
+				    tpt->b_un.b_addr, udf_vfsp->udf_iseq_len);
 				break;
 			}
 		}
@@ -846,7 +861,7 @@
 		 * disallow mount of any highier version
 		 */
 		if ((udf_vfsp->udf_miread > UDF_150) ||
-			(udf_vfsp->udf_miwrite > UDF_150)) {
+		    (udf_vfsp->udf_miwrite > UDF_150)) {
 			error = EINVAL;
 			goto out;
 		}
@@ -904,7 +919,7 @@
 	_NOTE(COMPETING_THREADS_NOW);
 #endif
 	if (error = ud_iget(vfsp, udf_vfsp->udf_ricb_prn,
-			udf_vfsp->udf_ricb_loc, &rip, NULL, cr)) {
+	    udf_vfsp->udf_ricb_loc, &rip, NULL, cr)) {
 		mutex_destroy(&udf_vfsp->udf_lock);
 		goto out;
 	}
@@ -937,7 +952,7 @@
 	ud_destroy_fsp(udf_vfsp);
 	if (needclose) {
 		(void) VOP_CLOSE(devvp, (vfsp->vfs_flag & VFS_RDONLY) ?
-			FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
+		    FREAD : FREAD|FWRITE, 1, (offset_t)0, cr, NULL);
 		bflush(dev);
 		binval(dev);
 	}
@@ -982,8 +997,8 @@
 	 */
 	secbp = ud_bread(dev, avd_loc << shift, ANCHOR_VOL_DESC_LEN);
 	if ((error = geterror(secbp)) != 0) {
-		cmn_err(CE_NOTE,
-		"udfs : Could not read Anchor Volume Desc %x", error);
+		cmn_err(CE_NOTE, "udfs : Could not read Anchor Volume Desc %x",
+		    error);
 		brelse(secbp);
 		return (NULL);
 	}
@@ -994,7 +1009,7 @@
 		return (NULL);
 	}
 	udf_vfsp = (struct udf_vfs *)
-		kmem_zalloc(sizeof (struct udf_vfs), KM_SLEEP);
+	    kmem_zalloc(sizeof (struct udf_vfs), KM_SLEEP);
 	udf_vfsp->udf_mvds_loc = SWAP_32(avdp->avd_main_vdse.ext_loc);
 	udf_vfsp->udf_mvds_len = SWAP_32(avdp->avd_main_vdse.ext_len);
 	udf_vfsp->udf_rvds_loc = SWAP_32(avdp->avd_res_vdse.ext_loc);
@@ -1008,15 +1023,15 @@
 	 */
 	vds_loc = udf_vfsp->udf_mvds_loc;
 	secbp = ud_bread(dev, vds_loc << shift,
-			udf_vfsp->udf_mvds_len);
+	    udf_vfsp->udf_mvds_len);
 	if ((error = geterror(secbp)) != 0) {
 		brelse(secbp);
-		cmn_err(CE_NOTE,
-		"udfs : Could not read Main Volume Desc %x", error);
+		cmn_err(CE_NOTE, "udfs : Could not read Main Volume Desc %x",
+		    error);
 
 		vds_loc = udf_vfsp->udf_rvds_loc;
 		secbp = ud_bread(dev, vds_loc << shift,
-			udf_vfsp->udf_rvds_len);
+		    udf_vfsp->udf_rvds_len);
 		if ((error = geterror(secbp)) != 0) {
 			brelse(secbp);
 			cmn_err(CE_NOTE,
@@ -1046,7 +1061,7 @@
 		    1, desc_len) == 0) {
 			if (udf_vfsp->udf_pvd == NULL) {
 				udf_vfsp->udf_pvd =
-					(struct pri_vol_desc *)ttag;
+				    (struct pri_vol_desc *)ttag;
 			} else {
 				struct pri_vol_desc *opvd, *npvd;
 
@@ -1054,15 +1069,15 @@
 				npvd = (struct pri_vol_desc *)ttag;
 
 				if ((strncmp(opvd->pvd_vsi,
-					npvd->pvd_vsi, 128) == 0) &&
-					(strncmp(opvd->pvd_vol_id,
-					npvd->pvd_vol_id, 32) == 0) &&
-					(strncmp((caddr_t)&opvd->pvd_desc_cs,
-						(caddr_t)&npvd->pvd_desc_cs,
-						sizeof (charspec_t)) == 0)) {
+				    npvd->pvd_vsi, 128) == 0) &&
+				    (strncmp(opvd->pvd_vol_id,
+				    npvd->pvd_vol_id, 32) == 0) &&
+				    (strncmp((caddr_t)&opvd->pvd_desc_cs,
+				    (caddr_t)&npvd->pvd_desc_cs,
+				    sizeof (charspec_t)) == 0)) {
 
 					if (SWAP_32(opvd->pvd_vdsn) <
-						SWAP_32(npvd->pvd_vdsn)) {
+					    SWAP_32(npvd->pvd_vdsn)) {
 						udf_vfsp->udf_pvd = npvd;
 					}
 				} else {
@@ -1076,7 +1091,7 @@
 
 			lvd = (struct log_vol_desc *)ttag;
 			if (strncmp(lvd->lvd_dom_id.reg_id,
-					UDF_DOMAIN_NAME, 23) != 0) {
+			    UDF_DOMAIN_NAME, 23) != 0) {
 				printf("Domain ID in lvd is not valid\n");
 				goto out;
 			}
@@ -1088,12 +1103,12 @@
 
 				olvd = udf_vfsp->udf_lvd;
 				if ((strncmp((caddr_t)&olvd->lvd_desc_cs,
-						(caddr_t)&lvd->lvd_desc_cs,
-						sizeof (charspec_t)) == 0) &&
-					(strncmp(olvd->lvd_lvid,
-						lvd->lvd_lvid, 128) == 0)) {
+				    (caddr_t)&lvd->lvd_desc_cs,
+				    sizeof (charspec_t)) == 0) &&
+				    (strncmp(olvd->lvd_lvid,
+				    lvd->lvd_lvid, 128) == 0)) {
 					if (SWAP_32(olvd->lvd_vdsn) <
-						SWAP_32(lvd->lvd_vdsn)) {
+					    SWAP_32(lvd->lvd_vdsn)) {
 						udf_vfsp->udf_lvd = lvd;
 					}
 				} else {
@@ -1111,35 +1126,37 @@
 			pdesc = (struct part_desc *)ttag;
 			pold = udf_vfsp->udf_parts;
 			for (i = 0; i < udf_vfsp->udf_npart; i++) {
-				if (pold->udp_number ==
-					SWAP_16(pdesc->pd_pnum)) {
-					if (SWAP_32(pdesc->pd_vdsn) >
-						pold->udp_seqno) {
-						pold->udp_seqno =
-							SWAP_32(pdesc->pd_vdsn);
-						pold->udp_access =
-						SWAP_32(pdesc->pd_acc_type);
-						pold->udp_start =
-						SWAP_32(pdesc->pd_part_start);
-						pold->udp_length =
-						SWAP_32(pdesc->pd_part_length);
-					}
-					goto loop_end;
+				if (pold->udp_number !=
+				    SWAP_16(pdesc->pd_pnum)) {
+					pold++;
+					continue;
 				}
-				pold ++;
+
+				if (SWAP_32(pdesc->pd_vdsn) >
+				    pold->udp_seqno) {
+					pold->udp_seqno =
+					    SWAP_32(pdesc->pd_vdsn);
+					pold->udp_access =
+					    SWAP_32(pdesc->pd_acc_type);
+					pold->udp_start =
+					    SWAP_32(pdesc->pd_part_start);
+					pold->udp_length =
+					    SWAP_32(pdesc->pd_part_length);
+				}
+				goto loop_end;
 			}
 			pold = udf_vfsp->udf_parts;
 			udf_vfsp->udf_npart++;
 			pnew = kmem_zalloc(udf_vfsp->udf_npart *
-					sizeof (struct ud_part), KM_SLEEP);
+			    sizeof (struct ud_part), KM_SLEEP);
 			udf_vfsp->udf_parts = pnew;
 			if (pold) {
 				bcopy(pold, pnew,
-					sizeof (struct ud_part) *
-					(udf_vfsp->udf_npart - 1));
+				    sizeof (struct ud_part) *
+				    (udf_vfsp->udf_npart - 1));
 				kmem_free(pold,
-					sizeof (struct ud_part) *
-					(udf_vfsp->udf_npart - 1));
+				    sizeof (struct ud_part) *
+				    (udf_vfsp->udf_npart - 1));
 			}
 			part = pnew + (udf_vfsp->udf_npart - 1);
 			part->udp_number = SWAP_16(pdesc->pd_pnum);
@@ -1157,23 +1174,23 @@
 			if (hdr->phdr_ust.sad_ext_len) {
 				part->udp_flags = UDP_SPACETBLS;
 				part->udp_unall_loc =
-					SWAP_32(hdr->phdr_ust.sad_ext_loc);
+				    SWAP_32(hdr->phdr_ust.sad_ext_loc);
 				part->udp_unall_len =
-					SWAP_32(hdr->phdr_ust.sad_ext_len);
+				    SWAP_32(hdr->phdr_ust.sad_ext_len);
 				part->udp_freed_loc =
-					SWAP_32(hdr->phdr_fst.sad_ext_loc);
+				    SWAP_32(hdr->phdr_fst.sad_ext_loc);
 				part->udp_freed_len =
-					SWAP_32(hdr->phdr_fst.sad_ext_len);
+				    SWAP_32(hdr->phdr_fst.sad_ext_len);
 			} else {
 				part->udp_flags = UDP_BITMAPS;
 				part->udp_unall_loc =
-					SWAP_32(hdr->phdr_usb.sad_ext_loc);
+				    SWAP_32(hdr->phdr_usb.sad_ext_loc);
 				part->udp_unall_len =
-					SWAP_32(hdr->phdr_usb.sad_ext_len);
+				    SWAP_32(hdr->phdr_usb.sad_ext_len);
 				part->udp_freed_loc =
-					SWAP_32(hdr->phdr_fsb.sad_ext_loc);
+				    SWAP_32(hdr->phdr_fsb.sad_ext_loc);
 				part->udp_freed_len =
-					SWAP_32(hdr->phdr_fsb.sad_ext_len);
+				    SWAP_32(hdr->phdr_fsb.sad_ext_len);
 			}
 		} else if (ud_verify_tag_and_desc(ttag, UD_TERM_DESC,
 		    vds_loc + (index >> shift),
@@ -1185,8 +1202,8 @@
 		;
 	}
 	if ((udf_vfsp->udf_pvd == NULL) ||
-		(udf_vfsp->udf_lvd == NULL) ||
-		(udf_vfsp->udf_parts == NULL)) {
+	    (udf_vfsp->udf_lvd == NULL) ||
+	    (udf_vfsp->udf_parts == NULL)) {
 		goto out;
 	}
 
@@ -1201,7 +1218,7 @@
 	 * Process Logical Volume Descriptor
 	 */
 	udf_vfsp->udf_lbsize =
-		SWAP_32(udf_vfsp->udf_lvd->lvd_log_bsize);
+	    SWAP_32(udf_vfsp->udf_lvd->lvd_log_bsize);
 	udf_vfsp->udf_lbmask = udf_vfsp->udf_lbsize - 1;
 	udf_vfsp->udf_l2d_shift = shift;
 	udf_vfsp->udf_l2b_shift = shift + DEV_BSHIFT;
@@ -1211,7 +1228,7 @@
 	 * proper domain.
 	 */
 	if (strcmp(udf_vfsp->udf_lvd->lvd_dom_id.reg_id,
-			UDF_DOMAIN_NAME) != 0) {
+	    UDF_DOMAIN_NAME) != 0) {
 		goto out;
 	}
 
@@ -1224,16 +1241,16 @@
 	}
 
 	udf_vfsp->udf_iseq_loc =
-		SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_loc);
+	    SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_loc);
 	udf_vfsp->udf_iseq_len =
-		SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_len);
+	    SWAP_32(udf_vfsp->udf_lvd->lvd_int_seq_ext.ext_len);
 
 	udf_vfsp->udf_fsd_prn =
-		SWAP_16(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_prn);
+	    SWAP_16(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_prn);
 	udf_vfsp->udf_fsd_loc =
-		SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_loc);
+	    SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_loc);
 	udf_vfsp->udf_fsd_len =
-		SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_len);
+	    SWAP_32(udf_vfsp->udf_lvd->lvd_lvcu.lad_ext_len);
 
 
 	/*
@@ -1242,13 +1259,13 @@
 	udf_vfsp->udf_mtype = udf_vfsp->udf_parts[0].udp_access;
 	for (index = 0; index < udf_vfsp->udf_npart; index ++) {
 		if (udf_vfsp->udf_parts[index].udp_access <
-				udf_vfsp->udf_mtype) {
+		    udf_vfsp->udf_mtype) {
 			udf_vfsp->udf_mtype =
-				udf_vfsp->udf_parts[index].udp_access;
+			    udf_vfsp->udf_parts[index].udp_access;
 		}
 	}
 	if ((udf_vfsp->udf_mtype < UDF_MT_RO) ||
-		(udf_vfsp->udf_mtype > UDF_MT_OW)) {
+	    (udf_vfsp->udf_mtype > UDF_MT_OW)) {
 		udf_vfsp->udf_mtype = UDF_MT_RO;
 	}
 
@@ -1258,19 +1275,19 @@
 	for (index = 0; index < count; index++) {
 
 		if ((hdr->maph_type == MAP_TYPE1) &&
-			(hdr->maph_length == MAP_TYPE1_LEN)) {
+		    (hdr->maph_length == MAP_TYPE1_LEN)) {
 			typ1 = (struct pmap_typ1 *)hdr;
 
 			map = udf_vfsp->udf_maps;
 			udf_vfsp->udf_maps =
-				kmem_zalloc(sizeof (struct ud_map) *
-					(udf_vfsp->udf_nmaps + 1),
-					KM_SLEEP);
+			    kmem_zalloc(sizeof (struct ud_map) *
+			    (udf_vfsp->udf_nmaps + 1), KM_SLEEP);
 			if (map != NULL) {
 				bcopy(map, udf_vfsp->udf_maps,
-				sizeof (struct ud_map) * udf_vfsp->udf_nmaps);
-				kmem_free(map,
-				sizeof (struct ud_map) * udf_vfsp->udf_nmaps);
+				    sizeof (struct ud_map) *
+				    udf_vfsp->udf_nmaps);
+				kmem_free(map, sizeof (struct ud_map) *
+				    udf_vfsp->udf_nmaps);
 			}
 			map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
 			map->udm_flags = UDM_MAP_NORM;
@@ -1278,11 +1295,11 @@
 			map->udm_pn = SWAP_16(typ1->map1_pn);
 			udf_vfsp->udf_nmaps ++;
 		} else if ((hdr->maph_type == MAP_TYPE2) &&
-			(hdr->maph_length == MAP_TYPE2_LEN)) {
+		    (hdr->maph_length == MAP_TYPE2_LEN)) {
 			typ2 = (struct pmap_typ2 *)hdr;
 
 			if (strncmp(typ2->map2_pti.reg_id,
-				UDF_VIRT_PART, 23) == 0) {
+			    UDF_VIRT_PART, 23) == 0) {
 				/*
 				 * Add this to the normal
 				 * partition table so that
@@ -1290,16 +1307,15 @@
 				 */
 				map = udf_vfsp->udf_maps;
 				udf_vfsp->udf_maps =
-					kmem_zalloc(sizeof (struct ud_map) *
-						(udf_vfsp->udf_nmaps + 1),
-						KM_SLEEP);
+				    kmem_zalloc(sizeof (struct ud_map) *
+				    (udf_vfsp->udf_nmaps + 1), KM_SLEEP);
 				if (map != NULL) {
 					bcopy(map, udf_vfsp->udf_maps,
-						sizeof (struct ud_map) *
-						udf_vfsp->udf_nmaps);
+					    sizeof (struct ud_map) *
+					    udf_vfsp->udf_nmaps);
 					kmem_free(map,
-						sizeof (struct ud_map) *
-						udf_vfsp->udf_nmaps);
+					    sizeof (struct ud_map) *
+					    udf_vfsp->udf_nmaps);
 				}
 				map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
 				map->udm_flags = UDM_MAP_VPM;
@@ -1310,34 +1326,34 @@
 					goto out;
 				}
 				if (error = ud_val_get_vat(udf_vfsp, dev,
-					lblkno, map)) {
+				    lblkno, map)) {
 					goto out;
 				}
 			} else if (strncmp(typ2->map2_pti.reg_id,
-				UDF_SPAR_PART, 23) == 0) {
+			    UDF_SPAR_PART, 23) == 0) {
 
 				if (SWAP_16(typ2->map2_pl) != 32) {
 					printf(
-					"Packet Length is not valid %x\n",
-						SWAP_16(typ2->map2_pl));
+					    "Packet Length is not valid %x\n",
+					    SWAP_16(typ2->map2_pl));
 					goto out;
 				}
 				if ((typ2->map2_nst < 1) ||
-					(typ2->map2_nst > 4)) {
+				    (typ2->map2_nst > 4)) {
 					goto out;
 				}
 				map = udf_vfsp->udf_maps;
 				udf_vfsp->udf_maps =
-					kmem_zalloc(sizeof (struct ud_map) *
-						(udf_vfsp->udf_nmaps + 1),
-						KM_SLEEP);
+				    kmem_zalloc(sizeof (struct ud_map) *
+				    (udf_vfsp->udf_nmaps + 1),
+				    KM_SLEEP);
 				if (map != NULL) {
 					bcopy(map, udf_vfsp->udf_maps,
-						sizeof (struct ud_map) *
-						udf_vfsp->udf_nmaps);
+					    sizeof (struct ud_map) *
+					    udf_vfsp->udf_nmaps);
 					kmem_free(map,
-						sizeof (struct ud_map) *
-						udf_vfsp->udf_nmaps);
+					    sizeof (struct ud_map) *
+					    udf_vfsp->udf_nmaps);
 				}
 				map = udf_vfsp->udf_maps + udf_vfsp->udf_nmaps;
 				map->udm_flags = UDM_MAP_SPM;
@@ -1347,7 +1363,7 @@
 				udf_vfsp->udf_nmaps ++;
 
 				if (error = ud_read_sparing_tbls(udf_vfsp,
-						dev, map, typ2)) {
+				    dev, map, typ2)) {
 					goto out;
 				}
 			} else {
@@ -1373,11 +1389,11 @@
 	 * and process it
 	 */
 	secbp = ud_bread(dev, udf_vfsp->udf_iseq_loc << shift,
-			udf_vfsp->udf_iseq_len);
+	    udf_vfsp->udf_iseq_len);
 	if ((error = geterror(secbp)) != 0) {
 		cmn_err(CE_NOTE,
 		"udfs : Could not read Logical Volume Integrity Sequence %x",
-			error);
+		    error);
 		brelse(secbp);
 		goto out;
 	}
@@ -1424,8 +1440,8 @@
 	}
 
 	if ((blkno = ud_xlate_to_daddr(udf_vfsp,
-		udf_vfsp->udf_fsd_prn, udf_vfsp->udf_fsd_loc,
-			1, &dummy)) == 0) {
+	    udf_vfsp->udf_fsd_prn, udf_vfsp->udf_fsd_loc,
+	    1, &dummy)) == 0) {
 		goto out;
 	}
 	secbp = ud_bread(dev, blkno << shift, udf_vfsp->udf_fsd_len);
@@ -1449,8 +1465,8 @@
 	secbp->b_flags = B_AGE | B_STALE;
 	brelse(secbp);
 	udf_vfsp->udf_root_blkno = ud_xlate_to_daddr(udf_vfsp,
-			udf_vfsp->udf_ricb_prn, udf_vfsp->udf_ricb_loc,
-			1, &dummy);
+	    udf_vfsp->udf_ricb_prn, udf_vfsp->udf_ricb_loc,
+	    1, &dummy);
 
 	return (udf_vfsp);
 out:
@@ -1603,7 +1619,7 @@
 	int32_t rval, error;
 
 	if ((error = cdev_ioctl(dev, DKIOCGVTOC, (intptr_t)&vtoc,
-			FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
+	    FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
 		cmn_err(CE_NOTE, "Could not get the vtoc information");
 		return (error);
 	}
@@ -1612,7 +1628,7 @@
 		return (EINVAL);
 	}
 	if ((error = cdev_ioctl(dev, DKIOCINFO, (intptr_t)&dki_info,
-			FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
+	    FKIOCTL|FREAD|FNATIVE, CRED(), &rval)) != 0) {
 		cmn_err(CE_NOTE, "Could not get the slice information");
 		return (error);
 	}
@@ -1656,8 +1672,8 @@
 		udm->udm_vat_icb = end_loc - ud_sub_blks[i];
 
 		secbp = ud_bread(dev,
-			udm->udm_vat_icb << udf_vfsp->udf_l2d_shift,
-			udf_vfsp->udf_lbsize);
+		    udm->udm_vat_icb << udf_vfsp->udf_l2d_shift,
+		    udf_vfsp->udf_lbsize);
 		ASSERT(secbp->b_un.b_addr);
 
 		fe = (struct file_entry *)secbp->b_un.b_addr;
@@ -1683,10 +1699,10 @@
 		udm->udm_nent = 1;
 	} else if (ad_type == ICB_FLAG_SHORT_AD) {
 		udm->udm_nent =
-			SWAP_32(fe->fe_len_adesc) / sizeof (struct short_ad);
+		    SWAP_32(fe->fe_len_adesc) / sizeof (struct short_ad);
 	} else if (ad_type == ICB_FLAG_LONG_AD) {
 		udm->udm_nent =
-			SWAP_32(fe->fe_len_adesc) / sizeof (struct long_ad);
+		    SWAP_32(fe->fe_len_adesc) / sizeof (struct long_ad);
 	} else {
 		err = EINVAL;
 		goto end;
@@ -1701,22 +1717,22 @@
 
 	if (ad_type == ICB_FLAG_ONE_AD) {
 			udm->udm_count[0] = (SWAP_64(fe->fe_info_len) - 36) /
-						sizeof (uint32_t);
+			    sizeof (uint32_t);
 			udm->udm_bp[0] = secbp;
 			udm->udm_addr[0] = (uint32_t *)
-				&fe->fe_spec[SWAP_32(fe->fe_len_ear)];
+			    &fe->fe_spec[SWAP_32(fe->fe_len_ear)];
 			return (0);
 	}
 	for (i = 0; i < udm->udm_nent; i++) {
 		if (ad_type == ICB_FLAG_SHORT_AD) {
 			sad = (struct short_ad *)
-				(fe->fe_spec + SWAP_32(fe->fe_len_ear));
+			    (fe->fe_spec + SWAP_32(fe->fe_len_ear));
 			sad += i;
 			count = SWAP_32(sad->sad_ext_len);
 			blk = SWAP_32(sad->sad_ext_loc);
 		} else {
 			lad = (struct long_ad *)
-				(fe->fe_spec + SWAP_32(fe->fe_len_ear));
+			    (fe->fe_spec + SWAP_32(fe->fe_len_ear));
 			lad += i;
 			count = SWAP_32(lad->lad_ext_len);
 			blk = SWAP_32(lad->lad_ext_loc);
@@ -1744,9 +1760,9 @@
 
 		count = (count + DEV_BSIZE - 1) & ~(DEV_BSIZE - 1);
 		udm->udm_bp[i] = ud_bread(dev,
-			blk << udf_vfsp->udf_l2d_shift, count);
+		    blk << udf_vfsp->udf_l2d_shift, count);
 		if ((udm->udm_bp[i]->b_error != 0) ||
-			(udm->udm_bp[i]->b_resid)) {
+		    (udm->udm_bp[i]->b_resid)) {
 			err = EINVAL;
 			break;
 		}
@@ -1782,7 +1798,7 @@
 		map->udm_loc[index] = SWAP_32(typ2->map2_st[index]);
 
 		bp = ud_bread(dev,
-			map->udm_loc[index] << udf_vfsp->udf_l2d_shift, sz);
+		    map->udm_loc[index] << udf_vfsp->udf_l2d_shift, sz);
 		if ((bp->b_error != 0) || (bp->b_resid)) {
 			brelse(bp);
 			continue;
@@ -1840,23 +1856,23 @@
 	}
 
 	if (cdev_ioctl(dev, CDROMREADOFFSET, (intptr_t)&session_offset,
-			FKIOCTL|FREAD|FNATIVE, CRED(), &rval) != 0) {
+	    FKIOCTL|FREAD|FNATIVE, CRED(), &rval) != 0) {
 		session_offset = 0;
 	}
 
 	for (index = 0; index < end_index; index++) {
 
 		for (bsize = DEV_BSIZE, shift = 0;
-			bsize <= MAXBSIZE; bsize <<= 1, shift++) {
+		    bsize <= MAXBSIZE; bsize <<= 1, shift++) {
 
 			if (index == 0) {
 				avd_loc = 256;
 				if (bsize <= 2048) {
 					avd_loc +=
-						session_offset * 2048 / bsize;
+					    session_offset * 2048 / bsize;
 				} else {
 					avd_loc +=
-						session_offset / (bsize / 2048);
+					    session_offset / (bsize / 2048);
 				}
 			} else if (index == 1) {
 				avd_loc = last_block - (1 << shift);
@@ -1865,7 +1881,7 @@
 			}
 
 			bp = ud_bread(dev, avd_loc << shift,
-				ANCHOR_VOL_DESC_LEN);
+			    ANCHOR_VOL_DESC_LEN);
 			if (geterror(bp) != 0) {
 				brelse(bp);
 				continue;
--- a/usr/src/uts/common/fs/ufs/ufs_vfsops.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/uts/common/fs/ufs/ufs_vfsops.c	Tue May 27 18:25:14 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -265,7 +265,8 @@
 	char *data = uap->dataptr;
 	int datalen = uap->datalen;
 	dev_t dev;
-	struct vnode *bvp;
+	struct vnode *lvp = NULL;
+	struct vnode *svp = NULL;
 	struct pathname dpn;
 	int error;
 	enum whymountroot why = ROOT_INIT;
@@ -308,6 +309,16 @@
 	} else {
 		datalen = 0;
 	}
+
+	if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
+	    (uap->flags & MS_RDONLY) != 0) {
+		oflag = FREAD;
+		aflag = VREAD;
+	} else {
+		oflag = FREAD | FWRITE;
+		aflag = VREAD | VWRITE;
+	}
+
 	/*
 	 * Read in the mount point pathname
 	 * (so we can record the directory the file system was last mounted on).
@@ -318,55 +329,67 @@
 	/*
 	 * Resolve path name of special file being mounted.
 	 */
-	if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &bvp)) {
+	if (error = lookupname(uap->spec, fromspace, FOLLOW, NULL, &svp)) {
 		pn_free(&dpn);
 		return (error);
 	}
-	if (bvp->v_type != VBLK) {
-		VN_RELE(bvp);
+
+	error = vfs_get_lofi(vfsp, &lvp);
+
+	if (error > 0) {
+		VN_RELE(svp);
 		pn_free(&dpn);
-		return (ENOTBLK);
+		return (error);
+	} else if (error == 0) {
+		dev = lvp->v_rdev;
+
+		if (getmajor(dev) >= devcnt) {
+			error = ENXIO;
+			goto out;
+		}
+	} else {
+		dev = svp->v_rdev;
+
+		if (svp->v_type != VBLK) {
+			VN_RELE(svp);
+			pn_free(&dpn);
+			return (ENOTBLK);
+		}
+
+		if (getmajor(dev) >= devcnt) {
+			error = ENXIO;
+			goto out;
+		}
+
+		/*
+		 * In SunCluster, requests to a global device are
+		 * satisfied by a local device. We substitute the global
+		 * pxfs node with a local spec node here.
+		 */
+		if (IS_PXFSVP(svp)) {
+			ASSERT(lvp == NULL);
+			VN_RELE(svp);
+			svp = makespecvp(dev, VBLK);
+		}
+
+		if ((error = secpolicy_spec_open(cr, svp, oflag)) != 0) {
+			VN_RELE(svp);
+			pn_free(&dpn);
+			return (error);
+		}
 	}
-	dev = bvp->v_rdev;
-	if (getmajor(dev) >= devcnt) {
-		pn_free(&dpn);
-		VN_RELE(bvp);
-		return (ENXIO);
-	}
+
 	if (uap->flags & MS_REMOUNT)
 		why = ROOT_REMOUNT;
 
 	/*
-	 * In SunCluster, requests to a global device are satisfied by
-	 * a local device. We substitute the global pxfs node with a
-	 * local spec node here.
-	 */
-	if (IS_PXFSVP(bvp)) {
-		VN_RELE(bvp);
-		bvp = makespecvp(dev, VBLK);
-	}
-
-	/*
-	 * Open block device mounted on.  We need this to
-	 * check whether the caller has sufficient rights to
-	 * access the device in question.
-	 * When bio is fixed for vnodes this can all be vnode
+	 * Open device/file mounted on.  We need this to check whether
+	 * the caller has sufficient rights to access the resource in
+	 * question.  When bio is fixed for vnodes this can all be vnode
 	 * operations.
 	 */
-	if ((vfsp->vfs_flag & VFS_RDONLY) != 0 ||
-	    (uap->flags & MS_RDONLY) != 0) {
-		oflag = FREAD;
-		aflag = VREAD;
-	} else {
-		oflag = FREAD | FWRITE;
-		aflag = VREAD | VWRITE;
-	}
-	if ((error = VOP_ACCESS(bvp, aflag, 0, cr, NULL)) != 0 ||
-	    (error = secpolicy_spec_open(cr, bvp, oflag)) != 0) {
-		pn_free(&dpn);
-		VN_RELE(bvp);
-		return (error);
-	}
+	if ((error = VOP_ACCESS(svp, aflag, 0, cr, NULL)) != 0)
+		goto out;
 
 	/*
 	 * Ensure that this device isn't already mounted or in progress on a
@@ -376,15 +399,13 @@
 	if ((uap->flags & MS_NOCHECK) == 0) {
 		if ((uap->flags & MS_GLOBAL) == 0 &&
 		    vfs_devmounting(dev, vfsp)) {
-			pn_free(&dpn);
-			VN_RELE(bvp);
-			return (EBUSY);
+			error = EBUSY;
+			goto out;
 		}
 		if (vfs_devismounted(dev)) {
 			if ((uap->flags & MS_REMOUNT) == 0) {
-				pn_free(&dpn);
-				VN_RELE(bvp);
-				return (EBUSY);
+				error = EBUSY;
+				goto out;
 			}
 		}
 	}
@@ -402,15 +423,31 @@
 	/*
 	 * Mount the filesystem, free the device vnode on error.
 	 */
-	error = mountfs(vfsp, why, bvp, dpn.pn_path, cr, 0, &args, datalen);
+	error = mountfs(vfsp, why, lvp != NULL ? lvp : svp,
+	    dpn.pn_path, cr, 0, &args, datalen);
+
+	if (error == 0) {
+		vfs_set_feature(vfsp, VFSFT_XVATTR);
+
+		/*
+		 * If lofi, drop our reference to the original file.
+		 */
+		if (lvp != NULL)
+			VN_RELE(svp);
+	}
+
+out:
 	pn_free(&dpn);
+
 	if (error) {
-		VN_RELE(bvp);
+		if (lvp != NULL)
+			VN_RELE(lvp);
+		if (svp != NULL)
+			VN_RELE(svp);
 	}
-	if (error == 0)
-		vfs_set_feature(vfsp, VFSFT_XVATTR);
 	return (error);
 }
+
 /*
  * Mount root file system.
  * "why" is ROOT_INIT on initial call ROOT_REMOUNT if called to
--- a/usr/src/uts/common/fs/vfs.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/uts/common/fs/vfs.c	Tue May 27 18:25:14 2008 -0700
@@ -85,6 +85,7 @@
 #include <sys/reboot.h>
 #include <sys/attr.h>
 #include <sys/spa.h>
+#include <sys/lofi.h>
 
 #include <vm/page.h>
 
@@ -525,6 +526,7 @@
 	vfsp->vfs_prev = vfsp;
 	vfsp->vfs_zone_next = vfsp;
 	vfsp->vfs_zone_prev = vfsp;
+	vfsp->vfs_lofi_minor = 0;
 	sema_init(&vfsp->vfs_reflock, 1, NULL, SEMA_DEFAULT, NULL);
 	vfsimpl_setup(vfsp);
 	vfsp->vfs_data = (data);
@@ -982,6 +984,129 @@
 }
 
 /*
+ * Check to see if our "block device" is actually a file.  If so,
+ * automatically add a lofi device, and keep track of this fact.
+ */
+static int
+lofi_add(const char *fsname, struct vfs *vfsp,
+    mntopts_t *mntopts, struct mounta *uap)
+{
+	int fromspace = (uap->flags & MS_SYSSPACE) ?
+	    UIO_SYSSPACE : UIO_USERSPACE;
+	struct lofi_ioctl *li = NULL;
+	struct vnode *vp = NULL;
+	struct pathname	pn = { NULL };
+	ldi_ident_t ldi_id;
+	ldi_handle_t ldi_hdl;
+	int minor;
+	int err = 0;
+
+	if (fsname == NULL)
+		return (0);
+	if (strcmp(fsname, "mntfs") == 0 || strcmp(fsname, "lofs") == 0)
+		return (0);
+
+	if (pn_get(uap->spec, fromspace, &pn) != 0)
+		return (0);
+
+	if (lookupname(uap->spec, fromspace, FOLLOW, NULL, &vp) != 0)
+		goto out;
+
+	if (vp->v_type != VREG)
+		goto out;
+
+	/* OK, this is a lofi mount. */
+
+	if ((uap->flags & (MS_REMOUNT|MS_GLOBAL)) ||
+	    vfs_optionisset_nolock(mntopts, MNTOPT_SUID, NULL) ||
+	    vfs_optionisset_nolock(mntopts, MNTOPT_SETUID, NULL) ||
+	    vfs_optionisset_nolock(mntopts, MNTOPT_DEVICES, NULL)) {
+		err = EINVAL;
+		goto out;
+	}
+
+	ldi_id = ldi_ident_from_anon();
+	li = kmem_zalloc(sizeof (*li), KM_SLEEP);
+	(void) strlcpy(li->li_filename, pn.pn_path, MAXPATHLEN + 1);
+
+	/*
+	 * 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;
+	}
+
+	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);
+
+	if (!err)
+		vfsp->vfs_lofi_minor = minor;
+
+out2:
+	ldi_ident_release(ldi_id);
+out:
+	if (li != NULL)
+		kmem_free(li, sizeof (*li));
+	if (vp != NULL)
+		VN_RELE(vp);
+	pn_free(&pn);
+	return (err);
+}
+
+static void
+lofi_remove(struct vfs *vfsp)
+{
+	struct lofi_ioctl *li = NULL;
+	ldi_ident_t ldi_id;
+	ldi_handle_t ldi_hdl;
+	int err;
+
+	if (vfsp->vfs_lofi_minor == 0)
+		return;
+
+	ldi_id = ldi_ident_from_anon();
+
+	li = kmem_zalloc(sizeof (*li), KM_SLEEP);
+	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);
+
+	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);
+
+	if (!err)
+		vfsp->vfs_lofi_minor = 0;
+
+out:
+	ldi_ident_release(ldi_id);
+	if (li != NULL)
+		kmem_free(li, sizeof (*li));
+}
+
+/*
  * Common mount code.  Called from the system call entry point, from autofs,
  * nfsv4 trigger mounts, and from pxfs.
  *
@@ -1029,6 +1154,7 @@
 	refstr_t	*oldresource, *oldmntpt;
 	struct pathname	pn, rpn;
 	vsk_anchor_t	*vskap;
+	char fstname[FSTYPSZ];
 
 	/*
 	 * The v_flag value for the mount point vp is permanently set
@@ -1069,7 +1195,8 @@
 	} else if (uap->flags & (MS_OPTIONSTR | MS_DATA | MS_FSS)) {
 		size_t n;
 		uint_t fstype;
-		char name[FSTYPSZ];
+
+		fsname = fstname;
 
 		if ((fstype = (uintptr_t)uap->fstype) < 256) {
 			RLOCK_VFSSW();
@@ -1078,19 +1205,19 @@
 				RUNLOCK_VFSSW();
 				return (EINVAL);
 			}
-			(void) strcpy(name, vfssw[fstype].vsw_name);
+			(void) strcpy(fsname, vfssw[fstype].vsw_name);
 			RUNLOCK_VFSSW();
-			if ((vswp = vfs_getvfssw(name)) == NULL)
+			if ((vswp = vfs_getvfssw(fsname)) == NULL)
 				return (EINVAL);
 		} else {
 			/*
 			 * Handle either kernel or user address space.
 			 */
 			if (uap->flags & MS_SYSSPACE) {
-				error = copystr(uap->fstype, name,
+				error = copystr(uap->fstype, fsname,
 				    FSTYPSZ, &n);
 			} else {
-				error = copyinstr(uap->fstype, name,
+				error = copyinstr(uap->fstype, fsname,
 				    FSTYPSZ, &n);
 			}
 			if (error) {
@@ -1098,7 +1225,7 @@
 					return (EINVAL);
 				return (error);
 			}
-			if ((vswp = vfs_getvfssw(name)) == NULL)
+			if ((vswp = vfs_getvfssw(fsname)) == NULL)
 				return (EINVAL);
 		}
 	} else {
@@ -1354,6 +1481,26 @@
 
 	VFS_HOLD(vfsp);
 
+	if ((error = lofi_add(fsname, vfsp, &mnt_mntopts, uap)) != 0) {
+		if (!remount) {
+			if (splice)
+				vn_vfsunlock(vp);
+			vfs_free(vfsp);
+		} else {
+			vn_vfsunlock(vp);
+			VFS_RELE(vfsp);
+		}
+		goto errout;
+	}
+
+	/*
+	 * PRIV_SYS_MOUNT doesn't mean you can become root.
+	 */
+	if (vfsp->vfs_lofi_minor != 0) {
+		uap->flags |= MS_NOSUID;
+		vfs_setmntopt_nolock(&mnt_mntopts, MNTOPT_NOSUID, NULL, 0, 0);
+	}
+
 	/*
 	 * The vfs_reflock is not used anymore the code below explicitly
 	 * holds it preventing others accesing it directly.
@@ -1373,6 +1520,9 @@
 	if (!remount) {
 		if (error = vfs_lock(vfsp)) {
 			vfsp->vfs_flag = ovflags;
+
+			lofi_remove(vfsp);
+
 			if (splice)
 				vn_vfsunlock(vp);
 			vfs_free(vfsp);
@@ -1397,8 +1547,32 @@
 	}
 
 	if (addmip) {
-		bdev = bvp->v_rdev;
-		VN_RELE(bvp);
+		vnode_t *lvp = NULL;
+
+		error = vfs_get_lofi(vfsp, &lvp);
+		if (error > 0) {
+			lofi_remove(vfsp);
+
+			if (splice)
+				vn_vfsunlock(vp);
+			vfs_unlock(vfsp);
+
+			if (remount) {
+				VFS_RELE(vfsp);
+			} else {
+				vfs_free(vfsp);
+			}
+
+			goto errout;
+		} else if (error == -1) {
+			bdev = bvp->v_rdev;
+			VN_RELE(bvp);
+		} else {
+			bdev = lvp->v_rdev;
+			VN_RELE(lvp);
+			VN_RELE(bvp);
+		}
+
 		vfs_addmip(bdev, vfsp);
 		addmip = 0;
 		delmip = 1;
@@ -1478,6 +1652,8 @@
 		vfs_setmntopt(vfsp, MNTOPT_GLOBAL, NULL, 0);
 
 	if (error) {
+		lofi_remove(vfsp);
+
 		if (remount) {
 			/* put back pre-remount options */
 			vfs_swapopttbl(&mnt_mntopts, &vfsp->vfs_mntopts);
@@ -1648,6 +1824,7 @@
 	if (inargs != opts)
 		kmem_free(inargs, MAX_MNTOPT_STR);
 	if (copyout_error) {
+		lofi_remove(vfsp);
 		VFS_RELE(vfsp);
 		error = copyout_error;
 	}
@@ -4137,6 +4314,7 @@
 	ASSERT(vfsp->vfs_count != 0);
 	if (atomic_add_32_nv(&vfsp->vfs_count, -1) == 0) {
 		VFS_FREEVFS(vfsp);
+		lofi_remove(vfsp);
 		if (vfsp->vfs_zone)
 			zone_rele(vfsp->vfs_zone);
 		vfs_freemnttab(vfsp);
@@ -4483,3 +4661,35 @@
 		to->vfs_featureset[i] = from->vfs_featureset[i];
 	}
 }
+
+#define	LOFICTL_PATH "/devices/pseudo/lofi@0:%d"
+
+/*
+ * Return the vnode for the lofi node if there's a lofi mount in place.
+ * Returns -1 when there's no lofi node, 0 on success, and > 0 on
+ * failure.
+ */
+int
+vfs_get_lofi(vfs_t *vfsp, vnode_t **vpp)
+{
+	char *path = NULL;
+	int strsize;
+	int err;
+
+	if (vfsp->vfs_lofi_minor == 0) {
+		*vpp = NULL;
+		return (-1);
+	}
+
+	strsize = snprintf(NULL, 0, LOFICTL_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);
+
+	if (err)
+		*vpp = NULL;
+
+	kmem_free(path, strsize + 1);
+	return (err);
+}
--- a/usr/src/uts/common/io/lofi.c	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/uts/common/io/lofi.c	Tue May 27 18:25:14 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -325,11 +325,14 @@
 	mark_closed(lsp, otyp);
 
 	/*
-	 * If we have forcibly closed the underlying device, and this is the
-	 * last close, then tear down the rest of the device.
+	 * If we forcibly closed the underlying device (li_force), or
+	 * asked for cleanup (li_cleanup), finish up if we're the last
+	 * out of the door.
 	 */
-	if (minor != 0 && lsp->ls_vp == NULL && !is_opened(lsp))
+	if (minor != 0 && !is_opened(lsp) &&
+	    (lsp->ls_cleanup || lsp->ls_vp == NULL))
 		lofi_free_handle(dev, minor, lsp, credp);
+
 	mutex_exit(&lofi_lock);
 	return (0);
 }
@@ -1403,21 +1406,28 @@
 		return (ENXIO);
 	}
 
+	/*
+	 * If it's still held open, we'll do one of three things:
+	 *
+	 * If no flag is set, just return EBUSY.
+	 *
+	 * If the 'cleanup' flag is set, unmap and remove the device when
+	 * the last user finishes.
+	 *
+	 * If the 'force' flag is set, then we forcibly close the underlying
+	 * file.  Subsequent operations will fail, and the DKIOCSTATE ioctl
+	 * will return DKIO_DEV_GONE.  When the device is last closed, the
+	 * device will be cleaned up appropriately.
+	 *
+	 * This is complicated by the fact that we may have outstanding
+	 * dispatched I/Os.  Rather than having a single mutex to serialize all
+	 * I/O, we keep a count of the number of outstanding I/O requests, as
+	 * well as a flag to indicate that no new I/Os should be dispatched.
+	 * We set the flag, wait for the number of outstanding I/Os to reach 0,
+	 * and then close the underlying vnode.
+	 */
+
 	if (is_opened(lsp)) {
-		/*
-		 * If the 'force' flag is set, then we forcibly close the
-		 * underlying file.  Subsequent operations will fail, and the
-		 * DKIOCSTATE ioctl will return DKIO_DEV_GONE.  When the device
-		 * is last closed, the device will be cleaned up appropriately.
-		 *
-		 * This is complicated by the fact that we may have outstanding
-		 * dispatched I/Os.  Rather than having a single mutex to
-		 * serialize all I/O, we keep a count of the number of
-		 * outstanding I/O requests, as well as a flag to indicate that
-		 * no new I/Os should be dispatched.  We set the flag, wait for
-		 * the number of outstanding I/Os to reach 0, and then close the
-		 * underlying vnode.
-		 */
 		if (klip->li_force) {
 			mutex_enter(&lsp->ls_vp_lock);
 			lsp->ls_vp_closereq = B_TRUE;
@@ -1434,7 +1444,13 @@
 			(void) copy_out_lofi_ioctl(klip, ulip, ioctl_flag);
 			free_lofi_ioctl(klip);
 			return (0);
+		} else if (klip->li_cleanup) {
+			lsp->ls_cleanup = 1;
+			mutex_exit(&lofi_lock);
+			free_lofi_ioctl(klip);
+			return (0);
 		}
+
 		mutex_exit(&lofi_lock);
 		free_lofi_ioctl(klip);
 		return (EBUSY);
--- a/usr/src/uts/common/sys/lofi.h	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/uts/common/sys/lofi.h	Tue May 27 18:25:14 2008 -0700
@@ -19,7 +19,7 @@
  * CDDL HEADER END
  */
 /*
- * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
+ * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
  * Use is subject to license terms.
  */
 
@@ -106,6 +106,11 @@
  * removed, so the DKIOCSTATE ioctl will return DKIO_DEV_GONE.  When the device
  * is last closed, it will be torn down.
  *
+ * If the 'li_cleanup' flag is set for any of the LOFI_UNMAP_* commands, then
+ * if the device is busy, it is marked for removal at the next time it is
+ * no longer held open by anybody.  When the device is last closed, it will be
+ * torn down.
+ *
  * Oh, and last but not least: these ioctls are totally private and only
  * for use by lofiadm(1M).
  *
@@ -114,6 +119,7 @@
 struct lofi_ioctl {
 	uint32_t 	li_minor;
 	boolean_t	li_force;
+	boolean_t	li_cleanup;
 	char	li_filename[MAXPATHLEN + 1];
 	char	li_algorithm[MAXALGLEN];
 };
@@ -163,6 +169,7 @@
 	uint32_t	ls_chr_open;
 	uint32_t	ls_lyr_open_count;
 	int		ls_openflag;
+	boolean_t	ls_cleanup;	/* cleanup on close */
 	taskq_t		*ls_taskq;
 	kstat_t		*ls_kstat;
 	kmutex_t	ls_kstat_lock;
--- a/usr/src/uts/common/sys/vfs.h	Tue May 27 17:27:03 2008 -0700
+++ b/usr/src/uts/common/sys/vfs.h	Tue May 27 18:25:14 2008 -0700
@@ -251,7 +251,9 @@
 	struct zone	*vfs_zone;		/* zone that owns the mount */
 	struct vfs	*vfs_zone_next;		/* next VFS visible in zone */
 	struct vfs	*vfs_zone_prev;		/* prev VFS visible in zone */
+
 	struct fem_head	*vfs_femhead;		/* fs monitoring */
+	minor_t		vfs_lofi_minor;		/* minor if lofi mount */
 } vfs_t;
 
 #define	vfs_featureset	vfs_implp->vi_featureset
@@ -535,6 +537,8 @@
 
 int	vfs_zone_change_safe(vfs_t *);
 
+int	vfs_get_lofi(vfs_t *, vnode_t **);
+
 #define	VFSHASH(maj, min) (((int)((maj)+(min))) & (vfshsz - 1))
 #define	VFS_ON_LIST(vfsp) \
 	((vfsp)->vfs_next != (vfsp) && (vfsp)->vfs_next != NULL)