From 8ebae128befbc3cca0ba1597e46fe12c0340663d Mon Sep 17 00:00:00 2001 From: Kirk McKusick Date: Wed, 5 Dec 2018 06:31:50 +0000 Subject: [PATCH] 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 --- sbin/fsck_ffs/fsck.h | 1 + sbin/fsck_ffs/fsutil.c | 26 ++++++++++++++++++++++---- sbin/fsck_ffs/inode.c | 2 +- sbin/fsck_ffs/pass1.c | 2 +- sbin/fsck_ffs/pass5.c | 20 ++++++++++---------- sbin/fsck_ffs/setup.c | 7 +++++++ 6 files changed, 42 insertions(+), 16 deletions(-) diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h index ffe41be6cf3b..ed7e8f129c35 100644 --- a/sbin/fsck_ffs/fsck.h +++ b/sbin/fsck_ffs/fsck.h @@ -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); diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c index 91be4234ae48..117698a09c32 100644 --- a/sbin/fsck_ffs/fsutil.c +++ b/sbin/fsck_ffs/fsutil.c @@ -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); } } diff --git a/sbin/fsck_ffs/inode.c b/sbin/fsck_ffs/inode.c index 3f1cab8b3bd5..a914be8b87a5 100644 --- a/sbin/fsck_ffs/inode.c +++ b/sbin/fsck_ffs/inode.c @@ -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) { diff --git a/sbin/fsck_ffs/pass1.c b/sbin/fsck_ffs/pass1.c index 40e5e6d07e14..c9064ea704e4 100644 --- a/sbin/fsck_ffs/pass1.c +++ b/sbin/fsck_ffs/pass1.c @@ -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; diff --git a/sbin/fsck_ffs/pass5.c b/sbin/fsck_ffs/pass5.c index 436d184c327b..674ca91e22f3 100644 --- a/sbin/fsck_ffs/pass5.c +++ b/sbin/fsck_ffs/pass5.c @@ -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 && diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c index 4767b079e8c0..82a970e12858 100644 --- a/sbin/fsck_ffs/setup.c +++ b/sbin/fsck_ffs/setup.c @@ -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);