1*cfe60390STomohiro Kusumi /*- 2*cfe60390STomohiro Kusumi * modified for EXT2FS support in Lites 1.1 3*cfe60390STomohiro Kusumi * 4*cfe60390STomohiro Kusumi * Aug 1995, Godmar Back (gback@cs.utah.edu) 5*cfe60390STomohiro Kusumi * University of Utah, Department of Computer Science 6*cfe60390STomohiro Kusumi */ 7*cfe60390STomohiro Kusumi /*- 8*cfe60390STomohiro Kusumi * SPDX-License-Identifier: BSD-3-Clause 9*cfe60390STomohiro Kusumi * 10*cfe60390STomohiro Kusumi * Copyright (c) 1989, 1991, 1993, 1994 11*cfe60390STomohiro Kusumi * The Regents of the University of California. All rights reserved. 12*cfe60390STomohiro Kusumi * 13*cfe60390STomohiro Kusumi * Redistribution and use in source and binary forms, with or without 14*cfe60390STomohiro Kusumi * modification, are permitted provided that the following conditions 15*cfe60390STomohiro Kusumi * are met: 16*cfe60390STomohiro Kusumi * 1. Redistributions of source code must retain the above copyright 17*cfe60390STomohiro Kusumi * notice, this list of conditions and the following disclaimer. 18*cfe60390STomohiro Kusumi * 2. Redistributions in binary form must reproduce the above copyright 19*cfe60390STomohiro Kusumi * notice, this list of conditions and the following disclaimer in the 20*cfe60390STomohiro Kusumi * documentation and/or other materials provided with the distribution. 21*cfe60390STomohiro Kusumi * 3. Neither the name of the University nor the names of its contributors 22*cfe60390STomohiro Kusumi * may be used to endorse or promote products derived from this software 23*cfe60390STomohiro Kusumi * without specific prior written permission. 24*cfe60390STomohiro Kusumi * 25*cfe60390STomohiro Kusumi * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26*cfe60390STomohiro Kusumi * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27*cfe60390STomohiro Kusumi * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28*cfe60390STomohiro Kusumi * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29*cfe60390STomohiro Kusumi * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30*cfe60390STomohiro Kusumi * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31*cfe60390STomohiro Kusumi * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32*cfe60390STomohiro Kusumi * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33*cfe60390STomohiro Kusumi * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34*cfe60390STomohiro Kusumi * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35*cfe60390STomohiro Kusumi * SUCH DAMAGE. 36*cfe60390STomohiro Kusumi * 37*cfe60390STomohiro Kusumi * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94 38*cfe60390STomohiro Kusumi * $FreeBSD$ 39*cfe60390STomohiro Kusumi */ 40*cfe60390STomohiro Kusumi 41*cfe60390STomohiro Kusumi #include <sys/param.h> 42*cfe60390STomohiro Kusumi #include <sys/systm.h> 43*cfe60390STomohiro Kusumi #include <sys/namei.h> 44*cfe60390STomohiro Kusumi #include <sys/priv.h> 45*cfe60390STomohiro Kusumi #include <sys/proc.h> 46*cfe60390STomohiro Kusumi #include <sys/kernel.h> 47*cfe60390STomohiro Kusumi #include <sys/vnode.h> 48*cfe60390STomohiro Kusumi #include <sys/mount.h> 49*cfe60390STomohiro Kusumi #include <sys/bio.h> 50*cfe60390STomohiro Kusumi #include <sys/buf2.h> 51*cfe60390STomohiro Kusumi #include <sys/conf.h> 52*cfe60390STomohiro Kusumi #include <sys/endian.h> 53*cfe60390STomohiro Kusumi #include <sys/fcntl.h> 54*cfe60390STomohiro Kusumi #include <sys/malloc.h> 55*cfe60390STomohiro Kusumi #include <sys/stat.h> 56*cfe60390STomohiro Kusumi #include <sys/mutex2.h> 57*cfe60390STomohiro Kusumi #include <sys/nlookup.h> 58*cfe60390STomohiro Kusumi 59*cfe60390STomohiro Kusumi #include <vfs/ext2fs/fs.h> 60*cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_mount.h> 61*cfe60390STomohiro Kusumi #include <vfs/ext2fs/inode.h> 62*cfe60390STomohiro Kusumi 63*cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2fs.h> 64*cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_dinode.h> 65*cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_extern.h> 66*cfe60390STomohiro Kusumi #include <vfs/ext2fs/ext2_extents.h> 67*cfe60390STomohiro Kusumi 68*cfe60390STomohiro Kusumi SDT_PROVIDER_DECLARE(ext2fs); 69*cfe60390STomohiro Kusumi /* 70*cfe60390STomohiro Kusumi * ext2fs trace probe: 71*cfe60390STomohiro Kusumi * arg0: verbosity. Higher numbers give more verbose messages 72*cfe60390STomohiro Kusumi * arg1: Textual message 73*cfe60390STomohiro Kusumi */ 74*cfe60390STomohiro Kusumi SDT_PROBE_DEFINE2(ext2fs, , vfsops, trace, "int", "char*"); 75*cfe60390STomohiro Kusumi SDT_PROBE_DEFINE2(ext2fs, , vfsops, ext2_cg_validate_error, "char*", "int"); 76*cfe60390STomohiro Kusumi SDT_PROBE_DEFINE1(ext2fs, , vfsops, ext2_compute_sb_data_error, "char*"); 77*cfe60390STomohiro Kusumi 78*cfe60390STomohiro Kusumi 79*cfe60390STomohiro Kusumi static int ext2_flushfiles(struct mount *mp, int flags); 80*cfe60390STomohiro Kusumi static int ext2_mountfs(struct vnode *, struct mount *); 81*cfe60390STomohiro Kusumi static int ext2_reload(struct mount *mp); 82*cfe60390STomohiro Kusumi static int ext2_sbupdate(struct ext2mount *, int); 83*cfe60390STomohiro Kusumi static int ext2_cgupdate(struct ext2mount *, int); 84*cfe60390STomohiro Kusumi static int ext2_init(struct vfsconf *); 85*cfe60390STomohiro Kusumi static int ext2_uninit(struct vfsconf *); 86*cfe60390STomohiro Kusumi static vfs_unmount_t ext2_unmount; 87*cfe60390STomohiro Kusumi static vfs_root_t ext2_root; 88*cfe60390STomohiro Kusumi static vfs_statfs_t ext2_statfs; 89*cfe60390STomohiro Kusumi static vfs_statvfs_t ext2_statvfs; 90*cfe60390STomohiro Kusumi static vfs_sync_t ext2_sync; 91*cfe60390STomohiro Kusumi static vfs_vget_t ext2_vget; 92*cfe60390STomohiro Kusumi static vfs_fhtovp_t ext2_fhtovp; 93*cfe60390STomohiro Kusumi static vfs_vptofh_t ext2_vptofh; 94*cfe60390STomohiro Kusumi static vfs_checkexp_t ext2_check_export; 95*cfe60390STomohiro Kusumi static vfs_mount_t ext2_mount; 96*cfe60390STomohiro Kusumi 97*cfe60390STomohiro Kusumi MALLOC_DEFINE(M_EXT2NODE, "ext2_node", "EXT2 vnode private part"); 98*cfe60390STomohiro Kusumi static MALLOC_DEFINE(M_EXT2MNT, "ext2_mount", "EXT2 mount structure"); 99*cfe60390STomohiro Kusumi 100*cfe60390STomohiro Kusumi static struct vfsops ext2fs_vfsops = { 101*cfe60390STomohiro Kusumi .vfs_flags = 0, 102*cfe60390STomohiro Kusumi .vfs_mount = ext2_mount, 103*cfe60390STomohiro Kusumi .vfs_unmount = ext2_unmount, 104*cfe60390STomohiro Kusumi .vfs_root = ext2_root, /* root inode via vget */ 105*cfe60390STomohiro Kusumi .vfs_statfs = ext2_statfs, 106*cfe60390STomohiro Kusumi .vfs_statvfs = ext2_statvfs, 107*cfe60390STomohiro Kusumi .vfs_sync = ext2_sync, 108*cfe60390STomohiro Kusumi .vfs_vget = ext2_vget, 109*cfe60390STomohiro Kusumi .vfs_fhtovp = ext2_fhtovp, 110*cfe60390STomohiro Kusumi .vfs_vptofh = ext2_vptofh, 111*cfe60390STomohiro Kusumi .vfs_checkexp = ext2_check_export, 112*cfe60390STomohiro Kusumi .vfs_init = ext2_init, 113*cfe60390STomohiro Kusumi .vfs_uninit = ext2_uninit 114*cfe60390STomohiro Kusumi }; 115*cfe60390STomohiro Kusumi 116*cfe60390STomohiro Kusumi VFS_SET(ext2fs_vfsops, ext2fs, 0); 117*cfe60390STomohiro Kusumi MODULE_VERSION(ext2fs, 1); 118*cfe60390STomohiro Kusumi 119*cfe60390STomohiro Kusumi static int ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, 120*cfe60390STomohiro Kusumi int ronly); 121*cfe60390STomohiro Kusumi static int ext2_compute_sb_data(struct vnode * devvp, 122*cfe60390STomohiro Kusumi struct ext2fs * es, struct m_ext2fs * fs); 123*cfe60390STomohiro Kusumi 124*cfe60390STomohiro Kusumi int ext2fs_inode_hash_lock; 125*cfe60390STomohiro Kusumi 126*cfe60390STomohiro Kusumi /* 127*cfe60390STomohiro Kusumi * VFS Operations. 128*cfe60390STomohiro Kusumi * 129*cfe60390STomohiro Kusumi * mount system call 130*cfe60390STomohiro Kusumi */ 131*cfe60390STomohiro Kusumi static int 132*cfe60390STomohiro Kusumi ext2_mount(struct mount *mp, char *path, caddr_t data, struct ucred *cred) 133*cfe60390STomohiro Kusumi { 134*cfe60390STomohiro Kusumi struct ext2_args args; 135*cfe60390STomohiro Kusumi struct vnode *devvp; 136*cfe60390STomohiro Kusumi struct ext2mount *ump = NULL; 137*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 138*cfe60390STomohiro Kusumi struct nlookupdata nd; 139*cfe60390STomohiro Kusumi mode_t accmode; 140*cfe60390STomohiro Kusumi int error, flags; 141*cfe60390STomohiro Kusumi size_t size; 142*cfe60390STomohiro Kusumi 143*cfe60390STomohiro Kusumi if ((error = copyin(data, (caddr_t)&args, sizeof (struct ext2_args))) != 0) 144*cfe60390STomohiro Kusumi return (error); 145*cfe60390STomohiro Kusumi 146*cfe60390STomohiro Kusumi /* 147*cfe60390STomohiro Kusumi * If updating, check whether changing from read-only to 148*cfe60390STomohiro Kusumi * read/write; if there is no device name, that's all we do. 149*cfe60390STomohiro Kusumi */ 150*cfe60390STomohiro Kusumi if (mp->mnt_flag & MNT_UPDATE) { 151*cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 152*cfe60390STomohiro Kusumi fs = ump->um_e2fs; 153*cfe60390STomohiro Kusumi devvp = ump->um_devvp; 154*cfe60390STomohiro Kusumi error = 0; 155*cfe60390STomohiro Kusumi if (fs->e2fs_ronly == 0 && (mp->mnt_flag & MNT_RDONLY)) { 156*cfe60390STomohiro Kusumi error = VFS_SYNC(mp, MNT_WAIT); 157*cfe60390STomohiro Kusumi if (error) 158*cfe60390STomohiro Kusumi return (error); 159*cfe60390STomohiro Kusumi flags = WRITECLOSE; 160*cfe60390STomohiro Kusumi if (mp->mnt_flag & MNT_FORCE) 161*cfe60390STomohiro Kusumi flags |= FORCECLOSE; 162*cfe60390STomohiro Kusumi if (vfs_busy(mp, LK_NOWAIT)) 163*cfe60390STomohiro Kusumi return (EBUSY); 164*cfe60390STomohiro Kusumi error = ext2_flushfiles(mp, flags); 165*cfe60390STomohiro Kusumi vfs_unbusy(mp); 166*cfe60390STomohiro Kusumi if (error == 0 && fs->e2fs_wasvalid && 167*cfe60390STomohiro Kusumi ext2_cgupdate(ump, MNT_WAIT) == 0) { 168*cfe60390STomohiro Kusumi fs->e2fs->e2fs_state = 169*cfe60390STomohiro Kusumi htole16((le16toh(fs->e2fs->e2fs_state) | 170*cfe60390STomohiro Kusumi E2FS_ISCLEAN)); 171*cfe60390STomohiro Kusumi ext2_sbupdate(ump, MNT_WAIT); 172*cfe60390STomohiro Kusumi } 173*cfe60390STomohiro Kusumi fs->e2fs_ronly = 1; 174*cfe60390STomohiro Kusumi vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 175*cfe60390STomohiro Kusumi VOP_OPEN(devvp, FREAD, FSCRED, NULL); 176*cfe60390STomohiro Kusumi VOP_CLOSE(devvp, FREAD | FWRITE, NULL); 177*cfe60390STomohiro Kusumi vn_unlock(devvp); 178*cfe60390STomohiro Kusumi } 179*cfe60390STomohiro Kusumi if (!error && (mp->mnt_flag & MNT_RELOAD)) 180*cfe60390STomohiro Kusumi error = ext2_reload(mp); 181*cfe60390STomohiro Kusumi if (error) 182*cfe60390STomohiro Kusumi return (error); 183*cfe60390STomohiro Kusumi devvp = ump->um_devvp; 184*cfe60390STomohiro Kusumi if (fs->e2fs_ronly && (mp->mnt_kern_flag & MNTK_WANTRDWR)) { 185*cfe60390STomohiro Kusumi if (ext2_check_sb_compat(fs->e2fs, devvp->v_rdev, 0)) 186*cfe60390STomohiro Kusumi return (EPERM); 187*cfe60390STomohiro Kusumi 188*cfe60390STomohiro Kusumi /* 189*cfe60390STomohiro Kusumi * If upgrade to read-write by non-root, then verify 190*cfe60390STomohiro Kusumi * that user has necessary permissions on the device. 191*cfe60390STomohiro Kusumi */ 192*cfe60390STomohiro Kusumi if (cred->cr_uid != 0) { 193*cfe60390STomohiro Kusumi vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 194*cfe60390STomohiro Kusumi error = VOP_EACCESS(devvp, VREAD | VWRITE, cred); 195*cfe60390STomohiro Kusumi if (error) { 196*cfe60390STomohiro Kusumi vn_unlock(devvp); 197*cfe60390STomohiro Kusumi return (error); 198*cfe60390STomohiro Kusumi } 199*cfe60390STomohiro Kusumi vn_unlock(devvp); 200*cfe60390STomohiro Kusumi } 201*cfe60390STomohiro Kusumi 202*cfe60390STomohiro Kusumi if ((le16toh(fs->e2fs->e2fs_state) & E2FS_ISCLEAN) == 0 || 203*cfe60390STomohiro Kusumi (le16toh(fs->e2fs->e2fs_state) & E2FS_ERRORS)) { 204*cfe60390STomohiro Kusumi if (mp->mnt_flag & MNT_FORCE) { 205*cfe60390STomohiro Kusumi printf( 206*cfe60390STomohiro Kusumi "WARNING: %s was not properly dismounted\n", fs->e2fs_fsmnt); 207*cfe60390STomohiro Kusumi } else { 208*cfe60390STomohiro Kusumi printf( 209*cfe60390STomohiro Kusumi "WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", 210*cfe60390STomohiro Kusumi fs->e2fs_fsmnt); 211*cfe60390STomohiro Kusumi return (EPERM); 212*cfe60390STomohiro Kusumi } 213*cfe60390STomohiro Kusumi } 214*cfe60390STomohiro Kusumi fs->e2fs->e2fs_state = 215*cfe60390STomohiro Kusumi htole16(le16toh(fs->e2fs->e2fs_state) & ~E2FS_ISCLEAN); 216*cfe60390STomohiro Kusumi (void)ext2_cgupdate(ump, MNT_WAIT); 217*cfe60390STomohiro Kusumi fs->e2fs_ronly = 0; 218*cfe60390STomohiro Kusumi mp->mnt_flag &= ~MNT_RDONLY; 219*cfe60390STomohiro Kusumi 220*cfe60390STomohiro Kusumi vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 221*cfe60390STomohiro Kusumi VOP_OPEN(devvp, FREAD | FWRITE, FSCRED, NULL); 222*cfe60390STomohiro Kusumi VOP_CLOSE(devvp, FREAD, NULL); 223*cfe60390STomohiro Kusumi vn_unlock(devvp); 224*cfe60390STomohiro Kusumi } 225*cfe60390STomohiro Kusumi if (args.fspec == NULL) { 226*cfe60390STomohiro Kusumi /* 227*cfe60390STomohiro Kusumi * Process export requests. 228*cfe60390STomohiro Kusumi */ 229*cfe60390STomohiro Kusumi return (vfs_export(mp, &ump->um_export, &args.export)); 230*cfe60390STomohiro Kusumi } 231*cfe60390STomohiro Kusumi } 232*cfe60390STomohiro Kusumi 233*cfe60390STomohiro Kusumi /* 234*cfe60390STomohiro Kusumi * Not an update, or updating the name: look up the name 235*cfe60390STomohiro Kusumi * and verify that it refers to a sensible disk device. 236*cfe60390STomohiro Kusumi */ 237*cfe60390STomohiro Kusumi devvp = NULL; 238*cfe60390STomohiro Kusumi error = nlookup_init(&nd, args.fspec, UIO_USERSPACE, NLC_FOLLOW); 239*cfe60390STomohiro Kusumi if (error == 0) 240*cfe60390STomohiro Kusumi error = nlookup(&nd); 241*cfe60390STomohiro Kusumi if (error == 0) 242*cfe60390STomohiro Kusumi error = cache_vref(&nd.nl_nch, nd.nl_cred, &devvp); 243*cfe60390STomohiro Kusumi nlookup_done(&nd); 244*cfe60390STomohiro Kusumi if (error) 245*cfe60390STomohiro Kusumi return (error); 246*cfe60390STomohiro Kusumi 247*cfe60390STomohiro Kusumi if (!vn_isdisk(devvp, &error)) { 248*cfe60390STomohiro Kusumi vrele(devvp); 249*cfe60390STomohiro Kusumi return (error); 250*cfe60390STomohiro Kusumi } 251*cfe60390STomohiro Kusumi 252*cfe60390STomohiro Kusumi /* 253*cfe60390STomohiro Kusumi * If mount by non-root, then verify that user has necessary 254*cfe60390STomohiro Kusumi * permissions on the device. 255*cfe60390STomohiro Kusumi * 256*cfe60390STomohiro Kusumi * XXXRW: VOP_ACCESS() enough? 257*cfe60390STomohiro Kusumi */ 258*cfe60390STomohiro Kusumi if (cred->cr_uid != 0) { 259*cfe60390STomohiro Kusumi accmode = VREAD; 260*cfe60390STomohiro Kusumi if ((mp->mnt_flag & MNT_RDONLY) == 0) 261*cfe60390STomohiro Kusumi accmode |= VWRITE; 262*cfe60390STomohiro Kusumi vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 263*cfe60390STomohiro Kusumi if ((error = VOP_EACCESS(devvp, accmode, cred)) != 0) { 264*cfe60390STomohiro Kusumi vput(devvp); 265*cfe60390STomohiro Kusumi return (error); 266*cfe60390STomohiro Kusumi } 267*cfe60390STomohiro Kusumi vn_unlock(devvp); 268*cfe60390STomohiro Kusumi } 269*cfe60390STomohiro Kusumi 270*cfe60390STomohiro Kusumi if ((mp->mnt_flag & MNT_UPDATE) == 0) { 271*cfe60390STomohiro Kusumi error = ext2_mountfs(devvp, mp); 272*cfe60390STomohiro Kusumi } else { 273*cfe60390STomohiro Kusumi if (devvp != ump->um_devvp) 274*cfe60390STomohiro Kusumi error = EINVAL; /* needs translation */ 275*cfe60390STomohiro Kusumi else 276*cfe60390STomohiro Kusumi vrele(devvp); 277*cfe60390STomohiro Kusumi } 278*cfe60390STomohiro Kusumi if (error) { 279*cfe60390STomohiro Kusumi vrele(devvp); 280*cfe60390STomohiro Kusumi return (error); 281*cfe60390STomohiro Kusumi } 282*cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 283*cfe60390STomohiro Kusumi fs = ump->um_e2fs; 284*cfe60390STomohiro Kusumi 285*cfe60390STomohiro Kusumi /* 286*cfe60390STomohiro Kusumi * Note that this strncpy() is ok because of a check at the start 287*cfe60390STomohiro Kusumi * of ext2_mount(). 288*cfe60390STomohiro Kusumi */ 289*cfe60390STomohiro Kusumi copyinstr(path, fs->e2fs_fsmnt, sizeof(fs->e2fs_fsmnt) - 1, &size); 290*cfe60390STomohiro Kusumi bzero(fs->e2fs_fsmnt + size, sizeof(fs->e2fs_fsmnt) - size); 291*cfe60390STomohiro Kusumi copyinstr(args.fspec, mp->mnt_stat.f_mntfromname, MNAMELEN - 1, &size); 292*cfe60390STomohiro Kusumi bzero(mp->mnt_stat.f_mntfromname + size, MNAMELEN - size); 293*cfe60390STomohiro Kusumi ext2_statfs(mp, &mp->mnt_stat, cred); 294*cfe60390STomohiro Kusumi return (0); 295*cfe60390STomohiro Kusumi } 296*cfe60390STomohiro Kusumi 297*cfe60390STomohiro Kusumi static int 298*cfe60390STomohiro Kusumi ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, int ronly) 299*cfe60390STomohiro Kusumi { 300*cfe60390STomohiro Kusumi uint32_t i, mask; 301*cfe60390STomohiro Kusumi 302*cfe60390STomohiro Kusumi if (le16toh(es->e2fs_magic) != E2FS_MAGIC) { 303*cfe60390STomohiro Kusumi printf("ext2fs: %s: wrong magic number %#x (expected %#x)\n", 304*cfe60390STomohiro Kusumi devtoname(dev), le16toh(es->e2fs_magic), E2FS_MAGIC); 305*cfe60390STomohiro Kusumi return (1); 306*cfe60390STomohiro Kusumi } 307*cfe60390STomohiro Kusumi if (le32toh(es->e2fs_rev) > E2FS_REV0) { 308*cfe60390STomohiro Kusumi mask = le32toh(es->e2fs_features_incompat) & ~(EXT2F_INCOMPAT_SUPP); 309*cfe60390STomohiro Kusumi if (mask) { 310*cfe60390STomohiro Kusumi printf("WARNING: mount of %s denied due to " 311*cfe60390STomohiro Kusumi "unsupported optional features:\n", devtoname(dev)); 312*cfe60390STomohiro Kusumi for (i = 0; 313*cfe60390STomohiro Kusumi i < sizeof(incompat)/sizeof(struct ext2_feature); 314*cfe60390STomohiro Kusumi i++) 315*cfe60390STomohiro Kusumi if (mask & incompat[i].mask) 316*cfe60390STomohiro Kusumi printf("%s ", incompat[i].name); 317*cfe60390STomohiro Kusumi printf("\n"); 318*cfe60390STomohiro Kusumi return (1); 319*cfe60390STomohiro Kusumi } 320*cfe60390STomohiro Kusumi mask = le32toh(es->e2fs_features_rocompat) & ~EXT2F_ROCOMPAT_SUPP; 321*cfe60390STomohiro Kusumi if (!ronly && mask) { 322*cfe60390STomohiro Kusumi printf("WARNING: R/W mount of %s denied due to " 323*cfe60390STomohiro Kusumi "unsupported optional features:\n", devtoname(dev)); 324*cfe60390STomohiro Kusumi for (i = 0; 325*cfe60390STomohiro Kusumi i < sizeof(ro_compat)/sizeof(struct ext2_feature); 326*cfe60390STomohiro Kusumi i++) 327*cfe60390STomohiro Kusumi if (mask & ro_compat[i].mask) 328*cfe60390STomohiro Kusumi printf("%s ", ro_compat[i].name); 329*cfe60390STomohiro Kusumi printf("\n"); 330*cfe60390STomohiro Kusumi return (1); 331*cfe60390STomohiro Kusumi } 332*cfe60390STomohiro Kusumi } 333*cfe60390STomohiro Kusumi return (0); 334*cfe60390STomohiro Kusumi } 335*cfe60390STomohiro Kusumi 336*cfe60390STomohiro Kusumi static e4fs_daddr_t 337*cfe60390STomohiro Kusumi ext2_cg_location(struct m_ext2fs *fs, int number) 338*cfe60390STomohiro Kusumi { 339*cfe60390STomohiro Kusumi int cg, descpb, logical_sb, has_super = 0; 340*cfe60390STomohiro Kusumi 341*cfe60390STomohiro Kusumi /* 342*cfe60390STomohiro Kusumi * Adjust logical superblock block number. 343*cfe60390STomohiro Kusumi * Godmar thinks: if the blocksize is greater than 1024, then 344*cfe60390STomohiro Kusumi * the superblock is logically part of block zero. 345*cfe60390STomohiro Kusumi */ 346*cfe60390STomohiro Kusumi logical_sb = fs->e2fs_bsize > SBSIZE ? 0 : 1; 347*cfe60390STomohiro Kusumi 348*cfe60390STomohiro Kusumi if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_META_BG) || 349*cfe60390STomohiro Kusumi number < le32toh(fs->e2fs->e3fs_first_meta_bg)) 350*cfe60390STomohiro Kusumi return (logical_sb + number + 1); 351*cfe60390STomohiro Kusumi 352*cfe60390STomohiro Kusumi if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) 353*cfe60390STomohiro Kusumi descpb = fs->e2fs_bsize / sizeof(struct ext2_gd); 354*cfe60390STomohiro Kusumi else 355*cfe60390STomohiro Kusumi descpb = fs->e2fs_bsize / E2FS_REV0_GD_SIZE; 356*cfe60390STomohiro Kusumi 357*cfe60390STomohiro Kusumi cg = descpb * number; 358*cfe60390STomohiro Kusumi 359*cfe60390STomohiro Kusumi if (ext2_cg_has_sb(fs, cg)) 360*cfe60390STomohiro Kusumi has_super = 1; 361*cfe60390STomohiro Kusumi 362*cfe60390STomohiro Kusumi return (has_super + cg * (e4fs_daddr_t)EXT2_BLOCKS_PER_GROUP(fs) + 363*cfe60390STomohiro Kusumi le32toh(fs->e2fs->e2fs_first_dblock)); 364*cfe60390STomohiro Kusumi } 365*cfe60390STomohiro Kusumi 366*cfe60390STomohiro Kusumi static int 367*cfe60390STomohiro Kusumi ext2_cg_validate(struct m_ext2fs *fs) 368*cfe60390STomohiro Kusumi { 369*cfe60390STomohiro Kusumi uint64_t b_bitmap; 370*cfe60390STomohiro Kusumi uint64_t i_bitmap; 371*cfe60390STomohiro Kusumi uint64_t i_tables; 372*cfe60390STomohiro Kusumi uint64_t first_block, last_block, last_cg_block; 373*cfe60390STomohiro Kusumi struct ext2_gd *gd; 374*cfe60390STomohiro Kusumi unsigned int i, cg_count; 375*cfe60390STomohiro Kusumi 376*cfe60390STomohiro Kusumi first_block = le32toh(fs->e2fs->e2fs_first_dblock); 377*cfe60390STomohiro Kusumi last_cg_block = ext2_cg_number_gdb(fs, 0); 378*cfe60390STomohiro Kusumi cg_count = fs->e2fs_gcount; 379*cfe60390STomohiro Kusumi 380*cfe60390STomohiro Kusumi for (i = 0; i < fs->e2fs_gcount; i++) { 381*cfe60390STomohiro Kusumi gd = &fs->e2fs_gd[i]; 382*cfe60390STomohiro Kusumi 383*cfe60390STomohiro Kusumi if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG) || 384*cfe60390STomohiro Kusumi i == fs->e2fs_gcount - 1) { 385*cfe60390STomohiro Kusumi last_block = fs->e2fs_bcount - 1; 386*cfe60390STomohiro Kusumi } else { 387*cfe60390STomohiro Kusumi last_block = first_block + 388*cfe60390STomohiro Kusumi (EXT2_BLOCKS_PER_GROUP(fs) - 1); 389*cfe60390STomohiro Kusumi } 390*cfe60390STomohiro Kusumi 391*cfe60390STomohiro Kusumi if ((cg_count == fs->e2fs_gcount) && 392*cfe60390STomohiro Kusumi !(le16toh(gd->ext4bgd_flags) & EXT2_BG_INODE_ZEROED)) 393*cfe60390STomohiro Kusumi cg_count = i; 394*cfe60390STomohiro Kusumi 395*cfe60390STomohiro Kusumi b_bitmap = e2fs_gd_get_b_bitmap(gd); 396*cfe60390STomohiro Kusumi if (b_bitmap == 0) { 397*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 398*cfe60390STomohiro Kusumi "block bitmap is zero", i); 399*cfe60390STomohiro Kusumi return (EINVAL); 400*cfe60390STomohiro Kusumi 401*cfe60390STomohiro Kusumi } 402*cfe60390STomohiro Kusumi if (b_bitmap <= last_cg_block) { 403*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 404*cfe60390STomohiro Kusumi "block bitmap overlaps gds", i); 405*cfe60390STomohiro Kusumi return (EINVAL); 406*cfe60390STomohiro Kusumi } 407*cfe60390STomohiro Kusumi if (b_bitmap < first_block || b_bitmap > last_block) { 408*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 409*cfe60390STomohiro Kusumi "block bitmap not in group", i); 410*cfe60390STomohiro Kusumi return (EINVAL); 411*cfe60390STomohiro Kusumi } 412*cfe60390STomohiro Kusumi 413*cfe60390STomohiro Kusumi i_bitmap = e2fs_gd_get_i_bitmap(gd); 414*cfe60390STomohiro Kusumi if (i_bitmap == 0) { 415*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 416*cfe60390STomohiro Kusumi "inode bitmap is zero", i); 417*cfe60390STomohiro Kusumi return (EINVAL); 418*cfe60390STomohiro Kusumi } 419*cfe60390STomohiro Kusumi if (i_bitmap <= last_cg_block) { 420*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 421*cfe60390STomohiro Kusumi "inode bitmap overlaps gds", i); 422*cfe60390STomohiro Kusumi return (EINVAL); 423*cfe60390STomohiro Kusumi } 424*cfe60390STomohiro Kusumi if (i_bitmap < first_block || i_bitmap > last_block) { 425*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 426*cfe60390STomohiro Kusumi "inode bitmap not in group blk", i); 427*cfe60390STomohiro Kusumi return (EINVAL); 428*cfe60390STomohiro Kusumi } 429*cfe60390STomohiro Kusumi 430*cfe60390STomohiro Kusumi i_tables = e2fs_gd_get_i_tables(gd); 431*cfe60390STomohiro Kusumi if (i_tables == 0) { 432*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 433*cfe60390STomohiro Kusumi "inode table is zero", i); 434*cfe60390STomohiro Kusumi return (EINVAL); 435*cfe60390STomohiro Kusumi } 436*cfe60390STomohiro Kusumi if (i_tables <= last_cg_block) { 437*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 438*cfe60390STomohiro Kusumi "inode talbes overlaps gds", i); 439*cfe60390STomohiro Kusumi return (EINVAL); 440*cfe60390STomohiro Kusumi } 441*cfe60390STomohiro Kusumi if (i_tables < first_block || 442*cfe60390STomohiro Kusumi i_tables + fs->e2fs_itpg - 1 > last_block) { 443*cfe60390STomohiro Kusumi SDT_PROBE2(ext2fs, , vfsops, ext2_cg_validate_error, 444*cfe60390STomohiro Kusumi "inode tables not in group blk", i); 445*cfe60390STomohiro Kusumi return (EINVAL); 446*cfe60390STomohiro Kusumi } 447*cfe60390STomohiro Kusumi 448*cfe60390STomohiro Kusumi if (!EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_FLEX_BG)) 449*cfe60390STomohiro Kusumi first_block += EXT2_BLOCKS_PER_GROUP(fs); 450*cfe60390STomohiro Kusumi } 451*cfe60390STomohiro Kusumi 452*cfe60390STomohiro Kusumi return (0); 453*cfe60390STomohiro Kusumi } 454*cfe60390STomohiro Kusumi 455*cfe60390STomohiro Kusumi /* 456*cfe60390STomohiro Kusumi * This computes the fields of the m_ext2fs structure from the 457*cfe60390STomohiro Kusumi * data in the ext2fs structure read in. 458*cfe60390STomohiro Kusumi */ 459*cfe60390STomohiro Kusumi static int 460*cfe60390STomohiro Kusumi ext2_compute_sb_data(struct vnode *devvp, struct ext2fs *es, 461*cfe60390STomohiro Kusumi struct m_ext2fs *fs) 462*cfe60390STomohiro Kusumi { 463*cfe60390STomohiro Kusumi struct buf *bp; 464*cfe60390STomohiro Kusumi uint32_t e2fs_descpb, e2fs_gdbcount_alloc; 465*cfe60390STomohiro Kusumi int i, j; 466*cfe60390STomohiro Kusumi int g_count = 0; 467*cfe60390STomohiro Kusumi int error; 468*cfe60390STomohiro Kusumi 469*cfe60390STomohiro Kusumi /* Check checksum features */ 470*cfe60390STomohiro Kusumi if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) && 471*cfe60390STomohiro Kusumi EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 472*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 473*cfe60390STomohiro Kusumi "incorrect checksum features combination"); 474*cfe60390STomohiro Kusumi return (EINVAL); 475*cfe60390STomohiro Kusumi } 476*cfe60390STomohiro Kusumi 477*cfe60390STomohiro Kusumi /* Precompute checksum seed for all metadata */ 478*cfe60390STomohiro Kusumi ext2_sb_csum_set_seed(fs); 479*cfe60390STomohiro Kusumi 480*cfe60390STomohiro Kusumi /* Verify sb csum if possible */ 481*cfe60390STomohiro Kusumi if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 482*cfe60390STomohiro Kusumi error = ext2_sb_csum_verify(fs); 483*cfe60390STomohiro Kusumi if (error) { 484*cfe60390STomohiro Kusumi return (error); 485*cfe60390STomohiro Kusumi } 486*cfe60390STomohiro Kusumi } 487*cfe60390STomohiro Kusumi 488*cfe60390STomohiro Kusumi /* Check for block size = 1K|2K|4K */ 489*cfe60390STomohiro Kusumi if (le32toh(es->e2fs_log_bsize) > 2) { 490*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 491*cfe60390STomohiro Kusumi "bad block size"); 492*cfe60390STomohiro Kusumi return (EINVAL); 493*cfe60390STomohiro Kusumi } 494*cfe60390STomohiro Kusumi 495*cfe60390STomohiro Kusumi fs->e2fs_bshift = EXT2_MIN_BLOCK_LOG_SIZE + le32toh(es->e2fs_log_bsize); 496*cfe60390STomohiro Kusumi fs->e2fs_bsize = 1U << fs->e2fs_bshift; 497*cfe60390STomohiro Kusumi fs->e2fs_fsbtodb = le32toh(es->e2fs_log_bsize) + 1; 498*cfe60390STomohiro Kusumi fs->e2fs_qbmask = fs->e2fs_bsize - 1; 499*cfe60390STomohiro Kusumi 500*cfe60390STomohiro Kusumi /* Check for fragment size */ 501*cfe60390STomohiro Kusumi if (le32toh(es->e2fs_log_fsize) > 502*cfe60390STomohiro Kusumi (EXT2_MAX_FRAG_LOG_SIZE - EXT2_MIN_BLOCK_LOG_SIZE)) { 503*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 504*cfe60390STomohiro Kusumi "invalid log cluster size"); 505*cfe60390STomohiro Kusumi return (EINVAL); 506*cfe60390STomohiro Kusumi } 507*cfe60390STomohiro Kusumi 508*cfe60390STomohiro Kusumi fs->e2fs_fsize = EXT2_MIN_FRAG_SIZE << le32toh(es->e2fs_log_fsize); 509*cfe60390STomohiro Kusumi if (fs->e2fs_fsize != fs->e2fs_bsize) { 510*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 511*cfe60390STomohiro Kusumi "fragment size != block size"); 512*cfe60390STomohiro Kusumi return (EINVAL); 513*cfe60390STomohiro Kusumi } 514*cfe60390STomohiro Kusumi 515*cfe60390STomohiro Kusumi fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize; 516*cfe60390STomohiro Kusumi 517*cfe60390STomohiro Kusumi /* Check reserved gdt blocks for future filesystem expansion */ 518*cfe60390STomohiro Kusumi if (le16toh(es->e2fs_reserved_ngdb) > (fs->e2fs_bsize / 4)) { 519*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 520*cfe60390STomohiro Kusumi "number of reserved GDT blocks too large"); 521*cfe60390STomohiro Kusumi return (EINVAL); 522*cfe60390STomohiro Kusumi } 523*cfe60390STomohiro Kusumi 524*cfe60390STomohiro Kusumi if (le32toh(es->e2fs_rev) == E2FS_REV0) { 525*cfe60390STomohiro Kusumi fs->e2fs_isize = E2FS_REV0_INODE_SIZE; 526*cfe60390STomohiro Kusumi } else { 527*cfe60390STomohiro Kusumi fs->e2fs_isize = le16toh(es->e2fs_inode_size); 528*cfe60390STomohiro Kusumi 529*cfe60390STomohiro Kusumi /* 530*cfe60390STomohiro Kusumi * Check first ino. 531*cfe60390STomohiro Kusumi */ 532*cfe60390STomohiro Kusumi if (le32toh(es->e2fs_first_ino) < EXT2_FIRSTINO) { 533*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 534*cfe60390STomohiro Kusumi "invalid first ino"); 535*cfe60390STomohiro Kusumi return (EINVAL); 536*cfe60390STomohiro Kusumi } 537*cfe60390STomohiro Kusumi 538*cfe60390STomohiro Kusumi /* 539*cfe60390STomohiro Kusumi * Simple sanity check for superblock inode size value. 540*cfe60390STomohiro Kusumi */ 541*cfe60390STomohiro Kusumi if (EXT2_INODE_SIZE(fs) < E2FS_REV0_INODE_SIZE || 542*cfe60390STomohiro Kusumi EXT2_INODE_SIZE(fs) > fs->e2fs_bsize || 543*cfe60390STomohiro Kusumi (fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) { 544*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 545*cfe60390STomohiro Kusumi "invalid inode size"); 546*cfe60390STomohiro Kusumi return (EINVAL); 547*cfe60390STomohiro Kusumi } 548*cfe60390STomohiro Kusumi } 549*cfe60390STomohiro Kusumi 550*cfe60390STomohiro Kusumi /* Check group descriptors */ 551*cfe60390STomohiro Kusumi if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) && 552*cfe60390STomohiro Kusumi le16toh(es->e3fs_desc_size) != E2FS_64BIT_GD_SIZE) { 553*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 554*cfe60390STomohiro Kusumi "unsupported 64bit descriptor size"); 555*cfe60390STomohiro Kusumi return (EINVAL); 556*cfe60390STomohiro Kusumi } 557*cfe60390STomohiro Kusumi 558*cfe60390STomohiro Kusumi fs->e2fs_bpg = le32toh(es->e2fs_bpg); 559*cfe60390STomohiro Kusumi fs->e2fs_fpg = le32toh(es->e2fs_fpg); 560*cfe60390STomohiro Kusumi if (fs->e2fs_bpg == 0 || fs->e2fs_fpg == 0) { 561*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 562*cfe60390STomohiro Kusumi "zero blocks/fragments per group"); 563*cfe60390STomohiro Kusumi return (EINVAL); 564*cfe60390STomohiro Kusumi } else if (fs->e2fs_bpg != fs->e2fs_fpg) { 565*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 566*cfe60390STomohiro Kusumi "blocks per group not equal fragments per group"); 567*cfe60390STomohiro Kusumi return (EINVAL); 568*cfe60390STomohiro Kusumi } 569*cfe60390STomohiro Kusumi 570*cfe60390STomohiro Kusumi if (fs->e2fs_bpg != fs->e2fs_bsize * 8) { 571*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 572*cfe60390STomohiro Kusumi "non-standard group size unsupported"); 573*cfe60390STomohiro Kusumi return (EINVAL); 574*cfe60390STomohiro Kusumi } 575*cfe60390STomohiro Kusumi 576*cfe60390STomohiro Kusumi fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs); 577*cfe60390STomohiro Kusumi if (fs->e2fs_ipb == 0 || 578*cfe60390STomohiro Kusumi fs->e2fs_ipb > fs->e2fs_bsize / E2FS_REV0_INODE_SIZE) { 579*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 580*cfe60390STomohiro Kusumi "bad inodes per block size"); 581*cfe60390STomohiro Kusumi return (EINVAL); 582*cfe60390STomohiro Kusumi } 583*cfe60390STomohiro Kusumi 584*cfe60390STomohiro Kusumi fs->e2fs_ipg = le32toh(es->e2fs_ipg); 585*cfe60390STomohiro Kusumi if (fs->e2fs_ipg < fs->e2fs_ipb || fs->e2fs_ipg > fs->e2fs_bsize * 8) { 586*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 587*cfe60390STomohiro Kusumi "invalid inodes per group"); 588*cfe60390STomohiro Kusumi return (EINVAL); 589*cfe60390STomohiro Kusumi } 590*cfe60390STomohiro Kusumi 591*cfe60390STomohiro Kusumi fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb; 592*cfe60390STomohiro Kusumi 593*cfe60390STomohiro Kusumi fs->e2fs_bcount = le32toh(es->e2fs_bcount); 594*cfe60390STomohiro Kusumi fs->e2fs_rbcount = le32toh(es->e2fs_rbcount); 595*cfe60390STomohiro Kusumi fs->e2fs_fbcount = le32toh(es->e2fs_fbcount); 596*cfe60390STomohiro Kusumi if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { 597*cfe60390STomohiro Kusumi fs->e2fs_bcount |= (uint64_t)(le32toh(es->e4fs_bcount_hi)) << 32; 598*cfe60390STomohiro Kusumi fs->e2fs_rbcount |= (uint64_t)(le32toh(es->e4fs_rbcount_hi)) << 32; 599*cfe60390STomohiro Kusumi fs->e2fs_fbcount |= (uint64_t)(le32toh(es->e4fs_fbcount_hi)) << 32; 600*cfe60390STomohiro Kusumi } 601*cfe60390STomohiro Kusumi if (fs->e2fs_rbcount > fs->e2fs_bcount || 602*cfe60390STomohiro Kusumi fs->e2fs_fbcount > fs->e2fs_bcount) { 603*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 604*cfe60390STomohiro Kusumi "invalid block count"); 605*cfe60390STomohiro Kusumi return (EINVAL); 606*cfe60390STomohiro Kusumi } 607*cfe60390STomohiro Kusumi 608*cfe60390STomohiro Kusumi fs->e2fs_ficount = le32toh(es->e2fs_ficount); 609*cfe60390STomohiro Kusumi if (fs->e2fs_ficount > le32toh(es->e2fs_icount)) { 610*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 611*cfe60390STomohiro Kusumi "invalid number of free inodes"); 612*cfe60390STomohiro Kusumi return (EINVAL); 613*cfe60390STomohiro Kusumi } 614*cfe60390STomohiro Kusumi 615*cfe60390STomohiro Kusumi if (le32toh(es->e2fs_first_dblock) >= fs->e2fs_bcount) { 616*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 617*cfe60390STomohiro Kusumi "first data block out of range"); 618*cfe60390STomohiro Kusumi return (EINVAL); 619*cfe60390STomohiro Kusumi } 620*cfe60390STomohiro Kusumi 621*cfe60390STomohiro Kusumi fs->e2fs_gcount = howmany(fs->e2fs_bcount - 622*cfe60390STomohiro Kusumi le32toh(es->e2fs_first_dblock), EXT2_BLOCKS_PER_GROUP(fs)); 623*cfe60390STomohiro Kusumi if (fs->e2fs_gcount > ((uint64_t)1 << 32) - EXT2_DESCS_PER_BLOCK(fs)) { 624*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 625*cfe60390STomohiro Kusumi "groups count too large"); 626*cfe60390STomohiro Kusumi return (EINVAL); 627*cfe60390STomohiro Kusumi } 628*cfe60390STomohiro Kusumi 629*cfe60390STomohiro Kusumi /* Check for extra isize in big inodes. */ 630*cfe60390STomohiro Kusumi if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) && 631*cfe60390STomohiro Kusumi EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) { 632*cfe60390STomohiro Kusumi SDT_PROBE1(ext2fs, , vfsops, ext2_compute_sb_data_error, 633*cfe60390STomohiro Kusumi "no space for extra inode timestamps"); 634*cfe60390STomohiro Kusumi return (EINVAL); 635*cfe60390STomohiro Kusumi } 636*cfe60390STomohiro Kusumi 637*cfe60390STomohiro Kusumi /* s_resuid / s_resgid ? */ 638*cfe60390STomohiro Kusumi 639*cfe60390STomohiro Kusumi if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { 640*cfe60390STomohiro Kusumi e2fs_descpb = fs->e2fs_bsize / E2FS_64BIT_GD_SIZE; 641*cfe60390STomohiro Kusumi e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount, e2fs_descpb); 642*cfe60390STomohiro Kusumi } else { 643*cfe60390STomohiro Kusumi e2fs_descpb = fs->e2fs_bsize / E2FS_REV0_GD_SIZE; 644*cfe60390STomohiro Kusumi e2fs_gdbcount_alloc = howmany(fs->e2fs_gcount, 645*cfe60390STomohiro Kusumi fs->e2fs_bsize / sizeof(struct ext2_gd)); 646*cfe60390STomohiro Kusumi } 647*cfe60390STomohiro Kusumi fs->e2fs_gdbcount = howmany(fs->e2fs_gcount, e2fs_descpb); 648*cfe60390STomohiro Kusumi fs->e2fs_gd = malloc(e2fs_gdbcount_alloc * fs->e2fs_bsize, 649*cfe60390STomohiro Kusumi M_EXT2MNT, M_WAITOK | M_ZERO); 650*cfe60390STomohiro Kusumi fs->e2fs_contigdirs = malloc(fs->e2fs_gcount * 651*cfe60390STomohiro Kusumi sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK | M_ZERO); 652*cfe60390STomohiro Kusumi 653*cfe60390STomohiro Kusumi for (i = 0; i < fs->e2fs_gdbcount; i++) { 654*cfe60390STomohiro Kusumi error = ext2_bread(devvp, 655*cfe60390STomohiro Kusumi fsbtodoff(fs, ext2_cg_location(fs, i)), 656*cfe60390STomohiro Kusumi fs->e2fs_bsize, &bp); 657*cfe60390STomohiro Kusumi if (error) { 658*cfe60390STomohiro Kusumi /* 659*cfe60390STomohiro Kusumi * fs->e2fs_gd and fs->e2fs_contigdirs 660*cfe60390STomohiro Kusumi * will be freed later by the caller, 661*cfe60390STomohiro Kusumi * because this function could be called from 662*cfe60390STomohiro Kusumi * MNT_UPDATE path. 663*cfe60390STomohiro Kusumi */ 664*cfe60390STomohiro Kusumi return (error); 665*cfe60390STomohiro Kusumi } 666*cfe60390STomohiro Kusumi if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { 667*cfe60390STomohiro Kusumi memcpy(&fs->e2fs_gd[ 668*cfe60390STomohiro Kusumi i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 669*cfe60390STomohiro Kusumi bp->b_data, fs->e2fs_bsize); 670*cfe60390STomohiro Kusumi } else { 671*cfe60390STomohiro Kusumi for (j = 0; j < e2fs_descpb && 672*cfe60390STomohiro Kusumi g_count < fs->e2fs_gcount; j++, g_count++) 673*cfe60390STomohiro Kusumi memcpy(&fs->e2fs_gd[g_count], 674*cfe60390STomohiro Kusumi bp->b_data + j * E2FS_REV0_GD_SIZE, 675*cfe60390STomohiro Kusumi E2FS_REV0_GD_SIZE); 676*cfe60390STomohiro Kusumi } 677*cfe60390STomohiro Kusumi ext2_brelse(bp); 678*cfe60390STomohiro Kusumi bp = NULL; 679*cfe60390STomohiro Kusumi } 680*cfe60390STomohiro Kusumi 681*cfe60390STomohiro Kusumi /* Validate cgs consistency */ 682*cfe60390STomohiro Kusumi error = ext2_cg_validate(fs); 683*cfe60390STomohiro Kusumi if (error) 684*cfe60390STomohiro Kusumi return (error); 685*cfe60390STomohiro Kusumi 686*cfe60390STomohiro Kusumi /* Verfy cgs csum */ 687*cfe60390STomohiro Kusumi if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 688*cfe60390STomohiro Kusumi EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) { 689*cfe60390STomohiro Kusumi error = ext2_gd_csum_verify(fs, devvp->v_rdev); 690*cfe60390STomohiro Kusumi if (error) 691*cfe60390STomohiro Kusumi return (error); 692*cfe60390STomohiro Kusumi } 693*cfe60390STomohiro Kusumi /* Initialization for the ext2 Orlov allocator variant. */ 694*cfe60390STomohiro Kusumi fs->e2fs_total_dir = 0; 695*cfe60390STomohiro Kusumi for (i = 0; i < fs->e2fs_gcount; i++) 696*cfe60390STomohiro Kusumi fs->e2fs_total_dir += e2fs_gd_get_ndirs(&fs->e2fs_gd[i]); 697*cfe60390STomohiro Kusumi 698*cfe60390STomohiro Kusumi if (le32toh(es->e2fs_rev) == E2FS_REV0 || 699*cfe60390STomohiro Kusumi !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_LARGEFILE)) 700*cfe60390STomohiro Kusumi fs->e2fs_maxfilesize = 0x7fffffff; 701*cfe60390STomohiro Kusumi else { 702*cfe60390STomohiro Kusumi fs->e2fs_maxfilesize = 0xffffffffffff; 703*cfe60390STomohiro Kusumi if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_HUGE_FILE)) 704*cfe60390STomohiro Kusumi fs->e2fs_maxfilesize = 0x7fffffffffffffff; 705*cfe60390STomohiro Kusumi } 706*cfe60390STomohiro Kusumi if (le32toh(es->e4fs_flags) & E2FS_UNSIGNED_HASH) { 707*cfe60390STomohiro Kusumi fs->e2fs_uhash = 3; 708*cfe60390STomohiro Kusumi } else if ((le32toh(es->e4fs_flags) & E2FS_SIGNED_HASH) == 0) { 709*cfe60390STomohiro Kusumi #ifdef __CHAR_UNSIGNED__ 710*cfe60390STomohiro Kusumi es->e4fs_flags = htole32(le32toh(es->e4fs_flags) | E2FS_UNSIGNED_HASH); 711*cfe60390STomohiro Kusumi fs->e2fs_uhash = 3; 712*cfe60390STomohiro Kusumi #else 713*cfe60390STomohiro Kusumi es->e4fs_flags = htole32(le32toh(es->e4fs_flags) | E2FS_SIGNED_HASH); 714*cfe60390STomohiro Kusumi #endif 715*cfe60390STomohiro Kusumi } 716*cfe60390STomohiro Kusumi if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 717*cfe60390STomohiro Kusumi error = ext2_sb_csum_verify(fs); 718*cfe60390STomohiro Kusumi 719*cfe60390STomohiro Kusumi return (error); 720*cfe60390STomohiro Kusumi } 721*cfe60390STomohiro Kusumi 722*cfe60390STomohiro Kusumi struct scaninfo { 723*cfe60390STomohiro Kusumi int rescan; 724*cfe60390STomohiro Kusumi int allerror; 725*cfe60390STomohiro Kusumi int waitfor; 726*cfe60390STomohiro Kusumi struct vnode *devvp; 727*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 728*cfe60390STomohiro Kusumi }; 729*cfe60390STomohiro Kusumi 730*cfe60390STomohiro Kusumi static int 731*cfe60390STomohiro Kusumi ext2_reload_scan(struct mount *mp, struct vnode *vp, void *data) 732*cfe60390STomohiro Kusumi { 733*cfe60390STomohiro Kusumi struct scaninfo *info = data; 734*cfe60390STomohiro Kusumi struct inode *ip; 735*cfe60390STomohiro Kusumi struct buf *bp; 736*cfe60390STomohiro Kusumi int error; 737*cfe60390STomohiro Kusumi 738*cfe60390STomohiro Kusumi /* 739*cfe60390STomohiro Kusumi * Try to recycle 740*cfe60390STomohiro Kusumi */ 741*cfe60390STomohiro Kusumi if (vrecycle(vp)) 742*cfe60390STomohiro Kusumi return (0); 743*cfe60390STomohiro Kusumi 744*cfe60390STomohiro Kusumi /* 745*cfe60390STomohiro Kusumi * Step 1: invalidate all cached file data. 746*cfe60390STomohiro Kusumi */ 747*cfe60390STomohiro Kusumi if (vinvalbuf(vp, 0, 0, 0)) 748*cfe60390STomohiro Kusumi panic("ext2_reload: dirty2"); 749*cfe60390STomohiro Kusumi /* 750*cfe60390STomohiro Kusumi * Step 2: re-read inode data for all active vnodes. 751*cfe60390STomohiro Kusumi */ 752*cfe60390STomohiro Kusumi ip = VTOI(vp); 753*cfe60390STomohiro Kusumi error = ext2_bread(info->devvp, 754*cfe60390STomohiro Kusumi fsbtodoff(info->fs, ino_to_fsba(info->fs, ip->i_number)), 755*cfe60390STomohiro Kusumi (int)info->fs->e2fs_bsize, &bp); 756*cfe60390STomohiro Kusumi if (error) 757*cfe60390STomohiro Kusumi return (error); 758*cfe60390STomohiro Kusumi 759*cfe60390STomohiro Kusumi error = ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data + 760*cfe60390STomohiro Kusumi EXT2_INODE_SIZE(info->fs) * ino_to_fsbo(info->fs, ip->i_number)), 761*cfe60390STomohiro Kusumi ip); 762*cfe60390STomohiro Kusumi 763*cfe60390STomohiro Kusumi ext2_brelse(bp); 764*cfe60390STomohiro Kusumi return (error); 765*cfe60390STomohiro Kusumi } 766*cfe60390STomohiro Kusumi 767*cfe60390STomohiro Kusumi /* 768*cfe60390STomohiro Kusumi * Reload all incore data for a filesystem (used after running fsck on 769*cfe60390STomohiro Kusumi * the root filesystem and finding things to fix). The filesystem must 770*cfe60390STomohiro Kusumi * be mounted read-only. 771*cfe60390STomohiro Kusumi * 772*cfe60390STomohiro Kusumi * Things to do to update the mount: 773*cfe60390STomohiro Kusumi * 1) invalidate all cached meta-data. 774*cfe60390STomohiro Kusumi * 2) re-read superblock from disk. 775*cfe60390STomohiro Kusumi * 3) invalidate all cluster summary information. 776*cfe60390STomohiro Kusumi * 4) invalidate all inactive vnodes. 777*cfe60390STomohiro Kusumi * 5) invalidate all cached file data. 778*cfe60390STomohiro Kusumi * 6) re-read inode data for all active vnodes. 779*cfe60390STomohiro Kusumi * XXX we are missing some steps, in particular # 3, this has to be reviewed. 780*cfe60390STomohiro Kusumi */ 781*cfe60390STomohiro Kusumi static int 782*cfe60390STomohiro Kusumi ext2_reload(struct mount *mp) 783*cfe60390STomohiro Kusumi { 784*cfe60390STomohiro Kusumi struct vnode *devvp; 785*cfe60390STomohiro Kusumi struct buf *bp; 786*cfe60390STomohiro Kusumi struct ext2fs *es; 787*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 788*cfe60390STomohiro Kusumi struct csum *sump; 789*cfe60390STomohiro Kusumi struct scaninfo scaninfo; 790*cfe60390STomohiro Kusumi int error, i; 791*cfe60390STomohiro Kusumi int32_t *lp; 792*cfe60390STomohiro Kusumi 793*cfe60390STomohiro Kusumi if ((mp->mnt_flag & MNT_RDONLY) == 0) 794*cfe60390STomohiro Kusumi return (EINVAL); 795*cfe60390STomohiro Kusumi /* 796*cfe60390STomohiro Kusumi * Step 1: invalidate all cached meta-data. 797*cfe60390STomohiro Kusumi */ 798*cfe60390STomohiro Kusumi devvp = VFSTOEXT2(mp)->um_devvp; 799*cfe60390STomohiro Kusumi vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 800*cfe60390STomohiro Kusumi if (vinvalbuf(devvp, 0, 0, 0) != 0) 801*cfe60390STomohiro Kusumi panic("ext2_reload: dirty1"); 802*cfe60390STomohiro Kusumi vn_unlock(devvp); 803*cfe60390STomohiro Kusumi 804*cfe60390STomohiro Kusumi /* 805*cfe60390STomohiro Kusumi * Step 2: re-read superblock from disk. 806*cfe60390STomohiro Kusumi * constants have been adjusted for ext2 807*cfe60390STomohiro Kusumi */ 808*cfe60390STomohiro Kusumi if ((error = ext2_bread(devvp, SBOFF, SBSIZE, &bp)) != 0) 809*cfe60390STomohiro Kusumi return (error); 810*cfe60390STomohiro Kusumi es = (struct ext2fs *)bp->b_data; 811*cfe60390STomohiro Kusumi if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) { 812*cfe60390STomohiro Kusumi ext2_brelse(bp); 813*cfe60390STomohiro Kusumi return (EIO); /* XXX needs translation */ 814*cfe60390STomohiro Kusumi } 815*cfe60390STomohiro Kusumi fs = VFSTOEXT2(mp)->um_e2fs; 816*cfe60390STomohiro Kusumi bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs)); 817*cfe60390STomohiro Kusumi 818*cfe60390STomohiro Kusumi if ((error = ext2_compute_sb_data(devvp, es, fs)) != 0) { 819*cfe60390STomohiro Kusumi ext2_brelse(bp); 820*cfe60390STomohiro Kusumi return (error); 821*cfe60390STomohiro Kusumi } 822*cfe60390STomohiro Kusumi #ifdef UNKLAR 823*cfe60390STomohiro Kusumi if (fs->fs_sbsize < SBSIZE) 824*cfe60390STomohiro Kusumi bp->b_flags |= B_INVAL; 825*cfe60390STomohiro Kusumi #endif 826*cfe60390STomohiro Kusumi ext2_brelse(bp); 827*cfe60390STomohiro Kusumi 828*cfe60390STomohiro Kusumi /* 829*cfe60390STomohiro Kusumi * Step 3: invalidate all cluster summary information. 830*cfe60390STomohiro Kusumi */ 831*cfe60390STomohiro Kusumi if (fs->e2fs_contigsumsize > 0) { 832*cfe60390STomohiro Kusumi lp = fs->e2fs_maxcluster; 833*cfe60390STomohiro Kusumi sump = fs->e2fs_clustersum; 834*cfe60390STomohiro Kusumi for (i = 0; i < fs->e2fs_gcount; i++, sump++) { 835*cfe60390STomohiro Kusumi *lp++ = fs->e2fs_contigsumsize; 836*cfe60390STomohiro Kusumi sump->cs_init = 0; 837*cfe60390STomohiro Kusumi bzero(sump->cs_sum, fs->e2fs_contigsumsize + 1); 838*cfe60390STomohiro Kusumi } 839*cfe60390STomohiro Kusumi } 840*cfe60390STomohiro Kusumi 841*cfe60390STomohiro Kusumi scaninfo.rescan = 1; 842*cfe60390STomohiro Kusumi scaninfo.devvp = devvp; 843*cfe60390STomohiro Kusumi scaninfo.fs = fs; 844*cfe60390STomohiro Kusumi while (error == 0 && scaninfo.rescan) { 845*cfe60390STomohiro Kusumi scaninfo.rescan = 0; 846*cfe60390STomohiro Kusumi error = vmntvnodescan(mp, VMSC_GETVX, NULL, ext2_reload_scan, 847*cfe60390STomohiro Kusumi &scaninfo); 848*cfe60390STomohiro Kusumi } 849*cfe60390STomohiro Kusumi return (error); 850*cfe60390STomohiro Kusumi } 851*cfe60390STomohiro Kusumi 852*cfe60390STomohiro Kusumi /* 853*cfe60390STomohiro Kusumi * Common code for mount and mountroot. 854*cfe60390STomohiro Kusumi */ 855*cfe60390STomohiro Kusumi static int 856*cfe60390STomohiro Kusumi ext2_mountfs(struct vnode *devvp, struct mount *mp) 857*cfe60390STomohiro Kusumi { 858*cfe60390STomohiro Kusumi struct ext2mount *ump; 859*cfe60390STomohiro Kusumi struct buf *bp; 860*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 861*cfe60390STomohiro Kusumi struct ext2fs *es; 862*cfe60390STomohiro Kusumi struct cdev *dev = devvp->v_rdev; 863*cfe60390STomohiro Kusumi struct csum *sump; 864*cfe60390STomohiro Kusumi int error; 865*cfe60390STomohiro Kusumi int ronly; 866*cfe60390STomohiro Kusumi int i; 867*cfe60390STomohiro Kusumi u_long size; 868*cfe60390STomohiro Kusumi int32_t *lp; 869*cfe60390STomohiro Kusumi int32_t e2fs_maxcontig; 870*cfe60390STomohiro Kusumi 871*cfe60390STomohiro Kusumi /* 872*cfe60390STomohiro Kusumi * Disallow multiple mounts of the same device. 873*cfe60390STomohiro Kusumi * Disallow mounting of a device that is currently in use 874*cfe60390STomohiro Kusumi * (except for root, which might share swap device for miniroot). 875*cfe60390STomohiro Kusumi * Flush out any old buffers remaining from a previous use. 876*cfe60390STomohiro Kusumi */ 877*cfe60390STomohiro Kusumi if ((error = vfs_mountedon(devvp)) != 0) 878*cfe60390STomohiro Kusumi return (error); 879*cfe60390STomohiro Kusumi if (vcount(devvp) > 0) 880*cfe60390STomohiro Kusumi return (EBUSY); 881*cfe60390STomohiro Kusumi if ((error = vinvalbuf(devvp, V_SAVE, 0, 0)) != 0) 882*cfe60390STomohiro Kusumi return (error); 883*cfe60390STomohiro Kusumi #ifdef READONLY 884*cfe60390STomohiro Kusumi /* Turn on this to force it to be read-only. */ 885*cfe60390STomohiro Kusumi mp->mnt_flag |= MNT_RDONLY; 886*cfe60390STomohiro Kusumi #endif 887*cfe60390STomohiro Kusumi ronly = (mp->mnt_flag & MNT_RDONLY) != 0; 888*cfe60390STomohiro Kusumi vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 889*cfe60390STomohiro Kusumi error = VOP_OPEN(devvp, ronly ? FREAD : FREAD | FWRITE, FSCRED, NULL); 890*cfe60390STomohiro Kusumi vn_unlock(devvp); 891*cfe60390STomohiro Kusumi if (error) 892*cfe60390STomohiro Kusumi return (error); 893*cfe60390STomohiro Kusumi 894*cfe60390STomohiro Kusumi if (devvp->v_rdev->si_iosize_max != 0) 895*cfe60390STomohiro Kusumi mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; 896*cfe60390STomohiro Kusumi if (mp->mnt_iosize_max > MAXPHYS) 897*cfe60390STomohiro Kusumi mp->mnt_iosize_max = MAXPHYS; 898*cfe60390STomohiro Kusumi 899*cfe60390STomohiro Kusumi bp = NULL; 900*cfe60390STomohiro Kusumi ump = NULL; 901*cfe60390STomohiro Kusumi if ((error = ext2_bread(devvp, SBOFF, SBSIZE, &bp)) != 0) 902*cfe60390STomohiro Kusumi goto out; 903*cfe60390STomohiro Kusumi es = (struct ext2fs *)bp->b_data; 904*cfe60390STomohiro Kusumi if (ext2_check_sb_compat(es, dev, ronly) != 0) { 905*cfe60390STomohiro Kusumi error = EINVAL; /* XXX needs translation */ 906*cfe60390STomohiro Kusumi goto out; 907*cfe60390STomohiro Kusumi } 908*cfe60390STomohiro Kusumi if ((le16toh(es->e2fs_state) & E2FS_ISCLEAN) == 0 || 909*cfe60390STomohiro Kusumi (le16toh(es->e2fs_state) & E2FS_ERRORS)) { 910*cfe60390STomohiro Kusumi if (ronly || (mp->mnt_flag & MNT_FORCE)) { 911*cfe60390STomohiro Kusumi printf( 912*cfe60390STomohiro Kusumi "WARNING: Filesystem was not properly dismounted\n"); 913*cfe60390STomohiro Kusumi } else { 914*cfe60390STomohiro Kusumi printf( 915*cfe60390STomohiro Kusumi "WARNING: R/W mount denied. Filesystem is not clean - run fsck\n"); 916*cfe60390STomohiro Kusumi error = EPERM; 917*cfe60390STomohiro Kusumi goto out; 918*cfe60390STomohiro Kusumi } 919*cfe60390STomohiro Kusumi } 920*cfe60390STomohiro Kusumi ump = malloc(sizeof(*ump), M_EXT2MNT, M_WAITOK | M_ZERO); 921*cfe60390STomohiro Kusumi 922*cfe60390STomohiro Kusumi /* 923*cfe60390STomohiro Kusumi * I don't know whether this is the right strategy. Note that 924*cfe60390STomohiro Kusumi * we dynamically allocate both an m_ext2fs and an ext2fs 925*cfe60390STomohiro Kusumi * while Linux keeps the super block in a locked buffer. 926*cfe60390STomohiro Kusumi */ 927*cfe60390STomohiro Kusumi ump->um_e2fs = malloc(sizeof(struct m_ext2fs), 928*cfe60390STomohiro Kusumi M_EXT2MNT, M_WAITOK | M_ZERO); 929*cfe60390STomohiro Kusumi ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs), 930*cfe60390STomohiro Kusumi M_EXT2MNT, M_WAITOK); 931*cfe60390STomohiro Kusumi mtx_init(EXT2_MTX(ump), "EXT2FS Lock"); 932*cfe60390STomohiro Kusumi bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs)); 933*cfe60390STomohiro Kusumi if ((error = ext2_compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs))) 934*cfe60390STomohiro Kusumi goto out; 935*cfe60390STomohiro Kusumi 936*cfe60390STomohiro Kusumi /* 937*cfe60390STomohiro Kusumi * Calculate the maximum contiguous blocks and size of cluster summary 938*cfe60390STomohiro Kusumi * array. In FFS this is done by newfs; however, the superblock 939*cfe60390STomohiro Kusumi * in ext2fs doesn't have these variables, so we can calculate 940*cfe60390STomohiro Kusumi * them here. 941*cfe60390STomohiro Kusumi */ 942*cfe60390STomohiro Kusumi e2fs_maxcontig = MAX(1, MAXPHYS / ump->um_e2fs->e2fs_bsize); 943*cfe60390STomohiro Kusumi ump->um_e2fs->e2fs_contigsumsize = MIN(e2fs_maxcontig, EXT2_MAXCONTIG); 944*cfe60390STomohiro Kusumi if (ump->um_e2fs->e2fs_contigsumsize > 0) { 945*cfe60390STomohiro Kusumi size = ump->um_e2fs->e2fs_gcount * sizeof(int32_t); 946*cfe60390STomohiro Kusumi ump->um_e2fs->e2fs_maxcluster = malloc(size, M_EXT2MNT, M_WAITOK); 947*cfe60390STomohiro Kusumi size = ump->um_e2fs->e2fs_gcount * sizeof(struct csum); 948*cfe60390STomohiro Kusumi ump->um_e2fs->e2fs_clustersum = malloc(size, M_EXT2MNT, M_WAITOK); 949*cfe60390STomohiro Kusumi lp = ump->um_e2fs->e2fs_maxcluster; 950*cfe60390STomohiro Kusumi sump = ump->um_e2fs->e2fs_clustersum; 951*cfe60390STomohiro Kusumi for (i = 0; i < ump->um_e2fs->e2fs_gcount; i++, sump++) { 952*cfe60390STomohiro Kusumi *lp++ = ump->um_e2fs->e2fs_contigsumsize; 953*cfe60390STomohiro Kusumi sump->cs_init = 0; 954*cfe60390STomohiro Kusumi sump->cs_sum = malloc((ump->um_e2fs->e2fs_contigsumsize + 1) * 955*cfe60390STomohiro Kusumi sizeof(int32_t), M_EXT2MNT, M_WAITOK | M_ZERO); 956*cfe60390STomohiro Kusumi } 957*cfe60390STomohiro Kusumi } 958*cfe60390STomohiro Kusumi 959*cfe60390STomohiro Kusumi ext2_brelse(bp); 960*cfe60390STomohiro Kusumi bp = NULL; 961*cfe60390STomohiro Kusumi fs = ump->um_e2fs; 962*cfe60390STomohiro Kusumi fs->e2fs_ronly = ronly; /* ronly is set according to mnt_flags */ 963*cfe60390STomohiro Kusumi 964*cfe60390STomohiro Kusumi /* 965*cfe60390STomohiro Kusumi * If the fs is not mounted read-only, make sure the super block is 966*cfe60390STomohiro Kusumi * always written back on a sync(). 967*cfe60390STomohiro Kusumi */ 968*cfe60390STomohiro Kusumi fs->e2fs_wasvalid = le16toh(fs->e2fs->e2fs_state) & E2FS_ISCLEAN ? 1 : 0; 969*cfe60390STomohiro Kusumi if (ronly == 0) { 970*cfe60390STomohiro Kusumi fs->e2fs_fmod = 1; /* mark it modified and set fs invalid */ 971*cfe60390STomohiro Kusumi fs->e2fs->e2fs_state = 972*cfe60390STomohiro Kusumi htole16(le16toh(fs->e2fs->e2fs_state) & ~E2FS_ISCLEAN); 973*cfe60390STomohiro Kusumi } 974*cfe60390STomohiro Kusumi mp->mnt_data = (qaddr_t)ump; 975*cfe60390STomohiro Kusumi mp->mnt_stat.f_fsid.val[0] = devid_from_dev(dev); 976*cfe60390STomohiro Kusumi mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 977*cfe60390STomohiro Kusumi mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN; 978*cfe60390STomohiro Kusumi mp->mnt_flag |= MNT_LOCAL; 979*cfe60390STomohiro Kusumi ump->um_mountp = mp; 980*cfe60390STomohiro Kusumi ump->um_dev = dev; 981*cfe60390STomohiro Kusumi ump->um_devvp = devvp; 982*cfe60390STomohiro Kusumi 983*cfe60390STomohiro Kusumi /* 984*cfe60390STomohiro Kusumi * Setting those two parameters allowed us to use 985*cfe60390STomohiro Kusumi * ufs_bmap w/o changse! 986*cfe60390STomohiro Kusumi */ 987*cfe60390STomohiro Kusumi ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs); 988*cfe60390STomohiro Kusumi ump->um_bptrtodb = le32toh(fs->e2fs->e2fs_log_bsize) + 1; 989*cfe60390STomohiro Kusumi ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs); 990*cfe60390STomohiro Kusumi dev->si_mountpoint = mp; 991*cfe60390STomohiro Kusumi 992*cfe60390STomohiro Kusumi vfs_add_vnodeops(mp, &ext2_vnodeops, &mp->mnt_vn_norm_ops); 993*cfe60390STomohiro Kusumi vfs_add_vnodeops(mp, &ext2_specops, &mp->mnt_vn_spec_ops); 994*cfe60390STomohiro Kusumi vfs_add_vnodeops(mp, &ext2_fifoops, &mp->mnt_vn_fifo_ops); 995*cfe60390STomohiro Kusumi 996*cfe60390STomohiro Kusumi if (ronly == 0) 997*cfe60390STomohiro Kusumi ext2_sbupdate(ump, MNT_WAIT); 998*cfe60390STomohiro Kusumi return (0); 999*cfe60390STomohiro Kusumi out: 1000*cfe60390STomohiro Kusumi if (bp) 1001*cfe60390STomohiro Kusumi ext2_brelse(bp); 1002*cfe60390STomohiro Kusumi vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 1003*cfe60390STomohiro Kusumi VOP_CLOSE(devvp, ronly ? FREAD : FREAD | FWRITE, NULL); 1004*cfe60390STomohiro Kusumi vn_unlock(devvp); 1005*cfe60390STomohiro Kusumi if (ump) { 1006*cfe60390STomohiro Kusumi mtx_uninit(EXT2_MTX(ump)); 1007*cfe60390STomohiro Kusumi free(ump->um_e2fs->e2fs_gd, M_EXT2MNT); 1008*cfe60390STomohiro Kusumi free(ump->um_e2fs->e2fs_contigdirs, M_EXT2MNT); 1009*cfe60390STomohiro Kusumi free(ump->um_e2fs->e2fs, M_EXT2MNT); 1010*cfe60390STomohiro Kusumi free(ump->um_e2fs, M_EXT2MNT); 1011*cfe60390STomohiro Kusumi free(ump, M_EXT2MNT); 1012*cfe60390STomohiro Kusumi mp->mnt_data = NULL; 1013*cfe60390STomohiro Kusumi } 1014*cfe60390STomohiro Kusumi return (error); 1015*cfe60390STomohiro Kusumi } 1016*cfe60390STomohiro Kusumi 1017*cfe60390STomohiro Kusumi /* 1018*cfe60390STomohiro Kusumi * Unmount system call. 1019*cfe60390STomohiro Kusumi */ 1020*cfe60390STomohiro Kusumi static int 1021*cfe60390STomohiro Kusumi ext2_unmount(struct mount *mp, int mntflags) 1022*cfe60390STomohiro Kusumi { 1023*cfe60390STomohiro Kusumi struct ext2mount *ump; 1024*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 1025*cfe60390STomohiro Kusumi struct csum *sump; 1026*cfe60390STomohiro Kusumi int error, flags, i, ronly; 1027*cfe60390STomohiro Kusumi 1028*cfe60390STomohiro Kusumi flags = 0; 1029*cfe60390STomohiro Kusumi if (mntflags & MNT_FORCE) { 1030*cfe60390STomohiro Kusumi if (mp->mnt_flag & MNT_ROOTFS) 1031*cfe60390STomohiro Kusumi return (EINVAL); 1032*cfe60390STomohiro Kusumi flags |= FORCECLOSE; 1033*cfe60390STomohiro Kusumi } 1034*cfe60390STomohiro Kusumi if ((error = ext2_flushfiles(mp, flags)) != 0) 1035*cfe60390STomohiro Kusumi return (error); 1036*cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 1037*cfe60390STomohiro Kusumi fs = ump->um_e2fs; 1038*cfe60390STomohiro Kusumi ronly = fs->e2fs_ronly; 1039*cfe60390STomohiro Kusumi if (ronly == 0 && ext2_cgupdate(ump, MNT_WAIT) == 0) { 1040*cfe60390STomohiro Kusumi if (fs->e2fs_wasvalid) 1041*cfe60390STomohiro Kusumi fs->e2fs->e2fs_state = 1042*cfe60390STomohiro Kusumi htole16(le16toh(fs->e2fs->e2fs_state) | E2FS_ISCLEAN); 1043*cfe60390STomohiro Kusumi ext2_sbupdate(ump, MNT_WAIT); 1044*cfe60390STomohiro Kusumi } 1045*cfe60390STomohiro Kusumi 1046*cfe60390STomohiro Kusumi ump->um_devvp->v_rdev->si_mountpoint = NULL; 1047*cfe60390STomohiro Kusumi 1048*cfe60390STomohiro Kusumi vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); 1049*cfe60390STomohiro Kusumi error = VOP_CLOSE(ump->um_devvp, ronly ? FREAD : FREAD | FWRITE, NULL); 1050*cfe60390STomohiro Kusumi vn_unlock(ump->um_devvp); 1051*cfe60390STomohiro Kusumi 1052*cfe60390STomohiro Kusumi vrele(ump->um_devvp); 1053*cfe60390STomohiro Kusumi sump = fs->e2fs_clustersum; 1054*cfe60390STomohiro Kusumi for (i = 0; i < fs->e2fs_gcount; i++, sump++) 1055*cfe60390STomohiro Kusumi free(sump->cs_sum, M_EXT2MNT); 1056*cfe60390STomohiro Kusumi free(fs->e2fs_clustersum, M_EXT2MNT); 1057*cfe60390STomohiro Kusumi free(fs->e2fs_maxcluster, M_EXT2MNT); 1058*cfe60390STomohiro Kusumi free(fs->e2fs_gd, M_EXT2MNT); 1059*cfe60390STomohiro Kusumi free(fs->e2fs_contigdirs, M_EXT2MNT); 1060*cfe60390STomohiro Kusumi free(fs->e2fs, M_EXT2MNT); 1061*cfe60390STomohiro Kusumi free(fs, M_EXT2MNT); 1062*cfe60390STomohiro Kusumi free(ump, M_EXT2MNT); 1063*cfe60390STomohiro Kusumi mp->mnt_data = NULL; 1064*cfe60390STomohiro Kusumi mp->mnt_flag &= ~MNT_LOCAL; 1065*cfe60390STomohiro Kusumi return (error); 1066*cfe60390STomohiro Kusumi } 1067*cfe60390STomohiro Kusumi 1068*cfe60390STomohiro Kusumi /* 1069*cfe60390STomohiro Kusumi * Flush out all the files in a filesystem. 1070*cfe60390STomohiro Kusumi */ 1071*cfe60390STomohiro Kusumi static int 1072*cfe60390STomohiro Kusumi ext2_flushfiles(struct mount *mp, int flags) 1073*cfe60390STomohiro Kusumi { 1074*cfe60390STomohiro Kusumi int error; 1075*cfe60390STomohiro Kusumi 1076*cfe60390STomohiro Kusumi error = vflush(mp, 0, flags); 1077*cfe60390STomohiro Kusumi return (error); 1078*cfe60390STomohiro Kusumi } 1079*cfe60390STomohiro Kusumi 1080*cfe60390STomohiro Kusumi /* 1081*cfe60390STomohiro Kusumi * Get filesystem statistics. 1082*cfe60390STomohiro Kusumi */ 1083*cfe60390STomohiro Kusumi static int 1084*cfe60390STomohiro Kusumi ext2_statfs(struct mount *mp, struct statfs *sbp, struct ucred *cred) 1085*cfe60390STomohiro Kusumi { 1086*cfe60390STomohiro Kusumi struct ext2mount *ump; 1087*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 1088*cfe60390STomohiro Kusumi uint32_t overhead, overhead_per_group, ngdb; 1089*cfe60390STomohiro Kusumi int i, ngroups; 1090*cfe60390STomohiro Kusumi 1091*cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 1092*cfe60390STomohiro Kusumi fs = ump->um_e2fs; 1093*cfe60390STomohiro Kusumi if (le16toh(fs->e2fs->e2fs_magic) != E2FS_MAGIC) 1094*cfe60390STomohiro Kusumi panic("ext2_statfs"); 1095*cfe60390STomohiro Kusumi 1096*cfe60390STomohiro Kusumi /* 1097*cfe60390STomohiro Kusumi * Compute the overhead (FS structures) 1098*cfe60390STomohiro Kusumi */ 1099*cfe60390STomohiro Kusumi overhead_per_group = 1100*cfe60390STomohiro Kusumi 1 /* block bitmap */ + 1101*cfe60390STomohiro Kusumi 1 /* inode bitmap */ + 1102*cfe60390STomohiro Kusumi fs->e2fs_itpg; 1103*cfe60390STomohiro Kusumi overhead = le32toh(fs->e2fs->e2fs_first_dblock) + 1104*cfe60390STomohiro Kusumi fs->e2fs_gcount * overhead_per_group; 1105*cfe60390STomohiro Kusumi if (le32toh(fs->e2fs->e2fs_rev) > E2FS_REV0 && 1106*cfe60390STomohiro Kusumi le32toh(fs->e2fs->e2fs_features_rocompat) & EXT2F_ROCOMPAT_SPARSESUPER) { 1107*cfe60390STomohiro Kusumi for (i = 0, ngroups = 0; i < fs->e2fs_gcount; i++) { 1108*cfe60390STomohiro Kusumi if (ext2_cg_has_sb(fs, i)) 1109*cfe60390STomohiro Kusumi ngroups++; 1110*cfe60390STomohiro Kusumi } 1111*cfe60390STomohiro Kusumi } else { 1112*cfe60390STomohiro Kusumi ngroups = fs->e2fs_gcount; 1113*cfe60390STomohiro Kusumi } 1114*cfe60390STomohiro Kusumi ngdb = fs->e2fs_gdbcount; 1115*cfe60390STomohiro Kusumi if (le32toh(fs->e2fs->e2fs_rev) > E2FS_REV0 && 1116*cfe60390STomohiro Kusumi le32toh(fs->e2fs->e2fs_features_compat) & EXT2F_COMPAT_RESIZE) 1117*cfe60390STomohiro Kusumi ngdb += le16toh(fs->e2fs->e2fs_reserved_ngdb); 1118*cfe60390STomohiro Kusumi overhead += ngroups * (1 /* superblock */ + ngdb); 1119*cfe60390STomohiro Kusumi 1120*cfe60390STomohiro Kusumi sbp->f_type = mp->mnt_vfc->vfc_typenum; 1121*cfe60390STomohiro Kusumi sbp->f_bsize = EXT2_FRAG_SIZE(fs); 1122*cfe60390STomohiro Kusumi sbp->f_iosize = EXT2_BLOCK_SIZE(fs); 1123*cfe60390STomohiro Kusumi sbp->f_blocks = fs->e2fs_bcount - overhead; 1124*cfe60390STomohiro Kusumi sbp->f_bfree = fs->e2fs_fbcount; 1125*cfe60390STomohiro Kusumi sbp->f_bavail = sbp->f_bfree - fs->e2fs_rbcount; 1126*cfe60390STomohiro Kusumi sbp->f_files = le32toh(fs->e2fs->e2fs_icount); 1127*cfe60390STomohiro Kusumi sbp->f_ffree = fs->e2fs_ficount; 1128*cfe60390STomohiro Kusumi if (sbp != &mp->mnt_stat) { 1129*cfe60390STomohiro Kusumi bcopy((caddr_t)mp->mnt_stat.f_mntfromname, 1130*cfe60390STomohiro Kusumi (caddr_t)&sbp->f_mntfromname[0], MNAMELEN); 1131*cfe60390STomohiro Kusumi } 1132*cfe60390STomohiro Kusumi return (0); 1133*cfe60390STomohiro Kusumi } 1134*cfe60390STomohiro Kusumi 1135*cfe60390STomohiro Kusumi static int 1136*cfe60390STomohiro Kusumi ext2_statvfs(struct mount *mp, struct statvfs *sbp, struct ucred *cred) 1137*cfe60390STomohiro Kusumi { 1138*cfe60390STomohiro Kusumi struct ext2mount *ump; 1139*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 1140*cfe60390STomohiro Kusumi uint32_t overhead, overhead_per_group, ngdb; 1141*cfe60390STomohiro Kusumi int i, ngroups; 1142*cfe60390STomohiro Kusumi 1143*cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 1144*cfe60390STomohiro Kusumi fs = ump->um_e2fs; 1145*cfe60390STomohiro Kusumi if (le16toh(fs->e2fs->e2fs_magic) != E2FS_MAGIC) 1146*cfe60390STomohiro Kusumi panic("ext2_statfs"); 1147*cfe60390STomohiro Kusumi 1148*cfe60390STomohiro Kusumi /* 1149*cfe60390STomohiro Kusumi * Compute the overhead (FS structures) 1150*cfe60390STomohiro Kusumi */ 1151*cfe60390STomohiro Kusumi overhead_per_group = 1152*cfe60390STomohiro Kusumi 1 /* block bitmap */ + 1153*cfe60390STomohiro Kusumi 1 /* inode bitmap */ + 1154*cfe60390STomohiro Kusumi fs->e2fs_itpg; 1155*cfe60390STomohiro Kusumi overhead = le32toh(fs->e2fs->e2fs_first_dblock) + 1156*cfe60390STomohiro Kusumi fs->e2fs_gcount * overhead_per_group; 1157*cfe60390STomohiro Kusumi if (le32toh(fs->e2fs->e2fs_rev) > E2FS_REV0 && 1158*cfe60390STomohiro Kusumi le32toh(fs->e2fs->e2fs_features_rocompat) & EXT2F_ROCOMPAT_SPARSESUPER) { 1159*cfe60390STomohiro Kusumi for (i = 0, ngroups = 0; i < fs->e2fs_gcount; i++) { 1160*cfe60390STomohiro Kusumi if (ext2_cg_has_sb(fs, i)) 1161*cfe60390STomohiro Kusumi ngroups++; 1162*cfe60390STomohiro Kusumi } 1163*cfe60390STomohiro Kusumi } else { 1164*cfe60390STomohiro Kusumi ngroups = fs->e2fs_gcount; 1165*cfe60390STomohiro Kusumi } 1166*cfe60390STomohiro Kusumi ngdb = fs->e2fs_gdbcount; 1167*cfe60390STomohiro Kusumi if (le32toh(fs->e2fs->e2fs_rev) > E2FS_REV0 && 1168*cfe60390STomohiro Kusumi le32toh(fs->e2fs->e2fs_features_compat) & EXT2F_COMPAT_RESIZE) 1169*cfe60390STomohiro Kusumi ngdb += le16toh(fs->e2fs->e2fs_reserved_ngdb); 1170*cfe60390STomohiro Kusumi overhead += ngroups * (1 /* superblock */ + ngdb); 1171*cfe60390STomohiro Kusumi 1172*cfe60390STomohiro Kusumi sbp->f_type = mp->mnt_vfc->vfc_typenum; 1173*cfe60390STomohiro Kusumi sbp->f_bsize = EXT2_FRAG_SIZE(fs); 1174*cfe60390STomohiro Kusumi sbp->f_frsize = EXT2_BLOCK_SIZE(fs); 1175*cfe60390STomohiro Kusumi sbp->f_blocks = fs->e2fs_bcount - overhead; 1176*cfe60390STomohiro Kusumi sbp->f_bfree = fs->e2fs_fbcount; 1177*cfe60390STomohiro Kusumi sbp->f_bavail = sbp->f_bfree - fs->e2fs_rbcount; 1178*cfe60390STomohiro Kusumi sbp->f_files = le32toh(fs->e2fs->e2fs_icount); 1179*cfe60390STomohiro Kusumi sbp->f_ffree = fs->e2fs_ficount; 1180*cfe60390STomohiro Kusumi return (0); 1181*cfe60390STomohiro Kusumi } 1182*cfe60390STomohiro Kusumi 1183*cfe60390STomohiro Kusumi static int 1184*cfe60390STomohiro Kusumi ext2_sync_scan(struct mount *mp, struct vnode *vp, void *data) 1185*cfe60390STomohiro Kusumi { 1186*cfe60390STomohiro Kusumi struct scaninfo *info = data; 1187*cfe60390STomohiro Kusumi struct inode *ip; 1188*cfe60390STomohiro Kusumi int error; 1189*cfe60390STomohiro Kusumi 1190*cfe60390STomohiro Kusumi ip = VTOI(vp); 1191*cfe60390STomohiro Kusumi if (vp->v_type == VNON || 1192*cfe60390STomohiro Kusumi ((ip->i_flag & 1193*cfe60390STomohiro Kusumi (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && 1194*cfe60390STomohiro Kusumi (RB_EMPTY(&vp->v_rbdirty_tree) || (info->waitfor & MNT_LAZY)))) { 1195*cfe60390STomohiro Kusumi return (0); 1196*cfe60390STomohiro Kusumi } 1197*cfe60390STomohiro Kusumi if ((error = VOP_FSYNC(vp, info->waitfor, 0)) != 0) 1198*cfe60390STomohiro Kusumi info->allerror = error; 1199*cfe60390STomohiro Kusumi return (0); 1200*cfe60390STomohiro Kusumi } 1201*cfe60390STomohiro Kusumi 1202*cfe60390STomohiro Kusumi /* 1203*cfe60390STomohiro Kusumi * Go through the disk queues to initiate sandbagged IO; 1204*cfe60390STomohiro Kusumi * go through the inodes to write those that have been modified; 1205*cfe60390STomohiro Kusumi * initiate the writing of the super block if it has been modified. 1206*cfe60390STomohiro Kusumi * 1207*cfe60390STomohiro Kusumi * Note: we are always called with the filesystem marked `MPBUSY'. 1208*cfe60390STomohiro Kusumi */ 1209*cfe60390STomohiro Kusumi static int 1210*cfe60390STomohiro Kusumi ext2_sync(struct mount *mp, int waitfor) 1211*cfe60390STomohiro Kusumi { 1212*cfe60390STomohiro Kusumi struct ext2mount *ump = VFSTOEXT2(mp); 1213*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 1214*cfe60390STomohiro Kusumi struct scaninfo scaninfo; 1215*cfe60390STomohiro Kusumi int error; 1216*cfe60390STomohiro Kusumi 1217*cfe60390STomohiro Kusumi fs = ump->um_e2fs; 1218*cfe60390STomohiro Kusumi if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) { /* XXX */ 1219*cfe60390STomohiro Kusumi panic("ext2_sync: rofs mod fs=%s", fs->e2fs_fsmnt); 1220*cfe60390STomohiro Kusumi } 1221*cfe60390STomohiro Kusumi 1222*cfe60390STomohiro Kusumi /* 1223*cfe60390STomohiro Kusumi * Write back each (modified) inode. 1224*cfe60390STomohiro Kusumi */ 1225*cfe60390STomohiro Kusumi scaninfo.allerror = 0; 1226*cfe60390STomohiro Kusumi scaninfo.rescan = 1; 1227*cfe60390STomohiro Kusumi scaninfo.waitfor = waitfor; 1228*cfe60390STomohiro Kusumi while (scaninfo.rescan) { 1229*cfe60390STomohiro Kusumi scaninfo.rescan = 0; 1230*cfe60390STomohiro Kusumi vmntvnodescan(mp, VMSC_GETVP | VMSC_NOWAIT, 1231*cfe60390STomohiro Kusumi NULL, ext2_sync_scan, &scaninfo); 1232*cfe60390STomohiro Kusumi } 1233*cfe60390STomohiro Kusumi 1234*cfe60390STomohiro Kusumi /* 1235*cfe60390STomohiro Kusumi * Force stale filesystem control information to be flushed. 1236*cfe60390STomohiro Kusumi */ 1237*cfe60390STomohiro Kusumi if ((waitfor & MNT_LAZY) == 0) { 1238*cfe60390STomohiro Kusumi vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); 1239*cfe60390STomohiro Kusumi if ((error = VOP_FSYNC(ump->um_devvp, waitfor, 0)) != 0) 1240*cfe60390STomohiro Kusumi scaninfo.allerror = error; 1241*cfe60390STomohiro Kusumi vn_unlock(ump->um_devvp); 1242*cfe60390STomohiro Kusumi } 1243*cfe60390STomohiro Kusumi 1244*cfe60390STomohiro Kusumi /* 1245*cfe60390STomohiro Kusumi * Write back modified superblock. 1246*cfe60390STomohiro Kusumi */ 1247*cfe60390STomohiro Kusumi if (fs->e2fs_fmod != 0) { 1248*cfe60390STomohiro Kusumi fs->e2fs_fmod = 0; 1249*cfe60390STomohiro Kusumi fs->e2fs->e2fs_wtime = htole32(time_second); 1250*cfe60390STomohiro Kusumi if ((error = ext2_cgupdate(ump, waitfor)) != 0) 1251*cfe60390STomohiro Kusumi scaninfo.allerror = error; 1252*cfe60390STomohiro Kusumi } 1253*cfe60390STomohiro Kusumi return (scaninfo.allerror); 1254*cfe60390STomohiro Kusumi } 1255*cfe60390STomohiro Kusumi 1256*cfe60390STomohiro Kusumi /* 1257*cfe60390STomohiro Kusumi * Look up an EXT2FS dinode number to find its incore vnode, otherwise read it 1258*cfe60390STomohiro Kusumi * in from disk. If it is in core, wait for the lock bit to clear, then 1259*cfe60390STomohiro Kusumi * return the inode locked. Detection and handling of mount points must be 1260*cfe60390STomohiro Kusumi * done by the calling routine. 1261*cfe60390STomohiro Kusumi */ 1262*cfe60390STomohiro Kusumi static int 1263*cfe60390STomohiro Kusumi ext2_vget(struct mount *mp, struct vnode *dvp, ino_t ino, struct vnode **vpp) 1264*cfe60390STomohiro Kusumi { 1265*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 1266*cfe60390STomohiro Kusumi struct inode *ip; 1267*cfe60390STomohiro Kusumi struct ext2mount *ump; 1268*cfe60390STomohiro Kusumi struct buf *bp; 1269*cfe60390STomohiro Kusumi struct vnode *vp; 1270*cfe60390STomohiro Kusumi cdev_t dev; 1271*cfe60390STomohiro Kusumi unsigned int i, used_blocks; 1272*cfe60390STomohiro Kusumi int error; 1273*cfe60390STomohiro Kusumi 1274*cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 1275*cfe60390STomohiro Kusumi dev = ump->um_dev; 1276*cfe60390STomohiro Kusumi restart: 1277*cfe60390STomohiro Kusumi if ((*vpp = ext2_ihashget(dev, ino)) != NULL) 1278*cfe60390STomohiro Kusumi return (0); 1279*cfe60390STomohiro Kusumi 1280*cfe60390STomohiro Kusumi /* 1281*cfe60390STomohiro Kusumi * Lock out the creation of new entries in the FFS hash table in 1282*cfe60390STomohiro Kusumi * case getnewvnode() or MALLOC() blocks, otherwise a duplicate 1283*cfe60390STomohiro Kusumi * may occur! 1284*cfe60390STomohiro Kusumi */ 1285*cfe60390STomohiro Kusumi if (ext2fs_inode_hash_lock) { 1286*cfe60390STomohiro Kusumi while (ext2fs_inode_hash_lock) { 1287*cfe60390STomohiro Kusumi ext2fs_inode_hash_lock = -1; 1288*cfe60390STomohiro Kusumi tsleep(&ext2fs_inode_hash_lock, 0, "e2vget", 0); 1289*cfe60390STomohiro Kusumi } 1290*cfe60390STomohiro Kusumi goto restart; 1291*cfe60390STomohiro Kusumi } 1292*cfe60390STomohiro Kusumi ext2fs_inode_hash_lock = 1; 1293*cfe60390STomohiro Kusumi 1294*cfe60390STomohiro Kusumi /* 1295*cfe60390STomohiro Kusumi * If this MALLOC() is performed after the getnewvnode() 1296*cfe60390STomohiro Kusumi * it might block, leaving a vnode with a NULL v_data to be 1297*cfe60390STomohiro Kusumi * found by ext2_sync() if a sync happens to fire right then, 1298*cfe60390STomohiro Kusumi * which will cause a panic because ext2_sync() blindly 1299*cfe60390STomohiro Kusumi * dereferences vp->v_data (as well it should). 1300*cfe60390STomohiro Kusumi * 1301*cfe60390STomohiro Kusumi * XXX this may no longer be true since getnewvnode returns a 1302*cfe60390STomohiro Kusumi * VX locked vnode now. 1303*cfe60390STomohiro Kusumi */ 1304*cfe60390STomohiro Kusumi ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); 1305*cfe60390STomohiro Kusumi if (ip == NULL) { 1306*cfe60390STomohiro Kusumi return (ENOMEM); 1307*cfe60390STomohiro Kusumi } 1308*cfe60390STomohiro Kusumi 1309*cfe60390STomohiro Kusumi /* Allocate a new vnode/inode. */ 1310*cfe60390STomohiro Kusumi if ((error = getnewvnode(VT_EXT2FS, mp, &vp, VLKTIMEOUT, 1311*cfe60390STomohiro Kusumi LK_CANRECURSE)) != 0) { 1312*cfe60390STomohiro Kusumi if (ext2fs_inode_hash_lock < 0) 1313*cfe60390STomohiro Kusumi wakeup(&ext2fs_inode_hash_lock); 1314*cfe60390STomohiro Kusumi ext2fs_inode_hash_lock = 0; 1315*cfe60390STomohiro Kusumi *vpp = NULL; 1316*cfe60390STomohiro Kusumi free(ip, M_EXT2NODE); 1317*cfe60390STomohiro Kusumi return (error); 1318*cfe60390STomohiro Kusumi } 1319*cfe60390STomohiro Kusumi vp->v_data = ip; 1320*cfe60390STomohiro Kusumi ip->i_vnode = vp; 1321*cfe60390STomohiro Kusumi ip->i_e2fs = fs = ump->um_e2fs; 1322*cfe60390STomohiro Kusumi ip->i_dev = dev; 1323*cfe60390STomohiro Kusumi ip->i_ump = ump; 1324*cfe60390STomohiro Kusumi ip->i_number = ino; 1325*cfe60390STomohiro Kusumi 1326*cfe60390STomohiro Kusumi /* 1327*cfe60390STomohiro Kusumi * Put it onto its hash chain. Since our vnode is locked, other 1328*cfe60390STomohiro Kusumi * requests for this inode will block if they arrive while we are 1329*cfe60390STomohiro Kusumi * sleeping waiting for old data structures to be purged or for the 1330*cfe60390STomohiro Kusumi * contents of the disk portion of this inode to be read. 1331*cfe60390STomohiro Kusumi */ 1332*cfe60390STomohiro Kusumi if (ext2_ihashins(ip)) { 1333*cfe60390STomohiro Kusumi printf("debug: ext2fs ihashins collision, retrying inode %ld\n", 1334*cfe60390STomohiro Kusumi (long)ip->i_number); 1335*cfe60390STomohiro Kusumi *vpp = NULL; 1336*cfe60390STomohiro Kusumi vp->v_type = VBAD; 1337*cfe60390STomohiro Kusumi vx_put(vp); 1338*cfe60390STomohiro Kusumi free(ip, M_EXT2NODE); 1339*cfe60390STomohiro Kusumi goto restart; 1340*cfe60390STomohiro Kusumi } 1341*cfe60390STomohiro Kusumi 1342*cfe60390STomohiro Kusumi if (ext2fs_inode_hash_lock < 0) 1343*cfe60390STomohiro Kusumi wakeup(&ext2fs_inode_hash_lock); 1344*cfe60390STomohiro Kusumi ext2fs_inode_hash_lock = 0; 1345*cfe60390STomohiro Kusumi 1346*cfe60390STomohiro Kusumi /* Read in the disk contents for the inode, copy into the inode. */ 1347*cfe60390STomohiro Kusumi if ((error = ext2_bread(ump->um_devvp, fsbtodoff(fs, ino_to_fsba(fs, ino)), 1348*cfe60390STomohiro Kusumi (int)fs->e2fs_bsize, &bp)) != 0) { 1349*cfe60390STomohiro Kusumi /* 1350*cfe60390STomohiro Kusumi * The inode does not contain anything useful, so it would 1351*cfe60390STomohiro Kusumi * be misleading to leave it on its hash chain. With mode 1352*cfe60390STomohiro Kusumi * still zero, it will be unlinked and returned to the free 1353*cfe60390STomohiro Kusumi * list by vput(). 1354*cfe60390STomohiro Kusumi */ 1355*cfe60390STomohiro Kusumi vp->v_type = VBAD; 1356*cfe60390STomohiro Kusumi ext2_brelse(bp); 1357*cfe60390STomohiro Kusumi vx_put(vp); 1358*cfe60390STomohiro Kusumi *vpp = NULL; 1359*cfe60390STomohiro Kusumi return (error); 1360*cfe60390STomohiro Kusumi } 1361*cfe60390STomohiro Kusumi /* convert ext2 inode to dinode */ 1362*cfe60390STomohiro Kusumi error = ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data + 1363*cfe60390STomohiro Kusumi EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ino)), ip); 1364*cfe60390STomohiro Kusumi if (error) { 1365*cfe60390STomohiro Kusumi ext2_brelse(bp); 1366*cfe60390STomohiro Kusumi vx_put(vp); 1367*cfe60390STomohiro Kusumi *vpp = NULL; 1368*cfe60390STomohiro Kusumi return (error); 1369*cfe60390STomohiro Kusumi } 1370*cfe60390STomohiro Kusumi ip->i_block_group = ino_to_cg(fs, ino); 1371*cfe60390STomohiro Kusumi ip->i_next_alloc_block = 0; 1372*cfe60390STomohiro Kusumi ip->i_next_alloc_goal = 0; 1373*cfe60390STomohiro Kusumi 1374*cfe60390STomohiro Kusumi /* 1375*cfe60390STomohiro Kusumi * Now we want to make sure that block pointers for unused 1376*cfe60390STomohiro Kusumi * blocks are zeroed out - ext2_balloc depends on this 1377*cfe60390STomohiro Kusumi * although for regular files and directories only 1378*cfe60390STomohiro Kusumi * 1379*cfe60390STomohiro Kusumi * If IN_E4EXTENTS is enabled, unused blocks are not zeroed 1380*cfe60390STomohiro Kusumi * out because we could corrupt the extent tree. 1381*cfe60390STomohiro Kusumi */ 1382*cfe60390STomohiro Kusumi if (!(ip->i_flag & IN_E4EXTENTS) && 1383*cfe60390STomohiro Kusumi (S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode))) { 1384*cfe60390STomohiro Kusumi used_blocks = howmany(ip->i_size, fs->e2fs_bsize); 1385*cfe60390STomohiro Kusumi for (i = used_blocks; i < EXT2_NDIR_BLOCKS; i++) 1386*cfe60390STomohiro Kusumi ip->i_db[i] = 0; 1387*cfe60390STomohiro Kusumi } 1388*cfe60390STomohiro Kusumi #ifdef EXT2FS_PRINT_EXTENTS 1389*cfe60390STomohiro Kusumi ext2_print_inode(ip); 1390*cfe60390STomohiro Kusumi ext4_ext_print_extent_tree_status(ip); 1391*cfe60390STomohiro Kusumi #endif 1392*cfe60390STomohiro Kusumi ext2_bqrelse(bp); 1393*cfe60390STomohiro Kusumi 1394*cfe60390STomohiro Kusumi /* 1395*cfe60390STomohiro Kusumi * Initialize the vnode from the inode, check for aliases. 1396*cfe60390STomohiro Kusumi * Note that the underlying vnode may have changed. 1397*cfe60390STomohiro Kusumi */ 1398*cfe60390STomohiro Kusumi if ((error = ext2_vinit(mp, &vp)) != 0) { 1399*cfe60390STomohiro Kusumi vx_put(vp); 1400*cfe60390STomohiro Kusumi *vpp = NULL; 1401*cfe60390STomohiro Kusumi return (error); 1402*cfe60390STomohiro Kusumi } 1403*cfe60390STomohiro Kusumi 1404*cfe60390STomohiro Kusumi /* 1405*cfe60390STomohiro Kusumi * Finish inode initialization now that aliasing has been resolved. 1406*cfe60390STomohiro Kusumi */ 1407*cfe60390STomohiro Kusumi ip->i_devvp = ump->um_devvp; 1408*cfe60390STomohiro Kusumi vref(ip->i_devvp); 1409*cfe60390STomohiro Kusumi /* 1410*cfe60390STomohiro Kusumi * Set up a generation number for this inode if it does not 1411*cfe60390STomohiro Kusumi * already have one. This should only happen on old filesystems. 1412*cfe60390STomohiro Kusumi */ 1413*cfe60390STomohiro Kusumi if (ip->i_gen == 0) { 1414*cfe60390STomohiro Kusumi ip->i_gen = krandom() / 2 + 1; 1415*cfe60390STomohiro Kusumi if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 1416*cfe60390STomohiro Kusumi ip->i_flag |= IN_MODIFIED; 1417*cfe60390STomohiro Kusumi } 1418*cfe60390STomohiro Kusumi /* 1419*cfe60390STomohiro Kusumi * Return the locked and refd vnode. 1420*cfe60390STomohiro Kusumi */ 1421*cfe60390STomohiro Kusumi vx_downgrade(vp); /* downgrade VX lock to VN lock */ 1422*cfe60390STomohiro Kusumi *vpp = vp; 1423*cfe60390STomohiro Kusumi 1424*cfe60390STomohiro Kusumi return (0); 1425*cfe60390STomohiro Kusumi } 1426*cfe60390STomohiro Kusumi 1427*cfe60390STomohiro Kusumi /* 1428*cfe60390STomohiro Kusumi * File handle to vnode 1429*cfe60390STomohiro Kusumi * 1430*cfe60390STomohiro Kusumi * Have to be really careful about stale file handles: 1431*cfe60390STomohiro Kusumi * - check that the inode number is valid 1432*cfe60390STomohiro Kusumi * - call ext2_vget() to get the locked inode 1433*cfe60390STomohiro Kusumi * - check for an unallocated inode (i_mode == 0) 1434*cfe60390STomohiro Kusumi * - check that the given client host has export rights and return 1435*cfe60390STomohiro Kusumi * those rights via. exflagsp and credanonp 1436*cfe60390STomohiro Kusumi */ 1437*cfe60390STomohiro Kusumi static int 1438*cfe60390STomohiro Kusumi ext2_fhtovp(struct mount *mp, struct vnode *rootvp, struct fid *fhp, 1439*cfe60390STomohiro Kusumi struct vnode **vpp) 1440*cfe60390STomohiro Kusumi { 1441*cfe60390STomohiro Kusumi struct inode *ip; 1442*cfe60390STomohiro Kusumi struct ufid *ufhp; 1443*cfe60390STomohiro Kusumi struct vnode *nvp; 1444*cfe60390STomohiro Kusumi struct m_ext2fs *fs; 1445*cfe60390STomohiro Kusumi int error; 1446*cfe60390STomohiro Kusumi 1447*cfe60390STomohiro Kusumi ufhp = (struct ufid *)fhp; 1448*cfe60390STomohiro Kusumi fs = VFSTOEXT2(mp)->um_e2fs; 1449*cfe60390STomohiro Kusumi if (ufhp->ufid_ino < EXT2_ROOTINO || 1450*cfe60390STomohiro Kusumi ufhp->ufid_ino > fs->e2fs_gcount * fs->e2fs_ipg) 1451*cfe60390STomohiro Kusumi return (ESTALE); 1452*cfe60390STomohiro Kusumi 1453*cfe60390STomohiro Kusumi error = VFS_VGET(mp, NULL, LK_EXCLUSIVE, &nvp); 1454*cfe60390STomohiro Kusumi if (error) { 1455*cfe60390STomohiro Kusumi *vpp = NULLVP; 1456*cfe60390STomohiro Kusumi return (error); 1457*cfe60390STomohiro Kusumi } 1458*cfe60390STomohiro Kusumi ip = VTOI(nvp); 1459*cfe60390STomohiro Kusumi if (ip->i_mode == 0 || 1460*cfe60390STomohiro Kusumi ip->i_gen != ufhp->ufid_gen || ip->i_nlink <= 0) { 1461*cfe60390STomohiro Kusumi vput(nvp); 1462*cfe60390STomohiro Kusumi *vpp = NULLVP; 1463*cfe60390STomohiro Kusumi return (ESTALE); 1464*cfe60390STomohiro Kusumi } 1465*cfe60390STomohiro Kusumi *vpp = nvp; 1466*cfe60390STomohiro Kusumi return (0); 1467*cfe60390STomohiro Kusumi } 1468*cfe60390STomohiro Kusumi 1469*cfe60390STomohiro Kusumi /* 1470*cfe60390STomohiro Kusumi * Vnode pointer to File handle 1471*cfe60390STomohiro Kusumi */ 1472*cfe60390STomohiro Kusumi /* ARGSUSED */ 1473*cfe60390STomohiro Kusumi static int 1474*cfe60390STomohiro Kusumi ext2_vptofh(struct vnode *vp, struct fid *fhp) 1475*cfe60390STomohiro Kusumi { 1476*cfe60390STomohiro Kusumi struct inode *ip; 1477*cfe60390STomohiro Kusumi struct ufid *ufhp; 1478*cfe60390STomohiro Kusumi 1479*cfe60390STomohiro Kusumi ip = VTOI(vp); 1480*cfe60390STomohiro Kusumi ufhp = (struct ufid *)fhp; 1481*cfe60390STomohiro Kusumi ufhp->ufid_len = sizeof(struct ufid); 1482*cfe60390STomohiro Kusumi ufhp->ufid_ino = ip->i_number; 1483*cfe60390STomohiro Kusumi ufhp->ufid_gen = ip->i_gen; 1484*cfe60390STomohiro Kusumi return (0); 1485*cfe60390STomohiro Kusumi } 1486*cfe60390STomohiro Kusumi 1487*cfe60390STomohiro Kusumi /* 1488*cfe60390STomohiro Kusumi * This is the generic part of fhtovp called after the underlying 1489*cfe60390STomohiro Kusumi * filesystem has validated the file handle. 1490*cfe60390STomohiro Kusumi * 1491*cfe60390STomohiro Kusumi * Verify that a host should have access to a filesystem. 1492*cfe60390STomohiro Kusumi */ 1493*cfe60390STomohiro Kusumi static int 1494*cfe60390STomohiro Kusumi ext2_check_export(struct mount *mp, struct sockaddr *nam, int *exflagsp, 1495*cfe60390STomohiro Kusumi struct ucred **credanonp) 1496*cfe60390STomohiro Kusumi { 1497*cfe60390STomohiro Kusumi struct netcred *np; 1498*cfe60390STomohiro Kusumi struct ext2mount *ump; 1499*cfe60390STomohiro Kusumi 1500*cfe60390STomohiro Kusumi ump = VFSTOEXT2(mp); 1501*cfe60390STomohiro Kusumi /* 1502*cfe60390STomohiro Kusumi * Get the export permission structure for this <mp, client> tuple. 1503*cfe60390STomohiro Kusumi */ 1504*cfe60390STomohiro Kusumi np = vfs_export_lookup(mp, &ump->um_export, nam); 1505*cfe60390STomohiro Kusumi if (np == NULL) 1506*cfe60390STomohiro Kusumi return (EACCES); 1507*cfe60390STomohiro Kusumi 1508*cfe60390STomohiro Kusumi *exflagsp = np->netc_exflags; 1509*cfe60390STomohiro Kusumi *credanonp = &np->netc_anon; 1510*cfe60390STomohiro Kusumi return (0); 1511*cfe60390STomohiro Kusumi } 1512*cfe60390STomohiro Kusumi 1513*cfe60390STomohiro Kusumi /* 1514*cfe60390STomohiro Kusumi * Write a superblock and associated information back to disk. 1515*cfe60390STomohiro Kusumi */ 1516*cfe60390STomohiro Kusumi static int 1517*cfe60390STomohiro Kusumi ext2_sbupdate(struct ext2mount *mp, int waitfor) 1518*cfe60390STomohiro Kusumi { 1519*cfe60390STomohiro Kusumi struct m_ext2fs *fs = mp->um_e2fs; 1520*cfe60390STomohiro Kusumi struct ext2fs *es = fs->e2fs; 1521*cfe60390STomohiro Kusumi struct buf *bp; 1522*cfe60390STomohiro Kusumi int error = 0; 1523*cfe60390STomohiro Kusumi 1524*cfe60390STomohiro Kusumi es->e2fs_bcount = htole32(fs->e2fs_bcount & 0xffffffff); 1525*cfe60390STomohiro Kusumi es->e2fs_rbcount = htole32(fs->e2fs_rbcount & 0xffffffff); 1526*cfe60390STomohiro Kusumi es->e2fs_fbcount = htole32(fs->e2fs_fbcount & 0xffffffff); 1527*cfe60390STomohiro Kusumi if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { 1528*cfe60390STomohiro Kusumi es->e4fs_bcount_hi = htole32(fs->e2fs_bcount >> 32); 1529*cfe60390STomohiro Kusumi es->e4fs_rbcount_hi = htole32(fs->e2fs_rbcount >> 32); 1530*cfe60390STomohiro Kusumi es->e4fs_fbcount_hi = htole32(fs->e2fs_fbcount >> 32); 1531*cfe60390STomohiro Kusumi } 1532*cfe60390STomohiro Kusumi 1533*cfe60390STomohiro Kusumi es->e2fs_ficount = htole32(fs->e2fs_ficount); 1534*cfe60390STomohiro Kusumi 1535*cfe60390STomohiro Kusumi if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 1536*cfe60390STomohiro Kusumi ext2_sb_csum_set(fs); 1537*cfe60390STomohiro Kusumi 1538*cfe60390STomohiro Kusumi bp = getblk(mp->um_devvp, SBOFF, SBSIZE, 0, 0); 1539*cfe60390STomohiro Kusumi bcopy((caddr_t)es, bp->b_data, (u_int)sizeof(struct ext2fs)); 1540*cfe60390STomohiro Kusumi if (waitfor == MNT_WAIT) 1541*cfe60390STomohiro Kusumi error = bwrite(bp); 1542*cfe60390STomohiro Kusumi else 1543*cfe60390STomohiro Kusumi bawrite(bp); 1544*cfe60390STomohiro Kusumi 1545*cfe60390STomohiro Kusumi /* 1546*cfe60390STomohiro Kusumi * The buffers for group descriptors, inode bitmaps and block bitmaps 1547*cfe60390STomohiro Kusumi * are not busy at this point and are (hopefully) written by the 1548*cfe60390STomohiro Kusumi * usual sync mechanism. No need to write them here. 1549*cfe60390STomohiro Kusumi */ 1550*cfe60390STomohiro Kusumi return (error); 1551*cfe60390STomohiro Kusumi } 1552*cfe60390STomohiro Kusumi 1553*cfe60390STomohiro Kusumi static int 1554*cfe60390STomohiro Kusumi ext2_cgupdate(struct ext2mount *mp, int waitfor) 1555*cfe60390STomohiro Kusumi { 1556*cfe60390STomohiro Kusumi struct m_ext2fs *fs = mp->um_e2fs; 1557*cfe60390STomohiro Kusumi struct buf *bp; 1558*cfe60390STomohiro Kusumi int i, j, g_count = 0, error = 0, allerror = 0; 1559*cfe60390STomohiro Kusumi 1560*cfe60390STomohiro Kusumi allerror = ext2_sbupdate(mp, waitfor); 1561*cfe60390STomohiro Kusumi 1562*cfe60390STomohiro Kusumi /* Update gd csums */ 1563*cfe60390STomohiro Kusumi if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM) || 1564*cfe60390STomohiro Kusumi EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_METADATA_CKSUM)) 1565*cfe60390STomohiro Kusumi ext2_gd_csum_set(fs); 1566*cfe60390STomohiro Kusumi 1567*cfe60390STomohiro Kusumi for (i = 0; i < fs->e2fs_gdbcount; i++) { 1568*cfe60390STomohiro Kusumi bp = getblk(mp->um_devvp, fsbtodoff(fs, 1569*cfe60390STomohiro Kusumi ext2_cg_location(fs, i)), 1570*cfe60390STomohiro Kusumi fs->e2fs_bsize, 0, 0); 1571*cfe60390STomohiro Kusumi if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT)) { 1572*cfe60390STomohiro Kusumi memcpy(bp->b_data, &fs->e2fs_gd[ 1573*cfe60390STomohiro Kusumi i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 1574*cfe60390STomohiro Kusumi fs->e2fs_bsize); 1575*cfe60390STomohiro Kusumi } else { 1576*cfe60390STomohiro Kusumi for (j = 0; j < fs->e2fs_bsize / E2FS_REV0_GD_SIZE && 1577*cfe60390STomohiro Kusumi g_count < fs->e2fs_gcount; j++, g_count++) 1578*cfe60390STomohiro Kusumi memcpy(bp->b_data + j * E2FS_REV0_GD_SIZE, 1579*cfe60390STomohiro Kusumi &fs->e2fs_gd[g_count], E2FS_REV0_GD_SIZE); 1580*cfe60390STomohiro Kusumi } 1581*cfe60390STomohiro Kusumi if (waitfor == MNT_WAIT) 1582*cfe60390STomohiro Kusumi error = bwrite(bp); 1583*cfe60390STomohiro Kusumi else 1584*cfe60390STomohiro Kusumi bawrite(bp); 1585*cfe60390STomohiro Kusumi } 1586*cfe60390STomohiro Kusumi 1587*cfe60390STomohiro Kusumi if (!allerror && error) 1588*cfe60390STomohiro Kusumi allerror = error; 1589*cfe60390STomohiro Kusumi return (allerror); 1590*cfe60390STomohiro Kusumi } 1591*cfe60390STomohiro Kusumi 1592*cfe60390STomohiro Kusumi /* 1593*cfe60390STomohiro Kusumi * Return the root of a filesystem. 1594*cfe60390STomohiro Kusumi */ 1595*cfe60390STomohiro Kusumi static int 1596*cfe60390STomohiro Kusumi ext2_root(struct mount *mp, struct vnode **vpp) 1597*cfe60390STomohiro Kusumi { 1598*cfe60390STomohiro Kusumi struct vnode *nvp; 1599*cfe60390STomohiro Kusumi int error; 1600*cfe60390STomohiro Kusumi 1601*cfe60390STomohiro Kusumi error = VFS_VGET(mp, NULL, (ino_t)EXT2_ROOTINO, &nvp); 1602*cfe60390STomohiro Kusumi if (error) 1603*cfe60390STomohiro Kusumi return (error); 1604*cfe60390STomohiro Kusumi *vpp = nvp; 1605*cfe60390STomohiro Kusumi return (0); 1606*cfe60390STomohiro Kusumi } 1607*cfe60390STomohiro Kusumi 1608*cfe60390STomohiro Kusumi /* 1609*cfe60390STomohiro Kusumi * Initialize ext2 filesystems, done only once. 1610*cfe60390STomohiro Kusumi */ 1611*cfe60390STomohiro Kusumi static int 1612*cfe60390STomohiro Kusumi ext2_init(struct vfsconf *vfsp) 1613*cfe60390STomohiro Kusumi { 1614*cfe60390STomohiro Kusumi static int done; 1615*cfe60390STomohiro Kusumi 1616*cfe60390STomohiro Kusumi if (done) 1617*cfe60390STomohiro Kusumi return (0); 1618*cfe60390STomohiro Kusumi done = 1; 1619*cfe60390STomohiro Kusumi ext2_ihashinit(); 1620*cfe60390STomohiro Kusumi 1621*cfe60390STomohiro Kusumi return (0); 1622*cfe60390STomohiro Kusumi } 1623*cfe60390STomohiro Kusumi 1624*cfe60390STomohiro Kusumi static int 1625*cfe60390STomohiro Kusumi ext2_uninit(struct vfsconf *vfsp) 1626*cfe60390STomohiro Kusumi { 1627*cfe60390STomohiro Kusumi 1628*cfe60390STomohiro Kusumi ext2_ihashuninit(); 1629*cfe60390STomohiro Kusumi 1630*cfe60390STomohiro Kusumi return (0); 1631*cfe60390STomohiro Kusumi } 1632