Commit 62ce0782 authored by Li Nan's avatar Li Nan Committed by Song Liu
Browse files

md: ensure child flush IO does not affect origin bio->bi_status



When a flush is issued to an RAID array, a child flush IO is created and
issued for each member disk in the RAID array. Since commit b75197e8
("md: Remove flush handling"), each child flush IO has been chained with
the original bio. As a result, the failure of any child IO could modify
the bi_status of the original bio, potentially impacting the upper-layer
filesystem.

Fix the issue by preventing child flush IO from altering the original
bio->bi_status as before. However, this design introduces a known
issue: in the event of a power failure, if a flush IO on a member
disk fails, the upper layers may not be informed. This issue is not easy
to fix and will not be addressed for the time being in this issue.

Fixes: b75197e8 ("md: Remove flush handling")
Signed-off-by: default avatarLi Nan <linan122@huawei.com>
Reviewed-by: default avatarYu Kuai <yukuai3@huawei.com>
Link: https://lore.kernel.org/r/20240919063048.2887579-1-linan666@huaweicloud.com


Signed-off-by: default avatarSong Liu <song@kernel.org>
parent 42aafd8b
Loading
Loading
Loading
Loading
+23 −1
Original line number Diff line number Diff line
@@ -546,6 +546,26 @@ static int mddev_set_closing_and_sync_blockdev(struct mddev *mddev, int opener_n
	return 0;
}

/*
 * The only difference from bio_chain_endio() is that the current
 * bi_status of bio does not affect the bi_status of parent.
 */
static void md_end_flush(struct bio *bio)
{
	struct bio *parent = bio->bi_private;

	/*
	 * If any flush io error before the power failure,
	 * disk data may be lost.
	 */
	if (bio->bi_status)
		pr_err("md: %pg flush io error %d\n", bio->bi_bdev,
			blk_status_to_errno(bio->bi_status));

	bio_put(bio);
	bio_endio(parent);
}

bool md_flush_request(struct mddev *mddev, struct bio *bio)
{
	struct md_rdev *rdev;
@@ -565,7 +585,9 @@ bool md_flush_request(struct mddev *mddev, struct bio *bio)
		new = bio_alloc_bioset(rdev->bdev, 0,
				       REQ_OP_WRITE | REQ_PREFLUSH, GFP_NOIO,
				       &mddev->bio_set);
		bio_chain(new, bio);
		new->bi_private = bio;
		new->bi_end_io = md_end_flush;
		bio_inc_remaining(bio);
		submit_bio(new);
	}