diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -409,15 +409,84 @@ mp->mnt_kern_flag &= ~MNTK_FPLOOKUP; mp->mnt_flag |= mntorflags; MNT_IUNLOCK(mp); + + /* + * Must not call namei() while owning busy ref. + */ + if (mp->mnt_flag & MNT_UPDATE) + vfs_unbusy(mp); + + /* + * Not an update, or updating the name: look up the name + * and verify that it refers to a sensible disk device. + */ + NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec); + error = namei(&ndp); + if ((mp->mnt_flag & MNT_UPDATE) != 0) { + /* + * Unmount does not start if MNT_UPDATE is set. Mount + * update busies mp before setting MNT_UPDATE. We + * must be able to retain our busy ref successfully, + * without sleep. + */ + error1 = vfs_busy(mp, MBF_NOWAIT); + MPASS(error1 == 0); + } + if (error != 0) + return (error); + NDFREE(&ndp, NDF_ONLY_PNBUF); + if (!vn_isdisk_error(ndp.ni_vp, &error)) { + vput(ndp.ni_vp); + return (error); + } + /* - * If updating, check whether changing from read-only to - * read/write; if there is no device name, that's all we do. + * If mount by non-root, then verify that user has necessary + * permissions on the device. + */ + accmode = VREAD; + if ((mp->mnt_flag & MNT_RDONLY) == 0) + accmode |= VWRITE; + error = VOP_ACCESS(ndp.ni_vp, accmode, td->td_ucred, td); + if (error) + error = priv_check(td, PRIV_VFS_MOUNT_PERM); + if (error) { + vput(ndp.ni_vp); + return (error); + } + + /* + * New mount + * + * We need the name for the mount point (also used for + * "last mounted on") copied in. If an error occurs, + * the mount point is discarded by the upper level code. + * Note that vfs_mount_alloc() populates f_mntonname for us. */ - if (mp->mnt_flag & MNT_UPDATE) { + if ((mp->mnt_flag & MNT_UPDATE) == 0) { + if ((error = ffs_mountfs(ndp.ni_vp, mp, td)) != 0) { + vrele(ndp.ni_vp); + return (error); + } + } else { + /* + * When updating, check whether changing from read-only to + * read/write; if there is no device name, that's all we do. + */ ump = VFSTOUFS(mp); fs = ump->um_fs; odevvp = ump->um_odevvp; devvp = ump->um_devvp; + + /* + * If it's not the same vnode, or at least the same device + * then it's not correct. + */ + if (ndp.ni_vp->v_rdev != ump->um_odevvp->v_rdev) + error = EINVAL; /* needs translation */ + vput(ndp.ni_vp); + if (error) + return (error); if (fs->fs_ronly == 0 && vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0)) { /* @@ -620,79 +689,6 @@ */ if (mp->mnt_flag & MNT_SNAPSHOT) return (ffs_snapshot(mp, fspec)); - - /* - * Must not call namei() while owning busy ref. - */ - vfs_unbusy(mp); - } - - /* - * Not an update, or updating the name: look up the name - * and verify that it refers to a sensible disk device. - */ - NDINIT(&ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec); - error = namei(&ndp); - if ((mp->mnt_flag & MNT_UPDATE) != 0) { - /* - * Unmount does not start if MNT_UPDATE is set. Mount - * update busies mp before setting MNT_UPDATE. We - * must be able to retain our busy ref succesfully, - * without sleep. - */ - error1 = vfs_busy(mp, MBF_NOWAIT); - MPASS(error1 == 0); - } - if (error != 0) - return (error); - NDFREE(&ndp, NDF_ONLY_PNBUF); - devvp = ndp.ni_vp; - if (!vn_isdisk_error(devvp, &error)) { - vput(devvp); - return (error); - } - - /* - * If mount by non-root, then verify that user has necessary - * permissions on the device. - */ - accmode = VREAD; - if ((mp->mnt_flag & MNT_RDONLY) == 0) - accmode |= VWRITE; - error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); - if (error) - error = priv_check(td, PRIV_VFS_MOUNT_PERM); - if (error) { - vput(devvp); - return (error); - } - - if (mp->mnt_flag & MNT_UPDATE) { - /* - * Update only - * - * If it's not the same vnode, or at least the same device - * then it's not correct. - */ - - if (devvp->v_rdev != ump->um_devvp->v_rdev) - error = EINVAL; /* needs translation */ - vput(devvp); - if (error) - return (error); - } else { - /* - * New mount - * - * We need the name for the mount point (also used for - * "last mounted on") copied in. If an error occurs, - * the mount point is discarded by the upper level code. - * Note that vfs_mount_alloc() populates f_mntonname for us. - */ - if ((error = ffs_mountfs(devvp, mp, td)) != 0) { - vrele(devvp); - return (error); - } } MNT_ILOCK(mp);