Linux RAID subsystem development
 help / color / mirror / Atom feed
* Re: [PATCH v5 07/12] md: support to align bio to limits
From: Christoph Hellwig @ 2026-01-19  7:27 UTC (permalink / raw)
  To: Yu Kuai; +Cc: Christoph Hellwig, linux-raid, linan122, xni, dan.carpenter
In-Reply-To: <f7ba27c9-fc7b-44d5-9ddd-2bfb370e29d3@fnnas.com>

On Mon, Jan 19, 2026 at 03:21:14PM +0800, Yu Kuai wrote:
> Hi,
> 
> 在 2026/1/19 14:47, Christoph Hellwig 写道:
> > On Sun, Jan 18, 2026 at 07:40:23PM +0800, Yu Kuai wrote:
> >> No, the chunk_sectors and io_opt are different, and align io to io_opt
> >> is not a general idea, for now this is the only requirement in mdraid.
> > The chunk size was added for (hardware) devices that require I/O split at
> > a fixed granularity for performance reasons.  Which seems to e exactly
> > what you want here.
> >
> > This has nothing to do with max_sectors.
> 
> For example, 32 disks raid5 array with chunksize=64k, currently the queue
> limits are:
> 
> chunk_sectors = 64k
> io_min = 64k
> io_opt = 64 * 31k
> max_sectors = 1M
> 
> It's correct to split I/O at 64k boundary to avoid performance issues, however
> split at 64 *31k boundary is what we want to get best bandwidth.
> 
> So, if we simply changes chunk_sectors to 64 * 31k, it will be incorrect, because
> 64k boundary is still necessary for small IO.

What do you mean with "necessary for small IO"?


^ permalink raw reply

* Re: [PATCH v5 12/12] md: fix abnormal io_opt from member disks
From: Yu Kuai @ 2026-01-19  7:24 UTC (permalink / raw)
  To: Christoph Hellwig, Coly Li
  Cc: linux-raid, linan122, xni, dan.carpenter, yukuai
In-Reply-To: <aW3TuktsyQ0ADte7@infradead.org>

Hi,

在 2026/1/19 14:48, Christoph Hellwig 写道:
> On Sat, Jan 17, 2026 at 11:28:49AM +0800, Coly Li wrote:
>>> 2026年1月16日 23:08,Christoph Hellwig <hch@infradead.org> 写道:
>>>
>>> On Thu, Jan 15, 2026 at 01:12:40AM +0800, Yu Kuai wrote:
>>>> It's reported that mtp3sas can report abnormal io_opt, for consequence,
>>>> md array will end up with abnormal io_opt as well, due to the
>>> How do you define "abnormal”?
>> E.g. a spinning hard drive connect to this HBA card reports its max_sectors as 32767 sectors.
>> This is around 16MB and too large for normal hard drive.
> Which is larger than what we'd expect for the HDD itself, where it
> should be around 1MB.  But HBAs do weird stuff, so it might actually
> be correct here.  Have you talked to the mpt3sas maintainers?

We CC them in several previous threads, however, they're not responding. :(

>
-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH v5 07/12] md: support to align bio to limits
From: Yu Kuai @ 2026-01-19  7:21 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-raid, linan122, xni, dan.carpenter, yukuai
In-Reply-To: <aW3Tc66fqSwv319o@infradead.org>

Hi,

在 2026/1/19 14:47, Christoph Hellwig 写道:
> On Sun, Jan 18, 2026 at 07:40:23PM +0800, Yu Kuai wrote:
>> No, the chunk_sectors and io_opt are different, and align io to io_opt
>> is not a general idea, for now this is the only requirement in mdraid.
> The chunk size was added for (hardware) devices that require I/O split at
> a fixed granularity for performance reasons.  Which seems to e exactly
> what you want here.
>
> This has nothing to do with max_sectors.

For example, 32 disks raid5 array with chunksize=64k, currently the queue
limits are:

chunk_sectors = 64k
io_min = 64k
io_opt = 64 * 31k
max_sectors = 1M

It's correct to split I/O at 64k boundary to avoid performance issues, however
split at 64 *31k boundary is what we want to get best bandwidth.

So, if we simply changes chunk_sectors to 64 * 31k, it will be incorrect, because
64k boundary is still necessary for small IO.

So I'm not quite sure, are you suggesting following solution?

Add a max_chunk_sectors, and in this case it'll be 64 * 31k, for I/O:

1) First check and split to chunk_sectors boundary;
2) If I/O is already aligned to chunk_sectors, then check and split to
max_chunk_sectors boundary(BTW, this is what this set trying to do);

>
-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH v5 12/12] md: fix abnormal io_opt from member disks
From: Christoph Hellwig @ 2026-01-19  6:48 UTC (permalink / raw)
  To: Coly Li
  Cc: Christoph Hellwig, Yu Kuai, linux-raid, linan122, xni,
	dan.carpenter
In-Reply-To: <BDF73A40-1E2F-425F-8D79-4C6ADCB7566D@fnnas.com>

On Sat, Jan 17, 2026 at 11:28:49AM +0800, Coly Li wrote:
> > 2026年1月16日 23:08,Christoph Hellwig <hch@infradead.org> 写道:
> > 
> > On Thu, Jan 15, 2026 at 01:12:40AM +0800, Yu Kuai wrote:
> >> It's reported that mtp3sas can report abnormal io_opt, for consequence,
> >> md array will end up with abnormal io_opt as well, due to the
> > 
> > How do you define "abnormal”?
> 
> E.g. a spinning hard drive connect to this HBA card reports its max_sectors as 32767 sectors.
> This is around 16MB and too large for normal hard drive.

Which is larger than what we'd expect for the HDD itself, where it
should be around 1MB.  But HBAs do weird stuff, so it might actually
be correct here.  Have you talked to the mpt3sas maintainers?


^ permalink raw reply

* Re: [PATCH v5 07/12] md: support to align bio to limits
From: Christoph Hellwig @ 2026-01-19  6:47 UTC (permalink / raw)
  To: Yu Kuai; +Cc: Christoph Hellwig, linux-raid, linan122, xni, dan.carpenter
In-Reply-To: <df394803-b5fe-484f-a12d-dd10645d7a04@fnnas.com>

On Sun, Jan 18, 2026 at 07:40:23PM +0800, Yu Kuai wrote:
> No, the chunk_sectors and io_opt are different, and align io to io_opt
> is not a general idea, for now this is the only requirement in mdraid.

The chunk size was added for (hardware) devices that require I/O split at
a fixed granularity for performance reasons.  Which seems to e exactly
what you want here.

This has nothing to do with max_sectors.


^ permalink raw reply

