git: 817bac9a6327 - stable/13 - Optimize operations on UFS/FFS filesystems with bad cylinder group(s).
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Sun, 20 Aug 2023 04:28:27 UTC
The branch stable/13 has been updated by mckusick: URL: https://cgit.FreeBSD.org/src/commit/?id=817bac9a632745535febf2dc3489e038c540fc55 commit 817bac9a632745535febf2dc3489e038c540fc55 Author: Kirk McKusick <mckusick@FreeBSD.org> AuthorDate: 2023-08-11 06:02:47 +0000 Commit: Kirk McKusick <mckusick@FreeBSD.org> CommitDate: 2023-08-20 04:27:38 +0000 Optimize operations on UFS/FFS filesystems with bad cylinder group(s). Reported-by: Peter Holm Tested-by: Peter Holm Sponsored-by: The FreeBSD Foundation (cherry picked from commit c3046779b241768394a336de115e88cc7c10d922) --- sys/ufs/ffs/ffs_alloc.c | 53 +++++++++++++++++++++++++++++++++++++++++-------- 1 file changed, 45 insertions(+), 8 deletions(-) diff --git a/sys/ufs/ffs/ffs_alloc.c b/sys/ufs/ffs/ffs_alloc.c index 04dbfd90dee4..a84202eccc05 100644 --- a/sys/ufs/ffs/ffs_alloc.c +++ b/sys/ufs/ffs/ffs_alloc.c @@ -116,6 +116,7 @@ static void ffs_blkfree_cg(struct ufsmount *, struct fs *, #ifdef INVARIANTS static int ffs_checkfreeblk(struct inode *, ufs2_daddr_t, long); #endif +static void ffs_checkcgintegrity(struct fs *, uint64_t, int); static ufs2_daddr_t ffs_clusteralloc(struct inode *, uint64_t, ufs2_daddr_t, int); static ino_t ffs_dirpref(struct inode *); @@ -1722,8 +1723,10 @@ ffs_fragextend(struct inode *ip, return (0); } UFS_UNLOCK(ump); - if ((error = ffs_getcg(fs, ump->um_devvp, cg, 0, &bp, &cgp)) != 0) + if ((error = ffs_getcg(fs, ump->um_devvp, cg, 0, &bp, &cgp)) != 0) { + ffs_checkcgintegrity(fs, cg, error); goto fail; + } bno = dtogd(fs, bprev); blksfree = cg_blksfree(cgp); for (i = numfrags(fs, osize); i < frags; i++) @@ -1793,8 +1796,10 @@ ffs_alloccg(struct inode *ip, return (0); UFS_UNLOCK(ump); if ((error = ffs_getcg(fs, ump->um_devvp, cg, 0, &bp, &cgp)) != 0 || - (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) + (cgp->cg_cs.cs_nbfree == 0 && size == fs->fs_bsize)) { + ffs_checkcgintegrity(fs, cg, error); goto fail; + } if (size == fs->fs_bsize) { UFS_LOCK(ump); blkno = ffs_alloccgblk(ip, bp, bpref, rsize); @@ -1971,6 +1976,7 @@ ffs_clusteralloc(struct inode *ip, return (0); UFS_UNLOCK(ump); if ((error = ffs_getcg(fs, ump->um_devvp, cg, 0, &bp, &cgp)) != 0) { + ffs_checkcgintegrity(fs, cg, error); UFS_LOCK(ump); return (0); } @@ -2115,6 +2121,7 @@ check_nifree: return (0); UFS_UNLOCK(ump); if ((error = ffs_getcg(fs, ump->um_devvp, cg, 0, &bp, &cgp)) != 0) { + ffs_checkcgintegrity(fs, cg, error); UFS_LOCK(ump); return (0); } @@ -2762,7 +2769,7 @@ ffs_checkfreeblk(struct inode *ip, struct cg *cgp; struct buf *bp; ufs1_daddr_t cgbno; - int i, error, frags, blkalloced; + int i, frags, blkalloced; uint8_t *blksfree; fs = ITOFS(ip); @@ -2773,9 +2780,8 @@ ffs_checkfreeblk(struct inode *ip, } if ((uint64_t)bno >= fs->fs_size) panic("ffs_checkfreeblk: too big block %jd", (intmax_t)bno); - error = ffs_getcg(fs, ITODEVVP(ip), dtog(fs, bno), 0, &bp, &cgp); - if (error) - panic("ffs_checkfreeblk: cylinder group read failed"); + if (ffs_getcg(fs, ITODEVVP(ip), dtog(fs, bno), 0, &bp, &cgp) != 0) + return (0); blksfree = cg_blksfree(cgp); cgbno = dtogd(fs, bno); if (size == fs->fs_bsize) { @@ -3042,7 +3048,7 @@ ffs_getcg(struct fs *fs, bp->b_flags &= ~B_CKHASH; bp->b_flags |= B_INVAL | B_NOCACHE; brelse(bp); - return (EIO); + return (EINTEGRITY); } if (!cg_chkmagic(cgp) || cgp->cg_cgx != cg) { if (ppsratecheck(&VFSTOUFS(mp)->um_last_integritymsg, @@ -3062,7 +3068,7 @@ ffs_getcg(struct fs *fs, bp->b_flags &= ~B_CKHASH; bp->b_flags |= B_INVAL | B_NOCACHE; brelse(bp); - return (EIO); + return (EINTEGRITY); } bp->b_flags &= ~B_CKHASH; bp->b_xflags |= BX_BKGRDWRITE; @@ -3096,6 +3102,37 @@ ffs_ckhash_cg(struct buf *bp) cgp->cg_ckhash = ckhash; } +/* + * Called when a cylinder group read has failed. If an integrity check + * is the cause of failure then the cylinder group will not be usable + * until the filesystem has been unmounted and fsck has been run to + * repair it. To avoid future attempts to allocate resources from the + * cylinder group, its available resources are set to zero in the + * superblock summary information. Since it will appear to have no + * resources available, no further calls will be made to allocate + * resources from it. When resources are freed to the cylinder group + * the resource free routines will find the cylinder group unusable so + * the resource will simply be discarded and thus will not show up in + * the superblock summary information until they are recovered by fsck. + */ +static void +ffs_checkcgintegrity(struct fs *fs, + uint64_t cg, + int error) +{ + + if (error != EINTEGRITY) + return; + fs->fs_cstotal.cs_nffree -= fs->fs_cs(fs, cg).cs_nffree; + fs->fs_cs(fs, cg).cs_nffree = 0; + fs->fs_cstotal.cs_nbfree -= fs->fs_cs(fs, cg).cs_nbfree; + fs->fs_cs(fs, cg).cs_nbfree = 0; + fs->fs_cstotal.cs_nifree -= fs->fs_cs(fs, cg).cs_nifree; + fs->fs_cs(fs, cg).cs_nifree = 0; + fs->fs_maxcluster[cg] = 0; + fs->fs_fmod = 1; +} + /* * Fserr prints the name of a filesystem with an error diagnostic. *