Move the ability to search for alternate UFS superblocks from fsck_ffs(8)

into ffs_sbsearch() to allow use by other parts of the system.

Historically only fsck_ffs(8), the UFS filesystem checker, had code
to track down and use alternate UFS superblocks. Since fsdb(8) used
much of the fsck_ffs(8) implementation it had some ability to track
down alternate superblocks.

This change extracts the code to track down alternate superblocks
from fsck_ffs(8) and puts it into a new function ffs_sbsearch() in
sys/ufs/ffs/ffs_subr.c. Like ffs_sbget() and ffs_sbput() also found
in ffs_subr.c, these functions can be used directly by the kernel
subsystems. Additionally they are exported to the UFS library,
libufs(8) so that they can be used by user-level programs. The new
functions added to libufs(8) are sbfind(3) that is an alternative
to sbread(3) and sbsearch(3) that is an alternative to sbget(3).
See their manual pages for further details.

The utilities that have been changed to search for superblocks are
dumpfs(8), fsdb(8), ffsinfo(8), and fsck_ffs(8). Also, the prtblknos(8)
tool found in tools/diag/prtblknos searches for superblocks.

The UFS specific mount code uses the superblock search interface
when mounting the root filesystem and when the administrator doing
a mount(8) command specifies the force flag (-f). The standalone UFS
boot code (found in stand/libsa/ufs.c) uses the superblock search
code in the hope of being able to get the system up and running so
that fsck_ffs(8) can be used to get the filesystem cleaned up.

The following utilities have not been changed to search for
superblocks: clri(8), tunefs(8), snapinfo(8), fstyp(8), quot(8),
dump(8), fsirand(8), growfs(8), quotacheck(8), gjournal(8), and
glabel(8). When these utilities fail, they do report the cause of
the failure. The one exception is the tasting code used to try and
figure what a given disk contains. The tasting code will remain
silent so as not to put out a slew of messages as it trying to taste
every new mass storage device that shows up.

Reviewed by: kib
Reviewed by: Warner Losh
Tested by:   Peter Holm
Differential Revision: https://reviews.freebsd.org/D36053
Sponsored by: The FreeBSD Foundation
This commit is contained in:
Kirk McKusick 2022-08-13 12:41:53 -07:00
parent 88951aaaee
commit e688661642
17 changed files with 364 additions and 100 deletions

View File

@ -20,6 +20,8 @@ MLINKS+= cgread.3 cgput.3
MLINKS+= getinode.3 putinode.3
MLINKS+= sbread.3 sbwrite.3
MLINKS+= sbread.3 sbget.3
MLINKS+= sbread.3 sbsearch.3
MLINKS+= sbread.3 sbfind.3
MLINKS+= sbread.3 sbput.3
MLINKS+= ufs_disk_close.3 ufs_disk_fillout.3
MLINKS+= ufs_disk_close.3 ufs_disk_fillout_blank.3

View File

