mirror of
https://github.com/opnsense/src.git
synced 2026-05-28 04:12:45 -04:00
Have fsck_ffs(8) properly correct superblock check-hash failures.
(cherry picked from commit c0bfa109b9)
PR: 245916
This commit is contained in:
parent
7deb47265d
commit
efd949aaba
5 changed files with 261 additions and 247 deletions
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -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)
|
||||
{
|
||||
|
|
|
|||
|
|
@ -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…
Reference in a new issue