diff mbox series

[08/13] btrfs: allow btrfs read repair to submit writes in asynchronous mode

Message ID ad68ea136896b9ceb6dfed3b42764746e9c0357a.1651559986.git.wqu@suse.com (mailing list archive)
State New, archived
Headers show
Series btrfs: make read repair work in synchronous mode | expand

Commit Message

Qu Wenruo May 3, 2022, 6:49 a.m. UTC
Currently if we want to submit write for read time repair, we call
btrfs_repair_io_failure(), which will submit the bio and wait for it.

But for our newer btrfs_read_repair infrastructure , we want to submit
write bios and only wait for all of them to finish. Just like how we
handle the read bios.

This patch will get rid of the btrfs_repair_io_failure() call, replacing
it with the same bios handling, by try merging the sector into the bio
first, and if not mergeable then submit the current bio and allocate a
new one.

And finally submit the last bio, and wait for all write bios to finish.

Signed-off-by: Qu Wenruo <wqu@suse.com>
---
 fs/btrfs/read-repair.c | 46 +++++++++++++++++++++++++++++-------------
 1 file changed, 32 insertions(+), 14 deletions(-)
diff mbox series

Patch

diff --git a/fs/btrfs/read-repair.c b/fs/btrfs/read-repair.c
index 3169f01e961b..aecdc4ee54ba 100644
--- a/fs/btrfs/read-repair.c
+++ b/fs/btrfs/read-repair.c
@@ -119,7 +119,6 @@  static void read_repair_submit_bio(struct btrfs_read_repair_ctrl *ctrl,
 	struct btrfs_fs_info *fs_info = btrfs_sb(ctrl->inode->i_sb);
 	blk_status_t ret;
 
-	ASSERT(bio_op(&rbio->bio) == REQ_OP_READ);
 	ASSERT(rbio->bio.bi_private == ctrl);
 	ASSERT(rbio->bio.bi_end_io == read_repair_end_bio);
 	ASSERT(rbio->logical >= ctrl->logical &&
@@ -140,13 +139,22 @@  static void read_repair_submit_bio(struct btrfs_read_repair_ctrl *ctrl,
 /* Add a sector into the read repair bios list for later submission */
 static void read_repair_bio_add_sector(struct btrfs_read_repair_ctrl *ctrl,
 				       struct page *page, unsigned int pgoff,
-				       int sector_nr, int mirror)
+				       int sector_nr, int mirror,
+				       unsigned int opf)
 {
 	struct btrfs_fs_info *fs_info = btrfs_sb(ctrl->inode->i_sb);
 	struct btrfs_read_repair_bio *rbio;
 	struct bio *bio;
 	int ret;
 
+	ASSERT(opf == REQ_OP_WRITE || opf == REQ_OP_READ);
+
+	/* For write, we need to handle zoned case first */
+	if (opf == REQ_OP_WRITE) {
+		if (btrfs_repair_one_zone(fs_info, ctrl->logical))
+			return;
+	}
+
 	/* Check if the sector can be added to the last bio */
 	if (ctrl->cur_bio) {
 		bio = ctrl->cur_bio;
@@ -162,10 +170,6 @@  static void read_repair_bio_add_sector(struct btrfs_read_repair_ctrl *ctrl,
 		 * just submit it.
 		 */
 		read_repair_submit_bio(ctrl, rbio, mirror);
-		if (ret) {
-			bio->bi_status = ret;
-			bio_endio(bio);
-		}
 		ctrl->cur_bio = NULL;
 	}
 	ASSERT(ctrl->cur_bio == NULL);
@@ -176,7 +180,7 @@  static void read_repair_bio_add_sector(struct btrfs_read_repair_ctrl *ctrl,
 
 	rbio = repair_bio(bio);
 	rbio->logical = ctrl->logical + (sector_nr << fs_info->sectorsize_bits);
-	bio->bi_opf = REQ_OP_READ;
+	bio->bi_opf = opf;
 	bio->bi_iter.bi_sector = rbio->logical >> SECTOR_SHIFT;
 	bio->bi_private = ctrl;
 	bio->bi_end_io = read_repair_end_bio;
@@ -190,6 +194,15 @@  static void read_repair_bio_add_sector(struct btrfs_read_repair_ctrl *ctrl,
 	 */
 	ASSERT(ret == fs_info->sectorsize);
 	atomic_add(fs_info->sectorsize, &ctrl->io_bytes);
+
+	/* Output a meesage about we repaired a sector. */
+	btrfs_info_rl(fs_info,
+"read error corrected: root %lld ino %llu off %llu logical %llu from good mirror %d",
+		BTRFS_I(ctrl->inode)->root->root_key.objectid,
+		btrfs_ino(BTRFS_I(ctrl->inode)),
+		ctrl->file_offset + (sector_nr << fs_info->sectorsize_bits),
+		ctrl->logical + (sector_nr << fs_info->sectorsize_bits),
+		mirror);
 }
 
 static int get_prev_mirror(int cur_mirror, int num_copy)
@@ -243,11 +256,12 @@  static void read_repair_from_one_mirror(struct btrfs_read_repair_ctrl *ctrl,
 			continue;
 		/* Queue and submit bad sectors. */
 		read_repair_bio_add_sector(ctrl, bvec.bv_page, bvec.bv_offset,
-					   bit, mirror);
+					   bit, mirror, REQ_OP_READ);
 	}
 	/* Submit the last assembled bio and wait for all bios to finish. */
 	ASSERT(ctrl->cur_bio);
 	read_repair_submit_bio(ctrl, repair_bio(ctrl->cur_bio), mirror);
+	ctrl->cur_bio = NULL;
 	wait_event(ctrl->io_wait, atomic_read(&ctrl->io_bytes) == 0);
 
 	/* Now re-verify the newly read out data */
@@ -256,8 +270,6 @@  static void read_repair_from_one_mirror(struct btrfs_read_repair_ctrl *ctrl,
 		struct btrfs_inode *binode = BTRFS_I(ctrl->inode);
 		const u64 file_offset = ctrl->file_offset +
 					(bit << fs_info->sectorsize_bits);
-		const u64 logical = ctrl->logical +
-				    (bit << fs_info->sectorsize_bits);
 		struct extent_state *cached = NULL;
 		u8 *csum = NULL;
 		int ret;
@@ -288,10 +300,10 @@  static void read_repair_from_one_mirror(struct btrfs_read_repair_ctrl *ctrl,
 		 * We repaired one sector, write the correct data back to the bad
 		 * mirror.
 		 */
-		btrfs_repair_io_failure(fs_info, btrfs_ino(binode), file_offset,
-					sectorsize, logical, bvec.bv_page,
-					bvec.bv_offset,
-					get_prev_mirror(mirror, ctrl->num_copies));
+		read_repair_bio_add_sector(ctrl, bvec.bv_page, bvec.bv_offset,
+					bit, get_prev_mirror(mirror,
+							     ctrl->num_copies),
+					REQ_OP_WRITE);
 
 		/* Update the page status and extent locks. */
 		btrfs_end_page_read(bvec.bv_page, true, file_offset, sectorsize);
@@ -302,6 +314,12 @@  static void read_repair_from_one_mirror(struct btrfs_read_repair_ctrl *ctrl,
 				file_offset, file_offset + sectorsize - 1,
 				&cached);
 	}
+	/* Submit the last write bio from above loop and wait for them. */
+	if (ctrl->cur_bio)
+		read_repair_submit_bio(ctrl, repair_bio(ctrl->cur_bio),
+				get_prev_mirror(mirror, ctrl->num_copies));
+	ctrl->cur_bio = NULL;
+	wait_event(ctrl->io_wait, atomic_read(&ctrl->io_bytes) == 0);
 }
 
 void btrfs_read_repair_finish(struct btrfs_read_repair_ctrl *ctrl)