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