Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F167581715
D36053.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
24 KB
Referenced Files
None
Subscribers
None
D36053.diff
View Options
diff --git a/lib/libufs/Makefile b/lib/libufs/Makefile
--- a/lib/libufs/Makefile
+++ b/lib/libufs/Makefile
@@ -20,6 +20,8 @@
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
diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h
--- a/lib/libufs/libufs.h
+++ b/lib/libufs/libufs.h
@@ -111,6 +111,8 @@
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 @@
* 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);
/*
diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c
--- a/lib/libufs/sblock.c
+++ b/lib/libufs/sblock.c
@@ -73,6 +73,30 @@
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 @@
int
sbget(int devfd, struct fs **fsp, off_t sblockloc, int flags)
{
+ int error;
+
+ 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;
- return (ffs_sbget(&devfd, fsp, sblockloc, flags, "user", use_pread));
+ error = ffs_sbsearch(&devfd, fsp, flags, "user", use_pread);
+ fflush(NULL); /* flush any messages */
+ return (error);
}
/*
@@ -209,11 +252,10 @@
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 @@
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 @@
fs->fs_sblockactualloc = savedactualloc;
if (fs->fs_si != NULL)
fs->fs_csp = savedcsp;
+ fflush(NULL); /* flush any messages */
return (0);
}
diff --git a/lib/libufs/sbread.3 b/lib/libufs/sbread.3
--- a/lib/libufs/sbread.3
+++ b/lib/libufs/sbread.3
@@ -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 @@
.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 @@
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 @@
.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 @@
.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
diff --git a/sbin/dumpfs/dumpfs.c b/sbin/dumpfs/dumpfs.c
--- a/sbin/dumpfs/dumpfs.c
+++ b/sbin/dumpfs/dumpfs.c
@@ -130,13 +130,8 @@
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;
diff --git a/sbin/ffsinfo/ffsinfo.c b/sbin/ffsinfo/ffsinfo.c
--- a/sbin/ffsinfo/ffsinfo.c
+++ b/sbin/ffsinfo/ffsinfo.c
@@ -223,8 +223,9 @@
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 */
diff --git a/sbin/fsck_ffs/fsck.h b/sbin/fsck_ffs/fsck.h
--- a/sbin/fsck_ffs/fsck.h
+++ b/sbin/fsck_ffs/fsck.h
@@ -363,7 +363,6 @@
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 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);
diff --git a/sbin/fsck_ffs/globs.c b/sbin/fsck_ffs/globs.c
--- a/sbin/fsck_ffs/globs.c
+++ b/sbin/fsck_ffs/globs.c
@@ -96,7 +96,6 @@
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 @@
resolved = 0;
havesb = 0;
fsmodified = 0;
- sbhashfailed = 0;
fsreadfd = -1;
fswritefd = -1;
maxfsblock = 0;
diff --git a/sbin/fsck_ffs/main.c b/sbin/fsck_ffs/main.c
--- a/sbin/fsck_ffs/main.c
+++ b/sbin/fsck_ffs/main.c
@@ -271,7 +271,7 @@
*/
sblock_init();
sbreadfailed = 0;
- if (openfilesys(filesys) == 0 || readsb(0) == 0)
+ if (openfilesys(filesys) == 0 || readsb() == 0)
sbreadfailed = 1;
if (bkgrdcheck) {
if (sbreadfailed)
diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c
--- a/sbin/fsck_ffs/setup.c
+++ b/sbin/fsck_ffs/setup.c
@@ -60,6 +60,7 @@
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 @@
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 @@
* 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);
/*
diff --git a/sbin/fsdb/fsdb.c b/sbin/fsdb/fsdb.c
--- a/sbin/fsdb/fsdb.c
+++ b/sbin/fsdb/fsdb.c
@@ -111,7 +111,7 @@
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++;
diff --git a/stand/libsa/ufs.c b/stand/libsa/ufs.c
--- a/stand/libsa/ufs.c
+++ b/stand/libsa/ufs.c
@@ -151,7 +151,7 @@
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 @@
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 {
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -86,6 +86,8 @@
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 **);
diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c
--- a/sys/ufs/ffs/ffs_subr.c
+++ b/sys/ufs/ffs/ffs_subr.c
@@ -378,6 +378,40 @@
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 @@
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.
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -913,8 +913,7 @@
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 @@
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) {
diff --git a/sys/ufs/ffs/fs.h b/sys/ufs/ffs/fs.h
--- a/sys/ufs/ffs/fs.h
+++ b/sys/ufs/ffs/fs.h
@@ -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 */
/*
diff --git a/tools/diag/prtblknos/main.c b/tools/diag/prtblknos/main.c
--- a/tools/diag/prtblknos/main.c
+++ b/tools/diag/prtblknos/main.c
@@ -56,7 +56,6 @@
char ibuf[64];
char *fsname, *filename;
ino_t inonum;
- int error;
filename = NULL;
if (argc == 2) {
@@ -83,7 +82,8 @@
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 @@
(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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Sun, Aug 23, 8:58 PM (12 h, 29 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37118956
Default Alt Text
D36053.diff (24 KB)
Attached To
Mode
D36053: Move the ability to search for alternate UFS superblocks from fsck_ffs(8) into ffs_search() to allow use by other parts of the system.
Attached
Detach File
Event Timeline
Log In to Comment