aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTheodore Ts'o <tytso@mit.edu>2012-08-05 19:04:57 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2012-08-26 15:00:42 -0700
commit8b9f3861678e35b18cef66728d0fa896bbda65b6 (patch)
tree99a1336ea8e0dcc55d1c7f2a61f21526cfcf2f88
parent75a757189880a31759ed25c23229f085890cddb1 (diff)
ext4: make sure the journal sb is written in ext4_clear_journal_err()
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>
-rw-r--r--fs/ext4/super.c1
-rw-r--r--fs/jbd2/journal.c3
-rw-r--r--include/linux/jbd2.h1
3 files changed, 4 insertions, 1 deletions
diff --git a/fs/ext4/super.c b/fs/ext4/super.c
index 7fe3869d33d..78fb7ff3adb 100644
--- a/fs/ext4/super.c
+++ b/fs/ext4/super.c
@@ -4227,6 +4227,7 @@ static void ext4_clear_journal_err(struct super_block *sb,
ext4_commit_super(sb, 1);
jbd2_journal_clear_err(journal);
+ jbd2_journal_update_sb_errno(journal);
}
}
diff --git a/fs/jbd2/journal.c b/fs/jbd2/journal.c
index 1afb701622b..9956ac68b72 100644
--- a/fs/jbd2/journal.c
+++ b/fs/jbd2/journal.c
@@ -1340,7 +1340,7 @@ static void jbd2_mark_journal_empty(journal_t *journal)
* 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(journal_t *journal)
jbd2_write_superblock(journal, WRITE_SYNC);
}
+EXPORT_SYMBOL(jbd2_journal_update_sb_errno);
/*
* Read the superblock for a given journal, performing initial
diff --git a/include/linux/jbd2.h b/include/linux/jbd2.h
index 912c30a8ddb..2ed66ef2e68 100644
--- a/include/linux/jbd2.h
+++ b/include/linux/jbd2.h
@@ -1091,6 +1091,7 @@ extern int jbd2_journal_destroy (journal_t *);
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 *);