Linux RAID subsystem development
 help / color / mirror / Atom feed
* cleanup the RAID5 XOR library v2
From: Christoph Hellwig @ 2026-03-11  7:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Richard Henderson, Matt Turner, Magnus Lindholm, Russell King,
	Catalin Marinas, Will Deacon, Huacai Chen, WANG Xuerui,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	David S. Miller, Andreas Larsson, Richard Weinberger,
	Anton Ivanov, Johannes Berg, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, Herbert Xu,
	Dan Williams, Chris Mason, David Sterba, Arnd Bergmann, Song Liu,
	Yu Kuai, Li Nan, Theodore Ts'o, Jason A. Donenfeld,
	linux-alpha, linux-kernel, linux-arm-kernel, loongarch,
	linuxppc-dev, linux-riscv, linux-s390, sparclinux, linux-um,
	linux-crypto, linux-btrfs, linux-arch, linux-raid

Hi all,

the XOR library used for the RAID5 parity is a bit of a mess right now.
The main file sits in crypto/ despite not being cryptography and not
using the crypto API, with the generic implementations sitting in
include/asm-generic and the arch implementations sitting in an asm/
header in theory.  The latter doesn't work for many cases, so
architectures often build the code directly into the core kernel, or
create another module for the architecture code.

Changes this to a single module in lib/ that also contains the
architecture optimizations, similar to the library work Eric Biggers
has done for the CRC and crypto libraries later.  After that it changes
to better calling conventions that allow for smarter architecture
implementations (although none is contained here yet), and uses
static_call to avoid indirection function call overhead.

A git tree is also available here:

    git://git.infradead.org/users/hch/misc.git xor-improvements

Gitweb:

    https://git.infradead.org/?p=users/hch/misc.git;a=shortlog;h=refs/heads/xor-improvements

Changes since v1:
 - use lockdep_assert_preemption_enabled()
 - improve the commit message for the initial um xor.h cleanup
 - further clean up the um arch specific header
 - add SPDX identifier to the new build system files
 - use bool for xor_forced
 - fix an incorrect printk level conversion from warn to info
 - include xor_impl.h in xor-neon.c
 - remove unused exports for riscv
 - simply move the sparc code instead of splititng it
 - simplify the makefile for the x86-specific implementations
 - remove stray references to xor_blocks in crypto/async_tx
 - rework __DO_XOR_BLOCKS to avoid (theoretical) out of bounds references
 - improve the kerneldoc API documentration for xor_gen()
 - spell the name of the srcs argument to xor_gen correctly in xor.h
 - add a kunit test, and a new random helper for it.

Diffstat:
 arch/arm64/include/asm/xor.h              |   73 --
 arch/loongarch/include/asm/xor.h          |   68 --
 arch/loongarch/include/asm/xor_simd.h     |   34 -
 arch/loongarch/lib/xor_simd_glue.c        |   72 --
 arch/powerpc/include/asm/xor.h            |   47 -
 arch/powerpc/include/asm/xor_altivec.h    |   22 
 arch/powerpc/lib/xor_vmx.h                |   22 
 arch/powerpc/lib/xor_vmx_glue.c           |   63 --
 arch/riscv/include/asm/xor.h              |   68 --
 arch/s390/include/asm/xor.h               |   21 
 arch/sparc/include/asm/xor.h              |    9 
 arch/um/include/asm/xor.h                 |   24 
 arch/x86/include/asm/xor_64.h             |   28 -
 b/arch/alpha/Kconfig                      |    1 
 b/arch/arm/Kconfig                        |    1 
 b/arch/arm/lib/Makefile                   |    5 
 b/arch/arm64/Kconfig                      |    1 
 b/arch/arm64/lib/Makefile                 |    6 
 b/arch/loongarch/Kconfig                  |    1 
 b/arch/loongarch/lib/Makefile             |    2 
 b/arch/powerpc/Kconfig                    |    1 
 b/arch/powerpc/lib/Makefile               |    5 
 b/arch/riscv/Kconfig                      |    1 
 b/arch/riscv/lib/Makefile                 |    1 
 b/arch/s390/Kconfig                       |    1 
 b/arch/s390/lib/Makefile                  |    2 
 b/arch/sparc/Kconfig                      |    1 
 b/arch/sparc/include/asm/asm-prototypes.h |    1 
 b/arch/sparc/lib/Makefile                 |    2 
 b/arch/um/Kconfig                         |    1 
 b/arch/x86/Kconfig                        |    1 
 b/crypto/Kconfig                          |    2 
 b/crypto/Makefile                         |    1 
 b/crypto/async_tx/async_xor.c             |   34 -
 b/drivers/char/random.c                   |   26 -
 b/fs/btrfs/raid56.c                       |   27 -
 b/include/asm-generic/Kbuild              |    1 
 b/include/linux/raid/xor.h                |   27 -
 b/include/linux/random.h                  |    1 
 b/lib/Kconfig                             |    1 
 b/lib/Makefile                            |    2 
 b/lib/raid/Kconfig                        |   19 
 b/lib/raid/Makefile                       |    3 
 b/lib/raid/xor/Makefile                   |   43 +
 b/lib/raid/xor/alpha/xor.c                |   46 -
 b/lib/raid/xor/alpha/xor_arch.h           |   22 
 b/lib/raid/xor/arm/xor-neon-glue.c        |   19 
 b/lib/raid/xor/arm/xor-neon.c             |   22 
 b/lib/raid/xor/arm/xor.c                  |  105 ----
 b/lib/raid/xor/arm/xor_arch.h             |   22 
 b/lib/raid/xor/arm64/xor-neon-glue.c      |   26 +
 b/lib/raid/xor/arm64/xor-neon.c           |   94 +--
 b/lib/raid/xor/arm64/xor-neon.h           |    6 
 b/lib/raid/xor/arm64/xor_arch.h           |   21 
 b/lib/raid/xor/loongarch/xor_arch.h       |   33 +
 b/lib/raid/xor/loongarch/xor_simd_glue.c  |   37 +
 b/lib/raid/xor/powerpc/xor_arch.h         |   22 
 b/lib/raid/xor/powerpc/xor_vmx.c          |   40 -
 b/lib/raid/xor/powerpc/xor_vmx.h          |   10 
 b/lib/raid/xor/powerpc/xor_vmx_glue.c     |   28 +
 b/lib/raid/xor/riscv/xor-glue.c           |   25 +
 b/lib/raid/xor/riscv/xor.S                |    4 
 b/lib/raid/xor/riscv/xor_arch.h           |   17 
 b/lib/raid/xor/s390/xor.c                 |   15 
 b/lib/raid/xor/s390/xor_arch.h            |   13 
 b/lib/raid/xor/sparc/xor-sparc32.c        |   32 -
 b/lib/raid/xor/sparc/xor-sparc64-glue.c   |   48 -
 b/lib/raid/xor/sparc/xor-sparc64.S        |   10 
 b/lib/raid/xor/sparc/xor_arch.h           |   35 +
 b/lib/raid/xor/tests/Makefile             |    3 
 b/lib/raid/xor/tests/xor_kunit.c          |  180 +++++++
 b/lib/raid/xor/um/xor_arch.h              |    2 
 b/lib/raid/xor/x86/xor-avx.c              |   52 --
 b/lib/raid/xor/x86/xor-mmx.c              |  120 +---
 b/lib/raid/xor/x86/xor-sse.c              |  105 +---
 b/lib/raid/xor/x86/xor_arch.h             |   36 +
 b/lib/raid/xor/xor-32regs-prefetch.c      |  267 ++++++++++
 b/lib/raid/xor/xor-32regs.c               |  217 ++++++++
 b/lib/raid/xor/xor-8regs-prefetch.c       |  146 +++++
 b/lib/raid/xor/xor-8regs.c                |  103 ++++
 b/lib/raid/xor/xor-core.c                 |  191 +++++++
 b/lib/raid/xor/xor_impl.h                 |   60 ++
 crypto/xor.c                              |  174 -------
 include/asm-generic/xor.h                 |  738 ------------------------------
 84 files changed, 1840 insertions(+), 2078 deletions(-)

^ permalink raw reply

* [PATCH 01/27] xor: assert that xor_blocks is not from preemptible user context
From: Christoph Hellwig @ 2026-03-11  7:03 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Richard Henderson, Matt Turner, Magnus Lindholm, Russell King,
	Catalin Marinas, Will Deacon, Huacai Chen, WANG Xuerui,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Heiko Carstens, Vasily Gorbik,
	Alexander Gordeev, Christian Borntraeger, Sven Schnelle,
	David S. Miller, Andreas Larsson, Richard Weinberger,
	Anton Ivanov, Johannes Berg, Thomas Gleixner, Ingo Molnar,
	Borislav Petkov, Dave Hansen, x86, H. Peter Anvin, Herbert Xu,
	Dan Williams, Chris Mason, David Sterba, Arnd Bergmann, Song Liu,
	Yu Kuai, Li Nan, Theodore Ts'o, Jason A. Donenfeld,
	linux-alpha, linux-kernel, linux-arm-kernel, loongarch,
	linuxppc-dev, linux-riscv, linux-s390, sparclinux, linux-um,
	linux-crypto, linux-btrfs, linux-arch, linux-raid
In-Reply-To: <20260311070416.972667-1-hch@lst.de>

Most of the optimized xor_blocks versions require FPU/vector registers,
which generally are not supported in interrupt context.

