Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit dbfdb6d1 authored by Chandan Rajendra's avatar Chandan Rajendra Committed by David Sterba
Browse files

Btrfs: Search for all ordered extents that could span across a page



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: default avatarChandan Rajendra <chandan@linux.vnet.ibm.com>
Signed-off-by: default avatarDavid Sterba <dsterba@suse.com>
parent d0b7da88
Loading
Loading
Loading
Loading
+2 −1
Original line number Diff line number Diff line
@@ -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);
+18 −7
Original line number Diff line number Diff line
@@ -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);
@@ -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;

	/*
@@ -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,
@@ -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;
	}

	/*