X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/8e472461dc34438bcd18167e80560ac07dd86a7c..7188ac27426632d20adaac4191443dfefebf5789:/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 9f20ea1c22..4e7bfe4764 100644 --- a/usr/src/sys/ufs/lfs/lfs_vfsops.c +++ b/usr/src/sys/ufs/lfs/lfs_vfsops.c @@ -1,159 +1,207 @@ /* - * Copyright (c) 1982, 1986 Regents of the University of California. - * All rights reserved. The Berkeley software License Agreement - * specifies the terms and conditions for redistribution. + * Copyright (c) 1989 The Regents of the University of California. + * All rights reserved. * - * @(#)lfs_vfsops.c 7.12 (Berkeley) %G% + * 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. + * + * @(#)lfs_vfsops.c 7.13 (Berkeley) %G% */ + #include "param.h" #include "systm.h" -#include "dir.h" -#include "user.h" -#include "inode.h" -#include "proc.h" -#include "fs.h" -#include "buf.h" +#include "time.h" +#include "kernel.h" +#include "namei.h" +#include "vnode.h" #include "mount.h" +#include "buf.h" #include "file.h" -#include "conf.h" -#include "ioctl.h" #include "disklabel.h" -#include "stat.h" +#include "ioctl.h" +#include "errno.h" #include "malloc.h" +#include "../ufs/fs.h" +#include "../ufs/ufsmount.h" +#include "../ufs/inode.h" #include "ioctl.h" #include "disklabel.h" #include "stat.h" -smount() +/* + * ufs vfs operations. + */ +int ufs_mount(); +int ufs_unmount(); +int ufs_root(); +int ufs_statfs(); +int ufs_sync(); +int ufs_fhtovp(); +int ufs_vptofh(); + +struct vfsops ufs_vfsops = { + ufs_mount, + ufs_unmount, + ufs_root, + ufs_statfs, + ufs_sync, + ufs_fhtovp, + ufs_vptofh +}; + +/* + * ufs mount table. + */ +struct ufsmount mounttab[NMOUNT]; + +/* + * Called by vfs_mountroot when ufs is going to be mounted as root + * + * XXX - Need to have a way of figuring the name of the root device + */ +#define ROOTNAME "root device" + +ufs_mountroot() { - register struct a { - char *fspec; - char *freg; - int ronly; - } *uap = (struct a *)u.u_ap; - dev_t dev; - register struct inode *ip; + register struct mount *mp; + extern struct vnode *rootvp; + struct ufsmount *ump; register struct fs *fs; - register struct nameidata *ndp = &u.u_nd; - u_int len; + u_int size; + int error; - u.u_error = getmdev(&dev, uap->fspec); - if (u.u_error) - return; - ndp->ni_nameiop = LOOKUP | FOLLOW; - ndp->ni_segflg = UIO_USERSPACE; - ndp->ni_dirp = (caddr_t)uap->freg; - ip = namei(ndp); - if (ip == NULL) - return; - if (ip->i_count != 1) { - iput(ip); - u.u_error = EBUSY; - return; + 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; + error = mountfs(rootvp, mp); + if (error) { + free((caddr_t)mp, M_MOUNT); + return (error); } - if ((ip->i_mode&IFMT) != IFDIR) { - iput(ip); - u.u_error = ENOTDIR; - return; + error = vfs_add((struct vnode *)0, mp, 0); + if (error) { + (void)ufs_unmount(mp, 0); + free((caddr_t)mp, M_MOUNT); + return (error); } - fs = mountfs(dev, uap->ronly, ip); - if (fs == 0) { - iput(ip); - return; + ump = VFSTOUFS(mp); + fs = ump->um_fs; + 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); + vfs_unlock(mp); + inittodr(fs->fs_time); + return (0); +} + +/* + * VFS Operations. + * + * mount system call + */ +ufs_mount(mp, path, data, ndp) + 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); + if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) + return (error); + error = mountfs(devvp, mp); + if (error) { + vrele(devvp); + return (error); } - (void) copyinstr(uap->freg, fs->fs_fsmnt, sizeof(fs->fs_fsmnt)-1, &len); - bzero(fs->fs_fsmnt + len, sizeof (fs->fs_fsmnt) - len); + 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); + (void) copyinstr(args.fspec, ump->um_mntname, MNAMELEN - 1, &size); + bzero(ump->um_mntname + size, MNAMELEN - size); + return (0); } -struct fs * -mountfs(dev, ronly, ip) - dev_t dev; - int ronly; - struct inode *ip; +/* + * Common code for mount and mountroot + */ +mountfs(devvp, mp) + struct vnode *devvp; + struct mount *mp; { - register struct mount *mp; - struct mount *fmp = NULL; - register struct buf *bp = NULL; + register struct ufsmount *ump; + struct ufsmount *fmp = NULL; + 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 i, size; - register error; + int havepart = 0, blks; + int error, i, size; int needclose = 0; + int ronly = (mp->m_flag & M_RDONLY) != 0; - for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) { - if (mp->m_fs == NULL) { + for (ump = &mounttab[0]; ump < &mounttab[NMOUNT]; ump++) { + if (ump->um_fs == NULL) { if (fmp == NULL) - fmp = mp; - } else if (dev == mp->m_dev) { - u.u_error = EBUSY; /* XXX */ - return ((struct fs *) NULL); + fmp = ump; + } else if (dev == ump->um_dev) { + return (EBUSY); /* needs translation */ } } - if ((mp = fmp) == NULL) { - u.u_error = EMFILE; /* needs translation XXX */ - return ((struct fs *) NULL); - } - mp->m_fs = (struct fs *)1; /* just to reserve this slot */ - mp->m_dev = dev; - mp->m_inodp = NULL; - error = (*bdevsw[major(dev)].d_open)(dev, ronly ? FREAD : FREAD|FWRITE, S_IFBLK); if (error) { - u.u_error = error; - mp->m_fs = NULL; - return ((struct fs *) NULL); + ump->um_fs = NULL; + return (error); } needclose = 1; - if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, - (caddr_t)&dpart, FREAD) == 0) { - havepart = 1; - size = dpart.disklab->d_secsize; - } else + if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, + (struct ucred *)0) != 0) size = DEV_BSIZE; -#ifdef SECSIZE - /* - * If possible, determine hardware sector size - * and adjust fsbtodb to correspond. - */ -#endif SECSIZE - if ((*bdevsw[major(dev)].d_ioctl)(dev, DIOCGPART, - (caddr_t)&dpart, FREAD) == 0) { + else { havepart = 1; size = dpart.disklab->d_secsize; -#ifdef SECSIZE - if (size < MINSECSIZE) { - error = EINVAL; - goto out; - } -#endif SECSIZE - } else - size = DEV_BSIZE; -#ifdef SECSIZE - tp = bread(dev, (daddr_t)(SBOFF / size), SBSIZE, size); -#else SECSIZE - bp = bread(dev, SBLOCK, SBSIZE); - if (bp->b_flags & B_ERROR) { - mp->m_fs = NULL; + } + if (error = bread(devvp, SBLOCK, SBSIZE, &bp)) { + ump->um_fs = NULL; goto out; } fs = bp->b_un.b_fs; - if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || - fs->fs_bsize < sizeof(struct fs)) { - error = EINVAL; /* also needs translation */ + ump->um_fs = NULL; + error = EINVAL; /* XXX also needs translation */ goto out; } - mp->m_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, + 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)mp->m_fs, + bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, (u_int)fs->fs_sbsize); brelse(bp); bp = NULL; - fs = mp->m_fs; - fs->fs_ronly = (ronly != 0); + fs = ump->um_fs; + fs->fs_ronly = ronly; if (ronly == 0) fs->fs_fmod = 1; if (havepart) { @@ -190,10 +238,6 @@ mountfs(dev, ronly, ip) blks = howmany(fs->fs_cssize, fs->fs_fsize); base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, M_WAITOK); - if (space == NULL) { - error = ENOMEM; - goto out; - } for (i = 0; i < blks; i += fs->fs_frag) { size = fs->fs_bsize; if (i + fs->fs_frag > blks) @@ -202,8 +246,8 @@ mountfs(dev, ronly, ip) tp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size, fs->fs_dbsize); #else SECSIZE - bp = bread(dev, fsbtodb(fs, fs->fs_csaddr + i), size); - if (bp->b_flags&B_ERROR) { + error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, &bp); + if (error) { free((caddr_t)base, M_SUPERBLK); goto out; } @@ -213,64 +257,53 @@ mountfs(dev, ronly, ip) brelse(bp); bp = NULL; } - mp->m_inodp = ip; - if (ip) { - ip->i_flag |= IMOUNT; - cacheinval(ip); - iunlock(ip); - } + 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; + ump->um_mountp = mp; + ump->um_dev = dev; + ump->um_devvp = devvp; + ump->um_qinod = NULL; + /* 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 (fs); + return (0); out: if (needclose) - (void) closei(dev, IFBLK, ronly? FREAD : FREAD|FWRITE); - if (mp->m_fs) { - free((caddr_t)mp->m_fs, M_SUPERBLK); - mp->m_fs = NULL; + (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, + (struct ucred *)0); + if (ump->um_fs) { + free((caddr_t)ump->um_fs, M_SUPERBLK); + ump->um_fs = NULL; } if (bp) brelse(bp); - u.u_error = error ? error : EIO; /* XXX */ - return ((struct fs *) NULL); + return (error); } -umount() -{ - struct a { - char *fspec; - } *uap = (struct a *)u.u_ap; - u.u_error = unmount1(uap->fspec, 0); -} - -unmount1(fname, forcibly) - caddr_t fname; - int forcibly; +/* + * unmount system call + */ +ufs_unmount(mp, flags) + struct mount *mp; + int flags; { - dev_t dev; - register struct mount *mp; - int error; - register struct inode *ip; + register struct ufsmount *ump; register struct fs *fs; + dev_t dev; + int error, ronly; - forcibly = 0; /* XXX */ - forcibly = 0; /* XXX */ - error = getmdev(&dev, fname); - if (error) - return (error); - for (mp = &mount[0]; mp < &mount[NMOUNT]; mp++) - if (mp->m_fs != NULL && dev == mp->m_dev) - goto found; - return (EINVAL); -found: - xumount(dev); /* remove unused sticky files from text table */ - nchinval(dev); /* flush the name cache */ - update(); + if (flags & MNT_FORCE) + return (EINVAL); + ump = VFSTOUFS(mp); + dev = ump->um_dev; #ifdef QUOTA if ((error = iflush(dev, mp->m_qinod)) && !forcibly) #else @@ -278,40 +311,152 @@ found: #endif return (error); #ifdef QUOTA - closedq(mp); + (void)closedq(ump); /* * 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); #endif - ip = mp->m_inodp; - ip->i_flag &= ~IMOUNT; - fs = mp->m_fs; + fs = ump->um_fs; + ronly = !fs->fs_ronly; free((caddr_t)fs->fs_csp[0], M_SUPERBLK); - free((caddr_t)mp->m_fs, M_SUPERBLK); - mp->m_fs = NULL; - mp->m_dev = NODEV; - mpurge(mp - &mount[0]); error = closei(dev, IFBLK, fs->fs_ronly? FREAD : FREAD|FWRITE); irele(ip); return (error); } -sbupdate(mp) +/* + * Return root of a filesystem + */ +ufs_root(mp, vpp) + struct mount *mp; + struct vnode **vpp; +{ + struct inode tip, *ip; + int error; + + tip.i_dev = VFSTOUFS(mp)->um_dev; + tip.i_vnode.v_mount = mp; + error = iget(&tip, (ino_t)ROOTINO, &ip); + if (error) + return (error); + *vpp = ITOV(ip); + return (0); +} + +/* + * 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_flags = mp->m_flag &~ (M_MLOCK|M_MWAIT); + 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); + if (sbp->f_bavail < 0) + sbp->f_bavail = 0; + sbp->f_files = fs->fs_ncg * fs->fs_ipg; + sbp->f_ffree = fs->fs_cstotal.cs_nifree; + sbp->f_fsid = mp->m_fsid; + 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); + 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; + * initiate the writing of the super block if it has been modified. + */ +ufs_sync(mp, waitfor) struct mount *mp; + int waitfor; { - register struct fs *fs = mp->m_fs; + register struct inode *ip; + register struct ufsmount *ump = VFSTOUFS(mp); + register struct fs *fs; + int error = 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 + * 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; + error = sbupdate(ump, waitfor); + } + /* + * Write back each (modified) inode. + */ + for (ip = inode; ip < inodeNINODE; ip++) { + if (ip->i_devvp != ump->um_devvp || + (ip->i_flag & ILOCKED) != 0 || ITOV(ip)->v_count == 0 || + (ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0) + continue; + ip->i_flag |= ILOCKED; + ITOV(ip)->v_count++; + error = iupdat(ip, &time, &time, waitfor == MNT_WAIT); + iput(ip); + } + updlock = 0; + /* + * Force stale buffer cache information to be flushed. + */ + bflush(ump->um_devvp->v_rdev); + return (error); +} + +/* + * 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; + 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->m_dev, SBLOCK, (int)fs->fs_sbsize); + 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 */ @@ -324,7 +469,10 @@ sbupdate(mp) bp->b_un.b_fs->fs_sparecon[0] = 0; #endif #endif SECSIZE - bwrite(bp); + 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) { @@ -335,46 +483,118 @@ sbupdate(mp) bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size, fs->fs_dbsize); #else SECSIZE - bp = getblk(mp->m_dev, fsbtodb(fs, fs->fs_csaddr + i), size); + 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); } /* - * Common code for mount and umount. + * 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 + */ +ufs_fhtovp(mp, fhp, vpp) + struct mount *mp; + struct fid *fhp; + struct vnode **vpp; +{ + register struct ufid *ufhp; + struct inode tip, *ip; + int error; + + ufhp = (struct ufid *)fhp; + tip.i_dev = VFSTOUFS(mp)->um_dev; + tip.i_vnode.v_mount = mp; + if (error = iget(&tip, ufhp->ufid_ino, &ip)) { + *vpp = NULL; + return (error); + } + if (ip->i_gen != ufhp->ufid_gen) { + iput(ip); + *vpp = NULL; + return (EINVAL); + } + *vpp = ITOV(ip); + return (0); +} + +/* + * Vnode pointer to File handle, should never happen. + */ +/* ARGSUSED */ +ufs_vptofh(mp, fhp, vpp) + struct mount *mp; + struct fid *fhp; + struct vnode **vpp; +{ + + return (EINVAL); +} + +/* + * 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. */ -getmdev(pdev, fname) +getmdev(devvpp, fname, ndp) + struct vnode **devvpp; caddr_t fname; - dev_t *pdev; + register struct nameidata *ndp; { - dev_t dev; - register struct inode *ip; - register struct nameidata *ndp = &u.u_nd; + register struct vnode *vp; + int error; - if (u.u_error = suser(u.u_cred, &u.u_acflag)) - return (u.u_error); - ndp->ni_nameiop = LOOKUP | FOLLOW; + ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; ndp->ni_segflg = UIO_USERSPACE; ndp->ni_dirp = fname; - ip = namei(ndp); - if (ip == NULL) { - if (u.u_error == ENOENT) - return (ENODEV); /* needs translation */ - return (u.u_error); + if (error = namei(ndp)) { + if (error == ENOENT) + return (ENODEV); /* needs translation */ + return (error); } - if ((ip->i_mode&IFMT) != IFBLK) { - iput(ip); + vp = ndp->ni_vp; + if (vp->v_type != VBLK) { + vput(vp); return (ENOTBLK); } - dev = (dev_t)ip->i_rdev; - iput(ip); - if (major(dev) >= nblkdev) + if (major(vp->v_rdev) >= nblkdev) return (ENXIO); - *pdev = dev; + iunlock(VTOI(vp)); + *devvpp = vp; return (0); }