123400Smckusick /* 237737Smckusick * Copyright (c) 1989 The Regents of the University of California. 337737Smckusick * All rights reserved. 423400Smckusick * 5*44539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*44539Sbostic * @(#)lfs_vfsops.c 7.49 (Berkeley) 06/28/90 823400Smckusick */ 912795Ssam 1017100Sbloom #include "param.h" 1117100Sbloom #include "systm.h" 1241314Smckusick #include "user.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" 2441314Smckusick #include "../ufs/quota.h" 2537737Smckusick #include "../ufs/fs.h" 2637737Smckusick #include "../ufs/ufsmount.h" 2737737Smckusick #include "../ufs/inode.h" 2812795Ssam 2937737Smckusick /* 3037737Smckusick * ufs vfs operations. 3137737Smckusick */ 3237737Smckusick int ufs_mount(); 3339043Smckusick int ufs_start(); 3437737Smckusick int ufs_unmount(); 3537737Smckusick int ufs_root(); 3641314Smckusick int ufs_quotactl(); 3737737Smckusick int ufs_statfs(); 3837737Smckusick int ufs_sync(); 3937737Smckusick int ufs_fhtovp(); 4037737Smckusick int ufs_vptofh(); 4139437Smckusick int ufs_init(); 4237737Smckusick 4337737Smckusick struct vfsops ufs_vfsops = { 4437737Smckusick ufs_mount, 4539043Smckusick ufs_start, 4637737Smckusick ufs_unmount, 4737737Smckusick ufs_root, 4841314Smckusick ufs_quotactl, 4937737Smckusick ufs_statfs, 5037737Smckusick ufs_sync, 5137737Smckusick ufs_fhtovp, 5239437Smckusick ufs_vptofh, 5339437Smckusick ufs_init 5437737Smckusick }; 5537737Smckusick 5637737Smckusick /* 5739336Smckusick * Called by vfs_mountroot when ufs is going to be mounted as root. 5837737Smckusick * 5939336Smckusick * Name is updated by mount(8) after booting. 6037737Smckusick */ 6139297Smckusick #define ROOTNAME "root_device" 6237737Smckusick 6337737Smckusick ufs_mountroot() 6412795Ssam { 6537737Smckusick register struct mount *mp; 6637737Smckusick extern struct vnode *rootvp; 6737737Smckusick struct ufsmount *ump; 6812795Ssam register struct fs *fs; 6937737Smckusick u_int size; 7037737Smckusick int error; 7112795Ssam 7237737Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 7337737Smckusick M_MOUNT, M_WAITOK); 7441397Smckusick mp->mnt_op = &ufs_vfsops; 7541397Smckusick mp->mnt_flag = MNT_RDONLY; 7641397Smckusick mp->mnt_exroot = 0; 7741397Smckusick mp->mnt_mounth = NULLVP; 7837737Smckusick error = mountfs(rootvp, mp); 7937737Smckusick if (error) { 8037737Smckusick free((caddr_t)mp, M_MOUNT); 8137737Smckusick return (error); 8212795Ssam } 8339336Smckusick if (error = vfs_lock(mp)) { 8437737Smckusick (void)ufs_unmount(mp, 0); 8537737Smckusick free((caddr_t)mp, M_MOUNT); 8637737Smckusick return (error); 8721013Smckusick } 8839336Smckusick rootfs = mp; 8941397Smckusick mp->mnt_next = mp; 9041397Smckusick mp->mnt_prev = mp; 9141397Smckusick mp->mnt_vnodecovered = NULLVP; 9237737Smckusick ump = VFSTOUFS(mp); 9337737Smckusick fs = ump->um_fs; 9440346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 9537737Smckusick fs->fs_fsmnt[0] = '/'; 9641397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 9741397Smckusick MNAMELEN); 9841397Smckusick (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 9941397Smckusick &size); 10041397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 10141397Smckusick (void) ufs_statfs(mp, &mp->mnt_stat); 10237737Smckusick vfs_unlock(mp); 10337737Smckusick inittodr(fs->fs_time); 10437737Smckusick return (0); 10537737Smckusick } 10637737Smckusick 10737737Smckusick /* 10837737Smckusick * VFS Operations. 10937737Smckusick * 11037737Smckusick * mount system call 11137737Smckusick */ 11237737Smckusick ufs_mount(mp, path, data, ndp) 11340346Smckusick register struct mount *mp; 11437737Smckusick char *path; 11537737Smckusick caddr_t data; 11637737Smckusick struct nameidata *ndp; 11737737Smckusick { 11837737Smckusick struct vnode *devvp; 11937737Smckusick struct ufs_args args; 12037737Smckusick struct ufsmount *ump; 12137737Smckusick register struct fs *fs; 12237737Smckusick u_int size; 12337737Smckusick int error; 12437737Smckusick 12537737Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 12637737Smckusick return (error); 12740371Smckusick /* 12840371Smckusick * Process export requests. 12940371Smckusick */ 13041397Smckusick if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { 13141397Smckusick if (args.exflags & MNT_EXPORTED) 13241397Smckusick mp->mnt_flag |= MNT_EXPORTED; 13340371Smckusick else 13441397Smckusick mp->mnt_flag &= ~MNT_EXPORTED; 13541397Smckusick if (args.exflags & MNT_EXRDONLY) 13641397Smckusick mp->mnt_flag |= MNT_EXRDONLY; 13740371Smckusick else 13841397Smckusick mp->mnt_flag &= ~MNT_EXRDONLY; 13941397Smckusick mp->mnt_exroot = args.exroot; 14040371Smckusick } 14141397Smckusick if ((mp->mnt_flag & MNT_UPDATE) == 0) { 14240371Smckusick if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 14340371Smckusick return (error); 14439336Smckusick error = mountfs(devvp, mp); 14539336Smckusick } else { 14639336Smckusick ump = VFSTOUFS(mp); 14739336Smckusick fs = ump->um_fs; 14841397Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 14939336Smckusick fs->fs_ronly = 0; 15039336Smckusick /* 15139336Smckusick * Verify that the specified device is the one that 15239336Smckusick * is really being used for the root file system. 15339336Smckusick */ 15440371Smckusick if (args.fspec == 0) 15540371Smckusick return (0); 15640371Smckusick if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 15740371Smckusick return (error); 15839336Smckusick if (devvp != ump->um_devvp) 15939336Smckusick error = EINVAL; /* needs translation */ 16042858Smckusick else 16142858Smckusick vrele(devvp); 16239336Smckusick } 16337737Smckusick if (error) { 16437737Smckusick vrele(devvp); 16537737Smckusick return (error); 16632721Smckusick } 16737737Smckusick ump = VFSTOUFS(mp); 16837737Smckusick fs = ump->um_fs; 16937737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 17037737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 17141397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 17241397Smckusick MNAMELEN); 17341397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 17441397Smckusick &size); 17541397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 17641397Smckusick (void) ufs_statfs(mp, &mp->mnt_stat); 17737737Smckusick return (0); 17812795Ssam } 17912795Ssam 18037737Smckusick /* 18137737Smckusick * Common code for mount and mountroot 18237737Smckusick */ 18337737Smckusick mountfs(devvp, mp) 18440376Smckusick register struct vnode *devvp; 18537737Smckusick struct mount *mp; 18612795Ssam { 18741314Smckusick register struct ufsmount *ump = (struct ufsmount *)0; 18837737Smckusick struct buf *bp = NULL; 18912795Ssam register struct fs *fs; 19037737Smckusick dev_t dev = devvp->v_rdev; 19130749Skarels struct partinfo dpart; 19237737Smckusick caddr_t base, space; 19330749Skarels int havepart = 0, blks; 19437737Smckusick int error, i, size; 19521013Smckusick int needclose = 0; 19641397Smckusick int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 19712795Ssam 19840376Smckusick /* 19940376Smckusick * Disallow multiple mounts of the same device. 20040376Smckusick * Disallow mounting of a device that is currently in use. 20140376Smckusick * Flush out any old buffers remaining from a previous use. 20240376Smckusick */ 20340376Smckusick if (error = mountedon(devvp)) 20440376Smckusick return (error); 20540376Smckusick if (vcount(devvp) > 1) 20640376Smckusick return (EBUSY); 20740376Smckusick vinvalbuf(devvp, 1); 20841314Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED)) 20937737Smckusick return (error); 21021013Smckusick needclose = 1; 21141314Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED) != 0) { 21237737Smckusick size = DEV_BSIZE; 21341314Smckusick } else { 21430749Skarels havepart = 1; 21530749Skarels size = dpart.disklab->d_secsize; 21637737Smckusick } 21741314Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 21812795Ssam goto out; 21934421Skarels fs = bp->b_un.b_fs; 22030749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 22130749Skarels fs->fs_bsize < sizeof(struct fs)) { 22241314Smckusick error = EINVAL; /* XXX needs translation */ 22316639Skarels goto out; 22416639Skarels } 22541314Smckusick ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 22637737Smckusick ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 22734473Smckusick M_WAITOK); 22837737Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 22912795Ssam (u_int)fs->fs_sbsize); 23039675Smckusick if (fs->fs_sbsize < SBSIZE) 23139675Smckusick bp->b_flags |= B_INVAL; 23234421Skarels brelse(bp); 23334421Skarels bp = NULL; 23437737Smckusick fs = ump->um_fs; 23537737Smckusick fs->fs_ronly = ronly; 23612795Ssam if (ronly == 0) 23712795Ssam fs->fs_fmod = 1; 23830749Skarels if (havepart) { 23930749Skarels dpart.part->p_fstype = FS_BSDFFS; 24030749Skarels dpart.part->p_fsize = fs->fs_fsize; 24130749Skarels dpart.part->p_frag = fs->fs_frag; 24231385Skarels dpart.part->p_cpg = fs->fs_cpg; 24330749Skarels } 24412795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 24534473Smckusick base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 24634473Smckusick M_WAITOK); 24712795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 24812795Ssam size = fs->fs_bsize; 24912795Ssam if (i + fs->fs_frag > blks) 25012795Ssam size = (blks - i) * fs->fs_fsize; 25138776Smckusick error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 25238776Smckusick NOCRED, &bp); 25337737Smckusick if (error) { 25434473Smckusick free((caddr_t)base, M_SUPERBLK); 25512795Ssam goto out; 25612795Ssam } 25734421Skarels bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 25817225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 25912795Ssam space += size; 26034421Skarels brelse(bp); 26134421Skarels bp = NULL; 26212795Ssam } 26341397Smckusick mp->mnt_data = (qaddr_t)ump; 26441397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 26541397Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 26641397Smckusick mp->mnt_flag |= MNT_LOCAL; 26737737Smckusick ump->um_mountp = mp; 26837737Smckusick ump->um_dev = dev; 26937737Smckusick ump->um_devvp = devvp; 27041314Smckusick for (i = 0; i < MAXQUOTAS; i++) 27141314Smckusick ump->um_quotas[i] = NULLVP; 27240653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 27337737Smckusick 27430383Smckusick /* Sanity checks for old file systems. XXX */ 27530383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 27630383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 27734145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 27834145Smckusick fs->fs_nrpos = 8; /* XXX */ 27937737Smckusick return (0); 28012795Ssam out: 28140872Smckusick if (bp) 28240872Smckusick brelse(bp); 28332721Smckusick if (needclose) 28438776Smckusick (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 28541314Smckusick if (ump) { 28637737Smckusick free((caddr_t)ump->um_fs, M_SUPERBLK); 28741314Smckusick free((caddr_t)ump, M_UFSMNT); 28841397Smckusick mp->mnt_data = (qaddr_t)0; 28932721Smckusick } 29037737Smckusick return (error); 29112795Ssam } 29212795Ssam 29339043Smckusick /* 29439043Smckusick * Make a filesystem operational. 29539043Smckusick * Nothing to do at the moment. 29639043Smckusick */ 29739390Smckusick /* ARGSUSED */ 29839043Smckusick ufs_start(mp, flags) 29939043Smckusick struct mount *mp; 30039043Smckusick int flags; 30139043Smckusick { 30212795Ssam 30339043Smckusick return (0); 30439043Smckusick } 30539043Smckusick 30637737Smckusick /* 30737737Smckusick * unmount system call 30837737Smckusick */ 30941314Smckusick ufs_unmount(mp, mntflags) 31037737Smckusick struct mount *mp; 31141314Smckusick int mntflags; 31212795Ssam { 31337737Smckusick register struct ufsmount *ump; 31437737Smckusick register struct fs *fs; 31541314Smckusick int i, error, ronly, flags = 0; 31612795Ssam 31741314Smckusick if (mntflags & MNT_FORCE) 31837737Smckusick return (EINVAL); 31941314Smckusick if (mntflags & MNT_FORCE) 32041314Smckusick flags |= FORCECLOSE; 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; 33241314Smckusick quotaoff(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; 34538776Smckusick error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 34637737Smckusick vrele(ump->um_devvp); 34741314Smckusick free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 34841314Smckusick free((caddr_t)fs, M_SUPERBLK); 34941314Smckusick free((caddr_t)ump, M_UFSMNT); 35041397Smckusick mp->mnt_data = (qaddr_t)0; 35141397Smckusick mp->mnt_flag &= ~MNT_LOCAL; 35230749Skarels return (error); 35312795Ssam } 35412795Ssam 35537737Smckusick /* 35640376Smckusick * Check to see if a filesystem is mounted on a block device. 35740376Smckusick */ 35840376Smckusick mountedon(vp) 35940376Smckusick register struct vnode *vp; 36040376Smckusick { 36140376Smckusick register struct vnode *vq; 36240376Smckusick 36340653Smckusick if (vp->v_specflags & SI_MOUNTEDON) 36440376Smckusick return (EBUSY); 36540376Smckusick if (vp->v_flag & VALIASED) { 36640653Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 36740376Smckusick if (vq->v_rdev != vp->v_rdev || 36840376Smckusick vq->v_type != vp->v_type) 36940376Smckusick continue; 37040653Smckusick if (vq->v_specflags & SI_MOUNTEDON) 37140376Smckusick return (EBUSY); 37240376Smckusick } 37340376Smckusick } 37440376Smckusick return (0); 37540376Smckusick } 37640376Smckusick 37740376Smckusick /* 37837737Smckusick * Return root of a filesystem 37937737Smckusick */ 38037737Smckusick ufs_root(mp, vpp) 38112795Ssam struct mount *mp; 38237737Smckusick struct vnode **vpp; 38312795Ssam { 38439390Smckusick register struct inode *ip; 38539390Smckusick struct inode *nip; 38639390Smckusick struct vnode tvp; 38737737Smckusick int error; 38837737Smckusick 38939390Smckusick tvp.v_mount = mp; 39039390Smckusick ip = VTOI(&tvp); 39139390Smckusick ip->i_vnode = &tvp; 39239390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 39339390Smckusick error = iget(ip, (ino_t)ROOTINO, &nip); 39437737Smckusick if (error) 39537737Smckusick return (error); 39639390Smckusick *vpp = ITOV(nip); 39737737Smckusick return (0); 39837737Smckusick } 39937737Smckusick 40037737Smckusick /* 40141314Smckusick * Do operations associated with quotas 40241314Smckusick */ 40341314Smckusick ufs_quotactl(mp, cmds, uid, arg) 40441314Smckusick struct mount *mp; 40541314Smckusick int cmds; 40641314Smckusick uid_t uid; 40741314Smckusick caddr_t arg; 40841314Smckusick { 40941314Smckusick register struct nameidata *ndp = &u.u_nd; 41041314Smckusick struct ufsmount *ump = VFSTOUFS(mp); 41141515Smckusick struct proc *p = u.u_procp; /* XXX */ 41241314Smckusick int cmd, type, error; 41341314Smckusick 41441314Smckusick #ifndef QUOTA 41541314Smckusick return (EOPNOTSUPP); 41641314Smckusick #else 41741314Smckusick if (uid == -1) 41841515Smckusick uid = p->p_ruid; 41941314Smckusick cmd = cmds >> SUBCMDSHIFT; 42041314Smckusick 42141314Smckusick switch (cmd) { 42241314Smckusick case Q_GETQUOTA: 42341314Smckusick case Q_SYNC: 42441515Smckusick if (uid == p->p_ruid) 42541314Smckusick break; 42641314Smckusick /* fall through */ 42741314Smckusick default: 42841314Smckusick if (error = suser(ndp->ni_cred, &u.u_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: 43941314Smckusick return (quotaon(ndp, mp, type, arg)); 44041314Smckusick 44141314Smckusick case Q_QUOTAOFF: 44241314Smckusick if (vfs_busy(mp)) 44341314Smckusick return (0); 44441314Smckusick error = quotaoff(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 */ 47437737Smckusick ufs_statfs(mp, sbp) 47537737Smckusick struct mount *mp; 47637737Smckusick register struct statfs *sbp; 47737737Smckusick { 47837737Smckusick register struct ufsmount *ump; 47937737Smckusick register struct fs *fs; 48037737Smckusick 48137737Smckusick ump = VFSTOUFS(mp); 48237737Smckusick fs = ump->um_fs; 48337737Smckusick if (fs->fs_magic != FS_MAGIC) 48437737Smckusick panic("ufs_statfs"); 48537737Smckusick sbp->f_type = MOUNT_UFS; 48637737Smckusick sbp->f_fsize = fs->fs_fsize; 48737737Smckusick sbp->f_bsize = fs->fs_bsize; 48837737Smckusick sbp->f_blocks = fs->fs_dsize; 48937737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 49037737Smckusick fs->fs_cstotal.cs_nffree; 49137737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 49237737Smckusick (fs->fs_dsize - sbp->f_bfree); 49339350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 49437737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 49541397Smckusick if (sbp != &mp->mnt_stat) { 49641397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 49740346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 49841397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 49940346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 50040346Smckusick } 50137737Smckusick return (0); 50237737Smckusick } 50337737Smckusick 50437737Smckusick int syncprt = 0; 50537737Smckusick 50637737Smckusick /* 50737737Smckusick * Go through the disk queues to initiate sandbagged IO; 50837737Smckusick * go through the inodes to write those that have been modified; 50937737Smckusick * initiate the writing of the super block if it has been modified. 51041314Smckusick * 51141314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 51237737Smckusick */ 51337737Smckusick ufs_sync(mp, waitfor) 51437737Smckusick struct mount *mp; 51537737Smckusick int waitfor; 51637737Smckusick { 51739390Smckusick register struct vnode *vp; 51837737Smckusick register struct inode *ip; 51937737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 52037737Smckusick register struct fs *fs; 52139596Smckusick int error, allerror = 0; 52237737Smckusick 52337737Smckusick if (syncprt) 52437737Smckusick bufstats(); 52537737Smckusick fs = ump->um_fs; 52637737Smckusick /* 52737737Smckusick * Write back modified superblock. 52837737Smckusick * Consistency check that the superblock 52937737Smckusick * is still in the buffer cache. 53037737Smckusick */ 53137737Smckusick if (fs->fs_fmod != 0) { 53237737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 53337737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 53437737Smckusick panic("update: rofs mod"); 53537737Smckusick } 53637737Smckusick fs->fs_fmod = 0; 53737737Smckusick fs->fs_time = time.tv_sec; 53841510Smckusick allerror = sbupdate(ump, waitfor); 53937737Smckusick } 54037737Smckusick /* 54137737Smckusick * Write back each (modified) inode. 54237737Smckusick */ 54339877Smckusick loop: 54441462Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 54541462Smckusick /* 54641462Smckusick * If the vnode that we are about to sync is no longer 54741462Smckusick * associated with this mount point, start over. 54841462Smckusick */ 54941462Smckusick if (vp->v_mount != mp) 55041462Smckusick goto loop; 55139390Smckusick ip = VTOI(vp); 55239877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 55339877Smckusick vp->v_dirtyblkhd == NULL) 55437737Smckusick continue; 55539877Smckusick if (vget(vp)) 55639877Smckusick goto loop; 55739877Smckusick if (vp->v_dirtyblkhd) 55839877Smckusick vflushbuf(vp, 0); 55939877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && 56039877Smckusick (error = iupdat(ip, &time, &time, 0))) 56139596Smckusick allerror = error; 56239596Smckusick vput(vp); 56337737Smckusick } 56437737Smckusick /* 56539675Smckusick * Force stale file system control information to be flushed. 56637737Smckusick */ 56739675Smckusick vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 56841314Smckusick #ifdef QUOTA 56941314Smckusick qsync(mp); 57041314Smckusick #endif 57139596Smckusick return (allerror); 57237737Smckusick } 57337737Smckusick 57437737Smckusick /* 57537737Smckusick * Write a superblock and associated information back to disk. 57637737Smckusick */ 57737737Smckusick sbupdate(mp, waitfor) 57837737Smckusick struct ufsmount *mp; 57937737Smckusick int waitfor; 58037737Smckusick { 58137737Smckusick register struct fs *fs = mp->um_fs; 58212795Ssam register struct buf *bp; 58312795Ssam int blks; 58412795Ssam caddr_t space; 58537737Smckusick int i, size, error = 0; 58612795Ssam 58737737Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 58812795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 58934145Smckusick /* Restore compatibility to old file systems. XXX */ 59034145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 59134145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 59237737Smckusick if (waitfor == MNT_WAIT) 59337737Smckusick error = bwrite(bp); 59437737Smckusick else 59537737Smckusick bawrite(bp); 59612795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 59712795Ssam space = (caddr_t)fs->fs_csp[0]; 59812795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 59912795Ssam size = fs->fs_bsize; 60012795Ssam if (i + fs->fs_frag > blks) 60112795Ssam size = (blks - i) * fs->fs_fsize; 60237737Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 60312795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 60412795Ssam space += size; 60537737Smckusick if (waitfor == MNT_WAIT) 60637737Smckusick error = bwrite(bp); 60737737Smckusick else 60837737Smckusick bawrite(bp); 60912795Ssam } 61037737Smckusick return (error); 61112795Ssam } 61212795Ssam 61312795Ssam /* 61437737Smckusick * Print out statistics on the current allocation of the buffer pool. 61537737Smckusick * Can be enabled to print out on every ``sync'' by setting "syncprt" 61637737Smckusick * above. 61737737Smckusick */ 61837737Smckusick bufstats() 61937737Smckusick { 62037737Smckusick int s, i, j, count; 62137737Smckusick register struct buf *bp, *dp; 62237737Smckusick int counts[MAXBSIZE/CLBYTES+1]; 62337737Smckusick static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 62437737Smckusick 62537737Smckusick for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 62637737Smckusick count = 0; 62737737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 62837737Smckusick counts[j] = 0; 62937737Smckusick s = splbio(); 63037737Smckusick for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 63137737Smckusick counts[dp->b_bufsize/CLBYTES]++; 63237737Smckusick count++; 63337737Smckusick } 63437737Smckusick splx(s); 63537737Smckusick printf("%s: total-%d", bname[i], count); 63637737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 63737737Smckusick if (counts[j] != 0) 63837737Smckusick printf(", %d-%d", j * CLBYTES, counts[j]); 63937737Smckusick printf("\n"); 64037737Smckusick } 64137737Smckusick } 64237737Smckusick 64337737Smckusick /* 64437737Smckusick * File handle to vnode 64538453Smckusick * 64638453Smckusick * Have to be really careful about stale file handles: 64738453Smckusick * - check that the inode number is in range 64838453Smckusick * - call iget() to get the locked inode 64938453Smckusick * - check for an unallocated inode (i_mode == 0) 65038453Smckusick * - check that the generation number matches 65137737Smckusick */ 65237737Smckusick ufs_fhtovp(mp, fhp, vpp) 65338453Smckusick register struct mount *mp; 65437737Smckusick struct fid *fhp; 65537737Smckusick struct vnode **vpp; 65637737Smckusick { 65737737Smckusick register struct ufid *ufhp; 65838453Smckusick register struct fs *fs; 65939390Smckusick register struct inode *ip; 66039390Smckusick struct inode *nip; 66139390Smckusick struct vnode tvp; 66237737Smckusick int error; 66337737Smckusick 66437737Smckusick ufhp = (struct ufid *)fhp; 66538453Smckusick fs = VFSTOUFS(mp)->um_fs; 66638453Smckusick if (ufhp->ufid_ino < ROOTINO || 66738453Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 66841397Smckusick *vpp = NULLVP; 66938453Smckusick return (EINVAL); 67038453Smckusick } 67139390Smckusick tvp.v_mount = mp; 67239390Smckusick ip = VTOI(&tvp); 67339390Smckusick ip->i_vnode = &tvp; 67439390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 67539390Smckusick if (error = iget(ip, ufhp->ufid_ino, &nip)) { 67641397Smckusick *vpp = NULLVP; 67737737Smckusick return (error); 67837737Smckusick } 67939390Smckusick ip = nip; 68038453Smckusick if (ip->i_mode == 0) { 68138453Smckusick iput(ip); 68241397Smckusick *vpp = NULLVP; 68338453Smckusick return (EINVAL); 68438453Smckusick } 68537737Smckusick if (ip->i_gen != ufhp->ufid_gen) { 68637737Smckusick iput(ip); 68741397Smckusick *vpp = NULLVP; 68837737Smckusick return (EINVAL); 68937737Smckusick } 69037737Smckusick *vpp = ITOV(ip); 69137737Smckusick return (0); 69237737Smckusick } 69337737Smckusick 69437737Smckusick /* 69538355Smckusick * Vnode pointer to File handle 69637737Smckusick */ 69737737Smckusick /* ARGSUSED */ 69838143Smckusick ufs_vptofh(vp, fhp) 69938143Smckusick struct vnode *vp; 70037737Smckusick struct fid *fhp; 70137737Smckusick { 70238143Smckusick register struct inode *ip = VTOI(vp); 70338143Smckusick register struct ufid *ufhp; 70437737Smckusick 70538143Smckusick ufhp = (struct ufid *)fhp; 70638143Smckusick ufhp->ufid_len = sizeof(struct ufid); 70738143Smckusick ufhp->ufid_ino = ip->i_number; 70838143Smckusick ufhp->ufid_gen = ip->i_gen; 70938143Smckusick return (0); 71037737Smckusick } 71137737Smckusick 71237737Smckusick /* 71312795Ssam * Check that the user's argument is a reasonable 71412795Ssam * thing on which to mount, and return the device number if so. 71512795Ssam */ 71637737Smckusick getmdev(devvpp, fname, ndp) 71737737Smckusick struct vnode **devvpp; 71816697Smckusick caddr_t fname; 71937737Smckusick register struct nameidata *ndp; 72012795Ssam { 72137737Smckusick register struct vnode *vp; 72237737Smckusick int error; 72312795Ssam 72441463Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72516697Smckusick ndp->ni_segflg = UIO_USERSPACE; 72616697Smckusick ndp->ni_dirp = fname; 72743670Smckusick if (error = namei(ndp)) 72837737Smckusick return (error); 72937737Smckusick vp = ndp->ni_vp; 73037737Smckusick if (vp->v_type != VBLK) { 73141463Smckusick vrele(vp); 73212795Ssam return (ENOTBLK); 73315956Skarels } 73439532Smckusick if (major(vp->v_rdev) >= nblkdev) { 73541463Smckusick vrele(vp); 73612795Ssam return (ENXIO); 73739532Smckusick } 73837737Smckusick *devvpp = vp; 73912795Ssam return (0); 74012795Ssam } 741