Page MenuHomeFreeBSD

D36053.id.diff
No OneTemporary

D36053.id.diff

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

Mime Type
text/plain
Expires
Mon, Aug 24, 1:11 AM (16 h, 43 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
37118956
Default Alt Text
D36053.id.diff (24 KB)

Event Timeline