]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
md/raid10: fix writes_pending and barrier reference leaks on discard failures
authorAbd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Sat, 13 Jun 2026 18:28:09 +0000 (18:28 +0000)
committerYu Kuai <yukuai@fygo.io>
Sat, 20 Jun 2026 18:14:44 +0000 (02:14 +0800)
raid10_make_request() acquires a writes_pending reference with
md_write_start() before calling raid10_handle_discard(). Several failure
paths in raid10_handle_discard() complete the bio and return without
releasing the corresponding reference, causing md_write_end() to be
skipped.

Call md_write_end() before returning from these failure paths to keep
writes_pending accounting balanced.

Additionally, discard split allocation failures can occur after
wait_barrier() succeeds. Those paths return without calling
allow_barrier(), leaking the associated barrier reference.

Release the barrier before returning from those paths.

Fixes: c9aa889b035f ("md: raid10 add nowait support")
Fixes: 4cf58d952909 ("md/raid10: Handle bio_split() errors")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
Link: https://patch.msgid.link/20260613182810.1317258-4-abd.masalkhi@gmail.com
Signed-off-by: Yu Kuai <yukuai@fygo.io>
drivers/md/raid10.c

index c123a8c76ddcdddc90ccaafb07197538b997168c..0a3cfdd3f5df800af05d5cda8f570ee8c6ca0039 100644 (file)
@@ -1639,6 +1639,7 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
 
        if (!wait_barrier(conf, bio->bi_opf & REQ_NOWAIT)) {
                bio_wouldblock_error(bio);
+               md_write_end(mddev);
                return 0;
        }
 
@@ -1681,6 +1682,8 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
                if (IS_ERR(split)) {
                        bio->bi_status = errno_to_blk_status(PTR_ERR(split));
                        bio_endio(bio);
+                       md_write_end(mddev);
+                       allow_barrier(conf);
                        return 0;
                }
 
@@ -1698,6 +1701,8 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
                if (IS_ERR(split)) {
                        bio->bi_status = errno_to_blk_status(PTR_ERR(split));
                        bio_endio(bio);
+                       md_write_end(mddev);
+                       allow_barrier(conf);
                        return 0;
                }