diff options
author | Chuck Silvers <chs@FreeBSD.org> | 2020-03-06 18:41:37 +0000 |
---|---|---|
committer | Chuck Silvers <chs@FreeBSD.org> | 2020-03-06 18:41:37 +0000 |
commit | f15ccf8836d9d42b92f999dbd6c4746c9547f8a6 (patch) | |
tree | 38fe0edcbd4e53a2582d03f803e6da6ade9f1dac /sys/ufs | |
parent | 6c37d6032ed296370371f8c9f79068ba7c6a54df (diff) | |
download | src-f15ccf8836d9d42b92f999dbd6c4746c9547f8a6.tar.gz src-f15ccf8836d9d42b92f999dbd6c4746c9547f8a6.zip |
Add a new "mntfs" pseudo file system which provides private device vnodes for
file systems to safely access their disk devices, and adapt FFS to use it.
Also add a new BO_NOBUFS flag to allow enforcing that file systems using
mntfs vnodes do not accidentally use the original devfs vnode to create buffers.
Reviewed by: kib, mckusick
Approved by: imp (mentor)
Sponsored by: Netflix
Differential Revision: https://reviews.freebsd.org/D23787
Notes
Notes:
svn path=/head/; revision=358714
Diffstat (limited to 'sys/ufs')
-rw-r--r-- | sys/ufs/ffs/ffs_alloc.c | 5 | ||||
-rw-r--r-- | sys/ufs/ffs/ffs_vfsops.c | 48 | ||||
-rw-r--r-- | sys/ufs/ufs/ufsmount.h | 3 |
3 files changed, 43 insertions, 13 deletions
diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index fb270b11d912..0b8068db0da7 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -3594,6 +3594,7 @@ buffered_write(fp, uio, active_cred, flags, td) struct inode *ip; struct buf *bp; struct fs *fs; + struct ufsmount *ump; struct filedesc *fdp; int error; daddr_t lbn; @@ -3622,10 +3623,12 @@ buffered_write(fp, uio, active_cred, flags, td) return (EINVAL); } ip = VTOI(vp); - if (ITODEVVP(ip) != devvp) { + ump = ip->i_ump; + if (ump->um_odevvp != devvp) { vput(vp); return (EINVAL); } + devvp = ump->um_devvp; fs = ITOFS(ip); vput(vp); foffset_lock_uio(fp, uio, flags); diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 5051c0a11eb8..1ae7fdc6184f 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -151,7 +151,7 @@ static const char *ffs_opts[] = { "acls", "async", "noatime", "noclusterr", static int ffs_mount(struct mount *mp) { - struct vnode *devvp; + struct vnode *devvp, *odevvp; struct thread *td; struct ufsmount *ump = NULL; struct fs *fs; @@ -246,6 +246,7 @@ ffs_mount(struct mount *mp) if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOUFS(mp); fs = ump->um_fs; + odevvp = ump->um_odevvp; devvp = ump->um_devvp; if (fsckpid == -1 && ump->um_fsckpid > 0) { if ((error = ffs_flushfiles(mp, WRITECLOSE, td)) != 0 || @@ -337,16 +338,15 @@ ffs_mount(struct mount *mp) * If upgrade to read-write by non-root, then verify * that user has necessary permissions on the device. */ - vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); - error = VOP_ACCESS(devvp, VREAD | VWRITE, + vn_lock(odevvp, LK_EXCLUSIVE | LK_RETRY); + error = VOP_ACCESS(odevvp, VREAD | VWRITE, td->td_ucred, td); if (error) error = priv_check(td, PRIV_VFS_MOUNT_PERM); + VOP_UNLOCK(odevvp); if (error) { - VOP_UNLOCK(devvp); return (error); } - VOP_UNLOCK(devvp); fs->fs_flags &= ~FS_UNCLEAN; if (fs->fs_clean == 0) { fs->fs_flags |= FS_UNCLEAN; @@ -782,8 +782,8 @@ loop: * Common code for mount and mountroot */ static int -ffs_mountfs(devvp, mp, td) - struct vnode *devvp; +ffs_mountfs(odevvp, mp, td) + struct vnode *odevvp; struct mount *mp; struct thread *td; { @@ -794,6 +794,7 @@ ffs_mountfs(devvp, mp, td) struct ucred *cred; struct g_consumer *cp; struct mount *nmp; + struct vnode *devvp; int candelete, canspeedup; off_t loc; @@ -802,11 +803,13 @@ ffs_mountfs(devvp, mp, td) cred = td ? td->td_ucred : NOCRED; ronly = (mp->mnt_flag & MNT_RDONLY) != 0; + devvp = mntfs_allocvp(mp, odevvp); + VOP_UNLOCK(odevvp); KASSERT(devvp->v_type == VCHR, ("reclaimed devvp")); dev = devvp->v_rdev; if (atomic_cmpset_acq_ptr((uintptr_t *)&dev->si_mountpt, 0, (uintptr_t)mp) == 0) { - VOP_UNLOCK(devvp); + mntfs_freevp(devvp); return (EBUSY); } g_topology_lock(); @@ -814,12 +817,14 @@ ffs_mountfs(devvp, mp, td) g_topology_unlock(); if (error != 0) { atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); - VOP_UNLOCK(devvp); + mntfs_freevp(devvp); return (error); } dev_ref(dev); devvp->v_bufobj.bo_ops = &ffs_ops; - VOP_UNLOCK(devvp); + BO_LOCK(&odevvp->v_bufobj); + odevvp->v_bufobj.bo_flag |= BO_NOBUFS; + BO_UNLOCK(&odevvp->v_bufobj); if (dev->si_iosize_max != 0) mp->mnt_iosize_max = dev->si_iosize_max; if (mp->mnt_iosize_max > MAXPHYS) @@ -1020,6 +1025,7 @@ ffs_mountfs(devvp, mp, td) ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; + ump->um_odevvp = odevvp; ump->um_nindir = fs->fs_nindir; ump->um_bptrtodb = fs->fs_fsbtodb; ump->um_seqinc = fs->fs_frag; @@ -1099,7 +1105,11 @@ out: free(ump, M_UFSMNT); mp->mnt_data = NULL; } + BO_LOCK(&odevvp->v_bufobj); + odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS; + BO_UNLOCK(&odevvp->v_bufobj); atomic_store_rel_ptr((uintptr_t *)&dev->si_mountpt, 0); + mntfs_freevp(devvp); dev_rel(dev); return (error); } @@ -1304,8 +1314,12 @@ ffs_unmount(mp, mntflags) } g_vfs_close(ump->um_cp); g_topology_unlock(); + BO_LOCK(&ump->um_odevvp->v_bufobj); + ump->um_odevvp->v_bufobj.bo_flag &= ~BO_NOBUFS; + BO_UNLOCK(&ump->um_odevvp->v_bufobj); atomic_store_rel_ptr((uintptr_t *)&ump->um_dev->si_mountpt, 0); - vrele(ump->um_devvp); + mntfs_freevp(ump->um_devvp); + vrele(ump->um_odevvp); dev_rel(ump->um_dev); mtx_destroy(UFS_MTX(ump)); if (mp->mnt_gjprovider != NULL) { @@ -2293,7 +2307,19 @@ ffs_geom_strategy(struct bufobj *bo, struct buf *bp) struct buf *tbp; int error, nocopy; + /* + * This is the bufobj strategy for the private VCHR vnodes + * used by FFS to access the underlying storage device. + * We override the default bufobj strategy and thus bypass + * VOP_STRATEGY() for these vnodes. + */ vp = bo2vnode(bo); + KASSERT(bp->b_vp == NULL || bp->b_vp->v_type != VCHR || + bp->b_vp->v_rdev == NULL || + bp->b_vp->v_rdev->si_mountpt == NULL || + VFSTOUFS(bp->b_vp->v_rdev->si_mountpt) == NULL || + vp == VFSTOUFS(bp->b_vp->v_rdev->si_mountpt)->um_devvp, + ("ffs_geom_strategy() with wrong vp")); if (bp->b_iocmd == BIO_WRITE) { if ((bp->b_flags & B_VALIDSUSPWRT) == 0 && bp->b_vp != NULL && bp->b_vp->v_mount != NULL && diff --git a/sys/ufs/ufs/ufsmount.h b/sys/ufs/ufs/ufsmount.h index 493571442d67..2d669338f98c 100644 --- a/sys/ufs/ufs/ufsmount.h +++ b/sys/ufs/ufs/ufsmount.h @@ -83,7 +83,8 @@ struct ufsmount { struct cdev *um_dev; /* (r) device mounted */ struct g_consumer *um_cp; /* (r) GEOM access point */ struct bufobj *um_bo; /* (r) Buffer cache object */ - struct vnode *um_devvp; /* (r) blk dev mounted vnode */ + struct vnode *um_odevvp; /* (r) devfs dev vnode */ + struct vnode *um_devvp; /* (r) mntfs private vnode */ u_long um_fstype; /* (c) type of filesystem */ struct fs *um_fs; /* (r) pointer to superblock */ struct ufs_extattr_per_mount um_extattr; /* (c) extended attrs */ |