Whamcloud - gitweb
Add support for use of an external journal (so long as the external
authorTheodore Ts'o <tytso@mit.edu>
Mon, 23 Jul 2001 04:17:49 +0000 (00:17 -0400)
committerTheodore Ts'o <tytso@mit.edu>
Mon, 23 Jul 2001 04:17:49 +0000 (00:17 -0400)
journal only has one filesystem).

e2fsck/ChangeLog
e2fsck/e2fsck.8.in
e2fsck/e2fsck.c
e2fsck/e2fsck.h
e2fsck/journal.c
e2fsck/problem.c
e2fsck/problem.h
e2fsck/unix.c
lib/ext2fs/ChangeLog
lib/ext2fs/ext2_err.et.in

index b191359..d69d349 100644 (file)
@@ -1,3 +1,32 @@
+2001-07-22  Theodore Tso  <tytso@valinux.com>
+
+       * journal.c (ll_rw_block): Use ctx->journal_io instead of the
+               filesystem's io_channel.
+               (e2fsck_journal_init_dev): New function which supports 
+               initialization of the external journal.
+               (e2fsck_get_journal): Remove code which flagged an error
+               if the superblock reported the use of an external journal.
+               (ext3_journal_via_mount): Remove unsued, #ifdefed out function.
+
+       * problem.c, problem.h: Removed error codes no longer used
+               (PR_0_JOURNAL_UNSUPP_DEV, PR_0_JOURNAL_BAD_DEV,
+               PR_0_JOURNAL_UNSUPP_UUID) and replace them with new error
+               codes related with failures in loading the external
+               journal (PR_0_JOURNAL_UNSUPP_MULTIFS,
+               PR_0_CANT_FIND_JOURNAL, PR_0_EXT_JOURNAL_BAD_SUPER).
+               Also changed the text assocated with PR_0_JOURNAL_BAD_UUID
+               to reflect the case where the external journal isn't
+               correct for this filesystem.
+
+       * unix.c (PRS), e2fsck.8.in: Add new option -j which allows
+               the user to specify the pathname to find the external journal.
+
+       * e2fsck.c (e2fsck_reset_context): Close journal_io if it isn't
+               the same as the filesystem io_channel.
+
+       * e2fsck.h: Add new fields (journal_io and journal_name) in the
+               context structure to support external journals.
+
 2001-07-20  Theodore Tso  <tytso@valinux.com>
 
        * unix.c (main): Add an explicit warning when the filesystem is
index 378c908..f484f24 100644 (file)
@@ -26,6 +26,11 @@ e2fsck \- check a Linux second extended file system
 .B \-C
 .I fd
 ]
+@JDEV@[
+@JDEV@.B \-j
+@JDEV@.I external-journal
+@JDEV@]
+@JDEV@[
 .I device
 .SH DESCRIPTION
 .B e2fsck
@@ -117,6 +122,10 @@ Flush the filesystem device's buffer caches before beginning.  Only
 really useful for doing 
 .B e2fsck 
 time trials.
+@JDEV@.TP
+@JDEV@.BI \-j " external-journal"
+@JDEV@Set the pathname where the external-journal for this filesystem can be
+@JDEV@found.
 .TP
 .BI \-l " filename"
 Add the blocks listed in the file specified by 
index 3d9750c..0f61672 100644 (file)
@@ -62,6 +62,11 @@ errcode_t e2fsck_reset_context(e2fsck_t ctx)
                ext2fs_free_icount(ctx->inode_link_info);
                ctx->inode_link_info = 0;
        }
