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: releng/10.3/sys/fs/ext2fs/ext2_vfsops.c 293866 2016-01-14 01:50:06Z pfg $ 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); 144202283Slulf 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); 155202283Slulf 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 DROP_GIANT(); 162137039Sphk g_topology_lock(); 163137039Sphk g_access(ump->um_cp, 0, -1, 0); 164137039Sphk g_topology_unlock(); 165137039Sphk PICKUP_GIANT(); 16612115Sdyson } 16712115Sdyson if (!error && (mp->mnt_flag & MNT_RELOAD)) 168140736Sphk error = ext2_reload(mp, td); 16912115Sdyson if (error) 17012115Sdyson return (error); 17157839Sbde devvp = ump->um_devvp; 172202283Slulf if (fs->e2fs_ronly && !vfs_flagopt(opts, "ro", NULL, 0)) { 173202283Slulf if (ext2_check_sb_compat(fs->e2fs, devvp->v_rdev, 0)) 174138493Sphk return (EPERM); 175193382Sstas 17639028Sbde /* 17739028Sbde * If upgrade to read-write by non-root, then verify 17839028Sbde * that user has necessary permissions on the device. 17939028Sbde */ 180175202Sattilio vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 181164033Srwatson error = VOP_ACCESS(devvp, VREAD | VWRITE, 182164033Srwatson td->td_ucred, td); 183164033Srwatson if (error) 184164033Srwatson error = priv_check(td, PRIV_VFS_MOUNT_PERM); 185164033Srwatson if (error) { 186175294Sattilio VOP_UNLOCK(devvp, 0); 187164033Srwatson return (error); 18839028Sbde } 189175294Sattilio VOP_UNLOCK(devvp, 0); 190137039Sphk DROP_GIANT(); 191137039Sphk g_topology_lock(); 192137039Sphk error = g_access(ump->um_cp, 0, 1, 0); 193137039Sphk g_topology_unlock(); 194137039Sphk PICKUP_GIANT(); 195137039Sphk if (error) 196137039Sphk return (error); 19739028Sbde 198202283Slulf if ((fs->e2fs->e2fs_state & E2FS_ISCLEAN) == 0 || 199202283Slulf (fs->e2fs->e2fs_state & E2FS_ERRORS)) { 20039670Sbde if (mp->mnt_flag & MNT_FORCE) { 201193628Sstas printf( 202202283Slulf"WARNING: %s was not properly dismounted\n", fs->e2fs_fsmnt); 20339670Sbde } else { 204193628Sstas printf( 205193628Sstas"WARNING: R/W mount of %s denied. Filesystem is not clean - run fsck\n", 206202283Slulf fs->e2fs_fsmnt); 20739670Sbde return (EPERM); 20839670Sbde } 20939670Sbde } 210202283Slulf fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN; 211202283Slulf (void)ext2_cgupdate(ump, MNT_WAIT); 212202283Slulf fs->e2fs_ronly = 0; 213162647Stegge MNT_ILOCK(mp); 214138493Sphk mp->mnt_flag &= ~MNT_RDONLY; 215162647Stegge MNT_IUNLOCK(mp); 21612115Sdyson } 217158924Srodrigc if (vfs_flagopt(opts, "export", NULL, 0)) { 218158924Srodrigc /* Process export requests in vfs_mount.c. */ 219158924Srodrigc return (error); 22012115Sdyson } 22112115Sdyson } 222193382Sstas 22312115Sdyson /* 22412115Sdyson * Not an update, or updating the name: look up the name 225125786Sbde * and verify that it refers to a sensible disk device. 22612115Sdyson */ 22797255Smux if (fspec == NULL) 22897255Smux return (EINVAL); 229149720Sssouhlal NDINIT(ndp, LOOKUP, FOLLOW | LOCKLEAF, UIO_SYSSPACE, fspec, td); 23043301Sdillon if ((error = namei(ndp)) != 0) 23112115Sdyson return (error); 23254655Seivind NDFREE(ndp, NDF_ONLY_PNBUF); 23312115Sdyson devvp = ndp->ni_vp; 23412115Sdyson 23555756Sphk if (!vn_isdisk(devvp, &error)) { 236149720Sssouhlal vput(devvp); 23755756Sphk return (error); 23812115Sdyson } 23939028Sbde 24039028Sbde /* 24139028Sbde * If mount by non-root, then verify that user has necessary 24239028Sbde * permissions on the device. 243164033Srwatson * 244164033Srwatson * XXXRW: VOP_ACCESS() enough? 24539028Sbde */ 246184413Strasz accmode = VREAD; 247164033Srwatson if ((mp->mnt_flag & MNT_RDONLY) == 0) 248184413Strasz accmode |= VWRITE; 249184413Strasz error = VOP_ACCESS(devvp, accmode, td->td_ucred, td); 250164033Srwatson if (error) 251164033Srwatson error = priv_check(td, PRIV_VFS_MOUNT_PERM); 252164033Srwatson if (error) { 253164033Srwatson vput(devvp); 254164033Srwatson return (error); 25539028Sbde } 25639028Sbde 25729888Skato if ((mp->mnt_flag & MNT_UPDATE) == 0) { 258183754Sattilio error = ext2_mountfs(devvp, mp); 25929888Skato } else { 260149771Sssouhlal if (devvp != ump->um_devvp) { 261149720Sssouhlal vput(devvp); 262149771Sssouhlal return (EINVAL); /* needs translation */ 263149771Sssouhlal } else 264149771Sssouhlal vput(devvp); 26512115Sdyson } 26612115Sdyson if (error) { 26712115Sdyson vrele(devvp); 26812115Sdyson return (error); 26912115Sdyson } 27096749Siedowse ump = VFSTOEXT2(mp); 27112115Sdyson fs = ump->um_e2fs; 272193382Sstas 27373286Sadrian /* 27473286Sadrian * Note that this strncpy() is ok because of a check at the start 27573286Sadrian * of ext2_mount(). 27673286Sadrian */ 277202283Slulf strncpy(fs->e2fs_fsmnt, path, MAXMNTLEN); 278202283Slulf fs->e2fs_fsmnt[MAXMNTLEN - 1] = '\0'; 279138493Sphk vfs_mountedfrom(mp, fspec); 28012115Sdyson return (0); 28112115Sdyson} 28212115Sdyson 283193382Sstasstatic int 284202283Slulfext2_check_sb_compat(struct ext2fs *es, struct cdev *dev, int ronly) 28512115Sdyson{ 28612115Sdyson 287202283Slulf if (es->e2fs_magic != E2FS_MAGIC) { 28855313Sbde printf("ext2fs: %s: wrong magic number %#x (expected %#x)\n", 289202283Slulf devtoname(dev), es->e2fs_magic, E2FS_MAGIC); 29055313Sbde return (1); 29155313Sbde } 292202283Slulf if (es->e2fs_rev > E2FS_REV0) { 293262563Spfg if (es->e2fs_features_incompat & ~(EXT2F_INCOMPAT_SUPP | 294262563Spfg EXT4F_RO_INCOMPAT_SUPP)) { 295193628Sstas printf( 296193628Sstas"WARNING: mount of %s denied due to unsupported optional features\n", 297193628Sstas devtoname(dev)); 29855313Sbde return (1); 29955313Sbde } 30055313Sbde if (!ronly && 301202283Slulf (es->e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP)) { 302193382Sstas printf("WARNING: R/W mount of %s denied due to " 303193382Sstas "unsupported optional features\n", devtoname(dev)); 30455313Sbde return (1); 30555313Sbde } 30655313Sbde } 30755313Sbde return (0); 30855313Sbde} 30955313Sbde 31012115Sdyson/* 311193382Sstas * This computes the fields of the ext2_sb_info structure from the 312193382Sstas * data in the ext2_super_block structure read in. 31312115Sdyson */ 314193382Sstasstatic int 315202283Slulfcompute_sb_data(struct vnode *devvp, struct ext2fs *es, 316202283Slulf struct m_ext2fs *fs) 31712115Sdyson{ 318193382Sstas int db_count, error; 319202283Slulf int i; 320193382Sstas int logic_sb_block = 1; /* XXX for now */ 321202283Slulf struct buf *bp; 322246258Spfg uint32_t e2fs_descpb; 32312115Sdyson 324202283Slulf fs->e2fs_bshift = EXT2_MIN_BLOCK_LOG_SIZE + es->e2fs_log_bsize; 325246564Spfg fs->e2fs_bsize = 1U << fs->e2fs_bshift; 326202283Slulf fs->e2fs_fsbtodb = es->e2fs_log_bsize + 1; 327202283Slulf fs->e2fs_qbmask = fs->e2fs_bsize - 1; 328202283Slulf fs->e2fs_fsize = EXT2_MIN_FRAG_SIZE << es->e2fs_log_fsize; 329202283Slulf if (fs->e2fs_fsize) 330202283Slulf fs->e2fs_fpb = fs->e2fs_bsize / fs->e2fs_fsize; 331202283Slulf fs->e2fs_bpg = es->e2fs_bpg; 332202283Slulf fs->e2fs_fpg = es->e2fs_fpg; 333202283Slulf fs->e2fs_ipg = es->e2fs_ipg; 334202283Slulf if (es->e2fs_rev == E2FS_REV0) { 335202283Slulf fs->e2fs_isize = E2FS_REV0_INODE_SIZE ; 336193382Sstas } else { 337202283Slulf fs->e2fs_isize = es->e2fs_inode_size; 33812115Sdyson 339193382Sstas /* 340193382Sstas * Simple sanity check for superblock inode size value. 341193382Sstas */ 342232703Spfg if (EXT2_INODE_SIZE(fs) < E2FS_REV0_INODE_SIZE || 343232703Spfg EXT2_INODE_SIZE(fs) > fs->e2fs_bsize || 344202283Slulf (fs->e2fs_isize & (fs->e2fs_isize - 1)) != 0) { 345232703Spfg printf("ext2fs: invalid inode size %d\n", 346202283Slulf fs->e2fs_isize); 347193382Sstas return (EIO); 348193382Sstas } 349193377Sstas } 350232703Spfg /* Check for extra isize in big inodes. */ 351244475Spfg if (EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_EXTRA_ISIZE) && 352232703Spfg EXT2_INODE_SIZE(fs) < sizeof(struct ext2fs_dinode)) { 353232703Spfg printf("ext2fs: no space for extra inode timestamps\n"); 354232703Spfg return (EINVAL); 355232703Spfg } 356232703Spfg 357202283Slulf fs->e2fs_ipb = fs->e2fs_bsize / EXT2_INODE_SIZE(fs); 358279133Spfg fs->e2fs_itpg = fs->e2fs_ipg / fs->e2fs_ipb; 359193382Sstas /* s_resuid / s_resgid ? */ 360202283Slulf fs->e2fs_gcount = (es->e2fs_bcount - es->e2fs_first_dblock + 361193382Sstas EXT2_BLOCKS_PER_GROUP(fs) - 1) / EXT2_BLOCKS_PER_GROUP(fs); 362246258Spfg e2fs_descpb = fs->e2fs_bsize / sizeof(struct ext2_gd); 363246258Spfg db_count = (fs->e2fs_gcount + e2fs_descpb - 1) / e2fs_descpb; 364202283Slulf fs->e2fs_gdbcount = db_count; 365202283Slulf fs->e2fs_gd = malloc(db_count * fs->e2fs_bsize, 366193382Sstas M_EXT2MNT, M_WAITOK); 367232703Spfg fs->e2fs_contigdirs = malloc(fs->e2fs_gcount * 368279133Spfg sizeof(*fs->e2fs_contigdirs), M_EXT2MNT, M_WAITOK | M_ZERO); 36912115Sdyson 370193382Sstas /* 371193382Sstas * Adjust logic_sb_block. 372193382Sstas * Godmar thinks: if the blocksize is greater than 1024, then 373193382Sstas * the superblock is logically part of block zero. 37412115Sdyson */ 375202283Slulf if(fs->e2fs_bsize > SBSIZE) 376193382Sstas logic_sb_block = 0; 377193382Sstas for (i = 0; i < db_count; i++) { 378202283Slulf error = bread(devvp , 379202283Slulf fsbtodb(fs, logic_sb_block + i + 1 ), 380202283Slulf fs->e2fs_bsize, NOCRED, &bp); 381202283Slulf if (error) { 382279133Spfg free(fs->e2fs_contigdirs, M_EXT2MNT); 383202283Slulf free(fs->e2fs_gd, M_EXT2MNT); 384202283Slulf brelse(bp); 385202283Slulf return (error); 386193382Sstas } 387202283Slulf e2fs_cgload((struct ext2_gd *)bp->b_data, 388202283Slulf &fs->e2fs_gd[ 389202283Slulf i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 390202283Slulf fs->e2fs_bsize); 391202283Slulf brelse(bp); 392202283Slulf bp = NULL; 39312115Sdyson } 394279133Spfg /* Initialization for the ext2 Orlov allocator variant. */ 395202283Slulf fs->e2fs_total_dir = 0; 396279133Spfg for (i = 0; i < fs->e2fs_gcount; i++) 397202283Slulf fs->e2fs_total_dir += fs->e2fs_gd[i].ext2bgd_ndirs; 398279133Spfg 399202283Slulf if (es->e2fs_rev == E2FS_REV0 || 400232703Spfg !EXT2_HAS_RO_COMPAT_FEATURE(fs, EXT2F_ROCOMPAT_LARGEFILE)) 401202283Slulf fs->e2fs_maxfilesize = 0x7fffffff; 402281841Spfg else 403281841Spfg fs->e2fs_maxfilesize = 0x7fffffffffffffff; 404193382Sstas return (0); 40512115Sdyson} 40612115Sdyson 40712115Sdyson/* 40812115Sdyson * Reload all incore data for a filesystem (used after running fsck on 40912115Sdyson * the root filesystem and finding things to fix). The filesystem must 41012115Sdyson * be mounted read-only. 41112115Sdyson * 41212115Sdyson * Things to do to update the mount: 41312115Sdyson * 1) invalidate all cached meta-data. 41412115Sdyson * 2) re-read superblock from disk. 415228539Spfg * 3) invalidate all cluster summary information. 41612115Sdyson * 4) invalidate all inactive vnodes. 41712115Sdyson * 5) invalidate all cached file data. 41812115Sdyson * 6) re-read inode data for all active vnodes. 419202283Slulf * XXX we are missing some steps, in particular # 3, this has to be reviewed. 42012115Sdyson */ 42112911Sphkstatic int 422140736Sphkext2_reload(struct mount *mp, struct thread *td) 42312115Sdyson{ 424154152Stegge struct vnode *vp, *mvp, *devvp; 42512115Sdyson struct inode *ip; 42612115Sdyson struct buf *bp; 427202283Slulf struct ext2fs *es; 428202283Slulf struct m_ext2fs *fs; 429228539Spfg struct csum *sump; 430228539Spfg int error, i; 431228539Spfg int32_t *lp; 43212115Sdyson 433122114Sbde if ((mp->mnt_flag & MNT_RDONLY) == 0) 43412115Sdyson return (EINVAL); 43512115Sdyson /* 43612115Sdyson * Step 1: invalidate all cached meta-data. 43712115Sdyson */ 438122114Sbde devvp = VFSTOEXT2(mp)->um_devvp; 439175202Sattilio vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); 440183754Sattilio if (vinvalbuf(devvp, 0, 0, 0) != 0) 44112115Sdyson panic("ext2_reload: dirty1"); 442175294Sattilio VOP_UNLOCK(devvp, 0); 443125786Sbde 44412115Sdyson /* 44512115Sdyson * Step 2: re-read superblock from disk. 44612115Sdyson * constants have been adjusted for ext2 44712115Sdyson */ 44843301Sdillon if ((error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) != 0) 44912115Sdyson return (error); 450202283Slulf es = (struct ext2fs *)bp->b_data; 45155313Sbde if (ext2_check_sb_compat(es, devvp->v_rdev, 0) != 0) { 45212115Sdyson brelse(bp); 45312115Sdyson return (EIO); /* XXX needs translation */ 45412115Sdyson } 455122114Sbde fs = VFSTOEXT2(mp)->um_e2fs; 456202283Slulf bcopy(bp->b_data, fs->e2fs, sizeof(struct ext2fs)); 45712115Sdyson 45843301Sdillon if((error = compute_sb_data(devvp, es, fs)) != 0) { 45912115Sdyson brelse(bp); 460193382Sstas return (error); 46112115Sdyson } 46212115Sdyson#ifdef UNKLAR 46312115Sdyson if (fs->fs_sbsize < SBSIZE) 46412115Sdyson bp->b_flags |= B_INVAL; 46512115Sdyson#endif 46612115Sdyson brelse(bp); 46712115Sdyson 468228539Spfg /* 469228539Spfg * Step 3: invalidate all cluster summary information. 470228539Spfg */ 471228539Spfg if (fs->e2fs_contigsumsize > 0) { 472228539Spfg lp = fs->e2fs_maxcluster; 473228539Spfg sump = fs->e2fs_clustersum; 474228539Spfg for (i = 0; i < fs->e2fs_gcount; i++, sump++) { 475228539Spfg *lp++ = fs->e2fs_contigsumsize; 476228539Spfg sump->cs_init = 0; 477228539Spfg bzero(sump->cs_sum, fs->e2fs_contigsumsize + 1); 478228539Spfg } 479228539Spfg } 480228539Spfg 48112115Sdysonloop: 482234386Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 48312115Sdyson /* 484143509Sjeff * Step 4: invalidate all cached file data. 48512115Sdyson */ 48683366Sjulian if (vget(vp, LK_EXCLUSIVE | LK_INTERLOCK, td)) { 487234386Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 48812115Sdyson goto loop; 48939678Sbde } 490183754Sattilio if (vinvalbuf(vp, 0, 0, 0)) 49112115Sdyson panic("ext2_reload: dirty2"); 492193382Sstas 49312115Sdyson /* 494143509Sjeff * Step 5: re-read inode data for all active vnodes. 49512115Sdyson */ 49612115Sdyson ip = VTOI(vp); 497193382Sstas error = bread(devvp, fsbtodb(fs, ino_to_fsba(fs, ip->i_number)), 498202283Slulf (int)fs->e2fs_bsize, NOCRED, &bp); 49939678Sbde if (error) { 500175294Sattilio VOP_UNLOCK(vp, 0); 501121925Skan vrele(vp); 502234386Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 50312115Sdyson return (error); 50412115Sdyson } 505202283Slulf ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data + 506187395Sstas EXT2_INODE_SIZE(fs) * ino_to_fsbo(fs, ip->i_number)), ip); 50712115Sdyson brelse(bp); 508175294Sattilio VOP_UNLOCK(vp, 0); 509121925Skan vrele(vp); 51012115Sdyson } 51112115Sdyson return (0); 51212115Sdyson} 51312115Sdyson 51412115Sdyson/* 515193382Sstas * Common code for mount and mountroot. 51612115Sdyson */ 51712911Sphkstatic int 518193382Sstasext2_mountfs(struct vnode *devvp, struct mount *mp) 51912115Sdyson{ 52096752Siedowse struct ext2mount *ump; 52112115Sdyson struct buf *bp; 522202283Slulf struct m_ext2fs *fs; 523202283Slulf struct ext2fs *es; 524130585Sphk struct cdev *dev = devvp->v_rdev; 525137039Sphk struct g_consumer *cp; 526137039Sphk struct bufobj *bo; 527228539Spfg struct csum *sump; 52896749Siedowse int error; 52912115Sdyson int ronly; 530228539Spfg int i, size; 531228539Spfg int32_t *lp; 532246563Spfg int32_t e2fs_maxcontig; 53312115Sdyson 534138493Sphk ronly = vfs_flagopt(mp->mnt_optnew, "ro", NULL, 0); 535137039Sphk /* XXX: use VOP_ACESS to check FS perms */ 536137039Sphk DROP_GIANT(); 537137039Sphk g_topology_lock(); 538137039Sphk error = g_vfs_open(devvp, &cp, "ext2fs", ronly ? 0 : 1); 539137039Sphk g_topology_unlock(); 540137039Sphk PICKUP_GIANT(); 541175294Sattilio VOP_UNLOCK(devvp, 0); 54253059Sphk if (error) 54312115Sdyson return (error); 544149960Srodrigc 545149960Srodrigc /* XXX: should we check for some sectorsize or 512 instead? */ 546149960Srodrigc if (((SBSIZE % cp->provider->sectorsize) != 0) || 547149960Srodrigc (SBSIZE < cp->provider->sectorsize)) { 548149960Srodrigc DROP_GIANT(); 549149960Srodrigc g_topology_lock(); 550183754Sattilio g_vfs_close(cp); 551149960Srodrigc g_topology_unlock(); 552149960Srodrigc PICKUP_GIANT(); 553149960Srodrigc return (EINVAL); 554149960Srodrigc } 555149960Srodrigc 556137039Sphk bo = &devvp->v_bufobj; 557137039Sphk bo->bo_private = cp; 558137039Sphk bo->bo_ops = g_vfs_bufops; 55993430Sbde if (devvp->v_rdev->si_iosize_max != 0) 56093430Sbde mp->mnt_iosize_max = devvp->v_rdev->si_iosize_max; 56193430Sbde if (mp->mnt_iosize_max > MAXPHYS) 56293430Sbde mp->mnt_iosize_max = MAXPHYS; 56393430Sbde 56412115Sdyson bp = NULL; 56512115Sdyson ump = NULL; 56643301Sdillon if ((error = bread(devvp, SBLOCK, SBSIZE, NOCRED, &bp)) != 0) 56712115Sdyson goto out; 568202283Slulf es = (struct ext2fs *)bp->b_data; 56955313Sbde if (ext2_check_sb_compat(es, dev, ronly) != 0) { 57012115Sdyson error = EINVAL; /* XXX needs translation */ 57112115Sdyson goto out; 57212115Sdyson } 573202283Slulf if ((es->e2fs_state & E2FS_ISCLEAN) == 0 || 574202283Slulf (es->e2fs_state & E2FS_ERRORS)) { 57539670Sbde if (ronly || (mp->mnt_flag & MNT_FORCE)) { 576193628Sstas printf( 577193628Sstas"WARNING: Filesystem was not properly dismounted\n"); 57839670Sbde } else { 579193628Sstas printf( 580193628Sstas"WARNING: R/W mount denied. Filesystem is not clean - run fsck\n"); 58139670Sbde error = EPERM; 58239670Sbde goto out; 58339670Sbde } 58439670Sbde } 585228583Spfg ump = malloc(sizeof(*ump), M_EXT2MNT, M_WAITOK | M_ZERO); 586193382Sstas 587193382Sstas /* 588193382Sstas * I don't know whether this is the right strategy. Note that 589193382Sstas * we dynamically allocate both an ext2_sb_info and an ext2_super_block 590193382Sstas * while Linux keeps the super block in a locked buffer. 59112115Sdyson */ 592202283Slulf ump->um_e2fs = malloc(sizeof(struct m_ext2fs), 593293866Spfg M_EXT2MNT, M_WAITOK | M_ZERO); 594202283Slulf ump->um_e2fs->e2fs = malloc(sizeof(struct ext2fs), 595111119Simp M_EXT2MNT, M_WAITOK); 596202283Slulf mtx_init(EXT2_MTX(ump), "EXT2FS", "EXT2FS Lock", MTX_DEF); 597202283Slulf bcopy(es, ump->um_e2fs->e2fs, (u_int)sizeof(struct ext2fs)); 598202283Slulf if ((error = compute_sb_data(devvp, ump->um_e2fs->e2fs, ump->um_e2fs))) 59939671Sbde goto out; 600193382Sstas 601228539Spfg /* 602228539Spfg * Calculate the maximum contiguous blocks and size of cluster summary 603228583Spfg * array. In FFS this is done by newfs; however, the superblock 604228583Spfg * in ext2fs doesn't have these variables, so we can calculate 605228539Spfg * them here. 606228539Spfg */ 607246563Spfg e2fs_maxcontig = MAX(1, MAXPHYS / ump->um_e2fs->e2fs_bsize); 608246563Spfg ump->um_e2fs->e2fs_contigsumsize = MIN(e2fs_maxcontig, EXT2_MAXCONTIG); 609228539Spfg if (ump->um_e2fs->e2fs_contigsumsize > 0) { 610228539Spfg size = ump->um_e2fs->e2fs_gcount * sizeof(int32_t); 611228539Spfg ump->um_e2fs->e2fs_maxcluster = malloc(size, M_EXT2MNT, M_WAITOK); 612228539Spfg size = ump->um_e2fs->e2fs_gcount * sizeof(struct csum); 613228539Spfg ump->um_e2fs->e2fs_clustersum = malloc(size, M_EXT2MNT, M_WAITOK); 614228539Spfg lp = ump->um_e2fs->e2fs_maxcluster; 615228539Spfg sump = ump->um_e2fs->e2fs_clustersum; 616228539Spfg for (i = 0; i < ump->um_e2fs->e2fs_gcount; i++, sump++) { 617228539Spfg *lp++ = ump->um_e2fs->e2fs_contigsumsize; 618228539Spfg sump->cs_init = 0; 619228539Spfg sump->cs_sum = malloc((ump->um_e2fs->e2fs_contigsumsize + 1) * 620228539Spfg sizeof(int32_t), M_EXT2MNT, M_WAITOK | M_ZERO); 621228539Spfg } 622228539Spfg } 623228539Spfg 62412115Sdyson brelse(bp); 62512115Sdyson bp = NULL; 62612115Sdyson fs = ump->um_e2fs; 627202283Slulf fs->e2fs_ronly = ronly; /* ronly is set according to mnt_flags */ 628193382Sstas 629193382Sstas /* 630193382Sstas * If the fs is not mounted read-only, make sure the super block is 631193382Sstas * always written back on a sync(). 63212115Sdyson */ 633202283Slulf fs->e2fs_wasvalid = fs->e2fs->e2fs_state & E2FS_ISCLEAN ? 1 : 0; 63412115Sdyson if (ronly == 0) { 635202283Slulf fs->e2fs_fmod = 1; /* mark it modified */ 636202283Slulf fs->e2fs->e2fs_state &= ~E2FS_ISCLEAN; /* set fs invalid */ 63712115Sdyson } 638172697Salfred mp->mnt_data = ump; 63950256Sbde mp->mnt_stat.f_fsid.val[0] = dev2udev(dev); 64038909Sbde mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; 64112115Sdyson mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN; 642162647Stegge MNT_ILOCK(mp); 64312115Sdyson mp->mnt_flag |= MNT_LOCAL; 644162647Stegge MNT_IUNLOCK(mp); 64512115Sdyson ump->um_mountp = mp; 64612115Sdyson ump->um_dev = dev; 64712115Sdyson ump->um_devvp = devvp; 648137320Sphk ump->um_bo = &devvp->v_bufobj; 649137320Sphk ump->um_cp = cp; 650193382Sstas 651193382Sstas /* 652193382Sstas * Setting those two parameters allowed us to use 653193382Sstas * ufs_bmap w/o changse! 654193382Sstas */ 65512115Sdyson ump->um_nindir = EXT2_ADDR_PER_BLOCK(fs); 656202283Slulf ump->um_bptrtodb = fs->e2fs->e2fs_log_bsize + 1; 65712115Sdyson ump->um_seqinc = EXT2_FRAGS_PER_BLOCK(fs); 658187396Sstas if (ronly == 0) 65934430Seivind ext2_sbupdate(ump, MNT_WAIT); 660202283Slulf /* 661202283Slulf * Initialize filesystem stat information in mount struct. 662202283Slulf */ 663202283Slulf MNT_ILOCK(mp); 664282270Srmacklem mp->mnt_kern_flag |= MNTK_LOOKUP_SHARED | MNTK_EXTENDED_SHARED | 665282270Srmacklem MNTK_USES_BCACHE; 666202283Slulf MNT_IUNLOCK(mp); 66712115Sdyson return (0); 66812115Sdysonout: 66912115Sdyson if (bp) 67012115Sdyson brelse(bp); 671137039Sphk if (cp != NULL) { 672137039Sphk DROP_GIANT(); 673137039Sphk g_topology_lock(); 674183754Sattilio g_vfs_close(cp); 675137039Sphk g_topology_unlock(); 676137039Sphk PICKUP_GIANT(); 677137039Sphk } 67812115Sdyson if (ump) { 679262723Spfg mtx_destroy(EXT2_MTX(ump)); 680202283Slulf free(ump->um_e2fs->e2fs_gd, M_EXT2MNT); 681202283Slulf free(ump->um_e2fs->e2fs_contigdirs, M_EXT2MNT); 682202283Slulf free(ump->um_e2fs->e2fs, M_EXT2MNT); 683193382Sstas free(ump->um_e2fs, M_EXT2MNT); 684193382Sstas free(ump, M_EXT2MNT); 685172697Salfred mp->mnt_data = NULL; 68612115Sdyson } 68712115Sdyson return (error); 68812115Sdyson} 68912115Sdyson 69012115Sdyson/* 691193382Sstas * Unmount system call. 69212115Sdyson */ 69312911Sphkstatic int 694193382Sstasext2_unmount(struct mount *mp, int mntflags) 69512115Sdyson{ 69696752Siedowse struct ext2mount *ump; 697202283Slulf struct m_ext2fs *fs; 698228539Spfg struct csum *sump; 699228539Spfg int error, flags, i, ronly; 70012115Sdyson 70112115Sdyson flags = 0; 70212115Sdyson if (mntflags & MNT_FORCE) { 70312115Sdyson if (mp->mnt_flag & MNT_ROOTFS) 70412115Sdyson return (EINVAL); 70512115Sdyson flags |= FORCECLOSE; 70612115Sdyson } 707191990Sattilio if ((error = ext2_flushfiles(mp, flags, curthread)) != 0) 70812115Sdyson return (error); 70996749Siedowse ump = VFSTOEXT2(mp); 71012115Sdyson fs = ump->um_e2fs; 711202283Slulf ronly = fs->e2fs_ronly; 712202283Slulf if (ronly == 0 && ext2_cgupdate(ump, MNT_WAIT) == 0) { 713202283Slulf if (fs->e2fs_wasvalid) 714262723Spfg fs->e2fs->e2fs_state |= E2FS_ISCLEAN; 715262723Spfg ext2_sbupdate(ump, MNT_WAIT); 71612115Sdyson } 71727881Sdyson 718137039Sphk DROP_GIANT(); 719137039Sphk g_topology_lock(); 720183754Sattilio g_vfs_close(ump->um_cp); 721137039Sphk g_topology_unlock(); 722137039Sphk PICKUP_GIANT(); 72312115Sdyson vrele(ump->um_devvp); 724228539Spfg sump = fs->e2fs_clustersum; 725228539Spfg for (i = 0; i < fs->e2fs_gcount; i++, sump++) 726228539Spfg free(sump->cs_sum, M_EXT2MNT); 727228539Spfg free(fs->e2fs_clustersum, M_EXT2MNT); 728228539Spfg free(fs->e2fs_maxcluster, M_EXT2MNT); 729202283Slulf free(fs->e2fs_gd, M_EXT2MNT); 730202283Slulf free(fs->e2fs_contigdirs, M_EXT2MNT); 731202283Slulf free(fs->e2fs, M_EXT2MNT); 732193382Sstas free(fs, M_EXT2MNT); 733193382Sstas free(ump, M_EXT2MNT); 734172697Salfred mp->mnt_data = NULL; 735162647Stegge MNT_ILOCK(mp); 73612115Sdyson mp->mnt_flag &= ~MNT_LOCAL; 737162647Stegge MNT_IUNLOCK(mp); 73812115Sdyson return (error); 73912115Sdyson} 74012115Sdyson 74112115Sdyson/* 74212115Sdyson * Flush out all the files in a filesystem. 74312115Sdyson */ 74412911Sphkstatic int 745193382Sstasext2_flushfiles(struct mount *mp, int flags, struct thread *td) 74612115Sdyson{ 74712147Sdyson int error; 74812115Sdyson 749132023Salfred error = vflush(mp, 0, flags, td); 75012115Sdyson return (error); 75112115Sdyson} 75212115Sdyson/* 753251612Spfg * Get filesystem statistics. 75412115Sdyson */ 755202283Slulfint 756193382Sstasext2_statfs(struct mount *mp, struct statfs *sbp) 75712115Sdyson{ 75896752Siedowse struct ext2mount *ump; 759202283Slulf struct m_ext2fs *fs; 760202283Slulf uint32_t overhead, overhead_per_group, ngdb; 761202283Slulf int i, ngroups; 76212115Sdyson 76396749Siedowse ump = VFSTOEXT2(mp); 76412115Sdyson fs = ump->um_e2fs; 765202283Slulf if (fs->e2fs->e2fs_magic != E2FS_MAGIC) 766246258Spfg panic("ext2_statfs"); 76712115Sdyson 76812115Sdyson /* 76912115Sdyson * Compute the overhead (FS structures) 77012115Sdyson */ 771202283Slulf overhead_per_group = 772202283Slulf 1 /* block bitmap */ + 773202283Slulf 1 /* inode bitmap */ + 774202283Slulf fs->e2fs_itpg; 775202283Slulf overhead = fs->e2fs->e2fs_first_dblock + 776202283Slulf fs->e2fs_gcount * overhead_per_group; 777202283Slulf if (fs->e2fs->e2fs_rev > E2FS_REV0 && 778202283Slulf fs->e2fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_SPARSESUPER) { 779202283Slulf for (i = 0, ngroups = 0; i < fs->e2fs_gcount; i++) { 780202283Slulf if (cg_has_sb(i)) 781202283Slulf ngroups++; 782202283Slulf } 783202283Slulf } else { 784202283Slulf ngroups = fs->e2fs_gcount; 785202283Slulf } 786202283Slulf ngdb = fs->e2fs_gdbcount; 787202283Slulf if (fs->e2fs->e2fs_rev > E2FS_REV0 && 788202283Slulf fs->e2fs->e2fs_features_compat & EXT2F_COMPAT_RESIZE) 789202283Slulf ngdb += fs->e2fs->e2fs_reserved_ngdb; 790202283Slulf overhead += ngroups * (1 /* superblock */ + ngdb); 79112115Sdyson 792187396Sstas sbp->f_bsize = EXT2_FRAG_SIZE(fs); 79312115Sdyson sbp->f_iosize = EXT2_BLOCK_SIZE(fs); 794202283Slulf sbp->f_blocks = fs->e2fs->e2fs_bcount - overhead; 795202283Slulf sbp->f_bfree = fs->e2fs->e2fs_fbcount; 796202283Slulf sbp->f_bavail = sbp->f_bfree - fs->e2fs->e2fs_rbcount; 797202283Slulf sbp->f_files = fs->e2fs->e2fs_icount; 798202283Slulf sbp->f_ffree = fs->e2fs->e2fs_ficount; 79912115Sdyson return (0); 80012115Sdyson} 80112115Sdyson 80212115Sdyson/* 80312115Sdyson * Go through the disk queues to initiate sandbagged IO; 80412115Sdyson * go through the inodes to write those that have been modified; 80512115Sdyson * initiate the writing of the super block if it has been modified. 80612115Sdyson * 80712115Sdyson * Note: we are always called with the filesystem marked `MPBUSY'. 80812115Sdyson */ 80912911Sphkstatic int 810193382Sstasext2_sync(struct mount *mp, int waitfor) 81112115Sdyson{ 812154152Stegge struct vnode *mvp, *vp; 813191990Sattilio struct thread *td; 81439678Sbde struct inode *ip; 81596749Siedowse struct ext2mount *ump = VFSTOEXT2(mp); 816202283Slulf struct m_ext2fs *fs; 81712115Sdyson int error, allerror = 0; 81812115Sdyson 819191990Sattilio td = curthread; 82012115Sdyson fs = ump->um_e2fs; 821202283Slulf if (fs->e2fs_fmod != 0 && fs->e2fs_ronly != 0) { /* XXX */ 822202283Slulf printf("fs = %s\n", fs->e2fs_fsmnt); 82339678Sbde panic("ext2_sync: rofs mod"); 82412115Sdyson } 825193382Sstas 82612115Sdyson /* 82712115Sdyson * Write back each (modified) inode. 82812115Sdyson */ 82912115Sdysonloop: 830234386Smckusick MNT_VNODE_FOREACH_ALL(vp, mp, mvp) { 831234386Smckusick if (vp->v_type == VNON) { 832120783Sjeff VI_UNLOCK(vp); 833120783Sjeff continue; 834120783Sjeff } 83512115Sdyson ip = VTOI(vp); 836137008Sphk if ((ip->i_flag & 83712115Sdyson (IN_ACCESS | IN_CHANGE | IN_MODIFIED | IN_UPDATE)) == 0 && 838136943Sphk (vp->v_bufobj.bo_dirty.bv_cnt == 0 || 839137008Sphk waitfor == MNT_LAZY)) { 840103938Sjeff VI_UNLOCK(vp); 84112115Sdyson continue; 84239678Sbde } 84383366Sjulian error = vget(vp, LK_EXCLUSIVE | LK_NOWAIT | LK_INTERLOCK, td); 84439678Sbde if (error) { 845154152Stegge if (error == ENOENT) { 846234386Smckusick MNT_VNODE_FOREACH_ALL_ABORT(mp, mvp); 84739678Sbde goto loop; 848154152Stegge } 84939678Sbde continue; 85039678Sbde } 851140048Sphk if ((error = VOP_FSYNC(vp, waitfor, td)) != 0) 85212115Sdyson allerror = error; 853175294Sattilio VOP_UNLOCK(vp, 0); 854121874Skan vrele(vp); 85512115Sdyson } 856193382Sstas 85712115Sdyson /* 858251612Spfg * Force stale filesystem control information to be flushed. 85912115Sdyson */ 86039678Sbde if (waitfor != MNT_LAZY) { 861175202Sattilio vn_lock(ump->um_devvp, LK_EXCLUSIVE | LK_RETRY); 862140048Sphk if ((error = VOP_FSYNC(ump->um_devvp, waitfor, td)) != 0) 86339678Sbde allerror = error; 864175294Sattilio VOP_UNLOCK(ump->um_devvp, 0); 86539678Sbde } 866193382Sstas 86739678Sbde /* 86839678Sbde * Write back modified superblock. 86939678Sbde */ 870202283Slulf if (fs->e2fs_fmod != 0) { 871202283Slulf fs->e2fs_fmod = 0; 872202283Slulf fs->e2fs->e2fs_wtime = time_second; 873202283Slulf if ((error = ext2_cgupdate(ump, waitfor)) != 0) 87439678Sbde allerror = error; 87539678Sbde } 87612115Sdyson return (allerror); 87712115Sdyson} 87812115Sdyson 87912115Sdyson/* 880108533Sschweikh * Look up an EXT2FS dinode number to find its incore vnode, otherwise read it 88112115Sdyson * in from disk. If it is in core, wait for the lock bit to clear, then 88212115Sdyson * return the inode locked. Detection and handling of mount points must be 88312115Sdyson * done by the calling routine. 88412115Sdyson */ 88512911Sphkstatic int 886193382Sstasext2_vget(struct mount *mp, ino_t ino, int flags, struct vnode **vpp) 88712115Sdyson{ 888202283Slulf struct m_ext2fs *fs; 88996752Siedowse struct inode *ip; 89096749Siedowse struct ext2mount *ump; 89112115Sdyson struct buf *bp; 89212115Sdyson struct vnode *vp; 893193382Sstas struct thread *td; 89430280Sphk int i, error; 89512115Sdyson int used_blocks; 89612115Sdyson 897167497Stegge td = curthread; 898167497Stegge error = vfs_hash_get(mp, ino, flags, td, vpp, NULL, NULL); 899143619Sphk if (error || *vpp != NULL) 90092462Smckusick return (error); 90112115Sdyson 902143578Sphk ump = VFSTOEXT2(mp); 903143578Sphk ip = malloc(sizeof(struct inode), M_EXT2NODE, M_WAITOK | M_ZERO); 90436102Sbde 90512115Sdyson /* Allocate a new vnode/inode. */ 906138290Sphk if ((error = getnewvnode("ext2fs", mp, &ext2_vnodeops, &vp)) != 0) { 90712115Sdyson *vpp = NULL; 908143578Sphk free(ip, M_EXT2NODE); 90912115Sdyson return (error); 91012115Sdyson } 91112115Sdyson vp->v_data = ip; 91212115Sdyson ip->i_vnode = vp; 91312115Sdyson ip->i_e2fs = fs = ump->um_e2fs; 914202283Slulf ip->i_ump = ump; 91512115Sdyson ip->i_number = ino; 916143578Sphk 917175635Sattilio lockmgr(vp->v_vnlock, LK_EXCLUSIVE, NULL); 918167497Stegge error = insmntque(vp, mp); 919167497Stegge if (error != 0) { 920167497Stegge free(ip, M_EXT2NODE); 921167497Stegge *vpp = NULL; 922167497Stegge return (error); 923167497Stegge } 924167497Stegge error = vfs_hash_insert(vp, ino, flags, td, vpp, NULL, NULL); 925143663Sphk if (error || *vpp != NULL) 926143578Sphk return (error); 92712406Sdyson 92812115Sdyson /* Read in the disk contents for the inode, copy into the inode. */ 92943301Sdillon if ((error = bread(ump->um_devvp, fsbtodb(fs, ino_to_fsba(fs, ino)), 930202283Slulf (int)fs->e2fs_bsize, NOCRED, &bp)) != 0) { 93112115Sdyson /* 93212115Sdyson * The inode does not contain anything useful, so it would 93312115Sdyson * be misleading to leave it on its hash chain. With mode 93412115Sdyson * still zero, it will be unlinked and returned to the free 93512115Sdyson * list by vput(). 93612115Sdyson */ 937202283Slulf brelse(bp); 93812115Sdyson vput(vp); 93912115Sdyson *vpp = NULL; 94012115Sdyson return (error); 94112115Sdyson } 94212115Sdyson /* convert ext2 inode to dinode */ 943202283Slulf ext2_ei2i((struct ext2fs_dinode *) ((char *)bp->b_data + EXT2_INODE_SIZE(fs) * 94496749Siedowse ino_to_fsbo(fs, ino)), ip); 94512115Sdyson ip->i_block_group = ino_to_cg(fs, ino); 94612115Sdyson ip->i_next_alloc_block = 0; 94712115Sdyson ip->i_next_alloc_goal = 0; 948193382Sstas 949193382Sstas /* 950193382Sstas * Now we want to make sure that block pointers for unused 951193382Sstas * blocks are zeroed out - ext2_balloc depends on this 952193382Sstas * although for regular files and directories only 953254260Spfg * 954261311Spfg * If IN_E4EXTENTS is enabled, unused blocks are not zeroed 955261311Spfg * out because we could corrupt the extent tree. 956193382Sstas */ 957261311Spfg if (!(ip->i_flag & IN_E4EXTENTS) && 958254260Spfg (S_ISDIR(ip->i_mode) || S_ISREG(ip->i_mode))) { 959202283Slulf used_blocks = (ip->i_size+fs->e2fs_bsize-1) / fs->e2fs_bsize; 960228583Spfg for (i = used_blocks; i < EXT2_NDIR_BLOCKS; i++) 96112115Sdyson ip->i_db[i] = 0; 96212115Sdyson } 963276102Spfg#ifdef EXT2FS_DEBUG 96412115Sdyson ext2_print_inode(ip); 965276102Spfg#endif 966202283Slulf bqrelse(bp); 96712115Sdyson 96812115Sdyson /* 96912115Sdyson * Initialize the vnode from the inode, check for aliases. 97012115Sdyson * Note that the underlying vnode may have changed. 97112115Sdyson */ 972138290Sphk if ((error = ext2_vinit(mp, &ext2_fifoops, &vp)) != 0) { 97312115Sdyson vput(vp); 97412115Sdyson *vpp = NULL; 97512115Sdyson return (error); 97612115Sdyson } 977193382Sstas 97812115Sdyson /* 979217582Sjhb * Finish inode initialization. 98012115Sdyson */ 981193382Sstas 98212115Sdyson /* 98312115Sdyson * Set up a generation number for this inode if it does not 98412115Sdyson * already have one. This should only happen on old filesystems. 98512115Sdyson */ 98612115Sdyson if (ip->i_gen == 0) { 987252397Spfg ip->i_gen = random() + 1; 98812115Sdyson if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) 98912115Sdyson ip->i_flag |= IN_MODIFIED; 99012115Sdyson } 99112115Sdyson *vpp = vp; 99212115Sdyson return (0); 99312115Sdyson} 99412115Sdyson 99512115Sdyson/* 99612115Sdyson * File handle to vnode 99712115Sdyson * 99812115Sdyson * Have to be really careful about stale file handles: 99912115Sdyson * - check that the inode number is valid 100012115Sdyson * - call ext2_vget() to get the locked inode 100112115Sdyson * - check for an unallocated inode (i_mode == 0) 100212115Sdyson * - check that the given client host has export rights and return 100312115Sdyson * those rights via. exflagsp and credanonp 100412115Sdyson */ 100512911Sphkstatic int 1006222167Srmacklemext2_fhtovp(struct mount *mp, struct fid *fhp, int flags, struct vnode **vpp) 100712115Sdyson{ 100896749Siedowse struct inode *ip; 100996752Siedowse struct ufid *ufhp; 101096749Siedowse struct vnode *nvp; 1011202283Slulf struct m_ext2fs *fs; 101296749Siedowse int error; 101312115Sdyson 101412115Sdyson ufhp = (struct ufid *)fhp; 101596749Siedowse fs = VFSTOEXT2(mp)->um_e2fs; 1016221128Sjhb if (ufhp->ufid_ino < EXT2_ROOTINO || 1017202283Slulf ufhp->ufid_ino > fs->e2fs_gcount * fs->e2fs->e2fs_ipg) 101812115Sdyson return (ESTALE); 101996749Siedowse 102096749Siedowse error = VFS_VGET(mp, ufhp->ufid_ino, LK_EXCLUSIVE, &nvp); 102196749Siedowse if (error) { 102296749Siedowse *vpp = NULLVP; 102396749Siedowse return (error); 102496749Siedowse } 102596749Siedowse ip = VTOI(nvp); 102696749Siedowse if (ip->i_mode == 0 || 102796749Siedowse ip->i_gen != ufhp->ufid_gen || ip->i_nlink <= 0) { 102896749Siedowse vput(nvp); 102996749Siedowse *vpp = NULLVP; 103096749Siedowse return (ESTALE); 103196749Siedowse } 103296749Siedowse *vpp = nvp; 1033140768Sphk vnode_create_vobject(*vpp, 0, curthread); 103496749Siedowse return (0); 103512115Sdyson} 103612115Sdyson 103712115Sdyson/* 103812115Sdyson * Write a superblock and associated information back to disk. 103912115Sdyson */ 104012911Sphkstatic int 1041193382Sstasext2_sbupdate(struct ext2mount *mp, int waitfor) 104212115Sdyson{ 1043202283Slulf struct m_ext2fs *fs = mp->um_e2fs; 1044202283Slulf struct ext2fs *es = fs->e2fs; 104596752Siedowse struct buf *bp; 104641591Sarchie int error = 0; 1047193382Sstas 1048111856Sjeff bp = getblk(mp->um_devvp, SBLOCK, SBSIZE, 0, 0, 0); 1049202283Slulf bcopy((caddr_t)es, bp->b_data, (u_int)sizeof(struct ext2fs)); 105012115Sdyson if (waitfor == MNT_WAIT) 105112115Sdyson error = bwrite(bp); 105212115Sdyson else 105312115Sdyson bawrite(bp); 105412115Sdyson 105527881Sdyson /* 105627881Sdyson * The buffers for group descriptors, inode bitmaps and block bitmaps 105727881Sdyson * are not busy at this point and are (hopefully) written by the 1058193382Sstas * usual sync mechanism. No need to write them here. 1059193382Sstas */ 106012115Sdyson return (error); 106112115Sdyson} 1062202283Slulfint 1063202283Slulfext2_cgupdate(struct ext2mount *mp, int waitfor) 1064202283Slulf{ 1065202283Slulf struct m_ext2fs *fs = mp->um_e2fs; 1066202283Slulf struct buf *bp; 1067202283Slulf int i, error = 0, allerror = 0; 106896749Siedowse 1069202283Slulf allerror = ext2_sbupdate(mp, waitfor); 1070202283Slulf for (i = 0; i < fs->e2fs_gdbcount; i++) { 1071202283Slulf bp = getblk(mp->um_devvp, fsbtodb(fs, 1072202283Slulf fs->e2fs->e2fs_first_dblock + 1073202283Slulf 1 /* superblock */ + i), fs->e2fs_bsize, 0, 0, 0); 1074202283Slulf e2fs_cgsave(&fs->e2fs_gd[ 1075202283Slulf i * fs->e2fs_bsize / sizeof(struct ext2_gd)], 1076202283Slulf (struct ext2_gd *)bp->b_data, fs->e2fs_bsize); 1077202283Slulf if (waitfor == MNT_WAIT) 1078202283Slulf error = bwrite(bp); 1079202283Slulf else 1080202283Slulf bawrite(bp); 1081202283Slulf } 1082202283Slulf 1083202283Slulf if (!allerror && error) 1084202283Slulf allerror = error; 1085202283Slulf return (allerror); 1086202283Slulf} 108796749Siedowse/* 108896749Siedowse * Return the root of a filesystem. 108996749Siedowse */ 109096749Siedowsestatic int 1091193382Sstasext2_root(struct mount *mp, int flags, struct vnode **vpp) 109296749Siedowse{ 109396749Siedowse struct vnode *nvp; 109496749Siedowse int error; 109596749Siedowse 1096221128Sjhb error = VFS_VGET(mp, EXT2_ROOTINO, LK_EXCLUSIVE, &nvp); 109796749Siedowse if (error) 109896749Siedowse return (error); 109996749Siedowse *vpp = nvp; 110096749Siedowse return (0); 110196749Siedowse} 1102