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.
*