* [PATCH v2 07/14] md/raid1: clean up useless sync_blocks handling in raid1_sync_request
From: linan666 @ 2026-01-28 7:57 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
Since the loop is changed to while(0), some handling of sync_blocks
in raid1_sync_request() is no longer needed and can be removed.
No functional changes.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid1.c | 18 +++++++-----------
1 file changed, 7 insertions(+), 11 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 5954ead7dfd4..2308e16b1280 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2985,7 +2985,6 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
if (max_sector > sector_nr + good_sectors)
max_sector = sector_nr + good_sectors;
nr_sectors = 0;
- sync_blocks = 0;
do {
struct folio *folio;
int len = RESYNC_BLOCK_SIZE;
@@ -2993,15 +2992,13 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
len = (max_sector - sector_nr) << 9;
if (len == 0)
break;
- if (sync_blocks == 0) {
- if (!md_bitmap_start_sync(mddev, sector_nr,
- &sync_blocks, still_degraded) &&
- !conf->fullsync &&
- !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
- break;
- if ((len >> 9) > sync_blocks)
- len = sync_blocks<<9;
- }
+ if (!md_bitmap_start_sync(mddev, sector_nr,
+ &sync_blocks, still_degraded) &&
+ !conf->fullsync &&
+ !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ break;
+ if ((len >> 9) > sync_blocks)
+ len = sync_blocks<<9;
for (i = 0 ; i < conf->raid_disks * 2; i++) {
struct resync_folio *rf;
@@ -3015,7 +3012,6 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
}
nr_sectors += len>>9;
sector_nr += len>>9;
- sync_blocks -= (len>>9);
} while (0);
r1_bio->sectors = nr_sectors;
--
2.39.2
^ permalink raw reply related
* [PATCH v2 02/14] md: introduce sync_folio_io for folio support in RAID
From: linan666 @ 2026-01-28 7:56 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
Prepare for folio support in RAID by introducing sync_folio_io(),
matching sync_page_io()'s functionality. Differences are:
- Replace input parameter 'page' with 'folio'
- Replace __bio_add_page() calls with bio_add_folio_nofail()
- Add new parameter 'off' to prepare for adding a folio to bio in segments,
e.g. in fix_recovery_read_error()
sync_page_io() will be removed once full folio support is complete.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/md.h | 2 ++
drivers/md/md.c | 27 +++++++++++++++++++++++++++
2 files changed, 29 insertions(+)
diff --git a/drivers/md/md.h b/drivers/md/md.h
index a083f37374d0..410f8a6b75e7 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -920,6 +920,8 @@ void md_write_metadata(struct mddev *mddev, struct md_rdev *rdev,
extern int md_super_wait(struct mddev *mddev);
extern int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
struct page *page, blk_opf_t opf, bool metadata_op);
+extern int sync_folio_io(struct md_rdev *rdev, sector_t sector, int size,
+ int off, struct folio *folio, blk_opf_t opf, bool metadata_op);
extern void md_do_sync(struct md_thread *thread);
extern void md_new_event(void);
extern void md_allow_write(struct mddev *mddev);
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5df2220b1bd1..b8c8a16cf037 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1192,6 +1192,33 @@ int sync_page_io(struct md_rdev *rdev, sector_t sector, int size,
}
EXPORT_SYMBOL_GPL(sync_page_io);
+int sync_folio_io(struct md_rdev *rdev, sector_t sector, int size, int off,
+ struct folio *folio, blk_opf_t opf, bool metadata_op)
+{
+ struct bio bio;
+ struct bio_vec bvec;
+
+ if (metadata_op && rdev->meta_bdev)
+ bio_init(&bio, rdev->meta_bdev, &bvec, 1, opf);
+ else
+ bio_init(&bio, rdev->bdev, &bvec, 1, opf);
+
+ if (metadata_op)
+ bio.bi_iter.bi_sector = sector + rdev->sb_start;
+ else if (rdev->mddev->reshape_position != MaxSector &&
+ (rdev->mddev->reshape_backwards ==
+ (sector >= rdev->mddev->reshape_position)))
+ bio.bi_iter.bi_sector = sector + rdev->new_data_offset;
+ else
+ bio.bi_iter.bi_sector = sector + rdev->data_offset;
+ bio_add_folio_nofail(&bio, folio, size, off);
+
+ submit_bio_wait(&bio);
+
+ return !bio.bi_status;
+}
+EXPORT_SYMBOL_GPL(sync_folio_io);
+
static int read_disk_sb(struct md_rdev *rdev, int size)
{
if (rdev->sb_loaded)
--
2.39.2
^ permalink raw reply related
* [PATCH v2 00/14] folio support for sync I/O in RAID
From: linan666 @ 2026-01-28 7:56 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
From: Li Nan <linan122@huawei.com>
This patchset adds folio support to sync operations in raid1/10.
Previously, we used 16 * 4K pages for 64K sync I/O. With this change,
we'll use a single 64K folio instead. Using folios reduces
resync/recovery time by 20% on HDD.
This is the first step towards full folio support in RAID. Going forward,
I will replace the remaining page-based usage with folio.
The patchset was tested with mdadm. Additional fault injection stress tests
were run under file systems.
v2:
- Remove patch "md: use folio for bb_folio". It will be included in
a later patch set
- In patch 5:
1) fix typo
2) rewrite the logic of copying data in process_checks()
3) rename resync_get_all_folio() to resync_get_folio()
4) s/resync_pages *rps/resync_folio *rfs/g in
raid1_alloc_init_r1buf() and raid10_alloc_init_r10buf()
- Subsequent patches: Adapting conflicts caused by patch 5
Li Nan (14):
md/raid1,raid10: clean up of RESYNC_SECTORS
md: introduce sync_folio_io for folio support in RAID
md/raid1: use folio for tmppage
md/raid10: use folio for tmppage
md/raid1,raid10: use folio for sync path IO
md: Clean up folio sync support related code
md/raid1: clean up useless sync_blocks handling in raid1_sync_request
md/raid1: fix IO error at logical block size granularity
md/raid10: fix IO error at logical block size granularity
md/raid1,raid10: clean up resync_fetch_folio
md: clean up resync_free_folio
md/raid1: clean up sync IO size calculation in raid1_sync_request
md/raid10: clean up sync IO size calculation in raid10_sync_request
md/raid1,raid10: fall back to smaller order if sync folio alloc fails
drivers/md/md.h | 2 +
drivers/md/raid1.h | 2 +-
drivers/md/raid10.h | 2 +-
drivers/md/md.c | 29 +++-
drivers/md/raid1-10.c | 81 ++++-------
drivers/md/raid1.c | 233 ++++++++++++++-----------------
drivers/md/raid10.c | 315 ++++++++++++++++++++----------------------
7 files changed, 308 insertions(+), 356 deletions(-)
--
2.39.2
^ permalink raw reply
* [PATCH v2 10/14] md/raid1,raid10: clean up resync_fetch_folio
From: linan666 @ 2026-01-28 7:57 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
The helper resync_fetch_folio() only returns the folio member without
any additional logic. Clean it up by accessing rf->folio directly.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid1-10.c | 7 +------
drivers/md/raid1.c | 10 ++++------
drivers/md/raid10.c | 3 +--
3 files changed, 6 insertions(+), 14 deletions(-)
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index 568ab002691f..2ff1f8855900 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -55,11 +55,6 @@ static inline void resync_free_folio(struct resync_folio *rf)
folio_put(rf->folio);
}
-static inline struct folio *resync_fetch_folio(struct resync_folio *rf)
-{
- return rf->folio;
-}
-
/*
* 'strct resync_folio' stores actual pages used for doing the resync
* IO, and it is per-bio, so make .bi_private points to it.
@@ -74,7 +69,7 @@ static void md_bio_reset_resync_folio(struct bio *bio, struct resync_folio *rf,
int size)
{
/* initialize bvec table again */
- if (WARN_ON(!bio_add_folio(bio, resync_fetch_folio(rf),
+ if (WARN_ON(!bio_add_folio(bio, rf->folio,
min_t(int, size, RESYNC_BLOCK_SIZE),
0))) {
bio->bi_status = BLK_STS_RESOURCE;
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 27e3b2375b16..a303349eeff4 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2981,8 +2981,8 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
max_sector = sector_nr + good_sectors;
nr_sectors = 0;
do {
- struct folio *folio;
int len = RESYNC_BLOCK_SIZE;
+
if (sector_nr + (len>>9) > max_sector)
len = (max_sector - sector_nr) << 9;
if (len == 0)
@@ -2996,13 +2996,11 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
len = sync_blocks<<9;
for (i = 0 ; i < conf->raid_disks * 2; i++) {
- struct resync_folio *rf;
-
bio = r1_bio->bios[i];
- rf = get_resync_folio(bio);
if (bio->bi_end_io) {
- folio = resync_fetch_folio(rf);
- bio_add_folio_nofail(bio, folio, len, 0);
+ struct resync_folio *rf = get_resync_folio(bio);
+
+ bio_add_folio_nofail(bio, rf->folio, len, 0);
}
}
nr_sectors += len>>9;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 06257eea97ed..d8a5fadfc933 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3630,9 +3630,8 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
break;
for (bio= biolist ; bio ; bio=bio->bi_next) {
struct resync_folio *rf = get_resync_folio(bio);
- struct folio *folio = resync_fetch_folio(rf);
- if (WARN_ON(!bio_add_folio(bio, folio, len, 0))) {
+ if (WARN_ON(!bio_add_folio(bio, rf->folio, len, 0))) {
bio->bi_status = BLK_STS_RESOURCE;
bio_endio(bio);
*skipped = 1;
--
2.39.2
^ permalink raw reply related
* [PATCH v2 06/14] md: Clean up folio sync support related code
From: linan666 @ 2026-01-28 7:57 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
1. Remove resync_get_all_folio() and invoke folio_get() directly instead.
2. Clean up redundant while(0) loop in md_bio_reset_resync_folio().
3. Clean up bio variable by directly referencing r10_bio->devs[j].bio
instead in r1buf_pool_alloc() and r10buf_pool_alloc().
4. Clean up RESYNC_PAGES.
Signed-off-by: Li Nan <linan122@huawei.com>
Reviewed-by: Xiao Ni <xni@redhat.com>
---
drivers/md/raid1-10.c | 22 ++++++----------------
drivers/md/raid1.c | 6 ++----
drivers/md/raid10.c | 6 ++----
3 files changed, 10 insertions(+), 24 deletions(-)
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index 300fbe9dc02e..568ab002691f 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -1,7 +1,6 @@
// SPDX-License-Identifier: GPL-2.0
/* Maximum size of each resync request */
#define RESYNC_BLOCK_SIZE (64*1024)
-#define RESYNC_PAGES ((RESYNC_BLOCK_SIZE + PAGE_SIZE-1) / PAGE_SIZE)
#define RESYNC_SECTORS (RESYNC_BLOCK_SIZE >> 9)
/*
@@ -56,11 +55,6 @@ static inline void resync_free_folio(struct resync_folio *rf)
folio_put(rf->folio);
}
-static inline void resync_get_folio(struct resync_folio *rf)
-{
- folio_get(rf->folio);
-}
-
static inline struct folio *resync_fetch_folio(struct resync_folio *rf)
{
return rf->folio;
@@ -80,16 +74,12 @@ static void md_bio_reset_resync_folio(struct bio *bio, struct resync_folio *rf,
int size)
{
/* initialize bvec table again */
- do {
- struct folio *folio = resync_fetch_folio(rf);
- int len = min_t(int, size, RESYNC_BLOCK_SIZE);
-
- if (WARN_ON(!bio_add_folio(bio, folio, len, 0))) {
- bio->bi_status = BLK_STS_RESOURCE;
- bio_endio(bio);
- return;
- }
- } while (0);
+ if (WARN_ON(!bio_add_folio(bio, resync_fetch_folio(rf),
+ min_t(int, size, RESYNC_BLOCK_SIZE),
+ 0))) {
+ bio->bi_status = BLK_STS_RESOURCE;
+ bio_endio(bio);
+ }
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index d9c106529289..5954ead7dfd4 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -181,18 +181,16 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
for (j = 0; j < conf->raid_disks * 2; j++) {
struct resync_folio *rf = &rfs[j];
- bio = r1_bio->bios[j];
-
if (j < need_folio) {
if (resync_alloc_folio(rf, gfp_flags))
goto out_free_folio;
} else {
memcpy(rf, &rfs[0], sizeof(*rf));
- resync_get_folio(rf);
+ folio_get(rf->folio);
}
rf->raid_bio = r1_bio;
- bio->bi_private = rf;
+ r1_bio->bios[j]->bi_private = rf;
}
r1_bio->master_bio = NULL;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 7533aeb23819..5c0975ec8809 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -183,19 +183,17 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
if (rbio)
rf_repl = &rfs[nalloc + j];
- bio = r10_bio->devs[j].bio;
-
if (!j || test_bit(MD_RECOVERY_SYNC,
&conf->mddev->recovery)) {
if (resync_alloc_folio(rf, gfp_flags))
goto out_free_folio;
} else {
memcpy(rf, &rfs[0], sizeof(*rf));
- resync_get_folio(rf);
+ folio_get(rf->folio);
}
rf->raid_bio = r10_bio;
- bio->bi_private = rf;
+ r10_bio->devs[j].bio->bi_private = rf;
if (rbio) {
memcpy(rf_repl, rf, sizeof(*rf));
rbio->bi_private = rf_repl;
--
2.39.2
^ permalink raw reply related
* [PATCH v2 08/14] md/raid1: fix IO error at logical block size granularity
From: linan666 @ 2026-01-28 7:57 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
RAID1 currently fixes IO error at PAGE_SIZE granularity. Fix at smaller
granularity can handle more errors, and RAID will support logical block
sizes larger than PAGE_SIZE in the future, where PAGE_SIZE IO will fail.
Switch IO error fix granularity to logical block size.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid1.c | 13 ++++---------
1 file changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 2308e16b1280..27e3b2375b16 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2114,7 +2114,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
{
/* Try some synchronous reads of other devices to get
* good data, much like with normal read errors. Only
- * read into the pages we already have so we don't
+ * read into the block we already have so we don't
* need to re-issue the read request.
* We don't need to freeze the array, because being in an
* active sync request, there is no normal IO, and
@@ -2145,13 +2145,11 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
}
while(sectors) {
- int s = sectors;
+ int s = min_t(int, sectors, mddev->logical_block_size >> 9);
int d = r1_bio->read_disk;
int success = 0;
int start;
- if (s > (PAGE_SIZE>>9))
- s = PAGE_SIZE >> 9;
do {
if (r1_bio->bios[d]->bi_end_io == end_sync_read) {
/* No rcu protection needed here devices
@@ -2190,7 +2188,7 @@ static int fix_sync_read_error(struct r1bio *r1_bio)
if (abort)
return 0;
- /* Try next page */
+ /* Try next block */
sectors -= s;
sect += s;
off += s << 9;
@@ -2388,14 +2386,11 @@ static void fix_read_error(struct r1conf *conf, struct r1bio *r1_bio)
}
while(sectors) {
- int s = sectors;
+ int s = min_t(int, sectors, mddev->logical_block_size >> 9);
int d = read_disk;
int success = 0;
int start;
- if (s > (PAGE_SIZE>>9))
- s = PAGE_SIZE >> 9;
-
do {
rdev = conf->mirrors[d].rdev;
if (rdev &&
--
2.39.2
^ permalink raw reply related
* [PATCH v2 13/14] md/raid10: clean up sync IO size calculation in raid10_sync_request
From: linan666 @ 2026-01-28 7:57 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
Use 'nr_sectors' directly for sync IO size calculation. Prepare folio
allocation failure fallback.
No functional changes.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid10.c | 14 +++++---------
1 file changed, 5 insertions(+), 9 deletions(-)
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index b728131bdad4..030812f908ac 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -3618,28 +3618,24 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
}
}
- nr_sectors = 0;
if (sector_nr + max_sync < max_sector)
max_sector = sector_nr + max_sync;
do {
- int len = RESYNC_BLOCK_SIZE;
+ nr_sectors = max_sector - sector_nr;
- if (sector_nr + (len>>9) > max_sector)
- len = (max_sector - sector_nr) << 9;
- if (len == 0)
+ if (nr_sectors == 0)
break;
for (bio= biolist ; bio ; bio=bio->bi_next) {
struct resync_folio *rf = get_resync_folio(bio);
- if (WARN_ON(!bio_add_folio(bio, rf->folio, len, 0))) {
+ if (WARN_ON(!bio_add_folio(bio, rf->folio, nr_sectors << 9, 0))) {
bio->bi_status = BLK_STS_RESOURCE;
bio_endio(bio);
*skipped = 1;
- return len;
+ return nr_sectors << 9;
}
}
- nr_sectors += len>>9;
- sector_nr += len>>9;
+ sector_nr += nr_sectors;;
} while (0);
r10_bio->sectors = nr_sectors;
--
2.39.2
^ permalink raw reply related
* [PATCH v2 11/14] md: clean up resync_free_folio
From: linan666 @ 2026-01-28 7:57 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
The resync_free_folio() helper only wraps a single folio_put() call,
so remove it and call folio_put() directly.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid1-10.c | 5 -----
drivers/md/raid1.c | 4 ++--
drivers/md/raid10.c | 4 ++--
3 files changed, 4 insertions(+), 9 deletions(-)
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index 2ff1f8855900..ffbd7bd0f6e8 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -50,11 +50,6 @@ static inline int resync_alloc_folio(struct resync_folio *rf,
return 0;
}
-static inline void resync_free_folio(struct resync_folio *rf)
-{
- folio_put(rf->folio);
-}
-
/*
* 'strct resync_folio' stores actual pages used for doing the resync
* IO, and it is per-bio, so make .bi_private points to it.
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index a303349eeff4..b5239b5cb4e9 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -199,7 +199,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
out_free_folio:
while (--j >= 0)
- resync_free_folio(&rfs[j]);
+ folio_put(rfs[j].folio);
out_free_bio:
while (++j < conf->raid_disks * 2) {
@@ -222,7 +222,7 @@ static void r1buf_pool_free(void *__r1_bio, void *data)
for (i = conf->raid_disks * 2; i--; ) {
rf = get_resync_folio(r1bio->bios[i]);
- resync_free_folio(rf);
+ folio_put(rf->folio);
bio_uninit(r1bio->bios[i]);
kfree(r1bio->bios[i]);
}
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index d8a5fadfc933..b728131bdad4 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -204,7 +204,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
out_free_folio:
while (--j >= 0)
- resync_free_folio(&rfs[j]);
+ folio_put(rfs[j].folio);
j = 0;
out_free_bio:
@@ -234,7 +234,7 @@ static void r10buf_pool_free(void *__r10_bio, void *data)
if (bio) {
rf = get_resync_folio(bio);
- resync_free_folio(rf);
+ folio_put(rf->folio);
bio_uninit(bio);
kfree(bio);
}
--
2.39.2
^ permalink raw reply related
* [PATCH v2 14/14] md/raid1,raid10: fall back to smaller order if sync folio alloc fails
From: linan666 @ 2026-01-28 7:57 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
RESYNC_BLOCK_SIZE (64K) has higher allocation failure chance than 4k,
so retry with lower orders to improve allocation reliability.
A r1/10_bio may have different rf->folio orders. Use minimum order as
r1/10_bio sectors to prevent exceeding size when adding folio to IO later.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid1-10.c | 14 +++++++++++---
drivers/md/raid1.c | 13 +++++++++----
drivers/md/raid10.c | 28 ++++++++++++++++++++++++++--
3 files changed, 46 insertions(+), 9 deletions(-)
diff --git a/drivers/md/raid1-10.c b/drivers/md/raid1-10.c
index ffbd7bd0f6e8..e966d11a81e7 100644
--- a/drivers/md/raid1-10.c
+++ b/drivers/md/raid1-10.c
@@ -41,12 +41,20 @@ static void rbio_pool_free(void *rbio, void *data)
}
static inline int resync_alloc_folio(struct resync_folio *rf,
- gfp_t gfp_flags)
+ gfp_t gfp_flags, int *order)
{
- rf->folio = folio_alloc(gfp_flags, get_order(RESYNC_BLOCK_SIZE));
- if (!rf->folio)
+ struct folio *folio;
+
+ do {
+ folio = folio_alloc(gfp_flags, *order);
+ if (folio)
+ break;
+ } while (--(*order) > 0);
+
+ if (!folio)
return -ENOMEM;
+ rf->folio = folio;
return 0;
}
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index 2253e65c5f03..5bee846f1534 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -149,6 +149,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
int need_folio;
int j;
struct resync_folio *rfs;
+ int order = get_order(RESYNC_BLOCK_SIZE);
r1_bio = r1bio_pool_alloc(gfp_flags, conf);
if (!r1_bio)
@@ -182,7 +183,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
struct resync_folio *rf = &rfs[j];
if (j < need_folio) {
- if (resync_alloc_folio(rf, gfp_flags))
+ if (resync_alloc_folio(rf, gfp_flags, &order))
goto out_free_folio;
} else {
memcpy(rf, &rfs[0], sizeof(*rf));
@@ -193,6 +194,7 @@ static void * r1buf_pool_alloc(gfp_t gfp_flags, void *data)
r1_bio->bios[j]->bi_private = rf;
}
+ r1_bio->sectors = 1 << (order + PAGE_SECTORS_SHIFT);
r1_bio->master_bio = NULL;
return r1_bio;
@@ -2776,7 +2778,7 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
int write_targets = 0, read_targets = 0;
sector_t sync_blocks;
bool still_degraded = false;
- int good_sectors = RESYNC_SECTORS;
+ int good_sectors;
int min_bad = 0; /* number of sectors that are bad in all devices */
int idx = sector_to_idx(sector_nr);
@@ -2858,8 +2860,11 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
r1_bio->sector = sector_nr;
r1_bio->state = 0;
set_bit(R1BIO_IsSync, &r1_bio->state);
- /* make sure good_sectors won't go across barrier unit boundary */
- good_sectors = align_to_barrier_unit_end(sector_nr, good_sectors);
+ /*
+ * make sure good_sectors won't go across barrier unit boundary.
+ * r1_bio->sectors <= RESYNC_SECTORS.
+ */
+ good_sectors = align_to_barrier_unit_end(sector_nr, r1_bio->sectors);
for (i = 0; i < conf->raid_disks * 2; i++) {
struct md_rdev *rdev;
diff --git a/drivers/md/raid10.c b/drivers/md/raid10.c
index 030812f908ac..72c77db9957c 100644
--- a/drivers/md/raid10.c
+++ b/drivers/md/raid10.c
@@ -135,6 +135,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
int j;
int nalloc, nalloc_rf;
struct resync_folio *rfs;
+ int order = get_order(RESYNC_BLOCK_SIZE);
r10_bio = r10bio_pool_alloc(gfp_flags, conf);
if (!r10_bio)
@@ -185,7 +186,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
if (!j || test_bit(MD_RECOVERY_SYNC,
&conf->mddev->recovery)) {
- if (resync_alloc_folio(rf, gfp_flags))
+ if (resync_alloc_folio(rf, gfp_flags, &order))
goto out_free_folio;
} else {
memcpy(rf, &rfs[0], sizeof(*rf));
@@ -200,6 +201,7 @@ static void * r10buf_pool_alloc(gfp_t gfp_flags, void *data)
}
}
+ r10_bio->sectors = 1 << (order + PAGE_SECTORS_SHIFT);
return r10_bio;
out_free_folio:
@@ -3374,6 +3376,15 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
continue;
}
}
+
+ /*
+ * RESYNC_BLOCK_SIZE folio might alloc failed in
+ * resync_alloc_folio(). Fall back to smaller sync
+ * size if needed.
+ */
+ if (max_sync > r10_bio->sectors)
+ max_sync = r10_bio->sectors;
+
any_working = 1;
bio = r10_bio->devs[0].bio;
bio->bi_next = biolist;
@@ -3525,7 +3536,15 @@ static sector_t raid10_sync_request(struct mddev *mddev, sector_t sector_nr,
}
if (sync_blocks < max_sync)
max_sync = sync_blocks;
+
r10_bio = raid10_alloc_init_r10buf(conf);
+ /*
+ * RESYNC_BLOCK_SIZE folio might alloc failed in resync_alloc_folio().
+ * Fall back to smaller sync size if needed.
+ */
+ if (max_sync > r10_bio->sectors)
+ max_sync = r10_bio->sectors;
+
r10_bio->state = 0;
r10_bio->mddev = mddev;
@@ -4702,7 +4721,12 @@ static sector_t reshape_request(struct mddev *mddev, sector_t sector_nr,
r10_bio->mddev = mddev;
r10_bio->sector = sector_nr;
set_bit(R10BIO_IsReshape, &r10_bio->state);
- r10_bio->sectors = last - sector_nr + 1;
+ /*
+ * RESYNC_BLOCK_SIZE folio might alloc failed in
+ * resync_alloc_folio(). Fall back to smaller sync
+ * size if needed.
+ */
+ r10_bio->sectors = min_t(int, r10_bio->sectors, last - sector_nr + 1);
rdev = read_balance(conf, r10_bio, &max_sectors);
BUG_ON(!test_bit(R10BIO_Previous, &r10_bio->state));
--
2.39.2
^ permalink raw reply related
* [PATCH v2 12/14] md/raid1: clean up sync IO size calculation in raid1_sync_request
From: linan666 @ 2026-01-28 7:57 UTC (permalink / raw)
To: song, yukuai; +Cc: xni, linux-raid, linux-kernel, linan666, yangerkun, yi.zhang
In-Reply-To: <20260128075708.2259525-1-linan666@huaweicloud.com>
From: Li Nan <linan122@huawei.com>
Use 'nr_sectors' directly for sync IO size calculation. Prepare folio
allocation failure fallback.
No functional changes.
Signed-off-by: Li Nan <linan122@huawei.com>
---
drivers/md/raid1.c | 17 ++++++-----------
1 file changed, 6 insertions(+), 11 deletions(-)
diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
index b5239b5cb4e9..2253e65c5f03 100644
--- a/drivers/md/raid1.c
+++ b/drivers/md/raid1.c
@@ -2979,32 +2979,27 @@ static sector_t raid1_sync_request(struct mddev *mddev, sector_t sector_nr,
max_sector = mddev->resync_max; /* Don't do IO beyond here */
if (max_sector > sector_nr + good_sectors)
max_sector = sector_nr + good_sectors;
- nr_sectors = 0;
do {
- int len = RESYNC_BLOCK_SIZE;
-
- if (sector_nr + (len>>9) > max_sector)
- len = (max_sector - sector_nr) << 9;
- if (len == 0)
+ nr_sectors = max_sector - sector_nr;
+ if (nr_sectors == 0)
break;
if (!md_bitmap_start_sync(mddev, sector_nr,
&sync_blocks, still_degraded) &&
!conf->fullsync &&
!test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
break;
- if ((len >> 9) > sync_blocks)
- len = sync_blocks<<9;
+ if (nr_sectors > sync_blocks)
+ nr_sectors = sync_blocks;
for (i = 0 ; i < conf->raid_disks * 2; i++) {
bio = r1_bio->bios[i];
if (bio->bi_end_io) {
struct resync_folio *rf = get_resync_folio(bio);
- bio_add_folio_nofail(bio, rf->folio, len, 0);
+ bio_add_folio_nofail(bio, rf->folio, nr_sectors << 9, 0);
}
}
- nr_sectors += len>>9;
- sector_nr += len>>9;
+ sector_nr += nr_sectors;
} while (0);
r1_bio->sectors = nr_sectors;
--
2.39.2
^ permalink raw reply related
* Re: [PATCH 1/1] md: fix return value of mddev_trylock
From: Li Nan @ 2026-01-28 8:24 UTC (permalink / raw)
To: Xiao Ni, yukuai; +Cc: linux-raid, bvanassche
In-Reply-To: <20260127073951.17248-1-xni@redhat.com>
在 2026/1/27 15:39, Xiao Ni 写道:
> A return value of 0 is treaded as successful lock acquisition. In fact, a
> return value of 1 means getting the lock successfully.
>
> Fixes: 9e59d609763f ("md: call del_gendisk in control path")
> Reported-by: Bart Van Assche <bvanassche@acm.org>
> Closes: https://lore.kernel.org/linux-raid/20250611073108.25463-1-xni@redhat.com/T/#mfa369ef5faa4aa58e13e6d9fdb88aecd862b8f2f
> Signed-off-by: Xiao Ni <xni@redhat.com>
> ---
> drivers/md/md.h | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/md/md.h b/drivers/md/md.h
> index 6985f2829bbd..3bfbee595156 100644
> --- a/drivers/md/md.h
> +++ b/drivers/md/md.h
> @@ -737,8 +737,8 @@ static inline int mddev_trylock(struct mddev *mddev)
> int ret;
>
> ret = mutex_trylock(&mddev->reconfig_mutex);
> - if (!ret && test_bit(MD_DELETED, &mddev->flags)) {
> - ret = -ENODEV;
> + if (ret && test_bit(MD_DELETED, &mddev->flags)) {
> + ret = 0;
> mutex_unlock(&mddev->reconfig_mutex);
> }
> return ret;
LGTM
Reviewed-by: Li Nan <linan122@huawei.com>
--
Thanks,
Nan
^ permalink raw reply
* md: regression: incorrect warn about updating super block failure
From: Tj @ 2026-01-28 8:25 UTC (permalink / raw)
To: yukuai; +Cc: linux-kernel, linux-raid
Commit 8c9e376b9d1a222 introduces an error message that is incorrectly reported for LVM raid volumes:
$ journalctl --dmesg --priority err
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
md_update_sb: can't update sb for read-only array mdX
$ sudo dmsetup table --target raid
SUNNY-Documents: 0 20971520 raid raid1 3 0 region_size 4096 2 254:74 254:75 254:76 254:77
SUNNY-Media: 0 171966464 raid raid1 3 0 region_size 4096 2 254:69 254:70 254:71 254:72
SUNNY-NAS: 0 46874624 raid raid1 3 0 region_size 4096 2 254:15 254:16 254:17 254:18
SUNNY-Projects: 0 23068672 raid raid1 3 0 region_size 4096 2 254:20 254:21 254:22 254:23
SUNNY-SourceCode_wcorig: 0 478150656 raid raid1 3 0 region_size 4096 2 254:26 254:27 254:28 254:29
SUNNY-WINE: 0 16777216 raid raid1 3 0 region_size 4096 2 254:80 254:81 254:82 254:83
SUNNY-etc: 0 106496 raid raid1 3 0 region_size 4096 2 254:57 254:58 254:59 254:60
SUNNY-home_wcorig: 0 301989888 raid raid1 3 0 region_size 4096 2 254:46 254:47 254:48 254:49
SUNNY-l8r: 0 16777216 raid raid1 3 0 region_size 4096 2 254:37 254:38 254:39 254:40
SUNNY-machines_old: 0 34185216 raid raid1 3 0 region_size 4096 2 254:32 254:33 254:34 254:35
SUNNY-opt: 0 41943040 raid raid1 3 0 region_size 4096 2 254:64 254:65 254:66 254:67
SUNNY-rootfs: 0 67108864 raid raid1 3 0 region_size 4096 2 254:3 254:4 254:5 254:6
SUNNY-usr_local: 0 16777216 raid raid1 3 0 region_size 4096 2 254:52 254:53 254:54 254:55
SUNNY-var_wcorig: 0 25165824 raid raid1 3 0 region_size 4096 2 254:9 254:10 254:11 254:12
^ permalink raw reply
* Re: md: regression: incorrect warn about updating super block failure
From: Yu Kuai @ 2026-01-28 9:30 UTC (permalink / raw)
To: Tj; +Cc: linux-kernel, linux-raid, yukuai
In-Reply-To: <20260128082430.96788-1-tj.iam.tj@proton.me>
Hi,
在 2026/1/28 16:25, Tj 写道:
> Commit 8c9e376b9d1a222 introduces an error message that is incorrectly reported for LVM raid volumes:
>
> $ journalctl --dmesg --priority err
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
> md_update_sb: can't update sb for read-only array mdX
Yeah, we should bypass dmraid, will fix it soon.
>
> $ sudo dmsetup table --target raid
> SUNNY-Documents: 0 20971520 raid raid1 3 0 region_size 4096 2 254:74 254:75 254:76 254:77
> SUNNY-Media: 0 171966464 raid raid1 3 0 region_size 4096 2 254:69 254:70 254:71 254:72
> SUNNY-NAS: 0 46874624 raid raid1 3 0 region_size 4096 2 254:15 254:16 254:17 254:18
> SUNNY-Projects: 0 23068672 raid raid1 3 0 region_size 4096 2 254:20 254:21 254:22 254:23
> SUNNY-SourceCode_wcorig: 0 478150656 raid raid1 3 0 region_size 4096 2 254:26 254:27 254:28 254:29
> SUNNY-WINE: 0 16777216 raid raid1 3 0 region_size 4096 2 254:80 254:81 254:82 254:83
> SUNNY-etc: 0 106496 raid raid1 3 0 region_size 4096 2 254:57 254:58 254:59 254:60
> SUNNY-home_wcorig: 0 301989888 raid raid1 3 0 region_size 4096 2 254:46 254:47 254:48 254:49
> SUNNY-l8r: 0 16777216 raid raid1 3 0 region_size 4096 2 254:37 254:38 254:39 254:40
> SUNNY-machines_old: 0 34185216 raid raid1 3 0 region_size 4096 2 254:32 254:33 254:34 254:35
> SUNNY-opt: 0 41943040 raid raid1 3 0 region_size 4096 2 254:64 254:65 254:66 254:67
> SUNNY-rootfs: 0 67108864 raid raid1 3 0 region_size 4096 2 254:3 254:4 254:5 254:6
> SUNNY-usr_local: 0 16777216 raid raid1 3 0 region_size 4096 2 254:52 254:53 254:54 254:55
> SUNNY-var_wcorig: 0 25165824 raid raid1 3 0 region_size 4096 2 254:9 254:10 254:11 254:12
>
>
--
Thansk,
Kuai
^ permalink raw reply
* [PATCH 1/3] lib/raid6: Divide the raid6 algorithm selection process into two parts
From: sunliming @ 2026-01-28 10:49 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, sunliming
In-Reply-To: <20260128104923.338443-1-sunliming@linux.dev>
From: sunliming <sunliming@kylinos.cn>
Divide the RAID6 algorithm selection process into two parts: fast selection
and benchmark selection. To prepare for the asynchronous processing of
the benchmark phase.
Signed-off-by: sunliming <sunliming@kylinos.cn>
---
lib/raid6/algos.c | 76 +++++++++++++++++++++++++++++++----------------
1 file changed, 51 insertions(+), 25 deletions(-)
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index 799e0e5eac26..ac6a77b0ae1d 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -134,7 +134,7 @@ const struct raid6_recov_calls *const raid6_recov_algos[] = {
static inline const struct raid6_recov_calls *raid6_choose_recov(void)
{
const struct raid6_recov_calls *const *algo;
- const struct raid6_recov_calls *best;
+ const struct raid6_recov_calls *best = NULL;
for (best = NULL, algo = raid6_recov_algos; *algo; algo++)
if (!best || (*algo)->priority > best->priority)
@@ -152,24 +152,44 @@ static inline const struct raid6_recov_calls *raid6_choose_recov(void)
return best;
}
-static inline const struct raid6_calls *raid6_choose_gen(
- void *(*const dptrs)[RAID6_TEST_DISKS], const int disks)
+/* Quick selection: selects the first valid algorithm. */
+static inline const struct raid6_calls *raid6_choose_gen_fast(void)
+{
+ const struct raid6_calls *const *algo;
+ const struct raid6_calls *best = NULL;
+
+ for (algo = raid6_algos; *algo; algo++) {
+ if ((*algo)->valid && !(*algo)->valid())
+ continue;
+
+ best = *algo;
+ break;
+ }
+
+ if (best) {
+ raid6_call = *best;
+ pr_info("raid6: skipped pq benchmark and selected %s\n",
+ best->name);
+ } else {
+ pr_err("raid6: No valid algorithm found even for fast selection!\n");
+ }
+
+ return best;
+}
+
+static inline const struct raid6_calls *raid6_gen_benchmark(
+ void *(*const dptrs)[RAID6_TEST_DISKS], const int disks)
{
unsigned long perf, bestgenperf, j0, j1;
int start = (disks>>1)-1, stop = disks-3; /* work on the second half of the disks */
const struct raid6_calls *const *algo;
- const struct raid6_calls *best;
+ const struct raid6_calls *best = NULL;
for (bestgenperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) {
if (!best || (*algo)->priority >= best->priority) {
if ((*algo)->valid && !(*algo)->valid())
continue;
- if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK)) {
- best = *algo;
- break;
- }
-
perf = 0;
preempt_disable();
@@ -200,12 +220,6 @@ static inline const struct raid6_calls *raid6_choose_gen(
raid6_call = *best;
- if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK)) {
- pr_info("raid6: skipped pq benchmark and selected %s\n",
- best->name);
- goto out;
- }
-
pr_info("raid6: using algorithm %s gen() %ld MB/s\n",
best->name,
(bestgenperf * HZ * (disks - 2)) >>
@@ -235,16 +249,11 @@ static inline const struct raid6_calls *raid6_choose_gen(
return best;
}
-
/* Try to pick the best algorithm */
/* This code uses the gfmul table as convenient data set to abuse */
-
-int __init raid6_select_algo(void)
+static int raid6_choose_gen_benmark(const struct raid6_calls **gen_best)
{
const int disks = RAID6_TEST_DISKS;
-
- const struct raid6_calls *gen_best;
- const struct raid6_recov_calls *rec_best;
char *disk_ptr, *p;
void *dptrs[RAID6_TEST_DISKS];
int i, cycle;
@@ -269,14 +278,31 @@ int __init raid6_select_algo(void)
if ((disks - 2) * PAGE_SIZE % 65536)
memcpy(p, raid6_gfmul, (disks - 2) * PAGE_SIZE % 65536);
- /* select raid gen_syndrome function */
- gen_best = raid6_choose_gen(&dptrs, disks);
+ *gen_best = raid6_gen_benchmark(&dptrs, disks);
+
+ free_pages((unsigned long)disk_ptr, RAID6_TEST_DISKS_ORDER);
+
+ return 0;
+}
+
+int __init raid6_select_algo(void)
+{
+ int ret;
+ const struct raid6_calls *gen_best = NULL;
+ const struct raid6_recov_calls *rec_best = NULL;
+
+ /* select raid gen_syndrome functions */
+ if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK))
+ gen_best = raid6_choose_gen_fast();
+ else {
+ ret = raid6_choose_gen_benmark(&gen_best);
+ if (ret < 0)
+ return ret;
+ }
/* select raid recover functions */
rec_best = raid6_choose_recov();
- free_pages((unsigned long)disk_ptr, RAID6_TEST_DISKS_ORDER);
-
return gen_best && rec_best ? 0 : -EINVAL;
}
--
2.25.1
^ permalink raw reply related
* [PATCH 0/3] lib/raid6: Optimize raid6_select_algo while ensuring
From: sunliming @ 2026-01-28 10:49 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, sunliming
From: sunliming <sunliming@kylinos.cn>
The selection of RAID6 PQ functions involves a dual-strategy approach:
prioritizing startup speed leads to quickly choosing a usable algorithm,
while prioritizing performance leads to selecting an optimal algorithm
via benchmarking. This choice is determined by the RAID6_PQ_BENCHMARK
configuration. This patch series achieves both fast startup and optimal
algorithm selection by initially choosing an algorithm quickly at startup,
then asynchronously determining the optimal algorithm through benchmarking.
Since all RAID6 PQ function algorithms are functionally equivalent despite
performance differences, this approach should be effective.
sunliming (3):
lib/raid6: Divide the raid6 algorithm selection process into two parts
lib/raid6: Optimizing the raid6_select_algo time through asynchronous
processing
lib/raid6: Delete the RAID6_PQ_BENCHMARK config
lib/Kconfig | 8 -----
lib/raid6/algos.c | 92 +++++++++++++++++++++++++++++++----------------
2 files changed, 61 insertions(+), 39 deletions(-)
--
2.25.1
^ permalink raw reply
* [PATCH 2/3] lib/raid6: Optimizing the raid6_select_algo time through asynchronous processing
From: sunliming @ 2026-01-28 10:49 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, sunliming
In-Reply-To: <20260128104923.338443-1-sunliming@linux.dev>
From: sunliming <sunliming@kylinos.cn>
Optimizing the raid6_select_algo time. In raid6_select_algo(), an raid6 gen
algorithm is first selected quickly through synchronous processing, while
the time-consuming process of selecting the optimal algorithm via benchmarking
is handled asynchronously. This approach speeds up the overall startup time
and ultimately ensures the selection of an optimal algorithm.
Signed-off-by: sunliming <sunliming@kylinos.cn>
---
lib/raid6/algos.c | 44 ++++++++++++++++++++++++--------------------
1 file changed, 24 insertions(+), 20 deletions(-)
diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
index ac6a77b0ae1d..c92168d59df2 100644
--- a/lib/raid6/algos.c
+++ b/lib/raid6/algos.c
@@ -12,6 +12,7 @@
*/
#include <linux/raid/pq.h>
+#include <linux/workqueue.h>
#ifndef __KERNEL__
#include <sys/mman.h>
#include <stdio.h>
@@ -168,7 +169,7 @@ static inline const struct raid6_calls *raid6_choose_gen_fast(void)
if (best) {
raid6_call = *best;
- pr_info("raid6: skipped pq benchmark and selected %s\n",
+ pr_info("raid6: fast selected %s, async benchmark pending\n",
best->name);
} else {
pr_err("raid6: No valid algorithm found even for fast selection!\n");
@@ -177,7 +178,7 @@ static inline const struct raid6_calls *raid6_choose_gen_fast(void)
return best;
}
-static inline const struct raid6_calls *raid6_gen_benchmark(
+static inline void raid6_gen_benchmark(
void *(*const dptrs)[RAID6_TEST_DISKS], const int disks)
{
unsigned long perf, bestgenperf, j0, j1;
@@ -214,12 +215,11 @@ static inline const struct raid6_calls *raid6_gen_benchmark(
}
if (!best) {
- pr_err("raid6: Yikes! No algorithm found!\n");
- goto out;
+ pr_err("raid6: async benchmark failed to find any algorithm\n");
+ return;
}
raid6_call = *best;
-
pr_info("raid6: using algorithm %s gen() %ld MB/s\n",
best->name,
(bestgenperf * HZ * (disks - 2)) >>
@@ -244,14 +244,11 @@ static inline const struct raid6_calls *raid6_gen_benchmark(
(perf * HZ * (disks - 2)) >>
(20 - PAGE_SHIFT + RAID6_TIME_JIFFIES_LG2 + 1));
}
-
-out:
- return best;
}
/* Try to pick the best algorithm */
/* This code uses the gfmul table as convenient data set to abuse */
-static int raid6_choose_gen_benmark(const struct raid6_calls **gen_best)
+static int raid6_choose_gen_benmark(void)
{
const int disks = RAID6_TEST_DISKS;
char *disk_ptr, *p;
@@ -278,32 +275,39 @@ static int raid6_choose_gen_benmark(const struct raid6_calls **gen_best)
if ((disks - 2) * PAGE_SIZE % 65536)
memcpy(p, raid6_gfmul, (disks - 2) * PAGE_SIZE % 65536);
- *gen_best = raid6_gen_benchmark(&dptrs, disks);
+ raid6_gen_benchmark(&dptrs, disks);
free_pages((unsigned long)disk_ptr, RAID6_TEST_DISKS_ORDER);
return 0;
}
+static struct work_struct raid6_benchmark_work __initdata;
+
+static __init void benchmark_work_func(struct work_struct *work)
+{
+ raid6_choose_gen_benmark();
+}
+
int __init raid6_select_algo(void)
{
- int ret;
const struct raid6_calls *gen_best = NULL;
const struct raid6_recov_calls *rec_best = NULL;
- /* select raid gen_syndrome functions */
- if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK))
- gen_best = raid6_choose_gen_fast();
- else {
- ret = raid6_choose_gen_benmark(&gen_best);
- if (ret < 0)
- return ret;
- }
+ /* phase 1: synchronous fast selection generation algorithm */
+ gen_best = raid6_choose_gen_fast();
/* select raid recover functions */
rec_best = raid6_choose_recov();
- return gen_best && rec_best ? 0 : -EINVAL;
+ if (!gen_best || !rec_best)
+ return -EINVAL;
+
+ /* phase 2: asynchronous performance benchmarking */
+ INIT_WORK(&raid6_benchmark_work, benchmark_work_func);
+ schedule_work(&raid6_benchmark_work);
+
+ return 0;
}
static void raid6_exit(void)
--
2.25.1
^ permalink raw reply related
* [PATCH 3/3] lib/raid6: Delete the RAID6_PQ_BENCHMARK config
From: sunliming @ 2026-01-28 10:49 UTC (permalink / raw)
To: song, yukuai; +Cc: linux-raid, linux-kernel, sunliming
In-Reply-To: <20260128104923.338443-1-sunliming@linux.dev>
From: sunliming <sunliming@kylinos.cn>
Now RAID6 PQ functions is automatically choosed and the
RAID6_PQ_BENCHMARK is not needed.
Signed-off-by: sunliming <sunliming@kylinos.cn>
---
lib/Kconfig | 8 --------
1 file changed, 8 deletions(-)
diff --git a/lib/Kconfig b/lib/Kconfig
index 2923924bea78..841a0245a2c4 100644
--- a/lib/Kconfig
+++ b/lib/Kconfig
@@ -11,14 +11,6 @@ menu "Library routines"
config RAID6_PQ
tristate
-config RAID6_PQ_BENCHMARK
- bool "Automatically choose fastest RAID6 PQ functions"
- depends on RAID6_PQ
- default y
- help
- Benchmark all available RAID6 PQ functions on init and choose the
- fastest one.
-
config LINEAR_RANGES
tristate
--
2.25.1
^ permalink raw reply related
* Re: [PATCH 1/3] lib/raid6: Divide the raid6 algorithm selection process into two parts
From: Li Nan @ 2026-01-29 3:26 UTC (permalink / raw)
To: sunliming, song, yukuai; +Cc: linux-raid, linux-kernel, sunliming
In-Reply-To: <20260128104923.338443-2-sunliming@linux.dev>
在 2026/1/28 18:49, sunliming@linux.dev 写道:
> From: sunliming <sunliming@kylinos.cn>
>
> Divide the RAID6 algorithm selection process into two parts: fast selection
> and benchmark selection. To prepare for the asynchronous processing of
> the benchmark phase.
>
> Signed-off-by: sunliming <sunliming@kylinos.cn>
> ---
> lib/raid6/algos.c | 76 +++++++++++++++++++++++++++++++----------------
> 1 file changed, 51 insertions(+), 25 deletions(-)
>
> diff --git a/lib/raid6/algos.c b/lib/raid6/algos.c
> index 799e0e5eac26..ac6a77b0ae1d 100644
> --- a/lib/raid6/algos.c
> +++ b/lib/raid6/algos.c
> @@ -134,7 +134,7 @@ const struct raid6_recov_calls *const raid6_recov_algos[] = {
> static inline const struct raid6_recov_calls *raid6_choose_recov(void)
> {
> const struct raid6_recov_calls *const *algo;
> - const struct raid6_recov_calls *best;
> + const struct raid6_recov_calls *best = NULL;
>
> for (best = NULL, algo = raid6_recov_algos; *algo; algo++)
> if (!best || (*algo)->priority > best->priority)
> @@ -152,24 +152,44 @@ static inline const struct raid6_recov_calls *raid6_choose_recov(void)
> return best;
> }
>
> -static inline const struct raid6_calls *raid6_choose_gen(
> - void *(*const dptrs)[RAID6_TEST_DISKS], const int disks)
> +/* Quick selection: selects the first valid algorithm. */
> +static inline const struct raid6_calls *raid6_choose_gen_fast(void)
> +{
> + const struct raid6_calls *const *algo;
> + const struct raid6_calls *best = NULL;
> +
> + for (algo = raid6_algos; *algo; algo++) {
> + if ((*algo)->valid && !(*algo)->valid())
> + continue;
This logic is odd. We should select the highest-priority algorithm
instead of the first one. This was introduced by commit be85f93ae2df
("lib/raid6: add option to skip algorithm benchmarking").
After fix, this logic is identical to raid6_choose_recov(). Could we reuse
it after renaming the function?
> +
> + best = *algo;
> + break;
> + }
> +
> + if (best) {
> + raid6_call = *best;
> + pr_info("raid6: skipped pq benchmark and selected %s\n",
> + best->name);
> + } else {
> + pr_err("raid6: No valid algorithm found even for fast selection!\n");
> + }
> +
> + return best;
> +}
> +
> +static inline const struct raid6_calls *raid6_gen_benchmark(
> + void *(*const dptrs)[RAID6_TEST_DISKS], const int disks)
> {
> unsigned long perf, bestgenperf, j0, j1;
> int start = (disks>>1)-1, stop = disks-3; /* work on the second half of the disks */
> const struct raid6_calls *const *algo;
> - const struct raid6_calls *best;
> + const struct raid6_calls *best = NULL;
>
> for (bestgenperf = 0, best = NULL, algo = raid6_algos; *algo; algo++) {
> if (!best || (*algo)->priority >= best->priority) {
> if ((*algo)->valid && !(*algo)->valid())
> continue;
>
> - if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK)) {
> - best = *algo;
> - break;
> - }
> -
> perf = 0;
>
> preempt_disable();
> @@ -200,12 +220,6 @@ static inline const struct raid6_calls *raid6_choose_gen(
>
> raid6_call = *best;
>
> - if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK)) {
> - pr_info("raid6: skipped pq benchmark and selected %s\n",
> - best->name);
> - goto out;
> - }
> -
> pr_info("raid6: using algorithm %s gen() %ld MB/s\n",
> best->name,
> (bestgenperf * HZ * (disks - 2)) >>
> @@ -235,16 +249,11 @@ static inline const struct raid6_calls *raid6_choose_gen(
> return best;
> }
>
> -
> /* Try to pick the best algorithm */
> /* This code uses the gfmul table as convenient data set to abuse */
> -
> -int __init raid6_select_algo(void)
> +static int raid6_choose_gen_benmark(const struct raid6_calls **gen_best)
> {
> const int disks = RAID6_TEST_DISKS;
> -
> - const struct raid6_calls *gen_best;
> - const struct raid6_recov_calls *rec_best;
> char *disk_ptr, *p;
> void *dptrs[RAID6_TEST_DISKS];
> int i, cycle;
> @@ -269,14 +278,31 @@ int __init raid6_select_algo(void)
> if ((disks - 2) * PAGE_SIZE % 65536)
> memcpy(p, raid6_gfmul, (disks - 2) * PAGE_SIZE % 65536);
>
> - /* select raid gen_syndrome function */
> - gen_best = raid6_choose_gen(&dptrs, disks);
> + *gen_best = raid6_gen_benchmark(&dptrs, disks);
> +
> + free_pages((unsigned long)disk_ptr, RAID6_TEST_DISKS_ORDER);
> +
> + return 0;
> +}
> +
> +int __init raid6_select_algo(void)
> +{
> + int ret;
> + const struct raid6_calls *gen_best = NULL;
> + const struct raid6_recov_calls *rec_best = NULL;
> +
> + /* select raid gen_syndrome functions */
> + if (!IS_ENABLED(CONFIG_RAID6_PQ_BENCHMARK))
> + gen_best = raid6_choose_gen_fast();
> + else {
> + ret = raid6_choose_gen_benmark(&gen_best);
'gen_best' is meaningless, use 'ret' directly. The input parameter of
raid6_choose_gen_benchmark() can be modified to void.
> + if (ret < 0)
> + return ret;
> + }
>
> /* select raid recover functions */
> rec_best = raid6_choose_recov();
>
> - free_pages((unsigned long)disk_ptr, RAID6_TEST_DISKS_ORDER);
> -
> return gen_best && rec_best ? 0 : -EINVAL;
> }
>
--
Thanks,
Nan
^ permalink raw reply
* Re: [PATCH] MAINTAINERS: Add Li Nan as md/raid reviewer
From: Li Nan @ 2026-01-30 7:55 UTC (permalink / raw)
To: linan666, song, yukuai
Cc: linux-kernel, yangerkun, yi.zhang, Linux RAID Mailing List
In-Reply-To: <20260129130056.1014405-1-linan666@huaweicloud.com>
Sorry for missing cc to linux-raid.
On 2026/1/29 21:00, linan666@huaweicloud.com wrote:
> From: Li Nan <linan122@huawei.com>
>
> I've long contributed to and reviewed the md/raid subsystem. I've fixed
> numerous bugs and done code refactors, with dozens of patches merged.
> I now volunteer to work as a reviewer for this subsystem.
>
> Signed-off-by: Li Nan <linan122@huawei.com>
> ---
> MAINTAINERS | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index 67db88b04537..3262c74b93b4 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -24260,6 +24260,7 @@ F: include/linux/property.h
> SOFTWARE RAID (Multiple Disks) SUPPORT
> M: Song Liu <song@kernel.org>
> M: Yu Kuai <yukuai@fnnas.com>
> +R: Li Nan <linan122@huawei.com>
> L: linux-raid@vger.kernel.org
> S: Supported
> Q: https://patchwork.kernel.org/project/linux-raid/list/
--
Thanks,
Nan
^ permalink raw reply
* Re: [PATCH] md/raid1: fix memory leak in raid1_run()
From: Li Nan @ 2026-01-31 1:45 UTC (permalink / raw)
To: Zilin Guan, song; +Cc: yukuai, linux-raid, linux-kernel, jianhao.xu
In-Reply-To: <20260126071533.606263-1-zilin@seu.edu.cn>
在 2026/1/26 15:15, Zilin Guan 写道:
> raid1_run() calls setup_conf() which registers a thread via
> md_register_thread(). If raid1_set_limits() fails, the previously
> registered thread is not unregistered, resulting in a memory leak
> of the md_thread structure and the thread resource itself.
>
> Add md_unregister_thread() to the error path to properly cleanup
> the thread, which aligns with the error handling logic of other paths
> in this function.
>
> Compile tested only. Issue found using a prototype static analysis tool
> and code review.
>
> Fixes: 97894f7d3c29 ("md/raid1: use the atomic queue limit update APIs")
> Signed-off-by: Zilin Guan <zilin@seu.edu.cn>
> ---
> drivers/md/raid1.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/md/raid1.c b/drivers/md/raid1.c
> index 57d50465eed1..cc9914bd15c1 100644
> --- a/drivers/md/raid1.c
> +++ b/drivers/md/raid1.c
> @@ -3254,6 +3254,7 @@ static int raid1_run(struct mddev *mddev)
> if (!mddev_is_dm(mddev)) {
> ret = raid1_set_limits(mddev);
> if (ret) {
> + md_unregister_thread(mddev, &conf->thread);
> if (!mddev->private)
> raid1_free(mddev, conf);
> return ret;
LGTM
Reviewed-by: Li Nan <linan122@huawei.com>
--
Thanks,
Nan
^ permalink raw reply
* [PATCH RESEND] MAINTAINERS: Add Li Nan as md/raid reviewer
From: linan666 @ 2026-02-02 8:32 UTC (permalink / raw)
To: song, yukuai
Cc: linux-raid, linux-kernel, linan666, yangerkun, yi.zhang,
wanghai38
From: Li Nan <linan122@huawei.com>
I've long contributed to and reviewed the md/raid subsystem. I've fixed
many bugs and done code refactors, with dozens of patches merged.
I now volunteer to work as a reviewer for this subsystem.
Signed-off-by: Li Nan <linan122@huawei.com>
---
MAINTAINERS | 1 +
1 file changed, 1 insertion(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 67db88b04537..3262c74b93b4 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -24260,6 +24260,7 @@ F: include/linux/property.h
SOFTWARE RAID (Multiple Disks) SUPPORT
M: Song Liu <song@kernel.org>
M: Yu Kuai <yukuai@fnnas.com>
+R: Li Nan <linan122@huawei.com>
L: linux-raid@vger.kernel.org
S: Supported
Q: https://patchwork.kernel.org/project/linux-raid/list/
--
2.39.2
^ permalink raw reply related
* [GIT PULL] md-7.0-20260202
From: Yu Kuai @ 2026-02-02 12:42 UTC (permalink / raw)
To: Jens Axboe; +Cc: Song Liu, linux-raid, linux-block, Li Nan, Xiao Ni, Zilin Guan
Hi Jens,
Please consider pulling the following changes into your for-7.0/block
branch.
This pull request contains:
Bug Fixes:
- Fix return value of mddev_trylock (Xiao Ni)
- Fix memory leak in raid1_run() (Zilin Guan)
Maintainers:
- Add Li Nan as mdraid reviewer (Li Nan)
Thanks,
Kuai
The following changes since commit 5314d25afbc44d0449fa2519d2c9d7f3c319f74c:
selftests: ublk: improve I/O ordering test with bpftrace (2026-01-31 14:56:28 -0700)
are available in the Git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/mdraid/linux.git tags/md-7.0-20260202
for you to fetch changes up to b36844f7d11e1f322d1e48a828c5bfb4a0ecabd1:
MAINTAINERS: Add Li Nan as md/raid reviewer (2026-02-02 20:31:40 +0800)
----------------------------------------------------------------
Li Nan (1):
MAINTAINERS: Add Li Nan as md/raid reviewer
Xiao Ni (1):
md: fix return value of mddev_trylock
Zilin Guan (1):
md/raid1: fix memory leak in raid1_run()
MAINTAINERS | 1 +
drivers/md/md.h | 4 ++--
drivers/md/raid1.c | 1 +
3 files changed, 4 insertions(+), 2 deletions(-)
^ permalink raw reply
* Re: [GIT PULL] md-7.0-20260202
From: Jens Axboe @ 2026-02-02 14:04 UTC (permalink / raw)
To: Yu Kuai; +Cc: Song Liu, linux-raid, linux-block, Li Nan, Xiao Ni, Zilin Guan
In-Reply-To: <20260202124236.4065531-1-yukuai@fnnas.com>
On 2/2/26 5:42 AM, Yu Kuai wrote:
> Hi Jens,
>
> Please consider pulling the following changes into your for-7.0/block
> branch.
>
> This pull request contains:
>
> Bug Fixes:
> - Fix return value of mddev_trylock (Xiao Ni)
> - Fix memory leak in raid1_run() (Zilin Guan)
>
> Maintainers:
> - Add Li Nan as mdraid reviewer (Li Nan)
Pulled, thanks.
--
Jens Axboe
^ permalink raw reply
* [RFC v2 1/5] md: add helpers for requested sync action
From: Zheng Qixing @ 2026-02-03 6:12 UTC (permalink / raw)
To: song, yukuai, linan122
Cc: xni, linux-raid, linux-kernel, yi.zhang, yangerkun, houtao1,
zhengqixing
In-Reply-To: <20260203061259.609206-1-zhengqixing@huaweicloud.com>
From: Zheng Qixing <zhengqixing@huawei.com>
Add helpers for handling requested sync action.
No functional change.
Signed-off-by: Zheng Qixing <zhengqixing@huawei.com>
---
drivers/md/md.c | 65 ++++++++++++++++++++++++++++++++++---------------
1 file changed, 46 insertions(+), 19 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index 5df2220b1bd1..84af578876e2 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -665,6 +665,41 @@ void mddev_put(struct mddev *mddev)
spin_unlock(&all_mddevs_lock);
}
+static int handle_requested_sync_action(struct mddev *mddev,
+ enum sync_action action)
+{
+ switch (action) {
+ case ACTION_CHECK:
+ set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
+ fallthrough;
+ case ACTION_REPAIR:
+ set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
+ set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ return 0;
+ default:
+ return -EINVAL;
+ }
+}
+
+static enum sync_action get_recovery_sync_action(struct mddev *mddev)
+{
+ if (test_bit(MD_RECOVERY_CHECK, &mddev->recovery))
+ return ACTION_CHECK;
+ if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
+ return ACTION_REPAIR;
+ return ACTION_RESYNC;
+}
+
+static void set_requested_position(struct mddev *mddev, sector_t value)
+{
+ mddev->resync_min = value;
+}
+
+static sector_t get_requested_position(struct mddev *mddev)
+{
+ return mddev->resync_min;
+}
+
static void md_safemode_timeout(struct timer_list *t);
static void md_start_sync(struct work_struct *ws);
@@ -5101,17 +5136,9 @@ enum sync_action md_sync_action(struct mddev *mddev)
if (test_bit(MD_RECOVERY_RECOVER, &recovery))
return ACTION_RECOVER;
- if (test_bit(MD_RECOVERY_SYNC, &recovery)) {
- /*
- * MD_RECOVERY_CHECK must be paired with
- * MD_RECOVERY_REQUESTED.
- */
- if (test_bit(MD_RECOVERY_CHECK, &recovery))
- return ACTION_CHECK;
- if (test_bit(MD_RECOVERY_REQUESTED, &recovery))
- return ACTION_REPAIR;
- return ACTION_RESYNC;
- }
+ /* MD_RECOVERY_CHECK must be paired with MD_RECOVERY_REQUESTED. */
+ if (test_bit(MD_RECOVERY_SYNC, &recovery))
+ return get_recovery_sync_action(mddev);
/*
* MD_RECOVERY_NEEDED or MD_RECOVERY_RUNNING is set, however, no
@@ -5300,11 +5327,10 @@ action_store(struct mddev *mddev, const char *page, size_t len)
set_bit(MD_RECOVERY_RECOVER, &mddev->recovery);
break;
case ACTION_CHECK:
- set_bit(MD_RECOVERY_CHECK, &mddev->recovery);
- fallthrough;
case ACTION_REPAIR:
- set_bit(MD_RECOVERY_REQUESTED, &mddev->recovery);
- set_bit(MD_RECOVERY_SYNC, &mddev->recovery);
+ ret = handle_requested_sync_action(mddev, action);
+ if (ret)
+ goto out;
fallthrough;
case ACTION_RESYNC:
case ACTION_IDLE:
@@ -9370,7 +9396,7 @@ static sector_t md_sync_position(struct mddev *mddev, enum sync_action action)
switch (action) {
case ACTION_CHECK:
case ACTION_REPAIR:
- return mddev->resync_min;
+ return get_requested_position(mddev);
case ACTION_RESYNC:
if (!mddev->bitmap)
return mddev->resync_offset;
@@ -9795,10 +9821,11 @@ void md_do_sync(struct md_thread *thread)
if (!test_bit(MD_RECOVERY_INTR, &mddev->recovery)) {
/* We completed so min/max setting can be forgotten if used. */
if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
- mddev->resync_min = 0;
+ set_requested_position(mddev, 0);
mddev->resync_max = MaxSector;
- } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery))
- mddev->resync_min = mddev->curr_resync_completed;
+ } else if (test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
+ set_requested_position(mddev, mddev->curr_resync_completed);
+ }
set_bit(MD_RECOVERY_DONE, &mddev->recovery);
mddev->curr_resync = MD_RESYNC_NONE;
spin_unlock(&mddev->lock);
--
2.39.2
^ permalink raw reply related
* [RFC v2 4/5] md: introduce MAX_RAID_DISKS macro to replace magic number
From: Zheng Qixing @ 2026-02-03 6:12 UTC (permalink / raw)
To: song, yukuai, linan122
Cc: xni, linux-raid, linux-kernel, yi.zhang, yangerkun, houtao1,
zhengqixing
In-Reply-To: <20260203061259.609206-1-zhengqixing@huaweicloud.com>
From: Zheng Qixing <zhengqixing@huawei.com>
Per-device state is stored as a __le16 dev_roles[] array (2 bytes per
device) plus a fixed 256-byte header, still within a 4 KiB superblock.
Therefore the theoretical maximum is (4096 - 256) / 2 = 1920 entries.
Define MAX_RAID_DISKS macro for the maximum number of RAID disks. No
functional change.
Signed-off-by: Zheng Qixing <zhengqixing@huawei.com>
---
drivers/md/md.c | 4 ++--
drivers/md/md.h | 5 +++++
2 files changed, 7 insertions(+), 2 deletions(-)
diff --git a/drivers/md/md.c b/drivers/md/md.c
index f319621c6832..aebbdbaa4e0a 100644
--- a/drivers/md/md.c
+++ b/drivers/md/md.c
@@ -1873,7 +1873,7 @@ static int super_1_load(struct md_rdev *rdev, struct md_rdev *refdev, int minor_
if (sb->magic != cpu_to_le32(MD_SB_MAGIC) ||
sb->major_version != cpu_to_le32(1) ||
- le32_to_cpu(sb->max_dev) > (4096-256)/2 ||
+ le32_to_cpu(sb->max_dev) > MAX_RAID_DISKS ||
le64_to_cpu(sb->super_offset) != rdev->sb_start ||
(le32_to_cpu(sb->feature_map) & ~MD_FEATURE_ALL) != 0)
return -EINVAL;
@@ -2050,7 +2050,7 @@ static int super_1_validate(struct mddev *mddev, struct md_rdev *freshest, struc
mddev->resync_offset = le64_to_cpu(sb->resync_offset);
memcpy(mddev->uuid, sb->set_uuid, 16);
- mddev->max_disks = (4096-256)/2;
+ mddev->max_disks = MAX_RAID_DISKS;
if (!mddev->logical_block_size)
mddev->logical_block_size = le32_to_cpu(sb->logical_block_size);
diff --git a/drivers/md/md.h b/drivers/md/md.h
index a083f37374d0..14f9db38b7c5 100644
--- a/drivers/md/md.h
+++ b/drivers/md/md.h
@@ -21,6 +21,11 @@
#include <linux/raid/md_u.h>
#include <trace/events/block.h>
+/*
+ * v1.x superblock occupies one 4 KiB block: 256B header + 2B per device
+ * in dev_roles[].
+ */
+#define MAX_RAID_DISKS ((4096-256)/2)
#define MaxSector (~(sector_t)0)
enum md_submodule_type {
--
2.39.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox