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*41314Smckusick * @(#)lfs_vfsops.c 7.40 (Berkeley) 05/02/90 1823400Smckusick */ 1912795Ssam 2017100Sbloom #include "param.h" 2117100Sbloom #include "systm.h" 22*41314Smckusick #include "user.h" 23*41314Smckusick #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" 34*41314Smckusick #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(); 46*41314Smckusick 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, 58*41314Smckusick 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); 8437737Smckusick mp->m_op = &ufs_vfsops; 8539675Smckusick mp->m_flag = M_RDONLY; 8637737Smckusick mp->m_exroot = 0; 8739390Smckusick mp->m_mounth = (struct vnode *)0; 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; 9939336Smckusick mp->m_next = mp; 10039336Smckusick mp->m_prev = mp; 10139336Smckusick mp->m_vnodecovered = (struct vnode *)0; 10237737Smckusick ump = VFSTOUFS(mp); 10337737Smckusick fs = ump->um_fs; 10440346Smckusick bzero(fs->fs_fsmnt, sizeof(fs->fs_fsmnt)); 10537737Smckusick fs->fs_fsmnt[0] = '/'; 10640346Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->m_stat.f_mntonname, MNAMELEN); 10740346Smckusick (void) copystr(ROOTNAME, mp->m_stat.f_mntfromname, MNAMELEN - 1, &size); 10840346Smckusick bzero(mp->m_stat.f_mntfromname + size, MNAMELEN - size); 10940346Smckusick (void) ufs_statfs(mp, &mp->m_stat); 11037737Smckusick vfs_unlock(mp); 11137737Smckusick inittodr(fs->fs_time); 11237737Smckusick return (0); 11337737Smckusick } 11437737Smckusick 11537737Smckusick /* 11637737Smckusick * VFS Operations. 11737737Smckusick * 11837737Smckusick * mount system call 11937737Smckusick */ 12037737Smckusick ufs_mount(mp, path, data, ndp) 12140346Smckusick register struct mount *mp; 12237737Smckusick char *path; 12337737Smckusick caddr_t data; 12437737Smckusick struct nameidata *ndp; 12537737Smckusick { 12637737Smckusick struct vnode *devvp; 12737737Smckusick struct ufs_args args; 12837737Smckusick struct ufsmount *ump; 12937737Smckusick register struct fs *fs; 13037737Smckusick u_int size; 13137737Smckusick int error; 13237737Smckusick 13337737Smckusick if (error = copyin(data, (caddr_t)&args, sizeof (struct ufs_args))) 13437737Smckusick return (error); 13540371Smckusick /* 13640371Smckusick * Process export requests. 13740371Smckusick */ 13840371Smckusick if ((args.exflags & M_EXPORTED) || (mp->m_flag & M_EXPORTED)) { 13940371Smckusick if (args.exflags & M_EXPORTED) 14040371Smckusick mp->m_flag |= M_EXPORTED; 14140371Smckusick else 14240371Smckusick mp->m_flag &= ~M_EXPORTED; 14340371Smckusick if (args.exflags & M_EXRDONLY) 14440371Smckusick mp->m_flag |= M_EXRDONLY; 14540371Smckusick else 14640371Smckusick mp->m_flag &= ~M_EXRDONLY; 14740371Smckusick mp->m_exroot = args.exroot; 14840371Smckusick } 14939336Smckusick if ((mp->m_flag & M_UPDATE) == 0) { 15040371Smckusick if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 15140371Smckusick return (error); 15239336Smckusick error = mountfs(devvp, mp); 15339336Smckusick } else { 15439336Smckusick ump = VFSTOUFS(mp); 15539336Smckusick fs = ump->um_fs; 15639336Smckusick if (fs->fs_ronly && (mp->m_flag & M_RDONLY) == 0) 15739336Smckusick fs->fs_ronly = 0; 15839336Smckusick /* 15939336Smckusick * Verify that the specified device is the one that 16039336Smckusick * is really being used for the root file system. 16139336Smckusick */ 16240371Smckusick if (args.fspec == 0) 16340371Smckusick return (0); 16440371Smckusick if ((error = getmdev(&devvp, args.fspec, ndp)) != 0) 16540371Smckusick return (error); 16639336Smckusick if (devvp != ump->um_devvp) 16739336Smckusick error = EINVAL; /* needs translation */ 16839336Smckusick } 16937737Smckusick if (error) { 17037737Smckusick vrele(devvp); 17137737Smckusick return (error); 17232721Smckusick } 17337737Smckusick ump = VFSTOUFS(mp); 17437737Smckusick fs = ump->um_fs; 17537737Smckusick (void) copyinstr(path, fs->fs_fsmnt, sizeof(fs->fs_fsmnt) - 1, &size); 17637737Smckusick bzero(fs->fs_fsmnt + size, sizeof(fs->fs_fsmnt) - size); 17740346Smckusick bcopy((caddr_t)fs->fs_fsmnt, (caddr_t)mp->m_stat.f_mntonname, MNAMELEN); 17840346Smckusick (void) copyinstr(args.fspec, mp->m_stat.f_mntfromname, MNAMELEN - 1, 17940346Smckusick &size); 18040346Smckusick bzero(mp->m_stat.f_mntfromname + size, MNAMELEN - size); 18140346Smckusick (void) ufs_statfs(mp, &mp->m_stat); 18237737Smckusick return (0); 18312795Ssam } 18412795Ssam 18537737Smckusick /* 18637737Smckusick * Common code for mount and mountroot 18737737Smckusick */ 18837737Smckusick mountfs(devvp, mp) 18940376Smckusick register struct vnode *devvp; 19037737Smckusick struct mount *mp; 19112795Ssam { 192*41314Smckusick register struct ufsmount *ump = (struct ufsmount *)0; 19337737Smckusick struct buf *bp = NULL; 19412795Ssam register struct fs *fs; 19537737Smckusick dev_t dev = devvp->v_rdev; 19630749Skarels struct partinfo dpart; 19737737Smckusick caddr_t base, space; 19830749Skarels int havepart = 0, blks; 19937737Smckusick int error, i, size; 20021013Smckusick int needclose = 0; 20137737Smckusick int ronly = (mp->m_flag & M_RDONLY) != 0; 20212795Ssam 20340376Smckusick /* 20440376Smckusick * Disallow multiple mounts of the same device. 20540376Smckusick * Disallow mounting of a device that is currently in use. 20640376Smckusick * Flush out any old buffers remaining from a previous use. 20740376Smckusick */ 20840376Smckusick if (error = mountedon(devvp)) 20940376Smckusick return (error); 21040376Smckusick if (vcount(devvp) > 1) 21140376Smckusick return (EBUSY); 21240376Smckusick vinvalbuf(devvp, 1); 213*41314Smckusick if (error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED)) 21437737Smckusick return (error); 21521013Smckusick needclose = 1; 216*41314Smckusick if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED) != 0) { 21737737Smckusick size = DEV_BSIZE; 218*41314Smckusick } else { 21930749Skarels havepart = 1; 22030749Skarels size = dpart.disklab->d_secsize; 22137737Smckusick } 222*41314Smckusick if (error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) 22312795Ssam goto out; 22434421Skarels fs = bp->b_un.b_fs; 22530749Skarels if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 22630749Skarels fs->fs_bsize < sizeof(struct fs)) { 227*41314Smckusick error = EINVAL; /* XXX needs translation */ 22816639Skarels goto out; 22916639Skarels } 230*41314Smckusick ump = (struct ufsmount *)malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 23137737Smckusick ump->um_fs = (struct fs *)malloc((u_long)fs->fs_sbsize, M_SUPERBLK, 23234473Smckusick M_WAITOK); 23337737Smckusick bcopy((caddr_t)bp->b_un.b_addr, (caddr_t)ump->um_fs, 23412795Ssam (u_int)fs->fs_sbsize); 23539675Smckusick if (fs->fs_sbsize < SBSIZE) 23639675Smckusick bp->b_flags |= B_INVAL; 23734421Skarels brelse(bp); 23834421Skarels bp = NULL; 23937737Smckusick fs = ump->um_fs; 24037737Smckusick fs->fs_ronly = ronly; 24112795Ssam if (ronly == 0) 24212795Ssam fs->fs_fmod = 1; 24330749Skarels if (havepart) { 24430749Skarels dpart.part->p_fstype = FS_BSDFFS; 24530749Skarels dpart.part->p_fsize = fs->fs_fsize; 24630749Skarels dpart.part->p_frag = fs->fs_frag; 24731385Skarels dpart.part->p_cpg = fs->fs_cpg; 24830749Skarels } 24912795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 25034473Smckusick base = space = (caddr_t)malloc((u_long)fs->fs_cssize, M_SUPERBLK, 25134473Smckusick M_WAITOK); 25212795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 25312795Ssam size = fs->fs_bsize; 25412795Ssam if (i + fs->fs_frag > blks) 25512795Ssam size = (blks - i) * fs->fs_fsize; 25638776Smckusick error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 25738776Smckusick NOCRED, &bp); 25837737Smckusick if (error) { 25934473Smckusick free((caddr_t)base, M_SUPERBLK); 26012795Ssam goto out; 26112795Ssam } 26234421Skarels bcopy((caddr_t)bp->b_un.b_addr, space, (u_int)size); 26317225Smckusick fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 26412795Ssam space += size; 26534421Skarels brelse(bp); 26634421Skarels bp = NULL; 26712795Ssam } 26837737Smckusick mp->m_data = (qaddr_t)ump; 26940346Smckusick mp->m_stat.f_fsid.val[0] = (long)dev; 27040346Smckusick mp->m_stat.f_fsid.val[1] = MOUNT_UFS; 271*41314Smckusick mp->m_flag |= M_LOCAL; 27237737Smckusick ump->um_mountp = mp; 27337737Smckusick ump->um_dev = dev; 27437737Smckusick ump->um_devvp = devvp; 275*41314Smckusick for (i = 0; i < MAXQUOTAS; i++) 276*41314Smckusick ump->um_quotas[i] = NULLVP; 27740653Smckusick devvp->v_specflags |= SI_MOUNTEDON; 27837737Smckusick 27930383Smckusick /* Sanity checks for old file systems. XXX */ 28030383Smckusick fs->fs_npsect = MAX(fs->fs_npsect, fs->fs_nsect); /* XXX */ 28130383Smckusick fs->fs_interleave = MAX(fs->fs_interleave, 1); /* XXX */ 28234145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 28334145Smckusick fs->fs_nrpos = 8; /* XXX */ 28437737Smckusick return (0); 28512795Ssam out: 28640872Smckusick if (bp) 28740872Smckusick brelse(bp); 28832721Smckusick if (needclose) 28938776Smckusick (void) VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 290*41314Smckusick if (ump) { 29137737Smckusick free((caddr_t)ump->um_fs, M_SUPERBLK); 292*41314Smckusick free((caddr_t)ump, M_UFSMNT); 293*41314Smckusick mp->m_data = (qaddr_t)0; 29432721Smckusick } 29537737Smckusick return (error); 29612795Ssam } 29712795Ssam 29839043Smckusick /* 29939043Smckusick * Make a filesystem operational. 30039043Smckusick * Nothing to do at the moment. 30139043Smckusick */ 30239390Smckusick /* ARGSUSED */ 30339043Smckusick ufs_start(mp, flags) 30439043Smckusick struct mount *mp; 30539043Smckusick int flags; 30639043Smckusick { 30712795Ssam 30839043Smckusick return (0); 30939043Smckusick } 31039043Smckusick 31137737Smckusick /* 31237737Smckusick * unmount system call 31337737Smckusick */ 314*41314Smckusick ufs_unmount(mp, mntflags) 31537737Smckusick struct mount *mp; 316*41314Smckusick int mntflags; 31712795Ssam { 31837737Smckusick register struct ufsmount *ump; 31937737Smckusick register struct fs *fs; 320*41314Smckusick int i, error, ronly, flags = 0; 32112795Ssam 322*41314Smckusick if (mntflags & MNT_FORCE) 32337737Smckusick return (EINVAL); 324*41314Smckusick if (mntflags & MNT_FORCE) 325*41314Smckusick flags |= FORCECLOSE; 32639675Smckusick mntflushbuf(mp, 0); 32739675Smckusick if (mntinvalbuf(mp)) 32839675Smckusick return (EBUSY); 32937737Smckusick ump = VFSTOUFS(mp); 33012795Ssam #ifdef QUOTA 331*41314Smckusick if (mp->m_flag & M_QUOTA) { 332*41314Smckusick if (error = vflush(mp, NULLVP, SKIPSYSTEM|flags)) 33339898Smckusick return (error); 334*41314Smckusick for (i = 0; i < MAXQUOTAS; i++) { 335*41314Smckusick if (ump->um_quotas[i] == NULLVP) 336*41314Smckusick continue; 337*41314Smckusick quotaoff(mp, i); 338*41314Smckusick } 33939898Smckusick /* 340*41314Smckusick * Here we fall through to vflush again to ensure 341*41314Smckusick * that we have gotten rid of all the system vnodes. 34239898Smckusick */ 343*41314Smckusick } 34412795Ssam #endif 345*41314Smckusick if (error = vflush(mp, NULLVP, flags)) 34639898Smckusick return (error); 34737737Smckusick fs = ump->um_fs; 34837737Smckusick ronly = !fs->fs_ronly; 34940653Smckusick ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 35038776Smckusick error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED); 35137737Smckusick vrele(ump->um_devvp); 352*41314Smckusick free((caddr_t)fs->fs_csp[0], M_SUPERBLK); 353*41314Smckusick free((caddr_t)fs, M_SUPERBLK); 354*41314Smckusick free((caddr_t)ump, M_UFSMNT); 355*41314Smckusick mp->m_data = (qaddr_t)0; 356*41314Smckusick mp->m_flag &= ~M_LOCAL; 35730749Skarels return (error); 35812795Ssam } 35912795Ssam 36037737Smckusick /* 36140376Smckusick * Check to see if a filesystem is mounted on a block device. 36240376Smckusick */ 36340376Smckusick mountedon(vp) 36440376Smckusick register struct vnode *vp; 36540376Smckusick { 36640376Smckusick register struct vnode *vq; 36740376Smckusick 36840653Smckusick if (vp->v_specflags & SI_MOUNTEDON) 36940376Smckusick return (EBUSY); 37040376Smckusick if (vp->v_flag & VALIASED) { 37140653Smckusick for (vq = *vp->v_hashchain; vq; vq = vq->v_specnext) { 37240376Smckusick if (vq->v_rdev != vp->v_rdev || 37340376Smckusick vq->v_type != vp->v_type) 37440376Smckusick continue; 37540653Smckusick if (vq->v_specflags & SI_MOUNTEDON) 37640376Smckusick return (EBUSY); 37740376Smckusick } 37840376Smckusick } 37940376Smckusick return (0); 38040376Smckusick } 38140376Smckusick 38240376Smckusick /* 38337737Smckusick * Return root of a filesystem 38437737Smckusick */ 38537737Smckusick ufs_root(mp, vpp) 38612795Ssam struct mount *mp; 38737737Smckusick struct vnode **vpp; 38812795Ssam { 38939390Smckusick register struct inode *ip; 39039390Smckusick struct inode *nip; 39139390Smckusick struct vnode tvp; 39237737Smckusick int error; 39337737Smckusick 39439390Smckusick tvp.v_mount = mp; 39539390Smckusick ip = VTOI(&tvp); 39639390Smckusick ip->i_vnode = &tvp; 39739390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 39839390Smckusick error = iget(ip, (ino_t)ROOTINO, &nip); 39937737Smckusick if (error) 40037737Smckusick return (error); 40139390Smckusick *vpp = ITOV(nip); 40237737Smckusick return (0); 40337737Smckusick } 40437737Smckusick 40537737Smckusick /* 406*41314Smckusick * Do operations associated with quotas 407*41314Smckusick */ 408*41314Smckusick ufs_quotactl(mp, cmds, uid, arg) 409*41314Smckusick struct mount *mp; 410*41314Smckusick int cmds; 411*41314Smckusick uid_t uid; 412*41314Smckusick caddr_t arg; 413*41314Smckusick { 414*41314Smckusick register struct nameidata *ndp = &u.u_nd; 415*41314Smckusick struct ufsmount *ump = VFSTOUFS(mp); 416*41314Smckusick int cmd, type, error; 417*41314Smckusick 418*41314Smckusick #ifndef QUOTA 419*41314Smckusick return (EOPNOTSUPP); 420*41314Smckusick #else 421*41314Smckusick if (uid == -1) 422*41314Smckusick uid = u.u_ruid; 423*41314Smckusick cmd = cmds >> SUBCMDSHIFT; 424*41314Smckusick 425*41314Smckusick switch (cmd) { 426*41314Smckusick case Q_GETQUOTA: 427*41314Smckusick case Q_SYNC: 428*41314Smckusick if (uid == u.u_ruid) 429*41314Smckusick break; 430*41314Smckusick /* fall through */ 431*41314Smckusick default: 432*41314Smckusick if (error = suser(ndp->ni_cred, &u.u_acflag)) 433*41314Smckusick return (error); 434*41314Smckusick } 435*41314Smckusick 436*41314Smckusick type = cmd & SUBCMDMASK; 437*41314Smckusick if ((u_int)type >= MAXQUOTAS) 438*41314Smckusick return (EINVAL); 439*41314Smckusick 440*41314Smckusick switch (cmd) { 441*41314Smckusick 442*41314Smckusick case Q_QUOTAON: 443*41314Smckusick return (quotaon(ndp, mp, type, arg)); 444*41314Smckusick 445*41314Smckusick case Q_QUOTAOFF: 446*41314Smckusick if (vfs_busy(mp)) 447*41314Smckusick return (0); 448*41314Smckusick error = quotaoff(mp, type); 449*41314Smckusick vfs_unbusy(mp); 450*41314Smckusick return (error); 451*41314Smckusick 452*41314Smckusick case Q_SETQUOTA: 453*41314Smckusick return (setquota(mp, uid, type, arg)); 454*41314Smckusick 455*41314Smckusick case Q_SETUSE: 456*41314Smckusick return (setuse(mp, uid, type, arg)); 457*41314Smckusick 458*41314Smckusick case Q_GETQUOTA: 459*41314Smckusick return (getquota(mp, uid, type, arg)); 460*41314Smckusick 461*41314Smckusick case Q_SYNC: 462*41314Smckusick if (vfs_busy(mp)) 463*41314Smckusick return (0); 464*41314Smckusick error = qsync(mp); 465*41314Smckusick vfs_unbusy(mp); 466*41314Smckusick return (error); 467*41314Smckusick 468*41314Smckusick default: 469*41314Smckusick return (EINVAL); 470*41314Smckusick } 471*41314Smckusick /* NOTREACHED */ 472*41314Smckusick #endif 473*41314Smckusick } 474*41314Smckusick 475*41314Smckusick /* 47637737Smckusick * Get file system statistics. 47737737Smckusick */ 47837737Smckusick ufs_statfs(mp, sbp) 47937737Smckusick struct mount *mp; 48037737Smckusick register struct statfs *sbp; 48137737Smckusick { 48237737Smckusick register struct ufsmount *ump; 48337737Smckusick register struct fs *fs; 48437737Smckusick 48537737Smckusick ump = VFSTOUFS(mp); 48637737Smckusick fs = ump->um_fs; 48737737Smckusick if (fs->fs_magic != FS_MAGIC) 48837737Smckusick panic("ufs_statfs"); 48937737Smckusick sbp->f_type = MOUNT_UFS; 49037737Smckusick sbp->f_fsize = fs->fs_fsize; 49137737Smckusick sbp->f_bsize = fs->fs_bsize; 49237737Smckusick sbp->f_blocks = fs->fs_dsize; 49337737Smckusick sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 49437737Smckusick fs->fs_cstotal.cs_nffree; 49537737Smckusick sbp->f_bavail = (fs->fs_dsize * (100 - fs->fs_minfree) / 100) - 49637737Smckusick (fs->fs_dsize - sbp->f_bfree); 49739350Smckusick sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 49837737Smckusick sbp->f_ffree = fs->fs_cstotal.cs_nifree; 49940346Smckusick if (sbp != &mp->m_stat) { 50040346Smckusick bcopy((caddr_t)mp->m_stat.f_mntonname, 50140346Smckusick (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 50240346Smckusick bcopy((caddr_t)mp->m_stat.f_mntfromname, 50340346Smckusick (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 50440346Smckusick } 50537737Smckusick return (0); 50637737Smckusick } 50737737Smckusick 50837737Smckusick int syncprt = 0; 50937737Smckusick 51037737Smckusick /* 51137737Smckusick * Go through the disk queues to initiate sandbagged IO; 51237737Smckusick * go through the inodes to write those that have been modified; 51337737Smckusick * initiate the writing of the super block if it has been modified. 514*41314Smckusick * 515*41314Smckusick * Note: we are always called with the filesystem marked `MPBUSY'. 51637737Smckusick */ 51737737Smckusick ufs_sync(mp, waitfor) 51837737Smckusick struct mount *mp; 51937737Smckusick int waitfor; 52037737Smckusick { 52139390Smckusick register struct vnode *vp; 52237737Smckusick register struct inode *ip; 52337737Smckusick register struct ufsmount *ump = VFSTOUFS(mp); 52437737Smckusick register struct fs *fs; 52539877Smckusick struct vnode *nvp; 52639596Smckusick int error, allerror = 0; 52737737Smckusick static int updlock = 0; 52837737Smckusick 52937737Smckusick if (syncprt) 53037737Smckusick bufstats(); 53137737Smckusick if (updlock) 53237737Smckusick return (EBUSY); 53337737Smckusick fs = ump->um_fs; 53437737Smckusick if (fs == (struct fs *)1) 53537737Smckusick return (0); 53637737Smckusick updlock++; 53737737Smckusick /* 53837737Smckusick * Write back modified superblock. 53937737Smckusick * Consistency check that the superblock 54037737Smckusick * is still in the buffer cache. 54137737Smckusick */ 54237737Smckusick if (fs->fs_fmod != 0) { 54337737Smckusick if (fs->fs_ronly != 0) { /* XXX */ 54437737Smckusick printf("fs = %s\n", fs->fs_fsmnt); 54537737Smckusick panic("update: rofs mod"); 54637737Smckusick } 54737737Smckusick fs->fs_fmod = 0; 54837737Smckusick fs->fs_time = time.tv_sec; 54937737Smckusick error = sbupdate(ump, waitfor); 55037737Smckusick } 55137737Smckusick /* 55237737Smckusick * Write back each (modified) inode. 55337737Smckusick */ 55439877Smckusick loop: 55539877Smckusick for (vp = mp->m_mounth; vp; vp = nvp) { 55639877Smckusick nvp = vp->v_mountf; 55739390Smckusick ip = VTOI(vp); 55839877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) == 0 && 55939877Smckusick vp->v_dirtyblkhd == NULL) 56037737Smckusick continue; 56139877Smckusick if (vget(vp)) 56239877Smckusick goto loop; 56339877Smckusick if (vp->v_dirtyblkhd) 56439877Smckusick vflushbuf(vp, 0); 56539877Smckusick if ((ip->i_flag & (IMOD|IACC|IUPD|ICHG)) && 56639877Smckusick (error = iupdat(ip, &time, &time, 0))) 56739596Smckusick allerror = error; 56839596Smckusick vput(vp); 56937737Smckusick } 57037737Smckusick updlock = 0; 57137737Smckusick /* 57239675Smckusick * Force stale file system control information to be flushed. 57337737Smckusick */ 57439675Smckusick vflushbuf(ump->um_devvp, waitfor == MNT_WAIT ? B_SYNC : 0); 575*41314Smckusick #ifdef QUOTA 576*41314Smckusick qsync(mp); 577*41314Smckusick #endif 57839596Smckusick return (allerror); 57937737Smckusick } 58037737Smckusick 58137737Smckusick /* 58237737Smckusick * Write a superblock and associated information back to disk. 58337737Smckusick */ 58437737Smckusick sbupdate(mp, waitfor) 58537737Smckusick struct ufsmount *mp; 58637737Smckusick int waitfor; 58737737Smckusick { 58837737Smckusick register struct fs *fs = mp->um_fs; 58912795Ssam register struct buf *bp; 59012795Ssam int blks; 59112795Ssam caddr_t space; 59237737Smckusick int i, size, error = 0; 59312795Ssam 59437737Smckusick bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize); 59512795Ssam bcopy((caddr_t)fs, bp->b_un.b_addr, (u_int)fs->fs_sbsize); 59634145Smckusick /* Restore compatibility to old file systems. XXX */ 59734145Smckusick if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 59834145Smckusick bp->b_un.b_fs->fs_nrpos = -1; /* XXX */ 59937737Smckusick if (waitfor == MNT_WAIT) 60037737Smckusick error = bwrite(bp); 60137737Smckusick else 60237737Smckusick bawrite(bp); 60312795Ssam blks = howmany(fs->fs_cssize, fs->fs_fsize); 60412795Ssam space = (caddr_t)fs->fs_csp[0]; 60512795Ssam for (i = 0; i < blks; i += fs->fs_frag) { 60612795Ssam size = fs->fs_bsize; 60712795Ssam if (i + fs->fs_frag > blks) 60812795Ssam size = (blks - i) * fs->fs_fsize; 60937737Smckusick bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), size); 61012795Ssam bcopy(space, bp->b_un.b_addr, (u_int)size); 61112795Ssam space += size; 61237737Smckusick if (waitfor == MNT_WAIT) 61337737Smckusick error = bwrite(bp); 61437737Smckusick else 61537737Smckusick bawrite(bp); 61612795Ssam } 61737737Smckusick return (error); 61812795Ssam } 61912795Ssam 62012795Ssam /* 62137737Smckusick * Print out statistics on the current allocation of the buffer pool. 62237737Smckusick * Can be enabled to print out on every ``sync'' by setting "syncprt" 62337737Smckusick * above. 62437737Smckusick */ 62537737Smckusick bufstats() 62637737Smckusick { 62737737Smckusick int s, i, j, count; 62837737Smckusick register struct buf *bp, *dp; 62937737Smckusick int counts[MAXBSIZE/CLBYTES+1]; 63037737Smckusick static char *bname[BQUEUES] = { "LOCKED", "LRU", "AGE", "EMPTY" }; 63137737Smckusick 63237737Smckusick for (bp = bfreelist, i = 0; bp < &bfreelist[BQUEUES]; bp++, i++) { 63337737Smckusick count = 0; 63437737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 63537737Smckusick counts[j] = 0; 63637737Smckusick s = splbio(); 63737737Smckusick for (dp = bp->av_forw; dp != bp; dp = dp->av_forw) { 63837737Smckusick counts[dp->b_bufsize/CLBYTES]++; 63937737Smckusick count++; 64037737Smckusick } 64137737Smckusick splx(s); 64237737Smckusick printf("%s: total-%d", bname[i], count); 64337737Smckusick for (j = 0; j <= MAXBSIZE/CLBYTES; j++) 64437737Smckusick if (counts[j] != 0) 64537737Smckusick printf(", %d-%d", j * CLBYTES, counts[j]); 64637737Smckusick printf("\n"); 64737737Smckusick } 64837737Smckusick } 64937737Smckusick 65037737Smckusick /* 65137737Smckusick * File handle to vnode 65238453Smckusick * 65338453Smckusick * Have to be really careful about stale file handles: 65438453Smckusick * - check that the inode number is in range 65538453Smckusick * - call iget() to get the locked inode 65638453Smckusick * - check for an unallocated inode (i_mode == 0) 65738453Smckusick * - check that the generation number matches 65837737Smckusick */ 65937737Smckusick ufs_fhtovp(mp, fhp, vpp) 66038453Smckusick register struct mount *mp; 66137737Smckusick struct fid *fhp; 66237737Smckusick struct vnode **vpp; 66337737Smckusick { 66437737Smckusick register struct ufid *ufhp; 66538453Smckusick register struct fs *fs; 66639390Smckusick register struct inode *ip; 66739390Smckusick struct inode *nip; 66839390Smckusick struct vnode tvp; 66937737Smckusick int error; 67037737Smckusick 67137737Smckusick ufhp = (struct ufid *)fhp; 67238453Smckusick fs = VFSTOUFS(mp)->um_fs; 67338453Smckusick if (ufhp->ufid_ino < ROOTINO || 67438453Smckusick ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) { 67538453Smckusick *vpp = (struct vnode *)0; 67638453Smckusick return (EINVAL); 67738453Smckusick } 67839390Smckusick tvp.v_mount = mp; 67939390Smckusick ip = VTOI(&tvp); 68039390Smckusick ip->i_vnode = &tvp; 68139390Smckusick ip->i_dev = VFSTOUFS(mp)->um_dev; 68239390Smckusick if (error = iget(ip, ufhp->ufid_ino, &nip)) { 68338453Smckusick *vpp = (struct vnode *)0; 68437737Smckusick return (error); 68537737Smckusick } 68639390Smckusick ip = nip; 68738453Smckusick if (ip->i_mode == 0) { 68838453Smckusick iput(ip); 68938453Smckusick *vpp = (struct vnode *)0; 69038453Smckusick return (EINVAL); 69138453Smckusick } 69237737Smckusick if (ip->i_gen != ufhp->ufid_gen) { 69337737Smckusick iput(ip); 69438453Smckusick *vpp = (struct vnode *)0; 69537737Smckusick return (EINVAL); 69637737Smckusick } 69737737Smckusick *vpp = ITOV(ip); 69837737Smckusick return (0); 69937737Smckusick } 70037737Smckusick 70137737Smckusick /* 70238355Smckusick * Vnode pointer to File handle 70337737Smckusick */ 70437737Smckusick /* ARGSUSED */ 70538143Smckusick ufs_vptofh(vp, fhp) 70638143Smckusick struct vnode *vp; 70737737Smckusick struct fid *fhp; 70837737Smckusick { 70938143Smckusick register struct inode *ip = VTOI(vp); 71038143Smckusick register struct ufid *ufhp; 71137737Smckusick 71238143Smckusick ufhp = (struct ufid *)fhp; 71338143Smckusick ufhp->ufid_len = sizeof(struct ufid); 71438143Smckusick ufhp->ufid_ino = ip->i_number; 71538143Smckusick ufhp->ufid_gen = ip->i_gen; 71638143Smckusick return (0); 71737737Smckusick } 71837737Smckusick 71937737Smckusick /* 72037737Smckusick * Common code for mount and quota. 72112795Ssam * Check that the user's argument is a reasonable 72212795Ssam * thing on which to mount, and return the device number if so. 72312795Ssam */ 72437737Smckusick getmdev(devvpp, fname, ndp) 72537737Smckusick struct vnode **devvpp; 72616697Smckusick caddr_t fname; 72737737Smckusick register struct nameidata *ndp; 72812795Ssam { 72937737Smckusick register struct vnode *vp; 73037737Smckusick int error; 73112795Ssam 73237737Smckusick ndp->ni_nameiop = LOOKUP | LOCKLEAF | FOLLOW; 73316697Smckusick ndp->ni_segflg = UIO_USERSPACE; 73416697Smckusick ndp->ni_dirp = fname; 73537737Smckusick if (error = namei(ndp)) { 73637737Smckusick if (error == ENOENT) 73737737Smckusick return (ENODEV); /* needs translation */ 73837737Smckusick return (error); 73921013Smckusick } 74037737Smckusick vp = ndp->ni_vp; 74137737Smckusick if (vp->v_type != VBLK) { 74237737Smckusick vput(vp); 74312795Ssam return (ENOTBLK); 74415956Skarels } 74539532Smckusick if (major(vp->v_rdev) >= nblkdev) { 74639532Smckusick vput(vp); 74712795Ssam return (ENXIO); 74839532Smckusick } 74937737Smckusick iunlock(VTOI(vp)); 75037737Smckusick *devvpp = vp; 75112795Ssam return (0); 75212795Ssam } 753