Skip to content

Commit

Permalink
Btrfs: Search for all ordered extents that could span across a page
Browse files Browse the repository at this point in the history
In subpagesize-blocksize scenario it is not sufficient to search using the
first byte of the page to make sure that there are no ordered extents
present across the page. Fix this.

Signed-off-by: Chandan Rajendra <chandan@linux.vnet.ibm.com>
Signed-off-by: David Sterba <dsterba@suse.com>
  • Loading branch information
Chandan Rajendra authored and David Sterba committed Feb 1, 2016
1 parent d0b7da8 commit dbfdb6d
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 8 deletions.
3 changes: 2 additions & 1 deletion fs/btrfs/extent_io.c
Original file line number Diff line number Diff line change
Expand Up @@ -3186,7 +3186,8 @@ static int __extent_read_full_page(struct extent_io_tree *tree,

while (1) {
lock_extent(tree, start, end);
ordered = btrfs_lookup_ordered_extent(inode, start);
ordered = btrfs_lookup_ordered_range(inode, start,
PAGE_CACHE_SIZE);
if (!ordered)
break;
unlock_extent(tree, start, end);
Expand Down
25 changes: 18 additions & 7 deletions fs/btrfs/inode.c
Original file line number Diff line number Diff line change
Expand Up @@ -2002,7 +2002,8 @@ static void btrfs_writepage_fixup_worker(struct btrfs_work *work)
if (PagePrivate2(page))
goto out;

ordered = btrfs_lookup_ordered_extent(inode, page_start);
ordered = btrfs_lookup_ordered_range(inode, page_start,
PAGE_CACHE_SIZE);
if (ordered) {
unlock_extent_cached(&BTRFS_I(inode)->io_tree, page_start,
page_end, &cached_state, GFP_NOFS);
Expand Down Expand Up @@ -8683,6 +8684,8 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,
struct extent_state *cached_state = NULL;
u64 page_start = page_offset(page);
u64 page_end = page_start + PAGE_CACHE_SIZE - 1;
u64 start;
u64 end;
int inode_evicting = inode->i_state & I_FREEING;

/*
Expand All @@ -8702,14 +8705,18 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,

if (!inode_evicting)
lock_extent_bits(tree, page_start, page_end, &cached_state);
ordered = btrfs_lookup_ordered_extent(inode, page_start);
again:
start = page_start;
ordered = btrfs_lookup_ordered_range(inode, start,
page_end - start + 1);
if (ordered) {
end = min(page_end, ordered->file_offset + ordered->len - 1);
/*
* IO on this page will never be started, so we need
* to account for any ordered extents now
*/
if (!inode_evicting)
clear_extent_bit(tree, page_start, page_end,
clear_extent_bit(tree, start, end,
EXTENT_DIRTY | EXTENT_DELALLOC |
EXTENT_LOCKED | EXTENT_DO_ACCOUNTING |
EXTENT_DEFRAG, 1, 0, &cached_state,
Expand All @@ -8726,22 +8733,26 @@ static void btrfs_invalidatepage(struct page *page, unsigned int offset,

spin_lock_irq(&tree->lock);
set_bit(BTRFS_ORDERED_TRUNCATED, &ordered->flags);
new_len = page_start - ordered->file_offset;
new_len = start - ordered->file_offset;
if (new_len < ordered->truncated_len)
ordered->truncated_len = new_len;
spin_unlock_irq(&tree->lock);

if (btrfs_dec_test_ordered_pending(inode, &ordered,
page_start,
PAGE_CACHE_SIZE, 1))
start,
end - start + 1, 1))
btrfs_finish_ordered_io(ordered);
}
btrfs_put_ordered_extent(ordered);
if (!inode_evicting) {
cached_state = NULL;
lock_extent_bits(tree, page_start, page_end,
lock_extent_bits(tree, start, end,
&cached_state);
}

start = end + 1;
if (start < page_end)
goto again;
}

/*
Expand Down

0 comments on commit dbfdb6d

Please sign in to comment.