diff mbox series

[4/9] btrfs: support read bios in btrfs_map_repair_bio

Message ID 20220527084320.2130831-5-hch@lst.de (mailing list archive)
State New, archived
Headers show
Series [1/9] btrfs: save the original bi_iter into btrfs_bio for buffered read | expand

Commit Message

Christoph Hellwig May 27, 2022, 8:43 a.m. UTC
Enhance btrfs_map_repair_bio to also support reading so that we have a
single function dealing with all synchronous bio I/O for the repair code.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 fs/btrfs/volumes.c | 48 ++++++++++++++++++++++++++++++++++++----------
 1 file changed, 38 insertions(+), 10 deletions(-)
diff mbox series

Patch

diff --git a/fs/btrfs/volumes.c b/fs/btrfs/volumes.c
index 515f5fccf3d17..9053b62af3607 100644
--- a/fs/btrfs/volumes.c
+++ b/fs/btrfs/volumes.c
@@ -6805,6 +6805,11 @@  blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
 	return errno_to_blk_status(ret);
 }
 
+static void btrfs_bio_end_io_sync(struct bio *bio)
+{
+	complete(bio->bi_private);
+}
+
 /*
  * This bypasses the standard btrfs submit functions deliberately, as the
  * standard behavior is to write all copies in a raid setup. Here we only want
@@ -6814,15 +6819,17 @@  blk_status_t btrfs_map_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
 int btrfs_map_repair_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
 		int mirror_num)
 {
+	enum btrfs_map_op op = btrfs_op(bio);
 	u64 logical = bio->bi_iter.bi_sector << 9;
 	u64 map_length = bio->bi_iter.bi_size;
+	bool is_raid56 = btrfs_is_parity_mirror(fs_info, logical, map_length);
 	struct btrfs_io_context *bioc = NULL;
+	unsigned int stripe_idx = 0;
 	struct btrfs_device *dev;
 	u64 sector;
 	int ret;
 
 	ASSERT(mirror_num);
-	ASSERT(bio_op(bio) == REQ_OP_WRITE);
 
 	/*
 	 * Avoid races with device replace and make sure our bioc has devices
@@ -6830,7 +6837,23 @@  int btrfs_map_repair_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
 	 * read repair operation.
 	 */
 	btrfs_bio_counter_inc_blocked(fs_info);
-	if (btrfs_is_parity_mirror(fs_info, logical, map_length)) {
+	if (is_raid56) {
+		if (op == BTRFS_MAP_READ) {
+			DECLARE_COMPLETION_ONSTACK(done);
+
+			ret = __btrfs_map_block(fs_info, op, logical,
+					&map_length, &bioc, mirror_num, 1);
+			if (ret)
+				goto out_counter_dec;
+
+			bio->bi_private = &done;
+			bio->bi_end_io = btrfs_bio_end_io_sync;
+			ret = raid56_parity_recover(bio, bioc,
+					map_length, mirror_num, 1);
+			wait_for_completion_io(&done);
+			goto out_bio_status;
+		}
+
 		/*
 		 * Note that we don't use BTRFS_MAP_WRITE because it's supposed
 		 * to update all raid stripes, but here we just want to correct
@@ -6843,19 +6866,24 @@  int btrfs_map_repair_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
 			goto out_counter_dec;
 		ASSERT(bioc->mirror_num == 1);
 	} else {
-		ret = btrfs_map_block(fs_info, BTRFS_MAP_WRITE, logical,
-				&map_length, &bioc, mirror_num);
+		ret = btrfs_map_block(fs_info, op, logical, &map_length, &bioc,
+				mirror_num);
 		if (ret)
 			goto out_counter_dec;
-		BUG_ON(mirror_num != bioc->mirror_num);
+
+		if (op == BTRFS_MAP_WRITE) {
+			ASSERT(mirror_num == bioc->mirror_num);
+			stripe_idx = bioc->mirror_num - 1;
+		}
 	}
 
-	sector = bioc->stripes[bioc->mirror_num - 1].physical >> 9;
-	dev = bioc->stripes[bioc->mirror_num - 1].dev;
+	sector = bioc->stripes[stripe_idx].physical >> 9;
+	dev = bioc->stripes[stripe_idx].dev;
 	btrfs_put_bioc(bioc);
 
 	if (!dev || !dev->bdev ||
-	    !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state)) {
+	    (op == BTRFS_MAP_WRITE &&
+	     !test_bit(BTRFS_DEV_STATE_WRITEABLE, &dev->dev_state))) {
 		ret = -EIO;
 		goto out_counter_dec;
 	}
@@ -6865,9 +6893,9 @@  int btrfs_map_repair_bio(struct btrfs_fs_info *fs_info, struct bio *bio,
 
 	btrfsic_check_bio(bio);
 	submit_bio_wait(bio);
-
+out_bio_status:
 	ret = blk_status_to_errno(bio->bi_status);
-	if (ret)
+	if (ret && op == BTRFS_MAP_WRITE)
 		btrfs_dev_stat_inc_and_print(dev, BTRFS_DEV_STAT_WRITE_ERRS);
 out_counter_dec:
 	btrfs_bio_counter_dec(fs_info);