--- old/usr/src/cmd/lofiadm/main.c	Mon Sep 16 15:02:46 2013
+++ new/usr/src/cmd/lofiadm/main.c	Mon Sep 16 15:02:46 2013
@@ -64,7 +64,7 @@
 #include <blowfish/blowfish_impl.h>
 
 static const char USAGE[] =
-	"Usage: %s -a file [ device ] "
+	"Usage: %s [-r] -a file [ device ] "
 	" [-c aes-128-cbc|aes-192-cbc|aes-256-cbc|des3-cbc|blowfish-cbc]"
 	" [-e] [-k keyfile] [-T [token]:[manuf]:[serial]:key]\n"
 	"       %s -d file | device\n"
@@ -364,10 +364,12 @@
  */
 static void
 add_mapping(int lfd, const char *devicename, const char *filename,
-    mech_alias_t *cipher, const char *rkey, size_t rksz)
+    mech_alias_t *cipher, const char *rkey, size_t rksz, boolean_t rdonly)
 {
 	struct lofi_ioctl li;
 
+	li.li_readonly = rdonly;
+
 	li.li_crypto_enabled = B_FALSE;
 	if (cipher != NULL) {
 		/* set up encryption for mapped file */
@@ -497,7 +499,7 @@
 	int	minor;
 	int	maxminor;
 	char	path[MAXPATHLEN];
-	char	options[MAXPATHLEN];
+	char	options[MAXPATHLEN] = { 0 };
 
 	li.li_minor = 0;
 	if (ioctl(fd, LOFI_GET_MAXMINOR, &li) == -1) {
@@ -517,6 +519,9 @@
 		}
 		(void) snprintf(path, sizeof (path), "/dev/%s/%d",
 		    LOFI_BLOCK_NAME, minor);
+
+		options[0] = '\0';
+
 		/*
 		 * Encrypted lofi and compressed lofi are mutually exclusive.
 		 */
@@ -526,7 +531,17 @@
 		else if (li.li_algorithm[0] != '\0')
 			(void) snprintf(options, sizeof (options),
 			    gettext("Compressed(%s)"), li.li_algorithm);
-		else
+		if (li.li_readonly) {
+			if (strlen(options) != 0) {
+				(void) strlcat(options, ",", sizeof (options));
+				(void) strlcat(options, "Readonly",
+				    sizeof (options));
+			} else {
+				(void) snprintf(options, sizeof (options),
+				    gettext("Readonly"));
+			}
+		}
+		if (strlen(options) == 0)
 			(void) snprintf(options, sizeof (options), "-");
 
 		(void) printf(FORMAT, path, li.li_filename, options);
@@ -1789,6 +1804,7 @@
 	const char *pname;
 	boolean_t errflag = B_FALSE;
 	boolean_t addflag = B_FALSE;
+	boolean_t rdflag = B_FALSE;
 	boolean_t deleteflag = B_FALSE;
 	boolean_t ephflag = B_FALSE;
 	boolean_t compressflag = B_FALSE;
@@ -1808,7 +1824,7 @@
 	(void) setlocale(LC_ALL, "");
 	(void) textdomain(TEXT_DOMAIN);
 
-	while ((c = getopt(argc, argv, "a:c:Cd:efk:o:s:T:U")) != EOF) {
+	while ((c = getopt(argc, argv, "a:c:Cd:efk:o:rs:T:U")) != EOF) {
 		switch (c) {
 		case 'a':
 			addflag = B_TRUE;
@@ -1863,6 +1879,9 @@
 			need_crypto = B_TRUE;
 			cipher_only = B_FALSE;	/* need to unset cipher_only */
 			break;
+		case 'r':
+			rdflag = B_TRUE;
+			break;
 		case 's':
 			segsize = convert_to_num(optarg);
 			if (segsize < DEV_BSIZE || !ISP2(segsize))
@@ -1893,6 +1912,7 @@
 	/* Check for mutually exclusive combinations of options */
 	if (errflag ||
 	    (addflag && deleteflag) ||
+	    (rdflag && !addflag) ||
 	    (!addflag && need_crypto) ||
 	    ((compressflag || uncompressflag) && (addflag || deleteflag)))
 		usage(pname);
@@ -2009,7 +2029,8 @@
 	 * Now to the real work.
 	 */
 	if (addflag)
-		add_mapping(lfd, devicename, filename, cipher, rkey, rksz);
+		add_mapping(lfd, devicename, filename, cipher, rkey, rksz,
+		    rdflag);
 	else if (compressflag)
 		lofi_compress(&lfd, filename, compress_index, segsize);
 	else if (uncompressflag)
--- old/usr/src/man/man1m/lofiadm.1m	Mon Sep 16 15:02:48 2013
+++ new/usr/src/man/man1m/lofiadm.1m	Mon Sep 16 15:02:47 2013
@@ -3,59 +3,59 @@
 .\" The contents of this file are subject to the terms of the Common Development and Distribution License (the "License").  You may not use this file except in compliance with the License. You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE or http://www.opensolaris.org/os/licensing.
 .\"  See the License for the specific language governing permissions and limitations under the License. When distributing Covered Code, include this CDDL HEADER in each file and include the License file at usr/src/OPENSOLARIS.LICENSE.  If applicable, add the following below this CDDL HEADER, with
 .\" the fields enclosed by brackets "[]" replaced with your own identifying information: Portions Copyright [yyyy] [name of copyright owner]
-.TH LOFIADM 1M "Aug 31, 2009"
+.TH LOFIADM 1M "Aug 28, 2013"
 .SH NAME
 lofiadm \- administer files available as block devices through lofi
 .SH SYNOPSIS
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
+\fBlofiadm\fR [\fB-r\fR] \fB-a\fR \fIfile\fR [\fIdevice\fR]
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-c\fR \fIcrypto_algorithm\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
+\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-c\fR \fIcrypto_algorithm\fR \fB-k\fR \fIraw_key_file\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
+\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-k\fR \fIraw_key_file\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-c\fR \fIcrypto_algorithm\fR \fB-T\fR \fItoken_key\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
+\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-T\fR \fItoken_key\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-c\fR \fIcrypto_algorithm\fR \fB-T\fR \fItoken_key\fR
+\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-T\fR \fItoken_key\fR
      \fB-k\fR \fIwrapped_key_file\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-c\fR \fIcrypto_algorithm\fR \fB-e\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
+\fBlofiadm\fR [\fB-r\fR] \fB-c\fR \fIcrypto_algorithm\fR \fB-e\fR \fB-a\fR \fIfile\fR [\fIdevice\fR]
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-C\fR \fIalgorithm\fR [\fB-s\fR \fIsegment_size\fR] \fIfile\fR
+\fBlofiadm\fR \fB-C\fR \fIalgorithm\fR [\fB-s\fR \fIsegment_size\fR] \fIfile\fR
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-d\fR \fIfile\fR | \fIdevice\fR
+\fBlofiadm\fR \fB-d\fR \fIfile\fR | \fIdevice\fR
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR \fB-U\fR \fIfile\fR
+\fBlofiadm\fR \fB-U\fR \fIfile\fR
 .fi
 
 .LP
 .nf
-\fB/usr/sbin/lofiadm\fR [ \fIfile\fR | \fIdevice\fR]
+\fBlofiadm\fR [ \fIfile\fR | \fIdevice\fR]
 .fi
 
 .SH DESCRIPTION
@@ -132,6 +132,17 @@
 block device is not busy, and deallocates the block device.
 .RE
 
+.sp
+.ne 2
+.na
+\fB\fB-r\fR
+.ad
+.sp .6
+.RS 4n
+If the \fB-r\fR option is specified before the \fB-a\fR option, the
+\fIdevice\fR will be opened read-only.
+.RE
+
 .sp
 .ne 2
 .na
--- old/usr/src/uts/common/io/lofi.c	Mon Sep 16 15:02:50 2013
+++ new/usr/src/uts/common/io/lofi.c	Mon Sep 16 15:02:48 2013
@@ -478,6 +478,11 @@
 		return (EINVAL);
 	}
 
+	if (lsp->ls_readonly && (flag & FWRITE)) {
+		mutex_exit(&lofi_lock);
+		return (EROFS);
+	}
+
 	mutex_exit(&lofi_lock);
 	return (0);
 }
@@ -1620,11 +1625,13 @@
  * allow the global zone visibility into NGZ lofi nodes.
  */
 static int
-file_to_lofi_nocheck(char *filename, struct lofi_state **lspp)
+file_to_lofi_nocheck(char *filename, boolean_t readonly,
+    struct lofi_state **lspp)
 {
 	struct lofi_state *lsp;
 	vnode_t *vp = NULL;
 	int err = 0;
+	int rdfiles = 0;
 
 	ASSERT(MUTEX_HELD(&lofi_lock));
 
@@ -1646,6 +1653,12 @@
 		if (lsp->ls_vp == vp) {
 			if (lspp != NULL)
 				*lspp = lsp;
+			if (lsp->ls_readonly) {
+				rdfiles++;
+				/* Skip if '-r' is specified */
+				if (readonly)
+					continue;
+			}
 			goto out;
 		}
 	}
@@ -1652,6 +1665,18 @@
 
 	err = ENOENT;
 
+	/*
+	 * If a filename is given as an argument for lofi_unmap, we shouldn't
+	 * allow unmap if there are multiple read-only lofi devices associated
+	 * with this file.
+	 */
+	if (lspp != NULL) {
+		if (rdfiles == 1)
+			err = 0;
+		else if (rdfiles > 1)
+			err = EBUSY;
+	}
+
 out:
 	if (vp != NULL)
 		VN_RELE(vp);
@@ -1663,13 +1688,13 @@
  * it.
  */
 static int
-file_to_lofi(char *filename, struct lofi_state **lspp)
+file_to_lofi(char *filename, boolean_t readonly, struct lofi_state **lspp)
 {
 	int err = 0;
 
 	ASSERT(MUTEX_HELD(&lofi_lock));
 
-	if ((err = file_to_lofi_nocheck(filename, lspp)) != 0)
+	if ((err = file_to_lofi_nocheck(filename, readonly, lspp)) != 0)
 		return (err);
 
 	if ((err = lofi_access(*lspp)) != 0)
@@ -2122,7 +2147,8 @@
 	}
 	mutex_exit(&curproc->p_lock);
 
-	if (file_to_lofi_nocheck(klip->li_filename, NULL) == 0) {
+	if (file_to_lofi_nocheck(klip->li_filename, klip->li_readonly,
+	    NULL) == 0) {
 		error = EBUSY;
 		goto err;
 	}
@@ -2243,6 +2269,8 @@
 	lsp->ls_kstat->ks_lock = &lsp->ls_kstat_lock;
 	kstat_zone_add(lsp->ls_kstat, GLOBAL_ZONEID);
 
+	lsp->ls_readonly = klip->li_readonly;
+
 	if ((error = lofi_init_crypto(lsp, klip)) != 0)
 		goto err;
 
@@ -2343,7 +2371,8 @@
 
 	mutex_enter(&lofi_lock);
 	if (byfilename) {
-		if ((err = file_to_lofi(klip->li_filename, &lsp)) != 0) {
+		if ((err = file_to_lofi(klip->li_filename, klip->li_readonly,
+		    &lsp)) != 0) {
 			mutex_exit(&lofi_lock);
 			return (err);
 		}
@@ -2460,6 +2489,8 @@
 			    sizeof (klip->li_filename));
 		}
 
+		klip->li_readonly = lsp->ls_readonly;
+
 		(void) strlcpy(klip->li_algorithm, lsp->ls_comp_algorithm,
 		    sizeof (klip->li_algorithm));
 		klip->li_crypto_enabled = lsp->ls_crypto_enabled;
@@ -2469,7 +2500,8 @@
 		return (error);
 	case LOFI_GET_MINOR:
 		mutex_enter(&lofi_lock);
-		error = file_to_lofi(klip->li_filename, &lsp);
+		error = file_to_lofi(klip->li_filename,
+		    klip->li_readonly, &lsp);
 		if (error == 0)
 			klip->li_minor = getminor(lsp->ls_dev);
 		mutex_exit(&lofi_lock);
@@ -2481,7 +2513,8 @@
 		return (error);
 	case LOFI_CHECK_COMPRESSED:
 		mutex_enter(&lofi_lock);
-		error = file_to_lofi(klip->li_filename, &lsp);
+		error = file_to_lofi(klip->li_filename,
+		    klip->li_readonly, &lsp);
 		if (error != 0) {
 			mutex_exit(&lofi_lock);
 			free_lofi_ioctl(klip);
--- old/usr/src/uts/common/sys/lofi.h	Mon Sep 16 15:02:53 2013
+++ new/usr/src/uts/common/sys/lofi.h	Mon Sep 16 15:02:50 2013
@@ -128,6 +128,7 @@
 	uint32_t 	li_minor;
 	boolean_t	li_force;
 	boolean_t	li_cleanup;
+	boolean_t	li_readonly;
 	char	li_filename[MAXPATHLEN];
 
 	/* the following fields are required for compression support */
@@ -223,6 +224,7 @@
 	uint32_t	ls_lyr_open_count;
 	int		ls_openflag;
 	boolean_t	ls_cleanup;	/* cleanup on close */
+	boolean_t	ls_readonly;
 	taskq_t		*ls_taskq;
 	kstat_t		*ls_kstat;
 	kmutex_t	ls_kstat_lock;
