Commit dcfec0dc authored by Yan's avatar Yan Committed by Chris Mason

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: default avatarChris Mason <chris.mason@oracle.com>
parent 081e9573
...@@ -239,9 +239,8 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -239,9 +239,8 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
u64 start_pos; u64 start_pos;
u64 end_of_last_block; u64 end_of_last_block;
u64 end_pos = pos + write_bytes; u64 end_pos = pos + write_bytes;
u32 inline_size; u64 inline_size;
loff_t isize = i_size_read(inode); loff_t isize = i_size_read(inode);
em = alloc_extent_map(GFP_NOFS); em = alloc_extent_map(GFP_NOFS);
if (!em) if (!em)
return -ENOMEM; return -ENOMEM;
...@@ -328,9 +327,11 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -328,9 +327,11 @@ static int dirty_and_release_pages(struct btrfs_trans_handle *trans,
aligned_end, aligned_end, &hint_byte); aligned_end, aligned_end, &hint_byte);
if (err) if (err)
goto failed; 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, err = insert_inline_extent(trans, root, inode, start_pos,
end_pos - start_pos, pages, 0, inline_size, pages, 0, num_pages);
num_pages);
BUG_ON(err); BUG_ON(err);
} }
if (end_pos > isize) { if (end_pos > isize) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment