int ext2fs_cgupdate(struct ufsmount *mp, int waitfor) { struct m_ext2fs *fs = mp->um_e2fs; struct buf *bp; int i, error = 0, allerror = 0; allerror = ext2fs_sbupdate(mp, waitfor); for (i = 0; i < fs->e2fs_ngdb; i++) { bp = getblk(mp->um_devvp, EXT2_FSBTODB(fs, fs->e2fs.e2fs_first_dblock + 1 /* superblock */ + i), fs->e2fs_bsize, 0, 0); e2fs_cgsave(&fs->e2fs_gd[ i * fs->e2fs_bsize / sizeof(struct ext2_gd)], (struct ext2_gd *)bp->b_data, fs->e2fs_bsize); if (waitfor == MNT_WAIT) error = bwrite(bp); else bawrite(bp); } if (!allerror && error) allerror = error; return allerror; }
int setup(const char *dev) { long cg, asked, i; long bmapsize; struct disklabel *lp; off_t sizepb; struct stat statb; struct m_ext2fs proto; int doskipclean; u_int64_t maxfilesize; havesb = 0; fswritefd = -1; doskipclean = skipclean; if (stat(dev, &statb) < 0) { printf("Can't stat %s: %s\n", dev, strerror(errno)); return 0; } if (!S_ISCHR(statb.st_mode)) { pfatal("%s is not a character device", dev); if (reply("CONTINUE") == 0) return 0; } if ((fsreadfd = open(dev, O_RDONLY)) < 0) { printf("Can't open %s: %s\n", dev, strerror(errno)); return 0; } if (preen == 0) printf("** %s", dev); if (nflag || (fswritefd = open(dev, O_WRONLY)) < 0) { fswritefd = -1; if (preen) pfatal("NO WRITE ACCESS"); printf(" (NO WRITE)"); } if (preen == 0) printf("\n"); fsmodified = 0; lfdir = 0; initbarea(&sblk); initbarea(&asblk); sblk.b_un.b_buf = malloc(SBSIZE); asblk.b_un.b_buf = malloc(SBSIZE); if (sblk.b_un.b_buf == NULL || asblk.b_un.b_buf == NULL) errexit("cannot allocate space for superblock"); if ((lp = getdisklabel(NULL, fsreadfd)) != NULL) dev_bsize = secsize = lp->d_secsize; else dev_bsize = secsize = DEV_BSIZE; /* * Read in the superblock, looking for alternates if necessary */ if (readsb(1) == 0) { if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) return 0; if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0) return 0; for (cg = 1; cg < proto.e2fs_ncg; cg++) { bflag = EXT2_FSBTODB(&proto, cg * proto.e2fs.e2fs_bpg + proto.e2fs.e2fs_first_dblock); if (readsb(0) != 0) break; } if (cg >= proto.e2fs_ncg) { printf("%s %s\n%s %s\n%s %s\n", "SEARCH FOR ALTERNATE SUPER-BLOCK", "FAILED. YOU MUST USE THE", "-b OPTION TO FSCK_FFS TO SPECIFY THE", "LOCATION OF AN ALTERNATE", "SUPER-BLOCK TO SUPPLY NEEDED", "INFORMATION; SEE fsck_ext2fs(8)."); return 0; } doskipclean = 0; pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag); } if (debug) printf("state = %d\n", sblock.e2fs.e2fs_state); if (sblock.e2fs.e2fs_state == E2FS_ISCLEAN) { if (doskipclean) { pwarn("%sile system is clean; not checking\n", preen ? "f" : "** F"); return -1; } if (!preen) pwarn("** File system is already clean\n"); } maxfsblock = sblock.e2fs.e2fs_bcount; maxino = sblock.e2fs_ncg * sblock.e2fs.e2fs_ipg; sizepb = sblock.e2fs_bsize; maxfilesize = sblock.e2fs_bsize * EXT2FS_NDADDR - 1; for (i = 0; i < EXT2FS_NIADDR; i++) { sizepb *= EXT2_NINDIR(&sblock); maxfilesize += sizepb; } /* * Check and potentially fix certain fields in the super block. */ if (/* (sblock.e2fs.e2fs_rbcount < 0) || */ (sblock.e2fs.e2fs_rbcount > sblock.e2fs.e2fs_bcount)) { pfatal("IMPOSSIBLE RESERVED BLOCK COUNT=%d IN SUPERBLOCK", sblock.e2fs.e2fs_rbcount); if (reply("SET TO DEFAULT") == 1) { sblock.e2fs.e2fs_rbcount = sblock.e2fs.e2fs_bcount * MINFREE / 100; sbdirty(); dirty(&asblk); } } if (sblock.e2fs.e2fs_bpg != sblock.e2fs.e2fs_fpg) { pfatal("WRONG FPG=%d (BPG=%d) IN SUPERBLOCK", sblock.e2fs.e2fs_fpg, sblock.e2fs.e2fs_bpg); return 0; } if (asblk.b_dirty && !bflag) { copyback_sb(&asblk); flush(fswritefd, &asblk); } /* * read in the summary info. */ sblock.e2fs_gd = malloc(sblock.e2fs_ngdb * sblock.e2fs_bsize); if (sblock.e2fs_gd == NULL) errexit("out of memory"); asked = 0; for (i = 0; i < sblock.e2fs_ngdb; i++) { if (bread(fsreadfd, (char *)&sblock.e2fs_gd[i * sblock.e2fs_bsize / sizeof(struct ext2_gd)], EXT2_FSBTODB(&sblock, ((sblock.e2fs_bsize > 1024) ? 0 : 1) + i + 1), sblock.e2fs_bsize) != 0 && !asked) { pfatal("BAD SUMMARY INFORMATION"); if (reply("CONTINUE") == 0) exit(FSCK_EXIT_CHECK_FAILED); asked++; } } /* * allocate and initialize the necessary maps */ bmapsize = roundup(howmany(maxfsblock, NBBY), sizeof(int16_t)); blockmap = calloc((unsigned int)bmapsize, sizeof(char)); if (blockmap == NULL) { printf("cannot alloc %u bytes for blockmap\n", (unsigned int)bmapsize); goto badsblabel; } statemap = calloc((unsigned int)(maxino + 2), sizeof(char)); if (statemap == NULL) { printf("cannot alloc %u bytes for statemap\n", (unsigned int)(maxino + 1)); goto badsblabel; } typemap = calloc((unsigned int)(maxino + 1), sizeof(char)); if (typemap == NULL) { printf("cannot alloc %u bytes for typemap\n", (unsigned int)(maxino + 1)); goto badsblabel; } lncntp = calloc((unsigned)(maxino + 1), sizeof(int16_t)); if (lncntp == NULL) { printf("cannot alloc %u bytes for lncntp\n", (unsigned int)((maxino + 1) * sizeof(int16_t))); goto badsblabel; } for (numdirs = 0, cg = 0; cg < sblock.e2fs_ncg; cg++) { numdirs += fs2h16(sblock.e2fs_gd[cg].ext2bgd_ndirs); } inplast = 0; listmax = numdirs + 10; inpsort = calloc((unsigned int)listmax, sizeof(struct inoinfo *)); inphead = calloc((unsigned int)numdirs, sizeof(struct inoinfo *)); if (inpsort == NULL || inphead == NULL) { printf("cannot alloc %u bytes for inphead\n", (unsigned int)(numdirs * sizeof(struct inoinfo *))); goto badsblabel; } bufinit(); return 1; badsblabel: ckfini(0); return 0; }
/* * 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; }
/* * Read an inode from disk and initialize this vnode / inode pair. * Caller assures no other thread will try to load this inode. */ int ext2fs_loadvnode(struct mount *mp, struct vnode *vp, const void *key, size_t key_len, const void **new_key) { ino_t ino; struct m_ext2fs *fs; struct inode *ip; struct ufsmount *ump; struct buf *bp; dev_t dev; int error; KASSERT(key_len == sizeof(ino)); memcpy(&ino, key, key_len); ump = VFSTOUFS(mp); dev = ump->um_dev; fs = ump->um_e2fs; /* Read in the disk contents for the inode, copy into the inode. */ error = bread(ump->um_devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ino)), (int)fs->e2fs_bsize, 0, &bp); if (error) return error; /* Allocate and initialize inode. */ ip = pool_get(&ext2fs_inode_pool, PR_WAITOK); memset(ip, 0, sizeof(struct inode)); vp->v_tag = VT_EXT2FS; vp->v_op = ext2fs_vnodeop_p; vp->v_vflag |= VV_LOCKSWORK; vp->v_data = ip; ip->i_vnode = vp; ip->i_ump = ump; ip->i_e2fs = fs; ip->i_dev = dev; ip->i_number = ino; ip->i_e2fs_last_lblk = 0; ip->i_e2fs_last_blk = 0; /* Initialize genfs node. */ genfs_node_init(vp, &ext2fs_genfsops); error = ext2fs_loadvnode_content(fs, ino, bp, ip); brelse(bp, 0); if (error) return error; /* If the inode was deleted, reset all fields */ if (ip->i_e2fs_dtime != 0) { ip->i_e2fs_mode = 0; (void)ext2fs_setsize(ip, 0); (void)ext2fs_setnblock(ip, 0); memset(ip->i_e2fs_blocks, 0, sizeof(ip->i_e2fs_blocks)); } /* Initialize the vnode from the inode. */ ext2fs_vinit(mp, ext2fs_specop_p, ext2fs_fifoop_p, &vp); /* Finish inode initialization. */ ip->i_devvp = ump->um_devvp; vref(ip->i_devvp); /* * Set up a generation number for this inode if it does not * already have one. This should only happen on old filesystems. */ if (ip->i_e2fs_gen == 0) { if (++ext2gennumber < (u_long)time_second) ext2gennumber = time_second; ip->i_e2fs_gen = ext2gennumber; if ((mp->mnt_flag & MNT_RDONLY) == 0) ip->i_flag |= IN_MODIFIED; } uvm_vnp_setsize(vp, ext2fs_size(ip)); *new_key = &ip->i_number; return 0; }
/* * 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; }
/* * Balloc defines the structure of file system storage * by allocating the physical blocks on a device given * the inode and the logical block number in a file. */ int ext2fs_balloc(struct inode *ip, daddr_t bn, int size, kauth_cred_t cred, struct buf **bpp, int flags) { struct m_ext2fs *fs; daddr_t nb; struct buf *bp, *nbp; struct vnode *vp = ITOV(ip); struct indir indirs[EXT2FS_NIADDR + 2]; daddr_t newb, lbn, pref; int32_t *bap; /* XXX ondisk32 */ int num, i, error; u_int deallocated; daddr_t *blkp, *allocblk, allociblk[EXT2FS_NIADDR + 1]; int32_t *allocib; /* XXX ondisk32 */ int unwindidx = -1; UVMHIST_FUNC("ext2fs_balloc"); UVMHIST_CALLED(ubchist); UVMHIST_LOG(ubchist, "bn 0x%x", bn,0,0,0); if (bpp != NULL) { *bpp = NULL; } if (bn < 0) return (EFBIG); fs = ip->i_e2fs; lbn = bn; /* * The first EXT2FS_NDADDR blocks are direct blocks */ if (bn < EXT2FS_NDADDR) { /* XXX ondisk32 */ nb = fs2h32(ip->i_e2fs_blocks[bn]); if (nb != 0) { /* * the block is already allocated, just read it. */ if (bpp != NULL) { error = bread(vp, bn, fs->e2fs_bsize, NOCRED, B_MODIFY, &bp); if (error) { return (error); } *bpp = bp; } return (0); } /* * allocate a new direct block. */ error = ext2fs_alloc(ip, bn, ext2fs_blkpref(ip, bn, bn, &ip->i_e2fs_blocks[0]), cred, &newb); if (error) return (error); ip->i_e2fs_last_lblk = lbn; ip->i_e2fs_last_blk = newb; /* XXX ondisk32 */ ip->i_e2fs_blocks[bn] = h2fs32((int32_t)newb); ip->i_flag |= IN_CHANGE | IN_UPDATE; if (bpp != NULL) { bp = getblk(vp, bn, fs->e2fs_bsize, 0, 0); bp->b_blkno = EXT2_FSBTODB(fs, newb); if (flags & B_CLRBUF) clrbuf(bp); *bpp = bp; } return (0); } /* * Determine the number of levels of indirection. */ pref = 0; if ((error = ufs_getlbns(vp, bn, indirs, &num)) != 0) return(error); #ifdef DIAGNOSTIC if (num < 1) panic ("ext2fs_balloc: ufs_getlbns returned indirect block\n"); #endif /* * Fetch the first indirect block allocating if necessary. */ --num; /* XXX ondisk32 */ nb = fs2h32(ip->i_e2fs_blocks[EXT2FS_NDADDR + indirs[0].in_off]); allocib = NULL; allocblk = allociblk; if (nb == 0) { pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); error = ext2fs_alloc(ip, lbn, pref, cred, &newb); if (error) return (error); nb = newb; *allocblk++ = nb; ip->i_e2fs_last_blk = newb; bp = getblk(vp, indirs[1].in_lbn, fs->e2fs_bsize, 0, 0); bp->b_blkno = EXT2_FSBTODB(fs, newb); clrbuf(bp); /* * Write synchronously so that indirect blocks * never point at garbage. */ if ((error = bwrite(bp)) != 0) goto fail; unwindidx = 0; allocib = &ip->i_e2fs_blocks[EXT2FS_NDADDR + indirs[0].in_off]; /* XXX ondisk32 */ *allocib = h2fs32((int32_t)newb); ip->i_flag |= IN_CHANGE | IN_UPDATE; } /* * Fetch through the indirect blocks, allocating as necessary. */ for (i = 1;;) { error = bread(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { goto fail; } bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ nb = fs2h32(bap[indirs[i].in_off]); if (i == num) break; i++; if (nb != 0) { brelse(bp, 0); continue; } pref = ext2fs_blkpref(ip, lbn, 0, (int32_t *)0); error = ext2fs_alloc(ip, lbn, pref, cred, &newb); if (error) { brelse(bp, 0); goto fail; } nb = newb; *allocblk++ = nb; ip->i_e2fs_last_blk = newb; nbp = getblk(vp, indirs[i].in_lbn, fs->e2fs_bsize, 0, 0); nbp->b_blkno = EXT2_FSBTODB(fs, nb); clrbuf(nbp); /* * Write synchronously so that indirect blocks * never point at garbage. */ if ((error = bwrite(nbp)) != 0) { brelse(bp, 0); goto fail; } if (unwindidx < 0) unwindidx = i - 1; /* XXX ondisk32 */ bap[indirs[i - 1].in_off] = h2fs32((int32_t)nb); /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & B_SYNC) { bwrite(bp); } else { bdwrite(bp); } } /* * Get the data block, allocating if necessary. */ if (nb == 0) { pref = ext2fs_blkpref(ip, lbn, indirs[num].in_off, &bap[0]); error = ext2fs_alloc(ip, lbn, pref, cred, &newb); if (error) { brelse(bp, 0); goto fail; } nb = newb; *allocblk++ = nb; ip->i_e2fs_last_lblk = lbn; ip->i_e2fs_last_blk = newb; /* XXX ondisk32 */ bap[indirs[num].in_off] = h2fs32((int32_t)nb); /* * If required, write synchronously, otherwise use * delayed write. */ if (flags & B_SYNC) { bwrite(bp); } else { bdwrite(bp); } if (bpp != NULL) { nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); nbp->b_blkno = EXT2_FSBTODB(fs, nb); if (flags & B_CLRBUF) clrbuf(nbp); *bpp = nbp; } return (0); } brelse(bp, 0); if (bpp != NULL) { if (flags & B_CLRBUF) { error = bread(vp, lbn, (int)fs->e2fs_bsize, NOCRED, B_MODIFY, &nbp); if (error) { goto fail; } } else { nbp = getblk(vp, lbn, fs->e2fs_bsize, 0, 0); nbp->b_blkno = EXT2_FSBTODB(fs, nb); } *bpp = nbp; } return (0); fail: /* * If we have failed part way through block allocation, we * have to deallocate any indirect blocks that we have allocated. */ for (deallocated = 0, blkp = allociblk; blkp < allocblk; blkp++) { ext2fs_blkfree(ip, *blkp); deallocated += fs->e2fs_bsize; } if (unwindidx >= 0) { if (unwindidx == 0) { *allocib = 0; } else { int r; r = bread(vp, indirs[unwindidx].in_lbn, (int)fs->e2fs_bsize, NOCRED, B_MODIFY, &bp); if (r) { panic("Could not unwind indirect block, error %d", r); } else { bap = (int32_t *)bp->b_data; /* XXX ondisk32 */ bap[indirs[unwindidx].in_off] = 0; if (flags & B_SYNC) bwrite(bp); else bdwrite(bp); } } for (i = unwindidx + 1; i <= num; i++) { bp = getblk(vp, indirs[i].in_lbn, (int)fs->e2fs_bsize, 0, 0); brelse(bp, BC_INVAL); } } if (deallocated) { ext2fs_setnblock(ip, ext2fs_nblock(ip) - btodb(deallocated)); ip->i_e2fs_flags |= IN_CHANGE | IN_UPDATE; } return error; }
/* * Look up a EXT2FS dinode number to find its incore vnode, otherwise read it * in from disk. If it is in core, wait for the lock bit to clear, then * return the inode locked. Detection and handling of mount points must be * done by the calling routine. */ int ext2fs_vget(struct mount *mp, ino_t ino, struct vnode **vpp) { struct m_ext2fs *fs; struct inode *ip; struct ufsmount *ump; struct buf *bp; struct vnode *vp; dev_t dev; int error; void *cp; ump = VFSTOUFS(mp); dev = ump->um_dev; retry: if ((*vpp = ufs_ihashget(dev, ino, LK_EXCLUSIVE)) != NULL) return (0); /* Allocate a new vnode/inode. */ error = getnewvnode(VT_EXT2FS, mp, ext2fs_vnodeop_p, NULL, &vp); if (error) { *vpp = NULL; return (error); } ip = pool_get(&ext2fs_inode_pool, PR_WAITOK); mutex_enter(&ufs_hashlock); if ((*vpp = ufs_ihashget(dev, ino, 0)) != NULL) { mutex_exit(&ufs_hashlock); ungetnewvnode(vp); pool_put(&ext2fs_inode_pool, ip); goto retry; } vp->v_vflag |= VV_LOCKSWORK; memset(ip, 0, sizeof(struct inode)); vp->v_data = ip; ip->i_vnode = vp; ip->i_ump = ump; ip->i_e2fs = fs = ump->um_e2fs; ip->i_dev = dev; ip->i_number = ino; ip->i_e2fs_last_lblk = 0; ip->i_e2fs_last_blk = 0; genfs_node_init(vp, &ext2fs_genfsops); /* * Put it onto its hash chain and lock it so that other requests for * this inode will block if they arrive while we are sleeping waiting * for old data structures to be purged or for the contents of the * disk portion of this inode to be read. */ ufs_ihashins(ip); mutex_exit(&ufs_hashlock); /* Read in the disk contents for the inode, copy into the inode. */ error = bread(ump->um_devvp, EXT2_FSBTODB(fs, ino_to_fsba(fs, ino)), (int)fs->e2fs_bsize, NOCRED, 0, &bp); if (error) { /* * The inode does not contain anything useful, so it would * be misleading to leave it on its hash chain. With mode * still zero, it will be unlinked and returned to the free * list by vput(). */ vput(vp); *vpp = NULL; return (error); } cp = (char *)bp->b_data + (ino_to_fsbo(fs, ino) * EXT2_DINODE_SIZE(fs)); ip->i_din.e2fs_din = pool_get(&ext2fs_dinode_pool, PR_WAITOK); e2fs_iload((struct ext2fs_dinode *)cp, ip->i_din.e2fs_din); ext2fs_set_inode_guid(ip); brelse(bp, 0); /* If the inode was deleted, reset all fields */ if (ip->i_e2fs_dtime != 0) { ip->i_e2fs_mode = 0; (void)ext2fs_setsize(ip, 0); (void)ext2fs_setnblock(ip, 0); memset(ip->i_e2fs_blocks, 0, sizeof(ip->i_e2fs_blocks)); } /* * Initialize the vnode from the inode, check for aliases. */ error = ext2fs_vinit(mp, ext2fs_specop_p, ext2fs_fifoop_p, &vp); if (error) { vput(vp); *vpp = NULL; return (error); } /* * Finish inode initialization now that aliasing has been resolved. */ ip->i_devvp = ump->um_devvp; vref(ip->i_devvp); /* * Set up a generation number for this inode if it does not * already have one. This should only happen on old filesystems. */ if (ip->i_e2fs_gen == 0) { if (++ext2gennumber < (u_long)time_second) ext2gennumber = time_second; ip->i_e2fs_gen = ext2gennumber; if ((vp->v_mount->mnt_flag & MNT_RDONLY) == 0) ip->i_flag |= IN_MODIFIED; } uvm_vnp_setsize(vp, ext2fs_size(ip)); *vpp = vp; return (0); }
/* * 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); }
/* * 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); }