Ensure that cylinder-group check-hashes are properly updated when first

creating them and when correcting them when they are found to be corrupted.

Reported by:  Don Lewis (truckman@)
Sponsored by: Netflix
This commit is contained in:
Kirk McKusick 2018-12-05 06:31:50 +00:00
parent db19a093bb
commit 8ebae128be
6 changed files with 42 additions and 16 deletions

View File

@ -417,6 +417,7 @@ void blzero(int fd, ufs2_daddr_t blk, long size);
void cacheino(union dinode *dp, ino_t inumber);
void catch(int);
void catchquit(int);
void cgdirty(struct bufarea *);
int changeino(ino_t dir, const char *name, ino_t newnum);
int check_cgmagic(int cg, struct bufarea *cgbp);
int chkrange(ufs2_daddr_t blk, int cnt);

View File

@ -248,6 +248,24 @@ cglookup(int cg)
return (cgbp);
}
/*
* Mark a cylinder group buffer as dirty.
* Update its check-hash if they are enabled.
*/
void
cgdirty(struct bufarea *cgbp)
{
struct cg *cg;
cg = cgbp->b_un.b_cg;
if ((sblock.fs_metackhash & CK_CYLGRP) != 0) {
cg->cg_ckhash = 0;
cg->cg_ckhash =
calculate_crc32c(~0L, (void *)cg, sblock.fs_cgsize);
}
dirty(cgbp);
}
/*
* Attempt to flush a cylinder group cache entry.
* Return whether the flush was successful.
@ -348,11 +366,11 @@ flush(int fd, struct bufarea *bp)
if (bp != &sblk)
pfatal("BUFFER %p DOES NOT MATCH SBLK %p\n",
bp, &sblk);
if (sbput(fd, (struct fs *)bp->b_un.b_buf, 0) == 0)
if (sbput(fd, bp->b_un.b_fs, 0) == 0)
fsmodified = 1;
break;
case BT_CYLGRP:
if (cgput(&disk, (struct cg *)bp->b_un.b_buf) == 0)
if (cgput(&disk, bp->b_un.b_cg) == 0)
fsmodified = 1;
break;
default:
@ -740,7 +758,7 @@ check_cgmagic(int cg, struct bufarea *cgbp)
cgp->cg_nextfreeoff = cgp->cg_clusteroff +
howmany(fragstoblks(&sblock, sblock.fs_fpg), CHAR_BIT);
}
dirty(cgbp);
cgdirty(cgbp);
return (0);
}
@ -782,7 +800,7 @@ allocblk(long frags)
cgp->cg_cs.cs_nbfree--;
else
cgp->cg_cs.cs_nffree -= frags;
dirty(cgbp);
cgdirty(cgbp);
return (i + j);
}
}

View File

@ -692,7 +692,7 @@ allocino(ino_t request, int type)
default:
return (0);
}
dirty(cgbp);
cgdirty(cgbp);
dp = ginode(ino);
DIP_SET(dp, di_db[0], allocblk((long)1));
if (DIP(dp, di_db[0]) == 0) {

View File

@ -200,7 +200,7 @@ pass1(void)
cgp->cg_initediblk = mininos;
pwarn("CYLINDER GROUP %d: RESET FROM %ju TO %d %s\n",
c, i, cgp->cg_initediblk, "VALID INODES");
dirty(cgbp);
cgdirty(cgbp);
}
if (inosused < sblock.fs_ipg)
continue;

View File

@ -182,14 +182,19 @@ pass5(void)
ckhash = cg->cg_ckhash;
cg->cg_ckhash = 0;
thishash = calculate_crc32c(~0L, cg, fs->fs_cgsize);
if (ckhash != thishash)
if (ckhash == thishash) {
cg->cg_ckhash = ckhash;
} else {
pwarn("CG %d: BAD CHECK-HASH %#x vs %#x\n",
c, ckhash, thishash);
cg->cg_ckhash = ckhash;
cg->cg_ckhash = thishash;
cgdirty(cgbp);
}
}
newcg->cg_time = cg->cg_time;
newcg->cg_old_time = cg->cg_old_time;
newcg->cg_unrefs = cg->cg_unrefs;
newcg->cg_ckhash = cg->cg_ckhash;
newcg->cg_cgx = c;
dbase = cgbase(fs, c);
dmax = dbase + fs->fs_fpg;
@ -326,11 +331,6 @@ pass5(void)
sump[run]++;
}
}
if ((fs->fs_metackhash & CK_CYLGRP) != 0) {
newcg->cg_ckhash = 0;
newcg->cg_ckhash =
calculate_crc32c(~0L, (void *)newcg, fs->fs_cgsize);
}
if (bkgrdflag != 0) {
cstotal.cs_nffree += cg->cg_cs.cs_nffree;
@ -352,14 +352,14 @@ pass5(void)
}
if (rewritecg) {
memmove(cg, newcg, (size_t)fs->fs_cgsize);
dirty(cgbp);
cgdirty(cgbp);
continue;
}
if (cursnapshot == 0 &&
memcmp(newcg, cg, basesize) != 0 &&
dofix(&idesc[2], "SUMMARY INFORMATION BAD")) {
memmove(cg, newcg, (size_t)basesize);
dirty(cgbp);
cgdirty(cgbp);
}
if (bkgrdflag != 0 || usedsoftdep || debug)
update_maps(cg, newcg, bkgrdflag);
@ -368,7 +368,7 @@ pass5(void)
dofix(&idesc[1], "BLK(S) MISSING IN BIT MAPS")) {
memmove(cg_inosused(cg), cg_inosused(newcg),
(size_t)mapsize);
dirty(cgbp);
cgdirty(cgbp);
}
}
if (cursnapshot == 0 &&

View File

@ -208,6 +208,13 @@ setup(char *dev)
pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag);
bflag = 0;
}
/* Save copy of things needed by libufs */
memcpy(&disk.d_fs, &sblock, sblock.fs_sbsize);
disk.d_ufs = (sblock.fs_magic == FS_UFS1_MAGIC) ? 1 : 2;
disk.d_bsize = sblock.fs_fsize / fsbtodb(&sblock, 1);
disk.d_sblock = sblock.fs_sblockloc / disk.d_bsize;
disk.d_sbcsum = sblock.fs_csp;
if (skipclean && ckclean && sblock.fs_clean) {
pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
return (-1);