diff --git a/lib/libufs/libufs.h b/lib/libufs/libufs.h index dbd378949877..9d1e7355c2f7 100644 --- a/lib/libufs/libufs.h +++ b/lib/libufs/libufs.h @@ -117,6 +117,12 @@ int ffs_sbget(void *, struct fs **, off_t, char *, int ffs_sbput(void *, struct fs *, off_t, int (*)(void *, off_t, void *, int)); +/* + * Request standard superblock location in ffs_sbget + */ +#define STDSB -1 /* Fail if check-hash is bad */ +#define STDSB_NOHASHFAIL -2 /* Ignore check-hash failure */ + /* * block.c */ diff --git a/lib/libufs/sblock.c b/lib/libufs/sblock.c index 29ff258b6ebf..53c8d44f6d65 100644 --- a/lib/libufs/sblock.c +++ b/lib/libufs/sblock.c @@ -54,7 +54,7 @@ sbread(struct uufsd *disk) ERROR(disk, NULL); - if ((errno = sbget(disk->d_fd, &fs, -1)) != 0) { + if ((errno = sbget(disk->d_fd, &fs, STDSB)) != 0) { switch (errno) { case EIO: ERROR(disk, "non-existent or truncated superblock"); diff --git a/sbin/dump/main.c b/sbin/dump/main.c index 7301ca318d80..135b4fcfb64c 100644 --- a/sbin/dump/main.c +++ b/sbin/dump/main.c @@ -433,7 +433,7 @@ main(int argc, char *argv[]) msgtail("to %s\n", tape); sync(); - if ((ret = sbget(diskfd, &sblock, -1)) != 0) { + if ((ret = sbget(diskfd, &sblock, STDSB)) != 0) { switch (ret) { case ENOENT: warn("Cannot find file system superblock"); diff --git a/sbin/fsck_ffs/setup.c b/sbin/fsck_ffs/setup.c index 82a970e12858..8599f6cde739 100644 --- a/sbin/fsck_ffs/setup.c +++ b/sbin/fsck_ffs/setup.c @@ -327,7 +327,7 @@ readsb(int listerr) int bad, ret; struct fs *fs; - super = bflag ? bflag * dev_bsize : -1; + super = bflag ? bflag * dev_bsize : STDSB; readcnt[sblk.b_type]++; if ((ret = sbget(fsreadfd, &fs, super)) != 0) { switch (ret) { diff --git a/sbin/fsirand/fsirand.c b/sbin/fsirand/fsirand.c index f5e26571f903..8675f7c3fd33 100644 --- a/sbin/fsirand/fsirand.c +++ b/sbin/fsirand/fsirand.c @@ -126,7 +126,7 @@ fsirand(char *device) dp2 = NULL; /* Read in master superblock */ - if ((ret = sbget(devfd, &sblock, -1)) != 0) { + if ((ret = sbget(devfd, &sblock, STDSB)) != 0) { switch (ret) { case ENOENT: warn("Cannot find file system superblock"); diff --git a/sbin/growfs/growfs.c b/sbin/growfs/growfs.c index b75f377841ef..967cda3330d0 100644 --- a/sbin/growfs/growfs.c +++ b/sbin/growfs/growfs.c @@ -1449,7 +1449,7 @@ main(int argc, char **argv) /* * Read the current superblock, and take a backup. */ - if ((ret = sbget(fsi, &fs, -1)) != 0) { + if ((ret = sbget(fsi, &fs, STDSB)) != 0) { switch (ret) { case ENOENT: errx(1, "superblock not recognized"); diff --git a/sbin/quotacheck/quotacheck.c b/sbin/quotacheck/quotacheck.c index 3b192a7a9585..9a01be11d9d0 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, -1)) != 0) { + if ((ret = sbget(fi, &fs, STDSB)) != 0) { switch (ret) { case ENOENT: warn("Cannot find file system superblock"); diff --git a/stand/libsa/ufs.c b/stand/libsa/ufs.c index 204bc969f968..317d6e9fdb1c 100644 --- a/stand/libsa/ufs.c +++ b/stand/libsa/ufs.c @@ -140,6 +140,11 @@ 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 (*)(void *, off_t, void **, int)); +/* + * Request standard superblock location in ffs_sbget + */ +#define STDSB -1 /* Fail if check-hash is bad */ +#define STDSB_NOHASHFAIL -2 /* Ignore check-hash failure */ /* * Read a new inode into a file structure. @@ -519,7 +524,8 @@ ufs_open(upath, f) /* read super block */ twiddle(1); - if ((rc = ffs_sbget(f, &fs, -1, "stand", ufs_use_sa_read)) != 0) + if ((rc = ffs_sbget(f, &fs, STDSB_NOHASHFAIL, "stand", + ufs_use_sa_read)) != 0) goto out; fp->f_fs = fs; /* diff --git a/sys/geom/journal/g_journal_ufs.c b/sys/geom/journal/g_journal_ufs.c index de0dbd83d48b..028c68079482 100644 --- a/sys/geom/journal/g_journal_ufs.c +++ b/sys/geom/journal/g_journal_ufs.c @@ -72,7 +72,7 @@ g_journal_ufs_dirty(struct g_consumer *cp) fs = NULL; if (SBLOCKSIZE % cp->provider->sectorsize != 0 || - ffs_sbget(cp, &fs, -1, M_GEOM, g_use_g_read_data) != 0) { + ffs_sbget(cp, &fs, STDSB, 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 b247eaad827d..4c4d43cad0f7 100644 --- a/sys/geom/label/g_label_ufs.c +++ b/sys/geom/label/g_label_ufs.c @@ -77,7 +77,7 @@ g_label_ufs_taste_common(struct g_consumer *cp, char *label, size_t size, int wh fs = NULL; if (SBLOCKSIZE % pp->sectorsize != 0 || - ffs_sbget(cp, &fs, -1, M_GEOM, g_use_g_read_data) != 0) { + ffs_sbget(cp, &fs, STDSB, M_GEOM, g_use_g_read_data) != 0) { KASSERT(fs == NULL, ("g_label_ufs_taste_common: non-NULL fs %p\n", fs)); return; diff --git a/sys/ufs/ffs/ffs_extern.h b/sys/ufs/ffs/ffs_extern.h index d3f6cb597b9a..16f517d5f12e 100644 --- a/sys/ufs/ffs/ffs_extern.h +++ b/sys/ufs/ffs/ffs_extern.h @@ -125,6 +125,12 @@ void process_deferred_inactive(struct mount *mp); #define FFSR_FORCE 0x0001 #define FFSR_UNSUSPEND 0x0002 +/* + * Request standard superblock location in ffs_sbget + */ +#define STDSB -1 /* Fail if check-hash is bad */ +#define STDSB_NOHASHFAIL -2 /* Ignore check-hash failure */ + /* * Definitions for TRIM interface * diff --git a/sys/ufs/ffs/ffs_subr.c b/sys/ufs/ffs/ffs_subr.c index e4dbd730b186..64354bbd5383 100644 --- a/sys/ufs/ffs/ffs_subr.c +++ b/sys/ufs/ffs/ffs_subr.c @@ -51,6 +51,11 @@ struct malloc_type; #define UFS_MALLOC(size, type, flags) malloc(size) #define UFS_FREE(ptr, type) free(ptr) #define UFS_TIME time(NULL) +/* + * Request standard superblock location in ffs_sbget + */ +#define STDSB -1 /* Fail if check-hash is bad */ +#define STDSB_NOHASHFAIL -2 /* Ignore check-hash failure */ #else /* _KERNEL */ #include @@ -139,14 +144,14 @@ ffs_load_inode(struct buf *bp, struct inode *ip, struct fs *fs, ino_t ino) ip->i_gid = dip2->di_gid; return (0); } -#endif /* KERNEL */ +#endif /* _KERNEL */ /* * These are the low-level functions that actually read and write * the superblock and its associated data. */ static off_t sblock_try[] = SBLOCKSEARCH; -static int readsuper(void *, struct fs **, off_t, int, +static int readsuper(void *, struct fs **, off_t, int, int, int (*)(void *, off_t, void **, int)); /* @@ -177,21 +182,25 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock, int i, error, size, blks; uint8_t *space; int32_t *lp; + int chkhash; char *buf; fs = NULL; *fsp = NULL; - if (altsblock != -1) { - if ((error = readsuper(devfd, &fs, altsblock, 1, + chkhash = 1; + if (altsblock >= 0) { + if ((error = readsuper(devfd, &fs, altsblock, 1, chkhash, readfunc)) != 0) { if (fs != NULL) UFS_FREE(fs, filltype); return (error); } } else { + if (altsblock == STDSB_NOHASHFAIL) + chkhash = 0; for (i = 0; sblock_try[i] != -1; i++) { if ((error = readsuper(devfd, &fs, sblock_try[i], 0, - readfunc)) == 0) + chkhash, readfunc)) == 0) break; if (fs != NULL) { UFS_FREE(fs, filltype); @@ -255,7 +264,7 @@ ffs_sbget(void *devfd, struct fs **fsp, off_t altsblock, */ static int readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk, - int (*readfunc)(void *devfd, off_t loc, void **bufp, int size)) + int chkhash, int (*readfunc)(void *devfd, off_t loc, void **bufp, int size)) { struct fs *fs; int error, res; @@ -285,8 +294,9 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk, if (fs->fs_ckhash != (ckhash = ffs_calc_sbhash(fs))) { #ifdef _KERNEL res = uprintf("Superblock check-hash failed: recorded " - "check-hash 0x%x != computed check-hash 0x%x\n", - fs->fs_ckhash, ckhash); + "check-hash 0x%x != computed check-hash 0x%x%s\n", + fs->fs_ckhash, ckhash, + chkhash == 0 ? " (Ignored)" : ""); #else res = 0; #endif @@ -297,7 +307,14 @@ readsuper(void *devfd, struct fs **fsp, off_t sblockloc, int isaltsblk, if (res == 0) printf("Superblock check-hash failed: recorded " "check-hash 0x%x != computed check-hash " - "0x%x\n", fs->fs_ckhash, ckhash); + "0x%x%s\n", fs->fs_ckhash, ckhash, + chkhash == 0 ? " (Ignored)" : ""); + if (chkhash == 0) { + fs->fs_flags |= FS_NEEDSFSCK; + fs->fs_fmod = 1; + return (0); + } + fs->fs_fmod = 0; return (EINVAL); } /* Have to set for old filesystems that predate this field */ diff --git a/sys/ufs/ffs/ffs_vfsops.c b/sys/ufs/ffs/ffs_vfsops.c index 9670d6217e86..7cb81cfa450a 100644 --- a/sys/ufs/ffs/ffs_vfsops.c +++ b/sys/ufs/ffs/ffs_vfsops.c @@ -774,6 +774,7 @@ ffs_mountfs(devvp, mp, td) struct g_consumer *cp; struct mount *nmp; int candelete; + off_t loc; fs = NULL; ump = NULL; @@ -810,9 +811,11 @@ ffs_mountfs(devvp, mp, td) goto out; } /* fetch the superblock and summary information */ - if ((error = ffs_sbget(devvp, &fs, -1, M_UFSMNT, ffs_use_bread)) != 0) + loc = STDSB; + if ((mp->mnt_flag & MNT_ROOTFS) != 0) + loc = STDSB_NOHASHFAIL; + if ((error = ffs_sbget(devvp, &fs, loc, M_UFSMNT, ffs_use_bread)) != 0) goto out; - fs->fs_fmod = 0; /* none of these types of check-hashes are maintained by this kernel */ fs->fs_metackhash &= ~(CK_INODE | CK_INDIR | CK_DIR); /* no support for any undefined flags */ diff --git a/usr.sbin/fstyp/ufs.c b/usr.sbin/fstyp/ufs.c index 340119dada4c..4002fc89c9ee 100644 --- a/usr.sbin/fstyp/ufs.c +++ b/usr.sbin/fstyp/ufs.c @@ -50,7 +50,7 @@ fstyp_ufs(FILE *fp, char *label, size_t labelsize) { struct fs *fs; - switch (sbget(fileno(fp), &fs, -1)) { + switch (sbget(fileno(fp), &fs, STDSB)) { case 0: strlcpy(label, fs->fs_volname, labelsize); return (0); diff --git a/usr.sbin/quot/quot.c b/usr.sbin/quot/quot.c index 348946ff7dbb..18b1e398ec09 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, -1)) { + switch (sbget(fd, &fs, STDSB)) { case 0: break; case ENOENT: