From: Theodore Ts'o Date: Mon, 23 Jul 2001 04:17:49 +0000 (-0400) Subject: Add support for use of an external journal (so long as the external X-Git-Tag: E2FSPROGS-1_23-WIP-0722~2 X-Git-Url: https://git.whamcloud.com/gitweb?a=commitdiff_plain;h=adee8d75db09dc8ecb2a32f59a8c64d3f4c64b0e;p=tools%2Fe2fsprogs.git Add support for use of an external journal (so long as the external journal only has one filesystem). --- diff --git a/e2fsck/ChangeLog b/e2fsck/ChangeLog index b191359..d69d349 100644 --- a/e2fsck/ChangeLog +++ b/e2fsck/ChangeLog @@ -1,3 +1,32 @@ +2001-07-22 Theodore Tso + + * 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 * unix.c (main): Add an explicit warning when the filesystem is diff --git a/e2fsck/e2fsck.8.in b/e2fsck/e2fsck.8.in index 378c908..f484f24 100644 --- a/e2fsck/e2fsck.8.in +++ b/e2fsck/e2fsck.8.in @@ -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 diff --git a/e2fsck/e2fsck.c b/e2fsck/e2fsck.c index 3d9750c..0f61672 100644 --- a/e2fsck/e2fsck.c +++ b/e2fsck/e2fsck.c @@ -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; diff --git a/e2fsck/e2fsck.h b/e2fsck/e2fsck.h index a5c58ad..2ce49ae 100644 --- a/e2fsck/e2fsck.h +++ b/e2fsck/e2fsck.h @@ -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 diff --git a/e2fsck/journal.c b/e2fsck/journal.c index dcdcfb9..7768b9b 100644 --- a/e2fsck/journal.c +++ b/e2fsck/journal.c @@ -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; diff --git a/e2fsck/problem.c b/e2fsck/problem.c index 2ded448..34a3784 100644 --- a/e2fsck/problem.c +++ b/e2fsck/problem.c @@ -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, diff --git a/e2fsck/problem.h b/e2fsck/problem.h index be35fc9..7dec436 100644 --- a/e2fsck/problem.h +++ b/e2fsck/problem.h @@ -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 diff --git a/e2fsck/unix.c b/e2fsck/unix.c index 3e52fec..c9c11b3 100644 --- a/e2fsck/unix.c +++ b/e2fsck/unix.c @@ -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; diff --git a/lib/ext2fs/ChangeLog b/lib/ext2fs/ChangeLog index e62f6fd..76873a5 100644 --- a/lib/ext2fs/ChangeLog +++ b/lib/ext2fs/ChangeLog @@ -1,3 +1,7 @@ +2001-07-21 Theodore Tso + + * ext2_err.et.in (EXT2_ET_LOAD_EXT_JOURNAL): Add new error code + 2001-07-20 Theodore Tso * ext_attr.c (ext2fs_write_ext_attr): When writing the extended diff --git a/lib/ext2fs/ext2_err.et.in b/lib/ext2fs/ext2_err.et.in index c4f84c9..235f75d 100644 --- a/lib/ext2fs/ext2_err.et.in +++ b/lib/ext2fs/ext2_err.et.in @@ -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