Skip to content

Commit 4327ba5

Browse files
daehojeongtytso
authored andcommitted
ext4, jbd2: ensure entering into panic after recording an error in superblock
If a EXT4 filesystem utilizes JBD2 journaling and an error occurs, the journaling will be aborted first and the error number will be recorded into JBD2 superblock and, finally, the system will enter into the panic state in "errors=panic" option. But, in the rare case, this sequence is little twisted like the below figure and it will happen that the system enters into panic state, which means the system reset in mobile environment, before completion of recording an error in the journal superblock. In this case, e2fsck cannot recognize that the filesystem failure occurred in the previous run and the corruption wouldn't be fixed. Task A Task B ext4_handle_error() -> jbd2_journal_abort() -> __journal_abort_soft() -> __jbd2_journal_abort_hard() | -> journal->j_flags |= JBD2_ABORT; | | __ext4_abort() | -> jbd2_journal_abort() | | -> __journal_abort_soft() | | -> if (journal->j_flags & JBD2_ABORT) | | return; | -> panic() | -> jbd2_journal_update_sb_errno() Tested-by: Hobin Woo <[email protected]> Signed-off-by: Daeho Jeong <[email protected]> Signed-off-by: Theodore Ts'o <[email protected]> Cc: [email protected]
1 parent 904dad4 commit 4327ba5

File tree

3 files changed

+16
-3
lines changed

3 files changed

+16
-3
lines changed

fs/ext4/super.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -388,9 +388,13 @@ static void ext4_handle_error(struct super_block *sb)
388388
smp_wmb();
389389
sb->s_flags |= MS_RDONLY;
390390
}
391-
if (test_opt(sb, ERRORS_PANIC))
391+
if (test_opt(sb, ERRORS_PANIC)) {
392+
if (EXT4_SB(sb)->s_journal &&
393+
!(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
394+
return;
392395
panic("EXT4-fs (device %s): panic forced after error\n",
393396
sb->s_id);
397+
}
394398
}
395399

396400
#define ext4_error_ratelimit(sb) \
@@ -585,8 +589,12 @@ void __ext4_abort(struct super_block *sb, const char *function,
585589
jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
586590
save_error_info(sb, function, line);
587591
}
588-
if (test_opt(sb, ERRORS_PANIC))
592+
if (test_opt(sb, ERRORS_PANIC)) {
593+
if (EXT4_SB(sb)->s_journal &&
594+
!(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
595+
return;
589596
panic("EXT4-fs panic from previous error\n");
597+
}
590598
}
591599

592600
void __ext4_msg(struct super_block *sb,

fs/jbd2/journal.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2072,8 +2072,12 @@ static void __journal_abort_soft (journal_t *journal, int errno)
20722072

20732073
__jbd2_journal_abort_hard(journal);
20742074

2075-
if (errno)
2075+
if (errno) {
20762076
jbd2_journal_update_sb_errno(journal);
2077+
write_lock(&journal->j_state_lock);
2078+
journal->j_flags |= JBD2_REC_ERR;
2079+
write_unlock(&journal->j_state_lock);
2080+
}
20772081
}
20782082

20792083
/**

include/linux/jbd2.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,7 @@ JBD2_FEATURE_INCOMPAT_FUNCS(csum3, CSUM_V3)
11121112
#define JBD2_ABORT_ON_SYNCDATA_ERR 0x040 /* Abort the journal on file
11131113
* data write error in ordered
11141114
* mode */
1115+
#define JBD2_REC_ERR 0x080 /* The errno in the sb has been recorded */
11151116

11161117
/*
11171118
* Function declarations for the journaling transaction and buffer

0 commit comments

Comments
 (0)