Do some basic checks of the WAPBL journal, to abort the boot before the
kernel refuse to mount a filesystem read-write (booting a system multiuser with critical filesystems read-only is bad): Add a check_wapbl() which will check some WAPBL values in the superblock, and try to read the journal via wapbl_replay_start() if there is one. pfatal() if one of these fail (abort boot if in preen mode, as "CONTINUE" otherwise). In non-preen mode the bogus journal will be cleared. check_wapbl() is always called if the superblock supports WAPBL. Even if FS_DOWAPBL is not there, there could be flags asking the kernel to clear or create a log with bogus values which would cause the kernel refuse to mount the filesystem. Discussed in http://mail-index.netbsd.org/tech-kern/2009/08/17/msg005896.html and followups.
This commit is contained in:
parent
32992733fa
commit
cab6cd67bc
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: extern.h,v 1.24 2008/08/30 10:46:16 bouyer Exp $ */
|
||||
/* $NetBSD: extern.h,v 1.25 2009/09/13 14:25:28 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1994 James A. Jegers
|
||||
@ -82,6 +82,7 @@ void setinodebuf(ino_t);
|
||||
int setup(const char *, const char *);
|
||||
void voidquit(int);
|
||||
|
||||
int check_wapbl(void);
|
||||
void replay_wapbl(void);
|
||||
void cleanup_wapbl(void);
|
||||
int read_wapbl(char *, long, daddr_t);
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: setup.c,v 1.87 2009/04/07 05:50:11 mrg Exp $ */
|
||||
/* $NetBSD: setup.c,v 1.88 2009/09/13 14:25:28 bouyer Exp $ */
|
||||
|
||||
/*
|
||||
* Copyright (c) 1980, 1986, 1993
|
||||
@ -34,7 +34,7 @@
|
||||
#if 0
|
||||
static char sccsid[] = "@(#)setup.c 8.10 (Berkeley) 5/9/95";
|
||||
#else
|
||||
__RCSID("$NetBSD: setup.c,v 1.87 2009/04/07 05:50:11 mrg Exp $");
|
||||
__RCSID("$NetBSD: setup.c,v 1.88 2009/09/13 14:25:28 bouyer Exp $");
|
||||
#endif
|
||||
#endif /* not lint */
|
||||
|
||||
@ -173,25 +173,36 @@ setup(const char *dev, const char *origdev)
|
||||
doskipclean = 0;
|
||||
pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
|
||||
}
|
||||
/* ffs_superblock_layout() == 2 */
|
||||
if (sblock->fs_magic != FS_UFS1_MAGIC ||
|
||||
(sblock->fs_old_flags & FS_FLAGS_UPDATED) != 0) {
|
||||
/* can have WAPBL */
|
||||
if (check_wapbl() != 0) {
|
||||
doskipclean = 0;
|
||||
}
|
||||
if (sblock->fs_flags & FS_DOWAPBL) {
|
||||
if (preen && skipclean) {
|
||||
if (preen) {
|
||||
if (!quiet)
|
||||
pwarn("file system is journaled; not checking\n");
|
||||
pwarn("file system is journaled; "
|
||||
"not checking\n");
|
||||
return (-1);
|
||||
}
|
||||
if (!quiet)
|
||||
pwarn("** File system is journaled; replaying journal\n");
|
||||
pwarn("** File system is journaled; "
|
||||
"replaying journal\n");
|
||||
replay_wapbl();
|
||||
doskipclean = 0;
|
||||
sblock->fs_flags &= ~FS_DOWAPBL;
|
||||
sbdirty();
|
||||
/* Although we may have updated the superblock from the
|
||||
* journal, we are still going to do a full check, so we
|
||||
* don't bother to re-read the superblock from the journal.
|
||||
* XXX, instead we could re-read the superblock and then not
|
||||
* force doskipclean = 0
|
||||
/* Although we may have updated the superblock from
|
||||
* the journal, we are still going to do a full check,
|
||||
* so we don't bother to re-read the superblock from
|
||||
* the journal.
|
||||
* XXX, instead we could re-read the superblock and
|
||||
* then not force doskipclean = 0
|
||||
*/
|
||||
}
|
||||
}
|
||||
if (debug)
|
||||
printf("clean = %d\n", sblock->fs_clean);
|
||||
if (doswap)
|
||||
|
@ -1,4 +1,4 @@
|
||||
/* $NetBSD: wapbl.c,v 1.3 2008/11/10 20:12:13 joerg Exp $ */
|
||||
/* $NetBSD: wapbl.c,v 1.4 2009/09/13 14:25:28 bouyer Exp $ */
|
||||
|
||||
/*-
|
||||
* Copyright (c) 2005,2008 The NetBSD Foundation, Inc.
|
||||
@ -34,7 +34,7 @@
|
||||
#define WAPBL_INTERNAL
|
||||
|
||||
#include <sys/cdefs.h>
|
||||
__KERNEL_RCSID(0, "$NetBSD: wapbl.c,v 1.3 2008/11/10 20:12:13 joerg Exp $");
|
||||
__KERNEL_RCSID(0, "$NetBSD: wapbl.c,v 1.4 2009/09/13 14:25:28 bouyer Exp $");
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/time.h>
|
||||
@ -90,60 +90,8 @@ struct wapbl_replay *wapbl_replay;
|
||||
void
|
||||
replay_wapbl(void)
|
||||
{
|
||||
uint64_t addr, count, blksize;
|
||||
int error;
|
||||
|
||||
if (debug)
|
||||
wapbl_debug_print = WAPBL_PRINT_ERROR | WAPBL_PRINT_REPLAY;
|
||||
if (debug > 1)
|
||||
wapbl_debug_print |= WAPBL_PRINT_IO;
|
||||
|
||||
if (sblock->fs_journal_version != UFS_WAPBL_VERSION) {
|
||||
pfatal("INVALID JOURNAL VERSION %d",
|
||||
sblock->fs_journal_version);
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
switch (sblock->fs_journal_location) {
|
||||
case UFS_WAPBL_JOURNALLOC_NONE:
|
||||
pfatal("INVALID JOURNAL LOCATION 'NONE'");
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
return;
|
||||
|
||||
case UFS_WAPBL_JOURNALLOC_END_PARTITION:
|
||||
addr = sblock->fs_journallocs[UFS_WAPBL_EPART_ADDR];
|
||||
count = sblock->fs_journallocs[UFS_WAPBL_EPART_COUNT];
|
||||
blksize = sblock->fs_journallocs[UFS_WAPBL_EPART_BLKSZ];
|
||||
break;
|
||||
|
||||
case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
|
||||
addr = sblock->fs_journallocs[UFS_WAPBL_INFS_ADDR];
|
||||
count = sblock->fs_journallocs[UFS_WAPBL_INFS_COUNT];
|
||||
blksize = sblock->fs_journallocs[UFS_WAPBL_INFS_BLKSZ];
|
||||
break;
|
||||
|
||||
default:
|
||||
pfatal("INVALID JOURNAL LOCATION %d",
|
||||
sblock->fs_journal_location);
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
error = wapbl_replay_start(&wapbl_replay, 0, addr, count, blksize);
|
||||
if (error) {
|
||||
pfatal("UNABLE TO READ JOURNAL FOR REPLAY");
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
return;
|
||||
}
|
||||
if (!nflag) {
|
||||
error = wapbl_replay_write(wapbl_replay, 0);
|
||||
if (error) {
|
||||
@ -201,3 +149,125 @@ is_journal_inode(ino_t ino)
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
check_wapbl(void)
|
||||
{
|
||||
uint64_t addr = 0, count = 0, blksize = 0;
|
||||
int error;
|
||||
int ret = 0;
|
||||
if (debug)
|
||||
wapbl_debug_print = WAPBL_PRINT_ERROR | WAPBL_PRINT_REPLAY;
|
||||
if (debug > 1)
|
||||
wapbl_debug_print |= WAPBL_PRINT_IO;
|
||||
|
||||
if (sblock->fs_flags & FS_DOWAPBL) {
|
||||
if (sblock->fs_journal_version != UFS_WAPBL_VERSION) {
|
||||
pfatal("INVALID JOURNAL VERSION %d",
|
||||
sblock->fs_journal_version);
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
pwarn("CLEARING EXISTING JOURNAL\n");
|
||||
sblock->fs_flags &= ~FS_DOWAPBL;
|
||||
sbdirty();
|
||||
ret = FSCK_EXIT_CHECK_FAILED;
|
||||
} else {
|
||||
switch(sblock->fs_journal_location) {
|
||||
case UFS_WAPBL_JOURNALLOC_END_PARTITION:
|
||||
addr =
|
||||
sblock->fs_journallocs[UFS_WAPBL_EPART_ADDR];
|
||||
count =
|
||||
sblock->fs_journallocs[UFS_WAPBL_EPART_COUNT];
|
||||
blksize =
|
||||
sblock->fs_journallocs[UFS_WAPBL_EPART_BLKSZ];
|
||||
break;
|
||||
case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
|
||||
addr =
|
||||
sblock->fs_journallocs[UFS_WAPBL_INFS_ADDR];
|
||||
count =
|
||||
sblock->fs_journallocs[UFS_WAPBL_INFS_COUNT];
|
||||
blksize =
|
||||
sblock->fs_journallocs[UFS_WAPBL_INFS_BLKSZ];
|
||||
break;
|
||||
default:
|
||||
pfatal("INVALID JOURNAL LOCATION %d",
|
||||
sblock->fs_journal_location);
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
pwarn("CLEARING EXISTING JOURNAL\n");
|
||||
sblock->fs_flags &= ~FS_DOWAPBL;
|
||||
sblock->fs_journal_location =
|
||||
UFS_WAPBL_JOURNALLOC_NONE;
|
||||
sbdirty();
|
||||
ret = FSCK_EXIT_CHECK_FAILED;
|
||||
break;
|
||||
}
|
||||
if (sblock->fs_flags & FS_DOWAPBL) {
|
||||
error = wapbl_replay_start(
|
||||
&wapbl_replay, 0, addr, count, blksize);
|
||||
if (error) {
|
||||
pfatal(
|
||||
"UNABLE TO READ JOURNAL FOR REPLAY");
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
pwarn("CLEARING EXISTING JOURNAL\n");
|
||||
sblock->fs_flags &= ~FS_DOWAPBL;
|
||||
sbdirty();
|
||||
ret = FSCK_EXIT_CHECK_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
/*
|
||||
* at this time fs_journal_flags can only be 0,
|
||||
* UFS_WAPBL_FLAGS_CREATE_LOG or UFS_WAPBL_FLAGS_CLEAR_LOG.
|
||||
* We can't have both flags at the same time.
|
||||
*/
|
||||
switch (sblock->fs_journal_flags) {
|
||||
case 0:
|
||||
break;
|
||||
case UFS_WAPBL_FLAGS_CREATE_LOG:
|
||||
case UFS_WAPBL_FLAGS_CLEAR_LOG:
|
||||
switch(sblock->fs_journal_location) {
|
||||
case UFS_WAPBL_JOURNALLOC_END_PARTITION:
|
||||
case UFS_WAPBL_JOURNALLOC_IN_FILESYSTEM:
|
||||
break;
|
||||
case UFS_WAPBL_JOURNALLOC_NONE:
|
||||
if (sblock->fs_journal_flags ==
|
||||
UFS_WAPBL_FLAGS_CLEAR_LOG)
|
||||
break;
|
||||
/* FALLTHROUGH */
|
||||
default:
|
||||
pfatal("INVALID JOURNAL LOCATION %d",
|
||||
sblock->fs_journal_location);
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
pwarn("CLEARING JOURNAL FLAGS\n");
|
||||
sblock->fs_journal_flags = 0;
|
||||
sblock->fs_journal_location =
|
||||
UFS_WAPBL_JOURNALLOC_NONE;
|
||||
sbdirty();
|
||||
ret = FSCK_EXIT_CHECK_FAILED;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
pfatal("INVALID JOURNAL FLAGS %d",
|
||||
sblock->fs_journal_flags);
|
||||
if (reply("CONTINUE") == 0) {
|
||||
exit(FSCK_EXIT_CHECK_FAILED);
|
||||
}
|
||||
pwarn("CLEARING JOURNAL FLAGS\n");
|
||||
sblock->fs_journal_flags = 0;
|
||||
sblock->fs_journal_location =
|
||||
UFS_WAPBL_JOURNALLOC_NONE;
|
||||
sbdirty();
|
||||
ret = FSCK_EXIT_CHECK_FAILED;
|
||||
break;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user