123400Smckusick /* 237737Smckusick * Copyright (c) 1989 The Regents of the University of California. 337737Smckusick * All rights reserved. 423400Smckusick * 544539Sbostic * %sccs.include.redist.c% 637737Smckusick * 7*48036Smckusick * @(#)lfs_vfsops.c 7.52 (Berkeley) 04/16/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 /* 4439336Smckusick * Called by vfs_mountroot when ufs is going to be mounted as root. 4537737Smckusick * 4639336Smckusick * Name is updated by mount(8) after booting. 4737737Smckusick */ 4839297Smckusick #define ROOTNAME "root_device" 4937737Smckusick 5037737Smckusick ufs_mountroot() 5112795Ssam { 5237737Smckusick register struct mount *mp; 5337737Smckusick extern struct vnode *rootvp; 54*48036Smckusick struct proc *p = curproc; /* XXX */ 5537737Smckusick struct ufsmount *ump; 5612795Ssam register struct fs *fs; 5737737Smckusick u_int size; 5837737Smckusick int error; 5912795Ssam 6037737Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 6137737Smckusick M_MOUNT, M_WAITOK); 6241397Smckusick mp->mnt_op = &ufs_vfsops; 6341397Smckusick mp->mnt_flag = MNT_RDONLY; 6441397Smckusick mp->mnt_exroot = 0; 6541397Smckusick mp->mnt_mounth = NULLVP; 66*48036Smckusick error = mountfs(rootvp, mp, p); 6737737Smckusick if (error) { 6837737Smckusick free((caddr_t)mp, M_MOUNT); 6937737Smckusick return (error); 7012795Ssam } 7139336Smckusick if (error = vfs_lock(mp)) { 72*48036Smckusick (void)ufs_unmount(mp, 0, p); 7337737Smckusick free((caddr_t)mp, M_MOUNT); 7437737Smckusick return (error); 7521013Smckusick } 7639336Smckusick rootfs = mp; 7741397Smckusick mp->mnt_next = mp; 7841397Smckusick mp->mnt_prev = mp; 7941397Smckusick mp->mnt_vnodecovered = NULLVP; 8037737Smckusick ump = VFSTOUFS(mp); 8137737Smckusick fs = ump->um_fs; 8240346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 8337737Smckusick fs->fs_fsmnt[0] = '/'; 8441397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 8541397Smckusick MNAMELEN); 8641397Smckusick (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 8741397Smckusick &size); 8841397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 89*48036Smckusick (void) ufs_statfs(mp, &mp->mnt_stat, p); 9037737Smckusick vfs_unlock(mp); 9137737Smckusick inittodr(fs->fs_time); 9237737Smckusick return (0); 9337737Smckusick } 9437737Smckusick 9537737Smckusick /* 9637737Smckusick * VFS Operations. 9737737Smckusick * 9837737Smckusick * mount system call 9937737Smckusick */ 100*48036Smckusick ufs_mount(mp, path, data, ndp, p) 10140346Smckusick register struct mount *mp; 10237737Smckusick char *path; 10337737Smckusick caddr_t data; 10437737Smckusick struct nameidata *ndp; 105*48036Smckusick struct proc *p; 10637737Smckusick { 10737737Smckusick struct vnode *devvp; 10837737Smckusick struct ufs_args args; 10937737Smckusick struct ufsmount *ump; 11037737Smckusick register struct fs *fs; 11137737Smckusick u_int size; 11237737Smckusick int error; 11337737Smckusick 11437737Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 11537737Smckusick return (error); 11640371Smckusick /* 11740371Smckusick * Process export requests. 11840371Smckusick */ 11941397Smckusick if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { 12041397Smckusick if (args.exflags & MNT_EXPORTED) 12141397Smckusick mp->mnt_flag |= MNT_EXPORTED; 12240371Smckusick else 12341397Smckusick mp->mnt_flag &= ~MNT_EXPORTED; 12441397Smckusick if (args.exflags & MNT_EXRDONLY) 12541397Smckusick mp->mnt_flag |= MNT_EXRDONLY; 12640371Smckusick else 12741397Smckusick mp->mnt_flag &= ~MNT_EXRDONLY; 12841397Smckusick mp->mnt_exroot = args.exroot; 12940371Smckusick } 13041397Smckusick if ((mp->mnt_flag & MNT_UPDATE) == 0) { 131*48036Smckusick if ((error = getmdev(&devvp, args.fspec, ndp, p)) != 0) 13240371Smckusick return (error); 133*48036Smckusick error = mountfs(devvp, mp, p); 13439336Smckusick } else { 13539336Smckusick ump = VFSTOUFS(mp); 13639336Smckusick fs = ump->um_fs; 13741397Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 13839336Smckusick fs->fs_ronly = 0; 13939336Smckusick /* 14039336Smckusick * Verify that the specified device is the one that 14139336Smckusick * is really being used for the root file system. 14239336Smckusick */ 14340371Smckusick if (args.fspec == 0) 14440371Smckusick return (0); 145*48036Smckusick if ((error = getmdev(&devvp, args.fspec, ndp, p)) != 0) 14640371Smckusick return (error); 14739336Smckusick if (devvp != ump->um_devvp) 14839336Smckusick error = EINVAL; /* needs translation */ 14942858Smckusick else 15042858Smckusick vrele(devvp); 15139336Smckusick } 15237737Smckusick if (error) { 15337737Smckusick vrele(devvp); 15437737Smckusick return (error); 15532721Smckusick } 15637737Smckusick ump = VFSTOUFS(mp); 15737737Smckusick fs = ump->um_fs; 15837737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 15937737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 16041397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 16141397Smckusick MNAMELEN); 16241397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 16341397Smckusick &size); 16441397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 165*48036Smckusick (void) ufs_statfs(mp, &mp->mnt_stat, p); 16637737Smckusick return (0); 16712795Ssam } 16812795Ssam 16937737Smckusick /* 17037737Smckusick * Common code for mount and mountroot 17137737Smckusick */ 172*48036Smckusick mountfs(devvp, mp, p) 17340376Smckusick register struct vnode *devvp; 17437737Smckusick struct mount *mp; 175*48036Smckusick struct proc *p; 17612795Ssam { 17741314Smckusick register struct ufsmount *ump = (struct ufsmount *)0; 17837737Smckusick struct buf *bp = NULL; 17912795Ssam register struct fs *fs; 18037737Smckusick dev_t dev = devvp->v_rdev; 18130749Skarels struct partinfo dpart; 18237737Smckusick caddr_t base, space; 18330749Skarels int havepart = 0, blks; 18437737Smckusick int error, i, size; 18521013Smckusick int needclose = 0; 18641397Smckusick int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 18745652Smckusick extern struct vnode *rootvp; 18812795Ssam 18940376Smckusick /* 19040376Smckusick * Disallow multiple mounts of the same device. 19145652Smckusick * Disallow mounting of a device that is currently in use 19245652Smckusick * (except for root, which might share swap device for miniroot). 19340376Smckusick * Flush out any old buffers remaining from a previous use. 19440376Smckusick */ 19540376Smckusick if (error = mountedon(devvp)) 19640376Smckusick return (error); 19745652Smckusick if (vcount(devvp) > 1 && devvp != rootvp) 19840376Smckusick return (EBUSY); 19940376Smckusick vinvalbuf(devvp, 1); 200*48036Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p)) 20137737Smckusick return (error); 20221013Smckusick needclose = 1; 203*48036Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 20437737Smckusick size = DEV_BSIZE; 205*48036Smckusick else { 20630749Skarels havepart = 1; 20730749Skarels size = dpart.disklab->d_secsize; 20837737Smckusick } 20941314Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 21012795Ssam goto out; 21134421Skarels fs = bp->b_un.b_fs; 21230749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 21330749Skarels fs->fs_bsize < sizeof(struct fs)) { 21441314Smckusick error = EINVAL; /* XXX needs translation */ 21516639Skarels goto out; 21616639Skarels } 21741314Smckusick ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 21837737Smckusick ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 21934473Smckusick M_WAITOK); 22037737Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 22112795Ssam (u_int)fs->fs_sbsize); 22239675Smckusick if (fs->fs_sbsize < SBSIZE) 22339675Smckusick bp->b_flags |= B_INVAL; 22434421Skarels brelse(bp); 22534421Skarels bp = NULL; 22637737Smckusick fs = ump->um_fs; 22737737Smckusick fs->fs_ronly = ronly; 22812795Ssam if (ronly == 0) 22912795Ssam fs->fs_fmod = 1; 23030749Skarels if (havepart) { 23130749Skarels dpart.part->p_fstype = FS_BSDFFS; 23230749Skarels dpart.part->p_fsize = fs->fs_fsize; 23330749Skarels dpart.part->p_frag = fs->fs_frag; 23431385Skarels dpart.part->p_cpg = fs->fs_cpg; 23530749Skarels } 23612795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 23734473Smckusick base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 23834473Smckusick M_WAITOK); 23912795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 24012795Ssam size = fs->fs_bsize; 24112795Ssam if (i + fs->fs_frag > blks) 24212795Ssam size = (blks - i) * fs->fs_fsize; 24338776Smckusick error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 24438776Smckusick NOCRED, &bp); 24537737Smckusick if (error) { 24634473Smckusick free((caddr_t)base, M_SUPERBLK); 24712795Ssam goto out; 24812795Ssam } 24934421Skarels bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 25017225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 25112795Ssam space += size; 25234421Skarels brelse(bp); 25334421Skarels bp = NULL; 25412795Ssam } 25541397Smckusick mp->mnt_data = (qaddr_t)ump; 25641397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 25741397Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 25841397Smckusick mp->mnt_flag |= MNT_LOCAL; 25937737Smckusick ump->um_mountp = mp; 26037737Smckusick ump->um_dev = dev; 26137737Smckusick ump->um_devvp = devvp; 26241314Smckusick for (i = 0; i < MAXQUOTAS; i++) 26341314Smckusick ump->um_quotas[i] = NULLVP; 26440653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 26537737Smckusick 26630383Smckusick /* Sanity checks for old file systems. XXX */ 26730383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 26830383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 26934145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 27034145Smckusick fs->fs_nrpos = 8; /* XXX */ 27137737Smckusick return (0); 27212795Ssam out: 27340872Smckusick if (bp) 27440872Smckusick brelse(bp); 27532721Smckusick if (needclose) 276*48036Smckusick (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 27741314Smckusick if (ump) { 27837737Smckusick free((caddr_t)ump->um_fs, M_SUPERBLK); 27941314Smckusick free((caddr_t)ump, M_UFSMNT); 28041397Smckusick mp->mnt_data = (qaddr_t)0; 28132721Smckusick } 28237737Smckusick return (error); 28312795Ssam } 28412795Ssam 28539043Smckusick /* 28639043Smckusick * Make a filesystem operational. 28739043Smckusick * Nothing to do at the moment. 28839043Smckusick */ 28939390Smckusick /* ARGSUSED */ 290*48036Smckusick ufs_start(mp, flags, p) 29139043Smckusick struct mount *mp; 29239043Smckusick int flags; 293*48036Smckusick struct proc *p; 29439043Smckusick { 29512795Ssam 29639043Smckusick return (0); 29739043Smckusick } 29839043Smckusick 29937737Smckusick /* 30037737Smckusick * unmount system call 30137737Smckusick */ 302*48036Smckusick ufs_unmount(mp, mntflags, p) 30337737Smckusick struct mount *mp; 30441314Smckusick int mntflags; 305*48036Smckusick struct proc *p; 30612795Ssam { 30737737Smckusick register struct ufsmount *ump; 30837737Smckusick register struct fs *fs; 30941314Smckusick int i, error, ronly, flags = 0; 31012795Ssam 31141314Smckusick if (mntflags & MNT_FORCE) 31237737Smckusick return (EINVAL); 31341314Smckusick if (mntflags & MNT_FORCE) 31441314Smckusick flags |= FORCECLOSE; 31539675Smckusick mntflushbuf(mp, 0); 31639675Smckusick if (mntinvalbuf(mp)) 31739675Smckusick return (EBUSY); 31837737Smckusick ump = VFSTOUFS(mp); 31912795Ssam #ifdef QUOTA 32041397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 32141314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 32239898Smckusick return (error); 32341314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 32441314Smckusick if (ump->um_quotas[i] == NULLVP) 32541314Smckusick continue; 32641314Smckusick quotaoff(mp, i); 32741314Smckusick } 32839898Smckusick /* 32941314Smckusick * Here we fall through to vflush again to ensure 33041314Smckusick * that we have gotten rid of all the system vnodes. 33139898Smckusick */ 33241314Smckusick } 33312795Ssam #endif 33441314Smckusick if (error = vflush(mp, NULLVP, flags)) 33539898Smckusick return (error); 33637737Smckusick fs = ump->um_fs; 33737737Smckusick ronly = !fs->fs_ronly; 33840653Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 339*48036Smckusick error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 340*48036Smckusick NOCRED, p); 34137737Smckusick vrele(ump->um_devvp); 34241314Smckusick free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 34341314Smckusick free((caddr_t)fs, M_SUPERBLK); 34441314Smckusick free((caddr_t)ump, M_UFSMNT); 34541397Smckusick mp->mnt_data = (qaddr_t)0; 34641397Smckusick mp->mnt_flag &= ~MNT_LOCAL; 34730749Skarels return (error); 34812795Ssam } 34912795Ssam 35037737Smckusick /* 35140376Smckusick * Check to see if a filesystem is mounted on a block device. 35240376Smckusick */ 35340376Smckusick mountedon(vp) 35440376Smckusick register struct vnode *vp; 35540376Smckusick { 35640376Smckusick register struct vnode *vq; 35740376Smckusick 35840653Smckusick if (vp->v_specflags & SI_MOUNTEDON) 35940376Smckusick return (EBUSY); 36040376Smckusick if (vp->v_flag & VALIASED) { 36140653Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 36240376Smckusick if (vq->v_rdev != vp->v_rdev || 36340376Smckusick vq->v_type != vp->v_type) 36440376Smckusick continue; 36540653Smckusick if (vq->v_specflags & SI_MOUNTEDON) 36640376Smckusick return (EBUSY); 36740376Smckusick } 36840376Smckusick } 36940376Smckusick return (0); 37040376Smckusick } 37140376Smckusick 37240376Smckusick /* 37337737Smckusick * Return root of a filesystem 37437737Smckusick */ 37537737Smckusick ufs_root(mp, vpp) 37612795Ssam struct mount *mp; 37737737Smckusick struct vnode **vpp; 37812795Ssam { 37939390Smckusick register struct inode *ip; 38039390Smckusick struct inode *nip; 38139390Smckusick struct vnode tvp; 38237737Smckusick int error; 38337737Smckusick 38439390Smckusick tvp.v_mount = mp; 38539390Smckusick ip = VTOI(&tvp); 38639390Smckusick ip->i_vnode = &tvp; 38739390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 38839390Smckusick error = iget(ip, (ino_t)ROOTINO, &nip); 38937737Smckusick if (error) 39037737Smckusick return (error); 39139390Smckusick *vpp = ITOV(nip); 39237737Smckusick return (0); 39337737Smckusick } 39437737Smckusick 39537737Smckusick /* 39641314Smckusick * Do operations associated with quotas 39741314Smckusick */ 398*48036Smckusick ufs_quotactl(mp, cmds, uid, arg, p) 39941314Smckusick struct mount *mp; 40041314Smckusick int cmds; 40141314Smckusick uid_t uid; 40241314Smckusick caddr_t arg; 403*48036Smckusick struct proc *p; 40441314Smckusick { 40541314Smckusick struct ufsmount *ump = VFSTOUFS(mp); 40641314Smckusick int cmd, type, error; 40741314Smckusick 40841314Smckusick #ifndef QUOTA 40941314Smckusick return (EOPNOTSUPP); 41041314Smckusick #else 41141314Smckusick if (uid == -1) 41247571Skarels uid = p->p_cred->p_ruid; 41341314Smckusick cmd = cmds >> SUBCMDSHIFT; 41441314Smckusick 41541314Smckusick switch (cmd) { 41641314Smckusick case Q_GETQUOTA: 41741314Smckusick case Q_SYNC: 41847571Skarels if (uid == p->p_cred->p_ruid) 41941314Smckusick break; 42041314Smckusick /* fall through */ 42141314Smckusick default: 42247571Skarels if (error = suser(p->p_ucred, &p->p_acflag)) 42341314Smckusick return (error); 42441314Smckusick } 42541314Smckusick 42641314Smckusick type = cmd & SUBCMDMASK; 42741314Smckusick if ((u_int)type >= MAXQUOTAS) 42841314Smckusick return (EINVAL); 42941314Smckusick 43041314Smckusick switch (cmd) { 43141314Smckusick 43241314Smckusick case Q_QUOTAON: 43347571Skarels return (quotaon(p, mp, type, arg)); 43441314Smckusick 43541314Smckusick case Q_QUOTAOFF: 43641314Smckusick if (vfs_busy(mp)) 43741314Smckusick return (0); 43841314Smckusick error = quotaoff(mp, type); 43941314Smckusick vfs_unbusy(mp); 44041314Smckusick return (error); 44141314Smckusick 44241314Smckusick case Q_SETQUOTA: 44341314Smckusick return (setquota(mp, uid, type, arg)); 44441314Smckusick 44541314Smckusick case Q_SETUSE: 44641314Smckusick return (setuse(mp, uid, type, arg)); 44741314Smckusick 44841314Smckusick case Q_GETQUOTA: 44941314Smckusick return (getquota(mp, uid, type, arg)); 45041314Smckusick 45141314Smckusick case Q_SYNC: 45241314Smckusick if (vfs_busy(mp)) 45341314Smckusick return (0); 45441314Smckusick error = qsync(mp); 45541314Smckusick vfs_unbusy(mp); 45641314Smckusick return (error); 45741314Smckusick 45841314Smckusick default: 45941314Smckusick return (EINVAL); 46041314Smckusick } 46141314Smckusick /* NOTREACHED */ 46241314Smckusick #endif 46341314Smckusick } 46441314Smckusick 46541314Smckusick /* 46637737Smckusick * Get file system statistics. 46737737Smckusick */ 468*48036Smckusick ufs_statfs(mp, sbp, p) 46937737Smckusick struct mount *mp; 47037737Smckusick register struct statfs *sbp; 471*48036Smckusick struct proc *p; 47237737Smckusick { 47337737Smckusick register struct ufsmount *ump; 47437737Smckusick register struct fs *fs; 47537737Smckusick 47637737Smckusick ump = VFSTOUFS(mp); 47737737Smckusick fs = ump->um_fs; 47837737Smckusick if (fs->fs_magic != FS_MAGIC) 47937737Smckusick panic("ufs_statfs"); 48037737Smckusick sbp->f_type = MOUNT_UFS; 48137737Smckusick sbp->f_fsize = fs->fs_fsize; 48237737Smckusick sbp->f_bsize = fs->fs_bsize; 48337737Smckusick sbp->f_blocks = fs->fs_dsize; 48437737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 48537737Smckusick fs->fs_cstotal.cs_nffree; 48637737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 48737737Smckusick (fs->fs_dsize - sbp->f_bfree); 48839350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 48937737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 49041397Smckusick if (sbp != &mp->mnt_stat) { 49141397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 49240346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 49341397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 49440346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 49540346Smckusick } 49637737Smckusick return (0); 49737737Smckusick } 49837737Smckusick 49937737Smckusick int syncprt = 0; 50037737Smckusick 50137737Smckusick /* 50237737Smckusick * Go through the disk queues to initiate sandbagged IO; 50337737Smckusick * go through the inodes to write those that have been modified; 50437737Smckusick * initiate the writing of the super block if it has been modified. 50541314Smckusick * 50641314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 50737737Smckusick */ 50837737Smckusick ufs_sync(mp, waitfor) 50937737Smckusick struct mount *mp; 51037737Smckusick int waitfor; 51137737Smckusick { 51239390Smckusick register struct vnode *vp; 51337737Smckusick register struct inode *ip; 51437737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 51537737Smckusick register struct fs *fs; 51639596Smckusick int error, allerror = 0; 51737737Smckusick 51837737Smckusick if (syncprt) 51937737Smckusick bufstats(); 52037737Smckusick fs = ump->um_fs; 52137737Smckusick /* 52237737Smckusick * Write back modified superblock. 52337737Smckusick * Consistency check that the superblock 52437737Smckusick * is still in the buffer cache. 52537737Smckusick */ 52637737Smckusick if (fs->fs_fmod != 0) { 52737737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 52837737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 52937737Smckusick panic("update: rofs mod"); 53037737Smckusick } 53137737Smckusick fs->fs_fmod = 0; 53237737Smckusick fs->fs_time = time.tv_sec; 53341510Smckusick allerror = sbupdate(ump, waitfor); 53437737Smckusick } 53537737Smckusick /* 53637737Smckusick * Write back each (modified) inode. 53737737Smckusick */ 53839877Smckusick loop: 53941462Smckusick for (vp = mp->mnt_mounth; vp; vp = vp->v_mountf) { 54041462Smckusick /* 54141462Smckusick * If the vnode that we are about to sync is no longer 54241462Smckusick * associated with this mount point, start over. 54341462Smckusick */ 54441462Smckusick if (vp->v_mount != mp) 54541462Smckusick goto loop; 54639390Smckusick ip = VTOI(vp); 54739877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 54839877Smckusick vp->v_dirtyblkhd == NULL) 54937737Smckusick continue; 55039877Smckusick if (vget(vp)) 55139877Smckusick goto loop; 55239877Smckusick if (vp->v_dirtyblkhd) 55339877Smckusick vflushbuf(vp, 0); 55439877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && 55539877Smckusick (error = iupdat(ip, &time, &time, 0))) 55639596Smckusick allerror = error; 55739596Smckusick vput(vp); 55837737Smckusick } 55937737Smckusick /* 56039675Smckusick * Force stale file system control information to be flushed. 56137737Smckusick */ 56239675Smckusick vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 56341314Smckusick #ifdef QUOTA 56441314Smckusick qsync(mp); 56541314Smckusick #endif 56639596Smckusick return (allerror); 56737737Smckusick } 56837737Smckusick 56937737Smckusick /* 57037737Smckusick * Write a superblock and associated information back to disk. 57137737Smckusick */ 57237737Smckusick sbupdate(mp, waitfor) 57337737Smckusick struct ufsmount *mp; 57437737Smckusick int waitfor; 57537737Smckusick { 57637737Smckusick register struct fs *fs = mp->um_fs; 57712795Ssam register struct buf *bp; 57812795Ssam int blks; 57912795Ssam caddr_t space; 58037737Smckusick int i, size, error = 0; 58112795Ssam 58237737Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 58312795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 58434145Smckusick /* Restore compatibility to old file systems. XXX */ 58534145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 58634145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 58737737Smckusick if (waitfor == MNT_WAIT) 58837737Smckusick error = bwrite(bp); 58937737Smckusick else 59037737Smckusick bawrite(bp); 59112795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 59212795Ssam space = (caddr_t)fs->fs_csp[0]; 59312795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 59412795Ssam size = fs->fs_bsize; 59512795Ssam if (i + fs->fs_frag > blks) 59612795Ssam size = (blks - i) * fs->fs_fsize; 59737737Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 59812795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 59912795Ssam space += size; 60037737Smckusick if (waitfor == MNT_WAIT) 60137737Smckusick error = bwrite(bp); 60237737Smckusick else 60337737Smckusick bawrite(bp); 60412795Ssam } 60537737Smckusick return (error); 60612795Ssam } 60712795Ssam 60812795Ssam /* 60937737Smckusick * Print out statistics on the current allocation of the buffer pool. 61037737Smckusick * Can be enabled to print out on every ``sync'' by setting "syncprt" 61137737Smckusick * above. 61237737Smckusick */ 61337737Smckusick bufstats() 61437737Smckusick { 61537737Smckusick int s, i, j, count; 61637737Smckusick register struct buf *bp, *dp; 61737737Smckusick int counts[MAXBSIZE/CLBYTES+1]; 61837737Smckusick static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 61937737Smckusick 62037737Smckusick for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 62137737Smckusick count = 0; 62237737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 62337737Smckusick counts[j] = 0; 62437737Smckusick s = splbio(); 62537737Smckusick for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 62637737Smckusick counts[dp->b_bufsize/CLBYTES]++; 62737737Smckusick count++; 62837737Smckusick } 62937737Smckusick splx(s); 63037737Smckusick printf("%s: total-%d", bname[i], count); 63137737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 63237737Smckusick if (counts[j] != 0) 63337737Smckusick printf(", %d-%d", j * CLBYTES, counts[j]); 63437737Smckusick printf("\n"); 63537737Smckusick } 63637737Smckusick } 63737737Smckusick 63837737Smckusick /* 63937737Smckusick * File handle to vnode 64038453Smckusick * 64138453Smckusick * Have to be really careful about stale file handles: 64238453Smckusick * - check that the inode number is in range 64338453Smckusick * - call iget() to get the locked inode 64438453Smckusick * - check for an unallocated inode (i_mode == 0) 64538453Smckusick * - check that the generation number matches 64637737Smckusick */ 64737737Smckusick ufs_fhtovp(mp, fhp, vpp) 64838453Smckusick register struct mount *mp; 64937737Smckusick struct fid *fhp; 65037737Smckusick struct vnode **vpp; 65137737Smckusick { 65237737Smckusick register struct ufid *ufhp; 65338453Smckusick register struct fs *fs; 65439390Smckusick register struct inode *ip; 65539390Smckusick struct inode *nip; 65639390Smckusick struct vnode tvp; 65737737Smckusick int error; 65837737Smckusick 65937737Smckusick ufhp = (struct ufid *)fhp; 66038453Smckusick fs = VFSTOUFS(mp)->um_fs; 66138453Smckusick if (ufhp->ufid_ino < ROOTINO || 66238453Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 66341397Smckusick *vpp = NULLVP; 66438453Smckusick return (EINVAL); 66538453Smckusick } 66639390Smckusick tvp.v_mount = mp; 66739390Smckusick ip = VTOI(&tvp); 66839390Smckusick ip->i_vnode = &tvp; 66939390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 67039390Smckusick if (error = iget(ip, ufhp->ufid_ino, &nip)) { 67141397Smckusick *vpp = NULLVP; 67237737Smckusick return (error); 67337737Smckusick } 67439390Smckusick ip = nip; 67538453Smckusick if (ip->i_mode == 0) { 67638453Smckusick iput(ip); 67741397Smckusick *vpp = NULLVP; 67838453Smckusick return (EINVAL); 67938453Smckusick } 68037737Smckusick if (ip->i_gen != ufhp->ufid_gen) { 68137737Smckusick iput(ip); 68241397Smckusick *vpp = NULLVP; 68337737Smckusick return (EINVAL); 68437737Smckusick } 68537737Smckusick *vpp = ITOV(ip); 68637737Smckusick return (0); 68737737Smckusick } 68837737Smckusick 68937737Smckusick /* 69038355Smckusick * Vnode pointer to File handle 69137737Smckusick */ 69237737Smckusick /* ARGSUSED */ 69338143Smckusick ufs_vptofh(vp, fhp) 69438143Smckusick struct vnode *vp; 69537737Smckusick struct fid *fhp; 69637737Smckusick { 69738143Smckusick register struct inode *ip = VTOI(vp); 69838143Smckusick register struct ufid *ufhp; 69937737Smckusick 70038143Smckusick ufhp = (struct ufid *)fhp; 70138143Smckusick ufhp->ufid_len = sizeof(struct ufid); 70238143Smckusick ufhp->ufid_ino = ip->i_number; 70338143Smckusick ufhp->ufid_gen = ip->i_gen; 70438143Smckusick return (0); 70537737Smckusick } 70637737Smckusick 70737737Smckusick /* 70812795Ssam * Check that the user's argument is a reasonable 70912795Ssam * thing on which to mount, and return the device number if so. 71012795Ssam */ 711*48036Smckusick getmdev(devvpp, fname, ndp, p) 71237737Smckusick struct vnode **devvpp; 71316697Smckusick caddr_t fname; 71437737Smckusick register struct nameidata *ndp; 715*48036Smckusick struct proc *p; 71612795Ssam { 71737737Smckusick register struct vnode *vp; 71837737Smckusick int error; 71912795Ssam 72041463Smckusick ndp->ni_nameiop = LOOKUP | FOLLOW; 72116697Smckusick ndp->ni_segflg = UIO_USERSPACE; 72216697Smckusick ndp->ni_dirp = fname; 723*48036Smckusick if (error = namei(ndp, p)) 72437737Smckusick return (error); 72537737Smckusick vp = ndp->ni_vp; 72637737Smckusick if (vp->v_type != VBLK) { 72741463Smckusick vrele(vp); 72812795Ssam return (ENOTBLK); 72915956Skarels } 73039532Smckusick if (major(vp->v_rdev) >= nblkdev) { 73141463Smckusick vrele(vp); 73212795Ssam return (ENXIO); 73339532Smckusick } 73437737Smckusick *devvpp = vp; 73512795Ssam return (0); 73612795Ssam } 737