2000-07-07 12:13:21 +08:00
|
|
|
/*
|
|
|
|
* journal.c --- code for handling the "ext3" journal
|
2000-08-14 22:25:19 +08: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 12:13:21 +08:00
|
|
|
*/
|
|
|
|
|
2011-09-19 05:34:37 +08:00
|
|
|
#include "config.h"
|
2000-08-14 22:25:19 +08:00
|
|
|
#ifdef HAVE_SYS_MOUNT_H
|
2003-12-29 01:21:26 +08:00
|
|
|
#include <sys/param.h>
|
2000-08-14 22:25:19 +08:00
|
|
|
#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 12:13:21 +08:00
|
|
|
|
2001-01-06 13:55:58 +08:00
|
|
|
#define E2FSCK_INCLUDE_INLINE_FUNCS
|
2000-12-09 14:41:25 +08:00
|
|
|
#include "jfs_user.h"
|
2000-08-14 22:25:19 +08:00
|
|
|
#include "problem.h"
|
|
|
|
#include "uuid/uuid.h"
|
2000-07-07 12:13:21 +08:00
|
|
|
|
2001-12-16 15:23:36 +08:00
|
|
|
#ifdef CONFIG_JBD_DEBUG /* Enabled by configure --enable-jfs-debug */
|
2000-08-14 22:25:19 +08:00
|
|
|
static int bh_count = 0;
|
|
|
|
#endif
|
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
/*
|
|
|
|
* Define USE_INODE_IO to use the inode_io.c / fileio.c codepaths.
|
|
|
|
* This creates a larger static binary, and a smaller binary using
|
|
|
|
* shared libraries. It's also probably slightly less CPU-efficient,
|
|
|
|
* which is why it's not on by default. But, it's a good way of
|
|
|
|
* testing the functions in inode_io.c and fileio.c.
|
|
|
|
*/
|
|
|
|
#undef USE_INODE_IO
|
|
|
|
|
2000-12-31 04:33:42 +08: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.
|
|
|
|
*/
|
2012-05-22 09:30:45 +08:00
|
|
|
int journal_bmap(journal_t *journal, blk64_t block, unsigned long long *phys)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
2002-02-22 13:17:59 +08:00
|
|
|
#ifdef USE_INODE_IO
|
|
|
|
*phys = block;
|
|
|
|
return 0;
|
|
|
|
#else
|
2001-12-16 15:23:36 +08:00
|
|
|
struct inode *inode = journal->j_inode;
|
|
|
|
errcode_t retval;
|
2010-06-14 05:00:00 +08:00
|
|
|
blk64_t pblk;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2001-12-16 15:23:36 +08:00
|
|
|
if (!inode) {
|
|
|
|
*phys = block;
|
|
|
|
return 0;
|
|
|
|
}
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2010-06-14 05:00:00 +08:00
|
|
|
retval= ext2fs_bmap2(inode->i_ctx->fs, inode->i_ino,
|
|
|
|
&inode->i_ext2, NULL, 0, block, 0, &pblk);
|
2001-12-16 15:23:36 +08:00
|
|
|
*phys = pblk;
|
|
|
|
return (retval);
|
2002-02-22 13:17:59 +08:00
|
|
|
#endif
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
2010-06-14 05:00:00 +08:00
|
|
|
struct buffer_head *getblk(kdev_t kdev, blk64_t blocknr, int blocksize)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
|
|
|
struct buffer_head *bh;
|
2009-01-03 07:14:42 +08:00
|
|
|
int bufsize = sizeof(*bh) + kdev->k_ctx->fs->blocksize -
|
|
|
|
sizeof(bh->b_data);
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2009-01-03 07:14:42 +08:00
|
|
|
bh = e2fsck_allocate_memory(kdev->k_ctx, bufsize, "block buffer");
|
2000-08-14 22:25:19 +08:00
|
|
|
if (!bh)
|
|
|
|
return NULL;
|
|
|
|
|
2008-05-23 13:00:19 +08:00
|
|
|
#ifdef CONFIG_JBD_DEBUG
|
|
|
|
if (journal_enable_debug >= 3)
|
|
|
|
bh_count++;
|
|
|
|
#endif
|
2012-05-22 09:30:45 +08:00
|
|
|
jfs_debug(4, "getblk for block %llu (%d bytes)(total %d)\n",
|
|
|
|
(unsigned long long) blocknr, blocksize, bh_count);
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2001-12-16 15:23:36 +08:00
|
|
|
bh->b_ctx = kdev->k_ctx;
|
|
|
|
if (kdev->k_dev == K_DEV_FS)
|
|
|
|
bh->b_io = kdev->k_ctx->fs->io;
|
2008-08-28 11:07:54 +08:00
|
|
|
else
|
2001-12-16 15:23:36 +08:00
|
|
|
bh->b_io = kdev->k_ctx->journal_io;
|
2000-08-14 22:25:19 +08:00
|
|
|
bh->b_size = blocksize;
|
|
|
|
bh->b_blocknr = blocknr;
|
|
|
|
|
|
|
|
return bh;
|
|
|
|
}
|
|
|
|
|
2004-05-27 08:58:45 +08:00
|
|
|
void sync_blockdev(kdev_t kdev)
|
|
|
|
{
|
|
|
|
io_channel io;
|
|
|
|
|
|
|
|
if (kdev->k_dev == K_DEV_FS)
|
|
|
|
io = kdev->k_ctx->fs->io;
|
2008-08-28 11:07:54 +08:00
|
|
|
else
|
2004-05-27 08:58:45 +08:00
|
|
|
io = kdev->k_ctx->journal_io;
|
|
|
|
|
|
|
|
io_channel_flush(io);
|
|
|
|
}
|
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
void ll_rw_block(int rw, int nr, struct buffer_head *bhp[])
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
|
|
|
int retval;
|
2000-12-09 14:41:25 +08:00
|
|
|
struct buffer_head *bh;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
for (; nr > 0; --nr) {
|
|
|
|
bh = *bhp++;
|
|
|
|
if (rw == READ && !bh->b_uptodate) {
|
2012-05-22 09:30:45 +08:00
|
|
|
jfs_debug(3, "reading block %llu/%p\n",
|
|
|
|
bh->b_blocknr, (void *) bh);
|
2009-09-08 09:14:24 +08:00
|
|
|
retval = io_channel_read_blk64(bh->b_io,
|
2000-12-09 14:41:25 +08:00
|
|
|
bh->b_blocknr,
|
|
|
|
1, bh->b_data);
|
|
|
|
if (retval) {
|
|
|
|
com_err(bh->b_ctx->device_name, retval,
|
2012-05-22 09:30:45 +08:00
|
|
|
"while reading block %llu\n",
|
|
|
|
bh->b_blocknr);
|
2000-12-09 14:41:25 +08:00
|
|
|
bh->b_err = retval;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bh->b_uptodate = 1;
|
|
|
|
} else if (rw == WRITE && bh->b_dirty) {
|
2012-05-22 09:30:45 +08:00
|
|
|
jfs_debug(3, "writing block %llu/%p\n",
|
|
|
|
bh->b_blocknr,
|
|
|
|
(void *) bh);
|
2009-09-08 09:14:24 +08:00
|
|
|
retval = io_channel_write_blk64(bh->b_io,
|
2000-12-09 14:41:25 +08:00
|
|
|
bh->b_blocknr,
|
|
|
|
1, bh->b_data);
|
|
|
|
if (retval) {
|
|
|
|
com_err(bh->b_ctx->device_name, retval,
|
2012-05-22 09:30:45 +08:00
|
|
|
"while writing block %llu\n",
|
|
|
|
bh->b_blocknr);
|
2000-12-09 14:41:25 +08:00
|
|
|
bh->b_err = retval;
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
bh->b_dirty = 0;
|
|
|
|
bh->b_uptodate = 1;
|
2003-12-28 20:04:35 +08:00
|
|
|
} else {
|
2012-05-22 09:30:45 +08:00
|
|
|
jfs_debug(3, "no-op %s for block %llu\n",
|
2008-08-28 11:07:54 +08:00
|
|
|
rw == READ ? "read" : "write",
|
2012-05-22 09:30:45 +08:00
|
|
|
bh->b_blocknr);
|
2003-12-28 20:04:35 +08:00
|
|
|
}
|
2000-12-09 14:41:25 +08:00
|
|
|
}
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
2001-12-16 15:23:36 +08:00
|
|
|
void mark_buffer_dirty(struct buffer_head *bh)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
2001-12-16 15:23:36 +08:00
|
|
|
bh->b_dirty = 1;
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
static void mark_buffer_clean(struct buffer_head * bh)
|
|
|
|
{
|
|
|
|
bh->b_dirty = 0;
|
|
|
|
}
|
|
|
|
|
2000-08-14 22:25:19 +08:00
|
|
|
void brelse(struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
if (bh->b_dirty)
|
2000-12-09 14:41:25 +08:00
|
|
|
ll_rw_block(WRITE, 1, &bh);
|
2012-05-22 09:30:45 +08:00
|
|
|
jfs_debug(3, "freeing block %llu/%p (total %d)\n",
|
|
|
|
bh->b_blocknr, (void *) bh, --bh_count);
|
2003-08-01 21:41:07 +08:00
|
|
|
ext2fs_free_mem(&bh);
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
int buffer_uptodate(struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
return bh->b_uptodate;
|
|
|
|
}
|
|
|
|
|
2001-03-30 03:22:16 +08:00
|
|
|
void mark_buffer_uptodate(struct buffer_head *bh, int val)
|
|
|
|
{
|
|
|
|
bh->b_uptodate = val;
|
|
|
|
}
|
|
|
|
|
2000-08-14 22:25:19 +08:00
|
|
|
void wait_on_buffer(struct buffer_head *bh)
|
|
|
|
{
|
|
|
|
if (!bh->b_uptodate)
|
2000-12-09 14:41:25 +08:00
|
|
|
ll_rw_block(READ, 1, &bh);
|
2000-08-14 22:25:19 +08: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 23:08:37 +08:00
|
|
|
|
2000-08-14 22:25:19 +08:00
|
|
|
static void e2fsck_clear_recover(e2fsck_t ctx, int error)
|
|
|
|
{
|
2001-01-01 23:51:50 +08:00
|
|
|
ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
|
|
|
/* if we had an error doing journal recovery, we need a full fsck */
|
|
|
|
if (error)
|
2001-01-01 23:51:50 +08:00
|
|
|
ctx->fs->super->s_state &= ~EXT2_VALID_FS;
|
2000-08-14 22:25:19 +08:00
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
|
|
|
|
2007-06-21 23:59:06 +08:00
|
|
|
/*
|
|
|
|
* This is a helper function to check the validity of the journal.
|
|
|
|
*/
|
|
|
|
struct process_block_struct {
|
|
|
|
e2_blkcnt_t last_block;
|
|
|
|
};
|
|
|
|
|
|
|
|
static int process_journal_block(ext2_filsys fs,
|
2010-06-14 05:00:00 +08:00
|
|
|
blk64_t *block_nr,
|
2007-06-21 23:59:06 +08:00
|
|
|
e2_blkcnt_t blockcnt,
|
2010-06-14 05:00:00 +08:00
|
|
|
blk64_t ref_block EXT2FS_ATTR((unused)),
|
2007-06-21 23:59:06 +08:00
|
|
|
int ref_offset EXT2FS_ATTR((unused)),
|
|
|
|
void *priv_data)
|
|
|
|
{
|
|
|
|
struct process_block_struct *p;
|
2010-06-14 05:00:00 +08:00
|
|
|
blk64_t blk = *block_nr;
|
2007-06-21 23:59:06 +08:00
|
|
|
|
|
|
|
p = (struct process_block_struct *) priv_data;
|
|
|
|
|
2010-04-13 06:36:33 +08:00
|
|
|
if (!blk || blk < fs->super->s_first_data_block ||
|
2009-09-08 08:46:34 +08:00
|
|
|
blk >= ext2fs_blocks_count(fs->super))
|
2007-06-21 23:59:06 +08:00
|
|
|
return BLOCK_ABORT;
|
|
|
|
|
|
|
|
if (blockcnt >= 0)
|
|
|
|
p->last_block = blockcnt;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
2007-06-21 23:59:06 +08:00
|
|
|
struct process_block_struct pb;
|
2002-02-22 13:17:59 +08:00
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
|
|
|
struct ext2_super_block jsuper;
|
|
|
|
struct problem_context pctx;
|
|
|
|
struct buffer_head *bh;
|
|
|
|
struct inode *j_inode = NULL;
|
|
|
|
struct kdev_s *dev_fs = NULL, *dev_journal;
|
2002-10-14 11:56:28 +08:00
|
|
|
const char *journal_name = 0;
|
2002-02-22 13:17:59 +08:00
|
|
|
journal_t *journal = NULL;
|
2002-10-14 11:56:28 +08:00
|
|
|
errcode_t retval = 0;
|
|
|
|
io_manager io_ptr = 0;
|
2012-05-22 09:30:45 +08:00
|
|
|
unsigned long long start = 0;
|
2002-02-22 13:17:59 +08:00
|
|
|
int ext_journal = 0;
|
2003-08-21 12:40:26 +08:00
|
|
|
int tried_backup_jnl = 0;
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
clear_problem_context(&pctx);
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal");
|
|
|
|
if (!journal) {
|
2000-08-14 22:25:19 +08:00
|
|
|
return EXT2_ET_NO_MEMORY;
|
|
|
|
}
|
|
|
|
|
2001-12-16 15:23:36 +08:00
|
|
|
dev_fs = e2fsck_allocate_memory(ctx, 2*sizeof(struct kdev_s), "kdev");
|
|
|
|
if (!dev_fs) {
|
|
|
|
retval = EXT2_ET_NO_MEMORY;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
dev_journal = dev_fs+1;
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2001-12-16 15:23:36 +08:00
|
|
|
dev_fs->k_ctx = dev_journal->k_ctx = ctx;
|
|
|
|
dev_fs->k_dev = K_DEV_FS;
|
|
|
|
dev_journal->k_dev = K_DEV_JOURNAL;
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
journal->j_dev = dev_journal;
|
|
|
|
journal->j_fs_dev = dev_fs;
|
|
|
|
journal->j_inode = NULL;
|
|
|
|
journal->j_blocksize = ctx->fs->blocksize;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
if (uuid_is_null(sb->s_journal_uuid)) {
|
2007-03-29 12:19:17 +08:00
|
|
|
if (!sb->s_journal_inum) {
|
|
|
|
retval = EXT2_ET_BAD_INODE_NUM;
|
|
|
|
goto errout;
|
|
|
|
}
|
2002-02-22 13:17:59 +08:00
|
|
|
j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode),
|
|
|
|
"journal inode");
|
|
|
|
if (!j_inode) {
|
|
|
|
retval = EXT2_ET_NO_MEMORY;
|
|
|
|
goto errout;
|
|
|
|
}
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
j_inode->i_ctx = ctx;
|
|
|
|
j_inode->i_ino = sb->s_journal_inum;
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
if ((retval = ext2fs_read_inode(ctx->fs,
|
|
|
|
sb->s_journal_inum,
|
2003-08-21 12:40:26 +08:00
|
|
|
&j_inode->i_ext2))) {
|
|
|
|
try_backup_journal:
|
|
|
|
if (sb->s_jnl_backup_type != EXT3_JNL_BACKUP_BLOCKS ||
|
|
|
|
tried_backup_jnl)
|
|
|
|
goto errout;
|
|
|
|
memset(&j_inode->i_ext2, 0, sizeof(struct ext2_inode));
|
2008-08-28 11:07:54 +08:00
|
|
|
memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks,
|
2003-08-21 12:40:26 +08:00
|
|
|
EXT2_N_BLOCKS*4);
|
2011-06-12 00:17:29 +08:00
|
|
|
j_inode->i_ext2.i_size_high = sb->s_jnl_blocks[15];
|
2003-08-21 12:40:26 +08:00
|
|
|
j_inode->i_ext2.i_size = sb->s_jnl_blocks[16];
|
|
|
|
j_inode->i_ext2.i_links_count = 1;
|
|
|
|
j_inode->i_ext2.i_mode = LINUX_S_IFREG | 0600;
|
2007-06-21 23:59:06 +08:00
|
|
|
e2fsck_use_inode_shortcuts(ctx, 1);
|
|
|
|
ctx->stashed_ino = j_inode->i_ino;
|
|
|
|
ctx->stashed_inode = &j_inode->i_ext2;
|
2003-08-21 12:40:26 +08:00
|
|
|
tried_backup_jnl++;
|
|
|
|
}
|
2002-02-22 13:17:59 +08:00
|
|
|
if (!j_inode->i_ext2.i_links_count ||
|
|
|
|
!LINUX_S_ISREG(j_inode->i_ext2.i_mode)) {
|
|
|
|
retval = EXT2_ET_NO_JOURNAL;
|
2003-08-21 12:40:26 +08:00
|
|
|
goto try_backup_journal;
|
2002-02-22 13:17:59 +08:00
|
|
|
}
|
2011-06-12 00:17:29 +08:00
|
|
|
if (EXT2_I_SIZE(&j_inode->i_ext2) / journal->j_blocksize <
|
2002-02-22 13:17:59 +08:00
|
|
|
JFS_MIN_JOURNAL_BLOCKS) {
|
|
|
|
retval = EXT2_ET_JOURNAL_TOO_SMALL;
|
2003-08-21 12:40:26 +08:00
|
|
|
goto try_backup_journal;
|
|
|
|
}
|
2007-06-21 23:59:06 +08:00
|
|
|
pb.last_block = -1;
|
2010-06-14 05:00:00 +08:00
|
|
|
retval = ext2fs_block_iterate3(ctx->fs, j_inode->i_ino,
|
2008-08-28 11:07:54 +08:00
|
|
|
BLOCK_FLAG_HOLE, 0,
|
2007-06-21 23:59:06 +08:00
|
|
|
process_journal_block, &pb);
|
2011-06-12 00:17:29 +08:00
|
|
|
if ((pb.last_block + 1) * ctx->fs->blocksize <
|
|
|
|
EXT2_I_SIZE(&j_inode->i_ext2)) {
|
2007-06-21 23:59:06 +08:00
|
|
|
retval = EXT2_ET_JOURNAL_TOO_SMALL;
|
|
|
|
goto try_backup_journal;
|
2002-02-22 13:17:59 +08:00
|
|
|
}
|
2007-06-21 23:59:06 +08:00
|
|
|
if (tried_backup_jnl && !(ctx->options & E2F_OPT_READONLY)) {
|
|
|
|
retval = ext2fs_write_inode(ctx->fs, sb->s_journal_inum,
|
|
|
|
&j_inode->i_ext2);
|
|
|
|
if (retval)
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
|
2011-06-12 00:17:29 +08:00
|
|
|
journal->j_maxlen = EXT2_I_SIZE(&j_inode->i_ext2) /
|
|
|
|
journal->j_blocksize;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
#ifdef USE_INODE_IO
|
2003-08-21 12:40:26 +08:00
|
|
|
retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum,
|
|
|
|
&j_inode->i_ext2,
|
|
|
|
&journal_name);
|
2002-02-22 13:17:59 +08:00
|
|
|
if (retval)
|
|
|
|
goto errout;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
io_ptr = inode_io_manager;
|
|
|
|
#else
|
|
|
|
journal->j_inode = j_inode;
|
|
|
|
ctx->journal_io = ctx->fs->io;
|
|
|
|
if ((retval = journal_bmap(journal, 0, &start)) != 0)
|
|
|
|
goto errout;
|
|
|
|
#endif
|
|
|
|
} else {
|
|
|
|
ext_journal = 1;
|
2003-03-02 08:47:44 +08:00
|
|
|
if (!ctx->journal_name) {
|
|
|
|
char uuid[37];
|
|
|
|
|
|
|
|
uuid_unparse(sb->s_journal_uuid, uuid);
|
|
|
|
ctx->journal_name = blkid_get_devname(ctx->blkid,
|
|
|
|
"UUID", uuid);
|
|
|
|
if (!ctx->journal_name)
|
|
|
|
ctx->journal_name = blkid_devno_to_devname(sb->s_journal_dev);
|
2002-02-22 13:17:59 +08:00
|
|
|
}
|
2003-03-02 08:47:44 +08:00
|
|
|
journal_name = ctx->journal_name;
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
if (!journal_name) {
|
|
|
|
fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx);
|
2007-03-29 12:19:17 +08:00
|
|
|
retval = EXT2_ET_LOAD_EXT_JOURNAL;
|
|
|
|
goto errout;
|
2002-02-22 13:17:59 +08:00
|
|
|
}
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
jfs_debug(1, "Using journal file %s\n", journal_name);
|
|
|
|
io_ptr = unix_io_manager;
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
#if 0
|
|
|
|
test_io_backing_manager = io_ptr;
|
2001-07-23 12:17:49 +08:00
|
|
|
io_ptr = test_io_manager;
|
|
|
|
#endif
|
2002-02-22 13:17:59 +08:00
|
|
|
#ifndef USE_INODE_IO
|
|
|
|
if (ext_journal)
|
|
|
|
#endif
|
2010-09-26 09:14:06 +08:00
|
|
|
retval = io_ptr->open(journal_name,
|
|
|
|
IO_FLAG_RW | IO_FLAG_EXCLUSIVE,
|
2002-02-22 13:17:59 +08:00
|
|
|
&ctx->journal_io);
|
2001-07-30 00:06:58 +08:00
|
|
|
if (retval)
|
2002-02-22 13:17:59 +08:00
|
|
|
goto errout;
|
2001-07-23 12:17:49 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
io_channel_set_blksize(ctx->journal_io, ctx->fs->blocksize);
|
|
|
|
|
|
|
|
if (ext_journal) {
|
|
|
|
if (ctx->fs->blocksize == 1024)
|
|
|
|
start = 1;
|
|
|
|
bh = getblk(dev_journal, start, ctx->fs->blocksize);
|
|
|
|
if (!bh) {
|
|
|
|
retval = EXT2_ET_NO_MEMORY;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
ll_rw_block(READ, 1, &bh);
|
2006-05-15 05:16:29 +08:00
|
|
|
if ((retval = bh->b_err) != 0) {
|
|
|
|
brelse(bh);
|
2002-02-22 13:17:59 +08:00
|
|
|
goto errout;
|
2006-05-15 05:16:29 +08:00
|
|
|
}
|
2002-02-22 13:17:59 +08:00
|
|
|
memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024,
|
|
|
|
sizeof(jsuper));
|
|
|
|
brelse(bh);
|
2007-08-11 14:57:31 +08:00
|
|
|
#ifdef WORDS_BIGENDIAN
|
2008-08-28 11:07:54 +08:00
|
|
|
if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC))
|
2002-02-22 13:17:59 +08:00
|
|
|
ext2fs_swap_super(&jsuper);
|
2001-07-23 12:17:49 +08:00
|
|
|
#endif
|
2002-02-22 13:17:59 +08:00
|
|
|
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);
|
|
|
|
retval = EXT2_ET_LOAD_EXT_JOURNAL;
|
|
|
|
goto errout;
|
|
|
|
}
|
|
|
|
/* 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);
|
|
|
|
retval = EXT2_ET_LOAD_EXT_JOURNAL;
|
|
|
|
goto errout;
|
|
|
|
}
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2009-09-08 08:46:34 +08:00
|
|
|
journal->j_maxlen = ext2fs_blocks_count(&jsuper);
|
2002-02-22 13:17:59 +08:00
|
|
|
start++;
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) {
|
2001-07-23 12:17:49 +08:00
|
|
|
retval = EXT2_ET_NO_MEMORY;
|
|
|
|
goto errout;
|
|
|
|
}
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
journal->j_sb_buffer = bh;
|
|
|
|
journal->j_superblock = (journal_superblock_t *)bh->b_data;
|
2007-03-29 12:19:17 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
#ifdef USE_INODE_IO
|
|
|
|
if (j_inode)
|
2003-08-01 21:41:07 +08:00
|
|
|
ext2fs_free_mem(&j_inode);
|
2002-02-22 13:17:59 +08:00
|
|
|
#endif
|
|
|
|
|
|
|
|
*ret_journal = journal;
|
2007-06-21 23:59:06 +08:00
|
|
|
e2fsck_use_inode_shortcuts(ctx, 0);
|
2001-07-23 12:17:49 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
errout:
|
2007-06-21 23:59:06 +08:00
|
|
|
e2fsck_use_inode_shortcuts(ctx, 0);
|
2002-02-22 13:17:59 +08:00
|
|
|
if (dev_fs)
|
2003-08-01 21:41:07 +08:00
|
|
|
ext2fs_free_mem(&dev_fs);
|
2002-02-22 13:17:59 +08:00
|
|
|
if (j_inode)
|
2003-08-01 21:41:07 +08:00
|
|
|
ext2fs_free_mem(&j_inode);
|
2002-02-22 13:17:59 +08:00
|
|
|
if (journal)
|
2003-08-01 21:41:07 +08:00
|
|
|
ext2fs_free_mem(&journal);
|
2001-07-23 12:17:49 +08:00
|
|
|
return retval;
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx,
|
|
|
|
struct problem_context *pctx)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
2001-01-01 23:51:50 +08: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 22:25:19 +08:00
|
|
|
|
2001-01-01 23:51:50 +08:00
|
|
|
if (has_journal || sb->s_journal_inum) {
|
2000-08-14 22:25:19 +08:00
|
|
|
/* The journal inode is bogus, remove and force full fsck */
|
2001-01-12 23:30:25 +08:00
|
|
|
pctx->ino = sb->s_journal_inum;
|
2000-08-14 22:25:19 +08:00
|
|
|
if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) {
|
2001-01-01 23:51:50 +08:00
|
|
|
if (has_journal && sb->s_journal_inum)
|
2000-08-14 22:25:19 +08:00
|
|
|
printf("*** ext3 journal has been deleted - "
|
|
|
|
"filesystem is now ext2 only ***\n\n");
|
2001-01-01 23:51:50 +08:00
|
|
|
sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL;
|
|
|
|
sb->s_journal_inum = 0;
|
2007-06-21 23:59:06 +08:00
|
|
|
ctx->flags |= E2F_FLAG_JOURNAL_INODE;
|
2007-10-07 00:37:08 +08:00
|
|
|
ctx->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
|
2000-08-14 22:25:19 +08: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;
|
|
|
|
}
|
|
|
|
|
2001-10-07 14:13:30 +08:00
|
|
|
#define V1_SB_SIZE 0x0024
|
|
|
|
static void clear_v2_journal_fields(journal_t *journal)
|
|
|
|
{
|
2001-12-16 15:23:36 +08:00
|
|
|
e2fsck_t ctx = journal->j_dev->k_ctx;
|
2001-10-07 14:13:30 +08:00
|
|
|
struct problem_context pctx;
|
|
|
|
|
|
|
|
clear_problem_context(&pctx);
|
|
|
|
|
|
|
|
if (!fix_problem(ctx, PR_0_CLEAR_V2_JOURNAL, &pctx))
|
|
|
|
return;
|
|
|
|
|
|
|
|
memset(((char *) journal->j_superblock) + V1_SB_SIZE, 0,
|
|
|
|
ctx->fs->blocksize-V1_SB_SIZE);
|
2001-12-16 15:23:36 +08:00
|
|
|
mark_buffer_dirty(journal->j_sb_buffer);
|
2001-10-07 14:13:30 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
static errcode_t e2fsck_journal_load(journal_t *journal)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
2001-12-16 15:23:36 +08:00
|
|
|
e2fsck_t ctx = journal->j_dev->k_ctx;
|
2000-08-14 22:25:19 +08:00
|
|
|
journal_superblock_t *jsb;
|
|
|
|
struct buffer_head *jbh = journal->j_sb_buffer;
|
|
|
|
struct problem_context pctx;
|
|
|
|
|
|
|
|
clear_problem_context(&pctx);
|
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
ll_rw_block(READ, 1, &jbh);
|
2000-08-14 22:25:19 +08: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 14:41:25 +08:00
|
|
|
switch (ntohl(jsb->s_header.h_blocktype)) {
|
|
|
|
case JFS_SUPERBLOCK_V1:
|
|
|
|
journal->j_format_version = 1;
|
2001-10-07 14:13:30 +08:00
|
|
|
if (jsb->s_feature_compat ||
|
|
|
|
jsb->s_feature_incompat ||
|
|
|
|
jsb->s_feature_ro_compat ||
|
|
|
|
jsb->s_nr_users)
|
|
|
|
clear_v2_journal_fields(journal);
|
2000-12-09 14:41:25 +08:00
|
|
|
break;
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
case JFS_SUPERBLOCK_V2:
|
|
|
|
journal->j_format_version = 2;
|
2001-11-30 20:45:28 +08:00
|
|
|
if (ntohl(jsb->s_nr_users) > 1 &&
|
2003-08-21 12:40:26 +08:00
|
|
|
uuid_is_null(ctx->fs->super->s_journal_uuid))
|
2001-10-07 14:13:30 +08:00
|
|
|
clear_v2_journal_fields(journal);
|
2001-07-23 12:17:49 +08:00
|
|
|
if (ntohl(jsb->s_nr_users) > 1) {
|
|
|
|
fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx);
|
|
|
|
return EXT2_ET_JOURNAL_UNSUPP_VERSION;
|
|
|
|
}
|
2000-12-09 14:41:25 +08:00
|
|
|
break;
|
2001-05-24 06:19:47 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* These should never appear in a journal super block, so if
|
|
|
|
* they do, the journal is badly corrupted.
|
|
|
|
*/
|
|
|
|
case JFS_DESCRIPTOR_BLOCK:
|
|
|
|
case JFS_COMMIT_BLOCK:
|
|
|
|
case JFS_REVOKE_BLOCK:
|
|
|
|
return EXT2_ET_CORRUPT_SUPERBLOCK;
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
/* 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:
|
2001-05-24 06:19:47 +08:00
|
|
|
return EXT2_ET_JOURNAL_UNSUPP_VERSION;
|
2000-12-09 14:41:25 +08:00
|
|
|
}
|
|
|
|
|
2001-06-02 08:38:40 +08:00
|
|
|
if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES))
|
|
|
|
return EXT2_ET_UNSUPP_FEATURE;
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2001-06-02 08:38:40 +08:00
|
|
|
if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES))
|
|
|
|
return EXT2_ET_RO_UNSUPP_FEATURE;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2000-12-09 14:41:25 +08: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 22:25:19 +08: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 14:41:25 +08:00
|
|
|
com_err(ctx->program_name, EXT2_ET_CORRUPT_SUPERBLOCK,
|
|
|
|
_("%s: journal too short\n"),
|
|
|
|
ctx->device_name);
|
2000-08-14 22:25:19 +08: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 06:06:31 +08:00
|
|
|
journal->j_transaction_sequence = journal->j_tail_sequence;
|
2000-08-14 22:25:19 +08: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 13:55:58 +08:00
|
|
|
static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb,
|
2001-01-13 05:11:24 +08:00
|
|
|
journal_t *journal)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
2000-12-09 14:41:25 +08:00
|
|
|
char *p;
|
ChangeLog, e2fsck.h, journal.c, problem.c, problem.h, super.c:
super.c (check_super_block): Be more strict on checking
s_r_blocks_count superblock field.
problem.c, problem.h (PR_0_JOURNAL_UNSUPP_ROCOMPAT,
PR_0_JOURNAL_UNSUPP_INCOMPAT, PR_0_JOURNAL_RESET_COMPAT): New problem
codes.
journal.c (e2fsck_journal_load): Use a problem code to report
unsupported feature flags. There is code to clear unsupported flags,
but since this is dangerous, it's not allowed in the problem code
table.
journal.c (e2fsck_journal_reset_super): initialize the journal
sequence number to a random value to avoid recovering bad transactions
from a corrupt journal.
2001-05-14 12:06:56 +08:00
|
|
|
union {
|
|
|
|
uuid_t uuid;
|
|
|
|
__u32 val[4];
|
|
|
|
} u;
|
|
|
|
__u32 new_seq = 0;
|
|
|
|
int i;
|
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
/* Leave a valid existing V1 superblock signature alone.
|
|
|
|
* Anything unrecognisable we overwrite with a new V2
|
|
|
|
* signature. */
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
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 */
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
p = ((char *) jsb) + sizeof(journal_header_t);
|
|
|
|
memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t));
|
|
|
|
|
2000-08-14 22:25:19 +08:00
|
|
|
jsb->s_blocksize = htonl(ctx->fs->blocksize);
|
2000-12-09 14:41:25 +08:00
|
|
|
jsb->s_maxlen = htonl(journal->j_maxlen);
|
|
|
|
jsb->s_first = htonl(1);
|
|
|
|
|
ChangeLog, e2fsck.h, journal.c, problem.c, problem.h, super.c:
super.c (check_super_block): Be more strict on checking
s_r_blocks_count superblock field.
problem.c, problem.h (PR_0_JOURNAL_UNSUPP_ROCOMPAT,
PR_0_JOURNAL_UNSUPP_INCOMPAT, PR_0_JOURNAL_RESET_COMPAT): New problem
codes.
journal.c (e2fsck_journal_load): Use a problem code to report
unsupported feature flags. There is code to clear unsupported flags,
but since this is dangerous, it's not allowed in the problem code
table.
journal.c (e2fsck_journal_reset_super): initialize the journal
sequence number to a random value to avoid recovering bad transactions
from a corrupt journal.
2001-05-14 12:06:56 +08:00
|
|
|
/* Initialize the journal sequence number so that there is "no"
|
|
|
|
* chance we will find old "valid" transactions in the journal.
|
|
|
|
* This avoids the need to zero the whole journal (slow to do,
|
|
|
|
* and risky when we are just recovering the filesystem).
|
|
|
|
*/
|
|
|
|
uuid_generate(u.uuid);
|
|
|
|
for (i = 0; i < 4; i ++)
|
|
|
|
new_seq ^= u.val[i];
|
|
|
|
jsb->s_sequence = htonl(new_seq);
|
2000-12-09 14:41:25 +08:00
|
|
|
|
2001-12-16 15:23:36 +08:00
|
|
|
mark_buffer_dirty(journal->j_sb_buffer);
|
2000-12-09 14:41:25 +08:00
|
|
|
ll_rw_block(WRITE, 1, &journal->j_sb_buffer);
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx,
|
|
|
|
journal_t *journal,
|
|
|
|
struct problem_context *pctx)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
2001-01-01 23:51:50 +08:00
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
|
|
|
int recover = ctx->fs->super->s_feature_incompat &
|
|
|
|
EXT3_FEATURE_INCOMPAT_RECOVER;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2001-01-01 23:51:50 +08:00
|
|
|
if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) {
|
2000-08-14 22:25:19 +08:00
|
|
|
if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) {
|
2000-12-31 04:33:42 +08:00
|
|
|
e2fsck_journal_reset_super(ctx, journal->j_superblock,
|
|
|
|
journal);
|
2000-08-14 22:25:19 +08: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;
|
|
|
|
}
|
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal,
|
|
|
|
int reset, int drop)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
|
|
|
journal_superblock_t *jsb;
|
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
if (drop)
|
|
|
|
mark_buffer_clean(journal->j_sb_buffer);
|
|
|
|
else if (!(ctx->options & E2F_OPT_READONLY)) {
|
2000-08-14 22:25:19 +08:00
|
|
|
jsb = journal->j_superblock;
|
|
|
|
jsb->s_sequence = htonl(journal->j_transaction_sequence);
|
|
|
|
if (reset)
|
|
|
|
jsb->s_start = 0; /* this marks the journal as empty */
|
2001-12-16 15:23:36 +08:00
|
|
|
mark_buffer_dirty(journal->j_sb_buffer);
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
brelse(journal->j_sb_buffer);
|
|
|
|
|
2001-07-30 00:06:58 +08:00
|
|
|
if (ctx->journal_io) {
|
|
|
|
if (ctx->fs && ctx->fs->io != ctx->journal_io)
|
|
|
|
io_channel_close(ctx->journal_io);
|
|
|
|
ctx->journal_io = 0;
|
|
|
|
}
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2002-02-22 13:17:59 +08:00
|
|
|
#ifndef USE_INODE_IO
|
2000-08-14 22:25:19 +08:00
|
|
|
if (journal->j_inode)
|
2003-08-01 21:41:07 +08:00
|
|
|
ext2fs_free_mem(&journal->j_inode);
|
2002-02-22 13:17:59 +08:00
|
|
|
#endif
|
|
|
|
if (journal->j_fs_dev)
|
2003-08-01 21:41:07 +08:00
|
|
|
ext2fs_free_mem(&journal->j_fs_dev);
|
|
|
|
ext2fs_free_mem(&journal);
|
2000-08-14 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
2000-12-14 02:50:22 +08:00
|
|
|
/*
|
|
|
|
* This function makes sure that the superblock fields regarding the
|
|
|
|
* journal are consistent.
|
|
|
|
*/
|
2000-08-14 22:25:19 +08:00
|
|
|
int e2fsck_check_ext3_journal(e2fsck_t ctx)
|
|
|
|
{
|
2001-01-01 23:51:50 +08:00
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
2000-08-14 22:25:19 +08:00
|
|
|
journal_t *journal;
|
2001-01-01 23:51:50 +08:00
|
|
|
int recover = ctx->fs->super->s_feature_incompat &
|
|
|
|
EXT3_FEATURE_INCOMPAT_RECOVER;
|
2000-08-14 22:25:19 +08:00
|
|
|
struct problem_context pctx;
|
2001-12-22 12:28:54 +08:00
|
|
|
problem_t problem;
|
2001-01-03 21:00:43 +08:00
|
|
|
int reset = 0, force_fsck = 0;
|
2000-08-14 22:25:19 +08:00
|
|
|
int retval;
|
|
|
|
|
|
|
|
/* If we don't have any journal features, don't do anything more */
|
2001-01-01 23:51:50 +08: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-14 02:50:22 +08:00
|
|
|
return 0;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
|
|
|
clear_problem_context(&pctx);
|
2001-01-01 23:51:50 +08:00
|
|
|
pctx.num = sb->s_journal_inum;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
|
|
|
retval = e2fsck_get_journal(ctx, &journal);
|
|
|
|
if (retval) {
|
2002-03-07 16:13:07 +08:00
|
|
|
if ((retval == EXT2_ET_BAD_INODE_NUM) ||
|
2004-10-05 00:56:24 +08:00
|
|
|
(retval == EXT2_ET_BAD_BLOCK_NUM) ||
|
2002-03-07 16:13:07 +08:00
|
|
|
(retval == EXT2_ET_JOURNAL_TOO_SMALL) ||
|
|
|
|
(retval == EXT2_ET_NO_JOURNAL))
|
2000-08-14 22:25:19 +08:00
|
|
|
return e2fsck_journal_fix_bad_inode(ctx, &pctx);
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
retval = e2fsck_journal_load(journal);
|
|
|
|
if (retval) {
|
2001-05-24 06:19:47 +08:00
|
|
|
if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) ||
|
2001-06-02 08:38:40 +08:00
|
|
|
((retval == EXT2_ET_UNSUPP_FEATURE) &&
|
|
|
|
(!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_INCOMPAT,
|
|
|
|
&pctx))) ||
|
|
|
|
((retval == EXT2_ET_RO_UNSUPP_FEATURE) &&
|
|
|
|
(!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_ROCOMPAT,
|
|
|
|
&pctx))) ||
|
2001-05-24 06:19:47 +08:00
|
|
|
((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) &&
|
|
|
|
(!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx))))
|
2001-01-13 05:11:24 +08:00
|
|
|
retval = e2fsck_journal_fix_corrupt_super(ctx, journal,
|
|
|
|
&pctx);
|
|
|
|
e2fsck_journal_release(ctx, journal, 0, 1);
|
2000-08-14 22:25:19 +08:00
|
|
|
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 23:51:50 +08:00
|
|
|
if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) {
|
|
|
|
recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER;
|
2000-08-14 22:25:19 +08: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 21:00:43 +08:00
|
|
|
/*
|
|
|
|
* Need a full fsck if we are releasing a
|
2001-01-03 21:14:23 +08:00
|
|
|
* journal stored on a reserved inode.
|
2001-01-03 21:00:43 +08:00
|
|
|
*/
|
|
|
|
force_fsck = recover ||
|
|
|
|
(sb->s_journal_inum < EXT2_FIRST_INODE(sb));
|
|
|
|
/* Clear all of the journal fields */
|
2001-01-01 23:51:50 +08:00
|
|
|
sb->s_journal_inum = 0;
|
2001-01-03 21:00:43 +08: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 22:25:19 +08:00
|
|
|
} else if (!(ctx->options & E2F_OPT_READONLY)) {
|
2001-01-01 23:51:50 +08:00
|
|
|
sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL;
|
2007-10-07 00:37:08 +08:00
|
|
|
ctx->fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
|
2000-08-14 22:25:19 +08:00
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2001-01-01 23:51:50 +08:00
|
|
|
if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL &&
|
|
|
|
!(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
|
2000-08-14 22:25:19 +08:00
|
|
|
journal->j_superblock->s_start != 0) {
|
2001-12-22 12:28:54 +08:00
|
|
|
/* Print status information */
|
|
|
|
fix_problem(ctx, PR_0_JOURNAL_RECOVERY_CLEAR, &pctx);
|
|
|
|
if (ctx->superblock)
|
|
|
|
problem = PR_0_JOURNAL_RUN_DEFAULT;
|
|
|
|
else
|
|
|
|
problem = PR_0_JOURNAL_RUN;
|
|
|
|
if (fix_problem(ctx, problem, &pctx)) {
|
|
|
|
ctx->options |= E2F_OPT_FORCE;
|
|
|
|
sb->s_feature_incompat |=
|
|
|
|
EXT3_FEATURE_INCOMPAT_RECOVER;
|
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
} else if (fix_problem(ctx,
|
|
|
|
PR_0_JOURNAL_RESET_JOURNAL, &pctx)) {
|
2000-08-14 22:25:19 +08:00
|
|
|
reset = 1;
|
2001-01-03 21:00:43 +08: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.
|
2008-08-28 11:07:54 +08:00
|
|
|
*
|
2001-01-03 21:00:43 +08:00
|
|
|
* 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 22:25:19 +08:00
|
|
|
}
|
|
|
|
|
e2fsck: handle an already recovered journal with a non-zero s_error field
If a file system was remounted read-only after a file system
corruption is detected, and then that file system is mounted and
unmounted by the kernel, the journal would have been recovered, but
the kernel currently leaves the s_errno field still set. This is
arguably a bug, since it has already propgated the non-zero s_errno
field to the file system superblock, where it will be retained until
e2fsck has been run.
However, e2fsck should handle this case for existing kernel by
checking the journal superblock's s_errno field even if journal
recovery is not required.
Without this commit, e2fsck would not notice anything wrong with the
file system, but a subsequent mount of the file system by the kernel
would mark the file system's superblock as needing checking (since the
journal's s_errno field would still be set), resulting an full e2fsck
run at the next reboot, which would find nothing wrong --- and then
when the file system was mounted, the whole cycle would repeat again.
I had seen reports of this in the past, but it wasn't until recently
that I realized exactly how this had come about, since normally e2fsck
would be run automatically before the file system is mounted again,
thus avoiding this problem. However, a user using a rescue CD who
didn't run e2fsck before mounting the a file system in this condition
could trigger this situation, and unfortunately, with previous
versions of e2fsprogs and the kernel, there would be no way out no
matter what the user tried to do.
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2012-06-01 07:19:02 +08:00
|
|
|
/*
|
|
|
|
* If we don't need to do replay the journal, check to see if
|
|
|
|
* the journal's errno is set; if so, we need to mark the file
|
|
|
|
* system as being corrupt and clear the journal's s_errno.
|
|
|
|
*/
|
|
|
|
if (!(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) &&
|
|
|
|
journal->j_superblock->s_errno) {
|
|
|
|
ctx->fs->super->s_state |= EXT2_ERROR_FS;
|
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
journal->j_superblock->s_errno = 0;
|
|
|
|
mark_buffer_dirty(journal->j_sb_buffer);
|
|
|
|
}
|
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
e2fsck_journal_release(ctx, journal, reset, 0);
|
2000-08-14 22:25:19 +08:00
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
static errcode_t recover_ext3_journal(e2fsck_t ctx)
|
2000-08-14 22:25:19 +08:00
|
|
|
{
|
2008-05-23 13:00:19 +08:00
|
|
|
struct problem_context pctx;
|
2000-08-14 22:25:19 +08:00
|
|
|
journal_t *journal;
|
|
|
|
int retval;
|
|
|
|
|
2008-05-23 13:00:19 +08:00
|
|
|
clear_problem_context(&pctx);
|
|
|
|
|
2001-12-16 15:23:36 +08:00
|
|
|
journal_init_revoke_caches();
|
2000-08-14 22:25:19 +08:00
|
|
|
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 06:06:31 +08:00
|
|
|
return retval;
|
|
|
|
|
2000-08-14 22:25:19 +08:00
|
|
|
retval = e2fsck_journal_load(journal);
|
|
|
|
if (retval)
|
2001-01-13 05:11:24 +08:00
|
|
|
goto errout;
|
2000-08-14 22:25:19 +08:00
|
|
|
|
2000-12-09 14:41:25 +08:00
|
|
|
retval = journal_init_revoke(journal, 1024);
|
|
|
|
if (retval)
|
2001-01-13 05:11:24 +08:00
|
|
|
goto errout;
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2000-08-14 22:25:19 +08:00
|
|
|
retval = -journal_recover(journal);
|
2001-08-07 22:17:41 +08:00
|
|
|
if (retval)
|
|
|
|
goto errout;
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2008-05-23 13:00:19 +08:00
|
|
|
if (journal->j_failed_commit) {
|
|
|
|
pctx.ino = journal->j_failed_commit;
|
|
|
|
fix_problem(ctx, PR_0_JNL_TXN_CORRUPT, &pctx);
|
|
|
|
ctx->fs->super->s_state |= EXT2_ERROR_FS;
|
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2001-08-07 22:17:41 +08:00
|
|
|
if (journal->j_superblock->s_errno) {
|
|
|
|
ctx->fs->super->s_state |= EXT2_ERROR_FS;
|
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
journal->j_superblock->s_errno = 0;
|
2001-12-16 15:23:36 +08:00
|
|
|
mark_buffer_dirty(journal->j_sb_buffer);
|
2001-08-07 22:17:41 +08:00
|
|
|
}
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2001-01-13 05:11:24 +08:00
|
|
|
errout:
|
2002-02-22 13:17:59 +08:00
|
|
|
journal_destroy_revoke(journal);
|
2001-12-16 15:23:36 +08:00
|
|
|
journal_destroy_revoke_caches();
|
2001-01-13 05:11:24 +08:00
|
|
|
e2fsck_journal_release(ctx, journal, 1, 0);
|
2000-08-14 22:25:19 +08:00
|
|
|
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 23:08:37 +08:00
|
|
|
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 06:06:31 +08:00
|
|
|
errcode_t retval, recover_retval;
|
2009-05-26 08:14:04 +08:00
|
|
|
io_stats stats = 0;
|
|
|
|
unsigned long long kbytes_written = 0;
|
2000-10-25 09:38:50 +08: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 06:06:31 +08:00
|
|
|
if (ctx->options & E2F_OPT_READONLY) {
|
2000-10-25 09:38:50 +08: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 06:06:31 +08:00
|
|
|
ctx->device_name);
|
|
|
|
return EXT2_ET_FILE_RO;
|
|
|
|
}
|
|
|
|
|
2001-07-11 02:34:41 +08:00
|
|
|
if (ctx->fs->flags & EXT2_FLAG_DIRTY)
|
2001-07-11 02:27:58 +08:00
|
|
|
ext2fs_flush(ctx->fs); /* Force out any modifications */
|
2001-02-13 12:32:53 +08: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 06:06:31 +08:00
|
|
|
recover_retval = recover_ext3_journal(ctx);
|
2008-08-28 11:07:54 +08: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 23:08:37 +08:00
|
|
|
/*
|
|
|
|
* Reload the filesystem context to get up-to-date data from disk
|
|
|
|
* because journal recovery will change the filesystem under us.
|
|
|
|
*/
|
2009-05-26 08:14:04 +08:00
|
|
|
if (ctx->fs->super->s_kbytes_written &&
|
|
|
|
ctx->fs->io->manager->get_stats)
|
|
|
|
ctx->fs->io->manager->get_stats(ctx->fs->io, &stats);
|
|
|
|
if (stats && stats->bytes_written)
|
|
|
|
kbytes_written = stats->bytes_written >> 10;
|
2011-09-25 01:48:55 +08:00
|
|
|
|
|
|
|
ext2fs_mmp_stop(ctx->fs);
|
2009-05-26 08:14:04 +08:00
|
|
|
ext2fs_free(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 06:06:31 +08: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 23:08:37 +08: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 05:41:52 +08: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 23:08:37 +08:00
|
|
|
}
|
|
|
|
ctx->fs->priv_data = ctx;
|
2005-09-25 09:59:45 +08:00
|
|
|
ctx->fs->now = ctx->now;
|
2007-06-19 06:26:50 +08:00
|
|
|
ctx->fs->flags |= EXT2_FLAG_MASTER_SB_ONLY;
|
2009-05-26 08:14:04 +08:00
|
|
|
ctx->fs->super->s_kbytes_written += kbytes_written;
|
2000-07-07 12:13:21 +08: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 06:06:31 +08:00
|
|
|
/* Set the superblock flags */
|
|
|
|
e2fsck_clear_recover(ctx, recover_retval);
|
|
|
|
return recover_retval;
|
2000-07-07 12:13:21 +08:00
|
|
|
}
|
2001-10-07 09:26:27 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* This function will move the journal inode from a visible file in
|
|
|
|
* the filesystem directory hierarchy to the reserved inode if necessary.
|
|
|
|
*/
|
2002-03-08 12:52:56 +08:00
|
|
|
static const char * const journal_names[] = {
|
2001-10-07 09:26:27 +08:00
|
|
|
".journal", "journal", ".journal.dat", "journal.dat", 0 };
|
|
|
|
|
|
|
|
void e2fsck_move_ext3_journal(e2fsck_t ctx)
|
|
|
|
{
|
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
|
|
|
struct problem_context pctx;
|
|
|
|
struct ext2_inode inode;
|
|
|
|
ext2_filsys fs = ctx->fs;
|
|
|
|
ext2_ino_t ino;
|
|
|
|
errcode_t retval;
|
|
|
|
const char * const * cpp;
|
|
|
|
int group, mount_flags;
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2003-08-21 12:40:26 +08:00
|
|
|
clear_problem_context(&pctx);
|
|
|
|
|
2001-10-07 09:26:27 +08:00
|
|
|
/*
|
|
|
|
* If the filesystem is opened read-only, or there is no
|
2003-08-21 12:40:26 +08:00
|
|
|
* journal, then do nothing.
|
2001-10-07 09:26:27 +08:00
|
|
|
*/
|
|
|
|
if ((ctx->options & E2F_OPT_READONLY) ||
|
|
|
|
(sb->s_journal_inum == 0) ||
|
|
|
|
!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL))
|
|
|
|
return;
|
|
|
|
|
2003-08-21 12:40:26 +08:00
|
|
|
/*
|
|
|
|
* Read in the journal inode
|
|
|
|
*/
|
|
|
|
if (ext2fs_read_inode(fs, sb->s_journal_inum, &inode) != 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If it's necessary to backup the journal inode, do so.
|
|
|
|
*/
|
|
|
|
if ((sb->s_jnl_backup_type == 0) ||
|
|
|
|
((sb->s_jnl_backup_type == EXT3_JNL_BACKUP_BLOCKS) &&
|
|
|
|
memcmp(inode.i_block, sb->s_jnl_blocks, EXT2_N_BLOCKS*4))) {
|
|
|
|
if (fix_problem(ctx, PR_0_BACKUP_JNL, &pctx)) {
|
|
|
|
memcpy(sb->s_jnl_blocks, inode.i_block,
|
|
|
|
EXT2_N_BLOCKS*4);
|
2011-06-12 00:17:29 +08:00
|
|
|
sb->s_jnl_blocks[15] = inode.i_size_high;
|
2003-08-21 12:40:26 +08:00
|
|
|
sb->s_jnl_blocks[16] = inode.i_size;
|
|
|
|
sb->s_jnl_backup_type = EXT3_JNL_BACKUP_BLOCKS;
|
|
|
|
ext2fs_mark_super_dirty(fs);
|
2003-08-21 20:59:38 +08:00
|
|
|
fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
|
2003-08-21 12:40:26 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If the journal is already the hidden inode, then do nothing
|
|
|
|
*/
|
|
|
|
if (sb->s_journal_inum == EXT2_JOURNAL_INO)
|
|
|
|
return;
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2003-08-21 12:40:26 +08:00
|
|
|
/*
|
|
|
|
* The journal inode had better have only one link and not be readable.
|
|
|
|
*/
|
|
|
|
if (inode.i_links_count != 1)
|
|
|
|
return;
|
|
|
|
|
2001-10-07 09:26:27 +08:00
|
|
|
/*
|
|
|
|
* If the filesystem is mounted, or we can't tell whether
|
|
|
|
* or not it's mounted, do nothing.
|
|
|
|
*/
|
|
|
|
retval = ext2fs_check_if_mounted(ctx->filesystem_name, &mount_flags);
|
|
|
|
if (retval || (mount_flags & EXT2_MF_MOUNTED))
|
|
|
|
return;
|
|
|
|
|
|
|
|
/*
|
|
|
|
* If we can't find the name of the journal inode, then do
|
|
|
|
* nothing.
|
|
|
|
*/
|
|
|
|
for (cpp = journal_names; *cpp; cpp++) {
|
|
|
|
retval = ext2fs_lookup(fs, EXT2_ROOT_INO, *cpp,
|
|
|
|
strlen(*cpp), 0, &ino);
|
|
|
|
if ((retval == 0) && (ino == sb->s_journal_inum))
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (*cpp == 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
/* We need the inode bitmap to be loaded */
|
|
|
|
retval = ext2fs_read_bitmaps(fs);
|
|
|
|
if (retval)
|
|
|
|
return;
|
|
|
|
|
|
|
|
pctx.str = *cpp;
|
|
|
|
if (!fix_problem(ctx, PR_0_MOVE_JOURNAL, &pctx))
|
|
|
|
return;
|
2008-08-28 11:07:54 +08:00
|
|
|
|
2001-10-07 09:26:27 +08:00
|
|
|
/*
|
|
|
|
* OK, we've done all the checks, let's actually move the
|
|
|
|
* journal inode. Errors at this point mean we need to force
|
|
|
|
* an ext2 filesystem check.
|
|
|
|
*/
|
|
|
|
if ((retval = ext2fs_unlink(fs, EXT2_ROOT_INO, *cpp, ino, 0)) != 0)
|
|
|
|
goto err_out;
|
|
|
|
if ((retval = ext2fs_write_inode(fs, EXT2_JOURNAL_INO, &inode)) != 0)
|
|
|
|
goto err_out;
|
|
|
|
sb->s_journal_inum = EXT2_JOURNAL_INO;
|
|
|
|
ext2fs_mark_super_dirty(fs);
|
2003-08-21 20:59:38 +08:00
|
|
|
fs->flags &= ~EXT2_FLAG_MASTER_SB_ONLY;
|
2001-10-07 09:26:27 +08:00
|
|
|
inode.i_links_count = 0;
|
2005-04-15 02:07:53 +08:00
|
|
|
inode.i_dtime = ctx->now;
|
2001-10-07 09:26:27 +08:00
|
|
|
if ((retval = ext2fs_write_inode(fs, ino, &inode)) != 0)
|
|
|
|
goto err_out;
|
|
|
|
|
|
|
|
group = ext2fs_group_of_ino(fs, ino);
|
2009-08-23 10:29:02 +08:00
|
|
|
ext2fs_unmark_inode_bitmap2(fs->inode_map, ino);
|
2001-10-07 09:26:27 +08:00
|
|
|
ext2fs_mark_ib_dirty(fs);
|
Convert to use block group accessor functions
Convert direct accesses to use the following block group accessor
functions: ext2fs_block_bitmap_loc(), ext2fs_inode_bitmap_loc(),
ext2fs_inode_table_loc(), ext2fs_bg_itable_unused(),
ext2fs_block_bitmap_loc_set(), ext2fs_inode_bitmap_loc_set(),
ext2fs_inode_table_loc_set(), ext2fs_bg_free_inodes_count(),
ext2fs_ext2fs_bg_used_dirs_count(), ext2fs_bg_free_inodes_count_set(),
ext2fs_bg_free_blocks_count_set(), ext2fs_bg_used_dirs_count_set()
Signed-off-by: Valerie Aurora Henson <vaurora@redhat.com>
Signed-off-by: Nick Dokos <nicholas.dokos@hp.com>
Signed-off-by: "Theodore Ts'o" <tytso@mit.edu>
2009-10-26 09:43:47 +08:00
|
|
|
ext2fs_bg_free_inodes_count_set(fs, group, ext2fs_bg_free_inodes_count(fs, group) + 1);
|
2007-10-22 10:04:03 +08:00
|
|
|
ext2fs_group_desc_csum_set(fs, group);
|
2001-10-07 09:26:27 +08:00
|
|
|
fs->super->s_free_inodes_count++;
|
|
|
|
return;
|
|
|
|
|
|
|
|
err_out:
|
|
|
|
pctx.errcode = retval;
|
|
|
|
fix_problem(ctx, PR_0_ERR_MOVE_JOURNAL, &pctx);
|
|
|
|
fs->super->s_state &= ~EXT2_VALID_FS;
|
|
|
|
ext2fs_mark_super_dirty(fs);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2006-03-11 04:25:59 +08:00
|
|
|
/*
|
|
|
|
* This function makes sure the superblock hint for the external
|
|
|
|
* journal is correct.
|
|
|
|
*/
|
|
|
|
int e2fsck_fix_ext3_journal_hint(e2fsck_t ctx)
|
|
|
|
{
|
|
|
|
struct ext2_super_block *sb = ctx->fs->super;
|
|
|
|
struct problem_context pctx;
|
|
|
|
char uuid[37], *journal_name;
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) ||
|
|
|
|
uuid_is_null(sb->s_journal_uuid))
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uuid_unparse(sb->s_journal_uuid, uuid);
|
|
|
|
journal_name = blkid_get_devname(ctx->blkid, "UUID", uuid);
|
|
|
|
if (!journal_name)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (stat(journal_name, &st) < 0)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (st.st_rdev != sb->s_journal_dev) {
|
|
|
|
clear_problem_context(&pctx);
|
|
|
|
pctx.num = st.st_rdev;
|
|
|
|
if (fix_problem(ctx, PR_0_EXTERNAL_JOURNAL_HINT, &pctx)) {
|
|
|
|
sb->s_journal_dev = st.st_rdev;
|
|
|
|
ext2fs_mark_super_dirty(ctx->fs);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
free(journal_name);
|
|
|
|
return 0;
|
|
|
|
}
|