+       if (ctx->journal_io) {
+               if (ctx->fs && ctx->fs->io == ctx->journal_io)
+                       io_channel_close(ctx->journal_io);
+               ctx->journal_io = 0;
+       }
        if (ctx->fs && ctx->fs->dblist) {
                ext2fs_free_dblist(ctx->fs->dblist);
                ctx->fs->dblist = 0;
index a5c58ad..2ce49ae 100644 (file)
@@ -208,6 +208,12 @@ struct e2fsck_struct {
        int process_inode_size;
        int inode_buffer_blocks;
 
+       /*
+        * ext3 journal support
+        */
+       io_channel      journal_io;
+       const char      *journal_name;
+
 #ifdef RESOURCE_TRACK
        /*
         * For timing purposes
index dcdcfb9..7768b9b 100644 (file)
@@ -78,7 +78,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
                if (rw == READ && !bh->b_uptodate) {
                        jfs_debug(3, "reading block %lu/%p\n", 
                                  (unsigned long) bh->b_blocknr, (void *) bh);
-                       retval = io_channel_read_blk(bh->b_ctx->fs->io, 
+                       retval = io_channel_read_blk(bh->b_ctx->journal_io, 
                                                     bh->b_blocknr,
                                                     1, bh->b_data);
                        if (retval) {
@@ -92,7 +92,7 @@ void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
                } else if (rw == WRITE && bh->b_dirty) {
                        jfs_debug(3, "writing block %lu/%p\n", 
                                  (unsigned long) bh->b_blocknr, (void *) bh);
-                       retval = io_channel_write_blk(bh->b_ctx->fs->io, 
+                       retval = io_channel_write_blk(bh->b_ctx->journal_io, 
                                                      bh->b_blocknr,
                                                      1, bh->b_data);
                        if (retval) {
@@ -159,7 +159,6 @@ static void e2fsck_clear_recover(e2fsck_t ctx, int error)
 
 static errcode_t e2fsck_journal_init_inode(e2fsck_t ctx,
                                           struct ext2_super_block *s,
-                                          ext2_ino_t journal_inum,
                                           journal_t **journal)
 {
        struct inode *inode;
@@ -167,7 +166,7 @@ static errcode_t e2fsck_journal_init_inode(e2fsck_t ctx,
        blk_t start;
        int retval;
 
-       jfs_debug(1, "Using journal inode %u\n", journal_inum);
+       jfs_debug(1, "Using journal inode %u\n", s->s_journal_inum);
        *journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
        if (!*journal) {
                return EXT2_ET_NO_MEMORY;
@@ -180,8 +179,8 @@ static errcode_t e2fsck_journal_init_inode(e2fsck_t ctx,
        }
 
        inode->i_ctx = ctx;
-       inode->i_ino = journal_inum;
-       retval = ext2fs_read_inode(ctx->fs, journal_inum, &inode->i_ext2);
+       inode->i_ino = s->s_journal_inum;
+       retval = ext2fs_read_inode(ctx->fs, s->s_journal_inum, &inode->i_ext2);
        if (retval)
                goto exit_inode;
 
@@ -189,6 +188,7 @@ static errcode_t e2fsck_journal_init_inode(e2fsck_t ctx,
        (*journal)->j_inode = inode;
        (*journal)->j_blocksize = ctx->fs->blocksize;
        (*journal)->j_maxlen = inode->i_ext2.i_size / (*journal)->j_blocksize;
+       ctx->journal_io = ctx->fs->io;
 
        if (!inode->i_ext2.i_links_count ||
            !LINUX_S_ISREG(inode->i_ext2.i_mode) ||
@@ -205,7 +205,7 @@ static errcode_t e2fsck_journal_init_inode(e2fsck_t ctx,
        }
        (*journal)->j_sb_buffer = bh;
        (*journal)->j_superblock = (journal_superblock_t *)bh->b_data;
-
+       
        return 0;
 
 exit_inode:
@@ -216,59 +216,102 @@ exit_journal:
        return retval;
 }
 
-static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **journal)
+static errcode_t e2fsck_journal_init_dev(e2fsck_t ctx,
+                                        struct ext2_super_block *s,
+                                        journal_t **journal)
 {
-       char uuid_str[40];
+       struct buffer_head *bh;
+       io_manager      io_ptr;
+       blk_t           start;
+       int             retval;
+       int             blocksize = ctx->fs->blocksize;
+       struct ext2_super_block jsuper;
        struct problem_context pctx;
-       struct ext2_super_block *sb = ctx->fs->super;
 
        clear_problem_context(&pctx);
+       if (!ctx->journal_name)
+               ctx->journal_name = ext2fs_find_block_device(s->s_journal_dev);
 
-       if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
-               /* FIXME: check if dev is valid block dev, has a journal */
-               if (sb->s_journal_dev) {
-                       pctx.num = sb->s_journal_dev;
-                       /* this problem aborts on -y, -p, unsupported on -n */
-                       if (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_DEV, &pctx))
-                               return EXT2_ET_UNSUPP_FEATURE;
-                       sb->s_journal_dev = 0;
-                       sb->s_state &= ~EXT2_VALID_FS;
-                       ext2fs_mark_super_dirty(ctx->fs);
-               }
-               /* FIXME: check if UUID is valid block dev, has a journal */
-               if (!uuid_is_null(sb->s_journal_uuid)) {
-                       uuid_unparse(sb->s_journal_uuid, uuid_str);
-                       pctx.str = uuid_str;
-                       /* this problem aborts on -y, -p, unsupported on -n */
-                       if (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_UUID, &pctx))
-                               return EXT2_ET_UNSUPP_FEATURE;
-                       uuid_clear(sb->s_journal_uuid);
-                       sb->s_state &= ~EXT2_VALID_FS;
-                       ext2fs_mark_super_dirty(ctx->fs);
-               }
-               if (!sb->s_journal_inum)
-                       return EXT2_ET_BAD_INODE_NUM;
+       if (!ctx->journal_name) {
+               fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
+               return EXT2_ET_LOAD_EXT_JOURNAL;
        }
 
