git: efd949aaba74 - stable/13 - Have fsck_ffs(8) properly correct superblock check-hash failures.
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 16 Feb 2022 01:14:38 UTC
The branch stable/13 has been updated by mckusick: URL: https://cgit.FreeBSD.org/src/commit/?id=efd949aaba7449ae994fe5052178c2ba3efd2e7b commit efd949aaba7449ae994fe5052178c2ba3efd2e7b Author: Kirk McKusick <mckusick@FreeBSD.org> AuthorDate: 2022-02-04 19:46:36 +0000 Commit: Kirk McKusick <mckusick@FreeBSD.org> CommitDate: 2022-02-16 01:14:22 +0000 Have fsck_ffs(8) properly correct superblock check-hash failures. (cherry picked from commit c0bfa109b942659f609b7e2bf3ba042ec0cb3f9d) PR: 245916 --- sbin/fsck_ffs/fsck.h | 1 + sbin/fsck_ffs/fsutil.c | 4 +- sbin/fsck_ffs/globs.c | 6 +- sbin/fsck_ffs/main.c | 309 +++++++++++++++++++++++++++++++++---------------- sbin/fsck_ffs/setup.c | 182 +++++++---------------------- 5 files changed, 258 insertions(+), 244 deletions(-) diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h index 9ecc5793e644..690a98038884 100644 --- a/sbin/fsck_ffs/fsck.h +++ b/sbin/fsck_ffs/fsck.h @@ -356,6 +356,7 @@ extern char preen; /* just fix normal inconsistencies */ extern char rerun; /* rerun fsck. Only used in non-preen mode */ extern int returntosingle; /* 1 => return to single user mode on exit */ extern char resolved; /* cleared if unresolved changes => not clean */ +extern int sbhashfailed; /* when reading superblock check hash failed */ extern char havesb; /* superblock has been read */ extern char skipclean; /* skip clean file systems if preening */ extern int fsmodified; /* 1 => write done to file system */ diff --git a/sbin/fsck_ffs/fsutil.c b/sbin/fsck_ffs/fsutil.c index db22ee5b20cf..711c9bb63549 100644 --- a/sbin/fsck_ffs/fsutil.c +++ b/sbin/fsck_ffs/fsutil.c @@ -250,6 +250,7 @@ cglookup(int cg) if (cgp == NULL) { if (sujrecovery) errx(EEXIT,"Ran out of memory during journal recovery"); + flush(fswritefd, &cgblk); getblk(&cgblk, cgtod(&sblock, cg), sblock.fs_cgsize); return (&cgblk); } @@ -564,7 +565,7 @@ ckfini(int markclean) cmd.size = markclean ? -1 : 1; if (sysctlbyname("vfs.ffs.setflags", 0, 0, &cmd, sizeof cmd) == -1) - rwerror("SET FILE SYSTEM FLAGS", FS_UNCLEAN); + pwarn("CANNOT SET FILE SYSTEM DIRTY FLAG\n"); if (!preen) { printf("\n***** FILE SYSTEM MARKED %s *****\n", markclean ? "CLEAN" : "DIRTY"); @@ -575,6 +576,7 @@ ckfini(int markclean) printf("\n***** FILE SYSTEM STILL DIRTY *****\n"); rerun = 1; } + bkgrdflag = 0; } if (debug && cachelookups > 0) printf("cache with %d buffers missed %d of %d (%d%%)\n", diff --git a/sbin/fsck_ffs/globs.c b/sbin/fsck_ffs/globs.c index be4434ce38ca..09dbcc6694a2 100644 --- a/sbin/fsck_ffs/globs.c +++ b/sbin/fsck_ffs/globs.c @@ -96,6 +96,7 @@ char preen; /* just fix normal inconsistencies */ char rerun; /* rerun fsck. Only used in non-preen mode */ int returntosingle; /* 1 => return to single user mode on exit */ char resolved; /* cleared if unresolved changes => not clean */ +int sbhashfailed; /* when reading superblock check hash failed */ char havesb; /* superblock has been read */ char skipclean; /* skip clean file systems if preening */ int fsmodified; /* 1 => write done to file system */ @@ -155,8 +156,9 @@ fsckinit(void) resolved = 0; havesb = 0; fsmodified = 0; - fsreadfd = 0; - fswritefd = 0; + sbhashfailed = 0; + fsreadfd = -1; + fswritefd = -1; maxfsblock = 0; maxino = 0; lfdir = 0; diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c index e78e2d206499..f7224b48a9a4 100644 --- a/sbin/fsck_ffs/main.c +++ b/sbin/fsck_ffs/main.c @@ -75,6 +75,8 @@ static int restarts; static void usage(void) __dead2; static intmax_t argtoimax(int flag, const char *req, const char *str, int base); static int checkfilesys(char *filesys); +static int setup_bkgrdchk(struct statfs *mntp, int sbrdfailed, char **filesys); +static int openfilesys(char *dev); static int chkdoreload(struct statfs *mntp); static struct statfs *getmntpt(const char *); @@ -181,6 +183,11 @@ main(int argc, char *argv[]) if (!argc) usage(); + if (bkgrdflag && cvtlevel > 0) { + pfatal("CANNOT CONVERT A SNAPSHOT\n"); + exit(EEXIT); + } + if (signal(SIGINT, SIG_IGN) != SIG_IGN) (void)signal(SIGINT, catch); if (ckclean) @@ -237,18 +244,10 @@ checkfilesys(char *filesys) ufs2_daddr_t n_ffree, n_bfree; struct dups *dp; struct statfs *mntp; - struct stat snapdir; - struct group *grp; - struct iovec *iov; - char errmsg[255]; - int ofsmodified; - int iovlen; intmax_t blks, files; size_t size; + int sbreadfailed, ofsmodified; - iov = NULL; - iovlen = 0; - errmsg[0] = '\0'; fsutilinit(); fsckinit(); @@ -272,10 +271,12 @@ checkfilesys(char *filesys) * exit status will cause a foreground check to be run. */ sblock_init(); + sbreadfailed = 0; + if (openfilesys(filesys) == 0 || readsb(0) == 0) + sbreadfailed = 1; if (bkgrdcheck) { - if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0) + if (sbreadfailed) exit(3); /* Cannot read superblock */ - close(fsreadfd); /* Earlier background failed or journaled */ if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ)) exit(4); @@ -293,7 +294,7 @@ checkfilesys(char *filesys) /* * If file system is gjournaled, check it here. */ - if ((fsreadfd = open(filesys, O_RDONLY)) < 0 || readsb(0) == 0) + if (sbreadfailed) exit(3); /* Cannot read superblock */ if (bkgrdflag == 0 && (nflag || (fswritefd = open(filesys, O_WRONLY)) < 0)) { @@ -307,107 +308,30 @@ checkfilesys(char *filesys) pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); exit(0); } - if ((sblock.fs_flags & (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) { + if ((sblock.fs_flags & + (FS_UNCLEAN | FS_NEEDSFSCK)) == 0) { bufinit(); gjournal_check(filesys); if (chkdoreload(mntp) == 0) exit(0); exit(4); } else { - pfatal("UNEXPECTED INCONSISTENCY, CANNOT RUN " - "FAST FSCK\n"); + pfatal("FULL FSCK NEEDED, CANNOT RUN FAST " + "FSCK\n"); } } - close(fsreadfd); close(fswritefd); + fswritefd = -1; } - /* - * If we are to do a background check: - * Get the mount point information of the file system - * create snapshot file - * return created snapshot file - * if not found, clear bkgrdflag and proceed with normal fsck - */ if (bkgrdflag) { - /* Get the mount point information of the file system */ - if (mntp == NULL) { - bkgrdflag = 0; - pfatal("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n"); - } else if ((mntp->f_flags & MNT_SOFTDEP) == 0) { - bkgrdflag = 0; - pfatal("NOT USING SOFT UPDATES, CANNOT RUN IN " - "BACKGROUND\n"); - } else if ((mntp->f_flags & MNT_RDONLY) != 0) { - bkgrdflag = 0; - pfatal("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n"); - } else if ((fsreadfd = open(filesys, O_RDONLY)) >= 0) { - if (readsb(0) != 0) { - if (sblock.fs_flags & (FS_NEEDSFSCK | FS_SUJ)) { - bkgrdflag = 0; - pfatal( - "UNEXPECTED INCONSISTENCY, CANNOT RUN IN BACKGROUND\n"); - } - if ((sblock.fs_flags & FS_UNCLEAN) == 0 && - skipclean && ckclean) { - /* - * file system is clean; - * skip snapshot and report it clean - */ - pwarn( - "FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); - goto clean; - } - } - close(fsreadfd); - } - if (bkgrdflag) { - snprintf(snapname, sizeof snapname, "%s/.snap", - mntp->f_mntonname); - if (stat(snapname, &snapdir) < 0) { - if (errno != ENOENT) { - bkgrdflag = 0; - pfatal( - "CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n", - snapname, strerror(errno)); - } else if ((grp = getgrnam("operator")) == NULL || - mkdir(snapname, 0770) < 0 || - chown(snapname, -1, grp->gr_gid) < 0 || - chmod(snapname, 0770) < 0) { - bkgrdflag = 0; - pfatal( - "CANNOT CREATE SNAPSHOT DIRECTORY %s: %s, CANNOT RUN IN BACKGROUND\n", - snapname, strerror(errno)); - } - } else if (!S_ISDIR(snapdir.st_mode)) { - bkgrdflag = 0; - pfatal( - "%s IS NOT A DIRECTORY, CANNOT RUN IN BACKGROUND\n", - snapname); - } - } - if (bkgrdflag) { - snprintf(snapname, sizeof snapname, - "%s/.snap/fsck_snapshot", mntp->f_mntonname); - build_iovec(&iov, &iovlen, "fstype", "ffs", 4); - build_iovec(&iov, &iovlen, "from", snapname, - (size_t)-1); - build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, - (size_t)-1); - build_iovec(&iov, &iovlen, "errmsg", errmsg, - sizeof(errmsg)); - build_iovec(&iov, &iovlen, "update", NULL, 0); - build_iovec(&iov, &iovlen, "snapshot", NULL, 0); - - while (nmount(iov, iovlen, mntp->f_flags) < 0) { - if (errno == EEXIST && unlink(snapname) == 0) - continue; - bkgrdflag = 0; - pfatal("CANNOT CREATE SNAPSHOT %s: %s %s\n", - snapname, strerror(errno), errmsg); - break; - } - if (bkgrdflag != 0) - filesys = snapname; + switch (setup_bkgrdchk(mntp, sbreadfailed, &filesys)) { + case -1: /* filesystem clean */ + goto clean; + case 0: /* cannot do background, give up */ + exit(EEXIT); + case 1: /* doing background check, preen rules apply */ + preen = 1; + break; } } @@ -646,6 +570,187 @@ checkfilesys(char *filesys) return (rerun ? ERERUN : 0); } +/* + * If we are to do a background check: + * Get the mount point information of the file system + * If already clean, return -1 + * Check that kernel supports background fsck + * Find or create the snapshot directory + * Create the snapshot file + * Open snapshot + * If anything fails print reason and return 0 which exits + */ +static int +setup_bkgrdchk(struct statfs *mntp, int sbreadfailed, char **filesys) +{ + struct stat snapdir; + struct group *grp; + struct iovec *iov; + char errmsg[255]; + int iovlen; + long size; + + /* Get the mount point information of the file system */ + if (mntp == NULL) { + pwarn("NOT MOUNTED, CANNOT RUN IN BACKGROUND\n"); + return (0); + } + if ((mntp->f_flags & MNT_RDONLY) != 0) { + pwarn("MOUNTED READ-ONLY, CANNOT RUN IN BACKGROUND\n"); + return (0); + } + if ((mntp->f_flags & MNT_SOFTDEP) == 0) { + pwarn("NOT USING SOFT UPDATES, CANNOT RUN IN BACKGROUND\n"); + return (0); + } + if (sbreadfailed) { + pwarn("SUPERBLOCK READ FAILED, CANNOT RUN IN BACKGROUND\n"); + return (0); + } + if ((sblock.fs_flags & FS_NEEDSFSCK) != 0) { + pwarn("FULL FSCK NEEDED, CANNOT RUN IN BACKGROUND\n"); + return (0); + } + if ((sblock.fs_flags & FS_SUJ) != 0) { + pwarn("JOURNALED FILESYSTEM, CANNOT RUN IN BACKGROUND\n"); + return (0); + } + if (skipclean && ckclean && + (sblock.fs_flags & (FS_UNCLEAN|FS_NEEDSFSCK)) == 0) { + /* + * file system is clean; + * skip snapshot and report it clean + */ + pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); + return (-1); + } + /* Check that kernel supports background fsck */ + size = MIBSIZE; + if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| + sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| + sysctlnametomib("vfs.ffs.setsize", setsize, &size) < 0 || + sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| + sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || + sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { + pwarn("KERNEL LACKS BACKGROUND FSCK SUPPORT\n"); + return (0); + } + /* + * When kernel lacks runtime bgfsck superblock summary + * adjustment functionality, it does not mean we can not + * continue, as old kernels will recompute the summary at + * mount time. However, it will be an unexpected softupdates + * inconsistency if it turns out that the summary is still + * incorrect. Set a flag so subsequent operation can know this. + */ + bkgrdsumadj = 1; + if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 || + sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 || + sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 || + sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 || + sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, + &size) < 0) { + bkgrdsumadj = 0; + pwarn("KERNEL LACKS RUNTIME SUPERBLOCK SUMMARY ADJUSTMENT " + "SUPPORT\n"); + } + /* Find or create the snapshot directory */ + snprintf(snapname, sizeof snapname, "%s/.snap", + mntp->f_mntonname); + if (stat(snapname, &snapdir) < 0) { + if (errno != ENOENT) { + pwarn("CANNOT FIND SNAPSHOT DIRECTORY %s: %s, CANNOT " + "RUN IN BACKGROUND\n", snapname, strerror(errno)); + return (0); + } + if ((grp = getgrnam("operator")) == NULL || + mkdir(snapname, 0770) < 0 || + chown(snapname, -1, grp->gr_gid) < 0 || + chmod(snapname, 0770) < 0) { + pwarn("CANNOT CREATE SNAPSHOT DIRECTORY %s: %s, " + "CANNOT RUN IN BACKGROUND\n", snapname, + strerror(errno)); + return (0); + } + } else if (!S_ISDIR(snapdir.st_mode)) { + pwarn("%s IS NOT A DIRECTORY, CANNOT RUN IN BACKGROUND\n", + snapname); + return (0); + } + /* Create the snapshot file */ + iov = NULL; + iovlen = 0; + errmsg[0] = '\0'; + snprintf(snapname, sizeof snapname, "%s/.snap/fsck_snapshot", + mntp->f_mntonname); + build_iovec(&iov, &iovlen, "fstype", "ffs", 4); + build_iovec(&iov, &iovlen, "from", snapname, (size_t)-1); + build_iovec(&iov, &iovlen, "fspath", mntp->f_mntonname, (size_t)-1); + build_iovec(&iov, &iovlen, "errmsg", errmsg, sizeof(errmsg)); + build_iovec(&iov, &iovlen, "update", NULL, 0); + build_iovec(&iov, &iovlen, "snapshot", NULL, 0); + /* Create snapshot, removing old snapshot it it exists */ + while (nmount(iov, iovlen, mntp->f_flags) < 0) { + if (errno == EEXIST && unlink(snapname) == 0) + continue; + pwarn("CANNOT CREATE SNAPSHOT %s: %s %s\n", snapname, + strerror(errno), errmsg); + return (0); + } + /* Open snapshot */ + if (openfilesys(snapname) == 0) { + unlink(snapname); + pwarn("CANNOT OPEN SNAPSHOT %s: %s, CANNOT RUN IN " + "BACKGROUND\n", snapname, strerror(errno)); + return (0); + } + free(sblock.fs_csp); + free(sblock.fs_si); + havesb = 0; + *filesys = snapname; + cmd.version = FFS_CMD_VERSION; + cmd.handle = fsreadfd; + return (1); +} + +/* + * Open a device or file to be checked by fsck. + */ +static int +openfilesys(char *dev) +{ + struct stat statb; + int saved_fsreadfd; + + if (stat(dev, &statb) < 0) { + pfatal("CANNOT STAT %s: %s\n", dev, strerror(errno)); + return (0); + } + if ((statb.st_mode & S_IFMT) != S_IFCHR && + (statb.st_mode & S_IFMT) != S_IFBLK) { + if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { + pfatal("BACKGROUND FSCK LACKS A SNAPSHOT\n"); + exit(EEXIT); + } + if (bkgrdflag != 0) { + cursnapshot = statb.st_ino; + } else { + pfatal("%s IS NOT A DISK DEVICE\n", dev); + if (reply("CONTINUE") == 0) + return (0); + } + } + saved_fsreadfd = fsreadfd; + if ((fsreadfd = open(dev, O_RDONLY)) < 0) { + fsreadfd = saved_fsreadfd; + pfatal("CANNOT OPEN %s: %s\n", dev, strerror(errno)); + return (0); + } + if (saved_fsreadfd != -1) + close(saved_fsreadfd); + return (1); +} + static int chkdoreload(struct statfs *mntp) { diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c index 0ae7f1bbb28f..506a027f40ac 100644 --- a/sbin/fsck_ffs/setup.c +++ b/sbin/fsck_ffs/setup.c @@ -76,114 +76,19 @@ static int chkrecovery(int devfd); int setup(char *dev) { - long cg, asked, i, j; - long bmapsize; - struct stat statb; + long cg, bmapsize; struct fs proto; - size_t size; - havesb = 0; - fswritefd = -1; - cursnapshot = 0; - if (stat(dev, &statb) < 0) { - printf("Can't stat %s: %s\n", dev, strerror(errno)); - if (bkgrdflag) { - unlink(snapname); - bkgrdflag = 0; - } - return (0); - } - if ((statb.st_mode & S_IFMT) != S_IFCHR && - (statb.st_mode & S_IFMT) != S_IFBLK) { - if (bkgrdflag != 0 && (statb.st_flags & SF_SNAPSHOT) == 0) { - unlink(snapname); - printf("background fsck lacks a snapshot\n"); - exit(EEXIT); - } - if ((statb.st_flags & SF_SNAPSHOT) != 0 && cvtlevel == 0) { - cursnapshot = statb.st_ino; - } else { - if (cvtlevel == 0 || - (statb.st_flags & SF_SNAPSHOT) == 0) { - if (preen && bkgrdflag) { - unlink(snapname); - bkgrdflag = 0; - } - pfatal("%s is not a disk device", dev); - if (reply("CONTINUE") == 0) { - if (bkgrdflag) { - unlink(snapname); - bkgrdflag = 0; - } - return (0); - } - } else { - if (bkgrdflag) { - unlink(snapname); - bkgrdflag = 0; - } - pfatal("cannot convert a snapshot"); - exit(EEXIT); - } - } - } - if ((fsreadfd = open(dev, O_RDONLY)) < 0) { - if (bkgrdflag) { - unlink(snapname); - bkgrdflag = 0; - } - printf("Can't open %s: %s\n", dev, strerror(errno)); + /* + * We are expected to have an open file descriptor + */ + if (fsreadfd < 0) return (0); - } - if (bkgrdflag) { - unlink(snapname); - size = MIBSIZE; - if (sysctlnametomib("vfs.ffs.adjrefcnt", adjrefcnt, &size) < 0|| - sysctlnametomib("vfs.ffs.adjblkcnt", adjblkcnt, &size) < 0|| - sysctlnametomib("vfs.ffs.setsize", setsize, &size) < 0 || - sysctlnametomib("vfs.ffs.freefiles", freefiles, &size) < 0|| - sysctlnametomib("vfs.ffs.freedirs", freedirs, &size) < 0 || - sysctlnametomib("vfs.ffs.freeblks", freeblks, &size) < 0) { - pfatal("kernel lacks background fsck support\n"); - exit(EEXIT); - } - /* - * When kernel is lack of runtime bgfsck superblock summary - * adjustment functionality, it does not mean we can not - * continue, as old kernels will recompute the summary at - * mount time. However, it will be an unexpected softupdates - * inconsistency if it turns out that the summary is still - * incorrect. Set a flag so subsequent operation can know - * this. - */ - bkgrdsumadj = 1; - if (sysctlnametomib("vfs.ffs.adjndir", adjndir, &size) < 0 || - sysctlnametomib("vfs.ffs.adjnbfree", adjnbfree, &size) < 0 || - sysctlnametomib("vfs.ffs.adjnifree", adjnifree, &size) < 0 || - sysctlnametomib("vfs.ffs.adjnffree", adjnffree, &size) < 0 || - sysctlnametomib("vfs.ffs.adjnumclusters", adjnumclusters, &size) < 0) { - bkgrdsumadj = 0; - pwarn("kernel lacks runtime superblock summary adjustment support"); - } - cmd.version = FFS_CMD_VERSION; - cmd.handle = fsreadfd; - fswritefd = -1; - } - if (preen == 0) - printf("** %s", dev); - if (bkgrdflag == 0 && - (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { - fswritefd = -1; - if (preen) - pfatal("NO WRITE ACCESS"); - printf(" (NO WRITE)"); - } - if (preen == 0) - printf("\n"); /* - * Read in the superblock, looking for alternates if necessary + * If we do not yet have a superblock, read it in looking + * for alternates if necessary. */ - if (readsb(1) == 0) { + if (havesb == 0 && readsb(1) == 0) { skipclean = 0; if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0) return(0); @@ -195,19 +100,38 @@ setup(char *dev) break; } if (cg >= proto.fs_ncg) { - printf("%s %s\n%s %s\n%s %s\n", - "SEARCH FOR ALTERNATE SUPER-BLOCK", - "FAILED. YOU MUST USE THE", - "-b OPTION TO FSCK TO SPECIFY THE", - "LOCATION OF AN ALTERNATE", - "SUPER-BLOCK TO SUPPLY NEEDED", - "INFORMATION; SEE fsck_ffs(8)."); + printf("SEARCH FOR ALTERNATE SUPER-BLOCK FAILED. " + "YOU MUST USE THE\n-b OPTION TO FSCK TO SPECIFY " + "THE LOCATION OF AN ALTERNATE\nSUPER-BLOCK TO " + "SUPPLY NEEDED INFORMATION; SEE fsck_ffs(8).\n"); bflag = 0; return(0); } pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag); bflag = 0; } + if (preen == 0) + printf("** %s", dev); + if (bkgrdflag == 0 && + (nflag || (fswritefd = open(dev, O_WRONLY)) < 0)) { + fswritefd = -1; + if (preen) + pfatal("NO WRITE ACCESS"); + printf(" (NO WRITE)"); + } + if (preen == 0) + printf("\n"); + if (sbhashfailed != 0) { + pwarn("SUPERBLOCK CHECK HASH FAILED"); + if (fswritefd == -1) + pwarn("OPENED READONLY SO CANNOT CORRECT CHECK HASH\n"); + else if (preen || reply("CORRECT CHECK HASH") != 0) { + if (preen) + printf(" (CORRECTED)\n"); + sblock.fs_clean = 0; + sbdirty(); + } + } if (skipclean && ckclean && sblock.fs_clean) { pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n"); return (-1); @@ -247,30 +171,6 @@ setup(char *dev) fswritefd != -1 && chkrecovery(fsreadfd) == 0 && reply("SAVE DATA TO FIND ALTERNATE SUPERBLOCKS") != 0) saverecovery(fsreadfd, fswritefd); - /* - * read in the summary info. - */ - asked = 0; - sblock.fs_csp = Calloc(1, sblock.fs_cssize); - if (sblock.fs_csp == NULL) { - printf("cannot alloc %u bytes for cg summary info\n", - (unsigned)sblock.fs_cssize); - goto badsb; - } - for (i = 0, j = 0; i < sblock.fs_cssize; i += sblock.fs_bsize, j++) { - size = MIN(sblock.fs_cssize - i, sblock.fs_bsize); - readcnt[sblk.b_type]++; - if (blread(fsreadfd, (char *)sblock.fs_csp + i, - fsbtodb(&sblock, sblock.fs_csaddr + j * sblock.fs_frag), - size) != 0 && !asked) { - pfatal("BAD SUMMARY INFORMATION"); - if (reply("CONTINUE") == 0) { - ckfini(0); - exit(EEXIT); - } - asked++; - } - } /* * allocate and initialize the necessary maps */ @@ -320,13 +220,17 @@ readsb(int listerr) int bad, ret; struct fs *fs; - super = bflag ? bflag * dev_bsize : STDSB_NOHASHFAIL; + super = bflag ? bflag * dev_bsize : + sbhashfailed ? STDSB_NOHASHFAIL_NOMSG : STDSB_NOMSG; readcnt[sblk.b_type]++; - if ((ret = sbget(fsreadfd, &fs, super)) != 0) { + while ((ret = sbget(fsreadfd, &fs, super)) != 0) { switch (ret) { - case EINVAL: - /* Superblock check-hash failed */ - return (0); + case EINTEGRITY: + if (bflag || super == STDSB_NOHASHFAIL_NOMSG) + return (0); + super = STDSB_NOHASHFAIL_NOMSG; + sbhashfailed = 1; + continue; case ENOENT: if (bflag) printf("%jd is not a file system "