Skip to content

Commit 2d01ddc

Browse files
jankaratytso
authored andcommitted
ext4: save error info to sb through journal if available
If journalling is still working at the moment we get to writing error information to the superblock we cannot write directly to the superblock as such write could race with journalled update of the superblock and cause journal checksum failures, writing inconsistent information to the journal or other problems. We cannot journal the superblock directly from the error handling functions as we are running in uncertain context and could deadlock so just punt journalled superblock update to a workqueue. Signed-off-by: Jan Kara <jack@suse.cz> Link: https://lore.kernel.org/r/20201216101844.22917-5-jack@suse.cz Signed-off-by: Theodore Ts'o <tytso@mit.edu>
1 parent 05c2c00 commit 2d01ddc

File tree

1 file changed

+75
-26
lines changed

1 file changed

+75
-26
lines changed

fs/ext4/super.c

Lines changed: 75 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ static struct ratelimit_state ext4_mount_msg_ratelimit;
6565
static int ext4_load_journal(struct super_block *, struct ext4_super_block *,
6666
unsigned long journal_devnum);
6767
static int ext4_show_options(struct seq_file *seq, struct dentry *root);
68+
static void ext4_update_super(struct super_block *sb);
6869
static int ext4_commit_super(struct super_block *sb);
6970
static int ext4_mark_recovery_complete(struct super_block *sb,
7071
struct ext4_super_block *es);
@@ -586,9 +587,9 @@ static int ext4_errno_to_code(int errno)
586587
return EXT4_ERR_UNKNOWN;
587588
}
588589

589-
static void __save_error_info(struct super_block *sb, int error,
590-
__u32 ino, __u64 block,
591-
const char *func, unsigned int line)
590+
static void save_error_info(struct super_block *sb, int error,
591+
__u32 ino, __u64 block,
592+
const char *func, unsigned int line)
592593
{
593594
struct ext4_sb_info *sbi = EXT4_SB(sb);
594595

@@ -615,15 +616,6 @@ static void __save_error_info(struct super_block *sb, int error,
615616
spin_unlock(&sbi->s_error_lock);
616617
}
617618

618-
static void save_error_info(struct super_block *sb, int error,
619-
__u32 ino, __u64 block,
620-
const char *func, unsigned int line)
621-
{
622-
__save_error_info(sb, error, ino, block, func, line);
623-
if (!bdev_read_only(sb->s_bdev))
624-
ext4_commit_super(sb);
625-
}
626-
627619
/* Deal with the reporting of failure conditions on a filesystem such as
628620
* inconsistencies detected or read IO failures.
629621
*
@@ -649,20 +641,35 @@ static void ext4_handle_error(struct super_block *sb, bool force_ro, int error,
649641
const char *func, unsigned int line)
650642
{
651643
journal_t *journal = EXT4_SB(sb)->s_journal;
644+
bool continue_fs = !force_ro && test_opt(sb, ERRORS_CONT);
652645

653646
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
654647
if (test_opt(sb, WARN_ON_ERROR))
655648
WARN_ON_ONCE(1);
656649

657-
if (!bdev_read_only(sb->s_bdev))
650+
if (!continue_fs && !sb_rdonly(sb)) {
651+
ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED);
652+
if (journal)
653+
jbd2_journal_abort(journal, -EIO);
654+
}
655+
656+
if (!bdev_read_only(sb->s_bdev)) {
658657
save_error_info(sb, error, ino, block, func, line);
658+
/*
659+
* In case the fs should keep running, we need to writeout
660+
* superblock through the journal. Due to lock ordering
661+
* constraints, it may not be safe to do it right here so we
662+
* defer superblock flushing to a workqueue.
663+
*/
664+
if (continue_fs)
665+
schedule_work(&EXT4_SB(sb)->s_error_work);
666+
else
667+
ext4_commit_super(sb);
668+
}
659669

660-
if (sb_rdonly(sb) || (!force_ro && test_opt(sb, ERRORS_CONT)))
670+
if (sb_rdonly(sb) || continue_fs)
661671
return;
662672

