summaryrefslogtreecommitdiff
path: root/drivers/md
diff options
context:
space:
mode:
authorYu Kuai <yukuai@fnnas.com>2026-01-15 01:12:34 +0800
committerYu Kuai <yukuai@fnnas.com>2026-01-26 13:11:51 +0800
commit4ffe28ed0d7ce7f2f72372cb13152ad37a43ff21 (patch)
treeb42e560fc9d8c7505bb0b4dc5f89b232f3353687 /drivers/md
parent9340a95d489ab5ff3c2d18c78283211b03a4265a (diff)
downloadlinux-next-4ffe28ed0d7ce7f2f72372cb13152ad37a43ff21.tar.gz
linux-next-4ffe28ed0d7ce7f2f72372cb13152ad37a43ff21.zip
md/raid5: make sure max_sectors is not less than io_opt
Otherwise, even if user issue IO by io_opt, such IO will be split by max_sectors before they are submitted to raid5. For consequence, full stripe IO is impossible. BTW, dm-raid5 is not affected and still have such problem. Link: https://lore.kernel.org/linux-raid/20260114171241.3043364-7-yukuai@fnnas.com Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Diffstat (limited to 'drivers/md')
-rw-r--r--drivers/md/raid5.c38
-rw-r--r--drivers/md/raid5.h1
2 files changed, 29 insertions, 10 deletions
diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
index 2fa63bd2431a..84626ad71ffb 100644
--- a/drivers/md/raid5.c
+++ b/drivers/md/raid5.c
@@ -777,14 +777,14 @@ struct stripe_request_ctx {
/* last sector in the request */
sector_t last_sector;
+ /* the request had REQ_PREFLUSH, cleared after the first stripe_head */
+ bool do_flush;
+
/*
* bitmap to track stripe sectors that have been added to stripes
* add one to account for unaligned requests
*/
- DECLARE_BITMAP(sectors_to_do, RAID5_MAX_REQ_STRIPES + 1);
-
- /* the request had REQ_PREFLUSH, cleared after the first stripe_head */
- bool do_flush;
+ unsigned long sectors_to_do[];
};
/*
@@ -6127,7 +6127,7 @@ static bool raid5_make_request(struct mddev *mddev, struct bio * bi)
bi->bi_next = NULL;
ctx = mempool_alloc(conf->ctx_pool, GFP_NOIO);
- memset(ctx, 0, sizeof(*ctx));
+ memset(ctx, 0, conf->ctx_size);
ctx->first_sector = logical_sector;
ctx->last_sector = bio_end_sector(bi);
/*
@@ -7743,6 +7743,25 @@ static int only_parity(int raid_disk, int algo, int raid_disks, int max_degraded
return 0;
}
+static int raid5_create_ctx_pool(struct r5conf *conf)
+{
+ struct stripe_request_ctx *ctx;
+ int size;
+
+ if (mddev_is_dm(conf->mddev))
+ size = BITS_TO_LONGS(RAID5_MAX_REQ_STRIPES);
+ else
+ size = BITS_TO_LONGS(
+ queue_max_hw_sectors(conf->mddev->gendisk->queue) >>
+ RAID5_STRIPE_SHIFT(conf));
+
+ conf->ctx_size = struct_size(ctx, sectors_to_do, size);
+ conf->ctx_pool = mempool_create_kmalloc_pool(NR_RAID_BIOS,
+ conf->ctx_size);
+
+ return conf->ctx_pool ? 0 : -ENOMEM;
+}
+
static int raid5_set_limits(struct mddev *mddev)
{
struct r5conf *conf = mddev->private;
@@ -7799,6 +7818,8 @@ static int raid5_set_limits(struct mddev *mddev)
* Limit the max sectors based on this.
*/
lim.max_hw_sectors = RAID5_MAX_REQ_STRIPES << RAID5_STRIPE_SHIFT(conf);
+ if ((lim.max_hw_sectors << 9) < lim.io_opt)
+ lim.max_hw_sectors = lim.io_opt >> 9;
/* No restrictions on the number of segments in the request */
lim.max_segments = USHRT_MAX;
@@ -8071,12 +8092,9 @@ static int raid5_run(struct mddev *mddev)
goto abort;
}
- conf->ctx_pool = mempool_create_kmalloc_pool(NR_RAID_BIOS,
- sizeof(struct stripe_request_ctx));
- if (!conf->ctx_pool) {
- ret = -ENOMEM;
+ ret = raid5_create_ctx_pool(conf);
+ if (ret)
goto abort;
- }
ret = log_init(conf, journal_dev, raid5_has_ppl(conf));
if (ret)
diff --git a/drivers/md/raid5.h b/drivers/md/raid5.h
index 6e3f07119fa4..ddfe65237888 100644
--- a/drivers/md/raid5.h
+++ b/drivers/md/raid5.h
@@ -692,6 +692,7 @@ struct r5conf {
struct r5pending_data *next_pending_data;
mempool_t *ctx_pool;
+ int ctx_size;
};
#if PAGE_SIZE == DEFAULT_STRIPE_SIZE