Skip site navigation (1)Skip section navigation (2)
Date:      Sun, 31 Jul 2022 05:51:45 GMT
From:      Kirk McKusick <mckusick@FreeBSD.org>
To:        src-committers@FreeBSD.org, dev-commits-src-all@FreeBSD.org, dev-commits-src-main@FreeBSD.org
Subject:   git: b21582ee03ec - main - Add a flags parameter to the ffs_sbget() function that reads UFS superblocks.
Message-ID:  <202207310551.26V5pj4e093383@gitrepo.freebsd.org>

next in thread | raw e-mail | index | archive | help
The branch main has been updated by mckusick:

URL: https://cgit.FreeBSD.org/src/commit/?id=b21582ee03ec1394e08173e276df311979856e54

commit b21582ee03ec1394e08173e276df311979856e54
Author:     Kirk McKusick <mckusick@FreeBSD.org>
AuthorDate: 2022-07-31 05:44:01 +0000
Commit:     Kirk McKusick <mckusick@FreeBSD.org>
CommitDate: 2022-07-31 05:51:38 +0000

    Add a flags parameter to the ffs_sbget() function that reads UFS superblocks.
    
    Rather than trying to shoehorn flags into the requested superblock
    address, create a separate flags parameter to the ffs_sbget()
    function in sys/ufs/ffs/ffs_subr.c. The ffs_sbget() function is
    used both in the kernel and in user-level utilities through export
    to the sbget() function in the libufs(3) library (see sbget(3)
    for details). The kernel uses ffs_sbget() when mounting UFS
    filesystems, in the glabel(8) and gjournal(8) GEOM utilities,
    and in the standalone library used when booting the system
    from a UFS root filesystem.
    
    The ffs_sbget() function reads the superblock located at the byte
    offset specified by its sblockloc parameter. The value UFS_STDSB
    may be specified for sblockloc to request that the standard
    location for the superblock be read.
    
    The two existing options are now flags:
    
    UFS_NOHASHFAIL will note if the check hash is wrong but will still
       return the superblock. This is used by the bootstrap code to
       give the system a chance to come up so that fsck can be run to
       correct the problem.
    
    UFS_NOMSG indicates that superblock inconsistency error messages
       should not be printed. It is used by programs like fsck that
       want to print their own error message and programs like glabel(8)
       that just want to know if a UFS filesystem exists on a partition.
    
    One additional flag is added:
    
    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 is used by clients like glabel(8) that
       just want to check for possible filesystem types. Using UFS_NOCSUM
       skips the superblock checks for csum data which allows superblocks
       that have corrupted csum data to be read and used.
    
    The validate_sblock() function checks that the superblock has not
    been corrupted in a way that can crash or hang the system. Unless
    the UFS_NOMSG flag is specified, it will print out any errors that
    it finds. Prior to this commit, validate_sblock() returned as soon
    as it found an inconsistency so would print at most one message.
    It now does all its checks so when UFS_NOMSG has not been specified
    will print out everything that it finds inconsistent.
    
    Sponsored by: The FreeBSD Foundation
---
 lib/libufs/libufs.h              |  7 ++--
 lib/libufs/sblock.c              | 36 +++++++++++++++----
 lib/libufs/sbread.3              | 24 +++++++++++--
 lib/libufs/type.c                |  3 +-
 sbin/dump/main.c                 |  2 +-
 sbin/dumpfs/dumpfs.c             |  5 +--
 sbin/fsck_ffs/setup.c            | 14 ++++----
 sbin/fsirand/fsirand.c           |  8 ++---
 sbin/growfs/growfs.c             |  2 +-
 sbin/quotacheck/quotacheck.c     |  2 +-
 stand/libsa/ufs.c                |  4 +--
 sys/geom/journal/g_journal_ufs.c |  3 +-
 sys/geom/label/g_label_ufs.c     |  7 ++--
 sys/ufs/ffs/ffs_extern.h         |  2 +-
 sys/ufs/ffs/ffs_subr.c           | 77 ++++++++++++++++++++++++----------------
 sys/ufs/ffs/ffs_vfsops.c         | 10 +++---
 sys/ufs/ffs/fs.h                 | 40 +++++++++++----------
 usr.sbin/fstyp/ufs.c             |  4 +--
 usr.sbin/quot/quot.c             |  4 +--
 19 files changed, 158 insertions(+), 96 deletions(-)

diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h
index 5045117b5d7d..cb8774454b38 100644
--- a/lib/libufs/libufs.h
+++ b/lib/libufs/libufs.h
@@ -65,7 +65,8 @@ struct uufsd {
 	int d_ccg;			/* current cylinder group */
 	int d_lcg;			/* last cylinder group (in d_cg) */
 	const char *d_error;		/* human readable disk error */
-	off_t	d_sblockloc;		/* where to look for the superblock */
+	off_t d_sblockloc;		/* where to look for the superblock */
+	int d_lookupflags;		/* flags to superblock lookup */
 	int d_mine;			/* internal flags */
 #define	d_fs	d_sbunion.d_fs
 #define	d_sb	d_sbunion.d_sb
@@ -111,7 +112,7 @@ 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);
 void	ffs_setblock(struct fs *, u_char *, ufs1_daddr_t);
-int	ffs_sbget(void *, struct fs **, off_t, char *,
+int	ffs_sbget(void *, struct fs **, off_t, int, char *,
 	    int (*)(void *, off_t, void **, int));
 int	ffs_sbput(void *, struct fs *, off_t,
 	    int (*)(void *, off_t, void *, int));
@@ -150,7 +151,7 @@ int putinode(struct uufsd *);
 int sbread(struct uufsd *);
 int sbwrite(struct uufsd *, int);
 /* low level superblock read/write functions */
-int sbget(int, struct fs **, off_t);
+int sbget(int, struct fs **, off_t, int);
 int sbput(int, struct fs *, int);
 
 /*
diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c
index 9ba012400f1d..5708d50aa4f9 100644
--- a/lib/libufs/sblock.c
+++ b/lib/libufs/sblock.c
@@ -53,6 +53,15 @@ static int handle_disk_read(struct uufsd *, struct fs *, int);
 
 /*
  * Read the standard superblock.
+ *
+ * The following option flags can be or'ed into disk->d_lookupflags:
+ *
+ * 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
 sbread(struct uufsd *disk)
@@ -60,7 +69,7 @@ sbread(struct uufsd *disk)
 	struct fs *fs;
 	int error;
 
-	error = sbget(disk->d_fd, &fs, disk->d_sblockloc);
+	error = sbget(disk->d_fd, &fs, disk->d_sblockloc, disk->d_lookupflags);
 	return (handle_disk_read(disk, fs, error));
 }
 
@@ -149,14 +158,24 @@ static int use_pread(void *devfd, off_t loc, void **bufp, int size);
 static int use_pwrite(void *devfd, off_t loc, void *buf, int size);
 
 /*
+ * The following two functions read a superblock. Their flags
+ * parameter 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.
+ *
  * Read a superblock from the devfd device allocating memory returned
- * in fsp. Also read the superblock summary information.
+ * in fsp.
  */
 int
-sbget(int devfd, struct fs **fsp, off_t sblockloc)
+sbget(int devfd, struct fs **fsp, off_t sblockloc, int flags)
 {
 
-	return (ffs_sbget(&devfd, fsp, sblockloc, "user", use_pread));
+	return (ffs_sbget(&devfd, fsp, sblockloc, flags, "user", use_pread));
 }
 
 /*
@@ -196,8 +215,10 @@ sbput(int devfd, struct fs *fs, int numaltwrite)
 	if (numaltwrite == 0)
 		return (0);
 	savedactualloc = fs->fs_sblockactualloc;
-	savedcsp = fs->fs_csp;
-	fs->fs_csp = NULL;
+	if (fs->fs_si != NULL) {
+		savedcsp = fs->fs_csp;
+		fs->fs_csp = NULL;
+	}
 	for (i = 0; i < numaltwrite; i++) {
 		fs->fs_sblockactualloc = dbtob(fsbtodb(fs, cgsblock(fs, i)));
 		if ((error = ffs_sbput(&devfd, fs, fs->fs_sblockactualloc,
@@ -208,7 +229,8 @@ sbput(int devfd, struct fs *fs, int numaltwrite)
 		}
 	}
 	fs->fs_sblockactualloc = savedactualloc;
-	fs->fs_csp = savedcsp;
+	if (fs->fs_si != NULL)
+		fs->fs_csp = savedcsp;
 	return (0);
 }
 
diff --git a/lib/libufs/sbread.3 b/lib/libufs/sbread.3
index e97469f86873..f579fc7ffdf1 100644
--- a/lib/libufs/sbread.3
+++ b/lib/libufs/sbread.3
@@ -27,7 +27,7 @@
 .In ufs/ffs/fs.h
 .In libufs.h
 .Ft int
-.Fn sbget "int devfd" "struct fs **fsp" "off_t sblockloc"
+.Fn sbget "int devfd" "struct fs **fsp" "off_t sblockloc" "int flags"
 .Ft int
 .Fn sbput "int devfd" "struct fs *fs" "int numaltwrite"
 .Ft int
@@ -60,7 +60,27 @@ file descriptor that references the filesystem disk,
 reads the superblock located at the byte offset specified by
 .Va sblockloc
 into the allocated buffer.
-If successful, it returns a pointer to the buffer containing the superblock in
+The value
+.Cm UFS_STDSB
+may be specified for
+.Va sblockloc
+to request that the standard location for the superblock be read.
+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.
+.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
 .Va fsp .
 The
 .Fn sbget
diff --git a/lib/libufs/type.c b/lib/libufs/type.c
index ac5b8d17e84c..80b26cdb9c84 100644
--- a/lib/libufs/type.c
+++ b/lib/libufs/type.c
@@ -168,7 +168,8 @@ again:	if ((ret = stat(name, &st)) < 0) {
 	disk->d_ufs = 0;
 	disk->d_error = NULL;
 	disk->d_si = NULL;
-	disk->d_sblockloc = STDSB;
+	disk->d_sblockloc = UFS_STDSB;
+	disk->d_lookupflags = 0;
 
 	if (oname != name) {
 		name = strdup(name);
diff --git a/sbin/dump/main.c b/sbin/dump/main.c
index 8752f2c1bea5..779db5fb4b43 100644
--- a/sbin/dump/main.c
+++ b/sbin/dump/main.c
@@ -457,7 +457,7 @@ main(int argc, char *argv[])
 		msgtail("to %s\n", tape);
 
 	sync();
-	if ((ret = sbget(diskfd, &sblock, STDSB)) != 0) {
+	if ((ret = sbget(diskfd, &sblock, UFS_STDSB, UFS_NOCSUM)) != 0) {
 		switch (ret) {
 		case ENOENT:
 			warn("Cannot find file system superblock");
diff --git a/sbin/dumpfs/dumpfs.c b/sbin/dumpfs/dumpfs.c
index 7f2acdf435ea..6a586ffb95ec 100644
--- a/sbin/dumpfs/dumpfs.c
+++ b/sbin/dumpfs/dumpfs.c
@@ -135,7 +135,7 @@ main(int argc, char *argv[])
 			eval |= 1;
 			continue;
 		}
-		disk.d_sblockloc = STDSB_NOHASHFAIL;
+		disk.d_lookupflags |= UFS_NOHASHFAIL;
 		if (sbread(&disk) == -1) {
 			ufserr(name);
 			eval |= 1;
@@ -314,9 +314,6 @@ dumpfs(const char *name, int dosb)
 		afs.fs_volname, (uintmax_t)afs.fs_swuid,
 		(uintmax_t)afs.fs_providersize);
 	printf("\ncs[].cs_(nbfree,ndir,nifree,nffree):\n\t");
-	afs.fs_csp = calloc(1, afs.fs_cssize);
-	if (bread(&disk, fsbtodb(&afs, afs.fs_csaddr), afs.fs_csp, afs.fs_cssize) == -1)
-		goto err;
 	for (i = 0; i < afs.fs_ncg; i++) {
 		struct csum *cs = &afs.fs_cs(&afs, i);
 		if (i && i % 4 == 0)
diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c
index 0f0d9b61a076..0daac100499a 100644
--- a/sbin/fsck_ffs/setup.c
+++ b/sbin/fsck_ffs/setup.c
@@ -252,18 +252,20 @@ int
 readsb(int listerr)
 {
 	off_t super;
-	int bad, ret;
+	int bad, ret, flags;
 	struct fs *fs;
 
-	super = bflag ? bflag * dev_bsize :
-	    sbhashfailed ? STDSB_NOHASHFAIL_NOMSG : STDSB_NOMSG;
+	super = bflag ? bflag * dev_bsize : UFS_STDSB;
+	flags = sbhashfailed ? UFS_NOHASHFAIL | UFS_NOMSG : UFS_NOMSG;
 	readcnt[sblk.b_type]++;
-	while ((ret = sbget(fsreadfd, &fs, super)) != 0) {
+	while ((ret = sbget(fsreadfd, &fs, super, flags)) != 0) {
 		switch (ret) {
 		case EINTEGRITY:
-			if (bflag || super == STDSB_NOHASHFAIL_NOMSG)
+			if (bflag || (super == UFS_STDSB &&
+			    flags == (UFS_NOHASHFAIL | UFS_NOMSG)))
 				return (0);
-			super = STDSB_NOHASHFAIL_NOMSG;
+			super = UFS_STDSB;
+			flags = UFS_NOHASHFAIL | UFS_NOMSG;
 			sbhashfailed = 1;
 			continue;
 		case ENOENT:
diff --git a/sbin/fsirand/fsirand.c b/sbin/fsirand/fsirand.c
index c4db8848f18b..90305416f556 100644
--- a/sbin/fsirand/fsirand.c
+++ b/sbin/fsirand/fsirand.c
@@ -112,7 +112,7 @@ fsirand(char *device)
 	struct fs *sblock;
 	ino_t inumber;
 	ufs2_daddr_t dblk;
-	int devfd, n, cg, ret;
+	int devfd, n, cg;
 	u_int32_t bsize = DEV_BSIZE;
 
 	if ((devfd = open(device, printonly ? O_RDONLY : O_RDWR)) < 0) {
@@ -124,10 +124,10 @@ fsirand(char *device)
 	dp2 = NULL;
 
 	/* Read in master superblock */
-	if ((ret = sbget(devfd, &sblock, STDSB)) != 0) {
-		switch (ret) {
+	if ((errno = sbget(devfd, &sblock, UFS_STDSB, UFS_NOCSUM)) != 0) {
+		switch (errno) {
 		case ENOENT:
-			warn("Cannot find file system superblock");
+			warnx("Cannot find file system superblock");
 			return (1);
 		default:
 			warn("Unable to read file system superblock");
diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c
index 69e6f04dd4c2..4a8d935d91c7 100644
--- a/sbin/growfs/growfs.c
+++ b/sbin/growfs/growfs.c
@@ -1455,7 +1455,7 @@ main(int argc, char **argv)
 	/*
 	 * Read the current superblock, and take a backup.
 	 */
-	if ((ret = sbget(fsi, &fs, STDSB)) != 0) {
+	if ((ret = sbget(fsi, &fs, UFS_STDSB, 0)) != 0) {
 		switch (ret) {
 		case ENOENT:
 			errx(1, "superblock not recognized");
diff --git a/sbin/quotacheck/quotacheck.c b/sbin/quotacheck/quotacheck.c
index 9a01be11d9d0..1e656d2a5811 100644
--- a/sbin/quotacheck/quotacheck.c
+++ b/sbin/quotacheck/quotacheck.c
@@ -321,7 +321,7 @@ chkquota(char *specname, struct quotafile *qfu, struct quotafile *qfg)
 		}
 	}
 	sync();
-	if ((ret = sbget(fi, &fs, STDSB)) != 0) {
+	if ((ret = sbget(fi, &fs, UFS_STDSB, UFS_NOCSUM)) != 0) {
 		switch (ret) {
 		case ENOENT:
 			warn("Cannot find file system superblock");
diff --git a/stand/libsa/ufs.c b/stand/libsa/ufs.c
index 12703a3e18aa..de3dbe58789b 100644
--- a/stand/libsa/ufs.c
+++ b/stand/libsa/ufs.c
@@ -152,7 +152,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, char *,
+int	ffs_sbget(void *, struct fs **, off_t, int, char *,
 	    int (*)(void *, off_t, void **, int));
 
 /*
@@ -530,7 +530,7 @@ ufs_open(const char *upath, struct open_file *f)
 	if (mnt == NULL) {
 		/* read super block */
 		twiddle(1);
-		if ((rc = ffs_sbget(f, &fs, STDSB_NOHASHFAIL, "stand",
+		if ((rc = ffs_sbget(f, &fs, UFS_STDSB, UFS_NOHASHFAIL, "stand",
 		     ufs_use_sa_read)) != 0) {
 			goto out;
 		}
diff --git a/sys/geom/journal/g_journal_ufs.c b/sys/geom/journal/g_journal_ufs.c
index dec28e547f82..dc9604abae22 100644
--- a/sys/geom/journal/g_journal_ufs.c
+++ b/sys/geom/journal/g_journal_ufs.c
@@ -73,7 +73,8 @@ g_journal_ufs_dirty(struct g_consumer *cp)
 
 	fs = NULL;
 	if (SBLOCKSIZE % cp->provider->sectorsize != 0 ||
-	    ffs_sbget(cp, &fs, STDSB, M_GEOM, g_use_g_read_data) != 0) {
+	    ffs_sbget(cp, &fs, UFS_STDSB, UFS_NOCSUM, M_GEOM, g_use_g_read_data)
+		    != 0) {
 		GJ_DEBUG(0, "Cannot find superblock to mark file system %s "
 		    "as dirty.", cp->provider->name);
 		KASSERT(fs == NULL,
diff --git a/sys/geom/label/g_label_ufs.c b/sys/geom/label/g_label_ufs.c
index 0de09ec93896..691f875cf6cc 100644
--- a/sys/geom/label/g_label_ufs.c
+++ b/sys/geom/label/g_label_ufs.c
@@ -139,8 +139,9 @@ g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int wh
 	label[0] = '\0';
 
 	fs = NULL;
-	if (SBLOCKSIZE % pp->sectorsize != 0 || ffs_sbget(cp, &fs,
-	    STDSB_NOHASHFAIL_NOMSG, M_GEOM, g_use_g_read_data) != 0) {
+	if (SBLOCKSIZE % pp->sectorsize != 0 || ffs_sbget(cp, &fs, UFS_STDSB,
+	    UFS_NOHASHFAIL | UFS_NOCSUM | UFS_NOMSG, M_GEOM, g_use_g_read_data)
+	    != 0) {
 		KASSERT(fs == NULL,
 		    ("g_label_ufs_taste_common: non-NULL fs %p\n", fs));
 		return;
@@ -172,8 +173,6 @@ g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int wh
 		break;
 	}
 out:
-	g_free(fs->fs_csp);
-	g_free(fs->fs_si);
 	g_free(fs);
 }
 
diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h
index fdc08dc6aafb..54820fc5b3ce 100644
--- a/sys/ufs/ffs/ffs_extern.h
+++ b/sys/ufs/ffs/ffs_extern.h
@@ -90,7 +90,7 @@ 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 **);
 int	ffs_reload(struct mount *, int);
-int	ffs_sbget(void *, struct fs **, off_t, struct malloc_type *,
+int	ffs_sbget(void *, struct fs **, off_t, int, struct malloc_type *,
 	    int (*)(void *, off_t, void **, int));
 int	ffs_sbput(void *, struct fs *, off_t, int (*)(void *, off_t, void *,
 	    int));
diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c
index 502ef79c7bd3..611f1989e8f9 100644
--- a/sys/ufs/ffs/ffs_subr.c
+++ b/sys/ufs/ffs/ffs_subr.c
@@ -125,7 +125,7 @@ ffs_update_dinode_ckhash(struct fs *fs, struct ufs2_dinode *dip)
  * the superblock and its associated data.
  */
 static off_t sblock_try[] = SBLOCKSEARCH;
-static int readsuper(void *, struct fs **, off_t, int, int,
+static int readsuper(void *, struct fs **, off_t, int,
 	int (*)(void *, off_t, void **, int));
 static int validate_sblock(struct fs *, int);
 
@@ -149,7 +149,7 @@ static int validate_sblock(struct fs *, int);
  *         The administrator must complete newfs before using this volume.
  */
 int
-ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock,
+ffs_sbget(void *devfd, struct fs **fsp, off_t sblock, int flags,
     struct malloc_type *filltype,
     int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
 {
@@ -163,18 +163,23 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock,
 
 	fs = NULL;
 	*fsp = NULL;
-	if (altsblock >= 0) {
-		if ((error = readsuper(devfd, &fs, altsblock, 1, 0,
-		     readfunc)) != 0) {
+	if (sblock != UFS_STDSB) {
+		if ((error = readsuper(devfd, &fs, sblock,
+		    flags | UFS_ALTSBLK, readfunc)) != 0) {
 			if (fs != NULL)
 				UFS_FREE(fs, filltype);
 			return (error);
 		}
 	} else {
 		for (i = 0; sblock_try[i] != -1; i++) {
-			if ((error = readsuper(devfd, &fs, sblock_try[i], 0,
-			     altsblock, readfunc)) == 0)
+			if ((error = readsuper(devfd, &fs, sblock_try[i],
+			     flags, readfunc)) == 0) {
+				if ((flags & UFS_NOCSUM) != 0) {
+					*fsp = fs;
+					return (0);
+				}
 				break;
+			}
 			if (fs != NULL) {
 				UFS_FREE(fs, filltype);
 				fs = NULL;
@@ -243,8 +248,8 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock,
  * Return zero on success or an errno on failure.
  */
 static int
-readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
-    int chkhash, int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
+readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int flags,
+    int (*readfunc)(void *devfd, off_t loc, void **bufp, int size))
 {
 	struct fs *fs;
 	int error, res;
@@ -263,10 +268,10 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
 	 * that will be accessed. Here we fail the lookup so that we can
 	 * retry with the correct location for the UFS1 superblock.
 	 */
-	if (fs->fs_magic == FS_UFS1_MAGIC && !isaltsblk &&
+	if (fs->fs_magic == FS_UFS1_MAGIC && (flags & UFS_ALTSBLK) == 0 &&
 	    fs->fs_bsize == SBLOCK_UFS2 && sblockloc == SBLOCK_UFS2)
 		return (ENOENT);
-	if ((error = validate_sblock(fs, isaltsblk)) != 0)
+	if ((error = validate_sblock(fs, flags)) > 0)
 		return (error);
 	/*
 	 * If the filesystem has been run on a kernel without
@@ -281,15 +286,16 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
 	fs->fs_metackhash &= CK_SUPPORTED;
 	fs->fs_flags &= FS_SUPPORTED;
 	if (fs->fs_ckhash != (ckhash = ffs_calc_sbhash(fs))) {
-		if (chkhash == STDSB_NOMSG)
-			return (EINTEGRITY);
-		if (chkhash == STDSB_NOHASHFAIL_NOMSG)
+		if ((flags & (UFS_NOMSG | UFS_NOHASHFAIL)) ==
+		    (UFS_NOMSG | UFS_NOHASHFAIL))
 			return (0);
+		if ((flags & UFS_NOMSG) != 0)
+			return (EINTEGRITY);
 #ifdef _KERNEL
 		res = uprintf("Superblock check-hash failed: recorded "
 		    "check-hash 0x%x != computed check-hash 0x%x%s\n",
 		    fs->fs_ckhash, ckhash,
-		    chkhash == STDSB_NOHASHFAIL ? " (Ignored)" : "");
+		    (flags & UFS_NOHASHFAIL) != 0 ? " (Ignored)" : "");
 #else
 		res = 0;
 #endif
@@ -301,12 +307,10 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
 			printf("Superblock check-hash failed: recorded "
 			    "check-hash 0x%x != computed check-hash "
 			    "0x%x%s\n", fs->fs_ckhash, ckhash,
-			    chkhash == STDSB_NOHASHFAIL ?
-			    " (Ignored)" : "");
-		if (chkhash == STDSB)
-			return (EINTEGRITY);
-		/* chkhash == STDSB_NOHASHFAIL */
-		return (0);
+			    (flags & UFS_NOHASHFAIL) ? " (Ignored)" : "");
+		if ((flags & UFS_NOHASHFAIL) != 0)
+			return (0);
+		return (EINTEGRITY);
 	}
 	/* Have to set for old filesystems that predate this field */
 	fs->fs_sblockactualloc = sblockloc;
@@ -318,34 +322,40 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk,
 /*
  * Verify the filesystem values.
  */
-#define ILOG2(num) (fls(num) - 1)
+#define ILOG2(num)	(fls(num) - 1)
+#define MPRINT		if (prtmsg) printf
 #undef CHK
 #define CHK(lhs, op, rhs, fmt)						\
 	if (lhs op rhs) {						\
-		printf("UFS%d superblock failed: %s (" #fmt ") %s %s ("	\
+		MPRINT("UFS%d superblock failed: %s (" #fmt ") %s %s ("	\
 		    #fmt ")\n", fs->fs_magic == FS_UFS1_MAGIC ? 1 : 2,	\
 		    #lhs, (intmax_t)lhs, #op, #rhs, (intmax_t)rhs);	\
-		return (ENOENT);					\
+		if (error == 0)						\
+			error = ENOENT;					\
 	}
 #define CHK2(lhs1, op1, rhs1, lhs2, op2, rhs2, fmt)			\
 	if (lhs1 op1 rhs1 && lhs2 op2 rhs2) {				\
-		printf("UFS%d superblock failed: %s (" #fmt ") %s %s ("	\
+		MPRINT("UFS%d superblock failed: %s (" #fmt ") %s %s ("	\
 		    #fmt ") && %s (" #fmt ") %s %s (" #fmt ")\n",	\
 		    fs->fs_magic == FS_UFS1_MAGIC ? 1 : 2, #lhs1, 	\
 		    (intmax_t)lhs1, #op1, #rhs1, (intmax_t)rhs1, #lhs2,	\
 		    (intmax_t)lhs2, #op2, #rhs2, (intmax_t)rhs2);	\
-		return (ENOENT);					\
+		if (error == 0)						\
+			error = ENOENT;					\
 	}
 
 static int
-validate_sblock(struct fs *fs, int isaltsblk)
+validate_sblock(struct fs *fs, int flags)
 {
 	u_long i, sectorsize;
 	u_int64_t maxfilesize, sizepb;
+	int error, prtmsg;
 
+	error = 0;
 	sectorsize = dbtob(1);
+	prtmsg = ((flags & UFS_NOMSG) == 0);
 	if (fs->fs_magic == FS_UFS2_MAGIC) {
-		if (!isaltsblk) {
+		if ((flags & UFS_ALTSBLK) == 0) {
 			CHK(fs->fs_sblockloc, !=, SBLOCK_UFS2, %#jx);
 			CHK2(fs->fs_sblockactualloc, !=, SBLOCK_UFS2,
 			    fs->fs_sblockactualloc, !=, 0, %jd);
@@ -358,7 +368,7 @@ validate_sblock(struct fs *fs, int isaltsblk)
 		CHK(fs->fs_inopb, !=, fs->fs_bsize / sizeof(struct ufs2_dinode),
 		    %jd);
 	} else if (fs->fs_magic == FS_UFS1_MAGIC) {
-		if (!isaltsblk) {
+		if ((flags & UFS_ALTSBLK) == 0) {
 			CHK(fs->fs_sblockloc, >, SBLOCK_UFS1, %jd);
 			CHK(fs->fs_sblockactualloc, >, SBLOCK_UFS1, %jd);
 		}
@@ -459,6 +469,13 @@ validate_sblock(struct fs *fs, int isaltsblk)
 	CHK(fs->fs_size, <, 8 * fs->fs_frag, %jd);
 	CHK(fs->fs_size, <=, (fs->fs_ncg - 1) * fs->fs_fpg, %jd);
 	CHK(fs->fs_size, >, fs->fs_ncg * fs->fs_fpg, %jd);
+	/*
+	 * If we are not requested to read in the csum data stop here
+	 * as the correctness of the remaining values is only important
+	 * to bound the space needed to be allocated to hold the csum data.
+	 */
+	if ((flags & UFS_NOCSUM) != 0)
+		return (error);
 	CHK(fs->fs_csaddr, <, 0, %jd);
 	CHK(fs->fs_cssize, !=,
 	    fragroundup(fs, fs->fs_ncg * sizeof(struct csum)), %jd);
@@ -490,7 +507,7 @@ validate_sblock(struct fs *fs, int isaltsblk)
 	CHK2(fs->fs_maxcontig, ==, 0, fs->fs_contigsumsize, !=, 0, %jd);
 	CHK2(fs->fs_maxcontig, >, 1, fs->fs_contigsumsize, !=,
 	    MIN(fs->fs_maxcontig, FS_MAXCONTIG), %jd);
-	return (0);
+	return (error);
 }
 
 /*
diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c
index b41c162dea7d..2944d0c5077d 100644
--- a/sys/ufs/ffs/ffs_vfsops.c
+++ b/sys/ufs/ffs/ffs_vfsops.c
@@ -913,7 +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;
+	int candelete, canspeedup, flags;
 	off_t loc;
 
 	fs = NULL;
@@ -958,10 +958,12 @@ ffs_mountfs(struct vnode *odevvp, struct mount *mp, struct thread *td)
 		goto out;
 	}
 	/* fetch the superblock and summary information */
-	loc = STDSB;
+	loc = UFS_STDSB;
+	flags = 0;
 	if ((mp->mnt_flag & (MNT_ROOTFS | MNT_FORCE)) != 0)
-		loc = STDSB_NOHASHFAIL;
-	if ((error = ffs_sbget(devvp, &fs, loc, M_UFSMNT, ffs_use_bread)) != 0)
+		flags = UFS_NOHASHFAIL;
+	if ((error = ffs_sbget(devvp, &fs, loc, flags, M_UFSMNT, ffs_use_bread))
+	    != 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
index 8c0047f17caf..81cb416b383d 100644
--- a/sys/ufs/ffs/fs.h
+++ b/sys/ufs/ffs/fs.h
@@ -79,26 +79,30 @@
 	{ SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
 /*
  * Request standard superblock location in ffs_sbget().
+ */
+#define	UFS_STDSB	-1	/* Search standard places for superblock */
+
+/*
+ * UFS_NOMSG indicates that superblock inconsistency error messages
+ *    should not be printed. It is used by programs like fsck that
+ *    want to print their own error message.
  *
- * STDSB will fail if the superblock has a check hash and it is wrong.
- *
- * STDSB_NOHASHFAIL will note that the check hash is wrong but will
- *    still return the superblock. This is used by the bootstrap code
- *    to give the system a chance to come up so that fsck can be run
- *    to correct the problem.
- *
- * STDSB_NOMSG is the same as STDSB but the kernel does not print an 
- *    error message. It is used by programs like fsck that want to
- *    print their own error message.
+ * 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 is used by clients like glabel that just
+ *    want to check for possible filesystem types. Using UFS_NOCSUM
+ *    skips the superblock checks for csum data which allows superblocks
+ *    that have corrupted csum data to be read and used.
  *
- * STDSB_NOHASHFAIL_NOMSG is the same as STDSB_NOHASHFAIL but the kernel
- *    does not print an error message. It is used by clients like glabel
- *    that just want to check for possible filesystem types.
- */
-#define	STDSB			-1	/* Fail if check-hash is bad */
-#define	STDSB_NOHASHFAIL	-2	/* Ignore check-hash failure */
-#define	STDSB_NOMSG		-3	/* STDSB with no kernel message */
-#define	STDSB_NOHASHFAIL_NOMSG	-4	/* STDSB_NOHASHFAIL with no message */
+ * UFS_NOHASHFAIL will note that the check hash is wrong but will still
+ *    return the superblock. This is used by the bootstrap code to
+ *    give the system a chance to come up so that fsck can be run to
+ *    correct the problem.
+ */
+#define	UFS_NOHASHFAIL	0x0001	/* Ignore check-hash failure */
+#define	UFS_NOMSG	0x0004	/* Print no error message */
+#define	UFS_NOCSUM	0x0008	/* Read just the superblock without csum */
+#define	UFS_ALTSBLK	0x1000	/* Flag used internally */
 
 /*
  * Max number of fragments per block. This value is NOT tweakable.
diff --git a/usr.sbin/fstyp/ufs.c b/usr.sbin/fstyp/ufs.c
index e4de1283e769..69ce90d600f2 100644
--- a/usr.sbin/fstyp/ufs.c
+++ b/usr.sbin/fstyp/ufs.c
@@ -50,11 +50,9 @@ fstyp_ufs(FILE *fp, char *label, size_t labelsize)
 {
 	struct fs *fs;
 
-	switch (sbget(fileno(fp), &fs, STDSB)) {
+	switch (sbget(fileno(fp), &fs, UFS_STDSB, UFS_NOCSUM)) {
 	case 0:
 		strlcpy(label, fs->fs_volname, labelsize);
-		free(fs->fs_csp);
-		free(fs->fs_si);
 		free(fs);
 		return (0);
 	case ENOENT:
diff --git a/usr.sbin/quot/quot.c b/usr.sbin/quot/quot.c
index fa1ee1c65fe7..7e84dd79e148 100644
--- a/usr.sbin/quot/quot.c
+++ b/usr.sbin/quot/quot.c
@@ -550,7 +550,7 @@ quot(char *name, char *mp)
 		close(fd);
 		return;
 	}
-	switch (sbget(fd, &fs, STDSB)) {
+	switch (errno = sbget(fd, &fs, UFS_STDSB, UFS_NOCSUM)) {
 	case 0:
 		break;
 	case ENOENT:
@@ -567,8 +567,6 @@ quot(char *name, char *mp)
 		printf(" (%s)",mp);
 	putchar('\n');
 	(*func)(fd, fs, name);
-	free(fs->fs_csp);
-	free(fs->fs_si);
 	free(fs);
 	close(fd);
 }



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?202207310551.26V5pj4e093383>