@ -111,6 +111,8 @@ void ffs_clusteracct(struct fs *, struct cg *, ufs1_daddr_t, int);
void ffs_fragacct(struct fs *, int, int32_t [], int);
int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t);
int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t);
int ffs_sbsearch(void *, struct fs **, int, char *,
int (*)(void *, off_t, void **, int));
void ffs_setblock(struct fs *, u_char *, ufs1_daddr_t);
int ffs_sbget(void *, struct fs **, off_t, int, char *,
int (*)(void *, off_t, void **, int));
@ -149,9 +151,11 @@ int putinode(struct uufsd *);
* sblock.c
*/
int sbread(struct uufsd *);
int sbfind(struct uufsd *, int);
int sbwrite(struct uufsd *, int);
/* low level superblock read/write functions */
int sbget(int, struct fs **, off_t, int);
int sbsearch(int, struct fs **, int);
int sbput(int, struct fs *, int);
/*

View File

@ -73,6 +73,30 @@ sbread(struct uufsd *disk)
return (handle_disk_read(disk, fs, error));
}
/*
* Make an extensive search to find a superblock. If the superblock
* in the standard place cannot be used, try looking for one of the
* backup superblocks.
*
* The flags parameter is made up of the following or'ed together options:
*
* UFS_NOMSG indicates that superblock inconsistency error messages
* should not be printed.
*
* UFS_NOCSUM causes only the superblock itself to be returned, but does
* not read in any auxillary data structures like the cylinder group
* summary information.
*/
int
sbfind(struct uufsd *disk, int flags)
{
struct fs *fs;
int error;
error = sbsearch(disk->d_fd, &fs, flags);
return (handle_disk_read(disk, fs, error));
}
static int
handle_disk_read(struct uufsd *disk, struct fs *fs, int error)
{
@ -174,8 +198,27 @@ static int use_pwrite(void *devfd, off_t loc, void *buf, int size);
int
sbget(int devfd, struct fs **fsp, off_t sblockloc, int flags)
{
int error;
return (ffs_sbget(&devfd, fsp, sblockloc, flags, "user", use_pread));
error = ffs_sbget(&devfd, fsp, sblockloc, flags, "user", use_pread);
fflush(NULL); /* flush any messages */
return (error);
}
/*
* Make an extensive search of the devfd device to find a superblock.
* If the superblock in the standard place cannot be used, try looking
* for one of the backup superblocks. If found, memory is allocated and
* returned in fsp.
*/
int
sbsearch(int devfd, struct fs **fsp, int flags)
{
int error;
error = ffs_sbsearch(&devfd, fsp, flags, "user", use_pread);
fflush(NULL); /* flush any messages */
return (error);
}
/*
@ -209,11 +252,10 @@ sbput(int devfd, struct fs *fs, int numaltwrite)
off_t savedactualloc;
int i, error;
if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc,
use_pwrite)) != 0)
error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc, use_pwrite);
fflush(NULL); /* flush any messages */
if (error != 0 || numaltwrite == 0)
return (error);
if (numaltwrite == 0)
return (0);
savedactualloc = fs->fs_sblockactualloc;
if (fs->fs_si != NULL) {
savedcsp = fs->fs_csp;
@ -223,6 +265,7 @@ sbput(int devfd, struct fs *fs, int numaltwrite)
fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i)));
if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc,
use_pwrite)) != 0) {
fflush(NULL); /* flush any messages */
fs->fs_sblockactualloc = savedactualloc;
fs->fs_csp = savedcsp;
return (error);
@ -231,6 +274,7 @@ sbput(int devfd, struct fs *fs, int numaltwrite)
fs->fs_sblockactualloc = savedactualloc;
if (fs->fs_si != NULL)
fs->fs_csp = savedcsp;
fflush(NULL); /* flush any messages */
return (0);
}

View File

