Skip site navigation (1)Skip section navigation (2)
Date:      Mon, 13 Sep 1999 17:30:39 +0100
From:      Tony Finch <fanf@demon.net>
To:        hackers@freebsd.org
Subject:   Re: mounting a partition more than once
Message-ID:  <E11QZ03-000DDr-00@fanf.noc.demon.net>
In-Reply-To: <E11QIUW-0006zu-00@dotat.at>

next in thread | previous in thread | raw e-mail | index | archive | help
Tony Finch <fanf@demon.net> wrote:
>
>Is there a reason for disallowing concurrent read-only mounts of the
>same disk device? i.e. would things go pear-shaped if I added this
>capability? 

Well, in the absence of any comments I hacked around a bit and ended
up with the following patch (against 3.3-RC), which permits the same
block device to be mounted read-only more than once. The motivation
for this is to permit multiple chrooted environments to share the same
/usr partition.

Some things I wonder about this change is whether the mounts will share
the same pages in the buffer cache, and whether the resource
accounting is still right. I've subtly funted the meaning of
v_specmountpoint when multiple mounts happen; does this matter?

Tony.
-- 
f.a.n.finch    dot@dotat.at    fanf@demon.net    e pluribus unix


--- /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 17:08:23 1999
@@ -586,28 +586,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 +627,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 +731,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 +844,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);
 


To Unsubscribe: send mail to majordomo@FreeBSD.org
with "unsubscribe freebsd-hackers" in the body of the message




Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?E11QZ03-000DDr-00>