diff mbox series

[v3,40/49] btrfs: disk-io: support subpage metadata csum calculation at write time

Message ID 20200930015539.48867-41-wqu@suse.com
State New, archived
Headers show
Series btrfs: add partial rw support for subpage sector size | expand

Commit Message

Qu Wenruo Sept. 30, 2020, 1:55 a.m. UTC
Add a new helper, csum_dirty_subpage_buffers(), to iterate through all
possible extent buffers in one bvec.

Also extract the code to calculate csum for one extent buffer into
csum_one_extent_buffer(), so that both the existing csum_dirty_buffer()
and the new csum_dirty_subpage_buffers() can reuse the same routine.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/disk-io.c | 103 ++++++++++++++++++++++++++++++++++-----------
 1 file changed, 79 insertions(+), 24 deletions(-)
diff mbox series

Patch

diff --git a/fs/btrfs/disk-io.c b/fs/btrfs/disk-io.c
index d31999978821..9aa68e2344e1 100644
--- a/fs/btrfs/disk-io.c
+++ b/fs/btrfs/disk-io.c
@@ -490,35 +490,13 @@  static int btree_read_extent_buffer_pages(struct extent_buffer *eb,
 	return ret;
 }
 
-/*
- * checksum a dirty tree block before IO.  This has extra checks to make sure
- * we only fill in the checksum field in the first page of a multi-page block
- */
-
-static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct bio_vec *bvec)
+static int csum_one_extent_buffer(struct extent_buffer *eb)
 {
-	struct extent_buffer *eb;
-	struct page *page = bvec->bv_page;
-	u64 start = page_offset(page);
-	u64 found_start;
+	struct btrfs_fs_info *fs_info = eb->fs_info;
 	u8 result[BTRFS_CSUM_SIZE];
 	u16 csum_size = btrfs_super_csum_size(fs_info->super_copy);
 	int ret;
 
-	eb = (struct extent_buffer *)page->private;
-	if (page != eb->pages[0])
-		return 0;
-
-	found_start = btrfs_header_bytenr(eb);
-	/*
-	 * Please do not consolidate these warnings into a single if.
-	 * It is useful to know what went wrong.
-	 */
-	if (WARN_ON(found_start != start))
-		return -EUCLEAN;
-	if (WARN_ON(!PageUptodate(page)))
-		return -EUCLEAN;
-
 	ASSERT(memcmp_extent_buffer(eb, fs_info->fs_devices->metadata_uuid,
 				    offsetof(struct btrfs_header, fsid),
 				    BTRFS_FSID_SIZE) == 0);
@@ -543,6 +521,83 @@  static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct bio_vec *bvec
 	return 0;
 }
 
+/*
+ * Do all the csum calculation and extra sanity checks on all extent
+ * buffers in the bvec.
+ */
+static int csum_dirty_subpage_buffers(struct btrfs_fs_info *fs_info,
+				      struct bio_vec *bvec)
+{
+	struct page *page = bvec->bv_page;
+	u64 page_start = page_offset(page);
+	u64 start = page_start + bvec->bv_offset;
+	u64 end = start + bvec->bv_len - 1;
+	u64 cur = start;
+	int ret = 0;
+
+	while (cur <= end) {
+		struct extent_io_tree *io_tree = info_to_btree_io_tree(fs_info);
+		struct extent_buffer *eb;
+
+		ret = btrfs_find_first_subpage_eb(fs_info, &eb, cur, end, 0);
+		if (ret > 0) {
+			ret = 0;
+			break;
+		}
+
+		/*
+		 * Here we can't use PageUptodate() to check the status.
+		 * As one page is uptodate only when all its extent buffers
+		 * are uptodate, and no holes between them.
+		 * So here we use EXTENT_UPTODATE bit to make sure the exntent
+		 * buffer is uptodate.
+		 */
+		if (WARN_ON(test_range_bit(io_tree, eb->start,
+				eb->start + eb->len - 1, EXTENT_UPTODATE, 1,
+				NULL) == 0))
+			return -EUCLEAN;
+		if (WARN_ON(cur != btrfs_header_bytenr(eb)))
+			return -EUCLEAN;
+
+		ret = csum_one_extent_buffer(eb);
+		if (ret < 0)
+			return ret;
+		cur = eb->start + eb->len;
+	}
+	return ret;
+}
+
+/*
+ * checksum a dirty tree block before IO.  This has extra checks to make sure
+ * we only fill in the checksum field in the first page of a multi-page block
+ */
+static int csum_dirty_buffer(struct btrfs_fs_info *fs_info, struct bio_vec *bvec)
+{
+	struct extent_buffer *eb;
+	struct page *page = bvec->bv_page;
+	u64 start = page_offset(page) + bvec->bv_offset;
+	u64 found_start;
+
+	if (btrfs_is_subpage(fs_info))
+		return csum_dirty_subpage_buffers(fs_info, bvec);
+
+	eb = (struct extent_buffer *)page->private;
+	if (page != eb->pages[0])
+		return 0;
+
+	found_start = btrfs_header_bytenr(eb);
+	/*
+	 * Please do not consolidate these warnings into a single if.
+	 * It is useful to know what went wrong.
+	 */
+	if (WARN_ON(found_start != start))
+		return -EUCLEAN;
+	if (WARN_ON(!PageUptodate(page)))
+		return -EUCLEAN;
+
+	return csum_one_extent_buffer(eb);
+}
+
 static int check_tree_block_fsid(struct extent_buffer *eb)
 {
 	struct btrfs_fs_info *fs_info = eb->fs_info;