@ -3,19 +3,21 @@
.\" Description:
.\" Manual page for libufs functions:
.\" sbget(3)
.\" sbsearch(3)
.\" sbput(3)
.\" sbread(3)
.\" sbfind(3)
.\" sbwrite(3)
.\"
.\" This file is in the public domain.
.\"
.\" $FreeBSD$
.\"
.Dd September 2, 2020
.Dd August 8, 2022
.Dt SBREAD 3
.Os
.Sh NAME
.Nm sbget , sbput , sbread , sbwrite
.Nm sbget , sbsearch , sbput , sbread , sbfind , sbwrite
.Nd read and write superblocks of a UFS file system
.Sh LIBRARY
.Lb libufs
@ -29,16 +31,22 @@
.Ft int
.Fn sbget "int devfd" "struct fs **fsp" "off_t sblockloc" "int flags"
.Ft int
.Fn sbsearch "int devfd" "struct fs **fsp" "int flags"
.Ft int
.Fn sbput "int devfd" "struct fs *fs" "int numaltwrite"
.Ft int
.Fn sbread "struct uufsd *disk"
.Ft int
.Fn sbfind "struct uufsd *disk" "int flags"
.Ft int
.Fn sbwrite "struct uufsd *disk" "int all"
.Sh DESCRIPTION
The
.Fn sbget
.Fn sbget ,
.Fn sbsearch ,
.Fn sbread ,
and
.Fn sbread
.Fn sbfind
functions provide superblock reads for
.Xr libufs 3
consumers.
@ -52,7 +60,9 @@ consumers.
.Pp
The
.Fn sbget
function first allocates a buffer to hold the superblock.
and
.Fn sbsearch
functions first allocate a buffer to hold the superblock.
Using the
.Va devfd
file descriptor that references the filesystem disk,
@ -65,26 +75,38 @@ The value
may be specified for
.Va sblockloc
to request that the standard location for the superblock be read.
The
.Fn sbsearch
function uses the
.Va devfd
file descriptor that references the filesystem disk,
to search first for the superblock at the standard location.
If it is not found or is too damaged to use
.Fn sbsearch
will attempt to find one of the filesystem's alternate superblocks.
Flags are specified by
.Em or Ns 'ing
the following values:
.Pp
.Bl -tag -width UFS_NOHASHFAIL
.It Cm UFS_NOHASHFAIL
Will note if the check hash is wrong but will still return the superblock.
.Bl -tag -width UFS_NOCSUM
.It Cm UFS_NOCSUM
Causes only the superblock itself to be returned, but does not read in any
auxiliary data structures like the cylinder group summary information.
.It Cm UFS_NOMSG
Indicates that superblock inconsistency error messages should not be printed.
.It Cm UFS_NOCSUM
Causes only the superblock itself to be returned, but does not read in any auxiliary data structures like the cylinder group summary information.
.El
.Pp
If successful,
.Fn sbget
returns a pointer to the buffer containing the superblock in
and
.Fn sbsearch
functions return a pointer to the buffer containing the superblock in
.Va fsp .
The
.Fn sbget
function is safe to use in threaded applications.
and
.Fn sbsearch
functions are safe to use in threaded applications.
.Pp
The
.Fn sbput
@ -113,7 +135,19 @@ modified and the on-disk copy needs to be updated.
.Pp
The
.Fn sbread
function reads the standard filesystem superblock into the
function reads the standard filesystem superblock.
The
.Fn sbfind
function tries to find a usable superblock.
It searchs first for the superblock at the standard location.
If it is not found or is too damaged to use
.Fn sbfind
will attempt to find one of the filesystem's alternate superblocks.
If successful
.Fn sbread
and
.Fn sbfind
return a superblock in the
.Va d_sb ,
structure embedded in the given user-land UFS disk structure.
.Pp
@ -131,16 +165,19 @@ value is non-zero.
.Sh RETURN VALUES
.Rv -std sbread sbwrite
The
.Fn sbget
.Fn sbget ,
.Fn sbsearch ,
and
.Fn sbput
functions return the value 0 if successful;
otherwise they return one of the errors described below.
.Sh ERRORS
The errors returned by
.Fn sbget
.Fn sbget ,
.Fn sbsearch ,
.Fn sbread ,
and
.Fn sbread
.Fn sbfind ,
include any of the errors specified for the library function
.Xr bread 3 .
Additionally, they may follow the

View File

@ -130,13 +130,8 @@ main(int argc, char *argv[])
usage();
while ((name = *argv++) != NULL) {
if (ufs_disk_fillout_blank(&disk, name) == -1) {
ufserr(name);
eval |= 1;
continue;
}
disk.d_lookupflags |= UFS_NOHASHFAIL;
if (sbread(&disk) == -1) {
if (ufs_disk_fillout_blank(&disk, name) == -1 ||
sbfind(&disk, 0) == -1) {
ufserr(name);
eval |= 1;
continue;

View File

@ -223,8 +223,9 @@ main(int argc, char **argv)
device = special;
}
if (ufs_disk_fillout(&disk, device) == -1)
err(1, "ufs_disk_fillout(%s) failed: %s", device, disk.d_error);
if (ufs_disk_fillout_blank(&disk, device) == -1 ||
sbfind(&disk, 0) == -1)
err(1, "superblock fetch(%s) failed: %s", device, disk.d_error);
DBG_OPEN(out_file); /* already here we need a superblock */

View File

@ -363,7 +363,6 @@ extern char preen; /* just fix normal inconsistencies */
extern char rerun; /* rerun fsck. Only used in non-preen mode */
extern char resolved; /* cleared if unresolved changes => not clean */
extern int returntosingle; /* 1 => return to single user mode on exit */
extern int sbhashfailed; /* when reading superblock check hash failed */
extern long secsize; /* actual disk sector size */
extern char skipclean; /* skip clean file systems if preening */
extern char snapname[BUFSIZ]; /* when doing snapshots, the name of the file */
@ -502,7 +501,7 @@ void pfatal(const char *fmt, ...) __printflike(1, 2);
void propagate(void);
void prtinode(struct inode *);
void pwarn(const char *fmt, ...) __printflike(1, 2);
int readsb(int listerr);
int readsb(void);
int reply(const char *question);
void rwerror(const char *mesg, ufs2_daddr_t blk);
void sblock_init(void);

View File

@ -96,7 +96,6 @@ 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 */
@ -156,7 +155,6 @@ fsckinit(void)
resolved = 0;
havesb = 0;
fsmodified = 0;
sbhashfailed = 0;
fsreadfd = -1;
fswritefd = -1;
maxfsblock = 0;

View File

@ -271,7 +271,7 @@ checkfilesys(char *filesys)
*/
sblock_init();
sbreadfailed = 0;
if (openfilesys(filesys) == 0 || readsb(0) == 0)
if (openfilesys(filesys) == 0 || readsb() == 0)
sbreadfailed = 1;
if (bkgrdcheck) {
if (sbreadfailed)

View File

@ -60,6 +60,7 @@ __FBSDID("$FreeBSD$");
struct inoinfo **inphead, **inpsort; /* info about all inodes */
static int sbhashfailed;
#define POWEROF2(num) (((num) & ((num) - 1)) == 0)
static int calcsb(char *dev, int devfd, struct fs *fs);
@ -74,39 +75,15 @@ static int chkrecovery(int devfd);
int
setup(char *dev)
{
long cg, bmapsize;
struct fs proto;
long bmapsize;
/*
* We are expected to have an open file descriptor
* We are expected to have an open file descriptor and a superblock.
*/
if (fsreadfd < 0)
if (fsreadfd < 0 || havesb == 0) {
if (debug)
printf("setup: bad fsreadfd or missing superblock\n");
return (0);
/*
* 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 (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);
}
pwarn("USING ALTERNATE SUPERBLOCK AT %jd\n", bflag);
bflag = 0;
}
if (preen == 0)
printf("** %s", dev);
@ -243,40 +220,64 @@ openfilesys(char *dev)
* Read in the super block and its summary info.
*/
int
readsb(int listerr)
readsb(void)
{
off_t super;
int ret, flags;
struct fs *fs;
super = bflag ? bflag * dev_bsize : UFS_STDSB;
flags = sbhashfailed ? UFS_NOHASHFAIL | UFS_NOMSG : UFS_NOMSG;
sbhashfailed = 0;
readcnt[sblk.b_type]++;
while ((ret = sbget(fsreadfd, &fs, super, flags)) != 0) {
switch (ret) {
/*
* If bflag is given, then check just that superblock.
*/
if (bflag) {
switch (sbget(fsreadfd, &fs, bflag * dev_bsize, UFS_NOMSG)) {
case 0:
goto goodsb;
case EINTEGRITY:
if (bflag || (super == UFS_STDSB &&
flags == (UFS_NOHASHFAIL | UFS_NOMSG)))
return (0);
super = UFS_STDSB;
flags = UFS_NOHASHFAIL | UFS_NOMSG;
sbhashfailed = 1;
continue;
printf("Check hash failed for superblock at %jd\n",
bflag);
return (0);
case ENOENT:
if (bflag)
printf("%jd is not a file system "
"superblock\n", super / dev_bsize);
else
printf("Cannot find file system "
"superblock\n");
printf("%jd is not a file system superblock\n", bflag);
return (0);
case EIO:
default:
printf("I/O error reading %jd\n",
super / dev_bsize);
printf("I/O error reading %jd\n", bflag);
return (0);
}
}
/*
* Check for the standard superblock and use it if good.
*/
if (sbget(fsreadfd, &fs, UFS_STDSB, UFS_NOMSG) == 0)
goto goodsb;
/*
* Check if the only problem is a check-hash failure.
*/
skipclean = 0;
if (sbget(fsreadfd, &fs, UFS_STDSB, UFS_NOMSG | UFS_NOHASHFAIL) == 0) {
sbhashfailed = 1;
goto goodsb;
}
/*
* Do an exhaustive search for a usable superblock.
*/
switch (sbsearch(fsreadfd, &fs, 0)) {
case 0:
goto goodsb;
case ENOENT:
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");
return (0);
case EIO:
default:
printf("I/O error reading a usable superblock\n");
return (0);
}
goodsb:
memcpy(&sblock, fs, fs->fs_sbsize);
free(fs);
/*

View File

@ -111,7 +111,7 @@ main(int argc, char *argv[])
fsys = argv[0];
sblock_init();
if (openfilesys(fsys) == 0 || readsb(0) == 0 || setup(fsys) == 0)
if (openfilesys(fsys) == 0 || readsb() == 0 || setup(fsys) == 0)
errx(1, "cannot set up file system `%s'", fsys);
if (fswritefd < 0)
nflag++;

View File

@ -151,7 +151,7 @@ static int search_directory(char *, struct open_file *, ino_t *);
static int ufs_use_sa_read(void *, off_t, void **, int);
/* from ffs_subr.c */
int ffs_sbget(void *, struct fs **, off_t, int, char *,
int ffs_sbsearch(void *, struct fs **, int, char *,
int (*)(void *, off_t, void **, int));
/*
@ -529,8 +529,8 @@ ufs_open(const char *upath, struct open_file *f)
if (mnt == NULL) {
/* read super block */
twiddle(1);
if ((rc = ffs_sbget(f, &fs, UFS_STDSB, UFS_NOHASHFAIL, "stand",
ufs_use_sa_read)) != 0) {
if ((rc = ffs_sbsearch(f, &fs, 0, "stand", ufs_use_sa_read))
!= 0) {
goto out;
}
} else {

View File

@ -86,6 +86,8 @@ int ffs_isblock(struct fs *, u_char *, ufs1_daddr_t);
int ffs_isfreeblock(struct fs *, u_char *, ufs1_daddr_t);
void ffs_oldfscompat_write(struct fs *, struct ufsmount *);
int ffs_own_mount(const struct mount *mp);
int ffs_sbsearch(void *, struct fs **, int, struct malloc_type *,
int (*)(void *, off_t, void **, int));
int ffs_reallocblks(struct vop_reallocblks_args *);
int ffs_realloccg(struct inode *, ufs2_daddr_t, ufs2_daddr_t,
ufs2_daddr_t, int, int, int, struct ucred *, struct buf **);

View File

@ -378,6 +378,40 @@ validate_sblock(struct fs *fs, int flags)
prtmsg = ((flags & UFS_NOMSG) == 0);
warnerr = (flags & UFS_NOWARNFAIL) == UFS_NOWARNFAIL ? 0 : ENOENT;
wmsg = warnerr ? "" : " (Ignored)";
/*
* If just validating for recovery, then do just the minimal
* checks needed for the superblock fields needed to find
* alternate superblocks.
*/
if ((flags & UFS_FSRONLY) == UFS_FSRONLY &&
(fs->fs_magic == FS_UFS1_MAGIC || fs->fs_magic == FS_UFS2_MAGIC)) {
if (fs->fs_magic == FS_UFS2_MAGIC) {
FCHK(fs->fs_sblockloc, !=, SBLOCK_UFS2, %#jx);
} else if (fs->fs_magic == FS_UFS1_MAGIC) {
FCHK(fs->fs_sblockloc, <, 0, %jd);
FCHK(fs->fs_sblockloc, >, SBLOCK_UFS1, %jd);
}
FCHK(fs->fs_frag, <, 1, %jd);
FCHK(fs->fs_frag, >, MAXFRAG, %jd);
FCHK(fs->fs_bsize, <, MINBSIZE, %jd);
FCHK(fs->fs_bsize, >, MAXBSIZE, %jd);
FCHK(fs->fs_bsize, <, roundup(sizeof(struct fs), DEV_BSIZE),
%jd);
FCHK(fs->fs_fsize, <, sectorsize, %jd);
FCHK(fs->fs_fsize * fs->fs_frag, !=, fs->fs_bsize, %jd);
FCHK(powerof2(fs->fs_fsize), ==, 0, %jd);
FCHK(fs->fs_fpg, <, 3 * fs->fs_frag, %jd);
FCHK(fs->fs_ncg, <, 1, %jd);
FCHK(fs->fs_fsbtodb, !=, ILOG2(fs->fs_fsize / sectorsize), %jd);
FCHK(fs->fs_old_cgoffset, <, 0, %jd);
FCHK2(fs->fs_old_cgoffset, >, 0, ~fs->fs_old_cgmask, <, 0, %jd);
FCHK(fs->fs_old_cgoffset * (~fs->fs_old_cgmask), >, fs->fs_fpg,
%jd);
FCHK(fs->fs_sblkno, !=, roundup(
howmany(fs->fs_sblockloc + SBLOCKSIZE, fs->fs_fsize),
fs->fs_frag), %jd);
return (error);
}
if (fs->fs_magic == FS_UFS2_MAGIC) {
if ((flags & UFS_ALTSBLK) == 0)
FCHK2(fs->fs_sblockactualloc, !=, SBLOCK_UFS2,
@ -530,6 +564,146 @@ validate_sblock(struct fs *fs, int flags)
return (error);
}
/*
* Make an extensive search to find a superblock. If the superblock
* in the standard place cannot be used, try looking for one of the
* backup superblocks.
*
* Flags are made up of the following or'ed together options:
*
* UFS_NOMSG indicates that superblock inconsistency error messages
* should not be printed.
*
* UFS_NOCSUM causes only the superblock itself to be returned, but does
* not read in any auxillary data structures like the cylinder group
* summary information.
*/
int
ffs_sbsearch(void *devfd, struct fs **fsp, int reqflags,
struct malloc_type *filltype,
int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
{
struct fsrecovery *fsr;
struct fs *protofs;
void *fsrbuf;
char *cp;
long nocsum, flags, msg, cg;
off_t sblk, secsize;
int error;
msg = (reqflags & UFS_NOMSG) == 0;
nocsum = reqflags & UFS_NOCSUM;
/*
* Try normal superblock read and return it if it works.
*
* Suppress messages if it fails until we find out if
* failure can be avoided.
*/
flags = UFS_NOMSG | nocsum;
if (ffs_sbget(devfd, fsp, UFS_STDSB, flags, filltype, readfunc) == 0)
return (0);
/*
* First try: ignoring hash failures.
*/
flags |= UFS_NOHASHFAIL;
if (msg)
flags &= ~UFS_NOMSG;
if (ffs_sbget(devfd, fsp, UFS_STDSB, flags, filltype, readfunc) == 0)
return (0);
/*
* Next up is to check if fields of the superblock that are
* needed to find backup superblocks are usable.
*/
if (msg)
printf("Attempted recovery for standard superblock: failed\n");
flags = UFS_FSRONLY | UFS_NOHASHFAIL | UFS_NOMSG;
if (ffs_sbget(devfd, &protofs, UFS_STDSB, flags, filltype,
readfunc) == 0) {
if (msg)
printf("Attempted extraction of recovery data from "
"standard superblock: ");
} else {
/*
* Final desperation is to see if alternate superblock
* parameters have been saved in the boot area.
*/
if (msg)
printf("Attempted extraction of recovery data from "
"standard superblock: failed\nAttempt to find "
"boot zone recovery data: ");
/*
* Look to see if recovery information has been saved.
* If so we can generate a prototype superblock based
* on that information.
*
* We need fragments-per-group, number of cylinder groups,
* location of the superblock within the cylinder group, and
* the conversion from filesystem fragments to disk blocks.
*
* When building a UFS2 filesystem, newfs(8) stores these
* details at the end of the boot block area at the start
* of the filesystem partition. If they have been overwritten
* by a boot block, we fail. But usually they are there
* and we can use them.
*
* We could ask the underlying device for its sector size,
* but some devices lie. So we just try a plausible range.
*/
error = ENOENT;
for (secsize = dbtob(1); secsize <= SBLOCKSIZE; secsize *= 2)
if ((error = (*readfunc)(devfd, (SBLOCK_UFS2 - secsize),
&fsrbuf, secsize)) == 0)
break;
if (error != 0)
goto trynowarn;
cp = fsrbuf; /* type change to keep compiler happy */
fsr = (struct fsrecovery *)&cp[secsize - sizeof *fsr];
if (fsr->fsr_magic != FS_UFS2_MAGIC ||
(protofs = UFS_MALLOC(SBLOCKSIZE, filltype, M_NOWAIT))
== NULL) {
UFS_FREE(fsrbuf, filltype);
goto trynowarn;
}
memset(protofs, 0, sizeof(struct fs));
protofs->fs_fpg = fsr->fsr_fpg;
protofs->fs_fsbtodb = fsr->fsr_fsbtodb;
protofs->fs_sblkno = fsr->fsr_sblkno;
protofs->fs_magic = fsr->fsr_magic;
protofs->fs_ncg = fsr->fsr_ncg;
UFS_FREE(fsrbuf, filltype);
}
/*
* Scan looking for alternative superblocks.
*/
for (cg = 0; cg < protofs->fs_ncg; cg++) {
sblk = dbtob(fsbtodb(protofs, cgsblock(protofs, cg)));
if (ffs_sbget(devfd, fsp, sblk, UFS_NOMSG | nocsum, filltype,
readfunc) == 0) {
if (msg)
printf("succeeded with alternate superblock "
"at %jd\n", (intmax_t)btodb(sblk));
UFS_FREE(protofs, filltype);
return (0);
}
}
UFS_FREE(protofs, filltype);
/*
* Our alternate superblock strategies failed. Our last ditch effort
* is to see if the standard superblock has only non-critical errors.
*/
trynowarn:
flags = UFS_NOWARNFAIL | UFS_NOMSG | nocsum;
if (msg) {
printf("failed\n");
flags &= ~UFS_NOMSG;
}
if (ffs_sbget(devfd, fsp, UFS_STDSB, flags, filltype, readfunc) != 0)
return (ENOENT);
if (msg)
printf("Using standard superblock with non-critical errors.\n");
return (0);
}
/*
* Write a superblock to the devfd device from the memory pointed to by fs.
* Write out the superblock summary information if it is present.

View File

@ -913,8 +913,7 @@ ffs_mountfs(struct vnode *odevvp, struct mount *mp, struct thread *td)
struct g_consumer *cp;
struct mount *nmp;
struct vnode *devvp;
int candelete, canspeedup, flags;
off_t loc;
int candelete, canspeedup;
fs = NULL;
ump = NULL;
@ -958,12 +957,12 @@ ffs_mountfs(struct vnode *odevvp, struct mount *mp, struct thread *td)
goto out;
}
/* fetch the superblock and summary information */
loc = UFS_STDSB;
flags = 0;
if ((mp->mnt_flag & (MNT_ROOTFS | MNT_FORCE)) != 0)
flags = UFS_NOHASHFAIL;
if ((error = ffs_sbget(devvp, &fs, loc, flags, M_UFSMNT, ffs_use_bread))
!= 0)
error = ffs_sbsearch(devvp, &fs, 0, M_UFSMNT, ffs_use_bread);
else
error = ffs_sbget(devvp, &fs, UFS_STDSB, 0, M_UFSMNT,
ffs_use_bread);
if (error != 0)
goto out;
fs->fs_flags &= ~FS_UNCLEAN;
if (fs->fs_clean == 0) {

View File

@ -102,11 +102,19 @@
* UFS_NOWARNFAIL will warn about inconsistencies but still return the
* superblock. It includes UFS_NOHASHFAIL. UFS_NOWARNFAIL is used by
* programs like fsck_ffs(8) to debug broken filesystems.
*
* UFS_FSRONLY will only validate the superblock fields needed to
* calculate where the backup filesystem superblocks are located.
* If these values pass their validation tests, then the superblock
* is returned. This flag is used as part of the attempt to find
* alternate superblocks when using ffs_sbsearch().
*/
#define UFS_NOHASHFAIL 0x0001 /* Ignore check-hash failure */
#define UFS_NOWARNFAIL 0x0003 /* Ignore non-fatal inconsistencies */
#define UFS_NOMSG 0x0004 /* Print no error message */
#define UFS_NOCSUM 0x0008 /* Read just the superblock without csum */
#define UFS_FSRONLY 0x0010 /* Validate only values needed for recovery
of alternate superblocks */
#define UFS_ALTSBLK 0x1000 /* Flag used internally */
/*

View File

@ -56,7 +56,6 @@ main(argc, argv)
char ibuf[64];
char *fsname, *filename;
ino_t inonum;
int error;
filename = NULL;
if (argc == 2) {
@ -83,7 +82,8 @@ main(argc, argv)
fsname = *++argv;
/* get the superblock. */
if ((error = ufs_disk_fillout(&disk, fsname)) < 0)
if (ufs_disk_fillout_blank(&disk, fsname) == -1 ||
sbfind(&disk, 0) == -1)
err(1, "Cannot access file system superblock on %s", fsname);
fs = (struct fs *)&disk.d_sb;
@ -99,7 +99,7 @@ main(argc, argv)
(void)printf("%s (inode #%jd): ", filename,
(intmax_t)inonum);
if ((error = getinode(&disk, &dp, inonum)) < 0)
if (getinode(&disk, &dp, inonum) < 0)
warn("Read of inode %jd on %s failed: %s",
(intmax_t)inonum, fsname, disk.d_error);