1df8bae1dSRodney W. Grimes /* 2df8bae1dSRodney W. Grimes * Copyright (c) 1989, 1991, 1993, 1994 3df8bae1dSRodney W. Grimes * The Regents of the University of California. All rights reserved. 4df8bae1dSRodney W. Grimes * 5df8bae1dSRodney W. Grimes * Redistribution and use in source and binary forms, with or without 6df8bae1dSRodney W. Grimes * modification, are permitted provided that the following conditions 7df8bae1dSRodney W. Grimes * are met: 8df8bae1dSRodney W. Grimes * 1. Redistributions of source code must retain the above copyright 9df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer. 10df8bae1dSRodney W. Grimes * 2. Redistributions in binary form must reproduce the above copyright 11df8bae1dSRodney W. Grimes * notice, this list of conditions and the following disclaimer in the 12df8bae1dSRodney W. Grimes * documentation and/or other materials provided with the distribution. 13df8bae1dSRodney W. Grimes * 3. All advertising materials mentioning features or use of this software 14df8bae1dSRodney W. Grimes * must display the following acknowledgement: 15df8bae1dSRodney W. Grimes * This product includes software developed by the University of 16df8bae1dSRodney W. Grimes * California, Berkeley and its contributors. 17df8bae1dSRodney W. Grimes * 4. Neither the name of the University nor the names of its contributors 18df8bae1dSRodney W. Grimes * may be used to endorse or promote products derived from this software 19df8bae1dSRodney W. Grimes * without specific prior written permission. 20df8bae1dSRodney W. Grimes * 21df8bae1dSRodney W. Grimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22df8bae1dSRodney W. Grimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23df8bae1dSRodney W. Grimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24df8bae1dSRodney W. Grimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25df8bae1dSRodney W. Grimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26df8bae1dSRodney W. Grimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27df8bae1dSRodney W. Grimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28df8bae1dSRodney W. Grimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29df8bae1dSRodney W. Grimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30df8bae1dSRodney W. Grimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31df8bae1dSRodney W. Grimes * SUCH DAMAGE. 32df8bae1dSRodney W. Grimes * 33df8bae1dSRodney W. Grimes * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94 342f9bae59SDavid Greenman * $Id: ffs_vfsops.c,v 1.38 1996/03/02 22:18:34 dyson Exp $ 35df8bae1dSRodney W. Grimes */ 36df8bae1dSRodney W. Grimes 3701733a9bSGarrett Wollman #include "opt_quota.h" 3801733a9bSGarrett Wollman 39df8bae1dSRodney W. Grimes #include <sys/param.h> 40df8bae1dSRodney W. Grimes #include <sys/systm.h> 41df8bae1dSRodney W. Grimes #include <sys/namei.h> 42df8bae1dSRodney W. Grimes #include <sys/proc.h> 43df8bae1dSRodney W. Grimes #include <sys/kernel.h> 44df8bae1dSRodney W. Grimes #include <sys/vnode.h> 45df8bae1dSRodney W. Grimes #include <sys/socket.h> 46df8bae1dSRodney W. Grimes #include <sys/mount.h> 47df8bae1dSRodney W. Grimes #include <sys/buf.h> 48df8bae1dSRodney W. Grimes #include <sys/mbuf.h> 49df8bae1dSRodney W. Grimes #include <sys/file.h> 50df8bae1dSRodney W. Grimes #include <sys/disklabel.h> 51df8bae1dSRodney W. Grimes #include <sys/ioctl.h> 52df8bae1dSRodney W. Grimes #include <sys/errno.h> 53df8bae1dSRodney W. Grimes #include <sys/malloc.h> 54df8bae1dSRodney W. Grimes 55df8bae1dSRodney W. Grimes #include <miscfs/specfs/specdev.h> 56df8bae1dSRodney W. Grimes 57df8bae1dSRodney W. Grimes #include <ufs/ufs/quota.h> 58df8bae1dSRodney W. Grimes #include <ufs/ufs/ufsmount.h> 59df8bae1dSRodney W. Grimes #include <ufs/ufs/inode.h> 60df8bae1dSRodney W. Grimes #include <ufs/ufs/ufs_extern.h> 61df8bae1dSRodney W. Grimes 62df8bae1dSRodney W. Grimes #include <ufs/ffs/fs.h> 63df8bae1dSRodney W. Grimes #include <ufs/ffs/ffs_extern.h> 64df8bae1dSRodney W. Grimes 65f6b04d2bSDavid Greenman #include <vm/vm.h> 66efeaf95aSDavid Greenman #include <vm/vm_param.h> 67efeaf95aSDavid Greenman #include <vm/vm_prot.h> 68f6b04d2bSDavid Greenman #include <vm/vm_page.h> 69f6b04d2bSDavid Greenman #include <vm/vm_object.h> 70f6b04d2bSDavid Greenman 71b8dce649SPoul-Henning Kamp static int ffs_sbupdate __P((struct ufsmount *, int)); 72b8dce649SPoul-Henning Kamp static int ffs_reload __P((struct mount *,struct ucred *,struct proc *)); 73b8dce649SPoul-Henning Kamp static int ffs_oldfscompat __P((struct fs *)); 74b8dce649SPoul-Henning Kamp static int ffs_mount __P((struct mount *, 75b8dce649SPoul-Henning Kamp char *, caddr_t, struct nameidata *, struct proc *)); 76df8bae1dSRodney W. Grimes 77df8bae1dSRodney W. Grimes struct vfsops ufs_vfsops = { 78df8bae1dSRodney W. Grimes ffs_mount, 79df8bae1dSRodney W. Grimes ufs_start, 80df8bae1dSRodney W. Grimes ffs_unmount, 81df8bae1dSRodney W. Grimes ufs_root, 82df8bae1dSRodney W. Grimes ufs_quotactl, 83df8bae1dSRodney W. Grimes ffs_statfs, 84df8bae1dSRodney W. Grimes ffs_sync, 85df8bae1dSRodney W. Grimes ffs_vget, 86df8bae1dSRodney W. Grimes ffs_fhtovp, 87df8bae1dSRodney W. Grimes ffs_vptofh, 88df8bae1dSRodney W. Grimes ffs_init, 89df8bae1dSRodney W. Grimes }; 90df8bae1dSRodney W. Grimes 91862cdb8eSGarrett Wollman VFS_SET(ufs_vfsops, ufs, MOUNT_UFS, 0); 92c901836cSGarrett Wollman 93df8bae1dSRodney W. Grimes extern u_long nextgennumber; 94df8bae1dSRodney W. Grimes 952b14f991SJulian Elischer 96df8bae1dSRodney W. Grimes /* 972b14f991SJulian Elischer * ffs_mount 98df8bae1dSRodney W. Grimes * 992b14f991SJulian Elischer * Called when mounting local physical media 100df8bae1dSRodney W. Grimes * 1012b14f991SJulian Elischer * PARAMETERS: 1022b14f991SJulian Elischer * mountroot 1032b14f991SJulian Elischer * mp mount point structure 1042b14f991SJulian Elischer * path NULL (flag for root mount!!!) 1052b14f991SJulian Elischer * data <unused> 1062b14f991SJulian Elischer * ndp <unused> 1072b14f991SJulian Elischer * p process (user credentials check [statfs]) 1082b14f991SJulian Elischer * 1092b14f991SJulian Elischer * mount 1102b14f991SJulian Elischer * mp mount point structure 1112b14f991SJulian Elischer * path path to mount point 1122b14f991SJulian Elischer * data pointer to argument struct in user space 1132b14f991SJulian Elischer * ndp mount point namei() return (used for 1142b14f991SJulian Elischer * credentials on reload), reused to look 1152b14f991SJulian Elischer * up block device. 1162b14f991SJulian Elischer * p process (user credentials check) 1172b14f991SJulian Elischer * 1182b14f991SJulian Elischer * RETURNS: 0 Success 1192b14f991SJulian Elischer * !0 error number (errno.h) 1202b14f991SJulian Elischer * 1212b14f991SJulian Elischer * LOCK STATE: 1222b14f991SJulian Elischer * 1232b14f991SJulian Elischer * ENTRY 1242b14f991SJulian Elischer * mount point is locked 1252b14f991SJulian Elischer * EXIT 1262b14f991SJulian Elischer * mount point is locked 1272b14f991SJulian Elischer * 1282b14f991SJulian Elischer * NOTES: 1292b14f991SJulian Elischer * A NULL path can be used for a flag since the mount 1302b14f991SJulian Elischer * system call will fail with EFAULT in copyinstr in 1312b14f991SJulian Elischer * namei() if it is a genuine NULL from the user. 132df8bae1dSRodney W. Grimes */ 133b8dce649SPoul-Henning Kamp static int 134df8bae1dSRodney W. Grimes ffs_mount( mp, path, data, ndp, p) 1352b14f991SJulian Elischer register struct mount *mp; /* mount struct pointer*/ 1362b14f991SJulian Elischer char *path; /* path to mount point*/ 1372b14f991SJulian Elischer caddr_t data; /* arguments to FS specific mount*/ 1382b14f991SJulian Elischer struct nameidata *ndp; /* mount point credentials*/ 1392b14f991SJulian Elischer struct proc *p; /* process requesting mount*/ 140df8bae1dSRodney W. Grimes { 1412b14f991SJulian Elischer u_int size; 1422b14f991SJulian Elischer int err = 0; 143df8bae1dSRodney W. Grimes struct vnode *devvp; 1442b14f991SJulian Elischer 145df8bae1dSRodney W. Grimes struct ufs_args args; 14626f9a767SRodney W. Grimes struct ufsmount *ump = 0; 147df8bae1dSRodney W. Grimes register struct fs *fs; 1482b14f991SJulian Elischer int flags; 149df8bae1dSRodney W. Grimes 1502b14f991SJulian Elischer /* 1512b14f991SJulian Elischer * Use NULL path to flag a root mount 1522b14f991SJulian Elischer */ 1532b14f991SJulian Elischer if( path == NULL) { 1542b14f991SJulian Elischer /* 1552b14f991SJulian Elischer *** 1562b14f991SJulian Elischer * Mounting root file system 1572b14f991SJulian Elischer *** 1582b14f991SJulian Elischer */ 1592b14f991SJulian Elischer 1602b14f991SJulian Elischer /* Get vnode for root device*/ 1612b14f991SJulian Elischer if( bdevvp( rootdev, &rootvp)) 1622b14f991SJulian Elischer panic("ffs_mountroot: can't setup bdevvp for root"); 1632b14f991SJulian Elischer 1642b14f991SJulian Elischer /* 1652b14f991SJulian Elischer * FS specific handling 1662b14f991SJulian Elischer */ 1672b14f991SJulian Elischer mp->mnt_flag |= MNT_RDONLY; /* XXX globally applicable?*/ 1682b14f991SJulian Elischer 1692b14f991SJulian Elischer /* 1702b14f991SJulian Elischer * Attempt mount 1712b14f991SJulian Elischer */ 1722b14f991SJulian Elischer if( ( err = ffs_mountfs(rootvp, mp, p)) != 0) { 1732b14f991SJulian Elischer /* fs specific cleanup (if any)*/ 1742b14f991SJulian Elischer goto error_1; 1752b14f991SJulian Elischer } 1762b14f991SJulian Elischer 1772b14f991SJulian Elischer goto dostatfs; /* success*/ 1782b14f991SJulian Elischer 1792b14f991SJulian Elischer } 1802b14f991SJulian Elischer 1812b14f991SJulian Elischer /* 1822b14f991SJulian Elischer *** 1832b14f991SJulian Elischer * Mounting non-root file system or updating a file system 1842b14f991SJulian Elischer *** 1852b14f991SJulian Elischer */ 1862b14f991SJulian Elischer 1872b14f991SJulian Elischer /* copy in user arguments*/ 1882b14f991SJulian Elischer err = copyin(data, (caddr_t)&args, sizeof (struct ufs_args)); 1892b14f991SJulian Elischer if (err) 1902b14f991SJulian Elischer goto error_1; /* can't get arguments*/ 1912b14f991SJulian Elischer 192df8bae1dSRodney W. Grimes /* 193df8bae1dSRodney W. Grimes * If updating, check whether changing from read-only to 194df8bae1dSRodney W. Grimes * read/write; if there is no device name, that's all we do. 195df8bae1dSRodney W. Grimes */ 196df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_UPDATE) { 197df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 198df8bae1dSRodney W. Grimes fs = ump->um_fs; 1992b14f991SJulian Elischer err = 0; 200df8bae1dSRodney W. Grimes if (fs->fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 201df8bae1dSRodney W. Grimes flags = WRITECLOSE; 202df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_FORCE) 203df8bae1dSRodney W. Grimes flags |= FORCECLOSE; 2042b14f991SJulian Elischer if (vfs_busy(mp)) { 2052b14f991SJulian Elischer err = EBUSY; 2062b14f991SJulian Elischer goto error_1; 2072b14f991SJulian Elischer } 2082b14f991SJulian Elischer err = ffs_flushfiles(mp, flags, p); 209df8bae1dSRodney W. Grimes vfs_unbusy(mp); 210df8bae1dSRodney W. Grimes } 2112b14f991SJulian Elischer if (!err && (mp->mnt_flag & MNT_RELOAD)) 2122b14f991SJulian Elischer err = ffs_reload(mp, ndp->ni_cnd.cn_cred, p); 2132b14f991SJulian Elischer if (err) { 2142b14f991SJulian Elischer goto error_1; 2152b14f991SJulian Elischer } 2161469eec8SDavid Greenman if (fs->fs_ronly && (mp->mnt_flag & MNT_WANTRDWR)) { 2171469eec8SDavid Greenman if (!fs->fs_clean) { 2181469eec8SDavid Greenman if (mp->mnt_flag & MNT_FORCE) { 2191469eec8SDavid Greenman printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt); 2201469eec8SDavid Greenman } else { 2211469eec8SDavid Greenman printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n", 2221469eec8SDavid Greenman fs->fs_fsmnt); 2232b14f991SJulian Elischer err = EPERM; 2242b14f991SJulian Elischer goto error_1; 2251469eec8SDavid Greenman } 2261469eec8SDavid Greenman } 227df8bae1dSRodney W. Grimes fs->fs_ronly = 0; 2281469eec8SDavid Greenman } 229e0e9c421SDavid Greenman if (fs->fs_ronly == 0) { 230e0e9c421SDavid Greenman fs->fs_clean = 0; 231e0e9c421SDavid Greenman ffs_sbupdate(ump, MNT_WAIT); 232e0e9c421SDavid Greenman } 2332b14f991SJulian Elischer /* if not updating name...*/ 234df8bae1dSRodney W. Grimes if (args.fspec == 0) { 235df8bae1dSRodney W. Grimes /* 2362b14f991SJulian Elischer * Process export requests. Jumping to "success" 2372b14f991SJulian Elischer * will return the vfs_export() error code. 238df8bae1dSRodney W. Grimes */ 2392b14f991SJulian Elischer err = vfs_export(mp, &ump->um_export, &args.export); 2402b14f991SJulian Elischer goto success; 241df8bae1dSRodney W. Grimes } 242df8bae1dSRodney W. Grimes } 2432b14f991SJulian Elischer 244df8bae1dSRodney W. Grimes /* 245df8bae1dSRodney W. Grimes * Not an update, or updating the name: look up the name 246df8bae1dSRodney W. Grimes * and verify that it refers to a sensible block device. 247df8bae1dSRodney W. Grimes */ 248df8bae1dSRodney W. Grimes NDINIT(ndp, LOOKUP, FOLLOW, UIO_USERSPACE, args.fspec, p); 2492b14f991SJulian Elischer err = namei(ndp); 2502b14f991SJulian Elischer if (err) { 2512b14f991SJulian Elischer /* can't get devvp!*/ 2522b14f991SJulian Elischer goto error_1; 2532b14f991SJulian Elischer } 2542b14f991SJulian Elischer 255df8bae1dSRodney W. Grimes devvp = ndp->ni_vp; 256df8bae1dSRodney W. Grimes 257df8bae1dSRodney W. Grimes if (devvp->v_type != VBLK) { 2582b14f991SJulian Elischer err = ENOTBLK; 2592b14f991SJulian Elischer goto error_2; 260df8bae1dSRodney W. Grimes } 261df8bae1dSRodney W. Grimes if (major(devvp->v_rdev) >= nblkdev) { 2622b14f991SJulian Elischer err = ENXIO; 2632b14f991SJulian Elischer goto error_2; 264df8bae1dSRodney W. Grimes } 2652b14f991SJulian Elischer if (mp->mnt_flag & MNT_UPDATE) { 2662b14f991SJulian Elischer /* 2672b14f991SJulian Elischer ******************** 2682b14f991SJulian Elischer * UPDATE 2692b14f991SJulian Elischer ******************** 2702b14f991SJulian Elischer */ 2712b14f991SJulian Elischer 272df8bae1dSRodney W. Grimes if (devvp != ump->um_devvp) 2732b14f991SJulian Elischer err = EINVAL; /* needs translation */ 274df8bae1dSRodney W. Grimes else 275df8bae1dSRodney W. Grimes vrele(devvp); 2762b14f991SJulian Elischer /* 2772b14f991SJulian Elischer * Update device name only on success 2782b14f991SJulian Elischer */ 2792b14f991SJulian Elischer if( !err) { 2802b14f991SJulian Elischer /* Save "mounted from" info for mount point (NULL pad)*/ 2812b14f991SJulian Elischer copyinstr( args.fspec, 2822b14f991SJulian Elischer mp->mnt_stat.f_mntfromname, 2832b14f991SJulian Elischer MNAMELEN - 1, 284df8bae1dSRodney W. Grimes &size); 285df8bae1dSRodney W. Grimes bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 286df8bae1dSRodney W. Grimes } 2872b14f991SJulian Elischer } else { 2882b14f991SJulian Elischer /* 2892b14f991SJulian Elischer ******************** 2902b14f991SJulian Elischer * NEW MOUNT 2912b14f991SJulian Elischer ******************** 2922b14f991SJulian Elischer */ 2932b14f991SJulian Elischer 2942b14f991SJulian Elischer /* 2952b14f991SJulian Elischer * Since this is a new mount, we want the names for 2962b14f991SJulian Elischer * the device and the mount point copied in. If an 2972b14f991SJulian Elischer * error occurs, the mountpoint is discarded by the 2982b14f991SJulian Elischer * upper level code. 2992b14f991SJulian Elischer */ 3002b14f991SJulian Elischer /* Save "last mounted on" info for mount point (NULL pad)*/ 3012b14f991SJulian Elischer copyinstr( path, /* mount point*/ 3022b14f991SJulian Elischer mp->mnt_stat.f_mntonname, /* save area*/ 3032b14f991SJulian Elischer MNAMELEN - 1, /* max size*/ 3042b14f991SJulian Elischer &size); /* real size*/ 3052b14f991SJulian Elischer bzero( mp->mnt_stat.f_mntonname + size, MNAMELEN - size); 3062b14f991SJulian Elischer 3072b14f991SJulian Elischer /* Save "mounted from" info for mount point (NULL pad)*/ 3082b14f991SJulian Elischer copyinstr( args.fspec, /* device name*/ 3092b14f991SJulian Elischer mp->mnt_stat.f_mntfromname, /* save area*/ 3102b14f991SJulian Elischer MNAMELEN - 1, /* max size*/ 3112b14f991SJulian Elischer &size); /* real size*/ 3122b14f991SJulian Elischer bzero( mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 3132b14f991SJulian Elischer 3142b14f991SJulian Elischer err = ffs_mountfs(devvp, mp, p); 3152b14f991SJulian Elischer } 3162b14f991SJulian Elischer if (err) { 3172b14f991SJulian Elischer goto error_2; 3182b14f991SJulian Elischer } 3192b14f991SJulian Elischer 3202b14f991SJulian Elischer dostatfs: 3212b14f991SJulian Elischer /* 3222b14f991SJulian Elischer * Initialize FS stat information in mount struct; uses both 3232b14f991SJulian Elischer * mp->mnt_stat.f_mntonname and mp->mnt_stat.f_mntfromname 3242b14f991SJulian Elischer * 3252b14f991SJulian Elischer * This code is common to root and non-root mounts 3262b14f991SJulian Elischer */ 3272b14f991SJulian Elischer (void)VFS_STATFS(mp, &mp->mnt_stat, p); 3282b14f991SJulian Elischer 3292b14f991SJulian Elischer goto success; 3302b14f991SJulian Elischer 3312b14f991SJulian Elischer 3322b14f991SJulian Elischer error_2: /* error with devvp held*/ 3332b14f991SJulian Elischer 3342b14f991SJulian Elischer /* release devvp before failing*/ 3352b14f991SJulian Elischer vrele(devvp); 3362b14f991SJulian Elischer 3372b14f991SJulian Elischer error_1: /* no state to back out*/ 3382b14f991SJulian Elischer 3392b14f991SJulian Elischer success: 3402b14f991SJulian Elischer return( err); 3412b14f991SJulian Elischer } 3422b14f991SJulian Elischer 343df8bae1dSRodney W. Grimes 344df8bae1dSRodney W. Grimes /* 345df8bae1dSRodney W. Grimes * Reload all incore data for a filesystem (used after running fsck on 346df8bae1dSRodney W. Grimes * the root filesystem and finding things to fix). The filesystem must 347df8bae1dSRodney W. Grimes * be mounted read-only. 348df8bae1dSRodney W. Grimes * 349df8bae1dSRodney W. Grimes * Things to do to update the mount: 350df8bae1dSRodney W. Grimes * 1) invalidate all cached meta-data. 351df8bae1dSRodney W. Grimes * 2) re-read superblock from disk. 352df8bae1dSRodney W. Grimes * 3) re-read summary information from disk. 353df8bae1dSRodney W. Grimes * 4) invalidate all inactive vnodes. 354df8bae1dSRodney W. Grimes * 5) invalidate all cached file data. 355df8bae1dSRodney W. Grimes * 6) re-read inode data for all active vnodes. 356df8bae1dSRodney W. Grimes */ 357b8dce649SPoul-Henning Kamp static int 3582b14f991SJulian Elischer ffs_reload(mp, cred, p) 3592b14f991SJulian Elischer register struct mount *mp; 360df8bae1dSRodney W. Grimes struct ucred *cred; 361df8bae1dSRodney W. Grimes struct proc *p; 362df8bae1dSRodney W. Grimes { 363df8bae1dSRodney W. Grimes register struct vnode *vp, *nvp, *devvp; 364df8bae1dSRodney W. Grimes struct inode *ip; 365df8bae1dSRodney W. Grimes struct csum *space; 366df8bae1dSRodney W. Grimes struct buf *bp; 367df8bae1dSRodney W. Grimes struct fs *fs; 368df8bae1dSRodney W. Grimes int i, blks, size, error; 369df8bae1dSRodney W. Grimes 3702b14f991SJulian Elischer if ((mp->mnt_flag & MNT_RDONLY) == 0) 371df8bae1dSRodney W. Grimes return (EINVAL); 372df8bae1dSRodney W. Grimes /* 373df8bae1dSRodney W. Grimes * Step 1: invalidate all cached meta-data. 374df8bae1dSRodney W. Grimes */ 3752b14f991SJulian Elischer devvp = VFSTOUFS(mp)->um_devvp; 376df8bae1dSRodney W. Grimes if (vinvalbuf(devvp, 0, cred, p, 0, 0)) 377df8bae1dSRodney W. Grimes panic("ffs_reload: dirty1"); 378df8bae1dSRodney W. Grimes /* 379df8bae1dSRodney W. Grimes * Step 2: re-read superblock from disk. 380df8bae1dSRodney W. Grimes */ 381c9671602SPoul-Henning Kamp error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp); 382c9671602SPoul-Henning Kamp if (error) 383df8bae1dSRodney W. Grimes return (error); 384df8bae1dSRodney W. Grimes fs = (struct fs *)bp->b_data; 385df8bae1dSRodney W. Grimes if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 386df8bae1dSRodney W. Grimes fs->fs_bsize < sizeof(struct fs)) { 387df8bae1dSRodney W. Grimes brelse(bp); 388df8bae1dSRodney W. Grimes return (EIO); /* XXX needs translation */ 389df8bae1dSRodney W. Grimes } 3902b14f991SJulian Elischer fs = VFSTOUFS(mp)->um_fs; 391df8bae1dSRodney W. Grimes bcopy(&fs->fs_csp[0], &((struct fs *)bp->b_data)->fs_csp[0], 392df8bae1dSRodney W. Grimes sizeof(fs->fs_csp)); 393df8bae1dSRodney W. Grimes bcopy(bp->b_data, fs, (u_int)fs->fs_sbsize); 394df8bae1dSRodney W. Grimes if (fs->fs_sbsize < SBSIZE) 395df8bae1dSRodney W. Grimes bp->b_flags |= B_INVAL; 396df8bae1dSRodney W. Grimes brelse(bp); 397df8bae1dSRodney W. Grimes ffs_oldfscompat(fs); 398df8bae1dSRodney W. Grimes /* 399df8bae1dSRodney W. Grimes * Step 3: re-read summary information from disk. 400df8bae1dSRodney W. Grimes */ 401df8bae1dSRodney W. Grimes blks = howmany(fs->fs_cssize, fs->fs_fsize); 402df8bae1dSRodney W. Grimes space = fs->fs_csp[0]; 403df8bae1dSRodney W. Grimes for (i = 0; i < blks; i += fs->fs_frag) { 404df8bae1dSRodney W. Grimes size = fs->fs_bsize; 405df8bae1dSRodney W. Grimes if (i + fs->fs_frag > blks) 406df8bae1dSRodney W. Grimes size = (blks - i) * fs->fs_fsize; 407c9671602SPoul-Henning Kamp error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 408c9671602SPoul-Henning Kamp NOCRED, &bp); 409c9671602SPoul-Henning Kamp if (error) 410df8bae1dSRodney W. Grimes return (error); 411df8bae1dSRodney W. Grimes bcopy(bp->b_data, fs->fs_csp[fragstoblks(fs, i)], (u_int)size); 412df8bae1dSRodney W. Grimes brelse(bp); 413df8bae1dSRodney W. Grimes } 414df8bae1dSRodney W. Grimes loop: 4152b14f991SJulian Elischer for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 416df8bae1dSRodney W. Grimes nvp = vp->v_mntvnodes.le_next; 417df8bae1dSRodney W. Grimes /* 418df8bae1dSRodney W. Grimes * Step 4: invalidate all inactive vnodes. 419df8bae1dSRodney W. Grimes */ 420df8bae1dSRodney W. Grimes if (vp->v_usecount == 0) { 421df8bae1dSRodney W. Grimes vgone(vp); 422df8bae1dSRodney W. Grimes continue; 423df8bae1dSRodney W. Grimes } 424df8bae1dSRodney W. Grimes /* 425df8bae1dSRodney W. Grimes * Step 5: invalidate all cached file data. 426df8bae1dSRodney W. Grimes */ 427df8bae1dSRodney W. Grimes if (vget(vp, 1)) 428df8bae1dSRodney W. Grimes goto loop; 429df8bae1dSRodney W. Grimes if (vinvalbuf(vp, 0, cred, p, 0, 0)) 430df8bae1dSRodney W. Grimes panic("ffs_reload: dirty2"); 431df8bae1dSRodney W. Grimes /* 432df8bae1dSRodney W. Grimes * Step 6: re-read inode data for all active vnodes. 433df8bae1dSRodney W. Grimes */ 434df8bae1dSRodney W. Grimes ip = VTOI(vp); 435c9671602SPoul-Henning Kamp error = 436df8bae1dSRodney W. Grimes bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 437c9671602SPoul-Henning Kamp (int)fs->fs_bsize, NOCRED, &bp); 438c9671602SPoul-Henning Kamp if (error) { 439df8bae1dSRodney W. Grimes vput(vp); 440df8bae1dSRodney W. Grimes return (error); 441df8bae1dSRodney W. Grimes } 442df8bae1dSRodney W. Grimes ip->i_din = *((struct dinode *)bp->b_data + 443df8bae1dSRodney W. Grimes ino_to_fsbo(fs, ip->i_number)); 444df8bae1dSRodney W. Grimes brelse(bp); 445df8bae1dSRodney W. Grimes vput(vp); 4462b14f991SJulian Elischer if (vp->v_mount != mp) 447df8bae1dSRodney W. Grimes goto loop; 448df8bae1dSRodney W. Grimes } 449df8bae1dSRodney W. Grimes return (0); 450df8bae1dSRodney W. Grimes } 451df8bae1dSRodney W. Grimes 452df8bae1dSRodney W. Grimes /* 453df8bae1dSRodney W. Grimes * Common code for mount and mountroot 454df8bae1dSRodney W. Grimes */ 455df8bae1dSRodney W. Grimes int 456df8bae1dSRodney W. Grimes ffs_mountfs(devvp, mp, p) 457df8bae1dSRodney W. Grimes register struct vnode *devvp; 458df8bae1dSRodney W. Grimes struct mount *mp; 459df8bae1dSRodney W. Grimes struct proc *p; 460df8bae1dSRodney W. Grimes { 461df8bae1dSRodney W. Grimes register struct ufsmount *ump; 462df8bae1dSRodney W. Grimes struct buf *bp; 463df8bae1dSRodney W. Grimes register struct fs *fs; 464df8bae1dSRodney W. Grimes dev_t dev = devvp->v_rdev; 465df8bae1dSRodney W. Grimes struct partinfo dpart; 466df8bae1dSRodney W. Grimes caddr_t base, space; 467df8bae1dSRodney W. Grimes int havepart = 0, blks; 468df8bae1dSRodney W. Grimes int error, i, size; 469df8bae1dSRodney W. Grimes int ronly; 4702b14f991SJulian Elischer u_int strsize; 471df8bae1dSRodney W. Grimes 472df8bae1dSRodney W. Grimes /* 473df8bae1dSRodney W. Grimes * Disallow multiple mounts of the same device. 474df8bae1dSRodney W. Grimes * Disallow mounting of a device that is currently in use 475df8bae1dSRodney W. Grimes * (except for root, which might share swap device for miniroot). 476df8bae1dSRodney W. Grimes * Flush out any old buffers remaining from a previous use. 477df8bae1dSRodney W. Grimes */ 478c9671602SPoul-Henning Kamp error = vfs_mountedon(devvp); 479c9671602SPoul-Henning Kamp if (error) 480df8bae1dSRodney W. Grimes return (error); 481df8bae1dSRodney W. Grimes if (vcount(devvp) > 1 && devvp != rootvp) 482df8bae1dSRodney W. Grimes return (EBUSY); 483c9671602SPoul-Henning Kamp error = vinvalbuf(devvp, V_SAVE, p->p_ucred, p, 0, 0); 484c9671602SPoul-Henning Kamp if (error) 485df8bae1dSRodney W. Grimes return (error); 486df8bae1dSRodney W. Grimes 487df8bae1dSRodney W. Grimes ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 488c9671602SPoul-Henning Kamp error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); 489c9671602SPoul-Henning Kamp if (error) 490df8bae1dSRodney W. Grimes return (error); 491df8bae1dSRodney W. Grimes if (VOP_IOCTL(devvp, DIOCGPART, (caddr_t)&dpart, FREAD, NOCRED, p) != 0) 492df8bae1dSRodney W. Grimes size = DEV_BSIZE; 493df8bae1dSRodney W. Grimes else { 494df8bae1dSRodney W. Grimes havepart = 1; 495df8bae1dSRodney W. Grimes size = dpart.disklab->d_secsize; 496df8bae1dSRodney W. Grimes } 497df8bae1dSRodney W. Grimes 498df8bae1dSRodney W. Grimes bp = NULL; 499df8bae1dSRodney W. Grimes ump = NULL; 500c9671602SPoul-Henning Kamp error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp); 501c9671602SPoul-Henning Kamp if (error) 502df8bae1dSRodney W. Grimes goto out; 503df8bae1dSRodney W. Grimes fs = (struct fs *)bp->b_data; 504df8bae1dSRodney W. Grimes if (fs->fs_magic != FS_MAGIC || fs->fs_bsize > MAXBSIZE || 505df8bae1dSRodney W. Grimes fs->fs_bsize < sizeof(struct fs)) { 506df8bae1dSRodney W. Grimes error = EINVAL; /* XXX needs translation */ 507df8bae1dSRodney W. Grimes goto out; 508df8bae1dSRodney W. Grimes } 5091469eec8SDavid Greenman if (!fs->fs_clean) { 5101469eec8SDavid Greenman if (ronly || (mp->mnt_flag & MNT_FORCE)) { 5111469eec8SDavid Greenman printf("WARNING: %s was not properly dismounted.\n",fs->fs_fsmnt); 5121469eec8SDavid Greenman } else { 5131469eec8SDavid Greenman printf("WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck.\n",fs->fs_fsmnt); 5141469eec8SDavid Greenman error = EPERM; 5151469eec8SDavid Greenman goto out; 5161469eec8SDavid Greenman } 5171469eec8SDavid Greenman } 518df8bae1dSRodney W. Grimes ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK); 519df8bae1dSRodney W. Grimes bzero((caddr_t)ump, sizeof *ump); 520df8bae1dSRodney W. Grimes ump->um_fs = malloc((u_long)fs->fs_sbsize, M_UFSMNT, 521df8bae1dSRodney W. Grimes M_WAITOK); 522df8bae1dSRodney W. Grimes bcopy(bp->b_data, ump->um_fs, (u_int)fs->fs_sbsize); 523df8bae1dSRodney W. Grimes if (fs->fs_sbsize < SBSIZE) 524df8bae1dSRodney W. Grimes bp->b_flags |= B_INVAL; 525df8bae1dSRodney W. Grimes brelse(bp); 526df8bae1dSRodney W. Grimes bp = NULL; 527df8bae1dSRodney W. Grimes fs = ump->um_fs; 528df8bae1dSRodney W. Grimes fs->fs_ronly = ronly; 529e0e9c421SDavid Greenman if (ronly == 0) { 530df8bae1dSRodney W. Grimes fs->fs_fmod = 1; 531e0e9c421SDavid Greenman fs->fs_clean = 0; 532e0e9c421SDavid Greenman } 533df8bae1dSRodney W. Grimes blks = howmany(fs->fs_cssize, fs->fs_fsize); 534df8bae1dSRodney W. Grimes base = space = malloc((u_long)fs->fs_cssize, M_UFSMNT, 535df8bae1dSRodney W. Grimes M_WAITOK); 536df8bae1dSRodney W. Grimes for (i = 0; i < blks; i += fs->fs_frag) { 537df8bae1dSRodney W. Grimes size = fs->fs_bsize; 538df8bae1dSRodney W. Grimes if (i + fs->fs_frag > blks) 539df8bae1dSRodney W. Grimes size = (blks - i) * fs->fs_fsize; 540df8bae1dSRodney W. Grimes error = bread(devvp, fsbtodb(fs, fs->fs_csaddr + i), size, 541df8bae1dSRodney W. Grimes NOCRED, &bp); 542df8bae1dSRodney W. Grimes if (error) { 543df8bae1dSRodney W. Grimes free(base, M_UFSMNT); 544df8bae1dSRodney W. Grimes goto out; 545df8bae1dSRodney W. Grimes } 546df8bae1dSRodney W. Grimes bcopy(bp->b_data, space, (u_int)size); 547df8bae1dSRodney W. Grimes fs->fs_csp[fragstoblks(fs, i)] = (struct csum *)space; 548df8bae1dSRodney W. Grimes space += size; 549df8bae1dSRodney W. Grimes brelse(bp); 550df8bae1dSRodney W. Grimes bp = NULL; 551df8bae1dSRodney W. Grimes } 552df8bae1dSRodney W. Grimes mp->mnt_data = (qaddr_t)ump; 553df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[0] = (long)dev; 554df8bae1dSRodney W. Grimes mp->mnt_stat.f_fsid.val[1] = MOUNT_UFS; 555df8bae1dSRodney W. Grimes mp->mnt_maxsymlinklen = fs->fs_maxsymlinklen; 556df8bae1dSRodney W. Grimes mp->mnt_flag |= MNT_LOCAL; 557df8bae1dSRodney W. Grimes ump->um_mountp = mp; 558df8bae1dSRodney W. Grimes ump->um_dev = dev; 559df8bae1dSRodney W. Grimes ump->um_devvp = devvp; 560df8bae1dSRodney W. Grimes ump->um_nindir = fs->fs_nindir; 561df8bae1dSRodney W. Grimes ump->um_bptrtodb = fs->fs_fsbtodb; 562df8bae1dSRodney W. Grimes ump->um_seqinc = fs->fs_frag; 563df8bae1dSRodney W. Grimes for (i = 0; i < MAXQUOTAS; i++) 564df8bae1dSRodney W. Grimes ump->um_quotas[i] = NULLVP; 565df8bae1dSRodney W. Grimes devvp->v_specflags |= SI_MOUNTEDON; 566df8bae1dSRodney W. Grimes ffs_oldfscompat(fs); 5672b14f991SJulian Elischer 5682b14f991SJulian Elischer /* 5692b14f991SJulian Elischer * Set FS local "last mounted on" information (NULL pad) 5702b14f991SJulian Elischer */ 5712b14f991SJulian Elischer copystr( mp->mnt_stat.f_mntonname, /* mount point*/ 5722b14f991SJulian Elischer fs->fs_fsmnt, /* copy area*/ 5732b14f991SJulian Elischer sizeof(fs->fs_fsmnt) - 1, /* max size*/ 5742b14f991SJulian Elischer &strsize); /* real size*/ 5752b14f991SJulian Elischer bzero( fs->fs_fsmnt + strsize, sizeof(fs->fs_fsmnt) - strsize); 5762b14f991SJulian Elischer 5772b14f991SJulian Elischer if( mp->mnt_flag & MNT_ROOTFS) { 5782b14f991SJulian Elischer /* 5792b14f991SJulian Elischer * Root mount; update timestamp in mount structure. 5802b14f991SJulian Elischer * this will be used by the common root mount code 5812b14f991SJulian Elischer * to update the system clock. 5822b14f991SJulian Elischer */ 5832b14f991SJulian Elischer mp->mnt_time = fs->fs_time; 5842b14f991SJulian Elischer } 585e0e9c421SDavid Greenman if (ronly == 0) 586e0e9c421SDavid Greenman ffs_sbupdate(ump, MNT_WAIT); 587847a3ba7SJohn Dyson /* 588847a3ba7SJohn Dyson * Only VMIO the backing device if the backing device is a real 589847a3ba7SJohn Dyson * block device. This excludes the original MFS implementation. 590847a3ba7SJohn Dyson */ 591847a3ba7SJohn Dyson if ((devvp->v_type == VBLK) && (major(devvp->v_rdev) < nblkdev)) { 59291477adcSJohn Dyson vn_vmio_open(devvp, p, p->p_ucred); 593847a3ba7SJohn Dyson } 594df8bae1dSRodney W. Grimes return (0); 595df8bae1dSRodney W. Grimes out: 596df8bae1dSRodney W. Grimes if (bp) 597df8bae1dSRodney W. Grimes brelse(bp); 598df8bae1dSRodney W. Grimes (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, NOCRED, p); 599df8bae1dSRodney W. Grimes if (ump) { 600df8bae1dSRodney W. Grimes free(ump->um_fs, M_UFSMNT); 601df8bae1dSRodney W. Grimes free(ump, M_UFSMNT); 602df8bae1dSRodney W. Grimes mp->mnt_data = (qaddr_t)0; 603df8bae1dSRodney W. Grimes } 604df8bae1dSRodney W. Grimes return (error); 605df8bae1dSRodney W. Grimes } 606df8bae1dSRodney W. Grimes 607df8bae1dSRodney W. Grimes /* 608df8bae1dSRodney W. Grimes * Sanity checks for old file systems. 609df8bae1dSRodney W. Grimes * 610df8bae1dSRodney W. Grimes * XXX - goes away some day. 611df8bae1dSRodney W. Grimes */ 612b8dce649SPoul-Henning Kamp static int 613df8bae1dSRodney W. Grimes ffs_oldfscompat(fs) 614df8bae1dSRodney W. Grimes struct fs *fs; 615df8bae1dSRodney W. Grimes { 616df8bae1dSRodney W. Grimes 617df8bae1dSRodney W. Grimes fs->fs_npsect = max(fs->fs_npsect, fs->fs_nsect); /* XXX */ 618df8bae1dSRodney W. Grimes fs->fs_interleave = max(fs->fs_interleave, 1); /* XXX */ 619df8bae1dSRodney W. Grimes if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 620df8bae1dSRodney W. Grimes fs->fs_nrpos = 8; /* XXX */ 621df8bae1dSRodney W. Grimes if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 622c03020b2SPoul-Henning Kamp #if 0 623c03020b2SPoul-Henning Kamp int i; /* XXX */ 624df8bae1dSRodney W. Grimes quad_t sizepb = fs->fs_bsize; /* XXX */ 625df8bae1dSRodney W. Grimes fs->fs_maxfilesize = fs->fs_bsize * NDADDR - 1; /* XXX */ 626df8bae1dSRodney W. Grimes for (i = 0; i < NIADDR; i++) { /* XXX */ 627df8bae1dSRodney W. Grimes sizepb *= NINDIR(fs); /* XXX */ 628df8bae1dSRodney W. Grimes fs->fs_maxfilesize += sizepb; /* XXX */ 629df8bae1dSRodney W. Grimes } /* XXX */ 630901ba606SDavid Greenman #endif 631a316d390SJohn Dyson fs->fs_maxfilesize = (u_quad_t) 1LL << 39; 632df8bae1dSRodney W. Grimes fs->fs_qbmask = ~fs->fs_bmask; /* XXX */ 633df8bae1dSRodney W. Grimes fs->fs_qfmask = ~fs->fs_fmask; /* XXX */ 634df8bae1dSRodney W. Grimes } /* XXX */ 635df8bae1dSRodney W. Grimes return (0); 636df8bae1dSRodney W. Grimes } 637df8bae1dSRodney W. Grimes 638df8bae1dSRodney W. Grimes /* 639df8bae1dSRodney W. Grimes * unmount system call 640df8bae1dSRodney W. Grimes */ 641df8bae1dSRodney W. Grimes int 642df8bae1dSRodney W. Grimes ffs_unmount(mp, mntflags, p) 643df8bae1dSRodney W. Grimes struct mount *mp; 644df8bae1dSRodney W. Grimes int mntflags; 645df8bae1dSRodney W. Grimes struct proc *p; 646df8bae1dSRodney W. Grimes { 647df8bae1dSRodney W. Grimes register struct ufsmount *ump; 648df8bae1dSRodney W. Grimes register struct fs *fs; 649df8bae1dSRodney W. Grimes int error, flags, ronly; 650df8bae1dSRodney W. Grimes 651df8bae1dSRodney W. Grimes flags = 0; 652df8bae1dSRodney W. Grimes if (mntflags & MNT_FORCE) { 653df8bae1dSRodney W. Grimes flags |= FORCECLOSE; 654df8bae1dSRodney W. Grimes } 655c9671602SPoul-Henning Kamp error = ffs_flushfiles(mp, flags, p); 656c9671602SPoul-Henning Kamp if (error) 657df8bae1dSRodney W. Grimes return (error); 658df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 659df8bae1dSRodney W. Grimes fs = ump->um_fs; 660e0e9c421SDavid Greenman ronly = fs->fs_ronly; 661e0e9c421SDavid Greenman if (!ronly) { 662e0e9c421SDavid Greenman fs->fs_clean = 1; 663e0e9c421SDavid Greenman ffs_sbupdate(ump, MNT_WAIT); 664e0e9c421SDavid Greenman } 665df8bae1dSRodney W. Grimes ump->um_devvp->v_specflags &= ~SI_MOUNTEDON; 666df8bae1dSRodney W. Grimes error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD|FWRITE, 667df8bae1dSRodney W. Grimes NOCRED, p); 668a316d390SJohn Dyson vn_vmio_close(ump->um_devvp); 669df8bae1dSRodney W. Grimes free(fs->fs_csp[0], M_UFSMNT); 670df8bae1dSRodney W. Grimes free(fs, M_UFSMNT); 671df8bae1dSRodney W. Grimes free(ump, M_UFSMNT); 672df8bae1dSRodney W. Grimes mp->mnt_data = (qaddr_t)0; 673df8bae1dSRodney W. Grimes mp->mnt_flag &= ~MNT_LOCAL; 674df8bae1dSRodney W. Grimes return (error); 675df8bae1dSRodney W. Grimes } 676df8bae1dSRodney W. Grimes 677df8bae1dSRodney W. Grimes /* 678df8bae1dSRodney W. Grimes * Flush out all the files in a filesystem. 679df8bae1dSRodney W. Grimes */ 68026f9a767SRodney W. Grimes int 681df8bae1dSRodney W. Grimes ffs_flushfiles(mp, flags, p) 682df8bae1dSRodney W. Grimes register struct mount *mp; 683df8bae1dSRodney W. Grimes int flags; 684df8bae1dSRodney W. Grimes struct proc *p; 685df8bae1dSRodney W. Grimes { 686df8bae1dSRodney W. Grimes register struct ufsmount *ump; 687c9671602SPoul-Henning Kamp int error; 688df8bae1dSRodney W. Grimes 689df8bae1dSRodney W. Grimes if (!doforce) 690df8bae1dSRodney W. Grimes flags &= ~FORCECLOSE; 691df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 692df8bae1dSRodney W. Grimes #ifdef QUOTA 693df8bae1dSRodney W. Grimes if (mp->mnt_flag & MNT_QUOTA) { 694c1d9efcbSPoul-Henning Kamp int i; 695c1d9efcbSPoul-Henning Kamp error = vflush(mp, NULLVP, SKIPSYSTEM|flags); 696c1d9efcbSPoul-Henning Kamp if (error) 697df8bae1dSRodney W. Grimes return (error); 698df8bae1dSRodney W. Grimes for (i = 0; i < MAXQUOTAS; i++) { 699df8bae1dSRodney W. Grimes if (ump->um_quotas[i] == NULLVP) 700df8bae1dSRodney W. Grimes continue; 701df8bae1dSRodney W. Grimes quotaoff(p, mp, i); 702df8bae1dSRodney W. Grimes } 703df8bae1dSRodney W. Grimes /* 704df8bae1dSRodney W. Grimes * Here we fall through to vflush again to ensure 705df8bae1dSRodney W. Grimes * that we have gotten rid of all the system vnodes. 706df8bae1dSRodney W. Grimes */ 707df8bae1dSRodney W. Grimes } 708df8bae1dSRodney W. Grimes #endif 709df8bae1dSRodney W. Grimes error = vflush(mp, NULLVP, flags); 710df8bae1dSRodney W. Grimes return (error); 711df8bae1dSRodney W. Grimes } 712df8bae1dSRodney W. Grimes 713df8bae1dSRodney W. Grimes /* 714df8bae1dSRodney W. Grimes * Get file system statistics. 715df8bae1dSRodney W. Grimes */ 716df8bae1dSRodney W. Grimes int 717df8bae1dSRodney W. Grimes ffs_statfs(mp, sbp, p) 718df8bae1dSRodney W. Grimes struct mount *mp; 719df8bae1dSRodney W. Grimes register struct statfs *sbp; 720df8bae1dSRodney W. Grimes struct proc *p; 721df8bae1dSRodney W. Grimes { 722df8bae1dSRodney W. Grimes register struct ufsmount *ump; 723df8bae1dSRodney W. Grimes register struct fs *fs; 724df8bae1dSRodney W. Grimes 725df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 726df8bae1dSRodney W. Grimes fs = ump->um_fs; 727df8bae1dSRodney W. Grimes if (fs->fs_magic != FS_MAGIC) 728df8bae1dSRodney W. Grimes panic("ffs_statfs"); 729df8bae1dSRodney W. Grimes sbp->f_type = MOUNT_UFS; 730df8bae1dSRodney W. Grimes sbp->f_bsize = fs->fs_fsize; 731df8bae1dSRodney W. Grimes sbp->f_iosize = fs->fs_bsize; 732df8bae1dSRodney W. Grimes sbp->f_blocks = fs->fs_dsize; 733df8bae1dSRodney W. Grimes sbp->f_bfree = fs->fs_cstotal.cs_nbfree * fs->fs_frag + 734df8bae1dSRodney W. Grimes fs->fs_cstotal.cs_nffree; 73551ea8b57SBruce Evans sbp->f_bavail = freespace(fs, fs->fs_minfree); 736df8bae1dSRodney W. Grimes sbp->f_files = fs->fs_ncg * fs->fs_ipg - ROOTINO; 737df8bae1dSRodney W. Grimes sbp->f_ffree = fs->fs_cstotal.cs_nifree; 738df8bae1dSRodney W. Grimes if (sbp != &mp->mnt_stat) { 739df8bae1dSRodney W. Grimes bcopy((caddr_t)mp->mnt_stat.f_mntonname, 740df8bae1dSRodney W. Grimes (caddr_t)&sbp->f_mntonname[0], MNAMELEN); 741df8bae1dSRodney W. Grimes bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 742df8bae1dSRodney W. Grimes (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 743df8bae1dSRodney W. Grimes } 744df8bae1dSRodney W. Grimes return (0); 745df8bae1dSRodney W. Grimes } 746df8bae1dSRodney W. Grimes 747df8bae1dSRodney W. Grimes /* 748df8bae1dSRodney W. Grimes * Go through the disk queues to initiate sandbagged IO; 749df8bae1dSRodney W. Grimes * go through the inodes to write those that have been modified; 750df8bae1dSRodney W. Grimes * initiate the writing of the super block if it has been modified. 751df8bae1dSRodney W. Grimes * 752df8bae1dSRodney W. Grimes * Note: we are always called with the filesystem marked `MPBUSY'. 753df8bae1dSRodney W. Grimes */ 754df8bae1dSRodney W. Grimes int 755df8bae1dSRodney W. Grimes ffs_sync(mp, waitfor, cred, p) 756df8bae1dSRodney W. Grimes struct mount *mp; 757df8bae1dSRodney W. Grimes int waitfor; 758df8bae1dSRodney W. Grimes struct ucred *cred; 759df8bae1dSRodney W. Grimes struct proc *p; 760df8bae1dSRodney W. Grimes { 761a316d390SJohn Dyson register struct vnode *vp, *nvp; 762df8bae1dSRodney W. Grimes register struct inode *ip; 763df8bae1dSRodney W. Grimes register struct ufsmount *ump = VFSTOUFS(mp); 764df8bae1dSRodney W. Grimes register struct fs *fs; 76581c6e3e5SDavid Greenman struct timeval tv; 766df8bae1dSRodney W. Grimes int error, allerror = 0; 767df8bae1dSRodney W. Grimes 768df8bae1dSRodney W. Grimes fs = ump->um_fs; 769df8bae1dSRodney W. Grimes /* 770df8bae1dSRodney W. Grimes * Write back modified superblock. 771df8bae1dSRodney W. Grimes * Consistency check that the superblock 772df8bae1dSRodney W. Grimes * is still in the buffer cache. 773df8bae1dSRodney W. Grimes */ 774df8bae1dSRodney W. Grimes if (fs->fs_fmod != 0) { 775df8bae1dSRodney W. Grimes if (fs->fs_ronly != 0) { /* XXX */ 776df8bae1dSRodney W. Grimes printf("fs = %s\n", fs->fs_fsmnt); 777df8bae1dSRodney W. Grimes panic("update: rofs mod"); 778df8bae1dSRodney W. Grimes } 779df8bae1dSRodney W. Grimes fs->fs_fmod = 0; 780df8bae1dSRodney W. Grimes fs->fs_time = time.tv_sec; 781df8bae1dSRodney W. Grimes allerror = ffs_sbupdate(ump, waitfor); 782df8bae1dSRodney W. Grimes } 783df8bae1dSRodney W. Grimes /* 784df8bae1dSRodney W. Grimes * Write back each (modified) inode. 785df8bae1dSRodney W. Grimes */ 786df8bae1dSRodney W. Grimes loop: 787a316d390SJohn Dyson for (vp = mp->mnt_vnodelist.lh_first; vp != NULL; vp = nvp) { 788df8bae1dSRodney W. Grimes /* 789df8bae1dSRodney W. Grimes * If the vnode that we are about to sync is no longer 790df8bae1dSRodney W. Grimes * associated with this mount point, start over. 791df8bae1dSRodney W. Grimes */ 792df8bae1dSRodney W. Grimes if (vp->v_mount != mp) 793df8bae1dSRodney W. Grimes goto loop; 794a316d390SJohn Dyson nvp = vp->v_mntvnodes.le_next; 795df8bae1dSRodney W. Grimes if (VOP_ISLOCKED(vp)) 796df8bae1dSRodney W. Grimes continue; 797df8bae1dSRodney W. Grimes ip = VTOI(vp); 79881c6e3e5SDavid Greenman if ((((ip->i_flag & 7994e83f749SDavid Greenman (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0)) && 800df8bae1dSRodney W. Grimes vp->v_dirtyblkhd.lh_first == NULL) 801df8bae1dSRodney W. Grimes continue; 80281c6e3e5SDavid Greenman if (vp->v_type != VCHR) { 803df8bae1dSRodney W. Grimes if (vget(vp, 1)) 804df8bae1dSRodney W. Grimes goto loop; 805c9671602SPoul-Henning Kamp error = VOP_FSYNC(vp, cred, waitfor, p); 806c9671602SPoul-Henning Kamp if (error) 807df8bae1dSRodney W. Grimes allerror = error; 808df8bae1dSRodney W. Grimes vput(vp); 80981c6e3e5SDavid Greenman } else { 81081c6e3e5SDavid Greenman tv = time; 811a316d390SJohn Dyson /* VOP_UPDATE(vp, &tv, &tv, waitfor == MNT_WAIT); */ 812a316d390SJohn Dyson VOP_UPDATE(vp, &tv, &tv, 0); 81381c6e3e5SDavid Greenman } 814df8bae1dSRodney W. Grimes } 815df8bae1dSRodney W. Grimes /* 816df8bae1dSRodney W. Grimes * Force stale file system control information to be flushed. 817df8bae1dSRodney W. Grimes */ 818c9671602SPoul-Henning Kamp error = VOP_FSYNC(ump->um_devvp, cred, waitfor, p); 819c9671602SPoul-Henning Kamp if (error) 820df8bae1dSRodney W. Grimes allerror = error; 821df8bae1dSRodney W. Grimes #ifdef QUOTA 822df8bae1dSRodney W. Grimes qsync(mp); 823df8bae1dSRodney W. Grimes #endif 824df8bae1dSRodney W. Grimes return (allerror); 825df8bae1dSRodney W. Grimes } 826df8bae1dSRodney W. Grimes 827df8bae1dSRodney W. Grimes /* 828df8bae1dSRodney W. Grimes * Look up a FFS dinode number to find its incore vnode, otherwise read it 829df8bae1dSRodney W. Grimes * in from disk. If it is in core, wait for the lock bit to clear, then 830df8bae1dSRodney W. Grimes * return the inode locked. Detection and handling of mount points must be 831df8bae1dSRodney W. Grimes * done by the calling routine. 832df8bae1dSRodney W. Grimes */ 833b8dce649SPoul-Henning Kamp static int ffs_inode_hash_lock; 8342094ddb6SDavid Greenman 835df8bae1dSRodney W. Grimes int 836df8bae1dSRodney W. Grimes ffs_vget(mp, ino, vpp) 837df8bae1dSRodney W. Grimes struct mount *mp; 838df8bae1dSRodney W. Grimes ino_t ino; 839df8bae1dSRodney W. Grimes struct vnode **vpp; 840df8bae1dSRodney W. Grimes { 841df8bae1dSRodney W. Grimes register struct fs *fs; 842df8bae1dSRodney W. Grimes register struct inode *ip; 843df8bae1dSRodney W. Grimes struct ufsmount *ump; 844df8bae1dSRodney W. Grimes struct buf *bp; 845df8bae1dSRodney W. Grimes struct vnode *vp; 846df8bae1dSRodney W. Grimes dev_t dev; 847c9671602SPoul-Henning Kamp int type, error; 848df8bae1dSRodney W. Grimes 849df8bae1dSRodney W. Grimes ump = VFSTOUFS(mp); 850df8bae1dSRodney W. Grimes dev = ump->um_dev; 8518997d94fSDavid Greenman restart: 852df8bae1dSRodney W. Grimes if ((*vpp = ufs_ihashget(dev, ino)) != NULL) 853df8bae1dSRodney W. Grimes return (0); 854df8bae1dSRodney W. Grimes 8552094ddb6SDavid Greenman /* 8568997d94fSDavid Greenman * Lock out the creation of new entries in the FFS hash table in 8578997d94fSDavid Greenman * case getnewvnode() or MALLOC() blocks, otherwise a duplicate 8582094ddb6SDavid Greenman * may occur! 8592094ddb6SDavid Greenman */ 8602094ddb6SDavid Greenman if (ffs_inode_hash_lock) { 8612094ddb6SDavid Greenman while (ffs_inode_hash_lock) { 8622094ddb6SDavid Greenman ffs_inode_hash_lock = -1; 8632094ddb6SDavid Greenman tsleep(&ffs_inode_hash_lock, PVM, "ffsvgt", 0); 8642094ddb6SDavid Greenman } 8658997d94fSDavid Greenman goto restart; 8662094ddb6SDavid Greenman } 8672094ddb6SDavid Greenman ffs_inode_hash_lock = 1; 8682094ddb6SDavid Greenman 8692f9bae59SDavid Greenman /* 8702f9bae59SDavid Greenman * If this MALLOC() is performed after the getnewvnode() 8712f9bae59SDavid Greenman * it might block, leaving a vnode with a NULL v_data to be 8722f9bae59SDavid Greenman * found by ffs_sync() if a sync happens to fire right then, 8732f9bae59SDavid Greenman * which will cause a panic because ffs_sync() blindly 8742f9bae59SDavid Greenman * dereferences vp->v_data (as well it should). 8752f9bae59SDavid Greenman */ 8762f9bae59SDavid Greenman type = ump->um_devvp->v_tag == VT_MFS ? M_MFSNODE : M_FFSNODE; /* XXX */ 8772f9bae59SDavid Greenman MALLOC(ip, struct inode *, sizeof(struct inode), type, M_WAITOK); 8782f9bae59SDavid Greenman 879df8bae1dSRodney W. Grimes /* Allocate a new vnode/inode. */ 880c9671602SPoul-Henning Kamp error = getnewvnode(VT_UFS, mp, ffs_vnodeop_p, &vp); 881c9671602SPoul-Henning Kamp if (error) { 8828997d94fSDavid Greenman if (ffs_inode_hash_lock < 0) 8832094ddb6SDavid Greenman wakeup(&ffs_inode_hash_lock); 8842094ddb6SDavid Greenman ffs_inode_hash_lock = 0; 885df8bae1dSRodney W. Grimes *vpp = NULL; 8862f9bae59SDavid Greenman FREE(ip, type); 887df8bae1dSRodney W. Grimes return (error); 888df8bae1dSRodney W. Grimes } 889df8bae1dSRodney W. Grimes bzero((caddr_t)ip, sizeof(struct inode)); 890df8bae1dSRodney W. Grimes vp->v_data = ip; 891df8bae1dSRodney W. Grimes ip->i_vnode = vp; 892df8bae1dSRodney W. Grimes ip->i_fs = fs = ump->um_fs; 893df8bae1dSRodney W. Grimes ip->i_dev = dev; 894df8bae1dSRodney W. Grimes ip->i_number = ino; 895df8bae1dSRodney W. Grimes #ifdef QUOTA 896c1d9efcbSPoul-Henning Kamp { 897c1d9efcbSPoul-Henning Kamp int i; 898df8bae1dSRodney W. Grimes for (i = 0; i < MAXQUOTAS; i++) 899df8bae1dSRodney W. Grimes ip->i_dquot[i] = NODQUOT; 900c1d9efcbSPoul-Henning Kamp } 901df8bae1dSRodney W. Grimes #endif 902df8bae1dSRodney W. Grimes /* 903df8bae1dSRodney W. Grimes * Put it onto its hash chain and lock it so that other requests for 904df8bae1dSRodney W. Grimes * this inode will block if they arrive while we are sleeping waiting 905df8bae1dSRodney W. Grimes * for old data structures to be purged or for the contents of the 906df8bae1dSRodney W. Grimes * disk portion of this inode to be read. 907df8bae1dSRodney W. Grimes */ 908df8bae1dSRodney W. Grimes ufs_ihashins(ip); 909df8bae1dSRodney W. Grimes 9108997d94fSDavid Greenman if (ffs_inode_hash_lock < 0) 9112094ddb6SDavid Greenman wakeup(&ffs_inode_hash_lock); 9122094ddb6SDavid Greenman ffs_inode_hash_lock = 0; 9132094ddb6SDavid Greenman 914df8bae1dSRodney W. Grimes /* Read in the disk contents for the inode, copy into the inode. */ 915c9671602SPoul-Henning Kamp error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 916c9671602SPoul-Henning Kamp (int)fs->fs_bsize, NOCRED, &bp); 917c9671602SPoul-Henning Kamp if (error) { 918df8bae1dSRodney W. Grimes /* 919df8bae1dSRodney W. Grimes * The inode does not contain anything useful, so it would 920df8bae1dSRodney W. Grimes * be misleading to leave it on its hash chain. With mode 921df8bae1dSRodney W. Grimes * still zero, it will be unlinked and returned to the free 922df8bae1dSRodney W. Grimes * list by vput(). 923df8bae1dSRodney W. Grimes */ 924df8bae1dSRodney W. Grimes brelse(bp); 925bd7e5f99SJohn Dyson vput(vp); 926df8bae1dSRodney W. Grimes *vpp = NULL; 927df8bae1dSRodney W. Grimes return (error); 928df8bae1dSRodney W. Grimes } 929df8bae1dSRodney W. Grimes ip->i_din = *((struct dinode *)bp->b_data + ino_to_fsbo(fs, ino)); 930bd7e5f99SJohn Dyson bqrelse(bp); 931df8bae1dSRodney W. Grimes 932df8bae1dSRodney W. Grimes /* 933df8bae1dSRodney W. Grimes * Initialize the vnode from the inode, check for aliases. 934df8bae1dSRodney W. Grimes * Note that the underlying vnode may have changed. 935df8bae1dSRodney W. Grimes */ 936e6302eabSBruce Evans error = ufs_vinit(mp, ffs_specop_p, ffs_fifoop_p, &vp); 937c9671602SPoul-Henning Kamp if (error) { 938df8bae1dSRodney W. Grimes vput(vp); 939df8bae1dSRodney W. Grimes *vpp = NULL; 940df8bae1dSRodney W. Grimes return (error); 941df8bae1dSRodney W. Grimes } 942df8bae1dSRodney W. Grimes /* 943df8bae1dSRodney W. Grimes * Finish inode initialization now that aliasing has been resolved. 944df8bae1dSRodney W. Grimes */ 945df8bae1dSRodney W. Grimes ip->i_devvp = ump->um_devvp; 946df8bae1dSRodney W. Grimes VREF(ip->i_devvp); 947df8bae1dSRodney W. Grimes /* 948df8bae1dSRodney W. Grimes * Set up a generation number for this inode if it does not 949df8bae1dSRodney W. Grimes * already have one. This should only happen on old filesystems. 950df8bae1dSRodney W. Grimes */ 951df8bae1dSRodney W. Grimes if (ip->i_gen == 0) { 952df8bae1dSRodney W. Grimes if (++nextgennumber < (u_long)time.tv_sec) 953df8bae1dSRodney W. Grimes nextgennumber = time.tv_sec; 954df8bae1dSRodney W. Grimes ip->i_gen = nextgennumber; 955df8bae1dSRodney W. Grimes if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 956df8bae1dSRodney W. Grimes ip->i_flag |= IN_MODIFIED; 957df8bae1dSRodney W. Grimes } 958df8bae1dSRodney W. Grimes /* 959df8bae1dSRodney W. Grimes * Ensure that uid and gid are correct. This is a temporary 960df8bae1dSRodney W. Grimes * fix until fsck has been changed to do the update. 961df8bae1dSRodney W. Grimes */ 962df8bae1dSRodney W. Grimes if (fs->fs_inodefmt < FS_44INODEFMT) { /* XXX */ 963df8bae1dSRodney W. Grimes ip->i_uid = ip->i_din.di_ouid; /* XXX */ 964df8bae1dSRodney W. Grimes ip->i_gid = ip->i_din.di_ogid; /* XXX */ 965df8bae1dSRodney W. Grimes } /* XXX */ 966df8bae1dSRodney W. Grimes 967df8bae1dSRodney W. Grimes *vpp = vp; 968df8bae1dSRodney W. Grimes return (0); 969df8bae1dSRodney W. Grimes } 970df8bae1dSRodney W. Grimes 971df8bae1dSRodney W. Grimes /* 972df8bae1dSRodney W. Grimes * File handle to vnode 973df8bae1dSRodney W. Grimes * 974df8bae1dSRodney W. Grimes * Have to be really careful about stale file handles: 975df8bae1dSRodney W. Grimes * - check that the inode number is valid 976df8bae1dSRodney W. Grimes * - call ffs_vget() to get the locked inode 977df8bae1dSRodney W. Grimes * - check for an unallocated inode (i_mode == 0) 978df8bae1dSRodney W. Grimes * - check that the given client host has export rights and return 979df8bae1dSRodney W. Grimes * those rights via. exflagsp and credanonp 980df8bae1dSRodney W. Grimes */ 981df8bae1dSRodney W. Grimes int 982df8bae1dSRodney W. Grimes ffs_fhtovp(mp, fhp, nam, vpp, exflagsp, credanonp) 983df8bae1dSRodney W. Grimes register struct mount *mp; 984df8bae1dSRodney W. Grimes struct fid *fhp; 985df8bae1dSRodney W. Grimes struct mbuf *nam; 986df8bae1dSRodney W. Grimes struct vnode **vpp; 987df8bae1dSRodney W. Grimes int *exflagsp; 988df8bae1dSRodney W. Grimes struct ucred **credanonp; 989df8bae1dSRodney W. Grimes { 990df8bae1dSRodney W. Grimes register struct ufid *ufhp; 991df8bae1dSRodney W. Grimes struct fs *fs; 992df8bae1dSRodney W. Grimes 993df8bae1dSRodney W. Grimes ufhp = (struct ufid *)fhp; 994df8bae1dSRodney W. Grimes fs = VFSTOUFS(mp)->um_fs; 995df8bae1dSRodney W. Grimes if (ufhp->ufid_ino < ROOTINO || 996df8bae1dSRodney W. Grimes ufhp->ufid_ino >= fs->fs_ncg * fs->fs_ipg) 997df8bae1dSRodney W. Grimes return (ESTALE); 998df8bae1dSRodney W. Grimes return (ufs_check_export(mp, ufhp, nam, vpp, exflagsp, credanonp)); 999df8bae1dSRodney W. Grimes } 1000df8bae1dSRodney W. Grimes 1001df8bae1dSRodney W. Grimes /* 1002df8bae1dSRodney W. Grimes * Vnode pointer to File handle 1003df8bae1dSRodney W. Grimes */ 1004df8bae1dSRodney W. Grimes /* ARGSUSED */ 100526f9a767SRodney W. Grimes int 1006df8bae1dSRodney W. Grimes ffs_vptofh(vp, fhp) 1007df8bae1dSRodney W. Grimes struct vnode *vp; 1008df8bae1dSRodney W. Grimes struct fid *fhp; 1009df8bae1dSRodney W. Grimes { 1010df8bae1dSRodney W. Grimes register struct inode *ip; 1011df8bae1dSRodney W. Grimes register struct ufid *ufhp; 1012df8bae1dSRodney W. Grimes 1013df8bae1dSRodney W. Grimes ip = VTOI(vp); 1014df8bae1dSRodney W. Grimes ufhp = (struct ufid *)fhp; 1015df8bae1dSRodney W. Grimes ufhp->ufid_len = sizeof(struct ufid); 1016df8bae1dSRodney W. Grimes ufhp->ufid_ino = ip->i_number; 1017df8bae1dSRodney W. Grimes ufhp->ufid_gen = ip->i_gen; 1018df8bae1dSRodney W. Grimes return (0); 1019df8bae1dSRodney W. Grimes } 1020df8bae1dSRodney W. Grimes 1021df8bae1dSRodney W. Grimes /* 1022df8bae1dSRodney W. Grimes * Write a superblock and associated information back to disk. 1023df8bae1dSRodney W. Grimes */ 1024b8dce649SPoul-Henning Kamp static int 1025df8bae1dSRodney W. Grimes ffs_sbupdate(mp, waitfor) 1026df8bae1dSRodney W. Grimes struct ufsmount *mp; 1027df8bae1dSRodney W. Grimes int waitfor; 1028df8bae1dSRodney W. Grimes { 1029df8bae1dSRodney W. Grimes register struct fs *fs = mp->um_fs; 1030df8bae1dSRodney W. Grimes register struct buf *bp; 1031df8bae1dSRodney W. Grimes int blks; 1032df8bae1dSRodney W. Grimes caddr_t space; 1033df8bae1dSRodney W. Grimes int i, size, error = 0; 1034df8bae1dSRodney W. Grimes 1035df8bae1dSRodney W. Grimes bp = getblk(mp->um_devvp, SBLOCK, (int)fs->fs_sbsize, 0, 0); 1036df8bae1dSRodney W. Grimes bcopy((caddr_t)fs, bp->b_data, (u_int)fs->fs_sbsize); 1037df8bae1dSRodney W. Grimes /* Restore compatibility to old file systems. XXX */ 1038df8bae1dSRodney W. Grimes if (fs->fs_postblformat == FS_42POSTBLFMT) /* XXX */ 1039df8bae1dSRodney W. Grimes ((struct fs *)bp->b_data)->fs_nrpos = -1; /* XXX */ 1040df8bae1dSRodney W. Grimes if (waitfor == MNT_WAIT) 1041df8bae1dSRodney W. Grimes error = bwrite(bp); 1042df8bae1dSRodney W. Grimes else 1043df8bae1dSRodney W. Grimes bawrite(bp); 1044df8bae1dSRodney W. Grimes blks = howmany(fs->fs_cssize, fs->fs_fsize); 1045df8bae1dSRodney W. Grimes space = (caddr_t)fs->fs_csp[0]; 1046df8bae1dSRodney W. Grimes for (i = 0; i < blks; i += fs->fs_frag) { 1047df8bae1dSRodney W. Grimes size = fs->fs_bsize; 1048df8bae1dSRodney W. Grimes if (i + fs->fs_frag > blks) 1049df8bae1dSRodney W. Grimes size = (blks - i) * fs->fs_fsize; 1050df8bae1dSRodney W. Grimes bp = getblk(mp->um_devvp, fsbtodb(fs, fs->fs_csaddr + i), 1051df8bae1dSRodney W. Grimes size, 0, 0); 1052df8bae1dSRodney W. Grimes bcopy(space, bp->b_data, (u_int)size); 1053df8bae1dSRodney W. Grimes space += size; 1054df8bae1dSRodney W. Grimes if (waitfor == MNT_WAIT) 1055df8bae1dSRodney W. Grimes error = bwrite(bp); 1056df8bae1dSRodney W. Grimes else 1057df8bae1dSRodney W. Grimes bawrite(bp); 1058df8bae1dSRodney W. Grimes } 1059df8bae1dSRodney W. Grimes return (error); 1060df8bae1dSRodney W. Grimes } 1061