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