BSD 4_3_Net_2 release
[unix-history] / usr / src / sys / ufs / ufs_vfsops.c
index 200b352..150c974 100644 (file)
@@ -1,27 +1,41 @@
 /*
 /*
- * Copyright (c) 1989 The Regents of the University of California.
+ * Copyright (c) 1989, 1991 The Regents of the University of California.
  * All rights reserved.
  *
  * All rights reserved.
  *
- * Redistribution and use in source and binary forms are permitted provided
- * that: (1) source distributions retain this entire copyright notice and
- * comment, and (2) distributions including binaries display the following
- * acknowledgement:  ``This product includes software developed by the
- * University of California, Berkeley and its contributors'' in the
- * documentation or other materials provided with the distribution and in
- * all advertising materials mentioning features or use of this software.
- * Neither the name of the University nor the names of its contributors may
- * be used to endorse or promote products derived from this software without
- * specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *     This product includes software developed by the University of
+ *     California, Berkeley and its contributors.
+ * 4. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
  *
  *
- *     @(#)ufs_vfsops.c        7.50 (Berkeley) 11/28/90
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ *     @(#)ufs_vfsops.c        7.56 (Berkeley) 6/28/91
  */
 
 #include "param.h"
 #include "systm.h"
  */
 
 #include "param.h"
 #include "systm.h"
-#include "user.h"
+#include "namei.h"
 #include "proc.h"
 #include "kernel.h"
 #include "vnode.h"
 #include "proc.h"
 #include "kernel.h"
 #include "vnode.h"
 #include "ioctl.h"
 #include "errno.h"
 #include "malloc.h"
 #include "ioctl.h"
 #include "errno.h"
 #include "malloc.h"
-#include "../ufs/quota.h"
-#include "../ufs/fs.h"
-#include "../ufs/ufsmount.h"
-#include "../ufs/inode.h"
 
 
-/*
- * ufs vfs operations.
- */
-int ufs_mount();
-int ufs_start();
-int ufs_unmount();
-int ufs_root();
-int ufs_quotactl();
-int ufs_statfs();
-int ufs_sync();
-int ufs_fhtovp();
-int ufs_vptofh();
-int ufs_init();
+#include "quota.h"
+#include "fs.h"
+#include "ufsmount.h"
+#include "inode.h"
 
 struct vfsops ufs_vfsops = {
        ufs_mount,
 
 struct vfsops ufs_vfsops = {
        ufs_mount,
@@ -65,6 +66,11 @@ struct vfsops ufs_vfsops = {
        ufs_init
 };
 
        ufs_init
 };
 
+/*
+ * Flag to allow forcible unmounting.
+ */
+int doforce = 1;
+
 /*
  * Called by vfs_mountroot when ufs is going to be mounted as root.
  *
 /*
  * Called by vfs_mountroot when ufs is going to be mounted as root.
  *
@@ -76,6 +82,7 @@ ufs_mountroot()
 {
        register struct mount *mp;
        extern struct vnode *rootvp;
 {
        register struct mount *mp;
        extern struct vnode *rootvp;
+       struct proc *p = curproc;       /* XXX */
        struct ufsmount *ump;
        register struct fs *fs;
        u_int size;
        struct ufsmount *ump;
        register struct fs *fs;
        u_int size;
@@ -87,13 +94,13 @@ ufs_mountroot()
        mp->mnt_flag = MNT_RDONLY;
        mp->mnt_exroot = 0;
        mp->mnt_mounth = NULLVP;
        mp->mnt_flag = MNT_RDONLY;
        mp->mnt_exroot = 0;
        mp->mnt_mounth = NULLVP;
-       error = mountfs(rootvp, mp);
+       error = mountfs(rootvp, mp, p);
        if (error) {
                free((caddr_t)mp, M_MOUNT);
                return (error);
        }
        if (error = vfs_lock(mp)) {
        if (error) {
                free((caddr_t)mp, M_MOUNT);
                return (error);
        }
        if (error = vfs_lock(mp)) {
-               (void)ufs_unmount(mp, 0);
+               (void)ufs_unmount(mp, 0, p);
                free((caddr_t)mp, M_MOUNT);
                return (error);
        }
                free((caddr_t)mp, M_MOUNT);
                return (error);
        }
@@ -110,7 +117,7 @@ ufs_mountroot()
        (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
            &size);
        bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
        (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1,
            &size);
        bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
-       (void) ufs_statfs(mp, &mp->mnt_stat);
+       (void) ufs_statfs(mp, &mp->mnt_stat, p);
        vfs_unlock(mp);
        inittodr(fs->fs_time);
        return (0);
        vfs_unlock(mp);
        inittodr(fs->fs_time);
        return (0);
@@ -121,11 +128,12 @@ ufs_mountroot()
  *
  * mount system call
  */
  *
  * mount system call
  */
-ufs_mount(mp, path, data, ndp)
+ufs_mount(mp, path, data, ndp, p)
        register struct mount *mp;
        char *path;
        caddr_t data;
        struct nameidata *ndp;
        register struct mount *mp;
        char *path;
        caddr_t data;
        struct nameidata *ndp;
+       struct proc *p;
 {
        struct vnode *devvp;
        struct ufs_args args;
 {
        struct vnode *devvp;
        struct ufs_args args;
@@ -150,23 +158,39 @@ ufs_mount(mp, path, data, ndp)
                        mp->mnt_flag &= ~MNT_EXRDONLY;
                mp->mnt_exroot = args.exroot;
        }
                        mp->mnt_flag &= ~MNT_EXRDONLY;
                mp->mnt_exroot = args.exroot;
        }
-       if ((mp->mnt_flag & MNT_UPDATE) == 0) {
-               if ((error = getmdev(&devvp, args.fspec, ndp)) != 0)
-                       return (error);
-               error = mountfs(devvp, mp);
-       } else {
+       /*
+        * If updating, check whether changing from read-only to
+        * read/write; if there is no device name, that's all we do.
+        */
+       if (mp->mnt_flag & MNT_UPDATE) {
                ump = VFSTOUFS(mp);
                fs = ump->um_fs;
                if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
                        fs->fs_ronly = 0;
                ump = VFSTOUFS(mp);
                fs = ump->um_fs;
                if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
                        fs->fs_ronly = 0;
-               /*
-                * Verify that the specified device is the one that
-                * is really being used for the root file system.
-                */
                if (args.fspec == 0)
                        return (0);
                if (args.fspec == 0)
                        return (0);
-               if ((error = getmdev(&devvp, args.fspec, ndp)) != 0)
-                       return (error);
+       }
+       /*
+        * Not an update, or updating the name: look up the name
+        * and verify that it refers to a sensible block device.
+        */
+       ndp->ni_nameiop = LOOKUP | FOLLOW;
+       ndp->ni_segflg = UIO_USERSPACE;
+       ndp->ni_dirp = args.fspec;
+       if (error = namei(ndp, p))
+               return (error);
+       devvp = ndp->ni_vp;
+       if (devvp->v_type != VBLK) {
+               vrele(devvp);
+               return (ENOTBLK);
+       }
+       if (major(devvp->v_rdev) >= nblkdev) {
+               vrele(devvp);
+               return (ENXIO);
+       }
+       if ((mp->mnt_flag & MNT_UPDATE) == 0)
+               error = mountfs(devvp, mp, p);
+       else {
                if (devvp != ump->um_devvp)
                        error = EINVAL; /* needs translation */
                else
                if (devvp != ump->um_devvp)
                        error = EINVAL; /* needs translation */
                else
@@ -185,16 +209,17 @@ ufs_mount(mp, path, data, ndp)
        (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 
            &size);
        bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
        (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 
            &size);
        bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size);
-       (void) ufs_statfs(mp, &mp->mnt_stat);
+       (void) ufs_statfs(mp, &mp->mnt_stat, p);
        return (0);
 }
 
 /*
  * Common code for mount and mountroot
  */
        return (0);
 }
 
 /*
  * Common code for mount and mountroot
  */
-mountfs(devvp, mp)
+mountfs(devvp, mp, p)
        register struct vnode *devvp;
        struct mount *mp;
        register struct vnode *devvp;
        struct mount *mp;
