X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/2309ea70a8f2b2ad6ab999f0b313fa826440bb6b..1c26e003994596967e39011851eb9b6122d2af5c:/usr/src/sys/ufs/lfs/lfs_vfsops.c diff --git a/usr/src/sys/ufs/lfs/lfs_vfsops.c b/usr/src/sys/ufs/lfs/lfs_vfsops.c index 3d336925df..c264471464 100644 --- a/usr/src/sys/ufs/lfs/lfs_vfsops.c +++ b/usr/src/sys/ufs/lfs/lfs_vfsops.c @@ -2,35 +2,26 @@ * 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.27 (Berkeley) %G% + * @(#)lfs_vfsops.c 7.50 (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" @@ -45,6 +36,7 @@ int ufs_mount(); int ufs_start(); int ufs_unmount(); int ufs_root(); +int ufs_quotactl(); int ufs_statfs(); int ufs_sync(); int ufs_fhtovp(); @@ -56,6 +48,7 @@ struct vfsops ufs_vfsops = { ufs_start, ufs_unmount, ufs_root, + ufs_quotactl, ufs_statfs, ufs_sync, ufs_fhtovp, @@ -63,11 +56,6 @@ struct vfsops ufs_vfsops = { ufs_init }; -/* - * ufs mount table. - */ -struct ufsmount mounttab[NMOUNT]; - /* * Called by vfs_mountroot when ufs is going to be mounted as root. * @@ -86,10 +74,10 @@ ufs_mountroot() mp = (struct mount *)malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); - mp->m_op = &ufs_vfsops; - mp->m_flag = 0; - 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); @@ -101,15 +89,19 @@ ufs_mountroot() 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] = '/'; - bzero(fs->fs_fsmnt + 1, sizeof(fs->fs_fsmnt) - 1); - (void) copystr(ROOTNAME, ump->um_mntname, MNAMELEN - 1, &size); - bzero(ump->um_mntname + size, MNAMELEN - size); + 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); @@ -121,7 +113,7 @@ ufs_mountroot() * mount system call */ ufs_mount(mp, path, data, ndp) - struct mount *mp; + register struct mount *mp; char *path; caddr_t data; struct nameidata *ndp; @@ -135,21 +127,41 @@ ufs_mount(mp, path, data, ndp) if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) return (error); - if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) - return (error); - if ((mp->m_flag & M_UPDATE) == 0) { + /* + * Process export requests. + */ + if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { + if (args.exflags & MNT_EXPORTED) + mp->mnt_flag |= MNT_EXPORTED; + else + mp->mnt_flag &= ~MNT_EXPORTED; + if (args.exflags & MNT_EXRDONLY) + mp->mnt_flag |= MNT_EXRDONLY; + else + 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 { 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 * is really being used for the root file system. */ + if (args.fspec == 0) + return (0); + if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) + return (error); if (devvp != ump->um_devvp) error = EINVAL; /* needs translation */ + else + vrele(devvp); } if (error) { vrele(devvp); @@ -159,8 +171,12 @@ ufs_mount(mp, path, data, ndp) 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); - (void) copyinstr(args.fspec, ump->um_mntname, MNAMELEN - 1, &size); - bzero(ump->um_mntname + size, MNAMELEN - size); + 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); } @@ -168,11 +184,10 @@ ufs_mount(mp, path, data, ndp) * Common code for mount and mountroot */ mountfs(devvp, mp) - struct vnode *devvp; + register struct vnode *devvp; struct mount *mp; { - register struct ufsmount *ump; - struct ufsmount *fmp = NULL; + register struct ufsmount *ump = (struct ufsmount *)0; struct buf *bp = NULL; register struct fs *fs; dev_t dev = devvp->v_rdev; @@ -182,42 +197,31 @@ mountfs(devvp, mp) int havepart = 0, blks; int error, i, size; int needclose = 0; - int ronly = (mp->m_flag & M_RDONLY) != 0; - - for (ump = &mounttab[0]; ump < &mounttab[NMOUNT]; ump++) { - if (ump->um_fs == NULL) { - if (fmp == NULL) - fmp = ump; - } else if (dev == ump->um_dev) { - return (EBUSY); /* needs translation */ - } - } - (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE, - S_IFBLK); - if (error) { - ump->um_fs = NULL; + int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; + extern struct vnode *rootvp; + + 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, (u_int)fs->fs_sbsize); + if (fs->fs_sbsize < SBSIZE) + bp->b_flags |= B_INVAL; brelse(bp); bp = NULL; fs = ump->um_fs; @@ -278,16 +282,16 @@ mountfs(devvp, mp) brelse(bp); bp = NULL; } - mp->m_data = (qaddr_t)ump; - mp->m_bsize = fs->fs_bsize; - mp->m_fsize = fs->fs_fsize; - mp->m_fsid.val[0] = (long)dev; - mp->m_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_mount = mp; + 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 */ @@ -297,14 +301,15 @@ mountfs(devvp, mp) 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); } @@ -324,30 +329,42 @@ ufs_start(mp, flags) /* * 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); - if (error = vflush(mp, ITOV(ump->um_qinod), flags)) return (error); #ifdef QUOTA - (void) closedq(ump); - /* - * A drag, but it would be ugly to cheat, & this doesn't happen often. - */ - if (vflush(mp, (struct vnode *)NULL, MNT_NOFORCE)) - panic("ufs_unmount: quota"); + if (mp->mnt_flag & MNT_QUOTA) { + if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) + return (error); + for (i = 0; i < MAXQUOTAS; i++) { + if (ump->um_quotas[i] == NULLVP) + continue; + quotaoff(mp, i); + } + /* + * Here we fall through to vflush again to ensure + * that we have gotten rid of all the system vnodes. + */ + } #endif + 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); @@ -376,6 +393,77 @@ ufs_root(mp, vpp) 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. */ @@ -400,9 +488,12 @@ ufs_statfs(mp, sbp) (fs->fs_dsize - sbp->f_bfree); sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; sbp->f_ffree = fs->fs_cstotal.cs_nifree; - bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)&sbp->f_mntonname[0], MNAMELEN); - bcopy((caddr_t)ump->um_mntname, (caddr_t)&sbp->f_mntfromname[0], - MNAMELEN); + if (sbp != &mp->mnt_stat) { + bcopy((caddr_t)mp->mnt_stat.f_mntonname, + (caddr_t)&sbp->f_mntonname[0], MNAMELEN); + bcopy((caddr_t)mp->mnt_stat.f_mntfromname, + (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); + } return (0); } @@ -412,6 +503,8 @@ int syncprt = 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; @@ -421,17 +514,11 @@ ufs_sync(mp, waitfor) register struct inode *ip; register struct ufsmount *ump = VFSTOUFS(mp); register struct fs *fs; - int error = 0; - static int updlock = 0; + int error, allerror = 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 @@ -444,27 +531,40 @@ ufs_sync(mp, waitfor) } fs->fs_fmod = 0; fs->fs_time = time.tv_sec; - error = sbupdate(ump, waitfor); + allerror = sbupdate(ump, waitfor); } /* * Write back each (modified) inode. */ - for (vp = mp->m_mounth; vp; vp = vp->v_mountf) { +loop: + 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 & ILOCKED) != 0 || ITOV(ip)->v_count == 0 || - (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) + if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && + vp->v_dirtyblkhd == NULL) continue; - ILOCK(ip); - VREF(vp); - error = iupdat(ip, &time, &time, waitfor == MNT_WAIT); - iput(ip); + if (vget(vp)) + goto loop; + if (vp->v_dirtyblkhd) + vflushbuf(vp, 0); + if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && + (error = iupdat(ip, &time, &time, 0))) + allerror = error; + vput(vp); } - updlock = 0; /* - * Force stale buffer cache information to be flushed. + * Force stale file system control information to be flushed. */ - bflush(ump->um_devvp->v_mount); - return (error); + vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); +#ifdef QUOTA + qsync(mp); +#endif + return (allerror); } /* @@ -578,7 +678,7 @@ ufs_fhtovp(mp, fhp, vpp) 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; @@ -586,18 +686,18 @@ ufs_fhtovp(mp, fhp, vpp) 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); @@ -623,7 +723,6 @@ ufs_vptofh(vp, fhp) } /* - * 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. */ @@ -635,22 +734,20 @@ getmdev(devvpp, fname, ndp) 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) + if (major(vp->v_rdev) >= nblkdev) { + vrele(vp); return (ENXIO); - iunlock(VTOI(vp)); + } *devvpp = vp; return (0); }