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