Changeset View
Changeset View
Standalone View
Standalone View
sbin/fsck_ffs/suj.c
| Show First 20 Lines • Show All 315 Lines • ▼ Show 20 Lines | blk_freemask(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn, int frags) | ||||
| struct jblkrec *brec; | struct jblkrec *brec; | ||||
| int mask; | int mask; | ||||
| int off; | int off; | ||||
| /* | /* | ||||
| * To be certain we're not freeing a reallocated block we lookup | * To be certain we're not freeing a reallocated block we lookup | ||||
| * this block in the blk hash and see if there is an allocation | * this block in the blk hash and see if there is an allocation | ||||
| * journal record that overlaps with any fragments in the block | * journal record that overlaps with any fragments in the block | ||||
| * we're concerned with. If any fragments have ben reallocated | * we're concerned with. If any fragments have been reallocated | ||||
| * the block has already been freed and re-used for another purpose. | * the block has already been freed and re-used for another purpose. | ||||
| */ | */ | ||||
| mask = 0; | mask = 0; | ||||
| sblk = blk_lookup(blknum(fs, blk), 0); | sblk = blk_lookup(blknum(fs, blk), 0); | ||||
| if (sblk == NULL) | if (sblk == NULL) | ||||
| return (0); | return (0); | ||||
| off = blk - sblk->sb_blk; | off = blk - sblk->sb_blk; | ||||
| TAILQ_FOREACH(srec, &sblk->sb_recs, sr_next) { | TAILQ_FOREACH(srec, &sblk->sb_recs, sr_next) { | ||||
| ▲ Show 20 Lines • Show All 41 Lines • ▼ Show 20 Lines | blk_isindir(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn) | ||||
| brec = (struct jblkrec *)TAILQ_LAST(&sblk->sb_recs, srechd)->sr_rec; | brec = (struct jblkrec *)TAILQ_LAST(&sblk->sb_recs, srechd)->sr_rec; | ||||
| if (blk_equals(brec, ino, lbn, blk, fs->fs_frag)) | if (blk_equals(brec, ino, lbn, blk, fs->fs_frag)) | ||||
| if (brec->jb_op == JOP_FREEBLK) | if (brec->jb_op == JOP_FREEBLK) | ||||
| return (!blk_isfree(blk)); | return (!blk_isfree(blk)); | ||||
| return (0); | return (0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Check to see if the requested block is available. | |||||
| * We can just check in the cylinder-group maps as | |||||
| * they will only have usable blocks in them. | |||||
| */ | |||||
| ufs2_daddr_t | |||||
| suj_checkblkavail(blkno, frags) | |||||
| ufs2_daddr_t blkno; | |||||
| long frags; | |||||
| { | |||||
| struct bufarea *cgbp; | |||||
| struct cg *cgp; | |||||
| ufs2_daddr_t j, k, baseblk; | |||||
| long cg; | |||||
| cg = dtog(&sblock, blkno); | |||||
| cgbp = cglookup(cg); | |||||
| cgp = cgbp->b_un.b_cg; | |||||
| if (!check_cgmagic(cg, cgbp, 0)) | |||||
| return (-((cg + 1) * sblock.fs_fpg - sblock.fs_frag)); | |||||
| baseblk = dtogd(&sblock, blkno); | |||||
| for (j = 0; j <= sblock.fs_frag - frags; j++) { | |||||
| if (!isset(cg_blksfree(cgp), baseblk + j)) | |||||
| continue; | |||||
| for (k = 1; k < frags; k++) | |||||
| if (!isset(cg_blksfree(cgp), baseblk + j + k)) | |||||
| break; | |||||
| if (k < frags) { | |||||
| j += k; | |||||
| continue; | |||||
| } | |||||
| for (k = 0; k < frags; k++) | |||||
| clrbit(cg_blksfree(cgp), baseblk + j + k); | |||||
| n_blks += frags; | |||||
| if (frags == sblock.fs_frag) | |||||
| cgp->cg_cs.cs_nbfree--; | |||||
| else | |||||
| cgp->cg_cs.cs_nffree -= frags; | |||||
| cgdirty(cgbp); | |||||
| return ((cg * sblock.fs_fpg) + baseblk + j); | |||||
| } | |||||
| return (0); | |||||
| } | |||||
| /* | |||||
| * Clear an inode from the cg bitmap. If the inode was already clear return | * Clear an inode from the cg bitmap. If the inode was already clear return | ||||
| * 0 so the caller knows it does not have to check the inode contents. | * 0 so the caller knows it does not have to check the inode contents. | ||||
| */ | */ | ||||
| static int | static int | ||||
| ino_free(ino_t ino, int mode) | ino_free(ino_t ino, int mode) | ||||
| { | { | ||||
| struct suj_cg *sc; | struct suj_cg *sc; | ||||
| uint8_t *inosused; | uint8_t *inosused; | ||||
| Show All 25 Lines | ino_free(ino_t ino, int mode) | ||||
| return (1); | return (1); | ||||
| } | } | ||||
| /* | /* | ||||
| * Free 'frags' frags starting at filesystem block 'bno' skipping any frags | * Free 'frags' frags starting at filesystem block 'bno' skipping any frags | ||||
| * set in the mask. | * set in the mask. | ||||
| */ | */ | ||||
| static void | static void | ||||
| blk_free(ufs2_daddr_t bno, int mask, int frags) | blk_free(ino_t ino, ufs2_daddr_t bno, int mask, int frags) | ||||
| { | { | ||||
| ufs1_daddr_t fragno, cgbno; | ufs1_daddr_t fragno, cgbno; | ||||
| struct suj_cg *sc; | struct suj_cg *sc; | ||||
| struct cg *cgp; | struct cg *cgp; | ||||
| int i, cg; | int i, cg; | ||||
| uint8_t *blksfree; | uint8_t *blksfree; | ||||
| if (debug) | if (debug) | ||||
| printf("Freeing %d frags at blk %jd mask 0x%x\n", | printf("Freeing %d frags at blk %jd mask 0x%x\n", | ||||
| frags, bno, mask); | frags, bno, mask); | ||||
| /* | |||||
| * Check to see if the block needs to be claimed by a snapshot. | |||||
| * If wanted, the snapshot references it. Otherwise we free it. | |||||
| */ | |||||
| if (snapblkfree(fs, bno, lfragtosize(fs, frags), ino, | |||||
| suj_checkblkavail)) | |||||
| return; | |||||
| cg = dtog(fs, bno); | cg = dtog(fs, bno); | ||||
| sc = cg_lookup(cg); | sc = cg_lookup(cg); | ||||
| cgp = sc->sc_cgp; | cgp = sc->sc_cgp; | ||||
| cgbno = dtogd(fs, bno); | cgbno = dtogd(fs, bno); | ||||
| blksfree = cg_blksfree(cgp); | blksfree = cg_blksfree(cgp); | ||||
| /* | /* | ||||
| * If it's not allocated we only wrote the journal entry | * If it's not allocated we only wrote the journal entry | ||||
| ▲ Show 20 Lines • Show All 399 Lines • ▼ Show 20 Lines | ino_adjblks(struct suj_ino *sino) | ||||
| inodirty(&ip); | inodirty(&ip); | ||||
| irelse(&ip); | irelse(&ip); | ||||
| } | } | ||||
| static void | static void | ||||
| blk_free_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags) | blk_free_visit(ino_t ino, ufs_lbn_t lbn, ufs2_daddr_t blk, int frags) | ||||
| { | { | ||||
| blk_free(blk, blk_freemask(blk, ino, lbn, frags), frags); | blk_free(ino, blk, blk_freemask(blk, ino, lbn, frags), frags); | ||||
| } | } | ||||
| /* | /* | ||||
| * Free a block or tree of blocks that was previously rooted in ino at | * Free a block or tree of blocks that was previously rooted in ino at | ||||
| * the given lbn. If the lbn is an indirect all children are freed | * the given lbn. If the lbn is an indirect all children are freed | ||||
| * recursively. | * recursively. | ||||
| */ | */ | ||||
| static void | static void | ||||
| blk_free_lbn(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn, int frags, int follow) | blk_free_lbn(ufs2_daddr_t blk, ino_t ino, ufs_lbn_t lbn, int frags, int follow) | ||||
| { | { | ||||
| uint64_t resid; | uint64_t resid; | ||||
| int mask; | int mask; | ||||
| mask = blk_freemask(blk, ino, lbn, frags); | mask = blk_freemask(blk, ino, lbn, frags); | ||||
| resid = 0; | resid = 0; | ||||
| if (lbn <= -UFS_NDADDR && follow && mask == 0) | if (lbn <= -UFS_NDADDR && follow && mask == 0) | ||||
| indir_visit(ino, lbn, blk, &resid, blk_free_visit, VISIT_INDIR); | indir_visit(ino, lbn, blk, &resid, blk_free_visit, VISIT_INDIR); | ||||
| else | else | ||||
| blk_free(blk, mask, frags); | blk_free(ino, blk, mask, frags); | ||||
| } | } | ||||
| static void | static void | ||||
| ino_setskip(struct suj_ino *sino, ino_t parent) | ino_setskip(struct suj_ino *sino, ino_t parent) | ||||
| { | { | ||||
| int isdot; | int isdot; | ||||
| int mode; | int mode; | ||||
| ▲ Show 20 Lines • Show All 115 Lines • ▼ Show 20 Lines | ino_reclaim(struct inode *ip, ino_t ino, int mode) | ||||
| if (debug) | if (debug) | ||||
| printf("Truncating and freeing ino %ju, nlink %d, mode %o\n", | printf("Truncating and freeing ino %ju, nlink %d, mode %o\n", | ||||
| (uintmax_t)ino, DIP(dp, di_nlink), DIP(dp, di_mode)); | (uintmax_t)ino, DIP(dp, di_nlink), DIP(dp, di_mode)); | ||||
| /* We are freeing an inode or directory. */ | /* We are freeing an inode or directory. */ | ||||
| if ((DIP(dp, di_mode) & IFMT) == IFDIR) | if ((DIP(dp, di_mode) & IFMT) == IFDIR) | ||||
| ino_visit(dp, ino, ino_free_children, 0); | ino_visit(dp, ino, ino_free_children, 0); | ||||
| DIP_SET(dp, di_nlink, 0); | DIP_SET(dp, di_nlink, 0); | ||||
| if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) | |||||
| snapremove(ino); | |||||
| ino_visit(dp, ino, blk_free_visit, VISIT_EXT | VISIT_INDIR); | ino_visit(dp, ino, blk_free_visit, VISIT_EXT | VISIT_INDIR); | ||||
| /* Here we have to clear the inode and release any blocks it holds. */ | /* Here we have to clear the inode and release any blocks it holds. */ | ||||
| gen = DIP(dp, di_gen); | gen = DIP(dp, di_gen); | ||||
| if (fs->fs_magic == FS_UFS1_MAGIC) | if (fs->fs_magic == FS_UFS1_MAGIC) | ||||
| bzero(dp, sizeof(struct ufs1_dinode)); | bzero(dp, sizeof(struct ufs1_dinode)); | ||||
| else | else | ||||
| bzero(dp, sizeof(struct ufs2_dinode)); | bzero(dp, sizeof(struct ufs2_dinode)); | ||||
| DIP_SET(dp, di_gen, gen); | DIP_SET(dp, di_gen, gen); | ||||
| ▲ Show 20 Lines • Show All 196 Lines • ▼ Show 20 Lines | if (level != 0) { | ||||
| if (nlbn < lastlbn) | if (nlbn < lastlbn) | ||||
| continue; | continue; | ||||
| } else { | } else { | ||||
| nlbn = -lbn + i * lbnadd; | nlbn = -lbn + i * lbnadd; | ||||
| if (nlbn < lastlbn) | if (nlbn < lastlbn) | ||||
| continue; | continue; | ||||
| } | } | ||||
| isdirty = 1; | isdirty = 1; | ||||
| blk_free(nblk, 0, fs->fs_frag); | blk_free(ino, nblk, 0, fs->fs_frag); | ||||
| IBLK_SET(bp, i, 0); | IBLK_SET(bp, i, 0); | ||||
| } | } | ||||
| if (isdirty) | if (isdirty) | ||||
| dirty(bp); | dirty(bp); | ||||
| brelse(bp); | brelse(bp); | ||||
| } | } | ||||
| /* | /* | ||||
| Show All 19 Lines | ino_trunc(ino_t ino, off_t size) | ||||
| off_t cursize; | off_t cursize; | ||||
| off_t off; | off_t off; | ||||
| int mode; | int mode; | ||||
| ginode(ino, &ip); | ginode(ino, &ip); | ||||
| dp = ip.i_dp; | dp = ip.i_dp; | ||||
| mode = DIP(dp, di_mode) & IFMT; | mode = DIP(dp, di_mode) & IFMT; | ||||
| cursize = DIP(dp, di_size); | cursize = DIP(dp, di_size); | ||||
| /* If no size change, nothing to do */ | |||||
| if (size == cursize) { | |||||
| irelse(&ip); | |||||
| return; | |||||
| } | |||||
| if (debug) | if (debug) | ||||
| printf("Truncating ino %ju, mode %o to size %jd from size %jd\n", | printf("Truncating ino %ju, mode %o to size %jd from size %jd\n", | ||||
| (uintmax_t)ino, mode, size, cursize); | (uintmax_t)ino, mode, size, cursize); | ||||
| /* Skip datablocks for short links and devices. */ | /* Skip datablocks for short links and devices. */ | ||||
| if (mode == 0 || mode == IFBLK || mode == IFCHR || | if (mode == 0 || mode == IFBLK || mode == IFCHR || | ||||
| (mode == IFLNK && cursize < fs->fs_maxsymlinklen)) { | (mode == IFLNK && cursize < fs->fs_maxsymlinklen)) { | ||||
| irelse(&ip); | irelse(&ip); | ||||
| return; | return; | ||||
| } | } | ||||
| /* Don't extend. */ | /* Don't extend. */ | ||||
| if (size > cursize) { | if (size > cursize) { | ||||
| irelse(&ip); | irelse(&ip); | ||||
| return; | return; | ||||
| } | } | ||||
| if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) { | if ((DIP(dp, di_flags) & SF_SNAPSHOT) != 0) { | ||||
| if (size > 0) | if (size > 0) | ||||
| err_suj("Partial truncation of ino %ju snapshot file\n", | err_suj("Partial truncation of ino %ju snapshot file\n", | ||||
| (uintmax_t)ino); | (uintmax_t)ino); | ||||
| snapremove(ino); | |||||
| } | } | ||||
| lastlbn = lblkno(fs, blkroundup(fs, size)); | lastlbn = lblkno(fs, blkroundup(fs, size)); | ||||
| for (i = lastlbn; i < UFS_NDADDR; i++) { | for (i = lastlbn; i < UFS_NDADDR; i++) { | ||||
| if ((bn = DIP(dp, di_db[i])) == 0) | if ((bn = DIP(dp, di_db[i])) == 0) | ||||
| continue; | continue; | ||||
| blksize = sblksize(fs, cursize, i); | blksize = sblksize(fs, cursize, i); | ||||
| blk_free(bn, 0, numfrags(fs, blksize)); | blk_free(ino, bn, 0, numfrags(fs, blksize)); | ||||
| DIP_SET(dp, di_db[i], 0); | DIP_SET(dp, di_db[i], 0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Follow indirect blocks, freeing anything required. | * Follow indirect blocks, freeing anything required. | ||||
| */ | */ | ||||
| for (i = 0, tmpval = NINDIR(fs), lbn = UFS_NDADDR; i < UFS_NIADDR; i++, | for (i = 0, tmpval = NINDIR(fs), lbn = UFS_NDADDR; i < UFS_NIADDR; i++, | ||||
| lbn = nextlbn) { | lbn = nextlbn) { | ||||
| nextlbn = lbn + tmpval; | nextlbn = lbn + tmpval; | ||||
| tmpval *= NINDIR(fs); | tmpval *= NINDIR(fs); | ||||
| /* If we're not freeing any in this indirect range skip it. */ | /* If we're not freeing any in this indirect range skip it. */ | ||||
| if (lastlbn >= nextlbn) | if (lastlbn >= nextlbn) | ||||
| continue; | continue; | ||||
| if (DIP(dp, di_ib[i]) == 0) | if ((bn = DIP(dp, di_ib[i])) == 0) | ||||
| continue; | continue; | ||||
| indir_trunc(ino, -lbn - i, DIP(dp, di_ib[i]), lastlbn, dp); | indir_trunc(ino, -lbn - i, bn, lastlbn, dp); | ||||
| /* If we freed everything in this indirect free the indir. */ | /* If we freed everything in this indirect free the indir. */ | ||||
| if (lastlbn > lbn) | if (lastlbn > lbn) | ||||
| continue; | continue; | ||||
| blk_free(DIP(dp, di_ib[i]), 0, fs->fs_frag); | blk_free(ino, bn, 0, fs->fs_frag); | ||||
| DIP_SET(dp, di_ib[i], 0); | DIP_SET(dp, di_ib[i], 0); | ||||
| } | } | ||||
| /* | /* | ||||
| * Now that we've freed any whole blocks that exceed the desired | * Now that we've freed any whole blocks that exceed the desired | ||||
| * truncation size, figure out how many blocks remain and what the | * truncation size, figure out how many blocks remain and what the | ||||
| * last populated lbn is. We will set the size to this last lbn | * last populated lbn is. We will set the size to this last lbn | ||||
| * rather than worrying about allocating the final lbn as the kernel | * rather than worrying about allocating the final lbn as the kernel | ||||
| * would've done. This is consistent with normal fsck behavior. | * would've done. This is consistent with normal fsck behavior. | ||||
| Show All 13 Lines | if (visitlbn < UFS_NDADDR && totalfrags) { | ||||
| if (bn == 0) | if (bn == 0) | ||||
| err_suj("Bad blk at ino %ju lbn %jd\n", | err_suj("Bad blk at ino %ju lbn %jd\n", | ||||
| (uintmax_t)ino, visitlbn); | (uintmax_t)ino, visitlbn); | ||||
| oldspace = sblksize(fs, cursize, visitlbn); | oldspace = sblksize(fs, cursize, visitlbn); | ||||
| newspace = sblksize(fs, size, visitlbn); | newspace = sblksize(fs, size, visitlbn); | ||||
| if (oldspace != newspace) { | if (oldspace != newspace) { | ||||
| bn += numfrags(fs, newspace); | bn += numfrags(fs, newspace); | ||||
| frags = numfrags(fs, oldspace - newspace); | frags = numfrags(fs, oldspace - newspace); | ||||
| blk_free(bn, 0, frags); | blk_free(ino, bn, 0, frags); | ||||
| totalfrags -= frags; | totalfrags -= frags; | ||||
| } | } | ||||
| } | } | ||||
| DIP_SET(dp, di_blocks, fsbtodb(fs, totalfrags)); | DIP_SET(dp, di_blocks, fsbtodb(fs, totalfrags)); | ||||
| DIP_SET(dp, di_size, size); | DIP_SET(dp, di_size, size); | ||||
| inodirty(&ip); | inodirty(&ip); | ||||
| /* | /* | ||||
| * If we've truncated into the middle of a block or frag we have | * If we've truncated into the middle of a block or frag we have | ||||
| ▲ Show 20 Lines • Show All 132 Lines • ▼ Show 20 Lines | TAILQ_FOREACH(srec, &sblk->sb_recs, sr_next) { | ||||
| if (isat == 1) { | if (isat == 1) { | ||||
| if (frags == brec->jb_frags) | if (frags == brec->jb_frags) | ||||
| continue; | continue; | ||||
| mask = blk_freemask(blk, brec->jb_ino, brec->jb_lbn, | mask = blk_freemask(blk, brec->jb_ino, brec->jb_lbn, | ||||
| brec->jb_frags); | brec->jb_frags); | ||||
| mask >>= frags; | mask >>= frags; | ||||
| blk += frags; | blk += frags; | ||||
| frags = brec->jb_frags - frags; | frags = brec->jb_frags - frags; | ||||
| blk_free(blk, mask, frags); | blk_free(brec->jb_ino, blk, mask, frags); | ||||
| continue; | continue; | ||||
| } | } | ||||
| /* | /* | ||||
| * The block wasn't found, attempt to free it. It won't be | * The block wasn't found, attempt to free it. It won't be | ||||
| * freed if it was actually reallocated. If this was an | * freed if it was actually reallocated. If this was an | ||||
| * allocation we don't want to follow indirects as they | * allocation we don't want to follow indirects as they | ||||
| * may not be written yet. Any children of the indirect will | * may not be written yet. Any children of the indirect will | ||||
| * have their own records. If it's a free we need to | * have their own records. If it's a free we need to | ||||
| ▲ Show 20 Lines • Show All 921 Lines • ▼ Show 20 Lines | if (preen || reply("RECOVER")) { | ||||
| printf("** Processing journal entries.\n"); | printf("** Processing journal entries.\n"); | ||||
| cg_apply(cg_trunc); | cg_apply(cg_trunc); | ||||
| cg_apply(cg_check_blk); | cg_apply(cg_check_blk); | ||||
| cg_apply(cg_adj_blk); | cg_apply(cg_adj_blk); | ||||
| cg_apply(cg_check_ino); | cg_apply(cg_check_ino); | ||||
| } | } | ||||
| if (preen == 0 && (jrecs > 0 || jbytes > 0) && reply("WRITE CHANGES") == 0) | if (preen == 0 && (jrecs > 0 || jbytes > 0) && reply("WRITE CHANGES") == 0) | ||||
| return (0); | return (0); | ||||
| /* | |||||
| * Check block counts of snapshot inodes and | |||||
| * make copies of any needed snapshot blocks. | |||||
| */ | |||||
| for (i = 0; i < snapcnt; i++) | |||||
| check_blkcnt(&snaplist[i]); | |||||
| snapflush(suj_checkblkavail); | |||||
| /* | /* | ||||
| * Recompute the fs summary info from correct cs summaries. | * Recompute the fs summary info from correct cs summaries. | ||||
| */ | */ | ||||
| bzero(&fs->fs_cstotal, sizeof(struct csum_total)); | bzero(&fs->fs_cstotal, sizeof(struct csum_total)); | ||||
| for (i = 0; i < fs->fs_ncg; i++) { | for (i = 0; i < fs->fs_ncg; i++) { | ||||
| cgsum = &fs->fs_cs(fs, i); | cgsum = &fs->fs_cs(fs, i); | ||||
| fs->fs_cstotal.cs_nffree += cgsum->cs_nffree; | fs->fs_cstotal.cs_nffree += cgsum->cs_nffree; | ||||
| fs->fs_cstotal.cs_nbfree += cgsum->cs_nbfree; | fs->fs_cstotal.cs_nbfree += cgsum->cs_nbfree; | ||||
| Show All 40 Lines | |||||