Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

btrfs: Drop EXTENT_UPTODATE check in hole punching and direct locking

In these instances, we are trying to determine if a page has been accessed
since we began the operation for the sake of retry. This is easily
accomplished by doing a gang lookup in the page mapping radix tree, and it
saves us the dependency on the flag (so that we might eventually delete
it).

btrfs_page_exists_in_range borrows heavily from find_get_page, replacing
the radix tree look up with a gang lookup of 1, so that we can find the
next highest page >= index and see if it falls into our lock range.

Signed-off-by: Chris Mason <clm@fb.com>
Signed-off-by: Alex Gartrell <agartrell@fb.com>

authored by

Alex Gartrell and committed by
Chris Mason
fc4adbff 0e378df1

+71 -7
+2
fs/btrfs/btrfs_inode.h
··· 284 284 &BTRFS_I(inode)->runtime_flags); 285 285 } 286 286 287 + bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end); 288 + 287 289 #endif
+1 -3
fs/btrfs/file.c
··· 2266 2266 if ((!ordered || 2267 2267 (ordered->file_offset + ordered->len <= lockstart || 2268 2268 ordered->file_offset > lockend)) && 2269 - !test_range_bit(&BTRFS_I(inode)->io_tree, lockstart, 2270 - lockend, EXTENT_UPTODATE, 0, 2271 - cached_state)) { 2269 + !btrfs_page_exists_in_range(inode, lockstart, lockend)) { 2272 2270 if (ordered) 2273 2271 btrfs_put_ordered_extent(ordered); 2274 2272 break;
+68 -4
fs/btrfs/inode.c
··· 6735 6735 return ret; 6736 6736 } 6737 6737 6738 + bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end) 6739 + { 6740 + struct radix_tree_root *root = &inode->i_mapping->page_tree; 6741 + int found = false; 6742 + void **pagep = NULL; 6743 + struct page *page = NULL; 6744 + int start_idx; 6745 + int end_idx; 6746 + 6747 + start_idx = start >> PAGE_CACHE_SHIFT; 6748 + 6749 + /* 6750 + * end is the last byte in the last page. end == start is legal 6751 + */ 6752 + end_idx = end >> PAGE_CACHE_SHIFT; 6753 + 6754 + rcu_read_lock(); 6755 + 6756 + /* Most of the code in this while loop is lifted from 6757 + * find_get_page. It's been modified to begin searching from a 6758 + * page and return just the first page found in that range. If the 6759 + * found idx is less than or equal to the end idx then we know that 6760 + * a page exists. If no pages are found or if those pages are 6761 + * outside of the range then we're fine (yay!) */ 6762 + while (page == NULL && 6763 + radix_tree_gang_lookup_slot(root, &pagep, NULL, start_idx, 1)) { 6764 + page = radix_tree_deref_slot(pagep); 6765 + if (unlikely(!page)) 6766 + break; 6767 + 6768 + if (radix_tree_exception(page)) { 6769 + if (radix_tree_deref_retry(page)) 6770 + continue; 6771 + /* 6772 + * Otherwise, shmem/tmpfs must be storing a swap entry 6773 + * here as an exceptional entry: so return it without 6774 + * attempting to raise page count. 6775 + */ 6776 + break; /* TODO: Is this relevant for this use case? */ 6777 + } 6778 + 6779 + if (!page_cache_get_speculative(page)) 6780 + continue; 6781 + 6782 + /* 6783 + * Has the page moved? 6784 + * This is part of the lockless pagecache protocol. See 6785 + * include/linux/pagemap.h for details. 6786 + */ 6787 + if (unlikely(page != *pagep)) { 6788 + page_cache_release(page); 6789 + page = NULL; 6790 + } 6791 + } 6792 + 6793 + if (page) { 6794 + if (page->index <= end_idx) 6795 + found = true; 6796 + page_cache_release(page); 6797 + } 6798 + 6799 + rcu_read_unlock(); 6800 + return found; 6801 + } 6802 + 6738 6803 static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend, 6739 6804 struct extent_state **cached_state, int writing) 6740 6805 { ··· 6824 6759 * invalidate needs to happen so that reads after a write do not 6825 6760 * get stale data. 6826 6761 */ 6827 - if (!ordered && (!writing || 6828 - !test_range_bit(&BTRFS_I(inode)->io_tree, 6829 - lockstart, lockend, EXTENT_UPTODATE, 0, 6830 - *cached_state))) 6762 + if (!ordered && 6763 + (!writing || 6764 + !btrfs_page_exists_in_range(inode, lockstart, lockend))) 6831 6765 break; 6832 6766 6833 6767 unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,