* Re: [PATCH 04/15] md/raid1: use folio for tmppage
From: Xiao Ni @ 2026-01-19  3:20 UTC (permalink / raw)
  To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
In-Reply-To: <20251217120013.2616531-5-linan666@huaweicloud.com>

On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>
> From: Li Nan <linan122@huawei.com>
>
> Convert tmppage to tmpfolio and use it throughout in raid1.
>
> Signed-off-by: Li Nan <linan122@huawei.com>
> ---
>  drivers/md/raid1.h |  2 +-
>  drivers/md/raid1.c | 18 ++++++++++--------
>  2 files changed, 11 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/md/raid1.h b/drivers/md/raid1.h
> index c98d43a7ae99..d480b3a8c2c4 100644
> --- a/drivers/md/raid1.h
> +++ b/drivers/md/raid1.h
> @@ -101,7 +101,7 @@ struct r1conf {
>         /* temporary buffer to synchronous IO when attempting to repair
>          * a read error.
>          */
> -       struct page             *tmppage;
> +       struct folio            *tmpfolio;
>
>         /* When taking over an array from a different personality, we store
>          * the new thread here until we fully activate the array.
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index 407925951299..43453f1a04f4 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -2417,8 +2417,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
>                               rdev->recovery_offset >= sect + s)) &&
>                             rdev_has_badblock(rdev, sect, s) == 0) {
>                                 atomic_inc(&rdev->nr_pending);
> -                               if (sync_page_io(rdev, sect, s<<9,
> -                                        conf->tmppage, REQ_OP_READ, false))
> +                               if (sync_folio_io(rdev, sect, s<<9, 0,
> +                                        conf->tmpfolio, REQ_OP_READ, false))
>                                         success = 1;
>                                 rdev_dec_pending(rdev, mddev);
>                                 if (success)
> @@ -2447,7 +2447,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
>                             !test_bit(Faulty, &rdev->flags)) {
>                                 atomic_inc(&rdev->nr_pending);
>                                 r1_sync_page_io(rdev, sect, s,
> -                                               conf->tmppage, REQ_OP_WRITE);
> +                                               folio_page(conf->tmpfolio, 0),
> +                                               REQ_OP_WRITE);
>                                 rdev_dec_pending(rdev, mddev);
>                         }
>                 }
> @@ -2461,7 +2462,8 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
>                             !test_bit(Faulty, &rdev->flags)) {
>                                 atomic_inc(&rdev->nr_pending);
>                                 if (r1_sync_page_io(rdev, sect, s,
> -                                               conf->tmppage, REQ_OP_READ)) {
> +                                               folio_page(conf->tmpfolio, 0),
> +                                               REQ_OP_READ)) {
>                                         atomic_add(s, &rdev->corrected_errors);
>                                         pr_info("md/raid1:%s: read error corrected (%d sectors at %llu on %pg)\n",
>                                                 mdname(mddev), s,
> @@ -3120,8 +3122,8 @@ static struct r1conf *setup_conf(struct mddev *mddev)
>         if (!conf->mirrors)
>                 goto abort;
>
> -       conf->tmppage = alloc_page(GFP_KERNEL);
> -       if (!conf->tmppage)
> +       conf->tmpfolio = folio_alloc(GFP_KERNEL, 0);
> +       if (!conf->tmpfolio)
>                 goto abort;
>
>         r1bio_size = offsetof(struct r1bio, bios[mddev->raid_disks * 2]);
> @@ -3196,7 +3198,7 @@ static struct r1conf *setup_conf(struct mddev *mddev)
>         if (conf) {
>                 mempool_destroy(conf->r1bio_pool);
>                 kfree(conf->mirrors);
> -               safe_put_page(conf->tmppage);
> +               folio_put(conf->tmpfolio);
>                 kfree(conf->nr_pending);
>                 kfree(conf->nr_waiting);
>                 kfree(conf->nr_queued);
> @@ -3310,7 +3312,7 @@ static void raid1_free(struct mddev *mddev, void *priv)
>
>         mempool_destroy(conf->r1bio_pool);
>         kfree(conf->mirrors);
> -       safe_put_page(conf->tmppage);
> +       folio_put(conf->tmpfolio);
>         kfree(conf->nr_pending);
>         kfree(conf->nr_waiting);
>         kfree(conf->nr_queued);
> --
> 2.39.2
>

Hi Nan

Same question for patch04 and patch05, tmpage is used in read io path.
From the cover letter, this patch set wants to resolve the multi pages
in sync io path. Is it better to keep them for your future patch set?

Best Regards
Xiao

Xiao


^ permalink raw reply

* Re: [RFC PATCH 5/5] md/raid1: introduce rectify action to repair badblocks
From: Zheng Qixing @ 2026-01-19  3:06 UTC (permalink / raw)
  To: Li Nan
  Cc: linux-raid, linux-kernel, yi.zhang, yangerkun, houtao1, linan122,
	song, yukuai, Zheng Qixing
In-Reply-To: <434dd5ec-1cd9-4893-feb6-7936a0e82749@huaweicloud.com>


在 2026/1/14 11:11, Li Nan 写道:
>
>
> 在 2025/12/31 15:09, Zheng Qixing 写道:
>> From: Zheng Qixing <zhengqixing@huawei.com>
>>
>> Add support for repairing known badblocks in RAID1. When disks
>> have known badblocks (shown in sysfs bad_blocks), data can be
>> read from other healthy disks in the array and written to repair
>> the badblock areas and clear it in bad_blocks.
>>
>> echo rectify > sync_action can trigger this action.
>>
>> Signed-off-by: Zheng Qixing <zhengqixing@huawei.com>
>
>> +static void end_rectify_read(struct bio *bio)
>> +{
>> +    struct r1bio *r1_bio = get_resync_r1bio(bio);
>> +    struct r1conf *conf = r1_bio->mddev->private;
>> +    struct md_rdev *rdev;
>> +    struct bio *next_bio;
>> +    bool all_fail = true;
>> +    int i;
>> +
>> +    update_head_pos(r1_bio->read_disk, r1_bio);
>> +
>> +    if (!bio->bi_status) {
>> +        set_bit(R1BIO_Uptodate, &r1_bio->state);
>> +        goto out;
>> +    }
>> +
>> +    for (i = r1_bio->read_disk + 1; i < conf->raid_disks; i++) {
>> +        rdev = conf->mirrors[i].rdev;
>> +        if (!rdev || test_bit(Faulty, &rdev->flags))
>> +            continue;
>> +
>> +        next_bio = r1_bio->bios[i];
>> +        if (next_bio->bi_end_io == end_rectify_read) {
>> +            next_bio->bi_opf &= ~MD_FAILFAST;
>
> Why set MD_FAILFAST and clear it soon?
> And submit_rectify_read() will clear it again.


Indeed.

>
>> +static void rectify_request_write(struct mddev *mddev, struct r1bio *r1_bio)
>> +{
>> +    struct r1conf *conf = mddev->private;
>> +    struct bio *wbio = NULL;
>> +    int wcnt = 0;
>> +    int i;
>> +
>> +    if (!test_bit(R1BIO_Uptodate, &r1_bio->state)) {
>> +        submit_rectify_read(r1_bio);
>> +        return;
>> +    }
>> +
>> +    atomic_set(&r1_bio->remaining, 0);
>> +    for (i = 0; i < conf->raid_disks; i++) {
>> +        wbio = r1_bio->bios[i];
>> +        if (wbio->bi_end_io == end_rectify_write) {
>> +            atomic_inc(&r1_bio->remaining);
>> +            wcnt++;
>> +            submit_bio_noacct(wbio);
>> +        }
>> +    }
>> +
>> +    if (unlikely(!wcnt)) {
>> +        md_done_sync(r1_bio->mddev, r1_bio->sectors);
>> +        put_buf(r1_bio);
>> +    }
>
> How can 'wcnt' be 0?


Oh, I forgot to check the faulty state of rdev.😳

>
>> +}
>> +
>> +static void handle_rectify_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
>> +{
>> +    struct md_rdev *rdev;
>> +    struct bio *bio;
>> +    int i;
>> +
>> +    for (i = 0; i < conf->raid_disks; i++) {
>> +        rdev = conf->mirrors[i].rdev;
>> +        bio = r1_bio->bios[i];
>> +        if (bio->bi_end_io == NULL)
>> +            continue;
>> +
>> +        if (!bio->bi_status && bio->bi_end_io == end_rectify_write &&
>> +            test_bit(R1BIO_MadeGood, &r1_bio->state)) {
>> +            rdev_clear_badblocks(rdev, r1_bio->sector,
>> +                         r1_bio->sectors, 0);
>> +        }
>
> Reuse handle_sync_write_finished() seems better.

Good point.


Thanks,

Qixing


^ permalink raw reply

* Re: [PATCH 03/15] md: use folio for bb_folio
From: Xiao Ni @ 2026-01-19  3:03 UTC (permalink / raw)
  To: linan666; +Cc: song, yukuai, linux-raid, linux-kernel, yangerkun, yi.zhang
In-Reply-To: <20251217120013.2616531-4-linan666@huaweicloud.com>

On Wed, Dec 17, 2025 at 8:11 PM <linan666@huaweicloud.com> wrote:
>
> From: Li Nan <linan122@huawei.com>
>
> Convert bio_page to bio_folio and use it throughout.
>
> Signed-off-by: Li Nan <linan122@huawei.com>
> ---
>  drivers/md/md.h |  3 ++-
>  drivers/md/md.c | 25 +++++++++++++------------
>  2 files changed, 15 insertions(+), 13 deletions(-)
>
> diff --git a/drivers/md/md.h b/drivers/md/md.h
> index 410f8a6b75e7..aa6d9df50fd0 100644
> --- a/drivers/md/md.h
> +++ b/drivers/md/md.h
> @@ -144,7 +144,8 @@ struct md_rdev {
>         struct block_device *bdev;      /* block device handle */
>         struct file *bdev_file;         /* Handle from open for bdev */
>
> -       struct page     *sb_page, *bb_page;
> +       struct page     *sb_page;
> +       struct folio    *bb_folio;
>         int             sb_loaded;
>         __u64           sb_events;
>         sector_t        data_offset;    /* start of data in array */
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 9dfd6f8da5b8..0732bbcdb95d 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -1073,9 +1073,9 @@ void md_rdev_clear(struct md_rdev *rdev)
>                 rdev->sb_start = 0;
>                 rdev->sectors = 0;
>         }
> -       if (rdev->bb_page) {
> -               put_page(rdev->bb_page);
> -               rdev->bb_page = NULL;
> +       if (rdev->bb_folio) {
> +               folio_put(rdev->bb_folio);
> +               rdev->bb_folio = NULL;
>         }
>         badblocks_exit(&rdev->badblocks);
>  }
> @@ -1909,9 +1909,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
>
>         rdev->desc_nr = le32_to_cpu(sb->dev_number);
>
> -       if (!rdev->bb_page) {
> -               rdev->bb_page = alloc_page(GFP_KERNEL);
> -               if (!rdev->bb_page)
> +       if (!rdev->bb_folio) {
> +               rdev->bb_folio = folio_alloc(GFP_KERNEL, 0);
> +
> +               if (!rdev->bb_folio)
>                         return -ENOMEM;
>         }
>         if ((le32_to_cpu(sb->feature_map) & MD_FEATURE_BAD_BLOCKS) &&
> @@ -1930,10 +1931,10 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
>                 if (offset == 0)
>                         return -EINVAL;
>                 bb_sector = (long long)offset;
> -               if (!sync_page_io(rdev, bb_sector, sectors << 9,
> -                                 rdev->bb_page, REQ_OP_READ, true))
> +               if (!sync_folio_io(rdev, bb_sector, sectors << 9, 0,
> +                                 rdev->bb_folio, REQ_OP_READ, true))
>                         return -EIO;
> -               bbp = (__le64 *)page_address(rdev->bb_page);
> +               bbp = (__le64 *)folio_address(rdev->bb_folio);
>                 rdev->badblocks.shift = sb->bblog_shift;
>                 for (i = 0 ; i < (sectors << (9-3)) ; i++, bbp++) {
>                         u64 bb = le64_to_cpu(*bbp);
> @@ -2300,7 +2301,7 @@ static void super_1_sync(struct mddev *mddev, struct md_rdev *rdev)
>                 md_error(mddev, rdev);
>         else {
>                 struct badblocks *bb = &rdev->badblocks;
> -               __le64 *bbp = (__le64 *)page_address(rdev->bb_page);
> +               __le64 *bbp = (__le64 *)folio_address(rdev->bb_folio);
>                 u64 *p = bb->page;
>                 sb->feature_map |= cpu_to_le32(MD_FEATURE_BAD_BLOCKS);
>                 if (bb->changed) {
> @@ -2953,7 +2954,7 @@ void md_update_sb(struct mddev *mddev, int force_change)
>                                 md_write_metadata(mddev, rdev,
>                                                   rdev->badblocks.sector,
>                                                   rdev->badblocks.size << 9,
> -                                                 rdev->bb_page, 0);
> +                                                 folio_page(rdev->bb_folio, 0), 0);
>                                 rdev->badblocks.size = 0;
>                         }
>
> @@ -3809,7 +3810,7 @@ int md_rdev_init(struct md_rdev *rdev)
>         rdev->sb_events = 0;
>         rdev->last_read_error = 0;
>         rdev->sb_loaded = 0;
> -       rdev->bb_page = NULL;
> +       rdev->bb_folio = NULL;
>         atomic_set(&rdev->nr_pending, 0);
>         atomic_set(&rdev->read_errors, 0);
>         atomic_set(&rdev->corrected_errors, 0);
> --
> 2.39.2
>

Hi Nan

Bad block page is only one single page. I don't think it's necessary
to use folio here. And it uses folio_page to get the page again. Or do
you plan to replace all page apis to folio apis? Looking through all
patches, sync_page_io is not removed. In patch02, it says sync_page_io
will be removed. So maybe it's better to switch bb_page to bb_folio in
your second patch set? And this patch set only focuses on replacing
sync pages with folio. It's my 2 cents point. If you think it's better
to change the bad block page here, I'm still ok.

Best Regards
Xiao


^ permalink raw reply

* Re: [RFC PATCH 5/5] md/raid1: introduce rectify action to repair badblocks
From: Zheng Qixing @ 2026-01-19  2:51 UTC (permalink / raw)
  To: Li Nan
  Cc: linux-raid, linux-kernel, yi.zhang, yangerkun, houtao1, linan122,
	song, yukuai, Zheng Qixing
In-Reply-To: <905c81d3-a235-dd36-e17b-37acb8a6128b@huaweicloud.com>

Hi,

>> @@ -700,21 +738,34 @@ static enum sync_action __get_recovery_sync_action(struct mddev *mddev)
>>     static enum sync_action get_recovery_sync_action(struct mddev *mddev)
>>   {
>> +    if (test_bit(MD_RECOVERY_BADBLOCKS_RECTIFY, &mddev->recovery))
>> +        return ACTION_RECTIFY;
>>       return __get_recovery_sync_action(mddev);
>>   }
>>     static void init_recovery_position(struct mddev *mddev)
>>   {
>>       mddev->resync_min = 0;
>> +    mddev->rectify_min = 0;
>> +}
>
> As mentioned in patch 1, can we directly reuse resync_min?


To keep rectify's progress separate from check and repair, it's better to use
a dedicated variable to record it.

I'll update the other suggestions in v2.


Thanks,

Qixing


^ permalink raw reply

* Re: [PATCH v5 07/12] md: support to align bio to limits
From: Yu Kuai @ 2026-01-18 11:40 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-raid, linan122, xni, dan.carpenter, yukuai
In-Reply-To: <aWpUYD1D1n-HJR9u@infradead.org>

Hi,

在 2026/1/16 23:08, Christoph Hellwig 写道:
> On Thu, Jan 15, 2026 at 01:12:35AM +0800, Yu Kuai wrote:
>> For personalities that report optimal IO size, it indicates that users
>> can get the best IO bandwidth if they issue IO with this size. However
>> there is also an implicit condition that IO should also be aligned to the
>> optimal IO size.
>>
>> Currently, bio will only be split by limits, if bio offset is not aligned
>> to limits, then all split bio will not be aligned. This patch add a new
>> feature to align bio to limits first, and following patches will support
>> this for each personality if necessary.
> This feels a bit odd and mixes up different things as right now
> nothing in the block layer splits to the opt_io size.  If you want
> a boundary that is split on, the chunk_size limit seems to be what
> you want, and the existing code would do the work based on that.

No, the chunk_sectors and io_opt are different, and align io to io_opt
is not a general idea, for now this is the only requirement in mdraid.

Not sure if you remembered, Coly used to send a version to align IO to
io_opt separately, and we discussed and both agree align max_sectors to
io_opt and then align io to max_sectors in mdraid is better.

For now, current setting of max_sectors, and split IO to max_sectors
does not make much sense for raid0/10/456.

>
-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH v5 02/12] md: merge mddev has_superblock into mddev_flags
From: Yu Kuai @ 2026-01-18 11:30 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: linux-raid, linan122, xni, dan.carpenter, yukuai
In-Reply-To: <aWpT2N7S8l560MIP@infradead.org>

Hi,

在 2026/1/16 23:06, Christoph Hellwig 写道:
> On Thu, Jan 15, 2026 at 01:12:30AM +0800, Yu Kuai wrote:
>> There is not need to use a separate field in struct mddev, there are no
>> functional changes.
> It seems to be that right now the bitfields are persistent "features"
> while the bits are state.  This might not matter much, but it seems like
> there is some rationale behind the current version.

I don't think so, there are already flags like MD_CLOSING, MD_ARRAY_FIRST_USE
that is set only in memory for a long time now. Anyway, it'll make sense to
split feature flags and state flags later.

>
-- 
Thansk,
Kuai

^ permalink raw reply

* [PATCH] md-cluster: fix NULL pointer dereference in process_metadata_update
From: Jiasheng Jiang @ 2026-01-17 14:59 UTC (permalink / raw)
  To: Song Liu, Yu Kuai, linux-raid, linux-kernel; +Cc: Jiasheng Jiang

The function process_metadata_update() blindly dereferences the 'thread'
pointer (acquired via rcu_dereference_protected) within the wait_event()
macro.

While the code comment states "daemon thread must exist", there is a valid
race condition window during the MD array startup sequence (md_run):

1. bitmap_load() is called, which invokes md_cluster_ops->join().
2. join() starts the "cluster_recv" thread (recv_daemon).
3. At this point, recv_daemon is active and processing messages.
4. However, mddev->thread (the main MD thread) is not initialized until
   later in md_run().

If a METADATA_UPDATED message is received from a remote node during this
specific window, process_metadata_update() will be called while
mddev->thread is still NULL, leading to a kernel panic.

To fix this, we must validate the 'thread' pointer. If it is NULL, we
release the held lock (no_new_dev_lockres) and return early, safely
ignoring the update request as the array is not yet fully ready to
process it.

Signed-off-by: Jiasheng Jiang <jiashengjiangcool@gmail.com>
---
 drivers/md/md-cluster.c | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/drivers/md/md-cluster.c b/drivers/md/md-cluster.c
index 11f1e91d387d..896279988dfd 100644
--- a/drivers/md/md-cluster.c
+++ b/drivers/md/md-cluster.c
@@ -549,8 +549,13 @@ static void process_metadata_update(struct mddev *mddev, struct cluster_msg *msg
 
 	dlm_lock_sync(cinfo->no_new_dev_lockres, DLM_LOCK_CR);
 
-	/* daemaon thread must exist */
 	thread = rcu_dereference_protected(mddev->thread, true);
+	if (!thread) {
+		pr_warn("md-cluster: Received metadata update but MD thread is not ready\n");
+		dlm_unlock_sync(cinfo->no_new_dev_lockres);
+		return;
+	}
+
 	wait_event(thread->wqueue,
 		   (got_lock = mddev_trylock(mddev)) ||
 		    test_bit(MD_CLUSTER_HOLDING_MUTEX_FOR_RECVD, &cinfo->state));
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH v5 12/12] md: fix abnormal io_opt from member disks
From: Coly Li @ 2026-01-17  3:28 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Yu Kuai, linux-raid, linan122, xni, dan.carpenter
In-Reply-To: <aWpUgGsZ7yvnnkgo@infradead.org>

> 2026年1月16日 23:08,Christoph Hellwig <hch@infradead.org> 写道:
> 
> On Thu, Jan 15, 2026 at 01:12:40AM +0800, Yu Kuai wrote:
>> It's reported that mtp3sas can report abnormal io_opt, for consequence,
>> md array will end up with abnormal io_opt as well, due to the
> 
> How do you define "abnormal”?

E.g. a spinning hard drive connect to this HBA card reports its max_sectors as 32767 sectors.
This is around 16MB and too large for normal hard drive.

Coly Li

^ permalink raw reply

* Re: [PATCH v5 12/12] md: fix abnormal io_opt from member disks
From: Christoph Hellwig @ 2026-01-16 15:08 UTC (permalink / raw)
  To: Yu Kuai; +Cc: linux-raid, linan122, xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-13-yukuai@fnnas.com>

On Thu, Jan 15, 2026 at 01:12:40AM +0800, Yu Kuai wrote:
> It's reported that mtp3sas can report abnormal io_opt, for consequence,
> md array will end up with abnormal io_opt as well, due to the

How do you define "abnormal"?


^ permalink raw reply

* Re: [PATCH v5 07/12] md: support to align bio to limits
From: Christoph Hellwig @ 2026-01-16 15:08 UTC (permalink / raw)
  To: Yu Kuai; +Cc: linux-raid, linan122, xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-8-yukuai@fnnas.com>

On Thu, Jan 15, 2026 at 01:12:35AM +0800, Yu Kuai wrote:
> For personalities that report optimal IO size, it indicates that users
> can get the best IO bandwidth if they issue IO with this size. However
> there is also an implicit condition that IO should also be aligned to the
> optimal IO size.
> 
> Currently, bio will only be split by limits, if bio offset is not aligned
> to limits, then all split bio will not be aligned. This patch add a new
> feature to align bio to limits first, and following patches will support
> this for each personality if necessary.

This feels a bit odd and mixes up different things as right now
nothing in the block layer splits to the opt_io size.  If you want
a boundary that is split on, the chunk_size limit seems to be what
you want, and the existing code would do the work based on that.


^ permalink raw reply

* Re: [PATCH v5 02/12] md: merge mddev has_superblock into mddev_flags
From: Christoph Hellwig @ 2026-01-16 15:06 UTC (permalink / raw)
  To: Yu Kuai; +Cc: linux-raid, linan122, xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-3-yukuai@fnnas.com>

On Thu, Jan 15, 2026 at 01:12:30AM +0800, Yu Kuai wrote:
> There is not need to use a separate field in struct mddev, there are no
> functional changes.

It seems to be that right now the bitfields are persistent "features"
while the bits are state.  This might not matter much, but it seems like
there is some rationale behind the current version.


^ permalink raw reply

* Re: [PATCH v5 01/12] md/raid5: fix raid5_run() to return error when log_init() fails
From: Christoph Hellwig @ 2026-01-16 15:05 UTC (permalink / raw)
  To: Yu Kuai; +Cc: linux-raid, linan122, xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-2-yukuai@fnnas.com>

Looks good:

Reviewed-by: Christoph Hellwig <hch@lst.de>


^ permalink raw reply

* Re: [PATCH v6 1/2] md: Don't set MD_BROKEN for RAID1 and RAID10 when using FailFast
From: Kenta Akagi @ 2026-01-16  2:04 UTC (permalink / raw)
  To: Xiao Ni, linan666
  Cc: Kenta Akagi, linux-raid, linux-kernel, song, yukuai, shli,
	mtkaczyk
In-Reply-To: <CALTww282Kyg9ERXeSiY5Thd-O40vEXjAXsD8A2PxEsd-h-Cg3Q@mail.gmail.com>



On 2026/01/07 12:35, Xiao Ni wrote:
> On Tue, Jan 6, 2026 at 8:30 PM Kenta Akagi <k@mgml.me> wrote:
>>
>> Hi,
>> Thank you for reviewing.
>>
>> On 2026/01/06 11:57, Li Nan wrote:
>>>
>>>
>>> 在 2026/1/5 22:40, Kenta Akagi 写道:
>>>> After commit 9631abdbf406 ("md: Set MD_BROKEN for RAID1 and RAID10"),
>>>> if the error handler is called on the last rdev in RAID1 or RAID10,
>>>> the MD_BROKEN flag will be set on that mddev.
>>>> When MD_BROKEN is set, write bios to the md will result in an I/O error.
>>>>
>>>> This causes a problem when using FailFast.
>>>> The current implementation of FailFast expects the array to continue
>>>> functioning without issues even after calling md_error for the last
>>>> rdev.  Furthermore, due to the nature of its functionality, FailFast may
>>>> call md_error on all rdevs of the md. Even if retrying I/O on an rdev
>>>> would succeed, it first calls md_error before retrying.
>>>>
>>>> To fix this issue, this commit ensures that for RAID1 and RAID10, if the
>>>> last In_sync rdev has the FailFast flag set and the mddev's fail_last_dev
>>>> is off, the MD_BROKEN flag will not be set on that mddev.
>>>>
>>>> This change impacts userspace. After this commit, If the rdev has the
>>>> FailFast flag, the mddev never broken even if the failing bio is not
>>>> FailFast. However, it's unlikely that any setup using FailFast expects
>>>> the array to halt when md_error is called on the last rdev.
>>>>
>>>
>>> In the current RAID design, when an IO error occurs, RAID ensures faulty
>>> data is not read via the following actions:
>>> 1. Mark the badblocks (no FailFast flag); if this fails,
>>> 2. Mark the disk as Faulty.
>>>
>>> If neither action is taken, and BROKEN is not set to prevent continued RAID
>>> use, errors on the last remaining disk will be ignored. Subsequent reads
>>> may return incorrect data. This seems like a more serious issue in my opinion.
>>
>> I agree that data inconsistency can certainly occur in this scenario.
>>
>> However, a RAID1 with only one remaining rdev can considered the same as a plain
>> disk. From that perspective, I do not believe it is the mandatory responsibility
>> of md raid to block subsequent writes nor prevent data inconsistency in this situation.
>>
>> The commit 9631abdbf406 ("md: Set MD_BROKEN for RAID1 and RAID10") that introduced
>> BROKEN for RAID1/10 also does not seem to have done so for that responsibility.
>>
>>>
>>> In scenarios with a large number of transient IO errors, is FailFast not a
>>> suitable configuration? As you mentioned: "retrying I/O on an rdev would
>>
>> It seems be right about that. Using FailFast with unstable underlayer is not good.
>> However, as md raid, which is issuer of FailFast bios,
>> I believe it is incorrect to shutdown the array due to the failure of a FailFast bio.
> 
> Hi all
> 
> I understand @Li Nan 's point now. The badblock can't be recorded in
> this situation and the last working device is not set to faulty. To be
> frank, I think consistency of data is more important. Users don't
> think it's a single disk, they must think raid1 should guarantee the
> consistency. But the write request should return an error when calling
> raid1_error for the last working device, right? So there is no
> consistency problem?

Hi all,

I understand that when md_error is issued for the last remaining rdev, 
the array should be stopped except in the failfast case, also, 
it is no longer appropriate to treat an RAID1 array that has lost 
redundancy as "just a normal single drive" [1].

I will post an PATCH v7 based on v5.

[1] commit 9631abdbf406 ("md: Set MD_BROKEN for RAID1 and RAID10")

Thanks.

> 
> hi, Kenta. I have a question too. What will you do in your environment
> after the network connection works again? Add those disks one by one
> to do recovery?
> 
> Best Regards
> Xiao
> 
>>
>> Thanks,
>> Akagi
>>
>>> succeed".
>>>
>>> --
>>> Thanks,
>>> Nan
>>>
>>>
>>
> 
> 


^ permalink raw reply

* Re: [PATCH v5 00/12] md: align bio to io_opt for better performance
From: John Stoffel @ 2026-01-15 23:38 UTC (permalink / raw)
  To: Yu Kuai; +Cc: linux-raid, linan122, xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-1-yukuai@fnnas.com>

>>>>> "Yu" == Yu Kuai <yukuai@fnnas.com> writes:

> This patchset optimizes MD RAID performance by aligning bios to the
> optimal I/O size before splitting. When I/O is aligned to io_opt,
> raid5 can perform full stripe writes without needing to read extra
> data for parity calculation, significantly improving bandwidth.

> Patch 1: Fix a bug in raid5_run() error handling
> Patches 2-4: Cleanup - merge boolean fields into mddev_flags
> Patches 5-6: Preparation - use mempool for stripe_request_ctx and
>              ensure max_sectors >= io_opt
> Patches 7-8: Core - add bio alignment infrastructure
> Patches 9-11: Enable bio alignment for raid5, raid10, and raid0
> Patch 12: Fix abnormal io_opt from member disks

> Performance improvement on 32-disk raid5 with 64kb chunk:
>   dd if=/dev/zero of=/dev/md0 bs=100M oflag=direct
>   Before: 782 MB/s
>   After:  1.1 GB/s

My only comment is how is performance impacted at other block sizes?
And smaller RAID5 arrays?  What about RAID6?  

And more importantly, are random disk writes impacted?  It's great
that you have gotten streaming direct writes faster, but have other
writes slowed down for the common case?




> Changes in v5:
> - Add patch 1 to fix raid5_run() returning success when log_init() fails
> - Patch 12: Fix stale commit message (remove mention of MD_STACK_IO_OPT flag)

> Changes in v4:
> - Patch 12: Simplify by checking rdev_is_mddev() first, remove
>   MD_STACK_IO_OPT flag

> Changes in v3:
> - Patch 5: Remove unnecessary NULL check before mempool_destroy()
> - Patch 7: Use sector_div() instead of roundup()/rounddown() to fix
>   64-bit division issue on 32-bit platforms

> Changes in v2:
> - Fix mempool in patch 5
> - Add prep cleanup patches, 2-4
> - Add patch 12 to fix abnormal io_opt
> - Add Link tags to patches

> Yu Kuai (12):
>   md/raid5: fix raid5_run() to return error when log_init() fails
>   md: merge mddev has_superblock into mddev_flags
>   md: merge mddev faillast_dev into mddev_flags
>   md: merge mddev serialize_policy into mddev_flags
>   md/raid5: use mempool to allocate stripe_request_ctx
>   md/raid5: make sure max_sectors is not less than io_opt
>   md: support to align bio to limits
>   md: add a helper md_config_align_limits()
>   md/raid5: align bio to io_opt
>   md/raid10: align bio to io_opt
>   md/raid0: align bio to io_opt
>   md: fix abnormal io_opt from member disks

>  drivers/md/md-bitmap.c |   4 +-
>  drivers/md/md.c        | 118 +++++++++++++++++++++++++++++++++++------
>  drivers/md/md.h        |  30 +++++++++--
>  drivers/md/raid0.c     |   6 ++-
>  drivers/md/raid1-10.c  |   5 --
>  drivers/md/raid1.c     |  13 ++---
>  drivers/md/raid10.c    |  10 ++--
>  drivers/md/raid5.c     |  95 +++++++++++++++++++++++----------
>  drivers/md/raid5.h     |   3 ++
>  9 files changed, 217 insertions(+), 67 deletions(-)

> -- 
> 2.51.0



^ permalink raw reply

* Re: [PATCH v5 01/12] md/raid5: fix raid5_run() to return error when log_init() fails
From: Xiao Ni @ 2026-01-15  2:29 UTC (permalink / raw)
  To: Yu Kuai; +Cc: linux-raid, linan122, dan.carpenter
In-Reply-To: <20260114171241.3043364-2-yukuai@fnnas.com>

On Thu, Jan 15, 2026 at 1:17 AM Yu Kuai <yukuai@fnnas.com> wrote:
>
> Since commit f63f17350e53 ("md/raid5: use the atomic queue limit
> update APIs"), the abort path in raid5_run() returns 'ret' instead of
> -EIO. However, if log_init() fails, 'ret' is still 0 from the previous
> successful call, causing raid5_run() to return success despite the
> failure.
>
> Fix this by capturing the return value from log_init().
>
> Fixes: f63f17350e53 ("md/raid5: use the atomic queue limit update APIs")
> Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
> Closes: https://lore.kernel.org/r/202601130531.LGfcZsa4-lkp@intel.com/
> Signed-off-by: Yu Kuai <yukuai3@huawei.com>
> ---
>  drivers/md/raid5.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index e57ce3295292..39bec4d199a1 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
> @@ -8055,7 +8055,8 @@ static int raid5_run(struct mddev *mddev)
>                         goto abort;
>         }
>
> -       if (log_init(conf, journal_dev, raid5_has_ppl(conf)))
> +       ret = log_init(conf, journal_dev, raid5_has_ppl(conf));
> +       if (ret)
>                 goto abort;
>
>         return 0;
> --
> 2.51.0
>
>

Reviewed-by: Xiao Ni <xni@redhat.com>


^ permalink raw reply

* Re: [PATCH v5 01/12] md/raid5: fix raid5_run() to return error when log_init() fails
From: Li Nan @ 2026-01-15  1:28 UTC (permalink / raw)
  To: Yu Kuai, linux-raid; +Cc: xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-2-yukuai@fnnas.com>



在 2026/1/15 1:12, Yu Kuai 写道:
> Since commit f63f17350e53 ("md/raid5: use the atomic queue limit
> update APIs"), the abort path in raid5_run() returns 'ret' instead of
> -EIO. However, if log_init() fails, 'ret' is still 0 from the previous
> successful call, causing raid5_run() to return success despite the
> failure.
> 
> Fix this by capturing the return value from log_init().
> 
> Fixes: f63f17350e53 ("md/raid5: use the atomic queue limit update APIs")
> Reported-by: Dan Carpenter <dan.carpenter@linaro.org>
> Closes: https://lore.kernel.org/r/202601130531.LGfcZsa4-lkp@intel.com/
> Signed-off-by: Yu Kuai <yukuai3@huawei.com>
> ---
>   drivers/md/raid5.c | 3 ++-
>   1 file changed, 2 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/md/raid5.c b/drivers/md/raid5.c
> index e57ce3295292..39bec4d199a1 100644
> --- a/drivers/md/raid5.c
> +++ b/drivers/md/raid5.c
> @@ -8055,7 +8055,8 @@ static int raid5_run(struct mddev *mddev)
>   			goto abort;
>   	}
>   
> -	if (log_init(conf, journal_dev, raid5_has_ppl(conf)))
> +	ret = log_init(conf, journal_dev, raid5_has_ppl(conf));
> +	if (ret)
>   		goto abort;
>   
>   	return 0;

Reviewed-by: Li Nan <linan122@huawei.com>

-- 
Thanks,
Nan


^ permalink raw reply

* Fwd: [PATCH V2] md raid: fix hang when stopping arrays with metadata through dm-raid
From: Heinz Mauelshagen @ 2026-01-14 17:52 UTC (permalink / raw)
  To: linux-raid, Linux-Kernel, Song Liu
In-Reply-To: <d4bab4c8921eaecae856447131c4f4f1aa190dd3.1758631268.git.heinzm@redhat.com>

Resending, as it seems to have gotten lost.

---------- Forwarded message ---------
From: Heinz Mauelshagen <heinzm@redhat.com>
Date: Tue, Sep 23, 2025 at 2:58 PM
Subject: [PATCH V2] md raid: fix hang when stopping arrays with
metadata through dm-raid
To: <yukuai1@huaweicloud.com>, <song@kernel.org>
Cc: <linux-raid@vger.kernel.org>, <linux-kernel@vger.kernel.org>,
Heinz Mauelshagen <heinzm@redhat.com>


When using device-mapper's dm-raid target, stopping a RAID array can cause the
system to hang under specific conditions.

This occurs when:

- A dm-raid managed device tree is suspended from top to bottom
   (the top-level RAID device is suspended first, followed by its
    underlying metadata and data devices)

- The top-level RAID device is then removed

Removing the top-level device triggers a hang in the following
sequence: the dm-raid
destructor calls md_stop(), which tries to flush the write-intent
bitmap by writing
to the metadata sub-devices. However, these devices are already
suspended, making
them unable to complete the write operations and causing an indefinite block.

Fix:

- Prevent bitmap flushing when md_stop() is called from dm-raid
destructor context
  and avoid a quiescing/unquescing cycle which could also cause I/O

- Still allow write-intent bitmap flushing when called from dm-raid
suspend context

This ensures that RAID array teardown can complete successfully even when the
underlying devices are in a suspended state.

This second patch uses md_is_rdwr() to distinguish between suspend and
destructor paths as elaborated on above.

Signed-off-by: Heinz Mauelshagen <heinzm@redhat.com>
---
 drivers/md/md.c | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/drivers/md/md.c b/drivers/md/md.c
index 4e033c26fdd4..78408d2f78fc 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6541,12 +6541,14 @@ static void __md_stop_writes(struct mddev *mddev)
 {
        timer_delete_sync(&mddev->safemode_timer);

-       if (mddev->pers && mddev->pers->quiesce) {
-               mddev->pers->quiesce(mddev, 1);
-               mddev->pers->quiesce(mddev, 0);
-       }
+       if (md_is_rdwr(mddev) || !mddev_is_dm(mddev)) {
+               if (mddev->pers && mddev->pers->quiesce) {
+                       mddev->pers->quiesce(mddev, 1);
+                       mddev->pers->quiesce(mddev, 0);
+               }

-       mddev->bitmap_ops->flush(mddev);
+               mddev->bitmap_ops->flush(mddev);
+       }

        if (md_is_rdwr(mddev) &&
            ((!mddev->in_sync && !mddev_is_clustered(mddev)) ||
--
2.51.0


^ permalink raw reply related

* [PATCH v5 12/12] md: fix abnormal io_opt from member disks
From: Yu Kuai @ 2026-01-14 17:12 UTC (permalink / raw)
  To: linux-raid; +Cc: yukuai, linan122, xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-1-yukuai@fnnas.com>

It's reported that mtp3sas can report abnormal io_opt, for consequence,
md array will end up with abnormal io_opt as well, due to the
lcm_not_zero() from blk_stack_limits().

Some personalities will configure optimal IO size, and it's indicate that
users can get the best IO bandwidth if they issue IO with this size, and
we don't want io_opt to be covered by member disks with abnormal io_opt.

Fix this problem by checking if the member disk is an mdraid array. If
not, keep the io_opt configured by personalities and ignore io_opt from
member disk.

Reported-by: Filippo Giunchedi <filippo@debian.org>
Closes: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=1121006
Reported-by: Coly Li <colyli@fnnas.com>
Closes: https://lore.kernel.org/all/20250817152645.7115-1-colyli@kernel.org/
Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Reviewed-by: Li Nan <linan122@huawei.com> 
Reviewed-by: Xiao Ni <xni@redhat.com>
---
 drivers/md/md.c     | 28 +++++++++++++++++++++++++++-
 drivers/md/md.h     |  3 ++-
 drivers/md/raid1.c  |  2 +-
 drivers/md/raid10.c |  4 ++--
 4 files changed, 32 insertions(+), 5 deletions(-)

diff --git a/drivers/md/md.c b/drivers/md/md.c
index 731ec800f5cb..6c0fb09c26dc 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -6200,18 +6200,33 @@ static const struct kobj_type md_ktype = {
 
 int mdp_major = 0;
 
+static bool rdev_is_mddev(struct md_rdev *rdev)
+{
+	return rdev->bdev->bd_disk->fops == &md_fops;
+}
+
 /* stack the limit for all rdevs into lim */
 int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim,
 		unsigned int flags)
 {
 	struct md_rdev *rdev;
+	bool io_opt_configured = lim->io_opt;
 
 	rdev_for_each(rdev, mddev) {
+		unsigned int io_opt = lim->io_opt;
+
 		queue_limits_stack_bdev(lim, rdev->bdev, rdev->data_offset,
 					mddev->gendisk->disk_name);
 		if ((flags & MDDEV_STACK_INTEGRITY) &&
 		    !queue_limits_stack_integrity_bdev(lim, rdev->bdev))
 			return -EINVAL;
+
+		/*
+		 * If member disk is not mdraid array, keep the io_opt
+		 * from personality and ignore io_opt from member disk.
+		 */
+		if (!rdev_is_mddev(rdev) && io_opt_configured)
+			lim->io_opt = io_opt;
 	}
 
 	/*
@@ -6230,9 +6245,11 @@ int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim,
 EXPORT_SYMBOL_GPL(mddev_stack_rdev_limits);
 
 /* apply the extra stacking limits from a new rdev into mddev */
-int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev)
+int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev,
+			 bool io_opt_configured)
 {
 	struct queue_limits lim;
+	unsigned int io_opt;
 
 	if (mddev_is_dm(mddev))
 		return 0;
@@ -6245,6 +6262,8 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev)
 	}
 
 	lim = queue_limits_start_update(mddev->gendisk->queue);
+	io_opt = lim.io_opt;
+
 	queue_limits_stack_bdev(&lim, rdev->bdev, rdev->data_offset,
 				mddev->gendisk->disk_name);
 
@@ -6255,6 +6274,13 @@ int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev)
 		return -ENXIO;
 	}
 
+	/*
+	 * If member disk is not mdraid array, keep the io_opt from
+	 * personality and ignore io_opt from member disk.
+	 */
+	if (!rdev_is_mddev(rdev) && io_opt_configured)
+		lim.io_opt = io_opt;
+
 	return queue_limits_commit_update(mddev->gendisk->queue, &lim);
 }
 EXPORT_SYMBOL_GPL(mddev_stack_new_rdev);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index ddf989f2a139..80c527b3777d 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -1041,7 +1041,8 @@ int do_md_run(struct mddev *mddev);
 #define MDDEV_STACK_INTEGRITY	(1u << 0)
 int mddev_stack_rdev_limits(struct mddev *mddev, struct queue_limits *lim,
 		unsigned int flags);
