X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/d85a9d1ba25ee5e21d630b594fa9811d7d33594d..80409bdc15459b1562b1e288e45e7bbad4210deb:/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 152bada809..55530ef36c 100644 --- a/usr/src/sys/ufs/ffs/ffs_vfsops.c +++ b/usr/src/sys/ufs/ffs/ffs_vfsops.c @@ -1,84 +1,93 @@ /* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1989, 1991, 1993 + * The Regents of the University of California. All rights reserved. * * %sccs.include.redist.c% * - * @(#)ffs_vfsops.c 7.54 (Berkeley) %G% + * @(#)ffs_vfsops.c 8.1 (Berkeley) %G% */ -#include "param.h" -#include "systm.h" -#include "namei.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 +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include #include "ioctl.h" #include "disklabel.h" #include "stat.h" -#include "quota.h" -#include "fs.h" -#include "ufsmount.h" -#include "inode.h" +#include +#include +#include +#include + +#include +#include + +int ffs_sbupdate __P((struct ufsmount *, int)); struct vfsops ufs_vfsops = { - ufs_mount, + ffs_mount, ufs_start, - ufs_unmount, - ufs_root, + ffs_unmount, + ffs_root, ufs_quotactl, - ufs_statfs, - ufs_sync, - ufs_fhtovp, - ufs_vptofh, - ufs_init + ffs_statfs, + ffs_sync, + ffs_vget, + ffs_fhtovp, + ffs_vptofh, + ffs_init, }; -/* - * Flag to allow forcible unmounting. - */ -int doforce = 1; +extern u_long nextgennumber; /* - * Called by vfs_mountroot when ufs is going to be mounted as root. + * Called by main() when ufs is going to be mounted as root. * * Name is updated by mount(8) after booting. */ #define ROOTNAME "root_device" -ufs_mountroot() +ffs_mountroot() { - register struct mount *mp; extern struct vnode *rootvp; + register struct fs *fs; + register struct mount *mp; struct proc *p = curproc; /* XXX */ struct ufsmount *ump; - register struct fs *fs; u_int size; int error; + + /* + * Get vnodes for swapdev and rootdev. + */ + if (bdevvp(swapdev, &swapdev_vp) || bdevvp(rootdev, &rootvp)) + panic("ffs_mountroot: can't setup bdevvp's"); - mp = (struct mount *)malloc((u_long)sizeof(struct mount), - M_MOUNT, M_WAITOK); + mp = malloc((u_long)sizeof(struct mount), M_MOUNT, M_WAITOK); + bzero((char *)mp, (u_long)sizeof(struct mount)); mp->mnt_op = &ufs_vfsops; mp->mnt_flag = MNT_RDONLY; - mp->mnt_exroot = 0; - mp->mnt_mounth = NULLVP; - error = mountfs(rootvp, mp, p); - if (error) { - free((caddr_t)mp, M_MOUNT); + if (error = ffs_mountfs(rootvp, mp, p)) { + free(mp, M_MOUNT); return (error); } if (error = vfs_lock(mp)) { - (void)ufs_unmount(mp, 0, p); - free((caddr_t)mp, M_MOUNT); + (void)ffs_unmount(mp, 0, p); + free(mp, M_MOUNT); return (error); } rootfs = mp; @@ -94,7 +103,7 @@ ufs_mountroot() (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, p); + (void)ffs_statfs(mp, &mp->mnt_stat, p); vfs_unlock(mp); inittodr(fs->fs_time); return (0); @@ -105,7 +114,8 @@ ufs_mountroot() * * mount system call */ -ufs_mount(mp, path, data, ndp, p) +int +ffs_mount(mp, path, data, ndp, p) register struct mount *mp; char *path; caddr_t data; @@ -117,41 +127,70 @@ ufs_mount(mp, path, data, ndp, p) struct ufsmount *ump; register struct fs *fs; u_int size; - int error; + int error, flags; if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) return (error); /* - * Process export requests. + * If updating, check whether changing from read-only to + * read/write; if there is no device name, that's all we do. */ - 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, p)) != 0) - return (error); - error = mountfs(devvp, mp, p); - } else { + if (mp->mnt_flag & MNT_UPDATE) { ump = VFSTOUFS(mp); fs = ump->um_fs; - if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) + error = 0; + if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { + flags = WRITECLOSE; + if (mp->mnt_flag & MNT_FORCE) + flags |= FORCECLOSE; + if (vfs_busy(mp)) + return (EBUSY); + error = ffs_flushfiles(mp, flags, p); + vfs_unbusy(mp); + } + if (!error && (mp->mnt_flag & MNT_RELOAD)) + error = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); + if (error) + return (error); + if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) 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) + if (args.fspec == 0) { + /* + * Process export requests. + */ + if (args.exflags & MNT_EXPORTED) { + if (error = ufs_hang_addrlist(mp, &args)) + return (error); + mp->mnt_flag |= MNT_EXPORTED; + } + if (args.exflags & MNT_DELEXPORT) { + ufs_free_addrlist(ump); + mp->mnt_flag &= + ~(MNT_EXPORTED | MNT_DEFEXPORTED); + } return (0); - if ((error = getmdev(&devvp, args.fspec, ndp, p)) != 0) - return (error); + } + } + /* + * Not an update, or updating the name: look up the name + * and verify that it refers to a sensible block device. + */ + NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); + if (error = namei(ndp)) + 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 = ffs_mountfs(devvp, mp, p); + else { if (devvp != ump->um_devvp) error = EINVAL; /* needs translation */ else @@ -170,20 +209,127 @@ ufs_mount(mp, path, data, ndp, p) (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, p); + (void)ffs_statfs(mp, &mp->mnt_stat, p); + return (0); +} + +/* + * Reload all incore data for a filesystem (used after running fsck on + * the root filesystem and finding things to fix). The filesystem must + * be mounted read-only. + * + * Things to do to update the mount: + * 1) invalidate all cached meta-data. + * 2) re-read superblock from disk. + * 3) re-read summary information from disk. + * 4) invalidate all inactive vnodes. + * 5) invalidate all cached file data. + * 6) re-read inode data for all active vnodes. + */ +ffs_reload(mountp, cred, p) + register struct mount *mountp; + struct ucred *cred; + struct proc *p; +{ + register struct vnode *vp, *nvp, *devvp; + struct inode *ip; + struct dinode *dp; + struct csum *space; + struct buf *bp; + struct fs *fs; + int i, blks, size, error; + + if ((mountp->mnt_flag & MNT_RDONLY) == 0) + return (EINVAL); + /* + * Step 1: invalidate all cached meta-data. + */ + devvp = VFSTOUFS(mountp)->um_devvp; + if (vinvalbuf(devvp, 0, cred, p, 0, 0)) + panic("ffs_reload: dirty1"); + /* + * Step 2: re-read superblock from disk. + */ + if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) + return (error); + fs = bp->b_un.b_fs; + if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || + fs->fs_bsize < sizeof(struct fs)) { + brelse(bp); + return (EIO); /* XXX needs translation */ + } + fs = VFSTOUFS(mountp)->um_fs; + bcopy((caddr_t)&fs->fs_csp[0], (caddr_t)&bp->b_un.b_fs->fs_csp[0], + sizeof(fs->fs_csp)); + bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)fs, (u_int)fs->fs_sbsize); + if (fs->fs_sbsize < SBSIZE) + bp->b_flags |= B_INVAL; + brelse(bp); + ffs_oldfscompat(fs); + /* + * Step 3: re-read summary information from disk. + */ + blks = howmany(fs->fs_cssize, fs->fs_fsize); + space = 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; + if (error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, + NOCRED, &bp)) + return (error); + bcopy((caddr_t)bp->b_un.b_addr, fs->fs_csp[fragstoblks(fs, i)], + (u_int)size); + brelse(bp); + } +loop: + for (vp = mountp->mnt_mounth; vp; vp = nvp) { + nvp = vp->v_mountf; + /* + * Step 4: invalidate all inactive vnodes. + */ + if (vp->v_usecount == 0) { + vgone(vp); + continue; + } + /* + * Step 5: invalidate all cached file data. + */ + if (vget(vp)) + goto loop; + if (vinvalbuf(vp, 0, cred, p, 0, 0)) + panic("ffs_reload: dirty2"); + /* + * Step 6: re-read inode data for all active vnodes. + */ + ip = VTOI(vp); + if (error = bread(devvp, fsbtodb(fs, itod(fs, ip->i_number)), + (int)fs->fs_bsize, NOCRED, &bp)) { + vput(vp); + return (error); + } + dp = bp->b_un.b_dino; + dp += itoo(fs, ip->i_number); + ip->i_din = *dp; + brelse(bp); + vput(vp); + if (vp->v_mount != mountp) + goto loop; + } return (0); } /* * Common code for mount and mountroot */ -mountfs(devvp, mp, p) +int +ffs_mountfs(devvp, mp, p) 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 buf *bp; register struct fs *fs; dev_t dev = devvp->v_rdev; struct partinfo dpart; @@ -191,27 +337,29 @@ mountfs(devvp, mp, p) caddr_t base, space; int havepart = 0, blks; int error, i, size; - int needclose = 0; - int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; + int ronly; extern struct vnode *rootvp; - if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) + if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p)) return (error); - needclose = 1; if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) size = DEV_BSIZE; else { havepart = 1; size = dpart.disklab->d_secsize; } + + bp = NULL; + ump = NULL; if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) goto out; fs = bp->b_un.b_fs; 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, + ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); + bzero((caddr_t)ump, sizeof *ump); + ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, M_WAITOK); bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, (u_int)fs->fs_sbsize); @@ -255,7 +403,7 @@ mountfs(devvp, mp, p) fs->fs_dbsize = size; } blks = howmany(fs->fs_cssize, fs->fs_fsize); - base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, + base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT, M_WAITOK); for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; @@ -268,7 +416,7 @@ mountfs(devvp, mp, p) error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, NOCRED, &bp); if (error) { - free((caddr_t)base, M_SUPERBLK); + free(base, M_UFSMNT); goto out; } bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); @@ -280,44 +428,56 @@ mountfs(devvp, mp, p) 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_maxsymlinklen = fs->fs_maxsymlinklen; mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; + ump->um_nindir = fs->fs_nindir; + ump->um_bptrtodb = fs->fs_fsbtodb; + ump->um_seqinc = fs->fs_frag; 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 */ - + ffs_oldfscompat(fs); return (0); out: if (bp) brelse(bp); - if (needclose) - (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); + (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); + free(ump->um_fs, M_UFSMNT); + free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; } return (error); } /* - * Make a filesystem operational. - * Nothing to do at the moment. + * Sanity checks for old file systems. + * + * XXX - goes away some day. */ -/* ARGSUSED */ -ufs_start(mp, flags, p) - struct mount *mp; - int flags; - struct proc *p; +ffs_oldfscompat(fs) + struct fs *fs; { + int i; + + 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 */ + if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ + quad_t sizepb = fs->fs_bsize; /* XXX */ + /* XXX */ + fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ + for (i = 0; i < NIADDR; i++) { /* XXX */ + sizepb *= NINDIR(fs); /* XXX */ + fs->fs_maxfilesize += sizepb; /* XXX */ + } /* XXX */ + fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ + fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ + } /* XXX */ return (0); } @@ -325,23 +485,53 @@ ufs_start(mp, flags, p) /* * unmount system call */ -ufs_unmount(mp, mntflags, p) +int +ffs_unmount(mp, mntflags, p) struct mount *mp; int mntflags; struct proc *p; { register struct ufsmount *ump; register struct fs *fs; - int i, error, ronly, flags = 0; + int error, flags, ronly; + flags = 0; if (mntflags & MNT_FORCE) { - if (!doforce || mp == rootfs) + if (mp == rootfs) return (EINVAL); flags |= FORCECLOSE; } - mntflushbuf(mp, 0); - if (mntinvalbuf(mp)) - return (EBUSY); + if (error = ffs_flushfiles(mp, flags, p)) + return (error); + ump = VFSTOUFS(mp); + 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, p); + vrele(ump->um_devvp); + free(fs->fs_csp[0], M_UFSMNT); + free(fs, M_UFSMNT); + free(ump, M_UFSMNT); + mp->mnt_data = (qaddr_t)0; + mp->mnt_flag &= ~MNT_LOCAL; + return (error); +} + +/* + * Flush out all the files in a filesystem. + */ +ffs_flushfiles(mp, flags, p) + register struct mount *mp; + int flags; + struct proc *p; +{ + extern int doforce; + register struct ufsmount *ump; + int i, error; + + if (!doforce) + flags &= ~FORCECLOSE; ump = VFSTOUFS(mp); return (error); #ifdef QUOTA @@ -351,7 +541,7 @@ ufs_unmount(mp, mntflags, p) 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 @@ -359,112 +549,10 @@ ufs_unmount(mp, mntflags, p) */ } #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); -} - -/* - * Return root of a filesystem - */ -ufs_root(mp, vpp) - struct mount *mp; - struct vnode **vpp; -{ - register struct inode *ip; - struct inode *nip; - struct vnode tvp; - int error; - - 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); - *vpp = ITOV(nip); - return (0); -} - -/* - * Do operations associated with quotas - */ -ufs_quotactl(mp, cmds, uid, arg, p) - struct mount *mp; - int cmds; - uid_t uid; - caddr_t arg; - struct proc *p; -{ - struct ufsmount *ump = VFSTOUFS(mp); - int cmd, type, error; - -#ifndef QUOTA - return (EOPNOTSUPP); -#else - if (uid == -1) - uid = p->p_cred->p_ruid; - cmd = cmds >> SUBCMDSHIFT; - - switch (cmd) { - case Q_GETQUOTA: - case Q_SYNC: - if (uid == p->p_cred->p_ruid) - break; - /* fall through */ - default: - if (error = suser(p->p_ucred, &p->p_acflag)) - return (error); - } - - type = cmd & SUBCMDMASK; - if ((u_int)type >= MAXQUOTAS) - return (EINVAL); - - switch (cmd) { - - case Q_QUOTAON: - return (quotaon(p, 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. */ -ufs_statfs(mp, sbp, p) +int +ffs_statfs(mp, sbp, p) struct mount *mp; register struct statfs *sbp; struct proc *p; @@ -475,10 +563,10 @@ ufs_statfs(mp, sbp, p) ump = VFSTOUFS(mp); fs = ump->um_fs; if (fs->fs_magic != FS_MAGIC) - panic("ufs_statfs"); + panic("ffs_statfs"); sbp->f_type = MOUNT_UFS; - sbp->f_fsize = fs->fs_fsize; - sbp->f_bsize = fs->fs_bsize; + sbp->f_bsize = fs->fs_fsize; + sbp->f_iosize = 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; @@ -495,8 +583,6 @@ ufs_statfs(mp, sbp, p) return (0); } -int syncprt = 0; - /* * Go through the disk queues to initiate sandbagged IO; * go through the inodes to write those that have been modified; @@ -504,9 +590,12 @@ int syncprt = 0; * * Note: we are always called with the filesystem marked `MPBUSY'. */ -ufs_sync(mp, waitfor) +int +ffs_sync(mp, waitfor, cred, p) struct mount *mp; int waitfor; + struct ucred *cred; + struct proc *p; { register struct vnode *vp; register struct inode *ip; @@ -514,8 +603,6 @@ ufs_sync(mp, waitfor) register struct fs *fs; int error, allerror = 0; - if (syncprt) - bufstats(); fs = ump->um_fs; /* * Write back modified superblock. @@ -529,7 +616,7 @@ ufs_sync(mp, waitfor) } fs->fs_fmod = 0; fs->fs_time = time.tv_sec; - allerror = sbupdate(ump, waitfor); + allerror = ffs_sbupdate(ump, waitfor); } /* * Write back each (modified) inode. @@ -546,31 +633,189 @@ loop: continue; ip = VTOI(vp); if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && - vp->v_dirtyblkhd == NULL) + vp->v_dirtyblkhd.le_next == 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))) + if (error = VOP_FSYNC(vp, cred, waitfor, p)) allerror = error; vput(vp); } /* * Force stale file system control information to be flushed. */ - vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); + if (error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p)) + allerror = error; #ifdef QUOTA qsync(mp); #endif return (allerror); } +/* + * Look up a FFS dinode number to find its incore vnode. + * If it is not in core, read it in from the specified device. + * If it is in core, wait for the lock bit to clear, then + * return the inode locked. Detection and handling of mount + * points must be done by the calling routine. + */ +int +ffs_vget(mp, ino, vpp) + struct mount *mp; + ino_t ino; + struct vnode **vpp; +{ + register struct fs *fs; + register struct inode *ip; + struct ufsmount *ump; + struct buf *bp; + struct dinode *dp; + struct vnode *vp; + union ihead *ih; + dev_t dev; + int i, type, error; + + ump = VFSTOUFS(mp); + dev = ump->um_dev; + if ((*vpp = ufs_ihashget(dev, ino)) != NULL) + return (0); + + /* Allocate a new vnode/inode. */ + if (error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp)) { + *vpp = NULL; + return (error); + } + type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ + MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); + bzero((caddr_t)ip, sizeof(struct inode)); + vp->v_data = ip; + ip->i_vnode = vp; + ip->i_fs = fs = ump->um_fs; + ip->i_dev = dev; + ip->i_number = ino; +#ifdef QUOTA + for (i = 0; i < MAXQUOTAS; i++) + ip->i_dquot[i] = NODQUOT; +#endif + /* + * Put it onto its hash chain and lock it so that other requests for + * this inode will block if they arrive while we are sleeping waiting + * for old data structures to be purged or for the contents of the + * disk portion of this inode to be read. + */ + ufs_ihashins(ip); + + /* Read in the disk contents for the inode, copy into the inode. */ + if (error = bread(ump->um_devvp, fsbtodb(fs, itod(fs, ino)), + (int)fs->fs_bsize, NOCRED, &bp)) { + /* + * The inode does not contain anything useful, so it would + * be misleading to leave it on its hash chain. With mode + * still zero, it will be unlinked and returned to the free + * list by vput(). + */ + vput(vp); + brelse(bp); + *vpp = NULL; + return (error); + } + dp = bp->b_un.b_dino; + dp += itoo(fs, ino); + ip->i_din = *dp; + brelse(bp); + + /* + * Initialize the vnode from the inode, check for aliases. + * Note that the underlying vnode may have changed. + */ + if (error = ufs_vinit(mp, ffs_specop_p, FFS_FIFOOPS, &vp)) { + vput(vp); + *vpp = NULL; + return (error); + } + /* + * Finish inode initialization now that aliasing has been resolved. + */ + ip->i_devvp = ump->um_devvp; + VREF(ip->i_devvp); + /* + * Set up a generation number for this inode if it does not + * already have one. This should only happen on old filesystems. + */ + if (ip->i_gen == 0) { + if (++nextgennumber < (u_long)time.tv_sec) + nextgennumber = time.tv_sec; + ip->i_gen = nextgennumber; + if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) + ip->i_flag |= IMOD; + } + /* + * Ensure that uid and gid are correct. This is a temporary + * fix until fsck has been changed to do the update. + */ + if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ + ip->i_uid = ip->i_din.di_ouid; /* XXX */ + ip->i_gid = ip->i_din.di_ogid; /* XXX */ + } /* XXX */ + + *vpp = vp; + return (0); +} + +/* + * File handle to vnode + * + * Have to be really careful about stale file handles: + * - check that the inode number is valid + * - call ffs_vget() to get the locked inode + * - check for an unallocated inode (i_mode == 0) + * - check that the given client host has export rights and return + * those rights via. exflagsp and credanonp + */ +int +ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) + register struct mount *mp; + struct fid *fhp; + struct mbuf *nam; + struct vnode **vpp; + int *exflagsp; + struct ucred **credanonp; +{ + register struct ufid *ufhp; + struct fs *fs; + + ufhp = (struct ufid *)fhp; + fs = VFSTOUFS(mp)->um_fs; + if (ufhp->ufid_ino < ROOTINO || + ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) + return (ESTALE); + return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); +} + +/* + * Vnode pointer to File handle + */ +/* ARGSUSED */ +ffs_vptofh(vp, fhp) + struct vnode *vp; + struct fid *fhp; +{ + register struct inode *ip; + register struct ufid *ufhp; + + ip = VTOI(vp); + ufhp = (struct ufid *)fhp; + ufhp->ufid_len = sizeof(struct ufid); + ufhp->ufid_ino = ip->i_number; + ufhp->ufid_gen = ip->i_gen; + return (0); +} + /* * Write a superblock and associated information back to disk. */ -sbupdate(mp, waitfor) +int +ffs_sbupdate(mp, waitfor) struct ufsmount *mp; int waitfor; { @@ -584,7 +829,7 @@ sbupdate(mp, waitfor) 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); + bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); #endif SECSIZE bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); /* Restore compatibility to old file systems. XXX */ @@ -611,7 +856,8 @@ sbupdate(mp, waitfor) 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); + bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), + size, 0, 0); #endif SECSIZE bcopy(space, bp->b_un.b_addr, (u_int)size); space += size; @@ -622,133 +868,3 @@ sbupdate(mp, waitfor) } 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); -} - -/* - * 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, p) - struct vnode **devvpp; - caddr_t fname; - register struct nameidata *ndp; - struct proc *p; -{ - register struct vnode *vp; - int error; - - ndp->ni_nameiop = LOOKUP | FOLLOW; - ndp->ni_segflg = UIO_USERSPACE; - ndp->ni_dirp = fname; - if (error = namei(ndp, p)) - 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); -}