123400Smckusick /* 2*50264Skarels * Copyright (c) 1989, 1991 The Regents of the University of California. 337737Smckusick * All rights reserved. 423400Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*50264Skarels * @(#)lfs_vfsops.c 7.56 (Berkeley) 06/28/91 823400Smckusick */ 912795Ssam 1017100Sbloom #include "param.h" 1117100Sbloom #include "systm.h" 1247571Skarels #include "namei.h" 1341314Smckusick #include "proc.h" 1437737Smckusick #include "kernel.h" 1537737Smckusick #include "vnode.h" 1640653Smckusick #include "specdev.h" 1737737Smckusick #include "mount.h" 1817100Sbloom #include "buf.h" 1917100Sbloom #include "file.h" 2037737Smckusick #include "disklabel.h" 2130749Skarels #include "ioctl.h" 2237737Smckusick #include "errno.h" 2331660Smckusick #include "malloc.h" 2412795Ssam 2547571Skarels #include "quota.h" 2647571Skarels #include "fs.h" 2747571Skarels #include "ufsmount.h" 2847571Skarels #include "inode.h" 2947571Skarels 3037737Smckusick struct vfsops ufs_vfsops = { 3137737Smckusick ufs_mount, 3239043Smckusick ufs_start, 3337737Smckusick ufs_unmount, 3437737Smckusick ufs_root, 3541314Smckusick ufs_quotactl, 3637737Smckusick ufs_statfs, 3737737Smckusick ufs_sync, 3837737Smckusick ufs_fhtovp, 3939437Smckusick ufs_vptofh, 4039437Smckusick ufs_init 4137737Smckusick }; 4237737Smckusick 4337737Smckusick /* 4448359Smckusick * Flag to allow forcible unmounting. 4548359Smckusick */ 4648359Smckusick int doforce = 1; 4748359Smckusick 4848359Smckusick /* 4939336Smckusick * Called by vfs_mountroot when ufs is going to be mounted as root. 5037737Smckusick * 5139336Smckusick * Name is updated by mount(8) after booting. 5237737Smckusick */ 5339297Smckusick #define ROOTNAME "root_device" 5437737Smckusick 5537737Smckusick ufs_mountroot() 5612795Ssam { 5737737Smckusick register struct mount *mp; 5837737Smckusick extern struct vnode *rootvp; 5948036Smckusick struct proc *p = curproc; /* XXX */ 6037737Smckusick struct ufsmount *ump; 6112795Ssam register struct fs *fs; 6237737Smckusick u_int size; 6337737Smckusick int error; 6412795Ssam 6537737Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 6637737Smckusick M_MOUNT, M_WAITOK); 6741397Smckusick mp->mnt_op = &ufs_vfsops; 6841397Smckusick mp->mnt_flag = MNT_RDONLY; 6941397Smckusick mp->mnt_exroot = 0; 7041397Smckusick mp->mnt_mounth = NULLVP; 7148036Smckusick error = mountfs(rootvp, mp, p); 7237737Smckusick if (error) { 7337737Smckusick free((caddr_t)mp, M_MOUNT); 7437737Smckusick return (error); 7512795Ssam } 7639336Smckusick if (error = vfs_lock(mp)) { 7748036Smckusick (void)ufs_unmount(mp, 0, p); 7837737Smckusick free((caddr_t)mp, M_MOUNT); 7937737Smckusick return (error); 8021013Smckusick } 8139336Smckusick rootfs = mp; 8241397Smckusick mp->mnt_next = mp; 8341397Smckusick mp->mnt_prev = mp; 8441397Smckusick mp->mnt_vnodecovered = NULLVP; 8537737Smckusick ump = VFSTOUFS(mp); 8637737Smckusick fs = ump->um_fs; 8740346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 8837737Smckusick fs->fs_fsmnt[0] = '/'; 8941397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 9041397Smckusick MNAMELEN); 9141397Smckusick (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 9241397Smckusick &size); 9341397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 9448036Smckusick (void) ufs_statfs(mp, &mp->mnt_stat, p); 9537737Smckusick vfs_unlock(mp); 9637737Smckusick inittodr(fs->fs_time); 9737737Smckusick return (0); 9837737Smckusick } 9937737Smckusick 10037737Smckusick /* 10137737Smckusick * VFS Operations. 10237737Smckusick * 10337737Smckusick * mount system call 10437737Smckusick */ 10548036Smckusick ufs_mount(mp, path, data, ndp, p) 10640346Smckusick register struct mount *mp; 10737737Smckusick char *path; 10837737Smckusick caddr_t data; 10937737Smckusick struct nameidata *ndp; 11048036Smckusick struct proc *p; 11137737Smckusick { 11237737Smckusick struct vnode *devvp; 11337737Smckusick struct ufs_args args; 11437737Smckusick struct ufsmount *ump; 11537737Smckusick register struct fs *fs; 11637737Smckusick u_int size; 11737737Smckusick int error; 11837737Smckusick 11937737Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 12037737Smckusick return (error); 12140371Smckusick /* 12240371Smckusick * Process export requests. 12340371Smckusick */ 12441397Smckusick if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { 12541397Smckusick if (args.exflags & MNT_EXPORTED) 12641397Smckusick mp->mnt_flag |= MNT_EXPORTED; 12740371Smckusick else 12841397Smckusick mp->mnt_flag &= ~MNT_EXPORTED; 12941397Smckusick if (args.exflags & MNT_EXRDONLY) 13041397Smckusick mp->mnt_flag |= MNT_EXRDONLY; 13140371Smckusick else 13241397Smckusick mp->mnt_flag &= ~MNT_EXRDONLY; 13341397Smckusick mp->mnt_exroot = args.exroot; 13440371Smckusick } 135*50264Skarels /* 136*50264Skarels * If updating, check whether changing from read-only to 137*50264Skarels * read/write; if there is no device name, that's all we do. 138*50264Skarels */ 139*50264Skarels if (mp->mnt_flag & MNT_UPDATE) { 14039336Smckusick ump = VFSTOUFS(mp); 14139336Smckusick fs = ump->um_fs; 14241397Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 14339336Smckusick fs->fs_ronly = 0; 14440371Smckusick if (args.fspec == 0) 14540371Smckusick return (0); 146*50264Skarels } 147*50264Skarels /* 148*50264Skarels * Not an update, or updating the name: look up the name 149*50264Skarels * and verify that it refers to a sensible block device. 150*50264Skarels */ 151*50264Skarels ndp->ni_nameiop = LOOKUP | FOLLOW; 152*50264Skarels ndp->ni_segflg = UIO_USERSPACE; 153*50264Skarels ndp->ni_dirp = args.fspec; 154*50264Skarels if (error = namei(ndp, p)) 155*50264Skarels return (error); 156*50264Skarels devvp = ndp->ni_vp; 157*50264Skarels if (devvp->v_type != VBLK) { 158*50264Skarels vrele(devvp); 159*50264Skarels return (ENOTBLK); 160*50264Skarels } 161*50264Skarels if (major(devvp->v_rdev) >= nblkdev) { 162*50264Skarels vrele(devvp); 163*50264Skarels return (ENXIO); 164*50264Skarels } 165*50264Skarels if ((mp->mnt_flag & MNT_UPDATE) == 0) 166*50264Skarels error = mountfs(devvp, mp, p); 167*50264Skarels else { 16839336Smckusick if (devvp != ump->um_devvp) 16939336Smckusick error = EINVAL; /* needs translation */ 17042858Smckusick else 17142858Smckusick vrele(devvp); 17239336Smckusick } 17337737Smckusick if (error) { 17437737Smckusick vrele(devvp); 17537737Smckusick return (error); 17632721Smckusick } 17737737Smckusick ump = VFSTOUFS(mp); 17837737Smckusick fs = ump->um_fs; 17937737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 18037737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 18141397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 18241397Smckusick MNAMELEN); 18341397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 18441397Smckusick &size); 18541397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 18648036Smckusick (void) ufs_statfs(mp, &mp->mnt_stat, p); 18737737Smckusick return (0); 18812795Ssam } 18912795Ssam 19037737Smckusick /* 19137737Smckusick * Common code for mount and mountroot 19237737Smckusick */ 19348036Smckusick mountfs(devvp, mp, p) 19440376Smckusick register struct vnode *devvp; 19537737Smckusick struct mount *mp; 19648036Smckusick struct proc *p; 19712795Ssam { 19841314Smckusick register struct ufsmount *ump = (struct ufsmount *)0; 19937737Smckusick struct buf *bp = NULL; 20012795Ssam register struct fs *fs; 20137737Smckusick dev_t dev = devvp->v_rdev; 20230749Skarels struct partinfo dpart; 20337737Smckusick caddr_t base, space; 20430749Skarels int havepart = 0, blks; 20537737Smckusick int error, i, size; 20621013Smckusick int needclose = 0; 20741397Smckusick int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 20845652Smckusick extern struct vnode *rootvp; 20912795Ssam 21040376Smckusick /* 21140376Smckusick * Disallow multiple mounts of the same device. 21245652Smckusick * Disallow mounting of a device that is currently in use 21345652Smckusick * (except for root, which might share swap device for miniroot). 21440376Smckusick * Flush out any old buffers remaining from a previous use. 21540376Smckusick */ 21640376Smckusick if (error = mountedon(devvp)) 21740376Smckusick return (error); 21845652Smckusick if (vcount(devvp) > 1 && devvp != rootvp) 21940376Smckusick return (EBUSY); 22040376Smckusick vinvalbuf(devvp, 1); 22148036Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) 22237737Smckusick return (error); 22321013Smckusick needclose = 1; 22448036Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 22537737Smckusick size = DEV_BSIZE; 22648036Smckusick else { 22730749Skarels havepart = 1; 22830749Skarels size = dpart.disklab->d_secsize; 22937737Smckusick } 23041314Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 23112795Ssam goto out; 23234421Skarels fs = bp->b_un.b_fs; 23330749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 23430749Skarels fs->fs_bsize < sizeof(struct fs)) { 23541314Smckusick error = EINVAL; /* XXX needs translation */ 23616639Skarels goto out; 23716639Skarels } 23841314Smckusick ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 23937737Smckusick ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 24034473Smckusick M_WAITOK); 24137737Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 24212795Ssam (u_int)fs->fs_sbsize); 24339675Smckusick if (fs->fs_sbsize < SBSIZE) 24439675Smckusick bp->b_flags |= B_INVAL; 24534421Skarels brelse(bp); 24634421Skarels bp = NULL; 24737737Smckusick fs = ump->um_fs; 24837737Smckusick fs->fs_ronly = ronly; 24912795Ssam if (ronly == 0) 25012795Ssam fs->fs_fmod = 1; 25130749Skarels if (havepart) { 25230749Skarels dpart.part->p_fstype = FS_BSDFFS; 25330749Skarels dpart.part->p_fsize = fs->fs_fsize; 25430749Skarels dpart.part->p_frag = fs->fs_frag; 25531385Skarels dpart.part->p_cpg = fs->fs_cpg; 25630749Skarels } 25712795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 25834473Smckusick base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 25934473Smckusick M_WAITOK); 26012795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 26112795Ssam size = fs->fs_bsize; 26212795Ssam if (i + fs->fs_frag > blks) 26312795Ssam size = (blks - i) * fs->fs_fsize; 26438776Smckusick error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 26538776Smckusick NOCRED, &bp); 26637737Smckusick if (error) { 26734473Smckusick free((caddr_t)base, M_SUPERBLK); 26812795Ssam goto out; 26912795Ssam } 27034421Skarels bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 27117225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 27212795Ssam space += size; 27334421Skarels brelse(bp); 27434421Skarels bp = NULL; 27512795Ssam } 27641397Smckusick mp->mnt_data = (qaddr_t)ump; 27741397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 27841397Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 27941397Smckusick mp->mnt_flag |= MNT_LOCAL; 28037737Smckusick ump->um_mountp = mp; 28137737Smckusick ump->um_dev = dev; 28237737Smckusick ump->um_devvp = devvp; 28341314Smckusick for (i = 0; i < MAXQUOTAS; i++) 28441314Smckusick ump->um_quotas[i] = NULLVP; 28540653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 28637737Smckusick 28730383Smckusick /* Sanity checks for old file systems. XXX */ 28830383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 28930383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 29034145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 29134145Smckusick fs->fs_nrpos = 8; /* XXX */ 29237737Smckusick return (0); 29312795Ssam out: 29440872Smckusick if (bp) 29540872Smckusick brelse(bp); 29632721Smckusick if (needclose) 29748036Smckusick (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 29841314Smckusick if (ump) { 29937737Smckusick free((caddr_t)ump->um_fs, M_SUPERBLK); 30041314Smckusick free((caddr_t)ump, M_UFSMNT); 30141397Smckusick mp->mnt_data = (qaddr_t)0; 30232721Smckusick } 30337737Smckusick return (error); 30412795Ssam } 30512795Ssam 30639043Smckusick /* 30739043Smckusick * Make a filesystem operational. 30839043Smckusick * Nothing to do at the moment. 30939043Smckusick */ 31039390Smckusick /* ARGSUSED */ 31148036Smckusick ufs_start(mp, flags, p) 31239043Smckusick struct mount *mp; 31339043Smckusick int flags; 31448036Smckusick struct proc *p; 31539043Smckusick { 31612795Ssam 31739043Smckusick return (0); 31839043Smckusick } 31939043Smckusick 32037737Smckusick /* 32137737Smckusick * unmount system call 32237737Smckusick */ 32348036Smckusick ufs_unmount(mp, mntflags, p) 32437737Smckusick struct mount *mp; 32541314Smckusick int mntflags; 32648036Smckusick struct proc *p; 32712795Ssam { 32837737Smckusick register struct ufsmount *ump; 32937737Smckusick register struct fs *fs; 33041314Smckusick int i, error, ronly, flags = 0; 33112795Ssam 33248065Smckusick if (mntflags & MNT_FORCE) { 33348359Smckusick if (!doforce || mp == rootfs) 33448065Smckusick return (EINVAL); 33541314Smckusick flags |= FORCECLOSE; 33648065Smckusick } 33739675Smckusick mntflushbuf(mp, 0); 33839675Smckusick if (mntinvalbuf(mp)) 33939675Smckusick return (EBUSY); 34037737Smckusick ump = VFSTOUFS(mp); 34112795Ssam #ifdef QUOTA 34241397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 34341314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 34439898Smckusick return (error); 34541314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 34641314Smckusick if (ump->um_quotas[i] == NULLVP) 34741314Smckusick continue; 34850114Smckusick quotaoff(p, mp, i); 34941314Smckusick } 35039898Smckusick /* 35141314Smckusick * Here we fall through to vflush again to ensure 35241314Smckusick * that we have gotten rid of all the system vnodes. 35339898Smckusick */ 35441314Smckusick } 35512795Ssam #endif 35641314Smckusick if (error = vflush(mp, NULLVP, flags)) 35739898Smckusick return (error); 35837737Smckusick fs = ump->um_fs; 35937737Smckusick ronly = !fs->fs_ronly; 36040653Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 36148036Smckusick error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 36248036Smckusick NOCRED, p); 36337737Smckusick vrele(ump->um_devvp); 36441314Smckusick free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 36541314Smckusick free((caddr_t)fs, M_SUPERBLK); 36641314Smckusick free((caddr_t)ump, M_UFSMNT); 36741397Smckusick mp->mnt_data = (qaddr_t)0; 36841397Smckusick mp->mnt_flag &= ~MNT_LOCAL; 36930749Skarels return (error); 37012795Ssam } 37112795Ssam 37237737Smckusick /* 37340376Smckusick * Check to see if a filesystem is mounted on a block device. 37440376Smckusick */ 37540376Smckusick mountedon(vp) 37640376Smckusick register struct vnode *vp; 37740376Smckusick { 37840376Smckusick register struct vnode *vq; 37940376Smckusick 38040653Smckusick if (vp->v_specflags & SI_MOUNTEDON) 38140376Smckusick return (EBUSY); 38240376Smckusick if (vp->v_flag & VALIASED) { 38340653Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 38440376Smckusick if (vq->v_rdev != vp->v_rdev || 38540376Smckusick vq->v_type != vp->v_type) 38640376Smckusick continue; 38740653Smckusick if (vq->v_specflags & SI_MOUNTEDON) 38840376Smckusick return (EBUSY); 38940376Smckusick } 39040376Smckusick } 39140376Smckusick return (0); 39240376Smckusick } 39340376Smckusick 39440376Smckusick /* 39537737Smckusick * Return root of a filesystem 39637737Smckusick */ 39737737Smckusick ufs_root(mp, vpp) 39812795Ssam struct mount *mp; 39937737Smckusick struct vnode **vpp; 40012795Ssam { 40139390Smckusick register struct inode *ip; 40239390Smckusick struct inode *nip; 40339390Smckusick struct vnode tvp; 40437737Smckusick int error; 40537737Smckusick 40639390Smckusick tvp.v_mount = mp; 40739390Smckusick ip = VTOI(&tvp); 40839390Smckusick ip->i_vnode = &tvp; 40939390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 41039390Smckusick error = iget(ip, (ino_t)ROOTINO, &nip); 41137737Smckusick if (error) 41237737Smckusick return (error); 41339390Smckusick *vpp = ITOV(nip); 41437737Smckusick return (0); 41537737Smckusick } 41637737Smckusick 41737737Smckusick /* 41841314Smckusick * Do operations associated with quotas 41941314Smckusick */ 42048036Smckusick ufs_quotactl(mp, cmds, uid, arg, p) 42141314Smckusick struct mount *mp; 42241314Smckusick int cmds; 42341314Smckusick uid_t uid; 42441314Smckusick caddr_t arg; 42548036Smckusick struct proc *p; 42641314Smckusick { 42741314Smckusick struct ufsmount *ump = VFSTOUFS(mp); 42841314Smckusick int cmd, type, error; 42941314Smckusick 43041314Smckusick #ifndef QUOTA 43141314Smckusick return (EOPNOTSUPP); 43241314Smckusick #else 43341314Smckusick if (uid == -1) 43447571Skarels uid = p->p_cred->p_ruid; 43541314Smckusick cmd = cmds >> SUBCMDSHIFT; 43641314Smckusick 43741314Smckusick switch (cmd) { 43841314Smckusick case Q_GETQUOTA: 43941314Smckusick case Q_SYNC: 44047571Skarels if (uid == p->p_cred->p_ruid) 44141314Smckusick break; 44241314Smckusick /* fall through */ 44341314Smckusick default: 44447571Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 44541314Smckusick return (error); 44641314Smckusick } 44741314Smckusick 44841314Smckusick type = cmd & SUBCMDMASK; 44941314Smckusick if ((u_int)type >= MAXQUOTAS) 45041314Smckusick return (EINVAL); 45141314Smckusick 45241314Smckusick switch (cmd) { 45341314Smckusick 45441314Smckusick case Q_QUOTAON: 45547571Skarels return (quotaon(p, mp, type, arg)); 45641314Smckusick 45741314Smckusick case Q_QUOTAOFF: 45841314Smckusick if (vfs_busy(mp)) 45941314Smckusick return (0); 46050114Smckusick error = quotaoff(p, mp, type); 46141314Smckusick vfs_unbusy(mp); 46241314Smckusick return (error); 46341314Smckusick 46441314Smckusick case Q_SETQUOTA: 46541314Smckusick return (setquota(mp, uid, type, arg)); 46641314Smckusick 46741314Smckusick case Q_SETUSE: 46841314Smckusick return (setuse(mp, uid, type, arg)); 46941314Smckusick 47041314Smckusick case Q_GETQUOTA: 47141314Smckusick return (getquota(mp, uid, type, arg)); 47241314Smckusick 47341314Smckusick case Q_SYNC: 47441314Smckusick if (vfs_busy(mp)) 47541314Smckusick return (0); 47641314Smckusick error = qsync(mp); 47741314Smckusick vfs_unbusy(mp); 47841314Smckusick return (error); 47941314Smckusick 48041314Smckusick default: 48141314Smckusick return (EINVAL); 48241314Smckusick } 48341314Smckusick /* NOTREACHED */ 48441314Smckusick #endif 48541314Smckusick } 48641314Smckusick 48741314Smckusick /* 48837737Smckusick * Get file system statistics. 48937737Smckusick */ 49048036Smckusick ufs_statfs(mp, sbp, p) 49137737Smckusick struct mount *mp; 49237737Smckusick register struct statfs *sbp; 49348036Smckusick struct proc *p; 49437737Smckusick { 49537737Smckusick register struct ufsmount *ump; 49637737Smckusick register struct fs *fs; 49737737Smckusick 49837737Smckusick ump = VFSTOUFS(mp); 49937737Smckusick fs = ump->um_fs; 50037737Smckusick if (fs->fs_magic != FS_MAGIC) 50137737Smckusick panic("ufs_statfs"); 50237737Smckusick sbp->f_type = MOUNT_UFS; 50337737Smckusick sbp->f_fsize = fs->fs_fsize; 50437737Smckusick sbp->f_bsize = fs->fs_bsize; 50537737Smckusick sbp->f_blocks = fs->fs_dsize; 50637737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 50737737Smckusick fs->fs_cstotal.cs_nffree; 50837737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 50937737Smckusick (fs->fs_dsize - sbp->f_bfree); 51039350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 51137737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 51241397Smckusick if (sbp != &mp->mnt_stat) { 51341397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 51440346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 51541397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 51640346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 51740346Smckusick } 51837737Smckusick return (0); 51937737Smckusick } 52037737Smckusick 52137737Smckusick int syncprt = 0; 52237737Smckusick 52337737Smckusick /* 52437737Smckusick * Go through the disk queues to initiate sandbagged IO; 52537737Smckusick * go through the inodes to write those that have been modified; 52637737Smckusick * initiate the writing of the super block if it has been modified. 52741314Smckusick * 52841314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 52937737Smckusick */ 53037737Smckusick ufs_sync(mp, waitfor) 53137737Smckusick struct mount *mp; 53237737Smckusick int waitfor; 53337737Smckusick { 53439390Smckusick register struct vnode *vp; 53537737Smckusick register struct inode *ip; 53637737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 53737737Smckusick register struct fs *fs; 53839596Smckusick int error, allerror = 0; 53937737Smckusick 54037737Smckusick if (syncprt) 54137737Smckusick bufstats(); 54237737Smckusick fs = ump->um_fs; 54337737Smckusick /* 54437737Smckusick * Write back modified superblock. 54537737Smckusick * Consistency check that the superblock 54637737Smckusick * is still in the buffer cache. 54737737Smckusick */ 54837737Smckusick if (fs->fs_fmod != 0) { 54937737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 55037737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 55137737Smckusick panic("update: rofs mod"); 55237737Smckusick } 55337737Smckusick fs->fs_fmod = 0; 55437737Smckusick fs->fs_time = time.tv_sec; 55541510Smckusick allerror = sbupdate(ump, waitfor); 55637737Smckusick } 55737737Smckusick /* 55837737Smckusick * Write back each (modified) inode. 55937737Smckusick */ 56039877Smckusick loop: 56141462Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 56241462Smckusick /* 56341462Smckusick * If the vnode that we are about to sync is no longer 56441462Smckusick * associated with this mount point, start over. 56541462Smckusick */ 56641462Smckusick if (vp->v_mount != mp) 56741462Smckusick goto loop; 56848359Smckusick if (VOP_ISLOCKED(vp)) 56948359Smckusick continue; 57039390Smckusick ip = VTOI(vp); 57139877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 57239877Smckusick vp->v_dirtyblkhd == NULL) 57337737Smckusick continue; 57439877Smckusick if (vget(vp)) 57539877Smckusick goto loop; 57639877Smckusick if (vp->v_dirtyblkhd) 57739877Smckusick vflushbuf(vp, 0); 57839877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && 57939877Smckusick (error = iupdat(ip, &time, &time, 0))) 58039596Smckusick allerror = error; 58139596Smckusick vput(vp); 58237737Smckusick } 58337737Smckusick /* 58439675Smckusick * Force stale file system control information to be flushed. 58537737Smckusick */ 58639675Smckusick vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 58741314Smckusick #ifdef QUOTA 58841314Smckusick qsync(mp); 58941314Smckusick #endif 59039596Smckusick return (allerror); 59137737Smckusick } 59237737Smckusick 59337737Smckusick /* 59437737Smckusick * Write a superblock and associated information back to disk. 59537737Smckusick */ 59637737Smckusick sbupdate(mp, waitfor) 59737737Smckusick struct ufsmount *mp; 59837737Smckusick int waitfor; 59937737Smckusick { 60037737Smckusick register struct fs *fs = mp->um_fs; 60112795Ssam register struct buf *bp; 60212795Ssam int blks; 60312795Ssam caddr_t space; 60437737Smckusick int i, size, error = 0; 60512795Ssam 60637737Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 60712795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 60834145Smckusick /* Restore compatibility to old file systems. XXX */ 60934145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 61034145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 61137737Smckusick if (waitfor == MNT_WAIT) 61237737Smckusick error = bwrite(bp); 61337737Smckusick else 61437737Smckusick bawrite(bp); 61512795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 61612795Ssam space = (caddr_t)fs->fs_csp[0]; 61712795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 61812795Ssam size = fs->fs_bsize; 61912795Ssam if (i + fs->fs_frag > blks) 62012795Ssam size = (blks - i) * fs->fs_fsize; 62137737Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 62212795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 62312795Ssam space += size; 62437737Smckusick if (waitfor == MNT_WAIT) 62537737Smckusick error = bwrite(bp); 62637737Smckusick else 62737737Smckusick bawrite(bp); 62812795Ssam } 62937737Smckusick return (error); 63012795Ssam } 63112795Ssam 63212795Ssam /* 63337737Smckusick * Print out statistics on the current allocation of the buffer pool. 63437737Smckusick * Can be enabled to print out on every ``sync'' by setting "syncprt" 63537737Smckusick * above. 63637737Smckusick */ 63737737Smckusick bufstats() 63837737Smckusick { 63937737Smckusick int s, i, j, count; 64037737Smckusick register struct buf *bp, *dp; 64137737Smckusick int counts[MAXBSIZE/CLBYTES+1]; 64237737Smckusick static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 64337737Smckusick 64437737Smckusick for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 64537737Smckusick count = 0; 64637737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 64737737Smckusick counts[j] = 0; 64837737Smckusick s = splbio(); 64937737Smckusick for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 65037737Smckusick counts[dp->b_bufsize/CLBYTES]++; 65137737Smckusick count++; 65237737Smckusick } 65337737Smckusick splx(s); 65437737Smckusick printf("%s: total-%d", bname[i], count); 65537737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 65637737Smckusick if (counts[j] != 0) 65737737Smckusick printf(", %d-%d", j * CLBYTES, counts[j]); 65837737Smckusick printf("\n"); 65937737Smckusick } 66037737Smckusick } 66137737Smckusick 66237737Smckusick /* 66337737Smckusick * File handle to vnode 66438453Smckusick * 66538453Smckusick * Have to be really careful about stale file handles: 66638453Smckusick * - check that the inode number is in range 66738453Smckusick * - call iget() to get the locked inode 66838453Smckusick * - check for an unallocated inode (i_mode == 0) 66938453Smckusick * - check that the generation number matches 67037737Smckusick */ 67137737Smckusick ufs_fhtovp(mp, fhp, vpp) 67238453Smckusick register struct mount *mp; 67337737Smckusick struct fid *fhp; 67437737Smckusick struct vnode **vpp; 67537737Smckusick { 67637737Smckusick register struct ufid *ufhp; 67738453Smckusick register struct fs *fs; 67839390Smckusick register struct inode *ip; 67939390Smckusick struct inode *nip; 68039390Smckusick struct vnode tvp; 68137737Smckusick int error; 68237737Smckusick 68337737Smckusick ufhp = (struct ufid *)fhp; 68438453Smckusick fs = VFSTOUFS(mp)->um_fs; 68538453Smckusick if (ufhp->ufid_ino < ROOTINO || 68638453Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 68741397Smckusick *vpp = NULLVP; 68838453Smckusick return (EINVAL); 68938453Smckusick } 69039390Smckusick tvp.v_mount = mp; 69139390Smckusick ip = VTOI(&tvp); 69239390Smckusick ip->i_vnode = &tvp; 69339390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 69439390Smckusick if (error = iget(ip, ufhp->ufid_ino, &nip)) { 69541397Smckusick *vpp = NULLVP; 69637737Smckusick return (error); 69737737Smckusick } 69839390Smckusick ip = nip; 69938453Smckusick if (ip->i_mode == 0) { 70038453Smckusick iput(ip); 70141397Smckusick *vpp = NULLVP; 70238453Smckusick return (EINVAL); 70338453Smckusick } 70437737Smckusick if (ip->i_gen != ufhp->ufid_gen) { 70537737Smckusick iput(ip); 70641397Smckusick *vpp = NULLVP; 70737737Smckusick return (EINVAL); 70837737Smckusick } 70937737Smckusick *vpp = ITOV(ip); 71037737Smckusick return (0); 71137737Smckusick } 71237737Smckusick 71337737Smckusick /* 71438355Smckusick * Vnode pointer to File handle 71537737Smckusick */ 71637737Smckusick /* ARGSUSED */ 71738143Smckusick ufs_vptofh(vp, fhp) 71838143Smckusick struct vnode *vp; 71937737Smckusick struct fid *fhp; 72037737Smckusick { 72138143Smckusick register struct inode *ip = VTOI(vp); 72238143Smckusick register struct ufid *ufhp; 72337737Smckusick 72438143Smckusick ufhp = (struct ufid *)fhp; 72538143Smckusick ufhp->ufid_len = sizeof(struct ufid); 72638143Smckusick ufhp->ufid_ino = ip->i_number; 72738143Smckusick ufhp->ufid_gen = ip->i_gen; 72838143Smckusick return (0); 72937737Smckusick } 730