From: Yan <yanzheng@21cn.com>
Date: Tue, 6 Nov 2007 15:26:26 +0000 (-0500)
Subject: Btrfs: Fix u32 overflow in dirty_and_release_pages.
X-Git-Url: https://git.stricted.de/?a=commitdiff_plain;h=dcfec0dcb1b1a037fb26177789e8f108bc429cb3;p=GitHub%2FLineageOS%2FG12%2Fandroid_kernel_amlogic_linux-4.9.git

Btrfs: Fix u32 overflow in dirty_and_release_pages.

When calculating the size of inline extent,  inode->i_size should also
be take into consideration, otherwise sys_write may drop some data
silently.  You can test this bug by:

#dd if=/dev/zero bs=4k count=1 of=test_file
#dd if=/dev/zero bs=2k count=1 of=test_file conv=notrunc

Signed-off-by: Chris Mason <chris.mason@oracle.com>
---

diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 4e52f7ec1cbe..bb98f52f4ea4 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -239,9 +239,8 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
 	u64 start_pos;
 	u64 end_of_last_block;
 	u64 end_pos = pos + write_bytes;
-	u32 inline_size;
+	u64 inline_size;
 	loff_t isize = i_size_read(inode);
-
 	em = alloc_extent_map(GFP_NOFS);
 	if (!em)
 		return -ENOMEM;
@@ -328,9 +327,11 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
 					 aligned_end, aligned_end, &hint_byte);
 		if (err)
 			goto failed;
+		if (isize > inline_size)
+			inline_size = min_t(u64, isize, aligned_end);
+		inline_size -= start_pos;
 		err = insert_inline_extent(trans, root, inode, start_pos,
-					   end_pos - start_pos, pages, 0,
-					   num_pages);
+					   inline_size, pages, 0, num_pages);
 		BUG_ON(err);
 	}
 	if (end_pos > isize) {