X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/71e4e98b7a314b1e09b7f602b2a20bccf03a62ad..b702c21db8cef3072e2845d46ab411775f9ec58c:/usr/src/sys/ufs/ffs/ffs_vfsops.c diff --git a/usr/src/sys/ufs/ffs/ffs_vfsops.c b/usr/src/sys/ufs/ffs/ffs_vfsops.c index 23d8546729..6ab1f3ada4 100644 --- a/usr/src/sys/ufs/ffs/ffs_vfsops.c +++ b/usr/src/sys/ufs/ffs/ffs_vfsops.c @@ -1,251 +1,752 @@ -/* ffs_vfsops.c 4.1 83/05/27 */ - -#include "../h/param.h" -#include "../h/systm.h" -#include "../h/dir.h" -#include "../h/user.h" -#include "../h/inode.h" -#include "../h/proc.h" -#include "../h/fs.h" -#include "../h/buf.h" -#include "../h/mount.h" -#include "../h/file.h" -#include "../h/nami.h" -#include "../h/conf.h" - -smount() +/* + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. + * + * %sccs.include.redist.c% + * + * @(#)ffs_vfsops.c 7.49 (Berkeley) %G% + */ + +#include "param.h" +#include "systm.h" +#include "user.h" +#include "proc.h" +#include "kernel.h" +#include "vnode.h" +#include "specdev.h" +#include "mount.h" +#include "buf.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" +#include "ioctl.h" +#include "disklabel.h" +#include "stat.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(); + +struct vfsops ufs_vfsops = { + ufs_mount, + ufs_start, + ufs_unmount, + ufs_root, + ufs_quotactl, + ufs_statfs, + ufs_sync, + ufs_fhtovp, + ufs_vptofh, + ufs_init +}; + +/* + * Called by vfs_mountroot when ufs is going to be mounted as root. + * + * Name is updated by mount(8) after booting. + */ +#define ROOTNAME "root_device" + +ufs_mountroot() { - register struct a { - char *fspec; - char *freg; - int ronly; - } *uap; - dev_t dev; - register struct inode *ip; + register struct mount *mp; + extern struct vnode *rootvp; + struct ufsmount *ump; register struct fs *fs; - register char *cp; - - uap = (struct a *)u.u_ap; - u.u_error = getmdev(&dev); - if (u.u_error) - return; - u.u_dirp = (caddr_t)uap->freg; - ip = namei(uchar, LOOKUP, 1); - if (ip == NULL) - return; - if (ip->i_count!=1 || (ip->i_mode&IFMT) != IFDIR) { - iput(ip); - u.u_error = EBUSY; - return; - } - fs = mountfs(dev, uap->ronly, ip); - if (fs == 0) - return; - u.u_dirp = uap->freg; - for (cp = fs->fs_fsmnt; cp < &fs->fs_fsmnt[sizeof(fs->fs_fsmnt) - 2]; ) - if ((*cp++ = uchar()) == 0) - u.u_dirp--; /* get 0 again */ - *cp = 0; + u_int size; + int error; + + mp = (struct mount *)malloc((u_long)sizeof(struct mount), + M_MOUNT, M_WAITOK); + 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); + } + if (error = vfs_lock(mp)) { + (void)ufs_unmount(mp, 0); + free((caddr_t)mp, M_MOUNT); + return (error); + } + rootfs = mp; + 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->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); +} + +/* + * VFS Operations. + * + * mount system call + */ +ufs_mount(mp, path, data, ndp) + register struct mount *mp; + char *path; + caddr_t data; + struct nameidata *ndp; +{ + struct vnode *devvp; + struct ufs_args args; + struct ufsmount *ump; + register struct fs *fs; + u_int size; + int error; + + if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) + return (error); + /* + * 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->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); + return (error); + } + ump = VFSTOUFS(mp); + 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->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); } -/* this routine has lousy error codes */ -/* this routine has races if running twice */ -struct fs * -mountfs(dev, ronly, ip) - dev_t dev; - int ronly; - struct inode *ip; +/* + * Common code for mount and mountroot + */ +mountfs(devvp, mp) + register struct vnode *devvp; + struct mount *mp; { - register struct mount *mp = 0; - struct buf *tp = 0; - register struct buf *bp = 0; + register struct ufsmount *ump = (struct ufsmount *)0; + struct buf *bp = NULL; register struct fs *fs; - int blks; - caddr_t space; - int i, size; + dev_t dev = devvp->v_rdev; + struct partinfo dpart; + int havepart = 0, blks; + caddr_t base, space; + int havepart = 0, blks; + int error, i, size; + int needclose = 0; + int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; - u.u_error = - (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE); - if (u.u_error) { - u.u_error = EIO; - goto out; + 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) { + size = DEV_BSIZE; + } else { + havepart = 1; + size = dpart.disklab->d_secsize; } - tp = bread(dev, SBLOCK, SBSIZE); - if (tp->b_flags & B_ERROR) + if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) goto out; - for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) - if (mp->m_bufp != 0 && dev == mp->m_dev) { - mp = 0; - goto out; - } - for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) - if (mp->m_bufp == 0) - goto found; - mp = 0; - goto out; -found: - mp->m_bufp = tp; /* just to reserve this slot */ - mp->m_dev = NODEV; - fs = tp->b_un.b_fs; - bp = geteblk((int)fs->fs_sbsize); - mp->m_bufp = bp; - bcopy((caddr_t)tp->b_un.b_addr, (caddr_t)bp->b_un.b_addr, - (u_int)fs->fs_sbsize); - brelse(tp); - tp = 0; fs = bp->b_un.b_fs; - if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE) + error = EINVAL; /* XXX needs translation */ goto out; - fs->fs_ronly = (ronly != 0); + } + 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; + fs->fs_ronly = ronly; if (ronly == 0) fs->fs_fmod = 1; + if (havepart) { + dpart.part->p_fstype = FS_BSDFFS; + dpart.part->p_fsize = fs->fs_fsize; + dpart.part->p_frag = fs->fs_frag; + dpart.part->p_cpg = fs->fs_cpg; + } +#ifdef SECSIZE + /* + * If we have a disk label, force per-partition + * filesystem information to be correct + * and set correct current fsbtodb shift. + */ +#endif SECSIZE + if (havepart) { + dpart.part->p_fstype = FS_BSDFFS; + dpart.part->p_fsize = fs->fs_fsize; + dpart.part->p_frag = fs->fs_frag; +#ifdef SECSIZE +#ifdef tahoe + /* + * Save the original fsbtodb shift to restore on updates. + * (Console doesn't understand fsbtodb changes.) + */ + fs->fs_sparecon[0] = fs->fs_fsbtodb; +#endif + i = fs->fs_fsize / size; + for (fs->fs_fsbtodb = 0; i > 1; i >>= 1) + fs->fs_fsbtodb++; +#endif SECSIZE + fs->fs_dbsize = size; + } blks = howmany(fs->fs_cssize, fs->fs_fsize); - space = wmemall(vmemall, (int)fs->fs_cssize); - if (space == 0) - goto out; + base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, + M_WAITOK); for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; - tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); - if (tp->b_flags&B_ERROR) { - wmemfree(space, (int)fs->fs_cssize); +#ifdef SECSIZE + tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size, + fs->fs_dbsize); +#else SECSIZE + error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, + NOCRED, &bp); + if (error) { + free((caddr_t)base, M_SUPERBLK); goto out; } - bcopy((caddr_t)tp->b_un.b_addr, space, (u_int)size); - fs->fs_csp[i / fs->fs_frag] = (struct csum *)space; + bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); + fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; space += size; - brelse(tp); - tp = 0; - } - mp->m_inodp = ip; - mp->m_dev = dev; - if (ip) { - ip->i_flag |= IMOUNT; - iunlock(ip); + brelse(bp); + bp = NULL; } - return (fs); + 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; + 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 */ + fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ + if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ + fs->fs_nrpos = 8; /* XXX */ + + return (0); out: - u.u_error = EBUSY; - if (ip) - iput(ip); - if (mp) - mp->m_bufp = 0; if (bp) brelse(bp); - if (tp) - brelse(tp); + if (needclose) + (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); + if (ump) { + free((caddr_t)ump->um_fs, M_SUPERBLK); + free((caddr_t)ump, M_UFSMNT); + mp->mnt_data = (qaddr_t)0; + } + return (error); +} + +/* + * Make a filesystem operational. + * Nothing to do at the moment. + */ +/* ARGSUSED */ +ufs_start(mp, flags) + struct mount *mp; + int flags; +{ + return (0); } -umount() +/* + * unmount system call + */ +ufs_unmount(mp, mntflags) + struct mount *mp; + int mntflags; { - struct a { - char *fspec; - }; + register struct ufsmount *ump; + register struct fs *fs; + int i, error, ronly, flags = 0; - u.u_error = unmount1(0); + 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 (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; + error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE); + irele(ip); + return (error); } -unmount1(forcibly) - int forcibly; +/* + * Return root of a filesystem + */ +ufs_root(mp, vpp) + struct mount *mp; + struct vnode **vpp; { - dev_t dev; - register struct mount *mp; - int stillopen, flag, error; register struct inode *ip; - register struct fs *fs; + struct inode *nip; + struct vnode tvp; + int error; - error = getmdev(&dev); + tvp.v_mount = mp; + ip = VTOI(&tvp); + ip->i_vnode = &tvp; + ip->i_dev = VFSTOUFS(mp)->um_dev; + error = iget(ip, (ino_t)ROOTINO, &nip); if (error) return (error); - for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) - if (mp->m_bufp != NULL && dev == mp->m_dev) - goto found; - return (EINVAL); -found: - xumount(dev); /* remove unused sticky files from text table */ - update(); -#ifdef QUOTA - if ((stillopen = iflush(dev, mp->m_qinod)) < 0 && !forcibly) + *vpp = ITOV(nip); + 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 ((stillopen = iflush(dev)) < 0 && !forcibly) -#endif - return (EBUSY); - if (stillopen < 0) - return (EBUSY); /* XXX */ -#ifdef QUOTA - closedq(mp); - /* - * Here we have to iflush again to get rid of the quota inode. - * A drag, but it would be ugly to cheat, & this doesn't happen often - */ - (void)iflush(dev, (struct inode *)NULL); + 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 - ip = mp->m_inodp; - ip->i_flag &= ~IMOUNT; - irele(ip); - fs = mp->m_bufp->b_un.b_fs; - wmemfree((caddr_t)fs->fs_csp[0], (int)fs->fs_cssize); - flag = !fs->fs_ronly; - brelse(mp->m_bufp); - mp->m_bufp = 0; - mp->m_dev = 0; - mpurge(mp - &mount[0]); - if (!stillopen) { - (*bdevsw[major(dev)].d_close)(dev, flag); - binval(dev); +} + +/* + * Get file system statistics. + */ +ufs_statfs(mp, sbp) + struct mount *mp; + register struct statfs *sbp; +{ + register struct ufsmount *ump; + register struct fs *fs; + + ump = VFSTOUFS(mp); + fs = ump->um_fs; + if (fs->fs_magic != FS_MAGIC) + panic("ufs_statfs"); + sbp->f_type = MOUNT_UFS; + sbp->f_fsize = fs->fs_fsize; + sbp->f_bsize = fs->fs_bsize; + sbp->f_blocks = fs->fs_dsize; + sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + + fs->fs_cstotal.cs_nffree; + sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - + (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->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); } -sbupdate(mp) +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; + int waitfor; +{ + register struct vnode *vp; + register struct inode *ip; + register struct ufsmount *ump = VFSTOUFS(mp); + register struct fs *fs; + int error, allerror = 0; + + if (syncprt) + bufstats(); + fs = ump->um_fs; + /* + * Write back modified superblock. + * Consistency check that the superblock + * is still in the buffer cache. + */ + if (fs->fs_fmod != 0) { + if (fs->fs_ronly != 0) { /* XXX */ + printf("fs = %s\n", fs->fs_fsmnt); + panic("update: rofs mod"); + } + fs->fs_fmod = 0; + fs->fs_time = time.tv_sec; + allerror = sbupdate(ump, waitfor); + } + /* + * Write back each (modified) inode. + */ +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 & (IMOD|IACC|IUPD|ICHG)) == 0 && + vp->v_dirtyblkhd == NULL) + continue; + 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); + } + /* + * 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); +} + +/* + * Write a superblock and associated information back to disk. + */ +sbupdate(mp, waitfor) + struct ufsmount *mp; + int waitfor; { - register struct fs *fs = mp->m_bufp->b_un.b_fs; + register struct fs *fs = mp->um_fs; register struct buf *bp; int blks; caddr_t space; - int i, size; + int i, size, error = 0; - bp = getblk(mp->m_dev, SBLOCK, (int)fs->fs_sbsize); +#ifdef SECSIZE + bp = getblk(mp->m_dev, (daddr_t)fsbtodb(fs, SBOFF / fs->fs_fsize), + (int)fs->fs_sbsize, fs->fs_dbsize); +#else SECSIZE + bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); +#endif SECSIZE bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); - bwrite(bp); + /* Restore compatibility to old file systems. XXX */ + if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ + bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ +#ifdef SECSIZE +#ifdef tahoe + /* restore standard fsbtodb shift */ + bp->b_un.b_fs->fs_fsbtodb = fs->fs_sparecon[0]; + bp->b_un.b_fs->fs_sparecon[0] = 0; +#endif +#endif SECSIZE + if (waitfor == MNT_WAIT) + error = bwrite(bp); + else + bawrite(bp); blks = howmany(fs->fs_cssize, fs->fs_fsize); space = (caddr_t)fs->fs_csp[0]; for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) size = (blks - i) * fs->fs_fsize; - bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); +#ifdef SECSIZE + bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size, + fs->fs_dbsize); +#else SECSIZE + bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); +#endif SECSIZE bcopy(space, bp->b_un.b_addr, (u_int)size); space += size; - bwrite(bp); + if (waitfor == MNT_WAIT) + error = bwrite(bp); + else + bawrite(bp); } + return (error); +} + +/* + * Print out statistics on the current allocation of the buffer pool. + * Can be enabled to print out on every ``sync'' by setting "syncprt" + * above. + */ +bufstats() +{ + int s, i, j, count; + register struct buf *bp, *dp; + int counts[MAXBSIZE/CLBYTES+1]; + static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; + + for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { + count = 0; + for (j = 0; j <= MAXBSIZE/CLBYTES; j++) + counts[j] = 0; + s = splbio(); + for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { + counts[dp->b_bufsize/CLBYTES]++; + count++; + } + splx(s); + printf("%s: total-%d", bname[i], count); + for (j = 0; j <= MAXBSIZE/CLBYTES; j++) + if (counts[j] != 0) + printf(", %d-%d", j * CLBYTES, counts[j]); + printf("\n"); + } +} + +/* + * File handle to vnode + * + * Have to be really careful about stale file handles: + * - check that the inode number is in range + * - call iget() to get the locked inode + * - check for an unallocated inode (i_mode == 0) + * - check that the generation number matches + */ +ufs_fhtovp(mp, fhp, vpp) + register struct mount *mp; + struct fid *fhp; + struct vnode **vpp; +{ + register struct ufid *ufhp; + register struct fs *fs; + register struct inode *ip; + struct inode *nip; + struct vnode tvp; + int error; + + ufhp = (struct ufid *)fhp; + fs = VFSTOUFS(mp)->um_fs; + if (ufhp->ufid_ino < ROOTINO || + ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { + *vpp = NULLVP; + return (EINVAL); + } + tvp.v_mount = mp; + ip = VTOI(&tvp); + ip->i_vnode = &tvp; + ip->i_dev = VFSTOUFS(mp)->um_dev; + if (error = iget(ip, ufhp->ufid_ino, &nip)) { + *vpp = NULLVP; + return (error); + } + ip = nip; + if (ip->i_mode == 0) { + iput(ip); + *vpp = NULLVP; + return (EINVAL); + } + if (ip->i_gen != ufhp->ufid_gen) { + iput(ip); + *vpp = NULLVP; + return (EINVAL); + } + *vpp = ITOV(ip); + return (0); +} + +/* + * Vnode pointer to File handle + */ +/* ARGSUSED */ +ufs_vptofh(vp, fhp) + struct vnode *vp; + struct fid *fhp; +{ + register struct inode *ip = VTOI(vp); + register struct ufid *ufhp; + + ufhp = (struct ufid *)fhp; + ufhp->ufid_len = sizeof(struct ufid); + ufhp->ufid_ino = ip->i_number; + ufhp->ufid_gen = ip->i_gen; + return (0); } /* - * Common code for mount and umount. * Check that the user's argument is a reasonable * thing on which to mount, and return the device number if so. */ -getmdev(pdev) - dev_t *pdev; +getmdev(devvpp, fname, ndp) + struct vnode **devvpp; + caddr_t fname; + register struct nameidata *ndp; { - dev_t dev; - register struct inode *ip; + register struct vnode *vp; + int error; - if (!suser()) - return (u.u_error); - ip = namei(uchar, LOOKUP, 1); - if (ip == NULL) - return (u.u_error); - if ((ip->i_mode&IFMT) != IFBLK) + 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); - dev = (dev_t)ip->i_rdev; - if (major(dev) >= nblkdev) + } + if (major(vp->v_rdev) >= nblkdev) { + vrele(vp); return (ENXIO); - iput(ip); - *pdev = dev; + } + *devvpp = vp; return (0); }