-       if (sb->s_journal_dev) {
-               pctx.num = sb->s_journal_dev;
-               if (!fix_problem(ctx, PR_0_JOURNAL_BAD_DEV, &pctx))
-                       return EXT2_ET_UNSUPP_FEATURE;
-               sb->s_journal_dev = 0;
-               sb->s_state &= ~EXT2_VALID_FS;
-               ext2fs_mark_super_dirty(ctx->fs);
+       jfs_debug(1, "Using journal file %s\n", ctx->journal_name);
+
+#if 1
+       io_ptr = unix_io_manager;
+#else
+       io_ptr = test_io_manager;
+       test_io_backing_manager = unix_io_manager;
+#endif
+       if ((retval = io_ptr->open(ctx->journal_name, IO_FLAG_RW,
+                                           &ctx->journal_io)))
+               return retval;
+
+       io_channel_set_blksize(ctx->journal_io, blocksize);
+       start = (blocksize == 1024) ? 1 : 0;
+       bh = getblk(ctx, start, blocksize);
+       if (!bh)
+               return EXT2_ET_NO_MEMORY;
+       ll_rw_block(READ, 1, &bh);
+       if (bh->b_err)
+               return bh->b_err;
+       memcpy(&jsuper, start ? bh->b_data :  bh->b_data + 1024,
+              sizeof(jsuper));
+       brelse(bh);
+#ifdef EXT2FS_ENABLE_SWAPFS
+       if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) 
+               ext2fs_swap_super(&jsuper);
+#endif
+       if (jsuper.s_magic != EXT2_SUPER_MAGIC ||
+           !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) {
+               fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx);
+               return EXT2_ET_LOAD_EXT_JOURNAL;
        }
-       if (!uuid_is_null(sb->s_journal_uuid)) {
-               uuid_unparse(sb->s_journal_uuid, uuid_str);
-               pctx.str = uuid_str;
-               if (!fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx))
-                       return EXT2_ET_UNSUPP_FEATURE;
-               uuid_clear(sb->s_journal_uuid);
-               sb->s_state &= ~EXT2_VALID_FS;
-               ext2fs_mark_super_dirty(ctx->fs);
+       /* Make sure the journal UUID is correct */
+       if (memcmp(jsuper.s_uuid, ctx->fs->super->s_journal_uuid,
+                  sizeof(jsuper.s_uuid))) {
+               fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx);
+               return EXT2_ET_LOAD_EXT_JOURNAL;
        }
