mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2026-07-22 02:17:36 -04:00
md/raid10: fix writes_pending leak on write request failures
raid10_make_request() acquires a writes_pending reference with md_write_start() before dispatching write requests. Several failure paths in raid10_write_request() complete the bio and return without reaching the normal write completion path, causing the corresponding md_write_end() to be skipped. Make raid10_write_request() return a status indicating whether the write request was successfully queued. This allows raid10_make_request() to release the writes_pending reference with md_write_end() when a write request fails. Fixes:4cf58d9529("md/raid10: Handle bio_split() errors") Fixes:c9aa889b03("md: raid10 add nowait support") Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com> Link: https://patch.msgid.link/20260613182810.1317258-3-abd.masalkhi@gmail.com Signed-off-by: Yu Kuai <yukuai@fygo.io>
This commit is contained in:
committed by
Yu Kuai
parent
8e065a1602
commit
e045d6ed33
@@ -1349,7 +1349,7 @@ static void wait_blocked_dev(struct mddev *mddev, struct r10bio *r10_bio)
|
||||
}
|
||||
}
|
||||
|
||||
static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
static bool raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
struct r10bio *r10_bio)
|
||||
{
|
||||
struct r10conf *conf = mddev->private;
|
||||
@@ -1365,7 +1365,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
/* Bail out if REQ_NOWAIT is set for the bio */
|
||||
if (bio->bi_opf & REQ_NOWAIT) {
|
||||
bio_wouldblock_error(bio);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
for (;;) {
|
||||
prepare_to_wait(&conf->wait_barrier,
|
||||
@@ -1381,7 +1381,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
sectors = r10_bio->sectors;
|
||||
if (!regular_request_wait(mddev, conf, bio, sectors)) {
|
||||
free_r10bio(r10_bio);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
|
||||
if (test_bit(MD_RECOVERY_RESHAPE, &mddev->recovery) &&
|
||||
@@ -1398,7 +1398,7 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
if (bio->bi_opf & REQ_NOWAIT) {
|
||||
allow_barrier(conf);
|
||||
bio_wouldblock_error(bio);
|
||||
return;
|
||||
return false;
|
||||
}
|
||||
mddev_add_trace_msg(conf->mddev,
|
||||
"raid10 wait reshape metadata");
|
||||
@@ -1514,7 +1514,8 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
raid10_write_one_disk(mddev, r10_bio, bio, true, i);
|
||||
}
|
||||
one_write_done(r10_bio);
|
||||
return;
|
||||
return true;
|
||||
|
||||
err_handle:
|
||||
for (k = 0; k < i; k++) {
|
||||
int d = r10_bio->devs[k].devnum;
|
||||
@@ -1532,10 +1533,12 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
|
||||
}
|
||||
|
||||
raid_end_bio_io(r10_bio);
|
||||
return false;
|
||||
}
|
||||
|
||||
static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
|
||||
static bool __make_request(struct mddev *mddev, struct bio *bio, int sectors)
|
||||
{
|
||||
bool ret;
|
||||
struct r10conf *conf = mddev->private;
|
||||
struct r10bio *r10_bio;
|
||||
|
||||
@@ -1551,10 +1554,13 @@ static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
|
||||
memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) *
|
||||
conf->geo.raid_disks);
|
||||
|
||||
ret = true;
|
||||
if (bio_data_dir(bio) == READ)
|
||||
raid10_read_request(mddev, bio, r10_bio);
|
||||
else
|
||||
raid10_write_request(mddev, bio, r10_bio);
|
||||
ret = raid10_write_request(mddev, bio, r10_bio);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void raid_end_discard_bio(struct r10bio *r10bio)
|
||||
@@ -1900,7 +1906,8 @@ static bool raid10_make_request(struct mddev *mddev, struct bio *bio)
|
||||
sectors = chunk_sects -
|
||||
(bio->bi_iter.bi_sector &
|
||||
(chunk_sects - 1));
|
||||
__make_request(mddev, bio, sectors);
|
||||
if (!__make_request(mddev, bio, sectors))
|
||||
md_write_end(mddev);
|
||||
|
||||
/* In case raid10d snuck in to freeze_array */
|
||||
wake_up_barrier(conf);
|
||||
|
||||
Reference in New Issue
Block a user