X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/d85a9d1ba25ee5e21d630b594fa9811d7d33594d..9e8b5f025e5fe4bd4db2fd214d0b257e246aad36:/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 d4683e98b3..6460727a0c 100644 --- a/usr/src/sys/ufs/lfs/lfs_vfsops.c +++ b/usr/src/sys/ufs/lfs/lfs_vfsops.c @@ -1,102 +1,90 @@ /* - * Copyright (c) 1989 The Regents of the University of California. - * All rights reserved. + * Copyright (c) 1989, 1991, 1993, 1994 + * The Regents of the University of California. All rights reserved. * * %sccs.include.redist.c% * - * @(#)lfs_vfsops.c 7.54 (Berkeley) %G% + * @(#)lfs_vfsops.c 8.20 (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 lfs_mountfs __P((struct vnode *, struct mount *, struct proc *)); -struct vfsops ufs_vfsops = { - ufs_mount, +struct vfsops lfs_vfsops = { + lfs_mount, ufs_start, - ufs_unmount, + lfs_unmount, ufs_root, ufs_quotactl, - ufs_statfs, - ufs_sync, - ufs_fhtovp, - ufs_vptofh, - ufs_init + lfs_statfs, + lfs_sync, + lfs_vget, + lfs_fhtovp, + lfs_vptofh, + lfs_init, + lfs_sysctl, }; /* - * Flag to allow forcible unmounting. - */ -int doforce = 1; - -/* - * Called by vfs_mountroot when ufs is going to be mounted as root. - * - * Name is updated by mount(8) after booting. + * Called by main() when ufs is going to be mounted as root. */ -#define ROOTNAME "root_device" - -ufs_mountroot() +lfs_mountroot() { - register struct mount *mp; extern struct vnode *rootvp; + struct fs *fs; + struct mount *mp; struct proc *p = curproc; /* XXX */ - struct ufsmount *ump; - register struct fs *fs; - 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, p); - if (error) { - free((caddr_t)mp, M_MOUNT); + + /* + * Get vnodes for swapdev and rootdev. + */ + if ((error = bdevvp(swapdev, &swapdev_vp)) || + (error = bdevvp(rootdev, &rootvp))) { + printf("lfs_mountroot: can't setup bdevvp's"); return (error); } - if (error = vfs_lock(mp)) { - (void)ufs_unmount(mp, 0, p); - free((caddr_t)mp, M_MOUNT); + if (error = vfs_rootmountalloc("lfs", "root_device", &mp)) + return (error); + if (error = lfs_mountfs(rootvp, mp, p)) { + mp->mnt_vfc->vfc_refcount--; + vfs_unbusy(mp, p); + free(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, p); - vfs_unlock(mp); - inittodr(fs->fs_time); + simple_lock(&mountlist_slock); + CIRCLEQ_INSERT_TAIL(&mountlist, mp, mnt_list); + simple_unlock(&mountlist_slock); + (void)lfs_statfs(mp, &mp->mnt_stat, p); + vfs_unbusy(mp, p); return (0); } @@ -105,7 +93,7 @@ ufs_mountroot() * * mount system call */ -ufs_mount(mp, path, data, ndp, p) +lfs_mount(mp, path, data, ndp, p) register struct mount *mp; char *path; caddr_t data; @@ -115,43 +103,82 @@ ufs_mount(mp, path, data, ndp, p) struct vnode *devvp; struct ufs_args args; struct ufsmount *ump; - register struct fs *fs; + register struct lfs *fs; /* LFS */ u_int size; int error; + mode_t accessmode; if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) return (error); + + /* Until LFS can do NFS right. XXX */ + if (args.export.ex_flags & MNT_EXPORTED) + return (EINVAL); + /* - * 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) - 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, p)) != 0) + if (fs->lfs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { + /* + * If upgrade to read-write by non-root, then verify + * that user has necessary permissions on the device. + */ + if (p->p_ucred->cr_uid != 0) { + vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY, + p); + if (error = VOP_ACCESS(ump->um_devvp, + VREAD | VWRITE, p->p_ucred, p)) { + VOP_UNLOCK(ump->um_devvp, 0, p); + return (error); + } + VOP_UNLOCK(ump->um_devvp, 0, p); + } + fs->lfs_ronly = 0; + } + if (args.fspec == 0) { + /* + * Process export requests. + */ + return (vfs_export(mp, &ump->um_export, &args.export)); + } + } + /* + * 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 mount by non-root, then verify that user has necessary + * permissions on the device. + */ + if (p->p_ucred->cr_uid != 0) { + accessmode = VREAD; + if ((mp->mnt_flag & MNT_RDONLY) == 0) + accessmode |= VWRITE; + vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); + if (error = VOP_ACCESS(devvp, accessmode, p->p_ucred, p)) { + vput(devvp); return (error); + } + VOP_UNLOCK(devvp, 0, p); + } + if ((mp->mnt_flag & MNT_UPDATE) == 0) + error = lfs_mountfs(devvp, mp, p); /* LFS */ + else { if (devvp != ump->um_devvp) error = EINVAL; /* needs translation */ else @@ -162,196 +189,170 @@ ufs_mount(mp, path, data, ndp, p) return (error); } ump = VFSTOUFS(mp); - fs = ump->um_fs; + fs = ump->um_lfs; /* LFS */ +#ifdef NOTLFS /* LFS */ (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, + (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); +#else + (void)copyinstr(path, fs->lfs_fsmnt, sizeof(fs->lfs_fsmnt) - 1, &size); + bzero(fs->lfs_fsmnt + size, sizeof(fs->lfs_fsmnt) - size); + bcopy((caddr_t)fs->lfs_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) lfs_statfs(mp, &mp->mnt_stat, p); +#endif return (0); } /* * Common code for mount and mountroot + * LFS specific */ -mountfs(devvp, mp, p) +int +lfs_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 fs *fs; - 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; extern struct vnode *rootvp; + register struct lfs *fs; + register struct ufsmount *ump; + struct vnode *vp; + struct buf *bp; + struct partinfo dpart; + dev_t dev; + int error, i, ronly, size; + struct ucred *cred; - if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) + cred = p ? p->p_ucred : NOCRED; + 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) + + if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, cred, p) != 0) size = DEV_BSIZE; else { - havepart = 1; size = dpart.disklab->d_secsize; +#ifdef NEVER_USED + dpart.part->p_fstype = FS_LFS; + dpart.part->p_fsize = fs->lfs_fsize; /* frag size */ + dpart.part->p_frag = fs->lfs_frag; /* frags per block */ + dpart.part->p_cpg = fs->lfs_segshift; /* segment shift */ +#endif } - if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) + + /* Don't free random space on error. */ + bp = NULL; + ump = NULL; + + /* Read in the superblock. */ + if (error = bread(devvp, LFS_LABELPAD / size, LFS_SBPAD, cred, &bp)) goto out; - fs = bp->b_un.b_fs; error = EINVAL; /* XXX needs translation */ goto out; } + + /* Allocate the mount structure, copy the superblock into it. */ 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) + fs = ump->um_lfs = malloc(sizeof(struct lfs), M_UFSMNT, M_WAITOK); + bcopy(bp->b_data, fs, sizeof(struct lfs)); + if (sizeof(struct lfs) < LFS_SBPAD) /* XXX why? */ bp->b_flags |= B_INVAL; brelse(bp); bp = NULL; - fs = ump->um_fs; - fs->fs_ronly = ronly; + + /* Set up the I/O information */ + fs->lfs_iocount = 0; + + /* Set up the ifile and lock aflags */ + fs->lfs_doifile = 0; + fs->lfs_writer = 0; + fs->lfs_dirops = 0; + fs->lfs_seglock = 0; + + /* Set the file system readonly/modify bits. */ + fs->lfs_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); - 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; -#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)bp->b_un.b_addr, space, (u_int)size); - fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; - space += size; - brelse(bp); - bp = NULL; - } + fs->lfs_fmod = 1; + + /* Initialize the mount structure. */ + dev = devvp->v_rdev; 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_stat.f_fsid.val[1] = lfs_mount_type; + mp->mnt_maxsymlinklen = fs->lfs_maxsymlinklen; mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; + ump->um_bptrtodb = 0; + ump->um_seqinc = 1 << fs->lfs_fsbtodb; + ump->um_nindir = fs->lfs_nindir; 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 */ + /* + * We use the ifile vnode for almost every operation. Instead of + * retrieving it from the hash table each time we retrieve it here, + * artificially increment the reference count and keep a pointer + * to it in the incore copy of the superblock. + */ + if (error = VFS_VGET(mp, LFS_IFILE_INUM, &vp)) + goto out; + fs->lfs_ivnode = vp; + VREF(vp); + vput(vp); + 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, cred, p); if (ump) { - free((caddr_t)ump->um_fs, M_SUPERBLK); - free((caddr_t)ump, M_UFSMNT); + free(ump->um_lfs, M_UFSMNT); + free(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, p) - struct mount *mp; - int flags; - struct proc *p; -{ - - return (0); -} - /* * unmount system call */ -ufs_unmount(mp, mntflags, p) +lfs_unmount(mp, mntflags, p) struct mount *mp; int mntflags; struct proc *p; { + extern int doforce; register struct ufsmount *ump; - register struct fs *fs; - int i, error, ronly, flags = 0; + register struct lfs *fs; + int i, error, flags, ronly; - if (mntflags & MNT_FORCE) { - if (!doforce || mp == rootfs) - return (EINVAL); + flags = 0; + if (mntflags & MNT_FORCE) flags |= FORCECLOSE; - } - mntflushbuf(mp, 0); - if (mntinvalbuf(mp)) - return (EBUSY); + ump = VFSTOUFS(mp); + fs = ump->um_lfs; return (error); #ifdef QUOTA if (mp->mnt_flag & MNT_QUOTA) { - if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) + if (error = vflush(mp, fs->lfs_ivnode, SKIPSYSTEM|flags)) return (error); 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,134 +360,48 @@ ufs_unmount(mp, mntflags, p) */ } #endif - if (error = vflush(mp, NULLVP, flags)) + if (error = vflush(mp, fs->lfs_ivnode, 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) + fs->lfs_clean = 1; + if (error = VFS_SYNC(mp, 1, p->p_ucred, p)) return (error); - *vpp = ITOV(nip); - return (0); -} + if (fs->lfs_ivnode->v_dirtyblkhd.lh_first) + panic("lfs_unmount: still dirty blocks on ifile vnode\n"); + vrele(fs->lfs_ivnode); + vgone(fs->lfs_ivnode); -/* - * 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 -} - -/* + ronly = !fs->lfs_ronly; * Get file system statistics. */ -ufs_statfs(mp, sbp, p) +lfs_statfs(mp, sbp, p) struct mount *mp; register struct statfs *sbp; struct proc *p; { + register struct lfs *fs; 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; + fs = ump->um_lfs; + if (fs->lfs_magic != LFS_MAGIC) + panic("lfs_statfs: magic"); + sbp->f_bsize = fs->lfs_fsize; + sbp->f_iosize = fs->lfs_bsize; + sbp->f_blocks = dbtofrags(fs,fs->lfs_dsize); + sbp->f_bfree = dbtofrags(fs, fs->lfs_bfree); + /* + * To compute the available space. Subtract the minimum free + * from the total number of blocks in the file system. Set avail + * to the smaller of this number and fs->lfs_bfree. + */ + sbp->f_bavail = fs->lfs_dsize * (100 - fs->lfs_minfree) / 100; + sbp->f_bavail = + sbp->f_bavail > fs->lfs_bfree ? fs->lfs_bfree : sbp->f_bavail; + sbp->f_bavail = dbtofrags(fs, sbp->f_bavail); + sbp->f_files = fs->lfs_nfiles; + sbp->f_ffree = sbp->f_bfree * INOPB(fs); if (sbp != &mp->mnt_stat) { + sbp->f_type = mp->mnt_vfc->vfc_typenum; bcopy((caddr_t)mp->mnt_stat.f_mntonname, (caddr_t)&sbp->f_mntonname[0], MNAMELEN); bcopy((caddr_t)mp->mnt_stat.f_mntfromname, @@ -495,8 +410,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,217 +417,162 @@ int syncprt = 0; * * Note: we are always called with the filesystem marked `MPBUSY'. */ -ufs_sync(mp, waitfor) +lfs_sync(mp, waitfor, cred, p) struct mount *mp; int waitfor; + struct ucred *cred; + struct proc *p; { - register struct vnode *vp; + int error; + + /* All syncs must be checkpoints until roll-forward is implemented. */ + error = lfs_segwrite(mp, SEGM_CKP | (waitfor ? SEGM_SYNC : 0)); +#ifdef QUOTA + qsync(mp); +#endif + return (error); +} + +/* + * Look up an LFS dinode number to find its incore vnode. If not already + * in core, read it in from the specified device. Return the inode locked. + * Detection and handling of mount points must be done by the calling routine. + */ +int +lfs_vget(mp, ino, vpp) + struct mount *mp; + ino_t ino; + struct vnode **vpp; +{ + register struct lfs *fs; register struct inode *ip; - register struct ufsmount *ump = VFSTOUFS(mp); - register struct fs *fs; - int error, allerror = 0; + struct buf *bp; + struct ifile *ifp; + struct vnode *vp; + struct ufsmount *ump; + ufs_daddr_t daddr; + dev_t dev; + int error; + + ump = VFSTOUFS(mp); + dev = ump->um_dev; + if ((*vpp = ufs_ihashget(dev, ino)) != NULL) + return (0); + + /* Translate the inode number to a disk address. */ + fs = ump->um_lfs; + if (ino == LFS_IFILE_INUM) + daddr = fs->lfs_idaddr; + else { + LFS_IENTRY(ifp, fs, ino, bp); + daddr = ifp->if_daddr; + brelse(bp); + if (daddr == LFS_UNUSED_DADDR) + return (ENOENT); + } + + /* Allocate new vnode/inode. */ + if (error = lfs_vcreate(mp, ino, &vp)) { + *vpp = NULL; + return (error); + } - if (syncprt) - bufstats(); - fs = ump->um_fs; /* - * Write back modified superblock. - * Consistency check that the superblock - * is still in the buffer cache. + * 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. */ - 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); - } + ip = VTOI(vp); + ufs_ihashins(ip); + /* - * Write back each (modified) inode. + * XXX + * This may not need to be here, logically it should go down with + * the i_devvp initialization. + * Ask Kirk. */ -loop: - for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { + ip->i_lfs = ump->um_lfs; + + /* Read in the disk contents for the inode, copy into the inode. */ + if (error = + bread(ump->um_devvp, daddr, (int)fs->lfs_bsize, NOCRED, &bp)) { /* - * If the vnode that we are about to sync is no longer - * associated with this mount point, start over. + * 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(). */ - 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) - 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); + brelse(bp); + *vpp = NULL; + return (error); } + ip->i_din = *lfs_ifind(fs, ino, (struct dinode *)bp->b_data); + brelse(bp); + /* - * Force stale file system control information to be flushed. + * Initialize the vnode from the inode, check for aliases. In all + * cases re-init ip, the underlying vnode/inode may have changed. */ - 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->um_fs; - register struct buf *bp; - int blks; - caddr_t space; - int i, size, error = 0; - -#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); - /* 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; -#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; - 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"); + if (error = ufs_vinit(mp, lfs_specop_p, LFS_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); + *vpp = vp; + return (0); } /* * 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 that the inode number is valid + * - call lfs_vget() to get the locked inode * - check for an unallocated inode (i_mode == 0) - * - check that the generation number matches + * - check that the given client host has export rights and return + * those rights via. exflagsp and credanonp + * + * XXX + * use ifile to see if inode is allocated instead of reading off disk + * what is the relationship between my generational number and the NFS + * generational number. */ -ufs_fhtovp(mp, fhp, vpp) +int +lfs_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; - 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); + if (ufhp->ufid_ino < ROOTINO) + return (ESTALE); + return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); } /* * Vnode pointer to File handle */ /* ARGSUSED */ -ufs_vptofh(vp, fhp) +lfs_vptofh(vp, fhp) struct vnode *vp; struct fid *fhp; { - register struct inode *ip = VTOI(vp); + 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; @@ -723,32 +581,15 @@ ufs_vptofh(vp, fhp) } /* - * Check that the user's argument is a reasonable - * thing on which to mount, and return the device number if so. + * Initialize the filesystem, most work done by ufs_init. */ -getmdev(devvpp, fname, ndp, p) - struct vnode **devvpp; - caddr_t fname; - register struct nameidata *ndp; - struct proc *p; +int lfs_mount_type; + +int +lfs_init(vfsp) + struct vfsconf *vfsp; { - 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); + lfs_mount_type = vfsp->vfc_typenum; + return (ufs_init(vfsp)); }