journal.c revision 80bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96
117390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o/* 217390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o * journal.c --- code for handling the "ext3" journal 33b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * 43b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Copyright (C) 2000 Andreas Dilger 53b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Copyright (C) 2000 Theodore Ts'o 63b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * 73b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Parts of the code are based on fs/jfs/journal.c by Stephen C. Tweedie 83b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Copyright (C) 1999 Red Hat Software 93b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * 103b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * This file may be redistributed under the terms of the 113b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * GNU General Public License version 2 or at your discretion 123b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * any later version. 1317390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o */ 1417390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o 153b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#ifdef HAVE_SYS_MOUNT_H 163b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#include <sys/mount.h> 173b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#define MNT_FL (MS_MGC_VAL | MS_RDONLY) 183b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#endif 193b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#ifdef HAVE_SYS_STAT_H 203b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#include <sys/stat.h> 213b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#endif 2217390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o 233b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#include "jfs.h" 243b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#include "problem.h" 253b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#include "uuid/uuid.h" 2617390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o 273b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#ifdef JFS_DEBUG 283b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic int bh_count = 0; 293b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'oint jfs_enable_debug = 2; 303b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#endif 313b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 323b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'oint bmap(struct inode *inode, int block) 333b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 343b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int retval; 353b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o blk_t phys; 363b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 373b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = ext2fs_bmap(inode->i_ctx->fs, inode->i_ino, &inode->i_ext2, 383b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o NULL, 0, block, &phys); 393b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 403b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) 413b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o com_err(inode->i_ctx->device_name, retval, 423b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o _("bmap journal inode %ld, block %d\n"), 433b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o inode->i_ino, block); 443b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 453b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return phys; 463b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 473b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 483b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostruct buffer_head *getblk(e2fsck_t ctx, blk_t blocknr, int blocksize) 493b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 503b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct buffer_head *bh; 513b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 523b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh = e2fsck_allocate_memory(ctx, sizeof(*bh), "block buffer"); 533b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!bh) 543b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return NULL; 553b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 563b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jfs_debug(4, "getblk for block %lu (%d bytes)(total %d)\n", 573b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o blocknr, blocksize, ++bh_count); 583b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 593b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_ctx = ctx; 603b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_size = blocksize; 613b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_blocknr = blocknr; 623b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 633b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return bh; 643b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 653b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 663b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ovoid ll_rw_block(int rw, int dummy, struct buffer_head *bh) 673b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 683b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int retval; 693b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 703b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (rw == READ && !bh->b_uptodate) { 713b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jfs_debug(3, "reading block %lu/%p\n", bh->b_blocknr, bh); 723b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = io_channel_read_blk(bh->b_ctx->fs->io, bh->b_blocknr, 733b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1, bh->b_data); 743b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) { 753b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o com_err(bh->b_ctx->device_name, retval, 763b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o "while reading block %ld\n", bh->b_blocknr); 773b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_err = retval; 783b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return; 793b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 803b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_uptodate = 1; 813b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } else if (rw == WRITE && bh->b_dirty) { 823b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jfs_debug(3, "writing block %lu/%p\n", bh->b_blocknr, bh); 833b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = io_channel_write_blk(bh->b_ctx->fs->io, bh->b_blocknr, 843b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1, bh->b_data); 853b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) { 863b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o com_err(bh->b_ctx->device_name, retval, 873b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o "while writing block %ld\n", bh->b_blocknr); 883b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_err = retval; 893b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return; 903b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 913b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_dirty = 0; 923b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_uptodate = 1; 933b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } else 943b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jfs_debug(3, "no-op %s for block %lu\n", 953b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o rw == READ ? "read" : "write", bh->b_blocknr); 963b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 973b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 983b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ovoid mark_buffer_dirty(struct buffer_head *bh, int dummy) 993b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 1003b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_dirty = dummy | 1; /* use dummy to avoid unused variable */ 1013b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 1023b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1033b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ovoid brelse(struct buffer_head *bh) 1043b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 1053b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (bh->b_dirty) 1063b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ll_rw_block(WRITE, 1, bh); 1073b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jfs_debug(3, "freeing block %lu/%p (total %d)\n", 1083b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh->b_blocknr, bh, --bh_count); 1093b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_free_mem((void **) &bh); 1103b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 1113b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1123b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'oint buffer_uptodate(struct buffer_head *bh) 1133b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 1143b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return bh->b_uptodate; 1153b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 1163b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1173b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ovoid wait_on_buffer(struct buffer_head *bh) 1183b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 1193b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!bh->b_uptodate) 1203b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ll_rw_block(READ, 1, bh); 1213b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 1223b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 12380bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o 1243b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic void e2fsck_clear_recover(e2fsck_t ctx, int error) 1253b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 1263b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct ext2fs_sb *s = (struct ext2fs_sb *)ctx->fs->super; 1273b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1283b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; 1293b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1303b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* if we had an error doing journal recovery, we need a full fsck */ 1313b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (error) 1323b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_state &= ~EXT2_VALID_FS; 1333b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_mark_super_dirty(ctx->fs); 1343b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 1353b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1363b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic int e2fsck_journal_init_inode(e2fsck_t ctx, struct ext2fs_sb *s, 1373b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ino_t journal_inum, journal_t **journal) 1383b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 1393b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct inode *inode; 1403b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o const char *cmdname = ctx->program_name; 1413b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct buffer_head *bh; 1423b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o blk_t start; 1433b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int retval; 1443b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1453b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jfs_debug(1, "Using journal inode %lu\n", journal_inum); 1463b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o *journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal"); 1473b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!*journal) { 1483b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_NO_MEMORY; 1493b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 1503b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1513b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o inode = e2fsck_allocate_memory(ctx, sizeof(*inode), "journal inode"); 1523b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!inode) { 1533b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = EXT2_ET_NO_MEMORY; 1543b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto exit_journal; 1553b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 1563b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1573b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o inode->i_ctx = ctx; 1583b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o inode->i_ino = journal_inum; 1593b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = ext2fs_read_inode(ctx->fs, journal_inum, &inode->i_ext2); 1603b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) 1613b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto exit_inode; 1623b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1633b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o (*journal)->j_dev = ctx; 1643b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o (*journal)->j_inode = inode; 1653b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o (*journal)->j_blocksize = ctx->fs->blocksize; 1663b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o (*journal)->j_maxlen = inode->i_ext2.i_size / (*journal)->j_blocksize; 1673b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1683b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!inode->i_ext2.i_links_count || 1693b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o !LINUX_S_ISREG(inode->i_ext2.i_mode) || 1703b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o (*journal)->j_maxlen < JFS_MIN_JOURNAL_BLOCKS || 1713b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o (start = bmap(inode, 0)) == 0) { 1723b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = EXT2_ET_BAD_INODE_NUM; 1733b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto exit_inode; 1743b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 1753b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1763b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o bh = getblk(ctx, start, (*journal)->j_blocksize); 1773b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!bh) { 1783b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = EXT2_ET_NO_MEMORY; 1793b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto exit_inode; 1803b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 1813b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o (*journal)->j_sb_buffer = bh; 1823b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o (*journal)->j_superblock = (journal_superblock_t *)bh->b_data; 1833b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1843b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 1853b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1863b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'oexit_inode: 1873b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_free_mem((void **)&inode); 1883b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'oexit_journal: 1893b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_free_mem((void **)journal); 1903b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1913b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return retval; 1923b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 1933b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 1943b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic int e2fsck_get_journal(e2fsck_t ctx, journal_t **journal) 1953b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 1963b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o char uuid_str[40]; 1973b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct problem_context pctx; 1983b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct ext2fs_sb *s = (struct ext2fs_sb *)ctx->fs->super; 1993b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int recover = s->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; 2003b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2013b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o clear_problem_context(&pctx); 2023b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2033b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (s->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) { 2043b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (s->s_journal_dev) { 2053b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o pctx.num = s->s_journal_dev; 2063b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* this problem aborts on -y, -p, unsupported on -n */ 2073b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_DEV, &pctx)) 2083b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_UNSUPP_FEATURE; 2093b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_journal_dev = 0; 2103b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_state &= ~EXT2_VALID_FS; 2113b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_mark_super_dirty(ctx->fs); 2123b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 2133b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!uuid_is_null(s->s_journal_uuid)) { 2143b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o uuid_unparse(s->s_journal_uuid, uuid_str); 2153b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o pctx.str = uuid_str; 2163b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* this problem aborts on -y, -p, unsupported on -n */ 2173b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_UUID, &pctx)) 2183b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_UNSUPP_FEATURE; 2193b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o uuid_clear(s->s_journal_uuid); 2203b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_state &= ~EXT2_VALID_FS; 2213b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_mark_super_dirty(ctx->fs); 2223b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 2233b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!s->s_journal_inum) 2243b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_BAD_INODE_NUM; 2253b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 2263b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2273b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (s->s_journal_dev) { 2283b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o pctx.num = s->s_journal_dev; 2293b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!fix_problem(ctx, PR_0_JOURNAL_BAD_DEV, &pctx)) 2303b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_UNSUPP_FEATURE; 2313b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_journal_dev = 0; 2323b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_state &= ~EXT2_VALID_FS; 2333b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_mark_super_dirty(ctx->fs); 2343b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 2353b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!uuid_is_null(s->s_journal_uuid)) { 2363b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o uuid_unparse(s->s_journal_uuid, uuid_str); 2373b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o pctx.str = uuid_str; 2383b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!fix_problem(ctx, PR_0_JOURNAL_BAD_UUID, &pctx)) 2393b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_UNSUPP_FEATURE; 2403b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o uuid_clear(s->s_journal_uuid); 2413b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_state &= ~EXT2_VALID_FS; 2423b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_mark_super_dirty(ctx->fs); 2433b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 2443b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2453b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return e2fsck_journal_init_inode(ctx, s, s->s_journal_inum, journal); 2463b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 2473b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2483b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic int e2fsck_journal_fix_bad_inode(e2fsck_t ctx, 2493b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct problem_context *pctx) 2503b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 2513b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct ext2fs_sb *s = (struct ext2fs_sb *)ctx->fs->super; 2523b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int recover = s->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; 2533b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int has_journal = s->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL; 2543b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2553b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (has_journal || s->s_journal_inum) { 2563b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* The journal inode is bogus, remove and force full fsck */ 2573b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) { 2583b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct ext2fs_sb *s =(struct ext2fs_sb *)ctx->fs->super; 2593b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2603b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (has_journal && s->s_journal_inum) 2613b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o printf("*** ext3 journal has been deleted - " 2623b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o "filesystem is now ext2 only ***\n\n"); 2633b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; 2643b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_journal_inum = 0; 2653b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_clear_recover(ctx, 1); 2663b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 2673b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 2683b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_BAD_INODE_NUM; 2693b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } else if (recover) { 2703b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, pctx)) { 2713b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_clear_recover(ctx, 1); 2723b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 2733b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 2743b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_UNSUPP_FEATURE; 2753b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 2763b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 2773b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 2783b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2793b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic int e2fsck_journal_fix_unsupported_super(e2fsck_t ctx, 2803b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct problem_context *pctx) 2813b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 2823b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct ext2fs_sb *s = (struct ext2fs_sb *)ctx->fs->super; 2833b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2843b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* Unsupported journal superblock - first choice is abort. 2853b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Declining that gives the option to reset the superblock. 2863b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * 2873b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Otherwise we get the chance to delete the journal, and 2883b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * failing that we abort because we can't handle this. 2893b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o */ 2903b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (s->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL && 2913b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o fix_problem(ctx, PR_0_JOURNAL_UNSUPP_SUPER, pctx)) 2923b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_CORRUPT_SUPERBLOCK; 2933b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2943b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (e2fsck_journal_fix_bad_inode(ctx, pctx)) 2953b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_UNSUPP_FEATURE; 2963b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 2973b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 2983b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 2993b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3003b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic int e2fsck_journal_load(journal_t *journal) 3013b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 3023b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_t ctx = journal->j_dev; 3033b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal_superblock_t *jsb; 3043b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct buffer_head *jbh = journal->j_sb_buffer; 3053b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct problem_context pctx; 3063b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3073b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o clear_problem_context(&pctx); 3083b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3093b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ll_rw_block(READ, 1, jbh); 3103b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (jbh->b_err) { 3113b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o com_err(ctx->device_name, jbh->b_err, 3123b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o _("reading journal superblock\n")); 3133b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return jbh->b_err; 3143b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 3153b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3163b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb = journal->j_superblock; 3173b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* If we don't even have JFS_MAGIC, we probably have a wrong inode */ 3183b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER)) 3193b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return e2fsck_journal_fix_bad_inode(ctx, &pctx); 3203b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3213b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK) || 3223b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_blocksize != htonl(journal->j_blocksize)) { 3233b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o com_err(ctx->device_name, EXT2_ET_CORRUPT_SUPERBLOCK, 3243b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o _("%s: no valid journal superblock found\n")); 3253b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_CORRUPT_SUPERBLOCK; 3263b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 3273b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3283b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK)) { 3293b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o pctx.num = ntohl(jsb->s_header.h_blocktype); 3303b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return e2fsck_journal_fix_unsupported_super(ctx, &pctx); 3313b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 3323b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3333b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (ntohl(jsb->s_maxlen) < journal->j_maxlen) 3343b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal->j_maxlen = ntohl(jsb->s_maxlen); 3353b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) { 3363b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o com_err(ctx->device_name, EXT2_ET_CORRUPT_SUPERBLOCK, 3373b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o _("%s: journal too short\n")); 3383b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_CORRUPT_SUPERBLOCK; 3393b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 3403b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3413b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal->j_tail_sequence = ntohl(jsb->s_sequence); 3423b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal->j_tail = ntohl(jsb->s_start); 3433b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal->j_first = ntohl(jsb->s_first); 3443b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal->j_last = ntohl(jsb->s_maxlen); 3453b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3463b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 3473b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 3483b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3493b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ovoid e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb, 3503b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o blk_t size) 3513b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 3523b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); 3533b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK); 3543b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_blocksize = htonl(ctx->fs->blocksize); 3553b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_maxlen = htonl(size); 3563b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_first = 1; 3573b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_sequence = htonl(1); 3583b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 3593b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3603b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic int e2fsck_journal_fix_corrupt_super(e2fsck_t ctx, journal_t *journal, 3613b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct problem_context *pctx) 3623b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 3633b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct ext2fs_sb *s = (struct ext2fs_sb *)ctx->fs->super; 3643b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int recover = s->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; 3653b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3663b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o pctx->num = journal->j_inode->i_ino; 3673b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3683b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (s->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) { 3693b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) { 3703b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal_superblock_t *jsb = journal->j_superblock; 3713b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3723b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_journal_reset_super(ctx, jsb, journal->j_maxlen); 3733b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3743b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal->j_transaction_sequence = 1; 3753b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_clear_recover(ctx, recover); 3763b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 3773b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 3783b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_CORRUPT_SUPERBLOCK; 3793b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } else if (e2fsck_journal_fix_bad_inode(ctx, pctx)) 3803b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_CORRUPT_SUPERBLOCK; 3813b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3823b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 3833b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 3843b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3853b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ostatic void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal, int reset) 3863b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 3873b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal_superblock_t *jsb; 3883b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3893b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!(ctx->options & E2F_OPT_READONLY)) { 3903b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb = journal->j_superblock; 3913b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_sequence = htonl(journal->j_transaction_sequence); 3923b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (reset) 3933b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jsb->s_start = 0; /* this marks the journal as empty */ 3943b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o mark_buffer_dirty(journal->j_sb_buffer, 1); 3953b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 3963b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o brelse(journal->j_sb_buffer); 3973b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 3983b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (journal->j_inode) 3993b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o free(journal->j_inode); 4003b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_free_mem((void **)&journal); 4013b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 4023b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4033b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'oint e2fsck_check_ext3_journal(e2fsck_t ctx) 4043b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 4053b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct ext2fs_sb *s = (struct ext2fs_sb *)ctx->fs->super; 4063b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal_t *journal; 4073b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int recover = s->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; 4083b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct problem_context pctx; 4093b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int reset = 0; 4103b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int retval; 4113b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4123b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* If we don't have any journal features, don't do anything more */ 4133b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!(s->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) && 4143b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o !recover && s->s_journal_inum == 0 && s->s_journal_dev == 0 && 4153b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o uuid_is_null(s->s_journal_uuid)) 4163b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 4173b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4183b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o clear_problem_context(&pctx); 4193b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o pctx.num = s->s_journal_inum; 4203b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4213b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = e2fsck_get_journal(ctx, &journal); 4223b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) { 4233b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval == EXT2_ET_BAD_INODE_NUM) 4243b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return e2fsck_journal_fix_bad_inode(ctx, &pctx); 4253b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return retval; 4263b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 4273b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4283b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = e2fsck_journal_load(journal); 4293b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) { 4303b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval == EXT2_ET_CORRUPT_SUPERBLOCK) 4313b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return e2fsck_journal_fix_corrupt_super(ctx, journal, 4323b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o &pctx); 4333b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return retval; 4343b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 4353b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4363b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* 4373b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * We want to make the flags consistent here. We will not leave with 4383b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * needs_recovery set but has_journal clear. We can't get in a loop 4393b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * with -y, -n, or -p, only if a user isn't making up their mind. 4403b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o */ 4413b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'ono_has_journal: 4423b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!(s->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { 4433b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o recover = s->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; 4443b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o pctx.str = "inode"; 4453b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (fix_problem(ctx, PR_0_JOURNAL_HAS_JOURNAL, &pctx)) { 4463b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (recover && 4473b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o !fix_problem(ctx, PR_0_JOURNAL_RECOVER_SET, &pctx)) 4483b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto no_has_journal; 4493b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_journal_inum = 0; 4503b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_clear_recover(ctx, recover); 4513b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } else if (!(ctx->options & E2F_OPT_READONLY)) { 4523b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o s->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; 4533b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2fs_mark_super_dirty(ctx->fs); 4543b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 4553b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 4563b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4573b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (s->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL && 4583b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o !(s->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) && 4593b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal->j_superblock->s_start != 0) { 4603b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (fix_problem(ctx, PR_0_JOURNAL_RESET_JOURNAL, &pctx)) 4613b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o reset = 1; 4623b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* I refuse to enable recovery for journal */ 4633b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 4643b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4653b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_journal_release(ctx, journal, reset); 4663b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return retval; 4673b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 4683b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 46980bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'ostatic int recover_ext3_journal(e2fsck_t ctx) 4703b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o{ 4713b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2_filsys fs = ctx->fs; 4723b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o journal_t *journal; 4733b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int retval; 4743b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4753b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = e2fsck_get_journal(ctx, &journal); 4763b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) 4773b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto exit; 4783b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = e2fsck_journal_load(journal); 4793b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) 4803b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto exit; 4813b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4823b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o retval = -journal_recover(journal); 4833b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4843b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_journal_release(ctx, journal, 1); 4853b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (retval) 4863b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto exit; 4873b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4883b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'oexit: 4893b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o e2fsck_clear_recover(ctx, retval); 4903b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return retval; 4913b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o} 4923b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 4933b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 49480bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o#if 0 4953b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o#define TEMPLATE "/tmp/ext3.XXXXXX" 49617390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o 49717390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o/* 49817390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o * This function attempts to mount and unmount an ext3 filesystem, 49917390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o * which is a cheap way to force the kernel to run the journal and 50080bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o * handle the recovery for us. 50117390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o */ 50280bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'ostatic int recover_ext3_journal_via_mount(e2fsck_t ctx) 50317390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o{ 5043b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ext2_filsys fs = ctx->fs; 5053b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o char *dirlist[] = {"/mnt","/lost+found","/tmp","/root","/boot",0}; 50680bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o errcode_t retval, retval2; 5073b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int count = 0; 5083b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o char template[] = TEMPLATE; 5093b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o struct stat buf; 51017390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o char *tmpdir; 51117390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o 5123b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (ctx->options & E2F_OPT_READONLY) { 5133b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o printf("%s: won't do journal recovery while read-only\n", 5143b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ctx->device_name); 5153b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return EXT2_ET_FILE_RO; 5163b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 5173b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 5183b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o printf(_("%s: trying for ext3 kernel journal recovery\n"), 5193b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o ctx->device_name); 52017390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o /* 52117390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o * First try to make a temporary directory. This may fail if 52217390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o * the root partition is still mounted read-only. 52317390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o */ 5243b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'onewtemp: 52517390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o tmpdir = mktemp(template); 52617390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o if (tmpdir) { 5273b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jfs_debug(2, "trying %s as ext3 temp mount point\n", tmpdir); 52880bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o if (mkdir(template, 0700)) { 5293b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (errno == EROFS) { 5303b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o tmpdir = NULL; 5313b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o template[0] = '\0'; 5323b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } else if (errno == EEXIST && count++ < 10) { 5333b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o strcpy(template, TEMPLATE); 5343b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o goto newtemp; 53580bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o } 53680bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o return errno; 53717390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o } 5383b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 5393b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 5403b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* 5413b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * OK, creating a temporary directory didn't work. 5423b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Let's try a list of possible temporary mountpoints. 5433b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o */ 5443b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (!tmpdir) { 5453b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o dev_t rootdev; 5463b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o char **cpp, *dir; 5473b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 5483b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (stat("/", &buf)) 54980bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o return errno; 5503b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 5513b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o rootdev = buf.st_dev; 5523b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 55317390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o /* 5543b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Check that dir is on the same device as root (no other 5553b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * filesystem is mounted there), and it's a directory. 55617390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o */ 5573b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o for (cpp = dirlist; (dir = *cpp); cpp++) 5583b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (stat(dir, &buf) == 0 && buf.st_dev == rootdev && 5593b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o S_ISDIR(buf.st_mode)) { 5603b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o tmpdir = dir; 56117390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o break; 5623b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 5633b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o } 5643b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 5653b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (tmpdir) { 5663b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o io_manager io_ptr = fs->io->manager; 5673b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o int blocksize = fs->blocksize; 5683b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 5693b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o jfs_debug(2, "using %s for ext3 mount\n", tmpdir); 5703b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* FIXME - need to handle loop devices here */ 57180bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o if (mount(ctx->device_name, tmpdir, "ext3", MNT_FL, NULL)) { 57280bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o retval = errno; 5733b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o com_err(ctx->program_name, errno, 5743b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o "when mounting %s", ctx->device_name); 5753b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (template[0]) 5763b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o rmdir(tmpdir); 57780bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o return retval; 57817390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o } 5793b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* 5803b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Now that it mounted cleanly, the filesystem will have been 5813b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * recovered, so we can now unmount it. 5823b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o */ 58380bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o if (umount(tmpdir)) 58417390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o return errno; 5853b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o 5863b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o /* 5873b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o * Remove the temporary directory, if it was created. 5883b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o */ 5893b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o if (template[0]) 5903b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o rmdir(tmpdir); 5913b5386dca8e0008e13351be5de6323576329aa58Theodore Ts'o return 0; 59217390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o } 59380bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o} 59480bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o#endif 59580bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o 59680bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'oint e2fsck_run_ext3_journal(e2fsck_t ctx) 59780bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o{ 59880bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o io_manager io_ptr = ctx->fs->io->manager; 59980bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o int blocksize = ctx->fs->blocksize; 60080bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o errcode_t retval; 60180bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o 60280bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o if ((retval = recover_ext3_journal(ctx))) 60380bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o return retval; 60480bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o 60580bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o /* 60680bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o * Reload the filesystem context to get up-to-date data from disk 60780bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o * because journal recovery will change the filesystem under us. 60880bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o */ 60980bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o ext2fs_close(ctx->fs); 61080bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o retval = ext2fs_open(ctx->device_name, EXT2_FLAG_RW, 61180bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o ctx->superblock, blocksize, io_ptr, 61280bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o &ctx->fs); 61380bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o 61480bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o if (retval) { 61580bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o com_err(ctx->program_name, retval, 61680bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o _("while trying to re-open %s"), 61780bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o ctx->device_name); 61880bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o exit(FSCK_ERROR); 61980bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o } 62080bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o ctx->fs->priv_data = ctx; 62117390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o 62280bfaa3e40ae6ab00cc3d4d1f4c0eeefce0b1a96Theodore Ts'o return 0; 62317390c047f5470eec005c5461a7926d03d6bbbe7Theodore Ts'o} 624