Commit 211c17f5 authored by Chris Mason's avatar Chris Mason

Fix corners in writepage and btrfs_truncate_page

The extent_io writepage calls needed an extra check for discarding
pages that started on th last byte in the file.

btrfs_truncate_page needed checks to make sure the page was still part
of the file after reading it, and most importantly, needed to wait for
all IO to the page to finish before freeing the corresponding extents on
disk.
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent a0af469b
...@@ -1988,9 +1988,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, ...@@ -1988,9 +1988,12 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
u64 nr_delalloc; u64 nr_delalloc;
u64 delalloc_end; u64 delalloc_end;
WARN_ON(!PageLocked(page)); WARN_ON(!PageLocked(page));
if (page->index > end_index) { page_offset = i_size & (PAGE_CACHE_SIZE - 1);
clear_extent_dirty(tree, start, page_end, GFP_NOFS); if (page->index > end_index ||
(page->index == end_index && !page_offset)) {
page->mapping->a_ops->invalidatepage(page, 0);
unlock_page(page); unlock_page(page);
return 0; return 0;
} }
...@@ -1998,13 +2001,13 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc, ...@@ -1998,13 +2001,13 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
if (page->index == end_index) { if (page->index == end_index) {
char *userpage; char *userpage;
size_t offset = i_size & (PAGE_CACHE_SIZE - 1);
userpage = kmap_atomic(page, KM_USER0); userpage = kmap_atomic(page, KM_USER0);
memset(userpage + offset, 0, PAGE_CACHE_SIZE - offset); memset(userpage + page_offset, 0,
flush_dcache_page(page); PAGE_CACHE_SIZE - page_offset);
kunmap_atomic(userpage, KM_USER0); kunmap_atomic(userpage, KM_USER0);
flush_dcache_page(page);
} }
page_offset = 0;
set_page_extent_mapped(page); set_page_extent_mapped(page);
......
...@@ -305,7 +305,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -305,7 +305,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
(inline_size & (root->sectorsize -1)) == 0 || (inline_size & (root->sectorsize -1)) == 0 ||
inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) { inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
u64 last_end; u64 last_end;
u64 existing_delalloc = 0;
for (i = 0; i < num_pages; i++) { for (i = 0; i < num_pages; i++) {
struct page *p = pages[i]; struct page *p = pages[i];
...@@ -315,13 +314,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans, ...@@ -315,13 +314,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
last_end = (u64)(pages[num_pages -1]->index) << last_end = (u64)(pages[num_pages -1]->index) <<
PAGE_CACHE_SHIFT; PAGE_CACHE_SHIFT;
last_end += PAGE_CACHE_SIZE - 1; last_end += PAGE_CACHE_SIZE - 1;
if (start_pos < isize) {
u64 delalloc_start = start_pos;
existing_delalloc = count_range_bits(io_tree,
&delalloc_start,
end_of_last_block, (u64)-1,
EXTENT_DELALLOC);
}
set_extent_delalloc(io_tree, start_pos, end_of_last_block, set_extent_delalloc(io_tree, start_pos, end_of_last_block,
GFP_NOFS); GFP_NOFS);
btrfs_add_ordered_inode(inode); btrfs_add_ordered_inode(inode);
......
...@@ -1180,19 +1180,26 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from) ...@@ -1180,19 +1180,26 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
goto out; goto out;
ret = -ENOMEM; ret = -ENOMEM;
again:
page = grab_cache_page(mapping, index); page = grab_cache_page(mapping, index);
if (!page) if (!page)
goto out; goto out;
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
ret = btrfs_readpage(NULL, page); ret = btrfs_readpage(NULL, page);
lock_page(page); lock_page(page);
if (page->mapping != mapping) {
unlock_page(page);
page_cache_release(page);
goto again;
}
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
ret = -EIO; ret = -EIO;
goto out; goto out;
} }
} }
page_start = (u64)page->index << PAGE_CACHE_SHIFT;
page_start = (u64)page->index << PAGE_CACHE_SHIFT;
wait_on_page_writeback(page);
ret = btrfs_cow_one_page(inode, page, offset); ret = btrfs_cow_one_page(inode, page, offset);
unlock_page(page); unlock_page(page);
......
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