From: Ye Bin yebin10@huawei.com
mainline inclusion from mainline-v5.14-rc1 commit 558d6450c7755aa005d89021204b6cdcae5e848f category: bugfix bugzilla: 109280 CVE: NA
-----------------------------------------------
If a writeback of the superblock fails with an I/O error, the buffer is marked not uptodate. However, this can cause a WARN_ON to trigger when we attempt to write superblock a second time. (Which might succeed this time, for cerrtain types of block devices such as iSCSI devices over a flaky network.)
Try to detect this case in flush_stashed_error_work(), and also change __ext4_handle_dirty_metadata() so we always set the uptodate flag, not just in the nojournal case.
Before this commit, this problem can be repliciated via:
1. dmsetup create dust1 --table '0 2097152 dust /dev/sdc 0 4096' 2. mount /dev/mapper/dust1 /home/test 3. dmsetup message dust1 0 addbadblock 0 10 4. cd /home/test 5. echo "XXXXXXX" > t
After a few seconds, we got following warning:
[ 80.654487] end_buffer_async_write: bh=0xffff88842f18bdd0 [ 80.656134] Buffer I/O error on dev dm-0, logical block 0, lost async page write [ 85.774450] EXT4-fs error (device dm-0): ext4_check_bdev_write_error:193: comm kworker/u16:8: Error while async write back metadata [ 91.415513] mark_buffer_dirty: bh=0xffff88842f18bdd0 [ 91.417038] ------------[ cut here ]------------ [ 91.418450] WARNING: CPU: 1 PID: 1944 at fs/buffer.c:1092 mark_buffer_dirty.cold+0x1c/0x5e [ 91.440322] Call Trace: [ 91.440652] __jbd2_journal_temp_unlink_buffer+0x135/0x220 [ 91.441354] __jbd2_journal_unfile_buffer+0x24/0x90 [ 91.441981] __jbd2_journal_refile_buffer+0x134/0x1d0 [ 91.442628] jbd2_journal_commit_transaction+0x249a/0x3240 [ 91.443336] ? put_prev_entity+0x2a/0x200 [ 91.443856] ? kjournald2+0x12e/0x510 [ 91.444324] kjournald2+0x12e/0x510 [ 91.444773] ? woken_wake_function+0x30/0x30 [ 91.445326] kthread+0x150/0x1b0 [ 91.445739] ? commit_timeout+0x20/0x20 [ 91.446258] ? kthread_flush_worker+0xb0/0xb0 [ 91.446818] ret_from_fork+0x1f/0x30 [ 91.447293] ---[ end trace 66f0b6bf3d1abade ]---
Signed-off-by: Ye Bin yebin10@huawei.com Link: https://lore.kernel.org/r/20210615090537.3423231-1-yebin10@huawei.com Signed-off-by: Theodore Ts'o tytso@mit.edu Signed-off-by: Ye Bin yebin10@huawei.com Reviewed-by: Zhang Yi yi.zhang@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- fs/ext4/ext4_jbd2.c | 2 +- fs/ext4/super.c | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-)
diff --git a/fs/ext4/ext4_jbd2.c b/fs/ext4/ext4_jbd2.c index fd7c41da1f8f9..022ab8afd9499 100644 --- a/fs/ext4/ext4_jbd2.c +++ b/fs/ext4/ext4_jbd2.c @@ -304,6 +304,7 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line,
set_buffer_meta(bh); set_buffer_prio(bh); + set_buffer_uptodate(bh); if (ext4_handle_valid(handle)) { err = jbd2_journal_dirty_metadata(handle, bh); /* Errors can only happen due to aborted journal or a nasty bug */ @@ -332,7 +333,6 @@ int __ext4_handle_dirty_metadata(const char *where, unsigned int line, err); } } else { - set_buffer_uptodate(bh); if (inode) mark_buffer_dirty_inode(bh, inode); else diff --git a/fs/ext4/super.c b/fs/ext4/super.c index fd67f3037fb8e..dd96627ec6ae4 100644 --- a/fs/ext4/super.c +++ b/fs/ext4/super.c @@ -695,15 +695,23 @@ static void flush_stashed_error_work(struct work_struct *work) * ext4 error handling code during handling of previous errors. */ if (!sb_rdonly(sbi->s_sb) && journal) { + struct buffer_head *sbh = sbi->s_sbh; handle = jbd2_journal_start(journal, 1); if (IS_ERR(handle)) goto write_directly; - if (jbd2_journal_get_write_access(handle, sbi->s_sbh)) { + if (jbd2_journal_get_write_access(handle, sbh)) { jbd2_journal_stop(handle); goto write_directly; } ext4_update_super(sbi->s_sb); - if (jbd2_journal_dirty_metadata(handle, sbi->s_sbh)) { + if (buffer_write_io_error(sbh) || !buffer_uptodate(sbh)) { + ext4_msg(sbi->s_sb, KERN_ERR, "previous I/O error to " + "superblock detected"); + clear_buffer_write_io_error(sbh); + set_buffer_uptodate(sbh); + } + + if (jbd2_journal_dirty_metadata(handle, sbh)) { jbd2_journal_stop(handle); goto write_directly; }
From: Ye Bin yebin10@huawei.com
hulk inclusion category: bugfix bugzilla: NA CVE: NA
-----------------------------------------------
This reverts commit 4b45cdf515cc8c252aeca00656767e7c1359dc57.
Signed-off-by: Ye Bin yebin10@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- drivers/scsi/sd.c | 6 +++--- include/scsi/scsi.h | 13 ------------- 2 files changed, 3 insertions(+), 16 deletions(-)
diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index 5fa02f8261cba..4e89a7b499bd3 100644 --- a/drivers/scsi/sd.c +++ b/drivers/scsi/sd.c @@ -2651,18 +2651,18 @@ sd_read_write_protect_flag(struct scsi_disk *sdkp, unsigned char *buffer) * 5: Illegal Request, Sense Code 24: Invalid field in * CDB. */ - if (!scsi_result_is_good(res)) + if (!scsi_status_is_good(res)) res = sd_do_mode_sense(sdp, 0, 0, buffer, 4, &data, NULL);
/* * Third attempt: ask 255 bytes, as we did earlier. */ - if (!scsi_result_is_good(res)) + if (!scsi_status_is_good(res)) res = sd_do_mode_sense(sdp, 0, 0x3F, buffer, 255, &data, NULL); }
- if (!scsi_result_is_good(res)) { + if (!scsi_status_is_good(res)) { sd_first_printk(KERN_WARNING, sdkp, "Test WP failed, assume Write Enabled\n"); } else { diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index f6c2dedd7f8c9..eb7853c1a23b8 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -55,19 +55,6 @@ static inline int scsi_status_is_good(int status) (status == SAM_STAT_COMMAND_TERMINATED)); }
-/** scsi_result_is_good - check the result return. - * - * @result: the result passed up from the driver (including host and - * driver components) - * - * Drivers may only set other bytes but not status byte. - * This checks both the status byte and other bytes. - */ -static inline int scsi_result_is_good(int result) -{ - return scsi_status_is_good(result) && (result & ~0xff) == 0; -} -
/* * standard mode-select header prepended to all mode-select commands
From: Jason Yan yanaijie@huawei.com
mainline inclusion from mainline-v5.14 commit 1ee2753422349723d27009f2f973d03289d430ab category: bugfix bugzilla: NA CVE: NA
-----------------------------------------------
When a SCSI device is offline a MODE SENSE command will return a result with only DID_NO_CONNECT set. In sd_read_write_protect_flag() only the status byte of the result is checked. Despite a returned status of DID_NO_CONNECT the command is considered successful and we read sdkp->write_prot from a buffer containing garbage.
Modify scsi_status_is_good() to treat DID_NO_CONNECT as a failure case.
Link: https://lore.kernel.org/r/20210330114727.234467-1-yanaijie@huawei.com Signed-off-by: Jason Yan yanaijie@huawei.com Signed-off-by: Martin K. Petersen martin.petersen@oracle.com
conflicts: include/scsi/scsi.h
Signed-off-by: Ye Bin yebin10@huawei.com Reviewed-by: Jason Yan yanaijie@huawei.com Signed-off-by: Yang Yingliang yangyingliang@huawei.com --- include/scsi/scsi.h | 54 +++++++++++++++++++++++---------------------- 1 file changed, 28 insertions(+), 26 deletions(-)
diff --git a/include/scsi/scsi.h b/include/scsi/scsi.h index eb7853c1a23b8..6eb693edd36d7 100644 --- a/include/scsi/scsi.h +++ b/include/scsi/scsi.h @@ -30,32 +30,6 @@ enum scsi_timeouts { */ #define SCAN_WILD_CARD ~0
-/** scsi_status_is_good - check the status return. - * - * @status: the status passed up from the driver (including host and - * driver components) - * - * This returns true for known good conditions that may be treated as - * command completed normally - */ -static inline int scsi_status_is_good(int status) -{ - /* - * FIXME: bit0 is listed as reserved in SCSI-2, but is - * significant in SCSI-3. For now, we follow the SCSI-2 - * behaviour and ignore reserved bits. - */ - status &= 0xfe; - return ((status == SAM_STAT_GOOD) || - (status == SAM_STAT_CONDITION_MET) || - /* Next two "intermediate" statuses are obsolete in SAM-4 */ - (status == SAM_STAT_INTERMEDIATE) || - (status == SAM_STAT_INTERMEDIATE_CONDITION_MET) || - /* FIXME: this is obsolete in SAM-3 */ - (status == SAM_STAT_COMMAND_TERMINATED)); -} - - /* * standard mode-select header prepended to all mode-select commands */ @@ -280,4 +254,32 @@ static inline __u32 scsi_to_u32(__u8 *ptr) return (ptr[0]<<24) + (ptr[1]<<16) + (ptr[2]<<8) + ptr[3]; }
+/** scsi_status_is_good - check the status return. + * + * @status: the status passed up from the driver (including host and + * driver components) + * + * This returns true for known good conditions that may be treated as + * command completed normally + */ +static inline int scsi_status_is_good(int status) +{ + if (host_byte(status) == DID_NO_CONNECT) + return 0; + + /* + * FIXME: bit0 is listed as reserved in SCSI-2, but is + * significant in SCSI-3. For now, we follow the SCSI-2 + * behaviour and ignore reserved bits. + */ + status &= 0xfe; + return ((status == SAM_STAT_GOOD) || + (status == SAM_STAT_CONDITION_MET) || + /* Next two "intermediate" statuses are obsolete in SAM-4 */ + (status == SAM_STAT_INTERMEDIATE) || + (status == SAM_STAT_INTERMEDIATE_CONDITION_MET) || + /* FIXME: this is obsolete in SAM-3 */ + (status == SAM_STAT_COMMAND_TERMINATED)); +} + #endif /* _SCSI_SCSI_H */