diff options
author | Alex Gartrell <agartrell@fb.com> | 2014-05-20 16:07:56 -0400 |
---|---|---|
committer | Chris Mason <clm@fb.com> | 2014-06-09 20:20:57 -0400 |
commit | fc4adbff823f76577ece26dcb88bf6f8392dbd43 (patch) | |
tree | d3708c9b2f6e3023a7da4452d90f65e99a007213 /fs | |
parent | 0e378df15cd87f540f1ba9503e4aa039e1c72741 (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.h | 2 | ||||
-rw-r--r-- | fs/btrfs/file.c | 4 | ||||
-rw-r--r-- | fs/btrfs/inode.c | 72 |
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 | ||
287 | bool 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 | ||
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 | static int lock_extent_direct(struct inode *inode, u64 lockstart, u64 lockend, | 6803 | static 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, |