+               
+       *journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
+       if (!*journal) {
+               return EXT2_ET_NO_MEMORY;
+       }
+
+       (*journal)->j_dev = ctx;
+       (*journal)->j_inode = NULL;
+       (*journal)->j_blocksize = ctx->fs->blocksize;
+       (*journal)->j_maxlen = jsuper.s_blocks_count;
+
+       bh = getblk(ctx, start+1, (*journal)->j_blocksize);
+       if (!bh) {
+               retval = EXT2_ET_NO_MEMORY;
+               goto errout;
+       }
+       (*journal)->j_sb_buffer = bh;
+       (*journal)->j_superblock = (journal_superblock_t *)bh->b_data;
+       
+       return 0;
 
-       return e2fsck_journal_init_inode(ctx, sb, sb->s_journal_inum, journal);
+errout:
+       ext2fs_free_mem((void **)journal);
+       return retval;
+}
+
+static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **journal)
+{
+       struct ext2_super_block *sb = ctx->fs->super;
+
+       if (uuid_is_null(sb->s_journal_uuid)) {
+               if (!sb->s_journal_inum)
+                       return EXT2_ET_BAD_INODE_NUM;
+               return e2fsck_journal_init_inode(ctx, sb, journal);
+       } else {
+               return e2fsck_journal_init_dev(ctx, sb, journal);
+       }
 }
 
 static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
@@ -332,6 +375,10 @@ static errcode_t e2fsck_journal_load(journal_t *journal)
                
        case JFS_SUPERBLOCK_V2:
                journal->j_format_version = 2;
