diff options
author | Yu Kuai <yukuai3@huawei.com> | 2023-03-10 15:38:53 +0800 |
---|---|---|
committer | Song Liu <song@kernel.org> | 2023-04-14 00:41:40 -0700 |
commit | 26208a7cffd0c7cbf14237ccd20c7270b3ffeb7e (patch) | |
tree | 1e9287682c03065f3f293a66a25eb2220c7a4fb7 /drivers/md | |
parent | 9fdfe6d45be2fe1bd07678bfc453e6a627c08223 (diff) | |
download | linux-stable-26208a7cffd0c7cbf14237ccd20c7270b3ffeb7e.tar.gz linux-stable-26208a7cffd0c7cbf14237ccd20c7270b3ffeb7e.tar.bz2 linux-stable-26208a7cffd0c7cbf14237ccd20c7270b3ffeb7e.zip |
md/raid10: fix leak of 'r10bio->remaining' for recovery
raid10_sync_request() will add 'r10bio->remaining' for both rdev and
replacement rdev. However, if the read io fails, recovery_request_write()
returns without issuing the write io, in this case, end_sync_request()
is only called once and 'remaining' is leaked, cause an io hang.
Fix the problem by decreasing 'remaining' according to if 'bio' and
'repl_bio' is valid.
Fixes: 24afd80d99f8 ("md/raid10: handle recovery of replacement devices.")
Signed-off-by: Yu Kuai <yukuai3@huawei.com>
Signed-off-by: Song Liu <song@kernel.org>
Link: https://lore.kernel.org/r/20230310073855.1337560-5-yukuai1@huaweicloud.com
Diffstat (limited to 'drivers/md')
-rw-r--r-- | drivers/md/raid10.c | 23 |
1 files changed, 13 insertions, 10 deletions
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c index f82a930f7be0..82f2277d7bcf 100644 --- a/drivers/md/raid10.c +++ b/drivers/md/raid10.c @@ -2615,11 +2615,22 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio) { struct r10conf *conf = mddev->private; int d; - struct bio *wbio, *wbio2; + struct bio *wbio = r10_bio->devs[1].bio; + struct bio *wbio2 = r10_bio->devs[1].repl_bio; + + /* Need to test wbio2->bi_end_io before we call + * submit_bio_noacct as if the former is NULL, + * the latter is free to free wbio2. + */ + if (wbio2 && !wbio2->bi_end_io) + wbio2 = NULL; if (!test_bit(R10BIO_Uptodate, &r10_bio->state)) { fix_recovery_read_error(r10_bio); - end_sync_request(r10_bio); + if (wbio->bi_end_io) + end_sync_request(r10_bio); + if (wbio2) + end_sync_request(r10_bio); return; } @@ -2628,14 +2639,6 @@ static void recovery_request_write(struct mddev *mddev, struct r10bio *r10_bio) * and submit the write request */ d = r10_bio->devs[1].devnum; - wbio = r10_bio->devs[1].bio; - wbio2 = r10_bio->devs[1].repl_bio; - /* Need to test wbio2->bi_end_io before we call - * submit_bio_noacct as if the former is NULL, - * the latter is free to free wbio2. - */ - if (wbio2 && !wbio2->bi_end_io) - wbio2 = NULL; if (wbio->bi_end_io) { atomic_inc(&conf->mirrors[d].rdev->nr_pending); md_sync_acct(conf->mirrors[d].rdev->bdev, bio_sectors(wbio)); |