+       struct proc *p;
 {
        register struct ufsmount *ump = (struct ufsmount *)0;
        struct buf *bp = NULL;
 {
        register struct ufsmount *ump = (struct ufsmount *)0;
        struct buf *bp = NULL;
@@ -219,12 +244,12 @@ mountfs(devvp, mp)
        if (vcount(devvp) > 1 && devvp != rootvp)
                return (EBUSY);
        vinvalbuf(devvp, 1);
        if (vcount(devvp) > 1 && devvp != rootvp)
                return (EBUSY);
        vinvalbuf(devvp, 1);
-       if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED))
+       if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p))
                return (error);
        needclose = 1;
                return (error);
        needclose = 1;
-       if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED) != 0) {
+       if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0)
                size = DEV_BSIZE;
                size = DEV_BSIZE;
-       else {
+       else {
                havepart = 1;
                size = dpart.disklab->d_secsize;
        }
                havepart = 1;
                size = dpart.disklab->d_secsize;
        }
@@ -295,7 +320,7 @@ out:
        if (bp)
                brelse(bp);
        if (needclose)
        if (bp)
                brelse(bp);
        if (needclose)
-               (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED);
+               (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p);
        if (ump) {
                free((caddr_t)ump->um_fs, M_SUPERBLK);
                free((caddr_t)ump, M_UFSMNT);
        if (ump) {
                free((caddr_t)ump->um_fs, M_SUPERBLK);
                free((caddr_t)ump, M_UFSMNT);
@@ -309,9 +334,10 @@ out:
  * Nothing to do at the moment.
  */
 /* ARGSUSED */
  * Nothing to do at the moment.
  */
 /* ARGSUSED */
-ufs_start(mp, flags)
+ufs_start(mp, flags, p)
        struct mount *mp;
        int flags;
        struct mount *mp;
        int flags;
+       struct proc *p;
 {
 
        return (0);
 {
 
        return (0);
@@ -320,18 +346,20 @@ ufs_start(mp, flags)
 /*
  * unmount system call
  */
 /*
  * unmount system call
  */
-ufs_unmount(mp, mntflags)
+ufs_unmount(mp, mntflags, p)
        struct mount *mp;
        int mntflags;
        struct mount *mp;
        int mntflags;
+       struct proc *p;
 {
        register struct ufsmount *ump;
        register struct fs *fs;
        int i, error, ronly, flags = 0;
 
 {
        register struct ufsmount *ump;
        register struct fs *fs;
        int i, error, ronly, flags = 0;
 
-       if (mntflags & MNT_FORCE)
-               return (EINVAL);
-       if (mntflags & MNT_FORCE)
+       if (mntflags & MNT_FORCE) {
+               if (!doforce || mp == rootfs)
+                       return (EINVAL);
                flags |= FORCECLOSE;
                flags |= FORCECLOSE;
+       }
        mntflushbuf(mp, 0);
        if (mntinvalbuf(mp))
                return (EBUSY);
        mntflushbuf(mp, 0);
        if (mntinvalbuf(mp))
                return (EBUSY);
@@ -343,7 +371,7 @@ ufs_unmount(mp, mntflags)
                for (i = 0; i < MAXQUOTAS; i++) {
                        if (ump->um_quotas[i] == NULLVP)
                                continue;
                for (i = 0; i < MAXQUOTAS; i++) {
                        if (ump->um_quotas[i] == NULLVP)
                                continue;
-                       quotaoff(mp, i);
+                       quotaoff(p, mp, i);
                }
                /*
                 * Here we fall through to vflush again to ensure
                }
                /*
                 * Here we fall through to vflush again to ensure
@@ -356,7 +384,8 @@ ufs_unmount(mp, mntflags)
        fs = ump->um_fs;
        ronly = !fs->fs_ronly;
        ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
        fs = ump->um_fs;
        ronly = !fs->fs_ronly;
        ump->um_devvp->v_specflags &= ~SI_MOUNTEDON;
-       error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED);
+       error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE,
+               NOCRED, p);
        vrele(ump->um_devvp);
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
        free((caddr_t)fs, M_SUPERBLK);
        vrele(ump->um_devvp);
        free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
        free((caddr_t)fs, M_SUPERBLK);
@@ -414,32 +443,31 @@ ufs_root(mp, vpp)
 /*
  * Do operations associated with quotas
  */
 /*
  * Do operations associated with quotas
  */
-ufs_quotactl(mp, cmds, uid, arg)
+ufs_quotactl(mp, cmds, uid, arg, p)
        struct mount *mp;
        int cmds;
        uid_t uid;
        caddr_t arg;
        struct mount *mp;
        int cmds;
        uid_t uid;
        caddr_t arg;
+       struct proc *p;
 {
 {
-       register struct nameidata *ndp = &u.u_nd;
        struct ufsmount *ump = VFSTOUFS(mp);
        struct ufsmount *ump = VFSTOUFS(mp);
-       struct proc *p = u.u_procp;     /* XXX */
        int cmd, type, error;
 
 #ifndef QUOTA
        return (EOPNOTSUPP);
 #else
        if (uid == -1)
        int cmd, type, error;
 
 #ifndef QUOTA
        return (EOPNOTSUPP);
 #else
        if (uid == -1)
-               uid = p->p_ruid;
+               uid = p->p_cred->p_ruid;
        cmd = cmds >> SUBCMDSHIFT;
 
        switch (cmd) {
        case Q_GETQUOTA:
        case Q_SYNC:
        cmd = cmds >> SUBCMDSHIFT;
 
        switch (cmd) {
        case Q_GETQUOTA:
        case Q_SYNC:
-               if (uid == p->p_ruid)
+               if (uid == p->p_cred->p_ruid)
                        break;
                /* fall through */
        default:
                        break;
                /* fall through */
        default:
-               if (error = suser(ndp->ni_cred, &u.u_acflag))
+               if (error = suser(p->p_ucred, &p->p_acflag))
                        return (error);
        }
 
                        return (error);
        }
 
@@ -450,12 +478,12 @@ ufs_quotactl(mp, cmds, uid, arg)
        switch (cmd) {
 
        case Q_QUOTAON:
        switch (cmd) {
 
        case Q_QUOTAON:
-               return (quotaon(ndp, mp, type, arg));
+               return (quotaon(p, mp, type, arg));
 
        case Q_QUOTAOFF:
                if (vfs_busy(mp))
                        return (0);
 
        case Q_QUOTAOFF:
                if (vfs_busy(mp))
                        return (0);
-               error = quotaoff(mp, type);
+               error = quotaoff(p, mp, type);
                vfs_unbusy(mp);
                return (error);
 
                vfs_unbusy(mp);
                return (error);
 
@@ -485,9 +513,10 @@ ufs_quotactl(mp, cmds, uid, arg)
 /*
  * Get file system statistics.
  */
 /*
  * Get file system statistics.
  */
-ufs_statfs(mp, sbp)
+ufs_statfs(mp, sbp, p)
        struct mount *mp;
        register struct statfs *sbp;
        struct mount *mp;
        register struct statfs *sbp;
+       struct proc *p;
 {
        register struct ufsmount *ump;
        register struct fs *fs;
 {
        register struct ufsmount *ump;
        register struct fs *fs;
@@ -562,6 +591,8 @@ loop:
                 */
                if (vp->v_mount != mp)
                        goto loop;
                 */
                if (vp->v_mount != mp)
                        goto loop;
+               if (VOP_ISLOCKED(vp))
+                       continue;
                ip = VTOI(vp);
                if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
                    vp->v_dirtyblkhd == NULL)
                ip = VTOI(vp);
                if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
                    vp->v_dirtyblkhd == NULL)
@@ -722,33 +753,3 @@ ufs_vptofh(vp, fhp)
        ufhp->ufid_gen = ip->i_gen;
        return (0);
 }
        ufhp->ufid_gen = ip->i_gen;
        return (0);
 }
-
-/*
- * Check that the user's argument is a reasonable
- * thing on which to mount, and return the device number if so.
- */
-getmdev(devvpp, fname, ndp)
-       struct vnode **devvpp;
-       caddr_t fname;
-       register struct nameidata *ndp;
-{
-       register struct vnode *vp;
-       int error;
-
-       ndp->ni_nameiop = LOOKUP | FOLLOW;
-       ndp->ni_segflg = UIO_USERSPACE;
-       ndp->ni_dirp = fname;
-       if (error = namei(ndp))
-               return (error);
-       vp = ndp->ni_vp;
-       if (vp->v_type != VBLK) {
-               vrele(vp);
-               return (ENOTBLK);
-       }
-       if (major(vp->v_rdev) >= nblkdev) {
-               vrele(vp);
-               return (ENXIO);
-       }
-       *devvpp = vp;
-       return (0);
-}