Skip to content

Commit 211c17f

Browse files
committed
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: Chris Mason <chris.mason@oracle.com>
1 parent a0af469 commit 211c17f

File tree

3 files changed

+17
-15
lines changed

3 files changed

+17
-15
lines changed

fs/btrfs/extent_io.c

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1988,23 +1988,26 @@ static int __extent_writepage(struct page *page, struct writeback_control *wbc,
19881988
u64 nr_delalloc;
19891989
u64 delalloc_end;
19901990

1991+
19911992
WARN_ON(!PageLocked(page));
1992-
if (page->index > end_index) {
1993-
clear_extent_dirty(tree, start, page_end, GFP_NOFS);
1993+
page_offset = i_size & (PAGE_CACHE_SIZE - 1);
1994+
if (page->index > end_index ||
1995+
(page->index == end_index && !page_offset)) {
1996+
page->mapping->a_ops->invalidatepage(page, 0);
19941997
unlock_page(page);
19951998
return 0;
19961999
}
19972000

19982001
if (page->index == end_index) {
19992002
char *userpage;
20002003

2001-
size_t offset = i_size & (PAGE_CACHE_SIZE - 1);
2002-
20032004
userpage = kmap_atomic(page, KM_USER0);
2004-
memset(userpage + offset, 0, PAGE_CACHE_SIZE - offset);
2005-
flush_dcache_page(page);
2005+
memset(userpage + page_offset, 0,
2006+
PAGE_CACHE_SIZE - page_offset);
20062007
kunmap_atomic(userpage, KM_USER0);
2008+
flush_dcache_page(page);
20072009
}
2010+
page_offset = 0;
20082011

20092012
set_page_extent_mapped(page);
20102013

fs/btrfs/file.c

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -305,7 +305,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
305305
(inline_size & (root->sectorsize -1)) == 0 ||
306306
inline_size >= BTRFS_MAX_INLINE_DATA_SIZE(root)) {
307307
u64 last_end;
308-
u64 existing_delalloc = 0;
309308

310309
for (i = 0; i < num_pages; i++) {
311310
struct page *p = pages[i];
@@ -315,13 +314,6 @@ static int noinline dirty_and_release_pages(struct btrfs_trans_handle *trans,
315314
last_end = (u64)(pages[num_pages -1]->index) <<
316315
PAGE_CACHE_SHIFT;
317316
last_end += PAGE_CACHE_SIZE - 1;
318-
if (start_pos < isize) {
319-
u64 delalloc_start = start_pos;
320-
existing_delalloc = count_range_bits(io_tree,
321-
&delalloc_start,
322-
end_of_last_block, (u64)-1,
323-
EXTENT_DELALLOC);
324-
}
325317
set_extent_delalloc(io_tree, start_pos, end_of_last_block,
326318
GFP_NOFS);
327319
btrfs_add_ordered_inode(inode);

fs/btrfs/inode.c

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1180,19 +1180,26 @@ static int btrfs_truncate_page(struct address_space *mapping, loff_t from)
11801180
goto out;
11811181

11821182
ret = -ENOMEM;
1183+
again:
11831184
page = grab_cache_page(mapping, index);
11841185
if (!page)
11851186
goto out;
11861187
if (!PageUptodate(page)) {
11871188
ret = btrfs_readpage(NULL, page);
11881189
lock_page(page);
1190+
if (page->mapping != mapping) {
1191+
unlock_page(page);
1192+
page_cache_release(page);
1193+
goto again;
1194+
}
11891195
if (!PageUptodate(page)) {
11901196
ret = -EIO;
11911197
goto out;
11921198
}
11931199
}
1194-
page_start = (u64)page->index << PAGE_CACHE_SHIFT;
11951200

1201+
page_start = (u64)page->index << PAGE_CACHE_SHIFT;
1202+
wait_on_page_writeback(page);
11961203
ret = btrfs_cow_one_page(inode, page, offset);
11971204

11981205
unlock_page(page);

0 commit comments

Comments
 (0)