+               if (ntohl(jsb->s_nr_users) > 1) {
+                       fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
+                       return EXT2_ET_JOURNAL_UNSUPP_VERSION;
+               }
                break;
 
        /*
@@ -600,109 +647,6 @@ errout:
        return retval;
 }
 
-
-#if 0
-#define TEMPLATE "/tmp/ext3.XXXXXX"
-
-/*
- * This function attempts to mount and unmount an ext3 filesystem,
- * which is a cheap way to force the kernel to run the journal and
- * handle the recovery for us.
- */
-static errcode_t recover_ext3_journal_via_mount(e2fsck_t ctx)
-{
-       ext2_filsys fs = ctx->fs;
-       char    *dirlist[] = {"/mnt","/lost+found","/tmp","/root","/boot",0};
-       errcode_t        retval, retval2;
-       int      count = 0;
-       char     template[] = TEMPLATE;
-       struct stat buf;
-       char    *tmpdir;
-
-       if (ctx->options & E2F_OPT_READONLY) {
-               printf("%s: won't do journal recovery while read-only\n",
-                      ctx->device_name);
-               return EXT2_ET_FILE_RO;
-       }
-
-       printf(_("%s: trying for ext3 kernel journal recovery\n"),
-              ctx->device_name);
-       /*
-        * First try to make a temporary directory.  This may fail if
-        * the root partition is still mounted read-only.
-        */
-newtemp:
-       tmpdir = mktemp(template);
-       if (tmpdir) {
-               jfs_debug(2, "trying %s as ext3 temp mount point\n", tmpdir);
-               if (mkdir(template, 0700)) {
-                       if (errno == EROFS) {
-                               tmpdir = NULL;
-                               template[0] = '\0';
-                       } else if (errno == EEXIST && count++ < 10) {
-                               strcpy(template, TEMPLATE);
-                               goto newtemp;
-                       }
-                       return errno;
-               }
-       }
-
-       /*
-        * OK, creating a temporary directory didn't work.
-        * Let's try a list of possible temporary mountpoints.
-        */
-       if (!tmpdir) {
-               dev_t   rootdev;
-               char    **cpp, *dir;
-
-               if (stat("/", &buf))
-                       return errno;
-
-               rootdev = buf.st_dev;
-
-               /*
-                * Check that dir is on the same device as root (no other
-                * filesystem is mounted there), and it's a directory.
-                */
-               for (cpp = dirlist; (dir = *cpp); cpp++)
-                       if (stat(dir, &buf) == 0 && buf.st_dev == rootdev &&
-                           S_ISDIR(buf.st_mode)) {
-                               tmpdir = dir;
-                               break;
-                       }
-       }
-
-       if (tmpdir) {
-               io_manager      io_ptr = fs->io->manager;
-               int             blocksize = fs->blocksize;
-
-               jfs_debug(2, "using %s for ext3 mount\n", tmpdir);
-               /* FIXME - need to handle loop devices here */
-               if (mount(ctx->device_name, tmpdir, "ext3", MNT_FL, NULL)) {
-                       retval = errno;
-                       com_err(ctx->program_name, errno,
-                               "when mounting %s", ctx->device_name);
-                       if (template[0])
-                               rmdir(tmpdir);
-                       return retval;
-               }
-               /*
-                * Now that it mounted cleanly, the filesystem will have been
-                * recovered, so we can now unmount it.
-                */
-               if (umount(tmpdir))
-                       return errno;
-
-               /*
-                * Remove the temporary directory, if it was created.
-                */
-               if (template[0])
-                       rmdir(tmpdir);
-               return 0;
-       }
-}
-#endif
-
 int e2fsck_run_ext3_journal(e2fsck_t ctx)
 {
        io_manager io_ptr = ctx->fs->io->manager;
index 2ded448..34a3784 100644 (file)
@@ -179,25 +179,25 @@ static const struct e2fsck_problem problem_table[] = {
          N_("@S has a bad ext3 @j (@i %i).\n"),
          PROMPT_CLEAR, PR_PREEN_OK },
 
-       /* Superblock has a journal device (which we can't handle yet) */
-       { PR_0_JOURNAL_UNSUPP_DEV,
-         N_("@S has external ext3 @j @v (unsupported).\n"),
-         PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_DEV },
-
-       /* Superblock has a bad journal device */
-       { PR_0_JOURNAL_BAD_DEV,
-         N_("@S has a bad ext3 @j (@v %X).\n"),
-         PROMPT_CLEAR, PR_PREEN_OK },
+       /* The external journal has (unsupported) multiple filesystems */
+       { PR_0_JOURNAL_UNSUPP_MULTIFS,
+         N_("External @j has multiple @f users (unsupported).\n"),
+         PROMPT_NONE, PR_FATAL },
 
-       /* Superblock has a journal UUID (which we can't handle yet) */
-       { PR_0_JOURNAL_UNSUPP_UUID,
-         N_("@S has an ext3 @j UUID (unsupported).\n"),
-         PROMPT_ABORT, PR_NO_OK | PR_AFTER_CODE, PR_0_JOURNAL_BAD_UUID },
+       /* Can't find external journal */
+       { PR_0_CANT_FIND_JOURNAL,
+         N_("Can't find external @j\n"),
+         PROMPT_NONE, PR_FATAL },
+
+       /* External journal has bad superblock */
+       { PR_0_EXT_JOURNAL_BAD_SUPER,
+         N_("External @j has bad @S\n"),
+         PROMPT_NONE, PR_FATAL },
 
        /* Superblock has a bad journal UUID */
        { PR_0_JOURNAL_BAD_UUID,
-         N_("@S has a bad ext3 @j (UUID %s).\n"),
-         PROMPT_CLEAR, PR_PREEN_OK },
+         N_("External @j does not support this @f\n"),
+         PROMPT_NONE, PR_FATAL },
 
        /* Journal has an unknown superblock type */
        { PR_0_JOURNAL_UNSUPP_SUPER,
index be35fc9..7dec436 100644 (file)
@@ -98,14 +98,14 @@ struct problem_context {
 /* Journal inode is invalid */
 #define PR_0_JOURNAL_BAD_INODE 0x00000F
 
-/* Superblock has a journal device (which we can't handle yet) */
-#define PR_0_JOURNAL_UNSUPP_DEV        0x000010
+/* The external journal has multiple filesystems (which we can't handle yet) */
+#define PR_0_JOURNAL_UNSUPP_MULTIFS 0x000010
 
-/* Superblock has a bad journal device */
-#define PR_0_JOURNAL_BAD_DEV   0x000011
+/* Can't find external journal */
+#define PR_0_CANT_FIND_JOURNAL 0x000011
 
-/* Superblock has a journal UUID (which we can't handle yet) */
-#define PR_0_JOURNAL_UNSUPP_UUID 0x000012
+/* External journal has bad superblock */
+#define PR_0_EXT_JOURNAL_BAD_SUPER 0x000012
 
 /* Superblock has a bad journal UUID */
 #define PR_0_JOURNAL_BAD_UUID  0x000013
index 3e52fec..c9c11b3 100644 (file)
@@ -65,7 +65,7 @@ static void usage(e2fsck_t ctx)
        fprintf(stderr,
                _("Usage: %s [-panyrcdfvstFSV] [-b superblock] [-B blocksize]\n"
                "\t\t[-I inode_buffer_blocks] [-P process_inode_size]\n"
-               "\t\t[-l|-L bad_blocks_file] [-C fd] device\n"),
+               "\t\t[-l|-L bad_blocks_file] [-C fd] [-j ext-journal] device\n"),
                ctx->program_name);
 
        fprintf(stderr, _("\nEmergency help:\n"
@@ -78,6 +78,7 @@ static void usage(e2fsck_t ctx)
                " -v                   Be verbose\n"
                " -b superblock        Use alternative superblock\n"
                " -B blocksize         Force blocksize when looking for superblock\n"
+               " -j external-journal  Set location of the external journal\n"
                " -l bad_blocks_file   Add to badblocks list\n"
                " -L bad_blocks_file   Set badblocks list\n"
                ));
@@ -485,7 +486,7 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                ctx->program_name = *argv;
        else
                ctx->program_name = "e2fsck";
-       while ((c = getopt (argc, argv, "panyrcC:B:dfvtFVM:b:I:P:l:L:N:Ss")) != EOF)
+       while ((c = getopt (argc, argv, "panyrcC:B:dfvtFVM:b:I:j:P:l:L:N:Ss")) != EOF)
                switch (c) {
                case 'C':
                        ctx->progress = e2fsck_update_progress;
@@ -544,6 +545,9 @@ static errcode_t PRS(int argc, char *argv[], e2fsck_t *ret_ctx)
                case 'I':
                        ctx->inode_buffer_blocks = atoi(optarg);
                        break;
+               case 'j':
+                       ctx->journal_name = optarg;
+                       break;
                case 'P':
                        ctx->process_inode_size = atoi(optarg);
                        break;
index e62f6fd..76873a5 100644 (file)
@@ -1,3 +1,7 @@
+2001-07-21  Theodore Tso  <tytso@valinux.com>
+
+       * ext2_err.et.in (EXT2_ET_LOAD_EXT_JOURNAL): Add new error code
+
 2001-07-20  Theodore Tso  <tytso@valinux.com>
 
        * ext_attr.c (ext2fs_write_ext_attr): When writing the extended
index c4f84c9..235f75d 100644 (file)
@@ -269,5 +269,8 @@ ec  EXT2_ET_JOURNAL_TOO_SMALL,
 ec     EXT2_ET_JOURNAL_UNSUPP_VERSION,
        "Unsupported journal version"
 
+ec     EXT2_ET_LOAD_EXT_JOURNAL,
+       "Error loading external journal"
+
        end