int read_sblock(struct open_file *f, struct m_ext2fs *fs) { static uint8_t sbbuf[SBSIZE]; struct ext2fs ext2fs; size_t buf_size; int rc; rc = DEV_STRATEGY(f->f_dev)(f->f_devdata, F_READ, SBOFF / DEV_BSIZE, SBSIZE, sbbuf, &buf_size); if (rc) return rc; if (buf_size != SBSIZE) return EIO; e2fs_sbload((void *)sbbuf, &ext2fs); if (ext2fs.e2fs_magic != E2FS_MAGIC) return EINVAL; if (ext2fs.e2fs_rev > E2FS_REV1 || (ext2fs.e2fs_rev == E2FS_REV1 && (ext2fs.e2fs_first_ino != EXT2_FIRSTINO || (ext2fs.e2fs_inode_size != 128 && ext2fs.e2fs_inode_size != 256) || ext2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP))) { return ENODEV; } e2fs_sbload((void *)sbbuf, &fs->e2fs); /* compute in-memory m_ext2fs values */ fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, fs->e2fs.e2fs_bpg); /* XXX assume hw bsize = 512 */ fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize; fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; fs->e2fs_qbmask = fs->e2fs_bsize - 1; fs->e2fs_bmask = ~fs->e2fs_qbmask; fs->e2fs_ngdb = howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); fs->e2fs_ipb = fs->e2fs_bsize / ext2fs.e2fs_inode_size; fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb; return 0; }
/* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must * be mounted read-only. * * Things to do to update the mount: * 1) invalidate all cached meta-data. * 2) re-read superblock from disk. * 3) re-read summary information from disk. * 4) invalidate all inactive vnodes. * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. */ int ext2fs_reload(struct mount *mountp, struct ucred *cred, struct proc *p) { struct vnode *devvp; struct buf *bp; struct m_ext2fs *fs; struct ext2fs *newfs; int error; struct ext2fs_reload_args era; if ((mountp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); /* * Step 1: invalidate all cached meta-data. */ devvp = VFSTOUFS(mountp)->um_devvp; if (vinvalbuf(devvp, 0, cred, p, 0, 0)) panic("ext2fs_reload: dirty1"); /* * Step 2: re-read superblock from disk. */ error = bread(devvp, (daddr_t)(SBOFF / DEV_BSIZE), SBSIZE, &bp); if (error) { brelse(bp); return (error); } newfs = (struct ext2fs *)bp->b_data; error = e2fs_sbcheck(newfs, (mountp->mnt_flag & MNT_RDONLY)); if (error) { brelse(bp); return (error); } fs = VFSTOUFS(mountp)->um_e2fs; /* * Copy in the new superblock, compute in-memory values * and load group descriptors. */ e2fs_sbload(newfs, &fs->e2fs); if ((error = e2fs_sbfill(devvp, fs)) != 0) return (error); era.p = p; era.cred = cred; era.fs = fs; era.devvp = devvp; error = vfs_mount_foreach_vnode(mountp, ext2fs_reload_vnode, &era); return (error); }
/* * Common code for mount and mountroot */ int ext2fs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p) { struct ufsmount *ump; struct buf *bp; struct ext2fs *fs; struct m_ext2fs *m_fs; dev_t dev; int error, i, ronly; struct ucred *cred; dev = devvp->v_rdev; cred = p ? p->p_ucred : NOCRED; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp)) != 0) return (error); if (vcount(devvp) > 1 && devvp != rootvp) return (EBUSY); if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED); if (error) return (error); bp = NULL; ump = NULL; #ifdef DEBUG_EXT2 printf("ext2 sb size: %d\n", sizeof(struct ext2fs)); #endif error = bread(devvp, (daddr_t)(SBOFF / DEV_BSIZE), SBSIZE, &bp); if (error) goto out; fs = (struct ext2fs *)bp->b_data; error = ext2fs_checksb(fs, ronly); if (error) goto out; ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO); ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK | M_ZERO); e2fs_sbload((struct ext2fs*)bp->b_data, &ump->um_e2fs->e2fs); brelse(bp); bp = NULL; m_fs = ump->um_e2fs; m_fs->e2fs_ronly = ronly; ump->um_fstype = UM_EXT2FS; #ifdef DEBUG_EXT2 printf("ext2 ino size %d\n", EXT2_DINODE_SIZE(m_fs)); #endif if (ronly == 0) { if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) m_fs->e2fs.e2fs_state = 0; else m_fs->e2fs.e2fs_state = E2FS_ERRORS; m_fs->e2fs_fmod = 1; } /* compute dynamic sb infos */ m_fs->e2fs_ncg = howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock, m_fs->e2fs.e2fs_bpg); /* XXX assume hw bsize = 512 */ m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + 1; m_fs->e2fs_bsize = 1024 << m_fs->e2fs.e2fs_log_bsize; m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize; m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1; m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask; m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg, m_fs->e2fs_bsize / sizeof(struct ext2_gd)); m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE(m_fs); m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg/m_fs->e2fs_ipb; m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, M_UFSMNT, M_WAITOK); for (i=0; i < m_fs->e2fs_ngdb; i++) { error = bread(devvp , fsbtodb(m_fs, ((m_fs->e2fs_bsize>1024)? 0 : 1) + i + 1), m_fs->e2fs_bsize, &bp); if (error) { free(m_fs->e2fs_gd, M_UFSMNT); goto out; } e2fs_cgload((struct ext2_gd*)bp->b_data, &m_fs->e2fs_gd[i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], m_fs->e2fs_bsize); brelse(bp); bp = NULL; } mp->mnt_data = (qaddr_t)ump; mp->mnt_stat.f_fsid.val[0] = (long)dev; mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_maxsymlinklen = EXT2_MAXSYMLINKLEN; mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = NINDIR(m_fs); ump->um_bptrtodb = m_fs->e2fs_fsbtodb; ump->um_seqinc = 1; /* no frags */ devvp->v_specmountpoint = mp; return (0); out: if (bp) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred); VOP_UNLOCK(devvp, 0); if (ump) { free(ump->um_e2fs, M_UFSMNT); free(ump, M_UFSMNT); mp->mnt_data = (qaddr_t)0; } return (error); }
/* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must * be mounted read-only. * * Things to do to update the mount: * 1) invalidate all cached meta-data. * 2) re-read superblock from disk. * 3) re-read summary information from disk. * 4) invalidate all inactive vnodes. * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. */ int ext2fs_reload(struct mount *mountp, struct ucred *cred, struct proc *p) { struct vnode *devvp; struct buf *bp; struct m_ext2fs *fs; struct ext2fs *newfs; int i, error; struct ext2fs_reload_args era; if ((mountp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); /* * Step 1: invalidate all cached meta-data. */ devvp = VFSTOUFS(mountp)->um_devvp; if (vinvalbuf(devvp, 0, cred, p, 0, 0)) panic("ext2fs_reload: dirty1"); /* * Step 2: re-read superblock from disk. */ error = bread(devvp, (daddr_t)(SBOFF / DEV_BSIZE), SBSIZE, &bp); if (error) { brelse(bp); return (error); } newfs = (struct ext2fs *)bp->b_data; error = ext2fs_checksb(newfs, (mountp->mnt_flag & MNT_RDONLY) != 0); if (error) { brelse(bp); return (error); } fs = VFSTOUFS(mountp)->um_e2fs; /* * copy in new superblock, and compute in-memory values */ e2fs_sbload(newfs, &fs->e2fs); fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, fs->e2fs.e2fs_bpg); /* XXX assume hw bsize = 512 */ fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + 1; fs->e2fs_bsize = 1024 << fs->e2fs.e2fs_log_bsize; fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; fs->e2fs_qbmask = fs->e2fs_bsize - 1; fs->e2fs_bmask = ~fs->e2fs_qbmask; fs->e2fs_ngdb = howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE(fs); fs->e2fs_itpg = fs->e2fs.e2fs_ipg/fs->e2fs_ipb; /* * Step 3: re-read summary information from disk. */ for (i=0; i < fs->e2fs_ngdb; i++) { error = bread(devvp , fsbtodb(fs, ((fs->e2fs_bsize>1024)? 0 : 1) + i + 1), fs->e2fs_bsize, &bp); if (error) { brelse(bp); return (error); } e2fs_cgload((struct ext2_gd*)bp->b_data, &fs->e2fs_gd[i* fs->e2fs_bsize / sizeof(struct ext2_gd)], fs->e2fs_bsize); brelse(bp); } era.p = p; era.cred = cred; era.fs = fs; era.devvp = devvp; error = vfs_mount_foreach_vnode(mountp, ext2fs_reload_vnode, &era); return (error); }
/* * Read in the super block and its summary info, convert to host byte order. */ static int readsb(int listerr) { daddr_t super = bflag ? bflag : SBOFF / dev_bsize; if (bread(fsreadfd, (char *)sblk.b_un.b_fs, super, (long)SBSIZE) != 0) return 0; sblk.b_bno = super; sblk.b_size = SBSIZE; /* Copy the superblock in memory */ e2fs_sbload(sblk.b_un.b_fs, &sblock.e2fs); /* * run a few consistency checks of the super block */ if (sblock.e2fs.e2fs_magic != E2FS_MAGIC) { badsb(listerr, "MAGIC NUMBER WRONG"); return 0; } if (sblock.e2fs.e2fs_log_bsize > 2) { badsb(listerr, "BAD LOG_BSIZE"); return 0; } if (sblock.e2fs.e2fs_rev > E2FS_REV0 && (!powerof2(sblock.e2fs.e2fs_inode_size) || sblock.e2fs.e2fs_inode_size < EXT2_REV0_DINODE_SIZE || sblock.e2fs.e2fs_inode_size > (1024 << sblock.e2fs.e2fs_log_bsize))) { badsb(listerr, "BAD INODE_SIZE"); return 0; } /* compute the dynamic fields of the in-memory sb */ /* compute dynamic sb infos */ sblock.e2fs_ncg = howmany(sblock.e2fs.e2fs_bcount - sblock.e2fs.e2fs_first_dblock, sblock.e2fs.e2fs_bpg); /* XXX assume hw bsize = 512 */ sblock.e2fs_fsbtodb = sblock.e2fs.e2fs_log_bsize + 1; sblock.e2fs_bsize = 1024 << sblock.e2fs.e2fs_log_bsize; sblock.e2fs_bshift = LOG_MINBSIZE + sblock.e2fs.e2fs_log_bsize; sblock.e2fs_qbmask = sblock.e2fs_bsize - 1; sblock.e2fs_bmask = ~sblock.e2fs_qbmask; sblock.e2fs_ngdb = howmany(sblock.e2fs_ncg, sblock.e2fs_bsize / sizeof(struct ext2_gd)); sblock.e2fs_ipb = sblock.e2fs_bsize / EXT2_DINODE_SIZE(&sblock); sblock.e2fs_itpg = howmany(sblock.e2fs.e2fs_ipg, sblock.e2fs_ipb); /* * Compute block size that the filesystem is based on, * according to fsbtodb, and adjust superblock block number * so we can tell if this is an alternate later. */ super *= dev_bsize; dev_bsize = sblock.e2fs_bsize / EXT2_FSBTODB(&sblock, 1); sblk.b_bno = super / dev_bsize; if (sblock.e2fs_ncg == 1) { /* no alternate superblock; assume it's okay */ havesb = 1; return 1; } getblk(&asblk, 1 * sblock.e2fs.e2fs_bpg + sblock.e2fs.e2fs_first_dblock, (long)SBSIZE); if (asblk.b_errs) return 0; if (bflag) { havesb = 1; return 1; } /* * Set all possible fields that could differ, then do check * of whole super block against an alternate super block. * When an alternate super-block is specified this check is skipped. */ asblk.b_un.b_fs->e2fs_rbcount = sblk.b_un.b_fs->e2fs_rbcount; asblk.b_un.b_fs->e2fs_fbcount = sblk.b_un.b_fs->e2fs_fbcount; asblk.b_un.b_fs->e2fs_ficount = sblk.b_un.b_fs->e2fs_ficount; asblk.b_un.b_fs->e2fs_mtime = sblk.b_un.b_fs->e2fs_mtime; asblk.b_un.b_fs->e2fs_wtime = sblk.b_un.b_fs->e2fs_wtime; asblk.b_un.b_fs->e2fs_mnt_count = sblk.b_un.b_fs->e2fs_mnt_count; asblk.b_un.b_fs->e2fs_max_mnt_count = sblk.b_un.b_fs->e2fs_max_mnt_count; asblk.b_un.b_fs->e2fs_state = sblk.b_un.b_fs->e2fs_state; asblk.b_un.b_fs->e2fs_beh = sblk.b_un.b_fs->e2fs_beh; asblk.b_un.b_fs->e2fs_lastfsck = sblk.b_un.b_fs->e2fs_lastfsck; asblk.b_un.b_fs->e2fs_fsckintv = sblk.b_un.b_fs->e2fs_fsckintv; asblk.b_un.b_fs->e2fs_ruid = sblk.b_un.b_fs->e2fs_ruid; asblk.b_un.b_fs->e2fs_rgid = sblk.b_un.b_fs->e2fs_rgid; asblk.b_un.b_fs->e2fs_block_group_nr = sblk.b_un.b_fs->e2fs_block_group_nr; asblk.b_un.b_fs->e2fs_features_rocompat &= ~EXT2F_ROCOMPAT_LARGEFILE; asblk.b_un.b_fs->e2fs_features_rocompat |= sblk.b_un.b_fs->e2fs_features_rocompat & EXT2F_ROCOMPAT_LARGEFILE; if (sblock.e2fs.e2fs_rev > E2FS_REV0 && ((sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP_FSCK) || (sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP_FSCK))) { if (debug) { printf("compat 0x%08x, incompat 0x%08x, compat_ro " "0x%08x\n", sblock.e2fs.e2fs_features_compat, sblock.e2fs.e2fs_features_incompat, sblock.e2fs.e2fs_features_rocompat); if ((sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP_FSCK)) { char buf[512]; snprintb(buf, sizeof(buf), EXT2F_ROCOMPAT_BITS, sblock.e2fs.e2fs_features_rocompat & ~EXT2F_ROCOMPAT_SUPP_FSCK); printf("unsupported rocompat features: %s\n", buf); } if ((sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP_FSCK)) { char buf[512]; snprintb(buf, sizeof(buf), EXT2F_INCOMPAT_BITS, sblock.e2fs.e2fs_features_incompat & ~EXT2F_INCOMPAT_SUPP_FSCK); printf("unsupported incompat features: %s\n", buf); } } badsb(listerr, "INCOMPATIBLE FEATURE BITS IN SUPER BLOCK"); return 0; } if (memcmp(sblk.b_un.b_fs, asblk.b_un.b_fs, SBSIZE)) { if (debug) { u_int32_t *nlp, *olp, *endlp; printf("superblock mismatches\n"); nlp = (u_int32_t *)asblk.b_un.b_fs; olp = (u_int32_t *)sblk.b_un.b_fs; endlp = olp + (SBSIZE / sizeof(*olp)); for ( ; olp < endlp; olp++, nlp++) { if (*olp == *nlp) continue; printf("offset %ld, original %ld, " "alternate %ld\n", (long)(olp - (u_int32_t *)sblk.b_un.b_fs), (long)fs2h32(*olp), (long)fs2h32(*nlp)); } } badsb(listerr, "VALUES IN SUPER BLOCK DISAGREE WITH " "THOSE IN FIRST ALTERNATE"); return 0; } havesb = 1; return 1; }
/* * Common code for mount and mountroot */ int ext2fs_mountfs(struct vnode *devvp, struct mount *mp) { struct lwp *l = curlwp; struct ufsmount *ump; struct buf *bp; struct ext2fs *fs; struct m_ext2fs *m_fs; dev_t dev; int error, i, ronly; kauth_cred_t cred; dev = devvp->v_rdev; cred = l->l_cred; /* Flush out any old buffers remaining from a previous use. */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) return error; ronly = (mp->mnt_flag & MNT_RDONLY) != 0; bp = NULL; ump = NULL; /* Read the superblock from disk, and swap it directly. */ error = bread(devvp, SBLOCK, SBSIZE, 0, &bp); if (error) goto out; fs = (struct ext2fs *)bp->b_data; m_fs = kmem_zalloc(sizeof(struct m_ext2fs), KM_SLEEP); e2fs_sbload(fs, &m_fs->e2fs); brelse(bp, 0); bp = NULL; /* Once swapped, validate and fill in the superblock. */ error = ext2fs_sbfill(m_fs, ronly); if (error) { kmem_free(m_fs, sizeof(struct m_ext2fs)); goto out; } m_fs->e2fs_ronly = ronly; ump = kmem_zalloc(sizeof(*ump), KM_SLEEP); ump->um_fstype = UFS1; ump->um_ops = &ext2fs_ufsops; ump->um_e2fs = m_fs; if (ronly == 0) { if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) m_fs->e2fs.e2fs_state = 0; else m_fs->e2fs.e2fs_state = E2FS_ERRORS; m_fs->e2fs_fmod = 1; } /* XXX: should be added in ext2fs_sbfill()? */ m_fs->e2fs_gd = kmem_alloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, KM_SLEEP); for (i = 0; i < m_fs->e2fs_ngdb; i++) { error = bread(devvp, EXT2_FSBTODB(m_fs, m_fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), m_fs->e2fs_bsize, 0, &bp); if (error) { kmem_free(m_fs->e2fs_gd, m_fs->e2fs_ngdb * m_fs->e2fs_bsize); goto out; } e2fs_cgload((struct ext2_gd *)bp->b_data, &m_fs->e2fs_gd[ i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], m_fs->e2fs_bsize); brelse(bp, 0); bp = NULL; } error = ext2fs_cg_verify_and_initialize(devvp, m_fs, ronly); if (error) { kmem_free(m_fs->e2fs_gd, m_fs->e2fs_ngdb * m_fs->e2fs_bsize); goto out; } mp->mnt_data = ump; mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = EXT2FS_MAXNAMLEN; mp->mnt_flag |= MNT_LOCAL; mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */ mp->mnt_fs_bshift = m_fs->e2fs_bshift; mp->mnt_iflag |= IMNT_DTYPE; ump->um_flags = 0; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = EXT2_NINDIR(m_fs); ump->um_lognindir = ffs(EXT2_NINDIR(m_fs)) - 1; ump->um_bptrtodb = m_fs->e2fs_fsbtodb; ump->um_seqinc = 1; /* no frags */ ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN; ump->um_dirblksiz = m_fs->e2fs_bsize; ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1); spec_node_setmountedfs(devvp, mp); return 0; out: if (bp != NULL) brelse(bp, 0); if (ump) { kmem_free(ump->um_e2fs, sizeof(struct m_ext2fs)); kmem_free(ump, sizeof(*ump)); mp->mnt_data = NULL; } return error; }
/* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must * be mounted read-only. * * Things to do to update the mount: * 1) invalidate all cached meta-data. * 2) re-read superblock from disk. * 3) re-read summary information from disk. * 4) invalidate all inactive vnodes. * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. */ int ext2fs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l) { struct vnode *vp, *devvp; struct inode *ip; struct buf *bp; struct m_ext2fs *fs; struct ext2fs *newfs; int i, error; struct ufsmount *ump; struct vnode_iterator *marker; if ((mp->mnt_flag & MNT_RDONLY) == 0) return EINVAL; ump = VFSTOUFS(mp); /* * Step 1: invalidate all cached meta-data. */ devvp = ump->um_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, 0, cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) panic("ext2fs_reload: dirty1"); fs = ump->um_e2fs; /* * Step 2: re-read superblock from disk. Copy in new superblock, and compute * in-memory values. */ error = bread(devvp, SBLOCK, SBSIZE, 0, &bp); if (error) return error; newfs = (struct ext2fs *)bp->b_data; e2fs_sbload(newfs, &fs->e2fs); brelse(bp, 0); error = ext2fs_sbfill(fs, (mp->mnt_flag & MNT_RDONLY) != 0); if (error) return error; /* * Step 3: re-read summary information from disk. */ for (i = 0; i < fs->e2fs_ngdb; i++) { error = bread(devvp , EXT2_FSBTODB(fs, fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), fs->e2fs_bsize, 0, &bp); if (error) { return error; } e2fs_cgload((struct ext2_gd *)bp->b_data, &fs->e2fs_gd[i * fs->e2fs_bsize / sizeof(struct ext2_gd)], fs->e2fs_bsize); brelse(bp, 0); } vfs_vnode_iterator_init(mp, &marker); while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { /* * Step 4: invalidate all inactive vnodes. */ if (vrecycle(vp)) continue; /* * Step 5: invalidate all cached file data. */ if (vn_lock(vp, LK_EXCLUSIVE)) { vrele(vp); continue; } if (vinvalbuf(vp, 0, cred, l, 0, 0)) panic("ext2fs_reload: dirty2"); /* * Step 6: re-read inode data for all active vnodes. */ ip = VTOI(vp); error = bread(devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->e2fs_bsize, 0, &bp); if (error) { vput(vp); break; } error = ext2fs_loadvnode_content(fs, ip->i_number, bp, ip); brelse(bp, 0); if (error) { vput(vp); break; } vput(vp); } vfs_vnode_iterator_destroy(marker); return error; }
/* * Common code for mount and mountroot */ int ext2fs_mountfs(struct vnode *devvp, struct mount *mp) { struct lwp *l = curlwp; struct ufsmount *ump; struct buf *bp; struct ext2fs *fs; struct m_ext2fs *m_fs; dev_t dev; int error, i, ronly; kauth_cred_t cred; dev = devvp->v_rdev; cred = l ? l->l_cred : NOCRED; /* Flush out any old buffers remaining from a previous use. */ vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, V_SAVE, cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; bp = NULL; ump = NULL; #ifdef DEBUG_EXT2 printf("ext2 sb size: %zu\n", sizeof(struct ext2fs)); #endif error = bread(devvp, SBLOCK, SBSIZE, cred, 0, &bp); if (error) goto out; fs = (struct ext2fs *)bp->b_data; error = ext2fs_checksb(fs, ronly); if (error) goto out; ump = kmem_zalloc(sizeof(*ump), KM_SLEEP); ump->um_fstype = UFS1; ump->um_ops = &ext2fs_ufsops; ump->um_e2fs = kmem_zalloc(sizeof(struct m_ext2fs), KM_SLEEP); e2fs_sbload((struct ext2fs *)bp->b_data, &ump->um_e2fs->e2fs); brelse(bp, 0); bp = NULL; m_fs = ump->um_e2fs; m_fs->e2fs_ronly = ronly; #ifdef DEBUG_EXT2 printf("ext2 ino size %zu\n", EXT2_DINODE_SIZE(m_fs)); #endif if (ronly == 0) { if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) m_fs->e2fs.e2fs_state = 0; else m_fs->e2fs.e2fs_state = E2FS_ERRORS; m_fs->e2fs_fmod = 1; } /* compute dynamic sb infos */ m_fs->e2fs_ncg = howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock, m_fs->e2fs.e2fs_bpg); m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + LOG_MINBSIZE - DEV_BSHIFT; m_fs->e2fs_bsize = MINBSIZE << m_fs->e2fs.e2fs_log_bsize; m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize; m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1; m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask; m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg, m_fs->e2fs_bsize / sizeof(struct ext2_gd)); m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE(m_fs); m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg / m_fs->e2fs_ipb; m_fs->e2fs_gd = kmem_alloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, KM_SLEEP); for (i = 0; i < m_fs->e2fs_ngdb; i++) { error = bread(devvp , EXT2_FSBTODB(m_fs, m_fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), m_fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { kmem_free(m_fs->e2fs_gd, m_fs->e2fs_ngdb * m_fs->e2fs_bsize); goto out; } e2fs_cgload((struct ext2_gd *)bp->b_data, &m_fs->e2fs_gd[ i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], m_fs->e2fs_bsize); brelse(bp, 0); bp = NULL; } mp->mnt_data = ump; mp->mnt_stat.f_fsidx.__fsid_val[0] = (long)dev; mp->mnt_stat.f_fsidx.__fsid_val[1] = makefstype(MOUNT_EXT2FS); mp->mnt_stat.f_fsid = mp->mnt_stat.f_fsidx.__fsid_val[0]; mp->mnt_stat.f_namemax = EXT2FS_MAXNAMLEN; mp->mnt_flag |= MNT_LOCAL; mp->mnt_dev_bshift = DEV_BSHIFT; /* XXX */ mp->mnt_fs_bshift = m_fs->e2fs_bshift; mp->mnt_iflag |= IMNT_DTYPE; ump->um_flags = 0; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = EXT2_NINDIR(m_fs); ump->um_lognindir = ffs(EXT2_NINDIR(m_fs)) - 1; ump->um_bptrtodb = m_fs->e2fs_fsbtodb; ump->um_seqinc = 1; /* no frags */ ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN; ump->um_dirblksiz = m_fs->e2fs_bsize; ump->um_maxfilesize = ((uint64_t)0x80000000 * m_fs->e2fs_bsize - 1); spec_node_setmountedfs(devvp, mp); return (0); out: if (bp != NULL) brelse(bp, 0); if (ump) { kmem_free(ump->um_e2fs, sizeof(struct m_ext2fs)); kmem_free(ump, sizeof(*ump)); mp->mnt_data = NULL; } return (error); }
/* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must * be mounted read-only. * * Things to do to update the mount: * 1) invalidate all cached meta-data. * 2) re-read superblock from disk. * 3) re-read summary information from disk. * 4) invalidate all inactive vnodes. * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. */ int ext2fs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l) { struct vnode *vp, *mvp, *devvp; struct inode *ip; struct buf *bp; struct m_ext2fs *fs; struct ext2fs *newfs; int i, error; void *cp; struct ufsmount *ump; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); ump = VFSTOUFS(mp); /* * Step 1: invalidate all cached meta-data. */ devvp = ump->um_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, 0, cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) panic("ext2fs_reload: dirty1"); /* * Step 2: re-read superblock from disk. */ error = bread(devvp, SBLOCK, SBSIZE, NOCRED, 0, &bp); if (error) { return (error); } newfs = (struct ext2fs *)bp->b_data; error = ext2fs_checksb(newfs, (mp->mnt_flag & MNT_RDONLY) != 0); if (error) { brelse(bp, 0); return (error); } fs = ump->um_e2fs; /* * copy in new superblock, and compute in-memory values */ e2fs_sbload(newfs, &fs->e2fs); fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, fs->e2fs.e2fs_bpg); fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + LOG_MINBSIZE - DEV_BSHIFT; fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize; fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; fs->e2fs_qbmask = fs->e2fs_bsize - 1; fs->e2fs_bmask = ~fs->e2fs_qbmask; fs->e2fs_ngdb = howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE(fs); fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb; brelse(bp, 0); /* * Step 3: re-read summary information from disk. */ for (i = 0; i < fs->e2fs_ngdb; i++) { error = bread(devvp , EXT2_FSBTODB(fs, fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { return (error); } e2fs_cgload((struct ext2_gd *)bp->b_data, &fs->e2fs_gd[i * fs->e2fs_bsize / sizeof(struct ext2_gd)], fs->e2fs_bsize); brelse(bp, 0); } /* Allocate a marker vnode. */ mvp = vnalloc(mp); /* * NOTE: not using the TAILQ_FOREACH here since in this loop vgone() * and vclean() can be called indirectly */ mutex_enter(&mntvnode_lock); loop: for (vp = TAILQ_FIRST(&mp->mnt_vnodelist); vp; vp = vunmark(mvp)) { vmark(mvp, vp); if (vp->v_mount != mp || vismarker(vp)) continue; /* * Step 4: invalidate all inactive vnodes. */ if (vrecycle(vp, &mntvnode_lock)) { mutex_enter(&mntvnode_lock); (void)vunmark(mvp); goto loop; } /* * Step 5: invalidate all cached file data. */ mutex_enter(vp->v_interlock); mutex_exit(&mntvnode_lock); if (vget(vp, LK_EXCLUSIVE)) { mutex_enter(&mntvnode_lock); (void)vunmark(mvp); goto loop; } if (vinvalbuf(vp, 0, cred, l, 0, 0)) panic("ext2fs_reload: dirty2"); /* * Step 6: re-read inode data for all active vnodes. */ ip = VTOI(vp); error = bread(devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { vput(vp); mutex_enter(&mntvnode_lock); (void)vunmark(mvp); break; } cp = (char *)bp->b_data + (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE(fs)); e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din); ext2fs_set_inode_guid(ip); brelse(bp, 0); vput(vp); mutex_enter(&mntvnode_lock); } mutex_exit(&mntvnode_lock); vnfree(mvp); return (error); }
*/ int #define struct ext2fs_mountfs(struct vnode *devvp, struct mount *mp) #undef struct { struct buf *bp; struct ext2fs *fs; struct m_ext2fs *m_fs; int error, i, ronly; ronly = (mp->mnt_flag & MNT_RDONLY) != 0; DEBUG ((EFI_D_INFO, "mountrootf 3\n")); bp = NULL; error = bread(devvp, SBLOCK, SBSIZE, cred, 0, &bp); if (error) goto out; fs = (struct ext2fs *)bp->b_data; DEBUG ((EFI_D_INFO, "mountrootf 4\n")); error = ext2fs_checksb(fs, ronly); if (error) goto out; mp->fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK); memset(mp->fs, 0, sizeof(struct m_ext2fs)); DEBUG ((EFI_D_INFO, "mountrootf 5\n")); e2fs_sbload((struct ext2fs *)bp->b_data, &mp->fs->e2fs); brelse(bp, 0); bp = NULL; m_fs = mp->fs; m_fs->e2fs_ronly = ronly; #ifdef DEBUG_EXT2 printf("ext2 ino size %zu\n", EXT2_DINODE_SIZE(m_fs)); #endif DEBUG ((EFI_D_INFO, "mountrootf 6\n")); if (ronly == 0) { if (m_fs->e2fs.e2fs_state == E2FS_ISCLEAN) m_fs->e2fs.e2fs_state = 0; else m_fs->e2fs.e2fs_state = E2FS_ERRORS; m_fs->e2fs_fmod = 1; } DEBUG ((EFI_D_INFO, "mountrootf 7\n")); /* compute dynamic sb infos */ m_fs->e2fs_ncg = howmany(m_fs->e2fs.e2fs_bcount - m_fs->e2fs.e2fs_first_dblock, m_fs->e2fs.e2fs_bpg); m_fs->e2fs_fsbtodb = m_fs->e2fs.e2fs_log_bsize + LOG_MINBSIZE - DEV_BSHIFT; m_fs->e2fs_bsize = MINBSIZE << m_fs->e2fs.e2fs_log_bsize; m_fs->e2fs_bshift = LOG_MINBSIZE + m_fs->e2fs.e2fs_log_bsize; m_fs->e2fs_qbmask = m_fs->e2fs_bsize - 1; m_fs->e2fs_bmask = ~m_fs->e2fs_qbmask; m_fs->e2fs_ngdb = howmany(m_fs->e2fs_ncg, m_fs->e2fs_bsize / sizeof(struct ext2_gd)); m_fs->e2fs_ipb = m_fs->e2fs_bsize / EXT2_DINODE_SIZE(m_fs); m_fs->e2fs_itpg = m_fs->e2fs.e2fs_ipg / m_fs->e2fs_ipb; m_fs->e2fs_gd = malloc(m_fs->e2fs_ngdb * m_fs->e2fs_bsize, M_UFSMNT, M_WAITOK); for (i = 0; i < m_fs->e2fs_ngdb; i++) { DEBUG ((EFI_D_INFO, "mountrootf 8\n")); error = bread(devvp , fsbtodb(m_fs, m_fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), m_fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { free(m_fs->e2fs_gd, M_UFSMNT); goto out; } e2fs_cgload((struct ext2_gd *)bp->b_data, &m_fs->e2fs_gd[ i * m_fs->e2fs_bsize / sizeof(struct ext2_gd)], m_fs->e2fs_bsize); brelse(bp, 0); bp = NULL; }
/* * Common code for mount and mountroot */ int ext2fs_mountfs(struct vnode *devvp, struct mount *mp, struct proc *p) { struct ufsmount *ump; struct buf *bp; struct ext2fs *fs; dev_t dev; int error, ronly; struct ucred *cred; dev = devvp->v_rdev; cred = p ? p->p_ucred : NOCRED; /* * Disallow multiple mounts of the same device. * Disallow mounting of a device that is currently in use * (except for root, which might share swap device for miniroot). * Flush out any old buffers remaining from a previous use. */ if ((error = vfs_mountedon(devvp)) != 0) return (error); if (vcount(devvp) > 1 && devvp != rootvp) return (EBUSY); if ((error = vinvalbuf(devvp, V_SAVE, cred, p, 0, 0)) != 0) return (error); ronly = (mp->mnt_flag & MNT_RDONLY) != 0; error = VOP_OPEN(devvp, ronly ? FREAD : FREAD|FWRITE, FSCRED, p); if (error) return (error); bp = NULL; ump = NULL; /* * Read the superblock from disk. */ error = bread(devvp, (daddr_t)(SBOFF / DEV_BSIZE), SBSIZE, &bp); if (error) goto out; fs = (struct ext2fs *)bp->b_data; error = e2fs_sbcheck(fs, ronly); if (error) goto out; ump = malloc(sizeof *ump, M_UFSMNT, M_WAITOK | M_ZERO); ump->um_e2fs = malloc(sizeof(struct m_ext2fs), M_UFSMNT, M_WAITOK | M_ZERO); /* * Copy in the superblock, compute in-memory values * and load group descriptors. */ e2fs_sbload(fs, &ump->um_e2fs->e2fs); if ((error = e2fs_sbfill(devvp, ump->um_e2fs)) != 0) goto out; brelse(bp); bp = NULL; fs = &ump->um_e2fs->e2fs; ump->um_e2fs->e2fs_ronly = ronly; ump->um_fstype = UM_EXT2FS; if (ronly == 0) { if (fs->e2fs_state == E2FS_ISCLEAN) fs->e2fs_state = 0; else fs->e2fs_state = E2FS_ERRORS; ump->um_e2fs->e2fs_fmod = 1; } mp->mnt_data = (qaddr_t)ump; mp->mnt_stat.f_fsid.val[0] = (long)dev; mp->mnt_stat.f_fsid.val[1] = mp->mnt_vfc->vfc_typenum; mp->mnt_stat.f_namemax = MAXNAMLEN; mp->mnt_flag |= MNT_LOCAL; ump->um_mountp = mp; ump->um_dev = dev; ump->um_devvp = devvp; ump->um_nindir = NINDIR(ump->um_e2fs); ump->um_bptrtodb = ump->um_e2fs->e2fs_fsbtodb; ump->um_seqinc = 1; /* no frags */ ump->um_maxsymlinklen = EXT2_MAXSYMLINKLEN; devvp->v_specmountpoint = mp; return (0); out: if (bp) brelse(bp); vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY, p); (void)VOP_CLOSE(devvp, ronly ? FREAD : FREAD|FWRITE, cred, p); VOP_UNLOCK(devvp, p); if (ump) { free(ump->um_e2fs, M_UFSMNT, sizeof *ump->um_e2fs); free(ump, M_UFSMNT, sizeof *ump); mp->mnt_data = NULL; } return (error); }
/* * Reload all incore data for a filesystem (used after running fsck on * the root filesystem and finding things to fix). The filesystem must * be mounted read-only. * * Things to do to update the mount: * 1) invalidate all cached meta-data. * 2) re-read superblock from disk. * 3) re-read summary information from disk. * 4) invalidate all inactive vnodes. * 5) invalidate all cached file data. * 6) re-read inode data for all active vnodes. */ int ext2fs_reload(struct mount *mp, kauth_cred_t cred, struct lwp *l) { struct vnode *vp, *devvp; struct inode *ip; struct buf *bp; struct m_ext2fs *fs; struct ext2fs *newfs; int i, error; void *cp; struct ufsmount *ump; struct vnode_iterator *marker; if ((mp->mnt_flag & MNT_RDONLY) == 0) return (EINVAL); ump = VFSTOUFS(mp); /* * Step 1: invalidate all cached meta-data. */ devvp = ump->um_devvp; vn_lock(devvp, LK_EXCLUSIVE | LK_RETRY); error = vinvalbuf(devvp, 0, cred, l, 0, 0); VOP_UNLOCK(devvp); if (error) panic("ext2fs_reload: dirty1"); /* * Step 2: re-read superblock from disk. */ error = bread(devvp, SBLOCK, SBSIZE, NOCRED, 0, &bp); if (error) { return (error); } newfs = (struct ext2fs *)bp->b_data; error = ext2fs_checksb(newfs, (mp->mnt_flag & MNT_RDONLY) != 0); if (error) { brelse(bp, 0); return (error); } fs = ump->um_e2fs; /* * copy in new superblock, and compute in-memory values */ e2fs_sbload(newfs, &fs->e2fs); fs->e2fs_ncg = howmany(fs->e2fs.e2fs_bcount - fs->e2fs.e2fs_first_dblock, fs->e2fs.e2fs_bpg); fs->e2fs_fsbtodb = fs->e2fs.e2fs_log_bsize + LOG_MINBSIZE - DEV_BSHIFT; fs->e2fs_bsize = MINBSIZE << fs->e2fs.e2fs_log_bsize; fs->e2fs_bshift = LOG_MINBSIZE + fs->e2fs.e2fs_log_bsize; fs->e2fs_qbmask = fs->e2fs_bsize - 1; fs->e2fs_bmask = ~fs->e2fs_qbmask; fs->e2fs_ngdb = howmany(fs->e2fs_ncg, fs->e2fs_bsize / sizeof(struct ext2_gd)); fs->e2fs_ipb = fs->e2fs_bsize / EXT2_DINODE_SIZE(fs); fs->e2fs_itpg = fs->e2fs.e2fs_ipg / fs->e2fs_ipb; brelse(bp, 0); /* * Step 3: re-read summary information from disk. */ for (i = 0; i < fs->e2fs_ngdb; i++) { error = bread(devvp , EXT2_FSBTODB(fs, fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { return (error); } e2fs_cgload((struct ext2_gd *)bp->b_data, &fs->e2fs_gd[i * fs->e2fs_bsize / sizeof(struct ext2_gd)], fs->e2fs_bsize); brelse(bp, 0); } vfs_vnode_iterator_init(mp, &marker); while ((vp = vfs_vnode_iterator_next(marker, NULL, NULL))) { /* * Step 4: invalidate all inactive vnodes. */ if (vrecycle(vp)) continue; /* * Step 5: invalidate all cached file data. */ if (vn_lock(vp, LK_EXCLUSIVE)) { vrele(vp); continue; } if (vinvalbuf(vp, 0, cred, l, 0, 0)) panic("ext2fs_reload: dirty2"); /* * Step 6: re-read inode data for all active vnodes. */ ip = VTOI(vp); error = bread(devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ip->i_number)), (int)fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { vput(vp); break; } cp = (char *)bp->b_data + (ino_to_fsbo(fs, ip->i_number) * EXT2_DINODE_SIZE(fs)); e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din); ext2fs_set_inode_guid(ip); brelse(bp, 0); vput(vp); } vfs_vnode_iterator_destroy(marker); return (error); }