|
Jan Kara |
7e8f58 |
From 7b97d868b7ab2448859668de9222b8af43f76e78 Mon Sep 17 00:00:00 2001
|
|
Jan Kara |
7e8f58 |
From: "zhangyi (F)" <yi.zhang@huawei.com>
|
|
Jan Kara |
7e8f58 |
Date: Tue, 9 Jun 2020 15:35:40 +0800
|
|
Jan Kara |
7e8f58 |
Subject: [PATCH] ext4, jbd2: ensure panic by fix a race between jbd2 abort and
|
|
Jan Kara |
7e8f58 |
ext4 error handlers
|
|
Jan Kara |
7e8f58 |
Git-commit: 7b97d868b7ab2448859668de9222b8af43f76e78
|
|
Jan Kara |
7e8f58 |
Patch-mainline: v5.8-rc2
|
|
Jan Kara |
7e8f58 |
References: bsc#1173833
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
In the ext4 filesystem with errors=panic, if one process is recording
|
|
Jan Kara |
7e8f58 |
errno in the superblock when invoking jbd2_journal_abort() due to some
|
|
Jan Kara |
7e8f58 |
error cases, it could be raced by another __ext4_abort() which is
|
|
Jan Kara |
7e8f58 |
setting the SB_RDONLY flag but missing panic because errno has not been
|
|
Jan Kara |
7e8f58 |
recorded.
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
jbd2_journal_commit_transaction()
|
|
Jan Kara |
7e8f58 |
jbd2_journal_abort()
|
|
Jan Kara |
7e8f58 |
journal->j_flags |= JBD2_ABORT;
|
|
Jan Kara |
7e8f58 |
jbd2_journal_update_sb_errno()
|
|
Jan Kara |
7e8f58 |
| ext4_journal_check_start()
|
|
Jan Kara |
7e8f58 |
| __ext4_abort()
|
|
Jan Kara |
7e8f58 |
| sb->s_flags |= SB_RDONLY;
|
|
Jan Kara |
7e8f58 |
| if (!JBD2_REC_ERR)
|
|
Jan Kara |
7e8f58 |
| return;
|
|
Jan Kara |
7e8f58 |
journal->j_flags |= JBD2_REC_ERR;
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
Finally, it will no longer trigger panic because the filesystem has
|
|
Jan Kara |
7e8f58 |
already been set read-only. Fix this by introduce j_abort_mutex to make
|
|
Jan Kara |
7e8f58 |
sure journal abort is completed before panic, and remove JBD2_REC_ERR
|
|
Jan Kara |
7e8f58 |
flag.
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
Fixes: 4327ba52afd03 ("ext4, jbd2: ensure entering into panic after recording an error in superblock")
|
|
Jan Kara |
7e8f58 |
Signed-off-by: zhangyi (F) <yi.zhang@huawei.com>
|
|
Jan Kara |
7e8f58 |
Reviewed-by: Jan Kara <jack@suse.cz>
|
|
Jan Kara |
7e8f58 |
Cc: stable@vger.kernel.org
|
|
Jan Kara |
7e8f58 |
Link: https://lore.kernel.org/r/20200609073540.3810702-1-yi.zhang@huawei.com
|
|
Jan Kara |
7e8f58 |
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
|
|
Jan Kara |
7e8f58 |
Acked-by: Jan Kara <jack@suse.cz>
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
---
|
|
Jan Kara |
7e8f58 |
fs/ext4/super.c | 16 +++++-----------
|
|
Jan Kara |
7e8f58 |
fs/jbd2/journal.c | 16 ++++++++++++----
|
|
Jan Kara |
7e8f58 |
include/linux/jbd2.h | 6 +++++-
|
|
Jan Kara |
7e8f58 |
3 files changed, 22 insertions(+), 16 deletions(-)
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
--- a/fs/ext4/super.c
|
|
Jan Kara |
7e8f58 |
+++ b/fs/ext4/super.c
|
|
Jan Kara |
7e8f58 |
@@ -433,9 +433,6 @@ static void ext4_handle_error(struct sup
|
|
Jan Kara |
7e8f58 |
smp_wmb();
|
|
Jan Kara |
7e8f58 |
sb->s_flags |= MS_RDONLY;
|
|
Jan Kara |
7e8f58 |
} else if (test_opt(sb, ERRORS_PANIC)) {
|
|
Jan Kara |
7e8f58 |
- if (EXT4_SB(sb)->s_journal &&
|
|
Jan Kara |
7e8f58 |
- !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
|
|
Jan Kara |
7e8f58 |
- return;
|
|
Jan Kara |
7e8f58 |
panic("EXT4-fs (device %s): panic forced after error\n",
|
|
Jan Kara |
7e8f58 |
sb->s_id);
|
|
Jan Kara |
7e8f58 |
}
|
|
Jan Kara |
7e8f58 |
@@ -637,24 +634,21 @@ void __ext4_abort(struct super_block *sb
|
|
Jan Kara |
7e8f58 |
va_end(args);
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
if ((sb->s_flags & MS_RDONLY) == 0) {
|
|
Jan Kara |
7e8f58 |
- ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
|
|
Jan Kara |
7e8f58 |
EXT4_SB(sb)->s_mount_flags |= EXT4_MF_FS_ABORTED;
|
|
Jan Kara |
7e8f58 |
+ if (EXT4_SB(sb)->s_journal)
|
|
Jan Kara |
7e8f58 |
+ jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
|
|
Jan Kara |
7e8f58 |
+
|
|
Jan Kara |
7e8f58 |
+ ext4_msg(sb, KERN_CRIT, "Remounting filesystem read-only");
|
|
Jan Kara |
7e8f58 |
/*
|
|
Jan Kara |
7e8f58 |
* Make sure updated value of ->s_mount_flags will be visible
|
|
Jan Kara |
7e8f58 |
* before ->s_flags update
|
|
Jan Kara |
7e8f58 |
*/
|
|
Jan Kara |
7e8f58 |
smp_wmb();
|
|
Jan Kara |
7e8f58 |
sb->s_flags |= MS_RDONLY;
|
|
Jan Kara |
7e8f58 |
- if (EXT4_SB(sb)->s_journal)
|
|
Jan Kara |
7e8f58 |
- jbd2_journal_abort(EXT4_SB(sb)->s_journal, -EIO);
|
|
Jan Kara |
7e8f58 |
save_error_info(sb, function, line);
|
|
Jan Kara |
7e8f58 |
}
|
|
Jan Kara |
7e8f58 |
- if (test_opt(sb, ERRORS_PANIC) && !system_going_down()) {
|
|
Jan Kara |
7e8f58 |
- if (EXT4_SB(sb)->s_journal &&
|
|
Jan Kara |
7e8f58 |
- !(EXT4_SB(sb)->s_journal->j_flags & JBD2_REC_ERR))
|
|
Jan Kara |
7e8f58 |
- return;
|
|
Jan Kara |
7e8f58 |
+ if (test_opt(sb, ERRORS_PANIC) && !system_going_down())
|
|
Jan Kara |
7e8f58 |
panic("EXT4-fs panic from previous error\n");
|
|
Jan Kara |
7e8f58 |
- }
|
|
Jan Kara |
7e8f58 |
}
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
void __ext4_msg(struct super_block *sb,
|
|
Jan Kara |
7e8f58 |
--- a/fs/jbd2/journal.c
|
|
Jan Kara |
7e8f58 |
+++ b/fs/jbd2/journal.c
|
|
Jan Kara |
7e8f58 |
@@ -1151,6 +1151,7 @@ static journal_t *journal_init_common(st
|
|
Jan Kara |
7e8f58 |
init_waitqueue_head(&journal->j_wait_commit);
|
|
Jan Kara |
7e8f58 |
init_waitqueue_head(&journal->j_wait_updates);
|
|
Jan Kara |
7e8f58 |
init_waitqueue_head(&journal->j_wait_reserved);
|
|
Jan Kara |
7e8f58 |
+ mutex_init(&journal->j_abort_mutex);
|
|
Jan Kara |
7e8f58 |
mutex_init(&journal->j_barrier);
|
|
Jan Kara |
7e8f58 |
mutex_init(&journal->j_checkpoint_mutex);
|
|
Jan Kara |
7e8f58 |
spin_lock_init(&journal->j_revoke_lock);
|
|
Jan Kara |
7e8f58 |
@@ -1405,7 +1406,8 @@ static int jbd2_write_superblock(journal
|
|
Jan Kara |
7e8f58 |
printk(KERN_ERR "JBD2: Error %d detected when updating "
|
|
Jan Kara |
7e8f58 |
"journal superblock for %s.\n", ret,
|
|
Jan Kara |
7e8f58 |
journal->j_devname);
|
|
Jan Kara |
7e8f58 |
- jbd2_journal_abort(journal, ret);
|
|
Jan Kara |
7e8f58 |
+ if (!is_journal_aborted(journal))
|
|
Jan Kara |
7e8f58 |
+ jbd2_journal_abort(journal, ret);
|
|
Jan Kara |
7e8f58 |
}
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
return ret;
|
|
Jan Kara |
7e8f58 |
@@ -2127,6 +2129,13 @@ static void __journal_abort_soft (journa
|
|
Jan Kara |
7e8f58 |
{
|
|
Jan Kara |
7e8f58 |
int old_errno;
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
+ /*
|
|
Jan Kara |
7e8f58 |
+ * Lock the aborting procedure until everything is done, this avoid
|
|
Jan Kara |
7e8f58 |
+ * races between filesystem's error handling flow (e.g. ext4_abort()),
|
|
Jan Kara |
7e8f58 |
+ * ensure panic after the error info is written into journal's
|
|
Jan Kara |
7e8f58 |
+ * superblock.
|
|
Jan Kara |
7e8f58 |
+ */
|
|
Jan Kara |
7e8f58 |
+ mutex_lock(&journal->j_abort_mutex);
|
|
Jan Kara |
7e8f58 |
write_lock(&journal->j_state_lock);
|
|
Jan Kara |
7e8f58 |
old_errno = journal->j_errno;
|
|
Jan Kara |
7e8f58 |
if (!journal->j_errno || errno == -ESHUTDOWN)
|
|
Jan Kara |
7e8f58 |
@@ -2136,6 +2145,7 @@ static void __journal_abort_soft (journa
|
|
Jan Kara |
7e8f58 |
write_unlock(&journal->j_state_lock);
|
|
Jan Kara |
7e8f58 |
if (old_errno != -ESHUTDOWN && errno == -ESHUTDOWN)
|
|
Jan Kara |
7e8f58 |
jbd2_journal_update_sb_errno(journal);
|
|
Jan Kara |
7e8f58 |
+ mutex_unlock(&journal->j_abort_mutex);
|
|
Jan Kara |
7e8f58 |
return;
|
|
Jan Kara |
7e8f58 |
}
|
|
Jan Kara |
7e8f58 |
write_unlock(&journal->j_state_lock);
|
|
Jan Kara |
7e8f58 |
@@ -2143,9 +2153,7 @@ static void __journal_abort_soft (journa
|
|
Jan Kara |
7e8f58 |
__jbd2_journal_abort_hard(journal);
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
jbd2_journal_update_sb_errno(journal);
|
|
Jan Kara |
7e8f58 |
- write_lock(&journal->j_state_lock);
|
|
Jan Kara |
7e8f58 |
- journal->j_flags |= JBD2_REC_ERR;
|
|
Jan Kara |
7e8f58 |
- write_unlock(&journal->j_state_lock);
|
|
Jan Kara |
7e8f58 |
+ mutex_unlock(&journal->j_abort_mutex);
|
|
Jan Kara |
7e8f58 |
}
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
/**
|
|
Jan Kara |
7e8f58 |
--- a/include/linux/jbd2.h
|
|
Jan Kara |
7e8f58 |
+++ b/include/linux/jbd2.h
|
|
Jan Kara |
7e8f58 |
@@ -779,6 +779,11 @@ struct journal_s
|
|
Jan Kara |
7e8f58 |
int j_errno;
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
/**
|
|
Jan Kara |
7e8f58 |
+ * @j_abort_mutex: Lock the whole aborting procedure.
|
|
Jan Kara |
7e8f58 |
+ */
|
|
Jan Kara |
7e8f58 |
+ struct mutex j_abort_mutex;
|
|
Jan Kara |
7e8f58 |
+
|
|
Jan Kara |
7e8f58 |
+ /**
|
|
Jan Kara |
7e8f58 |
* @j_sb_buffer: The first part of the superblock buffer.
|
|
Jan Kara |
7e8f58 |
*/
|
|
Jan Kara |
7e8f58 |
struct buffer_head *j_sb_buffer;
|
|
Jan Kara |
7e8f58 |
@@ -1253,7 +1258,6 @@ JBD2_FEATURE_INCOMPAT_FUNCS(csum3, CSUM
|
|
Jan Kara |
7e8f58 |
#define JBD2_ABORT_ON_SYNCDATA_ERR 0x040 /* Abort the journal on file
|
|
Jan Kara |
7e8f58 |
* data write error in ordered
|
|
Jan Kara |
7e8f58 |
* mode */
|
|
Jan Kara |
7e8f58 |
-#define JBD2_REC_ERR 0x080 /* The errno in the sb has been recorded */
|
|
Jan Kara |
7e8f58 |
|
|
Jan Kara |
7e8f58 |
/*
|
|
Jan Kara |
7e8f58 |
* Function declarations for the journaling transaction and buffer
|