]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
md/raid5: make sure max_sectors is not less than io_opt
authorYu Kuai <yukuai@fnnas.com>
Wed, 14 Jan 2026 17:12:34 +0000 (01:12 +0800)
committerYu Kuai <yukuai@fnnas.com>
Mon, 26 Jan 2026 05:11:51 +0000 (13:11 +0800)
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>
drivers/md/raid5.c
drivers/md/raid5.h

index 2fa63bd2431aa5b0c6718b4dc52cce8f202f5c3d..84626ad71ffb8237929a95c3d4a7e0311c476bc6 100644 (file)
@@ -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)
index 6e3f07119fa4a7a1fc6147d35403696616cbd66a..ddfe65237888cc568b673a13e7ed20beea109b7b 100644 (file)
@@ -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