Skip to content

Commit 62ce078

Browse files
Li Nanliu-song-6
authored andcommitted
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 b75197e ("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: b75197e ("md: Remove flush handling") Signed-off-by: Li Nan <linan122@huawei.com> Reviewed-by: Yu Kuai <yukuai3@huawei.com> Link: https://lore.kernel.org/r/20240919063048.2887579-1-linan666@huaweicloud.com Signed-off-by: Song Liu <song@kernel.org>
1 parent 42aafd8 commit 62ce078

File tree

1 file changed

+23
-1
lines changed

1 file changed

+23
-1
lines changed

drivers/md/md.c

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,26 @@ static int mddev_set_closing_and_sync_blockdev(struct mddev *mddev, int opener_n
546546
return 0;
547547
}
548548

549+
/*
550+
* The only difference from bio_chain_endio() is that the current
551+
* bi_status of bio does not affect the bi_status of parent.
552+
*/
553+
static void md_end_flush(struct bio *bio)
554+
{
555+
struct bio *parent = bio->bi_private;
556+
557+
/*
558+
* If any flush io error before the power failure,
559+
* disk data may be lost.
560+
*/
561+
if (bio->bi_status)
562+
pr_err("md: %pg flush io error %d\n", bio->bi_bdev,
563+
blk_status_to_errno(bio->bi_status));
564+
565+
bio_put(bio);
566+
bio_endio(parent);
567+
}
568+
549569
bool md_flush_request(struct mddev *mddev, struct bio *bio)
550570
{
551571
struct md_rdev *rdev;
@@ -565,7 +585,9 @@ bool md_flush_request(struct mddev *mddev, struct bio *bio)
565585
new = bio_alloc_bioset(rdev->bdev, 0,
566586
REQ_OP_WRITE | REQ_PREFLUSH, GFP_NOIO,
567587
&mddev->bio_set);
568-
bio_chain(new, bio);
588+
new->bi_private = bio;
589+
new->bi_end_io = md_end_flush;
590+
bio_inc_remaining(bio);
569591
submit_bio(new);
570592
}
571593

0 commit comments

Comments
 (0)