static errcode_t recover_ext3_journal(e2fsck_t ctx) { journal_t *journal; int retval; journal_init_revoke_caches(); retval = e2fsck_get_journal(ctx, &journal); if (retval) return retval; retval = e2fsck_journal_load(journal); if (retval) goto errout; retval = journal_init_revoke(journal, 1024); if (retval) goto errout; retval = -journal_recover(journal); if (retval) goto errout; 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; mark_buffer_dirty(journal->j_sb_buffer); } errout: journal_destroy_revoke(journal); journal_destroy_revoke_caches(); e2fsck_journal_release(ctx, journal, 1, 0); return retval; }
static errcode_t recover_ext3_journal(e2fsck_t ctx) { struct problem_context pctx; journal_t *journal; int retval; clear_problem_context(&pctx); journal_init_revoke_caches(); retval = e2fsck_get_journal(ctx, &journal); if (retval) return retval; retval = e2fsck_journal_load(journal); if (retval) goto errout; retval = journal_init_revoke(journal, 1024); if (retval) goto errout; retval = -journal_recover(journal); if (retval) goto errout; if (journal->j_failed_commit) { pctx.ino = journal->j_failed_commit; fix_problem(ctx, PR_0_JNL_TXN_CORRUPT, &pctx); journal->j_superblock->s_errno = -EINVAL; mark_buffer_dirty(journal->j_sb_buffer); } errout: journal_destroy_revoke(journal); journal_destroy_revoke_caches(); e2fsck_journal_release(ctx, journal, 1, 0); return retval; }
/* * This function makes sure that the superblock fields regarding the * journal are consistent. */ 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; /* * Need a full fsck if we are releasing a * journal stored on a reserved inode. */ force_fsck = recover || (sb->s_journal_inum < EXT2_FIRST_INODE(sb)); /* Clear all of the journal fields */ sb->s_journal_inum = 0; sb->s_journal_dev = 0; memset(sb->s_journal_uuid, 0, sizeof(sb->s_journal_uuid)); e2fsck_clear_recover(ctx, force_fsck); } else if (!(ctx->options & E2F_OPT_READONLY)) { sb->s_feature_compat |= EXT3_FEATURE_COMPAT_HAS_JOURNAL; ext2fs_mark_super_dirty(ctx->fs); } } if (sb->s_feature_compat & EXT3_FEATURE_COMPAT_HAS_JOURNAL && !(sb->s_feature_incompat & EXT3_FEATURE_INCOMPAT_RECOVER) && journal->j_superblock->s_start != 0) { /* 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)) { reset = 1; sb->s_state &= ~EXT2_VALID_FS; ext2fs_mark_super_dirty(ctx->fs); } /* * If the user answers no to the above question, we * ignore the fact that journal apparently has data; * accidentally replaying over valid data would be far * worse than skipping a questionable recovery. * * XXX should we abort with a fatal error here? What * will the ext3 kernel code do if a filesystem with * !NEEDS_RECOVERY but with a non-zero * journal->j_superblock->s_start is mounted? */ } e2fsck_journal_release(ctx, journal, reset, 0); return retval; }