123400Smckusick /* 237737Smckusick * Copyright (c) 1989 The Regents of the University of California. 337737Smckusick * All rights reserved. 423400Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*47571Skarels * @(#)lfs_vfsops.c 7.51 (Berkeley) 03/19/91 823400Smckusick */ 912795Ssam 1017100Sbloom #include "param.h" 1117100Sbloom #include "systm.h" 12*47571Skarels #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 25*47571Skarels #include "quota.h" 26*47571Skarels #include "fs.h" 27*47571Skarels #include "ufsmount.h" 28*47571Skarels #include "inode.h" 29*47571Skarels 3037737Smckusick /* 3137737Smckusick * ufs vfs operations. 3237737Smckusick */ 3337737Smckusick int ufs_mount(); 3439043Smckusick int ufs_start(); 3537737Smckusick int ufs_unmount(); 3637737Smckusick int ufs_root(); 3741314Smckusick int ufs_quotactl(); 3837737Smckusick int ufs_statfs(); 3937737Smckusick int ufs_sync(); 4037737Smckusick int ufs_fhtovp(); 4137737Smckusick int ufs_vptofh(); 4239437Smckusick int ufs_init(); 4337737Smckusick 4437737Smckusick struct vfsops ufs_vfsops = { 4537737Smckusick ufs_mount, 4639043Smckusick ufs_start, 4737737Smckusick ufs_unmount, 4837737Smckusick ufs_root, 4941314Smckusick ufs_quotactl, 5037737Smckusick ufs_statfs, 5137737Smckusick ufs_sync, 5237737Smckusick ufs_fhtovp, 5339437Smckusick ufs_vptofh, 5439437Smckusick ufs_init 5537737Smckusick }; 5637737Smckusick 5737737Smckusick /* 5839336Smckusick * Called by vfs_mountroot when ufs is going to be mounted as root. 5937737Smckusick * 6039336Smckusick * Name is updated by mount(8) after booting. 6137737Smckusick */ 6239297Smckusick #define ROOTNAME "root_device" 6337737Smckusick 6437737Smckusick ufs_mountroot() 6512795Ssam { 6637737Smckusick register struct mount *mp; 6737737Smckusick extern struct vnode *rootvp; 6837737Smckusick struct ufsmount *ump; 6912795Ssam register struct fs *fs; 7037737Smckusick u_int size; 7137737Smckusick int error; 7212795Ssam 7337737Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 7437737Smckusick M_MOUNT, M_WAITOK); 7541397Smckusick mp->mnt_op = &ufs_vfsops; 7641397Smckusick mp->mnt_flag = MNT_RDONLY; 7741397Smckusick mp->mnt_exroot = 0; 7841397Smckusick mp->mnt_mounth = NULLVP; 7937737Smckusick error = mountfs(rootvp, mp); 8037737Smckusick if (error) { 8137737Smckusick free((caddr_t)mp, M_MOUNT); 8237737Smckusick return (error); 8312795Ssam } 8439336Smckusick if (error = vfs_lock(mp)) { 8537737Smckusick (void)ufs_unmount(mp, 0); 8637737Smckusick free((caddr_t)mp, M_MOUNT); 8737737Smckusick return (error); 8821013Smckusick } 8939336Smckusick rootfs = mp; 9041397Smckusick mp->mnt_next = mp; 9141397Smckusick mp->mnt_prev = mp; 9241397Smckusick mp->mnt_vnodecovered = NULLVP; 9337737Smckusick ump = VFSTOUFS(mp); 9437737Smckusick fs = ump->um_fs; 9540346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 9637737Smckusick fs->fs_fsmnt[0] = '/'; 9741397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 9841397Smckusick MNAMELEN); 9941397Smckusick (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 10041397Smckusick &size); 10141397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 10241397Smckusick (void) ufs_statfs(mp, &mp->mnt_stat); 10337737Smckusick vfs_unlock(mp); 10437737Smckusick inittodr(fs->fs_time); 10537737Smckusick return (0); 10637737Smckusick } 10737737Smckusick 10837737Smckusick /* 10937737Smckusick * VFS Operations. 11037737Smckusick * 11137737Smckusick * mount system call 11237737Smckusick */ 11337737Smckusick ufs_mount(mp, path, data, ndp) 11440346Smckusick register struct mount *mp; 11537737Smckusick char *path; 11637737Smckusick caddr_t data; 11737737Smckusick struct nameidata *ndp; 11837737Smckusick { 11937737Smckusick struct vnode *devvp; 12037737Smckusick struct ufs_args args; 12137737Smckusick struct ufsmount *ump; 12237737Smckusick register struct fs *fs; 12337737Smckusick u_int size; 12437737Smckusick int error; 12537737Smckusick 12637737Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 12737737Smckusick return (error); 12840371Smckusick /* 12940371Smckusick * Process export requests. 13040371Smckusick */ 13141397Smckusick if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { 13241397Smckusick if (args.exflags & MNT_EXPORTED) 13341397Smckusick mp->mnt_flag |= MNT_EXPORTED; 13440371Smckusick else 13541397Smckusick mp->mnt_flag &= ~MNT_EXPORTED; 13641397Smckusick if (args.exflags & MNT_EXRDONLY) 13741397Smckusick mp->mnt_flag |= MNT_EXRDONLY; 13840371Smckusick else 13941397Smckusick mp->mnt_flag &= ~MNT_EXRDONLY; 14041397Smckusick mp->mnt_exroot = args.exroot; 14140371Smckusick } 14241397Smckusick if ((mp->mnt_flag & MNT_UPDATE) == 0) { 14340371Smckusick if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 14440371Smckusick return (error); 14539336Smckusick error = mountfs(devvp, mp); 14639336Smckusick } else { 14739336Smckusick ump = VFSTOUFS(mp); 14839336Smckusick fs = ump->um_fs; 14941397Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 15039336Smckusick fs->fs_ronly = 0; 15139336Smckusick /* 15239336Smckusick * Verify that the specified device is the one that 15339336Smckusick * is really being used for the root file system. 15439336Smckusick */ 15540371Smckusick if (args.fspec == 0) 15640371Smckusick return (0); 15740371Smckusick if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 15840371Smckusick return (error); 15939336Smckusick if (devvp != ump->um_devvp) 16039336Smckusick error = EINVAL; /* needs translation */ 16142858Smckusick else 16242858Smckusick vrele(devvp); 16339336Smckusick } 16437737Smckusick if (error) { 16537737Smckusick vrele(devvp); 16637737Smckusick return (error); 16732721Smckusick } 16837737Smckusick ump = VFSTOUFS(mp); 16937737Smckusick fs = ump->um_fs; 17037737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 17137737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 17241397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 17341397Smckusick MNAMELEN); 17441397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 17541397Smckusick &size); 17641397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 17741397Smckusick (void) ufs_statfs(mp, &mp->mnt_stat); 17837737Smckusick return (0); 17912795Ssam } 18012795Ssam 18137737Smckusick /* 18237737Smckusick * Common code for mount and mountroot 18337737Smckusick */ 18437737Smckusick mountfs(devvp, mp) 18540376Smckusick register struct vnode *devvp; 18637737Smckusick struct mount *mp; 18712795Ssam { 18841314Smckusick register struct ufsmount *ump = (struct ufsmount *)0; 18937737Smckusick struct buf *bp = NULL; 19012795Ssam register struct fs *fs; 19137737Smckusick dev_t dev = devvp->v_rdev; 19230749Skarels struct partinfo dpart; 19337737Smckusick caddr_t base, space; 19430749Skarels int havepart = 0, blks; 19537737Smckusick int error, i, size; 19621013Smckusick int needclose = 0; 19741397Smckusick int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 19845652Smckusick extern struct vnode *rootvp; 19912795Ssam 20040376Smckusick /* 20140376Smckusick * Disallow multiple mounts of the same device. 20245652Smckusick * Disallow mounting of a device that is currently in use 20345652Smckusick * (except for root, which might share swap device for miniroot). 20440376Smckusick * Flush out any old buffers remaining from a previous use. 20540376Smckusick */ 20640376Smckusick if (error = mountedon(devvp)) 20740376Smckusick return (error); 20845652Smckusick if (vcount(devvp) > 1 && devvp != rootvp) 20940376Smckusick return (EBUSY); 21040376Smckusick vinvalbuf(devvp, 1); 21141314Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED)) 21237737Smckusick return (error); 21321013Smckusick needclose = 1; 21441314Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED) != 0) { 21537737Smckusick size = DEV_BSIZE; 21641314Smckusick } else { 21730749Skarels havepart = 1; 21830749Skarels size = dpart.disklab->d_secsize; 21937737Smckusick } 22041314Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 22112795Ssam goto out; 22234421Skarels fs = bp->b_un.b_fs; 22330749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 22430749Skarels fs->fs_bsize < sizeof(struct fs)) { 22541314Smckusick error = EINVAL; /* XXX needs translation */ 22616639Skarels goto out; 22716639Skarels } 22841314Smckusick ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 22937737Smckusick ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 23034473Smckusick M_WAITOK); 23137737Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 23212795Ssam (u_int)fs->fs_sbsize); 23339675Smckusick if (fs->fs_sbsize < SBSIZE) 23439675Smckusick bp->b_flags |= B_INVAL; 23534421Skarels brelse(bp); 23634421Skarels bp = NULL; 23737737Smckusick fs = ump->um_fs; 23837737Smckusick fs->fs_ronly = ronly; 23912795Ssam if (ronly == 0) 24012795Ssam fs->fs_fmod = 1; 24130749Skarels if (havepart) { 24230749Skarels dpart.part->p_fstype = FS_BSDFFS; 24330749Skarels dpart.part->p_fsize = fs->fs_fsize; 24430749Skarels dpart.part->p_frag = fs->fs_frag; 24531385Skarels dpart.part->p_cpg = fs->fs_cpg; 24630749Skarels } 24712795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 24834473Smckusick base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 24934473Smckusick M_WAITOK); 25012795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 25112795Ssam size = fs->fs_bsize; 25212795Ssam if (i + fs->fs_frag > blks) 25312795Ssam size = (blks - i) * fs->fs_fsize; 25438776Smckusick error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 25538776Smckusick NOCRED, &bp); 25637737Smckusick if (error) { 25734473Smckusick free((caddr_t)base, M_SUPERBLK); 25812795Ssam goto out; 25912795Ssam } 26034421Skarels bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 26117225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 26212795Ssam space += size; 26334421Skarels brelse(bp); 26434421Skarels bp = NULL; 26512795Ssam } 26641397Smckusick mp->mnt_data = (qaddr_t)ump; 26741397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 26841397Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 26941397Smckusick mp->mnt_flag |= MNT_LOCAL; 27037737Smckusick ump->um_mountp = mp; 27137737Smckusick ump->um_dev = dev; 27237737Smckusick ump->um_devvp = devvp; 27341314Smckusick for (i = 0; i < MAXQUOTAS; i++) 27441314Smckusick ump->um_quotas[i] = NULLVP; 27540653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 27637737Smckusick 27730383Smckusick /* Sanity checks for old file systems. XXX */ 27830383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 27930383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 28034145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 28134145Smckusick fs->fs_nrpos = 8; /* XXX */ 28237737Smckusick return (0); 28312795Ssam out: 28440872Smckusick if (bp) 28540872Smckusick brelse(bp); 28632721Smckusick if (needclose) 28738776Smckusick (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 28841314Smckusick if (ump) { 28937737Smckusick free((caddr_t)ump->um_fs, M_SUPERBLK); 29041314Smckusick free((caddr_t)ump, M_UFSMNT); 29141397Smckusick mp->mnt_data = (qaddr_t)0; 29232721Smckusick } 29337737Smckusick return (error); 29412795Ssam } 29512795Ssam 29639043Smckusick /* 29739043Smckusick * Make a filesystem operational. 29839043Smckusick * Nothing to do at the moment. 29939043Smckusick */ 30039390Smckusick /* ARGSUSED */ 30139043Smckusick ufs_start(mp, flags) 30239043Smckusick struct mount *mp; 30339043Smckusick int flags; 30439043Smckusick { 30512795Ssam 30639043Smckusick return (0); 30739043Smckusick } 30839043Smckusick 30937737Smckusick /* 31037737Smckusick * unmount system call 31137737Smckusick */ 31241314Smckusick ufs_unmount(mp, mntflags) 31337737Smckusick struct mount *mp; 31441314Smckusick int mntflags; 31512795Ssam { 31637737Smckusick register struct ufsmount *ump; 31737737Smckusick register struct fs *fs; 31841314Smckusick int i, error, ronly, flags = 0; 31912795Ssam 32041314Smckusick if (mntflags & MNT_FORCE) 32137737Smckusick return (EINVAL); 32241314Smckusick if (mntflags & MNT_FORCE) 32341314Smckusick flags |= FORCECLOSE; 32439675Smckusick mntflushbuf(mp, 0); 32539675Smckusick if (mntinvalbuf(mp)) 32639675Smckusick return (EBUSY); 32737737Smckusick ump = VFSTOUFS(mp); 32812795Ssam #ifdef QUOTA 32941397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 33041314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 33139898Smckusick return (error); 33241314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 33341314Smckusick if (ump->um_quotas[i] == NULLVP) 33441314Smckusick continue; 33541314Smckusick quotaoff(mp, i); 33641314Smckusick } 33739898Smckusick /* 33841314Smckusick * Here we fall through to vflush again to ensure 33941314Smckusick * that we have gotten rid of all the system vnodes. 34039898Smckusick */ 34141314Smckusick } 34212795Ssam #endif 34341314Smckusick if (error = vflush(mp, NULLVP, flags)) 34439898Smckusick return (error); 34537737Smckusick fs = ump->um_fs; 34637737Smckusick ronly = !fs->fs_ronly; 34740653Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 34838776Smckusick error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 34937737Smckusick vrele(ump->um_devvp); 35041314Smckusick free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 35141314Smckusick free((caddr_t)fs, M_SUPERBLK); 35241314Smckusick free((caddr_t)ump, M_UFSMNT); 35341397Smckusick mp->mnt_data = (qaddr_t)0; 35441397Smckusick mp->mnt_flag &= ~MNT_LOCAL; 35530749Skarels return (error); 35612795Ssam } 35712795Ssam 35837737Smckusick /* 35940376Smckusick * Check to see if a filesystem is mounted on a block device. 36040376Smckusick */ 36140376Smckusick mountedon(vp) 36240376Smckusick register struct vnode *vp; 36340376Smckusick { 36440376Smckusick register struct vnode *vq; 36540376Smckusick 36640653Smckusick if (vp->v_specflags & SI_MOUNTEDON) 36740376Smckusick return (EBUSY); 36840376Smckusick if (vp->v_flag & VALIASED) { 36940653Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 37040376Smckusick if (vq->v_rdev != vp->v_rdev || 37140376Smckusick vq->v_type != vp->v_type) 37240376Smckusick continue; 37340653Smckusick if (vq->v_specflags & SI_MOUNTEDON) 37440376Smckusick return (EBUSY); 37540376Smckusick } 37640376Smckusick } 37740376Smckusick return (0); 37840376Smckusick } 37940376Smckusick 38040376Smckusick /* 38137737Smckusick * Return root of a filesystem 38237737Smckusick */ 38337737Smckusick ufs_root(mp, vpp) 38412795Ssam struct mount *mp; 38537737Smckusick struct vnode **vpp; 38612795Ssam { 38739390Smckusick register struct inode *ip; 38839390Smckusick struct inode *nip; 38939390Smckusick struct vnode tvp; 39037737Smckusick int error; 39137737Smckusick 39239390Smckusick tvp.v_mount = mp; 39339390Smckusick ip = VTOI(&tvp); 39439390Smckusick ip->i_vnode = &tvp; 39539390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 39639390Smckusick error = iget(ip, (ino_t)ROOTINO, &nip); 39737737Smckusick if (error) 39837737Smckusick return (error); 39939390Smckusick *vpp = ITOV(nip); 40037737Smckusick return (0); 40137737Smckusick } 40237737Smckusick 40337737Smckusick /* 40441314Smckusick * Do operations associated with quotas 40541314Smckusick */ 40641314Smckusick ufs_quotactl(mp, cmds, uid, arg) 40741314Smckusick struct mount *mp; 40841314Smckusick int cmds; 40941314Smckusick uid_t uid; 41041314Smckusick caddr_t arg; 41141314Smckusick { 41241314Smckusick struct ufsmount *ump = VFSTOUFS(mp); 413*47571Skarels struct proc *p = curproc; /* XXX */ 41441314Smckusick int cmd, type, error; 41541314Smckusick 41641314Smckusick #ifndef QUOTA 41741314Smckusick return (EOPNOTSUPP); 41841314Smckusick #else 41941314Smckusick if (uid == -1) 420*47571Skarels uid = p->p_cred->p_ruid; 42141314Smckusick cmd = cmds >> SUBCMDSHIFT; 42241314Smckusick 42341314Smckusick switch (cmd) { 42441314Smckusick case Q_GETQUOTA: 42541314Smckusick case Q_SYNC: 426*47571Skarels if (uid == p->p_cred->p_ruid) 42741314Smckusick break; 42841314Smckusick /* fall through */ 42941314Smckusick default: 430*47571Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 43141314Smckusick return (error); 43241314Smckusick } 43341314Smckusick 43441314Smckusick type = cmd & SUBCMDMASK; 43541314Smckusick if ((u_int)type >= MAXQUOTAS) 43641314Smckusick return (EINVAL); 43741314Smckusick 43841314Smckusick switch (cmd) { 43941314Smckusick 44041314Smckusick case Q_QUOTAON: 441*47571Skarels return (quotaon(p, mp, type, arg)); 44241314Smckusick 44341314Smckusick case Q_QUOTAOFF: 44441314Smckusick if (vfs_busy(mp)) 44541314Smckusick return (0); 44641314Smckusick error = quotaoff(mp, type); 44741314Smckusick vfs_unbusy(mp); 44841314Smckusick return (error); 44941314Smckusick 45041314Smckusick case Q_SETQUOTA: 45141314Smckusick return (setquota(mp, uid, type, arg)); 45241314Smckusick 45341314Smckusick case Q_SETUSE: 45441314Smckusick return (setuse(mp, uid, type, arg)); 45541314Smckusick 45641314Smckusick case Q_GETQUOTA: 45741314Smckusick return (getquota(mp, uid, type, arg)); 45841314Smckusick 45941314Smckusick case Q_SYNC: 46041314Smckusick if (vfs_busy(mp)) 46141314Smckusick return (0); 46241314Smckusick error = qsync(mp); 46341314Smckusick vfs_unbusy(mp); 46441314Smckusick return (error); 46541314Smckusick 46641314Smckusick default: 46741314Smckusick return (EINVAL); 46841314Smckusick } 46941314Smckusick /* NOTREACHED */ 47041314Smckusick #endif 47141314Smckusick } 47241314Smckusick 47341314Smckusick /* 47437737Smckusick * Get file system statistics. 47537737Smckusick */ 47637737Smckusick ufs_statfs(mp, sbp) 47737737Smckusick struct mount *mp; 47837737Smckusick register struct statfs *sbp; 47937737Smckusick { 48037737Smckusick register struct ufsmount *ump; 48137737Smckusick register struct fs *fs; 48237737Smckusick 48337737Smckusick ump = VFSTOUFS(mp); 48437737Smckusick fs = ump->um_fs; 48537737Smckusick if (fs->fs_magic != FS_MAGIC) 48637737Smckusick panic("ufs_statfs"); 48737737Smckusick sbp->f_type = MOUNT_UFS; 48837737Smckusick sbp->f_fsize = fs->fs_fsize; 48937737Smckusick sbp->f_bsize = fs->fs_bsize; 49037737Smckusick sbp->f_blocks = fs->fs_dsize; 49137737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 49237737Smckusick fs->fs_cstotal.cs_nffree; 49337737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 49437737Smckusick (fs->fs_dsize - sbp->f_bfree); 49539350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 49637737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 49741397Smckusick if (sbp != &mp->mnt_stat) { 49841397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 49940346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 50041397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 50140346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 50240346Smckusick } 50337737Smckusick return (0); 50437737Smckusick } 50537737Smckusick 50637737Smckusick int syncprt = 0; 50737737Smckusick 50837737Smckusick /* 50937737Smckusick * Go through the disk queues to initiate sandbagged IO; 51037737Smckusick * go through the inodes to write those that have been modified; 51137737Smckusick * initiate the writing of the super block if it has been modified. 51241314Smckusick * 51341314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 51437737Smckusick */ 51537737Smckusick ufs_sync(mp, waitfor) 51637737Smckusick struct mount *mp; 51737737Smckusick int waitfor; 51837737Smckusick { 51939390Smckusick register struct vnode *vp; 52037737Smckusick register struct inode *ip; 52137737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 52237737Smckusick register struct fs *fs; 52339596Smckusick int error, allerror = 0; 52437737Smckusick 52537737Smckusick if (syncprt) 52637737Smckusick bufstats(); 52737737Smckusick fs = ump->um_fs; 52837737Smckusick /* 52937737Smckusick * Write back modified superblock. 53037737Smckusick * Consistency check that the superblock 53137737Smckusick * is still in the buffer cache. 53237737Smckusick */ 53337737Smckusick if (fs->fs_fmod != 0) { 53437737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 53537737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 53637737Smckusick panic("update: rofs mod"); 53737737Smckusick } 53837737Smckusick fs->fs_fmod = 0; 53937737Smckusick fs->fs_time = time.tv_sec; 54041510Smckusick allerror = sbupdate(ump, waitfor); 54137737Smckusick } 54237737Smckusick /* 54337737Smckusick * Write back each (modified) inode. 54437737Smckusick */ 54539877Smckusick loop: 54641462Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 54741462Smckusick /* 54841462Smckusick * If the vnode that we are about to sync is no longer 54941462Smckusick * associated with this mount point, start over. 55041462Smckusick */ 55141462Smckusick if (vp->v_mount != mp) 55241462Smckusick goto loop; 55339390Smckusick ip = VTOI(vp); 55439877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 55539877Smckusick vp->v_dirtyblkhd == NULL) 55637737Smckusick continue; 55739877Smckusick if (vget(vp)) 55839877Smckusick goto loop; 55939877Smckusick if (vp->v_dirtyblkhd) 56039877Smckusick vflushbuf(vp, 0); 56139877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && 56239877Smckusick (error = iupdat(ip, &time, &time, 0))) 56339596Smckusick allerror = error; 56439596Smckusick vput(vp); 56537737Smckusick } 56637737Smckusick /* 56739675Smckusick * Force stale file system control information to be flushed. 56837737Smckusick */ 56939675Smckusick vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 57041314Smckusick #ifdef QUOTA 57141314Smckusick qsync(mp); 57241314Smckusick #endif 57339596Smckusick return (allerror); 57437737Smckusick } 57537737Smckusick 57637737Smckusick /* 57737737Smckusick * Write a superblock and associated information back to disk. 57837737Smckusick */ 57937737Smckusick sbupdate(mp, waitfor) 58037737Smckusick struct ufsmount *mp; 58137737Smckusick int waitfor; 58237737Smckusick { 58337737Smckusick register struct fs *fs = mp->um_fs; 58412795Ssam register struct buf *bp; 58512795Ssam int blks; 58612795Ssam caddr_t space; 58737737Smckusick int i, size, error = 0; 58812795Ssam 58937737Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 59012795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 59134145Smckusick /* Restore compatibility to old file systems. XXX */ 59234145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 59334145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 59437737Smckusick if (waitfor == MNT_WAIT) 59537737Smckusick error = bwrite(bp); 59637737Smckusick else 59737737Smckusick bawrite(bp); 59812795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 59912795Ssam space = (caddr_t)fs->fs_csp[0]; 60012795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 60112795Ssam size = fs->fs_bsize; 60212795Ssam if (i + fs->fs_frag > blks) 60312795Ssam size = (blks - i) * fs->fs_fsize; 60437737Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 60512795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 60612795Ssam space += size; 60737737Smckusick if (waitfor == MNT_WAIT) 60837737Smckusick error = bwrite(bp); 60937737Smckusick else 61037737Smckusick bawrite(bp); 61112795Ssam } 61237737Smckusick return (error); 61312795Ssam } 61412795Ssam 61512795Ssam /* 61637737Smckusick * Print out statistics on the current allocation of the buffer pool. 61737737Smckusick * Can be enabled to print out on every ``sync'' by setting "syncprt" 61837737Smckusick * above. 61937737Smckusick */ 62037737Smckusick bufstats() 62137737Smckusick { 62237737Smckusick int s, i, j, count; 62337737Smckusick register struct buf *bp, *dp; 62437737Smckusick int counts[MAXBSIZE/CLBYTES+1]; 62537737Smckusick static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 62637737Smckusick 62737737Smckusick for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 62837737Smckusick count = 0; 62937737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 63037737Smckusick counts[j] = 0; 63137737Smckusick s = splbio(); 63237737Smckusick for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 63337737Smckusick counts[dp->b_bufsize/CLBYTES]++; 63437737Smckusick count++; 63537737Smckusick } 63637737Smckusick splx(s); 63737737Smckusick printf("%s: total-%d", bname[i], count); 63837737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 63937737Smckusick if (counts[j] != 0) 64037737Smckusick printf(", %d-%d", j * CLBYTES, counts[j]); 64137737Smckusick printf("\n"); 64237737Smckusick } 64337737Smckusick } 64437737Smckusick 64537737Smckusick /* 64637737Smckusick * File handle to vnode 64738453Smckusick * 64838453Smckusick * Have to be really careful about stale file handles: 64938453Smckusick * - check that the inode number is in range 65038453Smckusick * - call iget() to get the locked inode 65138453Smckusick * - check for an unallocated inode (i_mode == 0) 65238453Smckusick * - check that the generation number matches 65337737Smckusick */ 65437737Smckusick ufs_fhtovp(mp, fhp, vpp) 65538453Smckusick register struct mount *mp; 65637737Smckusick struct fid *fhp; 65737737Smckusick struct vnode **vpp; 65837737Smckusick { 65937737Smckusick register struct ufid *ufhp; 66038453Smckusick register struct fs *fs; 66139390Smckusick register struct inode *ip; 66239390Smckusick struct inode *nip; 66339390Smckusick struct vnode tvp; 66437737Smckusick int error; 66537737Smckusick 66637737Smckusick ufhp = (struct ufid *)fhp; 66738453Smckusick fs = VFSTOUFS(mp)->um_fs; 66838453Smckusick if (ufhp->ufid_ino < ROOTINO || 66938453Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 67041397Smckusick *vpp = NULLVP; 67138453Smckusick return (EINVAL); 67238453Smckusick } 67339390Smckusick tvp.v_mount = mp; 67439390Smckusick ip = VTOI(&tvp); 67539390Smckusick ip->i_vnode = &tvp; 67639390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 67739390Smckusick if (error = iget(ip, ufhp->ufid_ino, &nip)) { 67841397Smckusick *vpp = NULLVP; 67937737Smckusick return (error); 68037737Smckusick } 68139390Smckusick ip = nip; 68238453Smckusick if (ip->i_mode == 0) { 68338453Smckusick iput(ip); 68441397Smckusick *vpp = NULLVP; 68538453Smckusick return (EINVAL); 68638453Smckusick } 68737737Smckusick if (ip->i_gen != ufhp->ufid_gen) { 68837737Smckusick iput(ip); 68941397Smckusick *vpp = NULLVP; 69037737Smckusick return (EINVAL); 69137737Smckusick } 69237737Smckusick *vpp = ITOV(ip); 69337737Smckusick return (0); 69437737Smckusick } 69537737Smckusick 69637737Smckusick /* 69738355Smckusick * Vnode pointer to File handle 69837737Smckusick */ 69937737Smckusick /* ARGSUSED */ 70038143Smckusick ufs_vptofh(vp, fhp) 70138143Smckusick struct vnode *vp; 70237737Smckusick struct fid *fhp; 70337737Smckusick { 70438143Smckusick register struct inode *ip = VTOI(vp); 70538143Smckusick register struct ufid *ufhp; 70637737Smckusick 70738143Smckusick ufhp = (struct ufid *)fhp; 70838143Smckusick ufhp->ufid_len = sizeof(struct ufid); 70938143Smckusick ufhp->ufid_ino = ip->i_number; 71038143Smckusick ufhp->ufid_gen = ip->i_gen; 71138143Smckusick return (0); 71237737Smckusick } 71337737Smckusick 71437737Smckusick /* 71512795Ssam * Check that the user's argument is a reasonable 71612795Ssam * thing on which to mount, and return the device number if so. 71712795Ssam */ 71837737Smckusick getmdev(devvpp, fname, ndp) 71937737Smckusick struct vnode **devvpp; 72016697Smckusick caddr_t fname; 72137737Smckusick register struct nameidata *ndp; 72212795Ssam { 72337737Smckusick register struct vnode *vp; 72437737Smckusick int error; 72512795Ssam 72641463Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72716697Smckusick ndp->ni_segflg = UIO_USERSPACE; 72816697Smckusick ndp->ni_dirp = fname; 729*47571Skarels if (error = namei(ndp, curproc)) /* XXX */ 73037737Smckusick return (error); 73137737Smckusick vp = ndp->ni_vp; 73237737Smckusick if (vp->v_type != VBLK) { 73341463Smckusick vrele(vp); 73412795Ssam return (ENOTBLK); 73515956Skarels } 73639532Smckusick if (major(vp->v_rdev) >= nblkdev) { 73741463Smckusick vrele(vp); 73812795Ssam return (ENXIO); 73939532Smckusick } 74037737Smckusick *devvpp = vp; 74112795Ssam return (0); 74212795Ssam } 743