summaryrefslogtreecommitdiff
path: root/fs
diff options
context:
space:
mode:
authorYan <yanzheng@21cn.com>2007-11-06 15:26:26 (GMT)
committerChris Mason <chris.mason@oracle.com>2008-09-25 15:03:57 (GMT)
commitdcfec0dcb1b1a037fb26177789e8f108bc429cb3 (patch)
treeab052a4aa666d6453e26d32ba509e46c0ef3d85f /fs
parent081e95736d9118a96e9f6dcc5cec02dc75c9e1cb (diff)
downloadlinux-fsl-qoriq-dcfec0dcb1b1a037fb26177789e8f108bc429cb3.tar.xz
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/file.c9
1 files changed, 5 insertions, 4 deletions
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 4e52f7e..bb98f52 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) {