aboutsummaryrefslogtreecommitdiffstats
path: root/fs
diff options
context:
space:
mode:
authorAlex Gartrell <agartrell@fb.com>2014-05-20 16:07:56 -0400
committerChris Mason <clm@fb.com>2014-06-09 20:20:57 -0400
commitfc4adbff823f76577ece26dcb88bf6f8392dbd43 (patch)
treed3708c9b2f6e3023a7da4452d90f65e99a007213 /fs
parent0e378df15cd87f540f1ba9503e4aa039e1c72741 (diff)
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>
Diffstat (limited to 'fs')
-rw-r--r--fs/btrfs/btrfs_inode.h2
-rw-r--r--fs/btrfs/file.c4
-rw-r--r--fs/btrfs/inode.c72
3 files changed, 71 insertions, 7 deletions
diff --git a/fs/btrfs/btrfs_inode.h b/fs/btrfs/btrfs_inode.h
index c9a24444ec9a..a0cf3e56fe20 100644
--- a/fs/btrfs/btrfs_inode.h
+++ b/fs/btrfs/btrfs_inode.h
@@ -284,4 +284,6 @@ static inline void btrfs_inode_resume_unlocked_dio(struct inode *inode)
284 &BTRFS_I(inode)->runtime_flags); 284 &BTRFS_I(inode)->runtime_flags);
285} 285}
286 286
287bool btrfs_page_exists_in_range(struct inode *inode, loff_t start, loff_t end);
288
287#endif 289#endif
diff --git a/fs/btrfs/file.c b/fs/btrfs/file.c
index 8accf94ef220..e46bfaf6cde2 100644
--- a/fs/btrfs/file.c
+++ b/fs/btrfs/file.c
@@ -2266,9 +2266,7 @@ static int btrfs_punch_hole(struct inode *inode, loff_t offset, loff_t len)
2266 if ((!ordered || 2266 if ((!ordered ||
2267 (ordered->file_offset + ordered->len <= lockstart || 2267 (ordered->file_offset + ordered->len <= lockstart ||
2268 ordered->file_offset > lockend)) && 2268 ordered->file_offset > lockend)) &&
2269 !test_range_bit(&BTRFS_I(inode)->io_tree, lockstart, 2269 !btrfs_page_exists_in_range(inode, lockstart, lockend)) {
2270 lockend, EXTENT_UPTODATE, 0,
2271 cached_state)) {
2272 if (ordered) 2270 if (ordered)
2273 btrfs_put_ordered_extent(ordered); 2271 btrfs_put_ordered_extent(ordered);
2274 break; 2272 break;
diff --git a/fs/btrfs/inode.c b/fs/btrfs/inode.c
index 0b8ce3002cfe..a462da1a3e6a 100644
--- a/fs/btrfs/inode.c
+++ b/fs/btrfs/inode.c
@@ -6735,6 +6735,71 @@ out:
6735 return ret; 6735 return ret;
6736} 6736}
6737 6737
6738bool 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
6738static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend, 6803static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
6739 struct extent_state **cached_state, int writing) 6804 struct extent_state **cached_state, int writing)
6740{ 6805{
@@ -6759,10 +6824,9 @@ static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend,
6759 * invalidate needs to happen so that reads after a write do not 6824 * invalidate needs to happen so that reads after a write do not
6760 * get stale data. 6825 * get stale data.
6761 */ 6826 */
6762 if (!ordered && (!writing || 6827 if (!ordered &&
6763 !test_range_bit(&BTRFS_I(inode)->io_tree, 6828 (!writing ||
6764 lockstart, lockend, EXTENT_UPTODATE, 0, 6829 !btrfs_page_exists_in_range(inode, lockstart, lockend)))
6765 *cached_state)))
6766 break; 6830 break;
6767 6831
6768 unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend, 6832 unlock_extent_cached(&BTRFS_I(inode)->io_tree, lockstart, lockend,