Tony Finch <f...@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    d...@dotat.at    f...@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 majord...@freebsd.org
with "unsubscribe freebsd-hackers" in the body of the message

Reply via email to