| From d796c52ef0b71a988364f6109aeb63d79c5b116b Mon Sep 17 00:00:00 2001 |
| From: Theodore Ts'o <tytso@mit.edu> |
| Date: Sun, 5 Aug 2012 19:04:57 -0400 |
| Subject: ext4: make sure the journal sb is written in ext4_clear_journal_err() |
| |
| From: Theodore Ts'o <tytso@mit.edu> |
| |
| commit d796c52ef0b71a988364f6109aeb63d79c5b116b upstream. |
| |
| After we transfer set the EXT4_ERROR_FS bit in the file system |
| superblock, it's not enough to call jbd2_journal_clear_err() to clear |
| the error indication from journal superblock --- we need to call |
| jbd2_journal_update_sb_errno() as well. Otherwise, when the root file |
| system is mounted read-only, the journal is replayed, and the error |
| indicator is transferred to the superblock --- but the s_errno field |
| in the jbd2 superblock is left set (since although we cleared it in |
| memory, we never flushed it out to disk). |
| |
| This can end up confusing e2fsck. We should make e2fsck more robust |
| in this case, but the kernel shouldn't be leaving things in this |
| confused state, either. |
| |
| Signed-off-by: "Theodore Ts'o" <tytso@mit.edu> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| |
| --- |
| fs/ext4/super.c | 1 + |
| fs/jbd2/journal.c | 3 ++- |
| include/linux/jbd2.h | 1 + |
| 3 files changed, 4 insertions(+), 1 deletion(-) |
| |
| --- a/fs/ext4/super.c |
| +++ b/fs/ext4/super.c |
| @@ -4227,6 +4227,7 @@ static void ext4_clear_journal_err(struc |
| ext4_commit_super(sb, 1); |
| |
| jbd2_journal_clear_err(journal); |
| + jbd2_journal_update_sb_errno(journal); |
| } |
| } |
| |
| --- a/fs/jbd2/journal.c |
| +++ b/fs/jbd2/journal.c |
| @@ -1340,7 +1340,7 @@ static void jbd2_mark_journal_empty(jour |
| * Update a journal's errno. Write updated superblock to disk waiting for IO |
| * to complete. |
| */ |
| -static void jbd2_journal_update_sb_errno(journal_t *journal) |
| +void jbd2_journal_update_sb_errno(journal_t *journal) |
| { |
| journal_superblock_t *sb = journal->j_superblock; |
| |
| @@ -1352,6 +1352,7 @@ static void jbd2_journal_update_sb_errno |
| |
| jbd2_write_superblock(journal, WRITE_SYNC); |
| } |
| +EXPORT_SYMBOL(jbd2_journal_update_sb_errno); |
| |
| /* |
| * Read the superblock for a given journal, performing initial |
| --- a/include/linux/jbd2.h |
| +++ b/include/linux/jbd2.h |
| @@ -1091,6 +1091,7 @@ extern int jbd2_journal_destroy (j |
| extern int jbd2_journal_recover (journal_t *journal); |
| extern int jbd2_journal_wipe (journal_t *, int); |
| extern int jbd2_journal_skip_recovery (journal_t *); |
| +extern void jbd2_journal_update_sb_errno(journal_t *); |
| extern void jbd2_journal_update_sb_log_tail (journal_t *, tid_t, |
| unsigned long, int); |
| extern void __jbd2_journal_abort_hard (journal_t *); |