tech-kern archive
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index][Old Index]
Re: clearing bogus journal
On Mon, Aug 17, 2009 at 11:52:26PM +0200, Manuel Bouyer wrote:
> Hi,
> I have some old filesystems (from the NetBSD 1.x date) that refuses to
> mount -o log, or even r/w, after fsck_ffs -c4:
> # mount -o log /usr
> ffs_wapbl: unknown journal type 255
> mount_ffs: /dev/raid1e on /usr: incorrect super block
> # mount /dev/raid1e /usr
> ffs_wapbl: unknown journal type 255
> mount_ffs: /dev/raid1e on /usr: incorrect super block
>
> [...]
> A second question is whenever fsck_ffs should do minimum checks against
> the log integrity, and ask for help if it finds a problem. My guess is that
> it should propose to clear the log flag(s) and do a "normal" ffs check in
> such a case. Any idea on what proper behavior of fsck_ffs would be
> with log ?
Attached is a patch adding basic checks to fsck_ffs about the journal
feature. fsck -p should detect that the kernel won't be able to mount
the filesystem R/W and abort the boot. In non-preen mode it should
also be able to clear the bogus journal or journal flags.
What it does is always check journal-related values in the
superblock for bogus values, and tries to read the journal.
For my test case that gives:
# fsck -p
/dev/rraid0a: file system is clean; not checking
INVALID JOURNAL FLAGS -1
/dev/rraid1e: UNEXPECTED INCONSISTENCY; RUN fsck_ffs MANUALLY.
/dev/rraid1f: file system is journaled; not checking
/dev/rraid1g: file system is journaled; not checking
THE FOLLOWING FILE SYSTEM HAD AN UNEXPECTED INCONSISTENCY:
ffs: /dev/rraid1e (/usr)
# echo $?
8
# fsck /usr
** /dev/rraid1e
INVALID JOURNAL FLAGS -1
CONTINUE? [yn] y
CLEARING JOURNAL FLAGS
** File system is already clean
** Last Mounted on /usr
** Phase 1 - Check Blocks and Sizes
** Phase 2 - Check Pathnames
** Phase 3 - Check Connectivity
** Phase 4 - Check Reference Counts
** Phase 5 - Check Cyl groups
26344 files, 419200 used, 77031 free (999 frags, 9504 blocks, 0.2%
fragmentation)
***** FILE SYSTEM WAS MODIFIED *****
# fsck -p
/dev/rraid0a: file system is clean; not checking
/dev/rraid1e: file system is clean; not checking
/dev/rraid1f: file system is journaled; not checking
/dev/rraid1g: file system is journaled; not checking
# mount -a
# mount
/dev/raid0a on / type ffs (log, local)
/dev/raid1e on /usr type ffs (local)
/dev/raid1f on /var type ffs (log, local)
/dev/raid1g on /home type ffs (log, local)
mfs:21 on /tmp type mfs (synchronous, local)
I also tried clearing/recreating the log:
# tunefs -l0 /usr
tunefs: tuning /dev/rraid1e
tunefs: log file size cleared from 0
# fsck -p
/dev/rraid0a: file system is clean; not checking
/dev/rraid1e: file system is clean; not checking
/dev/rraid1f: file system is clean; not checking
/dev/rraid1g: file system is clean; not checking
# tunefs -l64m /usr
tunefs: tuning /dev/rraid1e
tunefs: log file size set to 67108864
# fsck -p
/dev/rraid0a: file system is clean; not checking
/dev/rraid1e: file system is clean; not checking
/dev/rraid1f: file system is clean; not checking
/dev/rraid1g: file system is clean; not checking
and after an unclean shutdown:
# fsck -p
/dev/rraid0a: file system is journaled; not checking
/dev/rraid1e: file system is journaled; not checking
/dev/rraid1f: file system is journaled; not checking
/dev/rraid1g: file system is journaled; not checking
# mount -a
/: replaying log to disk
/usr: replaying log to disk
/var: replaying log to disk
/home: replaying log to disk
Any comments ?
--
Manuel Bouyer, LIP6, Universite Paris VI.
Manuel.Bouyer%lip6.fr@localhost
NetBSD: 26 ans d'experience feront toujours la difference
--
Index: extern.h
===================================================================
RCS file: /cvsroot/src/sbin/fsck_ffs/extern.h,v
retrieving revision 1.24
diff -u -p -u -r1.24 extern.h
--- extern.h 30 Aug 2008 10:46:16 -0000 1.24
+++ extern.h 20 Aug 2009 17:05:18 -0000
@@ -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);
Index: setup.c
===================================================================
RCS file: /cvsroot/src/sbin/fsck_ffs/setup.c,v
retrieving revision 1.84
diff -u -p -u -r1.84 setup.c
--- setup.c 30 Aug 2008 10:46:16 -0000 1.84
+++ setup.c 20 Aug 2009 17:05:18 -0000
@@ -173,24 +173,35 @@ setup(const char *dev, const char *origd
doskipclean = 0;
pwarn("USING ALTERNATE SUPERBLOCK AT %d\n", bflag);
}
- if (sblock->fs_flags & FS_DOWAPBL) {
- if (preen) {
+ /* 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) {
+ if (!quiet)
+ pwarn("file system is journaled; "
+ "not checking\n");
+ return (-1);
+ }
if (!quiet)
- pwarn("file system is journaled; not
checking\n");
- return (-1);
+ 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
+ */
}
- if (!quiet)
- 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
- */
}
if (debug)
printf("clean = %d\n", sblock->fs_clean);
Index: wapbl.c
===================================================================
RCS file: /cvsroot/src/sbin/fsck_ffs/wapbl.c,v
retrieving revision 1.2
diff -u -p -u -r1.2 wapbl.c
--- wapbl.c 31 Jul 2008 05:38:04 -0000 1.2
+++ wapbl.c 20 Aug 2009 17:05:18 -0000
@@ -89,60 +89,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) {
@@ -200,3 +148,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;
+}
Home |
Main Index |
Thread Index |
Old Index