@@ -2791,13 +2791,36 @@ static void end_bio_extent_writepage(struct bio *bio)
}
static void
-endio_readpage_release_extent(struct extent_io_tree *tree, u64 start, u64 end,
- int uptodate)
+endio_readpage_release_extent(struct extent_io_tree *tree, struct page *page,
+ u64 start, u64 end, int uptodate)
{
struct extent_state *cached = NULL;
- if (uptodate && tree->track_uptodate)
- set_extent_uptodate(tree, start, end, &cached, GFP_ATOMIC);
+ if (uptodate) {
+ u64 page_start = page_offset(page);
+ u64 page_end = page_offset(page) + PAGE_SIZE - 1;
+
+ if (tree->track_uptodate) {
+ /*
+ * The tree has EXTENT_UPTODATE bit tracking, update
+ * extent io tree, and use it to update the page if
+ * needed.
+ */
+ set_extent_uptodate(tree, start, end, &cached,
+ GFP_NOFS);
+ check_page_uptodate(tree, page);
+ } else if ((start <= page_start && end >= page_end)) {
+ /* We have covered the full page, set it uptodate */
+ SetPageUptodate(page);
+ }
+ } else if (!uptodate){
+ if (tree->track_uptodate)
+ clear_extent_uptodate(tree, start, end, &cached);
+
+ /* Any error in the page range would invalid the uptodate bit */
+ ClearPageUptodate(page);
+ SetPageError(page);
+ }
unlock_extent_cached_atomic(tree, start, end, &cached);
}
@@ -2921,15 +2944,11 @@ static void end_bio_extent_readpage(struct bio *bio)
off = offset_in_page(i_size);
if (page->index == end_index && off)
zero_user_segment(page, off, PAGE_SIZE);
- SetPageUptodate(page);
- } else {
- ClearPageUptodate(page);
- SetPageError(page);
}
- unlock_page(page);
offset += len;
- endio_readpage_release_extent(tree, start, end, uptodate);
+ endio_readpage_release_extent(tree, page, start, end, uptodate);
+ unlock_page(page);
}
btrfs_io_bio_free_csum(io_bio);
In end_bio_extent_readpage(), we set page uptodate or error according to the bio status. However that assumes all submitted read are in page size. To support case like subpage read, we should only set the whole page uptodate if all data in the page has been read from disk. This patch will integrate the page status update into endio_readpage_release_extent() for end_bio_extent_readpage(). Now in endio_readpage_release_extent() we will set the page uptodate if either: - start/end covers the full page This is the existing behavior already. - all the page range is already uptodate This adds the support for subpage read. And for the error path, we always clear the page uptodate and set the page error. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/extent_io.c | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-)