-int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev);
+int mddev_stack_new_rdev(struct mddev *mddev, struct md_rdev *rdev,
+			 bool io_opt_configured);
 void mddev_update_io_opt(struct mddev *mddev, unsigned int nr_stripes);
 
 extern const struct block_device_operations md_fops;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 1a957dba2640..f3f3086f27fa 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1944,7 +1944,7 @@ static int raid1_add_disk(struct mddev *mddev, struct md_rdev *rdev)
 	for (mirror = first; mirror <= last; mirror++) {
 		p = conf->mirrors + mirror;
 		if (!p->rdev) {
-			err = mddev_stack_new_rdev(mddev, rdev);
+			err = mddev_stack_new_rdev(mddev, rdev, false);
 			if (err)
 				return err;
 
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 2c6b65b83724..a6edc91e7a9a 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -2139,7 +2139,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
 			continue;
 		}
 
-		err = mddev_stack_new_rdev(mddev, rdev);
+		err = mddev_stack_new_rdev(mddev, rdev, true);
 		if (err)
 			return err;
 		p->head_position = 0;
@@ -2157,7 +2157,7 @@ static int raid10_add_disk(struct mddev *mddev, struct md_rdev *rdev)
 		clear_bit(In_sync, &rdev->flags);
 		set_bit(Replacement, &rdev->flags);
 		rdev->raid_disk = repl_slot;
-		err = mddev_stack_new_rdev(mddev, rdev);
+		err = mddev_stack_new_rdev(mddev, rdev, true);
 		if (err)
 			return err;
 		conf->fullsync = 1;
-- 
2.51.0


^ permalink raw reply related

* [PATCH v5 11/12] md/raid0: align bio to io_opt
From: Yu Kuai @ 2026-01-14 17:12 UTC (permalink / raw)
  To: linux-raid; +Cc: yukuai, linan122, xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-1-yukuai@fnnas.com>

The impact is not so significant for raid0 compared to raid5, however
it's still more appropriate to issue IOs evenly to underlying disks.

Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Reviewed-by: Li Nan <linan122@huawei.com>
---
 drivers/md/raid0.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index f3814a69cd13..0ae44e3bfff2 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -29,8 +29,7 @@ module_param(default_layout, int, 0644);
 	 (1L << MD_HAS_PPL) |		\
 	 (1L << MD_HAS_MULTIPLE_PPLS) |	\
 	 (1L << MD_FAILLAST_DEV) |	\
-	 (1L << MD_SERIALIZE_POLICY) |	\
-	 (1L << MD_BIO_ALIGN))
+	 (1L << MD_SERIALIZE_POLICY))
 
 /*
  * inform the user of the raid configuration
@@ -398,6 +397,8 @@ static int raid0_set_limits(struct mddev *mddev)
 	err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY);
 	if (err)
 		return err;
+
+	md_config_align_limits(mddev, &lim);
 	return queue_limits_set(mddev->gendisk->queue, &lim);
 }
 
-- 
2.51.0


^ permalink raw reply related

* [PATCH v5 10/12] md/raid10: align bio to io_opt
From: Yu Kuai @ 2026-01-14 17:12 UTC (permalink / raw)
  To: linux-raid; +Cc: yukuai, linan122, xni, dan.carpenter
In-Reply-To: <20260114171241.3043364-1-yukuai@fnnas.com>

The impact is not so significant for raid10 compared to raid5, however
it's still more appropriate to issue IOs evenly to underlying disks.

Signed-off-by: Yu Kuai <yukuai@fnnas.com>
Reviewed-by: Li Nan <linan122@huawei.com>
---
 drivers/md/raid10.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 09328e032f14..2c6b65b83724 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -4008,6 +4008,8 @@ static int raid10_set_queue_limits(struct mddev *mddev)
 	err = mddev_stack_rdev_limits(mddev, &lim, MDDEV_STACK_INTEGRITY);
 	if (err)
 		return err;
+
+	md_config_align_limits(mddev, &lim);
 	return queue_limits_set(mddev->gendisk->queue, &lim);
 }
 
-- 
2.51.0


^ permalink raw reply related


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox