Linux RAID subsystem development
 help / color / mirror / Atom feed
* [PATCH v3 2/2] raid6: use kmalloc() in raid6_select_algo()
From: Mike Rapoport (Microsoft) @ 2026-05-28  7:27 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Christoph Hellwig, David Laight, Li Nan, Mike Rapoport, Song Liu,
	Xiao Ni, Yu Kuai, linux-kernel, linux-mm, linux-raid
In-Reply-To: <20260528-lib-v3-0-feccddf1cb6d@kernel.org>

raid6_select_algo() allocates 8 pages for buffer that is used
as a scratch area for selection of the best algorithm.

This buffer can be allocated with kmalloc() as there's nothing special
about it to go directly to the page allocator.

kmalloc() provides a better API than ancient __get_free_pages().
kmalloc() does not require ugly casts and kfree() does not need to know the
size of the freed object.

There is no performance difference because kmalloc() redirects allocations
of such size to the page allocator.

Replace __get_free_pages() call with kmalloc().

Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
 lib/raid6/algos.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 799e0e5eac26..89e627c62e30 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/raid/pq.h>
+#include <linux/slab.h>
 #ifndef __KERNEL__
 #include <sys/mman.h>
 #include <stdio.h>
@@ -129,7 +130,6 @@ const struct raid6_recov_calls *const raid6_recov_algos[] = {
 #endif
 
 #define RAID6_TEST_DISKS	8
-#define RAID6_TEST_DISKS_ORDER	3
 
 static inline const struct raid6_recov_calls *raid6_choose_recov(void)
 {
@@ -250,7 +250,7 @@ int __init raid6_select_algo(void)
 	int i, cycle;
 
 	/* prepare the buffer and fill it circularly with gfmul table */
-	disk_ptr = (char *)__get_free_pages(GFP_KERNEL, RAID6_TEST_DISKS_ORDER);
+	disk_ptr = kmalloc(PAGE_SIZE * RAID6_TEST_DISKS, GFP_KERNEL);
 	if (!disk_ptr) {
 		pr_err("raid6: Yikes!  No memory available.\n");
 		return -ENOMEM;
@@ -275,7 +275,7 @@ int __init raid6_select_algo(void)
 	/* select raid recover functions */
 	rec_best = raid6_choose_recov();
 
-	free_pages((unsigned long)disk_ptr, RAID6_TEST_DISKS_ORDER);
+	kfree(disk_ptr);
 
 	return gen_best && rec_best ? 0 : -EINVAL;
 }

-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v3 1/2] xor: use kmalloc() in calibrate_xor_blocks()
From: Christoph Hellwig @ 2026-05-28  8:54 UTC (permalink / raw)
  To: Mike Rapoport (Microsoft)
  Cc: Andrew Morton, Christoph Hellwig, David Laight, Li Nan, Song Liu,
	Xiao Ni, Yu Kuai, linux-kernel, linux-mm, linux-raid
In-Reply-To: <20260528-lib-v3-1-feccddf1cb6d@kernel.org>

On Thu, May 28, 2026 at 10:27:55AM +0300, Mike Rapoport (Microsoft) wrote:
> -	b1 = (void *) __get_free_pages(GFP_KERNEL, 2);
> +	b1 = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
>  	if (!b1) {
>  		pr_warn("xor: Yikes!  No memory available.\n");
>  		return -ENOMEM;
> @@ -132,7 +133,7 @@ static int __init calibrate_xor_blocks(void)
>  	pr_info("xor: using function: %s (%d MB/sec)\n",
>  	       fastest->name, fastest->speed);
>  
> -	free_pages((unsigned long)b1, 2);
> +	kvfree(b1);

This should be kfree now.


^ permalink raw reply

* Re: [PATCH v3 2/2] raid6: use kmalloc() in raid6_select_algo()
From: Christoph Hellwig @ 2026-05-28  8:55 UTC (permalink / raw)
  To: Mike Rapoport (Microsoft)
  Cc: Andrew Morton, Christoph Hellwig, David Laight, Li Nan, Song Liu,
	Xiao Ni, Yu Kuai, linux-kernel, linux-mm, linux-raid
In-Reply-To: <20260528-lib-v3-2-feccddf1cb6d@kernel.org>

Looks good:

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


^ permalink raw reply

* Re: [PATCH v3 1/2] xor: use kmalloc() in calibrate_xor_blocks()
From: Mike Rapoport @ 2026-05-28  9:49 UTC (permalink / raw)
  To: Christoph Hellwig
  Cc: Andrew Morton, David Laight, Li Nan, Song Liu, Xiao Ni, Yu Kuai,
	linux-kernel, linux-mm, linux-raid
In-Reply-To: <ahgC1PDFtFrJrsKC@infradead.org>

On Thu, May 28, 2026 at 01:54:44AM -0700, Christoph Hellwig wrote:
> On Thu, May 28, 2026 at 10:27:55AM +0300, Mike Rapoport (Microsoft) wrote:
> > -	b1 = (void *) __get_free_pages(GFP_KERNEL, 2);
> > +	b1 = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
> >  	if (!b1) {
> >  		pr_warn("xor: Yikes!  No memory available.\n");
> >  		return -ENOMEM;
> > @@ -132,7 +133,7 @@ static int __init calibrate_xor_blocks(void)
> >  	pr_info("xor: using function: %s (%d MB/sec)\n",
> >  	       fastest->name, fastest->speed);
> >  
> > -	free_pages((unsigned long)b1, 2);
> > +	kvfree(b1);
> 
> This should be kfree now.

kvfree still works, but I'll send v4 for pedantry sake ;-P

-- 
Sincerely yours,
Mike.

^ permalink raw reply

* [PATCH v4 0/2] lib/raid: replace __get_free_pages() call with kvmalloc()
From: Mike Rapoport (Microsoft) @ 2026-05-28  9:52 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Christoph Hellwig, David Laight, Li Nan, Mike Rapoport, Song Liu,
	Xiao Ni, Yu Kuai, linux-kernel, linux-mm, linux-raid,
	Christoph Hellwig

This is a (tiny) part of larger work of replacing page allocator calls
with k*malloc.

Nowadays the right way to say "I need a buffer" is kmalloc() rather than
ancient and ugly __get_free_pages().

---
v4 changes:
* s/kvfee/kfree

v3: https://patch.msgid.link/20260528-lib-v3-0-feccddf1cb6d@kernel.org
* restore kmalloc() per Christoph
* update changelog

v2: https://patch.msgid.link/20260526-lib-v2-0-ca3f0fc24b14@kernel.org
* replace kmalloc() with kvmalloc()

v1: https://patch.msgid.link/20260520-lib-v1-0-cb3045bef2d8@kernel.org

---
Mike Rapoport (Microsoft) (2):
      xor: use kmalloc() in calibrate_xor_blocks()
      raid6: use kmalloc() in raid6_select_algo()

 lib/raid/xor/xor-core.c | 5 +++--
 lib/raid6/algos.c       | 6 +++---
 2 files changed, 6 insertions(+), 5 deletions(-)
---
base-commit: 5d6919055dec134de3c40167a490f33c74c12581
change-id: 20260520-lib-8afb92134307

Best regards,
--  
Sincerely yours,
Mike.


^ permalink raw reply

* [PATCH v4 1/2] xor: use kmalloc() in calibrate_xor_blocks()
From: Mike Rapoport (Microsoft) @ 2026-05-28  9:53 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Christoph Hellwig, David Laight, Li Nan, Mike Rapoport, Song Liu,
	Xiao Ni, Yu Kuai, linux-kernel, linux-mm, linux-raid
In-Reply-To: <20260528-lib-v4-0-4e3ad1277279@kernel.org>

The xor benchmark allocates 4 pages for a scratch buffer that is used
purely as a CPU-only XOR working area.

This buffer can be allocated with kmalloc() as there's nothing special
about it to go directly to the page allocator.

kmalloc() provides a better API than ancient __get_free_pages().
kmalloc() does not require ugly casts and kfree() does not need to know the
size of the freed object.

There is no performance difference because kmalloc() redirects allocations
of such size to the page allocator.

Replace __get_free_pages() call with kmalloc().

Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
---
 lib/raid/xor/xor-core.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/lib/raid/xor/xor-core.c b/lib/raid/xor/xor-core.c
index bd4e6e434418..50931fbf0324 100644
--- a/lib/raid/xor/xor-core.c
+++ b/lib/raid/xor/xor-core.c
@@ -8,6 +8,7 @@
 
 #include <linux/module.h>
 #include <linux/gfp.h>
+#include <linux/slab.h>
 #include <linux/raid/xor.h>
 #include <linux/jiffies.h>
 #include <linux/preempt.h>
@@ -114,7 +115,7 @@ static int __init calibrate_xor_blocks(void)
 	if (forced_template)
 		return 0;
 
-	b1 = (void *) __get_free_pages(GFP_KERNEL, 2);
+	b1 = kmalloc(PAGE_SIZE * 4, GFP_KERNEL);
 	if (!b1) {
 		pr_warn("xor: Yikes!  No memory available.\n");
 		return -ENOMEM;
@@ -132,7 +133,7 @@ static int __init calibrate_xor_blocks(void)
 	pr_info("xor: using function: %s (%d MB/sec)\n",
 	       fastest->name, fastest->speed);
 
-	free_pages((unsigned long)b1, 2);
+	kfree(b1);
 	return 0;
 }
 

-- 
2.53.0


^ permalink raw reply related

* [PATCH v4 2/2] raid6: use kmalloc() in raid6_select_algo()
From: Mike Rapoport (Microsoft) @ 2026-05-28  9:53 UTC (permalink / raw)
  To: Andrew Morton
  Cc: Christoph Hellwig, David Laight, Li Nan, Mike Rapoport, Song Liu,
	Xiao Ni, Yu Kuai, linux-kernel, linux-mm, linux-raid,
	Christoph Hellwig
In-Reply-To: <20260528-lib-v4-0-4e3ad1277279@kernel.org>

raid6_select_algo() allocates 8 pages for buffer that is used
as a scratch area for selection of the best algorithm.

This buffer can be allocated with kmalloc() as there's nothing special
about it to go directly to the page allocator.

kmalloc() provides a better API than ancient __get_free_pages().
kmalloc() does not require ugly casts and kfree() does not need to know the
size of the freed object.

There is no performance difference because kmalloc() redirects allocations
of such size to the page allocator.

Replace __get_free_pages() call with kmalloc().

Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
Reviewed-by: Christoph Hellwig <hch@lst.de>
---
 lib/raid6/algos.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 799e0e5eac26..89e627c62e30 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -12,6 +12,7 @@
  */
 
 #include <linux/raid/pq.h>
+#include <linux/slab.h>
 #ifndef __KERNEL__
 #include <sys/mman.h>
 #include <stdio.h>
@@ -129,7 +130,6 @@ const struct raid6_recov_calls *const raid6_recov_algos[] = {
 #endif
 
 #define RAID6_TEST_DISKS	8
-#define RAID6_TEST_DISKS_ORDER	3
 
 static inline const struct raid6_recov_calls *raid6_choose_recov(void)
 {
@@ -250,7 +250,7 @@ int __init raid6_select_algo(void)
 	int i, cycle;
 
 	/* prepare the buffer and fill it circularly with gfmul table */
-	disk_ptr = (char *)__get_free_pages(GFP_KERNEL, RAID6_TEST_DISKS_ORDER);
+	disk_ptr = kmalloc(PAGE_SIZE * RAID6_TEST_DISKS, GFP_KERNEL);
 	if (!disk_ptr) {
 		pr_err("raid6: Yikes!  No memory available.\n");
 		return -ENOMEM;
@@ -275,7 +275,7 @@ int __init raid6_select_algo(void)
 	/* select raid recover functions */
 	rec_best = raid6_choose_recov();
 
-	free_pages((unsigned long)disk_ptr, RAID6_TEST_DISKS_ORDER);
+	kfree(disk_ptr);
 
 	return gen_best && rec_best ? 0 : -EINVAL;
 }

-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v4 1/2] xor: use kmalloc() in calibrate_xor_blocks()
From: Hannes Reinecke @ 2026-05-28  9:55 UTC (permalink / raw)
  To: Mike Rapoport (Microsoft), Andrew Morton
  Cc: Christoph Hellwig, David Laight, Li Nan, Song Liu, Xiao Ni,
	Yu Kuai, linux-kernel, linux-mm, linux-raid
In-Reply-To: <20260528-lib-v4-1-4e3ad1277279@kernel.org>

On 5/28/26 11:53, Mike Rapoport (Microsoft) wrote:
> The xor benchmark allocates 4 pages for a scratch buffer that is used
> purely as a CPU-only XOR working area.
> 
> This buffer can be allocated with kmalloc() as there's nothing special
> about it to go directly to the page allocator.
> 
> kmalloc() provides a better API than ancient __get_free_pages().
> kmalloc() does not require ugly casts and kfree() does not need to know the
> size of the freed object.
> 
> There is no performance difference because kmalloc() redirects allocations
> of such size to the page allocator.
> 
> Replace __get_free_pages() call with kmalloc().
> 
> Link: https://lore.kernel.org/all/635405e4-9423-4a25-a6e7-e03c8ea0bcbe@redhat.com
> Signed-off-by: Mike Rapoport (Microsoft) <rppt@kernel.org>
> ---
>   lib/raid/xor/xor-core.c | 5 +++--
>   1 file changed, 3 insertions(+), 2 deletions(-)
> 
Reviewed-by: Hannes Reinecke <hare@kernel.org>

Cheers,

Hannes
-- 
Dr. Hannes Reinecke                  Kernel Storage Architect
hare@suse.de                                +49 911 74053 688
SUSE Software Solutions GmbH, Frankenstr. 146, 90461 Nürnberg
HRB 36809 (AG Nürnberg), GF: I. Totev, A. McDonald, W. Knoblich

^ permalink raw reply

* Re: [PATCH v4 1/2] xor: use kmalloc() in calibrate_xor_blocks()
From: Christoph Hellwig @ 2026-05-28 12:47 UTC (permalink / raw)
  To: Mike Rapoport (Microsoft)
  Cc: Andrew Morton, Christoph Hellwig, David Laight, Li Nan, Song Liu,
	Xiao Ni, Yu Kuai, linux-kernel, linux-mm, linux-raid
In-Reply-To: <20260528-lib-v4-1-4e3ad1277279@kernel.org>

Looks good:

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


^ permalink raw reply

* [PATCH v2 30/34] md-bitmap: Convert read_file_page and write_file_page to bh_submit()
From: Matthew Wilcox (Oracle) @ 2026-05-28 17:31 UTC (permalink / raw)
  To: Jan Kara
  Cc: Matthew Wilcox (Oracle), Christian Brauner, Christoph Hellwig,
	linux-fsdevel, linux-raid
In-Reply-To: <20260528173150.1093780-1-willy@infradead.org>

Avoid an extra indirect function call by using bh_submit() instead of
submit_bh().

Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
Cc: linux-raid@vger.kernel.org
---
 drivers/md/md-bitmap.c | 27 ++++++++++++++-------------
 1 file changed, 14 insertions(+), 13 deletions(-)

diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
index 028b9ca8ce52..7d778fe1c47c 100644
--- a/drivers/md/md-bitmap.c
+++ b/drivers/md/md-bitmap.c
@@ -502,6 +502,18 @@ static void write_sb_page(struct bitmap *bitmap, unsigned long pg_index,
 static void md_bitmap_file_kick(struct bitmap *bitmap);
 
 #ifdef CONFIG_MD_BITMAP_FILE
+static void end_bitmap_write(struct bio *bio)
+{
+	struct buffer_head *bh;
+	bool uptodate = bio_endio_bh(bio, &bh);
+	struct bitmap *bitmap = bh->b_private;
+
+	if (!uptodate)
+		set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
+	if (atomic_dec_and_test(&bitmap->pending_writes))
+		wake_up(&bitmap->write_wait);
+}
+
 static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
 {
 	struct buffer_head *bh = page_buffers(page);
@@ -510,7 +522,7 @@ static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
 		atomic_inc(&bitmap->pending_writes);
 		set_buffer_locked(bh);
 		set_buffer_mapped(bh);
-		submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
+		bh_submit(bh, REQ_OP_WRITE | REQ_SYNC, end_bitmap_write);
 		bh = bh->b_this_page;
 	}
 
@@ -519,16 +531,6 @@ static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
 			   atomic_read(&bitmap->pending_writes) == 0);
 }
 
-static void end_bitmap_write(struct buffer_head *bh, int uptodate)
-{
-	struct bitmap *bitmap = bh->b_private;
-
-	if (!uptodate)
-		set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
-	if (atomic_dec_and_test(&bitmap->pending_writes))
-		wake_up(&bitmap->write_wait);
-}
-
 static void free_buffers(struct page *page)
 {
 	struct buffer_head *bh;
@@ -592,12 +594,11 @@ static int read_file_page(struct file *file, unsigned long index,
 			else
 				count -= blocksize;
 
-			bh->b_end_io = end_bitmap_write;
 			bh->b_private = bitmap;
 			atomic_inc(&bitmap->pending_writes);
 			set_buffer_locked(bh);
 			set_buffer_mapped(bh);
-			submit_bh(REQ_OP_READ, bh);
+			bh_submit(bh, REQ_OP_READ, end_bitmap_write);
 		}
 		blk_cur++;
 		bh = bh->b_this_page;
-- 
2.47.3


^ permalink raw reply related

* Re: [PATCH 0/8] ARM crc64 and XOR using NEON intrinsics
From: Eric Biggers @ 2026-05-28 20:35 UTC (permalink / raw)
  To: Ard Biesheuvel
  Cc: linux-arm-kernel, linux-crypto, linux-raid, Ard Biesheuvel,
	Christoph Hellwig, Russell King, Arnd Bergmann
In-Reply-To: <20260422171655.3437334-10-ardb+git@google.com>

On Wed, Apr 22, 2026 at 07:16:56PM +0200, Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
> 
> This is a follow-up to both [0] and [1], both of which included patch #1
> of this series, which introduces the asm/neon-intrinsics.h header on
> 32-bit ARM. The remaining changes rely on this.
> 
> The purpose of this series is to streamline / clean up the use of NEON
> intrinsics on 32-bit ARM, by sharing more code, clean up Make rules and
> finally, getting rid of the hacked up types.h header, which does some
> nasty things that are only needed when building NEON intrinsics code.
> 
> Patches #2 and #3 replace the ARM autovectorized XOR implementation with
> the NEON intrinsics version used by arm64.
> 
> Patches #4 and #5 enable the arm64 NEON intrinsics implementation of
> crc64 on 32-bit ARM.
> 
> Patches #6 and #7 drop the direct includes of <arm_neon.h> and perform
> some additional cleanup to reduce the delta between ARM and arm64 code
> and Make rules.
> 
> It would probably be easiest to take all these changes through a single
> tree, and the CRC tree seems like a suitable candidate, if Eric agrees.
> 
> Cc: Christoph Hellwig <hch@lst.de>
> Cc: Russell King <linux@armlinux.org.uk>
> Cc: Arnd Bergmann <arnd@arndb.de>
> Cc: Eric Biggers <ebiggers@kernel.org>
> 
> [0] https://lore.kernel.org/all/20260331074940.55502-7-ardb+git@google.com/
> [1] https://lore.kernel.org/all/20260330144630.33026-7-ardb@kernel.org/
> 
> Ard Biesheuvel (8):
>   ARM: Add a neon-intrinsics.h header like on arm64
>   xor/arm: Replace vectorized implementation with arm64's intrinsics
>   xor/arm64: Use shared NEON intrinsics implementation from 32-bit ARM
>   lib/crc: Turn NEON intrinsics crc64 implementation into common code
>   lib/crc: arm: Enable arm64's NEON intrinsics implementation of crc64
>   crypto: aegis128 - Use neon-intrinsics.h on ARM too
>   lib/raid6: Include asm/neon-intrinsics.h rather than arm_neon.h
>   ARM: Remove hacked-up asm/types.h header

Applied patches 1-6 to
https://git.kernel.org/pub/scm/linux/kernel/git/ebiggers/linux.git/log/?h=crc-next

- Eric

^ permalink raw reply

* Re: [PATCH v4 0/2] lib/raid: replace __get_free_pages() call with kvmalloc()
From: Andrew Morton @ 2026-05-28 22:03 UTC (permalink / raw)
  To: Mike Rapoport (Microsoft)
  Cc: Christoph Hellwig, David Laight, Li Nan, Song Liu, Xiao Ni,
	Yu Kuai, linux-kernel, linux-mm, linux-raid, Christoph Hellwig
In-Reply-To: <20260528-lib-v4-0-4e3ad1277279@kernel.org>

On Thu, 28 May 2026 12:52:59 +0300 "Mike Rapoport (Microsoft)" <rppt@kernel.org> wrote:

> Subject: [PATCH v4 0/2] lib/raid: replace __get_free_pages() call with kvmalloc()

I'll rewrite this to "... kmalloc()"

^ permalink raw reply

* two small RAID1 cleanups
From: Christoph Hellwig @ 2026-05-29  5:42 UTC (permalink / raw)
  To: Song Liu, Yu Kuai; +Cc: Li Nan, Xiao Ni, linux-raid

Hi all,

this series has two little cleanups that helped me understand the
code when reading through it.

Diffstat:
 raid1.c |   44 ++++++++++++++++++++------------------------
 1 file changed, 20 insertions(+), 24 deletions(-)

^ permalink raw reply

* [PATCH 1/2] md/raid1: cleanup handle_read_error
From: Christoph Hellwig @ 2026-05-29  5:42 UTC (permalink / raw)
  To: Song Liu, Yu Kuai; +Cc: Li Nan, Xiao Ni, linux-raid
In-Reply-To: <20260529054308.2720300-1-hch@lst.de>

Unwind the main conditional with duplicate conditions and initialize
variables at initialization time where possible.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 drivers/md/raid1.c | 34 ++++++++++++++++------------------
 1 file changed, 16 insertions(+), 18 deletions(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 64d970e2ef50..8fad1692cf66 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2627,35 +2627,33 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
 
 static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
 {
+	struct md_rdev *rdev = conf->mirrors[r1_bio->read_disk].rdev;
+	struct bio *bio = r1_bio->bios[r1_bio->read_disk];
 	struct mddev *mddev = conf->mddev;
-	struct bio *bio;
-	struct md_rdev *rdev;
 	sector_t sector;
 
 	clear_bit(R1BIO_ReadError, &r1_bio->state);
-	/* we got a read error. Maybe the drive is bad.  Maybe just
-	 * the block and we can fix it.
-	 * We freeze all other IO, and try reading the block from
-	 * other devices.  When we find one, we re-write
-	 * and check it that fixes the read error.
-	 * This is all done synchronously while the array is
-	 * frozen
-	 */
 
-	bio = r1_bio->bios[r1_bio->read_disk];
 	bio_put(bio);
 	r1_bio->bios[r1_bio->read_disk] = NULL;
 
-	rdev = conf->mirrors[r1_bio->read_disk].rdev;
-	if (mddev->ro == 0
-	    && !test_bit(FailFast, &rdev->flags)) {
+	/*
+	 * We got a read error. Maybe the drive is bad.  Maybe just the block
+	 * and we can fix it.
+	 *
+	 * If allowed, freeze all other IO, and try reading the block from other
+	 * devices.  If we find one, we re-write and check it that fixes the
+	 * read error.  This is all done synchronously while the array is
+	 * frozen.
+	 */
+	if (mddev->ro) {
+		r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
+	} else if (test_bit(FailFast, &rdev->flags)) {
+		md_error(mddev, rdev);
+	} else {
 		freeze_array(conf, 1);
 		fix_read_error(conf, r1_bio);
 		unfreeze_array(conf);
-	} else if (mddev->ro == 0 && test_bit(FailFast, &rdev->flags)) {
-		md_error(mddev, rdev);
-	} else {
-		r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
 	}
 
 	rdev_dec_pending(rdev, conf->mddev);
-- 
2.53.0


^ permalink raw reply related

* [PATCH 2/2] md/raid1: move the exceed_read_errors condition out of fix_read_error
From: Christoph Hellwig @ 2026-05-29  5:43 UTC (permalink / raw)
  To: Song Liu, Yu Kuai; +Cc: Li Nan, Xiao Ni, linux-raid
In-Reply-To: <20260529054308.2720300-1-hch@lst.de>

This condition much better fits into the only caller, limiting
fix_read_error to actually fix up data devices after a read error.

Signed-off-by: Christoph Hellwig <hch@lst.de>
---
 drivers/md/raid1.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 8fad1692cf66..e510ad7eef32 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2411,11 +2411,6 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
 	struct mddev *mddev = conf->mddev;
 	struct md_rdev *rdev = conf->mirrors[read_disk].rdev;
 
-	if (exceed_read_errors(mddev, rdev)) {
-		r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
-		return;
-	}
-
 	while(sectors) {
 		int s = sectors;
 		int d = read_disk;
@@ -2652,7 +2647,10 @@ static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
 		md_error(mddev, rdev);
 	} else {
 		freeze_array(conf, 1);
-		fix_read_error(conf, r1_bio);
+		if (exceed_read_errors(mddev, rdev))
+			r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
+		else
+			fix_read_error(conf, r1_bio);
 		unfreeze_array(conf);
 	}
 
-- 
2.53.0


^ permalink raw reply related

* Re: [PATCH v2 30/34] md-bitmap: Convert read_file_page and write_file_page to bh_submit()
From: Jan Kara @ 2026-05-30 11:58 UTC (permalink / raw)
  To: Matthew Wilcox (Oracle)
  Cc: Jan Kara, Christian Brauner, Christoph Hellwig, linux-fsdevel,
	linux-raid
In-Reply-To: <20260528173150.1093780-31-willy@infradead.org>

On Thu 28-05-26 18:31:43, Matthew Wilcox (Oracle) wrote:
> Avoid an extra indirect function call by using bh_submit() instead of
> submit_bh().
> 
> Signed-off-by: Matthew Wilcox (Oracle) <willy@infradead.org>
> Cc: linux-raid@vger.kernel.org

Looks good. Feel free to add:

Reviewed-by: Jan Kara <jack@suse.cz>

								Honza

> ---
>  drivers/md/md-bitmap.c | 27 ++++++++++++++-------------
>  1 file changed, 14 insertions(+), 13 deletions(-)
> 
> diff --git a/drivers/md/md-bitmap.c b/drivers/md/md-bitmap.c
> index 028b9ca8ce52..7d778fe1c47c 100644
> --- a/drivers/md/md-bitmap.c
> +++ b/drivers/md/md-bitmap.c
> @@ -502,6 +502,18 @@ static void write_sb_page(struct bitmap *bitmap, unsigned long pg_index,
>  static void md_bitmap_file_kick(struct bitmap *bitmap);
>  
>  #ifdef CONFIG_MD_BITMAP_FILE
> +static void end_bitmap_write(struct bio *bio)
> +{
> +	struct buffer_head *bh;
> +	bool uptodate = bio_endio_bh(bio, &bh);
> +	struct bitmap *bitmap = bh->b_private;
> +
> +	if (!uptodate)
> +		set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
> +	if (atomic_dec_and_test(&bitmap->pending_writes))
> +		wake_up(&bitmap->write_wait);
> +}
> +
>  static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
>  {
>  	struct buffer_head *bh = page_buffers(page);
> @@ -510,7 +522,7 @@ static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
>  		atomic_inc(&bitmap->pending_writes);
>  		set_buffer_locked(bh);
>  		set_buffer_mapped(bh);
> -		submit_bh(REQ_OP_WRITE | REQ_SYNC, bh);
> +		bh_submit(bh, REQ_OP_WRITE | REQ_SYNC, end_bitmap_write);
>  		bh = bh->b_this_page;
>  	}
>  
> @@ -519,16 +531,6 @@ static void write_file_page(struct bitmap *bitmap, struct page *page, int wait)
>  			   atomic_read(&bitmap->pending_writes) == 0);
>  }
>  
> -static void end_bitmap_write(struct buffer_head *bh, int uptodate)
> -{
> -	struct bitmap *bitmap = bh->b_private;
> -
> -	if (!uptodate)
> -		set_bit(BITMAP_WRITE_ERROR, &bitmap->flags);
> -	if (atomic_dec_and_test(&bitmap->pending_writes))
> -		wake_up(&bitmap->write_wait);
> -}
> -
>  static void free_buffers(struct page *page)
>  {
>  	struct buffer_head *bh;
> @@ -592,12 +594,11 @@ static int read_file_page(struct file *file, unsigned long index,
>  			else
>  				count -= blocksize;
>  
> -			bh->b_end_io = end_bitmap_write;
>  			bh->b_private = bitmap;
>  			atomic_inc(&bitmap->pending_writes);
>  			set_buffer_locked(bh);
>  			set_buffer_mapped(bh);
> -			submit_bh(REQ_OP_READ, bh);
> +			bh_submit(bh, REQ_OP_READ, end_bitmap_write);
>  		}
>  		blk_cur++;
>  		bh = bh->b_this_page;
> -- 
> 2.47.3
> 
-- 
Jan Kara <jack@suse.com>
SUSE Labs, CR

^ permalink raw reply

* [PATCH] raid1: fix nr_pending leak in REQ_ATOMIC bad-block error path
From: Abd-Alrhman Masalkhi @ 2026-05-30 15:14 UTC (permalink / raw)
  To: song, yukuai, linan122, john.g.garry, martin.petersen, axboe
  Cc: linux-raid, linux-kernel, Abd-Alrhman Masalkhi

In raid1_write_request(), each per-mirror loop iteration begins by
incrementing rdev->nr_pending. If a REQ_ATOMIC write encounters a
badblock within the requested range, the code jumps to err_handle
without dropping the reference taken for the current mirror.

err_handle's cleanup loop will only decrements for k < i and
r1_bio->bios[k] is non-NULL. The current slot is therefore skipped,
leaving its nr_pending reference leaked permanently. The reference
prevents the rdev from ever being removed, since raid1_remove_conf()
refuses to remove an rdev with nr_pending > 0.

Fix this by calling rdev_dec_pending() before jumping to err_handle.

Fixes: f2a38abf5f1c ("md/raid1: Atomic write support")
Signed-off-by: Abd-Alrhman Masalkhi <abd.masalkhi@gmail.com>
---
 drivers/md/raid1.c | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 181400e147c0..0084bbc24076 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -1580,8 +1580,10 @@ static void raid1_write_request(struct mddev *mddev, struct bio *bio,
 				 * complexity of supporting that is not worth
 				 * the benefit.
 				 */
-				if (bio->bi_opf & REQ_ATOMIC)
+				if (bio->bi_opf & REQ_ATOMIC) {
+					rdev_dec_pending(rdev, mddev);
 					goto err_handle;
+				}
 
 				good_sectors = first_bad - r1_bio->sector;
 				if (good_sectors < max_sectors)
-- 
2.43.0


^ permalink raw reply related

* Re: two small RAID1 cleanups
From: Yu Kuai @ 2026-05-31 10:19 UTC (permalink / raw)
  To: Christoph Hellwig, Song Liu, yukuai; +Cc: Li Nan, Xiao Ni, linux-raid
In-Reply-To: <20260529054308.2720300-1-hch@lst.de>

在 2026/5/29 13:42, Christoph Hellwig 写道:

> Hi all,
>
> this series has two little cleanups that helped me understand the
> code when reading through it.
>
> Diffstat:
>   raid1.c |   44 ++++++++++++++++++++------------------------
>   1 file changed, 20 insertions(+), 24 deletions(-)
Applied to md-7.2

-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH] raid1: fix nr_pending leak in REQ_ATOMIC bad-block error path
From: Yu Kuai @ 2026-05-31 10:21 UTC (permalink / raw)
  To: Abd-Alrhman Masalkhi, song, yukuai, john.g.garry, martin.petersen,
	axboe
  Cc: linux-raid, linux-kernel
In-Reply-To: <20260530151411.4119-1-abd.masalkhi@gmail.com>

在 2026/5/30 23:14, Abd-Alrhman Masalkhi 写道:

> In raid1_write_request(), each per-mirror loop iteration begins by
> incrementing rdev->nr_pending. If a REQ_ATOMIC write encounters a
> badblock within the requested range, the code jumps to err_handle
> without dropping the reference taken for the current mirror.
>
> err_handle's cleanup loop will only decrements for k < i and
> r1_bio->bios[k] is non-NULL. The current slot is therefore skipped,
> leaving its nr_pending reference leaked permanently. The reference
> prevents the rdev from ever being removed, since raid1_remove_conf()
> refuses to remove an rdev with nr_pending > 0.
>
> Fix this by calling rdev_dec_pending() before jumping to err_handle.
>
> Fixes: f2a38abf5f1c ("md/raid1: Atomic write support")
> Signed-off-by: Abd-Alrhman Masalkhi<abd.masalkhi@gmail.com>
> ---
>   drivers/md/raid1.c | 4 +++-
>   1 file changed, 3 insertions(+), 1 deletion(-)
Applied to md-7.2

-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH v3 1/2] md/raid10: make r10bio_pool use fixed-size objects
From: Yu Kuai @ 2026-05-31 10:36 UTC (permalink / raw)
  To: Chen Cheng, linux-raid, yukuai; +Cc: linux-kernel
In-Reply-To: <20260525015520.2565423-2-chencheng@fnnas.com>

Hi,

在 2026/5/25 9:55, Chen Cheng 写道:
> From: Chen Cheng <chencheng@fnnas.com>
>
> raid10 currently allocates r10bio_pool objects with conf->geo.raid_disks,
> which makes regular r10bio objects geometry-dependent.
>
> That model breaks down across reshape. mempool objects are preallocated and
> reused, so a reshape that changes the number of raid disks can leave old
> r10bio objects in the regular I/O pool with a devs[] array sized for the
> previous geometry. After the geometry switch, those stale objects may be
> reused or later freed under the new layout, creating a width mismatch
> between the reused r10bio and the current array geometry.
>
> For example, during a 4-disk to 5-disk reshape, an r10bio allocated before
> the geometry switch has room for only 4 devs[] entries. After reshape
> updates conf->geo.raid_disks to 5, that stale object can be reused under
> the new geometry. Code such as __make_request(), put_all_bios(), and
> find_bio_disk() may then access devs[] using the new geometry and step
> past the end of the old 4-slot object, leading to slab out-of-bounds
> accesses.
>
> The root problem is that regular r10bio pool objects are geometry-dependent,
> while mempool elements are preallocated and reused across requests.
>
> Switch r10bio_pool to a fixed-size kmalloc mempool so regular I/O objects no
> longer carry an allocation width tied to the current geometry. Use the same
> fixed-size allocation rule for the standalone r10bio allocated from
> r10buf_pool_alloc().
>
> Signed-off-by: Chen Cheng <chencheng@fnnas.com>
> ---
>   drivers/md/raid10.c | 57 ++++++++++++++++++++++++++++++++++-----------
>   drivers/md/raid10.h |  2 +-
>   2 files changed, 45 insertions(+), 14 deletions(-)
>
> diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
> index 39085e7dd6d2..64677dbe5152 100644
> --- a/drivers/md/raid10.c
> +++ b/drivers/md/raid10.c
> @@ -101,17 +101,32 @@ static void end_reshape(struct r10conf *conf);
>   static inline struct r10bio *get_resync_r10bio(struct bio *bio)
>   {
>   	return get_resync_pages(bio)->raid_bio;
>   }
>   
> -static void * r10bio_pool_alloc(gfp_t gfp_flags, void *data)
> +static inline unsigned int calc_r10bio_pool_disks(struct mddev *mddev)
>   {
> -	struct r10conf *conf = data;
> -	int size = offsetof(struct r10bio, devs[conf->geo.raid_disks]);
> +	/* If delta_disks < 0, use bigger r10bio->devs[] is ok. */
> +	return mddev->raid_disks + max(0, mddev->delta_disks);
> +}
> +
> +static inline int calc_r10bio_size(struct mddev *mddev)
> +{
> +	return offsetof(struct r10bio, devs[calc_r10bio_pool_disks(mddev)]);
> +}
> +
> +static mempool_t *create_r10bio_pool(struct mddev *mddev)
> +{
> +	int size = calc_r10bio_size(mddev);
> +
> +	return mempool_create_kmalloc_pool(NR_RAID_BIOS, size);
> +}
> +
> +static struct r10bio *alloc_r10bio(struct mddev *mddev, gfp_t gfp_flags)
> +{
> +	int size = calc_r10bio_size(mddev);
>   
> -	/* allocate a r10bio with room for raid_disks entries in the
> -	 * bios array */
>   	return kzalloc(size, gfp_flags);
>   }
>   
>   #define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
>   /* amount of memory to reserve for resync requests */
> @@ -135,11 +150,11 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
>   	struct bio *bio;
>   	int j;
>   	int nalloc, nalloc_rp;
>   	struct resync_pages *rps;
>   
> -	r10_bio = r10bio_pool_alloc(gfp_flags, conf);
> +	r10_bio = alloc_r10bio(conf->mddev, gfp_flags);
>   	if (!r10_bio)
>   		return NULL;
>   
>   	if (test_bit(MD_RECOVERY_SYNC, &conf->mddev->recovery) ||
>   	    test_bit(MD_RECOVERY_RESHAPE, &conf->mddev->recovery))
> @@ -275,11 +290,11 @@ static void put_all_bios(struct r10conf *conf, struct r10bio *r10_bio)
>   static void free_r10bio(struct r10bio *r10_bio)
>   {
>   	struct r10conf *conf = r10_bio->mddev->private;
>   
>   	put_all_bios(conf, r10_bio);
> -	mempool_free(r10_bio, &conf->r10bio_pool);
> +	mempool_free(r10_bio, conf->r10bio_pool);
>   }
>   
>   static void put_buf(struct r10bio *r10_bio)
>   {
>   	struct r10conf *conf = r10_bio->mddev->private;
> @@ -1529,11 +1544,11 @@ static void raid10_write_request(struct mddev *mddev, struct bio *bio,
>   static void __make_request(struct mddev *mddev, struct bio *bio, int sectors)
>   {
>   	struct r10conf *conf = mddev->private;
>   	struct r10bio *r10_bio;
>   
> -	r10_bio = mempool_alloc(&conf->r10bio_pool, GFP_NOIO);
> +	r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
>   
>   	r10_bio->master_bio = bio;
>   	r10_bio->sectors = sectors;
>   
>   	r10_bio->mddev = mddev;
> @@ -1721,11 +1736,11 @@ static int raid10_handle_discard(struct mddev *mddev, struct bio *bio)
>   		last_stripe_index *= geo->far_copies;
>   	end_disk_offset = (bio_end & geo->chunk_mask) +
>   				(last_stripe_index << geo->chunk_shift);
>   
>   retry_discard:
> -	r10_bio = mempool_alloc(&conf->r10bio_pool, GFP_NOIO);
> +	r10_bio = mempool_alloc(conf->r10bio_pool, GFP_NOIO);
>   	r10_bio->mddev = mddev;
>   	r10_bio->state = 0;
>   	r10_bio->sectors = 0;
>   	memset(r10_bio->devs, 0, sizeof(r10_bio->devs[0]) * geo->raid_disks);
>   	wait_blocked_dev(mddev, r10_bio);
> @@ -3821,11 +3836,11 @@ static int setup_geo(struct geom *geo, struct mddev *mddev, enum geo_type new)
>   static void raid10_free_conf(struct r10conf *conf)
>   {
>   	if (!conf)
>   		return;
>   
> -	mempool_exit(&conf->r10bio_pool);
> +	mempool_destroy(conf->r10bio_pool);
>   	kfree(conf->mirrors);
>   	kfree(conf->mirrors_old);
>   	kfree(conf->mirrors_new);
>   	safe_put_page(conf->tmppage);
>   	bioset_exit(&conf->bio_split);
> @@ -3868,13 +3883,12 @@ static struct r10conf *setup_conf(struct mddev *mddev)
>   	if (!conf->tmppage)
>   		goto out;
>   
>   	conf->geo = geo;
>   	conf->copies = copies;
> -	err = mempool_init(&conf->r10bio_pool, NR_RAID_BIOS, r10bio_pool_alloc,
> -			   rbio_pool_free, conf);
> -	if (err)
> +	conf->r10bio_pool = create_r10bio_pool(mddev);
> +	if (!conf->r10bio_pool)
>   		goto out;
>   
>   	err = bioset_init(&conf->bio_split, BIO_POOL_SIZE, 0, 0);
>   	if (err)
>   		goto out;
> @@ -4363,10 +4377,11 @@ static int raid10_start_reshape(struct mddev *mddev)
>   	struct geom new;
>   	struct r10conf *conf = mddev->private;
>   	struct md_rdev *rdev;
>   	int spares = 0;
>   	int ret;
> +	mempool_t *new_pool;
>   
>   	if (test_bit(MD_RECOVERY_RUNNING, &mddev->recovery))
>   		return -EBUSY;
>   
>   	if (setup_geo(&new, mddev, geo_start) != conf->copies)
> @@ -4398,11 +4413,23 @@ static int raid10_start_reshape(struct mddev *mddev)
>   		return -EINVAL;
>   
>   	if (spares < mddev->delta_disks)
>   		return -EINVAL;
>   
> +	mddev_unlock(mddev);
> +	mddev_suspend_and_lock_nointr(mddev);

This is weird, unless there is a strong reason, this is not acceptable to
unlock and then lock again.

Please check all the callers of pers->start_reshape, and if it's possible
to suspend before the lock.

>   	conf->offset_diff = min_offset_diff;
> +	if (mddev->delta_disks > 0) {
> +		new_pool = create_r10bio_pool(mddev);
> +		if (!new_pool) {
> +			mddev_unlock_and_resume(mddev);
> +			mddev_lock_nointr(mddev);
> +			return -ENOMEM;
> +		}
> +		mempool_destroy(conf->r10bio_pool);
> +		conf->r10bio_pool = new_pool;
> +	}
>   	spin_lock_irq(&conf->device_lock);
>   	if (conf->mirrors_new) {
>   		memcpy(conf->mirrors_new, conf->mirrors,
>   		       sizeof(struct raid10_info)*conf->prev.raid_disks);
>   		smp_mb();
> @@ -4415,20 +4442,24 @@ static int raid10_start_reshape(struct mddev *mddev)
>   	smp_mb();
>   	if (mddev->reshape_backwards) {
>   		sector_t size = raid10_size(mddev, 0, 0);
>   		if (size < mddev->array_sectors) {
>   			spin_unlock_irq(&conf->device_lock);
> +			mddev_unlock_and_resume(mddev);
> +			mddev_lock_nointr(mddev);
>   			pr_warn("md/raid10:%s: array size must be reduce before number of disks\n",
>   				mdname(mddev));
>   			return -EINVAL;
>   		}
>   		mddev->resync_max_sectors = size;
>   		conf->reshape_progress = size;
>   	} else
>   		conf->reshape_progress = 0;
>   	conf->reshape_safe = conf->reshape_progress;
>   	spin_unlock_irq(&conf->device_lock);
> +	mddev_unlock_and_resume(mddev);
> +	mddev_lock_nointr(mddev);
>   
>   	if (mddev->delta_disks && mddev->bitmap) {
>   		struct mdp_superblock_1 *sb = NULL;
>   		sector_t oldsize, newsize;
>   
> diff --git a/drivers/md/raid10.h b/drivers/md/raid10.h
> index ec79d87fb92f..b711626a5db7 100644
> --- a/drivers/md/raid10.h
> +++ b/drivers/md/raid10.h
> @@ -85,11 +85,11 @@ struct r10conf {
>   	int			have_replacement; /* There is at least one
>   						   * replacement device.
>   						   */
>   	wait_queue_head_t	wait_barrier;
>   
> -	mempool_t		r10bio_pool;
> +	mempool_t		*r10bio_pool;
>   	mempool_t		r10buf_pool;
>   	struct page		*tmppage;
>   	struct bio_set		bio_split;
>   
>   	/* When taking over an array from a different personality, we store

-- 
Thansk,
Kuai

^ permalink raw reply

* Re: [PATCH v3 0/2] md/raid10: fix r10bio width mismatches across reshape
From: Yu Kuai @ 2026-05-31 10:46 UTC (permalink / raw)
  To: Chen Cheng, linux-raid, yukuai; +Cc: linux-kernel
In-Reply-To: <20260525015520.2565423-1-chencheng@fnnas.com>

Hi,

在 2026/5/25 9:55, Chen Cheng 写道:
> From: Chen Cheng <chencheng@fnnas.com>
>
> Hi,
>
> This series fixes slab out-of-bounds accesses in raid10 when reshape changes
> the number of raid disks while regular I/O is still reusing r10bio objects
> allocated under the previous geometry.
>
> The bug is reproducible with a simple 4-disk to 5-disk reshape under write
> load, for example:
>
>    mdadm -C /dev/md777 -l10 -n4 /dev/sda /dev/sdb /dev/sdc /dev/sdd
>    mkfs.ext4 /dev/md777
>    mount /dev/md777 /mnt/test
>    fsstress -d /mnt/test -n 24000 -p 8 -l 24 &
>    mdadm /dev/md777 --add /dev/sde
>    mdadm --grow /dev/md777 --raid-devices=5 \
>      --backup-file=/tmp/md-reshape-backup
>
> Without these changes, an r10bio allocated under the old geometry can later be
> reused, initialized, or freed after conf->geo.raid_disks has switched to the
> new geometry. This creates width mismatches between the object and the current
> devs[] walk/initialization width, which can trigger KASAN reports such as
> slab-out-of-bounds in __make_request(), put_all_bios(), or find_bio_disk().
>
> This series addresses the problem in two steps:
>
>    1. make the regular r10bio pool fixed-size across reshape transitions, and
>       move the pool rebuild into the freeze window before the live geometry
>       switch;
>
>    2. track the number of valid devs[] entries in each reused r10bio and use
>       that recorded width when walking devs[] after reshape.
>
>
> Changes in v3:
>     - Replace freeze_array()/unfreeze_array() in raid10_start_reshape() with
>       mddev_suspend_and_lock_nointr()/mddev_unlock_and_resume(). freeze_array()
>       returns when nr_pending == nr_queued, which still allows retry-list items
>       to hold pool objects; mddev_suspend() provides the correct upper-layer
>       quiesce interface. (Suggested by Yu Kuai)
>
>
> Changes in v2:
>    - add this cover letter
>    - convert r10bio_pool to a fixed-size kmalloc mempool
>    - rebuild r10bio_pool inside the freeze window before switching live reshape
>      geometry
>    - switch raid10_quiesce() to freeze_array()/unfreeze_array()
>
>
> Testing:
>    - reproduced the original KASAN slab-out-of-bounds on 4-disk -> 5-disk
>      raid10 reshape with fsstress
>    - verified that this series fixes that reproducer
>    - exercised the 5-disk -> 4-disk reshape direction as well
>
> Thanks,
> Chen Cheng
>
> Chen Cheng (2):
>    md/raid10: make r10bio_pool use fixed-size objects
>    md/raid10: bound reused r10bio devs[] walks by used_nr_devs
>
>   drivers/md/raid10.c | 65 ++++++++++++++++++++++++++++++++++-----------
>   drivers/md/raid10.h |  4 ++-
>   2 files changed, 53 insertions(+), 16 deletions(-)

This patch does not apply cleanly on md-7.2, please rebase first.

>
-- 
Thansk,
Kuai

^ permalink raw reply

* [GIT PULL] md-7.2-20260531
From: Yu Kuai @ 2026-05-31 11:26 UTC (permalink / raw)
  To: Jens Axboe
  Cc: Yu Kuai, linux-raid, linux-block, Abd-Alrhman Masalkhi,
	Benjamin Marzinski, Chen Cheng, Christoph Hellwig, Li Nan,
	Thorsten Blum

Hi Jens,

Please consider pulling the following changes into your for-7.2/block
branch.

This pull request contains:

Bug Fixes:
- Only requeue dm-raid bios when dm is suspending. (Benjamin Marzinski)
- Reset raid10 read_slot when reusing r10bio for discard. (Chen Cheng)
- Fix raid1/raid10 deadlock in read error recovery path. (Abd-Alrhman Masalkhi)
- Fix raid1/raid10 error-path detection with md_cloned_bio(). (Abd-Alrhman Masalkhi)
- Fix raid1/raid10 bio accounting for split md cloned bios. (Abd-Alrhman Masalkhi)
- Fix raid1 nr_pending leak in REQ_ATOMIC bad-block path. (Abd-Alrhman Masalkhi)

Improvements:
- Skip redundant raid_disks updates when the value is unchanged. (Abd-Alrhman Masalkhi)

Cleanups:
- Update MAINTAINERS email addresses. (Yu Kuai, Li Nan)
- Clean up raid1 read error handling. (Christoph Hellwig)
- Move the exceed_read_errors condition out of fix_read_error(). (Christoph Hellwig)
- Use str_plural() in raid0 dump_zones(). (Thorsten Blum)

Thanks,
Kuai

---

The following changes since commit be34ec59ef061a1cc435a3e066ad71ca675c7fcd:

  block: unexport bio_{set,check}_pages_dirty (2026-05-15 08:46:45 -0600)

are available in the Git repository at:

  https://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux.git tags/md-7.2-20260531

for you to fetch changes up to 717359a168bb66ac95f6161715d17e491ee86ca7:

  md/raid0: use str_plural helper in dump_zones (2026-05-31 19:09:20 +0800)

----------------------------------------------------------------
Abd-Alrhman Masalkhi (5):
      md: skip redundant raid_disks update when value is unchanged
      md/raid1,raid10: fix deadlock in read error recovery path
      md/raid1,raid10: fix error-path detection with md_cloned_bio()
      md/raid1,raid10: fix bio accounting for split md cloned bios
      raid1: fix nr_pending leak in REQ_ATOMIC bad-block error path

Benjamin Marzinski (1):
      dm-raid: only requeue bios when dm is suspending

Chen Cheng (1):
      md/raid10: reset read_slot when reusing r10bio for discard

Christoph Hellwig (2):
      md/raid1: cleanup handle_read_error
      md/raid1: move the exceed_read_errors condition out of fix_read_error

Li Nan (1):
      MAINTAINERS: Update Li Nan's E-mail address

Thorsten Blum (1):
      md/raid0: use str_plural helper in dump_zones

Yu Kuai (1):
      MAINTAINERS: update Yu Kuai's email address

 MAINTAINERS          |  6 ++---
 drivers/md/dm-raid.c |  6 +++++
 drivers/md/md.c      | 32 ++++++++++++++++----------
 drivers/md/md.h      |  7 ++++++
 drivers/md/raid0.c   |  3 ++-
 drivers/md/raid1.c   | 63 ++++++++++++++++++++++++++++------------------------
 drivers/md/raid10.c  | 29 +++++++++++++++---------
 drivers/md/raid5.c   |  7 ++++--
 8 files changed, 96 insertions(+), 57 deletions(-)

^ permalink raw reply

* Re: --bitmap=lockless across server reboot
From: Yu Kuai @ 2026-05-31 11:50 UTC (permalink / raw)
  To: Anton Gavriliuk; +Cc: linux-raid, yukuai
In-Reply-To: <CAAiJnjoh9rTHh4gRu2=7A4C7EFP4yfBED94qmeS_ATDyB0yevQ@mail.gmail.com>

Hi,

在 2026/5/25 23:08, Anton Gavriliuk 写道:
> Hhmm.... I just re-checked it with latest kernel (7.1-rc5) on Fedora
> Server 44, and now it works, log below.  I don't remember on which
> kernel I saw that issue (7.1-rc3 or 7.1-rc4)

If the latest kernel works well, then it's fine. llbitmap is still
under experimental stage, and there will be patches for bug fix and
features.

>
> BTW, earlier you mentioned that you are working on raid5 performance
> improvements,
>
> "“BTW we're working on performance
> improvement for large raid5 arrays for at most 64 disks, results looks great.
> However, it might take sometime before we push our work to upstream.”
>
> Are there any progress ?, I'm very interested to test on PCIe 5.0 NVMe drives.

Yes, but we'll keep those improvements downstream for sometime. We have plans
to push them to upstream but it'll wait for about 1 or 2 years :)

>
> This is Fedora Server 44 (up to date) with compiled kernel 7.1-rc5
>
> [root@qdevice ~]# cat /etc/*release
> Fedora release 44 (Forty Four)
> NAME="Fedora Linux"
> VERSION="44 (Server Edition)"
> RELEASE_TYPE=stable
> ID=fedora
> VERSION_ID=44
> VERSION_CODENAME=""
> PRETTY_NAME="Fedora Linux 44 (Server Edition)"
> ANSI_COLOR="0;38;2;60;110;180"
> LOGO=fedora-logo-icon
> CPE_NAME="cpe:/o:fedoraproject:fedora:44"
> HOME_URL="https://fedoraproject.org/"
> DOCUMENTATION_URL="https://docs.fedoraproject.org/en-US/fedora/f44/"
> SUPPORT_URL="https://ask.fedoraproject.org/"
> BUG_REPORT_URL="https://bugzilla.redhat.com/"
> REDHAT_BUGZILLA_PRODUCT="Fedora"
> REDHAT_BUGZILLA_PRODUCT_VERSION=44
> REDHAT_SUPPORT_PRODUCT="Fedora"
> REDHAT_SUPPORT_PRODUCT_VERSION=44
> SUPPORT_END=2027-05-19
> VARIANT="Server Edition"
> VARIANT_ID=server
> Fedora release 44 (Forty Four)
> Fedora release 44 (Forty Four)
> [root@qdevice ~]#
> [root@qdevice ~]# uname -a
> Linux qdevice 7.1.0-rc5 #1 SMP PREEMPT_DYNAMIC Mon May 25 15:02:20
> EEST 2026 x86_64 GNU/Linux
> [root@qdevice ~]#
> [root@qdevice mdadm]# lsblk
> NAME        MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
> nvme6n1     259:1    0 447.1G  0 disk
> ├─nvme6n1p1 259:2    0     1G  0 part /boot/efi
> ├─nvme6n1p2 259:3    0     1G  0 part /boot
> ├─nvme6n1p3 259:4    0   220G  0 part /
> ├─nvme6n1p4 259:5    0     1G  0 part
> └─nvme6n1p5 259:6    0   220G  0 part
> nvme3n1     259:10   0   2.9T  0 disk
> nvme1n1     259:11   0   2.9T  0 disk
> nvme0n1     259:12   0   2.9T  0 disk
> nvme4n1     259:16   0   2.9T  0 disk
> nvme2n1     259:17   0   2.9T  0 disk
> nvme5n1     259:18   0   2.9T  0 disk
> [root@qdevice mdadm]#
> [root@qdevice mdadm]# mdadm --create --verbose /dev/md0 --level=6
> --bitmap=lockless --raid-devices=6 /dev/nvme0n1 /dev/nvme1n1
> /dev/nvme2n1 /dev/nvme3n1 /dev/nvme4n1 /dev/nvme5n1
> mdadm: Experimental lockless bitmap, use at your own risk!
> mdadm: layout defaults to left-symmetric
> mdadm: layout defaults to left-symmetric
> mdadm: chunk size defaults to 512K
> mdadm: /dev/nvme0n1 appears to be part of a raid array:
>         level=raid6 devices=5 ctime=Wed May 20 12:45:26 2026
> mdadm: /dev/nvme1n1 appears to be part of a raid array:
>         level=raid6 devices=5 ctime=Wed May 20 12:45:26 2026
> mdadm: /dev/nvme2n1 appears to be part of a raid array:
>         level=raid6 devices=5 ctime=Wed May 20 12:45:26 2026
> mdadm: /dev/nvme3n1 appears to be part of a raid array:
>         level=raid6 devices=5 ctime=Wed May 20 12:45:26 2026
> mdadm: /dev/nvme4n1 appears to be part of a raid array:
>         level=raid6 devices=5 ctime=Wed May 20 12:45:26 2026
> mdadm: /dev/nvme5n1 appears to be part of a raid array:
>         level=raid6 devices=6 ctime=Wed May 20 11:45:38 2026
> mdadm: size set to 3125484544K
> Continue creating array [y/N]? y
> mdadm: Defaulting to version 1.2 metadata
> mdadm: array /dev/md0 started.
> [root@qdevice mdadm]#
> [root@qdevice mdadm]# lsblk
> NAME        MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
> nvme6n1     259:1    0 447.1G  0 disk
> ├─nvme6n1p1 259:2    0     1G  0 part  /boot/efi
> ├─nvme6n1p2 259:3    0     1G  0 part  /boot
> ├─nvme6n1p3 259:4    0   220G  0 part  /
> ├─nvme6n1p4 259:5    0     1G  0 part
> └─nvme6n1p5 259:6    0   220G  0 part
> nvme3n1     259:10   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme1n1     259:11   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme0n1     259:12   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme4n1     259:16   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme2n1     259:17   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme5n1     259:18   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> [root@qdevice mdadm]#
> [root@qdevice mdadm]# reboot
> [root@qdevice mdadm]#
>
> After reboot,
>
> [root@qdevice ~]# lsblk
> NAME        MAJ:MIN RM   SIZE RO TYPE  MOUNTPOINTS
> nvme6n1     259:1    0 447.1G  0 disk
> ├─nvme6n1p1 259:2    0     1G  0 part  /boot/efi
> ├─nvme6n1p2 259:3    0     1G  0 part  /boot
> ├─nvme6n1p3 259:4    0   220G  0 part  /
> ├─nvme6n1p4 259:5    0     1G  0 part
> └─nvme6n1p5 259:6    0   220G  0 part
> nvme2n1     259:9    0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme1n1     259:10   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme4n1     259:15   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme0n1     259:16   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme3n1     259:17   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> nvme5n1     259:18   0   2.9T  0 disk
> └─md0         9:0    0  11.6T  0 raid6
> [root@qdevice ~]#
>
>
> Anton
>
> пн, 25 мая 2026 г. в 08:32, Yu Kuai <yukuai@fnnas.com>:
>> Hi,
>>
>> 在 2026/5/20 1:28, Anton Gavriliuk 写道:
>>> Hi
>>>
>>> Does md-raid lockless bitmap support server's reboot ?
>> Yes, of course it should support reboot.
>>
>>> I don't see md-raid6 created with --bitmap=lockless after reboot.
>> Do you check kernel log if there is any failure log? And do you try
>> mdadm -a manually?
>>
>> BTW, pPlease report with your environment and test script in details,
>> especially kernel version and mdadm version.
>>
>>> Anton
>>>
>> --
>> Thansk,
>> Kuai

-- 
Thansk,
Kuai

^ permalink raw reply

* [PATCH] raid10: badblock-aware reshape write error handling
From: ghuicao @ 2026-06-01  5:46 UTC (permalink / raw)
  To: song, yukuai; +Cc: linan122, xiao, linux-raid, linux-kernel, Cao Guanghui

From: Cao Guanghui <caoguanghui@kylinos.cn>

Replace the FIXME in end_reshape_write(). Instead of failing the device
immediately on write errors during reshape, attempt to record badblocks
using new_data_offset with is_new=1.

rdev_set_badblocks() returns true on success. On failure (e.g., badblocks
table full), it has already called md_error() internally to degrade the
device. Queue WantReplacement for member devices regardless of badblock
recording success, but skip this for replacement devices to avoid
replacement loops.

On successful write, clear stale badblock records at the new location
since data has migrated.

Signed-off-by: Cao Guanghui <caoguanghui@kylinos.cn>
---
 drivers/md/raid10.c | 27 ++++++++++++++++++++++++---
 1 file changed, 24 insertions(+), 3 deletions(-)

diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 4901ebe45c87..08d58a1c680e 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -4991,9 +4991,30 @@ static void end_reshape_write(struct bio *bio)
 		      conf->mirrors[d].rdev;
 
 	if (bio->bi_status) {
-		/* FIXME should record badblock */
-		md_error(mddev, rdev);
-	}
+		set_bit(WriteErrorSeen, &rdev->flags);
+
+		/* rdev_set_badblocks returns true on success.
+		 * On failure, it has already called md_error() internally.
+		 * Use is_new=1 as reshape writes target the new layout
+		 * (new_data_offset).
+		 */
+		if (rdev_set_badblocks(rdev, r10_bio->devs[slot].addr,
+				       r10_bio->sectors, 1)) {
+			/* Queue async replacement for member devices
+			 * For replacement devices, do not trigger WantReplacement
+			 * to avoid circular replacement storms.
+			 */
+			if (!repl) {
+				if (!test_and_set_bit(WantReplacement, &rdev->flags))
+					set_bit(MD_RECOVERY_NEEDED,
+						&rdev->mddev->recovery);
+			}
+		}
+	} else {
+		/* Write succeeded, clear stale badblock records */
+		rdev_clear_badblocks(rdev, r10_bio->devs[slot].addr,
+				     r10_bio->sectors, 1);
+	}
 
 	rdev_dec_pending(rdev, mddev);
 	end_reshape_request(r10_bio);
-- 
2.25.1


^ permalink raw reply related

* Re: [PATCH 1/2] md/raid1: cleanup handle_read_error
From: Xiao Ni @ 2026-06-01  5:51 UTC (permalink / raw)
  To: Christoph Hellwig; +Cc: Song Liu, Yu Kuai, Li Nan, Xiao Ni, linux-raid
In-Reply-To: <20260529054308.2720300-2-hch@lst.de>

On Fri, May 29, 2026 at 1:46 PM Christoph Hellwig <hch@lst.de> wrote:
>
> Unwind the main conditional with duplicate conditions and initialize
> variables at initialization time where possible.
>
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  drivers/md/raid1.c | 34 ++++++++++++++++------------------
>  1 file changed, 16 insertions(+), 18 deletions(-)
>
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index 64d970e2ef50..8fad1692cf66 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -2627,35 +2627,33 @@ static void handle_write_finished(struct r1conf *conf, struct r1bio *r1_bio)
>
>  static void handle_read_error(struct r1conf *conf, struct r1bio *r1_bio)
>  {
> +       struct md_rdev *rdev = conf->mirrors[r1_bio->read_disk].rdev;
> +       struct bio *bio = r1_bio->bios[r1_bio->read_disk];
>         struct mddev *mddev = conf->mddev;
> -       struct bio *bio;
> -       struct md_rdev *rdev;
>         sector_t sector;
>
>         clear_bit(R1BIO_ReadError, &r1_bio->state);
> -       /* we got a read error. Maybe the drive is bad.  Maybe just
> -        * the block and we can fix it.
> -        * We freeze all other IO, and try reading the block from
> -        * other devices.  When we find one, we re-write
> -        * and check it that fixes the read error.
> -        * This is all done synchronously while the array is
> -        * frozen
> -        */
>
> -       bio = r1_bio->bios[r1_bio->read_disk];
>         bio_put(bio);
>         r1_bio->bios[r1_bio->read_disk] = NULL;
>
> -       rdev = conf->mirrors[r1_bio->read_disk].rdev;
> -       if (mddev->ro == 0
> -           && !test_bit(FailFast, &rdev->flags)) {
> +       /*
> +        * We got a read error. Maybe the drive is bad.  Maybe just the block
> +        * and we can fix it.
> +        *
> +        * If allowed, freeze all other IO, and try reading the block from other
> +        * devices.  If we find one, we re-write and check it that fixes the
> +        * read error.  This is all done synchronously while the array is
> +        * frozen.
> +        */
> +       if (mddev->ro) {
> +               r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
> +       } else if (test_bit(FailFast, &rdev->flags)) {
> +               md_error(mddev, rdev);
> +       } else {
>                 freeze_array(conf, 1);
>                 fix_read_error(conf, r1_bio);
>                 unfreeze_array(conf);
> -       } else if (mddev->ro == 0 && test_bit(FailFast, &rdev->flags)) {
> -               md_error(mddev, rdev);
> -       } else {
> -               r1_bio->bios[r1_bio->read_disk] = IO_BLOCKED;
>         }
>
>         rdev_dec_pending(rdev, conf->mddev);
> --
> 2.53.0
>
>

Yes, it's more readable. This patch is good to me.
Reviewed-by: Xiao Ni <xiao@kernel.org>


^ 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