For subpage metadata validation check, there are some differences:

- Read must finish in one bvec
  Since we're just reading one subpage range in one page, it should
  never be split into two bios nor two bvecs.

- How to grab the existing eb
  Instead of grabbing eb using page->private, we have to go search radix
  tree as we don't have any direct pointer at hand.

Signed-off-by: Qu Wenruo <w...@suse.com>
Reviewed-by: David Sterba <dste...@suse.com>
Signed-off-by: David Sterba <dste...@suse.com>
---
 fs/btrfs/disk-io.c | 57 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index 5473bed6a7e8..0b10577ad2bd 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -591,6 +591,59 @@ static int validate_extent_buffer(struct extent_buffer *eb)
        return ret;
 }
 
+static int validate_subpage_buffer(struct page *page, u64 start, u64 end,
+                                  int mirror)
+{
+       struct btrfs_fs_info *fs_info = btrfs_sb(page->mapping->host->i_sb);
+       struct extent_buffer *eb;
+       bool reads_done;
+       int ret = 0;
+
+       /*
+        * We don't allow bio merge for subpage metadata read, so we should
+        * only get one eb for each endio hook.
+        */
+       ASSERT(end == start + fs_info->nodesize - 1);
+       ASSERT(PagePrivate(page));
+
+       eb = find_extent_buffer(fs_info, start);
+       /*
+        * When we are reading one tree block, eb must have been inserted into
+        * the radix tree. If not, something is wrong.
+        */
+       ASSERT(eb);
+
+       reads_done = atomic_dec_and_test(&eb->io_pages);
+       /* Subpage read must finish in page read */
+       ASSERT(reads_done);
+
+       eb->read_mirror = mirror;
+       if (test_bit(EXTENT_BUFFER_READ_ERR, &eb->bflags)) {
+               ret = -EIO;
+               goto err;
+       }
+       ret = validate_extent_buffer(eb);
+       if (ret < 0)
+               goto err;
+
+       if (test_and_clear_bit(EXTENT_BUFFER_READAHEAD, &eb->bflags))
+               btree_readahead_hook(eb, ret);
+
+       set_extent_buffer_uptodate(eb);
+
+       free_extent_buffer(eb);
+       return ret;
+err:
+       /*
+        * end_bio_extent_readpage decrements io_pages in case of error,
+        * make sure it has something to decrement.
+        */
+       atomic_inc(&eb->io_pages);
+       clear_extent_buffer_uptodate(eb);
+       free_extent_buffer(eb);
+       return ret;
+}
+
 int btrfs_validate_metadata_buffer(struct btrfs_io_bio *io_bio,
                                   struct page *page, u64 start, u64 end,
                                   int mirror)
@@ -600,6 +653,10 @@ int btrfs_validate_metadata_buffer(struct btrfs_io_bio 
*io_bio,
        int reads_done;
 
        ASSERT(page->private);
+
+       if (btrfs_sb(page->mapping->host->i_sb)->sectorsize < PAGE_SIZE)
+               return validate_subpage_buffer(page, start, end, mirror);
+
        eb = (struct extent_buffer *)page->private;
 
        /*
-- 
2.30.0

Reply via email to