Have fsck_ffs(8) properly correct superblock check-hash failures.
Part of the problem was that fsck_ffs would read the superblock multiple times complaining and repairing the superblock check hash each time and then at the end failing to write out the superblock with the corrected check hash. This fix reads the superblock just once and if the check hash is corrected ensures that the fixed superblock gets written. Tested by: Peter Holm PR: 245916 MFC after: 1 week Sponsored by: Netflix
This commit is contained in:
parent
930a7c2ac6
commit
c0bfa109b9
@ -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 */
|
||||
|
@ -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",
|
||||
|
@ -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;
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -648,6 +572,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)
|
||||
{
|
||||
|
@ -76,98 +76,39 @@ 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;
|
||||
}
|
||||
/*
|
||||
* We are expected to have an open file descriptor
|
||||
*/
|
||||
if (fsreadfd < 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 we do not yet have a superblock, read it in looking
|
||||
* for alternates if necessary.
|
||||
*/
|
||||
if (havesb == 0 && readsb(1) == 0) {
|
||||
skipclean = 0;
|
||||
if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
|
||||
return(0);
|
||||
if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
|
||||
return (0);
|
||||
for (cg = 0; cg < proto.fs_ncg; cg++) {
|
||||
bflag = fsbtodb(&proto, cgsblock(&proto, cg));
|
||||
if (readsb(0) != 0)
|
||||
break;
|
||||
}
|
||||
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 (cg >= proto.fs_ncg) {
|
||||
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);
|
||||
}
|
||||
}
|
||||
if ((fsreadfd = open(dev, O_RDONLY)) < 0) {
|
||||
if (bkgrdflag) {
|
||||
unlink(snapname);
|
||||
bkgrdflag = 0;
|
||||
}
|
||||
printf("Can't open %s: %s\n", dev, strerror(errno));
|
||||
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;
|
||||
pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag);
|
||||
bflag = 0;
|
||||
}
|
||||
if (preen == 0)
|
||||
printf("** %s", dev);
|
||||
@ -180,33 +121,16 @@ setup(char *dev)
|
||||
}
|
||||
if (preen == 0)
|
||||
printf("\n");
|
||||
/*
|
||||
* Read in the superblock, looking for alternates if necessary
|
||||
*/
|
||||
if (readsb(1) == 0) {
|
||||
skipclean = 0;
|
||||
if (bflag || preen || calcsb(dev, fsreadfd, &proto) == 0)
|
||||
return(0);
|
||||
if (reply("LOOK FOR ALTERNATE SUPERBLOCKS") == 0)
|
||||
return (0);
|
||||
for (cg = 0; cg < proto.fs_ncg; cg++) {
|
||||
bflag = fsbtodb(&proto, cgsblock(&proto, cg));
|
||||
if (readsb(0) != 0)
|
||||
break;
|
||||
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 (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).");
|
||||
bflag = 0;
|
||||
return(0);
|
||||
}
|
||||
pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag);
|
||||
bflag = 0;
|
||||
}
|
||||
if (skipclean && ckclean && sblock.fs_clean) {
|
||||
pwarn("FILE SYSTEM CLEAN; SKIPPING CHECKS\n");
|
||||
@ -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 "
|
||||
|
Loading…
x
Reference in New Issue
Block a user