Jan Kara 9b7f6a
From 0f2f87d51aebcf71a709b52f661d681594c7dffa Mon Sep 17 00:00:00 2001
Jan Kara 9b7f6a
From: Zhang Yi <yi.zhang@huawei.com>
Jan Kara 9b7f6a
Date: Wed, 8 Sep 2021 20:08:50 +0800
Jan Kara 9b7f6a
Subject: [PATCH] ext4: prevent partial update of the extent blocks
Jan Kara 9b7f6a
Git-commit: 0f2f87d51aebcf71a709b52f661d681594c7dffa
Jan Kara 9b7f6a
Patch-mainline: v5.16-rc1
Jan Kara 9b7f6a
References: bsc#1194163 bsc#1196339
Jan Kara 9b7f6a
Jan Kara 9b7f6a
In the most error path of current extents updating operations are not
Jan Kara 9b7f6a
roll back partial updates properly when some bad things happens(.e.g in
Jan Kara 9b7f6a
ext4_ext_insert_extent()). So we may get an inconsistent extents tree
Jan Kara 9b7f6a
if journal has been aborted due to IO error, which may probability lead
Jan Kara 9b7f6a
to BUGON later when we accessing these extent entries in errors=continue
Jan Kara 9b7f6a
mode. This patch drop extent buffer's verify flag before updatng the
Jan Kara 9b7f6a
contents in ext4_ext_get_access(), and reset it after updating in
Jan Kara 9b7f6a
__ext4_ext_dirty(). After this patch we could force to check the extent
Jan Kara 9b7f6a
buffer if extents tree updating was break off, make sure the extents are
Jan Kara 9b7f6a
consistent.
Jan Kara 9b7f6a
Jan Kara 9b7f6a
Signed-off-by: Zhang Yi <yi.zhang@huawei.com>
Jan Kara 9b7f6a
Reviewed-by: Theodore Ts'o <tytso@mit.edu>
Jan Kara 9b7f6a
Link: https://lore.kernel.org/r/20210908120850.4012324-4-yi.zhang@huawei.com
Jan Kara 9b7f6a
Signed-off-by: Theodore Ts'o <tytso@mit.edu>
Jan Kara 9b7f6a
Acked-by: Jan Kara <jack@suse.cz>
Jan Kara 9b7f6a
Jan Kara 9b7f6a
---
Jan Kara 9b7f6a
 fs/ext4/extents.c |   17 +++++++++++++++--
Jan Kara 9b7f6a
 1 file changed, 15 insertions(+), 2 deletions(-)
Jan Kara 9b7f6a
Jan Kara 9b7f6a
--- a/fs/ext4/extents.c
Jan Kara 9b7f6a
+++ b/fs/ext4/extents.c
Jan Kara 9b7f6a
@@ -133,14 +133,24 @@ static int ext4_ext_truncate_extend_rest
Jan Kara 9b7f6a
 static int ext4_ext_get_access(handle_t *handle, struct inode *inode,
Jan Kara 9b7f6a
 				struct ext4_ext_path *path)
Jan Kara 9b7f6a
 {
Jan Kara 9b7f6a
+	int err = 0;
Jan Kara 9b7f6a
+
Jan Kara 9b7f6a
 	if (path->p_bh) {
Jan Kara 9b7f6a
 		/* path points to block */
Jan Kara 9b7f6a
 		BUFFER_TRACE(path->p_bh, "get_write_access");
Jan Kara 9b7f6a
-		return ext4_journal_get_write_access(handle, path->p_bh);
Jan Kara 9b7f6a
+		err = ext4_journal_get_write_access(handle, path->p_bh);
Jan Kara 9b7f6a
+		/*
Jan Kara 9b7f6a
+		 * The extent buffer's verified bit will be set again in
Jan Kara 9b7f6a
+		 * __ext4_ext_dirty(). We could leave an inconsistent
Jan Kara 9b7f6a
+		 * buffer if the extents updating procudure break off du
Jan Kara 9b7f6a
+		 * to some error happens, force to check it again.
Jan Kara 9b7f6a
+		 */
Jan Kara 9b7f6a
+		if (!err)
Jan Kara 9b7f6a
+			clear_buffer_verified(path->p_bh);
Jan Kara 9b7f6a
 	}
Jan Kara 9b7f6a
 	/* path points to leaf/index in inode body */
Jan Kara 9b7f6a
 	/* we use in-core data, no need to protect them */
Jan Kara 9b7f6a
-	return 0;
Jan Kara 9b7f6a
+	return err;
Jan Kara 9b7f6a
 }
Jan Kara 9b7f6a
 
Jan Kara 9b7f6a
 /*
Jan Kara 9b7f6a
@@ -160,6 +170,9 @@ int __ext4_ext_dirty(const char *where,
Jan Kara 9b7f6a
 		/* path points to block */
Jan Kara 9b7f6a
 		err = __ext4_handle_dirty_metadata(where, line, handle,
Jan Kara 9b7f6a
 						   inode, path->p_bh);
Jan Kara 9b7f6a
+		/* Extents updating done, re-set verified flag */
Jan Kara 9b7f6a
+		if (!err)
Jan Kara 9b7f6a
+			set_buffer_verified(path->p_bh);
Jan Kara 9b7f6a
 	} else {
Jan Kara 9b7f6a
 		/* path points to leaf/index in inode body */
Jan Kara 9b7f6a
 		err = ext4_mark_inode_dirty(handle, inode);