663-
ext4_set_mount_flag(sb, EXT4_MF_FS_ABORTED);
664-
if (journal)
665-
jbd2_journal_abort(journal, -EIO);
666673
/*
667674
* We force ERRORS_RO behavior when system is rebooting. Otherwise we
668675
* could panic during 'reboot -f' as the underlying device got already
@@ -685,7 +692,38 @@ static void flush_stashed_error_work(struct work_struct *work)
685692
{
686693
struct ext4_sb_info *sbi = container_of(work, struct ext4_sb_info,
687694
s_error_work);
695+
journal_t *journal = sbi->s_journal;
696+
handle_t *handle;
688697

698+
/*
699+
* If the journal is still running, we have to write out superblock
700+
* through the journal to avoid collisions of other journalled sb
701+
* updates.
702+
*
703+
* We use directly jbd2 functions here to avoid recursing back into
704+
* ext4 error handling code during handling of previous errors.
705+
*/
706+
if (!sb_rdonly(sbi->s_sb) && journal) {
707+
handle = jbd2_journal_start(journal, 1);
708+
if (IS_ERR(handle))
709+
goto write_directly;
710+
if (jbd2_journal_get_write_access(handle, sbi->s_sbh)) {
711+
jbd2_journal_stop(handle);
712+
goto write_directly;
713+
}
714+
ext4_update_super(sbi->s_sb);
715+
if (jbd2_journal_dirty_metadata(handle, sbi->s_sbh)) {
716+
jbd2_journal_stop(handle);
717+
goto write_directly;
718+
}
719+
jbd2_journal_stop(handle);
720+
return;
721+
}
722+
write_directly:
723+
/*
724+
* Write through journal failed. Write sb directly to get error info
725+
* out and hope for the best.
726+
*/
689727
ext4_commit_super(sbi->s_sb);
690728
}
691729

@@ -944,9 +982,11 @@ __acquires(bitlock)
944982
if (test_opt(sb, WARN_ON_ERROR))
945983
WARN_ON_ONCE(1);
946984
EXT4_SB(sb)->s_mount_state |= EXT4_ERROR_FS;
947-
__save_error_info(sb, EFSCORRUPTED, ino, block, function, line);
948-
if (!bdev_read_only(sb->s_bdev))
985+
if (!bdev_read_only(sb->s_bdev)) {
986+
save_error_info(sb, EFSCORRUPTED, ino, block, function,
987+
line);
949988
schedule_work(&EXT4_SB(sb)->s_error_work);
989+
}
950990
return;
951991
}
952992
ext4_unlock_group(sb, grp);
@@ -5434,15 +5474,12 @@ static int ext4_load_journal(struct super_block *sb,
54345474
return err;
54355475
}
54365476

5437-
static int ext4_commit_super(struct super_block *sb)
5477+
/* Copy state of EXT4_SB(sb) into buffer for on-disk superblock */
5478+
static void ext4_update_super(struct super_block *sb)
54385479
{
54395480
struct ext4_sb_info *sbi = EXT4_SB(sb);
54405481
struct ext4_super_block *es = EXT4_SB(sb)->s_es;
54415482
struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
5442-
int error = 0;
5443-
5444-
if (!sbh || block_device_ejected(sb))
5445-
return error;
54465483

54475484
lock_buffer(sbh);
54485485
/*
@@ -5514,8 +5551,20 @@ static int ext4_commit_super(struct super_block *sb)
55145551
}
55155552
spin_unlock(&sbi->s_error_lock);
55165553

5517-
BUFFER_TRACE(sbh, "marking dirty");
55185554
ext4_superblock_csum_set(sb);
5555+
unlock_buffer(sbh);
5556+
}
5557+
5558+
static int ext4_commit_super(struct super_block *sb)
5559+
{
5560+
struct buffer_head *sbh = EXT4_SB(sb)->s_sbh;
5561+
int error = 0;
5562+
5563+
if (!sbh || block_device_ejected(sb))
5564+
return error;
5565+
5566+
ext4_update_super(sb);
5567+
55195568
if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) {
55205569
/*
55215570
* Oh, dear. A previous attempt to write the
@@ -5530,8 +5579,8 @@ static int ext4_commit_super(struct super_block *sb)
55305579
clear_buffer_write_io_error(sbh);
55315580
set_buffer_uptodate(sbh);
55325581
}
5582+
BUFFER_TRACE(sbh, "marking dirty");
55335583
mark_buffer_dirty(sbh);
5534-
unlock_buffer(sbh);
55355584
error = __sync_dirty_buffer(sbh,
55365585
REQ_SYNC | (test_opt(sb, BARRIER) ? REQ_FUA : 0));
55375586
if (buffer_write_io_error(sbh)) {

0 commit comments

Comments
 (0)