@@ -2847,15 +2847,59 @@ endio_readpage_release_extent(struct processed_extent *processed,
processed->uptodate = uptodate;
}
-static void endio_readpage_update_page_status(struct page *page, bool uptodate)
+static void endio_readpage_update_page_status(struct page *page, bool uptodate,
+ u64 start, u64 end)
{
- if (uptodate) {
- SetPageUptodate(page);
- } else {
+ struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
+ struct btrfs_subpage *subpage;
+ int bit_start;
+ int nbits;
+ bool all_uptodate = false;
+ bool no_error = false;
+
+ ASSERT(page_offset(page) <= start &&
+ end <= page_offset(page) + PAGE_SIZE - 1);
+
+ if (!btrfs_is_subpage(fs_info)) {
+ if (uptodate) {
+ SetPageUptodate(page);
+ } else {
+ ClearPageUptodate(page);
+ SetPageError(page);
+ }
+ unlock_page(page);
+ return;
+ }
+
+ ASSERT(PagePrivate(page) && page->private);
+ subpage = (struct btrfs_subpage *)page->private;
+ bit_start = (start - page_offset(page)) >> fs_info->sectorsize_bits;
+ nbits = fs_info->nodesize >> fs_info->sectorsize_bits;
+
+ if (!uptodate) {
+ spin_lock_bh(&subpage->lock);
+ bitmap_set(subpage->error_bitmap, bit_start, nbits);
+ spin_unlock_bh(&subpage->lock);
+
ClearPageUptodate(page);
SetPageError(page);
+ return;
}
- unlock_page(page);
+
+ spin_lock_bh(&subpage->lock);
+ bitmap_set(subpage->uptodate_bitmap, bit_start, nbits);
+ bitmap_clear(subpage->error_bitmap, bit_start, nbits);
+ if (bitmap_full(subpage->uptodate_bitmap, BTRFS_SUBPAGE_BITMAP_SIZE))
+ all_uptodate = true;
+ if (bitmap_empty(subpage->error_bitmap, BTRFS_SUBPAGE_BITMAP_SIZE))
+ no_error = true;
+ spin_unlock_bh(&subpage->lock);
+
+ if (no_error)
+ ClearPageError(page);
+ if (all_uptodate)
+ SetPageUptodate(page);
+ return;
}
/*
@@ -2985,7 +3029,7 @@ static void end_bio_extent_readpage(struct bio *bio)
}
bio_offset += len;
- endio_readpage_update_page_status(page, uptodate);
+ endio_readpage_update_page_status(page, uptodate, start, end);
endio_readpage_release_extent(&processed, BTRFS_I(inode),
start, end, uptodate);
}
@@ -312,6 +312,7 @@ struct btrfs_subpage {
spinlock_t lock;
DECLARE_BITMAP(tree_block_bitmap, BTRFS_SUBPAGE_BITMAP_SIZE);
DECLARE_BITMAP(uptodate_bitmap, BTRFS_SUBPAGE_BITMAP_SIZE);
+ DECLARE_BITMAP(error_bitmap, BTRFS_SUBPAGE_BITMAP_SIZE);
};
int btrfs_attach_subpage(struct btrfs_fs_info *fs_info, struct page *page);
To handle subpage status update, add the following new tricks: - Set btrfs_subpage::error_bitmap Now if we hit an error, we set the corresponding bits in error bitmap, then call ClearPageUptodate() and SetPageError(). - Uptodate page status according to uptodate_bitmap Now we only SetPageUptodate() when the full page contains uptodate sectors. Also if we cleared all error bit during read, then we also ClearPageError() - No page unlock for metadata Since metadata doesn't utilize page locking at all, skip it for now. Signed-off-by: Qu Wenruo <wqu@suse.com> --- fs/btrfs/extent_io.c | 56 +++++++++++++++++++++++++++++++++++++++----- fs/btrfs/extent_io.h | 1 + 2 files changed, 51 insertions(+), 6 deletions(-)