2000-07-07 08:13:21 +04:00
|
|
|
/*
|
|
|
|
* journal.c --- code for handling the "ext3" journal
|
2000-08-14 18:25:19 +04:00
|
|
|
*
|
|
|
|
* Copyright (C) 2000 Andreas Dilger
|
|
|
|
* Copyright (C) 2000 Theodore Ts'o
|
|
|
|
*
|
|
|
|
* Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie
|
|
|
|
* Copyright (C) 1999 Red Hat Software
|
|
|
|
*
|
|
|
|
* This file may be redistributed under the terms of the
|
|
|
|
* GNU General Public License version 2 or at your discretion
|
|
|
|
* any later version.
|
2000-07-07 08:13:21 +04:00
|
|
|
*/
|
|
|
|
|
2000-08-14 18:25:19 +04:00
|
|
|
#ifdef HAVE_SYS_MOUNT_H
|
|
|
|
#include <sys/mount.h>
|
|
|
|
#define MNT_FL (MS_MGC_VAL | MS_RDONLY)
|
|
|
|
#endif
|
|
|
|
#ifdef HAVE_SYS_STAT_H
|
|
|
|
#include <sys/stat.h>
|
|
|
|
#endif
|
2000-07-07 08:13:21 +04:00
|
|
|
|
2001-01-06 08:55:58 +03:00
|
|
|
#define E2FSCK_INCLUDE_INLINE_FUNCS
|
2000-12-09 09:41:25 +03:00
|
|
|
#include "jfs_user.h"
|
2000-08-14 18:25:19 +04:00
|
|
|
#include "problem.h"
|
|
|
|
#include "uuid/uuid.h"
|
2000-07-07 08:13:21 +04:00
|
|
|
|
2000-08-14 18:25:19 +04:00
|
|
|
#ifdef JFS_DEBUG
|
|
|
|
static int bh_count = 0;
|
2000-12-09 09:41:25 +03:00
|
|
|
int journal_enable_debug = 0;
|
2000-08-14 18:25:19 +04:00
|
|
|
#endif
|
|
|
|
|
2000-12-30 23:33:42 +03:00
|
|
|
/* Kernel compatibility functions for handling the journal. These allow us
|
|
|
|
* to use the recovery.c file virtually unchanged from the kernel, so we
|
|
|
|
* don't have to do much to keep kernel and user recovery in sync.
|
|
|
|
*/
|
2000-08-14 18:25:19 +04:00
|
|
|
int bmap(struct inode *inode, int block)
|
|
|
|
{
|
|
|
|
int retval;
|
|
|
|
blk_t phys;
|
|
|
|
|
|
|
|
retval = ext2fs_bmap(inode->i_ctx->fs, inode->i_ino, &inode->i_ext2,
|
|
|
|
NULL, 0, block, &phys);
|
|
|
|
|
|
|
|
if (retval)
|
|
|
|
com_err(inode->i_ctx->device_name, retval,
|
|
|
|
_("bmap journal inode %ld, block %d\n"),
|
|
|
|
inode->i_ino, block);
|
|
|
|
|
|
|
|
return phys;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct buffer_head *getblk(e2fsck_t ctx, blk_t blocknr, int blocksize)
|
|
|
|
{
|
|
|
|
struct buffer_head *bh;
|
|
|
|
|
|
|
|
bh = e2fsck_allocate_memory(ctx, sizeof(*bh), "block buffer");
|
|
|
|
if (!bh)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n",
|
2001-01-06 08:55:58 +03:00
|
|
|
(unsigned long) blocknr, blocksize, ++bh_count);
|
2000-08-14 18:25:19 +04:00
|
|
|
|
|
|
|
bh->b_ctx = ctx;
|
|
|
|
bh->b_size = blocksize;
|
|
|
|
bh->b_blocknr = blocknr;
|
|
|
|
|
|
|
|
return bh;
|
|
|
|
}
|
|
|
|
|
2000-12-09 09:41:25 +03:00
|
|
|
void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
|
2000-08-14 18:25:19 +04:00
|
|
|
{
|
|
|
|
int retval;
|
2000-12-09 09:41:25 +03:00
|
|
|
struct buffer_head *bh;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
2000-12-09 09:41:25 +03:00
|
|
|
for (; nr > 0; --nr) {
|
|
|
|
bh = *bhp++;
|
|
|
|
if (rw == READ && !bh->b_uptodate) {
|
|
|
|
jfs_debug(3, "reading block %lu/%p\n",
|
2001-01-06 08:55:58 +03:00
|
|
|
(unsigned long) bh->b_blocknr, (void *) bh);
|
2000-12-09 09:41:25 +03:00
|
|
|
retval = io_channel_read_blk(bh->b_ctx->fs->io,
|
|
|
|
bh->b_blocknr,
|
|
|
|
1, bh->b_data);
|
|
|
|
if (retval) {
|
|
|
|
com_err(bh->b_ctx->device_name, retval,
|
|
|
|
"while reading block %ld\n",
|
|
|
|
bh->b_blocknr);
|
|
|
|
bh->b_err = retval;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bh->b_uptodate = 1;
|
|
|
|
} else if (rw == WRITE && bh->b_dirty) {
|
|
|
|
jfs_debug(3, "writing block %lu/%p\n",
|
2001-01-06 08:55:58 +03:00
|
|
|
(unsigned long) bh->b_blocknr, (void *) bh);
|
2000-12-09 09:41:25 +03:00
|
|
|
retval = io_channel_write_blk(bh->b_ctx->fs->io,
|
|
|
|
bh->b_blocknr,
|
|
|
|
1, bh->b_data);
|
|
|
|
if (retval) {
|
|
|
|
com_err(bh->b_ctx->device_name, retval,
|
|
|
|
"while writing block %ld\n",
|
|
|
|
bh->b_blocknr);
|
|
|
|
bh->b_err = retval;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bh->b_dirty = 0;
|
|
|
|
bh->b_uptodate = 1;
|
|
|
|
} else
|
|
|
|
jfs_debug(3, "no-op %s for block %lu\n",
|
|
|
|
rw == READ ? "read" : "write",
|
2001-01-06 08:55:58 +03:00
|
|
|
(unsigned long) bh->b_blocknr);
|
2000-12-09 09:41:25 +03:00
|
|
|
}
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
void mark_buffer_dirty(struct buffer_head *bh, int dummy)
|
|
|
|
{
|
|
|
|
bh->b_dirty = dummy | 1; /* use dummy to avoid unused variable */
|
|
|
|
}
|
|
|
|
|
|
|
|
void brelse(struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
if (bh->b_dirty)
|
2000-12-09 09:41:25 +03:00
|
|
|
ll_rw_block(WRITE, 1, &bh);
|
2000-08-14 18:25:19 +04:00
|
|
|
jfs_debug(3, "freeing block %lu/%p (total %d)\n",
|
2001-01-06 08:55:58 +03:00
|
|
|
(unsigned long) bh->b_blocknr, (void *) bh, --bh_count);
|
2000-08-14 18:25:19 +04:00
|
|
|
ext2fs_free_mem((void **) &bh);
|
|
|
|
}
|
|
|
|
|
|
|
|
int buffer_uptodate(struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
return bh->b_uptodate;
|
|
|
|
}
|
|
|
|
|
|
|
|
void wait_on_buffer(struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
if (!bh->b_uptodate)
|
2000-12-09 09:41:25 +03:00
|
|
|
ll_rw_block(READ, 1, &bh);
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
|
2000-08-14 18:25:19 +04:00
|
|
|
static void e2fsck_clear_recover(e2fsck_t ctx, int error)
|
|
|
|
{
|
2001-01-01 18:51:50 +03:00
|
|
|
ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
|
|
|
/* if we had an error doing journal recovery, we need a full fsck */
|
|
|
|
if (error)
|
2001-01-01 18:51:50 +03:00
|
|
|
ctx->fs->super->s_state &= ~EXT2_VALID_FS;
|
2000-08-14 18:25:19 +04:00
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
|
|
|
|
2001-01-01 18:51:50 +03:00
|
|
|
static int e2fsck_journal_init_inode(e2fsck_t ctx,
|
|
|
|
struct ext2_super_block *s,
|
Many files:
dirinfo.c, e2fsck.h, emptydir.c, iscan.c, jfs_user.h, journal.c,
message.c, pass1.c, pass1b.c, pass2.c, pass3.c, pass4.c, pass5.c,
problem.h, scantest.c, super.c, swapfs.c: Change ino_t to ext2_ino_t.
2001-01-11 18:12:14 +03:00
|
|
|
ext2_ino_t journal_inum,
|
|
|
|
journal_t **journal)
|
2000-08-14 18:25:19 +04:00
|
|
|
{
|
|
|
|
struct inode *inode;
|
|
|
|
struct buffer_head *bh;
|
|
|
|
blk_t start;
|
|
|
|
int retval;
|
|
|
|
|
Many files:
dirinfo.c, e2fsck.h, emptydir.c, iscan.c, jfs_user.h, journal.c,
message.c, pass1.c, pass1b.c, pass2.c, pass3.c, pass4.c, pass5.c,
problem.h, scantest.c, super.c, swapfs.c: Change ino_t to ext2_ino_t.
2001-01-11 18:12:14 +03:00
|
|
|
jfs_debug(1, "Using journal inode %u\n", journal_inum);
|
2000-08-14 18:25:19 +04:00
|
|
|
*journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
|
|
|
|
if (!*journal) {
|
|
|
|
return EXT2_ET_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
|
|
|
inode = e2fsck_allocate_memory(ctx, sizeof(*inode), "journal inode");
|
|
|
|
if (!inode) {
|
|
|
|
retval = EXT2_ET_NO_MEMORY;
|
|
|
|
goto exit_journal;
|
|
|
|
}
|
|
|
|
|
|
|
|
inode->i_ctx = ctx;
|
|
|
|
inode->i_ino = journal_inum;
|
|
|
|
retval = ext2fs_read_inode(ctx->fs, journal_inum, &inode->i_ext2);
|
|
|
|
if (retval)
|
|
|
|
goto exit_inode;
|
|
|
|
|
|
|
|
(*journal)->j_dev = ctx;
|
|
|
|
(*journal)->j_inode = inode;
|
|
|
|
(*journal)->j_blocksize = ctx->fs->blocksize;
|
|
|
|
(*journal)->j_maxlen = inode->i_ext2.i_size / (*journal)->j_blocksize;
|
|
|
|
|
|
|
|
if (!inode->i_ext2.i_links_count ||
|
|
|
|
!LINUX_S_ISREG(inode->i_ext2.i_mode) ||
|
|
|
|
(*journal)->j_maxlen < JFS_MIN_JOURNAL_BLOCKS ||
|
|
|
|
(start = bmap(inode, 0)) == 0) {
|
|
|
|
retval = EXT2_ET_BAD_INODE_NUM;
|
|
|
|
goto exit_inode;
|
|
|
|
}
|
|
|
|
|
|
|
|
bh = getblk(ctx, start, (*journal)->j_blocksize);
|
|
|
|
if (!bh) {
|
|
|
|
retval = EXT2_ET_NO_MEMORY;
|
|
|
|
goto exit_inode;
|
|
|
|
}
|
|
|
|
(*journal)->j_sb_buffer = bh;
|
|
|
|
(*journal)->j_superblock = (journal_superblock_t *)bh->b_data;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
exit_inode:
|
|
|
|
ext2fs_free_mem((void **)&inode);
|
|
|
|
exit_journal:
|
|
|
|
ext2fs_free_mem((void **)journal);
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int e2fsck_get_journal(e2fsck_t ctx, journal_t **journal)
|
|
|
|
{
|
|
|
|
char uuid_str[40];
|
|
|
|
struct problem_context pctx;
|
2001-01-01 18:51:50 +03:00
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
|
|
|
clear_problem_context(&pctx);
|
|
|
|
|
2001-01-01 18:51:50 +03:00
|
|
|
if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
|
|
|
|
if (sb->s_journal_dev) {
|
|
|
|
pctx.num = sb->s_journal_dev;
|
2000-08-14 18:25:19 +04:00
|
|
|
/* this problem aborts on -y, -p, unsupported on -n */
|
|
|
|
if (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_DEV, &pctx))
|
|
|
|
return EXT2_ET_UNSUPP_FEATURE;
|
2001-01-01 18:51:50 +03:00
|
|
|
sb->s_journal_dev = 0;
|
|
|
|
sb->s_state &= ~EXT2_VALID_FS;
|
2000-08-14 18:25:19 +04:00
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
2001-01-01 18:51:50 +03:00
|
|
|
if (!uuid_is_null(sb->s_journal_uuid)) {
|
|
|
|
uuid_unparse(sb->s_journal_uuid, uuid_str);
|
2000-08-14 18:25:19 +04:00
|
|
|
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;
|
2001-01-01 18:51:50 +03:00
|
|
|
uuid_clear(sb->s_journal_uuid);
|
|
|
|
sb->s_state &= ~EXT2_VALID_FS;
|
2000-08-14 18:25:19 +04:00
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
2001-01-01 18:51:50 +03:00
|
|
|
if (!sb->s_journal_inum)
|
2000-08-14 18:25:19 +04:00
|
|
|
return EXT2_ET_BAD_INODE_NUM;
|
|
|
|
}
|
|
|
|
|
2001-01-01 18:51:50 +03:00
|
|
|
if (sb->s_journal_dev) {
|
|
|
|
pctx.num = sb->s_journal_dev;
|
2000-08-14 18:25:19 +04:00
|
|
|
if (!fix_problem(ctx, PR_0_JOURNAL_BAD_DEV, &pctx))
|
|
|
|
return EXT2_ET_UNSUPP_FEATURE;
|
2001-01-01 18:51:50 +03:00
|
|
|
sb->s_journal_dev = 0;
|
|
|
|
sb->s_state &= ~EXT2_VALID_FS;
|
2000-08-14 18:25:19 +04:00
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
2001-01-01 18:51:50 +03:00
|
|
|
if (!uuid_is_null(sb->s_journal_uuid)) {
|
|
|
|
uuid_unparse(sb->s_journal_uuid, uuid_str);
|
2000-08-14 18:25:19 +04:00
|
|
|
pctx.str = uuid_str;
|
|
|
|
if (!fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx))
|
|
|
|
return EXT2_ET_UNSUPP_FEATURE;
|
2001-01-01 18:51:50 +03:00
|
|
|
uuid_clear(sb->s_journal_uuid);
|
|
|
|
sb->s_state &= ~EXT2_VALID_FS;
|
2000-08-14 18:25:19 +04:00
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
|
|
|
|
2001-01-01 18:51:50 +03:00
|
|
|
return e2fsck_journal_init_inode(ctx, sb, sb->s_journal_inum, journal);
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
|
|
|
|
struct problem_context *pctx)
|
|
|
|
{
|
2001-01-01 18:51:50 +03:00
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
|
|
|
int recover = ctx->fs->super->s_feature_incompat &
|
|
|
|
EXT3_FEATURE_INCOMPAT_RECOVER;
|
|
|
|
int has_journal = ctx->fs->super->s_feature_compat &
|
|
|
|
EXT3_FEATURE_COMPAT_HAS_JOURNAL;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
2001-01-01 18:51:50 +03:00
|
|
|
if (has_journal || sb->s_journal_inum) {
|
2000-08-14 18:25:19 +04:00
|
|
|
/* The journal inode is bogus, remove and force full fsck */
|
2001-01-12 18:30:25 +03:00
|
|
|
pctx->ino = sb->s_journal_inum;
|
2000-08-14 18:25:19 +04:00
|
|
|
if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
|
2001-01-01 18:51:50 +03:00
|
|
|
if (has_journal && sb->s_journal_inum)
|
2000-08-14 18:25:19 +04:00
|
|
|
printf("*** ext3 journal has been deleted - "
|
|
|
|
"filesystem is now ext2 only ***\n\n");
|
2001-01-01 18:51:50 +03:00
|
|
|
sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
|
|
|
|
sb->s_journal_inum = 0;
|
2000-08-14 18:25:19 +04:00
|
|
|
e2fsck_clear_recover(ctx, 1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return EXT2_ET_BAD_INODE_NUM;
|
|
|
|
} else if (recover) {
|
|
|
|
if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) {
|
|
|
|
e2fsck_clear_recover(ctx, 1);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return EXT2_ET_UNSUPP_FEATURE;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int e2fsck_journal_fix_unsupported_super(e2fsck_t ctx,
|
|
|
|
struct problem_context *pctx)
|
|
|
|
{
|
2001-01-01 18:51:50 +03:00
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
|
|
|
/* Unsupported journal superblock - first choice is abort.
|
|
|
|
* Declining that gives the option to reset the superblock.
|
|
|
|
*
|
|
|
|
* Otherwise we get the chance to delete the journal, and
|
|
|
|
* failing that we abort because we can't handle this.
|
|
|
|
*/
|
2001-01-01 18:51:50 +03:00
|
|
|
if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
|
2000-08-14 18:25:19 +04:00
|
|
|
fix_problem(ctx, PR_0_JOURNAL_UNSUPP_SUPER, pctx))
|
|
|
|
return EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
|
|
|
|
if (e2fsck_journal_fix_bad_inode(ctx, pctx))
|
|
|
|
return EXT2_ET_UNSUPP_FEATURE;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int e2fsck_journal_load(journal_t *journal)
|
|
|
|
{
|
|
|
|
e2fsck_t ctx = journal->j_dev;
|
|
|
|
journal_superblock_t *jsb;
|
|
|
|
struct buffer_head *jbh = journal->j_sb_buffer;
|
|
|
|
struct problem_context pctx;
|
|
|
|
|
|
|
|
clear_problem_context(&pctx);
|
|
|
|
|
2000-12-09 09:41:25 +03:00
|
|
|
ll_rw_block(READ, 1, &jbh);
|
2000-08-14 18:25:19 +04:00
|
|
|
if (jbh->b_err) {
|
|
|
|
com_err(ctx->device_name, jbh->b_err,
|
|
|
|
_("reading journal superblock\n"));
|
|
|
|
return jbh->b_err;
|
|
|
|
}
|
|
|
|
|
|
|
|
jsb = journal->j_superblock;
|
|
|
|
/* If we don't even have JFS_MAGIC, we probably have a wrong inode */
|
|
|
|
if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER))
|
|
|
|
return e2fsck_journal_fix_bad_inode(ctx, &pctx);
|
|
|
|
|
2000-12-09 09:41:25 +03:00
|
|
|
switch (ntohl(jsb->s_header.h_blocktype)) {
|
|
|
|
case JFS_SUPERBLOCK_V1:
|
|
|
|
journal->j_format_version = 1;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case JFS_SUPERBLOCK_V2:
|
|
|
|
journal->j_format_version = 2;
|
|
|
|
break;
|
|
|
|
|
|
|
|
/* If we don't understand the superblock major type, but there
|
|
|
|
* is a magic number, then it is likely to be a new format we
|
|
|
|
* just don't understand, so leave it alone. */
|
|
|
|
default:
|
|
|
|
com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
|
|
|
|
_("%s: journal has unrecognised format\n"),
|
|
|
|
ctx->device_name);
|
|
|
|
return EXT2_ET_UNSUPP_FEATURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES)) {
|
|
|
|
com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
|
|
|
|
_("%s: journal has incompatible features\n"),
|
|
|
|
ctx->device_name);
|
|
|
|
return EXT2_ET_UNSUPP_FEATURE;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES)) {
|
|
|
|
com_err(ctx->program_name, EXT2_ET_UNSUPP_FEATURE,
|
|
|
|
_("%s: journal has readonly-incompatible features\n"),
|
|
|
|
ctx->device_name);
|
|
|
|
return EXT2_ET_RO_UNSUPP_FEATURE;
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
|
2000-12-09 09:41:25 +03:00
|
|
|
/* We have now checked whether we know enough about the journal
|
|
|
|
* format to be able to proceed safely, so any other checks that
|
|
|
|
* fail we should attempt to recover from. */
|
|
|
|
if (jsb->s_blocksize != htonl(journal->j_blocksize)) {
|
|
|
|
com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
|
|
|
|
_("%s: no valid journal superblock found\n"),
|
|
|
|
ctx->device_name);
|
|
|
|
return EXT2_ET_CORRUPT_SUPERBLOCK;
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
if (ntohl(jsb->s_maxlen) < journal->j_maxlen)
|
|
|
|
journal->j_maxlen = ntohl(jsb->s_maxlen);
|
|
|
|
else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) {
|
2000-12-09 09:41:25 +03:00
|
|
|
com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
|
|
|
|
_("%s: journal too short\n"),
|
|
|
|
ctx->device_name);
|
2000-08-14 18:25:19 +04:00
|
|
|
return EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
}
|
|
|
|
|
|
|
|
journal->j_tail_sequence = ntohl(jsb->s_sequence);
|
ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
e2fsck_check_ext3_journal to smash the journal because
journal->j_transaction_sequence wasn't getting initialized.
journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
to e2fsck_clear_recover from recover_ext3_journal to after the
filesystem has been closed and reopened. Otherwise, the superblock in
the filesystem handle will probably be stale, and will overwrite the
newer version of the superblock written by the log recovery.
message.c (expand_inode_expression): Add support for %Iu and %Ig
problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
super.c (release_orphan_inodes, release_inode_block,
release_inode_blocks): Update the block group descriptor counts when
freeing the orphan inode. Use PR_0_CLEAR_ORPHAN_INODE to report when
we clear an orphan.
journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
reopen the filesystem using the device name instead of the filesystem
name.
2000-08-21 02:06:31 +04:00
|
|
|
journal->j_transaction_sequence = journal->j_tail_sequence;
|
2000-08-14 18:25:19 +04:00
|
|
|
journal->j_tail = ntohl(jsb->s_start);
|
|
|
|
journal->j_first = ntohl(jsb->s_first);
|
|
|
|
journal->j_last = ntohl(jsb->s_maxlen);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2001-01-06 08:55:58 +03:00
|
|
|
static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
|
2000-12-09 09:41:25 +03:00
|
|
|
journal_t *journal)
|
2000-08-14 18:25:19 +04:00
|
|
|
{
|
2000-12-09 09:41:25 +03:00
|
|
|
char *p;
|
|
|
|
|
|
|
|
/* Leave a valid existing V1 superblock signature alone.
|
|
|
|
* Anything unrecognisable we overwrite with a new V2
|
|
|
|
* signature. */
|
|
|
|
|
|
|
|
if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) ||
|
|
|
|
jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) {
|
|
|
|
jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER);
|
|
|
|
jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Zero out everything else beyond the superblock header */
|
|
|
|
|
|
|
|
p = ((char *) jsb) + sizeof(journal_header_t);
|
|
|
|
memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
|
|
|
|
|
2000-08-14 18:25:19 +04:00
|
|
|
jsb->s_blocksize = htonl(ctx->fs->blocksize);
|
2000-12-09 09:41:25 +03:00
|
|
|
jsb->s_maxlen = htonl(journal->j_maxlen);
|
|
|
|
jsb->s_first = htonl(1);
|
2000-08-14 18:25:19 +04:00
|
|
|
jsb->s_sequence = htonl(1);
|
2000-12-09 09:41:25 +03:00
|
|
|
|
|
|
|
/* In theory we should also re-zero the entire journal here.
|
|
|
|
* Initialising s_sequence to a random value would be a
|
|
|
|
* reasonable compromise. */
|
|
|
|
|
|
|
|
ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
static int e2fsck_journal_fix_corrupt_super(e2fsck_t ctx, journal_t *journal,
|
|
|
|
struct problem_context *pctx)
|
|
|
|
{
|
2001-01-01 18:51:50 +03:00
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
|
|
|
int recover = ctx->fs->super->s_feature_incompat &
|
|
|
|
EXT3_FEATURE_INCOMPAT_RECOVER;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
|
|
|
pctx->num = journal->j_inode->i_ino;
|
|
|
|
|
2001-01-01 18:51:50 +03:00
|
|
|
if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
|
2000-08-14 18:25:19 +04:00
|
|
|
if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
|
2000-12-30 23:33:42 +03:00
|
|
|
e2fsck_journal_reset_super(ctx, journal->j_superblock,
|
|
|
|
journal);
|
2000-08-14 18:25:19 +04:00
|
|
|
journal->j_transaction_sequence = 1;
|
|
|
|
e2fsck_clear_recover(ctx, recover);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
return EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
} else if (e2fsck_journal_fix_bad_inode(ctx, pctx))
|
|
|
|
return EXT2_ET_CORRUPT_SUPERBLOCK;
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal, int reset)
|
|
|
|
{
|
|
|
|
journal_superblock_t *jsb;
|
|
|
|
|
|
|
|
if (!(ctx->options & E2F_OPT_READONLY)) {
|
|
|
|
jsb = journal->j_superblock;
|
|
|
|
jsb->s_sequence = htonl(journal->j_transaction_sequence);
|
|
|
|
if (reset)
|
|
|
|
jsb->s_start = 0; /* this marks the journal as empty */
|
|
|
|
mark_buffer_dirty(journal->j_sb_buffer, 1);
|
|
|
|
}
|
|
|
|
brelse(journal->j_sb_buffer);
|
|
|
|
|
|
|
|
if (journal->j_inode)
|
|
|
|
free(journal->j_inode);
|
|
|
|
ext2fs_free_mem((void **)&journal);
|
|
|
|
}
|
|
|
|
|
2000-12-13 21:50:22 +03:00
|
|
|
/*
|
|
|
|
* This function makes sure that the superblock fields regarding the
|
|
|
|
* journal are consistent.
|
|
|
|
*/
|
2000-08-14 18:25:19 +04:00
|
|
|
int e2fsck_check_ext3_journal(e2fsck_t ctx)
|
|
|
|
{
|
2001-01-01 18:51:50 +03:00
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
2000-08-14 18:25:19 +04:00
|
|
|
journal_t *journal;
|
2001-01-01 18:51:50 +03:00
|
|
|
int recover = ctx->fs->super->s_feature_incompat &
|
|
|
|
EXT3_FEATURE_INCOMPAT_RECOVER;
|
2000-08-14 18:25:19 +04:00
|
|
|
struct problem_context pctx;
|
2001-01-03 16:00:43 +03:00
|
|
|
int reset = 0, force_fsck = 0;
|
2000-08-14 18:25:19 +04:00
|
|
|
int retval;
|
|
|
|
|
|
|
|
/* If we don't have any journal features, don't do anything more */
|
2001-01-01 18:51:50 +03:00
|
|
|
if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) &&
|
|
|
|
!recover && sb->s_journal_inum == 0 && sb->s_journal_dev == 0 &&
|
|
|
|
uuid_is_null(sb->s_journal_uuid))
|
2000-12-13 21:50:22 +03:00
|
|
|
return 0;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
2001-01-03 16:00:43 +03:00
|
|
|
#ifdef JFS_DEBUG /* Enabled by configure --enable-jfs-debug */
|
2000-12-09 09:47:56 +03:00
|
|
|
journal_enable_debug = 2;
|
|
|
|
#endif
|
2000-08-14 18:25:19 +04:00
|
|
|
clear_problem_context(&pctx);
|
2001-01-01 18:51:50 +03:00
|
|
|
pctx.num = sb->s_journal_inum;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
|
|
|
retval = e2fsck_get_journal(ctx, &journal);
|
|
|
|
if (retval) {
|
|
|
|
if (retval == EXT2_ET_BAD_INODE_NUM)
|
|
|
|
return e2fsck_journal_fix_bad_inode(ctx, &pctx);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = e2fsck_journal_load(journal);
|
|
|
|
if (retval) {
|
|
|
|
if (retval == EXT2_ET_CORRUPT_SUPERBLOCK)
|
|
|
|
return e2fsck_journal_fix_corrupt_super(ctx, journal,
|
|
|
|
&pctx);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* We want to make the flags consistent here. We will not leave with
|
|
|
|
* needs_recovery set but has_journal clear. We can't get in a loop
|
|
|
|
* with -y, -n, or -p, only if a user isn't making up their mind.
|
|
|
|
*/
|
|
|
|
no_has_journal:
|
2001-01-01 18:51:50 +03:00
|
|
|
if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
|
|
|
|
recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
|
2000-08-14 18:25:19 +04:00
|
|
|
pctx.str = "inode";
|
|
|
|
if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) {
|
|
|
|
if (recover &&
|
|
|
|
!fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx))
|
|
|
|
goto no_has_journal;
|
2001-01-03 16:00:43 +03:00
|
|
|
/*
|
|
|
|
* Need a full fsck if we are releasing a
|
2001-01-03 16:14:23 +03:00
|
|
|
* journal stored on a reserved inode.
|
2001-01-03 16:00:43 +03:00
|
|
|
*/
|
|
|
|
force_fsck = recover ||
|
|
|
|
(sb->s_journal_inum < EXT2_FIRST_INODE(sb));
|
|
|
|
/* Clear all of the journal fields */
|
2001-01-01 18:51:50 +03:00
|
|
|
sb->s_journal_inum = 0;
|
2001-01-03 16:00:43 +03:00
|
|
|
sb->s_journal_dev = 0;
|
|
|
|
memset(sb->s_journal_uuid, 0,
|
|
|
|
sizeof(sb->s_journal_uuid));
|
|
|
|
e2fsck_clear_recover(ctx, force_fsck);
|
2000-08-14 18:25:19 +04:00
|
|
|
} else if (!(ctx->options & E2F_OPT_READONLY)) {
|
2001-01-01 18:51:50 +03:00
|
|
|
sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
|
2000-08-14 18:25:19 +04:00
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-01 18:51:50 +03:00
|
|
|
if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
|
|
|
|
!(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
|
2000-08-14 18:25:19 +04:00
|
|
|
journal->j_superblock->s_start != 0) {
|
2001-01-03 16:00:43 +03:00
|
|
|
if (fix_problem(ctx, PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
|
2000-08-14 18:25:19 +04:00
|
|
|
reset = 1;
|
2001-01-03 16:00:43 +03:00
|
|
|
sb->s_state &= ~EXT2_VALID_FS;
|
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
* If the user answers no to the above question, we
|
|
|
|
* ignore the fact that journal apparently has data;
|
|
|
|
* accidentally replaying over valid data would be far
|
|
|
|
* worse than skipping a questionable recovery.
|
|
|
|
*
|
|
|
|
* XXX should we abort with a fatal error here? What
|
|
|
|
* will the ext3 kernel code do if a filesystem with
|
|
|
|
* !NEEDS_RECOVERY but with a non-zero
|
|
|
|
* journal->j_superblock->s_start is mounted?
|
|
|
|
*/
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
e2fsck_journal_release(ctx, journal, reset);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
static int recover_ext3_journal(e2fsck_t ctx)
|
2000-08-14 18:25:19 +04:00
|
|
|
{
|
|
|
|
journal_t *journal;
|
|
|
|
int retval;
|
|
|
|
|
|
|
|
retval = e2fsck_get_journal(ctx, &journal);
|
|
|
|
if (retval)
|
ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
e2fsck_check_ext3_journal to smash the journal because
journal->j_transaction_sequence wasn't getting initialized.
journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
to e2fsck_clear_recover from recover_ext3_journal to after the
filesystem has been closed and reopened. Otherwise, the superblock in
the filesystem handle will probably be stale, and will overwrite the
newer version of the superblock written by the log recovery.
message.c (expand_inode_expression): Add support for %Iu and %Ig
problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
super.c (release_orphan_inodes, release_inode_block,
release_inode_blocks): Update the block group descriptor counts when
freeing the orphan inode. Use PR_0_CLEAR_ORPHAN_INODE to report when
we clear an orphan.
journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
reopen the filesystem using the device name instead of the filesystem
name.
2000-08-21 02:06:31 +04:00
|
|
|
return retval;
|
|
|
|
|
2000-08-14 18:25:19 +04:00
|
|
|
retval = e2fsck_journal_load(journal);
|
|
|
|
if (retval)
|
ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
e2fsck_check_ext3_journal to smash the journal because
journal->j_transaction_sequence wasn't getting initialized.
journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
to e2fsck_clear_recover from recover_ext3_journal to after the
filesystem has been closed and reopened. Otherwise, the superblock in
the filesystem handle will probably be stale, and will overwrite the
newer version of the superblock written by the log recovery.
message.c (expand_inode_expression): Add support for %Iu and %Ig
problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
super.c (release_orphan_inodes, release_inode_block,
release_inode_blocks): Update the block group descriptor counts when
freeing the orphan inode. Use PR_0_CLEAR_ORPHAN_INODE to report when
we clear an orphan.
journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
reopen the filesystem using the device name instead of the filesystem
name.
2000-08-21 02:06:31 +04:00
|
|
|
return retval;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
2000-12-09 09:41:25 +03:00
|
|
|
retval = journal_init_revoke(journal, 1024);
|
|
|
|
if (retval)
|
|
|
|
return retval;
|
|
|
|
|
2000-08-14 18:25:19 +04:00
|
|
|
retval = -journal_recover(journal);
|
|
|
|
e2fsck_journal_release(ctx, journal, 1);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
#if 0
|
2000-08-14 18:25:19 +04:00
|
|
|
#define TEMPLATE "/tmp/ext3.XXXXXX"
|
2000-07-07 08:13:21 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This function attempts to mount and unmount an ext3 filesystem,
|
|
|
|
* which is a cheap way to force the kernel to run the journal and
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
* handle the recovery for us.
|
2000-07-07 08:13:21 +04:00
|
|
|
*/
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
static int recover_ext3_journal_via_mount(e2fsck_t ctx)
|
2000-07-07 08:13:21 +04:00
|
|
|
{
|
2000-08-14 18:25:19 +04:00
|
|
|
ext2_filsys fs = ctx->fs;
|
|
|
|
char *dirlist[] = {"/mnt","/lost+found","/tmp","/root","/boot",0};
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
errcode_t retval, retval2;
|
2000-08-14 18:25:19 +04:00
|
|
|
int count = 0;
|
|
|
|
char template[] = TEMPLATE;
|
|
|
|
struct stat buf;
|
2000-07-07 08:13:21 +04:00
|
|
|
char *tmpdir;
|
|
|
|
|
2000-08-14 18:25:19 +04:00
|
|
|
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);
|
2000-07-07 08:13:21 +04:00
|
|
|
/*
|
|
|
|
* First try to make a temporary directory. This may fail if
|
|
|
|
* the root partition is still mounted read-only.
|
|
|
|
*/
|
2000-08-14 18:25:19 +04:00
|
|
|
newtemp:
|
2000-07-07 08:13:21 +04:00
|
|
|
tmpdir = mktemp(template);
|
|
|
|
if (tmpdir) {
|
2000-08-14 18:25:19 +04:00
|
|
|
jfs_debug(2, "trying %s as ext3 temp mount point\n", tmpdir);
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
if (mkdir(template, 0700)) {
|
2000-08-14 18:25:19 +04:00
|
|
|
if (errno == EROFS) {
|
|
|
|
tmpdir = NULL;
|
|
|
|
template[0] = '\0';
|
|
|
|
} else if (errno == EEXIST && count++ < 10) {
|
|
|
|
strcpy(template, TEMPLATE);
|
|
|
|
goto newtemp;
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
}
|
|
|
|
return errno;
|
2000-07-07 08:13:21 +04:00
|
|
|
}
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* 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))
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
return errno;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
|
|
|
rootdev = buf.st_dev;
|
|
|
|
|
2000-07-07 08:13:21 +04:00
|
|
|
/*
|
2000-08-14 18:25:19 +04:00
|
|
|
* Check that dir is on the same device as root (no other
|
|
|
|
* filesystem is mounted there), and it's a directory.
|
2000-07-07 08:13:21 +04:00
|
|
|
*/
|
2000-08-14 18:25:19 +04:00
|
|
|
for (cpp = dirlist; (dir = *cpp); cpp++)
|
|
|
|
if (stat(dir, &buf) == 0 && buf.st_dev == rootdev &&
|
|
|
|
S_ISDIR(buf.st_mode)) {
|
|
|
|
tmpdir = dir;
|
2000-07-07 08:13:21 +04:00
|
|
|
break;
|
2000-08-14 18:25:19 +04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
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 */
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
if (mount(ctx->device_name, tmpdir, "ext3", MNT_FL, NULL)) {
|
|
|
|
retval = errno;
|
2000-08-14 18:25:19 +04:00
|
|
|
com_err(ctx->program_name, errno,
|
|
|
|
"when mounting %s", ctx->device_name);
|
|
|
|
if (template[0])
|
|
|
|
rmdir(tmpdir);
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
return retval;
|
2000-07-07 08:13:21 +04:00
|
|
|
}
|
2000-08-14 18:25:19 +04:00
|
|
|
/*
|
|
|
|
* Now that it mounted cleanly, the filesystem will have been
|
|
|
|
* recovered, so we can now unmount it.
|
|
|
|
*/
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
if (umount(tmpdir))
|
2000-07-07 08:13:21 +04:00
|
|
|
return errno;
|
2000-08-14 18:25:19 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Remove the temporary directory, if it was created.
|
|
|
|
*/
|
|
|
|
if (template[0])
|
|
|
|
rmdir(tmpdir);
|
|
|
|
return 0;
|
2000-07-07 08:13:21 +04:00
|
|
|
}
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
}
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int e2fsck_run_ext3_journal(e2fsck_t ctx)
|
|
|
|
{
|
|
|
|
io_manager io_ptr = ctx->fs->io->manager;
|
|
|
|
int blocksize = ctx->fs->blocksize;
|
ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
e2fsck_check_ext3_journal to smash the journal because
journal->j_transaction_sequence wasn't getting initialized.
journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
to e2fsck_clear_recover from recover_ext3_journal to after the
filesystem has been closed and reopened. Otherwise, the superblock in
the filesystem handle will probably be stale, and will overwrite the
newer version of the superblock written by the log recovery.
message.c (expand_inode_expression): Add support for %Iu and %Ig
problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
super.c (release_orphan_inodes, release_inode_block,
release_inode_blocks): Update the block group descriptor counts when
freeing the orphan inode. Use PR_0_CLEAR_ORPHAN_INODE to report when
we clear an orphan.
journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
reopen the filesystem using the device name instead of the filesystem
name.
2000-08-21 02:06:31 +04:00
|
|
|
errcode_t retval, recover_retval;
|
2000-10-25 05:38:50 +04:00
|
|
|
|
|
|
|
printf(_("%s: recovering journal\n"), ctx->device_name);
|
ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
e2fsck_check_ext3_journal to smash the journal because
journal->j_transaction_sequence wasn't getting initialized.
journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
to e2fsck_clear_recover from recover_ext3_journal to after the
filesystem has been closed and reopened. Otherwise, the superblock in
the filesystem handle will probably be stale, and will overwrite the
newer version of the superblock written by the log recovery.
message.c (expand_inode_expression): Add support for %Iu and %Ig
problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
super.c (release_orphan_inodes, release_inode_block,
release_inode_blocks): Update the block group descriptor counts when
freeing the orphan inode. Use PR_0_CLEAR_ORPHAN_INODE to report when
we clear an orphan.
journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
reopen the filesystem using the device name instead of the filesystem
name.
2000-08-21 02:06:31 +04:00
|
|
|
if (ctx->options & E2F_OPT_READONLY) {
|
2000-10-25 05:38:50 +04:00
|
|
|
printf(_("%s: won't do journal recovery while read-only\n"),
|
ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
e2fsck_check_ext3_journal to smash the journal because
journal->j_transaction_sequence wasn't getting initialized.
journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
to e2fsck_clear_recover from recover_ext3_journal to after the
filesystem has been closed and reopened. Otherwise, the superblock in
the filesystem handle will probably be stale, and will overwrite the
newer version of the superblock written by the log recovery.
message.c (expand_inode_expression): Add support for %Iu and %Ig
problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
super.c (release_orphan_inodes, release_inode_block,
release_inode_blocks): Update the block group descriptor counts when
freeing the orphan inode. Use PR_0_CLEAR_ORPHAN_INODE to report when
we clear an orphan.
journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
reopen the filesystem using the device name instead of the filesystem
name.
2000-08-21 02:06:31 +04:00
|
|
|
ctx->device_name);
|
|
|
|
return EXT2_ET_FILE_RO;
|
|
|
|
}
|
|
|
|
|
|
|
|
recover_retval = recover_ext3_journal(ctx);
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
|
|
|
|
/*
|
|
|
|
* Reload the filesystem context to get up-to-date data from disk
|
|
|
|
* because journal recovery will change the filesystem under us.
|
|
|
|
*/
|
|
|
|
ext2fs_close(ctx->fs);
|
ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
e2fsck_check_ext3_journal to smash the journal because
journal->j_transaction_sequence wasn't getting initialized.
journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
to e2fsck_clear_recover from recover_ext3_journal to after the
filesystem has been closed and reopened. Otherwise, the superblock in
the filesystem handle will probably be stale, and will overwrite the
newer version of the superblock written by the log recovery.
message.c (expand_inode_expression): Add support for %Iu and %Ig
problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
super.c (release_orphan_inodes, release_inode_block,
release_inode_blocks): Update the block group descriptor counts when
freeing the orphan inode. Use PR_0_CLEAR_ORPHAN_INODE to report when
we clear an orphan.
journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
reopen the filesystem using the device name instead of the filesystem
name.
2000-08-21 02:06:31 +04:00
|
|
|
retval = ext2fs_open(ctx->filesystem_name, EXT2_FLAG_RW,
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
ctx->superblock, blocksize, io_ptr,
|
|
|
|
&ctx->fs);
|
|
|
|
|
|
|
|
if (retval) {
|
|
|
|
com_err(ctx->program_name, retval,
|
|
|
|
_("while trying to re-open %s"),
|
|
|
|
ctx->device_name);
|
2000-08-23 01:41:52 +04:00
|
|
|
fatal_error(ctx, 0);
|
Many files:
Makefile.in: Update the make dependencies
problem.c, problem.h: Add the problem codes:
PR_0_ORPHAN_ILLEGAL_BLOCK_NUM, PR_0_ORPHAN_ALREADY_CLEARED_BLOCK,
PR_0_ORPHAN_ILLEGAL_HEAD_INODE, PR_0_ORPHAN_ILLEGAL_INODE,
PR_0_ORPHAN_INODE_INUSE
super.c (release_inode_blocks, release_orphan_inodes,
check_super_block): Add support for clearing orphaned inodes from the
unmounted filesystem.
journal.c (e2fsck_recover_ext3_journal): Remove the last orphan check;
this is now handled in check_super_block --- non-journaled filesystems
can use the orphan list in the future. Also, move the the re-opening
of the filesystem to e2fsck_run_ext3_journal().
debugfs.c:
debugfs.c (finish_range): Make sure the pager FILE pointer to use.
configure, configure.in, ChangeLog:
configure.in (JFS_DEBUG): Add support for --enable-jfs-debug
2000-08-18 19:08:37 +04:00
|
|
|
}
|
|
|
|
ctx->fs->priv_data = ctx;
|
2000-07-07 08:13:21 +04:00
|
|
|
|
ChangeLog, journal.c, message.c, problem.c, problem.h, super.c:
journal.c (e2fsck_journal_load): Fix **nasty** bug which caused
e2fsck_check_ext3_journal to smash the journal because
journal->j_transaction_sequence wasn't getting initialized.
journal.c: (recover_ext3_journal, e2fsck_run_ext3_journal): Move call
to e2fsck_clear_recover from recover_ext3_journal to after the
filesystem has been closed and reopened. Otherwise, the superblock in
the filesystem handle will probably be stale, and will overwrite the
newer version of the superblock written by the log recovery.
message.c (expand_inode_expression): Add support for %Iu and %Ig
problem.h (PR_0_CLEAR_ORPHAN_INODE): Add new problem code.
super.c (release_orphan_inodes, release_inode_block,
release_inode_blocks): Update the block group descriptor counts when
freeing the orphan inode. Use PR_0_CLEAR_ORPHAN_INODE to report when
we clear an orphan.
journal.c (e2fsck_run_ext3_journal): Fix a bug where we attempted to
reopen the filesystem using the device name instead of the filesystem
name.
2000-08-21 02:06:31 +04:00
|
|
|
/* Set the superblock flags */
|
|
|
|
e2fsck_clear_recover(ctx, recover_retval);
|
|
|
|
return recover_retval;
|
2000-07-07 08:13:21 +04:00
|
|
|
}
|