123400Smckusick /* 237737Smckusick * Copyright (c) 1989 The Regents of the University of California. 337737Smckusick * All rights reserved. 423400Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*50114Smckusick * @(#)lfs_vfsops.c 7.55 (Berkeley) 06/21/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 } 13541397Smckusick if ((mp->mnt_flag & MNT_UPDATE) == 0) { 13648036Smckusick if ((error = getmdev(&devvp, args.fspec, ndp, p)) != 0) 13740371Smckusick return (error); 13848036Smckusick error = mountfs(devvp, mp, p); 13939336Smckusick } else { 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; 14439336Smckusick /* 14539336Smckusick * Verify that the specified device is the one that 14639336Smckusick * is really being used for the root file system. 14739336Smckusick */ 14840371Smckusick if (args.fspec == 0) 14940371Smckusick return (0); 15048036Smckusick if ((error = getmdev(&devvp, args.fspec, ndp, p)) != 0) 15140371Smckusick return (error); 15239336Smckusick if (devvp != ump->um_devvp) 15339336Smckusick error = EINVAL; /* needs translation */ 15442858Smckusick else 15542858Smckusick vrele(devvp); 15639336Smckusick } 15737737Smckusick if (error) { 15837737Smckusick vrele(devvp); 15937737Smckusick return (error); 16032721Smckusick } 16137737Smckusick ump = VFSTOUFS(mp); 16237737Smckusick fs = ump->um_fs; 16337737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 16437737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 16541397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 16641397Smckusick MNAMELEN); 16741397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 16841397Smckusick &size); 16941397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 17048036Smckusick (void) ufs_statfs(mp, &mp->mnt_stat, p); 17137737Smckusick return (0); 17212795Ssam } 17312795Ssam 17437737Smckusick /* 17537737Smckusick * Common code for mount and mountroot 17637737Smckusick */ 17748036Smckusick mountfs(devvp, mp, p) 17840376Smckusick register struct vnode *devvp; 17937737Smckusick struct mount *mp; 18048036Smckusick struct proc *p; 18112795Ssam { 18241314Smckusick register struct ufsmount *ump = (struct ufsmount *)0; 18337737Smckusick struct buf *bp = NULL; 18412795Ssam register struct fs *fs; 18537737Smckusick dev_t dev = devvp->v_rdev; 18630749Skarels struct partinfo dpart; 18737737Smckusick caddr_t base, space; 18830749Skarels int havepart = 0, blks; 18937737Smckusick int error, i, size; 19021013Smckusick int needclose = 0; 19141397Smckusick int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 19245652Smckusick extern struct vnode *rootvp; 19312795Ssam 19440376Smckusick /* 19540376Smckusick * Disallow multiple mounts of the same device. 19645652Smckusick * Disallow mounting of a device that is currently in use 19745652Smckusick * (except for root, which might share swap device for miniroot). 19840376Smckusick * Flush out any old buffers remaining from a previous use. 19940376Smckusick */ 20040376Smckusick if (error = mountedon(devvp)) 20140376Smckusick return (error); 20245652Smckusick if (vcount(devvp) > 1 && devvp != rootvp) 20340376Smckusick return (EBUSY); 20440376Smckusick vinvalbuf(devvp, 1); 20548036Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) 20637737Smckusick return (error); 20721013Smckusick needclose = 1; 20848036Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 20937737Smckusick size = DEV_BSIZE; 21048036Smckusick else { 21130749Skarels havepart = 1; 21230749Skarels size = dpart.disklab->d_secsize; 21337737Smckusick } 21441314Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 21512795Ssam goto out; 21634421Skarels fs = bp->b_un.b_fs; 21730749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 21830749Skarels fs->fs_bsize < sizeof(struct fs)) { 21941314Smckusick error = EINVAL; /* XXX needs translation */ 22016639Skarels goto out; 22116639Skarels } 22241314Smckusick ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 22337737Smckusick ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 22434473Smckusick M_WAITOK); 22537737Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 22612795Ssam (u_int)fs->fs_sbsize); 22739675Smckusick if (fs->fs_sbsize < SBSIZE) 22839675Smckusick bp->b_flags |= B_INVAL; 22934421Skarels brelse(bp); 23034421Skarels bp = NULL; 23137737Smckusick fs = ump->um_fs; 23237737Smckusick fs->fs_ronly = ronly; 23312795Ssam if (ronly == 0) 23412795Ssam fs->fs_fmod = 1; 23530749Skarels if (havepart) { 23630749Skarels dpart.part->p_fstype = FS_BSDFFS; 23730749Skarels dpart.part->p_fsize = fs->fs_fsize; 23830749Skarels dpart.part->p_frag = fs->fs_frag; 23931385Skarels dpart.part->p_cpg = fs->fs_cpg; 24030749Skarels } 24112795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 24234473Smckusick base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 24334473Smckusick M_WAITOK); 24412795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 24512795Ssam size = fs->fs_bsize; 24612795Ssam if (i + fs->fs_frag > blks) 24712795Ssam size = (blks - i) * fs->fs_fsize; 24838776Smckusick error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 24938776Smckusick NOCRED, &bp); 25037737Smckusick if (error) { 25134473Smckusick free((caddr_t)base, M_SUPERBLK); 25212795Ssam goto out; 25312795Ssam } 25434421Skarels bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 25517225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 25612795Ssam space += size; 25734421Skarels brelse(bp); 25834421Skarels bp = NULL; 25912795Ssam } 26041397Smckusick mp->mnt_data = (qaddr_t)ump; 26141397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 26241397Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 26341397Smckusick mp->mnt_flag |= MNT_LOCAL; 26437737Smckusick ump->um_mountp = mp; 26537737Smckusick ump->um_dev = dev; 26637737Smckusick ump->um_devvp = devvp; 26741314Smckusick for (i = 0; i < MAXQUOTAS; i++) 26841314Smckusick ump->um_quotas[i] = NULLVP; 26940653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 27037737Smckusick 27130383Smckusick /* Sanity checks for old file systems. XXX */ 27230383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 27330383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 27434145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 27534145Smckusick fs->fs_nrpos = 8; /* XXX */ 27637737Smckusick return (0); 27712795Ssam out: 27840872Smckusick if (bp) 27940872Smckusick brelse(bp); 28032721Smckusick if (needclose) 28148036Smckusick (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 28241314Smckusick if (ump) { 28337737Smckusick free((caddr_t)ump->um_fs, M_SUPERBLK); 28441314Smckusick free((caddr_t)ump, M_UFSMNT); 28541397Smckusick mp->mnt_data = (qaddr_t)0; 28632721Smckusick } 28737737Smckusick return (error); 28812795Ssam } 28912795Ssam 29039043Smckusick /* 29139043Smckusick * Make a filesystem operational. 29239043Smckusick * Nothing to do at the moment. 29339043Smckusick */ 29439390Smckusick /* ARGSUSED */ 29548036Smckusick ufs_start(mp, flags, p) 29639043Smckusick struct mount *mp; 29739043Smckusick int flags; 29848036Smckusick struct proc *p; 29939043Smckusick { 30012795Ssam 30139043Smckusick return (0); 30239043Smckusick } 30339043Smckusick 30437737Smckusick /* 30537737Smckusick * unmount system call 30637737Smckusick */ 30748036Smckusick ufs_unmount(mp, mntflags, p) 30837737Smckusick struct mount *mp; 30941314Smckusick int mntflags; 31048036Smckusick struct proc *p; 31112795Ssam { 31237737Smckusick register struct ufsmount *ump; 31337737Smckusick register struct fs *fs; 31441314Smckusick int i, error, ronly, flags = 0; 31512795Ssam 31648065Smckusick if (mntflags & MNT_FORCE) { 31748359Smckusick if (!doforce || mp == rootfs) 31848065Smckusick return (EINVAL); 31941314Smckusick flags |= FORCECLOSE; 32048065Smckusick } 32139675Smckusick mntflushbuf(mp, 0); 32239675Smckusick if (mntinvalbuf(mp)) 32339675Smckusick return (EBUSY); 32437737Smckusick ump = VFSTOUFS(mp); 32512795Ssam #ifdef QUOTA 32641397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 32741314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 32839898Smckusick return (error); 32941314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 33041314Smckusick if (ump->um_quotas[i] == NULLVP) 33141314Smckusick continue; 332*50114Smckusick quotaoff(p, mp, i); 33341314Smckusick } 33439898Smckusick /* 33541314Smckusick * Here we fall through to vflush again to ensure 33641314Smckusick * that we have gotten rid of all the system vnodes. 33739898Smckusick */ 33841314Smckusick } 33912795Ssam #endif 34041314Smckusick if (error = vflush(mp, NULLVP, flags)) 34139898Smckusick return (error); 34237737Smckusick fs = ump->um_fs; 34337737Smckusick ronly = !fs->fs_ronly; 34440653Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 34548036Smckusick error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 34648036Smckusick NOCRED, p); 34737737Smckusick vrele(ump->um_devvp); 34841314Smckusick free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 34941314Smckusick free((caddr_t)fs, M_SUPERBLK); 35041314Smckusick free((caddr_t)ump, M_UFSMNT); 35141397Smckusick mp->mnt_data = (qaddr_t)0; 35241397Smckusick mp->mnt_flag &= ~MNT_LOCAL; 35330749Skarels return (error); 35412795Ssam } 35512795Ssam 35637737Smckusick /* 35740376Smckusick * Check to see if a filesystem is mounted on a block device. 35840376Smckusick */ 35940376Smckusick mountedon(vp) 36040376Smckusick register struct vnode *vp; 36140376Smckusick { 36240376Smckusick register struct vnode *vq; 36340376Smckusick 36440653Smckusick if (vp->v_specflags & SI_MOUNTEDON) 36540376Smckusick return (EBUSY); 36640376Smckusick if (vp->v_flag & VALIASED) { 36740653Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 36840376Smckusick if (vq->v_rdev != vp->v_rdev || 36940376Smckusick vq->v_type != vp->v_type) 37040376Smckusick continue; 37140653Smckusick if (vq->v_specflags & SI_MOUNTEDON) 37240376Smckusick return (EBUSY); 37340376Smckusick } 37440376Smckusick } 37540376Smckusick return (0); 37640376Smckusick } 37740376Smckusick 37840376Smckusick /* 37937737Smckusick * Return root of a filesystem 38037737Smckusick */ 38137737Smckusick ufs_root(mp, vpp) 38212795Ssam struct mount *mp; 38337737Smckusick struct vnode **vpp; 38412795Ssam { 38539390Smckusick register struct inode *ip; 38639390Smckusick struct inode *nip; 38739390Smckusick struct vnode tvp; 38837737Smckusick int error; 38937737Smckusick 39039390Smckusick tvp.v_mount = mp; 39139390Smckusick ip = VTOI(&tvp); 39239390Smckusick ip->i_vnode = &tvp; 39339390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 39439390Smckusick error = iget(ip, (ino_t)ROOTINO, &nip); 39537737Smckusick if (error) 39637737Smckusick return (error); 39739390Smckusick *vpp = ITOV(nip); 39837737Smckusick return (0); 39937737Smckusick } 40037737Smckusick 40137737Smckusick /* 40241314Smckusick * Do operations associated with quotas 40341314Smckusick */ 40448036Smckusick ufs_quotactl(mp, cmds, uid, arg, p) 40541314Smckusick struct mount *mp; 40641314Smckusick int cmds; 40741314Smckusick uid_t uid; 40841314Smckusick caddr_t arg; 40948036Smckusick struct proc *p; 41041314Smckusick { 41141314Smckusick struct ufsmount *ump = VFSTOUFS(mp); 41241314Smckusick int cmd, type, error; 41341314Smckusick 41441314Smckusick #ifndef QUOTA 41541314Smckusick return (EOPNOTSUPP); 41641314Smckusick #else 41741314Smckusick if (uid == -1) 41847571Skarels uid = p->p_cred->p_ruid; 41941314Smckusick cmd = cmds >> SUBCMDSHIFT; 42041314Smckusick 42141314Smckusick switch (cmd) { 42241314Smckusick case Q_GETQUOTA: 42341314Smckusick case Q_SYNC: 42447571Skarels if (uid == p->p_cred->p_ruid) 42541314Smckusick break; 42641314Smckusick /* fall through */ 42741314Smckusick default: 42847571Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 42941314Smckusick return (error); 43041314Smckusick } 43141314Smckusick 43241314Smckusick type = cmd & SUBCMDMASK; 43341314Smckusick if ((u_int)type >= MAXQUOTAS) 43441314Smckusick return (EINVAL); 43541314Smckusick 43641314Smckusick switch (cmd) { 43741314Smckusick 43841314Smckusick case Q_QUOTAON: 43947571Skarels return (quotaon(p, mp, type, arg)); 44041314Smckusick 44141314Smckusick case Q_QUOTAOFF: 44241314Smckusick if (vfs_busy(mp)) 44341314Smckusick return (0); 444*50114Smckusick error = quotaoff(p, mp, type); 44541314Smckusick vfs_unbusy(mp); 44641314Smckusick return (error); 44741314Smckusick 44841314Smckusick case Q_SETQUOTA: 44941314Smckusick return (setquota(mp, uid, type, arg)); 45041314Smckusick 45141314Smckusick case Q_SETUSE: 45241314Smckusick return (setuse(mp, uid, type, arg)); 45341314Smckusick 45441314Smckusick case Q_GETQUOTA: 45541314Smckusick return (getquota(mp, uid, type, arg)); 45641314Smckusick 45741314Smckusick case Q_SYNC: 45841314Smckusick if (vfs_busy(mp)) 45941314Smckusick return (0); 46041314Smckusick error = qsync(mp); 46141314Smckusick vfs_unbusy(mp); 46241314Smckusick return (error); 46341314Smckusick 46441314Smckusick default: 46541314Smckusick return (EINVAL); 46641314Smckusick } 46741314Smckusick /* NOTREACHED */ 46841314Smckusick #endif 46941314Smckusick } 47041314Smckusick 47141314Smckusick /* 47237737Smckusick * Get file system statistics. 47337737Smckusick */ 47448036Smckusick ufs_statfs(mp, sbp, p) 47537737Smckusick struct mount *mp; 47637737Smckusick register struct statfs *sbp; 47748036Smckusick struct proc *p; 47837737Smckusick { 47937737Smckusick register struct ufsmount *ump; 48037737Smckusick register struct fs *fs; 48137737Smckusick 48237737Smckusick ump = VFSTOUFS(mp); 48337737Smckusick fs = ump->um_fs; 48437737Smckusick if (fs->fs_magic != FS_MAGIC) 48537737Smckusick panic("ufs_statfs"); 48637737Smckusick sbp->f_type = MOUNT_UFS; 48737737Smckusick sbp->f_fsize = fs->fs_fsize; 48837737Smckusick sbp->f_bsize = fs->fs_bsize; 48937737Smckusick sbp->f_blocks = fs->fs_dsize; 49037737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 49137737Smckusick fs->fs_cstotal.cs_nffree; 49237737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 49337737Smckusick (fs->fs_dsize - sbp->f_bfree); 49439350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 49537737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 49641397Smckusick if (sbp != &mp->mnt_stat) { 49741397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 49840346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 49941397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 50040346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 50140346Smckusick } 50237737Smckusick return (0); 50337737Smckusick } 50437737Smckusick 50537737Smckusick int syncprt = 0; 50637737Smckusick 50737737Smckusick /* 50837737Smckusick * Go through the disk queues to initiate sandbagged IO; 50937737Smckusick * go through the inodes to write those that have been modified; 51037737Smckusick * initiate the writing of the super block if it has been modified. 51141314Smckusick * 51241314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 51337737Smckusick */ 51437737Smckusick ufs_sync(mp, waitfor) 51537737Smckusick struct mount *mp; 51637737Smckusick int waitfor; 51737737Smckusick { 51839390Smckusick register struct vnode *vp; 51937737Smckusick register struct inode *ip; 52037737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 52137737Smckusick register struct fs *fs; 52239596Smckusick int error, allerror = 0; 52337737Smckusick 52437737Smckusick if (syncprt) 52537737Smckusick bufstats(); 52637737Smckusick fs = ump->um_fs; 52737737Smckusick /* 52837737Smckusick * Write back modified superblock. 52937737Smckusick * Consistency check that the superblock 53037737Smckusick * is still in the buffer cache. 53137737Smckusick */ 53237737Smckusick if (fs->fs_fmod != 0) { 53337737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 53437737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 53537737Smckusick panic("update: rofs mod"); 53637737Smckusick } 53737737Smckusick fs->fs_fmod = 0; 53837737Smckusick fs->fs_time = time.tv_sec; 53941510Smckusick allerror = sbupdate(ump, waitfor); 54037737Smckusick } 54137737Smckusick /* 54237737Smckusick * Write back each (modified) inode. 54337737Smckusick */ 54439877Smckusick loop: 54541462Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 54641462Smckusick /* 54741462Smckusick * If the vnode that we are about to sync is no longer 54841462Smckusick * associated with this mount point, start over. 54941462Smckusick */ 55041462Smckusick if (vp->v_mount != mp) 55141462Smckusick goto loop; 55248359Smckusick if (VOP_ISLOCKED(vp)) 55348359Smckusick continue; 55439390Smckusick ip = VTOI(vp); 55539877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 55639877Smckusick vp->v_dirtyblkhd == NULL) 55737737Smckusick continue; 55839877Smckusick if (vget(vp)) 55939877Smckusick goto loop; 56039877Smckusick if (vp->v_dirtyblkhd) 56139877Smckusick vflushbuf(vp, 0); 56239877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && 56339877Smckusick (error = iupdat(ip, &time, &time, 0))) 56439596Smckusick allerror = error; 56539596Smckusick vput(vp); 56637737Smckusick } 56737737Smckusick /* 56839675Smckusick * Force stale file system control information to be flushed. 56937737Smckusick */ 57039675Smckusick vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 57141314Smckusick #ifdef QUOTA 57241314Smckusick qsync(mp); 57341314Smckusick #endif 57439596Smckusick return (allerror); 57537737Smckusick } 57637737Smckusick 57737737Smckusick /* 57837737Smckusick * Write a superblock and associated information back to disk. 57937737Smckusick */ 58037737Smckusick sbupdate(mp, waitfor) 58137737Smckusick struct ufsmount *mp; 58237737Smckusick int waitfor; 58337737Smckusick { 58437737Smckusick register struct fs *fs = mp->um_fs; 58512795Ssam register struct buf *bp; 58612795Ssam int blks; 58712795Ssam caddr_t space; 58837737Smckusick int i, size, error = 0; 58912795Ssam 59037737Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 59112795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 59234145Smckusick /* Restore compatibility to old file systems. XXX */ 59334145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 59434145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 59537737Smckusick if (waitfor == MNT_WAIT) 59637737Smckusick error = bwrite(bp); 59737737Smckusick else 59837737Smckusick bawrite(bp); 59912795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 60012795Ssam space = (caddr_t)fs->fs_csp[0]; 60112795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 60212795Ssam size = fs->fs_bsize; 60312795Ssam if (i + fs->fs_frag > blks) 60412795Ssam size = (blks - i) * fs->fs_fsize; 60537737Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 60612795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 60712795Ssam space += size; 60837737Smckusick if (waitfor == MNT_WAIT) 60937737Smckusick error = bwrite(bp); 61037737Smckusick else 61137737Smckusick bawrite(bp); 61212795Ssam } 61337737Smckusick return (error); 61412795Ssam } 61512795Ssam 61612795Ssam /* 61737737Smckusick * Print out statistics on the current allocation of the buffer pool. 61837737Smckusick * Can be enabled to print out on every ``sync'' by setting "syncprt" 61937737Smckusick * above. 62037737Smckusick */ 62137737Smckusick bufstats() 62237737Smckusick { 62337737Smckusick int s, i, j, count; 62437737Smckusick register struct buf *bp, *dp; 62537737Smckusick int counts[MAXBSIZE/CLBYTES+1]; 62637737Smckusick static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 62737737Smckusick 62837737Smckusick for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 62937737Smckusick count = 0; 63037737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 63137737Smckusick counts[j] = 0; 63237737Smckusick s = splbio(); 63337737Smckusick for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 63437737Smckusick counts[dp->b_bufsize/CLBYTES]++; 63537737Smckusick count++; 63637737Smckusick } 63737737Smckusick splx(s); 63837737Smckusick printf("%s: total-%d", bname[i], count); 63937737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 64037737Smckusick if (counts[j] != 0) 64137737Smckusick printf(", %d-%d", j * CLBYTES, counts[j]); 64237737Smckusick printf("\n"); 64337737Smckusick } 64437737Smckusick } 64537737Smckusick 64637737Smckusick /* 64737737Smckusick * File handle to vnode 64838453Smckusick * 64938453Smckusick * Have to be really careful about stale file handles: 65038453Smckusick * - check that the inode number is in range 65138453Smckusick * - call iget() to get the locked inode 65238453Smckusick * - check for an unallocated inode (i_mode == 0) 65338453Smckusick * - check that the generation number matches 65437737Smckusick */ 65537737Smckusick ufs_fhtovp(mp, fhp, vpp) 65638453Smckusick register struct mount *mp; 65737737Smckusick struct fid *fhp; 65837737Smckusick struct vnode **vpp; 65937737Smckusick { 66037737Smckusick register struct ufid *ufhp; 66138453Smckusick register struct fs *fs; 66239390Smckusick register struct inode *ip; 66339390Smckusick struct inode *nip; 66439390Smckusick struct vnode tvp; 66537737Smckusick int error; 66637737Smckusick 66737737Smckusick ufhp = (struct ufid *)fhp; 66838453Smckusick fs = VFSTOUFS(mp)->um_fs; 66938453Smckusick if (ufhp->ufid_ino < ROOTINO || 67038453Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 67141397Smckusick *vpp = NULLVP; 67238453Smckusick return (EINVAL); 67338453Smckusick } 67439390Smckusick tvp.v_mount = mp; 67539390Smckusick ip = VTOI(&tvp); 67639390Smckusick ip->i_vnode = &tvp; 67739390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 67839390Smckusick if (error = iget(ip, ufhp->ufid_ino, &nip)) { 67941397Smckusick *vpp = NULLVP; 68037737Smckusick return (error); 68137737Smckusick } 68239390Smckusick ip = nip; 68338453Smckusick if (ip->i_mode == 0) { 68438453Smckusick iput(ip); 68541397Smckusick *vpp = NULLVP; 68638453Smckusick return (EINVAL); 68738453Smckusick } 68837737Smckusick if (ip->i_gen != ufhp->ufid_gen) { 68937737Smckusick iput(ip); 69041397Smckusick *vpp = NULLVP; 69137737Smckusick return (EINVAL); 69237737Smckusick } 69337737Smckusick *vpp = ITOV(ip); 69437737Smckusick return (0); 69537737Smckusick } 69637737Smckusick 69737737Smckusick /* 69838355Smckusick * Vnode pointer to File handle 69937737Smckusick */ 70037737Smckusick /* ARGSUSED */ 70138143Smckusick ufs_vptofh(vp, fhp) 70238143Smckusick struct vnode *vp; 70337737Smckusick struct fid *fhp; 70437737Smckusick { 70538143Smckusick register struct inode *ip = VTOI(vp); 70638143Smckusick register struct ufid *ufhp; 70737737Smckusick 70838143Smckusick ufhp = (struct ufid *)fhp; 70938143Smckusick ufhp->ufid_len = sizeof(struct ufid); 71038143Smckusick ufhp->ufid_ino = ip->i_number; 71138143Smckusick ufhp->ufid_gen = ip->i_gen; 71238143Smckusick return (0); 71337737Smckusick } 71437737Smckusick 71537737Smckusick /* 71612795Ssam * Check that the user's argument is a reasonable 71712795Ssam * thing on which to mount, and return the device number if so. 71812795Ssam */ 71948036Smckusick getmdev(devvpp, fname, ndp, p) 72037737Smckusick struct vnode **devvpp; 72116697Smckusick caddr_t fname; 72237737Smckusick register struct nameidata *ndp; 72348036Smckusick struct proc *p; 72412795Ssam { 72537737Smckusick register struct vnode *vp; 72637737Smckusick int error; 72712795Ssam 72841463Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72916697Smckusick ndp->ni_segflg = UIO_USERSPACE; 73016697Smckusick ndp->ni_dirp = fname; 73148036Smckusick if (error = namei(ndp, p)) 73237737Smckusick return (error); 73337737Smckusick vp = ndp->ni_vp; 73437737Smckusick if (vp->v_type != VBLK) { 73541463Smckusick vrele(vp); 73612795Ssam return (ENOTBLK); 73715956Skarels } 73839532Smckusick if (major(vp->v_rdev) >= nblkdev) { 73941463Smckusick vrele(vp); 74012795Ssam return (ENXIO); 74139532Smckusick } 74237737Smckusick *devvpp = vp; 74312795Ssam return (0); 74412795Ssam } 745