Both callers already are in user context, so enforce this at the highest
level.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 crypto/xor.c | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/crypto/xor.c b/crypto/xor.c
index f39621a57bb3..676d7401af43 100644
--- a/crypto/xor.c
+++ b/crypto/xor.c
@@ -28,6 +28,8 @@ xor_blocks(unsigned int src_count, unsigned int bytes, void *dest, void **srcs)
 {
 	unsigned long *p1, *p2, *p3, *p4;
 
+	lockdep_assert_preemption_enabled();
+
 	p1 = (unsigned long *) srcs[0];
 	if (src_count == 1) {
 		active_template->do_2(bytes, dest, p1);
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH 09/25] xor: move generic implementations out of asm-generic/xor.h
From: Christoph Hellwig @ 2026-03-10 14:00 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Christoph Hellwig, Andrew Morton, Richard Henderson, Matt Turner,
	Magnus Lindholm, Russell King, Catalin Marinas, Will Deacon,
	Huacai Chen, WANG Xuerui, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Heiko Carstens,
	Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
	Sven Schnelle, David S. Miller, Andreas Larsson,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Herbert Xu, Dan Williams, Chris Mason, David Sterba,
	Arnd Bergmann, Song Liu, Yu Kuai, Li Nan, linux-alpha,
	linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
	linux-riscv, linux-s390, sparclinux, linux-um, linux-crypto,
	linux-btrfs, linux-arch, linux-raid
In-Reply-To: <20260303160911.GI7021@lst.de>

On Tue, Mar 03, 2026 at 05:09:11PM +0100, Christoph Hellwig wrote:
> And earlier version did this, but it's a bit ugly.  What I might
> consider is to require architectures that provide optimized version
> to opt into any generic one they want to use.  This would require
> extra kconfig symbols, but be a lot cleaner overall.

I looked into this, but because the static_call requires a default
version I gave up on it for now.  In theory we could build just
a single generic one for that and make the others optional, but
that feels a bit odd.

^ permalink raw reply

* Re: [PATCH 21/25] xor: add a better public API
From: Christoph Hellwig @ 2026-03-10  6:58 UTC (permalink / raw)
  To: Eric Biggers
  Cc: Christoph Hellwig, Andrew Morton, Richard Henderson, Matt Turner,
	Magnus Lindholm, Russell King, Catalin Marinas, Will Deacon,
	Huacai Chen, WANG Xuerui, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Heiko Carstens,
	Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
	Sven Schnelle, David S. Miller, Andreas Larsson,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Herbert Xu, Dan Williams, Chris Mason, David Sterba,
	Arnd Bergmann, Song Liu, Yu Kuai, Li Nan, linux-alpha,
	linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
	linux-riscv, linux-s390, sparclinux, linux-um, linux-crypto,
	linux-btrfs, linux-arch, linux-raid
In-Reply-To: <20260228065038.GH65277@quark>

On Fri, Feb 27, 2026 at 10:50:38PM -0800, Eric Biggers wrote:
> > +void xor_gen(void *dest, void **srcss, unsigned int src_cnt,
> > +		unsigned int bytes);
> 
> srcss => srcs
> 
> Ideally the source vectors would be 'const' as well.

I looked at the constification, and it's a bit painful because the
same source arrays are also passed to the raid6 code by the callers.
I'll clean up the raid6 API first, and then will give it another
spin.


^ permalink raw reply

* Re: [PATCH 3/5] md: add fallback to correct bitmap_ops on version mismatch
From: Su Yue @ 2026-03-10  5:19 UTC (permalink / raw)
  To: Xiao Ni; +Cc: Yu Kuai, song, linan122, colyli, linux-raid, linux-kernel
In-Reply-To: <cd987627-5255-4d43-918e-a59e2237d188@redhat.com>

On Tue 10 Mar 2026 at 09:15, Xiao Ni <xni@redhat.com> wrote:

> 在 2026/2/24 09:52, Su Yue 写道:
>> On Mon 23 Feb 2026 at 10:22, "Yu Kuai" <yukuai@fnnas.com> 
>> wrote:
>>
>>> Hi,
>>>
>>> 在 2026/2/17 16:54, Su Yue 写道:
>>>> On Sat 14 Feb 2026 at 14:10, Yu Kuai <yukuai@fnnas.com> 
>>>> wrote:
>>>>
>>>>> If default bitmap version and on-disk version doesn't match, 
>>>>> and mdadm
>>>>> is not the latest version to set bitmap_type, set bitmap_ops 
>>>>> based on
>>>>> the disk version.
>>>>>
>>>> Why not just let old version mdadm fails  since llbitmap is a 
>>>> new
>>>> feature.
>>>
>>> The original use case is that we found llbitmap array fails to 
>>> assemble in
>>> some corner cases, and with the respect I'm not quite familiar 
>>> with mdadm
>>> code, so I think this patch is the best solution for now.
>>>
>> Would you please elaborate which corner cases that llbitmap 
>> array fails to
>> assemble
>> in? Do they happen in mdadm <= 4.5?
>>
>>> On the other hand, this should also be helpful if we decide to 
>>> make llbitmap
>>> the default option in the future.
>>>
>> But it's so far, right? llbitmap support is still on the 
>> way(mdadm 4.6 is not
>> released).
>>
>> I am not opposed to the patch. It just looks strange to me that 
>> changing
>> kernel code to
>> let old userspace work with *new* feature.
>> Maybe the mdadm maintainers have words in another angles?
>
>
> Yes. Is it better to upgrade mdadm to the version which supports 
> llbitmap?
>

Yes. This's what I mean.

--
Su
>
> Regards
>
> Xiao
>
>>
>> -- Su
>>>
>>>>
>>>>> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
>>>>> ---
>>>>>  drivers/md/md.c | 103 
>>>>>  +++++++++++++++++++++++++++++++++++++++++++++++-
>>>>>  1 file changed, 102 insertions(+), 1 deletion(-)
>>>>>
>>>>> diff --git a/drivers/md/md.c b/drivers/md/md.c
>>>>> index 59cd303548de..d2607ed5c2e9 100644
>>>>> --- a/drivers/md/md.c
>>>>> +++ b/drivers/md/md.c
>>>>> @@ -6447,15 +6447,116 @@ static void 
>>>>> md_safemode_timeout(struct
>>>>> timer_list *t)
>>>>>
>>>>>  static int start_dirty_degraded;
>>>>>
>>>>> +/*
>>>>> + * Read bitmap superblock and return the bitmap_id based on 
>>>>> disk
>>>>> version.
>>>>> + * This is used as fallback when default bitmap version and 
>>>>> on-disk
>>>>> version
>>>>> + * doesn't match, and mdadm is not the latest version to 
>>>>> set
>>>>> bitmap_type.
>>>>> + */
>>>>> +static enum md_submodule_id md_bitmap_get_id_from_sb(struct 
>>>>> mddev
>>>>> *mddev)
>>>>> +{
>>>>> +    struct md_rdev *rdev;
>>>>> +    struct page *sb_page;
>>>>> +    bitmap_super_t *sb;
>>>>> +    enum md_submodule_id id = ID_BITMAP_NONE;
>>>>> +    sector_t sector;
>>>>> +    u32 version;
>>>>> +
>>>>> +    if (!mddev->bitmap_info.offset)
>>>>> +        return ID_BITMAP_NONE;
>>>>> +
>>>>> +    sb_page = alloc_page(GFP_KERNEL);
>>>>> +    if (!sb_page)
>>>>> +        return ID_BITMAP_NONE;
>>>>> +
>>>>>
>>>> Personally I don't like the way treating error as 
>>>> ID_BITMAP_NONE.
>>>> When wrong things happen everything looks fine, no error 
>>>> code, no
>>>> error message.
>>>
>>> Ok, sounds reasonable.
>>>
>>>>
>>>>> +    sector = mddev->bitmap_info.offset;
>>>>> +
>>>>> +    rdev_for_each(rdev, mddev) {
>>>>> +        u32 iosize;
>>>>> +
>>>>> +        if (!test_bit(In_sync, &rdev->flags) ||
>>>>> +            test_bit(Faulty, &rdev->flags) ||
>>>>> +            test_bit(Bitmap_sync, &rdev->flags))
>>>>> +            continue;
>>>>> +
>>>>> +        iosize = roundup(sizeof(bitmap_super_t),
>>>>> +                 bdev_logical_block_size(rdev->bdev));
>>>>> +        if (sync_page_io(rdev, sector, iosize, sb_page, 
>>>>> REQ_OP_READ,
>>>>> +                 true))
>>>>> +            goto read_ok;
>>>>> +    }
>>>>>
>>>> And here.
>>>>
>>>>> +    goto out;
>>>>> +
>>>>> +read_ok:
>>>>> +    sb = kmap_local_page(sb_page);
>>>>> +    if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
>>>>> +        goto out_unmap;
>>>>> +
>>>>> +    version = le32_to_cpu(sb->version);
>>>>> +    switch (version) {
>>>>> +    case BITMAP_MAJOR_LO:
>>>>> +    case BITMAP_MAJOR_HI:
>>>>> +    case BITMAP_MAJOR_CLUSTERED:
>>>>>
>>>> For BITMAP_MAJOR_CLUSTERED, why not ID_CLUSTER ?
>>>
>>> Because there is no optional bitmap_ops for md-cluster, it's 
>>> still
>>> the old bitmap, and llbitmap does not support md-cluster for 
>>> now.
>>>
>>>>
>>>> -- Su
>>>>> +        id = ID_BITMAP;
>>>>> +        break;
>>>>> +    case BITMAP_MAJOR_LOCKLESS:
>>>>> +        id = ID_LLBITMAP;
>>>>> +        break;
>>>>> +    default:
>>>>> +        pr_warn("md: %s: unknown bitmap version %u\n",
>>>>> +            mdname(mddev), version);
>>>>> +        break;
>>>>> +    }
>>>>> +
>>>>> +out_unmap:
>>>>> +    kunmap_local(sb);
>>>>> +out:
>>>>> +    __free_page(sb_page);
>>>>> +    return id;
>>>>> +}
>>>>> +
>>>>>  static int md_bitmap_create(struct mddev *mddev)
>>>>>  {
>>>>> +    enum md_submodule_id orig_id = mddev->bitmap_id;
>>>>> +    enum md_submodule_id sb_id;
>>>>> +    int err;
>>>>> +
>>>>>      if (mddev->bitmap_id == ID_BITMAP_NONE)
>>>>>          return -EINVAL;
>>>>>
>>>>>      if (!mddev_set_bitmap_ops(mddev))
>>>>>          return -ENOENT;
>>>>>
>>>>> -    return mddev->bitmap_ops->create(mddev);
>>>>> +    err = mddev->bitmap_ops->create(mddev);
>>>>> +    if (!err)
>>>>> +        return 0;
>>>>>
>>>>> +
>>>>> +    /*
>>>>> +     * Create failed, if default bitmap version and on-disk 
>>>>> version
>>>>> +     * doesn't match, and mdadm is not the latest version 
>>>>> to set
>>>>> +     * bitmap_type, set bitmap_ops based on the disk 
>>>>> version.
>>>>> +     */
>>>>> +    mddev_clear_bitmap_ops(mddev);
>>>>> +
>>>>> +    sb_id = md_bitmap_get_id_from_sb(mddev);
>>>>> +    if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
>>>>> +        return err;
>>>>> +
>>>>> +    pr_info("md: %s: bitmap version mismatch, switching 
>>>>> from %d to
>>>>> %d\n",
>>>>> +        mdname(mddev), orig_id, sb_id);
>>>>> +
>>>>> +    mddev->bitmap_id = sb_id;
>>>>> +    if (!mddev_set_bitmap_ops(mddev)) {
>>>>> +        mddev->bitmap_id = orig_id;
>>>>> +        return -ENOENT;
>>>>> +    }
>>>>> +
>>>>> +    err = mddev->bitmap_ops->create(mddev);
>>>>> +    if (err) {
>>>>> +        mddev_clear_bitmap_ops(mddev);
>>>>> +        mddev->bitmap_id = orig_id;
>>>>> +    }
>>>>> +
>>>>> +    return err;
>>>>>  }
>>>>>
>>>>>  static void md_bitmap_destroy(struct mddev *mddev)
>>

^ permalink raw reply

* Re: [PATCH 3/5] md: add fallback to correct bitmap_ops on version mismatch
From: Xiao Ni @ 2026-03-10  1:15 UTC (permalink / raw)
  To: Su Yue, Yu Kuai; +Cc: song, linan122, colyli, linux-raid, linux-kernel
In-Reply-To: <bjhe7vsu.fsf@damenly.org>


在 2026/2/24 09:52, Su Yue 写道:
> On Mon 23 Feb 2026 at 10:22, "Yu Kuai" <yukuai@fnnas.com> wrote:
>
>> Hi,
>>
>> 在 2026/2/17 16:54, Su Yue 写道:
>>> On Sat 14 Feb 2026 at 14:10, Yu Kuai <yukuai@fnnas.com> wrote:
>>>
>>>> If default bitmap version and on-disk version doesn't match, and mdadm
>>>> is not the latest version to set bitmap_type, set bitmap_ops based on
>>>> the disk version.
>>>>
>>> Why not just let old version mdadm fails  since llbitmap is a new
>>> feature.
>>
>> The original use case is that we found llbitmap array fails to 
>> assemble in
>> some corner cases, and with the respect I'm not quite familiar with 
>> mdadm
>> code, so I think this patch is the best solution for now.
>>
> Would you please elaborate which corner cases that llbitmap array 
> fails to assemble
> in? Do they happen in mdadm <= 4.5?
>
>> On the other hand, this should also be helpful if we decide to make 
>> llbitmap
>> the default option in the future.
>>
> But it's so far, right? llbitmap support is still on the way(mdadm 4.6 
> is not released).
>
> I am not opposed to the patch. It just looks strange to me that 
> changing kernel code to
> let old userspace work with *new* feature.
> Maybe the mdadm maintainers have words in another angles?


