📄 e2fsck.c
字号:
static void e2fsck_clear_recover(e2fsck_t ctx, int error){ ctx->fs->super->s_feature_incompat &= ~EXT3_FEATURE_INCOMPAT_RECOVER; /* if we had an error doing journal recovery, we need a full fsck */ if (error) ctx->fs->super->s_state &= ~EXT2_VALID_FS; ext2fs_mark_super_dirty(ctx->fs);}static errcode_t e2fsck_get_journal(e2fsck_t ctx, journal_t **ret_journal){ 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; const char *journal_name = 0; journal_t *journal = NULL; errcode_t retval = 0; io_manager io_ptr = 0; unsigned long start = 0; blk_t blk; int ext_journal = 0; int tried_backup_jnl = 0; int i; clear_problem_context(&pctx); journal = e2fsck_allocate_memory(ctx, sizeof(journal_t), "journal"); if (!journal) { return EXT2_ET_NO_MEMORY; } 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; dev_fs->k_ctx = dev_journal->k_ctx = ctx; dev_fs->k_dev = K_DEV_FS; dev_journal->k_dev = K_DEV_JOURNAL; journal->j_dev = dev_journal; journal->j_fs_dev = dev_fs; journal->j_inode = NULL; journal->j_blocksize = ctx->fs->blocksize; if (uuid_is_null(sb->s_journal_uuid)) { if (!sb->s_journal_inum) return EXT2_ET_BAD_INODE_NUM; j_inode = e2fsck_allocate_memory(ctx, sizeof(*j_inode), "journal inode"); if (!j_inode) { retval = EXT2_ET_NO_MEMORY; goto errout; } j_inode->i_ctx = ctx; j_inode->i_ino = sb->s_journal_inum; if ((retval = ext2fs_read_inode(ctx->fs, sb->s_journal_inum, &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)); memcpy(&j_inode->i_ext2.i_block[0], sb->s_jnl_blocks, EXT2_N_BLOCKS*4); 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; tried_backup_jnl++; } if (!j_inode->i_ext2.i_links_count || !LINUX_S_ISREG(j_inode->i_ext2.i_mode)) { retval = EXT2_ET_NO_JOURNAL; goto try_backup_journal; } if (j_inode->i_ext2.i_size / journal->j_blocksize < JFS_MIN_JOURNAL_BLOCKS) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } for (i=0; i < EXT2_N_BLOCKS; i++) { blk = j_inode->i_ext2.i_block[i]; if (!blk) { if (i < EXT2_NDIR_BLOCKS) { retval = EXT2_ET_JOURNAL_TOO_SMALL; goto try_backup_journal; } continue; } if (blk < sb->s_first_data_block || blk >= sb->s_blocks_count) { retval = EXT2_ET_BAD_BLOCK_NUM; goto try_backup_journal; } } journal->j_maxlen = j_inode->i_ext2.i_size / journal->j_blocksize;#ifdef USE_INODE_IO retval = ext2fs_inode_io_intern2(ctx->fs, sb->s_journal_inum, &j_inode->i_ext2, &journal_name); if (retval) goto errout; 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; 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); } journal_name = ctx->journal_name; if (!journal_name) { fix_problem(ctx, PR_0_CANT_FIND_JOURNAL, &pctx); return EXT2_ET_LOAD_EXT_JOURNAL; } io_ptr = unix_io_manager; }#ifndef USE_INODE_IO if (ext_journal)#endif retval = io_ptr->open(journal_name, IO_FLAG_RW, &ctx->journal_io); if (retval) goto errout; 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); if ((retval = bh->b_err) != 0) goto errout; memcpy(&jsuper, start ? bh->b_data : bh->b_data + 1024, sizeof(jsuper)); brelse(bh);#if BB_BIG_ENDIAN if (jsuper.s_magic == ext2fs_swab16(EXT2_SUPER_MAGIC)) ext2fs_swap_super(&jsuper);#endif if (jsuper.s_magic != EXT2_SUPER_MAGIC || !(jsuper.s_feature_incompat & EXT3_FEATURE_INCOMPAT_JOURNAL_DEV)) { fix_problem(ctx, PR_0_EXT_JOURNAL_BAD_SUPER, &pctx); 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; } journal->j_maxlen = jsuper.s_blocks_count; start++; } if (!(bh = getblk(dev_journal, start, journal->j_blocksize))) { retval = EXT2_ET_NO_MEMORY; goto errout; } journal->j_sb_buffer = bh; journal->j_superblock = (journal_superblock_t *)bh->b_data;#ifdef USE_INODE_IO ext2fs_free_mem(&j_inode);#endif *ret_journal = journal; return 0;errout: ext2fs_free_mem(&dev_fs); ext2fs_free_mem(&j_inode); ext2fs_free_mem(&journal); return retval;}static errcode_t e2fsck_journal_fix_bad_inode(e2fsck_t ctx, struct problem_context *pctx){ 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; if (has_journal || sb->s_journal_inum) { /* The journal inode is bogus, remove and force full fsck */ pctx->ino = sb->s_journal_inum; if (fix_problem(ctx, PR_0_JOURNAL_BAD_INODE, pctx)) { if (has_journal && sb->s_journal_inum) printf("*** ext3 journal has been deleted - " "filesystem is now ext2 only ***\n\n"); sb->s_feature_compat &= ~EXT3_FEATURE_COMPAT_HAS_JOURNAL; sb->s_journal_inum = 0; ctx->flags |= E2F_FLAG_JOURNAL_INODE; /* FIXME: todo */ 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;}#define V1_SB_SIZE 0x0024static void clear_v2_journal_fields(journal_t *journal){ e2fsck_t ctx = journal->j_dev->k_ctx; 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); mark_buffer_dirty(journal->j_sb_buffer);}static errcode_t e2fsck_journal_load(journal_t *journal){ e2fsck_t ctx = journal->j_dev->k_ctx; journal_superblock_t *jsb; struct buffer_head *jbh = journal->j_sb_buffer; struct problem_context pctx; clear_problem_context(&pctx); ll_rw_block(READ, 1, &jbh); if (jbh->b_err) { bb_error_msg(_("reading journal superblock")); 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); switch (ntohl(jsb->s_header.h_blocktype)) { case JFS_SUPERBLOCK_V1: journal->j_format_version = 1; if (jsb->s_feature_compat || jsb->s_feature_incompat || jsb->s_feature_ro_compat || jsb->s_nr_users) clear_v2_journal_fields(journal); break; case JFS_SUPERBLOCK_V2: journal->j_format_version = 2; if (ntohl(jsb->s_nr_users) > 1 && uuid_is_null(ctx->fs->super->s_journal_uuid)) clear_v2_journal_fields(journal); if (ntohl(jsb->s_nr_users) > 1) { fix_problem(ctx, PR_0_JOURNAL_UNSUPP_MULTIFS, &pctx); return EXT2_ET_JOURNAL_UNSUPP_VERSION; } break; /* * 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; /* 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: return EXT2_ET_JOURNAL_UNSUPP_VERSION; } if (JFS_HAS_INCOMPAT_FEATURE(journal, ~JFS_KNOWN_INCOMPAT_FEATURES)) return EXT2_ET_UNSUPP_FEATURE; if (JFS_HAS_RO_COMPAT_FEATURE(journal, ~JFS_KNOWN_ROCOMPAT_FEATURES)) return EXT2_ET_RO_UNSUPP_FEATURE; /* 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)) { bb_error_msg(_("%s: no valid journal superblock found"), ctx->device_name); return EXT2_ET_CORRUPT_SUPERBLOCK; } if (ntohl(jsb->s_maxlen) < journal->j_maxlen) journal->j_maxlen = ntohl(jsb->s_maxlen); else if (ntohl(jsb->s_maxlen) > journal->j_maxlen) { bb_error_msg(_("%s: journal too short"), ctx->device_name); return EXT2_ET_CORRUPT_SUPERBLOCK; } journal->j_tail_sequence = ntohl(jsb->s_sequence); journal->j_transaction_sequence = journal->j_tail_sequence; journal->j_tail = ntohl(jsb->s_start); journal->j_first = ntohl(jsb->s_first); journal->j_last = ntohl(jsb->s_maxlen); return 0;}static void e2fsck_journal_reset_super(e2fsck_t ctx, journal_superblock_t *jsb, journal_t *journal){ char *p; union { uuid_t uuid; __u32 val[4]; } u; __u32 new_seq = 0; int i; /* Leave a valid existing V1 superblock signature alone. * Anything unrecognisable we overwrite with a new V2 * signature. */ if (jsb->s_header.h_magic != htonl(JFS_MAGIC_NUMBER) || jsb->s_header.h_blocktype != htonl(JFS_SUPERBLOCK_V1)) { jsb->s_header.h_magic = htonl(JFS_MAGIC_NUMBER); jsb->s_header.h_blocktype = htonl(JFS_SUPERBLOCK_V2); } /* Zero out everything else beyond the superblock header */ p = ((char *) jsb) + sizeof(journal_header_t); memset (p, 0, ctx->fs->blocksize-sizeof(journal_header_t)); jsb->s_blocksize = htonl(ctx->fs->blocksize); jsb->s_maxlen = htonl(journal->j_maxlen); jsb->s_first = htonl(1); /* 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); mark_buffer_dirty(journal->j_sb_buffer); ll_rw_block(WRITE, 1, &journal->j_sb_buffer);}static errcode_t e2fsck_journal_fix_corrupt_super(e2fsck_t ctx, journal_t *journal, struct problem_context *pctx){ struct ext2_super_block *sb = ctx->fs->super; int recover = ctx->fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL) { if (fix_problem(ctx, PR_0_JOURNAL_BAD_SUPER, pctx)) { e2fsck_journal_reset_super(ctx, journal->j_superblock, journal); journal->j_transaction_sequence = 1; e2fsck_clear_recover(ctx, recover); return 0; } return EXT2_ET_CORRUPT_SUPERBLOCK; } else if (e2fsck_journal_fix_bad_inode(ctx, pctx)) return EXT2_ET_CORRUPT_SUPERBLOCK; return 0;}static void e2fsck_journal_release(e2fsck_t ctx, journal_t *journal, int reset, int drop){ journal_superblock_t *jsb; if (drop) mark_buffer_clean(journal->j_sb_buffer); else if (!(ctx->options & E2F_OPT_READONLY)) { jsb = journal->j_superblock; jsb->s_sequence = htonl(journal->j_transaction_sequence); if (reset) jsb->s_start = 0; /* this marks the journal as empty */ mark_buffer_dirty(journal->j_sb_buffer); } brelse(journal->j_sb_buffer); if (ctx->journal_io) { if (ctx->fs && ctx->fs->io != ctx->journal_io) io_channel_close(ctx->journal_io); ctx->journal_io = 0; }#ifndef USE_INODE_IO ext2fs_free_mem(&journal->j_inode);#endif ext2fs_free_mem(&journal->j_fs_dev); ext2fs_free_mem(&journal);}/* * This function makes sure that the superblock fields regarding the * journal are consistent. */static int e2fsck_check_ext3_journal(e2fsck_t ctx){ struct ext2_super_block *sb = ctx->fs->super; journal_t *journal; int recover = ctx->fs->super->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; struct problem_context pctx; problem_t problem; int reset = 0, force_fsck = 0; int retval; /* If we don't have any journal features, don't do anything more */ 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)) return 0; clear_problem_context(&pctx); pctx.num = sb->s_journal_inum; retval = e2fsck_get_journal(ctx, &journal); if (retval) { if ((retval == EXT2_ET_BAD_INODE_NUM) || (retval == EXT2_ET_BAD_BLOCK_NUM) || (retval == EXT2_ET_JOURNAL_TOO_SMALL) || (retval == EXT2_ET_NO_JOURNAL)) return e2fsck_journal_fix_bad_inode(ctx, &pctx); return retval; } retval = e2fsck_journal_load(journal); if (retval) { if ((retval == EXT2_ET_CORRUPT_SUPERBLOCK) || ((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))) || ((retval == EXT2_ET_JOURNAL_UNSUPP_VERSION) && (!fix_problem(ctx, PR_0_JOURNAL_UNSUPP_VERSION, &pctx)))) retval = e2fsck_journal_fix_corrupt_super(ctx, journal, &pctx); e2fsck_journal_release(ctx, journal, 0, 1); 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: if (!(sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL)) { recover = sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER; 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;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -