diff mbox series

[10/14] btrfs: extent_io: make endio_readpage_update_page_status() to handle subpage case

Message ID 20201118085319.56668-11-wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: add read-only support for subpage sector size | expand

Commit Message

Qu Wenruo Nov. 18, 2020, 8:53 a.m. UTC
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(-)
diff mbox series

Patch

diff --git a/fs/btrfs/extent_io.c b/fs/btrfs/extent_io.c
index 35aee688d6c1..236de0b6b20a 100644
--- a/fs/btrfs/extent_io.c
+++ b/fs/btrfs/extent_io.c
@@ -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);
 	}
diff --git a/fs/btrfs/extent_io.h b/fs/btrfs/extent_io.h
index 11e1e013cb8c..b4d0e39ebceb 100644
--- a/fs/btrfs/extent_io.h
+++ b/fs/btrfs/extent_io.h
@@ -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);