--- sys/fs/msdosfs/msdosfs_vfsops.c 2005/11/19 16:40:46 +++ sys/fs/msdosfs/msdosfs_vfsops.c 2006/03/25 19:17:56 @@ -285,7 +285,7 @@ return (error); DROP_GIANT(); g_topology_lock(); - g_access(pmp->pm_cp, 0, -1, 0); + g_vfs_access(pmp->pm_cp, 0, -1, 0); g_topology_unlock(); PICKUP_GIANT(); } else if ((pmp->pm_flags & MSDOSFSMNT_RONLY) && @@ -307,7 +307,7 @@ } DROP_GIANT(); g_topology_lock(); - error = g_access(pmp->pm_cp, 0, 1, 0); + error = g_vfs_access(pmp->pm_cp, 0, 1, 0); g_topology_unlock(); PICKUP_GIANT(); if (error) --- sys/geom/geom_vfs.c 2006/03/02 05:40:19 +++ sys/geom/geom_vfs.c 2006/03/25 19:17:56 @@ -137,28 +137,43 @@ g_topology_assert(); *cpp = NULL; - pp = g_dev_getprovider(vp->v_rdev); - if (pp == NULL) - return (ENOENT); - gp = g_new_geomf(&g_vfs_class, "%s.%s", fsname, pp->name); - cp = g_new_consumer(gp); - g_attach(cp, pp); - error = g_access(cp, 1, wr, 1); - if (error) { - g_wither_geom(gp, ENXIO); - return (error); + bo = &vp->v_bufobj; + /* Is this first mount? */ + if (bo->bo_private == vp) { + pp = g_dev_getprovider(vp->v_rdev); + if (pp == NULL) + return (ENOENT); + gp = g_new_geomf(&g_vfs_class, "%s.%s", fsname, pp->name); + cp = g_new_consumer(gp); + g_attach(cp, pp); + error = g_access(cp, 1, wr, 1); + if (error) { + g_wither_geom(gp, ENXIO); + return (error); + } + cp->private = vp; + vfslocked = VFS_LOCK_GIANT(vp->v_mount); + vnode_create_vobject(vp, pp->mediasize, curthread); + VFS_UNLOCK_GIANT(vfslocked); + bo = &vp->v_bufobj; + bo->bo_ops = g_vfs_bufops; + bo->bo_private = cp; + bo->bo_bsize = pp->sectorsize; + gp->softc = bo; + } else { + cp = bo->bo_private; + /* + * Don't allow for mount when already mounted R/W. + * Don't allow for R/W mount when already mounted. + */ + if (cp->acw > 0 || wr) + return (EPERM); + error = g_access(cp, 1, wr, 1); + if (error) + return (error); } - vfslocked = VFS_LOCK_GIANT(vp->v_mount); - vnode_create_vobject(vp, pp->mediasize, curthread); - VFS_UNLOCK_GIANT(vfslocked); *cpp = cp; - bo = &vp->v_bufobj; - bo->bo_ops = g_vfs_bufops; - bo->bo_private = cp; - bo->bo_bsize = pp->sectorsize; - gp->softc = bo; - - return (error); + return (0); } void @@ -171,6 +186,32 @@ gp = cp->geom; bo = gp->softc; - bufobj_invalbuf(bo, V_SAVE, td, 0, 0); - g_wither_geom_close(gp, ENXIO); + /* Is this last close? */ + if (cp->acr == 1) { + /* + * Put device vnode back into bo_private, so we can mount this + * file system later and first mount will be detected properly. + */ + bo->bo_private = cp->private; + bufobj_invalbuf(bo, V_SAVE, td, 0, 0); + g_wither_geom_close(gp, ENXIO); + } else { + /* It could be open only for reading here. */ + KASSERT(cp->acr > 1 && cp->acw == 0 && cp->ace >= 0, + ("Invalid access for %s (r%dw%de%d).", cp->provider->name, + cp->acr, cp->acw, cp->ace)); + g_access(cp, -1, 0, -1); + } +} + +int +g_vfs_access(struct g_consumer *cp, int dcr, int dcw, int dce) +{ + + g_topology_assert(); + + /* If already mounted read-only multiple times, we cannot upgrade. */ + if (dcw > 0 && cp->acr > 1) + return (EPERM); + return (g_access(cp, dcr, dcw, dce)); } --- sys/geom/geom_vfs.h 2005/02/10 12:10:50 +++ sys/geom/geom_vfs.h 2006/03/25 19:17:56 @@ -38,5 +38,6 @@ void g_vfs_strategy(struct bufobj *bo, struct buf *bp); int g_vfs_open(struct vnode *vp, struct g_consumer **cpp, const char *fsname, int wr); void g_vfs_close(struct g_consumer *cp, struct thread *td); +int g_vfs_access(struct g_consumer *cp, int dcr, int dcw, int dce); #endif /* _GEOM_GEOM_VFS_H_ */ --- sys/gnu/fs/ext2fs/ext2_vfsops.c 2006/01/09 20:49:39 +++ sys/gnu/fs/ext2fs/ext2_vfsops.c 2006/03/25 19:17:56 @@ -182,7 +182,7 @@ vfs_flagopt(opts, "ro", &mp->mnt_flag, MNT_RDONLY); DROP_GIANT(); g_topology_lock(); - g_access(ump->um_cp, 0, -1, 0); + g_vfs_access(ump->um_cp, 0, -1, 0); g_topology_unlock(); PICKUP_GIANT(); } @@ -209,7 +209,7 @@ } DROP_GIANT(); g_topology_lock(); - error = g_access(ump->um_cp, 0, 1, 0); + error = g_vfs_access(ump->um_cp, 0, 1, 0); g_topology_unlock(); PICKUP_GIANT(); if (error) --- sys/ufs/ffs/ffs_vfsops.c 2006/03/19 22:20:45 +++ sys/ufs/ffs/ffs_vfsops.c 2006/03/25 19:17:56 @@ -243,7 +243,7 @@ vn_finished_write(mp); DROP_GIANT(); g_topology_lock(); - g_access(ump->um_cp, 0, -1, 0); + g_vfs_access(ump->um_cp, 0, -1, 0); g_topology_unlock(); PICKUP_GIANT(); fs->fs_ronly = 1; @@ -289,9 +289,9 @@ * yet, get it now. */ if (ump->um_cp->ace == 0) - error = g_access(ump->um_cp, 0, 1, 1); + error = g_vfs_access(ump->um_cp, 0, 1, 1); else - error = g_access(ump->um_cp, 0, 1, 0); + error = g_vfs_access(ump->um_cp, 0, 1, 0); g_topology_unlock(); PICKUP_GIANT(); if (error) @@ -614,7 +614,7 @@ * We will pick it up again when we remount R/W. */ if (error == 0 && ronly && (mp->mnt_flag & MNT_ROOTFS)) - error = g_access(cp, 0, 0, -1); + error = g_vfs_access(cp, 0, 0, -1); g_topology_unlock(); PICKUP_GIANT(); VOP_UNLOCK(devvp, 0, td);