123400Smckusick /* 237737Smckusick * Copyright (c) 1989 The Regents of the University of California. 337737Smckusick * All rights reserved. 423400Smckusick * 537737Smckusick * Redistribution and use in source and binary forms are permitted 637737Smckusick * provided that the above copyright notice and this paragraph are 737737Smckusick * duplicated in all such forms and that any documentation, 837737Smckusick * advertising materials, and other materials related to such 937737Smckusick * distribution and use acknowledge that the software was developed 1037737Smckusick * by the University of California, Berkeley. The name of the 1137737Smckusick * University may not be used to endorse or promote products derived 1237737Smckusick * from this software without specific prior written permission. 1337737Smckusick * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR 1437737Smckusick * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED 1537737Smckusick * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. 1637737Smckusick * 17*41397Smckusick * @(#)lfs_vfsops.c 7.41 (Berkeley) 05/04/90 1823400Smckusick */ 1912795Ssam 2017100Sbloom #include "param.h" 2117100Sbloom #include "systm.h" 2241314Smckusick #include "user.h" 2341314Smckusick #include "proc.h" 2437737Smckusick #include "kernel.h" 2537737Smckusick #include "vnode.h" 2640653Smckusick #include "specdev.h" 2737737Smckusick #include "mount.h" 2817100Sbloom #include "buf.h" 2917100Sbloom #include "file.h" 3037737Smckusick #include "disklabel.h" 3130749Skarels #include "ioctl.h" 3237737Smckusick #include "errno.h" 3331660Smckusick #include "malloc.h" 3441314Smckusick #include "../ufs/quota.h" 3537737Smckusick #include "../ufs/fs.h" 3637737Smckusick #include "../ufs/ufsmount.h" 3737737Smckusick #include "../ufs/inode.h" 3812795Ssam 3937737Smckusick /* 4037737Smckusick * ufs vfs operations. 4137737Smckusick */ 4237737Smckusick int ufs_mount(); 4339043Smckusick int ufs_start(); 4437737Smckusick int ufs_unmount(); 4537737Smckusick int ufs_root(); 4641314Smckusick int ufs_quotactl(); 4737737Smckusick int ufs_statfs(); 4837737Smckusick int ufs_sync(); 4937737Smckusick int ufs_fhtovp(); 5037737Smckusick int ufs_vptofh(); 5139437Smckusick int ufs_init(); 5237737Smckusick 5337737Smckusick struct vfsops ufs_vfsops = { 5437737Smckusick ufs_mount, 5539043Smckusick ufs_start, 5637737Smckusick ufs_unmount, 5737737Smckusick ufs_root, 5841314Smckusick ufs_quotactl, 5937737Smckusick ufs_statfs, 6037737Smckusick ufs_sync, 6137737Smckusick ufs_fhtovp, 6239437Smckusick ufs_vptofh, 6339437Smckusick ufs_init 6437737Smckusick }; 6537737Smckusick 6637737Smckusick /* 6739336Smckusick * Called by vfs_mountroot when ufs is going to be mounted as root. 6837737Smckusick * 6939336Smckusick * Name is updated by mount(8) after booting. 7037737Smckusick */ 7139297Smckusick #define ROOTNAME "root_device" 7237737Smckusick 7337737Smckusick ufs_mountroot() 7412795Ssam { 7537737Smckusick register struct mount *mp; 7637737Smckusick extern struct vnode *rootvp; 7737737Smckusick struct ufsmount *ump; 7812795Ssam register struct fs *fs; 7937737Smckusick u_int size; 8037737Smckusick int error; 8112795Ssam 8237737Smckusick mp = (struct mount *)malloc((u_long)sizeof(struct mount), 8337737Smckusick M_MOUNT, M_WAITOK); 84*41397Smckusick mp->mnt_op = &ufs_vfsops; 85*41397Smckusick mp->mnt_flag = MNT_RDONLY; 86*41397Smckusick mp->mnt_exroot = 0; 87*41397Smckusick mp->mnt_mounth = NULLVP; 8837737Smckusick error = mountfs(rootvp, mp); 8937737Smckusick if (error) { 9037737Smckusick free((caddr_t)mp, M_MOUNT); 9137737Smckusick return (error); 9212795Ssam } 9339336Smckusick if (error = vfs_lock(mp)) { 9437737Smckusick (void)ufs_unmount(mp, 0); 9537737Smckusick free((caddr_t)mp, M_MOUNT); 9637737Smckusick return (error); 9721013Smckusick } 9839336Smckusick rootfs = mp; 99*41397Smckusick mp->mnt_next = mp; 100*41397Smckusick mp->mnt_prev = mp; 101*41397Smckusick mp->mnt_vnodecovered = NULLVP; 10237737Smckusick ump = VFSTOUFS(mp); 10337737Smckusick fs = ump->um_fs; 10440346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 10537737Smckusick fs->fs_fsmnt[0] = '/'; 106*41397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 107*41397Smckusick MNAMELEN); 108*41397Smckusick (void) copystr(ROOTNAME, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 109*41397Smckusick &size); 110*41397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 111*41397Smckusick (void) ufs_statfs(mp, &mp->mnt_stat); 11237737Smckusick vfs_unlock(mp); 11337737Smckusick inittodr(fs->fs_time); 11437737Smckusick return (0); 11537737Smckusick } 11637737Smckusick 11737737Smckusick /* 11837737Smckusick * VFS Operations. 11937737Smckusick * 12037737Smckusick * mount system call 12137737Smckusick */ 12237737Smckusick ufs_mount(mp, path, data, ndp) 12340346Smckusick register struct mount *mp; 12437737Smckusick char *path; 12537737Smckusick caddr_t data; 12637737Smckusick struct nameidata *ndp; 12737737Smckusick { 12837737Smckusick struct vnode *devvp; 12937737Smckusick struct ufs_args args; 13037737Smckusick struct ufsmount *ump; 13137737Smckusick register struct fs *fs; 13237737Smckusick u_int size; 13337737Smckusick int error; 13437737Smckusick 13537737Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 13637737Smckusick return (error); 13740371Smckusick /* 13840371Smckusick * Process export requests. 13940371Smckusick */ 140*41397Smckusick if ((args.exflags & MNT_EXPORTED) || (mp->mnt_flag & MNT_EXPORTED)) { 141*41397Smckusick if (args.exflags & MNT_EXPORTED) 142*41397Smckusick mp->mnt_flag |= MNT_EXPORTED; 14340371Smckusick else 144*41397Smckusick mp->mnt_flag &= ~MNT_EXPORTED; 145*41397Smckusick if (args.exflags & MNT_EXRDONLY) 146*41397Smckusick mp->mnt_flag |= MNT_EXRDONLY; 14740371Smckusick else 148*41397Smckusick mp->mnt_flag &= ~MNT_EXRDONLY; 149*41397Smckusick mp->mnt_exroot = args.exroot; 15040371Smckusick } 151*41397Smckusick if ((mp->mnt_flag & MNT_UPDATE) == 0) { 15240371Smckusick if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 15340371Smckusick return (error); 15439336Smckusick error = mountfs(devvp, mp); 15539336Smckusick } else { 15639336Smckusick ump = VFSTOUFS(mp); 15739336Smckusick fs = ump->um_fs; 158*41397Smckusick if (fs->fs_ronly && (mp->mnt_flag & MNT_RDONLY) == 0) 15939336Smckusick fs->fs_ronly = 0; 16039336Smckusick /* 16139336Smckusick * Verify that the specified device is the one that 16239336Smckusick * is really being used for the root file system. 16339336Smckusick */ 16440371Smckusick if (args.fspec == 0) 16540371Smckusick return (0); 16640371Smckusick if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 16740371Smckusick return (error); 16839336Smckusick if (devvp != ump->um_devvp) 16939336Smckusick error = EINVAL; /* needs translation */ 17039336Smckusick } 17137737Smckusick if (error) { 17237737Smckusick vrele(devvp); 17337737Smckusick return (error); 17432721Smckusick } 17537737Smckusick ump = VFSTOUFS(mp); 17637737Smckusick fs = ump->um_fs; 17737737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 17837737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 179*41397Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->mnt_stat.f_mntonname, 180*41397Smckusick MNAMELEN); 181*41397Smckusick (void) copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, 182*41397Smckusick &size); 183*41397Smckusick bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 184*41397Smckusick (void) ufs_statfs(mp, &mp->mnt_stat); 18537737Smckusick return (0); 18612795Ssam } 18712795Ssam 18837737Smckusick /* 18937737Smckusick * Common code for mount and mountroot 19037737Smckusick */ 19137737Smckusick mountfs(devvp, mp) 19240376Smckusick register struct vnode *devvp; 19337737Smckusick struct mount *mp; 19412795Ssam { 19541314Smckusick register struct ufsmount *ump = (struct ufsmount *)0; 19637737Smckusick struct buf *bp = NULL; 19712795Ssam register struct fs *fs; 19837737Smckusick dev_t dev = devvp->v_rdev; 19930749Skarels struct partinfo dpart; 20037737Smckusick caddr_t base, space; 20130749Skarels int havepart = 0, blks; 20237737Smckusick int error, i, size; 20321013Smckusick int needclose = 0; 204*41397Smckusick int ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 20512795Ssam 20640376Smckusick /* 20740376Smckusick * Disallow multiple mounts of the same device. 20840376Smckusick * Disallow mounting of a device that is currently in use. 20940376Smckusick * Flush out any old buffers remaining from a previous use. 21040376Smckusick */ 21140376Smckusick if (error = mountedon(devvp)) 21240376Smckusick return (error); 21340376Smckusick if (vcount(devvp) > 1) 21440376Smckusick return (EBUSY); 21540376Smckusick vinvalbuf(devvp, 1); 21641314Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED)) 21737737Smckusick return (error); 21821013Smckusick needclose = 1; 21941314Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED) != 0) { 22037737Smckusick size = DEV_BSIZE; 22141314Smckusick } else { 22230749Skarels havepart = 1; 22330749Skarels size = dpart.disklab->d_secsize; 22437737Smckusick } 22541314Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 22612795Ssam goto out; 22734421Skarels fs = bp->b_un.b_fs; 22830749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 22930749Skarels fs->fs_bsize < sizeof(struct fs)) { 23041314Smckusick error = EINVAL; /* XXX needs translation */ 23116639Skarels goto out; 23216639Skarels } 23341314Smckusick ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 23437737Smckusick ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 23534473Smckusick M_WAITOK); 23637737Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 23712795Ssam (u_int)fs->fs_sbsize); 23839675Smckusick if (fs->fs_sbsize < SBSIZE) 23939675Smckusick bp->b_flags |= B_INVAL; 24034421Skarels brelse(bp); 24134421Skarels bp = NULL; 24237737Smckusick fs = ump->um_fs; 24337737Smckusick fs->fs_ronly = ronly; 24412795Ssam if (ronly == 0) 24512795Ssam fs->fs_fmod = 1; 24630749Skarels if (havepart) { 24730749Skarels dpart.part->p_fstype = FS_BSDFFS; 24830749Skarels dpart.part->p_fsize = fs->fs_fsize; 24930749Skarels dpart.part->p_frag = fs->fs_frag; 25031385Skarels dpart.part->p_cpg = fs->fs_cpg; 25130749Skarels } 25212795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 25334473Smckusick base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 25434473Smckusick M_WAITOK); 25512795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 25612795Ssam size = fs->fs_bsize; 25712795Ssam if (i + fs->fs_frag > blks) 25812795Ssam size = (blks - i) * fs->fs_fsize; 25938776Smckusick error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 26038776Smckusick NOCRED, &bp); 26137737Smckusick if (error) { 26234473Smckusick free((caddr_t)base, M_SUPERBLK); 26312795Ssam goto out; 26412795Ssam } 26534421Skarels bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 26617225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 26712795Ssam space += size; 26834421Skarels brelse(bp); 26934421Skarels bp = NULL; 27012795Ssam } 271*41397Smckusick mp->mnt_data = (qaddr_t)ump; 272*41397Smckusick mp->mnt_stat.f_fsid.val[0] = (long)dev; 273*41397Smckusick mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 274*41397Smckusick mp->mnt_flag |= MNT_LOCAL; 27537737Smckusick ump->um_mountp = mp; 27637737Smckusick ump->um_dev = dev; 27737737Smckusick ump->um_devvp = devvp; 27841314Smckusick for (i = 0; i < MAXQUOTAS; i++) 27941314Smckusick ump->um_quotas[i] = NULLVP; 28040653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 28137737Smckusick 28230383Smckusick /* Sanity checks for old file systems. XXX */ 28330383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 28430383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 28534145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 28634145Smckusick fs->fs_nrpos = 8; /* XXX */ 28737737Smckusick return (0); 28812795Ssam out: 28940872Smckusick if (bp) 29040872Smckusick brelse(bp); 29132721Smckusick if (needclose) 29238776Smckusick (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 29341314Smckusick if (ump) { 29437737Smckusick free((caddr_t)ump->um_fs, M_SUPERBLK); 29541314Smckusick free((caddr_t)ump, M_UFSMNT); 296*41397Smckusick mp->mnt_data = (qaddr_t)0; 29732721Smckusick } 29837737Smckusick return (error); 29912795Ssam } 30012795Ssam 30139043Smckusick /* 30239043Smckusick * Make a filesystem operational. 30339043Smckusick * Nothing to do at the moment. 30439043Smckusick */ 30539390Smckusick /* ARGSUSED */ 30639043Smckusick ufs_start(mp, flags) 30739043Smckusick struct mount *mp; 30839043Smckusick int flags; 30939043Smckusick { 31012795Ssam 31139043Smckusick return (0); 31239043Smckusick } 31339043Smckusick 31437737Smckusick /* 31537737Smckusick * unmount system call 31637737Smckusick */ 31741314Smckusick ufs_unmount(mp, mntflags) 31837737Smckusick struct mount *mp; 31941314Smckusick int mntflags; 32012795Ssam { 32137737Smckusick register struct ufsmount *ump; 32237737Smckusick register struct fs *fs; 32341314Smckusick int i, error, ronly, flags = 0; 32412795Ssam 32541314Smckusick if (mntflags & MNT_FORCE) 32637737Smckusick return (EINVAL); 32741314Smckusick if (mntflags & MNT_FORCE) 32841314Smckusick flags |= FORCECLOSE; 32939675Smckusick mntflushbuf(mp, 0); 33039675Smckusick if (mntinvalbuf(mp)) 33139675Smckusick return (EBUSY); 33237737Smckusick ump = VFSTOUFS(mp); 33312795Ssam #ifdef QUOTA 334*41397Smckusick if (mp->mnt_flag & MNT_QUOTA) { 33541314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 33639898Smckusick return (error); 33741314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 33841314Smckusick if (ump->um_quotas[i] == NULLVP) 33941314Smckusick continue; 34041314Smckusick quotaoff(mp, i); 34141314Smckusick } 34239898Smckusick /* 34341314Smckusick * Here we fall through to vflush again to ensure 34441314Smckusick * that we have gotten rid of all the system vnodes. 34539898Smckusick */ 34641314Smckusick } 34712795Ssam #endif 34841314Smckusick if (error = vflush(mp, NULLVP, flags)) 34939898Smckusick return (error); 35037737Smckusick fs = ump->um_fs; 35137737Smckusick ronly = !fs->fs_ronly; 35240653Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 35338776Smckusick error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 35437737Smckusick vrele(ump->um_devvp); 35541314Smckusick free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 35641314Smckusick free((caddr_t)fs, M_SUPERBLK); 35741314Smckusick free((caddr_t)ump, M_UFSMNT); 358*41397Smckusick mp->mnt_data = (qaddr_t)0; 359*41397Smckusick mp->mnt_flag &= ~MNT_LOCAL; 36030749Skarels return (error); 36112795Ssam } 36212795Ssam 36337737Smckusick /* 36440376Smckusick * Check to see if a filesystem is mounted on a block device. 36540376Smckusick */ 36640376Smckusick mountedon(vp) 36740376Smckusick register struct vnode *vp; 36840376Smckusick { 36940376Smckusick register struct vnode *vq; 37040376Smckusick 37140653Smckusick if (vp->v_specflags & SI_MOUNTEDON) 37240376Smckusick return (EBUSY); 37340376Smckusick if (vp->v_flag & VALIASED) { 37440653Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 37540376Smckusick if (vq->v_rdev != vp->v_rdev || 37640376Smckusick vq->v_type != vp->v_type) 37740376Smckusick continue; 37840653Smckusick if (vq->v_specflags & SI_MOUNTEDON) 37940376Smckusick return (EBUSY); 38040376Smckusick } 38140376Smckusick } 38240376Smckusick return (0); 38340376Smckusick } 38440376Smckusick 38540376Smckusick /* 38637737Smckusick * Return root of a filesystem 38737737Smckusick */ 38837737Smckusick ufs_root(mp, vpp) 38912795Ssam struct mount *mp; 39037737Smckusick struct vnode **vpp; 39112795Ssam { 39239390Smckusick register struct inode *ip; 39339390Smckusick struct inode *nip; 39439390Smckusick struct vnode tvp; 39537737Smckusick int error; 39637737Smckusick 39739390Smckusick tvp.v_mount = mp; 39839390Smckusick ip = VTOI(&tvp); 39939390Smckusick ip->i_vnode = &tvp; 40039390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 40139390Smckusick error = iget(ip, (ino_t)ROOTINO, &nip); 40237737Smckusick if (error) 40337737Smckusick return (error); 40439390Smckusick *vpp = ITOV(nip); 40537737Smckusick return (0); 40637737Smckusick } 40737737Smckusick 40837737Smckusick /* 40941314Smckusick * Do operations associated with quotas 41041314Smckusick */ 41141314Smckusick ufs_quotactl(mp, cmds, uid, arg) 41241314Smckusick struct mount *mp; 41341314Smckusick int cmds; 41441314Smckusick uid_t uid; 41541314Smckusick caddr_t arg; 41641314Smckusick { 41741314Smckusick register struct nameidata *ndp = &u.u_nd; 41841314Smckusick struct ufsmount *ump = VFSTOUFS(mp); 41941314Smckusick int cmd, type, error; 42041314Smckusick 42141314Smckusick #ifndef QUOTA 42241314Smckusick return (EOPNOTSUPP); 42341314Smckusick #else 42441314Smckusick if (uid == -1) 42541314Smckusick uid = u.u_ruid; 42641314Smckusick cmd = cmds >> SUBCMDSHIFT; 42741314Smckusick 42841314Smckusick switch (cmd) { 42941314Smckusick case Q_GETQUOTA: 43041314Smckusick case Q_SYNC: 43141314Smckusick if (uid == u.u_ruid) 43241314Smckusick break; 43341314Smckusick /* fall through */ 43441314Smckusick default: 43541314Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 43641314Smckusick return (error); 43741314Smckusick } 43841314Smckusick 43941314Smckusick type = cmd & SUBCMDMASK; 44041314Smckusick if ((u_int)type >= MAXQUOTAS) 44141314Smckusick return (EINVAL); 44241314Smckusick 44341314Smckusick switch (cmd) { 44441314Smckusick 44541314Smckusick case Q_QUOTAON: 44641314Smckusick return (quotaon(ndp, mp, type, arg)); 44741314Smckusick 44841314Smckusick case Q_QUOTAOFF: 44941314Smckusick if (vfs_busy(mp)) 45041314Smckusick return (0); 45141314Smckusick error = quotaoff(mp, type); 45241314Smckusick vfs_unbusy(mp); 45341314Smckusick return (error); 45441314Smckusick 45541314Smckusick case Q_SETQUOTA: 45641314Smckusick return (setquota(mp, uid, type, arg)); 45741314Smckusick 45841314Smckusick case Q_SETUSE: 45941314Smckusick return (setuse(mp, uid, type, arg)); 46041314Smckusick 46141314Smckusick case Q_GETQUOTA: 46241314Smckusick return (getquota(mp, uid, type, arg)); 46341314Smckusick 46441314Smckusick case Q_SYNC: 46541314Smckusick if (vfs_busy(mp)) 46641314Smckusick return (0); 46741314Smckusick error = qsync(mp); 46841314Smckusick vfs_unbusy(mp); 46941314Smckusick return (error); 47041314Smckusick 47141314Smckusick default: 47241314Smckusick return (EINVAL); 47341314Smckusick } 47441314Smckusick /* NOTREACHED */ 47541314Smckusick #endif 47641314Smckusick } 47741314Smckusick 47841314Smckusick /* 47937737Smckusick * Get file system statistics. 48037737Smckusick */ 48137737Smckusick ufs_statfs(mp, sbp) 48237737Smckusick struct mount *mp; 48337737Smckusick register struct statfs *sbp; 48437737Smckusick { 48537737Smckusick register struct ufsmount *ump; 48637737Smckusick register struct fs *fs; 48737737Smckusick 48837737Smckusick ump = VFSTOUFS(mp); 48937737Smckusick fs = ump->um_fs; 49037737Smckusick if (fs->fs_magic != FS_MAGIC) 49137737Smckusick panic("ufs_statfs"); 49237737Smckusick sbp->f_type = MOUNT_UFS; 49337737Smckusick sbp->f_fsize = fs->fs_fsize; 49437737Smckusick sbp->f_bsize = fs->fs_bsize; 49537737Smckusick sbp->f_blocks = fs->fs_dsize; 49637737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 49737737Smckusick fs->fs_cstotal.cs_nffree; 49837737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 49937737Smckusick (fs->fs_dsize - sbp->f_bfree); 50039350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 50137737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 502*41397Smckusick if (sbp != &mp->mnt_stat) { 503*41397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntonname, 50440346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 505*41397Smckusick bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 50640346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 50740346Smckusick } 50837737Smckusick return (0); 50937737Smckusick } 51037737Smckusick 51137737Smckusick int syncprt = 0; 51237737Smckusick 51337737Smckusick /* 51437737Smckusick * Go through the disk queues to initiate sandbagged IO; 51537737Smckusick * go through the inodes to write those that have been modified; 51637737Smckusick * initiate the writing of the super block if it has been modified. 51741314Smckusick * 51841314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 51937737Smckusick */ 52037737Smckusick ufs_sync(mp, waitfor) 52137737Smckusick struct mount *mp; 52237737Smckusick int waitfor; 52337737Smckusick { 52439390Smckusick register struct vnode *vp; 52537737Smckusick register struct inode *ip; 52637737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 52737737Smckusick register struct fs *fs; 52839877Smckusick struct vnode *nvp; 52939596Smckusick int error, allerror = 0; 53037737Smckusick static int updlock = 0; 53137737Smckusick 53237737Smckusick if (syncprt) 53337737Smckusick bufstats(); 53437737Smckusick if (updlock) 53537737Smckusick return (EBUSY); 53637737Smckusick fs = ump->um_fs; 53737737Smckusick if (fs == (struct fs *)1) 53837737Smckusick return (0); 53937737Smckusick updlock++; 54037737Smckusick /* 54137737Smckusick * Write back modified superblock. 54237737Smckusick * Consistency check that the superblock 54337737Smckusick * is still in the buffer cache. 54437737Smckusick */ 54537737Smckusick if (fs->fs_fmod != 0) { 54637737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 54737737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 54837737Smckusick panic("update: rofs mod"); 54937737Smckusick } 55037737Smckusick fs->fs_fmod = 0; 55137737Smckusick fs->fs_time = time.tv_sec; 55237737Smckusick error = sbupdate(ump, waitfor); 55337737Smckusick } 55437737Smckusick /* 55537737Smckusick * Write back each (modified) inode. 55637737Smckusick */ 55739877Smckusick loop: 558*41397Smckusick for (vp = mp->mnt_mounth; vp; vp = nvp) { 55939877Smckusick nvp = vp->v_mountf; 56039390Smckusick ip = VTOI(vp); 56139877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 56239877Smckusick vp->v_dirtyblkhd == NULL) 56337737Smckusick continue; 56439877Smckusick if (vget(vp)) 56539877Smckusick goto loop; 56639877Smckusick if (vp->v_dirtyblkhd) 56739877Smckusick vflushbuf(vp, 0); 56839877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && 56939877Smckusick (error = iupdat(ip, &time, &time, 0))) 57039596Smckusick allerror = error; 57139596Smckusick vput(vp); 57237737Smckusick } 57337737Smckusick updlock = 0; 57437737Smckusick /* 57539675Smckusick * Force stale file system control information to be flushed. 57637737Smckusick */ 57739675Smckusick vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 57841314Smckusick #ifdef QUOTA 57941314Smckusick qsync(mp); 58041314Smckusick #endif 58139596Smckusick return (allerror); 58237737Smckusick } 58337737Smckusick 58437737Smckusick /* 58537737Smckusick * Write a superblock and associated information back to disk. 58637737Smckusick */ 58737737Smckusick sbupdate(mp, waitfor) 58837737Smckusick struct ufsmount *mp; 58937737Smckusick int waitfor; 59037737Smckusick { 59137737Smckusick register struct fs *fs = mp->um_fs; 59212795Ssam register struct buf *bp; 59312795Ssam int blks; 59412795Ssam caddr_t space; 59537737Smckusick int i, size, error = 0; 59612795Ssam 59737737Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 59812795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 59934145Smckusick /* Restore compatibility to old file systems. XXX */ 60034145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 60134145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 60237737Smckusick if (waitfor == MNT_WAIT) 60337737Smckusick error = bwrite(bp); 60437737Smckusick else 60537737Smckusick bawrite(bp); 60612795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 60712795Ssam space = (caddr_t)fs->fs_csp[0]; 60812795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 60912795Ssam size = fs->fs_bsize; 61012795Ssam if (i + fs->fs_frag > blks) 61112795Ssam size = (blks - i) * fs->fs_fsize; 61237737Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 61312795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 61412795Ssam space += size; 61537737Smckusick if (waitfor == MNT_WAIT) 61637737Smckusick error = bwrite(bp); 61737737Smckusick else 61837737Smckusick bawrite(bp); 61912795Ssam } 62037737Smckusick return (error); 62112795Ssam } 62212795Ssam 62312795Ssam /* 62437737Smckusick * Print out statistics on the current allocation of the buffer pool. 62537737Smckusick * Can be enabled to print out on every ``sync'' by setting "syncprt" 62637737Smckusick * above. 62737737Smckusick */ 62837737Smckusick bufstats() 62937737Smckusick { 63037737Smckusick int s, i, j, count; 63137737Smckusick register struct buf *bp, *dp; 63237737Smckusick int counts[MAXBSIZE/CLBYTES+1]; 63337737Smckusick static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 63437737Smckusick 63537737Smckusick for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 63637737Smckusick count = 0; 63737737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 63837737Smckusick counts[j] = 0; 63937737Smckusick s = splbio(); 64037737Smckusick for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 64137737Smckusick counts[dp->b_bufsize/CLBYTES]++; 64237737Smckusick count++; 64337737Smckusick } 64437737Smckusick splx(s); 64537737Smckusick printf("%s: total-%d", bname[i], count); 64637737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 64737737Smckusick if (counts[j] != 0) 64837737Smckusick printf(", %d-%d", j * CLBYTES, counts[j]); 64937737Smckusick printf("\n"); 65037737Smckusick } 65137737Smckusick } 65237737Smckusick 65337737Smckusick /* 65437737Smckusick * File handle to vnode 65538453Smckusick * 65638453Smckusick * Have to be really careful about stale file handles: 65738453Smckusick * - check that the inode number is in range 65838453Smckusick * - call iget() to get the locked inode 65938453Smckusick * - check for an unallocated inode (i_mode == 0) 66038453Smckusick * - check that the generation number matches 66137737Smckusick */ 66237737Smckusick ufs_fhtovp(mp, fhp, vpp) 66338453Smckusick register struct mount *mp; 66437737Smckusick struct fid *fhp; 66537737Smckusick struct vnode **vpp; 66637737Smckusick { 66737737Smckusick register struct ufid *ufhp; 66838453Smckusick register struct fs *fs; 66939390Smckusick register struct inode *ip; 67039390Smckusick struct inode *nip; 67139390Smckusick struct vnode tvp; 67237737Smckusick int error; 67337737Smckusick 67437737Smckusick ufhp = (struct ufid *)fhp; 67538453Smckusick fs = VFSTOUFS(mp)->um_fs; 67638453Smckusick if (ufhp->ufid_ino < ROOTINO || 67738453Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 678*41397Smckusick *vpp = NULLVP; 67938453Smckusick return (EINVAL); 68038453Smckusick } 68139390Smckusick tvp.v_mount = mp; 68239390Smckusick ip = VTOI(&tvp); 68339390Smckusick ip->i_vnode = &tvp; 68439390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 68539390Smckusick if (error = iget(ip, ufhp->ufid_ino, &nip)) { 686*41397Smckusick *vpp = NULLVP; 68737737Smckusick return (error); 68837737Smckusick } 68939390Smckusick ip = nip; 69038453Smckusick if (ip->i_mode == 0) { 69138453Smckusick iput(ip); 692*41397Smckusick *vpp = NULLVP; 69338453Smckusick return (EINVAL); 69438453Smckusick } 69537737Smckusick if (ip->i_gen != ufhp->ufid_gen) { 69637737Smckusick iput(ip); 697*41397Smckusick *vpp = NULLVP; 69837737Smckusick return (EINVAL); 69937737Smckusick } 70037737Smckusick *vpp = ITOV(ip); 70137737Smckusick return (0); 70237737Smckusick } 70337737Smckusick 70437737Smckusick /* 70538355Smckusick * Vnode pointer to File handle 70637737Smckusick */ 70737737Smckusick /* ARGSUSED */ 70838143Smckusick ufs_vptofh(vp, fhp) 70938143Smckusick struct vnode *vp; 71037737Smckusick struct fid *fhp; 71137737Smckusick { 71238143Smckusick register struct inode *ip = VTOI(vp); 71338143Smckusick register struct ufid *ufhp; 71437737Smckusick 71538143Smckusick ufhp = (struct ufid *)fhp; 71638143Smckusick ufhp->ufid_len = sizeof(struct ufid); 71738143Smckusick ufhp->ufid_ino = ip->i_number; 71838143Smckusick ufhp->ufid_gen = ip->i_gen; 71938143Smckusick return (0); 72037737Smckusick } 72137737Smckusick 72237737Smckusick /* 72337737Smckusick * Common code for mount and quota. 72412795Ssam * Check that the user's argument is a reasonable 72512795Ssam * thing on which to mount, and return the device number if so. 72612795Ssam */ 72737737Smckusick getmdev(devvpp, fname, ndp) 72837737Smckusick struct vnode **devvpp; 72916697Smckusick caddr_t fname; 73037737Smckusick register struct nameidata *ndp; 73112795Ssam { 73237737Smckusick register struct vnode *vp; 73337737Smckusick int error; 73412795Ssam 73537737Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 73616697Smckusick ndp->ni_segflg = UIO_USERSPACE; 73716697Smckusick ndp->ni_dirp = fname; 73837737Smckusick if (error = namei(ndp)) { 73937737Smckusick if (error == ENOENT) 74037737Smckusick return (ENODEV); /* needs translation */ 74137737Smckusick return (error); 74221013Smckusick } 74337737Smckusick vp = ndp->ni_vp; 74437737Smckusick if (vp->v_type != VBLK) { 74537737Smckusick vput(vp); 74612795Ssam return (ENOTBLK); 74715956Skarels } 74839532Smckusick if (major(vp->v_rdev) >= nblkdev) { 74939532Smckusick vput(vp); 75012795Ssam return (ENXIO); 75139532Smckusick } 75237737Smckusick iunlock(VTOI(vp)); 75337737Smckusick *devvpp = vp; 75412795Ssam return (0); 75512795Ssam } 756