From c905ff44e24c008337685cef37c40a2044a6f50b Mon Sep 17 00:00:00 2001 From: Theodore Ts'o Date: Mon, 4 Jul 2016 11:01:18 -0400 Subject: [PATCH] add patch fix-warn-on-once-in-ext4_commit_super --- fix-warn-on-once-in-ext4_commit_super | 69 +++++++++++++++++++++++++++++++++++ series | 2 + timestamps | 5 ++- 3 files changed, 74 insertions(+), 2 deletions(-) create mode 100644 fix-warn-on-once-in-ext4_commit_super diff --git a/fix-warn-on-once-in-ext4_commit_super b/fix-warn-on-once-in-ext4_commit_super new file mode 100644 index 00000000..6463563a --- /dev/null +++ b/fix-warn-on-once-in-ext4_commit_super @@ -0,0 +1,69 @@ +ext4: Fix WARN_ON_ONCE in ext4_commit_super() + +From: "Pranay Kr. Srivastava" + +If there are racing calls to ext4_commit_super() it's possible for +another writeback of the superblock to result in the buffer being +marked with an error after we check if the buffer is marked as having +a write error and the buffer up-to-date flag is set again. If that +happens mark_buffer_dirty() can end up throwing a WARN_ON_ONCE. + +Fix this by moving this check to write before we call +write_buffer_dirty(), and keeping the buffer locked during this whole +sequence. + +Signed-off-by: Pranay Kr. Srivastava +Signed-off-by: Theodore Ts'o +--- + fs/ext4/super.c | 30 ++++++++++++++++-------------- + 1 file changed, 16 insertions(+), 14 deletions(-) + +diff --git a/fs/ext4/super.c b/fs/ext4/super.c +index 6e2f9d6..5664ee6 100644 +--- a/fs/ext4/super.c ++++ b/fs/ext4/super.c +@@ -4327,20 +4327,6 @@ static int ext4_commit_super(struct super_block *sb, int sync) + + if (!sbh || block_device_ejected(sb)) + return error; +- if (buffer_write_io_error(sbh)) { +- /* +- * Oh, dear. A previous attempt to write the +- * superblock failed. This could happen because the +- * USB device was yanked out. Or it could happen to +- * be a transient write error and maybe the block will +- * be remapped. Nothing we can do but to retry the +- * write and hope for the best. +- */ +- ext4_msg(sb, KERN_ERR, "previous I/O error to " +- "superblock detected"); +- clear_buffer_write_io_error(sbh); +- set_buffer_uptodate(sbh); +- } + /* + * If the file system is mounted read-only, don't update the + * superblock write time. This avoids updating the superblock +@@ -4371,7 +4357,23 @@ static int ext4_commit_super(struct super_block *sb, int sync) + &EXT4_SB(sb)->s_freeinodes_counter)); + BUFFER_TRACE(sbh, "marking dirty"); + ext4_superblock_csum_set(sb); ++ lock_buffer(sbh); ++ if (buffer_write_io_error(sbh)) { ++ /* ++ * Oh, dear. A previous attempt to write the ++ * superblock failed. This could happen because the ++ * USB device was yanked out. Or it could happen to ++ * be a transient write error and maybe the block will ++ * be remapped. Nothing we can do but to retry the ++ * write and hope for the best. ++ */ ++ ext4_msg(sb, KERN_ERR, "previous I/O error to " ++ "superblock detected"); ++ clear_buffer_write_io_error(sbh); ++ set_buffer_uptodate(sbh); ++ } + mark_buffer_dirty(sbh); ++ unlock_buffer(sbh); + if (sync) { + error = __sync_dirty_buffer(sbh, + test_opt(sb, BARRIER) ? WRITE_FUA : WRITE_SYNC); diff --git a/series b/series index 011ffd19..ca8cfc04 100644 --- a/series +++ b/series @@ -14,6 +14,8 @@ correct-error-value-of-function-verifying-dx-checksum fix-deadlock-during-page-writeback +fix-warn-on-once-in-ext4_commit_super + ########################################## # unstable patches #################################################### diff --git a/timestamps b/timestamps index 975d87e3..16c5afcd 100755 --- a/timestamps +++ b/timestamps @@ -42,7 +42,8 @@ touch -d @1467594668 correct-error-value-of-function-verifying-dx-checksum touch -d @1467598849 only-call-ext4_truncate-if-there-is-data-to-truncate touch -d @1467598909 stable-boundary touch -d @1467638021 fix-deadlock-during-page-writeback.orig -touch -d @1467639145 series touch -d @1467641641 fix-deadlock-during-page-writeback -touch -d @1467641642 status touch -d @1467642174 timestamps +touch -d @1467642198 series +touch -d @1467642292 fix-warn-on-once-in-ext4_commit_super +touch -d @1467642292 status -- 2.11.4.GIT