mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/next/linux-next.git
synced 2025-01-10 15:58:47 +00:00
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>
This commit is contained in:
parent
0e378df15c
commit
fc4adbff82
@ -284,4 +284,6 @@ static inline void btrfs_inode_resume_unlocked_dio(struct inode *inode)
|
|||||||
&BTRFS_I(inode)->runtime_flags);
|
&BTRFS_I(inode)->runtime_flags);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -2266,9 +2266,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
|
|||||||
if ((!ordered ||
|
if ((!ordered ||
|
||||||
(ordered->file_offset + ordered->len <= lockstart ||
|
(ordered->file_offset + ordered->len <= lockstart ||
|
||||||
ordered->file_offset > lockend)) &&
|
ordered->file_offset > lockend)) &&
|
||||||
!test_range_bit(&BTRFS_I(inode)->io_tree, lockstart,
|
!btrfs_page_exists_in_range(inode, lockstart, lockend)) {
|
||||||
lockend, EXTENT_UPTODATE, 0,
|
|
||||||
cached_state)) {
|
|
||||||
if (ordered)
|
if (ordered)
|
||||||
btrfs_put_ordered_extent(ordered);
|
btrfs_put_ordered_extent(ordered);
|
||||||
break;
|
break;
|
||||||
|
@ -6735,6 +6735,71 @@ out:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end)
|
||||||
|
{
|
||||||
|
struct radix_tree_root *root = &inode->i_mapping->page_tree;
|
||||||
|
int found = false;
|
||||||
|
void **pagep = NULL;
|
||||||
|
struct page *page = NULL;
|
||||||
|
int start_idx;
|
||||||
|
int end_idx;
|
||||||
|
|
||||||
|
start_idx = start >> PAGE_CACHE_SHIFT;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* end is the last byte in the last page. end == start is legal
|
||||||
|
*/
|
||||||
|
end_idx = end >> PAGE_CACHE_SHIFT;
|
||||||
|
|
||||||
|
rcu_read_lock();
|
||||||
|
|
||||||
|
/* Most of the code in this while loop is lifted from
|
||||||
|
* find_get_page. It's been modified to begin searching from a
|
||||||
|
* page and return just the first page found in that range. If the
|
||||||
|
* found idx is less than or equal to the end idx then we know that
|
||||||
|
* a page exists. If no pages are found or if those pages are
|
||||||
|
* outside of the range then we're fine (yay!) */
|
||||||
|
while (page == NULL &&
|
||||||
|
radix_tree_gang_lookup_slot(root, &pagep, NULL, start_idx, 1)) {
|
||||||
|
page = radix_tree_deref_slot(pagep);
|
||||||
|
if (unlikely(!page))
|
||||||
|
break;
|
||||||
|
|
||||||
|
if (radix_tree_exception(page)) {
|
||||||
|
if (radix_tree_deref_retry(page))
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
|
* Otherwise, shmem/tmpfs must be storing a swap entry
|
||||||
|
* here as an exceptional entry: so return it without
|
||||||
|
* attempting to raise page count.
|
||||||
|
*/
|
||||||
|
break; /* TODO: Is this relevant for this use case? */
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!page_cache_get_speculative(page))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Has the page moved?
|
||||||
|
* This is part of the lockless pagecache protocol. See
|
||||||
|
* include/linux/pagemap.h for details.
|
||||||
|
*/
|
||||||
|
if (unlikely(page != *pagep)) {
|
||||||
|
page_cache_release(page);
|
||||||
|
page = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (page) {
|
||||||
|
if (page->index <= end_idx)
|
||||||
|
found = true;
|
||||||
|
page_cache_release(page);
|
||||||
|
}
|
||||||
|
|
||||||
|
rcu_read_unlock();
|
||||||
|
return found;
|
||||||
|
}
|
||||||
|
|
||||||
static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
|
static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
|
||||||
struct extent_state **cached_state, int writing)
|
struct extent_state **cached_state, int writing)
|
||||||
{
|
{
|
||||||
@ -6759,10 +6824,9 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
|
|||||||
* invalidate needs to happen so that reads after a write do not
|
* invalidate needs to happen so that reads after a write do not
|
||||||
* get stale data.
|
* get stale data.
|
||||||
*/
|
*/
|
||||||
if (!ordered && (!writing ||
|
if (!ordered &&
|
||||||
!test_range_bit(&BTRFS_I(inode)->io_tree,
|
(!writing ||
|
||||||
lockstart, lockend, EXTENT_UPTODATE, 0,
|
!btrfs_page_exists_in_range(inode, lockstart, lockend)))
|
||||||
*cached_state)))
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user