mirror of
https://git.FreeBSD.org/src.git
synced 2024-11-25 07:49:18 +00:00
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
This commit is contained in:
parent
dc9e68ad01
commit
b21582ee03
@ -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);
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
|
@ -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);
|
||||
|
@ -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");
|
||||
|
@ -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)
|
||||
|
@ -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:
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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");
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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,
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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) {
|
||||
|
@ -79,26 +79,30 @@
|
||||
{ SBLOCK_UFS2, SBLOCK_UFS1, SBLOCK_FLOPPY, SBLOCK_PIGGY, -1 }
|
||||
/*
|
||||
* Request standard superblock location in ffs_sbget().
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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 */
|
||||
#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.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* 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.
|
||||
|
@ -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:
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user