Yes. Is it better to upgrade mdadm to the version which supports llbitmap?


Regards

Xiao

>
> -- 
> Su
>>
>>>
>>>> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
>>>> ---
>>>>  drivers/md/md.c | 103 
>>>>  +++++++++++++++++++++++++++++++++++++++++++++++-
>>>>  1 file changed, 102 insertions(+), 1 deletion(-)
>>>>
>>>> diff --git a/drivers/md/md.c b/drivers/md/md.c
>>>> index 59cd303548de..d2607ed5c2e9 100644
>>>> --- a/drivers/md/md.c
>>>> +++ b/drivers/md/md.c
>>>> @@ -6447,15 +6447,116 @@ static void md_safemode_timeout(struct
>>>> timer_list *t)
>>>>
>>>>  static int start_dirty_degraded;
>>>>
>>>> +/*
>>>> + * Read bitmap superblock and return the bitmap_id based on disk
>>>> version.
>>>> + * This is used as fallback when default bitmap version and on-disk
>>>> version
>>>> + * doesn't match, and mdadm is not the latest version to set
>>>> bitmap_type.
>>>> + */
>>>> +static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev
>>>> *mddev)
>>>> +{
>>>> +    struct md_rdev *rdev;
>>>> +    struct page *sb_page;
>>>> +    bitmap_super_t *sb;
>>>> +    enum md_submodule_id id = ID_BITMAP_NONE;
>>>> +    sector_t sector;
>>>> +    u32 version;
>>>> +
>>>> +    if (!mddev->bitmap_info.offset)
>>>> +        return ID_BITMAP_NONE;
>>>> +
>>>> +    sb_page = alloc_page(GFP_KERNEL);
>>>> +    if (!sb_page)
>>>> +        return ID_BITMAP_NONE;
>>>> +
>>>>
>>> Personally I don't like the way treating error as ID_BITMAP_NONE.
>>> When wrong things happen everything looks fine, no error code, no
>>> error message.
>>
>> Ok, sounds reasonable.
>>
>>>
>>>> +    sector = mddev->bitmap_info.offset;
>>>> +
>>>> +    rdev_for_each(rdev, mddev) {
>>>> +        u32 iosize;
>>>> +
>>>> +        if (!test_bit(In_sync, &rdev->flags) ||
>>>> +            test_bit(Faulty, &rdev->flags) ||
>>>> +            test_bit(Bitmap_sync, &rdev->flags))
>>>> +            continue;
>>>> +
>>>> +        iosize = roundup(sizeof(bitmap_super_t),
>>>> +                 bdev_logical_block_size(rdev->bdev));
>>>> +        if (sync_page_io(rdev, sector, iosize, sb_page, REQ_OP_READ,
>>>> +                 true))
>>>> +            goto read_ok;
>>>> +    }
>>>>
>>> And here.
>>>
>>>> +    goto out;
>>>> +
>>>> +read_ok:
>>>> +    sb = kmap_local_page(sb_page);
>>>> +    if (sb->magic != cpu_to_le32(BITMAP_MAGIC))
>>>> +        goto out_unmap;
>>>> +
>>>> +    version = le32_to_cpu(sb->version);
>>>> +    switch (version) {
>>>> +    case BITMAP_MAJOR_LO:
>>>> +    case BITMAP_MAJOR_HI:
>>>> +    case BITMAP_MAJOR_CLUSTERED:
>>>>
>>> For BITMAP_MAJOR_CLUSTERED, why not ID_CLUSTER ?
>>
>> Because there is no optional bitmap_ops for md-cluster, it's still
>> the old bitmap, and llbitmap does not support md-cluster for now.
>>
>>>
>>> -- 
>>> Su
>>>> +        id = ID_BITMAP;
>>>> +        break;
>>>> +    case BITMAP_MAJOR_LOCKLESS:
>>>> +        id = ID_LLBITMAP;
>>>> +        break;
>>>> +    default:
>>>> +        pr_warn("md: %s: unknown bitmap version %u\n",
>>>> +            mdname(mddev), version);
>>>> +        break;
>>>> +    }
>>>> +
>>>> +out_unmap:
>>>> +    kunmap_local(sb);
>>>> +out:
>>>> +    __free_page(sb_page);
>>>> +    return id;
>>>> +}
>>>> +
>>>>  static int md_bitmap_create(struct mddev *mddev)
>>>>  {
>>>> +    enum md_submodule_id orig_id = mddev->bitmap_id;
>>>> +    enum md_submodule_id sb_id;
>>>> +    int err;
>>>> +
>>>>      if (mddev->bitmap_id == ID_BITMAP_NONE)
>>>>          return -EINVAL;
>>>>
>>>>      if (!mddev_set_bitmap_ops(mddev))
>>>>          return -ENOENT;
>>>>
>>>> -    return mddev->bitmap_ops->create(mddev);
>>>> +    err = mddev->bitmap_ops->create(mddev);
>>>> +    if (!err)
>>>> +        return 0;
>>>>
>>>> +
>>>> +    /*
>>>> +     * Create failed, if default bitmap version and on-disk version
>>>> +     * doesn't match, and mdadm is not the latest version to set
>>>> +     * bitmap_type, set bitmap_ops based on the disk version.
>>>> +     */
>>>> +    mddev_clear_bitmap_ops(mddev);
>>>> +
>>>> +    sb_id = md_bitmap_get_id_from_sb(mddev);
>>>> +    if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
>>>> +        return err;
>>>> +
>>>> +    pr_info("md: %s: bitmap version mismatch, switching from %d to
>>>> %d\n",
>>>> +        mdname(mddev), orig_id, sb_id);
>>>> +
>>>> +    mddev->bitmap_id = sb_id;
>>>> +    if (!mddev_set_bitmap_ops(mddev)) {
>>>> +        mddev->bitmap_id = orig_id;
>>>> +        return -ENOENT;
>>>> +    }
>>>> +
>>>> +    err = mddev->bitmap_ops->create(mddev);
>>>> +    if (err) {
>>>> +        mddev_clear_bitmap_ops(mddev);
>>>> +        mddev->bitmap_id = orig_id;
>>>> +    }
>>>> +
>>>> +    return err;
>>>>  }
>>>>
>>>>  static void md_bitmap_destroy(struct mddev *mddev)
>


^ permalink raw reply

* Re: [PATCH v2 3/5] md: add fallback to correct bitmap_ops on version mismatch
From: Xiao Ni @ 2026-03-10  1:06 UTC (permalink / raw)
  To: Yu Kuai; +Cc: song, linan122, colyli, linux-raid, linux-kernel
In-Reply-To: <20260223024038.3084853-4-yukuai@fnnas.com>

On Mon, Feb 23, 2026 at 10:43 AM Yu Kuai <yukuai@fnnas.com> wrote:
>
> If default bitmap version and on-disk version doesn't match, and mdadm
> is not the latest version to set bitmap_type, set bitmap_ops based on
> the disk version.

Hi Kuai

How can I do test to check if this patch works?

1. Create array with llbitmap
2. Stop the array
3. uninstall mdadm with llbitmap support and install mdadm without llbitmap
4. assemble the array

Is it the case you want to fix?

Regards
Xiao
>
> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
> ---
>  drivers/md/md.c | 111 +++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 110 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 72a1c7267851..245785ad0ffd 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -6447,15 +6447,124 @@ static void md_safemode_timeout(struct timer_list *t)
>
>  static int start_dirty_degraded;
>
> +/*
> + * Read bitmap superblock and return the bitmap_id based on disk version.
> + * This is used as fallback when default bitmap version and on-disk version
> + * doesn't match, and mdadm is not the latest version to set bitmap_type.
> + */
> +static enum md_submodule_id md_bitmap_get_id_from_sb(struct mddev *mddev)
> +{
> +       struct md_rdev *rdev;
> +       struct page *sb_page;
> +       bitmap_super_t *sb;
> +       enum md_submodule_id id = ID_BITMAP_NONE;
> +       sector_t sector;
> +       u32 version;
> +
> +       if (!mddev->bitmap_info.offset)
> +               return ID_BITMAP_NONE;
> +
> +       sb_page = alloc_page(GFP_KERNEL);
> +       if (!sb_page) {
> +               pr_warn("md: %s: failed to allocate memory for bitmap\n",
> +                       mdname(mddev));
> +               return ID_BITMAP_NONE;
> +       }
> +
> +       sector = mddev->bitmap_info.offset;
> +
> +       rdev_for_each(rdev, mddev) {
> +               u32 iosize;
> +
> +               if (!test_bit(In_sync, &rdev->flags) ||
> +                   test_bit(Faulty, &rdev->flags) ||
> +                   test_bit(Bitmap_sync, &rdev->flags))
> +                       continue;
> +
> +               iosize = roundup(sizeof(bitmap_super_t),
> +                                bdev_logical_block_size(rdev->bdev));
> +               if (sync_page_io(rdev, sector, iosize, sb_page, REQ_OP_READ,
> +                                true))
> +                       goto read_ok;
> +       }
> +       pr_warn("md: %s: failed to read bitmap from any device\n",
> +               mdname(mddev));
> +       goto out;
> +
> +read_ok:
> +       sb = kmap_local_page(sb_page);
> +       if (sb->magic != cpu_to_le32(BITMAP_MAGIC)) {
> +               pr_warn("md: %s: invalid bitmap magic 0x%x\n",
> +                       mdname(mddev), le32_to_cpu(sb->magic));
> +               goto out_unmap;
> +       }
> +
> +       version = le32_to_cpu(sb->version);
> +       switch (version) {
> +       case BITMAP_MAJOR_LO:
> +       case BITMAP_MAJOR_HI:
> +       case BITMAP_MAJOR_CLUSTERED:
> +               id = ID_BITMAP;
> +               break;
> +       case BITMAP_MAJOR_LOCKLESS:
> +               id = ID_LLBITMAP;
> +               break;
> +       default:
> +               pr_warn("md: %s: unknown bitmap version %u\n",
> +                       mdname(mddev), version);
> +               break;
> +       }
> +
> +out_unmap:
> +       kunmap_local(sb);
> +out:
> +       __free_page(sb_page);
> +       return id;
> +}
> +
>  static int md_bitmap_create(struct mddev *mddev)
>  {
> +       enum md_submodule_id orig_id = mddev->bitmap_id;
> +       enum md_submodule_id sb_id;
> +       int err;
> +
>         if (mddev->bitmap_id == ID_BITMAP_NONE)
>                 return -EINVAL;
>
>         if (!mddev_set_bitmap_ops(mddev))
>                 return -ENOENT;
>
> -       return mddev->bitmap_ops->create(mddev);
> +       err = mddev->bitmap_ops->create(mddev);
> +       if (!err)
> +               return 0;
> +
> +       /*
> +        * Create failed, if default bitmap version and on-disk version
> +        * doesn't match, and mdadm is not the latest version to set
> +        * bitmap_type, set bitmap_ops based on the disk version.
> +        */
> +       mddev_clear_bitmap_ops(mddev);
> +
> +       sb_id = md_bitmap_get_id_from_sb(mddev);
> +       if (sb_id == ID_BITMAP_NONE || sb_id == orig_id)
> +               return err;
> +
> +       pr_info("md: %s: bitmap version mismatch, switching from %d to %d\n",
> +               mdname(mddev), orig_id, sb_id);
> +
> +       mddev->bitmap_id = sb_id;
> +       if (!mddev_set_bitmap_ops(mddev)) {
> +               mddev->bitmap_id = orig_id;
> +               return -ENOENT;
> +       }
> +
> +       err = mddev->bitmap_ops->create(mddev);
> +       if (err) {
> +               mddev_clear_bitmap_ops(mddev);
> +               mddev->bitmap_id = orig_id;
> +       }
> +
> +       return err;
>  }
>
>  static void md_bitmap_destroy(struct mddev *mddev)
> --
> 2.51.0
>
>


^ permalink raw reply

* Re: [PATCH v2 2/5] md/md-llbitmap: raise barrier before state machine transition
From: Xiao Ni @ 2026-03-09 13:05 UTC (permalink / raw)
  To: Yu Kuai; +Cc: song, linan122, colyli, linux-raid, linux-kernel
In-Reply-To: <20260223024038.3084853-3-yukuai@fnnas.com>

On Mon, Feb 23, 2026 at 10:42 AM Yu Kuai <yukuai@fnnas.com> wrote:
>
> Move the barrier raise operation before calling llbitmap_state_machine()
> in both llbitmap_start_write() and llbitmap_start_discard(). This
> ensures the barrier is in place before any state transitions occur,
> preventing potential race conditions where the state machine could
> complete before the barrier is properly raised.

Hi Kuai

In the above commit message, race conditions are mentioned. I want to
give an example here to check if I understand correctly.

raid1 with 2 disks is used in this case.
T0: Thread A calls llbitmap_state_machine() and state of bit is set to BitDirty
T1: Thread daemon calls llbitmap_daemon_work() and the state of the
bit is set to BitClean from BitDirty.
(Now the state is already wrong)
T2: Thread A calls llbitmap_raise_barrier to wait Thread daemon
finishes and go on working
T3: data is written to disk1 and disk2. A power failure occurs.
(The data on disk1 and disk2 maybe different, so a data curruption happens)

Does this case belong the race conditions you mentioned in the commit
message? Can you add one race condtion in your message?

Best Regards
Xiao

>
> Cc: stable@vger.kernel.org
> Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap")
> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
> ---
>  drivers/md/md-llbitmap.c | 8 ++++----
>  1 file changed, 4 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
> index 30d7e36b22c4..5f9e7004e3e3 100644
> --- a/drivers/md/md-llbitmap.c
> +++ b/drivers/md/md-llbitmap.c
> @@ -1070,12 +1070,12 @@ static void llbitmap_start_write(struct mddev *mddev, sector_t offset,
>         int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>         int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>
> -       llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
> -
>         while (page_start <= page_end) {
>                 llbitmap_raise_barrier(llbitmap, page_start);
>                 page_start++;
>         }
> +
> +       llbitmap_state_machine(llbitmap, start, end, BitmapActionStartwrite);
>  }
>
>  static void llbitmap_end_write(struct mddev *mddev, sector_t offset,
> @@ -1102,12 +1102,12 @@ static void llbitmap_start_discard(struct mddev *mddev, sector_t offset,
>         int page_start = (start + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>         int page_end = (end + BITMAP_DATA_OFFSET) >> PAGE_SHIFT;
>
> -       llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
> -
>         while (page_start <= page_end) {
>                 llbitmap_raise_barrier(llbitmap, page_start);
>                 page_start++;
>         }
> +
> +       llbitmap_state_machine(llbitmap, start, end, BitmapActionDiscard);
>  }
>
>  static void llbitmap_end_discard(struct mddev *mddev, sector_t offset,
> --
> 2.51.0
>
>


^ permalink raw reply

* Re: [PATCH v2 1/5] md/md-llbitmap: skip reading rdevs that are not in_sync
From: Xiao Ni @ 2026-03-09  7:32 UTC (permalink / raw)
  To: Yu Kuai; +Cc: song, linan122, colyli, linux-raid, linux-kernel
In-Reply-To: <20260223024038.3084853-2-yukuai@fnnas.com>

On Mon, Feb 23, 2026 at 10:41 AM Yu Kuai <yukuai@fnnas.com> wrote:
>
> When reading bitmap pages from member disks, the code iterates through
> all rdevs and attempts to read from the first available one. However,
> it only checks for raid_disk assignment and Faulty flag, missing the
> In_sync flag check.
>
> This can cause bitmap data to be read from spare disks that are still
> being rebuilt and don't have valid bitmap information yet. Reading
> stale or uninitialized bitmap data from such disks can lead to
> incorrect dirty bit tracking, potentially causing data corruption
> during recovery or normal operation.
>
> Add the In_sync flag check to ensure bitmap pages are only read from
> fully synchronized member disks that have valid bitmap data.
>
> Cc: stable@vger.kernel.org
> Fixes: 5ab829f1971d ("md/md-llbitmap: introduce new lockless bitmap")
> Signed-off-by: Yu Kuai <yukuai@fnnas.com>
> ---
>  drivers/md/md-llbitmap.c | 3 ++-
>  1 file changed, 2 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
> index cd713a7dc270..30d7e36b22c4 100644
> --- a/drivers/md/md-llbitmap.c
> +++ b/drivers/md/md-llbitmap.c
> @@ -459,7 +459,8 @@ static struct page *llbitmap_read_page(struct llbitmap *llbitmap, int idx)
>         rdev_for_each(rdev, mddev) {
>                 sector_t sector;
>
> -               if (rdev->raid_disk < 0 || test_bit(Faulty, &rdev->flags))
> +               if (rdev->raid_disk < 0 || test_bit(Faulty, &rdev->flags) ||
> +                   !test_bit(In_sync, &rdev->flags))
>                         continue;
>
>                 sector = mddev->bitmap_info.offset +
> --
> 2.51.0
>
>

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


^ permalink raw reply

* [PATCH] md/raid0: use kvzalloc/kvfree for strip_zone and devlist allocations
From: Gregory Price @ 2026-03-08 23:42 UTC (permalink / raw)
  To: song, yukuai, linan122
  Cc: linux-raid, linux-kernel, linux-mm, syzbot+924649752adf0d3ac9dd,
	akpm
In-Reply-To: <69adaba8.a00a0220.b130.0005.GAE@google.com>

syzbot reported a WARNING at mm/page_alloc.c:__alloc_frozen_pages_noprof()
triggered by create_strip_zones() in the RAID0 driver.

When raid_disks is large, the allocation size exceeds MAX_PAGE_ORDER (4MB
on x86), causing WARN_ON_ONCE_GFP(order > MAX_PAGE_ORDER).

Convert the strip_zone and devlist allocations from kzalloc/kzalloc_objs to
kvzalloc/kvzalloc_objs, which first attempts a contiguous allocation with
__GFP_NOWARN and then falls back to vmalloc for large sizes. Convert the
corresponding kfree calls to kvfree.

Both arrays are pure metadata lookup tables (arrays of pointers and zone
descriptors) accessed only via indexing, so they do not require physically
contiguous memory.

Reported-by: syzbot+924649752adf0d3ac9dd@syzkaller.appspotmail.com
Signed-off-by: Gregory Price <gourry@gourry.net>
---
 drivers/md/raid0.c | 18 +++++++++---------
 1 file changed, 9 insertions(+), 9 deletions(-)

diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
index ef0045db409f..5e38a51e349a 100644
--- a/drivers/md/raid0.c
+++ b/drivers/md/raid0.c
@@ -143,13 +143,13 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
 	}
 
 	err = -ENOMEM;
-	conf->strip_zone = kzalloc_objs(struct strip_zone, conf->nr_strip_zones);
+	conf->strip_zone = kvzalloc_objs(struct strip_zone, conf->nr_strip_zones);
 	if (!conf->strip_zone)
 		goto abort;
-	conf->devlist = kzalloc(array3_size(sizeof(struct md_rdev *),
-					    conf->nr_strip_zones,
-					    mddev->raid_disks),
-				GFP_KERNEL);
+	conf->devlist = kvzalloc(array3_size(sizeof(struct md_rdev *),
+					     conf->nr_strip_zones,
+					     mddev->raid_disks),
+				 GFP_KERNEL);
 	if (!conf->devlist)
 		goto abort;
 
@@ -291,8 +291,8 @@ static int create_strip_zones(struct mddev *mddev, struct r0conf **private_conf)
 
 	return 0;
 abort:
-	kfree(conf->strip_zone);
-	kfree(conf->devlist);
+	kvfree(conf->strip_zone);
+	kvfree(conf->devlist);
 	kfree(conf);
 	*private_conf = ERR_PTR(err);
 	return err;
@@ -373,8 +373,8 @@ static void raid0_free(struct mddev *mddev, void *priv)
 {
 	struct r0conf *conf = priv;
 
-	kfree(conf->strip_zone);
-	kfree(conf->devlist);
+	kvfree(conf->strip_zone);
+	kvfree(conf->devlist);
 	kfree(conf);
 }
 
-- 
2.53.0


^ permalink raw reply related

* md-raid support 50/60 & spare space support
From: Anton Gavriliuk @ 2026-03-06 11:17 UTC (permalink / raw)
  To: linux-raid

Hi

Are there any plans to add support for md-raid 50/60 ?
Maximum recommended number of disks for single raid5 shouldn't exceed 8.
So raid 50/60 would be very useful for systems with 64-96 disks.

And also any plans for spare space support (instead of spare disk) ?

Anton

^ permalink raw reply

* Re: [PATCH 1/3] md: restore bitmap/location to fix wrong bitmap offset while growing
From: Glass Su @ 2026-03-06  4:25 UTC (permalink / raw)
  To: kernel test robot
  Cc: linux-raid, oe-kbuild-all, song, xni, linan122, yukuai,
	Heming Zhao, Su Yue
In-Reply-To: <202603060614.AZY6J9w9-lkp@intel.com>



> On Mar 6, 2026, at 06:50, kernel test robot <lkp@intel.com> wrote:
> 
> Hi Su,
> 
> kernel test robot noticed the following build errors:
> 
> [auto build test ERROR on linus/master]
> [also build test ERROR on v7.0-rc2 next-20260305]
> [If your patch is applied to the wrong git tree, kindly drop us a note.
> And when submitting patch, we suggest to use '--base' as documented in
> https://git-scm.com/docs/git-format-patch#_base_tree_information]
> 
> url:    https://github.com/intel-lab-lkp/linux/commits/Su-Yue/md-restore-bitmap-location-to-fix-wrong-bitmap-offset-while-growing/20260303-114108
> base:   linus/master
> patch link:    https://lore.kernel.org/r/20260303033731.83885-2-glass.su%40suse.com
> patch subject: [PATCH 1/3] md: restore bitmap/location to fix wrong bitmap offset while growing
> config: i386-randconfig-051-20260305 (https://download.01.org/0day-ci/archive/20260306/202603060614.AZY6J9w9-lkp@intel.com/config)
> compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
> reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260306/202603060614.AZY6J9w9-lkp@intel.com/reproduce)
> 
> If you fix the issue in a separate patch/commit (i.e. not just a new version of
> the same patch/commit), kindly add following tags
> | Reported-by: kernel test robot <lkp@intel.com>
> | Closes: https://lore.kernel.org/oe-kbuild-all/202603060614.AZY6J9w9-lkp@intel.com/
> 
> All errors (new ones prefixed by >>):
> 
>   ld: drivers/md/md.o: in function `md_alloc':
>>> drivers/md/md.c:6376:(.text+0xb36c): undefined reference to `md_sysfs_create_common_group'

Forget to test it with 

# CONFIG_MD_BITMAP is not set

Anyway, I will do  revision as Yu Kuai’s suggestion.

— 
Su

> 

> 
> vim +6376 drivers/md/md.c
> 
>  6276 
>  6277 struct mddev *md_alloc(dev_t dev, char *name)
>  6278 {
>  6279 /*
>  6280 * If dev is zero, name is the name of a device to allocate with
>  6281 * an arbitrary minor number.  It will be "md_???"
>  6282 * If dev is non-zero it must be a device number with a MAJOR of
>  6283 * MD_MAJOR or mdp_major.  In this case, if "name" is NULL, then
>  6284 * the device is being created by opening a node in /dev.
>  6285 * If "name" is not NULL, the device is being created by
>  6286 * writing to /sys/module/md_mod/parameters/new_array.
>  6287 */
>  6288 static DEFINE_MUTEX(disks_mutex);
>  6289 struct mddev *mddev;
>  6290 struct gendisk *disk;
>  6291 int partitioned;
>  6292 int shift;
>  6293 int unit;
>  6294 int error;
>  6295 
>  6296 /*
>  6297 * Wait for any previous instance of this device to be completely
>  6298 * removed (mddev_delayed_delete).
>  6299 */
>  6300 flush_workqueue(md_misc_wq);
>  6301 
>  6302 mutex_lock(&disks_mutex);
>  6303 mddev = mddev_alloc(dev);
>  6304 if (IS_ERR(mddev)) {
>  6305 error = PTR_ERR(mddev);
>  6306 goto out_unlock;
>  6307 }
>  6308 
>  6309 partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
>  6310 shift = partitioned ? MdpMinorShift : 0;
>  6311 unit = MINOR(mddev->unit) >> shift;
>  6312 
>  6313 if (name && !dev) {
>  6314 /* Need to ensure that 'name' is not a duplicate.
>  6315 */
>  6316 struct mddev *mddev2;
>  6317 spin_lock(&all_mddevs_lock);
>  6318 
>  6319 list_for_each_entry(mddev2, &all_mddevs, all_mddevs)
>  6320 if (mddev2->gendisk &&
>  6321    strcmp(mddev2->gendisk->disk_name, name) == 0) {
>  6322 spin_unlock(&all_mddevs_lock);
>  6323 error = -EEXIST;
>  6324 goto out_free_mddev;
>  6325 }
>  6326 spin_unlock(&all_mddevs_lock);
>  6327 }
>  6328 if (name && dev)
>  6329 /*
>  6330 * Creating /dev/mdNNN via "newarray", so adjust hold_active.
>  6331 */
>  6332 mddev->hold_active = UNTIL_STOP;
>  6333 
>  6334 disk = blk_alloc_disk(NULL, NUMA_NO_NODE);
>  6335 if (IS_ERR(disk)) {
>  6336 error = PTR_ERR(disk);
>  6337 goto out_free_mddev;
>  6338 }
>  6339 
>  6340 disk->major = MAJOR(mddev->unit);
>  6341 disk->first_minor = unit << shift;
>  6342 disk->minors = 1 << shift;
>  6343 if (name)
>  6344 strcpy(disk->disk_name, name);
>  6345 else if (partitioned)
>  6346 sprintf(disk->disk_name, "md_d%d", unit);
>  6347 else
>  6348 sprintf(disk->disk_name, "md%d", unit);
>  6349 disk->fops = &md_fops;
>  6350 disk->private_data = mddev;
>  6351 
>  6352 disk->events |= DISK_EVENT_MEDIA_CHANGE;
>  6353 mddev->gendisk = disk;
>  6354 error = add_disk(disk);
>  6355 if (error)
>  6356 goto out_put_disk;
>  6357 
>  6358 kobject_init(&mddev->kobj, &md_ktype);
>  6359 error = kobject_add(&mddev->kobj, &disk_to_dev(disk)->kobj, "%s", "md");
>  6360 if (error) {
>  6361 /*
>  6362 * The disk is already live at this point.  Clear the hold flag
>  6363 * and let mddev_put take care of the deletion, as it isn't any
>  6364 * different from a normal close on last release now.
>  6365 */
>  6366 mddev->hold_active = 0;
>  6367 mutex_unlock(&disks_mutex);
>  6368 mddev_put(mddev);
>  6369 return ERR_PTR(error);
>  6370 }
>  6371 
>  6372 /*
>  6373 * md_sysfs_remove_common_group is not needed because mddev_delayed_delete
>  6374 * calls kobject_put(&mddev->kobj) if mddev is to be deleted.
>  6375 */
>> 6376 if (md_sysfs_create_common_group(mddev))
>  6377 pr_warn("md: cannot register common bitmap attributes for %s\n",
>  6378 mdname(mddev));
>  6379 
>  6380 kobject_uevent(&mddev->kobj, KOBJ_ADD);
>  6381 mddev->sysfs_state = sysfs_get_dirent_safe(mddev->kobj.sd, "array_state");
>  6382 mddev->sysfs_level = sysfs_get_dirent_safe(mddev->kobj.sd, "level");
>  6383 mutex_unlock(&disks_mutex);
>  6384 return mddev;
>  6385 
>  6386 out_put_disk:
>  6387 put_disk(disk);
>  6388 out_free_mddev:
>  6389 mddev_free(mddev);
>  6390 out_unlock:
>  6391 mutex_unlock(&disks_mutex);
>  6392 return ERR_PTR(error);
>  6393 }
>  6394 
> 
> -- 
> 0-DAY CI Kernel Test Service
> https://github.com/intel/lkp-tests/wiki


^ permalink raw reply

* Re: [PATCH 1/3] md: restore bitmap/location to fix wrong bitmap offset while growing
From: kernel test robot @ 2026-03-05 22:50 UTC (permalink / raw)
  To: Su Yue, linux-raid
  Cc: oe-kbuild-all, song, xni, linan122, yukuai, heming.zhao, l,
	Su Yue
In-Reply-To: <20260303033731.83885-2-glass.su@suse.com>

Hi Su,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v7.0-rc2 next-20260305]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Su-Yue/md-restore-bitmap-location-to-fix-wrong-bitmap-offset-while-growing/20260303-114108
base:   linus/master
patch link:    https://lore.kernel.org/r/20260303033731.83885-2-glass.su%40suse.com
patch subject: [PATCH 1/3] md: restore bitmap/location to fix wrong bitmap offset while growing
config: i386-randconfig-051-20260305 (https://download.01.org/0day-ci/archive/20260306/202603060614.AZY6J9w9-lkp@intel.com/config)
compiler: gcc-14 (Debian 14.2.0-19) 14.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260306/202603060614.AZY6J9w9-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603060614.AZY6J9w9-lkp@intel.com/

All errors (new ones prefixed by >>):

   ld: drivers/md/md.o: in function `md_alloc':
>> drivers/md/md.c:6376:(.text+0xb36c): undefined reference to `md_sysfs_create_common_group'


vim +6376 drivers/md/md.c

  6276	
  6277	struct mddev *md_alloc(dev_t dev, char *name)
  6278	{
  6279		/*
  6280		 * If dev is zero, name is the name of a device to allocate with
  6281		 * an arbitrary minor number.  It will be "md_???"
  6282		 * If dev is non-zero it must be a device number with a MAJOR of
  6283		 * MD_MAJOR or mdp_major.  In this case, if "name" is NULL, then
  6284		 * the device is being created by opening a node in /dev.
  6285		 * If "name" is not NULL, the device is being created by
  6286		 * writing to /sys/module/md_mod/parameters/new_array.
  6287		 */
  6288		static DEFINE_MUTEX(disks_mutex);
  6289		struct mddev *mddev;
  6290		struct gendisk *disk;
  6291		int partitioned;
  6292		int shift;
  6293		int unit;
  6294		int error;
  6295	
  6296		/*
  6297		 * Wait for any previous instance of this device to be completely
  6298		 * removed (mddev_delayed_delete).
  6299		 */
  6300		flush_workqueue(md_misc_wq);
  6301	
  6302		mutex_lock(&disks_mutex);
  6303		mddev = mddev_alloc(dev);
  6304		if (IS_ERR(mddev)) {
  6305			error = PTR_ERR(mddev);
  6306			goto out_unlock;
  6307		}
  6308	
  6309		partitioned = (MAJOR(mddev->unit) != MD_MAJOR);
  6310		shift = partitioned ? MdpMinorShift : 0;
  6311		unit = MINOR(mddev->unit) >> shift;
  6312	
  6313		if (name && !dev) {
  6314			/* Need to ensure that 'name' is not a duplicate.
  6315			 */
  6316			struct mddev *mddev2;
  6317			spin_lock(&all_mddevs_lock);
  6318	
  6319			list_for_each_entry(mddev2, &all_mddevs, all_mddevs)
  6320				if (mddev2->gendisk &&
  6321				    strcmp(mddev2->gendisk->disk_name, name) == 0) {
  6322					spin_unlock(&all_mddevs_lock);
  6323					error = -EEXIST;
  6324					goto out_free_mddev;
  6325				}
  6326			spin_unlock(&all_mddevs_lock);
  6327		}
  6328		if (name && dev)
  6329			/*
  6330			 * Creating /dev/mdNNN via "newarray", so adjust hold_active.
  6331			 */
  6332			mddev->hold_active = UNTIL_STOP;
  6333	
  6334		disk = blk_alloc_disk(NULL, NUMA_NO_NODE);
  6335		if (IS_ERR(disk)) {
  6336			error = PTR_ERR(disk);
  6337			goto out_free_mddev;
  6338		}
  6339	
  6340		disk->major = MAJOR(mddev->unit);
  6341		disk->first_minor = unit << shift;
  6342		disk->minors = 1 << shift;
  6343		if (name)
  6344			strcpy(disk->disk_name, name);
  6345		else if (partitioned)
  6346			sprintf(disk->disk_name, "md_d%d", unit);
  6347		else
  6348			sprintf(disk->disk_name, "md%d", unit);
  6349		disk->fops = &md_fops;
  6350		disk->private_data = mddev;
  6351	
  6352		disk->events |= DISK_EVENT_MEDIA_CHANGE;
  6353		mddev->gendisk = disk;
  6354		error = add_disk(disk);
  6355		if (error)
  6356			goto out_put_disk;
  6357	
  6358		kobject_init(&mddev->kobj, &md_ktype);
  6359		error = kobject_add(&mddev->kobj, &disk_to_dev(disk)->kobj, "%s", "md");
  6360		if (error) {
  6361			/*
  6362			 * The disk is already live at this point.  Clear the hold flag
  6363			 * and let mddev_put take care of the deletion, as it isn't any
  6364			 * different from a normal close on last release now.
  6365			 */
  6366			mddev->hold_active = 0;
  6367			mutex_unlock(&disks_mutex);
  6368			mddev_put(mddev);
  6369			return ERR_PTR(error);
  6370		}
  6371	
  6372		/*
  6373		 * md_sysfs_remove_common_group is not needed because mddev_delayed_delete
  6374		 * calls kobject_put(&mddev->kobj) if mddev is to be deleted.
  6375		 */
> 6376		if (md_sysfs_create_common_group(mddev))
  6377			pr_warn("md: cannot register common bitmap attributes for %s\n",
  6378				mdname(mddev));
  6379	
  6380		kobject_uevent(&mddev->kobj, KOBJ_ADD);
  6381		mddev->sysfs_state = sysfs_get_dirent_safe(mddev->kobj.sd, "array_state");
  6382		mddev->sysfs_level = sysfs_get_dirent_safe(mddev->kobj.sd, "level");
  6383		mutex_unlock(&disks_mutex);
  6384		return mddev;
  6385	
  6386	out_put_disk:
  6387		put_disk(disk);
  6388	out_free_mddev:
  6389		mddev_free(mddev);
  6390	out_unlock:
  6391		mutex_unlock(&disks_mutex);
  6392		return ERR_PTR(error);
  6393	}
  6394	

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH 1/3] md: restore bitmap/location to fix wrong bitmap offset while growing
From: kernel test robot @ 2026-03-05 22:38 UTC (permalink / raw)
  To: Su Yue, linux-raid
  Cc: oe-kbuild-all, song, xni, linan122, yukuai, heming.zhao, l,
	Su Yue
In-Reply-To: <20260303033731.83885-2-glass.su@suse.com>

Hi Su,

kernel test robot noticed the following build errors:

[auto build test ERROR on linus/master]
[also build test ERROR on v7.0-rc2 next-20260305]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url:    https://github.com/intel-lab-lkp/linux/commits/Su-Yue/md-restore-bitmap-location-to-fix-wrong-bitmap-offset-while-growing/20260303-114108
base:   linus/master
patch link:    https://lore.kernel.org/r/20260303033731.83885-2-glass.su%40suse.com
patch subject: [PATCH 1/3] md: restore bitmap/location to fix wrong bitmap offset while growing
config: i386-randconfig-r064-20260305 (https://download.01.org/0day-ci/archive/20260306/202603060651.tJ5tGHRo-lkp@intel.com/config)
compiler: clang version 20.1.8 (https://github.com/llvm/llvm-project 87f0227cb60147a26a1eeb4fb06e3b505e9c7261)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260306/202603060651.tJ5tGHRo-lkp@intel.com/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202603060651.tJ5tGHRo-lkp@intel.com/

All errors (new ones prefixed by >>):

>> ld.lld: error: undefined symbol: md_sysfs_create_common_group
   >>> referenced by md.c:6376 (drivers/md/md.c:6376)
   >>>               drivers/md/md.o:(md_alloc) in archive vmlinux.a

-- 
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

^ permalink raw reply

* Re: [PATCH 1/3] md: restore bitmap/location to fix wrong bitmap offset while growing
From: Yu Kuai @ 2026-03-05 17:57 UTC (permalink / raw)
  To: Su Yue, yukuai; +Cc: Su Yue, linux-raid, song, xni, linan122, heming.zhao
In-Reply-To: <342g70bt.fsf@damenly.org>

Hi,

在 2026/3/4 11:14, Su Yue 写道:
> On Wed 04 Mar 2026 at 10:30, "Yu Kuai" <yukuai@fnnas.com> wrote:
>
>> Hi,
>>
>> 在 2026/3/3 11:37, Su Yue 写道:
>>> Before commit fb8cc3b0d9db ("md/md-bitmap: delay registration of 
>>> bitmap_ops until creating bitmap")
>>> if CONFIG_MD_BITMAP is enabled, both bitmap none, internal and 
>>> clustered have
>>> the sysfs file bitmap/location.
>>>
>>> After the commit, if bitmap is none, bitmap/location doesn't exist 
>>> anymore.
>>> It breaks 'grow' behavior of a md array of madam with 
>>> MD_FEATURE_BITMAP_OFFSET.
>>> Take level=mirror and metadata=1.2 as an example:
>>>
>>> $ mdadm  --create  /dev/md0 -f --bitmap=none --raid-devices=2 
>>> --level=mirror \
>>>    --metadata=1.2 /dev/vdd /dev/vde
>>> $ mdadm --grow /dev/md0 --bitmap=internal
>>> $ cat /sys/block/md0/md/bitmap/location
>>> Before:+8
>>> After: +2
>>>
>>> While growing bitmap from none to internal, clustered and llbitmap,
>>> mdadm/Grow.c:Grow_addbitmap() tries to detect bitmap/location first.
>>> 1)If bitmap/location exists, it sets bitmap/location after 
>>> getinfo_super().
>>> 2)If bitmap/location doesn't exist, mdadm just calls 
>>> md_set_array_info() then
>>> mddev->bitmap_info.default_offset will be used.
>>> Situation can be worse if growing none to clustered, bitmap offset 
>>> of the node
>>> calling `madm --grow` will be changed but the other node are reading 
>>> bitmap sb from
>>> the old location.
>>
>> Now that we have a new sysfs attribute bitmap_type, can we fix this by:
>> - in the kernel, allow writing to this file in this case;
>> - in mdadm and the grow case above, write to this file first, and change
>> bitmap_type from none to bitmap(For llbitmap, there is still more 
>> work to do).
>>
> Yes. It's indeed feasible. But how about old versions mdadm? We can't 
> require
> users' madadm + kernel combinations for old feature. Kernel part 
> should keep
> compatibility with userspace. sysfs changes and broken haviros are not 
> ideal
> especially userspace depends on it unless there's a strong reason.
> That's why linux/Documentation/ABI exists.

Okay, I can accept keep this old behavior.

However, instead of introducing a new common_group with the same name "bitmap",
I'll prefer to introducing a separate bitmap_ops for none bitmap as well, and
you can define the attrs that are necessary.

For llbitmap, I think it's fine, we don't need this old sysfs attr anyway. I'll
support to convert from none/bitmap to llbitmap by writing the new bitmap_type
file.
  

>
> -- 
> Su
>
>>>
>>> Here restore sysfs file bitmap/location for ID_BITMAP_NONE and 
>>> ID_BITMAP.
>>> And it d adds the entry for llbitmap too.
>>>
>>> New attribute_group md_bitmap_common_group is introduced and created in
>>> md_alloc() as before commit fb8cc3b0d9db.
>>> Add New operations register_group and unregister_group to struct 
>>> bitmap_operations.
>>>
>>> Fixes: fb8cc3b0d9db ("md/md-bitmap: delay registration of bitmap_ops 
>>> until creating bitmap")
>>> Signed-off-by: Su Yue <glass.su@suse.com>
>>> ---
>>>   drivers/md/md-bitmap.c   | 32 +++++++++++++++++++++++++++++++-
>>>   drivers/md/md-bitmap.h   |  5 +++++
>>>   drivers/md/md-llbitmap.c | 13 +++++++++++++
>>>   drivers/md/md.c          | 16 ++++++++++++----
>>>   4 files changed, 61 insertions(+), 5 deletions(-)
>>>
>>> diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
>>> index 83378c033c72..8ff1dc94ed78 100644
>>> --- a/drivers/md/md-bitmap.c
>>> +++ b/drivers/md/md-bitmap.c
>>> @@ -2956,7 +2956,6 @@ __ATTR(max_backlog_used, S_IRUGO | S_IWUSR,
>>>          behind_writes_used_show, behind_writes_used_reset);
>>>
>>>   static struct attribute *md_bitmap_attrs[] = {
>>> -    &bitmap_location.attr,
>>>       &bitmap_space.attr,
>>>       &bitmap_timeout.attr,
>>>       &bitmap_backlog.attr,
>>> @@ -2967,11 +2966,40 @@ static struct attribute *md_bitmap_attrs[] = {
>>>       NULL
>>>   };
>>>
>>> +static struct attribute *md_bitmap_common_attrs[] = {
>>> +    &bitmap_location.attr,
>>> +    NULL
>>> +};
>>> +
>>>   static struct attribute_group md_bitmap_group = {
>>>       .name = "bitmap",
>>>       .attrs = md_bitmap_attrs,
>>>   };
>>>
>>> +static struct attribute_group md_bitmap_common_group = {
>>> +    .name = "bitmap",
>>> +    .attrs = md_bitmap_common_attrs,
>>> +};
>>> +
>>> +int md_sysfs_create_common_group(struct mddev *mddev)
>>> +{
>>> +    return sysfs_create_group(&mddev->kobj, &md_bitmap_common_group);
>>> +}
>>> +
>>> +static int bitmap_register_group(struct mddev *mddev)
>>> +{
>>> +    /*
>>> +     * md_bitmap_group and md_bitmap_common_group are using same name
>>> +     * 'bitmap'.
>>> +     */
>>> +    return sysfs_merge_group(&mddev->kobj, &md_bitmap_group);
>>> +}
>>> +
>>> +static void bitmap_unregister_group(struct mddev *mddev)
>>> +{
>>> +    sysfs_unmerge_group(&mddev->kobj, &md_bitmap_group);
>>> +}
>>> +
>>>   static struct bitmap_operations bitmap_ops = {
>>>       .head = {
>>>           .type    = MD_BITMAP,
>>> @@ -3013,6 +3041,8 @@ static struct bitmap_operations bitmap_ops = {
>>>       .set_pages        = bitmap_set_pages,
>>>       .free            = md_bitmap_free,
>>>
>>> +    .register_group        = bitmap_register_group,
>>> +    .unregister_group    = bitmap_unregister_group,
>>>       .group            = &md_bitmap_group,
>>>   };
>>>
>>> diff --git a/drivers/md/md-bitmap.h b/drivers/md/md-bitmap.h
>>> index b42a28fa83a0..371791e9011d 100644
>>> --- a/drivers/md/md-bitmap.h
>>> +++ b/drivers/md/md-bitmap.h
>>> @@ -125,6 +125,9 @@ struct bitmap_operations {
>>>       void (*set_pages)(void *data, unsigned long pages);
>>>       void (*free)(void *data);
>>>
>>> +    int (*register_group)(struct mddev *mddev);
>>> +    void (*unregister_group)(struct mddev *mddev);
>>> +
>>>       struct attribute_group *group;
>>>   };
>>>
>>> @@ -169,6 +172,8 @@ static inline void md_bitmap_end_sync(struct 
>>> mddev *mddev, sector_t offset,
>>>       mddev->bitmap_ops->end_sync(mddev, offset, blocks);
>>>   }
>>>
>>> +int md_sysfs_create_common_group(struct mddev *mddev);
>>> +
>>>   #ifdef CONFIG_MD_BITMAP
>>>   int md_bitmap_init(void);
>>>   void md_bitmap_exit(void);
>>> diff --git a/drivers/md/md-llbitmap.c b/drivers/md/md-llbitmap.c
>>> index bf398d7476b3..24ff5f7f8751 100644
>>> --- a/drivers/md/md-llbitmap.c
>>> +++ b/drivers/md/md-llbitmap.c
>>> @@ -1561,6 +1561,16 @@ static struct attribute_group 
>>> md_llbitmap_group = {
>>>       .attrs = md_llbitmap_attrs,
>>>   };
>>>
>>> +static int llbitmap_register_group(struct mddev *mddev)
>>> +{
>>> +    return sysfs_create_group(&mddev->kobj, &md_llbitmap_group);
>>> +}
>>> +
>>> +static void llbitmap_unregister_group(struct mddev *mddev)
>>> +{
>>> +    sysfs_remove_group(&mddev->kobj, &md_llbitmap_group);
>>> +}
>>> +
>>>   static struct bitmap_operations llbitmap_ops = {
>>>       .head = {
>>>           .type    = MD_BITMAP,
>>> @@ -1597,6 +1607,9 @@ static struct bitmap_operations llbitmap_ops = {
>>>       .dirty_bits        = llbitmap_dirty_bits,
>>>       .write_all        = llbitmap_write_all,
>>>
>>> +    .register_group        = llbitmap_register_group,
>>> +    .unregister_group    = llbitmap_unregister_group,
>>> +
>>>       .group            = &md_llbitmap_group,
>>>   };
>>>
>>> diff --git a/drivers/md/md.c b/drivers/md/md.c
>>> index 3ce6f9e9d38e..ab969e950ea8 100644
>>> --- a/drivers/md/md.c
>>> +++ b/drivers/md/md.c
>>> @@ -703,8 +703,8 @@ static bool mddev_set_bitmap_ops(struct mddev 
>>> *mddev)
>>>       mddev->bitmap_ops = (void *)head;
>>>       xa_unlock(&md_submodule);
>>>
>>> -    if (!mddev_is_dm(mddev) && mddev->bitmap_ops->group) {
>>> -        if (sysfs_create_group(&mddev->kobj, 
>>> mddev->bitmap_ops->group))
>>> +    if (!mddev_is_dm(mddev) && mddev->bitmap_ops->register_group) {
>>> +        if (mddev->bitmap_ops->register_group(mddev))
>>>               pr_warn("md: cannot register extra bitmap attributes 
>>> for %s\n",
>>>                   mdname(mddev));
>>>           else
>>> @@ -724,8 +724,8 @@ static bool mddev_set_bitmap_ops(struct mddev 
>>> *mddev)
>>>   static void mddev_clear_bitmap_ops(struct mddev *mddev)
>>>   {
>>>       if (!mddev_is_dm(mddev) && mddev->bitmap_ops &&
>>> -        mddev->bitmap_ops->group)
>>> -        sysfs_remove_group(&mddev->kobj, mddev->bitmap_ops->group);
>>> +        mddev->bitmap_ops->unregister_group)
>>> +        mddev->bitmap_ops->unregister_group(mddev);
>>>
>>>       mddev->bitmap_ops = NULL;
>>>   }
>>> @@ -6369,6 +6369,14 @@ struct mddev *md_alloc(dev_t dev, char *name)
>>>           return ERR_PTR(error);
>>>       }
>>>
>>> +    /*
>>> +     * md_sysfs_remove_common_group is not needed because 
>>> mddev_delayed_delete
>>> +     * calls kobject_put(&mddev->kobj) if mddev is to be deleted.
>>> +     */
>>> +    if (md_sysfs_create_common_group(mddev))
>>> +        pr_warn("md: cannot register common bitmap attributes for 
>>> %s\n",
>>> +            mdname(mddev));
>>> +
>>>       kobject_uevent(&mddev->kobj, KOBJ_ADD);
>>>       mddev->sysfs_state = sysfs_get_dirent_safe(mddev->kobj.sd,   
>>> "array_state");
>>>       mddev->sysfs_level = sysfs_get_dirent_safe(mddev->kobj.sd,   
>>> "level");

-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH 2/2] md/raid5: move handle_stripe() comment to correct location
From: Yu Kuai @ 2026-03-05 17:31 UTC (permalink / raw)
  To: Chen Cheng, Song Liu, yukuai; +Cc: Li Nan, linux-raid
In-Reply-To: <20260304111001.15767-1-chencheng@fnnas.com>

在 2026/3/4 19:10, Chen Cheng 写道:

> Move the handle_stripe() documentation comment from above
> analyse_stripe() to directly above handle_stripe() where it belongs.
>
> Signed-off-by: Chen Cheng<chencheng@fnnas.com>
> ---
>   drivers/md/raid5.c | 26 ++++++++++++--------------
>   1 file changed, 12 insertions(+), 14 deletions(-)

Reviewed-by: Yu Kuai <yukuai@fnnas.com>

-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH 1/2] md/raid5: remove stale md_raid5_kick_device() declaration
From: Yu Kuai @ 2026-03-05 17:30 UTC (permalink / raw)
  To: Chen Cheng, Song Liu, yukuai; +Cc: Li Nan, linux-raid
In-Reply-To: <20260304110919.15071-1-chencheng@fnnas.com>

在 2026/3/4 19:09, Chen Cheng 写道:

> Remove the unused md_raid5_kick_device() declaration from raid5.h -
> no definition exists for this function.
>
> Signed-off-by: Chen Cheng<chencheng@fnnas.com>
> ---
>   drivers/md/raid5.h | 1 -
>   1 file changed, 1 deletion(-)

Reviewed-by: Yu Kuai <yukuai@fnnas.com>

-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH] md/raid0,linear: move error handling from make_request to IO completion
From: Yu Kuai @ 2026-03-05 17:27 UTC (permalink / raw)
  To: Chen Cheng, Song Liu, yukuai; +Cc: Li Nan, linux-raid
In-Reply-To: <20260304142907.3791-1-chencheng@fnnas.com>

Hi,

在 2026/3/4 22:29, Chen Cheng 写道:
> raid0 and linear call md_error() in the submission path after checking
> is_rdev_broken() (i.e. disk_live() == false). This was intended as a
> safety fast-fail for removed disks, but is unnecessary: the block layer
> already handles GD_DEAD disks in __bio_queue_enter() and fails IO
> immediately without hanging. More importantly, it misses the offline
> case where the disk still exists but rejects IO — in that scenario, IO
> fails silently and md_error() is never called.
>
> Remove the submission-path check and instead call md_error() from
> md_end_clone_io() on any IO failure. Store the target rdev in
> md_io_clone so the completion handler knows which device failed. This
> uniformly handles disk removal, offline status, and any other IO error.
>
> Since raid0 and linear have no redundancy, any disk IO failure means
> data is already lost, so marking the array broken on any error is
> correct.

I won't say it's correct, this will make the array more fragile, the
lost data can be insignificant for filesystem and user, and in this
case the array can still be used.

>
> Signed-off-by: Chen Cheng <chencheng@fnnas.com>
> ---
>   drivers/md/md-linear.c |  7 +------
>   drivers/md/md.c        |  5 +++++
>   drivers/md/md.h        | 11 ++++++-----
>   drivers/md/raid0.c     |  7 +------
>   4 files changed, 13 insertions(+), 17 deletions(-)
>
> diff --git a/drivers/md/md-linear.c b/drivers/md/md-linear.c
> index fdff250d0d51..2ba181a1297d 100644
> --- a/drivers/md/md-linear.c
> +++ b/drivers/md/md-linear.c
> @@ -251,12 +251,6 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
>   		     bio_sector < start_sector))
>   		goto out_of_bounds;
>   
> -	if (unlikely(is_rdev_broken(tmp_dev->rdev))) {
> -		md_error(mddev, tmp_dev->rdev);
> -		bio_io_error(bio);
> -		return true;
> -	}
> -
>   	if (unlikely(bio_end_sector(bio) > end_sector)) {
>   		/* This bio crosses a device boundary, so we have to split it */
>   		bio = bio_submit_split_bioset(bio, end_sector - bio_sector,
> @@ -269,6 +263,7 @@ static bool linear_make_request(struct mddev *mddev, struct bio *bio)
>   	bio_set_dev(bio, tmp_dev->rdev->bdev);
>   	bio->bi_iter.bi_sector = bio->bi_iter.bi_sector -
>   		start_sector + data_offset;
> +	md_set_clone_rdev((struct md_io_clone *)bio->bi_private, tmp_dev->rdev);
>   
>   	if (unlikely((bio_op(bio) == REQ_OP_DISCARD) &&
>   		     !bdev_max_discard_sectors(bio->bi_bdev))) {
> diff --git a/drivers/md/md.c b/drivers/md/md.c
> index 3ce6f9e9d38e..7caa24c4919d 100644
> --- a/drivers/md/md.c
> +++ b/drivers/md/md.c
> @@ -9218,6 +9218,7 @@ static void md_end_clone_io(struct bio *bio)
>   	struct md_io_clone *md_io_clone = bio->bi_private;
>   	struct bio *orig_bio = md_io_clone->orig_bio;
>   	struct mddev *mddev = md_io_clone->mddev;
> +	enum md_submodule_id id = mddev->pers->head.id;
>   
>   	if (bio_data_dir(orig_bio) == WRITE && md_bitmap_enabled(mddev, false))
>   		md_bitmap_end(mddev, md_io_clone);
> @@ -9225,6 +9226,10 @@ static void md_end_clone_io(struct bio *bio)
>   	if (bio->bi_status && !orig_bio->bi_status)
>   		orig_bio->bi_status = bio->bi_status;
>   
> +	if (bio->bi_status && md_io_clone->rdev &&
> +	    (id == ID_LINEAR || id == ID_RAID0))
> +		md_error(mddev, md_io_clone->rdev);

I'll suggest to introduce badblocks to linear and raid0 as well, in the case when
metadata update succeed, only call md_error() when there is too much badblocks.

> +
>   	if (md_io_clone->start_time)
>   		bio_end_io_acct(orig_bio, md_io_clone->start_time);
>   
> diff --git a/drivers/md/md.h b/drivers/md/md.h
> index ac84289664cd..625f8304de3b 100644
> --- a/drivers/md/md.h
> +++ b/drivers/md/md.h
> @@ -872,6 +872,7 @@ struct md_thread {
>   
>   struct md_io_clone {
>   	struct mddev	*mddev;
> +	struct md_rdev	*rdev;
>   	struct bio	*orig_bio;
>   	unsigned long	start_time;
>   	sector_t	offset;
> @@ -917,6 +918,11 @@ extern void md_finish_reshape(struct mddev *mddev);
>   void md_submit_discard_bio(struct mddev *mddev, struct md_rdev *rdev,
>   			struct bio *bio, sector_t start, sector_t size);
>   void md_account_bio(struct mddev *mddev, struct bio **bio);
> +static inline void md_set_clone_rdev(struct md_io_clone *clone,
> +				     struct md_rdev *rdev)
> +{
> +	clone->rdev = rdev;
> +}
>   void md_free_cloned_bio(struct bio *bio);
>   
>   extern bool __must_check md_flush_request(struct mddev *mddev, struct bio *bio);
> @@ -961,11 +967,6 @@ extern void mddev_destroy_serial_pool(struct mddev *mddev,
>   struct md_rdev *md_find_rdev_nr_rcu(struct mddev *mddev, int nr);
>   struct md_rdev *md_find_rdev_rcu(struct mddev *mddev, dev_t dev);
>   
> -static inline bool is_rdev_broken(struct md_rdev *rdev)
> -{
> -	return !disk_live(rdev->bdev->bd_disk);
> -}
> -
>   static inline void rdev_dec_pending(struct md_rdev *rdev, struct mddev *mddev)
>   {
>   	int faulty = test_bit(Faulty, &rdev->flags);
> diff --git a/drivers/md/raid0.c b/drivers/md/raid0.c
> index ef0045db409f..e933abeb0d70 100644
> --- a/drivers/md/raid0.c
> +++ b/drivers/md/raid0.c
> @@ -576,15 +576,10 @@ static void raid0_map_submit_bio(struct mddev *mddev, struct bio *bio)
>   		return;
>   	}
>   
> -	if (unlikely(is_rdev_broken(tmp_dev))) {
> -		bio_io_error(bio);
> -		md_error(mddev, tmp_dev);
> -		return;
> -	}
> -
>   	bio_set_dev(bio, tmp_dev->bdev);
>   	bio->bi_iter.bi_sector = sector + zone->dev_start +
>   		tmp_dev->data_offset;
> +	md_set_clone_rdev((struct md_io_clone *)bio->bi_private, tmp_dev);
>   	mddev_trace_remap(mddev, bio, bio_sector);
>   	mddev_check_write_zeroes(mddev, bio);
>   	submit_bio_noacct(bio);

-- 
Thansk,
Kuai

^ permalink raw reply

* [PATCH v2 2/2] md/raid1: serialize overlap io for writemostly disk
From: Xiao Ni @ 2026-03-05  1:18 UTC (permalink / raw)
  To: yukuai; +Cc: linux-raid, ncroxon
In-Reply-To: <20260305011839.5118-1-xni@redhat.com>

In behind mode, overlap bios for writemostly device are queued.
Those overlapped bios need to wait in waitqueue. They will be woken
up once the in-tree bio finishes.

Previously, using wait_event() would wake up all waiters simultaneously,
and they would compete for the tree lock. The bio which gets the lock
first will be handled, so the write sequence cannot be guaranteed.

For example:
bio1(100,200)
bio2(150,200)
bio3(150,300)

The write sequence of fast device is bio1,bio2,bio3. But the write
sequence of slow device could be bio1,bio3,bio2 due to lock competition.
This causes data corruption.

Use prepare_to_wait_exclusive() to ensure FIFO ordering. This adds
waiters to the tail of the waitqueue and wakes them from the head,
guaranteeing that bios are processed in the order they arrived.

Fixes: 3e148a320979 ("md/raid1: fix potential data inconsistency issue with write behind device")
Reviewed-by: Yu Kuai <yukuai@fnnas.com>
Signed-off-by: Xiao Ni <xni@redhat.com>
---
v2: use prepare_to_wait_exclusive
 drivers/md/raid1.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index be2565dee420..a95085fb3015 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -85,12 +85,20 @@ static void wait_for_serialization(struct md_rdev *rdev, struct r1bio *r1_bio)
 	struct serial_info *si;
 	int idx = sector_to_idx(r1_bio->sector);
 	struct serial_in_rdev *serial = &rdev->serial[idx];
+	DEFINE_WAIT(wait);
 
 	if (WARN_ON(!mddev->serial_info_pool))
 		return;
 	si = mempool_alloc(mddev->serial_info_pool, GFP_NOIO);
-	wait_event(serial->serial_io_wait,
-		   check_and_add_serial(rdev, r1_bio, si, idx) == 0);
+
+	for (;;) {
+		prepare_to_wait_exclusive(&serial->serial_io_wait, &wait,
+					  TASK_UNINTERRUPTIBLE);
+		if (check_and_add_serial(rdev, r1_bio, si, idx) == 0)
+			break;
+		schedule();
+	}
+	finish_wait(&serial->serial_io_wait, &wait);
 }
 
 static void remove_serial(struct md_rdev *rdev, sector_t lo, sector_t hi)
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH 1/2] md/raid1: fix the comparing region of interval tree
From: Xiao Ni @ 2026-03-05  1:18 UTC (permalink / raw)
  To: yukuai; +Cc: linux-raid, ncroxon
In-Reply-To: <20260305011839.5118-1-xni@redhat.com>

Interval tree uses [start, end] as a region which stores in the tree.
In raid1, it uses the wrong end value. For example:
bio(A,B) is too big and needs to be split to bio1(A,C-1), bio2(C,B).
The region of bio1 is [A,C] and the region of bio2 is [C,B]. So bio1 and
bio2 overlap which is not right.

Fix this problem by using right end value of the region.

Fixes: d0d2d8ba0494 ("md/raid1: introduce wait_for_serialization")
Signed-off-by: Xiao Ni <xni@redhat.com>
---
 drivers/md/raid1.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 181400e147c0..be2565dee420 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -62,7 +62,7 @@ static int check_and_add_serial(struct md_rdev *rdev, struct r1bio *r1_bio,
 	unsigned long flags;
 	int ret = 0;
 	sector_t lo = r1_bio->sector;
-	sector_t hi = lo + r1_bio->sectors;
+	sector_t hi = lo + r1_bio->sectors - 1;
 	struct serial_in_rdev *serial = &rdev->serial[idx];
 
 	spin_lock_irqsave(&serial->serial_lock, flags);
@@ -452,7 +452,7 @@ static void raid1_end_write_request(struct bio *bio)
 	int mirror = find_bio_disk(r1_bio, bio);
 	struct md_rdev *rdev = conf->mirrors[mirror].rdev;
 	sector_t lo = r1_bio->sector;
-	sector_t hi = r1_bio->sector + r1_bio->sectors;
+	sector_t hi = r1_bio->sector + r1_bio->sectors - 1;
 	bool ignore_error = !raid1_should_handle_error(bio) ||
 		(bio->bi_status && bio_op(bio) == REQ_OP_DISCARD);
 
-- 
2.50.1 (Apple Git-155)


^ permalink raw reply related

* [PATCH v2 0/2] md/raid1: serialize overlapped ios for writemostly device
From: Xiao Ni @ 2026-03-05  1:18 UTC (permalink / raw)
  To: yukuai; +Cc: linux-raid, ncroxon

Xiao Ni (2):
  md/raid1: fix the comparing region of interval tree
  md/raid1: serialize overlap io for writemostly disk

 drivers/md/raid1.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

-- 
2.50.1 (Apple Git-155)


^ permalink raw reply

* [PATCH 0/2] md/raid1: serialize overlapped ios for writemostly device
From: Xiao Ni @ 2026-03-05  1:16 UTC (permalink / raw)
  To: yukuai; +Cc: linux-raid, ncroxon

Xiao Ni (2):
  md/raid1: fix the comparing region of interval tree
  md/raid1: serialize overlap io for writemostly disk

 drivers/md/raid1.c | 16 ++++++++++++----
 1 file changed, 12 insertions(+), 4 deletions(-)

-- 
2.50.1 (Apple Git-155)


^ permalink raw reply

* Re: [PATCH 01/25] xor: assert that xor_blocks is not called from interrupt context
From: Christoph Hellwig @ 2026-03-04 15:42 UTC (permalink / raw)
  To: Peter Zijlstra
  Cc: Christoph Hellwig, Eric Biggers, Andrew Morton, Richard Henderson,
	Matt Turner, Magnus Lindholm, Russell King, Catalin Marinas,
	Will Deacon, Huacai Chen, WANG Xuerui, Madhavan Srinivasan,
	Michael Ellerman, Nicholas Piggin, Christophe Leroy (CS GROUP),
	Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
	Heiko Carstens, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, David S. Miller,
	Andreas Larsson, Richard Weinberger, Anton Ivanov, Johannes Berg,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Herbert Xu, Dan Williams, Chris Mason,
	David Sterba, Arnd Bergmann, Song Liu, Yu Kuai, Li Nan,
	linux-alpha, linux-kernel, linux-arm-kernel, loongarch,
	linuxppc-dev, linux-riscv, linux-s390, sparclinux, linux-um,
	linux-crypto, linux-btrfs, linux-arch, linux-raid
In-Reply-To: <20260304151548.GN1395266@noisy.programming.kicks-ass.net>

On Wed, Mar 04, 2026 at 04:15:48PM +0100, Peter Zijlstra wrote:
> On Wed, Mar 04, 2026 at 03:51:34PM +0100, Christoph Hellwig wrote:
> 
> > > How about "WARN_ON_ONCE(!preemptible())"?  I think that covers the union
> > > of the context restrictions correctly.  (Compared to in_task(), it
> > > handles the cases where hardirqs or softirqs are disabled.)
> > 
> > Good enough I guess.  Peter?
> 
> Sure. The only caveat with that is that for PREEMPT_COUNT=n this might
> not work, it unconditionally returns 0.

That's a pretty good argument for the lockdep version...

^ permalink raw reply

* Re: [PATCH 01/25] xor: assert that xor_blocks is not called from interrupt context
From: Peter Zijlstra @ 2026-03-04 15:15 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Eric Biggers, Andrew Morton, Richard Henderson, Matt Turner,
	Magnus Lindholm, Russell King, Catalin Marinas, Will Deacon,
	Huacai Chen, WANG Xuerui, Madhavan Srinivasan, Michael Ellerman,
	Nicholas Piggin, Christophe Leroy (CS GROUP), Paul Walmsley,
	Palmer Dabbelt, Albert Ou, Alexandre Ghiti, Heiko Carstens,
	Vasily Gorbik, Alexander Gordeev, Christian Borntraeger,
	Sven Schnelle, David S. Miller, Andreas Larsson,
	Richard Weinberger, Anton Ivanov, Johannes Berg, Thomas Gleixner,
	Ingo Molnar, Borislav Petkov, Dave Hansen, x86, H. Peter Anvin,
	Herbert Xu, Dan Williams, Chris Mason, David Sterba,
	Arnd Bergmann, Song Liu, Yu Kuai, Li Nan, linux-alpha,
	linux-kernel, linux-arm-kernel, loongarch, linuxppc-dev,
	linux-riscv, linux-s390, sparclinux, linux-um, linux-crypto,
	linux-btrfs, linux-arch, linux-raid
In-Reply-To: <20260304145134.GA21983@lst.de>

On Wed, Mar 04, 2026 at 03:51:34PM +0100, Christoph Hellwig wrote:

> > How about "WARN_ON_ONCE(!preemptible())"?  I think that covers the union
> > of the context restrictions correctly.  (Compared to in_task(), it
> > handles the cases where hardirqs or softirqs are disabled.)
> 
> Good enough I guess.  Peter?

Sure. The only caveat with that is that for PREEMPT_COUNT=n this might
not work, it unconditionally returns 0.

^ permalink raw reply

* Re: [PATCH 01/25] xor: assert that xor_blocks is not called from interrupt context
From: Heiko Carstens @ 2026-03-04 15:08 UTC (permalink / raw)
  To: Heiko Carstens
  Cc: Eric Biggers, Christoph Hellwig, Peter Zijlstra, Andrew Morton,
	Richard Henderson, Matt Turner, Magnus Lindholm, Russell King,
	Catalin Marinas, Will Deacon, Huacai Chen, WANG Xuerui,
	Madhavan Srinivasan, Michael Ellerman, Nicholas Piggin,
	Christophe Leroy (CS GROUP), Paul Walmsley, Palmer Dabbelt,
	Albert Ou, Alexandre Ghiti, Vasily Gorbik, Alexander Gordeev,
	Christian Borntraeger, Sven Schnelle, David S. Miller,
	Andreas Larsson, Richard Weinberger, Anton Ivanov, Johannes Berg,
	Thomas Gleixner, Ingo Molnar, Borislav Petkov, Dave Hansen, x86,
	H. Peter Anvin, Herbert Xu, Dan Williams, Chris Mason,
	David Sterba, Arnd Bergmann, Song Liu, Yu Kuai, Li Nan,
	linux-alpha, linux-kernel, linux-arm-kernel, loongarch,
	linuxppc-dev, linux-riscv, linux-s390, sparclinux, linux-um,
	linux-crypto, linux-btrfs, linux-arch, linux-raid
In-Reply-To: <20260304150142.10892A0b-hca@linux.ibm.com>

On Wed, Mar 04, 2026 at 04:01:46PM +0100, Heiko Carstens wrote:
> On Tue, Mar 03, 2026 at 11:55:17AM -0800, Eric Biggers wrote:
> > On Tue, Mar 03, 2026 at 05:00:50PM +0100, Christoph Hellwig wrote:
> > > On Fri, Feb 27, 2026 at 03:24:55PM +0100, Peter Zijlstra wrote:
> > Because of that CPU feature check, I don't think
> > "WARN_ON_ONCE(!may_use_simd())" would actually be correct here.
> > 
> > How about "WARN_ON_ONCE(!preemptible())"?  I think that covers the union
> > of the context restrictions correctly.  (Compared to in_task(), it
> > handles the cases where hardirqs or softirqs are disabled.)
> 
> I guess, this is not true, since there is at least one architecture which
> allows to run simd code in interrupt context (but which missed to implement
> may_use_simd()).

Oh, just to avoid confusion, which I may have caused: I made only
general comments about s390 simd usage. Our xor() implementation does
not make use of simd, since our normal xc instruction allows to xor up
to 256 bytes. A simd implementation wouldn't be faster.
Also here it would be possible to run it in any context.

^ permalink raw reply


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