diff mbox series

ext4: propagate errors from fast commit bitmap rebuild

Message ID tencent_B320F7091730E06C02BAB57D87B0CE363107@qq.com
State New
Headers show
Series ext4: propagate errors from fast commit bitmap rebuild | expand

Commit Message

lty Sept. 15, 2026, 10:29 a.m. UTC
ext4_fc_set_bitmaps_and_counters() rebuilds block bitmaps for modified
inodes during fast-commit replay. When ext4_map_blocks() fails, the helper
stops scanning but previously returned success. Errors from
ext4_find_extent() were also discarded, so replay continued after an
incomplete bitmap rebuild.

Return errors from the helper and propagate them through both replay call
sites so journal recovery aborts when bitmap reconstruction fails.

Fixes: 8016e29f4362 ("ext4: fast commit recovery path")
Cc: stable@vger.kernel.org

Testing: With CONFIG_EXT4_DEBUG, QEMU fast-commit replay was run using a
temporary fault injection that forced -EIO in the bitmap rebuild mapping
call. The unmodified kernel reported recovery complete and mounted the
filesystem; the patched kernel reported journal recovery failure and mount
returned EIO. Built fs/ext4/fast_commit.o and a complete x86 bzImage.

Signed-off-by: lty <781735889@qq.com>
---
 fs/ext4/fast_commit.c | 26 +++++++++++++++-----------
 1 file changed, 15 insertions(+), 11 deletions(-)

Comments

sashiko-bot@kernel.org Sept. 15, 2026, 10:48 a.m. UTC | #1
> ext4_fc_set_bitmaps_and_counters() rebuilds block bitmaps for modified
> inodes during fast-commit replay. When ext4_map_blocks() fails, the helper
> stops scanning but previously returned success. Errors from
> ext4_find_extent() were also discarded, so replay continued after an
> incomplete bitmap rebuild.
> 
> Return errors from the helper and propagate them through both replay call
> sites so journal recovery aborts when bitmap reconstruction fails.
> 
> Fixes: 8016e29f4362 ("ext4: fast commit recovery path")
> Cc: stable@vger.kernel.org
> 
> Testing: With CONFIG_EXT4_DEBUG, QEMU fast-commit replay was run using a
> temporary fault injection that forced -EIO in the bitmap rebuild mapping
> call. The unmodified kernel reported recovery complete and mounted the
> filesystem; the patched kernel reported journal recovery failure and mount
> returned EIO. Built fs/ext4/fast_commit.o and a complete x86 bzImage.
> 
> Signed-off-by: lty <781735889@qq.com>

Sashiko has reviewed this patch and found no issues. It looks great!
diff mbox series

Patch

diff --git a/fs/ext4/fast_commit.c b/fs/ext4/fast_commit.c
index 0cac890cf370..274d4b95ed17 100644
--- a/fs/ext4/fast_commit.c
+++ b/fs/ext4/fast_commit.c
@@ -2314,13 +2314,13 @@  ext4_fc_replay_del_range(struct super_block *sb, u8 *val)
 	return ret;
 }
 
-static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
+static int ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
 {
 	struct ext4_fc_replay_state *state;
 	struct inode *inode;
 	struct ext4_ext_path *path = NULL;
 	struct ext4_map_blocks map;
-	int i, ret, j;
+	int i, ret = 0, j;
 	ext4_lblk_t cur, end;
 
 	state = &EXT4_SB(sb)->s_fc_replay_state;
@@ -2348,13 +2348,14 @@  static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
 
 			if (ret > 0) {
 				path = ext4_find_extent(inode, map.m_lblk, path, 0);
-				if (!IS_ERR(path)) {
-					for (j = 0; j < path->p_depth; j++)
-						ext4_mb_mark_bb(inode->i_sb,
-							path[j].p_block, 1, true);
-				} else {
+				if (IS_ERR(path)) {
+					ret = PTR_ERR(path);
 					path = NULL;
+					break;
 				}
+				for (j = 0; j < path->p_depth; j++)
+					ext4_mb_mark_bb(inode->i_sb,
+							path[j].p_block, 1, true);
 				cur += ret;
 				ext4_mb_mark_bb(inode->i_sb, map.m_pblk,
 							map.m_len, true);
@@ -2363,9 +2364,14 @@  static void ext4_fc_set_bitmaps_and_counters(struct super_block *sb)
 			}
 		}
 		iput(inode);
+		if (ret < 0)
+			goto out;
 	}
 
+	ret = 0;
+out:
 	ext4_free_ext_path(path);
+	return ret;
 }
 
 /*
@@ -2589,8 +2595,7 @@  static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
 	}
 	if (!sbi->s_fc_replay_state.fc_replay_num_tags) {
 		ext4_debug("Replay stops\n");
-		ext4_fc_set_bitmaps_and_counters(sb);
-		return 0;
+		return ext4_fc_set_bitmaps_and_counters(sb);
 	}
 
 #ifdef CONFIG_EXT4_DEBUG
@@ -2609,8 +2614,7 @@  static int ext4_fc_replay(journal_t *journal, struct buffer_head *bh,
 		val = cur + EXT4_FC_TAG_BASE_LEN;
 
 		if (state->fc_replay_num_tags == 0) {
-			ret = JBD2_FC_REPLAY_STOP;
-			ext4_fc_set_bitmaps_and_counters(sb);
+			ret = ext4_fc_set_bitmaps_and_counters(sb);
 			break;
 		}