* Copyright (c) 1989 The Regents of the University of California.
* All rights reserved.
*
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley. The name of the
- * University may not 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.
+ * %sccs.include.redist.c%
*
- * @(#)lfs_vfsops.c 7.37 (Berkeley) %G%
+ * @(#)lfs_vfsops.c 7.49 (Berkeley) %G%
*/
#include "param.h"
#include "systm.h"
-#include "time.h"
+#include "user.h"
+#include "proc.h"
#include "kernel.h"
-#include "namei.h"
#include "vnode.h"
+#include "specdev.h"
#include "mount.h"
#include "buf.h"
-#include "ucred.h"
#include "file.h"
#include "disklabel.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"
int ufs_start();
int ufs_unmount();
int ufs_root();
+int ufs_quotactl();
int ufs_statfs();
int ufs_sync();
int ufs_fhtovp();
ufs_start,
ufs_unmount,
ufs_root,
+ ufs_quotactl,
ufs_statfs,
ufs_sync,
ufs_fhtovp,
ufs_init
};
-/*
- * ufs mount table.
- */
-struct ufsmount mounttab[NMOUNT];
-
/*
* Called by vfs_mountroot when ufs is going to be mounted as root.
*
mp = (struct mount *)malloc((u_long)sizeof(struct mount),
M_MOUNT, M_WAITOK);
- mp->m_op = &ufs_vfsops;
- mp->m_flag = M_RDONLY;
- mp->m_exroot = 0;
- mp->m_mounth = (struct vnode *)0;
+ mp->mnt_op = &ufs_vfsops;
+ mp->mnt_flag = MNT_RDONLY;
+ mp->mnt_exroot = 0;
+ mp->mnt_mounth = NULLVP;
error = mountfs(rootvp, mp);
if (error) {
free((caddr_t)mp, M_MOUNT);
return (error);
}
rootfs = mp;
- mp->m_next = mp;
- mp->m_prev = mp;
- mp->m_vnodecovered = (struct vnode *)0;
+ mp->mnt_next = mp;
+ mp->mnt_prev = mp;
+ mp->mnt_vnodecovered = NULLVP;
ump = VFSTOUFS(mp);
fs = ump->um_fs;
bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt));
fs->fs_fsmnt[0] = '/';
- bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->m_stat.f_mntonname, MNAMELEN);
- (void) copystr(ROOTNAME, mp->m_stat.f_mntfromname, MNAMELEN - 1, &size);
- bzero(mp->m_stat.f_mntfromname + size, MNAMELEN - size);
- (void) ufs_statfs(mp, &mp->m_stat);
+ bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
+ MNAMELEN);
+ (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);
vfs_unlock(mp);
inittodr(fs->fs_time);
return (0);
/*
* Process export requests.
*/
- if ((args.exflags & M_EXPORTED) || (mp->m_flag & M_EXPORTED)) {
- if (args.exflags & M_EXPORTED)
- mp->m_flag |= M_EXPORTED;
+ if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) {
+ if (args.exflags & MNT_EXPORTED)
+ mp->mnt_flag |= MNT_EXPORTED;
else
- mp->m_flag &= ~M_EXPORTED;
- if (args.exflags & M_EXRDONLY)
- mp->m_flag |= M_EXRDONLY;
+ mp->mnt_flag &= ~MNT_EXPORTED;
+ if (args.exflags & MNT_EXRDONLY)
+ mp->mnt_flag |= MNT_EXRDONLY;
else
- mp->m_flag &= ~M_EXRDONLY;
- mp->m_exroot = args.exroot;
+ mp->mnt_flag &= ~MNT_EXRDONLY;
+ mp->mnt_exroot = args.exroot;
}
- if ((mp->m_flag & M_UPDATE) == 0) {
+ if ((mp->mnt_flag & MNT_UPDATE) == 0) {
if ((error = getmdev(&devvp, args.fspec, ndp)) != 0)
return (error);
error = mountfs(devvp, mp);
} else {
ump = VFSTOUFS(mp);
fs = ump->um_fs;
- if (fs->fs_ronly && (mp->m_flag & M_RDONLY) == 0)
+ if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0)
fs->fs_ronly = 0;
/*
* Verify that the specified device is the one that
return (error);
if (devvp != ump->um_devvp)
error = EINVAL; /* needs translation */
+ else
+ vrele(devvp);
}
if (error) {
vrele(devvp);
fs = ump->um_fs;
(void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size);
bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size);
- bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->m_stat.f_mntonname, MNAMELEN);
- (void) copyinstr(args.fspec, mp->m_stat.f_mntfromname, MNAMELEN - 1,
- &size);
- bzero(mp->m_stat.f_mntfromname + size, MNAMELEN - size);
- (void) ufs_statfs(mp, &mp->m_stat);
+ bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname,
+ MNAMELEN);
+ (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);
return (0);
}
register struct vnode *devvp;
struct mount *mp;
{
- register struct ufsmount *ump;
+ register struct ufsmount *ump = (struct ufsmount *)0;
struct buf *bp = NULL;
register struct fs *fs;
dev_t dev = devvp->v_rdev;
int havepart = 0, blks;
int error, i, size;
int needclose = 0;
- int ronly = (mp->m_flag & M_RDONLY) != 0;
+ int ronly = (mp->mnt_flag & MNT_RDONLY) != 0;
- (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE,
- S_IFBLK);
- if (error) {
- ump->um_fs = NULL;
+ if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED))
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) != 0) {
size = DEV_BSIZE;
- else {
+ } else {
havepart = 1;
size = dpart.disklab->d_secsize;
}
- if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) {
- ump->um_fs = NULL;
+ if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp))
goto out;
- }
fs = bp->b_un.b_fs;
- ump->um_fs = NULL;
- error = EINVAL; /* XXX also needs translation */
+ error = EINVAL; /* XXX needs translation */
goto out;
}
+ ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK);
ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK,
M_WAITOK);
bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs,
brelse(bp);
bp = NULL;
}
- mp->m_data = (qaddr_t)ump;
- mp->m_stat.f_fsid.val[0] = (long)dev;
- mp->m_stat.f_fsid.val[1] = MOUNT_UFS;
+ mp->mnt_data = (qaddr_t)ump;
+ mp->mnt_stat.f_fsid.val[0] = (long)dev;
+ mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS;
+ mp->mnt_flag |= MNT_LOCAL;
ump->um_mountp = mp;
ump->um_dev = dev;
ump->um_devvp = devvp;
- ump->um_qinod = NULL;
- devvp->v_specinfo->si_flags |= SI_MOUNTEDON;
+ for (i = 0; i < MAXQUOTAS; i++)
+ ump->um_quotas[i] = NULLVP;
+ devvp->v_specflags |= SI_MOUNTEDON;
/* Sanity checks for old file systems. XXX */
fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */
return (0);
out:
+ if (bp)
+ brelse(bp);
if (needclose)
(void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED);
- if (ump->um_fs) {
+ if (ump) {
free((caddr_t)ump->um_fs, M_SUPERBLK);
- ump->um_fs = NULL;
+ free((caddr_t)ump, M_UFSMNT);
+ mp->mnt_data = (qaddr_t)0;
}
- if (bp)
- brelse(bp);
return (error);
}
/*
* unmount system call
*/
-ufs_unmount(mp, flags)
+ufs_unmount(mp, mntflags)
struct mount *mp;
- int flags;
+ int mntflags;
{
register struct ufsmount *ump;
register struct fs *fs;
- int error, ronly;
+ int i, error, ronly, flags = 0;
- if (flags & MNT_FORCE)
+ if (mntflags & MNT_FORCE)
return (EINVAL);
+ if (mntflags & MNT_FORCE)
+ flags |= FORCECLOSE;
mntflushbuf(mp, 0);
if (mntinvalbuf(mp))
return (EBUSY);
ump = VFSTOUFS(mp);
return (error);
#ifdef QUOTA
- if (ump->um_qinod) {
- if (error = vflush(mp, ITOV(ump->um_qinod), flags))
+ if (mp->mnt_flag & MNT_QUOTA) {
+ if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags))
return (error);
- (void) closedq(ump);
+ for (i = 0; i < MAXQUOTAS; i++) {
+ if (ump->um_quotas[i] == NULLVP)
+ continue;
+ quotaoff(mp, i);
+ }
/*
- * Here we have to vflush again to get rid of the quota inode.
- * A drag, but it would be ugly to cheat, and this system
- * call does not happen often.
+ * Here we fall through to vflush again to ensure
+ * that we have gotten rid of all the system vnodes.
*/
- if (vflush(mp, (struct vnode *)NULL, MNT_NOFORCE))
- panic("ufs_unmount: quota");
- } else
+ }
#endif
- if (error = vflush(mp, (struct vnode *)NULL, flags))
+ if (error = vflush(mp, NULLVP, flags))
return (error);
fs = ump->um_fs;
ronly = !fs->fs_ronly;
- free((caddr_t)fs->fs_csp[0], M_SUPERBLK);
error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE);
irele(ip);
return (error);
return (0);
}
+/*
+ * Do operations associated with quotas
+ */
+ufs_quotactl(mp, cmds, uid, arg)
+ struct mount *mp;
+ int cmds;
+ uid_t uid;
+ caddr_t arg;
+{
+ register struct nameidata *ndp = &u.u_nd;
+ struct ufsmount *ump = VFSTOUFS(mp);
+ struct proc *p = u.u_procp; /* XXX */
+ int cmd, type, error;
+
+#ifndef QUOTA
+ return (EOPNOTSUPP);
+#else
+ if (uid == -1)
+ uid = p->p_ruid;
+ cmd = cmds >> SUBCMDSHIFT;
+
+ switch (cmd) {
+ case Q_GETQUOTA:
+ case Q_SYNC:
+ if (uid == p->p_ruid)
+ break;
+ /* fall through */
+ default:
+ if (error = suser(ndp->ni_cred, &u.u_acflag))
+ return (error);
+ }
+
+ type = cmd & SUBCMDMASK;
+ if ((u_int)type >= MAXQUOTAS)
+ return (EINVAL);
+
+ switch (cmd) {
+
+ case Q_QUOTAON:
+ return (quotaon(ndp, mp, type, arg));
+
+ case Q_QUOTAOFF:
+ if (vfs_busy(mp))
+ return (0);
+ error = quotaoff(mp, type);
+ vfs_unbusy(mp);
+ return (error);
+
+ case Q_SETQUOTA:
+ return (setquota(mp, uid, type, arg));
+
+ case Q_SETUSE:
+ return (setuse(mp, uid, type, arg));
+
+ case Q_GETQUOTA:
+ return (getquota(mp, uid, type, arg));
+
+ case Q_SYNC:
+ if (vfs_busy(mp))
+ return (0);
+ error = qsync(mp);
+ vfs_unbusy(mp);
+ return (error);
+
+ default:
+ return (EINVAL);
+ }
+ /* NOTREACHED */
+#endif
+}
+
/*
* Get file system statistics.
*/
(fs->fs_dsize - sbp->f_bfree);
sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO;
sbp->f_ffree = fs->fs_cstotal.cs_nifree;
- if (sbp != &mp->m_stat) {
- bcopy((caddr_t)mp->m_stat.f_mntonname,
+ if (sbp != &mp->mnt_stat) {
+ bcopy((caddr_t)mp->mnt_stat.f_mntonname,
(caddr_t)&sbp->f_mntonname[0], MNAMELEN);
- bcopy((caddr_t)mp->m_stat.f_mntfromname,
+ bcopy((caddr_t)mp->mnt_stat.f_mntfromname,
(caddr_t)&sbp->f_mntfromname[0], MNAMELEN);
}
return (0);
* Go through the disk queues to initiate sandbagged IO;
* go through the inodes to write those that have been modified;
* initiate the writing of the super block if it has been modified.
+ *
+ * Note: we are always called with the filesystem marked `MPBUSY'.
*/
ufs_sync(mp, waitfor)
struct mount *mp;
register struct inode *ip;
register struct ufsmount *ump = VFSTOUFS(mp);
register struct fs *fs;
- struct vnode *nvp;
int error, allerror = 0;
- static int updlock = 0;
if (syncprt)
bufstats();
- if (updlock)
- return (EBUSY);
fs = ump->um_fs;
- if (fs == (struct fs *)1)
- return (0);
- updlock++;
/*
* Write back modified superblock.
* Consistency check that the superblock
}
fs->fs_fmod = 0;
fs->fs_time = time.tv_sec;
- error = sbupdate(ump, waitfor);
+ allerror = sbupdate(ump, waitfor);
}
/*
* Write back each (modified) inode.
*/
loop:
- for (vp = mp->m_mounth; vp; vp = nvp) {
- nvp = vp->v_mountf;
+ for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) {
+ /*
+ * If the vnode that we are about to sync is no longer
+ * associated with this mount point, start over.
+ */
+ if (vp->v_mount != mp)
+ goto loop;
ip = VTOI(vp);
if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 &&
vp->v_dirtyblkhd == NULL)
allerror = error;
vput(vp);
}
- updlock = 0;
/*
* Force stale file system control information to be flushed.
*/
vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0);
+#ifdef QUOTA
+ qsync(mp);
+#endif
return (allerror);
}
fs = VFSTOUFS(mp)->um_fs;
if (ufhp->ufid_ino < ROOTINO ||
ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) {
- *vpp = (struct vnode *)0;
+ *vpp = NULLVP;
return (EINVAL);
}
tvp.v_mount = mp;
ip->i_vnode = &tvp;
ip->i_dev = VFSTOUFS(mp)->um_dev;
if (error = iget(ip, ufhp->ufid_ino, &nip)) {
- *vpp = (struct vnode *)0;
+ *vpp = NULLVP;
return (error);
}
ip = nip;
if (ip->i_mode == 0) {
iput(ip);
- *vpp = (struct vnode *)0;
+ *vpp = NULLVP;
return (EINVAL);
}
if (ip->i_gen != ufhp->ufid_gen) {
iput(ip);
- *vpp = (struct vnode *)0;
+ *vpp = NULLVP;
return (EINVAL);
}
*vpp = ITOV(ip);
}
/*
- * Common code for mount and quota.
* Check that the user's argument is a reasonable
* thing on which to mount, and return the device number if so.
*/
register struct vnode *vp;
int error;
- ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW;
+ ndp->ni_nameiop = LOOKUP | FOLLOW;
ndp->ni_segflg = UIO_USERSPACE;
ndp->ni_dirp = fname;
- if (error = namei(ndp)) {
- if (error == ENOENT)
- return (ENODEV); /* needs translation */
+ if (error = namei(ndp))
return (error);
- }
vp = ndp->ni_vp;
if (vp->v_type != VBLK) {
- vput(vp);
+ vrele(vp);
return (ENOTBLK);
}
if (major(vp->v_rdev) >= nblkdev) {
- vput(vp);
+ vrele(vp);
return (ENXIO);
}
- iunlock(VTOI(vp));
*devvpp = vp;
return (0);
}