1139778Simp/*- 212115Sdyson * modified for EXT2FS support in Lites 1.1 312115Sdyson * 412115Sdyson * Aug 1995, Godmar Back (gback@cs.utah.edu) 512115Sdyson * University of Utah, Department of Computer Science 612115Sdyson */ 7139778Simp/*- 8187396Sstas * Copyright (c) 1989, 1991, 1993, 1994 912115Sdyson * The Regents of the University of California. All rights reserved. 1012115Sdyson * 1112115Sdyson * Redistribution and use in source and binary forms, with or without 1212115Sdyson * modification, are permitted provided that the following conditions 1312115Sdyson * are met: 1412115Sdyson * 1. Redistributions of source code must retain the above copyright 1512115Sdyson * notice, this list of conditions and the following disclaimer. 1612115Sdyson * 2. Redistributions in binary form must reproduce the above copyright 1712115Sdyson * notice, this list of conditions and the following disclaimer in the 1812115Sdyson * documentation and/or other materials provided with the distribution. 1912115Sdyson * 4. Neither the name of the University nor the names of its contributors 2012115Sdyson * may be used to endorse or promote products derived from this software 2112115Sdyson * without specific prior written permission. 2212115Sdyson * 2312115Sdyson * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 2412115Sdyson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 2512115Sdyson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2612115Sdyson * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 2712115Sdyson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2812115Sdyson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2912115Sdyson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 3012115Sdyson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 3112115Sdyson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 3212115Sdyson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 3312115Sdyson * SUCH DAMAGE. 3412115Sdyson * 3512115Sdyson * @(#)ffs_vfsops.c 8.8 (Berkeley) 4/18/94 3693016Sbde * $FreeBSD: stable/11/sys/fs/ext2fs/ext2_vfsops.c 350385 2019-07-27 19:29:28Z fsu $ 3712115Sdyson */ 3812115Sdyson 3912115Sdyson#include <sys/param.h> 4012115Sdyson#include <sys/systm.h> 4112115Sdyson#include <sys/namei.h> 42164033Srwatson#include <sys/priv.h> 4312115Sdyson#include <sys/proc.h> 4412115Sdyson#include <sys/kernel.h> 4512115Sdyson#include <sys/vnode.h> 4612115Sdyson#include <sys/mount.h> 4760041Sphk#include <sys/bio.h> 4812115Sdyson#include <sys/buf.h> 4929906Skato#include <sys/conf.h> 50232703Spfg#include <sys/endian.h> 5124131Sbde#include <sys/fcntl.h> 5212115Sdyson#include <sys/malloc.h> 5312115Sdyson#include <sys/stat.h> 5471576Sjasone#include <sys/mutex.h> 5512115Sdyson 56137039Sphk#include <geom/geom.h> 57137039Sphk#include <geom/geom_vfs.h> 58137039Sphk 59202283Slulf#include <fs/ext2fs/ext2_mount.h> 60202283Slulf#include <fs/ext2fs/inode.h> 6112115Sdyson 62202283Slulf#include <fs/ext2fs/fs.h> 63218176Sjhb#include <fs/ext2fs/ext2fs.h> 64218176Sjhb#include <fs/ext2fs/ext2_dinode.h> 65202283Slulf#include <fs/ext2fs/ext2_extern.h> 6612115Sdyson 67193382Sstasstatic int ext2_flushfiles(struct mount *mp, int flags, struct thread *td); 68193382Sstasstatic int ext2_mountfs(struct vnode *, struct mount *); 69193382Sstasstatic int ext2_reload(struct mount *mp, struct thread *td); 70193382Sstasstatic int ext2_sbupdate(struct ext2mount *, int); 71202283Slulfstatic int ext2_cgupdate(struct ext2mount *, int); 72116271Sphkstatic vfs_unmount_t ext2_unmount; 73116271Sphkstatic vfs_root_t ext2_root; 74116271Sphkstatic vfs_statfs_t ext2_statfs; 75116271Sphkstatic vfs_sync_t ext2_sync; 76116271Sphkstatic vfs_vget_t ext2_vget; 77116271Sphkstatic vfs_fhtovp_t ext2_fhtovp; 78132902Sphkstatic vfs_mount_t ext2_mount; 79116271Sphk 80151897SrwatsonMALLOC_DEFINE(M_EXT2NODE, "ext2_node", "EXT2 vnode private part"); 81151897Srwatsonstatic MALLOC_DEFINE(M_EXT2MNT, "ext2_mount", "EXT2 mount structure"); 8230280Sphk 8312911Sphkstatic struct vfsops ext2fs_vfsops = { 84116271Sphk .vfs_fhtovp = ext2_fhtovp, 85132902Sphk .vfs_mount = ext2_mount, 86116271Sphk .vfs_root = ext2_root, /* root inode via vget */ 87116271Sphk .vfs_statfs = ext2_statfs, 88116271Sphk .vfs_sync = ext2_sync, 89116271Sphk .vfs_unmount = ext2_unmount, 90116271Sphk .vfs_vget = ext2_vget, 9112115Sdyson}; 9212115Sdyson 9338909SbdeVFS_SET(ext2fs_vfsops, ext2fs, 0); 94137039Sphk 95202283Slulfstatic int ext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, 9693014Sbde int ronly); 9792728Salfredstatic int compute_sb_data(struct vnode * devvp, 98202283Slulf struct ext2fs * es, struct m_ext2fs * fs); 9916322Sgpalmer 100217702Sjhbstatic const char *ext2_opts[] = { "acls", "async", "noatime", "noclusterr", 101217702Sjhb "noclusterw", "noexec", "export", "force", "from", "multilabel", 102217702Sjhb "suiddir", "nosymfollow", "sync", "union", NULL }; 103187396Sstas 10412115Sdyson/* 10512115Sdyson * VFS Operations. 10612115Sdyson * 10712115Sdyson * mount system call 10812115Sdyson */ 10912911Sphkstatic int 110193382Sstasext2_mount(struct mount *mp) 11112115Sdyson{ 11297255Smux struct vfsoptlist *opts; 11312115Sdyson struct vnode *devvp; 114191990Sattilio struct thread *td; 115238697Skevlo struct ext2mount *ump = NULL; 116202283Slulf struct m_ext2fs *fs; 117193382Sstas struct nameidata nd, *ndp = &nd; 118193382Sstas accmode_t accmode; 11997255Smux char *path, *fspec; 12097255Smux int error, flags, len; 12112115Sdyson 122191990Sattilio td = curthread; 12397255Smux opts = mp->mnt_optnew; 12497255Smux 125138493Sphk if (vfs_filteropt(opts, ext2_opts)) 126138493Sphk return (EINVAL); 127138493Sphk 12897255Smux vfs_getopt(opts, "fspath", (void **)&path, NULL); 12973286Sadrian /* Double-check the length of path.. */ 130246258Spfg if (strlen(path) >= MAXMNTLEN) 13173286Sadrian return (ENAMETOOLONG); 13297255Smux 13397255Smux fspec = NULL; 13497255Smux error = vfs_getopt(opts, "from", (void **)&fspec, &len); 13597255Smux if (!error && fspec[len - 1] != '\0') 13697255Smux return (EINVAL); 13797255Smux 13812115Sdyson /* 13912115Sdyson * If updating, check whether changing from read-only to 14012115Sdyson * read/write; if there is no device name, that's all we do. 14112115Sdyson */ 14212115Sdyson if (mp->mnt_flag & MNT_UPDATE) { 14396749Siedowse ump = VFSTOEXT2(mp); 144311231Spfg fs = ump->um_e2fs; 14512115Sdyson error = 0; 146202283Slulf if (fs->e2fs_ronly == 0 && 147138493Sphk vfs_flagopt(opts, "ro", NULL, 0)) { 148191990Sattilio error = VFS_SYNC(mp, MNT_WAIT); 149137039Sphk if (error) 150137039Sphk return (error); 15112115Sdyson flags = WRITECLOSE; 15212115Sdyson if (mp->mnt_flag & MNT_FORCE) 15312115Sdyson flags |= FORCECLOSE; 15483366Sjulian error = ext2_flushfiles(mp, flags, td); 155311231Spfg if (error == 0 && fs->e2fs_wasvalid && ext2_cgupdate(ump, MNT_WAIT) == 0) { 156202283Slulf fs->e2fs->e2fs_state |= E2FS_ISCLEAN; 15739670Sbde ext2_sbupdate(ump, MNT_WAIT); 15839670Sbde } 159202283Slulf fs->e2fs_ronly = 1; 160138493Sphk vfs_flagopt(opts, "ro", &mp->mnt_flag, MNT_RDONLY); 161137039Sphk g_topology_lock(); 162137039Sphk g_access(ump->um_cp, 0, -1, 0); 163137039Sphk g_topology_unlock(); 16412115Sdyson } 16512115Sdyson if (!error && (mp->mnt_flag & MNT_RELOAD)) 166140736Sphk error = ext2_reload(mp, td); 16712115Sdyson if (error) 16812115Sdyson return (error); 16957839Sbde devvp = ump->um_devvp; 170202283Slulf if (fs->e2fs_ronly && !vfs_flagopt(opts, "ro", NULL, 0)) { 171202283Slulf if (ext2_check_sb_compat(fs->e2fs, devvp->v_rdev, 0)) 172138493Sphk return (EPERM); 173193382Sstas 17439028Sbde /* 17539028Sbde * If upgrade to read-write by non-root, then verify 17639028Sbde * that user has necessary permissions on the device. 17739028Sbde */ 178175202Sattilio vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 179164033Srwatson error = VOP_ACCESS(devvp, VREAD | VWRITE, 180164033Srwatson td->td_ucred, td); 181164033Srwatson if (error) 182164033Srwatson error = priv_check(td, PRIV_VFS_MOUNT_PERM); 183164033Srwatson if (error) { 184175294Sattilio VOP_UNLOCK(devvp, 0); 185164033Srwatson return (error); 18639028Sbde } 187175294Sattilio VOP_UNLOCK(devvp, 0); 188137039Sphk g_topology_lock(); 189137039Sphk error = g_access(ump->um_cp, 0, 1, 0); 190137039Sphk g_topology_unlock(); 191137039Sphk if (error) 192137039Sphk return (error); 19339028Sbde 194202283Slulf if ((fs->e2fs->e2fs_state & E2FS_ISCLEAN) == 0 || 195202283Slulf (fs->e2fs->e2fs_state & E2FS_ERRORS)) { 19639670Sbde if (mp->mnt_flag & MNT_FORCE) { 197193628Sstas printf( 198202283Slulf"WARNING: %s was not properly dismounted\n", fs->e2fs_fsmnt); 19939670Sbde } else { 200193628Sstas printf( 201193628Sstas"WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", 202202283Slulf fs->e2fs_fsmnt); 20339670Sbde return (EPERM); 20439670Sbde } 20539670Sbde } 206202283Slulf fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN; 207202283Slulf (void)ext2_cgupdate(ump, MNT_WAIT); 208202283Slulf fs->e2fs_ronly = 0; 209162647Stegge MNT_ILOCK(mp); 210138493Sphk mp->mnt_flag &= ~MNT_RDONLY; 211162647Stegge MNT_IUNLOCK(mp); 21212115Sdyson } 213158924Srodrigc if (vfs_flagopt(opts, "export", NULL, 0)) { 214158924Srodrigc /* Process export requests in vfs_mount.c. */ 215158924Srodrigc return (error); 21612115Sdyson } 21712115Sdyson } 218193382Sstas 21912115Sdyson /* 22012115Sdyson * Not an update, or updating the name: look up the name 221125786Sbde * and verify that it refers to a sensible disk device. 22212115Sdyson */ 22397255Smux if (fspec == NULL) 22497255Smux return (EINVAL); 225149720Sssouhlal NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td); 22643301Sdillon if ((error = namei(ndp)) != 0) 22712115Sdyson return (error); 22854655Seivind NDFREE(ndp, NDF_ONLY_PNBUF); 22912115Sdyson devvp = ndp->ni_vp; 23012115Sdyson 23155756Sphk if (!vn_isdisk(devvp, &error)) { 232149720Sssouhlal vput(devvp); 23355756Sphk return (error); 23412115Sdyson } 23539028Sbde 23639028Sbde /* 23739028Sbde * If mount by non-root, then verify that user has necessary 23839028Sbde * permissions on the device. 239164033Srwatson * 240164033Srwatson * XXXRW: VOP_ACCESS() enough? 24139028Sbde */ 242184413Strasz accmode = VREAD; 243164033Srwatson if ((mp->mnt_flag & MNT_RDONLY) == 0) 244184413Strasz accmode |= VWRITE; 245184413Strasz error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); 246164033Srwatson if (error) 247164033Srwatson error = priv_check(td, PRIV_VFS_MOUNT_PERM); 248164033Srwatson if (error) { 249164033Srwatson vput(devvp); 250164033Srwatson return (error); 25139028Sbde } 25239028Sbde 25329888Skato if ((mp->mnt_flag & MNT_UPDATE) == 0) { 254183754Sattilio error = ext2_mountfs(devvp, mp); 25529888Skato } else { 256149771Sssouhlal if (devvp != ump->um_devvp) { 257149720Sssouhlal vput(devvp); 258149771Sssouhlal return (EINVAL); /* needs translation */ 259149771Sssouhlal } else 260149771Sssouhlal vput(devvp); 26112115Sdyson } 26212115Sdyson if (error) { 26312115Sdyson vrele(devvp); 26412115Sdyson return (error); 26512115Sdyson } 26696749Siedowse ump = VFSTOEXT2(mp); 26712115Sdyson fs = ump->um_e2fs; 268193382Sstas 26973286Sadrian /* 27073286Sadrian * Note that this strncpy() is ok because of a check at the start 27173286Sadrian * of ext2_mount(). 27273286Sadrian */ 273202283Slulf strncpy(fs->e2fs_fsmnt, path, MAXMNTLEN); 274202283Slulf fs->e2fs_fsmnt[MAXMNTLEN - 1] = '\0'; 275138493Sphk vfs_mountedfrom(mp, fspec); 27612115Sdyson return (0); 27712115Sdyson} 27812115Sdyson 279193382Sstasstatic int 280202283Slulfext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, int ronly) 28112115Sdyson{ 282322738Spfg uint32_t i, mask; 28312115Sdyson 284202283Slulf if (es->e2fs_magic != E2FS_MAGIC) { 28555313Sbde printf("ext2fs: %s: wrong magic number %#x (expected %#x)\n", 286202283Slulf devtoname(dev), es->e2fs_magic, E2FS_MAGIC); 28755313Sbde return (1); 28855313Sbde } 289202283Slulf if (es->e2fs_rev > E2FS_REV0) { 290322738Spfg mask = es->e2fs_features_incompat & ~(EXT2F_INCOMPAT_SUPP | 291322738Spfg EXT4F_RO_INCOMPAT_SUPP); 292322738Spfg if (mask) { 293322738Spfg printf("WARNING: mount of %s denied due to " 294322738Spfg "unsupported optional features:\n", devtoname(dev)); 295322738Spfg for (i = 0; 296322738Spfg i < sizeof(incompat)/sizeof(struct ext2_feature); 297322738Spfg i++) 298322738Spfg if (mask & incompat[i].mask) 299322738Spfg printf("%s ", incompat[i].name); 300322738Spfg printf("\n"); 30155313Sbde return (1); 30255313Sbde } 303322738Spfg mask = es->e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP; 304322738Spfg if (!ronly && mask) { 305193382Sstas printf("WARNING: R/W mount of %s denied due to " 306322738Spfg "unsupported optional features:\n", devtoname(dev)); 307322738Spfg for (i = 0; 308322738Spfg i < sizeof(ro_compat)/sizeof(struct ext2_feature); 309322738Spfg i++) 310322738Spfg if (mask & ro_compat[i].mask) 311322738Spfg printf("%s ", ro_compat[i].name); 312322738Spfg printf("\n"); 31355313Sbde return (1); 31455313Sbde } 31555313Sbde } 31655313Sbde return (0); 31755313Sbde} 31855313Sbde 31912115Sdyson/* 320297695Skevlo * This computes the fields of the m_ext2fs structure from the 321297695Skevlo * data in the ext2fs structure read in. 32212115Sdyson */ 323193382Sstasstatic int 324202283Slulfcompute_sb_data(struct vnode *devvp, struct ext2fs *es, 325202283Slulf struct m_ext2fs *fs) 32612115Sdyson{ 327193382Sstas int db_count, error; 328202283Slulf int i; 329193382Sstas int logic_sb_block = 1; /* XXX for now */ 330202283Slulf struct buf *bp; 331246258Spfg uint32_t e2fs_descpb; 33212115Sdyson 333202283Slulf fs->e2fs_bshift = EXT2_MIN_BLOCK_LOG_SIZE + es->e2fs_log_bsize; 334246564Spfg fs->e2fs_bsize = 1U << fs->e2fs_bshift; 335202283Slulf fs->e2fs_fsbtodb = es->e2fs_log_bsize + 1; 336202283Slulf fs->e2fs_qbmask = fs->e2fs_bsize - 1; 337202283Slulf fs->e2fs_fsize = EXT2_MIN_FRAG_SIZE << es->e2fs_log_fsize; 338202283Slulf if (fs->e2fs_fsize) 339202283Slulf fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize; 340202283Slulf fs->e2fs_bpg = es->e2fs_bpg; 341202283Slulf fs->e2fs_fpg = es->e2fs_fpg; 342202283Slulf fs->e2fs_ipg = es->e2fs_ipg; 343202283Slulf if (es->e2fs_rev == E2FS_REV0) { 344311231Spfg fs->e2fs_isize = E2FS_REV0_INODE_SIZE; 345193382Sstas } else { 346202283Slulf fs->e2fs_isize = es->e2fs_inode_size; 34712115Sdyson 348193382Sstas /* 349193382Sstas * Simple sanity check for superblock inode size value. 350193382Sstas */ 351232703Spfg if (EXT2_INODE_SIZE(fs) < E2FS_REV0_INODE_SIZE || 352232703Spfg EXT2_INODE_SIZE(fs) > fs->e2fs_bsize || 353202283Slulf (fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) { 354232703Spfg printf("ext2fs: invalid inode size %d\n", 355202283Slulf fs->e2fs_isize); 356193382Sstas return (EIO); 357193382Sstas } 358193377Sstas } 359232703Spfg /* Check for extra isize in big inodes. */ 360244475Spfg if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) && 361232703Spfg EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) { 362232703Spfg printf("ext2fs: no space for extra inode timestamps\n"); 363232703Spfg return (EINVAL); 364232703Spfg } 365322712Spfg /* Check for group descriptor size */ 366322712Spfg if (EXT2_HAS_INCOMPAT_FEATURE(fs, EXT2F_INCOMPAT_64BIT) && 367322712Spfg (es->e3fs_desc_size != sizeof(struct ext2_gd))) { 368322712Spfg printf("ext2fs: group descriptor size unsupported %d\n", 369322712Spfg es->e3fs_desc_size); 370322712Spfg return (EINVAL); 371322712Spfg } 372343517Spfg /* Check for block size = 1K|2K|4K */ 373343517Spfg if (es->e2fs_log_bsize > 2) { 374343517Spfg printf("ext2fs: bad block size: %d\n", es->e2fs_log_bsize); 375343517Spfg return (EINVAL); 376343517Spfg } 377343517Spfg /* Check for group size */ 378350385Sfsu if (fs->e2fs_bpg == 0 || fs->e2fs_fpg == 0) { 379350385Sfsu printf("ext2fs: zero blocks/fragments per group"); 380343517Spfg return (EINVAL); 381350385Sfsu } else if (fs->e2fs_bpg != fs->e2fs_fpg) { 382350385Sfsu printf("ext2fs: blocks per group not equal fragments per group"); 383350385Sfsu return (EINVAL); 384343517Spfg } 385343517Spfg if (fs->e2fs_bpg != fs->e2fs_bsize * 8) { 386343517Spfg printf("ext2fs: non-standard group size unsupported %d\n", 387343517Spfg fs->e2fs_bpg); 388343517Spfg return (EINVAL); 389343517Spfg } 390232703Spfg 391202283Slulf fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs); 392343517Spfg if (fs->e2fs_ipg == 0) { 393343517Spfg printf("ext2fs: zero inodes per group\n"); 394343517Spfg return (EINVAL); 395343517Spfg } 396278790Spfg fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb; 397193382Sstas /* s_resuid / s_resgid ? */ 398298609Spfg fs->e2fs_gcount = howmany(es->e2fs_bcount - es->e2fs_first_dblock, 399298609Spfg EXT2_BLOCKS_PER_GROUP(fs)); 400246258Spfg e2fs_descpb = fs->e2fs_bsize / sizeof(struct ext2_gd); 401298609Spfg db_count = howmany(fs->e2fs_gcount, e2fs_descpb); 402202283Slulf fs->e2fs_gdbcount = db_count; 403202283Slulf fs->e2fs_gd = malloc(db_count * fs->e2fs_bsize, 404278802Spfg M_EXT2MNT, M_WAITOK); 405232703Spfg fs->e2fs_contigdirs = malloc(fs->e2fs_gcount * 406278790Spfg sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK | M_ZERO); 40712115Sdyson 408193382Sstas /* 409193382Sstas * Adjust logic_sb_block. 410193382Sstas * Godmar thinks: if the blocksize is greater than 1024, then 411193382Sstas * the superblock is logically part of block zero. 41212115Sdyson */ 413311231Spfg if (fs->e2fs_bsize > SBSIZE) 414193382Sstas logic_sb_block = 0; 415193382Sstas for (i = 0; i < db_count; i++) { 416311231Spfg error = bread(devvp, 417311231Spfg fsbtodb(fs, logic_sb_block + i + 1), 418311231Spfg fs->e2fs_bsize, NOCRED, &bp); 419202283Slulf if (error) { 420278802Spfg free(fs->e2fs_contigdirs, M_EXT2MNT); 421202283Slulf free(fs->e2fs_gd, M_EXT2MNT); 422202283Slulf brelse(bp); 423202283Slulf return (error); 424193382Sstas } 425202283Slulf e2fs_cgload((struct ext2_gd *)bp->b_data, 426202283Slulf &fs->e2fs_gd[ 427311231Spfg i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 428202283Slulf fs->e2fs_bsize); 429202283Slulf brelse(bp); 430202283Slulf bp = NULL; 43112115Sdyson } 432322712Spfg /* Verify cg csum */ 433322712Spfg if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) { 434322712Spfg error = ext2_gd_csum_verify(fs, devvp->v_rdev); 435322712Spfg if (error) 436322712Spfg return (error); 437322712Spfg } 438278790Spfg /* Initialization for the ext2 Orlov allocator variant. */ 439202283Slulf fs->e2fs_total_dir = 0; 440278790Spfg for (i = 0; i < fs->e2fs_gcount; i++) 441202283Slulf fs->e2fs_total_dir += fs->e2fs_gd[i].ext2bgd_ndirs; 442278790Spfg 443202283Slulf if (es->e2fs_rev == E2FS_REV0 || 444232703Spfg !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_LARGEFILE)) 445202283Slulf fs->e2fs_maxfilesize = 0x7fffffff; 446294504Spfg else { 447294504Spfg fs->e2fs_maxfilesize = 0xffffffffffff; 448294504Spfg if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_HUGE_FILE)) 449294504Spfg fs->e2fs_maxfilesize = 0x7fffffffffffffff; 450294504Spfg } 451294504Spfg if (es->e4fs_flags & E2FS_UNSIGNED_HASH) { 452294504Spfg fs->e2fs_uhash = 3; 453294504Spfg } else if ((es->e4fs_flags & E2FS_SIGNED_HASH) == 0) { 454294504Spfg#ifdef __CHAR_UNSIGNED__ 455294504Spfg es->e4fs_flags |= E2FS_UNSIGNED_HASH; 456294504Spfg fs->e2fs_uhash = 3; 457294504Spfg#else 458294504Spfg es->e4fs_flags |= E2FS_SIGNED_HASH; 459294504Spfg#endif 460294504Spfg } 461294504Spfg 462193382Sstas return (0); 46312115Sdyson} 46412115Sdyson 46512115Sdyson/* 46612115Sdyson * Reload all incore data for a filesystem (used after running fsck on 46712115Sdyson * the root filesystem and finding things to fix). The filesystem must 46812115Sdyson * be mounted read-only. 46912115Sdyson * 47012115Sdyson * Things to do to update the mount: 47112115Sdyson * 1) invalidate all cached meta-data. 47212115Sdyson * 2) re-read superblock from disk. 473228539Spfg * 3) invalidate all cluster summary information. 47412115Sdyson * 4) invalidate all inactive vnodes. 47512115Sdyson * 5) invalidate all cached file data. 47612115Sdyson * 6) re-read inode data for all active vnodes. 477202283Slulf * XXX we are missing some steps, in particular # 3, this has to be reviewed. 47812115Sdyson */ 47912911Sphkstatic int 480140736Sphkext2_reload(struct mount *mp, struct thread *td) 48112115Sdyson{ 482154152Stegge struct vnode *vp, *mvp, *devvp; 48312115Sdyson struct inode *ip; 48412115Sdyson struct buf *bp; 485202283Slulf struct ext2fs *es; 486202283Slulf struct m_ext2fs *fs; 487228539Spfg struct csum *sump; 488228539Spfg int error, i; 489228539Spfg int32_t *lp; 49012115Sdyson 491122114Sbde if ((mp->mnt_flag & MNT_RDONLY) == 0) 49212115Sdyson return (EINVAL); 49312115Sdyson /* 49412115Sdyson * Step 1: invalidate all cached meta-data. 49512115Sdyson */ 496122114Sbde devvp = VFSTOEXT2(mp)->um_devvp; 497175202Sattilio vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 498183754Sattilio if (vinvalbuf(devvp, 0, 0, 0) != 0) 49912115Sdyson panic("ext2_reload: dirty1"); 500175294Sattilio VOP_UNLOCK(devvp, 0); 501125786Sbde 50212115Sdyson /* 50312115Sdyson * Step 2: re-read superblock from disk. 50412115Sdyson * constants have been adjusted for ext2 50512115Sdyson */ 50643301Sdillon if ((error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) != 0) 50712115Sdyson return (error); 508202283Slulf es = (struct ext2fs *)bp->b_data; 50955313Sbde if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) { 51012115Sdyson brelse(bp); 51112115Sdyson return (EIO); /* XXX needs translation */ 51212115Sdyson } 513122114Sbde fs = VFSTOEXT2(mp)->um_e2fs; 514202283Slulf bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs)); 51512115Sdyson 516311231Spfg if ((error = compute_sb_data(devvp, es, fs)) != 0) { 51712115Sdyson brelse(bp); 518193382Sstas return (error); 51912115Sdyson } 52012115Sdyson#ifdef UNKLAR 52112115Sdyson if (fs->fs_sbsize < SBSIZE) 52212115Sdyson bp->b_flags |= B_INVAL; 52312115Sdyson#endif 52412115Sdyson brelse(bp); 52512115Sdyson 526228539Spfg /* 527228539Spfg * Step 3: invalidate all cluster summary information. 528228539Spfg */ 529228539Spfg if (fs->e2fs_contigsumsize > 0) { 530228539Spfg lp = fs->e2fs_maxcluster; 531228539Spfg sump = fs->e2fs_clustersum; 532228539Spfg for (i = 0; i < fs->e2fs_gcount; i++, sump++) { 533228539Spfg *lp++ = fs->e2fs_contigsumsize; 534228539Spfg sump->cs_init = 0; 535228539Spfg bzero(sump->cs_sum, fs->e2fs_contigsumsize + 1); 536228539Spfg } 537228539Spfg } 538228539Spfg 53912115Sdysonloop: 540234386Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 54112115Sdyson /* 542143509Sjeff * Step 4: invalidate all cached file data. 54312115Sdyson */ 54483366Sjulian if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 545234386Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 54612115Sdyson goto loop; 54739678Sbde } 548183754Sattilio if (vinvalbuf(vp, 0, 0, 0)) 54912115Sdyson panic("ext2_reload: dirty2"); 550193382Sstas 55112115Sdyson /* 552143509Sjeff * Step 5: re-read inode data for all active vnodes. 55312115Sdyson */ 55412115Sdyson ip = VTOI(vp); 555193382Sstas error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 556202283Slulf (int)fs->e2fs_bsize, NOCRED, &bp); 55739678Sbde if (error) { 558175294Sattilio VOP_UNLOCK(vp, 0); 559121925Skan vrele(vp); 560234386Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 56112115Sdyson return (error); 56212115Sdyson } 563311231Spfg ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data + 564187395Sstas EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)), ip); 56512115Sdyson brelse(bp); 566175294Sattilio VOP_UNLOCK(vp, 0); 567121925Skan vrele(vp); 56812115Sdyson } 56912115Sdyson return (0); 57012115Sdyson} 57112115Sdyson 57212115Sdyson/* 573193382Sstas * Common code for mount and mountroot. 57412115Sdyson */ 57512911Sphkstatic int 576193382Sstasext2_mountfs(struct vnode *devvp, struct mount *mp) 57712115Sdyson{ 57896752Siedowse struct ext2mount *ump; 57912115Sdyson struct buf *bp; 580202283Slulf struct m_ext2fs *fs; 581202283Slulf struct ext2fs *es; 582130585Sphk struct cdev *dev = devvp->v_rdev; 583137039Sphk struct g_consumer *cp; 584137039Sphk struct bufobj *bo; 585228539Spfg struct csum *sump; 58696749Siedowse int error; 58712115Sdyson int ronly; 588309455Spfg int i; 589309455Spfg u_long size; 590228539Spfg int32_t *lp; 591246563Spfg int32_t e2fs_maxcontig; 59212115Sdyson 593138493Sphk ronly = vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0); 594137039Sphk /* XXX: use VOP_ACESS to check FS perms */ 595137039Sphk g_topology_lock(); 596137039Sphk error = g_vfs_open(devvp, &cp, "ext2fs", ronly ? 0 : 1); 597137039Sphk g_topology_unlock(); 598175294Sattilio VOP_UNLOCK(devvp, 0); 59953059Sphk if (error) 60012115Sdyson return (error); 601149960Srodrigc 602149960Srodrigc /* XXX: should we check for some sectorsize or 512 instead? */ 603149960Srodrigc if (((SBSIZE % cp->provider->sectorsize) != 0) || 604149960Srodrigc (SBSIZE < cp->provider->sectorsize)) { 605149960Srodrigc g_topology_lock(); 606183754Sattilio g_vfs_close(cp); 607149960Srodrigc g_topology_unlock(); 608149960Srodrigc return (EINVAL); 609149960Srodrigc } 610149960Srodrigc 611137039Sphk bo = &devvp->v_bufobj; 612137039Sphk bo->bo_private = cp; 613137039Sphk bo->bo_ops = g_vfs_bufops; 61493430Sbde if (devvp->v_rdev->si_iosize_max != 0) 61593430Sbde mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; 61693430Sbde if (mp->mnt_iosize_max > MAXPHYS) 61793430Sbde mp->mnt_iosize_max = MAXPHYS; 61893430Sbde 61912115Sdyson bp = NULL; 62012115Sdyson ump = NULL; 62143301Sdillon if ((error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) != 0) 62212115Sdyson goto out; 623202283Slulf es = (struct ext2fs *)bp->b_data; 62455313Sbde if (ext2_check_sb_compat(es, dev, ronly) != 0) { 62512115Sdyson error = EINVAL; /* XXX needs translation */ 62612115Sdyson goto out; 62712115Sdyson } 628202283Slulf if ((es->e2fs_state & E2FS_ISCLEAN) == 0 || 629202283Slulf (es->e2fs_state & E2FS_ERRORS)) { 63039670Sbde if (ronly || (mp->mnt_flag & MNT_FORCE)) { 631193628Sstas printf( 632193628Sstas"WARNING: Filesystem was not properly dismounted\n"); 63339670Sbde } else { 634193628Sstas printf( 635193628Sstas"WARNING: R/W mount denied. Filesystem is not clean - run fsck\n"); 63639670Sbde error = EPERM; 63739670Sbde goto out; 63839670Sbde } 63939670Sbde } 640228583Spfg ump = malloc(sizeof(*ump), M_EXT2MNT, M_WAITOK | M_ZERO); 641193382Sstas 642193382Sstas /* 643193382Sstas * I don't know whether this is the right strategy. Note that 644297695Skevlo * we dynamically allocate both an m_ext2fs and an ext2fs 645193382Sstas * while Linux keeps the super block in a locked buffer. 64612115Sdyson */ 647202283Slulf ump->um_e2fs = malloc(sizeof(struct m_ext2fs), 648311231Spfg M_EXT2MNT, M_WAITOK | M_ZERO); 649202283Slulf ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs), 650311231Spfg M_EXT2MNT, M_WAITOK); 651202283Slulf mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF); 652202283Slulf bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs)); 653202283Slulf if ((error = compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs))) 65439671Sbde goto out; 655193382Sstas 656228539Spfg /* 657228539Spfg * Calculate the maximum contiguous blocks and size of cluster summary 658311231Spfg * array. In FFS this is done by newfs; however, the superblock 659311231Spfg * in ext2fs doesn't have these variables, so we can calculate 660228539Spfg * them here. 661228539Spfg */ 662246563Spfg e2fs_maxcontig = MAX(1, MAXPHYS / ump->um_e2fs->e2fs_bsize); 663246563Spfg ump->um_e2fs->e2fs_contigsumsize = MIN(e2fs_maxcontig, EXT2_MAXCONTIG); 664228539Spfg if (ump->um_e2fs->e2fs_contigsumsize > 0) { 665228539Spfg size = ump->um_e2fs->e2fs_gcount * sizeof(int32_t); 666228539Spfg ump->um_e2fs->e2fs_maxcluster = malloc(size, M_EXT2MNT, M_WAITOK); 667228539Spfg size = ump->um_e2fs->e2fs_gcount * sizeof(struct csum); 668228539Spfg ump->um_e2fs->e2fs_clustersum = malloc(size, M_EXT2MNT, M_WAITOK); 669228539Spfg lp = ump->um_e2fs->e2fs_maxcluster; 670228539Spfg sump = ump->um_e2fs->e2fs_clustersum; 671228539Spfg for (i = 0; i < ump->um_e2fs->e2fs_gcount; i++, sump++) { 672228539Spfg *lp++ = ump->um_e2fs->e2fs_contigsumsize; 673228539Spfg sump->cs_init = 0; 674228539Spfg sump->cs_sum = malloc((ump->um_e2fs->e2fs_contigsumsize + 1) * 675228539Spfg sizeof(int32_t), M_EXT2MNT, M_WAITOK | M_ZERO); 676228539Spfg } 677228539Spfg } 678228539Spfg 67912115Sdyson brelse(bp); 68012115Sdyson bp = NULL; 68112115Sdyson fs = ump->um_e2fs; 682202283Slulf fs->e2fs_ronly = ronly; /* ronly is set according to mnt_flags */ 683193382Sstas 684193382Sstas /* 685193382Sstas * If the fs is not mounted read-only, make sure the super block is 686193382Sstas * always written back on a sync(). 68712115Sdyson */ 688202283Slulf fs->e2fs_wasvalid = fs->e2fs->e2fs_state & E2FS_ISCLEAN ? 1 : 0; 68912115Sdyson if (ronly == 0) { 690311231Spfg fs->e2fs_fmod = 1; /* mark it modified */ 691202283Slulf fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN; /* set fs invalid */ 69212115Sdyson } 693172697Salfred mp->mnt_data = ump; 69450256Sbde mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 69538909Sbde mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 69612115Sdyson mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN; 697162647Stegge MNT_ILOCK(mp); 69812115Sdyson mp->mnt_flag |= MNT_LOCAL; 699162647Stegge MNT_IUNLOCK(mp); 70012115Sdyson ump->um_mountp = mp; 70112115Sdyson ump->um_dev = dev; 70212115Sdyson ump->um_devvp = devvp; 703137320Sphk ump->um_bo = &devvp->v_bufobj; 704137320Sphk ump->um_cp = cp; 705193382Sstas 706193382Sstas /* 707193382Sstas * Setting those two parameters allowed us to use 708193382Sstas * ufs_bmap w/o changse! 709193382Sstas */ 71012115Sdyson ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs); 711202283Slulf ump->um_bptrtodb = fs->e2fs->e2fs_log_bsize + 1; 71212115Sdyson ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs); 713187396Sstas if (ronly == 0) 71434430Seivind ext2_sbupdate(ump, MNT_WAIT); 715202283Slulf /* 716202283Slulf * Initialize filesystem stat information in mount struct. 717202283Slulf */ 718202283Slulf MNT_ILOCK(mp); 719281562Srmacklem mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED | 720281562Srmacklem MNTK_USES_BCACHE; 721202283Slulf MNT_IUNLOCK(mp); 72212115Sdyson return (0); 72312115Sdysonout: 72412115Sdyson if (bp) 72512115Sdyson brelse(bp); 726137039Sphk if (cp != NULL) { 727137039Sphk g_topology_lock(); 728183754Sattilio g_vfs_close(cp); 729137039Sphk g_topology_unlock(); 730137039Sphk } 73112115Sdyson if (ump) { 732262623Spfg mtx_destroy(EXT2_MTX(ump)); 733202283Slulf free(ump->um_e2fs->e2fs_gd, M_EXT2MNT); 734202283Slulf free(ump->um_e2fs->e2fs_contigdirs, M_EXT2MNT); 735202283Slulf free(ump->um_e2fs->e2fs, M_EXT2MNT); 736193382Sstas free(ump->um_e2fs, M_EXT2MNT); 737193382Sstas free(ump, M_EXT2MNT); 738172697Salfred mp->mnt_data = NULL; 73912115Sdyson } 74012115Sdyson return (error); 74112115Sdyson} 74212115Sdyson 74312115Sdyson/* 744193382Sstas * Unmount system call. 74512115Sdyson */ 74612911Sphkstatic int 747193382Sstasext2_unmount(struct mount *mp, int mntflags) 74812115Sdyson{ 74996752Siedowse struct ext2mount *ump; 750202283Slulf struct m_ext2fs *fs; 751228539Spfg struct csum *sump; 752228539Spfg int error, flags, i, ronly; 75312115Sdyson 75412115Sdyson flags = 0; 75512115Sdyson if (mntflags & MNT_FORCE) { 75612115Sdyson if (mp->mnt_flag & MNT_ROOTFS) 75712115Sdyson return (EINVAL); 75812115Sdyson flags |= FORCECLOSE; 75912115Sdyson } 760191990Sattilio if ((error = ext2_flushfiles(mp, flags, curthread)) != 0) 76112115Sdyson return (error); 76296749Siedowse ump = VFSTOEXT2(mp); 76312115Sdyson fs = ump->um_e2fs; 764202283Slulf ronly = fs->e2fs_ronly; 765202283Slulf if (ronly == 0 && ext2_cgupdate(ump, MNT_WAIT) == 0) { 766202283Slulf if (fs->e2fs_wasvalid) 767262623Spfg fs->e2fs->e2fs_state |= E2FS_ISCLEAN; 768262623Spfg ext2_sbupdate(ump, MNT_WAIT); 76912115Sdyson } 77027881Sdyson 771137039Sphk g_topology_lock(); 772183754Sattilio g_vfs_close(ump->um_cp); 773137039Sphk g_topology_unlock(); 77412115Sdyson vrele(ump->um_devvp); 775228539Spfg sump = fs->e2fs_clustersum; 776228539Spfg for (i = 0; i < fs->e2fs_gcount; i++, sump++) 777228539Spfg free(sump->cs_sum, M_EXT2MNT); 778228539Spfg free(fs->e2fs_clustersum, M_EXT2MNT); 779228539Spfg free(fs->e2fs_maxcluster, M_EXT2MNT); 780202283Slulf free(fs->e2fs_gd, M_EXT2MNT); 781202283Slulf free(fs->e2fs_contigdirs, M_EXT2MNT); 782202283Slulf free(fs->e2fs, M_EXT2MNT); 783193382Sstas free(fs, M_EXT2MNT); 784193382Sstas free(ump, M_EXT2MNT); 785172697Salfred mp->mnt_data = NULL; 786162647Stegge MNT_ILOCK(mp); 78712115Sdyson mp->mnt_flag &= ~MNT_LOCAL; 788162647Stegge MNT_IUNLOCK(mp); 78912115Sdyson return (error); 79012115Sdyson} 79112115Sdyson 79212115Sdyson/* 79312115Sdyson * Flush out all the files in a filesystem. 79412115Sdyson */ 79512911Sphkstatic int 796193382Sstasext2_flushfiles(struct mount *mp, int flags, struct thread *td) 79712115Sdyson{ 79812147Sdyson int error; 79912115Sdyson 800132023Salfred error = vflush(mp, 0, flags, td); 80112115Sdyson return (error); 80212115Sdyson} 803311231Spfg 80412115Sdyson/* 805251612Spfg * Get filesystem statistics. 80612115Sdyson */ 807202283Slulfint 808193382Sstasext2_statfs(struct mount *mp, struct statfs *sbp) 80912115Sdyson{ 81096752Siedowse struct ext2mount *ump; 811202283Slulf struct m_ext2fs *fs; 812202283Slulf uint32_t overhead, overhead_per_group, ngdb; 813202283Slulf int i, ngroups; 81412115Sdyson 81596749Siedowse ump = VFSTOEXT2(mp); 81612115Sdyson fs = ump->um_e2fs; 817202283Slulf if (fs->e2fs->e2fs_magic != E2FS_MAGIC) 818246258Spfg panic("ext2_statfs"); 81912115Sdyson 82012115Sdyson /* 82112115Sdyson * Compute the overhead (FS structures) 82212115Sdyson */ 823202283Slulf overhead_per_group = 824202283Slulf 1 /* block bitmap */ + 825202283Slulf 1 /* inode bitmap */ + 826202283Slulf fs->e2fs_itpg; 827202283Slulf overhead = fs->e2fs->e2fs_first_dblock + 828202283Slulf fs->e2fs_gcount * overhead_per_group; 829202283Slulf if (fs->e2fs->e2fs_rev > E2FS_REV0 && 830202283Slulf fs->e2fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) { 831202283Slulf for (i = 0, ngroups = 0; i < fs->e2fs_gcount; i++) { 832322712Spfg if (ext2_cg_has_sb(fs, i)) 833202283Slulf ngroups++; 834202283Slulf } 835202283Slulf } else { 836202283Slulf ngroups = fs->e2fs_gcount; 837202283Slulf } 838202283Slulf ngdb = fs->e2fs_gdbcount; 839202283Slulf if (fs->e2fs->e2fs_rev > E2FS_REV0 && 840202283Slulf fs->e2fs->e2fs_features_compat & EXT2F_COMPAT_RESIZE) 841202283Slulf ngdb += fs->e2fs->e2fs_reserved_ngdb; 842202283Slulf overhead += ngroups * (1 /* superblock */ + ngdb); 84312115Sdyson 844187396Sstas sbp->f_bsize = EXT2_FRAG_SIZE(fs); 84512115Sdyson sbp->f_iosize = EXT2_BLOCK_SIZE(fs); 846202283Slulf sbp->f_blocks = fs->e2fs->e2fs_bcount - overhead; 847202283Slulf sbp->f_bfree = fs->e2fs->e2fs_fbcount; 848202283Slulf sbp->f_bavail = sbp->f_bfree - fs->e2fs->e2fs_rbcount; 849202283Slulf sbp->f_files = fs->e2fs->e2fs_icount; 850202283Slulf sbp->f_ffree = fs->e2fs->e2fs_ficount; 85112115Sdyson return (0); 85212115Sdyson} 85312115Sdyson 85412115Sdyson/* 85512115Sdyson * Go through the disk queues to initiate sandbagged IO; 85612115Sdyson * go through the inodes to write those that have been modified; 85712115Sdyson * initiate the writing of the super block if it has been modified. 85812115Sdyson * 85912115Sdyson * Note: we are always called with the filesystem marked `MPBUSY'. 86012115Sdyson */ 86112911Sphkstatic int 862193382Sstasext2_sync(struct mount *mp, int waitfor) 86312115Sdyson{ 864154152Stegge struct vnode *mvp, *vp; 865191990Sattilio struct thread *td; 86639678Sbde struct inode *ip; 86796749Siedowse struct ext2mount *ump = VFSTOEXT2(mp); 868202283Slulf struct m_ext2fs *fs; 86912115Sdyson int error, allerror = 0; 87012115Sdyson 871191990Sattilio td = curthread; 87212115Sdyson fs = ump->um_e2fs; 873202283Slulf if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) { /* XXX */ 874202283Slulf printf("fs = %s\n", fs->e2fs_fsmnt); 87539678Sbde panic("ext2_sync: rofs mod"); 87612115Sdyson } 877193382Sstas 87812115Sdyson /* 87912115Sdyson * Write back each (modified) inode. 88012115Sdyson */ 88112115Sdysonloop: 882234386Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 883234386Smckusick if (vp->v_type == VNON) { 884120783Sjeff VI_UNLOCK(vp); 885120783Sjeff continue; 886120783Sjeff } 88712115Sdyson ip = VTOI(vp); 888137008Sphk if ((ip->i_flag & 88912115Sdyson (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && 890136943Sphk (vp->v_bufobj.bo_dirty.bv_cnt == 0 || 891137008Sphk waitfor == MNT_LAZY)) { 892103938Sjeff VI_UNLOCK(vp); 89312115Sdyson continue; 89439678Sbde } 89583366Sjulian error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td); 89639678Sbde if (error) { 897154152Stegge if (error == ENOENT) { 898234386Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 89939678Sbde goto loop; 900154152Stegge } 90139678Sbde continue; 90239678Sbde } 903140048Sphk if ((error = VOP_FSYNC(vp, waitfor, td)) != 0) 90412115Sdyson allerror = error; 905175294Sattilio VOP_UNLOCK(vp, 0); 906121874Skan vrele(vp); 90712115Sdyson } 908193382Sstas 90912115Sdyson /* 910251612Spfg * Force stale filesystem control information to be flushed. 91112115Sdyson */ 91239678Sbde if (waitfor != MNT_LAZY) { 913175202Sattilio vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); 914140048Sphk if ((error = VOP_FSYNC(ump->um_devvp, waitfor, td)) != 0) 91539678Sbde allerror = error; 916175294Sattilio VOP_UNLOCK(ump->um_devvp, 0); 91739678Sbde } 918193382Sstas 91939678Sbde /* 92039678Sbde * Write back modified superblock. 92139678Sbde */ 922202283Slulf if (fs->e2fs_fmod != 0) { 923202283Slulf fs->e2fs_fmod = 0; 924202283Slulf fs->e2fs->e2fs_wtime = time_second; 925202283Slulf if ((error = ext2_cgupdate(ump, waitfor)) != 0) 92639678Sbde allerror = error; 92739678Sbde } 92812115Sdyson return (allerror); 92912115Sdyson} 93012115Sdyson 93112115Sdyson/* 932108533Sschweikh * Look up an EXT2FS dinode number to find its incore vnode, otherwise read it 93312115Sdyson * in from disk. If it is in core, wait for the lock bit to clear, then 93412115Sdyson * return the inode locked. Detection and handling of mount points must be 93512115Sdyson * done by the calling routine. 93612115Sdyson */ 93712911Sphkstatic int 938193382Sstasext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) 93912115Sdyson{ 940202283Slulf struct m_ext2fs *fs; 94196752Siedowse struct inode *ip; 94296749Siedowse struct ext2mount *ump; 94312115Sdyson struct buf *bp; 94412115Sdyson struct vnode *vp; 945193382Sstas struct thread *td; 946346189Spfg unsigned int i, used_blocks; 947346189Spfg int error; 94812115Sdyson 949167497Stegge td = curthread; 950167497Stegge error = vfs_hash_get(mp, ino, flags, td, vpp, NULL, NULL); 951143619Sphk if (error || *vpp != NULL) 95292462Smckusick return (error); 95312115Sdyson 954143578Sphk ump = VFSTOEXT2(mp); 955143578Sphk ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); 95636102Sbde 95712115Sdyson /* Allocate a new vnode/inode. */ 958138290Sphk if ((error = getnewvnode("ext2fs", mp, &ext2_vnodeops, &vp)) != 0) { 95912115Sdyson *vpp = NULL; 960143578Sphk free(ip, M_EXT2NODE); 96112115Sdyson return (error); 96212115Sdyson } 96312115Sdyson vp->v_data = ip; 96412115Sdyson ip->i_vnode = vp; 96512115Sdyson ip->i_e2fs = fs = ump->um_e2fs; 966311231Spfg ip->i_ump = ump; 96712115Sdyson ip->i_number = ino; 968143578Sphk 969175635Sattilio lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); 970167497Stegge error = insmntque(vp, mp); 971167497Stegge if (error != 0) { 972167497Stegge free(ip, M_EXT2NODE); 973167497Stegge *vpp = NULL; 974167497Stegge return (error); 975167497Stegge } 976167497Stegge error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL); 977143663Sphk if (error || *vpp != NULL) 978143578Sphk return (error); 97912406Sdyson 98012115Sdyson /* Read in the disk contents for the inode, copy into the inode. */ 98143301Sdillon if ((error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 982202283Slulf (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 98312115Sdyson /* 98412115Sdyson * The inode does not contain anything useful, so it would 98512115Sdyson * be misleading to leave it on its hash chain. With mode 98612115Sdyson * still zero, it will be unlinked and returned to the free 98712115Sdyson * list by vput(). 98812115Sdyson */ 989202283Slulf brelse(bp); 99012115Sdyson vput(vp); 99112115Sdyson *vpp = NULL; 99212115Sdyson return (error); 99312115Sdyson } 99412115Sdyson /* convert ext2 inode to dinode */ 995311231Spfg ext2_ei2i((struct ext2fs_dinode *)((char *)bp->b_data + EXT2_INODE_SIZE(fs) * 996311231Spfg ino_to_fsbo(fs, ino)), ip); 99712115Sdyson ip->i_block_group = ino_to_cg(fs, ino); 99812115Sdyson ip->i_next_alloc_block = 0; 99912115Sdyson ip->i_next_alloc_goal = 0; 1000193382Sstas 1001193382Sstas /* 1002193382Sstas * Now we want to make sure that block pointers for unused 1003193382Sstas * blocks are zeroed out - ext2_balloc depends on this 1004193382Sstas * although for regular files and directories only 1005254260Spfg * 1006261235Spfg * If IN_E4EXTENTS is enabled, unused blocks are not zeroed 1007260988Spfg * out because we could corrupt the extent tree. 1008193382Sstas */ 1009261235Spfg if (!(ip->i_flag & IN_E4EXTENTS) && 1010254260Spfg (S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode))) { 1011298609Spfg used_blocks = howmany(ip->i_size, fs->e2fs_bsize); 1012228583Spfg for (i = used_blocks; i < EXT2_NDIR_BLOCKS; i++) 101312115Sdyson ip->i_db[i] = 0; 101412115Sdyson } 1015274437Spfg#ifdef EXT2FS_DEBUG 101612115Sdyson ext2_print_inode(ip); 1017274437Spfg#endif 1018202283Slulf bqrelse(bp); 101912115Sdyson 102012115Sdyson /* 102112115Sdyson * Initialize the vnode from the inode, check for aliases. 102212115Sdyson * Note that the underlying vnode may have changed. 102312115Sdyson */ 1024138290Sphk if ((error = ext2_vinit(mp, &ext2_fifoops, &vp)) != 0) { 102512115Sdyson vput(vp); 102612115Sdyson *vpp = NULL; 102712115Sdyson return (error); 102812115Sdyson } 1029193382Sstas 103012115Sdyson /* 1031217582Sjhb * Finish inode initialization. 103212115Sdyson */ 1033193382Sstas 103412115Sdyson *vpp = vp; 103512115Sdyson return (0); 103612115Sdyson} 103712115Sdyson 103812115Sdyson/* 103912115Sdyson * File handle to vnode 104012115Sdyson * 104112115Sdyson * Have to be really careful about stale file handles: 104212115Sdyson * - check that the inode number is valid 104312115Sdyson * - call ext2_vget() to get the locked inode 104412115Sdyson * - check for an unallocated inode (i_mode == 0) 104512115Sdyson * - check that the given client host has export rights and return 104612115Sdyson * those rights via. exflagsp and credanonp 104712115Sdyson */ 104812911Sphkstatic int 1049222167Srmacklemext2_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) 105012115Sdyson{ 105196749Siedowse struct inode *ip; 105296752Siedowse struct ufid *ufhp; 105396749Siedowse struct vnode *nvp; 1054202283Slulf struct m_ext2fs *fs; 105596749Siedowse int error; 105612115Sdyson 105712115Sdyson ufhp = (struct ufid *)fhp; 105896749Siedowse fs = VFSTOEXT2(mp)->um_e2fs; 1059221128Sjhb if (ufhp->ufid_ino < EXT2_ROOTINO || 1060202283Slulf ufhp->ufid_ino > fs->e2fs_gcount * fs->e2fs->e2fs_ipg) 106112115Sdyson return (ESTALE); 106296749Siedowse 106396749Siedowse error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp); 106496749Siedowse if (error) { 106596749Siedowse *vpp = NULLVP; 106696749Siedowse return (error); 106796749Siedowse } 106896749Siedowse ip = VTOI(nvp); 106996749Siedowse if (ip->i_mode == 0 || 107096749Siedowse ip->i_gen != ufhp->ufid_gen || ip->i_nlink <= 0) { 107196749Siedowse vput(nvp); 107296749Siedowse *vpp = NULLVP; 107396749Siedowse return (ESTALE); 107496749Siedowse } 107596749Siedowse *vpp = nvp; 1076140768Sphk vnode_create_vobject(*vpp, 0, curthread); 107796749Siedowse return (0); 107812115Sdyson} 107912115Sdyson 108012115Sdyson/* 108112115Sdyson * Write a superblock and associated information back to disk. 108212115Sdyson */ 108312911Sphkstatic int 1084193382Sstasext2_sbupdate(struct ext2mount *mp, int waitfor) 108512115Sdyson{ 1086202283Slulf struct m_ext2fs *fs = mp->um_e2fs; 1087202283Slulf struct ext2fs *es = fs->e2fs; 108896752Siedowse struct buf *bp; 108941591Sarchie int error = 0; 1090193382Sstas 1091111856Sjeff bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0, 0); 1092202283Slulf bcopy((caddr_t)es, bp->b_data, (u_int)sizeof(struct ext2fs)); 109312115Sdyson if (waitfor == MNT_WAIT) 109412115Sdyson error = bwrite(bp); 109512115Sdyson else 109612115Sdyson bawrite(bp); 109712115Sdyson 109827881Sdyson /* 109927881Sdyson * The buffers for group descriptors, inode bitmaps and block bitmaps 110027881Sdyson * are not busy at this point and are (hopefully) written by the 1101193382Sstas * usual sync mechanism. No need to write them here. 1102193382Sstas */ 110312115Sdyson return (error); 110412115Sdyson} 1105202283Slulfint 1106202283Slulfext2_cgupdate(struct ext2mount *mp, int waitfor) 1107202283Slulf{ 1108202283Slulf struct m_ext2fs *fs = mp->um_e2fs; 1109202283Slulf struct buf *bp; 1110202283Slulf int i, error = 0, allerror = 0; 111196749Siedowse 1112202283Slulf allerror = ext2_sbupdate(mp, waitfor); 1113322712Spfg 1114322712Spfg /* Update gd csums */ 1115322712Spfg if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_GDT_CSUM)) 1116322712Spfg ext2_gd_csum_set(fs); 1117322712Spfg 1118202283Slulf for (i = 0; i < fs->e2fs_gdbcount; i++) { 1119202283Slulf bp = getblk(mp->um_devvp, fsbtodb(fs, 1120202283Slulf fs->e2fs->e2fs_first_dblock + 1121202283Slulf 1 /* superblock */ + i), fs->e2fs_bsize, 0, 0, 0); 1122202283Slulf e2fs_cgsave(&fs->e2fs_gd[ 1123202283Slulf i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 1124202283Slulf (struct ext2_gd *)bp->b_data, fs->e2fs_bsize); 1125202283Slulf if (waitfor == MNT_WAIT) 1126202283Slulf error = bwrite(bp); 1127202283Slulf else 1128202283Slulf bawrite(bp); 1129202283Slulf } 1130202283Slulf 1131202283Slulf if (!allerror && error) 1132202283Slulf allerror = error; 1133202283Slulf return (allerror); 1134202283Slulf} 1135311231Spfg 113696749Siedowse/* 113796749Siedowse * Return the root of a filesystem. 113896749Siedowse */ 113996749Siedowsestatic int 1140193382Sstasext2_root(struct mount *mp, int flags, struct vnode **vpp) 114196749Siedowse{ 114296749Siedowse struct vnode *nvp; 114396749Siedowse int error; 114496749Siedowse 1145221128Sjhb error = VFS_VGET(mp, EXT2_ROOTINO, LK_EXCLUSIVE, &nvp); 114696749Siedowse if (error) 114796749Siedowse return (error); 114896749Siedowse *vpp = nvp; 114996749Siedowse return (0); 115096749Siedowse} 1151