Commit 1f12bd06 authored by Liu Bo's avatar Liu Bo Committed by Chris Mason

Btrfs: fix the mismatch of page->mapping

commit 600a45e1
(Btrfs: fix deadlock on page lock when doing auto-defragment)
fixes the deadlock on page, but it also introduces another bug.

A page may have been truncated after unlock & lock.
So we need to find it again to get the right one.

And since we've held i_mutex lock, inode size remains unchanged and
we can drop isize overflow checks.
Signed-off-by: default avatarLiu Bo <liubo2009@cn.fujitsu.com>
Signed-off-by: default avatarMiao Xie <miaox@cn.fujitsu.com>
Signed-off-by: default avatarChris Mason <chris.mason@oracle.com>
parent ecb8bea8
...@@ -871,6 +871,7 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -871,6 +871,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
u64 isize = i_size_read(inode); u64 isize = i_size_read(inode);
u64 page_start; u64 page_start;
u64 page_end; u64 page_end;
u64 page_cnt;
int ret; int ret;
int i; int i;
int i_done; int i_done;
...@@ -879,19 +880,21 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -879,19 +880,21 @@ static int cluster_pages_for_defrag(struct inode *inode,
struct extent_io_tree *tree; struct extent_io_tree *tree;
gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping); gfp_t mask = btrfs_alloc_write_mask(inode->i_mapping);
if (isize == 0)
return 0;
file_end = (isize - 1) >> PAGE_CACHE_SHIFT; file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
if (!isize || start_index > file_end)
return 0;
page_cnt = min_t(u64, (u64)num_pages, (u64)file_end - start_index + 1);
ret = btrfs_delalloc_reserve_space(inode, ret = btrfs_delalloc_reserve_space(inode,
num_pages << PAGE_CACHE_SHIFT); page_cnt << PAGE_CACHE_SHIFT);
if (ret) if (ret)
return ret; return ret;
i_done = 0; i_done = 0;
tree = &BTRFS_I(inode)->io_tree; tree = &BTRFS_I(inode)->io_tree;
/* step one, lock all the pages */ /* step one, lock all the pages */
for (i = 0; i < num_pages; i++) { for (i = 0; i < page_cnt; i++) {
struct page *page; struct page *page;
again: again:
page = find_or_create_page(inode->i_mapping, page = find_or_create_page(inode->i_mapping,
...@@ -913,6 +916,15 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -913,6 +916,15 @@ static int cluster_pages_for_defrag(struct inode *inode,
btrfs_start_ordered_extent(inode, ordered, 1); btrfs_start_ordered_extent(inode, ordered, 1);
btrfs_put_ordered_extent(ordered); btrfs_put_ordered_extent(ordered);
lock_page(page); lock_page(page);
/*
* we unlocked the page above, so we need check if
* it was released or not.
*/
if (page->mapping != inode->i_mapping) {
unlock_page(page);
page_cache_release(page);
goto again;
}
} }
if (!PageUptodate(page)) { if (!PageUptodate(page)) {
...@@ -926,15 +938,6 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -926,15 +938,6 @@ static int cluster_pages_for_defrag(struct inode *inode,
} }
} }
isize = i_size_read(inode);
file_end = (isize - 1) >> PAGE_CACHE_SHIFT;
if (!isize || page->index > file_end) {
/* whoops, we blew past eof, skip this page */
unlock_page(page);
page_cache_release(page);
break;
}
if (page->mapping != inode->i_mapping) { if (page->mapping != inode->i_mapping) {
unlock_page(page); unlock_page(page);
page_cache_release(page); page_cache_release(page);
...@@ -967,12 +970,12 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -967,12 +970,12 @@ static int cluster_pages_for_defrag(struct inode *inode,
EXTENT_DO_ACCOUNTING, 0, 0, &cached_state, EXTENT_DO_ACCOUNTING, 0, 0, &cached_state,
GFP_NOFS); GFP_NOFS);
if (i_done != num_pages) { if (i_done != page_cnt) {
spin_lock(&BTRFS_I(inode)->lock); spin_lock(&BTRFS_I(inode)->lock);
BTRFS_I(inode)->outstanding_extents++; BTRFS_I(inode)->outstanding_extents++;
spin_unlock(&BTRFS_I(inode)->lock); spin_unlock(&BTRFS_I(inode)->lock);
btrfs_delalloc_release_space(inode, btrfs_delalloc_release_space(inode,
(num_pages - i_done) << PAGE_CACHE_SHIFT); (page_cnt - i_done) << PAGE_CACHE_SHIFT);
} }
...@@ -997,7 +1000,7 @@ static int cluster_pages_for_defrag(struct inode *inode, ...@@ -997,7 +1000,7 @@ static int cluster_pages_for_defrag(struct inode *inode,
unlock_page(pages[i]); unlock_page(pages[i]);
page_cache_release(pages[i]); page_cache_release(pages[i]);
} }
btrfs_delalloc_release_space(inode, num_pages << PAGE_CACHE_SHIFT); btrfs_delalloc_release_space(inode, page_cnt << PAGE_CACHE_SHIFT);
return ret; return ret;
} }
......
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