This is an experimental patch to allow the same block device to be
mounted read-only as a filesystem more than once on the same machine.
It doesn't currently work, and so should not be used
unless you plan to fix it :-)

--- /usr/src/sys/sys/fcntl.h.orig	Mon Sep 13 15:21:29 1999
+++ /usr/src/sys/sys/fcntl.h	Mon Sep 13 17:04:46 1999
@@ -93,6 +93,7 @@
 #define	FMARK		0x1000		/* mark during gc() */
 #define	FDEFER		0x2000		/* defer for next gc pass */
 #define	FHASLOCK	0x4000		/* descriptor holds advisory lock */
+#define	FMOUNTING	0x8000		/* a block device is being mounted */
 #endif
 
 /* Defined by POSIX 1003.1; BSD default, but must be distinct from O_RDONLY. */
--- /usr/src/sys/miscfs/specfs/spec_vnops.c.orig	Mon Sep 13 17:11:17 1999
+++ /usr/src/sys/miscfs/specfs/spec_vnops.c	Mon Sep 13 15:37:22 1999
@@ -229,7 +229,7 @@
 		 * Do not allow opens of block devices that are
 		 * currently mounted.
 		 */
-		error = vfs_mountedon(vp);
+		error = (ap->a_mode & FMOUNTING) ? 0 : vfs_mountedon(vp);
 		if (error)
 			return (error);
 		return ((*bdevsw[maj]->d_open)(dev, ap->a_mode, S_IFBLK, p));
--- /usr/src/sys/kern/vfs_subr.c.orig	Mon Sep 13 11:44:59 1999
+++ /usr/src/sys/kern/vfs_subr.c	Mon Sep 13 11:55:06 1999
@@ -1886,6 +1886,39 @@
 	simple_unlock(&spechash_slock);
 	return (count);
 }
+
+/*
+ * Calculate the total number of writers on a special device.
+ */
+int
+vwritecount(vp)
+	register struct vnode *vp;
+{
+	struct vnode *vq, *vnext;
+	int count;
+
+loop:
+	if ((vp->v_flag & VALIASED) == 0)
+		return (vp->v_writecount);
+	simple_lock(&spechash_slock);
+	for (count = 0, vq = *vp->v_hashchain; vq; vq = vnext) {
+		vnext = vq->v_specnext;
+		if (vq->v_rdev != vp->v_rdev || vq->v_type != vp->v_type)
+			continue;
+		/*
+		 * Alias, but not in use, so flush it out.
+		 */
+		if (vq->v_writecount == 0 && vq != vp) {
+			simple_unlock(&spechash_slock);
+			vgone(vq);
+			goto loop;
+		}
+		count += vq->v_writecount;
+	}
+	simple_unlock(&spechash_slock);
+	return (count);
+}
+
 /*
  * Print out a description of a vnode.
  */
--- /usr/src/sys/ufs/ffs/ffs_vfsops.c.orig	Mon Sep 13 11:21:07 1999
+++ /usr/src/sys/ufs/ffs/ffs_vfsops.c	Mon Sep 13 23:34:23 1999
@@ -216,6 +216,11 @@
 		}
 		if (ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) {
 			/*
+			 * We can't change if there are multiple r/o mounts.
+			 */
+			if (vcount(devvp) > 1)
+				return (EBUSY);
+			/*
 			 * If upgrade to read-write by non-root, then verify
 			 * that user has necessary permissions on the device.
 			 */
@@ -586,28 +591,33 @@
 	struct ucred *cred;
 	u_int64_t maxfilesize;					/* XXX */
 	size_t strsize;
-	int ncount;
+	int ncount, nwritecount;
 
 	dev = devvp->v_rdev;
 	cred = p ? p->p_ucred : NOCRED;
+	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
 	/*
-	 * Disallow multiple mounts of the same device.
+	 * Only allow multiple read-only mounts of the same device.
 	 * Disallow mounting of a device that is currently in use
 	 * (except for root, which might share swap device for miniroot).
 	 * Flush out any old buffers remaining from a previous use.
 	 */
-	error = vfs_mountedon(devvp);
+	error = ronly ? 0 : vfs_mountedon(devvp);
 	if (error)
 		return (error);
+	nwritecount = vwritecount(devvp);
+	if (nwritecount)
+		return (EBUSY);
 	ncount = vcount(devvp);
-
-	if (ncount > 1 && devvp != rootvp)
+	if (!ronly && ncount > 1 && devvp != rootvp)
 		return (EBUSY);
-	vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
-	error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
-	VOP_UNLOCK(devvp, 0, p);
-	if (error)
-		return (error);
+	if (ncount <= 1) {
+		vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p);
+		error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0);
+		VOP_UNLOCK(devvp, 0, p);
+		if (error)
+			return (error);
+	}
 
 	/*
 	 * Only VMIO the backing device if the backing device is a real
@@ -622,8 +632,8 @@
 		VOP_UNLOCK(devvp, LK_INTERLOCK, p);
 	}
 
-	ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
-	error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p);
+	error = VOP_OPEN(devvp,
+		ronly ? FMOUNTING|FREAD : FMOUNTING|FREAD|FWRITE, FSCRED, p);
 	if (error)
 		return (error);
 
@@ -726,6 +736,7 @@
 	for (i = 0; i < MAXQUOTAS; i++)
 		ump->um_quotas[i] = NULLVP;
 	devvp->v_specmountpoint = mp;
+	if (!ronly) devvp->v_writecount++;
 	ffs_oldfscompat(fs);
 
 	/*
@@ -838,10 +849,12 @@
 			fs->fs_clean = 0;
 			return (error);
 		}
+		ump->um_devvp->v_writecount--;
+	}
+	if (vcount(ump->um_devvp) <= 1) {
+		ump->um_devvp->v_specmountpoint = NULL;
+		vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0);
 	}
-	ump->um_devvp->v_specmountpoint = NULL;
-
-	vinvalbuf(ump->um_devvp, V_SAVE, NOCRED, p, 0, 0);
 	error = VOP_CLOSE(ump->um_devvp, fs->fs_ronly ? FREAD : FREAD|FWRITE,
 		NOCRED, p);
 
