Skip to content

Commit fc4adbf

Browse files
Alex Gartrellmasoncl
authored andcommitted
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 <[email protected]> Signed-off-by: Alex Gartrell <[email protected]>
1 parent 0e378df commit fc4adbf

File tree

3 files changed

+71
-7
lines changed

3 files changed

+71
-7
lines changed

fs/btrfs/btrfs_inode.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -284,4 +284,6 @@ static inline void btrfs_inode_resume_unlocked_dio(struct inode *inode)
284284
&BTRFS_I(inode)->runtime_flags);
285285
}
286286

287+
bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end);
288+
287289
#endif

fs/btrfs/file.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2266,9 +2266,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
22662266
if ((!ordered ||
22672267
(ordered->file_offset + ordered->len <= lockstart ||
22682268
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)) {
22722270
if (ordered)
22732271
btrfs_put_ordered_extent(ordered);
22742272
break;

fs/btrfs/inode.c

Lines changed: 68 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -6735,6 +6735,71 @@ noinline int can_nocow_extent(struct inode *inode, u64 offset, u64 *len,
67356735
return ret;
67366736
}
67376737

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+
67386803
static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
67396804
struct extent_state **cached_state, int writing)
67406805
{
@@ -6759,10 +6824,9 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
67596824
* invalidate needs to happen so that reads after a write do not
67606825
* get stale data.
67616826
*/
6762-
if (!ordered && (!writing ||
6763-
!test_range_bit(&BTRFS_I(inode)->io_tree,
6764-
lockstart, lockend, EXTENT_UPTODATE, 0,
6765-
*cached_state)))
6827+
if (!ordered &&
6828+
(!writing ||
6829+
!btrfs_page_exists_in_range(inode, lockstart, lockend)))
67666830
break;
67676831

67686832
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,

0 commit comments

Comments
 (0)