From: colyli@kernel.org
To: linux-raid@vger.kernel.org
Cc: linux-block@vger.kernel.org, Coly Li <colyli@kernel.org>,
Yu Kuai <yukuai3@huawei.com>, Xiao Ni <xni@redhat.com>,
Hannes Reinecke <hare@suse.de>, Martin Wilck <mwilck@suse.com>,
Christoph Hellwig <hch@lst.de>, Keith Busch <kbusch@kernel.org>
Subject: [RFC PATCH] md: split bio by io_opt size in md_submit_bio()
Date: Wed, 16 Jul 2025 02:02:41 +0800 [thread overview]
Message-ID: <20250715180241.29731-1-colyli@kernel.org> (raw)
From: Coly Li <colyli@kernel.org>
Currently in md_submit_bio() the incoming request bio is split by
bio_split_to_limits() which makes sure the bio won't exceed
max_hw_sectors of a specific raid level before senting into its
.make_request method.
For raid level 4/5/6 such split method might be problematic and hurt
large read/write perforamnce. Because limits.max_hw_sectors are not
always aligned to limits.io_opt size, the split bio won't be full
stripes covered on all data disks, and will introduce extra read-in I/O.
Even the bio's bi_sector is aligned to limits.io_opt size and large
enough, the resulted split bio is not size-friendly to corresponding
raid456 level.
This patch introduces bio_split_by_io_opt() to solve the above issue,
1, If the incoming bio is not limits.io_opt aligned, split the non-
aligned head part. Then the next one will be aligned.
2, If the imcoming bio is limits.io_opt aligned, and split is necessary,
then try to split a by multiple of limits.io_opt but not exceed
limits.max_hw_sectors.
Then for large bio, the sligned split part will be full-stripes covered
to all data disks, no extra read-in I/Os when rmw_level is 0. And for
rmw_level > 0 condistions, the limits.io_opt aligned bios are welcomed
for performace as well.
This RFC patch only tests on 8 disks raid5 array with 64KiB chunk size.
By this patch, 64KiB chunk size for a 8 disks raid5 array, sequential
write performance increases from 900MiB/s to 1.1GiB/s by fio bs=10M.
If fio bs=488K (exact limits.io_opt size) the peak sequential write
throughput can reach 1.51GiB/s.
(Resend to include Christoph and Keith in CC list.)
Signed-off-by: Coly Li <colyli@kernel.org>
Cc: Yu Kuai <yukuai3@huawei.com>
Cc: Xiao Ni <xni@redhat.com>
Cc: Hannes Reinecke <hare@suse.de>
Cc: Martin Wilck <mwilck@suse.com>
Cc: Christoph Hellwig <hch@lst.de>
Cc: Keith Busch <kbusch@kernel.org>
---
drivers/md/md.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 62 insertions(+), 1 deletion(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 0f03b21e66e4..363cff633af3 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -426,6 +426,67 @@ bool md_handle_request(struct mddev *mddev, struct bio *bio)
}
EXPORT_SYMBOL(md_handle_request);
+static struct bio *bio_split_by_io_opt(struct bio *bio)
+{
+ sector_t io_opt_sectors, sectors, n;
+ struct queue_limits lim;
+ struct mddev *mddev;
+ struct bio *split;
+ int level;
+
+ mddev = bio->bi_bdev->bd_disk->private_data;
+ level = mddev->level;
+ if (level == 1 || level == 10 || level == 0 || level == LEVEL_LINEAR)
+ return bio_split_to_limits(bio);
+
+ lim = mddev->gendisk->queue->limits;
+ io_opt_sectors = min3(bio_sectors(bio), lim.io_opt >> SECTOR_SHIFT,
+ lim.max_hw_sectors);
+
+ /* No need to split */
+ if (bio_sectors(bio) == io_opt_sectors)
+ return bio;
+
+ n = bio->bi_iter.bi_sector;
+ sectors = do_div(n, io_opt_sectors);
+ /* Aligned to io_opt size and no need to split for radi456 */
+ if (!sectors && (bio_sectors(bio) <= lim.max_hw_sectors))
+ return bio;
+
+ if (sectors) {
+ /**
+ * Not aligned to io_opt, split
+ * non-aligned head part.
+ */
+ sectors = io_opt_sectors - sectors;
+ } else {
+ /**
+ * Aligned to io_opt, split to the largest multiple
+ * of io_opt within max_hw_sectors, to make full
+ * stripe write/read for underlying raid456 levels.
+ */
+ n = lim.max_hw_sectors;
+ do_div(n, io_opt_sectors);
+ sectors = n * io_opt_sectors;
+ }
+
+ /* Almost won't happen */
+ if (unlikely(sectors >= bio_sectors(bio))) {
+ pr_warn("%s raid level %d: sectors %llu >= bio_sectors %u, not split\n",
+ __func__, level, sectors, bio_sectors(bio));
+ return bio;
+ }
+
+ split = bio_split(bio, sectors, GFP_NOIO,
+ &bio->bi_bdev->bd_disk->bio_split);
+ if (!split)
+ return bio;
+ split->bi_opf |= REQ_NOMERGE;
+ bio_chain(split, bio);
+ submit_bio_noacct(bio);
+ return split;
+}
+
static void md_submit_bio(struct bio *bio)
{
const int rw = bio_data_dir(bio);
@@ -441,7 +502,7 @@ static void md_submit_bio(struct bio *bio)
return;
}
- bio = bio_split_to_limits(bio);
+ bio = bio_split_by_io_opt(bio);
if (!bio)
return;
--
2.39.5
next reply other threads:[~2025-07-15 18:02 UTC|newest]
Thread overview: 19+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-07-15 18:02 colyli [this message]
2025-07-16 1:46 ` [RFC PATCH] md: split bio by io_opt size in md_submit_bio() Yu Kuai
2025-07-16 6:58 ` Yu Kuai
2025-07-16 8:50 ` Coly Li
2025-07-16 9:30 ` Yu Kuai
2025-07-16 11:37 ` Christoph Hellwig
2025-07-16 11:39 ` Coly Li
2025-07-16 11:41 ` Christoph Hellwig
2025-07-16 11:44 ` Coly Li
2025-07-16 11:45 ` Christoph Hellwig
2025-07-16 12:10 ` Coly Li
2025-07-16 12:14 ` Christoph Hellwig
2025-07-16 12:16 ` Coly Li
2025-07-16 12:17 ` Christoph Hellwig
2025-07-16 12:23 ` Coly Li
2025-07-16 16:29 ` Yu Kuai
2025-07-17 4:52 ` Christoph Hellwig
2025-07-17 15:19 ` Coly Li
-- strict thread matches above, loose matches on Subject: below --
2025-07-15 17:59 colyli
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20250715180241.29731-1-colyli@kernel.org \
--to=colyli@kernel.org \
--cc=hare@suse.de \
--cc=hch@lst.de \
--cc=kbusch@kernel.org \
--cc=linux-block@vger.kernel.org \
--cc=linux-raid@vger.kernel.org \
--cc=mwilck@suse.com \
--cc=xni@redhat.com \
--cc=yukuai3@huawei.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.